summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig10
-rw-r--r--.gitattributes4
-rw-r--r--.gitignore41
-rw-r--r--.travis.yml2
-rw-r--r--Doxyfile2432
-rw-r--r--LICENSE.md27
-rw-r--r--LOGO_LICENSE.md2
-rw-r--r--README.md12
-rw-r--r--SConstruct243
-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.cpp30
-rw-r--r--bin/tests/test_gdscript.h2
-rw-r--r--bin/tests/test_gui.cpp17
-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.cpp3
-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.cpp4
-rw-r--r--bin/tests/test_physics.h2
-rw-r--r--bin/tests/test_physics_2d.cpp6
-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.cpp10
-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.h26
-rw-r--r--bin/tests/test_string.cpp365
-rw-r--r--bin/tests/test_string.h2
-rw-r--r--core/SCsub6
-rw-r--r--core/allocators.h2
-rw-r--r--core/array.cpp2
-rw-r--r--core/array.h2
-rw-r--r--core/balloon_allocator.h2
-rw-r--r--core/bind/SCsub2
-rw-r--r--core/bind/core_bind.cpp373
-rw-r--r--core/bind/core_bind.h90
-rw-r--r--core/color.cpp6
-rw-r--r--core/color.h2
-rw-r--r--core/command_queue_mt.cpp2
-rw-r--r--core/command_queue_mt.h6
-rw-r--r--core/compressed_translation.cpp2
-rw-r--r--core/compressed_translation.h2
-rw-r--r--core/core_string_names.cpp3
-rw-r--r--core/core_string_names.h3
-rw-r--r--core/dictionary.cpp4
-rw-r--r--core/dictionary.h2
-rw-r--r--core/dvector.cpp2
-rw-r--r--core/dvector.h19
-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.cpp20
-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.cpp33
-rw-r--r--core/global_constants.h2
-rw-r--r--core/globals.cpp49
-rw-r--r--core/globals.h3
-rw-r--r--core/hash_map.h2
-rw-r--r--core/hashfuncs.h2
-rw-r--r--core/image.cpp280
-rw-r--r--core/image.h27
-rw-r--r--core/image_quantize.cpp2
-rw-r--r--core/input_map.cpp22
-rw-r--r--core/input_map.h4
-rw-r--r--core/int_types.h4
-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.h52
-rw-r--r--core/io/config_file.cpp13
-rw-r--r--core/io/config_file.h2
-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.h148
-rw-r--r--core/io/file_access_encrypted.cpp4
-rw-r--r--core/io/file_access_memory.cpp52
-rw-r--r--core/io/file_access_memory.h3
-rw-r--r--core/io/file_access_network.cpp3
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.cpp34
-rw-r--r--core/io/file_access_pack.h41
-rw-r--r--core/io/file_access_zip.cpp21
-rw-r--r--core/io/http_client.cpp82
-rw-r--r--core/io/http_client.h10
-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.cpp6
-rw-r--r--core/io/ip.h2
-rw-r--r--core/io/ip_address.cpp4
-rw-r--r--core/io/ip_address.h8
-rw-r--r--core/io/json.cpp16
-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/object_format_binary.cpp1491
-rw-r--r--core/io/object_format_binary.h158
-rw-r--r--core/io/object_format_xml.cpp3190
-rw-r--r--core/io/object_format_xml.h196
-rw-r--r--core/io/object_loader.cpp84
-rw-r--r--core/io/object_loader.h76
-rw-r--r--core/io/object_saver.cpp157
-rw-r--r--core/io/object_saver.h128
-rw-r--r--core/io/object_saver_base.cpp150
-rw-r--r--core/io/object_saver_base.h76
-rw-r--r--core/io/packet_peer.cpp28
-rw-r--r--core/io/packet_peer.h10
-rw-r--r--core/io/packet_peer_udp.cpp63
-rw-r--r--core/io/packet_peer_udp.h37
-rw-r--r--core/io/resource_format_binary.cpp411
-rw-r--r--core/io/resource_format_binary.h18
-rw-r--r--core/io/resource_format_xml.cpp476
-rw-r--r--core/io/resource_format_xml.h29
-rw-r--r--core/io/resource_loader.cpp114
-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.cpp2
-rw-r--r--core/io/stream_peer.h2
-rw-r--r--core/io/stream_peer_tcp.cpp4
-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.cpp6
-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.h68
-rw-r--r--core/make_binders.py29
-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.h14
-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.cpp28
-rw-r--r--core/math/camera_matrix.h4
-rw-r--r--core/math/face3.cpp98
-rw-r--r--core/math/face3.h3
-rw-r--r--core/math/geometry.cpp133
-rw-r--r--core/math/geometry.h73
-rw-r--r--core/math/math_2d.cpp64
-rw-r--r--core/math/math_2d.h200
-rw-r--r--core/math/math_defs.cpp6
-rw-r--r--core/math/math_defs.h66
-rw-r--r--core/math/math_funcs.cpp15
-rw-r--r--core/math/math_funcs.h12
-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.h41
-rw-r--r--core/math/quick_hull.cpp5
-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.cpp1082
-rw-r--r--core/math/triangle_mesh.h144
-rw-r--r--core/math/triangulate.cpp2
-rw-r--r--core/math/triangulate.h2
-rw-r--r--core/math/triangulator.cpp1550
-rw-r--r--core/math/triangulator.h306
-rw-r--r--core/math/vector3.cpp21
-rw-r--r--core/math/vector3.h48
-rw-r--r--core/message_queue.cpp21
-rw-r--r--core/message_queue.h2
-rw-r--r--core/method_bind.cpp10
-rw-r--r--core/method_bind.h7
-rw-r--r--core/multi_bucket_array.h2
-rw-r--r--core/object.cpp221
-rw-r--r--core/object.h113
-rw-r--r--core/object_type_db.cpp209
-rw-r--r--core/object_type_db.h47
-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.cpp67
-rw-r--r--core/os/dir_access.h6
-rw-r--r--core/os/file_access.cpp2
-rw-r--r--core/os/file_access.h2
-rw-r--r--core/os/input.cpp263
-rw-r--r--core/os/input.h76
-rw-r--r--core/os/input_event.cpp16
-rw-r--r--core/os/input_event.h6
-rw-r--r--core/os/keyboard.cpp107
-rw-r--r--core/os/keyboard.h3
-rw-r--r--core/os/main_loop.cpp32
-rw-r--r--core/os/main_loop.h4
-rw-r--r--core/os/memory.cpp9
-rw-r--r--core/os/memory.h19
-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.cpp178
-rw-r--r--core/os/memory_pool_dynamic_prealloc.h66
-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.cpp51
-rw-r--r--core/os/os.h80
-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.cpp2
-rw-r--r--core/os/thread.h2
-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.cpp322
-rw-r--r--core/path_remap.h80
-rw-r--r--core/pool_allocator.cpp2
-rw-r--r--core/pool_allocator.h2
-rw-r--r--core/print_string.cpp8
-rw-r--r--core/print_string.h5
-rw-r--r--core/ref_ptr.cpp2
-rw-r--r--core/ref_ptr.h2
-rw-r--r--core/reference.cpp6
-rw-r--r--core/reference.h6
-rw-r--r--core/register_core_types.cpp46
-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.cpp16
-rw-r--r--core/resource.h8
-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.cpp292
-rw-r--r--core/script_debugger_remote.h51
-rw-r--r--core/script_language.cpp35
-rw-r--r--core/script_language.h66
-rw-r--r--core/self_list.h2
-rw-r--r--core/set.h39
-rw-r--r--core/simple_type.h2
-rw-r--r--core/sort.h2
-rw-r--r--core/string_db.cpp24
-rw-r--r--core/string_db.h14
-rw-r--r--core/translation.cpp90
-rw-r--r--core/translation.h5
-rw-r--r--core/typedefs.h6
-rw-r--r--core/undo_redo.cpp170
-rw-r--r--core/undo_redo.h20
-rw-r--r--core/ustring.cpp640
-rw-r--r--core/ustring.h21
-rw-r--r--core/variant.cpp487
-rw-r--r--core/variant.h26
-rw-r--r--core/variant_call.cpp175
-rw-r--r--core/variant_call_bind.h2
-rw-r--r--core/variant_construct_string.cpp433
-rw-r--r--core/variant_op.cpp209
-rw-r--r--core/variant_parser.cpp1495
-rw-r--r--core/variant_parser.h103
-rw-r--r--core/vector.h61
-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/box_area.pngbin0 -> 1246 bytes
-rw-r--r--demos/2d/area_input/circle_area.pngbin0 -> 3030 bytes
-rw-r--r--demos/2d/area_input/engine.cfg5
-rw-r--r--demos/2d/area_input/icon.pngbin0 -> 3416 bytes
-rw-r--r--demos/2d/area_input/input.gd15
-rw-r--r--demos/2d/area_input/input.scnbin0 -> 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.cfg12
-rw-r--r--demos/2d/fog_of_war/floor.pngbin0 -> 572 bytes
-rw-r--r--demos/2d/fog_of_war/fog.gd78
-rw-r--r--demos/2d/fog_of_war/fog.pngbin0 -> 31448 bytes
-rw-r--r--demos/2d/fog_of_war/fog.scnbin0 -> 4159 bytes
-rw-r--r--demos/2d/fog_of_war/fog.xml29
-rw-r--r--demos/2d/fog_of_war/icon.pngbin0 -> 8681 bytes
-rw-r--r--demos/2d/fog_of_war/tile_edit.scnbin0 -> 1570 bytes
-rw-r--r--demos/2d/fog_of_war/troll.gd38
-rw-r--r--demos/2d/fog_of_war/troll.pngbin0 -> 7246 bytes
-rw-r--r--demos/2d/fog_of_war/troll.scnbin0 -> 1979 bytes
-rw-r--r--demos/2d/hdr/beach_cave.gd21
-rw-r--r--demos/2d/hdr/beach_cave.scnbin0 -> 4834 bytes
-rw-r--r--demos/2d/hdr/engine.cfg14
-rw-r--r--demos/2d/hdr/icon.pngbin0 -> 3962 bytes
-rw-r--r--demos/2d/hdr/ocean_beach.pngbin0 -> 443558 bytes
-rw-r--r--demos/2d/hdr/ocean_beach.png.flags1
-rw-r--r--demos/2d/hdr/ocean_cave.pngbin0 -> 745215 bytes
-rw-r--r--demos/2d/hdr/ocean_cave.png.flags1
-rw-r--r--demos/2d/hexamap/WWT-01.pngbin0 -> 20369 bytes
-rw-r--r--demos/2d/hexamap/WWT-02.pngbin0 -> 21993 bytes
-rw-r--r--demos/2d/hexamap/WWT-03.pngbin0 -> 22703 bytes
-rw-r--r--demos/2d/hexamap/WWT-04.pngbin0 -> 20615 bytes
-rw-r--r--demos/2d/hexamap/WWT-05.pngbin0 -> 22293 bytes
-rw-r--r--demos/2d/hexamap/WWT-06.pngbin0 -> 22971 bytes
-rw-r--r--demos/2d/hexamap/WWT-07.pngbin0 -> 22306 bytes
-rw-r--r--demos/2d/hexamap/WWT-08.pngbin0 -> 22084 bytes
-rw-r--r--demos/2d/hexamap/WWT-09.pngbin0 -> 22066 bytes
-rw-r--r--demos/2d/hexamap/WWT-10.pngbin0 -> 22019 bytes
-rw-r--r--demos/2d/hexamap/WWT-11.pngbin0 -> 21546 bytes
-rw-r--r--demos/2d/hexamap/WWT-12.pngbin0 -> 21405 bytes
-rw-r--r--demos/2d/hexamap/WWT-13.pngbin0 -> 19682 bytes
-rw-r--r--demos/2d/hexamap/WWT-14.pngbin0 -> 20491 bytes
-rw-r--r--demos/2d/hexamap/WWT-15.pngbin0 -> 21237 bytes
-rw-r--r--demos/2d/hexamap/WWT-16.pngbin0 -> 20673 bytes
-rw-r--r--demos/2d/hexamap/WWT-17.pngbin0 -> 20628 bytes
-rw-r--r--demos/2d/hexamap/WWT-18.pngbin0 -> 22559 bytes
-rw-r--r--demos/2d/hexamap/WWT-19.pngbin0 -> 21600 bytes
-rw-r--r--demos/2d/hexamap/WWT-20.pngbin0 -> 21130 bytes
-rw-r--r--demos/2d/hexamap/WWT-21.pngbin0 -> 21114 bytes
-rw-r--r--demos/2d/hexamap/WWT-22.pngbin0 -> 21440 bytes
-rw-r--r--demos/2d/hexamap/WWT-23.pngbin0 -> 20817 bytes
-rw-r--r--demos/2d/hexamap/WWT-24.pngbin0 -> 19964 bytes
-rw-r--r--demos/2d/hexamap/WWT-25.pngbin0 -> 20584 bytes
-rw-r--r--demos/2d/hexamap/WWT-26.pngbin0 -> 21405 bytes
-rw-r--r--demos/2d/hexamap/engine.cfg12
-rw-r--r--demos/2d/hexamap/icon.pngbin0 -> 5925 bytes
-rw-r--r--demos/2d/hexamap/map.scnbin0 -> 3517 bytes
-rw-r--r--demos/2d/hexamap/tiles.scnbin0 -> 2217 bytes
-rw-r--r--demos/2d/hexamap/tileset.resbin0 -> 6863 bytes
-rw-r--r--demos/2d/hexamap/troll.gd38
-rw-r--r--demos/2d/hexamap/troll.pngbin0 -> 7246 bytes
-rw-r--r--demos/2d/hexamap/troll.scnbin0 -> 1983 bytes
-rw-r--r--demos/2d/isometric/bastiles.resbin0 -> 2918 bytes
-rw-r--r--demos/2d/isometric/dungeon.scnbin0 -> 4708 bytes
-rw-r--r--demos/2d/isometric/engine.cfg21
-rw-r--r--demos/2d/isometric/icon.pngbin0 -> 9377 bytes
-rw-r--r--demos/2d/isometric/isotiles.pngbin0 -> 222339 bytes
-rw-r--r--demos/2d/isometric/tileset.scnbin0 -> 4476 bytes
-rw-r--r--demos/2d/isometric/troll.gd38
-rw-r--r--demos/2d/isometric/troll.pngbin0 -> 7246 bytes
-rw-r--r--demos/2d/isometric/troll.scnbin0 -> 2116 bytes
-rw-r--r--demos/2d/isometric_light/character_shder.resbin0 -> 1152 bytes
-rw-r--r--demos/2d/isometric_light/column.scnbin0 -> 2026 bytes
-rw-r--r--demos/2d/isometric_light/cubio.gd85
-rw-r--r--demos/2d/isometric_light/cubio.scnbin0 -> 6952 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0001.pngbin0 -> 7163 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0002.pngbin0 -> 7182 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0003.pngbin0 -> 7173 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0004.pngbin0 -> 7174 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0005.pngbin0 -> 7207 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0006.pngbin0 -> 7302 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0007.pngbin0 -> 7296 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0008.pngbin0 -> 7332 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0009.pngbin0 -> 7320 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0010.pngbin0 -> 7311 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0011.pngbin0 -> 7359 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0012.pngbin0 -> 7392 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0013.pngbin0 -> 7398 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0014.pngbin0 -> 7399 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0015.pngbin0 -> 7340 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0016.pngbin0 -> 7278 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0017.pngbin0 -> 7342 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0018.pngbin0 -> 7370 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0019.pngbin0 -> 7379 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0020.pngbin0 -> 7432 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0021.pngbin0 -> 7391 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0022.pngbin0 -> 7381 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0023.pngbin0 -> 7330 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0024.pngbin0 -> 7363 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0025.pngbin0 -> 7368 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0026.pngbin0 -> 7356 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0027.pngbin0 -> 7358 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0028.pngbin0 -> 7294 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0029.pngbin0 -> 7342 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0030.pngbin0 -> 7402 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0031.pngbin0 -> 7442 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0032.pngbin0 -> 7409 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0033.pngbin0 -> 7407 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0034.pngbin0 -> 7389 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0035.pngbin0 -> 7351 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0036.pngbin0 -> 7348 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0037.pngbin0 -> 7356 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0038.pngbin0 -> 7318 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0039.pngbin0 -> 7366 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0040.pngbin0 -> 7385 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0041.pngbin0 -> 7400 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0042.pngbin0 -> 7397 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0043.pngbin0 -> 7363 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0044.pngbin0 -> 7377 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0045.pngbin0 -> 7368 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0046.pngbin0 -> 7346 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0047.pngbin0 -> 7333 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0048.pngbin0 -> 7305 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0049.pngbin0 -> 7328 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0050.pngbin0 -> 7319 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0051.pngbin0 -> 7256 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0052.pngbin0 -> 7287 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0053.pngbin0 -> 7236 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0054.pngbin0 -> 7182 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0055.pngbin0 -> 7169 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0056.pngbin0 -> 7166 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0057.pngbin0 -> 7146 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0058.pngbin0 -> 7174 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0059.pngbin0 -> 7163 bytes
-rw-r--r--demos/2d/isometric_light/cubio/idle0060.pngbin0 -> 7163 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0001.pngbin0 -> 7027 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0002.pngbin0 -> 7234 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0003.pngbin0 -> 7658 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0004.pngbin0 -> 7999 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0005.pngbin0 -> 8086 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0006.pngbin0 -> 8004 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0007.pngbin0 -> 7759 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0008.pngbin0 -> 7485 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0009.pngbin0 -> 7066 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0010.pngbin0 -> 6925 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0011.pngbin0 -> 7003 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0012.pngbin0 -> 7316 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0013.pngbin0 -> 7607 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0014.pngbin0 -> 7924 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0015.pngbin0 -> 8000 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0016.pngbin0 -> 8025 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0017.pngbin0 -> 7918 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0018.pngbin0 -> 7532 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0019.pngbin0 -> 7247 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-b-0020.pngbin0 -> 7035 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0001.pngbin0 -> 7097 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0002.pngbin0 -> 7074 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0003.pngbin0 -> 7273 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0004.pngbin0 -> 7778 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0005.pngbin0 -> 7717 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0006.pngbin0 -> 8142 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0007.pngbin0 -> 8300 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0008.pngbin0 -> 8653 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0009.pngbin0 -> 8846 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0010.pngbin0 -> 8824 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0011.pngbin0 -> 8848 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0012.pngbin0 -> 8649 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0013.pngbin0 -> 8695 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0014.pngbin0 -> 8435 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0015.pngbin0 -> 8226 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0016.pngbin0 -> 7895 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0017.pngbin0 -> 7712 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0018.pngbin0 -> 7103 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0019.pngbin0 -> 7094 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-bl-0020.pngbin0 -> 7051 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0001.pngbin0 -> 8257 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0002.pngbin0 -> 7883 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0003.pngbin0 -> 6680 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0004.pngbin0 -> 6278 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0005.pngbin0 -> 6348 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0006.pngbin0 -> 5629 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0007.pngbin0 -> 6754 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0008.pngbin0 -> 7612 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0009.pngbin0 -> 8044 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0010.pngbin0 -> 8013 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0011.pngbin0 -> 7917 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0012.pngbin0 -> 7692 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0013.pngbin0 -> 6778 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0014.pngbin0 -> 6176 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0015.pngbin0 -> 6263 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0016.pngbin0 -> 6004 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0017.pngbin0 -> 6483 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0018.pngbin0 -> 7276 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0019.pngbin0 -> 7899 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-l-0020.pngbin0 -> 8119 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0001.pngbin0 -> 7095 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0002.pngbin0 -> 7064 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0003.pngbin0 -> 6854 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0004.pngbin0 -> 6801 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0005.pngbin0 -> 6900 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0006.pngbin0 -> 7017 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0007.pngbin0 -> 7128 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0008.pngbin0 -> 7065 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0009.pngbin0 -> 7000 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0010.pngbin0 -> 6980 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0011.pngbin0 -> 6978 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0012.pngbin0 -> 7139 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0013.pngbin0 -> 7191 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0014.pngbin0 -> 7119 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0015.pngbin0 -> 7051 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0016.pngbin0 -> 6995 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0017.pngbin0 -> 6832 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0018.pngbin0 -> 6962 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0019.pngbin0 -> 7049 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-u-0020.pngbin0 -> 7067 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0001.pngbin0 -> 8202 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0002.pngbin0 -> 8074 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0003.pngbin0 -> 7716 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0004.pngbin0 -> 7587 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0005.pngbin0 -> 7383 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0006.pngbin0 -> 7107 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0007.pngbin0 -> 6671 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0008.pngbin0 -> 6847 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0009.pngbin0 -> 6892 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0010.pngbin0 -> 6858 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0011.pngbin0 -> 7067 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0012.pngbin0 -> 6985 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0013.pngbin0 -> 6600 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0014.pngbin0 -> 7104 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0015.pngbin0 -> 7320 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0016.pngbin0 -> 7478 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0017.pngbin0 -> 7736 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0018.pngbin0 -> 7960 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0019.pngbin0 -> 7982 bytes
-rw-r--r--demos/2d/isometric_light/cubio/norm-ul-0020.pngbin0 -> 8137 bytes
-rw-r--r--demos/2d/isometric_light/energy.pngbin0 -> 6968 bytes
-rw-r--r--demos/2d/isometric_light/engine.cfg20
-rw-r--r--demos/2d/isometric_light/faceColor.pngbin0 -> 47941 bytes
-rw-r--r--demos/2d/isometric_light/faceMask.pngbin0 -> 3106 bytes
-rw-r--r--demos/2d/isometric_light/faceNormal.pngbin0 -> 54844 bytes
-rw-r--r--demos/2d/isometric_light/fire.pngbin0 -> 8116 bytes
-rw-r--r--demos/2d/isometric_light/floor_shader.resbin0 -> 1027 bytes
-rw-r--r--demos/2d/isometric_light/icon.pngbin0 -> 7675 bytes
-rw-r--r--demos/2d/isometric_light/light2.pngbin0 -> 3500 bytes
-rw-r--r--demos/2d/isometric_light/map.gd7
-rw-r--r--demos/2d/isometric_light/map.scnbin0 -> 9352 bytes
-rw-r--r--demos/2d/isometric_light/shadow_blob.pngbin0 -> 884 bytes
-rw-r--r--demos/2d/isometric_light/shoot.gd21
-rw-r--r--demos/2d/isometric_light/shoot.scnbin0 -> 4111 bytes
-rw-r--r--demos/2d/isometric_light/shoot_halo.pngbin0 -> 91312 bytes
-rw-r--r--demos/2d/isometric_light/tileset.resbin0 -> 2779 bytes
-rw-r--r--demos/2d/isometric_light/tileset_scene.scnbin0 -> 5339 bytes
-rw-r--r--demos/2d/isometric_light/torch.scnbin0 -> 3861 bytes
-rw-r--r--demos/2d/isometric_light/torch_light.pngbin0 -> 1262 bytes
-rw-r--r--demos/2d/isometric_light/torch_shader.resbin0 -> 746 bytes
-rw-r--r--demos/2d/isometric_light/wall_shader.resbin0 -> 1687 bytes
-rw-r--r--demos/2d/kinematic_char/circle.pngbin0 -> 6107 bytes
-rw-r--r--demos/2d/kinematic_char/colworld.gd17
-rw-r--r--demos/2d/kinematic_char/colworld.scnbin5090 -> 7366 bytes
-rw-r--r--demos/2d/kinematic_char/engine.cfg9
-rw-r--r--demos/2d/kinematic_char/long_obstacle.pngbin0 -> 534 bytes
-rw-r--r--demos/2d/kinematic_char/player.gd157
-rw-r--r--demos/2d/kinematic_char/player.scnbin1511 -> 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/burano.pngbin0 -> 974437 bytes
-rw-r--r--demos/2d/light_mask/engine.cfg9
-rw-r--r--demos/2d/light_mask/icon.pngbin0 -> 6285 bytes
-rw-r--r--demos/2d/light_mask/lightmask.scnbin0 -> 3829 bytes
-rw-r--r--demos/2d/light_mask/splat.pngbin0 -> 18255 bytes
-rw-r--r--demos/2d/lights_shadows/bg.pngbin0 -> 294 bytes
-rw-r--r--demos/2d/lights_shadows/caster.pngbin0 -> 122 bytes
-rw-r--r--demos/2d/lights_shadows/engine.cfg16
-rw-r--r--demos/2d/lights_shadows/icon.pngbin0 -> 3988 bytes
-rw-r--r--demos/2d/lights_shadows/light.pngbin0 -> 243776 bytes
-rw-r--r--demos/2d/lights_shadows/light_shadows.scnbin0 -> 4978 bytes
-rw-r--r--demos/2d/lights_shadows/spot.pngbin0 -> 3699 bytes
-rw-r--r--demos/2d/lookat/arrow.pngbin0 -> 2528 bytes
-rw-r--r--demos/2d/lookat/engine.cfg5
-rw-r--r--demos/2d/lookat/icon.pngbin0 -> 1495 bytes
-rw-r--r--demos/2d/lookat/lookat.gd33
-rw-r--r--demos/2d/lookat/lookat.scnbin0 -> 1640 bytes
-rw-r--r--demos/2d/motion/car.pngbin0 -> 2086 bytes
-rw-r--r--demos/2d/motion/engine.cfg12
-rw-r--r--demos/2d/motion/icon.pngbin0 -> 2621 bytes
-rw-r--r--demos/2d/motion/motion.gd33
-rw-r--r--demos/2d/motion/motion.scnbin0 -> 2738 bytes
-rw-r--r--demos/2d/navpoly/agent.pngbin0 -> 2508 bytes
-rw-r--r--demos/2d/navpoly/engine.cfg12
-rw-r--r--demos/2d/navpoly/icon.pngbin0 -> 3642 bytes
-rw-r--r--demos/2d/navpoly/navigation.gd53
-rw-r--r--demos/2d/navpoly/navigation.scnbin0 -> 5128 bytes
-rw-r--r--demos/2d/navpoly/path.pngbin0 -> 309506 bytes
-rw-r--r--demos/2d/normalmaps/diffuse.jpgbin0 -> 535660 bytes
-rw-r--r--demos/2d/normalmaps/diffuse.pngbin0 -> 2392221 bytes
-rw-r--r--demos/2d/normalmaps/engine.cfg12
-rw-r--r--demos/2d/normalmaps/icon.pngbin0 -> 10402 bytes
-rw-r--r--demos/2d/normalmaps/light.pngbin0 -> 243776 bytes
-rw-r--r--demos/2d/normalmaps/normal.pngbin0 -> 2301245 bytes
-rw-r--r--demos/2d/normalmaps/normal_material.resbin0 -> 503 bytes
-rw-r--r--demos/2d/normalmaps/normalmap.scnbin0 -> 3168 bytes
-rw-r--r--demos/2d/particles/particles.xml263
-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.gd93
-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.pngbin0 -> 2287 bytes
-rw-r--r--demos/2d/platformer/one_way_platform.xml207
-rw-r--r--demos/2d/platformer/parallax_bg.xml258
-rw-r--r--demos/2d/platformer/player.gd235
-rw-r--r--demos/2d/platformer/player.xml464
-rw-r--r--demos/2d/platformer/seesaw.xml207
-rw-r--r--demos/2d/platformer/stage.xml297
-rw-r--r--demos/2d/platformer/tiles_demo.pngbin11736 -> 10066 bytes
-rw-r--r--demos/2d/platformer/tiles_demo.png.flags1
-rw-r--r--demos/2d/platformer/tileset.xml185
-rw-r--r--demos/2d/platformer/tileset_edit.xml295
-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/art/burano.jpgbin0 -> 246589 bytes
-rw-r--r--demos/2d/screen_space_shaders/art/burano.pngbin0 -> 974437 bytes
-rw-r--r--demos/2d/screen_space_shaders/art/filmgrain.pngbin0 -> 290595 bytes
-rw-r--r--demos/2d/screen_space_shaders/art/filmgrain.png.flags1
-rw-r--r--demos/2d/screen_space_shaders/art/forest.pngbin0 -> 1199433 bytes
-rw-r--r--demos/2d/screen_space_shaders/art/mountains.pngbin0 -> 927435 bytes
-rw-r--r--demos/2d/screen_space_shaders/art/platformer.pngbin0 -> 44102 bytes
-rw-r--r--demos/2d/screen_space_shaders/art/vignette.pngbin0 -> 4075 bytes
-rw-r--r--demos/2d/screen_space_shaders/art/white.pngbin0 -> 174 bytes
-rw-r--r--demos/2d/screen_space_shaders/engine.cfg12
-rw-r--r--demos/2d/screen_space_shaders/icon.pngbin0 -> 7479 bytes
-rw-r--r--demos/2d/screen_space_shaders/screen_shaders.gd25
-rw-r--r--demos/2d/screen_space_shaders/screen_shaders.scnbin0 -> 7562 bytes
-rw-r--r--demos/2d/sdf_font/KaushanScript-Regular.otfbin0 -> 89168 bytes
-rw-r--r--demos/2d/sdf_font/engine.cfg5
-rw-r--r--demos/2d/sdf_font/font.fntbin0 -> 180332 bytes
-rw-r--r--demos/2d/sdf_font/icon.pngbin0 -> 3560 bytes
-rw-r--r--demos/2d/sdf_font/sdf.scnbin0 -> 2820 bytes
-rw-r--r--demos/2d/shower_of_bullets/bullet.pngbin0 -> 477 bytes
-rw-r--r--demos/2d/shower_of_bullets/bullets.gd71
-rw-r--r--demos/2d/shower_of_bullets/engine.cfg16
-rw-r--r--demos/2d/shower_of_bullets/face_happy.pngbin0 -> 1243 bytes
-rw-r--r--demos/2d/shower_of_bullets/face_sad.pngbin0 -> 1240 bytes
-rw-r--r--demos/2d/shower_of_bullets/icon.pngbin0 -> 2777 bytes
-rw-r--r--demos/2d/shower_of_bullets/shower.gd25
-rw-r--r--demos/2d/shower_of_bullets/shower.scnbin0 -> 1909 bytes
-rw-r--r--demos/2d/space_shooter/asteroid.gd43
-rw-r--r--demos/2d/space_shooter/asteroid.scnbin0 -> 3548 bytes
-rw-r--r--demos/2d/space_shooter/bg_gradient.pngbin0 -> 1572 bytes
-rw-r--r--demos/2d/space_shooter/big_star.pngbin0 -> 275 bytes
-rw-r--r--demos/2d/space_shooter/enemy1.gd36
-rw-r--r--demos/2d/space_shooter/enemy1.pngbin0 -> 7048 bytes
-rw-r--r--demos/2d/space_shooter/enemy1.scnbin0 -> 3369 bytes
-rw-r--r--demos/2d/space_shooter/enemy2.gd51
-rw-r--r--demos/2d/space_shooter/enemy2.pngbin0 -> 5676 bytes
-rw-r--r--demos/2d/space_shooter/enemy2.scnbin0 -> 3253 bytes
-rw-r--r--demos/2d/space_shooter/enemy_shot.gd31
-rw-r--r--demos/2d/space_shooter/enemy_shot.pngbin0 -> 330 bytes
-rw-r--r--demos/2d/space_shooter/enemy_shot.scnbin0 -> 3218 bytes
-rw-r--r--demos/2d/space_shooter/engine.cfg22
-rw-r--r--demos/2d/space_shooter/explosion.scnbin0 -> 1756 bytes
-rw-r--r--demos/2d/space_shooter/fire.pngbin0 -> 357 bytes
-rw-r--r--demos/2d/space_shooter/game_state.gd22
-rw-r--r--demos/2d/space_shooter/icon.pngbin0 -> 6931 bytes
-rw-r--r--demos/2d/space_shooter/level.scnbin0 -> 6496 bytes
-rw-r--r--demos/2d/space_shooter/level_tiles.resbin0 -> 720 bytes
-rw-r--r--demos/2d/space_shooter/level_tiles.scnbin0 -> 1825 bytes
-rw-r--r--demos/2d/space_shooter/main_menu.gd11
-rw-r--r--demos/2d/space_shooter/main_menu.scnbin0 -> 1903 bytes
-rw-r--r--demos/2d/space_shooter/meteorite.pngbin0 -> 6072 bytes
-rw-r--r--demos/2d/space_shooter/parallax.scnbin0 -> 2814 bytes
-rw-r--r--demos/2d/space_shooter/rail.gd19
-rw-r--r--demos/2d/space_shooter/ship.gd81
-rw-r--r--demos/2d/space_shooter/ship.pngbin0 -> 2815 bytes
-rw-r--r--demos/2d/space_shooter/ship.scnbin0 -> 4965 bytes
-rw-r--r--demos/2d/space_shooter/shoot.pngbin0 -> 222 bytes
-rw-r--r--demos/2d/space_shooter/shot.gd40
-rw-r--r--demos/2d/space_shooter/shot.scnbin0 -> 3315 bytes
-rw-r--r--demos/2d/space_shooter/small_star.pngbin0 -> 90 bytes
-rw-r--r--demos/2d/space_shooter/sound_explode.wavbin0 -> 75832 bytes
-rw-r--r--demos/2d/space_shooter/sound_shoot.wavbin0 -> 78888 bytes
-rw-r--r--demos/2d/space_shooter/tile.pngbin0 -> 810 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/cubio.pngbin0 -> 26579 bytes
-rw-r--r--demos/2d/sprite_shaders/engine.cfg5
-rw-r--r--demos/2d/sprite_shaders/icon.pngbin0 -> 8209 bytes
-rw-r--r--demos/2d/sprite_shaders/sprite_shaders.scnbin0 -> 5477 bytes
-rw-r--r--demos/2d/tetris/grid.gd218
-rw-r--r--demos/2d/tetris/grid.xml252
-rw-r--r--demos/2d/tetris/tetris.xml252
-rw-r--r--demos/2d/texscreen/OpenCV_Chessboard.pngbin0 -> 44884 bytes
-rw-r--r--demos/2d/texscreen/bubble.pngbin0 -> 18619 bytes
-rw-r--r--demos/2d/texscreen/bubbles.gd11
-rw-r--r--demos/2d/texscreen/bubbles.scnbin0 -> 2626 bytes
-rw-r--r--demos/2d/texscreen/burano.pngbin0 -> 974437 bytes
-rw-r--r--demos/2d/texscreen/engine.cfg12
-rw-r--r--demos/2d/texscreen/icon.pngbin0 -> 9245 bytes
-rw-r--r--demos/2d/texscreen/lens.gd32
-rw-r--r--demos/2d/texscreen/lens.scnbin0 -> 1850 bytes
-rw-r--r--demos/3d/fixed_materials/fixed_materials.scnbin6071 -> 8271 bytes
-rw-r--r--demos/3d/kinematic_char/cubelib.resbin0 -> 11532 bytes
-rw-r--r--demos/3d/kinematic_char/cubio.gd86
-rw-r--r--demos/3d/kinematic_char/engine.cfg17
-rw-r--r--demos/3d/kinematic_char/follow_camera.gd57
-rw-r--r--demos/3d/kinematic_char/kinebody3d.pngbin0 -> 6078 bytes
-rw-r--r--demos/3d/kinematic_char/level.scnbin0 -> 18847 bytes
-rw-r--r--demos/3d/kinematic_char/purple_wood.texbin0 -> 173520 bytes
-rw-r--r--demos/3d/kinematic_char/purplecube.scnbin0 -> 7927 bytes
-rw-r--r--demos/3d/kinematic_char/twood.texbin0 -> 168054 bytes
-rw-r--r--demos/3d/kinematic_char/white_wood.texbin0 -> 169001 bytes
-rw-r--r--demos/3d/mousepick_test/engine.cfg5
-rw-r--r--demos/3d/mousepick_test/icon.pngbin0 -> 2451 bytes
-rw-r--r--demos/3d/mousepick_test/mousepick.gd24
-rw-r--r--demos/3d/mousepick_test/mousepick.scnbin0 -> 40434 bytes
-rw-r--r--demos/3d/navmesh/engine.cfg9
-rw-r--r--demos/3d/navmesh/icon.pngbin0 -> 4902 bytes
-rw-r--r--demos/3d/navmesh/navmesh.gd95
-rw-r--r--demos/3d/navmesh/navmesh.scnbin0 -> 40827 bytes
-rw-r--r--demos/3d/navmesh/particle.pngbin0 -> 260 bytes
-rw-r--r--demos/3d/platformer/bullet.gd13
-rw-r--r--demos/3d/platformer/bullet.scnbin5465 -> 7303 bytes
-rw-r--r--demos/3d/platformer/coin.gd18
-rw-r--r--demos/3d/platformer/coin.scnbin6013 -> 7785 bytes
-rw-r--r--demos/3d/platformer/enemy.gd62
-rw-r--r--demos/3d/platformer/enemy.scnbin36976 -> 39181 bytes
-rw-r--r--demos/3d/platformer/engine.cfg2
-rw-r--r--demos/3d/platformer/follow_camera.gd94
-rw-r--r--demos/3d/platformer/player.gd212
-rw-r--r--demos/3d/platformer/player.scnbin0 -> 108067 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.xml356
-rw-r--r--demos/3d/platformer/texture.texbin29600 -> 18209 bytes
-rw-r--r--demos/3d/platformer/tiles.resbin81338 -> 81631 bytes
-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.scnbin5494 -> 9892 bytes
-rw-r--r--demos/3d/truck_town/car_base.scnbin0 -> 13459 bytes
-rw-r--r--demos/3d/truck_town/car_select.gd32
-rw-r--r--demos/3d/truck_town/car_select.scnbin0 -> 1968 bytes
-rw-r--r--demos/3d/truck_town/cement.texbin0 -> 169836 bytes
-rw-r--r--demos/3d/truck_town/choose_tow.pngbin0 -> 20702 bytes
-rw-r--r--demos/3d/truck_town/choose_trailer.pngbin0 -> 15646 bytes
-rw-r--r--demos/3d/truck_town/choose_van.pngbin0 -> 10106 bytes
-rw-r--r--demos/3d/truck_town/crane.scnbin0 -> 26350 bytes
-rw-r--r--demos/3d/truck_town/engine.cfg14
-rw-r--r--demos/3d/truck_town/follow_camera.gd57
-rw-r--r--demos/3d/truck_town/grass.texbin0 -> 177762 bytes
-rw-r--r--demos/3d/truck_town/icon.pngbin0 -> 6878 bytes
-rw-r--r--demos/3d/truck_town/trailer_truck.scnbin0 -> 22400 bytes
-rw-r--r--demos/3d/truck_town/truck_scene.scnbin0 -> 1889480 bytes
-rw-r--r--demos/3d/truck_town/trucktown.scnbin0 -> 165689 bytes
-rw-r--r--demos/3d/truck_town/vehicle.gd45
-rw-r--r--demos/gui/drag_and_drop/drag_and_drop.scnbin0 -> 2947 bytes
-rw-r--r--demos/gui/drag_and_drop/drag_drop_script.gd20
-rw-r--r--demos/gui/drag_and_drop/engine.cfg5
-rw-r--r--demos/gui/drag_and_drop/icon.pngbin0 -> 806 bytes
-rw-r--r--demos/gui/input_mapping/controls.gd54
-rw-r--r--demos/gui/input_mapping/controls.scnbin0 -> 2698 bytes
-rw-r--r--demos/gui/input_mapping/engine.cfg18
-rw-r--r--demos/gui/input_mapping/icon.pngbin0 -> 1503 bytes
-rw-r--r--demos/gui/rich_text_bbcode/OFL.txt92
-rw-r--r--demos/gui/rich_text_bbcode/TitilliumWeb-Bold.ttfbin0 -> 59908 bytes
-rw-r--r--demos/gui/rich_text_bbcode/TitilliumWeb-BoldItalic.ttfbin0 -> 69796 bytes
-rw-r--r--demos/gui/rich_text_bbcode/TitilliumWeb-Italic.ttfbin0 -> 72416 bytes
-rw-r--r--demos/gui/rich_text_bbcode/TitilliumWeb-Regular.ttfbin0 -> 63752 bytes
-rw-r--r--demos/gui/rich_text_bbcode/engine.cfg5
-rw-r--r--demos/gui/rich_text_bbcode/icon.pngbin0 -> 4304 bytes
-rw-r--r--demos/gui/rich_text_bbcode/rich_text_bbcode.gd6
-rw-r--r--demos/gui/rich_text_bbcode/rich_text_bbcode.scnbin0 -> 3217 bytes
-rw-r--r--demos/gui/rich_text_bbcode/titilium-bold.fntbin0 -> 36224 bytes
-rw-r--r--demos/gui/rich_text_bbcode/titilium-bolditalic.fntbin0 -> 36814 bytes
-rw-r--r--demos/gui/rich_text_bbcode/titilium-italic.fntbin0 -> 35274 bytes
-rw-r--r--demos/gui/rich_text_bbcode/titilium-regular.fntbin0 -> 34511 bytes
-rw-r--r--demos/gui/rich_text_bbcode/unicorn_icon.pngbin0 -> 850 bytes
-rw-r--r--demos/gui/translation/controls.gd9
-rw-r--r--demos/gui/translation/controls.scnbin0 -> 2272 bytes
-rw-r--r--demos/gui/translation/engine.cfg10
-rw-r--r--demos/gui/translation/flag_japan.pngbin0 -> 1473 bytes
-rw-r--r--demos/gui/translation/flag_spain.pngbin0 -> 3048 bytes
-rw-r--r--demos/gui/translation/flag_uk.pngbin0 -> 6544 bytes
-rw-r--r--demos/gui/translation/icon.pngbin0 -> 2557 bytes
-rw-r--r--demos/gui/translation/main.gd32
-rw-r--r--demos/gui/translation/main.scnbin0 -> 2939 bytes
-rw-r--r--demos/gui/translation/noto.fntbin0 -> 9171 bytes
-rw-r--r--demos/gui/translation/notosans.otfbin0 -> 16426032 bytes
-rw-r--r--demos/gui/translation/text.csv3
-rw-r--r--demos/gui/translation/translations/text.en.xlbin0 -> 575 bytes
-rw-r--r--demos/gui/translation/translations/text.es.xlbin0 -> 579 bytes
-rw-r--r--demos/gui/translation/translations/text.ja.xlbin0 -> 595 bytes
-rw-r--r--demos/misc/autoload/global.gd42
-rw-r--r--demos/misc/autoload/scene_a.gd7
-rw-r--r--demos/misc/autoload/scene_a.scnbin1459 -> 1660 bytes
-rw-r--r--demos/misc/autoload/scene_b.gd7
-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/engine.cfg10
-rw-r--r--demos/misc/joysticks/icon.pngbin0 -> 2916 bytes
-rw-r--r--demos/misc/joysticks/joysticks.gd43
-rw-r--r--demos/misc/joysticks/joysticks.scnbin0 -> 4016 bytes
-rw-r--r--demos/misc/pause/spinpause.gd6
-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/engine.cfg4
-rw-r--r--demos/misc/scene_changer/scene_a.gd16
-rw-r--r--demos/misc/scene_changer/scene_a.scnbin0 -> 1660 bytes
-rw-r--r--demos/misc/scene_changer/scene_b.gd16
-rw-r--r--demos/misc/scene_changer/scene_b.scnbin0 -> 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.cfg11
-rw-r--r--demos/misc/tween/icon.pngbin0 -> 2831 bytes
-rw-r--r--demos/misc/tween/main.gd165
-rw-r--r--demos/misc/tween/main.scnbin0 -> 5216 bytes
-rw-r--r--demos/misc/udp_chat/chat.gd66
-rw-r--r--demos/misc/udp_chat/chat.scnbin0 -> 3359 bytes
-rw-r--r--demos/misc/udp_chat/engine.cfg5
-rw-r--r--demos/misc/udp_chat/icon.pngbin0 -> 2388 bytes
-rw-r--r--demos/misc/window_management/control.gd186
-rw-r--r--demos/misc/window_management/engine.cfg19
-rw-r--r--demos/misc/window_management/icon.pngbin0 -> 4210 bytes
-rw-r--r--demos/misc/window_management/observer/observer.gd78
-rw-r--r--demos/misc/window_management/observer/observer.scnbin0 -> 3824 bytes
-rw-r--r--demos/misc/window_management/window_management.scnbin0 -> 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.gd69
-rw-r--r--demos/viewport/gui_in_3d/gui_3d.scnbin3498 -> 6137 bytes
-rw-r--r--demos/viewport/gui_in_3d/icon.pngbin0 -> 3770 bytes
-rw-r--r--demos/viewport/screen_capture/engine.cfg9
-rw-r--r--demos/viewport/screen_capture/icon.pngbin0 -> 7350 bytes
-rw-r--r--demos/viewport/screen_capture/mountains.pngbin0 -> 927435 bytes
-rw-r--r--demos/viewport/screen_capture/screen_capture.gd16
-rw-r--r--demos/viewport/screen_capture/screen_capture.scnbin0 -> 3482 bytes
-rw-r--r--doc/base/classes.xml20978
-rw-r--r--doc/core_classes.xml4
-rw-r--r--doc/engine_classes.xml4060
-rw-r--r--drivers/SCsub190
-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_openssl/SCsub646
-rw-r--r--drivers/builtin_openssl/crypto/asn1/a_strnid.c290
-rw-r--r--drivers/builtin_openssl/crypto/bio/bss_dgram.c1865
-rw-r--r--drivers/builtin_openssl/crypto/bn/bn_mont.c509
-rw-r--r--drivers/builtin_openssl/crypto/cms/cms_env.c876
-rw-r--r--drivers/builtin_openssl/crypto/cms/cms_sd.c985
-rw-r--r--drivers/builtin_openssl/crypto/cms/cms_smime.c850
-rw-r--r--drivers/builtin_openssl/crypto/dso/dso_dlfcn.c484
-rw-r--r--drivers/builtin_openssl/crypto/dso/dso_vms.c525
-rw-r--r--drivers/builtin_openssl/crypto/ec/ec_ameth.c660
-rw-r--r--drivers/builtin_openssl/crypto/ec/ec_asn1.c1445
-rw-r--r--drivers/builtin_openssl/crypto/ec/ec_lcl.h446
-rw-r--r--drivers/builtin_openssl/crypto/evp/bio_b64.c598
-rw-r--r--drivers/builtin_openssl/crypto/evp/e_dsa.c73
-rw-r--r--drivers/builtin_openssl/crypto/evp/encode.c445
-rw-r--r--drivers/builtin_openssl/crypto/md5/md5.h127
-rw-r--r--drivers/builtin_openssl/crypto/md5/md5_locl.h130
-rw-r--r--drivers/builtin_openssl/crypto/o_str.c113
-rw-r--r--drivers/builtin_openssl/crypto/opensslconf.h283
-rw-r--r--drivers/builtin_openssl/crypto/opensslv.h89
-rw-r--r--drivers/builtin_openssl/crypto/pkcs12/p12_crt.c366
-rw-r--r--drivers/builtin_openssl/crypto/pkcs12/p12_kiss.c302
-rw-r--r--drivers/builtin_openssl/crypto/pkcs7/pk7_doit.c1299
-rw-r--r--drivers/builtin_openssl/crypto/pkcs7/pkcs7.h499
-rw-r--r--drivers/builtin_openssl/crypto/pkcs7/pkcs7err.c187
-rw-r--r--drivers/builtin_openssl/crypto/rand/rand.h150
-rw-r--r--drivers/builtin_openssl/crypto/rsa/rsa_ameth.c698
-rw-r--r--drivers/builtin_openssl/crypto/rsa/rsa_sign.c319
-rw-r--r--drivers/builtin_openssl/crypto/srp/srp_vfy.c658
-rw-r--r--drivers/builtin_openssl/crypto/ts/ts_rsp_verify.c728
-rw-r--r--drivers/builtin_openssl/crypto/x509v3/v3_purp.c767
-rw-r--r--drivers/builtin_openssl/e_os.h743
-rw-r--r--drivers/builtin_openssl/openssl/aes.h147
-rw-r--r--drivers/builtin_openssl/openssl/asn1.h1404
-rw-r--r--drivers/builtin_openssl/openssl/asn1_mac.h578
-rw-r--r--drivers/builtin_openssl/openssl/asn1t.h960
-rw-r--r--drivers/builtin_openssl/openssl/bio.h847
-rw-r--r--drivers/builtin_openssl/openssl/blowfish.h129
-rw-r--r--drivers/builtin_openssl/openssl/bn.h902
-rw-r--r--drivers/builtin_openssl/openssl/buffer.h119
-rw-r--r--drivers/builtin_openssl/openssl/camellia.h130
-rw-r--r--drivers/builtin_openssl/openssl/cast.h107
-rw-r--r--drivers/builtin_openssl/openssl/cmac.h82
-rw-r--r--drivers/builtin_openssl/openssl/cms.h501
-rw-r--r--drivers/builtin_openssl/openssl/comp.h80
-rw-r--r--drivers/builtin_openssl/openssl/conf.h263
-rw-r--r--drivers/builtin_openssl/openssl/conf_api.h89
-rw-r--r--drivers/builtin_openssl/openssl/crypto.h611
-rw-r--r--drivers/builtin_openssl/openssl/des.h248
-rw-r--r--drivers/builtin_openssl/openssl/des_old.h446
-rw-r--r--drivers/builtin_openssl/openssl/dh.h280
-rw-r--r--drivers/builtin_openssl/openssl/dsa.h327
-rw-r--r--drivers/builtin_openssl/openssl/dso.h409
-rw-r--r--drivers/builtin_openssl/openssl/dtls1.h288
-rw-r--r--drivers/builtin_openssl/openssl/e_os2.h315
-rw-r--r--drivers/builtin_openssl/openssl/ebcdic.h19
-rw-r--r--drivers/builtin_openssl/openssl/ec.h1167
-rw-r--r--drivers/builtin_openssl/openssl/ecdh.h125
-rw-r--r--drivers/builtin_openssl/openssl/ecdsa.h260
-rw-r--r--drivers/builtin_openssl/openssl/engine.h842
-rw-r--r--drivers/builtin_openssl/openssl/err.h386
-rw-r--r--drivers/builtin_openssl/openssl/evp.h1409
-rw-r--r--drivers/builtin_openssl/openssl/hmac.h110
-rw-r--r--drivers/builtin_openssl/openssl/idea.h103
-rw-r--r--drivers/builtin_openssl/openssl/krb5_asn.h256
-rw-r--r--drivers/builtin_openssl/openssl/lhash.h241
-rw-r--r--drivers/builtin_openssl/openssl/md4.h120
-rw-r--r--drivers/builtin_openssl/openssl/md5.h127
-rw-r--r--drivers/builtin_openssl/openssl/mdc2.h98
-rw-r--r--drivers/builtin_openssl/openssl/modes.h135
-rw-r--r--drivers/builtin_openssl/openssl/obj_mac.h4032
-rw-r--r--drivers/builtin_openssl/openssl/objects.h1138
-rw-r--r--drivers/builtin_openssl/openssl/ocsp.h623
-rw-r--r--drivers/builtin_openssl/openssl/opensslv.h89
-rw-r--r--drivers/builtin_openssl/openssl/ossl_typ.h202
-rw-r--r--drivers/builtin_openssl/openssl/pem.h641
-rw-r--r--drivers/builtin_openssl/openssl/pem2.h70
-rw-r--r--drivers/builtin_openssl/openssl/pkcs12.h331
-rw-r--r--drivers/builtin_openssl/openssl/pkcs7.h499
-rw-r--r--drivers/builtin_openssl/openssl/pqueue.h94
-rw-r--r--drivers/builtin_openssl/openssl/rand.h151
-rw-r--r--drivers/builtin_openssl/openssl/rc2.h103
-rw-r--r--drivers/builtin_openssl/openssl/rc4.h90
-rw-r--r--drivers/builtin_openssl/openssl/ripemd.h107
-rw-r--r--drivers/builtin_openssl/openssl/rsa.h582
-rw-r--r--drivers/builtin_openssl/openssl/safestack.h2663
-rw-r--r--drivers/builtin_openssl/openssl/seed.h139
-rw-r--r--drivers/builtin_openssl/openssl/sha.h214
-rw-r--r--drivers/builtin_openssl/openssl/srp.h172
-rw-r--r--drivers/builtin_openssl/openssl/ssl.h2588
-rw-r--r--drivers/builtin_openssl/openssl/ssl3.h693
-rw-r--r--drivers/builtin_openssl/openssl/stack.h108
-rw-r--r--drivers/builtin_openssl/openssl/symhacks.h481
-rw-r--r--drivers/builtin_openssl/openssl/ts.h858
-rw-r--r--drivers/builtin_openssl/openssl/txt_db.h112
-rw-r--r--drivers/builtin_openssl/openssl/ui.h383
-rw-r--r--drivers/builtin_openssl/openssl/ui_compat.h83
-rw-r--r--drivers/builtin_openssl/openssl/whrlpool.h41
-rw-r--r--drivers/builtin_openssl/openssl/x509.h1297
-rw-r--r--drivers/builtin_openssl/openssl/x509_vfy.h567
-rw-r--r--drivers/builtin_openssl/openssl/x509v3.h1011
-rw-r--r--drivers/builtin_openssl/ssl/Makefile1061
-rw-r--r--drivers/builtin_openssl/ssl/Makefile.save1061
-rw-r--r--drivers/builtin_openssl/ssl/d1_both.c1608
-rw-r--r--drivers/builtin_openssl/ssl/d1_lib.c483
-rw-r--r--drivers/builtin_openssl/ssl/d1_pkt.c1900
-rw-r--r--drivers/builtin_openssl/ssl/d1_srvr.c1722
-rw-r--r--drivers/builtin_openssl/ssl/dtls1.h287
-rw-r--r--drivers/builtin_openssl/ssl/kssl.h192
-rw-r--r--drivers/builtin_openssl/ssl/s3_clnt.c3372
-rw-r--r--drivers/builtin_openssl/ssl/s3_pkt.c1529
-rw-r--r--drivers/builtin_openssl/ssl/s3_srvr.c3593
-rw-r--r--drivers/builtin_openssl/ssl/srtp.h145
-rw-r--r--drivers/builtin_openssl/ssl/ssl-lib.com1214
-rw-r--r--drivers/builtin_openssl/ssl/ssl.h2588
-rw-r--r--drivers/builtin_openssl/ssl/ssl2.h272
-rw-r--r--drivers/builtin_openssl/ssl/ssl23.h83
-rw-r--r--drivers/builtin_openssl/ssl/ssl3.h693
-rw-r--r--drivers/builtin_openssl/ssl/ssl_asn1.c642
-rw-r--r--drivers/builtin_openssl/ssl/ssl_cert.c863
-rw-r--r--drivers/builtin_openssl/ssl/ssl_err.c610
-rw-r--r--drivers/builtin_openssl/ssl/ssl_lib.c3265
-rw-r--r--drivers/builtin_openssl/ssl/t1_enc.c1254
-rw-r--r--drivers/builtin_openssl/ssl/t1_lib.c2729
-rw-r--r--drivers/builtin_openssl/ssl/tls1.h741
-rw-r--r--drivers/builtin_openssl2/SCsub646
-rw-r--r--drivers/builtin_openssl2/buildinf.h (renamed from drivers/builtin_openssl/buildinf.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/LPdir_nyi.c (renamed from drivers/builtin_openssl/crypto/LPdir_nyi.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/LPdir_unix.c (renamed from drivers/builtin_openssl/crypto/LPdir_unix.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/LPdir_vms.c (renamed from drivers/builtin_openssl/crypto/LPdir_vms.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/LPdir_win.c (renamed from drivers/builtin_openssl/crypto/LPdir_win.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/LPdir_win32.c (renamed from drivers/builtin_openssl/crypto/LPdir_win32.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/LPdir_wince.c (renamed from drivers/builtin_openssl/crypto/LPdir_wince.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/README (renamed from drivers/builtin_openssl/crypto/aes/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_cbc.c (renamed from drivers/builtin_openssl/crypto/aes/aes_cbc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_cfb.c (renamed from drivers/builtin_openssl/crypto/aes/aes_cfb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_core.c (renamed from drivers/builtin_openssl/crypto/aes/aes_core.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_ctr.c (renamed from drivers/builtin_openssl/crypto/aes/aes_ctr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_ecb.c (renamed from drivers/builtin_openssl/crypto/aes/aes_ecb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_ige.c (renamed from drivers/builtin_openssl/crypto/aes/aes_ige.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_locl.h (renamed from drivers/builtin_openssl/crypto/aes/aes_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_misc.c (renamed from drivers/builtin_openssl/crypto/aes/aes_misc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_ofb.c (renamed from drivers/builtin_openssl/crypto/aes/aes_ofb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_wrap.c (renamed from drivers/builtin_openssl/crypto/aes/aes_wrap.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/aes_x86core.c (renamed from drivers/builtin_openssl/crypto/aes/aes_x86core.c)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/aes/asm/aes-586.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aes-armv4.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-armv4.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aes-ia64.S (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-ia64.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aes-mips.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-mips.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aes-parisc.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-parisc.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aes-ppc.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-ppc.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aes-s390x.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-s390x.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/aes/asm/aes-sparcv9.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-sparcv9.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/aes/asm/aes-x86_64.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aes-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aesni-sha1-x86_64.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aesni-sha1-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aesni-x86.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aesni-x86.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/aesni-x86_64.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/aesni-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/bsaes-x86_64.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/bsaes-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/vpaes-x86.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/vpaes-x86.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/aes/asm/vpaes-x86_64.pl (renamed from drivers/builtin_openssl/crypto/aes/asm/vpaes-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/alphacpuid.pl (renamed from drivers/builtin_openssl/crypto/alphacpuid.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/arm_arch.h (renamed from drivers/builtin_openssl/crypto/arm_arch.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/armcap.c (renamed from drivers/builtin_openssl/crypto/armcap.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/armv4cpuid.S (renamed from drivers/builtin_openssl/crypto/armv4cpuid.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_bitstr.c (renamed from drivers/builtin_openssl/crypto/asn1/a_bitstr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_bool.c (renamed from drivers/builtin_openssl/crypto/asn1/a_bool.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_bytes.c (renamed from drivers/builtin_openssl/crypto/asn1/a_bytes.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_d2i_fp.c (renamed from drivers/builtin_openssl/crypto/asn1/a_d2i_fp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_digest.c (renamed from drivers/builtin_openssl/crypto/asn1/a_digest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_dup.c (renamed from drivers/builtin_openssl/crypto/asn1/a_dup.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_enum.c (renamed from drivers/builtin_openssl/crypto/asn1/a_enum.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_gentm.c (renamed from drivers/builtin_openssl/crypto/asn1/a_gentm.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_i2d_fp.c (renamed from drivers/builtin_openssl/crypto/asn1/a_i2d_fp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_int.c (renamed from drivers/builtin_openssl/crypto/asn1/a_int.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_mbstr.c (renamed from drivers/builtin_openssl/crypto/asn1/a_mbstr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_object.c (renamed from drivers/builtin_openssl/crypto/asn1/a_object.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_octet.c (renamed from drivers/builtin_openssl/crypto/asn1/a_octet.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_print.c (renamed from drivers/builtin_openssl/crypto/asn1/a_print.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_set.c (renamed from drivers/builtin_openssl/crypto/asn1/a_set.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_sign.c (renamed from drivers/builtin_openssl/crypto/asn1/a_sign.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_strex.c (renamed from drivers/builtin_openssl/crypto/asn1/a_strex.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_strnid.c290
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_time.c (renamed from drivers/builtin_openssl/crypto/asn1/a_time.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_type.c (renamed from drivers/builtin_openssl/crypto/asn1/a_type.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_utctm.c (renamed from drivers/builtin_openssl/crypto/asn1/a_utctm.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_utf8.c (renamed from drivers/builtin_openssl/crypto/asn1/a_utf8.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/a_verify.c (renamed from drivers/builtin_openssl/crypto/asn1/a_verify.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/ameth_lib.c (renamed from drivers/builtin_openssl/crypto/asn1/ameth_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/asn1_err.c (renamed from drivers/builtin_openssl/crypto/asn1/asn1_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/asn1_gen.c (renamed from drivers/builtin_openssl/crypto/asn1/asn1_gen.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/asn1_lib.c (renamed from drivers/builtin_openssl/crypto/asn1/asn1_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/asn1_locl.h (renamed from drivers/builtin_openssl/crypto/asn1/asn1_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/asn1_par.c (renamed from drivers/builtin_openssl/crypto/asn1/asn1_par.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/asn_mime.c (renamed from drivers/builtin_openssl/crypto/asn1/asn_mime.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/asn_moid.c (renamed from drivers/builtin_openssl/crypto/asn1/asn_moid.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/asn_pack.c (renamed from drivers/builtin_openssl/crypto/asn1/asn_pack.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/bio_asn1.c (renamed from drivers/builtin_openssl/crypto/asn1/bio_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/bio_ndef.c (renamed from drivers/builtin_openssl/crypto/asn1/bio_ndef.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/charmap.h (renamed from drivers/builtin_openssl/crypto/asn1/charmap.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/charmap.pl (renamed from drivers/builtin_openssl/crypto/asn1/charmap.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/d2i_pr.c (renamed from drivers/builtin_openssl/crypto/asn1/d2i_pr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/d2i_pu.c (renamed from drivers/builtin_openssl/crypto/asn1/d2i_pu.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/evp_asn1.c (renamed from drivers/builtin_openssl/crypto/asn1/evp_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/f_enum.c (renamed from drivers/builtin_openssl/crypto/asn1/f_enum.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/f_int.c (renamed from drivers/builtin_openssl/crypto/asn1/f_int.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/f_string.c (renamed from drivers/builtin_openssl/crypto/asn1/f_string.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/i2d_pr.c (renamed from drivers/builtin_openssl/crypto/asn1/i2d_pr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/i2d_pu.c (renamed from drivers/builtin_openssl/crypto/asn1/i2d_pu.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/n_pkey.c (renamed from drivers/builtin_openssl/crypto/asn1/n_pkey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/nsseq.c (renamed from drivers/builtin_openssl/crypto/asn1/nsseq.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/p5_pbe.c (renamed from drivers/builtin_openssl/crypto/asn1/p5_pbe.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/p5_pbev2.c (renamed from drivers/builtin_openssl/crypto/asn1/p5_pbev2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/p8_pkey.c (renamed from drivers/builtin_openssl/crypto/asn1/p8_pkey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/t_bitst.c (renamed from drivers/builtin_openssl/crypto/asn1/t_bitst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/t_crl.c (renamed from drivers/builtin_openssl/crypto/asn1/t_crl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/t_pkey.c (renamed from drivers/builtin_openssl/crypto/asn1/t_pkey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/t_req.c (renamed from drivers/builtin_openssl/crypto/asn1/t_req.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/t_spki.c (renamed from drivers/builtin_openssl/crypto/asn1/t_spki.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/t_x509.c (renamed from drivers/builtin_openssl/crypto/asn1/t_x509.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/t_x509a.c (renamed from drivers/builtin_openssl/crypto/asn1/t_x509a.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/tasn_dec.c (renamed from drivers/builtin_openssl/crypto/asn1/tasn_dec.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/tasn_enc.c (renamed from drivers/builtin_openssl/crypto/asn1/tasn_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/tasn_fre.c (renamed from drivers/builtin_openssl/crypto/asn1/tasn_fre.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/tasn_new.c (renamed from drivers/builtin_openssl/crypto/asn1/tasn_new.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/tasn_prn.c (renamed from drivers/builtin_openssl/crypto/asn1/tasn_prn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/tasn_typ.c (renamed from drivers/builtin_openssl/crypto/asn1/tasn_typ.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/tasn_utl.c (renamed from drivers/builtin_openssl/crypto/asn1/tasn_utl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_algor.c (renamed from drivers/builtin_openssl/crypto/asn1/x_algor.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_attrib.c (renamed from drivers/builtin_openssl/crypto/asn1/x_attrib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_bignum.c (renamed from drivers/builtin_openssl/crypto/asn1/x_bignum.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_crl.c (renamed from drivers/builtin_openssl/crypto/asn1/x_crl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_exten.c (renamed from drivers/builtin_openssl/crypto/asn1/x_exten.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_info.c (renamed from drivers/builtin_openssl/crypto/asn1/x_info.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_long.c (renamed from drivers/builtin_openssl/crypto/asn1/x_long.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_name.c (renamed from drivers/builtin_openssl/crypto/asn1/x_name.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_nx509.c (renamed from drivers/builtin_openssl/crypto/asn1/x_nx509.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_pkey.c (renamed from drivers/builtin_openssl/crypto/asn1/x_pkey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_pubkey.c (renamed from drivers/builtin_openssl/crypto/asn1/x_pubkey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_req.c (renamed from drivers/builtin_openssl/crypto/asn1/x_req.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_sig.c (renamed from drivers/builtin_openssl/crypto/asn1/x_sig.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_spki.c (renamed from drivers/builtin_openssl/crypto/asn1/x_spki.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_val.c (renamed from drivers/builtin_openssl/crypto/asn1/x_val.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_x509.c (renamed from drivers/builtin_openssl/crypto/asn1/x_x509.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/asn1/x_x509a.c (renamed from drivers/builtin_openssl/crypto/asn1/x_x509a.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/COPYRIGHT (renamed from drivers/builtin_openssl/crypto/bf/COPYRIGHT)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/INSTALL (renamed from drivers/builtin_openssl/crypto/bf/INSTALL)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/README (renamed from drivers/builtin_openssl/crypto/bf/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/VERSION (renamed from drivers/builtin_openssl/crypto/bf/VERSION)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/asm/bf-586.pl (renamed from drivers/builtin_openssl/crypto/bf/asm/bf-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/asm/bf-686.pl (renamed from drivers/builtin_openssl/crypto/bf/asm/bf-686.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/asm/readme (renamed from drivers/builtin_openssl/crypto/bf/asm/readme)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_cbc.c (renamed from drivers/builtin_openssl/crypto/bf/bf_cbc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_cfb64.c (renamed from drivers/builtin_openssl/crypto/bf/bf_cfb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_ecb.c (renamed from drivers/builtin_openssl/crypto/bf/bf_ecb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_enc.c (renamed from drivers/builtin_openssl/crypto/bf/bf_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_locl.h (renamed from drivers/builtin_openssl/crypto/bf/bf_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_ofb64.c (renamed from drivers/builtin_openssl/crypto/bf/bf_ofb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_opts.c (renamed from drivers/builtin_openssl/crypto/bf/bf_opts.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_pi.h (renamed from drivers/builtin_openssl/crypto/bf/bf_pi.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bf_skey.c (renamed from drivers/builtin_openssl/crypto/bf/bf_skey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bfs.cpp (renamed from drivers/builtin_openssl/crypto/bf/bfs.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bfspeed.c (renamed from drivers/builtin_openssl/crypto/bf/bfspeed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bf/bftest.c (renamed from drivers/builtin_openssl/crypto/bf/bftest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/b_dump.c (renamed from drivers/builtin_openssl/crypto/bio/b_dump.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/b_print.c (renamed from drivers/builtin_openssl/crypto/bio/b_print.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/b_sock.c (renamed from drivers/builtin_openssl/crypto/bio/b_sock.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bf_buff.c (renamed from drivers/builtin_openssl/crypto/bio/bf_buff.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bf_lbuf.c (renamed from drivers/builtin_openssl/crypto/bio/bf_lbuf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bf_nbio.c (renamed from drivers/builtin_openssl/crypto/bio/bf_nbio.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bf_null.c (renamed from drivers/builtin_openssl/crypto/bio/bf_null.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bio_cb.c (renamed from drivers/builtin_openssl/crypto/bio/bio_cb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bio_err.c (renamed from drivers/builtin_openssl/crypto/bio/bio_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bio_lcl.h (renamed from drivers/builtin_openssl/crypto/bio/bio_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bio_lib.c (renamed from drivers/builtin_openssl/crypto/bio/bio_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_acpt.c (renamed from drivers/builtin_openssl/crypto/bio/bss_acpt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_bio.c (renamed from drivers/builtin_openssl/crypto/bio/bss_bio.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_conn.c (renamed from drivers/builtin_openssl/crypto/bio/bss_conn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_dgram.c1872
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_fd.c (renamed from drivers/builtin_openssl/crypto/bio/bss_fd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_file.c (renamed from drivers/builtin_openssl/crypto/bio/bss_file.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_log.c (renamed from drivers/builtin_openssl/crypto/bio/bss_log.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_mem.c (renamed from drivers/builtin_openssl/crypto/bio/bss_mem.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_null.c (renamed from drivers/builtin_openssl/crypto/bio/bss_null.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_rtcp.c (renamed from drivers/builtin_openssl/crypto/bio/bss_rtcp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bio/bss_sock.c (renamed from drivers/builtin_openssl/crypto/bio/bss_sock.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/README (renamed from drivers/builtin_openssl/crypto/bn/asm/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/alpha-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/alpha-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/armv4-gf2m.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/armv4-gf2m.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/armv4-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/armv4-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/bn-586.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/bn-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/co-586.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/co-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/ia64-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/ia64-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/ia64.S (renamed from drivers/builtin_openssl/crypto/bn/asm/ia64.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/mips-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/mips-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/mips.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/mips.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/mips3-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/mips3-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/mips3.s (renamed from drivers/builtin_openssl/crypto/bn/asm/mips3.s)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/modexp512-x86_64.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/modexp512-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/pa-risc2.s (renamed from drivers/builtin_openssl/crypto/bn/asm/pa-risc2.s)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/pa-risc2W.s (renamed from drivers/builtin_openssl/crypto/bn/asm/pa-risc2W.s)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/parisc-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/parisc-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/ppc-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/ppc-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/ppc.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/ppc.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/ppc64-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/ppc64-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/s390x-gf2m.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/s390x-gf2m.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/s390x-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/s390x-mont.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/bn/asm/s390x.S (renamed from drivers/builtin_openssl/crypto/bn/asm/s390x.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/sparcv8.S (renamed from drivers/builtin_openssl/crypto/bn/asm/sparcv8.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/sparcv8plus.S (renamed from drivers/builtin_openssl/crypto/bn/asm/sparcv8plus.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/sparcv9-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/sparcv9-mont.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/bn/asm/sparcv9a-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/sparcv9a-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/via-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/via-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/vms.mar (renamed from drivers/builtin_openssl/crypto/bn/asm/vms.mar)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86-gf2m.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86-gf2m.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/bn/asm/x86-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86-mont.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86/add.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86/add.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86/comba.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86/comba.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86/div.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86/div.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86/f (renamed from drivers/builtin_openssl/crypto/bn/asm/x86/f)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86/mul.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86/mul.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86/mul_add.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86/mul_add.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86/sqr.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86/sqr.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86/sub.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86/sub.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86_64-gcc.c (renamed from drivers/builtin_openssl/crypto/bn/asm/x86_64-gcc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/asm/x86_64-gf2m.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86_64-gf2m.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/bn/asm/x86_64-mont.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86_64-mont.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/bn/asm/x86_64-mont5.pl (renamed from drivers/builtin_openssl/crypto/bn/asm/x86_64-mont5.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn.mul (renamed from drivers/builtin_openssl/crypto/bn/bn.mul)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_add.c (renamed from drivers/builtin_openssl/crypto/bn/bn_add.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_asm.c (renamed from drivers/builtin_openssl/crypto/bn/bn_asm.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_blind.c (renamed from drivers/builtin_openssl/crypto/bn/bn_blind.c)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/bn/bn_const.c (renamed from drivers/builtin_openssl/crypto/bn/bn_const.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_ctx.c (renamed from drivers/builtin_openssl/crypto/bn/bn_ctx.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_depr.c (renamed from drivers/builtin_openssl/crypto/bn/bn_depr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_div.c (renamed from drivers/builtin_openssl/crypto/bn/bn_div.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_err.c (renamed from drivers/builtin_openssl/crypto/bn/bn_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_exp.c (renamed from drivers/builtin_openssl/crypto/bn/bn_exp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_exp2.c (renamed from drivers/builtin_openssl/crypto/bn/bn_exp2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_gcd.c (renamed from drivers/builtin_openssl/crypto/bn/bn_gcd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_gf2m.c (renamed from drivers/builtin_openssl/crypto/bn/bn_gf2m.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_kron.c (renamed from drivers/builtin_openssl/crypto/bn/bn_kron.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_lcl.h (renamed from drivers/builtin_openssl/crypto/bn/bn_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_lib.c (renamed from drivers/builtin_openssl/crypto/bn/bn_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_mod.c (renamed from drivers/builtin_openssl/crypto/bn/bn_mod.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_mont.c515
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_mpi.c (renamed from drivers/builtin_openssl/crypto/bn/bn_mpi.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_mul.c (renamed from drivers/builtin_openssl/crypto/bn/bn_mul.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_nist.c (renamed from drivers/builtin_openssl/crypto/bn/bn_nist.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_prime.c (renamed from drivers/builtin_openssl/crypto/bn/bn_prime.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_prime.h (renamed from drivers/builtin_openssl/crypto/bn/bn_prime.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_prime.pl (renamed from drivers/builtin_openssl/crypto/bn/bn_prime.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_print.c (renamed from drivers/builtin_openssl/crypto/bn/bn_print.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_rand.c (renamed from drivers/builtin_openssl/crypto/bn/bn_rand.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_recp.c (renamed from drivers/builtin_openssl/crypto/bn/bn_recp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_shift.c (renamed from drivers/builtin_openssl/crypto/bn/bn_shift.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_sqr.c (renamed from drivers/builtin_openssl/crypto/bn/bn_sqr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_sqrt.c (renamed from drivers/builtin_openssl/crypto/bn/bn_sqrt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_word.c (renamed from drivers/builtin_openssl/crypto/bn/bn_word.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bn_x931p.c (renamed from drivers/builtin_openssl/crypto/bn/bn_x931p.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bnspeed.c (renamed from drivers/builtin_openssl/crypto/bn/bnspeed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/bntest.c (renamed from drivers/builtin_openssl/crypto/bn/bntest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/divtest.c (renamed from drivers/builtin_openssl/crypto/bn/divtest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/exp.c (renamed from drivers/builtin_openssl/crypto/bn/exp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/expspeed.c (renamed from drivers/builtin_openssl/crypto/bn/expspeed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/exptest.c (renamed from drivers/builtin_openssl/crypto/bn/exptest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/todo (renamed from drivers/builtin_openssl/crypto/bn/todo)0
-rw-r--r--drivers/builtin_openssl2/crypto/bn/vms-helper.c (renamed from drivers/builtin_openssl/crypto/bn/vms-helper.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/buffer/buf_err.c (renamed from drivers/builtin_openssl/crypto/buffer/buf_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/buffer/buf_str.c (renamed from drivers/builtin_openssl/crypto/buffer/buf_str.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/buffer/buffer.c (renamed from drivers/builtin_openssl/crypto/buffer/buffer.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/asm/cmll-x86.pl (renamed from drivers/builtin_openssl/crypto/camellia/asm/cmll-x86.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/asm/cmll-x86_64.pl (renamed from drivers/builtin_openssl/crypto/camellia/asm/cmll-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/camellia.c (renamed from drivers/builtin_openssl/crypto/camellia/camellia.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/cmll_cbc.c (renamed from drivers/builtin_openssl/crypto/camellia/cmll_cbc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/cmll_cfb.c (renamed from drivers/builtin_openssl/crypto/camellia/cmll_cfb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/cmll_ctr.c (renamed from drivers/builtin_openssl/crypto/camellia/cmll_ctr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/cmll_ecb.c (renamed from drivers/builtin_openssl/crypto/camellia/cmll_ecb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/cmll_locl.h (renamed from drivers/builtin_openssl/crypto/camellia/cmll_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/cmll_misc.c (renamed from drivers/builtin_openssl/crypto/camellia/cmll_misc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/cmll_ofb.c (renamed from drivers/builtin_openssl/crypto/camellia/cmll_ofb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/camellia/cmll_utl.c (renamed from drivers/builtin_openssl/crypto/camellia/cmll_utl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/asm/cast-586.pl (renamed from drivers/builtin_openssl/crypto/cast/asm/cast-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/asm/readme (renamed from drivers/builtin_openssl/crypto/cast/asm/readme)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/c_cfb64.c (renamed from drivers/builtin_openssl/crypto/cast/c_cfb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/c_ecb.c (renamed from drivers/builtin_openssl/crypto/cast/c_ecb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/c_enc.c (renamed from drivers/builtin_openssl/crypto/cast/c_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/c_ofb64.c (renamed from drivers/builtin_openssl/crypto/cast/c_ofb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/c_skey.c (renamed from drivers/builtin_openssl/crypto/cast/c_skey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/cast_lcl.h (renamed from drivers/builtin_openssl/crypto/cast/cast_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/cast_s.h (renamed from drivers/builtin_openssl/crypto/cast/cast_s.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/cast_spd.c (renamed from drivers/builtin_openssl/crypto/cast/cast_spd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/castopts.c (renamed from drivers/builtin_openssl/crypto/cast/castopts.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/casts.cpp (renamed from drivers/builtin_openssl/crypto/cast/casts.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/cast/casttest.c (renamed from drivers/builtin_openssl/crypto/cast/casttest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cmac/cm_ameth.c (renamed from drivers/builtin_openssl/crypto/cmac/cm_ameth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cmac/cm_pmeth.c (renamed from drivers/builtin_openssl/crypto/cmac/cm_pmeth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cmac/cmac.c (renamed from drivers/builtin_openssl/crypto/cmac/cmac.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_asn1.c (renamed from drivers/builtin_openssl/crypto/cms/cms_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_att.c (renamed from drivers/builtin_openssl/crypto/cms/cms_att.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_cd.c (renamed from drivers/builtin_openssl/crypto/cms/cms_cd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_dd.c (renamed from drivers/builtin_openssl/crypto/cms/cms_dd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_enc.c (renamed from drivers/builtin_openssl/crypto/cms/cms_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_env.c878
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_err.c (renamed from drivers/builtin_openssl/crypto/cms/cms_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_ess.c (renamed from drivers/builtin_openssl/crypto/cms/cms_ess.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_io.c (renamed from drivers/builtin_openssl/crypto/cms/cms_io.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_lcl.h (renamed from drivers/builtin_openssl/crypto/cms/cms_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_lib.c (renamed from drivers/builtin_openssl/crypto/cms/cms_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_pwri.c (renamed from drivers/builtin_openssl/crypto/cms/cms_pwri.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_sd.c985
-rw-r--r--drivers/builtin_openssl2/crypto/cms/cms_smime.c851
-rw-r--r--drivers/builtin_openssl2/crypto/comp/c_rle.c (renamed from drivers/builtin_openssl/crypto/comp/c_rle.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/comp/c_zlib.c (renamed from drivers/builtin_openssl/crypto/comp/c_zlib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/comp/comp_err.c (renamed from drivers/builtin_openssl/crypto/comp/comp_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/comp/comp_lib.c (renamed from drivers/builtin_openssl/crypto/comp/comp_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/README (renamed from drivers/builtin_openssl/crypto/conf/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/cnf_save.c (renamed from drivers/builtin_openssl/crypto/conf/cnf_save.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/conf_api.c (renamed from drivers/builtin_openssl/crypto/conf/conf_api.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/conf_def.c (renamed from drivers/builtin_openssl/crypto/conf/conf_def.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/conf_def.h (renamed from drivers/builtin_openssl/crypto/conf/conf_def.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/conf_err.c (renamed from drivers/builtin_openssl/crypto/conf/conf_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/conf_lib.c (renamed from drivers/builtin_openssl/crypto/conf/conf_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/conf_mall.c (renamed from drivers/builtin_openssl/crypto/conf/conf_mall.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/conf_mod.c (renamed from drivers/builtin_openssl/crypto/conf/conf_mod.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/conf_sap.c (renamed from drivers/builtin_openssl/crypto/conf/conf_sap.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/keysets.pl (renamed from drivers/builtin_openssl/crypto/conf/keysets.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/ssleay.cnf (renamed from drivers/builtin_openssl/crypto/conf/ssleay.cnf)0
-rw-r--r--drivers/builtin_openssl2/crypto/conf/test.c (renamed from drivers/builtin_openssl/crypto/conf/test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cpt_err.c (renamed from drivers/builtin_openssl/crypto/cpt_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cryptlib.c (renamed from drivers/builtin_openssl/crypto/cryptlib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/cryptlib.h (renamed from drivers/builtin_openssl/crypto/cryptlib.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/crypto-lib.com (renamed from drivers/builtin_openssl/crypto/crypto-lib.com)0
-rw-r--r--drivers/builtin_openssl2/crypto/cversion.c (renamed from drivers/builtin_openssl/crypto/cversion.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/COPYRIGHT (renamed from drivers/builtin_openssl/crypto/des/COPYRIGHT)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/DES.pm (renamed from drivers/builtin_openssl/crypto/des/DES.pm)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/DES.xs (renamed from drivers/builtin_openssl/crypto/des/DES.xs)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/FILES0 (renamed from drivers/builtin_openssl/crypto/des/FILES0)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/INSTALL (renamed from drivers/builtin_openssl/crypto/des/INSTALL)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/Imakefile35
-rw-r--r--drivers/builtin_openssl2/crypto/des/KERBEROS (renamed from drivers/builtin_openssl/crypto/des/KERBEROS)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/README (renamed from drivers/builtin_openssl/crypto/des/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/VERSION (renamed from drivers/builtin_openssl/crypto/des/VERSION)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/asm/crypt586.pl (renamed from drivers/builtin_openssl/crypto/des/asm/crypt586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/asm/des-586.pl (renamed from drivers/builtin_openssl/crypto/des/asm/des-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/asm/des_enc.m4 (renamed from drivers/builtin_openssl/crypto/des/asm/des_enc.m4)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/asm/desboth.pl (renamed from drivers/builtin_openssl/crypto/des/asm/desboth.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/asm/readme (renamed from drivers/builtin_openssl/crypto/des/asm/readme)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/cbc3_enc.c (renamed from drivers/builtin_openssl/crypto/des/cbc3_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/cbc_cksm.c (renamed from drivers/builtin_openssl/crypto/des/cbc_cksm.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/cbc_enc.c (renamed from drivers/builtin_openssl/crypto/des/cbc_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/cfb64ede.c (renamed from drivers/builtin_openssl/crypto/des/cfb64ede.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/cfb64enc.c (renamed from drivers/builtin_openssl/crypto/des/cfb64enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/cfb_enc.c (renamed from drivers/builtin_openssl/crypto/des/cfb_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des-lib.com (renamed from drivers/builtin_openssl/crypto/des/des-lib.com)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des.c (renamed from drivers/builtin_openssl/crypto/des/des.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des.pod (renamed from drivers/builtin_openssl/crypto/des/des.pod)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des3s.cpp (renamed from drivers/builtin_openssl/crypto/des/des3s.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des_enc.c (renamed from drivers/builtin_openssl/crypto/des/des_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des_locl.h (renamed from drivers/builtin_openssl/crypto/des/des_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des_old.c (renamed from drivers/builtin_openssl/crypto/des/des_old.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des_old2.c (renamed from drivers/builtin_openssl/crypto/des/des_old2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des_opts.c (renamed from drivers/builtin_openssl/crypto/des/des_opts.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/des_ver.h (renamed from drivers/builtin_openssl/crypto/des/des_ver.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/dess.cpp (renamed from drivers/builtin_openssl/crypto/des/dess.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/destest.c (renamed from drivers/builtin_openssl/crypto/des/destest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/ecb3_enc.c (renamed from drivers/builtin_openssl/crypto/des/ecb3_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/ecb_enc.c (renamed from drivers/builtin_openssl/crypto/des/ecb_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/ede_cbcm_enc.c (renamed from drivers/builtin_openssl/crypto/des/ede_cbcm_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/enc_read.c (renamed from drivers/builtin_openssl/crypto/des/enc_read.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/enc_writ.c (renamed from drivers/builtin_openssl/crypto/des/enc_writ.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/fcrypt.c (renamed from drivers/builtin_openssl/crypto/des/fcrypt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/fcrypt_b.c (renamed from drivers/builtin_openssl/crypto/des/fcrypt_b.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/makefile.bc50
-rw-r--r--drivers/builtin_openssl2/crypto/des/ncbc_enc.c (renamed from drivers/builtin_openssl/crypto/des/ncbc_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/ofb64ede.c (renamed from drivers/builtin_openssl/crypto/des/ofb64ede.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/ofb64enc.c (renamed from drivers/builtin_openssl/crypto/des/ofb64enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/ofb_enc.c (renamed from drivers/builtin_openssl/crypto/des/ofb_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/options.txt (renamed from drivers/builtin_openssl/crypto/des/options.txt)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/pcbc_enc.c (renamed from drivers/builtin_openssl/crypto/des/pcbc_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/qud_cksm.c (renamed from drivers/builtin_openssl/crypto/des/qud_cksm.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/rand_key.c (renamed from drivers/builtin_openssl/crypto/des/rand_key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/read2pwd.c (renamed from drivers/builtin_openssl/crypto/des/read2pwd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/read_pwd.c (renamed from drivers/builtin_openssl/crypto/des/read_pwd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/rpc_des.h (renamed from drivers/builtin_openssl/crypto/des/rpc_des.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/rpc_enc.c (renamed from drivers/builtin_openssl/crypto/des/rpc_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/rpw.c (renamed from drivers/builtin_openssl/crypto/des/rpw.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/set_key.c (renamed from drivers/builtin_openssl/crypto/des/set_key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/speed.c (renamed from drivers/builtin_openssl/crypto/des/speed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/spr.h (renamed from drivers/builtin_openssl/crypto/des/spr.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/str2key.c (renamed from drivers/builtin_openssl/crypto/des/str2key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/t/test (renamed from drivers/builtin_openssl/crypto/des/t/test)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/times/486-50.sol (renamed from drivers/builtin_openssl/crypto/des/times/486-50.sol)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/times/586-100.lnx (renamed from drivers/builtin_openssl/crypto/des/times/586-100.lnx)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/times/686-200.fre (renamed from drivers/builtin_openssl/crypto/des/times/686-200.fre)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/times/aix.cc (renamed from drivers/builtin_openssl/crypto/des/times/aix.cc)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/times/alpha.cc (renamed from drivers/builtin_openssl/crypto/des/times/alpha.cc)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/times/hpux.cc (renamed from drivers/builtin_openssl/crypto/des/times/hpux.cc)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/times/sparc.gcc (renamed from drivers/builtin_openssl/crypto/des/times/sparc.gcc)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/times/usparc.cc (renamed from drivers/builtin_openssl/crypto/des/times/usparc.cc)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/typemap (renamed from drivers/builtin_openssl/crypto/des/typemap)0
-rw-r--r--drivers/builtin_openssl2/crypto/des/xcbc_enc.c (renamed from drivers/builtin_openssl/crypto/des/xcbc_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh1024.pem (renamed from drivers/builtin_openssl/crypto/dh/dh1024.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh192.pem (renamed from drivers/builtin_openssl/crypto/dh/dh192.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh2048.pem (renamed from drivers/builtin_openssl/crypto/dh/dh2048.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh4096.pem (renamed from drivers/builtin_openssl/crypto/dh/dh4096.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh512.pem (renamed from drivers/builtin_openssl/crypto/dh/dh512.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_ameth.c (renamed from drivers/builtin_openssl/crypto/dh/dh_ameth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_asn1.c (renamed from drivers/builtin_openssl/crypto/dh/dh_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_check.c (renamed from drivers/builtin_openssl/crypto/dh/dh_check.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_depr.c (renamed from drivers/builtin_openssl/crypto/dh/dh_depr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_err.c (renamed from drivers/builtin_openssl/crypto/dh/dh_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_gen.c (renamed from drivers/builtin_openssl/crypto/dh/dh_gen.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_key.c (renamed from drivers/builtin_openssl/crypto/dh/dh_key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_lib.c (renamed from drivers/builtin_openssl/crypto/dh/dh_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_pmeth.c (renamed from drivers/builtin_openssl/crypto/dh/dh_pmeth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dh_prn.c (renamed from drivers/builtin_openssl/crypto/dh/dh_prn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/dhtest.c (renamed from drivers/builtin_openssl/crypto/dh/dhtest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/example (renamed from drivers/builtin_openssl/crypto/dh/example)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/generate (renamed from drivers/builtin_openssl/crypto/dh/generate)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/p1024.c (renamed from drivers/builtin_openssl/crypto/dh/p1024.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/p192.c (renamed from drivers/builtin_openssl/crypto/dh/p192.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dh/p512.c (renamed from drivers/builtin_openssl/crypto/dh/p512.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/README (renamed from drivers/builtin_openssl/crypto/dsa/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_ameth.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_ameth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_asn1.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_depr.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_depr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_err.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_gen.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_gen.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_key.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_lib.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_locl.h (renamed from drivers/builtin_openssl/crypto/dsa/dsa_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_ossl.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_ossl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_pmeth.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_pmeth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_prn.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_prn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_sign.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_sign.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsa_vrf.c (renamed from drivers/builtin_openssl/crypto/dsa/dsa_vrf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsagen.c (renamed from drivers/builtin_openssl/crypto/dsa/dsagen.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/dsatest.c (renamed from drivers/builtin_openssl/crypto/dsa/dsatest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dsa/fips186a.txt (renamed from drivers/builtin_openssl/crypto/dsa/fips186a.txt)0
-rw-r--r--drivers/builtin_openssl2/crypto/dso/README (renamed from drivers/builtin_openssl/crypto/dso/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_beos.c (renamed from drivers/builtin_openssl/crypto/dso/dso_beos.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_dl.c (renamed from drivers/builtin_openssl/crypto/dso/dso_dl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_dlfcn.c484
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_err.c (renamed from drivers/builtin_openssl/crypto/dso/dso_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_lib.c (renamed from drivers/builtin_openssl/crypto/dso/dso_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_null.c (renamed from drivers/builtin_openssl/crypto/dso/dso_null.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_openssl.c (renamed from drivers/builtin_openssl/crypto/dso/dso_openssl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_vms.c525
-rw-r--r--drivers/builtin_openssl2/crypto/dso/dso_win32.c (renamed from drivers/builtin_openssl/crypto/dso/dso_win32.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ebcdic.c (renamed from drivers/builtin_openssl/crypto/ebcdic.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec2_mult.c (renamed from drivers/builtin_openssl/crypto/ec/ec2_mult.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec2_oct.c (renamed from drivers/builtin_openssl/crypto/ec/ec2_oct.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec2_smpl.c (renamed from drivers/builtin_openssl/crypto/ec/ec2_smpl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_ameth.c661
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_asn1.c1448
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_check.c (renamed from drivers/builtin_openssl/crypto/ec/ec_check.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_curve.c (renamed from drivers/builtin_openssl/crypto/ec/ec_curve.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_cvt.c (renamed from drivers/builtin_openssl/crypto/ec/ec_cvt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_err.c (renamed from drivers/builtin_openssl/crypto/ec/ec_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_key.c (renamed from drivers/builtin_openssl/crypto/ec/ec_key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_lcl.h446
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_lib.c (renamed from drivers/builtin_openssl/crypto/ec/ec_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_mult.c (renamed from drivers/builtin_openssl/crypto/ec/ec_mult.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_oct.c (renamed from drivers/builtin_openssl/crypto/ec/ec_oct.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_pmeth.c (renamed from drivers/builtin_openssl/crypto/ec/ec_pmeth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ec_print.c (renamed from drivers/builtin_openssl/crypto/ec/ec_print.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/eck_prn.c (renamed from drivers/builtin_openssl/crypto/ec/eck_prn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ecp_mont.c (renamed from drivers/builtin_openssl/crypto/ec/ecp_mont.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ecp_nist.c (renamed from drivers/builtin_openssl/crypto/ec/ecp_nist.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ecp_nistp224.c (renamed from drivers/builtin_openssl/crypto/ec/ecp_nistp224.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ecp_nistp256.c (renamed from drivers/builtin_openssl/crypto/ec/ecp_nistp256.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ecp_nistp521.c (renamed from drivers/builtin_openssl/crypto/ec/ecp_nistp521.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ecp_nistputil.c (renamed from drivers/builtin_openssl/crypto/ec/ecp_nistputil.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ecp_oct.c (renamed from drivers/builtin_openssl/crypto/ec/ecp_oct.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ecp_smpl.c (renamed from drivers/builtin_openssl/crypto/ec/ecp_smpl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ec/ectest.c (renamed from drivers/builtin_openssl/crypto/ec/ectest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdh/ecdhtest.c (renamed from drivers/builtin_openssl/crypto/ecdh/ecdhtest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdh/ech_err.c (renamed from drivers/builtin_openssl/crypto/ecdh/ech_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdh/ech_key.c (renamed from drivers/builtin_openssl/crypto/ecdh/ech_key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdh/ech_lib.c (renamed from drivers/builtin_openssl/crypto/ecdh/ech_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdh/ech_locl.h (renamed from drivers/builtin_openssl/crypto/ecdh/ech_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdh/ech_ossl.c (renamed from drivers/builtin_openssl/crypto/ecdh/ech_ossl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdsa/ecdsatest.c (renamed from drivers/builtin_openssl/crypto/ecdsa/ecdsatest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdsa/ecs_asn1.c (renamed from drivers/builtin_openssl/crypto/ecdsa/ecs_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdsa/ecs_err.c (renamed from drivers/builtin_openssl/crypto/ecdsa/ecs_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdsa/ecs_lib.c (renamed from drivers/builtin_openssl/crypto/ecdsa/ecs_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdsa/ecs_locl.h (renamed from drivers/builtin_openssl/crypto/ecdsa/ecs_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdsa/ecs_ossl.c (renamed from drivers/builtin_openssl/crypto/ecdsa/ecs_ossl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdsa/ecs_sign.c (renamed from drivers/builtin_openssl/crypto/ecdsa/ecs_sign.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ecdsa/ecs_vrf.c (renamed from drivers/builtin_openssl/crypto/ecdsa/ecs_vrf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/README (renamed from drivers/builtin_openssl/crypto/engine/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_all.c (renamed from drivers/builtin_openssl/crypto/engine/eng_all.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_cnf.c (renamed from drivers/builtin_openssl/crypto/engine/eng_cnf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_cryptodev.c (renamed from drivers/builtin_openssl/crypto/engine/eng_cryptodev.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_ctrl.c (renamed from drivers/builtin_openssl/crypto/engine/eng_ctrl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_dyn.c (renamed from drivers/builtin_openssl/crypto/engine/eng_dyn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_err.c (renamed from drivers/builtin_openssl/crypto/engine/eng_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_fat.c (renamed from drivers/builtin_openssl/crypto/engine/eng_fat.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_init.c (renamed from drivers/builtin_openssl/crypto/engine/eng_init.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_int.h (renamed from drivers/builtin_openssl/crypto/engine/eng_int.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_lib.c (renamed from drivers/builtin_openssl/crypto/engine/eng_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_list.c (renamed from drivers/builtin_openssl/crypto/engine/eng_list.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_openssl.c (renamed from drivers/builtin_openssl/crypto/engine/eng_openssl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_pkey.c (renamed from drivers/builtin_openssl/crypto/engine/eng_pkey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_rdrand.c (renamed from drivers/builtin_openssl/crypto/engine/eng_rdrand.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_rsax.c (renamed from drivers/builtin_openssl/crypto/engine/eng_rsax.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/eng_table.c (renamed from drivers/builtin_openssl/crypto/engine/eng_table.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/enginetest.c (renamed from drivers/builtin_openssl/crypto/engine/enginetest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_asnmth.c (renamed from drivers/builtin_openssl/crypto/engine/tb_asnmth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_cipher.c (renamed from drivers/builtin_openssl/crypto/engine/tb_cipher.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_dh.c (renamed from drivers/builtin_openssl/crypto/engine/tb_dh.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_digest.c (renamed from drivers/builtin_openssl/crypto/engine/tb_digest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_dsa.c (renamed from drivers/builtin_openssl/crypto/engine/tb_dsa.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_ecdh.c (renamed from drivers/builtin_openssl/crypto/engine/tb_ecdh.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_ecdsa.c (renamed from drivers/builtin_openssl/crypto/engine/tb_ecdsa.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_pkmeth.c (renamed from drivers/builtin_openssl/crypto/engine/tb_pkmeth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_rand.c (renamed from drivers/builtin_openssl/crypto/engine/tb_rand.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_rsa.c (renamed from drivers/builtin_openssl/crypto/engine/tb_rsa.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/engine/tb_store.c (renamed from drivers/builtin_openssl/crypto/engine/tb_store.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/err/err.c (renamed from drivers/builtin_openssl/crypto/err/err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/err/err_all.c (renamed from drivers/builtin_openssl/crypto/err/err_all.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/err/err_prn.c (renamed from drivers/builtin_openssl/crypto/err/err_prn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/err/openssl.ec (renamed from drivers/builtin_openssl/crypto/err/openssl.ec)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/bio_b64.c599
-rw-r--r--drivers/builtin_openssl2/crypto/evp/bio_enc.c (renamed from drivers/builtin_openssl/crypto/evp/bio_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/bio_md.c (renamed from drivers/builtin_openssl/crypto/evp/bio_md.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/bio_ok.c (renamed from drivers/builtin_openssl/crypto/evp/bio_ok.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/c_all.c (renamed from drivers/builtin_openssl/crypto/evp/c_all.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/c_allc.c (renamed from drivers/builtin_openssl/crypto/evp/c_allc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/c_alld.c (renamed from drivers/builtin_openssl/crypto/evp/c_alld.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/digest.c (renamed from drivers/builtin_openssl/crypto/evp/digest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_aes.c (renamed from drivers/builtin_openssl/crypto/evp/e_aes.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_aes_cbc_hmac_sha1.c (renamed from drivers/builtin_openssl/crypto/evp/e_aes_cbc_hmac_sha1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_bf.c (renamed from drivers/builtin_openssl/crypto/evp/e_bf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_camellia.c (renamed from drivers/builtin_openssl/crypto/evp/e_camellia.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_cast.c (renamed from drivers/builtin_openssl/crypto/evp/e_cast.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_des.c (renamed from drivers/builtin_openssl/crypto/evp/e_des.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_des3.c (renamed from drivers/builtin_openssl/crypto/evp/e_des3.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_dsa.c71
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_idea.c (renamed from drivers/builtin_openssl/crypto/evp/e_idea.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_null.c (renamed from drivers/builtin_openssl/crypto/evp/e_null.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_old.c (renamed from drivers/builtin_openssl/crypto/evp/e_old.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_rc2.c (renamed from drivers/builtin_openssl/crypto/evp/e_rc2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_rc4.c (renamed from drivers/builtin_openssl/crypto/evp/e_rc4.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_rc4_hmac_md5.c (renamed from drivers/builtin_openssl/crypto/evp/e_rc4_hmac_md5.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_rc5.c (renamed from drivers/builtin_openssl/crypto/evp/e_rc5.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_seed.c (renamed from drivers/builtin_openssl/crypto/evp/e_seed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/e_xcbc_d.c (renamed from drivers/builtin_openssl/crypto/evp/e_xcbc_d.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/encode.c446
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_acnf.c (renamed from drivers/builtin_openssl/crypto/evp/evp_acnf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_cnf.c (renamed from drivers/builtin_openssl/crypto/evp/evp_cnf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_enc.c (renamed from drivers/builtin_openssl/crypto/evp/evp_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_err.c (renamed from drivers/builtin_openssl/crypto/evp/evp_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_fips.c (renamed from drivers/builtin_openssl/crypto/evp/evp_fips.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_key.c (renamed from drivers/builtin_openssl/crypto/evp/evp_key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_lib.c (renamed from drivers/builtin_openssl/crypto/evp/evp_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_locl.h (renamed from drivers/builtin_openssl/crypto/evp/evp_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_pbe.c (renamed from drivers/builtin_openssl/crypto/evp/evp_pbe.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_pkey.c (renamed from drivers/builtin_openssl/crypto/evp/evp_pkey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evp_test.c (renamed from drivers/builtin_openssl/crypto/evp/evp_test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/evptests.txt (renamed from drivers/builtin_openssl/crypto/evp/evptests.txt)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_dss.c (renamed from drivers/builtin_openssl/crypto/evp/m_dss.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_dss1.c (renamed from drivers/builtin_openssl/crypto/evp/m_dss1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_ecdsa.c (renamed from drivers/builtin_openssl/crypto/evp/m_ecdsa.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_md2.c (renamed from drivers/builtin_openssl/crypto/evp/m_md2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_md4.c (renamed from drivers/builtin_openssl/crypto/evp/m_md4.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_md5.c (renamed from drivers/builtin_openssl/crypto/evp/m_md5.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_mdc2.c (renamed from drivers/builtin_openssl/crypto/evp/m_mdc2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_null.c (renamed from drivers/builtin_openssl/crypto/evp/m_null.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_ripemd.c (renamed from drivers/builtin_openssl/crypto/evp/m_ripemd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_sha.c (renamed from drivers/builtin_openssl/crypto/evp/m_sha.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_sha1.c (renamed from drivers/builtin_openssl/crypto/evp/m_sha1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_sigver.c (renamed from drivers/builtin_openssl/crypto/evp/m_sigver.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/m_wp.c (renamed from drivers/builtin_openssl/crypto/evp/m_wp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/names.c (renamed from drivers/builtin_openssl/crypto/evp/names.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/openbsd_hw.c (renamed from drivers/builtin_openssl/crypto/evp/openbsd_hw.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p5_crpt.c (renamed from drivers/builtin_openssl/crypto/evp/p5_crpt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p5_crpt2.c (renamed from drivers/builtin_openssl/crypto/evp/p5_crpt2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p_dec.c (renamed from drivers/builtin_openssl/crypto/evp/p_dec.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p_enc.c (renamed from drivers/builtin_openssl/crypto/evp/p_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p_lib.c (renamed from drivers/builtin_openssl/crypto/evp/p_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p_open.c (renamed from drivers/builtin_openssl/crypto/evp/p_open.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p_seal.c (renamed from drivers/builtin_openssl/crypto/evp/p_seal.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p_sign.c (renamed from drivers/builtin_openssl/crypto/evp/p_sign.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/p_verify.c (renamed from drivers/builtin_openssl/crypto/evp/p_verify.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/pmeth_fn.c (renamed from drivers/builtin_openssl/crypto/evp/pmeth_fn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/pmeth_gn.c (renamed from drivers/builtin_openssl/crypto/evp/pmeth_gn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/evp/pmeth_lib.c (renamed from drivers/builtin_openssl/crypto/evp/pmeth_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ex_data.c (renamed from drivers/builtin_openssl/crypto/ex_data.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/fips_err.h (renamed from drivers/builtin_openssl/crypto/fips_err.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/fips_ers.c (renamed from drivers/builtin_openssl/crypto/fips_ers.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/hmac/hm_ameth.c (renamed from drivers/builtin_openssl/crypto/hmac/hm_ameth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/hmac/hm_pmeth.c (renamed from drivers/builtin_openssl/crypto/hmac/hm_pmeth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/hmac/hmac.c (renamed from drivers/builtin_openssl/crypto/hmac/hmac.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/hmac/hmactest.c (renamed from drivers/builtin_openssl/crypto/hmac/hmactest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ia64cpuid.S (renamed from drivers/builtin_openssl/crypto/ia64cpuid.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/i_cbc.c (renamed from drivers/builtin_openssl/crypto/idea/i_cbc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/i_cfb64.c (renamed from drivers/builtin_openssl/crypto/idea/i_cfb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/i_ecb.c (renamed from drivers/builtin_openssl/crypto/idea/i_ecb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/i_ofb64.c (renamed from drivers/builtin_openssl/crypto/idea/i_ofb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/i_skey.c (renamed from drivers/builtin_openssl/crypto/idea/i_skey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/idea_lcl.h (renamed from drivers/builtin_openssl/crypto/idea/idea_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/idea_spd.c (renamed from drivers/builtin_openssl/crypto/idea/idea_spd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/ideatest.c (renamed from drivers/builtin_openssl/crypto/idea/ideatest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/idea/version (renamed from drivers/builtin_openssl/crypto/idea/version)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/install-crypto.com (renamed from drivers/builtin_openssl/crypto/install-crypto.com)0
-rw-r--r--drivers/builtin_openssl2/crypto/jpake/jpake.c (renamed from drivers/builtin_openssl/crypto/jpake/jpake.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/jpake/jpake.h (renamed from drivers/builtin_openssl/crypto/jpake/jpake.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/jpake/jpake_err.c (renamed from drivers/builtin_openssl/crypto/jpake/jpake_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/jpake/jpaketest.c (renamed from drivers/builtin_openssl/crypto/jpake/jpaketest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/krb5/krb5_asn.c (renamed from drivers/builtin_openssl/crypto/krb5/krb5_asn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/lhash/lh_stats.c (renamed from drivers/builtin_openssl/crypto/lhash/lh_stats.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/lhash/lh_test.c (renamed from drivers/builtin_openssl/crypto/lhash/lh_test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/lhash/lhash.c (renamed from drivers/builtin_openssl/crypto/lhash/lhash.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/lhash/num.pl (renamed from drivers/builtin_openssl/crypto/lhash/num.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/md2/md2.c (renamed from drivers/builtin_openssl/crypto/md2/md2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md2/md2.h (renamed from drivers/builtin_openssl/crypto/md2/md2.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/md2/md2_dgst.c (renamed from drivers/builtin_openssl/crypto/md2/md2_dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md2/md2_one.c (renamed from drivers/builtin_openssl/crypto/md2/md2_one.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md2/md2test.c (renamed from drivers/builtin_openssl/crypto/md2/md2test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md32_common.h (renamed from drivers/builtin_openssl/crypto/md32_common.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/md4/md4.c (renamed from drivers/builtin_openssl/crypto/md4/md4.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md4/md4_dgst.c (renamed from drivers/builtin_openssl/crypto/md4/md4_dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md4/md4_locl.h (renamed from drivers/builtin_openssl/crypto/md4/md4_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/md4/md4_one.c (renamed from drivers/builtin_openssl/crypto/md4/md4_one.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md4/md4s.cpp (renamed from drivers/builtin_openssl/crypto/md4/md4s.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/md4/md4test.c (renamed from drivers/builtin_openssl/crypto/md4/md4test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md5/asm/md5-586.pl (renamed from drivers/builtin_openssl/crypto/md5/asm/md5-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/md5/asm/md5-ia64.S (renamed from drivers/builtin_openssl/crypto/md5/asm/md5-ia64.S)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/md5/asm/md5-x86_64.pl (renamed from drivers/builtin_openssl/crypto/md5/asm/md5-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/md5/md5.c (renamed from drivers/builtin_openssl/crypto/md5/md5.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md5/md5_dgst.c (renamed from drivers/builtin_openssl/crypto/md5/md5_dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md5/md5_locl.h130
-rw-r--r--drivers/builtin_openssl2/crypto/md5/md5_one.c (renamed from drivers/builtin_openssl/crypto/md5/md5_one.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/md5/md5s.cpp (renamed from drivers/builtin_openssl/crypto/md5/md5s.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/md5/md5test.c (renamed from drivers/builtin_openssl/crypto/md5/md5test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/mdc2/mdc2_one.c (renamed from drivers/builtin_openssl/crypto/mdc2/mdc2_one.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/mdc2/mdc2dgst.c (renamed from drivers/builtin_openssl/crypto/mdc2/mdc2dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/mdc2/mdc2test.c (renamed from drivers/builtin_openssl/crypto/mdc2/mdc2test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/mem.c (renamed from drivers/builtin_openssl/crypto/mem.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/mem_clr.c (renamed from drivers/builtin_openssl/crypto/mem_clr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/mem_dbg.c (renamed from drivers/builtin_openssl/crypto/mem_dbg.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/asm/ghash-alpha.pl (renamed from drivers/builtin_openssl/crypto/modes/asm/ghash-alpha.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/asm/ghash-armv4.pl (renamed from drivers/builtin_openssl/crypto/modes/asm/ghash-armv4.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/modes/asm/ghash-ia64.pl (renamed from drivers/builtin_openssl/crypto/modes/asm/ghash-ia64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/asm/ghash-parisc.pl (renamed from drivers/builtin_openssl/crypto/modes/asm/ghash-parisc.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/asm/ghash-s390x.pl (renamed from drivers/builtin_openssl/crypto/modes/asm/ghash-s390x.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/asm/ghash-sparcv9.pl (renamed from drivers/builtin_openssl/crypto/modes/asm/ghash-sparcv9.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/asm/ghash-x86.pl (renamed from drivers/builtin_openssl/crypto/modes/asm/ghash-x86.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/asm/ghash-x86_64.pl (renamed from drivers/builtin_openssl/crypto/modes/asm/ghash-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/cbc128.c (renamed from drivers/builtin_openssl/crypto/modes/cbc128.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/ccm128.c (renamed from drivers/builtin_openssl/crypto/modes/ccm128.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/cfb128.c (renamed from drivers/builtin_openssl/crypto/modes/cfb128.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/ctr128.c (renamed from drivers/builtin_openssl/crypto/modes/ctr128.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/cts128.c (renamed from drivers/builtin_openssl/crypto/modes/cts128.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/gcm128.c (renamed from drivers/builtin_openssl/crypto/modes/gcm128.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/modes_lcl.h (renamed from drivers/builtin_openssl/crypto/modes/modes_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/ofb128.c (renamed from drivers/builtin_openssl/crypto/modes/ofb128.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/modes/xts128.c (renamed from drivers/builtin_openssl/crypto/modes/xts128.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/o_dir.c (renamed from drivers/builtin_openssl/crypto/o_dir.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/o_dir.h (renamed from drivers/builtin_openssl/crypto/o_dir.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/o_dir_test.c (renamed from drivers/builtin_openssl/crypto/o_dir_test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/o_fips.c (renamed from drivers/builtin_openssl/crypto/o_fips.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/o_init.c (renamed from drivers/builtin_openssl/crypto/o_init.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/o_str.c115
-rw-r--r--drivers/builtin_openssl2/crypto/o_str.h (renamed from drivers/builtin_openssl/crypto/o_str.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/o_time.c (renamed from drivers/builtin_openssl/crypto/o_time.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/o_time.h (renamed from drivers/builtin_openssl/crypto/o_time.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/o_names.c (renamed from drivers/builtin_openssl/crypto/objects/o_names.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_dat.c (renamed from drivers/builtin_openssl/crypto/objects/obj_dat.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_dat.h (renamed from drivers/builtin_openssl/crypto/objects/obj_dat.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_dat.pl (renamed from drivers/builtin_openssl/crypto/objects/obj_dat.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_err.c (renamed from drivers/builtin_openssl/crypto/objects/obj_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_lib.c (renamed from drivers/builtin_openssl/crypto/objects/obj_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_mac.num (renamed from drivers/builtin_openssl/crypto/objects/obj_mac.num)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_xref.c (renamed from drivers/builtin_openssl/crypto/objects/obj_xref.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_xref.h (renamed from drivers/builtin_openssl/crypto/objects/obj_xref.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/obj_xref.txt (renamed from drivers/builtin_openssl/crypto/objects/obj_xref.txt)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/objects.README (renamed from drivers/builtin_openssl/crypto/objects/objects.README)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/objects.pl (renamed from drivers/builtin_openssl/crypto/objects/objects.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/objects.txt (renamed from drivers/builtin_openssl/crypto/objects/objects.txt)0
-rw-r--r--drivers/builtin_openssl2/crypto/objects/objxref.pl (renamed from drivers/builtin_openssl/crypto/objects/objxref.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_asn.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_asn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_cl.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_cl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_err.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_ext.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_ext.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_ht.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_ht.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_lib.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_prn.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_prn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_srv.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_srv.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ocsp/ocsp_vfy.c (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp_vfy.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/opensslconf.h.bak (renamed from drivers/builtin_openssl/crypto/opensslconf.h.bak)0
-rw-r--r--drivers/builtin_openssl2/crypto/opensslconf.h.in (renamed from drivers/builtin_openssl/crypto/opensslconf.h.in)0
-rw-r--r--drivers/builtin_openssl2/crypto/pariscid.pl (renamed from drivers/builtin_openssl/crypto/pariscid.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/message (renamed from drivers/builtin_openssl/crypto/pem/message)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_all.c (renamed from drivers/builtin_openssl/crypto/pem/pem_all.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_err.c (renamed from drivers/builtin_openssl/crypto/pem/pem_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_info.c (renamed from drivers/builtin_openssl/crypto/pem/pem_info.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_lib.c (renamed from drivers/builtin_openssl/crypto/pem/pem_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_oth.c (renamed from drivers/builtin_openssl/crypto/pem/pem_oth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_pk8.c (renamed from drivers/builtin_openssl/crypto/pem/pem_pk8.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_pkey.c (renamed from drivers/builtin_openssl/crypto/pem/pem_pkey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_seal.c (renamed from drivers/builtin_openssl/crypto/pem/pem_seal.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_sign.c (renamed from drivers/builtin_openssl/crypto/pem/pem_sign.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_x509.c (renamed from drivers/builtin_openssl/crypto/pem/pem_x509.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pem_xaux.c (renamed from drivers/builtin_openssl/crypto/pem/pem_xaux.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pkcs7.lis (renamed from drivers/builtin_openssl/crypto/pem/pkcs7.lis)0
-rw-r--r--drivers/builtin_openssl2/crypto/pem/pvkfmt.c (renamed from drivers/builtin_openssl/crypto/pem/pvkfmt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/perlasm/cbc.pl (renamed from drivers/builtin_openssl/crypto/perlasm/cbc.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/perlasm/ppc-xlate.pl (renamed from drivers/builtin_openssl/crypto/perlasm/ppc-xlate.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/perlasm/readme (renamed from drivers/builtin_openssl/crypto/perlasm/readme)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/perlasm/x86_64-xlate.pl (renamed from drivers/builtin_openssl/crypto/perlasm/x86_64-xlate.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/perlasm/x86asm.pl (renamed from drivers/builtin_openssl/crypto/perlasm/x86asm.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/perlasm/x86gas.pl (renamed from drivers/builtin_openssl/crypto/perlasm/x86gas.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/perlasm/x86masm.pl (renamed from drivers/builtin_openssl/crypto/perlasm/x86masm.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/perlasm/x86nasm.pl (renamed from drivers/builtin_openssl/crypto/perlasm/x86nasm.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_add.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_add.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_asn.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_asn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_attr.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_attr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_crpt.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_crpt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_crt.c374
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_decr.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_decr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_init.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_init.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_key.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_key.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_kiss.c302
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_mutl.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_mutl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_npas.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_npas.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_p8d.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_p8d.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_p8e.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_p8e.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/p12_utl.c (renamed from drivers/builtin_openssl/crypto/pkcs12/p12_utl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs12/pk12err.c (renamed from drivers/builtin_openssl/crypto/pkcs12/pk12err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/bio_ber.c (renamed from drivers/builtin_openssl/crypto/pkcs7/bio_ber.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/bio_pk7.c (renamed from drivers/builtin_openssl/crypto/pkcs7/bio_pk7.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/dec.c (renamed from drivers/builtin_openssl/crypto/pkcs7/dec.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/des.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/des.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/doc (renamed from drivers/builtin_openssl/crypto/pkcs7/doc)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/enc.c (renamed from drivers/builtin_openssl/crypto/pkcs7/enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/es1.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/es1.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/example.c (renamed from drivers/builtin_openssl/crypto/pkcs7/example.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/example.h (renamed from drivers/builtin_openssl/crypto/pkcs7/example.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/info.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/info.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/infokey.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/infokey.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/p7/a1 (renamed from drivers/builtin_openssl/crypto/pkcs7/p7/a1)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/p7/a2 (renamed from drivers/builtin_openssl/crypto/pkcs7/p7/a2)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/p7/cert.p7c (renamed from drivers/builtin_openssl/crypto/pkcs7/p7/cert.p7c)bin1728 -> 1728 bytes
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/p7/smime.p7m (renamed from drivers/builtin_openssl/crypto/pkcs7/p7/smime.p7m)bin4894 -> 4894 bytes
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/p7/smime.p7s (renamed from drivers/builtin_openssl/crypto/pkcs7/p7/smime.p7s)bin2625 -> 2625 bytes
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pk7_asn1.c (renamed from drivers/builtin_openssl/crypto/pkcs7/pk7_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pk7_attr.c (renamed from drivers/builtin_openssl/crypto/pkcs7/pk7_attr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pk7_dgst.c (renamed from drivers/builtin_openssl/crypto/pkcs7/pk7_dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pk7_doit.c1305
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pk7_enc.c (renamed from drivers/builtin_openssl/crypto/pkcs7/pk7_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pk7_lib.c (renamed from drivers/builtin_openssl/crypto/pkcs7/pk7_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pk7_mime.c (renamed from drivers/builtin_openssl/crypto/pkcs7/pk7_mime.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pk7_smime.c (renamed from drivers/builtin_openssl/crypto/pkcs7/pk7_smime.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/pkcs7err.c188
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/server.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/server.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/sign.c (renamed from drivers/builtin_openssl/crypto/pkcs7/sign.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/3des.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/3des.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/3dess.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/3dess.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/c.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/c.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/ff (renamed from drivers/builtin_openssl/crypto/pkcs7/t/ff)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/msie-e (renamed from drivers/builtin_openssl/crypto/pkcs7/t/msie-e)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/msie-e.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/msie-e.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-01 (renamed from drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-01)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-01.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-01.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-02 (renamed from drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-02)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-02.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-02.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/msie-s-a-e (renamed from drivers/builtin_openssl/crypto/pkcs7/t/msie-s-a-e)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/msie-s-a-e.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/msie-s-a-e.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/nav-smime (renamed from drivers/builtin_openssl/crypto/pkcs7/t/nav-smime)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/s.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/s.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/t/server.pem (renamed from drivers/builtin_openssl/crypto/pkcs7/t/server.pem)0
-rw-r--r--drivers/builtin_openssl2/crypto/pkcs7/verify.c (renamed from drivers/builtin_openssl/crypto/pkcs7/verify.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ppccap.c (renamed from drivers/builtin_openssl/crypto/ppccap.c)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/ppccpuid.pl (renamed from drivers/builtin_openssl/crypto/ppccpuid.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/pqueue/pq_test.c (renamed from drivers/builtin_openssl/crypto/pqueue/pq_test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/pqueue/pqueue.c (renamed from drivers/builtin_openssl/crypto/pqueue/pqueue.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/md_rand.c (renamed from drivers/builtin_openssl/crypto/rand/md_rand.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_egd.c (renamed from drivers/builtin_openssl/crypto/rand/rand_egd.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_err.c (renamed from drivers/builtin_openssl/crypto/rand/rand_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_lcl.h (renamed from drivers/builtin_openssl/crypto/rand/rand_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_lib.c (renamed from drivers/builtin_openssl/crypto/rand/rand_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_nw.c (renamed from drivers/builtin_openssl/crypto/rand/rand_nw.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_os2.c (renamed from drivers/builtin_openssl/crypto/rand/rand_os2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_unix.c (renamed from drivers/builtin_openssl/crypto/rand/rand_unix.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_vms.c (renamed from drivers/builtin_openssl/crypto/rand/rand_vms.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/rand_win.c (renamed from drivers/builtin_openssl/crypto/rand/rand_win.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/randfile.c (renamed from drivers/builtin_openssl/crypto/rand/randfile.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rand/randtest.c (renamed from drivers/builtin_openssl/crypto/rand/randtest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rc2_cbc.c (renamed from drivers/builtin_openssl/crypto/rc2/rc2_cbc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rc2_ecb.c (renamed from drivers/builtin_openssl/crypto/rc2/rc2_ecb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rc2_locl.h (renamed from drivers/builtin_openssl/crypto/rc2/rc2_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rc2_skey.c (renamed from drivers/builtin_openssl/crypto/rc2/rc2_skey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rc2cfb64.c (renamed from drivers/builtin_openssl/crypto/rc2/rc2cfb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rc2ofb64.c (renamed from drivers/builtin_openssl/crypto/rc2/rc2ofb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rc2speed.c (renamed from drivers/builtin_openssl/crypto/rc2/rc2speed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rc2test.c (renamed from drivers/builtin_openssl/crypto/rc2/rc2test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/rrc2.doc (renamed from drivers/builtin_openssl/crypto/rc2/rrc2.doc)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/tab.c (renamed from drivers/builtin_openssl/crypto/rc2/tab.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc2/version (renamed from drivers/builtin_openssl/crypto/rc2/version)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/asm/rc4-586.pl (renamed from drivers/builtin_openssl/crypto/rc4/asm/rc4-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/asm/rc4-ia64.pl (renamed from drivers/builtin_openssl/crypto/rc4/asm/rc4-ia64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/asm/rc4-md5-x86_64.pl (renamed from drivers/builtin_openssl/crypto/rc4/asm/rc4-md5-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/asm/rc4-parisc.pl (renamed from drivers/builtin_openssl/crypto/rc4/asm/rc4-parisc.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/asm/rc4-s390x.pl (renamed from drivers/builtin_openssl/crypto/rc4/asm/rc4-s390x.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/rc4/asm/rc4-x86_64.pl (renamed from drivers/builtin_openssl/crypto/rc4/asm/rc4-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rc4.c (renamed from drivers/builtin_openssl/crypto/rc4/rc4.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rc4_enc.c (renamed from drivers/builtin_openssl/crypto/rc4/rc4_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rc4_locl.h (renamed from drivers/builtin_openssl/crypto/rc4/rc4_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rc4_skey.c (renamed from drivers/builtin_openssl/crypto/rc4/rc4_skey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rc4_utl.c (renamed from drivers/builtin_openssl/crypto/rc4/rc4_utl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rc4s.cpp (renamed from drivers/builtin_openssl/crypto/rc4/rc4s.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rc4speed.c (renamed from drivers/builtin_openssl/crypto/rc4/rc4speed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rc4test.c (renamed from drivers/builtin_openssl/crypto/rc4/rc4test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc4/rrc4.doc (renamed from drivers/builtin_openssl/crypto/rc4/rrc4.doc)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/asm/rc5-586.pl (renamed from drivers/builtin_openssl/crypto/rc5/asm/rc5-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5.h (renamed from drivers/builtin_openssl/crypto/rc5/rc5.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5_ecb.c (renamed from drivers/builtin_openssl/crypto/rc5/rc5_ecb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5_enc.c (renamed from drivers/builtin_openssl/crypto/rc5/rc5_enc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5_locl.h (renamed from drivers/builtin_openssl/crypto/rc5/rc5_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5_skey.c (renamed from drivers/builtin_openssl/crypto/rc5/rc5_skey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5cfb64.c (renamed from drivers/builtin_openssl/crypto/rc5/rc5cfb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5ofb64.c (renamed from drivers/builtin_openssl/crypto/rc5/rc5ofb64.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5s.cpp (renamed from drivers/builtin_openssl/crypto/rc5/rc5s.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5speed.c (renamed from drivers/builtin_openssl/crypto/rc5/rc5speed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rc5/rc5test.c (renamed from drivers/builtin_openssl/crypto/rc5/rc5test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/README (renamed from drivers/builtin_openssl/crypto/ripemd/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/asm/rips.cpp (renamed from drivers/builtin_openssl/crypto/ripemd/asm/rips.cpp)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/asm/rmd-586.pl (renamed from drivers/builtin_openssl/crypto/ripemd/asm/rmd-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/rmd160.c (renamed from drivers/builtin_openssl/crypto/ripemd/rmd160.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/rmd_dgst.c (renamed from drivers/builtin_openssl/crypto/ripemd/rmd_dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/rmd_locl.h (renamed from drivers/builtin_openssl/crypto/ripemd/rmd_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/rmd_one.c (renamed from drivers/builtin_openssl/crypto/ripemd/rmd_one.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/rmdconst.h (renamed from drivers/builtin_openssl/crypto/ripemd/rmdconst.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/ripemd/rmdtest.c (renamed from drivers/builtin_openssl/crypto/ripemd/rmdtest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_ameth.c698
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_asn1.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_chk.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_chk.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_crpt.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_crpt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_depr.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_depr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_eay.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_eay.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_err.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_gen.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_gen.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_lib.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_locl.h (renamed from drivers/builtin_openssl/crypto/rsa/rsa_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_none.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_none.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_null.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_null.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_oaep.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_oaep.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_pk1.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_pk1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_pmeth.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_pmeth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_prn.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_prn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_pss.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_pss.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_saos.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_saos.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_sign.c318
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_ssl.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_ssl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_test.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/rsa/rsa_x931.c (renamed from drivers/builtin_openssl/crypto/rsa/rsa_x931.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/s390xcap.c (renamed from drivers/builtin_openssl/crypto/s390xcap.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/s390xcpuid.S (renamed from drivers/builtin_openssl/crypto/s390xcpuid.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/seed/seed.c (renamed from drivers/builtin_openssl/crypto/seed/seed.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/seed/seed_cbc.c (renamed from drivers/builtin_openssl/crypto/seed/seed_cbc.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/seed/seed_cfb.c (renamed from drivers/builtin_openssl/crypto/seed/seed_cfb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/seed/seed_ecb.c (renamed from drivers/builtin_openssl/crypto/seed/seed_ecb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/seed/seed_locl.h (renamed from drivers/builtin_openssl/crypto/seed/seed_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/seed/seed_ofb.c (renamed from drivers/builtin_openssl/crypto/seed/seed_ofb.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/README (renamed from drivers/builtin_openssl/crypto/sha/asm/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-586.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-alpha.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-alpha.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-armv4-large.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-armv4-large.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-ia64.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-ia64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-mips.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-mips.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-parisc.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-parisc.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/sha/asm/sha1-ppc.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-ppc.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-s390x.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-s390x.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-sparcv9.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-sparcv9.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-sparcv9a.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-sparcv9a.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha1-thumb.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-thumb.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/sha/asm/sha1-x86_64.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha1-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha256-586.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha256-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha256-armv4.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha256-armv4.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha512-586.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-586.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha512-armv4.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-armv4.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/sha/asm/sha512-ia64.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-ia64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha512-mips.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-mips.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/sha/asm/sha512-parisc.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-parisc.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/sha/asm/sha512-ppc.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-ppc.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha512-s390x.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-s390x.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/asm/sha512-sparcv9.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-sparcv9.pl)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/sha/asm/sha512-x86_64.pl (renamed from drivers/builtin_openssl/crypto/sha/asm/sha512-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha.c (renamed from drivers/builtin_openssl/crypto/sha/sha.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha1.c (renamed from drivers/builtin_openssl/crypto/sha/sha1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha1_one.c (renamed from drivers/builtin_openssl/crypto/sha/sha1_one.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha1dgst.c (renamed from drivers/builtin_openssl/crypto/sha/sha1dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha1test.c (renamed from drivers/builtin_openssl/crypto/sha/sha1test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha256.c (renamed from drivers/builtin_openssl/crypto/sha/sha256.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha256t.c (renamed from drivers/builtin_openssl/crypto/sha/sha256t.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha512.c (renamed from drivers/builtin_openssl/crypto/sha/sha512.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha512t.c (renamed from drivers/builtin_openssl/crypto/sha/sha512t.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha_dgst.c (renamed from drivers/builtin_openssl/crypto/sha/sha_dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha_locl.h (renamed from drivers/builtin_openssl/crypto/sha/sha_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/sha_one.c (renamed from drivers/builtin_openssl/crypto/sha/sha_one.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sha/shatest.c (renamed from drivers/builtin_openssl/crypto/sha/shatest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/sparccpuid.S (renamed from drivers/builtin_openssl/crypto/sparccpuid.S)0
-rw-r--r--drivers/builtin_openssl2/crypto/sparcv9cap.c (renamed from drivers/builtin_openssl/crypto/sparcv9cap.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/srp/srp_grps.h (renamed from drivers/builtin_openssl/crypto/srp/srp_grps.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/srp/srp_lcl.h (renamed from drivers/builtin_openssl/crypto/srp/srp_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/srp/srp_lib.c (renamed from drivers/builtin_openssl/crypto/srp/srp_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/srp/srp_vfy.c661
-rw-r--r--drivers/builtin_openssl2/crypto/srp/srptest.c (renamed from drivers/builtin_openssl/crypto/srp/srptest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/stack/stack.c (renamed from drivers/builtin_openssl/crypto/stack/stack.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/store/README (renamed from drivers/builtin_openssl/crypto/store/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/store/store.h (renamed from drivers/builtin_openssl/crypto/store/store.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/store/str_err.c (renamed from drivers/builtin_openssl/crypto/store/str_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/store/str_lib.c (renamed from drivers/builtin_openssl/crypto/store/str_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/store/str_locl.h (renamed from drivers/builtin_openssl/crypto/store/str_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/store/str_mem.c (renamed from drivers/builtin_openssl/crypto/store/str_mem.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/store/str_meth.c (renamed from drivers/builtin_openssl/crypto/store/str_meth.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/README (renamed from drivers/builtin_openssl/crypto/threads/README)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/mttest.c (renamed from drivers/builtin_openssl/crypto/threads/mttest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/netware.bat (renamed from drivers/builtin_openssl/crypto/threads/netware.bat)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/profile.sh (renamed from drivers/builtin_openssl/crypto/threads/profile.sh)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/threads/ptest.bat (renamed from drivers/builtin_openssl/crypto/threads/ptest.bat)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/pthread.sh (renamed from drivers/builtin_openssl/crypto/threads/pthread.sh)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/threads/pthread2.sh (renamed from drivers/builtin_openssl/crypto/threads/pthread2.sh)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/pthreads-vms.com (renamed from drivers/builtin_openssl/crypto/threads/pthreads-vms.com)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/purify.sh (renamed from drivers/builtin_openssl/crypto/threads/purify.sh)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/solaris.sh (renamed from drivers/builtin_openssl/crypto/threads/solaris.sh)0
-rw-r--r--drivers/builtin_openssl2/crypto/threads/th-lock.c (renamed from drivers/builtin_openssl/crypto/threads/th-lock.c)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/threads/win32.bat (renamed from drivers/builtin_openssl/crypto/threads/win32.bat)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_asn1.c (renamed from drivers/builtin_openssl/crypto/ts/ts_asn1.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_conf.c (renamed from drivers/builtin_openssl/crypto/ts/ts_conf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_err.c (renamed from drivers/builtin_openssl/crypto/ts/ts_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_lib.c (renamed from drivers/builtin_openssl/crypto/ts/ts_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_req_print.c (renamed from drivers/builtin_openssl/crypto/ts/ts_req_print.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_req_utils.c (renamed from drivers/builtin_openssl/crypto/ts/ts_req_utils.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_rsp_print.c (renamed from drivers/builtin_openssl/crypto/ts/ts_rsp_print.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_rsp_sign.c (renamed from drivers/builtin_openssl/crypto/ts/ts_rsp_sign.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_rsp_utils.c (renamed from drivers/builtin_openssl/crypto/ts/ts_rsp_utils.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_rsp_verify.c729
-rw-r--r--drivers/builtin_openssl2/crypto/ts/ts_verify_ctx.c (renamed from drivers/builtin_openssl/crypto/ts/ts_verify_ctx.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/txt_db/txt_db.c (renamed from drivers/builtin_openssl/crypto/txt_db/txt_db.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ui/ui_compat.c (renamed from drivers/builtin_openssl/crypto/ui/ui_compat.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ui/ui_err.c (renamed from drivers/builtin_openssl/crypto/ui/ui_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ui/ui_lib.c (renamed from drivers/builtin_openssl/crypto/ui/ui_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ui/ui_locl.h (renamed from drivers/builtin_openssl/crypto/ui/ui_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/ui/ui_openssl.c (renamed from drivers/builtin_openssl/crypto/ui/ui_openssl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/ui/ui_util.c (renamed from drivers/builtin_openssl/crypto/ui/ui_util.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/uid.c (renamed from drivers/builtin_openssl/crypto/uid.c)0
-rwxr-xr-xdrivers/builtin_openssl2/crypto/vms_rms.h (renamed from drivers/builtin_openssl/crypto/vms_rms.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/whrlpool/asm/wp-mmx.pl (renamed from drivers/builtin_openssl/crypto/whrlpool/asm/wp-mmx.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/whrlpool/asm/wp-x86_64.pl (renamed from drivers/builtin_openssl/crypto/whrlpool/asm/wp-x86_64.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/whrlpool/wp_block.c (renamed from drivers/builtin_openssl/crypto/whrlpool/wp_block.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/whrlpool/wp_dgst.c (renamed from drivers/builtin_openssl/crypto/whrlpool/wp_dgst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/whrlpool/wp_locl.h (renamed from drivers/builtin_openssl/crypto/whrlpool/wp_locl.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/whrlpool/wp_test.c (renamed from drivers/builtin_openssl/crypto/whrlpool/wp_test.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/by_dir.c (renamed from drivers/builtin_openssl/crypto/x509/by_dir.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/by_file.c (renamed from drivers/builtin_openssl/crypto/x509/by_file.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_att.c (renamed from drivers/builtin_openssl/crypto/x509/x509_att.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_cmp.c (renamed from drivers/builtin_openssl/crypto/x509/x509_cmp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_d2.c (renamed from drivers/builtin_openssl/crypto/x509/x509_d2.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_def.c (renamed from drivers/builtin_openssl/crypto/x509/x509_def.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_err.c (renamed from drivers/builtin_openssl/crypto/x509/x509_err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_ext.c (renamed from drivers/builtin_openssl/crypto/x509/x509_ext.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_lu.c (renamed from drivers/builtin_openssl/crypto/x509/x509_lu.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_obj.c (renamed from drivers/builtin_openssl/crypto/x509/x509_obj.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_r2x.c (renamed from drivers/builtin_openssl/crypto/x509/x509_r2x.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_req.c (renamed from drivers/builtin_openssl/crypto/x509/x509_req.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_set.c (renamed from drivers/builtin_openssl/crypto/x509/x509_set.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_trs.c (renamed from drivers/builtin_openssl/crypto/x509/x509_trs.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_txt.c (renamed from drivers/builtin_openssl/crypto/x509/x509_txt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_v3.c (renamed from drivers/builtin_openssl/crypto/x509/x509_v3.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_vfy.c (renamed from drivers/builtin_openssl/crypto/x509/x509_vfy.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_vpm.c (renamed from drivers/builtin_openssl/crypto/x509/x509_vpm.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509cset.c (renamed from drivers/builtin_openssl/crypto/x509/x509cset.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509name.c (renamed from drivers/builtin_openssl/crypto/x509/x509name.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509rset.c (renamed from drivers/builtin_openssl/crypto/x509/x509rset.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509spki.c (renamed from drivers/builtin_openssl/crypto/x509/x509spki.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509type.c (renamed from drivers/builtin_openssl/crypto/x509/x509type.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x_all.c (renamed from drivers/builtin_openssl/crypto/x509/x_all.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/ext_dat.h (renamed from drivers/builtin_openssl/crypto/x509v3/ext_dat.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/pcy_cache.c (renamed from drivers/builtin_openssl/crypto/x509v3/pcy_cache.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/pcy_data.c (renamed from drivers/builtin_openssl/crypto/x509v3/pcy_data.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/pcy_int.h (renamed from drivers/builtin_openssl/crypto/x509v3/pcy_int.h)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/pcy_lib.c (renamed from drivers/builtin_openssl/crypto/x509v3/pcy_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/pcy_map.c (renamed from drivers/builtin_openssl/crypto/x509v3/pcy_map.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/pcy_node.c (renamed from drivers/builtin_openssl/crypto/x509v3/pcy_node.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/pcy_tree.c (renamed from drivers/builtin_openssl/crypto/x509v3/pcy_tree.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/tabtest.c (renamed from drivers/builtin_openssl/crypto/x509v3/tabtest.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_addr.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_addr.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_akey.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_akey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_akeya.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_akeya.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_alt.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_alt.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_asid.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_asid.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_bcons.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_bcons.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_bitst.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_bitst.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_conf.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_conf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_cpols.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_cpols.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_crld.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_crld.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_enum.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_enum.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_extku.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_extku.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_genn.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_genn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_ia5.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_ia5.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_info.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_info.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_int.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_int.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_lib.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_lib.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_ncons.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_ncons.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_ocsp.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_ocsp.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_pci.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_pci.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_pcia.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_pcia.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_pcons.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_pcons.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_pku.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_pku.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_pmaps.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_pmaps.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_prn.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_prn.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_purp.c767
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_skey.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_skey.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_sxnet.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_sxnet.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3_utl.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3_utl.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3conf.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3conf.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3err.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3err.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x509v3/v3prin.c (renamed from drivers/builtin_openssl/crypto/x509v3/v3prin.c)0
-rw-r--r--drivers/builtin_openssl2/crypto/x86_64cpuid.pl (renamed from drivers/builtin_openssl/crypto/x86_64cpuid.pl)0
-rw-r--r--drivers/builtin_openssl2/crypto/x86cpuid.pl (renamed from drivers/builtin_openssl/crypto/x86cpuid.pl)0
-rw-r--r--drivers/builtin_openssl2/e_os.h753
-rw-r--r--drivers/builtin_openssl2/nocpuid.c (renamed from drivers/builtin_openssl/nocpuid.c)0
-rw-r--r--drivers/builtin_openssl2/openssl/aes.h (renamed from drivers/builtin_openssl/crypto/aes/aes.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/asn1.h (renamed from drivers/builtin_openssl/crypto/asn1/asn1.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/asn1_mac.h (renamed from drivers/builtin_openssl/crypto/asn1/asn1_mac.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/asn1t.h (renamed from drivers/builtin_openssl/crypto/asn1/asn1t.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/bio.h (renamed from drivers/builtin_openssl/crypto/bio/bio.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/blowfish.h (renamed from drivers/builtin_openssl/crypto/bf/blowfish.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/bn.h (renamed from drivers/builtin_openssl/crypto/bn/bn.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/buffer.h (renamed from drivers/builtin_openssl/crypto/buffer/buffer.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/camellia.h (renamed from drivers/builtin_openssl/crypto/camellia/camellia.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/cast.h (renamed from drivers/builtin_openssl/crypto/cast/cast.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/cmac.h (renamed from drivers/builtin_openssl/crypto/cmac/cmac.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/cms.h (renamed from drivers/builtin_openssl/crypto/cms/cms.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/comp.h (renamed from drivers/builtin_openssl/crypto/comp/comp.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/conf.h (renamed from drivers/builtin_openssl/crypto/conf/conf.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/conf_api.h (renamed from drivers/builtin_openssl/crypto/conf/conf_api.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/crypto.h (renamed from drivers/builtin_openssl/crypto/crypto.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/des.h (renamed from drivers/builtin_openssl/crypto/des/des.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/des_old.h (renamed from drivers/builtin_openssl/crypto/des/des_old.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/dh.h (renamed from drivers/builtin_openssl/crypto/dh/dh.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/dsa.h (renamed from drivers/builtin_openssl/crypto/dsa/dsa.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/dso.h (renamed from drivers/builtin_openssl/crypto/dso/dso.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/dtls1.h290
-rw-r--r--drivers/builtin_openssl2/openssl/e_os2.h (renamed from drivers/builtin_openssl/e_os2.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ebcdic.h (renamed from drivers/builtin_openssl/crypto/ebcdic.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ec.h (renamed from drivers/builtin_openssl/crypto/ec/ec.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ecdh.h (renamed from drivers/builtin_openssl/crypto/ecdh/ecdh.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ecdsa.h (renamed from drivers/builtin_openssl/crypto/ecdsa/ecdsa.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/engine.h (renamed from drivers/builtin_openssl/crypto/engine/engine.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/err.h (renamed from drivers/builtin_openssl/crypto/err/err.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/evp.h (renamed from drivers/builtin_openssl/crypto/evp/evp.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/hmac.h (renamed from drivers/builtin_openssl/crypto/hmac/hmac.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/idea.h (renamed from drivers/builtin_openssl/crypto/idea/idea.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/krb5_asn.h (renamed from drivers/builtin_openssl/crypto/krb5/krb5_asn.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/kssl.h (renamed from drivers/builtin_openssl/openssl/kssl.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/lhash.h (renamed from drivers/builtin_openssl/crypto/lhash/lhash.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/md4.h (renamed from drivers/builtin_openssl/crypto/md4/md4.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/md5.h127
-rw-r--r--drivers/builtin_openssl2/openssl/mdc2.h (renamed from drivers/builtin_openssl/crypto/mdc2/mdc2.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/modes.h (renamed from drivers/builtin_openssl/crypto/modes/modes.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/obj_mac.h (renamed from drivers/builtin_openssl/crypto/objects/obj_mac.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/objects.h (renamed from drivers/builtin_openssl/crypto/objects/objects.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ocsp.h (renamed from drivers/builtin_openssl/crypto/ocsp/ocsp.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/opensslconf.h (renamed from drivers/builtin_openssl/openssl/opensslconf.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/opensslv.h89
-rw-r--r--drivers/builtin_openssl2/openssl/ossl_typ.h (renamed from drivers/builtin_openssl/crypto/ossl_typ.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/pem.h (renamed from drivers/builtin_openssl/crypto/pem/pem.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/pem2.h (renamed from drivers/builtin_openssl/crypto/pem/pem2.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/pkcs12.h (renamed from drivers/builtin_openssl/crypto/pkcs12/pkcs12.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/pkcs7.h500
-rw-r--r--drivers/builtin_openssl2/openssl/pqueue.h (renamed from drivers/builtin_openssl/crypto/pqueue/pqueue.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/rand.h166
-rw-r--r--drivers/builtin_openssl2/openssl/rc2.h (renamed from drivers/builtin_openssl/crypto/rc2/rc2.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/rc4.h (renamed from drivers/builtin_openssl/crypto/rc4/rc4.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ripemd.h (renamed from drivers/builtin_openssl/crypto/ripemd/ripemd.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/rsa.h (renamed from drivers/builtin_openssl/crypto/rsa/rsa.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/safestack.h (renamed from drivers/builtin_openssl/crypto/stack/safestack.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/seed.h (renamed from drivers/builtin_openssl/crypto/seed/seed.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/sha.h (renamed from drivers/builtin_openssl/crypto/sha/sha.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/srp.h (renamed from drivers/builtin_openssl/crypto/srp/srp.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/srtp.h (renamed from drivers/builtin_openssl/openssl/srtp.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ssl.h2590
-rw-r--r--drivers/builtin_openssl2/openssl/ssl2.h (renamed from drivers/builtin_openssl/openssl/ssl2.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ssl23.h (renamed from drivers/builtin_openssl/openssl/ssl23.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ssl3.h694
-rw-r--r--drivers/builtin_openssl2/openssl/stack.h (renamed from drivers/builtin_openssl/crypto/stack/stack.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/symhacks.h (renamed from drivers/builtin_openssl/crypto/symhacks.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/tls1.h (renamed from drivers/builtin_openssl/openssl/tls1.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ts.h (renamed from drivers/builtin_openssl/crypto/ts/ts.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/txt_db.h (renamed from drivers/builtin_openssl/crypto/txt_db/txt_db.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ui.h (renamed from drivers/builtin_openssl/crypto/ui/ui.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/ui_compat.h (renamed from drivers/builtin_openssl/crypto/ui/ui_compat.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/whrlpool.h (renamed from drivers/builtin_openssl/crypto/whrlpool/whrlpool.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/x509.h (renamed from drivers/builtin_openssl/crypto/x509/x509.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/x509_vfy.h (renamed from drivers/builtin_openssl/crypto/x509/x509_vfy.h)0
-rw-r--r--drivers/builtin_openssl2/openssl/x509v3.h (renamed from drivers/builtin_openssl/crypto/x509v3/x509v3.h)0
-rw-r--r--drivers/builtin_openssl2/ssl/bio_ssl.c (renamed from drivers/builtin_openssl/ssl/bio_ssl.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/d1_both.c1617
-rw-r--r--drivers/builtin_openssl2/ssl/d1_clnt.c (renamed from drivers/builtin_openssl/ssl/d1_clnt.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/d1_enc.c (renamed from drivers/builtin_openssl/ssl/d1_enc.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/d1_lib.c486
-rw-r--r--drivers/builtin_openssl2/ssl/d1_meth.c (renamed from drivers/builtin_openssl/ssl/d1_meth.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/d1_pkt.c1901
-rw-r--r--drivers/builtin_openssl2/ssl/d1_srtp.c (renamed from drivers/builtin_openssl/ssl/d1_srtp.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/d1_srvr.c1723
-rw-r--r--drivers/builtin_openssl2/ssl/heartbeat_test.c465
-rwxr-xr-xdrivers/builtin_openssl2/ssl/install-ssl.com (renamed from drivers/builtin_openssl/ssl/install-ssl.com)0
-rw-r--r--drivers/builtin_openssl2/ssl/kssl.c (renamed from drivers/builtin_openssl/ssl/kssl.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/kssl_lcl.h (renamed from drivers/builtin_openssl/ssl/kssl_lcl.h)0
-rw-r--r--drivers/builtin_openssl2/ssl/s23_clnt.c (renamed from drivers/builtin_openssl/ssl/s23_clnt.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s23_lib.c (renamed from drivers/builtin_openssl/ssl/s23_lib.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s23_meth.c (renamed from drivers/builtin_openssl/ssl/s23_meth.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s23_pkt.c (renamed from drivers/builtin_openssl/ssl/s23_pkt.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s23_srvr.c (renamed from drivers/builtin_openssl/ssl/s23_srvr.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s2_clnt.c (renamed from drivers/builtin_openssl/ssl/s2_clnt.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s2_enc.c (renamed from drivers/builtin_openssl/ssl/s2_enc.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s2_lib.c (renamed from drivers/builtin_openssl/ssl/s2_lib.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s2_meth.c (renamed from drivers/builtin_openssl/ssl/s2_meth.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s2_pkt.c (renamed from drivers/builtin_openssl/ssl/s2_pkt.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s2_srvr.c (renamed from drivers/builtin_openssl/ssl/s2_srvr.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s3_both.c (renamed from drivers/builtin_openssl/ssl/s3_both.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s3_cbc.c (renamed from drivers/builtin_openssl/ssl/s3_cbc.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s3_clnt.c3381
-rw-r--r--drivers/builtin_openssl2/ssl/s3_enc.c (renamed from drivers/builtin_openssl/ssl/s3_enc.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s3_lib.c (renamed from drivers/builtin_openssl/ssl/s3_lib.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s3_meth.c (renamed from drivers/builtin_openssl/ssl/s3_meth.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/s3_pkt.c1557
-rw-r--r--drivers/builtin_openssl2/ssl/s3_srvr.c3594
-rw-r--r--drivers/builtin_openssl2/ssl/ssl-lib.com1226
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_algs.c (renamed from drivers/builtin_openssl/ssl/ssl_algs.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_asn1.c646
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_cert.c853
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_ciph.c (renamed from drivers/builtin_openssl/ssl/ssl_ciph.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_err.c610
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_err2.c (renamed from drivers/builtin_openssl/ssl/ssl_err2.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_lib.c3269
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_locl.h (renamed from drivers/builtin_openssl/ssl/ssl_locl.h)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_rsa.c (renamed from drivers/builtin_openssl/ssl/ssl_rsa.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_sess.c (renamed from drivers/builtin_openssl/ssl/ssl_sess.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_stat.c (renamed from drivers/builtin_openssl/ssl/ssl_stat.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_task.c (renamed from drivers/builtin_openssl/ssl/ssl_task.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssl_txt.c (renamed from drivers/builtin_openssl/ssl/ssl_txt.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/ssltest.c (renamed from drivers/builtin_openssl/ssl/ssltest.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/t1_clnt.c (renamed from drivers/builtin_openssl/ssl/t1_clnt.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/t1_enc.c1250
-rw-r--r--drivers/builtin_openssl2/ssl/t1_lib.c2732
-rw-r--r--drivers/builtin_openssl2/ssl/t1_meth.c (renamed from drivers/builtin_openssl/ssl/t1_meth.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/t1_reneg.c (renamed from drivers/builtin_openssl/ssl/t1_reneg.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/t1_srvr.c (renamed from drivers/builtin_openssl/ssl/t1_srvr.c)0
-rw-r--r--drivers/builtin_openssl2/ssl/tls_srp.c (renamed from drivers/builtin_openssl/ssl/tls_srp.c)0
-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.cpp2
-rw-r--r--drivers/chibi/cp_loader_mod.h2
-rw-r--r--drivers/chibi/cp_loader_s3m.cpp4
-rw-r--r--drivers/chibi/cp_loader_s3m.h2
-rw-r--r--drivers/chibi/cp_loader_xm.cpp2
-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.cpp4
-rw-r--r--drivers/chibi/cp_player_data.h2
-rw-r--r--drivers/chibi/cp_player_data_control.cpp6
-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.cpp18
-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.cpp35
-rw-r--r--drivers/chibi/event_stream_chibi.h4
-rw-r--r--drivers/convex_decomp/b2Glue.h3
-rw-r--r--drivers/convex_decomp/b2Polygon.cpp5
-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/SCsub4
-rw-r--r--drivers/etc1/rg_etc1.cpp4905
-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.h4
-rw-r--r--drivers/gl_context/glew.c4
-rw-r--r--drivers/gles1/SCsub5
-rw-r--r--drivers/gles1/rasterizer_gles1.cpp5957
-rw-r--r--drivers/gles1/rasterizer_gles1.h1242
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp2982
-rw-r--r--drivers/gles2/rasterizer_gles2.h229
-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.cpp403
-rw-r--r--drivers/gles2/shader_compiler_gles2.h35
-rw-r--r--drivers/gles2/shader_gles2.cpp6
-rw-r--r--drivers/gles2/shader_gles2.h2
-rw-r--r--drivers/gles2/shaders/SCsub3
-rw-r--r--drivers/gles2/shaders/canvas.glsl337
-rw-r--r--drivers/gles2/shaders/canvas_shadow.glsl62
-rw-r--r--drivers/gles2/shaders/copy.glsl20
-rw-r--r--drivers/gles2/shaders/material.glsl167
-rw-r--r--drivers/jpg/SCsub1
-rw-r--r--drivers/mpc/SCsub1
-rw-r--r--drivers/mpc/audio_stream_mpc.cpp139
-rw-r--r--drivers/mpc/audio_stream_mpc.h47
-rw-r--r--drivers/mpc/mpc_reader.c1
-rw-r--r--drivers/nedmalloc/SCsub1
-rw-r--r--drivers/nedmalloc/malloc.c.h11628
-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/SCsub1
-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/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/SCsub6
-rw-r--r--drivers/png/image_loader_png.cpp27
-rw-r--r--drivers/png/image_loader_png.h5
-rw-r--r--drivers/png/pngpriv.h6
-rw-r--r--drivers/png/resource_saver_png.cpp78
-rw-r--r--drivers/png/resource_saver_png.h4
-rw-r--r--drivers/pulseaudio/SCsub5
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp207
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h84
-rw-r--r--drivers/pvr/AlphaBitmap.h18
-rw-r--r--drivers/pvr/BitScale.cpp184
-rw-r--r--drivers/pvr/BitScale.h28
-rw-r--r--drivers/pvr/BitUtility.h19
-rw-r--r--drivers/pvr/Bitmap.h34
-rw-r--r--drivers/pvr/ColorRgba.h152
-rw-r--r--drivers/pvr/Interval.h21
-rw-r--r--drivers/pvr/MortonTable.cpp43
-rw-r--r--drivers/pvr/MortonTable.h18
-rw-r--r--drivers/pvr/Point2.h17
-rw-r--r--drivers/pvr/PvrTcDecoder.cpp144
-rw-r--r--drivers/pvr/PvrTcDecoder.h25
-rw-r--r--drivers/pvr/PvrTcEncoder.cpp474
-rw-r--r--drivers/pvr/PvrTcEncoder.h40
-rw-r--r--drivers/pvr/PvrTcPacket.cpp209
-rw-r--r--drivers/pvr/PvrTcPacket.h65
-rw-r--r--drivers/pvr/RgbBitmap.h23
-rw-r--r--drivers/pvr/RgbaBitmap.h23
-rw-r--r--drivers/pvr/SCsub6
-rw-r--r--drivers/pvr/texture_loader_pvr.cpp60
-rw-r--r--drivers/pvr/texture_loader_pvr.h2
-rw-r--r--drivers/register_driver_types.cpp30
-rw-r--r--drivers/rtaudio/RtAudio.cpp4635
-rw-r--r--drivers/rtaudio/RtAudio.h316
-rw-r--r--drivers/rtaudio/audio_driver_rtaudio.cpp2
-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/squish/image_compress_squish.cpp17
-rw-r--r--drivers/theora/SCsub32
-rw-r--r--drivers/theora/codec.h2
-rw-r--r--drivers/theora/decode.c46
-rw-r--r--drivers/theora/encint.h1
-rw-r--r--drivers/theora/video_stream_theora.cpp581
-rw-r--r--drivers/theora/video_stream_theora.h85
-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.cpp23
-rw-r--r--drivers/unix/dir_access_unix.h4
-rw-r--r--drivers/unix/file_access_unix.cpp12
-rw-r--r--drivers/unix/file_access_unix.h11
-rw-r--r--drivers/unix/ip_unix.cpp54
-rw-r--r--drivers/unix/ip_unix.h2
-rw-r--r--drivers/unix/memory_pool_static_malloc.cpp12
-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.cpp135
-rw-r--r--drivers/unix/os_unix.h11
-rw-r--r--drivers/unix/packet_peer_udp_posix.cpp200
-rw-r--r--drivers/unix/packet_peer_udp_posix.h57
-rw-r--r--drivers/unix/semaphore_posix.cpp2
-rw-r--r--drivers/unix/semaphore_posix.h2
-rw-r--r--drivers/unix/stream_peer_tcp_posix.cpp8
-rw-r--r--drivers/unix/stream_peer_tcp_posix.h2
-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.cpp2
-rw-r--r--drivers/unix/thread_posix.h2
-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/vorbis/codebook.c2
-rw-r--r--drivers/vorbis/floor1.c2
-rw-r--r--drivers/vorbis/os.h2
-rw-r--r--drivers/vorbis/psy.c2
-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/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.c243
-rw-r--r--drivers/webp/utils/bit_reader.h229
-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.cpp280
-rw-r--r--drivers/windows/dir_access_windows.h6
-rw-r--r--drivers/windows/file_access_windows.cpp27
-rw-r--r--drivers/windows/file_access_windows.h2
-rw-r--r--drivers/windows/mutex_windows.cpp8
-rw-r--r--drivers/windows/mutex_windows.h2
-rw-r--r--drivers/windows/semaphore_windows.cpp27
-rw-r--r--drivers/windows/semaphore_windows.h2
-rw-r--r--drivers/windows/shell_windows.cpp11
-rw-r--r--drivers/windows/shell_windows.h2
-rw-r--r--drivers/windows/thread_windows.cpp4
-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--godot_logo.svg134
-rw-r--r--logo_small.pngbin0 -> 2025 bytes
-rw-r--r--main/SCsub4
-rw-r--r--main/input_default.cpp343
-rw-r--r--main/input_default.h83
-rw-r--r--main/main.cpp412
-rw-r--r--main/main.h2
-rw-r--r--main/performance.cpp29
-rw-r--r--main/performance.h8
-rw-r--r--main/splash.h28
-rw-r--r--makefile30
-rw-r--r--makerel.bat1
-rwxr-xr-xmethods.py101
-rw-r--r--modules/SCsub4
-rw-r--r--modules/gdscript/SCsub2
-rw-r--r--modules/gdscript/gd_compiler.cpp223
-rw-r--r--modules/gdscript/gd_compiler.h128
-rw-r--r--modules/gdscript/gd_editor.cpp2120
-rw-r--r--modules/gdscript/gd_functions.cpp109
-rw-r--r--modules/gdscript/gd_functions.h7
-rw-r--r--modules/gdscript/gd_parser.cpp781
-rw-r--r--modules/gdscript/gd_parser.h81
-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.cpp659
-rw-r--r--modules/gdscript/gd_script.h113
-rw-r--r--modules/gdscript/gd_tokenizer.cpp122
-rw-r--r--modules/gdscript/gd_tokenizer.h13
-rw-r--r--modules/gdscript/register_types.cpp5
-rw-r--r--modules/gdscript/register_types.h2
-rw-r--r--modules/gridmap/SCsub3
-rw-r--r--modules/gridmap/grid_map.cpp88
-rw-r--r--modules/gridmap/grid_map.h4
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp212
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h30
-rw-r--r--modules/gridmap/register_types.cpp6
-rw-r--r--modules/gridmap/register_types.h2
-rw-r--r--platform/android/AndroidManifest.xml.template8
-rw-r--r--platform/android/SCsub14
-rw-r--r--platform/android/android_native_app_glue.h4
-rw-r--r--platform/android/audio_driver_jandroid.cpp2
-rw-r--r--platform/android/audio_driver_jandroid.h2
-rw-r--r--platform/android/audio_driver_opensl.cpp13
-rw-r--r--platform/android/audio_driver_opensl.h2
-rw-r--r--platform/android/cpu-features.c1089
-rw-r--r--platform/android/cpu-features.h214
-rw-r--r--platform/android/detect.py172
-rw-r--r--platform/android/dir_access_android.cpp5
-rw-r--r--platform/android/dir_access_android.h3
-rw-r--r--platform/android/dir_access_jandroid.cpp72
-rw-r--r--platform/android/dir_access_jandroid.h4
-rw-r--r--platform/android/export/export.cpp263
-rw-r--r--platform/android/file_access_android.cpp13
-rw-r--r--platform/android/file_access_android.h12
-rw-r--r--platform/android/file_access_jandroid.cpp7
-rw-r--r--platform/android/file_access_jandroid.h2
-rw-r--r--platform/android/globals/global_defaults.cpp2
-rw-r--r--platform/android/godot_android.cpp2
-rw-r--r--platform/android/java/res/drawable/icon.pngbin91728 -> 12574 bytes
-rw-r--r--platform/android/java/res/layout/downloading_expansion.xml166
-rw-r--r--platform/android/java/res/values-fa/strings.xml16
-rw-r--r--platform/android/java/res/values/strings.xml12
-rw-r--r--platform/android/java/src/com/android/godot/Godot.java459
-rw-r--r--platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java3
-rw-r--r--platform/android/java/src/com/android/godot/GodotDownloaderService.java13
-rw-r--r--platform/android/java/src/com/android/godot/GodotIO.java116
-rw-r--r--platform/android/java/src/com/android/godot/GodotLib.java6
-rw-r--r--platform/android/java/src/com/android/godot/GodotPaymentV3.java74
-rw-r--r--platform/android/java/src/com/android/godot/GodotView.java42
-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.java14
-rw-r--r--platform/android/java/src/com/android/godot/payments/PaymentsCache.java4
-rw-r--r--platform/android/java/src/com/android/godot/payments/PaymentsManager.java166
-rw-r--r--platform/android/java/src/com/android/godot/payments/PurchaseTask.java28
-rw-r--r--platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java87
-rw-r--r--platform/android/java_class_wrapper.cpp1332
-rw-r--r--platform/android/java_class_wrapper.h168
-rw-r--r--platform/android/java_glue.cpp199
-rw-r--r--platform/android/java_glue.h6
-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/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.pngbin0 -> 1027 bytes
-rw-r--r--platform/android/libs/downloader_library/res/drawable-mdpi/notify_panel_notification_icon_bg.pngbin0 -> 1125 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/.classpath1
-rw-r--r--platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseChecker.java2
-rw-r--r--platform/android/os_android.cpp51
-rw-r--r--platform/android/os_android.h24
-rw-r--r--platform/android/platform_config.h2
-rw-r--r--platform/android/project.properties.template2
-rw-r--r--platform/android/thread_jandroid.cpp2
-rw-r--r--platform/android/thread_jandroid.h2
-rw-r--r--platform/bb10/SCsub11
-rw-r--r--platform/bb10/audio_driver_bb10.cpp3
-rw-r--r--platform/bb10/audio_driver_bb10.h2
-rw-r--r--platform/bb10/bar/bar-descriptor.xml30
-rw-r--r--platform/bb10/detect.py4
-rw-r--r--platform/bb10/export/export.cpp109
-rw-r--r--platform/bb10/os_bb10.cpp5
-rw-r--r--platform/bb10/payment_service.cpp2
-rw-r--r--platform/bb10/payment_service.h2
-rw-r--r--platform/flash/SCsub3
-rw-r--r--platform/flash/detect.py4
-rw-r--r--platform/flash/os_flash.h175
-rw-r--r--platform/flash/rasterizer_flash.h2
-rw-r--r--platform/haiku/SCsub16
-rw-r--r--platform/haiku/audio_driver_media_kit.cpp143
-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.py61
-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.cpp344
-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/SCsub14
-rw-r--r--platform/iphone/app_delegate.h6
-rw-r--r--platform/iphone/app_delegate.mm107
-rw-r--r--platform/iphone/audio_driver_iphone.cpp41
-rw-r--r--platform/iphone/audio_driver_iphone.h6
-rw-r--r--platform/iphone/detect.py99
-rw-r--r--platform/iphone/game_center.h8
-rw-r--r--platform/iphone/game_center.mm240
-rwxr-xr-xplatform/iphone/gl_view.h19
-rwxr-xr-xplatform/iphone/gl_view.mm265
-rwxr-xr-x[-rw-r--r--]platform/iphone/globals/global_defaults.cpp2
-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.h4
-rw-r--r--platform/iphone/in_app_store.mm44
-rw-r--r--platform/iphone/os_iphone.cpp92
-rw-r--r--platform/iphone/os_iphone.h15
-rw-r--r--platform/iphone/platform_config.h5
-rw-r--r--platform/iphone/platform_refcount.h18
-rw-r--r--platform/iphone/rasterizer_iphone.cpp2
-rw-r--r--platform/iphone/rasterizer_iphone.h2
-rw-r--r--platform/iphone/sem_iphone.cpp5
-rw-r--r--platform/iphone/view_controller.h5
-rw-r--r--platform/iphone/view_controller.mm14
-rw-r--r--platform/isim/SCsub11
-rw-r--r--platform/isim/detect.py26
-rw-r--r--platform/javascript/SCsub9
-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.py50
-rw-r--r--platform/javascript/export/export.cpp69
-rw-r--r--platform/javascript/export/export.h2
-rw-r--r--platform/javascript/javascript_main.cpp59
-rw-r--r--platform/javascript/os_javascript.cpp61
-rw-r--r--platform/javascript/os_javascript.h17
-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.cpp46
-rw-r--r--platform/nacl/os_nacl.h6
-rw-r--r--platform/nacl/pepper_main.cpp2
-rw-r--r--platform/nacl/platform_config.h2
-rw-r--r--platform/osx/SCsub2
-rw-r--r--platform/osx/audio_driver_osx.cpp39
-rw-r--r--platform/osx/audio_driver_osx.h6
-rw-r--r--platform/osx/context_gl_osx.cpp2
-rw-r--r--platform/osx/context_gl_osx.h2
-rw-r--r--platform/osx/detect.py60
-rw-r--r--platform/osx/export/export.cpp35
-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.h44
-rw-r--r--platform/osx/os_osx.mm329
-rw-r--r--platform/osx/platform_config.h2
-rw-r--r--platform/server/detect.py42
-rw-r--r--platform/server/godot_server.cpp2
-rw-r--r--platform/server/os_server.cpp12
-rw-r--r--platform/server/os_server.h6
-rw-r--r--platform/server/platform_config.h2
-rw-r--r--platform/windows/SCsub15
-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.cpp318
-rw-r--r--platform/windows/ctxgl_procaddr.h22
-rw-r--r--platform/windows/detect.py610
-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.cpp116
-rw-r--r--platform/windows/key_mapping_win.cpp2
-rw-r--r--platform/windows/key_mapping_win.h48
-rw-r--r--platform/windows/lang_table.h2
-rw-r--r--platform/windows/os_windows.cpp780
-rw-r--r--platform/windows/os_windows.h61
-rw-r--r--platform/windows/packet_peer_udp_winsock.cpp219
-rw-r--r--platform/windows/packet_peer_udp_winsock.h56
-rw-r--r--platform/windows/platform_config.h4
-rw-r--r--platform/windows/stream_peer_winsock.cpp2
-rw-r--r--platform/windows/stream_peer_winsock.h2
-rw-r--r--platform/windows/tcp_server_winsock.cpp291
-rw-r--r--platform/windows/tcp_server_winsock.h56
-rw-r--r--platform/winrt/SCsub11
-rw-r--r--platform/winrt/app.cpp385
-rw-r--r--platform/winrt/app.h61
-rw-r--r--platform/winrt/detect.py156
-rw-r--r--platform/winrt/gl_context_egl.cpp177
-rw-r--r--platform/winrt/gl_context_egl.h45
-rw-r--r--platform/winrt/include/EGL/egl.h298
-rw-r--r--platform/winrt/include/EGL/eglext.h766
-rw-r--r--platform/winrt/include/EGL/eglplatform.h131
-rw-r--r--platform/winrt/include/FunctionDiscoveryKeys_devpkey.h213
-rw-r--r--platform/winrt/include/GLES2/gl2.h620
-rw-r--r--platform/winrt/include/GLES2/gl2ext.h2013
-rw-r--r--platform/winrt/include/GLES2/gl2platform.h30
-rw-r--r--platform/winrt/include/GLES3/gl3.h1061
-rw-r--r--platform/winrt/include/GLES3/gl3ext.h24
-rw-r--r--platform/winrt/include/GLES3/gl3platform.h30
-rw-r--r--platform/winrt/include/GLSLANG/ShaderLang.h411
-rw-r--r--platform/winrt/include/GLSLANG/ShaderVars.h185
-rw-r--r--platform/winrt/include/KHR/khrplatform.h282
-rw-r--r--platform/winrt/include/angle_gl.h23
-rw-r--r--platform/winrt/include/angle_windowsstore.h37
-rw-r--r--platform/winrt/logo.pngbin0 -> 1434 bytes
-rw-r--r--platform/winrt/os_winrt.cpp706
-rw-r--r--platform/winrt/os_winrt.h255
-rw-r--r--platform/winrt/platform_config.h2
-rw-r--r--platform/winrt/thread_winrt.cpp42
-rw-r--r--platform/winrt/thread_winrt.h35
-rw-r--r--platform/x11/SCsub2
-rw-r--r--platform/x11/context_gl_x11.cpp23
-rw-r--r--platform/x11/context_gl_x11.h2
-rw-r--r--platform/x11/detect.py150
-rw-r--r--platform/x11/export/export.cpp2
-rw-r--r--platform/x11/godot_x11.cpp2
-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.cpp852
-rw-r--r--platform/x11/os_x11.h61
-rw-r--r--platform/x11/platform_config.h6
-rw-r--r--scene/2d/SCsub2
-rw-r--r--scene/2d/animated_sprite.cpp31
-rw-r--r--scene/2d/animated_sprite.h2
-rw-r--r--scene/2d/area_2d.cpp465
-rw-r--r--scene/2d/area_2d.h76
-rw-r--r--scene/2d/back_buffer_copy.cpp75
-rw-r--r--scene/2d/back_buffer_copy.h41
-rw-r--r--scene/2d/camera_2d.cpp105
-rw-r--r--scene/2d/camera_2d.h199
-rw-r--r--scene/2d/canvas_item.cpp417
-rw-r--r--scene/2d/canvas_item.h81
-rw-r--r--scene/2d/canvas_modulate.cpp46
-rw-r--r--scene/2d/canvas_modulate.h23
-rw-r--r--scene/2d/collision_object_2d.cpp145
-rw-r--r--scene/2d/collision_object_2d.h14
-rw-r--r--scene/2d/collision_polygon_2d.cpp139
-rw-r--r--scene/2d/collision_polygon_2d.h19
-rw-r--r--scene/2d/collision_shape_2d.cpp172
-rw-r--r--scene/2d/collision_shape_2d.h10
-rw-r--r--scene/2d/joints_2d.cpp75
-rw-r--r--scene/2d/joints_2d.h13
-rw-r--r--scene/2d/light_2d.cpp382
-rw-r--r--scene/2d/light_2d.h112
-rw-r--r--scene/2d/light_occluder_2d.cpp202
-rw-r--r--scene/2d/light_occluder_2d.h73
-rw-r--r--scene/2d/navigation2d.cpp770
-rw-r--r--scene/2d/navigation2d.h151
-rw-r--r--scene/2d/navigation_polygon.cpp450
-rw-r--r--scene/2d/navigation_polygon.h84
-rw-r--r--scene/2d/node_2d.cpp140
-rw-r--r--scene/2d/node_2d.h24
-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.cpp28
-rw-r--r--scene/2d/parallax_background.h6
-rw-r--r--scene/2d/parallax_layer.cpp8
-rw-r--r--scene/2d/parallax_layer.h2
-rw-r--r--scene/2d/particles_2d.cpp286
-rw-r--r--scene/2d/particles_2d.h34
-rw-r--r--scene/2d/path_2d.cpp12
-rw-r--r--scene/2d/path_2d.h2
-rw-r--r--scene/2d/physics_body_2d.cpp451
-rw-r--r--scene/2d/physics_body_2d.h87
-rw-r--r--scene/2d/polygon_2d.cpp24
-rw-r--r--scene/2d/polygon_2d.h3
-rw-r--r--scene/2d/position_2d.cpp8
-rw-r--r--scene/2d/position_2d.h2
-rw-r--r--scene/2d/ray_cast_2d.cpp39
-rw-r--r--scene/2d/ray_cast_2d.h6
-rw-r--r--scene/2d/remote_transform_2d.cpp10
-rw-r--r--scene/2d/remote_transform_2d.h4
-rw-r--r--scene/2d/sample_player_2d.cpp7
-rw-r--r--scene/2d/sample_player_2d.h2
-rw-r--r--scene/2d/screen_button.cpp33
-rw-r--r--scene/2d/screen_button.h2
-rw-r--r--scene/2d/sound_player_2d.cpp6
-rw-r--r--scene/2d/sound_player_2d.h2
-rw-r--r--scene/2d/sprite.cpp80
-rw-r--r--scene/2d/sprite.h2
-rw-r--r--scene/2d/tile_map.cpp678
-rw-r--r--scene/2d/tile_map.h122
-rw-r--r--scene/2d/visibility_notifier_2d.cpp75
-rw-r--r--scene/2d/visibility_notifier_2d.h5
-rw-r--r--scene/2d/y_sort.cpp29
-rw-r--r--scene/2d/y_sort.h17
-rw-r--r--scene/3d/SCsub5
-rw-r--r--scene/3d/area.cpp385
-rw-r--r--scene/3d/area.h64
-rw-r--r--scene/3d/baked_light_instance.cpp78
-rw-r--r--scene/3d/baked_light_instance.h42
-rw-r--r--scene/3d/body_shape.cpp136
-rw-r--r--scene/3d/body_shape.h26
-rw-r--r--scene/3d/bone_attachment.cpp10
-rw-r--r--scene/3d/bone_attachment.h2
-rw-r--r--scene/3d/camera.cpp208
-rw-r--r--scene/3d/camera.h28
-rw-r--r--scene/3d/car_body.cpp741
-rw-r--r--scene/3d/car_body.h170
-rw-r--r--scene/3d/character_camera.cpp2
-rw-r--r--scene/3d/character_camera.h2
-rw-r--r--scene/3d/collision_object.cpp118
-rw-r--r--scene/3d/collision_object.h18
-rw-r--r--scene/3d/collision_polygon.cpp270
-rw-r--r--scene/3d/collision_polygon.h62
-rw-r--r--scene/3d/editable_shape.cpp85
-rw-r--r--scene/3d/editable_shape.h73
-rw-r--r--scene/3d/follow_camera.cpp778
-rw-r--r--scene/3d/follow_camera.h180
-rw-r--r--scene/3d/immediate_geometry.cpp52
-rw-r--r--scene/3d/immediate_geometry.h5
-rw-r--r--scene/3d/interpolated_camera.cpp12
-rw-r--r--scene/3d/interpolated_camera.h72
-rw-r--r--scene/3d/light.cpp67
-rw-r--r--scene/3d/light.h15
-rw-r--r--scene/3d/mesh_instance.cpp27
-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.cpp725
-rw-r--r--scene/3d/navigation.h159
-rw-r--r--scene/3d/navigation_agent.cpp5
-rw-r--r--scene/3d/navigation_agent.h10
-rw-r--r--scene/3d/navigation_mesh.cpp359
-rw-r--r--scene/3d/navigation_mesh.h85
-rw-r--r--scene/3d/optimized_spatial_scene.cpp2
-rw-r--r--scene/3d/optimized_spatial_scene.h2
-rw-r--r--scene/3d/particles.cpp2
-rw-r--r--scene/3d/particles.h2
-rw-r--r--scene/3d/path.cpp722
-rw-r--r--scene/3d/path.h190
-rw-r--r--scene/3d/physics_body.cpp742
-rw-r--r--scene/3d/physics_body.h137
-rw-r--r--scene/3d/physics_joint.cpp1060
-rw-r--r--scene/3d/physics_joint.h318
-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.cpp6
-rw-r--r--scene/3d/proximity_group.h2
-rw-r--r--scene/3d/quad.cpp8
-rw-r--r--scene/3d/quad.h2
-rw-r--r--scene/3d/ray_cast.cpp70
-rw-r--r--scene/3d/ray_cast.h11
-rw-r--r--scene/3d/room_instance.cpp4
-rw-r--r--scene/3d/room_instance.h2
-rw-r--r--scene/3d/scenario_fx.cpp25
-rw-r--r--scene/3d/scenario_fx.h2
-rw-r--r--scene/3d/skeleton.cpp141
-rw-r--r--scene/3d/skeleton.h13
-rw-r--r--scene/3d/spatial.cpp278
-rw-r--r--scene/3d/spatial.h40
-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.cpp3
-rw-r--r--scene/3d/spatial_sample_player.h2
-rw-r--r--scene/3d/spatial_stream_player.cpp295
-rw-r--r--scene/3d/spatial_stream_player.h58
-rw-r--r--scene/3d/sprite_3d.cpp60
-rw-r--r--scene/3d/test_cube.cpp2
-rw-r--r--scene/3d/test_cube.h2
-rw-r--r--scene/3d/vehicle_body.cpp1045
-rw-r--r--scene/3d/vehicle_body.h185
-rw-r--r--scene/3d/visibility_notifier.cpp20
-rw-r--r--scene/3d/visibility_notifier.h2
-rw-r--r--scene/3d/visual_instance.cpp76
-rw-r--r--scene/3d/visual_instance.h12
-rw-r--r--scene/SCsub4
-rw-r--r--scene/animation/SCsub2
-rw-r--r--scene/animation/animation_cache.cpp12
-rw-r--r--scene/animation/animation_cache.h4
-rw-r--r--scene/animation/animation_player.cpp173
-rw-r--r--scene/animation/animation_player.h12
-rw-r--r--scene/animation/animation_tree_player.cpp116
-rw-r--r--scene/animation/animation_tree_player.h21
-rw-r--r--scene/animation/transitioner.cpp2
-rw-r--r--scene/animation/transitioner.h2
-rw-r--r--scene/animation/tween.cpp1554
-rw-r--r--scene/animation/tween.h269
-rw-r--r--scene/animation/tween_interpolaters.cpp407
-rw-r--r--scene/audio/SCsub2
-rw-r--r--scene/audio/event_player.cpp21
-rw-r--r--scene/audio/event_player.h2
-rw-r--r--scene/audio/sample_player.cpp43
-rw-r--r--scene/audio/sample_player.h10
-rw-r--r--scene/audio/sound_room_params.cpp12
-rw-r--r--scene/audio/sound_room_params.h2
-rw-r--r--scene/audio/stream_player.cpp192
-rw-r--r--scene/audio/stream_player.h35
-rw-r--r--scene/gui/SCsub2
-rw-r--r--scene/gui/base_button.cpp88
-rw-r--r--scene/gui/base_button.h22
-rw-r--r--scene/gui/box_container.cpp42
-rw-r--r--scene/gui/box_container.h19
-rw-r--r--scene/gui/button.cpp23
-rw-r--r--scene/gui/button.h2
-rw-r--r--scene/gui/button_array.cpp10
-rw-r--r--scene/gui/button_array.h192
-rw-r--r--scene/gui/button_group.cpp9
-rw-r--r--scene/gui/button_group.h8
-rw-r--r--scene/gui/center_container.cpp34
-rw-r--r--scene/gui/center_container.h7
-rw-r--r--scene/gui/check_box.cpp79
-rw-r--r--scene/gui/check_box.h55
-rw-r--r--scene/gui/check_button.cpp2
-rw-r--r--scene/gui/check_button.h2
-rw-r--r--scene/gui/color_picker.cpp48
-rw-r--r--scene/gui/color_picker.h2
-rw-r--r--scene/gui/color_ramp_edit.cpp422
-rw-r--r--scene/gui/color_ramp_edit.h52
-rw-r--r--scene/gui/container.cpp16
-rw-r--r--scene/gui/container.h3
-rw-r--r--scene/gui/control.cpp357
-rw-r--r--scene/gui/control.h6
-rw-r--r--scene/gui/custom_button.cpp2
-rw-r--r--scene/gui/custom_button.h2
-rw-r--r--scene/gui/dialogs.cpp16
-rw-r--r--scene/gui/dialogs.h2
-rw-r--r--scene/gui/empty_control.cpp59
-rw-r--r--scene/gui/empty_control.h48
-rw-r--r--scene/gui/file_dialog.cpp73
-rw-r--r--scene/gui/file_dialog.h14
-rw-r--r--scene/gui/graph_edit.cpp773
-rw-r--r--scene/gui/graph_edit.h109
-rw-r--r--scene/gui/graph_node.cpp589
-rw-r--r--scene/gui/graph_node.h106
-rw-r--r--scene/gui/grid_container.cpp49
-rw-r--r--scene/gui/grid_container.h2
-rw-r--r--scene/gui/item_list.cpp1148
-rw-r--r--scene/gui/item_list.h144
-rw-r--r--scene/gui/label.cpp378
-rw-r--r--scene/gui/label.h45
-rw-r--r--scene/gui/line_edit.cpp172
-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.cpp7
-rw-r--r--scene/gui/menu_button.h2
-rw-r--r--scene/gui/option_button.cpp4
-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.cpp63
-rw-r--r--scene/gui/popup.h3
-rw-r--r--scene/gui/popup_menu.cpp55
-rw-r--r--scene/gui/popup_menu.h8
-rw-r--r--scene/gui/progress_bar.cpp2
-rw-r--r--scene/gui/progress_bar.h2
-rw-r--r--scene/gui/range.cpp8
-rw-r--r--scene/gui/range.h2
-rw-r--r--scene/gui/reference_frame.cpp6
-rw-r--r--scene/gui/reference_frame.h2
-rw-r--r--scene/gui/rich_text_label.cpp297
-rw-r--r--scene/gui/rich_text_label.h25
-rw-r--r--scene/gui/scroll_bar.cpp34
-rw-r--r--scene/gui/scroll_bar.h2
-rw-r--r--scene/gui/scroll_container.cpp14
-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.cpp7
-rw-r--r--scene/gui/slider.h2
-rw-r--r--scene/gui/spin_box.cpp89
-rw-r--r--scene/gui/spin_box.h18
-rw-r--r--scene/gui/split_container.cpp9
-rw-r--r--scene/gui/split_container.h2
-rw-r--r--scene/gui/tab_container.cpp236
-rw-r--r--scene/gui/tab_container.h15
-rw-r--r--scene/gui/tabs.cpp409
-rw-r--r--scene/gui/tabs.h45
-rw-r--r--scene/gui/text_edit.cpp2666
-rw-r--r--scene/gui/text_edit.h41
-rw-r--r--scene/gui/texture_button.cpp97
-rw-r--r--scene/gui/texture_button.h9
-rw-r--r--scene/gui/texture_frame.cpp12
-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.cpp591
-rw-r--r--scene/gui/tree.h30
-rw-r--r--scene/gui/video_player.cpp236
-rw-r--r--scene/gui/video_player.h38
-rw-r--r--scene/io/SCsub2
-rw-r--r--scene/io/resource_format_image.cpp67
-rw-r--r--scene/io/resource_format_image.h4
-rw-r--r--scene/io/resource_format_wav.cpp27
-rw-r--r--scene/io/resource_format_wav.h4
-rw-r--r--scene/io/scene_format_object.cpp851
-rw-r--r--scene/io/scene_format_object.h128
-rw-r--r--scene/io/scene_format_script.cpp65
-rw-r--r--scene/io/scene_format_script.h45
-rw-r--r--scene/io/scene_loader.cpp161
-rw-r--r--scene/io/scene_loader.h90
-rw-r--r--scene/io/scene_saver.cpp94
-rw-r--r--scene/io/scene_saver.h80
-rw-r--r--scene/main/SCsub2
-rw-r--r--scene/main/canvas_layer.cpp8
-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.cpp495
-rw-r--r--scene/main/node.h78
-rw-r--r--scene/main/resource_preloader.cpp2
-rw-r--r--scene/main/resource_preloader.h2
-rw-r--r--scene/main/scene_main_loop.cpp826
-rw-r--r--scene/main/scene_main_loop.h135
-rw-r--r--scene/main/scene_singleton.cpp2
-rw-r--r--scene/main/scene_singleton.h2
-rw-r--r--scene/main/timer.cpp81
-rw-r--r--scene/main/timer.h16
-rw-r--r--scene/main/viewport.cpp517
-rw-r--r--scene/main/viewport.h39
-rw-r--r--scene/register_scene_types.cpp169
-rw-r--r--scene/register_scene_types.h2
-rw-r--r--scene/resources/SCsub2
-rw-r--r--scene/resources/animation.cpp311
-rw-r--r--scene/resources/animation.h7
-rw-r--r--scene/resources/audio_stream.cpp72
-rw-r--r--scene/resources/audio_stream.h71
-rw-r--r--scene/resources/audio_stream_resampled.cpp91
-rw-r--r--scene/resources/audio_stream_resampled.h9
-rw-r--r--scene/resources/baked_light.cpp272
-rw-r--r--scene/resources/baked_light.h55
-rw-r--r--scene/resources/bit_mask.cpp9
-rw-r--r--scene/resources/bit_mask.h4
-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.cpp117
-rw-r--r--scene/resources/color_ramp.h98
-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.cpp30
-rw-r--r--scene/resources/convex_polygon_shape_2d.h5
-rw-r--r--scene/resources/curve.cpp28
-rw-r--r--scene/resources/curve.h2
-rw-r--r--scene/resources/default_theme/SCsub2
-rw-r--r--scene/resources/default_theme/arrow_down.pngbin260 -> 239 bytes
-rw-r--r--scene/resources/default_theme/arrow_right.pngbin275 -> 238 bytes
-rw-r--r--scene/resources/default_theme/button_disabled.pngbin388 -> 3048 bytes
-rw-r--r--scene/resources/default_theme/button_focus.pngbin0 -> 2931 bytes
-rw-r--r--scene/resources/default_theme/button_hover.pngbin531 -> 3072 bytes
-rw-r--r--scene/resources/default_theme/button_normal.pngbin527 -> 3070 bytes
-rw-r--r--scene/resources/default_theme/button_pressed.pngbin491 -> 3078 bytes
-rw-r--r--scene/resources/default_theme/checked.pngbin616 -> 601 bytes
-rw-r--r--scene/resources/default_theme/checker_bg.pngbin0 -> 180 bytes
-rw-r--r--scene/resources/default_theme/close_hl.pngbin562 -> 412 bytes
-rw-r--r--scene/resources/default_theme/default_theme.cpp697
-rw-r--r--scene/resources/default_theme/dropdown.pngbin257 -> 254 bytes
-rw-r--r--scene/resources/default_theme/focus.pngbin473 -> 2905 bytes
-rw-r--r--scene/resources/default_theme/frame_focus.pngbin0 -> 301 bytes
-rw-r--r--scene/resources/default_theme/full_panel_bg.pngbin1240 -> 366 bytes
-rw-r--r--scene/resources/default_theme/graph_node.pngbin0 -> 770 bytes
-rw-r--r--scene/resources/default_theme/graph_node_close.pngbin0 -> 243 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/graph_port.pngbin0 -> 509 bytes
-rw-r--r--scene/resources/default_theme/hscroll_bg.pngbin235 -> 0 bytes
-rw-r--r--scene/resources/default_theme/hscroll_bg_focus.pngbin235 -> 0 bytes
-rw-r--r--scene/resources/default_theme/hscroll_grabber.pngbin299 -> 0 bytes
-rw-r--r--scene/resources/default_theme/hscroll_grabber_hl.pngbin301 -> 0 bytes
-rw-r--r--scene/resources/default_theme/hslider_bg.pngbin361 -> 479 bytes
-rw-r--r--scene/resources/default_theme/hslider_grabber.pngbin624 -> 582 bytes
-rw-r--r--scene/resources/default_theme/hslider_grabber_hl.pngbin625 -> 611 bytes
-rw-r--r--scene/resources/default_theme/hslider_tick.pngbin227 -> 216 bytes
-rw-r--r--scene/resources/default_theme/hsplit_bg.pngbin290 -> 173 bytes
-rw-r--r--scene/resources/default_theme/hsplitter.pngbin225 -> 212 bytes
-rw-r--r--scene/resources/default_theme/icon_folder.pngbin471 -> 462 bytes
-rw-r--r--scene/resources/default_theme/icon_play.pngbin294 -> 295 bytes
-rw-r--r--scene/resources/default_theme/icon_stop.pngbin167 -> 172 bytes
-rw-r--r--scene/resources/default_theme/line_edit.pngbin344 -> 309 bytes
-rw-r--r--scene/resources/default_theme/line_edit_disabled.pngbin344 -> 294 bytes
-rw-r--r--scene/resources/default_theme/option_arrow.pngbin351 -> 249 bytes
-rw-r--r--scene/resources/default_theme/option_button_disabled.pngbin673 -> 3198 bytes
-rw-r--r--scene/resources/default_theme/option_button_hover.pngbin667 -> 3209 bytes
-rw-r--r--scene/resources/default_theme/option_button_normal.pngbin659 -> 3223 bytes
-rw-r--r--scene/resources/default_theme/option_button_pressed.pngbin672 -> 3231 bytes
-rw-r--r--scene/resources/default_theme/panel_bg.pngbin174 -> 174 bytes
-rw-r--r--scene/resources/default_theme/popup_bg.pngbin642 -> 3078 bytes
-rw-r--r--scene/resources/default_theme/popup_checked.pngbin184 -> 182 bytes
-rw-r--r--scene/resources/default_theme/popup_window.pngbin820 -> 1050 bytes
-rw-r--r--scene/resources/default_theme/progress_bar.pngbin586 -> 338 bytes
-rw-r--r--scene/resources/default_theme/progress_fill.pngbin818 -> 282 bytes
-rw-r--r--scene/resources/default_theme/radio_checked.pngbin0 -> 569 bytes
-rw-r--r--scene/resources/default_theme/radio_unchecked.pngbin0 -> 421 bytes
-rw-r--r--scene/resources/default_theme/scroll_bg.pngbin0 -> 468 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_down.pngbin562 -> 315 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_down_hl.pngbin553 -> 308 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_left.pngbin735 -> 339 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_left_hl.pngbin754 -> 347 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_right.pngbin731 -> 339 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_right_hl.pngbin752 -> 338 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_up.pngbin555 -> 306 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_up_hl.pngbin555 -> 306 bytes
-rw-r--r--scene/resources/default_theme/scroll_grabber.pngbin0 -> 364 bytes
-rw-r--r--scene/resources/default_theme/scroll_grabber_hl.pngbin0 -> 411 bytes
-rw-r--r--scene/resources/default_theme/selection.pngbin526 -> 319 bytes
-rw-r--r--scene/resources/default_theme/selection_oof.pngbin514 -> 321 bytes
-rw-r--r--scene/resources/default_theme/submenu.pngbin186 -> 173 bytes
-rw-r--r--scene/resources/default_theme/tab_behind.pngbin456 -> 394 bytes
-rw-r--r--scene/resources/default_theme/tab_container_bg.pngbin651 -> 3070 bytes
-rw-r--r--scene/resources/default_theme/tab_current.pngbin482 -> 3055 bytes
-rw-r--r--scene/resources/default_theme/tab_menu.pngbin0 -> 222 bytes
-rw-r--r--scene/resources/default_theme/tab_menu_hl.pngbin0 -> 226 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h218
-rw-r--r--scene/resources/default_theme/toggle_off.pngbin1900 -> 1613 bytes
-rw-r--r--scene/resources/default_theme/toggle_on.pngbin1902 -> 1618 bytes
-rw-r--r--scene/resources/default_theme/tooltip_bg.pngbin1114 -> 325 bytes
-rw-r--r--scene/resources/default_theme/tree_bg.pngbin344 -> 309 bytes
-rw-r--r--scene/resources/default_theme/tree_title.pngbin527 -> 181 bytes
-rw-r--r--scene/resources/default_theme/tree_title_pressed.pngbin513 -> 181 bytes
-rw-r--r--scene/resources/default_theme/unchecked.pngbin444 -> 385 bytes
-rw-r--r--scene/resources/default_theme/updown.pngbin372 -> 366 bytes
-rw-r--r--scene/resources/default_theme/vscroll_bg.pngbin233 -> 0 bytes
-rw-r--r--scene/resources/default_theme/vscroll_bg_focus.pngbin233 -> 0 bytes
-rw-r--r--scene/resources/default_theme/vscroll_grabber.pngbin308 -> 0 bytes
-rw-r--r--scene/resources/default_theme/vscroll_grabber_hl.pngbin314 -> 0 bytes
-rw-r--r--scene/resources/default_theme/vslider_bg.pngbin338 -> 543 bytes
-rw-r--r--scene/resources/default_theme/vslider_grabber.pngbin575 -> 533 bytes
-rw-r--r--scene/resources/default_theme/vslider_grabber_hl.pngbin580 -> 555 bytes
-rw-r--r--scene/resources/default_theme/vslider_tick.pngbin198 -> 185 bytes
-rw-r--r--scene/resources/default_theme/vsplit_bg.pngbin288 -> 173 bytes
-rw-r--r--scene/resources/default_theme/vsplitter.pngbin219 -> 208 bytes
-rw-r--r--scene/resources/environment.cpp11
-rw-r--r--scene/resources/environment.h8
-rw-r--r--scene/resources/event_stream.cpp4
-rw-r--r--scene/resources/event_stream.h2
-rw-r--r--scene/resources/font.cpp67
-rw-r--r--scene/resources/font.h18
-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/image_path_finder.cpp427
-rw-r--r--scene/resources/image_path_finder.h84
-rw-r--r--scene/resources/material.cpp187
-rw-r--r--scene/resources/material.h72
-rw-r--r--scene/resources/mesh.cpp258
-rw-r--r--scene/resources/mesh.h5
-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/mikktspace.c1890
-rw-r--r--scene/resources/mikktspace.h145
-rw-r--r--scene/resources/multimesh.cpp2
-rw-r--r--scene/resources/multimesh.h2
-rw-r--r--scene/resources/packed_scene.cpp1254
-rw-r--r--scene/resources/packed_scene.h250
-rw-r--r--scene/resources/plane_shape.cpp31
-rw-r--r--scene/resources/plane_shape.h4
-rw-r--r--scene/resources/polygon_path_finder.cpp30
-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.cpp2
-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.cpp1812
-rw-r--r--scene/resources/scene_format_text.h140
-rw-r--r--scene/resources/scene_preloader.cpp855
-rw-r--r--scene/resources/scene_preloader.h148
-rw-r--r--scene/resources/segment_shape_2d.cpp51
-rw-r--r--scene/resources/segment_shape_2d.h7
-rw-r--r--scene/resources/shader.cpp78
-rw-r--r--scene/resources/shader.h63
-rw-r--r--scene/resources/shader_graph.cpp3141
-rw-r--r--scene/resources/shader_graph.h488
-rw-r--r--scene/resources/shape.cpp61
-rw-r--r--scene/resources/shape.h12
-rw-r--r--scene/resources/shape_2d.cpp4
-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.cpp8
-rw-r--r--scene/resources/style_box.h2
-rw-r--r--scene/resources/surface_tool.cpp208
-rw-r--r--scene/resources/surface_tool.h12
-rw-r--r--scene/resources/texture.cpp144
-rw-r--r--scene/resources/texture.h38
-rw-r--r--scene/resources/theme.cpp41
-rw-r--r--scene/resources/theme.h4
-rw-r--r--scene/resources/tile_set.cpp108
-rw-r--r--scene/resources/tile_set.h24
-rw-r--r--scene/resources/video_stream.cpp9
-rw-r--r--scene/resources/video_stream.h56
-rw-r--r--scene/resources/volume.cpp2
-rw-r--r--scene/resources/volume.h2
-rw-r--r--scene/resources/world.cpp8
-rw-r--r--scene/resources/world.h4
-rw-r--r--scene/resources/world_2d.cpp15
-rw-r--r--scene/resources/world_2d.h6
-rw-r--r--scene/scene_binds.cpp55
-rw-r--r--scene/scene_binds.h62
-rw-r--r--scene/scene_string_names.cpp39
-rw-r--r--scene/scene_string_names.h44
-rw-r--r--servers/SCsub4
-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.cpp147
-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.cpp21
-rw-r--r--servers/audio/audio_server_sw.h11
-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.cpp45
-rw-r--r--servers/audio/sample_manager_sw.h204
-rw-r--r--servers/audio/voice_rb_sw.cpp14
-rw-r--r--servers/audio/voice_rb_sw.h2
-rw-r--r--servers/audio_server.cpp5
-rw-r--r--servers/audio_server.h5
-rw-r--r--servers/physics/SCsub2
-rw-r--r--servers/physics/area_pair_sw.cpp74
-rw-r--r--servers/physics/area_pair_sw.h20
-rw-r--r--servers/physics/area_sw.cpp97
-rw-r--r--servers/physics/area_sw.h55
-rw-r--r--servers/physics/body_pair_sw.cpp106
-rw-r--r--servers/physics/body_pair_sw.h4
-rw-r--r--servers/physics/body_sw.cpp214
-rw-r--r--servers/physics/body_sw.h65
-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.cpp4
-rw-r--r--servers/physics/collision_object_sw.h35
-rw-r--r--servers/physics/collision_solver_sat.cpp487
-rw-r--r--servers/physics/collision_solver_sat.h4
-rw-r--r--servers/physics/collision_solver_sw.cpp178
-rw-r--r--servers/physics/collision_solver_sw.h9
-rw-r--r--servers/physics/constraint_sw.cpp2
-rw-r--r--servers/physics/constraint_sw.h8
-rw-r--r--servers/physics/gjk_epa.cpp61
-rw-r--r--servers/physics/gjk_epa.h40
-rw-r--r--servers/physics/joints/SCsub5
-rw-r--r--servers/physics/joints/cone_twist_joint_sw.cpp340
-rw-r--r--servers/physics/joints/cone_twist_joint_sw.h125
-rw-r--r--servers/physics/joints/generic_6dof_joint_sw.cpp691
-rw-r--r--servers/physics/joints/generic_6dof_joint_sw.h428
-rw-r--r--servers/physics/joints/hinge_joint_sw.cpp438
-rw-r--r--servers/physics/joints/hinge_joint_sw.h89
-rw-r--r--servers/physics/joints/jacobian_entry_sw.cpp2
-rw-r--r--servers/physics/joints/jacobian_entry_sw.h146
-rw-r--r--servers/physics/joints/pin_joint_sw.cpp127
-rw-r--r--servers/physics/joints/pin_joint_sw.h67
-rw-r--r--servers/physics/joints/slider_joint_sw.cpp439
-rw-r--r--servers/physics/joints/slider_joint_sw.h218
-rw-r--r--servers/physics/joints_sw.cpp2
-rw-r--r--servers/physics/joints_sw.h20
-rw-r--r--servers/physics/physics_server_sw.cpp526
-rw-r--r--servers/physics/physics_server_sw.h80
-rw-r--r--servers/physics/shape_sw.cpp3293
-rw-r--r--servers/physics/shape_sw.h847
-rw-r--r--servers/physics/space_sw.cpp1178
-rw-r--r--servers/physics/space_sw.h344
-rw-r--r--servers/physics/step_sw.cpp58
-rw-r--r--servers/physics/step_sw.h2
-rw-r--r--servers/physics_2d/SCsub1
-rw-r--r--servers/physics_2d/area_2d_sw.cpp95
-rw-r--r--servers/physics_2d/area_2d_sw.h52
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp75
-rw-r--r--servers/physics_2d/area_pair_2d_sw.h20
-rw-r--r--servers/physics_2d/body_2d_sw.cpp137
-rw-r--r--servers/physics_2d/body_2d_sw.h57
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp82
-rw-r--r--servers/physics_2d/body_pair_2d_sw.h3
-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.cpp9
-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.cpp13
-rw-r--r--servers/physics_2d/collision_object_2d_sw.h32
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.cpp7
-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.cpp233
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h51
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.cpp169
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h316
-rw-r--r--servers/physics_2d/shape_2d_sw.cpp99
-rw-r--r--servers/physics_2d/shape_2d_sw.h47
-rw-r--r--servers/physics_2d/space_2d_sw.cpp700
-rw-r--r--servers/physics_2d/space_2d_sw.h33
-rw-r--r--servers/physics_2d/step_2d_sw.cpp6
-rw-r--r--servers/physics_2d/step_2d_sw.h2
-rw-r--r--servers/physics_2d_server.cpp382
-rw-r--r--servers/physics_2d_server.h172
-rw-r--r--servers/physics_server.cpp399
-rw-r--r--servers/physics_server.h293
-rw-r--r--servers/register_server_types.cpp25
-rw-r--r--servers/register_server_types.h2
-rw-r--r--servers/server_wrap_mt_common.h700
-rw-r--r--servers/spatial_sound/SCsub2
-rw-r--r--servers/spatial_sound/spatial_sound_server_sw.cpp13
-rw-r--r--servers/spatial_sound_2d/SCsub2
-rw-r--r--servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp4
-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.cpp29
-rw-r--r--servers/visual/rasterizer.h435
-rw-r--r--servers/visual/rasterizer_dummy.cpp81
-rw-r--r--servers/visual/rasterizer_dummy.h44
-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.h5
-rw-r--r--servers/visual/shader_language.cpp430
-rw-r--r--servers/visual/shader_language.h135
-rw-r--r--servers/visual/visual_server_raster.cpp2116
-rw-r--r--servers/visual/visual_server_raster.h348
-rw-r--r--servers/visual/visual_server_wrap_mt.cpp18
-rw-r--r--servers/visual/visual_server_wrap_mt.h672
-rw-r--r--servers/visual_server.cpp45
-rw-r--r--servers/visual_server.h163
-rwxr-xr-xtools/Godot.app/Contents/Info.plist4
-rw-r--r--tools/Godot.app/Contents/Resources/Godot.icnsbin294521 -> 260598 bytes
-rw-r--r--tools/SCsub21
-rw-r--r--tools/addheader/addheader.py2
-rw-r--r--tools/collada/SCsub2
-rw-r--r--tools/collada/collada.cpp145
-rw-r--r--tools/collada/collada.h48
-rw-r--r--tools/doc/SCsub2
-rw-r--r--tools/doc/doc_data.cpp31
-rw-r--r--tools/doc/doc_data.h2
-rw-r--r--tools/docdump/SCsub2
-rw-r--r--tools/docdump/class_list.xml4
-rw-r--r--tools/docdump/doc_dump.cpp8
-rw-r--r--tools/docdump/doc_dump.h2
-rw-r--r--tools/docdump/locales/es/LC_MESSAGES/makedocs.mobin0 -> 2321 bytes
-rw-r--r--tools/docdump/locales/es/LC_MESSAGES/makedocs.po142
-rw-r--r--tools/docdump/makedocs.pot108
-rw-r--r--tools/docdump/makedocs.py382
-rw-r--r--tools/docdump/makehtml.py19
-rw-r--r--tools/docdump/makemd.py2
-rw-r--r--tools/editor/SCsub11
-rw-r--r--tools/editor/animation_editor.cpp900
-rw-r--r--tools/editor/animation_editor.h63
-rw-r--r--tools/editor/array_property_edit.cpp231
-rw-r--r--tools/editor/array_property_edit.h36
-rw-r--r--tools/editor/call_dialog.cpp6
-rw-r--r--tools/editor/call_dialog.h2
-rw-r--r--tools/editor/code_editor.cpp55
-rw-r--r--tools/editor/code_editor.h6
-rw-r--r--tools/editor/connections_dialog.cpp186
-rw-r--r--tools/editor/connections_dialog.h4
-rw-r--r--tools/editor/console.cpp6
-rw-r--r--tools/editor/console.h2
-rw-r--r--tools/editor/create_dialog.cpp15
-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.h10
-rw-r--r--tools/editor/doc_font.h10
-rw-r--r--tools/editor/doc_title_font.h10
-rw-r--r--tools/editor/editor_data.cpp257
-rw-r--r--tools/editor/editor_data.h61
-rw-r--r--tools/editor/editor_dir_dialog.cpp35
-rw-r--r--tools/editor/editor_dir_dialog.h2
-rw-r--r--tools/editor/editor_file_dialog.cpp1378
-rw-r--r--tools/editor/editor_file_dialog.h246
-rw-r--r--tools/editor/editor_file_system.cpp98
-rw-r--r--tools/editor/editor_file_system.h14
-rw-r--r--tools/editor/editor_fonts.cpp96
-rw-r--r--tools/editor/editor_fonts.h18
-rw-r--r--tools/editor/editor_help.cpp619
-rw-r--r--tools/editor/editor_help.h96
-rw-r--r--tools/editor/editor_icons.h2
-rw-r--r--tools/editor/editor_import_export.cpp387
-rw-r--r--tools/editor/editor_import_export.h62
-rw-r--r--tools/editor/editor_layout_dialog.cpp59
-rw-r--r--tools/editor/editor_layout_dialog.h53
-rw-r--r--tools/editor/editor_log.cpp46
-rw-r--r--tools/editor/editor_log.h14
-rw-r--r--tools/editor/editor_node.cpp2718
-rw-r--r--tools/editor/editor_node.h214
-rw-r--r--tools/editor/editor_path.cpp16
-rw-r--r--tools/editor/editor_path.h2
-rw-r--r--tools/editor/editor_plugin.cpp16
-rw-r--r--tools/editor/editor_plugin.h10
-rw-r--r--tools/editor/editor_reimport_dialog.cpp8
-rw-r--r--tools/editor/editor_reimport_dialog.h2
-rw-r--r--tools/editor/editor_resource_preview.cpp261
-rw-r--r--tools/editor/editor_resource_preview.h95
-rw-r--r--tools/editor/editor_run.cpp99
-rw-r--r--tools/editor/editor_run.h12
-rw-r--r--tools/editor/editor_run_native.cpp55
-rw-r--r--tools/editor/editor_run_native.h15
-rw-r--r--tools/editor/editor_run_script.cpp2
-rw-r--r--tools/editor/editor_selection.cpp2
-rw-r--r--tools/editor/editor_selection.h2
-rw-r--r--tools/editor/editor_settings.cpp168
-rw-r--r--tools/editor/editor_settings.h18
-rw-r--r--tools/editor/editor_shape_gizmos.cpp468
-rw-r--r--tools/editor/editor_shape_gizmos.h60
-rw-r--r--tools/editor/editor_sub_scene.cpp6
-rw-r--r--tools/editor/editor_sub_scene.h6
-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.cpp22
-rw-r--r--tools/editor/groups_editor.cpp164
-rw-r--r--tools/editor/groups_editor.h38
-rw-r--r--tools/editor/icons/SCsub19
-rw-r--r--tools/editor/icons/icon_add.pngbin393 -> 351 bytes
-rw-r--r--tools/editor/icons/icon_anchor.pngbin0 -> 428 bytes
-rw-r--r--tools/editor/icons/icon_animation.pngbin651 -> 595 bytes
-rw-r--r--tools/editor/icons/icon_arrow_left.pngbin0 -> 243 bytes
-rw-r--r--tools/editor/icons/icon_arrow_left_disabled.pngbin0 -> 244 bytes
-rw-r--r--tools/editor/icons/icon_arrow_right.pngbin0 -> 263 bytes
-rw-r--r--tools/editor/icons/icon_arrow_right_disabled.pngbin0 -> 252 bytes
-rw-r--r--tools/editor/icons/icon_arrow_up.pngbin0 -> 259 bytes
-rw-r--r--tools/editor/icons/icon_arrow_up_disabled.pngbin0 -> 275 bytes
-rw-r--r--tools/editor/icons/icon_atlas_texture.pngbin458 -> 402 bytes
-rw-r--r--tools/editor/icons/icon_audio_stream_gibberish.pngbin456 -> 406 bytes
-rw-r--r--tools/editor/icons/icon_audio_stream_opus.pngbin0 -> 559 bytes
-rw-r--r--tools/editor/icons/icon_auto_play.pngbin217 -> 181 bytes
-rw-r--r--tools/editor/icons/icon_back.pngbin206 -> 180 bytes
-rw-r--r--tools/editor/icons/icon_back_buffer_copy.pngbin0 -> 204 bytes
-rw-r--r--tools/editor/icons/icon_back_disabled.pngbin0 -> 175 bytes
-rw-r--r--tools/editor/icons/icon_bake.pngbin419 -> 374 bytes
-rw-r--r--tools/editor/icons/icon_baked_light.pngbin0 -> 419 bytes
-rw-r--r--tools/editor/icons/icon_baked_light_instance.pngbin0 -> 380 bytes
-rw-r--r--tools/editor/icons/icon_blend.pngbin488 -> 443 bytes
-rw-r--r--tools/editor/icons/icon_bone.pngbin2992 -> 297 bytes
-rw-r--r--tools/editor/icons/icon_bool.pngbin184 -> 147 bytes
-rw-r--r--tools/editor/icons/icon_canvas_item.pngbin481 -> 434 bytes
-rw-r--r--tools/editor/icons/icon_canvas_item_material.pngbin0 -> 835 bytes
-rw-r--r--tools/editor/icons/icon_canvas_item_shader.pngbin0 -> 568 bytes
-rw-r--r--tools/editor/icons/icon_canvas_item_shader_graph.pngbin0 -> 575 bytes
-rw-r--r--tools/editor/icons/icon_canvas_modulate.pngbin0 -> 441 bytes
-rw-r--r--tools/editor/icons/icon_check_box.pngbin0 -> 344 bytes
-rw-r--r--tools/editor/icons/icon_class_list.pngbin0 -> 241 bytes
-rw-r--r--tools/editor/icons/icon_close.pngbin456 -> 398 bytes
-rw-r--r--tools/editor/icons/icon_close_hover.pngbin444 -> 391 bytes
-rw-r--r--tools/editor/icons/icon_collapse.pngbin343 -> 351 bytes
-rw-r--r--tools/editor/icons/icon_collapse_hl.pngbin341 -> 338 bytes
-rw-r--r--tools/editor/icons/icon_collision_polygon.pngbin0 -> 419 bytes
-rw-r--r--tools/editor/icons/icon_color_ramp.pngbin0 -> 290 bytes
-rw-r--r--tools/editor/icons/icon_connect.pngbin646 -> 592 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_curve_constant.pngbin0 -> 222 bytes
-rw-r--r--tools/editor/icons/icon_curve_in.pngbin0 -> 319 bytes
-rw-r--r--tools/editor/icons/icon_curve_in_out.pngbin0 -> 326 bytes
-rw-r--r--tools/editor/icons/icon_curve_linear.pngbin0 -> 275 bytes
-rw-r--r--tools/editor/icons/icon_curve_out.pngbin0 -> 319 bytes
-rw-r--r--tools/editor/icons/icon_curve_out_in.pngbin0 -> 318 bytes
-rw-r--r--tools/editor/icons/icon_debug.pngbin0 -> 659 bytes
-rw-r--r--tools/editor/icons/icon_default_project_icon.pngbin3621 -> 2713 bytes
-rw-r--r--tools/editor/icons/icon_del.pngbin456 -> 398 bytes
-rw-r--r--tools/editor/icons/icon_duplicate.pngbin363 -> 327 bytes
-rw-r--r--tools/editor/icons/icon_edit.pngbin523 -> 475 bytes
-rw-r--r--tools/editor/icons/icon_edit_key.pngbin534 -> 478 bytes
-rw-r--r--tools/editor/icons/icon_edit_resource.pngbin286 -> 234 bytes
-rw-r--r--tools/editor/icons/icon_editor_focus.pngbin1273 -> 629 bytes
-rw-r--r--tools/editor/icons/icon_enum.pngbin221 -> 193 bytes
-rw-r--r--tools/editor/icons/icon_event_player.pngbin352 -> 299 bytes
-rw-r--r--tools/editor/icons/icon_favorites.pngbin375 -> 412 bytes
-rw-r--r--tools/editor/icons/icon_file_big.pngbin0 -> 986 bytes
-rw-r--r--tools/editor/icons/icon_file_list.pngbin0 -> 288 bytes
-rw-r--r--tools/editor/icons/icon_file_server.pngbin636 -> 563 bytes
-rw-r--r--tools/editor/icons/icon_file_thumbnail.pngbin0 -> 296 bytes
-rw-r--r--tools/editor/icons/icon_filesystem.pngbin0 -> 241 bytes
-rw-r--r--tools/editor/icons/icon_folder.pngbin471 -> 428 bytes
-rw-r--r--tools/editor/icons/icon_folder_big.pngbin0 -> 1215 bytes
-rw-r--r--tools/editor/icons/icon_font.pngbin282 -> 248 bytes
-rw-r--r--tools/editor/icons/icon_forward.pngbin199 -> 191 bytes
-rw-r--r--tools/editor/icons/icon_g_d_script.pngbin628 -> 580 bytes
-rw-r--r--tools/editor/icons/icon_godot.pngbin0 -> 671 bytes
-rw-r--r--tools/editor/icons/icon_graph_color_ramp.pngbin0 -> 290 bytes
-rw-r--r--tools/editor/icons/icon_graph_comment.pngbin0 -> 310 bytes
-rw-r--r--tools/editor/icons/icon_graph_cube_uniform.pngbin0 -> 652 bytes
-rw-r--r--tools/editor/icons/icon_graph_curve_map.pngbin0 -> 619 bytes
-rw-r--r--tools/editor/icons/icon_graph_default_texture.pngbin0 -> 326 bytes
-rw-r--r--tools/editor/icons/icon_graph_input.pngbin0 -> 585 bytes
-rw-r--r--tools/editor/icons/icon_graph_rgb.pngbin0 -> 174 bytes
-rw-r--r--tools/editor/icons/icon_graph_rgb_op.pngbin0 -> 280 bytes
-rw-r--r--tools/editor/icons/icon_graph_rgb_uniform.pngbin0 -> 419 bytes
-rw-r--r--tools/editor/icons/icon_graph_scalar.pngbin0 -> 328 bytes
-rw-r--r--tools/editor/icons/icon_graph_scalar_interp.pngbin0 -> 352 bytes
-rw-r--r--tools/editor/icons/icon_graph_scalar_op.pngbin0 -> 238 bytes
-rw-r--r--tools/editor/icons/icon_graph_scalar_uniform.pngbin0 -> 392 bytes
-rw-r--r--tools/editor/icons/icon_graph_scalars_to_vec.pngbin0 -> 300 bytes
-rw-r--r--tools/editor/icons/icon_graph_texscreen.pngbin0 -> 578 bytes
-rw-r--r--tools/editor/icons/icon_graph_texture_uniform.pngbin0 -> 358 bytes
-rw-r--r--tools/editor/icons/icon_graph_time.pngbin0 -> 678 bytes
-rw-r--r--tools/editor/icons/icon_graph_vec_dp.pngbin0 -> 279 bytes
-rw-r--r--tools/editor/icons/icon_graph_vec_interp.pngbin0 -> 332 bytes
-rw-r--r--tools/editor/icons/icon_graph_vec_length.pngbin0 -> 303 bytes
-rw-r--r--tools/editor/icons/icon_graph_vec_op.pngbin0 -> 256 bytes
-rw-r--r--tools/editor/icons/icon_graph_vec_scalar_op.pngbin0 -> 267 bytes
-rw-r--r--tools/editor/icons/icon_graph_vec_to_scalars.pngbin0 -> 306 bytes
-rw-r--r--tools/editor/icons/icon_graph_vecs_to_xform.pngbin0 -> 288 bytes
-rw-r--r--tools/editor/icons/icon_graph_vector.pngbin0 -> 480 bytes
-rw-r--r--tools/editor/icons/icon_graph_vector_uniform.pngbin0 -> 531 bytes
-rw-r--r--tools/editor/icons/icon_graph_xform.pngbin0 -> 262 bytes
-rw-r--r--tools/editor/icons/icon_graph_xform_mult.pngbin0 -> 311 bytes
-rw-r--r--tools/editor/icons/icon_graph_xform_scalar_func.pngbin0 -> 378 bytes
-rw-r--r--tools/editor/icons/icon_graph_xform_to_vecs.pngbin0 -> 272 bytes
-rw-r--r--tools/editor/icons/icon_graph_xform_uniform.pngbin0 -> 346 bytes
-rw-r--r--tools/editor/icons/icon_graph_xform_vec_func.pngbin0 -> 389 bytes
-rw-r--r--tools/editor/icons/icon_graph_xform_vec_imult.pngbin0 -> 430 bytes
-rw-r--r--tools/editor/icons/icon_graph_xform_vec_mult.pngbin0 -> 422 bytes
-rw-r--r--tools/editor/icons/icon_grid.pngbin0 -> 354 bytes
-rw-r--r--tools/editor/icons/icon_group.pngbin402 -> 357 bytes
-rw-r--r--tools/editor/icons/icon_groups.pngbin558 -> 507 bytes
-rw-r--r--tools/editor/icons/icon_help.pngbin822 -> 841 bytes
-rw-r--r--tools/editor/icons/icon_hidden.pngbin553 -> 500 bytes
-rw-r--r--tools/editor/icons/icon_history.pngbin0 -> 572 bytes
-rw-r--r--tools/editor/icons/icon_image.pngbin444 -> 403 bytes
-rw-r--r--tools/editor/icons/icon_image_texture.pngbin352 -> 315 bytes
-rw-r--r--tools/editor/icons/icon_immediate_geometry.pngbin0 -> 363 bytes
-rw-r--r--tools/editor/icons/icon_instance_options.pngbin0 -> 483 bytes
-rw-r--r--tools/editor/icons/icon_integer.pngbin183 -> 142 bytes
-rw-r--r--tools/editor/icons/icon_interp_cubic.pngbin373 -> 340 bytes
-rw-r--r--tools/editor/icons/icon_interp_linear.pngbin172 -> 134 bytes
-rw-r--r--tools/editor/icons/icon_interp_raw.pngbin161 -> 127 bytes
-rw-r--r--tools/editor/icons/icon_item_list.pngbin0 -> 341 bytes
-rw-r--r--tools/editor/icons/icon_key.pngbin495 -> 450 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_key_next.pngbin0 -> 499 bytes
-rw-r--r--tools/editor/icons/icon_key_selected.pngbin257 -> 215 bytes
-rw-r--r--tools/editor/icons/icon_kinematic_body.pngbin0 -> 474 bytes
-rw-r--r--tools/editor/icons/icon_kinematic_body_2d.pngbin0 -> 475 bytes
-rw-r--r--tools/editor/icons/icon_light_2d.pngbin0 -> 342 bytes
-rw-r--r--tools/editor/icons/icon_light_map.pngbin0 -> 406 bytes
-rw-r--r--tools/editor/icons/icon_light_occluder_2d.pngbin0 -> 516 bytes
-rw-r--r--tools/editor/icons/icon_live_debug.pngbin0 -> 583 bytes
-rw-r--r--tools/editor/icons/icon_load.pngbin471 -> 428 bytes
-rw-r--r--tools/editor/icons/icon_lock.pngbin403 -> 362 bytes
-rw-r--r--tools/editor/icons/icon_loop.pngbin408 -> 366 bytes
-rw-r--r--tools/editor/icons/icon_main_play.pngbin367 -> 311 bytes
-rw-r--r--tools/editor/icons/icon_main_stop.pngbin336 -> 263 bytes
-rw-r--r--tools/editor/icons/icon_material_shader.pngbin0 -> 844 bytes
-rw-r--r--tools/editor/icons/icon_material_shader_graph.pngbin0 -> 949 bytes
-rw-r--r--tools/editor/icons/icon_mirror_x.pngbin230 -> 187 bytes
-rw-r--r--tools/editor/icons/icon_mirror_y.pngbin244 -> 215 bytes
-rw-r--r--tools/editor/icons/icon_move_down.pngbin286 -> 239 bytes
-rw-r--r--tools/editor/icons/icon_move_down_hl.pngbin266 -> 234 bytes
-rw-r--r--tools/editor/icons/icon_move_up.pngbin275 -> 225 bytes
-rw-r--r--tools/editor/icons/icon_move_up_hl.pngbin278 -> 224 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_navigation.pngbin0 -> 598 bytes
-rw-r--r--tools/editor/icons/icon_navigation_2d.pngbin0 -> 541 bytes
-rw-r--r--tools/editor/icons/icon_navigation_mesh_instance.pngbin0 -> 455 bytes
-rw-r--r--tools/editor/icons/icon_navigation_polygon_instance.pngbin0 -> 391 bytes
-rw-r--r--tools/editor/icons/icon_new.pngbin344 -> 298 bytes
-rw-r--r--tools/editor/icons/icon_node.pngbin301 -> 257 bytes
-rw-r--r--tools/editor/icons/icon_non_favorite.pngbin0 -> 469 bytes
-rw-r--r--tools/editor/icons/icon_occluder_polygon_2d.pngbin0 -> 581 bytes
-rw-r--r--tools/editor/icons/icon_open.pngbin471 -> 428 bytes
-rw-r--r--tools/editor/icons/icon_p_hash_translation.pngbin282 -> 234 bytes
-rw-r--r--tools/editor/icons/icon_packed_scene.pngbin536 -> 485 bytes
-rw-r--r--tools/editor/icons/icon_panel_top.pngbin0 -> 195 bytes
-rw-r--r--tools/editor/icons/icon_panels_1.pngbin195 -> 154 bytes
-rw-r--r--tools/editor/icons/icon_panels_2.pngbin196 -> 157 bytes
-rw-r--r--tools/editor/icons/icon_panels_2_alt.pngbin0 -> 156 bytes
-rw-r--r--tools/editor/icons/icon_panels_3.pngbin205 -> 166 bytes
-rw-r--r--tools/editor/icons/icon_panels_3_alt.pngbin0 -> 167 bytes
-rw-r--r--tools/editor/icons/icon_panels_4.pngbin198 -> 159 bytes
-rw-r--r--tools/editor/icons/icon_particle_attractor_2d.pngbin0 -> 574 bytes
-rw-r--r--tools/editor/icons/icon_patch_9_frame.pngbin0 -> 431 bytes
-rw-r--r--tools/editor/icons/icon_pause.pngbin367 -> 228 bytes
-rw-r--r--tools/editor/icons/icon_pin.pngbin420 -> 381 bytes
-rw-r--r--tools/editor/icons/icon_pin_joint.pngbin0 -> 334 bytes
-rw-r--r--tools/editor/icons/icon_pin_pressed.pngbin385 -> 346 bytes
-rw-r--r--tools/editor/icons/icon_play.pngbin302 -> 260 bytes
-rw-r--r--tools/editor/icons/icon_play_backwards.pngbin0 -> 256 bytes
-rw-r--r--tools/editor/icons/icon_play_custom.pngbin533 -> 500 bytes
-rw-r--r--tools/editor/icons/icon_play_scene.pngbin690 -> 600 bytes
-rw-r--r--tools/editor/icons/icon_play_start.pngbin0 -> 282 bytes
-rw-r--r--tools/editor/icons/icon_play_start_backwards.pngbin0 -> 289 bytes
-rw-r--r--tools/editor/icons/icon_polygon_2d.pngbin0 -> 405 bytes
-rw-r--r--tools/editor/icons/icon_prev_scene.pngbin279 -> 229 bytes
-rw-r--r--tools/editor/icons/icon_ray_cast.pngbin0 -> 214 bytes
-rw-r--r--tools/editor/icons/icon_real.pngbin183 -> 146 bytes
-rw-r--r--tools/editor/icons/icon_region_edit.pngbin0 -> 171 bytes
-rw-r--r--tools/editor/icons/icon_reload.pngbin567 -> 519 bytes
-rw-r--r--tools/editor/icons/icon_remote.pngbin0 -> 707 bytes
-rw-r--r--tools/editor/icons/icon_remove.pngbin456 -> 519 bytes
-rw-r--r--tools/editor/icons/icon_remove_small.pngbin0 -> 297 bytes
-rw-r--r--tools/editor/icons/icon_rename.pngbin320 -> 269 bytes
-rw-r--r--tools/editor/icons/icon_reparent.pngbin523 -> 474 bytes
-rw-r--r--tools/editor/icons/icon_replace.pngbin483 -> 435 bytes
-rw-r--r--tools/editor/icons/icon_resource_preloader.pngbin771 -> 716 bytes
-rw-r--r--tools/editor/icons/icon_rotate_0.pngbin0 -> 207 bytes
-rw-r--r--tools/editor/icons/icon_rotate_180.pngbin0 -> 303 bytes
-rw-r--r--tools/editor/icons/icon_rotate_270.pngbin0 -> 343 bytes
-rw-r--r--tools/editor/icons/icon_rotate_90.pngbin0 -> 256 bytes
-rw-r--r--tools/editor/icons/icon_sample_player.pngbin448 -> 415 bytes
-rw-r--r--tools/editor/icons/icon_save.pngbin515 -> 473 bytes
-rw-r--r--tools/editor/icons/icon_script.pngbin317 -> 272 bytes
-rw-r--r--tools/editor/icons/icon_script_list.pngbin0 -> 213 bytes
-rw-r--r--tools/editor/icons/icon_slider_joint.pngbin0 -> 283 bytes
-rw-r--r--tools/editor/icons/icon_sound_room_params.pngbin577 -> 534 bytes
-rw-r--r--tools/editor/icons/icon_stop.pngbin171 -> 236 bytes
-rw-r--r--tools/editor/icons/icon_stream_player.pngbin355 -> 327 bytes
-rw-r--r--tools/editor/icons/icon_string.pngbin156 -> 121 bytes
-rw-r--r--tools/editor/icons/icon_tab_menu.pngbin0 -> 251 bytes
-rw-r--r--tools/editor/icons/icon_texture.pngbin328 -> 292 bytes
-rw-r--r--tools/editor/icons/icon_timer.pngbin607 -> 551 bytes
-rw-r--r--tools/editor/icons/icon_tool_move.pngbin323 -> 275 bytes
-rw-r--r--tools/editor/icons/icon_tool_pan.pngbin1555 -> 1654 bytes
-rw-r--r--tools/editor/icons/icon_tool_rotate.pngbin610 -> 567 bytes
-rw-r--r--tools/editor/icons/icon_tool_scale.pngbin415 -> 366 bytes
-rw-r--r--tools/editor/icons/icon_tool_select.pngbin359 -> 311 bytes
-rw-r--r--tools/editor/icons/icon_tools.pngbin639 -> 589 bytes
-rw-r--r--tools/editor/icons/icon_touch_screen_button.pngbin0 -> 434 bytes
-rw-r--r--tools/editor/icons/icon_track_continuous.pngbin268 -> 231 bytes
-rw-r--r--tools/editor/icons/icon_track_discrete.pngbin153 -> 118 bytes
-rw-r--r--tools/editor/icons/icon_translation.pngbin286 -> 241 bytes
-rw-r--r--tools/editor/icons/icon_transpose.pngbin0 -> 244 bytes
-rw-r--r--tools/editor/icons/icon_unbone.pngbin3000 -> 303 bytes
-rw-r--r--tools/editor/icons/icon_ungroup.pngbin525 -> 478 bytes
-rw-r--r--tools/editor/icons/icon_unlock.pngbin367 -> 337 bytes
-rw-r--r--tools/editor/icons/icon_uv.pngbin381 -> 343 bytes
-rw-r--r--tools/editor/icons/icon_vector.pngbin190 -> 158 bytes
-rw-r--r--tools/editor/icons/icon_vector2.pngbin176 -> 141 bytes
-rw-r--r--tools/editor/icons/icon_vehicle_body.pngbin0 -> 443 bytes
-rw-r--r--tools/editor/icons/icon_vehicle_wheel.pngbin0 -> 528 bytes
-rw-r--r--tools/editor/icons/icon_viewport.pngbin325 -> 287 bytes
-rw-r--r--tools/editor/icons/icon_visible.pngbin563 -> 502 bytes
-rw-r--r--tools/editor/icons/icon_wait_no_preview.pngbin0 -> 1041 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_1.pngbin0 -> 1208 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_2.pngbin0 -> 1270 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_3.pngbin0 -> 1190 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_4.pngbin0 -> 1269 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_5.pngbin0 -> 1191 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_6.pngbin0 -> 1278 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_7.pngbin0 -> 1192 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_8.pngbin0 -> 1341 bytes
-rw-r--r--tools/editor/icons/icon_y_sort.pngbin0 -> 392 bytes
-rw-r--r--tools/editor/icons/icon_zoom.pngbin582 -> 537 bytes
-rw-r--r--tools/editor/import_settings.cpp4
-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.cpp395
-rw-r--r--tools/editor/io_plugins/editor_font_import_plugin.h2
-rw-r--r--tools/editor/io_plugins/editor_import_collada.cpp591
-rw-r--r--tools/editor/io_plugins/editor_import_collada.h4
-rw-r--r--tools/editor/io_plugins/editor_mesh_import_plugin.cpp51
-rw-r--r--tools/editor/io_plugins/editor_sample_import_plugin.cpp136
-rw-r--r--tools/editor/io_plugins/editor_sample_import_plugin.h16
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.cpp1091
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.h43
-rw-r--r--tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp1106
-rw-r--r--tools/editor/io_plugins/editor_scene_importer_fbxconv.h81
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.cpp543
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.h16
-rw-r--r--tools/editor/io_plugins/editor_translation_import_plugin.cpp14
-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.cpp4
-rw-r--r--tools/editor/output_strings.h124
-rw-r--r--tools/editor/pane_drag.cpp2
-rw-r--r--tools/editor/pane_drag.h48
-rw-r--r--tools/editor/plugins/SCsub4
-rw-r--r--tools/editor/plugins/animation_data_editor_plugin.cpp12
-rw-r--r--tools/editor/plugins/animation_data_editor_plugin.h22
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.cpp501
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.h52
-rw-r--r--tools/editor/plugins/animation_tree_editor_plugin.cpp12
-rw-r--r--tools/editor/plugins/animation_tree_editor_plugin.h4
-rw-r--r--tools/editor/plugins/baked_light_baker.cpp1297
-rw-r--r--tools/editor/plugins/baked_light_baker.h67
-rw-r--r--tools/editor/plugins/baked_light_baker_cmpxchg.cpp85
-rw-r--r--tools/editor/plugins/baked_light_editor_plugin.cpp58
-rw-r--r--tools/editor/plugins/baked_light_editor_plugin.h8
-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.cpp969
-rw-r--r--tools/editor/plugins/canvas_item_editor_plugin.h77
-rw-r--r--tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp456
-rw-r--r--tools/editor/plugins/collision_polygon_2d_editor_plugin.h83
-rw-r--r--tools/editor/plugins/collision_polygon_editor_plugin.cpp298
-rw-r--r--tools/editor/plugins/collision_polygon_editor_plugin.h26
-rw-r--r--tools/editor/plugins/collision_shape_2d_editor_plugin.cpp573
-rw-r--r--tools/editor/plugins/collision_shape_2d_editor_plugin.h73
-rw-r--r--tools/editor/plugins/color_ramp_editor_plugin.cpp83
-rw-r--r--tools/editor/plugins/color_ramp_editor_plugin.h37
-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.cpp6
-rw-r--r--tools/editor/plugins/cube_grid_theme_editor_plugin.h4
-rw-r--r--tools/editor/plugins/editor_preview_plugins.cpp783
-rw-r--r--tools/editor/plugins/editor_preview_plugins.h88
-rw-r--r--tools/editor/plugins/item_list_editor_plugin.cpp368
-rw-r--r--tools/editor/plugins/item_list_editor_plugin.h140
-rw-r--r--tools/editor/plugins/light_occluder_2d_editor_plugin.cpp492
-rw-r--r--tools/editor/plugins/light_occluder_2d_editor_plugin.h87
-rw-r--r--tools/editor/plugins/mesh_editor_plugin.cpp300
-rw-r--r--tools/editor/plugins/mesh_editor_plugin.h69
-rw-r--r--tools/editor/plugins/multimesh_editor_plugin.cpp59
-rw-r--r--tools/editor/plugins/multimesh_editor_plugin.h10
-rw-r--r--tools/editor/plugins/navigation_polygon_editor_plugin.cpp540
-rw-r--r--tools/editor/plugins/navigation_polygon_editor_plugin.h90
-rw-r--r--tools/editor/plugins/particles_2d_editor_plugin.cpp343
-rw-r--r--tools/editor/plugins/particles_2d_editor_plugin.h110
-rw-r--r--tools/editor/plugins/particles_editor_plugin.cpp35
-rw-r--r--tools/editor/plugins/particles_editor_plugin.h9
-rw-r--r--tools/editor/plugins/path_2d_editor_plugin.cpp37
-rw-r--r--tools/editor/plugins/path_2d_editor_plugin.h3
-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.cpp188
-rw-r--r--tools/editor/plugins/polygon_2d_editor_plugin.h18
-rw-r--r--tools/editor/plugins/resource_preloader_editor_plugin.cpp12
-rw-r--r--tools/editor/plugins/resource_preloader_editor_plugin.h4
-rw-r--r--tools/editor/plugins/rich_text_editor_plugin.cpp20
-rw-r--r--tools/editor/plugins/rich_text_editor_plugin.h8
-rw-r--r--tools/editor/plugins/sample_editor_plugin.cpp129
-rw-r--r--tools/editor/plugins/sample_editor_plugin.h2
-rw-r--r--tools/editor/plugins/sample_library_editor_plugin.cpp22
-rw-r--r--tools/editor/plugins/sample_library_editor_plugin.h4
-rw-r--r--tools/editor/plugins/sample_player_editor_plugin.cpp10
-rw-r--r--tools/editor/plugins/sample_player_editor_plugin.h2
-rw-r--r--tools/editor/plugins/script_editor_plugin.cpp1812
-rw-r--r--tools/editor/plugins/script_editor_plugin.h122
-rw-r--r--tools/editor/plugins/shader_editor_plugin.cpp92
-rw-r--r--tools/editor/plugins/shader_editor_plugin.h8
-rw-r--r--tools/editor/plugins/shader_graph_editor_plugin.cpp3203
-rw-r--r--tools/editor/plugins/shader_graph_editor_plugin.h247
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.cpp878
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.h86
-rw-r--r--tools/editor/plugins/sprite_frames_editor_plugin.cpp49
-rw-r--r--tools/editor/plugins/sprite_frames_editor_plugin.h6
-rw-r--r--tools/editor/plugins/sprite_region_editor_plugin.cpp565
-rw-r--r--tools/editor/plugins/sprite_region_editor_plugin.h125
-rw-r--r--tools/editor/plugins/stream_editor_plugin.cpp4
-rw-r--r--tools/editor/plugins/stream_editor_plugin.h2
-rw-r--r--tools/editor/plugins/style_box_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/style_box_editor_plugin.h2
-rw-r--r--tools/editor/plugins/theme_editor_plugin.cpp26
-rw-r--r--tools/editor/plugins/theme_editor_plugin.h6
-rw-r--r--tools/editor/plugins/tile_map_editor_plugin.cpp554
-rw-r--r--tools/editor/plugins/tile_map_editor_plugin.h44
-rw-r--r--tools/editor/plugins/tile_set_editor_plugin.cpp177
-rw-r--r--tools/editor/plugins/tile_set_editor_plugin.h4
-rw-r--r--tools/editor/progress_dialog.cpp9
-rw-r--r--tools/editor/progress_dialog.h2
-rw-r--r--tools/editor/project_export.cpp119
-rw-r--r--tools/editor/project_export.h20
-rw-r--r--tools/editor/project_manager.cpp101
-rw-r--r--tools/editor/project_manager.h2
-rw-r--r--tools/editor/project_settings.cpp268
-rw-r--r--tools/editor/project_settings.h19
-rw-r--r--tools/editor/property_editor.cpp1298
-rw-r--r--tools/editor/property_editor.h77
-rw-r--r--tools/editor/pvrtc_compress.cpp30
-rw-r--r--tools/editor/pvrtc_compress.h2
-rw-r--r--tools/editor/quick_open.cpp46
-rw-r--r--tools/editor/quick_open.h12
-rw-r--r--tools/editor/register_exporters.h2
-rw-r--r--tools/editor/reparent_dialog.cpp10
-rw-r--r--tools/editor/reparent_dialog.h2
-rw-r--r--tools/editor/resources_dock.cpp75
-rw-r--r--tools/editor/resources_dock.h5
-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.cpp345
-rw-r--r--tools/editor/scene_tree_dock.h11
-rw-r--r--tools/editor/scene_tree_editor.cpp267
-rw-r--r--tools/editor/scene_tree_editor.h24
-rw-r--r--tools/editor/scenes.cpp2
-rw-r--r--tools/editor/scenes.h2
-rw-r--r--tools/editor/scenes_dock.cpp1197
-rw-r--r--tools/editor/scenes_dock.h132
-rw-r--r--tools/editor/script_create_dialog.cpp22
-rw-r--r--tools/editor/script_create_dialog.h6
-rw-r--r--tools/editor/script_editor_debugger.cpp605
-rw-r--r--tools/editor/script_editor_debugger.h272
-rw-r--r--tools/editor/settings_config_dialog.cpp49
-rw-r--r--tools/editor/settings_config_dialog.h6
-rw-r--r--tools/editor/spatial_editor_gizmos.cpp5561
-rw-r--r--tools/editor/spatial_editor_gizmos.h858
-rw-r--r--tools/export/blender25/godot_export_manager.py472
-rw-r--r--tools/export/blender25/install.txt16
-rw-r--r--tools/export/blender25/io_scene_dae/__init__.py35
-rw-r--r--tools/export/blender25/io_scene_dae/export_dae.py813
-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/SCsub4
-rw-r--r--tools/pck/pck_packer.cpp163
-rw-r--r--tools/pck/pck_packer.h31
-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
-rw-r--r--tools/script_plugins/time/time.gd4
-rwxr-xr-xtools/scripts/file-hex-array.py52
-rw-r--r--tools/scripts/makeargs.py (renamed from tools/scrits/makeargs.py)0
-rw-r--r--version.py6
4377 files changed, 388179 insertions, 170002 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..e19057f0e8
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,10 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = tab
+
+[.travis.yml]
+indent_style = space
+indent_size = 2
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 45bf531311..d947306558 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,12 +12,23 @@ drivers/gles2/shaders/*.h
modules/register_module_types.cpp
core/version.h
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
-fpic
+.fscache
+make.bat
+log.txt
+
+# Doxygen generated documentation
+doc/doxygen/*
+
+# Javascript specific
+*.bc
# Android specific
platform/android/java/local.properties
@@ -43,6 +54,14 @@ platform/android/libs/play_licensing/gen/*
*.d
*.so
*.os
+*.Plo
+*.lo
+*.Po
+
+# Libs generated files
+.deps/*
+.dirstamp
+
# QT project files
*.config
@@ -66,6 +85,8 @@ platform/android/libs/play_licensing/gen/*
*.suo
*.user
*.sln.docstates
+*.sln
+*.vcxproj*
# Build results
[Dd]ebug/
@@ -257,3 +278,23 @@ Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
logo.h
+*.autosave
+
+# https://github.com/github/gitignore/blob/master/Global/Tags.gitignore
+# Ignore tags created by etags, ctags, gtags (GNU global) and cscope
+TAGS
+!TAGS/
+tags
+!tags/
+gtags.files
+GTAGS
+GRTAGS
+GPATH
+cscope.files
+cscope.out
+cscope.in.out
+cscope.po.out
+godot.creator.*
+
+projects/
+platform/windows/godot_res.res
diff --git a/.travis.yml b/.travis.yml
index 73b07acb7f..6dd21dae0b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,4 +11,4 @@ before_script:
- 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 bin/godot
+script: scons platform=x11
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000000..4268ed8c7d
--- /dev/null
+++ b/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_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 = ./doc/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/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000000..ca0a9702f7
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,27 @@
+ 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.
+
+
+**********************************************************************
+
diff --git a/LOGO_LICENSE.md b/LOGO_LICENSE.md
new file mode 100644
index 0000000000..2858712f18
--- /dev/null
+++ b/LOGO_LICENSE.md
@@ -0,0 +1,2 @@
+Godot Logo (c) Andrea Calabró, distributed under the terms of the CC By License:
+https://creativecommons.org/licenses/by/3.0/legalcode \ No newline at end of file
diff --git a/README.md b/README.md
index dba980bba9..d5dadb93a7 100644
--- a/README.md
+++ b/README.md
@@ -7,17 +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 is BETA. Collaborate!!
-
-Having been developed as in-house means that the user experience may still not be ideal for everyone. The features needed to make a great game are there, but we really need your help to fix all the rough edges and improve usability (via feedback and/or code contributions).
-We know we are close to having an awesome, open source, game engine with nothing to envy from the best commercial offerings, but we can't do this alone. This is why Godot is now open source, so everyone can help us reach this goal.
+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.
@@ -28,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 19c5d8ce8a..95ad0010a2 100644
--- a/SConstruct
+++ b/SConstruct
@@ -6,16 +6,6 @@ import os.path
import glob
import sys
import methods
-import multiprocessing
-
-# Enable aggresive compile mode if building on a multi core box
-# only is we have not set the number of jobs already or we do
-# not want it
-if ARGUMENTS.get('spawn_jobs', 'no') == 'yes' and \
- int(GetOption('num_jobs')) <= 1:
- NUM_JOBS = multiprocessing.cpu_count()
- if NUM_JOBS > 1:
- SetOption('num_jobs', NUM_JOBS+1)
methods.update_version()
@@ -58,36 +48,46 @@ for x in glob.glob("platform/*"):
module_list=methods.detect_modules()
-print "Detected Platforms: "+str(platform_list)
-print("Detected Modules: "+str(module_list))
+#print "Detected Platforms: "+str(platform_list)
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_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__.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,20 +99,18 @@ if profile:
customs.append(profile+".py")
opts=Variables(customs, ARGUMENTS)
-opts.Add('target', 'Compile Target (debug/profile/release).', "debug")
-opts.Add('platform','Platform: '+str(platform_list)+'(sfml).',"")
-opts.Add('python','Build Python Support: (yes/no)','no')
-opts.Add('squirrel','Build Squirrel Support: (yes/no)','no')
+opts.Add('target', 'Compile Target (debug/release_debug/release).', "debug")
+opts.Add('bits', 'Compile Target Bits (default/32/64).', "default")
+opts.Add('platform','Platform: '+str(platform_list)+'.',"")
+opts.Add('p','Platform (same as platform=).',"")
opts.Add('tools','Build Tools (Including Editor): (yes/no)','yes')
-opts.Add('lua','Build Lua Support: (yes/no)','no')
-opts.Add('rfd','Remote Filesystem Driver: (yes/no)','no')
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('opengl', 'Build OpenGL Support: (yes/no)', 'yes')
-opts.Add('game', 'Game (custom) Code Directory', "")
-opts.Add('squish','Squish BC Texture Compression (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('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')
@@ -121,18 +119,20 @@ opts.Add('jpg','JPG Image loader support (yes/no)','yes')
opts.Add('webp','WEBP Image loader support (yes/no)','yes')
opts.Add('dds','DDS Texture loader support (yes/no)','yes')
opts.Add('pvr','PVR (PowerVR) Texture loader support (yes/no)','yes')
+opts.Add('etc1','etc1 Texture compression support (yes/no)','yes')
opts.Add('builtin_zlib','Use built-in zlib (yes/no)','yes')
opts.Add('openssl','Use OpenSSL (yes/no/builtin)','no')
opts.Add('musepack','Musepack Audio (yes/no)','yes')
-opts.Add('default_gui_theme','Default GUI theme (yes/no)','yes')
opts.Add("CXX", "Compiler");
-opts.Add("nedmalloc", "Add nedmalloc support", 'yes');
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('old_scenes', 'Compatibility with old-style scenes', "yes")
+opts.Add('colored', 'Enable colored output for the compilation (yes/no)', 'no')
+opts.Add('extra_suffix', 'Custom extra suffix added to the base filename of all generated binary files.', '')
+opts.Add('vsproj', 'Generate Visual Studio Project. (yes/no)', 'no')
# add platform specific options
@@ -150,9 +150,8 @@ Help(opts.GenerateHelpText(env_base)) # generate help
# add default include paths
env_base.Append(CPPPATH=['#core','#core/math','#tools','#drivers','#'])
-
-# configure ENV for platform
-env_base.detect_python=True
+
+# configure ENV for platform
env_base.platform_exporters=platform_exporters
"""
@@ -170,17 +169,48 @@ if (env_base['target']=='debug'):
env_base.platforms = {}
-for p in platform_list:
+selected_platform =""
- if env_base['platform'] != "" and env_base['platform'] != p:
- continue
- sys.path.append("./platform/"+p)
+if env_base['platform'] != "":
+ selected_platform=env_base['platform']
+elif env_base['p'] != "":
+ selected_platform=env_base['p']
+ env_base["platform"]=selected_platform
+
+
+if selected_platform in platform_list:
+
+ sys.path.append("./platform/"+selected_platform)
import detect
if "create" in dir(detect):
env = detect.create(env_base)
else:
env = env_base.Clone()
+ if env['vsproj']=="yes":
+ env.vs_incs = []
+ env.vs_srcs = []
+
+ def AddToVSProject( sources ):
+ for x in sources:
+ if type(x) == type(""):
+ fname = env.File(x).path
+ else:
+ fname = env.File(x)[0].path
+ pieces = fname.split(".")
+ if len(pieces)>0:
+ 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.extra_suffix=""
+
+ if env["extra_suffix"] != '' :
+ env.extra_suffix += '.'+env["extra_suffix"]
+
CCFLAGS = env.get('CCFLAGS', '')
env['CCFLAGS'] = ''
@@ -196,17 +226,50 @@ for p in platform_list:
env.Append(LINKFLAGS=string.split(str(LINKFLAGS)))
+ 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]
+
+ #must happen after the flags, so when flags are used by configure, stuff happens (ie, ssl on x11)
detect.configure(env)
- env['platform'] = p
- if not env.has_key('platform_libsuffix'):
- env['platform_libsuffix'] = env['LIBSUFFIX']
- sys.path.remove("./platform/"+p)
+
+ #env['platform_libsuffix'] = env['LIBSUFFIX']
+
+ suffix="."+selected_platform
+
+ if (env["target"]=="release"):
+ if (env["tools"]=="yes"):
+ print("Tools can only be built with targets 'debug' and 'release_debug'.")
+ sys.exit(255)
+ suffix+=".opt"
+
+ elif (env["target"]=="release_debug"):
+ if (env["tools"]=="yes"):
+ suffix+=".opt.tools"
+ else:
+ suffix+=".opt.debug"
+ else:
+ if (env["tools"]=="yes"):
+ suffix+=".tools"
+ else:
+ suffix+=".debug"
+
+ if (env["bits"]=="32"):
+ suffix+=".32"
+ elif (env["bits"]=="64"):
+ suffix+=".64"
+
+ suffix+=env.extra_suffix
+
+ env["PROGSUFFIX"]=suffix+env["PROGSUFFIX"]
+ env["OBJSUFFIX"]=suffix+env["OBJSUFFIX"]
+ env["LIBSUFFIX"]=suffix+env["LIBSUFFIX"]
+ env["SHLIBSUFFIX"]=suffix+env["SHLIBSUFFIX"]
+
+ sys.path.remove("./platform/"+selected_platform)
sys.modules.pop('detect')
- flag_list = platform_flags[p]
- for f in flag_list:
- env[f[0]] = f[1]
- print(f[0]+":"+f[1])
env.module_list=[]
@@ -217,7 +280,7 @@ for p in platform_list:
sys.path.append(tmppath)
env.current_module=x
import config
- if (config.can_build(p)):
+ if (config.can_build(selected_platform)):
config.configure(env)
env.module_list.append(x)
sys.path.remove(tmppath)
@@ -226,16 +289,12 @@ for p 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_openssl'])
+ if (env['openssl']!='no'):
+ env.Append(CPPFLAGS=['-DOPENSSL_ENABLED']);
+ if (env['openssl']=="builtin"):
+ env.Append(CPPPATH=['#drivers/builtin_openssl2'])
- if (env["old_scenes"]=='yes'):
- env.Append(CPPFLAGS=['-DOLD_SCENE_FORMAT_ENABLED'])
- if (env["rfd"]=='yes'):
- env.Append(CPPFLAGS=['-DRFD_ENABLED'])
if (env["builtin_zlib"]=='yes'):
env.Append(CPPPATH=['#drivers/builtin_zlib/zlib'])
@@ -247,9 +306,15 @@ for p 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']);
@@ -280,34 +345,11 @@ for p in platform_list:
if (env['xml']=='yes'):
env.Append(CPPFLAGS=['-DXML_ENABLED'])
- if (env['default_gui_theme']=='no'):
- env.Append(CPPFLAGS=['-DDEFAULT_THEME_DISABLED'])
-
- if (env["python"]=='yes'):
- detected=False;
- if (env.detect_python):
- print("Python 3.0 Prefix:");
- pycfg_exec="python3-config"
- errorval=os.system(pycfg_exec+" --prefix")
- prefix=""
- if (not errorval):
- #gah, why can't it get both at the same time like pkg-config, sdl-config, etc?
- env.ParseConfig(pycfg_exec+" --cflags")
- env.ParseConfig(pycfg_exec+" --libs")
- detected=True
-
- if (detected):
- env.Append(CPPFLAGS=['-DPYTHON_ENABLED'])
- #remove annoying warnings
- if ('-Wstrict-prototypes' in env["CCFLAGS"]):
- env["CCFLAGS"].remove('-Wstrict-prototypes');
- if ('-fwrapv' in env["CCFLAGS"]):
- env["CCFLAGS"].remove('-fwrapv');
- else:
- print("Python 3.0 not detected ("+pycfg_exec+") support disabled.");
+ if (env['colored']=='yes'):
+ methods.colored(sys,env)
- #if env['nedmalloc'] == 'yes':
- # env.Append(CPPFLAGS = ['-DNEDMALLOC_ENABLED'])
+ if (env['etc1']=='yes'):
+ env.Append(CPPFLAGS=['-DETC1_ENABLED'])
Export('env')
@@ -320,11 +362,46 @@ for p in platform_list:
SConscript("drivers/SCsub")
SConscript("bin/SCsub")
- if env['game']:
- SConscript(env['game']+'/SCsub')
-
SConscript("modules/SCsub")
SConscript("main/SCsub")
- SConscript("platform/"+p+"/SCsub"); # build selected platform
-
+ SConscript("platform/"+selected_platform+"/SCsub"); # build selected platform
+
+ # Microsoft Visual Studio Project Generation
+ if (env['vsproj'])=="yes":
+
+ AddToVSProject(env.core_sources)
+ AddToVSProject(env.main_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 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']
+ variants = debug_variants + release_variants + release_debug_variants
+ debug_targets = ['Debug']+['Debug']
+ release_targets = ['Release']+['Release']
+ release_debug_targets = ['ReleaseDebug']+['ReleaseDebug']
+ 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)
+
+else:
+
+ print("No valid target platform selected.")
+ print("The following were detected:")
+ for x in platform_list:
+ print("\t"+x)
+ print("\nPlease run scons again with argument: platform=<string>")
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 d80dbd1f22..db877fcc1c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_containers.h b/bin/tests/test_containers.h
index 7f73d132a1..3bfdef301b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_detailer.cpp b/bin/tests/test_detailer.cpp
index 4cb927411a..ce318632dd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_detailer.h b/bin/tests/test_detailer.h
index 49c206ee93..a410f6a67a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_gdscript.cpp b/bin/tests/test_gdscript.cpp
index b62deee2cd..68209ecb54 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -478,6 +478,7 @@ static String _disassemble_addr(const Ref<GDScript>& p_script,const GDFunction&
case GDFunction::ADDR_TYPE_NIL: {
return "nil";
} break;
+
}
return "<err>";
@@ -738,6 +739,26 @@ static void _disassemble_class(const Ref<GDScript>& p_class,const Vector<String>
incr=4+argc;
} break;
+ case GDFunction::OPCODE_YIELD: {
+
+ txt+=" yield ";
+ incr=1;
+
+ } break;
+ case GDFunction::OPCODE_YIELD_SIGNAL: {
+
+ txt+=" yield_signal ";
+ txt+=DADDR(1);
+ txt+=",";
+ txt+=DADDR(2);
+ incr=3;
+ } break;
+ case GDFunction::OPCODE_YIELD_RESUME: {
+
+ txt+=" yield resume: ";
+ txt+=DADDR(1);
+ incr=2;
+ } break;
case GDFunction::OPCODE_JUMP: {
txt+=" jump ";
@@ -808,6 +829,13 @@ static void _disassemble_class(const Ref<GDScript>& p_class,const Vector<String>
txt+=" end";
incr+=1;
} break;
+ case GDFunction::OPCODE_ASSERT: {
+
+ txt+=" assert ";
+ txt+=DADDR(1);
+ incr+=2;
+
+ } break;
}
diff --git a/bin/tests/test_gdscript.h b/bin/tests/test_gdscript.h
index 1659880c2a..f599b9c9e1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_gui.cpp b/bin/tests/test_gui.cpp
index f814b0282b..c404623872 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -58,7 +58,7 @@
namespace TestGUI {
-class TestMainLoop : public SceneMainLoop {
+class TestMainLoop : public SceneTree {
Control *control;
@@ -72,7 +72,7 @@ public:
}
virtual void init() {
- SceneMainLoop::init();
+ SceneTree::init();
#if 0
@@ -109,6 +109,9 @@ public:
frame->set_anchor( MARGIN_RIGHT, Control::ANCHOR_END );
frame->set_anchor( MARGIN_BOTTOM, Control::ANCHOR_END );
frame->set_end( Point2(0,0) );
+
+ Ref<Theme> t = memnew( Theme );
+ frame->set_theme(t);
get_root()->add_child( frame );
@@ -140,10 +143,10 @@ public:
img.resize(512,512);
img.generate_mipmaps();
- img.compress();
- Ref<Texture> text = memnew( Texture );
- text->create_from_image(img);
- tf->set_texture(text);
+ img.compress(Image::COMPRESS_PVRTC4);
+ Ref<ImageTexture> tt = memnew( ImageTexture );
+ tt->create_from_image(img);
+ tf->set_texture(tt);
tf->set_pos(Point2(50,50));
//tf->set_scale(Point2(0.3,0.3));
diff --git a/bin/tests/test_gui.h b/bin/tests/test_gui.h
index 85c334dceb..556b45462a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_image.cpp b/bin/tests/test_image.cpp
index 5a25c47136..b378755dfe 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_image.h b/bin/tests/test_image.h
index cd6fe458d4..8812658464 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_io.cpp b/bin/tests/test_io.cpp
index b1d8188c42..4c211a1b0d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_io.h b/bin/tests/test_io.h
index 9184d4bb86..27a5118cf0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_main.cpp b/bin/tests/test_main.cpp
index 5d66f35f24..5567145aa0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 404e528e14..d1898387eb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_math.cpp b/bin/tests/test_math.cpp
index 2db945d5fd..d340515c65 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -80,6 +80,7 @@ MainLoop* test() {
{
+
// print_line("NUM: "+itos(237641278346127));
print_line("NUM: "+itos(-128));
return NULL;
diff --git a/bin/tests/test_math.h b/bin/tests/test_math.h
index 7b8d154475..3209ebcef6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_misc.cpp b/bin/tests/test_misc.cpp
index 819afc0d06..d6ea193853 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_misc.h b/bin/tests/test_misc.h
index d6310e5f38..ac751e5cc9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_particles.cpp b/bin/tests/test_particles.cpp
index 2ccbb31017..18b52444d8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_particles.h b/bin/tests/test_particles.h
index 876751a56f..e5e3cfab15 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_physics.cpp b/bin/tests/test_physics.cpp
index ba305cc769..e3fd96ff9d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -92,7 +92,7 @@ protected:
RID mesh_instance = vs->instance_create2(type_mesh_map[p_shape],scenario);
RID body = ps->body_create(p_body,!p_active_default);
ps->body_set_space(body,space);
- ps->body_set_param(body,PhysicsServer::BODY_PARAM_BOUNCE,0.5);
+ ps->body_set_param(body,PhysicsServer::BODY_PARAM_BOUNCE,0.0);
//todo set space
ps->body_add_shape(body,type_shape_map[p_shape]);
ps->body_set_force_integration_callback(body,this,"body_changed_transform",mesh_instance);
diff --git a/bin/tests/test_physics.h b/bin/tests/test_physics.h
index ef4f647829..f62806bf5e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_physics_2d.cpp b/bin/tests/test_physics_2d.cpp
index b2ad1d9ee8..70a7d868be 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -191,7 +191,7 @@ class TestPhysics2DMainLoop : public MainLoop {
Image image(convex_png);
- body_shape_data[Physics2DServer::SHAPE_CONVEX_POLYGON].image=vs->texture_create_from_image(image);
+ body_shape_data[Physics2DServer::SHAPE_CUSTOM+1].image=vs->texture_create_from_image(image);
RID convex_polygon_shape = ps->shape_create(Physics2DServer::SHAPE_CONVEX_POLYGON);
@@ -206,7 +206,7 @@ class TestPhysics2DMainLoop : public MainLoop {
arr.push_back(Point2(11,7)-sb);
ps->shape_set_data(convex_polygon_shape,arr);
- body_shape_data[Physics2DServer::SHAPE_CONVEX_POLYGON].shape = convex_polygon_shape;
+ body_shape_data[Physics2DServer::SHAPE_CUSTOM+1].shape = convex_polygon_shape;
}
diff --git a/bin/tests/test_physics_2d.h b/bin/tests/test_physics_2d.h
index 184c6973a8..eadd5ebcb4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_python.cpp b/bin/tests/test_python.cpp
index 0b2bac492c..a89e4a7eee 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_python.h b/bin/tests/test_python.h
index 781be1c0ce..9dafbd545d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_render.cpp b/bin/tests/test_render.cpp
index cad3658d84..97a52b16c1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,6 +33,8 @@
#include "print_string.h"
#include "os/os.h"
#include "quick_hull.h"
+#include "os/keyboard.h"
+
#define OBJECT_COUNT 50
namespace TestRender {
@@ -59,10 +61,14 @@ class TestMainLoop : public MainLoop {
float ofs;
bool quit;
+protected:
+
+
public:
virtual void input_event(const InputEvent& p_event) {
-
+ if (p_event.type==InputEvent::KEY && p_event.key.pressed)
+ quit=true;
}
virtual void init() {
diff --git a/bin/tests/test_render.h b/bin/tests/test_render.h
index d5d140a090..dc71a32978 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_shader_lang.cpp b/bin/tests/test_shader_lang.cpp
index 059781b64c..df826e489d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_shader_lang.h b/bin/tests/test_shader_lang.h
index a12b45293d..85d379bc43 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_sound.cpp b/bin/tests/test_sound.cpp
index 40800f6fa5..63c6edd9c9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/bin/tests/test_sound.h b/bin/tests/test_sound.h
index fd0dd7a621..32b66c8bba 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,15 +26,15 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TEST_SOUND_H
-#define TEST_SOUND_H
-
-#include "os/main_loop.h"
-
-namespace TestSound {
-
-MainLoop* test();
-
-}
-
-#endif // TEST_SOUND_H
+#ifndef TEST_SOUND_H
+#define TEST_SOUND_H
+
+#include "os/main_loop.h"
+
+namespace TestSound {
+
+MainLoop* test();
+
+}
+
+#endif // TEST_SOUND_H
diff --git a/bin/tests/test_string.cpp b/bin/tests/test_string.cpp
index 66238b066d..93b1835b78 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 {
@@ -487,7 +483,7 @@ struct test_27_data {
bool test_27() {
- OS::get_singleton()->print("\n\nTest 26: begins_with\n");
+ OS::get_singleton()->print("\n\nTest 27: begins_with\n");
test_27_data tc[] = {
{"res://foobar", "res://", true},
{"res", "res://", false},
@@ -504,11 +500,349 @@ bool test_27() {
}
if (!state) {
OS::get_singleton()->print("\n\t Failure on:\n\t\tstring: ", tc[i].data, "\n\t\tbegin: ", tc[i].begin, "\n\t\texpected: ", tc[i].expected ? "true" : "false", "\n");
+ break;
}
};
return state;
};
+
+bool test_28() {
+
+ OS::get_singleton()->print("\n\nTest 28: sprintf\n");
+
+ bool success, state = true;
+ char output_format[] = "\tTest:\t%ls => %ls (%s)\n";
+ String format, output;
+ Array args;
+ bool error;
+
+ // %%
+ format = "fish %% frog";
+ args.clear();
+ output = format.sprintf(args, &error);
+ success = (output == String("fish % frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ //////// INTS
+
+ // Int
+ format = "fish %d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int left padded with zeroes.
+ format = "fish %05d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 00005 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int left padded with spaces.
+ format = "fish %5d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int right padded with spaces.
+ format = "fish %-5d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int with sign (positive).
+ format = "fish %+d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish +5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Negative int.
+ format = "fish %d frog";
+ args.clear();
+ args.push_back(-5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish -5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Hex (lower)
+ format = "fish %x frog";
+ args.clear();
+ args.push_back(45);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 2d frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Hex (upper)
+ format = "fish %X frog";
+ args.clear();
+ args.push_back(45);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 2D frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Octal
+ format = "fish %o frog";
+ args.clear();
+ args.push_back(99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 143 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ////// REALS
+
+ // Real
+ format = "fish %f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real left-padded
+ format = "fish %11f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real right-padded
+ format = "fish %-11f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real given int.
+ format = "fish %f frog";
+ args.clear();
+ args.push_back(99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.000000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real with sign (positive).
+ format = "fish %+f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish +99.990000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real with 1 decimals.
+ format = "fish %.1f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 100.0 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real with 12 decimals.
+ format = "fish %.12f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990000000000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real with no decimals.
+ format = "fish %.f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 100 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ /////// Strings.
+
+ // String
+ format = "fish %s frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish cheese frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // String left-padded
+ format = "fish %10s frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish cheese frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // String right-padded
+ format = "fish %-10s frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish cheese frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ///// Characters
+
+ // Character as string.
+ format = "fish %c frog";
+ args.clear();
+ args.push_back("A");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish A frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Character as int.
+ format = "fish %c frog";
+ args.clear();
+ args.push_back(65);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish A frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ///// Dynamic width
+
+ // String dynamic width
+ format = "fish %*s frog";
+ args.clear();
+ args.push_back(10);
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish cheese frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int dynamic width
+ format = "fish %*d frog";
+ args.clear();
+ args.push_back(10);
+ args.push_back(99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Float dynamic width
+ format = "fish %*.*f frog";
+ args.clear();
+ args.push_back(10);
+ args.push_back(3);
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ///// Errors
+
+ // More formats than arguments.
+ format = "fish %s %s frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == "not enough arguments for format string" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // More arguments than formats.
+ format = "fish %s frog";
+ args.clear();
+ args.push_back("hello");
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == "not all arguments converted during string formatting" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Incomplete format.
+ format = "fish %10";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == "incomplete format" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Bad character in format string
+ format = "fish %&f frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == "unsupported format character" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Too many decimals.
+ format = "fish %2.2.2f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == "too many decimal points in format" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // * not a number
+ format = "fish %*f frog";
+ args.clear();
+ args.push_back("cheese");
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == "* wants number" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Character too long.
+ format = "fish %c frog";
+ args.clear();
+ args.push_back("sc");
+ output = format.sprintf(args, &error);
+ success = (output == "%c requires number or single-character string" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Character bad type.
+ format = "fish %c frog";
+ args.clear();
+ args.push_back(Array());
+ output = format.sprintf(args, &error);
+ success = (output == "%c requires number or single-character string" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ return state;
+}
+
typedef bool (*TestFunc)(void);
TestFunc test_funcs[] = {
@@ -540,6 +874,7 @@ TestFunc test_funcs[] = {
test_25,
test_26,
test_27,
+ test_28,
0
};
diff --git a/bin/tests/test_string.h b/bin/tests/test_string.h
index 31cef60014..b04eccb005 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/SCsub b/core/SCsub
index 7eace22b73..4ce91c794f 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -53,15 +53,13 @@ env.add_source_files(env.core_sources,"*.cpp")
Export('env')
import make_binders
-env.Command('method_bind.inc', 'make_binders.py', make_binders.run)
+env.Command(['method_bind.inc','method_bind_ext.inc'], 'make_binders.py', make_binders.run)
SConscript('os/SCsub');
SConscript('math/SCsub');
SConscript('io/SCsub');
SConscript('bind/SCsub');
-lib = env.Library("core",env.core_sources, LIBSUFFIX=env['platform_libsuffix'])
+lib = env.Library("core",env.core_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/core/allocators.h b/core/allocators.h
index 42eb4effaf..16e516e87b 100644
--- a/core/allocators.h
+++ b/core/allocators.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/array.cpp b/core/array.cpp
index 728ea5941c..ab9f19d6a0 100644
--- a/core/array.cpp
+++ b/core/array.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/array.h b/core/array.h
index 0b8240558f..904309b257 100644
--- a/core/array.h
+++ b/core/array.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/balloon_allocator.h b/core/balloon_allocator.h
index d99f805f52..177c744669 100644
--- a/core/balloon_allocator.h
+++ b/core/balloon_allocator.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 64b31d6fdd..94557d149d 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -5,16 +5,16 @@
#include "io/base64.h"
#include "core/globals.h"
#include "io/file_access_encrypted.h"
-
+#include "os/keyboard.h"
_ResourceLoader *_ResourceLoader::singleton=NULL;
Ref<ResourceInteractiveLoader> _ResourceLoader::load_interactive(const String& p_path,const String& p_type_hint) {
return ResourceLoader::load_interactive(p_path,p_type_hint);
}
-RES _ResourceLoader::load(const String &p_path,const String& p_type_hint) {
+RES _ResourceLoader::load(const String &p_path,const String& p_type_hint, bool p_no_cache) {
- RES ret = ResourceLoader::load(p_path,p_type_hint);
+ RES ret = ResourceLoader::load(p_path,p_type_hint, p_no_cache);
return ret;
}
@@ -59,7 +59,7 @@ void _ResourceLoader::_bind_methods() {
ObjectTypeDB::bind_method(_MD("load_interactive:ResourceInteractiveLoader","path","type_hint"),&_ResourceLoader::load_interactive,DEFVAL(""));
- ObjectTypeDB::bind_method(_MD("load:Resource","path","type_hint"),&_ResourceLoader::load,DEFVAL(""));
+ 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);
@@ -176,12 +176,86 @@ bool _OS::is_video_mode_fullscreen(int p_screen) const {
}
+
+int _OS::get_screen_count() const {
+ return OS::get_singleton()->get_screen_count();
+}
+
+int _OS::get_current_screen() const {
+ return OS::get_singleton()->get_current_screen();
+}
+
+void _OS::set_current_screen(int p_screen) {
+ OS::get_singleton()->set_current_screen(p_screen);
+}
+
+Point2 _OS::get_screen_position(int p_screen) const {
+ return OS::get_singleton()->get_screen_position(p_screen);
+}
+
+Size2 _OS::get_screen_size(int p_screen) const {
+ return OS::get_singleton()->get_screen_size(p_screen);
+}
+
+Point2 _OS::get_window_position() const {
+ return OS::get_singleton()->get_window_position();
+}
+
+void _OS::set_window_position(const Point2& p_position) {
+ OS::get_singleton()->set_window_position(p_position);
+}
+
+Size2 _OS::get_window_size() const {
+ return OS::get_singleton()->get_window_size();
+}
+
+void _OS::set_window_size(const Size2& p_size) {
+ OS::get_singleton()->set_window_size(p_size);
+}
+
+void _OS::set_window_fullscreen(bool p_enabled) {
+ OS::get_singleton()->set_window_fullscreen(p_enabled);
+}
+
+bool _OS::is_window_fullscreen() const {
+ return OS::get_singleton()->is_window_fullscreen();
+}
+
+void _OS::set_window_resizable(bool p_enabled) {
+ OS::get_singleton()->set_window_resizable(p_enabled);
+}
+
+bool _OS::is_window_resizable() const {
+ return OS::get_singleton()->is_window_resizable();
+}
+
+void _OS::set_window_minimized(bool p_enabled) {
+ OS::get_singleton()->set_window_minimized(p_enabled);
+}
+
+bool _OS::is_window_minimized() const {
+ return OS::get_singleton()->is_window_minimized();
+}
+
+void _OS::set_window_maximized(bool p_enabled) {
+ OS::get_singleton()->set_window_maximized(p_enabled);
+}
+
+bool _OS::is_window_maximized() const {
+ return OS::get_singleton()->is_window_maximized();
+}
+
+
+void _OS::set_use_file_access_save_and_swap(bool p_enable) {
+
+ FileAccess::set_backup_save(p_enable);
+}
+
bool _OS::is_video_mode_resizable(int p_screen) const {
OS::VideoMode vm;
vm = OS::get_singleton()->get_video_mode(p_screen);
return vm.resizable;
-
}
Array _OS::get_fullscreen_mode_list(int p_screen) const {
@@ -301,6 +375,21 @@ MainLoop *_OS::get_main_loop() const {
return OS::get_singleton()->get_main_loop();
}
+
+void _OS::set_time_scale(float p_scale) {
+ OS::get_singleton()->set_time_scale(p_scale);
+}
+
+float _OS::get_time_scale() {
+
+ return OS::get_singleton()->get_time_scale();
+}
+
+bool _OS::is_ok_left_and_cancel_right() const {
+
+ return OS::get_singleton()->get_swap_ok_cancel();
+}
+
/*
enum Weekday {
DAY_SUNDAY,
@@ -368,9 +457,9 @@ void _OS::set_icon(const Image& p_icon) {
OS::get_singleton()->set_icon(p_icon);
}
-Dictionary _OS::get_date() const {
+Dictionary _OS::get_date(bool utc) const {
- OS::Date date = OS::get_singleton()->get_date();
+ OS::Date date = OS::get_singleton()->get_date(utc);
Dictionary dated;
dated["year"]=date.year;
dated["month"]=date.month;
@@ -381,9 +470,9 @@ Dictionary _OS::get_date() const {
}
-Dictionary _OS::get_time() const {
+Dictionary _OS::get_time(bool utc) const {
- OS::Time time = OS::get_singleton()->get_time();
+ OS::Time time = OS::get_singleton()->get_time(utc);
Dictionary timed;
timed["hour"]=time.hour;
timed["minute"]=time.min;
@@ -391,11 +480,24 @@ Dictionary _OS::get_time() const {
return timed;
}
+
+Dictionary _OS::get_time_zone_info() const {
+ OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info();
+ Dictionary infod;
+ infod["bias"] = info.bias;
+ infod["name"] = info.name;
+ return infod;
+}
+
uint64_t _OS::get_unix_time() const {
return OS::get_singleton()->get_unix_time();
};
+uint64_t _OS::get_system_time_msec() const {
+ return OS::get_singleton()->get_system_time_msec();
+}
+
void _OS::delay_usec(uint32_t p_usec) const {
OS::get_singleton()->delay_usec(p_usec);
@@ -411,6 +513,10 @@ uint32_t _OS::get_ticks_msec() const {
return OS::get_singleton()->get_ticks_msec();
}
+uint32_t _OS::get_splash_tick_msec() const {
+
+ return OS::get_singleton()->get_splash_tick_msec();
+}
bool _OS::can_use_threads() const {
@@ -562,9 +668,9 @@ float _OS::get_frames_per_second() const {
return OS::get_singleton()->get_frames_per_second();
}
-Error _OS::native_video_play(String p_path, float p_volume) {
+Error _OS::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
- return OS::get_singleton()->native_video_play(p_path, p_volume);
+ return OS::get_singleton()->native_video_play(p_path, p_volume, p_audio_track, p_subtitle_track);
};
bool _OS::native_video_is_playing() {
@@ -582,11 +688,55 @@ void _OS::native_video_stop() {
OS::get_singleton()->native_video_stop();
};
+bool _OS::is_debug_build() const {
+
+#ifdef DEBUG_ENABLED
+ return true;
+#else
+ return false;
+#endif
+
+}
+
+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());
+}
+
+
+String _OS::get_system_dir(SystemDir p_dir) const {
+
+ return OS::get_singleton()->get_system_dir(OS::SystemDir(p_dir));
+}
String _OS::get_custom_level() const {
return OS::get_singleton()->get_custom_level();
}
+
+String _OS::get_scancode_string(uint32_t p_code) const {
+
+ return keycode_get_string(p_code);
+}
+bool _OS::is_scancode_unicode(uint32_t p_unicode) const {
+
+ return keycode_has_unicode(p_unicode);
+}
+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() {
@@ -603,14 +753,40 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_video_mode_resizable","screen"),&_OS::is_video_mode_resizable,DEFVAL(0));
ObjectTypeDB::bind_method(_MD("get_fullscreen_mode_list","screen"),&_OS::get_fullscreen_mode_list,DEFVAL(0));
+
+ ObjectTypeDB::bind_method(_MD("get_screen_count"),&_OS::get_screen_count);
+ ObjectTypeDB::bind_method(_MD("get_current_screen"),&_OS::get_current_screen);
+ ObjectTypeDB::bind_method(_MD("set_current_screen","screen"),&_OS::set_current_screen);
+ ObjectTypeDB::bind_method(_MD("get_screen_position","screen"),&_OS::get_screen_position,DEFVAL(0));
+ ObjectTypeDB::bind_method(_MD("get_screen_size","screen"),&_OS::get_screen_size,DEFVAL(0));
+ ObjectTypeDB::bind_method(_MD("get_window_position"),&_OS::get_window_position);
+ ObjectTypeDB::bind_method(_MD("set_window_position","position"),&_OS::set_window_position);
+ ObjectTypeDB::bind_method(_MD("get_window_size"),&_OS::get_window_size);
+ ObjectTypeDB::bind_method(_MD("set_window_size","size"),&_OS::set_window_size);
+ ObjectTypeDB::bind_method(_MD("set_window_fullscreen","enabled"),&_OS::set_window_fullscreen);
+ ObjectTypeDB::bind_method(_MD("is_window_fullscreen"),&_OS::is_window_fullscreen);
+ ObjectTypeDB::bind_method(_MD("set_window_resizable","enabled"),&_OS::set_window_resizable);
+ ObjectTypeDB::bind_method(_MD("is_window_resizable"),&_OS::is_window_resizable);
+ ObjectTypeDB::bind_method(_MD("set_window_minimized", "enabled"),&_OS::set_window_minimized);
+ ObjectTypeDB::bind_method(_MD("is_window_minimized"),&_OS::is_window_minimized);
+ 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_iterations_per_second","iterations_per_second"),&_OS::set_iterations_per_second);
ObjectTypeDB::bind_method(_MD("get_iterations_per_second"),&_OS::get_iterations_per_second);
ObjectTypeDB::bind_method(_MD("set_target_fps","target_fps"),&_OS::set_target_fps);
ObjectTypeDB::bind_method(_MD("get_target_fps"),&_OS::get_target_fps);
- ObjectTypeDB::bind_method(_MD("has_touchscreen_ui_hint"),&_OS::has_touchscreen_ui_hint);
+ ObjectTypeDB::bind_method(_MD("set_time_scale","time_scale"),&_OS::set_time_scale);
+ ObjectTypeDB::bind_method(_MD("get_time_scale"),&_OS::get_time_scale);
+ ObjectTypeDB::bind_method(_MD("has_touchscreen_ui_hint"),&_OS::has_touchscreen_ui_hint);
+ ObjectTypeDB::bind_method(_MD("set_window_title","title"),&_OS::set_window_title);
ObjectTypeDB::bind_method(_MD("set_low_processor_usage_mode","enable"),&_OS::set_low_processor_usage_mode);
ObjectTypeDB::bind_method(_MD("is_in_low_processor_usage_mode"),&_OS::is_in_low_processor_usage_mode);
@@ -630,15 +806,18 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_cmdline_args"),&_OS::get_cmdline_args);
ObjectTypeDB::bind_method(_MD("get_main_loop"),&_OS::get_main_loop);
- ObjectTypeDB::bind_method(_MD("get_date"),&_OS::get_date);
- ObjectTypeDB::bind_method(_MD("get_time"),&_OS::get_time);
+ ObjectTypeDB::bind_method(_MD("get_date","utc"),&_OS::get_date,DEFVAL(false));
+ 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_msec"), &_OS::get_system_time_msec);
ObjectTypeDB::bind_method(_MD("set_icon"),&_OS::set_icon);
ObjectTypeDB::bind_method(_MD("delay_usec","usec"),&_OS::delay_usec);
ObjectTypeDB::bind_method(_MD("delay_msec","msec"),&_OS::delay_msec);
ObjectTypeDB::bind_method(_MD("get_ticks_msec"),&_OS::get_ticks_msec);
+ ObjectTypeDB::bind_method(_MD("get_splash_tick_msec"),&_OS::get_splash_tick_msec);
ObjectTypeDB::bind_method(_MD("get_locale"),&_OS::get_locale);
ObjectTypeDB::bind_method(_MD("get_model_name"),&_OS::get_model_name);
@@ -650,6 +829,8 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("can_use_threads"),&_OS::can_use_threads);
+ ObjectTypeDB::bind_method(_MD("is_debug_build"),&_OS::is_debug_build);
+
//ObjectTypeDB::bind_method(_MD("get_mouse_button_state"),&_OS::get_mouse_button_state);
ObjectTypeDB::bind_method(_MD("dump_memory_to_file","file"),&_OS::dump_memory_to_file);
@@ -662,8 +843,11 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_dynamic_memory_usage"),&_OS::get_dynamic_memory_usage);
ObjectTypeDB::bind_method(_MD("get_data_dir"),&_OS::get_data_dir);
+ ObjectTypeDB::bind_method(_MD("get_system_dir","dir"),&_OS::get_system_dir);
ObjectTypeDB::bind_method(_MD("get_unique_ID"),&_OS::get_unique_ID);
+ ObjectTypeDB::bind_method(_MD("is_ok_left_and_cancel_right"),&_OS::is_ok_left_and_cancel_right);
+
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);
@@ -674,6 +858,14 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("native_video_stop"),&_OS::native_video_stop);
ObjectTypeDB::bind_method(_MD("native_video_pause"),&_OS::native_video_pause);
+ ObjectTypeDB::bind_method(_MD("get_scancode_string","code"),&_OS::get_scancode_string);
+ ObjectTypeDB::bind_method(_MD("is_scancode_unicode","code"),&_OS::is_scancode_unicode);
+ ObjectTypeDB::bind_method(_MD("find_scancode_from_string","string"),&_OS::find_scancode_from_string);
+
+ 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 );
BIND_CONSTANT( DAY_MONDAY );
@@ -696,6 +888,22 @@ 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 );
+ BIND_CONSTANT( SYSTEM_DIR_DOWNLOADS );
+ BIND_CONSTANT( SYSTEM_DIR_MOVIES );
+ BIND_CONSTANT( SYSTEM_DIR_MUSIC );
+ BIND_CONSTANT( SYSTEM_DIR_PICTURES );
+ BIND_CONSTANT( SYSTEM_DIR_RINGTONES );
}
@@ -791,6 +999,12 @@ Variant _Geometry::segment_intersects_triangle( const Vector3& p_from, const Vec
return Variant();
}
+
+bool _Geometry::point_is_inside_triangle(const Vector2& s, const Vector2& a, const Vector2& b, const Vector2& c) const {
+
+ return Geometry::is_point_in_triangle(s,a,b,c);
+}
+
DVector<Vector3> _Geometry::segment_intersects_sphere( const Vector3& p_from, const Vector3& p_to, const Vector3& p_sphere_pos,real_t p_sphere_radius) {
DVector<Vector3> r;
@@ -834,6 +1048,42 @@ Vector<int> _Geometry::triangulate_polygon(const Vector<Vector2>& p_polygon) {
return Geometry::triangulate_polygon(p_polygon);
}
+Dictionary _Geometry::make_atlas(const Vector<Size2>& p_rects) {
+
+ Dictionary ret;
+
+ Vector<Size2i> rects;
+ for (int i=0; i<p_rects.size(); i++) {
+
+ rects.push_back(p_rects[i]);
+ };
+
+ Vector<Point2i> result;
+ Size2i size;
+
+ Geometry::make_atlas(rects, result, size);
+
+ Size2 r_size = size;
+ Vector<Point2> r_result;
+ for (int i=0; i<result.size(); i++) {
+
+ r_result.push_back(result[i]);
+ };
+
+
+ ret["points"] = r_result;
+ ret["size"] = r_size;
+
+ return ret;
+};
+
+
+int _Geometry::get_uv84_normal_bit(const Vector3& p_vector) {
+
+ return Geometry::get_uv84_normal_bit(p_vector);
+}
+
+
void _Geometry::_bind_methods() {
@@ -848,14 +1098,18 @@ void _Geometry::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_closest_point_to_segment","point","s1","s2"),&_Geometry::get_closest_point_to_segment);
+ ObjectTypeDB::bind_method(_MD("get_uv84_normal_bit","normal"),&_Geometry::get_uv84_normal_bit);
+
ObjectTypeDB::bind_method(_MD("ray_intersects_triangle","from","dir","a","b","c"),&_Geometry::ray_intersects_triangle);
ObjectTypeDB::bind_method(_MD("segment_intersects_triangle","from","to","a","b","c"),&_Geometry::segment_intersects_triangle);
ObjectTypeDB::bind_method(_MD("segment_intersects_sphere","from","to","spos","sradius"),&_Geometry::segment_intersects_sphere);
ObjectTypeDB::bind_method(_MD("segment_intersects_cylinder","from","to","height","radius"),&_Geometry::segment_intersects_cylinder);
ObjectTypeDB::bind_method(_MD("segment_intersects_convex","from","to","planes"),&_Geometry::segment_intersects_convex);
+ ObjectTypeDB::bind_method(_MD("point_is_inside_triangle","point","a","b","c"),&_Geometry::point_is_inside_triangle);
ObjectTypeDB::bind_method(_MD("triangulate_polygon","polygon"),&_Geometry::triangulate_polygon);
+ ObjectTypeDB::bind_method(_MD("make_atlas","sizes"),&_Geometry::make_atlas);
}
@@ -1035,6 +1289,7 @@ String _File::get_as_text() const {
text+=l+"\n";
l = get_line();
}
+ text+=l;
return text;
@@ -1456,12 +1711,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);
+
};
@@ -1545,9 +1877,12 @@ _Mutex::~_Mutex(){
void _Thread::_start_func(void *ud) {
- _Thread *t=(_Thread*)ud;
+ Ref<_Thread>* tud=(Ref<_Thread>*)ud;
+ Ref<_Thread> t=*tud;
+ memdelete(tud);
Variant::CallError ce;
const Variant* arg[1]={&t->userdata};
+
t->ret=t->target_instance->call(t->target_method,arg,1,ce);
if (ce.error!=Variant::CallError::CALL_OK) {
@@ -1572,6 +1907,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();
}
@@ -1592,9 +1928,11 @@ Error _Thread::start(Object *p_instance,const StringName& p_method,const Variant
userdata=p_userdata;
active=true;
+ Ref<_Thread> *ud = memnew( Ref<_Thread>(this) );
+
Thread::Settings s;
s.priority=(Thread::Priority)p_priority;
- thread = Thread::create(_start_func,this,s);
+ thread = Thread::create(_start_func,ud,s);
if (!thread) {
active=false;
target_method=StringName();
@@ -1655,5 +1993,8 @@ _Thread::_Thread() {
_Thread::~_Thread() {
+ if (active) {
+ ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running..");
+ }
ERR_FAIL_COND(active==true);
}
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 20a33fa013..24ea810767 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -21,7 +21,7 @@ public:
static _ResourceLoader *get_singleton() { return singleton; }
Ref<ResourceInteractiveLoader> load_interactive(const String& p_path,const String& p_type_hint="");
- RES load(const String &p_path,const String& p_type_hint="");
+ RES load(const String &p_path,const String& p_type_hint="", bool p_no_cache = false);
DVector<String> get_recognized_extensions_for_type(const String& p_type);
void set_abort_on_missing_resources(bool p_abort);
StringArray get_dependencies(const String& p_path);
@@ -108,7 +108,27 @@ public:
bool is_video_mode_resizable(int p_screen=0) const;
Array get_fullscreen_mode_list(int p_screen=0) const;
- Error native_video_play(String p_path, float p_volume);
+
+ 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 Point2 get_window_position() const;
+ virtual void set_window_position(const Point2& p_position);
+ virtual Size2 get_window_size() const;
+ virtual void set_window_size(const Size2& p_size);
+ 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;
+
+
+ Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
bool native_video_is_playing();
void native_video_pause();
void native_video_stop();
@@ -154,8 +174,15 @@ public:
bool has_touchscreen_ui_hint() const;
+ bool is_debug_build() const;
+
String get_unique_ID() const;
+ String get_scancode_string(uint32_t p_code) const;
+ bool is_scancode_unicode(uint32_t p_unicode) const;
+ int find_scancode_from_string(const String& p_code) const;
+
+
/*
struct Date {
@@ -174,11 +201,14 @@ public:
};
*/
+ void set_use_file_access_save_and_swap(bool p_enable);
void set_icon(const Image& p_icon);
- Dictionary get_date() const;
- Dictionary get_time() const;
+ Dictionary get_date(bool utc) const;
+ Dictionary get_time(bool utc) const;
+ Dictionary get_time_zone_info() const;
uint64_t get_unix_time() const;
+ uint64_t get_system_time_msec() const;
int get_static_memory_usage() const;
int get_static_memory_peak_usage() const;
@@ -187,6 +217,7 @@ public:
void delay_usec(uint32_t p_usec) const;
void delay_msec(uint32_t p_msec) const;
uint32_t get_ticks_msec() const;
+ uint32_t get_splash_tick_msec() const;
bool can_use_threads() const;
@@ -198,13 +229,53 @@ public:
int get_processor_count() const;
+ enum SystemDir {
+ SYSTEM_DIR_DESKTOP,
+ SYSTEM_DIR_DCIM,
+ SYSTEM_DIR_DOCUMENTS,
+ SYSTEM_DIR_DOWNLOADS,
+ SYSTEM_DIR_MOVIES,
+ SYSTEM_DIR_MUSIC,
+ SYSTEM_DIR_PICTURES,
+ 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_time_scale(float p_scale);
+ float get_time_scale();
+
+ bool is_ok_left_and_cancel_right() const;
+
static _OS *get_singleton() { return singleton; }
_OS();
};
+VARIANT_ENUM_CAST(_OS::SystemDir);
+VARIANT_ENUM_CAST(_OS::ScreenOrientation);
+
+
class _Geometry : public Object {
OBJ_TYPE(_Geometry, Object);
@@ -225,13 +296,18 @@ public:
Vector3 get_closest_point_to_segment(const Vector3& p_point, const Vector3& p_a,const Vector3& p_b);
Variant ray_intersects_triangle( const Vector3& p_from, const Vector3& p_dir, const Vector3& p_v0,const Vector3& p_v1,const Vector3& p_v2);
Variant segment_intersects_triangle( const Vector3& p_from, const Vector3& p_to, const Vector3& p_v0,const Vector3& p_v1,const Vector3& p_v2);
+ bool point_is_inside_triangle(const Vector2& s, const Vector2& a, const Vector2& b, const Vector2& c) const;
+
DVector<Vector3> segment_intersects_sphere( const Vector3& p_from, const Vector3& p_to, const Vector3& p_sphere_pos,real_t p_sphere_radius);
DVector<Vector3> segment_intersects_cylinder( const Vector3& p_from, const Vector3& p_to, float p_height,float p_radius);
DVector<Vector3> segment_intersects_convex(const Vector3& p_from, const Vector3& p_to,const Vector<Plane>& p_planes);
real_t segment_intersects_circle(const Vector2& p_from, const Vector2& p_to, const Vector2& p_circle_pos, real_t p_circle_radius);
+ int get_uv84_normal_bit(const Vector3& p_vector);
Vector<int> triangulate_polygon(const Vector<Vector2>& p_polygon);
+ Dictionary make_atlas(const Vector<Size2>& p_rects);
+
_Geometry();
};
@@ -379,6 +455,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() {};
};
diff --git a/core/color.cpp b/core/color.cpp
index 1528db6aaa..32f3df6d4b 100644
--- a/core/color.cpp
+++ b/core/color.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -161,7 +161,7 @@ void Color::invert() {
r=1.0-r;
g=1.0-g;
- g=1.0-b;
+ b=1.0-b;
}
void Color::contrast() {
@@ -225,7 +225,7 @@ Color Color::inverted() const {
Color Color::contrasted() const {
Color c=*this;
- c.contrasted();
+ c.contrast();
return c;
}
diff --git a/core/color.h b/core/color.h
index 491c72d449..d5d5a4ea09 100644
--- a/core/color.h
+++ b/core/color.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/command_queue_mt.cpp b/core/command_queue_mt.cpp
index 78151b858f..f28617b33c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h
index 8b74b3b561..113199869b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,6 +34,7 @@
#include "os/mutex.h"
#include "os/memory.h"
#include "simple_type.h"
+#include "print_string.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -174,7 +175,7 @@ class CommandQueueMT {
R* ret;
SyncSemaphore *sync;
- virtual void call() { *ret = (instance->*method)(p1); sync->sem->post(); sync->in_use=false; ; }
+ virtual void call() { *ret = (instance->*method)(p1); sync->sem->post(); print_line("post"); sync->in_use=false; ; }
};
template<class T,class M,class P1,class P2,class R>
@@ -675,6 +676,7 @@ public:
if (sync) sync->post();
ss->sem->wait();
+ print_line("wait");
}
template<class T, class M, class P1, class P2,class R>
diff --git a/core/compressed_translation.cpp b/core/compressed_translation.cpp
index 0c97f459f8..45fd4b5080 100644
--- a/core/compressed_translation.cpp
+++ b/core/compressed_translation.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/compressed_translation.h b/core/compressed_translation.h
index a0b94116de..c41e2afb53 100644
--- a/core/compressed_translation.h
+++ b/core/compressed_translation.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 75cb48137b..d0cd19768f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -42,6 +42,7 @@ CoreStringNames::CoreStringNames() {
_iter_init=StaticCString::create("_iter_init");
_iter_next=StaticCString::create("_iter_next");
_iter_get=StaticCString::create("_iter_get");
+ get_rid=StaticCString::create("get_rid");
}
diff --git a/core/core_string_names.h b/core/core_string_names.h
index e2982acc1a..8bda1f3f79 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,6 +56,7 @@ public:
StringName _iter_init;
StringName _iter_next;
StringName _iter_get;
+ StringName get_rid;
};
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index 16ee397382..b2d31f230d 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -186,10 +186,12 @@ Error Dictionary::parse_json(const String& p_json) {
String errstr;
int errline=0;
+ if (p_json != ""){
Error err = JSON::parse(p_json,*this,errstr,errline);
if (err!=OK) {
ERR_EXPLAIN("Error parsing JSON: "+errstr+" at line: "+itos(errline));
ERR_FAIL_COND_V(err!=OK,err);
+ }
}
return OK;
diff --git a/core/dictionary.h b/core/dictionary.h
index de5be0fc6b..8cbabfc65d 100644
--- a/core/dictionary.h
+++ b/core/dictionary.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/dvector.cpp b/core/dvector.cpp
index e0a378a427..60aa2e079f 100644
--- a/core/dvector.cpp
+++ b/core/dvector.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/dvector.h b/core/dvector.h
index 72661882cd..2c75bbf9eb 100644
--- a/core/dvector.h
+++ b/core/dvector.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -262,6 +262,23 @@ public:
w[bs+i]=r[i];
}
+
+ Error insert(int p_pos,const T& p_val) {
+
+ int s=size();
+ ERR_FAIL_INDEX_V(p_pos,s+1,ERR_INVALID_PARAMETER);
+ resize(s+1);
+ {
+ Write w = write();
+ for (int i=s;i>p_pos;i--)
+ w[i]=w[i-1];
+ w[p_pos]=p_val;
+ }
+
+ return OK;
+ }
+
+
bool is_locked() const { return mem.is_locked(); }
inline const T operator[](int p_index) const;
diff --git a/core/error_list.h b/core/error_list.h
index 2127938769..92c417154c 100644
--- a/core/error_list.h
+++ b/core/error_list.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 bd08cbb2f5..53bce56626 100644
--- a/core/error_macros.cpp
+++ b/core/error_macros.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/error_macros.h b/core/error_macros.h
index 6cd38755c0..cc88686301 100644
--- a/core/error_macros.h
+++ b/core/error_macros.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 cf6e742f79..1afd686f86 100644
--- a/core/event_queue.cpp
+++ b/core/event_queue.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,28 +56,36 @@ Error EventQueue::push_call(uint32_t p_instance_ID, const StringName& p_method,
buffer_end+=sizeof(Event);
- if (args==1) {
+ if (args>=1) {
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
buffer_end+=sizeof(Variant);
*v=p_arg1;
- } else if (args==2) {
+ }
+
+ if (args>=2) {
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
buffer_end+=sizeof(Variant);
*v=p_arg2;
- } else if (args==3) {
+ }
+
+ if (args>=3) {
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
buffer_end+=sizeof(Variant);
*v=p_arg3;
- } else if (args==4) {
+ }
+
+ if (args>=4) {
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
buffer_end+=sizeof(Variant);
*v=p_arg4;
- } else if (args==5) {
+ }
+
+ if (args>=5) {
Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
buffer_end+=sizeof(Variant);
diff --git a/core/event_queue.h b/core/event_queue.h
index 0647c02777..51ed7373eb 100644
--- a/core/event_queue.h
+++ b/core/event_queue.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/fpstr.cpp b/core/fpstr.cpp
index 25784adb15..20b527d88b 100644
--- a/core/fpstr.cpp
+++ b/core/fpstr.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/fpstr.h b/core/fpstr.h
index d07ae7d5a2..c8ff80806e 100644
--- a/core/fpstr.h
+++ b/core/fpstr.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 efa72b6547..9fb45c672a 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -313,6 +313,7 @@ static _GlobalConstant _global_constants[]={
BIND_GLOBAL_CONSTANT( KEY_MASK_ALT ),
BIND_GLOBAL_CONSTANT( KEY_MASK_META ),
BIND_GLOBAL_CONSTANT( KEY_MASK_CTRL ),
+ BIND_GLOBAL_CONSTANT( KEY_MASK_CMD ),
BIND_GLOBAL_CONSTANT( KEY_MASK_KPAD ),
BIND_GLOBAL_CONSTANT( KEY_MASK_GROUP_SWITCH ),
@@ -421,6 +422,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 ),
@@ -445,15 +447,26 @@ static _GlobalConstant _global_constants[]={
BIND_GLOBAL_CONSTANT( ERR_BUG ), ///< a bug in the software certainly happened ), due to a double check failing or unexpected behavior.
BIND_GLOBAL_CONSTANT( ERR_WTF ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_NONE ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_RANGE ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_EXP_RANGE ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_ENUM ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_LENGTH ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_FLAGS ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_FILE ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_DIR ),
- BIND_GLOBAL_CONSTANT( PROPERTY_HINT_RESOURCE_TYPE ),
+
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_NONE ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_RANGE ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_EXP_RANGE ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_ENUM ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_EXP_EASING ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_LENGTH ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_KEY_ACCEL ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_FLAGS ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_ALL_FLAGS ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_FILE ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_DIR ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_GLOBAL_FILE ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_GLOBAL_DIR ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_RESOURCE_TYPE ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_MULTILINE_TEXT ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_COLOR_NO_ALPHA ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_IMAGE_COMPRESS_LOSSY ),
+ BIND_GLOBAL_CONSTANT( PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS ),
+
BIND_GLOBAL_CONSTANT( PROPERTY_USAGE_STORAGE ),
BIND_GLOBAL_CONSTANT( PROPERTY_USAGE_STORAGE ),
diff --git a/core/global_constants.h b/core/global_constants.h
index cd8304bd45..77cd3724c6 100644
--- a/core/global_constants.h
+++ b/core/global_constants.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/globals.cpp b/core/globals.cpp
index 3a04becef4..aee708d0cd 100644
--- a/core/globals.cpp
+++ b/core/globals.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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();
@@ -332,6 +332,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 +340,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")) {
+ if (first_time && (_load_resource_pack(current_dir+"/"+exec_name+".pck") || _load_resource_pack(current_dir+"/"+exec_name+".pcz") )) {
+ 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.pcz") )) {
if (_load_settings("res://engine.cfg")==OK || _load_settings_binary("res://engine.cfb")==OK) {
_load_settings("res://override.cfg");
@@ -566,9 +576,11 @@ static Variant _decode_variant(const String& p_string) {
ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant());
int scode=0;
- if (params[0].is_numeric())
+ if (params[0].is_numeric()) {
scode=params[0].to_int();
- else
+ if (scode<10)
+ scode+=KEY_0;
+ } else
scode=find_keycode(params[0]);
InputEvent ie;
@@ -672,7 +684,7 @@ static Variant _decode_variant(const String& p_string) {
int w=params[2].to_int();
int h=params[3].to_int();
- if (w == 0 && w == 0) {
+ if (w == 0 && h == 0) {
//r_v = Image(w, h, imgformat);
return Image();
};
@@ -1147,6 +1159,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);
@@ -1319,7 +1337,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,6 +1376,10 @@ void Globals::_bind_methods() {
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("save_custom"),&Globals::_save_custom_bnd);
+
}
Globals::Globals() {
@@ -1378,7 +1400,9 @@ Globals::Globals() {
set("application/name","" );
set("application/main_scene","");
- custom_prop_info["application/main_scene"]=PropertyInfo(Variant::STRING,"application/main_scene",PROPERTY_HINT_FILE,"xml,res,scn,xscn");
+ custom_prop_info["application/main_scene"]=PropertyInfo(Variant::STRING,"application/main_scene",PROPERTY_HINT_FILE,"scn,res,xscn,xml");
+ set("application/disable_stdout",false);
+ set("application/use_shared_user_dir",true);
key.key.scancode=KEY_RETURN;
@@ -1392,6 +1416,13 @@ Globals::Globals() {
set("input/ui_accept",va);
va=Array();
+ key.key.scancode=KEY_SPACE;
+ va.push_back(key);
+ joyb.joy_button.button_index=JOY_BUTTON_3;
+ va.push_back(joyb);
+ set("input/ui_select",va);
+
+ va=Array();
key.key.scancode=KEY_ESCAPE;
va.push_back(key);
joyb.joy_button.button_index=JOY_BUTTON_1;
@@ -1455,7 +1486,7 @@ Globals::Globals() {
custom_prop_info["display/orientation"]=PropertyInfo(Variant::STRING,"display/orientation",PROPERTY_HINT_ENUM,"landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
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");
- set("display/emulate_touchscreen",false);
+ custom_prop_info["physics_2d/thread_model"]=PropertyInfo(Variant::INT,"physics_2d/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded");
using_datapack=false;
}
diff --git a/core/globals.h b/core/globals.h
index 580fd0fecd..2ec56966f6 100644
--- a/core/globals.h
+++ b/core/globals.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -86,6 +86,7 @@ protected:
List<Singleton> singletons;
+ Error _save_custom_bnd(const String& p_file);
bool _load_resource_pack(const String& p_pack);
diff --git a/core/hash_map.h b/core/hash_map.h
index da8f038490..eea6d1a153 100644
--- a/core/hash_map.h
+++ b/core/hash_map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/hashfuncs.h b/core/hashfuncs.h
index 3b6715a4cd..b12950f160 100644
--- a/core/hashfuncs.h
+++ b/core/hashfuncs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/image.cpp b/core/image.cpp
index d9ba6c1594..eadb7ecc8b 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -35,6 +35,34 @@
#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) {
_put_pixelw(p_x,p_y,width,p_color,p_data);
@@ -133,6 +161,18 @@ void Image::get_mipmap_offset_and_size(int p_mipmap,int &r_ofs, int &r_size) con
}
+void Image::get_mipmap_offset_size_and_dimensions(int p_mipmap,int &r_ofs, int &r_size,int &w, int& h) const {
+
+
+ int ofs;
+ _get_mipmap_offset_and_size(p_mipmap,ofs,w,h);
+ int ofs2,w2,h2;
+ _get_mipmap_offset_and_size(p_mipmap+1,ofs2,w2,h2);
+ r_ofs=ofs;
+ r_size=ofs2-ofs;
+
+}
+
void Image::put_pixel(int p_x,int p_y, const Color& p_color,int p_mipmap){
ERR_FAIL_INDEX(p_mipmap,mipmaps+1);
@@ -282,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);
@@ -387,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) {
@@ -546,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;
+
}
@@ -1003,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);
@@ -1111,6 +1258,7 @@ void Image::create( const char ** p_xpm ) {
}
#define DETECT_ALPHA_MAX_TRESHOLD 254
#define DETECT_ALPHA_MIN_TRESHOLD 2
+
#define DETECT_ALPHA( m_value )\
{ \
uint8_t value=m_value;\
@@ -1123,6 +1271,82 @@ void Image::create( const char ** p_xpm ) {
}\
}
+#define DETECT_NON_ALPHA( m_value )\
+{ \
+ uint8_t value=m_value;\
+ if (value>0) {\
+ \
+ detected=true;\
+ break;\
+ }\
+}
+
+
+bool Image::is_invisible() const {
+
+ if (format==FORMAT_GRAYSCALE ||
+ format==FORMAT_RGB ||
+ format==FORMAT_INDEXED)
+ return false;
+
+ int len = data.size();
+
+ if (len==0)
+ return true;
+
+ if (format >= FORMAT_YUV_422 && format <= FORMAT_YUV_444)
+ return false;
+
+ int w,h;
+ _get_mipmap_offset_and_size(1,len,w,h);
+
+ DVector<uint8_t>::Read r = data.read();
+ const unsigned char *data_ptr=r.ptr();
+
+ bool detected=false;
+
+ switch(format) {
+ case FORMAT_INTENSITY: {
+
+ for(int i=0;i<len;i++) {
+ DETECT_NON_ALPHA(data_ptr[i]);
+ }
+ } break;
+ case FORMAT_GRAYSCALE_ALPHA: {
+
+
+ for(int i=0;i<(len>>1);i++) {
+ DETECT_NON_ALPHA(data_ptr[(i<<1)+1]);
+ }
+
+ } break;
+ case FORMAT_RGBA: {
+
+ for(int i=0;i<(len>>2);i++) {
+ DETECT_NON_ALPHA(data_ptr[(i<<2)+3])
+ }
+
+ } break;
+ case FORMAT_INDEXED: {
+
+ return false;
+ } break;
+ case FORMAT_INDEXED_ALPHA: {
+
+ return false;
+ } break;
+ case FORMAT_PVRTC2_ALPHA:
+ case FORMAT_PVRTC4_ALPHA:
+ case FORMAT_BC2:
+ case FORMAT_BC3: {
+ detected=true;
+ } break;
+ default: {}
+ }
+
+ return !detected;
+}
+
Image::AlphaMode Image::detect_alpha() const {
if (format==FORMAT_GRAYSCALE ||
@@ -1200,6 +1424,14 @@ Error Image::load(const String& p_path) {
return ImageLoader::load_image(p_path, this);
}
+Error Image::save_png(const String& p_path) {
+
+ if (save_png_func == NULL)
+ return ERR_UNAVAILABLE;
+
+ return save_png_func(p_path, *this);
+};
+
bool Image::operator==(const Image& p_image) const {
if (data.size() == 0 && p_image.data.size() == 0)
@@ -1725,6 +1957,10 @@ Error Image::_decompress_bc() {
return OK;
}
+bool Image::is_compressed() const {
+ return format>=FORMAT_BC1;
+}
+
Image Image::decompressed() const {
@@ -1977,7 +2213,7 @@ void Image::blit_rect(const Image& p_src, const Rect2& p_src_rect,const Point2&
}
-Image (*Image::_png_mem_loader_func)(const uint8_t*)=NULL;
+Image (*Image::_png_mem_loader_func)(const uint8_t*,int)=NULL;
void (*Image::_image_compress_bc_func)(Image *)=NULL;
void (*Image::_image_compress_pvrtc2_func)(Image *)=NULL;
void (*Image::_image_compress_pvrtc4_func)(Image *)=NULL;
@@ -1998,6 +2234,26 @@ void Image::set_compress_bc_func(void (*p_compress_func)(Image *)) {
+void Image::normalmap_to_xy() {
+
+ convert(Image::FORMAT_RGBA);
+
+ {
+ int len = data.size()/4;
+ DVector<uint8_t>::Write wp = data.write();
+ unsigned char *data_ptr=wp.ptr();
+
+ for(int i=0;i<len;i++) {
+
+ data_ptr[(i<<2)+3]=data_ptr[(i<<2)+0]; //x to w
+ data_ptr[(i<<2)+0]=data_ptr[(i<<2)+1]; //y to xz
+ data_ptr[(i<<2)+2]=data_ptr[(i<<2)+1];
+ }
+ }
+
+ convert(Image::FORMAT_GRAYSCALE_ALPHA);
+}
+
void Image::srgb_to_linear() {
if (data.size()==0)
@@ -2126,7 +2382,13 @@ void Image::fix_alpha_edges() {
}
-Image::Image(const uint8_t* p_png) {
+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;
height=0;
@@ -2134,7 +2396,7 @@ Image::Image(const uint8_t* p_png) {
format=FORMAT_GRAYSCALE;
if (_png_mem_loader_func) {
- *this = _png_mem_loader_func(p_png);
+ *this = _png_mem_loader_func(p_png,p_len);
}
}
diff --git a/core/image.h b/core/image.h
index 7a6ee1e4b0..a155823af7 100644
--- a/core/image.h
+++ b/core/image.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,7 +40,9 @@
* Images can be loaded from a file, or registered into the Render object as textures.
*/
+class Image;
+typedef Error (*SavePNGFunc)(const String &p_path, Image& p_img);
class Image {
@@ -50,6 +52,8 @@ class Image {
};
public:
+ static SavePNGFunc save_png_func;
+
enum Format {
FORMAT_GRAYSCALE, ///< one byte per pixel, 0-255
FORMAT_INTENSITY, ///< one byte per pixel, 0-255
@@ -83,14 +87,16 @@ public:
FORMAT_MAX
};
+ static const char* format_names[FORMAT_MAX];
enum Interpolation {
INTERPOLATE_NEAREST,
INTERPOLATE_BILINEAR,
+ INTERPOLATE_CUBIC,
/* INTERPOLATE GAUSS */
};
- static Image (*_png_mem_loader_func)(const uint8_t* p_png);
+ static Image (*_png_mem_loader_func)(const uint8_t* p_png,int p_size);
static void (*_image_compress_bc_func)(Image *);
static void (*_image_compress_pvrtc2_func)(Image *);
static void (*_image_compress_pvrtc4_func)(Image *);
@@ -216,6 +222,14 @@ public:
* Convert the image to another format, as close as it can be done.
*/
void convert( Format p_new_format );
+
+ Image converted(int p_new_format) {
+ ERR_FAIL_INDEX_V(p_new_format, FORMAT_MAX, Image());
+
+ Image ret = *this;
+ ret.convert((Format)p_new_format);
+ return ret;
+ };
/**
* Get the current image format.
@@ -224,6 +238,7 @@ public:
int get_mipmap_offset(int p_mipmap) const; //get where the mipmap begins in data
void get_mipmap_offset_and_size(int p_mipmap,int &r_ofs, int &r_size) const; //get where the mipmap begins in data
+ void get_mipmap_offset_size_and_dimensions(int p_mipmap,int &r_ofs, int &r_size,int &w, int& h) const; //get where the mipmap begins in data
/**
* Resize the image, using the prefered interpolation method.
@@ -270,6 +285,7 @@ public:
DVector<uint8_t> get_data() const;
Error load(const String& p_path);
+ Error save_png(const String& p_path);
/**
* create an empty image
@@ -291,6 +307,7 @@ public:
};
AlphaMode detect_alpha() const;
+ bool is_invisible() const;
void put_indexed_pixel(int p_x, int p_y, uint8_t p_idx,int p_mipmap=0);
uint8_t get_indexed_pixel(int p_x, int p_y,int p_mipmap=0) const;
@@ -321,10 +338,12 @@ public:
Image compressed(int p_mode); /* from the Image::CompressMode enum */
Error decompress();
Image decompressed() const;
+ bool is_compressed() const;
void fix_alpha_edges();
void premultiply_alpha();
void srgb_to_linear();
+ void normalmap_to_xy();
void blit_rect(const Image& p_src, const Rect2& p_src_rect,const Point2& p_dest);
void brush_transfer(const Image& p_src, const Image& p_brush, const Point2& p_dest);
@@ -334,7 +353,9 @@ public:
Image get_rect(const Rect2& p_area) const;
static void set_compress_bc_func(void (*p_compress_func)(Image *));
- Image(const uint8_t* p_mem_png);
+ 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 d728a32861..a14e0ab72e 100644
--- a/core/image_quantize.cpp
+++ b/core/image_quantize.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/input_map.cpp b/core/input_map.cpp
index 9426b0568e..24151c59c9 100644
--- a/core/input_map.cpp
+++ b/core/input_map.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -42,7 +42,7 @@ void InputMap::_bind_methods() {
ObjectTypeDB::bind_method(_MD("action_add_event","action","event"),&InputMap::action_add_event);
ObjectTypeDB::bind_method(_MD("action_has_event","action","event"),&InputMap::action_has_event);
ObjectTypeDB::bind_method(_MD("action_erase_event","action","event"),&InputMap::action_erase_event);
- ObjectTypeDB::bind_method(_MD("get_action_list","action"),&InputMap::get_action_list);
+ ObjectTypeDB::bind_method(_MD("get_action_list","action"),&InputMap::_get_action_list);
ObjectTypeDB::bind_method(_MD("event_is_action","event","action"),&InputMap::event_is_action);
ObjectTypeDB::bind_method(_MD("load_from_globals"),&InputMap::load_from_globals);
@@ -162,6 +162,22 @@ void InputMap::action_erase_event(const StringName& p_action,const InputEvent& p
}
+
+Array InputMap::_get_action_list(const StringName& p_action) {
+
+ Array ret;
+ const List<InputEvent> *al = get_action_list(p_action);
+ if (al) {
+ for(const List<InputEvent>::Element *E=al->front();E;E=E->next()) {
+
+ ret.push_back(E->get());;
+ }
+ }
+
+ return ret;
+
+}
+
const List<InputEvent> *InputMap::get_action_list(const StringName& p_action) {
const Map<StringName, Action>::Element *E=input_map.find(p_action);
@@ -176,7 +192,7 @@ bool InputMap::event_is_action(const InputEvent& p_event, const StringName& p_ac
Map<StringName,Action >::Element *E=input_map.find(p_action);
if(!E) {
- ERR_EXPLAIN("Request for unexisting InputMap action: "+String(p_action));
+ ERR_EXPLAIN("Request for nonexistent InputMap action: "+String(p_action));
ERR_FAIL_COND_V(!E,false);
}
diff --git a/core/input_map.h b/core/input_map.h
index bf20645b15..c5b21b1457 100644
--- a/core/input_map.h
+++ b/core/input_map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,6 +46,8 @@ class InputMap : public Object {
List<InputEvent>::Element *_find_event(List<InputEvent> &p_list,const InputEvent& p_event) const;
+ Array _get_action_list(const StringName& p_action);
+
protected:
static void _bind_methods();
diff --git a/core/int_types.h b/core/int_types.h
index 15ef68e915..231196b808 100644
--- a/core/int_types.h
+++ b/core/int_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -48,7 +48,7 @@ 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;
+typedef unsigned long long uint64_t;
#else
#include <stdint.h>
#endif
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 ea2f5d2d9c..729b7bec52 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 70742d42d6..106a3f0201 100644
--- a/core/io/compression.h
+++ b/core/io/compression.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,28 +26,28 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COMPRESSION_H
-#define COMPRESSION_H
-
-#include "typedefs.h"
-
-class Compression
-{
-public:
-
- enum Mode {
- MODE_FASTLZ,
- MODE_DEFLATE
- };
-
-
- static int compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
- static int get_max_compressed_buffer_size(int p_src_size,Mode p_mode=MODE_FASTLZ);
- static void decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
-
- Compression();
-};
-
-
-
-#endif // COMPRESSION_H
+#ifndef COMPRESSION_H
+#define COMPRESSION_H
+
+#include "typedefs.h"
+
+class Compression
+{
+public:
+
+ enum Mode {
+ MODE_FASTLZ,
+ MODE_DEFLATE
+ };
+
+
+ static int compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
+ static int get_max_compressed_buffer_size(int p_src_size,Mode p_mode=MODE_FASTLZ);
+ static void decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
+
+ Compression();
+};
+
+
+
+#endif // COMPRESSION_H
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 45e8cf69ab..75388f514a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -357,6 +357,7 @@ if (res!=-1 && res < min_pos) {\
} break;
case MIN_OPEN: {
int level=1;
+ end++;
while(end<close_pos) {
if (str[end]=='[')
@@ -373,6 +374,7 @@ if (res!=-1 && res < min_pos) {\
} break;
case MIN_CURLY_OPEN: {
int level=1;
+ end++;
while(end<close_pos) {
if (str[end]=='{')
@@ -471,9 +473,12 @@ static Variant _decode_variant(const String& p_string) {
ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant());
int scode=0;
- if (params[0].is_numeric())
+ if (params[0].is_numeric()) {
scode=params[0].to_int();
- else
+ if (scode < 10) {
+ scode=KEY_0+scode;
+ }
+ } else
scode=find_keycode(params[0]);
InputEvent ie;
@@ -577,7 +582,7 @@ static Variant _decode_variant(const String& p_string) {
int w=params[2].to_int();
int h=params[3].to_int();
- if (w == 0 && w == 0) {
+ if (w == 0 && h == 0) {
//r_v = Image(w, h, imgformat);
return Image();
};
diff --git a/core/io/config_file.h b/core/io/config_file.h
index e132e46fea..608f143fb1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp
index 6927b3772f..ab17cb8118 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/file_access_buffered.h b/core/io/file_access_buffered.h
index 533cc6c7dd..e6de203cda 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h
index 5de2f66ace..d36c4843e4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index b90a41df54..1d06dc8c4b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index 3039b5c8be..69a03fa14f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,76 +26,76 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef FILE_ACCESS_COMPRESSED_H
-#define FILE_ACCESS_COMPRESSED_H
-
-#include "io/compression.h"
-#include "os/file_access.h"
-
-class FileAccessCompressed : public FileAccess {
-
- Compression::Mode cmode;
- bool writing;
- int write_pos;
- uint8_t*write_ptr;
- int write_buffer_size;
- int write_max;
- int block_size;
- mutable bool read_eof;
- mutable bool at_end;
-
- struct ReadBlock {
- int csize;
- int offset;
- };
-
- mutable Vector<uint8_t> comp_buffer;
- uint8_t *read_ptr;
- mutable int read_block;
- int read_block_count;
- mutable int read_block_size;
- mutable int read_pos;
- Vector<ReadBlock> read_blocks;
- int read_total;
-
-
-
-
- String magic;
- mutable Vector<uint8_t> buffer;
- FileAccess *f;
-public:
-
- void configure(const String& p_magic, Compression::Mode p_mode=Compression::MODE_FASTLZ, int p_block_size=4096);
-
- Error open_after_magic(FileAccess *p_base);
-
- 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
-
- virtual void seek(size_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
- virtual size_t get_pos() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
-
- virtual bool eof_reached() const; ///< reading passed EOF
-
- virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
-
- virtual Error get_error() const; ///< get last error
-
- virtual void store_8(uint8_t p_dest); ///< store a byte
-
- virtual bool file_exists(const String& p_name); ///< return true if a file exists
-
- virtual uint64_t _get_modified_time(const String& p_file);
-
-
- FileAccessCompressed();
- virtual ~FileAccessCompressed();
-
-};
-
-#endif // FILE_ACCESS_COMPRESSED_H
+#ifndef FILE_ACCESS_COMPRESSED_H
+#define FILE_ACCESS_COMPRESSED_H
+
+#include "io/compression.h"
+#include "os/file_access.h"
+
+class FileAccessCompressed : public FileAccess {
+
+ Compression::Mode cmode;
+ bool writing;
+ int write_pos;
+ uint8_t*write_ptr;
+ int write_buffer_size;
+ int write_max;
+ int block_size;
+ mutable bool read_eof;
+ mutable bool at_end;
+
+ struct ReadBlock {
+ int csize;
+ int offset;
+ };
+
+ mutable Vector<uint8_t> comp_buffer;
+ uint8_t *read_ptr;
+ mutable int read_block;
+ int read_block_count;
+ mutable int read_block_size;
+ mutable int read_pos;
+ Vector<ReadBlock> read_blocks;
+ int read_total;
+
+
+
+
+ String magic;
+ mutable Vector<uint8_t> buffer;
+ FileAccess *f;
+public:
+
+ void configure(const String& p_magic, Compression::Mode p_mode=Compression::MODE_FASTLZ, int p_block_size=4096);
+
+ Error open_after_magic(FileAccess *p_base);
+
+ 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
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_name); ///< return true if a file exists
+
+ virtual uint64_t _get_modified_time(const String& p_file);
+
+
+ FileAccessCompressed();
+ virtual ~FileAccessCompressed();
+
+};
+
+#endif // FILE_ACCESS_COMPRESSED_H
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 a1dd2e48bb..83da55fc61 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,7 +39,7 @@ void FileAccessMemory::register_file(String p_name, Vector<uint8_t> p_data) {
if (!files) {
files = memnew((Map<String, Vector<uint8_t> >));
- };
+ }
String name;
if (Globals::get_singleton())
@@ -49,7 +49,7 @@ void FileAccessMemory::register_file(String p_name, Vector<uint8_t> p_data) {
name = DirAccess::normalize_path(name);
(*files)[name] = p_data;
-};
+}
void FileAccessMemory::cleanup() {
@@ -57,13 +57,13 @@ void FileAccessMemory::cleanup() {
return;
memdelete(files);
-};
+}
FileAccess* FileAccessMemory::create() {
return memnew(FileAccessMemory);
-};
+}
bool FileAccessMemory::file_exists(const String& p_name) {
@@ -71,8 +71,16 @@ bool FileAccessMemory::file_exists(const String& p_name) {
name = DirAccess::normalize_path(name);
return files && (files->find(name) != NULL);
-};
+}
+
+Error FileAccessMemory::open_custom(const uint8_t* p_data, int p_len) {
+
+ data=(uint8_t*)p_data;
+ length=p_len;
+ pos=0;
+ return OK;
+}
Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) {
@@ -89,57 +97,57 @@ Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) {
pos = 0;
return OK;
-};
+}
void FileAccessMemory::close() {
data = NULL;
-};
+}
bool FileAccessMemory::is_open() const {
return data != NULL;
-};
+}
void FileAccessMemory::seek(size_t p_position) {
ERR_FAIL_COND(!data);
pos = p_position;
-};
+}
void FileAccessMemory::seek_end(int64_t p_position) {
ERR_FAIL_COND(!data);
pos = length + p_position;
-};
+}
size_t FileAccessMemory::get_pos() const {
ERR_FAIL_COND_V(!data, 0);
return pos;
-};
+}
size_t FileAccessMemory::get_len() const {
ERR_FAIL_COND_V(!data, 0);
return length;
-};
+}
bool FileAccessMemory::eof_reached() const {
return pos >= length;
-};
+}
uint8_t FileAccessMemory::get_8() const {
- uint8_t ret;
+ uint8_t ret = 0;
if (pos < length) {
ret = data[pos];
- };
+ }
++pos;
return ret;
-};
+}
int FileAccessMemory::get_buffer(uint8_t *p_dst,int p_length) const {
@@ -156,19 +164,19 @@ int FileAccessMemory::get_buffer(uint8_t *p_dst,int p_length) const {
pos += p_length;
return read;
-};
+}
Error FileAccessMemory::get_error() const {
return pos >= length ? ERR_FILE_EOF : OK;
-};
+}
void FileAccessMemory::store_8(uint8_t p_byte) {
ERR_FAIL_COND(!data);
ERR_FAIL_COND(pos >= length);
data[pos++] = p_byte;
-};
+}
void FileAccessMemory::store_buffer(const uint8_t *p_src,int p_length) {
@@ -176,11 +184,11 @@ void FileAccessMemory::store_buffer(const uint8_t *p_src,int p_length) {
int write = MIN(p_length, left);
if (write < p_length) {
WARN_PRINT("Writing less data than requested");
- };
+ }
copymem(&data[pos], p_src, write);
pos += p_length;
-};
+}
FileAccessMemory::FileAccessMemory() {
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index a02a022a4f..8c58a8a8ce 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -44,6 +44,7 @@ public:
static void register_file(String p_name, Vector<uint8_t> p_data);
static void cleanup();
+ virtual Error open_custom(const uint8_t* p_data, int p_len); ///< 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
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 26194040b0..850e055129 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -254,6 +254,7 @@ FileAccessNetworkClient::~FileAccessNetworkClient() {
quit=true;
sem->post();
Thread::wait_to_finish(thread);
+ memdelete(thread);
}
memdelete(blockrequest_mutex);
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index f338bea43f..2190cdb0ea 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index e2cb300ebc..339a6d0528 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -48,7 +48,10 @@ Error PackedData::add_pack(const String& p_path) {
void PackedData::add_path(const String& pkg_path, const String& path, uint64_t ofs, uint64_t size,const uint8_t* p_md5, PackSource* p_src) {
- bool exists = files.has(path);
+ PathMD5 pmd5(path.md5_buffer());
+ //printf("adding path %ls, %lli, %lli\n", path.c_str(), pmd5.a, pmd5.b);
+
+ bool exists = files.has(pmd5);
PackedFile pf;
pf.pack=pkg_path;
@@ -58,7 +61,7 @@ void PackedData::add_path(const String& pkg_path, const String& path, uint64_t o
pf.md5[i]=p_md5[i];
pf.src = p_src;
- files[path]=pf;
+ files[pmd5]=pf;
if (!exists) {
//search for dir
@@ -89,7 +92,9 @@ void PackedData::add_path(const String& pkg_path, const String& path, uint64_t o
void PackedData::add_pack_source(PackSource *p_source) {
- sources.push_back(p_source);
+ if (p_source != NULL) {
+ sources.push_back(p_source);
+ }
};
PackedData *PackedData::singleton=NULL;
@@ -104,6 +109,21 @@ PackedData::PackedData() {
add_pack_source(memnew(PackedSourcePCK));
}
+void PackedData::_free_packed_dirs(PackedDir *p_dir) {
+
+ for (Map<String,PackedDir*>::Element *E=p_dir->subdirs.front();E;E=E->next())
+ _free_packed_dirs(E->get());
+ memdelete(p_dir);
+}
+
+PackedData::~PackedData() {
+
+ for(int i=0;i<sources.size();i++) {
+ memdelete(sources[i]);
+ }
+ _free_packed_dirs(root);
+}
+
//////////////////////////////////////////////////////////////////
@@ -113,6 +133,8 @@ bool PackedSourcePCK::try_open_pack(const String& p_path) {
if (!f)
return false;
+ //printf("try open %ls!\n", p_path.c_str());
+
uint32_t magic= f->get_32();
if (magic != 0x43504447) {
@@ -357,6 +379,10 @@ bool DirAccessPack::current_is_dir() const{
return cdir;
}
+bool DirAccessPack::current_is_hidden() const{
+
+ return false;
+}
void DirAccessPack::list_dir_end() {
list_dirs.clear();
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index a4c750bf3c..5bf5ad012c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -60,8 +60,34 @@ private:
Set<String> files;
};
+ struct PathMD5 {
+ uint64_t a;
+ uint64_t b;
+ bool operator < (const PathMD5& p_md5) const {
+
+ if (p_md5.a == a) {
+ return b < p_md5.b;
+ } else {
+ return a < p_md5.a;
+ }
+ }
+
+ bool operator == (const PathMD5& p_md5) const {
+ return a == p_md5.a && b == p_md5.b;
+ };
+
+ PathMD5() {
+ a = b = 0;
+ };
+
+ PathMD5(const Vector<uint8_t> p_buf) {
+ a = *((uint64_t*)&p_buf[0]);
+ b = *((uint64_t*)&p_buf[8]);
+ };
+ };
+
+ Map<PathMD5,PackedFile> files;
- Map<String,PackedFile> files;
Vector<PackSource*> sources;
PackedDir *root;
@@ -70,6 +96,8 @@ private:
static PackedData *singleton;
bool disabled;
+ void _free_packed_dirs(PackedDir *p_dir);
+
public:
void add_pack_source(PackSource* p_source);
@@ -85,6 +113,7 @@ public:
_FORCE_INLINE_ bool has_path(const String& p_path);
PackedData();
+ ~PackedData();
};
class PackSource {
@@ -93,6 +122,7 @@ public:
virtual bool try_open_pack(const String& p_path)=0;
virtual FileAccess* get_file(const String& p_path, PackedData::PackedFile* p_file)=0;
+ virtual ~PackSource() {}
};
class PackedSourcePCK : public PackSource {
@@ -151,7 +181,9 @@ public:
FileAccess *PackedData::try_open_path(const String& p_path) {
- Map<String,PackedFile>::Element *E=files.find(p_path);
+ //print_line("try open path " + p_path);
+ PathMD5 pmd5(p_path.md5_buffer());
+ Map<PathMD5,PackedFile>::Element *E=files.find(pmd5);
if (!E)
return NULL; //not found
if (E->get().offset==0)
@@ -162,7 +194,7 @@ FileAccess *PackedData::try_open_path(const String& p_path) {
bool PackedData::has_path(const String& p_path) {
- return files.has(p_path);
+ return files.has(PathMD5(p_path.md5_buffer()));
}
@@ -180,6 +212,7 @@ public:
virtual bool list_dir_begin();
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();
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 55c0dedad9..ab2eb3b3f2 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -31,6 +31,7 @@
#include "file_access_zip.h"
#include "core/os/file_access.h"
+#include "core/os/copymem.h"
ZipArchive* ZipArchive::instance = NULL;
@@ -103,9 +104,17 @@ static int godot_testerror(voidpf opaque, voidpf stream) {
return f->get_error()!=OK?1:0;
};
+static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) {
+ return memalloc(items * size);
};
+static void godot_free(voidpf opaque, voidpf address) {
+
+ memfree(address);
+};
+
+}; // extern "C"
void ZipArchive::close_handle(unzFile p_file) const {
@@ -125,6 +134,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
ERR_FAIL_COND_V(!f, NULL);
zlib_filefunc_def io;
+ zeromem(&io, sizeof(io));
io.opaque = f;
io.zopen_file = godot_open;
@@ -136,9 +146,13 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
io.zclose_file = godot_close;
io.zerror_file = godot_testerror;
+ io.alloc_mem = godot_alloc;
+ io.free_mem = godot_free;
+
unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io);
ERR_FAIL_COND_V(!pkg, NULL);
- unzGoToFilePos(pkg, &file.file_pos);
+ int unz_err = unzGoToFilePos(pkg, &file.file_pos);
+ ERR_FAIL_COND_V(unz_err != UNZ_OK, NULL);
if (unzOpenCurrentFile(pkg) != UNZ_OK) {
unzClose(pkg);
@@ -150,7 +164,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
bool ZipArchive::try_open_pack(const String& p_name) {
- printf("opening pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
+ //printf("opening zip pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
if (p_name.extension().nocasecmp_to("zip") != 0 && p_name.extension().nocasecmp_to("pcz") != 0)
return false;
@@ -198,7 +212,8 @@ bool ZipArchive::try_open_pack(const String& p_name) {
files[fname] = f;
uint8_t md5[16]={0,0,0,0,0,0,0,0 , 0,0,0,0,0,0,0,0};
- PackedData::get_singleton()->add_path(p_name, fname, 0, 0, md5, this);
+ PackedData::get_singleton()->add_path(p_name, fname, 1, 0, md5, this);
+ //printf("packed data add path %ls, %ls\n", p_name.c_str(), fname.c_str());
if ((i+1)<gi.number_entry) {
unzGoToNextFile(zfile);
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 27e202f47f..58092efd4b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,6 +29,8 @@
#include "http_client.h"
#include "io/stream_peer_ssl.h"
+VARIANT_ENUM_CAST(HTTPClient::Status);
+
Error HTTPClient::connect_url(const String& p_url) {
return OK;
@@ -271,7 +273,7 @@ Error HTTPClient::poll(){
while(true) {
uint8_t byte;
int rec=0;
- Error err = connection->get_partial_data(&byte,1,rec);
+ Error err = _get_http_data(&byte,1,rec);
if (err!=OK) {
close();
status=STATUS_CONNECTION_ERROR;
@@ -323,7 +325,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 {
@@ -415,7 +417,7 @@ ByteArray HTTPClient::read_response_body_chunk() {
//reading len
uint8_t b;
int rec=0;
- err = connection->get_partial_data(&b,1,rec);
+ err = _get_http_data(&b,1,rec);
if (rec==0)
break;
@@ -469,7 +471,7 @@ ByteArray HTTPClient::read_response_body_chunk() {
} else {
int rec=0;
- err = connection->get_partial_data(&chunk[chunk.size()-chunk_left],chunk_left,rec);
+ err = _get_http_data(&chunk[chunk.size()-chunk_left],chunk_left,rec);
if (rec==0) {
break;
}
@@ -500,20 +502,29 @@ ByteArray HTTPClient::read_response_body_chunk() {
}
} else {
- ByteArray::Write r = tmp_read.write();
- int rec=0;
- err = connection->get_partial_data(r.ptr(),MIN(body_left,tmp_read.size()),rec);
- if (rec>0) {
- ByteArray ret;
- ret.resize(rec);
- ByteArray::Write w = ret.write();
- copymem(w.ptr(),r.ptr(),rec);
- body_left-=rec;
- if (body_left==0) {
- status=STATUS_CONNECTED;
+
+ int to_read = MIN(body_left,read_chunk_size);
+ ByteArray ret;
+ ret.resize(to_read);
+ ByteArray::Write w = ret.write();
+ int _offset = 0;
+ while (to_read > 0) {
+ int rec=0;
+ err = _get_http_data(w.ptr()+_offset,to_read,rec);
+ if (rec>0) {
+ body_left-=rec;
+ to_read-=rec;
+ _offset += rec;
+ } else {
+ if (to_read>0) //ended up reading less
+ ret.resize(_offset);
+ break;
}
- return ret;
}
+ if (body_left==0) {
+ status=STATUS_CONNECTED;
+ }
+ return ret;
}
@@ -551,10 +562,24 @@ bool HTTPClient::is_blocking_mode_enabled() const{
return blocking;
}
+Error HTTPClient::_get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received) {
+
+ if (blocking) {
+
+ Error err = connection->get_data(p_buffer,p_bytes);
+ if (err==OK)
+ r_received=p_bytes;
+ else
+ r_received=0;
+ return err;
+ } else {
+ return connection->get_partial_data(p_buffer,p_bytes,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);
@@ -568,6 +593,7 @@ void HTTPClient::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_response_headers_as_dictionary"),&HTTPClient::_get_response_headers_as_dictionary);
ObjectTypeDB::bind_method(_MD("get_response_body_length"),&HTTPClient::get_response_body_length);
ObjectTypeDB::bind_method(_MD("read_response_body_chunk"),&HTTPClient::read_response_body_chunk);
+ ObjectTypeDB::bind_method(_MD("set_read_chunk_size","bytes"),&HTTPClient::set_read_chunk_size);
ObjectTypeDB::bind_method(_MD("set_blocking_mode","enabled"),&HTTPClient::set_blocking_mode);
ObjectTypeDB::bind_method(_MD("is_blocking_mode_enabled"),&HTTPClient::is_blocking_mode_enabled);
@@ -575,6 +601,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 );
@@ -658,6 +686,21 @@ void HTTPClient::_bind_methods() {
}
+void HTTPClient::set_read_chunk_size(int p_size) {
+ ERR_FAIL_COND(p_size<256 || p_size>(1<<24));
+ 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();
@@ -671,7 +714,7 @@ HTTPClient::HTTPClient(){
response_num=0;
ssl=false;
blocking=false;
- tmp_read.resize(4096);
+ read_chunk_size=4096;
}
HTTPClient::~HTTPClient(){
@@ -679,4 +722,3 @@ HTTPClient::~HTTPClient(){
}
-
diff --git a/core/io/http_client.h b/core/io/http_client.h
index 09ad64f48a..b103dc43fc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -157,7 +157,10 @@ private:
static void _bind_methods();
StringArray _get_response_headers();
Dictionary _get_response_headers_as_dictionary();
- ByteArray tmp_read;
+ int read_chunk_size;
+
+ Error _get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received);
+
public:
@@ -185,9 +188,12 @@ public:
void set_blocking_mode(bool p_enable); //useful mostly if running in a thread
bool is_blocking_mode_enabled() const;
+ void set_read_chunk_size(int p_size);
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 180df8964b..2db6e00f0a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 665cc0b460..ff972696ea 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 d2a685f6b0..523f9f472b 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,7 @@
#include "os/semaphore.h"
#include "hash_map.h"
-
+VARIANT_ENUM_CAST(IP::ResolverStatus);
/************* RESOLVER ******************/
@@ -183,7 +183,7 @@ void IP::erase_resolve_item(ResolverID p_id) {
GLOBAL_LOCK_FUNCTION;
- resolver->queue[p_id].status=IP::RESOLVER_STATUS_DONE;
+ resolver->queue[p_id].status=IP::RESOLVER_STATUS_NONE;
}
diff --git a/core/io/ip.h b/core/io/ip.h
index 0181dc7d12..6f50a190e6 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
index a1400adbb6..ed5a45c9ef 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 cd39aa6c81..e55f45a2d7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,6 +39,12 @@ struct IP_Address {
};
//operator Variant() const;
+ bool operator==(const IP_Address& p_ip) const {
+ return host==p_ip.host;
+ }
+ bool operator!=(const IP_Address& p_ip) const {
+ return host!=p_ip.host;
+ }
operator String() const;
IP_Address(const String& p_string);
IP_Address(uint8_t p_a,uint8_t p_b,uint8_t p_c,uint8_t p_d);
diff --git a/core/io/json.cpp b/core/io/json.cpp
index a83d7e4d6e..22c99d0465 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
}
@@ -250,7 +250,7 @@ Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_toke
if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) {
//a number
const CharType *rptr;
- double number = String::to_double(&p_str[idx],-1,&rptr);
+ double number = String::to_double(&p_str[idx],&rptr);
idx+=(rptr - &p_str[idx]);
r_token.type=TK_NUMBER;
r_token.value=number;
diff --git a/core/io/json.h b/core/io/json.h
index d113d0e4ef..78b6303451 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index c6c15af5e0..62ccd81489 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 bb8d3b336a..df673debf5 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/object_format_binary.cpp b/core/io/object_format_binary.cpp
deleted file mode 100644
index c031f6e82b..0000000000
--- a/core/io/object_format_binary.cpp
+++ /dev/null
@@ -1,1491 +0,0 @@
-/*************************************************************************/
-/* object_format_binary.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "object_format_binary.h"
-#include "resource.h"
-#include "io/resource_loader.h"
-#include "print_string.h"
-#include "object_type_db.h"
-#include "globals.h"
-#include "os/os.h"
-#include "version.h"
-
-
-#define print_bl(m_what)
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-
-enum {
-
- SECTION_RESOURCE=0,
- SECTION_OBJECT=1,
- SECTION_META_OBJECT=2,
- SECTION_PROPERTY=3,
- SECTION_END=4,
-
- //numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization)
- VARIANT_NIL=1,
- VARIANT_BOOL=2,
- VARIANT_INT=3,
- VARIANT_REAL=4,
- VARIANT_STRING=5,
- VARIANT_VECTOR2=10,
- VARIANT_RECT2=11,
- VARIANT_VECTOR3=12,
- VARIANT_PLANE=13,
- VARIANT_QUAT=14,
- VARIANT_AABB=15,
- VARIANT_MATRIX3=16,
- VARIANT_TRANSFORM=17,
- VARIANT_MATRIX32=18,
- VARIANT_COLOR=20,
- VARIANT_IMAGE=21,
- VARIANT_NODE_PATH=22,
- VARIANT_RID=23,
- VARIANT_OBJECT=24,
- VARIANT_INPUT_EVENT=25,
- VARIANT_DICTIONARY=26,
- VARIANT_ARRAY=30,
- VARIANT_RAW_ARRAY=31,
- VARIANT_INT_ARRAY=32,
- VARIANT_REAL_ARRAY=33,
- VARIANT_STRING_ARRAY=34,
- VARIANT_VECTOR3_ARRAY=35,
- VARIANT_COLOR_ARRAY=36,
- VARIANT_VECTOR2_ARRAY=37,
-
- IMAGE_ENCODING_EMPTY=0,
- IMAGE_ENCODING_RAW=1,
- IMAGE_ENCODING_PNG=2, //not yet
- IMAGE_ENCODING_JPG=3,
-
- IMAGE_FORMAT_GRAYSCALE=0,
- IMAGE_FORMAT_INTENSITY=1,
- IMAGE_FORMAT_GRAYSCALE_ALPHA=2,
- IMAGE_FORMAT_RGB=3,
- IMAGE_FORMAT_RGBA=4,
- IMAGE_FORMAT_INDEXED=5,
- IMAGE_FORMAT_INDEXED_ALPHA=6,
- IMAGE_FORMAT_BC1=7,
- IMAGE_FORMAT_BC2=8,
- IMAGE_FORMAT_BC3=9,
- IMAGE_FORMAT_BC4=10,
- IMAGE_FORMAT_BC5=11,
- IMAGE_FORMAT_CUSTOM=12,
-
- OBJECT_EMPTY=0,
- OBJECT_EXTERNAL_RESOURCE=1,
- OBJECT_INTERNAL_RESOURCE=2,
-
-
-};
-
-
-void ObjectFormatSaverBinary::_pad_buffer(int p_bytes) {
-
- int extra = 4-(p_bytes%4);
- if (extra<4) {
- for(int i=0;i<extra;i++)
- f->store_8(0); //pad to 32
- }
-
-}
-
-
-void ObjectFormatSaverBinary::write_property(int p_idx,const Variant& p_property) {
-
- f->store_32(SECTION_PROPERTY);
- f->store_32(p_idx);
-
- switch(p_property.get_type()) {
-
- case Variant::NIL: {
-
- f->store_32(VARIANT_NIL);
- // don't store anything
- } break;
- case Variant::BOOL: {
-
- f->store_32(VARIANT_BOOL);
- bool val=p_property;
- f->store_32(val);
- } break;
- case Variant::INT: {
-
- f->store_32(VARIANT_INT);
- int val=p_property;
- f->store_32(val);
- } break;
- case Variant::REAL: {
-
- f->store_32(VARIANT_REAL);
- real_t val=p_property;
- f->store_real(val);
-
- } break;
- case Variant::STRING: {
-
- f->store_32(VARIANT_STRING);
- String val=p_property;
- save_unicode_string(val);
-
- } break;
- case Variant::VECTOR2: {
-
- f->store_32(VARIANT_VECTOR2);
- Vector2 val=p_property;
- f->store_real(val.x);
- f->store_real(val.y);
-
- } break;
- case Variant::RECT2: {
-
- f->store_32(VARIANT_RECT2);
- Rect2 val=p_property;
- f->store_real(val.pos.x);
- f->store_real(val.pos.y);
- f->store_real(val.size.x);
- f->store_real(val.size.y);
-
- } break;
- case Variant::VECTOR3: {
-
- f->store_32(VARIANT_VECTOR3);
- Vector3 val=p_property;
- f->store_real(val.x);
- f->store_real(val.y);
- f->store_real(val.z);
-
- } break;
- case Variant::PLANE: {
-
- f->store_32(VARIANT_PLANE);
- Plane val=p_property;
- f->store_real(val.normal.x);
- f->store_real(val.normal.y);
- f->store_real(val.normal.z);
- f->store_real(val.d);
-
- } break;
- case Variant::QUAT: {
-
- f->store_32(VARIANT_QUAT);
- Quat val=p_property;
- f->store_real(val.x);
- f->store_real(val.y);
- f->store_real(val.z);
- f->store_real(val.w);
-
- } break;
- case Variant::_AABB: {
-
- f->store_32(VARIANT_AABB);
- AABB val=p_property;
- f->store_real(val.pos.x);
- f->store_real(val.pos.y);
- f->store_real(val.pos.z);
- f->store_real(val.size.x);
- f->store_real(val.size.y);
- f->store_real(val.size.z);
-
- } break;
- case Variant::MATRIX32: {
-
- f->store_32(VARIANT_MATRIX32);
- Matrix32 val=p_property;
- f->store_real(val.elements[0].x);
- f->store_real(val.elements[0].y);
- f->store_real(val.elements[1].x);
- f->store_real(val.elements[1].y);
- f->store_real(val.elements[2].x);
- f->store_real(val.elements[2].y);
-
- } break;
- case Variant::MATRIX3: {
-
- f->store_32(VARIANT_MATRIX3);
- Matrix3 val=p_property;
- f->store_real(val.elements[0].x);
- f->store_real(val.elements[0].y);
- f->store_real(val.elements[0].z);
- f->store_real(val.elements[1].x);
- f->store_real(val.elements[1].y);
- f->store_real(val.elements[1].z);
- f->store_real(val.elements[2].x);
- f->store_real(val.elements[2].y);
- f->store_real(val.elements[2].z);
-
- } break;
- case Variant::TRANSFORM: {
-
- f->store_32(VARIANT_TRANSFORM);
- Transform val=p_property;
- f->store_real(val.basis.elements[0].x);
- f->store_real(val.basis.elements[0].y);
- f->store_real(val.basis.elements[0].z);
- f->store_real(val.basis.elements[1].x);
- f->store_real(val.basis.elements[1].y);
- f->store_real(val.basis.elements[1].z);
- f->store_real(val.basis.elements[2].x);
- f->store_real(val.basis.elements[2].y);
- f->store_real(val.basis.elements[2].z);
- f->store_real(val.origin.x);
- f->store_real(val.origin.y);
- f->store_real(val.origin.z);
-
- } break;
- case Variant::COLOR: {
-
- f->store_32(VARIANT_COLOR);
- Color val=p_property;
- f->store_real(val.r);
- f->store_real(val.g);
- f->store_real(val.b);
- f->store_real(val.a);
-
- } break;
- case Variant::IMAGE: {
-
- f->store_32(VARIANT_IMAGE);
- Image val =p_property;
- if (val.empty()) {
- f->store_32(IMAGE_ENCODING_EMPTY);
- break;
- }
- f->store_32(IMAGE_ENCODING_RAW); //raw encoding
- f->store_32(val.get_width());
- f->store_32(val.get_height());
- f->store_32(val.get_mipmaps());
- switch(val.get_format()) {
-
- case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_GRAYSCALE ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
- case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_INTENSITY ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
- case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_GRAYSCALE_ALPHA ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255
- case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B
- case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A
- case Image::FORMAT_INDEXED: f->store_32(IMAGE_FORMAT_INDEXED ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*3 bytes of palette
- case Image::FORMAT_INDEXED_ALPHA: f->store_32(IMAGE_FORMAT_INDEXED_ALPHA ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*4 bytes of palette (alpha)
- case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_BC1 ); break; // DXT1
- case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_BC2 ); break; // DXT3
- case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_BC3 ); break; // DXT5
- case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_BC4 ); break; // ATI1
- case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_BC5 ); break; // ATI2
- case Image::FORMAT_CUSTOM: f->store_32(IMAGE_FORMAT_CUSTOM ); break;
- default: {}
-
- }
-
- int dlen = val.get_data().size();
- f->store_32(dlen);
- DVector<uint8_t>::Read r = val.get_data().read();
- f->store_buffer(r.ptr(),dlen);
- _pad_buffer(dlen);
-
- } break;
- case Variant::NODE_PATH: {
- f->store_32(VARIANT_NODE_PATH);
- save_unicode_string(p_property);
- } break;
- case Variant::_RID: {
-
- f->store_32(VARIANT_RID);
- WARN_PRINT("Can't save RIDs");
- RID val = p_property;
- f->store_32(val.get_id());
- } break;
- case Variant::OBJECT: {
-
- f->store_32(VARIANT_OBJECT);
- RES res = p_property;
- if (res.is_null()) {
- f->store_32(OBJECT_EMPTY);
- return; // don't save it
- }
-
- if (res->get_path().length() && res->get_path().find("::")==-1) {
- f->store_32(OBJECT_EXTERNAL_RESOURCE);
- save_unicode_string(res->get_type());
- String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
- save_unicode_string(path);
- } else {
-
- if (!resource_map.has(res)) {
- f->store_32(OBJECT_EMPTY);
- ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
- ERR_FAIL();
- }
-
- f->store_32(OBJECT_INTERNAL_RESOURCE);
- f->store_32(resource_map[res]);
- //internal resource
- }
-
-
- } break;
- case Variant::INPUT_EVENT: {
-
- f->store_32(VARIANT_INPUT_EVENT);
- WARN_PRINT("Can't save InputEvent (maybe it could..)");
- } break;
- case Variant::DICTIONARY: {
-
- f->store_32(VARIANT_DICTIONARY);
- Dictionary d = p_property;
- f->store_32(d.size());
-
- List<Variant> keys;
- d.get_key_list(&keys);
-
- for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
-
- //if (!_check_type(dict[E->get()]))
- // continue;
-
- write_property(0,E->get());
- write_property(0,d[E->get()]);
- }
-
-
- } break;
- case Variant::ARRAY: {
-
- f->store_32(VARIANT_ARRAY);
- Array a=p_property;
- f->store_32(a.size());
- for(int i=0;i<a.size();i++) {
-
- write_property(i,a[i]);
- }
-
- } break;
- case Variant::RAW_ARRAY: {
-
- f->store_32(VARIANT_RAW_ARRAY);
- DVector<uint8_t> arr = p_property;
- int len=arr.size();
- f->store_32(len);
- DVector<uint8_t>::Read r = arr.read();
- f->store_buffer(r.ptr(),len);
- _pad_buffer(len);
-
- } break;
- case Variant::INT_ARRAY: {
-
- f->store_32(VARIANT_INT_ARRAY);
- DVector<int> arr = p_property;
- int len=arr.size();
- f->store_32(len);
- DVector<int>::Read r = arr.read();
- for(int i=0;i<len;i++)
- f->store_32(r[i]);
-
- } break;
- case Variant::REAL_ARRAY: {
-
- f->store_32(VARIANT_REAL_ARRAY);
- DVector<real_t> arr = p_property;
- int len=arr.size();
- f->store_32(len);
- DVector<real_t>::Read r = arr.read();
- for(int i=0;i<len;i++) {
- f->store_real(r[i]);
- }
-
- } break;
- case Variant::STRING_ARRAY: {
-
- f->store_32(VARIANT_STRING_ARRAY);
- DVector<String> arr = p_property;
- int len=arr.size();
- f->store_32(len);
- DVector<String>::Read r = arr.read();
- for(int i=0;i<len;i++) {
- save_unicode_string(r[i]);
- }
-
- } break;
- case Variant::VECTOR3_ARRAY: {
-
- f->store_32(VARIANT_VECTOR3_ARRAY);
- DVector<Vector3> arr = p_property;
- int len=arr.size();
- f->store_32(len);
- DVector<Vector3>::Read r = arr.read();
- for(int i=0;i<len;i++) {
- f->store_real(r[i].x);
- f->store_real(r[i].y);
- f->store_real(r[i].z);
- }
-
- } break;
- case Variant::VECTOR2_ARRAY: {
-
- f->store_32(VARIANT_VECTOR2_ARRAY);
- DVector<Vector2> arr = p_property;
- int len=arr.size();
- f->store_32(len);
- DVector<Vector2>::Read r = arr.read();
- for(int i=0;i<len;i++) {
- f->store_real(r[i].x);
- f->store_real(r[i].y);
- }
-
- } break;
- case Variant::COLOR_ARRAY: {
-
- f->store_32(VARIANT_COLOR_ARRAY);
- DVector<Color> arr = p_property;
- int len=arr.size();
- f->store_32(len);
- DVector<Color>::Read r = arr.read();
- for(int i=0;i<len;i++) {
- f->store_real(r[i].r);
- f->store_real(r[i].g);
- f->store_real(r[i].b);
- f->store_real(r[i].a);
- }
-
- } break;
- default: {
-
- ERR_EXPLAIN("Invalid variant");
- ERR_FAIL();
- }
- }
-}
-
-
-void ObjectFormatSaverBinary::_find_resources(const Variant& p_variant) {
-
-
- switch(p_variant.get_type()) {
- case Variant::OBJECT: {
-
-
- RES res = p_variant.operator RefPtr();
-
- if (res.is_null())
- return;
-
- if (!bundle_resources && res->get_path().length() && res->get_path().find("::") == -1 )
- return;
-
- if (resource_map.has(res))
- return;
-
- List<PropertyInfo> property_list;
-
- res->get_property_list(&property_list);
-
- for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) {
-
- if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) {
-
- _find_resources(res->get(E->get().name));
- }
- }
-
- SavedObject *so = memnew( SavedObject );
- _save_obj(res.ptr(),so);
- so->meta=res.get_ref_ptr();
-
- resource_map[ res ] = saved_resources.size();
- saved_resources.push_back(so);
-
- } 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 ObjectFormatSaverBinary::_save_obj(const Object *p_object,SavedObject *so) {
-
- if (optimizer.is_valid()) {
- //use optimizer
-
- List<OptimizedSaver::Property> props;
- optimizer->get_property_list(p_object,&props);
-
- for(List<OptimizedSaver::Property>::Element *E=props.front();E;E=E->next()) {
-
- if (skip_editor && String(E->get().name).begins_with("__editor"))
- continue;
- _find_resources(E->get().value);
- SavedObject::SavedProperty sp;
-
- sp.name_idx=get_string_index(E->get().name);
- sp.value=E->get().value;
- so->properties.push_back(sp);
- }
-
- } else {
- //use classic way
- List<PropertyInfo> property_list;
- p_object->get_property_list( &property_list );
-
- for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) {
-
- if (skip_editor && E->get().name.begins_with("__editor"))
- continue;
- if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) {
-
- SavedObject::SavedProperty sp;
- sp.name_idx=get_string_index(E->get().name);
- sp.value = p_object->get(E->get().name);
- _find_resources(sp.value);
- so->properties.push_back(sp);
- }
- }
- }
-
- return OK;
-
-}
-
-Error ObjectFormatSaverBinary::save(const Object *p_object,const Variant &p_meta) {
-
- ERR_FAIL_COND_V(!f,ERR_UNCONFIGURED);
- ERR_EXPLAIN("write_object should supply either an object, a meta, or both");
- ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER);
-
- SavedObject *so = memnew( SavedObject );
-
- if (p_object)
- so->type=p_object->get_type();
-
- _find_resources(p_meta);
- so->meta=p_meta;
- Error err = _save_obj(p_object,so);
- ERR_FAIL_COND_V( err, ERR_INVALID_DATA );
-
- saved_objects.push_back(so);
-
- return OK;
-}
-
-void ObjectFormatSaverBinary::save_unicode_string(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);
-}
-
-ObjectFormatSaverBinary::ObjectFormatSaverBinary(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
-
- optimizer=p_optimizer;
- relative_paths=p_flags&ObjectSaver::FLAG_RELATIVE_PATHS;
- skip_editor=p_flags&ObjectSaver::FLAG_OMIT_EDITOR_PROPERTIES;
- bundle_resources=p_flags&ObjectSaver::FLAG_BUNDLE_RESOURCES;
- big_endian=p_flags&ObjectSaver::FLAG_SAVE_BIG_ENDIAN;
- f=p_file; // should be already opened
- local_path=p_local_path;
- magic=p_magic;
-
- bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create
-}
-
-int ObjectFormatSaverBinary::get_string_index(const String& p_string) {
-
- StringName s=p_string;
- if (string_map.has(s))
- return string_map[s];
-
- string_map[s]=strings.size();
- strings.push_back(s);
- return strings.size()-1;
-}
-
-ObjectFormatSaverBinary::~ObjectFormatSaverBinary() {
-
-
- static const uint8_t header[4]={'O','B','D','B'};
- f->store_buffer(header,4);
- if (big_endian) {
- f->store_32(1);
- f->set_endian_swap(true);
- } else
- f->store_32(0);
-
- f->store_32(0); //64 bits file, false for now
- f->store_32(VERSION_MAJOR);
- f->store_32(VERSION_MINOR);
- save_unicode_string(magic);
- for(int i=0;i<16;i++)
- f->store_32(0); // reserved
-
- f->store_32(strings.size()); //string table size
- for(int i=0;i<strings.size();i++) {
- print_bl("saving string: "+strings[i]);
- save_unicode_string(strings[i]);
- }
-
- // save resources
-
- for(int i=0;i<saved_resources.size();i++) {
-
- SavedObject *so = saved_resources[i];
- RES res = so->meta;
- ERR_CONTINUE(!resource_map.has(res));
-
- f->store_32(SECTION_RESOURCE);
- size_t skip_pos = f->get_pos();
- f->store_64(0); // resource skip seek pos
- save_unicode_string(res->get_type());
-
- if (res->get_path().length() && res->get_path().find("::") == -1 )
- save_unicode_string(res->get_path());
- else
- save_unicode_string("local://"+itos(i));
-
-
-
- List<SavedObject::SavedProperty>::Element *SE = so->properties.front();
-
- while(SE) {
-
- write_property(SE->get().name_idx,SE->get().value);
- SE=SE->next();
- }
-
- f->store_32(SECTION_END);
-
- size_t end=f->get_pos();
- f->seek(skip_pos);
- f->store_64(end);
- f->seek_end();
-
- memdelete( so );
- }
-
- if (!saved_objects.empty()) {
-
-
- for(List<SavedObject*>::Element *E=saved_objects.front();E;E=E->next()) {
-
- SavedObject *so = E->get();
-
-
- size_t section_end;
-
- if (so->type!="") {
- f->store_32(SECTION_OBJECT);
- section_end=f->get_pos();
- f->store_64(0); //section end
- save_unicode_string(so->type);
- } else {
- f->store_32(SECTION_META_OBJECT);
- section_end=f->get_pos();
- f->store_64(0); //section end
- }
-
-
- if (so->meta.get_type()!=Variant::NIL)
- write_property(bin_meta_idx,so->meta);
-
- List<SavedObject::SavedProperty>::Element *SE = so->properties.front();
-
- while(SE) {
-
- write_property(SE->get().name_idx,SE->get().value);
- SE=SE->next();
- }
-
- f->store_32(SECTION_END);
-
- size_t end=f->get_pos();
- f->seek(section_end);
- f->store_64(end);
- f->seek_end();
-
- memdelete(so); //no longer needed
- }
-
-
- }
-
- f->store_32(SECTION_END);
-
- f->close();
- memdelete(f);
-}
-
-
-ObjectFormatSaver* ObjectFormatSaverInstancerBinary::instance(const String& p_file,const String& p_magic,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
-
- FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE);
-
- ERR_FAIL_COND_V( !f, NULL );
- String local_path = Globals::get_singleton()->localize_path(p_file);
-
- return memnew( ObjectFormatSaverBinary( f, p_magic,local_path,p_flags,p_optimizer ) );
-}
-
-void ObjectFormatSaverInstancerBinary::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("bin");
-}
-
-
-ObjectFormatSaverInstancerBinary::~ObjectFormatSaverInstancerBinary() {
-
-
-}
-
-
-
-/************************************************/
-/************************************************/
-/************************************************/
-/************************************************/
-/************************************************/
-
-
-void ObjectFormatLoaderBinary::_advance_padding(uint32_t p_len) {
-
- uint32_t extra = 4-(p_len%4);
- if (extra<4) {
- for(uint32_t i=0;i<extra;i++)
- f->get_8(); //pad to 32
- }
-
-}
-
-Error ObjectFormatLoaderBinary::parse_property(Variant& r_v, int &r_index) {
-
-
- uint32_t prop = f->get_32();
- if (prop==SECTION_END)
- return ERR_FILE_EOF;
- ERR_FAIL_COND_V(prop!=SECTION_PROPERTY,ERR_FILE_CORRUPT);
-
- r_index = f->get_32();
-
- uint32_t type = f->get_32();
- print_bl("find property of type: "+itos(type));
-
-
- switch(type) {
-
- case VARIANT_NIL: {
-
- r_v=Variant();
- } break;
- case VARIANT_BOOL: {
-
- r_v=bool(f->get_32());
- } break;
- case VARIANT_INT: {
-
- r_v=int(f->get_32());
- } break;
- case VARIANT_REAL: {
-
- r_v=f->get_real();
- } break;
- case VARIANT_STRING: {
-
- r_v=get_unicode_string();
- } break;
- case VARIANT_VECTOR2: {
-
- Vector2 v;
- v.x=f->get_real();
- v.y=f->get_real();
- r_v=v;
-
- } break;
- case VARIANT_RECT2: {
-
- Rect2 v;
- v.pos.x=f->get_real();
- v.pos.y=f->get_real();
- v.size.x=f->get_real();
- v.size.y=f->get_real();
- r_v=v;
-
- } break;
- case VARIANT_VECTOR3: {
-
- Vector3 v;
- v.x=f->get_real();
- v.y=f->get_real();
- v.z=f->get_real();
- r_v=v;
- } break;
- case VARIANT_PLANE: {
-
- Plane v;
- v.normal.x=f->get_real();
- v.normal.y=f->get_real();
- v.normal.z=f->get_real();
- v.d=f->get_real();
- r_v=v;
- } break;
- case VARIANT_QUAT: {
- Quat v;
- v.x=f->get_real();
- v.y=f->get_real();
- v.z=f->get_real();
- v.w=f->get_real();
- r_v=v;
-
- } break;
- case VARIANT_AABB: {
-
- AABB v;
- v.pos.x=f->get_real();
- v.pos.y=f->get_real();
- v.pos.z=f->get_real();
- v.size.x=f->get_real();
- v.size.y=f->get_real();
- v.size.z=f->get_real();
- r_v=v;
-
- } break;
- case VARIANT_MATRIX32: {
-
- Matrix32 v;
- v.elements[0].x=f->get_real();
- v.elements[0].y=f->get_real();
- v.elements[1].x=f->get_real();
- v.elements[1].y=f->get_real();
- v.elements[2].x=f->get_real();
- v.elements[2].y=f->get_real();
- r_v=v;
-
- } break;
- case VARIANT_MATRIX3: {
-
- Matrix3 v;
- v.elements[0].x=f->get_real();
- v.elements[0].y=f->get_real();
- v.elements[0].z=f->get_real();
- v.elements[1].x=f->get_real();
- v.elements[1].y=f->get_real();
- v.elements[1].z=f->get_real();
- v.elements[2].x=f->get_real();
- v.elements[2].y=f->get_real();
- v.elements[2].z=f->get_real();
- r_v=v;
-
- } break;
- case VARIANT_TRANSFORM: {
-
- Transform v;
- v.basis.elements[0].x=f->get_real();
- v.basis.elements[0].y=f->get_real();
- v.basis.elements[0].z=f->get_real();
- v.basis.elements[1].x=f->get_real();
- v.basis.elements[1].y=f->get_real();
- v.basis.elements[1].z=f->get_real();
- v.basis.elements[2].x=f->get_real();
- v.basis.elements[2].y=f->get_real();
- v.basis.elements[2].z=f->get_real();
- v.origin.x=f->get_real();
- v.origin.y=f->get_real();
- v.origin.z=f->get_real();
- r_v=v;
- } break;
- case VARIANT_COLOR: {
-
- Color v;
- v.r=f->get_real();
- v.g=f->get_real();
- v.b=f->get_real();
- v.a=f->get_real();
- r_v=v;
-
- } break;
- case VARIANT_IMAGE: {
-
-
- uint32_t encoding = f->get_32();
- if (encoding==IMAGE_ENCODING_EMPTY) {
- r_v=Variant();
- break;
- }
-
- if (encoding==IMAGE_ENCODING_RAW) {
- uint32_t width = f->get_32();
- uint32_t height = f->get_32();
- uint32_t mipmaps = f->get_32();
- uint32_t format = f->get_32();
- Image::Format fmt;
- switch(format) {
-
- case IMAGE_FORMAT_GRAYSCALE: { fmt=Image::FORMAT_GRAYSCALE; } break;
- case IMAGE_FORMAT_INTENSITY: { fmt=Image::FORMAT_INTENSITY; } break;
- case IMAGE_FORMAT_GRAYSCALE_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; } break;
- case IMAGE_FORMAT_RGB: { fmt=Image::FORMAT_RGB; } break;
- case IMAGE_FORMAT_RGBA: { fmt=Image::FORMAT_RGBA; } break;
- case IMAGE_FORMAT_INDEXED: { fmt=Image::FORMAT_INDEXED; } break;
- case IMAGE_FORMAT_INDEXED_ALPHA: { fmt=Image::FORMAT_INDEXED_ALPHA; } break;
- case IMAGE_FORMAT_BC1: { fmt=Image::FORMAT_BC1; } break;
- case IMAGE_FORMAT_BC2: { fmt=Image::FORMAT_BC2; } break;
- case IMAGE_FORMAT_BC3: { fmt=Image::FORMAT_BC3; } break;
- case IMAGE_FORMAT_BC4: { fmt=Image::FORMAT_BC4; } break;
- case IMAGE_FORMAT_BC5: { fmt=Image::FORMAT_BC5; } break;
- case IMAGE_FORMAT_CUSTOM: { fmt=Image::FORMAT_CUSTOM; } break;
- default: {
-
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- }
-
- }
-
-
- uint32_t datalen = f->get_32();
-
- print_bl("width: "+itos(width));
- print_bl("height: "+itos(height));
- print_bl("mipmaps: "+itos(mipmaps));
- print_bl("format: "+itos(format));
- print_bl("datalen: "+itos(datalen));
-
- DVector<uint8_t> imgdata;
- imgdata.resize(datalen);
- DVector<uint8_t>::Write w = imgdata.write();
- f->get_buffer(w.ptr(),datalen);
- _advance_padding(datalen);
- w=DVector<uint8_t>::Write();
-
- r_v=Image(width,height,mipmaps,fmt,imgdata);
- }
-
-
- } break;
- case VARIANT_NODE_PATH: {
-
- r_v=NodePath(get_unicode_string());
- } break;
- case VARIANT_RID: {
-
- r_v=f->get_32();
- } break;
- case VARIANT_OBJECT: {
-
- uint32_t type=f->get_32();
-
- switch(type) {
-
- case OBJECT_EMPTY: {
- //do none
-
- } break;
- case OBJECT_INTERNAL_RESOURCE: {
- uint32_t index=f->get_32();
- String path = local_path+"::"+itos(index);
- RES res = ResourceLoader::load(path);
- if (res.is_null()) {
- WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data());
- }
- r_v=res;
-
- } break;
- case OBJECT_EXTERNAL_RESOURCE: {
-
- String type = get_unicode_string();
- String path = get_unicode_string();
-
- 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()+"/"+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);
- } break;
- }
-
- } break;
- case VARIANT_INPUT_EVENT: {
-
- } break;
- case VARIANT_DICTIONARY: {
-
- int len=f->get_32();
- Dictionary d;
- for(int i=0;i<len;i++) {
- int idx;
- Variant key;
- Error err = parse_property(key,idx);
- ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
- Variant value;
- err = parse_property(value,idx);
- ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
- d[key]=value;
- }
- r_v=d;
- } break;
- case VARIANT_ARRAY: {
- int len=f->get_32();
- Array a;
- a.resize(len);
- for(int i=0;i<len;i++) {
- int idx;
- Variant val;
- Error err = parse_property(val,idx);
- ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
- a[i]=val;
- }
- r_v=a;
-
- } break;
- case VARIANT_RAW_ARRAY: {
-
- uint32_t len = f->get_32();
-
- DVector<uint8_t> array;
- array.resize(len);
- DVector<uint8_t>::Write w = array.write();
- f->get_buffer(w.ptr(),len);
- _advance_padding(len);
- w=DVector<uint8_t>::Write();
- r_v=array;
-
- } break;
- case VARIANT_INT_ARRAY: {
-
- uint32_t len = f->get_32();
-
- DVector<int> array;
- array.resize(len);
- DVector<int>::Write w = array.write();
- f->get_buffer((uint8_t*)w.ptr(),len*4);
- w=DVector<int>::Write();
- r_v=array;
- } break;
- case VARIANT_REAL_ARRAY: {
-
- uint32_t len = f->get_32();
-
- DVector<real_t> array;
- array.resize(len);
- DVector<real_t>::Write w = array.write();
- f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t));
- w=DVector<real_t>::Write();
- r_v=array;
- } break;
- case VARIANT_STRING_ARRAY: {
-
- uint32_t len = f->get_32();
- DVector<String> array;
- array.resize(len);
- DVector<String>::Write w = array.write();
- for(int i=0;i<len;i++)
- w[i]=get_unicode_string();
- w=DVector<String>::Write();
- r_v=array;
-
-
- } break;
- case VARIANT_VECTOR2_ARRAY: {
-
- uint32_t len = f->get_32();
-
- DVector<Vector2> array;
- array.resize(len);
- DVector<Vector2>::Write w = array.write();
- if (sizeof(Vector2)==8) {
- f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*2);
- } else {
- ERR_EXPLAIN("Vector2 size is NOT 8!");
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- w=DVector<Vector2>::Write();
- r_v=array;
-
- } break;
- case VARIANT_VECTOR3_ARRAY: {
-
- uint32_t len = f->get_32();
-
- DVector<Vector3> array;
- array.resize(len);
- DVector<Vector3>::Write w = array.write();
- if (sizeof(Vector3)==12) {
- f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*3);
- } else {
- ERR_EXPLAIN("Vector3 size is NOT 12!");
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- w=DVector<Vector3>::Write();
- r_v=array;
-
- } break;
- case VARIANT_COLOR_ARRAY: {
-
- uint32_t len = f->get_32();
-
- DVector<Color> array;
- array.resize(len);
- DVector<Color>::Write w = array.write();
- if (sizeof(Color)==16) {
- f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*4);
- } else {
- ERR_EXPLAIN("Color size is NOT 16!");
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- w=DVector<Color>::Write();
- r_v=array;
- } break;
-
- default: {
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- } break;
- }
-
-
-
- return OK; //never reach anyway
-
-}
-
-Error ObjectFormatLoaderBinary::load(Object **p_object,Variant &p_meta) {
-
-
-
- while(true) {
-
- if (f->eof_reached()) {
- ERR_EXPLAIN("Premature end of file at: "+local_path);
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- }
-
- RES resource;
- Object *obj=NULL;
- bool meta=false;
-
- uint32_t section = f->get_32();
-
- switch(section) {
-
-
- case SECTION_RESOURCE: {
-
- print_bl("resource found");
-
- size_t section_end = f->get_64();
- print_bl("section end: "+itos(section_end));
- String type = get_unicode_string();
- String path = get_unicode_string();
- print_bl("path: "+path);
-
- if (path.begins_with("local://")) {
- //built-in resource (but really external)
- path=path.replace("local://",local_path+"::");
- }
-
- if (ResourceCache::has(path)) {
- f->seek(section_end);
- continue;
- }
-
- //load properties
-
-
- obj = ObjectTypeDB::instance(type);
- if (!obj) {
- ERR_EXPLAIN("Object of unrecognized type '"+type+"' in file: "+type);
- }
-
- ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
-
- Resource *r = obj->cast_to<Resource>();
- if (!r) {
- memdelete(obj); //bye
- ERR_EXPLAIN("Object type in resource field not a resource, type is: "+obj->get_type());
- ERR_FAIL_COND_V(!obj->cast_to<Resource>(),ERR_FILE_CORRUPT);
- }
-
- resource = RES( r );
- r->set_path(path);
- } break;
- case SECTION_META_OBJECT:
- meta=true;
- print_bl("meta found");
-
- case SECTION_OBJECT: {
-
- uint64_t section_end = f->get_64();
-
- if (!meta) {
- print_bl("object");
-
- String type = get_unicode_string();
- if (ObjectTypeDB::can_instance(type)) {
- obj = ObjectTypeDB::instance(type);
- if (!obj) {
- ERR_EXPLAIN("Object of unrecognized type in file: "+type);
- }
- ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
- } else {
-
- f->seek(section_end);
- return ERR_SKIP;
- };
-
-
- }
-
-
- } break;
- case SECTION_END: {
-
-
- return ERR_FILE_EOF;
- } break;
-
- default: {
-
- ERR_EXPLAIN("Invalid Section ID '"+itos(section)+"' in file: "+local_path);
- ERR_FAIL_V(ERR_FILE_CORRUPT);
-
- }
-
- }
-
-
- //load properties
-
- while(true) {
-
- int name_idx;
- Variant v;
- Error err;
- err = parse_property(v,name_idx);
-
- print_bl("prop idx "+itos(name_idx)+" value: "+String(v));
-
- if (err==ERR_FILE_EOF)
- break;
-
- if (err!=OK) {
- ERR_EXPLAIN("File Corrupted");
- ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT);
- }
-
-
- if (resource.is_null() && name_idx==0) { //0 is __bin_meta__
-
- p_meta=v;
- continue;
- } else if (!obj) {
-
- ERR_EXPLAIN("Normal property found in meta object.");
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- }
-
- Map<int,StringName>::Element *E=string_map.find(name_idx);
- if (!E) {
- ERR_EXPLAIN("Property ID has no matching name: "+itos(name_idx));
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- }
-
- obj->set(E->get(),v);
- }
-
- if (!obj) {
- *p_object=NULL;
- return OK; // it was a meta object
- }
-
- if (resource.is_null()) {
-
- //regular object
- *p_object=obj;
- return OK;
- } else {
-
- resource_cache.push_back(resource); //keep it in mem until finished loading
- }
-
- }
-}
-
-
-ObjectFormatLoaderBinary::~ObjectFormatLoaderBinary() {
-
- if (f) {
- if (f->is_open())
- f->close();
- memdelete(f);
- }
-}
-
-
-String ObjectFormatLoaderBinary::get_unicode_string() {
-
- uint32_t len = f->get_32();
- if (len>str_buf.size()) {
- str_buf.resize(len);
- }
- f->get_buffer((uint8_t*)&str_buf[0],len);
- String s;
- s.parse_utf8(&str_buf[0]);
- return s;
-}
-
-ObjectFormatLoaderBinary::ObjectFormatLoaderBinary(FileAccess *p_f,bool p_endian_swap,bool p_use64) {
-
- f=p_f;
- endian_swap=p_endian_swap;
- use_real64=p_use64;
-
- //load string table
- uint32_t string_table_size = f->get_32();
- print_bl("string table size: "+itos(string_table_size));
- for(int i=0;i<string_table_size;i++) {
-
- String str = get_unicode_string();
- print_bl("string "+itos(i)+" is: "+str);
- string_map[i]=str;
- }
-
-
-}
-
-ObjectFormatLoaderBinary* ObjectFormatLoaderInstancerBinary::instance(const String& p_file,const String& p_magic) {
-
- FileAccess *f=FileAccess::open(p_file,FileAccess::READ);
- ERR_FAIL_COND_V(!f,NULL);
-
- uint8_t header[4];
- f->get_buffer(header,4);
- if (header[0]!='O' || header[1]!='B' || header[2]!='D' || header[3]!='B') {
-
- ERR_EXPLAIN("File not in valid binary format: "+p_file);
- ERR_FAIL_V(NULL);
- }
-
- uint32_t big_endian = f->get_32();
-#ifdef BIG_ENDIAN_ENABLED
- bool 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
-
- uint32_t ver_major=f->get_32();
- uint32_t ver_minor=f->get_32();
-
- print_bl("big endian: "+itos(big_endian));
- print_bl("endian swap: "+itos(endian_swap));
- print_bl("real64: "+itos(use_real64));
- print_bl("major: "+itos(ver_major));
- print_bl("minor: "+itos(ver_minor));
-
- if (ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) {
-
- f->close();
- memdelete(f);
- ERR_EXPLAIN("File Format '"+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+p_file);
- ERR_FAIL_V(NULL);
-
- }
-
- uint32_t magic_len = f->get_32();
- Vector<char> magic;
- magic.resize(magic_len);
- f->get_buffer((uint8_t*)&magic[0],magic_len);
- String magic_str;
- magic_str.parse_utf8(&magic[0]);
-
- print_bl("magic: "+magic_str);
- if (magic_str!=p_magic) {
-
- f->close();
- memdelete(f);
- ERR_EXPLAIN("File magic mismatch, found '"+magic_str+"' in : "+p_file);
- ERR_FAIL_V(NULL);
- }
-
- print_bl("skipping 32");
- for(int i=0;i<16;i++)
- f->get_32(); //skip a few reserved fields
-
- if (f->eof_reached()) {
-
- f->close();
- memdelete(f);
- ERR_EXPLAIN("Premature End Of File: "+p_file);
- ERR_FAIL_V(NULL);
-
- }
-
- print_bl("creating loader");
- ObjectFormatLoaderBinary *loader = memnew( ObjectFormatLoaderBinary(f,endian_swap,use_real64) );
- loader->local_path=p_file;
-
- return loader;
-}
-
-void ObjectFormatLoaderInstancerBinary::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("bin");
-}
-
-
-#endif
diff --git a/core/io/object_format_binary.h b/core/io/object_format_binary.h
deleted file mode 100644
index aaf6bf357a..0000000000
--- a/core/io/object_format_binary.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*************************************************************************/
-/* object_format_binary.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef OBJECT_FORMAT_BINARY_H
-#define OBJECT_FORMAT_BINARY_H
-
-#include "object_loader.h"
-#include "object_saver_base.h"
-#include "dvector.h"
-#include "core/os/file_access.h"
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
-
-class ObjectFormatSaverBinary : public ObjectFormatSaver {
-
- String local_path;
-
-
- Ref<OptimizedSaver> optimizer;
-
- bool relative_paths;
- bool bundle_resources;
- bool skip_editor;
- bool big_endian;
- int bin_meta_idx;
- FileAccess *f;
- String magic;
- Map<RES,int> resource_map;
- Map<StringName,int> string_map;
- Vector<StringName> strings;
-
- struct SavedObject {
-
- Variant meta;
- String type;
-
-
- struct SavedProperty {
-
- int name_idx;
- Variant value;
- };
-
- List<SavedProperty> properties;
- };
-
-
- int get_string_index(const String& p_string);
- void save_unicode_string(const String& p_string);
-
- List<SavedObject*> saved_objects;
- List<SavedObject*> saved_resources;
-
- void _pad_buffer(int p_bytes);
- Error _save_obj(const Object *p_object,SavedObject *so);
- void _find_resources(const Variant& p_variant);
- void write_property(int p_idx,const Variant& p_property);
-
-
-public:
-
- virtual Error save(const Object *p_object,const Variant &p_meta);
-
- ObjectFormatSaverBinary(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer);
- ~ObjectFormatSaverBinary();
-};
-
-class ObjectFormatSaverInstancerBinary : public ObjectFormatSaverInstancer {
-public:
-
- virtual ObjectFormatSaver* instance(const String& p_file,const String& p_magic,uint32_t p_flags=0,const Ref<OptimizedSaver>& p_optimizer=Ref<OptimizedSaver>());
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
-
- virtual ~ObjectFormatSaverInstancerBinary();
-};
-
-
-
-
-/***********************************/
-/***********************************/
-/***********************************/
-/***********************************/
-
-class ObjectFormatLoaderBinary : public ObjectFormatLoader {
-
- String local_path;
-
- FileAccess *f;
-
- bool endian_swap;
- bool use_real64;
-
- Vector<char> str_buf;
- List<RES> resource_cache;
-
- Map<int,StringName> string_map;
-
- String get_unicode_string();
- void _advance_padding(uint32_t p_len);
-
-friend class ObjectFormatLoaderInstancerBinary;
-
-
- Error parse_property(Variant& r_v, int& r_index);
-
-public:
-
-
- virtual Error load(Object **p_object,Variant &p_meta);
-
- ObjectFormatLoaderBinary(FileAccess *f,bool p_endian_swap,bool p_use64);
- virtual ~ObjectFormatLoaderBinary();
-};
-
-class ObjectFormatLoaderInstancerBinary : public ObjectFormatLoaderInstancer {
-public:
-
- virtual ObjectFormatLoaderBinary* instance(const String& p_file,const String& p_magic);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
-
-
-
-};
-
-
-
-#endif // OBJECT_FORMAT_BINARY_H
-#endif
diff --git a/core/io/object_format_xml.cpp b/core/io/object_format_xml.cpp
deleted file mode 100644
index 0a8ce70d5e..0000000000
--- a/core/io/object_format_xml.cpp
+++ /dev/null
@@ -1,3190 +0,0 @@
-/*************************************************************************/
-/* object_format_xml.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifdef XML_ENABLED
-#ifdef OLD_SCENE_FORMAT_ENABLED
-#include "object_format_xml.h"
-#include "resource.h"
-#include "io/resource_loader.h"
-#include "print_string.h"
-#include "object_type_db.h"
-#include "globals.h"
-#include "os/os.h"
-#include "version.h"
-
-void ObjectFormatSaverXML::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("'","&apos;");
- p_str=p_str.replace("\"","&quot;");
- for (int i=1;i<32;i++) {
-
- char chr[2]={i,0};
- p_str=p_str.replace(chr,"&#"+String::num(i)+";");
- }
-
-
-}
-void ObjectFormatSaverXML::write_tabs(int p_diff) {
-
- for (int i=0;i<depth+p_diff;i++) {
-
- f->store_8('\t');
- }
-}
-
-void ObjectFormatSaverXML::write_string(String p_str,bool p_escape) {
-
- /* write an UTF8 string */
- if (p_escape)
- escape(p_str);
-
- f->store_string(p_str);;
- /*
- CharString cs=p_str.utf8();
- const char *data=cs.get_data();
-
- while (*data) {
- f->store_8(*data);
- data++;
- }*/
-
-
-}
-
-void ObjectFormatSaverXML::enter_tag(const String& p_section,const String& p_args) {
-
- if (p_args.length())
- write_string("<"+p_section+" "+p_args+">",false);
- else
- write_string("<"+p_section+">",false);
- depth++;
-}
-void ObjectFormatSaverXML::exit_tag(const String& p_section) {
-
- depth--;
- write_string("</"+p_section+">",false);
-
-}
-
-/*
-static bool _check_type(const Variant& p_property) {
-
- if (p_property.get_type()==Variant::_RID)
- return false;
- if (p_property.get_type()==Variant::OBJECT) {
- RES res = p_property;
- if (res.is_null())
- return false;
- }
-
- return true;
-}*/
-
-void ObjectFormatSaverXML::write_property(const String& p_name,const Variant& p_property,bool *r_ok) {
-
- if (r_ok)
- *r_ok=false;
-
- String type;
- String params;
- bool oneliner=true;
-
- switch( p_property.get_type() ) {
-
- case Variant::NIL: type="nil"; break;
- case Variant::BOOL: type="bool"; break;
- case Variant::INT: type="int"; break;
- case Variant::REAL: type="real"; break;
- case Variant::STRING: type="string"; break;
- case Variant::VECTOR2: type="vector2"; break;
- case Variant::RECT2: type="rect2"; break;
- case Variant::VECTOR3: type="vector3"; break;
- case Variant::PLANE: type="plane"; break;
- case Variant::_AABB: type="aabb"; break;
- case Variant::QUAT: type="quaternion"; break;
- case Variant::MATRIX32: type="matrix32"; break;
- case Variant::MATRIX3: type="matrix3"; break;
- case Variant::TRANSFORM: type="transform"; break;
- case Variant::COLOR: type="color"; break;
- case Variant::IMAGE: {
- type="image";
- Image img=p_property;
- if (img.empty()) {
- enter_tag(type,"name=\""+p_name+"\"");
- exit_tag(type);
- if (r_ok)
- *r_ok=true;
- return;
- }
- params+="encoding=\"raw\"";
- params+=" width=\""+itos(img.get_width())+"\"";
- params+=" height=\""+itos(img.get_height())+"\"";
- params+=" mipmaps=\""+itos(img.get_mipmaps())+"\"";
-
- switch(img.get_format()) {
-
- case Image::FORMAT_GRAYSCALE: params+=" format=\"grayscale\""; break;
- case Image::FORMAT_INTENSITY: params+=" format=\"intensity\""; break;
- case Image::FORMAT_GRAYSCALE_ALPHA: params+=" format=\"grayscale_alpha\""; break;
- case Image::FORMAT_RGB: params+=" format=\"rgb\""; break;
- case Image::FORMAT_RGBA: params+=" format=\"rgba\""; break;
- case Image::FORMAT_INDEXED : params+=" format=\"indexed\""; break;
- case Image::FORMAT_INDEXED_ALPHA: params+=" format=\"indexed_alpha\""; break;
- case Image::FORMAT_BC1: params+=" format=\"bc1\""; break;
- case Image::FORMAT_BC2: params+=" format=\"bc2\""; break;
- case Image::FORMAT_BC3: params+=" format=\"bc3\""; break;
- case Image::FORMAT_BC4: params+=" format=\"bc4\""; break;
- case Image::FORMAT_BC5: params+=" format=\"bc5\""; break;
- case Image::FORMAT_CUSTOM: params+=" format=\"custom\" custom_size=\""+itos(img.get_data().size())+"\""; break;
- default: {}
- }
- } break;
- case Variant::NODE_PATH: type="node_path"; break;
- case Variant::OBJECT: {
- type="resource";
- RES res = p_property;
- if (res.is_null()) {
- enter_tag(type,"name=\""+p_name+"\"");
- exit_tag(type);
- if (r_ok)
- *r_ok=true;
-
- return; // don't save it
- }
-
- params="resource_type=\""+res->get_type()+"\"";
-
- 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_map.has(res));
-
- params+=" path=\"local://"+itos(resource_map[res])+"\"";
- }
-
- } break;
- case Variant::INPUT_EVENT: type="input_event"; break;
- case Variant::DICTIONARY: type="dictionary" ; oneliner=false; break;
- case Variant::ARRAY: type="array"; params="len=\""+itos(p_property.operator Array().size())+"\""; oneliner=false; break;
-
- case Variant::RAW_ARRAY: type="raw_array"; params="len=\""+itos(p_property.operator DVector < uint8_t >().size())+"\""; break;
- case Variant::INT_ARRAY: type="int_array"; params="len=\""+itos(p_property.operator DVector < int >().size())+"\""; break;
- case Variant::REAL_ARRAY: type="real_array"; params="len=\""+itos(p_property.operator DVector < real_t >().size())+"\""; break;
- case Variant::STRING_ARRAY: type="string_array"; params="len=\""+itos(p_property.operator DVector < String >().size())+"\""; break;
- case Variant::VECTOR2_ARRAY: type="vector2_array"; params="len=\""+itos(p_property.operator DVector < Vector2 >().size())+"\""; break;
- case Variant::VECTOR3_ARRAY: type="vector3_array"; params="len=\""+itos(p_property.operator DVector < Vector3 >().size())+"\""; break;
- case Variant::COLOR_ARRAY: type="color_array"; params="len=\""+itos(p_property.operator DVector < Color >().size())+"\""; break;
- default: {
-
- ERR_PRINT("Unknown Variant type.");
- ERR_FAIL();
- }
-
- }
-
- write_tabs();
-
- if (p_name!="") {
- if (params.length())
- enter_tag(type,"name=\""+p_name+"\" "+params);
- else
- enter_tag(type,"name=\""+p_name+"\"");
- } else {
- if (params.length())
- enter_tag(type," "+params);
- else
- enter_tag(type,"");
- }
-
- if (!oneliner)
- write_string("\n",false);
- else
- write_string(" ",false);
-
-
- switch( p_property.get_type() ) {
-
- case Variant::NIL: {
-
- } break;
- case Variant::BOOL: {
-
- write_string( p_property.operator bool() ? "True":"False" );
- } break;
- case Variant::INT: {
-
- write_string( itos(p_property.operator int()) );
- } break;
- case Variant::REAL: {
-
- write_string( rtos(p_property.operator real_t()) );
- } break;
- case Variant::STRING: {
-
- String str=p_property;
- escape(str);
- str="\""+str+"\"";
- write_string( str,false );
- } break;
- case Variant::VECTOR2: {
-
- Vector2 v = p_property;
- write_string( rtoss(v.x) +", "+rtoss(v.y) );
- } break;
- case Variant::RECT2: {
-
- Rect2 aabb = p_property;
- write_string( rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) );
-
- } break;
- case Variant::VECTOR3: {
-
- Vector3 v = p_property;
- write_string( rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z) );
- } break;
- case Variant::PLANE: {
-
- Plane p = p_property;
- write_string( rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d) );
-
- } break;
- case Variant::_AABB: {
-
- AABB aabb = p_property;
- write_string( 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_property;
- write_string( rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+", ");
-
- } break;
- case Variant::MATRIX32: {
-
- String s;
- Matrix32 m3 = p_property;
- 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] );
- }
- }
-
- write_string(s);
-
- } break;
- case Variant::MATRIX3: {
-
- String s;
- Matrix3 m3 = p_property;
- 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] );
- }
- }
-
- write_string(s);
-
- } break;
- case Variant::TRANSFORM: {
-
- String s;
- Transform t = p_property;
- 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);
-
- write_string(s);
- } break;
-
- // misc types
- case Variant::COLOR: {
-
- Color c = p_property;
- write_string( rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a) );
-
- } break;
- case Variant::IMAGE: {
-
- String s;
- Image img = p_property;
- 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++) {
-
- uint8_t byte = ptr[i];
- const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
- char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
- s+=str;
- }
-
- write_string(s);
- } break;
- case Variant::NODE_PATH: {
-
- String str=p_property;
- escape(str);
- str="\""+str+"\"";
- write_string( str,false);
-
- } break;
-
- case Variant::OBJECT: {
- /* this saver does not save resources in here
- RES res = p_property;
-
- if (!res.is_null()) {
-
- String path=res->get_path();
- if (!res->is_shared() || !path.length()) {
- // if no path, or path is from inside a scene
- write_object( *res );
- }
-
- }
- */
-
- } break;
- case Variant::INPUT_EVENT: {
-
- write_string( p_property.operator String() );
- } break;
- case Variant::DICTIONARY: {
-
- Dictionary dict = p_property;
-
-
- List<Variant> keys;
- dict.get_key_list(&keys);
-
- for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
-
- //if (!_check_type(dict[E->get()]))
- // continue;
-
- bool ok;
- write_property("",E->get(),&ok);
- ERR_CONTINUE(!ok);
-
- write_property("",dict[E->get()],&ok);
- if (!ok)
- write_property("",Variant()); //at least make the file consistent..
- }
-
-
-
-
- } break;
- case Variant::ARRAY: {
-
- Array array = p_property;
- int len=array.size();
- for (int i=0;i<len;i++) {
-
- write_property("",array[i]);
-
- }
-
- } break;
-
- case Variant::RAW_ARRAY: {
-
- String s;
- DVector<uint8_t> data = p_property;
- int len = data.size();
- DVector<uint8_t>::Read r = data.read();
- const uint8_t *ptr=r.ptr();;
- for (int i=0;i<len;i++) {
-
- uint8_t byte = ptr[i];
- const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
- char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
- s+=str;
- }
-
- write_string(s,false);
-
- } break;
- case Variant::INT_ARRAY: {
-
- DVector<int> data = p_property;
- int len = data.size();
- DVector<int>::Read r = data.read();
- const int *ptr=r.ptr();;
- write_tabs();
-
- for (int i=0;i<len;i++) {
-
- if (i>0)
- write_string(", ",false);
-
- write_string(itos(ptr[i]),false);
- }
-
-
-
- } break;
- case Variant::REAL_ARRAY: {
-
- DVector<real_t> data = p_property;
- int len = data.size();
- DVector<real_t>::Read r = data.read();
- const real_t *ptr=r.ptr();;
- write_tabs();
-
- for (int i=0;i<len;i++) {
-
- if (i>0)
- write_string(", ",false);
- write_string(rtoss(ptr[i]),false);
- }
-
-
- } break;
- case Variant::STRING_ARRAY: {
-
- DVector<String> data = p_property;
- int len = data.size();
- DVector<String>::Read r = data.read();
- const String *ptr=r.ptr();;
- String s;
-
- for (int i=0;i<len;i++) {
-
- if (i>0)
- s+=", ";
- String str=ptr[i];
- escape(str);
- s=s+"\""+str+"\"";
- }
-
- write_string(s,false);
-
- } break;
- case Variant::VECTOR2_ARRAY: {
-
- DVector<Vector2> data = p_property;
- int len = data.size();
- DVector<Vector2>::Read r = data.read();
- const Vector2 *ptr=r.ptr();;
- write_tabs();
-
- for (int i=0;i<len;i++) {
-
- if (i>0)
- write_string(", ",false);
- write_string(rtoss(ptr[i].x),false);
- write_string(", "+rtoss(ptr[i].y),false);
-
- }
-
-
- } break;
- case Variant::VECTOR3_ARRAY: {
-
- DVector<Vector3> data = p_property;
- int len = data.size();
- DVector<Vector3>::Read r = data.read();
- const Vector3 *ptr=r.ptr();;
- write_tabs();
-
- for (int i=0;i<len;i++) {
-
- if (i>0)
- write_string(", ",false);
- write_string(rtoss(ptr[i].x),false);
- write_string(", "+rtoss(ptr[i].y),false);
- write_string(", "+rtoss(ptr[i].z),false);
-
- }
-
-
- } break;
- case Variant::COLOR_ARRAY: {
-
- DVector<Color> data = p_property;
- int len = data.size();
- DVector<Color>::Read r = data.read();
- const Color *ptr=r.ptr();;
- write_tabs();
-
- for (int i=0;i<len;i++) {
-
- if (i>0)
- write_string(", ",false);
-
- write_string(rtoss(ptr[i].r),false);
- write_string(", "+rtoss(ptr[i].g),false);
- write_string(", "+rtoss(ptr[i].b),false);
- write_string(", "+rtoss(ptr[i].a),false);
-
- }
-
- } break;
- default: {}
-
- }
- if (oneliner)
- write_string(" ");
- else
- write_tabs(-1);
- exit_tag(type);
-
- write_string("\n",false);
-
- if (r_ok)
- *r_ok=true;
-
-}
-
-
-void ObjectFormatSaverXML::_find_resources(const Variant& p_variant) {
-
-
- switch(p_variant.get_type()) {
- case Variant::OBJECT: {
-
-
-
- RES res = p_variant.operator RefPtr();
-
- if (res.is_null())
- return;
-
- if (!bundle_resources && res->get_path().length() && res->get_path().find("::") == -1 )
- return;
-
- if (resource_map.has(res))
- return;
-
- List<PropertyInfo> property_list;
-
- res->get_property_list( &property_list );
-
- 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_map[ res ] = resource_map.size(); //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 ObjectFormatSaverXML::save(const Object *p_object,const Variant &p_meta) {
-
- ERR_FAIL_COND_V(!f,ERR_UNCONFIGURED);
- ERR_EXPLAIN("write_object should supply either an object, a meta, or both");
- ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER);
-
- SavedObject *so = memnew( SavedObject );
-
- if (p_object)
- so->type=p_object->get_type();
-
- _find_resources(p_meta);
- so->meta=p_meta;
-
- if (p_object) {
-
-
- if (optimizer.is_valid()) {
- //use optimizer
-
- List<OptimizedSaver::Property> props;
- optimizer->get_property_list(p_object,&props);
-
- for(List<OptimizedSaver::Property>::Element *E=props.front();E;E=E->next()) {
-
- if (skip_editor && String(E->get().name).begins_with("__editor"))
- continue;
- _find_resources(E->get().value);
- SavedObject::SavedProperty sp;
- sp.name=E->get().name;
- sp.value=E->get().value;
- so->properties.push_back(sp);
- }
-
- } else {
- //use classic way
- List<PropertyInfo> property_list;
- p_object->get_property_list( &property_list );
-
- for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) {
-
- if (skip_editor && E->get().name.begins_with("__editor"))
- continue;
- if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) {
-
- SavedObject::SavedProperty sp;
- sp.name=E->get().name;
- sp.value = p_object->get(E->get().name);
- _find_resources(sp.value);
- so->properties.push_back(sp);
- }
- }
- }
-
- }
-
- saved_objects.push_back(so);
-
- return OK;
-}
-
-ObjectFormatSaverXML::ObjectFormatSaverXML(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
-
- optimizer=p_optimizer;
- relative_paths=p_flags&ObjectSaver::FLAG_RELATIVE_PATHS;
- skip_editor=p_flags&ObjectSaver::FLAG_OMIT_EDITOR_PROPERTIES;
- bundle_resources=p_flags&ObjectSaver::FLAG_BUNDLE_RESOURCES;
- f=p_file; // should be already opened
- depth=0;
- local_path=p_local_path;
- magic=p_magic;
-}
-ObjectFormatSaverXML::~ObjectFormatSaverXML() {
-
- write_string("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",false); //no escape
- write_string("\n",false);
- enter_tag("object_file","magic=\""+magic+"\" "+"version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\"");
- write_string("\n",false);
-
- // save resources
-
- for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
-
- RES res = E->get();
- ERR_CONTINUE(!resource_map.has(res));
-
- write_tabs();
- if (res->get_path().length() && res->get_path().find("::") == -1 )
- enter_tag("resource","type=\""+res->get_type()+"\" path=\""+res->get_path()+"\""); //bundled
- else
- enter_tag("resource","type=\""+res->get_type()+"\" path=\"local://"+itos(resource_map[res])+"\"");
-
- if (optimizer.is_valid()) {
-
- List<OptimizedSaver::Property> props;
- optimizer->get_property_list(res.ptr(),&props);
-
- for(List<OptimizedSaver::Property>::Element *E=props.front();E;E=E->next()) {
-
- if (skip_editor && String(E->get().name).begins_with("__editor"))
- continue;
-
- write_property(E->get().name,E->get().value);
- }
-
-
- } else {
-
- List<PropertyInfo> property_list;
- res->get_property_list(&property_list);
- 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);
- write_property(name,value);
- }
-
-
- }
-
- }
- write_tabs(-1);
- exit_tag("resource");
- write_string("\n",false);
- }
-
- if (!saved_objects.empty()) {
-
-
- for(List<SavedObject*>::Element *E=saved_objects.front();E;E=E->next()) {
-
- SavedObject *so = E->get();
-
-
-
- write_tabs();
- if (so->type!="")
- enter_tag("object","type=\""+so->type+"\"");
- else
- enter_tag("object");
- write_string("\n",false);
-
- if (so->meta.get_type()!=Variant::NIL) {
-
- write_property("__xml_meta__",so->meta);
-
- }
-
- List<SavedObject::SavedProperty>::Element *SE = so->properties.front();
-
- while(SE) {
-
- write_property(SE->get().name,SE->get().value);
- SE=SE->next();
- }
-
-
- write_tabs(-1);
- exit_tag("object");
- write_string("\n",false);
- memdelete(so); //no longer needed
- }
-
-
- } else {
-
- WARN_PRINT("File contains no saved objects.");
- }
-
- exit_tag("object_file");
- f->close();
- memdelete(f);
-}
-
-
-ObjectFormatSaver* ObjectFormatSaverInstancerXML::instance(const String& p_file,const String& p_magic,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
-
- Error err;
- FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE,&err);
-
- ERR_FAIL_COND_V( err, NULL );
- String local_path = Globals::get_singleton()->localize_path(p_file);
-
- return memnew( ObjectFormatSaverXML( f, p_magic,local_path,p_flags,p_optimizer ) );
-}
-
-void ObjectFormatSaverInstancerXML::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("xml");
-}
-
-
-ObjectFormatSaverInstancerXML::~ObjectFormatSaverInstancerXML() {
-
-
-}
-
-/************************************************/
-/************************************************/
-/************************************************/
-/************************************************/
-/************************************************/
-
-
-
-#ifdef OPTIMIZED_XML_LOADER
-
-#define IS_FLOAT_CHAR(m_c) \
- ((m_c>='0' && m_c<='9') || m_c=='e' || m_c=='-' || m_c=='+' || m_c=='.')
-
-#define XML_FAIL(m_cond,m_err) \
- if (m_cond) {\
- ERR_EXPLAIN(local_path+":"+itos(parser->get_current_line())+": "+String(m_err));\
- ERR_FAIL_COND_V( m_cond, ERR_FILE_CORRUPT );\
- }
-
-
-Error ObjectFormatLoaderXML::_parse_property(Variant& r_v,String& r_name) {
-
- XML_FAIL( parser->is_empty(), "unexpected empty tag");
-
- String type=parser->get_node_name();
- String name=parser->get_attribute_value_safe("name");
-
- r_v=Variant();
- r_name=name;
-
- if (type=="dictionary") {
-
- Dictionary d;
- int reading=0;
- Variant key;
- while(parser->read()==OK) {
-
- if (parser->get_node_type()==XMLParser::NODE_ELEMENT) {
- Error err;
- String tagname;
-
- if (reading==0) {
-
- err=_parse_property(key,tagname);
- XML_FAIL( err,"error parsing dictionary key: "+name);
- reading++;
- } else {
-
- reading=0;
- Variant value;
- err=_parse_property(value,tagname);
- XML_FAIL( err,"error parsing dictionary value: "+name);
- d[key]=value;
- }
-
- } else if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="dictionary") {
- r_v=d;
- return OK;
- }
- }
-
-
- XML_FAIL( true, "unexpected end of file while reading dictionary: "+name);
-
- } else if (type=="array") {
-
- XML_FAIL( !parser->has_attribute("len"), "array missing 'len' attribute");
-
- int len=parser->get_attribute_value("len").to_int();
-
- Array array;
- array.resize(len);
-
-
- Variant v;
- String tagname;
- int idx=0;
-
-
- while(parser->read()==OK) {
-
- if (parser->get_node_type()==XMLParser::NODE_ELEMENT) {
-
- XML_FAIL( idx >= len, "array size mismatch (too many elements)");
- Error err;
- String tagname;
- Variant key;
-
- err=_parse_property(key,tagname);
- XML_FAIL( err,"error parsing element of array: "+name);
- array[idx]=key;
- idx++;
-
-
- } else if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="array") {
-
- XML_FAIL( idx != len, "array size mismatch (not "+itos(len)+"):"+name);
- r_v=array;
- return OK;
- }
- }
-
- XML_FAIL( true, "unexpected end of file while reading dictionary: "+name);
-
- } else if (type=="resource") {
-
-
- XML_FAIL(!parser->has_attribute("path"),"resource property has no 'path' set (embedding not supported).")
-
- String path=parser->get_attribute_value("path");
- String hint = parser->get_attribute_value_safe("resource_type");
-
- if (path.begins_with("local://"))
- path=path.replace("local://",local_path+"::");
- else 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()+"/"+path);
-
- }
-
- //take advantage of the resource loader cache. The resource is cached on it, even if
- RES res=ResourceLoader::load(path,hint);
-
-
- if (res.is_null()) {
-
- WARN_PRINT(String("Couldn't load resource: "+path).ascii().get_data());
- }
-
- r_v=res.get_ref_ptr();
-
- } else if (type=="image") {
-
- if (parser->has_attribute("encoding")) { //there is image data
-
- String encoding=parser->get_attribute_value("encoding");
-
- if (encoding=="raw") {
-
- //raw image (bytes)
-
- XML_FAIL( !parser->has_attribute("width"), "missing attribute in raw encoding: 'width'.");
- XML_FAIL( !parser->has_attribute("height"), "missing attribute in raw encoding: 'height'.");
- XML_FAIL( !parser->has_attribute("format"), "missing attribute in raw encoding: 'format'.");
-
- String format = parser->get_attribute_value("format");
- String width = parser->get_attribute_value("width");
- String height = parser->get_attribute_value("height");
-
- Image::Format imgformat;
- int chans=0;
- int pal=0;
-
- if (format=="grayscale") {
- imgformat=Image::FORMAT_GRAYSCALE;
- chans=1;
- } else if (format=="intensity") {
- imgformat=Image::FORMAT_INTENSITY;
- chans=1;
- } else if (format=="grayscale_alpha") {
- imgformat=Image::FORMAT_GRAYSCALE_ALPHA;
- chans=2;
- } else if (format=="rgb") {
- imgformat=Image::FORMAT_RGB;
- chans=3;
- } else if (format=="rgba") {
- imgformat=Image::FORMAT_RGBA;
- chans=4;
- } else if (format=="indexed") {
- imgformat=Image::FORMAT_INDEXED;
- chans=1;
- pal=256*3;
- } else if (format=="indexed_alpha") {
- imgformat=Image::FORMAT_INDEXED_ALPHA;
- chans=1;
- pal=256*4;
- } else {
-
- XML_FAIL(true, "invalid format for image: "+format);
-
- }
-
- XML_FAIL( chans==0, "invalid number of color channels in image (0).");
-
- int w=width.to_int();
- int h=height.to_int();
-
- if (w == 0 && w == 0) { //epmty, don't even bother
- //r_v = Image(w, h, imgformat);
- r_v=Image();
- return OK;
- } else {
-
- //decode hexa
-
- DVector<uint8_t> pixels;
- pixels.resize(chans*w*h+pal);
- int pixels_size=pixels.size();
- XML_FAIL( pixels_size==0, "corrupt");
-
- ERR_FAIL_COND_V(pixels_size==0,ERR_FILE_CORRUPT);
- DVector<uint8_t>::Write wr=pixels.write();
- uint8_t *bytes=wr.ptr();
-
- XML_FAIL( parser->read()!=OK, "error reading" );
- XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
-
- String text = parser->get_node_data().strip_edges();
- XML_FAIL( text.length()/2 != pixels_size, "unexpected image data size" );
-
- for(int i=0;i<pixels_size*2;i++) {
-
- uint8_t byte;
- CharType c=text[i];
-
- if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
-
- if (i&1) {
-
- byte|=HEX2CHR(c);
- bytes[i>>1]=byte;
- } else {
-
- byte=HEX2CHR(c)<<4;
- }
-
-
- }
- }
-
- wr=DVector<uint8_t>::Write();
- r_v=Image(w,h,imgformat,pixels);
- }
- }
-
- } else {
- r_v=Image(); // empty image, since no encoding defined
- }
-
- } else if (type=="raw_array") {
-
- XML_FAIL( !parser->has_attribute("len"), "array missing 'len' attribute");
-
- int len=parser->get_attribute_value("len").to_int();
- if (len>0) {
-
- XML_FAIL( parser->read()!=OK, "error reading" );
- XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
- String text = parser->get_node_data();
-
- XML_FAIL( text.length() != len*2, "raw array length mismatch" );
-
- DVector<uint8_t> bytes;
- bytes.resize(len);
- DVector<uint8_t>::Write w=bytes.write();
- uint8_t *bytesptr=w.ptr();
-
-
- for(int i=0;i<len*2;i++) {
-
- uint8_t byte;
- CharType c=text[i];
-
- if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
-
- if (i&1) {
-
- byte|=HEX2CHR(c);
- bytesptr[i>>1]=byte;
- } else {
-
- byte=HEX2CHR(c)<<4;
- }
- }
- }
-
- w=DVector<uint8_t>::Write();
- r_v=bytes;
- }
-
- } else if (type=="int_array") {
-
- int len=parser->get_attribute_value("len").to_int();
-
- if (len>0) {
-
- XML_FAIL( parser->read()!=OK, "error reading" );
- XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
- String text = parser->get_node_data();
-
- const CharType *c=text.c_str();
- DVector<int> varray;
- varray.resize(len);
- DVector<int>::Write w = varray.write();
-
- int idx=0;
- const CharType *from=c-1;
-
- while(*c) {
-
- bool ischar = (*c >='0' && *c<='9') || *c=='+' || *c=='-';
- if (!ischar) {
-
- if (int64_t(c-from)>1) {
-
- int i = String::to_int(from+1,int64_t(c-from));
- w[idx++]=i;
- }
-
- from=c;
- } else {
-
- XML_FAIL( idx >= len, "array too big");
- }
-
- c++;
- }
-
- XML_FAIL( idx != len, "array size mismatch");
-
- w = varray.write();
- r_v=varray;
- }
-
-
-
- } else if (type=="real_array") {
-
- int len=parser->get_attribute_value("len").to_int();
-
- if (len>0) {
-
- XML_FAIL( parser->read()!=OK, "error reading" );
- XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
- String text = parser->get_node_data();
-
- const CharType *c=text.c_str();
- DVector<real_t> varray;
- varray.resize(len);
- DVector<real_t>::Write w = varray.write();
-
- int idx=0;
- const CharType *from=c-1;
-
- while(*c) {
-
- bool ischar = IS_FLOAT_CHAR((*c));
- if (!ischar) {
-
- if (int64_t(c-from)>1) {
-
- real_t f = String::to_double(from+1,int64_t(c-from));
- w[idx++]=f;
- }
-
- from=c;
- } else {
-
- XML_FAIL( idx >= len, "array too big");
- }
-
- c++;
- }
-
- XML_FAIL( idx != len, "array size mismatch");
-
- w = varray.write();
- r_v=varray;
- }
-
- } else if (type=="string_array") {
-
-
- // this is invalid xml, and will have to be fixed at some point..
-
- int len=parser->get_attribute_value("len").to_int();
-
- if (len>0) {
-
- XML_FAIL( parser->read()!=OK, "error reading" );
- XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
- String text = parser->get_node_data();
-
- const CharType *c=text.c_str();
- DVector<String> sarray;
- sarray.resize(len);
- DVector<String>::Write w = sarray.write();
-
-
- bool inside=false;
- const CharType *from=c;
- int idx=0;
-
- while(*c) {
-
- if (inside) {
-
- if (*c == '"') {
- inside=false;
- String s = String(from,int64_t(c-from));
- w[idx]=s;
- idx++;
- }
- } else {
-
- if (*c == '"') {
- inside=true;
- from=c+1;
- XML_FAIL( idx>=len, "string array is too big!!: "+name);
- }
- }
-
- c++;
- }
-
- XML_FAIL( inside, "unterminated string array: "+name);
- XML_FAIL( len != idx, "string array size mismatch: "+name);
-
- w = DVector<String>::Write();
-
- r_v=sarray;
-
- }
- } else if (type=="vector3_array") {
-
- int len=parser->get_attribute_value("len").to_int();
-
- if (len>0) {
-
- XML_FAIL( parser->read()!=OK, "error reading" );
- XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
- String text = parser->get_node_data();
-
- const CharType *c=text.c_str();
- DVector<Vector3> varray;
- varray.resize(len);
- DVector<Vector3>::Write w = varray.write();
-
- int idx=0;
- int sidx=0;
- Vector3 v;
- const CharType *from=c-1;
-
- while(*c) {
-
- bool ischar = IS_FLOAT_CHAR((*c));
- if (!ischar) {
-
- if (int64_t(c-from)>1) {
-
- real_t f = String::to_double(from+1,int64_t(c-from));
- v[sidx++]=f;
- if (sidx==3) {
- w[idx++]=v;
- sidx=0;
-
- }
- }
-
- from=c;
- } else {
-
- XML_FAIL( idx >= len, "array too big");
- }
-
- c++;
- }
-
- XML_FAIL( idx != len, "array size mismatch");
-
- w = varray.write();
- r_v=varray;
- }
-
- } else if (type=="color_array") {
-
- int len=parser->get_attribute_value("len").to_int();
-
- if (len>0) {
-
- XML_FAIL( parser->read()!=OK, "error reading" );
- XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
- String text = parser->get_node_data();
-
- const CharType *c=text.c_str();
- DVector<Color> carray;
- carray.resize(len);
- DVector<Color>::Write w = carray.write();
-
- int idx=0;
- int sidx=0;
- Color v;
- const CharType *from=c-1;
-
- while(*c) {
-
- bool ischar = IS_FLOAT_CHAR((*c));
- if (!ischar) {
-
- if (int64_t(c-from)>1) {
-
- real_t f = String::to_double(from+1,int64_t(c-from));
- v[sidx++]=f;
- if (sidx==4) {
- w[idx++]=v;
- sidx=0;
-
- }
- }
-
- from=c;
- } else {
-
- XML_FAIL( idx >= len, "array too big");
- }
-
- c++;
- }
-
- XML_FAIL( idx != len, "array size mismatch");
-
- w = carray.write();
- r_v=carray;
- }
- } else {
- // simple string parsing code
- XML_FAIL( parser->read()!=OK, "can't read data" );
-
- String data=parser->get_node_data();
- data=data.strip_edges();
-
- if (type=="nil") {
- // uh do nothing
-
- } else if (type=="bool") {
- // uh do nothing
- if (data.nocasecmp_to("true")==0 || data.to_int()!=0)
- r_v=true;
- else
- r_v=false;
-
- } else if (type=="int") {
-
- r_v=data.to_int();
- } else if (type=="real") {
-
- r_v=data.to_double();
- } else if (type=="string") {
-
- String str=data;
- str=str.substr(1,str.length()-2);
- r_v=str;
- } else if (type=="vector3") {
-
- r_v=Vector3(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double()
- );
-
- } else if (type=="vector2") {
-
-
- r_v=Vector2(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",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()
- );
-
- } 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()
- );
-
- } else if (type=="rect2") {
-
- r_v=Rect2(
- Vector2(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double()
- ),
- Vector2(
- data.get_slice(",",2).to_double(),
- data.get_slice(",",3).to_double()
- )
- );
-
-
- } else if (type=="aabb") {
-
- r_v=AABB(
- Vector3(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double()
- ),
- Vector3(
- data.get_slice(",",3).to_double(),
- data.get_slice(",",4).to_double(),
- data.get_slice(",",5).to_double()
- )
- );
-
-
- } else if (type=="matrix3") {
-
- 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();
- }
- }
- r_v=m3;
-
- } else if (type=="transform") {
-
- 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.origin=Vector3(
- data.get_slice(",",9).to_double(),
- data.get_slice(",",10).to_double(),
- data.get_slice(",",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()
- );
-
- } else if (type=="node_path") {
-
- String str=data;
- str=str.substr(1,str.length()-2);
- r_v=NodePath( str );
-
- } else if (type=="input_event") {
-
- // ?
- } else {
-
- XML_FAIL(true,"unrecognized property tag: "+type);
- }
- }
-
- _close_tag(type);
-
- return OK;
-}
-
-
-
-
-Error ObjectFormatLoaderXML::_close_tag(const String& p_tag) {
-
- int c=1;
-
- while(parser->read()==OK) {
-
-
- if (parser->get_node_type()==XMLParser::NODE_ELEMENT && parser->get_node_name()==p_tag) {
- c++;
- } else if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()==p_tag) {
- c--;
-
- if (c==0)
- return OK;
- }
-
- }
-
- return ERR_FILE_CORRUPT;
-}
-
-Error ObjectFormatLoaderXML::load(Object **p_object,Variant &p_meta) {
-
- *p_object=NULL;
- p_meta=Variant();
-
- while(parser->read()==OK) {
-
- if (parser->get_node_type()==XMLParser::NODE_ELEMENT) {
-
- String name = parser->get_node_name();
-
-
- XML_FAIL( !parser->has_attribute("type"), "'type' attribute missing." );
- String type = parser->get_attribute_value("type");
-
-
- Object *obj=NULL;
- Ref<Resource> resource;
- if (name=="resource") {
-
- XML_FAIL( !parser->has_attribute("path"), "'path' attribute missing." );
- String path = parser->get_attribute_value("path");
-
- XML_FAIL(!path.begins_with("local://"),"path does not begin with 'local://'");
-
-
- path=path.replace("local://",local_path+"::");
-
- if (ResourceCache::has(path)) {
- Error err = _close_tag(name);
- XML_FAIL( err, "error skipping resource.");
- continue; //it's a resource, and it's already loaded
-
- }
-
- obj = ObjectTypeDB::instance(type);
- XML_FAIL(!obj,"couldn't instance object of type: '"+type+"'");
-
- Resource *r = obj->cast_to<Resource>();
- XML_FAIL(!obj,"object isn't of type Resource: '"+type+"'");
-
- resource = RES( r );
- r->set_path(path);
-
-
- } else if (name=="object") {
-
-
- if (ObjectTypeDB::can_instance(type)) {
- obj = ObjectTypeDB::instance(type);
- XML_FAIL(!obj,"couldn't instance object of type: '"+type+"'");
- } else {
-
- _close_tag(name);
- return ERR_SKIP;
- };
- } else {
- XML_FAIL(true,"Unknown main tag: "+parser->get_node_name());
- }
-
- //load properties
-
- while (parser->read()==OK) {
-
- if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()==name)
- break;
- else if (parser->get_node_type()==XMLParser::NODE_ELEMENT) {
-
- String name;
- Variant v;
- Error err;
- err = _parse_property(v,name);
- XML_FAIL(err,"Error parsing property: "+name);
-
- if (resource.is_null() && name=="__xml_meta__") {
-
- p_meta=v;
- continue;
- } else {
-
- XML_FAIL( !obj, "Normal property found in meta object");
-
- }
-
- obj->set(name,v);
-
-
- }
- }
-
-
- if (!obj) {
- *p_object=NULL;
- return OK; // it was a meta object
- }
-
- if (resource.is_null()) {
- //regular object
- *p_object=obj;
- return OK;
- } else {
-
- resource_cache.push_back(resource); //keep it in mem until finished loading and load next
- }
-
-
- } else if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="object_file")
- return ERR_FILE_EOF;
- }
-
- return OK; //never reach anyway
-}
-
-ObjectFormatLoaderXML* ObjectFormatLoaderInstancerXML::instance(const String& p_file,const String& p_magic) {
-
- Ref<XMLParser> parser = memnew( XMLParser );
-
- Error err = parser->open(p_file);
- ERR_FAIL_COND_V(err,NULL);
-
- ObjectFormatLoaderXML *loader = memnew( ObjectFormatLoaderXML );
-
- loader->parser=parser;
- loader->local_path = Globals::get_singleton()->localize_path(p_file);
-
- while(parser->read()==OK) {
-
- if (parser->get_node_type()==XMLParser::NODE_ELEMENT && parser->get_node_name()=="object_file") {
-
- ERR_FAIL_COND_V( parser->is_empty(), NULL );
-
- String version = parser->get_attribute_value_safe("version");
- String magic = parser->get_attribute_value_safe("MAGIC");
-
- if (version.get_slice_count(".")!=2) {
-
- ERR_EXPLAIN("Invalid Version String '"+version+"'' in file: "+p_file);
- ERR_FAIL_V(NULL);
- }
-
- int major = version.get_slice(".",0).to_int();
- int minor = version.get_slice(".",1).to_int();
-
- if (major>VERSION_MAJOR || (major==VERSION_MAJOR && minor>VERSION_MINOR)) {
-
- ERR_EXPLAIN("File Format '"+version+"' is too new! Please upgrade to a a new engine version: "+p_file);
- ERR_FAIL_V(NULL);
-
- }
-
- return loader;
- }
-
- }
-
- ERR_EXPLAIN("No data found in file!");
- ERR_FAIL_V(NULL);
-}
-
-void ObjectFormatLoaderInstancerXML::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("xml");
-}
-
-
-
-#else
-
-ObjectFormatLoaderXML::Tag* ObjectFormatLoaderXML::parse_tag(bool *r_exit) {
-
-
- while(get_char()!='<' && !f->eof_reached()) {}
- if (f->eof_reached())
- return NULL;
-
- Tag tag;
- bool exit=false;
- if (r_exit)
- *r_exit=false;
-
- bool complete=false;
- while(!f->eof_reached()) {
-
- CharType c=get_char();
- if (c<33 && tag.name.length() && !exit) {
- break;
- } else if (c=='>') {
- complete=true;
- break;
- } else if (c=='/') {
- exit=true;
- } else {
- tag.name+=c;
- }
- }
-
- if (f->eof_reached())
- return NULL;
-
- if (exit) {
- if (!tag_stack.size()) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unmatched exit tag </"+tag.name+">");
- ERR_FAIL_COND_V(!tag_stack.size(),NULL);
- }
-
- if (tag_stack.back()->get().name!=tag.name) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Mismatched exit tag. Got </"+tag.name+">, expected </"+tag_stack.back()->get().name+">");
- ERR_FAIL_COND_V(tag_stack.back()->get().name!=tag.name,NULL);
- }
-
- if (!complete) {
- while(get_char()!='>' && !f->eof_reached()) {}
- if (f->eof_reached())
- return NULL;
- }
-
- if (r_exit)
- *r_exit=true;
-
- tag_stack.pop_back();
- return NULL;
-
- }
-
- if (!complete) {
- String name;
- String value;
- bool reading_value=false;
-
- while(!f->eof_reached()) {
-
- CharType c=get_char();
- if (c=='>') {
- if (value.length()) {
-
- tag.args[name]=value;
- }
- break;
-
- } else if ( ((!reading_value && (c<33)) || c=='=' || c=='"') && tag.name.length()) {
-
- if (!reading_value && name.length()) {
-
- reading_value=true;
- } else if (reading_value && value.length()) {
-
- tag.args[name]=value;
- name="";
- value="";
- reading_value=false;
- }
-
- } else if (reading_value) {
-
- value+=c;
- } else {
-
- name+=c;
- }
- }
-
- if (f->eof_reached())
- return NULL;
- }
-
- tag_stack.push_back(tag);
-
- return &tag_stack.back()->get();
-}
-
-
-Error ObjectFormatLoaderXML::close_tag(const String& p_name) {
-
- int level=0;
- bool inside_tag=false;
-
- while(true) {
-
- if (f->eof_reached()) {
-
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": EOF found while attempting to find </"+p_name+">");
- ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
- }
-
- uint8_t c = get_char();
-
- if (c == '<') {
-
- if (inside_tag) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML. Already inside Tag.");
- ERR_FAIL_COND_V(inside_tag,ERR_FILE_CORRUPT);
- }
- inside_tag=true;
- c = get_char();
- if (c == '/') {
-
- --level;
- } else {
-
- ++level;
- };
- } else if (c == '>') {
-
- if (!inside_tag) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML. Already outside Tag");
- ERR_FAIL_COND_V(!inside_tag,ERR_FILE_CORRUPT);
- }
- inside_tag=false;
- if (level == -1) {
- tag_stack.pop_back();
- return OK;
- };
- };
- }
-
- return OK;
-}
-
-void ObjectFormatLoaderXML::unquote(String& p_str) {
-
- p_str=p_str.strip_edges();
- p_str=p_str.replace("\"","");
- p_str=p_str.replace("&gt;","<");
- p_str=p_str.replace("&lt;",">");
- p_str=p_str.replace("&apos;","'");
- p_str=p_str.replace("&quot;","\"");
- for (int i=1;i<32;i++) {
-
- char chr[2]={i,0};
- p_str=p_str.replace("&#"+String::num(i)+";",chr);
- }
- p_str=p_str.replace("&amp;","&");
-
- //p_str.parse_utf8( p_str.ascii(true).get_data() );
-
-}
-
-Error ObjectFormatLoaderXML::goto_end_of_tag() {
-
- uint8_t c;
- while(true) {
-
- c=get_char();
- if (c=='>') //closetag
- break;
- if (f->eof_reached()) {
-
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": EOF found while attempting to find close tag.");
- ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
- }
-
- }
- tag_stack.pop_back();
-
- return OK;
-}
-
-
-Error ObjectFormatLoaderXML::parse_property_data(String &r_data) {
-
- r_data="";
- CharString cs;
- while(true) {
-
- CharType c=get_char();
- if (c=='<')
- break;
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
- cs.push_back(c);
- }
-
- cs.push_back(0);
-
- r_data.parse_utf8(cs.get_data());
-
- while(get_char()!='>' && !f->eof_reached()) {}
- if (f->eof_reached()) {
-
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML.");
- ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
- }
-
- r_data=r_data.strip_edges();
- tag_stack.pop_back();
-
- return OK;
-}
-
-
-Error ObjectFormatLoaderXML::_parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end) {
-
- if (buff.empty())
- buff.resize(32); // optimize
-
- int buff_max=buff.size();
- int buff_size=0;
- *end=false;
- char *buffptr=&buff[0];
- bool found=false;
- bool quoted=false;
-
- while(true) {
-
- char c=get_char();
-
- if (c==0) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (zero found).");
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- } else if (c=='"') {
- quoted=!quoted;
- } else if ((!quoted && ((p_number_only && c<33) || c==',')) || c=='<') {
-
-
- if (c=='<') {
- *end=true;
- break;
- }
- if (c<32 && f->eof_reached()) {
- *end=true;
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (unexpected EOF).");
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- }
-
- if (found)
- break;
-
- } else {
-
- found=true;
- if (buff_size>=buff_max) {
-
- buff_max++;
- buff.resize(buff_max);
-
- }
-
- buffptr[buff_size]=c;
- buff_size++;
- }
- }
-
- if (buff_size>=buff_max) {
-
- buff_max++;
- buff.resize(buff_max);
-
- }
-
- buff[buff_size]=0;
- buff_size++;
-
- return OK;
-}
-
-Error ObjectFormatLoaderXML::parse_property(Variant& r_v, String &r_name) {
-
- bool exit;
- Tag *tag = parse_tag(&exit);
-
- if (!tag) {
- if (exit) // shouldn't have exited
- return ERR_FILE_EOF;
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (No Property Tag).");
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- }
-
- r_v=Variant();
- r_name="";
-
-
- //ERR_FAIL_COND_V(tag->name!="property",ERR_FILE_CORRUPT);
- //ERR_FAIL_COND_V(!tag->args.has("name"),ERR_FILE_CORRUPT);
-// ERR_FAIL_COND_V(!tag->args.has("type"),ERR_FILE_CORRUPT);
-
- //String name=tag->args["name"];
- //ERR_FAIL_COND_V(name=="",ERR_FILE_CORRUPT);
- String type=tag->name;
- String name=tag->args["name"];
-
- if (type=="") {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": 'type' field is empty.");
- ERR_FAIL_COND_V(type=="",ERR_FILE_CORRUPT);
- }
-
- if (type=="dictionary") {
-
- Dictionary d;
-
- while(true) {
-
- Error err;
- String tagname;
- Variant key;
-
- int dictline = get_current_line();
-
-
- err=parse_property(key,tagname);
-
- if (err && err!=ERR_FILE_EOF) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error parsing dictionary: "+name+" (from line "+itos(dictline)+")");
- ERR_FAIL_COND_V(err && err!=ERR_FILE_EOF,err);
- }
- //ERR_FAIL_COND_V(tagname!="key",ERR_FILE_CORRUPT);
- if (err)
- break;
- Variant value;
- err=parse_property(value,tagname);
- if (err) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error parsing dictionary: "+name+" (from line "+itos(dictline)+")");
- }
-
- ERR_FAIL_COND_V(err,err);
- //ERR_FAIL_COND_V(tagname!="value",ERR_FILE_CORRUPT);
-
- d[key]=value;
- }
-
-
- //err=parse_property_data(name); // skip the rest
- //ERR_FAIL_COND_V(err,err);
-
- r_name=name;
- r_v=d;
- return OK;
-
- } else if (type=="array") {
-
- if (!tag->args.has("len")) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
- ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
- }
-
-
- int len=tag->args["len"].to_int();
-
- Array array;
- array.resize(len);
-
- Error err;
- Variant v;
- String tagname;
- int idx=0;
- while( (err=parse_property(v,tagname))==OK ) {
-
- ERR_CONTINUE( idx <0 || idx >=len );
-
- array.set(idx,v);
- idx++;
- }
-
- if (idx!=len) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error loading array (size mismatch): "+name);
- ERR_FAIL_COND_V(idx!=len,err);
- }
-
- if (err!=ERR_FILE_EOF) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error loading array: "+name);
- ERR_FAIL_COND_V(err!=ERR_FILE_EOF,err);
- }
-
- //err=parse_property_data(name); // skip the rest
- //ERR_FAIL_COND_V(err,err);
-
- r_name=name;
- r_v=array;
- return OK;
-
- } else if (type=="resource") {
-
- if (tag->args.has("path")) {
-
- String path=tag->args["path"];
- String hint;
- if (tag->args.has("resource_type"))
- hint=tag->args["resource_type"];
-
- if (path.begins_with("local://"))
- path=path.replace("local://",local_path+"::");
- else 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()+"/"+path);
-
- }
-
- //take advantage of the resource loader cache. The resource is cached on it, even if
- RES res=ResourceLoader::load(path,hint);
-
-
- if (res.is_null()) {
-
- WARN_PRINT(String("Couldn't load resource: "+path).ascii().get_data());
- }
-
- r_v=res.get_ref_ptr();
- }
-
-
-
- Error err=goto_end_of_tag();
- if (err) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error closing <resource> tag.");
- ERR_FAIL_COND_V(err,err);
- }
-
-
- r_name=name;
-
- return OK;
-
- } else if (type=="image") {
-
- if (!tag->args.has("encoding")) {
- //empty image
- r_v=Image();
- String sdfsdfg;
- Error err=parse_property_data(sdfsdfg);
- return OK;
- }
-
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'encoding' field.");
- ERR_FAIL_COND_V( !tag->args.has("encoding"), ERR_FILE_CORRUPT );
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'width' field.");
- ERR_FAIL_COND_V( !tag->args.has("width"), ERR_FILE_CORRUPT );
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'height' field.");
- ERR_FAIL_COND_V( !tag->args.has("height"), ERR_FILE_CORRUPT );
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'format' field.");
- ERR_FAIL_COND_V( !tag->args.has("format"), ERR_FILE_CORRUPT );
-
- String encoding=tag->args["encoding"];
-
- if (encoding=="raw") {
- String width=tag->args["width"];
- String height=tag->args["height"];
- String format=tag->args["format"];
- int mipmaps=tag->args.has("mipmaps")?int(tag->args["mipmaps"].to_int()):int(0);
- int custom_size = tag->args.has("custom_size")?int(tag->args["custom_size"].to_int()):int(0);
-
- r_name=name;
-
- 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( ERR_FILE_CORRUPT );
- }
-
-
- int datasize;
- int w=width.to_int();
- int h=height.to_int();
-
- if (w == 0 && w == 0) {
- //r_v = Image(w, h, imgformat);
- r_v=Image();
- String sdfsdfg;
- Error err=parse_property_data(sdfsdfg);
- return OK;
- };
-
- if (imgformat==Image::FORMAT_CUSTOM) {
-
- datasize=custom_size;
- } else {
-
- datasize = Image::get_image_data_size(h,w,imgformat,mipmaps);
- }
-
- if (datasize==0) {
- //r_v = Image(w, h, imgformat);
- r_v=Image();
- String sdfsdfg;
- Error err=parse_property_data(sdfsdfg);
- return OK;
- };
-
- DVector<uint8_t> pixels;
- pixels.resize(datasize);
- DVector<uint8_t>::Write wb = pixels.write();
-
- int idx=0;
- uint8_t byte;
- while( idx<datasize*2) {
-
- CharType c=get_char();
-
- 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++;
- }
-
- }
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
-
- wb=DVector<uint8_t>::Write();
-
- r_v=Image(w,h,mipmaps,imgformat,pixels);
- String sdfsdfg;
- Error err=parse_property_data(sdfsdfg);
- ERR_FAIL_COND_V(err,err);
-
- return OK;
- }
-
- ERR_FAIL_V(ERR_FILE_CORRUPT);
-
- } else if (type=="raw_array") {
-
- if (!tag->args.has("len")) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": RawArray missing 'len' field: "+name);
- ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
- }
- int len=tag->args["len"].to_int();
-
- DVector<uint8_t> bytes;
- bytes.resize(len);
- DVector<uint8_t>::Write w=bytes.write();
- uint8_t *bytesptr=w.ptr();
- int idx=0;
- uint8_t byte;
- while( idx<len*2) {
-
- CharType c=get_char();
-
- if (idx&1) {
-
- byte|=HEX2CHR(c);
- bytesptr[idx>>1]=byte;
- } else {
-
- byte=HEX2CHR(c)<<4;
- }
-
- idx++;
- }
-
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
-
- w=DVector<uint8_t>::Write();
- r_v=bytes;
- String sdfsdfg;
- Error err=parse_property_data(sdfsdfg);
- ERR_FAIL_COND_V(err,err);
- r_name=name;
-
- return OK;
-
- } else if (type=="int_array") {
-
- if (!tag->args.has("len")) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
- ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
- }
- int len=tag->args["len"].to_int();
-
- DVector<int> ints;
- ints.resize(len);
- DVector<int>::Write w=ints.write();
- int *intsptr=w.ptr();
- int idx=0;
- String str;
-#if 0
- while( idx<len ) {
-
-
- CharType c=get_char();
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
-
- if (c<33 || c==',' || c=='<') {
-
- if (str.length()) {
-
- intsptr[idx]=str.to_int();
- str="";
- idx++;
- }
-
- if (c=='<') {
-
- while(get_char()!='>' && !f->eof_reached()) {}
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
- break;
- }
-
- } else {
-
- str+=c;
- }
- }
-
-#else
-
- Vector<char> tmpdata;
-
- while( idx<len ) {
-
- bool end=false;
- Error err = _parse_array_element(tmpdata,true,f,&end);
- ERR_FAIL_COND_V(err,err);
-
- intsptr[idx]=String::to_int(&tmpdata[0]);
- idx++;
- if (end)
- break;
-
- }
-
-#endif
- w=DVector<int>::Write();
-
- r_v=ints;
- Error err=goto_end_of_tag();
- ERR_FAIL_COND_V(err,err);
- r_name=name;
-
- return OK;
- } else if (type=="real_array") {
-
- if (!tag->args.has("len")) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
- ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
- }
- int len=tag->args["len"].to_int();;
-
- DVector<real_t> reals;
- reals.resize(len);
- DVector<real_t>::Write w=reals.write();
- real_t *realsptr=w.ptr();
- int idx=0;
- String str;
-
-
-#if 0
- while( idx<len ) {
-
-
- CharType c=get_char();
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
-
-
- if (c<33 || c==',' || c=='<') {
-
- if (str.length()) {
-
- realsptr[idx]=str.to_double();
- str="";
- idx++;
- }
-
- if (c=='<') {
-
- while(get_char()!='>' && !f->eof_reached()) {}
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
- break;
- }
-
- } else {
-
- str+=c;
- }
- }
-
-#else
-
-
-
- Vector<char> tmpdata;
-
- while( idx<len ) {
-
- bool end=false;
- Error err = _parse_array_element(tmpdata,true,f,&end);
- ERR_FAIL_COND_V(err,err);
-
- realsptr[idx]=String::to_double(&tmpdata[0]);
- idx++;
-
- if (end)
- break;
- }
-
-#endif
-
- w=DVector<real_t>::Write();
- r_v=reals;
-
- Error err=goto_end_of_tag();
- ERR_FAIL_COND_V(err,err);
- r_name=name;
-
- return OK;
- } else if (type=="string_array") {
-
- if (!tag->args.has("len")) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
- ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
- }
- int len=tag->args["len"].to_int();
-
- DVector<String> strings;
- strings.resize(len);
- DVector<String>::Write w=strings.write();
- String *stringsptr=w.ptr();
- int idx=0;
- String str;
-
- bool inside_str=false;
- CharString cs;
- while( idx<len ) {
-
-
- CharType c=get_char();
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
-
-
- if (c=='"') {
- if (inside_str) {
-
- cs.push_back(0);
- String str;
- str.parse_utf8(cs.get_data());
- unquote(str);
- stringsptr[idx]=str;
- cs.clear();
- idx++;
- inside_str=false;
- } else {
- inside_str=true;
- }
- } else if (c=='<') {
-
- while(get_char()!='>' && !f->eof_reached()) {}
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
- break;
-
-
- } else if (inside_str){
-
- cs.push_back(c);
- }
- }
- w=DVector<String>::Write();
- r_v=strings;
- String sdfsdfg;
- Error err=parse_property_data(sdfsdfg);
- ERR_FAIL_COND_V(err,err);
-
- r_name=name;
-
- return OK;
- } else if (type=="vector3_array") {
-
- if (!tag->args.has("len")) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
- ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
- }
- int len=tag->args["len"].to_int();;
-
- DVector<Vector3> vectors;
- vectors.resize(len);
- DVector<Vector3>::Write w=vectors.write();
- Vector3 *vectorsptr=w.ptr();
- int idx=0;
- int subidx=0;
- Vector3 auxvec;
- String str;
-
-// uint64_t tbegin = OS::get_singleton()->get_ticks_usec();
-#if 0
- while( idx<len ) {
-
-
- CharType c=get_char();
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
-
-
- if (c<33 || c==',' || c=='<') {
-
- if (str.length()) {
-
- auxvec[subidx]=str.to_double();
- subidx++;
- str="";
- if (subidx==3) {
- vectorsptr[idx]=auxvec;
-
- idx++;
- subidx=0;
- }
- }
-
- if (c=='<') {
-
- while(get_char()!='>' && !f->eof_reached()) {}
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
- break;
- }
-
- } else {
-
- str+=c;
- }
- }
-#else
-
- Vector<char> tmpdata;
-
- while( idx<len ) {
-
- bool end=false;
- Error err = _parse_array_element(tmpdata,true,f,&end);
- ERR_FAIL_COND_V(err,err);
-
-
- auxvec[subidx]=String::to_double(&tmpdata[0]);
- subidx++;
- if (subidx==3) {
- vectorsptr[idx]=auxvec;
-
- idx++;
- subidx=0;
- }
-
- if (end)
- break;
- }
-
-
-
-#endif
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Premature end of vector3 array");
- ERR_FAIL_COND_V(idx<len,ERR_FILE_CORRUPT);
-// double time_taken = (OS::get_singleton()->get_ticks_usec() - tbegin)/1000000.0;
-
-
- w=DVector<Vector3>::Write();
- r_v=vectors;
- String sdfsdfg;
- Error err=goto_end_of_tag();
- ERR_FAIL_COND_V(err,err);
- r_name=name;
-
- return OK;
-
- } else if (type=="vector2_array") {
-
- if (!tag->args.has("len")) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
- ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
- }
- int len=tag->args["len"].to_int();;
-
- DVector<Vector2> vectors;
- vectors.resize(len);
- DVector<Vector2>::Write w=vectors.write();
- Vector2 *vectorsptr=w.ptr();
- int idx=0;
- int subidx=0;
- Vector2 auxvec;
- String str;
-
-// uint64_t tbegin = OS::get_singleton()->get_ticks_usec();
-#if 0
- while( idx<len ) {
-
-
- CharType c=get_char();
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
-
-
- if (c<22 || c==',' || c=='<') {
-
- if (str.length()) {
-
- auxvec[subidx]=str.to_double();
- subidx++;
- str="";
- if (subidx==2) {
- vectorsptr[idx]=auxvec;
-
- idx++;
- subidx=0;
- }
- }
-
- if (c=='<') {
-
- while(get_char()!='>' && !f->eof_reached()) {}
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
- break;
- }
-
- } else {
-
- str+=c;
- }
- }
-#else
-
- Vector<char> tmpdata;
-
- while( idx<len ) {
-
- bool end=false;
- Error err = _parse_array_element(tmpdata,true,f,&end);
- ERR_FAIL_COND_V(err,err);
-
-
- auxvec[subidx]=String::to_double(&tmpdata[0]);
- subidx++;
- if (subidx==2) {
- vectorsptr[idx]=auxvec;
-
- idx++;
- subidx=0;
- }
-
- if (end)
- break;
- }
-
-
-
-#endif
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Premature end of vector2 array");
- ERR_FAIL_COND_V(idx<len,ERR_FILE_CORRUPT);
-// double time_taken = (OS::get_singleton()->get_ticks_usec() - tbegin)/1000000.0;
-
-
- w=DVector<Vector2>::Write();
- r_v=vectors;
- String sdfsdfg;
- Error err=goto_end_of_tag();
- ERR_FAIL_COND_V(err,err);
- r_name=name;
-
- return OK;
-
- } else if (type=="color_array") {
-
- if (!tag->args.has("len")) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
- ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
- }
- int len=tag->args["len"].to_int();;
-
- DVector<Color> colors;
- colors.resize(len);
- DVector<Color>::Write w=colors.write();
- Color *colorsptr=w.ptr();
- int idx=0;
- int subidx=0;
- Color auxcol;
- String str;
-
- while( idx<len ) {
-
-
- CharType c=get_char();
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
-
-
- if (c<33 || c==',' || c=='<') {
-
- if (str.length()) {
-
- auxcol[subidx]=str.to_double();
- subidx++;
- str="";
- if (subidx==4) {
- colorsptr[idx]=auxcol;
- idx++;
- subidx=0;
- }
- }
-
- if (c=='<') {
-
- while(get_char()!='>' && !f->eof_reached()) {}
- ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
- break;
- }
-
- } else {
-
- str+=c;
- }
- }
- w=DVector<Color>::Write();
- r_v=colors;
- String sdfsdfg;
- Error err=parse_property_data(sdfsdfg);
- ERR_FAIL_COND_V(err,err);
- r_name=name;
-
- return OK;
- }
-
-
- String data;
- Error err = parse_property_data(data);
- ERR_FAIL_COND_V(err!=OK,err);
-
- if (type=="nil") {
- // uh do nothing
-
- } else if (type=="bool") {
- // uh do nothing
- if (data.nocasecmp_to("true")==0 || data.to_int()!=0)
- r_v=true;
- else
- r_v=false;
- } else if (type=="int") {
-
- r_v=data.to_int();
- } else if (type=="real") {
-
- r_v=data.to_double();
- } else if (type=="string") {
-
- String str=data;
- unquote(str);
- r_v=str;
- } else if (type=="vector3") {
-
-
- r_v=Vector3(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double()
- );
-
- } else if (type=="vector2") {
-
-
- r_v=Vector2(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",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()
- );
-
- } 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()
- );
-
- } else if (type=="rect2") {
-
- r_v=Rect2(
- Vector2(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double()
- ),
- Vector2(
- data.get_slice(",",2).to_double(),
- data.get_slice(",",3).to_double()
- )
- );
-
-
- } else if (type=="aabb") {
-
- r_v=AABB(
- Vector3(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double()
- ),
- Vector3(
- data.get_slice(",",3).to_double(),
- data.get_slice(",",4).to_double(),
- data.get_slice(",",5).to_double()
- )
- );
-
- } else if (type=="matrix32") {
-
- 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();
- }
- }
- r_v=m3;
-
- } else if (type=="matrix3") {
-
- 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();
- }
- }
- r_v=m3;
-
- } else if (type=="transform") {
-
- 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.origin=Vector3(
- data.get_slice(",",9).to_double(),
- data.get_slice(",",10).to_double(),
- data.get_slice(",",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()
- );
-
- } else if (type=="node_path") {
-
- String str=data;
- unquote(str);
- r_v=NodePath( str );
- } else if (type=="input_event") {
-
- // ?
- } else {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unrecognized tag in file: "+type);
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- }
- r_name=name;
- return OK;
-}
-
-
-Error ObjectFormatLoaderXML::load(Object **p_object,Variant &p_meta) {
-
- *p_object=NULL;
- p_meta=Variant();
-
-
-
- while(true) {
-
-
- bool exit;
- Tag *tag = parse_tag(&exit);
-
-
- if (!tag) {
- if (!exit) // shouldn't have exited
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- *p_object=NULL;
- return ERR_FILE_EOF;
- }
-
- RES resource;
- Object *obj=NULL;
-
- if (tag->name=="resource") {
- //loading resource
-
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <resource> missing 'len' field.");
- ERR_FAIL_COND_V(!tag->args.has("path"),ERR_FILE_CORRUPT);
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <resource> missing 'type' field.");
- ERR_FAIL_COND_V(!tag->args.has("type"),ERR_FILE_CORRUPT);
- String path=tag->args["path"];
-
- if (path.begins_with("local://")) {
- //built-in resource (but really external)
- path=path.replace("local://",local_path+"::");
- }
-
-
- if (ResourceCache::has(path)) {
- Error err = close_tag(tag->name);
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unable to close <resource> tag.");
- ERR_FAIL_COND_V( err, err );
- continue; //it's a resource, and it's already loaded
-
- }
-
- String type = tag->args["type"];
-
- obj = ObjectTypeDB::instance(type);
- if (!obj) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Object of unrecognized type in file: "+type);
- }
- ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
-
- Resource *r = obj->cast_to<Resource>();
- if (!r) {
- memdelete(obj); //bye
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Object type in resource field not a resource, type is: "+obj->get_type());
- ERR_FAIL_COND_V(!obj->cast_to<Resource>(),ERR_FILE_CORRUPT);
- }
-
- resource = RES( r );
- r->set_path(path);
-
-
-
- } else if (tag->name=="object") {
-
- if ( tag->args.has("type") ) {
-
- ERR_FAIL_COND_V(!ObjectTypeDB::type_exists(tag->args["type"]), ERR_FILE_CORRUPT);
-
- if (ObjectTypeDB::can_instance(tag->args["type"])) {
- obj = ObjectTypeDB::instance(tag->args["type"]);
- if (!obj) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Object of unrecognized type in file: "+tag->args["type"]);
- }
- ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
- } else {
-
- close_tag(tag->name);
- return ERR_SKIP;
- };
- } else {
- //otherwise it's a meta object
- }
-
- } else {
-
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unknown main tag: "+tag->name);
- ERR_FAIL_V( ERR_FILE_CORRUPT );
- }
-
- //load properties
-
- while(true) {
-
- String name;
- Variant v;
- Error err;
- err = parse_property(v,name);
- if (err==ERR_FILE_EOF) //tag closed
- break;
- if (err!=OK) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": XML Parsing aborted.");
- ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT);
- }
- if (resource.is_null() && name=="__xml_meta__") {
-
- p_meta=v;
- continue;
- } else if (!obj) {
-
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Normal property found in meta object.");
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- }
-
- obj->set(name,v);
- }
-
- if (!obj) {
- *p_object=NULL;
- return OK; // it was a meta object
- }
-
- if (resource.is_null()) {
-
- //regular object
- *p_object=obj;
- return OK;
- } else {
-
-
- resource_cache.push_back(resource); //keep it in mem until finished loading
- }
-
- // a resource.. continue!
-
- }
-
-
-
- return OK; //never reach anyway
-
-}
-
-int ObjectFormatLoaderXML::get_current_line() const {
-
- return lines;
-}
-
-
-uint8_t ObjectFormatLoaderXML::get_char() const {
-
- uint8_t c = f->get_8();
- if (c=='\n')
- lines++;
- return c;
-
-}
-
-ObjectFormatLoaderXML::~ObjectFormatLoaderXML() {
-
- if (f) {
- if (f->is_open())
- f->close();
- memdelete(f);
- }
-}
-
-
-
-ObjectFormatLoaderXML* ObjectFormatLoaderInstancerXML::instance(const String& p_file,const String& p_magic) {
-
- Error err;
- FileAccess *f=FileAccess::open(p_file,FileAccess::READ,&err);
- if (err!=OK) {
-
- ERR_FAIL_COND_V(err!=OK,NULL);
- }
-
- ObjectFormatLoaderXML *loader = memnew( ObjectFormatLoaderXML );
-
- loader->lines=1;
- loader->f=f;
- loader->local_path = Globals::get_singleton()->localize_path(p_file);
-
- ObjectFormatLoaderXML::Tag *tag = loader->parse_tag();
- if (!tag || tag->name!="?xml" || !tag->args.has("version") || !tag->args.has("encoding") || tag->args["encoding"]!="UTF-8") {
-
- f->close();
- memdelete(loader);
- ERR_EXPLAIN("Not a XML:UTF-8 File: "+p_file);
- ERR_FAIL_V(NULL);
- }
-
- loader->tag_stack.clear();
-
- tag = loader->parse_tag();
-
- if (!tag || tag->name!="object_file" || !tag->args.has("magic") || !tag->args.has("version") || tag->args["magic"]!=p_magic) {
-
- f->close();
- memdelete(loader);
- ERR_EXPLAIN("Unrecognized XML File: "+p_file);
- ERR_FAIL_V(NULL);
- }
-
- String version = tag->args["version"];
- if (version.get_slice_count(".")!=2) {
-
- f->close();
- memdelete(loader);
- ERR_EXPLAIN("Invalid Version String '"+version+"'' in file: "+p_file);
- ERR_FAIL_V(NULL);
- }
-
- int major = version.get_slice(".",0).to_int();
- int minor = version.get_slice(".",1).to_int();
-
- if (major>VERSION_MAJOR || (major==VERSION_MAJOR && minor>VERSION_MINOR)) {
-
- f->close();
- memdelete(loader);
- ERR_EXPLAIN("File Format '"+version+"' is too new! Please upgrade to a a new engine version: "+p_file);
- ERR_FAIL_V(NULL);
-
- }
-
- return loader;
-}
-
-void ObjectFormatLoaderInstancerXML::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("xml");
-}
-
-
-#endif
-#endif
-#endif
diff --git a/core/io/object_format_xml.h b/core/io/object_format_xml.h
deleted file mode 100644
index 1169a1de58..0000000000
--- a/core/io/object_format_xml.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*************************************************************************/
-/* object_format_xml.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef OBJECT_FORMAT_XML_H
-#define OBJECT_FORMAT_XML_H
-
-#ifdef XML_ENABLED
-#ifdef OLD_SCENE_FORMAT_ENABLED
-#include "io/object_loader.h"
-#include "io/object_saver.h"
-#include "os/file_access.h"
-#include "map.h"
-#include "resource.h"
-#include "xml_parser.h"
-
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
-class ObjectFormatSaverXML : public ObjectFormatSaver {
-
- String local_path;
-
-
- Ref<OptimizedSaver> optimizer;
-
- bool relative_paths;
- bool bundle_resources;
- bool skip_editor;
- FileAccess *f;
- String magic;
- int depth;
- Map<RES,int> resource_map;
-
- struct SavedObject {
-
- Variant meta;
- String type;
-
-
- struct SavedProperty {
-
- String name;
- Variant value;
- };
-
- List<SavedProperty> properties;
- };
-
- List<RES> saved_resources;
-
- List<SavedObject*> saved_objects;
-
- void enter_tag(const String& p_section,const String& p_args="");
- void exit_tag(const String& p_section);
-
- void _find_resources(const Variant& p_variant);
- void write_property(const String& p_name,const Variant& p_property,bool *r_ok=NULL);
-
-
- void escape(String& p_str);
- void write_tabs(int p_diff=0);
- void write_string(String p_str,bool p_escape=true);
-
-public:
-
- virtual Error save(const Object *p_object,const Variant &p_meta);
-
- ObjectFormatSaverXML(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer);
- ~ObjectFormatSaverXML();
-};
-
-class ObjectFormatSaverInstancerXML : public ObjectFormatSaverInstancer {
-public:
-
- virtual ObjectFormatSaver* instance(const String& p_file,const String& p_magic,uint32_t p_flags=0,const Ref<OptimizedSaver>& p_optimizer=Ref<OptimizedSaver>());
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
-
- virtual ~ObjectFormatSaverInstancerXML();
-};
-
-/***********************************/
-/***********************************/
-/***********************************/
-/***********************************/
-
-//#define OPTIMIZED_XML_LOADER
-
-#ifdef OPTIMIZED_XML_LOADER
-
-class ObjectFormatLoaderXML : public ObjectFormatLoader {
-
- Ref<XMLParser> parser;
- String local_path;
-
- Error _close_tag(const String& p_tag);
- Error _parse_property(Variant& r_property,String& r_name);
-
-friend class ObjectFormatLoaderInstancerXML;
-
- List<RES> resource_cache;
-public:
-
-
- virtual Error load(Object **p_object,Variant &p_meta);
-
-
-};
-
-class ObjectFormatLoaderInstancerXML : public ObjectFormatLoaderInstancer {
-public:
-
- virtual ObjectFormatLoaderXML* instance(const String& p_file,const String& p_magic);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
-
-};
-
-#else
-
-
-class ObjectFormatLoaderXML : public ObjectFormatLoader {
-
- String local_path;
-
- FileAccess *f;
-
- struct Tag {
-
- String name;
- HashMap<String,String> args;
- };
-
- _FORCE_INLINE_ Error _parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end);
-
- mutable int lines;
- uint8_t get_char() const;
- int get_current_line() const;
-
-friend class ObjectFormatLoaderInstancerXML;
- List<Tag> tag_stack;
-
- List<RES> resource_cache;
- Tag* parse_tag(bool* r_exit=NULL);
- Error close_tag(const String& p_name);
- void unquote(String& p_str);
- Error goto_end_of_tag();
- Error parse_property_data(String &r_data);
- Error parse_property(Variant& r_v, String &r_name);
-
-public:
-
-
- virtual Error load(Object **p_object,Variant &p_meta);
-
- virtual ~ObjectFormatLoaderXML();
-};
-
-class ObjectFormatLoaderInstancerXML : public ObjectFormatLoaderInstancer {
-public:
-
- virtual ObjectFormatLoaderXML* instance(const String& p_file,const String& p_magic);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
-
-
-
-};
-
-#endif
-#endif
-#endif
-#endif
diff --git a/core/io/object_loader.cpp b/core/io/object_loader.cpp
deleted file mode 100644
index bb42cf7338..0000000000
--- a/core/io/object_loader.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*************************************************************************/
-/* object_loader.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "object_loader.h"
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-bool ObjectFormatLoaderInstancer::recognize(const String& p_extension) const {
-
-
- List<String> extensions;
- get_recognized_extensions(&extensions);
- for (List<String>::Element *E=extensions.front();E;E=E->next()) {
-
- if (E->get().nocasecmp_to(p_extension)==0)
- return true;
- }
-
- return false;
-}
-
-ObjectFormatLoaderInstancer *ObjectLoader::loader[MAX_LOADERS];
-int ObjectLoader::loader_count=0;
-
-
-ObjectFormatLoader *ObjectLoader::instance_format_loader(const String& p_path,const String& p_magic,String p_force_extension) {
-
- String extension=p_force_extension.length()?p_force_extension:p_path.extension();
-
- for (int i=0;i<loader_count;i++) {
-
- if (!loader[i]->recognize(extension))
- continue;
- ObjectFormatLoader *format_loader = loader[i]->instance(p_path,p_magic);
- if (format_loader)
- return format_loader;
- }
-
- return NULL;
-}
-
-void ObjectLoader::get_recognized_extensions(List<String> *p_extensions) {
-
- for (int i=0;i<loader_count;i++) {
-
- loader[i]->get_recognized_extensions(p_extensions);
- }
-}
-
-
-
-void ObjectLoader::add_object_format_loader_instancer(ObjectFormatLoaderInstancer *p_format_loader_instancer) {
-
- ERR_FAIL_COND(loader_count>=MAX_LOADERS );
- loader[loader_count++]=p_format_loader_instancer;
-}
-
-
-#endif
diff --git a/core/io/object_loader.h b/core/io/object_loader.h
deleted file mode 100644
index 9199313f04..0000000000
--- a/core/io/object_loader.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*************************************************************************/
-/* object_loader.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef OBJECT_LOADER_H
-#define OBJECT_LOADER_H
-
-#include "object.h"
-
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-#ifdef OLD_SCENE_FORMAT_ENABLED
-class ObjectFormatLoader {
-public:
-
- virtual Error load(Object **p_object,Variant &p_meta)=0;
-
- virtual ~ObjectFormatLoader() {}
-};
-
-class ObjectFormatLoaderInstancer {
-public:
-
- virtual ObjectFormatLoader* instance(const String& p_file,const String& p_magic)=0;
- virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
- bool recognize(const String& p_extension) const;
-
- virtual ~ObjectFormatLoaderInstancer() {}
-};
-
-class ObjectLoader {
-
- enum {
- MAX_LOADERS=64
- };
-
- static ObjectFormatLoaderInstancer *loader[MAX_LOADERS];
- static int loader_count;
-
-public:
-
- static ObjectFormatLoader *instance_format_loader(const String& p_path,const String& p_magic,String p_force_extension="");
- static void add_object_format_loader_instancer(ObjectFormatLoaderInstancer *p_format_loader_instancer);
- static void get_recognized_extensions(List<String> *p_extensions);
-
-
-
-};
-
-#endif
-#endif
diff --git a/core/io/object_saver.cpp b/core/io/object_saver.cpp
deleted file mode 100644
index cff2e836a7..0000000000
--- a/core/io/object_saver.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*************************************************************************/
-/* object_saver.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "object_saver.h"
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-void OptimizedSaver::add_property(const StringName& p_name, const Variant& p_value) {
-
- ERR_FAIL_COND(!_list);
- Property p;
- p.name=p_name;
- p.value=p_value;
- _list->push_back(p);
-}
-
-bool OptimizedSaver::optimize_object(const Object *p_object) {
-
- return false; //not optimize
-}
-
-void OptimizedSaver::get_property_list(const Object* p_object,List<Property> *p_properties) {
-
-
- _list=p_properties;
-
- bool res = call("optimize_object",p_object);
-
- if (!res) {
-
- List<PropertyInfo> plist;
- p_object->get_property_list(&plist);
- for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
-
- PropertyInfo pinfo=E->get();
- if ((pinfo.usage&PROPERTY_USAGE_STORAGE) || (is_bundle_resources_enabled() && pinfo.usage&PROPERTY_USAGE_BUNDLE)) {
-
- add_property(pinfo.name,p_object->get(pinfo.name));
- }
- }
-
- }
-
- _list=NULL;
-}
-
-void OptimizedSaver::set_target_platform(const String& p_platform) {
-
- ERR_FAIL_COND(p_platform!="" && !p_platform.is_valid_identifier());
- platform=p_platform;
-}
-
-String OptimizedSaver::get_target_platform() const {
-
- return platform;
-}
-
-void OptimizedSaver::set_target_name(const String& p_name) {
-
- name=p_name;
-}
-
-String OptimizedSaver::get_target_name() const {
-
- return name;
-}
-
-void OptimizedSaver::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_target_platform","name"),&OptimizedSaver::set_target_platform);
- ObjectTypeDB::bind_method(_MD("get_target_platform"),&OptimizedSaver::get_target_platform);
- ObjectTypeDB::bind_method(_MD("set_target_name","name"),&OptimizedSaver::set_target_name);
- ObjectTypeDB::bind_method(_MD("add_property","name","value"),&OptimizedSaver::add_property);
- ObjectTypeDB::bind_method(_MD("optimize_object","obj"),&OptimizedSaver::optimize_object);
-}
-
-OptimizedSaver::OptimizedSaver() {
-
- _list=NULL;
-}
-
-ObjectFormatSaverInstancer *ObjectSaver::saver[MAX_LOADERS];
-int ObjectSaver::saver_count=0;
-
-bool ObjectFormatSaverInstancer::recognize(const String& p_extension) const {
-
-
- List<String> extensions;
- get_recognized_extensions(&extensions);
- for (List<String>::Element *E=extensions.front();E;E=E->next()) {
-
- if (E->get().nocasecmp_to(p_extension.extension())==0)
- return true;
- }
-
- return false;
-}
-
-ObjectFormatSaver *ObjectSaver::instance_format_saver(const String& p_path,const String& p_magic,String p_force_extension,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
-
- String extension=p_force_extension.length()?p_force_extension:p_path.extension();
-
- for (int i=0;i<saver_count;i++) {
-
- if (!saver[i]->recognize(extension))
- continue;
- ObjectFormatSaver *format_saver = saver[i]->instance(p_path,p_magic,p_flags,p_optimizer);
- if (format_saver)
- return format_saver;
- }
-
- return NULL;
-}
-
-void ObjectSaver::get_recognized_extensions(List<String> *p_extensions) {
-
- for (int i=0;i<saver_count;i++) {
-
- saver[i]->get_recognized_extensions(p_extensions);
- }
-}
-
-
-
-void ObjectSaver::add_object_format_saver_instancer(ObjectFormatSaverInstancer *p_format_saver_instancer) {
-
- ERR_FAIL_COND(saver_count>=MAX_LOADERS );
- saver[saver_count++]=p_format_saver_instancer;
-}
-
-
-
-#endif
diff --git a/core/io/object_saver.h b/core/io/object_saver.h
deleted file mode 100644
index b22f7e05bb..0000000000
--- a/core/io/object_saver.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*************************************************************************/
-/* object_saver.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef OBJECT_SAVER_H
-#define OBJECT_SAVER_H
-
-#include "object.h"
-#include "resource.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-class OptimizedSaver : public Reference {
-
- OBJ_TYPE(OptimizedSaver,Reference);
-public:
-
- struct Property {
-
- StringName name;
- Variant value;
- };
-
-private:
-
- String name;
- String platform;
- List<Property> *_list;
-protected:
-
-
- void set_target_platform(const String& p_platform);
- void set_target_name(const String& p_name);
- void add_property(const StringName& p_name, const Variant& p_value);
- static void _bind_methods();
-
- virtual bool optimize_object(const Object *p_object);
-
-public:
-
-
- virtual bool is_bundle_resources_enabled() const { return false; }
-
- String get_target_platform() const;
- String get_target_name() const;
- void get_property_list(const Object* p_object, List<Property> *p_properties);
-
-
- OptimizedSaver();
-
-};
-
-
-class ObjectFormatSaver {
-public:
-
- virtual Error save(const Object *p_object,const Variant &p_meta=Variant())=0;
-
- virtual ~ObjectFormatSaver() {}
-};
-
-class ObjectFormatSaverInstancer {
-public:
-
- virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
- virtual ObjectFormatSaver* instance(const String& p_file,const String& p_magic="",uint32_t p_flags=0,const Ref<OptimizedSaver>& p_optimizer=Ref<OptimizedSaver>())=0;
- bool recognize(const String& p_extension) const;
-
- virtual ~ObjectFormatSaverInstancer() {}
-};
-
-class ObjectSaver {
-
- enum {
- MAX_LOADERS=64
- };
-
- static ObjectFormatSaverInstancer *saver[MAX_LOADERS];
- static int saver_count;
-
-public:
-
- enum SaverFlags {
-
- FLAG_RELATIVE_PATHS=1,
- FLAG_BUNDLE_RESOURCES=2,
- FLAG_OMIT_EDITOR_PROPERTIES=4,
- FLAG_SAVE_BIG_ENDIAN=8
- };
-
-
- static ObjectFormatSaver *instance_format_saver(const String& p_path,const String& p_magic,String p_force_extension="",uint32_t p_flags=0,const Ref<OptimizedSaver>& p_optimizer=Ref<OptimizedSaver>());
- static void get_recognized_extensions(List<String> *p_extensions);
-
- static void add_object_format_saver_instancer(ObjectFormatSaverInstancer *p_format_saver_instancer);
-
-
-};
-
-#endif
-#endif
diff --git a/core/io/object_saver_base.cpp b/core/io/object_saver_base.cpp
deleted file mode 100644
index 94d715de28..0000000000
--- a/core/io/object_saver_base.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*************************************************************************/
-/* object_saver_base.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "object_saver_base.h"
-#ifdef OLD_SCENE_FORMAT_ENABLED
-void ObjectSaverBase::_find_resources(const Variant& p_variant) {
-
- switch(p_variant.get_type()) {
- case Variant::OBJECT: {
-
-
- RES res = p_variant.operator RefPtr();
-
- if (res.is_null() || (res->get_path().length() && res->get_path().find("::") == -1 ))
- return;
-
- if (resource_map.has(res))
- return;
-
- List<PropertyInfo> property_list;
-
- res->get_property_list( &property_list );
-
- List<PropertyInfo>::Element *I=property_list.front();
-
- while(I) {
-
- PropertyInfo pi=I->get();
-
- if (pi.usage&PROPERTY_USAGE_STORAGE) {
-
- if (pi.type==Variant::OBJECT) {
-
- Variant v=res->get(I->get().name);
- _find_resources(v);
- }
- }
-
- I=I->next();
- }
-
- resource_map[ res ] = resource_map.size(); //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 ObjectSaverBase::save(const Object *p_object,const Variant &p_meta) {
-
- ERR_EXPLAIN("write_object should supply either an object, a meta, or both");
- ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER);
-
- SavedObject *so = memnew( SavedObject );
-
- if (p_object) {
- so->type=p_object->get_type();
- };
-
- _find_resources(p_meta);
- so->meta=p_meta;
-
- if (p_object) {
-
- List<PropertyInfo> property_list;
- p_object->get_property_list( &property_list );
-
- List<PropertyInfo>::Element *I=property_list.front();
-
- while(I) {
-
- if (I->get().usage&PROPERTY_USAGE_STORAGE) {
-
- SavedObject::SavedProperty sp;
- sp.name=I->get().name;
- sp.value = p_object->get(I->get().name);
- _find_resources(sp.value);
- so->properties.push_back(sp);
- }
-
- I=I->next();
- }
-
- }
-
- saved_objects.push_back(so);
-
- return OK;
-}
-
-ObjectSaverBase::ObjectSaverBase() {
-
-};
-
-ObjectSaverBase::~ObjectSaverBase() {
-
-};
-#endif
diff --git a/core/io/object_saver_base.h b/core/io/object_saver_base.h
deleted file mode 100644
index d9ec4a3aba..0000000000
--- a/core/io/object_saver_base.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*************************************************************************/
-/* object_saver_base.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef OBJECT_SAVER_BASE_H
-#define OBJECT_SAVER_BASE_H
-
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-#include "object_saver.h"
-
-#include "map.h"
-#include "resource.h"
-
-class ObjectSaverBase : public ObjectFormatSaver {
-
-protected:
-
- Map<RES,int> resource_map;
-
- struct SavedObject {
-
- Variant meta;
- String type;
-
-
- struct SavedProperty {
-
- String name;
- Variant value;
- };
-
- List<SavedProperty> properties;
- };
-
- List<RES> saved_resources;
-
- List<SavedObject*> saved_objects;
-
- void _find_resources(const Variant& p_variant);
-
- virtual Error write()=0;
-public:
-
- virtual Error save(const Object *p_object,const Variant &p_meta);
-
- ObjectSaverBase();
- ~ObjectSaverBase();
-};
-
-#endif
-#endif // OBJECT_SAVER_BASE_H
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 37fc9c4a0a..f6d526b512 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,7 +36,7 @@
PacketPeer::PacketPeer() {
-
+ last_get_error=OK;
}
Error PacketPeer::get_packet_buffer(DVector<uint8_t> &r_buffer) const {
@@ -108,10 +108,29 @@ Variant PacketPeer::_bnd_get_var() const {
return var;
};
+Error PacketPeer::_put_packet(const DVector<uint8_t> &p_buffer) {
+ return put_packet_buffer(p_buffer);
+}
+DVector<uint8_t> PacketPeer::_get_packet() const {
+
+ DVector<uint8_t> raw;
+ last_get_error=get_packet_buffer(raw);
+ return raw;
+}
+
+Error PacketPeer::_get_packet_error() const {
+
+ return last_get_error;
+}
+
+
void PacketPeer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_var"),&PacketPeer::_bnd_get_var);
- ObjectTypeDB::bind_method(_MD("put_var", "var:Variant"),&PacketPeer::put_var);
+ ObjectTypeDB::bind_method(_MD("put_var", "var:var"),&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);
ObjectTypeDB::bind_method(_MD("get_available_packet_count"),&PacketPeer::get_available_packet_count);
};
@@ -137,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;
@@ -183,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 e9d6be4fb9..76d1eb22b5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -41,6 +41,14 @@ class PacketPeer : public Reference {
static void _bind_methods();
+
+ Error _put_packet(const DVector<uint8_t> &p_buffer);
+ DVector<uint8_t> _get_packet() const;
+ Error _get_packet_error() const;
+
+
+ mutable Error last_get_error;
+
public:
virtual int get_available_packet_count() const=0;
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
new file mode 100644
index 0000000000..83217ffc41
--- /dev/null
+++ b/core/io/packet_peer_udp.cpp
@@ -0,0 +1,63 @@
+#include "packet_peer_udp.h"
+#include "io/ip.h"
+
+
+PacketPeerUDP* (*PacketPeerUDP::_create)()=NULL;
+
+int PacketPeerUDP::_get_packet_address() const {
+
+ IP_Address ip = get_packet_address();
+ return ip.host;
+}
+
+String PacketPeerUDP::_get_packet_ip() const {
+
+ return get_packet_address();
+}
+
+Error PacketPeerUDP::_set_send_address(const String& p_address,int p_port) {
+
+ IP_Address ip;
+ if (p_address.is_valid_ip_address()) {
+ ip=p_address;
+ } else {
+ ip=IP::get_singleton()->resolve_hostname(p_address);
+ if (ip==IP_Address())
+ return ERR_CANT_RESOLVE;
+ }
+
+ set_send_address(ip,p_port);
+ return OK;
+}
+
+void PacketPeerUDP::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("listen:Error","port","recv_buf_size"),&PacketPeerUDP::listen,DEFVAL(65536));
+ ObjectTypeDB::bind_method(_MD("close"),&PacketPeerUDP::close);
+ ObjectTypeDB::bind_method(_MD("wait:Error"),&PacketPeerUDP::wait);
+ ObjectTypeDB::bind_method(_MD("is_listening"),&PacketPeerUDP::is_listening);
+ ObjectTypeDB::bind_method(_MD("get_packet_ip"),&PacketPeerUDP::_get_packet_ip);
+ ObjectTypeDB::bind_method(_MD("get_packet_address"),&PacketPeerUDP::_get_packet_address);
+ ObjectTypeDB::bind_method(_MD("get_packet_port"),&PacketPeerUDP::get_packet_port);
+ ObjectTypeDB::bind_method(_MD("set_send_address","host","port"),&PacketPeerUDP::_set_send_address);
+
+
+}
+
+Ref<PacketPeerUDP> PacketPeerUDP::create_ref() {
+
+ if (!_create)
+ return Ref<PacketPeerUDP>();
+ return Ref<PacketPeerUDP>(_create());
+}
+
+PacketPeerUDP* PacketPeerUDP::create() {
+
+ if (!_create)
+ return NULL;
+ return _create();
+}
+
+PacketPeerUDP::PacketPeerUDP()
+{
+}
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
new file mode 100644
index 0000000000..73ff487b19
--- /dev/null
+++ b/core/io/packet_peer_udp.h
@@ -0,0 +1,37 @@
+#ifndef PACKET_PEER_UDP_H
+#define PACKET_PEER_UDP_H
+
+
+#include "io/packet_peer.h"
+
+class PacketPeerUDP : public PacketPeer {
+ OBJ_TYPE(PacketPeerUDP,PacketPeer);
+
+protected:
+
+ static PacketPeerUDP* (*_create)();
+ static void _bind_methods();
+
+ int _get_packet_address() const;
+ String _get_packet_ip() const;
+
+ virtual Error _set_send_address(const String& p_address,int p_port);
+
+public:
+
+ virtual Error listen(int p_port,int p_recv_buffer_size=65536)=0;
+ virtual void close()=0;
+ virtual Error wait()=0;
+ virtual bool is_listening() const=0;
+ virtual IP_Address get_packet_address() const=0;
+ virtual int get_packet_port() const=0;
+ virtual void set_send_address(const IP_Address& p_address,int p_port)=0;
+
+
+ static Ref<PacketPeerUDP> create_ref();
+ static PacketPeerUDP* create();
+
+ PacketPeerUDP();
+};
+
+#endif // PACKET_PEER_UDP_H
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index e2371fe24f..9a3a191b3b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,16 +387,21 @@ 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();
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()+"/"+path);
+ path=Globals::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path));
}
+ 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);
}
@@ -663,14 +702,18 @@ Error ResourceInteractiveLoaderBinary::poll(){
//maybe it is loaded already
String path;
+ int subindex=0;
if (!main) {
path=internal_resources[s].path;
- if (path.begins_with("local://"))
- path=path.replace("local://",res_path+"::");
+ if (path.begins_with("local://")) {
+ path=path.replace_first("local://","");
+ subindex = path.to_int();
+ path=res_path+"::"+path;
+ }
@@ -709,6 +752,7 @@ Error ResourceInteractiveLoaderBinary::poll(){
RES res = RES( r );
r->set_path(path);
+ r->set_subindex(subindex);
int pc = f->get_32();
@@ -782,12 +826,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]);
@@ -796,7 +863,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)
@@ -809,6 +876,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);
}
@@ -836,7 +907,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();
@@ -861,7 +932,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 || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) {
+ 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);
@@ -898,6 +969,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();
@@ -908,7 +980,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();
@@ -968,7 +1040,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 || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) {
+ if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) {
f->close();
return "";
@@ -995,8 +1067,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);
@@ -1109,7 +1183,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);
@@ -1118,7 +1192,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;
}
@@ -1428,20 +1712,18 @@ 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_map.has(res)) {
+ if (!resource_set.has(res)) {
f->store_32(OBJECT_EMPTY);
ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
ERR_FAIL();
}
f->store_32(OBJECT_INTERNAL_RESOURCE);
- f->store_32(resource_map[res]);
+ f->store_32(res->get_subindex());
//internal resource
}
@@ -1589,16 +1871,17 @@ 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;
}
- if (resource_map.has(res))
+ if (resource_set.has(res))
return;
List<PropertyInfo> property_list;
@@ -1613,7 +1896,7 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant& p_variant
}
}
- resource_map[ res ] = saved_resources.size();
+ resource_set.insert(res);
saved_resources.push_back(res);
} break;
@@ -1778,6 +2061,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
f->store_32(VERSION_MINOR);
f->store_32(FORMAT_VERSION);
+ if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
+ f->close();
+ return ERR_CANT_CREATE;
+ }
+
//f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
save_unicode_string(p_resource->get_type());
uint64_t md_at = f->get_pos();
@@ -1809,7 +2097,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();
@@ -1832,25 +2120,65 @@ 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();
+ }
+
+ for(int i=0;i<save_order.size();i++) {
- save_unicode_string(E->get()->get_save_type());
- String path = E->get()->get_path();
+ 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
f->store_32(saved_resources.size()); //amount of internal resources
Vector<uint64_t> ofs_pos;
+ Set<int> used_indices;
+
for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
RES r = E->get();
if (r->get_path()=="" || r->get_path().find("::")!=-1) {
- save_unicode_string("local://"+itos(ofs_pos.size()));
+
+ if (r->get_subindex()!=0) {
+ if (used_indices.has(r->get_subindex())) {
+ r->set_subindex(0); //repeated
+ } else {
+ used_indices.insert(r->get_subindex());
+ }
+ }
+ }
+
+ }
+
+
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+
+ RES r = E->get();
+ if (r->get_path()=="" || r->get_path().find("::")!=-1) {
+ if (r->get_subindex()==0) {
+ int new_subindex=1;
+ if (used_indices.size()) {
+ new_subindex=used_indices.back()->get()+1;
+ }
+
+ r->set_subindex(new_subindex);
+ used_indices.insert(new_subindex);
+
+ }
+
+ 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
}
@@ -1910,6 +2238,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
f->store_buffer((const uint8_t*)"RSRC",4); //magic at end
+ if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
+ f->close();
+ return ERR_CANT_CREATE;
+ }
+
f->close();
@@ -1949,3 +2282,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 cc26357bfb..8bf20bc574 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
@@ -129,12 +132,12 @@ class ResourceFormatSaverBinaryInstance {
int bin_meta_idx;
FileAccess *f;
String magic;
- Map<RES,int> resource_map;
+ Set<RES> resource_set;
Map<StringName,int> string_map;
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 e6eede7de6..48917a19ea 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -193,6 +201,7 @@ Error ResourceInteractiveLoaderXML::close_tag(const String& p_name) {
void ResourceInteractiveLoaderXML::unquote(String& p_str) {
+
p_str=p_str.strip_edges().replace("\"","").xml_unescape();
/*p_str=p_str.strip_edges();
@@ -308,6 +317,7 @@ Error ResourceInteractiveLoaderXML::_parse_array_element(Vector<char> &buff,bool
buff_max++;
buff.resize(buff_max);
+ buffptr=buff.ptr();
}
@@ -457,8 +467,12 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
path=path.replace("local://",local_path+"::");
else 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()+"/"+path);
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+
+ }
+ if (remaps.has(path)) {
+ path=remaps[path];
}
//take advantage of the resource loader cache. The resource is cached on it, even if
@@ -471,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.");
@@ -571,7 +606,7 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
int w=width.to_int();
int h=height.to_int();
- if (w == 0 && w == 0) {
+ if (w == 0 && h == 0) {
//r_v = Image(w, h, imgformat);
r_v=Image();
String sdfsdfg;
@@ -1205,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()
)
);
@@ -1254,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()
)
);
@@ -1270,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;
@@ -1280,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;
@@ -1290,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") {
@@ -1362,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 unexisting 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);
@@ -1411,36 +1420,48 @@ 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);
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()+"/"+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()) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> referenced unexisting resource at: "+path);
+ 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;
@@ -1464,6 +1485,7 @@ Error ResourceInteractiveLoaderXML::poll() {
String type;
String path;
+ int subres=0;
if (!main) {
//loading resource
@@ -1474,11 +1496,15 @@ Error ResourceInteractiveLoaderXML::poll() {
ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <resource> missing 'type' field.");
ERR_FAIL_COND_V(!tag->args.has("type"),ERR_FILE_CORRUPT);
path=tag->args["path"];
+
error=OK;
if (path.begins_with("local://")) {
//built-in resource (but really external)
- path=path.replace("local://",local_path+"::");
+
+ path=path.replace("local://","");
+ subres=path.to_int();
+ path=local_path+"::"+path;
}
@@ -1517,6 +1543,7 @@ Error ResourceInteractiveLoaderXML::poll() {
res = RES( r );
if (path!="")
r->set_path(path);
+ r->set_subindex(subres);
//load properties
@@ -1558,7 +1585,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() {
@@ -1566,7 +1593,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);
@@ -1600,7 +1627,7 @@ void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *
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()+"/"+path);
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
}
if (path.ends_with("*")) {
@@ -1609,6 +1636,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");
@@ -1620,6 +1651,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) {
@@ -1666,10 +1858,10 @@ 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 || (major==VERSION_MAJOR && minor>VERSION_MINOR)) {
+ if (major>VERSION_MAJOR) {
error=ERR_FILE_UNRECOGNIZED;
ResourceLoader::notify_load_error(local_path+": File Format '"+version+"' is too new. Please upgrade to a newer engine version.");
@@ -1678,6 +1870,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();
@@ -1689,7 +1882,7 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) {
}
print_line(local_path+" - EXTERNAL RESOURCES: "+itos(ext_resources.size()));
}
-
+*/
}
@@ -1722,7 +1915,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);
@@ -1759,7 +1955,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");
@@ -1808,7 +2003,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) {
@@ -1820,11 +2015,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);
+}
+
+
/****************************************************************************************/
/****************************************************************************************/
/****************************************************************************************/
@@ -1844,14 +2055,17 @@ 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 (int i=1;i<32;i++) {
+ for (char i=1;i<32;i++) {
char chr[2]={i,0};
- p_str=p_str.replace(chr,"&#"+String::num(i)+";");
+ const char hexn[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ const char hex[8]={'&','#','0','0',hexn[i>>4],hexn[i&0xf],';',0};
+
+ p_str=p_str.replace(chr,hex);
}
@@ -2013,20 +2227,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_map.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+"\"";
+ } 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(resource_map[res])+"\"";
+ params+=" path=\"local://"+itos(res->get_subindex())+"\"";
+ }
}
} break;
@@ -2239,12 +2459,12 @@ void ResourceFormatSaverXMLInstance::write_property(const String& p_name,const V
List<Variant> keys;
dict.get_key_list(&keys);
+ keys.sort();
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
//if (!_check_type(dict[E->get()]))
// continue;
-
bool ok;
write_property("",E->get(),&ok);
ERR_CONTINUE(!ok);
@@ -2430,20 +2650,22 @@ 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.insert(res);
+ int index = external_resources.size();
+ external_resources[res]=index;
return;
}
- if (resource_map.has(res))
+ 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();
@@ -2460,7 +2682,7 @@ void ResourceFormatSaverXMLInstance::_find_resources(const Variant& p_variant,bo
I=I->next();
}
- resource_map[ res ] = resource_map.size(); //saved after, so the childs it needs are available when loaded
+ resource_set.insert( res ); //saved after, so the childs it needs are available when loaded
saved_resources.push_back(res);
} break;
@@ -2521,22 +2743,37 @@ 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(Set<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);
}
+ 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_map.has(res));
+ ERR_CONTINUE(!resource_set.has(res));
bool main = (E->next()==NULL);
write_tabs();
@@ -2546,7 +2783,18 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
else if (res->get_path().length() && res->get_path().find("::") == -1 )
enter_tag("resource","type=\""+res->get_type()+"\" path=\""+res->get_path()+"\""); //bundled
else {
- int idx = resource_map[res];
+
+ 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();
enter_tag("resource","type=\""+res->get_type()+"\" path=\"local://"+itos(idx)+"\"");
if (takeover_paths) {
res->set_path(p_path+"::"+itos(idx),true);
@@ -2558,6 +2806,7 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
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()) {
@@ -2568,9 +2817,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);
}
@@ -2588,6 +2840,11 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
}
exit_tag("resource_file");
+ if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
+ f->close();
+ return ERR_CANT_CREATE;
+ }
+
f->close();
//memdelete(f);
@@ -2620,3 +2877,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 40aaa01451..77987c6a5b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
};
@@ -123,9 +133,9 @@ class ResourceFormatSaverXMLInstance {
bool skip_editor;
FileAccess *f;
int depth;
- Map<RES,int> resource_map;
+ Set<RES> resource_set;
List<RES> saved_resources;
- Set<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 d2610d5d4f..3862790b02 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,11 +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);
@@ -129,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());
}
@@ -139,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
}
@@ -148,11 +155,18 @@ 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) {
- String local_path = Globals::get_singleton()->localize_path(p_path);
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
- local_path=find_complete_path(p_path,p_type_hint);
+ String local_path;
+ if (p_path.is_rel_path())
+ local_path="res://"+p_path;
+ else
+ local_path = Globals::get_singleton()->localize_path(p_path);
+
+ local_path=find_complete_path(local_path,p_type_hint);
ERR_FAIL_COND_V(local_path=="",RES());
if (!p_no_cache && ResourceCache::has(local_path)) {
@@ -178,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)
@@ -209,17 +223,20 @@ RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_n
Ref<ResourceImportMetadata> ResourceLoader::load_import_metadata(const String &p_path) {
- String local_path = Globals::get_singleton()->localize_path(p_path);
+
+ 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 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)
@@ -279,13 +296,19 @@ 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 = Globals::get_singleton()->localize_path(p_path);
+ String local_path;
+ if (p_path.is_rel_path())
+ local_path="res://"+p_path;
+ else
+ local_path = Globals::get_singleton()->localize_path(p_path);
- local_path=find_complete_path(p_path,p_type_hint);
+ local_path=find_complete_path(local_path,p_type_hint);
ERR_FAIL_COND_V(local_path=="",Ref<ResourceInteractiveLoader>());
@@ -313,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)
@@ -338,9 +361,15 @@ 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 local_path = Globals::get_singleton()->localize_path(p_path);
String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
String extension=remapped_path.extension();
@@ -352,14 +381,47 @@ 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);
+ 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;
+ 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;
+
+ 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 = Globals::get_singleton()->localize_path(p_path);
+ String local_path;
+ if (p_path.is_rel_path())
+ local_path="res://"+p_path;
+ else
+ local_path = Globals::get_singleton()->localize_path(p_path);
return find_complete_path(local_path,p_type);
@@ -367,7 +429,12 @@ String ResourceLoader::guess_full_filename(const String &p_path,const String& p_
String ResourceLoader::get_resource_type(const String &p_path) {
- String local_path = Globals::get_singleton()->localize_path(p_path);
+ 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();
@@ -385,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 ab23158785..00a05dcb43 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 598f517d76..fdb9a53f0d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index e307668721..8382b65290 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 0eae660373..b00b462eb6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index 84552cfd3e..e83fc71b93 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index 0e75e22767..c2343790ea 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@ StreamPeerTCP* (*StreamPeerTCP::_create)()=NULL;
void StreamPeerTCP::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("connect","host","ip"),&StreamPeerTCP::connect);
+ ObjectTypeDB::bind_method(_MD("connect","host","port"),&StreamPeerTCP::connect);
ObjectTypeDB::bind_method(_MD("is_connected"),&StreamPeerTCP::is_connected);
ObjectTypeDB::bind_method(_MD("get_status"),&StreamPeerTCP::get_status);
ObjectTypeDB::bind_method(_MD("get_connected_host"),&StreamPeerTCP::get_connected_host);
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index d447ded78b..0e37303516 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp
index bce9e19ae3..803df87086 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h
index fff00e5ce0..b59f3293d7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 0d42cebb41..020d168208 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 7a0c4e10dc..e07ae15e28 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 5d3e4f61ad..1ff458f325 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,9 +30,11 @@
#include "print_string.h"
//#define DEBUG_XML
+VARIANT_ENUM_CAST(XMLParser::NodeType);
+
static bool _equalsn(const CharType* str1, const CharType* str2, int len) {
int i;
- for(i=0; str1[i] && str2[i] && i < len; ++i)
+ for(i=0; i < len && str1[i] && str2[i] ; ++i)
if (str1[i] != str2[i])
return false;
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index 9debbf9e2f..418a8efa70 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 798265cc48..dd3c371a4a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 f581feb735..018abca940 100644
--- a/core/list.h
+++ b/core/list.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#define GLOBALS_LIST_H
#include "os/memory.h"
-
+#include "sort.h"
/**
* Generic Templatized Linked List Implementation.
@@ -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) {
@@ -551,7 +557,7 @@ public:
}
template<class C>
- void sort_custom() {
+ void sort_custom_inplace() {
if(size()<2)
return;
@@ -603,6 +609,58 @@ public:
_data->last=to;
}
+ template<class C>
+ struct AuxiliaryComparator {
+
+ C compare;
+ _FORCE_INLINE_ bool operator()(const Element *a,const Element* b) const {
+
+ return compare(a->value,b->value);
+ }
+ };
+
+ template<class C>
+ void sort_custom() {
+
+ //this version uses auxiliary memory for speed.
+ //if you don't want to use auxiliary memory, use the in_place version
+
+ int s = size();
+ if(s<2)
+ return;
+
+
+ Element **aux_buffer = memnew_arr(Element*,s);
+
+ int idx=0;
+ for(Element *E=front();E;E=E->next_ptr) {
+
+ aux_buffer[idx]=E;
+ idx++;
+ }
+
+ SortArray<Element*,AuxiliaryComparator<C> > sort;
+ sort.sort(aux_buffer,s);
+
+ _data->first=aux_buffer[0];
+ aux_buffer[0]->prev_ptr=NULL;
+ aux_buffer[0]->next_ptr=aux_buffer[1];
+
+ _data->last=aux_buffer[s-1];
+ aux_buffer[s-1]->prev_ptr=aux_buffer[s-2];
+ aux_buffer[s-1]->next_ptr=NULL;
+
+ for(int i=1;i<s-1;i++) {
+
+ aux_buffer[i]->prev_ptr=aux_buffer[i-1];
+ aux_buffer[i]->next_ptr=aux_buffer[i+1];
+
+ }
+
+ memdelete_arr(aux_buffer);
+ }
+
+
/**
* copy constructor for the list
*/
diff --git a/core/make_binders.py b/core/make_binders.py
index 5d35dd9337..ebd48777b6 100644
--- a/core/make_binders.py
+++ b/core/make_binders.py
@@ -214,25 +214,36 @@ def make_version(template,nargs,argmax,const,ret):
def run(target, source, env):
- versions=5
+ versions=10
+ versions_ext=6
text=""
+ text_ext=""
for i in range(0,versions+1):
- text+=make_version(template,i,5,False,False)
- text+=make_version(template_typed,i,5,False,False)
- text+=make_version(template,i,5,False,True)
- text+=make_version(template_typed,i,5,False,True)
- text+=make_version(template,i,5,True,False)
- text+=make_version(template_typed,i,5,True,False)
- text+=make_version(template,i,5,True,True)
- text+=make_version(template_typed,i,5,True,True)
+ t=""
+ t+=make_version(template,i,versions,False,False)
+ t+=make_version(template_typed,i,versions,False,False)
+ t+=make_version(template,i,versions,False,True)
+ t+=make_version(template_typed,i,versions,False,True)
+ t+=make_version(template,i,versions,True,False)
+ t+=make_version(template_typed,i,versions,True,False)
+ t+=make_version(template,i,versions,True,True)
+ t+=make_version(template_typed,i,versions,True,True)
+ if (i>=versions_ext):
+ text_ext+=t
+ else:
+ text+=t
f=open(target[0].path,"w")
f.write(text)
f.close()
+ f=open(target[1].path,"w")
+ f.write(text_ext)
+ f.close()
+
diff --git a/core/map.h b/core/map.h
index 05abdc510e..e45c833bcb 100644
--- a/core/map.h
+++ b/core/map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 576e4fa928..435df66aab 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/aabb.h b/core/math/aabb.h
index 089d5d15f7..4781e5c263 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -110,17 +110,17 @@ public:
inline bool AABB::intersects(const AABB& p_aabb) const {
- if ( pos.x > (p_aabb.pos.x + p_aabb.size.x) )
+ if ( pos.x >= (p_aabb.pos.x + p_aabb.size.x) )
return false;
- if ( (pos.x+size.x) < p_aabb.pos.x )
+ if ( (pos.x+size.x) <= p_aabb.pos.x )
return false;
- if ( pos.y > (p_aabb.pos.y + p_aabb.size.y) )
+ if ( pos.y >= (p_aabb.pos.y + p_aabb.size.y) )
return false;
- if ( (pos.y+size.y) < p_aabb.pos.y )
+ if ( (pos.y+size.y) <= p_aabb.pos.y )
return false;
- if ( pos.z > (p_aabb.pos.z + p_aabb.size.z) )
+ if ( pos.z >= (p_aabb.pos.z + p_aabb.size.z) )
return false;
- if ( (pos.z+size.z) < p_aabb.pos.z )
+ if ( (pos.z+size.z) <= p_aabb.pos.z )
return false;
return true;
diff --git a/core/math/bezier_curve.cpp b/core/math/bezier_curve.cpp
index 2676804945..c9467a77e4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/bezier_curve.h b/core/math/bezier_curve.h
index 6cc4c730db..de14d68987 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp
index 7f838b1215..d71b7551d9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/bsp_tree.h b/core/math/bsp_tree.h
index 03bfd947cb..b980d9590b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index 52d77b6ebc..f1afa33a4b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -67,9 +67,10 @@ Plane CameraMatrix::xform4(const Plane& p_vec4) {
void CameraMatrix::set_perspective(float p_fovy_degrees, float p_aspect, float p_z_near, float p_z_far,bool p_flip_fov) {
- if (p_flip_fov)
- p_fovy_degrees=get_fovy(p_fovy_degrees,p_aspect);
+ if (p_flip_fov) {
+ p_fovy_degrees=get_fovy(p_fovy_degrees,1.0/p_aspect);
+ }
float sine, cotangent, deltaZ;
float radians = p_fovy_degrees / 2.0 * Math_PI / 180.0;
@@ -110,7 +111,7 @@ void CameraMatrix::set_orthogonal(float p_left, float p_right, float p_bottom, f
void CameraMatrix::set_orthogonal(float p_size, float p_aspect, float p_znear, float p_zfar,bool p_flip_fov) {
- if (p_flip_fov) {
+ if (!p_flip_fov) {
p_size*=p_aspect;
}
@@ -120,7 +121,7 @@ void CameraMatrix::set_orthogonal(float p_size, float p_aspect, float p_znear, f
void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, float p_top, float p_near, float p_far) {
-
+#if 0
///@TODO, give a check to this. I'm not sure if it's working.
set_identity();
@@ -132,10 +133,27 @@ void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, floa
matrix[2][3]=-(2*p_far*p_near) / (p_far-p_near);
matrix[3][2]=-1;
matrix[3][3]=0;
+#else
+ float *te = &matrix[0][0];
+ float x = 2 * p_near / ( p_right - p_left );
+ float y = 2 * p_near / ( p_top - p_bottom );
+
+ float a = ( p_right + p_left ) / ( p_right - p_left );
+ float b = ( p_top + p_bottom ) / ( p_top - p_bottom );
+ float c = - ( p_far + p_near ) / ( p_far - p_near );
+ float d = - 2 * p_far * p_near / ( p_far - p_near );
+
+ te[0] = x; te[4] = 0; te[8] = a; te[12] = 0;
+ te[1] = 0; te[5] = y; te[9] = b; te[13] = 0;
+ te[2] = 0; te[6] = 0; te[10] = c; te[14] = d;
+ te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0;
+
+#endif
}
+
float CameraMatrix::get_z_far() const {
const float * matrix = (const float*)this->matrix;
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 6ffcb0ed0b..52b84f4870 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -60,7 +60,7 @@ struct CameraMatrix {
static float get_fovy(float p_fovx,float p_aspect) {
- return Math::atan(p_aspect * Math::tan(p_fovx * 0.5))*2.0;
+ return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5))*2.0);
}
float get_z_far() const;
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index 814f2d675d..354372df74 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -356,4 +356,100 @@ void Face3::get_support(const Vector3& p_normal,const Transform& p_transform,Vec
}
+Vector3 Face3::get_closest_point_to(const Vector3& p_point) const {
+
+ Vector3 edge0 = vertex[1] - vertex[0];
+ Vector3 edge1 = vertex[2] - vertex[0];
+ Vector3 v0 = vertex[0] - p_point;
+
+ float a = edge0.dot( edge0 );
+ float b = edge0.dot( edge1 );
+ float c = edge1.dot( edge1 );
+ float d = edge0.dot( v0 );
+ float e = edge1.dot( v0 );
+
+ float det = a*c - b*b;
+ float s = b*e - c*d;
+ float t = b*d - a*e;
+
+ if ( s + t < det )
+ {
+ if ( s < 0.f )
+ {
+ if ( t < 0.f )
+ {
+ if ( d < 0.f )
+ {
+ s = CLAMP( -d/a, 0.f, 1.f );
+ t = 0.f;
+ }
+ else
+ {
+ s = 0.f;
+ t = CLAMP( -e/c, 0.f, 1.f );
+ }
+ }
+ else
+ {
+ s = 0.f;
+ t = CLAMP( -e/c, 0.f, 1.f );
+ }
+ }
+ else if ( t < 0.f )
+ {
+ s = CLAMP( -d/a, 0.f, 1.f );
+ t = 0.f;
+ }
+ else
+ {
+ float invDet = 1.f / det;
+ s *= invDet;
+ t *= invDet;
+ }
+ }
+ else
+ {
+ if ( s < 0.f )
+ {
+ float tmp0 = b+d;
+ float tmp1 = c+e;
+ if ( tmp1 > tmp0 )
+ {
+ float numer = tmp1 - tmp0;
+ float denom = a-2*b+c;
+ s = CLAMP( numer/denom, 0.f, 1.f );
+ t = 1-s;
+ }
+ else
+ {
+ t = CLAMP( -e/c, 0.f, 1.f );
+ s = 0.f;
+ }
+ }
+ else if ( t < 0.f )
+ {
+ if ( a+d > b+e )
+ {
+ float numer = c+e-b-d;
+ float denom = a-2*b+c;
+ s = CLAMP( numer/denom, 0.f, 1.f );
+ t = 1-s;
+ }
+ else
+ {
+ s = CLAMP( -e/c, 0.f, 1.f );
+ t = 0.f;
+ }
+ }
+ else
+ {
+ float numer = c+e-b-d;
+ float denom = a-2*b+c;
+ s = CLAMP( numer/denom, 0.f, 1.f );
+ t = 1.f - s;
+ }
+ }
+
+ return vertex[0] + s * edge0 + t * edge1;
+}
diff --git a/core/math/face3.h b/core/math/face3.h
index 630c408de3..eccbc78122 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -68,6 +68,7 @@ public:
real_t get_area() const;
Vector3 get_median_point() const;
+ Vector3 get_closest_point_to(const Vector3& p_point) const;
bool intersects_ray(const Vector3& p_from,const Vector3& p_dir,Vector3 * p_intersection=0) const;
bool intersects_segment(const Vector3& p_from,const Vector3& p_dir,Vector3 * p_intersection=0) const;
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index cb76b9ed0f..14adde74e7 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -1004,3 +1004,134 @@ DVector<Plane> Geometry::build_capsule_planes(float p_radius, float p_height, in
}
+
+struct _AtlasWorkRect {
+
+ Size2i s;
+ Point2i p;
+ int idx;
+ _FORCE_INLINE_ bool operator<(const _AtlasWorkRect& p_r) const { return s.width > p_r.s.width; };
+};
+
+struct _AtlasWorkRectResult {
+
+ Vector<_AtlasWorkRect> result;
+ int max_w;
+ int max_h;
+};
+
+void Geometry::make_atlas(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, Size2i& r_size) {
+
+ //super simple, almost brute force scanline stacking fitter
+ //it's pretty basic for now, but it tries to make sure that the aspect ratio of the
+ //resulting atlas is somehow square. This is necesary because video cards have limits
+ //on texture size (usually 2048 or 4096), so the more square a texture, the more chances
+ //it will work in every hardware.
+ // for example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a
+ // 256x8192 atlas (won't work anywhere).
+
+ ERR_FAIL_COND(p_rects.size()==0);
+
+ Vector<_AtlasWorkRect> wrects;
+ wrects.resize(p_rects.size());
+ for(int i=0;i<p_rects.size();i++) {
+ wrects[i].s=p_rects[i];
+ wrects[i].idx=i;
+ }
+ wrects.sort();
+ int widest = wrects[0].s.width;
+
+ Vector<_AtlasWorkRectResult> results;
+
+ for(int i=0;i<=12;i++) {
+
+ int w = 1<<i;
+ int max_h=0;
+ int max_w=0;
+ if ( w < widest )
+ continue;
+
+ Vector<int> hmax;
+ hmax.resize(w);
+ for(int j=0;j<w;j++)
+ hmax[j]=0;
+
+ //place them
+ int ofs=0;
+ int limit_h=0;
+ for(int j=0;j<wrects.size();j++) {
+
+
+ if (ofs+wrects[j].s.width > w) {
+
+ ofs=0;
+ }
+
+ int from_y=0;
+ for(int k=0;k<wrects[j].s.width;k++) {
+
+ if (hmax[ofs+k] > from_y)
+ from_y=hmax[ofs+k];
+ }
+
+ 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)
+ limit_h=end_h;
+
+ for(int k=0;k<wrects[j].s.width;k++) {
+
+ hmax[ofs+k]=end_h;
+ }
+
+ if (end_h > max_h)
+ max_h=end_h;
+
+ if (end_w > max_w)
+ max_w=end_w;
+
+ if (ofs==0 || end_h>limit_h ) //while h limit not reched, keep stacking
+ ofs+=wrects[j].s.width;
+
+ }
+
+ _AtlasWorkRectResult result;
+ result.result=wrects;
+ result.max_h=max_h;
+ result.max_w=max_w;
+ results.push_back(result);
+
+ }
+
+ //find the result with the best aspect ratio
+
+ int best=-1;
+ float best_aspect=1e20;
+
+ 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 aspect = h>w ? h/w : w/h;
+ if (aspect < best_aspect) {
+ best=i;
+ best_aspect=aspect;
+ }
+ }
+
+ r_result.resize(p_rects.size());
+
+ for(int i=0;i<p_rects.size();i++) {
+
+ r_result[ results[best].result[i].idx ]=results[best].result[i].p;
+ }
+
+ r_size=Size2(results[best].max_w,results[best].max_h );
+
+}
+
+
+
+
diff --git a/core/math/geometry.h b/core/math/geometry.h
index 5b21c25bec..b438b41d61 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -511,6 +511,20 @@ public:
else
return p_segment[0]+n*d; // inside
}
+
+ static bool is_point_in_triangle(const Vector2& s, const Vector2& a, const Vector2& b, const Vector2& c)
+ {
+ int as_x = s.x-a.x;
+ int as_y = s.y-a.y;
+
+ bool s_ab = (b.x-a.x)*as_y-(b.y-a.y)*as_x > 0;
+
+ if(((c.x-a.x)*as_y-(c.y-a.y)*as_x > 0) == s_ab) return false;
+
+ if(((c.x-b.x)*(s.y-b.y)-(c.y-b.y)*(s.x-b.x) > 0) != s_ab) return false;
+
+ return true;
+ }
static Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2& p_point, const Vector2 *p_segment) {
Vector2 p=p_point-p_segment[0];
@@ -821,12 +835,67 @@ public:
};
+
+ _FORCE_INLINE_ static int get_uv84_normal_bit(const Vector3& p_vector) {
+
+ int lat = Math::fast_ftoi(Math::floor(Math::acos(p_vector.dot(Vector3(0,1,0)))*4.0/Math_PI+0.5));
+
+ if (lat==0) {
+ return 24;
+ } else if (lat==4) {
+ return 25;
+ }
+
+ int lon = Math::fast_ftoi(Math::floor( (Math_PI+Math::atan2(p_vector.x,p_vector.z))*8.0/(Math_PI*2.0) + 0.5))%8;
+
+ return lon+(lat-1)*8;
+ }
+
+ _FORCE_INLINE_ static int get_uv84_normal_bit_neighbors(int p_idx) {
+
+ if (p_idx==24) {
+ return 1|2|4|8;
+ } else if (p_idx==25) {
+ return (1<<23)|(1<<22)|(1<<21)|(1<<20);
+ } else {
+
+ int ret = 0;
+ if ((p_idx%8) == 0)
+ ret|=(1<<(p_idx+7));
+ else
+ ret|=(1<<(p_idx-1));
+ if ((p_idx%8) == 7)
+ ret|=(1<<(p_idx-7));
+ else
+ ret|=(1<<(p_idx+1));
+
+ int mask = ret|(1<<p_idx);
+ if (p_idx<8)
+ ret|=24;
+ else
+ ret|=mask>>8;
+
+ if (p_idx>=16)
+ ret|=25;
+ else
+ ret|=mask<<8;
+
+ return ret;
+ }
+
+ }
+
+
+
+
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);
static DVector<Plane> build_box_planes(const Vector3& p_extents);
static DVector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis=Vector3::AXIS_Z);
static DVector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis=Vector3::AXIS_Z);
-
+
+ static void make_atlas(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, Size2i& r_size);
+
};
diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp
index 6c160abaca..ce03f089e5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,7 +29,7 @@
#include "math_2d.h"
-real_t Vector2::atan2() const {
+real_t Vector2::angle() const {
return Math::atan2(x,y);
}
@@ -77,6 +77,11 @@ float Vector2::angle_to(const Vector2& p_vector2) const {
return Math::atan2( tangent().dot(p_vector2), dot(p_vector2) );
}
+float Vector2::angle_to_point(const Vector2& p_vector2) const {
+
+ return Math::atan2( x-p_vector2.x, y - p_vector2.y );
+}
+
float Vector2::dot(const Vector2& p_other) const {
return x*p_other.x + y*p_other.y;
@@ -160,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;
}
@@ -225,6 +230,23 @@ Vector2 Vector2::cubic_interpolate(const Vector2& p_b,const Vector2& p_pre_a, co
+ Vector2 p0=p_pre_a;
+ Vector2 p1=*this;
+ Vector2 p2=p_b;
+ Vector2 p3=p_post_b;
+
+ float t = p_t;
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ Vector2 out;
+ out = 0.5f * ( ( p1 * 2.0f) +
+ ( -p0 + p2 ) * t +
+ ( 2.0f * p0 - 5.0f * p1 + 4 * p2 - p3 ) * t2 +
+ ( -p0 + 3.0f * p1 - 3.0f * p2 + p3 ) * t3 );
+ return out;
+
+/*
float mu = p_t;
float mu2 = mu*mu;
@@ -234,7 +256,7 @@ Vector2 Vector2::cubic_interpolate(const Vector2& p_b,const Vector2& p_pre_a, co
Vector2 a3 = *this;
return ( a0*mu*mu2 + a1*mu2 + a2*mu + a3 );
-
+*/
/*
float t = p_t;
real_t t2 = t*t;
@@ -600,9 +622,39 @@ float Matrix32::basis_determinant() const {
}
Matrix32 Matrix32::interpolate_with(const Matrix32& p_transform, float p_c) const {
+
+ //extract parameters
+ Vector2 p1 = get_origin();
+ Vector2 p2 = p_transform.get_origin();
+
+ real_t r1 = get_rotation();
+ real_t r2 = p_transform.get_rotation();
+
+ Vector2 s1 = get_scale();
+ Vector2 s2 = p_transform.get_scale();
+
+ //slerp rotation
+ Vector2 v1(Math::cos(r1), Math::sin(r1));
+ Vector2 v2(Math::cos(r2), Math::sin(r2));
+
+ real_t dot = v1.dot(v2);
+
+ dot = (dot < -1.0) ? -1.0 : ((dot > 1.0) ? 1.0 : dot); //clamp dot to [-1,1]
+
+ Vector2 v;
-
- return Matrix32();
+ if (dot > 0.9995) {
+ v = Vector2::linear_interpolate(v1, v2, p_c).normalized(); //linearly interpolate to avoid numerical precision issues
+ } else {
+ real_t angle = p_c*Math::acos(dot);
+ Vector2 v3 = (v2 - v1*dot).normalized();
+ v = v1*Math::cos(angle) + v3*Math::sin(angle);
+ }
+
+ //construct matrix
+ Matrix32 res(Math::atan2(v.y, v.x), Vector2::linear_interpolate(p1, p2, p_c));
+ res.scale_basis(Vector2::linear_interpolate(s1, s2, p_c));
+ return res;
}
Matrix32::operator String() const {
diff --git a/core/math/math_2d.h b/core/math/math_2d.h
index 3cc5bdc843..3d40e24091 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -90,7 +90,8 @@ struct Vector2 {
float distance_to(const Vector2& p_vector2) const;
float distance_squared_to(const Vector2& p_vector2) const;
float angle_to(const Vector2& p_vector2) const;
-
+ float angle_to_point(const Vector2& p_vector2) const;
+
float dot(const Vector2& p_other) const;
float cross(const Vector2& p_other) const;
Vector2 cross(real_t p_other) const;
@@ -132,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) {
@@ -158,8 +159,8 @@ struct Vector2 {
operator String() const { return String::num(x)+","+String::num(y); }
- inline Vector2(float p_x,float p_y) { x=p_x; y=p_y; }
- inline Vector2() { x=0; y=0; }
+ _FORCE_INLINE_ Vector2(float p_x,float p_y) { x=p_x; y=p_y; }
+ _FORCE_INLINE_ Vector2() { x=0; y=0; }
};
_FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2& p_vec) const {
@@ -197,6 +198,8 @@ Vector2 Vector2::linear_interpolate(const Vector2& p_a, const Vector2& p_b,float
typedef Vector2 Size2;
typedef Vector2 Point2;
+struct Matrix32;
+
struct Rect2 {
@@ -211,18 +214,43 @@ struct Rect2 {
float get_area() const { return size.width*size.height; }
inline bool intersects(const Rect2& p_rect) const {
- if ( pos.x > (p_rect.pos.x + p_rect.size.width) )
+ if ( pos.x >= (p_rect.pos.x + p_rect.size.width) )
return false;
- if ( (pos.x+size.width) < p_rect.pos.x )
+ if ( (pos.x+size.width) <= p_rect.pos.x )
return false;
- if ( pos.y > (p_rect.pos.y + p_rect.size.height) )
+ if ( pos.y >= (p_rect.pos.y + p_rect.size.height) )
return false;
- if ( (pos.y+size.height) < p_rect.pos.y )
+ if ( (pos.y+size.height) <= p_rect.pos.y )
return false;
return true;
}
+ inline float distance_to(const Vector2& p_point) const {
+
+ float dist = 1e20;
+
+ if (p_point.x < pos.x) {
+ dist=MIN(dist,pos.x-p_point.x);
+ }
+ if (p_point.y < pos.y) {
+ dist=MIN(dist,pos.y-p_point.y);
+ }
+ if (p_point.x >= (pos.x+size.x) ) {
+ dist=MIN(p_point.x-(pos.x+size.x),dist);
+ }
+ if (p_point.y >= (pos.y+size.y) ) {
+ dist=MIN(p_point.y-(pos.y+size.y),dist);
+ }
+
+ if (dist==1e20)
+ return 0;
+ else
+ return dist;
+ }
+
+ _FORCE_INLINE_ bool intersects_transformed(const Matrix32& p_xform, const Rect2& p_rect) const;
+
bool intersects_segment(const Point2& p_from, const Point2& p_to, Point2* r_pos=NULL, Point2* r_normal=NULL) const;
inline bool encloses(const Rect2& p_rect) const {
@@ -596,6 +624,160 @@ struct Matrix32 {
};
+bool Rect2::intersects_transformed(const Matrix32& p_xform, const Rect2& p_rect) const {
+
+ //SAT intersection between local and transformed rect2
+
+ Vector2 xf_points[4]={
+ p_xform.xform(p_rect.pos),
+ p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y)),
+ p_xform.xform(Vector2(p_rect.pos.x,p_rect.pos.y+p_rect.size.y)),
+ p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y+p_rect.size.y)),
+ };
+
+ real_t low_limit;
+
+ //base rect2 first (faster)
+
+ if (xf_points[0].y>pos.y)
+ goto next1;
+ if (xf_points[1].y>pos.y)
+ goto next1;
+ if (xf_points[2].y>pos.y)
+ goto next1;
+ if (xf_points[3].y>pos.y)
+ goto next1;
+
+ return false;
+
+ next1:
+
+ low_limit=pos.y+size.y;
+
+ if (xf_points[0].y<low_limit)
+ goto next2;
+ if (xf_points[1].y<low_limit)
+ goto next2;
+ if (xf_points[2].y<low_limit)
+ goto next2;
+ if (xf_points[3].y<low_limit)
+ goto next2;
+
+ return false;
+
+ next2:
+
+ if (xf_points[0].x>pos.x)
+ goto next3;
+ if (xf_points[1].x>pos.x)
+ goto next3;
+ if (xf_points[2].x>pos.x)
+ goto next3;
+ if (xf_points[3].x>pos.x)
+ goto next3;
+
+ return false;
+
+ next3:
+
+ low_limit=pos.x+size.x;
+
+ if (xf_points[0].x<low_limit)
+ goto next4;
+ if (xf_points[1].x<low_limit)
+ goto next4;
+ if (xf_points[2].x<low_limit)
+ goto next4;
+ if (xf_points[3].x<low_limit)
+ goto next4;
+
+ return false;
+
+ next4:
+
+ Vector2 xf_points2[4]={
+ pos,
+ Vector2(pos.x+size.x,pos.y),
+ Vector2(pos.x,pos.y+size.y),
+ Vector2(pos.x+size.x,pos.y+size.y),
+ };
+
+ real_t maxa=p_xform.elements[0].dot(xf_points2[0]);
+ real_t mina=maxa;
+
+ real_t dp = p_xform.elements[0].dot(xf_points2[1]);
+ maxa=MAX(dp,maxa);
+ mina=MIN(dp,mina);
+
+ dp = p_xform.elements[0].dot(xf_points2[2]);
+ maxa=MAX(dp,maxa);
+ mina=MIN(dp,mina);
+
+ dp = p_xform.elements[0].dot(xf_points2[3]);
+ maxa=MAX(dp,maxa);
+ mina=MIN(dp,mina);
+
+ real_t maxb=p_xform.elements[0].dot(xf_points[0]);
+ real_t minb=maxb;
+
+ dp = p_xform.elements[0].dot(xf_points[1]);
+ maxb=MAX(dp,maxb);
+ minb=MIN(dp,minb);
+
+ dp = p_xform.elements[0].dot(xf_points[2]);
+ maxb=MAX(dp,maxb);
+ minb=MIN(dp,minb);
+
+ dp = p_xform.elements[0].dot(xf_points[3]);
+ maxb=MAX(dp,maxb);
+ minb=MIN(dp,minb);
+
+
+ if ( mina > maxb )
+ return false;
+ if ( minb > maxa )
+ return false;
+
+ maxa=p_xform.elements[1].dot(xf_points2[0]);
+ mina=maxa;
+
+ dp = p_xform.elements[1].dot(xf_points2[1]);
+ maxa=MAX(dp,maxa);
+ mina=MIN(dp,mina);
+
+ dp = p_xform.elements[1].dot(xf_points2[2]);
+ maxa=MAX(dp,maxa);
+ mina=MIN(dp,mina);
+
+ dp = p_xform.elements[1].dot(xf_points2[3]);
+ maxa=MAX(dp,maxa);
+ mina=MIN(dp,mina);
+
+ maxb=p_xform.elements[1].dot(xf_points[0]);
+ minb=maxb;
+
+ dp = p_xform.elements[1].dot(xf_points[1]);
+ maxb=MAX(dp,maxb);
+ minb=MIN(dp,minb);
+
+ dp = p_xform.elements[1].dot(xf_points[2]);
+ maxb=MAX(dp,maxb);
+ minb=MIN(dp,minb);
+
+ dp = p_xform.elements[1].dot(xf_points[3]);
+ maxb=MAX(dp,maxb);
+ minb=MIN(dp,minb);
+
+
+ if ( mina > maxb )
+ return false;
+ if ( minb > maxa )
+ return false;
+
+
+ return true;
+
+}
Vector2 Matrix32::basis_xform(const Vector2& v) const {
diff --git a/core/math/math_defs.cpp b/core/math/math_defs.cpp
index ca43bc7ae3..51aaa6800e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,5 +26,5 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "math_defs.h"
-
+#include "math_defs.h"
+
diff --git a/core/math/math_defs.h b/core/math/math_defs.h
index dd0390240a..7cb6c7f499 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,35 +26,35 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef MATH_DEFS_H
-#define MATH_DEFS_H
-
-#define CMP_EPSILON 0.00001
-#define CMP_EPSILON2 (CMP_EPSILON*CMP_EPSILON)
-#define CMP_NORMALIZE_TOLERANCE 0.000001
-#define CMP_POINT_IN_PLANE_EPSILON 0.00001
-
-/**
- * "Real" is a type that will be translated to either floats or fixed depending
- * on the compilation setting
- */
-
-enum ClockDirection {
-
- CLOCKWISE,
- COUNTERCLOCKWISE
-};
-
-
-#ifdef REAL_T_IS_DOUBLE
-
-typedef double real_t;
-
-#else
-
-typedef float real_t;
-
-#endif
-
-
-#endif // MATH_DEFS_H
+#ifndef MATH_DEFS_H
+#define MATH_DEFS_H
+
+#define CMP_EPSILON 0.00001
+#define CMP_EPSILON2 (CMP_EPSILON*CMP_EPSILON)
+#define CMP_NORMALIZE_TOLERANCE 0.000001
+#define CMP_POINT_IN_PLANE_EPSILON 0.00001
+
+/**
+ * "Real" is a type that will be translated to either floats or fixed depending
+ * on the compilation setting
+ */
+
+enum ClockDirection {
+
+ CLOCKWISE,
+ COUNTERCLOCKWISE
+};
+
+
+#ifdef REAL_T_IS_DOUBLE
+
+typedef double real_t;
+
+#else
+
+typedef float real_t;
+
+#endif
+
+
+#endif // MATH_DEFS_H
diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp
index 92236a374f..3c94ac5bc7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,8 +36,9 @@ uint32_t Math::default_seed=1;
#define PHI 0x9e3779b9
-static uint32_t Q[4096], c = 362436;
-
+#if 0
+static uint32_t Q[4096];
+#endif
uint32_t Math::rand_from_seed(uint32_t *seed) {
@@ -48,8 +49,8 @@ uint32_t Math::rand_from_seed(uint32_t *seed) {
s = 0x12345987;
k = s / 127773;
s = 16807 * (s - k * 127773) - 2836 * k;
- if (s < 0)
- s += 2147483647;
+// if (s < 0)
+// s += 2147483647;
(*seed) = s;
return (s & Math::RANDOM_MAX);
#else
@@ -76,7 +77,7 @@ void Math::seed(uint32_t x) {
void Math::randomize() {
OS::Time time = OS::get_singleton()->get_time();
- seed(OS::get_singleton()->get_ticks_usec()*time.hour*time.min*time.sec*rand()); /* *OS::get_singleton()->get_time().sec); // windows doesn't have get_time(), returns always 0 */
+ seed(OS::get_singleton()->get_ticks_usec()*(time.hour+1)*(time.min+1)*(time.sec+1)*rand()); /* *OS::get_singleton()->get_time().sec); // windows doesn't have get_time(), returns always 0 */
}
uint32_t Math::rand() {
@@ -269,7 +270,7 @@ bool Math::is_inf(double p_val) {
uint32_t Math::larger_prime(uint32_t p_val) {
- static const int primes[] = {
+ static const uint32_t primes[] = {
5,
13,
23,
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index c98a088912..ec089ebc8b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
@@ -136,7 +136,10 @@ public:
static int b;
-#if defined(_MSC_VER) && _MSC_VER < 1800
+#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0603) || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // windows 8 phone?
+ b = (int)((a>0.0f) ? (a + 0.5f):(a -0.5f));
+
+#elif defined(_MSC_VER) && _MSC_VER < 1800
__asm fld a
__asm fistp b
/*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
@@ -147,6 +150,7 @@ public:
"fistpl %0 \n\t"
: "=m" (b)
: "m" (a));*/
+
#else
b=lrintf(a); //assuming everything but msvc 2012 or earlier has lrint
#endif
diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp
index ff62e7786b..10f1461fdc 100644
--- a/core/math/matrix3.cpp
+++ b/core/math/matrix3.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/matrix3.h b/core/math/matrix3.h
index f68703ca23..98feb2dbbd 100644
--- a/core/math/matrix3.h
+++ b/core/math/matrix3.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/octree.h b/core/math/octree.h
index b64ba381c0..84de388178 100644
--- a/core/math/octree.h
+++ b/core/math/octree.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 88c7be5f63..f9395a002a 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/plane.h b/core/math/plane.h
index 608ec26926..604b880266 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index 950a4756ad..e0c4b0793c 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/quat.h b/core/math/quat.h
index d326073033..f161e35074 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -64,6 +64,22 @@ public:
Quat operator*(const Quat& q) const;
+
+ Quat operator*(const Vector3& v) const
+ {
+ return Quat( w * v.x + y * v.z - z * v.y,
+ w * v.y + z * v.x - x * v.z,
+ w * v.z + x * v.y - y * v.x,
+ -x * v.x - y * v.y - z * v.z);
+ }
+
+ _FORCE_INLINE_ Vector3 xform(const Vector3& v) const {
+
+ Quat q = *this * v;
+ q *= this->inverse();
+ return Vector3(q.x,q.y,q.z);
+ }
+
_FORCE_INLINE_ void operator+=(const Quat& q);
_FORCE_INLINE_ void operator-=(const Quat& q);
_FORCE_INLINE_ void operator*=(const real_t& s);
@@ -87,6 +103,29 @@ public:
x=p_x; y=p_y; z=p_z; w=p_w;
}
Quat(const Vector3& axis, const real_t& angle);
+
+ Quat(const Vector3& v0, const Vector3& v1) // shortest arc
+ {
+ Vector3 c = v0.cross(v1);
+ real_t d = v0.dot(v1);
+
+ if (d < -1.0 + CMP_EPSILON) {
+ x=0;
+ y=1;
+ z=0;
+ w=0;
+ } else {
+
+ real_t s = Math::sqrt((1.0f + d) * 2.0f);
+ real_t rs = 1.0f / s;
+
+ x=c.x*rs;
+ y=c.y*rs;
+ z=c.z*rs;
+ w=s * 0.5;
+ }
+ }
+
inline Quat() {x=y=z=0; w=1; }
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index ed30de6915..80ae0f04e1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -63,7 +63,7 @@ Error QuickHull::build(const Vector<Vector3>& p_points, Geometry::MeshData &r_me
Vector3 sp = p_points[i].snapped(0.0001);
if (valid_cache.has(sp)) {
valid_points[i]=false;
- print_line("INVALIDATED: "+itos(i));
+ //print_line("INVALIDATED: "+itos(i));
}else {
valid_points[i]=true;
valid_cache.insert(sp);
@@ -428,6 +428,7 @@ Error QuickHull::build(const Vector<Vector3>& p_points, Geometry::MeshData &r_me
List<Geometry::MeshData::Face>::Element *O = F->get().left == E ? F->get().right : F->get().left;
ERR_CONTINUE(O==E);
+ ERR_CONTINUE(O==NULL);
if (O->get().plane.is_almost_like(f.plane)) {
//merge and delete edge and contiguous face, while repointing edges (uuugh!)
diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h
index d7f056d366..cb486a0b6f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/transform.cpp b/core/math/transform.cpp
index bb874facbd..a6f4f626cc 100644
--- a/core/math/transform.cpp
+++ b/core/math/transform.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/transform.h b/core/math/transform.h
index b1a0ea1ab8..a992843d70 100644
--- a/core/math/transform.h
+++ b/core/math/transform.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 111ceca185..70cb639fc2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,543 +26,543 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "triangle_mesh.h"
-#include "sort.h"
-
-
-
-int TriangleMesh::_create_bvh(BVH*p_bvh,BVH** p_bb,int p_from,int p_size,int p_depth,int&max_depth,int&max_alloc) {
-
-
- if (p_depth>max_depth) {
- max_depth=p_depth;
- }
-
- if (p_size==1) {
-
-
- return p_bb[p_from]-p_bvh;
- } else if (p_size==0) {
-
- return -1;
- }
-
-
- AABB aabb;
- aabb=p_bb[p_from]->aabb;
- for(int i=1;i<p_size;i++) {
-
- aabb.merge_with(p_bb[p_from+i]->aabb);
- }
-
- int li=aabb.get_longest_axis_index();
-
- switch(li) {
-
- case Vector3::AXIS_X: {
- SortArray<BVH*,BVHCmpX> sort_x;
- sort_x.nth_element(0,p_size,p_size/2,&p_bb[p_from]);
- //sort_x.sort(&p_bb[p_from],p_size);
- } break;
- case Vector3::AXIS_Y: {
- SortArray<BVH*,BVHCmpY> sort_y;
- sort_y.nth_element(0,p_size,p_size/2,&p_bb[p_from]);
- //sort_y.sort(&p_bb[p_from],p_size);
- } break;
- case Vector3::AXIS_Z: {
- SortArray<BVH*,BVHCmpZ> sort_z;
- sort_z.nth_element(0,p_size,p_size/2,&p_bb[p_from]);
- //sort_z.sort(&p_bb[p_from],p_size);
-
- } break;
- }
-
-
- int left = _create_bvh(p_bvh,p_bb,p_from,p_size/2,p_depth+1,max_depth,max_alloc);
- int right = _create_bvh(p_bvh,p_bb,p_from+p_size/2,p_size-p_size/2,p_depth+1,max_depth,max_alloc);
-
- int index=max_alloc++;
- BVH *_new = &p_bvh[index];
- _new->aabb=aabb;
- _new->center=aabb.pos+aabb.size*0.5;
- _new->face_index=-1;
- _new->left=left;
- _new->right=right;
-
- return index;
-
-}
-
-
-void TriangleMesh::create(const DVector<Vector3>& p_faces) {
-
- valid=false;
-
- int fc=p_faces.size();
- ERR_FAIL_COND(!fc || ((fc%3) != 0));
- fc/=3;
- triangles.resize(fc);
-
- bvh.resize(fc*3); //will never be larger than this (todo make better)
- DVector<BVH>::Write bw = bvh.write();
-
- {
-
- //create faces and indices and base bvh
- //except for the Set for repeated triangles, everything
- //goes in-place.
-
- DVector<Vector3>::Read r = p_faces.read();
- DVector<Triangle>::Write w = triangles.write();
- Map<Vector3,int> db;
-
- for(int i=0;i<fc;i++) {
-
- Triangle&f=w[i];
- const Vector3 *v=&r[i*3];
-
- for(int j=0;j<3;j++) {
-
- int vidx=-1;
- Vector3 vs=v[j].snapped(0.0001);
- Map<Vector3,int>::Element *E=db.find(vs);
- if (E) {
- vidx=E->get();
- } else {
- vidx=db.size();
- db[vs]=vidx;
- }
-
- f.indices[j]=vidx;
- if (j==0)
- bw[i].aabb.pos=vs;
- else
- bw[i].aabb.expand_to(vs);
- }
-
- f.normal=Face3(r[i*3+0],r[i*3+1],r[i*3+2]).get_plane().get_normal();
-
- bw[i].left=-1;
- bw[i].right=-1;
- bw[i].face_index=i;
- bw[i].center=bw[i].aabb.pos+bw[i].aabb.size*0.5;
- }
-
- vertices.resize(db.size());
- DVector<Vector3>::Write vw = vertices.write();
- for (Map<Vector3,int>::Element *E=db.front();E;E=E->next()) {
- vw[E->get()]=E->key();
- }
-
- }
-
- DVector<BVH*> bwptrs;
- bwptrs.resize(fc);
- DVector<BVH*>::Write bwp = bwptrs.write();
- for(int i=0;i<fc;i++) {
-
- bwp[i]=&bw[i];
- }
-
- max_depth=0;
- int max_alloc=fc;
- int max=_create_bvh(bw.ptr(),bwp.ptr(),0,fc,1,max_depth,max_alloc);
-
- bw=DVector<BVH>::Write(); //clearup
- bvh.resize(max_alloc); //resize back
-
- valid=true;
-
-}
-
-
-Vector3 TriangleMesh::get_area_normal(const AABB& p_aabb) const {
-
- uint32_t* stack = (uint32_t*)alloca(sizeof(int)*max_depth);
-
- enum {
- TEST_AABB_BIT=0,
- VISIT_LEFT_BIT=1,
- VISIT_RIGHT_BIT=2,
- VISIT_DONE_BIT=3,
- VISITED_BIT_SHIFT=29,
- NODE_IDX_MASK=(1<<VISITED_BIT_SHIFT)-1,
- VISITED_BIT_MASK=~NODE_IDX_MASK,
-
-
- };
-
- int n_count=0;
- Vector3 n;
-
- //for(int i=0;i<max_depth;i++)
- // stack[i]=0;
-
- int level=0;
-
- DVector<Triangle>::Read trianglesr = triangles.read();
- DVector<Vector3>::Read verticesr=vertices.read();
- DVector<BVH>::Read bvhr=bvh.read();
-
- const Triangle *triangleptr=trianglesr.ptr();
- const Vector3 *vertexptr=verticesr.ptr();
- int pos=bvh.size()-1;
- const BVH *bvhptr = bvhr.ptr();
-
- stack[0]=pos;
- while(true) {
-
- uint32_t node = stack[level]&NODE_IDX_MASK;
- const BVH &b = bvhptr[ node ];
- bool done=false;
-
- switch(stack[level]>>VISITED_BIT_SHIFT) {
- case TEST_AABB_BIT: {
-
-
- bool valid = b.aabb.intersects(p_aabb);
- if (!valid) {
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
-
- } else {
-
- if (b.face_index>=0) {
-
- const Triangle &s=triangleptr[ b.face_index ];
- n+=s.normal;
- n_count++;
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
-
- } else {
-
- stack[level]=(VISIT_LEFT_BIT<<VISITED_BIT_SHIFT)|node;
- }
- }
-
- } continue;
- case VISIT_LEFT_BIT: {
-
- stack[level]=(VISIT_RIGHT_BIT<<VISITED_BIT_SHIFT)|node;
- stack[level+1]=b.left|TEST_AABB_BIT;
- level++;
-
- } continue;
- case VISIT_RIGHT_BIT: {
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
- stack[level+1]=b.right|TEST_AABB_BIT;
- level++;
- } continue;
- case VISIT_DONE_BIT: {
-
- if (level==0) {
- done=true;
- break;
- } else
- level--;
-
- } continue;
- }
-
-
- if (done)
- break;
- }
-
-
- if (n_count>0)
- n/=n_count;
-
- return n;
-
-}
-
-
-bool TriangleMesh::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const {
-
-
- uint32_t* stack = (uint32_t*)alloca(sizeof(int)*max_depth);
-
- enum {
- TEST_AABB_BIT=0,
- VISIT_LEFT_BIT=1,
- VISIT_RIGHT_BIT=2,
- VISIT_DONE_BIT=3,
- VISITED_BIT_SHIFT=29,
- NODE_IDX_MASK=(1<<VISITED_BIT_SHIFT)-1,
- VISITED_BIT_MASK=~NODE_IDX_MASK,
-
-
- };
-
- Vector3 n = (p_end-p_begin).normalized();
- real_t d=1e10;
- bool inters=false;
-
- //for(int i=0;i<max_depth;i++)
- // stack[i]=0;
-
- int level=0;
- //AABB ray_aabb;
- //ray_aabb.pos=p_begin;
- //ray_aabb.expand_to(p_end);
-
-
- DVector<Triangle>::Read trianglesr = triangles.read();
- DVector<Vector3>::Read verticesr=vertices.read();
- DVector<BVH>::Read bvhr=bvh.read();
-
- const Triangle *triangleptr=trianglesr.ptr();
- const Vector3 *vertexptr=verticesr.ptr();
- int pos=bvh.size()-1;
- const BVH *bvhptr = bvhr.ptr();
-
- stack[0]=pos;
- while(true) {
-
- uint32_t node = stack[level]&NODE_IDX_MASK;
- const BVH &b = bvhptr[ node ];
- bool done=false;
-
- switch(stack[level]>>VISITED_BIT_SHIFT) {
- case TEST_AABB_BIT: {
-
-
- bool valid = b.aabb.intersects_segment(p_begin,p_end);
-// bool valid = b.aabb.intersects(ray_aabb);
-
- if (!valid) {
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
-
- } else {
-
- if (b.face_index>=0) {
-
- const Triangle &s=triangleptr[ b.face_index ];
- Face3 f3(vertexptr[ s.indices[0] ],vertexptr[ s.indices[1] ],vertexptr[ s.indices[2] ]);
-
-
- Vector3 res;
-
- if (f3.intersects_segment(p_begin,p_end,&res)) {
-
-
- float nd = n.dot(res);
- if (nd<d) {
-
- d=nd;
- r_point=res;
- r_normal=f3.get_plane().get_normal();
- inters=true;
- }
-
- }
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
-
- } else {
-
- stack[level]=(VISIT_LEFT_BIT<<VISITED_BIT_SHIFT)|node;
- }
- }
-
- } continue;
- case VISIT_LEFT_BIT: {
-
- stack[level]=(VISIT_RIGHT_BIT<<VISITED_BIT_SHIFT)|node;
- stack[level+1]=b.left|TEST_AABB_BIT;
- level++;
-
- } continue;
- case VISIT_RIGHT_BIT: {
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
- stack[level+1]=b.right|TEST_AABB_BIT;
- level++;
- } continue;
- case VISIT_DONE_BIT: {
-
- if (level==0) {
- done=true;
- break;
- } else
- level--;
-
- } continue;
- }
-
-
- if (done)
- break;
- }
-
-
- if (inters) {
-
- if (n.dot(r_normal)>0)
- r_normal=-r_normal;
- }
-
- return inters;
-}
-
-
-bool TriangleMesh::intersect_ray(const Vector3& p_begin,const Vector3& p_dir,Vector3 &r_point, Vector3 &r_normal) const {
-
-
- uint32_t* stack = (uint32_t*)alloca(sizeof(int)*max_depth);
-
- enum {
- TEST_AABB_BIT=0,
- VISIT_LEFT_BIT=1,
- VISIT_RIGHT_BIT=2,
- VISIT_DONE_BIT=3,
- VISITED_BIT_SHIFT=29,
- NODE_IDX_MASK=(1<<VISITED_BIT_SHIFT)-1,
- VISITED_BIT_MASK=~NODE_IDX_MASK,
-
-
- };
-
- Vector3 n = p_dir;
- real_t d=1e20;
- bool inters=false;
-
- //for(int i=0;i<max_depth;i++)
- // stack[i]=0;
-
- int level=0;
-
- DVector<Triangle>::Read trianglesr = triangles.read();
- DVector<Vector3>::Read verticesr=vertices.read();
- DVector<BVH>::Read bvhr=bvh.read();
-
- const Triangle *triangleptr=trianglesr.ptr();
- const Vector3 *vertexptr=verticesr.ptr();
- int pos=bvh.size()-1;
- const BVH *bvhptr = bvhr.ptr();
-
- stack[0]=pos;
- while(true) {
-
- uint32_t node = stack[level]&NODE_IDX_MASK;
- const BVH &b = bvhptr[ node ];
- bool done=false;
-
- switch(stack[level]>>VISITED_BIT_SHIFT) {
- case TEST_AABB_BIT: {
-
-
- bool valid = b.aabb.intersects_ray(p_begin,p_dir);
- if (!valid) {
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
-
- } else {
-
- if (b.face_index>=0) {
-
- const Triangle &s=triangleptr[ b.face_index ];
- Face3 f3(vertexptr[ s.indices[0] ],vertexptr[ s.indices[1] ],vertexptr[ s.indices[2] ]);
-
-
- Vector3 res;
-
- if (f3.intersects_ray(p_begin,p_dir,&res)) {
-
-
- float nd = n.dot(res);
- if (nd<d) {
-
- d=nd;
- r_point=res;
- r_normal=f3.get_plane().get_normal();
- inters=true;
- }
-
- }
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
-
- } else {
-
- stack[level]=(VISIT_LEFT_BIT<<VISITED_BIT_SHIFT)|node;
- }
- }
-
- } continue;
- case VISIT_LEFT_BIT: {
-
- stack[level]=(VISIT_RIGHT_BIT<<VISITED_BIT_SHIFT)|node;
- stack[level+1]=b.left|TEST_AABB_BIT;
- level++;
-
- } continue;
- case VISIT_RIGHT_BIT: {
-
- stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
- stack[level+1]=b.right|TEST_AABB_BIT;
- level++;
- } continue;
- case VISIT_DONE_BIT: {
-
- if (level==0) {
- done=true;
- break;
- } else
- level--;
-
- } continue;
- }
-
-
- if (done)
- break;
- }
-
-
- if (inters) {
-
- if (n.dot(r_normal)>0)
- r_normal=-r_normal;
- }
-
- return inters;
-}
-
-bool TriangleMesh::is_valid() const {
-
- return valid;
-}
-
-DVector<Face3> TriangleMesh::get_faces() const {
-
- if (!valid)
- return DVector<Face3>();
-
- DVector<Face3> faces;
- int ts = triangles.size();
- faces.resize(triangles.size());
-
- DVector<Face3>::Write w=faces.write();
- DVector<Triangle>::Read r = triangles.read();
- DVector<Vector3>::Read rv = vertices.read();
-
- for(int i=0;i<ts;i++) {
- for(int j=0;j<3;j++) {
- w[i].vertex[j]=rv[r[i].indices[j]];
- }
- }
-
- w = DVector<Face3>::Write();
- return faces;
-}
-
-TriangleMesh::TriangleMesh() {
-
- valid=false;
- max_depth=0;
-}
+#include "triangle_mesh.h"
+#include "sort.h"
+
+
+
+int TriangleMesh::_create_bvh(BVH*p_bvh,BVH** p_bb,int p_from,int p_size,int p_depth,int&max_depth,int&max_alloc) {
+
+
+ if (p_depth>max_depth) {
+ max_depth=p_depth;
+ }
+
+ if (p_size==1) {
+
+
+ return p_bb[p_from]-p_bvh;
+ } else if (p_size==0) {
+
+ return -1;
+ }
+
+
+ AABB aabb;
+ aabb=p_bb[p_from]->aabb;
+ for(int i=1;i<p_size;i++) {
+
+ aabb.merge_with(p_bb[p_from+i]->aabb);
+ }
+
+ int li=aabb.get_longest_axis_index();
+
+ switch(li) {
+
+ case Vector3::AXIS_X: {
+ SortArray<BVH*,BVHCmpX> sort_x;
+ sort_x.nth_element(0,p_size,p_size/2,&p_bb[p_from]);
+ //sort_x.sort(&p_bb[p_from],p_size);
+ } break;
+ case Vector3::AXIS_Y: {
+ SortArray<BVH*,BVHCmpY> sort_y;
+ sort_y.nth_element(0,p_size,p_size/2,&p_bb[p_from]);
+ //sort_y.sort(&p_bb[p_from],p_size);
+ } break;
+ case Vector3::AXIS_Z: {
+ SortArray<BVH*,BVHCmpZ> sort_z;
+ sort_z.nth_element(0,p_size,p_size/2,&p_bb[p_from]);
+ //sort_z.sort(&p_bb[p_from],p_size);
+
+ } break;
+ }
+
+
+ int left = _create_bvh(p_bvh,p_bb,p_from,p_size/2,p_depth+1,max_depth,max_alloc);
+ int right = _create_bvh(p_bvh,p_bb,p_from+p_size/2,p_size-p_size/2,p_depth+1,max_depth,max_alloc);
+
+ int index=max_alloc++;
+ BVH *_new = &p_bvh[index];
+ _new->aabb=aabb;
+ _new->center=aabb.pos+aabb.size*0.5;
+ _new->face_index=-1;
+ _new->left=left;
+ _new->right=right;
+
+ return index;
+
+}
+
+
+void TriangleMesh::create(const DVector<Vector3>& p_faces) {
+
+ valid=false;
+
+ int fc=p_faces.size();
+ ERR_FAIL_COND(!fc || ((fc%3) != 0));
+ fc/=3;
+ triangles.resize(fc);
+
+ bvh.resize(fc*3); //will never be larger than this (todo make better)
+ DVector<BVH>::Write bw = bvh.write();
+
+ {
+
+ //create faces and indices and base bvh
+ //except for the Set for repeated triangles, everything
+ //goes in-place.
+
+ DVector<Vector3>::Read r = p_faces.read();
+ DVector<Triangle>::Write w = triangles.write();
+ Map<Vector3,int> db;
+
+ for(int i=0;i<fc;i++) {
+
+ Triangle&f=w[i];
+ const Vector3 *v=&r[i*3];
+
+ for(int j=0;j<3;j++) {
+
+ int vidx=-1;
+ Vector3 vs=v[j].snapped(0.0001);
+ Map<Vector3,int>::Element *E=db.find(vs);
+ if (E) {
+ vidx=E->get();
+ } else {
+ vidx=db.size();
+ db[vs]=vidx;
+ }
+
+ f.indices[j]=vidx;
+ if (j==0)
+ bw[i].aabb.pos=vs;
+ else
+ bw[i].aabb.expand_to(vs);
+ }
+
+ f.normal=Face3(r[i*3+0],r[i*3+1],r[i*3+2]).get_plane().get_normal();
+
+ bw[i].left=-1;
+ bw[i].right=-1;
+ bw[i].face_index=i;
+ bw[i].center=bw[i].aabb.pos+bw[i].aabb.size*0.5;
+ }
+
+ vertices.resize(db.size());
+ DVector<Vector3>::Write vw = vertices.write();
+ for (Map<Vector3,int>::Element *E=db.front();E;E=E->next()) {
+ vw[E->get()]=E->key();
+ }
+
+ }
+
+ DVector<BVH*> bwptrs;
+ bwptrs.resize(fc);
+ DVector<BVH*>::Write bwp = bwptrs.write();
+ for(int i=0;i<fc;i++) {
+
+ bwp[i]=&bw[i];
+ }
+
+ max_depth=0;
+ int max_alloc=fc;
+ int max=_create_bvh(bw.ptr(),bwp.ptr(),0,fc,1,max_depth,max_alloc);
+
+ bw=DVector<BVH>::Write(); //clearup
+ bvh.resize(max_alloc); //resize back
+
+ valid=true;
+
+}
+
+
+Vector3 TriangleMesh::get_area_normal(const AABB& p_aabb) const {
+
+ uint32_t* stack = (uint32_t*)alloca(sizeof(int)*max_depth);
+
+ enum {
+ TEST_AABB_BIT=0,
+ VISIT_LEFT_BIT=1,
+ VISIT_RIGHT_BIT=2,
+ VISIT_DONE_BIT=3,
+ VISITED_BIT_SHIFT=29,
+ NODE_IDX_MASK=(1<<VISITED_BIT_SHIFT)-1,
+ VISITED_BIT_MASK=~NODE_IDX_MASK,
+
+
+ };
+
+ int n_count=0;
+ Vector3 n;
+
+ //for(int i=0;i<max_depth;i++)
+ // stack[i]=0;
+
+ int level=0;
+
+ DVector<Triangle>::Read trianglesr = triangles.read();
+ DVector<Vector3>::Read verticesr=vertices.read();
+ DVector<BVH>::Read bvhr=bvh.read();
+
+ const Triangle *triangleptr=trianglesr.ptr();
+ const Vector3 *vertexptr=verticesr.ptr();
+ int pos=bvh.size()-1;
+ const BVH *bvhptr = bvhr.ptr();
+
+ stack[0]=pos;
+ while(true) {
+
+ uint32_t node = stack[level]&NODE_IDX_MASK;
+ const BVH &b = bvhptr[ node ];
+ bool done=false;
+
+ switch(stack[level]>>VISITED_BIT_SHIFT) {
+ case TEST_AABB_BIT: {
+
+
+ bool valid = b.aabb.intersects(p_aabb);
+ if (!valid) {
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+
+ } else {
+
+ if (b.face_index>=0) {
+
+ const Triangle &s=triangleptr[ b.face_index ];
+ n+=s.normal;
+ n_count++;
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+
+ } else {
+
+ stack[level]=(VISIT_LEFT_BIT<<VISITED_BIT_SHIFT)|node;
+ }
+ }
+
+ } continue;
+ case VISIT_LEFT_BIT: {
+
+ stack[level]=(VISIT_RIGHT_BIT<<VISITED_BIT_SHIFT)|node;
+ stack[level+1]=b.left|TEST_AABB_BIT;
+ level++;
+
+ } continue;
+ case VISIT_RIGHT_BIT: {
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+ stack[level+1]=b.right|TEST_AABB_BIT;
+ level++;
+ } continue;
+ case VISIT_DONE_BIT: {
+
+ if (level==0) {
+ done=true;
+ break;
+ } else
+ level--;
+
+ } continue;
+ }
+
+
+ if (done)
+ break;
+ }
+
+
+ if (n_count>0)
+ n/=n_count;
+
+ return n;
+
+}
+
+
+bool TriangleMesh::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const {
+
+
+ uint32_t* stack = (uint32_t*)alloca(sizeof(int)*max_depth);
+
+ enum {
+ TEST_AABB_BIT=0,
+ VISIT_LEFT_BIT=1,
+ VISIT_RIGHT_BIT=2,
+ VISIT_DONE_BIT=3,
+ VISITED_BIT_SHIFT=29,
+ NODE_IDX_MASK=(1<<VISITED_BIT_SHIFT)-1,
+ VISITED_BIT_MASK=~NODE_IDX_MASK,
+
+
+ };
+
+ Vector3 n = (p_end-p_begin).normalized();
+ real_t d=1e10;
+ bool inters=false;
+
+ //for(int i=0;i<max_depth;i++)
+ // stack[i]=0;
+
+ int level=0;
+ //AABB ray_aabb;
+ //ray_aabb.pos=p_begin;
+ //ray_aabb.expand_to(p_end);
+
+
+ DVector<Triangle>::Read trianglesr = triangles.read();
+ DVector<Vector3>::Read verticesr=vertices.read();
+ DVector<BVH>::Read bvhr=bvh.read();
+
+ const Triangle *triangleptr=trianglesr.ptr();
+ const Vector3 *vertexptr=verticesr.ptr();
+ int pos=bvh.size()-1;
+ const BVH *bvhptr = bvhr.ptr();
+
+ stack[0]=pos;
+ while(true) {
+
+ uint32_t node = stack[level]&NODE_IDX_MASK;
+ const BVH &b = bvhptr[ node ];
+ bool done=false;
+
+ switch(stack[level]>>VISITED_BIT_SHIFT) {
+ case TEST_AABB_BIT: {
+
+
+ bool valid = b.aabb.intersects_segment(p_begin,p_end);
+// bool valid = b.aabb.intersects(ray_aabb);
+
+ if (!valid) {
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+
+ } else {
+
+ if (b.face_index>=0) {
+
+ const Triangle &s=triangleptr[ b.face_index ];
+ Face3 f3(vertexptr[ s.indices[0] ],vertexptr[ s.indices[1] ],vertexptr[ s.indices[2] ]);
+
+
+ Vector3 res;
+
+ if (f3.intersects_segment(p_begin,p_end,&res)) {
+
+
+ float nd = n.dot(res);
+ if (nd<d) {
+
+ d=nd;
+ r_point=res;
+ r_normal=f3.get_plane().get_normal();
+ inters=true;
+ }
+
+ }
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+
+ } else {
+
+ stack[level]=(VISIT_LEFT_BIT<<VISITED_BIT_SHIFT)|node;
+ }
+ }
+
+ } continue;
+ case VISIT_LEFT_BIT: {
+
+ stack[level]=(VISIT_RIGHT_BIT<<VISITED_BIT_SHIFT)|node;
+ stack[level+1]=b.left|TEST_AABB_BIT;
+ level++;
+
+ } continue;
+ case VISIT_RIGHT_BIT: {
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+ stack[level+1]=b.right|TEST_AABB_BIT;
+ level++;
+ } continue;
+ case VISIT_DONE_BIT: {
+
+ if (level==0) {
+ done=true;
+ break;
+ } else
+ level--;
+
+ } continue;
+ }
+
+
+ if (done)
+ break;
+ }
+
+
+ if (inters) {
+
+ if (n.dot(r_normal)>0)
+ r_normal=-r_normal;
+ }
+
+ return inters;
+}
+
+
+bool TriangleMesh::intersect_ray(const Vector3& p_begin,const Vector3& p_dir,Vector3 &r_point, Vector3 &r_normal) const {
+
+
+ uint32_t* stack = (uint32_t*)alloca(sizeof(int)*max_depth);
+
+ enum {
+ TEST_AABB_BIT=0,
+ VISIT_LEFT_BIT=1,
+ VISIT_RIGHT_BIT=2,
+ VISIT_DONE_BIT=3,
+ VISITED_BIT_SHIFT=29,
+ NODE_IDX_MASK=(1<<VISITED_BIT_SHIFT)-1,
+ VISITED_BIT_MASK=~NODE_IDX_MASK,
+
+
+ };
+
+ Vector3 n = p_dir;
+ real_t d=1e20;
+ bool inters=false;
+
+ //for(int i=0;i<max_depth;i++)
+ // stack[i]=0;
+
+ int level=0;
+
+ DVector<Triangle>::Read trianglesr = triangles.read();
+ DVector<Vector3>::Read verticesr=vertices.read();
+ DVector<BVH>::Read bvhr=bvh.read();
+
+ const Triangle *triangleptr=trianglesr.ptr();
+ const Vector3 *vertexptr=verticesr.ptr();
+ int pos=bvh.size()-1;
+ const BVH *bvhptr = bvhr.ptr();
+
+ stack[0]=pos;
+ while(true) {
+
+ uint32_t node = stack[level]&NODE_IDX_MASK;
+ const BVH &b = bvhptr[ node ];
+ bool done=false;
+
+ switch(stack[level]>>VISITED_BIT_SHIFT) {
+ case TEST_AABB_BIT: {
+
+
+ bool valid = b.aabb.intersects_ray(p_begin,p_dir);
+ if (!valid) {
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+
+ } else {
+
+ if (b.face_index>=0) {
+
+ const Triangle &s=triangleptr[ b.face_index ];
+ Face3 f3(vertexptr[ s.indices[0] ],vertexptr[ s.indices[1] ],vertexptr[ s.indices[2] ]);
+
+
+ Vector3 res;
+
+ if (f3.intersects_ray(p_begin,p_dir,&res)) {
+
+
+ float nd = n.dot(res);
+ if (nd<d) {
+
+ d=nd;
+ r_point=res;
+ r_normal=f3.get_plane().get_normal();
+ inters=true;
+ }
+
+ }
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+
+ } else {
+
+ stack[level]=(VISIT_LEFT_BIT<<VISITED_BIT_SHIFT)|node;
+ }
+ }
+
+ } continue;
+ case VISIT_LEFT_BIT: {
+
+ stack[level]=(VISIT_RIGHT_BIT<<VISITED_BIT_SHIFT)|node;
+ stack[level+1]=b.left|TEST_AABB_BIT;
+ level++;
+
+ } continue;
+ case VISIT_RIGHT_BIT: {
+
+ stack[level]=(VISIT_DONE_BIT<<VISITED_BIT_SHIFT)|node;
+ stack[level+1]=b.right|TEST_AABB_BIT;
+ level++;
+ } continue;
+ case VISIT_DONE_BIT: {
+
+ if (level==0) {
+ done=true;
+ break;
+ } else
+ level--;
+
+ } continue;
+ }
+
+
+ if (done)
+ break;
+ }
+
+
+ if (inters) {
+
+ if (n.dot(r_normal)>0)
+ r_normal=-r_normal;
+ }
+
+ return inters;
+}
+
+bool TriangleMesh::is_valid() const {
+
+ return valid;
+}
+
+DVector<Face3> TriangleMesh::get_faces() const {
+
+ if (!valid)
+ return DVector<Face3>();
+
+ DVector<Face3> faces;
+ int ts = triangles.size();
+ faces.resize(triangles.size());
+
+ DVector<Face3>::Write w=faces.write();
+ DVector<Triangle>::Read r = triangles.read();
+ DVector<Vector3>::Read rv = vertices.read();
+
+ for(int i=0;i<ts;i++) {
+ for(int j=0;j<3;j++) {
+ w[i].vertex[j]=rv[r[i].indices[j]];
+ }
+ }
+
+ w = DVector<Face3>::Write();
+ return faces;
+}
+
+TriangleMesh::TriangleMesh() {
+
+ valid=false;
+ max_depth=0;
+}
diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h
index ab0cb713b1..87d8ce8e6c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,74 +26,74 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TRIANGLE_MESH_H
-#define TRIANGLE_MESH_H
-
-#include "reference.h"
-#include "face3.h"
-class TriangleMesh : public Reference {
-
- OBJ_TYPE( TriangleMesh, Reference);
-
- struct Triangle {
-
- Vector3 normal;
- int indices[3];
- };
-
- DVector<Triangle> triangles;
- DVector<Vector3> vertices;
-
- struct BVH {
-
- AABB aabb;
- Vector3 center; //used for sorting
- int left;
- int right;
-
- int face_index;
- };
-
- struct BVHCmpX {
-
- bool operator()(const BVH* p_left, const BVH* p_right) const {
-
- return p_left->center.x < p_right->center.x;
- }
- };
-
- struct BVHCmpY {
-
- bool operator()(const BVH* p_left, const BVH* p_right) const {
-
- return p_left->center.y < p_right->center.y;
- }
- };
- struct BVHCmpZ {
-
- bool operator()(const BVH* p_left, const BVH* p_right) const {
-
- return p_left->center.z < p_right->center.z;
- }
- };
-
- int _create_bvh(BVH*p_bvh,BVH** p_bb,int p_from,int p_size,int p_depth,int&max_depth,int&max_alloc);
-
- DVector<BVH> bvh;
- int max_depth;
- bool valid;
-
-public:
-
- bool is_valid() const;
- bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const;
- bool intersect_ray(const Vector3& p_begin,const Vector3& p_dir,Vector3 &r_point, Vector3 &r_normal) const;
- Vector3 get_area_normal(const AABB& p_aabb) const;
- DVector<Face3> get_faces() const;
-
-
- void create(const DVector<Vector3>& p_faces);
- TriangleMesh();
-};
-
-#endif // TRIANGLE_MESH_H
+#ifndef TRIANGLE_MESH_H
+#define TRIANGLE_MESH_H
+
+#include "reference.h"
+#include "face3.h"
+class TriangleMesh : public Reference {
+
+ OBJ_TYPE( TriangleMesh, Reference);
+
+ struct Triangle {
+
+ Vector3 normal;
+ int indices[3];
+ };
+
+ DVector<Triangle> triangles;
+ DVector<Vector3> vertices;
+
+ struct BVH {
+
+ AABB aabb;
+ Vector3 center; //used for sorting
+ int left;
+ int right;
+
+ int face_index;
+ };
+
+ struct BVHCmpX {
+
+ bool operator()(const BVH* p_left, const BVH* p_right) const {
+
+ return p_left->center.x < p_right->center.x;
+ }
+ };
+
+ struct BVHCmpY {
+
+ bool operator()(const BVH* p_left, const BVH* p_right) const {
+
+ return p_left->center.y < p_right->center.y;
+ }
+ };
+ struct BVHCmpZ {
+
+ bool operator()(const BVH* p_left, const BVH* p_right) const {
+
+ return p_left->center.z < p_right->center.z;
+ }
+ };
+
+ int _create_bvh(BVH*p_bvh,BVH** p_bb,int p_from,int p_size,int p_depth,int&max_depth,int&max_alloc);
+
+ DVector<BVH> bvh;
+ int max_depth;
+ bool valid;
+
+public:
+
+ bool is_valid() const;
+ bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const;
+ bool intersect_ray(const Vector3& p_begin,const Vector3& p_dir,Vector3 &r_point, Vector3 &r_normal) const;
+ Vector3 get_area_normal(const AABB& p_aabb) const;
+ DVector<Face3> get_faces() const;
+
+
+ void create(const DVector<Vector3>& p_faces);
+ TriangleMesh();
+};
+
+#endif // TRIANGLE_MESH_H
diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp
index 4a870def4b..b13e13c47d 100644
--- a/core/math/triangulate.cpp
+++ b/core/math/triangulate.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/triangulate.h b/core/math/triangulate.h
index b20b37bd44..927b7efb8d 100644
--- a/core/math/triangulate.h
+++ b/core/math/triangulate.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/math/triangulator.cpp b/core/math/triangulator.cpp
new file mode 100644
index 0000000000..8f82d76823
--- /dev/null
+++ b/core/math/triangulator.cpp
@@ -0,0 +1,1550 @@
+//Copyright (C) 2011 by Ivan Fratric
+//
+//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 <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "triangulator.h"
+
+
+#define TRIANGULATOR_VERTEXTYPE_REGULAR 0
+#define TRIANGULATOR_VERTEXTYPE_START 1
+#define TRIANGULATOR_VERTEXTYPE_END 2
+#define TRIANGULATOR_VERTEXTYPE_SPLIT 3
+#define TRIANGULATOR_VERTEXTYPE_MERGE 4
+
+TriangulatorPoly::TriangulatorPoly() {
+ hole = false;
+ numpoints = 0;
+ points = NULL;
+}
+
+TriangulatorPoly::~TriangulatorPoly() {
+ if(points) delete [] points;
+}
+
+void TriangulatorPoly::Clear() {
+ if(points) delete [] points;
+ hole = false;
+ numpoints = 0;
+ points = NULL;
+}
+
+void TriangulatorPoly::Init(long numpoints) {
+ Clear();
+ this->numpoints = numpoints;
+ points = new Vector2[numpoints];
+}
+
+void TriangulatorPoly::Triangle(Vector2 &p1, Vector2 &p2, Vector2 &p3) {
+ Init(3);
+ points[0] = p1;
+ points[1] = p2;
+ points[2] = p3;
+}
+
+TriangulatorPoly::TriangulatorPoly(const TriangulatorPoly &src) {
+ hole = src.hole;
+ numpoints = src.numpoints;
+ points = new Vector2[numpoints];
+ memcpy(points, src.points, numpoints*sizeof(Vector2));
+}
+
+TriangulatorPoly& TriangulatorPoly::operator=(const TriangulatorPoly &src) {
+ Clear();
+ hole = src.hole;
+ numpoints = src.numpoints;
+ points = new Vector2[numpoints];
+ memcpy(points, src.points, numpoints*sizeof(Vector2));
+ return *this;
+}
+
+int TriangulatorPoly::GetOrientation() {
+ long i1,i2;
+ real_t area = 0;
+ for(i1=0; i1<numpoints; i1++) {
+ i2 = i1+1;
+ if(i2 == numpoints) i2 = 0;
+ area += points[i1].x * points[i2].y - points[i1].y * points[i2].x;
+ }
+ if(area>0) return TRIANGULATOR_CCW;
+ if(area<0) return TRIANGULATOR_CW;
+ return 0;
+}
+
+void TriangulatorPoly::SetOrientation(int orientation) {
+ int polyorientation = GetOrientation();
+ if(polyorientation&&(polyorientation!=orientation)) {
+ Invert();
+ }
+}
+
+void TriangulatorPoly::Invert() {
+ long i;
+ Vector2 *invpoints;
+
+ invpoints = new Vector2[numpoints];
+ for(i=0;i<numpoints;i++) {
+ invpoints[i] = points[numpoints-i-1];
+ }
+
+ delete [] points;
+ points = invpoints;
+}
+
+Vector2 TriangulatorPartition::Normalize(const Vector2 &p) {
+ Vector2 r;
+ real_t n = sqrt(p.x*p.x + p.y*p.y);
+ if(n!=0) {
+ r = p/n;
+ } else {
+ r.x = 0;
+ r.y = 0;
+ }
+ return r;
+}
+
+real_t TriangulatorPartition::Distance(const Vector2 &p1, const Vector2 &p2) {
+ real_t dx,dy;
+ dx = p2.x - p1.x;
+ dy = p2.y - p1.y;
+ return(sqrt(dx*dx + dy*dy));
+}
+
+//checks if two lines intersect
+int TriangulatorPartition::Intersects(Vector2 &p11, Vector2 &p12, Vector2 &p21, Vector2 &p22) {
+ if((p11.x == p21.x)&&(p11.y == p21.y)) return 0;
+ if((p11.x == p22.x)&&(p11.y == p22.y)) return 0;
+ if((p12.x == p21.x)&&(p12.y == p21.y)) return 0;
+ if((p12.x == p22.x)&&(p12.y == p22.y)) return 0;
+
+ Vector2 v1ort,v2ort,v;
+ real_t dot11,dot12,dot21,dot22;
+
+ v1ort.x = p12.y-p11.y;
+ v1ort.y = p11.x-p12.x;
+
+ v2ort.x = p22.y-p21.y;
+ v2ort.y = p21.x-p22.x;
+
+ v = p21-p11;
+ dot21 = v.x*v1ort.x + v.y*v1ort.y;
+ v = p22-p11;
+ dot22 = v.x*v1ort.x + v.y*v1ort.y;
+
+ v = p11-p21;
+ dot11 = v.x*v2ort.x + v.y*v2ort.y;
+ v = p12-p21;
+ dot12 = v.x*v2ort.x + v.y*v2ort.y;
+
+ if(dot11*dot12>0) return 0;
+ if(dot21*dot22>0) return 0;
+
+ return 1;
+}
+
+//removes holes from inpolys by merging them with non-holes
+int TriangulatorPartition::RemoveHoles(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *outpolys) {
+ List<TriangulatorPoly> polys;
+ List<TriangulatorPoly>::Element *holeiter,*polyiter,*iter,*iter2;
+ long i,i2,holepointindex,polypointindex;
+ Vector2 holepoint,polypoint,bestpolypoint;
+ Vector2 linep1,linep2;
+ Vector2 v1,v2;
+ TriangulatorPoly newpoly;
+ bool hasholes;
+ bool pointvisible;
+ bool pointfound;
+
+ //check for trivial case (no holes)
+ hasholes = false;
+ for(iter = inpolys->front(); iter; iter=iter->next()) {
+ if(iter->get().IsHole()) {
+ hasholes = true;
+ break;
+ }
+ }
+ if(!hasholes) {
+ for(iter = inpolys->front(); iter; iter=iter->next()) {
+ outpolys->push_back(iter->get());
+ }
+ return 1;
+ }
+
+ polys = *inpolys;
+
+ while(1) {
+ //find the hole point with the largest x
+ hasholes = false;
+ for(iter = polys.front(); iter; iter=iter->next()) {
+ if(!iter->get().IsHole()) continue;
+
+ if(!hasholes) {
+ hasholes = true;
+ holeiter = iter;
+ holepointindex = 0;
+ }
+
+ for(i=0; i < iter->get().GetNumPoints(); i++) {
+ if(iter->get().GetPoint(i).x > holeiter->get().GetPoint(holepointindex).x) {
+ holeiter = iter;
+ holepointindex = i;
+ }
+ }
+ }
+ if(!hasholes) break;
+ holepoint = holeiter->get().GetPoint(holepointindex);
+
+ pointfound = false;
+ for(iter = polys.front(); iter; iter=iter->next()) {
+ if(iter->get().IsHole()) continue;
+ for(i=0; i < iter->get().GetNumPoints(); i++) {
+ if(iter->get().GetPoint(i).x <= holepoint.x) continue;
+ if(!InCone(iter->get().GetPoint((i+iter->get().GetNumPoints()-1)%(iter->get().GetNumPoints())),
+ iter->get().GetPoint(i),
+ iter->get().GetPoint((i+1)%(iter->get().GetNumPoints())),
+ holepoint))
+ continue;
+ polypoint = iter->get().GetPoint(i);
+ if(pointfound) {
+ v1 = Normalize(polypoint-holepoint);
+ v2 = Normalize(bestpolypoint-holepoint);
+ if(v2.x > v1.x) continue;
+ }
+ pointvisible = true;
+ for(iter2 = polys.front(); iter2; iter2=iter2->next()) {
+ if(iter2->get().IsHole()) continue;
+ for(i2=0; i2 < iter2->get().GetNumPoints(); i2++) {
+ linep1 = iter2->get().GetPoint(i2);
+ linep2 = iter2->get().GetPoint((i2+1)%(iter2->get().GetNumPoints()));
+ if(Intersects(holepoint,polypoint,linep1,linep2)) {
+ pointvisible = false;
+ break;
+ }
+ }
+ if(!pointvisible) break;
+ }
+ if(pointvisible) {
+ pointfound = true;
+ bestpolypoint = polypoint;
+ polyiter = iter;
+ polypointindex = i;
+ }
+ }
+ }
+
+ if(!pointfound) return 0;
+
+ newpoly.Init(holeiter->get().GetNumPoints() + polyiter->get().GetNumPoints() + 2);
+ i2 = 0;
+ for(i=0;i<=polypointindex;i++) {
+ newpoly[i2] = polyiter->get().GetPoint(i);
+ i2++;
+ }
+ for(i=0;i<=holeiter->get().GetNumPoints();i++) {
+ newpoly[i2] = holeiter->get().GetPoint((i+holepointindex)%holeiter->get().GetNumPoints());
+ i2++;
+ }
+ for(i=polypointindex;i<polyiter->get().GetNumPoints();i++) {
+ newpoly[i2] = polyiter->get().GetPoint(i);
+ i2++;
+ }
+
+ polys.erase(holeiter);
+ polys.erase(polyiter);
+ polys.push_back(newpoly);
+ }
+
+ for(iter = polys.front(); iter; iter=iter->next()) {
+ outpolys->push_back(iter->get());
+ }
+
+ return 1;
+}
+
+bool TriangulatorPartition::IsConvex(Vector2& p1, Vector2& p2, Vector2& p3) {
+ real_t tmp;
+ tmp = (p3.y-p1.y)*(p2.x-p1.x)-(p3.x-p1.x)*(p2.y-p1.y);
+ if(tmp>0) return 1;
+ else return 0;
+}
+
+bool TriangulatorPartition::IsReflex(Vector2& p1, Vector2& p2, Vector2& p3) {
+ real_t tmp;
+ tmp = (p3.y-p1.y)*(p2.x-p1.x)-(p3.x-p1.x)*(p2.y-p1.y);
+ if(tmp<0) return 1;
+ else return 0;
+}
+
+bool TriangulatorPartition::IsInside(Vector2& p1, Vector2& p2, Vector2& p3, Vector2 &p) {
+ if(IsConvex(p1,p,p2)) return false;
+ if(IsConvex(p2,p,p3)) return false;
+ if(IsConvex(p3,p,p1)) return false;
+ return true;
+}
+
+bool TriangulatorPartition::InCone(Vector2 &p1, Vector2 &p2, Vector2 &p3, Vector2 &p) {
+ bool convex;
+
+ convex = IsConvex(p1,p2,p3);
+
+ if(convex) {
+ if(!IsConvex(p1,p2,p)) return false;
+ if(!IsConvex(p2,p3,p)) return false;
+ return true;
+ } else {
+ if(IsConvex(p1,p2,p)) return true;
+ if(IsConvex(p2,p3,p)) return true;
+ return false;
+ }
+}
+
+bool TriangulatorPartition::InCone(PartitionVertex *v, Vector2 &p) {
+ Vector2 p1,p2,p3;
+
+ p1 = v->previous->p;
+ p2 = v->p;
+ p3 = v->next->p;
+
+ return InCone(p1,p2,p3,p);
+}
+
+void TriangulatorPartition::UpdateVertexReflexity(PartitionVertex *v) {
+ PartitionVertex *v1,*v3;
+ v1 = v->previous;
+ v3 = v->next;
+ v->isConvex = !IsReflex(v1->p,v->p,v3->p);
+}
+
+void TriangulatorPartition::UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, long numvertices) {
+ long i;
+ PartitionVertex *v1,*v3;
+ Vector2 vec1,vec3;
+
+ v1 = v->previous;
+ v3 = v->next;
+
+ v->isConvex = IsConvex(v1->p,v->p,v3->p);
+
+ vec1 = Normalize(v1->p - v->p);
+ vec3 = Normalize(v3->p - v->p);
+ v->angle = vec1.x*vec3.x + vec1.y*vec3.y;
+
+ if(v->isConvex) {
+ v->isEar = true;
+ for(i=0;i<numvertices;i++) {
+ if((vertices[i].p.x==v->p.x)&&(vertices[i].p.y==v->p.y)) continue;
+ if((vertices[i].p.x==v1->p.x)&&(vertices[i].p.y==v1->p.y)) continue;
+ if((vertices[i].p.x==v3->p.x)&&(vertices[i].p.y==v3->p.y)) continue;
+ if(IsInside(v1->p,v->p,v3->p,vertices[i].p)) {
+ v->isEar = false;
+ break;
+ }
+ }
+ } else {
+ v->isEar = false;
+ }
+}
+
+//triangulation by ear removal
+int TriangulatorPartition::Triangulate_EC(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles) {
+ long numvertices;
+ PartitionVertex *vertices;
+ PartitionVertex *ear;
+ TriangulatorPoly triangle;
+ long i,j;
+ bool earfound;
+
+ if(poly->GetNumPoints() < 3) return 0;
+ if(poly->GetNumPoints() == 3) {
+ triangles->push_back(*poly);
+ return 1;
+ }
+
+ numvertices = poly->GetNumPoints();
+
+ vertices = new PartitionVertex[numvertices];
+ for(i=0;i<numvertices;i++) {
+ vertices[i].isActive = true;
+ vertices[i].p = poly->GetPoint(i);
+ if(i==(numvertices-1)) vertices[i].next=&(vertices[0]);
+ else vertices[i].next=&(vertices[i+1]);
+ if(i==0) vertices[i].previous = &(vertices[numvertices-1]);
+ else vertices[i].previous = &(vertices[i-1]);
+ }
+ for(i=0;i<numvertices;i++) {
+ UpdateVertex(&vertices[i],vertices,numvertices);
+ }
+
+ for(i=0;i<numvertices-3;i++) {
+ earfound = false;
+ //find the most extruded ear
+ for(j=0;j<numvertices;j++) {
+ if(!vertices[j].isActive) continue;
+ if(!vertices[j].isEar) continue;
+ if(!earfound) {
+ earfound = true;
+ ear = &(vertices[j]);
+ } else {
+ if(vertices[j].angle > ear->angle) {
+ ear = &(vertices[j]);
+ }
+ }
+ }
+ if(!earfound) {
+ delete [] vertices;
+ return 0;
+ }
+
+ triangle.Triangle(ear->previous->p,ear->p,ear->next->p);
+ triangles->push_back(triangle);
+
+ ear->isActive = false;
+ ear->previous->next = ear->next;
+ ear->next->previous = ear->previous;
+
+ if(i==numvertices-4) break;
+
+ UpdateVertex(ear->previous,vertices,numvertices);
+ UpdateVertex(ear->next,vertices,numvertices);
+ }
+ for(i=0;i<numvertices;i++) {
+ if(vertices[i].isActive) {
+ triangle.Triangle(vertices[i].previous->p,vertices[i].p,vertices[i].next->p);
+ triangles->push_back(triangle);
+ break;
+ }
+ }
+
+ delete [] vertices;
+
+ return 1;
+}
+
+int TriangulatorPartition::Triangulate_EC(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles) {
+ List<TriangulatorPoly> outpolys;
+ List<TriangulatorPoly>::Element*iter;
+
+ if(!RemoveHoles(inpolys,&outpolys)) return 0;
+ for(iter=outpolys.front();iter;iter=iter->next()) {
+ if(!Triangulate_EC(&(iter->get()),triangles)) return 0;
+ }
+ return 1;
+}
+
+int TriangulatorPartition::ConvexPartition_HM(TriangulatorPoly *poly, List<TriangulatorPoly> *parts) {
+ List<TriangulatorPoly> triangles;
+ List<TriangulatorPoly>::Element *iter1,*iter2;
+ TriangulatorPoly *poly1,*poly2;
+ TriangulatorPoly newpoly;
+ Vector2 d1,d2,p1,p2,p3;
+ long i11,i12,i21,i22,i13,i23,j,k;
+ bool isdiagonal;
+ long numreflex;
+
+ //check if the poly is already convex
+ numreflex = 0;
+ for(i11=0;i11<poly->GetNumPoints();i11++) {
+ if(i11==0) i12 = poly->GetNumPoints()-1;
+ else i12=i11-1;
+ if(i11==(poly->GetNumPoints()-1)) i13=0;
+ else i13=i11+1;
+ if(IsReflex(poly->GetPoint(i12),poly->GetPoint(i11),poly->GetPoint(i13))) {
+ numreflex = 1;
+ break;
+ }
+ }
+ if(numreflex == 0) {
+ parts->push_back(*poly);
+ return 1;
+ }
+
+ if(!Triangulate_EC(poly,&triangles)) return 0;
+
+ for(iter1 = triangles.front(); iter1 ; iter1=iter1->next()) {
+ poly1 = &(iter1->get());
+ for(i11=0;i11<poly1->GetNumPoints();i11++) {
+ d1 = poly1->GetPoint(i11);
+ i12 = (i11+1)%(poly1->GetNumPoints());
+ d2 = poly1->GetPoint(i12);
+
+ isdiagonal = false;
+ for(iter2 = iter1; iter2 ; iter2=iter2->next()) {
+ if(iter1 == iter2) continue;
+ poly2 = &(iter2->get());
+
+ for(i21=0;i21<poly2->GetNumPoints();i21++) {
+ if((d2.x != poly2->GetPoint(i21).x)||(d2.y != poly2->GetPoint(i21).y)) continue;
+ i22 = (i21+1)%(poly2->GetNumPoints());
+ if((d1.x != poly2->GetPoint(i22).x)||(d1.y != poly2->GetPoint(i22).y)) continue;
+ isdiagonal = true;
+ break;
+ }
+ if(isdiagonal) break;
+ }
+
+ if(!isdiagonal) continue;
+
+ p2 = poly1->GetPoint(i11);
+ if(i11 == 0) i13 = poly1->GetNumPoints()-1;
+ else i13 = i11-1;
+ p1 = poly1->GetPoint(i13);
+ if(i22 == (poly2->GetNumPoints()-1)) i23 = 0;
+ else i23 = i22+1;
+ p3 = poly2->GetPoint(i23);
+
+ if(!IsConvex(p1,p2,p3)) continue;
+
+ p2 = poly1->GetPoint(i12);
+ if(i12 == (poly1->GetNumPoints()-1)) i13 = 0;
+ else i13 = i12+1;
+ p3 = poly1->GetPoint(i13);
+ if(i21 == 0) i23 = poly2->GetNumPoints()-1;
+ else i23 = i21-1;
+ p1 = poly2->GetPoint(i23);
+
+ if(!IsConvex(p1,p2,p3)) continue;
+
+ newpoly.Init(poly1->GetNumPoints()+poly2->GetNumPoints()-2);
+ k = 0;
+ for(j=i12;j!=i11;j=(j+1)%(poly1->GetNumPoints())) {
+ newpoly[k] = poly1->GetPoint(j);
+ k++;
+ }
+ for(j=i22;j!=i21;j=(j+1)%(poly2->GetNumPoints())) {
+ newpoly[k] = poly2->GetPoint(j);
+ k++;
+ }
+
+ triangles.erase(iter2);
+ iter1->get() = newpoly;
+ poly1 = &(iter1->get());
+ i11 = -1;
+
+ continue;
+ }
+ }
+
+ for(iter1 = triangles.front(); iter1 ; iter1=iter1->next()) {
+ parts->push_back(iter1->get());
+ }
+
+ return 1;
+}
+
+int TriangulatorPartition::ConvexPartition_HM(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *parts) {
+ List<TriangulatorPoly> outpolys;
+ List<TriangulatorPoly>::Element* iter;
+
+ if(!RemoveHoles(inpolys,&outpolys)) return 0;
+ for(iter=outpolys.front();iter;iter=iter->next()) {
+ if(!ConvexPartition_HM(&(iter->get()),parts)) return 0;
+ }
+ return 1;
+}
+
+//minimum-weight polygon triangulation by dynamic programming
+//O(n^3) time complexity
+//O(n^2) space complexity
+int TriangulatorPartition::Triangulate_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles) {
+ long i,j,k,gap,n;
+ DPState **dpstates;
+ Vector2 p1,p2,p3,p4;
+ long bestvertex;
+ real_t weight,minweight,d1,d2;
+ Diagonal diagonal,newdiagonal;
+ List<Diagonal> diagonals;
+ TriangulatorPoly triangle;
+ int ret = 1;
+
+ n = poly->GetNumPoints();
+ dpstates = new DPState *[n];
+ for(i=1;i<n;i++) {
+ dpstates[i] = new DPState[i];
+ }
+
+ //init states and visibility
+ for(i=0;i<(n-1);i++) {
+ p1 = poly->GetPoint(i);
+ for(j=i+1;j<n;j++) {
+ dpstates[j][i].visible = true;
+ dpstates[j][i].weight = 0;
+ dpstates[j][i].bestvertex = -1;
+ if(j!=(i+1)) {
+ p2 = poly->GetPoint(j);
+
+ //visibility check
+ if(i==0) p3 = poly->GetPoint(n-1);
+ else p3 = poly->GetPoint(i-1);
+ if(i==(n-1)) p4 = poly->GetPoint(0);
+ else p4 = poly->GetPoint(i+1);
+ if(!InCone(p3,p1,p4,p2)) {
+ dpstates[j][i].visible = false;
+ continue;
+ }
+
+ if(j==0) p3 = poly->GetPoint(n-1);
+ else p3 = poly->GetPoint(j-1);
+ if(j==(n-1)) p4 = poly->GetPoint(0);
+ else p4 = poly->GetPoint(j+1);
+ if(!InCone(p3,p2,p4,p1)) {
+ dpstates[j][i].visible = false;
+ continue;
+ }
+
+ for(k=0;k<n;k++) {
+ p3 = poly->GetPoint(k);
+ if(k==(n-1)) p4 = poly->GetPoint(0);
+ else p4 = poly->GetPoint(k+1);
+ if(Intersects(p1,p2,p3,p4)) {
+ dpstates[j][i].visible = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ dpstates[n-1][0].visible = true;
+ dpstates[n-1][0].weight = 0;
+ dpstates[n-1][0].bestvertex = -1;
+
+ for(gap = 2; gap<n; gap++) {
+ for(i=0; i<(n-gap); i++) {
+ j = i+gap;
+ if(!dpstates[j][i].visible) continue;
+ bestvertex = -1;
+ for(k=(i+1);k<j;k++) {
+ if(!dpstates[k][i].visible) continue;
+ if(!dpstates[j][k].visible) continue;
+
+ if(k<=(i+1)) d1=0;
+ else d1 = Distance(poly->GetPoint(i),poly->GetPoint(k));
+ if(j<=(k+1)) d2=0;
+ else d2 = Distance(poly->GetPoint(k),poly->GetPoint(j));
+
+ weight = dpstates[k][i].weight + dpstates[j][k].weight + d1 + d2;
+
+ if((bestvertex == -1)||(weight<minweight)) {
+ bestvertex = k;
+ minweight = weight;
+ }
+ }
+ if(bestvertex == -1) {
+ for(i=1;i<n;i++) {
+ delete [] dpstates[i];
+ }
+ delete [] dpstates;
+
+ return 0;
+ }
+
+ dpstates[j][i].bestvertex = bestvertex;
+ dpstates[j][i].weight = minweight;
+ }
+ }
+
+ newdiagonal.index1 = 0;
+ newdiagonal.index2 = n-1;
+ diagonals.push_back(newdiagonal);
+ while(!diagonals.empty()) {
+ diagonal = (diagonals.front()->get());
+ diagonals.pop_front();
+ bestvertex = dpstates[diagonal.index2][diagonal.index1].bestvertex;
+ if(bestvertex == -1) {
+ ret = 0;
+ break;
+ }
+ triangle.Triangle(poly->GetPoint(diagonal.index1),poly->GetPoint(bestvertex),poly->GetPoint(diagonal.index2));
+ triangles->push_back(triangle);
+ if(bestvertex > (diagonal.index1+1)) {
+ newdiagonal.index1 = diagonal.index1;
+ newdiagonal.index2 = bestvertex;
+ diagonals.push_back(newdiagonal);
+ }
+ if(diagonal.index2 > (bestvertex+1)) {
+ newdiagonal.index1 = bestvertex;
+ newdiagonal.index2 = diagonal.index2;
+ diagonals.push_back(newdiagonal);
+ }
+ }
+
+ for(i=1;i<n;i++) {
+ delete [] dpstates[i];
+ }
+ delete [] dpstates;
+
+ return ret;
+}
+
+void TriangulatorPartition::UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates) {
+ Diagonal newdiagonal;
+ List<Diagonal> *pairs;
+ long w2;
+
+ w2 = dpstates[a][b].weight;
+ if(w>w2) return;
+
+ pairs = &(dpstates[a][b].pairs);
+ newdiagonal.index1 = i;
+ newdiagonal.index2 = j;
+
+ if(w<w2) {
+ pairs->clear();
+ pairs->push_front(newdiagonal);
+ dpstates[a][b].weight = w;
+ } else {
+ if((!pairs->empty())&&(i <= pairs->front()->get().index1)) return;
+ while((!pairs->empty())&&(pairs->front()->get().index2 >= j)) pairs->pop_front();
+ pairs->push_front(newdiagonal);
+ }
+}
+
+void TriangulatorPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) {
+ List<Diagonal> *pairs;
+ List<Diagonal>::Element *iter,*lastiter;
+ long top;
+ long w;
+
+ if(!dpstates[i][j].visible) return;
+ top = j;
+ w = dpstates[i][j].weight;
+ if(k-j > 1) {
+ if (!dpstates[j][k].visible) return;
+ w += dpstates[j][k].weight + 1;
+ }
+ if(j-i > 1) {
+ pairs = &(dpstates[i][j].pairs);
+ iter = NULL;
+ lastiter = NULL;
+ while(iter!=pairs->front()) {
+ if (!iter)
+ iter=pairs->back();
+ else
+ iter=iter->prev();
+
+ if(!IsReflex(vertices[iter->get().index2].p,vertices[j].p,vertices[k].p)) lastiter = iter;
+ else break;
+ }
+ if(lastiter == NULL) w++;
+ else {
+ if(IsReflex(vertices[k].p,vertices[i].p,vertices[lastiter->get().index1].p)) w++;
+ else top = lastiter->get().index1;
+ }
+ }
+ UpdateState(i,k,w,top,j,dpstates);
+}
+
+void TriangulatorPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) {
+ List<Diagonal> *pairs;
+ List<Diagonal>::Element* iter,*lastiter;
+ long top;
+ long w;
+
+ if(!dpstates[j][k].visible) return;
+ top = j;
+ w = dpstates[j][k].weight;
+
+ if (j-i > 1) {
+ if (!dpstates[i][j].visible) return;
+ w += dpstates[i][j].weight + 1;
+ }
+ if (k-j > 1) {
+ pairs = &(dpstates[j][k].pairs);
+
+ iter = pairs->front();
+ if((!pairs->empty())&&(!IsReflex(vertices[i].p,vertices[j].p,vertices[iter->get().index1].p))) {
+ lastiter = iter;
+ while(iter!=NULL) {
+ if(!IsReflex(vertices[i].p,vertices[j].p,vertices[iter->get().index1].p)) {
+ lastiter = iter;
+ iter=iter->next();
+ }
+ else break;
+ }
+ if(IsReflex(vertices[lastiter->get().index2].p,vertices[k].p,vertices[i].p)) w++;
+ else top = lastiter->get().index2;
+ } else w++;
+ }
+ UpdateState(i,k,w,j,top,dpstates);
+}
+
+int TriangulatorPartition::ConvexPartition_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *parts) {
+ Vector2 p1,p2,p3,p4;
+ PartitionVertex *vertices;
+ DPState2 **dpstates;
+ long i,j,k,n,gap;
+ List<Diagonal> diagonals,diagonals2;
+ Diagonal diagonal,newdiagonal;
+ List<Diagonal> *pairs,*pairs2;
+ List<Diagonal>::Element* iter,*iter2;
+ int ret;
+ TriangulatorPoly newpoly;
+ List<long> indices;
+ List<long>::Element* iiter;
+ bool ijreal,jkreal;
+
+ n = poly->GetNumPoints();
+ vertices = new PartitionVertex[n];
+
+ dpstates = new DPState2 *[n];
+ for(i=0;i<n;i++) {
+ dpstates[i] = new DPState2[n];
+ }
+
+ //init vertex information
+ for(i=0;i<n;i++) {
+ vertices[i].p = poly->GetPoint(i);
+ vertices[i].isActive = true;
+ if(i==0) vertices[i].previous = &(vertices[n-1]);
+ else vertices[i].previous = &(vertices[i-1]);
+ if(i==(poly->GetNumPoints()-1)) vertices[i].next = &(vertices[0]);
+ else vertices[i].next = &(vertices[i+1]);
+ }
+ for(i=1;i<n;i++) {
+ UpdateVertexReflexity(&(vertices[i]));
+ }
+
+ //init states and visibility
+ for(i=0;i<(n-1);i++) {
+ p1 = poly->GetPoint(i);
+ for(j=i+1;j<n;j++) {
+ dpstates[i][j].visible = true;
+ if(j==i+1) {
+ dpstates[i][j].weight = 0;
+ } else {
+ dpstates[i][j].weight = 2147483647;
+ }
+ if(j!=(i+1)) {
+ p2 = poly->GetPoint(j);
+
+ //visibility check
+ if(!InCone(&vertices[i],p2)) {
+ dpstates[i][j].visible = false;
+ continue;
+ }
+ if(!InCone(&vertices[j],p1)) {
+ dpstates[i][j].visible = false;
+ continue;
+ }
+
+ for(k=0;k<n;k++) {
+ p3 = poly->GetPoint(k);
+ if(k==(n-1)) p4 = poly->GetPoint(0);
+ else p4 = poly->GetPoint(k+1);
+ if(Intersects(p1,p2,p3,p4)) {
+ dpstates[i][j].visible = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ for(i=0;i<(n-2);i++) {
+ j = i+2;
+ if(dpstates[i][j].visible) {
+ dpstates[i][j].weight = 0;
+ newdiagonal.index1 = i+1;
+ newdiagonal.index2 = i+1;
+ dpstates[i][j].pairs.push_back(newdiagonal);
+ }
+ }
+
+ dpstates[0][n-1].visible = true;
+ vertices[0].isConvex = false; //by convention
+
+ for(gap=3; gap<n; gap++) {
+ for(i=0;i<n-gap;i++) {
+ if(vertices[i].isConvex) continue;
+ k = i+gap;
+ if(dpstates[i][k].visible) {
+ if(!vertices[k].isConvex) {
+ for(j=i+1;j<k;j++) TypeA(i,j,k,vertices,dpstates);
+ } else {
+ for(j=i+1;j<(k-1);j++) {
+ if(vertices[j].isConvex) continue;
+ TypeA(i,j,k,vertices,dpstates);
+ }
+ TypeA(i,k-1,k,vertices,dpstates);
+ }
+ }
+ }
+ for(k=gap;k<n;k++) {
+ if(vertices[k].isConvex) continue;
+ i = k-gap;
+ if((vertices[i].isConvex)&&(dpstates[i][k].visible)) {
+ TypeB(i,i+1,k,vertices,dpstates);
+ for(j=i+2;j<k;j++) {
+ if(vertices[j].isConvex) continue;
+ TypeB(i,j,k,vertices,dpstates);
+ }
+ }
+ }
+ }
+
+
+ //recover solution
+ ret = 1;
+ newdiagonal.index1 = 0;
+ newdiagonal.index2 = n-1;
+ diagonals.push_front(newdiagonal);
+ while(!diagonals.empty()) {
+ diagonal = (diagonals.front()->get());
+ diagonals.pop_front();
+ if((diagonal.index2 - diagonal.index1) <=1) continue;
+ pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs);
+ if(pairs->empty()) {
+ ret = 0;
+ break;
+ }
+ if(!vertices[diagonal.index1].isConvex) {
+ iter = pairs->back();
+
+ j = iter->get().index2;
+ newdiagonal.index1 = j;
+ newdiagonal.index2 = diagonal.index2;
+ diagonals.push_front(newdiagonal);
+ if((j - diagonal.index1)>1) {
+ if(iter->get().index1 != iter->get().index2) {
+ pairs2 = &(dpstates[diagonal.index1][j].pairs);
+ while(1) {
+ if(pairs2->empty()) {
+ ret = 0;
+ break;
+ }
+ iter2 = pairs2->back();
+
+ if(iter->get().index1 != iter2->get().index1) pairs2->pop_back();
+ else break;
+ }
+ if(ret == 0) break;
+ }
+ newdiagonal.index1 = diagonal.index1;
+ newdiagonal.index2 = j;
+ diagonals.push_front(newdiagonal);
+ }
+ } else {
+ iter = pairs->front();
+ j = iter->get().index1;
+ newdiagonal.index1 = diagonal.index1;
+ newdiagonal.index2 = j;
+ diagonals.push_front(newdiagonal);
+ if((diagonal.index2 - j) > 1) {
+ if(iter->get().index1 != iter->get().index2) {
+ pairs2 = &(dpstates[j][diagonal.index2].pairs);
+ while(1) {
+ if(pairs2->empty()) {
+ ret = 0;
+ break;
+ }
+ iter2 = pairs2->front();
+ if(iter->get().index2 != iter2->get().index2) pairs2->pop_front();
+ else break;
+ }
+ if(ret == 0) break;
+ }
+ newdiagonal.index1 = j;
+ newdiagonal.index2 = diagonal.index2;
+ diagonals.push_front(newdiagonal);
+ }
+ }
+ }
+
+ if(ret == 0) {
+ for(i=0;i<n;i++) {
+ delete [] dpstates[i];
+ }
+ delete [] dpstates;
+ delete [] vertices;
+
+ return ret;
+ }
+
+ newdiagonal.index1 = 0;
+ newdiagonal.index2 = n-1;
+ diagonals.push_front(newdiagonal);
+ while(!diagonals.empty()) {
+ diagonal = (diagonals.front())->get();
+ diagonals.pop_front();
+ if((diagonal.index2 - diagonal.index1) <= 1) continue;
+
+ indices.clear();
+ diagonals2.clear();
+ indices.push_back(diagonal.index1);
+ indices.push_back(diagonal.index2);
+ diagonals2.push_front(diagonal);
+
+ while(!diagonals2.empty()) {
+ diagonal = (diagonals2.front()->get());
+ diagonals2.pop_front();
+ if((diagonal.index2 - diagonal.index1) <= 1) continue;
+ ijreal = true;
+ jkreal = true;
+ pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs);
+ if(!vertices[diagonal.index1].isConvex) {
+ iter = pairs->back();
+ j = iter->get().index2;
+ if(iter->get().index1 != iter->get().index2) ijreal = false;
+ } else {
+ iter = pairs->front();
+ j = iter->get().index1;
+ if(iter->get().index1 != iter->get().index2) jkreal = false;
+ }
+
+ newdiagonal.index1 = diagonal.index1;
+ newdiagonal.index2 = j;
+ if(ijreal) {
+ diagonals.push_back(newdiagonal);
+ } else {
+ diagonals2.push_back(newdiagonal);
+ }
+
+ newdiagonal.index1 = j;
+ newdiagonal.index2 = diagonal.index2;
+ if(jkreal) {
+ diagonals.push_back(newdiagonal);
+ } else {
+ diagonals2.push_back(newdiagonal);
+ }
+
+ indices.push_back(j);
+ }
+
+ indices.sort();
+ newpoly.Init((long)indices.size());
+ k=0;
+ for(iiter = indices.front();iiter;iiter=iiter->next()) {
+ newpoly[k] = vertices[iiter->get()].p;
+ k++;
+ }
+ parts->push_back(newpoly);
+ }
+
+ for(i=0;i<n;i++) {
+ delete [] dpstates[i];
+ }
+ delete [] dpstates;
+ delete [] vertices;
+
+ return ret;
+}
+
+//triangulates a set of polygons by first partitioning them into monotone polygons
+//O(n*log(n)) time complexity, O(n) space complexity
+//the algorithm used here is outlined in the book
+//"Computational Geometry: Algorithms and Applications"
+//by Mark de Berg, Otfried Cheong, Marc van Kreveld and Mark Overmars
+int TriangulatorPartition::MonotonePartition(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *monotonePolys) {
+ List<TriangulatorPoly>::Element *iter;
+ MonotoneVertex *vertices;
+ long i,numvertices,vindex,vindex2,newnumvertices,maxnumvertices;
+ long polystartindex, polyendindex;
+ TriangulatorPoly *poly;
+ MonotoneVertex *v,*v2,*vprev,*vnext;
+ ScanLineEdge newedge;
+ bool error = false;
+
+ numvertices = 0;
+ for(iter = inpolys->front(); iter ; iter=iter->next()) {
+ numvertices += iter->get().GetNumPoints();
+ }
+
+ maxnumvertices = numvertices*3;
+ vertices = new MonotoneVertex[maxnumvertices];
+ newnumvertices = numvertices;
+
+ polystartindex = 0;
+ for(iter = inpolys->front(); iter ; iter=iter->next()) {
+ poly = &(iter->get());
+ polyendindex = polystartindex + poly->GetNumPoints()-1;
+ for(i=0;i<poly->GetNumPoints();i++) {
+ vertices[i+polystartindex].p = poly->GetPoint(i);
+ if(i==0) vertices[i+polystartindex].previous = polyendindex;
+ else vertices[i+polystartindex].previous = i+polystartindex-1;
+ if(i==(poly->GetNumPoints()-1)) vertices[i+polystartindex].next = polystartindex;
+ else vertices[i+polystartindex].next = i+polystartindex+1;
+ }
+ polystartindex = polyendindex+1;
+ }
+
+ //construct the priority queue
+ long *priority = new long [numvertices];
+ for(i=0;i<numvertices;i++) priority[i] = i;
+ SortArray<long,VertexSorter> sorter;
+ sorter.compare.vertices=vertices;
+ sorter.sort(priority,numvertices);
+
+ //determine vertex types
+ char *vertextypes = new char[maxnumvertices];
+ for(i=0;i<numvertices;i++) {
+ v = &(vertices[i]);
+ vprev = &(vertices[v->previous]);
+ vnext = &(vertices[v->next]);
+
+ if(Below(vprev->p,v->p)&&Below(vnext->p,v->p)) {
+ if(IsConvex(vnext->p,vprev->p,v->p)) {
+ vertextypes[i] = TRIANGULATOR_VERTEXTYPE_START;
+ } else {
+ vertextypes[i] = TRIANGULATOR_VERTEXTYPE_SPLIT;
+ }
+ } else if(Below(v->p,vprev->p)&&Below(v->p,vnext->p)) {
+ if(IsConvex(vnext->p,vprev->p,v->p))
+ {
+ vertextypes[i] = TRIANGULATOR_VERTEXTYPE_END;
+ } else {
+ vertextypes[i] = TRIANGULATOR_VERTEXTYPE_MERGE;
+ }
+ } else {
+ vertextypes[i] = TRIANGULATOR_VERTEXTYPE_REGULAR;
+ }
+ }
+
+ //helpers
+ long *helpers = new long[maxnumvertices];
+
+ //binary search tree that holds edges intersecting the scanline
+ //note that while set doesn't actually have to be implemented as a tree
+ //complexity requirements for operations are the same as for the balanced binary search tree
+ Set<ScanLineEdge> edgeTree;
+ //store iterators to the edge tree elements
+ //this makes deleting existing edges much faster
+ Set<ScanLineEdge>::Element **edgeTreeIterators,*edgeIter;
+ edgeTreeIterators = new Set<ScanLineEdge>::Element*[maxnumvertices];
+// Pair<Set<ScanLineEdge>::Element*,bool> edgeTreeRet;
+ for(i = 0; i<numvertices; i++) edgeTreeIterators[i] = NULL;
+
+ //for each vertex
+ for(i=0;i<numvertices;i++) {
+ vindex = priority[i];
+ v = &(vertices[vindex]);
+ vindex2 = vindex;
+ v2 = v;
+
+ //depending on the vertex type, do the appropriate action
+ //comments in the following sections are copied from "Computational Geometry: Algorithms and Applications"
+ switch(vertextypes[vindex]) {
+ case TRIANGULATOR_VERTEXTYPE_START:
+ //Insert ei in T and set helper(ei) to vi.
+ newedge.p1 = v->p;
+ newedge.p2 = vertices[v->next].p;
+ newedge.index = vindex;
+ edgeTreeIterators[vindex] = edgeTree.insert(newedge);
+ helpers[vindex] = vindex;
+ break;
+
+ case TRIANGULATOR_VERTEXTYPE_END:
+ //if helper(ei-1) is a merge vertex
+ if(vertextypes[helpers[v->previous]]==TRIANGULATOR_VERTEXTYPE_MERGE) {
+ //Insert the diagonal connecting vi to helper(ei-1) in D.
+ AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous],
+ vertextypes, edgeTreeIterators, &edgeTree, helpers);
+ }
+ //Delete ei-1 from T
+ edgeTree.erase(edgeTreeIterators[v->previous]);
+ break;
+
+ case TRIANGULATOR_VERTEXTYPE_SPLIT:
+ //Search in T to find the edge e j directly left of vi.
+ newedge.p1 = v->p;
+ newedge.p2 = v->p;
+ edgeIter = edgeTree.lower_bound(newedge);
+ if(edgeIter == edgeTree.front()) {
+ error = true;
+ break;
+ }
+ edgeIter=edgeIter->prev();
+ //Insert the diagonal connecting vi to helper(ej) in D.
+ AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->get().index],
+ vertextypes, edgeTreeIterators, &edgeTree, helpers);
+ vindex2 = newnumvertices-2;
+ v2 = &(vertices[vindex2]);
+ //helper(e j)�vi
+ helpers[edgeIter->get().index] = vindex;
+ //Insert ei in T and set helper(ei) to vi.
+ newedge.p1 = v2->p;
+ newedge.p2 = vertices[v2->next].p;
+ newedge.index = vindex2;
+
+ edgeTreeIterators[vindex2] = edgeTree.insert(newedge);
+ helpers[vindex2] = vindex2;
+ break;
+
+ case TRIANGULATOR_VERTEXTYPE_MERGE:
+ //if helper(ei-1) is a merge vertex
+ if(vertextypes[helpers[v->previous]]==TRIANGULATOR_VERTEXTYPE_MERGE) {
+ //Insert the diagonal connecting vi to helper(ei-1) in D.
+ AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous],
+ vertextypes, edgeTreeIterators, &edgeTree, helpers);
+ vindex2 = newnumvertices-2;
+ v2 = &(vertices[vindex2]);
+ }
+ //Delete ei-1 from T.
+ edgeTree.erase(edgeTreeIterators[v->previous]);
+ //Search in T to find the edge e j directly left of vi.
+ newedge.p1 = v->p;
+ newedge.p2 = v->p;
+ edgeIter = edgeTree.lower_bound(newedge);
+ if(edgeIter == edgeTree.front()) {
+ error = true;
+ break;
+ }
+ edgeIter=edgeIter->prev();
+ //if helper(ej) is a merge vertex
+ if(vertextypes[helpers[edgeIter->get().index]]==TRIANGULATOR_VERTEXTYPE_MERGE) {
+ //Insert the diagonal connecting vi to helper(e j) in D.
+ AddDiagonal(vertices,&newnumvertices,vindex2,helpers[edgeIter->get().index],
+ vertextypes, edgeTreeIterators, &edgeTree, helpers);
+ }
+ //helper(e j)�vi
+ helpers[edgeIter->get().index] = vindex2;
+ break;
+
+ case TRIANGULATOR_VERTEXTYPE_REGULAR:
+ //if the interior of P lies to the right of vi
+ if(Below(v->p,vertices[v->previous].p)) {
+ //if helper(ei-1) is a merge vertex
+ if(vertextypes[helpers[v->previous]]==TRIANGULATOR_VERTEXTYPE_MERGE) {
+ //Insert the diagonal connecting vi to helper(ei-1) in D.
+ AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous],
+ vertextypes, edgeTreeIterators, &edgeTree, helpers);
+ vindex2 = newnumvertices-2;
+ v2 = &(vertices[vindex2]);
+ }
+ //Delete ei-1 from T.
+ edgeTree.erase(edgeTreeIterators[v->previous]);
+ //Insert ei in T and set helper(ei) to vi.
+ newedge.p1 = v2->p;
+ newedge.p2 = vertices[v2->next].p;
+ newedge.index = vindex2;
+ edgeTreeIterators[vindex2] = edgeTree.insert(newedge);
+ helpers[vindex2] = vindex;
+ } else {
+ //Search in T to find the edge ej directly left of vi.
+ newedge.p1 = v->p;
+ newedge.p2 = v->p;
+ edgeIter = edgeTree.lower_bound(newedge);
+ if(edgeIter == edgeTree.front()) {
+ error = true;
+ break;
+ }
+ edgeIter=edgeIter->prev();
+ //if helper(ej) is a merge vertex
+ if(vertextypes[helpers[edgeIter->get().index]]==TRIANGULATOR_VERTEXTYPE_MERGE) {
+ //Insert the diagonal connecting vi to helper(e j) in D.
+ AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->get().index],
+ vertextypes, edgeTreeIterators, &edgeTree, helpers);
+ }
+ //helper(e j)�vi
+ helpers[edgeIter->get().index] = vindex;
+ }
+ break;
+ }
+
+ if(error) break;
+ }
+
+ char *used = new char[newnumvertices];
+ memset(used,0,newnumvertices*sizeof(char));
+
+ if(!error) {
+ //return result
+ long size;
+ TriangulatorPoly mpoly;
+ for(i=0;i<newnumvertices;i++) {
+ if(used[i]) continue;
+ v = &(vertices[i]);
+ vnext = &(vertices[v->next]);
+ size = 1;
+ while(vnext!=v) {
+ vnext = &(vertices[vnext->next]);
+ size++;
+ }
+ mpoly.Init(size);
+ v = &(vertices[i]);
+ mpoly[0] = v->p;
+ vnext = &(vertices[v->next]);
+ size = 1;
+ used[i] = 1;
+ used[v->next] = 1;
+ while(vnext!=v) {
+ mpoly[size] = vnext->p;
+ used[vnext->next] = 1;
+ vnext = &(vertices[vnext->next]);
+ size++;
+ }
+ monotonePolys->push_back(mpoly);
+ }
+ }
+
+ //cleanup
+ delete [] vertices;
+ delete [] priority;
+ delete [] vertextypes;
+ delete [] edgeTreeIterators;
+ delete [] helpers;
+ delete [] used;
+
+ if(error) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+//adds a diagonal to the doubly-connected list of vertices
+void TriangulatorPartition::AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2,
+ char *vertextypes, Set<ScanLineEdge>::Element **edgeTreeIterators,
+ Set<ScanLineEdge> *edgeTree, long *helpers)
+{
+ long newindex1,newindex2;
+
+ newindex1 = *numvertices;
+ (*numvertices)++;
+ newindex2 = *numvertices;
+ (*numvertices)++;
+
+ vertices[newindex1].p = vertices[index1].p;
+ vertices[newindex2].p = vertices[index2].p;
+
+ vertices[newindex2].next = vertices[index2].next;
+ vertices[newindex1].next = vertices[index1].next;
+
+ vertices[vertices[index2].next].previous = newindex2;
+ vertices[vertices[index1].next].previous = newindex1;
+
+ vertices[index1].next = newindex2;
+ vertices[newindex2].previous = index1;
+
+ vertices[index2].next = newindex1;
+ vertices[newindex1].previous = index2;
+
+ //update all relevant structures
+ vertextypes[newindex1] = vertextypes[index1];
+ edgeTreeIterators[newindex1] = edgeTreeIterators[index1];
+ helpers[newindex1] = helpers[index1];
+ if(edgeTreeIterators[newindex1] != NULL)
+ edgeTreeIterators[newindex1]->get().index = newindex1;
+ vertextypes[newindex2] = vertextypes[index2];
+ edgeTreeIterators[newindex2] = edgeTreeIterators[index2];
+ helpers[newindex2] = helpers[index2];
+ if(edgeTreeIterators[newindex2] != NULL)
+ edgeTreeIterators[newindex2]->get().index = newindex2;
+}
+
+bool TriangulatorPartition::Below(Vector2 &p1, Vector2 &p2) {
+ if(p1.y < p2.y) return true;
+ else if(p1.y == p2.y) {
+ if(p1.x < p2.x) return true;
+ }
+ return false;
+}
+
+
+
+
+
+//sorts in the falling order of y values, if y is equal, x is used instead
+bool TriangulatorPartition::VertexSorter::operator() (long index1, long index2) const {
+ if(vertices[index1].p.y > vertices[index2].p.y) return true;
+ else if(vertices[index1].p.y == vertices[index2].p.y) {
+ if(vertices[index1].p.x > vertices[index2].p.x) return true;
+ }
+ return false;
+}
+
+bool TriangulatorPartition::ScanLineEdge::IsConvex(const Vector2& p1, const Vector2& p2, const Vector2& p3) const {
+ real_t tmp;
+ tmp = (p3.y-p1.y)*(p2.x-p1.x)-(p3.x-p1.x)*(p2.y-p1.y);
+ if(tmp>0) return 1;
+ else return 0;
+}
+
+bool TriangulatorPartition::ScanLineEdge::operator < (const ScanLineEdge & other) const {
+ if(other.p1.y == other.p2.y) {
+ if(p1.y == p2.y) {
+ if(p1.y < other.p1.y) return true;
+ else return false;
+ }
+ if(IsConvex(p1,p2,other.p1)) return true;
+ else return false;
+ } else if(p1.y == p2.y) {
+ if(IsConvex(other.p1,other.p2,p1)) return false;
+ else return true;
+ } else if(p1.y < other.p1.y) {
+ if(IsConvex(other.p1,other.p2,p1)) return false;
+ else return true;
+ } else {
+ if(IsConvex(p1,p2,other.p1)) return true;
+ else return false;
+ }
+}
+
+//triangulates monotone polygon
+//O(n) time, O(n) space complexity
+int TriangulatorPartition::TriangulateMonotone(TriangulatorPoly *inPoly, List<TriangulatorPoly> *triangles) {
+ long i,i2,j,topindex,bottomindex,leftindex,rightindex,vindex;
+ Vector2 *points;
+ long numpoints;
+ TriangulatorPoly triangle;
+
+ numpoints = inPoly->GetNumPoints();
+ points = inPoly->GetPoints();
+
+ //trivial calses
+ if(numpoints < 3) return 0;
+ if(numpoints == 3) {
+ triangles->push_back(*inPoly);
+ }
+
+ topindex = 0; bottomindex=0;
+ for(i=1;i<numpoints;i++) {
+ if(Below(points[i],points[bottomindex])) bottomindex = i;
+ if(Below(points[topindex],points[i])) topindex = i;
+ }
+
+ //check if the poly is really monotone
+ i = topindex;
+ while(i!=bottomindex) {
+ i2 = i+1; if(i2>=numpoints) i2 = 0;
+ if(!Below(points[i2],points[i])) return 0;
+ i = i2;
+ }
+ i = bottomindex;
+ while(i!=topindex) {
+ i2 = i+1; if(i2>=numpoints) i2 = 0;
+ if(!Below(points[i],points[i2])) return 0;
+ i = i2;
+ }
+
+ char *vertextypes = new char[numpoints];
+ long *priority = new long[numpoints];
+
+ //merge left and right vertex chains
+ priority[0] = topindex;
+ vertextypes[topindex] = 0;
+ leftindex = topindex+1; if(leftindex>=numpoints) leftindex = 0;
+ rightindex = topindex-1; if(rightindex<0) rightindex = numpoints-1;
+ for(i=1;i<(numpoints-1);i++) {
+ if(leftindex==bottomindex) {
+ priority[i] = rightindex;
+ rightindex--; if(rightindex<0) rightindex = numpoints-1;
+ vertextypes[priority[i]] = -1;
+ } else if(rightindex==bottomindex) {
+ priority[i] = leftindex;
+ leftindex++; if(leftindex>=numpoints) leftindex = 0;
+ vertextypes[priority[i]] = 1;
+ } else {
+ if(Below(points[leftindex],points[rightindex])) {
+ priority[i] = rightindex;
+ rightindex--; if(rightindex<0) rightindex = numpoints-1;
+ vertextypes[priority[i]] = -1;
+ } else {
+ priority[i] = leftindex;
+ leftindex++; if(leftindex>=numpoints) leftindex = 0;
+ vertextypes[priority[i]] = 1;
+ }
+ }
+ }
+ priority[i] = bottomindex;
+ vertextypes[bottomindex] = 0;
+
+ long *stack = new long[numpoints];
+ long stackptr = 0;
+
+ stack[0] = priority[0];
+ stack[1] = priority[1];
+ stackptr = 2;
+
+ //for each vertex from top to bottom trim as many triangles as possible
+ for(i=2;i<(numpoints-1);i++) {
+ vindex = priority[i];
+ if(vertextypes[vindex]!=vertextypes[stack[stackptr-1]]) {
+ for(j=0;j<(stackptr-1);j++) {
+ if(vertextypes[vindex]==1) {
+ triangle.Triangle(points[stack[j+1]],points[stack[j]],points[vindex]);
+ } else {
+ triangle.Triangle(points[stack[j]],points[stack[j+1]],points[vindex]);
+ }
+ triangles->push_back(triangle);
+ }
+ stack[0] = priority[i-1];
+ stack[1] = priority[i];
+ stackptr = 2;
+ } else {
+ stackptr--;
+ while(stackptr>0) {
+ if(vertextypes[vindex]==1) {
+ if(IsConvex(points[vindex],points[stack[stackptr-1]],points[stack[stackptr]])) {
+ triangle.Triangle(points[vindex],points[stack[stackptr-1]],points[stack[stackptr]]);
+ triangles->push_back(triangle);
+ stackptr--;
+ } else {
+ break;
+ }
+ } else {
+ if(IsConvex(points[vindex],points[stack[stackptr]],points[stack[stackptr-1]])) {
+ triangle.Triangle(points[vindex],points[stack[stackptr]],points[stack[stackptr-1]]);
+ triangles->push_back(triangle);
+ stackptr--;
+ } else {
+ break;
+ }
+ }
+ }
+ stackptr++;
+ stack[stackptr] = vindex;
+ stackptr++;
+ }
+ }
+ vindex = priority[i];
+ for(j=0;j<(stackptr-1);j++) {
+ if(vertextypes[stack[j+1]]==1) {
+ triangle.Triangle(points[stack[j]],points[stack[j+1]],points[vindex]);
+ } else {
+ triangle.Triangle(points[stack[j+1]],points[stack[j]],points[vindex]);
+ }
+ triangles->push_back(triangle);
+ }
+
+ delete [] priority;
+ delete [] vertextypes;
+ delete [] stack;
+
+ return 1;
+}
+
+int TriangulatorPartition::Triangulate_MONO(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles) {
+ List<TriangulatorPoly> monotone;
+ List<TriangulatorPoly>::Element* iter;
+
+ if(!MonotonePartition(inpolys,&monotone)) return 0;
+ for(iter = monotone.front(); iter;iter=iter->next()) {
+ if(!TriangulateMonotone(&(iter->get()),triangles)) return 0;
+ }
+ return 1;
+}
+
+int TriangulatorPartition::Triangulate_MONO(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles) {
+ List<TriangulatorPoly> polys;
+ polys.push_back(*poly);
+
+ return Triangulate_MONO(&polys, triangles);
+}
diff --git a/core/math/triangulator.h b/core/math/triangulator.h
new file mode 100644
index 0000000000..b6dd7e8236
--- /dev/null
+++ b/core/math/triangulator.h
@@ -0,0 +1,306 @@
+//Copyright (C) 2011 by Ivan Fratric
+//
+//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 TRIANGULATOR_H
+#define TRIANGULATOR_H
+
+#include "math_2d.h"
+#include "list.h"
+#include "set.h"
+//2D point structure
+
+
+#define TRIANGULATOR_CCW 1
+#define TRIANGULATOR_CW -1
+//Polygon implemented as an array of points with a 'hole' flag
+class TriangulatorPoly {
+protected:
+
+
+
+ Vector2 *points;
+ long numpoints;
+ bool hole;
+
+public:
+
+ //constructors/destructors
+ TriangulatorPoly();
+ ~TriangulatorPoly();
+
+ TriangulatorPoly(const TriangulatorPoly &src);
+ TriangulatorPoly& operator=(const TriangulatorPoly &src);
+
+ //getters and setters
+ long GetNumPoints() {
+ return numpoints;
+ }
+
+ bool IsHole() {
+ return hole;
+ }
+
+ void SetHole(bool hole) {
+ this->hole = hole;
+ }
+
+ Vector2 &GetPoint(long i) {
+ return points[i];
+ }
+
+ Vector2 *GetPoints() {
+ return points;
+ }
+
+ Vector2& operator[] (int i) {
+ return points[i];
+ }
+
+ //clears the polygon points
+ void Clear();
+
+ //inits the polygon with numpoints vertices
+ void Init(long numpoints);
+
+ //creates a triangle with points p1,p2,p3
+ void Triangle(Vector2 &p1, Vector2 &p2, Vector2 &p3);
+
+ //inverts the orfer of vertices
+ void Invert();
+
+ //returns the orientation of the polygon
+ //possible values:
+ // Triangulator_CCW : polygon vertices are in counter-clockwise order
+ // Triangulator_CW : polygon vertices are in clockwise order
+ // 0 : the polygon has no (measurable) area
+ int GetOrientation();
+
+ //sets the polygon orientation
+ //orientation can be
+ // Triangulator_CCW : sets vertices in counter-clockwise order
+ // Triangulator_CW : sets vertices in clockwise order
+ void SetOrientation(int orientation);
+};
+
+class TriangulatorPartition {
+protected:
+ struct PartitionVertex {
+ bool isActive;
+ bool isConvex;
+ bool isEar;
+
+ Vector2 p;
+ real_t angle;
+ PartitionVertex *previous;
+ PartitionVertex *next;
+ };
+
+ struct MonotoneVertex {
+ Vector2 p;
+ long previous;
+ long next;
+ };
+
+ struct VertexSorter{
+ mutable MonotoneVertex *vertices;
+ bool operator() (long index1, long index2) const;
+ };
+
+ struct Diagonal {
+ long index1;
+ long index2;
+ };
+
+ //dynamic programming state for minimum-weight triangulation
+ struct DPState {
+ bool visible;
+ real_t weight;
+ long bestvertex;
+ };
+
+ //dynamic programming state for convex partitioning
+ struct DPState2 {
+ bool visible;
+ long weight;
+ List<Diagonal> pairs;
+ };
+
+ //edge that intersects the scanline
+ struct ScanLineEdge {
+ mutable long index;
+ Vector2 p1;
+ Vector2 p2;
+
+ //determines if the edge is to the left of another edge
+ bool operator< (const ScanLineEdge & other) const;
+
+ bool IsConvex(const Vector2& p1, const Vector2& p2, const Vector2& p3) const;
+ };
+
+ //standard helper functions
+ bool IsConvex(Vector2& p1, Vector2& p2, Vector2& p3);
+ bool IsReflex(Vector2& p1, Vector2& p2, Vector2& p3);
+ bool IsInside(Vector2& p1, Vector2& p2, Vector2& p3, Vector2 &p);
+
+ bool InCone(Vector2 &p1, Vector2 &p2, Vector2 &p3, Vector2 &p);
+ bool InCone(PartitionVertex *v, Vector2 &p);
+
+ int Intersects(Vector2 &p11, Vector2 &p12, Vector2 &p21, Vector2 &p22);
+
+ Vector2 Normalize(const Vector2 &p);
+ real_t Distance(const Vector2 &p1, const Vector2 &p2);
+
+ //helper functions for Triangulate_EC
+ void UpdateVertexReflexity(PartitionVertex *v);
+ void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices);
+
+ //helper functions for ConvexPartition_OPT
+ void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates);
+ void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
+ void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
+
+ //helper functions for MonotonePartition
+ bool Below(Vector2 &p1, Vector2 &p2);
+ void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2,
+ char *vertextypes, Set<ScanLineEdge>::Element **edgeTreeIterators,
+ Set<ScanLineEdge> *edgeTree, long *helpers);
+
+ //triangulates a monotone polygon, used in Triangulate_MONO
+ int TriangulateMonotone(TriangulatorPoly *inPoly, List<TriangulatorPoly> *triangles);
+
+public:
+
+ //simple heuristic procedure for removing holes from a list of polygons
+ //works by creating a diagonal from the rightmost hole vertex to some visible vertex
+ //time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
+ //space complexity: O(n)
+ //params:
+ // inpolys : a list of polygons that can contain holes
+ // vertices of all non-hole polys have to be in counter-clockwise order
+ // vertices of all hole polys have to be in clockwise order
+ // outpolys : a list of polygons without holes
+ //returns 1 on success, 0 on failure
+ int RemoveHoles(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *outpolys);
+
+ //triangulates a polygon by ear clipping
+ //time complexity O(n^2), n is the number of vertices
+ //space complexity: O(n)
+ //params:
+ // poly : an input polygon to be triangulated
+ // vertices have to be in counter-clockwise order
+ // triangles : a list of triangles (result)
+ //returns 1 on success, 0 on failure
+ int Triangulate_EC(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
+
+ //triangulates a list of polygons that may contain holes by ear clipping algorithm
+ //first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon
+ //time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
+ //space complexity: O(n)
+ //params:
+ // inpolys : a list of polygons to be triangulated (can contain holes)
+ // vertices of all non-hole polys have to be in counter-clockwise order
+ // vertices of all hole polys have to be in clockwise order
+ // triangles : a list of triangles (result)
+ //returns 1 on success, 0 on failure
+ int Triangulate_EC(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles);
+
+ //creates an optimal polygon triangulation in terms of minimal edge length
+ //time complexity: O(n^3), n is the number of vertices
+ //space complexity: O(n^2)
+ //params:
+ // poly : an input polygon to be triangulated
+ // vertices have to be in counter-clockwise order
+ // triangles : a list of triangles (result)
+ //returns 1 on success, 0 on failure
+ int Triangulate_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
+
+ //triangulates a polygons by firstly partitioning it into monotone polygons
+ //time complexity: O(n*log(n)), n is the number of vertices
+ //space complexity: O(n)
+ //params:
+ // poly : an input polygon to be triangulated
+ // vertices have to be in counter-clockwise order
+ // triangles : a list of triangles (result)
+ //returns 1 on success, 0 on failure
+ int Triangulate_MONO(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
+
+ //triangulates a list of polygons by firstly partitioning them into monotone polygons
+ //time complexity: O(n*log(n)), n is the number of vertices
+ //space complexity: O(n)
+ //params:
+ // inpolys : a list of polygons to be triangulated (can contain holes)
+ // vertices of all non-hole polys have to be in counter-clockwise order
+ // vertices of all hole polys have to be in clockwise order
+ // triangles : a list of triangles (result)
+ //returns 1 on success, 0 on failure
+ int Triangulate_MONO(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles);
+
+ //creates a monotone partition of a list of polygons that can contain holes
+ //time complexity: O(n*log(n)), n is the number of vertices
+ //space complexity: O(n)
+ //params:
+ // inpolys : a list of polygons to be triangulated (can contain holes)
+ // vertices of all non-hole polys have to be in counter-clockwise order
+ // vertices of all hole polys have to be in clockwise order
+ // monotonePolys : a list of monotone polygons (result)
+ //returns 1 on success, 0 on failure
+ int MonotonePartition(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *monotonePolys);
+
+ //partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm
+ //the algorithm gives at most four times the number of parts as the optimal algorithm
+ //however, in practice it works much better than that and often gives optimal partition
+ //uses triangulation obtained by ear clipping as intermediate result
+ //time complexity O(n^2), n is the number of vertices
+ //space complexity: O(n)
+ //params:
+ // poly : an input polygon to be partitioned
+ // vertices have to be in counter-clockwise order
+ // parts : resulting list of convex polygons
+ //returns 1 on success, 0 on failure
+ int ConvexPartition_HM(TriangulatorPoly *poly, List<TriangulatorPoly> *parts);
+
+ //partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm
+ //the algorithm gives at most four times the number of parts as the optimal algorithm
+ //however, in practice it works much better than that and often gives optimal partition
+ //uses triangulation obtained by ear clipping as intermediate result
+ //time complexity O(n^2), n is the number of vertices
+ //space complexity: O(n)
+ //params:
+ // inpolys : an input list of polygons to be partitioned
+ // vertices of all non-hole polys have to be in counter-clockwise order
+ // vertices of all hole polys have to be in clockwise order
+ // parts : resulting list of convex polygons
+ //returns 1 on success, 0 on failure
+ int ConvexPartition_HM(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *parts);
+
+ //optimal convex partitioning (in terms of number of resulting convex polygons)
+ //using the Keil-Snoeyink algorithm
+ //M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998
+ //time complexity O(n^3), n is the number of vertices
+ //space complexity: O(n^3)
+ // poly : an input polygon to be partitioned
+ // vertices have to be in counter-clockwise order
+ // parts : resulting list of convex polygons
+ //returns 1 on success, 0 on failure
+ int ConvexPartition_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *parts);
+};
+
+
+#endif
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index cf6fd9242e..a3877eb9ff 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,27 +27,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "vector3.h"
-
+#include "matrix3.h"
void Vector3::rotate(const Vector3& p_axis,float p_phi) {
- Vector3 axis1 = cross(p_axis);
- float l = axis1.length();
- if (l==0)
- return;
- axis1/=l;
- Vector3 axis2 = axis1.cross(p_axis).normalized();
-
- float _x = axis1.dot(*this);
- float _y = axis2.dot(*this);
-
- float ang = Math::atan2(_x,_y);
-
- ang+=p_phi;
-
- *this=((axis1 * Math::cos(ang)) + (axis2 * Math::sin(ang))) * length();
-
+ *this=Matrix3(p_axis,p_phi).xform(*this);
}
Vector3 Vector3::rotated(const Vector3& p_axis,float p_phi) const {
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 959f7cd0a8..8a3cca8f33 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,10 +107,18 @@ 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;
+
+
+ _FORCE_INLINE_ Vector3 slide(const Vector3& p_vec) const;
+ _FORCE_INLINE_ Vector3 reflect(const Vector3& p_vec) const;
+
+
/* Operators */
_FORCE_INLINE_ Vector3& operator+=(const Vector3& p_v);
@@ -166,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 {
@@ -295,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 {
@@ -368,6 +386,16 @@ void Vector3::zero() {
x=y=z=0;
}
+Vector3 Vector3::slide(const Vector3& p_vec) const {
+
+ return p_vec - *this * this->dot(p_vec);
+}
+Vector3 Vector3::reflect(const Vector3& p_vec) const {
+
+ return p_vec - *this * this->dot(p_vec) * 2.0;
+
+}
+
#endif
#endif // VECTOR3_H
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index dbf6217dc2..489939ee65 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -324,6 +324,7 @@ int MessageQueue::get_max_buffer_usage() const {
void MessageQueue::flush() {
+
if (buffer_max_used<buffer_end); {
buffer_max_used=buffer_end;
//statistics();
@@ -331,9 +332,14 @@ void MessageQueue::flush() {
uint32_t read_pos=0;
- while (read_pos < buffer_end ) {
+ //using reverse locking strategy
+ _THREAD_SAFE_LOCK_
+
+ while (read_pos<buffer_end) {
+
+ _THREAD_SAFE_UNLOCK_
+
//lock on each interation, so a call can re-add itself to the message queue
- _THREAD_SAFE_LOCK_
Message *message = (Message*)&buffer[ read_pos ];
@@ -379,16 +385,17 @@ void MessageQueue::flush() {
}
- read_pos+=sizeof(Message);
+ uint32_t advance = sizeof(Message);
if (message->type!=TYPE_NOTIFICATION)
- read_pos+=sizeof(Variant)*message->args;
+ advance+=sizeof(Variant)*message->args;
message->~Message();
- _THREAD_SAFE_UNLOCK_
+ _THREAD_SAFE_LOCK_
+ read_pos+=advance;
}
- _THREAD_SAFE_LOCK_
+
buffer_end=0; // reset buffer
_THREAD_SAFE_UNLOCK_
diff --git a/core/message_queue.h b/core/message_queue.h
index 691c289813..5cee21847b 100644
--- a/core/message_queue.h
+++ b/core/message_queue.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/method_bind.cpp b/core/method_bind.cpp
index 739745f70f..ce57380434 100644
--- a/core/method_bind.cpp
+++ b/core/method_bind.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -87,7 +87,9 @@ Vector<StringName> MethodBind::get_argument_names() const {
void MethodBind::set_default_arguments(const Vector<Variant>& p_defargs) {
- default_arguments=p_defargs; default_argument_count=default_arguments.size();
+ default_arguments=p_defargs;
+ default_argument_count=default_arguments.size();
+
}
#ifdef DEBUG_METHODS_ENABLED
diff --git a/core/method_bind.h b/core/method_bind.h
index 3f08c70af8..85c1084f80 100644
--- a/core/method_bind.h
+++ b/core/method_bind.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -98,7 +98,7 @@ struct VariantCaster<m_enum> {\
#define CHECK_ARG(m_arg)\
if ((m_arg-1)<p_arg_count) {\
Variant::Type argtype=get_argument_type(m_arg-1);\
- if (!Variant::can_convert(p_args[m_arg-1]->get_type(),argtype)) {\
+ if (!Variant::can_convert_strict(p_args[m_arg-1]->get_type(),argtype)) {\
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\
r_error.argument=m_arg-1;\
r_error.expected=argtype;\
@@ -178,6 +178,7 @@ public:
#ifdef DEBUG_METHODS_ENABLED
_FORCE_INLINE_ void set_return_type(const StringName& p_type) { ret_type=p_type; }
+ _FORCE_INLINE_ StringName get_return_type() const { return ret_type; }
_FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const {
@@ -297,7 +298,7 @@ MethodBind* create_native_method_bind( Variant (T::*p_method)(const Variant**,in
// tale of an amazing hack.. //
-// if you declare an unexisting class..
+// if you declare an nonexistent class..
class __UnexistingClass;
diff --git a/core/multi_bucket_array.h b/core/multi_bucket_array.h
index a24af941f8..d85c9de583 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/object.cpp b/core/object.cpp
index b40f4ec151..f6ba76a0b5 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,6 +33,8 @@
#include "message_queue.h"
#include "core_string_names.h"
#include "translation.h"
+#include "os/os.h"
+#include "resource.h"
#ifdef DEBUG_ENABLED
@@ -256,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);
@@ -309,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)) {
@@ -321,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;
}
}
@@ -965,7 +971,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 {
@@ -994,12 +1003,44 @@ Variant Object::get_meta(const String& p_name) const {
return metadata[p_name];
}
+
Array Object::_get_property_list_bind() const {
List<PropertyInfo> lpi;
get_property_list(&lpi);
return convert_property_list(&lpi);
}
+
+Array Object::_get_method_list_bind() const {
+
+ List<MethodInfo> ml;
+ get_method_list(&ml);
+ Array ret;
+
+ 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;
+ //va.push_back(d);
+ ret.push_back(d);
+ }
+
+ return ret;
+
+}
+
DVector<String> Object::_get_meta_list_bind() const {
DVector<String> _metaret;
@@ -1033,6 +1074,13 @@ void Object::add_user_signal(const MethodInfo& p_signal) {
signal_map[p_signal.name]=s;
}
+bool Object::_has_user_signal(const StringName& p_name) const {
+
+ if (!signal_map.has(p_name))
+ return false;
+ return signal_map[p_name].user.name.length()>0;
+}
+
struct _ObjectSignalDisconnectData {
StringName signal;
@@ -1261,6 +1309,10 @@ Array Object::_get_signal_connection_list(const String& p_signal) const{
void Object::get_signal_list(List<MethodInfo> *p_signals ) const {
+ if (!script.is_null()) {
+ Ref<Script>(script)->get_script_signal_list(p_signals);
+ }
+
ObjectTypeDB::get_signal_list(get_type_name(),p_signals);
//find maybe usersignals?
const StringName *S=NULL;
@@ -1272,6 +1324,24 @@ void Object::get_signal_list(List<MethodInfo> *p_signals ) const {
p_signals->push_back(signal_map[*S].user);
}
}
+
+}
+
+
+void Object::get_all_signal_connections(List<Connection> *p_connections) const {
+
+ const StringName *S=NULL;
+
+ while((S=signal_map.next(S))) {
+
+ const Signal *s=&signal_map[*S];
+
+ for(int i=0;i<s->slot_map.size();i++) {
+
+ p_connections->push_back(s->slot_map.getv(i).conn);
+ }
+ }
+
}
void Object::get_signal_connection_list(const StringName& p_signal,List<Connection> *p_connections) const {
@@ -1286,16 +1356,20 @@ void Object::get_signal_connection_list(const StringName& p_signal,List<Connecti
}
-void Object::connect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method,const Vector<Variant>& p_binds,uint32_t p_flags) {
+Error Object::connect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method,const Vector<Variant>& p_binds,uint32_t p_flags) {
- ERR_FAIL_NULL(p_to_object);
+ ERR_FAIL_NULL_V(p_to_object,ERR_INVALID_PARAMETER);
Signal *s = signal_map.getptr(p_signal);
if (!s) {
bool signal_is_valid = ObjectTypeDB::has_signal(get_type_name(),p_signal);
+ //check in script
+ if (!signal_is_valid && !script.is_null() && Ref<Script>(script)->has_script_signal(p_signal))
+ signal_is_valid=true;
+
if (!signal_is_valid) {
- ERR_EXPLAIN("Attempt to connect to unexisting signal: "+p_signal);
- ERR_FAIL_COND(!signal_is_valid);
+ ERR_EXPLAIN("Attempt to connect nonexistent signal '"+p_signal+"' to method '"+p_to_method+"'");
+ ERR_FAIL_COND_V(!signal_is_valid,ERR_INVALID_PARAMETER);
}
signal_map[p_signal]=Signal();
s=&signal_map[p_signal];
@@ -1304,7 +1378,7 @@ void Object::connect(const StringName& p_signal, Object *p_to_object, const Stri
Signal::Target target(p_to_object->get_instance_ID(),p_to_method);
if (s->slot_map.has(target)) {
ERR_EXPLAIN("Signal '"+p_signal+"'' already connected to given method '"+p_to_method+"' in that object.");
- ERR_FAIL_COND(s->slot_map.has(target));
+ ERR_FAIL_COND_V(s->slot_map.has(target),ERR_INVALID_PARAMETER);
}
Signal::Slot slot;
@@ -1319,6 +1393,8 @@ void Object::connect(const StringName& p_signal, Object *p_to_object, const Stri
slot.conn=conn;
slot.cE=p_to_object->connections.push_back(conn);
s->slot_map[target]=slot;
+
+ return OK;
}
bool Object::is_connected(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method) const {
@@ -1329,7 +1405,11 @@ 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;
- ERR_EXPLAIN("Unexisting signal: "+p_signal);
+
+ 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);
}
@@ -1346,7 +1426,7 @@ void Object::disconnect(const StringName& p_signal, Object *p_to_object, const S
ERR_FAIL_NULL(p_to_object);
Signal *s = signal_map.getptr(p_signal);
if (!s) {
- ERR_EXPLAIN("Unexisting signal: "+p_signal);
+ ERR_EXPLAIN("Nonexistent signal: "+p_signal);
ERR_FAIL_COND(!s);
}
if (s->lock>0) {
@@ -1357,7 +1437,7 @@ void Object::disconnect(const StringName& p_signal, Object *p_to_object, const S
Signal::Target target(p_to_object->get_instance_ID(),p_to_method);
if (!s->slot_map.has(target)) {
- ERR_EXPLAIN("Disconnecting unexisting signal '"+p_signal+"', slot: "+itos(target._id)+":"+target.method);
+ ERR_EXPLAIN("Disconnecting nonexistent signal '"+p_signal+"', slot: "+itos(target._id)+":"+target.method);
ERR_FAIL();
}
int prev = p_to_object->connections.size();
@@ -1405,6 +1485,63 @@ StringName Object::tr(const StringName& p_message) const {
}
+
+void Object::_clear_internal_resource_paths(const Variant &p_var) {
+
+ switch(p_var.get_type()) {
+
+ case Variant::OBJECT: {
+
+ RES r = p_var;
+ if (!r.is_valid())
+ return;
+
+ if (!r->get_path().begins_with("res://") || r->get_path().find("::")==-1)
+ return; //not an internal resource
+
+ Object *object=p_var;
+ if (!object)
+ return;
+
+ r->set_path("");
+ r->clear_internal_resource_paths();
+ } break;
+ case Variant::ARRAY: {
+
+ Array a=p_var;
+ for(int i=0;i<a.size();i++) {
+ _clear_internal_resource_paths(a[i]);
+ }
+
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_var;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+
+ for (List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ _clear_internal_resource_paths(E->get());
+ _clear_internal_resource_paths(d[E->get()]);
+ }
+ } break;
+ }
+
+}
+
+void Object::clear_internal_resource_paths() {
+
+ List<PropertyInfo> pinfo;
+
+ get_property_list(&pinfo);
+
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+ _clear_internal_resource_paths(get(E->get().name));
+ }
+}
+
void Object::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_type"),&Object::get_type);
@@ -1412,6 +1549,7 @@ void Object::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set","property","value"),&Object::_set_bind);
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("get_instance_ID"),&Object::get_instance_ID);
@@ -1429,6 +1567,7 @@ void Object::_bind_methods() {
// ObjectTypeDB::bind_method(_MD("call_deferred","method","arg1","arg2","arg3","arg4"),&Object::_call_deferred_bind,DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()));
ObjectTypeDB::bind_method(_MD("add_user_signal","signal","arguments"),&Object::_add_user_signal,DEFVAL(Array()));
+ ObjectTypeDB::bind_method(_MD("has_user_signal","signal"),&Object::_has_user_signal);
// ObjectTypeDB::bind_method(_MD("emit_signal","signal","arguments"),&Object::_emit_signal,DEFVAL(Array()));
@@ -1487,12 +1626,16 @@ void Object::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_block_signals","enable"),&Object::set_block_signals);
ObjectTypeDB::bind_method(_MD("is_blocking_signals"),&Object::is_blocking_signals);
ObjectTypeDB::bind_method(_MD("set_message_translation","enable"),&Object::set_message_translation);
- ObjectTypeDB::bind_method(_MD("can_translate_messages"),&Object::set_message_translation);
+ ObjectTypeDB::bind_method(_MD("can_translate_messages"),&Object::can_translate_messages);
ObjectTypeDB::bind_method(_MD("property_list_changed_notify"),&Object::property_list_changed_notify);
ObjectTypeDB::bind_method(_MD("XL_MESSAGE","message"),&Object::XL_MESSAGE);
ObjectTypeDB::bind_method(_MD("tr","message"),&Object::tr);
+ ObjectTypeDB::bind_method(_MD("is_queued_for_deletion"),&Object::is_queued_for_deletion);
+
+ ObjectTypeDB::add_virtual_method("Object",MethodInfo("free"),false);
+
ADD_SIGNAL( MethodInfo("script_changed"));
BIND_VMETHOD( MethodInfo("_notification",PropertyInfo(Variant::INT,"what")) );
@@ -1503,10 +1646,12 @@ void Object::_bind_methods() {
BIND_VMETHOD( miget );
MethodInfo plget("_get_property_list");
+
plget.return_val.type=Variant::ARRAY;
BIND_VMETHOD( plget );
#endif
+ BIND_VMETHOD( MethodInfo("_init") );
@@ -1554,6 +1699,30 @@ 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;
+}
+
#ifdef TOOLS_ENABLED
void Object::set_edited(bool p_edited) {
@@ -1569,12 +1738,13 @@ bool Object::is_edited() const {
Object::Object() {
-
+ _type_ptr=NULL;
_block_signals=false;
_predelete_ok=0;
_instance_ID=0;
_instance_ID = ObjectDB::add_instance(this);
_can_translate=true;
+ _is_queued_for_deletion=false;
script_instance=NULL;
#ifdef TOOLS_ENABLED
@@ -1690,6 +1860,11 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
}
+void Object::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+
+
+}
+
int ObjectDB::get_object_count() {
GLOBAL_LOCK_FUNCTION;
@@ -1702,8 +1877,20 @@ void ObjectDB::cleanup() {
GLOBAL_LOCK_FUNCTION;
if (instances.size()) {
-
+
WARN_PRINT("ObjectDB Instances still exist!");
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ const uint32_t *K=NULL;
+ while((K=instances.next(K))) {
+
+ String node_name;
+ if (instances[*K]->is_type("Node"))
+ node_name=" - Node Name: "+String(instances[*K]->call("get_name"));
+ if (instances[*K]->is_type("Resoucre"))
+ node_name=" - Resource Name: "+String(instances[*K]->call("get_name"))+" Path: "+String(instances[*K]->call("get_path"));
+ print_line("Leaked Instance: "+String(instances[*K]->get_type())+":"+itos(*K)+node_name);
+ }
+ }
}
instances.clear();
instance_checks.clear();
diff --git a/core/object.h b/core/object.h
index 6290f9d64b..5b6361796f 100644
--- a/core/object.h
+++ b/core/object.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,20 +49,21 @@
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)
PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
+ PROPERTY_HINT_SPRITE_FRAME,
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,
@@ -70,7 +71,7 @@ enum PropertyHint {
};
enum PropertyUsageFlags {
-
+
PROPERTY_USAGE_STORAGE=1,
PROPERTY_USAGE_EDITOR=2,
PROPERTY_USAGE_NETWORK=4,
@@ -81,6 +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_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,
@@ -95,21 +98,26 @@ 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;
}
+ bool operator<(const PropertyInfo& p_info) const {
+ return name<p_info.name;
+ }
};
@@ -117,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);
@@ -150,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 \
@@ -174,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;\
@@ -306,7 +314,7 @@ private:
class ScriptInstance;
typedef uint32_t ObjectID;
-class Object {
+class Object {
public:
enum ConnectFlags {
@@ -383,8 +391,11 @@ 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;
Variant _emit_signal(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
Array _get_signal_list() const;
Array _get_signal_connection_list(const String& p_signal) const;
@@ -393,8 +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(); }
@@ -402,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;
}
@@ -421,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();
@@ -440,10 +450,17 @@ 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;
+ Array _get_method_list_bind() const;
+
+ void _clear_internal_resource_paths(const Variant &p_var);
public: //should be protected, but bug in clang++
static void initialize_type();
@@ -468,7 +485,7 @@ public:
void add_change_receptor( Object *p_receptor );
void remove_change_receptor( Object *p_receptor );
-
+
template<class T>
T *cast_to() {
@@ -483,7 +500,7 @@ public:
return NULL;
#endif
}
-
+
template<class T>
const T *cast_to() const {
@@ -500,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"); }
@@ -515,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;
@@ -529,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);
@@ -539,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;
@@ -570,8 +595,9 @@ public:
void emit_signal(const StringName& p_name,VARIANT_ARG_LIST);
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;
- void connect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method,const Vector<Variant>& p_binds=Vector<Variant>(),uint32_t p_flags=0);
+ Error connect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method,const Vector<Variant>& p_binds=Vector<Variant>(),uint32_t p_flags=0);
void disconnect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method);
bool is_connected(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method) const;
@@ -580,15 +606,24 @@ 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;
StringName XL_MESSAGE(const StringName& p_message) const; //translate message (internationalization)
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;
+
_FORCE_INLINE_ void set_message_translation(bool p_enable) { _can_translate=p_enable; }
_FORCE_INLINE_ bool can_translate_messages() const { return _can_translate; }
- Object();
+
+ void clear_internal_resource_paths();
+
+ Object();
virtual ~Object();
};
@@ -616,13 +651,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);
@@ -640,6 +675,8 @@ public:
#endif
+
+
};
//needed by macros
diff --git a/core/object_type_db.cpp b/core/object_type_db.cpp
index 18878007a6..f8ba0a9b15 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -105,10 +105,93 @@ MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,co
return md;
}
+
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6) {
+
+ MethodDefinition md;
+ md.name=StaticCString::create(p_name);
+ md.args.resize(6);
+ md.args[0]=StaticCString::create(p_arg1);
+ md.args[1]=StaticCString::create(p_arg2);
+ md.args[2]=StaticCString::create(p_arg3);
+ md.args[3]=StaticCString::create(p_arg4);
+ md.args[4]=StaticCString::create(p_arg5);
+ md.args[5]=StaticCString::create(p_arg6);
+ return md;
+}
+
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6,const char *p_arg7) {
+
+ MethodDefinition md;
+ md.name=StaticCString::create(p_name);
+ md.args.resize(7);
+ md.args[0]=StaticCString::create(p_arg1);
+ md.args[1]=StaticCString::create(p_arg2);
+ md.args[2]=StaticCString::create(p_arg3);
+ md.args[3]=StaticCString::create(p_arg4);
+ md.args[4]=StaticCString::create(p_arg5);
+ md.args[5]=StaticCString::create(p_arg6);
+ md.args[6]=StaticCString::create(p_arg7);
+ return md;
+}
+
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6,const char *p_arg7,const char *p_arg8) {
+
+ MethodDefinition md;
+ md.name=StaticCString::create(p_name);
+ md.args.resize(8);
+ md.args[0]=StaticCString::create(p_arg1);
+ md.args[1]=StaticCString::create(p_arg2);
+ md.args[2]=StaticCString::create(p_arg3);
+ md.args[3]=StaticCString::create(p_arg4);
+ md.args[4]=StaticCString::create(p_arg5);
+ md.args[5]=StaticCString::create(p_arg6);
+ md.args[6]=StaticCString::create(p_arg7);
+ md.args[7]=StaticCString::create(p_arg8);
+ return md;
+}
+
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6,const char *p_arg7,const char *p_arg8,const char *p_arg9) {
+
+ MethodDefinition md;
+ md.name=StaticCString::create(p_name);
+ md.args.resize(9);
+ md.args[0]=StaticCString::create(p_arg1);
+ md.args[1]=StaticCString::create(p_arg2);
+ md.args[2]=StaticCString::create(p_arg3);
+ md.args[3]=StaticCString::create(p_arg4);
+ md.args[4]=StaticCString::create(p_arg5);
+ md.args[5]=StaticCString::create(p_arg6);
+ md.args[6]=StaticCString::create(p_arg7);
+ md.args[7]=StaticCString::create(p_arg8);
+ md.args[8]=StaticCString::create(p_arg9);
+ return md;
+}
+
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6,const char *p_arg7,const char *p_arg8,const char *p_arg9,const char *p_arg10) {
+
+ MethodDefinition md;
+ md.name=StaticCString::create(p_name);
+ md.args.resize(10);
+ md.args[0]=StaticCString::create(p_arg1);
+ md.args[1]=StaticCString::create(p_arg2);
+ md.args[2]=StaticCString::create(p_arg3);
+ md.args[3]=StaticCString::create(p_arg4);
+ md.args[4]=StaticCString::create(p_arg5);
+ md.args[5]=StaticCString::create(p_arg6);
+ md.args[6]=StaticCString::create(p_arg7);
+ md.args[7]=StaticCString::create(p_arg8);
+ md.args[8]=StaticCString::create(p_arg9);
+ md.args[9]=StaticCString::create(p_arg10);
+ return md;
+}
+
+
#endif
HashMap<StringName,ObjectTypeDB::TypeInfo,StringNameHasher> ObjectTypeDB::types;
HashMap<StringName,StringName,StringNameHasher> ObjectTypeDB::resource_base_extensions;
+HashMap<StringName,StringName,StringNameHasher> ObjectTypeDB::compat_types;
ObjectTypeDB::TypeInfo::TypeInfo() {
@@ -122,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;
@@ -137,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;
@@ -152,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;
@@ -166,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;
@@ -175,18 +258,28 @@ 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);
}
-Object *ObjectTypeDB::instance(const String &p_type) {
+void ObjectTypeDB::add_compatibility_type(const StringName& p_type,const StringName& p_fallback) {
+
+ compat_types[p_type]=p_fallback;
+}
+
+Object *ObjectTypeDB::instance(const StringName &p_type) {
TypeInfo *ti;
{
OBJTYPE_LOCK;
ti=types.getptr(p_type);
+ if (!ti || ti->disabled || !ti->creation_func) {
+ if (compat_types.has(p_type)) {
+ ti=types.getptr(compat_types[p_type]);
+ }
+ }
ERR_FAIL_COND_V(!ti,NULL);
ERR_FAIL_COND_V(ti->disabled,NULL);
ERR_FAIL_COND_V(!ti->creation_func,NULL);
@@ -194,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;
@@ -519,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;
@@ -541,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());
@@ -550,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;
}
@@ -619,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) {
@@ -647,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;
@@ -711,24 +860,38 @@ else goto set_defvals;
}
-void ObjectTypeDB::add_virtual_method(const StringName& p_type,const MethodInfo& p_method ) {
+void ObjectTypeDB::add_virtual_method(const StringName& p_type, const MethodInfo& p_method , bool p_virtual) {
ERR_FAIL_COND(!types.has(p_type));
#ifdef DEBUG_METHODS_ENABLED
MethodInfo mi=p_method;
- mi.flags|=METHOD_FLAG_VIRTUAL;
+ if (p_virtual)
+ mi.flags|=METHOD_FLAG_VIRTUAL;
types[p_type].virtual_methods.push_back(mi);
#endif
}
-void ObjectTypeDB::get_virtual_methods(const StringName& p_type,List<MethodInfo> * p_methods ) {
+void ObjectTypeDB::get_virtual_methods(const StringName& p_type, List<MethodInfo> * p_methods , bool p_no_inheritance) {
ERR_FAIL_COND(!types.has(p_type));
#ifdef DEBUG_METHODS_ENABLED
- *p_methods=types[p_type].virtual_methods;
+
+ TypeInfo *type=types.getptr(p_type);
+ TypeInfo *check=type;
+ while(check) {
+
+ for(List<MethodInfo>::Element *E=check->virtual_methods.front();E;E=E->next()) {
+ p_methods->push_back(E->get());
+ }
+
+ if (p_no_inheritance)
+ return;
+ check=check->inherits_ptr;
+ }
+
#endif
}
@@ -741,8 +904,15 @@ void ObjectTypeDB::set_type_enabled(StringName p_type,bool p_enable) {
bool ObjectTypeDB::is_type_enabled(StringName p_type) {
- ERR_FAIL_COND_V(!types.has(p_type),false);
- return !types[p_type].disabled;
+ TypeInfo *ti=types.getptr(p_type);
+ if (!ti || !ti->creation_func) {
+ if (compat_types.has(p_type)) {
+ ti=types.getptr(compat_types[p_type]);
+ }
+ }
+
+ ERR_FAIL_COND_V(!ti,false);
+ return !ti->disabled;
}
StringName ObjectTypeDB::get_category(const StringName& p_node) {
@@ -819,6 +989,7 @@ void ObjectTypeDB::cleanup() {
}
types.clear();
resource_base_extensions.clear();
+ compat_types.clear();
}
//
diff --git a/core/object_type_db.h b/core/object_type_db.h
index 9eaec6171e..319e3ec02c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -86,6 +86,11 @@ MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2);
MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3);
MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4);
MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5);
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6);
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6,const char *p_arg7);
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6,const char *p_arg7,const char *p_arg8);
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6,const char *p_arg7,const char *p_arg8,const char *p_arg9);
+MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,const char *p_arg3,const char *p_arg4,const char *p_arg5,const char *p_arg6,const char *p_arg7,const char *p_arg8,const char *p_arg9,const char *p_arg10);
#else
@@ -112,6 +117,7 @@ class ObjectTypeDB {
StringName getter;
MethodBind *_setptr;
MethodBind *_getptr;
+ Variant::Type type;
};
struct TypeInfo {
@@ -146,6 +152,7 @@ class ObjectTypeDB {
static Mutex *lock;
static HashMap<StringName,TypeInfo,StringNameHasher> types;
static HashMap<StringName,StringName,StringNameHasher> resource_base_extensions;
+ static HashMap<StringName,StringName,StringNameHasher> compat_types;
#ifdef DEBUG_METHODS_ENABLED
static MethodBind* bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const MethodDefinition &method_name, const Variant **p_defs, int p_defcount);
@@ -222,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>
@@ -369,7 +376,7 @@ public:
return bind_methodfi(METHOD_FLAGS_DEFAULT,bind,p_method_name,ptr,4);
}
- template<class N, class M>
+ template<class N, class M>
static MethodBind* bind_method(N p_method_name, M p_method,const Variant& p_def1,const Variant& p_def2,const Variant& p_def3,const Variant& p_def4,const Variant& p_def5) {
MethodBind *bind = create_method_bind(p_method);
@@ -377,6 +384,16 @@ public:
return bind_methodfi(METHOD_FLAGS_DEFAULT,bind,p_method_name,ptr,5);
}
+
+ template<class N, class M>
+ static MethodBind* bind_method(N p_method_name, M p_method,const Variant& p_def1,const Variant& p_def2,const Variant& p_def3,const Variant& p_def4,const Variant& p_def5,const Variant& p_def6) {
+
+ MethodBind *bind = create_method_bind(p_method);
+ const Variant* ptr[6]={&p_def1,&p_def2,&p_def3,&p_def4,&p_def5,&p_def6};
+
+ return bind_methodfi(METHOD_FLAGS_DEFAULT,bind,p_method_name,ptr,6);
+ }
+
#if 0
template<class N, class M>
static MethodBind* bind_methodf(uint32_t p_flags, N p_method_name, M p_method,
@@ -440,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);
@@ -452,14 +470,16 @@ public:
static void get_method_list(StringName p_type,List<MethodInfo> *p_methods,bool p_no_inheritance=false);
static MethodBind *get_method(StringName p_type, StringName p_name);
- static void add_virtual_method(const StringName& p_type,const MethodInfo& p_method );
- static void get_virtual_methods(const StringName& p_type,List<MethodInfo> * p_methods );
+ static void add_virtual_method(const StringName& p_type,const MethodInfo& p_method,bool p_virtual=true );
+ static void get_virtual_methods(const StringName& p_type,List<MethodInfo> * p_methods,bool p_no_inheritance=false );
static void bind_integer_constant(const StringName& p_type, const StringName &p_name, int p_constant);
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);
@@ -467,6 +487,7 @@ public:
static void get_resource_base_extensions(List<String> *p_extensions);
static void get_extensions_for_type(const StringName& p_type,List<String> *p_extensions);
+ static void add_compatibility_type(const StringName& p_type,const StringName& p_fallback);
static void init();
static void cleanup();
};
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 4a36b6f6d1..54baf1e232 100644
--- a/core/os/copymem.cpp
+++ b/core/os/copymem.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/copymem.h b/core/os/copymem.h
index 09e8c6903e..a5d640edbf 100644
--- a/core/os/copymem.h
+++ b/core/os/copymem.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index 496ebdfa27..d0baae5872 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,6 +56,17 @@ String DirAccess::_get_root_string() const {
return "";
}
+int DirAccess::get_current_drive() {
+
+ String path = get_current_dir().to_lower();
+ for(int i=0;i<get_drive_count();i++) {
+ String d = get_drive(i).to_lower();
+ if (path.begins_with(d))
+ return i;
+ }
+
+ return 0;
+}
static Error _erase_recursive(DirAccess *da) {
@@ -130,35 +141,46 @@ Error DirAccess::make_dir_recursive(String p_dir) {
if (p_dir.length() < 1) {
return OK;
};
+
+ String full_dir;
Globals* g = Globals::get_singleton();
- String cur = normalize_path(g->globalize_path(get_current_dir()));
- if (cur[cur.length()-1] != '/') {
- cur = cur + "/";
- };
- String dir = normalize_path(g->globalize_path(p_dir));
- if (dir.length() < 1) {
- return OK;
- };
- if (dir[dir.length()-1] != '/') {
- dir = dir + "/";
- };
+ if (!p_dir.is_abs_path()) {
+ //append current
- ERR_FAIL_COND_V(dir.find(cur) != 0, FAILED);
+ String cur = normalize_path(g->globalize_path(get_current_dir()));
+ if (cur[cur.length()-1] != '/') {
+ cur = cur + "/";
+ };
- String rel = dir.substr(cur.length(), (dir.length() - cur.length()));
+ full_dir=(cur+"/"+p_dir).simplify_path();
+ } else {
+ //validate and use given
+ String dir = normalize_path(g->globalize_path(p_dir));
+ if (dir.length() < 1) {
+ return OK;
+ };
+ if (dir[dir.length()-1] != '/') {
+ dir = dir + "/";
+ };
+ full_dir=dir;
+ }
+
+ //int slices = full_dir.get_slice_count("/");
int pos = 0;
- while (pos < rel.length()) {
+ while (pos < full_dir.length()) {
- int n = rel.find("/", pos);
+ int n = full_dir.find("/", pos);
if (n < 0) {
- n = rel.length();
+ n = full_dir.length();
};
pos = n + 1;
if (pos > 1) {
- Error err = make_dir(rel.substr(0, pos -1));
+ String to_create = full_dir.substr(0, pos -1);
+ //print_line("MKDIR: "+to_create);
+ Error err = make_dir(to_create);
if (err != OK && err != ERR_ALREADY_EXISTS) {
ERR_FAIL_V(err);
@@ -388,6 +410,15 @@ Error DirAccess::copy(String p_from,String p_to) {
return err;
}
+bool DirAccess::exists(String p_dir) {
+
+ DirAccess* da = DirAccess::create_for_path(p_dir);
+ bool valid = da->change_dir(p_dir)==OK;
+ memdelete(da);
+ return valid;
+
+}
+
DirAccess::DirAccess(){
_access_type=ACCESS_FILESYSTEM;
diff --git a/core/os/dir_access.h b/core/os/dir_access.h
index d8672218bd..8bacc96c60 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -78,11 +78,13 @@ public:
virtual String get_next(bool* p_is_dir); // compatibility
virtual String get_next()=0;
virtual bool current_is_dir() const=0;
+ virtual bool current_is_hidden() const=0;
virtual void list_dir_end()=0; ///<
virtual int get_drive_count()=0;
virtual String get_drive(int p_drive)=0;
+ virtual int get_current_drive();
virtual Error change_dir(String p_dir)=0; ///< can be relative or absolute, return false on success
virtual String get_current_dir()=0; ///< return current dir location
@@ -92,7 +94,7 @@ public:
virtual bool file_exists(String p_file)=0;
virtual bool dir_exists(String p_dir)=0;
-
+ static bool exists(String p_dir);
virtual size_t get_space_left()=0;
virtual Error copy(String p_from,String p_to);
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index ffa0cad8e4..ef7efd27e1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/file_access.h b/core/os/file_access.h
index 793e971a4c..8e34013796 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/input.cpp b/core/os/input.cpp
index 70733aadec..15872d02fd 100644
--- a/core/os/input.cpp
+++ b/core/os/input.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,6 +29,7 @@
#include "input.h"
#include "input_map.h"
#include "os/os.h"
+#include "globals.h"
Input *Input::singleton=NULL;
Input *Input::get_singleton() {
@@ -53,268 +54,54 @@ void Input::_bind_methods() {
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("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_accelerometer"),&Input::get_accelerometer);
- ObjectTypeDB::bind_method(_MD("get_mouse_pos"),&Input::get_mouse_pos);
+ //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);
ObjectTypeDB::bind_method(_MD("get_mouse_button_mask"),&Input::get_mouse_button_mask);
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("set_custom_mouse_cursor","image:Texture","hotspot"),&Input::set_custom_mouse_cursor,DEFVAL(Vector2()));
BIND_CONSTANT( MOUSE_MODE_VISIBLE );
BIND_CONSTANT( MOUSE_MODE_HIDDEN );
BIND_CONSTANT( MOUSE_MODE_CAPTURED );
+ ADD_SIGNAL( MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")) );
}
-Input::Input() {
-
- singleton=this;
-}
-
-
-//////////////////////////////////////////////////////////
-
-
-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();
-}
+void Input::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+#ifdef TOOLS_ENABLED
-bool InputDefault::is_key_pressed(int p_scancode) {
+ String pf=p_function;
+ if (p_idx==0 && (pf=="is_action_pressed" || pf=="action_press" || pf=="action_release")) {
- _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
+ List<PropertyInfo> pinfo;
+ Globals::get_singleton()->get_property_list(&pinfo);
- const List<InputEvent> *alist = InputMap::get_singleton()->get_action_list(p_action);
- if (!alist)
- return NULL;
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ const PropertyInfo &pi=E->get();
+ if (!pi.name.begins_with("input/"))
+ continue;
- for (const List<InputEvent>::Element *E=alist->front();E;E=E->next()) {
+ String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
+ r_options->push_back("\""+name+"\"");
-
- 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;
}
}
+#endif
- 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;
- }
-}
-
-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::iteration(float p_step) {
-
-
-}
-
-void InputDefault::action_press(const StringName& p_action) {
-
- if (custom_action_press.has(p_action)) {
+Input::Input() {
- custom_action_press[p_action]++;
- } else {
- custom_action_press[p_action]=1;
- }
+ singleton=this;
}
-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 cc51dbf42f..8aa0e6b18a 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -61,82 +61,32 @@ public:
virtual bool is_action_pressed(const StringName& p_action)=0;
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 Point2 get_mouse_pos() const=0;
virtual Point2 get_mouse_speed() const=0;
virtual int get_mouse_button_mask() const=0;
+ virtual void warp_mouse_pos(const Vector2& p_to)=0;
+
virtual Vector3 get_accelerometer()=0;
virtual void action_press(const StringName& p_action)=0;
virtual void action_release(const StringName& p_action)=0;
- Input();
-};
-
-VARIANT_ENUM_CAST(Input::MouseMode);
-
-class InputDefault : public Input {
+ void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
- OBJ_TYPE( InputDefault, Input );
- _THREAD_SAFE_CLASS_
+ virtual bool is_emulating_touchscreen() const=0;
- 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;
-
- 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 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);
- 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);
-
- virtual Vector3 get_accelerometer();
-
- virtual Point2 get_mouse_pos() const;
- virtual Point2 get_mouse_speed() const;
- virtual int get_mouse_button_mask() const;
-
- 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 499ec0c08e..2bd62927b0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -141,11 +141,11 @@ InputEvent::operator String() const {
return "";
}
-void InputEvent::set_as_action(const String& p_action) {
+void InputEvent::set_as_action(const String& p_action, bool p_pressed) {
type=ACTION;
action.action=InputMap::get_singleton()->get_action_id(p_action);
- action.pressed=false;
+ action.pressed=p_pressed;
}
bool InputEvent::is_pressed() const {
@@ -173,6 +173,16 @@ bool InputEvent::is_action(const String& p_action) const {
return InputMap::get_singleton()->event_is_action(*this,p_action);
}
+bool InputEvent::is_action_pressed(const String& p_action) const {
+
+ return is_action(p_action) && is_pressed() && !is_echo();
+}
+
+bool InputEvent::is_action_released(const String& p_action) const {
+
+ return is_action(p_action) && !is_pressed();
+}
+
uint32_t InputEventKey::get_scancode_with_modifiers() const {
uint32_t sc=scancode;
diff --git a/core/os/input_event.h b/core/os/input_event.h
index 2c10bffcd2..4bb122ebc1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -287,8 +287,10 @@ struct InputEvent {
bool is_pressed() const;
bool is_action(const String& p_action) const;
+ bool is_action_pressed(const String& p_action) const;
+ bool is_action_released(const String& p_action) const;
bool is_echo() const;
- void set_as_action(const String& p_action);
+ void set_as_action(const String& p_action, bool p_pressed);
bool operator==(const InputEvent &p_event) const;
operator String() const;
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index a4201c34ea..10e64c3961 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "keyboard.h"
-
+#include "os/os.h"
struct _KeyCodeText {
int code;
@@ -353,3 +353,106 @@ int find_keycode(const String& p_code) {
return 0;
}
+
+
+
+
+struct _KeyCodeReplace {
+ int from;
+ int to;
+};
+
+static const _KeyCodeReplace _keycode_replace_qwertz[]={
+{KEY_Y,KEY_Z},
+{KEY_Z,KEY_Y},
+{0,0}
+};
+
+static const _KeyCodeReplace _keycode_replace_azerty[]={
+{KEY_W,KEY_Z},
+{KEY_Z,KEY_W},
+{KEY_A,KEY_Q},
+{KEY_Q,KEY_A},
+{KEY_SEMICOLON,KEY_M},
+{KEY_M,KEY_SEMICOLON},
+{0,0}
+};
+
+static const _KeyCodeReplace _keycode_replace_qzerty[]={
+{KEY_W,KEY_Z},
+{KEY_Z,KEY_W},
+{KEY_SEMICOLON,KEY_M},
+{KEY_M,KEY_SEMICOLON},
+{0,0}
+};
+
+static const _KeyCodeReplace _keycode_replace_dvorak[]={
+{KEY_UNDERSCORE,KEY_BRACELEFT},
+{KEY_EQUAL,KEY_BRACERIGHT},
+{KEY_Q,KEY_APOSTROPHE},
+{KEY_W,KEY_COMMA},
+{KEY_E,KEY_PERIOD},
+{KEY_R,KEY_P},
+{KEY_T,KEY_Y},
+{KEY_Y,KEY_F},
+{KEY_U,KEY_G},
+{KEY_I,KEY_C},
+{KEY_O,KEY_R},
+{KEY_P,KEY_L},
+{KEY_BRACELEFT,KEY_SLASH},
+{KEY_BRACERIGHT,KEY_EQUAL},
+{KEY_A,KEY_A},
+{KEY_S,KEY_O},
+{KEY_D,KEY_E},
+{KEY_F,KEY_U},
+{KEY_G,KEY_I},
+{KEY_H,KEY_D},
+{KEY_J,KEY_H},
+{KEY_K,KEY_T},
+{KEY_L,KEY_N},
+{KEY_SEMICOLON,KEY_S},
+{KEY_APOSTROPHE,KEY_UNDERSCORE},
+{KEY_Z,KEY_SEMICOLON},
+{KEY_X,KEY_Q},
+{KEY_C,KEY_J},
+{KEY_V,KEY_K},
+{KEY_B,KEY_X},
+{KEY_N,KEY_B},
+{KEY_M,KEY_M},
+{KEY_COMMA,KEY_W},
+{KEY_PERIOD,KEY_V},
+{KEY_SLASH,KEY_Z},
+{0,0}
+};
+
+static const _KeyCodeReplace _keycode_replace_neo[]={
+{0,0}
+};
+
+
+int latin_keyboard_keycode_convert(int p_keycode) {
+
+ const _KeyCodeReplace *kcr=NULL;
+ switch(OS::get_singleton()->get_latin_keyboard_variant()) {
+
+ case OS::LATIN_KEYBOARD_QWERTY: return p_keycode; break;
+ case OS::LATIN_KEYBOARD_QWERTZ: kcr=_keycode_replace_qwertz; break;
+ case OS::LATIN_KEYBOARD_AZERTY: kcr=_keycode_replace_azerty; break;
+ case OS::LATIN_KEYBOARD_QZERTY: kcr=_keycode_replace_qzerty; break;
+ case OS::LATIN_KEYBOARD_DVORAK: kcr=_keycode_replace_dvorak; break;
+ case OS::LATIN_KEYBOARD_NEO: kcr=_keycode_replace_neo; break;
+ default: return p_keycode;
+ }
+
+ if (!kcr) {
+ return p_keycode;
+ }
+
+ while(kcr->from) {
+ if (kcr->from==p_keycode)
+ return kcr->to;
+ kcr++;
+ }
+
+ return p_keycode;
+}
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 18b56b5830..eaf656dd4d 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -328,5 +328,6 @@ enum KeyModifierMask {
String keycode_get_string(uint32_t p_code);
bool keycode_has_unicode(uint32_t p_unicode);
int find_keycode(const String& p_code);
+int latin_keyboard_keycode_convert(int p_keycode);
#endif
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index d01331a256..c37c281fb9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,8 +31,22 @@
void MainLoop::_bind_methods() {
- ObjectTypeDB::bind_method("input_event",&MainLoop::input_event);
-
+ ObjectTypeDB::bind_method(_MD("input_event","ev"),&MainLoop::input_event);
+ ObjectTypeDB::bind_method(_MD("input_text","text"),&MainLoop::input_text);
+ ObjectTypeDB::bind_method(_MD("init"),&MainLoop::init);
+ ObjectTypeDB::bind_method(_MD("iteration","delta"),&MainLoop::iteration);
+ ObjectTypeDB::bind_method(_MD("idle","delta"),&MainLoop::idle);
+ ObjectTypeDB::bind_method(_MD("finish"),&MainLoop::finish);
+
+ BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"ev")) );
+ BIND_VMETHOD( MethodInfo("_input_text",PropertyInfo(Variant::STRING,"text")) );
+ BIND_VMETHOD( MethodInfo("_initialize") );
+ BIND_VMETHOD( MethodInfo("_iteration",PropertyInfo(Variant::REAL,"delta")) );
+ 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);
@@ -58,13 +72,15 @@ MainLoop::~MainLoop()
void MainLoop::input_text( const String& p_text ) {
+ if (get_script_instance())
+ get_script_instance()->call("_input_text",p_text);
}
void MainLoop::input_event( const InputEvent& p_event ) {
if (get_script_instance())
- get_script_instance()->call("input_event",p_event);
+ get_script_instance()->call("_input_event",p_event);
}
@@ -74,13 +90,13 @@ void MainLoop::init() {
set_script(init_script.get_ref_ptr());
if (get_script_instance())
- get_script_instance()->call("init");
+ get_script_instance()->call("_initialize");
}
bool MainLoop::iteration(float p_time) {
if (get_script_instance())
- return get_script_instance()->call("iteration",p_time);
+ return get_script_instance()->call("_iteration",p_time);
return false;
@@ -88,14 +104,14 @@ bool MainLoop::iteration(float p_time) {
bool MainLoop::idle(float p_time) {
if (get_script_instance())
- return get_script_instance()->call("idle",p_time);
+ return get_script_instance()->call("_idle",p_time);
return false;
}
void MainLoop::finish() {
if (get_script_instance()) {
- get_script_instance()->call("finish");
+ get_script_instance()->call("_finalize");
set_script(RefPtr()); //clear script
}
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index 6eb5881175..c5d58120c5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 ca5bacf9cd..1d9ac4e302 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -112,13 +112,6 @@ size_t Memory::get_dynamic_mem_usage() {
return MemoryPoolDynamic::get_singleton()->get_total_usage();
}
-void * operator new(size_t p_size,void *p_pointer,size_t check, const char *p_description) {
-
- void *failptr=0;
- ERR_FAIL_COND_V( check < p_size , failptr); /** bug, or strange compiler, most likely */
-
- return p_pointer;
-}
diff --git a/core/os/memory.h b/core/os/memory.h
index 6fc3d8f3eb..0a35c93fdb 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -236,11 +236,11 @@ void * operator new(size_t p_size,void *p_pointer,size_t check, const char *p_de
#endif
-_FORCE_INLINE_ void postinitialize_handler(void *) {}
+_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
template<class T>
-_FORCE_INLINE_ T *_post_initialize(T *p_obj) {
+_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
postinitialize_handler(p_obj);
return p_obj;
@@ -249,19 +249,26 @@ _FORCE_INLINE_ T *_post_initialize(T *p_obj) {
#ifdef DEBUG_MEMORY_ENABLED
#define memnew(m_class) _post_initialize(new(__FILE__":"__STR(__LINE__)", memnew type: "__STR(m_class)) m_class)
-#define memnew_placement(m_placement,m_class) _post_initialize(new(m_placement,sizeof(m_class),__FILE__":"__STR(__LINE__)", type: "__STR(m_class)) m_class)
#else
#define memnew(m_class) _post_initialize(new("") m_class)
-#define memnew_placement(m_placement,m_class) _post_initialize(new(m_placement,sizeof(m_class),"") m_class)
#endif
+_ALWAYS_INLINE_ void * operator new(size_t p_size,void *p_pointer,size_t check, const char *p_description) {
+// void *failptr=0;
+// ERR_FAIL_COND_V( check < p_size , failptr); /** bug, or strange compiler, most likely */
+
+ return p_pointer;
+}
+
+
#define memnew_allocator(m_class,m_allocator) _post_initialize(new(m_allocator::alloc) m_class)
+#define memnew_placement(m_placement,m_class) _post_initialize(new(m_placement,sizeof(m_class),"") m_class)
-_FORCE_INLINE_ bool predelete_handler(void *) { return true; }
+_ALWAYS_INLINE_ bool predelete_handler(void *) { return true; }
template<class T>
void memdelete(T *p_class) {
diff --git a/core/os/memory_pool_dynamic.cpp b/core/os/memory_pool_dynamic.cpp
index 4df554f18d..d1c41aff84 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/memory_pool_dynamic.h b/core/os/memory_pool_dynamic.h
index ca517daf41..00999ee24d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/memory_pool_dynamic_prealloc.cpp b/core/os/memory_pool_dynamic_prealloc.cpp
index c5823366c1..c7c25f32d1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,91 +26,91 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "memory_pool_dynamic_prealloc.h"
-#include "os/memory.h"
-
-#include "print_string.h"
-MemoryPoolDynamicPrealloc::ID MemoryPoolDynamicPrealloc::alloc(size_t p_amount,const char* p_description) {
-
-
-// print_line("dynpool - allocating: "+itos(p_amount));
- ID id = pool_alloc->alloc(p_amount);
-// print_line("dynpool - free: "+itos(pool_alloc->get_free_mem()));
- return id;
-
-}
-
-void MemoryPoolDynamicPrealloc::free(ID p_id) {
-
- pool_alloc->free(p_id);
-}
-
-Error MemoryPoolDynamicPrealloc::realloc(ID p_id, size_t p_amount) {
-
- return pool_alloc->resize(p_id,p_amount);
-}
-
-bool MemoryPoolDynamicPrealloc::is_valid(ID p_id) {
-
- return true;
-}
-
-size_t MemoryPoolDynamicPrealloc::get_size(ID p_id) const {
-
- return pool_alloc->get_size(p_id);
-}
-
-const char* MemoryPoolDynamicPrealloc::get_description(ID p_id) const {
-
- return "";
-}
-
-Error MemoryPoolDynamicPrealloc::lock(ID p_id) {
-
-// print_line("lock: "+itos(p_id));
- return pool_alloc->lock(p_id);
-}
-
-void * MemoryPoolDynamicPrealloc::get(ID p_ID) {
-
-// print_line("get: "+itos(p_ID));
- return pool_alloc->get(p_ID);
-}
-
-Error MemoryPoolDynamicPrealloc::unlock(ID p_id) {
-
-// print_line("unlock: "+itos(p_id));
- pool_alloc->unlock(p_id);
- return OK;
-}
-
-bool MemoryPoolDynamicPrealloc::is_locked(ID p_id) const {
-
- return pool_alloc->is_locked(p_id);
-}
-
-
-size_t MemoryPoolDynamicPrealloc::get_available_mem() const {
-
- return pool_alloc->get_free_mem();
-}
-
-size_t MemoryPoolDynamicPrealloc::get_total_usage() const {
-
- return pool_alloc->get_used_mem();
-}
-
-
-
-MemoryPoolDynamicPrealloc::MemoryPoolDynamicPrealloc(void * p_mem,int p_size, int p_align, int p_max_entries) {
-
- pool_alloc = memnew( PoolAllocator(p_mem,p_size,p_align,true,p_max_entries));
-
-}
-
-MemoryPoolDynamicPrealloc::~MemoryPoolDynamicPrealloc() {
-
-
- memdelete( pool_alloc );
-}
-
+#include "memory_pool_dynamic_prealloc.h"
+#include "os/memory.h"
+
+#include "print_string.h"
+MemoryPoolDynamicPrealloc::ID MemoryPoolDynamicPrealloc::alloc(size_t p_amount,const char* p_description) {
+
+
+// print_line("dynpool - allocating: "+itos(p_amount));
+ ID id = pool_alloc->alloc(p_amount);
+// print_line("dynpool - free: "+itos(pool_alloc->get_free_mem()));
+ return id;
+
+}
+
+void MemoryPoolDynamicPrealloc::free(ID p_id) {
+
+ pool_alloc->free(p_id);
+}
+
+Error MemoryPoolDynamicPrealloc::realloc(ID p_id, size_t p_amount) {
+
+ return pool_alloc->resize(p_id,p_amount);
+}
+
+bool MemoryPoolDynamicPrealloc::is_valid(ID p_id) {
+
+ return true;
+}
+
+size_t MemoryPoolDynamicPrealloc::get_size(ID p_id) const {
+
+ return pool_alloc->get_size(p_id);
+}
+
+const char* MemoryPoolDynamicPrealloc::get_description(ID p_id) const {
+
+ return "";
+}
+
+Error MemoryPoolDynamicPrealloc::lock(ID p_id) {
+
+// print_line("lock: "+itos(p_id));
+ return pool_alloc->lock(p_id);
+}
+
+void * MemoryPoolDynamicPrealloc::get(ID p_ID) {
+
+// print_line("get: "+itos(p_ID));
+ return pool_alloc->get(p_ID);
+}
+
+Error MemoryPoolDynamicPrealloc::unlock(ID p_id) {
+
+// print_line("unlock: "+itos(p_id));
+ pool_alloc->unlock(p_id);
+ return OK;
+}
+
+bool MemoryPoolDynamicPrealloc::is_locked(ID p_id) const {
+
+ return pool_alloc->is_locked(p_id);
+}
+
+
+size_t MemoryPoolDynamicPrealloc::get_available_mem() const {
+
+ return pool_alloc->get_free_mem();
+}
+
+size_t MemoryPoolDynamicPrealloc::get_total_usage() const {
+
+ return pool_alloc->get_used_mem();
+}
+
+
+
+MemoryPoolDynamicPrealloc::MemoryPoolDynamicPrealloc(void * p_mem,int p_size, int p_align, int p_max_entries) {
+
+ pool_alloc = memnew( PoolAllocator(p_mem,p_size,p_align,true,p_max_entries));
+
+}
+
+MemoryPoolDynamicPrealloc::~MemoryPoolDynamicPrealloc() {
+
+
+ memdelete( pool_alloc );
+}
+
diff --git a/core/os/memory_pool_dynamic_prealloc.h b/core/os/memory_pool_dynamic_prealloc.h
index 698885561a..3523079bac 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,35 +26,35 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef MEMORY_POOL_DYNAMIC_PREALLOC_H
-#define MEMORY_POOL_DYNAMIC_PREALLOC_H
-
-#include "pool_allocator.h"
-#include "core/os/memory_pool_dynamic.h"
-
-class MemoryPoolDynamicPrealloc : public MemoryPoolDynamic {
-
- PoolAllocator *pool_alloc;
-
-public:
-
- virtual ID alloc(size_t p_amount,const char* p_description);
- virtual void free(ID p_id);
- virtual Error realloc(ID p_id, size_t p_amount);
- virtual bool is_valid(ID p_id);
- virtual size_t get_size(ID p_id) const;
- virtual const char* get_description(ID p_id) const;
-
- virtual Error lock(ID p_id);
- virtual void * get(ID p_ID);
- virtual Error unlock(ID p_id);
- virtual bool is_locked(ID p_id) const;
-
- virtual size_t get_available_mem() const;
- virtual size_t get_total_usage() const;
-
- MemoryPoolDynamicPrealloc(void * p_mem,int p_size, int p_align = 16, int p_max_entries=PoolAllocator::DEFAULT_MAX_ALLOCS);
- ~MemoryPoolDynamicPrealloc();
-};
-
-#endif // MEMORY_POOL_DYNAMIC_PREALLOC_H
+#ifndef MEMORY_POOL_DYNAMIC_PREALLOC_H
+#define MEMORY_POOL_DYNAMIC_PREALLOC_H
+
+#include "pool_allocator.h"
+#include "core/os/memory_pool_dynamic.h"
+
+class MemoryPoolDynamicPrealloc : public MemoryPoolDynamic {
+
+ PoolAllocator *pool_alloc;
+
+public:
+
+ virtual ID alloc(size_t p_amount,const char* p_description);
+ virtual void free(ID p_id);
+ virtual Error realloc(ID p_id, size_t p_amount);
+ virtual bool is_valid(ID p_id);
+ virtual size_t get_size(ID p_id) const;
+ virtual const char* get_description(ID p_id) const;
+
+ virtual Error lock(ID p_id);
+ virtual void * get(ID p_ID);
+ virtual Error unlock(ID p_id);
+ virtual bool is_locked(ID p_id) const;
+
+ virtual size_t get_available_mem() const;
+ virtual size_t get_total_usage() const;
+
+ MemoryPoolDynamicPrealloc(void * p_mem,int p_size, int p_align = 16, int p_max_entries=PoolAllocator::DEFAULT_MAX_ALLOCS);
+ ~MemoryPoolDynamicPrealloc();
+};
+
+#endif // MEMORY_POOL_DYNAMIC_PREALLOC_H
diff --git a/core/os/memory_pool_dynamic_static.cpp b/core/os/memory_pool_dynamic_static.cpp
index 93f94d7726..029ef450cd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/memory_pool_dynamic_static.h b/core/os/memory_pool_dynamic_static.h
index d10cdb3d0a..a870f3070c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/memory_pool_static.cpp b/core/os/memory_pool_static.cpp
index 9dd5baf4e4..d3617eac73 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/memory_pool_static.h b/core/os/memory_pool_static.h
index f2b372d03b..40bd1aaf0e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/mutex.cpp b/core/os/mutex.cpp
index 03d423ae04..be984c080b 100644
--- a/core/os/mutex.cpp
+++ b/core/os/mutex.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/mutex.h b/core/os/mutex.h
index 241d70e232..ac6d36d635 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 11290409d5..8caf95e4d1 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,7 @@
#include <stdarg.h>
#include "dir_access.h"
#include "globals.h"
-
+#include "input.h"
OS* OS::singleton=NULL;
@@ -43,11 +43,16 @@ OS* OS::get_singleton() {
uint32_t OS::get_ticks_msec() const
{ return get_ticks_usec()/1000; }
+uint64_t OS::get_splash_tick_msec() const {
+ return _msec_splash;
+}
uint64_t OS::get_unix_time() const {
return 0;
};
-
+uint64_t OS::get_system_time_msec() const {
+ return 0;
+}
void OS::debug_break() {
// something
@@ -56,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, ...) {
@@ -280,6 +292,12 @@ String OS::get_resource_dir() const {
return Globals::get_singleton()->get_resource_path();
}
+
+String OS::get_system_dir(SystemDir p_dir) const {
+
+ return ".";
+}
+
String OS::get_data_dir() const {
return ".";
@@ -352,7 +370,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 {
@@ -386,7 +404,7 @@ void OS::_ensure_data_dir() {
}
da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- Error err = da->make_dir(dd);
+ Error err = da->make_dir_recursive(dd);
if (err!=OK) {
ERR_EXPLAIN("Error attempting to create data dir: "+dd);
}
@@ -438,7 +456,7 @@ int OS::get_processor_count() const {
return 1;
}
-Error OS::native_video_play(String p_path, float p_volume) {
+Error OS::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
return FAILED;
};
@@ -474,6 +492,21 @@ OS::MouseMode OS::get_mouse_mode() const{
return MOUSE_MODE_VISIBLE;
}
+void OS::set_time_scale(float p_scale) {
+
+ _time_scale=p_scale;
+}
+
+OS::LatinKeyboardVariant OS::get_latin_keyboard_variant() const {
+
+ return LATIN_KEYBOARD_QWERTY;
+}
+
+float OS::get_time_scale() const {
+
+ return _time_scale;
+}
+
OS::OS() {
last_error=NULL;
@@ -489,6 +522,8 @@ OS::OS() {
_fps=1;
_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 24e2b4f2d4..e908177df7 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,6 +34,7 @@
#include "vector.h"
#include "os/main_loop.h"
#include <stdarg.h>
+
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -50,11 +51,14 @@ class OS {
String _local_clipboard;
uint64_t frames_drawn;
uint32_t _frame_delay;
+ uint64_t _msec_splash;
bool _no_window;
int _exit_code;
int _orientation;
float _fps;
int _target_fps;
+ float _time_scale;
+ bool _pixel_snap;
char *last_error;
@@ -71,7 +75,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=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; }
};
protected:
friend class Main;
@@ -136,6 +140,7 @@ public:
virtual MouseMode get_mouse_mode() const;
+ virtual void warp_mouse_pos(const Point2& p_to) {}
virtual Point2 get_mouse_pos() const=0;
virtual int get_mouse_button_state() const=0;
virtual void set_window_title(const String& p_title)=0;
@@ -146,7 +151,27 @@ public:
virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0)=0;
virtual VideoMode get_video_mode(int p_screen=0) const=0;
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const=0;
-
+
+
+ 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) 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) {}
+ virtual Size2 get_window_size() const=0;
+ virtual void set_window_size(const Size2 p_size){}
+ virtual void set_window_fullscreen(bool p_enabled) {}
+ virtual bool is_window_fullscreen() const { return true; }
+ virtual void set_window_resizable(bool p_enabled) {}
+ virtual bool is_window_resizable() const { return false; }
+ virtual void set_window_minimized(bool p_enabled) {}
+ virtual bool is_window_minimized() const { return false; }
+ virtual void set_window_maximized(bool p_enabled) {}
+ virtual bool is_window_maximized() const { return true; }
+
+
virtual void set_iterations_per_second(int p_ips);
virtual int get_iterations_per_second() const;
@@ -159,6 +184,7 @@ public:
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;
@@ -220,14 +246,22 @@ public:
int min;
int sec;
};
-
- virtual Date get_date() const=0;
- virtual Time get_time() const=0;
+
+ struct TimeZoneInfo {
+ int bias;
+ String name;
+ };
+
+ virtual Date get_date(bool local=false) const=0;
+ 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_msec() const;
virtual void delay_usec(uint32_t p_usec) const=0;
virtual uint64_t get_ticks_usec() const=0;
uint32_t get_ticks_msec() const;
+ uint64_t get_splash_tick_msec() const;
void set_frame_delay(uint32_t p_msec);
uint32_t get_frame_delay() const;
@@ -284,6 +318,20 @@ public:
virtual String get_data_dir() const;
virtual String get_resource_dir() const;
+ enum SystemDir {
+ SYSTEM_DIR_DESKTOP,
+ SYSTEM_DIR_DCIM,
+ SYSTEM_DIR_DOCUMENTS,
+ SYSTEM_DIR_DOWNLOADS,
+ SYSTEM_DIR_MOVIES,
+ SYSTEM_DIR_MUSIC,
+ SYSTEM_DIR_PICTURES,
+ SYSTEM_DIR_RINGTONES,
+ };
+
+ virtual String get_system_dir(SystemDir p_dir) const;
+
+
virtual void set_no_window_mode(bool p_enable);
virtual bool is_no_window_mode_enabled() const;
@@ -321,7 +369,7 @@ public:
virtual String get_unique_ID() const;
- virtual Error native_video_play(String p_path, float p_volume);
+ virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
virtual bool native_video_is_playing() const;
virtual void native_video_pause();
virtual void native_video_stop();
@@ -331,6 +379,24 @@ public:
virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, Object* p_obj, String p_callback);
virtual Error dialog_input_text(String p_title, String p_description, String p_partial, Object* p_obj, String p_callback);
+
+ enum LatinKeyboardVariant {
+ LATIN_KEYBOARD_QWERTY,
+ LATIN_KEYBOARD_QWERTZ,
+ LATIN_KEYBOARD_AZERTY,
+ LATIN_KEYBOARD_QZERTY,
+ LATIN_KEYBOARD_DVORAK,
+ LATIN_KEYBOARD_NEO,
+ };
+
+
+ virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
+ void set_time_scale(float p_scale);
+ float get_time_scale() const;
+
+ _FORCE_INLINE_ bool get_use_pixel_snap() const { return _pixel_snap; }
+
OS();
virtual ~OS();
diff --git a/core/os/pc_joystick_map.h b/core/os/pc_joystick_map.h
index 171723439b..111dc9b3a8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/semaphore.cpp b/core/os/semaphore.cpp
index 3abab34886..8cb431d2cc 100644
--- a/core/os/semaphore.cpp
+++ b/core/os/semaphore.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/semaphore.h b/core/os/semaphore.h
index b188f07399..e8ad9d3c3a 100644
--- a/core/os/semaphore.h
+++ b/core/os/semaphore.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/shell.cpp b/core/os/shell.cpp
index 565929eae5..3746dc6804 100644
--- a/core/os/shell.cpp
+++ b/core/os/shell.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/shell.h b/core/os/shell.h
index 38b29c6eca..7ef5abbdef 100644
--- a/core/os/shell.h
+++ b/core/os/shell.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index d8d9f3e291..96b0f561ca 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/thread.h b/core/os/thread.h
index 864fc6db05..590fee1fc6 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/thread_dummy.cpp b/core/os/thread_dummy.cpp
index 1974bf615b..4e139f6379 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/thread_dummy.h b/core/os/thread_dummy.h
index b681005fb6..a83e42ff98 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/thread_safe.cpp b/core/os/thread_safe.cpp
index 9c7648be94..9a20db6a9d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/os/thread_safe.h b/core/os/thread_safe.h
index 8b20c31cc9..62d2181279 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp
index 65a6433912..fa17e93aa8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/packed_data_container.h b/core/packed_data_container.h
index b223d3bcfe..f4152bbb4d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/pair.cpp b/core/pair.cpp
index 4b6f350351..17076bb379 100644
--- a/core/pair.cpp
+++ b/core/pair.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/pair.h b/core/pair.h
index d4cf3630ee..83fc837fff 100644
--- a/core/pair.h
+++ b/core/pair.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/path_db.cpp b/core/path_db.cpp
index 1027ce7318..c6ea25d966 100644
--- a/core/path_db.cpp
+++ b/core/path_db.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 561dc01672..de84216006 100644
--- a/core/path_db.h
+++ b/core/path_db.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 34675c4575..2ef39470a0 100644
--- a/core/path_remap.cpp
+++ b/core/path_remap.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,163 +26,163 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "path_remap.h"
-#include "globals.h"
-#include "os/os.h"
-#include "translation.h"
-PathRemap* PathRemap::singleton=NULL;
-
-PathRemap* PathRemap::get_singleton() {
-
- return singleton;
-}
-
-void PathRemap::add_remap(const String& p_from, const String& p_to,const String& p_locale) {
-
- if (!remap.has(p_from)) {
- remap[p_from]=RemapData();
- }
-
- if (p_locale==String())
- remap[p_from].always=p_to;
- else
- remap[p_from].locale[p_locale]=p_to;
-}
-
-
-String PathRemap::get_remap(const String& p_from) const {
-
- const RemapData *ptr=remap.getptr(p_from);
- if (!ptr) {
- if (OS::get_singleton()->is_stdout_verbose())
- print_line("remap failed: "+p_from);
- return p_from;
- } else {
-
- String locale = TranslationServer::get_singleton()->get_locale();
-
- if (ptr->locale.has(locale)) {
- if (OS::get_singleton()->is_stdout_verbose())
- print_line("remap found: "+p_from+" -> "+ptr->locale[locale]);
- return ptr->locale[locale];
- }
-
- int p = locale.find("_");
- if (p!=-1) {
- locale=locale.substr(0,p);
- if (ptr->locale.has(locale)) {
- if (OS::get_singleton()->is_stdout_verbose())
- print_line("remap found: "+p_from+" -> "+ptr->locale[locale]);
- return ptr->locale[locale];
- }
- }
-
- if (ptr->always!=String()) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("remap found: "+p_from+" -> "+ptr->always);
- }
- return ptr->always;
- }
-
- if (OS::get_singleton()->is_stdout_verbose())
- print_line("remap failed: "+p_from);
-
- return p_from;
- }
-}
-bool PathRemap::has_remap(const String& p_from) const{
-
- return remap.has(p_from);
-}
-
-void PathRemap::erase_remap(const String& p_from){
-
- ERR_FAIL_COND(!remap.has(p_from));
- remap.erase(p_from);
-}
-
-void PathRemap::clear_remaps() {
-
- remap.clear();
-}
-
-void PathRemap::load_remaps() {
-
- // default remaps first
- DVector<String> remaps = Globals::get_singleton()->get("remap/all");
-
- {
- int rlen = remaps.size();
-
- ERR_FAIL_COND( rlen%2 );
- DVector<String>::Read r = remaps.read();
- for(int i=0;i<rlen/2;i++) {
-
- String from = r[i*2+0];
- String to = r[i*2+1];
- add_remap(from,to);
- }
- }
-
-
- // platform remaps second, so override
- remaps = Globals::get_singleton()->get("remap/"+OS::get_singleton()->get_name());
-// remaps = Globals::get_singleton()->get("remap/PSP");
- {
- int rlen = remaps.size();
-
- ERR_FAIL_COND( rlen%2 );
- DVector<String>::Read r = remaps.read();
- for(int i=0;i<rlen/2;i++) {
-
- String from = r[i*2+0];
- String to = r[i*2+1];
-// print_line("add remap: "+from+" -> "+to);
- add_remap(from,to);
- }
- }
-
-
- //locale based remaps
-
- if (Globals::get_singleton()->has("locale/translation_remaps")) {
-
- Dictionary remaps = Globals::get_singleton()->get("locale/translation_remaps");
- List<Variant> rk;
- remaps.get_key_list(&rk);
- for(List<Variant>::Element *E=rk.front();E;E=E->next()) {
-
- String source = E->get();
- StringArray sa = remaps[E->get()];
- int sas = sa.size();
- StringArray::Read r = sa.read();
-
- for(int i=0;i<sas;i++) {
-
- String s = r[i];
- int qp = s.find_last(":");
- if (qp!=-1) {
- String path = s.substr(0,qp);
- String locale = s.substr(qp+1,s.length());
- add_remap(source,path,locale);
- }
- }
- }
-
- }
-
-}
-
-void PathRemap::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("add_remap","from","to","locale"),&PathRemap::add_remap,DEFVAL(String()));
- ObjectTypeDB::bind_method(_MD("has_remap","path"),&PathRemap::has_remap);
- ObjectTypeDB::bind_method(_MD("get_remap","path"),&PathRemap::get_remap);
- ObjectTypeDB::bind_method(_MD("erase_remap","path"),&PathRemap::erase_remap);
- ObjectTypeDB::bind_method(_MD("clear_remaps"),&PathRemap::clear_remaps);
-}
-
-PathRemap::PathRemap() {
-
- singleton=this;
-}
+#include "path_remap.h"
+#include "globals.h"
+#include "os/os.h"
+#include "translation.h"
+PathRemap* PathRemap::singleton=NULL;
+
+PathRemap* PathRemap::get_singleton() {
+
+ return singleton;
+}
+
+void PathRemap::add_remap(const String& p_from, const String& p_to,const String& p_locale) {
+
+ if (!remap.has(p_from)) {
+ remap[p_from]=RemapData();
+ }
+
+ if (p_locale==String())
+ remap[p_from].always=p_to;
+ else
+ remap[p_from].locale[p_locale]=p_to;
+}
+
+
+String PathRemap::get_remap(const String& p_from) const {
+
+ const RemapData *ptr=remap.getptr(p_from);
+ if (!ptr) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ print_line("remap failed: "+p_from);
+ return p_from;
+ } else {
+
+ String locale = TranslationServer::get_singleton()->get_locale();
+
+ if (ptr->locale.has(locale)) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ print_line("remap found: "+p_from+" -> "+ptr->locale[locale]);
+ return ptr->locale[locale];
+ }
+
+ int p = locale.find("_");
+ if (p!=-1) {
+ locale=locale.substr(0,p);
+ if (ptr->locale.has(locale)) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ print_line("remap found: "+p_from+" -> "+ptr->locale[locale]);
+ return ptr->locale[locale];
+ }
+ }
+
+ if (ptr->always!=String()) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_line("remap found: "+p_from+" -> "+ptr->always);
+ }
+ return ptr->always;
+ }
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ print_line("remap failed: "+p_from);
+
+ return p_from;
+ }
+}
+bool PathRemap::has_remap(const String& p_from) const{
+
+ return remap.has(p_from);
+}
+
+void PathRemap::erase_remap(const String& p_from){
+
+ ERR_FAIL_COND(!remap.has(p_from));
+ remap.erase(p_from);
+}
+
+void PathRemap::clear_remaps() {
+
+ remap.clear();
+}
+
+void PathRemap::load_remaps() {
+
+ // default remaps first
+ DVector<String> remaps = Globals::get_singleton()->get("remap/all");
+
+ {
+ int rlen = remaps.size();
+
+ ERR_FAIL_COND( rlen%2 );
+ DVector<String>::Read r = remaps.read();
+ for(int i=0;i<rlen/2;i++) {
+
+ String from = r[i*2+0];
+ String to = r[i*2+1];
+ add_remap(from,to);
+ }
+ }
+
+
+ // platform remaps second, so override
+ remaps = Globals::get_singleton()->get("remap/"+OS::get_singleton()->get_name());
+// remaps = Globals::get_singleton()->get("remap/PSP");
+ {
+ int rlen = remaps.size();
+
+ ERR_FAIL_COND( rlen%2 );
+ DVector<String>::Read r = remaps.read();
+ for(int i=0;i<rlen/2;i++) {
+
+ String from = r[i*2+0];
+ String to = r[i*2+1];
+// print_line("add remap: "+from+" -> "+to);
+ add_remap(from,to);
+ }
+ }
+
+
+ //locale based remaps
+
+ if (Globals::get_singleton()->has("locale/translation_remaps")) {
+
+ Dictionary remaps = Globals::get_singleton()->get("locale/translation_remaps");
+ List<Variant> rk;
+ remaps.get_key_list(&rk);
+ for(List<Variant>::Element *E=rk.front();E;E=E->next()) {
+
+ String source = E->get();
+ StringArray sa = remaps[E->get()];
+ int sas = sa.size();
+ StringArray::Read r = sa.read();
+
+ for(int i=0;i<sas;i++) {
+
+ String s = r[i];
+ int qp = s.find_last(":");
+ if (qp!=-1) {
+ String path = s.substr(0,qp);
+ String locale = s.substr(qp+1,s.length());
+ add_remap(source,path,locale);
+ }
+ }
+ }
+
+ }
+
+}
+
+void PathRemap::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("add_remap","from","to","locale"),&PathRemap::add_remap,DEFVAL(String()));
+ ObjectTypeDB::bind_method(_MD("has_remap","path"),&PathRemap::has_remap);
+ ObjectTypeDB::bind_method(_MD("get_remap","path"),&PathRemap::get_remap);
+ ObjectTypeDB::bind_method(_MD("erase_remap","path"),&PathRemap::erase_remap);
+ ObjectTypeDB::bind_method(_MD("clear_remaps"),&PathRemap::clear_remaps);
+}
+
+PathRemap::PathRemap() {
+
+ singleton=this;
+}
diff --git a/core/path_remap.h b/core/path_remap.h
index a463cf259e..cb2a045668 100644
--- a/core/path_remap.h
+++ b/core/path_remap.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,42 +26,42 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PATH_REMAP_H
-#define PATH_REMAP_H
-
-#include "hash_map.h"
-#include "ustring.h"
-#include "object.h"
-
-
-class PathRemap : public Object {
-
- OBJ_TYPE(PathRemap,Object);
-
- static PathRemap* singleton;
- struct RemapData {
- String always;
- Map<String,String> locale;
- };
-
- HashMap<String,RemapData> remap;
-protected:
-
- static void _bind_methods();
-public:
-
- void add_remap(const String& p_from, const String& p_to,const String& p_locale=String());
- bool has_remap(const String& p_from) const;
- //_FORCE_INLINE_ String get_remap(const String& p_from) const { const String *ptr=remap.getptr(p_from); if (!ptr) return p_from; else return *ptr; }
- String get_remap(const String& p_from) const;
- void erase_remap(const String& p_from);
- void clear_remaps();
-
- void load_remaps();
-
- static PathRemap* get_singleton();
-
- PathRemap();
-};
-
-#endif // PATH_REMAP_H
+#ifndef PATH_REMAP_H
+#define PATH_REMAP_H
+
+#include "hash_map.h"
+#include "ustring.h"
+#include "object.h"
+
+
+class PathRemap : public Object {
+
+ OBJ_TYPE(PathRemap,Object);
+
+ static PathRemap* singleton;
+ struct RemapData {
+ String always;
+ Map<String,String> locale;
+ };
+
+ HashMap<String,RemapData> remap;
+protected:
+
+ static void _bind_methods();
+public:
+
+ void add_remap(const String& p_from, const String& p_to,const String& p_locale=String());
+ bool has_remap(const String& p_from) const;
+ //_FORCE_INLINE_ String get_remap(const String& p_from) const { const String *ptr=remap.getptr(p_from); if (!ptr) return p_from; else return *ptr; }
+ String get_remap(const String& p_from) const;
+ void erase_remap(const String& p_from);
+ void clear_remaps();
+
+ void load_remaps();
+
+ static PathRemap* get_singleton();
+
+ PathRemap();
+};
+
+#endif // PATH_REMAP_H
diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp
index 5af168ce82..d7dca45836 100644
--- a/core/pool_allocator.cpp
+++ b/core/pool_allocator.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/pool_allocator.h b/core/pool_allocator.h
index 4b94ae48d6..4b0f931eb3 100644
--- a/core/pool_allocator.h
+++ b/core/pool_allocator.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/print_string.cpp b/core/print_string.cpp
index 85700fe650..42e018f303 100644
--- a/core/print_string.cpp
+++ b/core/print_string.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,8 @@
#include <stdio.h>
static PrintHandlerList *print_handler_list=NULL;
-
+bool _print_line_enabled=true;
+bool _print_error_enabled = true;
void add_print_handler(PrintHandlerList *p_handler) {
@@ -75,6 +76,9 @@ void remove_print_handler(PrintHandlerList *p_handler) {
void print_line(String p_string) {
+ if (!_print_line_enabled)
+ return;
+
OS::get_singleton()->print("%s\n",p_string.utf8().get_data());
_global_lock();
diff --git a/core/print_string.h b/core/print_string.h
index 49960b7ed7..4ea389b3a1 100644
--- a/core/print_string.h
+++ b/core/print_string.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,9 +47,12 @@ struct PrintHandlerList {
};
+
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 f0758f66ce..ddb8054e3b 100644
--- a/core/ref_ptr.cpp
+++ b/core/ref_ptr.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/ref_ptr.h b/core/ref_ptr.h
index 007977d993..d1ee6a3a7d 100644
--- a/core/ref_ptr.h
+++ b/core/ref_ptr.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/reference.cpp b/core/reference.cpp
index 2fc941310d..509e132b5a 100644
--- a/core/reference.cpp
+++ b/core/reference.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -59,6 +59,10 @@ void Reference::_bind_methods() {
ObjectTypeDB::bind_method(_MD("unreference"),&Reference::unreference);
}
+int Reference::reference_get_count() const {
+ return refcount.get();
+}
+
void Reference::reference(){
refcount.ref();
diff --git a/core/reference.h b/core/reference.h
index 64d7a7acad..65f31f78f3 100644
--- a/core/reference.h
+++ b/core/reference.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -53,6 +53,7 @@ public:
bool init_ref();
void reference();
bool unreference();
+ int reference_get_count() const;
Reference();
~Reference();
@@ -293,6 +294,9 @@ public:
reference=NULL;
}
+ void instance() {
+ ref( memnew( T ));
+ }
Ref() {
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 473cf8706f..8754946bb1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,10 +27,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_core_types.h"
-#include "io/object_format_xml.h"
-#include "io/object_format_binary.h"
#include "io/tcp_server.h"
+#include "io/packet_peer_udp.h"
#include "io/config_file.h"
#include "os/main_loop.h"
#include "io/packet_peer.h"
@@ -56,14 +55,6 @@
#ifdef XML_ENABLED
static ResourceFormatSaverXML *resource_saver_xml=NULL;
static ResourceFormatLoaderXML *resource_loader_xml=NULL;
-#ifdef OLD_SCENE_FORMAT_ENABLED
-static ObjectFormatSaverInstancerXML *object_format_saver_xml=NULL;
-static ObjectFormatLoaderInstancerXML *object_format_loader_xml=NULL;
-#endif
-#endif
-#ifdef OLD_SCENE_FORMAT_ENABLED
-static ObjectFormatSaverInstancerBinary * object_format_saver_binary = NULL;
-static ObjectFormatLoaderInstancerBinary * object_format_loader_binary = NULL;
#endif
static ResourceFormatSaverBinary *resource_saver_binary=NULL;
static ResourceFormatLoaderBinary *resource_loader_binary=NULL;
@@ -101,23 +92,6 @@ void register_core_types() {
CoreStringNames::create();
-#ifdef XML_ENABLED
-#ifdef OLD_SCENE_FORMAT_ENABLED
- object_format_saver_xml = memnew( ObjectFormatSaverInstancerXML );
- ObjectSaver::add_object_format_saver_instancer( object_format_saver_xml );
-
- object_format_loader_xml = memnew( ObjectFormatLoaderInstancerXML );
- ObjectLoader::add_object_format_loader_instancer( object_format_loader_xml );
-#endif
-#endif
-#ifdef OLD_SCENE_FORMAT_ENABLED
- object_format_saver_binary = memnew( ObjectFormatSaverInstancerBinary );
- ObjectSaver::add_object_format_saver_instancer( object_format_saver_binary );
-
-
- object_format_loader_binary = memnew( ObjectFormatLoaderInstancerBinary );
- ObjectLoader::add_object_format_loader_instancer( object_format_loader_binary );
-#endif
resource_format_po = memnew( TranslationLoaderPO );
ResourceLoader::add_resource_format_loader( resource_format_po );
@@ -136,12 +110,14 @@ void register_core_types() {
ObjectTypeDB::register_type<Reference>();
+ ObjectTypeDB::register_type<WeakRef>();
ObjectTypeDB::register_type<ResourceImportMetadata>();
ObjectTypeDB::register_type<Resource>();
ObjectTypeDB::register_type<FuncRef>();
ObjectTypeDB::register_virtual_type<StreamPeer>();
ObjectTypeDB::register_create_type<StreamPeerTCP>();
ObjectTypeDB::register_create_type<TCP_Server>();
+ ObjectTypeDB::register_create_type<PacketPeerUDP>();
ObjectTypeDB::register_create_type<StreamPeerSSL>();
ObjectTypeDB::register_virtual_type<IP>();
ObjectTypeDB::register_virtual_type<PacketPeer>();
@@ -212,10 +188,6 @@ void unregister_core_types() {
memdelete( _geometry );
#ifdef XML_ENABLED
-#ifdef OLD_SCENE_FORMAT_ENABLED
- memdelete( object_format_saver_xml );
- memdelete( object_format_loader_xml );
-#endif
if (resource_saver_xml)
memdelete(resource_saver_xml);
if (resource_loader_xml)
@@ -228,21 +200,19 @@ void unregister_core_types() {
memdelete(resource_loader_binary);
-#ifdef OLD_SCENE_FORMAT_ENABLED
- memdelete( object_format_saver_binary );
- memdelete( object_format_loader_binary );
-#endif
memdelete( resource_format_po );
if (ip)
memdelete(ip);
+
+ ObjectDB::cleanup();
+
unregister_variant_methods();
- CoreStringNames::free();
ObjectTypeDB::cleanup();
ResourceCache::clear();
- ObjectDB::cleanup();
+ CoreStringNames::free();
StringName::cleanup();
if (_global_mutex) {
diff --git a/core/register_core_types.h b/core/register_core_types.h
index 9f89a3ffeb..a84849c969 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/res_ptr.cpp b/core/res_ptr.cpp
index b9bd931570..fcff285e8f 100644
--- a/core/res_ptr.cpp
+++ b/core/res_ptr.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/res_ptr.h b/core/res_ptr.h
index 69da69bf52..21f7fb6a2c 100644
--- a/core/res_ptr.h
+++ b/core/res_ptr.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/resource.cpp b/core/resource.cpp
index 987bd772b0..6967599f96 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -130,7 +130,7 @@ void ResourceImportMetadata::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_editor","name"),&ResourceImportMetadata::set_editor);
ObjectTypeDB::bind_method(_MD("get_editor"),&ResourceImportMetadata::get_editor);
- ObjectTypeDB::bind_method(_MD("add_source","path","md5"),&ResourceImportMetadata::add_source);
+ ObjectTypeDB::bind_method(_MD("add_source","path","md5"),&ResourceImportMetadata::add_source, "");
ObjectTypeDB::bind_method(_MD("get_source_path","idx"),&ResourceImportMetadata::get_source_path);
ObjectTypeDB::bind_method(_MD("get_source_md5","idx"),&ResourceImportMetadata::get_source_md5);
ObjectTypeDB::bind_method(_MD("remove_source","idx"),&ResourceImportMetadata::remove_source);
@@ -195,6 +195,17 @@ String Resource::get_path() const {
return path_cache;
}
+void Resource::set_subindex(int p_sub_index) {
+
+ subindex=p_sub_index;
+}
+
+int Resource::get_subindex() const{
+
+ return subindex;
+}
+
+
void Resource::set_name(const String& p_name) {
name=p_name;
@@ -326,6 +337,7 @@ Resource::Resource() {
last_modified_time=0;
#endif
+ subindex=0;
}
diff --git a/core/resource.h b/core/resource.h
index 8a637e7996..3596abe673 100644
--- a/core/resource.h
+++ b/core/resource.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -99,6 +99,7 @@ friend class ResourceCache;
String name;
String path_cache;
+ int subindex;
virtual bool _use_builtin_script() const { return true; }
@@ -129,9 +130,12 @@ 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);
+ int get_subindex() const;
+
Ref<Resource> duplicate(bool p_subresources=false);
void set_import_metadata(const Ref<ResourceImportMetadata>& p_metadata);
diff --git a/core/rid.cpp b/core/rid.cpp
index 3dc4c6aed4..0870e6ab2d 100644
--- a/core/rid.cpp
+++ b/core/rid.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/rid.h b/core/rid.h
index 4d4e11c251..e6582757ee 100644
--- a/core/rid.h
+++ b/core/rid.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/ring_buffer.h b/core/ring_buffer.h
index 71105e7bf1..5cbd261ec8 100644
--- a/core/ring_buffer.h
+++ b/core/ring_buffer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 3d867448e8..afe2a4eb33 100644
--- a/core/safe_refcount.cpp
+++ b/core/safe_refcount.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/safe_refcount.h b/core/safe_refcount.h
index 4357786732..481b9fa7e9 100644
--- a/core/safe_refcount.h
+++ b/core/safe_refcount.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/script_debugger_debugger.cpp b/core/script_debugger_debugger.cpp
index 6ff60e6ff4..5c592a130c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/script_debugger_local.cpp b/core/script_debugger_local.cpp
index 5e153a4912..649bbe89f0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 159dd15e58..45ff1d4466 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp
index cd8303b542..d72c9f7532 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,10 +31,36 @@
#include "io/ip.h"
#include "globals.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;
@@ -127,7 +153,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 +176,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 +269,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);
}
@@ -287,6 +327,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 +372,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 +546,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 +556,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 +631,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 +675,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 +698,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 861bcccff7..973fa23212 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 031fcb0c4c..b7a0f579f4 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -85,6 +85,13 @@ void ScriptServer::register_language(ScriptLanguage *p_language) {
_languages[_language_count++]=p_language;
}
+void ScriptServer::init_languages() {
+
+ for(int i=0;i<_language_count;i++) {
+ _languages[i]->init();
+ }
+}
+
Variant ScriptInstance::call(const StringName& p_method,VARIANT_ARG_DECLARE) {
VARIANT_ARGPTRS;
@@ -129,6 +136,14 @@ ScriptInstance::~ScriptInstance() {
}
+
+ScriptCodeCompletionCache *ScriptCodeCompletionCache::singleton=NULL;
+ScriptCodeCompletionCache::ScriptCodeCompletionCache() {
+ singleton=this;
+}
+
+
+
void ScriptLanguage::frame() {
@@ -252,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) {
@@ -283,8 +312,10 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties,co
to_remove.pop_front();
}
- if (owner && owner->get_script_instance()==this)
+ if (owner && owner->get_script_instance()==this) {
+
owner->_change_notify();
+ }
//change notify
}
diff --git a/core/script_language.h b/core/script_language.h
index 8c59a9e6b8..9660f141c7 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -54,6 +54,8 @@ public:
static int get_language_count();
static ScriptLanguage *get_language(int p_idx);
static void register_language(ScriptLanguage *p_language);
+
+ static void init_languages();
};
@@ -80,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;
@@ -92,6 +95,12 @@ public:
virtual ScriptLanguage *get_language() const=0;
+ virtual bool has_script_signal(const StringName& p_signal) const=0;
+ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const=0;
+
+
+ virtual void update_exports() {} //editor tool
+
Script() {}
};
@@ -101,6 +110,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;
@@ -118,6 +128,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:
@@ -140,7 +163,7 @@ public:
virtual bool has_named_classes() const=0;
virtual int find_function(const String& p_function,const String& p_code) const=0;
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const=0;
- virtual Error complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_keyword, List<String>* r_options) { return ERR_UNAVAILABLE; }
+ 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;
/* DEBUGGER FUNCTIONS */
@@ -155,6 +178,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;
@@ -180,6 +210,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; }
@@ -217,6 +248,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;
@@ -231,10 +288,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;
@@ -244,9 +303,10 @@ 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() {}
+ virtual ~ScriptDebugger() {singleton=NULL;}
};
diff --git a/core/self_list.h b/core/self_list.h
index 729b9fb680..b414baaba6 100644
--- a/core/self_list.h
+++ b/core/self_list.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/set.h b/core/set.h
index d87f635577..91c4e3f9c4 100644
--- a/core/set.h
+++ b/core/set.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -249,6 +249,37 @@ private:
return (node!=_data._nil)?node:NULL;
}
+ Element *_lower_bound(const T& p_value) const {
+
+ Element *node = _data._root->left;
+ Element *prev = NULL;
+ C less;
+
+ while(node!=_data._nil) {
+ prev=node;
+
+ if (less(p_value,node->value))
+ node=node->left;
+ else if (less(node->value,p_value))
+ node=node->right;
+ else
+ break; // found
+ }
+
+ if (node==_data._nil) {
+ if (prev==NULL)
+ return NULL;
+ if (less(prev->value,p_value)) {
+
+ prev=prev->_next;
+ }
+
+ return prev;
+
+ } else
+ return node;
+ }
+
Element *_insert(const T& p_value, bool& r_exists) {
@@ -582,6 +613,12 @@ public:
return e;
}
+
+ Element *lower_bound(const T& p_value) const {
+
+ return _lower_bound(p_value);
+ }
+
inline int size() const { return _data.size_cache; }
int calculate_depth() const {
diff --git a/core/simple_type.h b/core/simple_type.h
index fac6dceee8..84e08bf0b4 100644
--- a/core/simple_type.h
+++ b/core/simple_type.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/sort.h b/core/sort.h
index 583437a099..65664d0ed8 100644
--- a/core/sort.h
+++ b/core/sort.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/string_db.cpp b/core/string_db.cpp
index ffb7dc194b..b48d9f37d4 100644
--- a/core/string_db.cpp
+++ b/core/string_db.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,7 +28,7 @@
/*************************************************************************/
#include "string_db.h"
#include "print_string.h"
-
+#include "os/os.h"
StaticCString StaticCString::create(const char *p_ptr) {
StaticCString scs; scs.ptr=p_ptr; return scs;
}
@@ -55,15 +55,29 @@ void StringName::setup() {
void StringName::cleanup() {
_global_lock();
+ int lost_strings=0;
for(int i=0;i<STRING_TABLE_LEN;i++) {
while(_table[i]) {
_Data*d=_table[i];
- _table[i]=_table[i]->next;
+ lost_strings++;
+ if (OS::get_singleton()->is_stdout_verbose()) {
+
+ if (d->cname) {
+ print_line("Orphan StringName: "+String(d->cname));
+ } else {
+ print_line("Orphan StringName: "+String(d->name));
+ }
+ }
+
+ _table[i]=_table[i]->next;
memdelete(d);
}
}
+ if (OS::get_singleton()->is_stdout_verbose() && lost_strings) {
+ print_line("StringName: "+itos(lost_strings)+" unclaimed string names at exit.");
+ }
_global_unlock();
}
@@ -144,7 +158,7 @@ void StringName::operator=(const StringName& p_name) {
_data = p_name._data;
}
}
-
+/* was inlined
StringName::operator String() const {
if (_data)
@@ -152,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 45afbbe6fc..3b3249bf5e 100644
--- a/core/string_db.h
+++ b/core/string_db.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 045771f7c7..8247cd1201 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -470,6 +470,11 @@ void Translation::get_message_list(List<StringName> *r_messages) const {
}
+int Translation::get_message_count() const {
+
+ return translation_map.size();
+};
+
void Translation::_bind_methods() {
@@ -479,6 +484,7 @@ void Translation::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_message","src_message"),&Translation::get_message);
ObjectTypeDB::bind_method(_MD("erase_message","src_message"),&Translation::erase_message);
ObjectTypeDB::bind_method(_MD("get_message_list"),&Translation::_get_message_list);
+ ObjectTypeDB::bind_method(_MD("get_message_count"),&Translation::get_message_count);
ObjectTypeDB::bind_method(_MD("_set_messages"),&Translation::_set_messages);
ObjectTypeDB::bind_method(_MD("_get_messages"),&Translation::_get_messages);
@@ -519,6 +525,11 @@ void TranslationServer::remove_translation(const Ref<Translation> &p_translation
translations.erase(p_translation);
}
+void TranslationServer::clear() {
+
+ translations.clear();
+};
+
StringName TranslationServer::translate(const StringName& p_message) const {
//translate using locale
@@ -539,7 +550,7 @@ StringName TranslationServer::translate(const StringName& p_message) const {
continue; // locale not match
//near match
- bool match = (l!=lptr);
+ bool match = (l!=locale);
if (near_match && !match)
continue; //only near-match once
@@ -559,6 +570,42 @@ StringName TranslationServer::translate(const StringName& p_message) const {
}
+ if (!res) {
+ //try again with fallback
+ if (fallback.length()>=2) {
+
+ const CharType *fptr=&fallback[0];
+ bool near_match=false;
+ for (const Set< Ref<Translation> >::Element *E=translations.front();E;E=E->next()) {
+
+ const Ref<Translation>& t = E->get();
+ String l = t->get_locale();
+ if (fptr[0]!=l[0] || fptr[1]!=l[1])
+ continue; // locale not match
+
+ //near match
+ bool match = (l!=fallback);
+
+ if (near_match && !match)
+ continue; //only near-match once
+
+ StringName r=t->get_message(p_message);
+
+ if (!r)
+ continue;
+
+ res=r;
+
+ if (match)
+ break;
+ else
+ near_match=true;
+
+ }
+ }
+ }
+
+
if (!res)
return p_message;
@@ -593,9 +640,27 @@ bool TranslationServer::_load_translations(const String& p_from) {
void TranslationServer::setup() {
-
- set_locale( GLOBAL_DEF("locale/default",OS::get_singleton()->get_locale()) );
- fallback = GLOBAL_DEF("locale/fallback","");
+ String test = GLOBAL_DEF("locale/test","");
+ test=test.strip_edges();
+ if (test!="")
+ set_locale( test );
+ else
+ set_locale( OS::get_singleton()->get_locale() );
+ fallback = GLOBAL_DEF("locale/fallback","en");
+#ifdef TOOLS_ENABLED
+
+ {
+ String options="";
+ int idx=0;
+ while(locale_list[idx]) {
+ if (idx>0)
+ options+=", ";
+ options+=locale_list[idx];
+ idx++;
+ }
+ Globals::get_singleton()->set_custom_property_info("locale/fallback",PropertyInfo(Variant::STRING,"locale/fallback",PROPERTY_HINT_ENUM,options));
+ }
+#endif
//load translations
}
@@ -609,12 +674,16 @@ void TranslationServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_translation"),&TranslationServer::add_translation);
ObjectTypeDB::bind_method(_MD("remove_translation"),&TranslationServer::remove_translation);
+
+ ObjectTypeDB::bind_method(_MD("clear"),&TranslationServer::clear);
+
}
void TranslationServer::load_translations() {
String locale = get_locale();
bool found = _load_translations("locale/translations"); //all
+
if (_load_translations("locale/translations_"+locale.substr(0,2)))
found=true;
if ( locale.substr(0,2) != locale ) {
@@ -623,17 +692,6 @@ void TranslationServer::load_translations() {
}
- if (!found && fallback!="") { //none found anywhere, use fallback
-
- _load_translations("locale/translations_"+fallback.substr(0,2));
- if ( fallback.substr(0,2) != fallback ) {
- _load_translations("locale/translations_"+fallback);
- }
-
- this->locale=fallback;
-
- }
-
}
TranslationServer::TranslationServer() {
diff --git a/core/translation.h b/core/translation.h
index 1286f48a0b..54118cd3b5 100644
--- a/core/translation.h
+++ b/core/translation.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -60,6 +60,7 @@ public:
void erase_message(const StringName& p_src_text);
void get_message_list(List<StringName> *r_messages) const;
+ int get_message_count() const;
Translation();
};
@@ -103,6 +104,8 @@ public:
void setup();
+ void clear();
+
void load_translations();
TranslationServer();
diff --git a/core/typedefs.h b/core/typedefs.h
index 3107ac2ff7..6ca31fd137 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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_REVISION)"-"_MKSTR(VERSION_STATUS)
-#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_
diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp
index b78fd89883..85cc2bbc7f 100644
--- a/core/undo_redo.cpp
+++ b/core/undo_redo.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -234,15 +234,34 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
ERR_FAIL_COND(!obj);
}
+
switch(op.type) {
case Operation::TYPE_METHOD: {
- obj->call(op.name,VARIANT_ARGS_FROM_ARRAY(op.args));
+ obj->call(op.name,VARIANT_ARGS_FROM_ARRAY(op.args));
+#ifdef TOOLS_ENABLED
+ 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: {
obj->set(op.name,op.args[0]);
+#ifdef TOOLS_ENABLED
+ Resource* res = obj->cast_to<Resource>();
+ 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
@@ -271,6 +290,7 @@ void UndoRedo::undo() {
return; //nothing to redo
_process_operation_list(actions[current_action].undo_ops.front());
current_action--;
+ version--;
}
void UndoRedo::clear_history() {
@@ -281,7 +301,7 @@ void UndoRedo::clear_history() {
while(actions.size())
_pop_history_tail();
- version++;
+ //version++;
}
String UndoRedo::get_current_action_name() const {
@@ -313,18 +333,160 @@ 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=0;
+ version=1;
action_level=0;
current_action=-1;
max_steps=-1;
merging=true;
callback=NULL;
callback_ud=NULL;
+
+ method_callbck_ud=NULL;
+ prop_callback_ud=NULL;
+ method_callback=NULL;
+ property_callback=NULL;
+
}
UndoRedo::~UndoRedo() {
clear_history();
}
+
+Variant UndoRedo::_add_do_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+
+ if (p_argcount<2) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=0;
+ return Variant();
+ }
+
+ if (p_args[0]->get_type()!=Variant::OBJECT) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::OBJECT;
+ return Variant();
+ }
+
+ if (p_args[1]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=1;
+ r_error.expected=Variant::STRING;
+ return Variant();
+ }
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Object* object = *p_args[0];
+ String method = *p_args[1];
+
+ Variant v[VARIANT_ARG_MAX];
+
+
+ for(int i=0;i<MIN(VARIANT_ARG_MAX,p_argcount-2);++i) {
+
+ v[i]=*p_args[i+2];
+ }
+
+ add_do_method(object,method,v[0],v[1],v[2],v[3],v[4]);
+ return Variant();
+}
+
+Variant UndoRedo::_add_undo_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+
+ if (p_argcount<2) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=0;
+ return Variant();
+ }
+
+ if (p_args[0]->get_type()!=Variant::OBJECT) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::OBJECT;
+ return Variant();
+ }
+
+ if (p_args[1]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=1;
+ r_error.expected=Variant::STRING;
+ return Variant();
+ }
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Object* object = *p_args[0];
+ String method = *p_args[1];
+
+ Variant v[VARIANT_ARG_MAX];
+
+
+ for(int i=0;i<MIN(VARIANT_ARG_MAX,p_argcount-2);++i) {
+
+ v[i]=*p_args[i+2];
+ }
+
+ add_undo_method(object,method,v[0],v[1],v[2],v[3],v[4]);
+ return Variant();
+}
+
+void UndoRedo::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("create_action","name","mergeable"),&UndoRedo::create_action, DEFVAL(false) );
+ ObjectTypeDB::bind_method(_MD("commit_action"),&UndoRedo::commit_action);
+
+ //ObjectTypeDB::bind_method(_MD("add_do_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_do_method);
+ //ObjectTypeDB::bind_method(_MD("add_undo_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_undo_method);
+
+ {
+ MethodInfo mi;
+ mi.name="add_do_method";
+ mi.arguments.push_back( PropertyInfo( Variant::OBJECT, "object"));
+ mi.arguments.push_back( PropertyInfo( Variant::STRING, "method"));
+ Vector<Variant> defargs;
+ for(int i=0;i<VARIANT_ARG_MAX;++i) {
+ mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i)));
+ defargs.push_back(Variant());
+ }
+
+ ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"add_do_method",&UndoRedo::_add_do_method,mi,defargs);
+ }
+
+ {
+ MethodInfo mi;
+ mi.name="add_undo_method";
+ mi.arguments.push_back( PropertyInfo( Variant::OBJECT, "object"));
+ mi.arguments.push_back( PropertyInfo( Variant::STRING, "method"));
+ Vector<Variant> defargs;
+ for(int i=0;i<VARIANT_ARG_MAX;++i) {
+ mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i)));
+ defargs.push_back(Variant());
+ }
+
+ 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_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);
+ ObjectTypeDB::bind_method(_MD("get_current_action_name"),&UndoRedo::get_current_action_name);
+ ObjectTypeDB::bind_method(_MD("get_version"),&UndoRedo::get_version);
+}
diff --git a/core/undo_redo.h b/core/undo_redo.h
index ff729e1767..141a413c2a 100644
--- a/core/undo_redo.h
+++ b/core/undo_redo.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,9 +38,15 @@
class UndoRedo : public Object {
OBJ_TYPE(UndoRedo,Object);
+ OBJ_SAVE_TYPE( UndoRedo );
public:
typedef void (*CommitNotifyCallback)(void *p_ud,const String& p_name);
+ 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 {
@@ -80,6 +86,15 @@ private:
CommitNotifyCallback callback;
void* callback_ud;
+ void* method_callbck_ud;
+ void* prop_callback_ud;
+
+ MethodNotifyCallback method_callback;
+ PropertyNotifyCallback property_callback;
+
+
+protected:
+ static void _bind_methods();
public:
@@ -106,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 00477e7570..bf2494e9b5 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,6 +34,7 @@
#include "io/md5.h"
#include "ucaps.h"
#include "color.h"
+#include "variant.h"
#define MAX_DIGITS 6
#define UPPERCASE(m_c) (((m_c)>='a' && (m_c)<='z')?((m_c)-('a'-'A')):(m_c))
#define LOWERCASE(m_c) (((m_c)>='A' && (m_c)<='Z')?((m_c)+('a'-'A')):(m_c))
@@ -43,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 {
@@ -66,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];
}
}
@@ -485,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]);
@@ -497,6 +506,27 @@ String String::capitalize() const {
return cap;
}
+
+String String::camelcase_to_underscore() const {
+ const CharType * cstr = c_str();
+ String newString;
+ const char A = 'A', Z = 'Z';
+ int startIndex = 0;
+
+ for ( int i = 1; i < this->size()-1; i++ ) {
+ bool isCapital = cstr[i] >= A && cstr[i] <= Z;
+
+ if ( isCapital ) {
+ newString += "_" + this->substr(startIndex, i-startIndex);
+ startIndex = i;
+ }
+ }
+
+ newString += "_" + this->substr(startIndex, this->size()-startIndex);
+
+ return newString;
+}
+
int String::get_slice_count(String p_splitter) const{
if (empty())
@@ -555,6 +585,77 @@ 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 {
+
+ Vector<String> ret;
+ int from=0;
+ int i=0;
+ int len = length();
+ bool inside=false;
+
+ while(true) {
+
+ bool empty=operator[](i)<33;
+
+ if (i==0)
+ inside=!empty;
+
+ if (!empty && !inside) {
+ inside=true;
+ from=i;
+ }
+
+ if (empty && inside) {
+
+ ret.push_back(substr(from,i-from));
+ inside=false;
+ }
+
+ if (i==len)
+ break;
+ i++;
+ }
+
+ return ret;
+
+}
+
Vector<String> String::split(const String &p_splitter,bool p_allow_empty) const {
Vector<String> ret;
@@ -590,7 +691,7 @@ Vector<float> String::split_floats(const String &p_splitter,bool p_allow_empty)
if (end<0)
end=len;
if (p_allow_empty || (end>from))
- ret.push_back(String::to_double(&c_str()[from],end-from));
+ ret.push_back(String::to_double(&c_str()[from]));
if (end==len)
break;
@@ -618,8 +719,9 @@ Vector<float> String::split_floats_mk(const Vector<String> &p_splitters,bool p_a
spl_len=p_splitters[idx].length();
}
- if (p_allow_empty || (end>from))
- ret.push_back(String::to_double(&c_str()[from],end-from));
+ if (p_allow_empty || (end>from)) {
+ ret.push_back(String::to_double(&c_str()[from]));
+ }
if (end==len)
break;
@@ -795,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
@@ -944,7 +1037,7 @@ String String::num(double p_num,int p_decimals) {
}
-String String::num_int64(int64_t p_num) {
+String String::num_int64(int64_t p_num, int base, bool capitalize_hex) {
bool sign=p_num<0;
int64_t num=ABS(p_num);
@@ -953,7 +1046,7 @@ String String::num_int64(int64_t p_num) {
int chars=0;
do {
- n/=10;
+ n/=base;
chars++;
} while(n);
@@ -965,8 +1058,15 @@ String String::num_int64(int64_t p_num) {
c[chars]=0;
n=num;
do {
- c[--chars]='0'+(n%10);
- n/=10;
+ int mod = n%base;
+ if (mod >= 10) {
+ char a = (capitalize_hex ? 'A' : 'a');
+ c[--chars]=a+(mod - 10);
+ } else {
+ c[--chars]='0'+mod;
+ }
+
+ n/=base;
} while(n);
if (sign)
@@ -1069,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);
@@ -1923,8 +2020,10 @@ float String::to_float() const {
return to_double();
}
-double String::to_double(const CharType* p_str, int p_len, const CharType **r_end) {
+double String::to_double(const CharType* p_str, const CharType **r_end) {
+ return built_in_strtod<CharType>(p_str,(CharType**)r_end);
+#if 0
#if 0
//ndef NO_USE_STDLIB
return wcstod(p_str,p_len<0?NULL:p_str+p_len);
@@ -2017,6 +2116,7 @@ double String::to_double(const CharType* p_str, int p_len, const CharType **r_en
return sign*(integer+decimal)*Math::pow(10,exp_sign*exp);
#endif
+#endif
}
int64_t String::to_int(const CharType* p_str,int p_len) {
@@ -2276,6 +2376,24 @@ String String::md5_text() const {
return String::md5(ctx.digest);
}
+Vector<uint8_t> String::md5_buffer() const {
+
+ CharString cs=utf8();
+ MD5_CTX ctx;
+ MD5Init(&ctx);
+ MD5Update(&ctx,(unsigned char*)cs.ptr(),cs.length());
+ MD5Final(&ctx);
+
+ Vector<uint8_t> ret;
+ ret.resize(16);
+ for (int i=0; i<16; i++) {
+ ret[i] = ctx.digest[i];
+ };
+
+ return ret;
+};
+
+
String String::insert(int p_at_pos,String p_string) const {
if (p_at_pos<0)
@@ -2449,13 +2567,8 @@ int String::findn(String p_str,int p_from) const {
};
- CharType src=srcd[read_pos];
- CharType dst=p_str[j];
-
- if (src>='a' && src<='z')
- src-='a'-'A';
- if (dst>='a' && dst<='z')
- dst-='a'-'A';
+ CharType src=_find_lower(srcd[read_pos]);
+ CharType dst=_find_lower(p_str[j]);
if (src!=dst) {
found=false;
@@ -2472,10 +2585,101 @@ int String::findn(String p_str,int p_from) const {
int String::rfind(String p_str,int p_from) const {
+ //stabilish a limit
+ int limit = length()-p_str.length();
+ if (limit<0)
+ return -1;
+
+ //stabilish a starting point
+ if (p_from<0)
+ p_from=limit;
+ else if (p_from>limit)
+ p_from=limit;
+
+ int src_len=p_str.length();
+ int len=length();
+
+ if(src_len==0 || len==0)
+ return -1; //wont find anything!
+
+
+ const CharType *src = c_str();
+
+ for (int i=p_from;i>=0;i--) {
+
+ bool found=true;
+ for (int j=0;j<src_len;j++) {
+
+ int read_pos=i+j;
+
+ if (read_pos>=len) {
+
+ ERR_PRINT("read_pos>=len");
+ return -1;
+ };
+
+
+ if (src[read_pos]!=p_str[j]) {
+ found=false;
+ break;
+ }
+ }
+
+ if (found)
+ return i;
+ }
+
return -1;
}
int String::rfindn(String p_str,int p_from) const {
+ //stabilish a limit
+ int limit = length()-p_str.length();
+ if (limit<0)
+ return -1;
+
+ //stabilish a starting point
+ if (p_from<0)
+ p_from=limit;
+ else if (p_from>limit)
+ p_from=limit;
+
+ int src_len=p_str.length();
+ int len=length();
+
+ if(src_len==0 || len==0)
+ return -1; //wont find anything!
+
+
+ const CharType *src = c_str();
+
+ for (int i=p_from;i>=0;i--) {
+
+ bool found=true;
+ for (int j=0;j<src_len;j++) {
+
+ int read_pos=i+j;
+
+ if (read_pos>=len) {
+
+ ERR_PRINT("read_pos>=len");
+ return -1;
+ };
+
+ CharType srcc=_find_lower(src[read_pos]);
+ CharType dstc=_find_lower(p_str[j]);
+
+
+ if (srcc!=dstc) {
+ found=false;
+ break;
+ }
+ }
+
+ if (found)
+ return i;
+ }
+
return -1;
}
@@ -2837,6 +3041,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;
@@ -2877,8 +3158,8 @@ 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;");
@@ -2930,12 +3211,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]==';') {
@@ -3124,8 +3405,11 @@ String String::path_to_file(const String& p_path) const {
String src=this->replace("\\","/").get_base_dir();
String dst=p_path.replace("\\","/").get_base_dir();
-
- return src.path_to(dst)+p_path.get_file();
+ String rel = src.path_to(dst);
+ if (rel==dst) // failed
+ return p_path;
+ else
+ return rel+p_path.get_file();
}
String String::path_to(const String& p_path) const {
@@ -3157,10 +3441,12 @@ 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
- ERR_FAIL_COND_V(src_begin!=dst_begin,p_path); //return dst absolute path
base=src_begin;
src=src.substr(src_begin.length(),src.length());
dst=dst.substr(dst_begin.length(),dst.length());
@@ -3297,7 +3583,7 @@ String String::percent_encode() const {
uint8_t c = cs[i];
if ( (c>='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9') || c=='-' || c=='_' || c=='~' || c=='.') {
- char p[2]={c,0};
+ char p[2]={(char)c,0};
encoded+=p;
} else {
char p[4]={'%',0,0,0};
@@ -3374,4 +3660,270 @@ String rtoss(double p_val) {
return String::num_scientific(p_val);
}
+// Right-pad with a character.
+String String::rpad(int min_length, const String& character) const {
+ String s = *this;
+ int padding = min_length - s.length();
+ if (padding > 0) {
+ for (int i = 0; i < padding; i++) s = s + character;
+ }
+
+ return s;
+}
+// Left-pad with a character.
+String String::lpad(int min_length, const String& character) const {
+ String s = *this;
+ int padding = min_length - s.length();
+ if (padding > 0) {
+ for (int i = 0; i < padding; i++) s = character + s;
+ }
+
+ return s;
+}
+
+// sprintf is implemented in GDScript via:
+// "fish %s pie" % "frog"
+// "fish %s %d pie" % ["frog", 12]
+// In case of an error, the string returned is the error description and "error" is true.
+String String::sprintf(const Array& values, bool* error) const {
+ String formatted;
+ CharType* self = (CharType*)c_str();
+ int num_items = values.size();
+ bool in_format = false;
+ int value_index = 0;
+ int min_chars;
+ int min_decimals;
+ bool in_decimals;
+ bool pad_with_zeroes;
+ bool left_justified;
+ bool show_sign;
+
+ *error = true;
+
+ for (; *self; self++) {
+ const CharType c = *self;
+
+ if (in_format) { // We have % - lets see what else we get.
+ switch (c) {
+ case '%': { // Replace %% with %
+ formatted += chr(c);
+ in_format = false;
+ break;
+ }
+ case 'd': // Integer (signed)
+ case 'o': // Octal
+ case 'x': // Hexadecimal (lowercase)
+ case 'X': { // Hexadecimal (uppercase)
+ if (value_index >= values.size()) {
+ return "not enough arguments for format string";
+ }
+
+ if (!values[value_index].is_num()) {
+ return "a number is required";
+ }
+
+ int64_t value = values[value_index];
+ int base;
+ bool capitalize = false;
+ switch (c) {
+ case 'd': base = 10; break;
+ case 'o': base = 8; break;
+ case 'x': base = 16; break;
+ case 'X': base = 16; capitalize = true; break;
+ }
+ // Get basic number.
+ String str = String::num_int64(value, base, capitalize);
+
+ // Sign.
+ if (show_sign && value >= 0) {
+ str = str.insert(0, "+");
+ }
+
+ // Padding.
+ String pad_char = pad_with_zeroes ? String("0") : String(" ");
+ if (left_justified) {
+ str = str.rpad(min_chars, pad_char);
+ } else {
+ str = str.lpad(min_chars, pad_char);
+ }
+
+ formatted += str;
+ ++value_index;
+ in_format = false;
+
+ break;
+ }
+ case 'f': { // Float
+ if (value_index >= values.size()) {
+ return "not enough arguments for format string";
+ }
+
+ if (!values[value_index].is_num()) {
+ return "a number is required";
+ }
+
+ double value = values[value_index];
+ String str = String::num(value, min_decimals);
+
+ // Pad decimals out.
+ str = str.pad_decimals(min_decimals);
+
+ // Show sign
+ if (show_sign && value >= 0) {
+ str = str.insert(0, "+");
+ }
+
+ // Padding
+ if (left_justified) {
+ str = str.rpad(min_chars);
+ } else {
+ str = str.lpad(min_chars);
+ }
+
+ formatted += str;
+ ++value_index;
+ in_format = false;
+
+ break;
+ }
+ case 's': { // String
+ if (value_index >= values.size()) {
+ return "not enough arguments for format string";
+ }
+
+ String str = values[value_index];
+ // Padding.
+ if (left_justified) {
+ str = str.rpad(min_chars);
+ } else {
+ str = str.lpad(min_chars);
+ }
+
+ formatted += str;
+ ++value_index;
+ in_format = false;
+ break;
+ }
+ case 'c': {
+ if (value_index >= values.size()) {
+ return "not enough arguments for format string";
+ }
+
+ // Convert to character.
+ String str;
+ if (values[value_index].is_num()) {
+ int value = values[value_index];
+ if (value < 0) {
+ return "unsigned byte integer is lower than maximum";
+ } else if (value > 255) {
+ return "unsigned byte integer is greater than maximum";
+ }
+ str = chr(values[value_index]);
+ } else if (values[value_index].get_type() == Variant::STRING) {
+ str = values[value_index];
+ if (str.length() != 1) {
+ return "%c requires number or single-character string";
+ }
+ } else {
+ return "%c requires number or single-character string";
+ }
+ // Padding.
+ if (left_justified) {
+ str = str.rpad(min_chars);
+ } else {
+ str = str.lpad(min_chars);
+ }
+
+ formatted += str;
+ ++value_index;
+ in_format = false;
+ break;
+ }
+ case '-': { // Left justify
+ left_justified = true;
+ break;
+ }
+ case '+': { // Show + if positive.
+ show_sign = true;
+ break;
+ }
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ int n = c - '0';
+ if (in_decimals) {
+ min_decimals *= 10;
+ min_decimals += n;
+ } else {
+ if (c == '0' && min_chars == 0) {
+ pad_with_zeroes = true;
+ } else {
+ min_chars *= 10;
+ min_chars += n;
+ }
+ }
+ break;
+ }
+ case '.': { // Float separtor.
+ if (in_decimals) {
+ return "too many decimal points in format";
+ }
+ in_decimals = true;
+ min_decimals = 0; // We want to add the value manually.
+ break;
+ }
+
+ case '*': { // Dyanmic width, based on value.
+ if (value_index >= values.size()) {
+ return "not enough arguments for format string";
+ }
+
+ if (!values[value_index].is_num()) {
+ return "* wants number";
+ }
+
+ int size = values[value_index];
+
+ if (in_decimals) {
+ min_decimals = size;
+ } else {
+ min_chars = size;
+ }
+
+ ++value_index;
+ break;
+ }
+
+ default: {
+ return "unsupported format character";
+ }
+ }
+ } else { // Not in format string.
+ switch (c) {
+ case '%':
+ in_format = true;
+ // Back to defaults:
+ min_chars = 0;
+ min_decimals = 6;
+ pad_with_zeroes = false;
+ left_justified = false;
+ show_sign = false;
+ in_decimals = false;
+ break;
+ default:
+ formatted += chr(c);
+ }
+ }
+ }
+
+ if (in_format) {
+ return "incomplete format";
+ }
+
+ if (value_index != values.size()) {
+ return "not all arguments converted during string formatting";
+ }
+
+ *error = false;
+ return formatted;
+}
diff --git a/core/ustring.h b/core/ustring.h
index 13db00f07f..2f3c4bff4d 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,6 +31,7 @@
#include "typedefs.h"
#include "vector.h"
+#include "array.h"
/**
@author red <red@killy>
@@ -127,10 +128,13 @@ public:
String insert(int p_at_pos,String p_string) const;
String pad_decimals(int p_digits) const;
String pad_zeros(int p_digits) const;
+ String lpad(int min_length,const String& character=" ") const;
+ String rpad(int min_length,const String& character=" ") const;
+ String sprintf(const Array& values, bool* error) const;
static String num(double p_num,int p_decimals=-1);
static String num_scientific(double p_num);
static String num_real(double p_num);
- static String num_int64(int64_t p_num);
+ static String num_int64(int64_t p_num,int base=10,bool capitalize_hex=false);
static String chr(CharType p_char);
static String md5(const uint8_t *p_md5);
bool is_numeric() const;
@@ -142,14 +146,17 @@ public:
int64_t to_int64() const;
static int to_int(const char* p_str);
static double to_double(const char* p_str);
- static double to_double(const CharType* p_str, int p_len=-1, const CharType **r_end=NULL);
+ 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);
String capitalize() const;
+ String camelcase_to_underscore() const;
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;
Vector<float> split_floats(const String &p_splitter,bool p_allow_empty=true) const;
Vector<float> split_floats_mk(const Vector<String> &p_splitters,bool p_allow_empty=true) const;
Vector<int> split_ints(const String &p_splitter,bool p_allow_empty=true) const;
@@ -183,7 +190,8 @@ public:
uint32_t hash() const; /* hash the string */
uint64_t hash64() const; /* hash the string */
String md5_text() const;
-
+ Vector<uint8_t> md5_buffer() const;
+
inline bool empty() const { return length() == 0; }
// path functions
@@ -199,9 +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 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 fdb14c0c0f..c6a55b10e6 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@
#include "scene/main/node.h"
#include "scene/gui/control.h"
#include "io/marshalls.h"
-
+#include "core_string_names.h"
@@ -258,12 +258,12 @@ bool Variant::can_convert(Variant::Type p_type_from,Variant::Type p_type_to) {
case MATRIX32: {
- static const Type invalid[]={
+ static const Type valid[]={
TRANSFORM,
NIL
};
- invalid_types=invalid;
+ valid_types=valid;
} break;
case QUAT: {
@@ -445,6 +445,256 @@ bool Variant::can_convert(Variant::Type p_type_from,Variant::Type p_type_to) {
}
+bool Variant::can_convert_strict(Variant::Type p_type_from,Variant::Type p_type_to) {
+
+ if (p_type_from==p_type_to)
+ return true;
+ if (p_type_to==NIL && p_type_from!=NIL) //nil can convert to anything
+ return true;
+
+ if (p_type_from == NIL) {
+ return (p_type_to == OBJECT);
+ };
+
+ const Type *valid_types=NULL;
+ const Type *invalid_types=NULL;
+
+ switch(p_type_to) {
+ case BOOL: {
+
+ static const Type valid[]={
+ INT,
+ REAL,
+ //STRING,
+ NIL,
+ };
+
+ valid_types=valid;
+ } break;
+ case INT: {
+
+ static const Type valid[]={
+ BOOL,
+ REAL,
+ //STRING,
+ NIL,
+ };
+
+ valid_types=valid;
+
+ } break;
+ case REAL: {
+
+ static const Type valid[]={
+ BOOL,
+ INT,
+ //STRING,
+ NIL,
+ };
+
+ valid_types=valid;
+
+ } break;
+ case STRING: {
+
+
+ static const Type valid[]={
+ NODE_PATH,
+ NIL
+ };
+
+ valid_types=valid;
+ } break;
+ case MATRIX32: {
+
+
+ static const Type valid[]={
+ TRANSFORM,
+ NIL
+ };
+
+ valid_types=valid;
+ } break;
+ case QUAT: {
+
+ static const Type valid[]={
+ MATRIX3,
+ NIL
+ };
+
+ valid_types=valid;
+
+ } break;
+ case MATRIX3: {
+
+ static const Type valid[]={
+ QUAT,
+ NIL
+ };
+
+ valid_types=valid;
+
+
+ } break;
+ case TRANSFORM: {
+
+ static const Type valid[]={
+ MATRIX32,
+ QUAT,
+ MATRIX3,
+ NIL
+ };
+
+ valid_types=valid;
+
+ } break;
+
+ case COLOR: {
+
+ static const Type valid[] = {
+ STRING,
+ INT,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+
+ case _RID: {
+
+ static const Type valid[]={
+ OBJECT,
+ NIL
+ };
+
+ valid_types=valid;
+ } break;
+ case OBJECT: {
+
+ static const Type valid[]={
+ NIL
+ };
+
+ valid_types=valid;
+ } break;
+ case NODE_PATH: {
+
+ static const Type valid[]={
+ STRING,
+ NIL
+ };
+
+ valid_types=valid;
+ } break;
+ case ARRAY: {
+
+
+ static const Type valid[]={
+ RAW_ARRAY,
+ INT_ARRAY,
+ STRING_ARRAY,
+ REAL_ARRAY,
+ COLOR_ARRAY,
+ VECTOR2_ARRAY,
+ VECTOR3_ARRAY,
+ NIL
+ };
+
+ valid_types=valid;
+ } break;
+ // arrays
+ case RAW_ARRAY: {
+
+ static const Type valid[]={
+ ARRAY,
+ NIL
+ };
+
+ valid_types=valid;
+ } break;
+ case INT_ARRAY: {
+
+ static const Type valid[]={
+ ARRAY,
+ NIL
+ };
+ valid_types=valid;
+ } break;
+ case REAL_ARRAY: {
+
+ static const Type valid[]={
+ ARRAY,
+ NIL
+ };
+
+ valid_types=valid;
+ } break;
+ case STRING_ARRAY: {
+
+ static const Type valid[]={
+ ARRAY,
+ NIL
+ };
+ valid_types=valid;
+ } break;
+ case VECTOR2_ARRAY: {
+
+ static const Type valid[]={
+ ARRAY,
+ NIL
+ };
+ valid_types=valid;
+
+ } break;
+ case VECTOR3_ARRAY: {
+
+ static const Type valid[]={
+ ARRAY,
+ NIL
+ };
+ valid_types=valid;
+
+ } break;
+ case COLOR_ARRAY: {
+
+ static const Type valid[]={
+ ARRAY,
+ NIL
+ };
+
+ valid_types=valid;
+
+ } break;
+ default: {}
+ }
+
+
+ if (valid_types) {
+
+ int i=0;
+ while(valid_types[i]!=NIL) {
+
+ if (p_type_from==valid_types[i])
+ return true;
+ i++;
+ }
+ } else if (invalid_types) {
+
+
+ int i=0;
+ while(invalid_types[i]!=NIL) {
+
+ if (p_type_from==invalid_types[i])
+ return false;
+ i++;
+ }
+ }
+
+ return false;
+
+}
+
bool Variant::operator==(const Variant& p_variant) const {
if (type!=p_variant.type) //evaluation of operator== needs to be more strict
@@ -456,6 +706,15 @@ bool Variant::operator==(const Variant& p_variant) const {
}
+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;
+ bool v;
+ Variant r;
+ evaluate(OP_LESS,*this,p_variant,r,v);
+ return r;
+}
+
bool Variant::is_zero() const {
switch( type ) {
@@ -523,7 +782,7 @@ bool Variant::is_zero() const {
} break;
case QUAT: {
- *reinterpret_cast<const Quat*>(_data._mem)==Quat();
+ return *reinterpret_cast<const Quat*>(_data._mem)==Quat();
} break;
case MATRIX3: {
@@ -619,6 +878,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) {
@@ -1276,9 +1592,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;
@@ -1394,6 +1718,10 @@ Variant::operator Color() const {
if (type==COLOR)
return *reinterpret_cast<const Color*>(_data._mem);
+ else if (type==STRING)
+ return Color::html( operator String() );
+ else if (type==INT)
+ return Color::hex( operator int() );
else
return Color();
}
@@ -1430,8 +1758,16 @@ Variant::operator RID() const {
return *reinterpret_cast<const RID*>(_data._mem);
else if (type==OBJECT && !_get_obj().ref.is_null()) {
return _get_obj().ref.get_rid();
- } else
+ } else if (type==OBJECT && _get_obj().obj) {
+ Variant::CallError ce;
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid,NULL,0,ce);
+ if (ce.error==Variant::CallError::CALL_OK && ret.get_type()==Variant::_RID) {
+ return ret;
+ }
+ return RID();
+ } else {
return RID();
+ }
}
Variant::operator Object*() const {
@@ -2631,3 +2967,138 @@ Variant Variant::call(const StringName& p_method,VARIANT_ARG_DECLARE) {
return ret;
}
+void Variant::construct_from_string(const String& p_string,Variant& r_value,ObjectConstruct p_obj_construct,void *p_construct_ud) {
+
+ r_value=Variant();
+}
+
+
+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+="}";
+
+ 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: {
+
+ DVector<int> vec = operator DVector<int>();
+ String str="IntArray([";
+ for(int i=0;i<vec.size();i++) {
+
+ 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++) {
+
+ 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+"]";
+
+ } break;
+ case OBJECT: {
+
+ 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";
+
+ } break;
+ default: {
+ return "["+get_type_name(type)+"]";
+ }
+ }
+
+}
diff --git a/core/variant.h b/core/variant.h
index 3cfecb9388..e75a2b1c92 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -165,21 +165,27 @@ public:
_FORCE_INLINE_ Type get_type() const { return type; }
static String get_type_name(Variant::Type p_type);
- static bool can_convert(Type p_type_from,Type p_type_to);
+ static bool can_convert(Type p_type_from, Type p_type_to);
+ static bool can_convert_strict(Type p_type_from, Type p_type_to);
+
+
template<class T>
static Type get_type_for() {
GetSimpleType<T> t;
Variant v(t.type);
- return v.get_type();
+ Type r = v.get_type();
+ return r;
}
+
bool is_ref() const;
_FORCE_INLINE_ bool is_num() const { return type==INT || type==REAL; };
_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;
@@ -358,7 +364,7 @@ public:
static String get_operator_name(Operator p_op);
static void evaluate(const Operator& p_op,const Variant& p_a, const Variant& p_b,Variant &r_ret,bool &r_valid);
- static _FORCE_INLINE_ Variant evaluate(Operator& p_op,const Variant& p_a, const Variant& p_b) {
+ static _FORCE_INLINE_ Variant evaluate(const Operator& p_op,const Variant& p_a, const Variant& p_b) {
bool valid=true;
Variant res;
@@ -384,9 +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 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;
void set_named(const StringName& p_index, const Variant& p_value, bool *r_valid=NULL);
Variant get_named(const StringName& p_index, bool *r_valid=NULL) const;
@@ -403,7 +410,8 @@ 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;
bool booleanize(bool &valid) const;
@@ -414,6 +422,12 @@ public:
static bool has_numeric_constant(Variant::Type p_type, const StringName& p_value);
static int get_numeric_constant_value(Variant::Type p_type, const StringName& p_value);
+ 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;
+ 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
Variant(const Variant& p_variant);
_FORCE_INLINE_ Variant() { type=NIL; }
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 8cdfce1b0a..2d10cf4d44 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -263,6 +263,8 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM1R(String,ord_at);
//VCALL_LOCALMEM2R(String,erase);
VCALL_LOCALMEM0R(String,hash);
+ VCALL_LOCALMEM0R(String,md5_text);
+ VCALL_LOCALMEM0R(String,md5_buffer);
VCALL_LOCALMEM0R(String,empty);
VCALL_LOCALMEM0R(String,is_abs_path);
VCALL_LOCALMEM0R(String,is_rel_path);
@@ -283,6 +285,36 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM1R(String,pad_decimals);
VCALL_LOCALMEM1R(String,pad_zeros);
+ static void _call_String_to_ascii(Variant& r_ret,Variant& p_self,const Variant** p_args) {
+
+ String *s = reinterpret_cast<String*>(p_self._data._mem);
+ CharString charstr = s->ascii();
+
+ ByteArray retval;
+ size_t len = charstr.length();
+ retval.resize(len);
+ ByteArray::Write w = retval.write();
+ copymem(w.ptr(), charstr.ptr(), len);
+ w = DVector<uint8_t>::Write();
+
+ r_ret = retval;
+ }
+
+ static void _call_String_to_utf8(Variant& r_ret,Variant& p_self,const Variant** p_args) {
+
+ String *s = reinterpret_cast<String*>(p_self._data._mem);
+ CharString charstr = s->utf8();
+
+ ByteArray retval;
+ size_t len = charstr.length();
+ retval.resize(len);
+ ByteArray::Write w = retval.write();
+ copymem(w.ptr(), charstr.ptr(), len);
+ w = DVector<uint8_t>::Write();
+
+ r_ret = retval;
+ }
+
VCALL_LOCALMEM0R(Vector2,normalized);
VCALL_LOCALMEM0R(Vector2,length);
@@ -290,6 +322,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM1R(Vector2,distance_to);
VCALL_LOCALMEM1R(Vector2,distance_squared_to);
VCALL_LOCALMEM1R(Vector2,angle_to);
+ VCALL_LOCALMEM1R(Vector2,angle_to_point);
VCALL_LOCALMEM2R(Vector2,linear_interpolate);
VCALL_LOCALMEM4R(Vector2,cubic_interpolate);
VCALL_LOCALMEM1R(Vector2,rotated);
@@ -300,6 +333,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,angle);
// VCALL_LOCALMEM1R(Vector2,cross);
VCALL_LOCALMEM0R(Rect2,get_area);
@@ -325,8 +359,13 @@ 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);
+ VCALL_LOCALMEM1R(Vector3, reflect);
+
VCALL_LOCALMEM0R(Plane,normalized);
VCALL_LOCALMEM0R(Plane,center);
@@ -370,6 +409,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);
@@ -419,6 +459,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM0(Array,sort);
VCALL_LOCALMEM2(Array,sort_custom);
VCALL_LOCALMEM0(Array,invert);
+ VCALL_LOCALMEM0R(Array,is_shared);
static void _call_ByteArray_get_string_from_ascii(Variant& r_ret,Variant& p_self,const Variant** p_args) {
@@ -504,15 +545,15 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM1(ColorArray,append_array);
#define VCALL_PTR0(m_type,m_method)\
-static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(); }
+static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(); }
#define VCALL_PTR0R(m_type,m_method)\
static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(); }
#define VCALL_PTR1(m_type,m_method)\
-static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0]); }
+static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0]); }
#define VCALL_PTR1R(m_type,m_method)\
static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0]); }
#define VCALL_PTR2(m_type,m_method)\
-static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1]); }
+static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1]); }
#define VCALL_PTR2R(m_type,m_method)\
static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1]); }
#define VCALL_PTR3(m_type,m_method)\
@@ -520,11 +561,11 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
#define VCALL_PTR3R(m_type,m_method)\
static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2]); }
#define VCALL_PTR4(m_type,m_method)\
-static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3]); }
+static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3]); }
#define VCALL_PTR4R(m_type,m_method)\
static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3]); }
#define VCALL_PTR5(m_type,m_method)\
-static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3],*p_args[4]); }
+static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3],*p_args[4]); }
#define VCALL_PTR5R(m_type,m_method)\
static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3],*p_args[4]); }
@@ -533,9 +574,11 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_PTR0R(Image,get_height);
VCALL_PTR0R(Image,empty);
VCALL_PTR3R(Image,get_pixel);
+ VCALL_PTR4(Image, put_pixel);
VCALL_PTR0R(Image,get_used_rect);
VCALL_PTR3R(Image,brushed);
VCALL_PTR1R(Image,load);
+ VCALL_PTR1R(Image,save_png);
VCALL_PTR3(Image,brush_transfer);
VCALL_PTR1R(Image,get_rect);
VCALL_PTR1R(Image,compressed);
@@ -543,6 +586,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_PTR3R(Image, resized);
VCALL_PTR0R(Image, get_data);
VCALL_PTR3(Image, blit_rect);
+ VCALL_PTR1R(Image, converted);
VCALL_PTR0R( AABB, get_area );
VCALL_PTR0R( AABB, has_no_area );
@@ -552,6 +596,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_PTR1R( AABB, merge );
VCALL_PTR1R( AABB, intersection );
VCALL_PTR1R( AABB, intersects_plane );
+ VCALL_PTR2R( AABB, intersects_segment );
VCALL_PTR1R( AABB, has_point );
VCALL_PTR1R( AABB, get_support );
VCALL_PTR0R( AABB, get_longest_axis );
@@ -596,6 +641,25 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
}
}
+ static void _call_Matrix32_basis_xform(Variant& r_ret,Variant& p_self,const Variant** p_args) {
+
+ switch(p_args[0]->type) {
+
+ case Variant::VECTOR2: r_ret=reinterpret_cast<Matrix32*>(p_self._data._ptr)->basis_xform( p_args[0]->operator Vector2()); return;
+ default: r_ret=Variant();
+ }
+
+ }
+
+ static void _call_Matrix32_basis_xform_inv(Variant& r_ret,Variant& p_self,const Variant** p_args) {
+
+ switch(p_args[0]->type) {
+
+ case Variant::VECTOR2: r_ret=reinterpret_cast<Matrix32*>(p_self._data._ptr)->basis_xform_inv( p_args[0]->operator Vector2()); return;
+ default: r_ret=Variant();
+ }
+ }
+
VCALL_PTR0R( Matrix3, inverse );
VCALL_PTR0R( Matrix3, transposed );
@@ -654,7 +718,10 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_PTR0R( InputEvent, is_pressed );
VCALL_PTR1R( InputEvent, is_action );
+ VCALL_PTR1R( InputEvent, is_action_pressed );
+ VCALL_PTR1R( InputEvent, is_action_released );
VCALL_PTR0R( InputEvent, is_echo );
+ VCALL_PTR2( InputEvent, set_as_action );
struct ConstructData {
@@ -688,6 +755,12 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
r_ret=Rect2(*p_args[0],*p_args[1],*p_args[2],*p_args[3]);
}
+ static void Matrix32_init2(Variant& r_ret,const Variant** p_args) {
+
+ Matrix32 m(*p_args[0], *p_args[1]);
+ r_ret=m;
+ }
+
static void Matrix32_init3(Variant& r_ret,const Variant** p_args) {
Matrix32 m;
@@ -726,6 +799,11 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
r_ret=Quat(*p_args[0],*p_args[1],*p_args[2],*p_args[3]);
}
+ static void Quat_init2(Variant& r_ret,const Variant** p_args) {
+
+ r_ret=Quat(((Vector3)(*p_args[0])),((float)(*p_args[1])));
+ }
+
static void Color_init1(Variant& r_ret,const Variant** p_args) {
r_ret=Color(*p_args[0],*p_args[1],*p_args[2],*p_args[3]);
@@ -780,6 +858,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,
@@ -881,7 +964,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());
@@ -957,7 +1040,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) {
@@ -995,7 +1078,7 @@ Variant Variant::construct(const Variant::Type p_type,const Variant** p_args,int
case STRING_ARRAY: return (StringArray(*p_args[0]));
case VECTOR2_ARRAY: return (Vector2Array(*p_args[0])); // 25
case VECTOR3_ARRAY: return (Vector3Array(*p_args[0])); // 25
- case COLOR_ARRAY: return (Color(*p_args[0]));
+ case COLOR_ARRAY: return (ColorArray(*p_args[0]));
default: return Variant();
}
}
@@ -1003,6 +1086,32 @@ Variant Variant::construct(const Variant::Type p_type,const Variant** p_args,int
return Variant();
}
+
+bool Variant::has_method(const StringName& p_method) const {
+
+
+ if (type==OBJECT) {
+ Object *obj = operator Object*();
+ if (!obj)
+ return false;
+#ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton()) {
+ if (ObjectDB::instance_validate(obj)) {
+#endif
+ return obj->has_method(p_method);
+#ifdef DEBUG_ENABLED
+
+ }
+ }
+#endif
+ }
+
+
+ const _VariantCall::TypeFunc &fd = _VariantCall::type_funcs[type];
+ return fd.functions.has(p_method);
+
+}
+
void Variant::get_method_list(List<MethodInfo> *p_list) const {
@@ -1032,7 +1141,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);
}
@@ -1049,6 +1158,7 @@ void Variant::get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_lis
const _VariantCall::ConstructData &cd = E->get();
MethodInfo mi;
mi.name=Variant::get_type_name(p_type);
+ mi.return_val.type=p_type;
for(int i=0;i<cd.arg_count;i++) {
PropertyInfo pi;
@@ -1071,6 +1181,7 @@ void Variant::get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_lis
pi.name="from";
pi.type=Variant::Type(i);
mi.arguments.push_back(pi);
+ mi.return_val.type=p_type;
p_list->push_back(mi);
}
}
@@ -1150,9 +1261,10 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC0(STRING,STRING,String,capitalize,varray());
ADDFUNC2(STRING,STRING_ARRAY,String,split,STRING,"divisor",BOOL,"allow_empty",varray(true));
ADDFUNC2(STRING,REAL_ARRAY,String,split_floats,STRING,"divisor",BOOL,"allow_empty",varray(true));
- ADDFUNC0(STRING,STRING,String,to_upper,varray());
+ ADDFUNC0(STRING,STRING,String,to_upper,varray());
ADDFUNC0(STRING,STRING,String,to_lower,varray());
+
ADDFUNC1(STRING,STRING,String,left,INT,"pos",varray());
ADDFUNC1(STRING,STRING,String,right,INT,"pos",varray());
ADDFUNC0(STRING,STRING,String,strip_edges,varray());
@@ -1162,6 +1274,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC1(STRING,STRING,String,ord_at,INT,"at",varray());
// ADDFUNC2(STRING,String,erase,INT,INT,varray());
ADDFUNC0(STRING,INT,String,hash,varray());
+ ADDFUNC0(STRING,STRING,String,md5_text,varray());
+ ADDFUNC0(STRING,RAW_ARRAY,String,md5_buffer,varray());
ADDFUNC0(STRING,BOOL,String,empty,varray());
ADDFUNC0(STRING,BOOL,String,is_abs_path,varray());
ADDFUNC0(STRING,BOOL,String,is_rel_path,varray());
@@ -1182,12 +1296,18 @@ _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,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,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());
ADDFUNC1(VECTOR2,REAL,Vector2,angle_to,VECTOR2,"to",varray());
+ ADDFUNC1(VECTOR2,REAL,Vector2,angle_to_point,VECTOR2,"to",varray());
ADDFUNC2(VECTOR2,VECTOR2,Vector2,linear_interpolate,VECTOR2,"b",REAL,"t",varray());
ADDFUNC4(VECTOR2,VECTOR2,Vector2,cubic_interpolate,VECTOR2,"b",VECTOR2,"pre_a",VECTOR2,"post_b",REAL,"t",varray());
ADDFUNC1(VECTOR2,VECTOR2,Vector2,rotated,REAL,"phi",varray());
@@ -1197,8 +1317,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC1(VECTOR2,VECTOR2,Vector2,snapped,VECTOR2,"by",varray());
ADDFUNC0(VECTOR2,REAL,Vector2,get_aspect,varray());
ADDFUNC1(VECTOR2,REAL,Vector2,dot,VECTOR2,"with",varray());
- ADDFUNC1(VECTOR2,REAL,Vector2,slide,VECTOR2,"vec",varray());
- ADDFUNC1(VECTOR2,REAL,Vector2,reflect,VECTOR2,"vec",varray());
+ ADDFUNC1(VECTOR2,VECTOR2,Vector2,slide,VECTOR2,"vec",varray());
+ ADDFUNC1(VECTOR2,VECTOR2,Vector2,reflect,VECTOR2,"vec",varray());
//ADDFUNC1(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray());
ADDFUNC0(RECT2,REAL,Rect2,get_area,varray());
@@ -1224,8 +1344,12 @@ _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());
+ ADDFUNC1(VECTOR3,VECTOR3,Vector3,reflect,VECTOR3,"by",varray());
ADDFUNC0(PLANE,PLANE,Plane,normalized,varray());
ADDFUNC0(PLANE,VECTOR3,Plane,center,varray());
@@ -1243,6 +1367,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());
@@ -1261,8 +1386,10 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC0(IMAGE, INT, Image, get_height, varray());
ADDFUNC0(IMAGE, BOOL, Image, empty, varray());
ADDFUNC3(IMAGE, COLOR, Image, get_pixel, INT, "x", INT, "y", INT, "mipmap_level", varray(0));
+ ADDFUNC4(IMAGE, NIL, Image, put_pixel, INT, "x", INT, "y", COLOR, "color", INT, "mipmap_level", varray(0));
ADDFUNC3(IMAGE, IMAGE, Image, brushed, IMAGE, "src", IMAGE, "brush", VECTOR2, "pos", varray(0));
ADDFUNC1(IMAGE, INT, Image, load, STRING, "path", varray(0));
+ ADDFUNC1(IMAGE, INT, Image, save_png, STRING, "path", varray(0));
ADDFUNC3(IMAGE, NIL, Image, brush_transfer, IMAGE, "src", IMAGE, "brush", VECTOR2, "pos", varray(0));
ADDFUNC0(IMAGE, RECT2, Image, get_used_rect, varray(0));
ADDFUNC1(IMAGE, IMAGE, Image, get_rect, RECT2, "area", varray(0));
@@ -1271,6 +1398,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC3(IMAGE, IMAGE, Image, resized, INT, "x", INT, "y", INT, "interpolation", varray(((int)Image::INTERPOLATE_BILINEAR)));
ADDFUNC0(IMAGE, RAW_ARRAY, Image, get_data, varray());
ADDFUNC3(IMAGE, NIL, Image, blit_rect, IMAGE, "src", RECT2, "src_rect", VECTOR2, "dest", varray(0));
+ ADDFUNC1(IMAGE, IMAGE, Image, converted, INT, "format", varray(0));
ADDFUNC0(_RID,INT,RID,get_id,varray());
@@ -1307,6 +1435,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC0(ARRAY,NIL,Array,sort,varray());
ADDFUNC2(ARRAY,NIL,Array,sort_custom,OBJECT,"obj",STRING,"func",varray());
ADDFUNC0(ARRAY,NIL,Array,invert,varray());
+ ADDFUNC0(ARRAY,BOOL,Array,is_shared,varray());
ADDFUNC0(RAW_ARRAY,INT,ByteArray,size,varray());
ADDFUNC2(RAW_ARRAY,NIL,ByteArray,set,INT,"idx",INT,"byte",varray());
@@ -1364,6 +1493,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC1(_AABB,_AABB,AABB,merge,_AABB,"with",varray());
ADDFUNC1(_AABB,_AABB,AABB,intersection,_AABB,"with",varray());
ADDFUNC1(_AABB,BOOL,AABB,intersects_plane,PLANE,"plane",varray());
+ ADDFUNC2(_AABB,BOOL,AABB,intersects_segment,VECTOR3,"from",VECTOR3,"to",varray());
ADDFUNC1(_AABB,BOOL,AABB,has_point,VECTOR3,"point",varray());
ADDFUNC1(_AABB,VECTOR3,AABB,get_support,VECTOR3,"dir",varray());
ADDFUNC0(_AABB,VECTOR3,AABB,get_longest_axis,varray());
@@ -1387,6 +1517,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC1(MATRIX32,MATRIX32,Matrix32,translated,VECTOR2,"offset",varray());
ADDFUNC1(MATRIX32,MATRIX32,Matrix32,xform,NIL,"v",varray());
ADDFUNC1(MATRIX32,MATRIX32,Matrix32,xform_inv,NIL,"v",varray());
+ ADDFUNC1(MATRIX32,MATRIX32,Matrix32,basis_xform,NIL,"v",varray());
+ ADDFUNC1(MATRIX32,MATRIX32,Matrix32,basis_xform_inv,NIL,"v",varray());
ADDFUNC2(MATRIX32,MATRIX32,Matrix32,interpolate_with,MATRIX32,"m",REAL,"c",varray());
ADDFUNC0(MATRIX3,MATRIX3,Matrix3,inverse,varray());
@@ -1414,14 +1546,17 @@ _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());
+ ADDFUNC1(INPUT_EVENT,BOOL,InputEvent,is_action_pressed,STRING,"is_action_pressed",varray());
+ ADDFUNC1(INPUT_EVENT,BOOL,InputEvent,is_action_released,STRING,"is_action_released",varray());
ADDFUNC0(INPUT_EVENT,BOOL,InputEvent,is_echo,varray());
+ ADDFUNC2(INPUT_EVENT,NIL,InputEvent,set_as_action,STRING,"action",BOOL,"pressed",varray());
/* REGISTER CONSTRUCTORS */
@@ -1430,6 +1565,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
_VariantCall::add_constructor(_VariantCall::Rect2_init1,Variant::RECT2,"pos",Variant::VECTOR2,"size",Variant::VECTOR2);
_VariantCall::add_constructor(_VariantCall::Rect2_init2,Variant::RECT2,"x",Variant::REAL,"y",Variant::REAL,"width",Variant::REAL,"height",Variant::REAL);
+ _VariantCall::add_constructor(_VariantCall::Matrix32_init2,Variant::MATRIX32,"rot",Variant::REAL,"pos",Variant::VECTOR2);
_VariantCall::add_constructor(_VariantCall::Matrix32_init3,Variant::MATRIX32,"x_axis",Variant::VECTOR2,"y_axis",Variant::VECTOR2,"origin",Variant::VECTOR2);
_VariantCall::add_constructor(_VariantCall::Vector3_init1,Variant::VECTOR3,"x",Variant::REAL,"y",Variant::REAL,"z",Variant::REAL);
@@ -1439,6 +1575,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
_VariantCall::add_constructor(_VariantCall::Plane_init3,Variant::PLANE,"normal",Variant::VECTOR3,"d",Variant::REAL);
_VariantCall::add_constructor(_VariantCall::Quat_init1,Variant::QUAT,"x",Variant::REAL,"y",Variant::REAL,"z",Variant::REAL,"w",Variant::REAL);
+ _VariantCall::add_constructor(_VariantCall::Quat_init2,Variant::QUAT,"axis",Variant::VECTOR3,"angle",Variant::REAL);
_VariantCall::add_constructor(_VariantCall::Color_init1,Variant::COLOR,"r",Variant::REAL,"g",Variant::REAL,"b",Variant::REAL,"a",Variant::REAL);
_VariantCall::add_constructor(_VariantCall::Color_init2,Variant::COLOR,"r",Variant::REAL,"g",Variant::REAL,"b",Variant::REAL);
@@ -1451,6 +1588,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;
@@ -1509,9 +1648,3 @@ void unregister_variant_methods() {
}
-
-
-
-
-
-
diff --git a/core/variant_call_bind.h b/core/variant_call_bind.h
index 39fe25e8c7..613669203d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/variant_construct_string.cpp b/core/variant_construct_string.cpp
new file mode 100644
index 0000000000..0308fd3180
--- /dev/null
+++ b/core/variant_construct_string.cpp
@@ -0,0 +1,433 @@
+
+#include "variant.h"
+
+class VariantConstruct {
+
+ enum TokenType {
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_IDENTIFIER,
+ TK_STRING,
+ TK_NUMBER,
+ TK_COLON,
+ TK_COMMA,
+ TK_EOF,
+ TK_MAX
+ };
+
+ enum Expecting {
+
+ EXPECT_OBJECT,
+ EXPECT_OBJECT_KEY,
+ EXPECT_COLON,
+ EXPECT_OBJECT_VALUE,
+ };
+
+ struct Token {
+
+ TokenType type;
+ Variant value;
+ };
+
+ static const char * tk_name[TK_MAX];
+
+ static String _print_var(const Variant& p_var);
+
+ static Error _get_token(const CharType *p_str,int &index, int p_len,Token& r_token,int &line,String &r_err_str);
+ static Error _parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
+ static Error _parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
+ static Error _parse_dict(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
+
+public:
+
+ static Error parse(const String& p_string,Variant& r_ret,String &r_err_str,int &r_err_line,Variant::ObjectConstruct* p_construct,void* p_ud);
+};
+
+
+const char * VariantConstruct::tk_name[TK_MAX] = {
+ "'{'",
+ "'}'",
+ "'['",
+ "']'",
+ "identifier",
+ "string",
+ "number",
+ "':'",
+ "','",
+ "EOF",
+};
+
+
+
+Error VariantConstruct::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_token,int &line,String &r_err_str) {
+
+ while (true) {
+ switch(p_str[idx]) {
+
+ case '\n': {
+
+ line++;
+ idx++;
+ break;
+ };
+ case 0: {
+ r_token.type=TK_EOF;
+ return OK;
+ } break;
+ case '{': {
+
+ r_token.type=TK_CURLY_BRACKET_OPEN;
+ idx++;
+ return OK;
+ };
+ case '}': {
+
+ r_token.type=TK_CURLY_BRACKET_CLOSE;
+ idx++;
+ return OK;
+ };
+ case '[': {
+
+ r_token.type=TK_BRACKET_OPEN;
+ idx++;
+ return OK;
+ };
+ case ']': {
+
+ r_token.type=TK_BRACKET_CLOSE;
+ idx++;
+ return OK;
+ };
+ case ':': {
+
+ r_token.type=TK_COLON;
+ idx++;
+ return OK;
+ };
+ case ',': {
+
+ r_token.type=TK_COMMA;
+ idx++;
+ return OK;
+ };
+ case '"': {
+
+ idx++;
+ String str;
+ while(true) {
+ if (p_str[idx]==0) {
+ r_err_str="Unterminated String";
+ return ERR_PARSE_ERROR;
+ } else if (p_str[idx]=='"') {
+ idx++;
+ break;
+ } else if (p_str[idx]=='\\') {
+ //escaped characters...
+ idx++;
+ CharType next = p_str[idx];
+ if (next==0) {
+ r_err_str="Unterminated String";
+ 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 '\"': res='\"'; break;
+ case '\\': res='\\'; break;
+ case '/': res='/'; break; //wtf
+ case 'u': {
+ //hexnumbarh - oct is deprecated
+
+
+ for(int j=0;j<4;j++) {
+ CharType c = p_str[idx+j+1];
+ if (c==0) {
+ r_err_str="Unterminated String";
+ 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";
+ 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;
+
+
+ }
+ idx+=4; //will add at the end anyway
+
+
+ } break;
+ default: {
+
+ r_err_str="Invalid escape sequence";
+ return ERR_PARSE_ERROR;
+ } break;
+ }
+
+ str+=res;
+
+ } else {
+ if (p_str[idx]=='\n')
+ line++;
+ str+=p_str[idx];
+ }
+ idx++;
+ }
+
+ r_token.type=TK_STRING;
+ r_token.value=str;
+ return OK;
+
+ } break;
+ default: {
+
+ if (p_str[idx]<=32) {
+ idx++;
+ break;
+ }
+
+ if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) {
+ //a number
+ const CharType *rptr;
+ double number = String::to_double(&p_str[idx],&rptr);
+ idx+=(rptr - &p_str[idx]);
+ r_token.type=TK_NUMBER;
+ r_token.value=number;
+ return OK;
+
+ } else if ((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {
+
+ String id;
+
+ while((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {
+
+ id+=p_str[idx];
+ idx++;
+ }
+
+ r_token.type=TK_IDENTIFIER;
+ r_token.value=id;
+ return OK;
+ } else {
+ r_err_str="Unexpected character.";
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ }
+ }
+
+ return ERR_PARSE_ERROR;
+}
+
+
+
+Error VariantConstruct::_parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
+
+
+ if (token.type==TK_CURLY_BRACKET_OPEN) {
+
+ Dictionary d;
+ Error err = _parse_dict(d,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
+ if (err)
+ return err;
+ value=d;
+ return OK;
+ } else if (token.type==TK_BRACKET_OPEN) {
+
+ Array a;
+ Error err = _parse_array(a,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
+ if (err)
+ return err;
+ value=a;
+ return OK;
+
+ } else if (token.type==TK_IDENTIFIER) {
+
+ String id = token.value;
+ if (id=="true")
+ value=true;
+ else if (id=="false")
+ value=false;
+ else if (id=="null")
+ value=Variant();
+ else {
+ r_err_str="Expected 'true','false' or 'null', got '"+id+"'.";
+ return ERR_PARSE_ERROR;
+ }
+ 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 {
+ r_err_str="Expected value, got "+String(tk_name[token.type])+".";
+ return ERR_PARSE_ERROR;
+ }
+
+ return ERR_PARSE_ERROR;
+}
+
+
+Error VariantConstruct::_parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
+
+ Token token;
+ bool need_comma=false;
+
+
+ while(index<p_len) {
+
+ Error err = _get_token(p_str,index,p_len,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(v,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
+ if (err)
+ return err;
+
+ array.push_back(v);
+ need_comma=true;
+
+ }
+
+ return OK;
+
+}
+
+Error VariantConstruct::_parse_dict(Dictionary &dict,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
+
+ bool at_key=true;
+ Variant key;
+ Token token;
+ bool need_comma=false;
+
+
+ while(index<p_len) {
+
+
+ if (at_key) {
+
+ Error err = _get_token(p_str,index,p_len,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(key,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
+
+
+ if (err!=OK)
+ return err;
+
+ err = _get_token(p_str,index,p_len,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_str,index,p_len,token,line,r_err_str);
+ if (err!=OK)
+ return err;
+
+ Variant v;
+ err = _parse_value(v,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
+ if (err)
+ return err;
+ dict[key]=v;
+ need_comma=true;
+ at_key=true;
+ }
+ }
+
+ return OK;
+}
+
+
+Error VariantConstruct::parse(const String& p_string,Variant& r_ret,String &r_err_str,int &r_err_line,Variant::ObjectConstruct* p_construct,void* p_ud) {
+
+
+ const CharType *str = p_string.ptr();
+ int idx = 0;
+ int len = p_string.length();
+ Token token;
+ r_err_line=0;
+ String aux_key;
+
+ Error err = _get_token(str,idx,len,token,r_err_line,r_err_str);
+ if (err)
+ return err;
+
+ return _parse_value(r_ret,token,str,idx,len,r_err_line,r_err_str,p_construct,p_ud);
+}
+
+
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index 6c2667c7e9..e33b79e63c 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -165,6 +165,12 @@ r_valid=false;\
return;}
#define DEFAULT_OP_ARRAY_EQ(m_name,m_type)\
+DEFAULT_OP_ARRAY_OP(m_name,m_type,!=,!=,true,false,false)
+
+#define DEFAULT_OP_ARRAY_LT(m_name,m_type)\
+DEFAULT_OP_ARRAY_OP(m_name,m_type,<,!=,false,a_len<array_b.size(),true)
+
+#define DEFAULT_OP_ARRAY_OP(m_name,m_type,m_opa,m_opb,m_ret_def,m_ret_s,m_ret_f)\
case m_name: { \
if (p_a.type!=p_b.type) {\
r_valid=false;\
@@ -174,19 +180,19 @@ case m_name: { \
const DVector<m_type> &array_b=*reinterpret_cast<const DVector<m_type> *>(p_b._data._mem);\
\
int a_len = array_a.size();\
- if (a_len!=array_b.size()){\
- _RETURN( false);\
+ if (a_len m_opa array_b.size()){\
+ _RETURN( m_ret_s);\
}else {\
\
DVector<m_type>::Read ra = array_a.read();\
DVector<m_type>::Read rb = array_b.read();\
\
for(int i=0;i<a_len;i++) {\
- if (ra[i]!=rb[i])\
- _RETURN( false);\
+ if (ra[i] m_opb rb[i])\
+ _RETURN( m_ret_f);\
}\
\
- _RETURN( true);\
+ _RETURN( m_ret_def);\
}\
}
@@ -290,8 +296,9 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
if (arr_b->size()!=l)
_RETURN( false );
for(int i=0;i<l;i++) {
- if (!(arr_a[i]==arr_b[i]))
+ if (!((*arr_a)[i]==(*arr_b)[i])) {
_RETURN( false );
+ }
}
_RETURN( true );
@@ -356,14 +363,33 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
} break;
DEFAULT_OP_FAIL(INPUT_EVENT);
DEFAULT_OP_FAIL(DICTIONARY);
- DEFAULT_OP_FAIL(ARRAY);
- DEFAULT_OP_FAIL(RAW_ARRAY);
- DEFAULT_OP_FAIL(INT_ARRAY);
- DEFAULT_OP_FAIL(REAL_ARRAY);
- DEFAULT_OP_FAIL(STRING_ARRAY);
- DEFAULT_OP_FAIL(VECTOR2_ARRAY);
- DEFAULT_OP_FAIL(VECTOR3_ARRAY);
- DEFAULT_OP_FAIL(COLOR_ARRAY);
+ case ARRAY: {
+
+ if (p_b.type!=ARRAY)
+ _RETURN( false );
+
+ const Array *arr_a=reinterpret_cast<const Array*>(p_a._data._mem);
+ const Array *arr_b=reinterpret_cast<const Array*>(p_b._data._mem);
+
+ int l = arr_a->size();
+ if (arr_b->size()<l)
+ _RETURN( false );
+ for(int i=0;i<l;i++) {
+ if (!((*arr_a)[i]<(*arr_b)[i])) {
+ _RETURN( true );
+ }
+ }
+
+ _RETURN( false );
+
+ } break;
+ DEFAULT_OP_ARRAY_LT(RAW_ARRAY,uint8_t);
+ DEFAULT_OP_ARRAY_LT(INT_ARRAY,int);
+ DEFAULT_OP_ARRAY_LT(REAL_ARRAY,real_t);
+ DEFAULT_OP_ARRAY_LT(STRING_ARRAY,String);
+ DEFAULT_OP_ARRAY_LT(VECTOR2_ARRAY,Vector3);
+ DEFAULT_OP_ARRAY_LT(VECTOR3_ARRAY,Vector3);
+ DEFAULT_OP_ARRAY_LT(COLOR_ARRAY,Color);
case VARIANT_MAX: {
r_valid=false;
return;
@@ -471,7 +497,7 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
}
const Array &array_a=*reinterpret_cast<const Array *>(p_a._data._mem);
const Array &array_b=*reinterpret_cast<const Array *>(p_b._data._mem);
- Array sum;
+ Array sum(array_a.is_shared() || array_b.is_shared());
int asize=array_a.size();
int bsize=array_b.size();
sum.resize(asize+bsize);
@@ -552,12 +578,29 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
if (p_b.type==MATRIX32) {
_RETURN( *p_a._data._matrix32 * *p_b._data._matrix32 );
};
+ if (p_b.type==VECTOR2) {
+ _RETURN( p_a._data._matrix32->xform( *(const Vector2*)p_b._data._mem) );
+ };
r_valid=false;
return;
} 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: {
@@ -736,6 +779,24 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
}
#endif
_RETURN( p_a._data._int % p_b._data._int );
+
+ } else if (p_a.type==STRING) {
+ const String* format=reinterpret_cast<const String*>(p_a._data._mem);
+
+ String result;
+ bool error;
+ if (p_b.type==ARRAY) {
+ // e.g. "frog %s %d" % ["fish", 12]
+ const Array* args=reinterpret_cast<const Array*>(p_b._data._mem);
+ result=format->sprintf(*args, &error);
+ } else {
+ // e.g. "frog %d" % 12
+ Array args;
+ args.push_back(p_b);
+ result=format->sprintf(args, &error);
+ }
+ r_valid = !error;
+ _RETURN(result);
}
r_valid=false;
@@ -922,21 +983,31 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
case REAL: { return; } break;
case STRING: {
- if (p_value.type!=Variant::STRING)
+
+ if (p_index.type!=Variant::INT && p_index.type!=Variant::REAL)
return;
- if (p_index.get_type()==Variant::INT || p_index.get_type()==Variant::REAL) {
- //string index
- int idx=p_index;
- String *str=reinterpret_cast<String*>(_data._mem);
- if (idx >=0 && idx<str->length()) {
- String chr = p_value;
- *str = str->substr(0,idx-1)+chr+str->substr(idx+1,str->length());
- valid=true;
- return;
- }
+ int idx=p_index;
+ String *str=reinterpret_cast<String*>(_data._mem);
+ if (idx <0 || idx>=str->length())
+ return;
+
+ String chr;
+ if (p_value.type==Variant::INT || p_value.type==Variant::REAL) {
+
+ chr = String::chr(p_value);
+ } else if (p_value.type==Variant::STRING) {
+
+ chr = p_value;
+ } else {
+ return;
}
+ *str = str->substr(0,idx-1)+chr+str->substr(idx+1,str->length());
+ valid=true;
+ return;
+
+
} break;
case VECTOR2: {
@@ -951,7 +1022,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
Vector2 *v=reinterpret_cast<Vector2*>(_data._mem);
valid=true;
- v[idx]=p_value;
+ (*v)[idx]=p_value;
return;
}
} else if (p_index.get_type()==Variant::STRING) {
@@ -1045,7 +1116,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
Vector3 *v=reinterpret_cast<Vector3*>(_data._mem);
valid=true;
- v[idx]=p_value;
+ (*v)[idx]=p_value;
return;
}
} else if (p_index.get_type()==Variant::STRING) {
@@ -1145,6 +1216,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
if (p_value.type!=Variant::VECTOR3)
return;
+
if (p_index.get_type()==Variant::STRING) {
//scalar name
@@ -1181,6 +1253,24 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
v->set_axis(index,p_value);
return;
}
+ } else if (p_index.get_type()==Variant::STRING) {
+
+ const String *str=reinterpret_cast<const String*>(p_index._data._mem);
+ Matrix3 *v=_data._matrix3;
+
+ if (*str=="x") {
+ valid=true;
+ v->set_axis(0,p_value);
+ return;
+ } else if (*str=="y" ) {
+ valid=true;
+ v->set_axis(1,p_value);
+ return;
+ } else if (*str=="z" ) {
+ valid=true;
+ v->set_axis(2,p_value);
+ return;
+ }
}
} break;
@@ -1658,6 +1748,19 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
return;
}
}
+ if (ie.type == InputEvent::ACTION) {
+
+ if (str =="action") {
+ valid=true;
+ ie.action.action=p_value;
+ return;
+ }
+ else if (str == "pressed") {
+ valid=true;
+ ie.action.pressed=p_value;
+ return;
+ }
+ }
} break;
case DICTIONARY: {
@@ -2021,6 +2124,21 @@ Variant Variant::get(const Variant& p_index, bool *r_valid) const {
valid=true;
return v->get_axis(index);
}
+ } else if (p_index.get_type()==Variant::STRING) {
+
+ const String *str=reinterpret_cast<const String*>(p_index._data._mem);
+ const Matrix3 *v=_data._matrix3;
+
+ if (*str=="x") {
+ valid=true;
+ return v->get_axis(0);
+ } else if (*str=="y" ) {
+ valid=true;
+ return v->get_axis(1);
+ } else if (*str=="z" ) {
+ valid=true;
+ return v->get_axis(2);
+ }
}
} break;
@@ -2321,6 +2439,17 @@ Variant Variant::get(const Variant& p_index, bool *r_valid) const {
return Vector2(ie.screen_drag.speed_x,ie.screen_drag.speed_y);
}
}
+ if (ie.type == InputEvent::ACTION) {
+
+ if (str =="action") {
+ valid=true;
+ return ie.action.action;
+ }
+ else if (str == "pressed") {
+ valid=true;
+ return ie.action.pressed;
+ }
+ }
} break;
case DICTIONARY: {
@@ -2458,7 +2587,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;
@@ -2506,7 +2635,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;
}
@@ -2689,9 +2818,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: {
@@ -3273,7 +3402,15 @@ Variant Variant::iter_get(const Variant& r_iter,bool &r_valid) const {
void Variant::interpolate(const Variant& a, const Variant& b, float c,Variant &r_dst) {
if (a.type!=b.type) {
- r_dst=a;
+ if (a.is_num() && b.is_num()) {
+ //not as efficient but..
+ real_t va=a;
+ real_t vb=b;
+ r_dst=(1.0-c) * va + vb * c;
+
+ } else {
+ r_dst=a;
+ }
return;
}
diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp
new file mode 100644
index 0000000000..fed8c28740
--- /dev/null
+++ b/core/variant_parser.cpp
@@ -0,0 +1,1495 @@
+#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();
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+const char * VariantParser::tk_name[TK_MAX] = {
+ "'{'",
+ "'}'",
+ "'['",
+ "']'",
+ "'('",
+ "')'",
+ "identifier",
+ "string",
+ "number",
+ "':'",
+ "','",
+ "'='",
+ "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 ',': {
+
+ r_token.type=TK_COMMA;
+ return OK;
+ };
+ case '=': {
+
+ r_token.type=TK_EQUAL;
+ 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;
+}
+
+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 (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=="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_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ 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;
+ }
+
+ 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 {
+ 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 {
+ 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) {
+
+ r_tag.fields.clear();
+
+ if (token.type!=TK_BRACKET_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 (tag name)";
+ return ERR_PARSE_ERROR;
+ }
+
+ r_tag.name=token.value;
+
+ 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 (token.type!=TK_IDENTIFIER) {
+ r_err_str="Expected Identifier";
+ return ERR_PARSE_ERROR;
+ }
+
+ String id=token.value;
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_EQUAL) {
+ r_err_str="Expected '='";
+ 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) {
+
+ 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);
+
+}
+
+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) {
+
+
+ //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=='[' && 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);
+
+ 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);
+
+}
+
+
diff --git a/core/variant_parser.h b/core/variant_parser.h
new file mode 100644
index 0000000000..e1d25f7512
--- /dev/null
+++ b/core/variant_parser.h
@@ -0,0 +1,103 @@
+#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; }
+
+ };
+
+ 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_COLON,
+ TK_COMMA,
+ 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_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);
+
+public:
+
+ static Error parse_tag(Stream *p_stream, int &line, String &r_err_str,Tag& r_tag,ResourceParser *p_res_parser=NULL);
+ 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);
+
+ 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);
+};
+
+#endif // VARIANT_PARSER_H
diff --git a/core/vector.h b/core/vector.h
index 90a9bf715b..78dff5eadb 100644
--- a/core/vector.h
+++ b/core/vector.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
@@ -104,7 +104,7 @@ public:
template <class T_val>
- int find(T_val& p_val) const;
+ int find(const T_val& p_val) const;
void set(int p_index,T p_elem);
T get(int p_index) const;
@@ -149,7 +149,16 @@ public:
sort_custom<_DefaultComparator<T> >();
}
+ void ordered_insert(const T& p_val) {
+ int i;
+ for (i=0; i<size(); i++) {
+ if (p_val < operator[](i)) {
+ break;
+ };
+ };
+ insert(i, p_val);
+ }
void operator=(const Vector& p_from);
Vector(const Vector& p_from);
@@ -165,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
@@ -180,7 +189,7 @@ void Vector<T>::_unref(void *p_data) {
}
// free mem
- memfree(p_data);
+ memfree((uint8_t*)p_data-sizeof(int)-sizeof(SafeRefCount));
}
@@ -192,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();
@@ -206,13 +216,13 @@ void Vector<T>::_copy_on_write() {
}
_unref(_ptr);
- _ptr=src_new;
+ _ptr=_data;
}
}
template<class T> template<class T_val>
-int Vector<T>::find(T_val& p_val) const {
+int Vector<T>::find(const T_val &p_val) const {
int ret = -1;
if (size() == 0)
@@ -251,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
@@ -282,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;
@@ -331,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 4903a878b1..32481eb9eb 100644
--- a/core/vmap.cpp
+++ b/core/vmap.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/vmap.h b/core/vmap.h
index 516299280b..5ff8f73978 100644
--- a/core/vmap.h
+++ b/core/vmap.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/vset.cpp b/core/vset.cpp
index ffdd158996..c849bf3367 100644
--- a/core/vset.cpp
+++ b/core/vset.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/core/vset.h b/core/vset.h
index 3764b015b0..e1e02ab435 100644
--- a/core/vset.h
+++ b/core/vset.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/demos/2d/area_input/box_area.png b/demos/2d/area_input/box_area.png
new file mode 100644
index 0000000000..ba7c37f7de
--- /dev/null
+++ b/demos/2d/area_input/box_area.png
Binary files differ
diff --git a/demos/2d/area_input/circle_area.png b/demos/2d/area_input/circle_area.png
new file mode 100644
index 0000000000..3cc24c8a0c
--- /dev/null
+++ b/demos/2d/area_input/circle_area.png
Binary files differ
diff --git a/demos/2d/area_input/engine.cfg b/demos/2d/area_input/engine.cfg
new file mode 100644
index 0000000000..8fa2e15beb
--- /dev/null
+++ b/demos/2d/area_input/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+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
new file mode 100644
index 0000000000..e9cc9f3c1d
--- /dev/null
+++ b/demos/2d/area_input/input.gd
@@ -0,0 +1,15 @@
+
+extends Area2D
+
+
+# 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)
+ get_node("label").set_text(str(event.pos))
+
+
+# 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
new file mode 100644
index 0000000000..f3a19f64da
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..1f56851c58
--- /dev/null
+++ b/demos/2d/fog_of_war/engine.cfg
@@ -0,0 +1,12 @@
+[application]
+
+name="Fog of War"
+main_scene="res://fog.scn"
+icon="res://icon.png"
+
+[input]
+
+move_up=[key(Up)]
+move_bottom=[key(Down)]
+move_left=[key(Left)]
+move_right=[key(Right)]
diff --git a/demos/2d/fog_of_war/floor.png b/demos/2d/fog_of_war/floor.png
new file mode 100644
index 0000000000..07b4f8c98f
--- /dev/null
+++ b/demos/2d/fog_of_war/floor.png
Binary files differ
diff --git a/demos/2d/fog_of_war/fog.gd b/demos/2d/fog_of_war/fog.gd
new file mode 100644
index 0000000000..3ac8df0e17
--- /dev/null
+++ b/demos/2d/fog_of_war/fog.gd
@@ -0,0 +1,78 @@
+
+extends TileMap
+
+# Member variables
+
+# 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 # Player's position
+
+# Iteration variables
+var x
+var y
+
+# 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)
+
+
+# Process that runs in realtime
+func _fixed_process(delta):
+ position = get_node("../troll").get_pos()
+
+ # Calculate the corresponding tile
+ # from the players position
+ x = int(position.x/get_cell_size().x)
+ # Switching from positive to negative tile positions
+ # causes problems because of rounding problems
+ if position.x < 0:
+ x -= 1 # Correct negative values
+
+ y = int(position.y/get_cell_size().y)
+ 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
+ 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)
+ end -= 1
+ start += 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)
+ end -= 1
+ start += 1
+
+ x_old = x
+ y_old = y
+
+
+func _ready():
+ # 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)
diff --git a/demos/2d/fog_of_war/fog.png b/demos/2d/fog_of_war/fog.png
new file mode 100644
index 0000000000..56980c298d
--- /dev/null
+++ b/demos/2d/fog_of_war/fog.png
Binary files differ
diff --git a/demos/2d/fog_of_war/fog.scn b/demos/2d/fog_of_war/fog.scn
new file mode 100644
index 0000000000..cf19601567
--- /dev/null
+++ b/demos/2d/fog_of_war/fog.scn
Binary files differ
diff --git a/demos/2d/fog_of_war/fog.xml b/demos/2d/fog_of_war/fog.xml
new file mode 100644
index 0000000000..ed08d84a1f
--- /dev/null
+++ b/demos/2d/fog_of_war/fog.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<resource_file type="TileSet" subresource_count="3" version="1.0" version_name="Godot Engine v1.0.stable.custom_build">
+ <ext_resource path="res://floor.png" type="Texture"></ext_resource>
+ <ext_resource path="res://fog.png" type="Texture"></ext_resource>
+ <main_resource>
+ <string name="0/name"> "fog opaque" </string>
+ <resource name="0/texture" resource_type="Texture" path="res://fog.png"> </resource>
+ <vector2 name="0/tex_offset"> -48, -48 </vector2>
+ <vector2 name="0/shape_offset"> 0, 0 </vector2>
+ <rect2 name="0/region"> 0, 0, 144, 144 </rect2>
+ <array name="0/shapes" len="0" shared="false">
+ </array>
+ <string name="1/name"> "fog transparent" </string>
+ <resource name="1/texture" resource_type="Texture" path="res://fog.png"> </resource>
+ <vector2 name="1/tex_offset"> -48, -48 </vector2>
+ <vector2 name="1/shape_offset"> 0, 0 </vector2>
+ <rect2 name="1/region"> 144, 0, 144, 144 </rect2>
+ <array name="1/shapes" len="0" shared="false">
+ </array>
+ <string name="2/name"> "floor" </string>
+ <resource name="2/texture" resource_type="Texture" path="res://floor.png"> </resource>
+ <vector2 name="2/tex_offset"> 0, 0 </vector2>
+ <vector2 name="2/shape_offset"> 0, 0 </vector2>
+ <rect2 name="2/region"> 0, 0, 0, 0 </rect2>
+ <array name="2/shapes" len="0" shared="false">
+ </array>
+
+ </main_resource>
+</resource_file> \ No newline at end of file
diff --git a/demos/2d/fog_of_war/icon.png b/demos/2d/fog_of_war/icon.png
new file mode 100644
index 0000000000..a483390048
--- /dev/null
+++ b/demos/2d/fog_of_war/icon.png
Binary files differ
diff --git a/demos/2d/fog_of_war/tile_edit.scn b/demos/2d/fog_of_war/tile_edit.scn
new file mode 100644
index 0000000000..3eddf38e48
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..6f40072e84
--- /dev/null
+++ b/demos/2d/fog_of_war/troll.gd
@@ -0,0 +1,38 @@
+
+extends KinematicBody2D
+
+# 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 MOTION_SPEED = 160 # Pixels/second
+
+
+func _fixed_process(delta):
+ var motion = Vector2()
+
+ if (Input.is_action_pressed("move_up")):
+ motion += Vector2(0, -1)
+ if (Input.is_action_pressed("move_bottom")):
+ motion += Vector2(0, 1)
+ if (Input.is_action_pressed("move_left")):
+ motion += Vector2(-1, 0)
+ if (Input.is_action_pressed("move_right")):
+ motion += Vector2(1, 0)
+
+ motion = motion.normalized()*MOTION_SPEED*delta
+ motion = move(motion)
+
+ # Make character slide nicely through the world
+ var slide_attempts = 4
+ while(is_colliding() and slide_attempts > 0):
+ motion = get_collision_normal().slide(motion)
+ motion = move(motion)
+ slide_attempts -= 1
+
+
+func _ready():
+ set_fixed_process(true)
diff --git a/demos/2d/fog_of_war/troll.png b/demos/2d/fog_of_war/troll.png
new file mode 100644
index 0000000000..69f195d034
--- /dev/null
+++ b/demos/2d/fog_of_war/troll.png
Binary files differ
diff --git a/demos/2d/fog_of_war/troll.scn b/demos/2d/fog_of_war/troll.scn
new file mode 100644
index 0000000000..ab9af17221
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..fcc878e565
--- /dev/null
+++ b/demos/2d/hdr/beach_cave.gd
@@ -0,0 +1,21 @@
+
+extends Node2D
+
+# Member variables
+const CAVE_LIMIT = 1000
+
+
+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
+ get_node("cave").set_pos(cavepos)
+
+
+func _ready():
+ set_process_input(true)
diff --git a/demos/2d/hdr/beach_cave.scn b/demos/2d/hdr/beach_cave.scn
new file mode 100644
index 0000000000..6a4108e7a5
--- /dev/null
+++ b/demos/2d/hdr/beach_cave.scn
Binary files differ
diff --git a/demos/2d/hdr/engine.cfg b/demos/2d/hdr/engine.cfg
new file mode 100644
index 0000000000..ab53a022f0
--- /dev/null
+++ b/demos/2d/hdr/engine.cfg
@@ -0,0 +1,14 @@
+[application]
+
+name="HDR for 2D"
+main_scene="res://beach_cave.scn"
+icon="res://icon.png"
+
+[display]
+
+width=1080
+height=720
+
+[rasterizer]
+
+blur_buffer_size=128
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/hdr/ocean_beach.png b/demos/2d/hdr/ocean_beach.png
new file mode 100644
index 0000000000..a873d4f61d
--- /dev/null
+++ b/demos/2d/hdr/ocean_beach.png
Binary files differ
diff --git a/demos/2d/hdr/ocean_beach.png.flags b/demos/2d/hdr/ocean_beach.png.flags
new file mode 100644
index 0000000000..82127bd7d5
--- /dev/null
+++ b/demos/2d/hdr/ocean_beach.png.flags
@@ -0,0 +1 @@
+tolinear=true
diff --git a/demos/2d/hdr/ocean_cave.png b/demos/2d/hdr/ocean_cave.png
new file mode 100644
index 0000000000..8875499df3
--- /dev/null
+++ b/demos/2d/hdr/ocean_cave.png
Binary files differ
diff --git a/demos/2d/hdr/ocean_cave.png.flags b/demos/2d/hdr/ocean_cave.png.flags
new file mode 100644
index 0000000000..82127bd7d5
--- /dev/null
+++ b/demos/2d/hdr/ocean_cave.png.flags
@@ -0,0 +1 @@
+tolinear=true
diff --git a/demos/2d/hexamap/WWT-01.png b/demos/2d/hexamap/WWT-01.png
new file mode 100644
index 0000000000..79d75fa4c9
--- /dev/null
+++ b/demos/2d/hexamap/WWT-01.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-02.png b/demos/2d/hexamap/WWT-02.png
new file mode 100644
index 0000000000..7dcd1c8cca
--- /dev/null
+++ b/demos/2d/hexamap/WWT-02.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-03.png b/demos/2d/hexamap/WWT-03.png
new file mode 100644
index 0000000000..1e76c9a24d
--- /dev/null
+++ b/demos/2d/hexamap/WWT-03.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-04.png b/demos/2d/hexamap/WWT-04.png
new file mode 100644
index 0000000000..84a3b90e71
--- /dev/null
+++ b/demos/2d/hexamap/WWT-04.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-05.png b/demos/2d/hexamap/WWT-05.png
new file mode 100644
index 0000000000..850747dc8d
--- /dev/null
+++ b/demos/2d/hexamap/WWT-05.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-06.png b/demos/2d/hexamap/WWT-06.png
new file mode 100644
index 0000000000..52479e2d26
--- /dev/null
+++ b/demos/2d/hexamap/WWT-06.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-07.png b/demos/2d/hexamap/WWT-07.png
new file mode 100644
index 0000000000..87aa8a4102
--- /dev/null
+++ b/demos/2d/hexamap/WWT-07.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-08.png b/demos/2d/hexamap/WWT-08.png
new file mode 100644
index 0000000000..0234cccd56
--- /dev/null
+++ b/demos/2d/hexamap/WWT-08.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-09.png b/demos/2d/hexamap/WWT-09.png
new file mode 100644
index 0000000000..5467eb58c3
--- /dev/null
+++ b/demos/2d/hexamap/WWT-09.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-10.png b/demos/2d/hexamap/WWT-10.png
new file mode 100644
index 0000000000..bb0b5ae1ff
--- /dev/null
+++ b/demos/2d/hexamap/WWT-10.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-11.png b/demos/2d/hexamap/WWT-11.png
new file mode 100644
index 0000000000..926ad251b4
--- /dev/null
+++ b/demos/2d/hexamap/WWT-11.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-12.png b/demos/2d/hexamap/WWT-12.png
new file mode 100644
index 0000000000..e6c7d33894
--- /dev/null
+++ b/demos/2d/hexamap/WWT-12.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-13.png b/demos/2d/hexamap/WWT-13.png
new file mode 100644
index 0000000000..f14e42af6e
--- /dev/null
+++ b/demos/2d/hexamap/WWT-13.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-14.png b/demos/2d/hexamap/WWT-14.png
new file mode 100644
index 0000000000..826ed49d18
--- /dev/null
+++ b/demos/2d/hexamap/WWT-14.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-15.png b/demos/2d/hexamap/WWT-15.png
new file mode 100644
index 0000000000..c62de67c8e
--- /dev/null
+++ b/demos/2d/hexamap/WWT-15.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-16.png b/demos/2d/hexamap/WWT-16.png
new file mode 100644
index 0000000000..2e8c289d97
--- /dev/null
+++ b/demos/2d/hexamap/WWT-16.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-17.png b/demos/2d/hexamap/WWT-17.png
new file mode 100644
index 0000000000..f8c59a4dbe
--- /dev/null
+++ b/demos/2d/hexamap/WWT-17.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-18.png b/demos/2d/hexamap/WWT-18.png
new file mode 100644
index 0000000000..05269c843c
--- /dev/null
+++ b/demos/2d/hexamap/WWT-18.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-19.png b/demos/2d/hexamap/WWT-19.png
new file mode 100644
index 0000000000..7313ff8871
--- /dev/null
+++ b/demos/2d/hexamap/WWT-19.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-20.png b/demos/2d/hexamap/WWT-20.png
new file mode 100644
index 0000000000..2ec6fe94e2
--- /dev/null
+++ b/demos/2d/hexamap/WWT-20.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-21.png b/demos/2d/hexamap/WWT-21.png
new file mode 100644
index 0000000000..e7a51fa687
--- /dev/null
+++ b/demos/2d/hexamap/WWT-21.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-22.png b/demos/2d/hexamap/WWT-22.png
new file mode 100644
index 0000000000..0e4d7729ed
--- /dev/null
+++ b/demos/2d/hexamap/WWT-22.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-23.png b/demos/2d/hexamap/WWT-23.png
new file mode 100644
index 0000000000..ab1cc895e4
--- /dev/null
+++ b/demos/2d/hexamap/WWT-23.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-24.png b/demos/2d/hexamap/WWT-24.png
new file mode 100644
index 0000000000..b0a05671cf
--- /dev/null
+++ b/demos/2d/hexamap/WWT-24.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-25.png b/demos/2d/hexamap/WWT-25.png
new file mode 100644
index 0000000000..3d90080259
--- /dev/null
+++ b/demos/2d/hexamap/WWT-25.png
Binary files differ
diff --git a/demos/2d/hexamap/WWT-26.png b/demos/2d/hexamap/WWT-26.png
new file mode 100644
index 0000000000..a3baca90a0
--- /dev/null
+++ b/demos/2d/hexamap/WWT-26.png
Binary files differ
diff --git a/demos/2d/hexamap/engine.cfg b/demos/2d/hexamap/engine.cfg
new file mode 100644
index 0000000000..4567af7a16
--- /dev/null
+++ b/demos/2d/hexamap/engine.cfg
@@ -0,0 +1,12 @@
+[application]
+
+name="Hexagonal Game"
+main_scene="res://map.scn"
+icon="res://icon.png"
+
+[input]
+
+move_up=[key(Up)]
+move_left=[key(Left)]
+move_right=[key(Right)]
+move_bottom=[key(Down)]
diff --git a/demos/2d/hexamap/icon.png b/demos/2d/hexamap/icon.png
new file mode 100644
index 0000000000..0fcef95111
--- /dev/null
+++ b/demos/2d/hexamap/icon.png
Binary files differ
diff --git a/demos/2d/hexamap/map.scn b/demos/2d/hexamap/map.scn
new file mode 100644
index 0000000000..de49527003
--- /dev/null
+++ b/demos/2d/hexamap/map.scn
Binary files differ
diff --git a/demos/2d/hexamap/tiles.scn b/demos/2d/hexamap/tiles.scn
new file mode 100644
index 0000000000..a019bbb92d
--- /dev/null
+++ b/demos/2d/hexamap/tiles.scn
Binary files differ
diff --git a/demos/2d/hexamap/tileset.res b/demos/2d/hexamap/tileset.res
new file mode 100644
index 0000000000..05d89316a2
--- /dev/null
+++ b/demos/2d/hexamap/tileset.res
Binary files differ
diff --git a/demos/2d/hexamap/troll.gd b/demos/2d/hexamap/troll.gd
new file mode 100644
index 0000000000..82938fdf10
--- /dev/null
+++ b/demos/2d/hexamap/troll.gd
@@ -0,0 +1,38 @@
+
+extends KinematicBody2D
+
+# 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 MOTION_SPEED = 160 # Pixels/second
+
+
+func _fixed_process(delta):
+ var motion = Vector2()
+
+ if (Input.is_action_pressed("move_up")):
+ motion += Vector2(0, -1)
+ if (Input.is_action_pressed("move_bottom")):
+ motion += Vector2(0, 1)
+ if (Input.is_action_pressed("move_left")):
+ motion += Vector2(-1, 0)
+ if (Input.is_action_pressed("move_right")):
+ motion += Vector2(1, 0)
+
+ motion = motion.normalized()*MOTION_SPEED*delta
+ motion = move(motion)
+
+ # Make character slide nicely through the world
+ var slide_attempts = 4
+ while(is_colliding() and slide_attempts > 0):
+ motion = get_collision_normal().slide(motion)
+ motion = move(motion)
+ slide_attempts -= 1
+
+
+func _ready():
+ set_fixed_process(true)
diff --git a/demos/2d/hexamap/troll.png b/demos/2d/hexamap/troll.png
new file mode 100644
index 0000000000..69f195d034
--- /dev/null
+++ b/demos/2d/hexamap/troll.png
Binary files differ
diff --git a/demos/2d/hexamap/troll.scn b/demos/2d/hexamap/troll.scn
new file mode 100644
index 0000000000..1f33dabf8e
--- /dev/null
+++ b/demos/2d/hexamap/troll.scn
Binary files differ
diff --git a/demos/2d/isometric/bastiles.res b/demos/2d/isometric/bastiles.res
new file mode 100644
index 0000000000..50f3c78321
--- /dev/null
+++ b/demos/2d/isometric/bastiles.res
Binary files differ
diff --git a/demos/2d/isometric/dungeon.scn b/demos/2d/isometric/dungeon.scn
new file mode 100644
index 0000000000..8f0f316d73
--- /dev/null
+++ b/demos/2d/isometric/dungeon.scn
Binary files differ
diff --git a/demos/2d/isometric/engine.cfg b/demos/2d/isometric/engine.cfg
new file mode 100644
index 0000000000..48f39826f9
--- /dev/null
+++ b/demos/2d/isometric/engine.cfg
@@ -0,0 +1,21 @@
+[application]
+
+name="Isometric Game"
+main_scene="res://dungeon.scn"
+icon="res://icon.png"
+
+[image_loader]
+
+filter=false
+gen_mipmaps=false
+
+[input]
+
+move_up=[key(Up)]
+move_left=[key(Left)]
+move_right=[key(Right)]
+move_bottom=[key(Down)]
+
+[rasterizer]
+
+use_pixel_snap=true
diff --git a/demos/2d/isometric/icon.png b/demos/2d/isometric/icon.png
new file mode 100644
index 0000000000..c8fb5dcb42
--- /dev/null
+++ b/demos/2d/isometric/icon.png
Binary files differ
diff --git a/demos/2d/isometric/isotiles.png b/demos/2d/isometric/isotiles.png
new file mode 100644
index 0000000000..aa5a800f8f
--- /dev/null
+++ b/demos/2d/isometric/isotiles.png
Binary files differ
diff --git a/demos/2d/isometric/tileset.scn b/demos/2d/isometric/tileset.scn
new file mode 100644
index 0000000000..e487285f83
--- /dev/null
+++ b/demos/2d/isometric/tileset.scn
Binary files differ
diff --git a/demos/2d/isometric/troll.gd b/demos/2d/isometric/troll.gd
new file mode 100644
index 0000000000..d8d4880df1
--- /dev/null
+++ b/demos/2d/isometric/troll.gd
@@ -0,0 +1,38 @@
+
+extends KinematicBody2D
+
+# 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 MOTION_SPEED = 160 # Pixels/seconds
+
+
+func _fixed_process(delta):
+ var motion = Vector2()
+
+ if (Input.is_action_pressed("move_up")):
+ motion += Vector2(0, -1)
+ if (Input.is_action_pressed("move_bottom")):
+ motion += Vector2(0, 1)
+ if (Input.is_action_pressed("move_left")):
+ motion += Vector2(-1, 0)
+ if (Input.is_action_pressed("move_right")):
+ motion += Vector2(1, 0)
+
+ motion = motion.normalized()*MOTION_SPEED*delta
+ motion = move(motion)
+
+ # Make character slide nicely through the world
+ var slide_attempts = 4
+ while(is_colliding() and slide_attempts > 0):
+ motion = get_collision_normal().slide(motion)
+ motion = move(motion)
+ slide_attempts -= 1
+
+
+func _ready():
+ set_fixed_process(true)
diff --git a/demos/2d/isometric/troll.png b/demos/2d/isometric/troll.png
new file mode 100644
index 0000000000..69f195d034
--- /dev/null
+++ b/demos/2d/isometric/troll.png
Binary files differ
diff --git a/demos/2d/isometric/troll.scn b/demos/2d/isometric/troll.scn
new file mode 100644
index 0000000000..d53aac4fbf
--- /dev/null
+++ b/demos/2d/isometric/troll.scn
Binary files differ
diff --git a/demos/2d/isometric_light/character_shder.res b/demos/2d/isometric_light/character_shder.res
new file mode 100644
index 0000000000..17cd9ad287
--- /dev/null
+++ b/demos/2d/isometric_light/character_shder.res
Binary files differ
diff --git a/demos/2d/isometric_light/column.scn b/demos/2d/isometric_light/column.scn
new file mode 100644
index 0000000000..03f3c2c976
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..508cd3728c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio.gd
@@ -0,0 +1,85 @@
+
+extends KinematicBody2D
+
+# 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
+
+var speed = Vector2()
+var current_anim = ""
+var current_mirror = false
+
+var shoot_countdown = 0
+
+
+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)
+ get_parent().add_child(bullet)
+ shoot_countdown = SHOOT_INTERVAL
+
+
+func _fixed_process(delta):
+ shoot_countdown -= delta
+ var dir = Vector2()
+ if (Input.is_action_pressed("up")):
+ dir += Vector2(0, -1)
+ if (Input.is_action_pressed("down")):
+ dir += Vector2(0, 1)
+ if (Input.is_action_pressed("left")):
+ 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)
+
+ if (is_colliding()):
+ var n = get_collision_normal()
+ motion = n.slide(motion)
+ move(motion)
+
+ 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)
+
+ 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):
+ get_node("frames").set_flip_h(next_mirror)
+ get_node("anim").play(next_anim)
+ current_anim = next_anim
+ current_mirror = next_mirror
+
+
+func _ready():
+ set_fixed_process(true)
+ set_process_input(true)
diff --git a/demos/2d/isometric_light/cubio.scn b/demos/2d/isometric_light/cubio.scn
new file mode 100644
index 0000000000..55e2185247
--- /dev/null
+++ b/demos/2d/isometric_light/cubio.scn
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0001.png b/demos/2d/isometric_light/cubio/idle0001.png
new file mode 100644
index 0000000000..837dd38f9c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0001.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0002.png b/demos/2d/isometric_light/cubio/idle0002.png
new file mode 100644
index 0000000000..6137a37a9d
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0002.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0003.png b/demos/2d/isometric_light/cubio/idle0003.png
new file mode 100644
index 0000000000..7f3e3e0e31
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0003.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0004.png b/demos/2d/isometric_light/cubio/idle0004.png
new file mode 100644
index 0000000000..0a697dadf9
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0004.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0005.png b/demos/2d/isometric_light/cubio/idle0005.png
new file mode 100644
index 0000000000..9c47197247
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0005.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0006.png b/demos/2d/isometric_light/cubio/idle0006.png
new file mode 100644
index 0000000000..717a7be5b1
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0006.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0007.png b/demos/2d/isometric_light/cubio/idle0007.png
new file mode 100644
index 0000000000..dde18399f3
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0007.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0008.png b/demos/2d/isometric_light/cubio/idle0008.png
new file mode 100644
index 0000000000..0f716a5d84
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0008.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0009.png b/demos/2d/isometric_light/cubio/idle0009.png
new file mode 100644
index 0000000000..d271373f9d
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0009.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0010.png b/demos/2d/isometric_light/cubio/idle0010.png
new file mode 100644
index 0000000000..61311be0eb
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0010.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0011.png b/demos/2d/isometric_light/cubio/idle0011.png
new file mode 100644
index 0000000000..0b7d32d138
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0011.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0012.png b/demos/2d/isometric_light/cubio/idle0012.png
new file mode 100644
index 0000000000..c176034cfa
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0012.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0013.png b/demos/2d/isometric_light/cubio/idle0013.png
new file mode 100644
index 0000000000..c37018154b
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0013.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0014.png b/demos/2d/isometric_light/cubio/idle0014.png
new file mode 100644
index 0000000000..a4613e4269
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0014.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0015.png b/demos/2d/isometric_light/cubio/idle0015.png
new file mode 100644
index 0000000000..8354588b72
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0015.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0016.png b/demos/2d/isometric_light/cubio/idle0016.png
new file mode 100644
index 0000000000..4e5796fb89
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0016.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0017.png b/demos/2d/isometric_light/cubio/idle0017.png
new file mode 100644
index 0000000000..a4ac7e8c43
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0017.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0018.png b/demos/2d/isometric_light/cubio/idle0018.png
new file mode 100644
index 0000000000..aa7cc8fe6c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0018.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0019.png b/demos/2d/isometric_light/cubio/idle0019.png
new file mode 100644
index 0000000000..3ab603ceda
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0019.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0020.png b/demos/2d/isometric_light/cubio/idle0020.png
new file mode 100644
index 0000000000..9f02648f1a
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0020.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0021.png b/demos/2d/isometric_light/cubio/idle0021.png
new file mode 100644
index 0000000000..ec37fc331f
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0021.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0022.png b/demos/2d/isometric_light/cubio/idle0022.png
new file mode 100644
index 0000000000..34bf331af0
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0022.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0023.png b/demos/2d/isometric_light/cubio/idle0023.png
new file mode 100644
index 0000000000..80a458146e
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0023.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0024.png b/demos/2d/isometric_light/cubio/idle0024.png
new file mode 100644
index 0000000000..cd08c6d14a
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0024.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0025.png b/demos/2d/isometric_light/cubio/idle0025.png
new file mode 100644
index 0000000000..de500512d4
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0025.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0026.png b/demos/2d/isometric_light/cubio/idle0026.png
new file mode 100644
index 0000000000..4a8335a248
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0026.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0027.png b/demos/2d/isometric_light/cubio/idle0027.png
new file mode 100644
index 0000000000..c3d1609a03
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0027.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0028.png b/demos/2d/isometric_light/cubio/idle0028.png
new file mode 100644
index 0000000000..96c1f32223
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0028.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0029.png b/demos/2d/isometric_light/cubio/idle0029.png
new file mode 100644
index 0000000000..5b72d02300
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0029.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0030.png b/demos/2d/isometric_light/cubio/idle0030.png
new file mode 100644
index 0000000000..a84787bf0a
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0030.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0031.png b/demos/2d/isometric_light/cubio/idle0031.png
new file mode 100644
index 0000000000..dc9cd7ddc5
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0031.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0032.png b/demos/2d/isometric_light/cubio/idle0032.png
new file mode 100644
index 0000000000..c99f2e52bc
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0032.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0033.png b/demos/2d/isometric_light/cubio/idle0033.png
new file mode 100644
index 0000000000..cf5c648f9e
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0033.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0034.png b/demos/2d/isometric_light/cubio/idle0034.png
new file mode 100644
index 0000000000..8e18e12d8d
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0034.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0035.png b/demos/2d/isometric_light/cubio/idle0035.png
new file mode 100644
index 0000000000..ee2c25ee96
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0035.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0036.png b/demos/2d/isometric_light/cubio/idle0036.png
new file mode 100644
index 0000000000..f452b5db33
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0036.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0037.png b/demos/2d/isometric_light/cubio/idle0037.png
new file mode 100644
index 0000000000..7768c712e3
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0037.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0038.png b/demos/2d/isometric_light/cubio/idle0038.png
new file mode 100644
index 0000000000..1200127116
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0038.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0039.png b/demos/2d/isometric_light/cubio/idle0039.png
new file mode 100644
index 0000000000..25219f0582
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0039.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0040.png b/demos/2d/isometric_light/cubio/idle0040.png
new file mode 100644
index 0000000000..8da0a81050
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0040.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0041.png b/demos/2d/isometric_light/cubio/idle0041.png
new file mode 100644
index 0000000000..fa102aec8a
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0041.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0042.png b/demos/2d/isometric_light/cubio/idle0042.png
new file mode 100644
index 0000000000..0d19c32572
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0042.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0043.png b/demos/2d/isometric_light/cubio/idle0043.png
new file mode 100644
index 0000000000..bf284c62d0
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0043.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0044.png b/demos/2d/isometric_light/cubio/idle0044.png
new file mode 100644
index 0000000000..3daa1be0b8
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0044.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0045.png b/demos/2d/isometric_light/cubio/idle0045.png
new file mode 100644
index 0000000000..92abe74295
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0045.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0046.png b/demos/2d/isometric_light/cubio/idle0046.png
new file mode 100644
index 0000000000..2a1ab0f036
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0046.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0047.png b/demos/2d/isometric_light/cubio/idle0047.png
new file mode 100644
index 0000000000..da38b835ef
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0047.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0048.png b/demos/2d/isometric_light/cubio/idle0048.png
new file mode 100644
index 0000000000..35fac1b602
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0048.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0049.png b/demos/2d/isometric_light/cubio/idle0049.png
new file mode 100644
index 0000000000..7ebd79b8d7
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0049.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0050.png b/demos/2d/isometric_light/cubio/idle0050.png
new file mode 100644
index 0000000000..ba0678ba87
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0050.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0051.png b/demos/2d/isometric_light/cubio/idle0051.png
new file mode 100644
index 0000000000..03c54f1232
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0051.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0052.png b/demos/2d/isometric_light/cubio/idle0052.png
new file mode 100644
index 0000000000..0e2c8b5d9f
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0052.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0053.png b/demos/2d/isometric_light/cubio/idle0053.png
new file mode 100644
index 0000000000..d95095937f
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0053.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0054.png b/demos/2d/isometric_light/cubio/idle0054.png
new file mode 100644
index 0000000000..5a09fce69e
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0054.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0055.png b/demos/2d/isometric_light/cubio/idle0055.png
new file mode 100644
index 0000000000..6e2aad9d70
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0055.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0056.png b/demos/2d/isometric_light/cubio/idle0056.png
new file mode 100644
index 0000000000..45813e953f
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0056.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0057.png b/demos/2d/isometric_light/cubio/idle0057.png
new file mode 100644
index 0000000000..579b4e1647
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0057.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0058.png b/demos/2d/isometric_light/cubio/idle0058.png
new file mode 100644
index 0000000000..236f290651
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0058.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0059.png b/demos/2d/isometric_light/cubio/idle0059.png
new file mode 100644
index 0000000000..837dd38f9c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0059.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/idle0060.png b/demos/2d/isometric_light/cubio/idle0060.png
new file mode 100644
index 0000000000..837dd38f9c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/idle0060.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0001.png b/demos/2d/isometric_light/cubio/norm-b-0001.png
new file mode 100644
index 0000000000..cda17e21cc
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0001.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0002.png b/demos/2d/isometric_light/cubio/norm-b-0002.png
new file mode 100644
index 0000000000..fb36728cdf
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0002.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0003.png b/demos/2d/isometric_light/cubio/norm-b-0003.png
new file mode 100644
index 0000000000..c8bfecb100
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0003.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0004.png b/demos/2d/isometric_light/cubio/norm-b-0004.png
new file mode 100644
index 0000000000..e91213434f
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0004.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0005.png b/demos/2d/isometric_light/cubio/norm-b-0005.png
new file mode 100644
index 0000000000..a823fe9a92
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0005.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0006.png b/demos/2d/isometric_light/cubio/norm-b-0006.png
new file mode 100644
index 0000000000..d9de12baad
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0006.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0007.png b/demos/2d/isometric_light/cubio/norm-b-0007.png
new file mode 100644
index 0000000000..f042eed408
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0007.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0008.png b/demos/2d/isometric_light/cubio/norm-b-0008.png
new file mode 100644
index 0000000000..e18ca607dd
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0008.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0009.png b/demos/2d/isometric_light/cubio/norm-b-0009.png
new file mode 100644
index 0000000000..7e7ddd4c63
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0009.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0010.png b/demos/2d/isometric_light/cubio/norm-b-0010.png
new file mode 100644
index 0000000000..fddb956099
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0010.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0011.png b/demos/2d/isometric_light/cubio/norm-b-0011.png
new file mode 100644
index 0000000000..240a50a9ec
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0011.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0012.png b/demos/2d/isometric_light/cubio/norm-b-0012.png
new file mode 100644
index 0000000000..3e38628e98
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0012.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0013.png b/demos/2d/isometric_light/cubio/norm-b-0013.png
new file mode 100644
index 0000000000..2380e76909
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0013.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0014.png b/demos/2d/isometric_light/cubio/norm-b-0014.png
new file mode 100644
index 0000000000..db374927c6
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0014.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0015.png b/demos/2d/isometric_light/cubio/norm-b-0015.png
new file mode 100644
index 0000000000..1cd0e762c5
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0015.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0016.png b/demos/2d/isometric_light/cubio/norm-b-0016.png
new file mode 100644
index 0000000000..0d894db3f4
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0016.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0017.png b/demos/2d/isometric_light/cubio/norm-b-0017.png
new file mode 100644
index 0000000000..c184af8e85
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0017.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0018.png b/demos/2d/isometric_light/cubio/norm-b-0018.png
new file mode 100644
index 0000000000..1db06014b7
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0018.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0019.png b/demos/2d/isometric_light/cubio/norm-b-0019.png
new file mode 100644
index 0000000000..e74c9c7954
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0019.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-b-0020.png b/demos/2d/isometric_light/cubio/norm-b-0020.png
new file mode 100644
index 0000000000..326e60c64a
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-b-0020.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0001.png b/demos/2d/isometric_light/cubio/norm-bl-0001.png
new file mode 100644
index 0000000000..0b36e8caa3
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0001.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0002.png b/demos/2d/isometric_light/cubio/norm-bl-0002.png
new file mode 100644
index 0000000000..f00166d140
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0002.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0003.png b/demos/2d/isometric_light/cubio/norm-bl-0003.png
new file mode 100644
index 0000000000..d84993e097
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0003.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0004.png b/demos/2d/isometric_light/cubio/norm-bl-0004.png
new file mode 100644
index 0000000000..8e4c7f278b
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0004.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0005.png b/demos/2d/isometric_light/cubio/norm-bl-0005.png
new file mode 100644
index 0000000000..5009f2a514
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0005.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0006.png b/demos/2d/isometric_light/cubio/norm-bl-0006.png
new file mode 100644
index 0000000000..d0d654de6e
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0006.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0007.png b/demos/2d/isometric_light/cubio/norm-bl-0007.png
new file mode 100644
index 0000000000..2df2437a0d
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0007.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0008.png b/demos/2d/isometric_light/cubio/norm-bl-0008.png
new file mode 100644
index 0000000000..4bb8e91ecc
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0008.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0009.png b/demos/2d/isometric_light/cubio/norm-bl-0009.png
new file mode 100644
index 0000000000..e4ab80ab72
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0009.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0010.png b/demos/2d/isometric_light/cubio/norm-bl-0010.png
new file mode 100644
index 0000000000..7ead89343f
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0010.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0011.png b/demos/2d/isometric_light/cubio/norm-bl-0011.png
new file mode 100644
index 0000000000..9714999645
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0011.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0012.png b/demos/2d/isometric_light/cubio/norm-bl-0012.png
new file mode 100644
index 0000000000..95e0117df8
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0012.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0013.png b/demos/2d/isometric_light/cubio/norm-bl-0013.png
new file mode 100644
index 0000000000..85d4f25e7e
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0013.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0014.png b/demos/2d/isometric_light/cubio/norm-bl-0014.png
new file mode 100644
index 0000000000..3c9cc526d0
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0014.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0015.png b/demos/2d/isometric_light/cubio/norm-bl-0015.png
new file mode 100644
index 0000000000..3e30649ce1
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0015.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0016.png b/demos/2d/isometric_light/cubio/norm-bl-0016.png
new file mode 100644
index 0000000000..f39399c369
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0016.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0017.png b/demos/2d/isometric_light/cubio/norm-bl-0017.png
new file mode 100644
index 0000000000..47f79741a1
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0017.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0018.png b/demos/2d/isometric_light/cubio/norm-bl-0018.png
new file mode 100644
index 0000000000..8f4ccdcf33
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0018.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0019.png b/demos/2d/isometric_light/cubio/norm-bl-0019.png
new file mode 100644
index 0000000000..a278ec0f05
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0019.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-bl-0020.png b/demos/2d/isometric_light/cubio/norm-bl-0020.png
new file mode 100644
index 0000000000..db5fd0b73c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-bl-0020.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0001.png b/demos/2d/isometric_light/cubio/norm-l-0001.png
new file mode 100644
index 0000000000..7a989e79dd
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0001.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0002.png b/demos/2d/isometric_light/cubio/norm-l-0002.png
new file mode 100644
index 0000000000..2257923ee6
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0002.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0003.png b/demos/2d/isometric_light/cubio/norm-l-0003.png
new file mode 100644
index 0000000000..2e264e49a4
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0003.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0004.png b/demos/2d/isometric_light/cubio/norm-l-0004.png
new file mode 100644
index 0000000000..e0061451d6
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0004.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0005.png b/demos/2d/isometric_light/cubio/norm-l-0005.png
new file mode 100644
index 0000000000..e16cca081c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0005.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0006.png b/demos/2d/isometric_light/cubio/norm-l-0006.png
new file mode 100644
index 0000000000..694c2163eb
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0006.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0007.png b/demos/2d/isometric_light/cubio/norm-l-0007.png
new file mode 100644
index 0000000000..ed2ae64cad
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0007.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0008.png b/demos/2d/isometric_light/cubio/norm-l-0008.png
new file mode 100644
index 0000000000..4bbaeb8006
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0008.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0009.png b/demos/2d/isometric_light/cubio/norm-l-0009.png
new file mode 100644
index 0000000000..1f53a1067b
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0009.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0010.png b/demos/2d/isometric_light/cubio/norm-l-0010.png
new file mode 100644
index 0000000000..2007942a2a
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0010.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0011.png b/demos/2d/isometric_light/cubio/norm-l-0011.png
new file mode 100644
index 0000000000..0c27288646
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0011.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0012.png b/demos/2d/isometric_light/cubio/norm-l-0012.png
new file mode 100644
index 0000000000..8b885bcee8
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0012.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0013.png b/demos/2d/isometric_light/cubio/norm-l-0013.png
new file mode 100644
index 0000000000..ed08c9a470
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0013.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0014.png b/demos/2d/isometric_light/cubio/norm-l-0014.png
new file mode 100644
index 0000000000..3b6088c9a0
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0014.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0015.png b/demos/2d/isometric_light/cubio/norm-l-0015.png
new file mode 100644
index 0000000000..1ffa2b8cda
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0015.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0016.png b/demos/2d/isometric_light/cubio/norm-l-0016.png
new file mode 100644
index 0000000000..00279dc052
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0016.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0017.png b/demos/2d/isometric_light/cubio/norm-l-0017.png
new file mode 100644
index 0000000000..1805000a78
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0017.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0018.png b/demos/2d/isometric_light/cubio/norm-l-0018.png
new file mode 100644
index 0000000000..1ff123533f
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0018.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0019.png b/demos/2d/isometric_light/cubio/norm-l-0019.png
new file mode 100644
index 0000000000..2faf043a2b
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0019.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-l-0020.png b/demos/2d/isometric_light/cubio/norm-l-0020.png
new file mode 100644
index 0000000000..7948d2d79d
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-l-0020.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0001.png b/demos/2d/isometric_light/cubio/norm-u-0001.png
new file mode 100644
index 0000000000..6c702ba7c3
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0001.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0002.png b/demos/2d/isometric_light/cubio/norm-u-0002.png
new file mode 100644
index 0000000000..9a151e049b
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0002.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0003.png b/demos/2d/isometric_light/cubio/norm-u-0003.png
new file mode 100644
index 0000000000..0b7464260a
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0003.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0004.png b/demos/2d/isometric_light/cubio/norm-u-0004.png
new file mode 100644
index 0000000000..89061fdbcf
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0004.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0005.png b/demos/2d/isometric_light/cubio/norm-u-0005.png
new file mode 100644
index 0000000000..efc8ab0157
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0005.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0006.png b/demos/2d/isometric_light/cubio/norm-u-0006.png
new file mode 100644
index 0000000000..a89ef58f46
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0006.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0007.png b/demos/2d/isometric_light/cubio/norm-u-0007.png
new file mode 100644
index 0000000000..b069591200
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0007.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0008.png b/demos/2d/isometric_light/cubio/norm-u-0008.png
new file mode 100644
index 0000000000..8f0dbe8016
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0008.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0009.png b/demos/2d/isometric_light/cubio/norm-u-0009.png
new file mode 100644
index 0000000000..d4698f2584
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0009.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0010.png b/demos/2d/isometric_light/cubio/norm-u-0010.png
new file mode 100644
index 0000000000..cc3d442d4a
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0010.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0011.png b/demos/2d/isometric_light/cubio/norm-u-0011.png
new file mode 100644
index 0000000000..43c505d7e4
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0011.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0012.png b/demos/2d/isometric_light/cubio/norm-u-0012.png
new file mode 100644
index 0000000000..d4f955fd0c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0012.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0013.png b/demos/2d/isometric_light/cubio/norm-u-0013.png
new file mode 100644
index 0000000000..08dd875a54
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0013.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0014.png b/demos/2d/isometric_light/cubio/norm-u-0014.png
new file mode 100644
index 0000000000..4bea108a46
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0014.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0015.png b/demos/2d/isometric_light/cubio/norm-u-0015.png
new file mode 100644
index 0000000000..943c556706
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0015.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0016.png b/demos/2d/isometric_light/cubio/norm-u-0016.png
new file mode 100644
index 0000000000..d71a69c5a6
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0016.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0017.png b/demos/2d/isometric_light/cubio/norm-u-0017.png
new file mode 100644
index 0000000000..2d74e4472c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0017.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0018.png b/demos/2d/isometric_light/cubio/norm-u-0018.png
new file mode 100644
index 0000000000..17a5b10acb
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0018.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0019.png b/demos/2d/isometric_light/cubio/norm-u-0019.png
new file mode 100644
index 0000000000..e376c843e1
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0019.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-u-0020.png b/demos/2d/isometric_light/cubio/norm-u-0020.png
new file mode 100644
index 0000000000..fa1d3521ca
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-u-0020.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0001.png b/demos/2d/isometric_light/cubio/norm-ul-0001.png
new file mode 100644
index 0000000000..3e75621260
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0001.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0002.png b/demos/2d/isometric_light/cubio/norm-ul-0002.png
new file mode 100644
index 0000000000..d48d902936
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0002.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0003.png b/demos/2d/isometric_light/cubio/norm-ul-0003.png
new file mode 100644
index 0000000000..703cef6715
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0003.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0004.png b/demos/2d/isometric_light/cubio/norm-ul-0004.png
new file mode 100644
index 0000000000..7dd3e2884e
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0004.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0005.png b/demos/2d/isometric_light/cubio/norm-ul-0005.png
new file mode 100644
index 0000000000..1281b9ceb8
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0005.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0006.png b/demos/2d/isometric_light/cubio/norm-ul-0006.png
new file mode 100644
index 0000000000..e3c58752e9
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0006.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0007.png b/demos/2d/isometric_light/cubio/norm-ul-0007.png
new file mode 100644
index 0000000000..ccec10c83c
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0007.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0008.png b/demos/2d/isometric_light/cubio/norm-ul-0008.png
new file mode 100644
index 0000000000..1243c7dfe8
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0008.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0009.png b/demos/2d/isometric_light/cubio/norm-ul-0009.png
new file mode 100644
index 0000000000..77ea3ca8e9
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0009.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0010.png b/demos/2d/isometric_light/cubio/norm-ul-0010.png
new file mode 100644
index 0000000000..cf1cb7d0e3
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0010.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0011.png b/demos/2d/isometric_light/cubio/norm-ul-0011.png
new file mode 100644
index 0000000000..1063ee29a8
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0011.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0012.png b/demos/2d/isometric_light/cubio/norm-ul-0012.png
new file mode 100644
index 0000000000..a896237161
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0012.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0013.png b/demos/2d/isometric_light/cubio/norm-ul-0013.png
new file mode 100644
index 0000000000..cc289b18a0
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0013.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0014.png b/demos/2d/isometric_light/cubio/norm-ul-0014.png
new file mode 100644
index 0000000000..faf36e82b6
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0014.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0015.png b/demos/2d/isometric_light/cubio/norm-ul-0015.png
new file mode 100644
index 0000000000..925be82a2e
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0015.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0016.png b/demos/2d/isometric_light/cubio/norm-ul-0016.png
new file mode 100644
index 0000000000..1cb2300b9d
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0016.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0017.png b/demos/2d/isometric_light/cubio/norm-ul-0017.png
new file mode 100644
index 0000000000..5a841b57af
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0017.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0018.png b/demos/2d/isometric_light/cubio/norm-ul-0018.png
new file mode 100644
index 0000000000..2b30df8988
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0018.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0019.png b/demos/2d/isometric_light/cubio/norm-ul-0019.png
new file mode 100644
index 0000000000..12c0a72d6d
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0019.png
Binary files differ
diff --git a/demos/2d/isometric_light/cubio/norm-ul-0020.png b/demos/2d/isometric_light/cubio/norm-ul-0020.png
new file mode 100644
index 0000000000..3cffda17ca
--- /dev/null
+++ b/demos/2d/isometric_light/cubio/norm-ul-0020.png
Binary files differ
diff --git a/demos/2d/isometric_light/energy.png b/demos/2d/isometric_light/energy.png
new file mode 100644
index 0000000000..237e3ea4f0
--- /dev/null
+++ b/demos/2d/isometric_light/energy.png
Binary files differ
diff --git a/demos/2d/isometric_light/engine.cfg b/demos/2d/isometric_light/engine.cfg
new file mode 100644
index 0000000000..a5b053aa95
--- /dev/null
+++ b/demos/2d/isometric_light/engine.cfg
@@ -0,0 +1,20 @@
+[application]
+
+name="Isometric 2D + Lighting"
+main_scene="res://map.scn"
+icon="res://icon.png"
+
+[input]
+
+up=[key(Up), key(W)]
+down=[key(S), key(Down)]
+left=[key(Left), key(A)]
+right=[key(Right), key(D)]
+
+[rasterizer]
+
+shadow_filter=0
+
+[render]
+
+default_clear_color=#ff000000
diff --git a/demos/2d/isometric_light/faceColor.png b/demos/2d/isometric_light/faceColor.png
new file mode 100644
index 0000000000..c6daf73cb7
--- /dev/null
+++ b/demos/2d/isometric_light/faceColor.png
Binary files differ
diff --git a/demos/2d/isometric_light/faceMask.png b/demos/2d/isometric_light/faceMask.png
new file mode 100644
index 0000000000..d91e968c8e
--- /dev/null
+++ b/demos/2d/isometric_light/faceMask.png
Binary files differ
diff --git a/demos/2d/isometric_light/faceNormal.png b/demos/2d/isometric_light/faceNormal.png
new file mode 100644
index 0000000000..651f075fa1
--- /dev/null
+++ b/demos/2d/isometric_light/faceNormal.png
Binary files differ
diff --git a/demos/2d/isometric_light/fire.png b/demos/2d/isometric_light/fire.png
new file mode 100644
index 0000000000..746e4f9f4b
--- /dev/null
+++ b/demos/2d/isometric_light/fire.png
Binary files differ
diff --git a/demos/2d/isometric_light/floor_shader.res b/demos/2d/isometric_light/floor_shader.res
new file mode 100644
index 0000000000..c078d27b97
--- /dev/null
+++ b/demos/2d/isometric_light/floor_shader.res
Binary files differ
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/light2.png b/demos/2d/isometric_light/light2.png
new file mode 100644
index 0000000000..cd473251aa
--- /dev/null
+++ b/demos/2d/isometric_light/light2.png
Binary files differ
diff --git a/demos/2d/isometric_light/map.gd b/demos/2d/isometric_light/map.gd
new file mode 100644
index 0000000000..6b790ddf1c
--- /dev/null
+++ b/demos/2d/isometric_light/map.gd
@@ -0,0 +1,7 @@
+
+extends Node2D
+
+
+func _on_prince_area_body_enter(body):
+ if (body.get_name() == "cubio"):
+ get_node("message").show()
diff --git a/demos/2d/isometric_light/map.scn b/demos/2d/isometric_light/map.scn
new file mode 100644
index 0000000000..da3fc5654f
--- /dev/null
+++ b/demos/2d/isometric_light/map.scn
Binary files differ
diff --git a/demos/2d/isometric_light/shadow_blob.png b/demos/2d/isometric_light/shadow_blob.png
new file mode 100644
index 0000000000..e97fd2a826
--- /dev/null
+++ b/demos/2d/isometric_light/shadow_blob.png
Binary files differ
diff --git a/demos/2d/isometric_light/shoot.gd b/demos/2d/isometric_light/shoot.gd
new file mode 100644
index 0000000000..b48d4ad34b
--- /dev/null
+++ b/demos/2d/isometric_light/shoot.gd
@@ -0,0 +1,21 @@
+
+extends KinematicBody2D
+
+# Member variables
+const ADVANCE_SPEED = 500.0
+
+var advance_dir = Vector2(1, 0)
+var hit = false
+
+
+func _fixed_process(delta):
+ if (hit):
+ return
+ move(advance_dir*delta*ADVANCE_SPEED)
+ if (is_colliding()):
+ get_node("anim").play("explode")
+ hit = true
+
+
+func _ready():
+ set_fixed_process(true)
diff --git a/demos/2d/isometric_light/shoot.scn b/demos/2d/isometric_light/shoot.scn
new file mode 100644
index 0000000000..6909ae0c71
--- /dev/null
+++ b/demos/2d/isometric_light/shoot.scn
Binary files differ
diff --git a/demos/2d/isometric_light/shoot_halo.png b/demos/2d/isometric_light/shoot_halo.png
new file mode 100644
index 0000000000..5ba954b32b
--- /dev/null
+++ b/demos/2d/isometric_light/shoot_halo.png
Binary files differ
diff --git a/demos/2d/isometric_light/tileset.res b/demos/2d/isometric_light/tileset.res
new file mode 100644
index 0000000000..f64a4e32bd
--- /dev/null
+++ b/demos/2d/isometric_light/tileset.res
Binary files differ
diff --git a/demos/2d/isometric_light/tileset_scene.scn b/demos/2d/isometric_light/tileset_scene.scn
new file mode 100644
index 0000000000..4841cc18a7
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..9d6a8e2eae
--- /dev/null
+++ b/demos/2d/isometric_light/torch.scn
Binary files differ
diff --git a/demos/2d/isometric_light/torch_light.png b/demos/2d/isometric_light/torch_light.png
new file mode 100644
index 0000000000..a98113d36f
--- /dev/null
+++ b/demos/2d/isometric_light/torch_light.png
Binary files differ
diff --git a/demos/2d/isometric_light/torch_shader.res b/demos/2d/isometric_light/torch_shader.res
new file mode 100644
index 0000000000..31a35de1da
--- /dev/null
+++ b/demos/2d/isometric_light/torch_shader.res
Binary files differ
diff --git a/demos/2d/isometric_light/wall_shader.res b/demos/2d/isometric_light/wall_shader.res
new file mode 100644
index 0000000000..7e33c26201
--- /dev/null
+++ b/demos/2d/isometric_light/wall_shader.res
Binary files differ
diff --git a/demos/2d/kinematic_char/circle.png b/demos/2d/kinematic_char/circle.png
new file mode 100644
index 0000000000..ddb3ac4b9c
--- /dev/null
+++ b/demos/2d/kinematic_char/circle.png
Binary files differ
diff --git a/demos/2d/kinematic_char/colworld.gd b/demos/2d/kinematic_char/colworld.gd
index efd1dab805..7926ef9d54 100644
--- a/demos/2d/kinematic_char/colworld.gd
+++ b/demos/2d/kinematic_char/colworld.gd
@@ -1,17 +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
- get_node("youwin").show()
+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 b3a0a1f168..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 0132442c18..8bdd5e2fc5 100644
--- a/demos/2d/kinematic_char/engine.cfg
+++ b/demos/2d/kinematic_char/engine.cfg
@@ -1,9 +1,16 @@
[application]
-name="Kinematic Collision"
+name="Kinematic Character"
main_scene="res://colworld.scn"
icon="res://icon.png"
+[display]
+
+width=800
+height=600
+stretch_mode="2d"
+stretch_aspect="keep"
+
[input]
move_up=[key(Up)]
diff --git a/demos/2d/kinematic_char/long_obstacle.png b/demos/2d/kinematic_char/long_obstacle.png
new file mode 100644
index 0000000000..88cb22daee
--- /dev/null
+++ b/demos/2d/kinematic_char/long_obstacle.png
Binary files differ
diff --git a/demos/2d/kinematic_char/player.gd b/demos/2d/kinematic_char/player.gd
index b35bbfa693..2890cc2ce3 100644
--- a/demos/2d/kinematic_char/player.gd
+++ b/demos/2d/kinematic_char/player.gd
@@ -2,115 +2,122 @@
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 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_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
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)
-
- var stop = velocity.x!=0.0
+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<=0 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>=0 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()):
- #ran against something, is it the floor? get normal
+ # You can check which tile was collision against with this
+ # print(get_collider_metadata())
+
+ # 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()
- #velocity.y=0
-
- # But we were moving and our motion was interrupted,
- # so try to complete the motion by "sliding"
- # by the normal
- motion = n.slide(motion)
- velocity = n.slide(velocity)
- #then move again
- move(motion)
-
- if (floor_velocity!=Vector2()):
- #if floor moves, move with floor
+ 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
+ else:
+ # 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
+ move(motion)
+
+ 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.
+ # Makes controls more snappy.
+ velocity.y = -JUMP_SPEED
+ jumping = true
+
+ on_air_time += delta
+ prev_jump_pressed = jump
- if (jumping and velocity.y>0):
- jumping=false
-
- if (on_air_time<JUMP_MAX_AIRBORNE_TIME and jump and not prev_jump_pressed and not jumping):
- 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 126b332184..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/burano.png b/demos/2d/light_mask/burano.png
new file mode 100644
index 0000000000..6eec09d585
--- /dev/null
+++ b/demos/2d/light_mask/burano.png
Binary files differ
diff --git a/demos/2d/light_mask/engine.cfg b/demos/2d/light_mask/engine.cfg
new file mode 100644
index 0000000000..39608669ab
--- /dev/null
+++ b/demos/2d/light_mask/engine.cfg
@@ -0,0 +1,9 @@
+[application]
+
+name="Using Lights As Mask"
+main_scene="res://lightmask.scn"
+icon="res://icon.png"
+
+[rasterizer]
+
+shadow_filter=3
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
new file mode 100644
index 0000000000..fcf56b5b84
--- /dev/null
+++ b/demos/2d/light_mask/lightmask.scn
Binary files differ
diff --git a/demos/2d/light_mask/splat.png b/demos/2d/light_mask/splat.png
new file mode 100644
index 0000000000..8c35f068a0
--- /dev/null
+++ b/demos/2d/light_mask/splat.png
Binary files differ
diff --git a/demos/2d/lights_shadows/bg.png b/demos/2d/lights_shadows/bg.png
new file mode 100644
index 0000000000..4a3376f484
--- /dev/null
+++ b/demos/2d/lights_shadows/bg.png
Binary files differ
diff --git a/demos/2d/lights_shadows/caster.png b/demos/2d/lights_shadows/caster.png
new file mode 100644
index 0000000000..bf53a4565b
--- /dev/null
+++ b/demos/2d/lights_shadows/caster.png
Binary files differ
diff --git a/demos/2d/lights_shadows/engine.cfg b/demos/2d/lights_shadows/engine.cfg
new file mode 100644
index 0000000000..80142633d3
--- /dev/null
+++ b/demos/2d/lights_shadows/engine.cfg
@@ -0,0 +1,16 @@
+[application]
+
+name="2D Lighting"
+main_scene="res://light_shadows.scn"
+icon="res://icon.png"
+
+[display]
+
+stretch_mode="2d"
+width=800
+height=600
+stretch_aspect="keep"
+
+[rasterizer]
+
+shadow_filter=2
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.png b/demos/2d/lights_shadows/light.png
new file mode 100644
index 0000000000..936860de52
--- /dev/null
+++ b/demos/2d/lights_shadows/light.png
Binary files differ
diff --git a/demos/2d/lights_shadows/light_shadows.scn b/demos/2d/lights_shadows/light_shadows.scn
new file mode 100644
index 0000000000..24ccd1e0be
--- /dev/null
+++ b/demos/2d/lights_shadows/light_shadows.scn
Binary files differ
diff --git a/demos/2d/lights_shadows/spot.png b/demos/2d/lights_shadows/spot.png
new file mode 100644
index 0000000000..9ab2d34963
--- /dev/null
+++ b/demos/2d/lights_shadows/spot.png
Binary files differ
diff --git a/demos/2d/lookat/arrow.png b/demos/2d/lookat/arrow.png
new file mode 100644
index 0000000000..25db91e8d1
--- /dev/null
+++ b/demos/2d/lookat/arrow.png
Binary files differ
diff --git a/demos/2d/lookat/engine.cfg b/demos/2d/lookat/engine.cfg
new file mode 100644
index 0000000000..81df107f0e
--- /dev/null
+++ b/demos/2d/lookat/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+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
new file mode 100644
index 0000000000..c45c3ad622
--- /dev/null
+++ b/demos/2d/lookat/lookat.gd
@@ -0,0 +1,33 @@
+
+extends Sprite
+
+# 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
+
+
+func _process(delta):
+ var mpos = get_viewport().get_mouse_pos()
+
+ if (mode == MODE_DIRECT):
+ look_at(mpos)
+ elif (mode == MODE_CONSTANT):
+ var ang = get_angle_to(mpos)
+ var s = sign(ang)
+ ang = abs(ang)
+
+ rotate(min(ang, ROTATION_SPEED*delta)*s)
+ elif (mode == MODE_SMOOTH):
+ var ang = get_angle_to(mpos)
+
+ rotate(ang*delta*SMOOTH_SPEED)
+
+
+func _ready():
+ set_process(true)
diff --git a/demos/2d/lookat/lookat.scn b/demos/2d/lookat/lookat.scn
new file mode 100644
index 0000000000..66be060c06
--- /dev/null
+++ b/demos/2d/lookat/lookat.scn
Binary files differ
diff --git a/demos/2d/motion/car.png b/demos/2d/motion/car.png
new file mode 100644
index 0000000000..7ea973ceeb
--- /dev/null
+++ b/demos/2d/motion/car.png
Binary files differ
diff --git a/demos/2d/motion/engine.cfg b/demos/2d/motion/engine.cfg
new file mode 100644
index 0000000000..6e660572d6
--- /dev/null
+++ b/demos/2d/motion/engine.cfg
@@ -0,0 +1,12 @@
+[application]
+
+name="Motion Test"
+main_scene="res://motion.scn"
+icon="res://icon.png"
+
+[display]
+
+width=800
+height=600
+stretch_mode="2d"
+stretch_aspect="keep"
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
new file mode 100644
index 0000000000..f9bbd6f90d
--- /dev/null
+++ b/demos/2d/motion/motion.gd
@@ -0,0 +1,33 @@
+
+extends Sprite
+
+# Member variables
+const BEGIN = -113
+const END = 907
+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
+ set_pos(ofs)
+
+
+func _fixed_process(delta):
+ var ofs = get_pos()
+ ofs.x += delta*SPEED
+ if (ofs.x > END):
+ ofs.x = BEGIN
+ set_pos(ofs)
+
+
+func _ready():
+ if (use_idle):
+ set_process(true)
+ else:
+ set_fixed_process(true)
diff --git a/demos/2d/motion/motion.scn b/demos/2d/motion/motion.scn
new file mode 100644
index 0000000000..6e19356674
--- /dev/null
+++ b/demos/2d/motion/motion.scn
Binary files differ
diff --git a/demos/2d/navpoly/agent.png b/demos/2d/navpoly/agent.png
new file mode 100644
index 0000000000..23e396c478
--- /dev/null
+++ b/demos/2d/navpoly/agent.png
Binary files differ
diff --git a/demos/2d/navpoly/engine.cfg b/demos/2d/navpoly/engine.cfg
new file mode 100644
index 0000000000..b750419915
--- /dev/null
+++ b/demos/2d/navpoly/engine.cfg
@@ -0,0 +1,12 @@
+[application]
+
+name="Navigation Polygon (2D)"
+main_scene="res://navigation.scn"
+icon="res://icon.png"
+
+[display]
+
+width=800
+height=600
+stretch_mode="2d"
+stretch_aspect="keep"
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
new file mode 100644
index 0000000000..4cfa2ad733
--- /dev/null
+++ b/demos/2d/navpoly/navigation.gd
@@ -0,0 +1,53 @@
+
+extends Navigation2D
+
+# Member variables
+const SPEED = 200.0
+
+var begin = Vector2()
+var end = Vector2()
+var path = []
+
+
+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]
+ var d = pfrom.distance_to(pto)
+ 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]
+ get_node("agent").set_pos(atpos)
+
+ 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 too complex to use, convert to regular array
+ path.invert()
+
+ set_process(true)
+
+
+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():
+ set_process_input(true)
diff --git a/demos/2d/navpoly/navigation.scn b/demos/2d/navpoly/navigation.scn
new file mode 100644
index 0000000000..c56270bfd3
--- /dev/null
+++ b/demos/2d/navpoly/navigation.scn
Binary files differ
diff --git a/demos/2d/navpoly/path.png b/demos/2d/navpoly/path.png
new file mode 100644
index 0000000000..52a6d507c3
--- /dev/null
+++ b/demos/2d/navpoly/path.png
Binary files differ
diff --git a/demos/2d/normalmaps/diffuse.jpg b/demos/2d/normalmaps/diffuse.jpg
new file mode 100644
index 0000000000..87bc9cf158
--- /dev/null
+++ b/demos/2d/normalmaps/diffuse.jpg
Binary files differ
diff --git a/demos/2d/normalmaps/diffuse.png b/demos/2d/normalmaps/diffuse.png
new file mode 100644
index 0000000000..634d955f8d
--- /dev/null
+++ b/demos/2d/normalmaps/diffuse.png
Binary files differ
diff --git a/demos/2d/normalmaps/engine.cfg b/demos/2d/normalmaps/engine.cfg
new file mode 100644
index 0000000000..4f9f4f67f0
--- /dev/null
+++ b/demos/2d/normalmaps/engine.cfg
@@ -0,0 +1,12 @@
+[application]
+
+name="2D Normal Mapping"
+main_scene="res://normalmap.scn"
+icon="res://icon.png"
+
+[display]
+
+stretch_mode="2d"
+width=800
+height=600
+stretch_aspect="ignore"
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/light.png b/demos/2d/normalmaps/light.png
new file mode 100644
index 0000000000..9568298086
--- /dev/null
+++ b/demos/2d/normalmaps/light.png
Binary files differ
diff --git a/demos/2d/normalmaps/normal.png b/demos/2d/normalmaps/normal.png
new file mode 100644
index 0000000000..d5b3d53a24
--- /dev/null
+++ b/demos/2d/normalmaps/normal.png
Binary files differ
diff --git a/demos/2d/normalmaps/normal_material.res b/demos/2d/normalmaps/normal_material.res
new file mode 100644
index 0000000000..34129cccdc
--- /dev/null
+++ b/demos/2d/normalmaps/normal_material.res
Binary files differ
diff --git a/demos/2d/normalmaps/normalmap.scn b/demos/2d/normalmaps/normalmap.scn
new file mode 100644
index 0000000000..cf5fc05ce1
--- /dev/null
+++ b/demos/2d/normalmaps/normalmap.scn
Binary files differ
diff --git a/demos/2d/particles/particles.xml b/demos/2d/particles/particles.xml
index 56cd1aba06..c21ccb1f55 100644
--- a/demos/2d/particles/particles.xml
+++ b/demos/2d/particles/particles.xml
@@ -1,35 +1,49 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="4" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <ext_resource path="res://fire_particle.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://smoke_particle.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://spark_particle2.*" type="ImageTexture"></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="64">
+ <string_array len="41">
<string> "Node" </string>
<string> "__meta__" </string>
<string> "Fire" </string>
- <string> "Particles2D" </string>
- <string> "process/process" </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> "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>
@@ -41,133 +55,163 @@
<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> "randomness/initial_angle" </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="57" shared="false">
+ <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.598737 </real>
- <string> "ofs" </string>
- <vector2> 15.9452, 2.06145 </vector2>
+ <real> 0.440127 </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">
@@ -176,70 +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>
<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>
<bool> False </bool>
- <resource resource_type="ImageTexture" path="res://fire_particle.*"> </resource>
+ <resource external="0"> </resource>
+ <real> 0 </real>
<real> 20 </real>
<real> 180 </real>
<real> 80 </real>
<real> 0.7 </real>
<real> 0.3 </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>
+ <real> 2 </real>
+ <resource resource_type="ColorRamp" path="local://1"> </resource>
<vector2> 377.396, 543.147 </vector2>
<real> 176.575912 </real>
<real> 4 </real>
- <resource resource_type="ImageTexture" path="res://smoke_particle.*"> </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>
- <real> 2 </real>
<vector2> 40, 40 </vector2>
- <resource resource_type="ImageTexture" path="res://spark_particle2.*"> </resource>
+ <resource external="2"> </resource>
+ <real> 0.01 </real>
<real> 9.8 </real>
<real> 15.515152 </real>
- <color> 1, 0.477876, 0.60177, 1 </color>
- <real> 0.5 </real>
- <color> 0.533333, 0.752212, 1, 1 </color>
- <color> 0, 1, 0.699115, 0 </color>
+ <real> 45 </real>
+ <real> 100 </real>
+ <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>
- <int> 4 </int>
- <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>
<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="598"> -1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0, 3, 2, -1, 56, 4, 1, 5, 1, 6, 2, 7, 2, 8, 1, 9, 3, 10, 4, 11, 5, 12, 6, 13, 7, 14, 2, 15, 2, 16, 8, 17, 8, 18, 1, 19, 9, 20, 10, 21, 11, 22, 2, 23, 12, 24, 8, 25, 8, 26, 13, 27, 8, 28, 8, 29, 14, 30, 15, 31, 8, 32, 8, 33, 8, 34, 16, 35, 17, 36, 8, 37, 8, 38, 8, 39, 8, 40, 8, 41, 8, 42, 8, 43, 8, 44, 8, 45, 8, 46, 8, 47, 8, 48, 8, 49, 8, 50, 18, 51, 8, 52, 19, 53, 20, 54, 21, 55, 2, 56, 22, 57, 2, 58, 23, 59, 24, 0, 0, 0, 3, 60, -1, 55, 4, 1, 5, 1, 6, 2, 7, 2, 8, 1, 10, 25, 11, 26, 12, 6, 13, 7, 14, 27, 15, 2, 16, 8, 17, 8, 18, 1, 19, 9, 20, 9, 21, 11, 22, 2, 23, 28, 24, 8, 25, 29, 26, 30, 27, 2, 28, 8, 29, 8, 30, 8, 31, 8, 32, 8, 33, 8, 34, 2, 35, 31, 36, 8, 37, 8, 38, 8, 39, 8, 40, 2, 41, 8, 42, 8, 43, 8, 44, 8, 45, 8, 46, 8, 47, 8, 48, 8, 49, 8, 50, 18, 51, 8, 52, 19, 53, 32, 54, 33, 55, 2, 56, 34, 57, 2, 58, 23, 59, 24, 0, 0, 0, 3, 61, -1, 55, 4, 1, 5, 1, 6, 2, 7, 2, 8, 1, 10, 35, 11, 8, 12, 6, 13, 7, 14, 36, 15, 2, 16, 8, 17, 8, 18, 1, 19, 9, 20, 37, 21, 11, 22, 2, 23, 38, 24, 8, 25, 14, 26, 13, 27, 17, 28, 8, 29, 8, 30, 39, 31, 8, 32, 40, 33, 8, 34, 31, 35, 2, 36, 8, 37, 8, 38, 8, 39, 8, 40, 2, 41, 8, 42, 8, 43, 8, 44, 8, 45, 8, 46, 8, 47, 8, 48, 8, 49, 8, 50, 18, 51, 8, 52, 41, 53, 42, 54, 43, 55, 2, 56, 44, 57, 2, 58, 23, 59, 24, 0, 0, 0, 3, 62, -1, 56, 4, 1, 5, 1, 6, 2, 7, 2, 8, 11, 9, 3, 10, 45, 11, 5, 12, 6, 13, 7, 14, 36, 15, 36, 16, 8, 17, 8, 18, 1, 19, 9, 20, 10, 21, 11, 22, 46, 23, 28, 24, 8, 25, 14, 26, 47, 27, 8, 28, 8, 29, 14, 30, 15, 31, 8, 32, 8, 33, 48, 34, 16, 35, 31, 36, 8, 37, 8, 38, 8, 39, 8, 40, 8, 41, 8, 42, 8, 43, 8, 44, 8, 45, 8, 46, 8, 47, 8, 48, 8, 49, 8, 50, 49, 51, 8, 52, 19, 53, 20, 54, 50, 55, 16, 56, 51, 57, 2, 58, 34, 59, 24, 0, 0, 0, 3, 63, -1, 55, 4, 1, 5, 1, 6, 2, 7, 2, 8, 1, 10, 52, 11, 8, 12, 6, 13, 53, 14, 20, 15, 2, 16, 8, 17, 8, 18, 1, 19, 9, 20, 54, 21, 11, 22, 2, 23, 38, 24, 8, 25, 14, 26, 8, 27, 36, 28, 8, 29, 8, 30, 8, 31, 8, 32, 8, 33, 8, 34, 2, 35, 2, 36, 8, 37, 8, 38, 8, 39, 8, 40, 2, 41, 8, 42, 8, 43, 8, 44, 8, 45, 8, 46, 8, 47, 8, 48, 8, 49, 8, 50, 55, 51, 8, 52, 41, 53, 42, 54, 43, 55, 2, 56, 44, 57, 2, 58, 23, 59, 56, 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 b4e70477a8..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(true)
+ 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.png b/demos/2d/platformer/one_way_platform.png
new file mode 100644
index 0000000000..b5eca877a6
--- /dev/null
+++ b/demos/2d/platformer/one_way_platform.png
Binary files differ
diff --git a/demos/2d/platformer/one_way_platform.xml b/demos/2d/platformer/one_way_platform.xml
new file mode 100644
index 0000000000..85b2322711
--- /dev/null
+++ b/demos/2d/platformer/one_way_platform.xml
@@ -0,0 +1,207 @@
+<?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://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>
+
+ </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="23">
+ <string> "one_way_platform" </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> "one_way_collision/direction" </string>
+ <string> "one_way_collision/max_depth" </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> "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="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="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>
+ <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>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </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>
+ </dictionary>
+ <resource external="0"> </resource>
+ <vector2> 1.46304, -13.1672 </vector2>
+ <int> -1 </int>
+ </array>
+ <string> "version" </string>
+ <int> 2 </int>
+ </dictionary>
+
+ </main_resource>
+</resource_file> \ No newline at end of file
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 481f340ab8..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,40 +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 GRAVITY = 700.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")
@@ -72,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 c129d01f0d..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.3917-beta1">
- <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://sound_shoot.wav" type="Sample"></ext_resource>
- <ext_resource path="res://osb_fire.png" type="Texture"></ext_resource>
- <ext_resource path="res://robot_demo.png" type="Texture"></ext_resource>
- <ext_resource path="res://osb_left.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,14 +51,12 @@
<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>
<resource type="Animation" path="local://4">
- <string name="resource/name"> "run" </string>
- <real name="length"> 1.25 </real>
+ <string name="resource/name"> "jumping" </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>
@@ -60,25 +65,22 @@
<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="6"> 1, 1, 1, 1, 1, 1 </real_array>
+ <real_array len="3"> 1, 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="3" shared="false">
+ <int> 23 </int>
+ <int> 24 </int>
+ <int> 23 </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://5">
- <string name="resource/name"> "run_gun_fire" </string>
- <real name="length"> 1.25 </real>
+ <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>
<string name="tracks/0/type"> "value" </string>
@@ -87,24 +89,19 @@
<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> 10 </int>
- <int> 11 </int>
- <int> 12 </int>
- <int> 13 </int>
- <int> 14 </int>
- <int> 5 </int>
+ <array len="1" shared="false">
+ <int> 26 </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://6">
- <string name="resource/name"> "jumping_weapon" </string>
+ <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>
@@ -114,14 +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="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
- <int> 26 </int>
+ <int> 25 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
</resource>
@@ -136,20 +133,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> 22 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
</resource>
<resource type="Animation" path="local://8">
- <string name="resource/name"> "jumping" </string>
- <real name="length"> 0.5 </real>
+ <string name="resource/name"> "falling" </string>
+ <real name="length"> 0.01 </real>
<bool name="loop"> True </bool>
<real name="step"> 0.25 </real>
<string name="tracks/0/type"> "value" </string>
@@ -158,21 +155,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="3"> 1, 1, 1 </real_array>
+ <real_array len="1"> 1 </real_array>
<string> "values" </string>
- <array len="3" shared="false">
- <int> 23 </int>
- <int> 24 </int>
- <int> 23 </int>
+ <array len="1" shared="false">
+ <int> 21 </int>
</array>
- <string> "times" </string>
- <real_array len="3"> 0, 0.25, 0.5 </real_array>
</dictionary>
</resource>
<resource type="Animation" path="local://9">
- <string name="resource/name"> "run_weapon" </string>
<real name="length"> 1.25 </real>
<bool name="loop"> True </bool>
<real name="step"> 0.25 </real>
@@ -182,24 +176,23 @@
<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> 10 </int>
+ <int> 11 </int>
+ <int> 12 </int>
+ <int> 13 </int>
+ <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"> "idle_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>
@@ -209,20 +202,19 @@
<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://11">
- <string name="resource/name"> "falling_weapon" </string>
- <real name="length"> 0.5 </real>
+ <resource type="Animation" path="local://6">
+ <real name="length"> 1.25 </real>
<bool name="loop"> True </bool>
<real name="step"> 0.25 </real>
<string name="tracks/0/type"> "value" </string>
@@ -231,20 +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="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> 0 </int>
+ <int> 1 </int>
+ <int> 2 </int>
+ <int> 3 </int>
+ <int> 4 </int>
+ <int> 0 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
</resource>
- <resource type="Animation" path="local://12">
- <string name="resource/name"> "falling" </string>
- <real name="length"> 0.01 </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>
@@ -253,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> 21 </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>
@@ -271,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>
@@ -279,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>
@@ -287,72 +288,65 @@
<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="170">
+ <string_array len="144">
<string> "player" </string>
- <string> "RigidBody2D" </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> "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> "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> "params/direction" </string>
<string> "params/spread" </string>
@@ -364,53 +358,36 @@
<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> "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/run" </string>
- <string> "anims/standing_weapon_ready" </string>
- <string> "anims/jumping_weapon" </string>
- <string> "anims/crouch" </string>
<string> "anims/jumping" </string>
- <string> "anims/run_weapon" </string>
- <string> "anims/idle_weapon" </string>
<string> "anims/falling_weapon" </string>
+ <string> "anims/idle_weapon" </string>
+ <string> "anims/crouch" </string>
<string> "anims/falling" </string>
+ <string> "anims/standing_weapon_ready" </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>
@@ -425,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>
@@ -446,146 +425,181 @@
<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="71" shared="false">
- <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> "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.272073 </real>
- <string> "ofs" </string>
- <vector2> -181.946, -86.2812 </vector2>
+ <real> 2.050546 </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">
@@ -594,69 +608,61 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "3D" </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>
- <int> 1 </int>
<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="572"> -1, -1, 1, 0, -1, 28, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 8, 12, 2, 13, 9, 14, 10, 15, 2, 16, 6, 17, 11, 18, 4, 19, 4, 20, 0, 21, 12, 22, 13, 23, 2, 24, 0, 25, 0, 26, 3, 27, 4, 28, 14, 29, 15, 0, 0, 0, 31, 30, -1, 18, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 32, 16, 33, 0, 34, 3, 35, 2, 36, 2, 37, 6, 38, 17, 39, 12, 40, 18, 41, 2, 42, 19, 0, 1, 0, 44, 43, -1, 57, 2, 0, 3, 1, 4, 20, 5, 2, 45, 21, 6, 22, 7, 23, 8, 5, 46, 24, 47, 25, 48, 1, 49, 4, 50, 25, 51, 2, 52, 3, 53, 3, 54, 2, 55, 26, 56, 2, 57, 2, 58, 27, 59, 4, 60, 28, 61, 29, 62, 1, 63, 4, 64, 4, 65, 30, 66, 4, 67, 4, 68, 4, 69, 31, 70, 31, 71, 4, 72, 4, 73, 4, 74, 4, 75, 31, 76, 4, 77, 4, 78, 4, 79, 4, 80, 4, 81, 4, 82, 4, 83, 4, 84, 4, 85, 6, 86, 4, 87, 18, 88, 1, 89, 32, 90, 1, 91, 33, 92, 1, 93, 34, 94, 35, 0, 0, 0, 96, 95, -1, 17, 97, 21, 98, 4, 99, 36, 100, 37, 101, 38, 102, 39, 103, 40, 104, 41, 105, 42, 106, 43, 107, 44, 108, 45, 109, 46, 110, 0, 111, 31, 112, 47, 113, 48, 0, 0, 0, 115, 114, -1, 22, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 33, 0, 116, 2, 117, 0, 118, 4, 119, 5, 120, 12, 121, 12, 122, 49, 123, 49, 124, 0, 125, 0, 126, 50, 127, 50, 128, 50, 129, 50, 0, 0, 0, 131, 130, -1, 7, 2, 0, 3, 1, 4, 1, 5, 2, 6, 51, 7, 4, 8, 5, 0, 0, 0, 132, 132, -1, 9, 2, 0, 3, 1, 4, 1, 5, 2, 6, 52, 7, 4, 8, 53, 133, 7, 134, 2, 0, 0, 0, 136, 135, -1, 14, 137, 13, 138, 54, 139, 4, 140, 1, 141, 4, 142, 4, 143, 4, 144, 55, 145, 55, 146, 55, 147, 55, 148, 6, 149, 4, 150, 4, 0, 0, 0, 151, 151, -1, 9, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 152, 12, 153, 56, 0, 0, 0, 155, 154, -1, 4, 156, 12, 34, 3, 157, 4, 158, 5, 0, 9, 0, 160, 159, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 57, 7, 4, 8, 58, 161, 59, 162, 60, 163, 60, 164, 0, 165, 61, 166, 21, 0, 9, 0, 160, 167, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 62, 7, 4, 8, 58, 161, 63, 162, 60, 163, 60, 164, 0, 165, 64, 166, 21, 0, 9, 0, 160, 168, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 65, 7, 4, 8, 58, 161, 66, 162, 60, 163, 60, 164, 2, 165, 67, 166, 21, 0, 9, 0, 160, 169, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 68, 7, 4, 8, 58, 161, 69, 162, 60, 163, 60, 164, 2, 165, 70, 166, 21, 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 6a112e02aa..3b5d281551 100644
--- a/demos/2d/platformer/stage.xml
+++ b/demos/2d/platformer/stage.xml
@@ -1,37 +1,50 @@
<?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://music.ogg" type="AudioStream"></ext_resource>
- <ext_resource path="res://tileset.xml" type="TileSet"></ext_resource>
- <ext_resource path="res://coin.xml" type="PackedScene"></ext_resource>
- <ext_resource path="res://player.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://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="119">
+ <string_array len="112">
<string> "stage" </string>
- <string> "Node" </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/behind_parent" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "cell_size" </string>
- <string> "quadrant_size" </string>
+ <string> "mode" </string>
<string> "tile_set" </string>
+ <string> "cell/size" </string>
+ <string> "cell/quadrant_size" </string>
+ <string> "cell/custom_transform" </string>
+ <string> "cell/half_offset" </string>
+ <string> "cell/tile_origin" </string>
+ <string> "cell/y_sort" </string>
+ <string> "collision/use_kinematic" </string>
+ <string> "collision/friction" </string>
+ <string> "collision/bounce" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "tile_data" </string>
- <string> "collision_layers" </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>
@@ -73,24 +86,25 @@
<string> "coin 31 7 3" </string>
<string> "coin 31 7 4" </string>
<string> "coin 31 7 5" </string>
- <string> "player" </string>
- <string> "RigidBody2D" </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> "player" </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>
@@ -104,146 +118,157 @@
<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> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
- <int> 66 </int>
+ <int> 67 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <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="96" shared="false">
+ <array len="95" shared="false">
<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> 2 </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> -70.6559, 735.599 </vector2>
+ <string> "snap_grid" </string>
<bool> False </bool>
- <string> "zoom" </string>
- <real> 0.54036 </real>
- <string> "use_snap" </string>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
<bool> False </bool>
- <string> "ofs" </string>
- <vector2> 418.81, 615.088 </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> 0.663419 </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>
+ <real> 18.643827 </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">
@@ -252,32 +277,28 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <bool> True </bool>
- <real> 1 </real>
+ <int> 0 </int>
+ <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>
- <vector2> 0, 0 </vector2>
+ <real> 1 </real>
<real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 64 </int>
- <int> 16 </int>
- <resource resource_type="TileSet" path="res://tileset.xml"> </resource>
- <int_array len="1998"> 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, 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, 536870925, 1048587, 13, 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, 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, 536870918, 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>
<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>
- <dictionary shared="false">
- <string> "_editor_collapsed" </string>
- <bool> True </bool>
- </dictionary>
- <resource resource_type="PackedScene" path="res://coin.xml"> </resource>
- <vector2> 672, 1120 </vector2>
- <vector2> 704, 1120 </vector2>
- <vector2> 736, 1120 </vector2>
+ <resource external="1"> </resource>
+ <vector2> 672, 1179 </vector2>
+ <bool> True </bool>
+ <real> 0.1 </real>
+ <vector2> 704, 1179 </vector2>
+ <vector2> 736, 1179 </vector2>
<vector2> 1120, 992 </vector2>
<vector2> 1152, 992 </vector2>
<vector2> 1184, 992 </vector2>
@@ -317,9 +338,7 @@
<vector2> 4300.75, 541.058 </vector2>
<vector2> 4236.75, 541.058 </vector2>
<vector2> 4172.75, 541.058 </vector2>
- <resource resource_type="PackedScene" path="res://player.xml"> </resource>
- <vector2> 236.879, 1051.15 </vector2>
- <resource resource_type="PackedScene" path="res://moving_platform.xml"> </resource>
+ <resource external="2"> </resource>
<vector2> 1451.86, 742.969 </vector2>
<vector2> 0, 140 </vector2>
<real> 5 </real>
@@ -328,11 +347,16 @@
<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>
- <resource resource_type="AudioStream" path="res://music.ogg"> </resource>
+ <resource external="4"> </resource>
+ <vector2> 927.698, 1120.81 </vector2>
+ <resource external="5"> </resource>
+ <vector2> 251.684, 1045.6 </vector2>
+ <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>
<vector2> 707.665, 1225.05 </vector2>
<vector2> 1125.21, 1053.06 </vector2>
@@ -344,23 +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>
+ <resource external="8"> </resource>
<real> 12 </real>
<real> -202 </real>
<real> 358 </real>
<real> -10 </real>
- <node_path> "" </node_path>
- <int> 2 </int>
- <real> 14 </real>
- <real> 14.769231 </real>
- <string> "This is a simple demo on how to make a platformer game with Godot.&#10;This version uses physics and the 2D physics engine for motion and collision.&#10;&#10;The demo also shows the benefits of using the scene system, where coins,&#10;enemies and the player are edited separatedly and instanced in the stage.&#10;&#10;To edit the base tiles for the tileset, open the tileset_edit.xml file and follow &#10;instructions.&#10;" </string>
- <int> 0 </int>
- <real> -1 </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>
+ <int> -1 </int>
</array>
- <string> "nodes" </string>
- <int_array len="690"> -1, -1, 1, 0, -1, 1, 2, 0, 0, 0, 0, 4, 3, -1, 13, 5, 1, 6, 2, 7, 2, 8, 3, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 9, 15, 10, 16, 11, 2, 12, 0, 0, 0, 1, 17, -1, 1, 2, 13, 0, 2, 0, 19, 18, 14, 1, 9, 15, 0, 2, 0, 19, 20, 14, 1, 9, 16, 0, 2, 0, 19, 21, 14, 1, 9, 17, 0, 2, 0, 19, 22, 14, 1, 9, 18, 0, 2, 0, 19, 23, 14, 1, 9, 19, 0, 2, 0, 19, 24, 14, 1, 9, 20, 0, 2, 0, 19, 25, 14, 1, 9, 21, 0, 2, 0, 19, 26, 14, 1, 9, 22, 0, 2, 0, 19, 27, 14, 1, 9, 23, 0, 2, 0, 19, 28, 14, 1, 9, 24, 0, 2, 0, 19, 29, 14, 1, 9, 25, 0, 2, 0, 19, 30, 14, 1, 9, 26, 0, 2, 0, 19, 31, 14, 1, 9, 27, 0, 2, 0, 19, 32, 14, 1, 9, 28, 0, 2, 0, 19, 33, 14, 1, 9, 29, 0, 2, 0, 19, 34, 14, 1, 9, 30, 0, 2, 0, 19, 35, 14, 1, 9, 31, 0, 2, 0, 19, 36, 14, 1, 9, 32, 0, 2, 0, 19, 37, 14, 1, 9, 33, 0, 2, 0, 19, 38, 14, 1, 9, 34, 0, 2, 0, 19, 39, 14, 1, 9, 35, 0, 2, 0, 19, 40, 14, 1, 9, 36, 0, 2, 0, 19, 41, 14, 1, 9, 37, 0, 2, 0, 19, 42, 14, 1, 9, 38, 0, 2, 0, 19, 43, 14, 1, 9, 39, 0, 2, 0, 19, 44, 14, 1, 9, 40, 0, 2, 0, 19, 45, 14, 1, 9, 41, 0, 2, 0, 19, 46, 14, 1, 9, 42, 0, 2, 0, 19, 47, 14, 1, 9, 43, 0, 2, 0, 19, 48, 14, 1, 9, 44, 0, 2, 0, 19, 49, 14, 1, 9, 45, 0, 2, 0, 19, 50, 14, 1, 9, 46, 0, 2, 0, 19, 51, 14, 1, 9, 47, 0, 2, 0, 19, 52, 14, 1, 9, 48, 0, 2, 0, 19, 53, 14, 1, 9, 49, 0, 2, 0, 19, 54, 14, 1, 9, 50, 0, 2, 0, 19, 55, 14, 1, 9, 51, 0, 2, 0, 19, 56, 14, 1, 9, 52, 0, 2, 0, 19, 57, 14, 1, 9, 53, 0, 2, 0, 19, 58, 14, 1, 9, 54, 0, 2, 0, 19, 59, 14, 1, 9, 55, 0, 2, 0, 19, 60, 14, 1, 9, 56, 0, 0, 0, 62, 61, 57, 1, 9, 58, 0, 0, 0, 1, 63, -1, 0, 0, 46, 0, 65, 64, 59, 3, 9, 60, 66, 61, 67, 62, 0, 46, 0, 65, 68, 59, 3, 9, 63, 66, 64, 67, 65, 0, 46, 0, 65, 69, 59, 3, 9, 66, 66, 67, 67, 65, 0, 46, 0, 65, 70, 68, 1, 9, 69, 0, 0, 0, 72, 71, -1, 6, 73, 70, 74, 3, 75, 1, 76, 71, 77, 1, 78, 3, 0, 0, 0, 1, 79, -1, 0, 0, 52, 0, 62, 80, 72, 1, 9, 73, 0, 52, 0, 62, 81, 72, 1, 9, 74, 0, 52, 0, 62, 82, 72, 1, 9, 75, 0, 52, 0, 62, 83, 72, 1, 9, 76, 0, 52, 0, 62, 84, 72, 1, 9, 77, 0, 52, 0, 62, 85, 72, 1, 9, 78, 0, 52, 0, 62, 86, 72, 1, 9, 79, 0, 52, 0, 62, 87, 72, 1, 9, 80, 0, 52, 0, 62, 88, 72, 1, 9, 81, 0, 52, 0, 62, 89, 72, 1, 9, 82, 0, 52, 0, 62, 90, 72, 1, 9, 83, 0, 0, 0, 92, 91, 84, 0, 0, 0, 0, 93, 93, -1, 29, 5, 1, 6, 2, 7, 2, 8, 3, 94, 85, 95, 86, 96, 87, 97, 88, 98, 89, 99, 89, 100, 89, 101, 89, 102, 1, 103, 1, 104, 90, 105, 2, 106, 5, 107, 91, 108, 2, 109, 92, 110, 5, 111, 3, 112, 3, 113, 93, 114, 94, 115, 94, 116, 1, 117, 3, 118, 95, 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/tiles_demo.png b/demos/2d/platformer/tiles_demo.png
index a7a5000906..bc738e6d38 100644
--- a/demos/2d/platformer/tiles_demo.png
+++ b/demos/2d/platformer/tiles_demo.png
Binary files differ
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.xml b/demos/2d/platformer/tileset.xml
index 2e4ecc8c04..d8f9a651ee 100644
--- a/demos/2d/platformer/tileset.xml
+++ b/demos/2d/platformer/tileset.xml
@@ -1,134 +1,191 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="TileSet" subresource_count="12" version="0.99" version_name="Godot Engine v0.99.3037-pre-beta">
+<resource_file type="TileSet" 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 type="ConvexPolygonShape2D" path="local://0">
- <string name="resource/name"> "" </string>
- <real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 8, 64, 8, 64, 64, 0, 64 </vector2_array>
- <resource name="script/script"></resource>
- </resource>
<resource type="ConvexPolygonShape2D" path="local://1">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 8, 56, 8, 56, 64 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 32, -32, 32 </vector2_array>
+
</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"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="4"> -32, 32, -32, -24, 24, -24, 24, 32 </vector2_array>
+
</resource>
<resource type="ConvexPolygonShape2D" path="local://3">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="4"> -32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>
+
</resource>
<resource type="ConvexPolygonShape2D" path="local://4">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="5"> 0, 64, 0, 0, 56, 0, 64, 8, 64, 64 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="4"> -64, 32, -64, -32, -8, -32, -8, 32 </vector2_array>
+
</resource>
<resource type="ConvexPolygonShape2D" path="local://5">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 8, 64, 8, 64, 64 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="5"> -32, 32, -32, -32, 24, -32, 32, -24, 32, 32 </vector2_array>
+
</resource>
<resource type="ConvexPolygonShape2D" path="local://6">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 8, 64, 8, 64, 64 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="4"> -32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>
+
</resource>
<resource type="ConvexPolygonShape2D" path="local://7">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 0, 64, 0, 64, 64, 0, 64 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="4"> -32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>
+
</resource>
<resource type="ConvexPolygonShape2D" path="local://8">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 8, 64, 72, 64, 128, 0, 128 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="4"> -32, -32, 32, -32, 32, 32, -32, 32 </vector2_array>
+
</resource>
<resource type="ConvexPolygonShape2D" path="local://9">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
- <resource name="script/script"></resource>
+ <vector2_array name="points" len="4"> -32, -56, 32, 8, 32, 64, -32, 64 </vector2_array>
+
+ </resource>
+ <resource type="ConvexPolygonShape2D" path="local://10">
+ <real name="custom_solver_bias"> 0 </real>
+ <vector2_array name="points" len="4"> -32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>
+
+ </resource>
+ <resource type="ConvexPolygonShape2D" path="local://11">
+ <real name="custom_solver_bias"> 0 </real>
+ <vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 24, -32, 24 </vector2_array>
+
+ </resource>
+ <resource type="ConvexPolygonShape2D" path="local://12">
+ <real name="custom_solver_bias"> 0 </real>
+ <vector2_array name="points" len="4"> -32, -24, 24, -24, 24, 24, -32, 24 </vector2_array>
+
</resource>
<main_resource>
- <string name="resource/name"> "" </string>
<string name="0/name"> "floor" </string>
<resource name="0/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="0/offset"> 0, 0 </vector2>
+ <vector2 name="0/tex_offset"> 0, 0 </vector2>
+ <vector2 name="0/shape_offset"> 32, 32 </vector2>
<rect2 name="0/region"> 0, 0, 64, 64 </rect2>
- <resource name="0/shape" resource_type="ConvexPolygonShape2D" path="local://0"> </resource>
+ <array name="0/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://1"> </resource>
+ </array>
<string name="1/name"> "edge" </string>
<resource name="1/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="1/offset"> 0, 0 </vector2>
+ <vector2 name="1/tex_offset"> 0, 0 </vector2>
+ <vector2 name="1/shape_offset"> 32, 32 </vector2>
<rect2 name="1/region"> 64, 0, 64, 64 </rect2>
- <resource name="1/shape" resource_type="ConvexPolygonShape2D" path="local://1"> </resource>
+ <array name="1/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://2"> </resource>
+ </array>
<string name="2/name"> "wall" </string>
<resource name="2/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="2/offset"> 0, 0 </vector2>
+ <vector2 name="2/tex_offset"> 0, 0 </vector2>
+ <vector2 name="2/shape_offset"> 32, 32 </vector2>
<rect2 name="2/region"> 64, 64, 64, 64 </rect2>
- <resource name="2/shape" resource_type="ConvexPolygonShape2D" path="local://2"> </resource>
+ <array name="2/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://3"> </resource>
+ </array>
<string name="3/name"> "wall_deco" </string>
<resource name="3/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="3/offset"> 0, 0 </vector2>
+ <vector2 name="3/tex_offset"> 0, 0 </vector2>
+ <vector2 name="3/shape_offset"> 64, 32 </vector2>
<rect2 name="3/region"> 320, 128, 128, 64 </rect2>
- <resource name="3/shape" resource_type="ConvexPolygonShape2D" path="local://3"> </resource>
+ <array name="3/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://4"> </resource>
+ </array>
<string name="4/name"> "corner" </string>
<resource name="4/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="4/offset"> 0, 0 </vector2>
+ <vector2 name="4/tex_offset"> 0, 0 </vector2>
+ <vector2 name="4/shape_offset"> 32, 32 </vector2>
<rect2 name="4/region"> 64, 128, 64, 64 </rect2>
- <resource name="4/shape" resource_type="ConvexPolygonShape2D" path="local://4"> </resource>
+ <array name="4/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://5"> </resource>
+ </array>
<string name="5/name"> "flowers" </string>
<resource name="5/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="5/offset"> 0, 0 </vector2>
+ <vector2 name="5/tex_offset"> 0, 0 </vector2>
+ <vector2 name="5/shape_offset"> 32, 32 </vector2>
<rect2 name="5/region"> 192, 192, 64, 64 </rect2>
- <resource name="5/shape" resource_type="ConvexPolygonShape2D" path="local://5"> </resource>
+ <array name="5/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://6"> </resource>
+ </array>
<string name="6/name"> "tree_base" </string>
<resource name="6/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="6/offset"> 0, 0 </vector2>
+ <vector2 name="6/tex_offset"> 0, 0 </vector2>
+ <vector2 name="6/shape_offset"> 32, 32 </vector2>
<rect2 name="6/region"> 256, 192, 64, 64 </rect2>
- <resource name="6/shape" resource_type="ConvexPolygonShape2D" path="local://6"> </resource>
+ <array name="6/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://7"> </resource>
+ </array>
<string name="7/name"> "tree_mid" </string>
<resource name="7/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="7/offset"> 0, 0 </vector2>
+ <vector2 name="7/tex_offset"> 0, 0 </vector2>
+ <vector2 name="7/shape_offset"> 0, 0 </vector2>
<rect2 name="7/region"> 256, 128, 64, 64 </rect2>
- <resource name="7/shape"></resource> <string name="8/name"> "tree_mid 2" </string>
+ <array name="7/shapes" len="0" shared="false">
+ </array>
+ <string name="8/name"> "tree_mid 2" </string>
<resource name="8/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="8/offset"> 0, 0 </vector2>
+ <vector2 name="8/tex_offset"> 0, 0 </vector2>
+ <vector2 name="8/shape_offset"> 0, 0 </vector2>
<rect2 name="8/region"> 256, 64, 64, 64 </rect2>
- <resource name="8/shape"></resource> <string name="9/name"> "tree_top" </string>
+ <array name="8/shapes" len="0" shared="false">
+ </array>
+ <string name="9/name"> "tree_top" </string>
<resource name="9/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="9/offset"> 0, 0 </vector2>
+ <vector2 name="9/tex_offset"> 0, 0 </vector2>
+ <vector2 name="9/shape_offset"> 0, 0 </vector2>
<rect2 name="9/region"> 256, 0, 64, 64 </rect2>
- <resource name="9/shape"></resource> <string name="10/name"> "solid" </string>
+ <array name="9/shapes" len="0" shared="false">
+ </array>
+ <string name="10/name"> "solid" </string>
<resource name="10/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="10/offset"> 0, 0 </vector2>
+ <vector2 name="10/tex_offset"> 0, 0 </vector2>
+ <vector2 name="10/shape_offset"> 0, 0 </vector2>
<rect2 name="10/region"> 0, 64, 64, 64 </rect2>
- <resource name="10/shape"></resource> <string name="11/name"> "ceiling" </string>
+ <array name="10/shapes" len="0" shared="false">
+ </array>
+ <string name="11/name"> "ceiling" </string>
<resource name="11/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="11/offset"> 0, 0 </vector2>
+ <vector2 name="11/tex_offset"> 0, 0 </vector2>
+ <vector2 name="11/shape_offset"> 32, 32 </vector2>
<rect2 name="11/region"> 384, 64, 64, 64 </rect2>
- <resource name="11/shape" resource_type="ConvexPolygonShape2D" path="local://7"> </resource>
+ <array name="11/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://8"> </resource>
+ </array>
<string name="12/name"> "ramp" </string>
<resource name="12/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="12/offset"> 0, 0 </vector2>
+ <vector2 name="12/tex_offset"> 0, 0 </vector2>
+ <vector2 name="12/shape_offset"> 32, 64 </vector2>
<rect2 name="12/region"> 128, 128, 64, 128 </rect2>
- <resource name="12/shape" resource_type="ConvexPolygonShape2D" path="local://8"> </resource>
+ <array name="12/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://9"> </resource>
+ </array>
<string name="13/name"> "ceiling2wall" </string>
<resource name="13/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <vector2 name="13/offset"> 0, 0 </vector2>
+ <vector2 name="13/tex_offset"> 0, 0 </vector2>
+ <vector2 name="13/shape_offset"> 32, 32 </vector2>
<rect2 name="13/region"> 448, 64, 64, 64 </rect2>
- <resource name="13/shape" resource_type="ConvexPolygonShape2D" path="local://9"> </resource>
- <resource name="script/script"></resource>
+ <array name="13/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://10"> </resource>
+ </array>
+ <string name="14/name"> "platform_floor" </string>
+ <resource name="14/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
+ <vector2 name="14/tex_offset"> 0, 0 </vector2>
+ <vector2 name="14/shape_offset"> 32, 32 </vector2>
+ <rect2 name="14/region"> 128, 0, 64, 64 </rect2>
+ <array name="14/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://11"> </resource>
+ </array>
+ <string name="15/name"> "platform_edge" </string>
+ <resource name="15/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
+ <vector2 name="15/tex_offset"> 0, 0 </vector2>
+ <vector2 name="15/shape_offset"> 32, 32 </vector2>
+ <rect2 name="15/region"> 192, 0, 64, 64 </rect2>
+ <array name="15/shapes" len="1" shared="false">
+ <resource resource_type="Shape2D" path="local://12"> </resource>
+ </array>
+
</main_resource>
</resource_file> \ No newline at end of file
diff --git a/demos/2d/platformer/tileset_edit.xml b/demos/2d/platformer/tileset_edit.xml
index 2473656a6a..3ae9f1bd2a 100644
--- a/demos/2d/platformer/tileset_edit.xml
+++ b/demos/2d/platformer/tileset_edit.xml
@@ -1,100 +1,106 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="12" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <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"> 0, 8, 64, 8, 64, 64, 0, 64 </vector2_array>
+ <vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 32, -32, 32 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://2">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 8, 56, 8, 56, 64 </vector2_array>
+ <vector2_array name="points" len="4"> -32, 32, -32, -24, 24, -24, 24, 32 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://3">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
+ <vector2_array name="points" len="4"> -32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://4">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
+ <vector2_array name="points" len="4"> -64, 32, -64, -32, -8, -32, -8, 32 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://5">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="5"> 0, 64, 0, 0, 56, 0, 64, 8, 64, 64 </vector2_array>
+ <vector2_array name="points" len="5"> -32, 32, -32, -32, 24, -32, 32, -24, 32, 32 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://6">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 8, 64, 72, 64, 128, 0, 128 </vector2_array>
+ <vector2_array name="points" len="4"> -32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://7">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 8, 64, 8, 64, 64 </vector2_array>
+ <vector2_array name="points" len="4"> -32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://8">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 8, 64, 8, 64, 64 </vector2_array>
+ <vector2_array name="points" len="4"> -32, -32, 32, -32, 32, 32, -32, 32 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://9">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 0, 64, 0, 64, 64, 0, 64 </vector2_array>
+ <vector2_array name="points" len="4"> -32, -56, 32, 8, 32, 64, -32, 64 </vector2_array>
</resource>
<resource type="ConvexPolygonShape2D" path="local://10">
<real name="custom_solver_bias"> 0 </real>
- <vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
+ <vector2_array name="points" len="4"> -32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>
+
+ </resource>
+ <resource type="ConvexPolygonShape2D" path="local://11">
+ <real name="custom_solver_bias"> 0 </real>
+ <vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 24, -32, 24 </vector2_array>
+
+ </resource>
+ <resource type="ConvexPolygonShape2D" path="local://12">
+ <real name="custom_solver_bias"> 0 </real>
+ <vector2_array name="points" len="4"> -32, -24, 24, -24, 24, 24, -32, 24 </vector2_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="75">
+ <string_array len="49">
<string> "Node" </string>
<string> "__meta__" </string>
<string> "floor" </string>
- <string> "Sprite" </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> "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> "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>
- <string> "ramp" </string>
<string> "flowers" </string>
<string> "tree_base" </string>
<string> "tree_mid" </string>
@@ -102,131 +108,156 @@
<string> "tree_top" </string>
<string> "solid" </string>
<string> "ceiling" </string>
+ <string> "ramp" </string>
<string> "ceiling2wall" </string>
<string> "help" </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> "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> 36 </int>
+ <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="65" shared="false">
+ <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>
+ <string> "ofs" </string>
+ <vector2> -446.534, -87.6905 </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.670182 </real>
- <string> "ofs" </string>
- <vector2> -58.9115, 60.1605 </vector2>
+ <real> 1.670183 </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">
@@ -235,49 +266,43 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
+ <resource external="0"> </resource>
<bool> True </bool>
- <nil> </nil>
- <nil> </nil>
- <vector2> 0, 0 </vector2>
- <nil> </nil>
- <vector2> 1, 1 </vector2>
- <resource resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <int> 1 </int>
- <nil> </nil>
- <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>
- <vector2_array len="4"> 64, 8, 64, 64, 0, 64, 0, 8 </vector2_array>
+ <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>
- <vector2_array len="4"> 0, 8, 56, 8, 56, 64, 0, 64 </vector2_array>
+ <vector2_array len="4"> -32, -24, 24, -24, 24, 32, -32, 32 </vector2_array>
<vector2> 64, 64 </vector2>
<rect2> 64, 64, 64, 64 </rect2>
<resource resource_type="Shape2D" path="local://3"> </resource>
- <vector2_array len="4"> 0, 0, 56, 0, 56, 64, 0, 64 </vector2_array>
- <vector2> 64, 128 </vector2>
+ <vector2_array len="4"> -32, -32, 24, -32, 24, 32, -32, 32 </vector2_array>
+ <vector2> 96, 128 </vector2>
<rect2> 320, 128, 128, 64 </rect2>
<resource resource_type="Shape2D" path="local://4"> </resource>
+ <vector2_array len="4"> -64, -32, -8, -32, -8, 32, -64, 32 </vector2_array>
<vector2> 64, 192 </vector2>
<rect2> 64, 128, 64, 64 </rect2>
<resource resource_type="Shape2D" path="local://5"> </resource>
- <vector2_array len="5"> 0, 0, 56, 0, 64, 8, 64, 64, 0, 64 </vector2_array>
- <vector2> 256, 192 </vector2>
- <rect2> 128, 128, 64, 128 </rect2>
- <resource resource_type="Shape2D" path="local://6"> </resource>
- <vector2_array len="4"> 0, 8, 64, 72, 64, 128, 0, 128 </vector2_array>
+ <vector2_array len="5"> -32, -32, 24, -32, 32, -24, 32, 32, -32, 32 </vector2_array>
<vector2> 128, 192 </vector2>
<rect2> 192, 192, 64, 64 </rect2>
- <resource resource_type="Shape2D" path="local://7"> </resource>
- <vector2_array len="4"> 0, 64, 64, 64, 64, 8, 0, 8 </vector2_array>
+ <resource resource_type="Shape2D" path="local://6"> </resource>
+ <vector2_array len="4"> -32, 32, 32, 32, 32, -24, -32, -24 </vector2_array>
<vector2> 192, 192 </vector2>
<rect2> 256, 192, 64, 64 </rect2>
- <resource resource_type="Shape2D" path="local://8"> </resource>
+ <resource resource_type="Shape2D" path="local://7"> </resource>
<vector2> 192, 128 </vector2>
<rect2> 256, 128, 64, 64 </rect2>
<vector2> 192, 64 </vector2>
@@ -288,25 +313,29 @@
<rect2> 0, 64, 64, 64 </rect2>
<vector2> 0, 128 </vector2>
<rect2> 384, 64, 64, 64 </rect2>
+ <resource resource_type="Shape2D" path="local://8"> </resource>
+ <vector2_array len="4"> 32, -32, 32, 32, -32, 32, -32, -32 </vector2_array>
+ <vector2> 256, 224 </vector2>
+ <rect2> 128, 128, 64, 128 </rect2>
<resource resource_type="Shape2D" path="local://9"> </resource>
- <vector2_array len="4"> 64, 0, 64, 64, 0, 64, 0, 0 </vector2_array>
+ <vector2_array len="4"> -32, -56, 32, 8, 32, 64, -32, 64 </vector2_array>
<vector2> 0, 192 </vector2>
<rect2> 448, 64, 64, 64 </rect2>
<resource resource_type="Shape2D" path="local://10"> </resource>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
<int> 2 </int>
- <nil> </nil>
- <string> "This scene serves as a tool for editing the tileset.&#10;Nodes (sprites) and their respective collisions&#10;are edited here. &#10;&#10;To create a tileset from this, a &quot;TileSet&quot; resoucre &#10;must be created. Use the helper in:&#10;&#10; Scene -&lt; Convert To -&lt; TileSet&#10;&#10;This will save a tileset. Saving over it will merge your changes.&#10;&#10;Finally, the saved tileset resource (tileset.xml in this&#10; case), can be opened to be used into a TileMap node&#10; for editing a tile map.&#10;" </string>
- <real> -1 </real>
+ <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>
+ <int> -1 </int>
+ <vector2> 0, 256 </vector2>
+ <rect2> 128, 0, 64, 64 </rect2>
+ <resource resource_type="Shape2D" path="local://11"> </resource>
+ <vector2_array len="4"> 32, -24, 32, 24, -32, 24, -32, -24 </vector2_array>
+ <vector2> 64, 256 </vector2>
+ <rect2> 192, 0, 64, 64 </rect2>
+ <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="1296"> -1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0, 3, 2, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 11, 0, 1, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 12, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 2, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 14, 0, 0, 0, 3, 35, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 15, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 16, 0, 4, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 17, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 5, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 18, 0, 0, 0, 3, 36, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 19, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 20, 0, 7, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 21, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 8, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 22, 0, 0, 0, 3, 37, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 23, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 24, 0, 10, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 25, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 11, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 22, 0, 0, 0, 3, 38, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 26, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 27, 0, 13, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 28, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 14, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 29, 0, 0, 0, 3, 39, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 30, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 31, 0, 16, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 32, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 17, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 33, 0, 0, 0, 3, 40, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 34, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 35, 0, 19, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 36, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 20, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 37, 0, 0, 0, 3, 41, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 38, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 39, 0, 22, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 40, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 23, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 37, 0, 0, 0, 3, 42, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 41, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 42, 0, 0, 0, 3, 43, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 43, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 44, 0, 0, 0, 3, 44, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 45, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 46, 0, 0, 0, 3, 45, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 47, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 48, 0, 0, 0, 3, 46, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 49, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 50, 0, 29, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 51, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 30, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 52, 0, 0, 0, 3, 47, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 53, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 54, 0, 32, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 55, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 33, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 22, 0, 0, 0, 49, 48, -1, 29, 4, 1, 5, 2, 6, 2, 7, 3, 50, 56, 51, 57, 52, 58, 53, 59, 54, 60, 55, 60, 56, 60, 57, 60, 58, 1, 59, 1, 60, 61, 61, 2, 62, 5, 63, 62, 64, 2, 65, 62, 66, 5, 67, 3, 68, 3, 69, 63, 70, 9, 71, 9, 72, 3, 73, 3, 74, 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/pong/pong.gd b/demos/2d/pong/pong.gd
index bfffdcf0d8..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 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/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/art/burano.jpg b/demos/2d/screen_space_shaders/art/burano.jpg
new file mode 100644
index 0000000000..cdab993ec1
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/burano.jpg
Binary files differ
diff --git a/demos/2d/screen_space_shaders/art/burano.png b/demos/2d/screen_space_shaders/art/burano.png
new file mode 100644
index 0000000000..6eec09d585
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/burano.png
Binary files differ
diff --git a/demos/2d/screen_space_shaders/art/filmgrain.png b/demos/2d/screen_space_shaders/art/filmgrain.png
new file mode 100644
index 0000000000..b8ea89902c
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/filmgrain.png
Binary files differ
diff --git a/demos/2d/screen_space_shaders/art/filmgrain.png.flags b/demos/2d/screen_space_shaders/art/filmgrain.png.flags
new file mode 100644
index 0000000000..d5476d5499
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/filmgrain.png.flags
@@ -0,0 +1 @@
+repeat=true
diff --git a/demos/2d/screen_space_shaders/art/forest.png b/demos/2d/screen_space_shaders/art/forest.png
new file mode 100644
index 0000000000..f5a2fb9bfb
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/forest.png
Binary files differ
diff --git a/demos/2d/screen_space_shaders/art/mountains.png b/demos/2d/screen_space_shaders/art/mountains.png
new file mode 100644
index 0000000000..b8435bb1a8
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/mountains.png
Binary files differ
diff --git a/demos/2d/screen_space_shaders/art/platformer.png b/demos/2d/screen_space_shaders/art/platformer.png
new file mode 100644
index 0000000000..21c1cb4c4b
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/platformer.png
Binary files differ
diff --git a/demos/2d/screen_space_shaders/art/vignette.png b/demos/2d/screen_space_shaders/art/vignette.png
new file mode 100644
index 0000000000..8afeb7f9e1
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/vignette.png
Binary files differ
diff --git a/demos/2d/screen_space_shaders/art/white.png b/demos/2d/screen_space_shaders/art/white.png
new file mode 100644
index 0000000000..573faa33f2
--- /dev/null
+++ b/demos/2d/screen_space_shaders/art/white.png
Binary files differ
diff --git a/demos/2d/screen_space_shaders/engine.cfg b/demos/2d/screen_space_shaders/engine.cfg
new file mode 100644
index 0000000000..383ca7bf11
--- /dev/null
+++ b/demos/2d/screen_space_shaders/engine.cfg
@@ -0,0 +1,12 @@
+[application]
+
+name="Screen-Space Shaders"
+main_scene="res://screen_shaders.scn"
+icon="res://icon.png"
+
+[display]
+
+width=780
+height=600
+stretch_mode="2d"
+stretch_aspect="keep"
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
new file mode 100644
index 0000000000..b847a9c923
--- /dev/null
+++ b/demos/2d/screen_space_shaders/screen_shaders.gd
@@ -0,0 +1,25 @@
+
+extends Control
+
+
+func _ready():
+ for c in get_node("pictures").get_children():
+ 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())
+
+
+func _on_picture_item_selected(ID):
+ for c in range(get_node("pictures").get_child_count()):
+ if (ID == c):
+ get_node("pictures").get_child(c).show()
+ else:
+ get_node("pictures").get_child(c).hide()
+
+
+func _on_effect_item_selected(ID):
+ for c in range(get_node("effects").get_child_count()):
+ 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
new file mode 100644
index 0000000000..be12cef02d
--- /dev/null
+++ b/demos/2d/screen_space_shaders/screen_shaders.scn
Binary files differ
diff --git a/demos/2d/sdf_font/KaushanScript-Regular.otf b/demos/2d/sdf_font/KaushanScript-Regular.otf
new file mode 100644
index 0000000000..bd29502100
--- /dev/null
+++ b/demos/2d/sdf_font/KaushanScript-Regular.otf
Binary files differ
diff --git a/demos/2d/sdf_font/engine.cfg b/demos/2d/sdf_font/engine.cfg
new file mode 100644
index 0000000000..bf983041fa
--- /dev/null
+++ b/demos/2d/sdf_font/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+name="Signed Distance Field Font"
+main_scene="res://sdf.scn"
+icon="res://icon.png"
diff --git a/demos/2d/sdf_font/font.fnt b/demos/2d/sdf_font/font.fnt
new file mode 100644
index 0000000000..c2b6b0177d
--- /dev/null
+++ b/demos/2d/sdf_font/font.fnt
Binary files differ
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
new file mode 100644
index 0000000000..4880500d6d
--- /dev/null
+++ b/demos/2d/sdf_font/sdf.scn
Binary files differ
diff --git a/demos/2d/shower_of_bullets/bullet.png b/demos/2d/shower_of_bullets/bullet.png
new file mode 100644
index 0000000000..7466374129
--- /dev/null
+++ b/demos/2d/shower_of_bullets/bullet.png
Binary files differ
diff --git a/demos/2d/shower_of_bullets/bullets.gd b/demos/2d/shower_of_bullets/bullets.gd
new file mode 100644
index 0000000000..e0eba2682a
--- /dev/null
+++ b/demos/2d/shower_of_bullets/bullets.gd
@@ -0,0 +1,71 @@
+
+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 shape
+
+
+# Inner classes
+class Bullet:
+ var pos = Vector2()
+ var speed = 1.0
+ var body = RID()
+
+
+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)
+
+
+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
+ if (b.pos.x < -30):
+ 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
+
+ for i in range(BULLET_COUNT):
+ var b = Bullet.new()
+ 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)
+
+ 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)
+
+ bullets.append(b)
+
+ set_process(true)
+
+
+func _exit_tree():
+ for b in bullets:
+ Physics2DServer.free_rid(b.body)
+
+ Physics2DServer.free_rid(shape)
+ bullets.clear()
diff --git a/demos/2d/shower_of_bullets/engine.cfg b/demos/2d/shower_of_bullets/engine.cfg
new file mode 100644
index 0000000000..cad5751985
--- /dev/null
+++ b/demos/2d/shower_of_bullets/engine.cfg
@@ -0,0 +1,16 @@
+[application]
+
+name="Bullet Shower"
+main_scene="res://shower.scn"
+icon="res://icon.png"
+
+[display]
+
+width=1024
+height=600
+resizable=true
+stretch_aspect="keep"
+
+[physics_2d]
+
+cell_size=64
diff --git a/demos/2d/shower_of_bullets/face_happy.png b/demos/2d/shower_of_bullets/face_happy.png
new file mode 100644
index 0000000000..6ed643b62d
--- /dev/null
+++ b/demos/2d/shower_of_bullets/face_happy.png
Binary files differ
diff --git a/demos/2d/shower_of_bullets/face_sad.png b/demos/2d/shower_of_bullets/face_sad.png
new file mode 100644
index 0000000000..d6318b20a3
--- /dev/null
+++ b/demos/2d/shower_of_bullets/face_sad.png
Binary files differ
diff --git a/demos/2d/shower_of_bullets/icon.png b/demos/2d/shower_of_bullets/icon.png
new file mode 100644
index 0000000000..432c74a5a3
--- /dev/null
+++ b/demos/2d/shower_of_bullets/icon.png
Binary files differ
diff --git a/demos/2d/shower_of_bullets/shower.gd b/demos/2d/shower_of_bullets/shower.gd
new file mode 100644
index 0000000000..50c1109489
--- /dev/null
+++ b/demos/2d/shower_of_bullets/shower.gd
@@ -0,0 +1,25 @@
+
+extends Node2D
+
+# Member variables
+var touching = 0
+
+func _input(event):
+ if (event.type == InputEvent.MOUSE_MOTION):
+ get_node("player").set_pos(event.pos - Vector2(0, 16))
+
+
+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):
+ get_node("player/sprite").set_frame(0)
+
+
+func _ready():
+ set_process_input(true)
diff --git a/demos/2d/shower_of_bullets/shower.scn b/demos/2d/shower_of_bullets/shower.scn
new file mode 100644
index 0000000000..9e2181e9c6
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..9f6734e122
--- /dev/null
+++ b/demos/2d/space_shooter/asteroid.gd
@@ -0,0 +1,43 @@
+
+extends Area2D
+
+# Member variables
+const SPEED = -200
+const Y_RANDOM = 10
+
+var points = 1
+var speed_y = 0.0
+var destroyed = false
+
+
+func _process(delta):
+ translate(Vector2(SPEED, speed_y)*delta)
+
+
+func _ready():
+ speed_y = rand_range(-Y_RANDOM, Y_RANDOM)
+
+
+func destroy():
+ if (destroyed):
+ return
+ destroyed = true
+ get_node("anim").play("explode")
+ set_process(false)
+ get_node("sfx").play("sound_explode")
+ # Accumulate points
+ get_node("/root/game_state").points += 1
+
+
+func is_enemy():
+ return not destroyed
+
+
+func _on_visibility_enter_screen():
+ set_process(true)
+ # Make it spin!
+ get_node("anim").play("spin")
+
+
+func _on_visibility_exit_screen():
+ queue_free()
diff --git a/demos/2d/space_shooter/asteroid.scn b/demos/2d/space_shooter/asteroid.scn
new file mode 100644
index 0000000000..6bca98cd30
--- /dev/null
+++ b/demos/2d/space_shooter/asteroid.scn
Binary files differ
diff --git a/demos/2d/space_shooter/bg_gradient.png b/demos/2d/space_shooter/bg_gradient.png
new file mode 100644
index 0000000000..3e71976dc6
--- /dev/null
+++ b/demos/2d/space_shooter/bg_gradient.png
Binary files differ
diff --git a/demos/2d/space_shooter/big_star.png b/demos/2d/space_shooter/big_star.png
new file mode 100644
index 0000000000..7726a7aa12
--- /dev/null
+++ b/demos/2d/space_shooter/big_star.png
Binary files differ
diff --git a/demos/2d/space_shooter/enemy1.gd b/demos/2d/space_shooter/enemy1.gd
new file mode 100644
index 0000000000..204995c05d
--- /dev/null
+++ b/demos/2d/space_shooter/enemy1.gd
@@ -0,0 +1,36 @@
+
+extends Area2D
+
+# Member variables
+const SPEED = -200
+
+var destroyed=false
+
+
+func _process(delta):
+ get_parent().translate(Vector2(SPEED*delta, 0))
+
+
+func is_enemy():
+ return not destroyed
+
+
+func destroy():
+ if (destroyed):
+ return
+ destroyed = true
+ get_node("anim").play("explode")
+ set_process(false)
+ get_node("sfx").play("sound_explode")
+ # 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
+
+
+func _on_visibility_exit_screen():
+ queue_free()
diff --git a/demos/2d/space_shooter/enemy1.png b/demos/2d/space_shooter/enemy1.png
new file mode 100644
index 0000000000..242d8f0055
--- /dev/null
+++ b/demos/2d/space_shooter/enemy1.png
Binary files differ
diff --git a/demos/2d/space_shooter/enemy1.scn b/demos/2d/space_shooter/enemy1.scn
new file mode 100644
index 0000000000..805071b772
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..bfdb743103
--- /dev/null
+++ b/demos/2d/space_shooter/enemy2.gd
@@ -0,0 +1,51 @@
+
+extends Area2D
+
+# 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
+
+ if (shoot_timeout < 0):
+ shoot_timeout = SHOOT_INTERVAL
+
+ # 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
+ get_parent().add_child(shot)
+
+
+func is_enemy():
+ return not destroyed
+
+
+func destroy():
+ if (destroyed):
+ return
+ destroyed = true
+ get_node("anim").play("explode")
+ set_process(false)
+ get_node("sfx").play("sound_explode")
+ # Accumulate points
+ get_node("/root/game_state").points += 10
+
+
+func _ready():
+ set_fixed_process(true)
+
+
+func _on_visibility_enter_screen():
+ set_process(true)
+
+
+func _on_visibility_exit_screen():
+ queue_free()
diff --git a/demos/2d/space_shooter/enemy2.png b/demos/2d/space_shooter/enemy2.png
new file mode 100644
index 0000000000..5b63033696
--- /dev/null
+++ b/demos/2d/space_shooter/enemy2.png
Binary files differ
diff --git a/demos/2d/space_shooter/enemy2.scn b/demos/2d/space_shooter/enemy2.scn
new file mode 100644
index 0000000000..644add77aa
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..6c782b69f1
--- /dev/null
+++ b/demos/2d/space_shooter/enemy_shot.gd
@@ -0,0 +1,31 @@
+
+extends Area2D
+
+# Member variables
+const SPEED = -800
+
+var hit = false
+
+
+func _process(delta):
+ translate(Vector2(delta*SPEED, 0))
+
+
+func _ready():
+ set_process(true)
+
+
+func is_enemy():
+ return true
+
+
+func _hit_something():
+ if (hit):
+ return
+ 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.png b/demos/2d/space_shooter/enemy_shot.png
new file mode 100644
index 0000000000..04287211a9
--- /dev/null
+++ b/demos/2d/space_shooter/enemy_shot.png
Binary files differ
diff --git a/demos/2d/space_shooter/enemy_shot.scn b/demos/2d/space_shooter/enemy_shot.scn
new file mode 100644
index 0000000000..353c9058f7
--- /dev/null
+++ b/demos/2d/space_shooter/enemy_shot.scn
Binary files differ
diff --git a/demos/2d/space_shooter/engine.cfg b/demos/2d/space_shooter/engine.cfg
new file mode 100644
index 0000000000..8047cebdd3
--- /dev/null
+++ b/demos/2d/space_shooter/engine.cfg
@@ -0,0 +1,22 @@
+[application]
+
+name="Simple Shooter"
+main_scene="res://main_menu.scn"
+icon="res://icon.png"
+
+[autoload]
+
+game_state="res://game_state.gd"
+
+[display]
+
+width=1024
+height=600
+
+[input]
+
+move_up=[key(Up)]
+move_down=[key(Down)]
+move_left=[key(Left)]
+move_right=[key(Right)]
+shoot=[key(Space)]
diff --git a/demos/2d/space_shooter/explosion.scn b/demos/2d/space_shooter/explosion.scn
new file mode 100644
index 0000000000..6fc105fac3
--- /dev/null
+++ b/demos/2d/space_shooter/explosion.scn
Binary files differ
diff --git a/demos/2d/space_shooter/fire.png b/demos/2d/space_shooter/fire.png
new file mode 100644
index 0000000000..1c68c36213
--- /dev/null
+++ b/demos/2d/space_shooter/fire.png
Binary files differ
diff --git a/demos/2d/space_shooter/game_state.gd b/demos/2d/space_shooter/game_state.gd
new file mode 100644
index 0000000000..0aa5e1f42b
--- /dev/null
+++ b/demos/2d/space_shooter/game_state.gd
@@ -0,0 +1,22 @@
+
+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()
+
+
+func game_over():
+ if (points > max_points):
+ max_points = points
+ # Save high score
+ var f = File.new()
+ f.open("user://highscore", File.WRITE)
+ f.store_var(max_points)
diff --git a/demos/2d/space_shooter/icon.png b/demos/2d/space_shooter/icon.png
new file mode 100644
index 0000000000..1df2bf5d9d
--- /dev/null
+++ b/demos/2d/space_shooter/icon.png
Binary files differ
diff --git a/demos/2d/space_shooter/level.scn b/demos/2d/space_shooter/level.scn
new file mode 100644
index 0000000000..6d5f8005f5
--- /dev/null
+++ b/demos/2d/space_shooter/level.scn
Binary files differ
diff --git a/demos/2d/space_shooter/level_tiles.res b/demos/2d/space_shooter/level_tiles.res
new file mode 100644
index 0000000000..8712b8c799
--- /dev/null
+++ b/demos/2d/space_shooter/level_tiles.res
Binary files differ
diff --git a/demos/2d/space_shooter/level_tiles.scn b/demos/2d/space_shooter/level_tiles.scn
new file mode 100644
index 0000000000..932be39a29
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..a7f242da7b
--- /dev/null
+++ b/demos/2d/space_shooter/main_menu.gd
@@ -0,0 +1,11 @@
+
+extends Control
+
+
+func _ready():
+ 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_tree().change_scene("res://level.scn")
diff --git a/demos/2d/space_shooter/main_menu.scn b/demos/2d/space_shooter/main_menu.scn
new file mode 100644
index 0000000000..91b0b37b14
--- /dev/null
+++ b/demos/2d/space_shooter/main_menu.scn
Binary files differ
diff --git a/demos/2d/space_shooter/meteorite.png b/demos/2d/space_shooter/meteorite.png
new file mode 100644
index 0000000000..92fb4387df
--- /dev/null
+++ b/demos/2d/space_shooter/meteorite.png
Binary files differ
diff --git a/demos/2d/space_shooter/parallax.scn b/demos/2d/space_shooter/parallax.scn
new file mode 100644
index 0000000000..2753d16e84
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..7362dff97d
--- /dev/null
+++ b/demos/2d/space_shooter/rail.gd
@@ -0,0 +1,19 @@
+
+extends Node2D
+
+# Member variables
+const SPEED = 200
+var offset = 0
+
+
+func stop():
+ set_process(false)
+
+
+func _process(delta):
+ offset += delta*SPEED
+ set_pos(Vector2(offset, 0))
+
+
+func _ready():
+ set_process(true)
diff --git a/demos/2d/space_shooter/ship.gd b/demos/2d/space_shooter/ship.gd
new file mode 100644
index 0000000000..b6c1200632
--- /dev/null
+++ b/demos/2d/space_shooter/ship.gd
@@ -0,0 +1,81 @@
+
+extends Area2D
+
+# Member variables
+const SPEED = 200
+
+var screen_size
+var prev_shooting = false
+var killed = false
+
+
+func _process(delta):
+ var motion = Vector2()
+ if Input.is_action_pressed("move_up"):
+ motion += Vector2(0, -1)
+ if Input.is_action_pressed("move_down"):
+ motion += Vector2(0, 1)
+ if Input.is_action_pressed("move_left"):
+ motion += Vector2(-1, 0)
+ if Input.is_action_pressed("move_right"):
+ 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
+
+ set_pos(pos)
+
+ if (shooting and not prev_shooting):
+ # Just pressed
+ var shot = preload("res://shot.scn").instance()
+ # 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
+ 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))
+
+
+func _ready():
+ screen_size = get_viewport().get_rect().size
+ set_process(true)
+
+
+func _hit_something():
+ if (killed):
+ return
+ killed = true
+ get_node("anim").play("explode")
+ get_node("sfx").play("sound_explode")
+ get_node("../hud/game_over").show()
+ get_node("/root/game_state").game_over()
+ get_parent().stop()
+ set_process(false)
+
+
+func _on_ship_body_enter(body):
+ _hit_something()
+
+
+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")
diff --git a/demos/2d/space_shooter/ship.png b/demos/2d/space_shooter/ship.png
new file mode 100644
index 0000000000..a36b833903
--- /dev/null
+++ b/demos/2d/space_shooter/ship.png
Binary files differ
diff --git a/demos/2d/space_shooter/ship.scn b/demos/2d/space_shooter/ship.scn
new file mode 100644
index 0000000000..c60e2e3e3b
--- /dev/null
+++ b/demos/2d/space_shooter/ship.scn
Binary files differ
diff --git a/demos/2d/space_shooter/shoot.png b/demos/2d/space_shooter/shoot.png
new file mode 100644
index 0000000000..6e80ddab93
--- /dev/null
+++ b/demos/2d/space_shooter/shoot.png
Binary files differ
diff --git a/demos/2d/space_shooter/shot.gd b/demos/2d/space_shooter/shot.gd
new file mode 100644
index 0000000000..936dde73d1
--- /dev/null
+++ b/demos/2d/space_shooter/shot.gd
@@ -0,0 +1,40 @@
+
+extends Area2D
+
+# Member variables
+const SPEED = 800
+
+var hit = false
+
+
+func _process(delta):
+ translate(Vector2(delta*SPEED, 0))
+
+
+func _ready():
+ set_process(true)
+
+
+func _hit_something():
+ if (hit):
+ return
+ hit = true
+ set_process(false)
+ get_node("anim").play("splash")
+
+
+func _on_visibility_exit_screen():
+ queue_free()
+
+
+func _on_shot_area_enter(area):
+ # Hit an enemy or asteroid
+ if (area.has_method("destroy")):
+ # Duck typing at it's best
+ area.destroy()
+ _hit_something()
+
+
+func _on_shot_body_enter(body):
+ # Hit the tilemap
+ _hit_something()
diff --git a/demos/2d/space_shooter/shot.scn b/demos/2d/space_shooter/shot.scn
new file mode 100644
index 0000000000..9daf4ebe82
--- /dev/null
+++ b/demos/2d/space_shooter/shot.scn
Binary files differ
diff --git a/demos/2d/space_shooter/small_star.png b/demos/2d/space_shooter/small_star.png
new file mode 100644
index 0000000000..71c3c531cd
--- /dev/null
+++ b/demos/2d/space_shooter/small_star.png
Binary files differ
diff --git a/demos/2d/space_shooter/sound_explode.wav b/demos/2d/space_shooter/sound_explode.wav
new file mode 100644
index 0000000000..229c85399c
--- /dev/null
+++ b/demos/2d/space_shooter/sound_explode.wav
Binary files differ
diff --git a/demos/2d/space_shooter/sound_shoot.wav b/demos/2d/space_shooter/sound_shoot.wav
new file mode 100644
index 0000000000..ad74f328cb
--- /dev/null
+++ b/demos/2d/space_shooter/sound_shoot.wav
Binary files differ
diff --git a/demos/2d/space_shooter/tile.png b/demos/2d/space_shooter/tile.png
new file mode 100644
index 0000000000..d8f41d16f6
--- /dev/null
+++ b/demos/2d/space_shooter/tile.png
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/cubio.png b/demos/2d/sprite_shaders/cubio.png
new file mode 100644
index 0000000000..6f76220225
--- /dev/null
+++ b/demos/2d/sprite_shaders/cubio.png
Binary files differ
diff --git a/demos/2d/sprite_shaders/engine.cfg b/demos/2d/sprite_shaders/engine.cfg
new file mode 100644
index 0000000000..17bdada188
--- /dev/null
+++ b/demos/2d/sprite_shaders/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+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
new file mode 100644
index 0000000000..b6060f8eaa
--- /dev/null
+++ 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 dc89300881..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,129 +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
- 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/OpenCV_Chessboard.png b/demos/2d/texscreen/OpenCV_Chessboard.png
new file mode 100644
index 0000000000..31b7f8ccd8
--- /dev/null
+++ b/demos/2d/texscreen/OpenCV_Chessboard.png
Binary files differ
diff --git a/demos/2d/texscreen/bubble.png b/demos/2d/texscreen/bubble.png
new file mode 100644
index 0000000000..021abba601
--- /dev/null
+++ b/demos/2d/texscreen/bubble.png
Binary files differ
diff --git a/demos/2d/texscreen/bubbles.gd b/demos/2d/texscreen/bubbles.gd
new file mode 100644
index 0000000000..400da1a205
--- /dev/null
+++ b/demos/2d/texscreen/bubbles.gd
@@ -0,0 +1,11 @@
+
+extends Control
+
+# Member variables
+const MAX_BUBBLES = 10
+
+
+func _ready():
+ for i in range(MAX_BUBBLES):
+ var bubble = preload("res://lens.scn").instance()
+ add_child(bubble)
diff --git a/demos/2d/texscreen/bubbles.scn b/demos/2d/texscreen/bubbles.scn
new file mode 100644
index 0000000000..8509b3811c
--- /dev/null
+++ b/demos/2d/texscreen/bubbles.scn
Binary files differ
diff --git a/demos/2d/texscreen/burano.png b/demos/2d/texscreen/burano.png
new file mode 100644
index 0000000000..6eec09d585
--- /dev/null
+++ b/demos/2d/texscreen/burano.png
Binary files differ
diff --git a/demos/2d/texscreen/engine.cfg b/demos/2d/texscreen/engine.cfg
new file mode 100644
index 0000000000..92d0e98d5b
--- /dev/null
+++ b/demos/2d/texscreen/engine.cfg
@@ -0,0 +1,12 @@
+[application]
+
+name="Glass Bubbles (Texscreen)"
+main_scene="res://bubbles.scn"
+icon="res://icon.png"
+
+[display]
+
+width=800
+height=600
+stretch_mode="2d"
+stretch_aspect="keep"
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
new file mode 100644
index 0000000000..d1007553b0
--- /dev/null
+++ b/demos/2d/texscreen/lens.gd
@@ -0,0 +1,32 @@
+
+extends BackBufferCopy
+
+# Member variables
+const MOTION_SPEED = 150
+
+var vsize
+var dir
+
+
+func _process(delta):
+ 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)
+
+ 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()
+ set_process(true)
diff --git a/demos/2d/texscreen/lens.scn b/demos/2d/texscreen/lens.scn
new file mode 100644
index 0000000000..530a0b1eb0
--- /dev/null
+++ 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/cubelib.res b/demos/3d/kinematic_char/cubelib.res
new file mode 100644
index 0000000000..130b9529fe
--- /dev/null
+++ b/demos/3d/kinematic_char/cubelib.res
Binary files differ
diff --git a/demos/3d/kinematic_char/cubio.gd b/demos/3d/kinematic_char/cubio.gd
new file mode 100644
index 0000000000..769ada3bca
--- /dev/null
+++ b/demos/3d/kinematic_char/cubio.gd
@@ -0,0 +1,86 @@
+
+extends KinematicBody
+
+# Member variables
+var g = -9.8
+var vel = Vector3()
+const MAX_SPEED = 5
+const JUMP_SPEED = 7
+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
+ var cam_xform = get_node("target/camera").get_global_transform()
+
+ if (Input.is_action_pressed("move_forward")):
+ dir += -cam_xform.basis[2]
+ if (Input.is_action_pressed("move_backwards")):
+ dir += cam_xform.basis[2]
+ if (Input.is_action_pressed("move_left")):
+ 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
+
+ var hvel = vel
+ hvel.y = 0
+
+ var target = dir*MAX_SPEED
+ var accel
+ if (dir.dot(hvel) > 0):
+ accel = ACCEL
+ else:
+ accel = DEACCEL
+
+ hvel = hvel.linear_interpolate(target, accel*delta)
+
+ 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
+
+ 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
+
+ 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
+ motion=move(motion)
+ if (motion.length() < 0.001):
+ break
+ 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
+
+ var crid = get_node("../elevator1").get_rid()
+
+
+func _ready():
+ set_fixed_process(true)
+
+
+func _on_tcube_body_enter(body):
+ get_node("../ty").show()
diff --git a/demos/3d/kinematic_char/engine.cfg b/demos/3d/kinematic_char/engine.cfg
new file mode 100644
index 0000000000..b3060b65e0
--- /dev/null
+++ b/demos/3d/kinematic_char/engine.cfg
@@ -0,0 +1,17 @@
+[application]
+
+name="Kinematic Character 3D"
+main_scene="res://level.scn"
+icon="res://kinebody3d.png"
+
+[input]
+
+move_forward=[key(Up)]
+move_left=[key(Left)]
+move_right=[key(Right)]
+move_backwards=[key(Down)]
+jump=[key(Space)]
+
+[rasterizer]
+
+shadow_filter=3
diff --git a/demos/3d/kinematic_char/follow_camera.gd b/demos/3d/kinematic_char/follow_camera.gd
new file mode 100644
index 0000000000..37a1402053
--- /dev/null
+++ b/demos/3d/kinematic_char/follow_camera.gd
@@ -0,0 +1,57 @@
+
+extends Camera
+
+# 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 pos = get_global_transform().origin
+ var up = Vector3(0, 1, 0)
+
+ var delta = pos - target
+
+ # Regular delta follow
+
+ # Check ranges
+ if (delta.length() < min_distance):
+ delta = delta.normalized()*min_distance
+ elif (delta.length() > max_distance):
+ delta = delta.normalized()*max_distance
+
+ # 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)
+
+ # Turn a little up or down
+ var t = get_transform()
+ t.basis = Matrix3(t.basis[0], deg2rad(angle_v_adjust))*t.basis
+ set_transform(t)
+
+
+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()
+ set_fixed_process(true)
+ # This detaches the camera transform from the parent spatial node
+ set_as_toplevel(true)
diff --git a/demos/3d/kinematic_char/kinebody3d.png b/demos/3d/kinematic_char/kinebody3d.png
new file mode 100644
index 0000000000..41f0edb246
--- /dev/null
+++ b/demos/3d/kinematic_char/kinebody3d.png
Binary files differ
diff --git a/demos/3d/kinematic_char/level.scn b/demos/3d/kinematic_char/level.scn
new file mode 100644
index 0000000000..0082f55f43
--- /dev/null
+++ b/demos/3d/kinematic_char/level.scn
Binary files differ
diff --git a/demos/3d/kinematic_char/purple_wood.tex b/demos/3d/kinematic_char/purple_wood.tex
new file mode 100644
index 0000000000..cdf0f810f1
--- /dev/null
+++ b/demos/3d/kinematic_char/purple_wood.tex
Binary files differ
diff --git a/demos/3d/kinematic_char/purplecube.scn b/demos/3d/kinematic_char/purplecube.scn
new file mode 100644
index 0000000000..e3ed1bf84b
--- /dev/null
+++ b/demos/3d/kinematic_char/purplecube.scn
Binary files differ
diff --git a/demos/3d/kinematic_char/twood.tex b/demos/3d/kinematic_char/twood.tex
new file mode 100644
index 0000000000..65c1bd043c
--- /dev/null
+++ b/demos/3d/kinematic_char/twood.tex
Binary files differ
diff --git a/demos/3d/kinematic_char/white_wood.tex b/demos/3d/kinematic_char/white_wood.tex
new file mode 100644
index 0000000000..e003442e70
--- /dev/null
+++ b/demos/3d/kinematic_char/white_wood.tex
Binary files differ
diff --git a/demos/3d/mousepick_test/engine.cfg b/demos/3d/mousepick_test/engine.cfg
new file mode 100644
index 0000000000..093999a87a
--- /dev/null
+++ b/demos/3d/mousepick_test/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+name="3D Mouse Picking Test"
+main_scene="res://mousepick.scn"
+icon="res://icon.png"
diff --git a/demos/3d/mousepick_test/icon.png b/demos/3d/mousepick_test/icon.png
new file mode 100644
index 0000000000..264f991e15
--- /dev/null
+++ b/demos/3d/mousepick_test/icon.png
Binary files differ
diff --git a/demos/3d/mousepick_test/mousepick.gd b/demos/3d/mousepick_test/mousepick.gd
new file mode 100644
index 0000000000..674ec7ff6f
--- /dev/null
+++ b/demos/3d/mousepick_test/mousepick.gd
@@ -0,0 +1,24 @@
+
+extends RigidBody
+
+# Member variables
+var gray_mat = FixedMaterial.new()
+var selected = false
+
+
+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)
+ else:
+ 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))
diff --git a/demos/3d/mousepick_test/mousepick.scn b/demos/3d/mousepick_test/mousepick.scn
new file mode 100644
index 0000000000..0b6c33c119
--- /dev/null
+++ b/demos/3d/mousepick_test/mousepick.scn
Binary files differ
diff --git a/demos/3d/navmesh/engine.cfg b/demos/3d/navmesh/engine.cfg
new file mode 100644
index 0000000000..30af6ce5a5
--- /dev/null
+++ b/demos/3d/navmesh/engine.cfg
@@ -0,0 +1,9 @@
+[application]
+
+name="Navmesh Demo"
+main_scene="res://navmesh.scn"
+icon="res://icon.png"
+
+[rasterizer]
+
+shadow_filter=3
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
new file mode 100644
index 0000000000..30b8cfb32a
--- /dev/null
+++ b/demos/3d/navmesh/navmesh.gd
@@ -0,0 +1,95 @@
+
+extends Navigation
+
+# Member variables
+const SPEED = 4.0
+
+var camrot = 0.0
+
+var begin = Vector3()
+var end = Vector3()
+var m = FixedMaterial.new()
+
+var path = []
+var draw_path = false
+
+
+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]
+ to_watch = (pto - pfrom).normalized()
+ var d = pfrom.distance_to(pto)
+ 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]
+ var atdir = to_watch
+ atdir.y = 0
+
+ var t = Transform()
+ 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 = []
+ set_process(false)
+ else:
+ set_process(false)
+
+
+func _update_path():
+ 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)
+
+ if (draw_path):
+ var im = get_node("draw")
+ im.set_material_override(m)
+ im.clear()
+ im.begin(Mesh.PRIMITIVE_POINTS, null)
+ im.add_vertex(begin)
+ im.add_vertex(end)
+ im.end()
+ im.begin(Mesh.PRIMITIVE_LINE_STRIP, null)
+ for x in p:
+ im.add_vertex(x)
+ im.end()
+
+
+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 (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():
+ 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)
+ #begin = get_closest_point(get_node("start").get_translation())
+ #end = get_closest_point(get_node("end").get_translation())
+ #call_deferred("_update_path")
diff --git a/demos/3d/navmesh/navmesh.scn b/demos/3d/navmesh/navmesh.scn
new file mode 100644
index 0000000000..33183781ad
--- /dev/null
+++ b/demos/3d/navmesh/navmesh.scn
Binary files differ
diff --git a/demos/3d/navmesh/particle.png b/demos/3d/navmesh/particle.png
new file mode 100644
index 0000000000..18851c8c9d
--- /dev/null
+++ b/demos/3d/navmesh/particle.png
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 43f48fc99f..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 449bb0f895..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 1d0e0315d9..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(true)
- cc.disabled=true
+ set_friction(1)
+ 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 b3f69af600..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..84cac52c97 100644
--- a/demos/3d/platformer/engine.cfg
+++ b/demos/3d/platformer/engine.cfg
@@ -1,7 +1,7 @@
[application]
name="Platformer 3D"
-main_scene="res://stage.xml"
+main_scene="res://stage.scn"
icon="res://icon.png"
[display]
diff --git a/demos/3d/platformer/follow_camera.gd b/demos/3d/platformer/follow_camera.gd
index 0b9ff9bbb2..d0d531b9a5 100644
--- a/demos/3d/platformer/follow_camera.gd
+++ b/demos/3d/platformer/follow_camera.gd
@@ -1,92 +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,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!=null):
- #if main ray was occluded, get camera closer, this is the worst case scenario
+ if (!col.empty()):
+ # If main ray was occluded, get camera closer, this is the worst case scenario
delta = col.position - target
- elif (col_left!=null and col_right==null):
- #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==null and col_right!=null):
- #if only right ray is occluded, turn the camera around to the left
- delta = Matrix3(up,deg2rad(dt*autoturn_speed)).xform(delta)
+ 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)
+ 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)
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
+ # 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..854a8397e4
--- /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 f3a5caffa9..0000000000
--- a/demos/3d/platformer/stage.xml
+++ /dev/null
@@ -1,356 +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.3917-beta1">
- <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://coin.scn" type="PackedScene"></ext_resource>
- <ext_resource path="res://player.xml" 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>
- <real name="hdr/exposure"> 0.4 </real>
- <real name="hdr/scalar"> 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="92">
- <string> "world" </string>
- <string> "Spatial" </string>
- <string> "_import_path" </string>
- <string> "_import_transform" </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/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="79" shared="false">
- <node_path> "" </node_path>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </transform>
- <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> "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> 0.261354 </real>
- <string> "x_rot" </string>
- <real> 0.458294 </real>
- <string> "y_rot" </string>
- <real> -1.2 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </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> "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="MeshLibrary" path="res://tiles.res"> </resource>
- <bool> False </bool>
- <real> 2 </real>
- <int> 4 </int>
- <bool> True </bool>
- <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>
- <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>
- <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>
- </array>
- <string> "nodes" </string>
- <int_array len="569"> -1, -1, 1, 0, -1, 3, 2, 0, 3, 1, 4, 2, 0, 0, 0, 5, 5, -1, 13, 2, 0, 3, 1, 6, 3, 7, 4, 8, 4, 9, 5, 10, 6, 11, 7, 12, 7, 13, 7, 14, 8, 15, 9, 4, 10, 0, 0, 0, 16, 16, -1, 21, 2, 0, 3, 1, 17, 11, 18, 12, 19, 7, 20, 13, 21, 14, 22, 15, 23, 15, 24, 7, 25, 16, 26, 17, 27, 18, 28, 19, 29, 20, 30, 21, 31, 13, 32, 22, 33, 23, 34, 24, 35, 5, 0, 0, 0, 37, 36, -1, 3, 2, 0, 3, 1, 36, 25, 0, 0, 0, 39, 38, -1, 2, 2, 0, 4, 26, 0, 4, 0, 41, 40, 27, 1, 17, 28, 0, 4, 0, 41, 42, 27, 1, 17, 29, 0, 4, 0, 41, 43, 27, 1, 17, 30, 0, 4, 0, 41, 44, 27, 1, 17, 31, 0, 4, 0, 41, 45, 27, 1, 17, 32, 0, 4, 0, 41, 46, 27, 1, 17, 33, 0, 4, 0, 41, 47, 27, 1, 17, 34, 0, 4, 0, 41, 48, 27, 1, 17, 35, 0, 4, 0, 41, 49, 27, 1, 17, 36, 0, 4, 0, 41, 50, 27, 1, 17, 37, 0, 4, 0, 41, 51, 27, 1, 17, 38, 0, 4, 0, 41, 52, 27, 1, 17, 39, 0, 4, 0, 41, 53, 27, 1, 17, 40, 0, 4, 0, 41, 54, 27, 1, 17, 41, 0, 4, 0, 41, 55, 27, 1, 17, 42, 0, 4, 0, 41, 56, 27, 1, 17, 43, 0, 4, 0, 41, 57, 27, 1, 17, 44, 0, 4, 0, 41, 58, 27, 1, 17, 45, 0, 4, 0, 41, 59, 27, 1, 17, 46, 0, 4, 0, 41, 60, 27, 1, 17, 47, 0, 4, 0, 41, 61, 27, 1, 17, 48, 0, 4, 0, 41, 62, 27, 1, 17, 49, 0, 4, 0, 41, 63, 27, 1, 17, 50, 0, 4, 0, 41, 64, 27, 1, 17, 51, 0, 4, 0, 41, 65, 27, 1, 17, 52, 0, 4, 0, 41, 66, 27, 1, 17, 53, 0, 4, 0, 41, 67, 27, 1, 17, 54, 0, 4, 0, 41, 68, 27, 1, 17, 55, 0, 4, 0, 41, 69, 27, 1, 17, 56, 0, 4, 0, 41, 70, 27, 1, 17, 57, 0, 4, 0, 41, 71, 27, 1, 17, 58, 0, 4, 0, 41, 72, 27, 1, 17, 59, 0, 4, 0, 41, 73, 27, 1, 17, 60, 0, 4, 0, 41, 74, 27, 1, 17, 61, 0, 4, 0, 41, 75, 27, 1, 17, 62, 0, 4, 0, 41, 76, 27, 1, 17, 63, 0, 4, 0, 41, 77, 27, 1, 17, 64, 0, 4, 0, 41, 78, 27, 1, 17, 65, 0, 4, 0, 41, 79, 27, 1, 17, 66, 0, 4, 0, 41, 80, 27, 1, 17, 67, 0, 4, 0, 41, 81, 27, 1, 17, 68, 0, 4, 0, 41, 82, 27, 1, 17, 69, 0, 4, 0, 41, 83, 27, 1, 17, 70, 0, 4, 0, 41, 84, 27, 1, 17, 71, 0, 0, 0, 39, 85, -1, 1, 2, 0, 0, 49, 0, 87, 86, 72, 1, 17, 73, 0, 49, 0, 87, 88, 72, 1, 17, 74, 0, 49, 0, 87, 89, 72, 1, 17, 75, 0, 49, 0, 87, 90, 72, 1, 17, 76, 0, 0, 0, 87, 91, 77, 1, 17, 78, 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/texture.tex b/demos/3d/platformer/texture.tex
index 24c4607ab1..d9181b7ffa 100644
--- a/demos/3d/platformer/texture.tex
+++ b/demos/3d/platformer/texture.tex
Binary files differ
diff --git a/demos/3d/platformer/tiles.res b/demos/3d/platformer/tiles.res
index 53534788a1..d4fb779ff1 100644
--- a/demos/3d/platformer/tiles.res
+++ b/demos/3d/platformer/tiles.res
Binary files differ
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 d6a3efe73f..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
new file mode 100644
index 0000000000..acfbfae162
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..4efcf63426
--- /dev/null
+++ b/demos/3d/truck_town/car_select.gd
@@ -0,0 +1,32 @@
+
+extends Control
+
+# Member variables
+var town = null
+
+
+func _back():
+ town.queue_free()
+ show()
+
+
+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")
+ get_parent().add_child(town)
+ hide()
+
+
+func _on_van_1_pressed():
+ _load_scene("res://car_base.scn")
+
+
+func _on_van_2_pressed():
+ _load_scene("res://trailer_truck.scn")
+
+
+func _on_van_3_pressed():
+ _load_scene("res://crane.scn")
diff --git a/demos/3d/truck_town/car_select.scn b/demos/3d/truck_town/car_select.scn
new file mode 100644
index 0000000000..d838e995b2
--- /dev/null
+++ b/demos/3d/truck_town/car_select.scn
Binary files differ
diff --git a/demos/3d/truck_town/cement.tex b/demos/3d/truck_town/cement.tex
new file mode 100644
index 0000000000..a80cde6464
--- /dev/null
+++ b/demos/3d/truck_town/cement.tex
Binary files differ
diff --git a/demos/3d/truck_town/choose_tow.png b/demos/3d/truck_town/choose_tow.png
new file mode 100644
index 0000000000..8f92833450
--- /dev/null
+++ b/demos/3d/truck_town/choose_tow.png
Binary files differ
diff --git a/demos/3d/truck_town/choose_trailer.png b/demos/3d/truck_town/choose_trailer.png
new file mode 100644
index 0000000000..ead3330296
--- /dev/null
+++ b/demos/3d/truck_town/choose_trailer.png
Binary files differ
diff --git a/demos/3d/truck_town/choose_van.png b/demos/3d/truck_town/choose_van.png
new file mode 100644
index 0000000000..1ecdd54372
--- /dev/null
+++ b/demos/3d/truck_town/choose_van.png
Binary files differ
diff --git a/demos/3d/truck_town/crane.scn b/demos/3d/truck_town/crane.scn
new file mode 100644
index 0000000000..dfddd97882
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..b2a463e1e2
--- /dev/null
+++ b/demos/3d/truck_town/engine.cfg
@@ -0,0 +1,14 @@
+[application]
+
+name="Truck Town"
+main_scene="res://car_select.scn"
+icon="res://icon.png"
+
+[display]
+
+width=1280
+height=720
+
+[rasterizer]
+
+shadow_filter=3
diff --git a/demos/3d/truck_town/follow_camera.gd b/demos/3d/truck_town/follow_camera.gd
new file mode 100644
index 0000000000..7c6a0a2ba6
--- /dev/null
+++ b/demos/3d/truck_town/follow_camera.gd
@@ -0,0 +1,57 @@
+
+extends Camera
+
+# 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 pos = get_global_transform().origin
+ var up = Vector3(0, 1, 0)
+
+ var delta = pos - target
+
+ # Regular delta follow
+
+ # Check ranges
+ if (delta.length() < min_distance):
+ delta = delta.normalized()*min_distance
+ elif (delta.length() > max_distance):
+ delta = delta.normalized()*max_distance
+
+ # 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)
+
+ # Turn a little up or down
+ var t = get_transform()
+ t.basis = Matrix3(t.basis[0], deg2rad(angle_v_adjust))*t.basis
+ set_transform(t)
+
+
+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()
+ set_fixed_process(true)
+ # This detaches the camera transform from the parent spatial node
+ set_as_toplevel(true)
diff --git a/demos/3d/truck_town/grass.tex b/demos/3d/truck_town/grass.tex
new file mode 100644
index 0000000000..c28d060697
--- /dev/null
+++ b/demos/3d/truck_town/grass.tex
Binary files differ
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
new file mode 100644
index 0000000000..6fcf83e270
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..0c1be13ce2
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..4a8f7e7e52
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..c4224577c6
--- /dev/null
+++ b/demos/3d/truck_town/vehicle.gd
@@ -0,0 +1,45 @@
+
+extends VehicleBody
+
+# Member variables
+const STEER_SPEED = 1
+const STEER_LIMIT = 0.4
+
+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
+ elif (Input.is_action_pressed("ui_right")):
+ steer_target = STEER_LIMIT
+ else:
+ 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
+ elif (steer_target > steer_angle):
+ steer_angle += STEER_SPEED*delta
+ if (steer_target < steer_angle):
+ steer_angle = steer_target
+
+ set_steering(steer_angle)
+
+
+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
new file mode 100644
index 0000000000..9dec254ef7
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..719c42fe8f
--- /dev/null
+++ b/demos/gui/drag_and_drop/drag_drop_script.gd
@@ -0,0 +1,20 @@
+
+extends ColorPickerButton
+
+
+func get_drag_data(pos):
+ # Use another colorpicker as drag preview
+ var cpb = ColorPickerButton.new()
+ cpb.set_color(get_color())
+ cpb.set_size(Vector2(50, 50))
+ set_drag_preview(cpb)
+ # Return color as drag data
+ return get_color()
+
+
+func can_drop_data(pos, data):
+ return typeof(data) == TYPE_COLOR
+
+
+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
new file mode 100644
index 0000000000..49b9b93512
--- /dev/null
+++ b/demos/gui/drag_and_drop/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+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
new file mode 100644
index 0000000000..3cee6e6871
--- /dev/null
+++ b/demos/gui/input_mapping/controls.gd
@@ -0,0 +1,54 @@
+
+extends Control
+
+# Note for the reader:
+#
+# This demo conveniently uses the same names for actions and for the container nodes
+# that hold each remapping button. This allow to get back to the button based simply
+# on the name of the corresponding action, but it might not be so simple in your project.
+#
+# A better approach for large-scale input remapping might be to do the connections between
+# buttons and wait_for_input through the code, passing as arguments both the name of the
+# action and the node, e.g.:
+# button.connect("pressed", self, "wait_for_input", [ button, action ])
+
+# 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
+ button = get_node("bindings").get_node(action).get_node("Button")
+ 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):
+ # Register the event as handled and stop polling
+ get_tree().set_input_as_handled()
+ set_process_input(false)
+ # Reinitialise the contextual help label
+ get_node("contextual_help").set_text("Click a key binding to reassign it, or press the Cancel action.")
+ if (not event.is_action("ui_cancel")):
+ # Display the string corresponding to the pressed key
+ button.set_text(OS.get_scancode_string(event.scancode))
+ # Start by removing previously key binding(s)
+ for old_event in InputMap.get_action_list(action):
+ InputMap.action_erase_event(action, old_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
+ for action in player_actions:
+ # We assume that the key binding that we want is the first one (0), if there are several
+ input_event = InputMap.get_action_list(action)[0]
+ # See note at the beginning of the script
+ get_node("bindings").get_node(action).get_node("Button").set_text(OS.get_scancode_string(input_event.scancode))
diff --git a/demos/gui/input_mapping/controls.scn b/demos/gui/input_mapping/controls.scn
new file mode 100644
index 0000000000..98cbbca464
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..811635ce25
--- /dev/null
+++ b/demos/gui/input_mapping/engine.cfg
@@ -0,0 +1,18 @@
+[application]
+
+name="Input Mapping GUI"
+main_scene="res://controls.scn"
+icon="res://icon.png"
+
+[display]
+
+width=640
+height=480
+
+[input]
+
+move_up=[key(Up)]
+move_down=[key(Down)]
+move_left=[key(Left)]
+move_right=[key(Right)]
+jump=[key(Space)]
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/OFL.txt b/demos/gui/rich_text_bbcode/OFL.txt
new file mode 100644
index 0000000000..723d4560b9
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/OFL.txt
@@ -0,0 +1,92 @@
+Copyright (c) 2009-2011 by Accademia di Belle Arti di Urbino and students of MA course of Visual design. Some rights reserved.
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/demos/gui/rich_text_bbcode/TitilliumWeb-Bold.ttf b/demos/gui/rich_text_bbcode/TitilliumWeb-Bold.ttf
new file mode 100644
index 0000000000..0af0fe7d27
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/TitilliumWeb-Bold.ttf
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/TitilliumWeb-BoldItalic.ttf b/demos/gui/rich_text_bbcode/TitilliumWeb-BoldItalic.ttf
new file mode 100644
index 0000000000..77425eaab6
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/TitilliumWeb-BoldItalic.ttf
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/TitilliumWeb-Italic.ttf b/demos/gui/rich_text_bbcode/TitilliumWeb-Italic.ttf
new file mode 100644
index 0000000000..42f2c10f18
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/TitilliumWeb-Italic.ttf
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/TitilliumWeb-Regular.ttf b/demos/gui/rich_text_bbcode/TitilliumWeb-Regular.ttf
new file mode 100644
index 0000000000..6da821935d
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/TitilliumWeb-Regular.ttf
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/engine.cfg b/demos/gui/rich_text_bbcode/engine.cfg
new file mode 100644
index 0000000000..5f68b6a0e6
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+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
new file mode 100644
index 0000000000..79a08c1303
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/rich_text_bbcode.gd
@@ -0,0 +1,6 @@
+
+extends Panel
+
+
+func _on_RichTextLabel_meta_clicked(meta):
+ OS.shell_open(meta)
diff --git a/demos/gui/rich_text_bbcode/rich_text_bbcode.scn b/demos/gui/rich_text_bbcode/rich_text_bbcode.scn
new file mode 100644
index 0000000000..c908d44dc3
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/rich_text_bbcode.scn
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/titilium-bold.fnt b/demos/gui/rich_text_bbcode/titilium-bold.fnt
new file mode 100644
index 0000000000..7920ca743d
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/titilium-bold.fnt
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/titilium-bolditalic.fnt b/demos/gui/rich_text_bbcode/titilium-bolditalic.fnt
new file mode 100644
index 0000000000..cc2d650d08
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/titilium-bolditalic.fnt
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/titilium-italic.fnt b/demos/gui/rich_text_bbcode/titilium-italic.fnt
new file mode 100644
index 0000000000..f2e8edf2c2
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/titilium-italic.fnt
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/titilium-regular.fnt b/demos/gui/rich_text_bbcode/titilium-regular.fnt
new file mode 100644
index 0000000000..fc3b789e11
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/titilium-regular.fnt
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/unicorn_icon.png b/demos/gui/rich_text_bbcode/unicorn_icon.png
new file mode 100644
index 0000000000..a14517e12b
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/unicorn_icon.png
Binary files differ
diff --git a/demos/gui/translation/controls.gd b/demos/gui/translation/controls.gd
new file mode 100644
index 0000000000..ae2e26362b
--- /dev/null
+++ b/demos/gui/translation/controls.gd
@@ -0,0 +1,9 @@
+
+extends Panel
+
+
+func _on_back_pressed():
+ var s = load("res://main.scn")
+ var si = s.instance()
+ get_parent().add_child(si)
+ queue_free()
diff --git a/demos/gui/translation/controls.scn b/demos/gui/translation/controls.scn
new file mode 100644
index 0000000000..055ac90b9b
--- /dev/null
+++ b/demos/gui/translation/controls.scn
Binary files differ
diff --git a/demos/gui/translation/engine.cfg b/demos/gui/translation/engine.cfg
new file mode 100644
index 0000000000..dcd3d1983d
--- /dev/null
+++ b/demos/gui/translation/engine.cfg
@@ -0,0 +1,10 @@
+[application]
+
+name="Translation Demo"
+main_scene="res://main.scn"
+icon="res://icon.png"
+
+[locale]
+
+translations=["res://translations/text.en.xl", "res://translations/text.es.xl", "res://translations/text.ja.xl"]
+translation_remaps={"res://flag_uk.png":["res://flag_spain.png:es", "res://flag_japan.png:ja"]}
diff --git a/demos/gui/translation/flag_japan.png b/demos/gui/translation/flag_japan.png
new file mode 100644
index 0000000000..4cc8267a5c
--- /dev/null
+++ b/demos/gui/translation/flag_japan.png
Binary files differ
diff --git a/demos/gui/translation/flag_spain.png b/demos/gui/translation/flag_spain.png
new file mode 100644
index 0000000000..4d00f93593
--- /dev/null
+++ b/demos/gui/translation/flag_spain.png
Binary files differ
diff --git a/demos/gui/translation/flag_uk.png b/demos/gui/translation/flag_uk.png
new file mode 100644
index 0000000000..53fbef3d67
--- /dev/null
+++ b/demos/gui/translation/flag_uk.png
Binary files differ
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
new file mode 100644
index 0000000000..c3e788f82b
--- /dev/null
+++ b/demos/gui/translation/main.gd
@@ -0,0 +1,32 @@
+
+extends Panel
+
+
+func _goto_scene():
+ var s = load("res://controls.scn")
+ var si = s.instance()
+ get_parent().add_child(si)
+ queue_free()
+
+
+func _on_system_pressed():
+ # Will autodetect based on system, then fall back
+ # to english if not found
+ _goto_scene()
+
+# 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")
+ _goto_scene()
+
+
+func _on_spanish_pressed():
+ TranslationServer.set_locale("es")
+ _goto_scene()
+
+
+func _on_japanese_pressed():
+ TranslationServer.set_locale("ja")
+ _goto_scene()
diff --git a/demos/gui/translation/main.scn b/demos/gui/translation/main.scn
new file mode 100644
index 0000000000..8fc0b4ffb2
--- /dev/null
+++ b/demos/gui/translation/main.scn
Binary files differ
diff --git a/demos/gui/translation/noto.fnt b/demos/gui/translation/noto.fnt
new file mode 100644
index 0000000000..e019615f41
--- /dev/null
+++ b/demos/gui/translation/noto.fnt
Binary files differ
diff --git a/demos/gui/translation/notosans.otf b/demos/gui/translation/notosans.otf
new file mode 100644
index 0000000000..6443f9023e
--- /dev/null
+++ b/demos/gui/translation/notosans.otf
Binary files differ
diff --git a/demos/gui/translation/text.csv b/demos/gui/translation/text.csv
new file mode 100644
index 0000000000..0f4c148b95
--- /dev/null
+++ b/demos/gui/translation/text.csv
@@ -0,0 +1,3 @@
+,en,es,ja
+KEY_HELLO,Hello!,Hola!,こんにちは
+KEY_PUSH,Push Me!,Aprétame!,私をプッシュ \ No newline at end of file
diff --git a/demos/gui/translation/translations/text.en.xl b/demos/gui/translation/translations/text.en.xl
new file mode 100644
index 0000000000..7bcba63e71
--- /dev/null
+++ b/demos/gui/translation/translations/text.en.xl
Binary files differ
diff --git a/demos/gui/translation/translations/text.es.xl b/demos/gui/translation/translations/text.es.xl
new file mode 100644
index 0000000000..4474d955d5
--- /dev/null
+++ b/demos/gui/translation/translations/text.es.xl
Binary files differ
diff --git a/demos/gui/translation/translations/text.ja.xl b/demos/gui/translation/translations/text.ja.xl
new file mode 100644
index 0000000000..b3d1f0bf60
--- /dev/null
+++ b/demos/gui/translation/translations/text.ja.xl
Binary files differ
diff --git a/demos/misc/autoload/global.gd b/demos/misc/autoload/global.gd
index d9fa308a2f..2671b6f412 100644
--- a/demos/misc/autoload/global.gd
+++ b/demos/misc/autoload/global.gd
@@ -1,23 +1,37 @@
extends Node
-
+# Member variables
var current_scene = null
-func goto_scene(scene):
- #load new scene
- var s = ResourceLoader.load(scene)
- #queue erasing old (don't use free because that scene is calling this method)
- current_scene.queue_free()
- #instance the new scene
+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()
+
+ # Load new scene
+ var s = ResourceLoader.load(path)
+
+ # Instance the new scene
current_scene = s.instance()
- #add it to the active scene, as child of root
- get_scene().get_root().add_child(current_scene)
+
+ # Add it to the active scene, as child of root
+ get_tree().get_root().add_child(current_scene)
func _ready():
- # get the current scene
- # it is always the last child of root,
- # after the autoloaded nodes
- var root = get_scene().get_root()
- current_scene = root.get_child( root.get_child_count() -1 )
+ # Get the current scene at the time of initialization
+ current_scene = get_tree().get_current_scene()
diff --git a/demos/misc/autoload/scene_a.gd b/demos/misc/autoload/scene_a.gd
index 21a6a84eb9..f9c39887b0 100644
--- a/demos/misc/autoload/scene_a.gd
+++ b/demos/misc/autoload/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_node("/root/global").goto_scene("res://scene_b.scn")
- pass # replace with function body
+ 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..fdf2287a04 100644
--- a/demos/misc/autoload/scene_b.gd
+++ b/demos/misc/autoload/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_node("/root/global").goto_scene("res://scene_a.scn")
- pass # replace with function body
+ 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/engine.cfg b/demos/misc/joysticks/engine.cfg
new file mode 100644
index 0000000000..71ac91000e
--- /dev/null
+++ b/demos/misc/joysticks/engine.cfg
@@ -0,0 +1,10 @@
+[application]
+
+name="Joysticks"
+main_scene="res://joysticks.scn"
+icon="res://icon.png"
+
+[display]
+
+width=260
+height=300
diff --git a/demos/misc/joysticks/icon.png b/demos/misc/joysticks/icon.png
new file mode 100644
index 0000000000..06b0d7532d
--- /dev/null
+++ b/demos/misc/joysticks/icon.png
Binary files differ
diff --git a/demos/misc/joysticks/joysticks.gd b/demos/misc/joysticks/joysticks.gd
new file mode 100644
index 0000000000..7add88573d
--- /dev/null
+++ b/demos/misc/joysticks/joysticks.gd
@@ -0,0 +1,43 @@
+
+extends Node2D
+
+# Joysticks demo, written by Dana Olson <dana@shineuponthee.com>
+#
+# This is a demo of joystick support, and doubles as a testing application
+# inspired by and similar to jstest-gtk.
+#
+# Licensed under the MIT license
+
+# Member variables
+var joy_num
+var cur_joy
+var axis_value
+var btn_state
+
+
+func _input(event):
+ # 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
+ 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):
+ 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))
+ else:
+ get_node("btn" + str(btn)).add_color_override("font_color", Color(0.2, 0.1, 0.3, 1))
+
+
+func _ready():
+ set_process_input(true)
diff --git a/demos/misc/joysticks/joysticks.scn b/demos/misc/joysticks/joysticks.scn
new file mode 100644
index 0000000000..b78bccbf33
--- /dev/null
+++ b/demos/misc/joysticks/joysticks.scn
Binary files differ
diff --git a/demos/misc/pause/spinpause.gd b/demos/misc/pause/spinpause.gd
index c21c13b4e1..ea5617c06f 100644
--- a/demos/misc/pause/spinpause.gd
+++ b/demos/misc/pause/spinpause.gd
@@ -5,11 +5,9 @@ extends Spatial
func _on_pause_pressed():
get_node("pause_popup").set_exclusive(true)
get_node("pause_popup").popup()
- get_scene().set_pause(true)
+ get_tree().set_pause(true)
func _on_unpause_pressed():
get_node("pause_popup").hide()
- get_scene().set_pause(false)
-
-
+ 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/engine.cfg b/demos/misc/scene_changer/engine.cfg
new file mode 100644
index 0000000000..1ba1a41167
--- /dev/null
+++ b/demos/misc/scene_changer/engine.cfg
@@ -0,0 +1,4 @@
+[application]
+
+name="Scene Changer"
+main_scene="res://scene_a.scn"
diff --git a/demos/misc/scene_changer/scene_a.gd b/demos/misc/scene_changer/scene_a.gd
new file mode 100644
index 0000000000..0e80395e84
--- /dev/null
+++ b/demos/misc/scene_changer/scene_a.gd
@@ -0,0 +1,16 @@
+
+extends Panel
+
+# 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
diff --git a/demos/misc/scene_changer/scene_a.scn b/demos/misc/scene_changer/scene_a.scn
new file mode 100644
index 0000000000..9a4b6434be
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..9ed13cf26b
--- /dev/null
+++ b/demos/misc/scene_changer/scene_b.gd
@@ -0,0 +1,16 @@
+
+extends Panel
+
+# 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
diff --git a/demos/misc/scene_changer/scene_b.scn b/demos/misc/scene_changer/scene_b.scn
new file mode 100644
index 0000000000..4cdb03e90e
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..1d87303015
--- /dev/null
+++ b/demos/misc/tween/engine.cfg
@@ -0,0 +1,11 @@
+[application]
+
+name="Tween Demo"
+main_scene="res://main.scn"
+icon="res://icon.png"
+target_fps=60
+
+[display]
+
+stretch_mode="2d"
+stretch_aspect="keep_width"
diff --git a/demos/misc/tween/icon.png b/demos/misc/tween/icon.png
new file mode 100644
index 0000000000..ed55c24140
--- /dev/null
+++ b/demos/misc/tween/icon.png
Binary files differ
diff --git a/demos/misc/tween/main.gd b/demos/misc/tween/main.gd
new file mode 100644
index 0000000000..512271311e
--- /dev/null
+++ b/demos/misc/tween/main.gd
@@ -0,0 +1,165 @@
+
+extends Control
+
+# 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"]
+
+var state = {
+ trans = Tween.TRANS_LINEAR,
+ eases = Tween.EASE_IN,
+}
+
+
+func _ready():
+ for index in range(trans.size()):
+ var name = trans[index]
+ get_node("trans/" + name).connect("pressed", self, "on_trans_changed", [name, index])
+
+ for index in range(eases.size()):
+ var name = eases[index]
+ get_node("eases/" + name).connect("pressed", self, "on_eases_changed", [name, index])
+
+ for index in range(modes.size()):
+ var name = modes[index]
+ get_node("modes/" + name).connect("pressed", self, "on_modes_changed", [name])
+
+ get_node("color/color_from").set_color(Color(1, 0, 0, 1))
+ get_node("color/color_from").connect("color_changed", self, "on_color_changed")
+
+ get_node("color/color_to").set_color(Color(0, 1, 1, 1))
+ get_node("color/color_to").connect("color_changed", self, "on_color_changed")
+
+ get_node("trans/linear").set_pressed(true)
+ get_node("eases/in").set_pressed(true)
+ get_node("modes/move").set_pressed(true)
+ get_node("modes/repeat").set_pressed(true)
+
+ reset_tween()
+
+
+func on_trans_changed(name, index):
+ for index in range(trans.size()):
+ var pressed = trans[index] == name
+ var btn = get_node("trans/" + trans[index])
+
+ btn.set_pressed(pressed)
+ btn.set_ignore_mouse(pressed)
+
+ state.trans = index
+ reset_tween()
+
+
+func on_eases_changed(name, index):
+ for index in range(eases.size()):
+ var pressed = eases[index] == name
+ var btn = get_node("eases/" + eases[index])
+
+ btn.set_pressed(pressed)
+ btn.set_ignore_mouse(pressed)
+
+ state.eases = index
+ reset_tween()
+
+
+func on_modes_changed(name):
+ var tween = get_node("tween")
+ if name == "pause":
+ if get_node("modes/pause").is_pressed():
+ tween.stop_all()
+ get_node("timeline").set_ignore_mouse(false)
+ else:
+ tween.resume_all()
+ 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()
+ tween.reset_all()
+ tween.remove_all()
+
+ var sprite = get_node("tween/area/sprite")
+ var follow = get_node("tween/area/follow")
+ var follow_2 = get_node("tween/area/follow_2")
+ 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)
+
+ 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))
+
+ 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)
+ else:
+ 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)
+ tween.interpolate_property(sprite, "transform/rot", 360, 0, 2, state.trans, state.eases, 2)
+
+ if get_node("modes/callback").is_pressed():
+ tween.interpolate_callback(self, 0.5, "on_callback", "0.5 second's after")
+ tween.interpolate_callback(self, 0.2, "on_callback", "1.2 second's after")
+
+ if get_node("modes/follow").is_pressed():
+ follow.show()
+ follow_2.show()
+
+ tween.follow_method(follow, "set_pos", Vector2(0, size.height), sprite, "get_pos", 2, state.trans, state.eases)
+ tween.targeting_method(follow, "set_pos", sprite, "get_pos", Vector2(0, size.height), 2, state.trans, state.eases, 2)
+
+ tween.targeting_property(follow_2, "transform/pos", sprite, "transform/pos", Vector2(size.width, 0), 2, state.trans, state.eases)
+ tween.follow_property(follow_2, "transform/pos", Vector2(size.width, 0), sprite, "transform/pos", 2, state.trans, state.eases, 2)
+ else:
+ follow.hide()
+ follow_2.hide()
+
+ tween.set_repeat(get_node("modes/repeat").is_pressed())
+ tween.start()
+ tween.seek(pos)
+
+ if get_node("modes/pause").is_pressed():
+ tween.stop_all()
+ get_node("timeline").set_ignore_mouse(false)
+ get_node("timeline").set_value(0)
+ else:
+ tween.resume_all()
+ get_node("timeline").set_ignore_mouse(true)
+
+
+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)
+
+
+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)
+
+
+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/udp_chat/chat.gd b/demos/misc/udp_chat/chat.gd
new file mode 100644
index 0000000000..b60afa9ded
--- /dev/null
+++ b/demos/misc/udp_chat/chat.gd
@@ -0,0 +1,66 @@
+
+extends Panel
+
+# 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):
+ if (not udp.is_listening()):
+ return
+
+ while(udp.get_available_packet_count() > 0):
+ var packet = udp.get_var()
+ 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").newline()
+
+
+func _ready():
+ 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):
+ if (pressed):
+ 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.")
+ get_node("connect").set_pressed(false)
+ else:
+ 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_button_pressed():
+ var msg = get_node("entry_line").get_text()
+ if (msg == ""):
+ return
+ 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
new file mode 100644
index 0000000000..fe38e9da72
--- /dev/null
+++ b/demos/misc/udp_chat/chat.scn
Binary files differ
diff --git a/demos/misc/udp_chat/engine.cfg b/demos/misc/udp_chat/engine.cfg
new file mode 100644
index 0000000000..584841ea83
--- /dev/null
+++ b/demos/misc/udp_chat/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+name="UDP Chat"
+main_scene="res://chat.scn"
+icon="res://icon.png"
diff --git a/demos/misc/udp_chat/icon.png b/demos/misc/udp_chat/icon.png
new file mode 100644
index 0000000000..db6e21cce1
--- /dev/null
+++ b/demos/misc/udp_chat/icon.png
Binary files differ
diff --git a/demos/misc/window_management/control.gd b/demos/misc/window_management/control.gd
new file mode 100644
index 0000000000..cd8e0e185b
--- /dev/null
+++ b/demos/misc/window_management/control.gd
@@ -0,0 +1,186 @@
+
+extends Control
+
+# Member variables
+var mousepos
+
+
+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"
+
+ if(OS.is_window_minimized()):
+ modetext += "Minimized\n"
+
+ if(OS.is_window_maximized()):
+ modetext += "Maximized\n"
+
+ if(Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED):
+ modetext += "MouseGrab\n"
+ get_node("Label_MouseGrab_KeyInfo").show()
+ else:
+ get_node("Label_MouseGrab_KeyInfo").hide()
+
+ get_node("Label_Mode").set_text(modetext)
+
+ 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_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_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_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)))
+ 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)
+
+
+func check_wm_api():
+ var s = ""
+ if(!OS.has_method("get_screen_count")):
+ s += " - get_screen_count()\n"
+
+ if(!OS.has_method("get_current_screen")):
+ s += " - get_current_screen()\n"
+
+ if(!OS.has_method("set_current_screen")):
+ s += " - set_current_screen()\n"
+
+ if(!OS.has_method("get_screen_position")):
+ s += " - get_screen_position()\n"
+
+ if(!OS.has_method("get_screen_size")):
+ s += " - get_screen_size()\n"
+
+ if(!OS.has_method("get_window_position")):
+ s += " - get_window_position()\n"
+
+ if(!OS.has_method("set_window_position")):
+ s += " - set_window_position()\n"
+
+ if(!OS.has_method("get_window_size")):
+ s += " - get_window_size()\n"
+
+ if(!OS.has_method("set_window_size")):
+ s += " - set_window_size()\n"
+
+ if(!OS.has_method("set_window_fullscreen")):
+ s += " - set_window_fullscreen()\n"
+
+ if(!OS.has_method("is_window_fullscreen")):
+ s += " - is_window_fullscreen()\n"
+
+ if(!OS.has_method("set_window_resizable")):
+ s += " - set_window_resizable()\n"
+
+ if(!OS.has_method("is_window_resizable")):
+ s += " - is_window_resizable()\n"
+
+ if(!OS.has_method("set_window_minimized")):
+ s += " - set_window_minimized()\n"
+
+ if(!OS.has_method("is_window_minimized")):
+ s += " - is_window_minimized()\n"
+
+ if(!OS.has_method("set_window_maximized")):
+ s += " - set_window_maximized()\n"
+
+ if(!OS.has_method("is_window_maximized")):
+ s += " - is_window_maximized()\n"
+
+ 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").show()
+ return false
+
+
+func _ready():
+ if(check_wm_api()):
+ set_fixed_process(true)
+ set_process_input(true)
+
+
+func _input(event):
+ if (event.type == InputEvent.MOUSE_MOTION):
+ mousepos = event.pos
+
+
+func _on_Button_MoveTo_pressed():
+ OS.set_window_position(Vector2(100, 100))
+
+
+func _on_Button_Resize_pressed():
+ OS.set_window_size(Vector2(1024, 768))
+
+
+func _on_Button_Screen0_pressed():
+ OS.set_current_screen(0)
+
+
+func _on_Button_Screen1_pressed():
+ OS.set_current_screen(1)
+
+
+func _on_Button_Fullscreen_pressed():
+ if(OS.is_window_fullscreen()):
+ OS.set_window_fullscreen(false)
+ else:
+ OS.set_window_fullscreen(true)
+
+
+func _on_Button_FixedSize_pressed():
+ if(OS.is_window_resizable()):
+ OS.set_window_resizable(false)
+ else:
+ OS.set_window_resizable(true)
+
+
+func _on_Button_Minimized_pressed():
+ if(OS.is_window_minimized()):
+ OS.set_window_minimized(false)
+ else:
+ OS.set_window_minimized(true)
+
+
+func _on_Button_Maximized_pressed():
+ if(OS.is_window_maximized()):
+ OS.set_window_maximized(false)
+ else:
+ OS.set_window_maximized(true)
+
+
+func _on_Button_Mouse_Grab_pressed():
+ var observer = get_node("../Observer")
+ observer.state = observer.STATE_GRAB
diff --git a/demos/misc/window_management/engine.cfg b/demos/misc/window_management/engine.cfg
new file mode 100644
index 0000000000..911d3fd4a1
--- /dev/null
+++ b/demos/misc/window_management/engine.cfg
@@ -0,0 +1,19 @@
+[application]
+
+name="Window Management"
+main_scene="res://window_management.scn"
+icon="res://icon.png"
+
+[display]
+
+fullscreen=false
+resizable=true
+width=800
+height=600
+
+[input]
+
+move_forward=[key(W)]
+move_backwards=[key(S)]
+move_left=[key(A)]
+move_right=[key(D)]
diff --git a/demos/misc/window_management/icon.png b/demos/misc/window_management/icon.png
new file mode 100644
index 0000000000..ec5c7891f9
--- /dev/null
+++ b/demos/misc/window_management/icon.png
Binary files differ
diff --git a/demos/misc/window_management/observer/observer.gd b/demos/misc/window_management/observer/observer.gd
new file mode 100644
index 0000000000..f100811859
--- /dev/null
+++ b/demos/misc/window_management/observer/observer.gd
@@ -0,0 +1,78 @@
+
+extends Spatial
+
+# Member variables
+var r_pos = Vector2()
+var state
+
+const STATE_MENU = 0
+const STATE_GRAB = 1
+
+
+func direction(vector):
+ var v = get_node("Camera").get_global_transform().basis*vector
+ v = v.normalized()
+ return v
+
+
+func impulse(event, action):
+ if(event.is_action(action) && event.is_pressed() && !event.is_echo()):
+ return true
+ else:
+ return false
+
+
+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 cam = get_global_transform()
+ var org = get_translation()
+
+ if (Input.is_action_pressed("move_forward")):
+ dir += direction(Vector3(0, 0, -1))
+ if (Input.is_action_pressed("move_backwards")):
+ dir += direction(Vector3(0, 0, 1))
+ if (Input.is_action_pressed("move_left")):
+ dir += direction(Vector3(-1, 0, 0))
+ if (Input.is_action_pressed("move_right")):
+ dir += direction(Vector3(1, 0, 0))
+
+ dir = dir.normalized()
+
+ move(dir*10*delta)
+ var d = delta*0.1
+
+ 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)
+ cam.set_transform(pitch)
+
+ r_pos.x = 0.0
+ r_pos.y = 0.0
+
+
+func _input(event):
+ if(event.type == InputEvent.MOUSE_MOTION):
+ r_pos = event.relative_pos
+
+ if(impulse(event, "ui_cancel")):
+ if(state == STATE_GRAB):
+ Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
+ state = STATE_MENU
+ else:
+ Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
+ state = STATE_GRAB
+
+
+func _ready():
+ set_fixed_process(true)
+ 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
new file mode 100644
index 0000000000..813d7d4587
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..35662871f1
--- /dev/null
+++ 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 5309db9acb..b93c17521d 100644
--- a/demos/viewport/gui_in_3d/gui_3d.gd
+++ b/demos/viewport/gui_in_3d/gui_3d.gd
@@ -1,44 +1,37 @@
extends Spatial
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-var prev_pos=null
-
-func _input(ev):
- if (ev.type in [InputEvent.MOUSE_BUTTON,InputEvent.MOUSE_MOTION]):
- var pos = ev.pos
- var rfrom = get_node("camera").project_ray_origin(pos)
- var rnorm = get_node("camera").project_ray_normal(pos)
-
- #simple collision test against aligned plane
- #for game UIs of this kind consider more complex collision against plane
- var p = Plane(Vector3(0,0,1),0).intersects_ray(rfrom,rnorm)
- if (p==null):
- return
-
- pos.x=(p.x+1.5)*100
- pos.y=(-p.y+0.75)*100
- 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)
-func _ready():
- # Initalization here
- get_node("quad").get_material_override().set_texture(FixedMaterial.PARAM_DIFFUSE, get_node("viewport").get_render_target_texture() )
- set_process_input(true)
-
- pass
+# 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():
+ get_node("area/quad").get_material_override().set_texture(FixedMaterial.PARAM_DIFFUSE, get_node("viewport").get_render_target_texture())
+ set_process_input(true)
diff --git a/demos/viewport/gui_in_3d/gui_3d.scn b/demos/viewport/gui_in_3d/gui_3d.scn
index df8f7d6dc5..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
new file mode 100644
index 0000000000..a843242720
--- /dev/null
+++ b/demos/viewport/screen_capture/engine.cfg
@@ -0,0 +1,9 @@
+[application]
+
+name="Screen Capturing"
+main_scene="res://screen_capture.scn"
+icon="res://icon.png"
+
+[display]
+
+stretch_mode="2d"
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/mountains.png b/demos/viewport/screen_capture/mountains.png
new file mode 100644
index 0000000000..b8435bb1a8
--- /dev/null
+++ b/demos/viewport/screen_capture/mountains.png
Binary files differ
diff --git a/demos/viewport/screen_capture/screen_capture.gd b/demos/viewport/screen_capture/screen_capture.gd
new file mode 100644
index 0000000000..9867d95452
--- /dev/null
+++ b/demos/viewport/screen_capture/screen_capture.gd
@@ -0,0 +1,16 @@
+
+extends Control
+
+
+func _on_button_pressed():
+ get_viewport().queue_screen_capture()
+ # 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
+ var tex = ImageTexture.new()
+ tex.create_from_image(img)
+ # Set it to the capture node
+ get_node("capture").set_texture(tex)
diff --git a/demos/viewport/screen_capture/screen_capture.scn b/demos/viewport/screen_capture/screen_capture.scn
new file mode 100644
index 0000000000..ee847fbe62
--- /dev/null
+++ b/demos/viewport/screen_capture/screen_capture.scn
Binary files differ
diff --git a/doc/base/classes.xml b/doc/base/classes.xml
index e5330925a9..39b3791e84 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,394 +8,399 @@
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" >
- <return type="real">
+ <method name="sin">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Standard sine function.
</description>
</method>
- <method name="cos" >
- <return type="real">
+ <method name="cos">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Standard cosine function.
</description>
</method>
- <method name="tan" >
- <return type="real">
+ <method name="tan">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Standard tangent function.
</description>
</method>
- <method name="sinh" >
- <return type="real">
+ <method name="sinh">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Hyperbolic sine.
</description>
</method>
- <method name="cosh" >
- <return type="real">
+ <method name="cosh">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Hyperbolic cosine.
</description>
</method>
- <method name="tanh" >
- <return type="real">
+ <method name="tanh">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Hyperbolic tangent.
</description>
</method>
- <method name="asin" >
- <return type="real">
+ <method name="asin">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Arc-sine.
</description>
</method>
- <method name="acos" >
- <return type="real">
+ <method name="acos">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Arc-cosine.
</description>
</method>
- <method name="atan" >
- <return type="real">
+ <method name="atan">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Arc-tangent.
</description>
</method>
- <method name="atan2" >
- <return type="real">
+ <method name="atan2">
+ <return type="float">
</return>
- <argument index="0" name="x" type="real">
+ <argument index="0" name="x" type="float">
</argument>
- <argument index="1" name="y" type="real">
+ <argument index="1" name="y" type="float">
</argument>
<description>
Arc-tangent that takes a 2D vector as argument, retuns the full -pi to +pi range.
</description>
</method>
- <method name="sqrt" >
- <return type="real">
+ <method name="sqrt">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Square root.
</description>
</method>
- <method name="fmod" >
- <return type="real">
+ <method name="fmod">
+ <return type="float">
</return>
- <argument index="0" name="x" type="real">
+ <argument index="0" name="x" type="float">
</argument>
- <argument index="1" name="y" type="real">
+ <argument index="1" name="y" type="float">
</argument>
<description>
Module (remainder of x/y).
</description>
</method>
- <method name="fposmod" >
- <return type="real">
+ <method name="fposmod">
+ <return type="float">
</return>
- <argument index="0" name="x" type="real">
+ <argument index="0" name="x" type="float">
</argument>
- <argument index="1" name="y" type="real">
+ <argument index="1" name="y" type="float">
</argument>
<description>
Module (remainder of x/y) that wraps equally in positive and negative.
</description>
</method>
- <method name="floor" >
- <return type="real">
+ <method name="floor">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Floor (rounds down to nearest integer).
</description>
</method>
- <method name="ceil" >
- <return type="real">
+ <method name="ceil">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Ceiling (rounds up to nearest integer).
</description>
</method>
- <method name="round" >
- <return type="real">
+ <method name="round">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Round to nearest integer.
</description>
</method>
- <method name="abs" >
- <return type="real">
+ <method name="abs">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <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" >
- <return type="real">
+ <method name="sign">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Return sign (-1 or +1).
</description>
</method>
- <method name="pow" >
- <return type="real">
+ <method name="pow">
+ <return type="float">
</return>
- <argument index="0" name="x" type="real">
+ <argument index="0" name="x" type="float">
</argument>
- <argument index="1" name="y" type="real">
+ <argument index="1" name="y" type="float">
</argument>
<description>
Power function, x elevate to y.
</description>
</method>
- <method name="log" >
- <return type="real">
+ <method name="log">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Natural logarithm.
</description>
</method>
- <method name="exp" >
- <return type="real">
+ <method name="exp">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Exponential logarithm.
</description>
</method>
- <method name="isnan" >
- <return type="real">
+ <method name="isnan">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Return true if the float is not a number.
</description>
</method>
- <method name="isinf" >
- <return type="real">
+ <method name="isinf">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
<description>
Return true if the float is infinite.
</description>
</method>
- <method name="ease" >
- <return type="real">
+ <method name="ease">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
- <argument index="1" name="curve" type="real">
+ <argument index="1" name="curve" type="float">
</argument>
<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.
</description>
</method>
- <method name="decimals" >
- <return type="real">
+ <method name="decimals">
+ <return type="float">
</return>
- <argument index="0" name="step" type="real">
+ <argument index="0" name="step" type="float">
</argument>
<description>
Return the amount of decimals in the floating point value.
</description>
</method>
- <method name="stepify" >
- <return type="real">
+ <method name="stepify">
+ <return type="float">
</return>
- <argument index="0" name="s" type="real">
+ <argument index="0" name="s" type="float">
</argument>
- <argument index="1" name="step" type="real">
+ <argument index="1" name="step" type="float">
</argument>
<description>
Snap float value to a given step.
</description>
</method>
- <method name="lerp" >
- <return type="real">
+ <method name="lerp">
+ <return type="float">
</return>
- <argument index="0" name="a" type="real">
+ <argument index="0" name="from" type="float">
</argument>
- <argument index="1" name="b" type="real">
+ <argument index="1" name="to" type="float">
</argument>
- <argument index="2" name="c" type="real">
+ <argument index="2" name="weight" type="float">
</argument>
<description>
+ Linear interpolates between two values by a normalized value.
</description>
</method>
- <method name="dectime" >
- <return type="real">
+ <method name="dectime">
+ <return type="float">
</return>
- <argument index="0" name="value" type="real">
+ <argument index="0" name="value" type="float">
</argument>
- <argument index="1" name="amount" type="real">
+ <argument index="1" name="amount" type="float">
</argument>
- <argument index="2" name="step" type="real">
+ <argument index="2" name="step" type="float">
</argument>
<description>
+ 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" >
- <return type="real">
+ <method name="randf">
+ <return type="float">
</return>
<description>
Random value (0 to 1 float).
</description>
</method>
- <method name="rand_range" >
- <return type="real">
+ <method name="rand_range">
+ <return type="float">
</return>
- <argument index="0" name="from" type="real">
+ <argument index="0" name="from" type="float">
</argument>
- <argument index="1" name="to" type="real">
+ <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="real">
+ <argument index="0" name="seed" type="float">
</argument>
<description>
Random from seed, pass a seed and an array with both number and new seed is returned.
</description>
</method>
- <method name="deg2rad" >
- <return type="real">
+ <method name="deg2rad">
+ <return type="float">
</return>
- <argument index="0" name="deg" type="real">
+ <argument index="0" name="deg" type="float">
</argument>
<description>
Convert from degrees to radians.
</description>
</method>
- <method name="rad2deg" >
- <return type="real">
+ <method name="rad2deg">
+ <return type="float">
</return>
- <argument index="0" name="rad" type="real">
+ <argument index="0" name="rad" type="float">
</argument>
<description>
Convert from radias to degrees.
</description>
</method>
- <method name="linear2db" >
- <return type="real">
+ <method name="linear2db">
+ <return type="float">
</return>
- <argument index="0" name="nrg" type="real">
+ <argument index="0" name="nrg" type="float">
</argument>
<description>
Convert from linear energy to decibels (audio).
</description>
</method>
- <method name="db2linear" >
- <return type="real">
+ <method name="db2linear">
+ <return type="float">
</return>
- <argument index="0" name="db" type="real">
+ <argument index="0" name="db" type="float">
</argument>
<description>
Convert from decibels to linear energy (audio).
</description>
</method>
- <method name="max" >
- <return type="real">
+ <method name="max">
+ <return type="float">
</return>
- <argument index="0" name="a" type="real">
+ <argument index="0" name="a" type="float">
</argument>
- <argument index="1" name="b" type="real">
+ <argument index="1" name="b" type="float">
</argument>
<description>
Return the maximum of two values.
</description>
</method>
- <method name="min" >
- <return type="real">
+ <method name="min">
+ <return type="float">
</return>
- <argument index="0" name="a" type="real">
+ <argument index="0" name="a" type="float">
</argument>
- <argument index="1" name="b" type="real">
+ <argument index="1" name="b" type="float">
</argument>
<description>
Return the minimum of two values.
</description>
</method>
- <method name="clamp" >
- <return type="real">
+ <method name="clamp">
+ <return type="float">
</return>
- <argument index="0" name="val" type="real">
+ <argument index="0" name="val" type="float">
</argument>
- <argument index="1" name="min" type="real">
+ <argument index="1" name="min" type="float">
</argument>
- <argument index="2" name="max" type="real">
+ <argument index="2" name="max" type="float">
</argument>
<description>
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">
@@ -404,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>
@@ -413,17 +418,18 @@
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>
<argument index="1" name="funcname" type="String">
</argument>
<description>
+ 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">
@@ -434,7 +440,7 @@
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">
@@ -445,7 +451,7 @@
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">
@@ -456,7 +462,7 @@
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">
@@ -467,7 +473,18 @@
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>
+ <argument index="1" name="..." type="var">
+ </argument>
+ <description>
+ Print one or more arguments to the console with a tab between each argument.
+ </description>
+ </method>
+ <method name="prints">
<return type="Nil">
</return>
<argument index="0" name="what" type="var">
@@ -477,7 +494,7 @@
<description>
</description>
</method>
- <method name="printerr" >
+ <method name="printerr">
<return type="Nil">
</return>
<argument index="0" name="what" type="var">
@@ -488,7 +505,7 @@
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">
@@ -499,7 +516,25 @@
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="range" >
+ <method name="var2str">
+ <return type="String">
+ </return>
+ <argument index="0" name="var" type="var">
+ </argument>
+ <description>
+ Converts the value of a variable to a String.
+ </description>
+ </method>
+ <method name="str2var:var">
+ <return type="Nil">
+ </return>
+ <argument index="0" name="string" type="String">
+ </argument>
+ <description>
+ Converts the value of a String to a variable.
+ </description>
+ </method>
+ <method name="range">
<return type="Array">
</return>
<argument index="0" name="..." type="var">
@@ -508,49 +543,61 @@
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">
+ <return type="int">
+ </return>
+ <argument index="0" name="var:var" type="var">
+ </argument>
+ <description>
+ Hashes the variable passed and returns an integer.
</description>
</method>
- <method name="print_stack" >
+ <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>
@@ -560,7 +607,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>
@@ -568,79 +615,52 @@
<member name="Performance" type="Performance">
</member>
<member name="Globals" type="Globals">
- The file engine.cfg is read into this singleton.
</member>
<member name="IP" type="IP">
- Global IP protocol functions (like hostname resolution).
</member>
<member name="Geometry" type="Geometry">
- Geometry helpers.
</member>
<member name="ResourceLoader" type="ResourceLoader">
- Singleton that loads resources (load() calls this)
</member>
<member name="ResourceSaver" type="ResourceSaver">
- Singleton that saves resources.
</member>
<member name="PathRemap" type="PathRemap">
- Uset to setup remaps for the filesystem.
</member>
<member name="OS" type="OS">
- Operating system functions.
</member>
<member name="Marshalls" type="Reference">
- Used to serialize and deserialize, helpers.
</member>
<member name="TranslationServer" type="TranslationServer">
- Server that takes care of translating between different
- languages.
</member>
<member name="TS" type="TranslationServer">
- Short version for TranslationServer.
</member>
<member name="Input" type="Input">
- Global input variables and functions.
</member>
- <member name="SceneIO" type="SceneIO">
- Deprecaed.
+ <member name="InputMap" type="InputMap">
</member>
<member name="VisualServer" type="VisualServer">
- Server that handles anything visual at low level.
</member>
<member name="VS" type="VisualServer">
- Short for VisualServer.
</member>
<member name="AudioServer" type="AudioServer">
- Server that handles anything audio at low level.
</member>
<member name="AS" type="AudioServer">
- Short for AudioServer.
</member>
<member name="PhysicsServer" type="PhysicsServer">
- Server that handles anything 3D physics at low level.
</member>
<member name="PS" type="PhysicsServer">
- Short for PhysicsServer.
</member>
<member name="Physics2DServer" type="Physics2DServer">
- Server that handles anything 2D physics at low level.
</member>
<member name="PS2D" type="Physics2DServer">
- Short for Physics2DServer.
</member>
<member name="SpatialSoundServer" type="SpatialSound2DServer">
- Server that handles spatial audio positioning in 3D at low
- level.
</member>
<member name="SS" type="SpatialSound2DServer">
- Short for SpatialSoundServer.
</member>
<member name="SpatialSound2DServer" type="SpatialSound2DServer">
- Server that handles spatial audio positioning in 2D at low
- level.
</member>
<member name="SS2D" type="SpatialSound2DServer">
- Short for SpatialSound2DServer.
</member>
</members>
<constants>
@@ -1184,6 +1204,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,7 +1375,7 @@
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>
@@ -1385,78 +1407,99 @@
</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_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_KEY_ACCEL" value="7">
+ </constant>
+ <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_FILE" value="9">
+ <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="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_RESOURCE_TYPE" value="13">
+ <constant name="PROPERTY_HINT_GLOBAL_FILE" value="12">
+ </constant>
+ <constant name="PROPERTY_HINT_GLOBAL_DIR" value="13">
+ </constant>
+ <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="15">
+ </constant>
+ <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="16">
+ </constant>
+ <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="17">
+ </constant>
+ <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="18">
+ </constant>
<constant name="PROPERTY_USAGE_STORAGE" value="1">
Property will be used as storage (default).
</constant>
@@ -1560,39 +1603,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" >
- <return type="real">
+ <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">
@@ -1601,87 +1640,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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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="real">
+ <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">
@@ -1690,17 +1723,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">
@@ -1709,26 +1741,37 @@
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">
+ <return type="bool">
+ </return>
+ <argument index="0" name="from" type="Vector3">
+ </argument>
+ <argument index="1" name="to" type="Vector3">
+ </argument>
+ <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">
@@ -1744,7 +1787,6 @@
<member name="size" type="Vector3">
</member>
<member name="end" type="Vector3">
- Same as pos+size.
</member>
</members>
<constants>
@@ -1755,49 +1797,50 @@
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" default="&quot;&quot;">
+ <argument index="0" name="text" type="String">
+ </argument>
+ <argument index="1" name="right" type="bool" default="false">
+ </argument>
+ <argument index="2" name="action" type="String" default="&quot;&quot;">
</argument>
<description>
</description>
</method>
- <method name="add_cancel" >
+ <method name="add_cancel">
<return type="Button">
</return>
<argument index="0" name="name" type="String">
@@ -1805,22 +1848,21 @@
<description>
</description>
</method>
- <method name="register_text_enter" >
+ <method name="register_text_enter">
<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>
@@ -1853,104 +1895,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>
@@ -1958,6 +1994,52 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
+<class name="AnimatedSprite3D" inherits="SpriteBase3D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_sprite_frames">
+ <argument index="0" name="sprite_frames" type="SpriteFrames">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_sprite_frames" qualifiers="const">
+ <return type="Texture">
+ </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>
+ </methods>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
@@ -1969,7 +2051,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">
@@ -1980,21 +2062,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">
@@ -2003,7 +2085,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">
@@ -2012,16 +2094,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">
@@ -2029,26 +2111,26 @@
<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">
</argument>
- <argument index="1" name="time" type="real">
+ <argument index="1" name="time" type="float">
</argument>
<argument index="2" name="loc" type="Vector3">
</argument>
@@ -2060,20 +2142,20 @@
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="real">
+ <argument index="1" name="time" type="float">
</argument>
<argument index="2" name="key" type="var">
</argument>
- <argument index="3" name="transition" type="real" default="1">
+ <argument index="3" name="transition" type="float" default="1">
</argument>
<description>
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">
@@ -2082,16 +2164,16 @@
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="real">
+ <argument index="1" name="pos" type="float">
</argument>
<description>
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">
@@ -2102,31 +2184,29 @@
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">
</argument>
- <argument index="2" name="transition" type="real">
+ <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" >
- <return type="real">
+ <method name="track_get_key_transition" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="idx" type="int">
</argument>
<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">
@@ -2135,7 +2215,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">
@@ -2144,8 +2224,8 @@
Return the value of a given key in a given track.
</description>
</method>
- <method name="track_get_key_time" qualifiers="const" >
- <return type="real">
+ <method name="track_get_key_time" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="idx" type="int">
</argument>
@@ -2155,12 +2235,12 @@
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">
</argument>
- <argument index="1" name="time" type="real">
+ <argument index="1" name="time" type="float">
</argument>
<argument index="2" name="exact" type="bool" default="false">
</argument>
@@ -2168,7 +2248,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">
@@ -2177,7 +2257,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">
@@ -2186,18 +2266,18 @@
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">
</argument>
- <argument index="1" name="time_sec" type="real">
+ <argument index="1" name="time_sec" type="float">
</argument>
<description>
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">
@@ -2206,7 +2286,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">
@@ -2215,33 +2295,33 @@
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">
</argument>
- <argument index="1" name="time_sec" type="real">
+ <argument index="1" name="time_sec" type="float">
</argument>
- <argument index="2" name="delta" type="real">
+ <argument index="2" name="delta" type="float">
</argument>
<description>
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">
</argument>
- <argument index="1" name="time_sec" type="real">
+ <argument index="1" name="time_sec" type="float">
</argument>
- <argument index="2" name="delta" type="real">
+ <argument index="2" name="delta" type="float">
</argument>
<description>
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">
@@ -2252,7 +2332,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">
@@ -2263,47 +2343,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" >
- <argument index="0" name="time_sec" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="size_sec" type="real">
+ <method name="set_step">
+ <argument index="0" name="size_sec" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_step" qualifiers="const" >
- <return type="real">
+ <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>
@@ -2338,7 +2418,7 @@
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">
@@ -2346,17 +2426,17 @@
<argument index="1" name="animation" type="Animation">
</argument>
<description>
- Add an animation resource to the player, which will be later referenced by the "name" arguemnt.
+ 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">
@@ -2365,7 +2445,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">
@@ -2374,7 +2454,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">
@@ -2383,26 +2463,26 @@
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">
</argument>
- <argument index="2" name="sec" type="real">
+ <argument index="2" name="sec" type="float">
</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">
+ <method name="get_blend_time" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="anim_from" type="String">
</argument>
@@ -2412,80 +2492,86 @@
Get the blend time between two animations, referemced by their names.
</description>
</method>
- <method name="set_default_blend_time" >
- <argument index="0" name="sec" type="real">
+ <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" >
- <return type="real">
+ <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="real" default="-1">
+ <argument index="1" name="custom_blend" type="float" default="-1">
</argument>
- <argument index="2" name="custom_speed" type="real" default="1">
+ <argument index="2" name="custom_speed" type="float" default="1">
</argument>
<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="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" >
+ <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>
@@ -2493,77 +2579,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" >
- <argument index="0" name="speed" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="pos_sec" type="real">
+ <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" >
- <return type="real">
+ <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">
@@ -2572,39 +2653,43 @@
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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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">
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <description>
</description>
</method>
</methods>
@@ -2615,8 +2700,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">
@@ -2627,11 +2711,10 @@
</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.
+ Process animation on idle process.
</constant>
</constants>
</class>
@@ -2640,23 +2723,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">
@@ -2665,7 +2744,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">
@@ -2676,7 +2755,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">
@@ -2685,17 +2764,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_sourcre" qualifiers="const" >
+ <method name="node_get_input_source" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="id" type="String">
@@ -2706,7 +2784,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">
@@ -2715,7 +2793,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">
@@ -2723,7 +2801,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">
@@ -2731,7 +2809,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">
@@ -2739,39 +2817,39 @@
<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="real">
+ <argument index="1" name="time_sec" type="float">
</argument>
<description>
</description>
</method>
- <method name="oneshot_node_get_fadein_time" qualifiers="const" >
- <return type="real">
+ <method name="oneshot_node_get_fadein_time" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<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="real">
+ <argument index="1" name="time_sec" type="float">
</argument>
<description>
</description>
</method>
- <method name="oneshot_node_get_fadeout_time" qualifiers="const" >
- <return type="real">
+ <method name="oneshot_node_get_fadeout_time" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<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">
@@ -2779,23 +2857,23 @@
<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="real">
+ <argument index="1" name="delay_sec" type="float">
</argument>
<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="real">
+ <argument index="1" name="rand_sec" type="float">
</argument>
<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">
@@ -2803,35 +2881,35 @@
<description>
</description>
</method>
- <method name="oneshot_node_get_autorestart_delay" qualifiers="const" >
- <return type="real">
+ <method name="oneshot_node_get_autorestart_delay" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<description>
</description>
</method>
- <method name="oneshot_node_get_autorestart_random_delay" qualifiers="const" >
- <return type="real">
+ <method name="oneshot_node_get_autorestart_random_delay" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<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">
@@ -2839,7 +2917,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">
@@ -2849,39 +2927,39 @@
<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="real">
+ <argument index="1" name="ratio" type="float">
</argument>
<description>
</description>
</method>
- <method name="mix_node_get_amount" qualifiers="const" >
- <return type="real">
+ <method name="mix_node_get_amount" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<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="real">
+ <argument index="1" name="blend" type="float">
</argument>
<description>
</description>
</method>
- <method name="blend2_node_get_amount" qualifiers="const" >
- <return type="real">
+ <method name="blend2_node_get_amount" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<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">
@@ -2891,23 +2969,23 @@
<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="real">
+ <argument index="1" name="blend" type="float">
</argument>
<description>
</description>
</method>
- <method name="blend3_node_get_amount" qualifiers="const" >
- <return type="real">
+ <method name="blend3_node_get_amount" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<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">
@@ -2915,7 +2993,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">
@@ -2923,31 +3001,31 @@
<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="real">
+ <argument index="1" name="scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="timescale_node_get_scale" qualifiers="const" >
- <return type="real">
+ <method name="timescale_node_get_scale" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<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="real">
+ <argument index="1" name="pos_sec" type="float">
</argument>
<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">
@@ -2955,7 +3033,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">
@@ -2963,7 +3041,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">
@@ -2971,7 +3049,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">
@@ -2981,7 +3059,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">
@@ -2991,23 +3069,23 @@
<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="real">
+ <argument index="1" name="time_sec" type="float">
</argument>
<description>
</description>
</method>
- <method name="transition_node_get_xfade_time" qualifiers="const" >
- <return type="real">
+ <method name="transition_node_get_xfade_time" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="id" type="String">
</argument>
<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">
@@ -3015,7 +3093,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">
@@ -3023,7 +3101,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">
@@ -3031,7 +3109,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">
@@ -3039,13 +3117,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">
@@ -3057,7 +3135,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">
@@ -3069,7 +3147,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">
@@ -3077,41 +3155,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>
@@ -3145,90 +3253,154 @@
<description>
</description>
<methods>
- <method name="set_space_override_mode" >
+ <method name="set_space_override_mode">
<argument index="0" name="enable" type="int">
</argument>
<description>
</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" >
- <argument index="0" name="gravity" type="real">
+ <method name="set_gravity">
+ <argument index="0" name="gravity" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_gravity" 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_linear_damp">
+ <argument index="0" name="linear_damp" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_gravity" qualifiers="const" >
- <return type="real">
+ <method name="get_linear_damp" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_density" >
- <argument index="0" name="density" type="real">
+ <method name="set_priority">
+ <argument index="0" name="priority" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_density" qualifiers="const" >
- <return type="real">
+ <method name="get_priority" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_priority" >
- <argument index="0" name="priority" type="real">
+ <method name="set_monitorable">
+ <argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_priority" qualifiers="const" >
- <return type="real">
+ <method name="is_monitorable" qualifiers="const">
+ <return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_enable_monitoring" >
+ <method name="set_enable_monitoring">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_monitoring_enabled" qualifiers="const" >
+ <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">
@@ -3249,6 +3421,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>
@@ -3267,6 +3457,24 @@
<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>
@@ -3279,93 +3487,213 @@
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.
</description>
<methods>
- <method name="set_space_override_mode" >
+ <method name="set_space_override_mode">
<argument index="0" name="enable" type="int">
</argument>
<description>
</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>
When overriding space parameters, areas can have a center of gravity as a point.
</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.
</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="Vector2">
</argument>
<description>
- Set gravity vector. If gravity is a point, this will be the attraction center
+ Set gravity vector. If gravity is 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>
</description>
</method>
- <method name="set_gravity" >
- <argument index="0" name="gravity" type="real">
+ <method name="set_gravity">
+ <argument index="0" name="gravity" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_gravity" 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_priority">
+ <argument index="0" name="priority" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_priority" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_collision_mask">
+ <argument index="0" name="collision_mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_layer_mask">
+ <argument index="0" name="layer_mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_gravity" qualifiers="const" >
- <return type="real">
+ <method name="get_layer_mask" qualifiers="const">
+ <return type="int">
</return>
<description>
</description>
</method>
- <method name="set_density" >
- <argument index="0" name="density" type="real">
+ <method name="set_collision_mask_bit">
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_density" qualifiers="const" >
- <return type="real">
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
</return>
+ <argument index="0" name="bit" type="int">
+ </argument>
<description>
</description>
</method>
- <method name="set_priority" >
- <argument index="0" name="priority" type="real">
+ <method name="set_layer_mask_bit">
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_priority" qualifiers="const" >
- <return type="real">
+ <method name="get_layer_mask_bit" qualifiers="const">
+ <return type="bool">
</return>
+ <argument index="0" name="bit" type="int">
+ </argument>
<description>
</description>
</method>
- <method name="set_enable_monitoring" >
+ <method name="set_enable_monitoring">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_monitoring_enabled" qualifiers="const" >
+ <method name="is_monitoring_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
+ <method name="set_monitorable">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_monitorable" 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="PhysicsBody2D">
+ </return>
+ <argument index="0" name="body" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="overlaps_area" qualifiers="const">
+ <return type="Area2D">
+ </return>
+ <argument index="0" name="area" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="body_enter">
@@ -3386,6 +3714,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>
@@ -3404,6 +3750,24 @@
<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>
@@ -3416,46 +3780,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">
@@ -3464,93 +3831,117 @@
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="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="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>
@@ -3567,37 +3958,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>
@@ -3612,10 +4003,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">
@@ -3625,19 +4016,19 @@
<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">
@@ -3645,19 +4036,19 @@
<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">
@@ -3666,43 +4057,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>
<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">
@@ -3711,7 +4102,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">
@@ -3720,153 +4111,153 @@
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="real">
+ <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="real">
+ <argument index="1" name="pan" type="float">
</argument>
- <argument index="2" name="depth" type="real" default="0">
+ <argument index="2" name="depth" type="float" default="0">
</argument>
- <argument index="3" name="height" type="real" default="0">
+ <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">
</argument>
- <argument index="2" name="cutoff" type="real">
+ <argument index="2" name="cutoff" type="float">
</argument>
- <argument index="3" name="resonance" type="real">
+ <argument index="3" name="resonance" type="float">
</argument>
- <argument index="4" name="gain" type="real" default="0">
+ <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="real">
+ <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">
</argument>
- <argument index="2" name="reverb" type="real">
+ <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" >
- <return type="real">
+ <method name="voice_get_volume" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="voice" type="RID">
</argument>
@@ -3874,88 +4265,88 @@
Return the current volume for a given voice.
</description>
</method>
- <method name="voice_get_pan" qualifiers="const" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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">
@@ -3964,63 +4355,63 @@
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" >
- <argument index="0" name="scale" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="scale" type="real">
+ <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" >
- <return type="real">
+ <method name="get_fx_global_volume_scale" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_event_voice_global_volume_scale" >
- <argument index="0" name="scale" type="real">
+ <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" >
- <return type="real">
+ <method name="get_event_voice_global_volume_scale" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -4046,7 +4437,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.
@@ -4058,7 +4449,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).
@@ -4092,241 +4483,547 @@
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>
- <method name="play" >
+ </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>
+ </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">
+ <method name="get_loop_count" qualifiers="const">
+ <return type="int">
</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" >
- <return type="int">
+ <method name="seek_pos">
+ <argument index="0" name="pos" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_pos" qualifiers="const">
+ <return type="float">
</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" >
- <argument index="0" name="pos" type="real">
- </argument>
+ <method name="get_length" qualifiers="const">
+ <return type="float">
+ </return>
<description>
- Seek to a certain position (in seconds) in an audio"#10;"#9;"#9;"#9;stream.
</description>
</method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
+ <method name="get_channels" qualifiers="const">
+ <return type="int">
</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" >
- <return type="real">
+ <method name="get_mix_rate" qualifiers="const">
+ <return type="int">
</return>
<description>
</description>
</method>
- <method name="get_update_mode" qualifiers="const" >
+ <method name="get_minimum_buffer_size" 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" >
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="AudioStreamSpeex" inherits="AudioStream" 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>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="BackBufferCopy" inherits="Node2D" 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="set_copy_mode">
+ <argument index="0" name="copy_mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_copy_mode" 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 name="COPY_MODE_DISABLED" value="0">
</constant>
- <constant name="UPDATE_IDLE" value="1">
- Stream is updated on the main thread, when idle.
+ <constant name="COPY_MODE_RECT" value="1">
</constant>
- <constant name="UPDATE_THREAD" value="2">
- Stream is updated on its own thread.
+ <constant name="COPY_MODE_VIEWPORT" value="2">
</constant>
</constants>
</class>
-<class name="AudioStreamGibberish" inherits="AudioStream" category="Core">
+<class name="BakedLight" inherits="Resource" category="Core">
<brief_description>
- Simple gibberish speech stream playback.
</brief_description>
<description>
- AudioStream used for gibberish playback. It plays randomized phonemes, which can be used to accompany text dialogs.
</description>
<methods>
- <method name="set_phonemes" >
- <argument index="0" name="phonemes" type="Object">
+ <method name="set_mode">
+ <argument index="0" name="mode" type="int">
</argument>
<description>
- Set the phoneme library.
</description>
</method>
- <method name="get_phonemes" qualifiers="const" >
- <return type="Object">
+ <method name="get_mode" qualifiers="const">
+ <return type="int">
</return>
<description>
- Return the phoneme library.
</description>
</method>
- <method name="set_pitch_scale" >
- <argument index="0" name="pitch_scale" type="real">
+ <method name="set_octree">
+ <argument index="0" name="octree" type="RawArray">
</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="real">
+ <method name="get_octree" qualifiers="const">
+ <return type="RawArray">
</return>
<description>
- Return the pitch scale.
</description>
</method>
- <method name="set_pitch_random_scale" >
- <argument index="0" name="pitch_random_scale" type="real">
+ <method name="set_light">
+ <argument index="0" name="light" type="RawArray">
</argument>
<description>
- Set the random scaling for the pitch.
</description>
</method>
- <method name="get_pitch_random_scale" qualifiers="const" >
- <return type="real">
+ <method name="get_light" qualifiers="const">
+ <return type="RawArray">
</return>
<description>
- Return the pitch random scaling.
</description>
</method>
- <method name="set_xfade_time" >
- <argument index="0" name="sec" type="real">
+ <method name="set_sampler_octree">
+ <argument index="0" name="sampler_octree" type="IntArray">
</argument>
<description>
- Set the cross-fade time between random phonemes.
</description>
</method>
- <method name="get_xfade_time" qualifiers="const" >
- <return type="real">
+ <method name="get_sampler_octree" qualifiers="const">
+ <return type="IntArray">
</return>
<description>
- Return the cross-fade time between random phonemes.
</description>
</method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStreamMPC" inherits="AudioStreamResampled" 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="add_lightmap">
+ <argument index="0" name="texture" type="Texture">
+ </argument>
+ <argument index="1" name="gen_size" type="Vector2">
</argument>
<description>
- Set the file to be played.
</description>
</method>
- <method name="get_file" qualifiers="const" >
- <return type="String">
+ <method name="erase_lightmap">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear_lightmaps">
+ <description>
+ </description>
+ </method>
+ <method name="set_cell_subdivision">
+ <argument index="0" name="cell_subdivision" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_cell_subdivision" qualifiers="const">
+ <return type="int">
</return>
<description>
- Return the file being played.
+ </description>
+ </method>
+ <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">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_plot_size">
+ <argument index="0" name="plot_size" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_plot_size" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_bounces">
+ <argument index="0" name="bounces" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bounces" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_edge_damp">
+ <argument index="0" name="edge_damp" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_edge_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_normal_damp">
+ <argument index="0" name="normal_damp" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_normal_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_tint">
+ <argument index="0" name="tint" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tint" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_saturation">
+ <argument index="0" name="saturation" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_saturation" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_ao_radius">
+ <argument index="0" name="ao_radius" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_ao_radius" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_ao_strength">
+ <argument index="0" name="ao_strength" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_ao_strength" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_format">
+ <argument index="0" name="format" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_format" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_energy_multiplier">
+ <argument index="0" name="energy_multiplier" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_energy_multiplier" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_gamma_adjust">
+ <argument index="0" name="gamma_adjust" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_gamma_adjust" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_bake_flag">
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bake_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <description>
</description>
</method>
</methods>
<constants>
+ <constant name="MODE_OCTREE" value="0">
+ </constant>
+ <constant name="MODE_LIGHTMAPS" value="1">
+ </constant>
+ <constant name="BAKE_DIFFUSE" value="0">
+ </constant>
+ <constant name="BAKE_SPECULAR" value="1">
+ </constant>
+ <constant name="BAKE_TRANSLUCENT" value="2">
+ </constant>
+ <constant name="BAKE_CONSERVE_ENERGY" value="3">
+ </constant>
+ <constant name="BAKE_MAX" value="5">
+ </constant>
</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">
+<class name="BakedLightInstance" inherits="VisualInstance" category="Core">
<brief_description>
- Base class for resampled audio streams.
</brief_description>
<description>
- Base class for resampled audio streams.
</description>
<methods>
+ <method name="set_baked_light">
+ <argument index="0" name="baked_light" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_baked_light" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_baked_light_instance" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
+ <signals>
+ <signal name="baked_light_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
-<class name="AudioStreamSpeex" inherits="AudioStreamResampled" category="Core">
+<class name="BakedLightSampler" inherits="VisualInstance" 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_param">
+ <argument index="0" name="param" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
</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_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_resolution">
+ <argument index="0" name="resolution" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_resolution" qualifiers="const">
+ <return type="int">
</return>
<description>
- Return the speech file.
</description>
</method>
</methods>
<constants>
+ <constant name="PARAM_RADIUS" value="0">
+ </constant>
+ <constant name="PARAM_STRENGTH" value="1">
+ </constant>
+ <constant name="PARAM_ATTENUATION" value="2">
+ </constant>
+ <constant name="PARAM_DETAIL_RATIO" value="3">
+ </constant>
+ <constant name="PARAM_MAX" value="4">
+ </constant>
</constants>
</class>
<class name="BaseButton" inherits="Control" category="Core">
@@ -4337,64 +5034,91 @@
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>
+ 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">
<return type="bool">
</return>
<description>
- Return when the button is pressed (only if toggle_mode is active).
</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">
+ <return type="int">
+ </return>
+ <description>
+ Return the visual state used to draw the button. This is useful mainly when implementing your own draw code by either overiding _draw() or connecting to "draw" signal. The visual state of the button is defined by the DRAW_* enum.
+ </description>
+ </method>
</methods>
<signals>
+ <signal name="released">
+ <description>
+ </description>
+ </signal>
<signal name="toggled">
<argument index="0" name="pressed" type="bool">
</argument>
@@ -4409,6 +5133,14 @@
</signal>
</signals>
<constants>
+ <constant name="DRAW_NORMAL" value="0">
+ </constant>
+ <constant name="DRAW_PRESSED" value="1">
+ </constant>
+ <constant name="DRAW_HOVER" value="2">
+ </constant>
+ <constant name="DRAW_DISABLED" value="3">
+ </constant>
</constants>
</class>
<class name="BitMap" inherits="Resource" category="Core">
@@ -4417,19 +5149,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">
@@ -4437,7 +5169,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">
@@ -4445,7 +5177,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">
@@ -4453,13 +5185,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>
@@ -4487,8 +5219,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">
@@ -4499,14 +5249,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>
@@ -4525,66 +5275,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>
@@ -4594,6 +5344,30 @@
</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="ButtonArray" inherits="Control" category="Core">
<brief_description>
@@ -4603,14 +5377,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;">
@@ -4618,7 +5392,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">
@@ -4626,7 +5400,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">
@@ -4635,7 +5409,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">
@@ -4644,7 +5418,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">
@@ -4653,42 +5427,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>
@@ -4721,7 +5495,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>
@@ -4729,35 +5503,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>
@@ -4767,6 +5541,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>
@@ -4776,16 +5554,16 @@
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">
</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.
+ 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">
@@ -4793,16 +5571,16 @@
<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">
</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.
+ 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">
@@ -4811,7 +5589,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">
@@ -4819,131 +5605,113 @@
<description>
</description>
</method>
- <method name="set_perspective" >
- <argument index="0" name="fov" type="real">
+ <method name="set_perspective">
+ <argument index="0" name="fov" type="float">
</argument>
- <argument index="1" name="z_near" type="real">
+ <argument index="1" name="z_near" type="float">
</argument>
- <argument index="2" name="z_far" type="real">
+ <argument index="2" name="z_far" type="float">
</argument>
<description>
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" >
- <argument index="0" name="size" type="real">
+ <method name="set_orthogonal">
+ <argument index="0" name="size" type="float">
</argument>
- <argument index="1" name="z_near" type="real">
+ <argument index="1" name="z_near" type="float">
</argument>
- <argument index="2" name="z_far" type="real">
+ <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" >
- <return type="real">
+ <method name="get_fov" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_size" qualifiers="const" >
- <return type="real">
+ <method name="get_size" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_zfar" qualifiers="const" >
- <return type="real">
+ <method name="get_zfar" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_znear" qualifiers="const" >
- <return type="real">
+ <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_use_vertical_aspect" >
- <argument index="0" name="enable" type="bool">
+ <method name="set_keep_aspect_mode">
+ <argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="is_using_vertical_aspect" qualifiers="const" >
- <return type="bool">
+ <method name="get_keep_aspect_mode" qualifiers="const">
+ <return type="int">
</return>
<description>
</description>
@@ -4956,6 +5724,10 @@
<constant name="PROJECTION_ORTHOGONAL" value="1">
Orthogonal Projection (objects remain the same size on the screen no matter how far away they are).
</constant>
+ <constant name="KEEP_WIDTH" value="0">
+ </constant>
+ <constant name="KEEP_HEIGHT" value="1">
+ </constant>
</constants>
</class>
<class name="Camera2D" inherits="Node2D" category="Core">
@@ -4964,143 +5736,140 @@
</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" >
- <argument index="0" name="ofs" type="real">
+ <method name="set_v_offset">
+ <argument index="0" name="ofs" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_v_offset" qualifiers="const" >
- <return type="real">
+ <method name="get_v_offset" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_h_offset" >
- <argument index="0" name="ofs" type="real">
+ <method name="set_h_offset">
+ <argument index="0" name="ofs" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_h_offset" qualifiers="const" >
- <return type="real">
+ <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="real">
+ <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" >
- <return type="real">
+ <method name="get_drag_margin" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="margin" type="int">
</argument>
@@ -5108,50 +5877,54 @@
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" >
+ <method name="set_zoom">
<argument index="0" name="arg0" 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" >
- <argument index="0" name="follow_smoothing" type="real">
+ <method name="set_follow_smoothing">
+ <argument index="0" name="follow_smoothing" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_follow_smoothing" qualifiers="const" >
- <return type="real">
+ <method name="get_follow_smoothing" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="force_update_scroll" >
+ <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">
@@ -5160,165 +5933,180 @@
</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" >
- <argument index="0" name="degrees" type="real">
+ <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="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" >
- <argument index="0" name="opacity" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="self_opacity" type="real">
+ <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" >
- <return type="real">
+ <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">
</argument>
<argument index="2" name="color" type="Color">
</argument>
- <argument index="3" name="width" type="real" default="1">
+ <argument index="3" name="width" type="float" default="1">
</argument>
<description>
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">
@@ -5327,10 +6115,10 @@
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="real">
+ <argument index="1" name="radius" type="float">
</argument>
<argument index="2" name="color" type="Color">
</argument>
@@ -5338,7 +6126,7 @@
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">
@@ -5347,20 +6135,22 @@
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">
@@ -5369,11 +6159,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">
@@ -5382,7 +6174,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">
@@ -5391,43 +6183,39 @@
</argument>
<argument index="3" name="texture" type="Texture" default="Object()">
</argument>
- <argument index="4" name="width" type="real" default="1">
+ <argument index="4" name="width" type="float" default="1">
</argument>
<description>
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">
</argument>
- <argument index="2" name="uvs" type="Vector2Array">
- </argument>
- <argument index="3" name="texture" type="Texture" default="Array()">
+ <argument index="2" name="uvs" type="Vector2Array" default="Array()">
</argument>
- <argument index="4" name="arg4" type="real" default="Object()">
+ <argument index="3" name="texture" type="Texture" default="Object()">
</argument>
<description>
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="ColorArray">
- </argument>
- <argument index="2" name="uvs" type="Vector2Array">
+ <argument index="1" name="color" type="Color">
</argument>
- <argument index="3" name="texture" type="Texture" default="Array()">
+ <argument index="2" name="uvs" type="Vector2Array" default="Array()">
</argument>
- <argument index="4" name="arg4" type="real" default="Object()">
+ <argument index="3" name="texture" type="Texture" default="Object()">
</argument>
<description>
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">
@@ -5442,8 +6230,8 @@
Draw a string using a custom font.
</description>
</method>
- <method name="draw_char" >
- <return type="real">
+ <method name="draw_char">
+ <return type="float">
</return>
<argument index="0" name="font" type="Font">
</argument>
@@ -5459,10 +6247,10 @@
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="real">
+ <argument index="1" name="rot" type="float">
</argument>
<argument index="2" name="scale" type="Vector2">
</argument>
@@ -5470,48 +6258,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="get_viewport" qualifiers="const" >
- <return type="Object">
+ <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">
@@ -5531,13 +6369,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.
@@ -5548,6 +6386,9 @@
<constant name="BLEND_MODE_MUL" value="3">
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.
</constant>
@@ -5565,6 +6406,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.
@@ -5573,84 +6488,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" >
- <argument index="0" name="rotation" type="real">
+ <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" >
- <return type="real">
+ <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>
@@ -5661,301 +6576,123 @@
<constants>
</constants>
</class>
-<class name="CapsuleShape" inherits="Shape" category="Core">
+<class name="CanvasModulate" inherits="Node2D" category="Core">
<brief_description>
- Capsule shape resource.
</brief_description>
<description>
- Capsule shape resource, which can be set into a [PhysicsBody] or area.
</description>
<methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- Set the capsule radius.
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the capsule radius.
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="real">
+ <method name="set_color">
+ <argument index="0" name="color" type="Color">
</argument>
<description>
- Set the capsule height.
</description>
</method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
+ <method name="get_color" qualifiers="const">
+ <return type="Color">
</return>
<description>
- Return the capsule height.
</description>
</method>
</methods>
<constants>
</constants>
</class>
-<class name="CapsuleShape2D" inherits="Shape2D" category="Core">
+<class name="CapsuleShape" inherits="Shape" category="Core">
<brief_description>
- Capsule 2D shape resource for physics.
+ Capsule shape resource.
</brief_description>
<description>
- 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.
+ Capsule shape resource, which can be set into a [PhysicsBody] or area.
</description>
<methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
+ <method name="set_radius">
+ <argument index="0" name="radius" type="float">
</argument>
<description>
- Radius of the [CapsuleShape2D].
+ Set the capsule radius.
</description>
</method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
+ <method name="get_radius" qualifiers="const">
+ <return type="float">
</return>
<description>
- Return the radius of the [CapsuleShape2D].
+ Return the capsule radius.
</description>
</method>
- <method name="set_height" >
- <argument index="0" name="height" type="real">
+ <method name="set_height">
+ <argument index="0" name="height" type="float">
</argument>
<description>
- Height of the [CapsuleShape2D].
+ Set the capsule height.
</description>
</method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
+ <method name="get_height" qualifiers="const">
+ <return type="float">
</return>
<description>
- Return the height of the [CapsuleShape2D].
+ Return the capsule height.
</description>
</method>
</methods>
<constants>
</constants>
</class>
-<class name="CarBody" inherits="PhysicsBody" category="Core">
+<class name="CapsuleShape2D" inherits="Shape2D" category="Core">
<brief_description>
+ Capsule 2D shape resource for physics.
</brief_description>
<description>
+ 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_max_steer_angle" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_steer_rate" >
- <argument index="0" name="rate" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_drive_torque" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_steer_angle" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_steer_rate" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_drive_torque" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_target_steering" >
- <argument index="0" name="amount" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_target_accelerate" >
- <argument index="0" name="amount" type="real">
+ <method name="set_radius">
+ <argument index="0" name="radius" type="float">
</argument>
<description>
+ Set the radius of the [CapsuleShape2D].
</description>
</method>
- <method name="set_hand_brake" >
- <argument index="0" name="amount" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_target_steering" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_target_accelerate" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_hand_brake" qualifiers="const" >
- <return type="real">
- </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">
+ <method name="get_radius" qualifiers="const">
+ <return type="float">
</return>
<description>
+ Return the radius of the [CapsuleShape2D].
</description>
</method>
- <method name="set_friction" >
- <argument index="0" name="friction" type="real">
+ <method name="set_height">
+ <argument index="0" name="height" type="float">
</argument>
<description>
+ Set the height of the [CapsuleShape2D].
</description>
</method>
- <method name="get_friction" qualifiers="const" >
- <return type="real">
+ <method name="get_height" qualifiers="const">
+ <return type="float">
</return>
<description>
+ Return the height of the [CapsuleShape2D].
</description>
</method>
</methods>
<constants>
</constants>
</class>
-<class name="CarWheel" inherits="Spatial" category="Core">
+<class name="CenterContainer" inherits="Container" category="Core">
<brief_description>
+ Keeps children controls centered.
</brief_description>
<description>
+ CenterContainer Keeps children controls centered. This container keeps all children to their minimum size, in the center.
</description>
<methods>
- <method name="set_side_friction" >
- <argument index="0" name="friction" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_forward_friction" >
- <argument index="0" name="friction" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_travel" >
- <argument index="0" name="distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_resting_frac" >
- <argument index="0" name="frac" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_damping_frac" >
- <argument index="0" name="frac" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_num_rays" >
- <argument index="0" name="amount" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_side_friction" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_forward_friction" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_travel" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_resting_frac" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_damping_frac" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_num_rays" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_type_drive" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_type_drive" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_type_steer" >
+ <method name="set_use_top_left">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_type_steer" qualifiers="const" >
+ <method name="is_using_top_left" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -5965,17 +6702,49 @@
<constants>
</constants>
</class>
-<class name="CenterContainer" inherits="Container" category="Core">
+<class name="CheckBox" inherits="Button" category="Core">
<brief_description>
- Keeps children controls centered.
</brief_description>
<description>
- CenterContainer Keeps children controls centered. This container keeps all children to their minimum size, in the center.
</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>
@@ -5988,6 +6757,36 @@
</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="off" type="Texture">
+ </theme_item>
+ <theme_item name="on" 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="CircleShape2D" inherits="Shape2D" category="Core">
<brief_description>
@@ -5997,15 +6796,15 @@
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" >
- <argument index="0" name="radius" type="real">
+ <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" >
- <return type="real">
+ <method name="get_radius" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the radius of the circle shape.
@@ -6021,7 +6820,21 @@
<description>
</description>
<methods>
- <method name="add_shape" >
+ <method name="_input_event" qualifiers="virtual">
+ <argument index="0" name="camera" type="Object">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <argument index="2" name="click_pos" type="Vector3">
+ </argument>
+ <argument index="3" name="click_normal" type="Vector3">
+ </argument>
+ <argument index="4" name="shape_idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_shape">
<argument index="0" name="shape" type="Shape">
</argument>
<argument index="1" name="transform" type="Transform" default="Transform()">
@@ -6029,13 +6842,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">
@@ -6043,7 +6856,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">
@@ -6051,7 +6864,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">
@@ -6059,7 +6872,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">
@@ -6067,7 +6880,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">
@@ -6075,7 +6888,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">
@@ -6083,23 +6896,71 @@
<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">
+ <argument index="0" name="ray_pickable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_ray_pickable" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="bool">
+ </return>
<description>
</description>
</method>
- <method name="get_rid" qualifiers="const" >
+ <method name="get_rid" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
</methods>
+ <signals>
+ <signal name="mouse_enter">
+ <description>
+ </description>
+ </signal>
+ <signal name="input_event">
+ <argument index="0" name="camera" type="Object">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <argument index="2" name="click_pos" type="Vector3">
+ </argument>
+ <argument index="3" name="click_normal" type="Vector3">
+ </argument>
+ <argument index="4" name="shape_idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="mouse_exit">
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
@@ -6108,10 +6969,20 @@
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 [CollisionBody2D] and [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>
+ </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">
@@ -6120,14 +6991,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.
</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">
@@ -6136,7 +7007,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">
@@ -6145,7 +7016,7 @@
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">
@@ -6153,7 +7024,7 @@
<description>
</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">
@@ -6162,7 +7033,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">
@@ -6171,7 +7042,7 @@
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">
@@ -6179,22 +7050,113 @@
<description>
</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 the object.
+ </description>
+ </method>
+ <method name="set_pickable">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_pickable" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="mouse_enter">
+ <description>
+ </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>
+ </description>
+ </signal>
+ <signal name="mouse_exit">
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
+<class name="CollisionPolygon" inherits="Spatial" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_build_mode">
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_build_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_depth">
+ <argument index="0" name="depth" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_depth" qualifiers="const">
+ <return type="float">
+ </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>
+ <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>
</description>
</method>
</methods>
@@ -6203,12 +7165,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="arg0" 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="arg0" 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>
@@ -6219,18 +7240,93 @@
<description>
</description>
<methods>
+ <method name="resource_changed">
+ <argument index="0" name="arg0" 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>
@@ -6240,10 +7336,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">
@@ -6251,53 +7347,53 @@
<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" >
- <return type="real">
+ <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">
</argument>
- <argument index="1" name="t" type="real">
+ <argument index="1" name="t" type="float">
</argument>
<description>
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">
@@ -6306,25 +7402,47 @@
Return the HTML hexadecimal color string.
</description>
</method>
- <method name="Color" >
- <argument index="0" name="r" type="real">
+ <method name="Color">
+ <return type="Color">
+ </return>
+ <argument index="0" name="r" type="float">
</argument>
- <argument index="1" name="g" type="real">
+ <argument index="1" name="g" type="float">
</argument>
- <argument index="2" name="b" type="real">
+ <argument index="2" name="b" type="float">
</argument>
- <argument index="3" name="a" type="real">
+ <argument index="3" name="a" type="float">
</argument>
<description>
Construct the color from an RGBA profile.
</description>
</method>
- <method name="Color" >
- <argument index="0" name="r" type="real">
+ <method name="Color">
+ <return type="Color">
+ </return>
+ <argument index="0" name="r" type="float">
</argument>
- <argument index="1" name="g" type="real">
+ <argument index="1" name="g" type="float">
</argument>
- <argument index="2" name="b" type="real">
+ <argument index="2" name="b" type="float">
+ </argument>
+ <description>
+ Construct the color from an RGBA profile.
+ </description>
+ </method>
+ <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">
+ <return type="Color">
+ </return>
+ <argument index="0" name="from" type="String">
</argument>
<description>
Construct the color from an RGBA profile.
@@ -6332,19 +7450,19 @@
</method>
</methods>
<members>
- <member name="r" type="real">
+ <member name="r" type="float">
</member>
- <member name="g" type="real">
+ <member name="g" type="float">
</member>
- <member name="b" type="real">
+ <member name="b" type="float">
</member>
- <member name="a" type="real">
+ <member name="a" type="float">
</member>
- <member name="h" type="real">
+ <member name="h" type="float">
</member>
- <member name="s" type="real">
+ <member name="s" type="float">
</member>
- <member name="v" type="real">
+ <member name="v" type="float">
</member>
</members>
<constants>
@@ -6355,10 +7473,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">
@@ -6367,21 +7485,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">
@@ -6390,14 +7508,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>
@@ -6416,39 +7536,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>
@@ -6466,6 +7586,18 @@
</signals>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="value_width" type="int">
+ </theme_item>
+ <theme_item name="value_height" type="int">
+ </theme_item>
+ <theme_item name="color_width" type="int">
+ </theme_item>
+ <theme_item name="label_width" type="int">
+ </theme_item>
+ <theme_item name="hseparator" type="int">
+ </theme_item>
+ </theme_items>
</class>
<class name="ColorPickerButton" inherits="Button" category="Core">
<brief_description>
@@ -6473,25 +7605,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>
@@ -6508,23 +7640,81 @@
</signals>
<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="ColorRamp" inherits="Resource" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <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>
@@ -6541,16 +7731,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>
@@ -6561,13 +7752,51 @@
<constants>
</constants>
</class>
+<class name="ConeTwistJoint" inherits="Joint" 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="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="PARAM_SWING_SPAN" value="0">
+ </constant>
+ <constant name="PARAM_TWIST_SPAN" value="1">
+ </constant>
+ <constant name="PARAM_BIAS" value="2">
+ </constant>
+ <constant name="PARAM_SOFTNESS" value="3">
+ </constant>
+ <constant name="PARAM_RELAXATION" value="4">
+ </constant>
+ <constant name="PARAM_MAX" value="5">
+ </constant>
+ </constants>
+</class>
<class name="ConfigFile" inherits="Reference" category="Core">
<brief_description>
</brief_description>
<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">
@@ -6577,7 +7806,7 @@
<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">
@@ -6585,7 +7814,7 @@
<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">
@@ -6593,7 +7822,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">
@@ -6603,13 +7832,13 @@
<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">
@@ -6617,16 +7846,16 @@
<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>
@@ -6645,7 +7874,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>
@@ -6665,12 +7894,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">
@@ -6707,14 +7936,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">
@@ -6724,7 +7953,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">
@@ -6732,7 +7961,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">
@@ -6740,46 +7969,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">
@@ -6788,7 +8017,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">
@@ -6797,69 +8026,69 @@
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="real">
+ <argument index="1" name="offset" type="float">
</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" >
+ <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 index="2" name="offset" type="float">
</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" >
+ <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" >
- <return type="real">
+ <method name="get_margin" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="margin" type="int">
</argument>
@@ -6867,168 +8096,168 @@
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_custom_minimum_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_parent_area_size" qualifiers="const" >
+ <method name="get_parent_area_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_global_pos" qualifiers="const" >
+ <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" >
- <argument index="0" name="ratio" type="real">
+ <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" >
- <return type="real">
+ <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">
@@ -7037,7 +8266,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">
@@ -7046,7 +8275,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">
@@ -7055,7 +8284,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">
@@ -7063,7 +8292,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">
@@ -7072,7 +8301,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">
@@ -7082,7 +8311,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">
@@ -7092,7 +8321,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">
@@ -7102,7 +8331,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">
@@ -7112,7 +8341,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">
@@ -7122,20 +8351,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)">
@@ -7144,21 +8373,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)">
@@ -7167,7 +8396,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">
@@ -7176,7 +8405,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">
@@ -7185,21 +8414,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">
@@ -7207,28 +8436,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">
@@ -7262,6 +8497,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>
@@ -7274,14 +8511,16 @@
</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.
</constant>
+ <constant name="ANCHOR_CENTER" value="3">
+ </constant>
<constant name="FOCUS_NONE" value="0">
Control can't acquire focus.
</constant>
@@ -7356,19 +8595,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>
@@ -7380,27 +8619,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>
@@ -7417,37 +8657,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">
@@ -7455,7 +8695,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">
@@ -7463,26 +8703,26 @@
<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" >
- <argument index="0" name="quality" type="real">
+ <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" >
- <return type="real">
+ <method name="get_lossy_storage_quality" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -7519,132 +8759,169 @@
</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)">
</argument>
<argument index="2" name="out" type="Vector2" default="Vector2(0,0)">
</argument>
+ <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">
</argument>
- <argument index="1" name="t" type="real">
+ <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="bake" qualifiers="const" >
- <return type="Vector2Array">
+ <method name="interpolatef" qualifiers="const">
+ <return type="Vector2">
</return>
- <argument index="0" name="subdivs" type="int" default="10">
+ <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_points_in" >
- <argument index="0" name="arg0" type="Vector2Array">
+ <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="set_points_out" >
- <argument index="0" name="arg0" type="Vector2Array">
- </argument>
+ <method name="get_bake_interval" qualifiers="const">
+ <return type="float">
+ </return>
<description>
+ Returns the distance between two adjacent cached points.
</description>
</method>
- <method name="set_points_pos" >
- <argument index="0" name="arg0" type="Vector2Array">
- </argument>
+ <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="get_points_in" qualifiers="const" >
- <return type="Vector2Array">
+ <method name="interpolate_baked" qualifiers="const">
+ <return type="Vector2">
</return>
+ <argument index="0" name="offset" type="float">
+ </argument>
+ <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_points_out" 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="get_points_pos" qualifiers="const" >
+ <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>
@@ -7653,17 +8930,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)">
@@ -7673,134 +8954,171 @@
<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="real">
+ <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" >
- <return type="real">
+ <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">
</argument>
- <argument index="1" name="t" type="real">
+ <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="real">
+ <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" >
- <argument index="0" name="distance" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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="real">
+ <argument index="0" name="offset" type="float">
</argument>
<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>
@@ -7809,63 +9127,63 @@
</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" >
- <argument index="0" name="length" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="rest_length" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="stiffness" type="real">
+ <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" >
- <return type="real">
+ <method name="get_stiffness" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the stiffness of the spring joint.
</description>
</method>
- <method name="set_damping" >
- <argument index="0" name="damping" type="real">
+ <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" >
- <return type="real">
+ <method name="get_damping" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the damping of the spring joint.
@@ -7883,26 +9201,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">
@@ -7911,21 +9229,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">
@@ -7933,14 +9251,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>
@@ -7958,28 +9276,28 @@
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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_shadow_param" qualifiers="const" >
- <return type="real">
+ <method name="get_shadow_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="param" type="int">
</argument>
@@ -7992,7 +9310,9 @@
</constant>
<constant name="SHADOW_PERSPECTIVE" value="1">
</constant>
- <constant name="SHADOW_PARALLEL_SPLIT" value="2">
+ <constant name="SHADOW_PARALLEL_2_SPLITS" value="2">
+ </constant>
+ <constant name="SHADOW_PARALLEL_4_SPLITS" value="3">
</constant>
<constant name="SHADOW_PARAM_MAX_DISTANCE" value="0">
</constant>
@@ -8008,43 +9328,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">
@@ -8052,37 +9372,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">
@@ -8090,15 +9410,23 @@
<description>
</description>
</method>
- <method name="get_space_left" >
- <return type="int">
+ <method name="dir_exists">
+ <return type="bool">
</return>
+ <argument index="0" name="name" type="String">
+ </argument>
<description>
</description>
</method>
- <method name="copy" >
+ <method name="get_space_left">
<return type="int">
</return>
+ <description>
+ </description>
+ </method>
+ <method name="copy">
+ <return type="Error">
+ </return>
<argument index="0" name="from" type="String">
</argument>
<argument index="1" name="to" type="String">
@@ -8106,8 +9434,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>
@@ -8116,8 +9444,8 @@
<description>
</description>
</method>
- <method name="remove" >
- <return type="int">
+ <method name="remove">
+ <return type="Error">
</return>
<argument index="0" name="file" type="String">
</argument>
@@ -8128,36 +9456,152 @@
<constants>
</constants>
</class>
-<class name="EditableShape" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="EditableSphere" inherits="EditableShape" category="Core">
+<class name="EditorFileDialog" inherits="ConfirmationDialog" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
+ <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="arg0" 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_radius" qualifiers="const" >
- <return type="real">
+ <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">
@@ -8166,7 +9610,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">
@@ -8174,19 +9618,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">
@@ -8196,7 +9640,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>
@@ -8212,21 +9656,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">
@@ -8234,7 +9678,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">
@@ -8244,25 +9688,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">
@@ -8270,31 +9714,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" >
+ <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">
@@ -8302,7 +9746,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">
@@ -8314,7 +9758,7 @@
<description>
</description>
</method>
- <method name="remove_custom_type" >
+ <method name="remove_custom_type">
<argument index="0" name="type" type="String">
</argument>
<description>
@@ -8342,7 +9786,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>
@@ -8358,17 +9802,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>
@@ -8378,47 +9822,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">
@@ -8426,13 +9848,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">
@@ -8440,7 +9862,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">
@@ -8448,7 +9870,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">
@@ -8456,7 +9878,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>
@@ -8474,81 +9896,111 @@
</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_MAX" value="6">
</constant>
- <constant name="BG_CUBEMAP_RGBE" value="6">
+ <constant name="BG_PARAM_CANVAS_MAX_LAYER" value="0">
</constant>
- <constant name="BG_MAX" value="7">
+ <constant name="BG_PARAM_COLOR" value="1">
</constant>
- <constant name="BG_PARAM_COLOR" value="0">
+ <constant name="BG_PARAM_TEXTURE" value="2">
</constant>
- <constant name="BG_PARAM_TEXTURE" value="1">
+ <constant name="BG_PARAM_CUBEMAP" value="3">
</constant>
- <constant name="BG_PARAM_CUBEMAP" value="2">
+ <constant name="BG_PARAM_ENERGY" value="4">
</constant>
- <constant name="BG_PARAM_ENERGY" value="3">
+ <constant name="BG_PARAM_GLOW" value="6">
</constant>
- <constant name="BG_PARAM_MAX" value="5">
+ <constant name="BG_PARAM_MAX" value="7">
</constant>
- <constant name="FX_GLOW" value="0">
+ <constant name="FX_AMBIENT_LIGHT" value="0">
</constant>
- <constant name="FX_DOF_BLUR" value="1">
+ <constant name="FX_FXAA" value="1">
</constant>
- <constant name="FX_HDR" value="2">
+ <constant name="FX_GLOW" value="2">
</constant>
- <constant name="FX_FOG" value="3">
+ <constant name="FX_DOF_BLUR" value="3">
</constant>
- <constant name="FX_BCS" value="4">
+ <constant name="FX_HDR" value="4">
</constant>
- <constant name="FX_GAMMA" value="5">
+ <constant name="FX_FOG" value="5">
</constant>
- <constant name="FX_MAX" value="6">
+ <constant name="FX_BCS" value="6">
</constant>
- <constant name="FX_PARAM_GLOW_BLUR_PASSES" value="0">
+ <constant name="FX_SRGB" value="7">
</constant>
- <constant name="FX_PARAM_GLOW_BLOOM" value="1">
+ <constant name="FX_MAX" value="8">
</constant>
- <constant name="FX_PARAM_GLOW_BLOOM_TRESHOLD" value="2">
+ <constant name="FX_BLUR_BLEND_MODE_ADDITIVE" value="0">
</constant>
- <constant name="FX_PARAM_DOF_BLUR_PASSES" value="3">
+ <constant name="FX_BLUR_BLEND_MODE_SCREEN" value="1">
</constant>
- <constant name="FX_PARAM_DOF_BLUR_BEGIN" value="4">
+ <constant name="FX_BLUR_BLEND_MODE_SOFTLIGHT" value="2">
</constant>
- <constant name="FX_PARAM_DOF_BLUR_RANGE" value="5">
+ <constant name="FX_HDR_TONE_MAPPER_LINEAR" value="0">
</constant>
- <constant name="FX_PARAM_HDR_EXPOSURE" value="6">
+ <constant name="FX_HDR_TONE_MAPPER_LOG" value="1">
</constant>
- <constant name="FX_PARAM_HDR_SCALAR" value="7">
+ <constant name="FX_HDR_TONE_MAPPER_REINHARDT" value="2">
</constant>
- <constant name="FX_PARAM_HDR_GLOW_TRESHOLD" value="8">
+ <constant name="FX_HDR_TONE_MAPPER_REINHARDT_AUTOWHITE" value="3">
</constant>
- <constant name="FX_PARAM_HDR_GLOW_SCALE" value="9">
+ <constant name="FX_PARAM_AMBIENT_LIGHT_COLOR" value="0">
</constant>
- <constant name="FX_PARAM_HDR_MIN_LUMINANCE" value="10">
+ <constant name="FX_PARAM_AMBIENT_LIGHT_ENERGY" value="1">
</constant>
- <constant name="FX_PARAM_HDR_MAX_LUMINANCE" value="11">
+ <constant name="FX_PARAM_GLOW_BLUR_PASSES" value="2">
</constant>
- <constant name="FX_PARAM_HDR_EXPOSURE_ADJUST_SPEED" value="12">
+ <constant name="FX_PARAM_GLOW_BLUR_SCALE" value="3">
</constant>
- <constant name="FX_PARAM_FOG_BEGIN" value="13">
+ <constant name="FX_PARAM_GLOW_BLUR_STRENGTH" value="4">
</constant>
- <constant name="FX_PARAM_FOG_ATTENUATION" value="16">
+ <constant name="FX_PARAM_GLOW_BLUR_BLEND_MODE" value="5">
</constant>
- <constant name="FX_PARAM_FOG_BEGIN_COLOR" value="14">
+ <constant name="FX_PARAM_GLOW_BLOOM" value="6">
</constant>
- <constant name="FX_PARAM_FOG_END_COLOR" value="15">
+ <constant name="FX_PARAM_GLOW_BLOOM_TRESHOLD" value="7">
</constant>
- <constant name="FX_PARAM_FOG_BG" value="17">
+ <constant name="FX_PARAM_DOF_BLUR_PASSES" value="8">
</constant>
- <constant name="FX_PARAM_BCS_BRIGHTNESS" value="18">
+ <constant name="FX_PARAM_DOF_BLUR_BEGIN" value="9">
</constant>
- <constant name="FX_PARAM_BCS_CONTRAST" value="19">
+ <constant name="FX_PARAM_DOF_BLUR_RANGE" value="10">
</constant>
- <constant name="FX_PARAM_BCS_SATURATION" value="20">
+ <constant name="FX_PARAM_HDR_TONEMAPPER" value="11">
</constant>
- <constant name="FX_PARAM_GAMMA" value="21">
+ <constant name="FX_PARAM_HDR_EXPOSURE" value="12">
</constant>
- <constant name="FX_PARAM_MAX" value="22">
+ <constant name="FX_PARAM_HDR_WHITE" value="13">
+ </constant>
+ <constant name="FX_PARAM_HDR_GLOW_TRESHOLD" value="14">
+ </constant>
+ <constant name="FX_PARAM_HDR_GLOW_SCALE" value="15">
+ </constant>
+ <constant name="FX_PARAM_HDR_MIN_LUMINANCE" value="16">
+ </constant>
+ <constant name="FX_PARAM_HDR_MAX_LUMINANCE" value="17">
+ </constant>
+ <constant name="FX_PARAM_HDR_EXPOSURE_ADJUST_SPEED" value="18">
+ </constant>
+ <constant name="FX_PARAM_FOG_BEGIN" value="19">
+ </constant>
+ <constant name="FX_PARAM_FOG_ATTENUATION" value="22">
+ </constant>
+ <constant name="FX_PARAM_FOG_BEGIN_COLOR" value="20">
+ </constant>
+ <constant name="FX_PARAM_FOG_END_COLOR" value="21">
+ </constant>
+ <constant name="FX_PARAM_FOG_BG" value="23">
+ </constant>
+ <constant name="FX_PARAM_BCS_BRIGHTNESS" value="24">
+ </constant>
+ <constant name="FX_PARAM_BCS_CONTRAST" value="25">
+ </constant>
+ <constant name="FX_PARAM_BCS_SATURATION" value="26">
+ </constant>
+ <constant name="FX_PARAM_MAX" value="27">
</constant>
</constants>
</class>
@@ -8558,164 +10010,164 @@
<description>
</description>
<methods>
- <method name="set_stream" >
- <argument index="0" name="stream" type="Stream">
+ <method name="set_stream">
+ <argument index="0" name="stream" type="EventStream">
</argument>
<description>
</description>
</method>
- <method name="get_stream" qualifiers="const" >
- <return type="Stream">
+ <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" >
- <argument index="0" name="volume" type="real">
+ <method name="set_volume">
+ <argument index="0" name="volume" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume" qualifiers="const" >
- <return type="real">
+ <method name="get_volume" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_pitch_scale" >
- <argument index="0" name="pitch_scale" type="real">
+ <method name="set_pitch_scale">
+ <argument index="0" name="pitch_scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_pitch_scale" qualifiers="const" >
- <return type="real">
+ <method name="get_pitch_scale" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_tempo_scale" >
- <argument index="0" name="tempo_scale" type="real">
+ <method name="set_tempo_scale">
+ <argument index="0" name="tempo_scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_tempo_scale" qualifiers="const" >
- <return type="real">
+ <method name="get_tempo_scale" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_volume_db" >
- <argument index="0" name="db" type="real">
+ <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="real">
+ <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" >
- <return type="real">
+ <method name="get_pos" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="seek_pos" >
- <argument index="0" name="time" type="real">
+ <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="set_channel_volume" >
+ <method name="set_channel_volume">
<argument index="0" name="idx" type="int">
</argument>
- <argument index="1" name="channel_volume" type="real">
+ <argument index="1" name="channel_volume" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_channel_volumeidx" qualifiers="const" >
- <return type="real">
+ <method name="get_channel_volumeidx" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
+ <method name="get_length" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_channel_last_note_time" qualifiers="const" >
- <return type="real">
+ <method name="get_channel_last_note_time" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="int">
</argument>
@@ -8752,7 +10204,31 @@
<description>
</description>
<methods>
- <method name="open" >
+ <method name="open_encrypted">
+ <return type="int">
+ </return>
+ <argument index="0" name="path" type="String">
+ </argument>
+ <argument index="1" name="mode_flags" type="int">
+ </argument>
+ <argument index="2" name="key" type="RawArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="open_encrypted_with_pass">
+ <return type="int">
+ </return>
+ <argument index="0" name="path" type="String">
+ </argument>
+ <argument index="1" name="mode_flags" type="int">
+ </argument>
+ <argument index="2" name="pass" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="open">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -8762,89 +10238,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" >
- <return type="real">
+ <method name="get_float" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_double" qualifiers="const" >
- <return type="real">
+ <method name="get_double" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_real" qualifiers="const" >
- <return type="real">
+ <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">
@@ -8852,125 +10328,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" >
- <argument index="0" name="value" type="real">
+ <method name="store_float">
+ <argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="store_double" >
- <argument index="0" name="value" type="real">
+ <method name="store_double">
+ <argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="store_real" >
- <argument index="0" name="value" type="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">
@@ -8996,90 +10472,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="arg0" 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>
@@ -9107,14 +10595,16 @@
</signals>
<constants>
<constant name="MODE_OPEN_FILE" value="0">
- Editor will not allow to select unexisting 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>
@@ -9123,6 +10613,12 @@
<constant name="ACCESS_FILESYSTEM" value="2">
</constant>
</constants>
+ <theme_items>
+ <theme_item name="files_disabled" type="Color">
+ </theme_item>
+ <theme_item name="folder" type="Texture">
+ </theme_item>
+ </theme_items>
</class>
<class name="FixedMaterial" inherits="Material" category="Core">
<brief_description>
@@ -9132,23 +10628,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">
@@ -9157,7 +10653,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">
@@ -9166,7 +10662,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">
@@ -9175,7 +10671,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">
@@ -9184,7 +10680,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">
@@ -9192,7 +10688,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">
@@ -9200,40 +10696,40 @@
<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_point_size" >
- <argument index="0" name="size" type="real">
+ <method name="set_light_shader">
+ <argument index="0" name="shader" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_point_size" qualifiers="const" >
- <return type="real">
+ <method name="get_light_shader" qualifiers="const">
+ <return type="int">
</return>
<description>
</description>
</method>
- <method name="set_detail_blend_mode" >
- <argument index="0" name="mode" type="int">
+ <method name="set_point_size">
+ <argument index="0" name="size" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_detail_blend_mode" qualifiers="const" >
- <return type="int">
+ <method name="get_point_size" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -9250,10 +10746,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).
@@ -9264,7 +10760,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>
@@ -9283,280 +10779,70 @@
</constant>
<constant name="FLAG_USE_POINT_SIZE" value="2">
</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="FollowCamera" inherits="Camera" category="Core">
+<class name="Font" inherits="Resource" category="Core">
<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_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">
+ <method name="create_from_fnt">
+ <return type="int">
</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 index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_up_vector" >
- <argument index="0" name="vector" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_up_vector" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Font" inherits="Resource" category="Core">
- <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">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="px" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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">
@@ -9567,7 +10853,7 @@
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">
@@ -9578,14 +10864,14 @@
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">
@@ -9594,13 +10880,27 @@
</argument>
<argument index="3" name="align" type="Vector2" default="Vector2(0,0)">
</argument>
- <argument index="4" name="advance" type="real" default="-1">
+ <argument index="4" name="advance" type="float" default="-1">
</argument>
<description>
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">
@@ -9611,7 +10911,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">
@@ -9620,12 +10920,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">
@@ -9640,8 +10952,8 @@
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" >
- <return type="real">
+ <method name="draw_char" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="canvas_item" type="RID">
</argument>
@@ -9667,39 +10979,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>
- <argument index="4" name="arg3" type="var" default="NULL">
+ <argument index="3" name="arg3" type="var" default="NULL">
</argument>
- <argument index="5" name="arg4" type="var" default="NULL">
+ <argument index="4" name="arg4" type="var" default="NULL">
</argument>
- <argument index="6" name="arg5" type="var" default="NULL">
+ <argument index="5" name="arg5" type="var" default="NULL">
</argument>
- <argument index="7" name="arg6" type="var" default="NULL">
+ <argument index="6" name="arg6" type="var" default="NULL">
</argument>
- <argument index="8" name="arg7" type="var" default="NULL">
+ <argument index="7" name="arg7" type="var" default="NULL">
</argument>
- <argument index="9" name="arg8" type="var" default="NULL">
+ <argument index="8" 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>
@@ -9709,13 +11019,35 @@
<constants>
</constants>
</class>
+<class name="GDFunctionState" inherits="Reference" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="resume">
+ <argument index="0" name="arg" type="var" default="NULL">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_valid" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="GDNativeClass" inherits="Reference" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="new" >
+ <method name="new">
<description>
</description>
</method>
@@ -9729,12 +11061,162 @@
<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>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="Generic6DOFJoint" inherits="Joint" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_param_x">
+ <argument index="0" name="param" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param_x" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_param_y">
+ <argument index="0" name="param" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param_y" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_param_z">
+ <argument index="0" name="param" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param_z" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_flag_x">
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_flag_x" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_flag_y">
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_flag_y" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_flag_z">
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_flag_z" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int">
+ </argument>
<description>
</description>
</method>
</methods>
<constants>
+ <constant name="PARAM_LINEAR_LOWER_LIMIT" value="0">
+ </constant>
+ <constant name="PARAM_LINEAR_UPPER_LIMIT" value="1">
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_SOFTNESS" value="2">
+ </constant>
+ <constant name="PARAM_LINEAR_RESTITUTION" value="3">
+ </constant>
+ <constant name="PARAM_LINEAR_DAMPING" value="4">
+ </constant>
+ <constant name="PARAM_ANGULAR_LOWER_LIMIT" value="5">
+ </constant>
+ <constant name="PARAM_ANGULAR_UPPER_LIMIT" value="6">
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_SOFTNESS" value="7">
+ </constant>
+ <constant name="PARAM_ANGULAR_DAMPING" value="8">
+ </constant>
+ <constant name="PARAM_ANGULAR_RESTITUTION" value="9">
+ </constant>
+ <constant name="PARAM_ANGULAR_FORCE_LIMIT" value="10">
+ </constant>
+ <constant name="PARAM_ANGULAR_ERP" value="11">
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTOR_TARGET_VELOCITY" value="12">
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTOR_FORCE_LIMIT" value="13">
+ </constant>
+ <constant name="PARAM_MAX" value="14">
+ </constant>
+ <constant name="FLAG_ENABLE_LINEAR_LIMIT" value="0">
+ </constant>
+ <constant name="FLAG_ENABLE_ANGULAR_LIMIT" value="1">
+ </constant>
+ <constant name="FLAG_ENABLE_MOTOR" value="2">
+ </constant>
+ <constant name="FLAG_MAX" value="3">
+ </constant>
</constants>
</class>
<class name="Geometry" inherits="Object" category="Core">
@@ -9743,7 +11225,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">
@@ -9751,12 +11233,12 @@
<description>
</description>
</method>
- <method name="build_cylinder_planes" >
+ <method name="build_cylinder_planes">
<return type="Array">
</return>
- <argument index="0" name="radius" type="real">
+ <argument index="0" name="radius" type="float">
</argument>
- <argument index="1" name="height" type="real">
+ <argument index="1" name="height" type="float">
</argument>
<argument index="2" name="sides" type="int">
</argument>
@@ -9765,12 +11247,12 @@
<description>
</description>
</method>
- <method name="build_capsule_planes" >
+ <method name="build_capsule_planes">
<return type="Array">
</return>
- <argument index="0" name="radius" type="real">
+ <argument index="0" name="radius" type="float">
</argument>
- <argument index="1" name="height" type="real">
+ <argument index="1" name="height" type="float">
</argument>
<argument index="2" name="sides" type="int">
</argument>
@@ -9781,8 +11263,8 @@
<description>
</description>
</method>
- <method name="segment_intersects_circle" >
- <return type="real">
+ <method name="segment_intersects_circle">
+ <return type="float">
</return>
<argument index="0" name="segment_from" type="Vector2">
</argument>
@@ -9790,12 +11272,12 @@
</argument>
<argument index="2" name="circle_pos" type="Vector2">
</argument>
- <argument index="3" name="circle_radius" type="real">
+ <argument index="3" name="circle_radius" type="float">
</argument>
<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">
@@ -9807,7 +11289,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">
@@ -9821,7 +11303,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">
@@ -9835,7 +11317,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">
@@ -9847,7 +11329,15 @@
<description>
</description>
</method>
- <method name="ray_intersects_triangle" >
+ <method name="get_uv84_normal_bit">
+ <return type="int">
+ </return>
+ <argument index="0" name="normal" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="ray_intersects_triangle">
<argument index="0" name="from" type="Vector3">
</argument>
<argument index="1" name="dir" type="Vector3">
@@ -9861,7 +11351,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">
@@ -9875,7 +11365,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">
@@ -9884,26 +11374,26 @@
</argument>
<argument index="2" name="spos" type="Vector3">
</argument>
- <argument index="3" name="sradius" type="real">
+ <argument index="3" name="sradius" type="float">
</argument>
<description>
</description>
</method>
- <method name="segment_intersects_cylinder" >
+ <method name="segment_intersects_cylinder">
<return type="Vector3Array">
</return>
<argument index="0" name="from" type="Vector3">
</argument>
<argument index="1" name="to" type="Vector3">
</argument>
- <argument index="2" name="height" type="real">
+ <argument index="2" name="height" type="float">
</argument>
- <argument index="3" name="radius" type="real">
+ <argument index="3" name="radius" type="float">
</argument>
<description>
</description>
</method>
- <method name="segment_intersects_convex" >
+ <method name="segment_intersects_convex">
<return type="Vector3Array">
</return>
<argument index="0" name="from" type="Vector3">
@@ -9915,7 +11405,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">
@@ -9923,6 +11427,14 @@
<description>
</description>
</method>
+ <method name="make_atlas">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="sizes" type="Vector2Array">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -9935,21 +11447,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">
@@ -9957,7 +11469,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">
@@ -9965,37 +11477,55 @@
<description>
</description>
</method>
- <method name="set_draw_range_begin" >
- <argument index="0" name="mode" type="real">
+ <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" >
- <return type="real">
+ <method name="get_draw_range_begin" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_draw_range_end" >
- <argument index="0" name="mode" type="real">
+ <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" >
- <return type="real">
+ <method name="get_draw_range_end" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- </methods>
- <signals>
- <signal name="visibility_changed">
+ <method name="set_baked_light_texture_id">
+ <argument index="0" name="id" type="int">
+ </argument>
<description>
</description>
- </signal>
- </signals>
+ </method>
+ <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">
</constant>
@@ -10011,7 +11541,7 @@
</constant>
<constant name="FLAG_VISIBLE_IN_ALL_ROOMS" value="6">
</constant>
- <constant name="FLAG_MAX" value="7">
+ <constant name="FLAG_MAX" value="8">
</constant>
</constants>
</class>
@@ -10023,7 +11553,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">
@@ -10032,7 +11562,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">
@@ -10041,7 +11571,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">
@@ -10050,7 +11580,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">
@@ -10059,7 +11589,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">
@@ -10068,14 +11598,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">
@@ -10084,7 +11614,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">
@@ -10093,13 +11623,13 @@
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">
@@ -10107,7 +11637,7 @@
<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">
@@ -10115,9 +11645,411 @@
<description>
</description>
</method>
+ <method name="load_resource_pack">
+ <return type="bool">
+ </return>
+ <argument index="0" name="arg0" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="save_custom">
+ <return type="int">
+ </return>
+ <argument index="0" name="arg0" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <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>
@@ -10125,13 +12057,13 @@
<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>
@@ -10140,6 +12072,12 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="vseparation" type="int">
+ </theme_item>
+ <theme_item name="hseparation" type="int">
+ </theme_item>
+ </theme_items>
</class>
<class name="GridMap" inherits="Spatial" category="Core">
<brief_description>
@@ -10147,55 +12085,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" >
- <argument index="0" name="size" type="real">
+ <method name="set_cell_size">
+ <argument index="0" name="size" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_cell_size" qualifiers="const" >
- <return type="real">
+ <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">
@@ -10209,7 +12147,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">
@@ -10221,7 +12159,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">
@@ -10233,49 +12171,49 @@
<description>
</description>
</method>
- <method name="resource_changed" >
+ <method name="resource_changed">
<argument index="0" name="arg0" 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">
@@ -10287,7 +12225,7 @@
<description>
</description>
</method>
- <method name="crate_area" >
+ <method name="create_area">
<return type="int">
</return>
<argument index="0" name="id" type="int">
@@ -10297,7 +12235,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">
@@ -10305,7 +12243,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">
@@ -10313,7 +12251,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">
@@ -10321,7 +12259,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">
@@ -10329,7 +12267,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">
@@ -10337,23 +12275,23 @@
<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="real">
+ <argument index="1" name="distance" type="float">
</argument>
<description>
</description>
</method>
- <method name="area_get_portal_disable_distance" qualifiers="const" >
- <return type="real">
+ <method name="area_get_portal_disable_distance" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="area" type="int">
</argument>
<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">
@@ -10361,7 +12299,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">
@@ -10369,23 +12307,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">
+ <argument index="0" name="use" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_using_baked_light" qualifiers="const">
+ <return type="bool">
+ </return>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -10403,29 +12353,29 @@
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" >
- <argument index="0" name="length" type="real">
+ <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" >
- <return type="real">
+ <method name="get_length" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the length of the groove.
</description>
</method>
- <method name="set_initial_offset" >
- <argument index="0" name="offset" type="real">
+ <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" >
- <return type="real">
+ <method name="get_initial_offset" qualifiers="const">
+ <return type="float">
</return>
<description>
Set the final offset of the groove on body A.
@@ -10446,6 +12396,10 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="separation" type="int">
+ </theme_item>
+ </theme_items>
</class>
<class name="HButtonArray" inherits="ButtonArray" category="Core">
<brief_description>
@@ -10458,6 +12412,28 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="button_separator" type="int">
+ </theme_item>
+ <theme_item name="icon_separator" type="int">
+ </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_selected" type="Font">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ <theme_item name="hover" type="StyleBox">
+ </theme_item>
+ <theme_item name="focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="selected" type="StyleBox">
+ </theme_item>
+ <theme_item name="normal" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="HScrollBar" inherits="ScrollBar" category="Core">
<brief_description>
@@ -10470,6 +12446,24 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <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="grabber_hilite" type="StyleBox">
+ </theme_item>
+ <theme_item name="grabber" type="StyleBox">
+ </theme_item>
+ <theme_item name="scroll_focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="scroll" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="HSeparator" inherits="Separator" category="Core">
<brief_description>
@@ -10482,6 +12476,12 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="separation" type="int">
+ </theme_item>
+ <theme_item name="separator" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="HSlider" inherits="Slider" category="Core">
<brief_description>
@@ -10494,6 +12494,20 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="tick" type="Texture">
+ </theme_item>
+ <theme_item name="grabber_hilite" type="Texture">
+ </theme_item>
+ <theme_item name="grabber" type="Texture">
+ </theme_item>
+ <theme_item name="grabber_hilite" type="StyleBox">
+ </theme_item>
+ <theme_item name="slider" type="StyleBox">
+ </theme_item>
+ <theme_item name="focus" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="HSplitContainer" inherits="SplitContainer" category="Core">
<brief_description>
@@ -10506,6 +12520,16 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="autohide" type="int">
+ </theme_item>
+ <theme_item name="separation" type="int">
+ </theme_item>
+ <theme_item name="grabber" type="Texture">
+ </theme_item>
+ <theme_item name="bg" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="HTTPClient" inherits="Reference" category="Core">
<brief_description>
@@ -10513,23 +12537,31 @@
<description>
</description>
<methods>
- <method name="connect" >
- <return type="int">
+ <method name="connect">
+ <return type="Error">
</return>
<argument index="0" name="host" type="String">
</argument>
<argument index="1" name="port" type="int">
</argument>
+ <argument index="2" name="use_ssl" type="bool" default="false">
+ </argument>
+ <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">
@@ -10541,80 +12573,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="get_status" qualifiers="const" >
- <return type="int">
+ <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">
+ <return type="bool">
</return>
<description>
</description>
</method>
- <method name="poll" >
+ <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="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>
@@ -10655,6 +12738,8 @@
</constant>
<constant name="STATUS_CONNECTION_ERROR" value="8">
</constant>
+ <constant name="STATUS_SSL_HANDSHAKE_ERROR" value="9">
+ </constant>
<constant name="RESPONSE_CONTINUE" value="100">
</constant>
<constant name="RESPONSE_SWITCHING_PROTOCOLS" value="101">
@@ -10755,6 +12840,72 @@
</constant>
</constants>
</class>
+<class name="HingeJoint" inherits="Joint" 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="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_flag">
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <argument index="1" name="enabled" 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>
+ </methods>
+ <constants>
+ <constant name="PARAM_BIAS" value="0">
+ </constant>
+ <constant name="PARAM_LIMIT_UPPER" value="1">
+ </constant>
+ <constant name="PARAM_LIMIT_LOWER" value="2">
+ </constant>
+ <constant name="PARAM_LIMIT_BIAS" value="3">
+ </constant>
+ <constant name="PARAM_LIMIT_SOFTNESS" value="4">
+ </constant>
+ <constant name="PARAM_LIMIT_RELAXATION" value="5">
+ </constant>
+ <constant name="PARAM_MOTOR_TARGET_VELOCITY" value="6">
+ </constant>
+ <constant name="PARAM_MOTOR_MAX_IMPULSE" value="7">
+ </constant>
+ <constant name="PARAM_MAX" value="8">
+ </constant>
+ <constant name="FLAG_USE_LIMIT" value="0">
+ </constant>
+ <constant name="FLAG_ENABLE_MOTOR" value="1">
+ </constant>
+ <constant name="FLAG_MAX" value="2">
+ </constant>
+ </constants>
+</class>
<class name="IP" inherits="Object" category="Core">
<brief_description>
IP Protocol support functions.
@@ -10763,7 +12914,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">
@@ -10772,7 +12923,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">
@@ -10781,31 +12932,37 @@
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">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
<constant name="RESOLVER_STATUS_NONE" value="0">
@@ -10840,7 +12997,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">
@@ -10850,7 +13007,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">
@@ -10860,7 +13017,7 @@
<description>
</description>
</method>
- <method name="brushed" >
+ <method name="brushed">
<return type="Image">
</return>
<argument index="0" name="src" type="Image">
@@ -10872,7 +13029,15 @@
<description>
</description>
</method>
- <method name="compressed" >
+ <method name="compressed">
+ <return type="Image">
+ </return>
+ <argument index="0" name="format" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="converted">
<return type="Image">
</return>
<argument index="0" name="format" type="int" default="0">
@@ -10880,31 +13045,37 @@
<description>
</description>
</method>
- <method name="empty" >
+ <method name="decompressed">
+ <return type="Image">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
@@ -10916,7 +13087,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">
@@ -10924,19 +13095,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">
@@ -10944,7 +13115,19 @@
<description>
</description>
</method>
- <method name="resized" >
+ <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>
+ <argument index="3" name="mipmap_level" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="resized">
<return type="Image">
</return>
<argument index="0" name="x" type="int">
@@ -10956,6 +13139,29 @@
<description>
</description>
</method>
+ <method name="save_png">
+ <return type="int">
+ </return>
+ <argument index="0" name="path" type="String" default="0">
+ </argument>
+ <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">
@@ -11014,55 +13220,13 @@
</constant>
</constants>
</class>
-<class name="ImagePathFinder" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="find_path" >
- <return type="Vector2Array">
- </return>
- <argument index="0" name="from" type="Vector2">
- </argument>
- <argument index="1" name="to" type="Vector2">
- </argument>
- <argument index="2" name="optimize" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="is_solid" >
- <return type="bool">
- </return>
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="create_from_image_alpha" >
- <argument index="0" name="arg0" type="Image">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
<class name="ImageTexture" inherits="Texture" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="create" >
+ <method name="create">
<argument index="0" name="width" type="int">
</argument>
<argument index="1" name="height" type="int">
@@ -11074,7 +13238,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">
@@ -11082,59 +13246,67 @@
<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" >
- <argument index="0" name="quality" type="real">
+ <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" >
- <return type="real">
+ <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="set_size_override" >
+ <method name="premultiply_alpha">
+ <description>
+ </description>
+ </method>
+ <method name="normal_to_xy">
+ <description>
+ </description>
+ </method>
+ <method name="set_size_override">
<argument index="0" name="size" type="Vector2">
</argument>
<description>
@@ -11150,13 +13322,85 @@
</constant>
</constants>
</class>
+<class name="ImmediateGeometry" inherits="GeometryInstance" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="begin">
+ <argument index="0" name="primitive" type="int">
+ </argument>
+ <argument index="1" name="texture" type="Texture">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_normal">
+ <argument index="0" name="normal" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_tangent">
+ <argument index="0" name="tangent" type="Plane">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_color">
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_uv">
+ <argument index="0" name="uv" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_uv2">
+ <argument index="0" name="uv" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_vertex">
+ <argument index="0" name="pos" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_sphere">
+ <argument index="0" name="lats" type="int">
+ </argument>
+ <argument index="1" name="lons" type="int">
+ </argument>
+ <argument index="2" name="radius" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="end">
+ <description>
+ </description>
+ </method>
+ <method name="clear">
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="Input" inherits="Object" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="is_key_pressed" >
+ <method name="is_key_pressed">
<return type="bool">
</return>
<argument index="0" name="scancode" type="int">
@@ -11164,7 +13408,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">
@@ -11172,7 +13416,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">
@@ -11182,7 +13426,7 @@
<description>
</description>
</method>
- <method name="is_action_pressed" >
+ <method name="is_action_pressed">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11190,8 +13434,8 @@
<description>
</description>
</method>
- <method name="get_joy_axis" >
- <return type="real">
+ <method name="get_joy_axis">
+ <return type="float">
</return>
<argument index="0" name="device" type="int">
</argument>
@@ -11200,46 +13444,81 @@
<description>
</description>
</method>
- <method name="get_accelerometer" >
- <return type="Vector3">
+ <method name="get_joy_name">
+ <return type="String">
</return>
+ <argument index="0" name="device" type="int">
+ </argument>
<description>
</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">
+ <argument index="0" name="to" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="action_press">
+ <argument index="0" name="arg0" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="action_release">
+ <argument index="0" name="arg0" 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">
+ <argument index="0" name="index" type="int">
+ </argument>
+ <argument index="1" name="connected" type="bool">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="MOUSE_MODE_VISIBLE" value="0">
</constant>
@@ -11264,10 +13543,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">
@@ -11276,20 +13555,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">
@@ -11332,7 +13635,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11340,18 +13643,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">
@@ -11388,7 +13715,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11396,18 +13723,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">
@@ -11420,7 +13771,7 @@
</member>
<member name="pressed" type="bool">
</member>
- <member name="pressure" type="real">
+ <member name="pressure" type="float">
</member>
</members>
<constants>
@@ -11450,7 +13801,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11458,18 +13809,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">
@@ -11480,7 +13855,7 @@
</member>
<member name="axis" type="int">
</member>
- <member name="value" type="real">
+ <member name="value" type="float">
</member>
</members>
<constants>
@@ -11510,7 +13885,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11518,18 +13893,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">
@@ -11582,7 +13981,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11590,18 +13989,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">
@@ -11666,7 +14089,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11674,18 +14097,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">
@@ -11722,9 +14169,9 @@
</member>
<member name="relative_pos" type="Vector2">
</member>
- <member name="speed_x" type="real">
+ <member name="speed_x" type="float">
</member>
- <member name="speed_y" type="real">
+ <member name="speed_y" type="float">
</member>
<member name="speed" type="Vector2">
</member>
@@ -11756,7 +14203,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11764,18 +14211,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">
@@ -11786,21 +14257,21 @@
</member>
<member name="index" type="int">
</member>
- <member name="x" type="real">
+ <member name="x" type="float">
</member>
- <member name="y" type="real">
+ <member name="y" type="float">
</member>
<member name="pos" type="Vector2">
</member>
- <member name="relative_x" type="real">
+ <member name="relative_x" type="float">
</member>
- <member name="relative_y" type="real">
+ <member name="relative_y" type="float">
</member>
<member name="relative_pos" type="Vector2">
</member>
- <member name="speed_x" type="real">
+ <member name="speed_x" type="float">
</member>
- <member name="speed_y" type="real">
+ <member name="speed_y" type="float">
</member>
<member name="speed" type="Vector2">
</member>
@@ -11832,7 +14303,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11840,18 +14311,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">
@@ -11862,9 +14357,9 @@
</member>
<member name="index" type="int">
</member>
- <member name="x" type="real">
+ <member name="x" type="float">
</member>
- <member name="y" type="real">
+ <member name="y" type="float">
</member>
<member name="pos" type="Vector2">
</member>
@@ -11900,19 +14395,125 @@
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">
+ <return type="bool">
+ </return>
+ <argument index="0" name="action" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_action_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="action" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_action_from_id" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="erase_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="action_add_event">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="action_has_event">
+ <return type="bool">
+ </return>
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="action_erase_event">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="bool">
+ </return>
+ <argument index="0" name="event" type="InputEvent">
+ </argument>
+ <argument index="1" name="action" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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>
</methods>
<constants>
</constants>
</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">
@@ -11921,21 +14522,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">
@@ -11944,14 +14545,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>
@@ -11968,45 +14571,407 @@
<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" >
- <argument index="0" name="target" type="Object">
+ <method name="set_target">
+ <argument index="0" name="target" type="Camera">
</argument>
<description>
</description>
</method>
- <method name="set_speed" >
- <argument index="0" name="speed" type="real">
+ <method name="set_speed">
+ <argument index="0" name="speed" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_speed" qualifiers="const" >
- <return type="real">
+ <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>
+ </description>
+ </method>
+ </methods>
+ <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">
+ <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>
+ <method name="set_solver_priority">
+ <argument index="0" name="priority" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_solver_priority" qualifiers="const">
+ <return type="int">
+ </return>
<description>
</description>
</method>
@@ -12022,42 +14987,42 @@
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.
</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.
</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" >
- <argument index="0" name="bias" type="real">
+ <method name="set_bias">
+ <argument index="0" name="bias" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_bias" qualifiers="const" >
- <return type="real">
+ <method name="get_bias" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -12066,122 +15031,127 @@
<constants>
</constants>
</class>
-<class name="KinematicBody2D" inherits="PhysicsBody2D" category="Core">
+<class name="KinematicBody" inherits="PhysicsBody" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="move" >
- <return type="Vector2">
+ <method name="move">
+ <return type="Vector3">
</return>
- <argument index="0" name="rel_vec" type="Vector2">
+ <argument index="0" name="rel_vec" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="move_to" >
- <return type="Vector2">
+ <method name="move_to">
+ <return type="Vector3">
</return>
- <argument index="0" name="position" type="Vector2">
+ <argument index="0" name="position" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="can_move_to" >
+ <method name="can_teleport_to">
<return type="bool">
</return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <argument index="1" name="arg1" type="bool">
+ <argument index="0" name="position" type="Vector3">
</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" >
- <return type="Vector2">
+ <method name="get_collision_pos" qualifiers="const">
+ <return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="get_collision_normal" qualifiers="const" >
- <return type="Vector2">
+ <method name="get_collision_normal" qualifiers="const">
+ <return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="get_collider_velocity" qualifiers="const" >
- <return type="Vector2">
+ <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">
+ <description>
+ </description>
+ </method>
+ <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" >
- <argument index="0" name="pixels" type="real">
+ <method name="set_collision_margin">
+ <argument index="0" name="pixels" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_collision_margin" qualifiers="const" >
- <return type="real">
+ <method name="get_collision_margin" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -12190,7 +15160,101 @@
<constants>
</constants>
</class>
-<class name="Label" inherits="Range" category="Core">
+<class name="KinematicBody2D" inherits="PhysicsBody2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="move">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="rel_vec" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="move_to">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="position" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="test_move">
+ <return type="bool">
+ </return>
+ <argument index="0" name="rel_vec" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_travel" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="revert_motion">
+ <description>
+ </description>
+ </method>
+ <method name="is_colliding" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_pos" 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" qualifiers="const">
+ <description>
+ </description>
+ </method>
+ <method name="get_collider_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collider_metadata" qualifiers="const">
+ <description>
+ </description>
+ </method>
+ <method name="set_collision_margin">
+ <argument index="0" name="pixels" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="Label" inherits="Control" category="Core">
<brief_description>
Control that displays formatted text.
</brief_description>
@@ -12198,108 +15262,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="set_uppercase">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Display text in all capitals.
</description>
</method>
- <method name="get_line_height" qualifiers="const" >
+ <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" >
- <argument index="0" name="percent_visible" type="real">
+ <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" >
- <return type="real">
+ <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>
@@ -12329,6 +15450,20 @@
Align the whole text by spreading the rows.
</constant>
</constants>
+ <theme_items>
+ <theme_item name="shadow_offset_x" type="int">
+ </theme_item>
+ <theme_item name="shadow_offset_y" type="int">
+ </theme_item>
+ <theme_item name="shadow_as_outline" type="int">
+ </theme_item>
+ <theme_item name="font_color" type="Color">
+ </theme_item>
+ <theme_item name="font_color_shadow" type="Color">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ </theme_items>
</class>
<class name="LargeTexture" inherits="Texture" category="Core">
<brief_description>
@@ -12336,7 +15471,9 @@
<description>
</description>
<methods>
- <method name="add_piece" >
+ <method name="add_piece">
+ <return type="int">
+ </return>
<argument index="0" name="ofs" type="Vector2">
</argument>
<argument index="1" name="texture" type="Texture">
@@ -12344,23 +15481,39 @@
<description>
</description>
</method>
- <method name="set_size" >
+ <method name="set_piece_offset">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="ofs" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_piece_texture">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="texture" type="Texture">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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">
@@ -12368,7 +15521,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">
@@ -12388,23 +15541,23 @@
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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_parameter" qualifiers="const" >
- <return type="real">
+ <method name="get_parameter" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" 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">
@@ -12412,7 +15565,7 @@
<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">
@@ -12420,42 +15573,78 @@
<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">
+ <argument index="0" name="bake_mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bake_mode" qualifiers="const">
<return type="int">
</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>
+ </description>
+ </method>
+ <method name="set_editor_only">
+ <argument index="0" name="editor_only" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_editor_only" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
<constant name="PARAM_RADIUS" value="2">
@@ -12466,20 +15655,292 @@
</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>
<constant name="PARAM_SHADOW_Z_OFFSET" value="6">
</constant>
- <constant name="COLOR_AMBIENT" value="0">
+ <constant name="COLOR_DIFFUSE" value="0">
+ </constant>
+ <constant name="COLOR_SPECULAR" value="1">
+ </constant>
+ <constant name="BAKE_MODE_DISABLED" value="0">
+ </constant>
+ <constant name="BAKE_MODE_INDIRECT" value="1">
+ </constant>
+ <constant name="BAKE_MODE_INDIRECT_AND_SHADOWS" value="2">
+ </constant>
+ <constant name="BAKE_MODE_FULL" value="3">
+ </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="COLOR_DIFFUSE" value="1">
+ <constant name="MODE_SUB" value="1">
</constant>
- <constant name="COLOR_SPECULAR" value="2">
+ <constant name="MODE_MIX" value="2">
</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.
@@ -12488,96 +15949,110 @@
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" qualifiers="const" >
- <return type="bool">
- </return>
+ <method name="select">
+ <argument index="0" name="from" type="int" default="0">
+ </argument>
+ <argument index="1" name="to" type="int" default="-1">
+ </argument>
<description>
</description>
</method>
@@ -12599,7 +16074,35 @@
</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">
+ </theme_item>
+ <theme_item name="selection_color" type="Color">
+ </theme_item>
+ <theme_item name="cursor_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="read_only" type="StyleBox">
+ </theme_item>
+ <theme_item name="focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="normal" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="LineShape2D" inherits="Shape2D" category="Core">
<brief_description>
@@ -12609,29 +16112,29 @@
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" >
- <argument index="0" name="d" type="real">
+ <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" >
- <return type="real">
+ <method name="get_d" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the line distance from the origin.
@@ -12649,14 +16152,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">
@@ -12665,6 +16234,8 @@
</constant>
<constant name="NOTIFICATION_WM_UNFOCUS_REQUEST" value="8">
</constant>
+ <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="9">
+ </constant>
</constants>
</class>
<class name="MarginContainer" inherits="Container" category="Core">
@@ -12678,6 +16249,10 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="margin" type="int">
+ </theme_item>
+ </theme_items>
</class>
<class name="Marshalls" inherits="Reference" category="Core">
<brief_description>
@@ -12685,7 +16260,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">
@@ -12693,7 +16268,39 @@
<description>
</description>
</method>
- <method name="base64_to_variant" >
+ <method name="base64_to_variant">
+ <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>
@@ -12711,7 +16318,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">
@@ -12720,7 +16327,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">
@@ -12729,60 +16336,44 @@
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" >
+ <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_shade_model" >
- <argument index="0" name="model" type="int">
+ <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_shade_model" qualifiers="const" >
- <return type="int">
+ <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_line_width" >
- <argument index="0" name="width" type="real">
+ <method name="set_depth_draw_mode">
+ <argument index="0" name="mode" type="int">
</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">
+ <method name="get_depth_draw_mode" qualifiers="const">
+ <return type="int">
</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>
</methods>
@@ -12801,40 +16392,20 @@
</constant>
<constant name="FLAG_ONTOP" value="4">
</constant>
- <constant name="FLAG_WIREFRAME" value="5">
- Triangle geometry is drawn as lines if this flag is enabled.
+ <constant name="FLAG_LIGHTMAP_ON_UV2" value="5">
</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 name="FLAG_COLOR_ARRAY_SRGB" value="6">
</constant>
<constant name="FLAG_MAX" value="7">
- Maximum amount of flags
- </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">
+ Maximum amount of flags.
</constant>
- <constant name="HINT_MAX" value="4">
+ <constant name="DEPTH_DRAW_ALWAYS" value="0">
</constant>
- <constant name="SHADE_MODEL_LAMBERT" value="0">
+ <constant name="DEPTH_DRAW_OPAQUE_ONLY" value="1">
</constant>
- <constant name="SHADE_MODEL_LAMBERT_WRAP" value="1">
+ <constant name="DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA" value="2">
</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 name="DEPTH_DRAW_NEVER" value="3">
</constant>
<constant name="BLEND_MODE_MIX" value="0">
Use the regular alpha blending equation (source and dest colors are faded) (default).
@@ -12845,6 +16416,30 @@
<constant name="BLEND_MODE_SUB" value="2">
Use substractive blending equation, often used for some smoke effects or types of glass.
</constant>
+ <constant name="BLEND_MODE_MUL" value="3">
+ </constant>
+ <constant name="BLEND_MODE_PREMULT_ALPHA" value="4">
+ </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">
@@ -12855,52 +16450,58 @@
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" >
- <return type="real">
+ <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="inverse" >
+ <method name="get_scale">
+ <return type="Vector3">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
</argument>
- <argument index="1" name="phi" type="real">
+ <argument index="1" name="phi" type="float">
</argument>
<description>
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">
@@ -12909,8 +16510,8 @@
Return the scaled version of the matrix, by a 3D scale.
</description>
</method>
- <method name="tdotx" >
- <return type="real">
+ <method name="tdotx">
+ <return type="float">
</return>
<argument index="0" name="with" type="Vector3">
</argument>
@@ -12918,8 +16519,8 @@
Transposed dot product with the x axis of the matrix.
</description>
</method>
- <method name="tdoty" >
- <return type="real">
+ <method name="tdoty">
+ <return type="float">
</return>
<argument index="0" name="with" type="Vector3">
</argument>
@@ -12927,8 +16528,8 @@
Transposed dot product with the y axis of the matrix.
</description>
</method>
- <method name="tdotz" >
- <return type="real">
+ <method name="tdotz">
+ <return type="float">
</return>
<argument index="0" name="with" type="Vector3">
</argument>
@@ -12936,14 +16537,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">
@@ -12952,7 +16553,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">
@@ -12961,7 +16562,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">
@@ -12972,20 +16575,24 @@
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="real">
+ <argument index="1" name="phi" type="float">
</argument>
<description>
- Create a matrix from 3 axis vectors.
+ 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>
- Create a matrix from 3 axis vectors.
+ Create a matrix from a quaternion.
</description>
</method>
</methods>
@@ -13008,55 +16615,77 @@
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">
<return type="Matrix32">
</return>
+ <argument index="0" name="v" type="var">
+ </argument>
<description>
</description>
</method>
- <method name="get_origin" >
+ <method name="basis_xform_inv">
+ <return type="Matrix32">
+ </return>
+ <argument index="0" name="v" type="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_origin">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_rotation" >
- <return type="real">
+ <method name="get_rotation">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="interpolate_with" >
+ <method name="get_scale">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="interpolate_with">
<return type="Matrix32">
</return>
<argument index="0" name="m" type="Matrix32">
</argument>
- <argument index="1" name="c" type="real">
+ <argument index="1" name="c" type="float">
</argument>
<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="real">
+ <argument index="0" name="phi" type="float">
</argument>
<description>
</description>
</method>
- <method name="scaled" >
+ <method name="scaled">
<return type="Matrix32">
</return>
<argument index="0" name="scale" type="Vector2">
@@ -13064,7 +16693,7 @@
<description>
</description>
</method>
- <method name="translated" >
+ <method name="translated">
<return type="Matrix32">
</return>
<argument index="0" name="offset" type="Vector2">
@@ -13072,7 +16701,7 @@
<description>
</description>
</method>
- <method name="xform" >
+ <method name="xform">
<return type="Matrix32">
</return>
<argument index="0" name="v" type="var">
@@ -13080,7 +16709,7 @@
<description>
</description>
</method>
- <method name="xform_inv" >
+ <method name="xform_inv">
<return type="Matrix32">
</return>
<argument index="0" name="v" type="var">
@@ -13088,7 +16717,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">
@@ -13098,13 +16739,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="real">
+ <member name="x" type="Vector2">
</member>
- <member name="y" type="real">
+ <member name="y" type="Vector2">
</member>
- <member name="o" type="real">
+ <member name="o" type="Vector2">
</member>
</members>
<constants>
@@ -13118,8 +16767,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.
@@ -13134,6 +16783,30 @@
</signals>
<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="Mesh" inherits="Resource" category="Core">
<brief_description>
@@ -13143,19 +16816,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">
@@ -13163,23 +16836,23 @@
<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">
@@ -13189,24 +16862,26 @@
<argument index="3" name="arg3" type="bool" default="Array()">
</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">
@@ -13215,7 +16890,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">
@@ -13224,7 +16899,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">
@@ -13233,7 +16908,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">
@@ -13242,7 +16917,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">
@@ -13251,7 +16926,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">
@@ -13260,7 +16935,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">
@@ -13268,7 +16943,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">
@@ -13276,7 +16951,23 @@
<description>
</description>
</method>
- <method name="center_geometry" >
+ <method name="center_geometry">
+ <description>
+ </description>
+ </method>
+ <method name="regen_normalmaps">
+ <description>
+ </description>
+ </method>
+ <method name="set_custom_aabb">
+ <argument index="0" name="aabb" type="AABB">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_custom_aabb" qualifiers="const">
+ <return type="AABB">
+ </return>
<description>
</description>
</method>
@@ -13304,6 +16995,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.
@@ -13330,6 +17022,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.
@@ -13369,11 +17062,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">
@@ -13383,7 +17076,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">
@@ -13391,31 +17084,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">
@@ -13423,7 +17116,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">
@@ -13431,7 +17124,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">
@@ -13439,7 +17132,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">
@@ -13447,7 +17140,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">
@@ -13455,7 +17148,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">
@@ -13463,7 +17156,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">
@@ -13471,7 +17164,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">
@@ -13479,7 +17172,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">
@@ -13487,7 +17180,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">
@@ -13495,7 +17188,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">
@@ -13503,7 +17196,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">
@@ -13511,7 +17204,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">
@@ -13519,7 +17212,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">
@@ -13527,7 +17220,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">
@@ -13535,7 +17228,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">
@@ -13543,7 +17236,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">
@@ -13551,13 +17244,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">
@@ -13565,7 +17258,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">
@@ -13573,7 +17266,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">
@@ -13583,7 +17276,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">
@@ -13591,7 +17284,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">
@@ -13599,13 +17292,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">
@@ -13615,7 +17308,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">
@@ -13625,7 +17318,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">
@@ -13633,13 +17326,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">
@@ -13647,13 +17340,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>
@@ -13671,33 +17364,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="get_aabb" qualifiers="const" >
+ <method name="set_skeleton_path">
+ <argument index="0" name="skeleton_path" type="NodePath">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_skeleton_path">
+ <return type="NodePath">
+ </return>
+ <description>
+ </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" >
+ <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>
@@ -13713,14 +17418,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">
@@ -13729,7 +17434,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">
@@ -13738,7 +17443,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">
@@ -13746,7 +17451,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">
@@ -13755,7 +17460,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">
@@ -13764,7 +17469,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">
@@ -13772,26 +17477,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>
@@ -13807,38 +17512,40 @@
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" >
+ <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" >
+ <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" >
+ <method name="set_instance_transform">
<argument index="0" name="arg0" type="int">
</argument>
<argument index="1" name="arg1" type="Transform">
@@ -13847,7 +17554,7 @@
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">
@@ -13856,7 +17563,7 @@
Return the transform of a specific instance.
</description>
</method>
- <method name="set_instance_color" >
+ <method name="set_instance_color">
<argument index="0" name="arg0" type="int">
</argument>
<argument index="1" name="arg1" type="Color">
@@ -13865,7 +17572,7 @@
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">
@@ -13874,21 +17581,21 @@
Get the color of a specific instance.
</description>
</method>
- <method name="set_aabb" >
+ <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" >
+ <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>
@@ -13905,14 +17612,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>
@@ -13929,17 +17636,387 @@
<description>
</description>
<methods>
- <method name="lock" >
+ <method name="lock">
+ <description>
+ </description>
+ </method>
+ <method name="try_lock">
+ <return type="Error">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="unlock">
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="Navigation" inherits="Spatial" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="navmesh_create">
+ <return type="int">
+ </return>
+ <argument index="0" name="mesh" type="NavigationMesh">
+ </argument>
+ <argument index="1" name="xform" type="Transform">
+ </argument>
+ <argument index="2" name="owner" type="Object" default="NULL">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="navmesh_set_transform">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="xform" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="navmesh_remove">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_simple_path">
+ <return type="Vector3Array">
+ </return>
+ <argument index="0" name="start" type="Vector3">
+ </argument>
+ <argument index="1" name="end" type="Vector3">
+ </argument>
+ <argument index="2" name="optimize" type="bool" default="true">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="to_point" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_closest_point_normal">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="to_point" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="Vector3">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <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">
+ <argument index="0" name="vertices" type="Vector3Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_vertices" qualifiers="const">
+ <return type="Vector3Array">
+ </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>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="NavigationMeshInstance" inherits="Spatial" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_navigation_mesh">
+ <argument index="0" name="navmesh" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_navigation_mesh" 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>
+ </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="try_lock" >
+ <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="unlock" >
+ <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>
</description>
</method>
@@ -13953,169 +18030,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" >
- <argument index="0" name="from" type="real">
+ <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>
@@ -14131,123 +18208,115 @@
</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_scene" qualifiers="virtual" >
+ <method name="_enter_tree" qualifiers="virtual">
<description>
- Called when entered the scene.
</description>
</method>
- <method name="_exit_scene" qualifiers="virtual" >
+ <method name="_exit_tree" qualifiers="virtual">
<description>
- Called when being removed from the scene.
</description>
</method>
- <method name="_fixed_process" qualifiers="virtual" >
- <argument index="0" name="delta" type="real">
+ <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" >
- <argument index="0" name="delta" type="real">
+ <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>
<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" >
+ <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">
@@ -14255,23 +18324,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. "path" 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.[br] Examples ofa paths are: get_node("Sword") , get_node("../Swamp/Alligator") , get_node("/MyGame"). [br]Note: fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_scene]).
- </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">
@@ -14279,7 +18375,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">
@@ -14287,14 +18383,13 @@
<description>
</description>
</method>
- <method name="is_inside_scene" qualifiers="const" >
+ <method name="is_inside_tree" qualifiers="const">
<return type="bool">
</return>
<description>
- Return wether the node is inside a scene tree (a tree where the topmost node is a [RootNode])
</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">
@@ -14303,7 +18398,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">
@@ -14312,14 +18407,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">
@@ -14328,23 +18423,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>
<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">
@@ -14352,7 +18447,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">
@@ -14361,177 +18456,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="raise" >
+ <method name="get_groups" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </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" >
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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_pause_mode" >
+ <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">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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_scene" qualifiers="const" >
- <return type="SceneMainLoop">
+ <method name="get_tree" qualifiers="const">
+ <return type="SceneTree">
</return>
<description>
- Get the current SceneMainLoop. Only returned if the node is inside the scene, else returns null.
</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">
@@ -14540,34 +18653,48 @@
Replace a node in a scene by a given one. Subscriptions that pass through this node will be lost.
</description>
</method>
- <method name="queue_free" >
+ <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">
<description>
</description>
</method>
</methods>
<signals>
- <signal name="enter_scene">
+ <signal name="renamed">
<description>
- Emitted when the node enters the scene.
+ Emitted when the node is renamed.
</description>
</signal>
- <signal name="renamed">
+ <signal name="enter_tree">
<description>
- Emitted when the node is renamed.
</description>
</signal>
- <signal name="exit_scene">
+ <signal name="exit_tree">
<description>
- Emitted when the node exits the scene.
</description>
</signal>
</signals>
<constants>
- <constant name="NOTIFICATION_ENTER_SCENE" value="10">
- Notification received when the node enters the Scene Tree and gains access to the [RootNode]. Note that children nodes will not have received the notification at that time yet.
+ <constant name="NOTIFICATION_ENTER_TREE" value="10">
</constant>
- <constant name="NOTIFICATION_EXIT_SCENE" value="11">
- Notification received when the node exits the Scene Tree and loses access to the [RootNode]. Note that parent nodes will not have received the notification at that time yet.
+ <constant name="NOTIFICATION_EXIT_TREE" value="11">
</constant>
<constant name="NOTIFICATION_MOVED_IN_PARENT" value="12">
</constant>
@@ -14601,78 +18728,168 @@
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" >
- <argument index="0" name="rot" type="real">
+ <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" >
- <return type="real">
+ <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="get_global_pos" qualifiers="const" >
+ <method name="rotate">
+ <argument index="0" name="radians" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="move_local_x">
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <argument index="1" name="scaled" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="move_local_y">
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <argument index="1" name="scaled" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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_transform" >
+ <method name="set_transform">
<argument index="0" name="xform" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="set_global_transform" >
+ <method name="set_global_transform">
<argument index="0" name="xform" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="edit_set_pivot" >
+ <method name="look_at">
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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="arg0" type="Vector2">
</argument>
<description>
</description>
</method>
+ <method name="get_relative_transform" qualifiers="const">
+ <return type="Matrix32">
+ </return>
+ <argument index="0" name="arg0" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -14682,11 +18899,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">
@@ -14695,21 +18911,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">
@@ -14718,28 +18934,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>
@@ -14755,32 +18973,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">
@@ -14793,7 +19011,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">
@@ -14802,7 +19020,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">
@@ -14811,7 +19029,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">
@@ -14820,7 +19038,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">
@@ -14829,55 +19047,202 @@
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_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="has_touchscreen_ui_hint" qualifiers="const" >
+ <method name="set_target_fps">
+ <argument index="0" name="target_fps" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_target_fps" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_time_scale">
+ <argument index="0" name="time_scale" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_time_scale">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
@@ -14886,11 +19251,13 @@
</argument>
<argument index="2" name="blocking" type="bool">
</argument>
+ <argument index="3" name="output" type="Array" default="Array()">
+ </argument>
<description>
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">
@@ -14899,7 +19266,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">
@@ -14907,7 +19274,13 @@
<description>
</description>
</method>
- <method name="get_environment" qualifiers="const" >
+ <method name="get_process_ID" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_environment" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="environment" type="String">
@@ -14916,7 +19289,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">
@@ -14925,204 +19298,295 @@
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>
+ </description>
+ </method>
+ <method name="get_time_zone_info" qualifiers="const">
<return type="Dictionary">
</return>
<description>
- Return the current time.
</description>
</method>
- <method name="get_unix_time" qualifiers="const" >
+ <method name="get_unix_time" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_icon" >
+ <method name="get_system_time_msec" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_icon">
<argument index="0" name="arg0" 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="dump_memory_to_file" >
+ <method name="is_debug_build" qualifiers="const">
+ <return type="bool">
+ </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" >
+ <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_unique_ID" qualifiers="const" >
+ <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_frames_per_second" qualifiers="const" >
- <return type="real">
+ <method name="get_unique_ID" qualifiers="const">
+ <return type="String">
</return>
<description>
</description>
</method>
- <method name="print_all_textures_by_size" >
+ <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">
<description>
</description>
</method>
- <method name="native_video_play" >
+ <method name="print_resources_by_type">
+ <argument index="0" name="arg0" type="StringArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="native_video_play">
<return type="int">
</return>
<argument index="0" name="arg0" type="String">
</argument>
+ <argument index="1" name="arg1" type="float">
+ </argument>
+ <argument index="2" name="arg2" type="String">
+ </argument>
+ <argument index="3" name="arg3" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="native_video_is_playing">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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="native_video_is_playing" >
+ <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_stop" >
+ <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="native_video_pause" >
+ <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>
@@ -15166,6 +19630,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">
@@ -15174,34 +19668,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="_notification" qualifiers="virtual" >
+ <method name="_init" qualifiers="virtual">
+ <description>
+ </description>
+ </method>
+ <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">
@@ -15210,14 +19708,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">
@@ -15226,7 +19728,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">
@@ -15235,21 +19737,27 @@
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">
@@ -15258,28 +19766,28 @@
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">
@@ -15288,14 +19796,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">
@@ -15304,14 +19812,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()">
@@ -15320,7 +19828,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">
@@ -15337,7 +19853,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">
@@ -15364,7 +19880,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">
@@ -15381,7 +19897,7 @@
Create and store a function in the object. The call will take place on idle time.
</description>
</method>
- <method name="callv" >
+ <method name="callv">
<argument index="0" name="method" type="String">
</argument>
<argument index="1" name="arg_array" type="Array">
@@ -15389,7 +19905,7 @@
<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">
@@ -15397,14 +19913,16 @@
<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="connect">
+ <return type="int">
+ </return>
<argument index="0" name="signal" type="String">
</argument>
<argument index="1" name="target" type="Object">
@@ -15416,11 +19934,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">
@@ -15431,7 +19948,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">
@@ -15444,48 +19961,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" >
- <argument index="0" name="arg0" type="bool">
- </argument>
+ <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">
@@ -15494,6 +20011,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">
@@ -15519,6 +20042,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.
@@ -15539,7 +20114,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">
@@ -15548,7 +20123,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">
@@ -15559,7 +20134,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">
@@ -15568,7 +20143,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">
@@ -15577,7 +20152,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">
@@ -15585,7 +20160,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">
@@ -15594,7 +20169,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">
@@ -15602,7 +20177,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">
@@ -15611,7 +20186,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">
@@ -15620,7 +20195,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">
@@ -15629,13 +20204,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">
@@ -15643,48 +20218,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" >
+ <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" >
+ <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>
@@ -15702,6 +20277,72 @@
</signals>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="hseparation" type="int">
+ </theme_item>
+ <theme_item name="arrow_margin" 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="arrow" 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="PCKPacker" inherits="Reference" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="pck_start">
+ <return type="int">
+ </return>
+ <argument index="0" name="pck_name" type="String">
+ </argument>
+ <argument index="1" name="alignment" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_file">
+ <return type="int">
+ </return>
+ <argument index="0" name="pck_path" type="String">
+ </argument>
+ <argument index="1" name="source_path" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="flush">
+ <return type="int">
+ </return>
+ <argument index="0" name="arg0" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
</class>
<class name="PHashTranslation" inherits="Translation" category="Core">
<brief_description>
@@ -15711,7 +20352,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>
@@ -15727,15 +20368,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>
@@ -15751,7 +20392,7 @@
<description>
</description>
<methods>
- <method name="size" qualifiers="const" >
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -15765,28 +20406,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>
@@ -15804,18 +20444,44 @@
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="Variant">
+ <argument index="0" name="var" type="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -15828,7 +20494,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>
@@ -15839,18 +20505,89 @@
<constants>
</constants>
</class>
+<class name="PacketPeerUDP" inherits="PacketPeer" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="listen">
+ <return type="Error">
+ </return>
+ <argument index="0" name="port" type="int">
+ </argument>
+ <argument index="1" name="recv_buf_size" type="int" default="65536">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="close">
+ <description>
+ </description>
+ </method>
+ <method name="wait">
+ <return type="Error">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_listening" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_packet_ip" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_packet_address" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_packet_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_send_address">
+ <return type="int">
+ </return>
+ <argument index="0" name="host" type="String">
+ </argument>
+ <argument index="1" name="port" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="Panel" inherits="Control" category="Core">
<brief_description>
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>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="panelf" type="StyleBox">
+ </theme_item>
+ <theme_item name="panel" type="StyleBox">
+ </theme_item>
+ <theme_item name="panelnc" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="PanelContainer" inherits="Container" category="Core">
<brief_description>
@@ -15863,6 +20600,10 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="panel" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="ParallaxBackground" inherits="CanvasLayer" category="Core">
<brief_description>
@@ -15870,66 +20611,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="arg0" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_ignore_camera_zoom">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -15940,25 +20693,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>
@@ -15974,73 +20727,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" >
- <argument index="0" name="radius" type="real">
+ <method name="set_radius">
+ <argument index="0" name="radius" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
+ <method name="get_radius" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_disable_radius" >
- <argument index="0" name="radius" type="real">
+ <method name="set_disable_radius">
+ <argument index="0" name="radius" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_disable_radius" qualifiers="const" >
- <return type="real">
+ <method name="get_disable_radius" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_gravity" >
- <argument index="0" name="gravity" type="real">
+ <method name="set_gravity">
+ <argument index="0" name="gravity" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_gravity" qualifiers="const" >
- <return type="real">
+ <method name="get_gravity" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_absorption" >
- <argument index="0" name="absorption" type="real">
+ <method name="set_absorption">
+ <argument index="0" name="absorption" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_absorption" qualifiers="const" >
- <return type="real">
+ <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>
@@ -16050,28 +20803,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
@@ -16080,111 +20811,111 @@
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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
Set a specific variable for the particle system (see VAR_* enum).
</description>
</method>
- <method name="get_variable" qualifiers="const" >
- <return type="real">
+ <method name="get_variable" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="variable" type="int">
</argument>
@@ -16192,17 +20923,17 @@
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="real">
+ <argument index="1" name="randomness" type="float">
</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">
+ <method name="get_randomness" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="int">
</argument>
@@ -16210,25 +20941,25 @@
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="real">
+ <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" >
- <return type="real">
+ <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">
@@ -16237,7 +20968,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">
@@ -16246,63 +20977,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="real">
+ <method name="set_emit_timeout">
+ <argument index="0" name="arg0" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_emit_timeout" qualifiers="const" >
- <return type="real">
+ <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>
@@ -16346,183 +21077,231 @@
<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" >
- <argument index="0" name="lifetime" type="real">
+ <method name="set_lifetime">
+ <argument index="0" name="lifetime" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_lifetime" qualifiers="const" >
- <return type="real">
+ <method name="get_lifetime" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_time_scale" >
- <argument index="0" name="time_scale" type="real">
+ <method name="set_time_scale">
+ <argument index="0" name="time_scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_time_scale" qualifiers="const" >
- <return type="real">
+ <method name="get_time_scale" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_pre_process_time" >
- <argument index="0" name="time" type="real">
+ <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" >
- <return type="real">
+ <method name="get_pre_process_time" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_emit_timeout" >
- <argument index="0" name="value" type="real">
+ <method name="set_emit_timeout">
+ <argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_emit_timeout" qualifiers="const" >
- <return type="real">
+ <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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
+ <method name="get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="param" type="int">
</argument>
<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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_randomness" qualifiers="const" >
- <return type="real">
+ <method name="get_randomness" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="param" type="int">
</argument>
<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="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">
+ <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_emission_half_extents" >
+ <method name="set_h_frames">
+ <argument index="0" name="enable" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_h_frames" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_v_frames">
+ <argument index="0" name="enable" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_v_frames" qualifiers="const">
+ <return type="int">
+ </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" >
+ <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">
@@ -16530,7 +21309,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">
@@ -16538,71 +21317,71 @@
<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="real">
+ <argument index="1" name="pos" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_color_phase_pos" qualifiers="const" >
- <return type="real">
+ <method name="get_color_phase_pos" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="phase" type="int">
</argument>
<description>
</description>
</method>
- <method name="pre_process" >
- <argument index="0" name="time" type="real">
+ <method name="pre_process">
+ <argument index="0" name="time" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_use_local_space" >
+ <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" >
- <argument index="0" name="amount" type="real">
+ <method name="set_explosiveness">
+ <argument index="0" name="amount" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_explosiveness" qualifiers="const" >
- <return type="real">
+ <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>
@@ -16618,6 +21397,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">
@@ -16626,34 +21407,108 @@
</constant>
<constant name="PARAM_TANGENTIAL_ACCEL" value="8">
</constant>
- <constant name="PARAM_INITIAL_SIZE" value="10">
+ <constant name="PARAM_DAMPING" value="9">
+ </constant>
+ <constant name="PARAM_INITIAL_ANGLE" value="10">
</constant>
- <constant name="PARAM_FINAL_SIZE" value="11">
+ <constant name="PARAM_INITIAL_SIZE" value="11">
</constant>
- <constant name="PARAM_HUE_VARIATION" value="12">
+ <constant name="PARAM_FINAL_SIZE" value="12">
</constant>
- <constant name="PARAM_MAX" value="13">
+ <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>
@@ -16662,20 +21517,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>
@@ -16684,106 +21543,244 @@
</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" >
- <argument index="0" name="offset" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="h_offset" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="v_offset" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="unit_offset" type="real">
+ <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" >
- <return type="real">
+ <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">
+ <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">
+ <return type="float">
+ </return>
+ <description>
+ Returns the distance along the path in pixels.
+ </description>
+ </method>
+ <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">
+ <return type="float">
+ </return>
+ <description>
+ Returns the horizontal displacement this node has from its parent [Path2D].
+ </description>
+ </method>
+ <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">
+ <return type="float">
+ </return>
+ <description>
+ Returns the vertical displacement this node has from its parent [Path2D].
+ </description>
+ </method>
+ <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">
+ <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">
+ <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">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether this node rotates to follow the path.
+ </description>
+ </method>
+ <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">
+ <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">
+ <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">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether this node wraps its offsets around, or truncates them to the path ends.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="PathRemap" inherits="Object" category="Core">
<brief_description>
Singleton containing the list of remapped resources.
@@ -16792,7 +21789,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">
@@ -16803,7 +21800,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">
@@ -16812,7 +21809,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">
@@ -16821,14 +21818,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>
@@ -16843,8 +21840,8 @@
<description>
</description>
<methods>
- <method name="get_monitor" qualifiers="const" >
- <return type="real">
+ <method name="get_monitor" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="monitor" type="int">
</argument>
@@ -16895,7 +21892,19 @@
</constant>
<constant name="RENDER_VERTEX_MEM_USED" value="19">
</constant>
- <constant name="MONITOR_MAX" value="21">
+ <constant name="PHYSICS_2D_ACTIVE_OBJECTS" value="21">
+ </constant>
+ <constant name="PHYSICS_2D_COLLISION_PAIRS" value="22">
+ </constant>
+ <constant name="PHYSICS_2D_ISLAND_COUNT" value="23">
+ </constant>
+ <constant name="PHYSICS_3D_ACTIVE_OBJECTS" value="24">
+ </constant>
+ <constant name="PHYSICS_3D_COLLISION_PAIRS" value="25">
+ </constant>
+ <constant name="PHYSICS_3D_ISLAND_COUNT" value="26">
+ </constant>
+ <constant name="MONITOR_MAX" value="27">
</constant>
</constants>
</class>
@@ -16907,98 +21916,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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="velocity" type="real">
+ <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" >
- <return type="real">
+ <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">
@@ -17007,7 +22021,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">
@@ -17015,7 +22029,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">
@@ -17024,7 +22038,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">
@@ -17033,7 +22047,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">
@@ -17042,7 +22056,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">
@@ -17051,7 +22065,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">
@@ -17060,7 +22074,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">
@@ -17069,7 +22083,13 @@
Return the collider shape index.
</description>
</method>
- <method name="get_contact_collider_velocity_at_pos" qualifiers="const" >
+ <method name="get_contact_collider_shape_metadata" qualifiers="const">
+ <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">
@@ -17078,19 +22098,19 @@
Return the linear velocity vector at contact point of the collider.
</description>
</method>
- <method name="get_step" qualifiers="const" >
- <return type="real">
+ <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>
@@ -17119,58 +22139,98 @@
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" >
- <argument index="0" name="from" type="Vector2">
+ <method name="intersect_point">
+ <return type="Array">
+ </return>
+ <argument index="0" name="point" type="Vector2">
</argument>
- <argument index="1" name="to" type="Vector2">
+ <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="umask" type="int" default="0">
+ <argument index="3" name="layer_mask" type="int" default="2147483647">
+ </argument>
+ <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 null is returned instead of a [Dictionary].
</description>
</method>
- <method name="intersect_shape" >
- <argument index="0" name="shape" type="RID">
+ <method name="intersect_ray">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="from" type="Vector2">
</argument>
- <argument index="1" name="xform" type="Matrix32">
+ <argument index="1" name="to" type="Vector2">
</argument>
- <argument index="2" name="result_max" type="int">
+ <argument index="2" name="exclude" type="Array" default="Array()">
</argument>
- <argument index="3" name="exclude" type="Array" default="Array()">
+ <argument index="3" name="layer_mask" type="int" default="2147483647">
</argument>
- <argument index="4" name="umask" type="int" default="0">
+ <argument index="4" name="type_mask" type="int" default="15">
</argument>
<description>
- Intersect a given shape (RID or [Shape2D]) against the space, the intersected shapes are returned in a special result object.
+ 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="cast_motion" >
- <argument index="0" name="shape" type="RID">
+ <method name="intersect_shape">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="Physics2DShapeQueryParameters">
</argument>
- <argument index="1" name="xform" type="Matrix32">
+ <argument index="1" name="max_results" type="int" default="32">
</argument>
- <argument index="2" name="motion" type="int">
+ <description>
+ 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">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="Physics2DShapeQueryParameters">
</argument>
- <argument index="3" name="exclude" type="Array" default="Array()">
+ <description>
+ </description>
+ </method>
+ <method name="collide_shape">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="Physics2DShapeQueryParameters">
</argument>
- <argument index="4" name="umask" type="int" default="0">
+ <argument index="1" name="max_results" type="int" default="32">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_rest_info">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="shape" type="Physics2DShapeQueryParameters">
</argument>
<description>
</description>
</method>
</methods>
<constants>
+ <constant name="TYPE_MASK_STATIC_BODY" value="1">
+ </constant>
+ <constant name="TYPE_MASK_KINEMATIC_BODY" value="2">
+ </constant>
+ <constant name="TYPE_MASK_RIGID_BODY" value="4">
+ </constant>
+ <constant name="TYPE_MASK_CHARACTER_BODY" value="8">
+ </constant>
+ <constant name="TYPE_MASK_AREA" value="16">
+ </constant>
+ <constant name="TYPE_MASK_COLLISION" value="15">
+ </constant>
</constants>
</class>
<class name="Physics2DServer" inherits="Object" category="Core">
@@ -17181,7 +22241,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">
@@ -17189,7 +22249,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">
@@ -17197,7 +22257,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">
@@ -17205,19 +22265,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">
@@ -17225,7 +22285,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">
@@ -17233,18 +22293,18 @@
<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">
</argument>
- <argument index="2" name="value" type="real">
+ <argument index="2" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="space_get_param" qualifiers="const" >
- <return type="real">
+ <method name="space_get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="space" type="RID">
</argument>
@@ -17253,7 +22313,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">
@@ -17261,13 +22321,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">
@@ -17275,7 +22335,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">
@@ -17283,7 +22343,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">
@@ -17291,7 +22351,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">
@@ -17299,27 +22359,27 @@
<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="int">
+ <argument index="1" name="shape" type="RID">
</argument>
- <argument index="2" name="transform" type="RID" default="1,0, 0,1, 0,0">
+ <argument index="2" name="transform" type="Matrix32" default="1,0, 0,1, 0,0">
</argument>
<description>
</description>
</method>
- <method name="area_set_shape" qualifiers="const" >
- <return type="RID">
- </return>
+ <method name="area_set_shape">
<argument index="0" name="area" 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="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">
@@ -17329,7 +22389,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">
@@ -17337,7 +22397,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">
@@ -17347,7 +22407,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">
@@ -17357,7 +22417,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">
@@ -17365,13 +22425,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">
@@ -17381,7 +22457,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">
@@ -17389,7 +22465,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">
@@ -17397,7 +22473,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">
@@ -17405,7 +22481,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">
@@ -17413,7 +22489,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">
@@ -17421,7 +22497,7 @@
<description>
</description>
</method>
- <method name="area_set_monitor_callback" >
+ <method name="area_set_monitor_callback">
<argument index="0" name="receiver" type="RID">
</argument>
<argument index="1" name="method" type="Object">
@@ -17431,7 +22507,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">
@@ -17441,7 +22517,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">
@@ -17449,7 +22525,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">
@@ -17457,7 +22533,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">
@@ -17465,7 +22541,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">
@@ -17473,7 +22549,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">
@@ -17483,7 +22559,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">
@@ -17493,7 +22569,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">
@@ -17503,7 +22579,17 @@
<description>
</description>
</method>
- <method name="body_get_shape_count" qualifiers="const" >
+ <method name="body_set_shape_metadata">
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="metadata" type="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_shape_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -17511,7 +22597,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">
@@ -17521,7 +22607,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">
@@ -17531,7 +22617,15 @@
<description>
</description>
</method>
- <method name="body_remove_shape" >
+ <method name="body_get_shape_metadata" qualifiers="const">
+ <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">
@@ -17539,13 +22633,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">
@@ -17555,7 +22649,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">
@@ -17565,7 +22659,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">
@@ -17573,7 +22667,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">
@@ -17581,7 +22675,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">
@@ -17589,7 +22683,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">
@@ -17597,18 +22691,50 @@
<description>
</description>
</method>
- <method name="body_set_param" >
+ <method name="body_set_layer_mask">
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_layer_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_set_collision_mask">
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_collision_mask" qualifiers="const">
+ <return type="int">
+ </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 index="2" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="body_get_param" qualifiers="const" >
- <return type="real">
+ <method name="body_get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="body" type="RID">
</argument>
@@ -17617,7 +22743,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">
@@ -17627,7 +22753,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">
@@ -17635,7 +22761,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">
@@ -17645,7 +22771,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">
@@ -17653,7 +22779,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">
@@ -17661,7 +22787,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">
@@ -17669,7 +22795,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">
@@ -17677,7 +22803,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">
@@ -17685,7 +22811,39 @@
<description>
</description>
</method>
- <method name="body_set_omit_force_integration" >
+ <method name="body_set_one_way_collision_direction">
+ <argument index="0" name="normal" type="RID">
+ </argument>
+ <argument index="1" name="arg1" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_one_way_collision_direction" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="arg0" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_set_one_way_collision_max_depth">
+ <argument index="0" name="normal" type="RID">
+ </argument>
+ <argument index="1" name="arg1" 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="arg0" 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">
@@ -17693,7 +22851,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">
@@ -17701,7 +22859,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">
@@ -17713,18 +22871,32 @@
<description>
</description>
</method>
- <method name="joint_set_param" >
+ <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">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="param" type="int">
</argument>
- <argument index="2" name="value" type="real">
+ <argument index="2" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="joint_get_param" qualifiers="const" >
- <return type="real">
+ <method name="joint_get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="joint" type="RID">
</argument>
@@ -17733,7 +22905,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">
@@ -17745,7 +22917,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">
@@ -17761,7 +22933,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">
@@ -17775,18 +22947,18 @@
<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">
</argument>
- <argument index="2" name="value" type="real" default="RID()">
+ <argument index="2" name="value" type="float" default="RID()">
</argument>
<description>
</description>
</method>
- <method name="damped_string_joint_get_param" qualifiers="const" >
- <return type="real">
+ <method name="damped_string_joint_get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="joint" type="RID">
</argument>
@@ -17795,7 +22967,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">
@@ -17803,18 +22975,26 @@
<description>
</description>
</method>
- <method name="free" >
+ <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">
+ <return type="int">
+ </return>
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
<constant name="SHAPE_LINE" value="0">
@@ -17839,11 +23019,15 @@
</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_GRAVITY_POINT_ATTENUATION" value="4">
</constant>
- <constant name="AREA_PARAM_DENSITY" value="4">
+ <constant name="AREA_PARAM_LINEAR_DAMP" value="5">
</constant>
- <constant name="AREA_PARAM_PRIORITY" value="5">
+ <constant name="AREA_PARAM_ANGULAR_DAMP" value="6">
+ </constant>
+ <constant name="AREA_PARAM_PRIORITY" value="7">
</constant>
<constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1">
</constant>
@@ -17865,7 +23049,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>
@@ -17899,6 +23089,12 @@
</constant>
<constant name="AREA_BODY_REMOVED" value="1">
</constant>
+ <constant name="INFO_ACTIVE_OBJECTS" value="0">
+ </constant>
+ <constant name="INFO_COLLISION_PAIRS" value="1">
+ </constant>
+ <constant name="INFO_ISLAND_COUNT" value="2">
+ </constant>
</constants>
</class>
<class name="Physics2DServerSW" inherits="Physics2DServer" category="Core">
@@ -17911,19 +23107,119 @@
<constants>
</constants>
</class>
+<class name="Physics2DShapeQueryParameters" inherits="Reference" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_shape">
+ <argument index="0" name="shape" type="Shape2D">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_shape_rid">
+ <argument index="0" name="shape" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shape_rid" qualifiers="const">
+ <return type="RID">
+ </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_motion">
+ <argument index="0" name="motion" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_motion" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_margin">
+ <argument index="0" name="margin" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_layer_mask">
+ <argument index="0" name="layer_mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_layer_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_exclude">
+ <argument index="0" name="exclude" type="Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_exclude" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="Physics2DShapeQueryResult" inherits="Reference" category="Core">
<brief_description>
</brief_description>
<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">
@@ -17931,7 +23227,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">
@@ -17939,7 +23235,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">
@@ -17947,7 +23243,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">
@@ -17959,6 +23255,70 @@
<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.
@@ -17967,6 +23327,30 @@
PhysicsBody is an abstract base class for implementing a physics body. All PhysicsBody types inherit from it.
</description>
<methods>
+ <method name="set_layer_mask">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_layer_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="add_collision_exception_with">
+ <argument index="0" name="body" type="PhysicsBody">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_collision_exception_with">
+ <argument index="0" name="body" type="PhysicsBody">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -17977,6 +23361,98 @@
<description>
</description>
<methods>
+ <method name="set_layer_mask">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_layer_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_collision_mask">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </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>
+ </description>
+ </method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ </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>
+ </description>
+ </method>
+ <method name="get_layer_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_one_way_collision_direction">
+ <argument index="0" name="dir" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_one_way_collision_direction" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_one_way_collision_max_depth">
+ <argument index="0" name="depth" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_one_way_collision_max_depth" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="add_collision_exception_with">
+ <argument index="0" name="body" type="PhysicsBody2D">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_collision_exception_with">
+ <argument index="0" name="body" type="PhysicsBody2D">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -17987,67 +23463,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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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">
@@ -18055,25 +23537,33 @@
<description>
</description>
</method>
- <method name="set_sleep_state" >
+ <method name="apply_impulse">
+ <argument index="0" name="pos" type="Vector3">
+ </argument>
+ <argument index="1" name="j" type="Vector3">
+ </argument>
+ <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" >
+ <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">
@@ -18081,7 +23571,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">
@@ -18089,7 +23579,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">
@@ -18097,7 +23587,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">
@@ -18105,7 +23595,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">
@@ -18113,7 +23603,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">
@@ -18121,7 +23611,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">
@@ -18129,7 +23619,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">
@@ -18137,7 +23627,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">
@@ -18145,17 +23635,17 @@
<description>
</description>
</method>
- <method name="get_step" qualifiers="const" >
- <return type="real">
+ <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>
@@ -18181,34 +23671,74 @@
<description>
</description>
<methods>
- <method name="intersect_ray" >
+ <method name="intersect_ray">
+ <return type="Dictionary">
+ </return>
<argument index="0" name="from" type="Vector3">
</argument>
<argument index="1" name="to" type="Vector3">
</argument>
<argument index="2" name="exclude" type="Array" default="Array()">
</argument>
- <argument index="3" name="umask" type="int" default="0">
+ <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_shape" >
- <argument index="0" name="shape" type="RID">
+ <method name="intersect_shape">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters">
</argument>
- <argument index="1" name="xform" type="Transform">
+ <argument index="1" name="max_results" type="int" default="32">
</argument>
- <argument index="2" name="result_max" type="int">
+ <description>
+ </description>
+ </method>
+ <method name="cast_motion">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters">
</argument>
- <argument index="3" name="exclude" type="Array" default="Array()">
+ <argument index="1" name="motion" type="Vector3">
</argument>
- <argument index="4" name="umask" type="int" default="0">
+ <description>
+ </description>
+ </method>
+ <method name="collide_shape">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters">
+ </argument>
+ <argument index="1" name="max_results" type="int" default="32">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_rest_info">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters">
</argument>
<description>
</description>
</method>
</methods>
<constants>
+ <constant name="TYPE_MASK_STATIC_BODY" value="1">
+ </constant>
+ <constant name="TYPE_MASK_KINEMATIC_BODY" value="2">
+ </constant>
+ <constant name="TYPE_MASK_RIGID_BODY" value="4">
+ </constant>
+ <constant name="TYPE_MASK_CHARACTER_BODY" value="8">
+ </constant>
+ <constant name="TYPE_MASK_AREA" value="16">
+ </constant>
+ <constant name="TYPE_MASK_COLLISION" value="15">
+ </constant>
</constants>
</class>
<class name="PhysicsServer" inherits="Object" category="Core">
@@ -18217,7 +23747,7 @@
<description>
</description>
<methods>
- <method name="shape_create" >
+ <method name="shape_create">
<return type="RID">
</return>
<argument index="0" name="type" type="int">
@@ -18225,7 +23755,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">
@@ -18233,7 +23763,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">
@@ -18241,19 +23771,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">
@@ -18261,7 +23791,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">
@@ -18269,18 +23799,18 @@
<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">
</argument>
- <argument index="2" name="value" type="real">
+ <argument index="2" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="space_get_param" qualifiers="const" >
- <return type="real">
+ <method name="space_get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="space" type="RID">
</argument>
@@ -18289,7 +23819,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">
@@ -18297,13 +23827,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">
@@ -18311,7 +23841,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">
@@ -18319,7 +23849,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">
@@ -18327,7 +23857,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">
@@ -18335,27 +23865,27 @@
<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="int">
+ <argument index="1" name="shape" type="RID">
</argument>
- <argument index="2" name="transform" type="RID" default="Transform()">
+ <argument index="2" name="transform" type="Transform" default="Transform()">
</argument>
<description>
</description>
</method>
- <method name="area_set_shape" qualifiers="const" >
- <return type="RID">
- </return>
+ <method name="area_set_shape">
<argument index="0" name="area" 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="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">
@@ -18365,7 +23895,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">
@@ -18373,7 +23903,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">
@@ -18383,7 +23913,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">
@@ -18393,7 +23923,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">
@@ -18401,29 +23931,31 @@
<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" qualifiers="const" >
+ <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_transform" qualifiers="const" >
- <return type="Transform">
- </return>
+ <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" >
+ <method name="area_get_param" qualifiers="const">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -18431,7 +23963,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">
@@ -18439,7 +23971,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">
@@ -18447,7 +23979,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">
@@ -18455,7 +23987,7 @@
<description>
</description>
</method>
- <method name="area_set_monitor_callback" >
+ <method name="area_set_monitor_callback">
<argument index="0" name="receiver" type="RID">
</argument>
<argument index="1" name="method" type="Object">
@@ -18465,7 +23997,23 @@
<description>
</description>
</method>
- <method name="body_create" >
+ <method name="area_set_ray_pickable">
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_is_ray_pickable" qualifiers="const">
+ <return type="bool">
+ </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="2">
@@ -18475,7 +24023,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">
@@ -18483,7 +24031,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">
@@ -18491,7 +24039,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">
@@ -18499,7 +24047,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">
@@ -18509,7 +24057,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">
@@ -18519,7 +24067,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">
@@ -18529,7 +24077,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">
@@ -18539,7 +24087,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">
@@ -18547,7 +24095,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">
@@ -18557,7 +24105,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">
@@ -18567,7 +24115,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">
@@ -18575,13 +24123,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">
@@ -18589,7 +24137,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">
@@ -18597,7 +24145,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">
@@ -18605,7 +24153,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">
@@ -18613,18 +24161,18 @@
<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">
</argument>
- <argument index="2" name="value" type="real">
+ <argument index="2" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="body_get_param" qualifiers="const" >
- <return type="real">
+ <method name="body_get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="body" type="RID">
</argument>
@@ -18633,15 +24181,7 @@
<description>
</description>
</method>
- <method name="body_static_simulate_motion" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="new_xform" type="Transform">
- </argument>
- <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">
@@ -18651,7 +24191,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">
@@ -18659,7 +24199,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">
@@ -18669,7 +24209,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">
@@ -18677,7 +24217,23 @@
<description>
</description>
</method>
- <method name="body_add_collision_exception" >
+ <method name="body_set_axis_lock">
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_axis_lock" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </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">
@@ -18685,7 +24241,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">
@@ -18693,7 +24249,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">
@@ -18701,7 +24257,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">
@@ -18709,7 +24265,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">
@@ -18717,7 +24273,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">
@@ -18725,7 +24281,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">
@@ -18737,20 +24293,444 @@
<description>
</description>
</method>
- <method name="free" >
+ <method name="body_set_ray_pickable">
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_is_ray_pickable" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="joint_create_pin">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body_A" type="RID">
+ </argument>
+ <argument index="1" name="local_A" type="Vector3">
+ </argument>
+ <argument index="2" name="body_B" type="RID">
+ </argument>
+ <argument index="3" name="local_B" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="pin_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="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="pin_joint_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="pin_joint_set_local_A">
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="local_A" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="pin_joint_get_local_A" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="pin_joint_set_local_B">
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="local_B" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="pin_joint_get_local_B" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="joint_create_hinge">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body_A" type="RID">
+ </argument>
+ <argument index="1" name="hinge_A" type="Transform">
+ </argument>
+ <argument index="2" name="body_B" type="RID">
+ </argument>
+ <argument index="3" name="hinge_B" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hinge_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="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hinge_joint_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hinge_joint_set_flag">
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="flag" type="int">
+ </argument>
+ <argument index="2" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hinge_joint_get_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="flag" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="joint_create_slider">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body_A" type="RID">
+ </argument>
+ <argument index="1" name="local_ref_A" type="Transform">
+ </argument>
+ <argument index="2" name="body_B" type="RID">
+ </argument>
+ <argument index="3" name="local_ref_B" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="slider_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="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="slider_joint_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="joint_create_cone_twist">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body_A" type="RID">
+ </argument>
+ <argument index="1" name="local_ref_A" type="Transform">
+ </argument>
+ <argument index="2" name="body_B" type="RID">
+ </argument>
+ <argument index="3" name="local_ref_B" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="cone_twist_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="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="cone_twist_joint_get_param" qualifiers="const">
+ <return type="float">
+ </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="joint_set_solver_priority">
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="priority" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="joint_get_solver_priority" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="joint_create_generic_6dof">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body_A" type="RID">
+ </argument>
+ <argument index="1" name="local_ref_A" type="Transform">
+ </argument>
+ <argument index="2" name="body_B" type="RID">
+ </argument>
+ <argument index="3" name="local_ref_B" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="generic_6dof_joint_set_param">
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int">
+ </argument>
+ <argument index="2" name="param" type="int">
+ </argument>
+ <argument index="3" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="generic_6dof_joint_get_param">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int">
+ </argument>
+ <argument index="2" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="generic_6dof_joint_set_flag">
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int">
+ </argument>
+ <argument index="2" name="flag" type="int">
+ </argument>
+ <argument index="3" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="generic_6dof_joint_get_flag">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int">
+ </argument>
+ <argument index="2" name="flag" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="int">
+ </return>
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
+ <constant name="JOINT_PIN" value="0">
+ </constant>
+ <constant name="JOINT_HINGE" value="1">
+ </constant>
+ <constant name="JOINT_SLIDER" value="2">
+ </constant>
+ <constant name="JOINT_CONE_TWIST" value="3">
+ </constant>
+ <constant name="JOINT_6DOF" value="4">
+ </constant>
+ <constant name="PIN_JOINT_BIAS" value="0">
+ </constant>
+ <constant name="PIN_JOINT_DAMPING" value="1">
+ </constant>
+ <constant name="PIN_JOINT_IMPULSE_CLAMP" value="2">
+ </constant>
+ <constant name="HINGE_JOINT_BIAS" value="0">
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_UPPER" value="1">
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_LOWER" value="2">
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_BIAS" value="3">
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_SOFTNESS" value="4">
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_RELAXATION" value="5">
+ </constant>
+ <constant name="HINGE_JOINT_MOTOR_TARGET_VELOCITY" value="6">
+ </constant>
+ <constant name="HINGE_JOINT_MOTOR_MAX_IMPULSE" value="7">
+ </constant>
+ <constant name="HINGE_JOINT_FLAG_USE_LIMIT" value="0">
+ </constant>
+ <constant name="HINGE_JOINT_FLAG_ENABLE_MOTOR" value="1">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_UPPER" value="0">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_LOWER" value="1">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS" value="2">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION" value="3">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_DAMPING" value="4">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_MOTION_SOFTNESS" value="5">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_MOTION_RESTITUTION" value="6">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_MOTION_DAMPING" value="7">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS" value="8">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION" value="9">
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING" value="10">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_UPPER" value="11">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_LOWER" value="12">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS" value="13">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION" value="14">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_DAMPING" value="15">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS" value="16">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION" value="17">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_MOTION_DAMPING" value="18">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS" value="19">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION" value="20">
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING" value="21">
+ </constant>
+ <constant name="SLIDER_JOINT_MAX" value="22">
+ </constant>
+ <constant name="CONE_TWIST_JOINT_SWING_SPAN" value="0">
+ </constant>
+ <constant name="CONE_TWIST_JOINT_TWIST_SPAN" value="1">
+ </constant>
+ <constant name="CONE_TWIST_JOINT_BIAS" value="2">
+ </constant>
+ <constant name="CONE_TWIST_JOINT_SOFTNESS" value="3">
+ </constant>
+ <constant name="CONE_TWIST_JOINT_RELAXATION" value="4">
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_LOWER_LIMIT" value="0">
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_UPPER_LIMIT" value="1">
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS" value="2">
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_RESTITUTION" value="3">
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_DAMPING" value="4">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_LOWER_LIMIT" value="5">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_UPPER_LIMIT" value="6">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS" value="7">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_DAMPING" value="8">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_RESTITUTION" value="9">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_FORCE_LIMIT" value="10">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_ERP" value="11">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY" value="12">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT" value="13">
+ </constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT" value="0">
+ </constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT" value="1">
+ </constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_MOTOR" value="2">
+ </constant>
<constant name="SHAPE_PLANE" value="0">
</constant>
<constant name="SHAPE_RAY" value="1">
@@ -18775,11 +24755,15 @@
</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_GRAVITY_POINT_ATTENUATION" value="4">
+ </constant>
+ <constant name="AREA_PARAM_LINEAR_DAMP" value="5">
</constant>
- <constant name="AREA_PARAM_DENSITY" value="4">
+ <constant name="AREA_PARAM_ANGULAR_DAMP" value="6">
</constant>
- <constant name="AREA_PARAM_PRIORITY" value="5">
+ <constant name="AREA_PARAM_PRIORITY" value="7">
</constant>
<constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1">
</constant>
@@ -18801,7 +24785,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>
@@ -18817,6 +24807,12 @@
</constant>
<constant name="AREA_BODY_REMOVED" value="1">
</constant>
+ <constant name="INFO_ACTIVE_OBJECTS" value="0">
+ </constant>
+ <constant name="INFO_COLLISION_PAIRS" value="1">
+ </constant>
+ <constant name="INFO_ISLAND_COUNT" value="2">
+ </constant>
</constants>
</class>
<class name="PhysicsServerSW" inherits="PhysicsServer" category="Core">
@@ -18829,6 +24825,94 @@
<constants>
</constants>
</class>
+<class name="PhysicsShapeQueryParameters" inherits="Reference" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_shape">
+ <argument index="0" name="shape" type="Shape">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_shape_rid">
+ <argument index="0" name="shape" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shape_rid" qualifiers="const">
+ <return type="RID">
+ </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_margin">
+ <argument index="0" name="margin" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_layer_mask">
+ <argument index="0" name="layer_mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_layer_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_exclude">
+ <argument index="0" name="exclude" type="Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_exclude" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="PhysicsShapeQueryResult" inherits="Reference" category="Core">
<brief_description>
Result of a shape query in Physics2DServer.
@@ -18836,13 +24920,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">
@@ -18850,7 +24934,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">
@@ -18858,7 +24942,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">
@@ -18866,7 +24950,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">
@@ -18878,6 +24962,38 @@
<constants>
</constants>
</class>
+<class name="PinJoint" inherits="Joint" 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="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="PARAM_BIAS" value="0">
+ </constant>
+ <constant name="PARAM_DAMPING" value="1">
+ </constant>
+ <constant name="PARAM_IMPULSE_CLAMP" value="2">
+ </constant>
+ </constants>
+</class>
<class name="PinJoint2D" inherits="Joint2D" category="Core">
<brief_description>
Pin Joint for 2D Shapes.
@@ -18886,6 +25002,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>
@@ -18898,38 +25026,41 @@
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" >
- <return type="real">
+ <method name="distance_to">
+ <return type="float">
</return>
<argument index="0" name="point" type="Vector3">
</argument>
<description>
+ 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">
</argument>
- <argument index="1" name="epsilon" type="real" default="0.00001">
+ <argument index="1" name="epsilon" type="float" default="0.00001">
</argument>
<description>
- Returns true if "p" is inside the plane (by a very minimum treshold).
+ 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">
@@ -18937,10 +25068,10 @@
<argument index="1" name="c" type="Plane">
</argument>
<description>
- Returns true if this plane intersects with planes "a" and "b". The resulting intersectin is placed in "r".
+ 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">
@@ -18948,10 +25079,10 @@
<argument index="1" name="dir" type="Vector3">
</argument>
<description>
- Returns true if ray consiting of position "p" and direction normal "d" intersects this plane. If true, the result is placed in "r".
+ 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">
@@ -18959,26 +25090,26 @@
<argument index="1" name="end" type="Vector3">
</argument>
<description>
- Returns true if segment from position "sa" to position "sb" intersects this plane. If true, the result is placed in "r".
+ 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">
</argument>
<description>
- Returns true if "p" is located above the plane.
+ 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">
@@ -18987,19 +25118,24 @@
Returns the orthogonal projection of point "p" into a point in the plane.
</description>
</method>
- <method name="Plane" >
- <argument index="0" name="a" type="real">
+ <method name="Plane">
+ <return type="Plane">
+ </return>
+ <argument index="0" name="a" type="float">
</argument>
- <argument index="1" name="b" type="real">
+ <argument index="1" name="b" type="float">
</argument>
- <argument index="2" name="c" type="real">
+ <argument index="2" name="c" type="float">
</argument>
- <argument index="3" name="d" type="real">
+ <argument index="3" name="d" type="float">
</argument>
<description>
+ 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">
@@ -19007,27 +25143,31 @@
<argument index="2" name="v3" type="Vector3">
</argument>
<description>
+ 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="real">
+ <argument index="1" name="d" type="float">
</argument>
<description>
+ Creates a plane from the normal and the plane's distance to the origin.
</description>
</method>
</methods>
<members>
<member name="normal" type="Vector3">
</member>
- <member name="x" type="real">
+ <member name="x" type="float">
</member>
- <member name="y" type="real">
+ <member name="y" type="float">
</member>
- <member name="z" type="real">
+ <member name="z" type="float">
</member>
- <member name="d" type="real">
+ <member name="d" type="float">
</member>
</members>
<constants>
@@ -19039,13 +25179,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>
@@ -19055,6 +25195,212 @@
<constants>
</constants>
</class>
+<class name="Polygon2D" inherits="Node2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <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>
+ <method name="set_uv">
+ <argument index="0" name="uv" type="Vector2Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_uv" qualifiers="const">
+ <return type="Vector2Array">
+ </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_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_texture_rotation">
+ <argument index="0" name="texture_rotation" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_texture_rotation" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_texture_scale">
+ <argument index="0" name="texture_scale" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_texture_scale" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_invert">
+ <argument index="0" name="invert" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_invert" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_invert_border">
+ <argument index="0" name="invert_border" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_invert_border" qualifiers="const">
+ <return type="float">
+ </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>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="PolygonPathFinder" inherits="Resource" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="setup">
+ <argument index="0" name="points" type="Vector2Array">
+ </argument>
+ <argument index="1" name="connections" type="IntArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="find_path">
+ <return type="Vector2Array">
+ </return>
+ <argument index="0" name="from" type="Vector2">
+ </argument>
+ <argument index="1" name="to" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_intersections" qualifiers="const">
+ <return type="Vector2Array">
+ </return>
+ <argument index="0" name="from" type="Vector2">
+ </argument>
+ <argument index="1" name="to" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_closest_point" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_point_inside" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_point_penalty">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="penalty" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_point_penalty" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bounds" qualifiers="const">
+ <return type="Rect2">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="Popup" inherits="Control" category="Core">
<brief_description>
Base container control for popups and dialogs.
@@ -19063,38 +25409,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" >
- <argument index="0" name="ratio" type="real" default="0.75">
+ <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>
@@ -19102,6 +25448,10 @@
</method>
</methods>
<signals>
+ <signal name="popup_hide">
+ <description>
+ </description>
+ </signal>
<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).
@@ -19111,11 +25461,13 @@
<constants>
<constant name="NOTIFICATION_POST_POPUP" value="80">
</constant>
+ <constant name="NOTIFICATION_POPUP_HIDE" value="81">
+ </constant>
</constants>
</class>
<class name="PopupDialog" inherits="Popup" category="Core">
<brief_description>
- Base class for Popup Dialogs
+ Base class for Popup Dialogs.
</brief_description>
<description>
</description>
@@ -19132,7 +25484,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">
@@ -19142,10 +25494,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">
@@ -19156,7 +25508,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">
@@ -19166,10 +25518,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">
@@ -19177,20 +25529,20 @@
<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="int">
+ <argument index="1" name="submenu" type="String">
</argument>
<argument index="2" name="id" type="int" default="-1">
</argument>
<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">
@@ -19199,7 +25551,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">
@@ -19208,16 +25560,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">
@@ -19225,7 +25577,7 @@
<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">
@@ -19234,7 +25586,7 @@
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">
@@ -19242,7 +25594,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">
@@ -19250,7 +25602,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">
@@ -19258,7 +25610,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">
@@ -19266,7 +25618,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">
@@ -19275,7 +25627,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">
@@ -19284,7 +25636,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">
@@ -19293,22 +25645,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">
@@ -19316,7 +25668,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">
@@ -19324,7 +25676,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">
@@ -19332,7 +25684,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">
@@ -19341,7 +25693,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">
@@ -19349,7 +25701,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">
@@ -19358,7 +25710,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">
@@ -19367,25 +25719,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>
@@ -19402,6 +25754,36 @@
</signals>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="vseparation" 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_accel" 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="submenu" type="Texture">
+ </theme_item>
+ <theme_item name="checked" 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="panel_disabled" type="StyleBox">
+ </theme_item>
+ <theme_item name="panel" type="StyleBox">
+ </theme_item>
+ <theme_item name="separator" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="PopupPanel" inherits="Popup" category="Core">
<brief_description>
@@ -19413,81 +25795,84 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="panel" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="Portal" inherits="VisualInstance" category="Core">
<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 "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" >
- <argument index="0" name="distance" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="range" type="real">
+ <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" >
- <return type="real">
+ <method name="get_connect_range" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the range for auto-connecting two portals from different rooms sharing the same space.
@@ -19523,15 +25908,39 @@
</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">
+ <argument index="0" name="visible" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_percent_visible" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="font_color" type="Color">
+ </theme_item>
+ <theme_item name="font_color_shadow" type="Color">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ <theme_item name="fg" type="StyleBox">
+ </theme_item>
+ <theme_item name="bg" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="ProximityGroup" inherits="Spatial" category="Core">
<brief_description>
@@ -19541,13 +25950,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">
@@ -19555,19 +25964,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>
@@ -19593,49 +26002,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>
@@ -19650,10 +26059,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">
@@ -19662,13 +26071,13 @@
</argument>
<argument index="2" name="post_b" type="Quat">
</argument>
- <argument index="3" name="t" type="real">
+ <argument index="3" name="t" type="float">
</argument>
<description>
</description>
</method>
- <method name="dot" >
- <return type="real">
+ <method name="dot">
+ <return type="float">
</return>
<argument index="0" name="b" type="Quat">
</argument>
@@ -19676,68 +26085,90 @@
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" >
- <return type="real">
+ <method name="length">
+ <return type="float">
</return>
<description>
Returns the length of the quaternion.
</description>
</method>
- <method name="length_squared" >
- <return type="real">
+ <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">
</argument>
- <argument index="1" name="t" type="real">
+ <argument index="1" name="t" type="float">
</argument>
<description>
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">
</argument>
- <argument index="1" name="t" type="real">
+ <argument index="1" name="t" type="float">
</argument>
<description>
</description>
</method>
- <method name="Quat" >
- <argument index="0" name="x" type="real">
+ <method name="xform">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="v" type="Vector3">
</argument>
- <argument index="1" name="y" type="real">
+ <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">
+ </argument>
+ <argument index="2" name="z" type="float">
</argument>
- <argument index="2" name="z" type="real">
+ <argument index="3" name="w" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="Quat">
+ <return type="Quat">
+ </return>
+ <argument index="0" name="axis" type="Vector3">
</argument>
- <argument index="3" name="w" type="real">
+ <argument index="1" name="angle" type="float">
</argument>
<description>
</description>
</method>
- <method name="Quat" >
+ <method name="Quat">
+ <return type="Quat">
+ </return>
<argument index="0" name="from" type="Matrix3">
</argument>
<description>
@@ -19745,13 +26176,13 @@
</method>
</methods>
<members>
- <member name="x" type="real">
+ <member name="x" type="float">
</member>
- <member name="y" type="real">
+ <member name="y" type="float">
</member>
- <member name="z" type="real">
+ <member name="z" type="float">
</member>
- <member name="w" type="real">
+ <member name="w" type="float">
</member>
</members>
<constants>
@@ -19763,13 +26194,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>
@@ -19784,141 +26217,141 @@
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" >
- <return type="real">
+ <method name="get_val" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the current value.
</description>
</method>
- <method name="get_value" qualifiers="const" >
- <return type="real">
+ <method name="get_value" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_min" qualifiers="const" >
- <return type="real">
+ <method name="get_min" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the minimum value.
</description>
</method>
- <method name="get_max" qualifiers="const" >
- <return type="real">
+ <method name="get_max" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the maximum value.
</description>
</method>
- <method name="get_step" qualifiers="const" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
+ <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">
+ <method name="set_val">
+ <argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_value" >
- <argument index="0" name="value" type="real">
+ <method name="set_value">
+ <argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_min" >
- <argument index="0" name="minimum" type="real">
+ <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" >
- <argument index="0" name="maximum" type="real">
+ <method name="set_max">
+ <argument index="0" name="maximum" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_step" >
- <argument index="0" name="step" type="real">
+ <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" >
- <argument index="0" name="pagesize" type="real">
+ <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" >
- <argument index="0" name="value" type="real">
+ <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" >
+ <method name="set_rounded_values">
<argument index="0" name="arg0" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_exp_unit_value" >
+ <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>
</methods>
<signals>
<signal name="value_changed">
- <argument index="0" name="value" type="real">
+ <argument index="0" name="value" type="float">
</argument>
<description>
This signal is emitted when value changes.
@@ -19938,10 +26371,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">
@@ -19949,31 +26382,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">
@@ -19981,13 +26416,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>
@@ -20003,60 +26440,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>
@@ -20067,60 +26532,114 @@
<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">
+ <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>
+ <method name="set_layer_mask">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -20131,14 +26650,14 @@
<description>
</description>
<methods>
- <method name="set_length" >
- <argument index="0" name="length" type="real">
+ <method name="set_length">
+ <argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
+ <method name="get_length" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -20152,19 +26671,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" >
- <argument index="0" name="length" type="real">
+ <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" >
- <return type="real">
+ <method name="get_length" qualifiers="const">
+ <return type="float">
</return>
<description>
+ Return the length of the ray.
</description>
</method>
</methods>
@@ -20176,44 +26697,46 @@
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" >
- <return type="real">
+ <method name="get">
+ <return type="float">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="push_back" >
- <argument index="0" name="value" type="real">
+ <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="real">
+ <argument index="1" name="value" type="float">
</argument>
<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>
@@ -20225,96 +26748,113 @@
</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" >
- <return type="real">
+ <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="real">
+ <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" >
- <argument index="0" name="x" type="real">
+ <method name="Rect2">
+ <return type="Rect2">
+ </return>
+ <argument index="0" name="x" type="float">
</argument>
- <argument index="1" name="y" type="real">
+ <argument index="1" name="y" type="float">
</argument>
- <argument index="2" name="width" type="real">
+ <argument index="2" name="width" type="float">
</argument>
- <argument index="3" name="height" type="real">
+ <argument index="3" name="height" type="float">
</argument>
<description>
+ Construct a [Rect2] by x, y, width and height.
</description>
</method>
</methods>
@@ -20337,14 +26877,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>
@@ -20357,24 +26897,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>
@@ -20390,28 +26930,54 @@
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>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="border" type="StyleBox">
+ </theme_item>
+ </theme_items>
</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">
@@ -20421,12 +26987,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>
@@ -20439,13 +27035,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>
@@ -20473,54 +27069,60 @@
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't be changed by anything else.
+ </description>
+ </method>
+ <method name="take_over_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" >
+ <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">
@@ -20544,27 +27146,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">
@@ -20572,7 +27174,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">
@@ -20580,19 +27182,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">
@@ -20600,13 +27202,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>
@@ -20624,34 +27226,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>
@@ -20670,7 +27272,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">
@@ -20681,18 +27283,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">
@@ -20701,14 +27304,14 @@
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">
@@ -20716,7 +27319,7 @@
<description>
</description>
</method>
- <method name="has" >
+ <method name="has">
<return type="bool">
</return>
<argument index="0" name="arg0" type="String">
@@ -20736,7 +27339,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">
@@ -20745,14 +27348,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">
@@ -20761,7 +27364,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">
@@ -20770,7 +27373,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">
@@ -20779,7 +27382,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>
@@ -20798,7 +27401,7 @@
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">
@@ -20811,7 +27414,7 @@
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">
@@ -20822,6 +27425,18 @@
</method>
</methods>
<constants>
+ <constant name="FLAG_RELATIVE_PATHS" value="1">
+ </constant>
+ <constant name="FLAG_BUNDLE_RESOURCES" value="2">
+ </constant>
+ <constant name="FLAG_CHANGE_PATH" value="4">
+ </constant>
+ <constant name="FLAG_OMIT_EDITOR_PROPERTIES" value="8">
+ </constant>
+ <constant name="FLAG_SAVE_BIG_ENDIAN" value="16">
+ </constant>
+ <constant name="FLAG_COMPRESS" value="32">
+ </constant>
</constants>
</class>
<class name="RichTextLabel" inherits="Control" category="Core">
@@ -20832,132 +27447,202 @@
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="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="arg0" 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">
+ <return type="int">
+ </return>
+ <argument index="0" name="bbcode" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="append_bbcode">
+ <return type="int">
+ </return>
+ <argument index="0" name="bbcode" type="String">
+ </argument>
+ <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">
@@ -21005,6 +27690,28 @@
<constant name="ITEM_META" value="10">
</constant>
</constants>
+ <theme_items>
+ <theme_item name="line_separation" type="int">
+ </theme_item>
+ <theme_item name="default_color" type="Color">
+ </theme_item>
+ <theme_item name="selection_color" type="Color">
+ </theme_item>
+ <theme_item name="font_color_selected" type="Color">
+ </theme_item>
+ <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>
+ </theme_items>
</class>
<class name="RigidBody" inherits="PhysicsBody" category="Core">
<brief_description>
@@ -21012,151 +27719,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" >
- <argument index="0" name="mass" type="real">
+ <method name="set_mass">
+ <argument index="0" name="mass" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_mass" qualifiers="const" >
- <return type="real">
+ <method name="get_mass" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_weight" >
- <argument index="0" name="weight" type="real">
+ <method name="set_weight">
+ <argument index="0" name="weight" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_weight" qualifiers="const" >
- <return type="real">
+ <method name="get_weight" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_friction" >
- <argument index="0" name="friction" type="real">
+ <method name="set_friction">
+ <argument index="0" name="friction" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_friction" qualifiers="const" >
- <return type="real">
+ <method name="get_friction" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_bounce" >
- <argument index="0" name="bounce" type="real">
+ <method name="set_bounce">
+ <argument index="0" name="bounce" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
- <return type="real">
+ <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">
@@ -21164,30 +27907,48 @@
<description>
</description>
</method>
- <method name="set_active" >
- <argument index="0" name="active" type="bool">
+ <method name="set_sleeping">
+ <argument index="0" name="sleeping" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_active" 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">
+ <argument index="0" name="axis_lock" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_axis_lock" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_colliding_bodies" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="body_enter">
@@ -21243,178 +28004,214 @@
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 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.
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].
</description>
</method>
- <method name="set_mass" >
- <argument index="0" name="mass" type="real">
+ <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" >
- <return type="real">
+ <method name="get_mass" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the body mass.
</description>
</method>
- <method name="set_weight" >
- <argument index="0" name="weight" type="real">
+ <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 mass 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" >
- <return type="real">
+ <method name="get_weight" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the body mass given standard earth-weight (gravity 9.8).
</description>
</method>
- <method name="set_friction" >
- <argument index="0" name="friction" type="real">
+ <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" >
- <return type="real">
+ <method name="get_friction" qualifiers="const">
+ <return type="float">
</return>
<description>
Return the body friction.
</description>
</method>
- <method name="set_bounce" >
- <argument index="0" name="bounce" type="real">
+ <method name="set_bounce">
+ <argument index="0" name="bounce" type="float">
</argument>
<description>
Set the body bounciness, from 0 (no bounce) to 1 (bounce).
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
- <return type="real">
+ <method name="get_bounce" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Return the body bounciness.
+ </description>
+ </method>
+ <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>
- Return the body bouncyness.
</description>
</method>
- <method name="set_linear_velocity" >
+ <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].
</description>
</method>
- <method name="set_angular_velocity" >
- <argument index="0" name="angular_velocity" type="real">
+ <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" >
- <return type="real">
+ <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].
</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].
</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.
</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).
</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>
</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>
</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).
</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">
@@ -21423,46 +28220,62 @@
Apply a positioned impulse (which will be affected by the body mass and shape).
</description>
</method>
- <method name="set_applied_force" >
+ <method name="set_applied_force">
<argument index="0" name="force" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_applied_force" qualifiers="const" >
+ <method name="get_applied_force" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_active" >
- <argument index="0" name="active" type="bool">
+ <method name="set_sleeping">
+ <argument index="0" name="sleeping" type="bool">
</argument>
<description>
- Change the body state between sleeping/active states. As a note, static bodies can never be active.
</description>
</method>
- <method name="is_active" qualifiers="const" >
+ <method name="is_sleeping" qualifiers="const">
<return type="bool">
</return>
<description>
- Return the body state. As a note, static bodies are never active.
</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.
</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].
</description>
</method>
+ <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>
+ </description>
+ </method>
+ <method name="get_colliding_bodies" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="body_enter">
@@ -21534,29 +28347,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>
@@ -21572,35 +28385,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>
@@ -21610,13 +28423,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">
@@ -21624,194 +28437,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="real">
+ <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" >
- <return type="real">
+ <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="real">
+ <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" >
- <return type="real">
+ <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>
@@ -21826,33 +28645,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">
@@ -21860,104 +28681,112 @@
<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="real">
+ <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="real">
+ <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="real">
+ <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="real">
+ <argument index="1" name="pan" type="float">
</argument>
- <argument index="2" name="depth" type="real" default="0">
+ <argument index="2" name="depth" type="float" default="0">
</argument>
- <argument index="3" name="height" type="real" default="0">
+ <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">
</argument>
- <argument index="2" name="cutoff_hz" type="real">
+ <argument index="2" name="cutoff_hz" type="float">
</argument>
- <argument index="3" name="resonance" type="real">
+ <argument index="3" name="resonance" type="float">
</argument>
- <argument index="4" name="gain" type="real" default="0">
+ <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="real">
+ <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">
</argument>
- <argument index="2" name="send" type="real">
+ <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">
@@ -21966,8 +28795,8 @@
Return the current mix rate for a given voice.
</description>
</method>
- <method name="get_pitch_scale" qualifiers="const" >
- <return type="real">
+ <method name="get_pitch_scale" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
@@ -21975,256 +28804,285 @@
Return the current pitch scale for a given voice.
</description>
</method>
- <method name="get_volume" qualifiers="const" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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="real">
+ <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" >
- <return type="real">
+ <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" >
- <argument index="0" name="ratio" type="real">
+ <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="real">
+ <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" >
- <argument index="0" name="db" type="real">
+ <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" >
- <argument index="0" name="pan" type="real">
+ <method name="set_default_pan">
+ <argument index="0" name="pan" type="float">
</argument>
- <argument index="1" name="depth" type="real" default="0">
+ <argument index="1" name="depth" type="float" default="0">
</argument>
- <argument index="2" name="height" type="real" default="0">
+ <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="real">
+ <argument index="1" name="cutoff_hz" type="float">
</argument>
- <argument index="2" name="resonance" type="real">
+ <argument index="2" name="resonance" type="float">
</argument>
- <argument index="3" name="gain" type="real" default="0">
+ <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" >
- <argument index="0" name="send" type="real">
+ <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="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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="real">
+ <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" >
- <return type="real">
+ <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>
@@ -22233,77 +29091,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">
@@ -22311,257 +29175,221 @@
<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="real">
+ <argument index="1" name="ratio" type="float">
</argument>
<description>
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="real">
+ <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" >
- <argument index="0" name="val" type="real">
+ <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" >
- <return type="real">
+ <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>
-<class name="SceneIO" inherits="Object" category="Core">
+<class name="SceneTree" inherits="MainLoop" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="load" >
- <return type="Node">
- </return>
- <argument index="0" name="path" type="String">
+ <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="save" >
- <return type="int">
- </return>
- <argument index="0" name="path" type="String">
+ <method name="set_group">
+ <argument index="0" name="call_flags" type="int">
</argument>
- <argument index="1" name="scene" type="Node">
+ <argument index="1" name="group" type="String">
</argument>
- <argument index="2" name="flags" type="int" default="0">
+ <argument index="2" name="property" type="String">
</argument>
- <argument index="3" name="optimizer" type="OptimizedSaver" default="Object()">
+ <argument index="3" name="value" type="var">
</argument>
<description>
</description>
</method>
- <method name="load_interactive" >
- <return type="SceneInteractiveLoader">
+ <method name="get_nodes_in_group">
+ <return type="Array">
</return>
- <argument index="0" name="path" type="String">
+ <argument index="0" name="arg0" type="String">
</argument>
<description>
</description>
</method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SceneInteractiveLoader" inherits="Reference" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_scene" >
- <return type="Object">
+ <method name="get_root" qualifiers="const">
+ <return type="Viewport">
</return>
<description>
</description>
</method>
- <method name="poll" >
- <return type="int">
- </return>
+ <method name="set_auto_accept_quit">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
<description>
</description>
</method>
- <method name="get_stage" qualifiers="const" >
- <return type="int">
- </return>
+ <method name="set_editor_hint">
+ <argument index="0" name="enable" type="bool">
+ </argument>
<description>
</description>
</method>
- <method name="get_stage_count" qualifiers="const" >
- <return type="int">
+ <method name="is_editor_hint" qualifiers="const">
+ <return type="bool">
</return>
<description>
</description>
</method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SceneMainLoop" inherits="MainLoop" category="Core">
- <brief_description>
- Scene-Based implementation of the MainLoop.
- </brief_description>
- <description>
- Scene implementation of the MainLoop. All scenes edited using the editor are loaded with this main loop, which provides the base for the scene system.[br]
- All group operations (get nodes, call, etc) is performed here. All nodes in a group can be called a specific functions, set a property or notified. This happens in scene-order.
- </description>
- <methods>
- <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">
+ <method name="set_debug_collisions_hint">
+ <argument index="0" name="enable" type="bool">
</argument>
<description>
- Call a notification in all the nodes belonging to a given group. See GROUP_CALL_* enum for options.
</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>
+ <method name="is_debugging_collisions_hint" qualifiers="const">
+ <return type="bool">
+ </return>
<description>
- Set a property in all the nodes belonging to a given group. See GROUP_CALL_* enum for options.
</description>
</method>
- <method name="get_nodes_in_group" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="String">
+ <method name="set_debug_navigation_hint">
+ <argument index="0" name="enable" type="bool">
</argument>
<description>
- Get all the nods belonging to a given group.
</description>
</method>
- <method name="get_root" qualifiers="const" >
- <return type="Viewport">
+ <method name="is_debugging_navigation_hint" qualifiers="const">
+ <return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_auto_accept_quit" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Set to true if the application will quit automatically when quit is requested (Alt-f4 or ctrl-c).
- </description>
- </method>
- <method name="set_editor_hint" >
- <argument index="0" name="enable" type="bool">
+ <method name="set_edited_scene_root">
+ <argument index="0" name="scene" type="Object">
</argument>
<description>
- Set to true to tell nodes and the scene that it is being edited. This is used by editors, not release.
</description>
</method>
- <method name="is_editor_hint" qualifiers="const" >
- <return type="bool">
+ <method name="get_edited_scene_root" qualifiers="const">
+ <return type="Object">
</return>
<description>
- Return true if the scene is being run inside an editor.
</description>
</method>
- <method name="set_pause" >
+ <method name="set_pause">
<argument index="0" name="enable" type="bool">
</argument>
<description>
- Set pause. The built-in pause system is very basic and only meant to avoid processing nodes not allowed to work in pause mode.
</description>
</method>
- <method name="is_paused" qualifiers="const" >
+ <method name="is_paused" qualifiers="const">
<return type="bool">
</return>
<description>
- Return true if the scene is paused.
</description>
</method>
- <method name="set_input_as_handled" >
+ <method name="set_input_as_handled">
<description>
- Handle a current input event (avoid further processing of it).
</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>
- Return the frame index (how many frames were drawn).
</description>
</method>
- <method name="quit" >
+ <method name="quit">
<description>
- Quit the application.
</description>
</method>
- <method name="queue_delete" >
+ <method name="set_screen_stretch">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <argument index="1" name="aspect" type="int">
+ </argument>
+ <argument index="2" name="minsize" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="queue_delete">
<argument index="0" name="obj" type="Object">
</argument>
<description>
- Queue an object for deletion next time the loop goes idle.
</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">
@@ -22579,78 +29407,90 @@
<argument index="7" name="arg4" type="var" default="NULL">
</argument>
<description>
- Call a function for all the nodes in a given group.
+ </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">
<description>
- Emitted when the screen changes size.
</description>
</signal>
<signal name="node_removed">
<argument index="0" name="node" type="Object">
</argument>
<description>
- Emitted when a node is removed from the scene.
+ </description>
+ </signal>
+ <signal name="idle_frame">
+ <description>
</description>
</signal>
<signal name="tree_changed">
<description>
- Emitted when the scene tree changed (nodes added/removed/moved/etc)
+ </description>
+ </signal>
+ <signal name="fixed_frame">
+ <description>
</description>
</signal>
</signals>
<constants>
<constant name="GROUP_CALL_DEFAULT" value="0">
- Regular group call flag (no flags).
</constant>
<constant name="GROUP_CALL_REVERSE" value="1">
- Call a group in inverse-scene order.
</constant>
<constant name="GROUP_CALL_REALTIME" value="2">
- Call a group immediately (usually calls are delivered on idle).
</constant>
<constant name="GROUP_CALL_UNIQUE" value="4">
- Call a group only once, even if call is performed many times.
</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>
+ <constant name="STRETCH_MODE_DISABLED" value="0">
+ </constant>
+ <constant name="STRETCH_MODE_2D" value="1">
+ </constant>
+ <constant name="STRETCH_MODE_VIEWPORT" value="2">
+ </constant>
+ <constant name="STRETCH_ASPECT_IGNORE" value="0">
+ </constant>
+ <constant name="STRETCH_ASPECT_KEEP" value="1">
+ </constant>
+ <constant name="STRETCH_ASPECT_KEEP_WIDTH" value="2">
+ </constant>
+ <constant name="STRETCH_ASPECT_KEEP_HEIGHT" value="3">
+ </constant>
</constants>
</class>
<class name="Script" inherits="Resource" category="Core">
@@ -22661,14 +29501,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">
@@ -22677,28 +29517,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>
@@ -22717,14 +29557,14 @@
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" >
- <argument index="0" name="step" type="real">
+ <method name="set_custom_step">
+ <argument index="0" name="step" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_custom_step" qualifiers="const" >
- <return type="real">
+ <method name="get_custom_step" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -22735,53 +29575,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>
@@ -22799,28 +29641,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>
@@ -22833,14 +29679,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>
@@ -22869,43 +29715,61 @@
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">
</argument>
- <argument index="2" name="vofs" type="int" default="0">
+ <argument index="2" name="lcode" type="String">
</argument>
<argument index="3" name="fofs" type="int" default="0">
</argument>
+ <argument index="4" name="lofs" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_vertex_code" qualifiers="const">
+ <return type="String">
+ </return>
<description>
</description>
</method>
- <method name="get_vertex_code" qualifiers="const" >
+ <method name="get_fragment_code" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_fragment_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">
@@ -22923,24 +29787,906 @@
</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">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="arg2" type="float">
+ </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">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="arg2" type="Vector3">
+ </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">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="arg2" type="Color">
+ </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">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="arg2" type="Transform">
+ </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">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="arg2" 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">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <argument index="2" name="arg2" 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">
+ <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">
+ <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>
</methods>
<constants>
</constants>
@@ -22963,21 +30709,22 @@
Base class for all 2D Shapes. All 2D shape types inherit from this.
</description>
<methods>
- <method name="set_custom_solver_bias" >
- <argument index="0" name="bias" type="real">
+ <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" >
- <return type="real">
+ <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">
@@ -22987,9 +30734,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">
@@ -23003,9 +30752,11 @@
<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">
<argument index="0" name="local_xform" type="Matrix32">
</argument>
<argument index="1" name="with_shape" type="Shape2D">
@@ -23013,16 +30764,24 @@
<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">
<argument index="0" name="local_xform" type="Matrix32">
</argument>
- <argument index="1" name="local_motion" type="Object">
+ <argument index="1" name="local_motion" type="Vector2">
</argument>
<argument index="2" name="with_shape" type="Shape2D">
</argument>
+ <argument index="3" name="shape_xform" type="Matrix32">
+ </argument>
+ <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>
@@ -23037,14 +30796,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">
@@ -23053,7 +30812,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">
@@ -23062,7 +30821,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">
@@ -23071,7 +30830,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">
@@ -23080,14 +30839,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">
@@ -23096,7 +30861,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">
@@ -23105,39 +30870,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">
@@ -23146,7 +30927,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">
@@ -23155,7 +30936,23 @@
Return the pose transform for bone "bone_idx".
</description>
</method>
- <method name="get_bone_custom_pose" qualifiers="const" >
+ <method name="set_bone_global_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_global_pose" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bone_custom_pose" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -23163,7 +30960,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">
@@ -23171,7 +30968,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">
@@ -23193,28 +30990,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>
@@ -23225,6 +31022,78 @@
<constants>
</constants>
</class>
+<class name="SliderJoint" inherits="Joint" 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="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="PARAM_LINEAR_LIMIT_UPPER" value="0">
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_LOWER" value="1">
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_SOFTNESS" value="2">
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_RESTITUTION" value="3">
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_DAMPING" value="4">
+ </constant>
+ <constant name="PARAM_LINEAR_MOTION_SOFTNESS" value="5">
+ </constant>
+ <constant name="PARAM_LINEAR_MOTION_RESTITUTION" value="6">
+ </constant>
+ <constant name="PARAM_LINEAR_MOTION_DAMPING" value="7">
+ </constant>
+ <constant name="PARAM_LINEAR_ORTHOGONAL_SOFTNESS" value="8">
+ </constant>
+ <constant name="PARAM_LINEAR_ORTHOGONAL_RESTITUTION" value="9">
+ </constant>
+ <constant name="PARAM_LINEAR_ORTHOGONAL_DAMPING" value="10">
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_UPPER" value="11">
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_LOWER" value="12">
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_SOFTNESS" value="13">
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_RESTITUTION" value="14">
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_DAMPING" value="15">
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTION_SOFTNESS" value="16">
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTION_RESTITUTION" value="17">
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTION_DAMPING" value="18">
+ </constant>
+ <constant name="PARAM_ANGULAR_ORTHOGONAL_SOFTNESS" value="19">
+ </constant>
+ <constant name="PARAM_ANGULAR_ORTHOGONAL_RESTITUTION" value="20">
+ </constant>
+ <constant name="PARAM_ANGULAR_ORTHOGONAL_DAMPING" value="21">
+ </constant>
+ <constant name="PARAM_MAX" value="22">
+ </constant>
+ </constants>
+</class>
<class name="SoundPlayer2D" inherits="Node2D" category="Core">
<brief_description>
Base class for playing spatial 2D sound.
@@ -23233,16 +31102,16 @@
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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
+ <method name="get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="param" type="int">
</argument>
@@ -23271,41 +31140,41 @@
<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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
+ <method name="get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="param" type="int">
</argument>
<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>
@@ -23323,126 +31192,238 @@
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">
+ <description>
+ </description>
+ </method>
+ <method name="hide">
+ <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="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">
+ <description>
+ </description>
+ </signal>
+ </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>
<constant name="NOTIFICATION_EXIT_WORLD" value="42">
</constant>
+ <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="43">
+ </constant>
</constants>
</class>
<class name="SpatialPlayer" inherits="Spatial" category="Core">
@@ -23451,16 +31432,16 @@
<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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
+ <method name="get_param" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="param" type="int">
</argument>
@@ -23493,31 +31474,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">
@@ -23527,23 +31508,23 @@
<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="real">
+ <argument index="1" name="ratio" type="float">
</argument>
<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="real">
+ <argument index="1" name="db" type="float">
</argument>
<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">
@@ -23551,13 +31532,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>
@@ -23617,68 +31598,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="arg0" 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_loop" >
+ <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" >
+ <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" >
- <return type="real">
+ <method name="get_pos" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="seek_pos" >
- <argument index="0" name="time" type="real">
+ <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>
@@ -23689,14 +31750,14 @@
<description>
</description>
<methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
+ <method name="set_radius">
+ <argument index="0" name="radius" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
+ <method name="get_radius" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -23713,48 +31774,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>
@@ -23763,6 +31824,10 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="updown" type="Texture">
+ </theme_item>
+ </theme_items>
</class>
<class name="SplitContainer" inherits="Container" category="Core">
<brief_description>
@@ -23772,53 +31837,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.
@@ -23836,154 +31909,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>
@@ -23991,7 +32064,253 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
+<class name="Sprite3D" inherits="SpriteBase3D" 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_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>
+ </methods>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
+<class name="SpriteBase3D" inherits="GeometryInstance" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <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_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_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_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_opacity">
+ <argument index="0" name="opacity" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_opacity" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_pixel_size">
+ <argument index="0" name="pixel_size" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_pixel_size" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_axis">
+ <argument index="0" name="axis" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_axis" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_draw_flag">
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_draw_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_rect" qualifiers="const">
+ <return type="Rect2">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
<constants>
+ <constant name="FLAG_TRANSPARENT" value="0">
+ </constant>
+ <constant name="FLAG_SHADED" value="1">
+ </constant>
+ <constant name="FLAG_MAX" value="2">
+ </constant>
+ <constant name="ALPHA_CUT_DISABLED" value="0">
+ </constant>
+ <constant name="ALPHA_CUT_DISCARD" value="1">
+ </constant>
+ <constant name="ALPHA_CUT_OPAQUE_PREPASS" value="2">
+ </constant>
</constants>
</class>
<class name="SpriteFrames" inherits="Resource" category="Core">
@@ -24002,7 +32321,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">
@@ -24011,14 +32330,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">
@@ -24027,7 +32346,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">
@@ -24035,14 +32354,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>
@@ -24059,38 +32378,50 @@
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_simulate_motion" >
- <argument index="0" name="enabled" type="bool">
+ <method name="set_constant_linear_velocity">
+ <argument index="0" name="vel" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="is_simulating_motion" qualifiers="const" >
- <return type="bool">
+ <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">
+ <return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_constant_linear_velocity" >
- <argument index="0" name="vel" type="Vector3">
- </argument>
+ <method name="get_constant_angular_velocity" qualifiers="const">
+ <return type="Vector3">
+ </return>
<description>
</description>
</method>
- <method name="set_constant_angular_velocity" >
- <argument index="0" name="vel" type="Vector3">
+ <method name="set_friction">
+ <argument index="0" name="friction" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_constant_linear_velocity" qualifiers="const" >
- <return type="Vector3">
+ <method name="get_friction" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_constant_angular_velocity" qualifiers="const" >
- <return type="Vector3">
+ <method name="set_bounce">
+ <argument index="0" name="bounce" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bounce" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -24104,59 +32435,59 @@
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.
</description>
</method>
- <method name="set_constant_angular_velocity" >
- <argument index="0" name="vel" type="real">
+ <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.
</description>
</method>
- <method name="get_constant_angular_velocity" qualifiers="const" >
- <return type="real">
+ <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" >
- <argument index="0" name="friction" type="real">
+ <method name="set_friction">
+ <argument index="0" name="friction" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_friction" qualifiers="const" >
- <return type="real">
+ <method name="get_friction" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_bounce" >
- <argument index="0" name="bounce" type="real">
+ <method name="set_bounce">
+ <argument index="0" name="bounce" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
- <return type="real">
+ <method name="get_bounce" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -24173,7 +32504,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">
@@ -24182,7 +32513,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">
@@ -24191,7 +32522,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">
@@ -24200,7 +32531,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">
@@ -24213,6 +32544,54 @@
<constants>
</constants>
</class>
+<class name="StreamPeerSSL" inherits="StreamPeer" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="accept">
+ <return type="Error">
+ </return>
+ <argument index="0" name="stream" type="StreamPeer">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="connect">
+ <return type="Error">
+ </return>
+ <argument index="0" name="stream" type="StreamPeer">
+ </argument>
+ <argument index="1" name="validate_certs" type="bool" default="false">
+ </argument>
+ <argument index="2" name="for_hostname" type="String" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_status" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="disconnect">
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="STATUS_DISCONNECTED" value="0">
+ </constant>
+ <constant name="STATUS_CONNECTED" value="1">
+ </constant>
+ <constant name="STATUS_ERROR_NO_CERTIFICATE" value="2">
+ </constant>
+ <constant name="STATUS_ERROR_HOSTNAME_MISMATCH" value="3">
+ </constant>
+ </constants>
+</class>
<class name="StreamPeerTCP" inherits="StreamPeer" category="Core">
<brief_description>
TCP Stream peer.
@@ -24221,40 +32600,54 @@
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_connected_host" qualifiers="const" >
+ <method name="get_status" qualifiers="const">
+ <return type="int">
+ </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" >
+ <method name="get_connected_port" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="disconnect" >
+ <method name="disconnect">
<description>
</description>
</method>
</methods>
<constants>
+ <constant name="STATUS_NONE" value="0">
+ </constant>
+ <constant name="STATUS_CONNECTING" value="1">
+ </constant>
+ <constant name="STATUS_CONNECTED" value="2">
+ </constant>
+ <constant name="STATUS_ERROR" value="3">
+ </constant>
</constants>
</class>
<class name="StreamPlayer" inherits="Node" category="Core">
@@ -24265,118 +32658,144 @@
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="arg0" 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" >
- <argument index="0" name="volume" type="real">
+ <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_volume" qualifiers="const" >
- <return type="real">
+ <method name="get_buffering_msec" qualifiers="const">
+ <return type="int">
</return>
<description>
</description>
</method>
- <method name="set_volume_db" >
- <argument index="0" name="db" type="real">
+ <method name="set_loop_restart_time">
+ <argument index="0" name="secs" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
- <return type="real">
+ <method name="get_loop_restart_time" 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" >
- <return type="real">
+ <method name="get_pos" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="seek_pos" >
- <argument index="0" name="time" type="real">
+ <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" >
- <return type="real">
+ <method name="get_length" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
@@ -24387,20 +32806,20 @@
</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">
@@ -24409,14 +32828,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">
@@ -24425,21 +32844,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">
@@ -24450,7 +32869,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">
@@ -24459,7 +32878,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">
@@ -24470,34 +32889,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">
@@ -24508,51 +32928,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">
@@ -24561,14 +32985,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">
@@ -24577,7 +33001,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">
@@ -24586,7 +33010,19 @@
Do a simple, case insensitive, expression matching, using ? and * wildcards.
</description>
</method>
- <method name="nocasecmp_to" >
+ <method name="md5_buffer">
+ <return type="RawArray">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="md5_text">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="nocasecmp_to">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -24595,15 +33031,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">
@@ -24611,7 +33048,7 @@
<description>
</description>
</method>
- <method name="pad_zeros" >
+ <method name="pad_zeros">
<return type="String">
</return>
<argument index="0" name="digits" type="int">
@@ -24619,19 +33056,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">
@@ -24639,7 +33076,7 @@
<description>
</description>
</method>
- <method name="replace" >
+ <method name="replace">
<return type="String">
</return>
<argument index="0" name="what" type="String">
@@ -24650,7 +33087,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">
@@ -24661,7 +33098,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">
@@ -24672,7 +33109,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">
@@ -24683,7 +33120,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">
@@ -24692,7 +33129,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">
@@ -24703,7 +33140,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">
@@ -24714,14 +33151,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">
@@ -24729,42 +33166,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" >
- <return type="real">
+ <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_int" >
+ <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">
<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>
@@ -24777,13 +33231,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">
@@ -24791,19 +33245,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">
@@ -24811,13 +33265,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>
@@ -24829,13 +33285,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">
@@ -24846,17 +33302,17 @@
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="real">
+ <argument index="1" name="offset" type="float">
</argument>
<description>
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" >
- <return type="real">
+ <method name="get_default_margin" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="margin" type="int">
</argument>
@@ -24864,8 +33320,8 @@
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" >
- <return type="real">
+ <method name="get_margin" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="margin" type="int">
</argument>
@@ -24873,27 +33329,27 @@
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" >
+ <method name="draw" qualifiers="const">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Rect2">
@@ -24925,73 +33381,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>
@@ -25009,45 +33465,45 @@
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="real">
+ <argument index="1" name="size" type="float">
</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">
+ <method name="get_expand_margin_size" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="int">
</argument>
@@ -25067,57 +33523,57 @@
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="real">
+ <argument index="1" name="size" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_margin_size" qualifiers="const" >
- <return type="real">
+ <method name="get_margin_size" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" 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="real">
+ <argument index="1" name="size" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_expand_margin_size" qualifiers="const" >
- <return type="real">
+ <method name="get_expand_margin_size" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" 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>
@@ -25135,87 +33591,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="set_material" >
- <argument index="0" name="material" type="Material">
+ <method name="add_smooth_group">
+ <argument index="0" name="smooth" type="bool">
</argument>
<description>
</description>
</method>
- <method name="index" >
- <description>
- </description>
- </method>
- <method name="deindex" >
+ <method name="set_material">
+ <argument index="0" name="material" type="Material">
+ </argument>
<description>
</description>
</method>
- <method name="generate_flat_normals" >
+ <method name="index">
<description>
</description>
</method>
- <method name="generate_smooth_normals" >
+ <method name="deindex">
<description>
</description>
</method>
- <method name="generate_tangents" >
+ <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()">
@@ -25223,7 +33677,7 @@
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -25236,10 +33690,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">
@@ -25250,21 +33704,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>
@@ -25278,60 +33732,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">
@@ -25340,7 +33808,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">
@@ -25349,7 +33817,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">
@@ -25358,7 +33826,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">
@@ -25366,8 +33834,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>
@@ -25378,6 +33862,42 @@
</signals>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="label_valign_fg" type="int">
+ </theme_item>
+ <theme_item name="hseparation" type="int">
+ </theme_item>
+ <theme_item name="label_valign_bg" type="int">
+ </theme_item>
+ <theme_item name="top_margin" type="int">
+ </theme_item>
+ <theme_item name="side_margin" type="int">
+ </theme_item>
+ <theme_item name="font_color_bg" type="Color">
+ </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">
+ </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="tab_bg" type="StyleBox">
+ </theme_item>
+ <theme_item name="panel" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="Tabs" inherits="Control" category="Core">
<brief_description>
@@ -25387,25 +33907,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">
@@ -25413,7 +33933,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">
@@ -25421,7 +33941,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">
@@ -25429,7 +33949,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">
@@ -25437,14 +33957,46 @@
<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">
+ <argument index="0" name="title" type="String">
+ </argument>
+ <argument index="1" name="icon" type="Texture">
+ </argument>
+ <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>
@@ -25453,7 +34005,47 @@
</signal>
</signals>
<constants>
- </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">
+ </theme_item>
+ <theme_item name="hseparation" type="int">
+ </theme_item>
+ <theme_item name="label_valign_bg" type="int">
+ </theme_item>
+ <theme_item name="top_margin" type="int">
+ </theme_item>
+ <theme_item name="font_color_bg" type="Color">
+ </theme_item>
+ <theme_item name="font_color_fg" type="Color">
+ </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">
<brief_description>
@@ -25473,35 +34065,35 @@
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">
@@ -25510,76 +34102,78 @@
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="arg1" type="bool">
+ </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="arg1" type="bool">
+ </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">
@@ -25592,49 +34186,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="search" qualifiers="const" >
+ <method name="get_word_under_cursor" 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">
@@ -25649,45 +34249,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">
@@ -25697,24 +34297,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>
@@ -25732,10 +34332,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>
@@ -25751,6 +34347,50 @@
Search from end to begining.
</constant>
</constants>
+ <theme_items>
+ <theme_item name="line_spacing" type="int">
+ </theme_item>
+ <theme_item name="completion_lines" type="int">
+ </theme_item>
+ <theme_item name="completion_max_width" type="int">
+ </theme_item>
+ <theme_item name="completion_scroll_width" type="int">
+ </theme_item>
+ <theme_item name="symbol_color" type="Color">
+ </theme_item>
+ <theme_item name="cursor_color" type="Color">
+ </theme_item>
+ <theme_item name="selection_color" type="Color">
+ </theme_item>
+ <theme_item name="completion_existing" type="Color">
+ </theme_item>
+ <theme_item name="breakpoint_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="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">
+ </theme_item>
+ <theme_item name="tab" type="Texture">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ <theme_item name="focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="normal" type="StyleBox">
+ </theme_item>
+ <theme_item name="completion_selected" type="StyleBox">
+ </theme_item>
+ <theme_item name="completion" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="Texture" inherits="Resource" category="Core">
<brief_description>
@@ -25760,66 +34400,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="arg3" 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">
@@ -25828,10 +34469,12 @@
</argument>
<argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="4" name="arg4" 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">
@@ -25840,25 +34483,33 @@
</argument>
<argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="4" name="arg4" 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="16">
- Texture is a video surface
+ <constant name="FLAG_VIDEO_SURFACE" value="4096">
+ 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>
@@ -25867,82 +34518,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_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_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>
@@ -25955,37 +34630,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>
@@ -26003,44 +34678,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">
@@ -26048,11 +34783,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">
@@ -26062,7 +34797,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">
@@ -26072,7 +34807,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">
@@ -26082,7 +34817,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">
@@ -26090,7 +34825,7 @@
<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">
@@ -26098,7 +34833,7 @@
<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">
@@ -26108,7 +34843,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">
@@ -26118,7 +34853,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">
@@ -26128,7 +34863,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">
@@ -26136,7 +34871,7 @@
<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">
@@ -26144,7 +34879,7 @@
<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">
@@ -26154,7 +34889,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">
@@ -26164,7 +34899,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">
@@ -26174,7 +34909,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">
@@ -26182,7 +34917,7 @@
<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">
@@ -26190,7 +34925,7 @@
<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">
@@ -26200,7 +34935,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">
@@ -26210,7 +34945,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">
@@ -26220,7 +34955,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">
@@ -26228,7 +34963,7 @@
<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">
@@ -26236,7 +34971,7 @@
<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">
@@ -26246,7 +34981,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">
@@ -26256,7 +34991,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">
@@ -26266,7 +35001,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">
@@ -26274,7 +35009,7 @@
<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">
@@ -26282,19 +35017,19 @@
<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">
@@ -26302,7 +35037,7 @@
<description>
</description>
</method>
- <method name="copy_default_theme" >
+ <method name="copy_default_theme">
<description>
</description>
</method>
@@ -26316,8 +35051,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>
@@ -26330,19 +35065,19 @@
<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">
<description>
</description>
</method>
@@ -26358,84 +35093,231 @@
</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_cell_size" >
- <argument index="0" name="size" type="int">
+ <method name="set_mode">
+ <argument index="0" name="mode" type="int">
</argument>
<description>
- Set the cell size.
+ Set the orientation mode as square, isometric or custom (use MODE_* constants as argument).
+ </description>
+ </method>
+ <method name="get_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the orientation mode.
</description>
</method>
- <method name="get_cell_size" qualifiers="const" >
+ <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">
<return type="int">
</return>
<description>
+ Return the current half offset configuration.
+ </description>
+ </method>
+ <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">
+ <return type="Matrix32">
+ </return>
+ <description>
+ Return the custom transform matrix.
+ </description>
+ </method>
+ <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">
+ <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" >
+ <method name="get_quadrant_size" 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 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="set_center_x" >
+ <method name="get_tile_origin" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the tile origin configuration.
+ </description>
+ </method>
+ <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_cell" >
+ <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_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the collision mask.
+ </description>
+ </method>
+ <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">
+ <return type="float">
+ </return>
+ <description>
+ Return the collision friction parameter.
+ </description>
+ </method>
+ <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">
+ <return type="float">
+ </return>
+ <description>
+ Return the collision bounce parameter.
+ </description>
+ </method>
+ <method name="set_cell">
<argument index="0" name="x" type="int">
</argument>
<argument index="1" name="y" type="int">
@@ -26446,11 +35328,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">
@@ -26458,10 +35361,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">
@@ -26469,10 +35372,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">
@@ -26480,19 +35383,78 @@
<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="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">
+ </argument>
+ <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">
+ <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>
<constants>
<constant name="INVALID_CELL" value="-1">
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>
<class name="TileSet" inherits="Resource" category="Core">
@@ -26501,34 +35463,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">
@@ -26537,7 +35500,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">
@@ -26546,39 +35509,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">
@@ -26587,25 +35572,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">
@@ -26614,54 +35599,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="remove_tile" >
+ <method name="tile_set_navigation_polygon">
<argument index="0" name="id" type="int">
</argument>
+ <argument index="1" name="navigation_polygon" type="NavigationPolygon">
+ </argument>
<description>
- Remove a tile, by integer id.
+ Set a navigation polygon for the tile.
</description>
</method>
- <method name="clear" >
+ <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="tile_set_navigation_polygon_offset">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="navigation_polygon_offset" type="Vector2">
+ </argument>
+ <description>
+ Set an offset for the tile's navigation polygon.
+ </description>
+ </method>
+ <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>
@@ -26672,66 +35732,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" >
- <argument index="0" name="time_sec" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <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>
@@ -26743,7 +35817,47 @@
</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>
@@ -26751,79 +35865,79 @@
<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>
@@ -26831,11 +35945,11 @@
</method>
</methods>
<signals>
- <signal name="pressed">
+ <signal name="released">
<description>
</description>
</signal>
- <signal name="released">
+ <signal name="pressed">
<description>
</description>
</signal>
@@ -26851,20 +35965,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">
@@ -26874,23 +35988,23 @@
<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">
</argument>
- <argument index="1" name="phi" type="real">
+ <argument index="1" name="phi" type="float">
</argument>
<description>
</description>
</method>
- <method name="scaled" >
+ <method name="scaled">
<return type="Transform">
</return>
<argument index="0" name="scale" type="Vector3">
@@ -26898,7 +36012,7 @@
<description>
</description>
</method>
- <method name="translated" >
+ <method name="translated">
<return type="Transform">
</return>
<argument index="0" name="ofs" type="Vector3">
@@ -26906,7 +36020,7 @@
<description>
</description>
</method>
- <method name="xform" >
+ <method name="xform">
<return type="var">
</return>
<argument index="0" name="v" type="var">
@@ -26915,7 +36029,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">
@@ -26924,7 +36038,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">
@@ -26936,7 +36052,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">
@@ -26944,19 +36062,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>
@@ -26980,21 +36104,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">
@@ -27003,7 +36127,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">
@@ -27012,20 +36136,26 @@
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">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -27037,19 +36167,19 @@
<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">
@@ -27057,18 +36187,22 @@
<description>
</description>
</method>
- <method name="add_translation" >
+ <method name="add_translation">
<argument index="0" name="arg0" type="Object">
</argument>
<description>
</description>
</method>
- <method name="remove_translation" >
+ <method name="remove_translation">
<argument index="0" name="arg0" type="Object">
</argument>
<description>
</description>
</method>
+ <method name="clear">
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -27079,11 +36213,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()">
@@ -27091,13 +36225,13 @@
<description>
</description>
</method>
- <method name="get_root" >
+ <method name="get_root">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="set_column_min_width" >
+ <method name="set_column_min_width">
<argument index="0" name="arg0" type="int">
</argument>
<argument index="1" name="arg1" type="int">
@@ -27105,7 +36239,7 @@
<description>
</description>
</method>
- <method name="set_column_expand" >
+ <method name="set_column_expand">
<argument index="0" name="arg0" type="int">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -27113,7 +36247,7 @@
<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">
@@ -27121,13 +36255,13 @@
<description>
</description>
</method>
- <method name="set_hide_root" >
+ <method name="set_hide_root">
<argument index="0" name="arg0" 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">
@@ -27135,61 +36269,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">
@@ -27199,23 +36333,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">
@@ -27223,7 +36357,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">
@@ -27231,12 +36365,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">
@@ -27296,6 +36442,66 @@
<constant name="SELECT_MULTI" value="2">
</constant>
</constants>
+ <theme_items>
+ <theme_item name="item_margin" type="int">
+ </theme_item>
+ <theme_item name="vseparation" type="int">
+ </theme_item>
+ <theme_item name="guide_width" type="int">
+ </theme_item>
+ <theme_item name="hseparation" type="int">
+ </theme_item>
+ <theme_item name="button_margin" type="int">
+ </theme_item>
+ <theme_item name="title_button_color" type="Color">
+ </theme_item>
+ <theme_item name="guide_color" type="Color">
+ </theme_item>
+ <theme_item name="cursor_color" type="Color">
+ </theme_item>
+ <theme_item name="selection_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="arrow" type="Texture">
+ </theme_item>
+ <theme_item name="updown" type="Texture">
+ </theme_item>
+ <theme_item name="checked" type="Texture">
+ </theme_item>
+ <theme_item name="arrow_collapsed" type="Texture">
+ </theme_item>
+ <theme_item name="select_arrow" type="Texture">
+ </theme_item>
+ <theme_item name="unchecked" type="Texture">
+ </theme_item>
+ <theme_item name="title_button_font" type="Font">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ <theme_item name="title_button_normal" type="StyleBox">
+ </theme_item>
+ <theme_item name="cursor" type="StyleBox">
+ </theme_item>
+ <theme_item name="title_button_hover" 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="button_pressed" 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_item name="title_button_pressed" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="TreeItem" inherits="Object" category="Core">
<brief_description>
@@ -27303,7 +36509,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">
@@ -27311,7 +36517,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">
@@ -27319,7 +36525,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">
@@ -27327,7 +36533,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">
@@ -27335,7 +36541,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">
@@ -27343,7 +36549,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">
@@ -27351,7 +36557,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">
@@ -27359,7 +36565,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">
@@ -27367,7 +36573,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">
@@ -27375,7 +36581,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">
@@ -27383,7 +36589,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">
@@ -27391,7 +36597,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">
@@ -27399,37 +36605,37 @@
<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="real">
+ <argument index="1" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_range" qualifiers="const" >
- <return type="real">
+ <method name="get_range" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="column" type="int">
</argument>
<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="real">
+ <argument index="1" name="min" type="float">
</argument>
- <argument index="2" name="max" type="real">
+ <argument index="2" name="max" type="float">
</argument>
- <argument index="3" name="step" type="real">
+ <argument index="3" name="step" type="float">
</argument>
<argument index="4" name="expr" type="bool" default="false">
</argument>
<description>
</description>
</method>
- <method name="get_range_config" >
+ <method name="get_range_config">
<return type="Dictionary">
</return>
<argument index="0" name="column" type="int">
@@ -27437,7 +36643,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">
@@ -27445,13 +36651,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">
@@ -27461,61 +36667,61 @@
<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">
<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">
@@ -27523,7 +36729,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">
@@ -27531,7 +36737,7 @@
<description>
</description>
</method>
- <method name="is_selected" >
+ <method name="is_selected">
<return type="bool">
</return>
<argument index="0" name="column" type="int">
@@ -27539,19 +36745,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">
@@ -27559,7 +36765,7 @@
<description>
</description>
</method>
- <method name="is_editable" >
+ <method name="is_editable">
<return type="bool">
</return>
<argument index="0" name="column" type="int">
@@ -27567,7 +36773,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">
@@ -27575,13 +36781,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">
@@ -27589,13 +36795,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">
@@ -27603,7 +36809,7 @@
<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">
@@ -27613,7 +36819,7 @@
<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">
@@ -27621,7 +36827,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">
@@ -27631,7 +36837,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">
@@ -27639,7 +36845,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">
@@ -27647,7 +36853,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">
@@ -27655,11 +36861,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>
@@ -27677,45 +36883,501 @@
</constant>
</constants>
</class>
-<class name="UnshadedMaterial" inherits="Material" category="Core">
+<class name="Tween" inherits="Node" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
+ <method name="is_active" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_active">
+ <argument index="0" name="active" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_texture" qualifiers="const" >
- <return type="Texture">
+ <method name="is_repeat" qualifiers="const">
+ <return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_use_alpha" >
- <argument index="0" name="enable" type="bool">
+ <method name="set_repeat">
+ <argument index="0" name="repeat" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_speed">
+ <argument index="0" name="speed" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_speed" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_tween_process_mode">
+ <argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="is_using_alpha" qualifiers="const" >
+ <method name="get_tween_process_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="start">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_use_color_array" >
- <argument index="0" name="enable" type="bool">
+ <method name="reset">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="key" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="reset_all">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="stop">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="key" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="stop_all">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="resume">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="key" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="resume_all">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="remove">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="key" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_all">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="seek">
+ <return type="bool">
+ </return>
+ <argument index="0" name="time" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="tell" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_runtime" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="interpolate_property">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="property" type="String">
+ </argument>
+ <argument index="2" name="initial_val" type="var">
+ </argument>
+ <argument index="3" name="final_val" type="var">
+ </argument>
+ <argument index="4" name="times_in_sec" type="float">
+ </argument>
+ <argument index="5" name="trans_type" type="int">
+ </argument>
+ <argument index="6" name="ease_type" type="int">
+ </argument>
+ <argument index="7" name="delay" type="float" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="interpolate_method">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="method" type="String">
+ </argument>
+ <argument index="2" name="initial_val" type="var">
+ </argument>
+ <argument index="3" name="final_val" type="var">
+ </argument>
+ <argument index="4" name="times_in_sec" type="float">
+ </argument>
+ <argument index="5" name="trans_type" type="int">
+ </argument>
+ <argument index="6" name="ease_type" type="int">
+ </argument>
+ <argument index="7" name="delay" type="float" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="interpolate_callback">
+ <return type="bool">
+ </return>
+ <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="interpolate_deferred_callback">
+ <return type="bool">
+ </return>
+ <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="is_using_color_array" qualifiers="const" >
+ <method name="follow_property">
<return type="bool">
</return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="property" type="String">
+ </argument>
+ <argument index="2" name="initial_val" type="var">
+ </argument>
+ <argument index="3" name="target" type="Object">
+ </argument>
+ <argument index="4" name="target_property" type="String">
+ </argument>
+ <argument index="5" name="times_in_sec" type="float">
+ </argument>
+ <argument index="6" name="trans_type" type="int">
+ </argument>
+ <argument index="7" name="ease_type" type="int">
+ </argument>
+ <argument index="8" name="delay" type="float" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="follow_method">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="method" type="String">
+ </argument>
+ <argument index="2" name="initial_val" type="var">
+ </argument>
+ <argument index="3" name="target" type="Object">
+ </argument>
+ <argument index="4" name="target_method" type="String">
+ </argument>
+ <argument index="5" name="times_in_sec" type="float">
+ </argument>
+ <argument index="6" name="trans_type" type="int">
+ </argument>
+ <argument index="7" name="ease_type" type="int">
+ </argument>
+ <argument index="8" name="delay" type="float" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="targeting_property">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="property" type="String">
+ </argument>
+ <argument index="2" name="initial" type="Object">
+ </argument>
+ <argument index="3" name="initial_val" type="String">
+ </argument>
+ <argument index="4" name="final_val" type="var">
+ </argument>
+ <argument index="5" name="times_in_sec" type="float">
+ </argument>
+ <argument index="6" name="trans_type" type="int">
+ </argument>
+ <argument index="7" name="ease_type" type="int">
+ </argument>
+ <argument index="8" name="delay" type="float" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="targeting_method">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="method" type="String">
+ </argument>
+ <argument index="2" name="initial" type="Object">
+ </argument>
+ <argument index="3" name="initial_method" type="String">
+ </argument>
+ <argument index="4" name="final_val" type="var">
+ </argument>
+ <argument index="5" name="times_in_sec" type="float">
+ </argument>
+ <argument index="6" name="trans_type" type="int">
+ </argument>
+ <argument index="7" name="ease_type" type="int">
+ </argument>
+ <argument index="8" name="delay" type="float" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="tween_complete">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="key" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="tween_step">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="key" type="String">
+ </argument>
+ <argument index="2" name="elapsed" type="float">
+ </argument>
+ <argument index="3" name="value" type="Object">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="tween_start">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="key" type="String">
+ </argument>
+ <description>
+ </description>
+ </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">
+ </constant>
+ <constant name="TRANS_QUINT" value="2">
+ </constant>
+ <constant name="TRANS_QUART" value="3">
+ </constant>
+ <constant name="TRANS_QUAD" value="4">
+ </constant>
+ <constant name="TRANS_EXPO" value="5">
+ </constant>
+ <constant name="TRANS_ELASTIC" value="6">
+ </constant>
+ <constant name="TRANS_CUBIC" value="7">
+ </constant>
+ <constant name="TRANS_CIRC" value="8">
+ </constant>
+ <constant name="TRANS_BOUNCE" value="9">
+ </constant>
+ <constant name="TRANS_BACK" value="10">
+ </constant>
+ <constant name="EASE_IN" value="0">
+ </constant>
+ <constant name="EASE_OUT" value="1">
+ </constant>
+ <constant name="EASE_IN_OUT" value="2">
+ </constant>
+ <constant name="EASE_OUT_IN" value="3">
+ </constant>
+ </constants>
+</class>
+<class name="UndoRedo" inherits="Object" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <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="commit_action">
+ <description>
+ </description>
+ </method>
+ <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="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="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="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <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="var">
+ </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>
</method>
@@ -27734,6 +37396,10 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="separation" type="int">
+ </theme_item>
+ </theme_items>
</class>
<class name="VButtonArray" inherits="ButtonArray" category="Core">
<brief_description>
@@ -27746,6 +37412,28 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="button_separator" type="int">
+ </theme_item>
+ <theme_item name="icon_separator" type="int">
+ </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_selected" type="Font">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ <theme_item name="hover" type="StyleBox">
+ </theme_item>
+ <theme_item name="focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="selected" type="StyleBox">
+ </theme_item>
+ <theme_item name="normal" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="VScrollBar" inherits="ScrollBar" category="Core">
<brief_description>
@@ -27757,6 +37445,24 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <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="grabber_hilite" type="StyleBox">
+ </theme_item>
+ <theme_item name="grabber" type="StyleBox">
+ </theme_item>
+ <theme_item name="scroll_focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="scroll" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="VSeparator" inherits="Separator" category="Core">
<brief_description>
@@ -27769,6 +37475,12 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="separation" type="int">
+ </theme_item>
+ <theme_item name="separator" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="VSlider" inherits="Slider" category="Core">
<brief_description>
@@ -27781,6 +37493,18 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="tick" type="Texture">
+ </theme_item>
+ <theme_item name="grabber_hilite" type="Texture">
+ </theme_item>
+ <theme_item name="grabber" type="Texture">
+ </theme_item>
+ <theme_item name="grabber_hilite" type="StyleBox">
+ </theme_item>
+ <theme_item name="slider" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="VSplitContainer" inherits="SplitContainer" category="Core">
<brief_description>
@@ -27793,6 +37517,16 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="autohide" type="int">
+ </theme_item>
+ <theme_item name="separation" type="int">
+ </theme_item>
+ <theme_item name="grabber" type="Texture">
+ </theme_item>
+ <theme_item name="bg" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="Vector2" category="Built-In Types">
<brief_description>
@@ -27801,15 +37535,33 @@
<description>
</description>
<methods>
- <method name="angle_to" >
- <return type="real">
+ <method name="angle">
+ <return type="float">
+ </return>
+ <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">
+ <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="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">
@@ -27818,21 +37570,23 @@
</argument>
<argument index="2" name="post_b" type="Vector2">
</argument>
- <argument index="3" name="t" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <method name="distance_to">
+ <return type="float">
</return>
<argument index="0" name="to" type="Vector2">
</argument>
@@ -27840,8 +37594,8 @@
Returns the distance to vector "b".
</description>
</method>
- <method name="dot" >
- <return type="real">
+ <method name="dot">
+ <return type="float">
</return>
<argument index="0" name="with" type="Vector2">
</argument>
@@ -27849,111 +37603,121 @@
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" >
- <return type="real">
+ <method name="get_aspect">
+ <return type="float">
</return>
<description>
+ Returns the ratio of X to Y.
</description>
</method>
- <method name="length" >
- <return type="real">
+ <method name="length">
+ <return type="float">
</return>
<description>
Returns the length of the vector.
</description>
</method>
- <method name="length_squared" >
- <return type="real">
+ <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">
</argument>
- <argument index="1" name="t" type="real">
+ <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="real">
+ <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="real">
+ <argument index="0" name="phi" type="float">
</argument>
<description>
+ Rotates the vector by "phi" radians.
</description>
</method>
- <method name="slide" >
- <return type="real">
+ <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" >
- <argument index="0" name="x" type="real">
+ <method name="Vector2">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="x" type="float">
</argument>
- <argument index="1" name="y" type="real">
+ <argument index="1" name="y" type="float">
</argument>
<description>
+ Constructs a new Vector2 from the given x and y.
</description>
</method>
</methods>
<members>
- <member name="x" type="real">
+ <member name="x" type="float">
</member>
- <member name="y" type="real">
+ <member name="y" type="float">
</member>
- <member name="width" type="real">
+ <member name="width" type="float">
</member>
- <member name="height" type="real">
+ <member name="height" type="float">
</member>
</members>
<constants>
@@ -27961,48 +37725,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>
@@ -28014,16 +37788,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="ceil">
<return type="Vector3">
</return>
<description>
+ Returns a new vector with all components rounded up.
</description>
</method>
- <method name="cross" >
+ <method name="cross">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -28032,7 +37814,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">
@@ -28041,23 +37823,23 @@
</argument>
<argument index="2" name="post_b" type="Vector3">
</argument>
- <argument index="3" name="t" type="real">
+ <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" >
- <return type="real">
+ <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" >
- <return type="real">
+ <method name="distance_to">
+ <return type="float">
</return>
<argument index="0" name="b" type="Vector3">
</argument>
@@ -28065,8 +37847,8 @@
Return the distance to b.
</description>
</method>
- <method name="dot" >
- <return type="real">
+ <method name="dot">
+ <return type="float">
</return>
<argument index="0" name="b" type="Vector3">
</argument>
@@ -28074,286 +37856,536 @@
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" >
- <return type="real">
+ <method name="length">
+ <return type="float">
</return>
<description>
Return the length of the vector.
</description>
</method>
- <method name="length_squared" >
- <return type="real">
+ <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">
</argument>
- <argument index="1" name="t" type="real">
+ <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="rotated" >
+ <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">
<return type="Vector3">
</return>
<argument index="0" name="axis" type="Vector3">
</argument>
- <argument index="1" name="phi" type="real">
+ <argument index="1" name="phi" type="float">
+ </argument>
+ <description>
+ Rotates the vector around some axis by phi radians.
+ </description>
+ </method>
+ <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="real">
+ <argument index="0" name="by" type="float">
</argument>
<description>
Return a copy of the vector, snapped to the lowest neared multiple.
</description>
</method>
- <method name="Vector3" >
- <argument index="0" name="x" type="real">
+ <method name="Vector3">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="x" type="float">
</argument>
- <argument index="1" name="y" type="real">
+ <argument index="1" name="y" type="float">
</argument>
- <argument index="2" name="z" type="real">
+ <argument index="2" name="z" type="float">
</argument>
<description>
+ Returns a Vector3 with the given components.
</description>
</method>
</methods>
<members>
- <member name="x" type="real">
+ <member name="x" type="float">
</member>
- <member name="y" type="real">
+ <member name="y" type="float">
</member>
- <member name="z" type="real">
+ <member name="z" type="float">
</member>
</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>
<constants>
</constants>
</class>
-<class name="VideoPlayer" inherits="Control" category="Core">
+<class name="VehicleBody" inherits="PhysicsBody" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_stream" >
- <argument index="0" name="stream" type="Stream">
+ <method name="set_mass">
+ <argument index="0" name="mass" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_stream" qualifiers="const" >
- <return type="Stream">
+ <method name="get_mass" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="play" >
+ <method name="set_friction">
+ <argument index="0" name="friction" type="float">
+ </argument>
<description>
</description>
</method>
- <method name="stop" >
+ <method name="get_friction" qualifiers="const">
+ <return type="float">
+ </return>
<description>
</description>
</method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
+ <method name="set_engine_force">
+ <argument index="0" name="engine_force" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_engine_force" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_paused" >
- <argument index="0" name="paused" type="bool">
+ <method name="set_brake">
+ <argument index="0" name="brake" type="float">
</argument>
<description>
</description>
</method>
- <method name="is_paused" qualifiers="const" >
- <return type="bool">
+ <method name="get_brake" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_volume" >
- <argument index="0" name="volume" type="real">
+ <method name="set_steering">
+ <argument index="0" name="steering" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume" qualifiers="const" >
- <return type="real">
+ <method name="get_steering" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_volume_db" >
- <argument index="0" name="db" type="real">
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="VehicleWheel" inherits="Spatial" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_radius">
+ <argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
- <return type="real">
+ <method name="get_radius" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
+ <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">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
+ <method name="set_suspension_travel">
+ <argument index="0" name="length" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_suspension_travel" qualifiers="const">
+ <return type="float">
</return>
<description>
</description>
</method>
- <method name="set_autoplay" >
- <argument index="0" name="enabled" type="bool">
+ <method name="set_suspension_stiffness">
+ <argument index="0" name="length" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_suspension_stiffness" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_suspension_max_force">
+ <argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="has_autoplay" qualifiers="const" >
+ <method name="get_suspension_max_force" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_damping_compression">
+ <argument index="0" name="length" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_damping_compression" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_damping_relaxation">
+ <argument index="0" name="length" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_damping_relaxation" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_expand" >
+ <method name="set_use_as_steering">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_expand" qualifiers="const" >
+ <method name="is_used_as_steering" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
+ <method name="set_friction_slip">
+ <argument index="0" name="length" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_friction_slip" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
</class>
-<class name="VideoStream" inherits="AudioStreamResampled" category="Core">
+<class name="VideoPlayer" inherits="Control" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="get_pending_frame_count" qualifiers="const" >
+ <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="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_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="pop_frame" >
- <return type="Image">
+ <method name="get_stream_name" qualifiers="const">
+ <return type="String">
</return>
<description>
</description>
</method>
- <method name="peek_frame" qualifiers="const" >
- <return type="Image">
+ <method name="get_stream_pos" 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">
+ <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>
+ <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>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="VideoStream" inherits="Resource" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
</methods>
<constants>
</constants>
@@ -28373,104 +38405,104 @@
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)">
@@ -28480,105 +38512,217 @@
<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_update_mode" >
+ <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">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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_clear_on_new_frame" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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_filter" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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="get_viewport" qualifiers="const" >
+ <method name="set_physics_object_picking">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_physics_object_picking">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_viewport" qualifiers="const">
<return type="RID">
</return>
<description>
Get the viewport RID from the visual server.
</description>
</method>
- <method name="update_worlds" >
+ <method name="input">
+ <argument index="0" name="local_event" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="unhandled_input">
+ <argument index="0" name="local_event" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="update_worlds">
<description>
</description>
</method>
- <method name="set_as_audio_listener" >
+ <method name="set_use_own_world">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_audio_listener" qualifiers="const" >
+ <method name="is_using_own_world" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_as_audio_listener_2d" >
+ <method name="get_camera" qualifiers="const">
+ <return type="Camera">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_as_audio_listener">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_audio_listener" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <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">
+ </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>
+ </method>
</methods>
<signals>
<signal name="size_changed">
@@ -28597,13 +38741,71 @@
</constant>
</constants>
</class>
+<class name="ViewportSprite" inherits="Node2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_viewport_path">
+ <argument index="0" name="path" type="NodePath">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_viewport_path" qualifiers="const">
+ <return type="NodePath">
+ </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_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_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="VisibilityEnabler" inherits="VisibilityNotifier" category="Core">
<brief_description>
</brief_description>
<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">
@@ -28611,7 +38813,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">
@@ -28635,7 +38837,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">
@@ -28643,7 +38845,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">
@@ -28657,7 +38859,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>
@@ -28667,19 +38875,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>
@@ -28717,19 +38925,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>
@@ -28767,19 +38975,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>
@@ -28794,17 +39002,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">
@@ -28814,7 +39022,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">
@@ -28822,7 +39030,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">
@@ -28830,7 +39038,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">
@@ -28838,7 +39046,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">
@@ -28846,7 +39054,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">
@@ -28854,7 +39062,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">
@@ -28862,13 +39070,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">
@@ -28876,7 +39084,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">
@@ -28884,7 +39092,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">
@@ -28894,7 +39102,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">
@@ -28902,7 +39110,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">
@@ -28912,7 +39120,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">
@@ -28922,7 +39130,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">
@@ -28930,7 +39138,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">
@@ -28938,29 +39146,29 @@
<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="real">
+ <argument index="1" name="arg1" type="float">
</argument>
<description>
</description>
</method>
- <method name="material_get_line_width" qualifiers="const" >
- <return type="real">
+ <method name="material_get_line_width" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
<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">
@@ -28974,7 +39182,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">
@@ -28986,7 +39194,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">
@@ -28996,7 +39204,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">
@@ -29006,7 +39214,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">
@@ -29016,7 +39224,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">
@@ -29026,7 +39234,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">
@@ -29036,7 +39244,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">
@@ -29044,7 +39252,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">
@@ -29052,13 +39260,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">
@@ -29066,7 +39274,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">
@@ -29074,7 +39282,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">
@@ -29084,7 +39292,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">
@@ -29094,7 +39302,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">
@@ -29102,7 +39310,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">
@@ -29112,7 +39320,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">
@@ -29122,7 +39330,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">
@@ -29132,13 +39340,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">
@@ -29146,7 +39354,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">
@@ -29154,7 +39362,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">
@@ -29162,7 +39370,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">
@@ -29170,7 +39378,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">
@@ -29178,7 +39386,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">
@@ -29186,18 +39394,18 @@
<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">
</argument>
- <argument index="2" name="arg2" type="real">
+ <argument index="2" name="arg2" type="float">
</argument>
<description>
</description>
</method>
- <method name="particles_get_variable" qualifiers="const" >
- <return type="real">
+ <method name="particles_get_variable" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
@@ -29206,18 +39414,18 @@
<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">
</argument>
- <argument index="2" name="arg2" type="real">
+ <argument index="2" name="arg2" type="float">
</argument>
<description>
</description>
</method>
- <method name="particles_get_randomness" qualifiers="const" >
- <return type="real">
+ <method name="particles_get_randomness" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
@@ -29226,7 +39434,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">
@@ -29234,7 +39442,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">
@@ -29242,18 +39450,18 @@
<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">
</argument>
- <argument index="2" name="arg2" type="real">
+ <argument index="2" name="arg2" type="float">
</argument>
<description>
</description>
</method>
- <method name="particles_get_color_phase_pos" qualifiers="const" >
- <return type="real">
+ <method name="particles_get_color_phase_pos" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
@@ -29262,7 +39470,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">
@@ -29272,7 +39480,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">
@@ -29282,7 +39490,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">
@@ -29290,7 +39498,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">
@@ -29298,7 +39506,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">
@@ -29308,7 +39516,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">
@@ -29318,18 +39526,18 @@
<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">
</argument>
- <argument index="2" name="arg2" type="real">
+ <argument index="2" name="arg2" type="float">
</argument>
<description>
</description>
</method>
- <method name="particles_get_attractor_strength" qualifiers="const" >
- <return type="real">
+ <method name="particles_get_attractor_strength" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
@@ -29338,7 +39546,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">
@@ -29348,7 +39556,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">
@@ -29356,7 +39564,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">
@@ -29364,7 +39572,7 @@
<description>
</description>
</method>
- <method name="light_create" >
+ <method name="light_create">
<return type="RID">
</return>
<argument index="0" name="arg0" type="int">
@@ -29372,7 +39580,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">
@@ -29380,7 +39588,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">
@@ -29390,7 +39598,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">
@@ -29400,7 +39608,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">
@@ -29408,7 +39616,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">
@@ -29416,7 +39624,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">
@@ -29424,7 +39632,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">
@@ -29432,7 +39640,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">
@@ -29440,7 +39648,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">
@@ -29448,18 +39656,18 @@
<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">
</argument>
- <argument index="2" name="arg2" type="real">
+ <argument index="2" name="arg2" type="float">
</argument>
<description>
</description>
</method>
- <method name="light_get_var" qualifiers="const" >
- <return type="real">
+ <method name="light_get_var" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
@@ -29468,13 +39676,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">
@@ -29482,7 +39690,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">
@@ -29490,7 +39698,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">
@@ -29500,7 +39708,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">
@@ -29510,13 +39718,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">
@@ -29524,7 +39732,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">
@@ -29532,13 +39740,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">
@@ -29546,7 +39754,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">
@@ -29554,7 +39762,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">
@@ -29562,7 +39770,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">
@@ -29570,23 +39778,23 @@
<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="real">
+ <argument index="1" name="arg1" type="float">
</argument>
<description>
</description>
</method>
- <method name="portal_get_disable_distance" qualifiers="const" >
- <return type="real">
+ <method name="portal_get_disable_distance" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
<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">
@@ -29594,7 +39802,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">
@@ -29602,37 +39810,37 @@
<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="real">
+ <argument index="1" name="arg1" type="float">
</argument>
- <argument index="2" name="arg2" type="real">
+ <argument index="2" name="arg2" type="float">
</argument>
- <argument index="3" name="arg3" type="real">
+ <argument index="3" name="arg3" type="float">
</argument>
<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="real">
+ <argument index="1" name="arg1" type="float">
</argument>
- <argument index="2" name="arg2" type="real">
+ <argument index="2" name="arg2" type="float">
</argument>
- <argument index="3" name="arg3" type="real">
+ <argument index="3" name="arg3" type="float">
</argument>
<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">
@@ -29640,13 +39848,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">
@@ -29654,7 +39862,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">
@@ -29662,7 +39870,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()">
@@ -29670,7 +39878,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">
@@ -29678,7 +39886,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">
@@ -29686,7 +39894,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">
@@ -29694,7 +39902,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">
@@ -29702,7 +39910,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">
@@ -29710,13 +39918,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">
@@ -29724,13 +39932,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">
@@ -29738,7 +39946,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">
@@ -29746,7 +39954,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">
@@ -29754,7 +39962,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">
@@ -29762,7 +39970,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">
@@ -29770,7 +39978,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">
@@ -29778,7 +39986,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">
@@ -29786,7 +39994,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">
@@ -29794,7 +40002,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">
@@ -29802,7 +40010,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">
@@ -29810,7 +40018,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">
@@ -29818,7 +40026,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">
@@ -29826,7 +40034,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">
@@ -29836,7 +40044,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">
@@ -29848,19 +40056,17 @@
<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="Vector3">
- </argument>
- <argument index="1" name="arg1" type="Vector3">
+ <argument index="0" name="arg0" type="Array">
</argument>
- <argument index="2" name="arg2" type="RID">
+ <argument index="1" name="arg1" type="RID">
</argument>
<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">
@@ -29868,7 +40074,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">
@@ -29876,25 +40082,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">
@@ -29902,7 +40108,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">
@@ -29910,7 +40116,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">
@@ -29918,7 +40124,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">
@@ -29928,7 +40134,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">
@@ -29936,43 +40142,43 @@
<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="real">
+ <argument index="1" name="arg1" type="float">
</argument>
<description>
</description>
</method>
- <method name="canvas_item_get_opacity" qualifiers="const" >
- <return type="real">
+ <method name="canvas_item_get_opacity" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
- <argument index="1" name="arg1" type="real">
+ <argument index="1" name="arg1" type="float">
</argument>
<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="real">
+ <argument index="1" name="arg1" type="float">
</argument>
<description>
</description>
</method>
- <method name="canvas_item_get_self_opacity" qualifiers="const" >
- <return type="real">
+ <method name="canvas_item_get_self_opacity" qualifiers="const">
+ <return type="float">
</return>
<argument index="0" name="arg0" type="RID">
</argument>
- <argument index="1" name="arg1" type="real">
+ <argument index="1" name="arg1" type="float">
</argument>
<description>
</description>
</method>
- <method name="canvas_item_add_line" >
+ <method name="canvas_item_add_line">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Vector2">
@@ -29981,12 +40187,12 @@
</argument>
<argument index="3" name="arg3" type="Color">
</argument>
- <argument index="4" name="arg4" type="real" default="1">
+ <argument index="4" name="arg4" type="float" default="1">
</argument>
<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">
@@ -29996,7 +40202,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">
@@ -30007,10 +40213,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">
@@ -30021,10 +40229,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">
@@ -30038,19 +40248,19 @@
<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">
</argument>
- <argument index="2" name="arg2" type="real">
+ <argument index="2" name="arg2" type="float">
</argument>
<argument index="3" name="arg3" type="Color">
</argument>
<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">
@@ -30060,27 +40270,27 @@
<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" >
- <argument index="0" name="arg0" type="real">
+ <method name="cursor_set_rotation">
+ <argument index="0" name="arg0" type="float">
</argument>
<argument index="1" name="arg1" type="int">
</argument>
<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">
@@ -30090,7 +40300,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">
@@ -30098,7 +40308,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">
@@ -30106,7 +40316,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">
@@ -30118,19 +40328,31 @@
<description>
</description>
</method>
- <method name="make_sphere_mesh" >
+ <method name="black_bars_set_images">
+ <argument index="0" name="left" type="RID">
+ </argument>
+ <argument index="1" name="top" type="RID">
+ </argument>
+ <argument index="2" name="right" type="RID">
+ </argument>
+ <argument index="3" name="bottom" type="RID">
+ </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 index="2" name="arg2" type="float">
</argument>
<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">
@@ -30138,23 +40360,27 @@
<description>
</description>
</method>
- <method name="draw" >
+ <method name="draw">
+ <description>
+ </description>
+ </method>
+ <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">
@@ -30182,7 +40408,7 @@
</constant>
<constant name="TEXTURE_FLAG_FILTER" value="4">
</constant>
- <constant name="TEXTURE_FLAG_CUBEMAP" value="8">
+ <constant name="TEXTURE_FLAG_CUBEMAP" value="2048">
</constant>
<constant name="TEXTURE_FLAGS_DEFAULT" value="7">
</constant>
@@ -30212,10 +40438,6 @@
</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">
@@ -30336,11 +40558,9 @@
</constant>
<constant name="LIGHT_SPOT" value="2">
</constant>
- <constant name="LIGHT_COLOR_AMBIENT" value="0">
+ <constant name="LIGHT_COLOR_DIFFUSE" value="0">
</constant>
- <constant name="LIGHT_COLOR_DIFFUSE" value="1">
- </constant>
- <constant name="LIGHT_COLOR_SPECULAR" value="2">
+ <constant name="LIGHT_COLOR_SPECULAR" value="1">
</constant>
<constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="0">
</constant>
@@ -30352,7 +40572,7 @@
</constant>
<constant name="LIGHT_PARAM_ATTENUATION" value="4">
</constant>
- <constant name="LIGHT_PARAM_MAX" value="8">
+ <constant name="LIGHT_PARAM_MAX" value="10">
</constant>
<constant name="SCENARIO_DEBUG_DISABLED" value="0">
</constant>
@@ -30364,15 +40584,15 @@
</constant>
<constant name="INSTANCE_MULTIMESH" value="2">
</constant>
- <constant name="INSTANCE_PARTICLES" value="3">
+ <constant name="INSTANCE_PARTICLES" value="4">
</constant>
- <constant name="INSTANCE_LIGHT" value="4">
+ <constant name="INSTANCE_LIGHT" value="5">
</constant>
- <constant name="INSTANCE_ROOM" value="5">
+ <constant name="INSTANCE_ROOM" value="6">
</constant>
- <constant name="INSTANCE_PORTAL" value="6">
+ <constant name="INSTANCE_PORTAL" value="7">
</constant>
- <constant name="INSTANCE_GEOMETRY_MASK" value="14">
+ <constant name="INSTANCE_GEOMETRY_MASK" value="30">
</constant>
<constant name="INFO_OBJECTS_IN_FRAME" value="0">
</constant>
@@ -30396,6 +40616,20 @@
</constant>
</constants>
</class>
+<class name="WeakRef" inherits="Reference" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="get_ref" qualifiers="const">
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="WindowDialog" inherits="Popup" category="Core">
<brief_description>
Base class for window dialogs.
@@ -30404,21 +40638,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>
@@ -30428,6 +40662,26 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="close_h_ofs" type="int">
+ </theme_item>
+ <theme_item name="titlebar_height" 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">
+ </theme_item>
+ <theme_item name="close" type="Texture">
+ </theme_item>
+ <theme_item name="title_font" type="Font">
+ </theme_item>
+ <theme_item name="panel" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="World" inherits="Resource" category="Core">
<brief_description>
@@ -30437,36 +40691,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>
@@ -30479,24 +40739,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>
@@ -30507,13 +40773,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>
@@ -30529,43 +40795,43 @@
<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">
@@ -30573,7 +40839,7 @@
<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">
@@ -30581,7 +40847,7 @@
<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">
@@ -30589,7 +40855,7 @@
<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">
@@ -30597,7 +40863,7 @@
<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">
@@ -30605,23 +40871,23 @@
<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">
@@ -30629,7 +40895,7 @@
<description>
</description>
</method>
- <method name="open" >
+ <method name="open">
<return type="int">
</return>
<argument index="0" name="file" type="String">
@@ -30637,7 +40903,7 @@
<description>
</description>
</method>
- <method name="open_buffer" >
+ <method name="open_buffer">
<return type="int">
</return>
<argument index="0" name="buffer" type="RawArray">
@@ -30663,6 +40929,28 @@
</constant>
</constants>
</class>
+<class name="YSort" inherits="Node2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_sort_enabled">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_sort_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="bool" category="Built-In Types">
<brief_description>
Boolean built-in type
@@ -30671,19 +40959,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" >
- <argument index="0" name="from" type="real">
+ <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>
@@ -30693,27 +40987,31 @@
<constants>
</constants>
</class>
-<class name="int" category="Built-In Types">
+<class name="float" category="Built-In Types">
<brief_description>
- Integer built-in type.
</brief_description>
<description>
- Integer built-in type.
</description>
<methods>
- <method name="int" >
+ <method name="float">
+ <return type="float">
+ </return>
<argument index="0" name="from" type="bool">
</argument>
<description>
</description>
</method>
- <method name="int" >
- <argument index="0" name="from" type="real">
+ <method name="float">
+ <return type="float">
+ </return>
+ <argument index="0" name="from" type="int">
</argument>
<description>
</description>
</method>
- <method name="int" >
+ <method name="float">
+ <return type="float">
+ </return>
<argument index="0" name="from" type="String">
</argument>
<description>
@@ -30723,27 +41021,33 @@
<constants>
</constants>
</class>
-<class name="real" category="Built-In Types">
+<class name="int" category="Built-In Types">
<brief_description>
- Real (float) built-in type.
+ Integer built-in type.
</brief_description>
<description>
- Real (float) built-in type.
+ Integer built-in type.
</description>
<methods>
- <method name="real" >
+ <method name="int">
+ <return type="int">
+ </return>
<argument index="0" name="from" type="bool">
</argument>
<description>
</description>
</method>
- <method name="real" >
- <argument index="0" name="from" type="int">
+ <method name="int">
+ <return type="int">
+ </return>
+ <argument index="0" name="from" type="float">
</argument>
<description>
</description>
</method>
- <method name="real" >
+ <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
index 02b46ac4b9..c37b50f122 100644
--- a/doc/core_classes.xml
+++ b/doc/core_classes.xml
@@ -575,8 +575,8 @@
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).
+ </description>
<methods>
<method name="invert">
<description>
@@ -937,8 +937,8 @@
Vector used for 2D Math.
</brief_description>
<description>
- </description>
Vector class, which performs basic 2D vector math operations.
+ </description>
<methods>
<method name="operator+">
<argument index="0" name="b" type="Vector2">
diff --git a/doc/engine_classes.xml b/doc/engine_classes.xml
index fca2be0318..43602e26e9 100644
--- a/doc/engine_classes.xml
+++ b/doc/engine_classes.xml
@@ -6,31 +6,31 @@
<description>
</description>
<methods>
- <method name="get_ok" >
+ <method name="get_ok">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="get_label" >
+ <method name="get_label">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_hide_on_ok" >
+ <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" >
+ <method name="get_hide_on_ok" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="add_button" >
+ <method name="add_button">
<return type="Button">
</return>
<argument index="0" name="text" type="String" default="&quot;&quot;">
@@ -38,7 +38,7 @@
<description>
</description>
</method>
- <method name="add_cancel" >
+ <method name="add_cancel">
<return type="Button">
</return>
<argument index="0" name="name" type="String">
@@ -46,19 +46,19 @@
<description>
</description>
</method>
- <method name="register_text_enter" >
+ <method name="register_text_enter">
<argument index="0" name="line_edit" type="Object">
</argument>
<description>
</description>
</method>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
@@ -86,7 +86,7 @@
<description>
</description>
<methods>
- <method name="add_track" >
+ <method name="add_track">
<return type="int">
</return>
<argument index="0" name="type" type="int">
@@ -96,19 +96,19 @@
<description>
</description>
</method>
- <method name="remove_track" >
+ <method name="remove_track">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_track_count" qualifiers="const" >
+ <method name="get_track_count" qualifiers="const">
<return type="int">
</return>
<description>
</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">
@@ -116,7 +116,7 @@
<description>
</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">
@@ -124,7 +124,7 @@
<description>
</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">
@@ -132,19 +132,19 @@
<description>
</description>
</method>
- <method name="track_move_up" >
+ <method name="track_move_up">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="track_move_down" >
+ <method name="track_move_down">
<argument index="0" name="idx" type="int">
</argument>
<description>
</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">
@@ -160,7 +160,7 @@
<description>
</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="real">
@@ -172,7 +172,7 @@
<description>
</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">
@@ -180,7 +180,7 @@
<description>
</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="real">
@@ -188,7 +188,7 @@
<description>
</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">
@@ -198,7 +198,7 @@
<description>
</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">
@@ -208,7 +208,7 @@
<description>
</description>
</method>
- <method name="track_get_key_transition" qualifiers="const" >
+ <method name="track_get_key_transition" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="idx" type="int">
@@ -218,7 +218,7 @@
<description>
</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">
@@ -226,7 +226,7 @@
<description>
</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">
@@ -234,7 +234,7 @@
<description>
</description>
</method>
- <method name="track_get_key_time" qualifiers="const" >
+ <method name="track_get_key_time" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="idx" type="int">
@@ -244,7 +244,7 @@
<description>
</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">
@@ -256,7 +256,7 @@
<description>
</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">
@@ -264,7 +264,7 @@
<description>
</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">
@@ -272,7 +272,7 @@
<description>
</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">
@@ -282,7 +282,7 @@
<description>
</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">
@@ -290,7 +290,7 @@
<description>
</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">
@@ -298,7 +298,7 @@
<description>
</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">
@@ -310,7 +310,7 @@
<description>
</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">
@@ -322,7 +322,7 @@
<description>
</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">
@@ -332,7 +332,7 @@
<description>
</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">
@@ -342,31 +342,31 @@
<description>
</description>
</method>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="time_sec" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="real">
</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="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -392,7 +392,7 @@
<description>
</description>
<methods>
- <method name="add_animation" >
+ <method name="add_animation">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -402,13 +402,13 @@
<description>
</description>
</method>
- <method name="remove_animation" >
+ <method name="remove_animation">
<argument index="0" name="name" type="String">
</argument>
<description>
</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">
@@ -416,7 +416,7 @@
<description>
</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">
@@ -424,7 +424,7 @@
<description>
</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">
@@ -432,13 +432,13 @@
<description>
</description>
</method>
- <method name="get_animation_list" qualifiers="const" >
+ <method name="get_animation_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
</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">
@@ -448,7 +448,7 @@
<description>
</description>
</method>
- <method name="get_blend_time" qualifiers="const" >
+ <method name="get_blend_time" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="anim_from" type="String">
@@ -458,81 +458,81 @@
<description>
</description>
</method>
- <method name="play" >
+ <method name="play">
<argument index="0" name="name" type="String" default="&quot;&quot;">
</argument>
<description>
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
</description>
</method>
- <method name="stop_all" >
+ <method name="stop_all">
<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_current_animation" >
+ <method name="set_current_animation">
<argument index="0" name="anim" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_current_animation" qualifiers="const" >
+ <method name="get_current_animation" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="queue" >
+ <method name="queue">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_pause" >
+ <method name="set_pause">
<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_speed" >
+ <method name="set_speed">
<argument index="0" name="speed" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_speed" qualifiers="const" >
+ <method name="get_speed" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_autoplay" >
+ <method name="set_autoplay">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_autoplay" qualifiers="const" >
+ <method name="get_autoplay" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="seek" >
+ <method name="seek">
<argument index="0" name="pos_sec" type="real">
</argument>
<argument index="1" name="update" type="bool" default="false">
@@ -540,13 +540,13 @@
<description>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="real">
</return>
<description>
</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">
@@ -554,17 +554,17 @@
<description>
</description>
</method>
- <method name="clear_caches" >
+ <method name="clear_caches">
<description>
</description>
</method>
- <method name="set_animation_process_mode" >
+ <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" >
+ <method name="get_animation_process_mode" qualifiers="const">
<return type="int">
</return>
<description>
@@ -590,7 +590,7 @@
<description>
</description>
<methods>
- <method name="add_node" >
+ <method name="add_node">
<argument index="0" name="type" type="int">
</argument>
<argument index="1" name="id" type="int">
@@ -598,7 +598,7 @@
<description>
</description>
</method>
- <method name="get_node_id" qualifiers="const" >
+ <method name="get_node_id" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -606,7 +606,7 @@
<description>
</description>
</method>
- <method name="node_set_name" >
+ <method name="node_set_name">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="name" type="String">
@@ -614,7 +614,7 @@
<description>
</description>
</method>
- <method name="node_get_name" qualifiers="const" >
+ <method name="node_get_name" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="id" type="int">
@@ -622,7 +622,7 @@
<description>
</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="int">
@@ -630,7 +630,7 @@
<description>
</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="int">
@@ -638,7 +638,7 @@
<description>
</description>
</method>
- <method name="animation_node_set_animation" >
+ <method name="animation_node_set_animation">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="animation" type="Animation">
@@ -646,7 +646,7 @@
<description>
</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="int">
@@ -654,7 +654,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_fadein_time" >
+ <method name="oneshot_node_set_fadein_time">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="time_sec" type="real">
@@ -662,7 +662,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_get_fadein_time" qualifiers="const" >
+ <method name="oneshot_node_get_fadein_time" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="id" type="int">
@@ -670,7 +670,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_fadeout_time" >
+ <method name="oneshot_node_set_fadeout_time">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="time_sec" type="real">
@@ -678,7 +678,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_get_fadeout_time" qualifiers="const" >
+ <method name="oneshot_node_get_fadeout_time" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="id" type="int">
@@ -686,7 +686,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_autorestart" >
+ <method name="oneshot_node_set_autorestart">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="enable" type="bool">
@@ -694,7 +694,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_autorestart_delay" >
+ <method name="oneshot_node_set_autorestart_delay">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="delay_sec" type="real">
@@ -702,7 +702,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="int">
</argument>
<argument index="1" name="rand_sec" type="real">
@@ -710,7 +710,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="int">
@@ -718,7 +718,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_get_autorestart_delay" qualifiers="const" >
+ <method name="oneshot_node_get_autorestart_delay" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="id" type="int">
@@ -726,7 +726,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="real">
</return>
<argument index="0" name="id" type="int">
@@ -734,19 +734,19 @@
<description>
</description>
</method>
- <method name="oneshot_node_start" >
+ <method name="oneshot_node_start">
<argument index="0" name="id" type="int">
</argument>
<description>
</description>
</method>
- <method name="oneshot_node_stop" >
+ <method name="oneshot_node_stop">
<argument index="0" name="id" type="int">
</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="int">
@@ -754,7 +754,7 @@
<description>
</description>
</method>
- <method name="mix_node_set_amount" >
+ <method name="mix_node_set_amount">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="ratio" type="real">
@@ -762,7 +762,7 @@
<description>
</description>
</method>
- <method name="mix_node_get_amount" qualifiers="const" >
+ <method name="mix_node_get_amount" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="id" type="int">
@@ -770,7 +770,7 @@
<description>
</description>
</method>
- <method name="blend2_node_set_amount" >
+ <method name="blend2_node_set_amount">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="blend" type="real">
@@ -778,7 +778,7 @@
<description>
</description>
</method>
- <method name="blend2_node_get_amount" qualifiers="const" >
+ <method name="blend2_node_get_amount" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="id" type="int">
@@ -786,7 +786,7 @@
<description>
</description>
</method>
- <method name="blend3_node_set_amount" >
+ <method name="blend3_node_set_amount">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="blend" type="real">
@@ -794,7 +794,7 @@
<description>
</description>
</method>
- <method name="blend3_node_get_amount" qualifiers="const" >
+ <method name="blend3_node_get_amount" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="id" type="int">
@@ -802,7 +802,7 @@
<description>
</description>
</method>
- <method name="blend4_node_set_amount" >
+ <method name="blend4_node_set_amount">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="blend" type="Vector2">
@@ -810,7 +810,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="int">
@@ -818,7 +818,7 @@
<description>
</description>
</method>
- <method name="timescale_node_set_scale" >
+ <method name="timescale_node_set_scale">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="scale" type="real">
@@ -826,7 +826,7 @@
<description>
</description>
</method>
- <method name="timescale_node_get_scale" qualifiers="const" >
+ <method name="timescale_node_get_scale" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="id" type="int">
@@ -834,7 +834,7 @@
<description>
</description>
</method>
- <method name="timeseek_node_seek" >
+ <method name="timeseek_node_seek">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="pos_sec" type="real">
@@ -842,7 +842,7 @@
<description>
</description>
</method>
- <method name="transition_node_set_input_count" >
+ <method name="transition_node_set_input_count">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="count" type="int">
@@ -850,7 +850,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="int">
@@ -858,7 +858,7 @@
<description>
</description>
</method>
- <method name="transition_node_delete_input" >
+ <method name="transition_node_delete_input">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="input_idx" type="int">
@@ -866,7 +866,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="int">
</argument>
<argument index="1" name="input_idx" type="int">
@@ -876,7 +876,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="int">
@@ -886,7 +886,7 @@
<description>
</description>
</method>
- <method name="transition_node_set_xfade_time" >
+ <method name="transition_node_set_xfade_time">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="time_sec" type="real">
@@ -894,7 +894,7 @@
<description>
</description>
</method>
- <method name="transition_node_get_xfade_time" qualifiers="const" >
+ <method name="transition_node_get_xfade_time" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="id" type="int">
@@ -902,7 +902,7 @@
<description>
</description>
</method>
- <method name="transition_node_set_current" >
+ <method name="transition_node_set_current">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="input_idx" type="int">
@@ -910,7 +910,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="int">
@@ -918,7 +918,7 @@
<description>
</description>
</method>
- <method name="node_set_pos" >
+ <method name="node_set_pos">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="screen_pos" type="Vector2">
@@ -926,7 +926,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="int">
@@ -934,13 +934,13 @@
<description>
</description>
</method>
- <method name="remove_node" >
+ <method name="remove_node">
<argument index="0" name="id" type="int">
</argument>
<description>
</description>
</method>
- <method name="connect" >
+ <method name="connect">
<return type="int">
</return>
<argument index="0" name="id" type="int">
@@ -952,7 +952,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="int">
@@ -964,7 +964,7 @@
<description>
</description>
</method>
- <method name="disconnect" >
+ <method name="disconnect">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="dst_input_idx" type="int">
@@ -972,41 +972,41 @@
<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="get_node_list" >
+ <method name="get_node_list">
<return type="IntArray">
</return>
<description>
</description>
</method>
- <method name="reset" >
+ <method name="reset">
<description>
</description>
</method>
- <method name="recompute_caches" >
+ <method name="recompute_caches">
<description>
</description>
</method>
@@ -1040,85 +1040,85 @@
<description>
</description>
<methods>
- <method name="set_override_space_params" >
+ <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" >
+ <method name="is_overriding_space_params" qualifiers="const">
<return type="bool">
</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_vector">
<argument index="0" name="vector" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_gravity_vector" qualifiers="const" >
+ <method name="get_gravity_vector" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_gravity" >
+ <method name="set_gravity">
<argument index="0" name="gravity" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_gravity" qualifiers="const" >
+ <method name="get_gravity" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_density" >
+ <method name="set_density">
<argument index="0" name="density" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_density" qualifiers="const" >
+ <method name="get_density" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_priority" >
+ <method name="set_priority">
<argument index="0" name="priority" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_priority" qualifiers="const" >
+ <method name="get_priority" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_enable_monitoring" >
+ <method name="set_enable_monitoring">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_monitoring_enabled" qualifiers="const" >
+ <method name="is_monitoring_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -1176,7 +1176,7 @@
<description>
</description>
<methods>
- <method name="sample_create" >
+ <method name="sample_create">
<return type="RID">
</return>
<argument index="0" name="format" type="int">
@@ -1188,7 +1188,7 @@
<description>
</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">
@@ -1196,7 +1196,7 @@
<description>
</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">
@@ -1206,7 +1206,7 @@
<description>
</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">
@@ -1214,7 +1214,7 @@
<description>
</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">
@@ -1222,7 +1222,7 @@
<description>
</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">
@@ -1230,7 +1230,7 @@
<description>
</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">
@@ -1238,7 +1238,7 @@
<description>
</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">
@@ -1246,7 +1246,7 @@
<description>
</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">
@@ -1254,7 +1254,7 @@
<description>
</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">
@@ -1262,7 +1262,7 @@
<description>
</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">
@@ -1270,7 +1270,7 @@
<description>
</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">
@@ -1278,7 +1278,7 @@
<description>
</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">
@@ -1286,7 +1286,7 @@
<description>
</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">
@@ -1294,7 +1294,7 @@
<description>
</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">
@@ -1302,7 +1302,7 @@
<description>
</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">
@@ -1310,7 +1310,7 @@
<description>
</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">
@@ -1318,13 +1318,13 @@
<description>
</description>
</method>
- <method name="voice_create" >
+ <method name="voice_create">
<return type="RID">
</return>
<description>
</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">
@@ -1332,7 +1332,7 @@
<description>
</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="real">
@@ -1340,7 +1340,7 @@
<description>
</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="real">
@@ -1352,7 +1352,7 @@
<description>
</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">
@@ -1366,7 +1366,7 @@
<description>
</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="real">
@@ -1374,7 +1374,7 @@
<description>
</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">
@@ -1384,7 +1384,7 @@
<description>
</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">
@@ -1392,7 +1392,7 @@
<description>
</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">
@@ -1400,7 +1400,7 @@
<description>
</description>
</method>
- <method name="voice_get_volume" qualifiers="const" >
+ <method name="voice_get_volume" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="RID">
@@ -1408,7 +1408,7 @@
<description>
</description>
</method>
- <method name="voice_get_pan" qualifiers="const" >
+ <method name="voice_get_pan" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="RID">
@@ -1416,7 +1416,7 @@
<description>
</description>
</method>
- <method name="voice_get_pan_height" qualifiers="const" >
+ <method name="voice_get_pan_height" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="RID">
@@ -1424,7 +1424,7 @@
<description>
</description>
</method>
- <method name="voice_get_pan_depth" qualifiers="const" >
+ <method name="voice_get_pan_depth" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="RID">
@@ -1432,7 +1432,7 @@
<description>
</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">
@@ -1440,7 +1440,7 @@
<description>
</description>
</method>
- <method name="voice_get_filter_cutoff" qualifiers="const" >
+ <method name="voice_get_filter_cutoff" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="RID">
@@ -1448,7 +1448,7 @@
<description>
</description>
</method>
- <method name="voice_get_filter_resonance" qualifiers="const" >
+ <method name="voice_get_filter_resonance" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="RID">
@@ -1456,7 +1456,7 @@
<description>
</description>
</method>
- <method name="voice_get_chorus" qualifiers="const" >
+ <method name="voice_get_chorus" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="RID">
@@ -1464,7 +1464,7 @@
<description>
</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">
@@ -1472,7 +1472,7 @@
<description>
</description>
</method>
- <method name="voice_get_reverb" qualifiers="const" >
+ <method name="voice_get_reverb" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="RID">
@@ -1480,7 +1480,7 @@
<description>
</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">
@@ -1488,7 +1488,7 @@
<description>
</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">
@@ -1496,37 +1496,37 @@
<description>
</description>
</method>
- <method name="voice_stop" >
+ <method name="voice_stop">
<argument index="0" name="voice" type="RID">
</argument>
<description>
</description>
</method>
- <method name="free" >
+ <method name="free_rid">
<argument index="0" name="rid" type="RID">
</argument>
<description>
</description>
</method>
- <method name="set_stream_global_volume_scale" >
+ <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" >
+ <method name="get_stream_global_volume_scale" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_mixer_global_volume_scale" >
+ <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" >
+ <method name="get_mixer_global_volume_scale" qualifiers="const">
<return type="real">
</return>
<description>
@@ -1584,69 +1584,69 @@
<description>
</description>
<methods>
- <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_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="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="seek_pos" >
+ <method name="seek_pos">
<argument index="0" name="pos" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_update_mode" qualifiers="const" >
+ <method name="get_update_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="update" >
+ <method name="update">
<description>
</description>
</method>
@@ -1666,49 +1666,49 @@
<description>
</description>
<methods>
- <method name="set_phonemes" >
+ <method name="set_phonemes">
<argument index="0" name="phonemes" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_phonemes" qualifiers="const" >
+ <method name="get_phonemes" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_pitch_scale" >
+ <method name="set_pitch_scale">
<argument index="0" name="pitch_scale" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_pitch_scale" qualifiers="const" >
+ <method name="get_pitch_scale" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_pitch_random_scale" >
+ <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" >
+ <method name="get_pitch_random_scale" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_xfade_time" >
+ <method name="set_xfade_time">
<argument index="0" name="sec" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_xfade_time" qualifiers="const" >
+ <method name="get_xfade_time" qualifiers="const">
<return type="real">
</return>
<description>
@@ -1724,13 +1724,13 @@
<description>
</description>
<methods>
- <method name="set_file" >
+ <method name="set_file">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_file" qualifiers="const" >
+ <method name="get_file" qualifiers="const">
<return type="String">
</return>
<description>
@@ -1766,13 +1766,13 @@
<description>
</description>
<methods>
- <method name="set_file" >
+ <method name="set_file">
<argument index="0" name="file" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_file" qualifiers="const" >
+ <method name="get_file" qualifiers="const">
<return type="String">
</return>
<description>
@@ -1818,49 +1818,49 @@
<description>
</description>
<methods>
- <method name="set_pressed" >
+ <method name="set_pressed">
<argument index="0" name="pressed" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_pressed" qualifiers="const" >
+ <method name="is_pressed" 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>
</description>
</method>
- <method name="is_toggle_mode" qualifiers="const" >
+ <method name="is_toggle_mode" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_disabled" >
+ <method name="set_disabled">
<argument index="0" name="disabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_disabled" qualifiers="const" >
+ <method name="is_disabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_click_on_press" >
+ <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" >
+ <method name="get_click_on_press" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -1908,13 +1908,13 @@
<description>
</description>
<methods>
- <method name="set_extents" >
+ <method name="set_extents">
<argument index="0" name="extents" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_extents" qualifiers="const" >
+ <method name="get_extents" qualifiers="const">
<return type="Vector3">
</return>
<description>
@@ -1930,49 +1930,49 @@
<description>
</description>
<methods>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="set_icon" >
+ <method name="set_icon">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="get_icon" qualifiers="const" >
+ <method name="get_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>
</description>
</method>
- <method name="set_clip_text" >
+ <method name="set_clip_text">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_clip_text" qualifiers="const" >
+ <method name="get_clip_text" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_flat" qualifiers="const" >
+ <method name="is_flat" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -1988,13 +1988,13 @@
<description>
</description>
<methods>
- <method name="add_button" >
+ <method name="add_button">
<argument index="0" name="text" type="String">
</argument>
<description>
</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;">
@@ -2002,7 +2002,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">
@@ -2010,7 +2010,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">
@@ -2018,7 +2018,7 @@
<description>
</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">
@@ -2026,7 +2026,7 @@
<description>
</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">
@@ -2034,37 +2034,37 @@
<description>
</description>
</method>
- <method name="get_button_count" qualifiers="const" >
+ <method name="get_button_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_selected" qualifiers="const" >
+ <method name="get_selected" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_hovered" qualifiers="const" >
+ <method name="get_hovered" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_selected" >
+ <method name="set_selected">
<argument index="0" name="button" type="int">
</argument>
<description>
</description>
</method>
- <method name="erase_button" >
+ <method name="erase_button">
<argument index="0" name="button" type="int">
</argument>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -2096,31 +2096,31 @@
<description>
</description>
<methods>
- <method name="get_pressed_button" qualifiers="const" >
+ <method name="get_pressed_button" qualifiers="const">
<return type="BaseButton">
</return>
<description>
</description>
</method>
- <method name="get_pressed_button_index" qualifiers="const" >
+ <method name="get_pressed_button_index" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_focused_button" qualifiers="const" >
+ <method name="get_focused_button" qualifiers="const">
<return type="BaseButton">
</return>
<description>
</description>
</method>
- <method name="get_button_list" qualifiers="const" >
+ <method name="get_button_list" qualifiers="const">
<return type="Array">
</return>
<description>
</description>
</method>
- <method name="set_pressed_button" >
+ <method name="set_pressed_button">
<argument index="0" name="button" type="BaseButton">
</argument>
<description>
@@ -2136,7 +2136,7 @@
<description>
</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">
@@ -2144,7 +2144,7 @@
<description>
</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">
@@ -2152,7 +2152,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">
@@ -2160,7 +2160,7 @@
<description>
</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">
@@ -2168,7 +2168,7 @@
<description>
</description>
</method>
- <method name="project_position" qualifiers="const" >
+ <method name="project_position" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="screen_point" type="Vector2">
@@ -2176,7 +2176,7 @@
<description>
</description>
</method>
- <method name="set_perspective" >
+ <method name="set_perspective">
<argument index="0" name="fov" type="real">
</argument>
<argument index="1" name="z_near" type="real">
@@ -2186,7 +2186,7 @@
<description>
</description>
</method>
- <method name="set_orthogonal" >
+ <method name="set_orthogonal">
<argument index="0" name="size" type="real">
</argument>
<argument index="1" name="z_near" type="real">
@@ -2196,51 +2196,51 @@
<description>
</description>
</method>
- <method name="make_current" >
+ <method name="make_current">
<description>
</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>
</description>
</method>
- <method name="get_camera_transform" qualifiers="const" >
+ <method name="get_camera_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
</description>
</method>
- <method name="get_fov" qualifiers="const" >
+ <method name="get_fov" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_size" qualifiers="const" >
+ <method name="get_size" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_zfar" qualifiers="const" >
+ <method name="get_zfar" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_znear" qualifiers="const" >
+ <method name="get_znear" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_projection" qualifiers="const" >
+ <method name="get_projection" qualifiers="const">
<return type="int">
</return>
<description>
@@ -2260,41 +2260,41 @@
<description>
</description>
<methods>
- <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_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="make_current" >
+ <method name="make_current">
<description>
</description>
</method>
- <method name="is_current" qualifiers="const" >
+ <method name="is_current" qualifiers="const">
<return type="bool">
</return>
<description>
</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">
@@ -2302,7 +2302,7 @@
<description>
</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">
@@ -2310,7 +2310,7 @@
<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="real">
@@ -2318,7 +2318,7 @@
<description>
</description>
</method>
- <method name="get_drag_margin" qualifiers="const" >
+ <method name="get_drag_margin" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="margin" type="int">
@@ -2326,13 +2326,13 @@
<description>
</description>
</method>
- <method name="get_camera_pos" qualifiers="const" >
+ <method name="get_camera_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="force_update_scroll" >
+ <method name="force_update_scroll">
<description>
</description>
</method>
@@ -2346,113 +2346,113 @@
<description>
</description>
<methods>
- <method name="edit_set_state" >
+ <method name="edit_set_state">
<argument index="0" name="state" type="var">
</argument>
<description>
</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="real">
</argument>
<description>
</description>
</method>
- <method name="get_item_rect" qualifiers="const" >
+ <method name="get_item_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="get_canvas_item" qualifiers="const" >
+ <method name="get_canvas_item" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="is_visible" qualifiers="const" >
+ <method name="is_visible" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_hidden" qualifiers="const" >
+ <method name="is_hidden" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="show" >
+ <method name="show">
<description>
</description>
</method>
- <method name="hide" >
+ <method name="hide">
<description>
</description>
</method>
- <method name="update" >
+ <method name="update">
<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="set_blend_mode" >
+ <method name="set_blend_mode">
<argument index="0" name="blend_mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_blend_mode" qualifiers="const" >
+ <method name="get_blend_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_opacity" >
+ <method name="set_opacity">
<argument index="0" name="opacity" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_opacity" qualifiers="const" >
+ <method name="get_opacity" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_self_opacity" >
+ <method name="set_self_opacity">
<argument index="0" name="self_opacity" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_self_opacity" qualifiers="const" >
+ <method name="get_self_opacity" qualifiers="const">
<return type="real">
</return>
<description>
</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">
@@ -2464,7 +2464,7 @@
<description>
</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">
@@ -2472,7 +2472,7 @@
<description>
</description>
</method>
- <method name="draw_circle" >
+ <method name="draw_circle">
<argument index="0" name="pos" type="Vector2">
</argument>
<argument index="1" name="radius" type="real">
@@ -2482,7 +2482,7 @@
<description>
</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">
@@ -2490,7 +2490,7 @@
<description>
</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">
@@ -2499,10 +2499,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_texture_rect_region" >
+ <method name="draw_texture_rect_region">
<argument index="0" name="texture" type="Texture">
</argument>
<argument index="1" name="rect" type="Rect2">
@@ -2511,10 +2513,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_style_box" >
+ <method name="draw_style_box">
<argument index="0" name="style_box" type="StyleBox">
</argument>
<argument index="1" name="rect" type="Rect2">
@@ -2522,7 +2526,7 @@
<description>
</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">
@@ -2536,7 +2540,7 @@
<description>
</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">
@@ -2550,7 +2554,7 @@
<description>
</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="ColorArray">
@@ -2564,7 +2568,7 @@
<description>
</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">
@@ -2578,7 +2582,7 @@
<description>
</description>
</method>
- <method name="draw_char" >
+ <method name="draw_char">
<return type="real">
</return>
<argument index="0" name="font" type="Font">
@@ -2594,7 +2598,7 @@
<description>
</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="real">
@@ -2604,13 +2608,13 @@
<description>
</description>
</method>
- <method name="set_transform_notify" >
+ <method name="set_transform_notify">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_transform_notify_enabled" qualifiers="const" >
+ <method name="is_transform_notify_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -2662,73 +2666,73 @@
<description>
</description>
<methods>
- <method name="set_layer" >
+ <method name="set_layer">
<argument index="0" name="layer" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_layer" qualifiers="const" >
+ <method name="get_layer" qualifiers="const">
<return type="int">
</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_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_rotation" >
+ <method name="set_rotation">
<argument index="0" name="rotation" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_rotation" qualifiers="const" >
+ <method name="get_rotation" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_scale" >
+ <method name="set_scale">
<argument index="0" name="scale" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_scale" qualifiers="const" >
+ <method name="get_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_canvas" qualifiers="const" >
+ <method name="get_canvas" qualifiers="const">
<return type="Canvas">
</return>
<description>
</description>
</method>
- <method name="get_viewport" qualifiers="const" >
+ <method name="get_viewport" qualifiers="const">
<return type="RID">
</return>
<description>
@@ -2744,25 +2748,25 @@
<description>
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_height" >
+ <method name="set_height">
<argument index="0" name="height" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="real">
</return>
<description>
@@ -2778,25 +2782,25 @@
<description>
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_height" >
+ <method name="set_height">
<argument index="0" name="height" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="real">
</return>
<description>
@@ -2822,13 +2826,13 @@
<description>
</description>
<methods>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
@@ -2844,13 +2848,13 @@
<description>
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="real">
</return>
<description>
@@ -2866,7 +2870,7 @@
<description>
</description>
<methods>
- <method name="add_shape" >
+ <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">
@@ -2874,13 +2878,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">
@@ -2888,7 +2892,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="Matrix32">
@@ -2896,7 +2900,7 @@
<description>
</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">
@@ -2904,7 +2908,7 @@
<description>
</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">
@@ -2912,13 +2916,13 @@
<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>
@@ -2952,25 +2956,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_show_alpha" >
+ <method name="set_show_alpha">
<argument index="0" name="show" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_showing_alpha" qualifiers="const" >
+ <method name="is_showing_alpha" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -2994,13 +2998,13 @@
<description>
</description>
<methods>
- <method name="set_faces" >
+ <method name="set_faces">
<argument index="0" name="faces" type="Vector3Array">
</argument>
<description>
</description>
</method>
- <method name="get_faces" qualifiers="const" >
+ <method name="get_faces" qualifiers="const">
<return type="Vector3Array">
</return>
<description>
@@ -3016,13 +3020,13 @@
<description>
</description>
<methods>
- <method name="set_segments" >
+ <method name="set_segments">
<argument index="0" name="segments" type="Vector2Array">
</argument>
<description>
</description>
</method>
- <method name="get_segments" qualifiers="const" >
+ <method name="get_segments" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
@@ -3038,7 +3042,7 @@
<description>
</description>
<methods>
- <method name="get_cancel" >
+ <method name="get_cancel">
<return type="Button">
</return>
<description>
@@ -3054,11 +3058,11 @@
<description>
</description>
<methods>
- <method name="queue_sort" >
+ <method name="queue_sort">
<description>
</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">
@@ -3084,29 +3088,29 @@
<description>
</description>
<methods>
- <method name="accept_event" >
+ <method name="accept_event">
<description>
</description>
</method>
- <method name="get_minimum_size" qualifiers="const" >
+ <method name="get_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>
</description>
</method>
- <method name="get_window" qualifiers="const" >
+ <method name="get_window" qualifiers="const">
<return type="Object">
</return>
<description>
</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">
@@ -3114,7 +3118,7 @@
<description>
</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">
@@ -3122,7 +3126,7 @@
<description>
</description>
</method>
- <method name="set_margin" >
+ <method name="set_margin">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="offset" type="real">
@@ -3130,7 +3134,7 @@
<description>
</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">
@@ -3140,37 +3144,37 @@
<description>
</description>
</method>
- <method name="set_begin" >
+ <method name="set_begin">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="set_end" >
+ <method name="set_end">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="set_pos" >
+ <method name="set_pos">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="set_size" >
+ <method name="set_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>
</description>
</method>
- <method name="get_margin" qualifiers="const" >
+ <method name="get_margin" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="margin" type="int">
@@ -3178,141 +3182,141 @@
<description>
</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>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_size" qualifiers="const" >
+ <method name="get_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_parent_area_size" qualifiers="const" >
+ <method name="get_parent_area_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_global_pos" qualifiers="const" >
+ <method name="get_global_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_rect" qualifiers="const" >
+ <method name="get_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="get_global_rect" qualifiers="const" >
+ <method name="get_global_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
</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>
</description>
</method>
- <method name="show_modal" >
+ <method name="show_modal">
<argument index="0" name="exclusive" type="bool" default="false">
</argument>
<description>
</description>
</method>
- <method name="set_focus_mode" >
+ <method name="set_focus_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="has_focus" qualifiers="const" >
+ <method name="has_focus" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="grab_focus" >
+ <method name="grab_focus">
<description>
</description>
</method>
- <method name="release_focus" >
+ <method name="release_focus">
<description>
</description>
</method>
- <method name="get_focus_owner" qualifiers="const" >
+ <method name="get_focus_owner" qualifiers="const">
<return type="Control">
</return>
<description>
</description>
</method>
- <method name="set_h_size_flags" >
+ <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" >
+ <method name="get_h_size_flags" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_stretch_ratio" >
+ <method name="set_stretch_ratio">
<argument index="0" name="ratio" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_stretch_ratio" qualifiers="const" >
+ <method name="get_stretch_ratio" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_v_size_flags" >
+ <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" >
+ <method name="get_v_size_flags" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_theme" >
+ <method name="set_theme">
<argument index="0" name="theme" type="Theme">
</argument>
<description>
</description>
</method>
- <method name="get_theme" qualifiers="const" >
+ <method name="get_theme" qualifiers="const">
<return type="Theme">
</return>
<description>
</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">
@@ -3320,7 +3324,7 @@
<description>
</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">
@@ -3328,7 +3332,7 @@
<description>
</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">
@@ -3336,7 +3340,7 @@
<description>
</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">
@@ -3344,7 +3348,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">
@@ -3352,7 +3356,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">
@@ -3362,7 +3366,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">
@@ -3372,7 +3376,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">
@@ -3382,7 +3386,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">
@@ -3392,7 +3396,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">
@@ -3402,19 +3406,19 @@
<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>
</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)">
@@ -3422,19 +3426,19 @@
<description>
</description>
</method>
- <method name="set_default_cursor_shape" >
+ <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" >
+ <method name="get_default_cursor_shape" qualifiers="const">
<return type="int">
</return>
<description>
</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)">
@@ -3442,7 +3446,7 @@
<description>
</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">
@@ -3450,7 +3454,7 @@
<description>
</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">
@@ -3458,13 +3462,13 @@
<description>
</description>
</method>
- <method name="set_ignore_mouse" >
+ <method name="set_ignore_mouse">
<argument index="0" name="ignore" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_ignoring_mouse" qualifiers="const" >
+ <method name="is_ignoring_mouse" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -3574,13 +3578,13 @@
<description>
</description>
<methods>
- <method name="set_planes" >
+ <method name="set_planes">
<argument index="0" name="planes" type="Array">
</argument>
<description>
</description>
</method>
- <method name="get_planes" qualifiers="const" >
+ <method name="get_planes" qualifiers="const">
<return type="Array">
</return>
<description>
@@ -3596,13 +3600,13 @@
<description>
</description>
<methods>
- <method name="set_points" >
+ <method name="set_points">
<argument index="0" name="points" type="Vector2Array">
</argument>
<description>
</description>
</method>
- <method name="get_points" qualifiers="const" >
+ <method name="get_points" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
@@ -3628,49 +3632,49 @@
<description>
</description>
<methods>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="length" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_rest_length" >
+ <method name="set_rest_length">
<argument index="0" name="rest_length" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_rest_length" qualifiers="const" >
+ <method name="get_rest_length" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_stiffness" >
+ <method name="set_stiffness">
<argument index="0" name="stiffness" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_stiffness" qualifiers="const" >
+ <method name="get_stiffness" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_damping" >
+ <method name="set_damping">
<argument index="0" name="damping" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_damping" qualifiers="const" >
+ <method name="get_damping" qualifiers="const">
<return type="real">
</return>
<description>
@@ -3696,103 +3700,103 @@
<description>
</description>
<methods>
- <method name="set_mass" >
+ <method name="set_mass">
<argument index="0" name="mass" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_friction" >
+ <method name="set_friction">
<argument index="0" name="friction" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_bounce" >
+ <method name="set_bounce">
<argument index="0" name="bounce" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_mass" qualifiers="const" >
+ <method name="get_mass" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_friction" qualifiers="const" >
+ <method name="get_friction" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
+ <method name="get_bounce" qualifiers="const">
<return type="real">
</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_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_applied_force" >
+ <method name="set_applied_force">
<argument index="0" name="applied_force" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_applied_force" qualifiers="const" >
+ <method name="get_applied_force" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_applied_torque" >
+ <method name="set_applied_torque">
<argument index="0" name="applied_torque" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_applied_torque" qualifiers="const" >
+ <method name="get_applied_torque" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="apply_local_impulse" >
+ <method name="apply_local_impulse">
<argument index="0" name="pos" type="Vector3">
</argument>
<argument index="1" name="impulse" type="Vector3">
@@ -3800,31 +3804,31 @@
<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="set_direct_state_control" >
+ <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" >
+ <method name="is_direct_state_control_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_omit_force_integration" >
+ <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" >
+ <method name="is_omitting_force_integration" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -3850,7 +3854,7 @@
<description>
</description>
<methods>
- <method name="set_mode" >
+ <method name="set_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
@@ -3876,13 +3880,13 @@
<description>
</description>
<methods>
- <method name="set_minsize" >
+ <method name="set_minsize">
<argument index="0" name="minsize" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_minsize" qualifiers="const" >
+ <method name="get_minsize" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -3898,7 +3902,7 @@
<description>
</description>
<methods>
- <method name="open" >
+ <method name="open">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -3908,89 +3912,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="real">
</return>
<description>
</description>
</method>
- <method name="get_double" qualifiers="const" >
+ <method name="get_double" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_real" qualifiers="const" >
+ <method name="get_real" qualifiers="const">
<return type="real">
</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">
@@ -3998,101 +4002,101 @@
<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_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" >
+ <method name="get_error" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_var" qualifiers="const" >
+ <method name="get_var" qualifiers="const">
<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="real">
</argument>
<description>
</description>
</method>
- <method name="store_double" >
+ <method name="store_double">
<argument index="0" name="value" type="real">
</argument>
<description>
</description>
</method>
- <method name="store_real" >
+ <method name="store_real">
<argument index="0" name="value" type="real">
</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="file_exists" qualifiers="const" >
+ <method name="file_exists" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="path" type="String">
@@ -4116,65 +4120,65 @@
<description>
</description>
<methods>
- <method name="clear_filters" >
+ <method name="clear_filters">
<description>
</description>
</method>
- <method name="add_filter" >
+ <method name="add_filter">
<argument index="0" name="filter" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_current_dir" qualifiers="const" >
+ <method name="get_current_dir" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_current_file" qualifiers="const" >
+ <method name="get_current_file" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_current_path" qualifiers="const" >
+ <method name="get_current_path" qualifiers="const">
<return type="String">
</return>
<description>
</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>
</description>
</method>
- <method name="get_mode" qualifiers="const" >
+ <method name="get_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_vbox" >
+ <method name="get_vbox">
<return type="VBoxContainer">
</return>
<description>
@@ -4210,19 +4214,19 @@
<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_parameter" >
+ <method name="set_parameter">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="var">
@@ -4230,13 +4234,13 @@
<description>
</description>
</method>
- <method name="get_parameter" qualifiers="const" >
+ <method name="get_parameter" qualifiers="const">
<argument index="0" name="param" type="int">
</argument>
<description>
</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">
@@ -4244,7 +4248,7 @@
<description>
</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">
@@ -4252,19 +4256,19 @@
<description>
</description>
</method>
- <method name="set_texgen_mode" >
+ <method name="set_texgen_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_texgen_mode" qualifiers="const" >
+ <method name="get_texgen_mode" qualifiers="const">
<return type="int">
</return>
<description>
</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">
@@ -4272,7 +4276,7 @@
<description>
</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">
@@ -4280,25 +4284,25 @@
<description>
</description>
</method>
- <method name="set_uv_transform" >
+ <method name="set_uv_transform">
<argument index="0" name="transform" type="Transform">
</argument>
<description>
</description>
</method>
- <method name="get_uv_transform" qualifiers="const" >
+ <method name="get_uv_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
</description>
</method>
- <method name="set_detail_blend_mode" >
+ <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" >
+ <method name="get_detail_blend_mode" qualifiers="const">
<return type="int">
</return>
<description>
@@ -4358,205 +4362,205 @@
<description>
</description>
<methods>
- <method name="set_orbit" >
+ <method name="set_orbit">
<argument index="0" name="orbit" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_orbit" qualifiers="const" >
+ <method name="get_orbit" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_orbit_x" >
+ <method name="set_orbit_x">
<argument index="0" name="x" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_orbit_y" >
+ <method name="set_orbit_y">
<argument index="0" name="y" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_min_orbit_x" >
+ <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" >
+ <method name="get_min_orbit_x" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_max_orbit_x" >
+ <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" >
+ <method name="get_max_orbit_x" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_height" >
+ <method name="set_height">
<argument index="0" name="height" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_inclination" >
+ <method name="set_inclination">
<argument index="0" name="inclination" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_inclination" qualifiers="const" >
+ <method name="get_inclination" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="rotate_orbit" >
+ <method name="rotate_orbit">
<argument index="0" name="arg0" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="set_distance" >
+ <method name="set_distance">
<argument index="0" name="distance" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_distance" qualifiers="const" >
+ <method name="get_distance" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_max_distance" >
+ <method name="set_max_distance">
<argument index="0" name="max_distance" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_max_distance" qualifiers="const" >
+ <method name="get_max_distance" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_min_distance" >
+ <method name="set_min_distance">
<argument index="0" name="min_distance" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_min_distance" qualifiers="const" >
+ <method name="get_min_distance" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_clip" >
+ <method name="set_clip">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_clip" qualifiers="const" >
+ <method name="has_clip" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_autoturn" >
+ <method name="set_autoturn">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_autoturn" qualifiers="const" >
+ <method name="has_autoturn" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_autoturn_tolerance" >
+ <method name="set_autoturn_tolerance">
<argument index="0" name="degrees" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_autoturn_tolerance" qualifiers="const" >
+ <method name="get_autoturn_tolerance" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_autoturn_speed" >
+ <method name="set_autoturn_speed">
<argument index="0" name="speed" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_autoturn_speed" qualifiers="const" >
+ <method name="get_autoturn_speed" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_smoothing" >
+ <method name="set_smoothing">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_smoothing" qualifiers="const" >
+ <method name="has_smoothing" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_rotation_smoothing" >
+ <method name="set_rotation_smoothing">
<argument index="0" name="amount" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_rotation_smoothing" qualifiers="const" >
+ <method name="get_rotation_smoothing" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_translation_smoothing" >
+ <method name="set_translation_smoothing">
<argument index="0" name="amount" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_translation_smoothing" qualifiers="const" >
+ <method name="get_translation_smoothing" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_use_lookat_target" >
+ <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)">
@@ -4574,37 +4578,37 @@
<description>
</description>
<methods>
- <method name="set_height" >
+ <method name="set_height">
<argument index="0" name="px" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_ascent" >
+ <method name="set_ascent">
<argument index="0" name="px" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_ascent" qualifiers="const" >
+ <method name="get_ascent" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_descent" qualifiers="const" >
+ <method name="get_descent" qualifiers="const">
<return type="real">
</return>
<description>
</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">
@@ -4614,7 +4618,7 @@
<description>
</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">
@@ -4624,13 +4628,13 @@
<description>
</description>
</method>
- <method name="add_texture" >
+ <method name="add_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</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">
@@ -4644,7 +4648,7 @@
<description>
</description>
</method>
- <method name="get_char_size" qualifiers="const" >
+ <method name="get_char_size" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="char" type="int">
@@ -4654,7 +4658,7 @@
<description>
</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">
@@ -4662,11 +4666,11 @@
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</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">
@@ -4680,7 +4684,7 @@
<description>
</description>
</method>
- <method name="draw_char" qualifiers="const" >
+ <method name="draw_char" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="canvas_item" type="RID">
@@ -4706,7 +4710,7 @@
<description>
</description>
<methods>
- <method name="new" >
+ <method name="new">
<description>
</description>
</method>
@@ -4720,7 +4724,7 @@
<description>
</description>
<methods>
- <method name="new" >
+ <method name="new">
<description>
</description>
</method>
@@ -4744,7 +4748,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">
@@ -4752,7 +4756,7 @@
<description>
</description>
</method>
- <method name="build_cylinder_planes" >
+ <method name="build_cylinder_planes">
<return type="Array">
</return>
<argument index="0" name="radius" type="real">
@@ -4766,7 +4770,7 @@
<description>
</description>
</method>
- <method name="build_capsule_planes" >
+ <method name="build_capsule_planes">
<return type="Array">
</return>
<argument index="0" name="radius" type="real">
@@ -4782,7 +4786,7 @@
<description>
</description>
</method>
- <method name="segment_intersects_circle" >
+ <method name="segment_intersects_circle">
<return type="real">
</return>
<argument index="0" name="segment_from" type="Vector2">
@@ -4806,25 +4810,25 @@
<description>
</description>
<methods>
- <method name="set_visible" >
+ <method name="set_visible">
<argument index="0" name="visible" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_visible" qualifiers="const" >
+ <method name="is_visible" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_material_override" >
+ <method name="set_material_override">
<argument index="0" name="material" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_material_override" qualifiers="const" >
+ <method name="get_material_override" qualifiers="const">
<return type="Object">
</return>
<description>
@@ -4840,7 +4844,7 @@
<description>
</description>
<methods>
- <method name="has" qualifiers="const" >
+ <method name="has" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -4848,7 +4852,7 @@
<description>
</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">
@@ -4856,7 +4860,7 @@
<description>
</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">
@@ -4864,7 +4868,7 @@
<description>
</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">
@@ -4872,7 +4876,7 @@
<description>
</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">
@@ -4880,13 +4884,13 @@
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<argument index="0" name="name" type="String">
</argument>
<description>
</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">
@@ -4894,7 +4898,7 @@
<description>
</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">
@@ -4922,79 +4926,79 @@
<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_cell_size" >
+ <method name="set_cell_size">
<argument index="0" name="size" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_cell_size" qualifiers="const" >
+ <method name="get_cell_size" qualifiers="const">
<return type="real">
</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_width" >
+ <method name="set_width">
<argument index="0" name="width" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_width" qualifiers="const" >
+ <method name="get_width" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_height" >
+ <method name="set_height">
<argument index="0" name="height" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_depth" >
+ <method name="set_depth">
<argument index="0" name="depth" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_depth" qualifiers="const" >
+ <method name="get_depth" 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">
@@ -5008,7 +5012,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">
@@ -5020,7 +5024,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">
@@ -5032,49 +5036,49 @@
<description>
</description>
</method>
- <method name="resource_changed" >
+ <method name="resource_changed">
<argument index="0" name="arg0" 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">
@@ -5086,7 +5090,7 @@
<description>
</description>
</method>
- <method name="crate_area" >
+ <method name="crate_area">
<return type="int">
</return>
<argument index="0" name="id" type="int">
@@ -5096,7 +5100,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">
@@ -5104,7 +5108,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">
@@ -5112,7 +5116,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">
@@ -5120,7 +5124,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">
@@ -5128,7 +5132,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">
@@ -5136,7 +5140,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="real">
@@ -5144,7 +5148,7 @@
<description>
</description>
</method>
- <method name="area_get_portal_disable_distance" qualifiers="const" >
+ <method name="area_get_portal_disable_distance" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="area" type="int">
@@ -5152,7 +5156,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">
@@ -5160,7 +5164,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">
@@ -5168,13 +5172,13 @@
<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>
@@ -5192,25 +5196,25 @@
<description>
</description>
<methods>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="length" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_initial_offset" >
+ <method name="set_initial_offset">
<argument index="0" name="offset" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_initial_offset" qualifiers="const" >
+ <method name="get_initial_offset" qualifiers="const">
<return type="real">
</return>
<description>
@@ -5286,7 +5290,7 @@
<description>
</description>
<methods>
- <method name="resolve_hostname" >
+ <method name="resolve_hostname">
<return type="String">
</return>
<argument index="0" name="host" type="String">
@@ -5294,7 +5298,7 @@
<description>
</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">
@@ -5302,7 +5306,7 @@
<description>
</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">
@@ -5310,7 +5314,7 @@
<description>
</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">
@@ -5318,7 +5322,7 @@
<description>
</description>
</method>
- <method name="erase_resolve_item" >
+ <method name="erase_resolve_item">
<argument index="0" name="id" type="int">
</argument>
<description>
@@ -5366,43 +5370,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="Object">
</argument>
<description>
</description>
</method>
- <method name="set_speed" >
+ <method name="set_speed">
<argument index="0" name="speed" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_speed" qualifiers="const" >
+ <method name="get_speed" qualifiers="const">
<return type="real">
</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>
@@ -5418,25 +5422,25 @@
<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>
@@ -5452,61 +5456,61 @@
<description>
</description>
<methods>
- <method name="set_align" >
+ <method name="set_align">
<argument index="0" name="align" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_align" qualifiers="const" >
+ <method name="get_align" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_valign" >
+ <method name="set_valign">
<argument index="0" name="valign" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_valign" qualifiers="const" >
+ <method name="get_valign" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="set_autowrap" >
+ <method name="set_autowrap">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_autowrap" qualifiers="const" >
+ <method name="has_autowrap" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_line_height" qualifiers="const" >
+ <method name="get_line_height" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_line_count" qualifiers="const" >
+ <method name="get_line_count" qualifiers="const">
<return type="int">
</return>
<description>
@@ -5538,7 +5542,7 @@
<description>
</description>
<methods>
- <method name="set_parameter" >
+ <method name="set_parameter">
<argument index="0" name="variable" type="int">
</argument>
<argument index="1" name="value" type="real">
@@ -5546,7 +5550,7 @@
<description>
</description>
</method>
- <method name="get_parameter" qualifiers="const" >
+ <method name="get_parameter" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="int">
@@ -5554,7 +5558,7 @@
<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">
@@ -5562,7 +5566,7 @@
<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">
@@ -5570,37 +5574,37 @@
<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>
@@ -5634,81 +5638,81 @@
<description>
</description>
<methods>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
- <method name="select_all" >
+ <method name="select_all">
<description>
</description>
</method>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="set_cursor_pos" >
+ <method name="set_cursor_pos">
<argument index="0" name="pos" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_cursor_pos" qualifiers="const" >
+ <method name="get_cursor_pos" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_max_length" >
+ <method name="set_max_length">
<argument index="0" name="chars" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_max_length" qualifiers="const" >
+ <method name="get_max_length" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="append_at_cursor" >
+ <method name="append_at_cursor">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_editable" >
+ <method name="set_editable">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_editable" qualifiers="const" >
+ <method name="is_editable" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_secret" >
+ <method name="set_secret">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_secret" qualifiers="const" >
+ <method name="is_secret" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="select" qualifiers="const" >
+ <method name="select" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -5738,25 +5742,25 @@
<description>
</description>
<methods>
- <method name="set_normal" >
+ <method name="set_normal">
<argument index="0" name="normal" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_normal" qualifiers="const" >
+ <method name="get_normal" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_d" >
+ <method name="set_d">
<argument index="0" name="d" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_d" qualifiers="const" >
+ <method name="get_d" qualifiers="const">
<return type="real">
</return>
<description>
@@ -5772,7 +5776,7 @@
<description>
</description>
<methods>
- <method name="input_event" >
+ <method name="input_event">
<argument index="0" name="arg0" type="InputEvent">
</argument>
<description>
@@ -5804,7 +5808,7 @@
<description>
</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">
@@ -5812,7 +5816,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">
@@ -5820,7 +5824,7 @@
<description>
</description>
</method>
- <method name="set_hint" >
+ <method name="set_hint">
<argument index="0" name="hint" type="int">
</argument>
<argument index="1" name="enable" type="bool">
@@ -5828,7 +5832,7 @@
<description>
</description>
</method>
- <method name="get_hint" qualifiers="const" >
+ <method name="get_hint" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="hint" type="int">
@@ -5836,43 +5840,43 @@
<description>
</description>
</method>
- <method name="set_blend_mode" >
+ <method name="set_blend_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_blend_mode" qualifiers="const" >
+ <method name="get_blend_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_shade_model" >
+ <method name="set_shade_model">
<argument index="0" name="model" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_shade_model" qualifiers="const" >
+ <method name="get_shade_model" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_line_width" >
+ <method name="set_line_width">
<argument index="0" name="width" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_line_width" qualifiers="const" >
+ <method name="get_line_width" qualifiers="const">
<return type="real">
</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="arg1" type="var">
@@ -5880,7 +5884,7 @@
<description>
</description>
</method>
- <method name="get_shader_param" qualifiers="const" >
+ <method name="get_shader_param" qualifiers="const">
<argument index="0" name="arg0" type="String">
</argument>
<description>
@@ -5944,7 +5948,7 @@
<description>
</description>
<methods>
- <method name="get_popup" >
+ <method name="get_popup">
<return type="Object">
</return>
<description>
@@ -5966,19 +5970,19 @@
<description>
</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">
@@ -5986,23 +5990,23 @@
<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="format" type="int">
@@ -6014,19 +6018,19 @@
<description>
</description>
</method>
- <method name="get_surface_count" qualifiers="const" >
+ <method name="get_surface_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="surface_remove" >
+ <method name="surface_remove">
<argument index="0" name="surf_idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="surface_set_array" >
+ <method name="surface_set_array">
<return type="int">
</return>
<argument index="0" name="surf_idx" type="int">
@@ -6038,7 +6042,7 @@
<description>
</description>
</method>
- <method name="surface_get_array" qualifiers="const" >
+ <method name="surface_get_array" qualifiers="const">
<argument index="0" name="surf_idx" type="int">
</argument>
<argument index="1" name="array" type="int">
@@ -6046,7 +6050,7 @@
<description>
</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">
@@ -6054,7 +6058,7 @@
<description>
</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">
@@ -6062,7 +6066,7 @@
<description>
</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">
@@ -6070,7 +6074,7 @@
<description>
</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">
@@ -6078,7 +6082,7 @@
<description>
</description>
</method>
- <method name="surface_set_material" >
+ <method name="surface_set_material">
<argument index="0" name="surf_idx:Material" type="int">
</argument>
<argument index="1" name="arg1" type="Object">
@@ -6086,7 +6090,7 @@
<description>
</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">
@@ -6158,25 +6162,25 @@
<description>
</description>
<methods>
- <method name="set_mesh" >
+ <method name="set_mesh">
<argument index="0" name="mesh" type="Mesh">
</argument>
<description>
</description>
</method>
- <method name="get_mesh" qualifiers="const" >
+ <method name="get_mesh" qualifiers="const">
<return type="Mesh">
</return>
<description>
</description>
</method>
- <method name="get_aabb" qualifiers="const" >
+ <method name="get_aabb" qualifiers="const">
<return type="AABB">
</return>
<description>
</description>
</method>
- <method name="create_trimesh_collision" >
+ <method name="create_trimesh_collision">
<description>
</description>
</method>
@@ -6190,13 +6194,13 @@
<description>
</description>
<methods>
- <method name="create_item" >
+ <method name="create_item">
<argument index="0" name="id" type="int">
</argument>
<description>
</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">
@@ -6204,7 +6208,7 @@
<description>
</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">
@@ -6212,7 +6216,7 @@
<description>
</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">
@@ -6220,7 +6224,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">
@@ -6228,7 +6232,7 @@
<description>
</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">
@@ -6236,7 +6240,7 @@
<description>
</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">
@@ -6244,23 +6248,23 @@
<description>
</description>
</method>
- <method name="remove_item" >
+ <method name="remove_item">
<argument index="0" name="id" type="int">
</argument>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
- <method name="get_item_list" qualifiers="const" >
+ <method name="get_item_list" qualifiers="const">
<return type="IntArray">
</return>
<description>
</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>
@@ -6276,31 +6280,31 @@
<description>
</description>
<methods>
- <method name="set_mesh" >
+ <method name="set_mesh">
<argument index="0" name="mesh" type="Mesh">
</argument>
<description>
</description>
</method>
- <method name="get_mesh" qualifiers="const" >
+ <method name="get_mesh" qualifiers="const">
<return type="Mesh">
</return>
<description>
</description>
</method>
- <method name="set_instance_count" >
+ <method name="set_instance_count">
<argument index="0" name="arg0" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_instance_count" qualifiers="const" >
+ <method name="get_instance_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_instance_transform" >
+ <method name="set_instance_transform">
<argument index="0" name="arg0" type="int">
</argument>
<argument index="1" name="arg1" type="Transform">
@@ -6308,7 +6312,7 @@
<description>
</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">
@@ -6316,7 +6320,7 @@
<description>
</description>
</method>
- <method name="set_instance_color" >
+ <method name="set_instance_color">
<argument index="0" name="arg0" type="int">
</argument>
<argument index="1" name="arg1" type="Color">
@@ -6324,7 +6328,7 @@
<description>
</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">
@@ -6332,19 +6336,19 @@
<description>
</description>
</method>
- <method name="set_aabb" >
+ <method name="set_aabb">
<argument index="0" name="arg0" 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="generate_aabb" >
+ <method name="generate_aabb">
<description>
</description>
</method>
@@ -6358,13 +6362,13 @@
<description>
</description>
<methods>
- <method name="set_multimesh" >
+ <method name="set_multimesh">
<argument index="0" name="multimesh" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_multimesh" qualifiers="const" >
+ <method name="get_multimesh" qualifiers="const">
<return type="Object">
</return>
<description>
@@ -6380,43 +6384,43 @@
<description>
</description>
<methods>
- <method name="set_name" >
+ <method name="set_name">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_name" qualifiers="const" >
+ <method name="get_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="add_child" >
+ <method name="add_child">
<argument index="0" name="node" type="Node">
</argument>
<description>
</description>
</method>
- <method name="remove_child" >
+ <method name="remove_child">
<argument index="0" name="node" type="Node">
</argument>
<description>
</description>
</method>
- <method name="remove_and_delete_child" >
+ <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>
</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">
@@ -6424,7 +6428,7 @@
<description>
</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">
@@ -6432,7 +6436,7 @@
<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">
@@ -6440,13 +6444,13 @@
<description>
</description>
</method>
- <method name="get_parent" qualifiers="const" >
+ <method name="get_parent" qualifiers="const">
<return type="Parent">
</return>
<description>
</description>
</method>
- <method name="has_node_and_resource" qualifiers="const" >
+ <method name="has_node_and_resource" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="path" type="NodePath">
@@ -6454,7 +6458,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">
@@ -6462,13 +6466,13 @@
<description>
</description>
</method>
- <method name="is_inside_scene" qualifiers="const" >
+ <method name="is_inside_scene" 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">
@@ -6476,7 +6480,7 @@
<description>
</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">
@@ -6484,13 +6488,13 @@
<description>
</description>
</method>
- <method name="get_path" qualifiers="const" >
+ <method name="get_path" qualifiers="const">
<return type="NodePath">
</return>
<description>
</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">
@@ -6498,7 +6502,7 @@
<description>
</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">
@@ -6506,13 +6510,13 @@
<description>
</description>
</method>
- <method name="remove_from_group" >
+ <method name="remove_from_group">
<argument index="0" name="group" type="String">
</argument>
<description>
</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">
@@ -6520,7 +6524,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">
@@ -6528,167 +6532,167 @@
<description>
</description>
</method>
- <method name="raise" >
+ <method name="raise">
<description>
</description>
</method>
- <method name="set_owner" >
+ <method name="set_owner">
<argument index="0" name="owner" type="Node">
</argument>
<description>
</description>
</method>
- <method name="get_owner" qualifiers="const" >
+ <method name="get_owner" qualifiers="const">
<return type="Node">
</return>
<description>
</description>
</method>
- <method name="remove_and_skip" >
+ <method name="remove_and_skip">
<description>
</description>
</method>
- <method name="get_index" qualifiers="const" >
+ <method name="get_index" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="print_tree" >
+ <method name="print_tree">
<description>
</description>
</method>
- <method name="set_filename" >
+ <method name="set_filename">
<argument index="0" name="filename" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_filename" qualifiers="const" >
+ <method name="get_filename" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="propagate_notification" >
+ <method name="propagate_notification">
<argument index="0" name="what" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_process" >
+ <method name="set_process">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_process_time" qualifiers="const" >
+ <method name="get_process_time" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="is_processing" qualifiers="const" >
+ <method name="is_processing" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_idle_process" >
+ <method name="set_idle_process">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_idle_process_time" qualifiers="const" >
+ <method name="get_idle_process_time" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="is_idle_processing" qualifiers="const" >
+ <method name="is_idle_processing" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_process_input" >
+ <method name="set_process_input">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_processing_input" qualifiers="const" >
+ <method name="is_processing_input" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_process_unhandled_input" >
+ <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" >
+ <method name="is_processing_unhandled_input" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_process_mode" >
+ <method name="set_process_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_process_mode" qualifiers="const" >
+ <method name="get_process_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>
</description>
</method>
- <method name="print_stray_nodes" >
+ <method name="print_stray_nodes">
<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="get_current_world" qualifiers="const" >
+ <method name="get_current_world" qualifiers="const">
<return type="World">
</return>
<description>
</description>
</method>
- <method name="get_scene" qualifiers="const" >
+ <method name="get_scene" qualifiers="const">
<return type="SceneMainLoop">
</return>
<description>
</description>
</method>
- <method name="duplicate" qualifiers="const" >
+ <method name="duplicate" qualifiers="const">
<return type="Node">
</return>
<description>
</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">
@@ -6750,43 +6754,43 @@
<description>
</description>
<methods>
- <method name="set_pos" >
+ <method name="set_pos">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="set_rot" >
+ <method name="set_rot">
<argument index="0" name="rot" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_scale" >
+ <method name="set_scale">
<argument index="0" name="scale" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_rot" qualifiers="const" >
+ <method name="get_rot" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_scale" qualifiers="const" >
+ <method name="get_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_global_pos" qualifiers="const" >
+ <method name="get_global_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -6802,43 +6806,43 @@
<description>
</description>
<methods>
- <method name="set_mouse_show" >
+ <method name="set_mouse_show">
<argument index="0" name="show" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_mouse_grab" >
+ <method name="set_mouse_grab">
<argument index="0" name="grab" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_mouse_grab_enabled" qualifiers="const" >
+ <method name="is_mouse_grab_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_mouse_pos" qualifiers="const" >
+ <method name="get_mouse_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_clipboard" >
+ <method name="set_clipboard">
<argument index="0" name="clipboard" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_clipboard" qualifiers="const" >
+ <method name="get_clipboard" qualifiers="const">
<return type="String">
</return>
<description>
</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">
@@ -6850,7 +6854,7 @@
<description>
</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">
@@ -6858,7 +6862,7 @@
<description>
</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">
@@ -6866,7 +6870,7 @@
<description>
</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">
@@ -6874,7 +6878,7 @@
<description>
</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">
@@ -6882,37 +6886,37 @@
<description>
</description>
</method>
- <method name="set_iterations_per_second" >
+ <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" >
+ <method name="get_iterations_per_second" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_low_processor_usage_mode" >
+ <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" >
+ <method name="is_in_low_processor_usage_mode" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_executable_path" qualifiers="const" >
+ <method name="get_executable_path" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="execute" >
+ <method name="execute">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -6924,7 +6928,7 @@
<description>
</description>
</method>
- <method name="kill" >
+ <method name="kill">
<return type="int">
</return>
<argument index="0" name="pid" type="int">
@@ -6932,7 +6936,7 @@
<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">
@@ -6940,7 +6944,7 @@
<description>
</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">
@@ -6948,115 +6952,115 @@
<description>
</description>
</method>
- <method name="get_name" qualifiers="const" >
+ <method name="get_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_cmdline_args" >
+ <method name="get_cmdline_args">
<return type="StringArray">
</return>
<description>
</description>
</method>
- <method name="get_main_loop" qualifiers="const" >
+ <method name="get_main_loop" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="get_date" qualifiers="const" >
+ <method name="get_date" qualifiers="const">
<return type="Dictionary">
</return>
<description>
</description>
</method>
- <method name="get_time" qualifiers="const" >
+ <method name="get_time" qualifiers="const">
<return type="Dictionary">
</return>
<description>
</description>
</method>
- <method name="delay_usec" qualifiers="const" >
+ <method name="delay_usec" qualifiers="const">
<argument index="0" name="usec" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_ticks_msec" qualifiers="const" >
+ <method name="get_ticks_msec" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_locale" qualifiers="const" >
+ <method name="get_locale" 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>
</description>
</method>
- <method name="get_frames_drawn" >
+ <method name="get_frames_drawn">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="is_stdout_verbose" qualifiers="const" >
+ <method name="is_stdout_verbose" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_mouse_button_state" qualifiers="const" >
+ <method name="get_mouse_button_state" qualifiers="const">
<return type="int">
</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>
</description>
</method>
- <method name="get_dynamic_memory_usage" qualifiers="const" >
+ <method name="get_dynamic_memory_usage" qualifiers="const">
<return type="int">
</return>
<description>
@@ -7110,13 +7114,13 @@
<description>
</description>
<methods>
- <method name="get_type" qualifiers="const" >
+ <method name="get_type" qualifiers="const">
<return type="String">
</return>
<description>
</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">
@@ -7124,7 +7128,7 @@
<description>
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="property" type="String">
</argument>
<argument index="1" name="value" type="var">
@@ -7132,19 +7136,19 @@
<description>
</description>
</method>
- <method name="get" qualifiers="const" >
+ <method name="get" qualifiers="const">
<argument index="0" name="property" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_property_list" qualifiers="const" >
+ <method name="get_property_list" qualifiers="const">
<return type="Array">
</return>
<description>
</description>
</method>
- <method name="notification" >
+ <method name="notification">
<argument index="0" name="what" type="int">
</argument>
<argument index="1" name="arg1" type="bool" default="false">
@@ -7152,25 +7156,25 @@
<description>
</description>
</method>
- <method name="get_instance_ID" qualifiers="const" >
+ <method name="get_instance_ID" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_script" >
+ <method name="set_script">
<argument index="0" name="script" type="Script">
</argument>
<description>
</description>
</method>
- <method name="get_script" qualifiers="const" >
+ <method name="get_script" qualifiers="const">
<return type="Script">
</return>
<description>
</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">
@@ -7178,13 +7182,13 @@
<description>
</description>
</method>
- <method name="get_meta" qualifiers="const" >
+ <method name="get_meta" qualifiers="const">
<argument index="0" name="name" type="String">
</argument>
<description>
</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">
@@ -7192,13 +7196,13 @@
<description>
</description>
</method>
- <method name="get_meta_list" qualifiers="const" >
+ <method name="get_meta_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
</description>
</method>
- <method name="call" >
+ <method name="call">
<argument index="0" name="method" type="String">
</argument>
<argument index="1" name="arg1" type="var" default="NULL">
@@ -7212,7 +7216,7 @@
<description>
</description>
</method>
- <method name="call_deferred" >
+ <method name="call_deferred">
<argument index="0" name="method" type="String">
</argument>
<argument index="1" name="arg1" type="var" default="NULL">
@@ -7226,7 +7230,7 @@
<description>
</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()">
@@ -7234,7 +7238,7 @@
<description>
</description>
</method>
- <method name="emit_signal" >
+ <method name="emit_signal">
<argument index="0" name="signal" type="String">
</argument>
<argument index="1" name="arguments" type="Array" default="Array()">
@@ -7242,13 +7246,13 @@
<description>
</description>
</method>
- <method name="get_signal_list" qualifiers="const" >
+ <method name="get_signal_list" qualifiers="const">
<return type="Array">
</return>
<description>
</description>
</method>
- <method name="connect" >
+ <method name="connect">
<argument index="0" name="signal" type="String">
</argument>
<argument index="1" name="target" type="Object">
@@ -7262,7 +7266,7 @@
<description>
</description>
</method>
- <method name="disconnect" >
+ <method name="disconnect">
<argument index="0" name="signal" type="String">
</argument>
<argument index="1" name="target" type="Object">
@@ -7272,7 +7276,7 @@
<description>
</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">
@@ -7284,31 +7288,31 @@
<description>
</description>
</method>
- <method name="set_block_signals" >
+ <method name="set_block_signals">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_blocking_signals" qualifiers="const" >
+ <method name="is_blocking_signals" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_message_translation" >
+ <method name="set_message_translation">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="can_translate_messages" >
+ <method name="can_translate_messages">
<argument index="0" name="arg0" type="bool">
</argument>
<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">
@@ -7316,7 +7320,7 @@
<description>
</description>
</method>
- <method name="tr" qualifiers="const" >
+ <method name="tr" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="message" type="String">
@@ -7354,25 +7358,25 @@
<description>
</description>
<methods>
- <method name="set_target_platform" >
+ <method name="set_target_platform">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_target_platform" qualifiers="const" >
+ <method name="get_target_platform" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="set_target_name" >
+ <method name="set_target_name">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="add_property" >
+ <method name="add_property">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="value" type="var">
@@ -7380,7 +7384,7 @@
<description>
</description>
</method>
- <method name="optimize_object" >
+ <method name="optimize_object">
<return type="bool">
</return>
<argument index="0" name="obj" type="Object">
@@ -7398,7 +7402,7 @@
<description>
</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">
@@ -7406,7 +7410,7 @@
<description>
</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">
@@ -7416,7 +7420,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">
@@ -7424,7 +7428,7 @@
<description>
</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">
@@ -7432,7 +7436,7 @@
<description>
</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">
@@ -7440,7 +7444,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">
@@ -7448,7 +7452,7 @@
<description>
</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">
@@ -7456,7 +7460,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">
@@ -7464,7 +7468,7 @@
<description>
</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">
@@ -7472,7 +7476,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">
@@ -7480,13 +7484,13 @@
<description>
</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">
@@ -7494,43 +7498,43 @@
<description>
</description>
</method>
- <method name="get_item_count" qualifiers="const" >
+ <method name="get_item_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="add_separator" >
+ <method name="add_separator">
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
- <method name="select" >
+ <method name="select">
<argument index="0" name="arg0" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_selected" qualifiers="const" >
+ <method name="get_selected" qualifiers="const">
<return type="int">
</return>
<description>
</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>
@@ -7574,7 +7578,7 @@
<description>
</description>
<methods>
- <method name="set_stream_peer" >
+ <method name="set_stream_peer">
<argument index="0" name="peer" type="StreamPeer">
</argument>
<description>
@@ -7600,61 +7604,61 @@
<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>
@@ -7670,37 +7674,37 @@
<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_motion_wrap_begin" >
+ <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" >
+ <method name="get_motion_wrap_begin" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_motion_wrap_end" >
+ <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" >
+ <method name="get_motion_wrap_end" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -7716,91 +7720,91 @@
<description>
</description>
<methods>
- <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_emitting" >
+ <method name="set_emitting">
<argument index="0" name="enabled" 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_visibility_aabb" >
+ <method name="set_visibility_aabb">
<argument index="0" name="aabb" type="AABB">
</argument>
<description>
</description>
</method>
- <method name="get_visibility_aabb" qualifiers="const" >
+ <method name="get_visibility_aabb" qualifiers="const">
<return type="AABB">
</return>
<description>
</description>
</method>
- <method name="set_emission_half_extents" >
+ <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" >
+ <method name="get_emission_half_extents" qualifiers="const">
<return type="Vector3">
</return>
<description>
</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>
</description>
</method>
- <method name="get_gravity_normal" qualifiers="const" >
+ <method name="get_gravity_normal" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_variable" >
+ <method name="set_variable">
<argument index="0" name="variable" type="int">
</argument>
<argument index="1" name="value" type="real">
@@ -7808,7 +7812,7 @@
<description>
</description>
</method>
- <method name="get_variable" qualifiers="const" >
+ <method name="get_variable" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="variable" type="int">
@@ -7816,7 +7820,7 @@
<description>
</description>
</method>
- <method name="set_randomness" >
+ <method name="set_randomness">
<argument index="0" name="variable" type="int">
</argument>
<argument index="1" name="randomness" type="real">
@@ -7824,7 +7828,7 @@
<description>
</description>
</method>
- <method name="get_randomness" qualifiers="const" >
+ <method name="get_randomness" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="int">
@@ -7832,7 +7836,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="real">
@@ -7840,7 +7844,7 @@
<description>
</description>
</method>
- <method name="get_color_phase_pos" qualifiers="const" >
+ <method name="get_color_phase_pos" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="phase" type="int">
@@ -7848,7 +7852,7 @@
<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">
@@ -7856,7 +7860,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">
@@ -7864,49 +7868,49 @@
<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="Material">
</return>
<description>
</description>
</method>
- <method name="set_emit_timeout" >
+ <method name="set_emit_timeout">
<argument index="0" name="arg0" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_emit_timeout" qualifiers="const" >
+ <method name="get_emit_timeout" qualifiers="const">
<return type="real">
</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_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>
@@ -7950,67 +7954,67 @@
<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="real">
</argument>
<description>
</description>
</method>
- <method name="get_lifetime" qualifiers="const" >
+ <method name="get_lifetime" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_pre_process_time" >
+ <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" >
+ <method name="get_pre_process_time" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_emit_timeout" >
+ <method name="set_emit_timeout">
<argument index="0" name="value" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_emit_timeout" qualifiers="const" >
+ <method name="get_emit_timeout" qualifiers="const">
<return type="real">
</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="real">
@@ -8018,7 +8022,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="param" type="int">
@@ -8026,7 +8030,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="real">
@@ -8034,7 +8038,7 @@
<description>
</description>
</method>
- <method name="get_randomness" qualifiers="const" >
+ <method name="get_randomness" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="param" type="int">
@@ -8042,55 +8046,55 @@
<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="Texture">
</return>
<description>
</description>
</method>
- <method name="set_emissor_offset" >
+ <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_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">
@@ -8098,7 +8102,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">
@@ -8106,7 +8110,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="real">
@@ -8114,7 +8118,7 @@
<description>
</description>
</method>
- <method name="get_color_phase_pos" qualifiers="const" >
+ <method name="get_color_phase_pos" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="phase" type="int">
@@ -8122,37 +8126,37 @@
<description>
</description>
</method>
- <method name="pre_process" >
+ <method name="pre_process">
<argument index="0" name="time" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_use_local_space" >
+ <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="testee" >
+ <method name="testee">
<argument index="0" name="arg0" type="int" default="0">
</argument>
<argument index="1" name="arg1" type="int" default="1">
@@ -8202,7 +8206,7 @@
<description>
</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">
@@ -8210,7 +8214,7 @@
<description>
</description>
</method>
- <method name="has_remap" >
+ <method name="has_remap">
<argument index="0" name="path" type="String">
</argument>
<argument index="1" name="arg1" type="String">
@@ -8218,7 +8222,7 @@
<description>
</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">
@@ -8226,13 +8230,13 @@
<description>
</description>
</method>
- <method name="erase_remap" >
+ <method name="erase_remap">
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
- <method name="clear_remaps" >
+ <method name="clear_remaps">
<description>
</description>
</method>
@@ -8246,85 +8250,85 @@
<description>
</description>
<methods>
- <method name="get_total_gravity" qualifiers="const" >
+ <method name="get_total_gravity" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_total_density" qualifiers="const" >
+ <method name="get_total_density" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_inverse_mass" qualifiers="const" >
+ <method name="get_inverse_mass" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_inverse_inertia" qualifiers="const" >
+ <method name="get_inverse_inertia" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_linear_velocity" >
+ <method name="set_linear_velocity">
<argument index="0" name="velocity" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_linear_velocity" qualifiers="const" >
+ <method name="get_linear_velocity" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_angular_velocity" >
+ <method name="set_angular_velocity">
<argument index="0" name="velocity" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_angular_velocity" qualifiers="const" >
+ <method name="get_angular_velocity" qualifiers="const">
<return type="real">
</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_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="Vector2">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -8332,7 +8336,7 @@
<description>
</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">
@@ -8340,7 +8344,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">
@@ -8348,7 +8352,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">
@@ -8356,7 +8360,7 @@
<description>
</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">
@@ -8364,7 +8368,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">
@@ -8372,7 +8376,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">
@@ -8380,7 +8384,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">
@@ -8388,7 +8392,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="Vector2">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -8396,13 +8400,13 @@
<description>
</description>
</method>
- <method name="get_step" qualifiers="const" >
+ <method name="get_step" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="integrate_forces" >
+ <method name="integrate_forces">
<description>
</description>
</method>
@@ -8426,7 +8430,7 @@
<description>
</description>
<methods>
- <method name="shape_create" >
+ <method name="shape_create">
<return type="RID">
</return>
<argument index="0" name="type" type="int">
@@ -8434,7 +8438,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">
@@ -8442,7 +8446,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">
@@ -8450,19 +8454,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">
@@ -8470,7 +8474,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">
@@ -8478,7 +8482,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">
@@ -8488,7 +8492,7 @@
<description>
</description>
</method>
- <method name="space_get_param" qualifiers="const" >
+ <method name="space_get_param" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="space" type="RID">
@@ -8498,13 +8502,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">
@@ -8512,7 +8516,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">
@@ -8520,7 +8524,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="int">
@@ -8530,7 +8534,7 @@
<description>
</description>
</method>
- <method name="area_set_shape" qualifiers="const" >
+ <method name="area_set_shape" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="area" type="RID">
@@ -8540,7 +8544,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">
@@ -8550,7 +8554,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">
@@ -8558,7 +8562,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">
@@ -8568,7 +8572,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">
@@ -8578,7 +8582,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">
@@ -8586,13 +8590,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" qualifiers="const" >
+ <method name="area_set_param" qualifiers="const">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -8600,7 +8604,7 @@
<description>
</description>
</method>
- <method name="area_set_transform" qualifiers="const" >
+ <method name="area_set_transform" qualifiers="const">
<return type="Matrix32">
</return>
<argument index="0" name="area" type="RID">
@@ -8608,7 +8612,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">
@@ -8616,7 +8620,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">
@@ -8624,7 +8628,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">
@@ -8632,7 +8636,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">
@@ -8640,7 +8644,7 @@
<description>
</description>
</method>
- <method name="body_create" >
+ <method name="body_create">
<return type="RID">
</return>
<argument index="0" name="mode" type="int" default="1">
@@ -8650,7 +8654,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">
@@ -8658,7 +8662,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">
@@ -8666,7 +8670,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">
@@ -8674,7 +8678,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">
@@ -8684,7 +8688,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">
@@ -8694,7 +8698,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">
@@ -8704,7 +8708,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">
@@ -8714,7 +8718,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">
@@ -8722,7 +8726,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">
@@ -8732,7 +8736,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">
@@ -8742,7 +8746,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">
@@ -8750,13 +8754,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">
@@ -8764,7 +8768,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">
@@ -8772,7 +8776,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">
@@ -8780,7 +8784,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">
@@ -8788,7 +8792,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">
@@ -8798,7 +8802,7 @@
<description>
</description>
</method>
- <method name="body_get_param" qualifiers="const" >
+ <method name="body_get_param" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="body" type="RID">
@@ -8808,7 +8812,7 @@
<description>
</description>
</method>
- <method name="body_static_simulate_motion" >
+ <method name="body_static_simulate_motion">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="new_xform" type="Matrix32">
@@ -8816,7 +8820,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">
@@ -8826,7 +8830,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">
@@ -8834,7 +8838,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">
@@ -8844,7 +8848,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">
@@ -8852,7 +8856,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">
@@ -8860,7 +8864,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">
@@ -8868,7 +8872,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">
@@ -8876,7 +8880,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">
@@ -8884,7 +8888,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">
@@ -8892,7 +8896,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">
@@ -8900,7 +8904,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">
@@ -8912,7 +8916,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">
@@ -8928,7 +8932,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">
@@ -8942,7 +8946,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">
@@ -8952,7 +8956,7 @@
<description>
</description>
</method>
- <method name="damped_string_joint_get_param" qualifiers="const" >
+ <method name="damped_string_joint_get_param" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="joint" type="RID">
@@ -8962,7 +8966,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">
@@ -8970,7 +8974,7 @@
<description>
</description>
</method>
- <method name="query_create" >
+ <method name="query_create">
<return type="RID">
</return>
<argument index="0" name="receiver" type="Object">
@@ -8984,7 +8988,7 @@
<description>
</description>
</method>
- <method name="query_body_state" >
+ <method name="query_body_state">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="body" type="RID">
@@ -8992,7 +8996,7 @@
<description>
</description>
</method>
- <method name="query_body_direct_state" >
+ <method name="query_body_direct_state">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="body" type="RID">
@@ -9000,7 +9004,7 @@
<description>
</description>
</method>
- <method name="query_area" >
+ <method name="query_area">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="area" type="RID">
@@ -9008,7 +9012,7 @@
<description>
</description>
</method>
- <method name="query_intersection" >
+ <method name="query_intersection">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="space" type="RID">
@@ -9022,7 +9026,7 @@
<description>
</description>
</method>
- <method name="query_intersection_ray" >
+ <method name="query_intersection_ray">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="from" type="Vector2">
@@ -9032,7 +9036,7 @@
<description>
</description>
</method>
- <method name="query_intersection_segment" >
+ <method name="query_intersection_segment">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="from" type="Vector2">
@@ -9042,7 +9046,7 @@
<description>
</description>
</method>
- <method name="query_intersection_shape" >
+ <method name="query_intersection_shape">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="shape" type="RID">
@@ -9052,13 +9056,13 @@
<description>
</description>
</method>
- <method name="query_clear" >
+ <method name="query_clear">
<argument index="0" name="query" type="RID">
</argument>
<description>
</description>
</method>
- <method name="query_get_type" qualifiers="const" >
+ <method name="query_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="query" type="RID">
@@ -9066,7 +9070,7 @@
<description>
</description>
</method>
- <method name="query_get_target" qualifiers="const" >
+ <method name="query_get_target" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="query" type="RID">
@@ -9074,13 +9078,13 @@
<description>
</description>
</method>
- <method name="free" >
+ <method name="free">
<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>
@@ -9188,7 +9192,7 @@
<description>
</description>
<methods>
- <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()">
@@ -9196,13 +9200,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">
@@ -9210,7 +9214,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">
@@ -9218,7 +9222,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">
@@ -9226,7 +9230,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">
@@ -9234,41 +9238,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="get_body" qualifiers="const" >
+ <method name="get_body" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="set_max_contacts_reported" >
+ <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" >
+ <method name="get_max_contacts_reported" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_contacts_reported_depth_treshold" >
+ <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" >
+ <method name="get_contacts_reported_depth_treshold" qualifiers="const">
<return type="real">
</return>
<description>
@@ -9294,85 +9298,85 @@
<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_density" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_inverse_mass" qualifiers="const" >
+ <method name="get_inverse_mass" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_inverse_inertia_tensor" qualifiers="const" >
+ <method name="get_inverse_inertia_tensor" qualifiers="const">
<return type="Matrix3">
</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="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">
@@ -9380,7 +9384,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">
@@ -9388,7 +9392,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">
@@ -9396,7 +9400,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">
@@ -9404,7 +9408,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">
@@ -9412,7 +9416,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">
@@ -9420,7 +9424,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">
@@ -9428,7 +9432,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">
@@ -9456,7 +9460,7 @@
<description>
</description>
<methods>
- <method name="shape_create" >
+ <method name="shape_create">
<return type="RID">
</return>
<argument index="0" name="shape_type" type="int">
@@ -9464,7 +9468,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" default="-1">
@@ -9472,7 +9476,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">
@@ -9480,19 +9484,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="area_create" >
+ <method name="area_create">
<return type="RID">
</return>
<argument index="0" name="space" type="int">
@@ -9502,7 +9506,7 @@
<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">
@@ -9512,7 +9516,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" type="RID">
@@ -9520,7 +9524,7 @@
<description>
</description>
</method>
- <method name="area_set_bounds" >
+ <method name="area_set_bounds">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="bounds" type="Dictionary">
@@ -9528,7 +9532,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">
@@ -9536,7 +9540,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">
@@ -9544,7 +9548,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">
@@ -9552,7 +9556,7 @@
<description>
</description>
</method>
- <method name="area_get_bounds" qualifiers="const" >
+ <method name="area_get_bounds" qualifiers="const">
<return type="Dictionary">
</return>
<argument index="0" name="area" type="RID">
@@ -9560,7 +9564,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">
@@ -9568,7 +9572,7 @@
<description>
</description>
</method>
- <method name="body_create" >
+ <method name="body_create">
<return type="RID">
</return>
<argument index="0" name="space" type="int">
@@ -9578,7 +9582,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">
@@ -9586,7 +9590,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">
@@ -9596,7 +9600,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">
@@ -9606,7 +9610,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">
@@ -9616,7 +9620,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">
@@ -9626,7 +9630,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">
@@ -9634,7 +9638,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">
@@ -9644,7 +9648,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">
@@ -9654,7 +9658,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">
@@ -9662,7 +9666,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">
@@ -9670,7 +9674,7 @@
<description>
</description>
</method>
- <method name="body_set_user_flags" >
+ <method name="body_set_user_flags">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="user_flags" type="int">
@@ -9678,7 +9682,7 @@
<description>
</description>
</method>
- <method name="body_get_user_flags" qualifiers="const" >
+ <method name="body_get_user_flags" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -9688,7 +9692,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">
@@ -9698,7 +9702,7 @@
<description>
</description>
</method>
- <method name="body_get_param" qualifiers="const" >
+ <method name="body_get_param" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="body" type="RID">
@@ -9708,7 +9712,7 @@
<description>
</description>
</method>
- <method name="body_static_simulate_motion" >
+ <method name="body_static_simulate_motion">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="motion" type="Transform">
@@ -9716,7 +9720,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">
@@ -9726,7 +9730,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">
@@ -9734,7 +9738,7 @@
<description>
</description>
</method>
- <method name="body_set_applied_force" >
+ <method name="body_set_applied_force">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="applied_force" type="Vector3">
@@ -9742,7 +9746,7 @@
<description>
</description>
</method>
- <method name="body_get_applied_force" qualifiers="const" >
+ <method name="body_get_applied_force" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="body" type="RID">
@@ -9750,7 +9754,7 @@
<description>
</description>
</method>
- <method name="body_set_applied_torque" >
+ <method name="body_set_applied_torque">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="applied_torque" type="Vector3">
@@ -9758,7 +9762,7 @@
<description>
</description>
</method>
- <method name="body_get_applied_torque" qualifiers="const" >
+ <method name="body_get_applied_torque" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="body" type="RID">
@@ -9766,7 +9770,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">
@@ -9774,7 +9778,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">
@@ -9784,7 +9788,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="against_body" type="RID">
@@ -9792,7 +9796,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="against_body" type="RID">
@@ -9800,7 +9804,7 @@
<description>
</description>
</method>
- <method name="query_create" >
+ <method name="query_create">
<return type="RID">
</return>
<argument index="0" name="receiver" type="Object">
@@ -9814,7 +9818,7 @@
<description>
</description>
</method>
- <method name="query_body_state" >
+ <method name="query_body_state">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="body" type="RID">
@@ -9822,7 +9826,7 @@
<description>
</description>
</method>
- <method name="query_body_direct_state" >
+ <method name="query_body_direct_state">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="body" type="RID">
@@ -9830,7 +9834,7 @@
<description>
</description>
</method>
- <method name="query_area" >
+ <method name="query_area">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="area" type="RID">
@@ -9838,7 +9842,7 @@
<description>
</description>
</method>
- <method name="query_intersection" >
+ <method name="query_intersection">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="space" type="RID">
@@ -9850,7 +9854,7 @@
<description>
</description>
</method>
- <method name="query_intersection_ray" >
+ <method name="query_intersection_ray">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="origin" type="Vector3">
@@ -9860,7 +9864,7 @@
<description>
</description>
</method>
- <method name="query_intersection_segment" >
+ <method name="query_intersection_segment">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="from" type="Vector3">
@@ -9870,7 +9874,7 @@
<description>
</description>
</method>
- <method name="query_intersection_shape" >
+ <method name="query_intersection_shape">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="shape" type="RID">
@@ -9880,7 +9884,7 @@
<description>
</description>
</method>
- <method name="query_intersection_bounds" >
+ <method name="query_intersection_bounds">
<argument index="0" name="query" type="RID">
</argument>
<argument index="1" name="bounds" type="Dictionary">
@@ -9890,13 +9894,13 @@
<description>
</description>
</method>
- <method name="query_clear" >
+ <method name="query_clear">
<argument index="0" name="query" type="RID">
</argument>
<description>
</description>
</method>
- <method name="query_get_type" qualifiers="const" >
+ <method name="query_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="query" type="RID">
@@ -9904,7 +9908,7 @@
<description>
</description>
</method>
- <method name="query_get_target" qualifiers="const" >
+ <method name="query_get_target" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="query" type="RID">
@@ -9912,13 +9916,13 @@
<description>
</description>
</method>
- <method name="free" >
+ <method name="free">
<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>
@@ -10044,13 +10048,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>
@@ -10066,35 +10070,35 @@
<description>
</description>
<methods>
- <method name="popup_centered" >
+ <method name="popup_centered">
<argument index="0" name="size" type="Vector2" default="Vector2(0,0)">
</argument>
<description>
</description>
</method>
- <method name="popup_centered_ratio" >
+ <method name="popup_centered_ratio">
<argument index="0" name="ratio" type="real" default="0.75">
</argument>
<description>
</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>
</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>
@@ -10128,7 +10132,7 @@
<description>
</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">
@@ -10140,7 +10144,7 @@
<description>
</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">
@@ -10150,7 +10154,7 @@
<description>
</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">
@@ -10162,7 +10166,7 @@
<description>
</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">
@@ -10172,7 +10176,7 @@
<description>
</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="int">
@@ -10182,7 +10186,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">
@@ -10190,7 +10194,7 @@
<description>
</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">
@@ -10198,7 +10202,7 @@
<description>
</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">
@@ -10206,7 +10210,7 @@
<description>
</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">
@@ -10214,7 +10218,7 @@
<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">
@@ -10222,7 +10226,7 @@
<description>
</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">
@@ -10230,7 +10234,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">
@@ -10238,7 +10242,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">
@@ -10246,7 +10250,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">
@@ -10254,7 +10258,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">
@@ -10262,7 +10266,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">
@@ -10270,7 +10274,7 @@
<description>
</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">
@@ -10278,13 +10282,13 @@
<description>
</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">
@@ -10292,7 +10296,7 @@
<description>
</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">
@@ -10300,7 +10304,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">
@@ -10308,7 +10312,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">
@@ -10316,7 +10320,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">
@@ -10324,7 +10328,7 @@
<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">
@@ -10332,7 +10336,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">
@@ -10340,7 +10344,7 @@
<description>
</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">
@@ -10348,23 +10352,23 @@
<description>
</description>
</method>
- <method name="get_item_count" qualifiers="const" >
+ <method name="get_item_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="add_separator" >
+ <method name="add_separator">
<description>
</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>
</description>
</method>
@@ -10396,61 +10400,61 @@
<description>
</description>
<methods>
- <method name="set_shape" >
+ <method name="set_shape">
<argument index="0" name="points" type="Vector2Array">
</argument>
<description>
</description>
</method>
- <method name="get_shape" qualifiers="const" >
+ <method name="get_shape" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
</description>
</method>
- <method name="set_enabled" >
+ <method name="set_enabled">
<argument index="0" name="enable" 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_disable_distance" >
+ <method name="set_disable_distance">
<argument index="0" name="distance" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_disable_distance" qualifiers="const" >
+ <method name="get_disable_distance" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_disabled_color" >
+ <method name="set_disabled_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_disabled_color" qualifiers="const" >
+ <method name="get_disabled_color" qualifiers="const">
<return type="Color">
</return>
<description>
</description>
</method>
- <method name="set_connect_range" >
+ <method name="set_connect_range">
<argument index="0" name="range" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_connect_range" qualifiers="const" >
+ <method name="get_connect_range" qualifiers="const">
<return type="real">
</return>
<description>
@@ -10486,13 +10490,13 @@
<description>
</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">
@@ -10500,19 +10504,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>
@@ -10538,25 +10542,25 @@
<description>
</description>
<methods>
- <method name="set_group_size" >
+ <method name="set_group_size">
<argument index="0" name="size" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_group_size" qualifiers="const" >
+ <method name="get_group_size" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_group_notifym" >
+ <method name="set_group_notifym">
<argument index="0" name="notify" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_group_notify" qualifiers="const" >
+ <method name="get_group_notify" qualifiers="const">
<return type="int">
</return>
<description>
@@ -10586,121 +10590,121 @@
<description>
</description>
<methods>
- <method name="get_val" qualifiers="const" >
+ <method name="get_val" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_value" qualifiers="const" >
+ <method name="get_value" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_min" qualifiers="const" >
+ <method name="get_min" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_max" qualifiers="const" >
+ <method name="get_max" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_step" qualifiers="const" >
+ <method name="get_step" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_page" qualifiers="const" >
+ <method name="get_page" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_unit_value" qualifiers="const" >
+ <method name="get_unit_value" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_rounded_values" qualifiers="const" >
+ <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="real">
</argument>
<description>
</description>
</method>
- <method name="set_value" >
+ <method name="set_value">
<argument index="0" name="value" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_min" >
+ <method name="set_min">
<argument index="0" name="minimum" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_max" >
+ <method name="set_max">
<argument index="0" name="maximum" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_step" >
+ <method name="set_step">
<argument index="0" name="step" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_page" >
+ <method name="set_page">
<argument index="0" name="pagesize" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_unit_value" >
+ <method name="set_unit_value">
<argument index="0" name="value" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_rounded_values" >
+ <method name="set_rounded_values">
<argument index="0" name="arg0" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_exp_unit_value" >
+ <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>
@@ -10726,13 +10730,13 @@
<description>
</description>
<methods>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="length" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="real">
</return>
<description>
@@ -10748,13 +10752,13 @@
<description>
</description>
<methods>
- <method name="set_extents" >
+ <method name="set_extents">
<argument index="0" name="extents" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_extents" qualifiers="const" >
+ <method name="get_extents" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -10770,17 +10774,17 @@
<description>
</description>
<methods>
- <method name="init_ref" >
+ <method name="init_ref">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="reference" >
+ <method name="reference">
<description>
</description>
</method>
- <method name="unreference" >
+ <method name="unreference">
<return type="bool">
</return>
<description>
@@ -10806,31 +10810,31 @@
<description>
</description>
<methods>
- <method name="set_path" >
+ <method name="set_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>
</description>
</method>
- <method name="set_name" >
+ <method name="set_name">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_name" qualifiers="const" >
+ <method name="get_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_rid" qualifiers="const" >
+ <method name="get_rid" qualifiers="const">
<return type="RID">
</return>
<description>
@@ -10852,7 +10856,7 @@
<description>
</description>
<methods>
- <method name="load" >
+ <method name="load">
<return type="Resource">
</return>
<argument index="0" name="path" type="String">
@@ -10862,7 +10866,7 @@
<description>
</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">
@@ -10880,7 +10884,7 @@
<description>
</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">
@@ -10888,13 +10892,13 @@
<description>
</description>
</method>
- <method name="remove_resource" >
+ <method name="remove_resource">
<argument index="0" name="name" type="String">
</argument>
<description>
</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">
@@ -10902,7 +10906,7 @@
<description>
</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">
@@ -10910,7 +10914,7 @@
<description>
</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">
@@ -10918,7 +10922,7 @@
<description>
</description>
</method>
- <method name="get_resource_list" qualifiers="const" >
+ <method name="get_resource_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
@@ -10934,7 +10938,7 @@
<description>
</description>
<methods>
- <method name="save" >
+ <method name="save">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -10944,7 +10948,7 @@
<description>
</description>
</method>
- <method name="get_recognized_extensions" >
+ <method name="get_recognized_extensions">
<return type="StringArray">
</return>
<argument index="0" name="type" type="Object">
@@ -10962,113 +10966,113 @@
<description>
</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="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="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>
@@ -11128,145 +11132,145 @@
<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_mass" >
+ <method name="set_mass">
<argument index="0" name="mass" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_mass" qualifiers="const" >
+ <method name="get_mass" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_weight" >
+ <method name="set_weight">
<argument index="0" name="weight" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_weight" qualifiers="const" >
+ <method name="get_weight" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_friction" >
+ <method name="set_friction">
<argument index="0" name="friction" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_friction" qualifiers="const" >
+ <method name="get_friction" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_bounce" >
+ <method name="set_bounce">
<argument index="0" name="bounce" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
+ <method name="get_bounce" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_linear_velocity" >
+ <method name="set_linear_velocity">
<argument index="0" name="linear_velocity" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_linear_velocity" qualifiers="const" >
+ <method name="get_linear_velocity" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_angular_velocity" >
+ <method name="set_angular_velocity">
<argument index="0" name="angular_velocity" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_angular_velocity" qualifiers="const" >
+ <method name="get_angular_velocity" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_max_contacts_reported" >
+ <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="Vector2">
</argument>
<description>
</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">
@@ -11274,13 +11278,13 @@
<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_active" qualifiers="const" >
+ <method name="is_active" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -11344,25 +11348,25 @@
<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>
@@ -11378,29 +11382,29 @@
<description>
</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>
@@ -11426,7 +11430,7 @@
<description>
</description>
<methods>
- <method name="create" >
+ <method name="create">
<argument index="0" name="format" type="int">
</argument>
<argument index="1" name="stereo" type="bool">
@@ -11436,79 +11440,79 @@
<description>
</description>
</method>
- <method name="get_format" qualifiers="const" >
+ <method name="get_format" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="is_stereo" qualifiers="const" >
+ <method name="is_stereo" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_data" >
+ <method name="set_data">
<argument index="0" name="data" type="RawArray">
</argument>
<description>
</description>
</method>
- <method name="get_data" qualifiers="const" >
+ <method name="get_data" qualifiers="const">
<return type="RawArray">
</return>
<description>
</description>
</method>
- <method name="set_mix_rate" >
+ <method name="set_mix_rate">
<argument index="0" name="hz" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_mix_rate" qualifiers="const" >
+ <method name="get_mix_rate" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_loop_format" >
+ <method name="set_loop_format">
<argument index="0" name="format" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_loop_format" qualifiers="const" >
+ <method name="get_loop_format" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_loop_begin" >
+ <method name="set_loop_begin">
<argument index="0" name="pos" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_loop_begin" qualifiers="const" >
+ <method name="get_loop_begin" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_loop_end" >
+ <method name="set_loop_end">
<argument index="0" name="pos" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_loop_end" qualifiers="const" >
+ <method name="get_loop_end" qualifiers="const">
<return type="int">
</return>
<description>
@@ -11536,7 +11540,7 @@
<description>
</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">
@@ -11544,7 +11548,7 @@
<description>
</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">
@@ -11552,7 +11556,7 @@
<description>
</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">
@@ -11560,7 +11564,7 @@
<description>
</description>
</method>
- <method name="remove_sample" >
+ <method name="remove_sample">
<argument index="0" name="name" type="String">
</argument>
<description>
@@ -11576,31 +11580,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_voice_count" >
+ <method name="set_voice_count">
<argument index="0" name="max_voices" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_voice_count" qualifiers="const" >
+ <method name="get_voice_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="play" >
+ <method name="play">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -11610,17 +11614,17 @@
<description>
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<argument index="0" name="voice" type="int">
</argument>
<description>
</description>
</method>
- <method name="stop_all" >
+ <method name="stop_all">
<description>
</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">
@@ -11628,7 +11632,7 @@
<description>
</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="real">
@@ -11636,7 +11640,7 @@
<description>
</description>
</method>
- <method name="set_volume" >
+ <method name="set_volume">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="nrg" type="real">
@@ -11644,7 +11648,7 @@
<description>
</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="real">
@@ -11652,7 +11656,7 @@
<description>
</description>
</method>
- <method name="set_pan" >
+ <method name="set_pan">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="pan" type="real">
@@ -11664,7 +11668,7 @@
<description>
</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">
@@ -11678,7 +11682,7 @@
<description>
</description>
</method>
- <method name="set_chorus" >
+ <method name="set_chorus">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="send" type="real">
@@ -11686,7 +11690,7 @@
<description>
</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">
@@ -11696,7 +11700,7 @@
<description>
</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">
@@ -11704,7 +11708,7 @@
<description>
</description>
</method>
- <method name="get_pitch_scale" qualifiers="const" >
+ <method name="get_pitch_scale" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11712,7 +11716,7 @@
<description>
</description>
</method>
- <method name="get_volume" qualifiers="const" >
+ <method name="get_volume" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11720,7 +11724,7 @@
<description>
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
+ <method name="get_volume_db" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11728,7 +11732,7 @@
<description>
</description>
</method>
- <method name="get_pan" qualifiers="const" >
+ <method name="get_pan" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11736,7 +11740,7 @@
<description>
</description>
</method>
- <method name="get_pan_depth" qualifiers="const" >
+ <method name="get_pan_depth" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11744,7 +11748,7 @@
<description>
</description>
</method>
- <method name="get_pan_height" qualifiers="const" >
+ <method name="get_pan_height" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11752,7 +11756,7 @@
<description>
</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">
@@ -11760,7 +11764,7 @@
<description>
</description>
</method>
- <method name="get_filter_cutoff" qualifiers="const" >
+ <method name="get_filter_cutoff" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11768,7 +11772,7 @@
<description>
</description>
</method>
- <method name="get_filter_resonance" qualifiers="const" >
+ <method name="get_filter_resonance" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11776,7 +11780,7 @@
<description>
</description>
</method>
- <method name="get_filter_gain" qualifiers="const" >
+ <method name="get_filter_gain" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11784,7 +11788,7 @@
<description>
</description>
</method>
- <method name="get_chorus" qualifiers="const" >
+ <method name="get_chorus" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11792,7 +11796,7 @@
<description>
</description>
</method>
- <method name="get_reverb_room" qualifiers="const" >
+ <method name="get_reverb_room" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11800,7 +11804,7 @@
<description>
</description>
</method>
- <method name="get_reverb" qualifiers="const" >
+ <method name="get_reverb" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="voice" type="int">
@@ -11808,25 +11812,25 @@
<description>
</description>
</method>
- <method name="set_default_pitch_scale" >
+ <method name="set_default_pitch_scale">
<argument index="0" name="ratio" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_default_volume" >
+ <method name="set_default_volume">
<argument index="0" name="nrg" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_default_volume_db" >
+ <method name="set_default_volume_db">
<argument index="0" name="db" type="real">
</argument>
<description>
</description>
</method>
- <method name="set_default_pan" >
+ <method name="set_default_pan">
<argument index="0" name="pan" type="real">
</argument>
<argument index="1" name="depth" type="real" default="0">
@@ -11836,7 +11840,7 @@
<description>
</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="real">
@@ -11848,13 +11852,13 @@
<description>
</description>
</method>
- <method name="set_default_chorus" >
+ <method name="set_default_chorus">
<argument index="0" name="send" type="real">
</argument>
<description>
</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="real">
@@ -11862,91 +11866,91 @@
<description>
</description>
</method>
- <method name="get_default_pitch_scale" qualifiers="const" >
+ <method name="get_default_pitch_scale" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_volume" qualifiers="const" >
+ <method name="get_default_volume" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_volume_db" qualifiers="const" >
+ <method name="get_default_volume_db" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_pan" qualifiers="const" >
+ <method name="get_default_pan" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_pan_depth" qualifiers="const" >
+ <method name="get_default_pan_depth" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_pan_height" qualifiers="const" >
+ <method name="get_default_pan_height" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_filter_type" qualifiers="const" >
+ <method name="get_default_filter_type" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_default_filter_cutoff" qualifiers="const" >
+ <method name="get_default_filter_cutoff" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_filter_resonance" qualifiers="const" >
+ <method name="get_default_filter_resonance" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_filter_gain" qualifiers="const" >
+ <method name="get_default_filter_gain" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_chorus" qualifiers="const" >
+ <method name="get_default_chorus" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_reverb_room" qualifiers="const" >
+ <method name="get_default_reverb_room" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="get_default_reverb" qualifiers="const" >
+ <method name="get_default_reverb" qualifiers="const">
<return type="real">
</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="is_voice_active" qualifiers="const" >
+ <method name="is_voice_active" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="voice" type="int">
@@ -12000,7 +12004,7 @@
<description>
</description>
<methods>
- <method name="load" >
+ <method name="load">
<return type="Object">
</return>
<argument index="0" name="path" type="String">
@@ -12008,7 +12012,7 @@
<description>
</description>
</method>
- <method name="save" >
+ <method name="save">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -12022,7 +12026,7 @@
<description>
</description>
</method>
- <method name="load_interactive" >
+ <method name="load_interactive">
<return type="SceneInteractiveLoader">
</return>
<argument index="0" name="path" type="String">
@@ -12040,37 +12044,37 @@
<description>
</description>
<methods>
- <method name="get_default_world" qualifiers="const" >
+ <method name="get_default_world" qualifiers="const">
<return type="World">
</return>
<description>
</description>
</method>
- <method name="get_default_viewport" qualifiers="const" >
+ <method name="get_default_viewport" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="get_default_viewport_size" qualifiers="const" >
+ <method name="get_default_viewport_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_default_canvas" qualifiers="const" >
+ <method name="get_default_canvas" qualifiers="const">
<return type="Canvas">
</return>
<description>
</description>
</method>
- <method name="get_default_space_2d" qualifiers="const" >
+ <method name="get_default_space_2d" qualifiers="const">
<return type="Space2D">
</return>
<description>
</description>
</method>
- <method name="notify_group" >
+ <method name="notify_group">
<argument index="0" name="call_flags" type="int">
</argument>
<argument index="1" name="group" type="String">
@@ -12080,7 +12084,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">
@@ -12092,63 +12096,63 @@
<description>
</description>
</method>
- <method name="get_root_node" >
+ <method name="get_root_node">
<return type="Node">
</return>
<description>
</description>
</method>
- <method name="set_root_node" >
+ <method name="set_root_node">
<argument index="0" name="node" type="Node">
</argument>
<description>
</description>
</method>
- <method name="set_auto_accept_quit" >
+ <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_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_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="call_group" >
+ <method name="call_group">
<argument index="0" name="flags" type="int">
</argument>
<argument index="1" name="group" type="String">
@@ -12202,7 +12206,7 @@
<description>
</description>
<methods>
- <method name="load_scene" >
+ <method name="load_scene">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -12210,19 +12214,19 @@
<description>
</description>
</method>
- <method name="get_scene_path" qualifiers="const" >
+ <method name="get_scene_path" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="instance" qualifiers="const" >
+ <method name="instance" qualifiers="const">
<return type="Node">
</return>
<description>
</description>
</method>
- <method name="can_instance" qualifiers="const" >
+ <method name="can_instance" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -12238,11 +12242,11 @@
<description>
</description>
<methods>
- <method name="enter_screen" >
+ <method name="enter_screen">
<description>
</description>
</method>
- <method name="exit_screen" >
+ <method name="exit_screen">
<description>
</description>
</method>
@@ -12266,13 +12270,13 @@
<description>
</description>
<methods>
- <method name="can_instance" qualifiers="const" >
+ <method name="can_instance" qualifiers="const">
<return type="bool">
</return>
<description>
</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">
@@ -12280,25 +12284,25 @@
<description>
</description>
</method>
- <method name="has_source_code" qualifiers="const" >
+ <method name="has_source_code" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_source_code" qualifiers="const" >
+ <method name="get_source_code" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="set_source_code" >
+ <method name="set_source_code">
<argument index="0" name="source" type="String">
</argument>
<description>
</description>
</method>
- <method name="reload" >
+ <method name="reload">
<return type="int">
</return>
<description>
@@ -12314,13 +12318,13 @@
<description>
</description>
<methods>
- <method name="set_custom_step" >
+ <method name="set_custom_step">
<argument index="0" name="step" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_custom_step" qualifiers="const" >
+ <method name="get_custom_step" qualifiers="const">
<return type="real">
</return>
<description>
@@ -12336,25 +12340,25 @@
<description>
</description>
<methods>
- <method name="set_a" >
+ <method name="set_a">
<argument index="0" name="a" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_a" qualifiers="const" >
+ <method name="get_a" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_b" >
+ <method name="set_b">
<argument index="0" name="b" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_b" qualifiers="const" >
+ <method name="get_b" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -12380,55 +12384,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_vertex_code" >
+ <method name="set_vertex_code">
<argument index="0" name="code" type="String">
</argument>
<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="set_fragment_code" >
+ <method name="set_fragment_code">
<argument index="0" name="code" type="String">
</argument>
<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="set_use_world_transform" >
+ <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" >
+ <method name="is_using_world_transform" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="String">
</argument>
<argument index="1" name="value" type="var">
@@ -12436,13 +12440,13 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<argument index="0" name="param" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_param_list" qualifiers="const" >
+ <method name="get_param_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
@@ -12462,13 +12466,13 @@
<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>
@@ -12504,13 +12508,13 @@
<description>
</description>
<methods>
- <method name="add_bone" >
+ <method name="add_bone">
<argument index="0" name="name" type="String">
</argument>
<description>
</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">
@@ -12518,7 +12522,7 @@
<description>
</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">
@@ -12526,7 +12530,7 @@
<description>
</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">
@@ -12534,7 +12538,7 @@
<description>
</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">
@@ -12542,13 +12546,13 @@
<description>
</description>
</method>
- <method name="get_bone_count" qualifiers="const" >
+ <method name="get_bone_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_bone_rest" qualifiers="const" >
+ <method name="get_bone_rest" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -12556,7 +12560,7 @@
<description>
</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">
@@ -12564,7 +12568,7 @@
<description>
</description>
</method>
- <method name="bind_child_node_to_bone" >
+ <method name="bind_child_node_to_bone">
<argument index="0" name="bone_idx" type="int">
</argument>
<argument index="1" name="node" type="Node">
@@ -12572,7 +12576,7 @@
<description>
</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">
@@ -12580,7 +12584,7 @@
<description>
</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">
@@ -12588,11 +12592,11 @@
<description>
</description>
</method>
- <method name="clear_bones" >
+ <method name="clear_bones">
<description>
</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">
@@ -12600,7 +12604,7 @@
<description>
</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">
@@ -12608,7 +12612,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">
@@ -12616,7 +12620,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">
@@ -12624,7 +12628,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">
@@ -12654,25 +12658,25 @@
<description>
</description>
<methods>
- <method name="set_ticks" >
+ <method name="set_ticks">
<argument index="0" name="count" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_ticks" qualifiers="const" >
+ <method name="get_ticks" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_ticks_on_borders" qualifiers="const" >
+ <method name="get_ticks_on_borders" qualifiers="const">
<return type="bool">
</return>
<description>
</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>
@@ -12688,7 +12692,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="real">
@@ -12696,7 +12700,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="param" type="int">
@@ -12704,25 +12708,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>
@@ -12738,37 +12742,37 @@
<description>
</description>
<methods>
- <method name="set_transform" >
+ <method name="set_transform">
<argument index="0" name="local" 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_global_transform" >
+ <method name="set_global_transform">
<argument index="0" name="global" type="Transform">
</argument>
<description>
</description>
</method>
- <method name="get_global_transform" qualifiers="const" >
+ <method name="get_global_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
</description>
</method>
- <method name="get_parent_spatial" qualifiers="const" >
+ <method name="get_parent_spatial" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="update_gizmo" >
+ <method name="update_gizmo">
<description>
</description>
</method>
@@ -12788,7 +12792,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="real">
@@ -12796,7 +12800,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="param" type="int">
@@ -12830,31 +12834,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">
@@ -12864,7 +12868,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="real">
@@ -12872,7 +12876,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="real">
@@ -12880,7 +12884,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">
@@ -12888,13 +12892,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>
@@ -12932,63 +12936,63 @@
<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_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="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="real">
</return>
<description>
</description>
</method>
- <method name="seek_pos" >
+ <method name="seek_pos">
<argument index="0" name="time" type="real">
</argument>
<description>
@@ -13004,13 +13008,13 @@
<description>
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="real">
</return>
<description>
@@ -13026,37 +13030,37 @@
<description>
</description>
<methods>
- <method name="set_suffix" >
+ <method name="set_suffix">
<argument index="0" name="suffix" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_suffix" qualifiers="const" >
+ <method name="get_suffix" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="set_prefix" >
+ <method name="set_prefix">
<argument index="0" name="prefix" type="String">
</argument>
<description>
</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>
</description>
</method>
- <method name="is_editable" qualifiers="const" >
+ <method name="is_editable" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -13082,121 +13086,121 @@
<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_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_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_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>
- <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>
@@ -13222,25 +13226,25 @@
<description>
</description>
<methods>
- <method name="set_simulated_motion" >
+ <method name="set_simulated_motion">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_simulating_motion" qualifiers="const" >
+ <method name="is_simulating_motion" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="simulate_motion" >
+ <method name="simulate_motion">
<argument index="0" name="new_transform" type="Transform">
</argument>
<description>
</description>
</method>
- <method name="create_shapes_from_child_meshes" >
+ <method name="create_shapes_from_child_meshes">
<description>
</description>
</method>
@@ -13254,37 +13258,37 @@
<description>
</description>
<methods>
- <method name="set_simulate_motion" >
+ <method name="set_simulate_motion">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_simulating_motion" qualifiers="const" >
+ <method name="is_simulating_motion" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_constant_linear_velocity" >
+ <method name="set_constant_linear_velocity">
<argument index="0" name="vel" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="set_constant_angular_velocity" >
+ <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" >
+ <method name="get_constant_linear_velocity" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_constant_angular_velocity" qualifiers="const" >
+ <method name="get_constant_angular_velocity" qualifiers="const">
<return type="real">
</return>
<description>
@@ -13300,7 +13304,7 @@
<description>
</description>
<methods>
- <method name="put_data" >
+ <method name="put_data">
<return type="int">
</return>
<argument index="0" name="data" type="RawArray">
@@ -13308,7 +13312,7 @@
<description>
</description>
</method>
- <method name="put_partial_data" >
+ <method name="put_partial_data">
<return type="Array">
</return>
<argument index="0" name="data" type="RawArray">
@@ -13316,7 +13320,7 @@
<description>
</description>
</method>
- <method name="get_data" >
+ <method name="get_data">
<return type="Array">
</return>
<argument index="0" name="bytes" type="int">
@@ -13324,7 +13328,7 @@
<description>
</description>
</method>
- <method name="get_partial_data" >
+ <method name="get_partial_data">
<return type="Array">
</return>
<argument index="0" name="bytes" type="int">
@@ -13342,7 +13346,7 @@
<description>
</description>
<methods>
- <method name="connect" >
+ <method name="connect">
<return type="int">
</return>
<argument index="0" name="host" type="String">
@@ -13352,25 +13356,25 @@
<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_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>
@@ -13384,117 +13388,117 @@
<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_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="real">
</argument>
<description>
</description>
</method>
- <method name="get_volume" qualifiers="const" >
+ <method name="get_volume" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_volume_db" >
+ <method name="set_volume_db">
<argument index="0" name="db" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
+ <method name="get_volume_db" qualifiers="const">
<return type="real">
</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="real">
</return>
<description>
</description>
</method>
- <method name="seek_pos" >
+ <method name="seek_pos">
<argument index="0" name="time" type="real">
</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="real">
</return>
<description>
@@ -13510,7 +13514,7 @@
<description>
</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">
@@ -13520,7 +13524,7 @@
<description>
</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="real">
@@ -13528,7 +13532,7 @@
<description>
</description>
</method>
- <method name="get_default_margin" qualifiers="const" >
+ <method name="get_default_margin" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="margin" type="int">
@@ -13536,7 +13540,7 @@
<description>
</description>
</method>
- <method name="get_margin" qualifiers="const" >
+ <method name="get_margin" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="margin" type="int">
@@ -13544,25 +13548,25 @@
<description>
</description>
</method>
- <method name="get_minimum_size" qualifiers="const" >
+ <method name="get_minimum_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</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>
</description>
</method>
- <method name="draw" qualifiers="const" >
+ <method name="draw" qualifiers="const">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Rect2">
@@ -13590,73 +13594,73 @@
<description>
</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>
@@ -13672,31 +13676,31 @@
<description>
</description>
<methods>
- <method name="set_image" >
+ <method name="set_image">
<argument index="0" name="image" type="Image">
</argument>
<description>
</description>
</method>
- <method name="get_image" qualifiers="const" >
+ <method name="get_image" qualifiers="const">
<return type="Image">
</return>
<description>
</description>
</method>
- <method name="set_expand" >
+ <method name="set_expand">
<argument index="0" name="expand" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_expand" qualifiers="const" >
+ <method name="get_expand" qualifiers="const">
<return type="bool">
</return>
<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="real">
@@ -13704,7 +13708,7 @@
<description>
</description>
</method>
- <method name="get_expand_margin_size" qualifiers="const" >
+ <method name="get_expand_margin_size" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="int">
@@ -13722,19 +13726,19 @@
<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_margin_size" >
+ <method name="set_margin_size">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="size" type="real">
@@ -13742,7 +13746,7 @@
<description>
</description>
</method>
- <method name="get_margin_size" qualifiers="const" >
+ <method name="get_margin_size" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="int">
@@ -13750,7 +13754,7 @@
<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="real">
@@ -13758,7 +13762,7 @@
<description>
</description>
</method>
- <method name="get_expand_margin_size" qualifiers="const" >
+ <method name="get_expand_margin_size" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="int">
@@ -13766,13 +13770,13 @@
<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>
@@ -13788,87 +13792,87 @@
<description>
</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="Vector3">
</argument>
<description>
</description>
</method>
- <method name="add_uv2" >
+ <method name="add_uv2">
<argument index="0" name="uv2" type="Vector3">
</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="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_flat_normals" >
+ <method name="generate_flat_normals">
<description>
</description>
</method>
- <method name="generate_smooth_normals" >
+ <method name="generate_smooth_normals">
<description>
</description>
</method>
- <method name="generate_tangents" >
+ <method name="generate_tangents">
<description>
</description>
</method>
- <method name="commit" >
+ <method name="commit">
<return type="Mesh">
</return>
<argument index="0" name="existing" type="Mesh" default="Object()">
@@ -13876,7 +13880,7 @@
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -13890,7 +13894,7 @@
<description>
</description>
<methods>
- <method name="listen" >
+ <method name="listen">
<return type="int">
</return>
<argument index="0" name="port" type="int">
@@ -13900,19 +13904,19 @@
<description>
</description>
</method>
- <method name="is_connection_available" qualifiers="const" >
+ <method name="is_connection_available" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="take_connection" >
+ <method name="take_connection">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
</description>
</method>
@@ -13926,49 +13930,49 @@
<description>
</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_align" >
+ <method name="set_tab_align">
<argument index="0" name="align" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_tab_align" qualifiers="const" >
+ <method name="get_tab_align" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_tabs_visible" >
+ <method name="set_tabs_visible">
<argument index="0" name="visible" type="bool">
</argument>
<description>
</description>
</method>
- <method name="are_tabs_visible" qualifiers="const" >
+ <method name="are_tabs_visible" qualifiers="const">
<return type="bool">
</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">
@@ -13976,7 +13980,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">
@@ -13984,7 +13988,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">
@@ -13992,7 +13996,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">
@@ -14028,31 +14032,31 @@
<description>
</description>
<methods>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="insert_text_at_cursor" >
+ <method name="insert_text_at_cursor">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_line_count" qualifiers="const" >
+ <method name="get_line_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_text" >
+ <method name="get_text">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_line" >
+ <method name="get_line">
<return type="String">
</return>
<argument index="0" name="arg0" type="int">
@@ -14060,65 +14064,65 @@
<description>
</description>
</method>
- <method name="cursor_set_column" >
+ <method name="cursor_set_column">
<argument index="0" name="column" type="int">
</argument>
<description>
</description>
</method>
- <method name="cursor_set_line" >
+ <method name="cursor_set_line">
<argument index="0" name="line" type="int">
</argument>
<description>
</description>
</method>
- <method name="cursor_get_column" qualifiers="const" >
+ <method name="cursor_get_column" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="cursor_get_line" qualifiers="const" >
+ <method name="cursor_get_line" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_readonly" >
+ <method name="set_readonly">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_wrap" >
+ <method name="set_wrap">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_max_chars" >
+ <method name="set_max_chars">
<argument index="0" name="amount" type="int">
</argument>
<description>
</description>
</method>
- <method name="cut" >
+ <method name="cut">
<description>
</description>
</method>
- <method name="copy" >
+ <method name="copy">
<description>
</description>
</method>
- <method name="paste" >
+ <method name="paste">
<description>
</description>
</method>
- <method name="select_all" >
+ <method name="select_all">
<description>
</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">
@@ -14130,43 +14134,43 @@
<description>
</description>
</method>
- <method name="is_selection_active" qualifiers="const" >
+ <method name="is_selection_active" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_selection_from_line" qualifiers="const" >
+ <method name="get_selection_from_line" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_selection_from_column" qualifiers="const" >
+ <method name="get_selection_from_column" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_selection_to_line" qualifiers="const" >
+ <method name="get_selection_to_line" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_selection_to_column" qualifiers="const" >
+ <method name="get_selection_to_column" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_selection_text" qualifiers="const" >
+ <method name="get_selection_text" 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">
@@ -14180,31 +14184,31 @@
<description>
</description>
</method>
- <method name="undo" >
+ <method name="undo">
<description>
</description>
</method>
- <method name="redo" >
+ <method name="redo">
<description>
</description>
</method>
- <method name="clear_undo_history" >
+ <method name="clear_undo_history">
<description>
</description>
</method>
- <method name="set_syntax_coloring" >
+ <method name="set_syntax_coloring">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_syntax_coloring_enabled" qualifiers="const" >
+ <method name="is_syntax_coloring_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</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">
@@ -14212,7 +14216,7 @@
<description>
</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">
@@ -14224,19 +14228,19 @@
<description>
</description>
</method>
- <method name="set_symbol_color" >
+ <method name="set_symbol_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="set_custom_bg_color" >
+ <method name="set_custom_bg_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="clear_colors" >
+ <method name="clear_colors">
<description>
</description>
</method>
@@ -14266,7 +14270,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">
@@ -14280,7 +14284,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">
@@ -14288,31 +14292,31 @@
<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="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>
<argument index="1" name="cube_side" type="int" default="0">
@@ -14320,7 +14324,7 @@
<description>
</description>
</method>
- <method name="get_data" qualifiers="const" >
+ <method name="get_data" qualifiers="const">
<return type="Image">
</return>
<argument index="0" name="cube_side" type="int" default="0">
@@ -14328,37 +14332,37 @@
<description>
</description>
</method>
- <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_size" qualifiers="const" >
+ <method name="get_size" qualifiers="const">
<return type="Vector2">
</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="has_alpha" qualifiers="const" >
+ <method name="has_alpha" qualifiers="const">
<return type="bool">
</return>
<description>
</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">
@@ -14402,73 +14406,73 @@
<description>
</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="texture:Image" type="Image">
</argument>
<description>
</description>
</method>
- <method name="get_normal_texture" qualifiers="const" >
+ <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="Image">
</return>
<description>
@@ -14484,25 +14488,25 @@
<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_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>
@@ -14518,37 +14522,37 @@
<description>
</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>
@@ -14564,7 +14568,7 @@
<description>
</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">
@@ -14574,7 +14578,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">
@@ -14584,7 +14588,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">
@@ -14594,7 +14598,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">
@@ -14602,7 +14606,7 @@
<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">
@@ -14610,7 +14614,7 @@
<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">
@@ -14620,7 +14624,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">
@@ -14630,7 +14634,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">
@@ -14640,7 +14644,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">
@@ -14648,7 +14652,7 @@
<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">
@@ -14656,7 +14660,7 @@
<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">
@@ -14666,7 +14670,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">
@@ -14676,7 +14680,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">
@@ -14686,7 +14690,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">
@@ -14694,7 +14698,7 @@
<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">
@@ -14702,7 +14706,7 @@
<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">
@@ -14712,7 +14716,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">
@@ -14722,7 +14726,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">
@@ -14732,7 +14736,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">
@@ -14740,7 +14744,7 @@
<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">
@@ -14748,7 +14752,7 @@
<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">
@@ -14758,7 +14762,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">
@@ -14768,7 +14772,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">
@@ -14778,7 +14782,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">
@@ -14786,7 +14790,7 @@
<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">
@@ -14794,7 +14798,7 @@
<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">
@@ -14802,7 +14806,7 @@
<description>
</description>
</method>
- <method name="copy_default_theme" >
+ <method name="copy_default_theme">
<description>
</description>
</method>
@@ -14816,67 +14820,67 @@
<description>
</description>
<methods>
- <method name="set_tileset" >
+ <method name="set_tileset">
<argument index="0" name="tileset" type="TileSet">
</argument>
<description>
</description>
</method>
- <method name="get_tileset" qualifiers="const" >
+ <method name="get_tileset" qualifiers="const">
<return type="TileSet">
</return>
<description>
</description>
</method>
- <method name="set_cell_size" >
+ <method name="set_cell_size">
<argument index="0" name="size" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_cell_size" qualifiers="const" >
+ <method name="get_cell_size" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_quadrant_size" >
+ <method name="set_quadrant_size">
<argument index="0" name="size" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_quadrant_size" qualifiers="const" >
+ <method name="get_quadrant_size" qualifiers="const">
<return type="int">
</return>
<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_cell" >
+ <method name="set_cell">
<argument index="0" name="x" type="int">
</argument>
<argument index="1" name="y" type="int">
@@ -14890,7 +14894,7 @@
<description>
</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">
@@ -14900,7 +14904,7 @@
<description>
</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">
@@ -14910,7 +14914,7 @@
<description>
</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">
@@ -14920,7 +14924,7 @@
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -14936,13 +14940,13 @@
<description>
</description>
<methods>
- <method name="create_tile" >
+ <method name="create_tile">
<argument index="0" name="id" type="int">
</argument>
<description>
</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">
@@ -14950,7 +14954,7 @@
<description>
</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">
@@ -14958,7 +14962,7 @@
<description>
</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">
@@ -14966,7 +14970,7 @@
<description>
</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">
@@ -14974,7 +14978,7 @@
<description>
</description>
</method>
- <method name="tile_set_offset" >
+ <method name="tile_set_offset">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="offset" type="Vector2">
@@ -14982,7 +14986,7 @@
<description>
</description>
</method>
- <method name="tile_get_offset" qualifiers="const" >
+ <method name="tile_get_offset" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="id" type="int">
@@ -14990,7 +14994,7 @@
<description>
</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">
@@ -14998,7 +15002,7 @@
<description>
</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">
@@ -15006,7 +15010,7 @@
<description>
</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">
@@ -15014,7 +15018,7 @@
<description>
</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">
@@ -15022,23 +15026,23 @@
<description>
</description>
</method>
- <method name="remove_tile" >
+ <method name="remove_tile">
<argument index="0" name="id" type="int">
</argument>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</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>
</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">
@@ -15046,7 +15050,7 @@
<description>
</description>
</method>
- <method name="get_tiles_ids" qualifiers="const" >
+ <method name="get_tiles_ids" qualifiers="const">
<return type="Array">
</return>
<description>
@@ -15063,51 +15067,51 @@
<description>
</description>
<methods>
- <method name="set_wait_time" >
+ <method name="set_wait_time">
<argument index="0" name="time_sec" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_wait_time" qualifiers="const" >
+ <method name="get_wait_time" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_one_shot" >
+ <method name="set_one_shot">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_one_shot" qualifiers="const" >
+ <method name="is_one_shot" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_autostart" >
+ <method name="set_autostart">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_autostart" qualifiers="const" >
+ <method name="has_autostart" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="start" >
+ <method name="start">
<description>
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
</description>
</method>
- <method name="get_time_left" qualifiers="const" >
+ <method name="get_time_left" qualifiers="const">
<return type="real">
</return>
<description>
@@ -15129,19 +15133,19 @@
<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="add_message" >
+ <method name="add_message">
<argument index="0" name="src_message" type="String">
</argument>
<argument index="1" name="xlated_message" type="String">
@@ -15149,7 +15153,7 @@
<description>
</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">
@@ -15157,13 +15161,13 @@
<description>
</description>
</method>
- <method name="erase_message" >
+ <method name="erase_message">
<argument index="0" name="src_message" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_message_list" qualifiers="const" >
+ <method name="get_message_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
@@ -15189,11 +15193,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()">
@@ -15201,13 +15205,13 @@
<description>
</description>
</method>
- <method name="get_root" >
+ <method name="get_root">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="set_column_min_width" >
+ <method name="set_column_min_width">
<argument index="0" name="arg0" type="int">
</argument>
<argument index="1" name="arg1" type="int">
@@ -15215,7 +15219,7 @@
<description>
</description>
</method>
- <method name="set_column_expand" >
+ <method name="set_column_expand">
<argument index="0" name="arg0" type="int">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -15223,7 +15227,7 @@
<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">
@@ -15231,13 +15235,13 @@
<description>
</description>
</method>
- <method name="set_hide_root" >
+ <method name="set_hide_root">
<argument index="0" name="arg0" 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">
@@ -15245,61 +15249,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">
@@ -15309,23 +15313,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">
@@ -15333,7 +15337,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">
@@ -15341,7 +15345,7 @@
<description>
</description>
</method>
- <method name="get_scroll" qualifiers="const" >
+ <method name="get_scroll" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -15407,7 +15411,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">
@@ -15415,7 +15419,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">
@@ -15423,7 +15427,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">
@@ -15431,7 +15435,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">
@@ -15439,7 +15443,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">
@@ -15447,7 +15451,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">
@@ -15455,7 +15459,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">
@@ -15463,7 +15467,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">
@@ -15471,7 +15475,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">
@@ -15479,7 +15483,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">
@@ -15487,7 +15491,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">
@@ -15495,7 +15499,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">
@@ -15503,7 +15507,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="real">
@@ -15511,7 +15515,7 @@
<description>
</description>
</method>
- <method name="get_range" qualifiers="const" >
+ <method name="get_range" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="column" type="int">
@@ -15519,7 +15523,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="real">
@@ -15533,7 +15537,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">
@@ -15541,7 +15545,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">
@@ -15549,67 +15553,67 @@
<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_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">
<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">
@@ -15617,7 +15621,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">
@@ -15625,7 +15629,7 @@
<description>
</description>
</method>
- <method name="is_selected" >
+ <method name="is_selected">
<return type="bool">
</return>
<argument index="0" name="column" type="int">
@@ -15633,19 +15637,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">
@@ -15653,7 +15657,7 @@
<description>
</description>
</method>
- <method name="is_editable" >
+ <method name="is_editable">
<return type="bool">
</return>
<argument index="0" name="column" type="int">
@@ -15661,7 +15665,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">
@@ -15669,13 +15673,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">
@@ -15683,13 +15687,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">
@@ -15697,7 +15701,7 @@
<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">
@@ -15707,7 +15711,7 @@
<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">
@@ -15715,7 +15719,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">
@@ -15725,7 +15729,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">
@@ -15733,7 +15737,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">
@@ -15741,7 +15745,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">
@@ -15819,99 +15823,99 @@
<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="real">
</argument>
<description>
</description>
</method>
- <method name="get_volume" qualifiers="const" >
+ <method name="get_volume" qualifiers="const">
<return type="real">
</return>
<description>
</description>
</method>
- <method name="set_volume_db" >
+ <method name="set_volume_db">
<argument index="0" name="db" type="real">
</argument>
<description>
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
+ <method name="get_volume_db" qualifiers="const">
<return type="real">
</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_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="real">
</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>
@@ -15927,19 +15931,19 @@
<description>
</description>
<methods>
- <method name="get_pending_frame_count" qualifiers="const" >
+ <method name="get_pending_frame_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="pop_frame" >
+ <method name="pop_frame">
<return type="Image">
</return>
<description>
</description>
</method>
- <method name="peek_frame" qualifiers="const" >
+ <method name="peek_frame" qualifiers="const">
<return type="Image">
</return>
<description>
@@ -15965,37 +15969,37 @@
<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="get_visible_rect" qualifiers="const" >
+ <method name="get_visible_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="set_transparent_background" >
+ <method name="set_transparent_background">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_transparent_background" qualifiers="const" >
+ <method name="has_transparent_background" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_viewport" qualifiers="const" >
+ <method name="get_viewport" qualifiers="const">
<return type="RID">
</return>
<description>
@@ -16011,7 +16015,7 @@
<description>
</description>
<methods>
- <method name="set_base" >
+ <method name="set_base">
<argument index="0" name="base" type="RID">
</argument>
<description>
@@ -16027,13 +16031,13 @@
<description>
</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">
@@ -16043,7 +16047,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">
@@ -16051,7 +16055,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">
@@ -16059,7 +16063,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">
@@ -16067,7 +16071,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">
@@ -16075,7 +16079,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">
@@ -16083,7 +16087,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">
@@ -16091,7 +16095,7 @@
<description>
</description>
</method>
- <method name="shader_get_mode" qualifiers="const" >
+ <method name="shader_get_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="shader" type="RID">
@@ -16099,7 +16103,7 @@
<description>
</description>
</method>
- <method name="shader_set_vertex_code" >
+ <method name="shader_set_vertex_code">
<argument index="0" name="shader" type="RID">
</argument>
<argument index="1" name="code" type="String">
@@ -16107,7 +16111,7 @@
<description>
</description>
</method>
- <method name="shader_get_vertex_code" qualifiers="const" >
+ <method name="shader_get_vertex_code" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="shader" type="RID">
@@ -16115,7 +16119,7 @@
<description>
</description>
</method>
- <method name="shader_set_fragment_code" >
+ <method name="shader_set_fragment_code">
<argument index="0" name="shader" type="RID">
</argument>
<argument index="1" name="code" type="String">
@@ -16123,7 +16127,7 @@
<description>
</description>
</method>
- <method name="shader_get_fragment_code" qualifiers="const" >
+ <method name="shader_get_fragment_code" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="shader" type="RID">
@@ -16131,7 +16135,7 @@
<description>
</description>
</method>
- <method name="shader_set_param" >
+ <method name="shader_set_param">
<argument index="0" name="shader" type="RID">
</argument>
<argument index="1" name="param" type="String">
@@ -16141,7 +16145,7 @@
<description>
</description>
</method>
- <method name="shader_get_param" qualifiers="const" >
+ <method name="shader_get_param" qualifiers="const">
<argument index="0" name="shader" type="RID">
</argument>
<argument index="1" name="param" type="String">
@@ -16149,7 +16153,7 @@
<description>
</description>
</method>
- <method name="shader_get_param_list" qualifiers="const" >
+ <method name="shader_get_param_list" qualifiers="const">
<return type="StringArray">
</return>
<argument index="0" name="shader" type="RID">
@@ -16157,7 +16161,7 @@
<description>
</description>
</method>
- <method name="shader_set_use_world_transform" >
+ <method name="shader_set_use_world_transform">
<argument index="0" name="shader" type="RID">
</argument>
<argument index="1" name="enable" type="bool">
@@ -16165,7 +16169,7 @@
<description>
</description>
</method>
- <method name="shader_is_using_world_transform" qualifiers="const" >
+ <method name="shader_is_using_world_transform" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="shader" type="RID">
@@ -16173,13 +16177,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">
@@ -16187,7 +16191,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">
@@ -16195,7 +16199,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">
@@ -16205,7 +16209,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">
@@ -16213,7 +16217,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">
@@ -16223,7 +16227,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">
@@ -16233,7 +16237,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">
@@ -16241,7 +16245,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">
@@ -16249,7 +16253,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="real">
@@ -16257,7 +16261,7 @@
<description>
</description>
</method>
- <method name="material_get_line_width" qualifiers="const" >
+ <method name="material_get_line_width" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16265,7 +16269,7 @@
<description>
</description>
</method>
- <method name="fixed_material_set_parameter" >
+ <method name="fixed_material_set_parameter">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -16275,7 +16279,7 @@
<description>
</description>
</method>
- <method name="fixed_material_get_parameter" qualifiers="const" >
+ <method name="fixed_material_get_parameter" qualifiers="const">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -16283,7 +16287,7 @@
<description>
</description>
</method>
- <method name="fixed_material_set_texture" >
+ <method name="fixed_material_set_texture">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -16293,7 +16297,7 @@
<description>
</description>
</method>
- <method name="fixed_material_get_texture" qualifiers="const" >
+ <method name="fixed_material_get_texture" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16303,7 +16307,7 @@
<description>
</description>
</method>
- <method name="fixed_material_set_texgen_mode" >
+ <method name="fixed_material_set_texgen_mode">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -16311,7 +16315,7 @@
<description>
</description>
</method>
- <method name="fixed_material_get_texgen_mode" qualifiers="const" >
+ <method name="fixed_material_get_texgen_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16319,7 +16323,7 @@
<description>
</description>
</method>
- <method name="fixed_material_set_texcoord_mode" >
+ <method name="fixed_material_set_texcoord_mode">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -16329,7 +16333,7 @@
<description>
</description>
</method>
- <method name="fixed_material_get_texcoord_mode" qualifiers="const" >
+ <method name="fixed_material_get_texcoord_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16339,7 +16343,7 @@
<description>
</description>
</method>
- <method name="fixed_material_set_uv_transform" >
+ <method name="fixed_material_set_uv_transform">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Transform">
@@ -16347,7 +16351,7 @@
<description>
</description>
</method>
- <method name="fixed_material_get_uv_transform" qualifiers="const" >
+ <method name="fixed_material_get_uv_transform" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16355,13 +16359,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">
@@ -16375,7 +16379,7 @@
<description>
</description>
</method>
- <method name="mesh_surface_set_array" >
+ <method name="mesh_surface_set_array">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16389,7 +16393,7 @@
<description>
</description>
</method>
- <method name="mesh_surface_get_array" qualifiers="const" >
+ <method name="mesh_surface_get_array" qualifiers="const">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -16399,7 +16403,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">
@@ -16411,7 +16415,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">
@@ -16421,7 +16425,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">
@@ -16431,7 +16435,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">
@@ -16441,7 +16445,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">
@@ -16451,7 +16455,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">
@@ -16461,7 +16465,7 @@
<description>
</description>
</method>
- <method name="mesh_erase_surface" >
+ <method name="mesh_erase_surface">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -16469,7 +16473,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">
@@ -16477,13 +16481,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">
@@ -16491,7 +16495,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">
@@ -16499,7 +16503,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">
@@ -16509,7 +16513,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">
@@ -16519,7 +16523,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">
@@ -16527,7 +16531,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">
@@ -16537,7 +16541,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">
@@ -16547,7 +16551,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">
@@ -16557,13 +16561,13 @@
<description>
</description>
</method>
- <method name="poly_create" >
+ <method name="poly_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="poly_set_material" >
+ <method name="poly_set_material">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -16573,19 +16577,19 @@
<description>
</description>
</method>
- <method name="poly_clear" >
+ <method name="poly_clear">
<argument index="0" name="arg0" type="RID">
</argument>
<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">
@@ -16593,7 +16597,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">
@@ -16601,7 +16605,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">
@@ -16609,7 +16613,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">
@@ -16617,7 +16621,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">
@@ -16625,7 +16629,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">
@@ -16633,7 +16637,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">
@@ -16643,7 +16647,7 @@
<description>
</description>
</method>
- <method name="particles_get_variable" qualifiers="const" >
+ <method name="particles_get_variable" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16653,7 +16657,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">
@@ -16663,7 +16667,7 @@
<description>
</description>
</method>
- <method name="particles_get_randomness" qualifiers="const" >
+ <method name="particles_get_randomness" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16673,7 +16677,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">
@@ -16681,7 +16685,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">
@@ -16689,7 +16693,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">
@@ -16699,7 +16703,7 @@
<description>
</description>
</method>
- <method name="particles_get_color_phase_pos" qualifiers="const" >
+ <method name="particles_get_color_phase_pos" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16709,7 +16713,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">
@@ -16719,7 +16723,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">
@@ -16729,7 +16733,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">
@@ -16737,7 +16741,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">
@@ -16745,7 +16749,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">
@@ -16755,7 +16759,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">
@@ -16765,7 +16769,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">
@@ -16775,7 +16779,7 @@
<description>
</description>
</method>
- <method name="particles_get_attractor_strength" qualifiers="const" >
+ <method name="particles_get_attractor_strength" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16785,7 +16789,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">
@@ -16795,7 +16799,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">
@@ -16803,7 +16807,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">
@@ -16811,7 +16815,7 @@
<description>
</description>
</method>
- <method name="light_create" >
+ <method name="light_create">
<return type="RID">
</return>
<argument index="0" name="arg0" type="int">
@@ -16819,7 +16823,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">
@@ -16827,7 +16831,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">
@@ -16837,7 +16841,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">
@@ -16847,7 +16851,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">
@@ -16855,7 +16859,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">
@@ -16863,7 +16867,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">
@@ -16871,7 +16875,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">
@@ -16879,7 +16883,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">
@@ -16887,7 +16891,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">
@@ -16895,7 +16899,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">
@@ -16905,7 +16909,7 @@
<description>
</description>
</method>
- <method name="light_get_var" qualifiers="const" >
+ <method name="light_get_var" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -16915,13 +16919,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">
@@ -16929,7 +16933,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">
@@ -16937,7 +16941,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">
@@ -16947,7 +16951,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">
@@ -16957,13 +16961,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">
@@ -16971,7 +16975,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">
@@ -16979,13 +16983,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">
@@ -16993,7 +16997,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">
@@ -17001,7 +17005,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">
@@ -17009,7 +17013,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">
@@ -17017,7 +17021,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="real">
@@ -17025,7 +17029,7 @@
<description>
</description>
</method>
- <method name="portal_get_disable_distance" qualifiers="const" >
+ <method name="portal_get_disable_distance" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -17033,7 +17037,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">
@@ -17041,7 +17045,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">
@@ -17049,13 +17053,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="real">
@@ -17067,7 +17071,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="real">
@@ -17079,7 +17083,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">
@@ -17087,13 +17091,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">
@@ -17101,7 +17105,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">
@@ -17109,7 +17113,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()">
@@ -17117,7 +17121,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">
@@ -17125,7 +17129,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">
@@ -17133,7 +17137,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">
@@ -17141,7 +17145,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">
@@ -17149,13 +17153,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">
@@ -17163,7 +17167,7 @@
<description>
</description>
</method>
- <method name="scenario_fx_get_effects" qualifiers="const" >
+ <method name="scenario_fx_get_effects" qualifiers="const">
<return type="StringArray">
</return>
<argument index="0" name="arg0" type="RID">
@@ -17171,7 +17175,7 @@
<description>
</description>
</method>
- <method name="scenario_fx_set_active" >
+ <method name="scenario_fx_set_active">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="String">
@@ -17181,7 +17185,7 @@
<description>
</description>
</method>
- <method name="scenario_fx_is_active" qualifiers="const" >
+ <method name="scenario_fx_is_active" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -17191,7 +17195,7 @@
<description>
</description>
</method>
- <method name="scenario_fx_get_effect_params" qualifiers="const" >
+ <method name="scenario_fx_get_effect_params" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="arg0" type="RID">
@@ -17201,7 +17205,7 @@
<description>
</description>
</method>
- <method name="scenario_fx_get_effect_param" qualifiers="const" >
+ <method name="scenario_fx_get_effect_param" qualifiers="const">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="String">
@@ -17211,7 +17215,7 @@
<description>
</description>
</method>
- <method name="scenario_fx_set_effect_param" >
+ <method name="scenario_fx_set_effect_param">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="String">
@@ -17223,13 +17227,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">
@@ -17237,7 +17241,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">
@@ -17245,7 +17249,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">
@@ -17253,7 +17257,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">
@@ -17261,7 +17265,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">
@@ -17269,7 +17273,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">
@@ -17277,7 +17281,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">
@@ -17285,7 +17289,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">
@@ -17293,7 +17297,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">
@@ -17301,7 +17305,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">
@@ -17309,7 +17313,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">
@@ -17317,7 +17321,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">
@@ -17325,7 +17329,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">
@@ -17335,7 +17339,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">
@@ -17347,7 +17351,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="Vector3">
@@ -17359,7 +17363,7 @@
<description>
</description>
</method>
- <method name="instance_geometry_set_visible" >
+ <method name="instance_geometry_set_visible">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -17367,7 +17371,7 @@
<description>
</description>
</method>
- <method name="instance_geometry_is_visible" qualifiers="const" >
+ <method name="instance_geometry_is_visible" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -17375,7 +17379,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">
@@ -17383,7 +17387,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">
@@ -17391,19 +17395,19 @@
<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">
@@ -17411,7 +17415,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">
@@ -17419,7 +17423,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">
@@ -17427,7 +17431,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">
@@ -17437,7 +17441,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">
@@ -17445,7 +17449,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="real">
@@ -17453,7 +17457,7 @@
<description>
</description>
</method>
- <method name="canvas_item_get_opacity" qualifiers="const" >
+ <method name="canvas_item_get_opacity" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -17463,7 +17467,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="real">
@@ -17471,7 +17475,7 @@
<description>
</description>
</method>
- <method name="canvas_item_get_self_opacity" qualifiers="const" >
+ <method name="canvas_item_get_self_opacity" qualifiers="const">
<return type="real">
</return>
<argument index="0" name="arg0" type="RID">
@@ -17481,7 +17485,7 @@
<description>
</description>
</method>
- <method name="canvas_item_add_line" >
+ <method name="canvas_item_add_line">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Vector2">
@@ -17495,7 +17499,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">
@@ -17505,7 +17509,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">
@@ -17519,7 +17523,7 @@
<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">
@@ -17533,7 +17537,7 @@
<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">
@@ -17547,7 +17551,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">
@@ -17559,7 +17563,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">
@@ -17569,19 +17573,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="real">
</argument>
<argument index="1" name="arg1" type="int">
@@ -17589,7 +17593,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">
@@ -17599,7 +17603,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">
@@ -17607,7 +17611,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">
@@ -17615,7 +17619,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">
@@ -17627,7 +17631,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">
@@ -17635,7 +17639,7 @@
<description>
</description>
</method>
- <method name="free" >
+ <method name="free">
<argument index="0" name="arg0" type="RID">
</argument>
<description>
@@ -17883,19 +17887,19 @@
<description>
</description>
<methods>
- <method name="set_title" >
+ <method name="set_title">
<argument index="0" name="title" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_title" qualifiers="const" >
+ <method name="get_title" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_close_button" >
+ <method name="get_close_button">
<return type="TextureButton">
</return>
<description>
@@ -17911,19 +17915,19 @@
<description>
</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>
diff --git a/drivers/SCsub b/drivers/SCsub
index 549ff1985f..e52d6538e5 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -1,88 +1,102 @@
-Import('env')
-
-env.drivers_sources=[]
-#env.add_source_files(env.drivers_sources,"*.cpp")
-env.Append(CPPPATH=["vorbis"])
-Export('env')
-
-SConscript('unix/SCsub');
-SConscript('alsa/SCsub');
-SConscript('windows/SCsub');
-SConscript('gles2/SCsub');
-SConscript('gles1/SCsub');
-SConscript('gl_context/SCsub');
-SConscript('openssl/SCsub');
-
-if (env["png"]=="yes"):
- SConscript("png/SCsub");
-if (env["jpg"]=="yes"):
- SConscript("jpg/SCsub");
-if (env["webp"]=="yes"):
- SConscript("webp/SCsub");
-SConscript("dds/SCsub");
-SConscript("pvr/SCsub");
-SConscript("etc1/SCsub")
-if (env["builtin_zlib"]=="yes"):
- SConscript("builtin_zlib/SCsub");
-if (env["openssl"]=="builtin"):
- SConscript("builtin_openssl/SCsub");
-
-SConscript("rtaudio/SCsub");
-SConscript("nedmalloc/SCsub");
-SConscript("trex/SCsub");
-SConscript("chibi/SCsub");
-if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theora"]=="yes"):
- SConscript("ogg/SCsub");
-if (env["vorbis"]=="yes"):
- SConscript("vorbis/SCsub");
-if (env["tools"]=="yes"):
- SConscript("convex_decomp/SCsub");
-if (env["theora"]=="yes"):
- SConscript("theora/SCsub");
-if (env['speex']=='yes'):
- SConscript("speex/SCsub");
-if (env['musepack']=='yes'):
- SConscript("mpc/SCsub");
-if (env["squish"]=="yes" and env["tools"]=="yes"):
- SConscript("squish/SCsub");
-
-num = 0
-cur_base = ""
-total = len(env.drivers_sources)
-max_src = 64
-list = []
-lib_list = []
-
-import string
-
-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 len(list) > 0:
- lib = env.Library("drivers"+str(num), list)
- lib_list.append(lib)
-
-
-drivers_base=[]
-env.add_source_files(drivers_base,"*.cpp")
-lib_list.insert(0, env.Library("drivers", drivers_base, LIBSUFFIX=env['platform_libsuffix']))
-
-env.Prepend(LIBS=lib_list)
-
-#lib = env.Library("drivers",env.drivers_sources)
-#env.Prepend(LIBS=[lib])
-
+Import('env')
+
+env.drivers_sources=[]
+#env.add_source_files(env.drivers_sources,"*.cpp")
+env.Append(CPPPATH=["vorbis"])
+Export('env')
+
+SConscript('unix/SCsub');
+SConscript('alsa/SCsub');
+SConscript('pulseaudio/SCsub');
+SConscript('windows/SCsub');
+SConscript('gles2/SCsub');
+SConscript('gl_context/SCsub');
+SConscript('openssl/SCsub');
+
+if (env["png"]=="yes"):
+ SConscript("png/SCsub");
+if (env["jpg"]=="yes"):
+ SConscript("jpg/SCsub");
+if (env["webp"]=="yes"):
+ SConscript("webp/SCsub");
+SConscript("dds/SCsub");
+SConscript("pvr/SCsub");
+SConscript("etc1/SCsub")
+if (env["builtin_zlib"]=="yes"):
+ SConscript("builtin_zlib/SCsub");
+if (env["openssl"]=="builtin"):
+ SConscript("builtin_openssl2/SCsub");
+
+SConscript("rtaudio/SCsub");
+SConscript("nedmalloc/SCsub");
+SConscript("nrex/SCsub");
+SConscript("chibi/SCsub");
+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["theoralib"]=="yes"):
+ SConscript("theora/SCsub");
+if (env['speex']=='yes'):
+ SConscript("speex/SCsub");
+if (env['musepack']=='yes'):
+ SConscript("mpc/SCsub");
+if (env["squish"]=="yes" and env["tools"]=="yes"):
+ SConscript("squish/SCsub");
+
+num = 0
+cur_base = ""
+total = len(env.drivers_sources)
+max_src = 64
+list = []
+lib_list = []
+
+import string
+
+if env['vsproj']=="yes":
+ env.AddToVSProject(env.drivers_sources)
+
+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)
+
+ 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'])
+
+ lib = env.Library("drivers_collated", lib_list)
+ lib_list = [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 9d9a856376..4bc35f86ee 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h
index 86cdde6215..10f9298859 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/builtin_openssl/SCsub b/drivers/builtin_openssl/SCsub
deleted file mode 100644
index 701d3fbe24..0000000000
--- a/drivers/builtin_openssl/SCsub
+++ /dev/null
@@ -1,646 +0,0 @@
-Import('env')
-
-openssl_sources = [
-"builtin_openssl/nocpuid.c",
-"builtin_openssl/ssl/t1_lib.c",
-"builtin_openssl/ssl/s3_srvr.c",
-"builtin_openssl/ssl/t1_enc.c",
-"builtin_openssl/ssl/t1_meth.c",
-"builtin_openssl/ssl/s23_clnt.c",
-"builtin_openssl/ssl/ssl_asn1.c",
-"builtin_openssl/ssl/tls_srp.c",
-"builtin_openssl/ssl/kssl.c",
-"builtin_openssl/ssl/d1_both.c",
-"builtin_openssl/ssl/d1_enc.c",
-"builtin_openssl/ssl/t1_clnt.c",
-"builtin_openssl/ssl/bio_ssl.c",
-"builtin_openssl/ssl/d1_srtp.c",
-"builtin_openssl/ssl/t1_reneg.c",
-"builtin_openssl/ssl/ssl_cert.c",
-"builtin_openssl/ssl/s3_lib.c",
-"builtin_openssl/ssl/d1_srvr.c",
-"builtin_openssl/ssl/s23_meth.c",
-"builtin_openssl/ssl/ssl_stat.c",
-"builtin_openssl/ssl/ssl_err.c",
-"builtin_openssl/ssl/ssl_algs.c",
-"builtin_openssl/ssl/s3_cbc.c",
-"builtin_openssl/ssl/d1_clnt.c",
-"builtin_openssl/ssl/s3_pkt.c",
-"builtin_openssl/ssl/d1_meth.c",
-"builtin_openssl/ssl/s3_both.c",
-"builtin_openssl/ssl/s2_enc.c",
-"builtin_openssl/ssl/s3_meth.c",
-"builtin_openssl/ssl/s3_enc.c",
-"builtin_openssl/ssl/s23_pkt.c",
-"builtin_openssl/ssl/s2_pkt.c",
-"builtin_openssl/ssl/d1_pkt.c",
-"builtin_openssl/ssl/ssl_rsa.c",
-"builtin_openssl/ssl/s23_srvr.c",
-"builtin_openssl/ssl/s2_meth.c",
-"builtin_openssl/ssl/s3_clnt.c",
-"builtin_openssl/ssl/s23_lib.c",
-"builtin_openssl/ssl/t1_srvr.c",
-"builtin_openssl/ssl/ssl_lib.c",
-"builtin_openssl/ssl/ssl_txt.c",
-"builtin_openssl/ssl/s2_srvr.c",
-"builtin_openssl/ssl/ssl_sess.c",
-"builtin_openssl/ssl/s2_clnt.c",
-"builtin_openssl/ssl/d1_lib.c",
-"builtin_openssl/ssl/s2_lib.c",
-"builtin_openssl/ssl/ssl_err2.c",
-"builtin_openssl/ssl/ssl_ciph.c",
-"builtin_openssl/crypto/dsa/dsa_lib.c",
-"builtin_openssl/crypto/dsa/dsa_pmeth.c",
-"builtin_openssl/crypto/dsa/dsa_ossl.c",
-"builtin_openssl/crypto/dsa/dsa_gen.c",
-"builtin_openssl/crypto/dsa/dsa_asn1.c",
-"builtin_openssl/crypto/dsa/dsa_prn.c",
-"builtin_openssl/crypto/dsa/dsa_sign.c",
-"builtin_openssl/crypto/dsa/dsa_key.c",
-"builtin_openssl/crypto/dsa/dsa_vrf.c",
-"builtin_openssl/crypto/dsa/dsa_err.c",
-"builtin_openssl/crypto/dsa/dsa_ameth.c",
-"builtin_openssl/crypto/dsa/dsa_depr.c",
-"builtin_openssl/crypto/x509/x509_lu.c",
-"builtin_openssl/crypto/x509/x509cset.c",
-"builtin_openssl/crypto/x509/x509_set.c",
-"builtin_openssl/crypto/x509/x509_d2.c",
-"builtin_openssl/crypto/x509/x509_txt.c",
-"builtin_openssl/crypto/x509/x509rset.c",
-"builtin_openssl/crypto/x509/by_dir.c",
-"builtin_openssl/crypto/x509/x509_vpm.c",
-"builtin_openssl/crypto/x509/x509_vfy.c",
-"builtin_openssl/crypto/x509/x509_trs.c",
-"builtin_openssl/crypto/x509/by_file.c",
-"builtin_openssl/crypto/x509/x509_obj.c",
-"builtin_openssl/crypto/x509/x509spki.c",
-"builtin_openssl/crypto/x509/x509_v3.c",
-"builtin_openssl/crypto/x509/x509_req.c",
-"builtin_openssl/crypto/x509/x509_att.c",
-"builtin_openssl/crypto/x509/x_all.c",
-"builtin_openssl/crypto/x509/x509_ext.c",
-"builtin_openssl/crypto/x509/x509type.c",
-"builtin_openssl/crypto/x509/x509_def.c",
-"builtin_openssl/crypto/x509/x509_err.c",
-"builtin_openssl/crypto/x509/x509name.c",
-"builtin_openssl/crypto/x509/x509_r2x.c",
-"builtin_openssl/crypto/x509/x509_cmp.c",
-"builtin_openssl/crypto/asn1/x_pkey.c",
-"builtin_openssl/crypto/asn1/a_gentm.c",
-"builtin_openssl/crypto/asn1/x_sig.c",
-"builtin_openssl/crypto/asn1/t_req.c",
-"builtin_openssl/crypto/asn1/t_pkey.c",
-"builtin_openssl/crypto/asn1/p8_pkey.c",
-"builtin_openssl/crypto/asn1/a_i2d_fp.c",
-"builtin_openssl/crypto/asn1/x_val.c",
-"builtin_openssl/crypto/asn1/f_string.c",
-"builtin_openssl/crypto/asn1/p5_pbe.c",
-"builtin_openssl/crypto/asn1/bio_ndef.c",
-"builtin_openssl/crypto/asn1/a_bool.c",
-"builtin_openssl/crypto/asn1/asn1_gen.c",
-"builtin_openssl/crypto/asn1/x_algor.c",
-"builtin_openssl/crypto/asn1/bio_asn1.c",
-"builtin_openssl/crypto/asn1/asn_mime.c",
-"builtin_openssl/crypto/asn1/t_x509.c",
-"builtin_openssl/crypto/asn1/a_strex.c",
-"builtin_openssl/crypto/asn1/x_nx509.c",
-"builtin_openssl/crypto/asn1/asn1_err.c",
-"builtin_openssl/crypto/asn1/x_crl.c",
-"builtin_openssl/crypto/asn1/a_print.c",
-"builtin_openssl/crypto/asn1/a_type.c",
-"builtin_openssl/crypto/asn1/tasn_new.c",
-"builtin_openssl/crypto/asn1/n_pkey.c",
-"builtin_openssl/crypto/asn1/x_bignum.c",
-"builtin_openssl/crypto/asn1/asn_pack.c",
-"builtin_openssl/crypto/asn1/evp_asn1.c",
-"builtin_openssl/crypto/asn1/t_bitst.c",
-"builtin_openssl/crypto/asn1/x_req.c",
-"builtin_openssl/crypto/asn1/a_time.c",
-"builtin_openssl/crypto/asn1/x_name.c",
-"builtin_openssl/crypto/asn1/x_pubkey.c",
-"builtin_openssl/crypto/asn1/tasn_typ.c",
-"builtin_openssl/crypto/asn1/asn_moid.c",
-"builtin_openssl/crypto/asn1/a_utctm.c",
-"builtin_openssl/crypto/asn1/asn1_lib.c",
-"builtin_openssl/crypto/asn1/x_x509a.c",
-"builtin_openssl/crypto/asn1/a_set.c",
-"builtin_openssl/crypto/asn1/t_crl.c",
-"builtin_openssl/crypto/asn1/p5_pbev2.c",
-"builtin_openssl/crypto/asn1/tasn_enc.c",
-"builtin_openssl/crypto/asn1/a_mbstr.c",
-"builtin_openssl/crypto/asn1/tasn_dec.c",
-"builtin_openssl/crypto/asn1/x_x509.c",
-"builtin_openssl/crypto/asn1/a_octet.c",
-"builtin_openssl/crypto/asn1/x_long.c",
-"builtin_openssl/crypto/asn1/a_bytes.c",
-"builtin_openssl/crypto/asn1/t_x509a.c",
-"builtin_openssl/crypto/asn1/a_enum.c",
-"builtin_openssl/crypto/asn1/a_int.c",
-"builtin_openssl/crypto/asn1/tasn_prn.c",
-"builtin_openssl/crypto/asn1/i2d_pr.c",
-"builtin_openssl/crypto/asn1/a_utf8.c",
-"builtin_openssl/crypto/asn1/t_spki.c",
-"builtin_openssl/crypto/asn1/a_digest.c",
-"builtin_openssl/crypto/asn1/a_dup.c",
-"builtin_openssl/crypto/asn1/i2d_pu.c",
-"builtin_openssl/crypto/asn1/a_verify.c",
-"builtin_openssl/crypto/asn1/f_enum.c",
-"builtin_openssl/crypto/asn1/a_sign.c",
-"builtin_openssl/crypto/asn1/d2i_pr.c",
-"builtin_openssl/crypto/asn1/asn1_par.c",
-"builtin_openssl/crypto/asn1/x_spki.c",
-"builtin_openssl/crypto/asn1/a_d2i_fp.c",
-"builtin_openssl/crypto/asn1/f_int.c",
-"builtin_openssl/crypto/asn1/x_exten.c",
-"builtin_openssl/crypto/asn1/tasn_utl.c",
-"builtin_openssl/crypto/asn1/nsseq.c",
-"builtin_openssl/crypto/asn1/a_bitstr.c",
-"builtin_openssl/crypto/asn1/x_info.c",
-"builtin_openssl/crypto/asn1/a_strnid.c",
-"builtin_openssl/crypto/asn1/a_object.c",
-"builtin_openssl/crypto/asn1/tasn_fre.c",
-"builtin_openssl/crypto/asn1/d2i_pu.c",
-"builtin_openssl/crypto/asn1/ameth_lib.c",
-"builtin_openssl/crypto/asn1/x_attrib.c",
-"builtin_openssl/crypto/evp/m_sha.c",
-"builtin_openssl/crypto/evp/e_camellia.c",
-"builtin_openssl/crypto/evp/e_aes.c",
-"builtin_openssl/crypto/evp/bio_b64.c",
-"builtin_openssl/crypto/evp/m_sigver.c",
-"builtin_openssl/crypto/evp/m_wp.c",
-"builtin_openssl/crypto/evp/m_sha1.c",
-"builtin_openssl/crypto/evp/p_seal.c",
-"builtin_openssl/crypto/evp/c_alld.c",
-"builtin_openssl/crypto/evp/p5_crpt.c",
-"builtin_openssl/crypto/evp/e_rc4.c",
-"builtin_openssl/crypto/evp/m_ecdsa.c",
-"builtin_openssl/crypto/evp/bio_enc.c",
-"builtin_openssl/crypto/evp/e_des3.c",
-"builtin_openssl/crypto/evp/m_null.c",
-"builtin_openssl/crypto/evp/bio_ok.c",
-"builtin_openssl/crypto/evp/pmeth_gn.c",
-"builtin_openssl/crypto/evp/e_rc5.c",
-"builtin_openssl/crypto/evp/e_rc2.c",
-"builtin_openssl/crypto/evp/p_dec.c",
-"builtin_openssl/crypto/evp/p_verify.c",
-"builtin_openssl/crypto/evp/e_rc4_hmac_md5.c",
-"builtin_openssl/crypto/evp/pmeth_lib.c",
-"builtin_openssl/crypto/evp/m_ripemd.c",
-"builtin_openssl/crypto/evp/m_md5.c",
-"builtin_openssl/crypto/evp/e_bf.c",
-"builtin_openssl/crypto/evp/p_enc.c",
-"builtin_openssl/crypto/evp/m_dss.c",
-"builtin_openssl/crypto/evp/bio_md.c",
-"builtin_openssl/crypto/evp/evp_pbe.c",
-"builtin_openssl/crypto/evp/e_seed.c",
-"builtin_openssl/crypto/evp/e_cast.c",
-"builtin_openssl/crypto/evp/p_open.c",
-"builtin_openssl/crypto/evp/p5_crpt2.c",
-"builtin_openssl/crypto/evp/m_dss1.c",
-"builtin_openssl/crypto/evp/names.c",
-"builtin_openssl/crypto/evp/evp_acnf.c",
-"builtin_openssl/crypto/evp/e_des.c",
-"builtin_openssl/crypto/evp/evp_cnf.c",
-"builtin_openssl/crypto/evp/evp_lib.c",
-"builtin_openssl/crypto/evp/digest.c",
-"builtin_openssl/crypto/evp/evp_err.c",
-"builtin_openssl/crypto/evp/evp_enc.c",
-"builtin_openssl/crypto/evp/e_old.c",
-"builtin_openssl/crypto/evp/c_all.c",
-"builtin_openssl/crypto/evp/m_md2.c",
-"builtin_openssl/crypto/evp/e_xcbc_d.c",
-"builtin_openssl/crypto/evp/evp_fips.c",
-"builtin_openssl/crypto/evp/pmeth_fn.c",
-"builtin_openssl/crypto/evp/p_lib.c",
-"builtin_openssl/crypto/evp/evp_key.c",
-"builtin_openssl/crypto/evp/encode.c",
-"builtin_openssl/crypto/evp/e_aes_cbc_hmac_sha1.c",
-"builtin_openssl/crypto/evp/m_mdc2.c",
-"builtin_openssl/crypto/evp/e_null.c",
-"builtin_openssl/crypto/evp/p_sign.c",
-"builtin_openssl/crypto/evp/e_idea.c",
-"builtin_openssl/crypto/evp/c_allc.c",
-"builtin_openssl/crypto/evp/evp_pkey.c",
-"builtin_openssl/crypto/evp/m_md4.c",
-"builtin_openssl/crypto/ex_data.c",
-"builtin_openssl/crypto/pkcs12/p12_p8e.c",
-"builtin_openssl/crypto/pkcs12/p12_crt.c",
-"builtin_openssl/crypto/pkcs12/p12_utl.c",
-"builtin_openssl/crypto/pkcs12/p12_attr.c",
-"builtin_openssl/crypto/pkcs12/p12_npas.c",
-"builtin_openssl/crypto/pkcs12/p12_decr.c",
-"builtin_openssl/crypto/pkcs12/p12_init.c",
-"builtin_openssl/crypto/pkcs12/p12_kiss.c",
-"builtin_openssl/crypto/pkcs12/p12_add.c",
-"builtin_openssl/crypto/pkcs12/p12_p8d.c",
-"builtin_openssl/crypto/pkcs12/p12_mutl.c",
-"builtin_openssl/crypto/pkcs12/p12_crpt.c",
-"builtin_openssl/crypto/pkcs12/pk12err.c",
-"builtin_openssl/crypto/pkcs12/p12_asn.c",
-"builtin_openssl/crypto/pkcs12/p12_key.c",
-"builtin_openssl/crypto/ecdh/ech_key.c",
-"builtin_openssl/crypto/ecdh/ech_ossl.c",
-"builtin_openssl/crypto/ecdh/ech_lib.c",
-"builtin_openssl/crypto/ecdh/ech_err.c",
-"builtin_openssl/crypto/o_str.c",
-"builtin_openssl/crypto/conf/conf_api.c",
-"builtin_openssl/crypto/conf/conf_err.c",
-"builtin_openssl/crypto/conf/conf_def.c",
-"builtin_openssl/crypto/conf/conf_lib.c",
-"builtin_openssl/crypto/conf/conf_mall.c",
-"builtin_openssl/crypto/conf/conf_sap.c",
-"builtin_openssl/crypto/conf/conf_mod.c",
-"builtin_openssl/crypto/ebcdic.c",
-"builtin_openssl/crypto/ecdsa/ecs_lib.c",
-"builtin_openssl/crypto/ecdsa/ecs_asn1.c",
-"builtin_openssl/crypto/ecdsa/ecs_ossl.c",
-"builtin_openssl/crypto/ecdsa/ecs_vrf.c",
-"builtin_openssl/crypto/ecdsa/ecs_sign.c",
-"builtin_openssl/crypto/ecdsa/ecs_err.c",
-"builtin_openssl/crypto/dso/dso_win32.c",
-"builtin_openssl/crypto/dso/dso_lib.c",
-"builtin_openssl/crypto/dso/dso_dlfcn.c",
-"builtin_openssl/crypto/dso/dso_dl.c",
-"builtin_openssl/crypto/dso/dso_beos.c",
-"builtin_openssl/crypto/dso/dso_null.c",
-"builtin_openssl/crypto/dso/dso_vms.c",
-"builtin_openssl/crypto/dso/dso_err.c",
-"builtin_openssl/crypto/dso/dso_openssl.c",
-"builtin_openssl/crypto/cryptlib.c",
-"builtin_openssl/crypto/md5/md5_one.c",
-"builtin_openssl/crypto/md5/md5_dgst.c",
-"builtin_openssl/crypto/pkcs7/pkcs7err.c",
-"builtin_openssl/crypto/pkcs7/pk7_smime.c",
-"builtin_openssl/crypto/pkcs7/bio_pk7.c",
-"builtin_openssl/crypto/pkcs7/pk7_mime.c",
-"builtin_openssl/crypto/pkcs7/pk7_lib.c",
-"builtin_openssl/crypto/pkcs7/pk7_asn1.c",
-"builtin_openssl/crypto/pkcs7/pk7_doit.c",
-"builtin_openssl/crypto/pkcs7/pk7_attr.c",
-"builtin_openssl/crypto/md4/md4_one.c",
-"builtin_openssl/crypto/md4/md4_dgst.c",
-"builtin_openssl/crypto/o_dir.c",
-"builtin_openssl/crypto/buffer/buf_err.c",
-"builtin_openssl/crypto/buffer/buf_str.c",
-"builtin_openssl/crypto/buffer/buffer.c",
-"builtin_openssl/crypto/cms/cms_lib.c",
-"builtin_openssl/crypto/cms/cms_io.c",
-"builtin_openssl/crypto/cms/cms_err.c",
-"builtin_openssl/crypto/cms/cms_dd.c",
-"builtin_openssl/crypto/cms/cms_smime.c",
-"builtin_openssl/crypto/cms/cms_att.c",
-"builtin_openssl/crypto/cms/cms_pwri.c",
-"builtin_openssl/crypto/cms/cms_cd.c",
-"builtin_openssl/crypto/cms/cms_sd.c",
-"builtin_openssl/crypto/cms/cms_asn1.c",
-"builtin_openssl/crypto/cms/cms_env.c",
-"builtin_openssl/crypto/cms/cms_enc.c",
-"builtin_openssl/crypto/cms/cms_ess.c",
-"builtin_openssl/crypto/mem_dbg.c",
-"builtin_openssl/crypto/uid.c",
-"builtin_openssl/crypto/stack/stack.c",
-"builtin_openssl/crypto/ec/ec_ameth.c",
-"builtin_openssl/crypto/ec/ec_err.c",
-"builtin_openssl/crypto/ec/ec_lib.c",
-"builtin_openssl/crypto/ec/ec_curve.c",
-"builtin_openssl/crypto/ec/ec_oct.c",
-"builtin_openssl/crypto/ec/ec_asn1.c",
-"builtin_openssl/crypto/ec/ecp_oct.c",
-"builtin_openssl/crypto/ec/ec_print.c",
-"builtin_openssl/crypto/ec/ec2_smpl.c",
-"builtin_openssl/crypto/ec/ecp_nistp224.c",
-"builtin_openssl/crypto/ec/ec2_oct.c",
-"builtin_openssl/crypto/ec/eck_prn.c",
-"builtin_openssl/crypto/ec/ec_key.c",
-"builtin_openssl/crypto/ec/ecp_nist.c",
-"builtin_openssl/crypto/ec/ec_check.c",
-"builtin_openssl/crypto/ec/ecp_smpl.c",
-"builtin_openssl/crypto/ec/ec2_mult.c",
-"builtin_openssl/crypto/ec/ecp_mont.c",
-"builtin_openssl/crypto/ec/ecp_nistp521.c",
-"builtin_openssl/crypto/ec/ec_mult.c",
-"builtin_openssl/crypto/ec/ecp_nistputil.c",
-"builtin_openssl/crypto/ec/ec_pmeth.c",
-"builtin_openssl/crypto/ec/ec_cvt.c",
-"builtin_openssl/crypto/ec/ecp_nistp256.c",
-"builtin_openssl/crypto/krb5/krb5_asn.c",
-"builtin_openssl/crypto/hmac/hmac.c",
-"builtin_openssl/crypto/hmac/hm_ameth.c",
-"builtin_openssl/crypto/hmac/hm_pmeth.c",
-"builtin_openssl/crypto/comp/c_rle.c",
-"builtin_openssl/crypto/comp/c_zlib.c",
-"builtin_openssl/crypto/comp/comp_lib.c",
-"builtin_openssl/crypto/comp/comp_err.c",
-"builtin_openssl/crypto/des/fcrypt.c",
-"builtin_openssl/crypto/des/str2key.c",
-"builtin_openssl/crypto/des/cbc_cksm.c",
-"builtin_openssl/crypto/des/des_enc.c",
-"builtin_openssl/crypto/des/ofb_enc.c",
-"builtin_openssl/crypto/des/read2pwd.c",
-"builtin_openssl/crypto/des/ecb3_enc.c",
-"builtin_openssl/crypto/des/rand_key.c",
-"builtin_openssl/crypto/des/cfb64ede.c",
-"builtin_openssl/crypto/des/rpc_enc.c",
-"builtin_openssl/crypto/des/ofb64ede.c",
-"builtin_openssl/crypto/des/qud_cksm.c",
-"builtin_openssl/crypto/des/enc_writ.c",
-"builtin_openssl/crypto/des/set_key.c",
-"builtin_openssl/crypto/des/xcbc_enc.c",
-"builtin_openssl/crypto/des/fcrypt_b.c",
-"builtin_openssl/crypto/des/ede_cbcm_enc.c",
-"builtin_openssl/crypto/des/des_old2.c",
-"builtin_openssl/crypto/des/cfb_enc.c",
-"builtin_openssl/crypto/des/ecb_enc.c",
-"builtin_openssl/crypto/des/enc_read.c",
-"builtin_openssl/crypto/des/des_old.c",
-"builtin_openssl/crypto/des/ofb64enc.c",
-"builtin_openssl/crypto/des/pcbc_enc.c",
-"builtin_openssl/crypto/des/cbc_enc.c",
-"builtin_openssl/crypto/des/cfb64enc.c",
-"builtin_openssl/crypto/lhash/lh_stats.c",
-"builtin_openssl/crypto/lhash/lhash.c",
-"builtin_openssl/crypto/x509v3/v3_genn.c",
-"builtin_openssl/crypto/x509v3/pcy_cache.c",
-"builtin_openssl/crypto/x509v3/v3_sxnet.c",
-"builtin_openssl/crypto/x509v3/v3err.c",
-"builtin_openssl/crypto/x509v3/v3_conf.c",
-"builtin_openssl/crypto/x509v3/v3_utl.c",
-"builtin_openssl/crypto/x509v3/v3_akeya.c",
-"builtin_openssl/crypto/x509v3/v3_lib.c",
-"builtin_openssl/crypto/x509v3/pcy_lib.c",
-"builtin_openssl/crypto/x509v3/v3_cpols.c",
-"builtin_openssl/crypto/x509v3/v3_ia5.c",
-"builtin_openssl/crypto/x509v3/v3_bitst.c",
-"builtin_openssl/crypto/x509v3/v3_skey.c",
-"builtin_openssl/crypto/x509v3/v3_info.c",
-"builtin_openssl/crypto/x509v3/v3_asid.c",
-"builtin_openssl/crypto/x509v3/pcy_tree.c",
-"builtin_openssl/crypto/x509v3/v3_pcons.c",
-"builtin_openssl/crypto/x509v3/v3_bcons.c",
-"builtin_openssl/crypto/x509v3/v3_pku.c",
-"builtin_openssl/crypto/x509v3/v3_ocsp.c",
-"builtin_openssl/crypto/x509v3/pcy_map.c",
-"builtin_openssl/crypto/x509v3/v3_ncons.c",
-"builtin_openssl/crypto/x509v3/v3_purp.c",
-"builtin_openssl/crypto/x509v3/v3_enum.c",
-"builtin_openssl/crypto/x509v3/v3_pmaps.c",
-"builtin_openssl/crypto/x509v3/pcy_node.c",
-"builtin_openssl/crypto/x509v3/v3_pcia.c",
-"builtin_openssl/crypto/x509v3/v3_crld.c",
-"builtin_openssl/crypto/x509v3/v3_pci.c",
-"builtin_openssl/crypto/x509v3/v3_akey.c",
-"builtin_openssl/crypto/x509v3/v3_addr.c",
-"builtin_openssl/crypto/x509v3/v3_int.c",
-"builtin_openssl/crypto/x509v3/v3_alt.c",
-"builtin_openssl/crypto/x509v3/v3_extku.c",
-"builtin_openssl/crypto/x509v3/v3_prn.c",
-"builtin_openssl/crypto/x509v3/pcy_data.c",
-"builtin_openssl/crypto/aes/aes_ofb.c",
-"builtin_openssl/crypto/aes/aes_ctr.c",
-"builtin_openssl/crypto/aes/aes_ecb.c",
-"builtin_openssl/crypto/aes/aes_cfb.c",
-"builtin_openssl/crypto/aes/aes_wrap.c",
-"builtin_openssl/crypto/aes/aes_ige.c",
-"builtin_openssl/crypto/aes/aes_misc.c",
-"builtin_openssl/crypto/pqueue/pqueue.c",
-"builtin_openssl/crypto/sha/sha_one.c",
-"builtin_openssl/crypto/sha/sha_dgst.c",
-"builtin_openssl/crypto/sha/sha512.c",
-"builtin_openssl/crypto/sha/sha1_one.c",
-"builtin_openssl/crypto/sha/sha1dgst.c",
-"builtin_openssl/crypto/sha/sha256.c",
-"builtin_openssl/crypto/whrlpool/wp_dgst.c",
-"builtin_openssl/crypto/objects/obj_xref.c",
-"builtin_openssl/crypto/objects/o_names.c",
-"builtin_openssl/crypto/objects/obj_err.c",
-"builtin_openssl/crypto/objects/obj_dat.c",
-"builtin_openssl/crypto/objects/obj_lib.c",
-"builtin_openssl/crypto/mem.c",
-"builtin_openssl/crypto/fips_ers.c",
-"builtin_openssl/crypto/o_fips.c",
-"builtin_openssl/crypto/engine/eng_rdrand.c",
-"builtin_openssl/crypto/engine/eng_err.c",
-"builtin_openssl/crypto/engine/eng_rsax.c",
-"builtin_openssl/crypto/engine/tb_ecdsa.c",
-"builtin_openssl/crypto/engine/tb_rsa.c",
-"builtin_openssl/crypto/engine/tb_cipher.c",
-"builtin_openssl/crypto/engine/tb_dsa.c",
-"builtin_openssl/crypto/engine/eng_lib.c",
-"builtin_openssl/crypto/engine/tb_asnmth.c",
-"builtin_openssl/crypto/engine/tb_ecdh.c",
-"builtin_openssl/crypto/engine/tb_dh.c",
-"builtin_openssl/crypto/engine/tb_store.c",
-"builtin_openssl/crypto/engine/eng_init.c",
-"builtin_openssl/crypto/engine/eng_cnf.c",
-"builtin_openssl/crypto/engine/eng_all.c",
-"builtin_openssl/crypto/engine/tb_digest.c",
-"builtin_openssl/crypto/engine/tb_pkmeth.c",
-"builtin_openssl/crypto/engine/eng_table.c",
-"builtin_openssl/crypto/engine/eng_ctrl.c",
-"builtin_openssl/crypto/engine/eng_list.c",
-"builtin_openssl/crypto/engine/eng_cryptodev.c",
-"builtin_openssl/crypto/engine/eng_pkey.c",
-"builtin_openssl/crypto/engine/tb_rand.c",
-"builtin_openssl/crypto/engine/eng_openssl.c",
-"builtin_openssl/crypto/engine/eng_fat.c",
-"builtin_openssl/crypto/engine/eng_dyn.c",
-"builtin_openssl/crypto/ts/ts_rsp_verify.c",
-"builtin_openssl/crypto/ts/ts_req_print.c",
-"builtin_openssl/crypto/ts/ts_verify_ctx.c",
-"builtin_openssl/crypto/ts/ts_req_utils.c",
-"builtin_openssl/crypto/ts/ts_err.c",
-"builtin_openssl/crypto/ts/ts_rsp_print.c",
-"builtin_openssl/crypto/ts/ts_rsp_utils.c",
-"builtin_openssl/crypto/ts/ts_lib.c",
-"builtin_openssl/crypto/ts/ts_conf.c",
-"builtin_openssl/crypto/ts/ts_asn1.c",
-"builtin_openssl/crypto/ts/ts_rsp_sign.c",
-"builtin_openssl/crypto/ocsp/ocsp_ext.c",
-"builtin_openssl/crypto/ocsp/ocsp_cl.c",
-"builtin_openssl/crypto/ocsp/ocsp_ht.c",
-"builtin_openssl/crypto/ocsp/ocsp_lib.c",
-"builtin_openssl/crypto/ocsp/ocsp_srv.c",
-"builtin_openssl/crypto/ocsp/ocsp_vfy.c",
-"builtin_openssl/crypto/ocsp/ocsp_err.c",
-"builtin_openssl/crypto/ocsp/ocsp_prn.c",
-"builtin_openssl/crypto/ocsp/ocsp_asn.c",
-"builtin_openssl/crypto/bf/bf_cfb64.c",
-"builtin_openssl/crypto/bf/bf_ecb.c",
-"builtin_openssl/crypto/bf/bf_enc.c",
-"builtin_openssl/crypto/bf/bf_skey.c",
-"builtin_openssl/crypto/bf/bf_ofb64.c",
-"builtin_openssl/crypto/idea/i_skey.c",
-"builtin_openssl/crypto/idea/i_ofb64.c",
-"builtin_openssl/crypto/idea/i_cbc.c",
-"builtin_openssl/crypto/idea/i_ecb.c",
-"builtin_openssl/crypto/idea/i_cfb64.c",
-"builtin_openssl/crypto/cmac/cm_ameth.c",
-"builtin_openssl/crypto/cmac/cmac.c",
-"builtin_openssl/crypto/cmac/cm_pmeth.c",
-"builtin_openssl/crypto/dh/dh_lib.c",
-"builtin_openssl/crypto/dh/dh_key.c",
-"builtin_openssl/crypto/dh/dh_asn1.c",
-"builtin_openssl/crypto/dh/dh_depr.c",
-"builtin_openssl/crypto/dh/dh_pmeth.c",
-"builtin_openssl/crypto/dh/dh_prn.c",
-"builtin_openssl/crypto/dh/dh_gen.c",
-"builtin_openssl/crypto/dh/dh_ameth.c",
-"builtin_openssl/crypto/dh/dh_check.c",
-"builtin_openssl/crypto/dh/dh_err.c",
-"builtin_openssl/crypto/modes/ccm128.c",
-"builtin_openssl/crypto/modes/ofb128.c",
-"builtin_openssl/crypto/modes/cts128.c",
-"builtin_openssl/crypto/modes/ctr128.c",
-"builtin_openssl/crypto/modes/gcm128.c",
-"builtin_openssl/crypto/modes/cbc128.c",
-"builtin_openssl/crypto/modes/cfb128.c",
-"builtin_openssl/crypto/modes/xts128.c",
-"builtin_openssl/crypto/camellia/cmll_cfb.c",
-"builtin_openssl/crypto/camellia/cmll_ecb.c",
-"builtin_openssl/crypto/camellia/cmll_utl.c",
-"builtin_openssl/crypto/camellia/cmll_misc.c",
-"builtin_openssl/crypto/camellia/cmll_ofb.c",
-"builtin_openssl/crypto/camellia/cmll_ctr.c",
-"builtin_openssl/crypto/seed/seed_ecb.c",
-"builtin_openssl/crypto/seed/seed_cbc.c",
-"builtin_openssl/crypto/seed/seed.c",
-"builtin_openssl/crypto/seed/seed_ofb.c",
-"builtin_openssl/crypto/seed/seed_cfb.c",
-"builtin_openssl/crypto/txt_db/txt_db.c",
-"builtin_openssl/crypto/cpt_err.c",
-"builtin_openssl/crypto/pem/pem_pk8.c",
-"builtin_openssl/crypto/pem/pem_lib.c",
-"builtin_openssl/crypto/pem/pem_sign.c",
-"builtin_openssl/crypto/pem/pem_all.c",
-"builtin_openssl/crypto/pem/pem_info.c",
-"builtin_openssl/crypto/pem/pem_pkey.c",
-"builtin_openssl/crypto/pem/pem_seal.c",
-"builtin_openssl/crypto/pem/pem_err.c",
-"builtin_openssl/crypto/pem/pem_xaux.c",
-"builtin_openssl/crypto/pem/pvkfmt.c",
-"builtin_openssl/crypto/pem/pem_x509.c",
-"builtin_openssl/crypto/pem/pem_oth.c",
-"builtin_openssl/crypto/rand/rand_lib.c",
-"builtin_openssl/crypto/rand/randfile.c",
-"builtin_openssl/crypto/rand/rand_os2.c",
-"builtin_openssl/crypto/rand/rand_unix.c",
-"builtin_openssl/crypto/rand/rand_nw.c",
-"builtin_openssl/crypto/rand/md_rand.c",
-"builtin_openssl/crypto/rand/rand_err.c",
-"builtin_openssl/crypto/rand/rand_win.c",
-"builtin_openssl/crypto/rand/rand_egd.c",
-"builtin_openssl/crypto/cversion.c",
-"builtin_openssl/crypto/cast/c_ecb.c",
-"builtin_openssl/crypto/cast/c_skey.c",
-"builtin_openssl/crypto/cast/c_ofb64.c",
-"builtin_openssl/crypto/cast/c_enc.c",
-"builtin_openssl/crypto/cast/c_cfb64.c",
-"builtin_openssl/crypto/o_time.c",
-"builtin_openssl/crypto/mdc2/mdc2dgst.c",
-"builtin_openssl/crypto/mdc2/mdc2_one.c",
-"builtin_openssl/crypto/rc4/rc4_utl.c",
-"builtin_openssl/crypto/ui/ui_compat.c",
-"builtin_openssl/crypto/ui/ui_util.c",
-"builtin_openssl/crypto/ui/ui_lib.c",
-"builtin_openssl/crypto/ui/ui_err.c",
-"builtin_openssl/crypto/ui/ui_openssl.c",
-"builtin_openssl/crypto/bio/bf_buff.c",
-"builtin_openssl/crypto/bio/bss_null.c",
-"builtin_openssl/crypto/bio/bss_acpt.c",
-"builtin_openssl/crypto/bio/bss_conn.c",
-"builtin_openssl/crypto/bio/bss_fd.c",
-"builtin_openssl/crypto/bio/bf_null.c",
-"builtin_openssl/crypto/bio/bio_err.c",
-"builtin_openssl/crypto/bio/bss_sock.c",
-"builtin_openssl/crypto/bio/bss_mem.c",
-"builtin_openssl/crypto/bio/b_dump.c",
-"builtin_openssl/crypto/bio/b_print.c",
-"builtin_openssl/crypto/bio/b_sock.c",
-"builtin_openssl/crypto/bio/bss_dgram.c",
-"builtin_openssl/crypto/bio/bf_nbio.c",
-"builtin_openssl/crypto/bio/bio_lib.c",
-"builtin_openssl/crypto/bio/bss_file.c",
-"builtin_openssl/crypto/bio/bss_bio.c",
-"builtin_openssl/crypto/bio/bss_log.c",
-"builtin_openssl/crypto/bio/bio_cb.c",
-"builtin_openssl/crypto/o_init.c",
-"builtin_openssl/crypto/rc2/rc2_skey.c",
-"builtin_openssl/crypto/rc2/rc2_cbc.c",
-"builtin_openssl/crypto/rc2/rc2cfb64.c",
-"builtin_openssl/crypto/rc2/rc2_ecb.c",
-"builtin_openssl/crypto/rc2/rc2ofb64.c",
-"builtin_openssl/crypto/bn/bn_x931p.c",
-"builtin_openssl/crypto/bn/bn_blind.c",
-"builtin_openssl/crypto/bn/bn_gf2m.c",
-"builtin_openssl/crypto/bn/bn_const.c",
-"builtin_openssl/crypto/bn/bn_sqr.c",
-"builtin_openssl/crypto/bn/bn_nist.c",
-"builtin_openssl/crypto/bn/bn_rand.c",
-"builtin_openssl/crypto/bn/bn_err.c",
-"builtin_openssl/crypto/bn/bn_div.c",
-"builtin_openssl/crypto/bn/bn_kron.c",
-"builtin_openssl/crypto/bn/bn_ctx.c",
-"builtin_openssl/crypto/bn/bn_shift.c",
-"builtin_openssl/crypto/bn/bn_mod.c",
-"builtin_openssl/crypto/bn/bn_exp2.c",
-"builtin_openssl/crypto/bn/bn_word.c",
-"builtin_openssl/crypto/bn/bn_add.c",
-"builtin_openssl/crypto/bn/bn_exp.c",
-"builtin_openssl/crypto/bn/bn_mont.c",
-"builtin_openssl/crypto/bn/bn_print.c",
-"builtin_openssl/crypto/bn/bn_mul.c",
-"builtin_openssl/crypto/bn/bn_prime.c",
-"builtin_openssl/crypto/bn/bn_depr.c",
-"builtin_openssl/crypto/bn/bn_gcd.c",
-"builtin_openssl/crypto/bn/bn_mpi.c",
-"builtin_openssl/crypto/bn/bn_sqrt.c",
-"builtin_openssl/crypto/bn/bn_recp.c",
-"builtin_openssl/crypto/bn/bn_lib.c",
-"builtin_openssl/crypto/ripemd/rmd_dgst.c",
-"builtin_openssl/crypto/ripemd/rmd_one.c",
-"builtin_openssl/crypto/rsa/rsa_x931.c",
-"builtin_openssl/crypto/rsa/rsa_depr.c",
-"builtin_openssl/crypto/rsa/rsa_saos.c",
-"builtin_openssl/crypto/rsa/rsa_crpt.c",
-"builtin_openssl/crypto/rsa/rsa_pss.c",
-"builtin_openssl/crypto/rsa/rsa_oaep.c",
-"builtin_openssl/crypto/rsa/rsa_null.c",
-"builtin_openssl/crypto/rsa/rsa_gen.c",
-"builtin_openssl/crypto/rsa/rsa_prn.c",
-"builtin_openssl/crypto/rsa/rsa_pmeth.c",
-"builtin_openssl/crypto/rsa/rsa_asn1.c",
-"builtin_openssl/crypto/rsa/rsa_ssl.c",
-"builtin_openssl/crypto/rsa/rsa_ameth.c",
-"builtin_openssl/crypto/rsa/rsa_pk1.c",
-"builtin_openssl/crypto/rsa/rsa_err.c",
-"builtin_openssl/crypto/rsa/rsa_lib.c",
-"builtin_openssl/crypto/rsa/rsa_none.c",
-"builtin_openssl/crypto/rsa/rsa_chk.c",
-"builtin_openssl/crypto/rsa/rsa_eay.c",
-"builtin_openssl/crypto/rsa/rsa_sign.c",
-"builtin_openssl/crypto/srp/srp_lib.c",
-"builtin_openssl/crypto/srp/srp_vfy.c",
-"builtin_openssl/crypto/err/err.c",
-"builtin_openssl/crypto/err/err_prn.c",
-"builtin_openssl/crypto/err/err_all.c",
-"builtin_openssl/crypto/mem_clr.c",
-"builtin_openssl/crypto/rc4/rc4_skey.c",
-"builtin_openssl/crypto/rc4/rc4_enc.c",
-"builtin_openssl/crypto/camellia/camellia.c",
-"builtin_openssl/crypto/camellia/cmll_cbc.c",
-#"builtin_openssl/crypto/aes/aes_x86core.c",
-"builtin_openssl/crypto/aes/aes_core.c",
-"builtin_openssl/crypto/aes/aes_cbc.c",
-"builtin_openssl/crypto/whrlpool/wp_block.c",
-"builtin_openssl/crypto/bn/bn_asm.c",
-]
-
-
-env.drivers_sources+=openssl_sources
-env.Append(CPPPATH=["#drivers/builtin_openssl/crypto"])
-env.Append(CPPPATH=["#drivers/builtin_openssl/crypto/evp"])
-env.Append(CPPPATH=["#drivers/builtin_openssl/crypto/asn1"])
-env.Append(CPPPATH=["#drivers/builtin_openssl/crypto/modes"])
-#env.Append(CPPPATH=["#drivers/builtin_openssl/crypto/store"])
-env.Append(CPPFLAGS=["-DOPENSSL_NO_ASM","-DOPENSSL_THREADS","-DL_ENDIAN"])
-Export('env')
diff --git a/drivers/builtin_openssl/crypto/asn1/a_strnid.c b/drivers/builtin_openssl/crypto/asn1/a_strnid.c
deleted file mode 100644
index 2fc48c1551..0000000000
--- a/drivers/builtin_openssl/crypto/asn1/a_strnid.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/* a_strnid.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 1999.
- */
-/* ====================================================================
- * Copyright (c) 1999 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include "cryptlib.h"
-#include <openssl/asn1.h>
-#include <openssl/objects.h>
-
-
-static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
-static void st_free(ASN1_STRING_TABLE *tbl);
-static int sk_table_cmp(const ASN1_STRING_TABLE * const *a,
- const ASN1_STRING_TABLE * const *b);
-
-
-/* This is the global mask for the mbstring functions: this is use to
- * mask out certain types (such as BMPString and UTF8String) because
- * certain software (e.g. Netscape) has problems with them.
- */
-
-static unsigned long global_mask = 0xFFFFFFFFL;
-
-void ASN1_STRING_set_default_mask(unsigned long mask)
-{
- global_mask = mask;
-}
-
-unsigned long ASN1_STRING_get_default_mask(void)
-{
- return global_mask;
-}
-
-/* This function sets the default to various "flavours" of configuration.
- * based on an ASCII string. Currently this is:
- * MASK:XXXX : a numerical mask value.
- * nobmp : Don't use BMPStrings (just Printable, T61).
- * pkix : PKIX recommendation in RFC2459.
- * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004).
- * default: the default value, Printable, T61, BMP.
- */
-
-int ASN1_STRING_set_default_mask_asc(const char *p)
-{
- unsigned long mask;
- char *end;
- if(!strncmp(p, "MASK:", 5)) {
- if(!p[5]) return 0;
- mask = strtoul(p + 5, &end, 0);
- if(*end) return 0;
- } else if(!strcmp(p, "nombstr"))
- mask = ~((unsigned long)(B_ASN1_BMPSTRING|B_ASN1_UTF8STRING));
- else if(!strcmp(p, "pkix"))
- mask = ~((unsigned long)B_ASN1_T61STRING);
- else if(!strcmp(p, "utf8only")) mask = B_ASN1_UTF8STRING;
- else if(!strcmp(p, "default"))
- mask = 0xFFFFFFFFL;
- else return 0;
- ASN1_STRING_set_default_mask(mask);
- return 1;
-}
-
-/* The following function generates an ASN1_STRING based on limits in a table.
- * Frequently the types and length of an ASN1_STRING are restricted by a
- * corresponding OID. For example certificates and certificate requests.
- */
-
-ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in,
- int inlen, int inform, int nid)
-{
- ASN1_STRING_TABLE *tbl;
- ASN1_STRING *str = NULL;
- unsigned long mask;
- int ret;
- if(!out) out = &str;
- tbl = ASN1_STRING_TABLE_get(nid);
- if(tbl) {
- mask = tbl->mask;
- if(!(tbl->flags & STABLE_NO_MASK)) mask &= global_mask;
- ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask,
- tbl->minsize, tbl->maxsize);
- } else ret = ASN1_mbstring_copy(out, in, inlen, inform, DIRSTRING_TYPE & global_mask);
- if(ret <= 0) return NULL;
- return *out;
-}
-
-/* Now the tables and helper functions for the string table:
- */
-
-/* size limits: this stuff is taken straight from RFC3280 */
-
-#define ub_name 32768
-#define ub_common_name 64
-#define ub_locality_name 128
-#define ub_state_name 128
-#define ub_organization_name 64
-#define ub_organization_unit_name 64
-#define ub_title 64
-#define ub_email_address 128
-#define ub_serial_number 64
-
-
-/* This table must be kept in NID order */
-
-static const ASN1_STRING_TABLE tbl_standard[] = {
-{NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0},
-{NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
-{NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0},
-{NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0},
-{NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0},
-{NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE, 0},
-{NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK},
-{NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0},
-{NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0},
-{NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0},
-{NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0},
-{NID_surname, 1, ub_name, DIRSTRING_TYPE, 0},
-{NID_initials, 1, ub_name, DIRSTRING_TYPE, 0},
-{NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
-{NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
-{NID_name, 1, ub_name, DIRSTRING_TYPE, 0},
-{NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
-{NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK},
-{NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}
-};
-
-static int sk_table_cmp(const ASN1_STRING_TABLE * const *a,
- const ASN1_STRING_TABLE * const *b)
-{
- return (*a)->nid - (*b)->nid;
-}
-
-DECLARE_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
-
-static int table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b)
-{
- return a->nid - b->nid;
-}
-
-IMPLEMENT_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
-
-ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
-{
- int idx;
- ASN1_STRING_TABLE *ttmp;
- ASN1_STRING_TABLE fnd;
- fnd.nid = nid;
- ttmp = OBJ_bsearch_table(&fnd, tbl_standard,
- sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE));
- if(ttmp) return ttmp;
- if(!stable) return NULL;
- idx = sk_ASN1_STRING_TABLE_find(stable, &fnd);
- if(idx < 0) return NULL;
- return sk_ASN1_STRING_TABLE_value(stable, idx);
-}
-
-int ASN1_STRING_TABLE_add(int nid,
- long minsize, long maxsize, unsigned long mask,
- unsigned long flags)
-{
- ASN1_STRING_TABLE *tmp;
- char new_nid = 0;
- flags &= ~STABLE_FLAGS_MALLOC;
- if(!stable) stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp);
- if(!stable) {
- ASN1err(ASN1_F_ASN1_STRING_TABLE_ADD, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- if(!(tmp = ASN1_STRING_TABLE_get(nid))) {
- tmp = OPENSSL_malloc(sizeof(ASN1_STRING_TABLE));
- if(!tmp) {
- ASN1err(ASN1_F_ASN1_STRING_TABLE_ADD,
- ERR_R_MALLOC_FAILURE);
- return 0;
- }
- tmp->flags = flags | STABLE_FLAGS_MALLOC;
- tmp->nid = nid;
- new_nid = 1;
- } else tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags;
- if(minsize != -1) tmp->minsize = minsize;
- if(maxsize != -1) tmp->maxsize = maxsize;
- tmp->mask = mask;
- if(new_nid) sk_ASN1_STRING_TABLE_push(stable, tmp);
- return 1;
-}
-
-void ASN1_STRING_TABLE_cleanup(void)
-{
- STACK_OF(ASN1_STRING_TABLE) *tmp;
- tmp = stable;
- if(!tmp) return;
- stable = NULL;
- sk_ASN1_STRING_TABLE_pop_free(tmp, st_free);
-}
-
-static void st_free(ASN1_STRING_TABLE *tbl)
-{
- if(tbl->flags & STABLE_FLAGS_MALLOC) OPENSSL_free(tbl);
-}
-
-
-IMPLEMENT_STACK_OF(ASN1_STRING_TABLE)
-
-#ifdef STRING_TABLE_TEST
-
-main()
-{
- ASN1_STRING_TABLE *tmp;
- int i, last_nid = -1;
-
- for (tmp = tbl_standard, i = 0;
- i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++)
- {
- if (tmp->nid < last_nid)
- {
- last_nid = 0;
- break;
- }
- last_nid = tmp->nid;
- }
-
- if (last_nid != 0)
- {
- printf("Table order OK\n");
- exit(0);
- }
-
- for (tmp = tbl_standard, i = 0;
- i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++)
- printf("Index %d, NID %d, Name=%s\n", i, tmp->nid,
- OBJ_nid2ln(tmp->nid));
-
-}
-
-#endif
diff --git a/drivers/builtin_openssl/crypto/bio/bss_dgram.c b/drivers/builtin_openssl/crypto/bio/bss_dgram.c
deleted file mode 100644
index 54c012c47d..0000000000
--- a/drivers/builtin_openssl/crypto/bio/bss_dgram.c
+++ /dev/null
@@ -1,1865 +0,0 @@
-/* crypto/bio/bio_dgram.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-
-#include <stdio.h>
-#include <errno.h>
-#define USE_SOCKETS
-#include "cryptlib.h"
-
-#include <openssl/bio.h>
-#ifndef OPENSSL_NO_DGRAM
-
-#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS)
-#include <sys/timeb.h>
-#endif
-
-#ifndef OPENSSL_NO_SCTP
-#include <netinet/sctp.h>
-#include <fcntl.h>
-#define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00
-#define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0
-#endif
-
-#if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU)
-#define IP_MTU 14 /* linux is lame */
-#endif
-
-#if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED)
-/* Standard definition causes type-punning problems. */
-#undef IN6_IS_ADDR_V4MAPPED
-#define s6_addr32 __u6_addr.__u6_addr32
-#define IN6_IS_ADDR_V4MAPPED(a) \
- (((a)->s6_addr32[0] == 0) && \
- ((a)->s6_addr32[1] == 0) && \
- ((a)->s6_addr32[2] == htonl(0x0000ffff)))
-#endif
-
-#ifdef WATT32
-#define sock_write SockWrite /* Watt-32 uses same names */
-#define sock_read SockRead
-#define sock_puts SockPuts
-#endif
-
-static int dgram_write(BIO *h, const char *buf, int num);
-static int dgram_read(BIO *h, char *buf, int size);
-static int dgram_puts(BIO *h, const char *str);
-static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2);
-static int dgram_new(BIO *h);
-static int dgram_free(BIO *data);
-static int dgram_clear(BIO *bio);
-
-#ifndef OPENSSL_NO_SCTP
-static int dgram_sctp_write(BIO *h, const char *buf, int num);
-static int dgram_sctp_read(BIO *h, char *buf, int size);
-static int dgram_sctp_puts(BIO *h, const char *str);
-static long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2);
-static int dgram_sctp_new(BIO *h);
-static int dgram_sctp_free(BIO *data);
-#ifdef SCTP_AUTHENTICATION_EVENT
-static void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp);
-#endif
-#endif
-
-static int BIO_dgram_should_retry(int s);
-
-static void get_current_time(struct timeval *t);
-
-static BIO_METHOD methods_dgramp=
- {
- BIO_TYPE_DGRAM,
- "datagram socket",
- dgram_write,
- dgram_read,
- dgram_puts,
- NULL, /* dgram_gets, */
- dgram_ctrl,
- dgram_new,
- dgram_free,
- NULL,
- };
-
-#ifndef OPENSSL_NO_SCTP
-static BIO_METHOD methods_dgramp_sctp=
- {
- BIO_TYPE_DGRAM_SCTP,
- "datagram sctp socket",
- dgram_sctp_write,
- dgram_sctp_read,
- dgram_sctp_puts,
- NULL, /* dgram_gets, */
- dgram_sctp_ctrl,
- dgram_sctp_new,
- dgram_sctp_free,
- NULL,
- };
-#endif
-
-typedef struct bio_dgram_data_st
- {
- union {
- struct sockaddr sa;
- struct sockaddr_in sa_in;
-#if OPENSSL_USE_IPV6
- struct sockaddr_in6 sa_in6;
-#endif
- } peer;
- unsigned int connected;
- unsigned int _errno;
- unsigned int mtu;
- struct timeval next_timeout;
- struct timeval socket_timeout;
- } bio_dgram_data;
-
-#ifndef OPENSSL_NO_SCTP
-typedef struct bio_dgram_sctp_save_message_st
- {
- BIO *bio;
- char *data;
- int length;
- } bio_dgram_sctp_save_message;
-
-typedef struct bio_dgram_sctp_data_st
- {
- union {
- struct sockaddr sa;
- struct sockaddr_in sa_in;
-#if OPENSSL_USE_IPV6
- struct sockaddr_in6 sa_in6;
-#endif
- } peer;
- unsigned int connected;
- unsigned int _errno;
- unsigned int mtu;
- struct bio_dgram_sctp_sndinfo sndinfo;
- struct bio_dgram_sctp_rcvinfo rcvinfo;
- struct bio_dgram_sctp_prinfo prinfo;
- void (*handle_notifications)(BIO *bio, void *context, void *buf);
- void* notification_context;
- int in_handshake;
- int ccs_rcvd;
- int ccs_sent;
- int save_shutdown;
- int peer_auth_tested;
- bio_dgram_sctp_save_message saved_message;
- } bio_dgram_sctp_data;
-#endif
-
-BIO_METHOD *BIO_s_datagram(void)
- {
- return(&methods_dgramp);
- }
-
-BIO *BIO_new_dgram(int fd, int close_flag)
- {
- BIO *ret;
-
- ret=BIO_new(BIO_s_datagram());
- if (ret == NULL) return(NULL);
- BIO_set_fd(ret,fd,close_flag);
- return(ret);
- }
-
-static int dgram_new(BIO *bi)
- {
- bio_dgram_data *data = NULL;
-
- bi->init=0;
- bi->num=0;
- data = OPENSSL_malloc(sizeof(bio_dgram_data));
- if (data == NULL)
- return 0;
- memset(data, 0x00, sizeof(bio_dgram_data));
- bi->ptr = data;
-
- bi->flags=0;
- return(1);
- }
-
-static int dgram_free(BIO *a)
- {
- bio_dgram_data *data;
-
- if (a == NULL) return(0);
- if ( ! dgram_clear(a))
- return 0;
-
- data = (bio_dgram_data *)a->ptr;
- if(data != NULL) OPENSSL_free(data);
-
- return(1);
- }
-
-static int dgram_clear(BIO *a)
- {
- if (a == NULL) return(0);
- if (a->shutdown)
- {
- if (a->init)
- {
- SHUTDOWN2(a->num);
- }
- a->init=0;
- a->flags=0;
- }
- return(1);
- }
-
-static void dgram_adjust_rcv_timeout(BIO *b)
- {
-#if defined(SO_RCVTIMEO)
- bio_dgram_data *data = (bio_dgram_data *)b->ptr;
- union { size_t s; int i; } sz = {0};
-
- /* Is a timer active? */
- if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0)
- {
- struct timeval timenow, timeleft;
-
- /* Read current socket timeout */
-#ifdef OPENSSL_SYS_WINDOWS
- int timeout;
-
- sz.i = sizeof(timeout);
- if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
- (void*)&timeout, &sz.i) < 0)
- { perror("getsockopt"); }
- else
- {
- data->socket_timeout.tv_sec = timeout / 1000;
- data->socket_timeout.tv_usec = (timeout % 1000) * 1000;
- }
-#else
- sz.i = sizeof(data->socket_timeout);
- if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
- &(data->socket_timeout), (void *)&sz) < 0)
- { perror("getsockopt"); }
- else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
- OPENSSL_assert(sz.s<=sizeof(data->socket_timeout));
-#endif
-
- /* Get current time */
- get_current_time(&timenow);
-
- /* Calculate time left until timer expires */
- memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval));
- timeleft.tv_sec -= timenow.tv_sec;
- timeleft.tv_usec -= timenow.tv_usec;
- if (timeleft.tv_usec < 0)
- {
- timeleft.tv_sec--;
- timeleft.tv_usec += 1000000;
- }
-
- if (timeleft.tv_sec < 0)
- {
- timeleft.tv_sec = 0;
- timeleft.tv_usec = 1;
- }
-
- /* Adjust socket timeout if next handhake message timer
- * will expire earlier.
- */
- if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) ||
- (data->socket_timeout.tv_sec > timeleft.tv_sec) ||
- (data->socket_timeout.tv_sec == timeleft.tv_sec &&
- data->socket_timeout.tv_usec >= timeleft.tv_usec))
- {
-#ifdef OPENSSL_SYS_WINDOWS
- timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000;
- if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
- (void*)&timeout, sizeof(timeout)) < 0)
- { perror("setsockopt"); }
-#else
- if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft,
- sizeof(struct timeval)) < 0)
- { perror("setsockopt"); }
-#endif
- }
- }
-#endif
- }
-
-static void dgram_reset_rcv_timeout(BIO *b)
- {
-#if defined(SO_RCVTIMEO)
- bio_dgram_data *data = (bio_dgram_data *)b->ptr;
-
- /* Is a timer active? */
- if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0)
- {
-#ifdef OPENSSL_SYS_WINDOWS
- int timeout = data->socket_timeout.tv_sec * 1000 +
- data->socket_timeout.tv_usec / 1000;
- if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
- (void*)&timeout, sizeof(timeout)) < 0)
- { perror("setsockopt"); }
-#else
- if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout),
- sizeof(struct timeval)) < 0)
- { perror("setsockopt"); }
-#endif
- }
-#endif
- }
-
-static int dgram_read(BIO *b, char *out, int outl)
- {
- int ret=0;
- bio_dgram_data *data = (bio_dgram_data *)b->ptr;
-
- struct {
- /*
- * See commentary in b_sock.c. <appro>
- */
- union { size_t s; int i; } len;
- union {
- struct sockaddr sa;
- struct sockaddr_in sa_in;
-#if OPENSSL_USE_IPV6
- struct sockaddr_in6 sa_in6;
-#endif
- } peer;
- } sa;
-
- sa.len.s=0;
- sa.len.i=sizeof(sa.peer);
-
- if (out != NULL)
- {
- clear_socket_error();
- memset(&sa.peer, 0x00, sizeof(sa.peer));
- dgram_adjust_rcv_timeout(b);
- ret=recvfrom(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len);
- if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0)
- {
- OPENSSL_assert(sa.len.s<=sizeof(sa.peer));
- sa.len.i = (int)sa.len.s;
- }
-
- if ( ! data->connected && ret >= 0)
- BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer);
-
- BIO_clear_retry_flags(b);
- if (ret < 0)
- {
- if (BIO_dgram_should_retry(ret))
- {
- BIO_set_retry_read(b);
- data->_errno = get_last_socket_error();
- }
- }
-
- dgram_reset_rcv_timeout(b);
- }
- return(ret);
- }
-
-static int dgram_write(BIO *b, const char *in, int inl)
- {
- int ret;
- bio_dgram_data *data = (bio_dgram_data *)b->ptr;
- clear_socket_error();
-
- if ( data->connected )
- ret=writesocket(b->num,in,inl);
- else
- {
- int peerlen = sizeof(data->peer);
-
- if (data->peer.sa.sa_family == AF_INET)
- peerlen = sizeof(data->peer.sa_in);
-#if OPENSSL_USE_IPV6
- else if (data->peer.sa.sa_family == AF_INET6)
- peerlen = sizeof(data->peer.sa_in6);
-#endif
-#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
- ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen);
-#else
- ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen);
-#endif
- }
-
- BIO_clear_retry_flags(b);
- if (ret <= 0)
- {
- if (BIO_dgram_should_retry(ret))
- {
- BIO_set_retry_write(b);
- data->_errno = get_last_socket_error();
-
-#if 0 /* higher layers are responsible for querying MTU, if necessary */
- if ( data->_errno == EMSGSIZE)
- /* retrieve the new MTU */
- BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
-#endif
- }
- }
- return(ret);
- }
-
-static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
- {
- long ret=1;
- int *ip;
- struct sockaddr *to = NULL;
- bio_dgram_data *data = NULL;
-#if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
- int sockopt_val = 0;
- socklen_t sockopt_len; /* assume that system supporting IP_MTU is
- * modern enough to define socklen_t */
- socklen_t addr_len;
- union {
- struct sockaddr sa;
- struct sockaddr_in s4;
-#if OPENSSL_USE_IPV6
- struct sockaddr_in6 s6;
-#endif
- } addr;
-#endif
-
- data = (bio_dgram_data *)b->ptr;
-
- switch (cmd)
- {
- case BIO_CTRL_RESET:
- num=0;
- case BIO_C_FILE_SEEK:
- ret=0;
- break;
- case BIO_C_FILE_TELL:
- case BIO_CTRL_INFO:
- ret=0;
- break;
- case BIO_C_SET_FD:
- dgram_clear(b);
- b->num= *((int *)ptr);
- b->shutdown=(int)num;
- b->init=1;
- break;
- case BIO_C_GET_FD:
- if (b->init)
- {
- ip=(int *)ptr;
- if (ip != NULL) *ip=b->num;
- ret=b->num;
- }
- else
- ret= -1;
- break;
- case BIO_CTRL_GET_CLOSE:
- ret=b->shutdown;
- break;
- case BIO_CTRL_SET_CLOSE:
- b->shutdown=(int)num;
- break;
- case BIO_CTRL_PENDING:
- case BIO_CTRL_WPENDING:
- ret=0;
- break;
- case BIO_CTRL_DUP:
- case BIO_CTRL_FLUSH:
- ret=1;
- break;
- case BIO_CTRL_DGRAM_CONNECT:
- to = (struct sockaddr *)ptr;
-#if 0
- if (connect(b->num, to, sizeof(struct sockaddr)) < 0)
- { perror("connect"); ret = 0; }
- else
- {
-#endif
- switch (to->sa_family)
- {
- case AF_INET:
- memcpy(&data->peer,to,sizeof(data->peer.sa_in));
- break;
-#if OPENSSL_USE_IPV6
- case AF_INET6:
- memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
- break;
-#endif
- default:
- memcpy(&data->peer,to,sizeof(data->peer.sa));
- break;
- }
-#if 0
- }
-#endif
- break;
- /* (Linux)kernel sets DF bit on outgoing IP packets */
- case BIO_CTRL_DGRAM_MTU_DISCOVER:
-#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
- addr_len = (socklen_t)sizeof(addr);
- memset((void *)&addr, 0, sizeof(addr));
- if (getsockname(b->num, &addr.sa, &addr_len) < 0)
- {
- ret = 0;
- break;
- }
- switch (addr.sa.sa_family)
- {
- case AF_INET:
- sockopt_val = IP_PMTUDISC_DO;
- if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
- &sockopt_val, sizeof(sockopt_val))) < 0)
- perror("setsockopt");
- break;
-#if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
- case AF_INET6:
- sockopt_val = IPV6_PMTUDISC_DO;
- if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
- &sockopt_val, sizeof(sockopt_val))) < 0)
- perror("setsockopt");
- break;
-#endif
- default:
- ret = -1;
- break;
- }
- ret = -1;
-#else
- break;
-#endif
- case BIO_CTRL_DGRAM_QUERY_MTU:
-#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU)
- addr_len = (socklen_t)sizeof(addr);
- memset((void *)&addr, 0, sizeof(addr));
- if (getsockname(b->num, &addr.sa, &addr_len) < 0)
- {
- ret = 0;
- break;
- }
- sockopt_len = sizeof(sockopt_val);
- switch (addr.sa.sa_family)
- {
- case AF_INET:
- if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val,
- &sockopt_len)) < 0 || sockopt_val < 0)
- {
- ret = 0;
- }
- else
- {
- /* we assume that the transport protocol is UDP and no
- * IP options are used.
- */
- data->mtu = sockopt_val - 8 - 20;
- ret = data->mtu;
- }
- break;
-#if OPENSSL_USE_IPV6 && defined(IPV6_MTU)
- case AF_INET6:
- if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val,
- &sockopt_len)) < 0 || sockopt_val < 0)
- {
- ret = 0;
- }
- else
- {
- /* we assume that the transport protocol is UDP and no
- * IPV6 options are used.
- */
- data->mtu = sockopt_val - 8 - 40;
- ret = data->mtu;
- }
- break;
-#endif
- default:
- ret = 0;
- break;
- }
-#else
- ret = 0;
-#endif
- break;
- case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
- switch (data->peer.sa.sa_family)
- {
- case AF_INET:
- ret = 576 - 20 - 8;
- break;
-#if OPENSSL_USE_IPV6
- case AF_INET6:
-#ifdef IN6_IS_ADDR_V4MAPPED
- if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr))
- ret = 576 - 20 - 8;
- else
-#endif
- ret = 1280 - 40 - 8;
- break;
-#endif
- default:
- ret = 576 - 20 - 8;
- break;
- }
- break;
- case BIO_CTRL_DGRAM_GET_MTU:
- return data->mtu;
- break;
- case BIO_CTRL_DGRAM_SET_MTU:
- data->mtu = num;
- ret = num;
- break;
- case BIO_CTRL_DGRAM_SET_CONNECTED:
- to = (struct sockaddr *)ptr;
-
- if ( to != NULL)
- {
- data->connected = 1;
- switch (to->sa_family)
- {
- case AF_INET:
- memcpy(&data->peer,to,sizeof(data->peer.sa_in));
- break;
-#if OPENSSL_USE_IPV6
- case AF_INET6:
- memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
- break;
-#endif
- default:
- memcpy(&data->peer,to,sizeof(data->peer.sa));
- break;
- }
- }
- else
- {
- data->connected = 0;
- memset(&(data->peer), 0x00, sizeof(data->peer));
- }
- break;
- case BIO_CTRL_DGRAM_GET_PEER:
- switch (data->peer.sa.sa_family)
- {
- case AF_INET:
- ret=sizeof(data->peer.sa_in);
- break;
-#if OPENSSL_USE_IPV6
- case AF_INET6:
- ret=sizeof(data->peer.sa_in6);
- break;
-#endif
- default:
- ret=sizeof(data->peer.sa);
- break;
- }
- if (num==0 || num>ret)
- num=ret;
- memcpy(ptr,&data->peer,(ret=num));
- break;
- case BIO_CTRL_DGRAM_SET_PEER:
- to = (struct sockaddr *) ptr;
- switch (to->sa_family)
- {
- case AF_INET:
- memcpy(&data->peer,to,sizeof(data->peer.sa_in));
- break;
-#if OPENSSL_USE_IPV6
- case AF_INET6:
- memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
- break;
-#endif
- default:
- memcpy(&data->peer,to,sizeof(data->peer.sa));
- break;
- }
- break;
- case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
- memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
- break;
-#if defined(SO_RCVTIMEO)
- case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
-#ifdef OPENSSL_SYS_WINDOWS
- {
- struct timeval *tv = (struct timeval *)ptr;
- int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
- if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
- (void*)&timeout, sizeof(timeout)) < 0)
- { perror("setsockopt"); ret = -1; }
- }
-#else
- if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
- sizeof(struct timeval)) < 0)
- { perror("setsockopt"); ret = -1; }
-#endif
- break;
- case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
- {
- union { size_t s; int i; } sz = {0};
-#ifdef OPENSSL_SYS_WINDOWS
- int timeout;
- struct timeval *tv = (struct timeval *)ptr;
-
- sz.i = sizeof(timeout);
- if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
- (void*)&timeout, &sz.i) < 0)
- { perror("getsockopt"); ret = -1; }
- else
- {
- tv->tv_sec = timeout / 1000;
- tv->tv_usec = (timeout % 1000) * 1000;
- ret = sizeof(*tv);
- }
-#else
- sz.i = sizeof(struct timeval);
- if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
- ptr, (void *)&sz) < 0)
- { perror("getsockopt"); ret = -1; }
- else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
- {
- OPENSSL_assert(sz.s<=sizeof(struct timeval));
- ret = (int)sz.s;
- }
- else
- ret = sz.i;
-#endif
- }
- break;
-#endif
-#if defined(SO_SNDTIMEO)
- case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
-#ifdef OPENSSL_SYS_WINDOWS
- {
- struct timeval *tv = (struct timeval *)ptr;
- int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
- if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
- (void*)&timeout, sizeof(timeout)) < 0)
- { perror("setsockopt"); ret = -1; }
- }
-#else
- if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
- sizeof(struct timeval)) < 0)
- { perror("setsockopt"); ret = -1; }
-#endif
- break;
- case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
- {
- union { size_t s; int i; } sz = {0};
-#ifdef OPENSSL_SYS_WINDOWS
- int timeout;
- struct timeval *tv = (struct timeval *)ptr;
-
- sz.i = sizeof(timeout);
- if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
- (void*)&timeout, &sz.i) < 0)
- { perror("getsockopt"); ret = -1; }
- else
- {
- tv->tv_sec = timeout / 1000;
- tv->tv_usec = (timeout % 1000) * 1000;
- ret = sizeof(*tv);
- }
-#else
- sz.i = sizeof(struct timeval);
- if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
- ptr, (void *)&sz) < 0)
- { perror("getsockopt"); ret = -1; }
- else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
- {
- OPENSSL_assert(sz.s<=sizeof(struct timeval));
- ret = (int)sz.s;
- }
- else
- ret = sz.i;
-#endif
- }
- break;
-#endif
- case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
- /* fall-through */
- case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
-#ifdef OPENSSL_SYS_WINDOWS
- if ( data->_errno == WSAETIMEDOUT)
-#else
- if ( data->_errno == EAGAIN)
-#endif
- {
- ret = 1;
- data->_errno = 0;
- }
- else
- ret = 0;
- break;
-#ifdef EMSGSIZE
- case BIO_CTRL_DGRAM_MTU_EXCEEDED:
- if ( data->_errno == EMSGSIZE)
- {
- ret = 1;
- data->_errno = 0;
- }
- else
- ret = 0;
- break;
-#endif
- default:
- ret=0;
- break;
- }
- return(ret);
- }
-
-static int dgram_puts(BIO *bp, const char *str)
- {
- int n,ret;
-
- n=strlen(str);
- ret=dgram_write(bp,str,n);
- return(ret);
- }
-
-#ifndef OPENSSL_NO_SCTP
-BIO_METHOD *BIO_s_datagram_sctp(void)
- {
- return(&methods_dgramp_sctp);
- }
-
-BIO *BIO_new_dgram_sctp(int fd, int close_flag)
- {
- BIO *bio;
- int ret, optval = 20000;
- int auth_data = 0, auth_forward = 0;
- unsigned char *p;
- struct sctp_authchunk auth;
- struct sctp_authchunks *authchunks;
- socklen_t sockopt_len;
-#ifdef SCTP_AUTHENTICATION_EVENT
-#ifdef SCTP_EVENT
- struct sctp_event event;
-#else
- struct sctp_event_subscribe event;
-#endif
-#endif
-
- bio=BIO_new(BIO_s_datagram_sctp());
- if (bio == NULL) return(NULL);
- BIO_set_fd(bio,fd,close_flag);
-
- /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */
- auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE;
- ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk));
- OPENSSL_assert(ret >= 0);
- auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE;
- ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk));
- OPENSSL_assert(ret >= 0);
-
- /* Test if activation was successful. When using accept(),
- * SCTP-AUTH has to be activated for the listening socket
- * already, otherwise the connected socket won't use it. */
- sockopt_len = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
- authchunks = OPENSSL_malloc(sockopt_len);
- memset(authchunks, 0, sizeof(sockopt_len));
- ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, &sockopt_len);
- OPENSSL_assert(ret >= 0);
-
- for (p = (unsigned char*) authchunks->gauth_chunks;
- p < (unsigned char*) authchunks + sockopt_len;
- p += sizeof(uint8_t))
- {
- if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1;
- if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1;
- }
-
- OPENSSL_free(authchunks);
-
- OPENSSL_assert(auth_data);
- OPENSSL_assert(auth_forward);
-
-#ifdef SCTP_AUTHENTICATION_EVENT
-#ifdef SCTP_EVENT
- memset(&event, 0, sizeof(struct sctp_event));
- event.se_assoc_id = 0;
- event.se_type = SCTP_AUTHENTICATION_EVENT;
- event.se_on = 1;
- ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
- OPENSSL_assert(ret >= 0);
-#else
- sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe);
- ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len);
- OPENSSL_assert(ret >= 0);
-
- event.sctp_authentication_event = 1;
-
- ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
- OPENSSL_assert(ret >= 0);
-#endif
-#endif
-
- /* Disable partial delivery by setting the min size
- * larger than the max record size of 2^14 + 2048 + 13
- */
- ret = setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, sizeof(optval));
- OPENSSL_assert(ret >= 0);
-
- return(bio);
- }
-
-int BIO_dgram_is_sctp(BIO *bio)
- {
- return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP);
- }
-
-static int dgram_sctp_new(BIO *bi)
- {
- bio_dgram_sctp_data *data = NULL;
-
- bi->init=0;
- bi->num=0;
- data = OPENSSL_malloc(sizeof(bio_dgram_sctp_data));
- if (data == NULL)
- return 0;
- memset(data, 0x00, sizeof(bio_dgram_sctp_data));
-#ifdef SCTP_PR_SCTP_NONE
- data->prinfo.pr_policy = SCTP_PR_SCTP_NONE;
-#endif
- bi->ptr = data;
-
- bi->flags=0;
- return(1);
- }
-
-static int dgram_sctp_free(BIO *a)
- {
- bio_dgram_sctp_data *data;
-
- if (a == NULL) return(0);
- if ( ! dgram_clear(a))
- return 0;
-
- data = (bio_dgram_sctp_data *)a->ptr;
- if(data != NULL) OPENSSL_free(data);
-
- return(1);
- }
-
-#ifdef SCTP_AUTHENTICATION_EVENT
-void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp)
- {
- int ret;
- struct sctp_authkey_event* authkeyevent = &snp->sn_auth_event;
-
- if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY)
- {
- struct sctp_authkeyid authkeyid;
-
- /* delete key */
- authkeyid.scact_keynumber = authkeyevent->auth_keynumber;
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
- &authkeyid, sizeof(struct sctp_authkeyid));
- }
- }
-#endif
-
-static int dgram_sctp_read(BIO *b, char *out, int outl)
- {
- int ret = 0, n = 0, i, optval;
- socklen_t optlen;
- bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
- union sctp_notification *snp;
- struct msghdr msg;
- struct iovec iov;
- struct cmsghdr *cmsg;
- char cmsgbuf[512];
-
- if (out != NULL)
- {
- clear_socket_error();
-
- do
- {
- memset(&data->rcvinfo, 0x00, sizeof(struct bio_dgram_sctp_rcvinfo));
- iov.iov_base = out;
- iov.iov_len = outl;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsgbuf;
- msg.msg_controllen = 512;
- msg.msg_flags = 0;
- n = recvmsg(b->num, &msg, 0);
-
- if (msg.msg_controllen > 0)
- {
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
- {
- if (cmsg->cmsg_level != IPPROTO_SCTP)
- continue;
-#ifdef SCTP_RCVINFO
- if (cmsg->cmsg_type == SCTP_RCVINFO)
- {
- struct sctp_rcvinfo *rcvinfo;
-
- rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
- data->rcvinfo.rcv_sid = rcvinfo->rcv_sid;
- data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn;
- data->rcvinfo.rcv_flags = rcvinfo->rcv_flags;
- data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid;
- data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn;
- data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn;
- data->rcvinfo.rcv_context = rcvinfo->rcv_context;
- }
-#endif
-#ifdef SCTP_SNDRCV
- if (cmsg->cmsg_type == SCTP_SNDRCV)
- {
- struct sctp_sndrcvinfo *sndrcvinfo;
-
- sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
- data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream;
- data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn;
- data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags;
- data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid;
- data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn;
- data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn;
- data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context;
- }
-#endif
- }
- }
-
- if (n <= 0)
- {
- if (n < 0)
- ret = n;
- break;
- }
-
- if (msg.msg_flags & MSG_NOTIFICATION)
- {
- snp = (union sctp_notification*) out;
- if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT)
- {
-#ifdef SCTP_EVENT
- struct sctp_event event;
-#else
- struct sctp_event_subscribe event;
- socklen_t eventsize;
-#endif
- /* If a message has been delayed until the socket
- * is dry, it can be sent now.
- */
- if (data->saved_message.length > 0)
- {
- dgram_sctp_write(data->saved_message.bio, data->saved_message.data,
- data->saved_message.length);
- OPENSSL_free(data->saved_message.data);
- data->saved_message.length = 0;
- }
-
- /* disable sender dry event */
-#ifdef SCTP_EVENT
- memset(&event, 0, sizeof(struct sctp_event));
- event.se_assoc_id = 0;
- event.se_type = SCTP_SENDER_DRY_EVENT;
- event.se_on = 0;
- i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
- OPENSSL_assert(i >= 0);
-#else
- eventsize = sizeof(struct sctp_event_subscribe);
- i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
- OPENSSL_assert(i >= 0);
-
- event.sctp_sender_dry_event = 0;
-
- i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
- OPENSSL_assert(i >= 0);
-#endif
- }
-
-#ifdef SCTP_AUTHENTICATION_EVENT
- if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
- dgram_sctp_handle_auth_free_key_event(b, snp);
-#endif
-
- if (data->handle_notifications != NULL)
- data->handle_notifications(b, data->notification_context, (void*) out);
-
- memset(out, 0, outl);
- }
- else
- ret += n;
- }
- while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) && (ret < outl));
-
- if (ret > 0 && !(msg.msg_flags & MSG_EOR))
- {
- /* Partial message read, this should never happen! */
-
- /* The buffer was too small, this means the peer sent
- * a message that was larger than allowed. */
- if (ret == outl)
- return -1;
-
- /* Test if socket buffer can handle max record
- * size (2^14 + 2048 + 13)
- */
- optlen = (socklen_t) sizeof(int);
- ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);
- OPENSSL_assert(ret >= 0);
- OPENSSL_assert(optval >= 18445);
-
- /* Test if SCTP doesn't partially deliver below
- * max record size (2^14 + 2048 + 13)
- */
- optlen = (socklen_t) sizeof(int);
- ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
- &optval, &optlen);
- OPENSSL_assert(ret >= 0);
- OPENSSL_assert(optval >= 18445);
-
- /* Partially delivered notification??? Probably a bug.... */
- OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION));
-
- /* Everything seems ok till now, so it's most likely
- * a message dropped by PR-SCTP.
- */
- memset(out, 0, outl);
- BIO_set_retry_read(b);
- return -1;
- }
-
- BIO_clear_retry_flags(b);
- if (ret < 0)
- {
- if (BIO_dgram_should_retry(ret))
- {
- BIO_set_retry_read(b);
- data->_errno = get_last_socket_error();
- }
- }
-
- /* Test if peer uses SCTP-AUTH before continuing */
- if (!data->peer_auth_tested)
- {
- int ii, auth_data = 0, auth_forward = 0;
- unsigned char *p;
- struct sctp_authchunks *authchunks;
-
- optlen = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
- authchunks = OPENSSL_malloc(optlen);
- memset(authchunks, 0, sizeof(optlen));
- ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, authchunks, &optlen);
- OPENSSL_assert(ii >= 0);
-
- for (p = (unsigned char*) authchunks->gauth_chunks;
- p < (unsigned char*) authchunks + optlen;
- p += sizeof(uint8_t))
- {
- if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1;
- if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1;
- }
-
- OPENSSL_free(authchunks);
-
- if (!auth_data || !auth_forward)
- {
- BIOerr(BIO_F_DGRAM_SCTP_READ,BIO_R_CONNECT_ERROR);
- return -1;
- }
-
- data->peer_auth_tested = 1;
- }
- }
- return(ret);
- }
-
-static int dgram_sctp_write(BIO *b, const char *in, int inl)
- {
- int ret;
- bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
- struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo);
- struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo);
- struct bio_dgram_sctp_sndinfo handshake_sinfo;
- struct iovec iov[1];
- struct msghdr msg;
- struct cmsghdr *cmsg;
-#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
- char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo))];
- struct sctp_sndinfo *sndinfo;
- struct sctp_prinfo *prinfo;
-#else
- char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
- struct sctp_sndrcvinfo *sndrcvinfo;
-#endif
-
- clear_socket_error();
-
- /* If we're send anything else than application data,
- * disable all user parameters and flags.
- */
- if (in[0] != 23) {
- memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo));
-#ifdef SCTP_SACK_IMMEDIATELY
- handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY;
-#endif
- sinfo = &handshake_sinfo;
- }
-
- /* If we have to send a shutdown alert message and the
- * socket is not dry yet, we have to save it and send it
- * as soon as the socket gets dry.
- */
- if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b))
- {
- data->saved_message.bio = b;
- data->saved_message.length = inl;
- data->saved_message.data = OPENSSL_malloc(inl);
- memcpy(data->saved_message.data, in, inl);
- return inl;
- }
-
- iov[0].iov_base = (char *)in;
- iov[0].iov_len = inl;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- msg.msg_control = (caddr_t)cmsgbuf;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
-#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
- cmsg = (struct cmsghdr *)cmsgbuf;
- cmsg->cmsg_level = IPPROTO_SCTP;
- cmsg->cmsg_type = SCTP_SNDINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
- sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg);
- memset(sndinfo, 0, sizeof(struct sctp_sndinfo));
- sndinfo->snd_sid = sinfo->snd_sid;
- sndinfo->snd_flags = sinfo->snd_flags;
- sndinfo->snd_ppid = sinfo->snd_ppid;
- sndinfo->snd_context = sinfo->snd_context;
- msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
-
- cmsg = (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))];
- cmsg->cmsg_level = IPPROTO_SCTP;
- cmsg->cmsg_type = SCTP_PRINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
- prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg);
- memset(prinfo, 0, sizeof(struct sctp_prinfo));
- prinfo->pr_policy = pinfo->pr_policy;
- prinfo->pr_value = pinfo->pr_value;
- msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
-#else
- cmsg = (struct cmsghdr *)cmsgbuf;
- cmsg->cmsg_level = IPPROTO_SCTP;
- cmsg->cmsg_type = SCTP_SNDRCV;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
- sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
- memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo));
- sndrcvinfo->sinfo_stream = sinfo->snd_sid;
- sndrcvinfo->sinfo_flags = sinfo->snd_flags;
-#ifdef __FreeBSD__
- sndrcvinfo->sinfo_flags |= pinfo->pr_policy;
-#endif
- sndrcvinfo->sinfo_ppid = sinfo->snd_ppid;
- sndrcvinfo->sinfo_context = sinfo->snd_context;
- sndrcvinfo->sinfo_timetolive = pinfo->pr_value;
- msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
-#endif
-
- ret = sendmsg(b->num, &msg, 0);
-
- BIO_clear_retry_flags(b);
- if (ret <= 0)
- {
- if (BIO_dgram_should_retry(ret))
- {
- BIO_set_retry_write(b);
- data->_errno = get_last_socket_error();
- }
- }
- return(ret);
- }
-
-static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr)
- {
- long ret=1;
- bio_dgram_sctp_data *data = NULL;
- socklen_t sockopt_len = 0;
- struct sctp_authkeyid authkeyid;
- struct sctp_authkey *authkey;
-
- data = (bio_dgram_sctp_data *)b->ptr;
-
- switch (cmd)
- {
- case BIO_CTRL_DGRAM_QUERY_MTU:
- /* Set to maximum (2^14)
- * and ignore user input to enable transport
- * protocol fragmentation.
- * Returns always 2^14.
- */
- data->mtu = 16384;
- ret = data->mtu;
- break;
- case BIO_CTRL_DGRAM_SET_MTU:
- /* Set to maximum (2^14)
- * and ignore input to enable transport
- * protocol fragmentation.
- * Returns always 2^14.
- */
- data->mtu = 16384;
- ret = data->mtu;
- break;
- case BIO_CTRL_DGRAM_SET_CONNECTED:
- case BIO_CTRL_DGRAM_CONNECT:
- /* Returns always -1. */
- ret = -1;
- break;
- case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
- /* SCTP doesn't need the DTLS timer
- * Returns always 1.
- */
- break;
- case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE:
- if (num > 0)
- data->in_handshake = 1;
- else
- data->in_handshake = 0;
-
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, &data->in_handshake, sizeof(int));
- break;
- case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY:
- /* New shared key for SCTP AUTH.
- * Returns 0 on success, -1 otherwise.
- */
-
- /* Get active key */
- sockopt_len = sizeof(struct sctp_authkeyid);
- ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
- if (ret < 0) break;
-
- /* Add new key */
- sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t);
- authkey = OPENSSL_malloc(sockopt_len);
- memset(authkey, 0x00, sockopt_len);
- authkey->sca_keynumber = authkeyid.scact_keynumber + 1;
-#ifndef __FreeBSD__
- /* This field is missing in FreeBSD 8.2 and earlier,
- * and FreeBSD 8.3 and higher work without it.
- */
- authkey->sca_keylength = 64;
-#endif
- memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t));
-
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, sockopt_len);
- if (ret < 0) break;
-
- /* Reset active key */
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
- &authkeyid, sizeof(struct sctp_authkeyid));
- if (ret < 0) break;
-
- break;
- case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY:
- /* Returns 0 on success, -1 otherwise. */
-
- /* Get active key */
- sockopt_len = sizeof(struct sctp_authkeyid);
- ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
- if (ret < 0) break;
-
- /* Set active key */
- authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1;
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
- &authkeyid, sizeof(struct sctp_authkeyid));
- if (ret < 0) break;
-
- /* CCS has been sent, so remember that and fall through
- * to check if we need to deactivate an old key
- */
- data->ccs_sent = 1;
-
- case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD:
- /* Returns 0 on success, -1 otherwise. */
-
- /* Has this command really been called or is this just a fall-through? */
- if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD)
- data->ccs_rcvd = 1;
-
- /* CSS has been both, received and sent, so deactivate an old key */
- if (data->ccs_rcvd == 1 && data->ccs_sent == 1)
- {
- /* Get active key */
- sockopt_len = sizeof(struct sctp_authkeyid);
- ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
- if (ret < 0) break;
-
- /* Deactivate key or delete second last key if
- * SCTP_AUTHENTICATION_EVENT is not available.
- */
- authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
-#ifdef SCTP_AUTH_DEACTIVATE_KEY
- sockopt_len = sizeof(struct sctp_authkeyid);
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY,
- &authkeyid, sockopt_len);
- if (ret < 0) break;
-#endif
-#ifndef SCTP_AUTHENTICATION_EVENT
- if (authkeyid.scact_keynumber > 0)
- {
- authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
- &authkeyid, sizeof(struct sctp_authkeyid));
- if (ret < 0) break;
- }
-#endif
-
- data->ccs_rcvd = 0;
- data->ccs_sent = 0;
- }
- break;
- case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO:
- /* Returns the size of the copied struct. */
- if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo))
- num = sizeof(struct bio_dgram_sctp_sndinfo);
-
- memcpy(ptr, &(data->sndinfo), num);
- ret = num;
- break;
- case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO:
- /* Returns the size of the copied struct. */
- if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo))
- num = sizeof(struct bio_dgram_sctp_sndinfo);
-
- memcpy(&(data->sndinfo), ptr, num);
- break;
- case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO:
- /* Returns the size of the copied struct. */
- if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo))
- num = sizeof(struct bio_dgram_sctp_rcvinfo);
-
- memcpy(ptr, &data->rcvinfo, num);
-
- ret = num;
- break;
- case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO:
- /* Returns the size of the copied struct. */
- if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo))
- num = sizeof(struct bio_dgram_sctp_rcvinfo);
-
- memcpy(&(data->rcvinfo), ptr, num);
- break;
- case BIO_CTRL_DGRAM_SCTP_GET_PRINFO:
- /* Returns the size of the copied struct. */
- if (num > (long) sizeof(struct bio_dgram_sctp_prinfo))
- num = sizeof(struct bio_dgram_sctp_prinfo);
-
- memcpy(ptr, &(data->prinfo), num);
- ret = num;
- break;
- case BIO_CTRL_DGRAM_SCTP_SET_PRINFO:
- /* Returns the size of the copied struct. */
- if (num > (long) sizeof(struct bio_dgram_sctp_prinfo))
- num = sizeof(struct bio_dgram_sctp_prinfo);
-
- memcpy(&(data->prinfo), ptr, num);
- break;
- case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN:
- /* Returns always 1. */
- if (num > 0)
- data->save_shutdown = 1;
- else
- data->save_shutdown = 0;
- break;
-
- default:
- /* Pass to default ctrl function to
- * process SCTP unspecific commands
- */
- ret=dgram_ctrl(b, cmd, num, ptr);
- break;
- }
- return(ret);
- }
-
-int BIO_dgram_sctp_notification_cb(BIO *b,
- void (*handle_notifications)(BIO *bio, void *context, void *buf),
- void *context)
- {
- bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
-
- if (handle_notifications != NULL)
- {
- data->handle_notifications = handle_notifications;
- data->notification_context = context;
- }
- else
- return -1;
-
- return 0;
- }
-
-int BIO_dgram_sctp_wait_for_dry(BIO *b)
-{
- int is_dry = 0;
- int n, sockflags, ret;
- union sctp_notification snp;
- struct msghdr msg;
- struct iovec iov;
-#ifdef SCTP_EVENT
- struct sctp_event event;
-#else
- struct sctp_event_subscribe event;
- socklen_t eventsize;
-#endif
- bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
-
- /* set sender dry event */
-#ifdef SCTP_EVENT
- memset(&event, 0, sizeof(struct sctp_event));
- event.se_assoc_id = 0;
- event.se_type = SCTP_SENDER_DRY_EVENT;
- event.se_on = 1;
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
-#else
- eventsize = sizeof(struct sctp_event_subscribe);
- ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
- if (ret < 0)
- return -1;
-
- event.sctp_sender_dry_event = 1;
-
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
-#endif
- if (ret < 0)
- return -1;
-
- /* peek for notification */
- memset(&snp, 0x00, sizeof(union sctp_notification));
- iov.iov_base = (char *)&snp;
- iov.iov_len = sizeof(union sctp_notification);
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
-
- n = recvmsg(b->num, &msg, MSG_PEEK);
- if (n <= 0)
- {
- if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
- return -1;
- else
- return 0;
- }
-
- /* if we find a notification, process it and try again if necessary */
- while (msg.msg_flags & MSG_NOTIFICATION)
- {
- memset(&snp, 0x00, sizeof(union sctp_notification));
- iov.iov_base = (char *)&snp;
- iov.iov_len = sizeof(union sctp_notification);
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
-
- n = recvmsg(b->num, &msg, 0);
- if (n <= 0)
- {
- if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
- return -1;
- else
- return is_dry;
- }
-
- if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT)
- {
- is_dry = 1;
-
- /* disable sender dry event */
-#ifdef SCTP_EVENT
- memset(&event, 0, sizeof(struct sctp_event));
- event.se_assoc_id = 0;
- event.se_type = SCTP_SENDER_DRY_EVENT;
- event.se_on = 0;
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
-#else
- eventsize = (socklen_t) sizeof(struct sctp_event_subscribe);
- ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
- if (ret < 0)
- return -1;
-
- event.sctp_sender_dry_event = 0;
-
- ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
-#endif
- if (ret < 0)
- return -1;
- }
-
-#ifdef SCTP_AUTHENTICATION_EVENT
- if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
- dgram_sctp_handle_auth_free_key_event(b, &snp);
-#endif
-
- if (data->handle_notifications != NULL)
- data->handle_notifications(b, data->notification_context, (void*) &snp);
-
- /* found notification, peek again */
- memset(&snp, 0x00, sizeof(union sctp_notification));
- iov.iov_base = (char *)&snp;
- iov.iov_len = sizeof(union sctp_notification);
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
-
- /* if we have seen the dry already, don't wait */
- if (is_dry)
- {
- sockflags = fcntl(b->num, F_GETFL, 0);
- fcntl(b->num, F_SETFL, O_NONBLOCK);
- }
-
- n = recvmsg(b->num, &msg, MSG_PEEK);
-
- if (is_dry)
- {
- fcntl(b->num, F_SETFL, sockflags);
- }
-
- if (n <= 0)
- {
- if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
- return -1;
- else
- return is_dry;
- }
- }
-
- /* read anything else */
- return is_dry;
-}
-
-int BIO_dgram_sctp_msg_waiting(BIO *b)
- {
- int n, sockflags;
- union sctp_notification snp;
- struct msghdr msg;
- struct iovec iov;
- bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
-
- /* Check if there are any messages waiting to be read */
- do
- {
- memset(&snp, 0x00, sizeof(union sctp_notification));
- iov.iov_base = (char *)&snp;
- iov.iov_len = sizeof(union sctp_notification);
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
-
- sockflags = fcntl(b->num, F_GETFL, 0);
- fcntl(b->num, F_SETFL, O_NONBLOCK);
- n = recvmsg(b->num, &msg, MSG_PEEK);
- fcntl(b->num, F_SETFL, sockflags);
-
- /* if notification, process and try again */
- if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION))
- {
-#ifdef SCTP_AUTHENTICATION_EVENT
- if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
- dgram_sctp_handle_auth_free_key_event(b, &snp);
-#endif
-
- memset(&snp, 0x00, sizeof(union sctp_notification));
- iov.iov_base = (char *)&snp;
- iov.iov_len = sizeof(union sctp_notification);
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
- n = recvmsg(b->num, &msg, 0);
-
- if (data->handle_notifications != NULL)
- data->handle_notifications(b, data->notification_context, (void*) &snp);
- }
-
- } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION));
-
- /* Return 1 if there is a message to be read, return 0 otherwise. */
- if (n > 0)
- return 1;
- else
- return 0;
- }
-
-static int dgram_sctp_puts(BIO *bp, const char *str)
- {
- int n,ret;
-
- n=strlen(str);
- ret=dgram_sctp_write(bp,str,n);
- return(ret);
- }
-#endif
-
-static int BIO_dgram_should_retry(int i)
- {
- int err;
-
- if ((i == 0) || (i == -1))
- {
- err=get_last_socket_error();
-
-#if defined(OPENSSL_SYS_WINDOWS)
- /* If the socket return value (i) is -1
- * and err is unexpectedly 0 at this point,
- * the error code was overwritten by
- * another system call before this error
- * handling is called.
- */
-#endif
-
- return(BIO_dgram_non_fatal_error(err));
- }
- return(0);
- }
-
-int BIO_dgram_non_fatal_error(int err)
- {
- switch (err)
- {
-#if defined(OPENSSL_SYS_WINDOWS)
-# if defined(WSAEWOULDBLOCK)
- case WSAEWOULDBLOCK:
-# endif
-
-# if 0 /* This appears to always be an error */
-# if defined(WSAENOTCONN)
- case WSAENOTCONN:
-# endif
-# endif
-#endif
-
-#ifdef EWOULDBLOCK
-# ifdef WSAEWOULDBLOCK
-# if WSAEWOULDBLOCK != EWOULDBLOCK
- case EWOULDBLOCK:
-# endif
-# else
- case EWOULDBLOCK:
-# endif
-#endif
-
-#ifdef EINTR
- case EINTR:
-#endif
-
-#ifdef EAGAIN
-#if EWOULDBLOCK != EAGAIN
- case EAGAIN:
-# endif
-#endif
-
-#ifdef EPROTO
- case EPROTO:
-#endif
-
-#ifdef EINPROGRESS
- case EINPROGRESS:
-#endif
-
-#ifdef EALREADY
- case EALREADY:
-#endif
-
- return(1);
- /* break; */
- default:
- break;
- }
- return(0);
- }
-
-static void get_current_time(struct timeval *t)
- {
-#ifdef OPENSSL_SYS_WIN32
- struct _timeb tb;
- _ftime(&tb);
- t->tv_sec = (long)tb.time;
- t->tv_usec = (long)tb.millitm * 1000;
-#elif defined(OPENSSL_SYS_VMS)
- struct timeb tb;
- ftime(&tb);
- t->tv_sec = (long)tb.time;
- t->tv_usec = (long)tb.millitm * 1000;
-#else
- gettimeofday(t, NULL);
-#endif
- }
-
-#endif
diff --git a/drivers/builtin_openssl/crypto/bn/bn_mont.c b/drivers/builtin_openssl/crypto/bn/bn_mont.c
deleted file mode 100644
index 427b5cf4df..0000000000
--- a/drivers/builtin_openssl/crypto/bn/bn_mont.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/* crypto/bn/bn_mont.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-/*
- * Details about Montgomery multiplication algorithms can be found at
- * http://security.ece.orst.edu/publications.html, e.g.
- * http://security.ece.orst.edu/koc/papers/j37acmon.pdf and
- * sections 3.8 and 4.2 in http://security.ece.orst.edu/koc/papers/r01rsasw.pdf
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include "bn_lcl.h"
-
-#define MONT_WORD /* use the faster word-based algorithm */
-
-#ifdef MONT_WORD
-static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont);
-#endif
-
-int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- BN_MONT_CTX *mont, BN_CTX *ctx)
- {
- BIGNUM *tmp;
- int ret=0;
-#if defined(OPENSSL_BN_ASM_MONT) && defined(MONT_WORD)
- int num = mont->N.top;
-
- if (num>1 && a->top==num && b->top==num)
- {
- if (bn_wexpand(r,num) == NULL) return(0);
- if (bn_mul_mont(r->d,a->d,b->d,mont->N.d,mont->n0,num))
- {
- r->neg = a->neg^b->neg;
- r->top = num;
- bn_correct_top(r);
- return(1);
- }
- }
-#endif
-
- BN_CTX_start(ctx);
- tmp = BN_CTX_get(ctx);
- if (tmp == NULL) goto err;
-
- bn_check_top(tmp);
- if (a == b)
- {
- if (!BN_sqr(tmp,a,ctx)) goto err;
- }
- else
- {
- if (!BN_mul(tmp,a,b,ctx)) goto err;
- }
- /* reduce from aRR to aR */
-#ifdef MONT_WORD
- if (!BN_from_montgomery_word(r,tmp,mont)) goto err;
-#else
- if (!BN_from_montgomery(r,tmp,mont,ctx)) goto err;
-#endif
- bn_check_top(r);
- ret=1;
-err:
- BN_CTX_end(ctx);
- return(ret);
- }
-
-#ifdef MONT_WORD
-static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
- {
- BIGNUM *n;
- BN_ULONG *ap,*np,*rp,n0,v,carry;
- int nl,max,i;
-
- n= &(mont->N);
- nl=n->top;
- if (nl == 0) { ret->top=0; return(1); }
-
- max=(2*nl); /* carry is stored separately */
- if (bn_wexpand(r,max) == NULL) return(0);
-
- r->neg^=n->neg;
- np=n->d;
- rp=r->d;
-
- /* clear the top words of T */
-#if 1
- for (i=r->top; i<max; i++) /* memset? XXX */
- rp[i]=0;
-#else
- memset(&(rp[r->top]),0,(max-r->top)*sizeof(BN_ULONG));
-#endif
-
- r->top=max;
- n0=mont->n0[0];
-
-#ifdef BN_COUNT
- fprintf(stderr,"word BN_from_montgomery_word %d * %d\n",nl,nl);
-#endif
- for (carry=0, i=0; i<nl; i++, rp++)
- {
-#ifdef __TANDEM
- {
- long long t1;
- long long t2;
- long long t3;
- t1 = rp[0] * (n0 & 0177777);
- t2 = 037777600000l;
- t2 = n0 & t2;
- t3 = rp[0] & 0177777;
- t2 = (t3 * t2) & BN_MASK2;
- t1 = t1 + t2;
- v=bn_mul_add_words(rp,np,nl,(BN_ULONG) t1);
- }
-#else
- v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2);
-#endif
- v = (v+carry+rp[nl])&BN_MASK2;
- carry |= (v != rp[nl]);
- carry &= (v <= rp[nl]);
- rp[nl]=v;
- }
-
- if (bn_wexpand(ret,nl) == NULL) return(0);
- ret->top=nl;
- ret->neg=r->neg;
-
- rp=ret->d;
- ap=&(r->d[nl]);
-
-#define BRANCH_FREE 1
-#if BRANCH_FREE
- {
- BN_ULONG *nrp;
- size_t m;
-
- v=bn_sub_words(rp,ap,np,nl)-carry;
- /* if subtraction result is real, then
- * trick unconditional memcpy below to perform in-place
- * "refresh" instead of actual copy. */
- m=(0-(size_t)v);
- nrp=(BN_ULONG *)(((PTR_SIZE_INT)rp&~m)|((PTR_SIZE_INT)ap&m));
-
- for (i=0,nl-=4; i<nl; i+=4)
- {
- BN_ULONG t1,t2,t3,t4;
-
- t1=nrp[i+0];
- t2=nrp[i+1];
- t3=nrp[i+2]; ap[i+0]=0;
- t4=nrp[i+3]; ap[i+1]=0;
- rp[i+0]=t1; ap[i+2]=0;
- rp[i+1]=t2; ap[i+3]=0;
- rp[i+2]=t3;
- rp[i+3]=t4;
- }
- for (nl+=4; i<nl; i++)
- rp[i]=nrp[i], ap[i]=0;
- }
-#else
- if (bn_sub_words (rp,ap,np,nl)-carry)
- memcpy(rp,ap,nl*sizeof(BN_ULONG));
-#endif
- bn_correct_top(r);
- bn_correct_top(ret);
- bn_check_top(ret);
-
- return(1);
- }
-#endif /* MONT_WORD */
-
-int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont,
- BN_CTX *ctx)
- {
- int retn=0;
-#ifdef MONT_WORD
- BIGNUM *t;
-
- BN_CTX_start(ctx);
- if ((t = BN_CTX_get(ctx)) && BN_copy(t,a))
- retn = BN_from_montgomery_word(ret,t,mont);
- BN_CTX_end(ctx);
-#else /* !MONT_WORD */
- BIGNUM *t1,*t2;
-
- BN_CTX_start(ctx);
- t1 = BN_CTX_get(ctx);
- t2 = BN_CTX_get(ctx);
- if (t1 == NULL || t2 == NULL) goto err;
-
- if (!BN_copy(t1,a)) goto err;
- BN_mask_bits(t1,mont->ri);
-
- if (!BN_mul(t2,t1,&mont->Ni,ctx)) goto err;
- BN_mask_bits(t2,mont->ri);
-
- if (!BN_mul(t1,t2,&mont->N,ctx)) goto err;
- if (!BN_add(t2,a,t1)) goto err;
- if (!BN_rshift(ret,t2,mont->ri)) goto err;
-
- if (BN_ucmp(ret, &(mont->N)) >= 0)
- {
- if (!BN_usub(ret,ret,&(mont->N))) goto err;
- }
- retn=1;
- bn_check_top(ret);
- err:
- BN_CTX_end(ctx);
-#endif /* MONT_WORD */
- return(retn);
- }
-
-BN_MONT_CTX *BN_MONT_CTX_new(void)
- {
- BN_MONT_CTX *ret;
-
- if ((ret=(BN_MONT_CTX *)OPENSSL_malloc(sizeof(BN_MONT_CTX))) == NULL)
- return(NULL);
-
- BN_MONT_CTX_init(ret);
- ret->flags=BN_FLG_MALLOCED;
- return(ret);
- }
-
-void BN_MONT_CTX_init(BN_MONT_CTX *ctx)
- {
- ctx->ri=0;
- BN_init(&(ctx->RR));
- BN_init(&(ctx->N));
- BN_init(&(ctx->Ni));
- ctx->n0[0] = ctx->n0[1] = 0;
- ctx->flags=0;
- }
-
-void BN_MONT_CTX_free(BN_MONT_CTX *mont)
- {
- if(mont == NULL)
- return;
-
- BN_free(&(mont->RR));
- BN_free(&(mont->N));
- BN_free(&(mont->Ni));
- if (mont->flags & BN_FLG_MALLOCED)
- OPENSSL_free(mont);
- }
-
-int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx)
- {
- int ret = 0;
- BIGNUM *Ri,*R;
-
- BN_CTX_start(ctx);
- if((Ri = BN_CTX_get(ctx)) == NULL) goto err;
- R= &(mont->RR); /* grab RR as a temp */
- if (!BN_copy(&(mont->N),mod)) goto err; /* Set N */
- mont->N.neg = 0;
-
-#ifdef MONT_WORD
- {
- BIGNUM tmod;
- BN_ULONG buf[2];
-
- BN_init(&tmod);
- tmod.d=buf;
- tmod.dmax=2;
- tmod.neg=0;
-
- mont->ri=(BN_num_bits(mod)+(BN_BITS2-1))/BN_BITS2*BN_BITS2;
-
-#if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2<=32)
- /* Only certain BN_BITS2<=32 platforms actually make use of
- * n0[1], and we could use the #else case (with a shorter R
- * value) for the others. However, currently only the assembler
- * files do know which is which. */
-
- BN_zero(R);
- if (!(BN_set_bit(R,2*BN_BITS2))) goto err;
-
- tmod.top=0;
- if ((buf[0] = mod->d[0])) tmod.top=1;
- if ((buf[1] = mod->top>1 ? mod->d[1] : 0)) tmod.top=2;
-
- if ((BN_mod_inverse(Ri,R,&tmod,ctx)) == NULL)
- goto err;
- if (!BN_lshift(Ri,Ri,2*BN_BITS2)) goto err; /* R*Ri */
- if (!BN_is_zero(Ri))
- {
- if (!BN_sub_word(Ri,1)) goto err;
- }
- else /* if N mod word size == 1 */
- {
- if (bn_expand(Ri,(int)sizeof(BN_ULONG)*2) == NULL)
- goto err;
- /* Ri-- (mod double word size) */
- Ri->neg=0;
- Ri->d[0]=BN_MASK2;
- Ri->d[1]=BN_MASK2;
- Ri->top=2;
- }
- if (!BN_div(Ri,NULL,Ri,&tmod,ctx)) goto err;
- /* Ni = (R*Ri-1)/N,
- * keep only couple of least significant words: */
- mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
- mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0;
-#else
- BN_zero(R);
- if (!(BN_set_bit(R,BN_BITS2))) goto err; /* R */
-
- buf[0]=mod->d[0]; /* tmod = N mod word size */
- buf[1]=0;
- tmod.top = buf[0] != 0 ? 1 : 0;
- /* Ri = R^-1 mod N*/
- if ((BN_mod_inverse(Ri,R,&tmod,ctx)) == NULL)
- goto err;
- if (!BN_lshift(Ri,Ri,BN_BITS2)) goto err; /* R*Ri */
- if (!BN_is_zero(Ri))
- {
- if (!BN_sub_word(Ri,1)) goto err;
- }
- else /* if N mod word size == 1 */
- {
- if (!BN_set_word(Ri,BN_MASK2)) goto err; /* Ri-- (mod word size) */
- }
- if (!BN_div(Ri,NULL,Ri,&tmod,ctx)) goto err;
- /* Ni = (R*Ri-1)/N,
- * keep only least significant word: */
- mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
- mont->n0[1] = 0;
-#endif
- }
-#else /* !MONT_WORD */
- { /* bignum version */
- mont->ri=BN_num_bits(&mont->N);
- BN_zero(R);
- if (!BN_set_bit(R,mont->ri)) goto err; /* R = 2^ri */
- /* Ri = R^-1 mod N*/
- if ((BN_mod_inverse(Ri,R,&mont->N,ctx)) == NULL)
- goto err;
- if (!BN_lshift(Ri,Ri,mont->ri)) goto err; /* R*Ri */
- if (!BN_sub_word(Ri,1)) goto err;
- /* Ni = (R*Ri-1) / N */
- if (!BN_div(&(mont->Ni),NULL,Ri,&mont->N,ctx)) goto err;
- }
-#endif
-
- /* setup RR for conversions */
- BN_zero(&(mont->RR));
- if (!BN_set_bit(&(mont->RR),mont->ri*2)) goto err;
- if (!BN_mod(&(mont->RR),&(mont->RR),&(mont->N),ctx)) goto err;
-
- ret = 1;
-err:
- BN_CTX_end(ctx);
- return ret;
- }
-
-BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from)
- {
- if (to == from) return(to);
-
- if (!BN_copy(&(to->RR),&(from->RR))) return NULL;
- if (!BN_copy(&(to->N),&(from->N))) return NULL;
- if (!BN_copy(&(to->Ni),&(from->Ni))) return NULL;
- to->ri=from->ri;
- to->n0[0]=from->n0[0];
- to->n0[1]=from->n0[1];
- return(to);
- }
-
-BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
- const BIGNUM *mod, BN_CTX *ctx)
- {
- int got_write_lock = 0;
- BN_MONT_CTX *ret;
-
- CRYPTO_r_lock(lock);
- if (!*pmont)
- {
- CRYPTO_r_unlock(lock);
- CRYPTO_w_lock(lock);
- got_write_lock = 1;
-
- if (!*pmont)
- {
- ret = BN_MONT_CTX_new();
- if (ret && !BN_MONT_CTX_set(ret, mod, ctx))
- BN_MONT_CTX_free(ret);
- else
- *pmont = ret;
- }
- }
-
- ret = *pmont;
-
- if (got_write_lock)
- CRYPTO_w_unlock(lock);
- else
- CRYPTO_r_unlock(lock);
-
- return ret;
- }
diff --git a/drivers/builtin_openssl/crypto/cms/cms_env.c b/drivers/builtin_openssl/crypto/cms/cms_env.c
deleted file mode 100644
index be20b1c024..0000000000
--- a/drivers/builtin_openssl/crypto/cms/cms_env.c
+++ /dev/null
@@ -1,876 +0,0 @@
-/* crypto/cms/cms_env.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project.
- */
-/* ====================================================================
- * Copyright (c) 2008 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 "cryptlib.h"
-#include <openssl/asn1t.h>
-#include <openssl/pem.h>
-#include <openssl/x509v3.h>
-#include <openssl/err.h>
-#include <openssl/cms.h>
-#include <openssl/rand.h>
-#include <openssl/aes.h>
-#include "cms_lcl.h"
-#include "asn1_locl.h"
-
-/* CMS EnvelopedData Utilities */
-
-DECLARE_ASN1_ITEM(CMS_EnvelopedData)
-DECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo)
-DECLARE_ASN1_ITEM(CMS_KEKRecipientInfo)
-DECLARE_ASN1_ITEM(CMS_OtherKeyAttribute)
-
-DECLARE_STACK_OF(CMS_RecipientInfo)
-
-CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
- {
- if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped)
- {
- CMSerr(CMS_F_CMS_GET0_ENVELOPED,
- CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
- return NULL;
- }
- return cms->d.envelopedData;
- }
-
-static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
- {
- if (cms->d.other == NULL)
- {
- cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData);
- if (!cms->d.envelopedData)
- {
- CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT,
- ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- cms->d.envelopedData->version = 0;
- cms->d.envelopedData->encryptedContentInfo->contentType =
- OBJ_nid2obj(NID_pkcs7_data);
- ASN1_OBJECT_free(cms->contentType);
- cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped);
- return cms->d.envelopedData;
- }
- return cms_get0_enveloped(cms);
- }
-
-STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms)
- {
- CMS_EnvelopedData *env;
- env = cms_get0_enveloped(cms);
- if (!env)
- return NULL;
- return env->recipientInfos;
- }
-
-int CMS_RecipientInfo_type(CMS_RecipientInfo *ri)
- {
- return ri->type;
- }
-
-CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
- {
- CMS_ContentInfo *cms;
- CMS_EnvelopedData *env;
- cms = CMS_ContentInfo_new();
- if (!cms)
- goto merr;
- env = cms_enveloped_data_init(cms);
- if (!env)
- goto merr;
- if (!cms_EncryptedContent_init(env->encryptedContentInfo,
- cipher, NULL, 0))
- goto merr;
- return cms;
- merr:
- if (cms)
- CMS_ContentInfo_free(cms);
- CMSerr(CMS_F_CMS_ENVELOPEDDATA_CREATE, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
-
-/* Key Transport Recipient Info (KTRI) routines */
-
-/* Add a recipient certificate. For now only handle key transport.
- * If we ever handle key agreement will need updating.
- */
-
-CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
- X509 *recip, unsigned int flags)
- {
- CMS_RecipientInfo *ri = NULL;
- CMS_KeyTransRecipientInfo *ktri;
- CMS_EnvelopedData *env;
- EVP_PKEY *pk = NULL;
- int i, type;
- env = cms_get0_enveloped(cms);
- if (!env)
- goto err;
-
- /* Initialize recipient info */
- ri = M_ASN1_new_of(CMS_RecipientInfo);
- if (!ri)
- goto merr;
-
- /* Initialize and add key transport recipient info */
-
- ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo);
- if (!ri->d.ktri)
- goto merr;
- ri->type = CMS_RECIPINFO_TRANS;
-
- ktri = ri->d.ktri;
-
- X509_check_purpose(recip, -1, -1);
- pk = X509_get_pubkey(recip);
- if (!pk)
- {
- CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
- CMS_R_ERROR_GETTING_PUBLIC_KEY);
- goto err;
- }
- CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509);
- ktri->pkey = pk;
- ktri->recip = recip;
-
- if (flags & CMS_USE_KEYID)
- {
- ktri->version = 2;
- type = CMS_RECIPINFO_KEYIDENTIFIER;
- }
- else
- {
- ktri->version = 0;
- type = CMS_RECIPINFO_ISSUER_SERIAL;
- }
-
- /* Not a typo: RecipientIdentifier and SignerIdentifier are the
- * same structure.
- */
-
- if (!cms_set1_SignerIdentifier(ktri->rid, recip, type))
- goto err;
-
- if (pk->ameth && pk->ameth->pkey_ctrl)
- {
- i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_ENVELOPE,
- 0, ri);
- if (i == -2)
- {
- CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
- CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
- goto err;
- }
- if (i <= 0)
- {
- CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
- CMS_R_CTRL_FAILURE);
- goto err;
- }
- }
-
- if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
- goto merr;
-
- return ri;
-
- merr:
- CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE);
- err:
- if (ri)
- M_ASN1_free_of(ri, CMS_RecipientInfo);
- return NULL;
-
- }
-
-int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
- EVP_PKEY **pk, X509 **recip,
- X509_ALGOR **palg)
- {
- CMS_KeyTransRecipientInfo *ktri;
- if (ri->type != CMS_RECIPINFO_TRANS)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS,
- CMS_R_NOT_KEY_TRANSPORT);
- return 0;
- }
-
- ktri = ri->d.ktri;
-
- if (pk)
- *pk = ktri->pkey;
- if (recip)
- *recip = ktri->recip;
- if (palg)
- *palg = ktri->keyEncryptionAlgorithm;
- return 1;
- }
-
-int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
- ASN1_OCTET_STRING **keyid,
- X509_NAME **issuer, ASN1_INTEGER **sno)
- {
- CMS_KeyTransRecipientInfo *ktri;
- if (ri->type != CMS_RECIPINFO_TRANS)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID,
- CMS_R_NOT_KEY_TRANSPORT);
- return 0;
- }
- ktri = ri->d.ktri;
-
- return cms_SignerIdentifier_get0_signer_id(ktri->rid,
- keyid, issuer, sno);
- }
-
-int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert)
- {
- if (ri->type != CMS_RECIPINFO_TRANS)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP,
- CMS_R_NOT_KEY_TRANSPORT);
- return -2;
- }
- return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert);
- }
-
-int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey)
- {
- if (ri->type != CMS_RECIPINFO_TRANS)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY,
- CMS_R_NOT_KEY_TRANSPORT);
- return 0;
- }
- ri->d.ktri->pkey = pkey;
- return 1;
- }
-
-/* Encrypt content key in key transport recipient info */
-
-static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
- CMS_RecipientInfo *ri)
- {
- CMS_KeyTransRecipientInfo *ktri;
- CMS_EncryptedContentInfo *ec;
- EVP_PKEY_CTX *pctx = NULL;
- unsigned char *ek = NULL;
- size_t eklen;
-
- int ret = 0;
-
- if (ri->type != CMS_RECIPINFO_TRANS)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT,
- CMS_R_NOT_KEY_TRANSPORT);
- return 0;
- }
- ktri = ri->d.ktri;
- ec = cms->d.envelopedData->encryptedContentInfo;
-
- pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
- if (!pctx)
- return 0;
-
- if (EVP_PKEY_encrypt_init(pctx) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
- EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_CTRL_ERROR);
- goto err;
- }
-
- if (EVP_PKEY_encrypt(pctx, NULL, &eklen, ec->key, ec->keylen) <= 0)
- goto err;
-
- ek = OPENSSL_malloc(eklen);
-
- if (ek == NULL)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (EVP_PKEY_encrypt(pctx, ek, &eklen, ec->key, ec->keylen) <= 0)
- goto err;
-
- ASN1_STRING_set0(ktri->encryptedKey, ek, eklen);
- ek = NULL;
-
- ret = 1;
-
- err:
- if (pctx)
- EVP_PKEY_CTX_free(pctx);
- if (ek)
- OPENSSL_free(ek);
- return ret;
-
- }
-
-/* Decrypt content key from KTRI */
-
-static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
- CMS_RecipientInfo *ri)
- {
- CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
- EVP_PKEY_CTX *pctx = NULL;
- unsigned char *ek = NULL;
- size_t eklen;
- int ret = 0;
- CMS_EncryptedContentInfo *ec;
- ec = cms->d.envelopedData->encryptedContentInfo;
-
- if (ktri->pkey == NULL)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT,
- CMS_R_NO_PRIVATE_KEY);
- return 0;
- }
-
- pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
- if (!pctx)
- return 0;
-
- if (EVP_PKEY_decrypt_init(pctx) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
- EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR);
- goto err;
- }
-
- if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
- ktri->encryptedKey->data,
- ktri->encryptedKey->length) <= 0)
- goto err;
-
- ek = OPENSSL_malloc(eklen);
-
- if (ek == NULL)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (EVP_PKEY_decrypt(pctx, ek, &eklen,
- ktri->encryptedKey->data,
- ktri->encryptedKey->length) <= 0)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB);
- goto err;
- }
-
- ret = 1;
-
- if (ec->key)
- {
- OPENSSL_cleanse(ec->key, ec->keylen);
- OPENSSL_free(ec->key);
- }
-
- ec->key = ek;
- ec->keylen = eklen;
-
- err:
- if (pctx)
- EVP_PKEY_CTX_free(pctx);
- if (!ret && ek)
- OPENSSL_free(ek);
-
- return ret;
- }
-
-/* Key Encrypted Key (KEK) RecipientInfo routines */
-
-int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri,
- const unsigned char *id, size_t idlen)
- {
- ASN1_OCTET_STRING tmp_os;
- CMS_KEKRecipientInfo *kekri;
- if (ri->type != CMS_RECIPINFO_KEK)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP, CMS_R_NOT_KEK);
- return -2;
- }
- kekri = ri->d.kekri;
- tmp_os.type = V_ASN1_OCTET_STRING;
- tmp_os.flags = 0;
- tmp_os.data = (unsigned char *)id;
- tmp_os.length = (int)idlen;
- return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier);
- }
-
-/* For now hard code AES key wrap info */
-
-static size_t aes_wrap_keylen(int nid)
- {
- switch (nid)
- {
- case NID_id_aes128_wrap:
- return 16;
-
- case NID_id_aes192_wrap:
- return 24;
-
- case NID_id_aes256_wrap:
- return 32;
-
- default:
- return 0;
- }
- }
-
-CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
- unsigned char *key, size_t keylen,
- unsigned char *id, size_t idlen,
- ASN1_GENERALIZEDTIME *date,
- ASN1_OBJECT *otherTypeId,
- ASN1_TYPE *otherType)
- {
- CMS_RecipientInfo *ri = NULL;
- CMS_EnvelopedData *env;
- CMS_KEKRecipientInfo *kekri;
- env = cms_get0_enveloped(cms);
- if (!env)
- goto err;
-
- if (nid == NID_undef)
- {
- switch (keylen)
- {
- case 16:
- nid = NID_id_aes128_wrap;
- break;
-
- case 24:
- nid = NID_id_aes192_wrap;
- break;
-
- case 32:
- nid = NID_id_aes256_wrap;
- break;
-
- default:
- CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
- CMS_R_INVALID_KEY_LENGTH);
- goto err;
- }
-
- }
- else
- {
-
- size_t exp_keylen = aes_wrap_keylen(nid);
-
- if (!exp_keylen)
- {
- CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
- CMS_R_UNSUPPORTED_KEK_ALGORITHM);
- goto err;
- }
-
- if (keylen != exp_keylen)
- {
- CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
- CMS_R_INVALID_KEY_LENGTH);
- goto err;
- }
-
- }
-
- /* Initialize recipient info */
- ri = M_ASN1_new_of(CMS_RecipientInfo);
- if (!ri)
- goto merr;
-
- ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo);
- if (!ri->d.kekri)
- goto merr;
- ri->type = CMS_RECIPINFO_KEK;
-
- kekri = ri->d.kekri;
-
- if (otherTypeId)
- {
- kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute);
- if (kekri->kekid->other == NULL)
- goto merr;
- }
-
- if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
- goto merr;
-
-
- /* After this point no calls can fail */
-
- kekri->version = 4;
-
- kekri->key = key;
- kekri->keylen = keylen;
-
- ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen);
-
- kekri->kekid->date = date;
-
- if (kekri->kekid->other)
- {
- kekri->kekid->other->keyAttrId = otherTypeId;
- kekri->kekid->other->keyAttr = otherType;
- }
-
- X509_ALGOR_set0(kekri->keyEncryptionAlgorithm,
- OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL);
-
- return ri;
-
- merr:
- CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE);
- err:
- if (ri)
- M_ASN1_free_of(ri, CMS_RecipientInfo);
- return NULL;
-
- }
-
-int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
- X509_ALGOR **palg,
- ASN1_OCTET_STRING **pid,
- ASN1_GENERALIZEDTIME **pdate,
- ASN1_OBJECT **potherid,
- ASN1_TYPE **pothertype)
- {
- CMS_KEKIdentifier *rkid;
- if (ri->type != CMS_RECIPINFO_KEK)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK);
- return 0;
- }
- rkid = ri->d.kekri->kekid;
- if (palg)
- *palg = ri->d.kekri->keyEncryptionAlgorithm;
- if (pid)
- *pid = rkid->keyIdentifier;
- if (pdate)
- *pdate = rkid->date;
- if (potherid)
- {
- if (rkid->other)
- *potherid = rkid->other->keyAttrId;
- else
- *potherid = NULL;
- }
- if (pothertype)
- {
- if (rkid->other)
- *pothertype = rkid->other->keyAttr;
- else
- *pothertype = NULL;
- }
- return 1;
- }
-
-int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
- unsigned char *key, size_t keylen)
- {
- CMS_KEKRecipientInfo *kekri;
- if (ri->type != CMS_RECIPINFO_KEK)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK);
- return 0;
- }
-
- kekri = ri->d.kekri;
- kekri->key = key;
- kekri->keylen = keylen;
- return 1;
- }
-
-
-/* Encrypt content key in KEK recipient info */
-
-static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms,
- CMS_RecipientInfo *ri)
- {
- CMS_EncryptedContentInfo *ec;
- CMS_KEKRecipientInfo *kekri;
- AES_KEY actx;
- unsigned char *wkey = NULL;
- int wkeylen;
- int r = 0;
-
- ec = cms->d.envelopedData->encryptedContentInfo;
-
- kekri = ri->d.kekri;
-
- if (!kekri->key)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY);
- return 0;
- }
-
- if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx))
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
- CMS_R_ERROR_SETTING_KEY);
- goto err;
- }
-
- wkey = OPENSSL_malloc(ec->keylen + 8);
-
- if (!wkey)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen);
-
- if (wkeylen <= 0)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR);
- goto err;
- }
-
- ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen);
-
- r = 1;
-
- err:
-
- if (!r && wkey)
- OPENSSL_free(wkey);
- OPENSSL_cleanse(&actx, sizeof(actx));
-
- return r;
-
- }
-
-/* Decrypt content key in KEK recipient info */
-
-static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
- CMS_RecipientInfo *ri)
- {
- CMS_EncryptedContentInfo *ec;
- CMS_KEKRecipientInfo *kekri;
- AES_KEY actx;
- unsigned char *ukey = NULL;
- int ukeylen;
- int r = 0, wrap_nid;
-
- ec = cms->d.envelopedData->encryptedContentInfo;
-
- kekri = ri->d.kekri;
-
- if (!kekri->key)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY);
- return 0;
- }
-
- wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm);
- if (aes_wrap_keylen(wrap_nid) != kekri->keylen)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
- CMS_R_INVALID_KEY_LENGTH);
- return 0;
- }
-
- /* If encrypted key length is invalid don't bother */
-
- if (kekri->encryptedKey->length < 16)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
- CMS_R_INVALID_ENCRYPTED_KEY_LENGTH);
- goto err;
- }
-
- if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx))
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
- CMS_R_ERROR_SETTING_KEY);
- goto err;
- }
-
- ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8);
-
- if (!ukey)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- ukeylen = AES_unwrap_key(&actx, NULL, ukey,
- kekri->encryptedKey->data,
- kekri->encryptedKey->length);
-
- if (ukeylen <= 0)
- {
- CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
- CMS_R_UNWRAP_ERROR);
- goto err;
- }
-
- ec->key = ukey;
- ec->keylen = ukeylen;
-
- r = 1;
-
- err:
-
- if (!r && ukey)
- OPENSSL_free(ukey);
- OPENSSL_cleanse(&actx, sizeof(actx));
-
- return r;
-
- }
-
-int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
- {
- switch(ri->type)
- {
- case CMS_RECIPINFO_TRANS:
- return cms_RecipientInfo_ktri_decrypt(cms, ri);
-
- case CMS_RECIPINFO_KEK:
- return cms_RecipientInfo_kekri_decrypt(cms, ri);
-
- case CMS_RECIPINFO_PASS:
- return cms_RecipientInfo_pwri_crypt(cms, ri, 0);
-
- default:
- CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT,
- CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE);
- return 0;
- }
- }
-
-BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
- {
- CMS_EncryptedContentInfo *ec;
- STACK_OF(CMS_RecipientInfo) *rinfos;
- CMS_RecipientInfo *ri;
- int i, r, ok = 0;
- BIO *ret;
-
- /* Get BIO first to set up key */
-
- ec = cms->d.envelopedData->encryptedContentInfo;
- ret = cms_EncryptedContent_init_bio(ec);
-
- /* If error or no cipher end of processing */
-
- if (!ret || !ec->cipher)
- return ret;
-
- /* Now encrypt content key according to each RecipientInfo type */
-
- rinfos = cms->d.envelopedData->recipientInfos;
-
- for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++)
- {
- ri = sk_CMS_RecipientInfo_value(rinfos, i);
-
- switch (ri->type)
- {
- case CMS_RECIPINFO_TRANS:
- r = cms_RecipientInfo_ktri_encrypt(cms, ri);
- break;
-
- case CMS_RECIPINFO_KEK:
- r = cms_RecipientInfo_kekri_encrypt(cms, ri);
- break;
-
- case CMS_RECIPINFO_PASS:
- r = cms_RecipientInfo_pwri_crypt(cms, ri, 1);
- break;
-
- default:
- CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
- CMS_R_UNSUPPORTED_RECIPIENT_TYPE);
- goto err;
- }
-
- if (r <= 0)
- {
- CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
- CMS_R_ERROR_SETTING_RECIPIENTINFO);
- goto err;
- }
- }
-
- ok = 1;
-
- err:
- ec->cipher = NULL;
- if (ec->key)
- {
- OPENSSL_cleanse(ec->key, ec->keylen);
- OPENSSL_free(ec->key);
- ec->key = NULL;
- ec->keylen = 0;
- }
- if (ok)
- return ret;
- BIO_free(ret);
- return NULL;
-
- }
diff --git a/drivers/builtin_openssl/crypto/cms/cms_sd.c b/drivers/builtin_openssl/crypto/cms/cms_sd.c
deleted file mode 100644
index 77fbd13596..0000000000
--- a/drivers/builtin_openssl/crypto/cms/cms_sd.c
+++ /dev/null
@@ -1,985 +0,0 @@
-/* crypto/cms/cms_sd.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project.
- */
-/* ====================================================================
- * Copyright (c) 2008 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 "cryptlib.h"
-#include <openssl/asn1t.h>
-#include <openssl/pem.h>
-#include <openssl/x509v3.h>
-#include <openssl/err.h>
-#include <openssl/cms.h>
-#include "cms_lcl.h"
-#include "asn1_locl.h"
-
-/* CMS SignedData Utilities */
-
-DECLARE_ASN1_ITEM(CMS_SignedData)
-
-static CMS_SignedData *cms_get0_signed(CMS_ContentInfo *cms)
- {
- if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_signed)
- {
- CMSerr(CMS_F_CMS_GET0_SIGNED, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA);
- return NULL;
- }
- return cms->d.signedData;
- }
-
-static CMS_SignedData *cms_signed_data_init(CMS_ContentInfo *cms)
- {
- if (cms->d.other == NULL)
- {
- cms->d.signedData = M_ASN1_new_of(CMS_SignedData);
- if (!cms->d.signedData)
- {
- CMSerr(CMS_F_CMS_SIGNED_DATA_INIT, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- cms->d.signedData->version = 1;
- cms->d.signedData->encapContentInfo->eContentType =
- OBJ_nid2obj(NID_pkcs7_data);
- cms->d.signedData->encapContentInfo->partial = 1;
- ASN1_OBJECT_free(cms->contentType);
- cms->contentType = OBJ_nid2obj(NID_pkcs7_signed);
- return cms->d.signedData;
- }
- return cms_get0_signed(cms);
- }
-
-/* Just initialize SignedData e.g. for certs only structure */
-
-int CMS_SignedData_init(CMS_ContentInfo *cms)
- {
- if (cms_signed_data_init(cms))
- return 1;
- else
- return 0;
- }
-
-/* Check structures and fixup version numbers (if necessary) */
-
-static void cms_sd_set_version(CMS_SignedData *sd)
- {
- int i;
- CMS_CertificateChoices *cch;
- CMS_RevocationInfoChoice *rch;
- CMS_SignerInfo *si;
-
- for (i = 0; i < sk_CMS_CertificateChoices_num(sd->certificates); i++)
- {
- cch = sk_CMS_CertificateChoices_value(sd->certificates, i);
- if (cch->type == CMS_CERTCHOICE_OTHER)
- {
- if (sd->version < 5)
- sd->version = 5;
- }
- else if (cch->type == CMS_CERTCHOICE_V2ACERT)
- {
- if (sd->version < 4)
- sd->version = 4;
- }
- else if (cch->type == CMS_CERTCHOICE_V1ACERT)
- {
- if (sd->version < 3)
- sd->version = 3;
- }
- }
-
- for (i = 0; i < sk_CMS_RevocationInfoChoice_num(sd->crls); i++)
- {
- rch = sk_CMS_RevocationInfoChoice_value(sd->crls, i);
- if (rch->type == CMS_REVCHOICE_OTHER)
- {
- if (sd->version < 5)
- sd->version = 5;
- }
- }
-
- if ((OBJ_obj2nid(sd->encapContentInfo->eContentType) != NID_pkcs7_data)
- && (sd->version < 3))
- sd->version = 3;
-
- for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++)
- {
- si = sk_CMS_SignerInfo_value(sd->signerInfos, i);
- if (si->sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
- {
- if (si->version < 3)
- si->version = 3;
- if (sd->version < 3)
- sd->version = 3;
- }
- else
- sd->version = 1;
- }
-
- if (sd->version < 1)
- sd->version = 1;
-
- }
-
-/* Copy an existing messageDigest value */
-
-static int cms_copy_messageDigest(CMS_ContentInfo *cms, CMS_SignerInfo *si)
- {
- STACK_OF(CMS_SignerInfo) *sinfos;
- CMS_SignerInfo *sitmp;
- int i;
- sinfos = CMS_get0_SignerInfos(cms);
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
- {
- ASN1_OCTET_STRING *messageDigest;
- sitmp = sk_CMS_SignerInfo_value(sinfos, i);
- if (sitmp == si)
- continue;
- if (CMS_signed_get_attr_count(sitmp) < 0)
- continue;
- if (OBJ_cmp(si->digestAlgorithm->algorithm,
- sitmp->digestAlgorithm->algorithm))
- continue;
- messageDigest = CMS_signed_get0_data_by_OBJ(sitmp,
- OBJ_nid2obj(NID_pkcs9_messageDigest),
- -3, V_ASN1_OCTET_STRING);
- if (!messageDigest)
- {
- CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST,
- CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE);
- return 0;
- }
-
- if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
- V_ASN1_OCTET_STRING,
- messageDigest, -1))
- return 1;
- else
- return 0;
- }
- CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST, CMS_R_NO_MATCHING_DIGEST);
- return 0;
- }
-
-int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type)
- {
- switch(type)
- {
- case CMS_SIGNERINFO_ISSUER_SERIAL:
- sid->d.issuerAndSerialNumber =
- M_ASN1_new_of(CMS_IssuerAndSerialNumber);
- if (!sid->d.issuerAndSerialNumber)
- goto merr;
- if (!X509_NAME_set(&sid->d.issuerAndSerialNumber->issuer,
- X509_get_issuer_name(cert)))
- goto merr;
- if (!ASN1_STRING_copy(
- sid->d.issuerAndSerialNumber->serialNumber,
- X509_get_serialNumber(cert)))
- goto merr;
- break;
-
- case CMS_SIGNERINFO_KEYIDENTIFIER:
- if (!cert->skid)
- {
- CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER,
- CMS_R_CERTIFICATE_HAS_NO_KEYID);
- return 0;
- }
- sid->d.subjectKeyIdentifier = ASN1_STRING_dup(cert->skid);
- if (!sid->d.subjectKeyIdentifier)
- goto merr;
- break;
-
- default:
- CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, CMS_R_UNKNOWN_ID);
- return 0;
- }
-
- sid->type = type;
-
- return 1;
-
- merr:
- CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, ERR_R_MALLOC_FAILURE);
- return 0;
-
- }
-
-int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
- ASN1_OCTET_STRING **keyid,
- X509_NAME **issuer, ASN1_INTEGER **sno)
- {
- if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
- {
- if (issuer)
- *issuer = sid->d.issuerAndSerialNumber->issuer;
- if (sno)
- *sno = sid->d.issuerAndSerialNumber->serialNumber;
- }
- else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
- {
- if (keyid)
- *keyid = sid->d.subjectKeyIdentifier;
- }
- else
- return 0;
- return 1;
- }
-
-int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert)
- {
- int ret;
- if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
- {
- ret = X509_NAME_cmp(sid->d.issuerAndSerialNumber->issuer,
- X509_get_issuer_name(cert));
- if (ret)
- return ret;
- return ASN1_INTEGER_cmp(sid->d.issuerAndSerialNumber->serialNumber,
- X509_get_serialNumber(cert));
- }
- else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
- {
- X509_check_purpose(cert, -1, -1);
- if (!cert->skid)
- return -1;
- return ASN1_OCTET_STRING_cmp(sid->d.subjectKeyIdentifier,
- cert->skid);
- }
- else
- return -1;
- }
-
-CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
- X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
- unsigned int flags)
- {
- CMS_SignedData *sd;
- CMS_SignerInfo *si = NULL;
- X509_ALGOR *alg;
- int i, type;
- if(!X509_check_private_key(signer, pk))
- {
- CMSerr(CMS_F_CMS_ADD1_SIGNER,
- CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
- return NULL;
- }
- sd = cms_signed_data_init(cms);
- if (!sd)
- goto err;
- si = M_ASN1_new_of(CMS_SignerInfo);
- if (!si)
- goto merr;
- X509_check_purpose(signer, -1, -1);
-
- CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY);
- CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
-
- si->pkey = pk;
- si->signer = signer;
-
- if (flags & CMS_USE_KEYID)
- {
- si->version = 3;
- if (sd->version < 3)
- sd->version = 3;
- type = CMS_SIGNERINFO_KEYIDENTIFIER;
- }
- else
- {
- type = CMS_SIGNERINFO_ISSUER_SERIAL;
- si->version = 1;
- }
-
- if (!cms_set1_SignerIdentifier(si->sid, signer, type))
- goto err;
-
- if (md == NULL)
- {
- int def_nid;
- if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0)
- goto err;
- md = EVP_get_digestbynid(def_nid);
- if (md == NULL)
- {
- CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DEFAULT_DIGEST);
- goto err;
- }
- }
-
- if (!md)
- {
- CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DIGEST_SET);
- goto err;
- }
-
- cms_DigestAlgorithm_set(si->digestAlgorithm, md);
-
- /* See if digest is present in digestAlgorithms */
- for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++)
- {
- ASN1_OBJECT *aoid;
- alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
- X509_ALGOR_get0(&aoid, NULL, NULL, alg);
- if (OBJ_obj2nid(aoid) == EVP_MD_type(md))
- break;
- }
-
- if (i == sk_X509_ALGOR_num(sd->digestAlgorithms))
- {
- alg = X509_ALGOR_new();
- if (!alg)
- goto merr;
- cms_DigestAlgorithm_set(alg, md);
- if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg))
- {
- X509_ALGOR_free(alg);
- goto merr;
- }
- }
-
- if (pk->ameth && pk->ameth->pkey_ctrl)
- {
- i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_SIGN,
- 0, si);
- if (i == -2)
- {
- CMSerr(CMS_F_CMS_ADD1_SIGNER,
- CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
- goto err;
- }
- if (i <= 0)
- {
- CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_CTRL_FAILURE);
- goto err;
- }
- }
-
- if (!(flags & CMS_NOATTR))
- {
- /* Initialialize signed attributes strutucture so other
- * attributes such as signing time etc are added later
- * even if we add none here.
- */
- if (!si->signedAttrs)
- {
- si->signedAttrs = sk_X509_ATTRIBUTE_new_null();
- if (!si->signedAttrs)
- goto merr;
- }
-
- if (!(flags & CMS_NOSMIMECAP))
- {
- STACK_OF(X509_ALGOR) *smcap = NULL;
- i = CMS_add_standard_smimecap(&smcap);
- if (i)
- i = CMS_add_smimecap(si, smcap);
- sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
- if (!i)
- goto merr;
- }
- if (flags & CMS_REUSE_DIGEST)
- {
- if (!cms_copy_messageDigest(cms, si))
- goto err;
- if (!(flags & CMS_PARTIAL) &&
- !CMS_SignerInfo_sign(si))
- goto err;
- }
- }
-
- if (!(flags & CMS_NOCERTS))
- {
- /* NB ignore -1 return for duplicate cert */
- if (!CMS_add1_cert(cms, signer))
- goto merr;
- }
-
- if (!sd->signerInfos)
- sd->signerInfos = sk_CMS_SignerInfo_new_null();
- if (!sd->signerInfos ||
- !sk_CMS_SignerInfo_push(sd->signerInfos, si))
- goto merr;
-
- return si;
-
- merr:
- CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE);
- err:
- if (si)
- M_ASN1_free_of(si, CMS_SignerInfo);
- return NULL;
-
- }
-
-static int cms_add1_signingTime(CMS_SignerInfo *si, ASN1_TIME *t)
- {
- ASN1_TIME *tt;
- int r = 0;
- if (t)
- tt = t;
- else
- tt = X509_gmtime_adj(NULL, 0);
-
- if (!tt)
- goto merr;
-
- if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_signingTime,
- tt->type, tt, -1) <= 0)
- goto merr;
-
- r = 1;
-
- merr:
-
- if (!t)
- ASN1_TIME_free(tt);
-
- if (!r)
- CMSerr(CMS_F_CMS_ADD1_SIGNINGTIME, ERR_R_MALLOC_FAILURE);
-
- return r;
-
- }
-
-STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms)
- {
- CMS_SignedData *sd;
- sd = cms_get0_signed(cms);
- if (!sd)
- return NULL;
- return sd->signerInfos;
- }
-
-STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms)
- {
- STACK_OF(X509) *signers = NULL;
- STACK_OF(CMS_SignerInfo) *sinfos;
- CMS_SignerInfo *si;
- int i;
- sinfos = CMS_get0_SignerInfos(cms);
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
- {
- si = sk_CMS_SignerInfo_value(sinfos, i);
- if (si->signer)
- {
- if (!signers)
- {
- signers = sk_X509_new_null();
- if (!signers)
- return NULL;
- }
- if (!sk_X509_push(signers, si->signer))
- {
- sk_X509_free(signers);
- return NULL;
- }
- }
- }
- return signers;
- }
-
-void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer)
- {
- if (signer)
- {
- CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
- if (si->pkey)
- EVP_PKEY_free(si->pkey);
- si->pkey = X509_get_pubkey(signer);
- }
- if (si->signer)
- X509_free(si->signer);
- si->signer = signer;
- }
-
-int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si,
- ASN1_OCTET_STRING **keyid,
- X509_NAME **issuer, ASN1_INTEGER **sno)
- {
- return cms_SignerIdentifier_get0_signer_id(si->sid, keyid, issuer, sno);
- }
-
-int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert)
- {
- return cms_SignerIdentifier_cert_cmp(si->sid, cert);
- }
-
-int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *scerts,
- unsigned int flags)
- {
- CMS_SignedData *sd;
- CMS_SignerInfo *si;
- CMS_CertificateChoices *cch;
- STACK_OF(CMS_CertificateChoices) *certs;
- X509 *x;
- int i, j;
- int ret = 0;
- sd = cms_get0_signed(cms);
- if (!sd)
- return -1;
- certs = sd->certificates;
- for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++)
- {
- si = sk_CMS_SignerInfo_value(sd->signerInfos, i);
- if (si->signer)
- continue;
-
- for (j = 0; j < sk_X509_num(scerts); j++)
- {
- x = sk_X509_value(scerts, j);
- if (CMS_SignerInfo_cert_cmp(si, x) == 0)
- {
- CMS_SignerInfo_set1_signer_cert(si, x);
- ret++;
- break;
- }
- }
-
- if (si->signer || (flags & CMS_NOINTERN))
- continue;
-
- for (j = 0; j < sk_CMS_CertificateChoices_num(certs); j++)
- {
- cch = sk_CMS_CertificateChoices_value(certs, j);
- if (cch->type != 0)
- continue;
- x = cch->d.certificate;
- if (CMS_SignerInfo_cert_cmp(si, x) == 0)
- {
- CMS_SignerInfo_set1_signer_cert(si, x);
- ret++;
- break;
- }
- }
- }
- return ret;
- }
-
-void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, X509 **signer,
- X509_ALGOR **pdig, X509_ALGOR **psig)
- {
- if (pk)
- *pk = si->pkey;
- if (signer)
- *signer = si->signer;
- if (pdig)
- *pdig = si->digestAlgorithm;
- if (psig)
- *psig = si->signatureAlgorithm;
- }
-
-static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
- CMS_SignerInfo *si, BIO *chain)
- {
- EVP_MD_CTX mctx;
- int r = 0;
- EVP_MD_CTX_init(&mctx);
-
-
- if (!si->pkey)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, CMS_R_NO_PRIVATE_KEY);
- return 0;
- }
-
- if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm))
- goto err;
-
- /* If any signed attributes calculate and add messageDigest attribute */
-
- if (CMS_signed_get_attr_count(si) >= 0)
- {
- ASN1_OBJECT *ctype =
- cms->d.signedData->encapContentInfo->eContentType;
- unsigned char md[EVP_MAX_MD_SIZE];
- unsigned int mdlen;
- if (!EVP_DigestFinal_ex(&mctx, md, &mdlen))
- goto err;
- if (!CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
- V_ASN1_OCTET_STRING,
- md, mdlen))
- goto err;
- /* Copy content type across */
- if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_contentType,
- V_ASN1_OBJECT, ctype, -1) <= 0)
- goto err;
- if (!CMS_SignerInfo_sign(si))
- goto err;
- }
- else
- {
- unsigned char *sig;
- unsigned int siglen;
- sig = OPENSSL_malloc(EVP_PKEY_size(si->pkey));
- if (!sig)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (!EVP_SignFinal(&mctx, sig, &siglen, si->pkey))
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN,
- CMS_R_SIGNFINAL_ERROR);
- OPENSSL_free(sig);
- goto err;
- }
- ASN1_STRING_set0(si->signature, sig, siglen);
- }
-
- r = 1;
-
- err:
- EVP_MD_CTX_cleanup(&mctx);
- return r;
-
- }
-
-int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain)
- {
- STACK_OF(CMS_SignerInfo) *sinfos;
- CMS_SignerInfo *si;
- int i;
- sinfos = CMS_get0_SignerInfos(cms);
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
- {
- si = sk_CMS_SignerInfo_value(sinfos, i);
- if (!cms_SignerInfo_content_sign(cms, si, chain))
- return 0;
- }
- cms->d.signedData->encapContentInfo->partial = 0;
- return 1;
- }
-
-int CMS_SignerInfo_sign(CMS_SignerInfo *si)
- {
- EVP_MD_CTX mctx;
- EVP_PKEY_CTX *pctx;
- unsigned char *abuf = NULL;
- int alen;
- size_t siglen;
- const EVP_MD *md = NULL;
-
- md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
- if (md == NULL)
- return 0;
-
- EVP_MD_CTX_init(&mctx);
-
- if (CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0)
- {
- if (!cms_add1_signingTime(si, NULL))
- goto err;
- }
-
- if (EVP_DigestSignInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
- EVP_PKEY_CTRL_CMS_SIGN, 0, si) <= 0)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
- goto err;
- }
-
- alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf,
- ASN1_ITEM_rptr(CMS_Attributes_Sign));
- if(!abuf)
- goto err;
- if (EVP_DigestSignUpdate(&mctx, abuf, alen) <= 0)
- goto err;
- if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0)
- goto err;
- OPENSSL_free(abuf);
- abuf = OPENSSL_malloc(siglen);
- if(!abuf)
- goto err;
- if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
- EVP_PKEY_CTRL_CMS_SIGN, 1, si) <= 0)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
- goto err;
- }
-
- EVP_MD_CTX_cleanup(&mctx);
-
- ASN1_STRING_set0(si->signature, abuf, siglen);
-
- return 1;
-
- err:
- if (abuf)
- OPENSSL_free(abuf);
- EVP_MD_CTX_cleanup(&mctx);
- return 0;
-
- }
-
-int CMS_SignerInfo_verify(CMS_SignerInfo *si)
- {
- EVP_MD_CTX mctx;
- EVP_PKEY_CTX *pctx;
- unsigned char *abuf = NULL;
- int alen, r = -1;
- const EVP_MD *md = NULL;
-
- if (!si->pkey)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_NO_PUBLIC_KEY);
- return -1;
- }
-
- md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
- if (md == NULL)
- return -1;
- EVP_MD_CTX_init(&mctx);
- if (EVP_DigestVerifyInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
- goto err;
-
- alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf,
- ASN1_ITEM_rptr(CMS_Attributes_Verify));
- if(!abuf)
- goto err;
- r = EVP_DigestVerifyUpdate(&mctx, abuf, alen);
- OPENSSL_free(abuf);
- if (r <= 0)
- {
- r = -1;
- goto err;
- }
- r = EVP_DigestVerifyFinal(&mctx,
- si->signature->data, si->signature->length);
- if (r <= 0)
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_VERIFICATION_FAILURE);
- err:
- EVP_MD_CTX_cleanup(&mctx);
- return r;
- }
-
-/* Create a chain of digest BIOs from a CMS ContentInfo */
-
-BIO *cms_SignedData_init_bio(CMS_ContentInfo *cms)
- {
- int i;
- CMS_SignedData *sd;
- BIO *chain = NULL;
- sd = cms_get0_signed(cms);
- if (!sd)
- return NULL;
- if (cms->d.signedData->encapContentInfo->partial)
- cms_sd_set_version(sd);
- for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++)
- {
- X509_ALGOR *digestAlgorithm;
- BIO *mdbio;
- digestAlgorithm = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
- mdbio = cms_DigestAlgorithm_init_bio(digestAlgorithm);
- if (!mdbio)
- goto err;
- if (chain)
- BIO_push(chain, mdbio);
- else
- chain = mdbio;
- }
- return chain;
- err:
- if (chain)
- BIO_free_all(chain);
- return NULL;
- }
-
-int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
- {
- ASN1_OCTET_STRING *os = NULL;
- EVP_MD_CTX mctx;
- int r = -1;
- EVP_MD_CTX_init(&mctx);
- /* If we have any signed attributes look for messageDigest value */
- if (CMS_signed_get_attr_count(si) >= 0)
- {
- os = CMS_signed_get0_data_by_OBJ(si,
- OBJ_nid2obj(NID_pkcs9_messageDigest),
- -3, V_ASN1_OCTET_STRING);
- if (!os)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
- CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE);
- goto err;
- }
- }
-
- if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm))
- goto err;
-
- /* If messageDigest found compare it */
-
- if (os)
- {
- unsigned char mval[EVP_MAX_MD_SIZE];
- unsigned int mlen;
- if (EVP_DigestFinal_ex(&mctx, mval, &mlen) <= 0)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
- CMS_R_UNABLE_TO_FINALIZE_CONTEXT);
- goto err;
- }
- if (mlen != (unsigned int)os->length)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
- CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH);
- goto err;
- }
-
- if (memcmp(mval, os->data, mlen))
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
- CMS_R_VERIFICATION_FAILURE);
- r = 0;
- }
- else
- r = 1;
- }
- else
- {
- r = EVP_VerifyFinal(&mctx, si->signature->data,
- si->signature->length, si->pkey);
- if (r <= 0)
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
- CMS_R_VERIFICATION_FAILURE);
- r = 0;
- }
- }
-
- err:
- EVP_MD_CTX_cleanup(&mctx);
- return r;
-
- }
-
-int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs)
- {
- unsigned char *smder = NULL;
- int smderlen, r;
- smderlen = i2d_X509_ALGORS(algs, &smder);
- if (smderlen <= 0)
- return 0;
- r = CMS_signed_add1_attr_by_NID(si, NID_SMIMECapabilities,
- V_ASN1_SEQUENCE, smder, smderlen);
- OPENSSL_free(smder);
- return r;
- }
-
-int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs,
- int algnid, int keysize)
- {
- X509_ALGOR *alg;
- ASN1_INTEGER *key = NULL;
- if (keysize > 0)
- {
- key = ASN1_INTEGER_new();
- if (!key || !ASN1_INTEGER_set(key, keysize))
- return 0;
- }
- alg = X509_ALGOR_new();
- if (!alg)
- {
- if (key)
- ASN1_INTEGER_free(key);
- return 0;
- }
-
- X509_ALGOR_set0(alg, OBJ_nid2obj(algnid),
- key ? V_ASN1_INTEGER : V_ASN1_UNDEF, key);
- if (!*algs)
- *algs = sk_X509_ALGOR_new_null();
- if (!*algs || !sk_X509_ALGOR_push(*algs, alg))
- {
- X509_ALGOR_free(alg);
- return 0;
- }
- return 1;
- }
-
-/* Check to see if a cipher exists and if so add S/MIME capabilities */
-
-static int cms_add_cipher_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg)
- {
- if (EVP_get_cipherbynid(nid))
- return CMS_add_simple_smimecap(sk, nid, arg);
- return 1;
- }
-
-static int cms_add_digest_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg)
- {
- if (EVP_get_digestbynid(nid))
- return CMS_add_simple_smimecap(sk, nid, arg);
- return 1;
- }
-
-int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap)
- {
- if (!cms_add_cipher_smcap(smcap, NID_aes_256_cbc, -1)
- || !cms_add_digest_smcap(smcap, NID_id_GostR3411_94, -1)
- || !cms_add_cipher_smcap(smcap, NID_id_Gost28147_89, -1)
- || !cms_add_cipher_smcap(smcap, NID_aes_192_cbc, -1)
- || !cms_add_cipher_smcap(smcap, NID_aes_128_cbc, -1)
- || !cms_add_cipher_smcap(smcap, NID_des_ede3_cbc, -1)
- || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 128)
- || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 64)
- || !cms_add_cipher_smcap(smcap, NID_des_cbc, -1)
- || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 40))
- return 0;
- return 1;
- }
diff --git a/drivers/builtin_openssl/crypto/cms/cms_smime.c b/drivers/builtin_openssl/crypto/cms/cms_smime.c
deleted file mode 100644
index 8c56e3a852..0000000000
--- a/drivers/builtin_openssl/crypto/cms/cms_smime.c
+++ /dev/null
@@ -1,850 +0,0 @@
-/* crypto/cms/cms_smime.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project.
- */
-/* ====================================================================
- * Copyright (c) 2008 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 "cryptlib.h"
-#include <openssl/asn1t.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/err.h>
-#include <openssl/cms.h>
-#include "cms_lcl.h"
-
-static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
- {
- unsigned char buf[4096];
- int r = 0, i;
- BIO *tmpout = NULL;
-
- if (out == NULL)
- tmpout = BIO_new(BIO_s_null());
- else if (flags & CMS_TEXT)
- {
- tmpout = BIO_new(BIO_s_mem());
- BIO_set_mem_eof_return(tmpout, 0);
- }
- else
- tmpout = out;
-
- if(!tmpout)
- {
- CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* Read all content through chain to process digest, decrypt etc */
- for (;;)
- {
- i=BIO_read(in,buf,sizeof(buf));
- if (i <= 0)
- {
- if (BIO_method_type(in) == BIO_TYPE_CIPHER)
- {
- if (!BIO_get_cipher_status(in))
- goto err;
- }
- if (i < 0)
- goto err;
- break;
- }
-
- if (tmpout && (BIO_write(tmpout, buf, i) != i))
- goto err;
- }
-
- if(flags & CMS_TEXT)
- {
- if(!SMIME_text(tmpout, out))
- {
- CMSerr(CMS_F_CMS_COPY_CONTENT,CMS_R_SMIME_TEXT_ERROR);
- goto err;
- }
- }
-
- r = 1;
-
- err:
- if (tmpout && (tmpout != out))
- BIO_free(tmpout);
- return r;
-
- }
-
-static int check_content(CMS_ContentInfo *cms)
- {
- ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
- if (!pos || !*pos)
- {
- CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT);
- return 0;
- }
- return 1;
- }
-
-static void do_free_upto(BIO *f, BIO *upto)
- {
- if (upto)
- {
- BIO *tbio;
- do
- {
- tbio = BIO_pop(f);
- BIO_free(f);
- f = tbio;
- }
- while (f != upto);
- }
- else
- BIO_free_all(f);
- }
-
-int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
- {
- BIO *cont;
- int r;
- if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data)
- {
- CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA);
- return 0;
- }
- cont = CMS_dataInit(cms, NULL);
- if (!cont)
- return 0;
- r = cms_copy_content(out, cont, flags);
- BIO_free_all(cont);
- return r;
- }
-
-CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
- {
- CMS_ContentInfo *cms;
- cms = cms_Data_create();
- if (!cms)
- return NULL;
-
- if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
- return cms;
-
- CMS_ContentInfo_free(cms);
-
- return NULL;
- }
-
-int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
- unsigned int flags)
- {
- BIO *cont;
- int r;
- if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest)
- {
- CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA);
- return 0;
- }
-
- if (!dcont && !check_content(cms))
- return 0;
-
- cont = CMS_dataInit(cms, dcont);
- if (!cont)
- return 0;
- r = cms_copy_content(out, cont, flags);
- if (r)
- r = cms_DigestedData_do_final(cms, cont, 1);
- do_free_upto(cont, dcont);
- return r;
- }
-
-CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
- unsigned int flags)
- {
- CMS_ContentInfo *cms;
- if (!md)
- md = EVP_sha1();
- cms = cms_DigestedData_create(md);
- if (!cms)
- return NULL;
-
- if(!(flags & CMS_DETACHED))
- CMS_set_detached(cms, 0);
-
- if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
- return cms;
-
- CMS_ContentInfo_free(cms);
- return NULL;
- }
-
-int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
- const unsigned char *key, size_t keylen,
- BIO *dcont, BIO *out, unsigned int flags)
- {
- BIO *cont;
- int r;
- if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted)
- {
- CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT,
- CMS_R_TYPE_NOT_ENCRYPTED_DATA);
- return 0;
- }
-
- if (!dcont && !check_content(cms))
- return 0;
-
- if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
- return 0;
- cont = CMS_dataInit(cms, dcont);
- if (!cont)
- return 0;
- r = cms_copy_content(out, cont, flags);
- do_free_upto(cont, dcont);
- return r;
- }
-
-CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
- const unsigned char *key, size_t keylen,
- unsigned int flags)
- {
- CMS_ContentInfo *cms;
- if (!cipher)
- {
- CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER);
- return NULL;
- }
- cms = CMS_ContentInfo_new();
- if (!cms)
- return NULL;
- if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
- return NULL;
-
- if(!(flags & CMS_DETACHED))
- CMS_set_detached(cms, 0);
-
- if ((flags & (CMS_STREAM|CMS_PARTIAL))
- || CMS_final(cms, in, NULL, flags))
- return cms;
-
- CMS_ContentInfo_free(cms);
- return NULL;
- }
-
-static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
- X509_STORE *store,
- STACK_OF(X509) *certs,
- STACK_OF(X509_CRL) *crls,
- unsigned int flags)
- {
- X509_STORE_CTX ctx;
- X509 *signer;
- int i, j, r = 0;
- CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
- if (!X509_STORE_CTX_init(&ctx, store, signer, certs))
- {
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
- CMS_R_STORE_INIT_ERROR);
- goto err;
- }
- X509_STORE_CTX_set_default(&ctx, "smime_sign");
- if (crls)
- X509_STORE_CTX_set0_crls(&ctx, crls);
-
- i = X509_verify_cert(&ctx);
- if (i <= 0)
- {
- j = X509_STORE_CTX_get_error(&ctx);
- CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
- CMS_R_CERTIFICATE_VERIFY_ERROR);
- ERR_add_error_data(2, "Verify error:",
- X509_verify_cert_error_string(j));
- goto err;
- }
- r = 1;
- err:
- X509_STORE_CTX_cleanup(&ctx);
- return r;
-
- }
-
-int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
- X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags)
- {
- CMS_SignerInfo *si;
- STACK_OF(CMS_SignerInfo) *sinfos;
- STACK_OF(X509) *cms_certs = NULL;
- STACK_OF(X509_CRL) *crls = NULL;
- X509 *signer;
- int i, scount = 0, ret = 0;
- BIO *cmsbio = NULL, *tmpin = NULL;
-
- if (!dcont && !check_content(cms))
- return 0;
-
- /* Attempt to find all signer certificates */
-
- sinfos = CMS_get0_SignerInfos(cms);
-
- if (sk_CMS_SignerInfo_num(sinfos) <= 0)
- {
- CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS);
- goto err;
- }
-
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
- {
- si = sk_CMS_SignerInfo_value(sinfos, i);
- CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
- if (signer)
- scount++;
- }
-
- if (scount != sk_CMS_SignerInfo_num(sinfos))
- scount += CMS_set1_signers_certs(cms, certs, flags);
-
- if (scount != sk_CMS_SignerInfo_num(sinfos))
- {
- CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
- goto err;
- }
-
- /* Attempt to verify all signers certs */
-
- if (!(flags & CMS_NO_SIGNER_CERT_VERIFY))
- {
- cms_certs = CMS_get1_certs(cms);
- if (!(flags & CMS_NOCRL))
- crls = CMS_get1_crls(cms);
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
- {
- si = sk_CMS_SignerInfo_value(sinfos, i);
- if (!cms_signerinfo_verify_cert(si, store,
- cms_certs, crls, flags))
- goto err;
- }
- }
-
- /* Attempt to verify all SignerInfo signed attribute signatures */
-
- if (!(flags & CMS_NO_ATTR_VERIFY))
- {
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
- {
- si = sk_CMS_SignerInfo_value(sinfos, i);
- if (CMS_signed_get_attr_count(si) < 0)
- continue;
- if (CMS_SignerInfo_verify(si) <= 0)
- goto err;
- }
- }
-
- /* Performance optimization: if the content is a memory BIO then
- * store its contents in a temporary read only memory BIO. This
- * avoids potentially large numbers of slow copies of data which will
- * occur when reading from a read write memory BIO when signatures
- * are calculated.
- */
-
- if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM))
- {
- char *ptr;
- long len;
- len = BIO_get_mem_data(dcont, &ptr);
- tmpin = BIO_new_mem_buf(ptr, len);
- if (tmpin == NULL)
- {
- CMSerr(CMS_F_CMS_VERIFY,ERR_R_MALLOC_FAILURE);
- return 0;
- }
- }
- else
- tmpin = dcont;
-
-
- cmsbio=CMS_dataInit(cms, tmpin);
- if (!cmsbio)
- goto err;
-
- if (!cms_copy_content(out, cmsbio, flags))
- goto err;
-
- if (!(flags & CMS_NO_CONTENT_VERIFY))
- {
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
- {
- si = sk_CMS_SignerInfo_value(sinfos, i);
- if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0)
- {
- CMSerr(CMS_F_CMS_VERIFY,
- CMS_R_CONTENT_VERIFY_ERROR);
- goto err;
- }
- }
- }
-
- ret = 1;
-
- err:
-
- if (dcont && (tmpin == dcont))
- do_free_upto(cmsbio, dcont);
- else
- BIO_free_all(cmsbio);
-
- if (cms_certs)
- sk_X509_pop_free(cms_certs, X509_free);
- if (crls)
- sk_X509_CRL_pop_free(crls, X509_CRL_free);
-
- return ret;
- }
-
-int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
- STACK_OF(X509) *certs,
- X509_STORE *store, unsigned int flags)
- {
- int r;
- flags &= ~(CMS_DETACHED|CMS_TEXT);
- r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
- if (r <= 0)
- return r;
- return cms_Receipt_verify(rcms, ocms);
- }
-
-CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
- BIO *data, unsigned int flags)
- {
- CMS_ContentInfo *cms;
- int i;
-
- cms = CMS_ContentInfo_new();
- if (!cms || !CMS_SignedData_init(cms))
- goto merr;
-
- if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags))
- {
- CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR);
- goto err;
- }
-
- for (i = 0; i < sk_X509_num(certs); i++)
- {
- X509 *x = sk_X509_value(certs, i);
- if (!CMS_add1_cert(cms, x))
- goto merr;
- }
-
- if(!(flags & CMS_DETACHED))
- CMS_set_detached(cms, 0);
-
- if ((flags & (CMS_STREAM|CMS_PARTIAL))
- || CMS_final(cms, data, NULL, flags))
- return cms;
- else
- goto err;
-
- merr:
- CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE);
-
- err:
- if (cms)
- CMS_ContentInfo_free(cms);
- return NULL;
- }
-
-CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
- X509 *signcert, EVP_PKEY *pkey,
- STACK_OF(X509) *certs,
- unsigned int flags)
- {
- CMS_SignerInfo *rct_si;
- CMS_ContentInfo *cms = NULL;
- ASN1_OCTET_STRING **pos, *os;
- BIO *rct_cont = NULL;
- int r = 0;
-
- flags &= ~(CMS_STREAM|CMS_TEXT);
- /* Not really detached but avoids content being allocated */
- flags |= CMS_PARTIAL|CMS_BINARY|CMS_DETACHED;
- if (!pkey || !signcert)
- {
- CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT);
- return NULL;
- }
-
- /* Initialize signed data */
-
- cms = CMS_sign(NULL, NULL, certs, NULL, flags);
- if (!cms)
- goto err;
-
- /* Set inner content type to signed receipt */
- if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt)))
- goto err;
-
- rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
- if (!rct_si)
- {
- CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR);
- goto err;
- }
-
- os = cms_encode_Receipt(si);
-
- if (!os)
- goto err;
-
- /* Set content to digest */
- rct_cont = BIO_new_mem_buf(os->data, os->length);
- if (!rct_cont)
- goto err;
-
- /* Add msgSigDigest attribute */
-
- if (!cms_msgSigDigest_add1(rct_si, si))
- goto err;
-
- /* Finalize structure */
- if (!CMS_final(cms, rct_cont, NULL, flags))
- goto err;
-
- /* Set embedded content */
- pos = CMS_get0_content(cms);
- *pos = os;
-
- r = 1;
-
- err:
- if (rct_cont)
- BIO_free(rct_cont);
- if (r)
- return cms;
- CMS_ContentInfo_free(cms);
- return NULL;
-
- }
-
-CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
- const EVP_CIPHER *cipher, unsigned int flags)
- {
- CMS_ContentInfo *cms;
- int i;
- X509 *recip;
- cms = CMS_EnvelopedData_create(cipher);
- if (!cms)
- goto merr;
- for (i = 0; i < sk_X509_num(certs); i++)
- {
- recip = sk_X509_value(certs, i);
- if (!CMS_add1_recipient_cert(cms, recip, flags))
- {
- CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
- goto err;
- }
- }
-
- if(!(flags & CMS_DETACHED))
- CMS_set_detached(cms, 0);
-
- if ((flags & (CMS_STREAM|CMS_PARTIAL))
- || CMS_final(cms, data, NULL, flags))
- return cms;
- else
- goto err;
-
- merr:
- CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
- err:
- if (cms)
- CMS_ContentInfo_free(cms);
- return NULL;
- }
-
-int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
- {
- STACK_OF(CMS_RecipientInfo) *ris;
- CMS_RecipientInfo *ri;
- int i, r;
- int debug = 0;
- ris = CMS_get0_RecipientInfos(cms);
- if (ris)
- debug = cms->d.envelopedData->encryptedContentInfo->debug;
- for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
- {
- ri = sk_CMS_RecipientInfo_value(ris, i);
- if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
- continue;
- /* If we have a cert try matching RecipientInfo
- * otherwise try them all.
- */
- if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0))
- {
- CMS_RecipientInfo_set0_pkey(ri, pk);
- r = CMS_RecipientInfo_decrypt(cms, ri);
- CMS_RecipientInfo_set0_pkey(ri, NULL);
- if (cert)
- {
- /* If not debugging clear any error and
- * return success to avoid leaking of
- * information useful to MMA
- */
- if (!debug)
- {
- ERR_clear_error();
- return 1;
- }
- if (r > 0)
- return 1;
- CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY,
- CMS_R_DECRYPT_ERROR);
- return 0;
- }
- /* If no cert and not debugging don't leave loop
- * after first successful decrypt. Always attempt
- * to decrypt all recipients to avoid leaking timing
- * of a successful decrypt.
- */
- else if (r > 0 && debug)
- return 1;
- }
- }
- /* If no cert and not debugging always return success */
- if (!cert && !debug)
- {
- ERR_clear_error();
- return 1;
- }
-
- CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
- return 0;
-
- }
-
-int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
- unsigned char *key, size_t keylen,
- unsigned char *id, size_t idlen)
- {
- STACK_OF(CMS_RecipientInfo) *ris;
- CMS_RecipientInfo *ri;
- int i, r;
- ris = CMS_get0_RecipientInfos(cms);
- for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
- {
- ri = sk_CMS_RecipientInfo_value(ris, i);
- if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK)
- continue;
-
- /* If we have an id try matching RecipientInfo
- * otherwise try them all.
- */
- if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0))
- {
- CMS_RecipientInfo_set0_key(ri, key, keylen);
- r = CMS_RecipientInfo_decrypt(cms, ri);
- CMS_RecipientInfo_set0_key(ri, NULL, 0);
- if (r > 0)
- return 1;
- if (id)
- {
- CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY,
- CMS_R_DECRYPT_ERROR);
- return 0;
- }
- ERR_clear_error();
- }
- }
-
- CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT);
- return 0;
-
- }
-
-int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
- unsigned char *pass, ossl_ssize_t passlen)
- {
- STACK_OF(CMS_RecipientInfo) *ris;
- CMS_RecipientInfo *ri;
- int i, r;
- ris = CMS_get0_RecipientInfos(cms);
- for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
- {
- ri = sk_CMS_RecipientInfo_value(ris, i);
- if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS)
- continue;
- CMS_RecipientInfo_set0_password(ri, pass, passlen);
- r = CMS_RecipientInfo_decrypt(cms, ri);
- CMS_RecipientInfo_set0_password(ri, NULL, 0);
- if (r > 0)
- return 1;
- }
-
- CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT);
- return 0;
-
- }
-
-int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
- BIO *dcont, BIO *out,
- unsigned int flags)
- {
- int r;
- BIO *cont;
- if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped)
- {
- CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
- return 0;
- }
- if (!dcont && !check_content(cms))
- return 0;
- if (flags & CMS_DEBUG_DECRYPT)
- cms->d.envelopedData->encryptedContentInfo->debug = 1;
- else
- cms->d.envelopedData->encryptedContentInfo->debug = 0;
- if (!pk && !cert && !dcont && !out)
- return 1;
- if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
- return 0;
- cont = CMS_dataInit(cms, dcont);
- if (!cont)
- return 0;
- r = cms_copy_content(out, cont, flags);
- do_free_upto(cont, dcont);
- return r;
- }
-
-int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
- {
- BIO *cmsbio;
- int ret = 0;
- if (!(cmsbio = CMS_dataInit(cms, dcont)))
- {
- CMSerr(CMS_F_CMS_FINAL,ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- SMIME_crlf_copy(data, cmsbio, flags);
-
- (void)BIO_flush(cmsbio);
-
-
- if (!CMS_dataFinal(cms, cmsbio))
- {
- CMSerr(CMS_F_CMS_FINAL,CMS_R_CMS_DATAFINAL_ERROR);
- goto err;
- }
-
- ret = 1;
-
- err:
- do_free_upto(cmsbio, dcont);
-
- return ret;
-
- }
-
-#ifdef ZLIB
-
-int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
- unsigned int flags)
- {
- BIO *cont;
- int r;
- if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData)
- {
- CMSerr(CMS_F_CMS_UNCOMPRESS,
- CMS_R_TYPE_NOT_COMPRESSED_DATA);
- return 0;
- }
-
- if (!dcont && !check_content(cms))
- return 0;
-
- cont = CMS_dataInit(cms, dcont);
- if (!cont)
- return 0;
- r = cms_copy_content(out, cont, flags);
- do_free_upto(cont, dcont);
- return r;
- }
-
-CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
- {
- CMS_ContentInfo *cms;
- if (comp_nid <= 0)
- comp_nid = NID_zlib_compression;
- cms = cms_CompressedData_create(comp_nid);
- if (!cms)
- return NULL;
-
- if(!(flags & CMS_DETACHED))
- CMS_set_detached(cms, 0);
-
- if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
- return cms;
-
- CMS_ContentInfo_free(cms);
- return NULL;
- }
-
-#else
-
-int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
- unsigned int flags)
- {
- CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
- return 0;
- }
-
-CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
- {
- CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
- return NULL;
- }
-
-#endif
diff --git a/drivers/builtin_openssl/crypto/dso/dso_dlfcn.c b/drivers/builtin_openssl/crypto/dso/dso_dlfcn.c
deleted file mode 100644
index 5f2254806c..0000000000
--- a/drivers/builtin_openssl/crypto/dso/dso_dlfcn.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/* dso_dlfcn.c -*- mode:C; c-file-style: "eay" -*- */
-/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
- * project 2000.
- */
-/* ====================================================================
- * Copyright (c) 2000 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-/* We need to do this early, because stdio.h includes the header files
- that handle _GNU_SOURCE and other similar macros. Defining it later
- is simply too late, because those headers are protected from re-
- inclusion. */
-#ifdef __linux
-# ifndef _GNU_SOURCE
-# define _GNU_SOURCE /* make sure dladdr is declared */
-# endif
-#endif
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/dso.h>
-
-#ifndef DSO_DLFCN
-DSO_METHOD *DSO_METHOD_dlfcn(void)
- {
- return NULL;
- }
-#else
-
-#ifdef HAVE_DLFCN_H
-# ifdef __osf__
-# define __EXTENSIONS__
-# endif
-# include <dlfcn.h>
-# define HAVE_DLINFO 1
-# if defined(_AIX) || defined(__CYGWIN__) || \
- defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
- (defined(__osf__) && !defined(RTLD_NEXT)) || \
- (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
- defined(__ANDROID__)
-# undef HAVE_DLINFO
-# endif
-#endif
-
-/* Part of the hack in "dlfcn_load" ... */
-#define DSO_MAX_TRANSLATED_SIZE 256
-
-static int dlfcn_load(DSO *dso);
-static int dlfcn_unload(DSO *dso);
-static void *dlfcn_bind_var(DSO *dso, const char *symname);
-static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
-#if 0
-static int dlfcn_unbind(DSO *dso, char *symname, void *symptr);
-static int dlfcn_init(DSO *dso);
-static int dlfcn_finish(DSO *dso);
-static long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg);
-#endif
-static char *dlfcn_name_converter(DSO *dso, const char *filename);
-static char *dlfcn_merger(DSO *dso, const char *filespec1,
- const char *filespec2);
-static int dlfcn_pathbyaddr(void *addr,char *path,int sz);
-static void *dlfcn_globallookup(const char *name);
-
-static DSO_METHOD dso_meth_dlfcn = {
- "OpenSSL 'dlfcn' shared library method",
- dlfcn_load,
- dlfcn_unload,
- dlfcn_bind_var,
- dlfcn_bind_func,
-/* For now, "unbind" doesn't exist */
-#if 0
- NULL, /* unbind_var */
- NULL, /* unbind_func */
-#endif
- NULL, /* ctrl */
- dlfcn_name_converter,
- dlfcn_merger,
- NULL, /* init */
- NULL, /* finish */
- dlfcn_pathbyaddr,
- dlfcn_globallookup
- };
-
-DSO_METHOD *DSO_METHOD_dlfcn(void)
- {
- return(&dso_meth_dlfcn);
- }
-
-/* Prior to using the dlopen() function, we should decide on the flag
- * we send. There's a few different ways of doing this and it's a
- * messy venn-diagram to match up which platforms support what. So
- * as we don't have autoconf yet, I'm implementing a hack that could
- * be hacked further relatively easily to deal with cases as we find
- * them. Initially this is to cope with OpenBSD. */
-#if defined(__OpenBSD__) || defined(__NetBSD__)
-# ifdef DL_LAZY
-# define DLOPEN_FLAG DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define DLOPEN_FLAG RTLD_NOW
-# else
-# define DLOPEN_FLAG 0
-# endif
-# endif
-#else
-# ifdef OPENSSL_SYS_SUNOS
-# define DLOPEN_FLAG 1
-# else
-# define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */
-# endif
-#endif
-
-/* For this DSO_METHOD, our meth_data STACK will contain;
- * (i) the handle (void*) returned from dlopen().
- */
-
-static int dlfcn_load(DSO *dso)
- {
- void *ptr = NULL;
- /* See applicable comments in dso_dl.c */
- char *filename = DSO_convert_filename(dso, NULL);
- int flags = DLOPEN_FLAG;
-
- if(filename == NULL)
- {
- DSOerr(DSO_F_DLFCN_LOAD,DSO_R_NO_FILENAME);
- goto err;
- }
-
-#ifdef RTLD_GLOBAL
- if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS)
- flags |= RTLD_GLOBAL;
-#endif
- ptr = dlopen(filename, flags);
- if(ptr == NULL)
- {
- DSOerr(DSO_F_DLFCN_LOAD,DSO_R_LOAD_FAILED);
- ERR_add_error_data(4, "filename(", filename, "): ", dlerror());
- goto err;
- }
- if(!sk_void_push(dso->meth_data, (char *)ptr))
- {
- DSOerr(DSO_F_DLFCN_LOAD,DSO_R_STACK_ERROR);
- goto err;
- }
- /* Success */
- dso->loaded_filename = filename;
- return(1);
-err:
- /* Cleanup! */
- if(filename != NULL)
- OPENSSL_free(filename);
- if(ptr != NULL)
- dlclose(ptr);
- return(0);
-}
-
-static int dlfcn_unload(DSO *dso)
- {
- void *ptr;
- if(dso == NULL)
- {
- DSOerr(DSO_F_DLFCN_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
- return(0);
- }
- if(sk_void_num(dso->meth_data) < 1)
- return(1);
- ptr = sk_void_pop(dso->meth_data);
- if(ptr == NULL)
- {
- DSOerr(DSO_F_DLFCN_UNLOAD,DSO_R_NULL_HANDLE);
- /* Should push the value back onto the stack in
- * case of a retry. */
- sk_void_push(dso->meth_data, ptr);
- return(0);
- }
- /* For now I'm not aware of any errors associated with dlclose() */
- dlclose(ptr);
- return(1);
- }
-
-static void *dlfcn_bind_var(DSO *dso, const char *symname)
- {
- void *ptr, *sym;
-
- if((dso == NULL) || (symname == NULL))
- {
- DSOerr(DSO_F_DLFCN_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER);
- return(NULL);
- }
- if(sk_void_num(dso->meth_data) < 1)
- {
- DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_STACK_ERROR);
- return(NULL);
- }
- ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
- if(ptr == NULL)
- {
- DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_NULL_HANDLE);
- return(NULL);
- }
- sym = dlsym(ptr, symname);
- if(sym == NULL)
- {
- DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_SYM_FAILURE);
- ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
- return(NULL);
- }
- return(sym);
- }
-
-static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
- {
- void *ptr;
- union {
- DSO_FUNC_TYPE sym;
- void *dlret;
- } u;
-
- if((dso == NULL) || (symname == NULL))
- {
- DSOerr(DSO_F_DLFCN_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER);
- return(NULL);
- }
- if(sk_void_num(dso->meth_data) < 1)
- {
- DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_STACK_ERROR);
- return(NULL);
- }
- ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
- if(ptr == NULL)
- {
- DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_NULL_HANDLE);
- return(NULL);
- }
- u.dlret = dlsym(ptr, symname);
- if(u.dlret == NULL)
- {
- DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_SYM_FAILURE);
- ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
- return(NULL);
- }
- return u.sym;
- }
-
-static char *dlfcn_merger(DSO *dso, const char *filespec1,
- const char *filespec2)
- {
- char *merged;
-
- if(!filespec1 && !filespec2)
- {
- DSOerr(DSO_F_DLFCN_MERGER,
- ERR_R_PASSED_NULL_PARAMETER);
- return(NULL);
- }
- /* If the first file specification is a rooted path, it rules.
- same goes if the second file specification is missing. */
- if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/'))
- {
- merged = OPENSSL_malloc(strlen(filespec1) + 1);
- if(!merged)
- {
- DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
- return(NULL);
- }
- strcpy(merged, filespec1);
- }
- /* If the first file specification is missing, the second one rules. */
- else if (!filespec1)
- {
- merged = OPENSSL_malloc(strlen(filespec2) + 1);
- if(!merged)
- {
- DSOerr(DSO_F_DLFCN_MERGER,
- ERR_R_MALLOC_FAILURE);
- return(NULL);
- }
- strcpy(merged, filespec2);
- }
- else
- /* This part isn't as trivial as it looks. It assumes that
- the second file specification really is a directory, and
- makes no checks whatsoever. Therefore, the result becomes
- the concatenation of filespec2 followed by a slash followed
- by filespec1. */
- {
- int spec2len, len;
-
- spec2len = strlen(filespec2);
- len = spec2len + (filespec1 ? strlen(filespec1) : 0);
-
- if(filespec2 && filespec2[spec2len - 1] == '/')
- {
- spec2len--;
- len--;
- }
- merged = OPENSSL_malloc(len + 2);
- if(!merged)
- {
- DSOerr(DSO_F_DLFCN_MERGER,
- ERR_R_MALLOC_FAILURE);
- return(NULL);
- }
- strcpy(merged, filespec2);
- merged[spec2len] = '/';
- strcpy(&merged[spec2len + 1], filespec1);
- }
- return(merged);
- }
-
-#ifdef OPENSSL_SYS_MACOSX
-#define DSO_ext ".dylib"
-#define DSO_extlen 6
-#else
-#define DSO_ext ".so"
-#define DSO_extlen 3
-#endif
-
-
-static char *dlfcn_name_converter(DSO *dso, const char *filename)
- {
- char *translated;
- int len, rsize, transform;
-
- len = strlen(filename);
- rsize = len + 1;
- transform = (strstr(filename, "/") == NULL);
- if(transform)
- {
- /* We will convert this to "%s.so" or "lib%s.so" etc */
- rsize += DSO_extlen; /* The length of ".so" */
- if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
- rsize += 3; /* The length of "lib" */
- }
- translated = OPENSSL_malloc(rsize);
- if(translated == NULL)
- {
- DSOerr(DSO_F_DLFCN_NAME_CONVERTER,
- DSO_R_NAME_TRANSLATION_FAILED);
- return(NULL);
- }
- if(transform)
- {
- if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
- sprintf(translated, "lib%s" DSO_ext, filename);
- else
- sprintf(translated, "%s" DSO_ext, filename);
- }
- else
- sprintf(translated, "%s", filename);
- return(translated);
- }
-
-#ifdef __sgi
-/*
-This is a quote from IRIX manual for dladdr(3c):
-
- <dlfcn.h> does not contain a prototype for dladdr or definition of
- Dl_info. The #include <dlfcn.h> in the SYNOPSIS line is traditional,
- but contains no dladdr prototype and no IRIX library contains an
- implementation. Write your own declaration based on the code below.
-
- The following code is dependent on internal interfaces that are not
- part of the IRIX compatibility guarantee; however, there is no future
- intention to change this interface, so on a practical level, the code
- below is safe to use on IRIX.
-*/
-#include <rld_interface.h>
-#ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
-#define _RLD_INTERFACE_DLFCN_H_DLADDR
-typedef struct Dl_info {
- const char * dli_fname;
- void * dli_fbase;
- const char * dli_sname;
- void * dli_saddr;
- int dli_version;
- int dli_reserved1;
- long dli_reserved[4];
-} Dl_info;
-#else
-typedef struct Dl_info Dl_info;
-#endif
-#define _RLD_DLADDR 14
-
-static int dladdr(void *address, Dl_info *dl)
-{
- void *v;
- v = _rld_new_interface(_RLD_DLADDR,address,dl);
- return (int)v;
-}
-#endif /* __sgi */
-
-static int dlfcn_pathbyaddr(void *addr,char *path,int sz)
- {
-#ifdef HAVE_DLINFO
- Dl_info dli;
- int len;
-
- if (addr == NULL)
- {
- union { int(*f)(void*,char*,int); void *p; } t =
- { dlfcn_pathbyaddr };
- addr = t.p;
- }
-
- if (dladdr(addr,&dli))
- {
- len = (int)strlen(dli.dli_fname);
- if (sz <= 0) return len+1;
- if (len >= sz) len=sz-1;
- memcpy(path,dli.dli_fname,len);
- path[len++]=0;
- return len;
- }
-
- ERR_add_error_data(4, "dlfcn_pathbyaddr(): ", dlerror());
-#endif
- return -1;
- }
-
-static void *dlfcn_globallookup(const char *name)
- {
- void *ret = NULL,*handle = dlopen(NULL,RTLD_LAZY);
-
- if (handle)
- {
- ret = dlsym(handle,name);
- dlclose(handle);
- }
-
- return ret;
- }
-#endif /* DSO_DLFCN */
diff --git a/drivers/builtin_openssl/crypto/dso/dso_vms.c b/drivers/builtin_openssl/crypto/dso/dso_vms.c
deleted file mode 100644
index eee20d14f1..0000000000
--- a/drivers/builtin_openssl/crypto/dso/dso_vms.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/* dso_vms.c -*- mode:C; c-file-style: "eay" -*- */
-/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
- * project 2000.
- */
-/* ====================================================================
- * Copyright (c) 2000 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include "cryptlib.h"
-#include <openssl/dso.h>
-#ifdef OPENSSL_SYS_VMS
-#pragma message disable DOLLARID
-#include <rms.h>
-#include <lib$routines.h>
-#include <stsdef.h>
-#include <descrip.h>
-#include <starlet.h>
-#include "vms_rms.h"
-#endif
-
-/* Some compiler options may mask the declaration of "_malloc32". */
-#if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE
-# if __INITIAL_POINTER_SIZE == 64
-# pragma pointer_size save
-# pragma pointer_size 32
- void * _malloc32 (__size_t);
-# pragma pointer_size restore
-# endif /* __INITIAL_POINTER_SIZE == 64 */
-#endif /* __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE */
-
-
-#ifndef OPENSSL_SYS_VMS
-DSO_METHOD *DSO_METHOD_vms(void)
- {
- return NULL;
- }
-#else
-#pragma message disable DOLLARID
-
-static int vms_load(DSO *dso);
-static int vms_unload(DSO *dso);
-static void *vms_bind_var(DSO *dso, const char *symname);
-static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname);
-#if 0
-static int vms_unbind_var(DSO *dso, char *symname, void *symptr);
-static int vms_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
-static int vms_init(DSO *dso);
-static int vms_finish(DSO *dso);
-static long vms_ctrl(DSO *dso, int cmd, long larg, void *parg);
-#endif
-static char *vms_name_converter(DSO *dso, const char *filename);
-static char *vms_merger(DSO *dso, const char *filespec1,
- const char *filespec2);
-
-static DSO_METHOD dso_meth_vms = {
- "OpenSSL 'VMS' shared library method",
- vms_load,
- NULL, /* unload */
- vms_bind_var,
- vms_bind_func,
-/* For now, "unbind" doesn't exist */
-#if 0
- NULL, /* unbind_var */
- NULL, /* unbind_func */
-#endif
- NULL, /* ctrl */
- vms_name_converter,
- vms_merger,
- NULL, /* init */
- NULL /* finish */
- };
-
-/* On VMS, the only "handle" is the file name. LIB$FIND_IMAGE_SYMBOL depends
- * on the reference to the file name being the same for all calls regarding
- * one shared image, so we'll just store it in an instance of the following
- * structure and put a pointer to that instance in the meth_data stack.
- */
-typedef struct dso_internal_st
- {
- /* This should contain the name only, no directory,
- * no extension, nothing but a name. */
- struct dsc$descriptor_s filename_dsc;
- char filename[ NAMX_MAXRSS+ 1];
- /* This contains whatever is not in filename, if needed.
- * Normally not defined. */
- struct dsc$descriptor_s imagename_dsc;
- char imagename[ NAMX_MAXRSS+ 1];
- } DSO_VMS_INTERNAL;
-
-DSO_METHOD *DSO_METHOD_vms(void)
- {
- return(&dso_meth_vms);
- }
-
-static int vms_load(DSO *dso)
- {
- void *ptr = NULL;
- /* See applicable comments in dso_dl.c */
- char *filename = DSO_convert_filename(dso, NULL);
-
-/* Ensure 32-bit pointer for "p", and appropriate malloc() function. */
-#if __INITIAL_POINTER_SIZE == 64
-# define DSO_MALLOC _malloc32
-# pragma pointer_size save
-# pragma pointer_size 32
-#else /* __INITIAL_POINTER_SIZE == 64 */
-# define DSO_MALLOC OPENSSL_malloc
-#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
-
- DSO_VMS_INTERNAL *p = NULL;
-
-#if __INITIAL_POINTER_SIZE == 64
-# pragma pointer_size restore
-#endif /* __INITIAL_POINTER_SIZE == 64 */
-
- const char *sp1, *sp2; /* Search result */
-
- if(filename == NULL)
- {
- DSOerr(DSO_F_VMS_LOAD,DSO_R_NO_FILENAME);
- goto err;
- }
-
- /* A file specification may look like this:
- *
- * node::dev:[dir-spec]name.type;ver
- *
- * or (for compatibility with TOPS-20):
- *
- * node::dev:<dir-spec>name.type;ver
- *
- * and the dir-spec uses '.' as separator. Also, a dir-spec
- * may consist of several parts, with mixed use of [] and <>:
- *
- * [dir1.]<dir2>
- *
- * We need to split the file specification into the name and
- * the rest (both before and after the name itself).
- */
- /* Start with trying to find the end of a dir-spec, and save the
- position of the byte after in sp1 */
- sp1 = strrchr(filename, ']');
- sp2 = strrchr(filename, '>');
- if (sp1 == NULL) sp1 = sp2;
- if (sp2 != NULL && sp2 > sp1) sp1 = sp2;
- if (sp1 == NULL) sp1 = strrchr(filename, ':');
- if (sp1 == NULL)
- sp1 = filename;
- else
- sp1++; /* The byte after the found character */
- /* Now, let's see if there's a type, and save the position in sp2 */
- sp2 = strchr(sp1, '.');
- /* If we found it, that's where we'll cut. Otherwise, look for a
- version number and save the position in sp2 */
- if (sp2 == NULL) sp2 = strchr(sp1, ';');
- /* If there was still nothing to find, set sp2 to point at the end of
- the string */
- if (sp2 == NULL) sp2 = sp1 + strlen(sp1);
-
- /* Check that we won't get buffer overflows */
- if (sp2 - sp1 > FILENAME_MAX
- || (sp1 - filename) + strlen(sp2) > FILENAME_MAX)
- {
- DSOerr(DSO_F_VMS_LOAD,DSO_R_FILENAME_TOO_BIG);
- goto err;
- }
-
- p = DSO_MALLOC(sizeof(DSO_VMS_INTERNAL));
- if(p == NULL)
- {
- DSOerr(DSO_F_VMS_LOAD,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- strncpy(p->filename, sp1, sp2-sp1);
- p->filename[sp2-sp1] = '\0';
-
- strncpy(p->imagename, filename, sp1-filename);
- p->imagename[sp1-filename] = '\0';
- strcat(p->imagename, sp2);
-
- p->filename_dsc.dsc$w_length = strlen(p->filename);
- p->filename_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
- p->filename_dsc.dsc$b_class = DSC$K_CLASS_S;
- p->filename_dsc.dsc$a_pointer = p->filename;
- p->imagename_dsc.dsc$w_length = strlen(p->imagename);
- p->imagename_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
- p->imagename_dsc.dsc$b_class = DSC$K_CLASS_S;
- p->imagename_dsc.dsc$a_pointer = p->imagename;
-
- if(!sk_void_push(dso->meth_data, (char *)p))
- {
- DSOerr(DSO_F_VMS_LOAD,DSO_R_STACK_ERROR);
- goto err;
- }
-
- /* Success (for now, we lie. We actually do not know...) */
- dso->loaded_filename = filename;
- return(1);
-err:
- /* Cleanup! */
- if(p != NULL)
- OPENSSL_free(p);
- if(filename != NULL)
- OPENSSL_free(filename);
- return(0);
- }
-
-/* Note that this doesn't actually unload the shared image, as there is no
- * such thing in VMS. Next time it get loaded again, a new copy will
- * actually be loaded.
- */
-static int vms_unload(DSO *dso)
- {
- DSO_VMS_INTERNAL *p;
- if(dso == NULL)
- {
- DSOerr(DSO_F_VMS_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
- return(0);
- }
- if(sk_void_num(dso->meth_data) < 1)
- return(1);
- p = (DSO_VMS_INTERNAL *)sk_void_pop(dso->meth_data);
- if(p == NULL)
- {
- DSOerr(DSO_F_VMS_UNLOAD,DSO_R_NULL_HANDLE);
- return(0);
- }
- /* Cleanup */
- OPENSSL_free(p);
- return(1);
- }
-
-/* We must do this in a separate function because of the way the exception
- handler works (it makes this function return */
-static int do_find_symbol(DSO_VMS_INTERNAL *ptr,
- struct dsc$descriptor_s *symname_dsc, void **sym,
- unsigned long flags)
- {
- /* Make sure that signals are caught and returned instead of
- aborting the program. The exception handler gets unestablished
- automatically on return from this function. */
- lib$establish(lib$sig_to_ret);
-
- if(ptr->imagename_dsc.dsc$w_length)
- return lib$find_image_symbol(&ptr->filename_dsc,
- symname_dsc, sym,
- &ptr->imagename_dsc, flags);
- else
- return lib$find_image_symbol(&ptr->filename_dsc,
- symname_dsc, sym,
- 0, flags);
- }
-
-void vms_bind_sym(DSO *dso, const char *symname, void **sym)
- {
- DSO_VMS_INTERNAL *ptr;
- int status;
-#if 0
- int flags = (1<<4); /* LIB$M_FIS_MIXEDCASE, but this symbol isn't
- defined in VMS older than 7.0 or so */
-#else
- int flags = 0;
-#endif
- struct dsc$descriptor_s symname_dsc;
-
-/* Arrange 32-bit pointer to (copied) string storage, if needed. */
-#if __INITIAL_POINTER_SIZE == 64
-# define SYMNAME symname_32p
-# pragma pointer_size save
-# pragma pointer_size 32
- char *symname_32p;
-# pragma pointer_size restore
- char symname_32[ NAMX_MAXRSS+ 1];
-#else /* __INITIAL_POINTER_SIZE == 64 */
-# define SYMNAME ((char *) symname)
-#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
-
- *sym = NULL;
-
- if((dso == NULL) || (symname == NULL))
- {
- DSOerr(DSO_F_VMS_BIND_SYM,ERR_R_PASSED_NULL_PARAMETER);
- return;
- }
-
-#if __INITIAL_POINTER_SIZE == 64
- /* Copy the symbol name to storage with a 32-bit pointer. */
- symname_32p = symname_32;
- strcpy( symname_32p, symname);
-#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
-
- symname_dsc.dsc$w_length = strlen(SYMNAME);
- symname_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
- symname_dsc.dsc$b_class = DSC$K_CLASS_S;
- symname_dsc.dsc$a_pointer = SYMNAME;
-
- if(sk_void_num(dso->meth_data) < 1)
- {
- DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_STACK_ERROR);
- return;
- }
- ptr = (DSO_VMS_INTERNAL *)sk_void_value(dso->meth_data,
- sk_void_num(dso->meth_data) - 1);
- if(ptr == NULL)
- {
- DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_NULL_HANDLE);
- return;
- }
-
- if(dso->flags & DSO_FLAG_UPCASE_SYMBOL) flags = 0;
-
- status = do_find_symbol(ptr, &symname_dsc, sym, flags);
-
- if(!$VMS_STATUS_SUCCESS(status))
- {
- unsigned short length;
- char errstring[257];
- struct dsc$descriptor_s errstring_dsc;
-
- errstring_dsc.dsc$w_length = sizeof(errstring);
- errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
- errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
- errstring_dsc.dsc$a_pointer = errstring;
-
- *sym = NULL;
-
- status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
-
- if (!$VMS_STATUS_SUCCESS(status))
- lib$signal(status); /* This is really bad. Abort! */
- else
- {
- errstring[length] = '\0';
-
- DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_SYM_FAILURE);
- if (ptr->imagename_dsc.dsc$w_length)
- ERR_add_error_data(9,
- "Symbol ", symname,
- " in ", ptr->filename,
- " (", ptr->imagename, ")",
- ": ", errstring);
- else
- ERR_add_error_data(6,
- "Symbol ", symname,
- " in ", ptr->filename,
- ": ", errstring);
- }
- return;
- }
- return;
- }
-
-static void *vms_bind_var(DSO *dso, const char *symname)
- {
- void *sym = 0;
- vms_bind_sym(dso, symname, &sym);
- return sym;
- }
-
-static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname)
- {
- DSO_FUNC_TYPE sym = 0;
- vms_bind_sym(dso, symname, (void **)&sym);
- return sym;
- }
-
-
-static char *vms_merger(DSO *dso, const char *filespec1, const char *filespec2)
- {
- int status;
- int filespec1len, filespec2len;
- struct FAB fab;
- struct NAMX_STRUCT nam;
- char esa[ NAMX_MAXRSS+ 1];
- char *merged;
-
-/* Arrange 32-bit pointer to (copied) string storage, if needed. */
-#if __INITIAL_POINTER_SIZE == 64
-# define FILESPEC1 filespec1_32p;
-# define FILESPEC2 filespec2_32p;
-# pragma pointer_size save
-# pragma pointer_size 32
- char *filespec1_32p;
- char *filespec2_32p;
-# pragma pointer_size restore
- char filespec1_32[ NAMX_MAXRSS+ 1];
- char filespec2_32[ NAMX_MAXRSS+ 1];
-#else /* __INITIAL_POINTER_SIZE == 64 */
-# define FILESPEC1 ((char *) filespec1)
-# define FILESPEC2 ((char *) filespec2)
-#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
-
- if (!filespec1) filespec1 = "";
- if (!filespec2) filespec2 = "";
- filespec1len = strlen(filespec1);
- filespec2len = strlen(filespec2);
-
-#if __INITIAL_POINTER_SIZE == 64
- /* Copy the file names to storage with a 32-bit pointer. */
- filespec1_32p = filespec1_32;
- filespec2_32p = filespec2_32;
- strcpy( filespec1_32p, filespec1);
- strcpy( filespec2_32p, filespec2);
-#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
-
- fab = cc$rms_fab;
- nam = CC_RMS_NAMX;
-
- FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = FILESPEC1;
- FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = filespec1len;
- FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = FILESPEC2;
- FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = filespec2len;
- NAMX_DNA_FNA_SET( fab)
-
- nam.NAMX_ESA = esa;
- nam.NAMX_ESS = NAMX_MAXRSS;
- nam.NAMX_NOP = NAM$M_SYNCHK | NAM$M_PWD;
- SET_NAMX_NO_SHORT_UPCASE( nam);
-
- fab.FAB_NAMX = &nam;
-
- status = sys$parse(&fab, 0, 0);
-
- if(!$VMS_STATUS_SUCCESS(status))
- {
- unsigned short length;
- char errstring[257];
- struct dsc$descriptor_s errstring_dsc;
-
- errstring_dsc.dsc$w_length = sizeof(errstring);
- errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
- errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
- errstring_dsc.dsc$a_pointer = errstring;
-
- status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
-
- if (!$VMS_STATUS_SUCCESS(status))
- lib$signal(status); /* This is really bad. Abort! */
- else
- {
- errstring[length] = '\0';
-
- DSOerr(DSO_F_VMS_MERGER,DSO_R_FAILURE);
- ERR_add_error_data(7,
- "filespec \"", filespec1, "\", ",
- "defaults \"", filespec2, "\": ",
- errstring);
- }
- return(NULL);
- }
-
- merged = OPENSSL_malloc( nam.NAMX_ESL+ 1);
- if(!merged)
- goto malloc_err;
- strncpy( merged, nam.NAMX_ESA, nam.NAMX_ESL);
- merged[ nam.NAMX_ESL] = '\0';
- return(merged);
- malloc_err:
- DSOerr(DSO_F_VMS_MERGER,
- ERR_R_MALLOC_FAILURE);
- }
-
-static char *vms_name_converter(DSO *dso, const char *filename)
- {
- int len = strlen(filename);
- char *not_translated = OPENSSL_malloc(len+1);
- strcpy(not_translated,filename);
- return(not_translated);
- }
-
-#endif /* OPENSSL_SYS_VMS */
diff --git a/drivers/builtin_openssl/crypto/ec/ec_ameth.c b/drivers/builtin_openssl/crypto/ec/ec_ameth.c
deleted file mode 100644
index 0ce4524076..0000000000
--- a/drivers/builtin_openssl/crypto/ec/ec_ameth.c
+++ /dev/null
@@ -1,660 +0,0 @@
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 2006.
- */
-/* ====================================================================
- * Copyright (c) 2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/x509.h>
-#include <openssl/ec.h>
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_CMS
-#include <openssl/cms.h>
-#endif
-#include "asn1_locl.h"
-
-static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key)
- {
- const EC_GROUP *group;
- int nid;
- if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL)
- {
- ECerr(EC_F_ECKEY_PARAM2TYPE, EC_R_MISSING_PARAMETERS);
- return 0;
- }
- if (EC_GROUP_get_asn1_flag(group)
- && (nid = EC_GROUP_get_curve_name(group)))
- /* we have a 'named curve' => just set the OID */
- {
- *ppval = OBJ_nid2obj(nid);
- *pptype = V_ASN1_OBJECT;
- }
- else /* explicit parameters */
- {
- ASN1_STRING *pstr = NULL;
- pstr = ASN1_STRING_new();
- if (!pstr)
- return 0;
- pstr->length = i2d_ECParameters(ec_key, &pstr->data);
- if (pstr->length <= 0)
- {
- ASN1_STRING_free(pstr);
- ECerr(EC_F_ECKEY_PARAM2TYPE, ERR_R_EC_LIB);
- return 0;
- }
- *ppval = pstr;
- *pptype = V_ASN1_SEQUENCE;
- }
- return 1;
- }
-
-static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
- {
- EC_KEY *ec_key = pkey->pkey.ec;
- void *pval = NULL;
- int ptype;
- unsigned char *penc = NULL, *p;
- int penclen;
-
- if (!eckey_param2type(&ptype, &pval, ec_key))
- {
- ECerr(EC_F_ECKEY_PUB_ENCODE, ERR_R_EC_LIB);
- return 0;
- }
- penclen = i2o_ECPublicKey(ec_key, NULL);
- if (penclen <= 0)
- goto err;
- penc = OPENSSL_malloc(penclen);
- if (!penc)
- goto err;
- p = penc;
- penclen = i2o_ECPublicKey(ec_key, &p);
- if (penclen <= 0)
- goto err;
- if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC),
- ptype, pval, penc, penclen))
- return 1;
- err:
- if (ptype == V_ASN1_OBJECT)
- ASN1_OBJECT_free(pval);
- else
- ASN1_STRING_free(pval);
- if (penc)
- OPENSSL_free(penc);
- return 0;
- }
-
-static EC_KEY *eckey_type2param(int ptype, void *pval)
- {
- EC_KEY *eckey = NULL;
- if (ptype == V_ASN1_SEQUENCE)
- {
- ASN1_STRING *pstr = pval;
- const unsigned char *pm = NULL;
- int pmlen;
- pm = pstr->data;
- pmlen = pstr->length;
- if (!(eckey = d2i_ECParameters(NULL, &pm, pmlen)))
- {
- ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR);
- goto ecerr;
- }
- }
- else if (ptype == V_ASN1_OBJECT)
- {
- ASN1_OBJECT *poid = pval;
- EC_GROUP *group;
-
- /* type == V_ASN1_OBJECT => the parameters are given
- * by an asn1 OID
- */
- if ((eckey = EC_KEY_new()) == NULL)
- {
- ECerr(EC_F_ECKEY_TYPE2PARAM, ERR_R_MALLOC_FAILURE);
- goto ecerr;
- }
- group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(poid));
- if (group == NULL)
- goto ecerr;
- EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
- if (EC_KEY_set_group(eckey, group) == 0)
- goto ecerr;
- EC_GROUP_free(group);
- }
- else
- {
- ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR);
- goto ecerr;
- }
-
- return eckey;
-
- ecerr:
- if (eckey)
- EC_KEY_free(eckey);
- return NULL;
- }
-
-static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
- {
- const unsigned char *p = NULL;
- void *pval;
- int ptype, pklen;
- EC_KEY *eckey = NULL;
- X509_ALGOR *palg;
-
- if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
- return 0;
- X509_ALGOR_get0(NULL, &ptype, &pval, palg);
-
- eckey = eckey_type2param(ptype, pval);
-
- if (!eckey)
- {
- ECerr(EC_F_ECKEY_PUB_DECODE, ERR_R_EC_LIB);
- return 0;
- }
-
- /* We have parameters now set public key */
- if (!o2i_ECPublicKey(&eckey, &p, pklen))
- {
- ECerr(EC_F_ECKEY_PUB_DECODE, EC_R_DECODE_ERROR);
- goto ecerr;
- }
-
- EVP_PKEY_assign_EC_KEY(pkey, eckey);
- return 1;
-
- ecerr:
- if (eckey)
- EC_KEY_free(eckey);
- return 0;
- }
-
-static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
- {
- int r;
- const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec);
- const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec),
- *pb = EC_KEY_get0_public_key(b->pkey.ec);
- r = EC_POINT_cmp(group, pa, pb, NULL);
- if (r == 0)
- return 1;
- if (r == 1)
- return 0;
- return -2;
- }
-
-static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
- {
- const unsigned char *p = NULL;
- void *pval;
- int ptype, pklen;
- EC_KEY *eckey = NULL;
- X509_ALGOR *palg;
-
- if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8))
- return 0;
- X509_ALGOR_get0(NULL, &ptype, &pval, palg);
-
- eckey = eckey_type2param(ptype, pval);
-
- if (!eckey)
- goto ecliberr;
-
- /* We have parameters now set private key */
- if (!d2i_ECPrivateKey(&eckey, &p, pklen))
- {
- ECerr(EC_F_ECKEY_PRIV_DECODE, EC_R_DECODE_ERROR);
- goto ecerr;
- }
-
- /* calculate public key (if necessary) */
- if (EC_KEY_get0_public_key(eckey) == NULL)
- {
- const BIGNUM *priv_key;
- const EC_GROUP *group;
- EC_POINT *pub_key;
- /* the public key was not included in the SEC1 private
- * key => calculate the public key */
- group = EC_KEY_get0_group(eckey);
- pub_key = EC_POINT_new(group);
- if (pub_key == NULL)
- {
- ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
- goto ecliberr;
- }
- if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group)))
- {
- EC_POINT_free(pub_key);
- ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
- goto ecliberr;
- }
- priv_key = EC_KEY_get0_private_key(eckey);
- if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL))
- {
- EC_POINT_free(pub_key);
- ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
- goto ecliberr;
- }
- if (EC_KEY_set_public_key(eckey, pub_key) == 0)
- {
- EC_POINT_free(pub_key);
- ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
- goto ecliberr;
- }
- EC_POINT_free(pub_key);
- }
-
- EVP_PKEY_assign_EC_KEY(pkey, eckey);
- return 1;
-
- ecliberr:
- ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
- ecerr:
- if (eckey)
- EC_KEY_free(eckey);
- return 0;
- }
-
-static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
-{
- EC_KEY *ec_key;
- unsigned char *ep, *p;
- int eplen, ptype;
- void *pval;
- unsigned int tmp_flags, old_flags;
-
- ec_key = pkey->pkey.ec;
-
- if (!eckey_param2type(&ptype, &pval, ec_key))
- {
- ECerr(EC_F_ECKEY_PRIV_ENCODE, EC_R_DECODE_ERROR);
- return 0;
- }
-
- /* set the private key */
-
- /* do not include the parameters in the SEC1 private key
- * see PKCS#11 12.11 */
- old_flags = EC_KEY_get_enc_flags(ec_key);
- tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS;
- EC_KEY_set_enc_flags(ec_key, tmp_flags);
- eplen = i2d_ECPrivateKey(ec_key, NULL);
- if (!eplen)
- {
- EC_KEY_set_enc_flags(ec_key, old_flags);
- ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
- return 0;
- }
- ep = (unsigned char *) OPENSSL_malloc(eplen);
- if (!ep)
- {
- EC_KEY_set_enc_flags(ec_key, old_flags);
- ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- p = ep;
- if (!i2d_ECPrivateKey(ec_key, &p))
- {
- EC_KEY_set_enc_flags(ec_key, old_flags);
- OPENSSL_free(ep);
- ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
- }
- /* restore old encoding flags */
- EC_KEY_set_enc_flags(ec_key, old_flags);
-
- if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), 0,
- ptype, pval, ep, eplen))
- return 0;
-
- return 1;
-}
-
-static int int_ec_size(const EVP_PKEY *pkey)
- {
- return ECDSA_size(pkey->pkey.ec);
- }
-
-static int ec_bits(const EVP_PKEY *pkey)
- {
- BIGNUM *order = BN_new();
- const EC_GROUP *group;
- int ret;
-
- if (!order)
- {
- ERR_clear_error();
- return 0;
- }
- group = EC_KEY_get0_group(pkey->pkey.ec);
- if (!EC_GROUP_get_order(group, order, NULL))
- {
- ERR_clear_error();
- return 0;
- }
-
- ret = BN_num_bits(order);
- BN_free(order);
- return ret;
- }
-
-static int ec_missing_parameters(const EVP_PKEY *pkey)
- {
- if (EC_KEY_get0_group(pkey->pkey.ec) == NULL)
- return 1;
- return 0;
- }
-
-static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
- {
- EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec));
- if (group == NULL)
- return 0;
- if (EC_KEY_set_group(to->pkey.ec, group) == 0)
- return 0;
- EC_GROUP_free(group);
- return 1;
- }
-
-static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
- {
- const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec),
- *group_b = EC_KEY_get0_group(b->pkey.ec);
- if (EC_GROUP_cmp(group_a, group_b, NULL))
- return 0;
- else
- return 1;
- }
-
-static void int_ec_free(EVP_PKEY *pkey)
- {
- EC_KEY_free(pkey->pkey.ec);
- }
-
-static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype)
- {
- unsigned char *buffer=NULL;
- const char *ecstr;
- size_t buf_len=0, i;
- int ret=0, reason=ERR_R_BIO_LIB;
- BIGNUM *pub_key=NULL, *order=NULL;
- BN_CTX *ctx=NULL;
- const EC_GROUP *group;
- const EC_POINT *public_key;
- const BIGNUM *priv_key;
-
- if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL)
- {
- reason = ERR_R_PASSED_NULL_PARAMETER;
- goto err;
- }
-
- ctx = BN_CTX_new();
- if (ctx == NULL)
- {
- reason = ERR_R_MALLOC_FAILURE;
- goto err;
- }
-
- if (ktype > 0)
- {
- public_key = EC_KEY_get0_public_key(x);
- if ((pub_key = EC_POINT_point2bn(group, public_key,
- EC_KEY_get_conv_form(x), NULL, ctx)) == NULL)
- {
- reason = ERR_R_EC_LIB;
- goto err;
- }
- if (pub_key)
- buf_len = (size_t)BN_num_bytes(pub_key);
- }
-
- if (ktype == 2)
- {
- priv_key = EC_KEY_get0_private_key(x);
- if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len)
- buf_len = i;
- }
- else
- priv_key = NULL;
-
- if (ktype > 0)
- {
- buf_len += 10;
- if ((buffer = OPENSSL_malloc(buf_len)) == NULL)
- {
- reason = ERR_R_MALLOC_FAILURE;
- goto err;
- }
- }
- if (ktype == 2)
- ecstr = "Private-Key";
- else if (ktype == 1)
- ecstr = "Public-Key";
- else
- ecstr = "ECDSA-Parameters";
-
- if (!BIO_indent(bp, off, 128))
- goto err;
- if ((order = BN_new()) == NULL)
- goto err;
- if (!EC_GROUP_get_order(group, order, NULL))
- goto err;
- if (BIO_printf(bp, "%s: (%d bit)\n", ecstr,
- BN_num_bits(order)) <= 0) goto err;
-
- if ((priv_key != NULL) && !ASN1_bn_print(bp, "priv:", priv_key,
- buffer, off))
- goto err;
- if ((pub_key != NULL) && !ASN1_bn_print(bp, "pub: ", pub_key,
- buffer, off))
- goto err;
- if (!ECPKParameters_print(bp, group, off))
- goto err;
- ret=1;
-err:
- if (!ret)
- ECerr(EC_F_DO_EC_KEY_PRINT, reason);
- if (pub_key)
- BN_free(pub_key);
- if (order)
- BN_free(order);
- if (ctx)
- BN_CTX_free(ctx);
- if (buffer != NULL)
- OPENSSL_free(buffer);
- return(ret);
- }
-
-static int eckey_param_decode(EVP_PKEY *pkey,
- const unsigned char **pder, int derlen)
- {
- EC_KEY *eckey;
- if (!(eckey = d2i_ECParameters(NULL, pder, derlen)))
- {
- ECerr(EC_F_ECKEY_PARAM_DECODE, ERR_R_EC_LIB);
- return 0;
- }
- EVP_PKEY_assign_EC_KEY(pkey, eckey);
- return 1;
- }
-
-static int eckey_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
- {
- return i2d_ECParameters(pkey->pkey.ec, pder);
- }
-
-static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx)
- {
- return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0);
- }
-
-static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx)
- {
- return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1);
- }
-
-
-static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx)
- {
- return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2);
- }
-
-static int old_ec_priv_decode(EVP_PKEY *pkey,
- const unsigned char **pder, int derlen)
- {
- EC_KEY *ec;
- if (!(ec = d2i_ECPrivateKey (NULL, pder, derlen)))
- {
- ECerr(EC_F_OLD_EC_PRIV_DECODE, EC_R_DECODE_ERROR);
- return 0;
- }
- EVP_PKEY_assign_EC_KEY(pkey, ec);
- return 1;
- }
-
-static int old_ec_priv_encode(const EVP_PKEY *pkey, unsigned char **pder)
- {
- return i2d_ECPrivateKey(pkey->pkey.ec, pder);
- }
-
-static int ec_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
- {
- switch (op)
- {
- case ASN1_PKEY_CTRL_PKCS7_SIGN:
- if (arg1 == 0)
- {
- int snid, hnid;
- X509_ALGOR *alg1, *alg2;
- PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, &alg1, &alg2);
- if (alg1 == NULL || alg1->algorithm == NULL)
- return -1;
- hnid = OBJ_obj2nid(alg1->algorithm);
- if (hnid == NID_undef)
- return -1;
- if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
- return -1;
- X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
- }
- return 1;
-#ifndef OPENSSL_NO_CMS
- case ASN1_PKEY_CTRL_CMS_SIGN:
- if (arg1 == 0)
- {
- int snid, hnid;
- X509_ALGOR *alg1, *alg2;
- CMS_SignerInfo_get0_algs(arg2, NULL, NULL,
- &alg1, &alg2);
- if (alg1 == NULL || alg1->algorithm == NULL)
- return -1;
- hnid = OBJ_obj2nid(alg1->algorithm);
- if (hnid == NID_undef)
- return -1;
- if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
- return -1;
- X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
- }
- return 1;
-#endif
-
- case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
- *(int *)arg2 = NID_sha1;
- return 2;
-
- default:
- return -2;
-
- }
-
- }
-
-const EVP_PKEY_ASN1_METHOD eckey_asn1_meth =
- {
- EVP_PKEY_EC,
- EVP_PKEY_EC,
- 0,
- "EC",
- "OpenSSL EC algorithm",
-
- eckey_pub_decode,
- eckey_pub_encode,
- eckey_pub_cmp,
- eckey_pub_print,
-
- eckey_priv_decode,
- eckey_priv_encode,
- eckey_priv_print,
-
- int_ec_size,
- ec_bits,
-
- eckey_param_decode,
- eckey_param_encode,
- ec_missing_parameters,
- ec_copy_parameters,
- ec_cmp_parameters,
- eckey_param_print,
- 0,
-
- int_ec_free,
- ec_pkey_ctrl,
- old_ec_priv_decode,
- old_ec_priv_encode
- };
diff --git a/drivers/builtin_openssl/crypto/ec/ec_asn1.c b/drivers/builtin_openssl/crypto/ec/ec_asn1.c
deleted file mode 100644
index 145807b611..0000000000
--- a/drivers/builtin_openssl/crypto/ec/ec_asn1.c
+++ /dev/null
@@ -1,1445 +0,0 @@
-/* crypto/ec/ec_asn1.c */
-/*
- * Written by Nils Larsch for the OpenSSL project.
- */
-/* ====================================================================
- * Copyright (c) 2000-2003 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <string.h>
-#include "ec_lcl.h"
-#include <openssl/err.h>
-#include <openssl/asn1t.h>
-#include <openssl/objects.h>
-
-
-int EC_GROUP_get_basis_type(const EC_GROUP *group)
- {
- int i=0;
-
- if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
- NID_X9_62_characteristic_two_field)
- /* everything else is currently not supported */
- return 0;
-
- while (group->poly[i] != 0)
- i++;
-
- if (i == 4)
- return NID_X9_62_ppBasis;
- else if (i == 2)
- return NID_X9_62_tpBasis;
- else
- /* everything else is currently not supported */
- return 0;
- }
-#ifndef OPENSSL_NO_EC2M
-int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k)
- {
- if (group == NULL)
- return 0;
-
- if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
- NID_X9_62_characteristic_two_field
- || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] == 0)))
- {
- ECerr(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
-
- if (k)
- *k = group->poly[1];
-
- return 1;
- }
-int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1,
- unsigned int *k2, unsigned int *k3)
- {
- if (group == NULL)
- return 0;
-
- if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
- NID_X9_62_characteristic_two_field
- || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] != 0) && (group->poly[3] != 0) && (group->poly[4] == 0)))
- {
- ECerr(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
-
- if (k1)
- *k1 = group->poly[3];
- if (k2)
- *k2 = group->poly[2];
- if (k3)
- *k3 = group->poly[1];
-
- return 1;
- }
-#endif
-
-
-/* some structures needed for the asn1 encoding */
-typedef struct x9_62_pentanomial_st {
- long k1;
- long k2;
- long k3;
- } X9_62_PENTANOMIAL;
-
-typedef struct x9_62_characteristic_two_st {
- long m;
- ASN1_OBJECT *type;
- union {
- char *ptr;
- /* NID_X9_62_onBasis */
- ASN1_NULL *onBasis;
- /* NID_X9_62_tpBasis */
- ASN1_INTEGER *tpBasis;
- /* NID_X9_62_ppBasis */
- X9_62_PENTANOMIAL *ppBasis;
- /* anything else */
- ASN1_TYPE *other;
- } p;
- } X9_62_CHARACTERISTIC_TWO;
-
-typedef struct x9_62_fieldid_st {
- ASN1_OBJECT *fieldType;
- union {
- char *ptr;
- /* NID_X9_62_prime_field */
- ASN1_INTEGER *prime;
- /* NID_X9_62_characteristic_two_field */
- X9_62_CHARACTERISTIC_TWO *char_two;
- /* anything else */
- ASN1_TYPE *other;
- } p;
- } X9_62_FIELDID;
-
-typedef struct x9_62_curve_st {
- ASN1_OCTET_STRING *a;
- ASN1_OCTET_STRING *b;
- ASN1_BIT_STRING *seed;
- } X9_62_CURVE;
-
-typedef struct ec_parameters_st {
- long version;
- X9_62_FIELDID *fieldID;
- X9_62_CURVE *curve;
- ASN1_OCTET_STRING *base;
- ASN1_INTEGER *order;
- ASN1_INTEGER *cofactor;
- } ECPARAMETERS;
-
-struct ecpk_parameters_st {
- int type;
- union {
- ASN1_OBJECT *named_curve;
- ECPARAMETERS *parameters;
- ASN1_NULL *implicitlyCA;
- } value;
- }/* ECPKPARAMETERS */;
-
-/* SEC1 ECPrivateKey */
-typedef struct ec_privatekey_st {
- long version;
- ASN1_OCTET_STRING *privateKey;
- ECPKPARAMETERS *parameters;
- ASN1_BIT_STRING *publicKey;
- } EC_PRIVATEKEY;
-
-/* the OpenSSL ASN.1 definitions */
-ASN1_SEQUENCE(X9_62_PENTANOMIAL) = {
- ASN1_SIMPLE(X9_62_PENTANOMIAL, k1, LONG),
- ASN1_SIMPLE(X9_62_PENTANOMIAL, k2, LONG),
- ASN1_SIMPLE(X9_62_PENTANOMIAL, k3, LONG)
-} ASN1_SEQUENCE_END(X9_62_PENTANOMIAL)
-
-DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL)
-IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL)
-
-ASN1_ADB_TEMPLATE(char_two_def) = ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.other, ASN1_ANY);
-
-ASN1_ADB(X9_62_CHARACTERISTIC_TWO) = {
- ADB_ENTRY(NID_X9_62_onBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.onBasis, ASN1_NULL)),
- ADB_ENTRY(NID_X9_62_tpBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.tpBasis, ASN1_INTEGER)),
- ADB_ENTRY(NID_X9_62_ppBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.ppBasis, X9_62_PENTANOMIAL))
-} ASN1_ADB_END(X9_62_CHARACTERISTIC_TWO, 0, type, 0, &char_two_def_tt, NULL);
-
-ASN1_SEQUENCE(X9_62_CHARACTERISTIC_TWO) = {
- ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, m, LONG),
- ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, type, ASN1_OBJECT),
- ASN1_ADB_OBJECT(X9_62_CHARACTERISTIC_TWO)
-} ASN1_SEQUENCE_END(X9_62_CHARACTERISTIC_TWO)
-
-DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO)
-IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO)
-
-ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY);
-
-ASN1_ADB(X9_62_FIELDID) = {
- ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)),
- ADB_ENTRY(NID_X9_62_characteristic_two_field, ASN1_SIMPLE(X9_62_FIELDID, p.char_two, X9_62_CHARACTERISTIC_TWO))
-} ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL);
-
-ASN1_SEQUENCE(X9_62_FIELDID) = {
- ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT),
- ASN1_ADB_OBJECT(X9_62_FIELDID)
-} ASN1_SEQUENCE_END(X9_62_FIELDID)
-
-ASN1_SEQUENCE(X9_62_CURVE) = {
- ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING),
- ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING),
- ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING)
-} ASN1_SEQUENCE_END(X9_62_CURVE)
-
-ASN1_SEQUENCE(ECPARAMETERS) = {
- ASN1_SIMPLE(ECPARAMETERS, version, LONG),
- ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID),
- ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE),
- ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING),
- ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER),
- ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER)
-} ASN1_SEQUENCE_END(ECPARAMETERS)
-
-DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS)
-IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS)
-
-ASN1_CHOICE(ECPKPARAMETERS) = {
- ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT),
- ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS),
- ASN1_SIMPLE(ECPKPARAMETERS, value.implicitlyCA, ASN1_NULL)
-} ASN1_CHOICE_END(ECPKPARAMETERS)
-
-DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS)
-DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS)
-IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS)
-
-ASN1_SEQUENCE(EC_PRIVATEKEY) = {
- ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG),
- ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING),
- ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0),
- ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1)
-} ASN1_SEQUENCE_END(EC_PRIVATEKEY)
-
-DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY)
-DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY)
-IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY)
-
-/* some declarations of internal function */
-
-/* ec_asn1_group2field() sets the values in a X9_62_FIELDID object */
-static int ec_asn1_group2fieldid(const EC_GROUP *, X9_62_FIELDID *);
-/* ec_asn1_group2curve() sets the values in a X9_62_CURVE object */
-static int ec_asn1_group2curve(const EC_GROUP *, X9_62_CURVE *);
-/* ec_asn1_parameters2group() creates a EC_GROUP object from a
- * ECPARAMETERS object */
-static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *);
-/* ec_asn1_group2parameters() creates a ECPARAMETERS object from a
- * EC_GROUP object */
-static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *,ECPARAMETERS *);
-/* ec_asn1_pkparameters2group() creates a EC_GROUP object from a
- * ECPKPARAMETERS object */
-static EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *);
-/* ec_asn1_group2pkparameters() creates a ECPKPARAMETERS object from a
- * EC_GROUP object */
-static ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *,
- ECPKPARAMETERS *);
-
-
-/* the function definitions */
-
-static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
- {
- int ok=0, nid;
- BIGNUM *tmp = NULL;
-
- if (group == NULL || field == NULL)
- return 0;
-
- /* clear the old values (if necessary) */
- if (field->fieldType != NULL)
- ASN1_OBJECT_free(field->fieldType);
- if (field->p.other != NULL)
- ASN1_TYPE_free(field->p.other);
-
- nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
- /* set OID for the field */
- if ((field->fieldType = OBJ_nid2obj(nid)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB);
- goto err;
- }
-
- if (nid == NID_X9_62_prime_field)
- {
- if ((tmp = BN_new()) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- /* the parameters are specified by the prime number p */
- if (!EC_GROUP_get_curve_GFp(group, tmp, NULL, NULL, NULL))
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB);
- goto err;
- }
- /* set the prime number */
- field->p.prime = BN_to_ASN1_INTEGER(tmp,NULL);
- if (field->p.prime == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB);
- goto err;
- }
- }
- else /* nid == NID_X9_62_characteristic_two_field */
-#ifdef OPENSSL_NO_EC2M
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_GF2M_NOT_SUPPORTED);
- goto err;
- }
-#else
- {
- int field_type;
- X9_62_CHARACTERISTIC_TWO *char_two;
-
- field->p.char_two = X9_62_CHARACTERISTIC_TWO_new();
- char_two = field->p.char_two;
-
- if (char_two == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- char_two->m = (long)EC_GROUP_get_degree(group);
-
- field_type = EC_GROUP_get_basis_type(group);
-
- if (field_type == 0)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB);
- goto err;
- }
- /* set base type OID */
- if ((char_two->type = OBJ_nid2obj(field_type)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB);
- goto err;
- }
-
- if (field_type == NID_X9_62_tpBasis)
- {
- unsigned int k;
-
- if (!EC_GROUP_get_trinomial_basis(group, &k))
- goto err;
-
- char_two->p.tpBasis = ASN1_INTEGER_new();
- if (!char_two->p.tpBasis)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (!ASN1_INTEGER_set(char_two->p.tpBasis, (long)k))
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID,
- ERR_R_ASN1_LIB);
- goto err;
- }
- }
- else if (field_type == NID_X9_62_ppBasis)
- {
- unsigned int k1, k2, k3;
-
- if (!EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3))
- goto err;
-
- char_two->p.ppBasis = X9_62_PENTANOMIAL_new();
- if (!char_two->p.ppBasis)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* set k? values */
- char_two->p.ppBasis->k1 = (long)k1;
- char_two->p.ppBasis->k2 = (long)k2;
- char_two->p.ppBasis->k3 = (long)k3;
- }
- else /* field_type == NID_X9_62_onBasis */
- {
- /* for ONB the parameters are (asn1) NULL */
- char_two->p.onBasis = ASN1_NULL_new();
- if (!char_two->p.onBasis)
- {
- ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- }
- }
-#endif
-
- ok = 1;
-
-err : if (tmp)
- BN_free(tmp);
- return(ok);
-}
-
-static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve)
- {
- int ok=0, nid;
- BIGNUM *tmp_1=NULL, *tmp_2=NULL;
- unsigned char *buffer_1=NULL, *buffer_2=NULL,
- *a_buf=NULL, *b_buf=NULL;
- size_t len_1, len_2;
- unsigned char char_zero = 0;
-
- if (!group || !curve || !curve->a || !curve->b)
- return 0;
-
- if ((tmp_1 = BN_new()) == NULL || (tmp_2 = BN_new()) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
-
- /* get a and b */
- if (nid == NID_X9_62_prime_field)
- {
- if (!EC_GROUP_get_curve_GFp(group, NULL, tmp_1, tmp_2, NULL))
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB);
- goto err;
- }
- }
-#ifndef OPENSSL_NO_EC2M
- else /* nid == NID_X9_62_characteristic_two_field */
- {
- if (!EC_GROUP_get_curve_GF2m(group, NULL, tmp_1, tmp_2, NULL))
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB);
- goto err;
- }
- }
-#endif
- len_1 = (size_t)BN_num_bytes(tmp_1);
- len_2 = (size_t)BN_num_bytes(tmp_2);
-
- if (len_1 == 0)
- {
- /* len_1 == 0 => a == 0 */
- a_buf = &char_zero;
- len_1 = 1;
- }
- else
- {
- if ((buffer_1 = OPENSSL_malloc(len_1)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if ( (len_1 = BN_bn2bin(tmp_1, buffer_1)) == 0)
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB);
- goto err;
- }
- a_buf = buffer_1;
- }
-
- if (len_2 == 0)
- {
- /* len_2 == 0 => b == 0 */
- b_buf = &char_zero;
- len_2 = 1;
- }
- else
- {
- if ((buffer_2 = OPENSSL_malloc(len_2)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if ( (len_2 = BN_bn2bin(tmp_2, buffer_2)) == 0)
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB);
- goto err;
- }
- b_buf = buffer_2;
- }
-
- /* set a and b */
- if (!M_ASN1_OCTET_STRING_set(curve->a, a_buf, len_1) ||
- !M_ASN1_OCTET_STRING_set(curve->b, b_buf, len_2))
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB);
- goto err;
- }
-
- /* set the seed (optional) */
- if (group->seed)
- {
- if (!curve->seed)
- if ((curve->seed = ASN1_BIT_STRING_new()) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- curve->seed->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
- curve->seed->flags |= ASN1_STRING_FLAG_BITS_LEFT;
- if (!ASN1_BIT_STRING_set(curve->seed, group->seed,
- (int)group->seed_len))
- {
- ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB);
- goto err;
- }
- }
- else
- {
- if (curve->seed)
- {
- ASN1_BIT_STRING_free(curve->seed);
- curve->seed = NULL;
- }
- }
-
- ok = 1;
-
-err: if (buffer_1)
- OPENSSL_free(buffer_1);
- if (buffer_2)
- OPENSSL_free(buffer_2);
- if (tmp_1)
- BN_free(tmp_1);
- if (tmp_2)
- BN_free(tmp_2);
- return(ok);
- }
-
-static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *group,
- ECPARAMETERS *param)
- {
- int ok=0;
- size_t len=0;
- ECPARAMETERS *ret=NULL;
- BIGNUM *tmp=NULL;
- unsigned char *buffer=NULL;
- const EC_POINT *point=NULL;
- point_conversion_form_t form;
-
- if ((tmp = BN_new()) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (param == NULL)
- {
- if ((ret = ECPARAMETERS_new()) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- }
- else
- ret = param;
-
- /* set the version (always one) */
- ret->version = (long)0x1;
-
- /* set the fieldID */
- if (!ec_asn1_group2fieldid(group, ret->fieldID))
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
- goto err;
- }
-
- /* set the curve */
- if (!ec_asn1_group2curve(group, ret->curve))
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
- goto err;
- }
-
- /* set the base point */
- if ((point = EC_GROUP_get0_generator(group)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, EC_R_UNDEFINED_GENERATOR);
- goto err;
- }
-
- form = EC_GROUP_get_point_conversion_form(group);
-
- len = EC_POINT_point2oct(group, point, form, NULL, len, NULL);
- if (len == 0)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
- goto err;
- }
- if ((buffer = OPENSSL_malloc(len)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (!EC_POINT_point2oct(group, point, form, buffer, len, NULL))
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
- goto err;
- }
- if (ret->base == NULL && (ret->base = ASN1_OCTET_STRING_new()) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (!ASN1_OCTET_STRING_set(ret->base, buffer, len))
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
- goto err;
- }
-
- /* set the order */
- if (!EC_GROUP_get_order(group, tmp, NULL))
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
- goto err;
- }
- ret->order = BN_to_ASN1_INTEGER(tmp, ret->order);
- if (ret->order == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
- goto err;
- }
-
- /* set the cofactor (optional) */
- if (EC_GROUP_get_cofactor(group, tmp, NULL))
- {
- ret->cofactor = BN_to_ASN1_INTEGER(tmp, ret->cofactor);
- if (ret->cofactor == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
- goto err;
- }
- }
-
- ok = 1;
-
-err : if(!ok)
- {
- if (ret && !param)
- ECPARAMETERS_free(ret);
- ret = NULL;
- }
- if (tmp)
- BN_free(tmp);
- if (buffer)
- OPENSSL_free(buffer);
- return(ret);
- }
-
-ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *group,
- ECPKPARAMETERS *params)
- {
- int ok = 1, tmp;
- ECPKPARAMETERS *ret = params;
-
- if (ret == NULL)
- {
- if ((ret = ECPKPARAMETERS_new()) == NULL)
- {
- ECerr(EC_F_EC_ASN1_GROUP2PKPARAMETERS,
- ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- }
- else
- {
- if (ret->type == 0 && ret->value.named_curve)
- ASN1_OBJECT_free(ret->value.named_curve);
- else if (ret->type == 1 && ret->value.parameters)
- ECPARAMETERS_free(ret->value.parameters);
- }
-
- if (EC_GROUP_get_asn1_flag(group))
- {
- /* use the asn1 OID to describe the
- * the elliptic curve parameters
- */
- tmp = EC_GROUP_get_curve_name(group);
- if (tmp)
- {
- ret->type = 0;
- if ((ret->value.named_curve = OBJ_nid2obj(tmp)) == NULL)
- ok = 0;
- }
- else
- /* we don't kmow the nid => ERROR */
- ok = 0;
- }
- else
- {
- /* use the ECPARAMETERS structure */
- ret->type = 1;
- if ((ret->value.parameters = ec_asn1_group2parameters(
- group, NULL)) == NULL)
- ok = 0;
- }
-
- if (!ok)
- {
- ECPKPARAMETERS_free(ret);
- return NULL;
- }
- return ret;
- }
-
-static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *params)
- {
- int ok = 0, tmp;
- EC_GROUP *ret = NULL;
- BIGNUM *p = NULL, *a = NULL, *b = NULL;
- EC_POINT *point=NULL;
- long field_bits;
-
- if (!params->fieldID || !params->fieldID->fieldType ||
- !params->fieldID->p.ptr)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
- goto err;
- }
-
- /* now extract the curve parameters a and b */
- if (!params->curve || !params->curve->a ||
- !params->curve->a->data || !params->curve->b ||
- !params->curve->b->data)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
- goto err;
- }
- a = BN_bin2bn(params->curve->a->data, params->curve->a->length, NULL);
- if (a == NULL)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_BN_LIB);
- goto err;
- }
- b = BN_bin2bn(params->curve->b->data, params->curve->b->length, NULL);
- if (b == NULL)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_BN_LIB);
- goto err;
- }
-
- /* get the field parameters */
- tmp = OBJ_obj2nid(params->fieldID->fieldType);
- if (tmp == NID_X9_62_characteristic_two_field)
-#ifdef OPENSSL_NO_EC2M
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_GF2M_NOT_SUPPORTED);
- goto err;
- }
-#else
- {
- X9_62_CHARACTERISTIC_TWO *char_two;
-
- char_two = params->fieldID->p.char_two;
-
- field_bits = char_two->m;
- if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_FIELD_TOO_LARGE);
- goto err;
- }
-
- if ((p = BN_new()) == NULL)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* get the base type */
- tmp = OBJ_obj2nid(char_two->type);
-
- if (tmp == NID_X9_62_tpBasis)
- {
- long tmp_long;
-
- if (!char_two->p.tpBasis)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
- goto err;
- }
-
- tmp_long = ASN1_INTEGER_get(char_two->p.tpBasis);
-
- if (!(char_two->m > tmp_long && tmp_long > 0))
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_TRINOMIAL_BASIS);
- goto err;
- }
-
- /* create the polynomial */
- if (!BN_set_bit(p, (int)char_two->m))
- goto err;
- if (!BN_set_bit(p, (int)tmp_long))
- goto err;
- if (!BN_set_bit(p, 0))
- goto err;
- }
- else if (tmp == NID_X9_62_ppBasis)
- {
- X9_62_PENTANOMIAL *penta;
-
- penta = char_two->p.ppBasis;
- if (!penta)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
- goto err;
- }
-
- if (!(char_two->m > penta->k3 && penta->k3 > penta->k2 && penta->k2 > penta->k1 && penta->k1 > 0))
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_PENTANOMIAL_BASIS);
- goto err;
- }
-
- /* create the polynomial */
- if (!BN_set_bit(p, (int)char_two->m)) goto err;
- if (!BN_set_bit(p, (int)penta->k1)) goto err;
- if (!BN_set_bit(p, (int)penta->k2)) goto err;
- if (!BN_set_bit(p, (int)penta->k3)) goto err;
- if (!BN_set_bit(p, 0)) goto err;
- }
- else if (tmp == NID_X9_62_onBasis)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_NOT_IMPLEMENTED);
- goto err;
- }
- else /* error */
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
- goto err;
- }
-
- /* create the EC_GROUP structure */
- ret = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
- }
-#endif
- else if (tmp == NID_X9_62_prime_field)
- {
- /* we have a curve over a prime field */
- /* extract the prime number */
- if (!params->fieldID->p.prime)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
- goto err;
- }
- p = ASN1_INTEGER_to_BN(params->fieldID->p.prime, NULL);
- if (p == NULL)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
- goto err;
- }
-
- if (BN_is_negative(p) || BN_is_zero(p))
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_FIELD);
- goto err;
- }
-
- field_bits = BN_num_bits(p);
- if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_FIELD_TOO_LARGE);
- goto err;
- }
-
- /* create the EC_GROUP structure */
- ret = EC_GROUP_new_curve_GFp(p, a, b, NULL);
- }
- else
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_FIELD);
- goto err;
- }
-
- if (ret == NULL)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
- goto err;
- }
-
- /* extract seed (optional) */
- if (params->curve->seed != NULL)
- {
- if (ret->seed != NULL)
- OPENSSL_free(ret->seed);
- if (!(ret->seed = OPENSSL_malloc(params->curve->seed->length)))
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- memcpy(ret->seed, params->curve->seed->data,
- params->curve->seed->length);
- ret->seed_len = params->curve->seed->length;
- }
-
- if (!params->order || !params->base || !params->base->data)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
- goto err;
- }
-
- if ((point = EC_POINT_new(ret)) == NULL) goto err;
-
- /* set the point conversion form */
- EC_GROUP_set_point_conversion_form(ret, (point_conversion_form_t)
- (params->base->data[0] & ~0x01));
-
- /* extract the ec point */
- if (!EC_POINT_oct2point(ret, point, params->base->data,
- params->base->length, NULL))
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
- goto err;
- }
-
- /* extract the order */
- if ((a = ASN1_INTEGER_to_BN(params->order, a)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
- goto err;
- }
- if (BN_is_negative(a) || BN_is_zero(a))
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_GROUP_ORDER);
- goto err;
- }
- if (BN_num_bits(a) > (int)field_bits + 1) /* Hasse bound */
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_GROUP_ORDER);
- goto err;
- }
-
- /* extract the cofactor (optional) */
- if (params->cofactor == NULL)
- {
- if (b)
- {
- BN_free(b);
- b = NULL;
- }
- }
- else
- if ((b = ASN1_INTEGER_to_BN(params->cofactor, b)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
- goto err;
- }
- /* set the generator, order and cofactor (if present) */
- if (!EC_GROUP_set_generator(ret, point, a, b))
- {
- ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
- goto err;
- }
-
- ok = 1;
-
-err: if (!ok)
- {
- if (ret)
- EC_GROUP_clear_free(ret);
- ret = NULL;
- }
-
- if (p)
- BN_free(p);
- if (a)
- BN_free(a);
- if (b)
- BN_free(b);
- if (point)
- EC_POINT_free(point);
- return(ret);
-}
-
-EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params)
- {
- EC_GROUP *ret=NULL;
- int tmp=0;
-
- if (params == NULL)
- {
- ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP,
- EC_R_MISSING_PARAMETERS);
- return NULL;
- }
-
- if (params->type == 0)
- { /* the curve is given by an OID */
- tmp = OBJ_obj2nid(params->value.named_curve);
- if ((ret = EC_GROUP_new_by_curve_name(tmp)) == NULL)
- {
- ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP,
- EC_R_EC_GROUP_NEW_BY_NAME_FAILURE);
- return NULL;
- }
- EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_NAMED_CURVE);
- }
- else if (params->type == 1)
- { /* the parameters are given by a ECPARAMETERS
- * structure */
- ret = ec_asn1_parameters2group(params->value.parameters);
- if (!ret)
- {
- ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, ERR_R_EC_LIB);
- return NULL;
- }
- EC_GROUP_set_asn1_flag(ret, 0x0);
- }
- else if (params->type == 2)
- { /* implicitlyCA */
- return NULL;
- }
- else
- {
- ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, EC_R_ASN1_ERROR);
- return NULL;
- }
-
- return ret;
- }
-
-/* EC_GROUP <-> DER encoding of ECPKPARAMETERS */
-
-EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len)
- {
- EC_GROUP *group = NULL;
- ECPKPARAMETERS *params = NULL;
-
- if ((params = d2i_ECPKPARAMETERS(NULL, in, len)) == NULL)
- {
- ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_D2I_ECPKPARAMETERS_FAILURE);
- ECPKPARAMETERS_free(params);
- return NULL;
- }
-
- if ((group = ec_asn1_pkparameters2group(params)) == NULL)
- {
- ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_PKPARAMETERS2GROUP_FAILURE);
- ECPKPARAMETERS_free(params);
- return NULL;
- }
-
-
- if (a && *a)
- EC_GROUP_clear_free(*a);
- if (a)
- *a = group;
-
- ECPKPARAMETERS_free(params);
- return(group);
- }
-
-int i2d_ECPKParameters(const EC_GROUP *a, unsigned char **out)
- {
- int ret=0;
- ECPKPARAMETERS *tmp = ec_asn1_group2pkparameters(a, NULL);
- if (tmp == NULL)
- {
- ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_GROUP2PKPARAMETERS_FAILURE);
- return 0;
- }
- if ((ret = i2d_ECPKPARAMETERS(tmp, out)) == 0)
- {
- ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_I2D_ECPKPARAMETERS_FAILURE);
- ECPKPARAMETERS_free(tmp);
- return 0;
- }
- ECPKPARAMETERS_free(tmp);
- return(ret);
- }
-
-/* some EC_KEY functions */
-
-EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
- {
- int ok=0;
- EC_KEY *ret=NULL;
- EC_PRIVATEKEY *priv_key=NULL;
-
- if ((priv_key = EC_PRIVATEKEY_new()) == NULL)
- {
- ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
-
- if ((priv_key = d2i_EC_PRIVATEKEY(&priv_key, in, len)) == NULL)
- {
- ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
- EC_PRIVATEKEY_free(priv_key);
- return NULL;
- }
-
- if (a == NULL || *a == NULL)
- {
- if ((ret = EC_KEY_new()) == NULL)
- {
- ECerr(EC_F_D2I_ECPRIVATEKEY,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (a)
- *a = ret;
- }
- else
- ret = *a;
-
- if (priv_key->parameters)
- {
- if (ret->group)
- EC_GROUP_clear_free(ret->group);
- ret->group = ec_asn1_pkparameters2group(priv_key->parameters);
- }
-
- if (ret->group == NULL)
- {
- ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
- goto err;
- }
-
- ret->version = priv_key->version;
-
- if (priv_key->privateKey)
- {
- ret->priv_key = BN_bin2bn(
- M_ASN1_STRING_data(priv_key->privateKey),
- M_ASN1_STRING_length(priv_key->privateKey),
- ret->priv_key);
- if (ret->priv_key == NULL)
- {
- ECerr(EC_F_D2I_ECPRIVATEKEY,
- ERR_R_BN_LIB);
- goto err;
- }
- }
- else
- {
- ECerr(EC_F_D2I_ECPRIVATEKEY,
- EC_R_MISSING_PRIVATE_KEY);
- goto err;
- }
-
- if (priv_key->publicKey)
- {
- const unsigned char *pub_oct;
- size_t pub_oct_len;
-
- if (ret->pub_key)
- EC_POINT_clear_free(ret->pub_key);
- ret->pub_key = EC_POINT_new(ret->group);
- if (ret->pub_key == NULL)
- {
- ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
- goto err;
- }
- pub_oct = M_ASN1_STRING_data(priv_key->publicKey);
- pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey);
- /* save the point conversion form */
- ret->conv_form = (point_conversion_form_t)(pub_oct[0] & ~0x01);
- if (!EC_POINT_oct2point(ret->group, ret->pub_key,
- pub_oct, pub_oct_len, NULL))
- {
- ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
- goto err;
- }
- }
-
- ok = 1;
-err:
- if (!ok)
- {
- if (ret)
- EC_KEY_free(ret);
- ret = NULL;
- }
-
- if (priv_key)
- EC_PRIVATEKEY_free(priv_key);
-
- return(ret);
- }
-
-int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out)
- {
- int ret=0, ok=0;
- unsigned char *buffer=NULL;
- size_t buf_len=0, tmp_len;
- EC_PRIVATEKEY *priv_key=NULL;
-
- if (a == NULL || a->group == NULL || a->priv_key == NULL)
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY,
- ERR_R_PASSED_NULL_PARAMETER);
- goto err;
- }
-
- if ((priv_key = EC_PRIVATEKEY_new()) == NULL)
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- priv_key->version = a->version;
-
- buf_len = (size_t)BN_num_bytes(a->priv_key);
- buffer = OPENSSL_malloc(buf_len);
- if (buffer == NULL)
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!BN_bn2bin(a->priv_key, buffer))
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_BN_LIB);
- goto err;
- }
-
- if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len))
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB);
- goto err;
- }
-
- if (!(a->enc_flag & EC_PKEY_NO_PARAMETERS))
- {
- if ((priv_key->parameters = ec_asn1_group2pkparameters(
- a->group, priv_key->parameters)) == NULL)
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
- goto err;
- }
- }
-
- if (!(a->enc_flag & EC_PKEY_NO_PUBKEY))
- {
- priv_key->publicKey = M_ASN1_BIT_STRING_new();
- if (priv_key->publicKey == NULL)
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- tmp_len = EC_POINT_point2oct(a->group, a->pub_key,
- a->conv_form, NULL, 0, NULL);
-
- if (tmp_len > buf_len)
- {
- unsigned char *tmp_buffer = OPENSSL_realloc(buffer, tmp_len);
- if (!tmp_buffer)
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- buffer = tmp_buffer;
- buf_len = tmp_len;
- }
-
- if (!EC_POINT_point2oct(a->group, a->pub_key,
- a->conv_form, buffer, buf_len, NULL))
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
- goto err;
- }
-
- priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
- priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
- if (!M_ASN1_BIT_STRING_set(priv_key->publicKey, buffer,
- buf_len))
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB);
- goto err;
- }
- }
-
- if ((ret = i2d_EC_PRIVATEKEY(priv_key, out)) == 0)
- {
- ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
- goto err;
- }
- ok=1;
-err:
- if (buffer)
- OPENSSL_free(buffer);
- if (priv_key)
- EC_PRIVATEKEY_free(priv_key);
- return(ok?ret:0);
- }
-
-int i2d_ECParameters(EC_KEY *a, unsigned char **out)
- {
- if (a == NULL)
- {
- ECerr(EC_F_I2D_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- return i2d_ECPKParameters(a->group, out);
- }
-
-EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len)
- {
- EC_KEY *ret;
-
- if (in == NULL || *in == NULL)
- {
- ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER);
- return NULL;
- }
-
- if (a == NULL || *a == NULL)
- {
- if ((ret = EC_KEY_new()) == NULL)
- {
- ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- if (a)
- *a = ret;
- }
- else
- ret = *a;
-
- if (!d2i_ECPKParameters(&ret->group, in, len))
- {
- ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_EC_LIB);
- return NULL;
- }
-
- return ret;
- }
-
-EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len)
- {
- EC_KEY *ret=NULL;
-
- if (a == NULL || (*a) == NULL || (*a)->group == NULL)
- {
- /* sorry, but a EC_GROUP-structur is necessary
- * to set the public key */
- ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- ret = *a;
- if (ret->pub_key == NULL &&
- (ret->pub_key = EC_POINT_new(ret->group)) == NULL)
- {
- ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- if (!EC_POINT_oct2point(ret->group, ret->pub_key, *in, len, NULL))
- {
- ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_EC_LIB);
- return 0;
- }
- /* save the point conversion form */
- ret->conv_form = (point_conversion_form_t)(*in[0] & ~0x01);
- *in += len;
- return ret;
- }
-
-int i2o_ECPublicKey(EC_KEY *a, unsigned char **out)
- {
- size_t buf_len=0;
- int new_buffer = 0;
-
- if (a == NULL)
- {
- ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
-
- buf_len = EC_POINT_point2oct(a->group, a->pub_key,
- a->conv_form, NULL, 0, NULL);
-
- if (out == NULL || buf_len == 0)
- /* out == NULL => just return the length of the octet string */
- return buf_len;
-
- if (*out == NULL)
- {
- if ((*out = OPENSSL_malloc(buf_len)) == NULL)
- {
- ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- new_buffer = 1;
- }
- if (!EC_POINT_point2oct(a->group, a->pub_key, a->conv_form,
- *out, buf_len, NULL))
- {
- ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_EC_LIB);
- OPENSSL_free(*out);
- *out = NULL;
- return 0;
- }
- if (!new_buffer)
- *out += buf_len;
- return buf_len;
- }
diff --git a/drivers/builtin_openssl/crypto/ec/ec_lcl.h b/drivers/builtin_openssl/crypto/ec/ec_lcl.h
deleted file mode 100644
index da7967df38..0000000000
--- a/drivers/builtin_openssl/crypto/ec/ec_lcl.h
+++ /dev/null
@@ -1,446 +0,0 @@
-/* crypto/ec/ec_lcl.h */
-/*
- * Originally written by Bodo Moeller for the OpenSSL project.
- */
-/* ====================================================================
- * Copyright (c) 1998-2010 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the OpenSSL open source
- * license provided above.
- *
- * The elliptic curve binary polynomial software is originally written by
- * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
- *
- */
-
-
-#include <stdlib.h>
-
-#include <openssl/obj_mac.h>
-#include <openssl/ec.h>
-#include <openssl/bn.h>
-
-#if defined(__SUNPRO_C)
-# if __SUNPRO_C >= 0x520
-# pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
-# endif
-#endif
-
-/* Use default functions for poin2oct, oct2point and compressed coordinates */
-#define EC_FLAGS_DEFAULT_OCT 0x1
-
-/* Structure details are not part of the exported interface,
- * so all this may change in future versions. */
-
-struct ec_method_st {
- /* Various method flags */
- int flags;
- /* used by EC_METHOD_get_field_type: */
- int field_type; /* a NID */
-
- /* used by EC_GROUP_new, EC_GROUP_free, EC_GROUP_clear_free, EC_GROUP_copy: */
- int (*group_init)(EC_GROUP *);
- void (*group_finish)(EC_GROUP *);
- void (*group_clear_finish)(EC_GROUP *);
- int (*group_copy)(EC_GROUP *, const EC_GROUP *);
-
- /* used by EC_GROUP_set_curve_GFp, EC_GROUP_get_curve_GFp, */
- /* EC_GROUP_set_curve_GF2m, and EC_GROUP_get_curve_GF2m: */
- int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
- int (*group_get_curve)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
-
- /* used by EC_GROUP_get_degree: */
- int (*group_get_degree)(const EC_GROUP *);
-
- /* used by EC_GROUP_check: */
- int (*group_check_discriminant)(const EC_GROUP *, BN_CTX *);
-
- /* used by EC_POINT_new, EC_POINT_free, EC_POINT_clear_free, EC_POINT_copy: */
- int (*point_init)(EC_POINT *);
- void (*point_finish)(EC_POINT *);
- void (*point_clear_finish)(EC_POINT *);
- int (*point_copy)(EC_POINT *, const EC_POINT *);
-
- /* used by EC_POINT_set_to_infinity,
- * EC_POINT_set_Jprojective_coordinates_GFp,
- * EC_POINT_get_Jprojective_coordinates_GFp,
- * EC_POINT_set_affine_coordinates_GFp, ..._GF2m,
- * EC_POINT_get_affine_coordinates_GFp, ..._GF2m,
- * EC_POINT_set_compressed_coordinates_GFp, ..._GF2m:
- */
- int (*point_set_to_infinity)(const EC_GROUP *, EC_POINT *);
- int (*point_set_Jprojective_coordinates_GFp)(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *);
- int (*point_get_Jprojective_coordinates_GFp)(const EC_GROUP *, const EC_POINT *,
- BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *);
- int (*point_set_affine_coordinates)(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, const BIGNUM *y, BN_CTX *);
- int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *,
- BIGNUM *x, BIGNUM *y, BN_CTX *);
- int (*point_set_compressed_coordinates)(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, int y_bit, BN_CTX *);
-
- /* used by EC_POINT_point2oct, EC_POINT_oct2point: */
- size_t (*point2oct)(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *);
- int (*oct2point)(const EC_GROUP *, EC_POINT *,
- const unsigned char *buf, size_t len, BN_CTX *);
-
- /* used by EC_POINT_add, EC_POINT_dbl, ECP_POINT_invert: */
- int (*add)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
- int (*dbl)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
- int (*invert)(const EC_GROUP *, EC_POINT *, BN_CTX *);
-
- /* used by EC_POINT_is_at_infinity, EC_POINT_is_on_curve, EC_POINT_cmp: */
- int (*is_at_infinity)(const EC_GROUP *, const EC_POINT *);
- int (*is_on_curve)(const EC_GROUP *, const EC_POINT *, BN_CTX *);
- int (*point_cmp)(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
-
- /* used by EC_POINT_make_affine, EC_POINTs_make_affine: */
- int (*make_affine)(const EC_GROUP *, EC_POINT *, BN_CTX *);
- int (*points_make_affine)(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
-
- /* used by EC_POINTs_mul, EC_POINT_mul, EC_POINT_precompute_mult, EC_POINT_have_precompute_mult
- * (default implementations are used if the 'mul' pointer is 0): */
- int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
- size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
- int (*precompute_mult)(EC_GROUP *group, BN_CTX *);
- int (*have_precompute_mult)(const EC_GROUP *group);
-
-
- /* internal functions */
-
- /* 'field_mul', 'field_sqr', and 'field_div' can be used by 'add' and 'dbl' so that
- * the same implementations of point operations can be used with different
- * optimized implementations of expensive field operations: */
- int (*field_mul)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
- int (*field_sqr)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
- int (*field_div)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-
- int (*field_encode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); /* e.g. to Montgomery */
- int (*field_decode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); /* e.g. from Montgomery */
- int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *);
-} /* EC_METHOD */;
-
-typedef struct ec_extra_data_st {
- struct ec_extra_data_st *next;
- void *data;
- void *(*dup_func)(void *);
- void (*free_func)(void *);
- void (*clear_free_func)(void *);
-} EC_EXTRA_DATA; /* used in EC_GROUP */
-
-struct ec_group_st {
- const EC_METHOD *meth;
-
- EC_POINT *generator; /* optional */
- BIGNUM order, cofactor;
-
- int curve_name;/* optional NID for named curve */
- int asn1_flag; /* flag to control the asn1 encoding */
- point_conversion_form_t asn1_form;
-
- unsigned char *seed; /* optional seed for parameters (appears in ASN1) */
- size_t seed_len;
-
- EC_EXTRA_DATA *extra_data; /* linked list */
-
- /* The following members are handled by the method functions,
- * even if they appear generic */
-
- BIGNUM field; /* Field specification.
- * For curves over GF(p), this is the modulus;
- * for curves over GF(2^m), this is the
- * irreducible polynomial defining the field.
- */
-
- int poly[6]; /* Field specification for curves over GF(2^m).
- * The irreducible f(t) is then of the form:
- * t^poly[0] + t^poly[1] + ... + t^poly[k]
- * where m = poly[0] > poly[1] > ... > poly[k] = 0.
- * The array is terminated with poly[k+1]=-1.
- * All elliptic curve irreducibles have at most 5
- * non-zero terms.
- */
-
- BIGNUM a, b; /* Curve coefficients.
- * (Here the assumption is that BIGNUMs can be used
- * or abused for all kinds of fields, not just GF(p).)
- * For characteristic > 3, the curve is defined
- * by a Weierstrass equation of the form
- * y^2 = x^3 + a*x + b.
- * For characteristic 2, the curve is defined by
- * an equation of the form
- * y^2 + x*y = x^3 + a*x^2 + b.
- */
-
- int a_is_minus3; /* enable optimized point arithmetics for special case */
-
- void *field_data1; /* method-specific (e.g., Montgomery structure) */
- void *field_data2; /* method-specific */
- int (*field_mod_func)(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); /* method-specific */
-} /* EC_GROUP */;
-
-struct ec_key_st {
- int version;
-
- EC_GROUP *group;
-
- EC_POINT *pub_key;
- BIGNUM *priv_key;
-
- unsigned int enc_flag;
- point_conversion_form_t conv_form;
-
- int references;
- int flags;
-
- EC_EXTRA_DATA *method_data;
-} /* EC_KEY */;
-
-/* Basically a 'mixin' for extra data, but available for EC_GROUPs/EC_KEYs only
- * (with visibility limited to 'package' level for now).
- * We use the function pointers as index for retrieval; this obviates
- * global ex_data-style index tables.
- */
-int EC_EX_DATA_set_data(EC_EXTRA_DATA **, void *data,
- void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
-void *EC_EX_DATA_get_data(const EC_EXTRA_DATA *,
- void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
-void EC_EX_DATA_free_data(EC_EXTRA_DATA **,
- void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
-void EC_EX_DATA_clear_free_data(EC_EXTRA_DATA **,
- void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
-void EC_EX_DATA_free_all_data(EC_EXTRA_DATA **);
-void EC_EX_DATA_clear_free_all_data(EC_EXTRA_DATA **);
-
-
-
-struct ec_point_st {
- const EC_METHOD *meth;
-
- /* All members except 'meth' are handled by the method functions,
- * even if they appear generic */
-
- BIGNUM X;
- BIGNUM Y;
- BIGNUM Z; /* Jacobian projective coordinates:
- * (X, Y, Z) represents (X/Z^2, Y/Z^3) if Z != 0 */
- int Z_is_one; /* enable optimized point arithmetics for special case */
-} /* EC_POINT */;
-
-
-
-/* method functions in ec_mult.c
- * (ec_lib.c uses these as defaults if group->method->mul is 0) */
-int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
- size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
-int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *);
-int ec_wNAF_have_precompute_mult(const EC_GROUP *group);
-
-
-/* method functions in ecp_smpl.c */
-int ec_GFp_simple_group_init(EC_GROUP *);
-void ec_GFp_simple_group_finish(EC_GROUP *);
-void ec_GFp_simple_group_clear_finish(EC_GROUP *);
-int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *);
-int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
-int ec_GFp_simple_group_get_degree(const EC_GROUP *);
-int ec_GFp_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *);
-int ec_GFp_simple_point_init(EC_POINT *);
-void ec_GFp_simple_point_finish(EC_POINT *);
-void ec_GFp_simple_point_clear_finish(EC_POINT *);
-int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *);
-int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
-int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *);
-int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *, const EC_POINT *,
- BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *);
-int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, const BIGNUM *y, BN_CTX *);
-int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *, const EC_POINT *,
- BIGNUM *x, BIGNUM *y, BN_CTX *);
-int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, int y_bit, BN_CTX *);
-size_t ec_GFp_simple_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *);
-int ec_GFp_simple_oct2point(const EC_GROUP *, EC_POINT *,
- const unsigned char *buf, size_t len, BN_CTX *);
-int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
-int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
-int ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
-int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *);
-int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
-int ec_GFp_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
-int ec_GFp_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
-int ec_GFp_simple_points_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
-int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
-
-
-/* method functions in ecp_mont.c */
-int ec_GFp_mont_group_init(EC_GROUP *);
-int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-void ec_GFp_mont_group_finish(EC_GROUP *);
-void ec_GFp_mont_group_clear_finish(EC_GROUP *);
-int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *);
-int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
-int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
-int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
-int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *);
-
-
-/* method functions in ecp_nist.c */
-int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src);
-int ec_GFp_nist_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int ec_GFp_nist_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int ec_GFp_nist_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
-
-
-/* method functions in ec2_smpl.c */
-int ec_GF2m_simple_group_init(EC_GROUP *);
-void ec_GF2m_simple_group_finish(EC_GROUP *);
-void ec_GF2m_simple_group_clear_finish(EC_GROUP *);
-int ec_GF2m_simple_group_copy(EC_GROUP *, const EC_GROUP *);
-int ec_GF2m_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int ec_GF2m_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
-int ec_GF2m_simple_group_get_degree(const EC_GROUP *);
-int ec_GF2m_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *);
-int ec_GF2m_simple_point_init(EC_POINT *);
-void ec_GF2m_simple_point_finish(EC_POINT *);
-void ec_GF2m_simple_point_clear_finish(EC_POINT *);
-int ec_GF2m_simple_point_copy(EC_POINT *, const EC_POINT *);
-int ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
-int ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, const BIGNUM *y, BN_CTX *);
-int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *, const EC_POINT *,
- BIGNUM *x, BIGNUM *y, BN_CTX *);
-int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, int y_bit, BN_CTX *);
-size_t ec_GF2m_simple_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *);
-int ec_GF2m_simple_oct2point(const EC_GROUP *, EC_POINT *,
- const unsigned char *buf, size_t len, BN_CTX *);
-int ec_GF2m_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
-int ec_GF2m_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
-int ec_GF2m_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
-int ec_GF2m_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *);
-int ec_GF2m_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
-int ec_GF2m_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
-int ec_GF2m_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
-int ec_GF2m_simple_points_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
-int ec_GF2m_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int ec_GF2m_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
-int ec_GF2m_simple_field_div(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-
-
-/* method functions in ec2_mult.c */
-int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
- size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
-int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
-int ec_GF2m_have_precompute_mult(const EC_GROUP *group);
-
-/* method functions in ec2_mult.c */
-int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
- size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
-int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
-int ec_GF2m_have_precompute_mult(const EC_GROUP *group);
-
-#ifndef OPENSSL_EC_NISTP_64_GCC_128
-/* method functions in ecp_nistp224.c */
-int ec_GFp_nistp224_group_init(EC_GROUP *group);
-int ec_GFp_nistp224_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
-int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
-int ec_GFp_nistp224_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
-int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
-int ec_GFp_nistp224_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
-int ec_GFp_nistp224_have_precompute_mult(const EC_GROUP *group);
-
-/* method functions in ecp_nistp256.c */
-int ec_GFp_nistp256_group_init(EC_GROUP *group);
-int ec_GFp_nistp256_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
-int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
-int ec_GFp_nistp256_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
-int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
-int ec_GFp_nistp256_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
-int ec_GFp_nistp256_have_precompute_mult(const EC_GROUP *group);
-
-/* method functions in ecp_nistp521.c */
-int ec_GFp_nistp521_group_init(EC_GROUP *group);
-int ec_GFp_nistp521_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
-int ec_GFp_nistp521_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
-int ec_GFp_nistp521_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
-int ec_GFp_nistp521_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
-int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
-int ec_GFp_nistp521_have_precompute_mult(const EC_GROUP *group);
-
-/* utility functions in ecp_nistputil.c */
-void ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
- size_t felem_size, void *tmp_felems,
- void (*felem_one)(void *out),
- int (*felem_is_zero)(const void *in),
- void (*felem_assign)(void *out, const void *in),
- void (*felem_square)(void *out, const void *in),
- void (*felem_mul)(void *out, const void *in1, const void *in2),
- void (*felem_inv)(void *out, const void *in),
- void (*felem_contract)(void *out, const void *in));
-void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign, unsigned char *digit, unsigned char in);
-#endif
diff --git a/drivers/builtin_openssl/crypto/evp/bio_b64.c b/drivers/builtin_openssl/crypto/evp/bio_b64.c
deleted file mode 100644
index ac6d441aad..0000000000
--- a/drivers/builtin_openssl/crypto/evp/bio_b64.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/* crypto/evp/bio_b64.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include "cryptlib.h"
-#include <openssl/buffer.h>
-#include <openssl/evp.h>
-
-static int b64_write(BIO *h, const char *buf, int num);
-static int b64_read(BIO *h, char *buf, int size);
-static int b64_puts(BIO *h, const char *str);
-/*static int b64_gets(BIO *h, char *str, int size); */
-static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2);
-static int b64_new(BIO *h);
-static int b64_free(BIO *data);
-static long b64_callback_ctrl(BIO *h,int cmd,bio_info_cb *fp);
-#define B64_BLOCK_SIZE 1024
-#define B64_BLOCK_SIZE2 768
-#define B64_NONE 0
-#define B64_ENCODE 1
-#define B64_DECODE 2
-
-typedef struct b64_struct
- {
- /*BIO *bio; moved to the BIO structure */
- int buf_len;
- int buf_off;
- int tmp_len; /* used to find the start when decoding */
- int tmp_nl; /* If true, scan until '\n' */
- int encode;
- int start; /* have we started decoding yet? */
- int cont; /* <= 0 when finished */
- EVP_ENCODE_CTX base64;
- char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE)+10];
- char tmp[B64_BLOCK_SIZE];
- } BIO_B64_CTX;
-
-static BIO_METHOD methods_b64=
- {
- BIO_TYPE_BASE64,"base64 encoding",
- b64_write,
- b64_read,
- b64_puts,
- NULL, /* b64_gets, */
- b64_ctrl,
- b64_new,
- b64_free,
- b64_callback_ctrl,
- };
-
-BIO_METHOD *BIO_f_base64(void)
- {
- return(&methods_b64);
- }
-
-static int b64_new(BIO *bi)
- {
- BIO_B64_CTX *ctx;
-
- ctx=(BIO_B64_CTX *)OPENSSL_malloc(sizeof(BIO_B64_CTX));
- if (ctx == NULL) return(0);
-
- ctx->buf_len=0;
- ctx->tmp_len=0;
- ctx->tmp_nl=0;
- ctx->buf_off=0;
- ctx->cont=1;
- ctx->start=1;
- ctx->encode=0;
-
- bi->init=1;
- bi->ptr=(char *)ctx;
- bi->flags=0;
- bi->num = 0;
- return(1);
- }
-
-static int b64_free(BIO *a)
- {
- if (a == NULL) return(0);
- OPENSSL_free(a->ptr);
- a->ptr=NULL;
- a->init=0;
- a->flags=0;
- return(1);
- }
-
-static int b64_read(BIO *b, char *out, int outl)
- {
- int ret=0,i,ii,j,k,x,n,num,ret_code=0;
- BIO_B64_CTX *ctx;
- unsigned char *p,*q;
-
- if (out == NULL) return(0);
- ctx=(BIO_B64_CTX *)b->ptr;
-
- if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
-
- BIO_clear_retry_flags(b);
-
- if (ctx->encode != B64_DECODE)
- {
- ctx->encode=B64_DECODE;
- ctx->buf_len=0;
- ctx->buf_off=0;
- ctx->tmp_len=0;
- EVP_DecodeInit(&(ctx->base64));
- }
-
- /* First check if there are bytes decoded/encoded */
- if (ctx->buf_len > 0)
- {
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- i=ctx->buf_len-ctx->buf_off;
- if (i > outl) i=outl;
- OPENSSL_assert(ctx->buf_off+i < (int)sizeof(ctx->buf));
- memcpy(out,&(ctx->buf[ctx->buf_off]),i);
- ret=i;
- out+=i;
- outl-=i;
- ctx->buf_off+=i;
- if (ctx->buf_len == ctx->buf_off)
- {
- ctx->buf_len=0;
- ctx->buf_off=0;
- }
- }
-
- /* At this point, we have room of outl bytes and an empty
- * buffer, so we should read in some more. */
-
- ret_code=0;
- while (outl > 0)
- {
- if (ctx->cont <= 0)
- break;
-
- i=BIO_read(b->next_bio,&(ctx->tmp[ctx->tmp_len]),
- B64_BLOCK_SIZE-ctx->tmp_len);
-
- if (i <= 0)
- {
- ret_code=i;
-
- /* Should we continue next time we are called? */
- if (!BIO_should_retry(b->next_bio))
- {
- ctx->cont=i;
- /* If buffer empty break */
- if(ctx->tmp_len == 0)
- break;
- /* Fall through and process what we have */
- else
- i = 0;
- }
- /* else we retry and add more data to buffer */
- else
- break;
- }
- i+=ctx->tmp_len;
- ctx->tmp_len = i;
-
- /* We need to scan, a line at a time until we
- * have a valid line if we are starting. */
- if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL))
- {
- /* ctx->start=1; */
- ctx->tmp_len=0;
- }
- else if (ctx->start)
- {
- q=p=(unsigned char *)ctx->tmp;
- for (j=0; j<i; j++)
- {
- if (*(q++) != '\n') continue;
-
- /* due to a previous very long line,
- * we need to keep on scanning for a '\n'
- * before we even start looking for
- * base64 encoded stuff. */
- if (ctx->tmp_nl)
- {
- p=q;
- ctx->tmp_nl=0;
- continue;
- }
-
- k=EVP_DecodeUpdate(&(ctx->base64),
- (unsigned char *)ctx->buf,
- &num,p,q-p);
- if ((k <= 0) && (num == 0) && (ctx->start))
- EVP_DecodeInit(&ctx->base64);
- else
- {
- if (p != (unsigned char *)
- &(ctx->tmp[0]))
- {
- i-=(p- (unsigned char *)
- &(ctx->tmp[0]));
- for (x=0; x < i; x++)
- ctx->tmp[x]=p[x];
- }
- EVP_DecodeInit(&ctx->base64);
- ctx->start=0;
- break;
- }
- p=q;
- }
-
- /* we fell off the end without starting */
- if ((j == i) && (num == 0))
- {
- /* Is this is one long chunk?, if so, keep on
- * reading until a new line. */
- if (p == (unsigned char *)&(ctx->tmp[0]))
- {
- /* Check buffer full */
- if (i == B64_BLOCK_SIZE)
- {
- ctx->tmp_nl=1;
- ctx->tmp_len=0;
- }
- }
- else if (p != q) /* finished on a '\n' */
- {
- n=q-p;
- for (ii=0; ii<n; ii++)
- ctx->tmp[ii]=p[ii];
- ctx->tmp_len=n;
- }
- /* else finished on a '\n' */
- continue;
- }
- else
- {
- ctx->tmp_len=0;
- }
- }
- else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0))
- {
- /* If buffer isn't full and we can retry then
- * restart to read in more data.
- */
- continue;
- }
-
- if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
- {
- int z,jj;
-
-#if 0
- jj=(i>>2)<<2;
-#else
- jj = i & ~3; /* process per 4 */
-#endif
- z=EVP_DecodeBlock((unsigned char *)ctx->buf,
- (unsigned char *)ctx->tmp,jj);
- if (jj > 2)
- {
- if (ctx->tmp[jj-1] == '=')
- {
- z--;
- if (ctx->tmp[jj-2] == '=')
- z--;
- }
- }
- /* z is now number of output bytes and jj is the
- * number consumed */
- if (jj != i)
- {
- memmove(ctx->tmp, &ctx->tmp[jj], i-jj);
- ctx->tmp_len=i-jj;
- }
- ctx->buf_len=0;
- if (z > 0)
- {
- ctx->buf_len=z;
- }
- i=z;
- }
- else
- {
- i=EVP_DecodeUpdate(&(ctx->base64),
- (unsigned char *)ctx->buf,&ctx->buf_len,
- (unsigned char *)ctx->tmp,i);
- ctx->tmp_len = 0;
- }
- ctx->buf_off=0;
- if (i < 0)
- {
- ret_code=0;
- ctx->buf_len=0;
- break;
- }
-
- if (ctx->buf_len <= outl)
- i=ctx->buf_len;
- else
- i=outl;
-
- memcpy(out,ctx->buf,i);
- ret+=i;
- ctx->buf_off=i;
- if (ctx->buf_off == ctx->buf_len)
- {
- ctx->buf_len=0;
- ctx->buf_off=0;
- }
- outl-=i;
- out+=i;
- }
- /* BIO_clear_retry_flags(b); */
- BIO_copy_next_retry(b);
- return((ret == 0)?ret_code:ret);
- }
-
-static int b64_write(BIO *b, const char *in, int inl)
- {
- int ret=0;
- int n;
- int i;
- BIO_B64_CTX *ctx;
-
- ctx=(BIO_B64_CTX *)b->ptr;
- BIO_clear_retry_flags(b);
-
- if (ctx->encode != B64_ENCODE)
- {
- ctx->encode=B64_ENCODE;
- ctx->buf_len=0;
- ctx->buf_off=0;
- ctx->tmp_len=0;
- EVP_EncodeInit(&(ctx->base64));
- }
-
- OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf));
- OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- n=ctx->buf_len-ctx->buf_off;
- while (n > 0)
- {
- i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
- if (i <= 0)
- {
- BIO_copy_next_retry(b);
- return(i);
- }
- OPENSSL_assert(i <= n);
- ctx->buf_off+=i;
- OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- n-=i;
- }
- /* at this point all pending data has been written */
- ctx->buf_off=0;
- ctx->buf_len=0;
-
- if ((in == NULL) || (inl <= 0)) return(0);
-
- while (inl > 0)
- {
- n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl;
-
- if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
- {
- if (ctx->tmp_len > 0)
- {
- OPENSSL_assert(ctx->tmp_len <= 3);
- n=3-ctx->tmp_len;
- /* There's a theoretical possibility for this */
- if (n > inl)
- n=inl;
- memcpy(&(ctx->tmp[ctx->tmp_len]),in,n);
- ctx->tmp_len+=n;
- ret += n;
- if (ctx->tmp_len < 3)
- break;
- ctx->buf_len=EVP_EncodeBlock((unsigned char *)ctx->buf,(unsigned char *)ctx->tmp,ctx->tmp_len);
- OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- /* Since we're now done using the temporary
- buffer, the length should be 0'd */
- ctx->tmp_len=0;
- }
- else
- {
- if (n < 3)
- {
- memcpy(ctx->tmp,in,n);
- ctx->tmp_len=n;
- ret += n;
- break;
- }
- n-=n%3;
- ctx->buf_len=EVP_EncodeBlock((unsigned char *)ctx->buf,(const unsigned char *)in,n);
- OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- ret += n;
- }
- }
- else
- {
- EVP_EncodeUpdate(&(ctx->base64),
- (unsigned char *)ctx->buf,&ctx->buf_len,
- (unsigned char *)in,n);
- OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- ret += n;
- }
- inl-=n;
- in+=n;
-
- ctx->buf_off=0;
- n=ctx->buf_len;
- while (n > 0)
- {
- i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
- if (i <= 0)
- {
- BIO_copy_next_retry(b);
- return((ret == 0)?i:ret);
- }
- OPENSSL_assert(i <= n);
- n-=i;
- ctx->buf_off+=i;
- OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- }
- ctx->buf_len=0;
- ctx->buf_off=0;
- }
- return(ret);
- }
-
-static long b64_ctrl(BIO *b, int cmd, long num, void *ptr)
- {
- BIO_B64_CTX *ctx;
- long ret=1;
- int i;
-
- ctx=(BIO_B64_CTX *)b->ptr;
-
- switch (cmd)
- {
- case BIO_CTRL_RESET:
- ctx->cont=1;
- ctx->start=1;
- ctx->encode=B64_NONE;
- ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
- break;
- case BIO_CTRL_EOF: /* More to read */
- if (ctx->cont <= 0)
- ret=1;
- else
- ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
- break;
- case BIO_CTRL_WPENDING: /* More to write in buffer */
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- ret=ctx->buf_len-ctx->buf_off;
- if ((ret == 0) && (ctx->encode != B64_NONE)
- && (ctx->base64.num != 0))
- ret=1;
- else if (ret <= 0)
- ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
- break;
- case BIO_CTRL_PENDING: /* More to read in buffer */
- OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
- ret=ctx->buf_len-ctx->buf_off;
- if (ret <= 0)
- ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
- break;
- case BIO_CTRL_FLUSH:
- /* do a final write */
-again:
- while (ctx->buf_len != ctx->buf_off)
- {
- i=b64_write(b,NULL,0);
- if (i < 0)
- return i;
- }
- if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
- {
- if (ctx->tmp_len != 0)
- {
- ctx->buf_len=EVP_EncodeBlock(
- (unsigned char *)ctx->buf,
- (unsigned char *)ctx->tmp,
- ctx->tmp_len);
- ctx->buf_off=0;
- ctx->tmp_len=0;
- goto again;
- }
- }
- else if (ctx->encode != B64_NONE && ctx->base64.num != 0)
- {
- ctx->buf_off=0;
- EVP_EncodeFinal(&(ctx->base64),
- (unsigned char *)ctx->buf,
- &(ctx->buf_len));
- /* push out the bytes */
- goto again;
- }
- /* Finally flush the underlying BIO */
- ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
- break;
-
- case BIO_C_DO_STATE_MACHINE:
- BIO_clear_retry_flags(b);
- ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
- BIO_copy_next_retry(b);
- break;
-
- case BIO_CTRL_DUP:
- break;
- case BIO_CTRL_INFO:
- case BIO_CTRL_GET:
- case BIO_CTRL_SET:
- default:
- ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
- break;
- }
- return(ret);
- }
-
-static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
- {
- long ret=1;
-
- if (b->next_bio == NULL) return(0);
- switch (cmd)
- {
- default:
- ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
- break;
- }
- return(ret);
- }
-
-static int b64_puts(BIO *b, const char *str)
- {
- return b64_write(b,str,strlen(str));
- }
diff --git a/drivers/builtin_openssl/crypto/evp/e_dsa.c b/drivers/builtin_openssl/crypto/evp/e_dsa.c
deleted file mode 100644
index 0711d63526..0000000000
--- a/drivers/builtin_openssl/crypto/evp/e_dsa.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* crypto/evp/e_dsa.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/evp.h>
-#include "evp_locl.h"
-#include <openssl/objects.h>
-#include <openssl/x509.h>
-#include <openssl/ossl_typ.h>
-
-static EVP_PKEY_METHOD dss_method=
- {
- DSA_sign,
- DSA_verify,
- {EVP_PKEY_DSA,EVP_PKEY_DSA2,EVP_PKEY_DSA3,NULL},
- };
-
diff --git a/drivers/builtin_openssl/crypto/evp/encode.c b/drivers/builtin_openssl/crypto/evp/encode.c
deleted file mode 100644
index 28546a84bc..0000000000
--- a/drivers/builtin_openssl/crypto/evp/encode.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/* crypto/evp/encode.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/evp.h>
-
-#ifndef CHARSET_EBCDIC
-#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f])
-#define conv_ascii2bin(a) (data_ascii2bin[(a)&0x7f])
-#else
-/* We assume that PEM encoded files are EBCDIC files
- * (i.e., printable text files). Convert them here while decoding.
- * When encoding, output is EBCDIC (text) format again.
- * (No need for conversion in the conv_bin2ascii macro, as the
- * underlying textstring data_bin2ascii[] is already EBCDIC)
- */
-#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f])
-#define conv_ascii2bin(a) (data_ascii2bin[os_toascii[a]&0x7f])
-#endif
-
-/* 64 char lines
- * pad input with 0
- * left over chars are set to =
- * 1 byte => xx==
- * 2 bytes => xxx=
- * 3 bytes => xxxx
- */
-#define BIN_PER_LINE (64/4*3)
-#define CHUNKS_PER_LINE (64/4)
-#define CHAR_PER_LINE (64+1)
-
-static const unsigned char data_bin2ascii[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\
-abcdefghijklmnopqrstuvwxyz0123456789+/";
-
-/* 0xF0 is a EOLN
- * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
- * 0xF2 is EOF
- * 0xE0 is ignore at start of line.
- * 0xFF is error
- */
-
-#define B64_EOLN 0xF0
-#define B64_CR 0xF1
-#define B64_EOF 0xF2
-#define B64_WS 0xE0
-#define B64_ERROR 0xFF
-#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3)
-
-static const unsigned char data_ascii2bin[128]={
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xE0,0xF0,0xFF,0xFF,0xF1,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0x3E,0xFF,0xF2,0xFF,0x3F,
- 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,
- 0x3C,0x3D,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
- 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,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,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,0xFF,0xFF,0xFF,0xFF,0xFF,
- };
-
-void EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
- {
- ctx->length=48;
- ctx->num=0;
- ctx->line_num=0;
- }
-
-void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
- const unsigned char *in, int inl)
- {
- int i,j;
- unsigned int total=0;
-
- *outl=0;
- if (inl == 0) return;
- OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
- if ((ctx->num+inl) < ctx->length)
- {
- memcpy(&(ctx->enc_data[ctx->num]),in,inl);
- ctx->num+=inl;
- return;
- }
- if (ctx->num != 0)
- {
- i=ctx->length-ctx->num;
- memcpy(&(ctx->enc_data[ctx->num]),in,i);
- in+=i;
- inl-=i;
- j=EVP_EncodeBlock(out,ctx->enc_data,ctx->length);
- ctx->num=0;
- out+=j;
- *(out++)='\n';
- *out='\0';
- total=j+1;
- }
- while (inl >= ctx->length)
- {
- j=EVP_EncodeBlock(out,in,ctx->length);
- in+=ctx->length;
- inl-=ctx->length;
- out+=j;
- *(out++)='\n';
- *out='\0';
- total+=j+1;
- }
- if (inl != 0)
- memcpy(&(ctx->enc_data[0]),in,inl);
- ctx->num=inl;
- *outl=total;
- }
-
-void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
- {
- unsigned int ret=0;
-
- if (ctx->num != 0)
- {
- ret=EVP_EncodeBlock(out,ctx->enc_data,ctx->num);
- out[ret++]='\n';
- out[ret]='\0';
- ctx->num=0;
- }
- *outl=ret;
- }
-
-int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
- {
- int i,ret=0;
- unsigned long l;
-
- for (i=dlen; i > 0; i-=3)
- {
- if (i >= 3)
- {
- l= (((unsigned long)f[0])<<16L)|
- (((unsigned long)f[1])<< 8L)|f[2];
- *(t++)=conv_bin2ascii(l>>18L);
- *(t++)=conv_bin2ascii(l>>12L);
- *(t++)=conv_bin2ascii(l>> 6L);
- *(t++)=conv_bin2ascii(l );
- }
- else
- {
- l=((unsigned long)f[0])<<16L;
- if (i == 2) l|=((unsigned long)f[1]<<8L);
-
- *(t++)=conv_bin2ascii(l>>18L);
- *(t++)=conv_bin2ascii(l>>12L);
- *(t++)=(i == 1)?'=':conv_bin2ascii(l>> 6L);
- *(t++)='=';
- }
- ret+=4;
- f+=3;
- }
-
- *t='\0';
- return(ret);
- }
-
-void EVP_DecodeInit(EVP_ENCODE_CTX *ctx)
- {
- ctx->length=30;
- ctx->num=0;
- ctx->line_num=0;
- ctx->expect_nl=0;
- }
-
-/* -1 for error
- * 0 for last line
- * 1 for full line
- */
-int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
- const unsigned char *in, int inl)
- {
- int seof= -1,eof=0,rv= -1,ret=0,i,v,tmp,n,ln,exp_nl;
- unsigned char *d;
-
- n=ctx->num;
- d=ctx->enc_data;
- ln=ctx->line_num;
- exp_nl=ctx->expect_nl;
-
- /* last line of input. */
- if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF)))
- { rv=0; goto end; }
-
- /* We parse the input data */
- for (i=0; i<inl; i++)
- {
- /* If the current line is > 80 characters, scream alot */
- if (ln >= 80) { rv= -1; goto end; }
-
- /* Get char and put it into the buffer */
- tmp= *(in++);
- v=conv_ascii2bin(tmp);
- /* only save the good data :-) */
- if (!B64_NOT_BASE64(v))
- {
- OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
- d[n++]=tmp;
- ln++;
- }
- else if (v == B64_ERROR)
- {
- rv= -1;
- goto end;
- }
-
- /* have we seen a '=' which is 'definitly' the last
- * input line. seof will point to the character that
- * holds it. and eof will hold how many characters to
- * chop off. */
- if (tmp == '=')
- {
- if (seof == -1) seof=n;
- eof++;
- }
-
- if (v == B64_CR)
- {
- ln = 0;
- if (exp_nl)
- continue;
- }
-
- /* eoln */
- if (v == B64_EOLN)
- {
- ln=0;
- if (exp_nl)
- {
- exp_nl=0;
- continue;
- }
- }
- exp_nl=0;
-
- /* If we are at the end of input and it looks like a
- * line, process it. */
- if (((i+1) == inl) && (((n&3) == 0) || eof))
- {
- v=B64_EOF;
- /* In case things were given us in really small
- records (so two '=' were given in separate
- updates), eof may contain the incorrect number
- of ending bytes to skip, so let's redo the count */
- eof = 0;
- if (d[n-1] == '=') eof++;
- if (d[n-2] == '=') eof++;
- /* There will never be more than two '=' */
- }
-
- if ((v == B64_EOF && (n&3) == 0) || (n >= 64))
- {
- /* This is needed to work correctly on 64 byte input
- * lines. We process the line and then need to
- * accept the '\n' */
- if ((v != B64_EOF) && (n >= 64)) exp_nl=1;
- if (n > 0)
- {
- v=EVP_DecodeBlock(out,d,n);
- n=0;
- if (v < 0) { rv=0; goto end; }
- ret+=(v-eof);
- }
- else
- {
- eof=1;
- v=0;
- }
-
- /* This is the case where we have had a short
- * but valid input line */
- if ((v < ctx->length) && eof)
- {
- rv=0;
- goto end;
- }
- else
- ctx->length=v;
-
- if (seof >= 0) { rv=0; goto end; }
- out+=v;
- }
- }
- rv=1;
-end:
- *outl=ret;
- ctx->num=n;
- ctx->line_num=ln;
- ctx->expect_nl=exp_nl;
- return(rv);
- }
-
-int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n)
- {
- int i,ret=0,a,b,c,d;
- unsigned long l;
-
- /* trim white space from the start of the line. */
- while ((conv_ascii2bin(*f) == B64_WS) && (n > 0))
- {
- f++;
- n--;
- }
-
- /* strip off stuff at the end of the line
- * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */
- while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n-1]))))
- n--;
-
- if (n%4 != 0) return(-1);
-
- for (i=0; i<n; i+=4)
- {
- a=conv_ascii2bin(*(f++));
- b=conv_ascii2bin(*(f++));
- c=conv_ascii2bin(*(f++));
- d=conv_ascii2bin(*(f++));
- if ( (a & 0x80) || (b & 0x80) ||
- (c & 0x80) || (d & 0x80))
- return(-1);
- l=( (((unsigned long)a)<<18L)|
- (((unsigned long)b)<<12L)|
- (((unsigned long)c)<< 6L)|
- (((unsigned long)d) ));
- *(t++)=(unsigned char)(l>>16L)&0xff;
- *(t++)=(unsigned char)(l>> 8L)&0xff;
- *(t++)=(unsigned char)(l )&0xff;
- ret+=3;
- }
- return(ret);
- }
-
-int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
- {
- int i;
-
- *outl=0;
- if (ctx->num != 0)
- {
- i=EVP_DecodeBlock(out,ctx->enc_data,ctx->num);
- if (i < 0) return(-1);
- ctx->num=0;
- *outl=i;
- return(1);
- }
- else
- return(1);
- }
-
-#ifdef undef
-int EVP_DecodeValid(unsigned char *buf, int len)
- {
- int i,num=0,bad=0;
-
- if (len == 0) return(-1);
- while (conv_ascii2bin(*buf) == B64_WS)
- {
- buf++;
- len--;
- if (len == 0) return(-1);
- }
-
- for (i=len; i >= 4; i-=4)
- {
- if ( (conv_ascii2bin(buf[0]) >= 0x40) ||
- (conv_ascii2bin(buf[1]) >= 0x40) ||
- (conv_ascii2bin(buf[2]) >= 0x40) ||
- (conv_ascii2bin(buf[3]) >= 0x40))
- return(-1);
- buf+=4;
- num+=1+(buf[2] != '=')+(buf[3] != '=');
- }
- if ((i == 1) && (conv_ascii2bin(buf[0]) == B64_EOLN))
- return(num);
- if ((i == 2) && (conv_ascii2bin(buf[0]) == B64_EOLN) &&
- (conv_ascii2bin(buf[0]) == B64_EOLN))
- return(num);
- return(1);
- }
-#endif
diff --git a/drivers/builtin_openssl/crypto/md5/md5.h b/drivers/builtin_openssl/crypto/md5/md5.h
deleted file mode 100644
index 8f392f0ec6..0000000000
--- a/drivers/builtin_openssl/crypto/md5/md5.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* crypto/md5/md5.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_MD5_H
-#define HEADER_MD5_H
-
-#include <openssl/e_os2.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_NO_MD5
-#error MD5 is disabled.
-#endif
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * ! MD5_LONG has to be at least 32 bits wide. If it's wider, then !
- * ! MD5_LONG_LOG2 has to be defined along. !
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- */
-
-#if defined(__LP32__)
-#define MD5_LONG unsigned long
-#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
-#define MD5_LONG unsigned long
-#define MD5_LONG_LOG2 3
-/*
- * _CRAY note. I could declare short, but I have no idea what impact
- * does it have on performance on none-T3E machines. I could declare
- * int, but at least on C90 sizeof(int) can be chosen at compile time.
- * So I've chosen long...
- * <appro@fy.chalmers.se>
- */
-#else
-#define MD5_LONG unsigned int
-#endif
-
-#define MD5_CBLOCK 64
-#define MD5_LBLOCK (MD5_CBLOCK/4)
-#define MD5_DIGEST_LENGTH 16
-
-typedef struct MD5state_st
- {
- MD5_LONG A,B,C,D;
- MD5_LONG Nl,Nh;
- MD5_LONG data[MD5_LBLOCK];
- unsigned int num;
- } MD5_CTX;
-
-#ifdef OPENSSL_FIPS
-int private_MD5_Init(MD5_CTX *c);
-#endif
-
-//#define MD5_Init _SSL_MD5_Init
-#define MD5_Final _SSL_MD5_Final
-#define MD5_Update _SSL_MD5_Update
-#define MD5_Transform _SSL_MD5_Transform
-#define MD5_Init private_MD5_Init
-
-int _SSL_MD5_Init(MD5_CTX *c);
-int _SSL_MD5_Update(MD5_CTX *c, const void *data, size_t len);
-int _SSL_MD5_Final(unsigned char *md, MD5_CTX *c);
-unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);
-void _SSL_MD5_Transform(MD5_CTX *c, const unsigned char *b);
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/crypto/md5/md5_locl.h b/drivers/builtin_openssl/crypto/md5/md5_locl.h
deleted file mode 100644
index 66bd9c6548..0000000000
--- a/drivers/builtin_openssl/crypto/md5/md5_locl.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* crypto/md5/md5_locl.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <openssl/e_os2.h>
-#include <openssl/md5.h>
-
-#ifndef MD5_LONG_LOG2
-#define MD5_LONG_LOG2 2 /* default to 32 bits */
-#endif
-
-#ifdef MD5_ASM
-# if defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(__INTEL__) || \
- defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
-# define md5_block_data_order md5_block_asm_data_order
-# elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
-# define md5_block_data_order md5_block_asm_data_order
-# endif
-#endif
-
-void md5_block_data_order (MD5_CTX *c, const void *p,size_t num);
-
-#define DATA_ORDER_IS_LITTLE_ENDIAN
-
-#define HASH_LONG MD5_LONG
-#define HASH_CTX MD5_CTX
-#define HASH_CBLOCK MD5_CBLOCK
-#define HASH_UPDATE _SSL_MD5_Update
-#define HASH_TRANSFORM _SSL_MD5_Transform
-#define HASH_FINAL _SSL_MD5_Final
-#define HASH_MAKE_STRING(c,s) do { \
- unsigned long ll; \
- ll=(c)->A; (void)HOST_l2c(ll,(s)); \
- ll=(c)->B; (void)HOST_l2c(ll,(s)); \
- ll=(c)->C; (void)HOST_l2c(ll,(s)); \
- ll=(c)->D; (void)HOST_l2c(ll,(s)); \
- } while (0)
-#define HASH_BLOCK_DATA_ORDER md5_block_data_order
-
-#include "md32_common.h"
-
-/*
-#define F(x,y,z) (((x) & (y)) | ((~(x)) & (z)))
-#define G(x,y,z) (((x) & (z)) | ((y) & (~(z))))
-*/
-
-/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
- * simplified to the code below. Wei attributes these optimizations
- * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
- */
-#define F(b,c,d) ((((c) ^ (d)) & (b)) ^ (d))
-#define G(b,c,d) ((((b) ^ (c)) & (d)) ^ (c))
-#define H(b,c,d) ((b) ^ (c) ^ (d))
-#define I(b,c,d) (((~(d)) | (b)) ^ (c))
-
-#define R0(a,b,c,d,k,s,t) { \
- a+=((k)+(t)+F((b),(c),(d))); \
- a=ROTATE(a,s); \
- a+=b; };\
-
-#define R1(a,b,c,d,k,s,t) { \
- a+=((k)+(t)+G((b),(c),(d))); \
- a=ROTATE(a,s); \
- a+=b; };
-
-#define R2(a,b,c,d,k,s,t) { \
- a+=((k)+(t)+H((b),(c),(d))); \
- a=ROTATE(a,s); \
- a+=b; };
-
-#define R3(a,b,c,d,k,s,t) { \
- a+=((k)+(t)+I((b),(c),(d))); \
- a=ROTATE(a,s); \
- a+=b; };
diff --git a/drivers/builtin_openssl/crypto/o_str.c b/drivers/builtin_openssl/crypto/o_str.c
deleted file mode 100644
index e78c19fbfc..0000000000
--- a/drivers/builtin_openssl/crypto/o_str.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/* crypto/o_str.c -*- mode:C; c-file-style: "eay" -*- */
-/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
- * project 2003.
- */
-/* ====================================================================
- * Copyright (c) 2003 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <ctype.h>
-#include <e_os.h>
-#include "o_str.h"
-
-#if !defined(OPENSSL_IMPLEMENTS_strncasecmp) && \
- !defined(OPENSSL_SYSNAME_WIN32) && \
- !defined(NETWARE_CLIB) && \
- !defined(_WIN32)
-
-# include <strings.h>
-#endif
-
-int OPENSSL_strncasecmp(const char *str1, const char *str2, size_t n)
- {
-#if defined(OPENSSL_IMPLEMENTS_strncasecmp)
- while (*str1 && *str2 && n)
- {
- int res = toupper(*str1) - toupper(*str2);
- if (res) return res < 0 ? -1 : 1;
- str1++;
- str2++;
- n--;
- }
- if (n == 0)
- return 0;
- if (*str1)
- return 1;
- if (*str2)
- return -1;
- return 0;
-#else
- /* Recursion hazard warning! Whenever strncasecmp is #defined as
- * OPENSSL_strncasecmp, OPENSSL_IMPLEMENTS_strncasecmp must be
- * defined as well. */
- return strncasecmp(str1, str2, n);
-#endif
- }
-int OPENSSL_strcasecmp(const char *str1, const char *str2)
- {
-#if defined(OPENSSL_IMPLEMENTS_strncasecmp)
- return OPENSSL_strncasecmp(str1, str2, (size_t)-1);
-#else
- return strcasecmp(str1, str2);
-#endif
- }
-
-int OPENSSL_memcmp(const void *v1,const void *v2,size_t n)
- {
- const unsigned char *c1=v1,*c2=v2;
- int ret=0;
-
- while(n && (ret=*c1-*c2)==0) n--,c1++,c2++;
-
- return ret;
- }
diff --git a/drivers/builtin_openssl/crypto/opensslconf.h b/drivers/builtin_openssl/crypto/opensslconf.h
deleted file mode 100644
index 6ece38cf29..0000000000
--- a/drivers/builtin_openssl/crypto/opensslconf.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/* opensslconf.h */
-/* WARNING: Generated automatically from opensslconf.h.in by Configure. */
-
-//sorry godot needs a single file for multiple builds
-
-// Check windows
-
-#ifdef USE_64BITS
-//weirder platforms that don't use GCC, LLVM or MSVC must define this
-# define OPENSSL_USE_64_BITS
-#elif _WIN32 || _WIN64
-# if _WIN64
-# define OPENSSL_USE_64_BITS
-# endif
-// Check GCC
-#elif __GNUC__
-# if __x86_64__ || __ppc64__
-# define OPENSSL_USE_64_BITS
-# endif
-#endif
-
-#ifndef OPENSSL_USE_64_BITS
-wqerw
-#endif
-
-
-
-/* OpenSSL was configured with the following options: */
-#ifndef OPENSSL_DOING_MAKEDEPEND
-
-
-#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
-# define OPENSSL_NO_EC_NISTP_64_GCC_128
-#endif
-#ifndef OPENSSL_NO_GMP
-# define OPENSSL_NO_GMP
-#endif
-#ifndef OPENSSL_NO_JPAKE
-# define OPENSSL_NO_JPAKE
-#endif
-#ifndef OPENSSL_NO_KRB5
-# define OPENSSL_NO_KRB5
-#endif
-#ifndef OPENSSL_NO_MD2
-# define OPENSSL_NO_MD2
-#endif
-#ifndef OPENSSL_NO_RC5
-# define OPENSSL_NO_RC5
-#endif
-#ifndef OPENSSL_NO_RFC3779
-# define OPENSSL_NO_RFC3779
-#endif
-#ifndef OPENSSL_NO_SCTP
-# define OPENSSL_NO_SCTP
-#endif
-#ifndef OPENSSL_NO_STORE
-# define OPENSSL_NO_STORE
-#endif
-
-#endif /* OPENSSL_DOING_MAKEDEPEND */
-
-#ifndef OPENSSL_THREADS
-# define OPENSSL_THREADS
-#endif
-#ifndef OPENSSL_NO_DYNAMIC_ENGINE
-# define OPENSSL_NO_DYNAMIC_ENGINE
-#endif
-
-/* The OPENSSL_NO_* macros are also defined as NO_* if the application
- asks for it. This is a transient feature that is provided for those
- who haven't had the time to do the appropriate changes in their
- applications. */
-#ifdef OPENSSL_ALGORITHM_DEFINES
-# if defined(OPENSSL_NO_EC_NISTP_64_GCC_128) && !defined(NO_EC_NISTP_64_GCC_128)
-# define NO_EC_NISTP_64_GCC_128
-# endif
-# if defined(OPENSSL_NO_GMP) && !defined(NO_GMP)
-# define NO_GMP
-# endif
-# if defined(OPENSSL_NO_JPAKE) && !defined(NO_JPAKE)
-# define NO_JPAKE
-# endif
-# if defined(OPENSSL_NO_KRB5) && !defined(NO_KRB5)
-# define NO_KRB5
-# endif
-# if defined(OPENSSL_NO_MD2) && !defined(NO_MD2)
-# define NO_MD2
-# endif
-# if defined(OPENSSL_NO_RC5) && !defined(NO_RC5)
-# define NO_RC5
-# endif
-# if defined(OPENSSL_NO_RFC3779) && !defined(NO_RFC3779)
-# define NO_RFC3779
-# endif
-# if defined(OPENSSL_NO_SCTP) && !defined(NO_SCTP)
-# define NO_SCTP
-# endif
-# if defined(OPENSSL_NO_STORE) && !defined(NO_STORE)
-# define NO_STORE
-# endif
-#endif
-
-#define OPENSSL_CPUID_OBJ
-
-/* crypto/opensslconf.h.in */
-
-/* Generate 80386 code? */
-#undef I386_ONLY
-
-#if !(defined(VMS) || defined(__VMS)) /* VMS uses logical names instead */
-#if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR)
-#define ENGINESDIR "/usr/local/ssl/lib/engines"
-#define OPENSSLDIR "/usr/local/ssl"
-#endif
-#endif
-
-#undef OPENSSL_UNISTD
-#define OPENSSL_UNISTD <unistd.h>
-
-#undef OPENSSL_EXPORT_VAR_AS_FUNCTION
-
-#if defined(HEADER_IDEA_H) && !defined(IDEA_INT)
-#define IDEA_INT unsigned int
-#endif
-
-#if defined(HEADER_MD2_H) && !defined(MD2_INT)
-#define MD2_INT unsigned int
-#endif
-
-#if defined(HEADER_RC2_H) && !defined(RC2_INT)
-/* I need to put in a mod for the alpha - eay */
-#define RC2_INT unsigned int
-#endif
-
-#if defined(HEADER_RC4_H)
-#if !defined(RC4_INT)
-/* using int types make the structure larger but make the code faster
- * on most boxes I have tested - up to %20 faster. */
-/*
- * I don't know what does "most" mean, but declaring "int" is a must on:
- * - Intel P6 because partial register stalls are very expensive;
- * - elder Alpha because it lacks byte load/store instructions;
- */
-#ifdef OPENSSL_USE_64_BITS
-#define RC4_INT unsigned int
-#else
-#define RC4_INT unsigned char
-#endif
-
-#endif
-#if !defined(RC4_CHUNK)
-/*
- * This enables code handling data aligned at natural CPU word
- * boundary. See crypto/rc4/rc4_enc.c for further details.
- */
-#define RC4_CHUNK unsigned long
-#endif
-#endif
-
-#if (defined(HEADER_NEW_DES_H) || defined(HEADER_DES_H)) && !defined(DES_LONG)
-/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
- * %20 speed up (longs are 8 bytes, int's are 4). */
-#ifndef DES_LONG
-#define DES_LONG unsigned int
-#endif
-#endif
-
-#if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H)
-#define CONFIG_HEADER_BN_H
-#ifdef OPENSSL_USE_64_BITS
-#undef BN_LLONG
-#else
-#define BN_LLONG
-#endif
-
-/* Should we define BN_DIV2W here? */
-
-/* Only one for the following should be defined */
-
-#ifdef OPENSSL_USE_64_BITS
-
-#define SIXTY_FOUR_BIT_LONG
-#undef SIXTY_FOUR_BIT
-#undef THIRTY_TWO_BIT
-
-#else
-
-#undef SIXTY_FOUR_BIT_LONG
-#undef SIXTY_FOUR_BIT
-#define THIRTY_TWO_BIT
-
-#endif
-
-
-
-#endif
-
-#endif
-
-#if defined(HEADER_RC4_LOCL_H) && !defined(CONFIG_HEADER_RC4_LOCL_H)
-#define CONFIG_HEADER_RC4_LOCL_H
-/* if this is defined data[i] is used instead of *data, this is a %20
- * speedup on x86 */
-#undef RC4_INDEX
-#endif
-
-#if defined(HEADER_BF_LOCL_H) && !defined(CONFIG_HEADER_BF_LOCL_H)
-#define CONFIG_HEADER_BF_LOCL_H
-#undef BF_PTR
-#endif /* HEADER_BF_LOCL_H */
-
-#if defined(HEADER_DES_LOCL_H) && !defined(CONFIG_HEADER_DES_LOCL_H)
-#define CONFIG_HEADER_DES_LOCL_H
-#ifndef DES_DEFAULT_OPTIONS
-/* the following is tweaked from a config script, that is why it is a
- * protected undef/define */
-#ifndef DES_PTR
-#undef DES_PTR
-#endif
-
-/* This helps C compiler generate the correct code for multiple functional
- * units. It reduces register dependancies at the expense of 2 more
- * registers */
-#ifndef DES_RISC1
-#undef DES_RISC1
-#endif
-
-#ifndef DES_RISC2
-#undef DES_RISC2
-#endif
-
-#if defined(DES_RISC1) && defined(DES_RISC2)
-YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
-#endif
-
-/* Unroll the inner loop, this sometimes helps, sometimes hinders.
- * Very mucy CPU dependant */
-#ifndef DES_UNROLL
-#define DES_UNROLL
-#endif
-
-/* These default values were supplied by
- * Peter Gutman <pgut001@cs.auckland.ac.nz>
- * They are only used if nothing else has been defined */
-#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
-/* Special defines which change the way the code is built depending on the
- CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
- even newer MIPS CPU's, but at the moment one size fits all for
- optimization options. Older Sparc's work better with only UNROLL, but
- there's no way to tell at compile time what it is you're running on */
-
-#if defined( sun ) /* Newer Sparc's */
-# define DES_PTR
-# define DES_RISC1
-# define DES_UNROLL
-#elif defined( __ultrix ) /* Older MIPS */
-# define DES_PTR
-# define DES_RISC2
-# define DES_UNROLL
-#elif defined( __osf1__ ) /* Alpha */
-# define DES_PTR
-# define DES_RISC2
-#elif defined ( _AIX ) /* RS6000 */
- /* Unknown */
-#elif defined( __hpux ) /* HP-PA */
- /* Unknown */
-#elif defined( __aux ) /* 68K */
- /* Unknown */
-#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */
-# define DES_UNROLL
-#elif defined( __sgi ) /* Newer MIPS */
-# define DES_PTR
-# define DES_RISC2
-# define DES_UNROLL
-#elif defined(i386) || defined(__i386__) /* x86 boxes, should be gcc */
-# define DES_PTR
-# define DES_RISC1
-# define DES_UNROLL
-#endif /* Systems-specific speed defines */
-#endif
-
-#endif /* DES_DEFAULT_OPTIONS */
-#endif /* HEADER_DES_LOCL_H */
diff --git a/drivers/builtin_openssl/crypto/opensslv.h b/drivers/builtin_openssl/crypto/opensslv.h
deleted file mode 100644
index ebe7180723..0000000000
--- a/drivers/builtin_openssl/crypto/opensslv.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef HEADER_OPENSSLV_H
-#define HEADER_OPENSSLV_H
-
-/* Numeric release version identifier:
- * MNNFFPPS: major minor fix patch status
- * The status nibble has one of the values 0 for development, 1 to e for betas
- * 1 to 14, and f for release. The patch level is exactly that.
- * For example:
- * 0.9.3-dev 0x00903000
- * 0.9.3-beta1 0x00903001
- * 0.9.3-beta2-dev 0x00903002
- * 0.9.3-beta2 0x00903002 (same as ...beta2-dev)
- * 0.9.3 0x0090300f
- * 0.9.3a 0x0090301f
- * 0.9.4 0x0090400f
- * 1.2.3z 0x102031af
- *
- * For continuity reasons (because 0.9.5 is already out, and is coded
- * 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level
- * part is slightly different, by setting the highest bit. This means
- * that 0.9.5a looks like this: 0x0090581f. At 0.9.6, we can start
- * with 0x0090600S...
- *
- * (Prior to 0.9.3-dev a different scheme was used: 0.9.2b is 0x0922.)
- * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
- * major minor fix final patch/beta)
- */
-#define OPENSSL_VERSION_NUMBER 0x1000107fL
-#ifdef OPENSSL_FIPS
-#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.1g-fips 7 Apr 2014"
-#else
-#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.1g 7 Apr 2014"
-#endif
-#define OPENSSL_VERSION_PTEXT " part of " OPENSSL_VERSION_TEXT
-
-
-/* The macros below are to be used for shared library (.so, .dll, ...)
- * versioning. That kind of versioning works a bit differently between
- * operating systems. The most usual scheme is to set a major and a minor
- * number, and have the runtime loader check that the major number is equal
- * to what it was at application link time, while the minor number has to
- * be greater or equal to what it was at application link time. With this
- * scheme, the version number is usually part of the file name, like this:
- *
- * libcrypto.so.0.9
- *
- * Some unixen also make a softlink with the major verson number only:
- *
- * libcrypto.so.0
- *
- * On Tru64 and IRIX 6.x it works a little bit differently. There, the
- * shared library version is stored in the file, and is actually a series
- * of versions, separated by colons. The rightmost version present in the
- * library when linking an application is stored in the application to be
- * matched at run time. When the application is run, a check is done to
- * see if the library version stored in the application matches any of the
- * versions in the version string of the library itself.
- * This version string can be constructed in any way, depending on what
- * kind of matching is desired. However, to implement the same scheme as
- * the one used in the other unixen, all compatible versions, from lowest
- * to highest, should be part of the string. Consecutive builds would
- * give the following versions strings:
- *
- * 3.0
- * 3.0:3.1
- * 3.0:3.1:3.2
- * 4.0
- * 4.0:4.1
- *
- * Notice how version 4 is completely incompatible with version, and
- * therefore give the breach you can see.
- *
- * There may be other schemes as well that I haven't yet discovered.
- *
- * So, here's the way it works here: first of all, the library version
- * number doesn't need at all to match the overall OpenSSL version.
- * However, it's nice and more understandable if it actually does.
- * The current library version is stored in the macro SHLIB_VERSION_NUMBER,
- * which is just a piece of text in the format "M.m.e" (Major, minor, edit).
- * For the sake of Tru64, IRIX, and any other OS that behaves in similar ways,
- * we need to keep a history of version numbers, which is done in the
- * macro SHLIB_VERSION_HISTORY. The numbers are separated by colons and
- * should only keep the versions that are binary compatible with the current.
- */
-#define SHLIB_VERSION_HISTORY ""
-#define SHLIB_VERSION_NUMBER "1.0.0"
-
-
-#endif /* HEADER_OPENSSLV_H */
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_crt.c b/drivers/builtin_openssl/crypto/pkcs12/p12_crt.c
deleted file mode 100644
index a34915d02d..0000000000
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_crt.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/* p12_crt.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project.
- */
-/* ====================================================================
- * Copyright (c) 1999-2002 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/pkcs12.h>
-
-
-static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, PKCS12_SAFEBAG *bag);
-
-static int copy_bag_attr(PKCS12_SAFEBAG *bag, EVP_PKEY *pkey, int nid)
- {
- int idx;
- X509_ATTRIBUTE *attr;
- idx = EVP_PKEY_get_attr_by_NID(pkey, nid, -1);
- if (idx < 0)
- return 1;
- attr = EVP_PKEY_get_attr(pkey, idx);
- if (!X509at_add1_attr(&bag->attrib, attr))
- return 0;
- return 1;
- }
-
-PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert,
- STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter, int mac_iter,
- int keytype)
-{
- PKCS12 *p12 = NULL;
- STACK_OF(PKCS7) *safes = NULL;
- STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
- PKCS12_SAFEBAG *bag = NULL;
- int i;
- unsigned char keyid[EVP_MAX_MD_SIZE];
- unsigned int keyidlen = 0;
-
- /* Set defaults */
- if (!nid_cert)
- {
-#ifdef OPENSSL_FIPS
- if (FIPS_mode())
- nid_cert = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
- else
-#endif
- nid_cert = NID_pbe_WithSHA1And40BitRC2_CBC;
- }
- if (!nid_key)
- nid_key = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
- if (!iter)
- iter = PKCS12_DEFAULT_ITER;
- if (!mac_iter)
- mac_iter = 1;
-
- if(!pkey && !cert && !ca)
- {
- PKCS12err(PKCS12_F_PKCS12_CREATE,PKCS12_R_INVALID_NULL_ARGUMENT);
- return NULL;
- }
-
- if (pkey && cert)
- {
- if(!X509_check_private_key(cert, pkey))
- return NULL;
- X509_digest(cert, EVP_sha1(), keyid, &keyidlen);
- }
-
- if (cert)
- {
- bag = PKCS12_add_cert(&bags, cert);
- if(name && !PKCS12_add_friendlyname(bag, name, -1))
- goto err;
- if(keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
- goto err;
- }
-
- /* Add all other certificates */
- for(i = 0; i < sk_X509_num(ca); i++)
- {
- if (!PKCS12_add_cert(&bags, sk_X509_value(ca, i)))
- goto err;
- }
-
- if (bags && !PKCS12_add_safe(&safes, bags, nid_cert, iter, pass))
- goto err;
-
- sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
- bags = NULL;
-
- if (pkey)
- {
- bag = PKCS12_add_key(&bags, pkey, keytype, iter, nid_key, pass);
-
- if (!bag)
- goto err;
-
- if (!copy_bag_attr(bag, pkey, NID_ms_csp_name))
- goto err;
- if (!copy_bag_attr(bag, pkey, NID_LocalKeySet))
- goto err;
-
- if(name && !PKCS12_add_friendlyname(bag, name, -1))
- goto err;
- if(keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
- goto err;
- }
-
- if (bags && !PKCS12_add_safe(&safes, bags, -1, 0, NULL))
- goto err;
-
- sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
- bags = NULL;
-
- p12 = PKCS12_add_safes(safes, 0);
-
- if (!p12)
- goto err;
-
- sk_PKCS7_pop_free(safes, PKCS7_free);
-
- safes = NULL;
-
- if ((mac_iter != -1) &&
- !PKCS12_set_mac(p12, pass, -1, NULL, 0, mac_iter, NULL))
- goto err;
-
- return p12;
-
- err:
-
- if (p12)
- PKCS12_free(p12);
- if (safes)
- sk_PKCS7_pop_free(safes, PKCS7_free);
- if (bags)
- sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
- return NULL;
-
-}
-
-PKCS12_SAFEBAG *PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert)
- {
- PKCS12_SAFEBAG *bag = NULL;
- char *name;
- int namelen = -1;
- unsigned char *keyid;
- int keyidlen = -1;
-
- /* Add user certificate */
- if(!(bag = PKCS12_x5092certbag(cert)))
- goto err;
-
- /* Use friendlyName and localKeyID in certificate.
- * (if present)
- */
-
- name = (char *)X509_alias_get0(cert, &namelen);
-
- if(name && !PKCS12_add_friendlyname(bag, name, namelen))
- goto err;
-
- keyid = X509_keyid_get0(cert, &keyidlen);
-
- if(keyid && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
- goto err;
-
- if (!pkcs12_add_bag(pbags, bag))
- goto err;
-
- return bag;
-
- err:
-
- if (bag)
- PKCS12_SAFEBAG_free(bag);
-
- return NULL;
-
- }
-
-PKCS12_SAFEBAG *PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags, EVP_PKEY *key,
- int key_usage, int iter,
- int nid_key, char *pass)
- {
-
- PKCS12_SAFEBAG *bag = NULL;
- PKCS8_PRIV_KEY_INFO *p8 = NULL;
-
- /* Make a PKCS#8 structure */
- if(!(p8 = EVP_PKEY2PKCS8(key)))
- goto err;
- if(key_usage && !PKCS8_add_keyusage(p8, key_usage))
- goto err;
- if (nid_key != -1)
- {
- bag = PKCS12_MAKE_SHKEYBAG(nid_key, pass, -1, NULL, 0, iter, p8);
- PKCS8_PRIV_KEY_INFO_free(p8);
- }
- else
- bag = PKCS12_MAKE_KEYBAG(p8);
-
- if(!bag)
- goto err;
-
- if (!pkcs12_add_bag(pbags, bag))
- goto err;
-
- return bag;
-
- err:
-
- if (bag)
- PKCS12_SAFEBAG_free(bag);
-
- return NULL;
-
- }
-
-int PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags,
- int nid_safe, int iter, char *pass)
- {
- PKCS7 *p7 = NULL;
- int free_safes = 0;
-
- if (!*psafes)
- {
- *psafes = sk_PKCS7_new_null();
- if (!*psafes)
- return 0;
- free_safes = 1;
- }
- else
- free_safes = 0;
-
- if (nid_safe == 0)
- nid_safe = NID_pbe_WithSHA1And40BitRC2_CBC;
-
- if (nid_safe == -1)
- p7 = PKCS12_pack_p7data(bags);
- else
- p7 = PKCS12_pack_p7encdata(nid_safe, pass, -1, NULL, 0,
- iter, bags);
- if (!p7)
- goto err;
-
- if (!sk_PKCS7_push(*psafes, p7))
- goto err;
-
- return 1;
-
- err:
- if (free_safes)
- {
- sk_PKCS7_free(*psafes);
- *psafes = NULL;
- }
-
- if (p7)
- PKCS7_free(p7);
-
- return 0;
-
- }
-
-static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, PKCS12_SAFEBAG *bag)
- {
- int free_bags;
- if (!pbags)
- return 1;
- if (!*pbags)
- {
- *pbags = sk_PKCS12_SAFEBAG_new_null();
- if (!*pbags)
- return 0;
- free_bags = 1;
- }
- else
- free_bags = 0;
-
- if (!sk_PKCS12_SAFEBAG_push(*pbags, bag))
- {
- if (free_bags)
- {
- sk_PKCS12_SAFEBAG_free(*pbags);
- *pbags = NULL;
- }
- return 0;
- }
-
- return 1;
-
- }
-
-
-PKCS12 *PKCS12_add_safes(STACK_OF(PKCS7) *safes, int nid_p7)
- {
- PKCS12 *p12;
- if (nid_p7 <= 0)
- nid_p7 = NID_pkcs7_data;
- p12 = PKCS12_init(nid_p7);
-
- if (!p12)
- return NULL;
-
- if(!PKCS12_pack_authsafes(p12, safes))
- {
- PKCS12_free(p12);
- return NULL;
- }
-
- return p12;
-
- }
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_kiss.c b/drivers/builtin_openssl/crypto/pkcs12/p12_kiss.c
deleted file mode 100644
index 206b1b0b18..0000000000
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_kiss.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* p12_kiss.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 1999.
- */
-/* ====================================================================
- * Copyright (c) 1999 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/pkcs12.h>
-
-/* Simplified PKCS#12 routines */
-
-static int parse_pk12( PKCS12 *p12, const char *pass, int passlen,
- EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
-
-static int parse_bags( STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass,
- int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
-
-static int parse_bag( PKCS12_SAFEBAG *bag, const char *pass, int passlen,
- EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
-
-/* Parse and decrypt a PKCS#12 structure returning user key, user cert
- * and other (CA) certs. Note either ca should be NULL, *ca should be NULL,
- * or it should point to a valid STACK structure. pkey and cert can be
- * passed unitialised.
- */
-
-int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert,
- STACK_OF(X509) **ca)
-{
- STACK_OF(X509) *ocerts = NULL;
- X509 *x = NULL;
- /* Check for NULL PKCS12 structure */
-
- if(!p12)
- {
- PKCS12err(PKCS12_F_PKCS12_PARSE,PKCS12_R_INVALID_NULL_PKCS12_POINTER);
- return 0;
- }
-
- if(pkey)
- *pkey = NULL;
- if(cert)
- *cert = NULL;
-
- /* Check the mac */
-
- /* If password is zero length or NULL then try verifying both cases
- * to determine which password is correct. The reason for this is that
- * under PKCS#12 password based encryption no password and a zero length
- * password are two different things...
- */
-
- if(!pass || !*pass) {
- if(PKCS12_verify_mac(p12, NULL, 0)) pass = NULL;
- else if(PKCS12_verify_mac(p12, "", 0)) pass = "";
- else {
- PKCS12err(PKCS12_F_PKCS12_PARSE,PKCS12_R_MAC_VERIFY_FAILURE);
- goto err;
- }
- } else if (!PKCS12_verify_mac(p12, pass, -1)) {
- PKCS12err(PKCS12_F_PKCS12_PARSE,PKCS12_R_MAC_VERIFY_FAILURE);
- goto err;
- }
-
- /* Allocate stack for other certificates */
- ocerts = sk_X509_new_null();
-
- if (!ocerts)
- {
- PKCS12err(PKCS12_F_PKCS12_PARSE,ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- if (!parse_pk12 (p12, pass, -1, pkey, ocerts))
- {
- PKCS12err(PKCS12_F_PKCS12_PARSE,PKCS12_R_PARSE_ERROR);
- goto err;
- }
-
- while ((x = sk_X509_pop(ocerts)))
- {
- if (pkey && *pkey && cert && !*cert)
- {
- if (X509_check_private_key(x, *pkey))
- {
- *cert = x;
- x = NULL;
- }
- }
-
- if (ca && x)
- {
- if (!*ca)
- *ca = sk_X509_new_null();
- if (!*ca)
- goto err;
- if (!sk_X509_push(*ca, x))
- goto err;
- x = NULL;
- }
- if (x)
- X509_free(x);
- }
-
- if (ocerts)
- sk_X509_pop_free(ocerts, X509_free);
-
- return 1;
-
- err:
-
- if (pkey && *pkey)
- EVP_PKEY_free(*pkey);
- if (cert && *cert)
- X509_free(*cert);
- if (x)
- X509_free(x);
- if (ocerts)
- sk_X509_pop_free(ocerts, X509_free);
- return 0;
-
-}
-
-/* Parse the outer PKCS#12 structure */
-
-static int parse_pk12(PKCS12 *p12, const char *pass, int passlen,
- EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
-{
- STACK_OF(PKCS7) *asafes;
- STACK_OF(PKCS12_SAFEBAG) *bags;
- int i, bagnid;
- PKCS7 *p7;
-
- if (!(asafes = PKCS12_unpack_authsafes (p12))) return 0;
- for (i = 0; i < sk_PKCS7_num (asafes); i++) {
- p7 = sk_PKCS7_value (asafes, i);
- bagnid = OBJ_obj2nid (p7->type);
- if (bagnid == NID_pkcs7_data) {
- bags = PKCS12_unpack_p7data(p7);
- } else if (bagnid == NID_pkcs7_encrypted) {
- bags = PKCS12_unpack_p7encdata(p7, pass, passlen);
- } else continue;
- if (!bags) {
- sk_PKCS7_pop_free(asafes, PKCS7_free);
- return 0;
- }
- if (!parse_bags(bags, pass, passlen, pkey, ocerts)) {
- sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
- sk_PKCS7_pop_free(asafes, PKCS7_free);
- return 0;
- }
- sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
- }
- sk_PKCS7_pop_free(asafes, PKCS7_free);
- return 1;
-}
-
-
-static int parse_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass,
- int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
-{
- int i;
- for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
- if (!parse_bag(sk_PKCS12_SAFEBAG_value (bags, i),
- pass, passlen, pkey, ocerts))
- return 0;
- }
- return 1;
-}
-
-static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen,
- EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
-{
- PKCS8_PRIV_KEY_INFO *p8;
- X509 *x509;
- ASN1_TYPE *attrib;
- ASN1_BMPSTRING *fname = NULL;
- ASN1_OCTET_STRING *lkid = NULL;
-
- if ((attrib = PKCS12_get_attr (bag, NID_friendlyName)))
- fname = attrib->value.bmpstring;
-
- if ((attrib = PKCS12_get_attr (bag, NID_localKeyID)))
- lkid = attrib->value.octet_string;
-
- switch (M_PKCS12_bag_type(bag))
- {
- case NID_keyBag:
- if (!pkey || *pkey)
- return 1;
- if (!(*pkey = EVP_PKCS82PKEY(bag->value.keybag)))
- return 0;
- break;
-
- case NID_pkcs8ShroudedKeyBag:
- if (!pkey || *pkey)
- return 1;
- if (!(p8 = PKCS12_decrypt_skey(bag, pass, passlen)))
- return 0;
- *pkey = EVP_PKCS82PKEY(p8);
- PKCS8_PRIV_KEY_INFO_free(p8);
- if (!(*pkey)) return 0;
- break;
-
- case NID_certBag:
- if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate )
- return 1;
- if (!(x509 = PKCS12_certbag2x509(bag)))
- return 0;
- if(lkid && !X509_keyid_set1(x509, lkid->data, lkid->length))
- {
- X509_free(x509);
- return 0;
- }
- if(fname) {
- int len, r;
- unsigned char *data;
- len = ASN1_STRING_to_UTF8(&data, fname);
- if(len > 0) {
- r = X509_alias_set1(x509, data, len);
- OPENSSL_free(data);
- if (!r)
- {
- X509_free(x509);
- return 0;
- }
- }
- }
-
- if(!sk_X509_push(ocerts, x509))
- {
- X509_free(x509);
- return 0;
- }
-
- break;
-
- case NID_safeContentsBag:
- return parse_bags(bag->value.safes, pass, passlen,
- pkey, ocerts);
- break;
-
- default:
- return 1;
- break;
- }
- return 1;
-}
-
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pk7_doit.c b/drivers/builtin_openssl/crypto/pkcs7/pk7_doit.c
deleted file mode 100644
index 77fda3b82a..0000000000
--- a/drivers/builtin_openssl/crypto/pkcs7/pk7_doit.c
+++ /dev/null
@@ -1,1299 +0,0 @@
-/* crypto/pkcs7/pk7_doit.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/err.h>
-
-static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
- void *value);
-static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid);
-
-static int PKCS7_type_is_other(PKCS7* p7)
- {
- int isOther=1;
-
- int nid=OBJ_obj2nid(p7->type);
-
- switch( nid )
- {
- case NID_pkcs7_data:
- case NID_pkcs7_signed:
- case NID_pkcs7_enveloped:
- case NID_pkcs7_signedAndEnveloped:
- case NID_pkcs7_digest:
- case NID_pkcs7_encrypted:
- isOther=0;
- break;
- default:
- isOther=1;
- }
-
- return isOther;
-
- }
-
-static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7)
- {
- if ( PKCS7_type_is_data(p7))
- return p7->d.data;
- if ( PKCS7_type_is_other(p7) && p7->d.other
- && (p7->d.other->type == V_ASN1_OCTET_STRING))
- return p7->d.other->value.octet_string;
- return NULL;
- }
-
-static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg)
- {
- BIO *btmp;
- const EVP_MD *md;
- if ((btmp=BIO_new(BIO_f_md())) == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB);
- goto err;
- }
-
- md=EVP_get_digestbyobj(alg->algorithm);
- if (md == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,PKCS7_R_UNKNOWN_DIGEST_TYPE);
- goto err;
- }
-
- BIO_set_md(btmp,md);
- if (*pbio == NULL)
- *pbio=btmp;
- else if (!BIO_push(*pbio,btmp))
- {
- PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB);
- goto err;
- }
- btmp=NULL;
-
- return 1;
-
- err:
- if (btmp)
- BIO_free(btmp);
- return 0;
-
- }
-
-static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri,
- unsigned char *key, int keylen)
- {
- EVP_PKEY_CTX *pctx = NULL;
- EVP_PKEY *pkey = NULL;
- unsigned char *ek = NULL;
- int ret = 0;
- size_t eklen;
-
- pkey = X509_get_pubkey(ri->cert);
-
- if (!pkey)
- return 0;
-
- pctx = EVP_PKEY_CTX_new(pkey, NULL);
- if (!pctx)
- return 0;
-
- if (EVP_PKEY_encrypt_init(pctx) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
- EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri) <= 0)
- {
- PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, PKCS7_R_CTRL_ERROR);
- goto err;
- }
-
- if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0)
- goto err;
-
- ek = OPENSSL_malloc(eklen);
-
- if (ek == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0)
- goto err;
-
- ASN1_STRING_set0(ri->enc_key, ek, eklen);
- ek = NULL;
-
- ret = 1;
-
- err:
- if (pkey)
- EVP_PKEY_free(pkey);
- if (pctx)
- EVP_PKEY_CTX_free(pctx);
- if (ek)
- OPENSSL_free(ek);
- return ret;
-
- }
-
-
-static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
- PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey)
- {
- EVP_PKEY_CTX *pctx = NULL;
- unsigned char *ek = NULL;
- size_t eklen;
-
- int ret = -1;
-
- pctx = EVP_PKEY_CTX_new(pkey, NULL);
- if (!pctx)
- return -1;
-
- if (EVP_PKEY_decrypt_init(pctx) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
- EVP_PKEY_CTRL_PKCS7_DECRYPT, 0, ri) <= 0)
- {
- PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, PKCS7_R_CTRL_ERROR);
- goto err;
- }
-
- if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
- ri->enc_key->data, ri->enc_key->length) <= 0)
- goto err;
-
- ek = OPENSSL_malloc(eklen);
-
- if (ek == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (EVP_PKEY_decrypt(pctx, ek, &eklen,
- ri->enc_key->data, ri->enc_key->length) <= 0)
- {
- ret = 0;
- PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB);
- goto err;
- }
-
- ret = 1;
-
- if (*pek)
- {
- OPENSSL_cleanse(*pek, *peklen);
- OPENSSL_free(*pek);
- }
-
- *pek = ek;
- *peklen = eklen;
-
- err:
- if (pctx)
- EVP_PKEY_CTX_free(pctx);
- if (!ret && ek)
- OPENSSL_free(ek);
-
- return ret;
- }
-
-BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
- {
- int i;
- BIO *out=NULL,*btmp=NULL;
- X509_ALGOR *xa = NULL;
- const EVP_CIPHER *evp_cipher=NULL;
- STACK_OF(X509_ALGOR) *md_sk=NULL;
- STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
- X509_ALGOR *xalg=NULL;
- PKCS7_RECIP_INFO *ri=NULL;
- ASN1_OCTET_STRING *os=NULL;
-
- i=OBJ_obj2nid(p7->type);
- p7->state=PKCS7_S_HEADER;
-
- switch (i)
- {
- case NID_pkcs7_signed:
- md_sk=p7->d.sign->md_algs;
- os = PKCS7_get_octet_string(p7->d.sign->contents);
- break;
- case NID_pkcs7_signedAndEnveloped:
- rsk=p7->d.signed_and_enveloped->recipientinfo;
- md_sk=p7->d.signed_and_enveloped->md_algs;
- xalg=p7->d.signed_and_enveloped->enc_data->algorithm;
- evp_cipher=p7->d.signed_and_enveloped->enc_data->cipher;
- if (evp_cipher == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAINIT,
- PKCS7_R_CIPHER_NOT_INITIALIZED);
- goto err;
- }
- break;
- case NID_pkcs7_enveloped:
- rsk=p7->d.enveloped->recipientinfo;
- xalg=p7->d.enveloped->enc_data->algorithm;
- evp_cipher=p7->d.enveloped->enc_data->cipher;
- if (evp_cipher == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAINIT,
- PKCS7_R_CIPHER_NOT_INITIALIZED);
- goto err;
- }
- break;
- case NID_pkcs7_digest:
- xa = p7->d.digest->md;
- os = PKCS7_get_octet_string(p7->d.digest->contents);
- break;
- case NID_pkcs7_data:
- break;
- default:
- PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
- goto err;
- }
-
- for (i=0; i<sk_X509_ALGOR_num(md_sk); i++)
- if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i)))
- goto err;
-
- if (xa && !PKCS7_bio_add_digest(&out, xa))
- goto err;
-
- if (evp_cipher != NULL)
- {
- unsigned char key[EVP_MAX_KEY_LENGTH];
- unsigned char iv[EVP_MAX_IV_LENGTH];
- int keylen,ivlen;
- EVP_CIPHER_CTX *ctx;
-
- if ((btmp=BIO_new(BIO_f_cipher())) == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_BIO_LIB);
- goto err;
- }
- BIO_get_cipher_ctx(btmp, &ctx);
- keylen=EVP_CIPHER_key_length(evp_cipher);
- ivlen=EVP_CIPHER_iv_length(evp_cipher);
- xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
- if (ivlen > 0)
- if (RAND_pseudo_bytes(iv,ivlen) <= 0)
- goto err;
- if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0)
- goto err;
- if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
- goto err;
- if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0)
- goto err;
-
- if (ivlen > 0) {
- if (xalg->parameter == NULL) {
- xalg->parameter = ASN1_TYPE_new();
- if (xalg->parameter == NULL)
- goto err;
- }
- if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0)
- goto err;
- }
-
- /* Lets do the pub key stuff :-) */
- for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
- {
- ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
- if (pkcs7_encode_rinfo(ri, key, keylen) <= 0)
- goto err;
- }
- OPENSSL_cleanse(key, keylen);
-
- if (out == NULL)
- out=btmp;
- else
- BIO_push(out,btmp);
- btmp=NULL;
- }
-
- if (bio == NULL)
- {
- if (PKCS7_is_detached(p7))
- bio=BIO_new(BIO_s_null());
- else if (os && os->length > 0)
- bio = BIO_new_mem_buf(os->data, os->length);
- if(bio == NULL)
- {
- bio=BIO_new(BIO_s_mem());
- if (bio == NULL)
- goto err;
- BIO_set_mem_eof_return(bio,0);
- }
- }
- if (out)
- BIO_push(out,bio);
- else
- out = bio;
- bio=NULL;
- if (0)
- {
-err:
- if (out != NULL)
- BIO_free_all(out);
- if (btmp != NULL)
- BIO_free_all(btmp);
- out=NULL;
- }
- return(out);
- }
-
-static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert)
- {
- int ret;
- ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
- pcert->cert_info->issuer);
- if (ret)
- return ret;
- return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber,
- ri->issuer_and_serial->serial);
- }
-
-/* int */
-BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
- {
- int i,j;
- BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL;
- X509_ALGOR *xa;
- ASN1_OCTET_STRING *data_body=NULL;
- const EVP_MD *evp_md;
- const EVP_CIPHER *evp_cipher=NULL;
- EVP_CIPHER_CTX *evp_ctx=NULL;
- X509_ALGOR *enc_alg=NULL;
- STACK_OF(X509_ALGOR) *md_sk=NULL;
- STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
- PKCS7_RECIP_INFO *ri=NULL;
- unsigned char *ek = NULL, *tkey = NULL;
- int eklen = 0, tkeylen = 0;
-
- i=OBJ_obj2nid(p7->type);
- p7->state=PKCS7_S_HEADER;
-
- switch (i)
- {
- case NID_pkcs7_signed:
- data_body=PKCS7_get_octet_string(p7->d.sign->contents);
- md_sk=p7->d.sign->md_algs;
- break;
- case NID_pkcs7_signedAndEnveloped:
- rsk=p7->d.signed_and_enveloped->recipientinfo;
- md_sk=p7->d.signed_and_enveloped->md_algs;
- data_body=p7->d.signed_and_enveloped->enc_data->enc_data;
- enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm;
- evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
- if (evp_cipher == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
- goto err;
- }
- break;
- case NID_pkcs7_enveloped:
- rsk=p7->d.enveloped->recipientinfo;
- enc_alg=p7->d.enveloped->enc_data->algorithm;
- data_body=p7->d.enveloped->enc_data->enc_data;
- evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
- if (evp_cipher == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
- goto err;
- }
- break;
- default:
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
- goto err;
- }
-
- /* We will be checking the signature */
- if (md_sk != NULL)
- {
- for (i=0; i<sk_X509_ALGOR_num(md_sk); i++)
- {
- xa=sk_X509_ALGOR_value(md_sk,i);
- if ((btmp=BIO_new(BIO_f_md())) == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
- goto err;
- }
-
- j=OBJ_obj2nid(xa->algorithm);
- evp_md=EVP_get_digestbynid(j);
- if (evp_md == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE);
- goto err;
- }
-
- BIO_set_md(btmp,evp_md);
- if (out == NULL)
- out=btmp;
- else
- BIO_push(out,btmp);
- btmp=NULL;
- }
- }
-
- if (evp_cipher != NULL)
- {
-#if 0
- unsigned char key[EVP_MAX_KEY_LENGTH];
- unsigned char iv[EVP_MAX_IV_LENGTH];
- unsigned char *p;
- int keylen,ivlen;
- int max;
- X509_OBJECT ret;
-#endif
-
- if ((etmp=BIO_new(BIO_f_cipher())) == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
- goto err;
- }
-
- /* It was encrypted, we need to decrypt the secret key
- * with the private key */
-
- /* Find the recipientInfo which matches the passed certificate
- * (if any)
- */
-
- if (pcert)
- {
- for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
- {
- ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
- if (!pkcs7_cmp_ri(ri, pcert))
- break;
- ri=NULL;
- }
- if (ri == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,
- PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
- goto err;
- }
- }
-
- /* If we haven't got a certificate try each ri in turn */
- if (pcert == NULL)
- {
- /* Always attempt to decrypt all rinfo even
- * after sucess as a defence against MMA timing
- * attacks.
- */
- for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
- {
- ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
-
- if (pkcs7_decrypt_rinfo(&ek, &eklen,
- ri, pkey) < 0)
- goto err;
- ERR_clear_error();
- }
- }
- else
- {
- /* Only exit on fatal errors, not decrypt failure */
- if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
- goto err;
- ERR_clear_error();
- }
-
- evp_ctx=NULL;
- BIO_get_cipher_ctx(etmp,&evp_ctx);
- if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
- goto err;
- if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
- goto err;
- /* Generate random key as MMA defence */
- tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
- tkey = OPENSSL_malloc(tkeylen);
- if (!tkey)
- goto err;
- if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
- goto err;
- if (ek == NULL)
- {
- ek = tkey;
- eklen = tkeylen;
- tkey = NULL;
- }
-
- if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) {
- /* Some S/MIME clients don't use the same key
- * and effective key length. The key length is
- * determined by the size of the decrypted RSA key.
- */
- if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen))
- {
- /* Use random key as MMA defence */
- OPENSSL_cleanse(ek, eklen);
- OPENSSL_free(ek);
- ek = tkey;
- eklen = tkeylen;
- tkey = NULL;
- }
- }
- /* Clear errors so we don't leak information useful in MMA */
- ERR_clear_error();
- if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0)
- goto err;
-
- if (ek)
- {
- OPENSSL_cleanse(ek,eklen);
- OPENSSL_free(ek);
- ek = NULL;
- }
- if (tkey)
- {
- OPENSSL_cleanse(tkey,tkeylen);
- OPENSSL_free(tkey);
- tkey = NULL;
- }
-
- if (out == NULL)
- out=etmp;
- else
- BIO_push(out,etmp);
- etmp=NULL;
- }
-
-#if 1
- if (PKCS7_is_detached(p7) || (in_bio != NULL))
- {
- bio=in_bio;
- }
- else
- {
-#if 0
- bio=BIO_new(BIO_s_mem());
- /* We need to set this so that when we have read all
- * the data, the encrypt BIO, if present, will read
- * EOF and encode the last few bytes */
- BIO_set_mem_eof_return(bio,0);
-
- if (data_body->length > 0)
- BIO_write(bio,(char *)data_body->data,data_body->length);
-#else
- if (data_body->length > 0)
- bio = BIO_new_mem_buf(data_body->data,data_body->length);
- else {
- bio=BIO_new(BIO_s_mem());
- BIO_set_mem_eof_return(bio,0);
- }
- if (bio == NULL)
- goto err;
-#endif
- }
- BIO_push(out,bio);
- bio=NULL;
-#endif
- if (0)
- {
-err:
- if (ek)
- {
- OPENSSL_cleanse(ek,eklen);
- OPENSSL_free(ek);
- }
- if (tkey)
- {
- OPENSSL_cleanse(tkey,tkeylen);
- OPENSSL_free(tkey);
- }
- if (out != NULL) BIO_free_all(out);
- if (btmp != NULL) BIO_free_all(btmp);
- if (etmp != NULL) BIO_free_all(etmp);
- if (bio != NULL) BIO_free_all(bio);
- out=NULL;
- }
- return(out);
- }
-
-static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid)
- {
- for (;;)
- {
- bio=BIO_find_type(bio,BIO_TYPE_MD);
- if (bio == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
- return NULL;
- }
- BIO_get_md_ctx(bio,pmd);
- if (*pmd == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,ERR_R_INTERNAL_ERROR);
- return NULL;
- }
- if (EVP_MD_CTX_type(*pmd) == nid)
- return bio;
- bio=BIO_next(bio);
- }
- return NULL;
- }
-
-static int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx)
- {
- unsigned char md_data[EVP_MAX_MD_SIZE];
- unsigned int md_len;
-
- /* Add signing time if not already present */
- if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime))
- {
- if (!PKCS7_add0_attrib_signing_time(si, NULL))
- {
- PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB,
- ERR_R_MALLOC_FAILURE);
- return 0;
- }
- }
-
- /* Add digest */
- if (!EVP_DigestFinal_ex(mctx, md_data,&md_len))
- {
- PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_EVP_LIB);
- return 0;
- }
- if (!PKCS7_add1_attrib_digest(si, md_data, md_len))
- {
- PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- /* Now sign the attributes */
- if (!PKCS7_SIGNER_INFO_sign(si))
- return 0;
-
- return 1;
- }
-
-
-int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
- {
- int ret=0;
- int i,j;
- BIO *btmp;
- PKCS7_SIGNER_INFO *si;
- EVP_MD_CTX *mdc,ctx_tmp;
- STACK_OF(X509_ATTRIBUTE) *sk;
- STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL;
- ASN1_OCTET_STRING *os=NULL;
-
- EVP_MD_CTX_init(&ctx_tmp);
- i=OBJ_obj2nid(p7->type);
- p7->state=PKCS7_S_HEADER;
-
- switch (i)
- {
- case NID_pkcs7_data:
- os = p7->d.data;
- break;
- case NID_pkcs7_signedAndEnveloped:
- /* XXXXXXXXXXXXXXXX */
- si_sk=p7->d.signed_and_enveloped->signer_info;
- os = p7->d.signed_and_enveloped->enc_data->enc_data;
- if (!os)
- {
- os=M_ASN1_OCTET_STRING_new();
- if (!os)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- p7->d.signed_and_enveloped->enc_data->enc_data=os;
- }
- break;
- case NID_pkcs7_enveloped:
- /* XXXXXXXXXXXXXXXX */
- os = p7->d.enveloped->enc_data->enc_data;
- if (!os)
- {
- os=M_ASN1_OCTET_STRING_new();
- if (!os)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- p7->d.enveloped->enc_data->enc_data=os;
- }
- break;
- case NID_pkcs7_signed:
- si_sk=p7->d.sign->signer_info;
- os=PKCS7_get_octet_string(p7->d.sign->contents);
- /* If detached data then the content is excluded */
- if(PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) {
- M_ASN1_OCTET_STRING_free(os);
- p7->d.sign->contents->d.data = NULL;
- }
- break;
-
- case NID_pkcs7_digest:
- os=PKCS7_get_octet_string(p7->d.digest->contents);
- /* If detached data then the content is excluded */
- if(PKCS7_type_is_data(p7->d.digest->contents) && p7->detached)
- {
- M_ASN1_OCTET_STRING_free(os);
- p7->d.digest->contents->d.data = NULL;
- }
- break;
-
- default:
- PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
- goto err;
- }
-
- if (si_sk != NULL)
- {
- for (i=0; i<sk_PKCS7_SIGNER_INFO_num(si_sk); i++)
- {
- si=sk_PKCS7_SIGNER_INFO_value(si_sk,i);
- if (si->pkey == NULL)
- continue;
-
- j = OBJ_obj2nid(si->digest_alg->algorithm);
-
- btmp=bio;
-
- btmp = PKCS7_find_digest(&mdc, btmp, j);
-
- if (btmp == NULL)
- goto err;
-
- /* We now have the EVP_MD_CTX, lets do the
- * signing. */
- if (!EVP_MD_CTX_copy_ex(&ctx_tmp,mdc))
- goto err;
-
- sk=si->auth_attr;
-
- /* If there are attributes, we add the digest
- * attribute and only sign the attributes */
- if (sk_X509_ATTRIBUTE_num(sk) > 0)
- {
- if (!do_pkcs7_signed_attrib(si, &ctx_tmp))
- goto err;
- }
- else
- {
- unsigned char *abuf = NULL;
- unsigned int abuflen;
- abuflen = EVP_PKEY_size(si->pkey);
- abuf = OPENSSL_malloc(abuflen);
- if (!abuf)
- goto err;
-
- if (!EVP_SignFinal(&ctx_tmp, abuf, &abuflen,
- si->pkey))
- {
- PKCS7err(PKCS7_F_PKCS7_DATAFINAL,
- ERR_R_EVP_LIB);
- goto err;
- }
- ASN1_STRING_set0(si->enc_digest, abuf, abuflen);
- }
- }
- }
- else if (i == NID_pkcs7_digest)
- {
- unsigned char md_data[EVP_MAX_MD_SIZE];
- unsigned int md_len;
- if (!PKCS7_find_digest(&mdc, bio,
- OBJ_obj2nid(p7->d.digest->md->algorithm)))
- goto err;
- if (!EVP_DigestFinal_ex(mdc,md_data,&md_len))
- goto err;
- M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
- }
-
- if (!PKCS7_is_detached(p7) && !(os->flags & ASN1_STRING_FLAG_NDEF))
- {
- char *cont;
- long contlen;
- btmp=BIO_find_type(bio,BIO_TYPE_MEM);
- if (btmp == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
- goto err;
- }
- contlen = BIO_get_mem_data(btmp, &cont);
- /* Mark the BIO read only then we can use its copy of the data
- * instead of making an extra copy.
- */
- BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
- BIO_set_mem_eof_return(btmp, 0);
- ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
- }
- ret=1;
-err:
- EVP_MD_CTX_cleanup(&ctx_tmp);
- return(ret);
- }
-
-int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si)
- {
- EVP_MD_CTX mctx;
- EVP_PKEY_CTX *pctx;
- unsigned char *abuf = NULL;
- int alen;
- size_t siglen;
- const EVP_MD *md = NULL;
-
- md = EVP_get_digestbyobj(si->digest_alg->algorithm);
- if (md == NULL)
- return 0;
-
- EVP_MD_CTX_init(&mctx);
- if (EVP_DigestSignInit(&mctx, &pctx, md,NULL, si->pkey) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
- EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0)
- {
- PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
- goto err;
- }
-
- alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr,&abuf,
- ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
- if(!abuf)
- goto err;
- if (EVP_DigestSignUpdate(&mctx,abuf,alen) <= 0)
- goto err;
- OPENSSL_free(abuf);
- if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0)
- goto err;
- abuf = OPENSSL_malloc(siglen);
- if(!abuf)
- goto err;
- if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
- EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0)
- {
- PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
- goto err;
- }
-
- EVP_MD_CTX_cleanup(&mctx);
-
- ASN1_STRING_set0(si->enc_digest, abuf, siglen);
-
- return 1;
-
- err:
- if (abuf)
- OPENSSL_free(abuf);
- EVP_MD_CTX_cleanup(&mctx);
- return 0;
-
- }
-
-int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
- PKCS7 *p7, PKCS7_SIGNER_INFO *si)
- {
- PKCS7_ISSUER_AND_SERIAL *ias;
- int ret=0,i;
- STACK_OF(X509) *cert;
- X509 *x509;
-
- if (PKCS7_type_is_signed(p7))
- {
- cert=p7->d.sign->cert;
- }
- else if (PKCS7_type_is_signedAndEnveloped(p7))
- {
- cert=p7->d.signed_and_enveloped->cert;
- }
- else
- {
- PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE);
- goto err;
- }
- /* XXXXXXXXXXXXXXXXXXXXXXX */
- ias=si->issuer_and_serial;
-
- x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial);
-
- /* were we able to find the cert in passed to us */
- if (x509 == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_UNABLE_TO_FIND_CERTIFICATE);
- goto err;
- }
-
- /* Lets verify */
- if(!X509_STORE_CTX_init(ctx,cert_store,x509,cert))
- {
- PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB);
- goto err;
- }
- X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN);
- i=X509_verify_cert(ctx);
- if (i <= 0)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB);
- X509_STORE_CTX_cleanup(ctx);
- goto err;
- }
- X509_STORE_CTX_cleanup(ctx);
-
- return PKCS7_signatureVerify(bio, p7, si, x509);
- err:
- return ret;
- }
-
-int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
- X509 *x509)
- {
- ASN1_OCTET_STRING *os;
- EVP_MD_CTX mdc_tmp,*mdc;
- int ret=0,i;
- int md_type;
- STACK_OF(X509_ATTRIBUTE) *sk;
- BIO *btmp;
- EVP_PKEY *pkey;
-
- EVP_MD_CTX_init(&mdc_tmp);
-
- if (!PKCS7_type_is_signed(p7) &&
- !PKCS7_type_is_signedAndEnveloped(p7)) {
- PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
- PKCS7_R_WRONG_PKCS7_TYPE);
- goto err;
- }
-
- md_type=OBJ_obj2nid(si->digest_alg->algorithm);
-
- btmp=bio;
- for (;;)
- {
- if ((btmp == NULL) ||
- ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL))
- {
- PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
- PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
- goto err;
- }
- BIO_get_md_ctx(btmp,&mdc);
- if (mdc == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
- if (EVP_MD_CTX_type(mdc) == md_type)
- break;
- /* Workaround for some broken clients that put the signature
- * OID instead of the digest OID in digest_alg->algorithm
- */
- if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type)
- break;
- btmp=BIO_next(btmp);
- }
-
- /* mdc is the digest ctx that we want, unless there are attributes,
- * in which case the digest is the signed attributes */
- if (!EVP_MD_CTX_copy_ex(&mdc_tmp,mdc))
- goto err;
-
- sk=si->auth_attr;
- if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0))
- {
- unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL;
- unsigned int md_len;
- int alen;
- ASN1_OCTET_STRING *message_digest;
-
- if (!EVP_DigestFinal_ex(&mdc_tmp,md_dat,&md_len))
- goto err;
- message_digest=PKCS7_digest_from_attributes(sk);
- if (!message_digest)
- {
- PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
- PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
- goto err;
- }
- if ((message_digest->length != (int)md_len) ||
- (memcmp(message_digest->data,md_dat,md_len)))
- {
-#if 0
-{
-int ii;
-for (ii=0; ii<message_digest->length; ii++)
- printf("%02X",message_digest->data[ii]); printf(" sent\n");
-for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n");
-}
-#endif
- PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
- PKCS7_R_DIGEST_FAILURE);
- ret= -1;
- goto err;
- }
-
- if (!EVP_VerifyInit_ex(&mdc_tmp,EVP_get_digestbynid(md_type), NULL))
- goto err;
-
- alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
- ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
- if (alen <= 0)
- {
- PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,ERR_R_ASN1_LIB);
- ret = -1;
- goto err;
- }
- if (!EVP_VerifyUpdate(&mdc_tmp, abuf, alen))
- goto err;
-
- OPENSSL_free(abuf);
- }
-
- os=si->enc_digest;
- pkey = X509_get_pubkey(x509);
- if (!pkey)
- {
- ret = -1;
- goto err;
- }
-
- i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey);
- EVP_PKEY_free(pkey);
- if (i <= 0)
- {
- PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
- PKCS7_R_SIGNATURE_FAILURE);
- ret= -1;
- goto err;
- }
- else
- ret=1;
-err:
- EVP_MD_CTX_cleanup(&mdc_tmp);
- return(ret);
- }
-
-PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx)
- {
- STACK_OF(PKCS7_RECIP_INFO) *rsk;
- PKCS7_RECIP_INFO *ri;
- int i;
-
- i=OBJ_obj2nid(p7->type);
- if (i != NID_pkcs7_signedAndEnveloped)
- return NULL;
- if (p7->d.signed_and_enveloped == NULL)
- return NULL;
- rsk=p7->d.signed_and_enveloped->recipientinfo;
- if (rsk == NULL)
- return NULL;
- ri=sk_PKCS7_RECIP_INFO_value(rsk,0);
- if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return(NULL);
- ri=sk_PKCS7_RECIP_INFO_value(rsk,idx);
- return(ri->issuer_and_serial);
- }
-
-ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid)
- {
- return(get_attribute(si->auth_attr,nid));
- }
-
-ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid)
- {
- return(get_attribute(si->unauth_attr,nid));
- }
-
-static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid)
- {
- int i;
- X509_ATTRIBUTE *xa;
- ASN1_OBJECT *o;
-
- o=OBJ_nid2obj(nid);
- if (!o || !sk) return(NULL);
- for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++)
- {
- xa=sk_X509_ATTRIBUTE_value(sk,i);
- if (OBJ_cmp(xa->object,o) == 0)
- {
- if (!xa->single && sk_ASN1_TYPE_num(xa->value.set))
- return(sk_ASN1_TYPE_value(xa->value.set,0));
- else
- return(NULL);
- }
- }
- return(NULL);
- }
-
-ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk)
-{
- ASN1_TYPE *astype;
- if(!(astype = get_attribute(sk, NID_pkcs9_messageDigest))) return NULL;
- return astype->value.octet_string;
-}
-
-int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
- STACK_OF(X509_ATTRIBUTE) *sk)
- {
- int i;
-
- if (p7si->auth_attr != NULL)
- sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr,X509_ATTRIBUTE_free);
- p7si->auth_attr=sk_X509_ATTRIBUTE_dup(sk);
- if (p7si->auth_attr == NULL)
- return 0;
- for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++)
- {
- if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr,i,
- X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i))))
- == NULL)
- return(0);
- }
- return(1);
- }
-
-int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk)
- {
- int i;
-
- if (p7si->unauth_attr != NULL)
- sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr,
- X509_ATTRIBUTE_free);
- p7si->unauth_attr=sk_X509_ATTRIBUTE_dup(sk);
- if (p7si->unauth_attr == NULL)
- return 0;
- for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++)
- {
- if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr,i,
- X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i))))
- == NULL)
- return(0);
- }
- return(1);
- }
-
-int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
- void *value)
- {
- return(add_attribute(&(p7si->auth_attr),nid,atrtype,value));
- }
-
-int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
- void *value)
- {
- return(add_attribute(&(p7si->unauth_attr),nid,atrtype,value));
- }
-
-static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
- void *value)
- {
- X509_ATTRIBUTE *attr=NULL;
-
- if (*sk == NULL)
- {
- *sk = sk_X509_ATTRIBUTE_new_null();
- if (*sk == NULL)
- return 0;
-new_attrib:
- if (!(attr=X509_ATTRIBUTE_create(nid,atrtype,value)))
- return 0;
- if (!sk_X509_ATTRIBUTE_push(*sk,attr))
- {
- X509_ATTRIBUTE_free(attr);
- return 0;
- }
- }
- else
- {
- int i;
-
- for (i=0; i<sk_X509_ATTRIBUTE_num(*sk); i++)
- {
- attr=sk_X509_ATTRIBUTE_value(*sk,i);
- if (OBJ_obj2nid(attr->object) == nid)
- {
- X509_ATTRIBUTE_free(attr);
- attr=X509_ATTRIBUTE_create(nid,atrtype,value);
- if (attr == NULL)
- return 0;
- if (!sk_X509_ATTRIBUTE_set(*sk,i,attr))
- {
- X509_ATTRIBUTE_free(attr);
- return 0;
- }
- goto end;
- }
- }
- goto new_attrib;
- }
-end:
- return(1);
- }
-
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pkcs7.h b/drivers/builtin_openssl/crypto/pkcs7/pkcs7.h
deleted file mode 100644
index e4d443193c..0000000000
--- a/drivers/builtin_openssl/crypto/pkcs7/pkcs7.h
+++ /dev/null
@@ -1,499 +0,0 @@
-/* crypto/pkcs7/pkcs7.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_PKCS7_H
-#define HEADER_PKCS7_H
-
-#include <openssl/asn1.h>
-#include <openssl/bio.h>
-#include <openssl/e_os2.h>
-
-#include <openssl/symhacks.h>
-#include <openssl/ossl_typ.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_SYS_WIN32
-/* Under Win32 thes are defined in wincrypt.h */
-#undef PKCS7_ISSUER_AND_SERIAL
-#undef PKCS7_SIGNER_INFO
-#endif
-
-/*
-Encryption_ID DES-CBC
-Digest_ID MD5
-Digest_Encryption_ID rsaEncryption
-Key_Encryption_ID rsaEncryption
-*/
-
-typedef struct pkcs7_issuer_and_serial_st
- {
- X509_NAME *issuer;
- ASN1_INTEGER *serial;
- } PKCS7_ISSUER_AND_SERIAL;
-
-typedef struct pkcs7_signer_info_st
- {
- ASN1_INTEGER *version; /* version 1 */
- PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;
- X509_ALGOR *digest_alg;
- STACK_OF(X509_ATTRIBUTE) *auth_attr; /* [ 0 ] */
- X509_ALGOR *digest_enc_alg;
- ASN1_OCTET_STRING *enc_digest;
- STACK_OF(X509_ATTRIBUTE) *unauth_attr; /* [ 1 ] */
-
- /* The private key to sign with */
- EVP_PKEY *pkey;
- } PKCS7_SIGNER_INFO;
-
-DECLARE_STACK_OF(PKCS7_SIGNER_INFO)
-DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO)
-
-typedef struct pkcs7_recip_info_st
- {
- ASN1_INTEGER *version; /* version 0 */
- PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;
- X509_ALGOR *key_enc_algor;
- ASN1_OCTET_STRING *enc_key;
- X509 *cert; /* get the pub-key from this */
- } PKCS7_RECIP_INFO;
-
-DECLARE_STACK_OF(PKCS7_RECIP_INFO)
-DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO)
-
-typedef struct pkcs7_signed_st
- {
- ASN1_INTEGER *version; /* version 1 */
- STACK_OF(X509_ALGOR) *md_algs; /* md used */
- STACK_OF(X509) *cert; /* [ 0 ] */
- STACK_OF(X509_CRL) *crl; /* [ 1 ] */
- STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
-
- struct pkcs7_st *contents;
- } PKCS7_SIGNED;
-/* The above structure is very very similar to PKCS7_SIGN_ENVELOPE.
- * How about merging the two */
-
-typedef struct pkcs7_enc_content_st
- {
- ASN1_OBJECT *content_type;
- X509_ALGOR *algorithm;
- ASN1_OCTET_STRING *enc_data; /* [ 0 ] */
- const EVP_CIPHER *cipher;
- } PKCS7_ENC_CONTENT;
-
-typedef struct pkcs7_enveloped_st
- {
- ASN1_INTEGER *version; /* version 0 */
- STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
- PKCS7_ENC_CONTENT *enc_data;
- } PKCS7_ENVELOPE;
-
-typedef struct pkcs7_signedandenveloped_st
- {
- ASN1_INTEGER *version; /* version 1 */
- STACK_OF(X509_ALGOR) *md_algs; /* md used */
- STACK_OF(X509) *cert; /* [ 0 ] */
- STACK_OF(X509_CRL) *crl; /* [ 1 ] */
- STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
-
- PKCS7_ENC_CONTENT *enc_data;
- STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
- } PKCS7_SIGN_ENVELOPE;
-
-typedef struct pkcs7_digest_st
- {
- ASN1_INTEGER *version; /* version 0 */
- X509_ALGOR *md; /* md used */
- struct pkcs7_st *contents;
- ASN1_OCTET_STRING *digest;
- } PKCS7_DIGEST;
-
-typedef struct pkcs7_encrypted_st
- {
- ASN1_INTEGER *version; /* version 0 */
- PKCS7_ENC_CONTENT *enc_data;
- } PKCS7_ENCRYPT;
-
-typedef struct pkcs7_st
- {
- /* The following is non NULL if it contains ASN1 encoding of
- * this structure */
- unsigned char *asn1;
- long length;
-
-#define PKCS7_S_HEADER 0
-#define PKCS7_S_BODY 1
-#define PKCS7_S_TAIL 2
- int state; /* used during processing */
-
- int detached;
-
- ASN1_OBJECT *type;
- /* content as defined by the type */
- /* all encryption/message digests are applied to the 'contents',
- * leaving out the 'type' field. */
- union {
- char *ptr;
-
- /* NID_pkcs7_data */
- ASN1_OCTET_STRING *data;
-
- /* NID_pkcs7_signed */
- PKCS7_SIGNED *sign;
-
- /* NID_pkcs7_enveloped */
- PKCS7_ENVELOPE *enveloped;
-
- /* NID_pkcs7_signedAndEnveloped */
- PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
-
- /* NID_pkcs7_digest */
- PKCS7_DIGEST *digest;
-
- /* NID_pkcs7_encrypted */
- PKCS7_ENCRYPT *encrypted;
-
- /* Anything else */
- ASN1_TYPE *other;
- } d;
- } PKCS7;
-
-DECLARE_STACK_OF(PKCS7)
-DECLARE_ASN1_SET_OF(PKCS7)
-DECLARE_PKCS12_STACK_OF(PKCS7)
-
-#define PKCS7_OP_SET_DETACHED_SIGNATURE 1
-#define PKCS7_OP_GET_DETACHED_SIGNATURE 2
-
-#define PKCS7_get_signed_attributes(si) ((si)->auth_attr)
-#define PKCS7_get_attributes(si) ((si)->unauth_attr)
-
-#define PKCS7_type_is_signed(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_signed)
-#define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
-#define PKCS7_type_is_enveloped(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_enveloped)
-#define PKCS7_type_is_signedAndEnveloped(a) \
- (OBJ_obj2nid((a)->type) == NID_pkcs7_signedAndEnveloped)
-#define PKCS7_type_is_data(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_data)
-#define PKCS7_type_is_digest(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
-#define PKCS7_type_is_encrypted(a) \
- (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
-
-#define PKCS7_type_is_digest(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
-
-#define PKCS7_set_detached(p,v) \
- PKCS7_ctrl(p,PKCS7_OP_SET_DETACHED_SIGNATURE,v,NULL)
-#define PKCS7_get_detached(p) \
- PKCS7_ctrl(p,PKCS7_OP_GET_DETACHED_SIGNATURE,0,NULL)
-
-#define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7))
-
-/* S/MIME related flags */
-
-#define PKCS7_TEXT 0x1
-#define PKCS7_NOCERTS 0x2
-#define PKCS7_NOSIGS 0x4
-#define PKCS7_NOCHAIN 0x8
-#define PKCS7_NOINTERN 0x10
-#define PKCS7_NOVERIFY 0x20
-#define PKCS7_DETACHED 0x40
-#define PKCS7_BINARY 0x80
-#define PKCS7_NOATTR 0x100
-#define PKCS7_NOSMIMECAP 0x200
-#define PKCS7_NOOLDMIMETYPE 0x400
-#define PKCS7_CRLFEOL 0x800
-#define PKCS7_STREAM 0x1000
-#define PKCS7_NOCRL 0x2000
-#define PKCS7_PARTIAL 0x4000
-#define PKCS7_REUSE_DIGEST 0x8000
-
-/* Flags: for compatibility with older code */
-
-#define SMIME_TEXT PKCS7_TEXT
-#define SMIME_NOCERTS PKCS7_NOCERTS
-#define SMIME_NOSIGS PKCS7_NOSIGS
-#define SMIME_NOCHAIN PKCS7_NOCHAIN
-#define SMIME_NOINTERN PKCS7_NOINTERN
-#define SMIME_NOVERIFY PKCS7_NOVERIFY
-#define SMIME_DETACHED PKCS7_DETACHED
-#define SMIME_BINARY PKCS7_BINARY
-#define SMIME_NOATTR PKCS7_NOATTR
-
-DECLARE_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL)
-
-int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data,const EVP_MD *type,
- unsigned char *md,unsigned int *len);
-#ifndef OPENSSL_NO_FP_API
-PKCS7 *d2i_PKCS7_fp(FILE *fp,PKCS7 **p7);
-int i2d_PKCS7_fp(FILE *fp,PKCS7 *p7);
-#endif
-PKCS7 *PKCS7_dup(PKCS7 *p7);
-PKCS7 *d2i_PKCS7_bio(BIO *bp,PKCS7 **p7);
-int i2d_PKCS7_bio(BIO *bp,PKCS7 *p7);
-int i2d_PKCS7_bio_stream(BIO *out, PKCS7 *p7, BIO *in, int flags);
-int PEM_write_bio_PKCS7_stream(BIO *out, PKCS7 *p7, BIO *in, int flags);
-
-DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNER_INFO)
-DECLARE_ASN1_FUNCTIONS(PKCS7_RECIP_INFO)
-DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNED)
-DECLARE_ASN1_FUNCTIONS(PKCS7_ENC_CONTENT)
-DECLARE_ASN1_FUNCTIONS(PKCS7_ENVELOPE)
-DECLARE_ASN1_FUNCTIONS(PKCS7_SIGN_ENVELOPE)
-DECLARE_ASN1_FUNCTIONS(PKCS7_DIGEST)
-DECLARE_ASN1_FUNCTIONS(PKCS7_ENCRYPT)
-DECLARE_ASN1_FUNCTIONS(PKCS7)
-
-DECLARE_ASN1_ITEM(PKCS7_ATTR_SIGN)
-DECLARE_ASN1_ITEM(PKCS7_ATTR_VERIFY)
-
-DECLARE_ASN1_NDEF_FUNCTION(PKCS7)
-DECLARE_ASN1_PRINT_FUNCTION(PKCS7)
-
-long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg);
-
-int PKCS7_set_type(PKCS7 *p7, int type);
-int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other);
-int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data);
-int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey,
- const EVP_MD *dgst);
-int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si);
-int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *p7i);
-int PKCS7_add_certificate(PKCS7 *p7, X509 *x509);
-int PKCS7_add_crl(PKCS7 *p7, X509_CRL *x509);
-int PKCS7_content_new(PKCS7 *p7, int nid);
-int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx,
- BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si);
-int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
- X509 *x509);
-
-BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio);
-int PKCS7_dataFinal(PKCS7 *p7, BIO *bio);
-BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert);
-
-
-PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509,
- EVP_PKEY *pkey, const EVP_MD *dgst);
-X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
-int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md);
-STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7);
-
-PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509);
-void PKCS7_SIGNER_INFO_get0_algs(PKCS7_SIGNER_INFO *si, EVP_PKEY **pk,
- X509_ALGOR **pdig, X509_ALGOR **psig);
-void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc);
-int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri);
-int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509);
-int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher);
-int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7);
-
-PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx);
-ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk);
-int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si,int nid,int type,
- void *data);
-int PKCS7_add_attribute (PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
- void *value);
-ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid);
-ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid);
-int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
- STACK_OF(X509_ATTRIBUTE) *sk);
-int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,STACK_OF(X509_ATTRIBUTE) *sk);
-
-
-PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
- BIO *data, int flags);
-
-PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7,
- X509 *signcert, EVP_PKEY *pkey, const EVP_MD *md,
- int flags);
-
-int PKCS7_final(PKCS7 *p7, BIO *data, int flags);
-int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
- BIO *indata, BIO *out, int flags);
-STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags);
-PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
- int flags);
-int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags);
-
-int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si,
- STACK_OF(X509_ALGOR) *cap);
-STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si);
-int PKCS7_simple_smimecap(STACK_OF(X509_ALGOR) *sk, int nid, int arg);
-
-int PKCS7_add_attrib_content_type(PKCS7_SIGNER_INFO *si, ASN1_OBJECT *coid);
-int PKCS7_add0_attrib_signing_time(PKCS7_SIGNER_INFO *si, ASN1_TIME *t);
-int PKCS7_add1_attrib_digest(PKCS7_SIGNER_INFO *si,
- const unsigned char *md, int mdlen);
-
-int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags);
-PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont);
-
-BIO *BIO_new_PKCS7(BIO *out, PKCS7 *p7);
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_PKCS7_strings(void);
-
-/* Error codes for the PKCS7 functions. */
-
-/* Function codes. */
-#define PKCS7_F_B64_READ_PKCS7 120
-#define PKCS7_F_B64_WRITE_PKCS7 121
-#define PKCS7_F_DO_PKCS7_SIGNED_ATTRIB 136
-#define PKCS7_F_I2D_PKCS7_BIO_STREAM 140
-#define PKCS7_F_PKCS7_ADD0_ATTRIB_SIGNING_TIME 135
-#define PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP 118
-#define PKCS7_F_PKCS7_ADD_CERTIFICATE 100
-#define PKCS7_F_PKCS7_ADD_CRL 101
-#define PKCS7_F_PKCS7_ADD_RECIPIENT_INFO 102
-#define PKCS7_F_PKCS7_ADD_SIGNATURE 131
-#define PKCS7_F_PKCS7_ADD_SIGNER 103
-#define PKCS7_F_PKCS7_BIO_ADD_DIGEST 125
-#define PKCS7_F_PKCS7_COPY_EXISTING_DIGEST 138
-#define PKCS7_F_PKCS7_CTRL 104
-#define PKCS7_F_PKCS7_DATADECODE 112
-#define PKCS7_F_PKCS7_DATAFINAL 128
-#define PKCS7_F_PKCS7_DATAINIT 105
-#define PKCS7_F_PKCS7_DATASIGN 106
-#define PKCS7_F_PKCS7_DATAVERIFY 107
-#define PKCS7_F_PKCS7_DECRYPT 114
-#define PKCS7_F_PKCS7_DECRYPT_RINFO 133
-#define PKCS7_F_PKCS7_ENCODE_RINFO 132
-#define PKCS7_F_PKCS7_ENCRYPT 115
-#define PKCS7_F_PKCS7_FINAL 134
-#define PKCS7_F_PKCS7_FIND_DIGEST 127
-#define PKCS7_F_PKCS7_GET0_SIGNERS 124
-#define PKCS7_F_PKCS7_RECIP_INFO_SET 130
-#define PKCS7_F_PKCS7_SET_CIPHER 108
-#define PKCS7_F_PKCS7_SET_CONTENT 109
-#define PKCS7_F_PKCS7_SET_DIGEST 126
-#define PKCS7_F_PKCS7_SET_TYPE 110
-#define PKCS7_F_PKCS7_SIGN 116
-#define PKCS7_F_PKCS7_SIGNATUREVERIFY 113
-#define PKCS7_F_PKCS7_SIGNER_INFO_SET 129
-#define PKCS7_F_PKCS7_SIGNER_INFO_SIGN 139
-#define PKCS7_F_PKCS7_SIGN_ADD_SIGNER 137
-#define PKCS7_F_PKCS7_SIMPLE_SMIMECAP 119
-#define PKCS7_F_PKCS7_VERIFY 117
-#define PKCS7_F_SMIME_READ_PKCS7 122
-#define PKCS7_F_SMIME_TEXT 123
-
-/* Reason codes. */
-#define PKCS7_R_CERTIFICATE_VERIFY_ERROR 117
-#define PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 144
-#define PKCS7_R_CIPHER_NOT_INITIALIZED 116
-#define PKCS7_R_CONTENT_AND_DATA_PRESENT 118
-#define PKCS7_R_CTRL_ERROR 152
-#define PKCS7_R_DECODE_ERROR 130
-#define PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH 100
-#define PKCS7_R_DECRYPT_ERROR 119
-#define PKCS7_R_DIGEST_FAILURE 101
-#define PKCS7_R_ENCRYPTION_CTRL_FAILURE 149
-#define PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 150
-#define PKCS7_R_ERROR_ADDING_RECIPIENT 120
-#define PKCS7_R_ERROR_SETTING_CIPHER 121
-#define PKCS7_R_INVALID_MIME_TYPE 131
-#define PKCS7_R_INVALID_NULL_POINTER 143
-#define PKCS7_R_MIME_NO_CONTENT_TYPE 132
-#define PKCS7_R_MIME_PARSE_ERROR 133
-#define PKCS7_R_MIME_SIG_PARSE_ERROR 134
-#define PKCS7_R_MISSING_CERIPEND_INFO 103
-#define PKCS7_R_NO_CONTENT 122
-#define PKCS7_R_NO_CONTENT_TYPE 135
-#define PKCS7_R_NO_DEFAULT_DIGEST 151
-#define PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND 154
-#define PKCS7_R_NO_MULTIPART_BODY_FAILURE 136
-#define PKCS7_R_NO_MULTIPART_BOUNDARY 137
-#define PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE 115
-#define PKCS7_R_NO_RECIPIENT_MATCHES_KEY 146
-#define PKCS7_R_NO_SIGNATURES_ON_DATA 123
-#define PKCS7_R_NO_SIGNERS 142
-#define PKCS7_R_NO_SIG_CONTENT_TYPE 138
-#define PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE 104
-#define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR 124
-#define PKCS7_R_PKCS7_ADD_SIGNER_ERROR 153
-#define PKCS7_R_PKCS7_DATAFINAL 126
-#define PKCS7_R_PKCS7_DATAFINAL_ERROR 125
-#define PKCS7_R_PKCS7_DATASIGN 145
-#define PKCS7_R_PKCS7_PARSE_ERROR 139
-#define PKCS7_R_PKCS7_SIG_PARSE_ERROR 140
-#define PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 127
-#define PKCS7_R_SIGNATURE_FAILURE 105
-#define PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND 128
-#define PKCS7_R_SIGNING_CTRL_FAILURE 147
-#define PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 148
-#define PKCS7_R_SIG_INVALID_MIME_TYPE 141
-#define PKCS7_R_SMIME_TEXT_ERROR 129
-#define PKCS7_R_UNABLE_TO_FIND_CERTIFICATE 106
-#define PKCS7_R_UNABLE_TO_FIND_MEM_BIO 107
-#define PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST 108
-#define PKCS7_R_UNKNOWN_DIGEST_TYPE 109
-#define PKCS7_R_UNKNOWN_OPERATION 110
-#define PKCS7_R_UNSUPPORTED_CIPHER_TYPE 111
-#define PKCS7_R_UNSUPPORTED_CONTENT_TYPE 112
-#define PKCS7_R_WRONG_CONTENT_TYPE 113
-#define PKCS7_R_WRONG_PKCS7_TYPE 114
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pkcs7err.c b/drivers/builtin_openssl/crypto/pkcs7/pkcs7err.c
deleted file mode 100644
index d0af32a265..0000000000
--- a/drivers/builtin_openssl/crypto/pkcs7/pkcs7err.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/* crypto/pkcs7/pkcs7err.c */
-/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-/* NOTE: this file was auto generated by the mkerr.pl script: any changes
- * made to it will be overwritten when the script next updates this file,
- * only reason strings will be preserved.
- */
-
-#include <stdio.h>
-#include <openssl/err.h>
-#include <openssl/pkcs7.h>
-
-/* BEGIN ERROR CODES */
-#ifndef OPENSSL_NO_ERR
-
-#define ERR_FUNC(func) ERR_PACK(ERR_LIB_PKCS7,func,0)
-#define ERR_REASON(reason) ERR_PACK(ERR_LIB_PKCS7,0,reason)
-
-static ERR_STRING_DATA PKCS7_str_functs[]=
- {
-{ERR_FUNC(PKCS7_F_B64_READ_PKCS7), "B64_READ_PKCS7"},
-{ERR_FUNC(PKCS7_F_B64_WRITE_PKCS7), "B64_WRITE_PKCS7"},
-{ERR_FUNC(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB), "DO_PKCS7_SIGNED_ATTRIB"},
-{ERR_FUNC(PKCS7_F_I2D_PKCS7_BIO_STREAM), "i2d_PKCS7_bio_stream"},
-{ERR_FUNC(PKCS7_F_PKCS7_ADD0_ATTRIB_SIGNING_TIME), "PKCS7_add0_attrib_signing_time"},
-{ERR_FUNC(PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP), "PKCS7_add_attrib_smimecap"},
-{ERR_FUNC(PKCS7_F_PKCS7_ADD_CERTIFICATE), "PKCS7_add_certificate"},
-{ERR_FUNC(PKCS7_F_PKCS7_ADD_CRL), "PKCS7_add_crl"},
-{ERR_FUNC(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO), "PKCS7_add_recipient_info"},
-{ERR_FUNC(PKCS7_F_PKCS7_ADD_SIGNATURE), "PKCS7_add_signature"},
-{ERR_FUNC(PKCS7_F_PKCS7_ADD_SIGNER), "PKCS7_add_signer"},
-{ERR_FUNC(PKCS7_F_PKCS7_BIO_ADD_DIGEST), "PKCS7_BIO_ADD_DIGEST"},
-{ERR_FUNC(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST), "PKCS7_COPY_EXISTING_DIGEST"},
-{ERR_FUNC(PKCS7_F_PKCS7_CTRL), "PKCS7_ctrl"},
-{ERR_FUNC(PKCS7_F_PKCS7_DATADECODE), "PKCS7_dataDecode"},
-{ERR_FUNC(PKCS7_F_PKCS7_DATAFINAL), "PKCS7_dataFinal"},
-{ERR_FUNC(PKCS7_F_PKCS7_DATAINIT), "PKCS7_dataInit"},
-{ERR_FUNC(PKCS7_F_PKCS7_DATASIGN), "PKCS7_DATASIGN"},
-{ERR_FUNC(PKCS7_F_PKCS7_DATAVERIFY), "PKCS7_dataVerify"},
-{ERR_FUNC(PKCS7_F_PKCS7_DECRYPT), "PKCS7_decrypt"},
-{ERR_FUNC(PKCS7_F_PKCS7_DECRYPT_RINFO), "PKCS7_DECRYPT_RINFO"},
-{ERR_FUNC(PKCS7_F_PKCS7_ENCODE_RINFO), "PKCS7_ENCODE_RINFO"},
-{ERR_FUNC(PKCS7_F_PKCS7_ENCRYPT), "PKCS7_encrypt"},
-{ERR_FUNC(PKCS7_F_PKCS7_FINAL), "PKCS7_final"},
-{ERR_FUNC(PKCS7_F_PKCS7_FIND_DIGEST), "PKCS7_FIND_DIGEST"},
-{ERR_FUNC(PKCS7_F_PKCS7_GET0_SIGNERS), "PKCS7_get0_signers"},
-{ERR_FUNC(PKCS7_F_PKCS7_RECIP_INFO_SET), "PKCS7_RECIP_INFO_set"},
-{ERR_FUNC(PKCS7_F_PKCS7_SET_CIPHER), "PKCS7_set_cipher"},
-{ERR_FUNC(PKCS7_F_PKCS7_SET_CONTENT), "PKCS7_set_content"},
-{ERR_FUNC(PKCS7_F_PKCS7_SET_DIGEST), "PKCS7_set_digest"},
-{ERR_FUNC(PKCS7_F_PKCS7_SET_TYPE), "PKCS7_set_type"},
-{ERR_FUNC(PKCS7_F_PKCS7_SIGN), "PKCS7_sign"},
-{ERR_FUNC(PKCS7_F_PKCS7_SIGNATUREVERIFY), "PKCS7_signatureVerify"},
-{ERR_FUNC(PKCS7_F_PKCS7_SIGNER_INFO_SET), "PKCS7_SIGNER_INFO_set"},
-{ERR_FUNC(PKCS7_F_PKCS7_SIGNER_INFO_SIGN), "PKCS7_SIGNER_INFO_sign"},
-{ERR_FUNC(PKCS7_F_PKCS7_SIGN_ADD_SIGNER), "PKCS7_sign_add_signer"},
-{ERR_FUNC(PKCS7_F_PKCS7_SIMPLE_SMIMECAP), "PKCS7_simple_smimecap"},
-{ERR_FUNC(PKCS7_F_PKCS7_VERIFY), "PKCS7_verify"},
-{ERR_FUNC(PKCS7_F_SMIME_READ_PKCS7), "SMIME_read_PKCS7"},
-{ERR_FUNC(PKCS7_F_SMIME_TEXT), "SMIME_text"},
-{0,NULL}
- };
-
-static ERR_STRING_DATA PKCS7_str_reasons[]=
- {
-{ERR_REASON(PKCS7_R_CERTIFICATE_VERIFY_ERROR),"certificate verify error"},
-{ERR_REASON(PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER),"cipher has no object identifier"},
-{ERR_REASON(PKCS7_R_CIPHER_NOT_INITIALIZED),"cipher not initialized"},
-{ERR_REASON(PKCS7_R_CONTENT_AND_DATA_PRESENT),"content and data present"},
-{ERR_REASON(PKCS7_R_CTRL_ERROR) ,"ctrl error"},
-{ERR_REASON(PKCS7_R_DECODE_ERROR) ,"decode error"},
-{ERR_REASON(PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH),"decrypted key is wrong length"},
-{ERR_REASON(PKCS7_R_DECRYPT_ERROR) ,"decrypt error"},
-{ERR_REASON(PKCS7_R_DIGEST_FAILURE) ,"digest failure"},
-{ERR_REASON(PKCS7_R_ENCRYPTION_CTRL_FAILURE),"encryption ctrl failure"},
-{ERR_REASON(PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"encryption not supported for this key type"},
-{ERR_REASON(PKCS7_R_ERROR_ADDING_RECIPIENT),"error adding recipient"},
-{ERR_REASON(PKCS7_R_ERROR_SETTING_CIPHER),"error setting cipher"},
-{ERR_REASON(PKCS7_R_INVALID_MIME_TYPE) ,"invalid mime type"},
-{ERR_REASON(PKCS7_R_INVALID_NULL_POINTER),"invalid null pointer"},
-{ERR_REASON(PKCS7_R_MIME_NO_CONTENT_TYPE),"mime no content type"},
-{ERR_REASON(PKCS7_R_MIME_PARSE_ERROR) ,"mime parse error"},
-{ERR_REASON(PKCS7_R_MIME_SIG_PARSE_ERROR),"mime sig parse error"},
-{ERR_REASON(PKCS7_R_MISSING_CERIPEND_INFO),"missing ceripend info"},
-{ERR_REASON(PKCS7_R_NO_CONTENT) ,"no content"},
-{ERR_REASON(PKCS7_R_NO_CONTENT_TYPE) ,"no content type"},
-{ERR_REASON(PKCS7_R_NO_DEFAULT_DIGEST) ,"no default digest"},
-{ERR_REASON(PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND),"no matching digest type found"},
-{ERR_REASON(PKCS7_R_NO_MULTIPART_BODY_FAILURE),"no multipart body failure"},
-{ERR_REASON(PKCS7_R_NO_MULTIPART_BOUNDARY),"no multipart boundary"},
-{ERR_REASON(PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE),"no recipient matches certificate"},
-{ERR_REASON(PKCS7_R_NO_RECIPIENT_MATCHES_KEY),"no recipient matches key"},
-{ERR_REASON(PKCS7_R_NO_SIGNATURES_ON_DATA),"no signatures on data"},
-{ERR_REASON(PKCS7_R_NO_SIGNERS) ,"no signers"},
-{ERR_REASON(PKCS7_R_NO_SIG_CONTENT_TYPE) ,"no sig content type"},
-{ERR_REASON(PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE),"operation not supported on this type"},
-{ERR_REASON(PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR),"pkcs7 add signature error"},
-{ERR_REASON(PKCS7_R_PKCS7_ADD_SIGNER_ERROR),"pkcs7 add signer error"},
-{ERR_REASON(PKCS7_R_PKCS7_DATAFINAL) ,"pkcs7 datafinal"},
-{ERR_REASON(PKCS7_R_PKCS7_DATAFINAL_ERROR),"pkcs7 datafinal error"},
-{ERR_REASON(PKCS7_R_PKCS7_DATASIGN) ,"pkcs7 datasign"},
-{ERR_REASON(PKCS7_R_PKCS7_PARSE_ERROR) ,"pkcs7 parse error"},
-{ERR_REASON(PKCS7_R_PKCS7_SIG_PARSE_ERROR),"pkcs7 sig parse error"},
-{ERR_REASON(PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),"private key does not match certificate"},
-{ERR_REASON(PKCS7_R_SIGNATURE_FAILURE) ,"signature failure"},
-{ERR_REASON(PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND),"signer certificate not found"},
-{ERR_REASON(PKCS7_R_SIGNING_CTRL_FAILURE),"signing ctrl failure"},
-{ERR_REASON(PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"signing not supported for this key type"},
-{ERR_REASON(PKCS7_R_SIG_INVALID_MIME_TYPE),"sig invalid mime type"},
-{ERR_REASON(PKCS7_R_SMIME_TEXT_ERROR) ,"smime text error"},
-{ERR_REASON(PKCS7_R_UNABLE_TO_FIND_CERTIFICATE),"unable to find certificate"},
-{ERR_REASON(PKCS7_R_UNABLE_TO_FIND_MEM_BIO),"unable to find mem bio"},
-{ERR_REASON(PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST),"unable to find message digest"},
-{ERR_REASON(PKCS7_R_UNKNOWN_DIGEST_TYPE) ,"unknown digest type"},
-{ERR_REASON(PKCS7_R_UNKNOWN_OPERATION) ,"unknown operation"},
-{ERR_REASON(PKCS7_R_UNSUPPORTED_CIPHER_TYPE),"unsupported cipher type"},
-{ERR_REASON(PKCS7_R_UNSUPPORTED_CONTENT_TYPE),"unsupported content type"},
-{ERR_REASON(PKCS7_R_WRONG_CONTENT_TYPE) ,"wrong content type"},
-{ERR_REASON(PKCS7_R_WRONG_PKCS7_TYPE) ,"wrong pkcs7 type"},
-{0,NULL}
- };
-
-#endif
-
-void ERR_load_PKCS7_strings(void)
- {
-#ifndef OPENSSL_NO_ERR
-
- if (ERR_func_error_string(PKCS7_str_functs[0].error) == NULL)
- {
- ERR_load_strings(0,PKCS7_str_functs);
- ERR_load_strings(0,PKCS7_str_reasons);
- }
-#endif
- }
diff --git a/drivers/builtin_openssl/crypto/rand/rand.h b/drivers/builtin_openssl/crypto/rand/rand.h
deleted file mode 100644
index bb5520e80a..0000000000
--- a/drivers/builtin_openssl/crypto/rand/rand.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* crypto/rand/rand.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_RAND_H
-#define HEADER_RAND_H
-
-#include <stdlib.h>
-#include <openssl/ossl_typ.h>
-#include <openssl/e_os2.h>
-
-#if defined(OPENSSL_SYS_WINDOWS)
-#include <windows.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(OPENSSL_FIPS)
-#define FIPS_RAND_SIZE_T size_t
-#endif
-
-/* Already defined in ossl_typ.h */
-/* typedef struct rand_meth_st RAND_METHOD; */
-
-struct rand_meth_st
- {
- void (*seed)(const void *buf, int num);
- int (*bytes)(unsigned char *buf, int num);
- void (*cleanup)(void);
- void (*add)(const void *buf, int num, double entropy);
- int (*pseudorand)(unsigned char *buf, int num);
- int (*status)(void);
- };
-
-#ifdef BN_DEBUG
-extern int rand_predictable;
-#endif
-
-int RAND_set_rand_method(const RAND_METHOD *meth);
-const RAND_METHOD *RAND_get_rand_method(void);
-#ifndef OPENSSL_NO_ENGINE
-int RAND_set_rand_engine(ENGINE *engine);
-#endif
-RAND_METHOD *RAND_SSLeay(void);
-void RAND_cleanup(void );
-int RAND_bytes(unsigned char *buf,int num);
-int RAND_pseudo_bytes(unsigned char *buf,int num);
-void RAND_seed(const void *buf,int num);
-void RAND_add(const void *buf,int num,double entropy);
-int RAND_load_file(const char *file,long max_bytes);
-int RAND_write_file(const char *file);
-const char *RAND_file_name(char *file,size_t num);
-int RAND_status(void);
-int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes);
-int RAND_egd(const char *path);
-int RAND_egd_bytes(const char *path,int bytes);
-int RAND_poll(void);
-
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-
-void RAND_screen(void);
-int RAND_event(UINT, WPARAM, LPARAM);
-
-#endif
-
-#ifdef OPENSSL_FIPS
-void RAND_set_fips_drbg_type(int type, int flags);
-int RAND_init_fips(void);
-#endif
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_RAND_strings(void);
-
-/* Error codes for the RAND functions. */
-
-/* Function codes. */
-#define RAND_F_RAND_GET_RAND_METHOD 101
-#define RAND_F_RAND_INIT_FIPS 102
-#define RAND_F_SSLEAY_RAND_BYTES 100
-
-/* Reason codes. */
-#define RAND_R_DUAL_EC_DRBG_DISABLED 104
-#define RAND_R_ERROR_INITIALISING_DRBG 102
-#define RAND_R_ERROR_INSTANTIATING_DRBG 103
-#define RAND_R_NO_FIPS_RANDOM_METHOD_SET 101
-#define RAND_R_PRNG_NOT_SEEDED 100
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_ameth.c b/drivers/builtin_openssl/crypto/rsa/rsa_ameth.c
deleted file mode 100644
index 5a2062f903..0000000000
--- a/drivers/builtin_openssl/crypto/rsa/rsa_ameth.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/* crypto/rsa/rsa_ameth.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 2006.
- */
-/* ====================================================================
- * Copyright (c) 2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/asn1t.h>
-#include <openssl/x509.h>
-#include <openssl/rsa.h>
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_CMS
-#include <openssl/cms.h>
-#endif
-#include "asn1_locl.h"
-
-static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
- {
- unsigned char *penc = NULL;
- int penclen;
- penclen = i2d_RSAPublicKey(pkey->pkey.rsa, &penc);
- if (penclen <= 0)
- return 0;
- if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA),
- V_ASN1_NULL, NULL, penc, penclen))
- return 1;
-
- OPENSSL_free(penc);
- return 0;
- }
-
-static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
- {
- const unsigned char *p;
- int pklen;
- RSA *rsa = NULL;
- if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey))
- return 0;
- if (!(rsa = d2i_RSAPublicKey(NULL, &p, pklen)))
- {
- RSAerr(RSA_F_RSA_PUB_DECODE, ERR_R_RSA_LIB);
- return 0;
- }
- EVP_PKEY_assign_RSA (pkey, rsa);
- return 1;
- }
-
-static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
- {
- if (BN_cmp(b->pkey.rsa->n,a->pkey.rsa->n) != 0
- || BN_cmp(b->pkey.rsa->e,a->pkey.rsa->e) != 0)
- return 0;
- return 1;
- }
-
-static int old_rsa_priv_decode(EVP_PKEY *pkey,
- const unsigned char **pder, int derlen)
- {
- RSA *rsa;
- if (!(rsa = d2i_RSAPrivateKey (NULL, pder, derlen)))
- {
- RSAerr(RSA_F_OLD_RSA_PRIV_DECODE, ERR_R_RSA_LIB);
- return 0;
- }
- EVP_PKEY_assign_RSA(pkey, rsa);
- return 1;
- }
-
-static int old_rsa_priv_encode(const EVP_PKEY *pkey, unsigned char **pder)
- {
- return i2d_RSAPrivateKey(pkey->pkey.rsa, pder);
- }
-
-static int rsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
- {
- unsigned char *rk = NULL;
- int rklen;
- rklen = i2d_RSAPrivateKey(pkey->pkey.rsa, &rk);
-
- if (rklen <= 0)
- {
- RSAerr(RSA_F_RSA_PRIV_ENCODE,ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_rsaEncryption), 0,
- V_ASN1_NULL, NULL, rk, rklen))
- {
- RSAerr(RSA_F_RSA_PRIV_ENCODE,ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- return 1;
- }
-
-static int rsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
- {
- const unsigned char *p;
- int pklen;
- if (!PKCS8_pkey_get0(NULL, &p, &pklen, NULL, p8))
- return 0;
- return old_rsa_priv_decode(pkey, &p, pklen);
- }
-
-static int int_rsa_size(const EVP_PKEY *pkey)
- {
- return RSA_size(pkey->pkey.rsa);
- }
-
-static int rsa_bits(const EVP_PKEY *pkey)
- {
- return BN_num_bits(pkey->pkey.rsa->n);
- }
-
-static void int_rsa_free(EVP_PKEY *pkey)
- {
- RSA_free(pkey->pkey.rsa);
- }
-
-
-static void update_buflen(const BIGNUM *b, size_t *pbuflen)
- {
- size_t i;
- if (!b)
- return;
- if (*pbuflen < (i = (size_t)BN_num_bytes(b)))
- *pbuflen = i;
- }
-
-static int do_rsa_print(BIO *bp, const RSA *x, int off, int priv)
- {
- char *str;
- const char *s;
- unsigned char *m=NULL;
- int ret=0, mod_len = 0;
- size_t buf_len=0;
-
- update_buflen(x->n, &buf_len);
- update_buflen(x->e, &buf_len);
-
- if (priv)
- {
- update_buflen(x->d, &buf_len);
- update_buflen(x->p, &buf_len);
- update_buflen(x->q, &buf_len);
- update_buflen(x->dmp1, &buf_len);
- update_buflen(x->dmq1, &buf_len);
- update_buflen(x->iqmp, &buf_len);
- }
-
- m=(unsigned char *)OPENSSL_malloc(buf_len+10);
- if (m == NULL)
- {
- RSAerr(RSA_F_DO_RSA_PRINT,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (x->n != NULL)
- mod_len = BN_num_bits(x->n);
-
- if(!BIO_indent(bp,off,128))
- goto err;
-
- if (priv && x->d)
- {
- if (BIO_printf(bp,"Private-Key: (%d bit)\n", mod_len)
- <= 0) goto err;
- str = "modulus:";
- s = "publicExponent:";
- }
- else
- {
- if (BIO_printf(bp,"Public-Key: (%d bit)\n", mod_len)
- <= 0) goto err;
- str = "Modulus:";
- s= "Exponent:";
- }
- if (!ASN1_bn_print(bp,str,x->n,m,off)) goto err;
- if (!ASN1_bn_print(bp,s,x->e,m,off))
- goto err;
- if (priv)
- {
- if (!ASN1_bn_print(bp,"privateExponent:",x->d,m,off))
- goto err;
- if (!ASN1_bn_print(bp,"prime1:",x->p,m,off))
- goto err;
- if (!ASN1_bn_print(bp,"prime2:",x->q,m,off))
- goto err;
- if (!ASN1_bn_print(bp,"exponent1:",x->dmp1,m,off))
- goto err;
- if (!ASN1_bn_print(bp,"exponent2:",x->dmq1,m,off))
- goto err;
- if (!ASN1_bn_print(bp,"coefficient:",x->iqmp,m,off))
- goto err;
- }
- ret=1;
-err:
- if (m != NULL) OPENSSL_free(m);
- return(ret);
- }
-
-static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx)
- {
- return do_rsa_print(bp, pkey->pkey.rsa, indent, 0);
- }
-
-
-static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx)
- {
- return do_rsa_print(bp, pkey->pkey.rsa, indent, 1);
- }
-
-static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg,
- X509_ALGOR **pmaskHash)
- {
- const unsigned char *p;
- int plen;
- RSA_PSS_PARAMS *pss;
-
- *pmaskHash = NULL;
-
- if (!alg->parameter || alg->parameter->type != V_ASN1_SEQUENCE)
- return NULL;
- p = alg->parameter->value.sequence->data;
- plen = alg->parameter->value.sequence->length;
- pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen);
-
- if (!pss)
- return NULL;
-
- if (pss->maskGenAlgorithm)
- {
- ASN1_TYPE *param = pss->maskGenAlgorithm->parameter;
- if (OBJ_obj2nid(pss->maskGenAlgorithm->algorithm) == NID_mgf1
- && param->type == V_ASN1_SEQUENCE)
- {
- p = param->value.sequence->data;
- plen = param->value.sequence->length;
- *pmaskHash = d2i_X509_ALGOR(NULL, &p, plen);
- }
- }
-
- return pss;
- }
-
-static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss,
- X509_ALGOR *maskHash, int indent)
- {
- int rv = 0;
- if (!pss)
- {
- if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0)
- return 0;
- return 1;
- }
- if (BIO_puts(bp, "\n") <= 0)
- goto err;
- if (!BIO_indent(bp, indent, 128))
- goto err;
- if (BIO_puts(bp, "Hash Algorithm: ") <= 0)
- goto err;
-
- if (pss->hashAlgorithm)
- {
- if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0)
- goto err;
- }
- else if (BIO_puts(bp, "sha1 (default)") <= 0)
- goto err;
-
- if (BIO_puts(bp, "\n") <= 0)
- goto err;
-
- if (!BIO_indent(bp, indent, 128))
- goto err;
-
- if (BIO_puts(bp, "Mask Algorithm: ") <= 0)
- goto err;
- if (pss->maskGenAlgorithm)
- {
- if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0)
- goto err;
- if (BIO_puts(bp, " with ") <= 0)
- goto err;
- if (maskHash)
- {
- if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0)
- goto err;
- }
- else if (BIO_puts(bp, "INVALID") <= 0)
- goto err;
- }
- else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0)
- goto err;
- BIO_puts(bp, "\n");
-
- if (!BIO_indent(bp, indent, 128))
- goto err;
- if (BIO_puts(bp, "Salt Length: 0x") <= 0)
- goto err;
- if (pss->saltLength)
- {
- if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0)
- goto err;
- }
- else if (BIO_puts(bp, "0x14 (default)") <= 0)
- goto err;
- BIO_puts(bp, "\n");
-
- if (!BIO_indent(bp, indent, 128))
- goto err;
- if (BIO_puts(bp, "Trailer Field: 0x") <= 0)
- goto err;
- if (pss->trailerField)
- {
- if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0)
- goto err;
- }
- else if (BIO_puts(bp, "BC (default)") <= 0)
- goto err;
- BIO_puts(bp, "\n");
-
- rv = 1;
-
- err:
- return rv;
-
- }
-
-static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
- const ASN1_STRING *sig,
- int indent, ASN1_PCTX *pctx)
- {
- if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss)
- {
- int rv;
- RSA_PSS_PARAMS *pss;
- X509_ALGOR *maskHash;
- pss = rsa_pss_decode(sigalg, &maskHash);
- rv = rsa_pss_param_print(bp, pss, maskHash, indent);
- if (pss)
- RSA_PSS_PARAMS_free(pss);
- if (maskHash)
- X509_ALGOR_free(maskHash);
- if (!rv)
- return 0;
- }
- else if (!sig && BIO_puts(bp, "\n") <= 0)
- return 0;
- if (sig)
- return X509_signature_dump(bp, sig, indent);
- return 1;
- }
-
-static int rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
- {
- X509_ALGOR *alg = NULL;
- switch (op)
- {
-
- case ASN1_PKEY_CTRL_PKCS7_SIGN:
- if (arg1 == 0)
- PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, NULL, &alg);
- break;
-
- case ASN1_PKEY_CTRL_PKCS7_ENCRYPT:
- if (arg1 == 0)
- PKCS7_RECIP_INFO_get0_alg(arg2, &alg);
- break;
-#ifndef OPENSSL_NO_CMS
- case ASN1_PKEY_CTRL_CMS_SIGN:
- if (arg1 == 0)
- CMS_SignerInfo_get0_algs(arg2, NULL, NULL, NULL, &alg);
- break;
-
- case ASN1_PKEY_CTRL_CMS_ENVELOPE:
- if (arg1 == 0)
- CMS_RecipientInfo_ktri_get0_algs(arg2, NULL, NULL, &alg);
- break;
-#endif
-
- case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
- *(int *)arg2 = NID_sha1;
- return 1;
-
- default:
- return -2;
-
- }
-
- if (alg)
- X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption),
- V_ASN1_NULL, 0);
-
- return 1;
-
- }
-
-/* Customised RSA item verification routine. This is called
- * when a signature is encountered requiring special handling. We
- * currently only handle PSS.
- */
-
-
-static int rsa_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
- X509_ALGOR *sigalg, ASN1_BIT_STRING *sig,
- EVP_PKEY *pkey)
- {
- int rv = -1;
- int saltlen;
- const EVP_MD *mgf1md = NULL, *md = NULL;
- RSA_PSS_PARAMS *pss;
- X509_ALGOR *maskHash;
- EVP_PKEY_CTX *pkctx;
- /* Sanity check: make sure it is PSS */
- if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss)
- {
- RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_SIGNATURE_TYPE);
- return -1;
- }
- /* Decode PSS parameters */
- pss = rsa_pss_decode(sigalg, &maskHash);
-
- if (pss == NULL)
- {
- RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_INVALID_PSS_PARAMETERS);
- goto err;
- }
- /* Check mask and lookup mask hash algorithm */
- if (pss->maskGenAlgorithm)
- {
- if (OBJ_obj2nid(pss->maskGenAlgorithm->algorithm) != NID_mgf1)
- {
- RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_MASK_ALGORITHM);
- goto err;
- }
- if (!maskHash)
- {
- RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_MASK_PARAMETER);
- goto err;
- }
- mgf1md = EVP_get_digestbyobj(maskHash->algorithm);
- if (mgf1md == NULL)
- {
- RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNKNOWN_MASK_DIGEST);
- goto err;
- }
- }
- else
- mgf1md = EVP_sha1();
-
- if (pss->hashAlgorithm)
- {
- md = EVP_get_digestbyobj(pss->hashAlgorithm->algorithm);
- if (md == NULL)
- {
- RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNKNOWN_PSS_DIGEST);
- goto err;
- }
- }
- else
- md = EVP_sha1();
-
- if (pss->saltLength)
- {
- saltlen = ASN1_INTEGER_get(pss->saltLength);
-
- /* Could perform more salt length sanity checks but the main
- * RSA routines will trap other invalid values anyway.
- */
- if (saltlen < 0)
- {
- RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_INVALID_SALT_LENGTH);
- goto err;
- }
- }
- else
- saltlen = 20;
-
- /* low-level routines support only trailer field 0xbc (value 1)
- * and PKCS#1 says we should reject any other value anyway.
- */
- if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1)
- {
- RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_INVALID_TRAILER);
- goto err;
- }
-
- /* We have all parameters now set up context */
-
- if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey))
- goto err;
-
- if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) <= 0)
- goto err;
-
- if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0)
- goto err;
- /* Carry on */
- rv = 2;
-
- err:
- RSA_PSS_PARAMS_free(pss);
- if (maskHash)
- X509_ALGOR_free(maskHash);
- return rv;
- }
-
-static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
- X509_ALGOR *alg1, X509_ALGOR *alg2,
- ASN1_BIT_STRING *sig)
- {
- int pad_mode;
- EVP_PKEY_CTX *pkctx = ctx->pctx;
- if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
- return 0;
- if (pad_mode == RSA_PKCS1_PADDING)
- return 2;
- if (pad_mode == RSA_PKCS1_PSS_PADDING)
- {
- const EVP_MD *sigmd, *mgf1md;
- RSA_PSS_PARAMS *pss = NULL;
- X509_ALGOR *mgf1alg = NULL;
- ASN1_STRING *os1 = NULL, *os2 = NULL;
- EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx);
- int saltlen, rv = 0;
- sigmd = EVP_MD_CTX_md(ctx);
- if (EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0)
- goto err;
- if (!EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen))
- goto err;
- if (saltlen == -1)
- saltlen = EVP_MD_size(sigmd);
- else if (saltlen == -2)
- {
- saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2;
- if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0)
- saltlen--;
- }
- pss = RSA_PSS_PARAMS_new();
- if (!pss)
- goto err;
- if (saltlen != 20)
- {
- pss->saltLength = ASN1_INTEGER_new();
- if (!pss->saltLength)
- goto err;
- if (!ASN1_INTEGER_set(pss->saltLength, saltlen))
- goto err;
- }
- if (EVP_MD_type(sigmd) != NID_sha1)
- {
- pss->hashAlgorithm = X509_ALGOR_new();
- if (!pss->hashAlgorithm)
- goto err;
- X509_ALGOR_set_md(pss->hashAlgorithm, sigmd);
- }
- if (EVP_MD_type(mgf1md) != NID_sha1)
- {
- ASN1_STRING *stmp = NULL;
- /* need to embed algorithm ID inside another */
- mgf1alg = X509_ALGOR_new();
- X509_ALGOR_set_md(mgf1alg, mgf1md);
- if (!ASN1_item_pack(mgf1alg, ASN1_ITEM_rptr(X509_ALGOR),
- &stmp))
- goto err;
- pss->maskGenAlgorithm = X509_ALGOR_new();
- if (!pss->maskGenAlgorithm)
- goto err;
- X509_ALGOR_set0(pss->maskGenAlgorithm,
- OBJ_nid2obj(NID_mgf1),
- V_ASN1_SEQUENCE, stmp);
- }
- /* Finally create string with pss parameter encoding. */
- if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os1))
- goto err;
- if (alg2)
- {
- os2 = ASN1_STRING_dup(os1);
- if (!os2)
- goto err;
- X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_rsassaPss),
- V_ASN1_SEQUENCE, os2);
- }
- X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_rsassaPss),
- V_ASN1_SEQUENCE, os1);
- os1 = os2 = NULL;
- rv = 3;
- err:
- if (mgf1alg)
- X509_ALGOR_free(mgf1alg);
- if (pss)
- RSA_PSS_PARAMS_free(pss);
- if (os1)
- ASN1_STRING_free(os1);
- return rv;
-
- }
- return 2;
- }
-
-const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] =
- {
- {
- EVP_PKEY_RSA,
- EVP_PKEY_RSA,
- ASN1_PKEY_SIGPARAM_NULL,
-
- "RSA",
- "OpenSSL RSA method",
-
- rsa_pub_decode,
- rsa_pub_encode,
- rsa_pub_cmp,
- rsa_pub_print,
-
- rsa_priv_decode,
- rsa_priv_encode,
- rsa_priv_print,
-
- int_rsa_size,
- rsa_bits,
-
- 0,0,0,0,0,0,
-
- rsa_sig_print,
- int_rsa_free,
- rsa_pkey_ctrl,
- old_rsa_priv_decode,
- old_rsa_priv_encode,
- rsa_item_verify,
- rsa_item_sign
- },
-
- {
- EVP_PKEY_RSA2,
- EVP_PKEY_RSA,
- ASN1_PKEY_ALIAS
- }
- };
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_sign.c b/drivers/builtin_openssl/crypto/rsa/rsa_sign.c
deleted file mode 100644
index a95c348cd4..0000000000
--- a/drivers/builtin_openssl/crypto/rsa/rsa_sign.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/* crypto/rsa/rsa_sign.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/bn.h>
-#include <openssl/rsa.h>
-#include <openssl/objects.h>
-#include <openssl/x509.h>
-#include "rsa_locl.h"
-
-/* Size of an SSL signature: MD5+SHA1 */
-#define SSL_SIG_LENGTH 36
-
-int RSA_sign(int type, const unsigned char *m, unsigned int m_len,
- unsigned char *sigret, unsigned int *siglen, RSA *rsa)
- {
- X509_SIG sig;
- ASN1_TYPE parameter;
- int i,j,ret=1;
- unsigned char *p, *tmps = NULL;
- const unsigned char *s = NULL;
- X509_ALGOR algor;
- ASN1_OCTET_STRING digest;
-#ifdef OPENSSL_FIPS
- if (FIPS_mode() && !(rsa->meth->flags & RSA_FLAG_FIPS_METHOD)
- && !(rsa->flags & RSA_FLAG_NON_FIPS_ALLOW))
- {
- RSAerr(RSA_F_RSA_SIGN, RSA_R_NON_FIPS_RSA_METHOD);
- return 0;
- }
-#endif
- if((rsa->flags & RSA_FLAG_SIGN_VER) && rsa->meth->rsa_sign)
- {
- return rsa->meth->rsa_sign(type, m, m_len,
- sigret, siglen, rsa);
- }
- /* Special case: SSL signature, just check the length */
- if(type == NID_md5_sha1) {
- if(m_len != SSL_SIG_LENGTH) {
- RSAerr(RSA_F_RSA_SIGN,RSA_R_INVALID_MESSAGE_LENGTH);
- return(0);
- }
- i = SSL_SIG_LENGTH;
- s = m;
- } else {
- sig.algor= &algor;
- sig.algor->algorithm=OBJ_nid2obj(type);
- if (sig.algor->algorithm == NULL)
- {
- RSAerr(RSA_F_RSA_SIGN,RSA_R_UNKNOWN_ALGORITHM_TYPE);
- return(0);
- }
- if (sig.algor->algorithm->length == 0)
- {
- RSAerr(RSA_F_RSA_SIGN,RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD);
- return(0);
- }
- parameter.type=V_ASN1_NULL;
- parameter.value.ptr=NULL;
- sig.algor->parameter= &parameter;
-
- sig.digest= &digest;
- sig.digest->data=(unsigned char *)m; /* TMP UGLY CAST */
- sig.digest->length=m_len;
-
- i=i2d_X509_SIG(&sig,NULL);
- }
- j=RSA_size(rsa);
- if (i > (j-RSA_PKCS1_PADDING_SIZE))
- {
- RSAerr(RSA_F_RSA_SIGN,RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
- return(0);
- }
- if(type != NID_md5_sha1) {
- tmps=(unsigned char *)OPENSSL_malloc((unsigned int)j+1);
- if (tmps == NULL)
- {
- RSAerr(RSA_F_RSA_SIGN,ERR_R_MALLOC_FAILURE);
- return(0);
- }
- p=tmps;
- i2d_X509_SIG(&sig,&p);
- s=tmps;
- }
- i=RSA_private_encrypt(i,s,sigret,rsa,RSA_PKCS1_PADDING);
- if (i <= 0)
- ret=0;
- else
- *siglen=i;
-
- if(type != NID_md5_sha1) {
- OPENSSL_cleanse(tmps,(unsigned int)j+1);
- OPENSSL_free(tmps);
- }
- return(ret);
- }
-
-int int_rsa_verify(int dtype, const unsigned char *m,
- unsigned int m_len,
- unsigned char *rm, size_t *prm_len,
- const unsigned char *sigbuf, size_t siglen,
- RSA *rsa)
- {
- int i,ret=0,sigtype;
- unsigned char *s;
- X509_SIG *sig=NULL;
-
-#ifdef OPENSSL_FIPS
- if (FIPS_mode() && !(rsa->meth->flags & RSA_FLAG_FIPS_METHOD)
- && !(rsa->flags & RSA_FLAG_NON_FIPS_ALLOW))
- {
- RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_NON_FIPS_RSA_METHOD);
- return 0;
- }
-#endif
-
- if (siglen != (unsigned int)RSA_size(rsa))
- {
- printf("siglen: %i - RSAs: %i\n",siglen,(unsigned int)RSA_size(rsa));
- RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_WRONG_SIGNATURE_LENGTH);
- return(0);
- }
-
- if((dtype == NID_md5_sha1) && rm)
- {
- i = RSA_public_decrypt((int)siglen,
- sigbuf,rm,rsa,RSA_PKCS1_PADDING);
- if (i <= 0)
- return 0;
- *prm_len = i;
- return 1;
- }
-
- s=(unsigned char *)OPENSSL_malloc((unsigned int)siglen);
- if (s == NULL)
- {
- RSAerr(RSA_F_INT_RSA_VERIFY,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if((dtype == NID_md5_sha1) && (m_len != SSL_SIG_LENGTH) ) {
- RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_INVALID_MESSAGE_LENGTH);
- goto err;
- }
- i=RSA_public_decrypt((int)siglen,sigbuf,s,rsa,RSA_PKCS1_PADDING);
-
- if (i <= 0) goto err;
- /* Oddball MDC2 case: signature can be OCTET STRING.
- * check for correct tag and length octets.
- */
- if (dtype == NID_mdc2 && i == 18 && s[0] == 0x04 && s[1] == 0x10)
- {
- if (rm)
- {
- memcpy(rm, s + 2, 16);
- *prm_len = 16;
- ret = 1;
- }
- else if(memcmp(m, s + 2, 16))
- RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
- else
- ret = 1;
- }
-
- /* Special case: SSL signature */
- if(dtype == NID_md5_sha1) {
- if((i != SSL_SIG_LENGTH) || memcmp(s, m, SSL_SIG_LENGTH))
- RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
- else ret = 1;
- } else {
- const unsigned char *p=s;
- sig=d2i_X509_SIG(NULL,&p,(long)i);
-
- if (sig == NULL) goto err;
-
- /* Excess data can be used to create forgeries */
- if(p != s+i)
- {
- RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
- goto err;
- }
-
- /* Parameters to the signature algorithm can also be used to
- create forgeries */
- if(sig->algor->parameter
- && ASN1_TYPE_get(sig->algor->parameter) != V_ASN1_NULL)
- {
- RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
- goto err;
- }
-
- sigtype=OBJ_obj2nid(sig->algor->algorithm);
-
-
- #ifdef RSA_DEBUG
- /* put a backward compatibility flag in EAY */
- fprintf(stderr,"in(%s) expect(%s)\n",OBJ_nid2ln(sigtype),
- OBJ_nid2ln(dtype));
- #endif
- if (sigtype != dtype)
- {
- if (((dtype == NID_md5) &&
- (sigtype == NID_md5WithRSAEncryption)) ||
- ((dtype == NID_md2) &&
- (sigtype == NID_md2WithRSAEncryption)))
- {
- /* ok, we will let it through */
-#if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)
- fprintf(stderr,"signature has problems, re-make with post SSLeay045\n");
-#endif
- }
- else
- {
- RSAerr(RSA_F_INT_RSA_VERIFY,
- RSA_R_ALGORITHM_MISMATCH);
- goto err;
- }
- }
- if (rm)
- {
- const EVP_MD *md;
- md = EVP_get_digestbynid(dtype);
- if (md && (EVP_MD_size(md) != sig->digest->length))
- RSAerr(RSA_F_INT_RSA_VERIFY,
- RSA_R_INVALID_DIGEST_LENGTH);
- else
- {
- memcpy(rm, sig->digest->data,
- sig->digest->length);
- *prm_len = sig->digest->length;
- ret = 1;
- }
- }
- else if (((unsigned int)sig->digest->length != m_len) ||
- (memcmp(m,sig->digest->data,m_len) != 0))
- {
- RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
- }
- else
- ret=1;
- }
-err:
- if (sig != NULL) X509_SIG_free(sig);
- if (s != NULL)
- {
- OPENSSL_cleanse(s,(unsigned int)siglen);
- OPENSSL_free(s);
- }
- return(ret);
- }
-
-int RSA_verify(int dtype, const unsigned char *m, unsigned int m_len,
- const unsigned char *sigbuf, unsigned int siglen,
- RSA *rsa)
- {
-
- if((rsa->flags & RSA_FLAG_SIGN_VER) && rsa->meth->rsa_verify)
- {
- return rsa->meth->rsa_verify(dtype, m, m_len,
- sigbuf, siglen, rsa);
- }
-
- return int_rsa_verify(dtype, m, m_len, NULL, NULL, sigbuf, siglen, rsa);
- }
diff --git a/drivers/builtin_openssl/crypto/srp/srp_vfy.c b/drivers/builtin_openssl/crypto/srp/srp_vfy.c
deleted file mode 100644
index 4a3d13edf6..0000000000
--- a/drivers/builtin_openssl/crypto/srp/srp_vfy.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/* crypto/srp/srp_vfy.c */
-/* Written by Christophe Renou (christophe.renou@edelweb.fr) with
- * the precious help of Peter Sylvester (peter.sylvester@edelweb.fr)
- * for the EdelKey project and contributed to the OpenSSL project 2004.
- */
-/* ====================================================================
- * Copyright (c) 2004 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-#ifndef OPENSSL_NO_SRP
-#include "cryptlib.h"
-#include "srp_lcl.h"
-#include <openssl/srp.h>
-#include <openssl/evp.h>
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/txt_db.h>
-
-#define SRP_RANDOM_SALT_LEN 20
-#define MAX_LEN 2500
-
-static char b64table[] =
- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
-
-/* the following two conversion routines have been inspired by code from Stanford */
-
-/*
- * Convert a base64 string into raw byte array representation.
- */
-static int t_fromb64(unsigned char *a, const char *src)
- {
- char *loc;
- int i, j;
- int size;
-
- while(*src && (*src == ' ' || *src == '\t' || *src == '\n'))
- ++src;
- size = strlen(src);
- i = 0;
- while(i < size)
- {
- loc = strchr(b64table, src[i]);
- if(loc == (char *) 0) break;
- else a[i] = loc - b64table;
- ++i;
- }
- size = i;
- i = size - 1;
- j = size;
- while(1)
- {
- a[j] = a[i];
- if(--i < 0) break;
- a[j] |= (a[i] & 3) << 6;
- --j;
- a[j] = (unsigned char) ((a[i] & 0x3c) >> 2);
- if(--i < 0) break;
- a[j] |= (a[i] & 0xf) << 4;
- --j;
- a[j] = (unsigned char) ((a[i] & 0x30) >> 4);
- if(--i < 0) break;
- a[j] |= (a[i] << 2);
-
- a[--j] = 0;
- if(--i < 0) break;
- }
- while(a[j] == 0 && j <= size) ++j;
- i = 0;
- while (j <= size) a[i++] = a[j++];
- return i;
- }
-
-
-/*
- * Convert a raw byte string into a null-terminated base64 ASCII string.
- */
-static char *t_tob64(char *dst, const unsigned char *src, int size)
- {
- int c, pos = size % 3;
- unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0;
- char *olddst = dst;
-
- switch(pos)
- {
- case 1:
- b2 = src[0];
- break;
- case 2:
- b1 = src[0];
- b2 = src[1];
- break;
- }
-
- while(1)
- {
- c = (b0 & 0xfc) >> 2;
- if(notleading || c != 0)
- {
- *dst++ = b64table[c];
- notleading = 1;
- }
- c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4);
- if(notleading || c != 0)
- {
- *dst++ = b64table[c];
- notleading = 1;
- }
- c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6);
- if(notleading || c != 0)
- {
- *dst++ = b64table[c];
- notleading = 1;
- }
- c = b2 & 0x3f;
- if(notleading || c != 0)
- {
- *dst++ = b64table[c];
- notleading = 1;
- }
- if(pos >= size) break;
- else
- {
- b0 = src[pos++];
- b1 = src[pos++];
- b2 = src[pos++];
- }
- }
-
- *dst++ = '\0';
- return olddst;
- }
-
-static void SRP_user_pwd_free(SRP_user_pwd *user_pwd)
- {
- if (user_pwd == NULL)
- return;
- BN_free(user_pwd->s);
- BN_clear_free(user_pwd->v);
- OPENSSL_free(user_pwd->id);
- OPENSSL_free(user_pwd->info);
- OPENSSL_free(user_pwd);
- }
-
-static SRP_user_pwd *SRP_user_pwd_new()
- {
- SRP_user_pwd *ret = OPENSSL_malloc(sizeof(SRP_user_pwd));
- if (ret == NULL)
- return NULL;
- ret->N = NULL;
- ret->g = NULL;
- ret->s = NULL;
- ret->v = NULL;
- ret->id = NULL ;
- ret->info = NULL;
- return ret;
- }
-
-static void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g,
- const BIGNUM *N)
- {
- vinfo->N = N;
- vinfo->g = g;
- }
-
-static int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id,
- const char *info)
- {
- if (id != NULL && NULL == (vinfo->id = BUF_strdup(id)))
- return 0;
- return (info == NULL || NULL != (vinfo->info = BUF_strdup(info))) ;
- }
-
-static int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s,
- const char *v)
- {
- unsigned char tmp[MAX_LEN];
- int len;
-
- if (strlen(s) > MAX_LEN || strlen(v) > MAX_LEN)
- return 0;
- len = t_fromb64(tmp, v);
- if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL)) )
- return 0;
- len = t_fromb64(tmp, s);
- return ((vinfo->s = BN_bin2bn(tmp, len, NULL)) != NULL) ;
- }
-
-static int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v)
- {
- vinfo->v = v;
- vinfo->s = s;
- return (vinfo->s != NULL && vinfo->v != NULL) ;
- }
-
-SRP_VBASE *SRP_VBASE_new(char *seed_key)
- {
- SRP_VBASE *vb = (SRP_VBASE *) OPENSSL_malloc(sizeof(SRP_VBASE));
-
- if (vb == NULL)
- return NULL;
- if (!(vb->users_pwd = sk_SRP_user_pwd_new_null()) ||
- !(vb->gN_cache = sk_SRP_gN_cache_new_null()))
- {
- OPENSSL_free(vb);
- return NULL;
- }
- vb->default_g = NULL;
- vb->default_N = NULL;
- vb->seed_key = NULL;
- if ((seed_key != NULL) &&
- (vb->seed_key = BUF_strdup(seed_key)) == NULL)
- {
- sk_SRP_user_pwd_free(vb->users_pwd);
- sk_SRP_gN_cache_free(vb->gN_cache);
- OPENSSL_free(vb);
- return NULL;
- }
- return vb;
- }
-
-
-int SRP_VBASE_free(SRP_VBASE *vb)
- {
- sk_SRP_user_pwd_pop_free(vb->users_pwd,SRP_user_pwd_free);
- sk_SRP_gN_cache_free(vb->gN_cache);
- OPENSSL_free(vb->seed_key);
- OPENSSL_free(vb);
- return 0;
- }
-
-
-static SRP_gN_cache *SRP_gN_new_init(const char *ch)
- {
- unsigned char tmp[MAX_LEN];
- int len;
-
- SRP_gN_cache *newgN = (SRP_gN_cache *)OPENSSL_malloc(sizeof(SRP_gN_cache));
- if (newgN == NULL)
- return NULL;
-
- if ((newgN->b64_bn = BUF_strdup(ch)) == NULL)
- goto err;
-
- len = t_fromb64(tmp, ch);
- if ((newgN->bn = BN_bin2bn(tmp, len, NULL)))
- return newgN;
-
- OPENSSL_free(newgN->b64_bn);
-err:
- OPENSSL_free(newgN);
- return NULL;
- }
-
-
-static void SRP_gN_free(SRP_gN_cache *gN_cache)
- {
- if (gN_cache == NULL)
- return;
- OPENSSL_free(gN_cache->b64_bn);
- BN_free(gN_cache->bn);
- OPENSSL_free(gN_cache);
- }
-
-static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab)
- {
- int i;
-
- SRP_gN *gN;
- if (gN_tab != NULL)
- for(i = 0; i < sk_SRP_gN_num(gN_tab); i++)
- {
- gN = sk_SRP_gN_value(gN_tab, i);
- if (gN && (id == NULL || strcmp(gN->id,id)==0))
- return gN;
- }
-
- return SRP_get_default_gN(id);
- }
-
-static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch)
- {
- int i;
- if (gN_cache == NULL)
- return NULL;
-
- /* search if we have already one... */
- for(i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++)
- {
- SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i);
- if (strcmp(cache->b64_bn,ch)==0)
- return cache->bn;
- }
- { /* it is the first time that we find it */
- SRP_gN_cache *newgN = SRP_gN_new_init(ch);
- if (newgN)
- {
- if (sk_SRP_gN_cache_insert(gN_cache,newgN,0)>0)
- return newgN->bn;
- SRP_gN_free(newgN);
- }
- }
- return NULL;
- }
-
-/* this function parses verifier file. Format is:
- * string(index):base64(N):base64(g):0
- * string(username):base64(v):base64(salt):int(index)
- */
-
-
-int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file)
- {
- int error_code ;
- STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null();
- char *last_index = NULL;
- int i;
- char **pp;
-
- SRP_gN *gN = NULL;
- SRP_user_pwd *user_pwd = NULL ;
-
- TXT_DB *tmpdb = NULL;
- BIO *in = BIO_new(BIO_s_file());
-
- error_code = SRP_ERR_OPEN_FILE;
-
- if (in == NULL || BIO_read_filename(in,verifier_file) <= 0)
- goto err;
-
- error_code = SRP_ERR_VBASE_INCOMPLETE_FILE;
-
- if ((tmpdb =TXT_DB_read(in,DB_NUMBER)) == NULL)
- goto err;
-
- error_code = SRP_ERR_MEMORY;
-
-
- if (vb->seed_key)
- {
- last_index = SRP_get_default_gN(NULL)->id;
- }
- for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++)
- {
- pp = sk_OPENSSL_PSTRING_value(tmpdb->data,i);
- if (pp[DB_srptype][0] == DB_SRP_INDEX)
- {
- /*we add this couple in the internal Stack */
-
- if ((gN = (SRP_gN *)OPENSSL_malloc(sizeof(SRP_gN))) == NULL)
- goto err;
-
- if (!(gN->id = BUF_strdup(pp[DB_srpid]))
- || !(gN->N = SRP_gN_place_bn(vb->gN_cache,pp[DB_srpverifier]))
- || !(gN->g = SRP_gN_place_bn(vb->gN_cache,pp[DB_srpsalt]))
- || sk_SRP_gN_insert(SRP_gN_tab,gN,0) == 0)
- goto err;
-
- gN = NULL;
-
- if (vb->seed_key != NULL)
- {
- last_index = pp[DB_srpid];
- }
- }
- else if (pp[DB_srptype][0] == DB_SRP_VALID)
- {
- /* it is a user .... */
- SRP_gN *lgN;
- if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN],SRP_gN_tab))!=NULL)
- {
- error_code = SRP_ERR_MEMORY;
- if ((user_pwd = SRP_user_pwd_new()) == NULL)
- goto err;
-
- SRP_user_pwd_set_gN(user_pwd,lgN->g,lgN->N);
- if (!SRP_user_pwd_set_ids(user_pwd, pp[DB_srpid],pp[DB_srpinfo]))
- goto err;
-
- error_code = SRP_ERR_VBASE_BN_LIB;
- if (!SRP_user_pwd_set_sv(user_pwd, pp[DB_srpsalt],pp[DB_srpverifier]))
- goto err;
-
- if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0)
- goto err;
- user_pwd = NULL; /* abandon responsability */
- }
- }
- }
-
- if (last_index != NULL)
- {
- /* this means that we want to simulate a default user */
-
- if (((gN = SRP_get_gN_by_id(last_index,SRP_gN_tab))==NULL))
- {
- error_code = SRP_ERR_VBASE_BN_LIB;
- goto err;
- }
- vb->default_g = gN->g ;
- vb->default_N = gN->N ;
- gN = NULL ;
- }
- error_code = SRP_NO_ERROR;
-
- err:
- /* there may be still some leaks to fix, if this fails, the application terminates most likely */
-
- if (gN != NULL)
- {
- OPENSSL_free(gN->id);
- OPENSSL_free(gN);
- }
-
- SRP_user_pwd_free(user_pwd);
-
- if (tmpdb) TXT_DB_free(tmpdb);
- if (in) BIO_free_all(in);
-
- sk_SRP_gN_free(SRP_gN_tab);
-
- return error_code;
-
- }
-
-
-SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username)
- {
- int i;
- SRP_user_pwd *user;
- unsigned char digv[SHA_DIGEST_LENGTH];
- unsigned char digs[SHA_DIGEST_LENGTH];
- EVP_MD_CTX ctxt;
-
- if (vb == NULL)
- return NULL;
- for(i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++)
- {
- user = sk_SRP_user_pwd_value(vb->users_pwd, i);
- if (strcmp(user->id,username)==0)
- return user;
- }
- if ((vb->seed_key == NULL) ||
- (vb->default_g == NULL) ||
- (vb->default_N == NULL))
- return NULL;
-
-/* if the user is unknown we set parameters as well if we have a seed_key */
-
- if ((user = SRP_user_pwd_new()) == NULL)
- return NULL;
-
- SRP_user_pwd_set_gN(user,vb->default_g,vb->default_N);
-
- if (!SRP_user_pwd_set_ids(user,username,NULL))
- goto err;
-
- RAND_pseudo_bytes(digv, SHA_DIGEST_LENGTH);
- EVP_MD_CTX_init(&ctxt);
- EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL);
- EVP_DigestUpdate(&ctxt, vb->seed_key, strlen(vb->seed_key));
- EVP_DigestUpdate(&ctxt, username, strlen(username));
- EVP_DigestFinal_ex(&ctxt, digs, NULL);
- EVP_MD_CTX_cleanup(&ctxt);
- if (SRP_user_pwd_set_sv_BN(user, BN_bin2bn(digs,SHA_DIGEST_LENGTH,NULL), BN_bin2bn(digv,SHA_DIGEST_LENGTH, NULL)))
- return user;
-
-err: SRP_user_pwd_free(user);
- return NULL;
- }
-
-
-/*
- create a verifier (*salt,*verifier,g and N are in base64)
-*/
-char *SRP_create_verifier(const char *user, const char *pass, char **salt,
- char **verifier, const char *N, const char *g)
- {
- int len;
- char * result=NULL;
- char *vf;
- BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL;
- unsigned char tmp[MAX_LEN];
- unsigned char tmp2[MAX_LEN];
- char * defgNid = NULL;
-
- if ((user == NULL)||
- (pass == NULL)||
- (salt == NULL)||
- (verifier == NULL))
- goto err;
-
- if (N)
- {
- if (!(len = t_fromb64(tmp, N))) goto err;
- N_bn = BN_bin2bn(tmp, len, NULL);
- if (!(len = t_fromb64(tmp, g))) goto err;
- g_bn = BN_bin2bn(tmp, len, NULL);
- defgNid = "*";
- }
- else
- {
- SRP_gN * gN = SRP_get_gN_by_id(g, NULL) ;
- if (gN == NULL)
- goto err;
- N_bn = gN->N;
- g_bn = gN->g;
- defgNid = gN->id;
- }
-
- if (*salt == NULL)
- {
- RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN);
-
- s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL);
- }
- else
- {
- if (!(len = t_fromb64(tmp2, *salt)))
- goto err;
- s = BN_bin2bn(tmp2, len, NULL);
- }
-
-
- if(!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn)) goto err;
-
- BN_bn2bin(v,tmp);
- if (((vf = OPENSSL_malloc(BN_num_bytes(v)*2)) == NULL))
- goto err;
- t_tob64(vf, tmp, BN_num_bytes(v));
-
- *verifier = vf;
- if (*salt == NULL)
- {
- char *tmp_salt;
-
- if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL)
- {
- OPENSSL_free(vf);
- goto err;
- }
- t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN);
- *salt = tmp_salt;
- }
-
- result=defgNid;
-
-err:
- if(N)
- {
- BN_free(N_bn);
- BN_free(g_bn);
- }
- return result;
- }
-
-/*
- create a verifier (*salt,*verifier,g and N are BIGNUMs)
-*/
-int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, BIGNUM **verifier, BIGNUM *N, BIGNUM *g)
- {
- int result=0;
- BIGNUM *x = NULL;
- BN_CTX *bn_ctx = BN_CTX_new();
- unsigned char tmp2[MAX_LEN];
-
- if ((user == NULL)||
- (pass == NULL)||
- (salt == NULL)||
- (verifier == NULL)||
- (N == NULL)||
- (g == NULL)||
- (bn_ctx == NULL))
- goto err;
-
- srp_bn_print(N);
- srp_bn_print(g);
-
- if (*salt == NULL)
- {
- RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN);
-
- *salt = BN_bin2bn(tmp2,SRP_RANDOM_SALT_LEN,NULL);
- }
-
- x = SRP_Calc_x(*salt,user,pass);
-
- *verifier = BN_new();
- if(*verifier == NULL) goto err;
-
- if (!BN_mod_exp(*verifier,g,x,N,bn_ctx))
- {
- BN_clear_free(*verifier);
- goto err;
- }
-
- srp_bn_print(*verifier);
-
- result=1;
-
-err:
-
- BN_clear_free(x);
- BN_CTX_free(bn_ctx);
- return result;
- }
-
-
-
-#endif
diff --git a/drivers/builtin_openssl/crypto/ts/ts_rsp_verify.c b/drivers/builtin_openssl/crypto/ts/ts_rsp_verify.c
deleted file mode 100644
index afe16afbe4..0000000000
--- a/drivers/builtin_openssl/crypto/ts/ts_rsp_verify.c
+++ /dev/null
@@ -1,728 +0,0 @@
-/* crypto/ts/ts_resp_verify.c */
-/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
- * project 2002.
- */
-/* ====================================================================
- * Copyright (c) 2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/objects.h>
-#include <openssl/ts.h>
-#include <openssl/pkcs7.h>
-
-/* Private function declarations. */
-
-static int TS_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
- X509 *signer, STACK_OF(X509) **chain);
-static int TS_check_signing_certs(PKCS7_SIGNER_INFO *si, STACK_OF(X509) *chain);
-static ESS_SIGNING_CERT *ESS_get_signing_cert(PKCS7_SIGNER_INFO *si);
-static int TS_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert);
-static int TS_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509_CINF *cinfo);
-static int int_TS_RESP_verify_token(TS_VERIFY_CTX *ctx,
- PKCS7 *token, TS_TST_INFO *tst_info);
-static int TS_check_status_info(TS_RESP *response);
-static char *TS_get_status_text(STACK_OF(ASN1_UTF8STRING) *text);
-static int TS_check_policy(ASN1_OBJECT *req_oid, TS_TST_INFO *tst_info);
-static int TS_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
- X509_ALGOR **md_alg,
- unsigned char **imprint, unsigned *imprint_len);
-static int TS_check_imprints(X509_ALGOR *algor_a,
- unsigned char *imprint_a, unsigned len_a,
- TS_TST_INFO *tst_info);
-static int TS_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info);
-static int TS_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer);
-static int TS_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name);
-
-/*
- * Local mapping between response codes and descriptions.
- * Don't forget to change TS_STATUS_BUF_SIZE when modifying
- * the elements of this array.
- */
-static const char *TS_status_text[] =
- { "granted",
- "grantedWithMods",
- "rejection",
- "waiting",
- "revocationWarning",
- "revocationNotification" };
-
-#define TS_STATUS_TEXT_SIZE (sizeof(TS_status_text)/sizeof(*TS_status_text))
-
-/*
- * This must be greater or equal to the sum of the strings in TS_status_text
- * plus the number of its elements.
- */
-#define TS_STATUS_BUF_SIZE 256
-
-static struct
- {
- int code;
- const char *text;
- } TS_failure_info[] =
- { { TS_INFO_BAD_ALG, "badAlg" },
- { TS_INFO_BAD_REQUEST, "badRequest" },
- { TS_INFO_BAD_DATA_FORMAT, "badDataFormat" },
- { TS_INFO_TIME_NOT_AVAILABLE, "timeNotAvailable" },
- { TS_INFO_UNACCEPTED_POLICY, "unacceptedPolicy" },
- { TS_INFO_UNACCEPTED_EXTENSION, "unacceptedExtension" },
- { TS_INFO_ADD_INFO_NOT_AVAILABLE, "addInfoNotAvailable" },
- { TS_INFO_SYSTEM_FAILURE, "systemFailure" } };
-
-#define TS_FAILURE_INFO_SIZE (sizeof(TS_failure_info) / \
- sizeof(*TS_failure_info))
-
-/* Functions for verifying a signed TS_TST_INFO structure. */
-
-/*
- * This function carries out the following tasks:
- * - Checks if there is one and only one signer.
- * - Search for the signing certificate in 'certs' and in the response.
- * - Check the extended key usage and key usage fields of the signer
- * certificate (done by the path validation).
- * - Build and validate the certificate path.
- * - Check if the certificate path meets the requirements of the
- * SigningCertificate ESS signed attribute.
- * - Verify the signature value.
- * - Returns the signer certificate in 'signer', if 'signer' is not NULL.
- */
-int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs,
- X509_STORE *store, X509 **signer_out)
- {
- STACK_OF(PKCS7_SIGNER_INFO) *sinfos = NULL;
- PKCS7_SIGNER_INFO *si;
- STACK_OF(X509) *signers = NULL;
- X509 *signer;
- STACK_OF(X509) *chain = NULL;
- char buf[4096];
- int i, j = 0, ret = 0;
- BIO *p7bio = NULL;
-
- /* Some sanity checks first. */
- if (!token)
- {
- TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_INVALID_NULL_POINTER);
- goto err;
- }
-
- /* Check for the correct content type */
- if(!PKCS7_type_is_signed(token))
- {
- TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_WRONG_CONTENT_TYPE);
- goto err;
- }
-
- /* Check if there is one and only one signer. */
- sinfos = PKCS7_get_signer_info(token);
- if (!sinfos || sk_PKCS7_SIGNER_INFO_num(sinfos) != 1)
- {
- TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE,
- TS_R_THERE_MUST_BE_ONE_SIGNER);
- goto err;
- }
- si = sk_PKCS7_SIGNER_INFO_value(sinfos, 0);
-
- /* Check for no content: no data to verify signature. */
- if (PKCS7_get_detached(token))
- {
- TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_NO_CONTENT);
- goto err;
- }
-
- /* Get hold of the signer certificate, search only internal
- certificates if it was requested. */
- signers = PKCS7_get0_signers(token, certs, 0);
- if (!signers || sk_X509_num(signers) != 1) goto err;
- signer = sk_X509_value(signers, 0);
-
- /* Now verify the certificate. */
- if (!TS_verify_cert(store, certs, signer, &chain)) goto err;
-
- /* Check if the signer certificate is consistent with the
- ESS extension. */
- if (!TS_check_signing_certs(si, chain)) goto err;
-
- /* Creating the message digest. */
- p7bio = PKCS7_dataInit(token, NULL);
-
- /* We now have to 'read' from p7bio to calculate digests etc. */
- while ((i = BIO_read(p7bio,buf,sizeof(buf))) > 0);
-
- /* Verifying the signature. */
- j = PKCS7_signatureVerify(p7bio, token, si, signer);
- if (j <= 0)
- {
- TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_SIGNATURE_FAILURE);
- goto err;
- }
-
- /* Return the signer certificate if needed. */
- if (signer_out)
- {
- *signer_out = signer;
- CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
- }
-
- ret = 1;
-
- err:
- BIO_free_all(p7bio);
- sk_X509_pop_free(chain, X509_free);
- sk_X509_free(signers);
-
- return ret;
- }
-
-/*
- * The certificate chain is returned in chain. Caller is responsible for
- * freeing the vector.
- */
-static int TS_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
- X509 *signer, STACK_OF(X509) **chain)
- {
- X509_STORE_CTX cert_ctx;
- int i;
- int ret = 1;
-
- /* chain is an out argument. */
- *chain = NULL;
- X509_STORE_CTX_init(&cert_ctx, store, signer, untrusted);
- X509_STORE_CTX_set_purpose(&cert_ctx, X509_PURPOSE_TIMESTAMP_SIGN);
- i = X509_verify_cert(&cert_ctx);
- if (i <= 0)
- {
- int j = X509_STORE_CTX_get_error(&cert_ctx);
- TSerr(TS_F_TS_VERIFY_CERT, TS_R_CERTIFICATE_VERIFY_ERROR);
- ERR_add_error_data(2, "Verify error:",
- X509_verify_cert_error_string(j));
- ret = 0;
- }
- else
- {
- /* Get a copy of the certificate chain. */
- *chain = X509_STORE_CTX_get1_chain(&cert_ctx);
- }
-
- X509_STORE_CTX_cleanup(&cert_ctx);
-
- return ret;
- }
-
-static int TS_check_signing_certs(PKCS7_SIGNER_INFO *si, STACK_OF(X509) *chain)
- {
- ESS_SIGNING_CERT *ss = ESS_get_signing_cert(si);
- STACK_OF(ESS_CERT_ID) *cert_ids = NULL;
- X509 *cert;
- int i = 0;
- int ret = 0;
-
- if (!ss) goto err;
- cert_ids = ss->cert_ids;
- /* The signer certificate must be the first in cert_ids. */
- cert = sk_X509_value(chain, 0);
- if (TS_find_cert(cert_ids, cert) != 0) goto err;
-
- /* Check the other certificates of the chain if there are more
- than one certificate ids in cert_ids. */
- if (sk_ESS_CERT_ID_num(cert_ids) > 1)
- {
- /* All the certificates of the chain must be in cert_ids. */
- for (i = 1; i < sk_X509_num(chain); ++i)
- {
- cert = sk_X509_value(chain, i);
- if (TS_find_cert(cert_ids, cert) < 0) goto err;
- }
- }
- ret = 1;
- err:
- if (!ret)
- TSerr(TS_F_TS_CHECK_SIGNING_CERTS,
- TS_R_ESS_SIGNING_CERTIFICATE_ERROR);
- ESS_SIGNING_CERT_free(ss);
- return ret;
- }
-
-static ESS_SIGNING_CERT *ESS_get_signing_cert(PKCS7_SIGNER_INFO *si)
- {
- ASN1_TYPE *attr;
- const unsigned char *p;
- attr = PKCS7_get_signed_attribute(si,
- NID_id_smime_aa_signingCertificate);
- if (!attr) return NULL;
- p = attr->value.sequence->data;
- return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
- }
-
-/* Returns < 0 if certificate is not found, certificate index otherwise. */
-static int TS_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert)
- {
- int i;
-
- if (!cert_ids || !cert) return -1;
-
- /* Recompute SHA1 hash of certificate if necessary (side effect). */
- X509_check_purpose(cert, -1, 0);
-
- /* Look for cert in the cert_ids vector. */
- for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i)
- {
- ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i);
-
- /* Check the SHA-1 hash first. */
- if (cid->hash->length == sizeof(cert->sha1_hash)
- && !memcmp(cid->hash->data, cert->sha1_hash,
- sizeof(cert->sha1_hash)))
- {
- /* Check the issuer/serial as well if specified. */
- ESS_ISSUER_SERIAL *is = cid->issuer_serial;
- if (!is || !TS_issuer_serial_cmp(is, cert->cert_info))
- return i;
- }
- }
-
- return -1;
- }
-
-static int TS_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509_CINF *cinfo)
- {
- GENERAL_NAME *issuer;
-
- if (!is || !cinfo || sk_GENERAL_NAME_num(is->issuer) != 1) return -1;
-
- /* Check the issuer first. It must be a directory name. */
- issuer = sk_GENERAL_NAME_value(is->issuer, 0);
- if (issuer->type != GEN_DIRNAME
- || X509_NAME_cmp(issuer->d.dirn, cinfo->issuer))
- return -1;
-
- /* Check the serial number, too. */
- if (ASN1_INTEGER_cmp(is->serial, cinfo->serialNumber))
- return -1;
-
- return 0;
- }
-
-/*
- * Verifies whether 'response' contains a valid response with regards
- * to the settings of the context:
- * - Gives an error message if the TS_TST_INFO is not present.
- * - Calls _TS_RESP_verify_token to verify the token content.
- */
-int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response)
- {
- PKCS7 *token = TS_RESP_get_token(response);
- TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
- int ret = 0;
-
- /* Check if we have a successful TS_TST_INFO object in place. */
- if (!TS_check_status_info(response)) goto err;
-
- /* Check the contents of the time stamp token. */
- if (!int_TS_RESP_verify_token(ctx, token, tst_info))
- goto err;
-
- ret = 1;
- err:
- return ret;
- }
-
-/*
- * Tries to extract a TS_TST_INFO structure from the PKCS7 token and
- * calls the internal int_TS_RESP_verify_token function for verifying it.
- */
-int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token)
- {
- TS_TST_INFO *tst_info = PKCS7_to_TS_TST_INFO(token);
- int ret = 0;
- if (tst_info)
- {
- ret = int_TS_RESP_verify_token(ctx, token, tst_info);
- TS_TST_INFO_free(tst_info);
- }
- return ret;
- }
-
-/*
- * Verifies whether the 'token' contains a valid time stamp token
- * with regards to the settings of the context. Only those checks are
- * carried out that are specified in the context:
- * - Verifies the signature of the TS_TST_INFO.
- * - Checks the version number of the response.
- * - Check if the requested and returned policies math.
- * - Check if the message imprints are the same.
- * - Check if the nonces are the same.
- * - Check if the TSA name matches the signer.
- * - Check if the TSA name is the expected TSA.
- */
-static int int_TS_RESP_verify_token(TS_VERIFY_CTX *ctx,
- PKCS7 *token, TS_TST_INFO *tst_info)
- {
- X509 *signer = NULL;
- GENERAL_NAME *tsa_name = TS_TST_INFO_get_tsa(tst_info);
- X509_ALGOR *md_alg = NULL;
- unsigned char *imprint = NULL;
- unsigned imprint_len = 0;
- int ret = 0;
-
- /* Verify the signature. */
- if ((ctx->flags & TS_VFY_SIGNATURE)
- && !TS_RESP_verify_signature(token, ctx->certs, ctx->store,
- &signer))
- goto err;
-
- /* Check version number of response. */
- if ((ctx->flags & TS_VFY_VERSION)
- && TS_TST_INFO_get_version(tst_info) != 1)
- {
- TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_UNSUPPORTED_VERSION);
- goto err;
- }
-
- /* Check policies. */
- if ((ctx->flags & TS_VFY_POLICY)
- && !TS_check_policy(ctx->policy, tst_info))
- goto err;
-
- /* Check message imprints. */
- if ((ctx->flags & TS_VFY_IMPRINT)
- && !TS_check_imprints(ctx->md_alg, ctx->imprint, ctx->imprint_len,
- tst_info))
- goto err;
-
- /* Compute and check message imprints. */
- if ((ctx->flags & TS_VFY_DATA)
- && (!TS_compute_imprint(ctx->data, tst_info,
- &md_alg, &imprint, &imprint_len)
- || !TS_check_imprints(md_alg, imprint, imprint_len, tst_info)))
- goto err;
-
- /* Check nonces. */
- if ((ctx->flags & TS_VFY_NONCE)
- && !TS_check_nonces(ctx->nonce, tst_info))
- goto err;
-
- /* Check whether TSA name and signer certificate match. */
- if ((ctx->flags & TS_VFY_SIGNER)
- && tsa_name && !TS_check_signer_name(tsa_name, signer))
- {
- TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_NAME_MISMATCH);
- goto err;
- }
-
- /* Check whether the TSA is the expected one. */
- if ((ctx->flags & TS_VFY_TSA_NAME)
- && !TS_check_signer_name(ctx->tsa_name, signer))
- {
- TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_UNTRUSTED);
- goto err;
- }
-
- ret = 1;
- err:
- X509_free(signer);
- X509_ALGOR_free(md_alg);
- OPENSSL_free(imprint);
- return ret;
- }
-
-static int TS_check_status_info(TS_RESP *response)
- {
- TS_STATUS_INFO *info = TS_RESP_get_status_info(response);
- long status = ASN1_INTEGER_get(info->status);
- const char *status_text = NULL;
- char *embedded_status_text = NULL;
- char failure_text[TS_STATUS_BUF_SIZE] = "";
-
- /* Check if everything went fine. */
- if (status == 0 || status == 1) return 1;
-
- /* There was an error, get the description in status_text. */
- if (0 <= status && status < (long)TS_STATUS_TEXT_SIZE)
- status_text = TS_status_text[status];
- else
- status_text = "unknown code";
-
- /* Set the embedded_status_text to the returned description. */
- if (sk_ASN1_UTF8STRING_num(info->text) > 0
- && !(embedded_status_text = TS_get_status_text(info->text)))
- return 0;
-
- /* Filling in failure_text with the failure information. */
- if (info->failure_info)
- {
- int i;
- int first = 1;
- for (i = 0; i < (int)TS_FAILURE_INFO_SIZE; ++i)
- {
- if (ASN1_BIT_STRING_get_bit(info->failure_info,
- TS_failure_info[i].code))
- {
- if (!first)
- strcpy(failure_text, ",");
- else
- first = 0;
- strcat(failure_text, TS_failure_info[i].text);
- }
- }
- }
- if (failure_text[0] == '\0')
- strcpy(failure_text, "unspecified");
-
- /* Making up the error string. */
- TSerr(TS_F_TS_CHECK_STATUS_INFO, TS_R_NO_TIME_STAMP_TOKEN);
- ERR_add_error_data(6,
- "status code: ", status_text,
- ", status text: ", embedded_status_text ?
- embedded_status_text : "unspecified",
- ", failure codes: ", failure_text);
- OPENSSL_free(embedded_status_text);
-
- return 0;
- }
-
-static char *TS_get_status_text(STACK_OF(ASN1_UTF8STRING) *text)
- {
- int i;
- unsigned int length = 0;
- char *result = NULL;
- char *p;
-
- /* Determine length first. */
- for (i = 0; i < sk_ASN1_UTF8STRING_num(text); ++i)
- {
- ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
- length += ASN1_STRING_length(current);
- length += 1; /* separator character */
- }
- /* Allocate memory (closing '\0' included). */
- if (!(result = OPENSSL_malloc(length)))
- {
- TSerr(TS_F_TS_GET_STATUS_TEXT, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- /* Concatenate the descriptions. */
- for (i = 0, p = result; i < sk_ASN1_UTF8STRING_num(text); ++i)
- {
- ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
- length = ASN1_STRING_length(current);
- if (i > 0) *p++ = '/';
- strncpy(p, (const char *)ASN1_STRING_data(current), length);
- p += length;
- }
- /* We do have space for this, too. */
- *p = '\0';
-
- return result;
- }
-
-static int TS_check_policy(ASN1_OBJECT *req_oid, TS_TST_INFO *tst_info)
- {
- ASN1_OBJECT *resp_oid = TS_TST_INFO_get_policy_id(tst_info);
-
- if (OBJ_cmp(req_oid, resp_oid) != 0)
- {
- TSerr(TS_F_TS_CHECK_POLICY, TS_R_POLICY_MISMATCH);
- return 0;
- }
-
- return 1;
- }
-
-static int TS_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
- X509_ALGOR **md_alg,
- unsigned char **imprint, unsigned *imprint_len)
- {
- TS_MSG_IMPRINT *msg_imprint = TS_TST_INFO_get_msg_imprint(tst_info);
- X509_ALGOR *md_alg_resp = TS_MSG_IMPRINT_get_algo(msg_imprint);
- const EVP_MD *md;
- EVP_MD_CTX md_ctx;
- unsigned char buffer[4096];
- int length;
-
- *md_alg = NULL;
- *imprint = NULL;
-
- /* Return the MD algorithm of the response. */
- if (!(*md_alg = X509_ALGOR_dup(md_alg_resp))) goto err;
-
- /* Getting the MD object. */
- if (!(md = EVP_get_digestbyobj((*md_alg)->algorithm)))
- {
- TSerr(TS_F_TS_COMPUTE_IMPRINT, TS_R_UNSUPPORTED_MD_ALGORITHM);
- goto err;
- }
-
- /* Compute message digest. */
- length = EVP_MD_size(md);
- if (length < 0)
- goto err;
- *imprint_len = length;
- if (!(*imprint = OPENSSL_malloc(*imprint_len)))
- {
- TSerr(TS_F_TS_COMPUTE_IMPRINT, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!EVP_DigestInit(&md_ctx, md))
- goto err;
- while ((length = BIO_read(data, buffer, sizeof(buffer))) > 0)
- {
- if (!EVP_DigestUpdate(&md_ctx, buffer, length))
- goto err;
- }
- if (!EVP_DigestFinal(&md_ctx, *imprint, NULL))
- goto err;
-
- return 1;
- err:
- X509_ALGOR_free(*md_alg);
- OPENSSL_free(*imprint);
- *imprint_len = 0;
- return 0;
- }
-
-static int TS_check_imprints(X509_ALGOR *algor_a,
- unsigned char *imprint_a, unsigned len_a,
- TS_TST_INFO *tst_info)
- {
- TS_MSG_IMPRINT *b = TS_TST_INFO_get_msg_imprint(tst_info);
- X509_ALGOR *algor_b = TS_MSG_IMPRINT_get_algo(b);
- int ret = 0;
-
- /* algor_a is optional. */
- if (algor_a)
- {
- /* Compare algorithm OIDs. */
- if (OBJ_cmp(algor_a->algorithm, algor_b->algorithm)) goto err;
-
- /* The parameter must be NULL in both. */
- if ((algor_a->parameter
- && ASN1_TYPE_get(algor_a->parameter) != V_ASN1_NULL)
- || (algor_b->parameter
- && ASN1_TYPE_get(algor_b->parameter) != V_ASN1_NULL))
- goto err;
- }
-
- /* Compare octet strings. */
- ret = len_a == (unsigned) ASN1_STRING_length(b->hashed_msg) &&
- memcmp(imprint_a, ASN1_STRING_data(b->hashed_msg), len_a) == 0;
- err:
- if (!ret)
- TSerr(TS_F_TS_CHECK_IMPRINTS, TS_R_MESSAGE_IMPRINT_MISMATCH);
- return ret;
- }
-
-static int TS_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info)
- {
- const ASN1_INTEGER *b = TS_TST_INFO_get_nonce(tst_info);
-
- /* Error if nonce is missing. */
- if (!b)
- {
- TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_NOT_RETURNED);
- return 0;
- }
-
- /* No error if a nonce is returned without being requested. */
- if (ASN1_INTEGER_cmp(a, b) != 0)
- {
- TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_MISMATCH);
- return 0;
- }
-
- return 1;
- }
-
-/* Check if the specified TSA name matches either the subject
- or one of the subject alternative names of the TSA certificate. */
-static int TS_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer)
- {
- STACK_OF(GENERAL_NAME) *gen_names = NULL;
- int idx = -1;
- int found = 0;
-
- /* Check the subject name first. */
- if (tsa_name->type == GEN_DIRNAME
- && X509_name_cmp(tsa_name->d.dirn, signer->cert_info->subject) == 0)
- return 1;
-
- /* Check all the alternative names. */
- gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name,
- NULL, &idx);
- while (gen_names != NULL
- && !(found = TS_find_name(gen_names, tsa_name) >= 0))
- {
- /* Get the next subject alternative name,
- although there should be no more than one. */
- GENERAL_NAMES_free(gen_names);
- gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name,
- NULL, &idx);
- }
- if (gen_names) GENERAL_NAMES_free(gen_names);
-
- return found;
- }
-
-/* Returns 1 if name is in gen_names, 0 otherwise. */
-static int TS_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name)
- {
- int i, found;
- for (i = 0, found = 0; !found && i < sk_GENERAL_NAME_num(gen_names);
- ++i)
- {
- GENERAL_NAME *current = sk_GENERAL_NAME_value(gen_names, i);
- found = GENERAL_NAME_cmp(current, name) == 0;
- }
- return found ? i - 1 : -1;
- }
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_purp.c b/drivers/builtin_openssl/crypto/x509v3/v3_purp.c
deleted file mode 100644
index ad688657e0..0000000000
--- a/drivers/builtin_openssl/crypto/x509v3/v3_purp.c
+++ /dev/null
@@ -1,767 +0,0 @@
-/* v3_purp.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 2001.
- */
-/* ====================================================================
- * Copyright (c) 1999-2004 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/x509v3.h>
-#include <openssl/x509_vfy.h>
-
-static void x509v3_cache_extensions(X509 *x);
-
-static int check_ssl_ca(const X509 *x);
-static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca);
-static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca);
-static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca);
-static int purpose_smime(const X509 *x, int ca);
-static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
-static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca);
-static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
-static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
-static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
-static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
-
-static int xp_cmp(const X509_PURPOSE * const *a,
- const X509_PURPOSE * const *b);
-static void xptable_free(X509_PURPOSE *p);
-
-static X509_PURPOSE xstandard[] = {
- {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, "SSL client", "sslclient", NULL},
- {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ssl_server, "SSL server", "sslserver", NULL},
- {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
- {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, "S/MIME signing", "smimesign", NULL},
- {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
- {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL},
- {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", NULL},
- {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL},
- {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", NULL},
-};
-
-#define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
-
-IMPLEMENT_STACK_OF(X509_PURPOSE)
-
-static STACK_OF(X509_PURPOSE) *xptable = NULL;
-
-static int xp_cmp(const X509_PURPOSE * const *a,
- const X509_PURPOSE * const *b)
-{
- return (*a)->purpose - (*b)->purpose;
-}
-
-/* As much as I'd like to make X509_check_purpose use a "const" X509*
- * I really can't because it does recalculate hashes and do other non-const
- * things. */
-int X509_check_purpose(X509 *x, int id, int ca)
-{
- int idx;
- const X509_PURPOSE *pt;
- if(!(x->ex_flags & EXFLAG_SET)) {
- CRYPTO_w_lock(CRYPTO_LOCK_X509);
- x509v3_cache_extensions(x);
- CRYPTO_w_unlock(CRYPTO_LOCK_X509);
- }
- if(id == -1) return 1;
- idx = X509_PURPOSE_get_by_id(id);
- if(idx == -1) return -1;
- pt = X509_PURPOSE_get0(idx);
- return pt->check_purpose(pt, x, ca);
-}
-
-int X509_PURPOSE_set(int *p, int purpose)
-{
- if(X509_PURPOSE_get_by_id(purpose) == -1) {
- X509V3err(X509V3_F_X509_PURPOSE_SET, X509V3_R_INVALID_PURPOSE);
- return 0;
- }
- *p = purpose;
- return 1;
-}
-
-int X509_PURPOSE_get_count(void)
-{
- if(!xptable) return X509_PURPOSE_COUNT;
- return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
-}
-
-X509_PURPOSE * X509_PURPOSE_get0(int idx)
-{
- if(idx < 0) return NULL;
- if(idx < (int)X509_PURPOSE_COUNT) return xstandard + idx;
- return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
-}
-
-int X509_PURPOSE_get_by_sname(char *sname)
-{
- int i;
- X509_PURPOSE *xptmp;
- for(i = 0; i < X509_PURPOSE_get_count(); i++) {
- xptmp = X509_PURPOSE_get0(i);
- if(!strcmp(xptmp->sname, sname)) return i;
- }
- return -1;
-}
-
-int X509_PURPOSE_get_by_id(int purpose)
-{
- X509_PURPOSE tmp;
- int idx;
- if((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX))
- return purpose - X509_PURPOSE_MIN;
- tmp.purpose = purpose;
- if(!xptable) return -1;
- idx = sk_X509_PURPOSE_find(xptable, &tmp);
- if(idx == -1) return -1;
- return idx + X509_PURPOSE_COUNT;
-}
-
-int X509_PURPOSE_add(int id, int trust, int flags,
- int (*ck)(const X509_PURPOSE *, const X509 *, int),
- char *name, char *sname, void *arg)
-{
- int idx;
- X509_PURPOSE *ptmp;
- /* This is set according to what we change: application can't set it */
- flags &= ~X509_PURPOSE_DYNAMIC;
- /* This will always be set for application modified trust entries */
- flags |= X509_PURPOSE_DYNAMIC_NAME;
- /* Get existing entry if any */
- idx = X509_PURPOSE_get_by_id(id);
- /* Need a new entry */
- if(idx == -1) {
- if(!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) {
- X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
- return 0;
- }
- ptmp->flags = X509_PURPOSE_DYNAMIC;
- } else ptmp = X509_PURPOSE_get0(idx);
-
- /* OPENSSL_free existing name if dynamic */
- if(ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
- OPENSSL_free(ptmp->name);
- OPENSSL_free(ptmp->sname);
- }
- /* dup supplied name */
- ptmp->name = BUF_strdup(name);
- ptmp->sname = BUF_strdup(sname);
- if(!ptmp->name || !ptmp->sname) {
- X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
- return 0;
- }
- /* Keep the dynamic flag of existing entry */
- ptmp->flags &= X509_PURPOSE_DYNAMIC;
- /* Set all other flags */
- ptmp->flags |= flags;
-
- ptmp->purpose = id;
- ptmp->trust = trust;
- ptmp->check_purpose = ck;
- ptmp->usr_data = arg;
-
- /* If its a new entry manage the dynamic table */
- if(idx == -1) {
- if(!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) {
- X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
- return 0;
- }
- if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
- X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
- return 0;
- }
- }
- return 1;
-}
-
-static void xptable_free(X509_PURPOSE *p)
- {
- if(!p) return;
- if (p->flags & X509_PURPOSE_DYNAMIC)
- {
- if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
- OPENSSL_free(p->name);
- OPENSSL_free(p->sname);
- }
- OPENSSL_free(p);
- }
- }
-
-void X509_PURPOSE_cleanup(void)
-{
- unsigned int i;
- sk_X509_PURPOSE_pop_free(xptable, xptable_free);
- for(i = 0; i < X509_PURPOSE_COUNT; i++) xptable_free(xstandard + i);
- xptable = NULL;
-}
-
-int X509_PURPOSE_get_id(X509_PURPOSE *xp)
-{
- return xp->purpose;
-}
-
-char *X509_PURPOSE_get0_name(X509_PURPOSE *xp)
-{
- return xp->name;
-}
-
-char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp)
-{
- return xp->sname;
-}
-
-int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
-{
- return xp->trust;
-}
-
-static int nid_cmp(const int *a, const int *b)
- {
- return *a - *b;
- }
-
-DECLARE_OBJ_BSEARCH_CMP_FN(int, int, nid);
-IMPLEMENT_OBJ_BSEARCH_CMP_FN(int, int, nid);
-
-int X509_supported_extension(X509_EXTENSION *ex)
- {
- /* This table is a list of the NIDs of supported extensions:
- * that is those which are used by the verify process. If
- * an extension is critical and doesn't appear in this list
- * then the verify process will normally reject the certificate.
- * The list must be kept in numerical order because it will be
- * searched using bsearch.
- */
-
- static const int supported_nids[] = {
- NID_netscape_cert_type, /* 71 */
- NID_key_usage, /* 83 */
- NID_subject_alt_name, /* 85 */
- NID_basic_constraints, /* 87 */
- NID_certificate_policies, /* 89 */
- NID_ext_key_usage, /* 126 */
-#ifndef OPENSSL_NO_RFC3779
- NID_sbgp_ipAddrBlock, /* 290 */
- NID_sbgp_autonomousSysNum, /* 291 */
-#endif
- NID_policy_constraints, /* 401 */
- NID_proxyCertInfo, /* 663 */
- NID_name_constraints, /* 666 */
- NID_policy_mappings, /* 747 */
- NID_inhibit_any_policy /* 748 */
- };
-
- int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
-
- if (ex_nid == NID_undef)
- return 0;
-
- if (OBJ_bsearch_nid(&ex_nid, supported_nids,
- sizeof(supported_nids)/sizeof(int)))
- return 1;
- return 0;
- }
-
-static void setup_dp(X509 *x, DIST_POINT *dp)
- {
- X509_NAME *iname = NULL;
- int i;
- if (dp->reasons)
- {
- if (dp->reasons->length > 0)
- dp->dp_reasons = dp->reasons->data[0];
- if (dp->reasons->length > 1)
- dp->dp_reasons |= (dp->reasons->data[1] << 8);
- dp->dp_reasons &= CRLDP_ALL_REASONS;
- }
- else
- dp->dp_reasons = CRLDP_ALL_REASONS;
- if (!dp->distpoint || (dp->distpoint->type != 1))
- return;
- for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++)
- {
- GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
- if (gen->type == GEN_DIRNAME)
- {
- iname = gen->d.directoryName;
- break;
- }
- }
- if (!iname)
- iname = X509_get_issuer_name(x);
-
- DIST_POINT_set_dpname(dp->distpoint, iname);
-
- }
-
-static void setup_crldp(X509 *x)
- {
- int i;
- x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL);
- for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++)
- setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
- }
-
-static void x509v3_cache_extensions(X509 *x)
-{
- BASIC_CONSTRAINTS *bs;
- PROXY_CERT_INFO_EXTENSION *pci;
- ASN1_BIT_STRING *usage;
- ASN1_BIT_STRING *ns;
- EXTENDED_KEY_USAGE *extusage;
- X509_EXTENSION *ex;
-
- int i;
- if(x->ex_flags & EXFLAG_SET) return;
-#ifndef OPENSSL_NO_SHA
- X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
-#endif
- /* Does subject name match issuer ? */
- if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
- x->ex_flags |= EXFLAG_SI;
- /* V1 should mean no extensions ... */
- if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;
- /* Handle basic constraints */
- if((bs=X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) {
- if(bs->ca) x->ex_flags |= EXFLAG_CA;
- if(bs->pathlen) {
- if((bs->pathlen->type == V_ASN1_NEG_INTEGER)
- || !bs->ca) {
- x->ex_flags |= EXFLAG_INVALID;
- x->ex_pathlen = 0;
- } else x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
- } else x->ex_pathlen = -1;
- BASIC_CONSTRAINTS_free(bs);
- x->ex_flags |= EXFLAG_BCONS;
- }
- /* Handle proxy certificates */
- if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
- if (x->ex_flags & EXFLAG_CA
- || X509_get_ext_by_NID(x, NID_subject_alt_name, 0) >= 0
- || X509_get_ext_by_NID(x, NID_issuer_alt_name, 0) >= 0) {
- x->ex_flags |= EXFLAG_INVALID;
- }
- if (pci->pcPathLengthConstraint) {
- x->ex_pcpathlen =
- ASN1_INTEGER_get(pci->pcPathLengthConstraint);
- } else x->ex_pcpathlen = -1;
- PROXY_CERT_INFO_EXTENSION_free(pci);
- x->ex_flags |= EXFLAG_PROXY;
- }
- /* Handle key usage */
- if((usage=X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
- if(usage->length > 0) {
- x->ex_kusage = usage->data[0];
- if(usage->length > 1)
- x->ex_kusage |= usage->data[1] << 8;
- } else x->ex_kusage = 0;
- x->ex_flags |= EXFLAG_KUSAGE;
- ASN1_BIT_STRING_free(usage);
- }
- x->ex_xkusage = 0;
- if((extusage=X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) {
- x->ex_flags |= EXFLAG_XKUSAGE;
- for(i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
- switch(OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage,i))) {
- case NID_server_auth:
- x->ex_xkusage |= XKU_SSL_SERVER;
- break;
-
- case NID_client_auth:
- x->ex_xkusage |= XKU_SSL_CLIENT;
- break;
-
- case NID_email_protect:
- x->ex_xkusage |= XKU_SMIME;
- break;
-
- case NID_code_sign:
- x->ex_xkusage |= XKU_CODE_SIGN;
- break;
-
- case NID_ms_sgc:
- case NID_ns_sgc:
- x->ex_xkusage |= XKU_SGC;
- break;
-
- case NID_OCSP_sign:
- x->ex_xkusage |= XKU_OCSP_SIGN;
- break;
-
- case NID_time_stamp:
- x->ex_xkusage |= XKU_TIMESTAMP;
- break;
-
- case NID_dvcs:
- x->ex_xkusage |= XKU_DVCS;
- break;
- }
- }
- sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
- }
-
- if((ns=X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) {
- if(ns->length > 0) x->ex_nscert = ns->data[0];
- else x->ex_nscert = 0;
- x->ex_flags |= EXFLAG_NSCERT;
- ASN1_BIT_STRING_free(ns);
- }
- x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
- x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
- x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
- x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL);
- if (!x->nc && (i != -1))
- x->ex_flags |= EXFLAG_INVALID;
- setup_crldp(x);
-
-#ifndef OPENSSL_NO_RFC3779
- x->rfc3779_addr =X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
- x->rfc3779_asid =X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum,
- NULL, NULL);
-#endif
- for (i = 0; i < X509_get_ext_count(x); i++)
- {
- ex = X509_get_ext(x, i);
- if (OBJ_obj2nid(X509_EXTENSION_get_object(ex))
- == NID_freshest_crl)
- x->ex_flags |= EXFLAG_FRESHEST;
- if (!X509_EXTENSION_get_critical(ex))
- continue;
- if (!X509_supported_extension(ex))
- {
- x->ex_flags |= EXFLAG_CRITICAL;
- break;
- }
- }
- x->ex_flags |= EXFLAG_SET;
-}
-
-/* CA checks common to all purposes
- * return codes:
- * 0 not a CA
- * 1 is a CA
- * 2 basicConstraints absent so "maybe" a CA
- * 3 basicConstraints absent but self signed V1.
- * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
- */
-
-#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
-#define ku_reject(x, usage) \
- (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
-#define xku_reject(x, usage) \
- (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
-#define ns_reject(x, usage) \
- (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
-
-static int check_ca(const X509 *x)
-{
- /* keyUsage if present should allow cert signing */
- if(ku_reject(x, KU_KEY_CERT_SIGN)) return 0;
- if(x->ex_flags & EXFLAG_BCONS) {
- if(x->ex_flags & EXFLAG_CA) return 1;
- /* If basicConstraints says not a CA then say so */
- else return 0;
- } else {
- /* we support V1 roots for... uh, I don't really know why. */
- if((x->ex_flags & V1_ROOT) == V1_ROOT) return 3;
- /* If key usage present it must have certSign so tolerate it */
- else if (x->ex_flags & EXFLAG_KUSAGE) return 4;
- /* Older certificates could have Netscape-specific CA types */
- else if (x->ex_flags & EXFLAG_NSCERT
- && x->ex_nscert & NS_ANY_CA) return 5;
- /* can this still be regarded a CA certificate? I doubt it */
- return 0;
- }
-}
-
-int X509_check_ca(X509 *x)
-{
- if(!(x->ex_flags & EXFLAG_SET)) {
- CRYPTO_w_lock(CRYPTO_LOCK_X509);
- x509v3_cache_extensions(x);
- CRYPTO_w_unlock(CRYPTO_LOCK_X509);
- }
-
- return check_ca(x);
-}
-
-/* Check SSL CA: common checks for SSL client and server */
-static int check_ssl_ca(const X509 *x)
-{
- int ca_ret;
- ca_ret = check_ca(x);
- if(!ca_ret) return 0;
- /* check nsCertType if present */
- if(ca_ret != 5 || x->ex_nscert & NS_SSL_CA) return ca_ret;
- else return 0;
-}
-
-
-static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca)
-{
- if(xku_reject(x,XKU_SSL_CLIENT)) return 0;
- if(ca) return check_ssl_ca(x);
- /* We need to do digital signatures with it */
- if(ku_reject(x,KU_DIGITAL_SIGNATURE)) return 0;
- /* nsCertType if present should allow SSL client use */
- if(ns_reject(x, NS_SSL_CLIENT)) return 0;
- return 1;
-}
-
-static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca)
-{
- if(xku_reject(x,XKU_SSL_SERVER|XKU_SGC)) return 0;
- if(ca) return check_ssl_ca(x);
-
- if(ns_reject(x, NS_SSL_SERVER)) return 0;
- /* Now as for keyUsage: we'll at least need to sign OR encipher */
- if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT)) return 0;
-
- return 1;
-
-}
-
-static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca)
-{
- int ret;
- ret = check_purpose_ssl_server(xp, x, ca);
- if(!ret || ca) return ret;
- /* We need to encipher or Netscape complains */
- if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0;
- return ret;
-}
-
-/* common S/MIME checks */
-static int purpose_smime(const X509 *x, int ca)
-{
- if(xku_reject(x,XKU_SMIME)) return 0;
- if(ca) {
- int ca_ret;
- ca_ret = check_ca(x);
- if(!ca_ret) return 0;
- /* check nsCertType if present */
- if(ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) return ca_ret;
- else return 0;
- }
- if(x->ex_flags & EXFLAG_NSCERT) {
- if(x->ex_nscert & NS_SMIME) return 1;
- /* Workaround for some buggy certificates */
- if(x->ex_nscert & NS_SSL_CLIENT) return 2;
- return 0;
- }
- return 1;
-}
-
-static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca)
-{
- int ret;
- ret = purpose_smime(x, ca);
- if(!ret || ca) return ret;
- if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_NON_REPUDIATION)) return 0;
- return ret;
-}
-
-static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca)
-{
- int ret;
- ret = purpose_smime(x, ca);
- if(!ret || ca) return ret;
- if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0;
- return ret;
-}
-
-static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca)
-{
- if(ca) {
- int ca_ret;
- if((ca_ret = check_ca(x)) != 2) return ca_ret;
- else return 0;
- }
- if(ku_reject(x, KU_CRL_SIGN)) return 0;
- return 1;
-}
-
-/* OCSP helper: this is *not* a full OCSP check. It just checks that
- * each CA is valid. Additional checks must be made on the chain.
- */
-
-static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
-{
- /* Must be a valid CA. Should we really support the "I don't know"
- value (2)? */
- if(ca) return check_ca(x);
- /* leaf certificate is checked in OCSP_verify() */
- return 1;
-}
-
-static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
- int ca)
-{
- int i_ext;
-
- /* If ca is true we must return if this is a valid CA certificate. */
- if (ca) return check_ca(x);
-
- /*
- * Check the optional key usage field:
- * if Key Usage is present, it must be one of digitalSignature
- * and/or nonRepudiation (other values are not consistent and shall
- * be rejected).
- */
- if ((x->ex_flags & EXFLAG_KUSAGE)
- && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) ||
- !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE))))
- return 0;
-
- /* Only time stamp key usage is permitted and it's required. */
- if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP)
- return 0;
-
- /* Extended Key Usage MUST be critical */
- i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, 0);
- if (i_ext >= 0)
- {
- X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext);
- if (!X509_EXTENSION_get_critical(ext))
- return 0;
- }
-
- return 1;
-}
-
-static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
-{
- return 1;
-}
-
-/* Various checks to see if one certificate issued the second.
- * This can be used to prune a set of possible issuer certificates
- * which have been looked up using some simple method such as by
- * subject name.
- * These are:
- * 1. Check issuer_name(subject) == subject_name(issuer)
- * 2. If akid(subject) exists check it matches issuer
- * 3. If key_usage(issuer) exists check it supports certificate signing
- * returns 0 for OK, positive for reason for mismatch, reasons match
- * codes for X509_verify_cert()
- */
-
-int X509_check_issued(X509 *issuer, X509 *subject)
-{
- if(X509_NAME_cmp(X509_get_subject_name(issuer),
- X509_get_issuer_name(subject)))
- return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
- x509v3_cache_extensions(issuer);
- x509v3_cache_extensions(subject);
-
- if(subject->akid)
- {
- int ret = X509_check_akid(issuer, subject->akid);
- if (ret != X509_V_OK)
- return ret;
- }
-
- if(subject->ex_flags & EXFLAG_PROXY)
- {
- if(ku_reject(issuer, KU_DIGITAL_SIGNATURE))
- return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
- }
- else if(ku_reject(issuer, KU_KEY_CERT_SIGN))
- return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
- return X509_V_OK;
-}
-
-int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
- {
-
- if(!akid)
- return X509_V_OK;
-
- /* Check key ids (if present) */
- if(akid->keyid && issuer->skid &&
- ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) )
- return X509_V_ERR_AKID_SKID_MISMATCH;
- /* Check serial number */
- if(akid->serial &&
- ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial))
- return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
- /* Check issuer name */
- if(akid->issuer)
- {
- /* Ugh, for some peculiar reason AKID includes
- * SEQUENCE OF GeneralName. So look for a DirName.
- * There may be more than one but we only take any
- * notice of the first.
- */
- GENERAL_NAMES *gens;
- GENERAL_NAME *gen;
- X509_NAME *nm = NULL;
- int i;
- gens = akid->issuer;
- for(i = 0; i < sk_GENERAL_NAME_num(gens); i++)
- {
- gen = sk_GENERAL_NAME_value(gens, i);
- if(gen->type == GEN_DIRNAME)
- {
- nm = gen->d.dirn;
- break;
- }
- }
- if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
- return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
- }
- return X509_V_OK;
- }
-
diff --git a/drivers/builtin_openssl/e_os.h b/drivers/builtin_openssl/e_os.h
deleted file mode 100644
index 9fcb8fbe2a..0000000000
--- a/drivers/builtin_openssl/e_os.h
+++ /dev/null
@@ -1,743 +0,0 @@
-/* e_os.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_E_OS_H
-#define HEADER_E_OS_H
-
-#include <openssl/opensslconf.h>
-
-#include <openssl/e_os2.h>
-/* <openssl/e_os2.h> contains what we can justify to make visible
- * to the outside; this file e_os.h is not part of the exported
- * interface. */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Used to checking reference counts, most while doing perl5 stuff :-) */
-#ifdef REF_PRINT
-#undef REF_PRINT
-#define REF_PRINT(a,b) fprintf(stderr,"%08X:%4d:%s\n",(int)b,b->references,a)
-#endif
-
-#ifndef DEVRANDOM
-/* set this to a comma-separated list of 'random' device files to try out.
- * My default, we will try to read at least one of these files */
-#define DEVRANDOM "/dev/urandom","/dev/random","/dev/srandom"
-#endif
-#ifndef DEVRANDOM_EGD
-/* set this to a comma-seperated list of 'egd' sockets to try out. These
- * sockets will be tried in the order listed in case accessing the device files
- * listed in DEVRANDOM did not return enough entropy. */
-#define DEVRANDOM_EGD "/var/run/egd-pool","/dev/egd-pool","/etc/egd-pool","/etc/entropy"
-#endif
-
-#if defined(OPENSSL_SYS_VXWORKS)
-# define NO_SYS_PARAM_H
-# define NO_CHMOD
-# define NO_SYSLOG
-#endif
-
-#if defined(OPENSSL_SYS_MACINTOSH_CLASSIC)
-# if macintosh==1
-# ifndef MAC_OS_GUSI_SOURCE
-# define MAC_OS_pre_X
-# define NO_SYS_TYPES_H
-# endif
-# define NO_SYS_PARAM_H
-# define NO_CHMOD
-# define NO_SYSLOG
-# undef DEVRANDOM
-# define GETPID_IS_MEANINGLESS
-# endif
-#endif
-
-/********************************************************************
- The Microsoft section
- ********************************************************************/
-/* The following is used because of the small stack in some
- * Microsoft operating systems */
-#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYSNAME_WIN32)
-# define MS_STATIC static
-#else
-# define MS_STATIC
-#endif
-
-#if defined(OPENSSL_SYS_WIN32) && !defined(WIN32)
-# define WIN32
-#endif
-#if defined(OPENSSL_SYS_WINDOWS) && !defined(WINDOWS)
-# define WINDOWS
-#endif
-#if defined(OPENSSL_SYS_MSDOS) && !defined(MSDOS)
-# define MSDOS
-#endif
-
-#if defined(MSDOS) && !defined(GETPID_IS_MEANINGLESS)
-# define GETPID_IS_MEANINGLESS
-#endif
-
-#ifdef WIN32
-#define get_last_sys_error() GetLastError()
-#define clear_sys_error() SetLastError(0)
-#if !defined(WINNT)
-#define WIN_CONSOLE_BUG
-#endif
-#else
-#define get_last_sys_error() errno
-#define clear_sys_error() errno=0
-#endif
-
-#if defined(WINDOWS)
-
-#define get_last_socket_error() WSAGetLastError()
-#define clear_socket_error() WSASetLastError(0)
-#define readsocket(s,b,n) recv((s),(b),(n),0)
-#define writesocket(s,b,n) send((s),(b),(n),0)
-#elif defined(__DJGPP__)
-#define WATT32
-#define get_last_socket_error() errno
-#define clear_socket_error() errno=0
-#define closesocket(s) close_s(s)
-#define readsocket(s,b,n) read_s(s,b,n)
-#define writesocket(s,b,n) send(s,b,n,0)
-#elif defined(MAC_OS_pre_X)
-#define get_last_socket_error() errno
-#define clear_socket_error() errno=0
-#define closesocket(s) MacSocket_close(s)
-#define readsocket(s,b,n) MacSocket_recv((s),(b),(n),true)
-#define writesocket(s,b,n) MacSocket_send((s),(b),(n))
-#elif defined(OPENSSL_SYS_VMS)
-#define get_last_socket_error() errno
-#define clear_socket_error() errno=0
-#define ioctlsocket(a,b,c) ioctl(a,b,c)
-#define closesocket(s) close(s)
-#define readsocket(s,b,n) recv((s),(b),(n),0)
-#define writesocket(s,b,n) send((s),(b),(n),0)
-#elif defined(OPENSSL_SYS_VXWORKS)
-#define get_last_socket_error() errno
-#define clear_socket_error() errno=0
-#define ioctlsocket(a,b,c) ioctl((a),(b),(int)(c))
-#define closesocket(s) close(s)
-#define readsocket(s,b,n) read((s),(b),(n))
-#define writesocket(s,b,n) write((s),(char *)(b),(n))
-#elif defined(OPENSSL_SYS_BEOS_R5)
-#define get_last_socket_error() errno
-#define clear_socket_error() errno=0
-#define FIONBIO SO_NONBLOCK
-#define ioctlsocket(a,b,c) setsockopt((a),SOL_SOCKET,(b),(c),sizeof(*(c)))
-#define readsocket(s,b,n) recv((s),(b),(n),0)
-#define writesocket(s,b,n) send((s),(b),(n),0)
-#elif defined(OPENSSL_SYS_NETWARE)
-#if defined(NETWARE_BSDSOCK)
-#define get_last_socket_error() errno
-#define clear_socket_error() errno=0
-#define closesocket(s) close(s)
-#define ioctlsocket(a,b,c) ioctl(a,b,c)
-#if defined(NETWARE_LIBC)
-#define readsocket(s,b,n) recv((s),(b),(n),0)
-#define writesocket(s,b,n) send((s),(b),(n),0)
-#else
-#define readsocket(s,b,n) recv((s),(char*)(b),(n),0)
-#define writesocket(s,b,n) send((s),(char*)(b),(n),0)
-#endif
-#else
-#define get_last_socket_error() WSAGetLastError()
-#define clear_socket_error() WSASetLastError(0)
-#define readsocket(s,b,n) recv((s),(b),(n),0)
-#define writesocket(s,b,n) send((s),(b),(n),0)
-#endif
-#else
-#define get_last_socket_error() errno
-#define clear_socket_error() errno=0
-#define ioctlsocket(a,b,c) ioctl(a,b,c)
-#define closesocket(s) close(s)
-#define readsocket(s,b,n) read((s),(b),(n))
-#define writesocket(s,b,n) write((s),(b),(n))
-#endif
-
-#ifdef WIN16 /* never the case */
-# define MS_CALLBACK _far _loadds
-# define MS_FAR _far
-#else
-# define MS_CALLBACK
-# define MS_FAR
-#endif
-
-#ifdef OPENSSL_NO_STDIO
-# undef OPENSSL_NO_FP_API
-# define OPENSSL_NO_FP_API
-#endif
-
-#if (defined(WINDOWS) || defined(MSDOS))
-
-# ifdef __DJGPP__
-# include <unistd.h>
-# include <sys/stat.h>
-# include <sys/socket.h>
-# include <tcp.h>
-# include <netdb.h>
-# define _setmode setmode
-# define _O_TEXT O_TEXT
-# define _O_BINARY O_BINARY
-# undef DEVRANDOM
-# define DEVRANDOM "/dev/urandom\x24"
-# endif /* __DJGPP__ */
-
-# ifndef S_IFDIR
-# define S_IFDIR _S_IFDIR
-# endif
-
-# ifndef S_IFMT
-# define S_IFMT _S_IFMT
-# endif
-
-# if !defined(WINNT) && !defined(__DJGPP__)
-# define NO_SYSLOG
-# endif
-# define NO_DIRENT
-
-# ifdef WINDOWS
-# if !defined(_WIN32_WCE) && !defined(_WIN32_WINNT)
- /*
- * Defining _WIN32_WINNT here in e_os.h implies certain "discipline."
- * Most notably we ought to check for availability of each specific
- * routine with GetProcAddress() and/or guard NT-specific calls with
- * GetVersion() < 0x80000000. One can argue that in latter "or" case
- * we ought to /DELAYLOAD some .DLLs in order to protect ourselves
- * against run-time link errors. This doesn't seem to be necessary,
- * because it turned out that already Windows 95, first non-NT Win32
- * implementation, is equipped with at least NT 3.51 stubs, dummy
- * routines with same name, but which do nothing. Meaning that it's
- * apparently sufficient to guard "vanilla" NT calls with GetVersion
- * alone, while NT 4.0 and above interfaces ought to be linked with
- * GetProcAddress at run-time.
- */
-# define _WIN32_WINNT 0x0400
-# endif
-# if !defined(OPENSSL_NO_SOCK) && defined(_WIN32_WINNT)
- /*
- * Just like defining _WIN32_WINNT including winsock2.h implies
- * certain "discipline" for maintaining [broad] binary compatibility.
- * As long as structures are invariant among Winsock versions,
- * it's sufficient to check for specific Winsock2 API availability
- * at run-time [DSO_global_lookup is recommended]...
- */
-# include <winsock2.h>
-# include <ws2tcpip.h>
- /* yes, they have to be #included prior to <windows.h> */
-# endif
-#define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-# include <stdio.h>
-# include <stddef.h>
-# include <errno.h>
-# include <string.h>
-# ifdef _WIN64
-# define strlen(s) _strlen31(s)
-/* cut strings to 2GB */
-static unsigned int _strlen31(const char *str)
- {
- unsigned int len=0;
- while (*str && len<0x80000000U) str++, len++;
- return len&0x7FFFFFFF;
- }
-# endif
-# include <malloc.h>
-# if defined(_MSC_VER) && _MSC_VER<=1200 && defined(_MT) && defined(isspace)
- /* compensate for bug in VC6 ctype.h */
-# undef isspace
-# undef isdigit
-# undef isalnum
-# undef isupper
-# undef isxdigit
-# endif
-# if defined(_MSC_VER) && !defined(_DLL) && defined(stdin)
-# if _MSC_VER>=1300
-# undef stdin
-# undef stdout
-# undef stderr
- FILE *__iob_func();
-# define stdin (&__iob_func()[0])
-# define stdout (&__iob_func()[1])
-# define stderr (&__iob_func()[2])
-# elif defined(I_CAN_LIVE_WITH_LNK4049)
-# undef stdin
-# undef stdout
-# undef stderr
- /* pre-1300 has __p__iob(), but it's available only in msvcrt.lib,
- * or in other words with /MD. Declaring implicit import, i.e.
- * with _imp_ prefix, works correctly with all compiler options,
- * but without /MD results in LINK warning LNK4049:
- * 'locally defined symbol "__iob" imported'.
- */
- extern FILE *_imp___iob;
-# define stdin (&_imp___iob[0])
-# define stdout (&_imp___iob[1])
-# define stderr (&_imp___iob[2])
-# endif
-# endif
-# endif
-# include <io.h>
-# include <fcntl.h>
-
-# ifdef OPENSSL_SYS_WINCE
-# define OPENSSL_NO_POSIX_IO
-# endif
-
-# if defined (__BORLANDC__)
-# define _setmode setmode
-# define _O_TEXT O_TEXT
-# define _O_BINARY O_BINARY
-# define _int64 __int64
-# define _kbhit kbhit
-# endif
-
-# define EXIT(n) exit(n)
-# define LIST_SEPARATOR_CHAR ';'
-# ifndef X_OK
-# define X_OK 0
-# endif
-# ifndef W_OK
-# define W_OK 2
-# endif
-# ifndef R_OK
-# define R_OK 4
-# endif
-# define OPENSSL_CONF "openssl.cnf"
-# define SSLEAY_CONF OPENSSL_CONF
-# define NUL_DEV "nul"
-# define RFILE ".rnd"
-# ifdef OPENSSL_SYS_WINCE
-# define DEFAULT_HOME ""
-# else
-# define DEFAULT_HOME "C:"
-# endif
-
-/* Avoid Windows 8 SDK GetVersion deprecated problems */
-#if defined(_MSC_VER) && _MSC_VER>=1800
-# define check_winnt() (1)
-#else
-# define check_winnt() (GetVersion() < 0x80000000)
-#endif
-
-#else /* The non-microsoft world */
-
-# ifdef OPENSSL_SYS_VMS
-# define VMS 1
- /* some programs don't include stdlib, so exit() and others give implicit
- function warnings */
-# include <stdlib.h>
-# if defined(__DECC)
-# include <unistd.h>
-# else
-# include <unixlib.h>
-# endif
-# define OPENSSL_CONF "openssl.cnf"
-# define SSLEAY_CONF OPENSSL_CONF
-# define RFILE ".rnd"
-# define LIST_SEPARATOR_CHAR ','
-# define NUL_DEV "NLA0:"
- /* We don't have any well-defined random devices on VMS, yet... */
-# undef DEVRANDOM
- /* We need to do this since VMS has the following coding on status codes:
-
- Bits 0-2: status type: 0 = warning, 1 = success, 2 = error, 3 = info ...
- The important thing to know is that odd numbers are considered
- good, while even ones are considered errors.
- Bits 3-15: actual status number
- Bits 16-27: facility number. 0 is considered "unknown"
- Bits 28-31: control bits. If bit 28 is set, the shell won't try to
- output the message (which, for random codes, just looks ugly)
-
- So, what we do here is to change 0 to 1 to get the default success status,
- and everything else is shifted up to fit into the status number field, and
- the status is tagged as an error, which I believe is what is wanted here.
- -- Richard Levitte
- */
-# define EXIT(n) do { int __VMS_EXIT = n; \
- if (__VMS_EXIT == 0) \
- __VMS_EXIT = 1; \
- else \
- __VMS_EXIT = (n << 3) | 2; \
- __VMS_EXIT |= 0x10000000; \
- exit(__VMS_EXIT); } while(0)
-# define NO_SYS_PARAM_H
-
-# elif defined(OPENSSL_SYS_NETWARE)
-# include <fcntl.h>
-# include <unistd.h>
-# define NO_SYS_TYPES_H
-# undef DEVRANDOM
-# ifdef NETWARE_CLIB
-# define getpid GetThreadID
- extern int GetThreadID(void);
-/* # include <conio.h> */
- extern int kbhit(void);
-# else
-# include <screen.h>
-# endif
-# define NO_SYSLOG
-# define _setmode setmode
-# define _kbhit kbhit
-# define _O_TEXT O_TEXT
-# define _O_BINARY O_BINARY
-# define OPENSSL_CONF "openssl.cnf"
-# define SSLEAY_CONF OPENSSL_CONF
-# define RFILE ".rnd"
-# define LIST_SEPARATOR_CHAR ';'
-# define EXIT(n) { if (n) printf("ERROR: %d\n", (int)n); exit(n); }
-
-# else
- /* !defined VMS */
-# ifdef OPENSSL_SYS_MPE
-# define NO_SYS_PARAM_H
-# endif
-# ifdef OPENSSL_UNISTD
-# include OPENSSL_UNISTD
-# else
-# include <unistd.h>
-# endif
-# ifndef NO_SYS_TYPES_H
-# include <sys/types.h>
-# endif
-# if defined(NeXT) || defined(OPENSSL_SYS_NEWS4)
-# define pid_t int /* pid_t is missing on NEXTSTEP/OPENSTEP
- * (unless when compiling with -D_POSIX_SOURCE,
- * which doesn't work for us) */
-# endif
-# ifdef OPENSSL_SYS_NEWS4 /* setvbuf is missing on mips-sony-bsd */
-# define setvbuf(a, b, c, d) setbuffer((a), (b), (d))
- typedef unsigned long clock_t;
-# endif
-# ifdef OPENSSL_SYS_WIN32_CYGWIN
-# include <io.h>
-# include <fcntl.h>
-# endif
-
-# define OPENSSL_CONF "openssl.cnf"
-# define SSLEAY_CONF OPENSSL_CONF
-# define RFILE ".rnd"
-# define LIST_SEPARATOR_CHAR ':'
-# define NUL_DEV "/dev/null"
-# define EXIT(n) exit(n)
-# endif
-
-# define SSLeay_getpid() getpid()
-
-#endif
-
-
-/*************/
-
-#ifdef USE_SOCKETS
-# if defined(WINDOWS) || defined(MSDOS)
- /* windows world */
-
-# ifdef OPENSSL_NO_SOCK
-# define SSLeay_Write(a,b,c) (-1)
-# define SSLeay_Read(a,b,c) (-1)
-# define SHUTDOWN(fd) close(fd)
-# define SHUTDOWN2(fd) close(fd)
-# elif !defined(__DJGPP__)
-# if defined(_WIN32_WCE) && _WIN32_WCE<410
-# define getservbyname _masked_declaration_getservbyname
-# endif
-# if !defined(IPPROTO_IP)
- /* winsock[2].h was included already? */
-# include <winsock.h>
-# endif
-# ifdef getservbyname
-# undef getservbyname
- /* this is used to be wcecompat/include/winsock_extras.h */
- struct servent* PASCAL getservbyname(const char*,const char*);
-# endif
-
-# ifdef _WIN64
-/*
- * Even though sizeof(SOCKET) is 8, it's safe to cast it to int, because
- * the value constitutes an index in per-process table of limited size
- * and not a real pointer.
- */
-# define socket(d,t,p) ((int)socket(d,t,p))
-# define accept(s,f,l) ((int)accept(s,f,l))
-# endif
-# define SSLeay_Write(a,b,c) send((a),(b),(c),0)
-# define SSLeay_Read(a,b,c) recv((a),(b),(c),0)
-# define SHUTDOWN(fd) { shutdown((fd),0); closesocket(fd); }
-# define SHUTDOWN2(fd) { shutdown((fd),2); closesocket(fd); }
-# else
-# define SSLeay_Write(a,b,c) write_s(a,b,c,0)
-# define SSLeay_Read(a,b,c) read_s(a,b,c)
-# define SHUTDOWN(fd) close_s(fd)
-# define SHUTDOWN2(fd) close_s(fd)
-# endif
-
-# elif defined(MAC_OS_pre_X)
-
-# include "MacSocket.h"
-# define SSLeay_Write(a,b,c) MacSocket_send((a),(b),(c))
-# define SSLeay_Read(a,b,c) MacSocket_recv((a),(b),(c),true)
-# define SHUTDOWN(fd) MacSocket_close(fd)
-# define SHUTDOWN2(fd) MacSocket_close(fd)
-
-# elif defined(OPENSSL_SYS_NETWARE)
- /* NetWare uses the WinSock2 interfaces by default, but can be configured for BSD
- */
-# if defined(NETWARE_BSDSOCK)
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <sys/time.h>
-# if defined(NETWARE_CLIB)
-# include <sys/bsdskt.h>
-# else
-# include <sys/select.h>
-# endif
-# define INVALID_SOCKET (int)(~0)
-# else
-# include <novsock2.h>
-# endif
-# define SSLeay_Write(a,b,c) send((a),(b),(c),0)
-# define SSLeay_Read(a,b,c) recv((a),(b),(c),0)
-# define SHUTDOWN(fd) { shutdown((fd),0); closesocket(fd); }
-# define SHUTDOWN2(fd) { shutdown((fd),2); closesocket(fd); }
-
-# else
-
-# ifndef NO_SYS_PARAM_H
-# include <sys/param.h>
-# endif
-# ifdef OPENSSL_SYS_VXWORKS
-# include <time.h>
-# elif !defined(OPENSSL_SYS_MPE)
-# include <sys/time.h> /* Needed under linux for FD_XXX */
-# endif
-
-# include <netdb.h>
-# if defined(OPENSSL_SYS_VMS_NODECC)
-# include <socket.h>
-# include <in.h>
-# include <inet.h>
-# else
-# include <sys/socket.h>
-# ifdef FILIO_H
-# include <sys/filio.h> /* Added for FIONBIO under unixware */
-# endif
-# include <netinet/in.h>
-# if !defined(OPENSSL_SYS_BEOS_R5)
-# include <arpa/inet.h>
-# endif
-# endif
-
-# if defined(NeXT) || defined(_NEXT_SOURCE)
-# include <sys/fcntl.h>
-# include <sys/types.h>
-# endif
-
-# ifdef OPENSSL_SYS_AIX
-# include <sys/select.h>
-# endif
-
-# ifdef __QNX__
-# include <sys/select.h>
-# endif
-
-# if defined(sun)
-# include <sys/filio.h>
-# else
-# ifndef VMS
-# include <sys/ioctl.h>
-# else
- /* ioctl is only in VMS > 7.0 and when socketshr is not used */
-# if !defined(TCPIP_TYPE_SOCKETSHR) && defined(__VMS_VER) && (__VMS_VER > 70000000)
-# include <sys/ioctl.h>
-# endif
-# endif
-# endif
-
-# ifdef VMS
-# include <unixio.h>
-# if defined(TCPIP_TYPE_SOCKETSHR)
-# include <socketshr.h>
-# endif
-# endif
-
-# define SSLeay_Read(a,b,c) read((a),(b),(c))
-# define SSLeay_Write(a,b,c) write((a),(b),(c))
-# define SHUTDOWN(fd) { shutdown((fd),0); closesocket((fd)); }
-# define SHUTDOWN2(fd) { shutdown((fd),2); closesocket((fd)); }
-# ifndef INVALID_SOCKET
-# define INVALID_SOCKET (-1)
-# endif /* INVALID_SOCKET */
-# endif
-
-/* Some IPv6 implementations are broken, disable them in known bad
- * versions.
- */
-# if !defined(OPENSSL_USE_IPV6)
-# if defined(AF_INET6) && !defined(OPENSSL_SYS_BEOS_BONE) && !defined(NETWARE_CLIB)
-# define OPENSSL_USE_IPV6 1
-# else
-# define OPENSSL_USE_IPV6 0
-# endif
-# endif
-
-#endif
-
-#if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
- /* include headers first, so our defines don't break it */
-#include <stdlib.h>
-#include <string.h>
- /* bcopy can handle overlapping moves according to SunOS 4.1.4 manpage */
-# define memmove(s1,s2,n) bcopy((s2),(s1),(n))
-# define strtoul(s,e,b) ((unsigned long int)strtol((s),(e),(b)))
-extern char *sys_errlist[]; extern int sys_nerr;
-# define strerror(errnum) \
- (((errnum)<0 || (errnum)>=sys_nerr) ? NULL : sys_errlist[errnum])
- /* Being signed SunOS 4.x memcpy breaks ASN1_OBJECT table lookup */
-#include "crypto/o_str.h"
-# define memcmp OPENSSL_memcmp
-#endif
-
-#ifndef OPENSSL_EXIT
-# if defined(MONOLITH) && !defined(OPENSSL_C)
-# define OPENSSL_EXIT(n) return(n)
-# else
-# define OPENSSL_EXIT(n) do { EXIT(n); return(n); } while(0)
-# endif
-#endif
-
-/***********************************************/
-
-#define DG_GCC_BUG /* gcc < 2.6.3 on DGUX */
-
-#ifdef sgi
-#define IRIX_CC_BUG /* all version of IRIX I've tested (4.* 5.*) */
-#endif
-#ifdef OPENSSL_SYS_SNI
-#define IRIX_CC_BUG /* CDS++ up to V2.0Bsomething suffered from the same bug.*/
-#endif
-
-#if defined(OPENSSL_SYS_WINDOWS)
-# define strcasecmp _stricmp
-# define strncasecmp _strnicmp
-#elif defined(OPENSSL_SYS_VMS)
-/* VMS below version 7.0 doesn't have strcasecmp() */
-# include "o_str.h"
-# define strcasecmp OPENSSL_strcasecmp
-# define strncasecmp OPENSSL_strncasecmp
-# define OPENSSL_IMPLEMENTS_strncasecmp
-#elif defined(OPENSSL_SYS_OS2) && defined(__EMX__)
-# define strcasecmp stricmp
-# define strncasecmp strnicmp
-#elif defined(OPENSSL_SYS_NETWARE)
-# include <string.h>
-# if defined(NETWARE_CLIB)
-# define strcasecmp stricmp
-# define strncasecmp strnicmp
-# endif /* NETWARE_CLIB */
-#endif
-
-#if defined(OPENSSL_SYS_OS2) && defined(__EMX__)
-# include <io.h>
-# include <fcntl.h>
-# define NO_SYSLOG
-#endif
-
-/* vxworks */
-#if defined(OPENSSL_SYS_VXWORKS)
-#include <ioLib.h>
-#include <tickLib.h>
-#include <sysLib.h>
-
-#define TTY_STRUCT int
-
-#define sleep(a) taskDelay((a) * sysClkRateGet())
-
-#include <vxWorks.h>
-#include <sockLib.h>
-#include <taskLib.h>
-
-#define getpid taskIdSelf
-
-/* NOTE: these are implemented by helpers in database app!
- * if the database is not linked, we need to implement them
- * elswhere */
-struct hostent *gethostbyname(const char *name);
-struct hostent *gethostbyaddr(const char *addr, int length, int type);
-struct servent *getservbyname(const char *name, const char *proto);
-
-#endif
-/* end vxworks */
-
-/* beos */
-#if defined(OPENSSL_SYS_BEOS_R5)
-#define SO_ERROR 0
-#define NO_SYS_UN
-#define IPPROTO_IP 0
-#include <OS.h>
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/drivers/builtin_openssl/openssl/aes.h b/drivers/builtin_openssl/openssl/aes.h
deleted file mode 100644
index 031abf01b5..0000000000
--- a/drivers/builtin_openssl/openssl/aes.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 HEADER_AES_H
-#define HEADER_AES_H
-
-#include <openssl/opensslconf.h>
-
-#ifdef OPENSSL_NO_AES
-#error AES is disabled.
-#endif
-
-#include <stddef.h>
-
-#define AES_ENCRYPT 1
-#define AES_DECRYPT 0
-
-/* Because array size can't be a const in C, the following two are macros.
- Both sizes are in bytes. */
-#define AES_MAXNR 14
-#define AES_BLOCK_SIZE 16
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This should be a hidden type, but EVP requires that the size be known */
-struct aes_key_st {
-#ifdef AES_LONG
- unsigned long rd_key[4 *(AES_MAXNR + 1)];
-#else
- unsigned int rd_key[4 *(AES_MAXNR + 1)];
-#endif
- int rounds;
-};
-typedef struct aes_key_st AES_KEY;
-
-const char *AES_options(void);
-
-int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
- AES_KEY *key);
-int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
- AES_KEY *key);
-
-int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits,
- AES_KEY *key);
-int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits,
- AES_KEY *key);
-
-void AES_encrypt(const unsigned char *in, unsigned char *out,
- const AES_KEY *key);
-void AES_decrypt(const unsigned char *in, unsigned char *out,
- const AES_KEY *key);
-
-void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
- const AES_KEY *key, const int enc);
-void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const AES_KEY *key,
- unsigned char *ivec, const int enc);
-void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const AES_KEY *key,
- unsigned char *ivec, int *num, const int enc);
-void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const AES_KEY *key,
- unsigned char *ivec, int *num, const int enc);
-void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const AES_KEY *key,
- unsigned char *ivec, int *num, const int enc);
-void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const AES_KEY *key,
- unsigned char *ivec, int *num);
-void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const AES_KEY *key,
- unsigned char ivec[AES_BLOCK_SIZE],
- unsigned char ecount_buf[AES_BLOCK_SIZE],
- unsigned int *num);
-/* NB: the IV is _two_ blocks long */
-void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const AES_KEY *key,
- unsigned char *ivec, const int enc);
-/* NB: the IV is _four_ blocks long */
-void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const AES_KEY *key,
- const AES_KEY *key2, const unsigned char *ivec,
- const int enc);
-
-int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
- unsigned char *out,
- const unsigned char *in, unsigned int inlen);
-int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
- unsigned char *out,
- const unsigned char *in, unsigned int inlen);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !HEADER_AES_H */
diff --git a/drivers/builtin_openssl/openssl/asn1.h b/drivers/builtin_openssl/openssl/asn1.h
deleted file mode 100644
index 220a0c8c63..0000000000
--- a/drivers/builtin_openssl/openssl/asn1.h
+++ /dev/null
@@ -1,1404 +0,0 @@
-/* crypto/asn1/asn1.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_ASN1_H
-#define HEADER_ASN1_H
-
-#include <time.h>
-#include <openssl/e_os2.h>
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#include <openssl/stack.h>
-#include <openssl/safestack.h>
-
-#include <openssl/symhacks.h>
-
-#include <openssl/ossl_typ.h>
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/bn.h>
-#endif
-
-#ifdef OPENSSL_BUILD_SHLIBCRYPTO
-# undef OPENSSL_EXTERN
-# define OPENSSL_EXTERN OPENSSL_EXPORT
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define V_ASN1_UNIVERSAL 0x00
-#define V_ASN1_APPLICATION 0x40
-#define V_ASN1_CONTEXT_SPECIFIC 0x80
-#define V_ASN1_PRIVATE 0xc0
-
-#define V_ASN1_CONSTRUCTED 0x20
-#define V_ASN1_PRIMITIVE_TAG 0x1f
-#define V_ASN1_PRIMATIVE_TAG 0x1f
-
-#define V_ASN1_APP_CHOOSE -2 /* let the recipient choose */
-#define V_ASN1_OTHER -3 /* used in ASN1_TYPE */
-#define V_ASN1_ANY -4 /* used in ASN1 template code */
-
-#define V_ASN1_NEG 0x100 /* negative flag */
-
-#define V_ASN1_UNDEF -1
-#define V_ASN1_EOC 0
-#define V_ASN1_BOOLEAN 1 /**/
-#define V_ASN1_INTEGER 2
-#define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG)
-#define V_ASN1_BIT_STRING 3
-#define V_ASN1_OCTET_STRING 4
-#define V_ASN1_NULL 5
-#define V_ASN1_OBJECT 6
-#define V_ASN1_OBJECT_DESCRIPTOR 7
-#define V_ASN1_EXTERNAL 8
-#define V_ASN1_REAL 9
-#define V_ASN1_ENUMERATED 10
-#define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG)
-#define V_ASN1_UTF8STRING 12
-#define V_ASN1_SEQUENCE 16
-#define V_ASN1_SET 17
-#define V_ASN1_NUMERICSTRING 18 /**/
-#define V_ASN1_PRINTABLESTRING 19
-#define V_ASN1_T61STRING 20
-#define V_ASN1_TELETEXSTRING 20 /* alias */
-#define V_ASN1_VIDEOTEXSTRING 21 /**/
-#define V_ASN1_IA5STRING 22
-#define V_ASN1_UTCTIME 23
-#define V_ASN1_GENERALIZEDTIME 24 /**/
-#define V_ASN1_GRAPHICSTRING 25 /**/
-#define V_ASN1_ISO64STRING 26 /**/
-#define V_ASN1_VISIBLESTRING 26 /* alias */
-#define V_ASN1_GENERALSTRING 27 /**/
-#define V_ASN1_UNIVERSALSTRING 28 /**/
-#define V_ASN1_BMPSTRING 30
-
-/* For use with d2i_ASN1_type_bytes() */
-#define B_ASN1_NUMERICSTRING 0x0001
-#define B_ASN1_PRINTABLESTRING 0x0002
-#define B_ASN1_T61STRING 0x0004
-#define B_ASN1_TELETEXSTRING 0x0004
-#define B_ASN1_VIDEOTEXSTRING 0x0008
-#define B_ASN1_IA5STRING 0x0010
-#define B_ASN1_GRAPHICSTRING 0x0020
-#define B_ASN1_ISO64STRING 0x0040
-#define B_ASN1_VISIBLESTRING 0x0040
-#define B_ASN1_GENERALSTRING 0x0080
-#define B_ASN1_UNIVERSALSTRING 0x0100
-#define B_ASN1_OCTET_STRING 0x0200
-#define B_ASN1_BIT_STRING 0x0400
-#define B_ASN1_BMPSTRING 0x0800
-#define B_ASN1_UNKNOWN 0x1000
-#define B_ASN1_UTF8STRING 0x2000
-#define B_ASN1_UTCTIME 0x4000
-#define B_ASN1_GENERALIZEDTIME 0x8000
-#define B_ASN1_SEQUENCE 0x10000
-
-/* For use with ASN1_mbstring_copy() */
-#define MBSTRING_FLAG 0x1000
-#define MBSTRING_UTF8 (MBSTRING_FLAG)
-#define MBSTRING_ASC (MBSTRING_FLAG|1)
-#define MBSTRING_BMP (MBSTRING_FLAG|2)
-#define MBSTRING_UNIV (MBSTRING_FLAG|4)
-
-#define SMIME_OLDMIME 0x400
-#define SMIME_CRLFEOL 0x800
-#define SMIME_STREAM 0x1000
-
-struct X509_algor_st;
-DECLARE_STACK_OF(X509_ALGOR)
-
-#define DECLARE_ASN1_SET_OF(type) /* filled in by mkstack.pl */
-#define IMPLEMENT_ASN1_SET_OF(type) /* nothing, no longer needed */
-
-/* We MUST make sure that, except for constness, asn1_ctx_st and
- asn1_const_ctx are exactly the same. Fortunately, as soon as
- the old ASN1 parsing macros are gone, we can throw this away
- as well... */
-typedef struct asn1_ctx_st
- {
- unsigned char *p;/* work char pointer */
- int eos; /* end of sequence read for indefinite encoding */
- int error; /* error code to use when returning an error */
- int inf; /* constructed if 0x20, indefinite is 0x21 */
- int tag; /* tag from last 'get object' */
- int xclass; /* class from last 'get object' */
- long slen; /* length of last 'get object' */
- unsigned char *max; /* largest value of p allowed */
- unsigned char *q;/* temporary variable */
- unsigned char **pp;/* variable */
- int line; /* used in error processing */
- } ASN1_CTX;
-
-typedef struct asn1_const_ctx_st
- {
- const unsigned char *p;/* work char pointer */
- int eos; /* end of sequence read for indefinite encoding */
- int error; /* error code to use when returning an error */
- int inf; /* constructed if 0x20, indefinite is 0x21 */
- int tag; /* tag from last 'get object' */
- int xclass; /* class from last 'get object' */
- long slen; /* length of last 'get object' */
- const unsigned char *max; /* largest value of p allowed */
- const unsigned char *q;/* temporary variable */
- const unsigned char **pp;/* variable */
- int line; /* used in error processing */
- } ASN1_const_CTX;
-
-/* These are used internally in the ASN1_OBJECT to keep track of
- * whether the names and data need to be free()ed */
-#define ASN1_OBJECT_FLAG_DYNAMIC 0x01 /* internal use */
-#define ASN1_OBJECT_FLAG_CRITICAL 0x02 /* critical x509v3 object id */
-#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 /* internal use */
-#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 /* internal use */
-typedef struct asn1_object_st
- {
- const char *sn,*ln;
- int nid;
- int length;
- const unsigned char *data; /* data remains const after init */
- int flags; /* Should we free this one */
- } ASN1_OBJECT;
-
-#define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */
-/* This indicates that the ASN1_STRING is not a real value but just a place
- * holder for the location where indefinite length constructed data should
- * be inserted in the memory buffer
- */
-#define ASN1_STRING_FLAG_NDEF 0x010
-
-/* This flag is used by the CMS code to indicate that a string is not
- * complete and is a place holder for content when it had all been
- * accessed. The flag will be reset when content has been written to it.
- */
-
-#define ASN1_STRING_FLAG_CONT 0x020
-/* This flag is used by ASN1 code to indicate an ASN1_STRING is an MSTRING
- * type.
- */
-#define ASN1_STRING_FLAG_MSTRING 0x040
-/* This is the base type that holds just about everything :-) */
-struct asn1_string_st
- {
- int length;
- int type;
- unsigned char *data;
- /* The value of the following field depends on the type being
- * held. It is mostly being used for BIT_STRING so if the
- * input data has a non-zero 'unused bits' value, it will be
- * handled correctly */
- long flags;
- };
-
-/* ASN1_ENCODING structure: this is used to save the received
- * encoding of an ASN1 type. This is useful to get round
- * problems with invalid encodings which can break signatures.
- */
-
-typedef struct ASN1_ENCODING_st
- {
- unsigned char *enc; /* DER encoding */
- long len; /* Length of encoding */
- int modified; /* set to 1 if 'enc' is invalid */
- } ASN1_ENCODING;
-
-/* Used with ASN1 LONG type: if a long is set to this it is omitted */
-#define ASN1_LONG_UNDEF 0x7fffffffL
-
-#define STABLE_FLAGS_MALLOC 0x01
-#define STABLE_NO_MASK 0x02
-#define DIRSTRING_TYPE \
- (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING)
-#define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING)
-
-typedef struct asn1_string_table_st {
- int nid;
- long minsize;
- long maxsize;
- unsigned long mask;
- unsigned long flags;
-} ASN1_STRING_TABLE;
-
-DECLARE_STACK_OF(ASN1_STRING_TABLE)
-
-/* size limits: this stuff is taken straight from RFC2459 */
-
-#define ub_name 32768
-#define ub_common_name 64
-#define ub_locality_name 128
-#define ub_state_name 128
-#define ub_organization_name 64
-#define ub_organization_unit_name 64
-#define ub_title 64
-#define ub_email_address 128
-
-/* Declarations for template structures: for full definitions
- * see asn1t.h
- */
-typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
-typedef struct ASN1_TLC_st ASN1_TLC;
-/* This is just an opaque pointer */
-typedef struct ASN1_VALUE_st ASN1_VALUE;
-
-/* Declare ASN1 functions: the implement macro in in asn1t.h */
-
-#define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type)
-
-#define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \
- DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type)
-
-#define DECLARE_ASN1_FUNCTIONS_name(type, name) \
- DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
- DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name)
-
-#define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \
- DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
- DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name)
-
-#define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \
- type *d2i_##name(type **a, const unsigned char **in, long len); \
- int i2d_##name(type *a, unsigned char **out); \
- DECLARE_ASN1_ITEM(itname)
-
-#define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \
- type *d2i_##name(type **a, const unsigned char **in, long len); \
- int i2d_##name(const type *a, unsigned char **out); \
- DECLARE_ASN1_ITEM(name)
-
-#define DECLARE_ASN1_NDEF_FUNCTION(name) \
- int i2d_##name##_NDEF(name *a, unsigned char **out);
-
-#define DECLARE_ASN1_FUNCTIONS_const(name) \
- DECLARE_ASN1_ALLOC_FUNCTIONS(name) \
- DECLARE_ASN1_ENCODE_FUNCTIONS_const(name, name)
-
-#define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
- type *name##_new(void); \
- void name##_free(type *a);
-
-#define DECLARE_ASN1_PRINT_FUNCTION(stname) \
- DECLARE_ASN1_PRINT_FUNCTION_fname(stname, stname)
-
-#define DECLARE_ASN1_PRINT_FUNCTION_fname(stname, fname) \
- int fname##_print_ctx(BIO *out, stname *x, int indent, \
- const ASN1_PCTX *pctx);
-
-#define D2I_OF(type) type *(*)(type **,const unsigned char **,long)
-#define I2D_OF(type) int (*)(type *,unsigned char **)
-#define I2D_OF_const(type) int (*)(const type *,unsigned char **)
-
-#define CHECKED_D2I_OF(type, d2i) \
- ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0)))
-#define CHECKED_I2D_OF(type, i2d) \
- ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0)))
-#define CHECKED_NEW_OF(type, xnew) \
- ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0)))
-#define CHECKED_PTR_OF(type, p) \
- ((void*) (1 ? p : (type*)0))
-#define CHECKED_PPTR_OF(type, p) \
- ((void**) (1 ? p : (type**)0))
-
-#define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **,const unsigned char **,long)
-#define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(type *,unsigned char **)
-#define TYPEDEF_D2I2D_OF(type) TYPEDEF_D2I_OF(type); TYPEDEF_I2D_OF(type)
-
-TYPEDEF_D2I2D_OF(void);
-
-/* The following macros and typedefs allow an ASN1_ITEM
- * to be embedded in a structure and referenced. Since
- * the ASN1_ITEM pointers need to be globally accessible
- * (possibly from shared libraries) they may exist in
- * different forms. On platforms that support it the
- * ASN1_ITEM structure itself will be globally exported.
- * Other platforms will export a function that returns
- * an ASN1_ITEM pointer.
- *
- * To handle both cases transparently the macros below
- * should be used instead of hard coding an ASN1_ITEM
- * pointer in a structure.
- *
- * The structure will look like this:
- *
- * typedef struct SOMETHING_st {
- * ...
- * ASN1_ITEM_EXP *iptr;
- * ...
- * } SOMETHING;
- *
- * It would be initialised as e.g.:
- *
- * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...};
- *
- * and the actual pointer extracted with:
- *
- * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr);
- *
- * Finally an ASN1_ITEM pointer can be extracted from an
- * appropriate reference with: ASN1_ITEM_rptr(X509). This
- * would be used when a function takes an ASN1_ITEM * argument.
- *
- */
-
-#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
-
-/* ASN1_ITEM pointer exported type */
-typedef const ASN1_ITEM ASN1_ITEM_EXP;
-
-/* Macro to obtain ASN1_ITEM pointer from exported type */
-#define ASN1_ITEM_ptr(iptr) (iptr)
-
-/* Macro to include ASN1_ITEM pointer from base type */
-#define ASN1_ITEM_ref(iptr) (&(iptr##_it))
-
-#define ASN1_ITEM_rptr(ref) (&(ref##_it))
-
-#define DECLARE_ASN1_ITEM(name) \
- OPENSSL_EXTERN const ASN1_ITEM name##_it;
-
-#else
-
-/* Platforms that can't easily handle shared global variables are declared
- * as functions returning ASN1_ITEM pointers.
- */
-
-/* ASN1_ITEM pointer exported type */
-typedef const ASN1_ITEM * ASN1_ITEM_EXP(void);
-
-/* Macro to obtain ASN1_ITEM pointer from exported type */
-#define ASN1_ITEM_ptr(iptr) (iptr())
-
-/* Macro to include ASN1_ITEM pointer from base type */
-#define ASN1_ITEM_ref(iptr) (iptr##_it)
-
-#define ASN1_ITEM_rptr(ref) (ref##_it())
-
-#define DECLARE_ASN1_ITEM(name) \
- const ASN1_ITEM * name##_it(void);
-
-#endif
-
-/* Parameters used by ASN1_STRING_print_ex() */
-
-/* These determine which characters to escape:
- * RFC2253 special characters, control characters and
- * MSB set characters
- */
-
-#define ASN1_STRFLGS_ESC_2253 1
-#define ASN1_STRFLGS_ESC_CTRL 2
-#define ASN1_STRFLGS_ESC_MSB 4
-
-
-/* This flag determines how we do escaping: normally
- * RC2253 backslash only, set this to use backslash and
- * quote.
- */
-
-#define ASN1_STRFLGS_ESC_QUOTE 8
-
-
-/* These three flags are internal use only. */
-
-/* Character is a valid PrintableString character */
-#define CHARTYPE_PRINTABLESTRING 0x10
-/* Character needs escaping if it is the first character */
-#define CHARTYPE_FIRST_ESC_2253 0x20
-/* Character needs escaping if it is the last character */
-#define CHARTYPE_LAST_ESC_2253 0x40
-
-/* NB the internal flags are safely reused below by flags
- * handled at the top level.
- */
-
-/* If this is set we convert all character strings
- * to UTF8 first
- */
-
-#define ASN1_STRFLGS_UTF8_CONVERT 0x10
-
-/* If this is set we don't attempt to interpret content:
- * just assume all strings are 1 byte per character. This
- * will produce some pretty odd looking output!
- */
-
-#define ASN1_STRFLGS_IGNORE_TYPE 0x20
-
-/* If this is set we include the string type in the output */
-#define ASN1_STRFLGS_SHOW_TYPE 0x40
-
-/* This determines which strings to display and which to
- * 'dump' (hex dump of content octets or DER encoding). We can
- * only dump non character strings or everything. If we
- * don't dump 'unknown' they are interpreted as character
- * strings with 1 octet per character and are subject to
- * the usual escaping options.
- */
-
-#define ASN1_STRFLGS_DUMP_ALL 0x80
-#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100
-
-/* These determine what 'dumping' does, we can dump the
- * content octets or the DER encoding: both use the
- * RFC2253 #XXXXX notation.
- */
-
-#define ASN1_STRFLGS_DUMP_DER 0x200
-
-/* All the string flags consistent with RFC2253,
- * escaping control characters isn't essential in
- * RFC2253 but it is advisable anyway.
- */
-
-#define ASN1_STRFLGS_RFC2253 (ASN1_STRFLGS_ESC_2253 | \
- ASN1_STRFLGS_ESC_CTRL | \
- ASN1_STRFLGS_ESC_MSB | \
- ASN1_STRFLGS_UTF8_CONVERT | \
- ASN1_STRFLGS_DUMP_UNKNOWN | \
- ASN1_STRFLGS_DUMP_DER)
-
-DECLARE_STACK_OF(ASN1_INTEGER)
-DECLARE_ASN1_SET_OF(ASN1_INTEGER)
-
-DECLARE_STACK_OF(ASN1_GENERALSTRING)
-
-typedef struct asn1_type_st
- {
- int type;
- union {
- char *ptr;
- ASN1_BOOLEAN boolean;
- ASN1_STRING * asn1_string;
- ASN1_OBJECT * object;
- ASN1_INTEGER * integer;
- ASN1_ENUMERATED * enumerated;
- ASN1_BIT_STRING * bit_string;
- ASN1_OCTET_STRING * octet_string;
- ASN1_PRINTABLESTRING * printablestring;
- ASN1_T61STRING * t61string;
- ASN1_IA5STRING * ia5string;
- ASN1_GENERALSTRING * generalstring;
- ASN1_BMPSTRING * bmpstring;
- ASN1_UNIVERSALSTRING * universalstring;
- ASN1_UTCTIME * utctime;
- ASN1_GENERALIZEDTIME * generalizedtime;
- ASN1_VISIBLESTRING * visiblestring;
- ASN1_UTF8STRING * utf8string;
- /* set and sequence are left complete and still
- * contain the set or sequence bytes */
- ASN1_STRING * set;
- ASN1_STRING * sequence;
- ASN1_VALUE * asn1_value;
- } value;
- } ASN1_TYPE;
-
-DECLARE_STACK_OF(ASN1_TYPE)
-DECLARE_ASN1_SET_OF(ASN1_TYPE)
-
-typedef STACK_OF(ASN1_TYPE) ASN1_SEQUENCE_ANY;
-
-DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY)
-DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SET_ANY)
-
-typedef struct NETSCAPE_X509_st
- {
- ASN1_OCTET_STRING *header;
- X509 *cert;
- } NETSCAPE_X509;
-
-/* This is used to contain a list of bit names */
-typedef struct BIT_STRING_BITNAME_st {
- int bitnum;
- const char *lname;
- const char *sname;
-} BIT_STRING_BITNAME;
-
-
-#define M_ASN1_STRING_length(x) ((x)->length)
-#define M_ASN1_STRING_length_set(x, n) ((x)->length = (n))
-#define M_ASN1_STRING_type(x) ((x)->type)
-#define M_ASN1_STRING_data(x) ((x)->data)
-
-/* Macros for string operations */
-#define M_ASN1_BIT_STRING_new() (ASN1_BIT_STRING *)\
- ASN1_STRING_type_new(V_ASN1_BIT_STRING)
-#define M_ASN1_BIT_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_ASN1_BIT_STRING_dup(a) (ASN1_BIT_STRING *)\
- ASN1_STRING_dup((const ASN1_STRING *)a)
-#define M_ASN1_BIT_STRING_cmp(a,b) ASN1_STRING_cmp(\
- (const ASN1_STRING *)a,(const ASN1_STRING *)b)
-#define M_ASN1_BIT_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c)
-
-#define M_ASN1_INTEGER_new() (ASN1_INTEGER *)\
- ASN1_STRING_type_new(V_ASN1_INTEGER)
-#define M_ASN1_INTEGER_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_ASN1_INTEGER_dup(a) (ASN1_INTEGER *)\
- ASN1_STRING_dup((const ASN1_STRING *)a)
-#define M_ASN1_INTEGER_cmp(a,b) ASN1_STRING_cmp(\
- (const ASN1_STRING *)a,(const ASN1_STRING *)b)
-
-#define M_ASN1_ENUMERATED_new() (ASN1_ENUMERATED *)\
- ASN1_STRING_type_new(V_ASN1_ENUMERATED)
-#define M_ASN1_ENUMERATED_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_ASN1_ENUMERATED_dup(a) (ASN1_ENUMERATED *)\
- ASN1_STRING_dup((const ASN1_STRING *)a)
-#define M_ASN1_ENUMERATED_cmp(a,b) ASN1_STRING_cmp(\
- (const ASN1_STRING *)a,(const ASN1_STRING *)b)
-
-#define M_ASN1_OCTET_STRING_new() (ASN1_OCTET_STRING *)\
- ASN1_STRING_type_new(V_ASN1_OCTET_STRING)
-#define M_ASN1_OCTET_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_ASN1_OCTET_STRING_dup(a) (ASN1_OCTET_STRING *)\
- ASN1_STRING_dup((const ASN1_STRING *)a)
-#define M_ASN1_OCTET_STRING_cmp(a,b) ASN1_STRING_cmp(\
- (const ASN1_STRING *)a,(const ASN1_STRING *)b)
-#define M_ASN1_OCTET_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c)
-#define M_ASN1_OCTET_STRING_print(a,b) ASN1_STRING_print(a,(ASN1_STRING *)b)
-#define M_i2d_ASN1_OCTET_STRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,\
- V_ASN1_UNIVERSAL)
-
-#define B_ASN1_TIME \
- B_ASN1_UTCTIME | \
- B_ASN1_GENERALIZEDTIME
-
-#define B_ASN1_PRINTABLE \
- B_ASN1_NUMERICSTRING| \
- B_ASN1_PRINTABLESTRING| \
- B_ASN1_T61STRING| \
- B_ASN1_IA5STRING| \
- B_ASN1_BIT_STRING| \
- B_ASN1_UNIVERSALSTRING|\
- B_ASN1_BMPSTRING|\
- B_ASN1_UTF8STRING|\
- B_ASN1_SEQUENCE|\
- B_ASN1_UNKNOWN
-
-#define B_ASN1_DIRECTORYSTRING \
- B_ASN1_PRINTABLESTRING| \
- B_ASN1_TELETEXSTRING|\
- B_ASN1_BMPSTRING|\
- B_ASN1_UNIVERSALSTRING|\
- B_ASN1_UTF8STRING
-
-#define B_ASN1_DISPLAYTEXT \
- B_ASN1_IA5STRING| \
- B_ASN1_VISIBLESTRING| \
- B_ASN1_BMPSTRING|\
- B_ASN1_UTF8STRING
-
-#define M_ASN1_PRINTABLE_new() ASN1_STRING_type_new(V_ASN1_T61STRING)
-#define M_ASN1_PRINTABLE_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
- pp,a->type,V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_PRINTABLE(a,pp,l) \
- d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
- B_ASN1_PRINTABLE)
-
-#define M_DIRECTORYSTRING_new() ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING)
-#define M_DIRECTORYSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
- pp,a->type,V_ASN1_UNIVERSAL)
-#define M_d2i_DIRECTORYSTRING(a,pp,l) \
- d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
- B_ASN1_DIRECTORYSTRING)
-
-#define M_DISPLAYTEXT_new() ASN1_STRING_type_new(V_ASN1_VISIBLESTRING)
-#define M_DISPLAYTEXT_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
- pp,a->type,V_ASN1_UNIVERSAL)
-#define M_d2i_DISPLAYTEXT(a,pp,l) \
- d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
- B_ASN1_DISPLAYTEXT)
-
-#define M_ASN1_PRINTABLESTRING_new() (ASN1_PRINTABLESTRING *)\
- ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING)
-#define M_ASN1_PRINTABLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_ASN1_PRINTABLESTRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,\
- V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) \
- (ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes\
- ((ASN1_STRING **)a,pp,l,B_ASN1_PRINTABLESTRING)
-
-#define M_ASN1_T61STRING_new() (ASN1_T61STRING *)\
- ASN1_STRING_type_new(V_ASN1_T61STRING)
-#define M_ASN1_T61STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_ASN1_T61STRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_T61STRING,\
- V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_T61STRING(a,pp,l) \
- (ASN1_T61STRING *)d2i_ASN1_type_bytes\
- ((ASN1_STRING **)a,pp,l,B_ASN1_T61STRING)
-
-#define M_ASN1_IA5STRING_new() (ASN1_IA5STRING *)\
- ASN1_STRING_type_new(V_ASN1_IA5STRING)
-#define M_ASN1_IA5STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_ASN1_IA5STRING_dup(a) \
- (ASN1_IA5STRING *)ASN1_STRING_dup((const ASN1_STRING *)a)
-#define M_i2d_ASN1_IA5STRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_IA5STRING,\
- V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_IA5STRING(a,pp,l) \
- (ASN1_IA5STRING *)d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l,\
- B_ASN1_IA5STRING)
-
-#define M_ASN1_UTCTIME_new() (ASN1_UTCTIME *)\
- ASN1_STRING_type_new(V_ASN1_UTCTIME)
-#define M_ASN1_UTCTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_ASN1_UTCTIME_dup(a) (ASN1_UTCTIME *)\
- ASN1_STRING_dup((const ASN1_STRING *)a)
-
-#define M_ASN1_GENERALIZEDTIME_new() (ASN1_GENERALIZEDTIME *)\
- ASN1_STRING_type_new(V_ASN1_GENERALIZEDTIME)
-#define M_ASN1_GENERALIZEDTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_ASN1_GENERALIZEDTIME_dup(a) (ASN1_GENERALIZEDTIME *)ASN1_STRING_dup(\
- (const ASN1_STRING *)a)
-
-#define M_ASN1_TIME_new() (ASN1_TIME *)\
- ASN1_STRING_type_new(V_ASN1_UTCTIME)
-#define M_ASN1_TIME_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_ASN1_TIME_dup(a) (ASN1_TIME *)\
- ASN1_STRING_dup((const ASN1_STRING *)a)
-
-#define M_ASN1_GENERALSTRING_new() (ASN1_GENERALSTRING *)\
- ASN1_STRING_type_new(V_ASN1_GENERALSTRING)
-#define M_ASN1_GENERALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_ASN1_GENERALSTRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,\
- V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_GENERALSTRING(a,pp,l) \
- (ASN1_GENERALSTRING *)d2i_ASN1_type_bytes\
- ((ASN1_STRING **)a,pp,l,B_ASN1_GENERALSTRING)
-
-#define M_ASN1_UNIVERSALSTRING_new() (ASN1_UNIVERSALSTRING *)\
- ASN1_STRING_type_new(V_ASN1_UNIVERSALSTRING)
-#define M_ASN1_UNIVERSALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,\
- V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) \
- (ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes\
- ((ASN1_STRING **)a,pp,l,B_ASN1_UNIVERSALSTRING)
-
-#define M_ASN1_BMPSTRING_new() (ASN1_BMPSTRING *)\
- ASN1_STRING_type_new(V_ASN1_BMPSTRING)
-#define M_ASN1_BMPSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_ASN1_BMPSTRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,\
- V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_BMPSTRING(a,pp,l) \
- (ASN1_BMPSTRING *)d2i_ASN1_type_bytes\
- ((ASN1_STRING **)a,pp,l,B_ASN1_BMPSTRING)
-
-#define M_ASN1_VISIBLESTRING_new() (ASN1_VISIBLESTRING *)\
- ASN1_STRING_type_new(V_ASN1_VISIBLESTRING)
-#define M_ASN1_VISIBLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_ASN1_VISIBLESTRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,\
- V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) \
- (ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes\
- ((ASN1_STRING **)a,pp,l,B_ASN1_VISIBLESTRING)
-
-#define M_ASN1_UTF8STRING_new() (ASN1_UTF8STRING *)\
- ASN1_STRING_type_new(V_ASN1_UTF8STRING)
-#define M_ASN1_UTF8STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
-#define M_i2d_ASN1_UTF8STRING(a,pp) \
- i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,\
- V_ASN1_UNIVERSAL)
-#define M_d2i_ASN1_UTF8STRING(a,pp,l) \
- (ASN1_UTF8STRING *)d2i_ASN1_type_bytes\
- ((ASN1_STRING **)a,pp,l,B_ASN1_UTF8STRING)
-
- /* for the is_set parameter to i2d_ASN1_SET */
-#define IS_SEQUENCE 0
-#define IS_SET 1
-
-DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
-
-int ASN1_TYPE_get(ASN1_TYPE *a);
-void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value);
-int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value);
-int ASN1_TYPE_cmp(ASN1_TYPE *a, ASN1_TYPE *b);
-
-ASN1_OBJECT * ASN1_OBJECT_new(void );
-void ASN1_OBJECT_free(ASN1_OBJECT *a);
-int i2d_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char **pp);
-ASN1_OBJECT * c2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp,
- long length);
-ASN1_OBJECT * d2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp,
- long length);
-
-DECLARE_ASN1_ITEM(ASN1_OBJECT)
-
-DECLARE_STACK_OF(ASN1_OBJECT)
-DECLARE_ASN1_SET_OF(ASN1_OBJECT)
-
-ASN1_STRING * ASN1_STRING_new(void);
-void ASN1_STRING_free(ASN1_STRING *a);
-int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str);
-ASN1_STRING * ASN1_STRING_dup(const ASN1_STRING *a);
-ASN1_STRING * ASN1_STRING_type_new(int type );
-int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b);
- /* Since this is used to store all sorts of things, via macros, for now, make
- its data void * */
-int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
-void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len);
-int ASN1_STRING_length(const ASN1_STRING *x);
-void ASN1_STRING_length_set(ASN1_STRING *x, int n);
-int ASN1_STRING_type(ASN1_STRING *x);
-unsigned char * ASN1_STRING_data(ASN1_STRING *x);
-
-DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING)
-int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp);
-ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,const unsigned char **pp,
- long length);
-int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d,
- int length );
-int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value);
-int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n);
-int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a,
- unsigned char *flags, int flags_len);
-
-#ifndef OPENSSL_NO_BIO
-int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
- BIT_STRING_BITNAME *tbl, int indent);
-#endif
-int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl);
-int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value,
- BIT_STRING_BITNAME *tbl);
-
-int i2d_ASN1_BOOLEAN(int a,unsigned char **pp);
-int d2i_ASN1_BOOLEAN(int *a,const unsigned char **pp,long length);
-
-DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER)
-int i2c_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp);
-ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,const unsigned char **pp,
- long length);
-ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a,const unsigned char **pp,
- long length);
-ASN1_INTEGER * ASN1_INTEGER_dup(const ASN1_INTEGER *x);
-int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y);
-
-DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED)
-
-int ASN1_UTCTIME_check(ASN1_UTCTIME *a);
-ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s,time_t t);
-ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
- int offset_day, long offset_sec);
-int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str);
-int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t);
-#if 0
-time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s);
-#endif
-
-int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *a);
-ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,time_t t);
-ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
- time_t t, int offset_day, long offset_sec);
-int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str);
-
-DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING)
-ASN1_OCTET_STRING * ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *a);
-int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, const ASN1_OCTET_STRING *b);
-int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, int len);
-
-DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING)
-DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING)
-DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING)
-DECLARE_ASN1_FUNCTIONS(ASN1_NULL)
-DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING)
-
-int UTF8_getc(const unsigned char *str, int len, unsigned long *val);
-int UTF8_putc(unsigned char *str, int len, unsigned long value);
-
-DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE)
-
-DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING)
-DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT)
-DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING)
-DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING)
-DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING)
-DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING)
-DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME)
-DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME)
-DECLARE_ASN1_FUNCTIONS(ASN1_TIME)
-
-DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF)
-
-ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s,time_t t);
-ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s,time_t t,
- int offset_day, long offset_sec);
-int ASN1_TIME_check(ASN1_TIME *t);
-ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out);
-int ASN1_TIME_set_string(ASN1_TIME *s, const char *str);
-
-int i2d_ASN1_SET(STACK_OF(OPENSSL_BLOCK) *a, unsigned char **pp,
- i2d_of_void *i2d, int ex_tag, int ex_class,
- int is_set);
-STACK_OF(OPENSSL_BLOCK) *d2i_ASN1_SET(STACK_OF(OPENSSL_BLOCK) **a,
- const unsigned char **pp,
- long length, d2i_of_void *d2i,
- void (*free_func)(OPENSSL_BLOCK), int ex_tag,
- int ex_class);
-
-#ifndef OPENSSL_NO_BIO
-int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a);
-int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size);
-int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a);
-int a2i_ASN1_ENUMERATED(BIO *bp,ASN1_ENUMERATED *bs,char *buf,int size);
-int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a);
-int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size);
-int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type);
-#endif
-int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a);
-
-int a2d_ASN1_OBJECT(unsigned char *out,int olen, const char *buf, int num);
-ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len,
- const char *sn, const char *ln);
-
-int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
-long ASN1_INTEGER_get(const ASN1_INTEGER *a);
-ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai);
-BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai,BIGNUM *bn);
-
-int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);
-long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a);
-ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai);
-BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai,BIGNUM *bn);
-
-/* General */
-/* given a string, return the correct type, max is the maximum length */
-int ASN1_PRINTABLE_type(const unsigned char *s, int max);
-
-int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass);
-ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
- long length, int Ptag, int Pclass);
-unsigned long ASN1_tag2bit(int tag);
-/* type is one or more of the B_ASN1_ values. */
-ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a,const unsigned char **pp,
- long length,int type);
-
-/* PARSING */
-int asn1_Finish(ASN1_CTX *c);
-int asn1_const_Finish(ASN1_const_CTX *c);
-
-/* SPECIALS */
-int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
- int *pclass, long omax);
-int ASN1_check_infinite_end(unsigned char **p,long len);
-int ASN1_const_check_infinite_end(const unsigned char **p,long len);
-void ASN1_put_object(unsigned char **pp, int constructed, int length,
- int tag, int xclass);
-int ASN1_put_eoc(unsigned char **pp);
-int ASN1_object_size(int constructed, int length, int tag);
-
-/* Used to implement other functions */
-void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x);
-
-#define ASN1_dup_of(type,i2d,d2i,x) \
- ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \
- CHECKED_D2I_OF(type, d2i), \
- CHECKED_PTR_OF(type, x)))
-
-#define ASN1_dup_of_const(type,i2d,d2i,x) \
- ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \
- CHECKED_D2I_OF(type, d2i), \
- CHECKED_PTR_OF(const type, x)))
-
-void *ASN1_item_dup(const ASN1_ITEM *it, void *x);
-
-/* ASN1 alloc/free macros for when a type is only used internally */
-
-#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type))
-#define M_ASN1_free_of(x, type) \
- ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type))
-
-#ifndef OPENSSL_NO_FP_API
-void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x);
-
-#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \
- ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \
- CHECKED_D2I_OF(type, d2i), \
- in, \
- CHECKED_PPTR_OF(type, x)))
-
-void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
-int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x);
-
-#define ASN1_i2d_fp_of(type,i2d,out,x) \
- (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \
- out, \
- CHECKED_PTR_OF(type, x)))
-
-#define ASN1_i2d_fp_of_const(type,i2d,out,x) \
- (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \
- out, \
- CHECKED_PTR_OF(const type, x)))
-
-int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x);
-int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags);
-#endif
-
-int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in);
-
-#ifndef OPENSSL_NO_BIO
-void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x);
-
-#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \
- ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \
- CHECKED_D2I_OF(type, d2i), \
- in, \
- CHECKED_PPTR_OF(type, x)))
-
-void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x);
-int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, unsigned char *x);
-
-#define ASN1_i2d_bio_of(type,i2d,out,x) \
- (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \
- out, \
- CHECKED_PTR_OF(type, x)))
-
-#define ASN1_i2d_bio_of_const(type,i2d,out,x) \
- (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \
- out, \
- CHECKED_PTR_OF(const type, x)))
-
-int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x);
-int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a);
-int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a);
-int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a);
-int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v);
-int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags);
-int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num,
- unsigned char *buf, int off);
-int ASN1_parse(BIO *bp,const unsigned char *pp,long len,int indent);
-int ASN1_parse_dump(BIO *bp,const unsigned char *pp,long len,int indent,int dump);
-#endif
-const char *ASN1_tag2str(int tag);
-
-/* Used to load and write netscape format cert */
-
-DECLARE_ASN1_FUNCTIONS(NETSCAPE_X509)
-
-int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s);
-
-int ASN1_TYPE_set_octetstring(ASN1_TYPE *a,
- unsigned char *data, int len);
-int ASN1_TYPE_get_octetstring(ASN1_TYPE *a,
- unsigned char *data, int max_len);
-int ASN1_TYPE_set_int_octetstring(ASN1_TYPE *a, long num,
- unsigned char *data, int len);
-int ASN1_TYPE_get_int_octetstring(ASN1_TYPE *a,long *num,
- unsigned char *data, int max_len);
-
-STACK_OF(OPENSSL_BLOCK) *ASN1_seq_unpack(const unsigned char *buf, int len,
- d2i_of_void *d2i, void (*free_func)(OPENSSL_BLOCK));
-unsigned char *ASN1_seq_pack(STACK_OF(OPENSSL_BLOCK) *safes, i2d_of_void *i2d,
- unsigned char **buf, int *len );
-void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i);
-void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it);
-ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d,
- ASN1_OCTET_STRING **oct);
-
-#define ASN1_pack_string_of(type,obj,i2d,oct) \
- (ASN1_pack_string(CHECKED_PTR_OF(type, obj), \
- CHECKED_I2D_OF(type, i2d), \
- oct))
-
-ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct);
-
-void ASN1_STRING_set_default_mask(unsigned long mask);
-int ASN1_STRING_set_default_mask_asc(const char *p);
-unsigned long ASN1_STRING_get_default_mask(void);
-int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
- int inform, unsigned long mask);
-int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
- int inform, unsigned long mask,
- long minsize, long maxsize);
-
-ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
- const unsigned char *in, int inlen, int inform, int nid);
-ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid);
-int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long);
-void ASN1_STRING_TABLE_cleanup(void);
-
-/* ASN1 template functions */
-
-/* Old API compatible functions */
-ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it);
-void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it);
-ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it);
-int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
-int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
-
-void ASN1_add_oid_module(void);
-
-ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf);
-ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf);
-
-/* ASN1 Print flags */
-
-/* Indicate missing OPTIONAL fields */
-#define ASN1_PCTX_FLAGS_SHOW_ABSENT 0x001
-/* Mark start and end of SEQUENCE */
-#define ASN1_PCTX_FLAGS_SHOW_SEQUENCE 0x002
-/* Mark start and end of SEQUENCE/SET OF */
-#define ASN1_PCTX_FLAGS_SHOW_SSOF 0x004
-/* Show the ASN1 type of primitives */
-#define ASN1_PCTX_FLAGS_SHOW_TYPE 0x008
-/* Don't show ASN1 type of ANY */
-#define ASN1_PCTX_FLAGS_NO_ANY_TYPE 0x010
-/* Don't show ASN1 type of MSTRINGs */
-#define ASN1_PCTX_FLAGS_NO_MSTRING_TYPE 0x020
-/* Don't show field names in SEQUENCE */
-#define ASN1_PCTX_FLAGS_NO_FIELD_NAME 0x040
-/* Show structure names of each SEQUENCE field */
-#define ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME 0x080
-/* Don't show structure name even at top level */
-#define ASN1_PCTX_FLAGS_NO_STRUCT_NAME 0x100
-
-int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent,
- const ASN1_ITEM *it, const ASN1_PCTX *pctx);
-ASN1_PCTX *ASN1_PCTX_new(void);
-void ASN1_PCTX_free(ASN1_PCTX *p);
-unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p);
-void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags);
-unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p);
-void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags);
-unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p);
-void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags);
-unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p);
-void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags);
-unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p);
-void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags);
-
-BIO_METHOD *BIO_f_asn1(void);
-
-BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it);
-
-int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
- const ASN1_ITEM *it);
-int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
- const char *hdr,
- const ASN1_ITEM *it);
-int SMIME_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
- int ctype_nid, int econt_nid,
- STACK_OF(X509_ALGOR) *mdalgs,
- const ASN1_ITEM *it);
-ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it);
-int SMIME_crlf_copy(BIO *in, BIO *out, int flags);
-int SMIME_text(BIO *in, BIO *out);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_ASN1_strings(void);
-
-/* Error codes for the ASN1 functions. */
-
-/* Function codes. */
-#define ASN1_F_A2D_ASN1_OBJECT 100
-#define ASN1_F_A2I_ASN1_ENUMERATED 101
-#define ASN1_F_A2I_ASN1_INTEGER 102
-#define ASN1_F_A2I_ASN1_STRING 103
-#define ASN1_F_APPEND_EXP 176
-#define ASN1_F_ASN1_BIT_STRING_SET_BIT 183
-#define ASN1_F_ASN1_CB 177
-#define ASN1_F_ASN1_CHECK_TLEN 104
-#define ASN1_F_ASN1_COLLATE_PRIMITIVE 105
-#define ASN1_F_ASN1_COLLECT 106
-#define ASN1_F_ASN1_D2I_EX_PRIMITIVE 108
-#define ASN1_F_ASN1_D2I_FP 109
-#define ASN1_F_ASN1_D2I_READ_BIO 107
-#define ASN1_F_ASN1_DIGEST 184
-#define ASN1_F_ASN1_DO_ADB 110
-#define ASN1_F_ASN1_DUP 111
-#define ASN1_F_ASN1_ENUMERATED_SET 112
-#define ASN1_F_ASN1_ENUMERATED_TO_BN 113
-#define ASN1_F_ASN1_EX_C2I 204
-#define ASN1_F_ASN1_FIND_END 190
-#define ASN1_F_ASN1_GENERALIZEDTIME_ADJ 216
-#define ASN1_F_ASN1_GENERALIZEDTIME_SET 185
-#define ASN1_F_ASN1_GENERATE_V3 178
-#define ASN1_F_ASN1_GET_OBJECT 114
-#define ASN1_F_ASN1_HEADER_NEW 115
-#define ASN1_F_ASN1_I2D_BIO 116
-#define ASN1_F_ASN1_I2D_FP 117
-#define ASN1_F_ASN1_INTEGER_SET 118
-#define ASN1_F_ASN1_INTEGER_TO_BN 119
-#define ASN1_F_ASN1_ITEM_D2I_FP 206
-#define ASN1_F_ASN1_ITEM_DUP 191
-#define ASN1_F_ASN1_ITEM_EX_COMBINE_NEW 121
-#define ASN1_F_ASN1_ITEM_EX_D2I 120
-#define ASN1_F_ASN1_ITEM_I2D_BIO 192
-#define ASN1_F_ASN1_ITEM_I2D_FP 193
-#define ASN1_F_ASN1_ITEM_PACK 198
-#define ASN1_F_ASN1_ITEM_SIGN 195
-#define ASN1_F_ASN1_ITEM_SIGN_CTX 220
-#define ASN1_F_ASN1_ITEM_UNPACK 199
-#define ASN1_F_ASN1_ITEM_VERIFY 197
-#define ASN1_F_ASN1_MBSTRING_NCOPY 122
-#define ASN1_F_ASN1_OBJECT_NEW 123
-#define ASN1_F_ASN1_OUTPUT_DATA 214
-#define ASN1_F_ASN1_PACK_STRING 124
-#define ASN1_F_ASN1_PCTX_NEW 205
-#define ASN1_F_ASN1_PKCS5_PBE_SET 125
-#define ASN1_F_ASN1_SEQ_PACK 126
-#define ASN1_F_ASN1_SEQ_UNPACK 127
-#define ASN1_F_ASN1_SIGN 128
-#define ASN1_F_ASN1_STR2TYPE 179
-#define ASN1_F_ASN1_STRING_SET 186
-#define ASN1_F_ASN1_STRING_TABLE_ADD 129
-#define ASN1_F_ASN1_STRING_TYPE_NEW 130
-#define ASN1_F_ASN1_TEMPLATE_EX_D2I 132
-#define ASN1_F_ASN1_TEMPLATE_NEW 133
-#define ASN1_F_ASN1_TEMPLATE_NOEXP_D2I 131
-#define ASN1_F_ASN1_TIME_ADJ 217
-#define ASN1_F_ASN1_TIME_SET 175
-#define ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING 134
-#define ASN1_F_ASN1_TYPE_GET_OCTETSTRING 135
-#define ASN1_F_ASN1_UNPACK_STRING 136
-#define ASN1_F_ASN1_UTCTIME_ADJ 218
-#define ASN1_F_ASN1_UTCTIME_SET 187
-#define ASN1_F_ASN1_VERIFY 137
-#define ASN1_F_B64_READ_ASN1 209
-#define ASN1_F_B64_WRITE_ASN1 210
-#define ASN1_F_BIO_NEW_NDEF 208
-#define ASN1_F_BITSTR_CB 180
-#define ASN1_F_BN_TO_ASN1_ENUMERATED 138
-#define ASN1_F_BN_TO_ASN1_INTEGER 139
-#define ASN1_F_C2I_ASN1_BIT_STRING 189
-#define ASN1_F_C2I_ASN1_INTEGER 194
-#define ASN1_F_C2I_ASN1_OBJECT 196
-#define ASN1_F_COLLECT_DATA 140
-#define ASN1_F_D2I_ASN1_BIT_STRING 141
-#define ASN1_F_D2I_ASN1_BOOLEAN 142
-#define ASN1_F_D2I_ASN1_BYTES 143
-#define ASN1_F_D2I_ASN1_GENERALIZEDTIME 144
-#define ASN1_F_D2I_ASN1_HEADER 145
-#define ASN1_F_D2I_ASN1_INTEGER 146
-#define ASN1_F_D2I_ASN1_OBJECT 147
-#define ASN1_F_D2I_ASN1_SET 148
-#define ASN1_F_D2I_ASN1_TYPE_BYTES 149
-#define ASN1_F_D2I_ASN1_UINTEGER 150
-#define ASN1_F_D2I_ASN1_UTCTIME 151
-#define ASN1_F_D2I_AUTOPRIVATEKEY 207
-#define ASN1_F_D2I_NETSCAPE_RSA 152
-#define ASN1_F_D2I_NETSCAPE_RSA_2 153
-#define ASN1_F_D2I_PRIVATEKEY 154
-#define ASN1_F_D2I_PUBLICKEY 155
-#define ASN1_F_D2I_RSA_NET 200
-#define ASN1_F_D2I_RSA_NET_2 201
-#define ASN1_F_D2I_X509 156
-#define ASN1_F_D2I_X509_CINF 157
-#define ASN1_F_D2I_X509_PKEY 159
-#define ASN1_F_I2D_ASN1_BIO_STREAM 211
-#define ASN1_F_I2D_ASN1_SET 188
-#define ASN1_F_I2D_ASN1_TIME 160
-#define ASN1_F_I2D_DSA_PUBKEY 161
-#define ASN1_F_I2D_EC_PUBKEY 181
-#define ASN1_F_I2D_PRIVATEKEY 163
-#define ASN1_F_I2D_PUBLICKEY 164
-#define ASN1_F_I2D_RSA_NET 162
-#define ASN1_F_I2D_RSA_PUBKEY 165
-#define ASN1_F_LONG_C2I 166
-#define ASN1_F_OID_MODULE_INIT 174
-#define ASN1_F_PARSE_TAGGING 182
-#define ASN1_F_PKCS5_PBE2_SET_IV 167
-#define ASN1_F_PKCS5_PBE_SET 202
-#define ASN1_F_PKCS5_PBE_SET0_ALGOR 215
-#define ASN1_F_PKCS5_PBKDF2_SET 219
-#define ASN1_F_SMIME_READ_ASN1 212
-#define ASN1_F_SMIME_TEXT 213
-#define ASN1_F_X509_CINF_NEW 168
-#define ASN1_F_X509_CRL_ADD0_REVOKED 169
-#define ASN1_F_X509_INFO_NEW 170
-#define ASN1_F_X509_NAME_ENCODE 203
-#define ASN1_F_X509_NAME_EX_D2I 158
-#define ASN1_F_X509_NAME_EX_NEW 171
-#define ASN1_F_X509_NEW 172
-#define ASN1_F_X509_PKEY_NEW 173
-
-/* Reason codes. */
-#define ASN1_R_ADDING_OBJECT 171
-#define ASN1_R_ASN1_PARSE_ERROR 203
-#define ASN1_R_ASN1_SIG_PARSE_ERROR 204
-#define ASN1_R_AUX_ERROR 100
-#define ASN1_R_BAD_CLASS 101
-#define ASN1_R_BAD_OBJECT_HEADER 102
-#define ASN1_R_BAD_PASSWORD_READ 103
-#define ASN1_R_BAD_TAG 104
-#define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 214
-#define ASN1_R_BN_LIB 105
-#define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106
-#define ASN1_R_BUFFER_TOO_SMALL 107
-#define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 108
-#define ASN1_R_CONTEXT_NOT_INITIALISED 217
-#define ASN1_R_DATA_IS_WRONG 109
-#define ASN1_R_DECODE_ERROR 110
-#define ASN1_R_DECODING_ERROR 111
-#define ASN1_R_DEPTH_EXCEEDED 174
-#define ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 198
-#define ASN1_R_ENCODE_ERROR 112
-#define ASN1_R_ERROR_GETTING_TIME 173
-#define ASN1_R_ERROR_LOADING_SECTION 172
-#define ASN1_R_ERROR_PARSING_SET_ELEMENT 113
-#define ASN1_R_ERROR_SETTING_CIPHER_PARAMS 114
-#define ASN1_R_EXPECTING_AN_INTEGER 115
-#define ASN1_R_EXPECTING_AN_OBJECT 116
-#define ASN1_R_EXPECTING_A_BOOLEAN 117
-#define ASN1_R_EXPECTING_A_TIME 118
-#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 119
-#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 120
-#define ASN1_R_FIELD_MISSING 121
-#define ASN1_R_FIRST_NUM_TOO_LARGE 122
-#define ASN1_R_HEADER_TOO_LONG 123
-#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 175
-#define ASN1_R_ILLEGAL_BOOLEAN 176
-#define ASN1_R_ILLEGAL_CHARACTERS 124
-#define ASN1_R_ILLEGAL_FORMAT 177
-#define ASN1_R_ILLEGAL_HEX 178
-#define ASN1_R_ILLEGAL_IMPLICIT_TAG 179
-#define ASN1_R_ILLEGAL_INTEGER 180
-#define ASN1_R_ILLEGAL_NESTED_TAGGING 181
-#define ASN1_R_ILLEGAL_NULL 125
-#define ASN1_R_ILLEGAL_NULL_VALUE 182
-#define ASN1_R_ILLEGAL_OBJECT 183
-#define ASN1_R_ILLEGAL_OPTIONAL_ANY 126
-#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 170
-#define ASN1_R_ILLEGAL_TAGGED_ANY 127
-#define ASN1_R_ILLEGAL_TIME_VALUE 184
-#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 185
-#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 128
-#define ASN1_R_INVALID_BMPSTRING_LENGTH 129
-#define ASN1_R_INVALID_DIGIT 130
-#define ASN1_R_INVALID_MIME_TYPE 205
-#define ASN1_R_INVALID_MODIFIER 186
-#define ASN1_R_INVALID_NUMBER 187
-#define ASN1_R_INVALID_OBJECT_ENCODING 216
-#define ASN1_R_INVALID_SEPARATOR 131
-#define ASN1_R_INVALID_TIME_FORMAT 132
-#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 133
-#define ASN1_R_INVALID_UTF8STRING 134
-#define ASN1_R_IV_TOO_LARGE 135
-#define ASN1_R_LENGTH_ERROR 136
-#define ASN1_R_LIST_ERROR 188
-#define ASN1_R_MIME_NO_CONTENT_TYPE 206
-#define ASN1_R_MIME_PARSE_ERROR 207
-#define ASN1_R_MIME_SIG_PARSE_ERROR 208
-#define ASN1_R_MISSING_EOC 137
-#define ASN1_R_MISSING_SECOND_NUMBER 138
-#define ASN1_R_MISSING_VALUE 189
-#define ASN1_R_MSTRING_NOT_UNIVERSAL 139
-#define ASN1_R_MSTRING_WRONG_TAG 140
-#define ASN1_R_NESTED_ASN1_STRING 197
-#define ASN1_R_NON_HEX_CHARACTERS 141
-#define ASN1_R_NOT_ASCII_FORMAT 190
-#define ASN1_R_NOT_ENOUGH_DATA 142
-#define ASN1_R_NO_CONTENT_TYPE 209
-#define ASN1_R_NO_DEFAULT_DIGEST 201
-#define ASN1_R_NO_MATCHING_CHOICE_TYPE 143
-#define ASN1_R_NO_MULTIPART_BODY_FAILURE 210
-#define ASN1_R_NO_MULTIPART_BOUNDARY 211
-#define ASN1_R_NO_SIG_CONTENT_TYPE 212
-#define ASN1_R_NULL_IS_WRONG_LENGTH 144
-#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 191
-#define ASN1_R_ODD_NUMBER_OF_CHARS 145
-#define ASN1_R_PRIVATE_KEY_HEADER_MISSING 146
-#define ASN1_R_SECOND_NUMBER_TOO_LARGE 147
-#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 148
-#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 149
-#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 192
-#define ASN1_R_SHORT_LINE 150
-#define ASN1_R_SIG_INVALID_MIME_TYPE 213
-#define ASN1_R_STREAMING_NOT_SUPPORTED 202
-#define ASN1_R_STRING_TOO_LONG 151
-#define ASN1_R_STRING_TOO_SHORT 152
-#define ASN1_R_TAG_VALUE_TOO_HIGH 153
-#define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 154
-#define ASN1_R_TIME_NOT_ASCII_FORMAT 193
-#define ASN1_R_TOO_LONG 155
-#define ASN1_R_TYPE_NOT_CONSTRUCTED 156
-#define ASN1_R_UNABLE_TO_DECODE_RSA_KEY 157
-#define ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY 158
-#define ASN1_R_UNEXPECTED_EOC 159
-#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 215
-#define ASN1_R_UNKNOWN_FORMAT 160
-#define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 161
-#define ASN1_R_UNKNOWN_OBJECT_TYPE 162
-#define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE 163
-#define ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM 199
-#define ASN1_R_UNKNOWN_TAG 194
-#define ASN1_R_UNKOWN_FORMAT 195
-#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 164
-#define ASN1_R_UNSUPPORTED_CIPHER 165
-#define ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM 166
-#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 167
-#define ASN1_R_UNSUPPORTED_TYPE 196
-#define ASN1_R_WRONG_PUBLIC_KEY_TYPE 200
-#define ASN1_R_WRONG_TAG 168
-#define ASN1_R_WRONG_TYPE 169
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/asn1_mac.h b/drivers/builtin_openssl/openssl/asn1_mac.h
deleted file mode 100644
index 87bd0e9e1d..0000000000
--- a/drivers/builtin_openssl/openssl/asn1_mac.h
+++ /dev/null
@@ -1,578 +0,0 @@
-/* crypto/asn1/asn1_mac.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_ASN1_MAC_H
-#define HEADER_ASN1_MAC_H
-
-#include <openssl/asn1.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef ASN1_MAC_ERR_LIB
-#define ASN1_MAC_ERR_LIB ERR_LIB_ASN1
-#endif
-
-#define ASN1_MAC_H_err(f,r,line) \
- ERR_PUT_error(ASN1_MAC_ERR_LIB,(f),(r),__FILE__,(line))
-
-#define M_ASN1_D2I_vars(a,type,func) \
- ASN1_const_CTX c; \
- type ret=NULL; \
- \
- c.pp=(const unsigned char **)pp; \
- c.q= *(const unsigned char **)pp; \
- c.error=ERR_R_NESTED_ASN1_ERROR; \
- if ((a == NULL) || ((*a) == NULL)) \
- { if ((ret=(type)func()) == NULL) \
- { c.line=__LINE__; goto err; } } \
- else ret=(*a);
-
-#define M_ASN1_D2I_Init() \
- c.p= *(const unsigned char **)pp; \
- c.max=(length == 0)?0:(c.p+length);
-
-#define M_ASN1_D2I_Finish_2(a) \
- if (!asn1_const_Finish(&c)) \
- { c.line=__LINE__; goto err; } \
- *(const unsigned char **)pp=c.p; \
- if (a != NULL) (*a)=ret; \
- return(ret);
-
-#define M_ASN1_D2I_Finish(a,func,e) \
- M_ASN1_D2I_Finish_2(a); \
-err:\
- ASN1_MAC_H_err((e),c.error,c.line); \
- asn1_add_error(*(const unsigned char **)pp,(int)(c.q- *pp)); \
- if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \
- return(NULL)
-
-#define M_ASN1_D2I_start_sequence() \
- if (!asn1_GetSequence(&c,&length)) \
- { c.line=__LINE__; goto err; }
-/* Begin reading ASN1 without a surrounding sequence */
-#define M_ASN1_D2I_begin() \
- c.slen = length;
-
-/* End reading ASN1 with no check on length */
-#define M_ASN1_D2I_Finish_nolen(a, func, e) \
- *pp=c.p; \
- if (a != NULL) (*a)=ret; \
- return(ret); \
-err:\
- ASN1_MAC_H_err((e),c.error,c.line); \
- asn1_add_error(*pp,(int)(c.q- *pp)); \
- if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \
- return(NULL)
-
-#define M_ASN1_D2I_end_sequence() \
- (((c.inf&1) == 0)?(c.slen <= 0): \
- (c.eos=ASN1_const_check_infinite_end(&c.p,c.slen)))
-
-/* Don't use this with d2i_ASN1_BOOLEAN() */
-#define M_ASN1_D2I_get(b, func) \
- c.q=c.p; \
- if (func(&(b),&c.p,c.slen) == NULL) \
- {c.line=__LINE__; goto err; } \
- c.slen-=(c.p-c.q);
-
-/* Don't use this with d2i_ASN1_BOOLEAN() */
-#define M_ASN1_D2I_get_x(type,b,func) \
- c.q=c.p; \
- if (((D2I_OF(type))func)(&(b),&c.p,c.slen) == NULL) \
- {c.line=__LINE__; goto err; } \
- c.slen-=(c.p-c.q);
-
-/* use this instead () */
-#define M_ASN1_D2I_get_int(b,func) \
- c.q=c.p; \
- if (func(&(b),&c.p,c.slen) < 0) \
- {c.line=__LINE__; goto err; } \
- c.slen-=(c.p-c.q);
-
-#define M_ASN1_D2I_get_opt(b,func,type) \
- if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \
- == (V_ASN1_UNIVERSAL|(type)))) \
- { \
- M_ASN1_D2I_get(b,func); \
- }
-
-#define M_ASN1_D2I_get_int_opt(b,func,type) \
- if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \
- == (V_ASN1_UNIVERSAL|(type)))) \
- { \
- M_ASN1_D2I_get_int(b,func); \
- }
-
-#define M_ASN1_D2I_get_imp(b,func, type) \
- M_ASN1_next=(_tmp& V_ASN1_CONSTRUCTED)|type; \
- c.q=c.p; \
- if (func(&(b),&c.p,c.slen) == NULL) \
- {c.line=__LINE__; M_ASN1_next_prev = _tmp; goto err; } \
- c.slen-=(c.p-c.q);\
- M_ASN1_next_prev=_tmp;
-
-#define M_ASN1_D2I_get_IMP_opt(b,func,tag,type) \
- if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) == \
- (V_ASN1_CONTEXT_SPECIFIC|(tag)))) \
- { \
- unsigned char _tmp = M_ASN1_next; \
- M_ASN1_D2I_get_imp(b,func, type);\
- }
-
-#define M_ASN1_D2I_get_set(r,func,free_func) \
- M_ASN1_D2I_get_imp_set(r,func,free_func, \
- V_ASN1_SET,V_ASN1_UNIVERSAL);
-
-#define M_ASN1_D2I_get_set_type(type,r,func,free_func) \
- M_ASN1_D2I_get_imp_set_type(type,r,func,free_func, \
- V_ASN1_SET,V_ASN1_UNIVERSAL);
-
-#define M_ASN1_D2I_get_set_opt(r,func,free_func) \
- if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
- V_ASN1_CONSTRUCTED|V_ASN1_SET)))\
- { M_ASN1_D2I_get_set(r,func,free_func); }
-
-#define M_ASN1_D2I_get_set_opt_type(type,r,func,free_func) \
- if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
- V_ASN1_CONSTRUCTED|V_ASN1_SET)))\
- { M_ASN1_D2I_get_set_type(type,r,func,free_func); }
-
-#define M_ASN1_I2D_len_SET_opt(a,f) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- M_ASN1_I2D_len_SET(a,f);
-
-#define M_ASN1_I2D_put_SET_opt(a,f) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- M_ASN1_I2D_put_SET(a,f);
-
-#define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- M_ASN1_I2D_put_SEQUENCE(a,f);
-
-#define M_ASN1_I2D_put_SEQUENCE_opt_type(type,a,f) \
- if ((a != NULL) && (sk_##type##_num(a) != 0)) \
- M_ASN1_I2D_put_SEQUENCE_type(type,a,f);
-
-#define M_ASN1_D2I_get_IMP_set_opt(b,func,free_func,tag) \
- if ((c.slen != 0) && \
- (M_ASN1_next == \
- (V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\
- { \
- M_ASN1_D2I_get_imp_set(b,func,free_func,\
- tag,V_ASN1_CONTEXT_SPECIFIC); \
- }
-
-#define M_ASN1_D2I_get_IMP_set_opt_type(type,b,func,free_func,tag) \
- if ((c.slen != 0) && \
- (M_ASN1_next == \
- (V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\
- { \
- M_ASN1_D2I_get_imp_set_type(type,b,func,free_func,\
- tag,V_ASN1_CONTEXT_SPECIFIC); \
- }
-
-#define M_ASN1_D2I_get_seq(r,func,free_func) \
- M_ASN1_D2I_get_imp_set(r,func,free_func,\
- V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL);
-
-#define M_ASN1_D2I_get_seq_type(type,r,func,free_func) \
- M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\
- V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL)
-
-#define M_ASN1_D2I_get_seq_opt(r,func,free_func) \
- if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
- V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\
- { M_ASN1_D2I_get_seq(r,func,free_func); }
-
-#define M_ASN1_D2I_get_seq_opt_type(type,r,func,free_func) \
- if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
- V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\
- { M_ASN1_D2I_get_seq_type(type,r,func,free_func); }
-
-#define M_ASN1_D2I_get_IMP_set(r,func,free_func,x) \
- M_ASN1_D2I_get_imp_set(r,func,free_func,\
- x,V_ASN1_CONTEXT_SPECIFIC);
-
-#define M_ASN1_D2I_get_IMP_set_type(type,r,func,free_func,x) \
- M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\
- x,V_ASN1_CONTEXT_SPECIFIC);
-
-#define M_ASN1_D2I_get_imp_set(r,func,free_func,a,b) \
- c.q=c.p; \
- if (d2i_ASN1_SET(&(r),&c.p,c.slen,(char *(*)())func,\
- (void (*)())free_func,a,b) == NULL) \
- { c.line=__LINE__; goto err; } \
- c.slen-=(c.p-c.q);
-
-#define M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,a,b) \
- c.q=c.p; \
- if (d2i_ASN1_SET_OF_##type(&(r),&c.p,c.slen,func,\
- free_func,a,b) == NULL) \
- { c.line=__LINE__; goto err; } \
- c.slen-=(c.p-c.q);
-
-#define M_ASN1_D2I_get_set_strings(r,func,a,b) \
- c.q=c.p; \
- if (d2i_ASN1_STRING_SET(&(r),&c.p,c.slen,a,b) == NULL) \
- { c.line=__LINE__; goto err; } \
- c.slen-=(c.p-c.q);
-
-#define M_ASN1_D2I_get_EXP_opt(r,func,tag) \
- if ((c.slen != 0L) && (M_ASN1_next == \
- (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
- { \
- int Tinf,Ttag,Tclass; \
- long Tlen; \
- \
- c.q=c.p; \
- Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
- if (Tinf & 0x80) \
- { c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
- c.line=__LINE__; goto err; } \
- if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
- Tlen = c.slen - (c.p - c.q) - 2; \
- if (func(&(r),&c.p,Tlen) == NULL) \
- { c.line=__LINE__; goto err; } \
- if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
- Tlen = c.slen - (c.p - c.q); \
- if(!ASN1_const_check_infinite_end(&c.p, Tlen)) \
- { c.error=ERR_R_MISSING_ASN1_EOS; \
- c.line=__LINE__; goto err; } \
- }\
- c.slen-=(c.p-c.q); \
- }
-
-#define M_ASN1_D2I_get_EXP_set_opt(r,func,free_func,tag,b) \
- if ((c.slen != 0) && (M_ASN1_next == \
- (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
- { \
- int Tinf,Ttag,Tclass; \
- long Tlen; \
- \
- c.q=c.p; \
- Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
- if (Tinf & 0x80) \
- { c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
- c.line=__LINE__; goto err; } \
- if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
- Tlen = c.slen - (c.p - c.q) - 2; \
- if (d2i_ASN1_SET(&(r),&c.p,Tlen,(char *(*)())func, \
- (void (*)())free_func, \
- b,V_ASN1_UNIVERSAL) == NULL) \
- { c.line=__LINE__; goto err; } \
- if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
- Tlen = c.slen - (c.p - c.q); \
- if(!ASN1_check_infinite_end(&c.p, Tlen)) \
- { c.error=ERR_R_MISSING_ASN1_EOS; \
- c.line=__LINE__; goto err; } \
- }\
- c.slen-=(c.p-c.q); \
- }
-
-#define M_ASN1_D2I_get_EXP_set_opt_type(type,r,func,free_func,tag,b) \
- if ((c.slen != 0) && (M_ASN1_next == \
- (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
- { \
- int Tinf,Ttag,Tclass; \
- long Tlen; \
- \
- c.q=c.p; \
- Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
- if (Tinf & 0x80) \
- { c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
- c.line=__LINE__; goto err; } \
- if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
- Tlen = c.slen - (c.p - c.q) - 2; \
- if (d2i_ASN1_SET_OF_##type(&(r),&c.p,Tlen,func, \
- free_func,b,V_ASN1_UNIVERSAL) == NULL) \
- { c.line=__LINE__; goto err; } \
- if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
- Tlen = c.slen - (c.p - c.q); \
- if(!ASN1_check_infinite_end(&c.p, Tlen)) \
- { c.error=ERR_R_MISSING_ASN1_EOS; \
- c.line=__LINE__; goto err; } \
- }\
- c.slen-=(c.p-c.q); \
- }
-
-/* New macros */
-#define M_ASN1_New_Malloc(ret,type) \
- if ((ret=(type *)OPENSSL_malloc(sizeof(type))) == NULL) \
- { c.line=__LINE__; goto err2; }
-
-#define M_ASN1_New(arg,func) \
- if (((arg)=func()) == NULL) return(NULL)
-
-#define M_ASN1_New_Error(a) \
-/* err: ASN1_MAC_H_err((a),ERR_R_NESTED_ASN1_ERROR,c.line); \
- return(NULL);*/ \
- err2: ASN1_MAC_H_err((a),ERR_R_MALLOC_FAILURE,c.line); \
- return(NULL)
-
-
-/* BIG UGLY WARNING! This is so damn ugly I wanna puke. Unfortunately,
- some macros that use ASN1_const_CTX still insist on writing in the input
- stream. ARGH! ARGH! ARGH! Let's get rid of this macro package.
- Please? -- Richard Levitte */
-#define M_ASN1_next (*((unsigned char *)(c.p)))
-#define M_ASN1_next_prev (*((unsigned char *)(c.q)))
-
-/*************************************************/
-
-#define M_ASN1_I2D_vars(a) int r=0,ret=0; \
- unsigned char *p; \
- if (a == NULL) return(0)
-
-/* Length Macros */
-#define M_ASN1_I2D_len(a,f) ret+=f(a,NULL)
-#define M_ASN1_I2D_len_IMP_opt(a,f) if (a != NULL) M_ASN1_I2D_len(a,f)
-
-#define M_ASN1_I2D_len_SET(a,f) \
- ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET);
-
-#define M_ASN1_I2D_len_SET_type(type,a,f) \
- ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SET, \
- V_ASN1_UNIVERSAL,IS_SET);
-
-#define M_ASN1_I2D_len_SEQUENCE(a,f) \
- ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \
- IS_SEQUENCE);
-
-#define M_ASN1_I2D_len_SEQUENCE_type(type,a,f) \
- ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SEQUENCE, \
- V_ASN1_UNIVERSAL,IS_SEQUENCE)
-
-#define M_ASN1_I2D_len_SEQUENCE_opt(a,f) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- M_ASN1_I2D_len_SEQUENCE(a,f);
-
-#define M_ASN1_I2D_len_SEQUENCE_opt_type(type,a,f) \
- if ((a != NULL) && (sk_##type##_num(a) != 0)) \
- M_ASN1_I2D_len_SEQUENCE_type(type,a,f);
-
-#define M_ASN1_I2D_len_IMP_SET(a,f,x) \
- ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET);
-
-#define M_ASN1_I2D_len_IMP_SET_type(type,a,f,x) \
- ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
- V_ASN1_CONTEXT_SPECIFIC,IS_SET);
-
-#define M_ASN1_I2D_len_IMP_SET_opt(a,f,x) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
- IS_SET);
-
-#define M_ASN1_I2D_len_IMP_SET_opt_type(type,a,f,x) \
- if ((a != NULL) && (sk_##type##_num(a) != 0)) \
- ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
- V_ASN1_CONTEXT_SPECIFIC,IS_SET);
-
-#define M_ASN1_I2D_len_IMP_SEQUENCE(a,f,x) \
- ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
- IS_SEQUENCE);
-
-#define M_ASN1_I2D_len_IMP_SEQUENCE_opt(a,f,x) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
- IS_SEQUENCE);
-
-#define M_ASN1_I2D_len_IMP_SEQUENCE_opt_type(type,a,f,x) \
- if ((a != NULL) && (sk_##type##_num(a) != 0)) \
- ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
- V_ASN1_CONTEXT_SPECIFIC, \
- IS_SEQUENCE);
-
-#define M_ASN1_I2D_len_EXP_opt(a,f,mtag,v) \
- if (a != NULL)\
- { \
- v=f(a,NULL); \
- ret+=ASN1_object_size(1,v,mtag); \
- }
-
-#define M_ASN1_I2D_len_EXP_SET_opt(a,f,mtag,tag,v) \
- if ((a != NULL) && (sk_num(a) != 0))\
- { \
- v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL,IS_SET); \
- ret+=ASN1_object_size(1,v,mtag); \
- }
-
-#define M_ASN1_I2D_len_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \
- if ((a != NULL) && (sk_num(a) != 0))\
- { \
- v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL, \
- IS_SEQUENCE); \
- ret+=ASN1_object_size(1,v,mtag); \
- }
-
-#define M_ASN1_I2D_len_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \
- if ((a != NULL) && (sk_##type##_num(a) != 0))\
- { \
- v=i2d_ASN1_SET_OF_##type(a,NULL,f,tag, \
- V_ASN1_UNIVERSAL, \
- IS_SEQUENCE); \
- ret+=ASN1_object_size(1,v,mtag); \
- }
-
-/* Put Macros */
-#define M_ASN1_I2D_put(a,f) f(a,&p)
-
-#define M_ASN1_I2D_put_IMP_opt(a,f,t) \
- if (a != NULL) \
- { \
- unsigned char *q=p; \
- f(a,&p); \
- *q=(V_ASN1_CONTEXT_SPECIFIC|t|(*q&V_ASN1_CONSTRUCTED));\
- }
-
-#define M_ASN1_I2D_put_SET(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SET,\
- V_ASN1_UNIVERSAL,IS_SET)
-#define M_ASN1_I2D_put_SET_type(type,a,f) \
- i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET)
-#define M_ASN1_I2D_put_IMP_SET(a,f,x) i2d_ASN1_SET(a,&p,f,x,\
- V_ASN1_CONTEXT_SPECIFIC,IS_SET)
-#define M_ASN1_I2D_put_IMP_SET_type(type,a,f,x) \
- i2d_ASN1_SET_OF_##type(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET)
-#define M_ASN1_I2D_put_IMP_SEQUENCE(a,f,x) i2d_ASN1_SET(a,&p,f,x,\
- V_ASN1_CONTEXT_SPECIFIC,IS_SEQUENCE)
-
-#define M_ASN1_I2D_put_SEQUENCE(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SEQUENCE,\
- V_ASN1_UNIVERSAL,IS_SEQUENCE)
-
-#define M_ASN1_I2D_put_SEQUENCE_type(type,a,f) \
- i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \
- IS_SEQUENCE)
-
-#define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- M_ASN1_I2D_put_SEQUENCE(a,f);
-
-#define M_ASN1_I2D_put_IMP_SET_opt(a,f,x) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- { i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \
- IS_SET); }
-
-#define M_ASN1_I2D_put_IMP_SET_opt_type(type,a,f,x) \
- if ((a != NULL) && (sk_##type##_num(a) != 0)) \
- { i2d_ASN1_SET_OF_##type(a,&p,f,x, \
- V_ASN1_CONTEXT_SPECIFIC, \
- IS_SET); }
-
-#define M_ASN1_I2D_put_IMP_SEQUENCE_opt(a,f,x) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- { i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \
- IS_SEQUENCE); }
-
-#define M_ASN1_I2D_put_IMP_SEQUENCE_opt_type(type,a,f,x) \
- if ((a != NULL) && (sk_##type##_num(a) != 0)) \
- { i2d_ASN1_SET_OF_##type(a,&p,f,x, \
- V_ASN1_CONTEXT_SPECIFIC, \
- IS_SEQUENCE); }
-
-#define M_ASN1_I2D_put_EXP_opt(a,f,tag,v) \
- if (a != NULL) \
- { \
- ASN1_put_object(&p,1,v,tag,V_ASN1_CONTEXT_SPECIFIC); \
- f(a,&p); \
- }
-
-#define M_ASN1_I2D_put_EXP_SET_opt(a,f,mtag,tag,v) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- { \
- ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
- i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SET); \
- }
-
-#define M_ASN1_I2D_put_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \
- if ((a != NULL) && (sk_num(a) != 0)) \
- { \
- ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
- i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SEQUENCE); \
- }
-
-#define M_ASN1_I2D_put_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \
- if ((a != NULL) && (sk_##type##_num(a) != 0)) \
- { \
- ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
- i2d_ASN1_SET_OF_##type(a,&p,f,tag,V_ASN1_UNIVERSAL, \
- IS_SEQUENCE); \
- }
-
-#define M_ASN1_I2D_seq_total() \
- r=ASN1_object_size(1,ret,V_ASN1_SEQUENCE); \
- if (pp == NULL) return(r); \
- p= *pp; \
- ASN1_put_object(&p,1,ret,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL)
-
-#define M_ASN1_I2D_INF_seq_start(tag,ctx) \
- *(p++)=(V_ASN1_CONSTRUCTED|(tag)|(ctx)); \
- *(p++)=0x80
-
-#define M_ASN1_I2D_INF_seq_end() *(p++)=0x00; *(p++)=0x00
-
-#define M_ASN1_I2D_finish() *pp=p; \
- return(r);
-
-int asn1_GetSequence(ASN1_const_CTX *c, long *length);
-void asn1_add_error(const unsigned char *address,int offset);
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/asn1t.h b/drivers/builtin_openssl/openssl/asn1t.h
deleted file mode 100644
index d230e4bf70..0000000000
--- a/drivers/builtin_openssl/openssl/asn1t.h
+++ /dev/null
@@ -1,960 +0,0 @@
-/* asn1t.h */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 2000.
- */
-/* ====================================================================
- * Copyright (c) 2000-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-#ifndef HEADER_ASN1T_H
-#define HEADER_ASN1T_H
-
-#include <stddef.h>
-#include <openssl/e_os2.h>
-#include <openssl/asn1.h>
-
-#ifdef OPENSSL_BUILD_SHLIBCRYPTO
-# undef OPENSSL_EXTERN
-# define OPENSSL_EXTERN OPENSSL_EXPORT
-#endif
-
-/* ASN1 template defines, structures and functions */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
-
-/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
-#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr))
-
-
-/* Macros for start and end of ASN1_ITEM definition */
-
-#define ASN1_ITEM_start(itname) \
- OPENSSL_GLOBAL const ASN1_ITEM itname##_it = {
-
-#define ASN1_ITEM_end(itname) \
- };
-
-#else
-
-/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
-#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr()))
-
-
-/* Macros for start and end of ASN1_ITEM definition */
-
-#define ASN1_ITEM_start(itname) \
- const ASN1_ITEM * itname##_it(void) \
- { \
- static const ASN1_ITEM local_it = {
-
-#define ASN1_ITEM_end(itname) \
- }; \
- return &local_it; \
- }
-
-#endif
-
-
-/* Macros to aid ASN1 template writing */
-
-#define ASN1_ITEM_TEMPLATE(tname) \
- static const ASN1_TEMPLATE tname##_item_tt
-
-#define ASN1_ITEM_TEMPLATE_END(tname) \
- ;\
- ASN1_ITEM_start(tname) \
- ASN1_ITYPE_PRIMITIVE,\
- -1,\
- &tname##_item_tt,\
- 0,\
- NULL,\
- 0,\
- #tname \
- ASN1_ITEM_end(tname)
-
-
-/* This is a ASN1 type which just embeds a template */
-
-/* This pair helps declare a SEQUENCE. We can do:
- *
- * ASN1_SEQUENCE(stname) = {
- * ... SEQUENCE components ...
- * } ASN1_SEQUENCE_END(stname)
- *
- * This will produce an ASN1_ITEM called stname_it
- * for a structure called stname.
- *
- * If you want the same structure but a different
- * name then use:
- *
- * ASN1_SEQUENCE(itname) = {
- * ... SEQUENCE components ...
- * } ASN1_SEQUENCE_END_name(stname, itname)
- *
- * This will create an item called itname_it using
- * a structure called stname.
- */
-
-#define ASN1_SEQUENCE(tname) \
- static const ASN1_TEMPLATE tname##_seq_tt[]
-
-#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname)
-
-#define ASN1_SEQUENCE_END_name(stname, tname) \
- ;\
- ASN1_ITEM_start(tname) \
- ASN1_ITYPE_SEQUENCE,\
- V_ASN1_SEQUENCE,\
- tname##_seq_tt,\
- sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
- NULL,\
- sizeof(stname),\
- #stname \
- ASN1_ITEM_end(tname)
-
-#define ASN1_NDEF_SEQUENCE(tname) \
- ASN1_SEQUENCE(tname)
-
-#define ASN1_NDEF_SEQUENCE_cb(tname, cb) \
- ASN1_SEQUENCE_cb(tname, cb)
-
-#define ASN1_SEQUENCE_cb(tname, cb) \
- static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
- ASN1_SEQUENCE(tname)
-
-#define ASN1_BROKEN_SEQUENCE(tname) \
- static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0, 0}; \
- ASN1_SEQUENCE(tname)
-
-#define ASN1_SEQUENCE_ref(tname, cb, lck) \
- static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), lck, cb, 0}; \
- ASN1_SEQUENCE(tname)
-
-#define ASN1_SEQUENCE_enc(tname, enc, cb) \
- static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, 0, cb, offsetof(tname, enc)}; \
- ASN1_SEQUENCE(tname)
-
-#define ASN1_NDEF_SEQUENCE_END(tname) \
- ;\
- ASN1_ITEM_start(tname) \
- ASN1_ITYPE_NDEF_SEQUENCE,\
- V_ASN1_SEQUENCE,\
- tname##_seq_tt,\
- sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
- NULL,\
- sizeof(tname),\
- #tname \
- ASN1_ITEM_end(tname)
-
-#define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname)
-
-#define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
-
-#define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
-
-#define ASN1_SEQUENCE_END_ref(stname, tname) \
- ;\
- ASN1_ITEM_start(tname) \
- ASN1_ITYPE_SEQUENCE,\
- V_ASN1_SEQUENCE,\
- tname##_seq_tt,\
- sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
- &tname##_aux,\
- sizeof(stname),\
- #stname \
- ASN1_ITEM_end(tname)
-
-#define ASN1_NDEF_SEQUENCE_END_cb(stname, tname) \
- ;\
- ASN1_ITEM_start(tname) \
- ASN1_ITYPE_NDEF_SEQUENCE,\
- V_ASN1_SEQUENCE,\
- tname##_seq_tt,\
- sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
- &tname##_aux,\
- sizeof(stname),\
- #stname \
- ASN1_ITEM_end(tname)
-
-
-/* This pair helps declare a CHOICE type. We can do:
- *
- * ASN1_CHOICE(chname) = {
- * ... CHOICE options ...
- * ASN1_CHOICE_END(chname)
- *
- * This will produce an ASN1_ITEM called chname_it
- * for a structure called chname. The structure
- * definition must look like this:
- * typedef struct {
- * int type;
- * union {
- * ASN1_SOMETHING *opt1;
- * ASN1_SOMEOTHER *opt2;
- * } value;
- * } chname;
- *
- * the name of the selector must be 'type'.
- * to use an alternative selector name use the
- * ASN1_CHOICE_END_selector() version.
- */
-
-#define ASN1_CHOICE(tname) \
- static const ASN1_TEMPLATE tname##_ch_tt[]
-
-#define ASN1_CHOICE_cb(tname, cb) \
- static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
- ASN1_CHOICE(tname)
-
-#define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname)
-
-#define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type)
-
-#define ASN1_CHOICE_END_selector(stname, tname, selname) \
- ;\
- ASN1_ITEM_start(tname) \
- ASN1_ITYPE_CHOICE,\
- offsetof(stname,selname) ,\
- tname##_ch_tt,\
- sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\
- NULL,\
- sizeof(stname),\
- #stname \
- ASN1_ITEM_end(tname)
-
-#define ASN1_CHOICE_END_cb(stname, tname, selname) \
- ;\
- ASN1_ITEM_start(tname) \
- ASN1_ITYPE_CHOICE,\
- offsetof(stname,selname) ,\
- tname##_ch_tt,\
- sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\
- &tname##_aux,\
- sizeof(stname),\
- #stname \
- ASN1_ITEM_end(tname)
-
-/* This helps with the template wrapper form of ASN1_ITEM */
-
-#define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \
- (flags), (tag), 0,\
- #name, ASN1_ITEM_ref(type) }
-
-/* These help with SEQUENCE or CHOICE components */
-
-/* used to declare other types */
-
-#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \
- (flags), (tag), offsetof(stname, field),\
- #field, ASN1_ITEM_ref(type) }
-
-/* used when the structure is combined with the parent */
-
-#define ASN1_EX_COMBINE(flags, tag, type) { \
- (flags)|ASN1_TFLG_COMBINE, (tag), 0, NULL, ASN1_ITEM_ref(type) }
-
-/* implicit and explicit helper macros */
-
-#define ASN1_IMP_EX(stname, field, type, tag, ex) \
- ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type)
-
-#define ASN1_EXP_EX(stname, field, type, tag, ex) \
- ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type)
-
-/* Any defined by macros: the field used is in the table itself */
-
-#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
-#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) }
-#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) }
-#else
-#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, tblname##_adb }
-#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, tblname##_adb }
-#endif
-/* Plain simple type */
-#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type)
-
-/* OPTIONAL simple type */
-#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type)
-
-/* IMPLICIT tagged simple type */
-#define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0)
-
-/* IMPLICIT tagged OPTIONAL simple type */
-#define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
-
-/* Same as above but EXPLICIT */
-
-#define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0)
-#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
-
-/* SEQUENCE OF type */
-#define ASN1_SEQUENCE_OF(stname, field, type) \
- ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type)
-
-/* OPTIONAL SEQUENCE OF */
-#define ASN1_SEQUENCE_OF_OPT(stname, field, type) \
- ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type)
-
-/* Same as above but for SET OF */
-
-#define ASN1_SET_OF(stname, field, type) \
- ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type)
-
-#define ASN1_SET_OF_OPT(stname, field, type) \
- ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type)
-
-/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */
-
-#define ASN1_IMP_SET_OF(stname, field, type, tag) \
- ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
-
-#define ASN1_EXP_SET_OF(stname, field, type, tag) \
- ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
-
-#define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \
- ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL)
-
-#define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \
- ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL)
-
-#define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \
- ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
-
-#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \
- ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
-
-#define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \
- ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
-
-#define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \
- ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
-
-/* EXPLICIT using indefinite length constructed form */
-#define ASN1_NDEF_EXP(stname, field, type, tag) \
- ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF)
-
-/* EXPLICIT OPTIONAL using indefinite length constructed form */
-#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \
- ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF)
-
-/* Macros for the ASN1_ADB structure */
-
-#define ASN1_ADB(name) \
- static const ASN1_ADB_TABLE name##_adbtbl[]
-
-#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
-
-#define ASN1_ADB_END(name, flags, field, app_table, def, none) \
- ;\
- static const ASN1_ADB name##_adb = {\
- flags,\
- offsetof(name, field),\
- app_table,\
- name##_adbtbl,\
- sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\
- def,\
- none\
- }
-
-#else
-
-#define ASN1_ADB_END(name, flags, field, app_table, def, none) \
- ;\
- static const ASN1_ITEM *name##_adb(void) \
- { \
- static const ASN1_ADB internal_adb = \
- {\
- flags,\
- offsetof(name, field),\
- app_table,\
- name##_adbtbl,\
- sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\
- def,\
- none\
- }; \
- return (const ASN1_ITEM *) &internal_adb; \
- } \
- void dummy_function(void)
-
-#endif
-
-#define ADB_ENTRY(val, template) {val, template}
-
-#define ASN1_ADB_TEMPLATE(name) \
- static const ASN1_TEMPLATE name##_tt
-
-/* This is the ASN1 template structure that defines
- * a wrapper round the actual type. It determines the
- * actual position of the field in the value structure,
- * various flags such as OPTIONAL and the field name.
- */
-
-struct ASN1_TEMPLATE_st {
-unsigned long flags; /* Various flags */
-long tag; /* tag, not used if no tagging */
-unsigned long offset; /* Offset of this field in structure */
-#ifndef NO_ASN1_FIELD_NAMES
-const char *field_name; /* Field name */
-#endif
-ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */
-};
-
-/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */
-
-#define ASN1_TEMPLATE_item(t) (t->item_ptr)
-#define ASN1_TEMPLATE_adb(t) (t->item_ptr)
-
-typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE;
-typedef struct ASN1_ADB_st ASN1_ADB;
-
-struct ASN1_ADB_st {
- unsigned long flags; /* Various flags */
- unsigned long offset; /* Offset of selector field */
- STACK_OF(ASN1_ADB_TABLE) **app_items; /* Application defined items */
- const ASN1_ADB_TABLE *tbl; /* Table of possible types */
- long tblcount; /* Number of entries in tbl */
- const ASN1_TEMPLATE *default_tt; /* Type to use if no match */
- const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */
-};
-
-struct ASN1_ADB_TABLE_st {
- long value; /* NID for an object or value for an int */
- const ASN1_TEMPLATE tt; /* item for this value */
-};
-
-/* template flags */
-
-/* Field is optional */
-#define ASN1_TFLG_OPTIONAL (0x1)
-
-/* Field is a SET OF */
-#define ASN1_TFLG_SET_OF (0x1 << 1)
-
-/* Field is a SEQUENCE OF */
-#define ASN1_TFLG_SEQUENCE_OF (0x2 << 1)
-
-/* Special case: this refers to a SET OF that
- * will be sorted into DER order when encoded *and*
- * the corresponding STACK will be modified to match
- * the new order.
- */
-#define ASN1_TFLG_SET_ORDER (0x3 << 1)
-
-/* Mask for SET OF or SEQUENCE OF */
-#define ASN1_TFLG_SK_MASK (0x3 << 1)
-
-/* These flags mean the tag should be taken from the
- * tag field. If EXPLICIT then the underlying type
- * is used for the inner tag.
- */
-
-/* IMPLICIT tagging */
-#define ASN1_TFLG_IMPTAG (0x1 << 3)
-
-
-/* EXPLICIT tagging, inner tag from underlying type */
-#define ASN1_TFLG_EXPTAG (0x2 << 3)
-
-#define ASN1_TFLG_TAG_MASK (0x3 << 3)
-
-/* context specific IMPLICIT */
-#define ASN1_TFLG_IMPLICIT ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT
-
-/* context specific EXPLICIT */
-#define ASN1_TFLG_EXPLICIT ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT
-
-/* If tagging is in force these determine the
- * type of tag to use. Otherwise the tag is
- * determined by the underlying type. These
- * values reflect the actual octet format.
- */
-
-/* Universal tag */
-#define ASN1_TFLG_UNIVERSAL (0x0<<6)
-/* Application tag */
-#define ASN1_TFLG_APPLICATION (0x1<<6)
-/* Context specific tag */
-#define ASN1_TFLG_CONTEXT (0x2<<6)
-/* Private tag */
-#define ASN1_TFLG_PRIVATE (0x3<<6)
-
-#define ASN1_TFLG_TAG_CLASS (0x3<<6)
-
-/* These are for ANY DEFINED BY type. In this case
- * the 'item' field points to an ASN1_ADB structure
- * which contains a table of values to decode the
- * relevant type
- */
-
-#define ASN1_TFLG_ADB_MASK (0x3<<8)
-
-#define ASN1_TFLG_ADB_OID (0x1<<8)
-
-#define ASN1_TFLG_ADB_INT (0x1<<9)
-
-/* This flag means a parent structure is passed
- * instead of the field: this is useful is a
- * SEQUENCE is being combined with a CHOICE for
- * example. Since this means the structure and
- * item name will differ we need to use the
- * ASN1_CHOICE_END_name() macro for example.
- */
-
-#define ASN1_TFLG_COMBINE (0x1<<10)
-
-/* This flag when present in a SEQUENCE OF, SET OF
- * or EXPLICIT causes indefinite length constructed
- * encoding to be used if required.
- */
-
-#define ASN1_TFLG_NDEF (0x1<<11)
-
-/* This is the actual ASN1 item itself */
-
-struct ASN1_ITEM_st {
-char itype; /* The item type, primitive, SEQUENCE, CHOICE or extern */
-long utype; /* underlying type */
-const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains the contents */
-long tcount; /* Number of templates if SEQUENCE or CHOICE */
-const void *funcs; /* functions that handle this type */
-long size; /* Structure size (usually)*/
-#ifndef NO_ASN1_FIELD_NAMES
-const char *sname; /* Structure name */
-#endif
-};
-
-/* These are values for the itype field and
- * determine how the type is interpreted.
- *
- * For PRIMITIVE types the underlying type
- * determines the behaviour if items is NULL.
- *
- * Otherwise templates must contain a single
- * template and the type is treated in the
- * same way as the type specified in the template.
- *
- * For SEQUENCE types the templates field points
- * to the members, the size field is the
- * structure size.
- *
- * For CHOICE types the templates field points
- * to each possible member (typically a union)
- * and the 'size' field is the offset of the
- * selector.
- *
- * The 'funcs' field is used for application
- * specific functions.
- *
- * For COMPAT types the funcs field gives a
- * set of functions that handle this type, this
- * supports the old d2i, i2d convention.
- *
- * The EXTERN type uses a new style d2i/i2d.
- * The new style should be used where possible
- * because it avoids things like the d2i IMPLICIT
- * hack.
- *
- * MSTRING is a multiple string type, it is used
- * for a CHOICE of character strings where the
- * actual strings all occupy an ASN1_STRING
- * structure. In this case the 'utype' field
- * has a special meaning, it is used as a mask
- * of acceptable types using the B_ASN1 constants.
- *
- * NDEF_SEQUENCE is the same as SEQUENCE except
- * that it will use indefinite length constructed
- * encoding if requested.
- *
- */
-
-#define ASN1_ITYPE_PRIMITIVE 0x0
-
-#define ASN1_ITYPE_SEQUENCE 0x1
-
-#define ASN1_ITYPE_CHOICE 0x2
-
-#define ASN1_ITYPE_COMPAT 0x3
-
-#define ASN1_ITYPE_EXTERN 0x4
-
-#define ASN1_ITYPE_MSTRING 0x5
-
-#define ASN1_ITYPE_NDEF_SEQUENCE 0x6
-
-/* Cache for ASN1 tag and length, so we
- * don't keep re-reading it for things
- * like CHOICE
- */
-
-struct ASN1_TLC_st{
- char valid; /* Values below are valid */
- int ret; /* return value */
- long plen; /* length */
- int ptag; /* class value */
- int pclass; /* class value */
- int hdrlen; /* header length */
-};
-
-/* Typedefs for ASN1 function pointers */
-
-typedef ASN1_VALUE * ASN1_new_func(void);
-typedef void ASN1_free_func(ASN1_VALUE *a);
-typedef ASN1_VALUE * ASN1_d2i_func(ASN1_VALUE **a, const unsigned char ** in, long length);
-typedef int ASN1_i2d_func(ASN1_VALUE * a, unsigned char **in);
-
-typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it,
- int tag, int aclass, char opt, ASN1_TLC *ctx);
-
-typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass);
-typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
-typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
-
-typedef int ASN1_ex_print_func(BIO *out, ASN1_VALUE **pval,
- int indent, const char *fname,
- const ASN1_PCTX *pctx);
-
-typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it);
-typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it);
-typedef int ASN1_primitive_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, int indent, const ASN1_PCTX *pctx);
-
-typedef struct ASN1_COMPAT_FUNCS_st {
- ASN1_new_func *asn1_new;
- ASN1_free_func *asn1_free;
- ASN1_d2i_func *asn1_d2i;
- ASN1_i2d_func *asn1_i2d;
-} ASN1_COMPAT_FUNCS;
-
-typedef struct ASN1_EXTERN_FUNCS_st {
- void *app_data;
- ASN1_ex_new_func *asn1_ex_new;
- ASN1_ex_free_func *asn1_ex_free;
- ASN1_ex_free_func *asn1_ex_clear;
- ASN1_ex_d2i *asn1_ex_d2i;
- ASN1_ex_i2d *asn1_ex_i2d;
- ASN1_ex_print_func *asn1_ex_print;
-} ASN1_EXTERN_FUNCS;
-
-typedef struct ASN1_PRIMITIVE_FUNCS_st {
- void *app_data;
- unsigned long flags;
- ASN1_ex_new_func *prim_new;
- ASN1_ex_free_func *prim_free;
- ASN1_ex_free_func *prim_clear;
- ASN1_primitive_c2i *prim_c2i;
- ASN1_primitive_i2c *prim_i2c;
- ASN1_primitive_print *prim_print;
-} ASN1_PRIMITIVE_FUNCS;
-
-/* This is the ASN1_AUX structure: it handles various
- * miscellaneous requirements. For example the use of
- * reference counts and an informational callback.
- *
- * The "informational callback" is called at various
- * points during the ASN1 encoding and decoding. It can
- * be used to provide minor customisation of the structures
- * used. This is most useful where the supplied routines
- * *almost* do the right thing but need some extra help
- * at a few points. If the callback returns zero then
- * it is assumed a fatal error has occurred and the
- * main operation should be abandoned.
- *
- * If major changes in the default behaviour are required
- * then an external type is more appropriate.
- */
-
-typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it,
- void *exarg);
-
-typedef struct ASN1_AUX_st {
- void *app_data;
- int flags;
- int ref_offset; /* Offset of reference value */
- int ref_lock; /* Lock type to use */
- ASN1_aux_cb *asn1_cb;
- int enc_offset; /* Offset of ASN1_ENCODING structure */
-} ASN1_AUX;
-
-/* For print related callbacks exarg points to this structure */
-typedef struct ASN1_PRINT_ARG_st {
- BIO *out;
- int indent;
- const ASN1_PCTX *pctx;
-} ASN1_PRINT_ARG;
-
-/* For streaming related callbacks exarg points to this structure */
-typedef struct ASN1_STREAM_ARG_st {
- /* BIO to stream through */
- BIO *out;
- /* BIO with filters appended */
- BIO *ndef_bio;
- /* Streaming I/O boundary */
- unsigned char **boundary;
-} ASN1_STREAM_ARG;
-
-/* Flags in ASN1_AUX */
-
-/* Use a reference count */
-#define ASN1_AFLG_REFCOUNT 1
-/* Save the encoding of structure (useful for signatures) */
-#define ASN1_AFLG_ENCODING 2
-/* The Sequence length is invalid */
-#define ASN1_AFLG_BROKEN 4
-
-/* operation values for asn1_cb */
-
-#define ASN1_OP_NEW_PRE 0
-#define ASN1_OP_NEW_POST 1
-#define ASN1_OP_FREE_PRE 2
-#define ASN1_OP_FREE_POST 3
-#define ASN1_OP_D2I_PRE 4
-#define ASN1_OP_D2I_POST 5
-#define ASN1_OP_I2D_PRE 6
-#define ASN1_OP_I2D_POST 7
-#define ASN1_OP_PRINT_PRE 8
-#define ASN1_OP_PRINT_POST 9
-#define ASN1_OP_STREAM_PRE 10
-#define ASN1_OP_STREAM_POST 11
-#define ASN1_OP_DETACHED_PRE 12
-#define ASN1_OP_DETACHED_POST 13
-
-/* Macro to implement a primitive type */
-#define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0)
-#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \
- ASN1_ITEM_start(itname) \
- ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \
- ASN1_ITEM_end(itname)
-
-/* Macro to implement a multi string type */
-#define IMPLEMENT_ASN1_MSTRING(itname, mask) \
- ASN1_ITEM_start(itname) \
- ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \
- ASN1_ITEM_end(itname)
-
-/* Macro to implement an ASN1_ITEM in terms of old style funcs */
-
-#define IMPLEMENT_COMPAT_ASN1(sname) IMPLEMENT_COMPAT_ASN1_type(sname, V_ASN1_SEQUENCE)
-
-#define IMPLEMENT_COMPAT_ASN1_type(sname, tag) \
- static const ASN1_COMPAT_FUNCS sname##_ff = { \
- (ASN1_new_func *)sname##_new, \
- (ASN1_free_func *)sname##_free, \
- (ASN1_d2i_func *)d2i_##sname, \
- (ASN1_i2d_func *)i2d_##sname, \
- }; \
- ASN1_ITEM_start(sname) \
- ASN1_ITYPE_COMPAT, \
- tag, \
- NULL, \
- 0, \
- &sname##_ff, \
- 0, \
- #sname \
- ASN1_ITEM_end(sname)
-
-#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \
- ASN1_ITEM_start(sname) \
- ASN1_ITYPE_EXTERN, \
- tag, \
- NULL, \
- 0, \
- &fptrs, \
- 0, \
- #sname \
- ASN1_ITEM_end(sname)
-
-/* Macro to implement standard functions in terms of ASN1_ITEM structures */
-
-#define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)
-
-#define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname)
-
-#define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \
- IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname)
-
-#define IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(stname) \
- IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(static, stname, stname, stname)
-
-#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \
- IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname)
-
-#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(pre, stname, itname, fname) \
- pre stname *fname##_new(void) \
- { \
- return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
- } \
- pre void fname##_free(stname *a) \
- { \
- ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
- }
-
-#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \
- stname *fname##_new(void) \
- { \
- return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
- } \
- void fname##_free(stname *a) \
- { \
- ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
- }
-
-#define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \
- IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
- IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
-
-#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
- stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
- { \
- return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
- } \
- int i2d_##fname(stname *a, unsigned char **out) \
- { \
- return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
- }
-
-#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \
- int i2d_##stname##_NDEF(stname *a, unsigned char **out) \
- { \
- return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\
- }
-
-/* This includes evil casts to remove const: they will go away when full
- * ASN1 constification is done.
- */
-#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
- stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
- { \
- return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
- } \
- int i2d_##fname(const stname *a, unsigned char **out) \
- { \
- return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
- }
-
-#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \
- stname * stname##_dup(stname *x) \
- { \
- return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \
- }
-
-#define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \
- IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname)
-
-#define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \
- int fname##_print_ctx(BIO *out, stname *x, int indent, \
- const ASN1_PCTX *pctx) \
- { \
- return ASN1_item_print(out, (ASN1_VALUE *)x, indent, \
- ASN1_ITEM_rptr(itname), pctx); \
- }
-
-#define IMPLEMENT_ASN1_FUNCTIONS_const(name) \
- IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name)
-
-#define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \
- IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
- IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
-
-/* external definitions for primitive types */
-
-DECLARE_ASN1_ITEM(ASN1_BOOLEAN)
-DECLARE_ASN1_ITEM(ASN1_TBOOLEAN)
-DECLARE_ASN1_ITEM(ASN1_FBOOLEAN)
-DECLARE_ASN1_ITEM(ASN1_SEQUENCE)
-DECLARE_ASN1_ITEM(CBIGNUM)
-DECLARE_ASN1_ITEM(BIGNUM)
-DECLARE_ASN1_ITEM(LONG)
-DECLARE_ASN1_ITEM(ZLONG)
-
-DECLARE_STACK_OF(ASN1_VALUE)
-
-/* Functions used internally by the ASN1 code */
-
-int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
-void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
-int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
-int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
-
-void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
-int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt);
-int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it,
- int tag, int aclass, char opt, ASN1_TLC *ctx);
-
-int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass);
-int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt);
-void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
-
-int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it);
-int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it);
-
-int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it);
-int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it);
-
-ASN1_VALUE ** asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
-
-const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, int nullerr);
-
-int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it);
-
-void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it);
-void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
-int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, const ASN1_ITEM *it);
-int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, const ASN1_ITEM *it);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/bio.h b/drivers/builtin_openssl/openssl/bio.h
deleted file mode 100644
index 05699ab212..0000000000
--- a/drivers/builtin_openssl/openssl/bio.h
+++ /dev/null
@@ -1,847 +0,0 @@
-/* crypto/bio/bio.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_BIO_H
-#define HEADER_BIO_H
-
-#include <openssl/e_os2.h>
-
-#ifndef OPENSSL_NO_FP_API
-# include <stdio.h>
-#endif
-#include <stdarg.h>
-
-#include <openssl/crypto.h>
-
-#ifndef OPENSSL_NO_SCTP
-# ifndef OPENSSL_SYS_VMS
-# include <stdint.h>
-# else
-# include <inttypes.h>
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* These are the 'types' of BIOs */
-#define BIO_TYPE_NONE 0
-#define BIO_TYPE_MEM (1|0x0400)
-#define BIO_TYPE_FILE (2|0x0400)
-
-#define BIO_TYPE_FD (4|0x0400|0x0100)
-#define BIO_TYPE_SOCKET (5|0x0400|0x0100)
-#define BIO_TYPE_NULL (6|0x0400)
-#define BIO_TYPE_SSL (7|0x0200)
-#define BIO_TYPE_MD (8|0x0200) /* passive filter */
-#define BIO_TYPE_BUFFER (9|0x0200) /* filter */
-#define BIO_TYPE_CIPHER (10|0x0200) /* filter */
-#define BIO_TYPE_BASE64 (11|0x0200) /* filter */
-#define BIO_TYPE_CONNECT (12|0x0400|0x0100) /* socket - connect */
-#define BIO_TYPE_ACCEPT (13|0x0400|0x0100) /* socket for accept */
-#define BIO_TYPE_PROXY_CLIENT (14|0x0200) /* client proxy BIO */
-#define BIO_TYPE_PROXY_SERVER (15|0x0200) /* server proxy BIO */
-#define BIO_TYPE_NBIO_TEST (16|0x0200) /* server proxy BIO */
-#define BIO_TYPE_NULL_FILTER (17|0x0200)
-#define BIO_TYPE_BER (18|0x0200) /* BER -> bin filter */
-#define BIO_TYPE_BIO (19|0x0400) /* (half a) BIO pair */
-#define BIO_TYPE_LINEBUFFER (20|0x0200) /* filter */
-#define BIO_TYPE_DGRAM (21|0x0400|0x0100)
-#ifndef OPENSSL_NO_SCTP
-#define BIO_TYPE_DGRAM_SCTP (24|0x0400|0x0100)
-#endif
-#define BIO_TYPE_ASN1 (22|0x0200) /* filter */
-#define BIO_TYPE_COMP (23|0x0200) /* filter */
-
-#define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */
-#define BIO_TYPE_FILTER 0x0200
-#define BIO_TYPE_SOURCE_SINK 0x0400
-
-/* BIO_FILENAME_READ|BIO_CLOSE to open or close on free.
- * BIO_set_fp(in,stdin,BIO_NOCLOSE); */
-#define BIO_NOCLOSE 0x00
-#define BIO_CLOSE 0x01
-
-/* These are used in the following macros and are passed to
- * BIO_ctrl() */
-#define BIO_CTRL_RESET 1 /* opt - rewind/zero etc */
-#define BIO_CTRL_EOF 2 /* opt - are we at the eof */
-#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */
-#define BIO_CTRL_SET 4 /* man - set the 'IO' type */
-#define BIO_CTRL_GET 5 /* man - get the 'IO' type */
-#define BIO_CTRL_PUSH 6 /* opt - internal, used to signify change */
-#define BIO_CTRL_POP 7 /* opt - internal, used to signify change */
-#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */
-#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */
-#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */
-#define BIO_CTRL_FLUSH 11 /* opt - 'flush' buffered output */
-#define BIO_CTRL_DUP 12 /* man - extra stuff for 'duped' BIO */
-#define BIO_CTRL_WPENDING 13 /* opt - number of bytes still to write */
-/* callback is int cb(BIO *bio,state,ret); */
-#define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */
-#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */
-
-#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */
-
-/* dgram BIO stuff */
-#define BIO_CTRL_DGRAM_CONNECT 31 /* BIO dgram special */
-#define BIO_CTRL_DGRAM_SET_CONNECTED 32 /* allow for an externally
- * connected socket to be
- * passed in */
-#define BIO_CTRL_DGRAM_SET_RECV_TIMEOUT 33 /* setsockopt, essentially */
-#define BIO_CTRL_DGRAM_GET_RECV_TIMEOUT 34 /* getsockopt, essentially */
-#define BIO_CTRL_DGRAM_SET_SEND_TIMEOUT 35 /* setsockopt, essentially */
-#define BIO_CTRL_DGRAM_GET_SEND_TIMEOUT 36 /* getsockopt, essentially */
-
-#define BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP 37 /* flag whether the last */
-#define BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP 38 /* I/O operation tiemd out */
-
-/* #ifdef IP_MTU_DISCOVER */
-#define BIO_CTRL_DGRAM_MTU_DISCOVER 39 /* set DF bit on egress packets */
-/* #endif */
-
-#define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */
-#define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47
-#define BIO_CTRL_DGRAM_GET_MTU 41 /* get cached value for MTU */
-#define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for
- * MTU. want to use this
- * if asking the kernel
- * fails */
-
-#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU
- * was exceed in the
- * previous write
- * operation */
-
-#define BIO_CTRL_DGRAM_GET_PEER 46
-#define BIO_CTRL_DGRAM_SET_PEER 44 /* Destination for the data */
-
-#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45 /* Next DTLS handshake timeout to
- * adjust socket timeouts */
-
-#ifndef OPENSSL_NO_SCTP
-/* SCTP stuff */
-#define BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE 50
-#define BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY 51
-#define BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY 52
-#define BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD 53
-#define BIO_CTRL_DGRAM_SCTP_GET_SNDINFO 60
-#define BIO_CTRL_DGRAM_SCTP_SET_SNDINFO 61
-#define BIO_CTRL_DGRAM_SCTP_GET_RCVINFO 62
-#define BIO_CTRL_DGRAM_SCTP_SET_RCVINFO 63
-#define BIO_CTRL_DGRAM_SCTP_GET_PRINFO 64
-#define BIO_CTRL_DGRAM_SCTP_SET_PRINFO 65
-#define BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN 70
-#endif
-
-/* modifiers */
-#define BIO_FP_READ 0x02
-#define BIO_FP_WRITE 0x04
-#define BIO_FP_APPEND 0x08
-#define BIO_FP_TEXT 0x10
-
-#define BIO_FLAGS_READ 0x01
-#define BIO_FLAGS_WRITE 0x02
-#define BIO_FLAGS_IO_SPECIAL 0x04
-#define BIO_FLAGS_RWS (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL)
-#define BIO_FLAGS_SHOULD_RETRY 0x08
-#ifndef BIO_FLAGS_UPLINK
-/* "UPLINK" flag denotes file descriptors provided by application.
- It defaults to 0, as most platforms don't require UPLINK interface. */
-#define BIO_FLAGS_UPLINK 0
-#endif
-
-/* Used in BIO_gethostbyname() */
-#define BIO_GHBN_CTRL_HITS 1
-#define BIO_GHBN_CTRL_MISSES 2
-#define BIO_GHBN_CTRL_CACHE_SIZE 3
-#define BIO_GHBN_CTRL_GET_ENTRY 4
-#define BIO_GHBN_CTRL_FLUSH 5
-
-/* Mostly used in the SSL BIO */
-/* Not used anymore
- * #define BIO_FLAGS_PROTOCOL_DELAYED_READ 0x10
- * #define BIO_FLAGS_PROTOCOL_DELAYED_WRITE 0x20
- * #define BIO_FLAGS_PROTOCOL_STARTUP 0x40
- */
-
-#define BIO_FLAGS_BASE64_NO_NL 0x100
-
-/* This is used with memory BIOs: it means we shouldn't free up or change the
- * data in any way.
- */
-#define BIO_FLAGS_MEM_RDONLY 0x200
-
-typedef struct bio_st BIO;
-
-void BIO_set_flags(BIO *b, int flags);
-int BIO_test_flags(const BIO *b, int flags);
-void BIO_clear_flags(BIO *b, int flags);
-
-#define BIO_get_flags(b) BIO_test_flags(b, ~(0x0))
-#define BIO_set_retry_special(b) \
- BIO_set_flags(b, (BIO_FLAGS_IO_SPECIAL|BIO_FLAGS_SHOULD_RETRY))
-#define BIO_set_retry_read(b) \
- BIO_set_flags(b, (BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY))
-#define BIO_set_retry_write(b) \
- BIO_set_flags(b, (BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY))
-
-/* These are normally used internally in BIOs */
-#define BIO_clear_retry_flags(b) \
- BIO_clear_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
-#define BIO_get_retry_flags(b) \
- BIO_test_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
-
-/* These should be used by the application to tell why we should retry */
-#define BIO_should_read(a) BIO_test_flags(a, BIO_FLAGS_READ)
-#define BIO_should_write(a) BIO_test_flags(a, BIO_FLAGS_WRITE)
-#define BIO_should_io_special(a) BIO_test_flags(a, BIO_FLAGS_IO_SPECIAL)
-#define BIO_retry_type(a) BIO_test_flags(a, BIO_FLAGS_RWS)
-#define BIO_should_retry(a) BIO_test_flags(a, BIO_FLAGS_SHOULD_RETRY)
-
-/* The next three are used in conjunction with the
- * BIO_should_io_special() condition. After this returns true,
- * BIO *BIO_get_retry_BIO(BIO *bio, int *reason); will walk the BIO
- * stack and return the 'reason' for the special and the offending BIO.
- * Given a BIO, BIO_get_retry_reason(bio) will return the code. */
-/* Returned from the SSL bio when the certificate retrieval code had an error */
-#define BIO_RR_SSL_X509_LOOKUP 0x01
-/* Returned from the connect BIO when a connect would have blocked */
-#define BIO_RR_CONNECT 0x02
-/* Returned from the accept BIO when an accept would have blocked */
-#define BIO_RR_ACCEPT 0x03
-
-/* These are passed by the BIO callback */
-#define BIO_CB_FREE 0x01
-#define BIO_CB_READ 0x02
-#define BIO_CB_WRITE 0x03
-#define BIO_CB_PUTS 0x04
-#define BIO_CB_GETS 0x05
-#define BIO_CB_CTRL 0x06
-
-/* The callback is called before and after the underling operation,
- * The BIO_CB_RETURN flag indicates if it is after the call */
-#define BIO_CB_RETURN 0x80
-#define BIO_CB_return(a) ((a)|BIO_CB_RETURN))
-#define BIO_cb_pre(a) (!((a)&BIO_CB_RETURN))
-#define BIO_cb_post(a) ((a)&BIO_CB_RETURN)
-
-long (*BIO_get_callback(const BIO *b)) (struct bio_st *,int,const char *,int, long,long);
-void BIO_set_callback(BIO *b,
- long (*callback)(struct bio_st *,int,const char *,int, long,long));
-char *BIO_get_callback_arg(const BIO *b);
-void BIO_set_callback_arg(BIO *b, char *arg);
-
-const char * BIO_method_name(const BIO *b);
-int BIO_method_type(const BIO *b);
-
-typedef void bio_info_cb(struct bio_st *, int, const char *, int, long, long);
-
-typedef struct bio_method_st
- {
- int type;
- const char *name;
- int (*bwrite)(BIO *, const char *, int);
- int (*bread)(BIO *, char *, int);
- int (*bputs)(BIO *, const char *);
- int (*bgets)(BIO *, char *, int);
- long (*ctrl)(BIO *, int, long, void *);
- int (*create)(BIO *);
- int (*destroy)(BIO *);
- long (*callback_ctrl)(BIO *, int, bio_info_cb *);
- } BIO_METHOD;
-
-struct bio_st
- {
- BIO_METHOD *method;
- /* bio, mode, argp, argi, argl, ret */
- long (*callback)(struct bio_st *,int,const char *,int, long,long);
- char *cb_arg; /* first argument for the callback */
-
- int init;
- int shutdown;
- int flags; /* extra storage */
- int retry_reason;
- int num;
- void *ptr;
- struct bio_st *next_bio; /* used by filter BIOs */
- struct bio_st *prev_bio; /* used by filter BIOs */
- int references;
- unsigned long num_read;
- unsigned long num_write;
-
- CRYPTO_EX_DATA ex_data;
- };
-
-DECLARE_STACK_OF(BIO)
-
-typedef struct bio_f_buffer_ctx_struct
- {
- /* Buffers are setup like this:
- *
- * <---------------------- size ----------------------->
- * +---------------------------------------------------+
- * | consumed | remaining | free space |
- * +---------------------------------------------------+
- * <-- off --><------- len ------->
- */
-
- /* BIO *bio; */ /* this is now in the BIO struct */
- int ibuf_size; /* how big is the input buffer */
- int obuf_size; /* how big is the output buffer */
-
- char *ibuf; /* the char array */
- int ibuf_len; /* how many bytes are in it */
- int ibuf_off; /* write/read offset */
-
- char *obuf; /* the char array */
- int obuf_len; /* how many bytes are in it */
- int obuf_off; /* write/read offset */
- } BIO_F_BUFFER_CTX;
-
-/* Prefix and suffix callback in ASN1 BIO */
-typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg);
-
-#ifndef OPENSSL_NO_SCTP
-/* SCTP parameter structs */
-struct bio_dgram_sctp_sndinfo
- {
- uint16_t snd_sid;
- uint16_t snd_flags;
- uint32_t snd_ppid;
- uint32_t snd_context;
- };
-
-struct bio_dgram_sctp_rcvinfo
- {
- uint16_t rcv_sid;
- uint16_t rcv_ssn;
- uint16_t rcv_flags;
- uint32_t rcv_ppid;
- uint32_t rcv_tsn;
- uint32_t rcv_cumtsn;
- uint32_t rcv_context;
- };
-
-struct bio_dgram_sctp_prinfo
- {
- uint16_t pr_policy;
- uint32_t pr_value;
- };
-#endif
-
-/* connect BIO stuff */
-#define BIO_CONN_S_BEFORE 1
-#define BIO_CONN_S_GET_IP 2
-#define BIO_CONN_S_GET_PORT 3
-#define BIO_CONN_S_CREATE_SOCKET 4
-#define BIO_CONN_S_CONNECT 5
-#define BIO_CONN_S_OK 6
-#define BIO_CONN_S_BLOCKED_CONNECT 7
-#define BIO_CONN_S_NBIO 8
-/*#define BIO_CONN_get_param_hostname BIO_ctrl */
-
-#define BIO_C_SET_CONNECT 100
-#define BIO_C_DO_STATE_MACHINE 101
-#define BIO_C_SET_NBIO 102
-#define BIO_C_SET_PROXY_PARAM 103
-#define BIO_C_SET_FD 104
-#define BIO_C_GET_FD 105
-#define BIO_C_SET_FILE_PTR 106
-#define BIO_C_GET_FILE_PTR 107
-#define BIO_C_SET_FILENAME 108
-#define BIO_C_SET_SSL 109
-#define BIO_C_GET_SSL 110
-#define BIO_C_SET_MD 111
-#define BIO_C_GET_MD 112
-#define BIO_C_GET_CIPHER_STATUS 113
-#define BIO_C_SET_BUF_MEM 114
-#define BIO_C_GET_BUF_MEM_PTR 115
-#define BIO_C_GET_BUFF_NUM_LINES 116
-#define BIO_C_SET_BUFF_SIZE 117
-#define BIO_C_SET_ACCEPT 118
-#define BIO_C_SSL_MODE 119
-#define BIO_C_GET_MD_CTX 120
-#define BIO_C_GET_PROXY_PARAM 121
-#define BIO_C_SET_BUFF_READ_DATA 122 /* data to read first */
-#define BIO_C_GET_CONNECT 123
-#define BIO_C_GET_ACCEPT 124
-#define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125
-#define BIO_C_GET_SSL_NUM_RENEGOTIATES 126
-#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127
-#define BIO_C_FILE_SEEK 128
-#define BIO_C_GET_CIPHER_CTX 129
-#define BIO_C_SET_BUF_MEM_EOF_RETURN 130/*return end of input value*/
-#define BIO_C_SET_BIND_MODE 131
-#define BIO_C_GET_BIND_MODE 132
-#define BIO_C_FILE_TELL 133
-#define BIO_C_GET_SOCKS 134
-#define BIO_C_SET_SOCKS 135
-
-#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */
-#define BIO_C_GET_WRITE_BUF_SIZE 137
-#define BIO_C_MAKE_BIO_PAIR 138
-#define BIO_C_DESTROY_BIO_PAIR 139
-#define BIO_C_GET_WRITE_GUARANTEE 140
-#define BIO_C_GET_READ_REQUEST 141
-#define BIO_C_SHUTDOWN_WR 142
-#define BIO_C_NREAD0 143
-#define BIO_C_NREAD 144
-#define BIO_C_NWRITE0 145
-#define BIO_C_NWRITE 146
-#define BIO_C_RESET_READ_REQUEST 147
-#define BIO_C_SET_MD_CTX 148
-
-#define BIO_C_SET_PREFIX 149
-#define BIO_C_GET_PREFIX 150
-#define BIO_C_SET_SUFFIX 151
-#define BIO_C_GET_SUFFIX 152
-
-#define BIO_C_SET_EX_ARG 153
-#define BIO_C_GET_EX_ARG 154
-
-#define BIO_set_app_data(s,arg) BIO_set_ex_data(s,0,arg)
-#define BIO_get_app_data(s) BIO_get_ex_data(s,0)
-
-/* BIO_s_connect() and BIO_s_socks4a_connect() */
-#define BIO_set_conn_hostname(b,name) BIO_ctrl(b,BIO_C_SET_CONNECT,0,(char *)name)
-#define BIO_set_conn_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,1,(char *)port)
-#define BIO_set_conn_ip(b,ip) BIO_ctrl(b,BIO_C_SET_CONNECT,2,(char *)ip)
-#define BIO_set_conn_int_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,3,(char *)port)
-#define BIO_get_conn_hostname(b) BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,0)
-#define BIO_get_conn_port(b) BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,1)
-#define BIO_get_conn_ip(b) BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2)
-#define BIO_get_conn_int_port(b) BIO_int_ctrl(b,BIO_C_GET_CONNECT,3,0)
-
-
-#define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL)
-
-/* BIO_s_accept_socket() */
-#define BIO_set_accept_port(b,name) BIO_ctrl(b,BIO_C_SET_ACCEPT,0,(char *)name)
-#define BIO_get_accept_port(b) BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,0)
-/* #define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) */
-#define BIO_set_nbio_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,1,(n)?(void *)"a":NULL)
-#define BIO_set_accept_bios(b,bio) BIO_ctrl(b,BIO_C_SET_ACCEPT,2,(char *)bio)
-
-#define BIO_BIND_NORMAL 0
-#define BIO_BIND_REUSEADDR_IF_UNUSED 1
-#define BIO_BIND_REUSEADDR 2
-#define BIO_set_bind_mode(b,mode) BIO_ctrl(b,BIO_C_SET_BIND_MODE,mode,NULL)
-#define BIO_get_bind_mode(b,mode) BIO_ctrl(b,BIO_C_GET_BIND_MODE,0,NULL)
-
-#define BIO_do_connect(b) BIO_do_handshake(b)
-#define BIO_do_accept(b) BIO_do_handshake(b)
-#define BIO_do_handshake(b) BIO_ctrl(b,BIO_C_DO_STATE_MACHINE,0,NULL)
-
-/* BIO_s_proxy_client() */
-#define BIO_set_url(b,url) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,0,(char *)(url))
-#define BIO_set_proxies(b,p) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,1,(char *)(p))
-/* BIO_set_nbio(b,n) */
-#define BIO_set_filter_bio(b,s) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,2,(char *)(s))
-/* BIO *BIO_get_filter_bio(BIO *bio); */
-#define BIO_set_proxy_cb(b,cb) BIO_callback_ctrl(b,BIO_C_SET_PROXY_PARAM,3,(void *(*cb)()))
-#define BIO_set_proxy_header(b,sk) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,4,(char *)sk)
-#define BIO_set_no_connect_return(b,bool) BIO_int_ctrl(b,BIO_C_SET_PROXY_PARAM,5,bool)
-
-#define BIO_get_proxy_header(b,skp) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,0,(char *)skp)
-#define BIO_get_proxies(b,pxy_p) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,1,(char *)(pxy_p))
-#define BIO_get_url(b,url) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,2,(char *)(url))
-#define BIO_get_no_connect_return(b) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,5,NULL)
-
-#define BIO_set_fd(b,fd,c) BIO_int_ctrl(b,BIO_C_SET_FD,c,fd)
-#define BIO_get_fd(b,c) BIO_ctrl(b,BIO_C_GET_FD,0,(char *)c)
-
-#define BIO_set_fp(b,fp,c) BIO_ctrl(b,BIO_C_SET_FILE_PTR,c,(char *)fp)
-#define BIO_get_fp(b,fpp) BIO_ctrl(b,BIO_C_GET_FILE_PTR,0,(char *)fpp)
-
-#define BIO_seek(b,ofs) (int)BIO_ctrl(b,BIO_C_FILE_SEEK,ofs,NULL)
-#define BIO_tell(b) (int)BIO_ctrl(b,BIO_C_FILE_TELL,0,NULL)
-
-/* name is cast to lose const, but might be better to route through a function
- so we can do it safely */
-#ifdef CONST_STRICT
-/* If you are wondering why this isn't defined, its because CONST_STRICT is
- * purely a compile-time kludge to allow const to be checked.
- */
-int BIO_read_filename(BIO *b,const char *name);
-#else
-#define BIO_read_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \
- BIO_CLOSE|BIO_FP_READ,(char *)name)
-#endif
-#define BIO_write_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \
- BIO_CLOSE|BIO_FP_WRITE,name)
-#define BIO_append_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \
- BIO_CLOSE|BIO_FP_APPEND,name)
-#define BIO_rw_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \
- BIO_CLOSE|BIO_FP_READ|BIO_FP_WRITE,name)
-
-/* WARNING WARNING, this ups the reference count on the read bio of the
- * SSL structure. This is because the ssl read BIO is now pointed to by
- * the next_bio field in the bio. So when you free the BIO, make sure
- * you are doing a BIO_free_all() to catch the underlying BIO. */
-#define BIO_set_ssl(b,ssl,c) BIO_ctrl(b,BIO_C_SET_SSL,c,(char *)ssl)
-#define BIO_get_ssl(b,sslp) BIO_ctrl(b,BIO_C_GET_SSL,0,(char *)sslp)
-#define BIO_set_ssl_mode(b,client) BIO_ctrl(b,BIO_C_SSL_MODE,client,NULL)
-#define BIO_set_ssl_renegotiate_bytes(b,num) \
- BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_BYTES,num,NULL);
-#define BIO_get_num_renegotiates(b) \
- BIO_ctrl(b,BIO_C_GET_SSL_NUM_RENEGOTIATES,0,NULL);
-#define BIO_set_ssl_renegotiate_timeout(b,seconds) \
- BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT,seconds,NULL);
-
-/* defined in evp.h */
-/* #define BIO_set_md(b,md) BIO_ctrl(b,BIO_C_SET_MD,1,(char *)md) */
-
-#define BIO_get_mem_data(b,pp) BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp)
-#define BIO_set_mem_buf(b,bm,c) BIO_ctrl(b,BIO_C_SET_BUF_MEM,c,(char *)bm)
-#define BIO_get_mem_ptr(b,pp) BIO_ctrl(b,BIO_C_GET_BUF_MEM_PTR,0,(char *)pp)
-#define BIO_set_mem_eof_return(b,v) \
- BIO_ctrl(b,BIO_C_SET_BUF_MEM_EOF_RETURN,v,NULL)
-
-/* For the BIO_f_buffer() type */
-#define BIO_get_buffer_num_lines(b) BIO_ctrl(b,BIO_C_GET_BUFF_NUM_LINES,0,NULL)
-#define BIO_set_buffer_size(b,size) BIO_ctrl(b,BIO_C_SET_BUFF_SIZE,size,NULL)
-#define BIO_set_read_buffer_size(b,size) BIO_int_ctrl(b,BIO_C_SET_BUFF_SIZE,size,0)
-#define BIO_set_write_buffer_size(b,size) BIO_int_ctrl(b,BIO_C_SET_BUFF_SIZE,size,1)
-#define BIO_set_buffer_read_data(b,buf,num) BIO_ctrl(b,BIO_C_SET_BUFF_READ_DATA,num,buf)
-
-/* Don't use the next one unless you know what you are doing :-) */
-#define BIO_dup_state(b,ret) BIO_ctrl(b,BIO_CTRL_DUP,0,(char *)(ret))
-
-#define BIO_reset(b) (int)BIO_ctrl(b,BIO_CTRL_RESET,0,NULL)
-#define BIO_eof(b) (int)BIO_ctrl(b,BIO_CTRL_EOF,0,NULL)
-#define BIO_set_close(b,c) (int)BIO_ctrl(b,BIO_CTRL_SET_CLOSE,(c),NULL)
-#define BIO_get_close(b) (int)BIO_ctrl(b,BIO_CTRL_GET_CLOSE,0,NULL)
-#define BIO_pending(b) (int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
-#define BIO_wpending(b) (int)BIO_ctrl(b,BIO_CTRL_WPENDING,0,NULL)
-/* ...pending macros have inappropriate return type */
-size_t BIO_ctrl_pending(BIO *b);
-size_t BIO_ctrl_wpending(BIO *b);
-#define BIO_flush(b) (int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL)
-#define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0, \
- cbp)
-#define BIO_set_info_callback(b,cb) (int)BIO_callback_ctrl(b,BIO_CTRL_SET_CALLBACK,cb)
-
-/* For the BIO_f_buffer() type */
-#define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL)
-
-/* For BIO_s_bio() */
-#define BIO_set_write_buf_size(b,size) (int)BIO_ctrl(b,BIO_C_SET_WRITE_BUF_SIZE,size,NULL)
-#define BIO_get_write_buf_size(b,size) (size_t)BIO_ctrl(b,BIO_C_GET_WRITE_BUF_SIZE,size,NULL)
-#define BIO_make_bio_pair(b1,b2) (int)BIO_ctrl(b1,BIO_C_MAKE_BIO_PAIR,0,b2)
-#define BIO_destroy_bio_pair(b) (int)BIO_ctrl(b,BIO_C_DESTROY_BIO_PAIR,0,NULL)
-#define BIO_shutdown_wr(b) (int)BIO_ctrl(b, BIO_C_SHUTDOWN_WR, 0, NULL)
-/* macros with inappropriate type -- but ...pending macros use int too: */
-#define BIO_get_write_guarantee(b) (int)BIO_ctrl(b,BIO_C_GET_WRITE_GUARANTEE,0,NULL)
-#define BIO_get_read_request(b) (int)BIO_ctrl(b,BIO_C_GET_READ_REQUEST,0,NULL)
-size_t BIO_ctrl_get_write_guarantee(BIO *b);
-size_t BIO_ctrl_get_read_request(BIO *b);
-int BIO_ctrl_reset_read_request(BIO *b);
-
-/* ctrl macros for dgram */
-#define BIO_ctrl_dgram_connect(b,peer) \
- (int)BIO_ctrl(b,BIO_CTRL_DGRAM_CONNECT,0, (char *)peer)
-#define BIO_ctrl_set_connected(b, state, peer) \
- (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_CONNECTED, state, (char *)peer)
-#define BIO_dgram_recv_timedout(b) \
- (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL)
-#define BIO_dgram_send_timedout(b) \
- (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP, 0, NULL)
-#define BIO_dgram_get_peer(b,peer) \
- (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_PEER, 0, (char *)peer)
-#define BIO_dgram_set_peer(b,peer) \
- (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)peer)
-
-/* These two aren't currently implemented */
-/* int BIO_get_ex_num(BIO *bio); */
-/* void BIO_set_ex_free_func(BIO *bio,int idx,void (*cb)()); */
-int BIO_set_ex_data(BIO *bio,int idx,void *data);
-void *BIO_get_ex_data(BIO *bio,int idx);
-int BIO_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-unsigned long BIO_number_read(BIO *bio);
-unsigned long BIO_number_written(BIO *bio);
-
-/* For BIO_f_asn1() */
-int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
- asn1_ps_func *prefix_free);
-int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
- asn1_ps_func **pprefix_free);
-int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
- asn1_ps_func *suffix_free);
-int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
- asn1_ps_func **psuffix_free);
-
-# ifndef OPENSSL_NO_FP_API
-BIO_METHOD *BIO_s_file(void );
-BIO *BIO_new_file(const char *filename, const char *mode);
-BIO *BIO_new_fp(FILE *stream, int close_flag);
-# define BIO_s_file_internal BIO_s_file
-# endif
-BIO * BIO_new(BIO_METHOD *type);
-int BIO_set(BIO *a,BIO_METHOD *type);
-int BIO_free(BIO *a);
-void BIO_vfree(BIO *a);
-int BIO_read(BIO *b, void *data, int len);
-int BIO_gets(BIO *bp,char *buf, int size);
-int BIO_write(BIO *b, const void *data, int len);
-int BIO_puts(BIO *bp,const char *buf);
-int BIO_indent(BIO *b,int indent,int max);
-long BIO_ctrl(BIO *bp,int cmd,long larg,void *parg);
-long BIO_callback_ctrl(BIO *b, int cmd, void (*fp)(struct bio_st *, int, const char *, int, long, long));
-char * BIO_ptr_ctrl(BIO *bp,int cmd,long larg);
-long BIO_int_ctrl(BIO *bp,int cmd,long larg,int iarg);
-BIO * BIO_push(BIO *b,BIO *append);
-BIO * BIO_pop(BIO *b);
-void BIO_free_all(BIO *a);
-BIO * BIO_find_type(BIO *b,int bio_type);
-BIO * BIO_next(BIO *b);
-BIO * BIO_get_retry_BIO(BIO *bio, int *reason);
-int BIO_get_retry_reason(BIO *bio);
-BIO * BIO_dup_chain(BIO *in);
-
-int BIO_nread0(BIO *bio, char **buf);
-int BIO_nread(BIO *bio, char **buf, int num);
-int BIO_nwrite0(BIO *bio, char **buf);
-int BIO_nwrite(BIO *bio, char **buf, int num);
-
-long BIO_debug_callback(BIO *bio,int cmd,const char *argp,int argi,
- long argl,long ret);
-
-BIO_METHOD *BIO_s_mem(void);
-BIO *BIO_new_mem_buf(void *buf, int len);
-BIO_METHOD *BIO_s_socket(void);
-BIO_METHOD *BIO_s_connect(void);
-BIO_METHOD *BIO_s_accept(void);
-BIO_METHOD *BIO_s_fd(void);
-#ifndef OPENSSL_SYS_OS2
-BIO_METHOD *BIO_s_log(void);
-#endif
-BIO_METHOD *BIO_s_bio(void);
-BIO_METHOD *BIO_s_null(void);
-BIO_METHOD *BIO_f_null(void);
-BIO_METHOD *BIO_f_buffer(void);
-#ifdef OPENSSL_SYS_VMS
-BIO_METHOD *BIO_f_linebuffer(void);
-#endif
-BIO_METHOD *BIO_f_nbio_test(void);
-#ifndef OPENSSL_NO_DGRAM
-BIO_METHOD *BIO_s_datagram(void);
-#ifndef OPENSSL_NO_SCTP
-BIO_METHOD *BIO_s_datagram_sctp(void);
-#endif
-#endif
-
-/* BIO_METHOD *BIO_f_ber(void); */
-
-int BIO_sock_should_retry(int i);
-int BIO_sock_non_fatal_error(int error);
-int BIO_dgram_non_fatal_error(int error);
-
-int BIO_fd_should_retry(int i);
-int BIO_fd_non_fatal_error(int error);
-int BIO_dump_cb(int (*cb)(const void *data, size_t len, void *u),
- void *u, const char *s, int len);
-int BIO_dump_indent_cb(int (*cb)(const void *data, size_t len, void *u),
- void *u, const char *s, int len, int indent);
-int BIO_dump(BIO *b,const char *bytes,int len);
-int BIO_dump_indent(BIO *b,const char *bytes,int len,int indent);
-#ifndef OPENSSL_NO_FP_API
-int BIO_dump_fp(FILE *fp, const char *s, int len);
-int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent);
-#endif
-struct hostent *BIO_gethostbyname(const char *name);
-/* We might want a thread-safe interface too:
- * struct hostent *BIO_gethostbyname_r(const char *name,
- * struct hostent *result, void *buffer, size_t buflen);
- * or something similar (caller allocates a struct hostent,
- * pointed to by "result", and additional buffer space for the various
- * substructures; if the buffer does not suffice, NULL is returned
- * and an appropriate error code is set).
- */
-int BIO_sock_error(int sock);
-int BIO_socket_ioctl(int fd, long type, void *arg);
-int BIO_socket_nbio(int fd,int mode);
-int BIO_get_port(const char *str, unsigned short *port_ptr);
-int BIO_get_host_ip(const char *str, unsigned char *ip);
-int BIO_get_accept_socket(char *host_port,int mode);
-int BIO_accept(int sock,char **ip_port);
-int BIO_sock_init(void );
-void BIO_sock_cleanup(void);
-int BIO_set_tcp_ndelay(int sock,int turn_on);
-
-BIO *BIO_new_socket(int sock, int close_flag);
-BIO *BIO_new_dgram(int fd, int close_flag);
-#ifndef OPENSSL_NO_SCTP
-BIO *BIO_new_dgram_sctp(int fd, int close_flag);
-int BIO_dgram_is_sctp(BIO *bio);
-int BIO_dgram_sctp_notification_cb(BIO *b,
- void (*handle_notifications)(BIO *bio, void *context, void *buf),
- void *context);
-int BIO_dgram_sctp_wait_for_dry(BIO *b);
-int BIO_dgram_sctp_msg_waiting(BIO *b);
-#endif
-BIO *BIO_new_fd(int fd, int close_flag);
-BIO *BIO_new_connect(char *host_port);
-BIO *BIO_new_accept(char *host_port);
-
-int BIO_new_bio_pair(BIO **bio1, size_t writebuf1,
- BIO **bio2, size_t writebuf2);
-/* If successful, returns 1 and in *bio1, *bio2 two BIO pair endpoints.
- * Otherwise returns 0 and sets *bio1 and *bio2 to NULL.
- * Size 0 uses default value.
- */
-
-void BIO_copy_next_retry(BIO *b);
-
-/*long BIO_ghbn_ctrl(int cmd,int iarg,char *parg);*/
-
-#ifdef __GNUC__
-# define __bio_h__attr__ __attribute__
-#else
-# define __bio_h__attr__(x)
-#endif
-int BIO_printf(BIO *bio, const char *format, ...)
- __bio_h__attr__((__format__(__printf__,2,3)));
-int BIO_vprintf(BIO *bio, const char *format, va_list args)
- __bio_h__attr__((__format__(__printf__,2,0)));
-int BIO_snprintf(char *buf, size_t n, const char *format, ...)
- __bio_h__attr__((__format__(__printf__,3,4)));
-int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
- __bio_h__attr__((__format__(__printf__,3,0)));
-#undef __bio_h__attr__
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_BIO_strings(void);
-
-/* Error codes for the BIO functions. */
-
-/* Function codes. */
-#define BIO_F_ACPT_STATE 100
-#define BIO_F_BIO_ACCEPT 101
-#define BIO_F_BIO_BER_GET_HEADER 102
-#define BIO_F_BIO_CALLBACK_CTRL 131
-#define BIO_F_BIO_CTRL 103
-#define BIO_F_BIO_GETHOSTBYNAME 120
-#define BIO_F_BIO_GETS 104
-#define BIO_F_BIO_GET_ACCEPT_SOCKET 105
-#define BIO_F_BIO_GET_HOST_IP 106
-#define BIO_F_BIO_GET_PORT 107
-#define BIO_F_BIO_MAKE_PAIR 121
-#define BIO_F_BIO_NEW 108
-#define BIO_F_BIO_NEW_FILE 109
-#define BIO_F_BIO_NEW_MEM_BUF 126
-#define BIO_F_BIO_NREAD 123
-#define BIO_F_BIO_NREAD0 124
-#define BIO_F_BIO_NWRITE 125
-#define BIO_F_BIO_NWRITE0 122
-#define BIO_F_BIO_PUTS 110
-#define BIO_F_BIO_READ 111
-#define BIO_F_BIO_SOCK_INIT 112
-#define BIO_F_BIO_WRITE 113
-#define BIO_F_BUFFER_CTRL 114
-#define BIO_F_CONN_CTRL 127
-#define BIO_F_CONN_STATE 115
-#define BIO_F_DGRAM_SCTP_READ 132
-#define BIO_F_FILE_CTRL 116
-#define BIO_F_FILE_READ 130
-#define BIO_F_LINEBUFFER_CTRL 129
-#define BIO_F_MEM_READ 128
-#define BIO_F_MEM_WRITE 117
-#define BIO_F_SSL_NEW 118
-#define BIO_F_WSASTARTUP 119
-
-/* Reason codes. */
-#define BIO_R_ACCEPT_ERROR 100
-#define BIO_R_BAD_FOPEN_MODE 101
-#define BIO_R_BAD_HOSTNAME_LOOKUP 102
-#define BIO_R_BROKEN_PIPE 124
-#define BIO_R_CONNECT_ERROR 103
-#define BIO_R_EOF_ON_MEMORY_BIO 127
-#define BIO_R_ERROR_SETTING_NBIO 104
-#define BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET 105
-#define BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET 106
-#define BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET 107
-#define BIO_R_INVALID_ARGUMENT 125
-#define BIO_R_INVALID_IP_ADDRESS 108
-#define BIO_R_IN_USE 123
-#define BIO_R_KEEPALIVE 109
-#define BIO_R_NBIO_CONNECT_ERROR 110
-#define BIO_R_NO_ACCEPT_PORT_SPECIFIED 111
-#define BIO_R_NO_HOSTNAME_SPECIFIED 112
-#define BIO_R_NO_PORT_DEFINED 113
-#define BIO_R_NO_PORT_SPECIFIED 114
-#define BIO_R_NO_SUCH_FILE 128
-#define BIO_R_NULL_PARAMETER 115
-#define BIO_R_TAG_MISMATCH 116
-#define BIO_R_UNABLE_TO_BIND_SOCKET 117
-#define BIO_R_UNABLE_TO_CREATE_SOCKET 118
-#define BIO_R_UNABLE_TO_LISTEN_SOCKET 119
-#define BIO_R_UNINITIALIZED 120
-#define BIO_R_UNSUPPORTED_METHOD 121
-#define BIO_R_WRITE_TO_READ_ONLY_BIO 126
-#define BIO_R_WSASTARTUP 122
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/blowfish.h b/drivers/builtin_openssl/openssl/blowfish.h
deleted file mode 100644
index 4b6c8920a4..0000000000
--- a/drivers/builtin_openssl/openssl/blowfish.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* crypto/bf/blowfish.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_BLOWFISH_H
-#define HEADER_BLOWFISH_H
-
-#include <openssl/e_os2.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_NO_BF
-#error BF is disabled.
-#endif
-
-#define BF_ENCRYPT 1
-#define BF_DECRYPT 0
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * ! BF_LONG has to be at least 32 bits wide. If it's wider, then !
- * ! BF_LONG_LOG2 has to be defined along. !
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- */
-
-#if defined(__LP32__)
-#define BF_LONG unsigned long
-#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
-#define BF_LONG unsigned long
-#define BF_LONG_LOG2 3
-/*
- * _CRAY note. I could declare short, but I have no idea what impact
- * does it have on performance on none-T3E machines. I could declare
- * int, but at least on C90 sizeof(int) can be chosen at compile time.
- * So I've chosen long...
- * <appro@fy.chalmers.se>
- */
-#else
-#define BF_LONG unsigned int
-#endif
-
-#define BF_ROUNDS 16
-#define BF_BLOCK 8
-
-typedef struct bf_key_st
- {
- BF_LONG P[BF_ROUNDS+2];
- BF_LONG S[4*256];
- } BF_KEY;
-
-#ifdef OPENSSL_FIPS
-void private_BF_set_key(BF_KEY *key, int len, const unsigned char *data);
-#endif
-void BF_set_key(BF_KEY *key, int len, const unsigned char *data);
-
-void BF_encrypt(BF_LONG *data,const BF_KEY *key);
-void BF_decrypt(BF_LONG *data,const BF_KEY *key);
-
-void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
- const BF_KEY *key, int enc);
-void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
- const BF_KEY *schedule, unsigned char *ivec, int enc);
-void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length,
- const BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
-void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length,
- const BF_KEY *schedule, unsigned char *ivec, int *num);
-const char *BF_options(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/bn.h b/drivers/builtin_openssl/openssl/bn.h
deleted file mode 100644
index 21a1a3fe35..0000000000
--- a/drivers/builtin_openssl/openssl/bn.h
+++ /dev/null
@@ -1,902 +0,0 @@
-/* crypto/bn/bn.h */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the Eric Young open source
- * license provided above.
- *
- * The binary polynomial arithmetic software is originally written by
- * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
- *
- */
-
-#ifndef HEADER_BN_H
-#define HEADER_BN_H
-
-#include <openssl/e_os2.h>
-#ifndef OPENSSL_NO_FP_API
-#include <stdio.h> /* FILE */
-#endif
-#include <openssl/ossl_typ.h>
-#include <openssl/crypto.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* These preprocessor symbols control various aspects of the bignum headers and
- * library code. They're not defined by any "normal" configuration, as they are
- * intended for development and testing purposes. NB: defining all three can be
- * useful for debugging application code as well as openssl itself.
- *
- * BN_DEBUG - turn on various debugging alterations to the bignum code
- * BN_DEBUG_RAND - uses random poisoning of unused words to trip up
- * mismanagement of bignum internals. You must also define BN_DEBUG.
- */
-/* #define BN_DEBUG */
-/* #define BN_DEBUG_RAND */
-
-#ifndef OPENSSL_SMALL_FOOTPRINT
-#define BN_MUL_COMBA
-#define BN_SQR_COMBA
-#define BN_RECURSION
-#endif
-
-/* This next option uses the C libraries (2 word)/(1 word) function.
- * If it is not defined, I use my C version (which is slower).
- * The reason for this flag is that when the particular C compiler
- * library routine is used, and the library is linked with a different
- * compiler, the library is missing. This mostly happens when the
- * library is built with gcc and then linked using normal cc. This would
- * be a common occurrence because gcc normally produces code that is
- * 2 times faster than system compilers for the big number stuff.
- * For machines with only one compiler (or shared libraries), this should
- * be on. Again this in only really a problem on machines
- * using "long long's", are 32bit, and are not using my assembler code. */
-#if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) || \
- defined(OPENSSL_SYS_WIN32) || defined(linux)
-# ifndef BN_DIV2W
-# define BN_DIV2W
-# endif
-#endif
-
-/* assuming long is 64bit - this is the DEC Alpha
- * unsigned long long is only 64 bits :-(, don't define
- * BN_LLONG for the DEC Alpha */
-#ifdef SIXTY_FOUR_BIT_LONG
-#define BN_ULLONG unsigned long long
-#define BN_ULONG unsigned long
-#define BN_LONG long
-#define BN_BITS 128
-#define BN_BYTES 8
-#define BN_BITS2 64
-#define BN_BITS4 32
-#define BN_MASK (0xffffffffffffffffffffffffffffffffLL)
-#define BN_MASK2 (0xffffffffffffffffL)
-#define BN_MASK2l (0xffffffffL)
-#define BN_MASK2h (0xffffffff00000000L)
-#define BN_MASK2h1 (0xffffffff80000000L)
-#define BN_TBIT (0x8000000000000000L)
-#define BN_DEC_CONV (10000000000000000000UL)
-#define BN_DEC_FMT1 "%lu"
-#define BN_DEC_FMT2 "%019lu"
-#define BN_DEC_NUM 19
-#define BN_HEX_FMT1 "%lX"
-#define BN_HEX_FMT2 "%016lX"
-#endif
-
-/* This is where the long long data type is 64 bits, but long is 32.
- * For machines where there are 64bit registers, this is the mode to use.
- * IRIX, on R4000 and above should use this mode, along with the relevant
- * assembler code :-). Do NOT define BN_LLONG.
- */
-#ifdef SIXTY_FOUR_BIT
-#undef BN_LLONG
-#undef BN_ULLONG
-#define BN_ULONG unsigned long long
-#define BN_LONG long long
-#define BN_BITS 128
-#define BN_BYTES 8
-#define BN_BITS2 64
-#define BN_BITS4 32
-#define BN_MASK2 (0xffffffffffffffffLL)
-#define BN_MASK2l (0xffffffffL)
-#define BN_MASK2h (0xffffffff00000000LL)
-#define BN_MASK2h1 (0xffffffff80000000LL)
-#define BN_TBIT (0x8000000000000000LL)
-#define BN_DEC_CONV (10000000000000000000ULL)
-#define BN_DEC_FMT1 "%llu"
-#define BN_DEC_FMT2 "%019llu"
-#define BN_DEC_NUM 19
-#define BN_HEX_FMT1 "%llX"
-#define BN_HEX_FMT2 "%016llX"
-#endif
-
-#ifdef THIRTY_TWO_BIT
-#ifdef BN_LLONG
-# if defined(_WIN32) && !defined(__GNUC__)
-# define BN_ULLONG unsigned __int64
-# define BN_MASK (0xffffffffffffffffI64)
-# else
-# define BN_ULLONG unsigned long long
-# define BN_MASK (0xffffffffffffffffLL)
-# endif
-#endif
-#define BN_ULONG unsigned int
-#define BN_LONG int
-#define BN_BITS 64
-#define BN_BYTES 4
-#define BN_BITS2 32
-#define BN_BITS4 16
-#define BN_MASK2 (0xffffffffL)
-#define BN_MASK2l (0xffff)
-#define BN_MASK2h1 (0xffff8000L)
-#define BN_MASK2h (0xffff0000L)
-#define BN_TBIT (0x80000000L)
-#define BN_DEC_CONV (1000000000L)
-#define BN_DEC_FMT1 "%u"
-#define BN_DEC_FMT2 "%09u"
-#define BN_DEC_NUM 9
-#define BN_HEX_FMT1 "%X"
-#define BN_HEX_FMT2 "%08X"
-#endif
-
-/* 2011-02-22 SMS.
- * In various places, a size_t variable or a type cast to size_t was
- * used to perform integer-only operations on pointers. This failed on
- * VMS with 64-bit pointers (CC /POINTER_SIZE = 64) because size_t is
- * still only 32 bits. What's needed in these cases is an integer type
- * with the same size as a pointer, which size_t is not certain to be.
- * The only fix here is VMS-specific.
- */
-#if defined(OPENSSL_SYS_VMS)
-# if __INITIAL_POINTER_SIZE == 64
-# define PTR_SIZE_INT long long
-# else /* __INITIAL_POINTER_SIZE == 64 */
-# define PTR_SIZE_INT int
-# endif /* __INITIAL_POINTER_SIZE == 64 [else] */
-#else /* defined(OPENSSL_SYS_VMS) */
-# define PTR_SIZE_INT size_t
-#endif /* defined(OPENSSL_SYS_VMS) [else] */
-
-#define BN_DEFAULT_BITS 1280
-
-#define BN_FLG_MALLOCED 0x01
-#define BN_FLG_STATIC_DATA 0x02
-#define BN_FLG_CONSTTIME 0x04 /* avoid leaking exponent information through timing,
- * BN_mod_exp_mont() will call BN_mod_exp_mont_consttime,
- * BN_div() will call BN_div_no_branch,
- * BN_mod_inverse() will call BN_mod_inverse_no_branch.
- */
-
-#ifndef OPENSSL_NO_DEPRECATED
-#define BN_FLG_EXP_CONSTTIME BN_FLG_CONSTTIME /* deprecated name for the flag */
- /* avoid leaking exponent information through timings
- * (BN_mod_exp_mont() will call BN_mod_exp_mont_consttime) */
-#endif
-
-#ifndef OPENSSL_NO_DEPRECATED
-#define BN_FLG_FREE 0x8000 /* used for debuging */
-#endif
-#define BN_set_flags(b,n) ((b)->flags|=(n))
-#define BN_get_flags(b,n) ((b)->flags&(n))
-
-/* get a clone of a BIGNUM with changed flags, for *temporary* use only
- * (the two BIGNUMs cannot not be used in parallel!) */
-#define BN_with_flags(dest,b,n) ((dest)->d=(b)->d, \
- (dest)->top=(b)->top, \
- (dest)->dmax=(b)->dmax, \
- (dest)->neg=(b)->neg, \
- (dest)->flags=(((dest)->flags & BN_FLG_MALLOCED) \
- | ((b)->flags & ~BN_FLG_MALLOCED) \
- | BN_FLG_STATIC_DATA \
- | (n)))
-
-/* Already declared in ossl_typ.h */
-#if 0
-typedef struct bignum_st BIGNUM;
-/* Used for temp variables (declaration hidden in bn_lcl.h) */
-typedef struct bignum_ctx BN_CTX;
-typedef struct bn_blinding_st BN_BLINDING;
-typedef struct bn_mont_ctx_st BN_MONT_CTX;
-typedef struct bn_recp_ctx_st BN_RECP_CTX;
-typedef struct bn_gencb_st BN_GENCB;
-#endif
-
-struct bignum_st
- {
- BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks. */
- int top; /* Index of last used d +1. */
- /* The next are internal book keeping for bn_expand. */
- int dmax; /* Size of the d array. */
- int neg; /* one if the number is negative */
- int flags;
- };
-
-/* Used for montgomery multiplication */
-struct bn_mont_ctx_st
- {
- int ri; /* number of bits in R */
- BIGNUM RR; /* used to convert to montgomery form */
- BIGNUM N; /* The modulus */
- BIGNUM Ni; /* R*(1/R mod N) - N*Ni = 1
- * (Ni is only stored for bignum algorithm) */
- BN_ULONG n0[2];/* least significant word(s) of Ni;
- (type changed with 0.9.9, was "BN_ULONG n0;" before) */
- int flags;
- };
-
-/* Used for reciprocal division/mod functions
- * It cannot be shared between threads
- */
-struct bn_recp_ctx_st
- {
- BIGNUM N; /* the divisor */
- BIGNUM Nr; /* the reciprocal */
- int num_bits;
- int shift;
- int flags;
- };
-
-/* Used for slow "generation" functions. */
-struct bn_gencb_st
- {
- unsigned int ver; /* To handle binary (in)compatibility */
- void *arg; /* callback-specific data */
- union
- {
- /* if(ver==1) - handles old style callbacks */
- void (*cb_1)(int, int, void *);
- /* if(ver==2) - new callback style */
- int (*cb_2)(int, int, BN_GENCB *);
- } cb;
- };
-/* Wrapper function to make using BN_GENCB easier, */
-int BN_GENCB_call(BN_GENCB *cb, int a, int b);
-/* Macro to populate a BN_GENCB structure with an "old"-style callback */
-#define BN_GENCB_set_old(gencb, callback, cb_arg) { \
- BN_GENCB *tmp_gencb = (gencb); \
- tmp_gencb->ver = 1; \
- tmp_gencb->arg = (cb_arg); \
- tmp_gencb->cb.cb_1 = (callback); }
-/* Macro to populate a BN_GENCB structure with a "new"-style callback */
-#define BN_GENCB_set(gencb, callback, cb_arg) { \
- BN_GENCB *tmp_gencb = (gencb); \
- tmp_gencb->ver = 2; \
- tmp_gencb->arg = (cb_arg); \
- tmp_gencb->cb.cb_2 = (callback); }
-
-#define BN_prime_checks 0 /* default: select number of iterations
- based on the size of the number */
-
-/* number of Miller-Rabin iterations for an error rate of less than 2^-80
- * for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook
- * of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996];
- * original paper: Damgaard, Landrock, Pomerance: Average case error estimates
- * for the strong probable prime test. -- Math. Comp. 61 (1993) 177-194) */
-#define BN_prime_checks_for_size(b) ((b) >= 1300 ? 2 : \
- (b) >= 850 ? 3 : \
- (b) >= 650 ? 4 : \
- (b) >= 550 ? 5 : \
- (b) >= 450 ? 6 : \
- (b) >= 400 ? 7 : \
- (b) >= 350 ? 8 : \
- (b) >= 300 ? 9 : \
- (b) >= 250 ? 12 : \
- (b) >= 200 ? 15 : \
- (b) >= 150 ? 18 : \
- /* b >= 100 */ 27)
-
-#define BN_num_bytes(a) ((BN_num_bits(a)+7)/8)
-
-/* Note that BN_abs_is_word didn't work reliably for w == 0 until 0.9.8 */
-#define BN_abs_is_word(a,w) ((((a)->top == 1) && ((a)->d[0] == (BN_ULONG)(w))) || \
- (((w) == 0) && ((a)->top == 0)))
-#define BN_is_zero(a) ((a)->top == 0)
-#define BN_is_one(a) (BN_abs_is_word((a),1) && !(a)->neg)
-#define BN_is_word(a,w) (BN_abs_is_word((a),(w)) && (!(w) || !(a)->neg))
-#define BN_is_odd(a) (((a)->top > 0) && ((a)->d[0] & 1))
-
-#define BN_one(a) (BN_set_word((a),1))
-#define BN_zero_ex(a) \
- do { \
- BIGNUM *_tmp_bn = (a); \
- _tmp_bn->top = 0; \
- _tmp_bn->neg = 0; \
- } while(0)
-#ifdef OPENSSL_NO_DEPRECATED
-#define BN_zero(a) BN_zero_ex(a)
-#else
-#define BN_zero(a) (BN_set_word((a),0))
-#endif
-
-const BIGNUM *BN_value_one(void);
-char * BN_options(void);
-BN_CTX *BN_CTX_new(void);
-#ifndef OPENSSL_NO_DEPRECATED
-void BN_CTX_init(BN_CTX *c);
-#endif
-void BN_CTX_free(BN_CTX *c);
-void BN_CTX_start(BN_CTX *ctx);
-BIGNUM *BN_CTX_get(BN_CTX *ctx);
-void BN_CTX_end(BN_CTX *ctx);
-int BN_rand(BIGNUM *rnd, int bits, int top,int bottom);
-int BN_pseudo_rand(BIGNUM *rnd, int bits, int top,int bottom);
-int BN_rand_range(BIGNUM *rnd, const BIGNUM *range);
-int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range);
-int BN_num_bits(const BIGNUM *a);
-int BN_num_bits_word(BN_ULONG);
-BIGNUM *BN_new(void);
-void BN_init(BIGNUM *);
-void BN_clear_free(BIGNUM *a);
-BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b);
-void BN_swap(BIGNUM *a, BIGNUM *b);
-BIGNUM *BN_bin2bn(const unsigned char *s,int len,BIGNUM *ret);
-int BN_bn2bin(const BIGNUM *a, unsigned char *to);
-BIGNUM *BN_mpi2bn(const unsigned char *s,int len,BIGNUM *ret);
-int BN_bn2mpi(const BIGNUM *a, unsigned char *to);
-int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
-int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
-int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
-int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
-int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
-int BN_sqr(BIGNUM *r, const BIGNUM *a,BN_CTX *ctx);
-/** BN_set_negative sets sign of a BIGNUM
- * \param b pointer to the BIGNUM object
- * \param n 0 if the BIGNUM b should be positive and a value != 0 otherwise
- */
-void BN_set_negative(BIGNUM *b, int n);
-/** BN_is_negative returns 1 if the BIGNUM is negative
- * \param a pointer to the BIGNUM object
- * \return 1 if a < 0 and 0 otherwise
- */
-#define BN_is_negative(a) ((a)->neg != 0)
-
-int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
- BN_CTX *ctx);
-#define BN_mod(rem,m,d,ctx) BN_div(NULL,(rem),(m),(d),(ctx))
-int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx);
-int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
-int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m);
-int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
-int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m);
-int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- const BIGNUM *m, BN_CTX *ctx);
-int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
-int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
-int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m);
-int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m, BN_CTX *ctx);
-int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m);
-
-BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w);
-BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w);
-int BN_mul_word(BIGNUM *a, BN_ULONG w);
-int BN_add_word(BIGNUM *a, BN_ULONG w);
-int BN_sub_word(BIGNUM *a, BN_ULONG w);
-int BN_set_word(BIGNUM *a, BN_ULONG w);
-BN_ULONG BN_get_word(const BIGNUM *a);
-
-int BN_cmp(const BIGNUM *a, const BIGNUM *b);
-void BN_free(BIGNUM *a);
-int BN_is_bit_set(const BIGNUM *a, int n);
-int BN_lshift(BIGNUM *r, const BIGNUM *a, int n);
-int BN_lshift1(BIGNUM *r, const BIGNUM *a);
-int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,BN_CTX *ctx);
-
-int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m,BN_CTX *ctx);
-int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
-int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont);
-int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
-int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1,
- const BIGNUM *a2, const BIGNUM *p2,const BIGNUM *m,
- BN_CTX *ctx,BN_MONT_CTX *m_ctx);
-int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m,BN_CTX *ctx);
-
-int BN_mask_bits(BIGNUM *a,int n);
-#ifndef OPENSSL_NO_FP_API
-int BN_print_fp(FILE *fp, const BIGNUM *a);
-#endif
-#ifdef HEADER_BIO_H
-int BN_print(BIO *fp, const BIGNUM *a);
-#else
-int BN_print(void *fp, const BIGNUM *a);
-#endif
-int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx);
-int BN_rshift(BIGNUM *r, const BIGNUM *a, int n);
-int BN_rshift1(BIGNUM *r, const BIGNUM *a);
-void BN_clear(BIGNUM *a);
-BIGNUM *BN_dup(const BIGNUM *a);
-int BN_ucmp(const BIGNUM *a, const BIGNUM *b);
-int BN_set_bit(BIGNUM *a, int n);
-int BN_clear_bit(BIGNUM *a, int n);
-char * BN_bn2hex(const BIGNUM *a);
-char * BN_bn2dec(const BIGNUM *a);
-int BN_hex2bn(BIGNUM **a, const char *str);
-int BN_dec2bn(BIGNUM **a, const char *str);
-int BN_asc2bn(BIGNUM **a, const char *str);
-int BN_gcd(BIGNUM *r,const BIGNUM *a,const BIGNUM *b,BN_CTX *ctx);
-int BN_kronecker(const BIGNUM *a,const BIGNUM *b,BN_CTX *ctx); /* returns -2 for error */
-BIGNUM *BN_mod_inverse(BIGNUM *ret,
- const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
-BIGNUM *BN_mod_sqrt(BIGNUM *ret,
- const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
-
-void BN_consttime_swap(BN_ULONG swap, BIGNUM *a, BIGNUM *b, int nwords);
-
-/* Deprecated versions */
-#ifndef OPENSSL_NO_DEPRECATED
-BIGNUM *BN_generate_prime(BIGNUM *ret,int bits,int safe,
- const BIGNUM *add, const BIGNUM *rem,
- void (*callback)(int,int,void *),void *cb_arg);
-int BN_is_prime(const BIGNUM *p,int nchecks,
- void (*callback)(int,int,void *),
- BN_CTX *ctx,void *cb_arg);
-int BN_is_prime_fasttest(const BIGNUM *p,int nchecks,
- void (*callback)(int,int,void *),BN_CTX *ctx,void *cb_arg,
- int do_trial_division);
-#endif /* !defined(OPENSSL_NO_DEPRECATED) */
-
-/* Newer versions */
-int BN_generate_prime_ex(BIGNUM *ret,int bits,int safe, const BIGNUM *add,
- const BIGNUM *rem, BN_GENCB *cb);
-int BN_is_prime_ex(const BIGNUM *p,int nchecks, BN_CTX *ctx, BN_GENCB *cb);
-int BN_is_prime_fasttest_ex(const BIGNUM *p,int nchecks, BN_CTX *ctx,
- int do_trial_division, BN_GENCB *cb);
-
-int BN_X931_generate_Xpq(BIGNUM *Xp, BIGNUM *Xq, int nbits, BN_CTX *ctx);
-
-int BN_X931_derive_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
- const BIGNUM *Xp, const BIGNUM *Xp1, const BIGNUM *Xp2,
- const BIGNUM *e, BN_CTX *ctx, BN_GENCB *cb);
-int BN_X931_generate_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
- BIGNUM *Xp1, BIGNUM *Xp2,
- const BIGNUM *Xp,
- const BIGNUM *e, BN_CTX *ctx,
- BN_GENCB *cb);
-
-BN_MONT_CTX *BN_MONT_CTX_new(void );
-void BN_MONT_CTX_init(BN_MONT_CTX *ctx);
-int BN_mod_mul_montgomery(BIGNUM *r,const BIGNUM *a,const BIGNUM *b,
- BN_MONT_CTX *mont, BN_CTX *ctx);
-#define BN_to_montgomery(r,a,mont,ctx) BN_mod_mul_montgomery(\
- (r),(a),&((mont)->RR),(mont),(ctx))
-int BN_from_montgomery(BIGNUM *r,const BIGNUM *a,
- BN_MONT_CTX *mont, BN_CTX *ctx);
-void BN_MONT_CTX_free(BN_MONT_CTX *mont);
-int BN_MONT_CTX_set(BN_MONT_CTX *mont,const BIGNUM *mod,BN_CTX *ctx);
-BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to,BN_MONT_CTX *from);
-BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
- const BIGNUM *mod, BN_CTX *ctx);
-
-/* BN_BLINDING flags */
-#define BN_BLINDING_NO_UPDATE 0x00000001
-#define BN_BLINDING_NO_RECREATE 0x00000002
-
-BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod);
-void BN_BLINDING_free(BN_BLINDING *b);
-int BN_BLINDING_update(BN_BLINDING *b,BN_CTX *ctx);
-int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
-int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
-int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *);
-int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *);
-#ifndef OPENSSL_NO_DEPRECATED
-unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *);
-void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long);
-#endif
-CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *);
-unsigned long BN_BLINDING_get_flags(const BN_BLINDING *);
-void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long);
-BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
- const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
- int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx),
- BN_MONT_CTX *m_ctx);
-
-#ifndef OPENSSL_NO_DEPRECATED
-void BN_set_params(int mul,int high,int low,int mont);
-int BN_get_params(int which); /* 0, mul, 1 high, 2 low, 3 mont */
-#endif
-
-void BN_RECP_CTX_init(BN_RECP_CTX *recp);
-BN_RECP_CTX *BN_RECP_CTX_new(void);
-void BN_RECP_CTX_free(BN_RECP_CTX *recp);
-int BN_RECP_CTX_set(BN_RECP_CTX *recp,const BIGNUM *rdiv,BN_CTX *ctx);
-int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y,
- BN_RECP_CTX *recp,BN_CTX *ctx);
-int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx);
-int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m,
- BN_RECP_CTX *recp, BN_CTX *ctx);
-
-#ifndef OPENSSL_NO_EC2M
-
-/* Functions for arithmetic over binary polynomials represented by BIGNUMs.
- *
- * The BIGNUM::neg property of BIGNUMs representing binary polynomials is
- * ignored.
- *
- * Note that input arguments are not const so that their bit arrays can
- * be expanded to the appropriate size if needed.
- */
-
-int BN_GF2m_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); /*r = a + b*/
-#define BN_GF2m_sub(r, a, b) BN_GF2m_add(r, a, b)
-int BN_GF2m_mod(BIGNUM *r, const BIGNUM *a, const BIGNUM *p); /*r=a mod p*/
-int BN_GF2m_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- const BIGNUM *p, BN_CTX *ctx); /* r = (a * b) mod p */
-int BN_GF2m_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- BN_CTX *ctx); /* r = (a * a) mod p */
-int BN_GF2m_mod_inv(BIGNUM *r, const BIGNUM *b, const BIGNUM *p,
- BN_CTX *ctx); /* r = (1 / b) mod p */
-int BN_GF2m_mod_div(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- const BIGNUM *p, BN_CTX *ctx); /* r = (a / b) mod p */
-int BN_GF2m_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- const BIGNUM *p, BN_CTX *ctx); /* r = (a ^ b) mod p */
-int BN_GF2m_mod_sqrt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- BN_CTX *ctx); /* r = sqrt(a) mod p */
-int BN_GF2m_mod_solve_quad(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- BN_CTX *ctx); /* r^2 + r = a mod p */
-#define BN_GF2m_cmp(a, b) BN_ucmp((a), (b))
-/* Some functions allow for representation of the irreducible polynomials
- * as an unsigned int[], say p. The irreducible f(t) is then of the form:
- * t^p[0] + t^p[1] + ... + t^p[k]
- * where m = p[0] > p[1] > ... > p[k] = 0.
- */
-int BN_GF2m_mod_arr(BIGNUM *r, const BIGNUM *a, const int p[]);
- /* r = a mod p */
-int BN_GF2m_mod_mul_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- const int p[], BN_CTX *ctx); /* r = (a * b) mod p */
-int BN_GF2m_mod_sqr_arr(BIGNUM *r, const BIGNUM *a, const int p[],
- BN_CTX *ctx); /* r = (a * a) mod p */
-int BN_GF2m_mod_inv_arr(BIGNUM *r, const BIGNUM *b, const int p[],
- BN_CTX *ctx); /* r = (1 / b) mod p */
-int BN_GF2m_mod_div_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- const int p[], BN_CTX *ctx); /* r = (a / b) mod p */
-int BN_GF2m_mod_exp_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- const int p[], BN_CTX *ctx); /* r = (a ^ b) mod p */
-int BN_GF2m_mod_sqrt_arr(BIGNUM *r, const BIGNUM *a,
- const int p[], BN_CTX *ctx); /* r = sqrt(a) mod p */
-int BN_GF2m_mod_solve_quad_arr(BIGNUM *r, const BIGNUM *a,
- const int p[], BN_CTX *ctx); /* r^2 + r = a mod p */
-int BN_GF2m_poly2arr(const BIGNUM *a, int p[], int max);
-int BN_GF2m_arr2poly(const int p[], BIGNUM *a);
-
-#endif
-
-/* faster mod functions for the 'NIST primes'
- * 0 <= a < p^2 */
-int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
-int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
-int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
-int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
-int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
-
-const BIGNUM *BN_get0_nist_prime_192(void);
-const BIGNUM *BN_get0_nist_prime_224(void);
-const BIGNUM *BN_get0_nist_prime_256(void);
-const BIGNUM *BN_get0_nist_prime_384(void);
-const BIGNUM *BN_get0_nist_prime_521(void);
-
-/* library internal functions */
-
-#define bn_expand(a,bits) ((((((bits+BN_BITS2-1))/BN_BITS2)) <= (a)->dmax)?\
- (a):bn_expand2((a),(bits+BN_BITS2-1)/BN_BITS2))
-#define bn_wexpand(a,words) (((words) <= (a)->dmax)?(a):bn_expand2((a),(words)))
-BIGNUM *bn_expand2(BIGNUM *a, int words);
-#ifndef OPENSSL_NO_DEPRECATED
-BIGNUM *bn_dup_expand(const BIGNUM *a, int words); /* unused */
-#endif
-
-/* Bignum consistency macros
- * There is one "API" macro, bn_fix_top(), for stripping leading zeroes from
- * bignum data after direct manipulations on the data. There is also an
- * "internal" macro, bn_check_top(), for verifying that there are no leading
- * zeroes. Unfortunately, some auditing is required due to the fact that
- * bn_fix_top() has become an overabused duct-tape because bignum data is
- * occasionally passed around in an inconsistent state. So the following
- * changes have been made to sort this out;
- * - bn_fix_top()s implementation has been moved to bn_correct_top()
- * - if BN_DEBUG isn't defined, bn_fix_top() maps to bn_correct_top(), and
- * bn_check_top() is as before.
- * - if BN_DEBUG *is* defined;
- * - bn_check_top() tries to pollute unused words even if the bignum 'top' is
- * consistent. (ed: only if BN_DEBUG_RAND is defined)
- * - bn_fix_top() maps to bn_check_top() rather than "fixing" anything.
- * The idea is to have debug builds flag up inconsistent bignums when they
- * occur. If that occurs in a bn_fix_top(), we examine the code in question; if
- * the use of bn_fix_top() was appropriate (ie. it follows directly after code
- * that manipulates the bignum) it is converted to bn_correct_top(), and if it
- * was not appropriate, we convert it permanently to bn_check_top() and track
- * down the cause of the bug. Eventually, no internal code should be using the
- * bn_fix_top() macro. External applications and libraries should try this with
- * their own code too, both in terms of building against the openssl headers
- * with BN_DEBUG defined *and* linking with a version of OpenSSL built with it
- * defined. This not only improves external code, it provides more test
- * coverage for openssl's own code.
- */
-
-#ifdef BN_DEBUG
-
-/* We only need assert() when debugging */
-#include <assert.h>
-
-#ifdef BN_DEBUG_RAND
-/* To avoid "make update" cvs wars due to BN_DEBUG, use some tricks */
-#ifndef RAND_pseudo_bytes
-int RAND_pseudo_bytes(unsigned char *buf,int num);
-#define BN_DEBUG_TRIX
-#endif
-#define bn_pollute(a) \
- do { \
- const BIGNUM *_bnum1 = (a); \
- if(_bnum1->top < _bnum1->dmax) { \
- unsigned char _tmp_char; \
- /* We cast away const without the compiler knowing, any \
- * *genuinely* constant variables that aren't mutable \
- * wouldn't be constructed with top!=dmax. */ \
- BN_ULONG *_not_const; \
- memcpy(&_not_const, &_bnum1->d, sizeof(BN_ULONG*)); \
- RAND_pseudo_bytes(&_tmp_char, 1); \
- memset((unsigned char *)(_not_const + _bnum1->top), _tmp_char, \
- (_bnum1->dmax - _bnum1->top) * sizeof(BN_ULONG)); \
- } \
- } while(0)
-#ifdef BN_DEBUG_TRIX
-#undef RAND_pseudo_bytes
-#endif
-#else
-#define bn_pollute(a)
-#endif
-#define bn_check_top(a) \
- do { \
- const BIGNUM *_bnum2 = (a); \
- if (_bnum2 != NULL) { \
- assert((_bnum2->top == 0) || \
- (_bnum2->d[_bnum2->top - 1] != 0)); \
- bn_pollute(_bnum2); \
- } \
- } while(0)
-
-#define bn_fix_top(a) bn_check_top(a)
-
-#define bn_check_size(bn, bits) bn_wcheck_size(bn, ((bits+BN_BITS2-1))/BN_BITS2)
-#define bn_wcheck_size(bn, words) \
- do { \
- const BIGNUM *_bnum2 = (bn); \
- assert(words <= (_bnum2)->dmax && words >= (_bnum2)->top); \
- } while(0)
-
-#else /* !BN_DEBUG */
-
-#define bn_pollute(a)
-#define bn_check_top(a)
-#define bn_fix_top(a) bn_correct_top(a)
-#define bn_check_size(bn, bits)
-#define bn_wcheck_size(bn, words)
-
-#endif
-
-#define bn_correct_top(a) \
- { \
- BN_ULONG *ftl; \
- int tmp_top = (a)->top; \
- if (tmp_top > 0) \
- { \
- for (ftl= &((a)->d[tmp_top-1]); tmp_top > 0; tmp_top--) \
- if (*(ftl--)) break; \
- (a)->top = tmp_top; \
- } \
- bn_pollute(a); \
- }
-
-BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
-BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
-void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
-BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
-BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
-BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
-
-/* Primes from RFC 2409 */
-BIGNUM *get_rfc2409_prime_768(BIGNUM *bn);
-BIGNUM *get_rfc2409_prime_1024(BIGNUM *bn);
-
-/* Primes from RFC 3526 */
-BIGNUM *get_rfc3526_prime_1536(BIGNUM *bn);
-BIGNUM *get_rfc3526_prime_2048(BIGNUM *bn);
-BIGNUM *get_rfc3526_prime_3072(BIGNUM *bn);
-BIGNUM *get_rfc3526_prime_4096(BIGNUM *bn);
-BIGNUM *get_rfc3526_prime_6144(BIGNUM *bn);
-BIGNUM *get_rfc3526_prime_8192(BIGNUM *bn);
-
-int BN_bntest_rand(BIGNUM *rnd, int bits, int top,int bottom);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_BN_strings(void);
-
-/* Error codes for the BN functions. */
-
-/* Function codes. */
-#define BN_F_BNRAND 127
-#define BN_F_BN_BLINDING_CONVERT_EX 100
-#define BN_F_BN_BLINDING_CREATE_PARAM 128
-#define BN_F_BN_BLINDING_INVERT_EX 101
-#define BN_F_BN_BLINDING_NEW 102
-#define BN_F_BN_BLINDING_UPDATE 103
-#define BN_F_BN_BN2DEC 104
-#define BN_F_BN_BN2HEX 105
-#define BN_F_BN_CTX_GET 116
-#define BN_F_BN_CTX_NEW 106
-#define BN_F_BN_CTX_START 129
-#define BN_F_BN_DIV 107
-#define BN_F_BN_DIV_NO_BRANCH 138
-#define BN_F_BN_DIV_RECP 130
-#define BN_F_BN_EXP 123
-#define BN_F_BN_EXPAND2 108
-#define BN_F_BN_EXPAND_INTERNAL 120
-#define BN_F_BN_GF2M_MOD 131
-#define BN_F_BN_GF2M_MOD_EXP 132
-#define BN_F_BN_GF2M_MOD_MUL 133
-#define BN_F_BN_GF2M_MOD_SOLVE_QUAD 134
-#define BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR 135
-#define BN_F_BN_GF2M_MOD_SQR 136
-#define BN_F_BN_GF2M_MOD_SQRT 137
-#define BN_F_BN_MOD_EXP2_MONT 118
-#define BN_F_BN_MOD_EXP_MONT 109
-#define BN_F_BN_MOD_EXP_MONT_CONSTTIME 124
-#define BN_F_BN_MOD_EXP_MONT_WORD 117
-#define BN_F_BN_MOD_EXP_RECP 125
-#define BN_F_BN_MOD_EXP_SIMPLE 126
-#define BN_F_BN_MOD_INVERSE 110
-#define BN_F_BN_MOD_INVERSE_NO_BRANCH 139
-#define BN_F_BN_MOD_LSHIFT_QUICK 119
-#define BN_F_BN_MOD_MUL_RECIPROCAL 111
-#define BN_F_BN_MOD_SQRT 121
-#define BN_F_BN_MPI2BN 112
-#define BN_F_BN_NEW 113
-#define BN_F_BN_RAND 114
-#define BN_F_BN_RAND_RANGE 122
-#define BN_F_BN_USUB 115
-
-/* Reason codes. */
-#define BN_R_ARG2_LT_ARG3 100
-#define BN_R_BAD_RECIPROCAL 101
-#define BN_R_BIGNUM_TOO_LONG 114
-#define BN_R_CALLED_WITH_EVEN_MODULUS 102
-#define BN_R_DIV_BY_ZERO 103
-#define BN_R_ENCODING_ERROR 104
-#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA 105
-#define BN_R_INPUT_NOT_REDUCED 110
-#define BN_R_INVALID_LENGTH 106
-#define BN_R_INVALID_RANGE 115
-#define BN_R_NOT_A_SQUARE 111
-#define BN_R_NOT_INITIALIZED 107
-#define BN_R_NO_INVERSE 108
-#define BN_R_NO_SOLUTION 116
-#define BN_R_P_IS_NOT_PRIME 112
-#define BN_R_TOO_MANY_ITERATIONS 113
-#define BN_R_TOO_MANY_TEMPORARY_VARIABLES 109
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/buffer.h b/drivers/builtin_openssl/openssl/buffer.h
deleted file mode 100644
index f8da32b485..0000000000
--- a/drivers/builtin_openssl/openssl/buffer.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* crypto/buffer/buffer.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_BUFFER_H
-#define HEADER_BUFFER_H
-
-#include <openssl/ossl_typ.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stddef.h>
-
-#if !defined(NO_SYS_TYPES_H)
-#include <sys/types.h>
-#endif
-
-/* Already declared in ossl_typ.h */
-/* typedef struct buf_mem_st BUF_MEM; */
-
-struct buf_mem_st
- {
- size_t length; /* current number of bytes */
- char *data;
- size_t max; /* size of buffer */
- };
-
-BUF_MEM *BUF_MEM_new(void);
-void BUF_MEM_free(BUF_MEM *a);
-int BUF_MEM_grow(BUF_MEM *str, size_t len);
-int BUF_MEM_grow_clean(BUF_MEM *str, size_t len);
-char * BUF_strdup(const char *str);
-char * BUF_strndup(const char *str, size_t siz);
-void * BUF_memdup(const void *data, size_t siz);
-void BUF_reverse(unsigned char *out, const unsigned char *in, size_t siz);
-
-/* safe string functions */
-size_t BUF_strlcpy(char *dst,const char *src,size_t siz);
-size_t BUF_strlcat(char *dst,const char *src,size_t siz);
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_BUF_strings(void);
-
-/* Error codes for the BUF functions. */
-
-/* Function codes. */
-#define BUF_F_BUF_MEMDUP 103
-#define BUF_F_BUF_MEM_GROW 100
-#define BUF_F_BUF_MEM_GROW_CLEAN 105
-#define BUF_F_BUF_MEM_NEW 101
-#define BUF_F_BUF_STRDUP 102
-#define BUF_F_BUF_STRNDUP 104
-
-/* Reason codes. */
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/camellia.h b/drivers/builtin_openssl/openssl/camellia.h
deleted file mode 100644
index 67911e0adf..0000000000
--- a/drivers/builtin_openssl/openssl/camellia.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* crypto/camellia/camellia.h -*- mode:C; c-file-style: "eay" -*- */
-/* ====================================================================
- * Copyright (c) 2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 HEADER_CAMELLIA_H
-#define HEADER_CAMELLIA_H
-
-#include <openssl/opensslconf.h>
-
-#ifdef OPENSSL_NO_CAMELLIA
-#error CAMELLIA is disabled.
-#endif
-
-#include <stddef.h>
-
-#define CAMELLIA_ENCRYPT 1
-#define CAMELLIA_DECRYPT 0
-
-/* Because array size can't be a const in C, the following two are macros.
- Both sizes are in bytes. */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This should be a hidden type, but EVP requires that the size be known */
-
-#define CAMELLIA_BLOCK_SIZE 16
-#define CAMELLIA_TABLE_BYTE_LEN 272
-#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4)
-
-typedef unsigned int KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; /* to match with WORD */
-
-struct camellia_key_st
- {
- union {
- double d; /* ensures 64-bit align */
- KEY_TABLE_TYPE rd_key;
- } u;
- int grand_rounds;
- };
-typedef struct camellia_key_st CAMELLIA_KEY;
-
-#ifdef OPENSSL_FIPS
-int private_Camellia_set_key(const unsigned char *userKey, const int bits,
- CAMELLIA_KEY *key);
-#endif
-int Camellia_set_key(const unsigned char *userKey, const int bits,
- CAMELLIA_KEY *key);
-
-void Camellia_encrypt(const unsigned char *in, unsigned char *out,
- const CAMELLIA_KEY *key);
-void Camellia_decrypt(const unsigned char *in, unsigned char *out,
- const CAMELLIA_KEY *key);
-
-void Camellia_ecb_encrypt(const unsigned char *in, unsigned char *out,
- const CAMELLIA_KEY *key, const int enc);
-void Camellia_cbc_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const CAMELLIA_KEY *key,
- unsigned char *ivec, const int enc);
-void Camellia_cfb128_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const CAMELLIA_KEY *key,
- unsigned char *ivec, int *num, const int enc);
-void Camellia_cfb1_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const CAMELLIA_KEY *key,
- unsigned char *ivec, int *num, const int enc);
-void Camellia_cfb8_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const CAMELLIA_KEY *key,
- unsigned char *ivec, int *num, const int enc);
-void Camellia_ofb128_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const CAMELLIA_KEY *key,
- unsigned char *ivec, int *num);
-void Camellia_ctr128_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const CAMELLIA_KEY *key,
- unsigned char ivec[CAMELLIA_BLOCK_SIZE],
- unsigned char ecount_buf[CAMELLIA_BLOCK_SIZE],
- unsigned int *num);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !HEADER_Camellia_H */
diff --git a/drivers/builtin_openssl/openssl/cast.h b/drivers/builtin_openssl/openssl/cast.h
deleted file mode 100644
index 203922ea2b..0000000000
--- a/drivers/builtin_openssl/openssl/cast.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* crypto/cast/cast.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_CAST_H
-#define HEADER_CAST_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <openssl/opensslconf.h>
-
-#ifdef OPENSSL_NO_CAST
-#error CAST is disabled.
-#endif
-
-#define CAST_ENCRYPT 1
-#define CAST_DECRYPT 0
-
-#define CAST_LONG unsigned int
-
-#define CAST_BLOCK 8
-#define CAST_KEY_LENGTH 16
-
-typedef struct cast_key_st
- {
- CAST_LONG data[32];
- int short_key; /* Use reduced rounds for short key */
- } CAST_KEY;
-
-#ifdef OPENSSL_FIPS
-void private_CAST_set_key(CAST_KEY *key, int len, const unsigned char *data);
-#endif
-void CAST_set_key(CAST_KEY *key, int len, const unsigned char *data);
-void CAST_ecb_encrypt(const unsigned char *in, unsigned char *out, const CAST_KEY *key,
- int enc);
-void CAST_encrypt(CAST_LONG *data, const CAST_KEY *key);
-void CAST_decrypt(CAST_LONG *data, const CAST_KEY *key);
-void CAST_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
- const CAST_KEY *ks, unsigned char *iv, int enc);
-void CAST_cfb64_encrypt(const unsigned char *in, unsigned char *out,
- long length, const CAST_KEY *schedule, unsigned char *ivec,
- int *num, int enc);
-void CAST_ofb64_encrypt(const unsigned char *in, unsigned char *out,
- long length, const CAST_KEY *schedule, unsigned char *ivec,
- int *num);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/cmac.h b/drivers/builtin_openssl/openssl/cmac.h
deleted file mode 100644
index 712e92dced..0000000000
--- a/drivers/builtin_openssl/openssl/cmac.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* crypto/cmac/cmac.h */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project.
- */
-/* ====================================================================
- * Copyright (c) 2010 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 HEADER_CMAC_H
-#define HEADER_CMAC_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <openssl/evp.h>
-
-/* Opaque */
-typedef struct CMAC_CTX_st CMAC_CTX;
-
-CMAC_CTX *CMAC_CTX_new(void);
-void CMAC_CTX_cleanup(CMAC_CTX *ctx);
-void CMAC_CTX_free(CMAC_CTX *ctx);
-EVP_CIPHER_CTX *CMAC_CTX_get0_cipher_ctx(CMAC_CTX *ctx);
-int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in);
-
-int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
- const EVP_CIPHER *cipher, ENGINE *impl);
-int CMAC_Update(CMAC_CTX *ctx, const void *data, size_t dlen);
-int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen);
-int CMAC_resume(CMAC_CTX *ctx);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/cms.h b/drivers/builtin_openssl/openssl/cms.h
deleted file mode 100644
index 36994fa6a2..0000000000
--- a/drivers/builtin_openssl/openssl/cms.h
+++ /dev/null
@@ -1,501 +0,0 @@
-/* crypto/cms/cms.h */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project.
- */
-/* ====================================================================
- * Copyright (c) 2008 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 HEADER_CMS_H
-#define HEADER_CMS_H
-
-#include <openssl/x509.h>
-
-#ifdef OPENSSL_NO_CMS
-#error CMS is disabled.
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-typedef struct CMS_ContentInfo_st CMS_ContentInfo;
-typedef struct CMS_SignerInfo_st CMS_SignerInfo;
-typedef struct CMS_CertificateChoices CMS_CertificateChoices;
-typedef struct CMS_RevocationInfoChoice_st CMS_RevocationInfoChoice;
-typedef struct CMS_RecipientInfo_st CMS_RecipientInfo;
-typedef struct CMS_ReceiptRequest_st CMS_ReceiptRequest;
-typedef struct CMS_Receipt_st CMS_Receipt;
-
-DECLARE_STACK_OF(CMS_SignerInfo)
-DECLARE_STACK_OF(GENERAL_NAMES)
-DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)
-DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest)
-DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
-
-#define CMS_SIGNERINFO_ISSUER_SERIAL 0
-#define CMS_SIGNERINFO_KEYIDENTIFIER 1
-
-#define CMS_RECIPINFO_TRANS 0
-#define CMS_RECIPINFO_AGREE 1
-#define CMS_RECIPINFO_KEK 2
-#define CMS_RECIPINFO_PASS 3
-#define CMS_RECIPINFO_OTHER 4
-
-/* S/MIME related flags */
-
-#define CMS_TEXT 0x1
-#define CMS_NOCERTS 0x2
-#define CMS_NO_CONTENT_VERIFY 0x4
-#define CMS_NO_ATTR_VERIFY 0x8
-#define CMS_NOSIGS \
- (CMS_NO_CONTENT_VERIFY|CMS_NO_ATTR_VERIFY)
-#define CMS_NOINTERN 0x10
-#define CMS_NO_SIGNER_CERT_VERIFY 0x20
-#define CMS_NOVERIFY 0x20
-#define CMS_DETACHED 0x40
-#define CMS_BINARY 0x80
-#define CMS_NOATTR 0x100
-#define CMS_NOSMIMECAP 0x200
-#define CMS_NOOLDMIMETYPE 0x400
-#define CMS_CRLFEOL 0x800
-#define CMS_STREAM 0x1000
-#define CMS_NOCRL 0x2000
-#define CMS_PARTIAL 0x4000
-#define CMS_REUSE_DIGEST 0x8000
-#define CMS_USE_KEYID 0x10000
-#define CMS_DEBUG_DECRYPT 0x20000
-
-const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms);
-
-BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont);
-int CMS_dataFinal(CMS_ContentInfo *cms, BIO *bio);
-
-ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms);
-int CMS_is_detached(CMS_ContentInfo *cms);
-int CMS_set_detached(CMS_ContentInfo *cms, int detached);
-
-#ifdef HEADER_PEM_H
-DECLARE_PEM_rw_const(CMS, CMS_ContentInfo)
-#endif
-
-int CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms);
-CMS_ContentInfo *d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms);
-int i2d_CMS_bio(BIO *bp, CMS_ContentInfo *cms);
-
-BIO *BIO_new_CMS(BIO *out, CMS_ContentInfo *cms);
-int i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags);
-int PEM_write_bio_CMS_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags);
-CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont);
-int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags);
-
-int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags);
-
-CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
- BIO *data, unsigned int flags);
-
-CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
- X509 *signcert, EVP_PKEY *pkey,
- STACK_OF(X509) *certs,
- unsigned int flags);
-
-int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags);
-CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags);
-
-int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
- unsigned int flags);
-CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
- unsigned int flags);
-
-int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
- const unsigned char *key, size_t keylen,
- BIO *dcont, BIO *out, unsigned int flags);
-
-CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
- const unsigned char *key, size_t keylen,
- unsigned int flags);
-
-int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
- const unsigned char *key, size_t keylen);
-
-int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
- X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags);
-
-int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
- STACK_OF(X509) *certs,
- X509_STORE *store, unsigned int flags);
-
-STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms);
-
-CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
- const EVP_CIPHER *cipher, unsigned int flags);
-
-int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert,
- BIO *dcont, BIO *out,
- unsigned int flags);
-
-int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert);
-int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
- unsigned char *key, size_t keylen,
- unsigned char *id, size_t idlen);
-int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
- unsigned char *pass, ossl_ssize_t passlen);
-
-STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms);
-int CMS_RecipientInfo_type(CMS_RecipientInfo *ri);
-CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
-CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
- X509 *recip, unsigned int flags);
-int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey);
-int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert);
-int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
- EVP_PKEY **pk, X509 **recip,
- X509_ALGOR **palg);
-int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
- ASN1_OCTET_STRING **keyid,
- X509_NAME **issuer, ASN1_INTEGER **sno);
-
-CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
- unsigned char *key, size_t keylen,
- unsigned char *id, size_t idlen,
- ASN1_GENERALIZEDTIME *date,
- ASN1_OBJECT *otherTypeId,
- ASN1_TYPE *otherType);
-
-int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
- X509_ALGOR **palg,
- ASN1_OCTET_STRING **pid,
- ASN1_GENERALIZEDTIME **pdate,
- ASN1_OBJECT **potherid,
- ASN1_TYPE **pothertype);
-
-int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
- unsigned char *key, size_t keylen);
-
-int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri,
- const unsigned char *id, size_t idlen);
-
-int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
- unsigned char *pass,
- ossl_ssize_t passlen);
-
-CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
- int iter, int wrap_nid, int pbe_nid,
- unsigned char *pass,
- ossl_ssize_t passlen,
- const EVP_CIPHER *kekciph);
-
-int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
-
-int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
- unsigned int flags);
-CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags);
-
-int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid);
-const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms);
-
-CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms);
-int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert);
-int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert);
-STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms);
-
-CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms);
-int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl);
-int CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl);
-STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms);
-
-int CMS_SignedData_init(CMS_ContentInfo *cms);
-CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
- X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
- unsigned int flags);
-STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms);
-
-void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer);
-int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si,
- ASN1_OCTET_STRING **keyid,
- X509_NAME **issuer, ASN1_INTEGER **sno);
-int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert);
-int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
- unsigned int flags);
-void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, X509 **signer,
- X509_ALGOR **pdig, X509_ALGOR **psig);
-int CMS_SignerInfo_sign(CMS_SignerInfo *si);
-int CMS_SignerInfo_verify(CMS_SignerInfo *si);
-int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain);
-
-int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs);
-int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs,
- int algnid, int keysize);
-int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap);
-
-int CMS_signed_get_attr_count(const CMS_SignerInfo *si);
-int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid,
- int lastpos);
-int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj,
- int lastpos);
-X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc);
-X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc);
-int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr);
-int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si,
- const ASN1_OBJECT *obj, int type,
- const void *bytes, int len);
-int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si,
- int nid, int type,
- const void *bytes, int len);
-int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si,
- const char *attrname, int type,
- const void *bytes, int len);
-void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
- int lastpos, int type);
-
-int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si);
-int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid,
- int lastpos);
-int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj,
- int lastpos);
-X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc);
-X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc);
-int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr);
-int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si,
- const ASN1_OBJECT *obj, int type,
- const void *bytes, int len);
-int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si,
- int nid, int type,
- const void *bytes, int len);
-int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si,
- const char *attrname, int type,
- const void *bytes, int len);
-void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
- int lastpos, int type);
-
-#ifdef HEADER_X509V3_H
-
-int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr);
-CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
- int allorfirst,
- STACK_OF(GENERAL_NAMES) *receiptList,
- STACK_OF(GENERAL_NAMES) *receiptsTo);
-int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr);
-void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
- ASN1_STRING **pcid,
- int *pallorfirst,
- STACK_OF(GENERAL_NAMES) **plist,
- STACK_OF(GENERAL_NAMES) **prto);
-
-#endif
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_CMS_strings(void);
-
-/* Error codes for the CMS functions. */
-
-/* Function codes. */
-#define CMS_F_CHECK_CONTENT 99
-#define CMS_F_CMS_ADD0_CERT 164
-#define CMS_F_CMS_ADD0_RECIPIENT_KEY 100
-#define CMS_F_CMS_ADD0_RECIPIENT_PASSWORD 165
-#define CMS_F_CMS_ADD1_RECEIPTREQUEST 158
-#define CMS_F_CMS_ADD1_RECIPIENT_CERT 101
-#define CMS_F_CMS_ADD1_SIGNER 102
-#define CMS_F_CMS_ADD1_SIGNINGTIME 103
-#define CMS_F_CMS_COMPRESS 104
-#define CMS_F_CMS_COMPRESSEDDATA_CREATE 105
-#define CMS_F_CMS_COMPRESSEDDATA_INIT_BIO 106
-#define CMS_F_CMS_COPY_CONTENT 107
-#define CMS_F_CMS_COPY_MESSAGEDIGEST 108
-#define CMS_F_CMS_DATA 109
-#define CMS_F_CMS_DATAFINAL 110
-#define CMS_F_CMS_DATAINIT 111
-#define CMS_F_CMS_DECRYPT 112
-#define CMS_F_CMS_DECRYPT_SET1_KEY 113
-#define CMS_F_CMS_DECRYPT_SET1_PASSWORD 166
-#define CMS_F_CMS_DECRYPT_SET1_PKEY 114
-#define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX 115
-#define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO 116
-#define CMS_F_CMS_DIGESTEDDATA_DO_FINAL 117
-#define CMS_F_CMS_DIGEST_VERIFY 118
-#define CMS_F_CMS_ENCODE_RECEIPT 161
-#define CMS_F_CMS_ENCRYPT 119
-#define CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO 120
-#define CMS_F_CMS_ENCRYPTEDDATA_DECRYPT 121
-#define CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT 122
-#define CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY 123
-#define CMS_F_CMS_ENVELOPEDDATA_CREATE 124
-#define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO 125
-#define CMS_F_CMS_ENVELOPED_DATA_INIT 126
-#define CMS_F_CMS_FINAL 127
-#define CMS_F_CMS_GET0_CERTIFICATE_CHOICES 128
-#define CMS_F_CMS_GET0_CONTENT 129
-#define CMS_F_CMS_GET0_ECONTENT_TYPE 130
-#define CMS_F_CMS_GET0_ENVELOPED 131
-#define CMS_F_CMS_GET0_REVOCATION_CHOICES 132
-#define CMS_F_CMS_GET0_SIGNED 133
-#define CMS_F_CMS_MSGSIGDIGEST_ADD1 162
-#define CMS_F_CMS_RECEIPTREQUEST_CREATE0 159
-#define CMS_F_CMS_RECEIPT_VERIFY 160
-#define CMS_F_CMS_RECIPIENTINFO_DECRYPT 134
-#define CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT 135
-#define CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT 136
-#define CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID 137
-#define CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP 138
-#define CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP 139
-#define CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT 140
-#define CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT 141
-#define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS 142
-#define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID 143
-#define CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT 167
-#define CMS_F_CMS_RECIPIENTINFO_SET0_KEY 144
-#define CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD 168
-#define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY 145
-#define CMS_F_CMS_SET1_SIGNERIDENTIFIER 146
-#define CMS_F_CMS_SET_DETACHED 147
-#define CMS_F_CMS_SIGN 148
-#define CMS_F_CMS_SIGNED_DATA_INIT 149
-#define CMS_F_CMS_SIGNERINFO_CONTENT_SIGN 150
-#define CMS_F_CMS_SIGNERINFO_SIGN 151
-#define CMS_F_CMS_SIGNERINFO_VERIFY 152
-#define CMS_F_CMS_SIGNERINFO_VERIFY_CERT 153
-#define CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT 154
-#define CMS_F_CMS_SIGN_RECEIPT 163
-#define CMS_F_CMS_STREAM 155
-#define CMS_F_CMS_UNCOMPRESS 156
-#define CMS_F_CMS_VERIFY 157
-
-/* Reason codes. */
-#define CMS_R_ADD_SIGNER_ERROR 99
-#define CMS_R_CERTIFICATE_ALREADY_PRESENT 175
-#define CMS_R_CERTIFICATE_HAS_NO_KEYID 160
-#define CMS_R_CERTIFICATE_VERIFY_ERROR 100
-#define CMS_R_CIPHER_INITIALISATION_ERROR 101
-#define CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR 102
-#define CMS_R_CMS_DATAFINAL_ERROR 103
-#define CMS_R_CMS_LIB 104
-#define CMS_R_CONTENTIDENTIFIER_MISMATCH 170
-#define CMS_R_CONTENT_NOT_FOUND 105
-#define CMS_R_CONTENT_TYPE_MISMATCH 171
-#define CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA 106
-#define CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA 107
-#define CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA 108
-#define CMS_R_CONTENT_VERIFY_ERROR 109
-#define CMS_R_CTRL_ERROR 110
-#define CMS_R_CTRL_FAILURE 111
-#define CMS_R_DECRYPT_ERROR 112
-#define CMS_R_DIGEST_ERROR 161
-#define CMS_R_ERROR_GETTING_PUBLIC_KEY 113
-#define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 114
-#define CMS_R_ERROR_SETTING_KEY 115
-#define CMS_R_ERROR_SETTING_RECIPIENTINFO 116
-#define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 117
-#define CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER 176
-#define CMS_R_INVALID_KEY_LENGTH 118
-#define CMS_R_MD_BIO_INIT_ERROR 119
-#define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 120
-#define CMS_R_MESSAGEDIGEST_WRONG_LENGTH 121
-#define CMS_R_MSGSIGDIGEST_ERROR 172
-#define CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE 162
-#define CMS_R_MSGSIGDIGEST_WRONG_LENGTH 163
-#define CMS_R_NEED_ONE_SIGNER 164
-#define CMS_R_NOT_A_SIGNED_RECEIPT 165
-#define CMS_R_NOT_ENCRYPTED_DATA 122
-#define CMS_R_NOT_KEK 123
-#define CMS_R_NOT_KEY_TRANSPORT 124
-#define CMS_R_NOT_PWRI 177
-#define CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 125
-#define CMS_R_NO_CIPHER 126
-#define CMS_R_NO_CONTENT 127
-#define CMS_R_NO_CONTENT_TYPE 173
-#define CMS_R_NO_DEFAULT_DIGEST 128
-#define CMS_R_NO_DIGEST_SET 129
-#define CMS_R_NO_KEY 130
-#define CMS_R_NO_KEY_OR_CERT 174
-#define CMS_R_NO_MATCHING_DIGEST 131
-#define CMS_R_NO_MATCHING_RECIPIENT 132
-#define CMS_R_NO_MATCHING_SIGNATURE 166
-#define CMS_R_NO_MSGSIGDIGEST 167
-#define CMS_R_NO_PASSWORD 178
-#define CMS_R_NO_PRIVATE_KEY 133
-#define CMS_R_NO_PUBLIC_KEY 134
-#define CMS_R_NO_RECEIPT_REQUEST 168
-#define CMS_R_NO_SIGNERS 135
-#define CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 136
-#define CMS_R_RECEIPT_DECODE_ERROR 169
-#define CMS_R_RECIPIENT_ERROR 137
-#define CMS_R_SIGNER_CERTIFICATE_NOT_FOUND 138
-#define CMS_R_SIGNFINAL_ERROR 139
-#define CMS_R_SMIME_TEXT_ERROR 140
-#define CMS_R_STORE_INIT_ERROR 141
-#define CMS_R_TYPE_NOT_COMPRESSED_DATA 142
-#define CMS_R_TYPE_NOT_DATA 143
-#define CMS_R_TYPE_NOT_DIGESTED_DATA 144
-#define CMS_R_TYPE_NOT_ENCRYPTED_DATA 145
-#define CMS_R_TYPE_NOT_ENVELOPED_DATA 146
-#define CMS_R_UNABLE_TO_FINALIZE_CONTEXT 147
-#define CMS_R_UNKNOWN_CIPHER 148
-#define CMS_R_UNKNOWN_DIGEST_ALGORIHM 149
-#define CMS_R_UNKNOWN_ID 150
-#define CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM 151
-#define CMS_R_UNSUPPORTED_CONTENT_TYPE 152
-#define CMS_R_UNSUPPORTED_KEK_ALGORITHM 153
-#define CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM 179
-#define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 154
-#define CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE 155
-#define CMS_R_UNSUPPORTED_TYPE 156
-#define CMS_R_UNWRAP_ERROR 157
-#define CMS_R_UNWRAP_FAILURE 180
-#define CMS_R_VERIFICATION_FAILURE 158
-#define CMS_R_WRAP_ERROR 159
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/comp.h b/drivers/builtin_openssl/openssl/comp.h
deleted file mode 100644
index 4b405c7d49..0000000000
--- a/drivers/builtin_openssl/openssl/comp.h
+++ /dev/null
@@ -1,80 +0,0 @@
-
-#ifndef HEADER_COMP_H
-#define HEADER_COMP_H
-
-#include <openssl/crypto.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct comp_ctx_st COMP_CTX;
-
-typedef struct comp_method_st
- {
- int type; /* NID for compression library */
- const char *name; /* A text string to identify the library */
- int (*init)(COMP_CTX *ctx);
- void (*finish)(COMP_CTX *ctx);
- int (*compress)(COMP_CTX *ctx,
- unsigned char *out, unsigned int olen,
- unsigned char *in, unsigned int ilen);
- int (*expand)(COMP_CTX *ctx,
- unsigned char *out, unsigned int olen,
- unsigned char *in, unsigned int ilen);
- /* The following two do NOTHING, but are kept for backward compatibility */
- long (*ctrl)(void);
- long (*callback_ctrl)(void);
- } COMP_METHOD;
-
-struct comp_ctx_st
- {
- COMP_METHOD *meth;
- unsigned long compress_in;
- unsigned long compress_out;
- unsigned long expand_in;
- unsigned long expand_out;
-
- CRYPTO_EX_DATA ex_data;
- };
-
-
-COMP_CTX *COMP_CTX_new(COMP_METHOD *meth);
-void COMP_CTX_free(COMP_CTX *ctx);
-int COMP_compress_block(COMP_CTX *ctx, unsigned char *out, int olen,
- unsigned char *in, int ilen);
-int COMP_expand_block(COMP_CTX *ctx, unsigned char *out, int olen,
- unsigned char *in, int ilen);
-COMP_METHOD *COMP_rle(void );
-COMP_METHOD *COMP_zlib(void );
-void COMP_zlib_cleanup(void);
-
-#ifdef HEADER_BIO_H
-#ifdef ZLIB
-BIO_METHOD *BIO_f_zlib(void);
-#endif
-#endif
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_COMP_strings(void);
-
-/* Error codes for the COMP functions. */
-
-/* Function codes. */
-#define COMP_F_BIO_ZLIB_FLUSH 99
-#define COMP_F_BIO_ZLIB_NEW 100
-#define COMP_F_BIO_ZLIB_READ 101
-#define COMP_F_BIO_ZLIB_WRITE 102
-
-/* Reason codes. */
-#define COMP_R_ZLIB_DEFLATE_ERROR 99
-#define COMP_R_ZLIB_INFLATE_ERROR 100
-#define COMP_R_ZLIB_NOT_SUPPORTED 101
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/conf.h b/drivers/builtin_openssl/openssl/conf.h
deleted file mode 100644
index c2199978a3..0000000000
--- a/drivers/builtin_openssl/openssl/conf.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/* crypto/conf/conf.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_CONF_H
-#define HEADER_CONF_H
-
-#include <openssl/bio.h>
-#include <openssl/lhash.h>
-#include <openssl/stack.h>
-#include <openssl/safestack.h>
-#include <openssl/e_os2.h>
-
-#include <openssl/ossl_typ.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct
- {
- char *section;
- char *name;
- char *value;
- } CONF_VALUE;
-
-DECLARE_STACK_OF(CONF_VALUE)
-DECLARE_LHASH_OF(CONF_VALUE);
-
-struct conf_st;
-struct conf_method_st;
-typedef struct conf_method_st CONF_METHOD;
-
-struct conf_method_st
- {
- const char *name;
- CONF *(*create)(CONF_METHOD *meth);
- int (*init)(CONF *conf);
- int (*destroy)(CONF *conf);
- int (*destroy_data)(CONF *conf);
- int (*load_bio)(CONF *conf, BIO *bp, long *eline);
- int (*dump)(const CONF *conf, BIO *bp);
- int (*is_number)(const CONF *conf, char c);
- int (*to_int)(const CONF *conf, char c);
- int (*load)(CONF *conf, const char *name, long *eline);
- };
-
-/* Module definitions */
-
-typedef struct conf_imodule_st CONF_IMODULE;
-typedef struct conf_module_st CONF_MODULE;
-
-DECLARE_STACK_OF(CONF_MODULE)
-DECLARE_STACK_OF(CONF_IMODULE)
-
-/* DSO module function typedefs */
-typedef int conf_init_func(CONF_IMODULE *md, const CONF *cnf);
-typedef void conf_finish_func(CONF_IMODULE *md);
-
-#define CONF_MFLAGS_IGNORE_ERRORS 0x1
-#define CONF_MFLAGS_IGNORE_RETURN_CODES 0x2
-#define CONF_MFLAGS_SILENT 0x4
-#define CONF_MFLAGS_NO_DSO 0x8
-#define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10
-#define CONF_MFLAGS_DEFAULT_SECTION 0x20
-
-int CONF_set_default_method(CONF_METHOD *meth);
-void CONF_set_nconf(CONF *conf,LHASH_OF(CONF_VALUE) *hash);
-LHASH_OF(CONF_VALUE) *CONF_load(LHASH_OF(CONF_VALUE) *conf,const char *file,
- long *eline);
-#ifndef OPENSSL_NO_FP_API
-LHASH_OF(CONF_VALUE) *CONF_load_fp(LHASH_OF(CONF_VALUE) *conf, FILE *fp,
- long *eline);
-#endif
-LHASH_OF(CONF_VALUE) *CONF_load_bio(LHASH_OF(CONF_VALUE) *conf, BIO *bp,long *eline);
-STACK_OF(CONF_VALUE) *CONF_get_section(LHASH_OF(CONF_VALUE) *conf,
- const char *section);
-char *CONF_get_string(LHASH_OF(CONF_VALUE) *conf,const char *group,
- const char *name);
-long CONF_get_number(LHASH_OF(CONF_VALUE) *conf,const char *group,
- const char *name);
-void CONF_free(LHASH_OF(CONF_VALUE) *conf);
-int CONF_dump_fp(LHASH_OF(CONF_VALUE) *conf, FILE *out);
-int CONF_dump_bio(LHASH_OF(CONF_VALUE) *conf, BIO *out);
-
-void OPENSSL_config(const char *config_name);
-void OPENSSL_no_config(void);
-
-/* New conf code. The semantics are different from the functions above.
- If that wasn't the case, the above functions would have been replaced */
-
-struct conf_st
- {
- CONF_METHOD *meth;
- void *meth_data;
- LHASH_OF(CONF_VALUE) *data;
- };
-
-CONF *NCONF_new(CONF_METHOD *meth);
-CONF_METHOD *NCONF_default(void);
-CONF_METHOD *NCONF_WIN32(void);
-#if 0 /* Just to give you an idea of what I have in mind */
-CONF_METHOD *NCONF_XML(void);
-#endif
-void NCONF_free(CONF *conf);
-void NCONF_free_data(CONF *conf);
-
-int NCONF_load(CONF *conf,const char *file,long *eline);
-#ifndef OPENSSL_NO_FP_API
-int NCONF_load_fp(CONF *conf, FILE *fp,long *eline);
-#endif
-int NCONF_load_bio(CONF *conf, BIO *bp,long *eline);
-STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf,const char *section);
-char *NCONF_get_string(const CONF *conf,const char *group,const char *name);
-int NCONF_get_number_e(const CONF *conf,const char *group,const char *name,
- long *result);
-int NCONF_dump_fp(const CONF *conf, FILE *out);
-int NCONF_dump_bio(const CONF *conf, BIO *out);
-
-#if 0 /* The following function has no error checking,
- and should therefore be avoided */
-long NCONF_get_number(CONF *conf,char *group,char *name);
-#else
-#define NCONF_get_number(c,g,n,r) NCONF_get_number_e(c,g,n,r)
-#endif
-
-/* Module functions */
-
-int CONF_modules_load(const CONF *cnf, const char *appname,
- unsigned long flags);
-int CONF_modules_load_file(const char *filename, const char *appname,
- unsigned long flags);
-void CONF_modules_unload(int all);
-void CONF_modules_finish(void);
-void CONF_modules_free(void);
-int CONF_module_add(const char *name, conf_init_func *ifunc,
- conf_finish_func *ffunc);
-
-const char *CONF_imodule_get_name(const CONF_IMODULE *md);
-const char *CONF_imodule_get_value(const CONF_IMODULE *md);
-void *CONF_imodule_get_usr_data(const CONF_IMODULE *md);
-void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data);
-CONF_MODULE *CONF_imodule_get_module(const CONF_IMODULE *md);
-unsigned long CONF_imodule_get_flags(const CONF_IMODULE *md);
-void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags);
-void *CONF_module_get_usr_data(CONF_MODULE *pmod);
-void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data);
-
-char *CONF_get1_default_config_file(void);
-
-int CONF_parse_list(const char *list, int sep, int nospc,
- int (*list_cb)(const char *elem, int len, void *usr), void *arg);
-
-void OPENSSL_load_builtin_modules(void);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_CONF_strings(void);
-
-/* Error codes for the CONF functions. */
-
-/* Function codes. */
-#define CONF_F_CONF_DUMP_FP 104
-#define CONF_F_CONF_LOAD 100
-#define CONF_F_CONF_LOAD_BIO 102
-#define CONF_F_CONF_LOAD_FP 103
-#define CONF_F_CONF_MODULES_LOAD 116
-#define CONF_F_CONF_PARSE_LIST 119
-#define CONF_F_DEF_LOAD 120
-#define CONF_F_DEF_LOAD_BIO 121
-#define CONF_F_MODULE_INIT 115
-#define CONF_F_MODULE_LOAD_DSO 117
-#define CONF_F_MODULE_RUN 118
-#define CONF_F_NCONF_DUMP_BIO 105
-#define CONF_F_NCONF_DUMP_FP 106
-#define CONF_F_NCONF_GET_NUMBER 107
-#define CONF_F_NCONF_GET_NUMBER_E 112
-#define CONF_F_NCONF_GET_SECTION 108
-#define CONF_F_NCONF_GET_STRING 109
-#define CONF_F_NCONF_LOAD 113
-#define CONF_F_NCONF_LOAD_BIO 110
-#define CONF_F_NCONF_LOAD_FP 114
-#define CONF_F_NCONF_NEW 111
-#define CONF_F_STR_COPY 101
-
-/* Reason codes. */
-#define CONF_R_ERROR_LOADING_DSO 110
-#define CONF_R_LIST_CANNOT_BE_NULL 115
-#define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 100
-#define CONF_R_MISSING_EQUAL_SIGN 101
-#define CONF_R_MISSING_FINISH_FUNCTION 111
-#define CONF_R_MISSING_INIT_FUNCTION 112
-#define CONF_R_MODULE_INITIALIZATION_ERROR 109
-#define CONF_R_NO_CLOSE_BRACE 102
-#define CONF_R_NO_CONF 105
-#define CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE 106
-#define CONF_R_NO_SECTION 107
-#define CONF_R_NO_SUCH_FILE 114
-#define CONF_R_NO_VALUE 108
-#define CONF_R_UNABLE_TO_CREATE_NEW_SECTION 103
-#define CONF_R_UNKNOWN_MODULE_NAME 113
-#define CONF_R_VARIABLE_HAS_NO_VALUE 104
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/conf_api.h b/drivers/builtin_openssl/openssl/conf_api.h
deleted file mode 100644
index 87a954aff6..0000000000
--- a/drivers/builtin_openssl/openssl/conf_api.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* conf_api.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_CONF_API_H
-#define HEADER_CONF_API_H
-
-#include <openssl/lhash.h>
-#include <openssl/conf.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Up until OpenSSL 0.9.5a, this was new_section */
-CONF_VALUE *_CONF_new_section(CONF *conf, const char *section);
-/* Up until OpenSSL 0.9.5a, this was get_section */
-CONF_VALUE *_CONF_get_section(const CONF *conf, const char *section);
-/* Up until OpenSSL 0.9.5a, this was CONF_get_section */
-STACK_OF(CONF_VALUE) *_CONF_get_section_values(const CONF *conf,
- const char *section);
-
-int _CONF_add_string(CONF *conf, CONF_VALUE *section, CONF_VALUE *value);
-char *_CONF_get_string(const CONF *conf, const char *section,
- const char *name);
-long _CONF_get_number(const CONF *conf, const char *section, const char *name);
-
-int _CONF_new_data(CONF *conf);
-void _CONF_free_data(CONF *conf);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/openssl/crypto.h b/drivers/builtin_openssl/openssl/crypto.h
deleted file mode 100644
index f92fc5182d..0000000000
--- a/drivers/builtin_openssl/openssl/crypto.h
+++ /dev/null
@@ -1,611 +0,0 @@
-/* crypto/crypto.h */
-/* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECDH support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-
-#ifndef HEADER_CRYPTO_H
-#define HEADER_CRYPTO_H
-
-#include <stdlib.h>
-
-#include <openssl/e_os2.h>
-
-#ifndef OPENSSL_NO_FP_API
-#include <stdio.h>
-#endif
-
-#include <openssl/stack.h>
-#include <openssl/safestack.h>
-#include <openssl/opensslv.h>
-#include <openssl/ossl_typ.h>
-
-#ifdef CHARSET_EBCDIC
-#include <openssl/ebcdic.h>
-#endif
-
-/* Resolve problems on some operating systems with symbol names that clash
- one way or another */
-#include <openssl/symhacks.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Backward compatibility to SSLeay */
-/* This is more to be used to check the correct DLL is being used
- * in the MS world. */
-#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
-#define SSLEAY_VERSION 0
-/* #define SSLEAY_OPTIONS 1 no longer supported */
-#define SSLEAY_CFLAGS 2
-#define SSLEAY_BUILT_ON 3
-#define SSLEAY_PLATFORM 4
-#define SSLEAY_DIR 5
-
-/* Already declared in ossl_typ.h */
-#if 0
-typedef struct crypto_ex_data_st CRYPTO_EX_DATA;
-/* Called when a new object is created */
-typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
- int idx, long argl, void *argp);
-/* Called when an object is free()ed */
-typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
- int idx, long argl, void *argp);
-/* Called when we need to dup an object */
-typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d,
- int idx, long argl, void *argp);
-#endif
-
-/* A generic structure to pass assorted data in a expandable way */
-typedef struct openssl_item_st
- {
- int code;
- void *value; /* Not used for flag attributes */
- size_t value_size; /* Max size of value for output, length for input */
- size_t *value_length; /* Returned length of value for output */
- } OPENSSL_ITEM;
-
-
-/* When changing the CRYPTO_LOCK_* list, be sure to maintin the text lock
- * names in cryptlib.c
- */
-
-#define CRYPTO_LOCK_ERR 1
-#define CRYPTO_LOCK_EX_DATA 2
-#define CRYPTO_LOCK_X509 3
-#define CRYPTO_LOCK_X509_INFO 4
-#define CRYPTO_LOCK_X509_PKEY 5
-#define CRYPTO_LOCK_X509_CRL 6
-#define CRYPTO_LOCK_X509_REQ 7
-#define CRYPTO_LOCK_DSA 8
-#define CRYPTO_LOCK_RSA 9
-#define CRYPTO_LOCK_EVP_PKEY 10
-#define CRYPTO_LOCK_X509_STORE 11
-#define CRYPTO_LOCK_SSL_CTX 12
-#define CRYPTO_LOCK_SSL_CERT 13
-#define CRYPTO_LOCK_SSL_SESSION 14
-#define CRYPTO_LOCK_SSL_SESS_CERT 15
-#define CRYPTO_LOCK_SSL 16
-#define CRYPTO_LOCK_SSL_METHOD 17
-#define CRYPTO_LOCK_RAND 18
-#define CRYPTO_LOCK_RAND2 19
-#define CRYPTO_LOCK_MALLOC 20
-#define CRYPTO_LOCK_BIO 21
-#define CRYPTO_LOCK_GETHOSTBYNAME 22
-#define CRYPTO_LOCK_GETSERVBYNAME 23
-#define CRYPTO_LOCK_READDIR 24
-#define CRYPTO_LOCK_RSA_BLINDING 25
-#define CRYPTO_LOCK_DH 26
-#define CRYPTO_LOCK_MALLOC2 27
-#define CRYPTO_LOCK_DSO 28
-#define CRYPTO_LOCK_DYNLOCK 29
-#define CRYPTO_LOCK_ENGINE 30
-#define CRYPTO_LOCK_UI 31
-#define CRYPTO_LOCK_ECDSA 32
-#define CRYPTO_LOCK_EC 33
-#define CRYPTO_LOCK_ECDH 34
-#define CRYPTO_LOCK_BN 35
-#define CRYPTO_LOCK_EC_PRE_COMP 36
-#define CRYPTO_LOCK_STORE 37
-#define CRYPTO_LOCK_COMP 38
-#define CRYPTO_LOCK_FIPS 39
-#define CRYPTO_LOCK_FIPS2 40
-#define CRYPTO_NUM_LOCKS 41
-
-#define CRYPTO_LOCK 1
-#define CRYPTO_UNLOCK 2
-#define CRYPTO_READ 4
-#define CRYPTO_WRITE 8
-
-#ifndef OPENSSL_NO_LOCKING
-#ifndef CRYPTO_w_lock
-#define CRYPTO_w_lock(type) \
- CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,__FILE__,__LINE__)
-#define CRYPTO_w_unlock(type) \
- CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,__FILE__,__LINE__)
-#define CRYPTO_r_lock(type) \
- CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,__FILE__,__LINE__)
-#define CRYPTO_r_unlock(type) \
- CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,__FILE__,__LINE__)
-#define CRYPTO_add(addr,amount,type) \
- CRYPTO_add_lock(addr,amount,type,__FILE__,__LINE__)
-#endif
-#else
-#define CRYPTO_w_lock(a)
-#define CRYPTO_w_unlock(a)
-#define CRYPTO_r_lock(a)
-#define CRYPTO_r_unlock(a)
-#define CRYPTO_add(a,b,c) ((*(a))+=(b))
-#endif
-
-/* Some applications as well as some parts of OpenSSL need to allocate
- and deallocate locks in a dynamic fashion. The following typedef
- makes this possible in a type-safe manner. */
-/* struct CRYPTO_dynlock_value has to be defined by the application. */
-typedef struct
- {
- int references;
- struct CRYPTO_dynlock_value *data;
- } CRYPTO_dynlock;
-
-
-/* The following can be used to detect memory leaks in the SSLeay library.
- * It used, it turns on malloc checking */
-
-#define CRYPTO_MEM_CHECK_OFF 0x0 /* an enume */
-#define CRYPTO_MEM_CHECK_ON 0x1 /* a bit */
-#define CRYPTO_MEM_CHECK_ENABLE 0x2 /* a bit */
-#define CRYPTO_MEM_CHECK_DISABLE 0x3 /* an enume */
-
-/* The following are bit values to turn on or off options connected to the
- * malloc checking functionality */
-
-/* Adds time to the memory checking information */
-#define V_CRYPTO_MDEBUG_TIME 0x1 /* a bit */
-/* Adds thread number to the memory checking information */
-#define V_CRYPTO_MDEBUG_THREAD 0x2 /* a bit */
-
-#define V_CRYPTO_MDEBUG_ALL (V_CRYPTO_MDEBUG_TIME | V_CRYPTO_MDEBUG_THREAD)
-
-
-/* predec of the BIO type */
-typedef struct bio_st BIO_dummy;
-
-struct crypto_ex_data_st
- {
- STACK_OF(void) *sk;
- int dummy; /* gcc is screwing up this data structure :-( */
- };
-DECLARE_STACK_OF(void)
-
-/* This stuff is basically class callback functions
- * The current classes are SSL_CTX, SSL, SSL_SESSION, and a few more */
-
-typedef struct crypto_ex_data_func_st
- {
- long argl; /* Arbitary long */
- void *argp; /* Arbitary void * */
- CRYPTO_EX_new *new_func;
- CRYPTO_EX_free *free_func;
- CRYPTO_EX_dup *dup_func;
- } CRYPTO_EX_DATA_FUNCS;
-
-DECLARE_STACK_OF(CRYPTO_EX_DATA_FUNCS)
-
-/* Per class, we have a STACK of CRYPTO_EX_DATA_FUNCS for each CRYPTO_EX_DATA
- * entry.
- */
-
-#define CRYPTO_EX_INDEX_BIO 0
-#define CRYPTO_EX_INDEX_SSL 1
-#define CRYPTO_EX_INDEX_SSL_CTX 2
-#define CRYPTO_EX_INDEX_SSL_SESSION 3
-#define CRYPTO_EX_INDEX_X509_STORE 4
-#define CRYPTO_EX_INDEX_X509_STORE_CTX 5
-#define CRYPTO_EX_INDEX_RSA 6
-#define CRYPTO_EX_INDEX_DSA 7
-#define CRYPTO_EX_INDEX_DH 8
-#define CRYPTO_EX_INDEX_ENGINE 9
-#define CRYPTO_EX_INDEX_X509 10
-#define CRYPTO_EX_INDEX_UI 11
-#define CRYPTO_EX_INDEX_ECDSA 12
-#define CRYPTO_EX_INDEX_ECDH 13
-#define CRYPTO_EX_INDEX_COMP 14
-#define CRYPTO_EX_INDEX_STORE 15
-
-/* Dynamically assigned indexes start from this value (don't use directly, use
- * via CRYPTO_ex_data_new_class). */
-#define CRYPTO_EX_INDEX_USER 100
-
-
-/* This is the default callbacks, but we can have others as well:
- * this is needed in Win32 where the application malloc and the
- * library malloc may not be the same.
- */
-#define CRYPTO_malloc_init() CRYPTO_set_mem_functions(\
- malloc, realloc, free)
-
-#if defined CRYPTO_MDEBUG_ALL || defined CRYPTO_MDEBUG_TIME || defined CRYPTO_MDEBUG_THREAD
-# ifndef CRYPTO_MDEBUG /* avoid duplicate #define */
-# define CRYPTO_MDEBUG
-# endif
-#endif
-
-/* Set standard debugging functions (not done by default
- * unless CRYPTO_MDEBUG is defined) */
-#define CRYPTO_malloc_debug_init() do {\
- CRYPTO_set_mem_debug_functions(\
- CRYPTO_dbg_malloc,\
- CRYPTO_dbg_realloc,\
- CRYPTO_dbg_free,\
- CRYPTO_dbg_set_options,\
- CRYPTO_dbg_get_options);\
- } while(0)
-
-int CRYPTO_mem_ctrl(int mode);
-int CRYPTO_is_mem_check_on(void);
-
-/* for applications */
-#define MemCheck_start() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON)
-#define MemCheck_stop() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF)
-
-/* for library-internal use */
-#define MemCheck_on() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE)
-#define MemCheck_off() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE)
-#define is_MemCheck_on() CRYPTO_is_mem_check_on()
-
-#define OPENSSL_malloc(num) CRYPTO_malloc((int)num,__FILE__,__LINE__)
-#define OPENSSL_strdup(str) CRYPTO_strdup((str),__FILE__,__LINE__)
-#define OPENSSL_realloc(addr,num) \
- CRYPTO_realloc((char *)addr,(int)num,__FILE__,__LINE__)
-#define OPENSSL_realloc_clean(addr,old_num,num) \
- CRYPTO_realloc_clean(addr,old_num,num,__FILE__,__LINE__)
-#define OPENSSL_remalloc(addr,num) \
- CRYPTO_remalloc((char **)addr,(int)num,__FILE__,__LINE__)
-#define OPENSSL_freeFunc CRYPTO_free
-#define OPENSSL_free(addr) CRYPTO_free(addr)
-
-#define OPENSSL_malloc_locked(num) \
- CRYPTO_malloc_locked((int)num,__FILE__,__LINE__)
-#define OPENSSL_free_locked(addr) CRYPTO_free_locked(addr)
-
-
-const char *SSLeay_version(int type);
-unsigned long SSLeay(void);
-
-int OPENSSL_issetugid(void);
-
-/* An opaque type representing an implementation of "ex_data" support */
-typedef struct st_CRYPTO_EX_DATA_IMPL CRYPTO_EX_DATA_IMPL;
-/* Return an opaque pointer to the current "ex_data" implementation */
-const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void);
-/* Sets the "ex_data" implementation to be used (if it's not too late) */
-int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i);
-/* Get a new "ex_data" class, and return the corresponding "class_index" */
-int CRYPTO_ex_data_new_class(void);
-/* Within a given class, get/register a new index */
-int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
- CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
- CRYPTO_EX_free *free_func);
-/* Initialise/duplicate/free CRYPTO_EX_DATA variables corresponding to a given
- * class (invokes whatever per-class callbacks are applicable) */
-int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad);
-int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
- CRYPTO_EX_DATA *from);
-void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad);
-/* Get/set data in a CRYPTO_EX_DATA variable corresponding to a particular index
- * (relative to the class type involved) */
-int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val);
-void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad,int idx);
-/* This function cleans up all "ex_data" state. It mustn't be called under
- * potential race-conditions. */
-void CRYPTO_cleanup_all_ex_data(void);
-
-int CRYPTO_get_new_lockid(char *name);
-
-int CRYPTO_num_locks(void); /* return CRYPTO_NUM_LOCKS (shared libs!) */
-void CRYPTO_lock(int mode, int type,const char *file,int line);
-void CRYPTO_set_locking_callback(void (*func)(int mode,int type,
- const char *file,int line));
-void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file,
- int line);
-void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
- const char *file, int line));
-int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type,
- const char *file,int line);
-
-/* Don't use this structure directly. */
-typedef struct crypto_threadid_st
- {
- void *ptr;
- unsigned long val;
- } CRYPTO_THREADID;
-/* Only use CRYPTO_THREADID_set_[numeric|pointer]() within callbacks */
-void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val);
-void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr);
-int CRYPTO_THREADID_set_callback(void (*threadid_func)(CRYPTO_THREADID *));
-void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *);
-void CRYPTO_THREADID_current(CRYPTO_THREADID *id);
-int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b);
-void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src);
-unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id);
-#ifndef OPENSSL_NO_DEPRECATED
-void CRYPTO_set_id_callback(unsigned long (*func)(void));
-unsigned long (*CRYPTO_get_id_callback(void))(void);
-unsigned long CRYPTO_thread_id(void);
-#endif
-
-const char *CRYPTO_get_lock_name(int type);
-int CRYPTO_add_lock(int *pointer,int amount,int type, const char *file,
- int line);
-
-int CRYPTO_get_new_dynlockid(void);
-void CRYPTO_destroy_dynlockid(int i);
-struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i);
-void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*dyn_create_function)(const char *file, int line));
-void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line));
-void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *l, const char *file, int line));
-struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))(const char *file,int line);
-void (*CRYPTO_get_dynlock_lock_callback(void))(int mode, struct CRYPTO_dynlock_value *l, const char *file,int line);
-void (*CRYPTO_get_dynlock_destroy_callback(void))(struct CRYPTO_dynlock_value *l, const char *file,int line);
-
-/* CRYPTO_set_mem_functions includes CRYPTO_set_locked_mem_functions --
- * call the latter last if you need different functions */
-int CRYPTO_set_mem_functions(void *(*m)(size_t),void *(*r)(void *,size_t), void (*f)(void *));
-int CRYPTO_set_locked_mem_functions(void *(*m)(size_t), void (*free_func)(void *));
-int CRYPTO_set_mem_ex_functions(void *(*m)(size_t,const char *,int),
- void *(*r)(void *,size_t,const char *,int),
- void (*f)(void *));
-int CRYPTO_set_locked_mem_ex_functions(void *(*m)(size_t,const char *,int),
- void (*free_func)(void *));
-int CRYPTO_set_mem_debug_functions(void (*m)(void *,int,const char *,int,int),
- void (*r)(void *,void *,int,const char *,int,int),
- void (*f)(void *,int),
- void (*so)(long),
- long (*go)(void));
-void CRYPTO_get_mem_functions(void *(**m)(size_t),void *(**r)(void *, size_t), void (**f)(void *));
-void CRYPTO_get_locked_mem_functions(void *(**m)(size_t), void (**f)(void *));
-void CRYPTO_get_mem_ex_functions(void *(**m)(size_t,const char *,int),
- void *(**r)(void *, size_t,const char *,int),
- void (**f)(void *));
-void CRYPTO_get_locked_mem_ex_functions(void *(**m)(size_t,const char *,int),
- void (**f)(void *));
-void CRYPTO_get_mem_debug_functions(void (**m)(void *,int,const char *,int,int),
- void (**r)(void *,void *,int,const char *,int,int),
- void (**f)(void *,int),
- void (**so)(long),
- long (**go)(void));
-
-void *CRYPTO_malloc_locked(int num, const char *file, int line);
-void CRYPTO_free_locked(void *ptr);
-void *CRYPTO_malloc(int num, const char *file, int line);
-char *CRYPTO_strdup(const char *str, const char *file, int line);
-void CRYPTO_free(void *ptr);
-void *CRYPTO_realloc(void *addr,int num, const char *file, int line);
-void *CRYPTO_realloc_clean(void *addr,int old_num,int num,const char *file,
- int line);
-void *CRYPTO_remalloc(void *addr,int num, const char *file, int line);
-
-void OPENSSL_cleanse(void *ptr, size_t len);
-
-void CRYPTO_set_mem_debug_options(long bits);
-long CRYPTO_get_mem_debug_options(void);
-
-#define CRYPTO_push_info(info) \
- CRYPTO_push_info_(info, __FILE__, __LINE__);
-int CRYPTO_push_info_(const char *info, const char *file, int line);
-int CRYPTO_pop_info(void);
-int CRYPTO_remove_all_info(void);
-
-
-/* Default debugging functions (enabled by CRYPTO_malloc_debug_init() macro;
- * used as default in CRYPTO_MDEBUG compilations): */
-/* The last argument has the following significance:
- *
- * 0: called before the actual memory allocation has taken place
- * 1: called after the actual memory allocation has taken place
- */
-void CRYPTO_dbg_malloc(void *addr,int num,const char *file,int line,int before_p);
-void CRYPTO_dbg_realloc(void *addr1,void *addr2,int num,const char *file,int line,int before_p);
-void CRYPTO_dbg_free(void *addr,int before_p);
-/* Tell the debugging code about options. By default, the following values
- * apply:
- *
- * 0: Clear all options.
- * V_CRYPTO_MDEBUG_TIME (1): Set the "Show Time" option.
- * V_CRYPTO_MDEBUG_THREAD (2): Set the "Show Thread Number" option.
- * V_CRYPTO_MDEBUG_ALL (3): 1 + 2
- */
-void CRYPTO_dbg_set_options(long bits);
-long CRYPTO_dbg_get_options(void);
-
-
-#ifndef OPENSSL_NO_FP_API
-void CRYPTO_mem_leaks_fp(FILE *);
-#endif
-void CRYPTO_mem_leaks(struct bio_st *bio);
-/* unsigned long order, char *file, int line, int num_bytes, char *addr */
-typedef void *CRYPTO_MEM_LEAK_CB(unsigned long, const char *, int, int, void *);
-void CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb);
-
-/* die if we have to */
-void OpenSSLDie(const char *file,int line,const char *assertion);
-#define OPENSSL_assert(e) (void)((e) ? 0 : (OpenSSLDie(__FILE__, __LINE__, #e),1))
-
-unsigned long *OPENSSL_ia32cap_loc(void);
-#define OPENSSL_ia32cap (*(OPENSSL_ia32cap_loc()))
-int OPENSSL_isservice(void);
-
-int FIPS_mode(void);
-int FIPS_mode_set(int r);
-
-void OPENSSL_init(void);
-
-#define fips_md_init(alg) fips_md_init_ctx(alg, alg)
-
-#ifdef OPENSSL_FIPS
-#define fips_md_init_ctx(alg, cx) \
- int alg##_Init(cx##_CTX *c) \
- { \
- if (FIPS_mode()) OpenSSLDie(__FILE__, __LINE__, \
- "Low level API call to digest " #alg " forbidden in FIPS mode!"); \
- return private_##alg##_Init(c); \
- } \
- int private_##alg##_Init(cx##_CTX *c)
-
-#define fips_cipher_abort(alg) \
- if (FIPS_mode()) OpenSSLDie(__FILE__, __LINE__, \
- "Low level API call to cipher " #alg " forbidden in FIPS mode!")
-
-#else
-#define fips_md_init_ctx(alg, cx) \
- int alg##_Init(cx##_CTX *c)
-#define fips_cipher_abort(alg) while(0)
-#endif
-
-/* CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It
- * takes an amount of time dependent on |len|, but independent of the contents
- * of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a
- * defined order as the return value when a != b is undefined, other than to be
- * non-zero. */
-int CRYPTO_memcmp(const void *a, const void *b, size_t len);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_CRYPTO_strings(void);
-
-/* Error codes for the CRYPTO functions. */
-
-/* Function codes. */
-#define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX 100
-#define CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID 103
-#define CRYPTO_F_CRYPTO_GET_NEW_LOCKID 101
-#define CRYPTO_F_CRYPTO_SET_EX_DATA 102
-#define CRYPTO_F_DEF_ADD_INDEX 104
-#define CRYPTO_F_DEF_GET_CLASS 105
-#define CRYPTO_F_FIPS_MODE_SET 109
-#define CRYPTO_F_INT_DUP_EX_DATA 106
-#define CRYPTO_F_INT_FREE_EX_DATA 107
-#define CRYPTO_F_INT_NEW_EX_DATA 108
-
-/* Reason codes. */
-#define CRYPTO_R_FIPS_MODE_NOT_SUPPORTED 101
-#define CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK 100
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/des.h b/drivers/builtin_openssl/openssl/des.h
deleted file mode 100644
index 1eaedcbd24..0000000000
--- a/drivers/builtin_openssl/openssl/des.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/* crypto/des/des.h */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_NEW_DES_H
-#define HEADER_NEW_DES_H
-
-#include <openssl/e_os2.h> /* OPENSSL_EXTERN, OPENSSL_NO_DES,
- DES_LONG (via openssl/opensslconf.h */
-
-#ifdef OPENSSL_NO_DES
-#error DES is disabled.
-#endif
-
-#ifdef OPENSSL_BUILD_SHLIBCRYPTO
-# undef OPENSSL_EXTERN
-# define OPENSSL_EXTERN OPENSSL_EXPORT
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef unsigned char DES_cblock[8];
-typedef /* const */ unsigned char const_DES_cblock[8];
-/* With "const", gcc 2.8.1 on Solaris thinks that DES_cblock *
- * and const_DES_cblock * are incompatible pointer types. */
-
-typedef struct DES_ks
- {
- union
- {
- DES_cblock cblock;
- /* make sure things are correct size on machines with
- * 8 byte longs */
- DES_LONG deslong[2];
- } ks[16];
- } DES_key_schedule;
-
-#ifndef OPENSSL_DISABLE_OLD_DES_SUPPORT
-# ifndef OPENSSL_ENABLE_OLD_DES_SUPPORT
-# define OPENSSL_ENABLE_OLD_DES_SUPPORT
-# endif
-#endif
-
-#ifdef OPENSSL_ENABLE_OLD_DES_SUPPORT
-# include <openssl/des_old.h>
-#endif
-
-#define DES_KEY_SZ (sizeof(DES_cblock))
-#define DES_SCHEDULE_SZ (sizeof(DES_key_schedule))
-
-#define DES_ENCRYPT 1
-#define DES_DECRYPT 0
-
-#define DES_CBC_MODE 0
-#define DES_PCBC_MODE 1
-
-#define DES_ecb2_encrypt(i,o,k1,k2,e) \
- DES_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
-
-#define DES_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
- DES_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
-
-#define DES_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
- DES_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
-
-#define DES_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
- DES_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
-
-OPENSSL_DECLARE_GLOBAL(int,DES_check_key); /* defaults to false */
-#define DES_check_key OPENSSL_GLOBAL_REF(DES_check_key)
-OPENSSL_DECLARE_GLOBAL(int,DES_rw_mode); /* defaults to DES_PCBC_MODE */
-#define DES_rw_mode OPENSSL_GLOBAL_REF(DES_rw_mode)
-
-const char *DES_options(void);
-void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output,
- DES_key_schedule *ks1,DES_key_schedule *ks2,
- DES_key_schedule *ks3, int enc);
-DES_LONG DES_cbc_cksum(const unsigned char *input,DES_cblock *output,
- long length,DES_key_schedule *schedule,
- const_DES_cblock *ivec);
-/* DES_cbc_encrypt does not update the IV! Use DES_ncbc_encrypt instead. */
-void DES_cbc_encrypt(const unsigned char *input,unsigned char *output,
- long length,DES_key_schedule *schedule,DES_cblock *ivec,
- int enc);
-void DES_ncbc_encrypt(const unsigned char *input,unsigned char *output,
- long length,DES_key_schedule *schedule,DES_cblock *ivec,
- int enc);
-void DES_xcbc_encrypt(const unsigned char *input,unsigned char *output,
- long length,DES_key_schedule *schedule,DES_cblock *ivec,
- const_DES_cblock *inw,const_DES_cblock *outw,int enc);
-void DES_cfb_encrypt(const unsigned char *in,unsigned char *out,int numbits,
- long length,DES_key_schedule *schedule,DES_cblock *ivec,
- int enc);
-void DES_ecb_encrypt(const_DES_cblock *input,DES_cblock *output,
- DES_key_schedule *ks,int enc);
-
-/* This is the DES encryption function that gets called by just about
- every other DES routine in the library. You should not use this
- function except to implement 'modes' of DES. I say this because the
- functions that call this routine do the conversion from 'char *' to
- long, and this needs to be done to make sure 'non-aligned' memory
- access do not occur. The characters are loaded 'little endian'.
- Data is a pointer to 2 unsigned long's and ks is the
- DES_key_schedule to use. enc, is non zero specifies encryption,
- zero if decryption. */
-void DES_encrypt1(DES_LONG *data,DES_key_schedule *ks, int enc);
-
-/* This functions is the same as DES_encrypt1() except that the DES
- initial permutation (IP) and final permutation (FP) have been left
- out. As for DES_encrypt1(), you should not use this function.
- It is used by the routines in the library that implement triple DES.
- IP() DES_encrypt2() DES_encrypt2() DES_encrypt2() FP() is the same
- as DES_encrypt1() DES_encrypt1() DES_encrypt1() except faster :-). */
-void DES_encrypt2(DES_LONG *data,DES_key_schedule *ks, int enc);
-
-void DES_encrypt3(DES_LONG *data, DES_key_schedule *ks1,
- DES_key_schedule *ks2, DES_key_schedule *ks3);
-void DES_decrypt3(DES_LONG *data, DES_key_schedule *ks1,
- DES_key_schedule *ks2, DES_key_schedule *ks3);
-void DES_ede3_cbc_encrypt(const unsigned char *input,unsigned char *output,
- long length,
- DES_key_schedule *ks1,DES_key_schedule *ks2,
- DES_key_schedule *ks3,DES_cblock *ivec,int enc);
-void DES_ede3_cbcm_encrypt(const unsigned char *in,unsigned char *out,
- long length,
- DES_key_schedule *ks1,DES_key_schedule *ks2,
- DES_key_schedule *ks3,
- DES_cblock *ivec1,DES_cblock *ivec2,
- int enc);
-void DES_ede3_cfb64_encrypt(const unsigned char *in,unsigned char *out,
- long length,DES_key_schedule *ks1,
- DES_key_schedule *ks2,DES_key_schedule *ks3,
- DES_cblock *ivec,int *num,int enc);
-void DES_ede3_cfb_encrypt(const unsigned char *in,unsigned char *out,
- int numbits,long length,DES_key_schedule *ks1,
- DES_key_schedule *ks2,DES_key_schedule *ks3,
- DES_cblock *ivec,int enc);
-void DES_ede3_ofb64_encrypt(const unsigned char *in,unsigned char *out,
- long length,DES_key_schedule *ks1,
- DES_key_schedule *ks2,DES_key_schedule *ks3,
- DES_cblock *ivec,int *num);
-#if 0
-void DES_xwhite_in2out(const_DES_cblock *DES_key,const_DES_cblock *in_white,
- DES_cblock *out_white);
-#endif
-
-int DES_enc_read(int fd,void *buf,int len,DES_key_schedule *sched,
- DES_cblock *iv);
-int DES_enc_write(int fd,const void *buf,int len,DES_key_schedule *sched,
- DES_cblock *iv);
-char *DES_fcrypt(const char *buf,const char *salt, char *ret);
-char *DES_crypt(const char *buf,const char *salt);
-void DES_ofb_encrypt(const unsigned char *in,unsigned char *out,int numbits,
- long length,DES_key_schedule *schedule,DES_cblock *ivec);
-void DES_pcbc_encrypt(const unsigned char *input,unsigned char *output,
- long length,DES_key_schedule *schedule,DES_cblock *ivec,
- int enc);
-DES_LONG DES_quad_cksum(const unsigned char *input,DES_cblock output[],
- long length,int out_count,DES_cblock *seed);
-int DES_random_key(DES_cblock *ret);
-void DES_set_odd_parity(DES_cblock *key);
-int DES_check_key_parity(const_DES_cblock *key);
-int DES_is_weak_key(const_DES_cblock *key);
-/* DES_set_key (= set_key = DES_key_sched = key_sched) calls
- * DES_set_key_checked if global variable DES_check_key is set,
- * DES_set_key_unchecked otherwise. */
-int DES_set_key(const_DES_cblock *key,DES_key_schedule *schedule);
-int DES_key_sched(const_DES_cblock *key,DES_key_schedule *schedule);
-int DES_set_key_checked(const_DES_cblock *key,DES_key_schedule *schedule);
-void DES_set_key_unchecked(const_DES_cblock *key,DES_key_schedule *schedule);
-#ifdef OPENSSL_FIPS
-void private_DES_set_key_unchecked(const_DES_cblock *key,DES_key_schedule *schedule);
-#endif
-void DES_string_to_key(const char *str,DES_cblock *key);
-void DES_string_to_2keys(const char *str,DES_cblock *key1,DES_cblock *key2);
-void DES_cfb64_encrypt(const unsigned char *in,unsigned char *out,long length,
- DES_key_schedule *schedule,DES_cblock *ivec,int *num,
- int enc);
-void DES_ofb64_encrypt(const unsigned char *in,unsigned char *out,long length,
- DES_key_schedule *schedule,DES_cblock *ivec,int *num);
-
-int DES_read_password(DES_cblock *key, const char *prompt, int verify);
-int DES_read_2passwords(DES_cblock *key1, DES_cblock *key2, const char *prompt,
- int verify);
-
-#define DES_fixup_key_parity DES_set_odd_parity
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/des_old.h b/drivers/builtin_openssl/openssl/des_old.h
deleted file mode 100644
index 2b2c372354..0000000000
--- a/drivers/builtin_openssl/openssl/des_old.h
+++ /dev/null
@@ -1,446 +0,0 @@
-/* crypto/des/des_old.h -*- mode:C; c-file-style: "eay" -*- */
-
-/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
- *
- * The function names in here are deprecated and are only present to
- * provide an interface compatible with openssl 0.9.6 and older as
- * well as libdes. OpenSSL now provides functions where "des_" has
- * been replaced with "DES_" in the names, to make it possible to
- * make incompatible changes that are needed for C type security and
- * other stuff.
- *
- * This include files has two compatibility modes:
- *
- * - If OPENSSL_DES_LIBDES_COMPATIBILITY is defined, you get an API
- * that is compatible with libdes and SSLeay.
- * - If OPENSSL_DES_LIBDES_COMPATIBILITY isn't defined, you get an
- * API that is compatible with OpenSSL 0.9.5x to 0.9.6x.
- *
- * Note that these modes break earlier snapshots of OpenSSL, where
- * libdes compatibility was the only available mode or (later on) the
- * prefered compatibility mode. However, after much consideration
- * (and more or less violent discussions with external parties), it
- * was concluded that OpenSSL should be compatible with earlier versions
- * of itself before anything else. Also, in all honesty, libdes is
- * an old beast that shouldn't really be used any more.
- *
- * Please consider starting to use the DES_ functions rather than the
- * des_ ones. The des_ functions will disappear completely before
- * OpenSSL 1.0!
- *
- * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
- */
-
-/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
- * project 2001.
- */
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_DES_H
-#define HEADER_DES_H
-
-#include <openssl/e_os2.h> /* OPENSSL_EXTERN, OPENSSL_NO_DES, DES_LONG */
-
-#ifdef OPENSSL_NO_DES
-#error DES is disabled.
-#endif
-
-#ifndef HEADER_NEW_DES_H
-#error You must include des.h, not des_old.h directly.
-#endif
-
-#ifdef _KERBEROS_DES_H
-#error <openssl/des_old.h> replaces <kerberos/des.h>.
-#endif
-
-#include <openssl/symhacks.h>
-
-#ifdef OPENSSL_BUILD_SHLIBCRYPTO
-# undef OPENSSL_EXTERN
-# define OPENSSL_EXTERN OPENSSL_EXPORT
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef _
-#undef _
-#endif
-
-typedef unsigned char _ossl_old_des_cblock[8];
-typedef struct _ossl_old_des_ks_struct
- {
- union {
- _ossl_old_des_cblock _;
- /* make sure things are correct size on machines with
- * 8 byte longs */
- DES_LONG pad[2];
- } ks;
- } _ossl_old_des_key_schedule[16];
-
-#ifndef OPENSSL_DES_LIBDES_COMPATIBILITY
-#define des_cblock DES_cblock
-#define const_des_cblock const_DES_cblock
-#define des_key_schedule DES_key_schedule
-#define des_ecb3_encrypt(i,o,k1,k2,k3,e)\
- DES_ecb3_encrypt((i),(o),&(k1),&(k2),&(k3),(e))
-#define des_ede3_cbc_encrypt(i,o,l,k1,k2,k3,iv,e)\
- DES_ede3_cbc_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(e))
-#define des_ede3_cbcm_encrypt(i,o,l,k1,k2,k3,iv1,iv2,e)\
- DES_ede3_cbcm_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv1),(iv2),(e))
-#define des_ede3_cfb64_encrypt(i,o,l,k1,k2,k3,iv,n,e)\
- DES_ede3_cfb64_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(n),(e))
-#define des_ede3_ofb64_encrypt(i,o,l,k1,k2,k3,iv,n)\
- DES_ede3_ofb64_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(n))
-#define des_options()\
- DES_options()
-#define des_cbc_cksum(i,o,l,k,iv)\
- DES_cbc_cksum((i),(o),(l),&(k),(iv))
-#define des_cbc_encrypt(i,o,l,k,iv,e)\
- DES_cbc_encrypt((i),(o),(l),&(k),(iv),(e))
-#define des_ncbc_encrypt(i,o,l,k,iv,e)\
- DES_ncbc_encrypt((i),(o),(l),&(k),(iv),(e))
-#define des_xcbc_encrypt(i,o,l,k,iv,inw,outw,e)\
- DES_xcbc_encrypt((i),(o),(l),&(k),(iv),(inw),(outw),(e))
-#define des_cfb_encrypt(i,o,n,l,k,iv,e)\
- DES_cfb_encrypt((i),(o),(n),(l),&(k),(iv),(e))
-#define des_ecb_encrypt(i,o,k,e)\
- DES_ecb_encrypt((i),(o),&(k),(e))
-#define des_encrypt1(d,k,e)\
- DES_encrypt1((d),&(k),(e))
-#define des_encrypt2(d,k,e)\
- DES_encrypt2((d),&(k),(e))
-#define des_encrypt3(d,k1,k2,k3)\
- DES_encrypt3((d),&(k1),&(k2),&(k3))
-#define des_decrypt3(d,k1,k2,k3)\
- DES_decrypt3((d),&(k1),&(k2),&(k3))
-#define des_xwhite_in2out(k,i,o)\
- DES_xwhite_in2out((k),(i),(o))
-#define des_enc_read(f,b,l,k,iv)\
- DES_enc_read((f),(b),(l),&(k),(iv))
-#define des_enc_write(f,b,l,k,iv)\
- DES_enc_write((f),(b),(l),&(k),(iv))
-#define des_fcrypt(b,s,r)\
- DES_fcrypt((b),(s),(r))
-#if 0
-#define des_crypt(b,s)\
- DES_crypt((b),(s))
-#if !defined(PERL5) && !defined(__FreeBSD__) && !defined(NeXT) && !defined(__OpenBSD__)
-#define crypt(b,s)\
- DES_crypt((b),(s))
-#endif
-#endif
-#define des_ofb_encrypt(i,o,n,l,k,iv)\
- DES_ofb_encrypt((i),(o),(n),(l),&(k),(iv))
-#define des_pcbc_encrypt(i,o,l,k,iv,e)\
- DES_pcbc_encrypt((i),(o),(l),&(k),(iv),(e))
-#define des_quad_cksum(i,o,l,c,s)\
- DES_quad_cksum((i),(o),(l),(c),(s))
-#define des_random_seed(k)\
- _ossl_096_des_random_seed((k))
-#define des_random_key(r)\
- DES_random_key((r))
-#define des_read_password(k,p,v) \
- DES_read_password((k),(p),(v))
-#define des_read_2passwords(k1,k2,p,v) \
- DES_read_2passwords((k1),(k2),(p),(v))
-#define des_set_odd_parity(k)\
- DES_set_odd_parity((k))
-#define des_check_key_parity(k)\
- DES_check_key_parity((k))
-#define des_is_weak_key(k)\
- DES_is_weak_key((k))
-#define des_set_key(k,ks)\
- DES_set_key((k),&(ks))
-#define des_key_sched(k,ks)\
- DES_key_sched((k),&(ks))
-#define des_set_key_checked(k,ks)\
- DES_set_key_checked((k),&(ks))
-#define des_set_key_unchecked(k,ks)\
- DES_set_key_unchecked((k),&(ks))
-#define des_string_to_key(s,k)\
- DES_string_to_key((s),(k))
-#define des_string_to_2keys(s,k1,k2)\
- DES_string_to_2keys((s),(k1),(k2))
-#define des_cfb64_encrypt(i,o,l,ks,iv,n,e)\
- DES_cfb64_encrypt((i),(o),(l),&(ks),(iv),(n),(e))
-#define des_ofb64_encrypt(i,o,l,ks,iv,n)\
- DES_ofb64_encrypt((i),(o),(l),&(ks),(iv),(n))
-
-
-#define des_ecb2_encrypt(i,o,k1,k2,e) \
- des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
-
-#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
- des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
-
-#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
- des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
-
-#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
- des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
-
-#define des_check_key DES_check_key
-#define des_rw_mode DES_rw_mode
-#else /* libdes compatibility */
-/* Map all symbol names to _ossl_old_des_* form, so we avoid all
- clashes with libdes */
-#define des_cblock _ossl_old_des_cblock
-#define des_key_schedule _ossl_old_des_key_schedule
-#define des_ecb3_encrypt(i,o,k1,k2,k3,e)\
- _ossl_old_des_ecb3_encrypt((i),(o),(k1),(k2),(k3),(e))
-#define des_ede3_cbc_encrypt(i,o,l,k1,k2,k3,iv,e)\
- _ossl_old_des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(e))
-#define des_ede3_cfb64_encrypt(i,o,l,k1,k2,k3,iv,n,e)\
- _ossl_old_des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(n),(e))
-#define des_ede3_ofb64_encrypt(i,o,l,k1,k2,k3,iv,n)\
- _ossl_old_des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(n))
-#define des_options()\
- _ossl_old_des_options()
-#define des_cbc_cksum(i,o,l,k,iv)\
- _ossl_old_des_cbc_cksum((i),(o),(l),(k),(iv))
-#define des_cbc_encrypt(i,o,l,k,iv,e)\
- _ossl_old_des_cbc_encrypt((i),(o),(l),(k),(iv),(e))
-#define des_ncbc_encrypt(i,o,l,k,iv,e)\
- _ossl_old_des_ncbc_encrypt((i),(o),(l),(k),(iv),(e))
-#define des_xcbc_encrypt(i,o,l,k,iv,inw,outw,e)\
- _ossl_old_des_xcbc_encrypt((i),(o),(l),(k),(iv),(inw),(outw),(e))
-#define des_cfb_encrypt(i,o,n,l,k,iv,e)\
- _ossl_old_des_cfb_encrypt((i),(o),(n),(l),(k),(iv),(e))
-#define des_ecb_encrypt(i,o,k,e)\
- _ossl_old_des_ecb_encrypt((i),(o),(k),(e))
-#define des_encrypt(d,k,e)\
- _ossl_old_des_encrypt((d),(k),(e))
-#define des_encrypt2(d,k,e)\
- _ossl_old_des_encrypt2((d),(k),(e))
-#define des_encrypt3(d,k1,k2,k3)\
- _ossl_old_des_encrypt3((d),(k1),(k2),(k3))
-#define des_decrypt3(d,k1,k2,k3)\
- _ossl_old_des_decrypt3((d),(k1),(k2),(k3))
-#define des_xwhite_in2out(k,i,o)\
- _ossl_old_des_xwhite_in2out((k),(i),(o))
-#define des_enc_read(f,b,l,k,iv)\
- _ossl_old_des_enc_read((f),(b),(l),(k),(iv))
-#define des_enc_write(f,b,l,k,iv)\
- _ossl_old_des_enc_write((f),(b),(l),(k),(iv))
-#define des_fcrypt(b,s,r)\
- _ossl_old_des_fcrypt((b),(s),(r))
-#define des_crypt(b,s)\
- _ossl_old_des_crypt((b),(s))
-#if 0
-#define crypt(b,s)\
- _ossl_old_crypt((b),(s))
-#endif
-#define des_ofb_encrypt(i,o,n,l,k,iv)\
- _ossl_old_des_ofb_encrypt((i),(o),(n),(l),(k),(iv))
-#define des_pcbc_encrypt(i,o,l,k,iv,e)\
- _ossl_old_des_pcbc_encrypt((i),(o),(l),(k),(iv),(e))
-#define des_quad_cksum(i,o,l,c,s)\
- _ossl_old_des_quad_cksum((i),(o),(l),(c),(s))
-#define des_random_seed(k)\
- _ossl_old_des_random_seed((k))
-#define des_random_key(r)\
- _ossl_old_des_random_key((r))
-#define des_read_password(k,p,v) \
- _ossl_old_des_read_password((k),(p),(v))
-#define des_read_2passwords(k1,k2,p,v) \
- _ossl_old_des_read_2passwords((k1),(k2),(p),(v))
-#define des_set_odd_parity(k)\
- _ossl_old_des_set_odd_parity((k))
-#define des_is_weak_key(k)\
- _ossl_old_des_is_weak_key((k))
-#define des_set_key(k,ks)\
- _ossl_old_des_set_key((k),(ks))
-#define des_key_sched(k,ks)\
- _ossl_old_des_key_sched((k),(ks))
-#define des_string_to_key(s,k)\
- _ossl_old_des_string_to_key((s),(k))
-#define des_string_to_2keys(s,k1,k2)\
- _ossl_old_des_string_to_2keys((s),(k1),(k2))
-#define des_cfb64_encrypt(i,o,l,ks,iv,n,e)\
- _ossl_old_des_cfb64_encrypt((i),(o),(l),(ks),(iv),(n),(e))
-#define des_ofb64_encrypt(i,o,l,ks,iv,n)\
- _ossl_old_des_ofb64_encrypt((i),(o),(l),(ks),(iv),(n))
-
-
-#define des_ecb2_encrypt(i,o,k1,k2,e) \
- des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
-
-#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
- des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
-
-#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
- des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
-
-#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
- des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
-
-#define des_check_key DES_check_key
-#define des_rw_mode DES_rw_mode
-#endif
-
-const char *_ossl_old_des_options(void);
-void _ossl_old_des_ecb3_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,
- _ossl_old_des_key_schedule ks1,_ossl_old_des_key_schedule ks2,
- _ossl_old_des_key_schedule ks3, int enc);
-DES_LONG _ossl_old_des_cbc_cksum(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,
- long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec);
-void _ossl_old_des_cbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length,
- _ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc);
-void _ossl_old_des_ncbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length,
- _ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc);
-void _ossl_old_des_xcbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length,
- _ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,
- _ossl_old_des_cblock *inw,_ossl_old_des_cblock *outw,int enc);
-void _ossl_old_des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits,
- long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc);
-void _ossl_old_des_ecb_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,
- _ossl_old_des_key_schedule ks,int enc);
-void _ossl_old_des_encrypt(DES_LONG *data,_ossl_old_des_key_schedule ks, int enc);
-void _ossl_old_des_encrypt2(DES_LONG *data,_ossl_old_des_key_schedule ks, int enc);
-void _ossl_old_des_encrypt3(DES_LONG *data, _ossl_old_des_key_schedule ks1,
- _ossl_old_des_key_schedule ks2, _ossl_old_des_key_schedule ks3);
-void _ossl_old_des_decrypt3(DES_LONG *data, _ossl_old_des_key_schedule ks1,
- _ossl_old_des_key_schedule ks2, _ossl_old_des_key_schedule ks3);
-void _ossl_old_des_ede3_cbc_encrypt(_ossl_old_des_cblock *input, _ossl_old_des_cblock *output,
- long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2,
- _ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int enc);
-void _ossl_old_des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out,
- long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2,
- _ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int *num, int enc);
-void _ossl_old_des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out,
- long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2,
- _ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int *num);
-#if 0
-void _ossl_old_des_xwhite_in2out(_ossl_old_des_cblock (*des_key), _ossl_old_des_cblock (*in_white),
- _ossl_old_des_cblock (*out_white));
-#endif
-
-int _ossl_old_des_enc_read(int fd,char *buf,int len,_ossl_old_des_key_schedule sched,
- _ossl_old_des_cblock *iv);
-int _ossl_old_des_enc_write(int fd,char *buf,int len,_ossl_old_des_key_schedule sched,
- _ossl_old_des_cblock *iv);
-char *_ossl_old_des_fcrypt(const char *buf,const char *salt, char *ret);
-char *_ossl_old_des_crypt(const char *buf,const char *salt);
-#if !defined(PERL5) && !defined(NeXT)
-char *_ossl_old_crypt(const char *buf,const char *salt);
-#endif
-void _ossl_old_des_ofb_encrypt(unsigned char *in,unsigned char *out,
- int numbits,long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec);
-void _ossl_old_des_pcbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length,
- _ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc);
-DES_LONG _ossl_old_des_quad_cksum(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,
- long length,int out_count,_ossl_old_des_cblock *seed);
-void _ossl_old_des_random_seed(_ossl_old_des_cblock key);
-void _ossl_old_des_random_key(_ossl_old_des_cblock ret);
-int _ossl_old_des_read_password(_ossl_old_des_cblock *key,const char *prompt,int verify);
-int _ossl_old_des_read_2passwords(_ossl_old_des_cblock *key1,_ossl_old_des_cblock *key2,
- const char *prompt,int verify);
-void _ossl_old_des_set_odd_parity(_ossl_old_des_cblock *key);
-int _ossl_old_des_is_weak_key(_ossl_old_des_cblock *key);
-int _ossl_old_des_set_key(_ossl_old_des_cblock *key,_ossl_old_des_key_schedule schedule);
-int _ossl_old_des_key_sched(_ossl_old_des_cblock *key,_ossl_old_des_key_schedule schedule);
-void _ossl_old_des_string_to_key(char *str,_ossl_old_des_cblock *key);
-void _ossl_old_des_string_to_2keys(char *str,_ossl_old_des_cblock *key1,_ossl_old_des_cblock *key2);
-void _ossl_old_des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length,
- _ossl_old_des_key_schedule schedule, _ossl_old_des_cblock *ivec, int *num, int enc);
-void _ossl_old_des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length,
- _ossl_old_des_key_schedule schedule, _ossl_old_des_cblock *ivec, int *num);
-
-void _ossl_096_des_random_seed(des_cblock *key);
-
-/* The following definitions provide compatibility with the MIT Kerberos
- * library. The _ossl_old_des_key_schedule structure is not binary compatible. */
-
-#define _KERBEROS_DES_H
-
-#define KRBDES_ENCRYPT DES_ENCRYPT
-#define KRBDES_DECRYPT DES_DECRYPT
-
-#ifdef KERBEROS
-# define ENCRYPT DES_ENCRYPT
-# define DECRYPT DES_DECRYPT
-#endif
-
-#ifndef NCOMPAT
-# define C_Block des_cblock
-# define Key_schedule des_key_schedule
-# define KEY_SZ DES_KEY_SZ
-# define string_to_key des_string_to_key
-# define read_pw_string des_read_pw_string
-# define random_key des_random_key
-# define pcbc_encrypt des_pcbc_encrypt
-# define set_key des_set_key
-# define key_sched des_key_sched
-# define ecb_encrypt des_ecb_encrypt
-# define cbc_encrypt des_cbc_encrypt
-# define ncbc_encrypt des_ncbc_encrypt
-# define xcbc_encrypt des_xcbc_encrypt
-# define cbc_cksum des_cbc_cksum
-# define quad_cksum des_quad_cksum
-# define check_parity des_check_key_parity
-#endif
-
-#define des_fixup_key_parity DES_fixup_key_parity
-
-#ifdef __cplusplus
-}
-#endif
-
-/* for DES_read_pw_string et al */
-#include <openssl/ui_compat.h>
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/dh.h b/drivers/builtin_openssl/openssl/dh.h
deleted file mode 100644
index ea59e610ef..0000000000
--- a/drivers/builtin_openssl/openssl/dh.h
+++ /dev/null
@@ -1,280 +0,0 @@
-/* crypto/dh/dh.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_DH_H
-#define HEADER_DH_H
-
-#include <openssl/e_os2.h>
-
-#ifdef OPENSSL_NO_DH
-#error DH is disabled.
-#endif
-
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#include <openssl/ossl_typ.h>
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/bn.h>
-#endif
-
-#ifndef OPENSSL_DH_MAX_MODULUS_BITS
-# define OPENSSL_DH_MAX_MODULUS_BITS 10000
-#endif
-
-#define DH_FLAG_CACHE_MONT_P 0x01
-#define DH_FLAG_NO_EXP_CONSTTIME 0x02 /* new with 0.9.7h; the built-in DH
- * implementation now uses constant time
- * modular exponentiation for secret exponents
- * by default. This flag causes the
- * faster variable sliding window method to
- * be used for all exponents.
- */
-
-/* If this flag is set the DH method is FIPS compliant and can be used
- * in FIPS mode. This is set in the validated module method. If an
- * application sets this flag in its own methods it is its reposibility
- * to ensure the result is compliant.
- */
-
-#define DH_FLAG_FIPS_METHOD 0x0400
-
-/* If this flag is set the operations normally disabled in FIPS mode are
- * permitted it is then the applications responsibility to ensure that the
- * usage is compliant.
- */
-
-#define DH_FLAG_NON_FIPS_ALLOW 0x0400
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Already defined in ossl_typ.h */
-/* typedef struct dh_st DH; */
-/* typedef struct dh_method DH_METHOD; */
-
-struct dh_method
- {
- const char *name;
- /* Methods here */
- int (*generate_key)(DH *dh);
- int (*compute_key)(unsigned char *key,const BIGNUM *pub_key,DH *dh);
- int (*bn_mod_exp)(const DH *dh, BIGNUM *r, const BIGNUM *a,
- const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
- BN_MONT_CTX *m_ctx); /* Can be null */
-
- int (*init)(DH *dh);
- int (*finish)(DH *dh);
- int flags;
- char *app_data;
- /* If this is non-NULL, it will be used to generate parameters */
- int (*generate_params)(DH *dh, int prime_len, int generator, BN_GENCB *cb);
- };
-
-struct dh_st
- {
- /* This first argument is used to pick up errors when
- * a DH is passed instead of a EVP_PKEY */
- int pad;
- int version;
- BIGNUM *p;
- BIGNUM *g;
- long length; /* optional */
- BIGNUM *pub_key; /* g^x */
- BIGNUM *priv_key; /* x */
-
- int flags;
- BN_MONT_CTX *method_mont_p;
- /* Place holders if we want to do X9.42 DH */
- BIGNUM *q;
- BIGNUM *j;
- unsigned char *seed;
- int seedlen;
- BIGNUM *counter;
-
- int references;
- CRYPTO_EX_DATA ex_data;
- const DH_METHOD *meth;
- ENGINE *engine;
- };
-
-#define DH_GENERATOR_2 2
-/* #define DH_GENERATOR_3 3 */
-#define DH_GENERATOR_5 5
-
-/* DH_check error codes */
-#define DH_CHECK_P_NOT_PRIME 0x01
-#define DH_CHECK_P_NOT_SAFE_PRIME 0x02
-#define DH_UNABLE_TO_CHECK_GENERATOR 0x04
-#define DH_NOT_SUITABLE_GENERATOR 0x08
-
-/* DH_check_pub_key error codes */
-#define DH_CHECK_PUBKEY_TOO_SMALL 0x01
-#define DH_CHECK_PUBKEY_TOO_LARGE 0x02
-
-/* primes p where (p-1)/2 is prime too are called "safe"; we define
- this for backward compatibility: */
-#define DH_CHECK_P_NOT_STRONG_PRIME DH_CHECK_P_NOT_SAFE_PRIME
-
-#define d2i_DHparams_fp(fp,x) (DH *)ASN1_d2i_fp((char *(*)())DH_new, \
- (char *(*)())d2i_DHparams,(fp),(unsigned char **)(x))
-#define i2d_DHparams_fp(fp,x) ASN1_i2d_fp(i2d_DHparams,(fp), \
- (unsigned char *)(x))
-#define d2i_DHparams_bio(bp,x) ASN1_d2i_bio_of(DH,DH_new,d2i_DHparams,bp,x)
-#define i2d_DHparams_bio(bp,x) ASN1_i2d_bio_of_const(DH,i2d_DHparams,bp,x)
-
-DH *DHparams_dup(DH *);
-
-const DH_METHOD *DH_OpenSSL(void);
-
-void DH_set_default_method(const DH_METHOD *meth);
-const DH_METHOD *DH_get_default_method(void);
-int DH_set_method(DH *dh, const DH_METHOD *meth);
-DH *DH_new_method(ENGINE *engine);
-
-DH * DH_new(void);
-void DH_free(DH *dh);
-int DH_up_ref(DH *dh);
-int DH_size(const DH *dh);
-int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int DH_set_ex_data(DH *d, int idx, void *arg);
-void *DH_get_ex_data(DH *d, int idx);
-
-/* Deprecated version */
-#ifndef OPENSSL_NO_DEPRECATED
-DH * DH_generate_parameters(int prime_len,int generator,
- void (*callback)(int,int,void *),void *cb_arg);
-#endif /* !defined(OPENSSL_NO_DEPRECATED) */
-
-/* New version */
-int DH_generate_parameters_ex(DH *dh, int prime_len,int generator, BN_GENCB *cb);
-
-int DH_check(const DH *dh,int *codes);
-int DH_check_pub_key(const DH *dh,const BIGNUM *pub_key, int *codes);
-int DH_generate_key(DH *dh);
-int DH_compute_key(unsigned char *key,const BIGNUM *pub_key,DH *dh);
-DH * d2i_DHparams(DH **a,const unsigned char **pp, long length);
-int i2d_DHparams(const DH *a,unsigned char **pp);
-#ifndef OPENSSL_NO_FP_API
-int DHparams_print_fp(FILE *fp, const DH *x);
-#endif
-#ifndef OPENSSL_NO_BIO
-int DHparams_print(BIO *bp, const DH *x);
-#else
-int DHparams_print(char *bp, const DH *x);
-#endif
-
-#define EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, \
- EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN, len, NULL)
-
-#define EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, gen) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, \
- EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR, gen, NULL)
-
-#define EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN (EVP_PKEY_ALG_CTRL + 1)
-#define EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR (EVP_PKEY_ALG_CTRL + 2)
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_DH_strings(void);
-
-/* Error codes for the DH functions. */
-
-/* Function codes. */
-#define DH_F_COMPUTE_KEY 102
-#define DH_F_DHPARAMS_PRINT_FP 101
-#define DH_F_DH_BUILTIN_GENPARAMS 106
-#define DH_F_DH_COMPUTE_KEY 114
-#define DH_F_DH_GENERATE_KEY 115
-#define DH_F_DH_GENERATE_PARAMETERS_EX 116
-#define DH_F_DH_NEW_METHOD 105
-#define DH_F_DH_PARAM_DECODE 107
-#define DH_F_DH_PRIV_DECODE 110
-#define DH_F_DH_PRIV_ENCODE 111
-#define DH_F_DH_PUB_DECODE 108
-#define DH_F_DH_PUB_ENCODE 109
-#define DH_F_DO_DH_PRINT 100
-#define DH_F_GENERATE_KEY 103
-#define DH_F_GENERATE_PARAMETERS 104
-#define DH_F_PKEY_DH_DERIVE 112
-#define DH_F_PKEY_DH_KEYGEN 113
-
-/* Reason codes. */
-#define DH_R_BAD_GENERATOR 101
-#define DH_R_BN_DECODE_ERROR 109
-#define DH_R_BN_ERROR 106
-#define DH_R_DECODE_ERROR 104
-#define DH_R_INVALID_PUBKEY 102
-#define DH_R_KEYS_NOT_SET 108
-#define DH_R_KEY_SIZE_TOO_SMALL 110
-#define DH_R_MODULUS_TOO_LARGE 103
-#define DH_R_NON_FIPS_METHOD 111
-#define DH_R_NO_PARAMETERS_SET 107
-#define DH_R_NO_PRIVATE_VALUE 100
-#define DH_R_PARAMETER_ENCODING_ERROR 105
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/dsa.h b/drivers/builtin_openssl/openssl/dsa.h
deleted file mode 100644
index a6f6d0b0b2..0000000000
--- a/drivers/builtin_openssl/openssl/dsa.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/* crypto/dsa/dsa.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-/*
- * The DSS routines are based on patches supplied by
- * Steven Schoch <schoch@sheba.arc.nasa.gov>. He basically did the
- * work and I have just tweaked them a little to fit into my
- * stylistic vision for SSLeay :-) */
-
-#ifndef HEADER_DSA_H
-#define HEADER_DSA_H
-
-#include <openssl/e_os2.h>
-
-#ifdef OPENSSL_NO_DSA
-#error DSA is disabled.
-#endif
-
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#include <openssl/crypto.h>
-#include <openssl/ossl_typ.h>
-
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-#endif
-
-#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
-# define OPENSSL_DSA_MAX_MODULUS_BITS 10000
-#endif
-
-#define DSA_FLAG_CACHE_MONT_P 0x01
-#define DSA_FLAG_NO_EXP_CONSTTIME 0x02 /* new with 0.9.7h; the built-in DSA
- * implementation now uses constant time
- * modular exponentiation for secret exponents
- * by default. This flag causes the
- * faster variable sliding window method to
- * be used for all exponents.
- */
-
-/* If this flag is set the DSA method is FIPS compliant and can be used
- * in FIPS mode. This is set in the validated module method. If an
- * application sets this flag in its own methods it is its reposibility
- * to ensure the result is compliant.
- */
-
-#define DSA_FLAG_FIPS_METHOD 0x0400
-
-/* If this flag is set the operations normally disabled in FIPS mode are
- * permitted it is then the applications responsibility to ensure that the
- * usage is compliant.
- */
-
-#define DSA_FLAG_NON_FIPS_ALLOW 0x0400
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Already defined in ossl_typ.h */
-/* typedef struct dsa_st DSA; */
-/* typedef struct dsa_method DSA_METHOD; */
-
-typedef struct DSA_SIG_st
- {
- BIGNUM *r;
- BIGNUM *s;
- } DSA_SIG;
-
-struct dsa_method
- {
- const char *name;
- DSA_SIG * (*dsa_do_sign)(const unsigned char *dgst, int dlen, DSA *dsa);
- int (*dsa_sign_setup)(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
- BIGNUM **rp);
- int (*dsa_do_verify)(const unsigned char *dgst, int dgst_len,
- DSA_SIG *sig, DSA *dsa);
- int (*dsa_mod_exp)(DSA *dsa, BIGNUM *rr, BIGNUM *a1, BIGNUM *p1,
- BIGNUM *a2, BIGNUM *p2, BIGNUM *m, BN_CTX *ctx,
- BN_MONT_CTX *in_mont);
- int (*bn_mod_exp)(DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx,
- BN_MONT_CTX *m_ctx); /* Can be null */
- int (*init)(DSA *dsa);
- int (*finish)(DSA *dsa);
- int flags;
- char *app_data;
- /* If this is non-NULL, it is used to generate DSA parameters */
- int (*dsa_paramgen)(DSA *dsa, int bits,
- const unsigned char *seed, int seed_len,
- int *counter_ret, unsigned long *h_ret,
- BN_GENCB *cb);
- /* If this is non-NULL, it is used to generate DSA keys */
- int (*dsa_keygen)(DSA *dsa);
- };
-
-struct dsa_st
- {
- /* This first variable is used to pick up errors where
- * a DSA is passed instead of of a EVP_PKEY */
- int pad;
- long version;
- int write_params;
- BIGNUM *p;
- BIGNUM *q; /* == 20 */
- BIGNUM *g;
-
- BIGNUM *pub_key; /* y public key */
- BIGNUM *priv_key; /* x private key */
-
- BIGNUM *kinv; /* Signing pre-calc */
- BIGNUM *r; /* Signing pre-calc */
-
- int flags;
- /* Normally used to cache montgomery values */
- BN_MONT_CTX *method_mont_p;
- int references;
- CRYPTO_EX_DATA ex_data;
- const DSA_METHOD *meth;
- /* functional reference if 'meth' is ENGINE-provided */
- ENGINE *engine;
- };
-
-#define d2i_DSAparams_fp(fp,x) (DSA *)ASN1_d2i_fp((char *(*)())DSA_new, \
- (char *(*)())d2i_DSAparams,(fp),(unsigned char **)(x))
-#define i2d_DSAparams_fp(fp,x) ASN1_i2d_fp(i2d_DSAparams,(fp), \
- (unsigned char *)(x))
-#define d2i_DSAparams_bio(bp,x) ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSAparams,bp,x)
-#define i2d_DSAparams_bio(bp,x) ASN1_i2d_bio_of_const(DSA,i2d_DSAparams,bp,x)
-
-
-DSA *DSAparams_dup(DSA *x);
-DSA_SIG * DSA_SIG_new(void);
-void DSA_SIG_free(DSA_SIG *a);
-int i2d_DSA_SIG(const DSA_SIG *a, unsigned char **pp);
-DSA_SIG * d2i_DSA_SIG(DSA_SIG **v, const unsigned char **pp, long length);
-
-DSA_SIG * DSA_do_sign(const unsigned char *dgst,int dlen,DSA *dsa);
-int DSA_do_verify(const unsigned char *dgst,int dgst_len,
- DSA_SIG *sig,DSA *dsa);
-
-const DSA_METHOD *DSA_OpenSSL(void);
-
-void DSA_set_default_method(const DSA_METHOD *);
-const DSA_METHOD *DSA_get_default_method(void);
-int DSA_set_method(DSA *dsa, const DSA_METHOD *);
-
-DSA * DSA_new(void);
-DSA * DSA_new_method(ENGINE *engine);
-void DSA_free (DSA *r);
-/* "up" the DSA object's reference count */
-int DSA_up_ref(DSA *r);
-int DSA_size(const DSA *);
- /* next 4 return -1 on error */
-int DSA_sign_setup( DSA *dsa,BN_CTX *ctx_in,BIGNUM **kinvp,BIGNUM **rp);
-int DSA_sign(int type,const unsigned char *dgst,int dlen,
- unsigned char *sig, unsigned int *siglen, DSA *dsa);
-int DSA_verify(int type,const unsigned char *dgst,int dgst_len,
- const unsigned char *sigbuf, int siglen, DSA *dsa);
-int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int DSA_set_ex_data(DSA *d, int idx, void *arg);
-void *DSA_get_ex_data(DSA *d, int idx);
-
-DSA * d2i_DSAPublicKey(DSA **a, const unsigned char **pp, long length);
-DSA * d2i_DSAPrivateKey(DSA **a, const unsigned char **pp, long length);
-DSA * d2i_DSAparams(DSA **a, const unsigned char **pp, long length);
-
-/* Deprecated version */
-#ifndef OPENSSL_NO_DEPRECATED
-DSA * DSA_generate_parameters(int bits,
- unsigned char *seed,int seed_len,
- int *counter_ret, unsigned long *h_ret,void
- (*callback)(int, int, void *),void *cb_arg);
-#endif /* !defined(OPENSSL_NO_DEPRECATED) */
-
-/* New version */
-int DSA_generate_parameters_ex(DSA *dsa, int bits,
- const unsigned char *seed,int seed_len,
- int *counter_ret, unsigned long *h_ret, BN_GENCB *cb);
-
-int DSA_generate_key(DSA *a);
-int i2d_DSAPublicKey(const DSA *a, unsigned char **pp);
-int i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
-int i2d_DSAparams(const DSA *a,unsigned char **pp);
-
-#ifndef OPENSSL_NO_BIO
-int DSAparams_print(BIO *bp, const DSA *x);
-int DSA_print(BIO *bp, const DSA *x, int off);
-#endif
-#ifndef OPENSSL_NO_FP_API
-int DSAparams_print_fp(FILE *fp, const DSA *x);
-int DSA_print_fp(FILE *bp, const DSA *x, int off);
-#endif
-
-#define DSS_prime_checks 50
-/* Primality test according to FIPS PUB 186[-1], Appendix 2.1:
- * 50 rounds of Rabin-Miller */
-#define DSA_is_prime(n, callback, cb_arg) \
- BN_is_prime(n, DSS_prime_checks, callback, NULL, cb_arg)
-
-#ifndef OPENSSL_NO_DH
-/* Convert DSA structure (key or just parameters) into DH structure
- * (be careful to avoid small subgroup attacks when using this!) */
-DH *DSA_dup_DH(const DSA *r);
-#endif
-
-#define EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, nbits) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, \
- EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, nbits, NULL)
-
-#define EVP_PKEY_CTRL_DSA_PARAMGEN_BITS (EVP_PKEY_ALG_CTRL + 1)
-#define EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS (EVP_PKEY_ALG_CTRL + 2)
-#define EVP_PKEY_CTRL_DSA_PARAMGEN_MD (EVP_PKEY_ALG_CTRL + 3)
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_DSA_strings(void);
-
-/* Error codes for the DSA functions. */
-
-/* Function codes. */
-#define DSA_F_D2I_DSA_SIG 110
-#define DSA_F_DO_DSA_PRINT 104
-#define DSA_F_DSAPARAMS_PRINT 100
-#define DSA_F_DSAPARAMS_PRINT_FP 101
-#define DSA_F_DSA_DO_SIGN 112
-#define DSA_F_DSA_DO_VERIFY 113
-#define DSA_F_DSA_GENERATE_KEY 124
-#define DSA_F_DSA_GENERATE_PARAMETERS_EX 123
-#define DSA_F_DSA_NEW_METHOD 103
-#define DSA_F_DSA_PARAM_DECODE 119
-#define DSA_F_DSA_PRINT_FP 105
-#define DSA_F_DSA_PRIV_DECODE 115
-#define DSA_F_DSA_PRIV_ENCODE 116
-#define DSA_F_DSA_PUB_DECODE 117
-#define DSA_F_DSA_PUB_ENCODE 118
-#define DSA_F_DSA_SIGN 106
-#define DSA_F_DSA_SIGN_SETUP 107
-#define DSA_F_DSA_SIG_NEW 109
-#define DSA_F_DSA_SIG_PRINT 125
-#define DSA_F_DSA_VERIFY 108
-#define DSA_F_I2D_DSA_SIG 111
-#define DSA_F_OLD_DSA_PRIV_DECODE 122
-#define DSA_F_PKEY_DSA_CTRL 120
-#define DSA_F_PKEY_DSA_KEYGEN 121
-#define DSA_F_SIG_CB 114
-
-/* Reason codes. */
-#define DSA_R_BAD_Q_VALUE 102
-#define DSA_R_BN_DECODE_ERROR 108
-#define DSA_R_BN_ERROR 109
-#define DSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 100
-#define DSA_R_DECODE_ERROR 104
-#define DSA_R_INVALID_DIGEST_TYPE 106
-#define DSA_R_MISSING_PARAMETERS 101
-#define DSA_R_MODULUS_TOO_LARGE 103
-#define DSA_R_NEED_NEW_SETUP_VALUES 110
-#define DSA_R_NON_FIPS_DSA_METHOD 111
-#define DSA_R_NO_PARAMETERS_SET 107
-#define DSA_R_PARAMETER_ENCODING_ERROR 105
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/dso.h b/drivers/builtin_openssl/openssl/dso.h
deleted file mode 100644
index 839f2e0617..0000000000
--- a/drivers/builtin_openssl/openssl/dso.h
+++ /dev/null
@@ -1,409 +0,0 @@
-/* dso.h -*- mode:C; c-file-style: "eay" -*- */
-/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
- * project 2000.
- */
-/* ====================================================================
- * Copyright (c) 2000 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_DSO_H
-#define HEADER_DSO_H
-
-#include <openssl/crypto.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* These values are used as commands to DSO_ctrl() */
-#define DSO_CTRL_GET_FLAGS 1
-#define DSO_CTRL_SET_FLAGS 2
-#define DSO_CTRL_OR_FLAGS 3
-
-/* By default, DSO_load() will translate the provided filename into a form
- * typical for the platform (more specifically the DSO_METHOD) using the
- * dso_name_converter function of the method. Eg. win32 will transform "blah"
- * into "blah.dll", and dlfcn will transform it into "libblah.so". The
- * behaviour can be overriden by setting the name_converter callback in the DSO
- * object (using DSO_set_name_converter()). This callback could even utilise
- * the DSO_METHOD's converter too if it only wants to override behaviour for
- * one or two possible DSO methods. However, the following flag can be set in a
- * DSO to prevent *any* native name-translation at all - eg. if the caller has
- * prompted the user for a path to a driver library so the filename should be
- * interpreted as-is. */
-#define DSO_FLAG_NO_NAME_TRANSLATION 0x01
-/* An extra flag to give if only the extension should be added as
- * translation. This is obviously only of importance on Unix and
- * other operating systems where the translation also may prefix
- * the name with something, like 'lib', and ignored everywhere else.
- * This flag is also ignored if DSO_FLAG_NO_NAME_TRANSLATION is used
- * at the same time. */
-#define DSO_FLAG_NAME_TRANSLATION_EXT_ONLY 0x02
-
-/* The following flag controls the translation of symbol names to upper
- * case. This is currently only being implemented for OpenVMS.
- */
-#define DSO_FLAG_UPCASE_SYMBOL 0x10
-
-/* This flag loads the library with public symbols.
- * Meaning: The exported symbols of this library are public
- * to all libraries loaded after this library.
- * At the moment only implemented in unix.
- */
-#define DSO_FLAG_GLOBAL_SYMBOLS 0x20
-
-
-typedef void (*DSO_FUNC_TYPE)(void);
-
-typedef struct dso_st DSO;
-
-/* The function prototype used for method functions (or caller-provided
- * callbacks) that transform filenames. They are passed a DSO structure pointer
- * (or NULL if they are to be used independantly of a DSO object) and a
- * filename to transform. They should either return NULL (if there is an error
- * condition) or a newly allocated string containing the transformed form that
- * the caller will need to free with OPENSSL_free() when done. */
-typedef char* (*DSO_NAME_CONVERTER_FUNC)(DSO *, const char *);
-/* The function prototype used for method functions (or caller-provided
- * callbacks) that merge two file specifications. They are passed a
- * DSO structure pointer (or NULL if they are to be used independantly of
- * a DSO object) and two file specifications to merge. They should
- * either return NULL (if there is an error condition) or a newly allocated
- * string containing the result of merging that the caller will need
- * to free with OPENSSL_free() when done.
- * Here, merging means that bits and pieces are taken from each of the
- * file specifications and added together in whatever fashion that is
- * sensible for the DSO method in question. The only rule that really
- * applies is that if the two specification contain pieces of the same
- * type, the copy from the first string takes priority. One could see
- * it as the first specification is the one given by the user and the
- * second being a bunch of defaults to add on if they're missing in the
- * first. */
-typedef char* (*DSO_MERGER_FUNC)(DSO *, const char *, const char *);
-
-typedef struct dso_meth_st
- {
- const char *name;
- /* Loads a shared library, NB: new DSO_METHODs must ensure that a
- * successful load populates the loaded_filename field, and likewise a
- * successful unload OPENSSL_frees and NULLs it out. */
- int (*dso_load)(DSO *dso);
- /* Unloads a shared library */
- int (*dso_unload)(DSO *dso);
- /* Binds a variable */
- void *(*dso_bind_var)(DSO *dso, const char *symname);
- /* Binds a function - assumes a return type of DSO_FUNC_TYPE.
- * This should be cast to the real function prototype by the
- * caller. Platforms that don't have compatible representations
- * for different prototypes (this is possible within ANSI C)
- * are highly unlikely to have shared libraries at all, let
- * alone a DSO_METHOD implemented for them. */
- DSO_FUNC_TYPE (*dso_bind_func)(DSO *dso, const char *symname);
-
-/* I don't think this would actually be used in any circumstances. */
-#if 0
- /* Unbinds a variable */
- int (*dso_unbind_var)(DSO *dso, char *symname, void *symptr);
- /* Unbinds a function */
- int (*dso_unbind_func)(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
-#endif
- /* The generic (yuck) "ctrl()" function. NB: Negative return
- * values (rather than zero) indicate errors. */
- long (*dso_ctrl)(DSO *dso, int cmd, long larg, void *parg);
- /* The default DSO_METHOD-specific function for converting filenames to
- * a canonical native form. */
- DSO_NAME_CONVERTER_FUNC dso_name_converter;
- /* The default DSO_METHOD-specific function for converting filenames to
- * a canonical native form. */
- DSO_MERGER_FUNC dso_merger;
-
- /* [De]Initialisation handlers. */
- int (*init)(DSO *dso);
- int (*finish)(DSO *dso);
-
- /* Return pathname of the module containing location */
- int (*pathbyaddr)(void *addr,char *path,int sz);
- /* Perform global symbol lookup, i.e. among *all* modules */
- void *(*globallookup)(const char *symname);
- } DSO_METHOD;
-
-/**********************************************************************/
-/* The low-level handle type used to refer to a loaded shared library */
-
-struct dso_st
- {
- DSO_METHOD *meth;
- /* Standard dlopen uses a (void *). Win32 uses a HANDLE. VMS
- * doesn't use anything but will need to cache the filename
- * for use in the dso_bind handler. All in all, let each
- * method control its own destiny. "Handles" and such go in
- * a STACK. */
- STACK_OF(void) *meth_data;
- int references;
- int flags;
- /* For use by applications etc ... use this for your bits'n'pieces,
- * don't touch meth_data! */
- CRYPTO_EX_DATA ex_data;
- /* If this callback function pointer is set to non-NULL, then it will
- * be used in DSO_load() in place of meth->dso_name_converter. NB: This
- * should normally set using DSO_set_name_converter(). */
- DSO_NAME_CONVERTER_FUNC name_converter;
- /* If this callback function pointer is set to non-NULL, then it will
- * be used in DSO_load() in place of meth->dso_merger. NB: This
- * should normally set using DSO_set_merger(). */
- DSO_MERGER_FUNC merger;
- /* This is populated with (a copy of) the platform-independant
- * filename used for this DSO. */
- char *filename;
- /* This is populated with (a copy of) the translated filename by which
- * the DSO was actually loaded. It is NULL iff the DSO is not currently
- * loaded. NB: This is here because the filename translation process
- * may involve a callback being invoked more than once not only to
- * convert to a platform-specific form, but also to try different
- * filenames in the process of trying to perform a load. As such, this
- * variable can be used to indicate (a) whether this DSO structure
- * corresponds to a loaded library or not, and (b) the filename with
- * which it was actually loaded. */
- char *loaded_filename;
- };
-
-
-DSO * DSO_new(void);
-DSO * DSO_new_method(DSO_METHOD *method);
-int DSO_free(DSO *dso);
-int DSO_flags(DSO *dso);
-int DSO_up_ref(DSO *dso);
-long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg);
-
-/* This function sets the DSO's name_converter callback. If it is non-NULL,
- * then it will be used instead of the associated DSO_METHOD's function. If
- * oldcb is non-NULL then it is set to the function pointer value being
- * replaced. Return value is non-zero for success. */
-int DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb,
- DSO_NAME_CONVERTER_FUNC *oldcb);
-/* These functions can be used to get/set the platform-independant filename
- * used for a DSO. NB: set will fail if the DSO is already loaded. */
-const char *DSO_get_filename(DSO *dso);
-int DSO_set_filename(DSO *dso, const char *filename);
-/* This function will invoke the DSO's name_converter callback to translate a
- * filename, or if the callback isn't set it will instead use the DSO_METHOD's
- * converter. If "filename" is NULL, the "filename" in the DSO itself will be
- * used. If the DSO_FLAG_NO_NAME_TRANSLATION flag is set, then the filename is
- * simply duplicated. NB: This function is usually called from within a
- * DSO_METHOD during the processing of a DSO_load() call, and is exposed so that
- * caller-created DSO_METHODs can do the same thing. A non-NULL return value
- * will need to be OPENSSL_free()'d. */
-char *DSO_convert_filename(DSO *dso, const char *filename);
-/* This function will invoke the DSO's merger callback to merge two file
- * specifications, or if the callback isn't set it will instead use the
- * DSO_METHOD's merger. A non-NULL return value will need to be
- * OPENSSL_free()'d. */
-char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2);
-/* If the DSO is currently loaded, this returns the filename that it was loaded
- * under, otherwise it returns NULL. So it is also useful as a test as to
- * whether the DSO is currently loaded. NB: This will not necessarily return
- * the same value as DSO_convert_filename(dso, dso->filename), because the
- * DSO_METHOD's load function may have tried a variety of filenames (with
- * and/or without the aid of the converters) before settling on the one it
- * actually loaded. */
-const char *DSO_get_loaded_filename(DSO *dso);
-
-void DSO_set_default_method(DSO_METHOD *meth);
-DSO_METHOD *DSO_get_default_method(void);
-DSO_METHOD *DSO_get_method(DSO *dso);
-DSO_METHOD *DSO_set_method(DSO *dso, DSO_METHOD *meth);
-
-/* The all-singing all-dancing load function, you normally pass NULL
- * for the first and third parameters. Use DSO_up and DSO_free for
- * subsequent reference count handling. Any flags passed in will be set
- * in the constructed DSO after its init() function but before the
- * load operation. If 'dso' is non-NULL, 'flags' is ignored. */
-DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags);
-
-/* This function binds to a variable inside a shared library. */
-void *DSO_bind_var(DSO *dso, const char *symname);
-
-/* This function binds to a function inside a shared library. */
-DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname);
-
-/* This method is the default, but will beg, borrow, or steal whatever
- * method should be the default on any particular platform (including
- * DSO_METH_null() if necessary). */
-DSO_METHOD *DSO_METHOD_openssl(void);
-
-/* This method is defined for all platforms - if a platform has no
- * DSO support then this will be the only method! */
-DSO_METHOD *DSO_METHOD_null(void);
-
-/* If DSO_DLFCN is defined, the standard dlfcn.h-style functions
- * (dlopen, dlclose, dlsym, etc) will be used and incorporated into
- * this method. If not, this method will return NULL. */
-DSO_METHOD *DSO_METHOD_dlfcn(void);
-
-/* If DSO_DL is defined, the standard dl.h-style functions (shl_load,
- * shl_unload, shl_findsym, etc) will be used and incorporated into
- * this method. If not, this method will return NULL. */
-DSO_METHOD *DSO_METHOD_dl(void);
-
-/* If WIN32 is defined, use DLLs. If not, return NULL. */
-DSO_METHOD *DSO_METHOD_win32(void);
-
-/* If VMS is defined, use shared images. If not, return NULL. */
-DSO_METHOD *DSO_METHOD_vms(void);
-
-/* This function writes null-terminated pathname of DSO module
- * containing 'addr' into 'sz' large caller-provided 'path' and
- * returns the number of characters [including trailing zero]
- * written to it. If 'sz' is 0 or negative, 'path' is ignored and
- * required amount of charachers [including trailing zero] to
- * accomodate pathname is returned. If 'addr' is NULL, then
- * pathname of cryptolib itself is returned. Negative or zero
- * return value denotes error.
- */
-int DSO_pathbyaddr(void *addr,char *path,int sz);
-
-/* This function should be used with caution! It looks up symbols in
- * *all* loaded modules and if module gets unloaded by somebody else
- * attempt to dereference the pointer is doomed to have fatal
- * consequences. Primary usage for this function is to probe *core*
- * system functionality, e.g. check if getnameinfo(3) is available
- * at run-time without bothering about OS-specific details such as
- * libc.so.versioning or where does it actually reside: in libc
- * itself or libsocket. */
-void *DSO_global_lookup(const char *name);
-
-/* If BeOS is defined, use shared images. If not, return NULL. */
-DSO_METHOD *DSO_METHOD_beos(void);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_DSO_strings(void);
-
-/* Error codes for the DSO functions. */
-
-/* Function codes. */
-#define DSO_F_BEOS_BIND_FUNC 144
-#define DSO_F_BEOS_BIND_VAR 145
-#define DSO_F_BEOS_LOAD 146
-#define DSO_F_BEOS_NAME_CONVERTER 147
-#define DSO_F_BEOS_UNLOAD 148
-#define DSO_F_DLFCN_BIND_FUNC 100
-#define DSO_F_DLFCN_BIND_VAR 101
-#define DSO_F_DLFCN_LOAD 102
-#define DSO_F_DLFCN_MERGER 130
-#define DSO_F_DLFCN_NAME_CONVERTER 123
-#define DSO_F_DLFCN_UNLOAD 103
-#define DSO_F_DL_BIND_FUNC 104
-#define DSO_F_DL_BIND_VAR 105
-#define DSO_F_DL_LOAD 106
-#define DSO_F_DL_MERGER 131
-#define DSO_F_DL_NAME_CONVERTER 124
-#define DSO_F_DL_UNLOAD 107
-#define DSO_F_DSO_BIND_FUNC 108
-#define DSO_F_DSO_BIND_VAR 109
-#define DSO_F_DSO_CONVERT_FILENAME 126
-#define DSO_F_DSO_CTRL 110
-#define DSO_F_DSO_FREE 111
-#define DSO_F_DSO_GET_FILENAME 127
-#define DSO_F_DSO_GET_LOADED_FILENAME 128
-#define DSO_F_DSO_GLOBAL_LOOKUP 139
-#define DSO_F_DSO_LOAD 112
-#define DSO_F_DSO_MERGE 132
-#define DSO_F_DSO_NEW_METHOD 113
-#define DSO_F_DSO_PATHBYADDR 140
-#define DSO_F_DSO_SET_FILENAME 129
-#define DSO_F_DSO_SET_NAME_CONVERTER 122
-#define DSO_F_DSO_UP_REF 114
-#define DSO_F_GLOBAL_LOOKUP_FUNC 138
-#define DSO_F_PATHBYADDR 137
-#define DSO_F_VMS_BIND_SYM 115
-#define DSO_F_VMS_LOAD 116
-#define DSO_F_VMS_MERGER 133
-#define DSO_F_VMS_UNLOAD 117
-#define DSO_F_WIN32_BIND_FUNC 118
-#define DSO_F_WIN32_BIND_VAR 119
-#define DSO_F_WIN32_GLOBALLOOKUP 142
-#define DSO_F_WIN32_GLOBALLOOKUP_FUNC 143
-#define DSO_F_WIN32_JOINER 135
-#define DSO_F_WIN32_LOAD 120
-#define DSO_F_WIN32_MERGER 134
-#define DSO_F_WIN32_NAME_CONVERTER 125
-#define DSO_F_WIN32_PATHBYADDR 141
-#define DSO_F_WIN32_SPLITTER 136
-#define DSO_F_WIN32_UNLOAD 121
-
-/* Reason codes. */
-#define DSO_R_CTRL_FAILED 100
-#define DSO_R_DSO_ALREADY_LOADED 110
-#define DSO_R_EMPTY_FILE_STRUCTURE 113
-#define DSO_R_FAILURE 114
-#define DSO_R_FILENAME_TOO_BIG 101
-#define DSO_R_FINISH_FAILED 102
-#define DSO_R_INCORRECT_FILE_SYNTAX 115
-#define DSO_R_LOAD_FAILED 103
-#define DSO_R_NAME_TRANSLATION_FAILED 109
-#define DSO_R_NO_FILENAME 111
-#define DSO_R_NO_FILE_SPECIFICATION 116
-#define DSO_R_NULL_HANDLE 104
-#define DSO_R_SET_FILENAME_FAILED 112
-#define DSO_R_STACK_ERROR 105
-#define DSO_R_SYM_FAILURE 106
-#define DSO_R_UNLOAD_FAILED 107
-#define DSO_R_UNSUPPORTED 108
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/dtls1.h b/drivers/builtin_openssl/openssl/dtls1.h
deleted file mode 100644
index 1959e23991..0000000000
--- a/drivers/builtin_openssl/openssl/dtls1.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/* ssl/dtls1.h */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_DTLS1_H
-#define HEADER_DTLS1_H
-
-#ifdef OPENSSL_SYS_VMS
-#include <resource.h>
-#include <sys/timeb.h>
-#endif
-#ifdef OPENSSL_SYS_WIN32
-/* Needed for struct timeval */
-#include <winsock.h>
-#elif defined(OPENSSL_SYS_NETWARE) && !defined(_WINSOCK2API_)
-#include <sys/timeval.h>
-#else
-#if defined(OPENSSL_SYS_VXWORKS)
-#include <sys/times.h>
-#else
-#include <sys/time.h>
-#endif
-#endif
-
-#include <openssl/buffer.h>
-#include <openssl/pqueue.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DTLS1_VERSION 0xFEFF
-#define DTLS1_BAD_VER 0x0100
-
-#if 0
-/* this alert description is not specified anywhere... */
-#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE 110
-#endif
-
-/* lengths of messages */
-#define DTLS1_COOKIE_LENGTH 256
-
-#define DTLS1_RT_HEADER_LENGTH 13
-
-#define DTLS1_HM_HEADER_LENGTH 12
-
-#define DTLS1_HM_BAD_FRAGMENT -2
-#define DTLS1_HM_FRAGMENT_RETRY -3
-
-#define DTLS1_CCS_HEADER_LENGTH 1
-
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
-#define DTLS1_AL_HEADER_LENGTH 7
-#else
-#define DTLS1_AL_HEADER_LENGTH 2
-#endif
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-#ifndef OPENSSL_NO_SCTP
-#define DTLS1_SCTP_AUTH_LABEL "EXPORTER_DTLS_OVER_SCTP"
-#endif
-
-typedef struct dtls1_bitmap_st
- {
- unsigned long map; /* track 32 packets on 32-bit systems
- and 64 - on 64-bit systems */
- unsigned char max_seq_num[8]; /* max record number seen so far,
- 64-bit value in big-endian
- encoding */
- } DTLS1_BITMAP;
-
-struct dtls1_retransmit_state
- {
- EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
- EVP_MD_CTX *write_hash; /* used for mac generation */
-#ifndef OPENSSL_NO_COMP
- COMP_CTX *compress; /* compression */
-#else
- char *compress;
-#endif
- SSL_SESSION *session;
- unsigned short epoch;
- };
-
-struct hm_header_st
- {
- unsigned char type;
- unsigned long msg_len;
- unsigned short seq;
- unsigned long frag_off;
- unsigned long frag_len;
- unsigned int is_ccs;
- struct dtls1_retransmit_state saved_retransmit_state;
- };
-
-struct ccs_header_st
- {
- unsigned char type;
- unsigned short seq;
- };
-
-struct dtls1_timeout_st
- {
- /* Number of read timeouts so far */
- unsigned int read_timeouts;
-
- /* Number of write timeouts so far */
- unsigned int write_timeouts;
-
- /* Number of alerts received so far */
- unsigned int num_alerts;
- };
-
-typedef struct record_pqueue_st
- {
- unsigned short epoch;
- pqueue q;
- } record_pqueue;
-
-typedef struct hm_fragment_st
- {
- struct hm_header_st msg_header;
- unsigned char *fragment;
- unsigned char *reassembly;
- } hm_fragment;
-
-typedef struct dtls1_state_st
- {
- unsigned int send_cookie;
- unsigned char cookie[DTLS1_COOKIE_LENGTH];
- unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH];
- unsigned int cookie_len;
-
- /*
- * The current data and handshake epoch. This is initially
- * undefined, and starts at zero once the initial handshake is
- * completed
- */
- unsigned short r_epoch;
- unsigned short w_epoch;
-
- /* records being received in the current epoch */
- DTLS1_BITMAP bitmap;
-
- /* renegotiation starts a new set of sequence numbers */
- DTLS1_BITMAP next_bitmap;
-
- /* handshake message numbers */
- unsigned short handshake_write_seq;
- unsigned short next_handshake_write_seq;
-
- unsigned short handshake_read_seq;
-
- /* save last sequence number for retransmissions */
- unsigned char last_write_sequence[8];
-
- /* Received handshake records (processed and unprocessed) */
- record_pqueue unprocessed_rcds;
- record_pqueue processed_rcds;
-
- /* Buffered handshake messages */
- pqueue buffered_messages;
-
- /* Buffered (sent) handshake records */
- pqueue sent_messages;
-
- /* Buffered application records.
- * Only for records between CCS and Finished
- * to prevent either protocol violation or
- * unnecessary message loss.
- */
- record_pqueue buffered_app_data;
-
- /* Is set when listening for new connections with dtls1_listen() */
- unsigned int listen;
-
- unsigned int mtu; /* max DTLS packet size */
-
- struct hm_header_st w_msg_hdr;
- struct hm_header_st r_msg_hdr;
-
- struct dtls1_timeout_st timeout;
-
- /* Indicates when the last handshake msg or heartbeat sent will timeout */
- struct timeval next_timeout;
-
- /* Timeout duration */
- unsigned short timeout_duration;
-
- /* storage for Alert/Handshake protocol data received but not
- * yet processed by ssl3_read_bytes: */
- unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
- unsigned int alert_fragment_len;
- unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH];
- unsigned int handshake_fragment_len;
-
- unsigned int retransmitting;
- unsigned int change_cipher_spec_ok;
-
-#ifndef OPENSSL_NO_SCTP
- /* used when SSL_ST_XX_FLUSH is entered */
- int next_state;
-
- int shutdown_received;
-#endif
-
- } DTLS1_STATE;
-
-typedef struct dtls1_record_data_st
- {
- unsigned char *packet;
- unsigned int packet_length;
- SSL3_BUFFER rbuf;
- SSL3_RECORD rrec;
-#ifndef OPENSSL_NO_SCTP
- struct bio_dgram_sctp_rcvinfo recordinfo;
-#endif
- } DTLS1_RECORD_DATA;
-
-#endif
-
-/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
-#define DTLS1_TMO_READ_COUNT 2
-#define DTLS1_TMO_WRITE_COUNT 2
-
-#define DTLS1_TMO_ALERT_COUNT 12
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/openssl/e_os2.h b/drivers/builtin_openssl/openssl/e_os2.h
deleted file mode 100644
index d22c0368f8..0000000000
--- a/drivers/builtin_openssl/openssl/e_os2.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/* e_os2.h */
-/* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <openssl/opensslconf.h>
-
-#ifndef HEADER_E_OS2_H
-#define HEADER_E_OS2_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/******************************************************************************
- * Detect operating systems. This probably needs completing.
- * The result is that at least one OPENSSL_SYS_os macro should be defined.
- * However, if none is defined, Unix is assumed.
- **/
-
-#define OPENSSL_SYS_UNIX
-
-/* ----------------------- Macintosh, before MacOS X ----------------------- */
-#if defined(__MWERKS__) && defined(macintosh) || defined(OPENSSL_SYSNAME_MAC)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_MACINTOSH_CLASSIC
-#endif
-
-/* ----------------------- NetWare ----------------------------------------- */
-#if defined(NETWARE) || defined(OPENSSL_SYSNAME_NETWARE)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_NETWARE
-#endif
-
-/* ---------------------- Microsoft operating systems ---------------------- */
-
-/* Note that MSDOS actually denotes 32-bit environments running on top of
- MS-DOS, such as DJGPP one. */
-#if defined(OPENSSL_SYSNAME_MSDOS)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_MSDOS
-#endif
-
-/* For 32 bit environment, there seems to be the CygWin environment and then
- all the others that try to do the same thing Microsoft does... */
-#if defined(OPENSSL_SYSNAME_UWIN)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_WIN32_UWIN
-#else
-# if defined(__CYGWIN32__) || defined(OPENSSL_SYSNAME_CYGWIN32)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_WIN32_CYGWIN
-# else
-# if defined(_WIN32) || defined(OPENSSL_SYSNAME_WIN32)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_WIN32
-# endif
-# if defined(OPENSSL_SYSNAME_WINNT)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_WINNT
-# endif
-# if defined(OPENSSL_SYSNAME_WINCE)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_WINCE
-# endif
-# endif
-#endif
-
-/* Anything that tries to look like Microsoft is "Windows" */
-#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WINNT) || defined(OPENSSL_SYS_WINCE)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_WINDOWS
-# ifndef OPENSSL_SYS_MSDOS
-# define OPENSSL_SYS_MSDOS
-# endif
-#endif
-
-/* DLL settings. This part is a bit tough, because it's up to the application
- implementor how he or she will link the application, so it requires some
- macro to be used. */
-#ifdef OPENSSL_SYS_WINDOWS
-# ifndef OPENSSL_OPT_WINDLL
-# if defined(_WINDLL) /* This is used when building OpenSSL to indicate that
- DLL linkage should be used */
-# define OPENSSL_OPT_WINDLL
-# endif
-# endif
-#endif
-
-/* -------------------------------- OpenVMS -------------------------------- */
-#if defined(__VMS) || defined(VMS) || defined(OPENSSL_SYSNAME_VMS)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_VMS
-# if defined(__DECC)
-# define OPENSSL_SYS_VMS_DECC
-# elif defined(__DECCXX)
-# define OPENSSL_SYS_VMS_DECC
-# define OPENSSL_SYS_VMS_DECCXX
-# else
-# define OPENSSL_SYS_VMS_NODECC
-# endif
-#endif
-
-/* --------------------------------- OS/2 ---------------------------------- */
-#if defined(__EMX__) || defined(__OS2__)
-# undef OPENSSL_SYS_UNIX
-# define OPENSSL_SYS_OS2
-#endif
-
-/* --------------------------------- Unix ---------------------------------- */
-#ifdef OPENSSL_SYS_UNIX
-# if defined(linux) || defined(__linux__) || defined(OPENSSL_SYSNAME_LINUX)
-# define OPENSSL_SYS_LINUX
-# endif
-# ifdef OPENSSL_SYSNAME_MPE
-# define OPENSSL_SYS_MPE
-# endif
-# ifdef OPENSSL_SYSNAME_SNI
-# define OPENSSL_SYS_SNI
-# endif
-# ifdef OPENSSL_SYSNAME_ULTRASPARC
-# define OPENSSL_SYS_ULTRASPARC
-# endif
-# ifdef OPENSSL_SYSNAME_NEWS4
-# define OPENSSL_SYS_NEWS4
-# endif
-# ifdef OPENSSL_SYSNAME_MACOSX
-# define OPENSSL_SYS_MACOSX
-# endif
-# ifdef OPENSSL_SYSNAME_MACOSX_RHAPSODY
-# define OPENSSL_SYS_MACOSX_RHAPSODY
-# define OPENSSL_SYS_MACOSX
-# endif
-# ifdef OPENSSL_SYSNAME_SUNOS
-# define OPENSSL_SYS_SUNOS
-#endif
-# if defined(_CRAY) || defined(OPENSSL_SYSNAME_CRAY)
-# define OPENSSL_SYS_CRAY
-# endif
-# if defined(_AIX) || defined(OPENSSL_SYSNAME_AIX)
-# define OPENSSL_SYS_AIX
-# endif
-#endif
-
-/* --------------------------------- VOS ----------------------------------- */
-#if defined(__VOS__) || defined(OPENSSL_SYSNAME_VOS)
-# define OPENSSL_SYS_VOS
-#ifdef __HPPA__
-# define OPENSSL_SYS_VOS_HPPA
-#endif
-#ifdef __IA32__
-# define OPENSSL_SYS_VOS_IA32
-#endif
-#endif
-
-/* ------------------------------- VxWorks --------------------------------- */
-#ifdef OPENSSL_SYSNAME_VXWORKS
-# define OPENSSL_SYS_VXWORKS
-#endif
-
-/* --------------------------------- BeOS ---------------------------------- */
-#if defined(__BEOS__)
-# define OPENSSL_SYS_BEOS
-# include <sys/socket.h>
-# if defined(BONE_VERSION)
-# define OPENSSL_SYS_BEOS_BONE
-# else
-# define OPENSSL_SYS_BEOS_R5
-# endif
-#endif
-
-/**
- * That's it for OS-specific stuff
- *****************************************************************************/
-
-
-/* Specials for I/O an exit */
-#ifdef OPENSSL_SYS_MSDOS
-# define OPENSSL_UNISTD_IO <io.h>
-# define OPENSSL_DECLARE_EXIT extern void exit(int);
-#else
-# define OPENSSL_UNISTD_IO OPENSSL_UNISTD
-# define OPENSSL_DECLARE_EXIT /* declared in unistd.h */
-#endif
-
-/* Definitions of OPENSSL_GLOBAL and OPENSSL_EXTERN, to define and declare
- certain global symbols that, with some compilers under VMS, have to be
- defined and declared explicitely with globaldef and globalref.
- Definitions of OPENSSL_EXPORT and OPENSSL_IMPORT, to define and declare
- DLL exports and imports for compilers under Win32. These are a little
- more complicated to use. Basically, for any library that exports some
- global variables, the following code must be present in the header file
- that declares them, before OPENSSL_EXTERN is used:
-
- #ifdef SOME_BUILD_FLAG_MACRO
- # undef OPENSSL_EXTERN
- # define OPENSSL_EXTERN OPENSSL_EXPORT
- #endif
-
- The default is to have OPENSSL_EXPORT, OPENSSL_IMPORT and OPENSSL_GLOBAL
- have some generally sensible values, and for OPENSSL_EXTERN to have the
- value OPENSSL_IMPORT.
-*/
-
-#if defined(OPENSSL_SYS_VMS_NODECC)
-# define OPENSSL_EXPORT globalref
-# define OPENSSL_IMPORT globalref
-# define OPENSSL_GLOBAL globaldef
-#elif defined(OPENSSL_SYS_WINDOWS) && defined(OPENSSL_OPT_WINDLL)
-# define OPENSSL_EXPORT extern __declspec(dllexport)
-# define OPENSSL_IMPORT extern __declspec(dllimport)
-# define OPENSSL_GLOBAL
-#else
-# define OPENSSL_EXPORT extern
-# define OPENSSL_IMPORT extern
-# define OPENSSL_GLOBAL
-#endif
-#define OPENSSL_EXTERN OPENSSL_IMPORT
-
-/* Macros to allow global variables to be reached through function calls when
- required (if a shared library version requires it, for example.
- The way it's done allows definitions like this:
-
- // in foobar.c
- OPENSSL_IMPLEMENT_GLOBAL(int,foobar,0)
- // in foobar.h
- OPENSSL_DECLARE_GLOBAL(int,foobar);
- #define foobar OPENSSL_GLOBAL_REF(foobar)
-*/
-#ifdef OPENSSL_EXPORT_VAR_AS_FUNCTION
-# define OPENSSL_IMPLEMENT_GLOBAL(type,name,value) \
- type *_shadow_##name(void) \
- { static type _hide_##name=value; return &_hide_##name; }
-# define OPENSSL_DECLARE_GLOBAL(type,name) type *_shadow_##name(void)
-# define OPENSSL_GLOBAL_REF(name) (*(_shadow_##name()))
-#else
-# define OPENSSL_IMPLEMENT_GLOBAL(type,name,value) OPENSSL_GLOBAL type _shadow_##name=value;
-# define OPENSSL_DECLARE_GLOBAL(type,name) OPENSSL_EXPORT type _shadow_##name
-# define OPENSSL_GLOBAL_REF(name) _shadow_##name
-#endif
-
-#if defined(OPENSSL_SYS_MACINTOSH_CLASSIC) && macintosh==1 && !defined(MAC_OS_GUSI_SOURCE)
-# define ossl_ssize_t long
-#endif
-
-#ifdef OPENSSL_SYS_MSDOS
-# define ossl_ssize_t long
-#endif
-
-#if defined(NeXT) || defined(OPENSSL_SYS_NEWS4) || defined(OPENSSL_SYS_SUNOS)
-# define ssize_t int
-#endif
-
-#if defined(__ultrix) && !defined(ssize_t)
-# define ossl_ssize_t int
-#endif
-
-#ifndef ossl_ssize_t
-# define ossl_ssize_t ssize_t
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/ebcdic.h b/drivers/builtin_openssl/openssl/ebcdic.h
deleted file mode 100644
index 6d65afcf9e..0000000000
--- a/drivers/builtin_openssl/openssl/ebcdic.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* crypto/ebcdic.h */
-
-#ifndef HEADER_EBCDIC_H
-#define HEADER_EBCDIC_H
-
-#include <sys/types.h>
-
-/* Avoid name clashes with other applications */
-#define os_toascii _openssl_os_toascii
-#define os_toebcdic _openssl_os_toebcdic
-#define ebcdic2ascii _openssl_ebcdic2ascii
-#define ascii2ebcdic _openssl_ascii2ebcdic
-
-extern const unsigned char os_toascii[256];
-extern const unsigned char os_toebcdic[256];
-void *ebcdic2ascii(void *dest, const void *srce, size_t count);
-void *ascii2ebcdic(void *dest, const void *srce, size_t count);
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/ec.h b/drivers/builtin_openssl/openssl/ec.h
deleted file mode 100644
index dfe8710d33..0000000000
--- a/drivers/builtin_openssl/openssl/ec.h
+++ /dev/null
@@ -1,1167 +0,0 @@
-/* crypto/ec/ec.h */
-/*
- * Originally written by Bodo Moeller for the OpenSSL project.
- */
-/**
- * \file crypto/ec/ec.h Include file for the OpenSSL EC functions
- * \author Originally written by Bodo Moeller for the OpenSSL project
- */
-/* ====================================================================
- * Copyright (c) 1998-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the OpenSSL open source
- * license provided above.
- *
- * The elliptic curve binary polynomial software is originally written by
- * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
- *
- */
-
-#ifndef HEADER_EC_H
-#define HEADER_EC_H
-
-#include <openssl/opensslconf.h>
-
-#ifdef OPENSSL_NO_EC
-#error EC is disabled.
-#endif
-
-#include <openssl/asn1.h>
-#include <openssl/symhacks.h>
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/bn.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#elif defined(__SUNPRO_C)
-# if __SUNPRO_C >= 0x520
-# pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
-# endif
-#endif
-
-
-#ifndef OPENSSL_ECC_MAX_FIELD_BITS
-# define OPENSSL_ECC_MAX_FIELD_BITS 661
-#endif
-
-/** Enum for the point conversion form as defined in X9.62 (ECDSA)
- * for the encoding of a elliptic curve point (x,y) */
-typedef enum {
- /** the point is encoded as z||x, where the octet z specifies
- * which solution of the quadratic equation y is */
- POINT_CONVERSION_COMPRESSED = 2,
- /** the point is encoded as z||x||y, where z is the octet 0x02 */
- POINT_CONVERSION_UNCOMPRESSED = 4,
- /** the point is encoded as z||x||y, where the octet z specifies
- * which solution of the quadratic equation y is */
- POINT_CONVERSION_HYBRID = 6
-} point_conversion_form_t;
-
-
-typedef struct ec_method_st EC_METHOD;
-
-typedef struct ec_group_st
- /*
- EC_METHOD *meth;
- -- field definition
- -- curve coefficients
- -- optional generator with associated information (order, cofactor)
- -- optional extra data (precomputed table for fast computation of multiples of generator)
- -- ASN1 stuff
- */
- EC_GROUP;
-
-typedef struct ec_point_st EC_POINT;
-
-
-/********************************************************************/
-/* EC_METHODs for curves over GF(p) */
-/********************************************************************/
-
-/** Returns the basic GFp ec methods which provides the basis for the
- * optimized methods.
- * \return EC_METHOD object
- */
-const EC_METHOD *EC_GFp_simple_method(void);
-
-/** Returns GFp methods using montgomery multiplication.
- * \return EC_METHOD object
- */
-const EC_METHOD *EC_GFp_mont_method(void);
-
-/** Returns GFp methods using optimized methods for NIST recommended curves
- * \return EC_METHOD object
- */
-const EC_METHOD *EC_GFp_nist_method(void);
-
-#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
-/** Returns 64-bit optimized methods for nistp224
- * \return EC_METHOD object
- */
-const EC_METHOD *EC_GFp_nistp224_method(void);
-
-/** Returns 64-bit optimized methods for nistp256
- * \return EC_METHOD object
- */
-const EC_METHOD *EC_GFp_nistp256_method(void);
-
-/** Returns 64-bit optimized methods for nistp521
- * \return EC_METHOD object
- */
-const EC_METHOD *EC_GFp_nistp521_method(void);
-#endif
-
-#ifndef OPENSSL_NO_EC2M
-/********************************************************************/
-/* EC_METHOD for curves over GF(2^m) */
-/********************************************************************/
-
-/** Returns the basic GF2m ec method
- * \return EC_METHOD object
- */
-const EC_METHOD *EC_GF2m_simple_method(void);
-
-#endif
-
-
-/********************************************************************/
-/* EC_GROUP functions */
-/********************************************************************/
-
-/** Creates a new EC_GROUP object
- * \param meth EC_METHOD to use
- * \return newly created EC_GROUP object or NULL in case of an error.
- */
-EC_GROUP *EC_GROUP_new(const EC_METHOD *meth);
-
-/** Frees a EC_GROUP object
- * \param group EC_GROUP object to be freed.
- */
-void EC_GROUP_free(EC_GROUP *group);
-
-/** Clears and frees a EC_GROUP object
- * \param group EC_GROUP object to be cleared and freed.
- */
-void EC_GROUP_clear_free(EC_GROUP *group);
-
-/** Copies EC_GROUP objects. Note: both EC_GROUPs must use the same EC_METHOD.
- * \param dst destination EC_GROUP object
- * \param src source EC_GROUP object
- * \return 1 on success and 0 if an error occurred.
- */
-int EC_GROUP_copy(EC_GROUP *dst, const EC_GROUP *src);
-
-/** Creates a new EC_GROUP object and copies the copies the content
- * form src to the newly created EC_KEY object
- * \param src source EC_GROUP object
- * \return newly created EC_GROUP object or NULL in case of an error.
- */
-EC_GROUP *EC_GROUP_dup(const EC_GROUP *src);
-
-/** Returns the EC_METHOD of the EC_GROUP object.
- * \param group EC_GROUP object
- * \return EC_METHOD used in this EC_GROUP object.
- */
-const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group);
-
-/** Returns the field type of the EC_METHOD.
- * \param meth EC_METHOD object
- * \return NID of the underlying field type OID.
- */
-int EC_METHOD_get_field_type(const EC_METHOD *meth);
-
-/** Sets the generator and it's order/cofactor of a EC_GROUP object.
- * \param group EC_GROUP object
- * \param generator EC_POINT object with the generator.
- * \param order the order of the group generated by the generator.
- * \param cofactor the index of the sub-group generated by the generator
- * in the group of all points on the elliptic curve.
- * \return 1 on success and 0 if an error occured
- */
-int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor);
-
-/** Returns the generator of a EC_GROUP object.
- * \param group EC_GROUP object
- * \return the currently used generator (possibly NULL).
- */
-const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group);
-
-/** Gets the order of a EC_GROUP
- * \param group EC_GROUP object
- * \param order BIGNUM to which the order is copied
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx);
-
-/** Gets the cofactor of a EC_GROUP
- * \param group EC_GROUP object
- * \param cofactor BIGNUM to which the cofactor is copied
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx);
-
-/** Sets the name of a EC_GROUP object
- * \param group EC_GROUP object
- * \param nid NID of the curve name OID
- */
-void EC_GROUP_set_curve_name(EC_GROUP *group, int nid);
-
-/** Returns the curve name of a EC_GROUP object
- * \param group EC_GROUP object
- * \return NID of the curve name OID or 0 if not set.
- */
-int EC_GROUP_get_curve_name(const EC_GROUP *group);
-
-void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag);
-int EC_GROUP_get_asn1_flag(const EC_GROUP *group);
-
-void EC_GROUP_set_point_conversion_form(EC_GROUP *group, point_conversion_form_t form);
-point_conversion_form_t EC_GROUP_get_point_conversion_form(const EC_GROUP *);
-
-unsigned char *EC_GROUP_get0_seed(const EC_GROUP *x);
-size_t EC_GROUP_get_seed_len(const EC_GROUP *);
-size_t EC_GROUP_set_seed(EC_GROUP *, const unsigned char *, size_t len);
-
-/** Sets the parameter of a ec over GFp defined by y^2 = x^3 + a*x + b
- * \param group EC_GROUP object
- * \param p BIGNUM with the prime number
- * \param a BIGNUM with parameter a of the equation
- * \param b BIGNUM with parameter b of the equation
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
-
-/** Gets the parameter of the ec over GFp defined by y^2 = x^3 + a*x + b
- * \param group EC_GROUP object
- * \param p BIGNUM for the prime number
- * \param a BIGNUM for parameter a of the equation
- * \param b BIGNUM for parameter b of the equation
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx);
-
-#ifndef OPENSSL_NO_EC2M
-/** Sets the parameter of a ec over GF2m defined by y^2 + x*y = x^3 + a*x^2 + b
- * \param group EC_GROUP object
- * \param p BIGNUM with the polynomial defining the underlying field
- * \param a BIGNUM with parameter a of the equation
- * \param b BIGNUM with parameter b of the equation
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_GROUP_set_curve_GF2m(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
-
-/** Gets the parameter of the ec over GF2m defined by y^2 + x*y = x^3 + a*x^2 + b
- * \param group EC_GROUP object
- * \param p BIGNUM for the polynomial defining the underlying field
- * \param a BIGNUM for parameter a of the equation
- * \param b BIGNUM for parameter b of the equation
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_GROUP_get_curve_GF2m(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx);
-#endif
-/** Returns the number of bits needed to represent a field element
- * \param group EC_GROUP object
- * \return number of bits needed to represent a field element
- */
-int EC_GROUP_get_degree(const EC_GROUP *group);
-
-/** Checks whether the parameter in the EC_GROUP define a valid ec group
- * \param group EC_GROUP object
- * \param ctx BN_CTX object (optional)
- * \return 1 if group is a valid ec group and 0 otherwise
- */
-int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx);
-
-/** Checks whether the discriminant of the elliptic curve is zero or not
- * \param group EC_GROUP object
- * \param ctx BN_CTX object (optional)
- * \return 1 if the discriminant is not zero and 0 otherwise
- */
-int EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx);
-
-/** Compares two EC_GROUP objects
- * \param a first EC_GROUP object
- * \param b second EC_GROUP object
- * \param ctx BN_CTX object (optional)
- * \return 0 if both groups are equal and 1 otherwise
- */
-int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx);
-
-/* EC_GROUP_new_GF*() calls EC_GROUP_new() and EC_GROUP_set_GF*()
- * after choosing an appropriate EC_METHOD */
-
-/** Creates a new EC_GROUP object with the specified parameters defined
- * over GFp (defined by the equation y^2 = x^3 + a*x + b)
- * \param p BIGNUM with the prime number
- * \param a BIGNUM with the parameter a of the equation
- * \param b BIGNUM with the parameter b of the equation
- * \param ctx BN_CTX object (optional)
- * \return newly created EC_GROUP object with the specified parameters
- */
-EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
-#ifndef OPENSSL_NO_EC2M
-/** Creates a new EC_GROUP object with the specified parameters defined
- * over GF2m (defined by the equation y^2 + x*y = x^3 + a*x^2 + b)
- * \param p BIGNUM with the polynomial defining the underlying field
- * \param a BIGNUM with the parameter a of the equation
- * \param b BIGNUM with the parameter b of the equation
- * \param ctx BN_CTX object (optional)
- * \return newly created EC_GROUP object with the specified parameters
- */
-EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
-#endif
-/** Creates a EC_GROUP object with a curve specified by a NID
- * \param nid NID of the OID of the curve name
- * \return newly created EC_GROUP object with specified curve or NULL
- * if an error occurred
- */
-EC_GROUP *EC_GROUP_new_by_curve_name(int nid);
-
-
-/********************************************************************/
-/* handling of internal curves */
-/********************************************************************/
-
-typedef struct {
- int nid;
- const char *comment;
- } EC_builtin_curve;
-
-/* EC_builtin_curves(EC_builtin_curve *r, size_t size) returns number
- * of all available curves or zero if a error occurred.
- * In case r ist not zero nitems EC_builtin_curve structures
- * are filled with the data of the first nitems internal groups */
-size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
-
-
-/********************************************************************/
-/* EC_POINT functions */
-/********************************************************************/
-
-/** Creates a new EC_POINT object for the specified EC_GROUP
- * \param group EC_GROUP the underlying EC_GROUP object
- * \return newly created EC_POINT object or NULL if an error occurred
- */
-EC_POINT *EC_POINT_new(const EC_GROUP *group);
-
-/** Frees a EC_POINT object
- * \param point EC_POINT object to be freed
- */
-void EC_POINT_free(EC_POINT *point);
-
-/** Clears and frees a EC_POINT object
- * \param point EC_POINT object to be cleared and freed
- */
-void EC_POINT_clear_free(EC_POINT *point);
-
-/** Copies EC_POINT object
- * \param dst destination EC_POINT object
- * \param src source EC_POINT object
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_copy(EC_POINT *dst, const EC_POINT *src);
-
-/** Creates a new EC_POINT object and copies the content of the supplied
- * EC_POINT
- * \param src source EC_POINT object
- * \param group underlying the EC_GROUP object
- * \return newly created EC_POINT object or NULL if an error occurred
- */
-EC_POINT *EC_POINT_dup(const EC_POINT *src, const EC_GROUP *group);
-
-/** Returns the EC_METHOD used in EC_POINT object
- * \param point EC_POINT object
- * \return the EC_METHOD used
- */
-const EC_METHOD *EC_POINT_method_of(const EC_POINT *point);
-
-/** Sets a point to infinity (neutral element)
- * \param group underlying EC_GROUP object
- * \param point EC_POINT to set to infinity
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point);
-
-/** Sets the jacobian projective coordinates of a EC_POINT over GFp
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param x BIGNUM with the x-coordinate
- * \param y BIGNUM with the y-coordinate
- * \param z BIGNUM with the z-coordinate
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *p,
- const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx);
-
-/** Gets the jacobian projective coordinates of a EC_POINT over GFp
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param x BIGNUM for the x-coordinate
- * \param y BIGNUM for the y-coordinate
- * \param z BIGNUM for the z-coordinate
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
- const EC_POINT *p, BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx);
-
-/** Sets the affine coordinates of a EC_POINT over GFp
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param x BIGNUM with the x-coordinate
- * \param y BIGNUM with the y-coordinate
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *p,
- const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx);
-
-/** Gets the affine coordinates of a EC_POINT over GFp
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param x BIGNUM for the x-coordinate
- * \param y BIGNUM for the y-coordinate
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
- const EC_POINT *p, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
-
-/** Sets the x9.62 compressed coordinates of a EC_POINT over GFp
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param x BIGNUM with x-coordinate
- * \param y_bit integer with the y-Bit (either 0 or 1)
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *p,
- const BIGNUM *x, int y_bit, BN_CTX *ctx);
-#ifndef OPENSSL_NO_EC2M
-/** Sets the affine coordinates of a EC_POINT over GF2m
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param x BIGNUM with the x-coordinate
- * \param y BIGNUM with the y-coordinate
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p,
- const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx);
-
-/** Gets the affine coordinates of a EC_POINT over GF2m
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param x BIGNUM for the x-coordinate
- * \param y BIGNUM for the y-coordinate
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *group,
- const EC_POINT *p, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
-
-/** Sets the x9.62 compressed coordinates of a EC_POINT over GF2m
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param x BIGNUM with x-coordinate
- * \param y_bit integer with the y-Bit (either 0 or 1)
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p,
- const BIGNUM *x, int y_bit, BN_CTX *ctx);
-#endif
-/** Encodes a EC_POINT object to a octet string
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param form point conversion form
- * \param buf memory buffer for the result. If NULL the function returns
- * required buffer size.
- * \param len length of the memory buffer
- * \param ctx BN_CTX object (optional)
- * \return the length of the encoded octet string or 0 if an error occurred
- */
-size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *p,
- point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *ctx);
-
-/** Decodes a EC_POINT from a octet string
- * \param group underlying EC_GROUP object
- * \param p EC_POINT object
- * \param buf memory buffer with the encoded ec point
- * \param len length of the encoded ec point
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *p,
- const unsigned char *buf, size_t len, BN_CTX *ctx);
-
-/* other interfaces to point2oct/oct2point: */
-BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *,
- point_conversion_form_t form, BIGNUM *, BN_CTX *);
-EC_POINT *EC_POINT_bn2point(const EC_GROUP *, const BIGNUM *,
- EC_POINT *, BN_CTX *);
-char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *,
- point_conversion_form_t form, BN_CTX *);
-EC_POINT *EC_POINT_hex2point(const EC_GROUP *, const char *,
- EC_POINT *, BN_CTX *);
-
-
-/********************************************************************/
-/* functions for doing EC_POINT arithmetic */
-/********************************************************************/
-
-/** Computes the sum of two EC_POINT
- * \param group underlying EC_GROUP object
- * \param r EC_POINT object for the result (r = a + b)
- * \param a EC_POINT object with the first summand
- * \param b EC_POINT object with the second summand
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx);
-
-/** Computes the double of a EC_POINT
- * \param group underlying EC_GROUP object
- * \param r EC_POINT object for the result (r = 2 * a)
- * \param a EC_POINT object
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx);
-
-/** Computes the inverse of a EC_POINT
- * \param group underlying EC_GROUP object
- * \param a EC_POINT object to be inverted (it's used for the result as well)
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx);
-
-/** Checks whether the point is the neutral element of the group
- * \param group the underlying EC_GROUP object
- * \param p EC_POINT object
- * \return 1 if the point is the neutral element and 0 otherwise
- */
-int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *p);
-
-/** Checks whether the point is on the curve
- * \param group underlying EC_GROUP object
- * \param point EC_POINT object to check
- * \param ctx BN_CTX object (optional)
- * \return 1 if point if on the curve and 0 otherwise
- */
-int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx);
-
-/** Compares two EC_POINTs
- * \param group underlying EC_GROUP object
- * \param a first EC_POINT object
- * \param b second EC_POINT object
- * \param ctx BN_CTX object (optional)
- * \return 0 if both points are equal and a value != 0 otherwise
- */
-int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx);
-
-int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx);
-int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx);
-
-/** Computes r = generator * n sum_{i=0}^num p[i] * m[i]
- * \param group underlying EC_GROUP object
- * \param r EC_POINT object for the result
- * \param n BIGNUM with the multiplier for the group generator (optional)
- * \param num number futher summands
- * \param p array of size num of EC_POINT objects
- * \param m array of size num of BIGNUM objects
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, size_t num, const EC_POINT *p[], const BIGNUM *m[], BN_CTX *ctx);
-
-/** Computes r = generator * n + q * m
- * \param group underlying EC_GROUP object
- * \param r EC_POINT object for the result
- * \param n BIGNUM with the multiplier for the group generator (optional)
- * \param q EC_POINT object with the first factor of the second summand
- * \param m BIGNUM with the second factor of the second summand
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx);
-
-/** Stores multiples of generator for faster point multiplication
- * \param group EC_GROUP object
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occured
- */
-int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
-
-/** Reports whether a precomputation has been done
- * \param group EC_GROUP object
- * \return 1 if a pre-computation has been done and 0 otherwise
- */
-int EC_GROUP_have_precompute_mult(const EC_GROUP *group);
-
-
-/********************************************************************/
-/* ASN1 stuff */
-/********************************************************************/
-
-/* EC_GROUP_get_basis_type() returns the NID of the basis type
- * used to represent the field elements */
-int EC_GROUP_get_basis_type(const EC_GROUP *);
-#ifndef OPENSSL_NO_EC2M
-int EC_GROUP_get_trinomial_basis(const EC_GROUP *, unsigned int *k);
-int EC_GROUP_get_pentanomial_basis(const EC_GROUP *, unsigned int *k1,
- unsigned int *k2, unsigned int *k3);
-#endif
-
-#define OPENSSL_EC_NAMED_CURVE 0x001
-
-typedef struct ecpk_parameters_st ECPKPARAMETERS;
-
-EC_GROUP *d2i_ECPKParameters(EC_GROUP **, const unsigned char **in, long len);
-int i2d_ECPKParameters(const EC_GROUP *, unsigned char **out);
-
-#define d2i_ECPKParameters_bio(bp,x) ASN1_d2i_bio_of(EC_GROUP,NULL,d2i_ECPKParameters,bp,x)
-#define i2d_ECPKParameters_bio(bp,x) ASN1_i2d_bio_of_const(EC_GROUP,i2d_ECPKParameters,bp,x)
-#define d2i_ECPKParameters_fp(fp,x) (EC_GROUP *)ASN1_d2i_fp(NULL, \
- (char *(*)())d2i_ECPKParameters,(fp),(unsigned char **)(x))
-#define i2d_ECPKParameters_fp(fp,x) ASN1_i2d_fp(i2d_ECPKParameters,(fp), \
- (unsigned char *)(x))
-
-#ifndef OPENSSL_NO_BIO
-int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off);
-#endif
-#ifndef OPENSSL_NO_FP_API
-int ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off);
-#endif
-
-
-/********************************************************************/
-/* EC_KEY functions */
-/********************************************************************/
-
-typedef struct ec_key_st EC_KEY;
-
-/* some values for the encoding_flag */
-#define EC_PKEY_NO_PARAMETERS 0x001
-#define EC_PKEY_NO_PUBKEY 0x002
-
-/* some values for the flags field */
-#define EC_FLAG_NON_FIPS_ALLOW 0x1
-#define EC_FLAG_FIPS_CHECKED 0x2
-
-/** Creates a new EC_KEY object.
- * \return EC_KEY object or NULL if an error occurred.
- */
-EC_KEY *EC_KEY_new(void);
-
-int EC_KEY_get_flags(const EC_KEY *key);
-
-void EC_KEY_set_flags(EC_KEY *key, int flags);
-
-void EC_KEY_clear_flags(EC_KEY *key, int flags);
-
-/** Creates a new EC_KEY object using a named curve as underlying
- * EC_GROUP object.
- * \param nid NID of the named curve.
- * \return EC_KEY object or NULL if an error occurred.
- */
-EC_KEY *EC_KEY_new_by_curve_name(int nid);
-
-/** Frees a EC_KEY object.
- * \param key EC_KEY object to be freed.
- */
-void EC_KEY_free(EC_KEY *key);
-
-/** Copies a EC_KEY object.
- * \param dst destination EC_KEY object
- * \param src src EC_KEY object
- * \return dst or NULL if an error occurred.
- */
-EC_KEY *EC_KEY_copy(EC_KEY *dst, const EC_KEY *src);
-
-/** Creates a new EC_KEY object and copies the content from src to it.
- * \param src the source EC_KEY object
- * \return newly created EC_KEY object or NULL if an error occurred.
- */
-EC_KEY *EC_KEY_dup(const EC_KEY *src);
-
-/** Increases the internal reference count of a EC_KEY object.
- * \param key EC_KEY object
- * \return 1 on success and 0 if an error occurred.
- */
-int EC_KEY_up_ref(EC_KEY *key);
-
-/** Returns the EC_GROUP object of a EC_KEY object
- * \param key EC_KEY object
- * \return the EC_GROUP object (possibly NULL).
- */
-const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
-
-/** Sets the EC_GROUP of a EC_KEY object.
- * \param key EC_KEY object
- * \param group EC_GROUP to use in the EC_KEY object (note: the EC_KEY
- * object will use an own copy of the EC_GROUP).
- * \return 1 on success and 0 if an error occurred.
- */
-int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group);
-
-/** Returns the private key of a EC_KEY object.
- * \param key EC_KEY object
- * \return a BIGNUM with the private key (possibly NULL).
- */
-const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key);
-
-/** Sets the private key of a EC_KEY object.
- * \param key EC_KEY object
- * \param prv BIGNUM with the private key (note: the EC_KEY object
- * will use an own copy of the BIGNUM).
- * \return 1 on success and 0 if an error occurred.
- */
-int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv);
-
-/** Returns the public key of a EC_KEY object.
- * \param key the EC_KEY object
- * \return a EC_POINT object with the public key (possibly NULL)
- */
-const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key);
-
-/** Sets the public key of a EC_KEY object.
- * \param key EC_KEY object
- * \param pub EC_POINT object with the public key (note: the EC_KEY object
- * will use an own copy of the EC_POINT object).
- * \return 1 on success and 0 if an error occurred.
- */
-int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);
-
-unsigned EC_KEY_get_enc_flags(const EC_KEY *key);
-void EC_KEY_set_enc_flags(EC_KEY *eckey, unsigned int flags);
-point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key);
-void EC_KEY_set_conv_form(EC_KEY *eckey, point_conversion_form_t cform);
-/* functions to set/get method specific data */
-void *EC_KEY_get_key_method_data(EC_KEY *key,
- void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
-/** Sets the key method data of an EC_KEY object, if none has yet been set.
- * \param key EC_KEY object
- * \param data opaque data to install.
- * \param dup_func a function that duplicates |data|.
- * \param free_func a function that frees |data|.
- * \param clear_free_func a function that wipes and frees |data|.
- * \return the previously set data pointer, or NULL if |data| was inserted.
- */
-void *EC_KEY_insert_key_method_data(EC_KEY *key, void *data,
- void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
-/* wrapper functions for the underlying EC_GROUP object */
-void EC_KEY_set_asn1_flag(EC_KEY *eckey, int asn1_flag);
-
-/** Creates a table of pre-computed multiples of the generator to
- * accelerate further EC_KEY operations.
- * \param key EC_KEY object
- * \param ctx BN_CTX object (optional)
- * \return 1 on success and 0 if an error occurred.
- */
-int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx);
-
-/** Creates a new ec private (and optional a new public) key.
- * \param key EC_KEY object
- * \return 1 on success and 0 if an error occurred.
- */
-int EC_KEY_generate_key(EC_KEY *key);
-
-/** Verifies that a private and/or public key is valid.
- * \param key the EC_KEY object
- * \return 1 on success and 0 otherwise.
- */
-int EC_KEY_check_key(const EC_KEY *key);
-
-/** Sets a public key from affine coordindates performing
- * neccessary NIST PKV tests.
- * \param key the EC_KEY object
- * \param x public key x coordinate
- * \param y public key y coordinate
- * \return 1 on success and 0 otherwise.
- */
-int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y);
-
-
-/********************************************************************/
-/* de- and encoding functions for SEC1 ECPrivateKey */
-/********************************************************************/
-
-/** Decodes a private key from a memory buffer.
- * \param key a pointer to a EC_KEY object which should be used (or NULL)
- * \param in pointer to memory with the DER encoded private key
- * \param len length of the DER encoded private key
- * \return the decoded private key or NULL if an error occurred.
- */
-EC_KEY *d2i_ECPrivateKey(EC_KEY **key, const unsigned char **in, long len);
-
-/** Encodes a private key object and stores the result in a buffer.
- * \param key the EC_KEY object to encode
- * \param out the buffer for the result (if NULL the function returns number
- * of bytes needed).
- * \return 1 on success and 0 if an error occurred.
- */
-int i2d_ECPrivateKey(EC_KEY *key, unsigned char **out);
-
-
-/********************************************************************/
-/* de- and encoding functions for EC parameters */
-/********************************************************************/
-
-/** Decodes ec parameter from a memory buffer.
- * \param key a pointer to a EC_KEY object which should be used (or NULL)
- * \param in pointer to memory with the DER encoded ec parameters
- * \param len length of the DER encoded ec parameters
- * \return a EC_KEY object with the decoded parameters or NULL if an error
- * occurred.
- */
-EC_KEY *d2i_ECParameters(EC_KEY **key, const unsigned char **in, long len);
-
-/** Encodes ec parameter and stores the result in a buffer.
- * \param key the EC_KEY object with ec paramters to encode
- * \param out the buffer for the result (if NULL the function returns number
- * of bytes needed).
- * \return 1 on success and 0 if an error occurred.
- */
-int i2d_ECParameters(EC_KEY *key, unsigned char **out);
-
-
-/********************************************************************/
-/* de- and encoding functions for EC public key */
-/* (octet string, not DER -- hence 'o2i' and 'i2o') */
-/********************************************************************/
-
-/** Decodes a ec public key from a octet string.
- * \param key a pointer to a EC_KEY object which should be used
- * \param in memory buffer with the encoded public key
- * \param len length of the encoded public key
- * \return EC_KEY object with decoded public key or NULL if an error
- * occurred.
- */
-EC_KEY *o2i_ECPublicKey(EC_KEY **key, const unsigned char **in, long len);
-
-/** Encodes a ec public key in an octet string.
- * \param key the EC_KEY object with the public key
- * \param out the buffer for the result (if NULL the function returns number
- * of bytes needed).
- * \return 1 on success and 0 if an error occurred
- */
-int i2o_ECPublicKey(EC_KEY *key, unsigned char **out);
-
-#ifndef OPENSSL_NO_BIO
-/** Prints out the ec parameters on human readable form.
- * \param bp BIO object to which the information is printed
- * \param key EC_KEY object
- * \return 1 on success and 0 if an error occurred
- */
-int ECParameters_print(BIO *bp, const EC_KEY *key);
-
-/** Prints out the contents of a EC_KEY object
- * \param bp BIO object to which the information is printed
- * \param key EC_KEY object
- * \param off line offset
- * \return 1 on success and 0 if an error occurred
- */
-int EC_KEY_print(BIO *bp, const EC_KEY *key, int off);
-
-#endif
-#ifndef OPENSSL_NO_FP_API
-/** Prints out the ec parameters on human readable form.
- * \param fp file descriptor to which the information is printed
- * \param key EC_KEY object
- * \return 1 on success and 0 if an error occurred
- */
-int ECParameters_print_fp(FILE *fp, const EC_KEY *key);
-
-/** Prints out the contents of a EC_KEY object
- * \param fp file descriptor to which the information is printed
- * \param key EC_KEY object
- * \param off line offset
- * \return 1 on success and 0 if an error occurred
- */
-int EC_KEY_print_fp(FILE *fp, const EC_KEY *key, int off);
-
-#endif
-
-#define ECParameters_dup(x) ASN1_dup_of(EC_KEY,i2d_ECParameters,d2i_ECParameters,x)
-
-#ifndef __cplusplus
-#if defined(__SUNPRO_C)
-# if __SUNPRO_C >= 0x520
-# pragma error_messages (default,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
-# endif
-# endif
-#endif
-
-#define EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_PARAMGEN, \
- EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, nid, NULL)
-
-
-#define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID (EVP_PKEY_ALG_CTRL + 1)
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_EC_strings(void);
-
-/* Error codes for the EC functions. */
-
-/* Function codes. */
-#define EC_F_BN_TO_FELEM 224
-#define EC_F_COMPUTE_WNAF 143
-#define EC_F_D2I_ECPARAMETERS 144
-#define EC_F_D2I_ECPKPARAMETERS 145
-#define EC_F_D2I_ECPRIVATEKEY 146
-#define EC_F_DO_EC_KEY_PRINT 221
-#define EC_F_ECKEY_PARAM2TYPE 223
-#define EC_F_ECKEY_PARAM_DECODE 212
-#define EC_F_ECKEY_PRIV_DECODE 213
-#define EC_F_ECKEY_PRIV_ENCODE 214
-#define EC_F_ECKEY_PUB_DECODE 215
-#define EC_F_ECKEY_PUB_ENCODE 216
-#define EC_F_ECKEY_TYPE2PARAM 220
-#define EC_F_ECPARAMETERS_PRINT 147
-#define EC_F_ECPARAMETERS_PRINT_FP 148
-#define EC_F_ECPKPARAMETERS_PRINT 149
-#define EC_F_ECPKPARAMETERS_PRINT_FP 150
-#define EC_F_ECP_NIST_MOD_192 203
-#define EC_F_ECP_NIST_MOD_224 204
-#define EC_F_ECP_NIST_MOD_256 205
-#define EC_F_ECP_NIST_MOD_521 206
-#define EC_F_EC_ASN1_GROUP2CURVE 153
-#define EC_F_EC_ASN1_GROUP2FIELDID 154
-#define EC_F_EC_ASN1_GROUP2PARAMETERS 155
-#define EC_F_EC_ASN1_GROUP2PKPARAMETERS 156
-#define EC_F_EC_ASN1_PARAMETERS2GROUP 157
-#define EC_F_EC_ASN1_PKPARAMETERS2GROUP 158
-#define EC_F_EC_EX_DATA_SET_DATA 211
-#define EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY 208
-#define EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT 159
-#define EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE 195
-#define EC_F_EC_GF2M_SIMPLE_OCT2POINT 160
-#define EC_F_EC_GF2M_SIMPLE_POINT2OCT 161
-#define EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES 162
-#define EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES 163
-#define EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES 164
-#define EC_F_EC_GFP_MONT_FIELD_DECODE 133
-#define EC_F_EC_GFP_MONT_FIELD_ENCODE 134
-#define EC_F_EC_GFP_MONT_FIELD_MUL 131
-#define EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE 209
-#define EC_F_EC_GFP_MONT_FIELD_SQR 132
-#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE 189
-#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE_GFP 135
-#define EC_F_EC_GFP_NISTP224_GROUP_SET_CURVE 225
-#define EC_F_EC_GFP_NISTP224_POINTS_MUL 228
-#define EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES 226
-#define EC_F_EC_GFP_NISTP256_GROUP_SET_CURVE 230
-#define EC_F_EC_GFP_NISTP256_POINTS_MUL 231
-#define EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES 232
-#define EC_F_EC_GFP_NISTP521_GROUP_SET_CURVE 233
-#define EC_F_EC_GFP_NISTP521_POINTS_MUL 234
-#define EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES 235
-#define EC_F_EC_GFP_NIST_FIELD_MUL 200
-#define EC_F_EC_GFP_NIST_FIELD_SQR 201
-#define EC_F_EC_GFP_NIST_GROUP_SET_CURVE 202
-#define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT 165
-#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE 166
-#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP 100
-#define EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR 101
-#define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE 102
-#define EC_F_EC_GFP_SIMPLE_OCT2POINT 103
-#define EC_F_EC_GFP_SIMPLE_POINT2OCT 104
-#define EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE 137
-#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES 167
-#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP 105
-#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES 168
-#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP 128
-#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES 169
-#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP 129
-#define EC_F_EC_GROUP_CHECK 170
-#define EC_F_EC_GROUP_CHECK_DISCRIMINANT 171
-#define EC_F_EC_GROUP_COPY 106
-#define EC_F_EC_GROUP_GET0_GENERATOR 139
-#define EC_F_EC_GROUP_GET_COFACTOR 140
-#define EC_F_EC_GROUP_GET_CURVE_GF2M 172
-#define EC_F_EC_GROUP_GET_CURVE_GFP 130
-#define EC_F_EC_GROUP_GET_DEGREE 173
-#define EC_F_EC_GROUP_GET_ORDER 141
-#define EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS 193
-#define EC_F_EC_GROUP_GET_TRINOMIAL_BASIS 194
-#define EC_F_EC_GROUP_NEW 108
-#define EC_F_EC_GROUP_NEW_BY_CURVE_NAME 174
-#define EC_F_EC_GROUP_NEW_FROM_DATA 175
-#define EC_F_EC_GROUP_PRECOMPUTE_MULT 142
-#define EC_F_EC_GROUP_SET_CURVE_GF2M 176
-#define EC_F_EC_GROUP_SET_CURVE_GFP 109
-#define EC_F_EC_GROUP_SET_EXTRA_DATA 110
-#define EC_F_EC_GROUP_SET_GENERATOR 111
-#define EC_F_EC_KEY_CHECK_KEY 177
-#define EC_F_EC_KEY_COPY 178
-#define EC_F_EC_KEY_GENERATE_KEY 179
-#define EC_F_EC_KEY_NEW 182
-#define EC_F_EC_KEY_PRINT 180
-#define EC_F_EC_KEY_PRINT_FP 181
-#define EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES 229
-#define EC_F_EC_POINTS_MAKE_AFFINE 136
-#define EC_F_EC_POINT_ADD 112
-#define EC_F_EC_POINT_CMP 113
-#define EC_F_EC_POINT_COPY 114
-#define EC_F_EC_POINT_DBL 115
-#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M 183
-#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP 116
-#define EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP 117
-#define EC_F_EC_POINT_INVERT 210
-#define EC_F_EC_POINT_IS_AT_INFINITY 118
-#define EC_F_EC_POINT_IS_ON_CURVE 119
-#define EC_F_EC_POINT_MAKE_AFFINE 120
-#define EC_F_EC_POINT_MUL 184
-#define EC_F_EC_POINT_NEW 121
-#define EC_F_EC_POINT_OCT2POINT 122
-#define EC_F_EC_POINT_POINT2OCT 123
-#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M 185
-#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP 124
-#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M 186
-#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP 125
-#define EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP 126
-#define EC_F_EC_POINT_SET_TO_INFINITY 127
-#define EC_F_EC_PRE_COMP_DUP 207
-#define EC_F_EC_PRE_COMP_NEW 196
-#define EC_F_EC_WNAF_MUL 187
-#define EC_F_EC_WNAF_PRECOMPUTE_MULT 188
-#define EC_F_I2D_ECPARAMETERS 190
-#define EC_F_I2D_ECPKPARAMETERS 191
-#define EC_F_I2D_ECPRIVATEKEY 192
-#define EC_F_I2O_ECPUBLICKEY 151
-#define EC_F_NISTP224_PRE_COMP_NEW 227
-#define EC_F_NISTP256_PRE_COMP_NEW 236
-#define EC_F_NISTP521_PRE_COMP_NEW 237
-#define EC_F_O2I_ECPUBLICKEY 152
-#define EC_F_OLD_EC_PRIV_DECODE 222
-#define EC_F_PKEY_EC_CTRL 197
-#define EC_F_PKEY_EC_CTRL_STR 198
-#define EC_F_PKEY_EC_DERIVE 217
-#define EC_F_PKEY_EC_KEYGEN 199
-#define EC_F_PKEY_EC_PARAMGEN 219
-#define EC_F_PKEY_EC_SIGN 218
-
-/* Reason codes. */
-#define EC_R_ASN1_ERROR 115
-#define EC_R_ASN1_UNKNOWN_FIELD 116
-#define EC_R_BIGNUM_OUT_OF_RANGE 144
-#define EC_R_BUFFER_TOO_SMALL 100
-#define EC_R_COORDINATES_OUT_OF_RANGE 146
-#define EC_R_D2I_ECPKPARAMETERS_FAILURE 117
-#define EC_R_DECODE_ERROR 142
-#define EC_R_DISCRIMINANT_IS_ZERO 118
-#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 119
-#define EC_R_FIELD_TOO_LARGE 143
-#define EC_R_GF2M_NOT_SUPPORTED 147
-#define EC_R_GROUP2PKPARAMETERS_FAILURE 120
-#define EC_R_I2D_ECPKPARAMETERS_FAILURE 121
-#define EC_R_INCOMPATIBLE_OBJECTS 101
-#define EC_R_INVALID_ARGUMENT 112
-#define EC_R_INVALID_COMPRESSED_POINT 110
-#define EC_R_INVALID_COMPRESSION_BIT 109
-#define EC_R_INVALID_CURVE 141
-#define EC_R_INVALID_DIGEST_TYPE 138
-#define EC_R_INVALID_ENCODING 102
-#define EC_R_INVALID_FIELD 103
-#define EC_R_INVALID_FORM 104
-#define EC_R_INVALID_GROUP_ORDER 122
-#define EC_R_INVALID_PENTANOMIAL_BASIS 132
-#define EC_R_INVALID_PRIVATE_KEY 123
-#define EC_R_INVALID_TRINOMIAL_BASIS 137
-#define EC_R_KEYS_NOT_SET 140
-#define EC_R_MISSING_PARAMETERS 124
-#define EC_R_MISSING_PRIVATE_KEY 125
-#define EC_R_NOT_A_NIST_PRIME 135
-#define EC_R_NOT_A_SUPPORTED_NIST_PRIME 136
-#define EC_R_NOT_IMPLEMENTED 126
-#define EC_R_NOT_INITIALIZED 111
-#define EC_R_NO_FIELD_MOD 133
-#define EC_R_NO_PARAMETERS_SET 139
-#define EC_R_PASSED_NULL_PARAMETER 134
-#define EC_R_PKPARAMETERS2GROUP_FAILURE 127
-#define EC_R_POINT_AT_INFINITY 106
-#define EC_R_POINT_IS_NOT_ON_CURVE 107
-#define EC_R_SLOT_FULL 108
-#define EC_R_UNDEFINED_GENERATOR 113
-#define EC_R_UNDEFINED_ORDER 128
-#define EC_R_UNKNOWN_GROUP 129
-#define EC_R_UNKNOWN_ORDER 114
-#define EC_R_UNSUPPORTED_FIELD 131
-#define EC_R_WRONG_CURVE_PARAMETERS 145
-#define EC_R_WRONG_ORDER 130
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/ecdh.h b/drivers/builtin_openssl/openssl/ecdh.h
deleted file mode 100644
index 8887102c0b..0000000000
--- a/drivers/builtin_openssl/openssl/ecdh.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/* crypto/ecdh/ecdh.h */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
- * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
- * to the OpenSSL project.
- *
- * The ECC Code is licensed pursuant to the OpenSSL open source
- * license provided below.
- *
- * The ECDH software is originally written by Douglas Stebila of
- * Sun Microsystems Laboratories.
- *
- */
-/* ====================================================================
- * Copyright (c) 2000-2002 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-#ifndef HEADER_ECDH_H
-#define HEADER_ECDH_H
-
-#include <openssl/opensslconf.h>
-
-#ifdef OPENSSL_NO_ECDH
-#error ECDH is disabled.
-#endif
-
-#include <openssl/ec.h>
-#include <openssl/ossl_typ.h>
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/bn.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-const ECDH_METHOD *ECDH_OpenSSL(void);
-
-void ECDH_set_default_method(const ECDH_METHOD *);
-const ECDH_METHOD *ECDH_get_default_method(void);
-int ECDH_set_method(EC_KEY *, const ECDH_METHOD *);
-
-int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh,
- void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen));
-
-int ECDH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new
- *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int ECDH_set_ex_data(EC_KEY *d, int idx, void *arg);
-void *ECDH_get_ex_data(EC_KEY *d, int idx);
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_ECDH_strings(void);
-
-/* Error codes for the ECDH functions. */
-
-/* Function codes. */
-#define ECDH_F_ECDH_CHECK 102
-#define ECDH_F_ECDH_COMPUTE_KEY 100
-#define ECDH_F_ECDH_DATA_NEW_METHOD 101
-
-/* Reason codes. */
-#define ECDH_R_KDF_FAILED 102
-#define ECDH_R_NON_FIPS_METHOD 103
-#define ECDH_R_NO_PRIVATE_VALUE 100
-#define ECDH_R_POINT_ARITHMETIC_FAILURE 101
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/ecdsa.h b/drivers/builtin_openssl/openssl/ecdsa.h
deleted file mode 100644
index 7fb5254b62..0000000000
--- a/drivers/builtin_openssl/openssl/ecdsa.h
+++ /dev/null
@@ -1,260 +0,0 @@
-/* crypto/ecdsa/ecdsa.h */
-/**
- * \file crypto/ecdsa/ecdsa.h Include file for the OpenSSL ECDSA functions
- * \author Written by Nils Larsch for the OpenSSL project
- */
-/* ====================================================================
- * Copyright (c) 2000-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-#ifndef HEADER_ECDSA_H
-#define HEADER_ECDSA_H
-
-#include <openssl/opensslconf.h>
-
-#ifdef OPENSSL_NO_ECDSA
-#error ECDSA is disabled.
-#endif
-
-#include <openssl/ec.h>
-#include <openssl/ossl_typ.h>
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/bn.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct ECDSA_SIG_st
- {
- BIGNUM *r;
- BIGNUM *s;
- } ECDSA_SIG;
-
-/** Allocates and initialize a ECDSA_SIG structure
- * \return pointer to a ECDSA_SIG structure or NULL if an error occurred
- */
-ECDSA_SIG *ECDSA_SIG_new(void);
-
-/** frees a ECDSA_SIG structure
- * \param sig pointer to the ECDSA_SIG structure
- */
-void ECDSA_SIG_free(ECDSA_SIG *sig);
-
-/** DER encode content of ECDSA_SIG object (note: this function modifies *pp
- * (*pp += length of the DER encoded signature)).
- * \param sig pointer to the ECDSA_SIG object
- * \param pp pointer to a unsigned char pointer for the output or NULL
- * \return the length of the DER encoded ECDSA_SIG object or 0
- */
-int i2d_ECDSA_SIG(const ECDSA_SIG *sig, unsigned char **pp);
-
-/** Decodes a DER encoded ECDSA signature (note: this function changes *pp
- * (*pp += len)).
- * \param sig pointer to ECDSA_SIG pointer (may be NULL)
- * \param pp memory buffer with the DER encoded signature
- * \param len length of the buffer
- * \return pointer to the decoded ECDSA_SIG structure (or NULL)
- */
-ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **sig, const unsigned char **pp, long len);
-
-/** Computes the ECDSA signature of the given hash value using
- * the supplied private key and returns the created signature.
- * \param dgst pointer to the hash value
- * \param dgst_len length of the hash value
- * \param eckey EC_KEY object containing a private EC key
- * \return pointer to a ECDSA_SIG structure or NULL if an error occurred
- */
-ECDSA_SIG *ECDSA_do_sign(const unsigned char *dgst,int dgst_len,EC_KEY *eckey);
-
-/** Computes ECDSA signature of a given hash value using the supplied
- * private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
- * \param dgst pointer to the hash value to sign
- * \param dgstlen length of the hash value
- * \param kinv BIGNUM with a pre-computed inverse k (optional)
- * \param rp BIGNUM with a pre-computed rp value (optioanl),
- * see ECDSA_sign_setup
- * \param eckey EC_KEY object containing a private EC key
- * \return pointer to a ECDSA_SIG structure or NULL if an error occurred
- */
-ECDSA_SIG *ECDSA_do_sign_ex(const unsigned char *dgst, int dgstlen,
- const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey);
-
-/** Verifies that the supplied signature is a valid ECDSA
- * signature of the supplied hash value using the supplied public key.
- * \param dgst pointer to the hash value
- * \param dgst_len length of the hash value
- * \param sig ECDSA_SIG structure
- * \param eckey EC_KEY object containing a public EC key
- * \return 1 if the signature is valid, 0 if the signature is invalid
- * and -1 on error
- */
-int ECDSA_do_verify(const unsigned char *dgst, int dgst_len,
- const ECDSA_SIG *sig, EC_KEY* eckey);
-
-const ECDSA_METHOD *ECDSA_OpenSSL(void);
-
-/** Sets the default ECDSA method
- * \param meth new default ECDSA_METHOD
- */
-void ECDSA_set_default_method(const ECDSA_METHOD *meth);
-
-/** Returns the default ECDSA method
- * \return pointer to ECDSA_METHOD structure containing the default method
- */
-const ECDSA_METHOD *ECDSA_get_default_method(void);
-
-/** Sets method to be used for the ECDSA operations
- * \param eckey EC_KEY object
- * \param meth new method
- * \return 1 on success and 0 otherwise
- */
-int ECDSA_set_method(EC_KEY *eckey, const ECDSA_METHOD *meth);
-
-/** Returns the maximum length of the DER encoded signature
- * \param eckey EC_KEY object
- * \return numbers of bytes required for the DER encoded signature
- */
-int ECDSA_size(const EC_KEY *eckey);
-
-/** Precompute parts of the signing operation
- * \param eckey EC_KEY object containing a private EC key
- * \param ctx BN_CTX object (optional)
- * \param kinv BIGNUM pointer for the inverse of k
- * \param rp BIGNUM pointer for x coordinate of k * generator
- * \return 1 on success and 0 otherwise
- */
-int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv,
- BIGNUM **rp);
-
-/** Computes ECDSA signature of a given hash value using the supplied
- * private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
- * \param type this parameter is ignored
- * \param dgst pointer to the hash value to sign
- * \param dgstlen length of the hash value
- * \param sig memory for the DER encoded created signature
- * \param siglen pointer to the length of the returned signature
- * \param eckey EC_KEY object containing a private EC key
- * \return 1 on success and 0 otherwise
- */
-int ECDSA_sign(int type, const unsigned char *dgst, int dgstlen,
- unsigned char *sig, unsigned int *siglen, EC_KEY *eckey);
-
-
-/** Computes ECDSA signature of a given hash value using the supplied
- * private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
- * \param type this parameter is ignored
- * \param dgst pointer to the hash value to sign
- * \param dgstlen length of the hash value
- * \param sig buffer to hold the DER encoded signature
- * \param siglen pointer to the length of the returned signature
- * \param kinv BIGNUM with a pre-computed inverse k (optional)
- * \param rp BIGNUM with a pre-computed rp value (optioanl),
- * see ECDSA_sign_setup
- * \param eckey EC_KEY object containing a private EC key
- * \return 1 on success and 0 otherwise
- */
-int ECDSA_sign_ex(int type, const unsigned char *dgst, int dgstlen,
- unsigned char *sig, unsigned int *siglen, const BIGNUM *kinv,
- const BIGNUM *rp, EC_KEY *eckey);
-
-/** Verifies that the given signature is valid ECDSA signature
- * of the supplied hash value using the specified public key.
- * \param type this parameter is ignored
- * \param dgst pointer to the hash value
- * \param dgstlen length of the hash value
- * \param sig pointer to the DER encoded signature
- * \param siglen length of the DER encoded signature
- * \param eckey EC_KEY object containing a public EC key
- * \return 1 if the signature is valid, 0 if the signature is invalid
- * and -1 on error
- */
-int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen,
- const unsigned char *sig, int siglen, EC_KEY *eckey);
-
-/* the standard ex_data functions */
-int ECDSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new
- *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int ECDSA_set_ex_data(EC_KEY *d, int idx, void *arg);
-void *ECDSA_get_ex_data(EC_KEY *d, int idx);
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_ECDSA_strings(void);
-
-/* Error codes for the ECDSA functions. */
-
-/* Function codes. */
-#define ECDSA_F_ECDSA_CHECK 104
-#define ECDSA_F_ECDSA_DATA_NEW_METHOD 100
-#define ECDSA_F_ECDSA_DO_SIGN 101
-#define ECDSA_F_ECDSA_DO_VERIFY 102
-#define ECDSA_F_ECDSA_SIGN_SETUP 103
-
-/* Reason codes. */
-#define ECDSA_R_BAD_SIGNATURE 100
-#define ECDSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 101
-#define ECDSA_R_ERR_EC_LIB 102
-#define ECDSA_R_MISSING_PARAMETERS 103
-#define ECDSA_R_NEED_NEW_SETUP_VALUES 106
-#define ECDSA_R_NON_FIPS_METHOD 107
-#define ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED 104
-#define ECDSA_R_SIGNATURE_MALLOC_FAILED 105
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/engine.h b/drivers/builtin_openssl/openssl/engine.h
deleted file mode 100644
index f8be497724..0000000000
--- a/drivers/builtin_openssl/openssl/engine.h
+++ /dev/null
@@ -1,842 +0,0 @@
-/* openssl/engine.h */
-/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
- * project 2000.
- */
-/* ====================================================================
- * Copyright (c) 1999-2004 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECDH support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-
-#ifndef HEADER_ENGINE_H
-#define HEADER_ENGINE_H
-
-#include <openssl/opensslconf.h>
-
-#ifdef OPENSSL_NO_ENGINE
-#error ENGINE is disabled.
-#endif
-
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_RSA
-#include <openssl/rsa.h>
-#endif
-#ifndef OPENSSL_NO_DSA
-#include <openssl/dsa.h>
-#endif
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#endif
-#ifndef OPENSSL_NO_ECDH
-#include <openssl/ecdh.h>
-#endif
-#ifndef OPENSSL_NO_ECDSA
-#include <openssl/ecdsa.h>
-#endif
-#include <openssl/rand.h>
-#include <openssl/ui.h>
-#include <openssl/err.h>
-#endif
-
-#include <openssl/ossl_typ.h>
-#include <openssl/symhacks.h>
-
-#include <openssl/x509.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* These flags are used to control combinations of algorithm (methods)
- * by bitwise "OR"ing. */
-#define ENGINE_METHOD_RSA (unsigned int)0x0001
-#define ENGINE_METHOD_DSA (unsigned int)0x0002
-#define ENGINE_METHOD_DH (unsigned int)0x0004
-#define ENGINE_METHOD_RAND (unsigned int)0x0008
-#define ENGINE_METHOD_ECDH (unsigned int)0x0010
-#define ENGINE_METHOD_ECDSA (unsigned int)0x0020
-#define ENGINE_METHOD_CIPHERS (unsigned int)0x0040
-#define ENGINE_METHOD_DIGESTS (unsigned int)0x0080
-#define ENGINE_METHOD_STORE (unsigned int)0x0100
-#define ENGINE_METHOD_PKEY_METHS (unsigned int)0x0200
-#define ENGINE_METHOD_PKEY_ASN1_METHS (unsigned int)0x0400
-/* Obvious all-or-nothing cases. */
-#define ENGINE_METHOD_ALL (unsigned int)0xFFFF
-#define ENGINE_METHOD_NONE (unsigned int)0x0000
-
-/* This(ese) flag(s) controls behaviour of the ENGINE_TABLE mechanism used
- * internally to control registration of ENGINE implementations, and can be set
- * by ENGINE_set_table_flags(). The "NOINIT" flag prevents attempts to
- * initialise registered ENGINEs if they are not already initialised. */
-#define ENGINE_TABLE_FLAG_NOINIT (unsigned int)0x0001
-
-/* ENGINE flags that can be set by ENGINE_set_flags(). */
-/* #define ENGINE_FLAGS_MALLOCED 0x0001 */ /* Not used */
-
-/* This flag is for ENGINEs that wish to handle the various 'CMD'-related
- * control commands on their own. Without this flag, ENGINE_ctrl() handles these
- * control commands on behalf of the ENGINE using their "cmd_defns" data. */
-#define ENGINE_FLAGS_MANUAL_CMD_CTRL (int)0x0002
-
-/* This flag is for ENGINEs who return new duplicate structures when found via
- * "ENGINE_by_id()". When an ENGINE must store state (eg. if ENGINE_ctrl()
- * commands are called in sequence as part of some stateful process like
- * key-generation setup and execution), it can set this flag - then each attempt
- * to obtain the ENGINE will result in it being copied into a new structure.
- * Normally, ENGINEs don't declare this flag so ENGINE_by_id() just increments
- * the existing ENGINE's structural reference count. */
-#define ENGINE_FLAGS_BY_ID_COPY (int)0x0004
-
-/* This flag if for an ENGINE that does not want its methods registered as
- * part of ENGINE_register_all_complete() for example if the methods are
- * not usable as default methods.
- */
-
-#define ENGINE_FLAGS_NO_REGISTER_ALL (int)0x0008
-
-/* ENGINEs can support their own command types, and these flags are used in
- * ENGINE_CTRL_GET_CMD_FLAGS to indicate to the caller what kind of input each
- * command expects. Currently only numeric and string input is supported. If a
- * control command supports none of the _NUMERIC, _STRING, or _NO_INPUT options,
- * then it is regarded as an "internal" control command - and not for use in
- * config setting situations. As such, they're not available to the
- * ENGINE_ctrl_cmd_string() function, only raw ENGINE_ctrl() access. Changes to
- * this list of 'command types' should be reflected carefully in
- * ENGINE_cmd_is_executable() and ENGINE_ctrl_cmd_string(). */
-
-/* accepts a 'long' input value (3rd parameter to ENGINE_ctrl) */
-#define ENGINE_CMD_FLAG_NUMERIC (unsigned int)0x0001
-/* accepts string input (cast from 'void*' to 'const char *', 4th parameter to
- * ENGINE_ctrl) */
-#define ENGINE_CMD_FLAG_STRING (unsigned int)0x0002
-/* Indicates that the control command takes *no* input. Ie. the control command
- * is unparameterised. */
-#define ENGINE_CMD_FLAG_NO_INPUT (unsigned int)0x0004
-/* Indicates that the control command is internal. This control command won't
- * be shown in any output, and is only usable through the ENGINE_ctrl_cmd()
- * function. */
-#define ENGINE_CMD_FLAG_INTERNAL (unsigned int)0x0008
-
-/* NB: These 3 control commands are deprecated and should not be used. ENGINEs
- * relying on these commands should compile conditional support for
- * compatibility (eg. if these symbols are defined) but should also migrate the
- * same functionality to their own ENGINE-specific control functions that can be
- * "discovered" by calling applications. The fact these control commands
- * wouldn't be "executable" (ie. usable by text-based config) doesn't change the
- * fact that application code can find and use them without requiring per-ENGINE
- * hacking. */
-
-/* These flags are used to tell the ctrl function what should be done.
- * All command numbers are shared between all engines, even if some don't
- * make sense to some engines. In such a case, they do nothing but return
- * the error ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED. */
-#define ENGINE_CTRL_SET_LOGSTREAM 1
-#define ENGINE_CTRL_SET_PASSWORD_CALLBACK 2
-#define ENGINE_CTRL_HUP 3 /* Close and reinitialise any
- handles/connections etc. */
-#define ENGINE_CTRL_SET_USER_INTERFACE 4 /* Alternative to callback */
-#define ENGINE_CTRL_SET_CALLBACK_DATA 5 /* User-specific data, used
- when calling the password
- callback and the user
- interface */
-#define ENGINE_CTRL_LOAD_CONFIGURATION 6 /* Load a configuration, given
- a string that represents a
- file name or so */
-#define ENGINE_CTRL_LOAD_SECTION 7 /* Load data from a given
- section in the already loaded
- configuration */
-
-/* These control commands allow an application to deal with an arbitrary engine
- * in a dynamic way. Warn: Negative return values indicate errors FOR THESE
- * COMMANDS because zero is used to indicate 'end-of-list'. Other commands,
- * including ENGINE-specific command types, return zero for an error.
- *
- * An ENGINE can choose to implement these ctrl functions, and can internally
- * manage things however it chooses - it does so by setting the
- * ENGINE_FLAGS_MANUAL_CMD_CTRL flag (using ENGINE_set_flags()). Otherwise the
- * ENGINE_ctrl() code handles this on the ENGINE's behalf using the cmd_defns
- * data (set using ENGINE_set_cmd_defns()). This means an ENGINE's ctrl()
- * handler need only implement its own commands - the above "meta" commands will
- * be taken care of. */
-
-/* Returns non-zero if the supplied ENGINE has a ctrl() handler. If "not", then
- * all the remaining control commands will return failure, so it is worth
- * checking this first if the caller is trying to "discover" the engine's
- * capabilities and doesn't want errors generated unnecessarily. */
-#define ENGINE_CTRL_HAS_CTRL_FUNCTION 10
-/* Returns a positive command number for the first command supported by the
- * engine. Returns zero if no ctrl commands are supported. */
-#define ENGINE_CTRL_GET_FIRST_CMD_TYPE 11
-/* The 'long' argument specifies a command implemented by the engine, and the
- * return value is the next command supported, or zero if there are no more. */
-#define ENGINE_CTRL_GET_NEXT_CMD_TYPE 12
-/* The 'void*' argument is a command name (cast from 'const char *'), and the
- * return value is the command that corresponds to it. */
-#define ENGINE_CTRL_GET_CMD_FROM_NAME 13
-/* The next two allow a command to be converted into its corresponding string
- * form. In each case, the 'long' argument supplies the command. In the NAME_LEN
- * case, the return value is the length of the command name (not counting a
- * trailing EOL). In the NAME case, the 'void*' argument must be a string buffer
- * large enough, and it will be populated with the name of the command (WITH a
- * trailing EOL). */
-#define ENGINE_CTRL_GET_NAME_LEN_FROM_CMD 14
-#define ENGINE_CTRL_GET_NAME_FROM_CMD 15
-/* The next two are similar but give a "short description" of a command. */
-#define ENGINE_CTRL_GET_DESC_LEN_FROM_CMD 16
-#define ENGINE_CTRL_GET_DESC_FROM_CMD 17
-/* With this command, the return value is the OR'd combination of
- * ENGINE_CMD_FLAG_*** values that indicate what kind of input a given
- * engine-specific ctrl command expects. */
-#define ENGINE_CTRL_GET_CMD_FLAGS 18
-
-/* ENGINE implementations should start the numbering of their own control
- * commands from this value. (ie. ENGINE_CMD_BASE, ENGINE_CMD_BASE + 1, etc). */
-#define ENGINE_CMD_BASE 200
-
-/* NB: These 2 nCipher "chil" control commands are deprecated, and their
- * functionality is now available through ENGINE-specific control commands
- * (exposed through the above-mentioned 'CMD'-handling). Code using these 2
- * commands should be migrated to the more general command handling before these
- * are removed. */
-
-/* Flags specific to the nCipher "chil" engine */
-#define ENGINE_CTRL_CHIL_SET_FORKCHECK 100
- /* Depending on the value of the (long)i argument, this sets or
- * unsets the SimpleForkCheck flag in the CHIL API to enable or
- * disable checking and workarounds for applications that fork().
- */
-#define ENGINE_CTRL_CHIL_NO_LOCKING 101
- /* This prevents the initialisation function from providing mutex
- * callbacks to the nCipher library. */
-
-/* If an ENGINE supports its own specific control commands and wishes the
- * framework to handle the above 'ENGINE_CMD_***'-manipulation commands on its
- * behalf, it should supply a null-terminated array of ENGINE_CMD_DEFN entries
- * to ENGINE_set_cmd_defns(). It should also implement a ctrl() handler that
- * supports the stated commands (ie. the "cmd_num" entries as described by the
- * array). NB: The array must be ordered in increasing order of cmd_num.
- * "null-terminated" means that the last ENGINE_CMD_DEFN element has cmd_num set
- * to zero and/or cmd_name set to NULL. */
-typedef struct ENGINE_CMD_DEFN_st
- {
- unsigned int cmd_num; /* The command number */
- const char *cmd_name; /* The command name itself */
- const char *cmd_desc; /* A short description of the command */
- unsigned int cmd_flags; /* The input the command expects */
- } ENGINE_CMD_DEFN;
-
-/* Generic function pointer */
-typedef int (*ENGINE_GEN_FUNC_PTR)(void);
-/* Generic function pointer taking no arguments */
-typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *);
-/* Specific control function pointer */
-typedef int (*ENGINE_CTRL_FUNC_PTR)(ENGINE *, int, long, void *, void (*f)(void));
-/* Generic load_key function pointer */
-typedef EVP_PKEY * (*ENGINE_LOAD_KEY_PTR)(ENGINE *, const char *,
- UI_METHOD *ui_method, void *callback_data);
-typedef int (*ENGINE_SSL_CLIENT_CERT_PTR)(ENGINE *, SSL *ssl,
- STACK_OF(X509_NAME) *ca_dn, X509 **pcert, EVP_PKEY **pkey,
- STACK_OF(X509) **pother, UI_METHOD *ui_method, void *callback_data);
-/* These callback types are for an ENGINE's handler for cipher and digest logic.
- * These handlers have these prototypes;
- * int foo(ENGINE *e, const EVP_CIPHER **cipher, const int **nids, int nid);
- * int foo(ENGINE *e, const EVP_MD **digest, const int **nids, int nid);
- * Looking at how to implement these handlers in the case of cipher support, if
- * the framework wants the EVP_CIPHER for 'nid', it will call;
- * foo(e, &p_evp_cipher, NULL, nid); (return zero for failure)
- * If the framework wants a list of supported 'nid's, it will call;
- * foo(e, NULL, &p_nids, 0); (returns number of 'nids' or -1 for error)
- */
-/* Returns to a pointer to the array of supported cipher 'nid's. If the second
- * parameter is non-NULL it is set to the size of the returned array. */
-typedef int (*ENGINE_CIPHERS_PTR)(ENGINE *, const EVP_CIPHER **, const int **, int);
-typedef int (*ENGINE_DIGESTS_PTR)(ENGINE *, const EVP_MD **, const int **, int);
-typedef int (*ENGINE_PKEY_METHS_PTR)(ENGINE *, EVP_PKEY_METHOD **, const int **, int);
-typedef int (*ENGINE_PKEY_ASN1_METHS_PTR)(ENGINE *, EVP_PKEY_ASN1_METHOD **, const int **, int);
-/* STRUCTURE functions ... all of these functions deal with pointers to ENGINE
- * structures where the pointers have a "structural reference". This means that
- * their reference is to allowed access to the structure but it does not imply
- * that the structure is functional. To simply increment or decrement the
- * structural reference count, use ENGINE_by_id and ENGINE_free. NB: This is not
- * required when iterating using ENGINE_get_next as it will automatically
- * decrement the structural reference count of the "current" ENGINE and
- * increment the structural reference count of the ENGINE it returns (unless it
- * is NULL). */
-
-/* Get the first/last "ENGINE" type available. */
-ENGINE *ENGINE_get_first(void);
-ENGINE *ENGINE_get_last(void);
-/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
-ENGINE *ENGINE_get_next(ENGINE *e);
-ENGINE *ENGINE_get_prev(ENGINE *e);
-/* Add another "ENGINE" type into the array. */
-int ENGINE_add(ENGINE *e);
-/* Remove an existing "ENGINE" type from the array. */
-int ENGINE_remove(ENGINE *e);
-/* Retrieve an engine from the list by its unique "id" value. */
-ENGINE *ENGINE_by_id(const char *id);
-/* Add all the built-in engines. */
-void ENGINE_load_openssl(void);
-void ENGINE_load_dynamic(void);
-#ifndef OPENSSL_NO_STATIC_ENGINE
-void ENGINE_load_4758cca(void);
-void ENGINE_load_aep(void);
-void ENGINE_load_atalla(void);
-void ENGINE_load_chil(void);
-void ENGINE_load_cswift(void);
-void ENGINE_load_nuron(void);
-void ENGINE_load_sureware(void);
-void ENGINE_load_ubsec(void);
-void ENGINE_load_padlock(void);
-void ENGINE_load_capi(void);
-#ifndef OPENSSL_NO_GMP
-void ENGINE_load_gmp(void);
-#endif
-#ifndef OPENSSL_NO_GOST
-void ENGINE_load_gost(void);
-#endif
-#endif
-void ENGINE_load_cryptodev(void);
-void ENGINE_load_rsax(void);
-void ENGINE_load_rdrand(void);
-void ENGINE_load_builtin_engines(void);
-
-/* Get and set global flags (ENGINE_TABLE_FLAG_***) for the implementation
- * "registry" handling. */
-unsigned int ENGINE_get_table_flags(void);
-void ENGINE_set_table_flags(unsigned int flags);
-
-/* Manage registration of ENGINEs per "table". For each type, there are 3
- * functions;
- * ENGINE_register_***(e) - registers the implementation from 'e' (if it has one)
- * ENGINE_unregister_***(e) - unregister the implementation from 'e'
- * ENGINE_register_all_***() - call ENGINE_register_***() for each 'e' in the list
- * Cleanup is automatically registered from each table when required, so
- * ENGINE_cleanup() will reverse any "register" operations. */
-
-int ENGINE_register_RSA(ENGINE *e);
-void ENGINE_unregister_RSA(ENGINE *e);
-void ENGINE_register_all_RSA(void);
-
-int ENGINE_register_DSA(ENGINE *e);
-void ENGINE_unregister_DSA(ENGINE *e);
-void ENGINE_register_all_DSA(void);
-
-int ENGINE_register_ECDH(ENGINE *e);
-void ENGINE_unregister_ECDH(ENGINE *e);
-void ENGINE_register_all_ECDH(void);
-
-int ENGINE_register_ECDSA(ENGINE *e);
-void ENGINE_unregister_ECDSA(ENGINE *e);
-void ENGINE_register_all_ECDSA(void);
-
-int ENGINE_register_DH(ENGINE *e);
-void ENGINE_unregister_DH(ENGINE *e);
-void ENGINE_register_all_DH(void);
-
-int ENGINE_register_RAND(ENGINE *e);
-void ENGINE_unregister_RAND(ENGINE *e);
-void ENGINE_register_all_RAND(void);
-
-int ENGINE_register_STORE(ENGINE *e);
-void ENGINE_unregister_STORE(ENGINE *e);
-void ENGINE_register_all_STORE(void);
-
-int ENGINE_register_ciphers(ENGINE *e);
-void ENGINE_unregister_ciphers(ENGINE *e);
-void ENGINE_register_all_ciphers(void);
-
-int ENGINE_register_digests(ENGINE *e);
-void ENGINE_unregister_digests(ENGINE *e);
-void ENGINE_register_all_digests(void);
-
-int ENGINE_register_pkey_meths(ENGINE *e);
-void ENGINE_unregister_pkey_meths(ENGINE *e);
-void ENGINE_register_all_pkey_meths(void);
-
-int ENGINE_register_pkey_asn1_meths(ENGINE *e);
-void ENGINE_unregister_pkey_asn1_meths(ENGINE *e);
-void ENGINE_register_all_pkey_asn1_meths(void);
-
-/* These functions register all support from the above categories. Note, use of
- * these functions can result in static linkage of code your application may not
- * need. If you only need a subset of functionality, consider using more
- * selective initialisation. */
-int ENGINE_register_complete(ENGINE *e);
-int ENGINE_register_all_complete(void);
-
-/* Send parametrised control commands to the engine. The possibilities to send
- * down an integer, a pointer to data or a function pointer are provided. Any of
- * the parameters may or may not be NULL, depending on the command number. In
- * actuality, this function only requires a structural (rather than functional)
- * reference to an engine, but many control commands may require the engine be
- * functional. The caller should be aware of trying commands that require an
- * operational ENGINE, and only use functional references in such situations. */
-int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void));
-
-/* This function tests if an ENGINE-specific command is usable as a "setting".
- * Eg. in an application's config file that gets processed through
- * ENGINE_ctrl_cmd_string(). If this returns zero, it is not available to
- * ENGINE_ctrl_cmd_string(), only ENGINE_ctrl(). */
-int ENGINE_cmd_is_executable(ENGINE *e, int cmd);
-
-/* This function works like ENGINE_ctrl() with the exception of taking a
- * command name instead of a command number, and can handle optional commands.
- * See the comment on ENGINE_ctrl_cmd_string() for an explanation on how to
- * use the cmd_name and cmd_optional. */
-int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
- long i, void *p, void (*f)(void), int cmd_optional);
-
-/* This function passes a command-name and argument to an ENGINE. The cmd_name
- * is converted to a command number and the control command is called using
- * 'arg' as an argument (unless the ENGINE doesn't support such a command, in
- * which case no control command is called). The command is checked for input
- * flags, and if necessary the argument will be converted to a numeric value. If
- * cmd_optional is non-zero, then if the ENGINE doesn't support the given
- * cmd_name the return value will be success anyway. This function is intended
- * for applications to use so that users (or config files) can supply
- * engine-specific config data to the ENGINE at run-time to control behaviour of
- * specific engines. As such, it shouldn't be used for calling ENGINE_ctrl()
- * functions that return data, deal with binary data, or that are otherwise
- * supposed to be used directly through ENGINE_ctrl() in application code. Any
- * "return" data from an ENGINE_ctrl() operation in this function will be lost -
- * the return value is interpreted as failure if the return value is zero,
- * success otherwise, and this function returns a boolean value as a result. In
- * other words, vendors of 'ENGINE'-enabled devices should write ENGINE
- * implementations with parameterisations that work in this scheme, so that
- * compliant ENGINE-based applications can work consistently with the same
- * configuration for the same ENGINE-enabled devices, across applications. */
-int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
- int cmd_optional);
-
-/* These functions are useful for manufacturing new ENGINE structures. They
- * don't address reference counting at all - one uses them to populate an ENGINE
- * structure with personalised implementations of things prior to using it
- * directly or adding it to the builtin ENGINE list in OpenSSL. These are also
- * here so that the ENGINE structure doesn't have to be exposed and break binary
- * compatibility! */
-ENGINE *ENGINE_new(void);
-int ENGINE_free(ENGINE *e);
-int ENGINE_up_ref(ENGINE *e);
-int ENGINE_set_id(ENGINE *e, const char *id);
-int ENGINE_set_name(ENGINE *e, const char *name);
-int ENGINE_set_RSA(ENGINE *e, const RSA_METHOD *rsa_meth);
-int ENGINE_set_DSA(ENGINE *e, const DSA_METHOD *dsa_meth);
-int ENGINE_set_ECDH(ENGINE *e, const ECDH_METHOD *ecdh_meth);
-int ENGINE_set_ECDSA(ENGINE *e, const ECDSA_METHOD *ecdsa_meth);
-int ENGINE_set_DH(ENGINE *e, const DH_METHOD *dh_meth);
-int ENGINE_set_RAND(ENGINE *e, const RAND_METHOD *rand_meth);
-int ENGINE_set_STORE(ENGINE *e, const STORE_METHOD *store_meth);
-int ENGINE_set_destroy_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR destroy_f);
-int ENGINE_set_init_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR init_f);
-int ENGINE_set_finish_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR finish_f);
-int ENGINE_set_ctrl_function(ENGINE *e, ENGINE_CTRL_FUNC_PTR ctrl_f);
-int ENGINE_set_load_privkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpriv_f);
-int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f);
-int ENGINE_set_load_ssl_client_cert_function(ENGINE *e,
- ENGINE_SSL_CLIENT_CERT_PTR loadssl_f);
-int ENGINE_set_ciphers(ENGINE *e, ENGINE_CIPHERS_PTR f);
-int ENGINE_set_digests(ENGINE *e, ENGINE_DIGESTS_PTR f);
-int ENGINE_set_pkey_meths(ENGINE *e, ENGINE_PKEY_METHS_PTR f);
-int ENGINE_set_pkey_asn1_meths(ENGINE *e, ENGINE_PKEY_ASN1_METHS_PTR f);
-int ENGINE_set_flags(ENGINE *e, int flags);
-int ENGINE_set_cmd_defns(ENGINE *e, const ENGINE_CMD_DEFN *defns);
-/* These functions allow control over any per-structure ENGINE data. */
-int ENGINE_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int ENGINE_set_ex_data(ENGINE *e, int idx, void *arg);
-void *ENGINE_get_ex_data(const ENGINE *e, int idx);
-
-/* This function cleans up anything that needs it. Eg. the ENGINE_add() function
- * automatically ensures the list cleanup function is registered to be called
- * from ENGINE_cleanup(). Similarly, all ENGINE_register_*** functions ensure
- * ENGINE_cleanup() will clean up after them. */
-void ENGINE_cleanup(void);
-
-/* These return values from within the ENGINE structure. These can be useful
- * with functional references as well as structural references - it depends
- * which you obtained. Using the result for functional purposes if you only
- * obtained a structural reference may be problematic! */
-const char *ENGINE_get_id(const ENGINE *e);
-const char *ENGINE_get_name(const ENGINE *e);
-const RSA_METHOD *ENGINE_get_RSA(const ENGINE *e);
-const DSA_METHOD *ENGINE_get_DSA(const ENGINE *e);
-const ECDH_METHOD *ENGINE_get_ECDH(const ENGINE *e);
-const ECDSA_METHOD *ENGINE_get_ECDSA(const ENGINE *e);
-const DH_METHOD *ENGINE_get_DH(const ENGINE *e);
-const RAND_METHOD *ENGINE_get_RAND(const ENGINE *e);
-const STORE_METHOD *ENGINE_get_STORE(const ENGINE *e);
-ENGINE_GEN_INT_FUNC_PTR ENGINE_get_destroy_function(const ENGINE *e);
-ENGINE_GEN_INT_FUNC_PTR ENGINE_get_init_function(const ENGINE *e);
-ENGINE_GEN_INT_FUNC_PTR ENGINE_get_finish_function(const ENGINE *e);
-ENGINE_CTRL_FUNC_PTR ENGINE_get_ctrl_function(const ENGINE *e);
-ENGINE_LOAD_KEY_PTR ENGINE_get_load_privkey_function(const ENGINE *e);
-ENGINE_LOAD_KEY_PTR ENGINE_get_load_pubkey_function(const ENGINE *e);
-ENGINE_SSL_CLIENT_CERT_PTR ENGINE_get_ssl_client_cert_function(const ENGINE *e);
-ENGINE_CIPHERS_PTR ENGINE_get_ciphers(const ENGINE *e);
-ENGINE_DIGESTS_PTR ENGINE_get_digests(const ENGINE *e);
-ENGINE_PKEY_METHS_PTR ENGINE_get_pkey_meths(const ENGINE *e);
-ENGINE_PKEY_ASN1_METHS_PTR ENGINE_get_pkey_asn1_meths(const ENGINE *e);
-const EVP_CIPHER *ENGINE_get_cipher(ENGINE *e, int nid);
-const EVP_MD *ENGINE_get_digest(ENGINE *e, int nid);
-const EVP_PKEY_METHOD *ENGINE_get_pkey_meth(ENGINE *e, int nid);
-const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid);
-const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e,
- const char *str, int len);
-const EVP_PKEY_ASN1_METHOD *ENGINE_pkey_asn1_find_str(ENGINE **pe,
- const char *str, int len);
-const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *e);
-int ENGINE_get_flags(const ENGINE *e);
-
-/* FUNCTIONAL functions. These functions deal with ENGINE structures
- * that have (or will) be initialised for use. Broadly speaking, the
- * structural functions are useful for iterating the list of available
- * engine types, creating new engine types, and other "list" operations.
- * These functions actually deal with ENGINEs that are to be used. As
- * such these functions can fail (if applicable) when particular
- * engines are unavailable - eg. if a hardware accelerator is not
- * attached or not functioning correctly. Each ENGINE has 2 reference
- * counts; structural and functional. Every time a functional reference
- * is obtained or released, a corresponding structural reference is
- * automatically obtained or released too. */
-
-/* Initialise a engine type for use (or up its reference count if it's
- * already in use). This will fail if the engine is not currently
- * operational and cannot initialise. */
-int ENGINE_init(ENGINE *e);
-/* Free a functional reference to a engine type. This does not require
- * a corresponding call to ENGINE_free as it also releases a structural
- * reference. */
-int ENGINE_finish(ENGINE *e);
-
-/* The following functions handle keys that are stored in some secondary
- * location, handled by the engine. The storage may be on a card or
- * whatever. */
-EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
- UI_METHOD *ui_method, void *callback_data);
-EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id,
- UI_METHOD *ui_method, void *callback_data);
-int ENGINE_load_ssl_client_cert(ENGINE *e, SSL *s,
- STACK_OF(X509_NAME) *ca_dn, X509 **pcert, EVP_PKEY **ppkey,
- STACK_OF(X509) **pother,
- UI_METHOD *ui_method, void *callback_data);
-
-/* This returns a pointer for the current ENGINE structure that
- * is (by default) performing any RSA operations. The value returned
- * is an incremented reference, so it should be free'd (ENGINE_finish)
- * before it is discarded. */
-ENGINE *ENGINE_get_default_RSA(void);
-/* Same for the other "methods" */
-ENGINE *ENGINE_get_default_DSA(void);
-ENGINE *ENGINE_get_default_ECDH(void);
-ENGINE *ENGINE_get_default_ECDSA(void);
-ENGINE *ENGINE_get_default_DH(void);
-ENGINE *ENGINE_get_default_RAND(void);
-/* These functions can be used to get a functional reference to perform
- * ciphering or digesting corresponding to "nid". */
-ENGINE *ENGINE_get_cipher_engine(int nid);
-ENGINE *ENGINE_get_digest_engine(int nid);
-ENGINE *ENGINE_get_pkey_meth_engine(int nid);
-ENGINE *ENGINE_get_pkey_asn1_meth_engine(int nid);
-
-/* This sets a new default ENGINE structure for performing RSA
- * operations. If the result is non-zero (success) then the ENGINE
- * structure will have had its reference count up'd so the caller
- * should still free their own reference 'e'. */
-int ENGINE_set_default_RSA(ENGINE *e);
-int ENGINE_set_default_string(ENGINE *e, const char *def_list);
-/* Same for the other "methods" */
-int ENGINE_set_default_DSA(ENGINE *e);
-int ENGINE_set_default_ECDH(ENGINE *e);
-int ENGINE_set_default_ECDSA(ENGINE *e);
-int ENGINE_set_default_DH(ENGINE *e);
-int ENGINE_set_default_RAND(ENGINE *e);
-int ENGINE_set_default_ciphers(ENGINE *e);
-int ENGINE_set_default_digests(ENGINE *e);
-int ENGINE_set_default_pkey_meths(ENGINE *e);
-int ENGINE_set_default_pkey_asn1_meths(ENGINE *e);
-
-/* The combination "set" - the flags are bitwise "OR"d from the
- * ENGINE_METHOD_*** defines above. As with the "ENGINE_register_complete()"
- * function, this function can result in unnecessary static linkage. If your
- * application requires only specific functionality, consider using more
- * selective functions. */
-int ENGINE_set_default(ENGINE *e, unsigned int flags);
-
-void ENGINE_add_conf_module(void);
-
-/* Deprecated functions ... */
-/* int ENGINE_clear_defaults(void); */
-
-/**************************/
-/* DYNAMIC ENGINE SUPPORT */
-/**************************/
-
-/* Binary/behaviour compatibility levels */
-#define OSSL_DYNAMIC_VERSION (unsigned long)0x00020000
-/* Binary versions older than this are too old for us (whether we're a loader or
- * a loadee) */
-#define OSSL_DYNAMIC_OLDEST (unsigned long)0x00020000
-
-/* When compiling an ENGINE entirely as an external shared library, loadable by
- * the "dynamic" ENGINE, these types are needed. The 'dynamic_fns' structure
- * type provides the calling application's (or library's) error functionality
- * and memory management function pointers to the loaded library. These should
- * be used/set in the loaded library code so that the loading application's
- * 'state' will be used/changed in all operations. The 'static_state' pointer
- * allows the loaded library to know if it shares the same static data as the
- * calling application (or library), and thus whether these callbacks need to be
- * set or not. */
-typedef void *(*dyn_MEM_malloc_cb)(size_t);
-typedef void *(*dyn_MEM_realloc_cb)(void *, size_t);
-typedef void (*dyn_MEM_free_cb)(void *);
-typedef struct st_dynamic_MEM_fns {
- dyn_MEM_malloc_cb malloc_cb;
- dyn_MEM_realloc_cb realloc_cb;
- dyn_MEM_free_cb free_cb;
- } dynamic_MEM_fns;
-/* FIXME: Perhaps the memory and locking code (crypto.h) should declare and use
- * these types so we (and any other dependant code) can simplify a bit?? */
-typedef void (*dyn_lock_locking_cb)(int,int,const char *,int);
-typedef int (*dyn_lock_add_lock_cb)(int*,int,int,const char *,int);
-typedef struct CRYPTO_dynlock_value *(*dyn_dynlock_create_cb)(
- const char *,int);
-typedef void (*dyn_dynlock_lock_cb)(int,struct CRYPTO_dynlock_value *,
- const char *,int);
-typedef void (*dyn_dynlock_destroy_cb)(struct CRYPTO_dynlock_value *,
- const char *,int);
-typedef struct st_dynamic_LOCK_fns {
- dyn_lock_locking_cb lock_locking_cb;
- dyn_lock_add_lock_cb lock_add_lock_cb;
- dyn_dynlock_create_cb dynlock_create_cb;
- dyn_dynlock_lock_cb dynlock_lock_cb;
- dyn_dynlock_destroy_cb dynlock_destroy_cb;
- } dynamic_LOCK_fns;
-/* The top-level structure */
-typedef struct st_dynamic_fns {
- void *static_state;
- const ERR_FNS *err_fns;
- const CRYPTO_EX_DATA_IMPL *ex_data_fns;
- dynamic_MEM_fns mem_fns;
- dynamic_LOCK_fns lock_fns;
- } dynamic_fns;
-
-/* The version checking function should be of this prototype. NB: The
- * ossl_version value passed in is the OSSL_DYNAMIC_VERSION of the loading code.
- * If this function returns zero, it indicates a (potential) version
- * incompatibility and the loaded library doesn't believe it can proceed.
- * Otherwise, the returned value is the (latest) version supported by the
- * loading library. The loader may still decide that the loaded code's version
- * is unsatisfactory and could veto the load. The function is expected to
- * be implemented with the symbol name "v_check", and a default implementation
- * can be fully instantiated with IMPLEMENT_DYNAMIC_CHECK_FN(). */
-typedef unsigned long (*dynamic_v_check_fn)(unsigned long ossl_version);
-#define IMPLEMENT_DYNAMIC_CHECK_FN() \
- OPENSSL_EXPORT unsigned long v_check(unsigned long v); \
- OPENSSL_EXPORT unsigned long v_check(unsigned long v) { \
- if(v >= OSSL_DYNAMIC_OLDEST) return OSSL_DYNAMIC_VERSION; \
- return 0; }
-
-/* This function is passed the ENGINE structure to initialise with its own
- * function and command settings. It should not adjust the structural or
- * functional reference counts. If this function returns zero, (a) the load will
- * be aborted, (b) the previous ENGINE state will be memcpy'd back onto the
- * structure, and (c) the shared library will be unloaded. So implementations
- * should do their own internal cleanup in failure circumstances otherwise they
- * could leak. The 'id' parameter, if non-NULL, represents the ENGINE id that
- * the loader is looking for. If this is NULL, the shared library can choose to
- * return failure or to initialise a 'default' ENGINE. If non-NULL, the shared
- * library must initialise only an ENGINE matching the passed 'id'. The function
- * is expected to be implemented with the symbol name "bind_engine". A standard
- * implementation can be instantiated with IMPLEMENT_DYNAMIC_BIND_FN(fn) where
- * the parameter 'fn' is a callback function that populates the ENGINE structure
- * and returns an int value (zero for failure). 'fn' should have prototype;
- * [static] int fn(ENGINE *e, const char *id); */
-typedef int (*dynamic_bind_engine)(ENGINE *e, const char *id,
- const dynamic_fns *fns);
-#define IMPLEMENT_DYNAMIC_BIND_FN(fn) \
- OPENSSL_EXPORT \
- int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); \
- OPENSSL_EXPORT \
- int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) { \
- if(ENGINE_get_static_state() == fns->static_state) goto skip_cbs; \
- if(!CRYPTO_set_mem_functions(fns->mem_fns.malloc_cb, \
- fns->mem_fns.realloc_cb, fns->mem_fns.free_cb)) \
- return 0; \
- CRYPTO_set_locking_callback(fns->lock_fns.lock_locking_cb); \
- CRYPTO_set_add_lock_callback(fns->lock_fns.lock_add_lock_cb); \
- CRYPTO_set_dynlock_create_callback(fns->lock_fns.dynlock_create_cb); \
- CRYPTO_set_dynlock_lock_callback(fns->lock_fns.dynlock_lock_cb); \
- CRYPTO_set_dynlock_destroy_callback(fns->lock_fns.dynlock_destroy_cb); \
- if(!CRYPTO_set_ex_data_implementation(fns->ex_data_fns)) \
- return 0; \
- if(!ERR_set_implementation(fns->err_fns)) return 0; \
- skip_cbs: \
- if(!fn(e,id)) return 0; \
- return 1; }
-
-/* If the loading application (or library) and the loaded ENGINE library share
- * the same static data (eg. they're both dynamically linked to the same
- * libcrypto.so) we need a way to avoid trying to set system callbacks - this
- * would fail, and for the same reason that it's unnecessary to try. If the
- * loaded ENGINE has (or gets from through the loader) its own copy of the
- * libcrypto static data, we will need to set the callbacks. The easiest way to
- * detect this is to have a function that returns a pointer to some static data
- * and let the loading application and loaded ENGINE compare their respective
- * values. */
-void *ENGINE_get_static_state(void);
-
-#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV)
-void ENGINE_setup_bsd_cryptodev(void);
-#endif
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_ENGINE_strings(void);
-
-/* Error codes for the ENGINE functions. */
-
-/* Function codes. */
-#define ENGINE_F_DYNAMIC_CTRL 180
-#define ENGINE_F_DYNAMIC_GET_DATA_CTX 181
-#define ENGINE_F_DYNAMIC_LOAD 182
-#define ENGINE_F_DYNAMIC_SET_DATA_CTX 183
-#define ENGINE_F_ENGINE_ADD 105
-#define ENGINE_F_ENGINE_BY_ID 106
-#define ENGINE_F_ENGINE_CMD_IS_EXECUTABLE 170
-#define ENGINE_F_ENGINE_CTRL 142
-#define ENGINE_F_ENGINE_CTRL_CMD 178
-#define ENGINE_F_ENGINE_CTRL_CMD_STRING 171
-#define ENGINE_F_ENGINE_FINISH 107
-#define ENGINE_F_ENGINE_FREE_UTIL 108
-#define ENGINE_F_ENGINE_GET_CIPHER 185
-#define ENGINE_F_ENGINE_GET_DEFAULT_TYPE 177
-#define ENGINE_F_ENGINE_GET_DIGEST 186
-#define ENGINE_F_ENGINE_GET_NEXT 115
-#define ENGINE_F_ENGINE_GET_PKEY_ASN1_METH 193
-#define ENGINE_F_ENGINE_GET_PKEY_METH 192
-#define ENGINE_F_ENGINE_GET_PREV 116
-#define ENGINE_F_ENGINE_INIT 119
-#define ENGINE_F_ENGINE_LIST_ADD 120
-#define ENGINE_F_ENGINE_LIST_REMOVE 121
-#define ENGINE_F_ENGINE_LOAD_PRIVATE_KEY 150
-#define ENGINE_F_ENGINE_LOAD_PUBLIC_KEY 151
-#define ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT 194
-#define ENGINE_F_ENGINE_NEW 122
-#define ENGINE_F_ENGINE_REMOVE 123
-#define ENGINE_F_ENGINE_SET_DEFAULT_STRING 189
-#define ENGINE_F_ENGINE_SET_DEFAULT_TYPE 126
-#define ENGINE_F_ENGINE_SET_ID 129
-#define ENGINE_F_ENGINE_SET_NAME 130
-#define ENGINE_F_ENGINE_TABLE_REGISTER 184
-#define ENGINE_F_ENGINE_UNLOAD_KEY 152
-#define ENGINE_F_ENGINE_UNLOCKED_FINISH 191
-#define ENGINE_F_ENGINE_UP_REF 190
-#define ENGINE_F_INT_CTRL_HELPER 172
-#define ENGINE_F_INT_ENGINE_CONFIGURE 188
-#define ENGINE_F_INT_ENGINE_MODULE_INIT 187
-#define ENGINE_F_LOG_MESSAGE 141
-
-/* Reason codes. */
-#define ENGINE_R_ALREADY_LOADED 100
-#define ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER 133
-#define ENGINE_R_CMD_NOT_EXECUTABLE 134
-#define ENGINE_R_COMMAND_TAKES_INPUT 135
-#define ENGINE_R_COMMAND_TAKES_NO_INPUT 136
-#define ENGINE_R_CONFLICTING_ENGINE_ID 103
-#define ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED 119
-#define ENGINE_R_DH_NOT_IMPLEMENTED 139
-#define ENGINE_R_DSA_NOT_IMPLEMENTED 140
-#define ENGINE_R_DSO_FAILURE 104
-#define ENGINE_R_DSO_NOT_FOUND 132
-#define ENGINE_R_ENGINES_SECTION_ERROR 148
-#define ENGINE_R_ENGINE_CONFIGURATION_ERROR 102
-#define ENGINE_R_ENGINE_IS_NOT_IN_LIST 105
-#define ENGINE_R_ENGINE_SECTION_ERROR 149
-#define ENGINE_R_FAILED_LOADING_PRIVATE_KEY 128
-#define ENGINE_R_FAILED_LOADING_PUBLIC_KEY 129
-#define ENGINE_R_FINISH_FAILED 106
-#define ENGINE_R_GET_HANDLE_FAILED 107
-#define ENGINE_R_ID_OR_NAME_MISSING 108
-#define ENGINE_R_INIT_FAILED 109
-#define ENGINE_R_INTERNAL_LIST_ERROR 110
-#define ENGINE_R_INVALID_ARGUMENT 143
-#define ENGINE_R_INVALID_CMD_NAME 137
-#define ENGINE_R_INVALID_CMD_NUMBER 138
-#define ENGINE_R_INVALID_INIT_VALUE 151
-#define ENGINE_R_INVALID_STRING 150
-#define ENGINE_R_NOT_INITIALISED 117
-#define ENGINE_R_NOT_LOADED 112
-#define ENGINE_R_NO_CONTROL_FUNCTION 120
-#define ENGINE_R_NO_INDEX 144
-#define ENGINE_R_NO_LOAD_FUNCTION 125
-#define ENGINE_R_NO_REFERENCE 130
-#define ENGINE_R_NO_SUCH_ENGINE 116
-#define ENGINE_R_NO_UNLOAD_FUNCTION 126
-#define ENGINE_R_PROVIDE_PARAMETERS 113
-#define ENGINE_R_RSA_NOT_IMPLEMENTED 141
-#define ENGINE_R_UNIMPLEMENTED_CIPHER 146
-#define ENGINE_R_UNIMPLEMENTED_DIGEST 147
-#define ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD 101
-#define ENGINE_R_VERSION_INCOMPATIBILITY 145
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/err.h b/drivers/builtin_openssl/openssl/err.h
deleted file mode 100644
index 974cc9cc6f..0000000000
--- a/drivers/builtin_openssl/openssl/err.h
+++ /dev/null
@@ -1,386 +0,0 @@
-/* crypto/err/err.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_ERR_H
-#define HEADER_ERR_H
-
-#include <openssl/e_os2.h>
-
-#ifndef OPENSSL_NO_FP_API
-#include <stdio.h>
-#include <stdlib.h>
-#endif
-
-#include <openssl/ossl_typ.h>
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#ifndef OPENSSL_NO_LHASH
-#include <openssl/lhash.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef OPENSSL_NO_ERR
-#define ERR_PUT_error(a,b,c,d,e) ERR_put_error(a,b,c,d,e)
-#else
-#define ERR_PUT_error(a,b,c,d,e) ERR_put_error(a,b,c,NULL,0)
-#endif
-
-#include <errno.h>
-
-#define ERR_TXT_MALLOCED 0x01
-#define ERR_TXT_STRING 0x02
-
-#define ERR_FLAG_MARK 0x01
-
-#define ERR_NUM_ERRORS 16
-typedef struct err_state_st
- {
- CRYPTO_THREADID tid;
- int err_flags[ERR_NUM_ERRORS];
- unsigned long err_buffer[ERR_NUM_ERRORS];
- char *err_data[ERR_NUM_ERRORS];
- int err_data_flags[ERR_NUM_ERRORS];
- const char *err_file[ERR_NUM_ERRORS];
- int err_line[ERR_NUM_ERRORS];
- int top,bottom;
- } ERR_STATE;
-
-/* library */
-#define ERR_LIB_NONE 1
-#define ERR_LIB_SYS 2
-#define ERR_LIB_BN 3
-#define ERR_LIB_RSA 4
-#define ERR_LIB_DH 5
-#define ERR_LIB_EVP 6
-#define ERR_LIB_BUF 7
-#define ERR_LIB_OBJ 8
-#define ERR_LIB_PEM 9
-#define ERR_LIB_DSA 10
-#define ERR_LIB_X509 11
-/* #define ERR_LIB_METH 12 */
-#define ERR_LIB_ASN1 13
-#define ERR_LIB_CONF 14
-#define ERR_LIB_CRYPTO 15
-#define ERR_LIB_EC 16
-#define ERR_LIB_SSL 20
-/* #define ERR_LIB_SSL23 21 */
-/* #define ERR_LIB_SSL2 22 */
-/* #define ERR_LIB_SSL3 23 */
-/* #define ERR_LIB_RSAREF 30 */
-/* #define ERR_LIB_PROXY 31 */
-#define ERR_LIB_BIO 32
-#define ERR_LIB_PKCS7 33
-#define ERR_LIB_X509V3 34
-#define ERR_LIB_PKCS12 35
-#define ERR_LIB_RAND 36
-#define ERR_LIB_DSO 37
-#define ERR_LIB_ENGINE 38
-#define ERR_LIB_OCSP 39
-#define ERR_LIB_UI 40
-#define ERR_LIB_COMP 41
-#define ERR_LIB_ECDSA 42
-#define ERR_LIB_ECDH 43
-#define ERR_LIB_STORE 44
-#define ERR_LIB_FIPS 45
-#define ERR_LIB_CMS 46
-#define ERR_LIB_TS 47
-#define ERR_LIB_HMAC 48
-#define ERR_LIB_JPAKE 49
-
-#define ERR_LIB_USER 128
-
-#define SYSerr(f,r) ERR_PUT_error(ERR_LIB_SYS,(f),(r),__FILE__,__LINE__)
-#define BNerr(f,r) ERR_PUT_error(ERR_LIB_BN,(f),(r),__FILE__,__LINE__)
-#define RSAerr(f,r) ERR_PUT_error(ERR_LIB_RSA,(f),(r),__FILE__,__LINE__)
-#define DHerr(f,r) ERR_PUT_error(ERR_LIB_DH,(f),(r),__FILE__,__LINE__)
-#define EVPerr(f,r) ERR_PUT_error(ERR_LIB_EVP,(f),(r),__FILE__,__LINE__)
-#define BUFerr(f,r) ERR_PUT_error(ERR_LIB_BUF,(f),(r),__FILE__,__LINE__)
-#define OBJerr(f,r) ERR_PUT_error(ERR_LIB_OBJ,(f),(r),__FILE__,__LINE__)
-#define PEMerr(f,r) ERR_PUT_error(ERR_LIB_PEM,(f),(r),__FILE__,__LINE__)
-#define DSAerr(f,r) ERR_PUT_error(ERR_LIB_DSA,(f),(r),__FILE__,__LINE__)
-#define X509err(f,r) ERR_PUT_error(ERR_LIB_X509,(f),(r),__FILE__,__LINE__)
-#define ASN1err(f,r) ERR_PUT_error(ERR_LIB_ASN1,(f),(r),__FILE__,__LINE__)
-#define CONFerr(f,r) ERR_PUT_error(ERR_LIB_CONF,(f),(r),__FILE__,__LINE__)
-#define CRYPTOerr(f,r) ERR_PUT_error(ERR_LIB_CRYPTO,(f),(r),__FILE__,__LINE__)
-#define ECerr(f,r) ERR_PUT_error(ERR_LIB_EC,(f),(r),__FILE__,__LINE__)
-#define SSLerr(f,r) ERR_PUT_error(ERR_LIB_SSL,(f),(r),__FILE__,__LINE__)
-#define BIOerr(f,r) ERR_PUT_error(ERR_LIB_BIO,(f),(r),__FILE__,__LINE__)
-#define PKCS7err(f,r) ERR_PUT_error(ERR_LIB_PKCS7,(f),(r),__FILE__,__LINE__)
-#define X509V3err(f,r) ERR_PUT_error(ERR_LIB_X509V3,(f),(r),__FILE__,__LINE__)
-#define PKCS12err(f,r) ERR_PUT_error(ERR_LIB_PKCS12,(f),(r),__FILE__,__LINE__)
-#define RANDerr(f,r) ERR_PUT_error(ERR_LIB_RAND,(f),(r),__FILE__,__LINE__)
-#define DSOerr(f,r) ERR_PUT_error(ERR_LIB_DSO,(f),(r),__FILE__,__LINE__)
-#define ENGINEerr(f,r) ERR_PUT_error(ERR_LIB_ENGINE,(f),(r),__FILE__,__LINE__)
-#define OCSPerr(f,r) ERR_PUT_error(ERR_LIB_OCSP,(f),(r),__FILE__,__LINE__)
-#define UIerr(f,r) ERR_PUT_error(ERR_LIB_UI,(f),(r),__FILE__,__LINE__)
-#define COMPerr(f,r) ERR_PUT_error(ERR_LIB_COMP,(f),(r),__FILE__,__LINE__)
-#define ECDSAerr(f,r) ERR_PUT_error(ERR_LIB_ECDSA,(f),(r),__FILE__,__LINE__)
-#define ECDHerr(f,r) ERR_PUT_error(ERR_LIB_ECDH,(f),(r),__FILE__,__LINE__)
-#define STOREerr(f,r) ERR_PUT_error(ERR_LIB_STORE,(f),(r),__FILE__,__LINE__)
-#define FIPSerr(f,r) ERR_PUT_error(ERR_LIB_FIPS,(f),(r),__FILE__,__LINE__)
-#define CMSerr(f,r) ERR_PUT_error(ERR_LIB_CMS,(f),(r),__FILE__,__LINE__)
-#define TSerr(f,r) ERR_PUT_error(ERR_LIB_TS,(f),(r),__FILE__,__LINE__)
-#define HMACerr(f,r) ERR_PUT_error(ERR_LIB_HMAC,(f),(r),__FILE__,__LINE__)
-#define JPAKEerr(f,r) ERR_PUT_error(ERR_LIB_JPAKE,(f),(r),__FILE__,__LINE__)
-
-/* Borland C seems too stupid to be able to shift and do longs in
- * the pre-processor :-( */
-#define ERR_PACK(l,f,r) (((((unsigned long)l)&0xffL)*0x1000000)| \
- ((((unsigned long)f)&0xfffL)*0x1000)| \
- ((((unsigned long)r)&0xfffL)))
-#define ERR_GET_LIB(l) (int)((((unsigned long)l)>>24L)&0xffL)
-#define ERR_GET_FUNC(l) (int)((((unsigned long)l)>>12L)&0xfffL)
-#define ERR_GET_REASON(l) (int)((l)&0xfffL)
-#define ERR_FATAL_ERROR(l) (int)((l)&ERR_R_FATAL)
-
-
-/* OS functions */
-#define SYS_F_FOPEN 1
-#define SYS_F_CONNECT 2
-#define SYS_F_GETSERVBYNAME 3
-#define SYS_F_SOCKET 4
-#define SYS_F_IOCTLSOCKET 5
-#define SYS_F_BIND 6
-#define SYS_F_LISTEN 7
-#define SYS_F_ACCEPT 8
-#define SYS_F_WSASTARTUP 9 /* Winsock stuff */
-#define SYS_F_OPENDIR 10
-#define SYS_F_FREAD 11
-
-
-/* reasons */
-#define ERR_R_SYS_LIB ERR_LIB_SYS /* 2 */
-#define ERR_R_BN_LIB ERR_LIB_BN /* 3 */
-#define ERR_R_RSA_LIB ERR_LIB_RSA /* 4 */
-#define ERR_R_DH_LIB ERR_LIB_DH /* 5 */
-#define ERR_R_EVP_LIB ERR_LIB_EVP /* 6 */
-#define ERR_R_BUF_LIB ERR_LIB_BUF /* 7 */
-#define ERR_R_OBJ_LIB ERR_LIB_OBJ /* 8 */
-#define ERR_R_PEM_LIB ERR_LIB_PEM /* 9 */
-#define ERR_R_DSA_LIB ERR_LIB_DSA /* 10 */
-#define ERR_R_X509_LIB ERR_LIB_X509 /* 11 */
-#define ERR_R_ASN1_LIB ERR_LIB_ASN1 /* 13 */
-#define ERR_R_CONF_LIB ERR_LIB_CONF /* 14 */
-#define ERR_R_CRYPTO_LIB ERR_LIB_CRYPTO /* 15 */
-#define ERR_R_EC_LIB ERR_LIB_EC /* 16 */
-#define ERR_R_SSL_LIB ERR_LIB_SSL /* 20 */
-#define ERR_R_BIO_LIB ERR_LIB_BIO /* 32 */
-#define ERR_R_PKCS7_LIB ERR_LIB_PKCS7 /* 33 */
-#define ERR_R_X509V3_LIB ERR_LIB_X509V3 /* 34 */
-#define ERR_R_PKCS12_LIB ERR_LIB_PKCS12 /* 35 */
-#define ERR_R_RAND_LIB ERR_LIB_RAND /* 36 */
-#define ERR_R_DSO_LIB ERR_LIB_DSO /* 37 */
-#define ERR_R_ENGINE_LIB ERR_LIB_ENGINE /* 38 */
-#define ERR_R_OCSP_LIB ERR_LIB_OCSP /* 39 */
-#define ERR_R_UI_LIB ERR_LIB_UI /* 40 */
-#define ERR_R_COMP_LIB ERR_LIB_COMP /* 41 */
-#define ERR_R_ECDSA_LIB ERR_LIB_ECDSA /* 42 */
-#define ERR_R_ECDH_LIB ERR_LIB_ECDH /* 43 */
-#define ERR_R_STORE_LIB ERR_LIB_STORE /* 44 */
-#define ERR_R_TS_LIB ERR_LIB_TS /* 45 */
-
-#define ERR_R_NESTED_ASN1_ERROR 58
-#define ERR_R_BAD_ASN1_OBJECT_HEADER 59
-#define ERR_R_BAD_GET_ASN1_OBJECT_CALL 60
-#define ERR_R_EXPECTING_AN_ASN1_SEQUENCE 61
-#define ERR_R_ASN1_LENGTH_MISMATCH 62
-#define ERR_R_MISSING_ASN1_EOS 63
-
-/* fatal error */
-#define ERR_R_FATAL 64
-#define ERR_R_MALLOC_FAILURE (1|ERR_R_FATAL)
-#define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2|ERR_R_FATAL)
-#define ERR_R_PASSED_NULL_PARAMETER (3|ERR_R_FATAL)
-#define ERR_R_INTERNAL_ERROR (4|ERR_R_FATAL)
-#define ERR_R_DISABLED (5|ERR_R_FATAL)
-
-/* 99 is the maximum possible ERR_R_... code, higher values
- * are reserved for the individual libraries */
-
-
-typedef struct ERR_string_data_st
- {
- unsigned long error;
- const char *string;
- } ERR_STRING_DATA;
-
-void ERR_put_error(int lib, int func,int reason,const char *file,int line);
-void ERR_set_error_data(char *data,int flags);
-
-unsigned long ERR_get_error(void);
-unsigned long ERR_get_error_line(const char **file,int *line);
-unsigned long ERR_get_error_line_data(const char **file,int *line,
- const char **data, int *flags);
-unsigned long ERR_peek_error(void);
-unsigned long ERR_peek_error_line(const char **file,int *line);
-unsigned long ERR_peek_error_line_data(const char **file,int *line,
- const char **data,int *flags);
-unsigned long ERR_peek_last_error(void);
-unsigned long ERR_peek_last_error_line(const char **file,int *line);
-unsigned long ERR_peek_last_error_line_data(const char **file,int *line,
- const char **data,int *flags);
-void ERR_clear_error(void );
-char *ERR_error_string(unsigned long e,char *buf);
-void ERR_error_string_n(unsigned long e, char *buf, size_t len);
-const char *ERR_lib_error_string(unsigned long e);
-const char *ERR_func_error_string(unsigned long e);
-const char *ERR_reason_error_string(unsigned long e);
-void ERR_print_errors_cb(int (*cb)(const char *str, size_t len, void *u),
- void *u);
-#ifndef OPENSSL_NO_FP_API
-void ERR_print_errors_fp(FILE *fp);
-#endif
-#ifndef OPENSSL_NO_BIO
-void ERR_print_errors(BIO *bp);
-#endif
-void ERR_add_error_data(int num, ...);
-void ERR_add_error_vdata(int num, va_list args);
-void ERR_load_strings(int lib,ERR_STRING_DATA str[]);
-void ERR_unload_strings(int lib,ERR_STRING_DATA str[]);
-void ERR_load_ERR_strings(void);
-void ERR_load_crypto_strings(void);
-void ERR_free_strings(void);
-
-void ERR_remove_thread_state(const CRYPTO_THREADID *tid);
-#ifndef OPENSSL_NO_DEPRECATED
-void ERR_remove_state(unsigned long pid); /* if zero we look it up */
-#endif
-ERR_STATE *ERR_get_state(void);
-
-#ifndef OPENSSL_NO_LHASH
-LHASH_OF(ERR_STRING_DATA) *ERR_get_string_table(void);
-LHASH_OF(ERR_STATE) *ERR_get_err_state_table(void);
-void ERR_release_err_state_table(LHASH_OF(ERR_STATE) **hash);
-#endif
-
-int ERR_get_next_error_library(void);
-
-int ERR_set_mark(void);
-int ERR_pop_to_mark(void);
-
-/* Already defined in ossl_typ.h */
-/* typedef struct st_ERR_FNS ERR_FNS; */
-/* An application can use this function and provide the return value to loaded
- * modules that should use the application's ERR state/functionality */
-const ERR_FNS *ERR_get_implementation(void);
-/* A loaded module should call this function prior to any ERR operations using
- * the application's "ERR_FNS". */
-int ERR_set_implementation(const ERR_FNS *fns);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/evp.h b/drivers/builtin_openssl/openssl/evp.h
deleted file mode 100644
index faeb3c24e6..0000000000
--- a/drivers/builtin_openssl/openssl/evp.h
+++ /dev/null
@@ -1,1409 +0,0 @@
-/* crypto/evp/evp.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_ENVELOPE_H
-#define HEADER_ENVELOPE_H
-
-#ifdef OPENSSL_ALGORITHM_DEFINES
-# include <openssl/opensslconf.h>
-#else
-# define OPENSSL_ALGORITHM_DEFINES
-# include <openssl/opensslconf.h>
-# undef OPENSSL_ALGORITHM_DEFINES
-#endif
-
-#include <openssl/ossl_typ.h>
-
-#include <openssl/symhacks.h>
-
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-
-/*
-#define EVP_RC2_KEY_SIZE 16
-#define EVP_RC4_KEY_SIZE 16
-#define EVP_BLOWFISH_KEY_SIZE 16
-#define EVP_CAST5_KEY_SIZE 16
-#define EVP_RC5_32_12_16_KEY_SIZE 16
-*/
-#define EVP_MAX_MD_SIZE 64 /* longest known is SHA512 */
-#define EVP_MAX_KEY_LENGTH 64
-#define EVP_MAX_IV_LENGTH 16
-#define EVP_MAX_BLOCK_LENGTH 32
-
-#define PKCS5_SALT_LEN 8
-/* Default PKCS#5 iteration count */
-#define PKCS5_DEFAULT_ITER 2048
-
-#include <openssl/objects.h>
-
-#define EVP_PK_RSA 0x0001
-#define EVP_PK_DSA 0x0002
-#define EVP_PK_DH 0x0004
-#define EVP_PK_EC 0x0008
-#define EVP_PKT_SIGN 0x0010
-#define EVP_PKT_ENC 0x0020
-#define EVP_PKT_EXCH 0x0040
-#define EVP_PKS_RSA 0x0100
-#define EVP_PKS_DSA 0x0200
-#define EVP_PKS_EC 0x0400
-#define EVP_PKT_EXP 0x1000 /* <= 512 bit key */
-
-#define EVP_PKEY_NONE NID_undef
-#define EVP_PKEY_RSA NID_rsaEncryption
-#define EVP_PKEY_RSA2 NID_rsa
-#define EVP_PKEY_DSA NID_dsa
-#define EVP_PKEY_DSA1 NID_dsa_2
-#define EVP_PKEY_DSA2 NID_dsaWithSHA
-#define EVP_PKEY_DSA3 NID_dsaWithSHA1
-#define EVP_PKEY_DSA4 NID_dsaWithSHA1_2
-#define EVP_PKEY_DH NID_dhKeyAgreement
-#define EVP_PKEY_EC NID_X9_62_id_ecPublicKey
-#define EVP_PKEY_HMAC NID_hmac
-#define EVP_PKEY_CMAC NID_cmac
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Type needs to be a bit field
- * Sub-type needs to be for variations on the method, as in, can it do
- * arbitrary encryption.... */
-struct evp_pkey_st
- {
- int type;
- int save_type;
- int references;
- const EVP_PKEY_ASN1_METHOD *ameth;
- ENGINE *engine;
- union {
- char *ptr;
-#ifndef OPENSSL_NO_RSA
- struct rsa_st *rsa; /* RSA */
-#endif
-#ifndef OPENSSL_NO_DSA
- struct dsa_st *dsa; /* DSA */
-#endif
-#ifndef OPENSSL_NO_DH
- struct dh_st *dh; /* DH */
-#endif
-#ifndef OPENSSL_NO_EC
- struct ec_key_st *ec; /* ECC */
-#endif
- } pkey;
- int save_parameters;
- STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
- } /* EVP_PKEY */;
-
-#define EVP_PKEY_MO_SIGN 0x0001
-#define EVP_PKEY_MO_VERIFY 0x0002
-#define EVP_PKEY_MO_ENCRYPT 0x0004
-#define EVP_PKEY_MO_DECRYPT 0x0008
-
-#ifndef EVP_MD
-struct env_md_st
- {
- int type;
- int pkey_type;
- int md_size;
- unsigned long flags;
- int (*init)(EVP_MD_CTX *ctx);
- int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count);
- int (*final)(EVP_MD_CTX *ctx,unsigned char *md);
- int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from);
- int (*cleanup)(EVP_MD_CTX *ctx);
-
- /* FIXME: prototype these some day */
- int (*sign)(int type, const unsigned char *m, unsigned int m_length,
- unsigned char *sigret, unsigned int *siglen, void *key);
- int (*verify)(int type, const unsigned char *m, unsigned int m_length,
- const unsigned char *sigbuf, unsigned int siglen,
- void *key);
- int required_pkey_type[5]; /*EVP_PKEY_xxx */
- int block_size;
- int ctx_size; /* how big does the ctx->md_data need to be */
- /* control function */
- int (*md_ctrl)(EVP_MD_CTX *ctx, int cmd, int p1, void *p2);
- } /* EVP_MD */;
-
-typedef int evp_sign_method(int type,const unsigned char *m,
- unsigned int m_length,unsigned char *sigret,
- unsigned int *siglen, void *key);
-typedef int evp_verify_method(int type,const unsigned char *m,
- unsigned int m_length,const unsigned char *sigbuf,
- unsigned int siglen, void *key);
-
-#define EVP_MD_FLAG_ONESHOT 0x0001 /* digest can only handle a single
- * block */
-
-#define EVP_MD_FLAG_PKEY_DIGEST 0x0002 /* digest is a "clone" digest used
- * which is a copy of an existing
- * one for a specific public key type.
- * EVP_dss1() etc */
-
-/* Digest uses EVP_PKEY_METHOD for signing instead of MD specific signing */
-
-#define EVP_MD_FLAG_PKEY_METHOD_SIGNATURE 0x0004
-
-/* DigestAlgorithmIdentifier flags... */
-
-#define EVP_MD_FLAG_DIGALGID_MASK 0x0018
-
-/* NULL or absent parameter accepted. Use NULL */
-
-#define EVP_MD_FLAG_DIGALGID_NULL 0x0000
-
-/* NULL or absent parameter accepted. Use NULL for PKCS#1 otherwise absent */
-
-#define EVP_MD_FLAG_DIGALGID_ABSENT 0x0008
-
-/* Custom handling via ctrl */
-
-#define EVP_MD_FLAG_DIGALGID_CUSTOM 0x0018
-
-#define EVP_MD_FLAG_FIPS 0x0400 /* Note if suitable for use in FIPS mode */
-
-/* Digest ctrls */
-
-#define EVP_MD_CTRL_DIGALGID 0x1
-#define EVP_MD_CTRL_MICALG 0x2
-
-/* Minimum Algorithm specific ctrl value */
-
-#define EVP_MD_CTRL_ALG_CTRL 0x1000
-
-#define EVP_PKEY_NULL_method NULL,NULL,{0,0,0,0}
-
-#ifndef OPENSSL_NO_DSA
-#define EVP_PKEY_DSA_method (evp_sign_method *)DSA_sign, \
- (evp_verify_method *)DSA_verify, \
- {EVP_PKEY_DSA,EVP_PKEY_DSA2,EVP_PKEY_DSA3, \
- EVP_PKEY_DSA4,0}
-#else
-#define EVP_PKEY_DSA_method EVP_PKEY_NULL_method
-#endif
-
-#ifndef OPENSSL_NO_ECDSA
-#define EVP_PKEY_ECDSA_method (evp_sign_method *)ECDSA_sign, \
- (evp_verify_method *)ECDSA_verify, \
- {EVP_PKEY_EC,0,0,0}
-#else
-#define EVP_PKEY_ECDSA_method EVP_PKEY_NULL_method
-#endif
-
-#ifndef OPENSSL_NO_RSA
-#define EVP_PKEY_RSA_method (evp_sign_method *)RSA_sign, \
- (evp_verify_method *)RSA_verify, \
- {EVP_PKEY_RSA,EVP_PKEY_RSA2,0,0}
-#define EVP_PKEY_RSA_ASN1_OCTET_STRING_method \
- (evp_sign_method *)RSA_sign_ASN1_OCTET_STRING, \
- (evp_verify_method *)RSA_verify_ASN1_OCTET_STRING, \
- {EVP_PKEY_RSA,EVP_PKEY_RSA2,0,0}
-#else
-#define EVP_PKEY_RSA_method EVP_PKEY_NULL_method
-#define EVP_PKEY_RSA_ASN1_OCTET_STRING_method EVP_PKEY_NULL_method
-#endif
-
-#endif /* !EVP_MD */
-
-struct env_md_ctx_st
- {
- const EVP_MD *digest;
- ENGINE *engine; /* functional reference if 'digest' is ENGINE-provided */
- unsigned long flags;
- void *md_data;
- /* Public key context for sign/verify */
- EVP_PKEY_CTX *pctx;
- /* Update function: usually copied from EVP_MD */
- int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count);
- } /* EVP_MD_CTX */;
-
-/* values for EVP_MD_CTX flags */
-
-#define EVP_MD_CTX_FLAG_ONESHOT 0x0001 /* digest update will be called
- * once only */
-#define EVP_MD_CTX_FLAG_CLEANED 0x0002 /* context has already been
- * cleaned */
-#define EVP_MD_CTX_FLAG_REUSE 0x0004 /* Don't free up ctx->md_data
- * in EVP_MD_CTX_cleanup */
-/* FIPS and pad options are ignored in 1.0.0, definitions are here
- * so we don't accidentally reuse the values for other purposes.
- */
-
-#define EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 0x0008 /* Allow use of non FIPS digest
- * in FIPS mode */
-
-/* The following PAD options are also currently ignored in 1.0.0, digest
- * parameters are handled through EVP_DigestSign*() and EVP_DigestVerify*()
- * instead.
- */
-#define EVP_MD_CTX_FLAG_PAD_MASK 0xF0 /* RSA mode to use */
-#define EVP_MD_CTX_FLAG_PAD_PKCS1 0x00 /* PKCS#1 v1.5 mode */
-#define EVP_MD_CTX_FLAG_PAD_X931 0x10 /* X9.31 mode */
-#define EVP_MD_CTX_FLAG_PAD_PSS 0x20 /* PSS mode */
-
-#define EVP_MD_CTX_FLAG_NO_INIT 0x0100 /* Don't initialize md_data */
-
-struct evp_cipher_st
- {
- int nid;
- int block_size;
- int key_len; /* Default value for variable length ciphers */
- int iv_len;
- unsigned long flags; /* Various flags */
- int (*init)(EVP_CIPHER_CTX *ctx, const unsigned char *key,
- const unsigned char *iv, int enc); /* init key */
- int (*do_cipher)(EVP_CIPHER_CTX *ctx, unsigned char *out,
- const unsigned char *in, size_t inl);/* encrypt/decrypt data */
- int (*cleanup)(EVP_CIPHER_CTX *); /* cleanup ctx */
- int ctx_size; /* how big ctx->cipher_data needs to be */
- int (*set_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Populate a ASN1_TYPE with parameters */
- int (*get_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Get parameters from a ASN1_TYPE */
- int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); /* Miscellaneous operations */
- void *app_data; /* Application data */
- } /* EVP_CIPHER */;
-
-/* Values for cipher flags */
-
-/* Modes for ciphers */
-
-#define EVP_CIPH_STREAM_CIPHER 0x0
-#define EVP_CIPH_ECB_MODE 0x1
-#define EVP_CIPH_CBC_MODE 0x2
-#define EVP_CIPH_CFB_MODE 0x3
-#define EVP_CIPH_OFB_MODE 0x4
-#define EVP_CIPH_CTR_MODE 0x5
-#define EVP_CIPH_GCM_MODE 0x6
-#define EVP_CIPH_CCM_MODE 0x7
-#define EVP_CIPH_XTS_MODE 0x10001
-#define EVP_CIPH_MODE 0xF0007
-/* Set if variable length cipher */
-#define EVP_CIPH_VARIABLE_LENGTH 0x8
-/* Set if the iv handling should be done by the cipher itself */
-#define EVP_CIPH_CUSTOM_IV 0x10
-/* Set if the cipher's init() function should be called if key is NULL */
-#define EVP_CIPH_ALWAYS_CALL_INIT 0x20
-/* Call ctrl() to init cipher parameters */
-#define EVP_CIPH_CTRL_INIT 0x40
-/* Don't use standard key length function */
-#define EVP_CIPH_CUSTOM_KEY_LENGTH 0x80
-/* Don't use standard block padding */
-#define EVP_CIPH_NO_PADDING 0x100
-/* cipher handles random key generation */
-#define EVP_CIPH_RAND_KEY 0x200
-/* cipher has its own additional copying logic */
-#define EVP_CIPH_CUSTOM_COPY 0x400
-/* Allow use default ASN1 get/set iv */
-#define EVP_CIPH_FLAG_DEFAULT_ASN1 0x1000
-/* Buffer length in bits not bytes: CFB1 mode only */
-#define EVP_CIPH_FLAG_LENGTH_BITS 0x2000
-/* Note if suitable for use in FIPS mode */
-#define EVP_CIPH_FLAG_FIPS 0x4000
-/* Allow non FIPS cipher in FIPS mode */
-#define EVP_CIPH_FLAG_NON_FIPS_ALLOW 0x8000
-/* Cipher handles any and all padding logic as well
- * as finalisation.
- */
-#define EVP_CIPH_FLAG_CUSTOM_CIPHER 0x100000
-#define EVP_CIPH_FLAG_AEAD_CIPHER 0x200000
-
-/* ctrl() values */
-
-#define EVP_CTRL_INIT 0x0
-#define EVP_CTRL_SET_KEY_LENGTH 0x1
-#define EVP_CTRL_GET_RC2_KEY_BITS 0x2
-#define EVP_CTRL_SET_RC2_KEY_BITS 0x3
-#define EVP_CTRL_GET_RC5_ROUNDS 0x4
-#define EVP_CTRL_SET_RC5_ROUNDS 0x5
-#define EVP_CTRL_RAND_KEY 0x6
-#define EVP_CTRL_PBE_PRF_NID 0x7
-#define EVP_CTRL_COPY 0x8
-#define EVP_CTRL_GCM_SET_IVLEN 0x9
-#define EVP_CTRL_GCM_GET_TAG 0x10
-#define EVP_CTRL_GCM_SET_TAG 0x11
-#define EVP_CTRL_GCM_SET_IV_FIXED 0x12
-#define EVP_CTRL_GCM_IV_GEN 0x13
-#define EVP_CTRL_CCM_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN
-#define EVP_CTRL_CCM_GET_TAG EVP_CTRL_GCM_GET_TAG
-#define EVP_CTRL_CCM_SET_TAG EVP_CTRL_GCM_SET_TAG
-#define EVP_CTRL_CCM_SET_L 0x14
-#define EVP_CTRL_CCM_SET_MSGLEN 0x15
-/* AEAD cipher deduces payload length and returns number of bytes
- * required to store MAC and eventual padding. Subsequent call to
- * EVP_Cipher even appends/verifies MAC.
- */
-#define EVP_CTRL_AEAD_TLS1_AAD 0x16
-/* Used by composite AEAD ciphers, no-op in GCM, CCM... */
-#define EVP_CTRL_AEAD_SET_MAC_KEY 0x17
-/* Set the GCM invocation field, decrypt only */
-#define EVP_CTRL_GCM_SET_IV_INV 0x18
-
-/* GCM TLS constants */
-/* Length of fixed part of IV derived from PRF */
-#define EVP_GCM_TLS_FIXED_IV_LEN 4
-/* Length of explicit part of IV part of TLS records */
-#define EVP_GCM_TLS_EXPLICIT_IV_LEN 8
-/* Length of tag for TLS */
-#define EVP_GCM_TLS_TAG_LEN 16
-
-typedef struct evp_cipher_info_st
- {
- const EVP_CIPHER *cipher;
- unsigned char iv[EVP_MAX_IV_LENGTH];
- } EVP_CIPHER_INFO;
-
-struct evp_cipher_ctx_st
- {
- const EVP_CIPHER *cipher;
- ENGINE *engine; /* functional reference if 'cipher' is ENGINE-provided */
- int encrypt; /* encrypt or decrypt */
- int buf_len; /* number we have left */
-
- unsigned char oiv[EVP_MAX_IV_LENGTH]; /* original iv */
- unsigned char iv[EVP_MAX_IV_LENGTH]; /* working iv */
- unsigned char buf[EVP_MAX_BLOCK_LENGTH];/* saved partial block */
- int num; /* used by cfb/ofb/ctr mode */
-
- void *app_data; /* application stuff */
- int key_len; /* May change for variable length cipher */
- unsigned long flags; /* Various flags */
- void *cipher_data; /* per EVP data */
- int final_used;
- int block_mask;
- unsigned char final[EVP_MAX_BLOCK_LENGTH];/* possible final block */
- } /* EVP_CIPHER_CTX */;
-
-typedef struct evp_Encode_Ctx_st
- {
- int num; /* number saved in a partial encode/decode */
- int length; /* The length is either the output line length
- * (in input bytes) or the shortest input line
- * length that is ok. Once decoding begins,
- * the length is adjusted up each time a longer
- * line is decoded */
- unsigned char enc_data[80]; /* data to encode */
- int line_num; /* number read on current line */
- int expect_nl;
- } EVP_ENCODE_CTX;
-
-/* Password based encryption function */
-typedef int (EVP_PBE_KEYGEN)(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
- ASN1_TYPE *param, const EVP_CIPHER *cipher,
- const EVP_MD *md, int en_de);
-
-#ifndef OPENSSL_NO_RSA
-#define EVP_PKEY_assign_RSA(pkey,rsa) EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
- (char *)(rsa))
-#endif
-
-#ifndef OPENSSL_NO_DSA
-#define EVP_PKEY_assign_DSA(pkey,dsa) EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
- (char *)(dsa))
-#endif
-
-#ifndef OPENSSL_NO_DH
-#define EVP_PKEY_assign_DH(pkey,dh) EVP_PKEY_assign((pkey),EVP_PKEY_DH,\
- (char *)(dh))
-#endif
-
-#ifndef OPENSSL_NO_EC
-#define EVP_PKEY_assign_EC_KEY(pkey,eckey) EVP_PKEY_assign((pkey),EVP_PKEY_EC,\
- (char *)(eckey))
-#endif
-
-/* Add some extra combinations */
-#define EVP_get_digestbynid(a) EVP_get_digestbyname(OBJ_nid2sn(a))
-#define EVP_get_digestbyobj(a) EVP_get_digestbynid(OBJ_obj2nid(a))
-#define EVP_get_cipherbynid(a) EVP_get_cipherbyname(OBJ_nid2sn(a))
-#define EVP_get_cipherbyobj(a) EVP_get_cipherbynid(OBJ_obj2nid(a))
-
-int EVP_MD_type(const EVP_MD *md);
-#define EVP_MD_nid(e) EVP_MD_type(e)
-#define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_nid(e))
-int EVP_MD_pkey_type(const EVP_MD *md);
-int EVP_MD_size(const EVP_MD *md);
-int EVP_MD_block_size(const EVP_MD *md);
-unsigned long EVP_MD_flags(const EVP_MD *md);
-
-const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx);
-#define EVP_MD_CTX_size(e) EVP_MD_size(EVP_MD_CTX_md(e))
-#define EVP_MD_CTX_block_size(e) EVP_MD_block_size(EVP_MD_CTX_md(e))
-#define EVP_MD_CTX_type(e) EVP_MD_type(EVP_MD_CTX_md(e))
-
-int EVP_CIPHER_nid(const EVP_CIPHER *cipher);
-#define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e))
-int EVP_CIPHER_block_size(const EVP_CIPHER *cipher);
-int EVP_CIPHER_key_length(const EVP_CIPHER *cipher);
-int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher);
-unsigned long EVP_CIPHER_flags(const EVP_CIPHER *cipher);
-#define EVP_CIPHER_mode(e) (EVP_CIPHER_flags(e) & EVP_CIPH_MODE)
-
-const EVP_CIPHER * EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx);
-int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx);
-int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx);
-int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx);
-int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx);
-int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in);
-void * EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx);
-void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data);
-#define EVP_CIPHER_CTX_type(c) EVP_CIPHER_type(EVP_CIPHER_CTX_cipher(c))
-unsigned long EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx);
-#define EVP_CIPHER_CTX_mode(e) (EVP_CIPHER_CTX_flags(e) & EVP_CIPH_MODE)
-
-#define EVP_ENCODE_LENGTH(l) (((l+2)/3*4)+(l/48+1)*2+80)
-#define EVP_DECODE_LENGTH(l) ((l+3)/4*3+80)
-
-#define EVP_SignInit_ex(a,b,c) EVP_DigestInit_ex(a,b,c)
-#define EVP_SignInit(a,b) EVP_DigestInit(a,b)
-#define EVP_SignUpdate(a,b,c) EVP_DigestUpdate(a,b,c)
-#define EVP_VerifyInit_ex(a,b,c) EVP_DigestInit_ex(a,b,c)
-#define EVP_VerifyInit(a,b) EVP_DigestInit(a,b)
-#define EVP_VerifyUpdate(a,b,c) EVP_DigestUpdate(a,b,c)
-#define EVP_OpenUpdate(a,b,c,d,e) EVP_DecryptUpdate(a,b,c,d,e)
-#define EVP_SealUpdate(a,b,c,d,e) EVP_EncryptUpdate(a,b,c,d,e)
-#define EVP_DigestSignUpdate(a,b,c) EVP_DigestUpdate(a,b,c)
-#define EVP_DigestVerifyUpdate(a,b,c) EVP_DigestUpdate(a,b,c)
-
-#ifdef CONST_STRICT
-void BIO_set_md(BIO *,const EVP_MD *md);
-#else
-# define BIO_set_md(b,md) BIO_ctrl(b,BIO_C_SET_MD,0,(char *)md)
-#endif
-#define BIO_get_md(b,mdp) BIO_ctrl(b,BIO_C_GET_MD,0,(char *)mdp)
-#define BIO_get_md_ctx(b,mdcp) BIO_ctrl(b,BIO_C_GET_MD_CTX,0,(char *)mdcp)
-#define BIO_set_md_ctx(b,mdcp) BIO_ctrl(b,BIO_C_SET_MD_CTX,0,(char *)mdcp)
-#define BIO_get_cipher_status(b) BIO_ctrl(b,BIO_C_GET_CIPHER_STATUS,0,NULL)
-#define BIO_get_cipher_ctx(b,c_pp) BIO_ctrl(b,BIO_C_GET_CIPHER_CTX,0,(char *)c_pp)
-
-int EVP_Cipher(EVP_CIPHER_CTX *c,
- unsigned char *out,
- const unsigned char *in,
- unsigned int inl);
-
-#define EVP_add_cipher_alias(n,alias) \
- OBJ_NAME_add((alias),OBJ_NAME_TYPE_CIPHER_METH|OBJ_NAME_ALIAS,(n))
-#define EVP_add_digest_alias(n,alias) \
- OBJ_NAME_add((alias),OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS,(n))
-#define EVP_delete_cipher_alias(alias) \
- OBJ_NAME_remove(alias,OBJ_NAME_TYPE_CIPHER_METH|OBJ_NAME_ALIAS);
-#define EVP_delete_digest_alias(alias) \
- OBJ_NAME_remove(alias,OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS);
-
-void EVP_MD_CTX_init(EVP_MD_CTX *ctx);
-int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx);
-EVP_MD_CTX *EVP_MD_CTX_create(void);
-void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx);
-int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out,const EVP_MD_CTX *in);
-void EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, int flags);
-void EVP_MD_CTX_clear_flags(EVP_MD_CTX *ctx, int flags);
-int EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx,int flags);
-int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
-int EVP_DigestUpdate(EVP_MD_CTX *ctx,const void *d,
- size_t cnt);
-int EVP_DigestFinal_ex(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s);
-int EVP_Digest(const void *data, size_t count,
- unsigned char *md, unsigned int *size, const EVP_MD *type, ENGINE *impl);
-
-int EVP_MD_CTX_copy(EVP_MD_CTX *out,const EVP_MD_CTX *in);
-int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type);
-int EVP_DigestFinal(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s);
-
-int EVP_read_pw_string(char *buf,int length,const char *prompt,int verify);
-int EVP_read_pw_string_min(char *buf,int minlen,int maxlen,const char *prompt,int verify);
-void EVP_set_pw_prompt(const char *prompt);
-char * EVP_get_pw_prompt(void);
-
-int EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md,
- const unsigned char *salt, const unsigned char *data,
- int datal, int count, unsigned char *key,unsigned char *iv);
-
-void EVP_CIPHER_CTX_set_flags(EVP_CIPHER_CTX *ctx, int flags);
-void EVP_CIPHER_CTX_clear_flags(EVP_CIPHER_CTX *ctx, int flags);
-int EVP_CIPHER_CTX_test_flags(const EVP_CIPHER_CTX *ctx,int flags);
-
-int EVP_EncryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
- const unsigned char *key, const unsigned char *iv);
-int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
- const unsigned char *key, const unsigned char *iv);
-int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
- int *outl, const unsigned char *in, int inl);
-int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
-int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
-
-int EVP_DecryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
- const unsigned char *key, const unsigned char *iv);
-int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
- const unsigned char *key, const unsigned char *iv);
-int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
- int *outl, const unsigned char *in, int inl);
-int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
-int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
-
-int EVP_CipherInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
- const unsigned char *key,const unsigned char *iv,
- int enc);
-int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
- const unsigned char *key,const unsigned char *iv,
- int enc);
-int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
- int *outl, const unsigned char *in, int inl);
-int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
-int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
-
-int EVP_SignFinal(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s,
- EVP_PKEY *pkey);
-
-int EVP_VerifyFinal(EVP_MD_CTX *ctx,const unsigned char *sigbuf,
- unsigned int siglen,EVP_PKEY *pkey);
-
-int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
- const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
-int EVP_DigestSignFinal(EVP_MD_CTX *ctx,
- unsigned char *sigret, size_t *siglen);
-
-int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
- const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
-int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx,
- unsigned char *sig, size_t siglen);
-
-int EVP_OpenInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *type,
- const unsigned char *ek, int ekl, const unsigned char *iv,
- EVP_PKEY *priv);
-int EVP_OpenFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
-
-int EVP_SealInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
- unsigned char **ek, int *ekl, unsigned char *iv,
- EVP_PKEY **pubk, int npubk);
-int EVP_SealFinal(EVP_CIPHER_CTX *ctx,unsigned char *out,int *outl);
-
-void EVP_EncodeInit(EVP_ENCODE_CTX *ctx);
-void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl,
- const unsigned char *in,int inl);
-void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl);
-int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int n);
-
-void EVP_DecodeInit(EVP_ENCODE_CTX *ctx);
-int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl,
- const unsigned char *in, int inl);
-int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned
- char *out, int *outl);
-int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n);
-
-void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a);
-int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);
-EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void);
-void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
-int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
-int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad);
-int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
-int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key);
-
-#ifndef OPENSSL_NO_BIO
-BIO_METHOD *BIO_f_md(void);
-BIO_METHOD *BIO_f_base64(void);
-BIO_METHOD *BIO_f_cipher(void);
-BIO_METHOD *BIO_f_reliable(void);
-void BIO_set_cipher(BIO *b,const EVP_CIPHER *c,const unsigned char *k,
- const unsigned char *i, int enc);
-#endif
-
-const EVP_MD *EVP_md_null(void);
-#ifndef OPENSSL_NO_MD2
-const EVP_MD *EVP_md2(void);
-#endif
-#ifndef OPENSSL_NO_MD4
-const EVP_MD *EVP_md4(void);
-#endif
-#ifndef OPENSSL_NO_MD5
-const EVP_MD *EVP_md5(void);
-#endif
-#ifndef OPENSSL_NO_SHA
-const EVP_MD *EVP_sha(void);
-const EVP_MD *EVP_sha1(void);
-const EVP_MD *EVP_dss(void);
-const EVP_MD *EVP_dss1(void);
-const EVP_MD *EVP_ecdsa(void);
-#endif
-#ifndef OPENSSL_NO_SHA256
-const EVP_MD *EVP_sha224(void);
-const EVP_MD *EVP_sha256(void);
-#endif
-#ifndef OPENSSL_NO_SHA512
-const EVP_MD *EVP_sha384(void);
-const EVP_MD *EVP_sha512(void);
-#endif
-#ifndef OPENSSL_NO_MDC2
-const EVP_MD *EVP_mdc2(void);
-#endif
-#ifndef OPENSSL_NO_RIPEMD
-const EVP_MD *EVP_ripemd160(void);
-#endif
-#ifndef OPENSSL_NO_WHIRLPOOL
-const EVP_MD *EVP_whirlpool(void);
-#endif
-const EVP_CIPHER *EVP_enc_null(void); /* does nothing :-) */
-#ifndef OPENSSL_NO_DES
-const EVP_CIPHER *EVP_des_ecb(void);
-const EVP_CIPHER *EVP_des_ede(void);
-const EVP_CIPHER *EVP_des_ede3(void);
-const EVP_CIPHER *EVP_des_ede_ecb(void);
-const EVP_CIPHER *EVP_des_ede3_ecb(void);
-const EVP_CIPHER *EVP_des_cfb64(void);
-# define EVP_des_cfb EVP_des_cfb64
-const EVP_CIPHER *EVP_des_cfb1(void);
-const EVP_CIPHER *EVP_des_cfb8(void);
-const EVP_CIPHER *EVP_des_ede_cfb64(void);
-# define EVP_des_ede_cfb EVP_des_ede_cfb64
-#if 0
-const EVP_CIPHER *EVP_des_ede_cfb1(void);
-const EVP_CIPHER *EVP_des_ede_cfb8(void);
-#endif
-const EVP_CIPHER *EVP_des_ede3_cfb64(void);
-# define EVP_des_ede3_cfb EVP_des_ede3_cfb64
-const EVP_CIPHER *EVP_des_ede3_cfb1(void);
-const EVP_CIPHER *EVP_des_ede3_cfb8(void);
-const EVP_CIPHER *EVP_des_ofb(void);
-const EVP_CIPHER *EVP_des_ede_ofb(void);
-const EVP_CIPHER *EVP_des_ede3_ofb(void);
-const EVP_CIPHER *EVP_des_cbc(void);
-const EVP_CIPHER *EVP_des_ede_cbc(void);
-const EVP_CIPHER *EVP_des_ede3_cbc(void);
-const EVP_CIPHER *EVP_desx_cbc(void);
-/* This should now be supported through the dev_crypto ENGINE. But also, why are
- * rc4 and md5 declarations made here inside a "NO_DES" precompiler branch? */
-#if 0
-# ifdef OPENSSL_OPENBSD_DEV_CRYPTO
-const EVP_CIPHER *EVP_dev_crypto_des_ede3_cbc(void);
-const EVP_CIPHER *EVP_dev_crypto_rc4(void);
-const EVP_MD *EVP_dev_crypto_md5(void);
-# endif
-#endif
-#endif
-#ifndef OPENSSL_NO_RC4
-const EVP_CIPHER *EVP_rc4(void);
-const EVP_CIPHER *EVP_rc4_40(void);
-#ifndef OPENSSL_NO_MD5
-const EVP_CIPHER *EVP_rc4_hmac_md5(void);
-#endif
-#endif
-#ifndef OPENSSL_NO_IDEA
-const EVP_CIPHER *EVP_idea_ecb(void);
-const EVP_CIPHER *EVP_idea_cfb64(void);
-# define EVP_idea_cfb EVP_idea_cfb64
-const EVP_CIPHER *EVP_idea_ofb(void);
-const EVP_CIPHER *EVP_idea_cbc(void);
-#endif
-#ifndef OPENSSL_NO_RC2
-const EVP_CIPHER *EVP_rc2_ecb(void);
-const EVP_CIPHER *EVP_rc2_cbc(void);
-const EVP_CIPHER *EVP_rc2_40_cbc(void);
-const EVP_CIPHER *EVP_rc2_64_cbc(void);
-const EVP_CIPHER *EVP_rc2_cfb64(void);
-# define EVP_rc2_cfb EVP_rc2_cfb64
-const EVP_CIPHER *EVP_rc2_ofb(void);
-#endif
-#ifndef OPENSSL_NO_BF
-const EVP_CIPHER *EVP_bf_ecb(void);
-const EVP_CIPHER *EVP_bf_cbc(void);
-const EVP_CIPHER *EVP_bf_cfb64(void);
-# define EVP_bf_cfb EVP_bf_cfb64
-const EVP_CIPHER *EVP_bf_ofb(void);
-#endif
-#ifndef OPENSSL_NO_CAST
-const EVP_CIPHER *EVP_cast5_ecb(void);
-const EVP_CIPHER *EVP_cast5_cbc(void);
-const EVP_CIPHER *EVP_cast5_cfb64(void);
-# define EVP_cast5_cfb EVP_cast5_cfb64
-const EVP_CIPHER *EVP_cast5_ofb(void);
-#endif
-#ifndef OPENSSL_NO_RC5
-const EVP_CIPHER *EVP_rc5_32_12_16_cbc(void);
-const EVP_CIPHER *EVP_rc5_32_12_16_ecb(void);
-const EVP_CIPHER *EVP_rc5_32_12_16_cfb64(void);
-# define EVP_rc5_32_12_16_cfb EVP_rc5_32_12_16_cfb64
-const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void);
-#endif
-#ifndef OPENSSL_NO_AES
-const EVP_CIPHER *EVP_aes_128_ecb(void);
-const EVP_CIPHER *EVP_aes_128_cbc(void);
-const EVP_CIPHER *EVP_aes_128_cfb1(void);
-const EVP_CIPHER *EVP_aes_128_cfb8(void);
-const EVP_CIPHER *EVP_aes_128_cfb128(void);
-# define EVP_aes_128_cfb EVP_aes_128_cfb128
-const EVP_CIPHER *EVP_aes_128_ofb(void);
-const EVP_CIPHER *EVP_aes_128_ctr(void);
-const EVP_CIPHER *EVP_aes_128_ccm(void);
-const EVP_CIPHER *EVP_aes_128_gcm(void);
-const EVP_CIPHER *EVP_aes_128_xts(void);
-const EVP_CIPHER *EVP_aes_192_ecb(void);
-const EVP_CIPHER *EVP_aes_192_cbc(void);
-const EVP_CIPHER *EVP_aes_192_cfb1(void);
-const EVP_CIPHER *EVP_aes_192_cfb8(void);
-const EVP_CIPHER *EVP_aes_192_cfb128(void);
-# define EVP_aes_192_cfb EVP_aes_192_cfb128
-const EVP_CIPHER *EVP_aes_192_ofb(void);
-const EVP_CIPHER *EVP_aes_192_ctr(void);
-const EVP_CIPHER *EVP_aes_192_ccm(void);
-const EVP_CIPHER *EVP_aes_192_gcm(void);
-const EVP_CIPHER *EVP_aes_256_ecb(void);
-const EVP_CIPHER *EVP_aes_256_cbc(void);
-const EVP_CIPHER *EVP_aes_256_cfb1(void);
-const EVP_CIPHER *EVP_aes_256_cfb8(void);
-const EVP_CIPHER *EVP_aes_256_cfb128(void);
-# define EVP_aes_256_cfb EVP_aes_256_cfb128
-const EVP_CIPHER *EVP_aes_256_ofb(void);
-const EVP_CIPHER *EVP_aes_256_ctr(void);
-const EVP_CIPHER *EVP_aes_256_ccm(void);
-const EVP_CIPHER *EVP_aes_256_gcm(void);
-const EVP_CIPHER *EVP_aes_256_xts(void);
-#if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1)
-const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void);
-const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void);
-#endif
-#endif
-#ifndef OPENSSL_NO_CAMELLIA
-const EVP_CIPHER *EVP_camellia_128_ecb(void);
-const EVP_CIPHER *EVP_camellia_128_cbc(void);
-const EVP_CIPHER *EVP_camellia_128_cfb1(void);
-const EVP_CIPHER *EVP_camellia_128_cfb8(void);
-const EVP_CIPHER *EVP_camellia_128_cfb128(void);
-# define EVP_camellia_128_cfb EVP_camellia_128_cfb128
-const EVP_CIPHER *EVP_camellia_128_ofb(void);
-const EVP_CIPHER *EVP_camellia_192_ecb(void);
-const EVP_CIPHER *EVP_camellia_192_cbc(void);
-const EVP_CIPHER *EVP_camellia_192_cfb1(void);
-const EVP_CIPHER *EVP_camellia_192_cfb8(void);
-const EVP_CIPHER *EVP_camellia_192_cfb128(void);
-# define EVP_camellia_192_cfb EVP_camellia_192_cfb128
-const EVP_CIPHER *EVP_camellia_192_ofb(void);
-const EVP_CIPHER *EVP_camellia_256_ecb(void);
-const EVP_CIPHER *EVP_camellia_256_cbc(void);
-const EVP_CIPHER *EVP_camellia_256_cfb1(void);
-const EVP_CIPHER *EVP_camellia_256_cfb8(void);
-const EVP_CIPHER *EVP_camellia_256_cfb128(void);
-# define EVP_camellia_256_cfb EVP_camellia_256_cfb128
-const EVP_CIPHER *EVP_camellia_256_ofb(void);
-#endif
-
-#ifndef OPENSSL_NO_SEED
-const EVP_CIPHER *EVP_seed_ecb(void);
-const EVP_CIPHER *EVP_seed_cbc(void);
-const EVP_CIPHER *EVP_seed_cfb128(void);
-# define EVP_seed_cfb EVP_seed_cfb128
-const EVP_CIPHER *EVP_seed_ofb(void);
-#endif
-
-void OPENSSL_add_all_algorithms_noconf(void);
-void OPENSSL_add_all_algorithms_conf(void);
-
-#ifdef OPENSSL_LOAD_CONF
-#define OpenSSL_add_all_algorithms() \
- OPENSSL_add_all_algorithms_conf()
-#else
-#define OpenSSL_add_all_algorithms() \
- OPENSSL_add_all_algorithms_noconf()
-#endif
-
-void OpenSSL_add_all_ciphers(void);
-void OpenSSL_add_all_digests(void);
-#define SSLeay_add_all_algorithms() OpenSSL_add_all_algorithms()
-#define SSLeay_add_all_ciphers() OpenSSL_add_all_ciphers()
-#define SSLeay_add_all_digests() OpenSSL_add_all_digests()
-
-int EVP_add_cipher(const EVP_CIPHER *cipher);
-int EVP_add_digest(const EVP_MD *digest);
-
-const EVP_CIPHER *EVP_get_cipherbyname(const char *name);
-const EVP_MD *EVP_get_digestbyname(const char *name);
-void EVP_cleanup(void);
-
-void EVP_CIPHER_do_all(void (*fn)(const EVP_CIPHER *ciph,
- const char *from, const char *to, void *x), void *arg);
-void EVP_CIPHER_do_all_sorted(void (*fn)(const EVP_CIPHER *ciph,
- const char *from, const char *to, void *x), void *arg);
-
-void EVP_MD_do_all(void (*fn)(const EVP_MD *ciph,
- const char *from, const char *to, void *x), void *arg);
-void EVP_MD_do_all_sorted(void (*fn)(const EVP_MD *ciph,
- const char *from, const char *to, void *x), void *arg);
-
-int EVP_PKEY_decrypt_old(unsigned char *dec_key,
- const unsigned char *enc_key,int enc_key_len,
- EVP_PKEY *private_key);
-int EVP_PKEY_encrypt_old(unsigned char *enc_key,
- const unsigned char *key,int key_len,
- EVP_PKEY *pub_key);
-int EVP_PKEY_type(int type);
-int EVP_PKEY_id(const EVP_PKEY *pkey);
-int EVP_PKEY_base_id(const EVP_PKEY *pkey);
-int EVP_PKEY_bits(EVP_PKEY *pkey);
-int EVP_PKEY_size(EVP_PKEY *pkey);
-int EVP_PKEY_set_type(EVP_PKEY *pkey,int type);
-int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len);
-int EVP_PKEY_assign(EVP_PKEY *pkey,int type,void *key);
-void * EVP_PKEY_get0(EVP_PKEY *pkey);
-
-#ifndef OPENSSL_NO_RSA
-struct rsa_st;
-int EVP_PKEY_set1_RSA(EVP_PKEY *pkey,struct rsa_st *key);
-struct rsa_st *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
-#endif
-#ifndef OPENSSL_NO_DSA
-struct dsa_st;
-int EVP_PKEY_set1_DSA(EVP_PKEY *pkey,struct dsa_st *key);
-struct dsa_st *EVP_PKEY_get1_DSA(EVP_PKEY *pkey);
-#endif
-#ifndef OPENSSL_NO_DH
-struct dh_st;
-int EVP_PKEY_set1_DH(EVP_PKEY *pkey,struct dh_st *key);
-struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey);
-#endif
-#ifndef OPENSSL_NO_EC
-struct ec_key_st;
-int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey,struct ec_key_st *key);
-struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey);
-#endif
-
-EVP_PKEY * EVP_PKEY_new(void);
-void EVP_PKEY_free(EVP_PKEY *pkey);
-
-EVP_PKEY * d2i_PublicKey(int type,EVP_PKEY **a, const unsigned char **pp,
- long length);
-int i2d_PublicKey(EVP_PKEY *a, unsigned char **pp);
-
-EVP_PKEY * d2i_PrivateKey(int type,EVP_PKEY **a, const unsigned char **pp,
- long length);
-EVP_PKEY * d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp,
- long length);
-int i2d_PrivateKey(EVP_PKEY *a, unsigned char **pp);
-
-int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from);
-int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey);
-int EVP_PKEY_save_parameters(EVP_PKEY *pkey,int mode);
-int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b);
-
-int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
-
-int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey,
- int indent, ASN1_PCTX *pctx);
-int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey,
- int indent, ASN1_PCTX *pctx);
-int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey,
- int indent, ASN1_PCTX *pctx);
-
-int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid);
-
-int EVP_CIPHER_type(const EVP_CIPHER *ctx);
-
-/* calls methods */
-int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
-int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
-
-/* These are used by EVP_CIPHER methods */
-int EVP_CIPHER_set_asn1_iv(EVP_CIPHER_CTX *c,ASN1_TYPE *type);
-int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *c,ASN1_TYPE *type);
-
-/* PKCS5 password based encryption */
-int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
- ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md,
- int en_de);
-int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
- const unsigned char *salt, int saltlen, int iter,
- int keylen, unsigned char *out);
-int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
- const unsigned char *salt, int saltlen, int iter,
- const EVP_MD *digest,
- int keylen, unsigned char *out);
-int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
- ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md,
- int en_de);
-
-void PKCS5_PBE_add(void);
-
-int EVP_PBE_CipherInit (ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
- ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de);
-
-/* PBE type */
-
-/* Can appear as the outermost AlgorithmIdentifier */
-#define EVP_PBE_TYPE_OUTER 0x0
-/* Is an PRF type OID */
-#define EVP_PBE_TYPE_PRF 0x1
-
-int EVP_PBE_alg_add_type(int pbe_type, int pbe_nid, int cipher_nid, int md_nid,
- EVP_PBE_KEYGEN *keygen);
-int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md,
- EVP_PBE_KEYGEN *keygen);
-int EVP_PBE_find(int type, int pbe_nid,
- int *pcnid, int *pmnid, EVP_PBE_KEYGEN **pkeygen);
-void EVP_PBE_cleanup(void);
-
-#define ASN1_PKEY_ALIAS 0x1
-#define ASN1_PKEY_DYNAMIC 0x2
-#define ASN1_PKEY_SIGPARAM_NULL 0x4
-
-#define ASN1_PKEY_CTRL_PKCS7_SIGN 0x1
-#define ASN1_PKEY_CTRL_PKCS7_ENCRYPT 0x2
-#define ASN1_PKEY_CTRL_DEFAULT_MD_NID 0x3
-#define ASN1_PKEY_CTRL_CMS_SIGN 0x5
-#define ASN1_PKEY_CTRL_CMS_ENVELOPE 0x7
-
-int EVP_PKEY_asn1_get_count(void);
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx);
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pe, int type);
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pe,
- const char *str, int len);
-int EVP_PKEY_asn1_add0(const EVP_PKEY_ASN1_METHOD *ameth);
-int EVP_PKEY_asn1_add_alias(int to, int from);
-int EVP_PKEY_asn1_get0_info(int *ppkey_id, int *pkey_base_id, int *ppkey_flags,
- const char **pinfo, const char **ppem_str,
- const EVP_PKEY_ASN1_METHOD *ameth);
-
-const EVP_PKEY_ASN1_METHOD* EVP_PKEY_get0_asn1(EVP_PKEY *pkey);
-EVP_PKEY_ASN1_METHOD* EVP_PKEY_asn1_new(int id, int flags,
- const char *pem_str, const char *info);
-void EVP_PKEY_asn1_copy(EVP_PKEY_ASN1_METHOD *dst,
- const EVP_PKEY_ASN1_METHOD *src);
-void EVP_PKEY_asn1_free(EVP_PKEY_ASN1_METHOD *ameth);
-void EVP_PKEY_asn1_set_public(EVP_PKEY_ASN1_METHOD *ameth,
- int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub),
- int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk),
- int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b),
- int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *pctx),
- int (*pkey_size)(const EVP_PKEY *pk),
- int (*pkey_bits)(const EVP_PKEY *pk));
-void EVP_PKEY_asn1_set_private(EVP_PKEY_ASN1_METHOD *ameth,
- int (*priv_decode)(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf),
- int (*priv_encode)(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk),
- int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *pctx));
-void EVP_PKEY_asn1_set_param(EVP_PKEY_ASN1_METHOD *ameth,
- int (*param_decode)(EVP_PKEY *pkey,
- const unsigned char **pder, int derlen),
- int (*param_encode)(const EVP_PKEY *pkey, unsigned char **pder),
- int (*param_missing)(const EVP_PKEY *pk),
- int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from),
- int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b),
- int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *pctx));
-
-void EVP_PKEY_asn1_set_free(EVP_PKEY_ASN1_METHOD *ameth,
- void (*pkey_free)(EVP_PKEY *pkey));
-void EVP_PKEY_asn1_set_ctrl(EVP_PKEY_ASN1_METHOD *ameth,
- int (*pkey_ctrl)(EVP_PKEY *pkey, int op,
- long arg1, void *arg2));
-
-
-#define EVP_PKEY_OP_UNDEFINED 0
-#define EVP_PKEY_OP_PARAMGEN (1<<1)
-#define EVP_PKEY_OP_KEYGEN (1<<2)
-#define EVP_PKEY_OP_SIGN (1<<3)
-#define EVP_PKEY_OP_VERIFY (1<<4)
-#define EVP_PKEY_OP_VERIFYRECOVER (1<<5)
-#define EVP_PKEY_OP_SIGNCTX (1<<6)
-#define EVP_PKEY_OP_VERIFYCTX (1<<7)
-#define EVP_PKEY_OP_ENCRYPT (1<<8)
-#define EVP_PKEY_OP_DECRYPT (1<<9)
-#define EVP_PKEY_OP_DERIVE (1<<10)
-
-#define EVP_PKEY_OP_TYPE_SIG \
- (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER \
- | EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX)
-
-#define EVP_PKEY_OP_TYPE_CRYPT \
- (EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT)
-
-#define EVP_PKEY_OP_TYPE_NOGEN \
- (EVP_PKEY_OP_SIG | EVP_PKEY_OP_CRYPT | EVP_PKEY_OP_DERIVE)
-
-#define EVP_PKEY_OP_TYPE_GEN \
- (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN)
-
-#define EVP_PKEY_CTX_set_signature_md(ctx, md) \
- EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, \
- EVP_PKEY_CTRL_MD, 0, (void *)md)
-
-#define EVP_PKEY_CTRL_MD 1
-#define EVP_PKEY_CTRL_PEER_KEY 2
-
-#define EVP_PKEY_CTRL_PKCS7_ENCRYPT 3
-#define EVP_PKEY_CTRL_PKCS7_DECRYPT 4
-
-#define EVP_PKEY_CTRL_PKCS7_SIGN 5
-
-#define EVP_PKEY_CTRL_SET_MAC_KEY 6
-
-#define EVP_PKEY_CTRL_DIGESTINIT 7
-
-/* Used by GOST key encryption in TLS */
-#define EVP_PKEY_CTRL_SET_IV 8
-
-#define EVP_PKEY_CTRL_CMS_ENCRYPT 9
-#define EVP_PKEY_CTRL_CMS_DECRYPT 10
-#define EVP_PKEY_CTRL_CMS_SIGN 11
-
-#define EVP_PKEY_CTRL_CIPHER 12
-
-#define EVP_PKEY_ALG_CTRL 0x1000
-
-
-#define EVP_PKEY_FLAG_AUTOARGLEN 2
-/* Method handles all operations: don't assume any digest related
- * defaults.
- */
-#define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4
-
-const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type);
-EVP_PKEY_METHOD* EVP_PKEY_meth_new(int id, int flags);
-void EVP_PKEY_meth_get0_info(int *ppkey_id, int *pflags,
- const EVP_PKEY_METHOD *meth);
-void EVP_PKEY_meth_copy(EVP_PKEY_METHOD *dst, const EVP_PKEY_METHOD *src);
-void EVP_PKEY_meth_free(EVP_PKEY_METHOD *pmeth);
-int EVP_PKEY_meth_add0(const EVP_PKEY_METHOD *pmeth);
-
-EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
-EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
-EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx);
-void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
-
-int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
- int cmd, int p1, void *p2);
-int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
- const char *value);
-
-int EVP_PKEY_CTX_get_operation(EVP_PKEY_CTX *ctx);
-void EVP_PKEY_CTX_set0_keygen_info(EVP_PKEY_CTX *ctx, int *dat, int datlen);
-
-EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e,
- const unsigned char *key, int keylen);
-
-void EVP_PKEY_CTX_set_data(EVP_PKEY_CTX *ctx, void *data);
-void *EVP_PKEY_CTX_get_data(EVP_PKEY_CTX *ctx);
-EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx);
-
-EVP_PKEY *EVP_PKEY_CTX_get0_peerkey(EVP_PKEY_CTX *ctx);
-
-void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
-void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
-
-int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
- unsigned char *sig, size_t *siglen,
- const unsigned char *tbs, size_t tbslen);
-int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
- const unsigned char *sig, size_t siglen,
- const unsigned char *tbs, size_t tbslen);
-int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
- unsigned char *rout, size_t *routlen,
- const unsigned char *sig, size_t siglen);
-int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx,
- unsigned char *out, size_t *outlen,
- const unsigned char *in, size_t inlen);
-int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,
- unsigned char *out, size_t *outlen,
- const unsigned char *in, size_t inlen);
-
-int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer);
-int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
-
-typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx);
-
-int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
-int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
-
-void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb);
-EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx);
-
-int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx);
-
-void EVP_PKEY_meth_set_init(EVP_PKEY_METHOD *pmeth,
- int (*init)(EVP_PKEY_CTX *ctx));
-
-void EVP_PKEY_meth_set_copy(EVP_PKEY_METHOD *pmeth,
- int (*copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src));
-
-void EVP_PKEY_meth_set_cleanup(EVP_PKEY_METHOD *pmeth,
- void (*cleanup)(EVP_PKEY_CTX *ctx));
-
-void EVP_PKEY_meth_set_paramgen(EVP_PKEY_METHOD *pmeth,
- int (*paramgen_init)(EVP_PKEY_CTX *ctx),
- int (*paramgen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey));
-
-void EVP_PKEY_meth_set_keygen(EVP_PKEY_METHOD *pmeth,
- int (*keygen_init)(EVP_PKEY_CTX *ctx),
- int (*keygen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey));
-
-void EVP_PKEY_meth_set_sign(EVP_PKEY_METHOD *pmeth,
- int (*sign_init)(EVP_PKEY_CTX *ctx),
- int (*sign)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
- const unsigned char *tbs, size_t tbslen));
-
-void EVP_PKEY_meth_set_verify(EVP_PKEY_METHOD *pmeth,
- int (*verify_init)(EVP_PKEY_CTX *ctx),
- int (*verify)(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen,
- const unsigned char *tbs, size_t tbslen));
-
-void EVP_PKEY_meth_set_verify_recover(EVP_PKEY_METHOD *pmeth,
- int (*verify_recover_init)(EVP_PKEY_CTX *ctx),
- int (*verify_recover)(EVP_PKEY_CTX *ctx,
- unsigned char *sig, size_t *siglen,
- const unsigned char *tbs, size_t tbslen));
-
-void EVP_PKEY_meth_set_signctx(EVP_PKEY_METHOD *pmeth,
- int (*signctx_init)(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx),
- int (*signctx)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
- EVP_MD_CTX *mctx));
-
-void EVP_PKEY_meth_set_verifyctx(EVP_PKEY_METHOD *pmeth,
- int (*verifyctx_init)(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx),
- int (*verifyctx)(EVP_PKEY_CTX *ctx, const unsigned char *sig,int siglen,
- EVP_MD_CTX *mctx));
-
-void EVP_PKEY_meth_set_encrypt(EVP_PKEY_METHOD *pmeth,
- int (*encrypt_init)(EVP_PKEY_CTX *ctx),
- int (*encryptfn)(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
- const unsigned char *in, size_t inlen));
-
-void EVP_PKEY_meth_set_decrypt(EVP_PKEY_METHOD *pmeth,
- int (*decrypt_init)(EVP_PKEY_CTX *ctx),
- int (*decrypt)(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
- const unsigned char *in, size_t inlen));
-
-void EVP_PKEY_meth_set_derive(EVP_PKEY_METHOD *pmeth,
- int (*derive_init)(EVP_PKEY_CTX *ctx),
- int (*derive)(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen));
-
-void EVP_PKEY_meth_set_ctrl(EVP_PKEY_METHOD *pmeth,
- int (*ctrl)(EVP_PKEY_CTX *ctx, int type, int p1, void *p2),
- int (*ctrl_str)(EVP_PKEY_CTX *ctx,
- const char *type, const char *value));
-
-void EVP_add_alg_module(void);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_EVP_strings(void);
-
-/* Error codes for the EVP functions. */
-
-/* Function codes. */
-#define EVP_F_AESNI_INIT_KEY 165
-#define EVP_F_AESNI_XTS_CIPHER 176
-#define EVP_F_AES_INIT_KEY 133
-#define EVP_F_AES_XTS 172
-#define EVP_F_AES_XTS_CIPHER 175
-#define EVP_F_ALG_MODULE_INIT 177
-#define EVP_F_CAMELLIA_INIT_KEY 159
-#define EVP_F_CMAC_INIT 173
-#define EVP_F_D2I_PKEY 100
-#define EVP_F_DO_SIGVER_INIT 161
-#define EVP_F_DSAPKEY2PKCS8 134
-#define EVP_F_DSA_PKEY2PKCS8 135
-#define EVP_F_ECDSA_PKEY2PKCS8 129
-#define EVP_F_ECKEY_PKEY2PKCS8 132
-#define EVP_F_EVP_CIPHERINIT_EX 123
-#define EVP_F_EVP_CIPHER_CTX_COPY 163
-#define EVP_F_EVP_CIPHER_CTX_CTRL 124
-#define EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH 122
-#define EVP_F_EVP_DECRYPTFINAL_EX 101
-#define EVP_F_EVP_DIGESTINIT_EX 128
-#define EVP_F_EVP_ENCRYPTFINAL_EX 127
-#define EVP_F_EVP_MD_CTX_COPY_EX 110
-#define EVP_F_EVP_MD_SIZE 162
-#define EVP_F_EVP_OPENINIT 102
-#define EVP_F_EVP_PBE_ALG_ADD 115
-#define EVP_F_EVP_PBE_ALG_ADD_TYPE 160
-#define EVP_F_EVP_PBE_CIPHERINIT 116
-#define EVP_F_EVP_PKCS82PKEY 111
-#define EVP_F_EVP_PKCS82PKEY_BROKEN 136
-#define EVP_F_EVP_PKEY2PKCS8_BROKEN 113
-#define EVP_F_EVP_PKEY_COPY_PARAMETERS 103
-#define EVP_F_EVP_PKEY_CTX_CTRL 137
-#define EVP_F_EVP_PKEY_CTX_CTRL_STR 150
-#define EVP_F_EVP_PKEY_CTX_DUP 156
-#define EVP_F_EVP_PKEY_DECRYPT 104
-#define EVP_F_EVP_PKEY_DECRYPT_INIT 138
-#define EVP_F_EVP_PKEY_DECRYPT_OLD 151
-#define EVP_F_EVP_PKEY_DERIVE 153
-#define EVP_F_EVP_PKEY_DERIVE_INIT 154
-#define EVP_F_EVP_PKEY_DERIVE_SET_PEER 155
-#define EVP_F_EVP_PKEY_ENCRYPT 105
-#define EVP_F_EVP_PKEY_ENCRYPT_INIT 139
-#define EVP_F_EVP_PKEY_ENCRYPT_OLD 152
-#define EVP_F_EVP_PKEY_GET1_DH 119
-#define EVP_F_EVP_PKEY_GET1_DSA 120
-#define EVP_F_EVP_PKEY_GET1_ECDSA 130
-#define EVP_F_EVP_PKEY_GET1_EC_KEY 131
-#define EVP_F_EVP_PKEY_GET1_RSA 121
-#define EVP_F_EVP_PKEY_KEYGEN 146
-#define EVP_F_EVP_PKEY_KEYGEN_INIT 147
-#define EVP_F_EVP_PKEY_NEW 106
-#define EVP_F_EVP_PKEY_PARAMGEN 148
-#define EVP_F_EVP_PKEY_PARAMGEN_INIT 149
-#define EVP_F_EVP_PKEY_SIGN 140
-#define EVP_F_EVP_PKEY_SIGN_INIT 141
-#define EVP_F_EVP_PKEY_VERIFY 142
-#define EVP_F_EVP_PKEY_VERIFY_INIT 143
-#define EVP_F_EVP_PKEY_VERIFY_RECOVER 144
-#define EVP_F_EVP_PKEY_VERIFY_RECOVER_INIT 145
-#define EVP_F_EVP_RIJNDAEL 126
-#define EVP_F_EVP_SIGNFINAL 107
-#define EVP_F_EVP_VERIFYFINAL 108
-#define EVP_F_FIPS_CIPHERINIT 166
-#define EVP_F_FIPS_CIPHER_CTX_COPY 170
-#define EVP_F_FIPS_CIPHER_CTX_CTRL 167
-#define EVP_F_FIPS_CIPHER_CTX_SET_KEY_LENGTH 171
-#define EVP_F_FIPS_DIGESTINIT 168
-#define EVP_F_FIPS_MD_CTX_COPY 169
-#define EVP_F_HMAC_INIT_EX 174
-#define EVP_F_INT_CTX_NEW 157
-#define EVP_F_PKCS5_PBE_KEYIVGEN 117
-#define EVP_F_PKCS5_V2_PBE_KEYIVGEN 118
-#define EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN 164
-#define EVP_F_PKCS8_SET_BROKEN 112
-#define EVP_F_PKEY_SET_TYPE 158
-#define EVP_F_RC2_MAGIC_TO_METH 109
-#define EVP_F_RC5_CTRL 125
-
-/* Reason codes. */
-#define EVP_R_AES_IV_SETUP_FAILED 162
-#define EVP_R_AES_KEY_SETUP_FAILED 143
-#define EVP_R_ASN1_LIB 140
-#define EVP_R_BAD_BLOCK_LENGTH 136
-#define EVP_R_BAD_DECRYPT 100
-#define EVP_R_BAD_KEY_LENGTH 137
-#define EVP_R_BN_DECODE_ERROR 112
-#define EVP_R_BN_PUBKEY_ERROR 113
-#define EVP_R_BUFFER_TOO_SMALL 155
-#define EVP_R_CAMELLIA_KEY_SETUP_FAILED 157
-#define EVP_R_CIPHER_PARAMETER_ERROR 122
-#define EVP_R_COMMAND_NOT_SUPPORTED 147
-#define EVP_R_CTRL_NOT_IMPLEMENTED 132
-#define EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED 133
-#define EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH 138
-#define EVP_R_DECODE_ERROR 114
-#define EVP_R_DIFFERENT_KEY_TYPES 101
-#define EVP_R_DIFFERENT_PARAMETERS 153
-#define EVP_R_DISABLED_FOR_FIPS 163
-#define EVP_R_ENCODE_ERROR 115
-#define EVP_R_ERROR_LOADING_SECTION 165
-#define EVP_R_ERROR_SETTING_FIPS_MODE 166
-#define EVP_R_EVP_PBE_CIPHERINIT_ERROR 119
-#define EVP_R_EXPECTING_AN_RSA_KEY 127
-#define EVP_R_EXPECTING_A_DH_KEY 128
-#define EVP_R_EXPECTING_A_DSA_KEY 129
-#define EVP_R_EXPECTING_A_ECDSA_KEY 141
-#define EVP_R_EXPECTING_A_EC_KEY 142
-#define EVP_R_FIPS_MODE_NOT_SUPPORTED 167
-#define EVP_R_INITIALIZATION_ERROR 134
-#define EVP_R_INPUT_NOT_INITIALIZED 111
-#define EVP_R_INVALID_DIGEST 152
-#define EVP_R_INVALID_FIPS_MODE 168
-#define EVP_R_INVALID_KEY_LENGTH 130
-#define EVP_R_INVALID_OPERATION 148
-#define EVP_R_IV_TOO_LARGE 102
-#define EVP_R_KEYGEN_FAILURE 120
-#define EVP_R_MESSAGE_DIGEST_IS_NULL 159
-#define EVP_R_METHOD_NOT_SUPPORTED 144
-#define EVP_R_MISSING_PARAMETERS 103
-#define EVP_R_NO_CIPHER_SET 131
-#define EVP_R_NO_DEFAULT_DIGEST 158
-#define EVP_R_NO_DIGEST_SET 139
-#define EVP_R_NO_DSA_PARAMETERS 116
-#define EVP_R_NO_KEY_SET 154
-#define EVP_R_NO_OPERATION_SET 149
-#define EVP_R_NO_SIGN_FUNCTION_CONFIGURED 104
-#define EVP_R_NO_VERIFY_FUNCTION_CONFIGURED 105
-#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 150
-#define EVP_R_OPERATON_NOT_INITIALIZED 151
-#define EVP_R_PKCS8_UNKNOWN_BROKEN_TYPE 117
-#define EVP_R_PRIVATE_KEY_DECODE_ERROR 145
-#define EVP_R_PRIVATE_KEY_ENCODE_ERROR 146
-#define EVP_R_PUBLIC_KEY_NOT_RSA 106
-#define EVP_R_TOO_LARGE 164
-#define EVP_R_UNKNOWN_CIPHER 160
-#define EVP_R_UNKNOWN_DIGEST 161
-#define EVP_R_UNKNOWN_OPTION 169
-#define EVP_R_UNKNOWN_PBE_ALGORITHM 121
-#define EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS 135
-#define EVP_R_UNSUPPORTED_ALGORITHM 156
-#define EVP_R_UNSUPPORTED_CIPHER 107
-#define EVP_R_UNSUPPORTED_KEYLENGTH 123
-#define EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION 124
-#define EVP_R_UNSUPPORTED_KEY_SIZE 108
-#define EVP_R_UNSUPPORTED_PRF 125
-#define EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 118
-#define EVP_R_UNSUPPORTED_SALT_TYPE 126
-#define EVP_R_WRONG_FINAL_BLOCK_LENGTH 109
-#define EVP_R_WRONG_PUBLIC_KEY_TYPE 110
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/hmac.h b/drivers/builtin_openssl/openssl/hmac.h
deleted file mode 100644
index 1be0022190..0000000000
--- a/drivers/builtin_openssl/openssl/hmac.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* crypto/hmac/hmac.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-#ifndef HEADER_HMAC_H
-#define HEADER_HMAC_H
-
-#include <openssl/opensslconf.h>
-
-#ifdef OPENSSL_NO_HMAC
-#error HMAC is disabled.
-#endif
-
-#include <openssl/evp.h>
-
-#define HMAC_MAX_MD_CBLOCK 128 /* largest known is SHA512 */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct hmac_ctx_st
- {
- const EVP_MD *md;
- EVP_MD_CTX md_ctx;
- EVP_MD_CTX i_ctx;
- EVP_MD_CTX o_ctx;
- unsigned int key_length;
- unsigned char key[HMAC_MAX_MD_CBLOCK];
- } HMAC_CTX;
-
-#define HMAC_size(e) (EVP_MD_size((e)->md))
-
-
-void HMAC_CTX_init(HMAC_CTX *ctx);
-void HMAC_CTX_cleanup(HMAC_CTX *ctx);
-
-#define HMAC_cleanup(ctx) HMAC_CTX_cleanup(ctx) /* deprecated */
-
-int HMAC_Init(HMAC_CTX *ctx, const void *key, int len,
- const EVP_MD *md); /* deprecated */
-int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
- const EVP_MD *md, ENGINE *impl);
-int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len);
-int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len);
-unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
- const unsigned char *d, size_t n, unsigned char *md,
- unsigned int *md_len);
-int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx);
-
-void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/idea.h b/drivers/builtin_openssl/openssl/idea.h
deleted file mode 100644
index e9a1e7f1a5..0000000000
--- a/drivers/builtin_openssl/openssl/idea.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* crypto/idea/idea.h */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_IDEA_H
-#define HEADER_IDEA_H
-
-#include <openssl/opensslconf.h> /* IDEA_INT, OPENSSL_NO_IDEA */
-
-#ifdef OPENSSL_NO_IDEA
-#error IDEA is disabled.
-#endif
-
-#define IDEA_ENCRYPT 1
-#define IDEA_DECRYPT 0
-
-#define IDEA_BLOCK 8
-#define IDEA_KEY_LENGTH 16
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct idea_key_st
- {
- IDEA_INT data[9][6];
- } IDEA_KEY_SCHEDULE;
-
-const char *idea_options(void);
-void idea_ecb_encrypt(const unsigned char *in, unsigned char *out,
- IDEA_KEY_SCHEDULE *ks);
-#ifdef OPENSSL_FIPS
-void private_idea_set_encrypt_key(const unsigned char *key, IDEA_KEY_SCHEDULE *ks);
-#endif
-void idea_set_encrypt_key(const unsigned char *key, IDEA_KEY_SCHEDULE *ks);
-void idea_set_decrypt_key(IDEA_KEY_SCHEDULE *ek, IDEA_KEY_SCHEDULE *dk);
-void idea_cbc_encrypt(const unsigned char *in, unsigned char *out,
- long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv,int enc);
-void idea_cfb64_encrypt(const unsigned char *in, unsigned char *out,
- long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv,
- int *num,int enc);
-void idea_ofb64_encrypt(const unsigned char *in, unsigned char *out,
- long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv, int *num);
-void idea_encrypt(unsigned long *in, IDEA_KEY_SCHEDULE *ks);
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/krb5_asn.h b/drivers/builtin_openssl/openssl/krb5_asn.h
deleted file mode 100644
index 41725d0dc4..0000000000
--- a/drivers/builtin_openssl/openssl/krb5_asn.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/* krb5_asn.h */
-/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project,
-** using ocsp/{*.h,*asn*.c} as a starting point
-*/
-
-/* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_KRB5_ASN_H
-#define HEADER_KRB5_ASN_H
-
-/*
-#include <krb5.h>
-*/
-#include <openssl/safestack.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* ASN.1 from Kerberos RFC 1510
-*/
-
-/* EncryptedData ::= SEQUENCE {
-** etype[0] INTEGER, -- EncryptionType
-** kvno[1] INTEGER OPTIONAL,
-** cipher[2] OCTET STRING -- ciphertext
-** }
-*/
-typedef struct krb5_encdata_st
- {
- ASN1_INTEGER *etype;
- ASN1_INTEGER *kvno;
- ASN1_OCTET_STRING *cipher;
- } KRB5_ENCDATA;
-
-DECLARE_STACK_OF(KRB5_ENCDATA)
-
-/* PrincipalName ::= SEQUENCE {
-** name-type[0] INTEGER,
-** name-string[1] SEQUENCE OF GeneralString
-** }
-*/
-typedef struct krb5_princname_st
- {
- ASN1_INTEGER *nametype;
- STACK_OF(ASN1_GENERALSTRING) *namestring;
- } KRB5_PRINCNAME;
-
-DECLARE_STACK_OF(KRB5_PRINCNAME)
-
-
-/* Ticket ::= [APPLICATION 1] SEQUENCE {
-** tkt-vno[0] INTEGER,
-** realm[1] Realm,
-** sname[2] PrincipalName,
-** enc-part[3] EncryptedData
-** }
-*/
-typedef struct krb5_tktbody_st
- {
- ASN1_INTEGER *tktvno;
- ASN1_GENERALSTRING *realm;
- KRB5_PRINCNAME *sname;
- KRB5_ENCDATA *encdata;
- } KRB5_TKTBODY;
-
-typedef STACK_OF(KRB5_TKTBODY) KRB5_TICKET;
-DECLARE_STACK_OF(KRB5_TKTBODY)
-
-
-/* AP-REQ ::= [APPLICATION 14] SEQUENCE {
-** pvno[0] INTEGER,
-** msg-type[1] INTEGER,
-** ap-options[2] APOptions,
-** ticket[3] Ticket,
-** authenticator[4] EncryptedData
-** }
-**
-** APOptions ::= BIT STRING {
-** reserved(0), use-session-key(1), mutual-required(2) }
-*/
-typedef struct krb5_ap_req_st
- {
- ASN1_INTEGER *pvno;
- ASN1_INTEGER *msgtype;
- ASN1_BIT_STRING *apoptions;
- KRB5_TICKET *ticket;
- KRB5_ENCDATA *authenticator;
- } KRB5_APREQBODY;
-
-typedef STACK_OF(KRB5_APREQBODY) KRB5_APREQ;
-DECLARE_STACK_OF(KRB5_APREQBODY)
-
-
-/* Authenticator Stuff */
-
-
-/* Checksum ::= SEQUENCE {
-** cksumtype[0] INTEGER,
-** checksum[1] OCTET STRING
-** }
-*/
-typedef struct krb5_checksum_st
- {
- ASN1_INTEGER *ctype;
- ASN1_OCTET_STRING *checksum;
- } KRB5_CHECKSUM;
-
-DECLARE_STACK_OF(KRB5_CHECKSUM)
-
-
-/* EncryptionKey ::= SEQUENCE {
-** keytype[0] INTEGER,
-** keyvalue[1] OCTET STRING
-** }
-*/
-typedef struct krb5_encryptionkey_st
- {
- ASN1_INTEGER *ktype;
- ASN1_OCTET_STRING *keyvalue;
- } KRB5_ENCKEY;
-
-DECLARE_STACK_OF(KRB5_ENCKEY)
-
-
-/* AuthorizationData ::= SEQUENCE OF SEQUENCE {
-** ad-type[0] INTEGER,
-** ad-data[1] OCTET STRING
-** }
-*/
-typedef struct krb5_authorization_st
- {
- ASN1_INTEGER *adtype;
- ASN1_OCTET_STRING *addata;
- } KRB5_AUTHDATA;
-
-DECLARE_STACK_OF(KRB5_AUTHDATA)
-
-
-/* -- Unencrypted authenticator
-** Authenticator ::= [APPLICATION 2] SEQUENCE {
-** authenticator-vno[0] INTEGER,
-** crealm[1] Realm,
-** cname[2] PrincipalName,
-** cksum[3] Checksum OPTIONAL,
-** cusec[4] INTEGER,
-** ctime[5] KerberosTime,
-** subkey[6] EncryptionKey OPTIONAL,
-** seq-number[7] INTEGER OPTIONAL,
-** authorization-data[8] AuthorizationData OPTIONAL
-** }
-*/
-typedef struct krb5_authenticator_st
- {
- ASN1_INTEGER *avno;
- ASN1_GENERALSTRING *crealm;
- KRB5_PRINCNAME *cname;
- KRB5_CHECKSUM *cksum;
- ASN1_INTEGER *cusec;
- ASN1_GENERALIZEDTIME *ctime;
- KRB5_ENCKEY *subkey;
- ASN1_INTEGER *seqnum;
- KRB5_AUTHDATA *authorization;
- } KRB5_AUTHENTBODY;
-
-typedef STACK_OF(KRB5_AUTHENTBODY) KRB5_AUTHENT;
-DECLARE_STACK_OF(KRB5_AUTHENTBODY)
-
-
-/* DECLARE_ASN1_FUNCTIONS(type) = DECLARE_ASN1_FUNCTIONS_name(type, type) =
-** type *name##_new(void);
-** void name##_free(type *a);
-** DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) =
-** DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) =
-** type *d2i_##name(type **a, const unsigned char **in, long len);
-** int i2d_##name(type *a, unsigned char **out);
-** DECLARE_ASN1_ITEM(itname) = OPENSSL_EXTERN const ASN1_ITEM itname##_it
-*/
-
-DECLARE_ASN1_FUNCTIONS(KRB5_ENCDATA)
-DECLARE_ASN1_FUNCTIONS(KRB5_PRINCNAME)
-DECLARE_ASN1_FUNCTIONS(KRB5_TKTBODY)
-DECLARE_ASN1_FUNCTIONS(KRB5_APREQBODY)
-DECLARE_ASN1_FUNCTIONS(KRB5_TICKET)
-DECLARE_ASN1_FUNCTIONS(KRB5_APREQ)
-
-DECLARE_ASN1_FUNCTIONS(KRB5_CHECKSUM)
-DECLARE_ASN1_FUNCTIONS(KRB5_ENCKEY)
-DECLARE_ASN1_FUNCTIONS(KRB5_AUTHDATA)
-DECLARE_ASN1_FUNCTIONS(KRB5_AUTHENTBODY)
-DECLARE_ASN1_FUNCTIONS(KRB5_AUTHENT)
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/openssl/lhash.h b/drivers/builtin_openssl/openssl/lhash.h
deleted file mode 100644
index e7d8763591..0000000000
--- a/drivers/builtin_openssl/openssl/lhash.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/* crypto/lhash/lhash.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-/* Header for dynamic hash table routines
- * Author - Eric Young
- */
-
-#ifndef HEADER_LHASH_H
-#define HEADER_LHASH_H
-
-#include <openssl/e_os2.h>
-#ifndef OPENSSL_NO_FP_API
-#include <stdio.h>
-#endif
-
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct lhash_node_st
- {
- void *data;
- struct lhash_node_st *next;
-#ifndef OPENSSL_NO_HASH_COMP
- unsigned long hash;
-#endif
- } LHASH_NODE;
-
-typedef int (*LHASH_COMP_FN_TYPE)(const void *, const void *);
-typedef unsigned long (*LHASH_HASH_FN_TYPE)(const void *);
-typedef void (*LHASH_DOALL_FN_TYPE)(void *);
-typedef void (*LHASH_DOALL_ARG_FN_TYPE)(void *, void *);
-
-/* Macros for declaring and implementing type-safe wrappers for LHASH callbacks.
- * This way, callbacks can be provided to LHASH structures without function
- * pointer casting and the macro-defined callbacks provide per-variable casting
- * before deferring to the underlying type-specific callbacks. NB: It is
- * possible to place a "static" in front of both the DECLARE and IMPLEMENT
- * macros if the functions are strictly internal. */
-
-/* First: "hash" functions */
-#define DECLARE_LHASH_HASH_FN(name, o_type) \
- unsigned long name##_LHASH_HASH(const void *);
-#define IMPLEMENT_LHASH_HASH_FN(name, o_type) \
- unsigned long name##_LHASH_HASH(const void *arg) { \
- const o_type *a = arg; \
- return name##_hash(a); }
-#define LHASH_HASH_FN(name) name##_LHASH_HASH
-
-/* Second: "compare" functions */
-#define DECLARE_LHASH_COMP_FN(name, o_type) \
- int name##_LHASH_COMP(const void *, const void *);
-#define IMPLEMENT_LHASH_COMP_FN(name, o_type) \
- int name##_LHASH_COMP(const void *arg1, const void *arg2) { \
- const o_type *a = arg1; \
- const o_type *b = arg2; \
- return name##_cmp(a,b); }
-#define LHASH_COMP_FN(name) name##_LHASH_COMP
-
-/* Third: "doall" functions */
-#define DECLARE_LHASH_DOALL_FN(name, o_type) \
- void name##_LHASH_DOALL(void *);
-#define IMPLEMENT_LHASH_DOALL_FN(name, o_type) \
- void name##_LHASH_DOALL(void *arg) { \
- o_type *a = arg; \
- name##_doall(a); }
-#define LHASH_DOALL_FN(name) name##_LHASH_DOALL
-
-/* Fourth: "doall_arg" functions */
-#define DECLARE_LHASH_DOALL_ARG_FN(name, o_type, a_type) \
- void name##_LHASH_DOALL_ARG(void *, void *);
-#define IMPLEMENT_LHASH_DOALL_ARG_FN(name, o_type, a_type) \
- void name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \
- o_type *a = arg1; \
- a_type *b = arg2; \
- name##_doall_arg(a, b); }
-#define LHASH_DOALL_ARG_FN(name) name##_LHASH_DOALL_ARG
-
-typedef struct lhash_st
- {
- LHASH_NODE **b;
- LHASH_COMP_FN_TYPE comp;
- LHASH_HASH_FN_TYPE hash;
- unsigned int num_nodes;
- unsigned int num_alloc_nodes;
- unsigned int p;
- unsigned int pmax;
- unsigned long up_load; /* load times 256 */
- unsigned long down_load; /* load times 256 */
- unsigned long num_items;
-
- unsigned long num_expands;
- unsigned long num_expand_reallocs;
- unsigned long num_contracts;
- unsigned long num_contract_reallocs;
- unsigned long num_hash_calls;
- unsigned long num_comp_calls;
- unsigned long num_insert;
- unsigned long num_replace;
- unsigned long num_delete;
- unsigned long num_no_delete;
- unsigned long num_retrieve;
- unsigned long num_retrieve_miss;
- unsigned long num_hash_comps;
-
- int error;
- } _LHASH; /* Do not use _LHASH directly, use LHASH_OF
- * and friends */
-
-#define LH_LOAD_MULT 256
-
-/* Indicates a malloc() error in the last call, this is only bad
- * in lh_insert(). */
-#define lh_error(lh) ((lh)->error)
-
-_LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c);
-void lh_free(_LHASH *lh);
-void *lh_insert(_LHASH *lh, void *data);
-void *lh_delete(_LHASH *lh, const void *data);
-void *lh_retrieve(_LHASH *lh, const void *data);
-void lh_doall(_LHASH *lh, LHASH_DOALL_FN_TYPE func);
-void lh_doall_arg(_LHASH *lh, LHASH_DOALL_ARG_FN_TYPE func, void *arg);
-unsigned long lh_strhash(const char *c);
-unsigned long lh_num_items(const _LHASH *lh);
-
-#ifndef OPENSSL_NO_FP_API
-void lh_stats(const _LHASH *lh, FILE *out);
-void lh_node_stats(const _LHASH *lh, FILE *out);
-void lh_node_usage_stats(const _LHASH *lh, FILE *out);
-#endif
-
-#ifndef OPENSSL_NO_BIO
-void lh_stats_bio(const _LHASH *lh, BIO *out);
-void lh_node_stats_bio(const _LHASH *lh, BIO *out);
-void lh_node_usage_stats_bio(const _LHASH *lh, BIO *out);
-#endif
-
-/* Type checking... */
-
-#define LHASH_OF(type) struct lhash_st_##type
-
-#define DECLARE_LHASH_OF(type) LHASH_OF(type) { int dummy; }
-
-#define CHECKED_LHASH_OF(type,lh) \
- ((_LHASH *)CHECKED_PTR_OF(LHASH_OF(type),lh))
-
-/* Define wrapper functions. */
-#define LHM_lh_new(type, name) \
- ((LHASH_OF(type) *)lh_new(LHASH_HASH_FN(name), LHASH_COMP_FN(name)))
-#define LHM_lh_error(type, lh) \
- lh_error(CHECKED_LHASH_OF(type,lh))
-#define LHM_lh_insert(type, lh, inst) \
- ((type *)lh_insert(CHECKED_LHASH_OF(type, lh), \
- CHECKED_PTR_OF(type, inst)))
-#define LHM_lh_retrieve(type, lh, inst) \
- ((type *)lh_retrieve(CHECKED_LHASH_OF(type, lh), \
- CHECKED_PTR_OF(type, inst)))
-#define LHM_lh_delete(type, lh, inst) \
- ((type *)lh_delete(CHECKED_LHASH_OF(type, lh), \
- CHECKED_PTR_OF(type, inst)))
-#define LHM_lh_doall(type, lh,fn) lh_doall(CHECKED_LHASH_OF(type, lh), fn)
-#define LHM_lh_doall_arg(type, lh, fn, arg_type, arg) \
- lh_doall_arg(CHECKED_LHASH_OF(type, lh), fn, CHECKED_PTR_OF(arg_type, arg))
-#define LHM_lh_num_items(type, lh) lh_num_items(CHECKED_LHASH_OF(type, lh))
-#define LHM_lh_down_load(type, lh) (CHECKED_LHASH_OF(type, lh)->down_load)
-#define LHM_lh_node_stats_bio(type, lh, out) \
- lh_node_stats_bio(CHECKED_LHASH_OF(type, lh), out)
-#define LHM_lh_node_usage_stats_bio(type, lh, out) \
- lh_node_usage_stats_bio(CHECKED_LHASH_OF(type, lh), out)
-#define LHM_lh_stats_bio(type, lh, out) \
- lh_stats_bio(CHECKED_LHASH_OF(type, lh), out)
-#define LHM_lh_free(type, lh) lh_free(CHECKED_LHASH_OF(type, lh))
-
-DECLARE_LHASH_OF(OPENSSL_STRING);
-DECLARE_LHASH_OF(OPENSSL_CSTRING);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/drivers/builtin_openssl/openssl/md4.h b/drivers/builtin_openssl/openssl/md4.h
deleted file mode 100644
index a55368a790..0000000000
--- a/drivers/builtin_openssl/openssl/md4.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* crypto/md4/md4.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_MD4_H
-#define HEADER_MD4_H
-
-#include <openssl/e_os2.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_NO_MD4
-#error MD4 is disabled.
-#endif
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * ! MD4_LONG has to be at least 32 bits wide. If it's wider, then !
- * ! MD4_LONG_LOG2 has to be defined along. !
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- */
-
-#if defined(__LP32__)
-#define MD4_LONG unsigned long
-#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
-#define MD4_LONG unsigned long
-#define MD4_LONG_LOG2 3
-/*
- * _CRAY note. I could declare short, but I have no idea what impact
- * does it have on performance on none-T3E machines. I could declare
- * int, but at least on C90 sizeof(int) can be chosen at compile time.
- * So I've chosen long...
- * <appro@fy.chalmers.se>
- */
-#else
-#define MD4_LONG unsigned int
-#endif
-
-#define MD4_CBLOCK 64
-#define MD4_LBLOCK (MD4_CBLOCK/4)
-#define MD4_DIGEST_LENGTH 16
-
-typedef struct MD4state_st
- {
- MD4_LONG A,B,C,D;
- MD4_LONG Nl,Nh;
- MD4_LONG data[MD4_LBLOCK];
- unsigned int num;
- } MD4_CTX;
-
-#ifdef OPENSSL_FIPS
-int private_MD4_Init(MD4_CTX *c);
-#endif
-int MD4_Init(MD4_CTX *c);
-int MD4_Update(MD4_CTX *c, const void *data, size_t len);
-int MD4_Final(unsigned char *md, MD4_CTX *c);
-unsigned char *MD4(const unsigned char *d, size_t n, unsigned char *md);
-void MD4_Transform(MD4_CTX *c, const unsigned char *b);
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/md5.h b/drivers/builtin_openssl/openssl/md5.h
deleted file mode 100644
index 8f392f0ec6..0000000000
--- a/drivers/builtin_openssl/openssl/md5.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* crypto/md5/md5.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_MD5_H
-#define HEADER_MD5_H
-
-#include <openssl/e_os2.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_NO_MD5
-#error MD5 is disabled.
-#endif
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * ! MD5_LONG has to be at least 32 bits wide. If it's wider, then !
- * ! MD5_LONG_LOG2 has to be defined along. !
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- */
-
-#if defined(__LP32__)
-#define MD5_LONG unsigned long
-#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
-#define MD5_LONG unsigned long
-#define MD5_LONG_LOG2 3
-/*
- * _CRAY note. I could declare short, but I have no idea what impact
- * does it have on performance on none-T3E machines. I could declare
- * int, but at least on C90 sizeof(int) can be chosen at compile time.
- * So I've chosen long...
- * <appro@fy.chalmers.se>
- */
-#else
-#define MD5_LONG unsigned int
-#endif
-
-#define MD5_CBLOCK 64
-#define MD5_LBLOCK (MD5_CBLOCK/4)
-#define MD5_DIGEST_LENGTH 16
-
-typedef struct MD5state_st
- {
- MD5_LONG A,B,C,D;
- MD5_LONG Nl,Nh;
- MD5_LONG data[MD5_LBLOCK];
- unsigned int num;
- } MD5_CTX;
-
-#ifdef OPENSSL_FIPS
-int private_MD5_Init(MD5_CTX *c);
-#endif
-
-//#define MD5_Init _SSL_MD5_Init
-#define MD5_Final _SSL_MD5_Final
-#define MD5_Update _SSL_MD5_Update
-#define MD5_Transform _SSL_MD5_Transform
-#define MD5_Init private_MD5_Init
-
-int _SSL_MD5_Init(MD5_CTX *c);
-int _SSL_MD5_Update(MD5_CTX *c, const void *data, size_t len);
-int _SSL_MD5_Final(unsigned char *md, MD5_CTX *c);
-unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);
-void _SSL_MD5_Transform(MD5_CTX *c, const unsigned char *b);
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/mdc2.h b/drivers/builtin_openssl/openssl/mdc2.h
deleted file mode 100644
index f3e8e579d2..0000000000
--- a/drivers/builtin_openssl/openssl/mdc2.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* crypto/mdc2/mdc2.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_MDC2_H
-#define HEADER_MDC2_H
-
-#include <openssl/des.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_NO_MDC2
-#error MDC2 is disabled.
-#endif
-
-#define MDC2_BLOCK 8
-#define MDC2_DIGEST_LENGTH 16
-
-typedef struct mdc2_ctx_st
- {
- unsigned int num;
- unsigned char data[MDC2_BLOCK];
- DES_cblock h,hh;
- int pad_type; /* either 1 or 2, default 1 */
- } MDC2_CTX;
-
-
-#ifdef OPENSSL_FIPS
-int private_MDC2_Init(MDC2_CTX *c);
-#endif
-int MDC2_Init(MDC2_CTX *c);
-int MDC2_Update(MDC2_CTX *c, const unsigned char *data, size_t len);
-int MDC2_Final(unsigned char *md, MDC2_CTX *c);
-unsigned char *MDC2(const unsigned char *d, size_t n,
- unsigned char *md);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/drivers/builtin_openssl/openssl/modes.h b/drivers/builtin_openssl/openssl/modes.h
deleted file mode 100644
index f18215bb2b..0000000000
--- a/drivers/builtin_openssl/openssl/modes.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* ====================================================================
- * Copyright (c) 2008 The OpenSSL Project. All rights reserved.
- *
- * Rights for redistribution and usage in source and binary
- * forms are granted according to the OpenSSL license.
- */
-
-#include <stddef.h>
-
-typedef void (*block128_f)(const unsigned char in[16],
- unsigned char out[16],
- const void *key);
-
-typedef void (*cbc128_f)(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], int enc);
-
-typedef void (*ctr128_f)(const unsigned char *in, unsigned char *out,
- size_t blocks, const void *key,
- const unsigned char ivec[16]);
-
-typedef void (*ccm128_f)(const unsigned char *in, unsigned char *out,
- size_t blocks, const void *key,
- const unsigned char ivec[16],unsigned char cmac[16]);
-
-void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], block128_f block);
-void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], block128_f block);
-
-void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], unsigned char ecount_buf[16],
- unsigned int *num, block128_f block);
-
-void CRYPTO_ctr128_encrypt_ctr32(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], unsigned char ecount_buf[16],
- unsigned int *num, ctr128_f ctr);
-
-void CRYPTO_ofb128_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], int *num,
- block128_f block);
-
-void CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], int *num,
- int enc, block128_f block);
-void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
- size_t length, const void *key,
- unsigned char ivec[16], int *num,
- int enc, block128_f block);
-void CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out,
- size_t bits, const void *key,
- unsigned char ivec[16], int *num,
- int enc, block128_f block);
-
-size_t CRYPTO_cts128_encrypt_block(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], block128_f block);
-size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], cbc128_f cbc);
-size_t CRYPTO_cts128_decrypt_block(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], block128_f block);
-size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], cbc128_f cbc);
-
-size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], block128_f block);
-size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], cbc128_f cbc);
-size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], block128_f block);
-size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
- size_t len, const void *key,
- unsigned char ivec[16], cbc128_f cbc);
-
-typedef struct gcm128_context GCM128_CONTEXT;
-
-GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block);
-void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx,void *key,block128_f block);
-void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const unsigned char *iv,
- size_t len);
-int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const unsigned char *aad,
- size_t len);
-int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx,
- const unsigned char *in, unsigned char *out,
- size_t len);
-int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx,
- const unsigned char *in, unsigned char *out,
- size_t len);
-int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx,
- const unsigned char *in, unsigned char *out,
- size_t len, ctr128_f stream);
-int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx,
- const unsigned char *in, unsigned char *out,
- size_t len, ctr128_f stream);
-int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx,const unsigned char *tag,
- size_t len);
-void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len);
-void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx);
-
-typedef struct ccm128_context CCM128_CONTEXT;
-
-void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
- unsigned int M, unsigned int L, void *key,block128_f block);
-int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx,
- const unsigned char *nonce, size_t nlen, size_t mlen);
-void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx,
- const unsigned char *aad, size_t alen);
-int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx,
- const unsigned char *inp, unsigned char *out, size_t len);
-int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx,
- const unsigned char *inp, unsigned char *out, size_t len);
-int CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx,
- const unsigned char *inp, unsigned char *out, size_t len,
- ccm128_f stream);
-int CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx,
- const unsigned char *inp, unsigned char *out, size_t len,
- ccm128_f stream);
-size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len);
-
-typedef struct xts128_context XTS128_CONTEXT;
-
-int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx, const unsigned char iv[16],
- const unsigned char *inp, unsigned char *out, size_t len, int enc);
diff --git a/drivers/builtin_openssl/openssl/obj_mac.h b/drivers/builtin_openssl/openssl/obj_mac.h
deleted file mode 100644
index b5ea7cdab4..0000000000
--- a/drivers/builtin_openssl/openssl/obj_mac.h
+++ /dev/null
@@ -1,4032 +0,0 @@
-/* crypto/objects/obj_mac.h */
-
-/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the
- * following command:
- * perl objects.pl objects.txt obj_mac.num obj_mac.h
- */
-
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#define SN_undef "UNDEF"
-#define LN_undef "undefined"
-#define NID_undef 0
-#define OBJ_undef 0L
-
-#define SN_itu_t "ITU-T"
-#define LN_itu_t "itu-t"
-#define NID_itu_t 645
-#define OBJ_itu_t 0L
-
-#define NID_ccitt 404
-#define OBJ_ccitt OBJ_itu_t
-
-#define SN_iso "ISO"
-#define LN_iso "iso"
-#define NID_iso 181
-#define OBJ_iso 1L
-
-#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T"
-#define LN_joint_iso_itu_t "joint-iso-itu-t"
-#define NID_joint_iso_itu_t 646
-#define OBJ_joint_iso_itu_t 2L
-
-#define NID_joint_iso_ccitt 393
-#define OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t
-
-#define SN_member_body "member-body"
-#define LN_member_body "ISO Member Body"
-#define NID_member_body 182
-#define OBJ_member_body OBJ_iso,2L
-
-#define SN_identified_organization "identified-organization"
-#define NID_identified_organization 676
-#define OBJ_identified_organization OBJ_iso,3L
-
-#define SN_hmac_md5 "HMAC-MD5"
-#define LN_hmac_md5 "hmac-md5"
-#define NID_hmac_md5 780
-#define OBJ_hmac_md5 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,1L
-
-#define SN_hmac_sha1 "HMAC-SHA1"
-#define LN_hmac_sha1 "hmac-sha1"
-#define NID_hmac_sha1 781
-#define OBJ_hmac_sha1 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,2L
-
-#define SN_certicom_arc "certicom-arc"
-#define NID_certicom_arc 677
-#define OBJ_certicom_arc OBJ_identified_organization,132L
-
-#define SN_international_organizations "international-organizations"
-#define LN_international_organizations "International Organizations"
-#define NID_international_organizations 647
-#define OBJ_international_organizations OBJ_joint_iso_itu_t,23L
-
-#define SN_wap "wap"
-#define NID_wap 678
-#define OBJ_wap OBJ_international_organizations,43L
-
-#define SN_wap_wsg "wap-wsg"
-#define NID_wap_wsg 679
-#define OBJ_wap_wsg OBJ_wap,1L
-
-#define SN_selected_attribute_types "selected-attribute-types"
-#define LN_selected_attribute_types "Selected Attribute Types"
-#define NID_selected_attribute_types 394
-#define OBJ_selected_attribute_types OBJ_joint_iso_itu_t,5L,1L,5L
-
-#define SN_clearance "clearance"
-#define NID_clearance 395
-#define OBJ_clearance OBJ_selected_attribute_types,55L
-
-#define SN_ISO_US "ISO-US"
-#define LN_ISO_US "ISO US Member Body"
-#define NID_ISO_US 183
-#define OBJ_ISO_US OBJ_member_body,840L
-
-#define SN_X9_57 "X9-57"
-#define LN_X9_57 "X9.57"
-#define NID_X9_57 184
-#define OBJ_X9_57 OBJ_ISO_US,10040L
-
-#define SN_X9cm "X9cm"
-#define LN_X9cm "X9.57 CM ?"
-#define NID_X9cm 185
-#define OBJ_X9cm OBJ_X9_57,4L
-
-#define SN_dsa "DSA"
-#define LN_dsa "dsaEncryption"
-#define NID_dsa 116
-#define OBJ_dsa OBJ_X9cm,1L
-
-#define SN_dsaWithSHA1 "DSA-SHA1"
-#define LN_dsaWithSHA1 "dsaWithSHA1"
-#define NID_dsaWithSHA1 113
-#define OBJ_dsaWithSHA1 OBJ_X9cm,3L
-
-#define SN_ansi_X9_62 "ansi-X9-62"
-#define LN_ansi_X9_62 "ANSI X9.62"
-#define NID_ansi_X9_62 405
-#define OBJ_ansi_X9_62 OBJ_ISO_US,10045L
-
-#define OBJ_X9_62_id_fieldType OBJ_ansi_X9_62,1L
-
-#define SN_X9_62_prime_field "prime-field"
-#define NID_X9_62_prime_field 406
-#define OBJ_X9_62_prime_field OBJ_X9_62_id_fieldType,1L
-
-#define SN_X9_62_characteristic_two_field "characteristic-two-field"
-#define NID_X9_62_characteristic_two_field 407
-#define OBJ_X9_62_characteristic_two_field OBJ_X9_62_id_fieldType,2L
-
-#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis"
-#define NID_X9_62_id_characteristic_two_basis 680
-#define OBJ_X9_62_id_characteristic_two_basis OBJ_X9_62_characteristic_two_field,3L
-
-#define SN_X9_62_onBasis "onBasis"
-#define NID_X9_62_onBasis 681
-#define OBJ_X9_62_onBasis OBJ_X9_62_id_characteristic_two_basis,1L
-
-#define SN_X9_62_tpBasis "tpBasis"
-#define NID_X9_62_tpBasis 682
-#define OBJ_X9_62_tpBasis OBJ_X9_62_id_characteristic_two_basis,2L
-
-#define SN_X9_62_ppBasis "ppBasis"
-#define NID_X9_62_ppBasis 683
-#define OBJ_X9_62_ppBasis OBJ_X9_62_id_characteristic_two_basis,3L
-
-#define OBJ_X9_62_id_publicKeyType OBJ_ansi_X9_62,2L
-
-#define SN_X9_62_id_ecPublicKey "id-ecPublicKey"
-#define NID_X9_62_id_ecPublicKey 408
-#define OBJ_X9_62_id_ecPublicKey OBJ_X9_62_id_publicKeyType,1L
-
-#define OBJ_X9_62_ellipticCurve OBJ_ansi_X9_62,3L
-
-#define OBJ_X9_62_c_TwoCurve OBJ_X9_62_ellipticCurve,0L
-
-#define SN_X9_62_c2pnb163v1 "c2pnb163v1"
-#define NID_X9_62_c2pnb163v1 684
-#define OBJ_X9_62_c2pnb163v1 OBJ_X9_62_c_TwoCurve,1L
-
-#define SN_X9_62_c2pnb163v2 "c2pnb163v2"
-#define NID_X9_62_c2pnb163v2 685
-#define OBJ_X9_62_c2pnb163v2 OBJ_X9_62_c_TwoCurve,2L
-
-#define SN_X9_62_c2pnb163v3 "c2pnb163v3"
-#define NID_X9_62_c2pnb163v3 686
-#define OBJ_X9_62_c2pnb163v3 OBJ_X9_62_c_TwoCurve,3L
-
-#define SN_X9_62_c2pnb176v1 "c2pnb176v1"
-#define NID_X9_62_c2pnb176v1 687
-#define OBJ_X9_62_c2pnb176v1 OBJ_X9_62_c_TwoCurve,4L
-
-#define SN_X9_62_c2tnb191v1 "c2tnb191v1"
-#define NID_X9_62_c2tnb191v1 688
-#define OBJ_X9_62_c2tnb191v1 OBJ_X9_62_c_TwoCurve,5L
-
-#define SN_X9_62_c2tnb191v2 "c2tnb191v2"
-#define NID_X9_62_c2tnb191v2 689
-#define OBJ_X9_62_c2tnb191v2 OBJ_X9_62_c_TwoCurve,6L
-
-#define SN_X9_62_c2tnb191v3 "c2tnb191v3"
-#define NID_X9_62_c2tnb191v3 690
-#define OBJ_X9_62_c2tnb191v3 OBJ_X9_62_c_TwoCurve,7L
-
-#define SN_X9_62_c2onb191v4 "c2onb191v4"
-#define NID_X9_62_c2onb191v4 691
-#define OBJ_X9_62_c2onb191v4 OBJ_X9_62_c_TwoCurve,8L
-
-#define SN_X9_62_c2onb191v5 "c2onb191v5"
-#define NID_X9_62_c2onb191v5 692
-#define OBJ_X9_62_c2onb191v5 OBJ_X9_62_c_TwoCurve,9L
-
-#define SN_X9_62_c2pnb208w1 "c2pnb208w1"
-#define NID_X9_62_c2pnb208w1 693
-#define OBJ_X9_62_c2pnb208w1 OBJ_X9_62_c_TwoCurve,10L
-
-#define SN_X9_62_c2tnb239v1 "c2tnb239v1"
-#define NID_X9_62_c2tnb239v1 694
-#define OBJ_X9_62_c2tnb239v1 OBJ_X9_62_c_TwoCurve,11L
-
-#define SN_X9_62_c2tnb239v2 "c2tnb239v2"
-#define NID_X9_62_c2tnb239v2 695
-#define OBJ_X9_62_c2tnb239v2 OBJ_X9_62_c_TwoCurve,12L
-
-#define SN_X9_62_c2tnb239v3 "c2tnb239v3"
-#define NID_X9_62_c2tnb239v3 696
-#define OBJ_X9_62_c2tnb239v3 OBJ_X9_62_c_TwoCurve,13L
-
-#define SN_X9_62_c2onb239v4 "c2onb239v4"
-#define NID_X9_62_c2onb239v4 697
-#define OBJ_X9_62_c2onb239v4 OBJ_X9_62_c_TwoCurve,14L
-
-#define SN_X9_62_c2onb239v5 "c2onb239v5"
-#define NID_X9_62_c2onb239v5 698
-#define OBJ_X9_62_c2onb239v5 OBJ_X9_62_c_TwoCurve,15L
-
-#define SN_X9_62_c2pnb272w1 "c2pnb272w1"
-#define NID_X9_62_c2pnb272w1 699
-#define OBJ_X9_62_c2pnb272w1 OBJ_X9_62_c_TwoCurve,16L
-
-#define SN_X9_62_c2pnb304w1 "c2pnb304w1"
-#define NID_X9_62_c2pnb304w1 700
-#define OBJ_X9_62_c2pnb304w1 OBJ_X9_62_c_TwoCurve,17L
-
-#define SN_X9_62_c2tnb359v1 "c2tnb359v1"
-#define NID_X9_62_c2tnb359v1 701
-#define OBJ_X9_62_c2tnb359v1 OBJ_X9_62_c_TwoCurve,18L
-
-#define SN_X9_62_c2pnb368w1 "c2pnb368w1"
-#define NID_X9_62_c2pnb368w1 702
-#define OBJ_X9_62_c2pnb368w1 OBJ_X9_62_c_TwoCurve,19L
-
-#define SN_X9_62_c2tnb431r1 "c2tnb431r1"
-#define NID_X9_62_c2tnb431r1 703
-#define OBJ_X9_62_c2tnb431r1 OBJ_X9_62_c_TwoCurve,20L
-
-#define OBJ_X9_62_primeCurve OBJ_X9_62_ellipticCurve,1L
-
-#define SN_X9_62_prime192v1 "prime192v1"
-#define NID_X9_62_prime192v1 409
-#define OBJ_X9_62_prime192v1 OBJ_X9_62_primeCurve,1L
-
-#define SN_X9_62_prime192v2 "prime192v2"
-#define NID_X9_62_prime192v2 410
-#define OBJ_X9_62_prime192v2 OBJ_X9_62_primeCurve,2L
-
-#define SN_X9_62_prime192v3 "prime192v3"
-#define NID_X9_62_prime192v3 411
-#define OBJ_X9_62_prime192v3 OBJ_X9_62_primeCurve,3L
-
-#define SN_X9_62_prime239v1 "prime239v1"
-#define NID_X9_62_prime239v1 412
-#define OBJ_X9_62_prime239v1 OBJ_X9_62_primeCurve,4L
-
-#define SN_X9_62_prime239v2 "prime239v2"
-#define NID_X9_62_prime239v2 413
-#define OBJ_X9_62_prime239v2 OBJ_X9_62_primeCurve,5L
-
-#define SN_X9_62_prime239v3 "prime239v3"
-#define NID_X9_62_prime239v3 414
-#define OBJ_X9_62_prime239v3 OBJ_X9_62_primeCurve,6L
-
-#define SN_X9_62_prime256v1 "prime256v1"
-#define NID_X9_62_prime256v1 415
-#define OBJ_X9_62_prime256v1 OBJ_X9_62_primeCurve,7L
-
-#define OBJ_X9_62_id_ecSigType OBJ_ansi_X9_62,4L
-
-#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1"
-#define NID_ecdsa_with_SHA1 416
-#define OBJ_ecdsa_with_SHA1 OBJ_X9_62_id_ecSigType,1L
-
-#define SN_ecdsa_with_Recommended "ecdsa-with-Recommended"
-#define NID_ecdsa_with_Recommended 791
-#define OBJ_ecdsa_with_Recommended OBJ_X9_62_id_ecSigType,2L
-
-#define SN_ecdsa_with_Specified "ecdsa-with-Specified"
-#define NID_ecdsa_with_Specified 792
-#define OBJ_ecdsa_with_Specified OBJ_X9_62_id_ecSigType,3L
-
-#define SN_ecdsa_with_SHA224 "ecdsa-with-SHA224"
-#define NID_ecdsa_with_SHA224 793
-#define OBJ_ecdsa_with_SHA224 OBJ_ecdsa_with_Specified,1L
-
-#define SN_ecdsa_with_SHA256 "ecdsa-with-SHA256"
-#define NID_ecdsa_with_SHA256 794
-#define OBJ_ecdsa_with_SHA256 OBJ_ecdsa_with_Specified,2L
-
-#define SN_ecdsa_with_SHA384 "ecdsa-with-SHA384"
-#define NID_ecdsa_with_SHA384 795
-#define OBJ_ecdsa_with_SHA384 OBJ_ecdsa_with_Specified,3L
-
-#define SN_ecdsa_with_SHA512 "ecdsa-with-SHA512"
-#define NID_ecdsa_with_SHA512 796
-#define OBJ_ecdsa_with_SHA512 OBJ_ecdsa_with_Specified,4L
-
-#define OBJ_secg_ellipticCurve OBJ_certicom_arc,0L
-
-#define SN_secp112r1 "secp112r1"
-#define NID_secp112r1 704
-#define OBJ_secp112r1 OBJ_secg_ellipticCurve,6L
-
-#define SN_secp112r2 "secp112r2"
-#define NID_secp112r2 705
-#define OBJ_secp112r2 OBJ_secg_ellipticCurve,7L
-
-#define SN_secp128r1 "secp128r1"
-#define NID_secp128r1 706
-#define OBJ_secp128r1 OBJ_secg_ellipticCurve,28L
-
-#define SN_secp128r2 "secp128r2"
-#define NID_secp128r2 707
-#define OBJ_secp128r2 OBJ_secg_ellipticCurve,29L
-
-#define SN_secp160k1 "secp160k1"
-#define NID_secp160k1 708
-#define OBJ_secp160k1 OBJ_secg_ellipticCurve,9L
-
-#define SN_secp160r1 "secp160r1"
-#define NID_secp160r1 709
-#define OBJ_secp160r1 OBJ_secg_ellipticCurve,8L
-
-#define SN_secp160r2 "secp160r2"
-#define NID_secp160r2 710
-#define OBJ_secp160r2 OBJ_secg_ellipticCurve,30L
-
-#define SN_secp192k1 "secp192k1"
-#define NID_secp192k1 711
-#define OBJ_secp192k1 OBJ_secg_ellipticCurve,31L
-
-#define SN_secp224k1 "secp224k1"
-#define NID_secp224k1 712
-#define OBJ_secp224k1 OBJ_secg_ellipticCurve,32L
-
-#define SN_secp224r1 "secp224r1"
-#define NID_secp224r1 713
-#define OBJ_secp224r1 OBJ_secg_ellipticCurve,33L
-
-#define SN_secp256k1 "secp256k1"
-#define NID_secp256k1 714
-#define OBJ_secp256k1 OBJ_secg_ellipticCurve,10L
-
-#define SN_secp384r1 "secp384r1"
-#define NID_secp384r1 715
-#define OBJ_secp384r1 OBJ_secg_ellipticCurve,34L
-
-#define SN_secp521r1 "secp521r1"
-#define NID_secp521r1 716
-#define OBJ_secp521r1 OBJ_secg_ellipticCurve,35L
-
-#define SN_sect113r1 "sect113r1"
-#define NID_sect113r1 717
-#define OBJ_sect113r1 OBJ_secg_ellipticCurve,4L
-
-#define SN_sect113r2 "sect113r2"
-#define NID_sect113r2 718
-#define OBJ_sect113r2 OBJ_secg_ellipticCurve,5L
-
-#define SN_sect131r1 "sect131r1"
-#define NID_sect131r1 719
-#define OBJ_sect131r1 OBJ_secg_ellipticCurve,22L
-
-#define SN_sect131r2 "sect131r2"
-#define NID_sect131r2 720
-#define OBJ_sect131r2 OBJ_secg_ellipticCurve,23L
-
-#define SN_sect163k1 "sect163k1"
-#define NID_sect163k1 721
-#define OBJ_sect163k1 OBJ_secg_ellipticCurve,1L
-
-#define SN_sect163r1 "sect163r1"
-#define NID_sect163r1 722
-#define OBJ_sect163r1 OBJ_secg_ellipticCurve,2L
-
-#define SN_sect163r2 "sect163r2"
-#define NID_sect163r2 723
-#define OBJ_sect163r2 OBJ_secg_ellipticCurve,15L
-
-#define SN_sect193r1 "sect193r1"
-#define NID_sect193r1 724
-#define OBJ_sect193r1 OBJ_secg_ellipticCurve,24L
-
-#define SN_sect193r2 "sect193r2"
-#define NID_sect193r2 725
-#define OBJ_sect193r2 OBJ_secg_ellipticCurve,25L
-
-#define SN_sect233k1 "sect233k1"
-#define NID_sect233k1 726
-#define OBJ_sect233k1 OBJ_secg_ellipticCurve,26L
-
-#define SN_sect233r1 "sect233r1"
-#define NID_sect233r1 727
-#define OBJ_sect233r1 OBJ_secg_ellipticCurve,27L
-
-#define SN_sect239k1 "sect239k1"
-#define NID_sect239k1 728
-#define OBJ_sect239k1 OBJ_secg_ellipticCurve,3L
-
-#define SN_sect283k1 "sect283k1"
-#define NID_sect283k1 729
-#define OBJ_sect283k1 OBJ_secg_ellipticCurve,16L
-
-#define SN_sect283r1 "sect283r1"
-#define NID_sect283r1 730
-#define OBJ_sect283r1 OBJ_secg_ellipticCurve,17L
-
-#define SN_sect409k1 "sect409k1"
-#define NID_sect409k1 731
-#define OBJ_sect409k1 OBJ_secg_ellipticCurve,36L
-
-#define SN_sect409r1 "sect409r1"
-#define NID_sect409r1 732
-#define OBJ_sect409r1 OBJ_secg_ellipticCurve,37L
-
-#define SN_sect571k1 "sect571k1"
-#define NID_sect571k1 733
-#define OBJ_sect571k1 OBJ_secg_ellipticCurve,38L
-
-#define SN_sect571r1 "sect571r1"
-#define NID_sect571r1 734
-#define OBJ_sect571r1 OBJ_secg_ellipticCurve,39L
-
-#define OBJ_wap_wsg_idm_ecid OBJ_wap_wsg,4L
-
-#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1"
-#define NID_wap_wsg_idm_ecid_wtls1 735
-#define OBJ_wap_wsg_idm_ecid_wtls1 OBJ_wap_wsg_idm_ecid,1L
-
-#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3"
-#define NID_wap_wsg_idm_ecid_wtls3 736
-#define OBJ_wap_wsg_idm_ecid_wtls3 OBJ_wap_wsg_idm_ecid,3L
-
-#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4"
-#define NID_wap_wsg_idm_ecid_wtls4 737
-#define OBJ_wap_wsg_idm_ecid_wtls4 OBJ_wap_wsg_idm_ecid,4L
-
-#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5"
-#define NID_wap_wsg_idm_ecid_wtls5 738
-#define OBJ_wap_wsg_idm_ecid_wtls5 OBJ_wap_wsg_idm_ecid,5L
-
-#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6"
-#define NID_wap_wsg_idm_ecid_wtls6 739
-#define OBJ_wap_wsg_idm_ecid_wtls6 OBJ_wap_wsg_idm_ecid,6L
-
-#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7"
-#define NID_wap_wsg_idm_ecid_wtls7 740
-#define OBJ_wap_wsg_idm_ecid_wtls7 OBJ_wap_wsg_idm_ecid,7L
-
-#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8"
-#define NID_wap_wsg_idm_ecid_wtls8 741
-#define OBJ_wap_wsg_idm_ecid_wtls8 OBJ_wap_wsg_idm_ecid,8L
-
-#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9"
-#define NID_wap_wsg_idm_ecid_wtls9 742
-#define OBJ_wap_wsg_idm_ecid_wtls9 OBJ_wap_wsg_idm_ecid,9L
-
-#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10"
-#define NID_wap_wsg_idm_ecid_wtls10 743
-#define OBJ_wap_wsg_idm_ecid_wtls10 OBJ_wap_wsg_idm_ecid,10L
-
-#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11"
-#define NID_wap_wsg_idm_ecid_wtls11 744
-#define OBJ_wap_wsg_idm_ecid_wtls11 OBJ_wap_wsg_idm_ecid,11L
-
-#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12"
-#define NID_wap_wsg_idm_ecid_wtls12 745
-#define OBJ_wap_wsg_idm_ecid_wtls12 OBJ_wap_wsg_idm_ecid,12L
-
-#define SN_cast5_cbc "CAST5-CBC"
-#define LN_cast5_cbc "cast5-cbc"
-#define NID_cast5_cbc 108
-#define OBJ_cast5_cbc OBJ_ISO_US,113533L,7L,66L,10L
-
-#define SN_cast5_ecb "CAST5-ECB"
-#define LN_cast5_ecb "cast5-ecb"
-#define NID_cast5_ecb 109
-
-#define SN_cast5_cfb64 "CAST5-CFB"
-#define LN_cast5_cfb64 "cast5-cfb"
-#define NID_cast5_cfb64 110
-
-#define SN_cast5_ofb64 "CAST5-OFB"
-#define LN_cast5_ofb64 "cast5-ofb"
-#define NID_cast5_ofb64 111
-
-#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC"
-#define NID_pbeWithMD5AndCast5_CBC 112
-#define OBJ_pbeWithMD5AndCast5_CBC OBJ_ISO_US,113533L,7L,66L,12L
-
-#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC"
-#define LN_id_PasswordBasedMAC "password based MAC"
-#define NID_id_PasswordBasedMAC 782
-#define OBJ_id_PasswordBasedMAC OBJ_ISO_US,113533L,7L,66L,13L
-
-#define SN_id_DHBasedMac "id-DHBasedMac"
-#define LN_id_DHBasedMac "Diffie-Hellman based MAC"
-#define NID_id_DHBasedMac 783
-#define OBJ_id_DHBasedMac OBJ_ISO_US,113533L,7L,66L,30L
-
-#define SN_rsadsi "rsadsi"
-#define LN_rsadsi "RSA Data Security, Inc."
-#define NID_rsadsi 1
-#define OBJ_rsadsi OBJ_ISO_US,113549L
-
-#define SN_pkcs "pkcs"
-#define LN_pkcs "RSA Data Security, Inc. PKCS"
-#define NID_pkcs 2
-#define OBJ_pkcs OBJ_rsadsi,1L
-
-#define SN_pkcs1 "pkcs1"
-#define NID_pkcs1 186
-#define OBJ_pkcs1 OBJ_pkcs,1L
-
-#define LN_rsaEncryption "rsaEncryption"
-#define NID_rsaEncryption 6
-#define OBJ_rsaEncryption OBJ_pkcs1,1L
-
-#define SN_md2WithRSAEncryption "RSA-MD2"
-#define LN_md2WithRSAEncryption "md2WithRSAEncryption"
-#define NID_md2WithRSAEncryption 7
-#define OBJ_md2WithRSAEncryption OBJ_pkcs1,2L
-
-#define SN_md4WithRSAEncryption "RSA-MD4"
-#define LN_md4WithRSAEncryption "md4WithRSAEncryption"
-#define NID_md4WithRSAEncryption 396
-#define OBJ_md4WithRSAEncryption OBJ_pkcs1,3L
-
-#define SN_md5WithRSAEncryption "RSA-MD5"
-#define LN_md5WithRSAEncryption "md5WithRSAEncryption"
-#define NID_md5WithRSAEncryption 8
-#define OBJ_md5WithRSAEncryption OBJ_pkcs1,4L
-
-#define SN_sha1WithRSAEncryption "RSA-SHA1"
-#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption"
-#define NID_sha1WithRSAEncryption 65
-#define OBJ_sha1WithRSAEncryption OBJ_pkcs1,5L
-
-#define SN_rsaesOaep "RSAES-OAEP"
-#define LN_rsaesOaep "rsaesOaep"
-#define NID_rsaesOaep 919
-#define OBJ_rsaesOaep OBJ_pkcs1,7L
-
-#define SN_mgf1 "MGF1"
-#define LN_mgf1 "mgf1"
-#define NID_mgf1 911
-#define OBJ_mgf1 OBJ_pkcs1,8L
-
-#define SN_rsassaPss "RSASSA-PSS"
-#define LN_rsassaPss "rsassaPss"
-#define NID_rsassaPss 912
-#define OBJ_rsassaPss OBJ_pkcs1,10L
-
-#define SN_sha256WithRSAEncryption "RSA-SHA256"
-#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption"
-#define NID_sha256WithRSAEncryption 668
-#define OBJ_sha256WithRSAEncryption OBJ_pkcs1,11L
-
-#define SN_sha384WithRSAEncryption "RSA-SHA384"
-#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption"
-#define NID_sha384WithRSAEncryption 669
-#define OBJ_sha384WithRSAEncryption OBJ_pkcs1,12L
-
-#define SN_sha512WithRSAEncryption "RSA-SHA512"
-#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption"
-#define NID_sha512WithRSAEncryption 670
-#define OBJ_sha512WithRSAEncryption OBJ_pkcs1,13L
-
-#define SN_sha224WithRSAEncryption "RSA-SHA224"
-#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption"
-#define NID_sha224WithRSAEncryption 671
-#define OBJ_sha224WithRSAEncryption OBJ_pkcs1,14L
-
-#define SN_pkcs3 "pkcs3"
-#define NID_pkcs3 27
-#define OBJ_pkcs3 OBJ_pkcs,3L
-
-#define LN_dhKeyAgreement "dhKeyAgreement"
-#define NID_dhKeyAgreement 28
-#define OBJ_dhKeyAgreement OBJ_pkcs3,1L
-
-#define SN_pkcs5 "pkcs5"
-#define NID_pkcs5 187
-#define OBJ_pkcs5 OBJ_pkcs,5L
-
-#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES"
-#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC"
-#define NID_pbeWithMD2AndDES_CBC 9
-#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs5,1L
-
-#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES"
-#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC"
-#define NID_pbeWithMD5AndDES_CBC 10
-#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs5,3L
-
-#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64"
-#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC"
-#define NID_pbeWithMD2AndRC2_CBC 168
-#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs5,4L
-
-#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64"
-#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC"
-#define NID_pbeWithMD5AndRC2_CBC 169
-#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs5,6L
-
-#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES"
-#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC"
-#define NID_pbeWithSHA1AndDES_CBC 170
-#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs5,10L
-
-#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64"
-#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC"
-#define NID_pbeWithSHA1AndRC2_CBC 68
-#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs5,11L
-
-#define LN_id_pbkdf2 "PBKDF2"
-#define NID_id_pbkdf2 69
-#define OBJ_id_pbkdf2 OBJ_pkcs5,12L
-
-#define LN_pbes2 "PBES2"
-#define NID_pbes2 161
-#define OBJ_pbes2 OBJ_pkcs5,13L
-
-#define LN_pbmac1 "PBMAC1"
-#define NID_pbmac1 162
-#define OBJ_pbmac1 OBJ_pkcs5,14L
-
-#define SN_pkcs7 "pkcs7"
-#define NID_pkcs7 20
-#define OBJ_pkcs7 OBJ_pkcs,7L
-
-#define LN_pkcs7_data "pkcs7-data"
-#define NID_pkcs7_data 21
-#define OBJ_pkcs7_data OBJ_pkcs7,1L
-
-#define LN_pkcs7_signed "pkcs7-signedData"
-#define NID_pkcs7_signed 22
-#define OBJ_pkcs7_signed OBJ_pkcs7,2L
-
-#define LN_pkcs7_enveloped "pkcs7-envelopedData"
-#define NID_pkcs7_enveloped 23
-#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L
-
-#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData"
-#define NID_pkcs7_signedAndEnveloped 24
-#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L
-
-#define LN_pkcs7_digest "pkcs7-digestData"
-#define NID_pkcs7_digest 25
-#define OBJ_pkcs7_digest OBJ_pkcs7,5L
-
-#define LN_pkcs7_encrypted "pkcs7-encryptedData"
-#define NID_pkcs7_encrypted 26
-#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L
-
-#define SN_pkcs9 "pkcs9"
-#define NID_pkcs9 47
-#define OBJ_pkcs9 OBJ_pkcs,9L
-
-#define LN_pkcs9_emailAddress "emailAddress"
-#define NID_pkcs9_emailAddress 48
-#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L
-
-#define LN_pkcs9_unstructuredName "unstructuredName"
-#define NID_pkcs9_unstructuredName 49
-#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L
-
-#define LN_pkcs9_contentType "contentType"
-#define NID_pkcs9_contentType 50
-#define OBJ_pkcs9_contentType OBJ_pkcs9,3L
-
-#define LN_pkcs9_messageDigest "messageDigest"
-#define NID_pkcs9_messageDigest 51
-#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L
-
-#define LN_pkcs9_signingTime "signingTime"
-#define NID_pkcs9_signingTime 52
-#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L
-
-#define LN_pkcs9_countersignature "countersignature"
-#define NID_pkcs9_countersignature 53
-#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L
-
-#define LN_pkcs9_challengePassword "challengePassword"
-#define NID_pkcs9_challengePassword 54
-#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L
-
-#define LN_pkcs9_unstructuredAddress "unstructuredAddress"
-#define NID_pkcs9_unstructuredAddress 55
-#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L
-
-#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes"
-#define NID_pkcs9_extCertAttributes 56
-#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L
-
-#define SN_ext_req "extReq"
-#define LN_ext_req "Extension Request"
-#define NID_ext_req 172
-#define OBJ_ext_req OBJ_pkcs9,14L
-
-#define SN_SMIMECapabilities "SMIME-CAPS"
-#define LN_SMIMECapabilities "S/MIME Capabilities"
-#define NID_SMIMECapabilities 167
-#define OBJ_SMIMECapabilities OBJ_pkcs9,15L
-
-#define SN_SMIME "SMIME"
-#define LN_SMIME "S/MIME"
-#define NID_SMIME 188
-#define OBJ_SMIME OBJ_pkcs9,16L
-
-#define SN_id_smime_mod "id-smime-mod"
-#define NID_id_smime_mod 189
-#define OBJ_id_smime_mod OBJ_SMIME,0L
-
-#define SN_id_smime_ct "id-smime-ct"
-#define NID_id_smime_ct 190
-#define OBJ_id_smime_ct OBJ_SMIME,1L
-
-#define SN_id_smime_aa "id-smime-aa"
-#define NID_id_smime_aa 191
-#define OBJ_id_smime_aa OBJ_SMIME,2L
-
-#define SN_id_smime_alg "id-smime-alg"
-#define NID_id_smime_alg 192
-#define OBJ_id_smime_alg OBJ_SMIME,3L
-
-#define SN_id_smime_cd "id-smime-cd"
-#define NID_id_smime_cd 193
-#define OBJ_id_smime_cd OBJ_SMIME,4L
-
-#define SN_id_smime_spq "id-smime-spq"
-#define NID_id_smime_spq 194
-#define OBJ_id_smime_spq OBJ_SMIME,5L
-
-#define SN_id_smime_cti "id-smime-cti"
-#define NID_id_smime_cti 195
-#define OBJ_id_smime_cti OBJ_SMIME,6L
-
-#define SN_id_smime_mod_cms "id-smime-mod-cms"
-#define NID_id_smime_mod_cms 196
-#define OBJ_id_smime_mod_cms OBJ_id_smime_mod,1L
-
-#define SN_id_smime_mod_ess "id-smime-mod-ess"
-#define NID_id_smime_mod_ess 197
-#define OBJ_id_smime_mod_ess OBJ_id_smime_mod,2L
-
-#define SN_id_smime_mod_oid "id-smime-mod-oid"
-#define NID_id_smime_mod_oid 198
-#define OBJ_id_smime_mod_oid OBJ_id_smime_mod,3L
-
-#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3"
-#define NID_id_smime_mod_msg_v3 199
-#define OBJ_id_smime_mod_msg_v3 OBJ_id_smime_mod,4L
-
-#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88"
-#define NID_id_smime_mod_ets_eSignature_88 200
-#define OBJ_id_smime_mod_ets_eSignature_88 OBJ_id_smime_mod,5L
-
-#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97"
-#define NID_id_smime_mod_ets_eSignature_97 201
-#define OBJ_id_smime_mod_ets_eSignature_97 OBJ_id_smime_mod,6L
-
-#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88"
-#define NID_id_smime_mod_ets_eSigPolicy_88 202
-#define OBJ_id_smime_mod_ets_eSigPolicy_88 OBJ_id_smime_mod,7L
-
-#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97"
-#define NID_id_smime_mod_ets_eSigPolicy_97 203
-#define OBJ_id_smime_mod_ets_eSigPolicy_97 OBJ_id_smime_mod,8L
-
-#define SN_id_smime_ct_receipt "id-smime-ct-receipt"
-#define NID_id_smime_ct_receipt 204
-#define OBJ_id_smime_ct_receipt OBJ_id_smime_ct,1L
-
-#define SN_id_smime_ct_authData "id-smime-ct-authData"
-#define NID_id_smime_ct_authData 205
-#define OBJ_id_smime_ct_authData OBJ_id_smime_ct,2L
-
-#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert"
-#define NID_id_smime_ct_publishCert 206
-#define OBJ_id_smime_ct_publishCert OBJ_id_smime_ct,3L
-
-#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo"
-#define NID_id_smime_ct_TSTInfo 207
-#define OBJ_id_smime_ct_TSTInfo OBJ_id_smime_ct,4L
-
-#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo"
-#define NID_id_smime_ct_TDTInfo 208
-#define OBJ_id_smime_ct_TDTInfo OBJ_id_smime_ct,5L
-
-#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo"
-#define NID_id_smime_ct_contentInfo 209
-#define OBJ_id_smime_ct_contentInfo OBJ_id_smime_ct,6L
-
-#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData"
-#define NID_id_smime_ct_DVCSRequestData 210
-#define OBJ_id_smime_ct_DVCSRequestData OBJ_id_smime_ct,7L
-
-#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData"
-#define NID_id_smime_ct_DVCSResponseData 211
-#define OBJ_id_smime_ct_DVCSResponseData OBJ_id_smime_ct,8L
-
-#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData"
-#define NID_id_smime_ct_compressedData 786
-#define OBJ_id_smime_ct_compressedData OBJ_id_smime_ct,9L
-
-#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF"
-#define NID_id_ct_asciiTextWithCRLF 787
-#define OBJ_id_ct_asciiTextWithCRLF OBJ_id_smime_ct,27L
-
-#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest"
-#define NID_id_smime_aa_receiptRequest 212
-#define OBJ_id_smime_aa_receiptRequest OBJ_id_smime_aa,1L
-
-#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel"
-#define NID_id_smime_aa_securityLabel 213
-#define OBJ_id_smime_aa_securityLabel OBJ_id_smime_aa,2L
-
-#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory"
-#define NID_id_smime_aa_mlExpandHistory 214
-#define OBJ_id_smime_aa_mlExpandHistory OBJ_id_smime_aa,3L
-
-#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint"
-#define NID_id_smime_aa_contentHint 215
-#define OBJ_id_smime_aa_contentHint OBJ_id_smime_aa,4L
-
-#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest"
-#define NID_id_smime_aa_msgSigDigest 216
-#define OBJ_id_smime_aa_msgSigDigest OBJ_id_smime_aa,5L
-
-#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType"
-#define NID_id_smime_aa_encapContentType 217
-#define OBJ_id_smime_aa_encapContentType OBJ_id_smime_aa,6L
-
-#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier"
-#define NID_id_smime_aa_contentIdentifier 218
-#define OBJ_id_smime_aa_contentIdentifier OBJ_id_smime_aa,7L
-
-#define SN_id_smime_aa_macValue "id-smime-aa-macValue"
-#define NID_id_smime_aa_macValue 219
-#define OBJ_id_smime_aa_macValue OBJ_id_smime_aa,8L
-
-#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels"
-#define NID_id_smime_aa_equivalentLabels 220
-#define OBJ_id_smime_aa_equivalentLabels OBJ_id_smime_aa,9L
-
-#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference"
-#define NID_id_smime_aa_contentReference 221
-#define OBJ_id_smime_aa_contentReference OBJ_id_smime_aa,10L
-
-#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref"
-#define NID_id_smime_aa_encrypKeyPref 222
-#define OBJ_id_smime_aa_encrypKeyPref OBJ_id_smime_aa,11L
-
-#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate"
-#define NID_id_smime_aa_signingCertificate 223
-#define OBJ_id_smime_aa_signingCertificate OBJ_id_smime_aa,12L
-
-#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts"
-#define NID_id_smime_aa_smimeEncryptCerts 224
-#define OBJ_id_smime_aa_smimeEncryptCerts OBJ_id_smime_aa,13L
-
-#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken"
-#define NID_id_smime_aa_timeStampToken 225
-#define OBJ_id_smime_aa_timeStampToken OBJ_id_smime_aa,14L
-
-#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId"
-#define NID_id_smime_aa_ets_sigPolicyId 226
-#define OBJ_id_smime_aa_ets_sigPolicyId OBJ_id_smime_aa,15L
-
-#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType"
-#define NID_id_smime_aa_ets_commitmentType 227
-#define OBJ_id_smime_aa_ets_commitmentType OBJ_id_smime_aa,16L
-
-#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation"
-#define NID_id_smime_aa_ets_signerLocation 228
-#define OBJ_id_smime_aa_ets_signerLocation OBJ_id_smime_aa,17L
-
-#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr"
-#define NID_id_smime_aa_ets_signerAttr 229
-#define OBJ_id_smime_aa_ets_signerAttr OBJ_id_smime_aa,18L
-
-#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert"
-#define NID_id_smime_aa_ets_otherSigCert 230
-#define OBJ_id_smime_aa_ets_otherSigCert OBJ_id_smime_aa,19L
-
-#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp"
-#define NID_id_smime_aa_ets_contentTimestamp 231
-#define OBJ_id_smime_aa_ets_contentTimestamp OBJ_id_smime_aa,20L
-
-#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs"
-#define NID_id_smime_aa_ets_CertificateRefs 232
-#define OBJ_id_smime_aa_ets_CertificateRefs OBJ_id_smime_aa,21L
-
-#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs"
-#define NID_id_smime_aa_ets_RevocationRefs 233
-#define OBJ_id_smime_aa_ets_RevocationRefs OBJ_id_smime_aa,22L
-
-#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues"
-#define NID_id_smime_aa_ets_certValues 234
-#define OBJ_id_smime_aa_ets_certValues OBJ_id_smime_aa,23L
-
-#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues"
-#define NID_id_smime_aa_ets_revocationValues 235
-#define OBJ_id_smime_aa_ets_revocationValues OBJ_id_smime_aa,24L
-
-#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp"
-#define NID_id_smime_aa_ets_escTimeStamp 236
-#define OBJ_id_smime_aa_ets_escTimeStamp OBJ_id_smime_aa,25L
-
-#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp"
-#define NID_id_smime_aa_ets_certCRLTimestamp 237
-#define OBJ_id_smime_aa_ets_certCRLTimestamp OBJ_id_smime_aa,26L
-
-#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp"
-#define NID_id_smime_aa_ets_archiveTimeStamp 238
-#define OBJ_id_smime_aa_ets_archiveTimeStamp OBJ_id_smime_aa,27L
-
-#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType"
-#define NID_id_smime_aa_signatureType 239
-#define OBJ_id_smime_aa_signatureType OBJ_id_smime_aa,28L
-
-#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc"
-#define NID_id_smime_aa_dvcs_dvc 240
-#define OBJ_id_smime_aa_dvcs_dvc OBJ_id_smime_aa,29L
-
-#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES"
-#define NID_id_smime_alg_ESDHwith3DES 241
-#define OBJ_id_smime_alg_ESDHwith3DES OBJ_id_smime_alg,1L
-
-#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2"
-#define NID_id_smime_alg_ESDHwithRC2 242
-#define OBJ_id_smime_alg_ESDHwithRC2 OBJ_id_smime_alg,2L
-
-#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap"
-#define NID_id_smime_alg_3DESwrap 243
-#define OBJ_id_smime_alg_3DESwrap OBJ_id_smime_alg,3L
-
-#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap"
-#define NID_id_smime_alg_RC2wrap 244
-#define OBJ_id_smime_alg_RC2wrap OBJ_id_smime_alg,4L
-
-#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH"
-#define NID_id_smime_alg_ESDH 245
-#define OBJ_id_smime_alg_ESDH OBJ_id_smime_alg,5L
-
-#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap"
-#define NID_id_smime_alg_CMS3DESwrap 246
-#define OBJ_id_smime_alg_CMS3DESwrap OBJ_id_smime_alg,6L
-
-#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap"
-#define NID_id_smime_alg_CMSRC2wrap 247
-#define OBJ_id_smime_alg_CMSRC2wrap OBJ_id_smime_alg,7L
-
-#define SN_id_alg_PWRI_KEK "id-alg-PWRI-KEK"
-#define NID_id_alg_PWRI_KEK 893
-#define OBJ_id_alg_PWRI_KEK OBJ_id_smime_alg,9L
-
-#define SN_id_smime_cd_ldap "id-smime-cd-ldap"
-#define NID_id_smime_cd_ldap 248
-#define OBJ_id_smime_cd_ldap OBJ_id_smime_cd,1L
-
-#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri"
-#define NID_id_smime_spq_ets_sqt_uri 249
-#define OBJ_id_smime_spq_ets_sqt_uri OBJ_id_smime_spq,1L
-
-#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice"
-#define NID_id_smime_spq_ets_sqt_unotice 250
-#define OBJ_id_smime_spq_ets_sqt_unotice OBJ_id_smime_spq,2L
-
-#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin"
-#define NID_id_smime_cti_ets_proofOfOrigin 251
-#define OBJ_id_smime_cti_ets_proofOfOrigin OBJ_id_smime_cti,1L
-
-#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt"
-#define NID_id_smime_cti_ets_proofOfReceipt 252
-#define OBJ_id_smime_cti_ets_proofOfReceipt OBJ_id_smime_cti,2L
-
-#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery"
-#define NID_id_smime_cti_ets_proofOfDelivery 253
-#define OBJ_id_smime_cti_ets_proofOfDelivery OBJ_id_smime_cti,3L
-
-#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender"
-#define NID_id_smime_cti_ets_proofOfSender 254
-#define OBJ_id_smime_cti_ets_proofOfSender OBJ_id_smime_cti,4L
-
-#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval"
-#define NID_id_smime_cti_ets_proofOfApproval 255
-#define OBJ_id_smime_cti_ets_proofOfApproval OBJ_id_smime_cti,5L
-
-#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation"
-#define NID_id_smime_cti_ets_proofOfCreation 256
-#define OBJ_id_smime_cti_ets_proofOfCreation OBJ_id_smime_cti,6L
-
-#define LN_friendlyName "friendlyName"
-#define NID_friendlyName 156
-#define OBJ_friendlyName OBJ_pkcs9,20L
-
-#define LN_localKeyID "localKeyID"
-#define NID_localKeyID 157
-#define OBJ_localKeyID OBJ_pkcs9,21L
-
-#define SN_ms_csp_name "CSPName"
-#define LN_ms_csp_name "Microsoft CSP Name"
-#define NID_ms_csp_name 417
-#define OBJ_ms_csp_name 1L,3L,6L,1L,4L,1L,311L,17L,1L
-
-#define SN_LocalKeySet "LocalKeySet"
-#define LN_LocalKeySet "Microsoft Local Key set"
-#define NID_LocalKeySet 856
-#define OBJ_LocalKeySet 1L,3L,6L,1L,4L,1L,311L,17L,2L
-
-#define OBJ_certTypes OBJ_pkcs9,22L
-
-#define LN_x509Certificate "x509Certificate"
-#define NID_x509Certificate 158
-#define OBJ_x509Certificate OBJ_certTypes,1L
-
-#define LN_sdsiCertificate "sdsiCertificate"
-#define NID_sdsiCertificate 159
-#define OBJ_sdsiCertificate OBJ_certTypes,2L
-
-#define OBJ_crlTypes OBJ_pkcs9,23L
-
-#define LN_x509Crl "x509Crl"
-#define NID_x509Crl 160
-#define OBJ_x509Crl OBJ_crlTypes,1L
-
-#define OBJ_pkcs12 OBJ_pkcs,12L
-
-#define OBJ_pkcs12_pbeids OBJ_pkcs12,1L
-
-#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128"
-#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4"
-#define NID_pbe_WithSHA1And128BitRC4 144
-#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids,1L
-
-#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40"
-#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4"
-#define NID_pbe_WithSHA1And40BitRC4 145
-#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids,2L
-
-#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES"
-#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC"
-#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146
-#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids,3L
-
-#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES"
-#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC"
-#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147
-#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids,4L
-
-#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128"
-#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC"
-#define NID_pbe_WithSHA1And128BitRC2_CBC 148
-#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids,5L
-
-#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40"
-#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC"
-#define NID_pbe_WithSHA1And40BitRC2_CBC 149
-#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids,6L
-
-#define OBJ_pkcs12_Version1 OBJ_pkcs12,10L
-
-#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1,1L
-
-#define LN_keyBag "keyBag"
-#define NID_keyBag 150
-#define OBJ_keyBag OBJ_pkcs12_BagIds,1L
-
-#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag"
-#define NID_pkcs8ShroudedKeyBag 151
-#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds,2L
-
-#define LN_certBag "certBag"
-#define NID_certBag 152
-#define OBJ_certBag OBJ_pkcs12_BagIds,3L
-
-#define LN_crlBag "crlBag"
-#define NID_crlBag 153
-#define OBJ_crlBag OBJ_pkcs12_BagIds,4L
-
-#define LN_secretBag "secretBag"
-#define NID_secretBag 154
-#define OBJ_secretBag OBJ_pkcs12_BagIds,5L
-
-#define LN_safeContentsBag "safeContentsBag"
-#define NID_safeContentsBag 155
-#define OBJ_safeContentsBag OBJ_pkcs12_BagIds,6L
-
-#define SN_md2 "MD2"
-#define LN_md2 "md2"
-#define NID_md2 3
-#define OBJ_md2 OBJ_rsadsi,2L,2L
-
-#define SN_md4 "MD4"
-#define LN_md4 "md4"
-#define NID_md4 257
-#define OBJ_md4 OBJ_rsadsi,2L,4L
-
-#define SN_md5 "MD5"
-#define LN_md5 "md5"
-#define NID_md5 4
-#define OBJ_md5 OBJ_rsadsi,2L,5L
-
-#define SN_md5_sha1 "MD5-SHA1"
-#define LN_md5_sha1 "md5-sha1"
-#define NID_md5_sha1 114
-
-#define LN_hmacWithMD5 "hmacWithMD5"
-#define NID_hmacWithMD5 797
-#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L
-
-#define LN_hmacWithSHA1 "hmacWithSHA1"
-#define NID_hmacWithSHA1 163
-#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L
-
-#define LN_hmacWithSHA224 "hmacWithSHA224"
-#define NID_hmacWithSHA224 798
-#define OBJ_hmacWithSHA224 OBJ_rsadsi,2L,8L
-
-#define LN_hmacWithSHA256 "hmacWithSHA256"
-#define NID_hmacWithSHA256 799
-#define OBJ_hmacWithSHA256 OBJ_rsadsi,2L,9L
-
-#define LN_hmacWithSHA384 "hmacWithSHA384"
-#define NID_hmacWithSHA384 800
-#define OBJ_hmacWithSHA384 OBJ_rsadsi,2L,10L
-
-#define LN_hmacWithSHA512 "hmacWithSHA512"
-#define NID_hmacWithSHA512 801
-#define OBJ_hmacWithSHA512 OBJ_rsadsi,2L,11L
-
-#define SN_rc2_cbc "RC2-CBC"
-#define LN_rc2_cbc "rc2-cbc"
-#define NID_rc2_cbc 37
-#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L
-
-#define SN_rc2_ecb "RC2-ECB"
-#define LN_rc2_ecb "rc2-ecb"
-#define NID_rc2_ecb 38
-
-#define SN_rc2_cfb64 "RC2-CFB"
-#define LN_rc2_cfb64 "rc2-cfb"
-#define NID_rc2_cfb64 39
-
-#define SN_rc2_ofb64 "RC2-OFB"
-#define LN_rc2_ofb64 "rc2-ofb"
-#define NID_rc2_ofb64 40
-
-#define SN_rc2_40_cbc "RC2-40-CBC"
-#define LN_rc2_40_cbc "rc2-40-cbc"
-#define NID_rc2_40_cbc 98
-
-#define SN_rc2_64_cbc "RC2-64-CBC"
-#define LN_rc2_64_cbc "rc2-64-cbc"
-#define NID_rc2_64_cbc 166
-
-#define SN_rc4 "RC4"
-#define LN_rc4 "rc4"
-#define NID_rc4 5
-#define OBJ_rc4 OBJ_rsadsi,3L,4L
-
-#define SN_rc4_40 "RC4-40"
-#define LN_rc4_40 "rc4-40"
-#define NID_rc4_40 97
-
-#define SN_des_ede3_cbc "DES-EDE3-CBC"
-#define LN_des_ede3_cbc "des-ede3-cbc"
-#define NID_des_ede3_cbc 44
-#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L
-
-#define SN_rc5_cbc "RC5-CBC"
-#define LN_rc5_cbc "rc5-cbc"
-#define NID_rc5_cbc 120
-#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L
-
-#define SN_rc5_ecb "RC5-ECB"
-#define LN_rc5_ecb "rc5-ecb"
-#define NID_rc5_ecb 121
-
-#define SN_rc5_cfb64 "RC5-CFB"
-#define LN_rc5_cfb64 "rc5-cfb"
-#define NID_rc5_cfb64 122
-
-#define SN_rc5_ofb64 "RC5-OFB"
-#define LN_rc5_ofb64 "rc5-ofb"
-#define NID_rc5_ofb64 123
-
-#define SN_ms_ext_req "msExtReq"
-#define LN_ms_ext_req "Microsoft Extension Request"
-#define NID_ms_ext_req 171
-#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L
-
-#define SN_ms_code_ind "msCodeInd"
-#define LN_ms_code_ind "Microsoft Individual Code Signing"
-#define NID_ms_code_ind 134
-#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L
-
-#define SN_ms_code_com "msCodeCom"
-#define LN_ms_code_com "Microsoft Commercial Code Signing"
-#define NID_ms_code_com 135
-#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L
-
-#define SN_ms_ctl_sign "msCTLSign"
-#define LN_ms_ctl_sign "Microsoft Trust List Signing"
-#define NID_ms_ctl_sign 136
-#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L
-
-#define SN_ms_sgc "msSGC"
-#define LN_ms_sgc "Microsoft Server Gated Crypto"
-#define NID_ms_sgc 137
-#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L
-
-#define SN_ms_efs "msEFS"
-#define LN_ms_efs "Microsoft Encrypted File System"
-#define NID_ms_efs 138
-#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L
-
-#define SN_ms_smartcard_login "msSmartcardLogin"
-#define LN_ms_smartcard_login "Microsoft Smartcardlogin"
-#define NID_ms_smartcard_login 648
-#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L
-
-#define SN_ms_upn "msUPN"
-#define LN_ms_upn "Microsoft Universal Principal Name"
-#define NID_ms_upn 649
-#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L
-
-#define SN_idea_cbc "IDEA-CBC"
-#define LN_idea_cbc "idea-cbc"
-#define NID_idea_cbc 34
-#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L
-
-#define SN_idea_ecb "IDEA-ECB"
-#define LN_idea_ecb "idea-ecb"
-#define NID_idea_ecb 36
-
-#define SN_idea_cfb64 "IDEA-CFB"
-#define LN_idea_cfb64 "idea-cfb"
-#define NID_idea_cfb64 35
-
-#define SN_idea_ofb64 "IDEA-OFB"
-#define LN_idea_ofb64 "idea-ofb"
-#define NID_idea_ofb64 46
-
-#define SN_bf_cbc "BF-CBC"
-#define LN_bf_cbc "bf-cbc"
-#define NID_bf_cbc 91
-#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L
-
-#define SN_bf_ecb "BF-ECB"
-#define LN_bf_ecb "bf-ecb"
-#define NID_bf_ecb 92
-
-#define SN_bf_cfb64 "BF-CFB"
-#define LN_bf_cfb64 "bf-cfb"
-#define NID_bf_cfb64 93
-
-#define SN_bf_ofb64 "BF-OFB"
-#define LN_bf_ofb64 "bf-ofb"
-#define NID_bf_ofb64 94
-
-#define SN_id_pkix "PKIX"
-#define NID_id_pkix 127
-#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L
-
-#define SN_id_pkix_mod "id-pkix-mod"
-#define NID_id_pkix_mod 258
-#define OBJ_id_pkix_mod OBJ_id_pkix,0L
-
-#define SN_id_pe "id-pe"
-#define NID_id_pe 175
-#define OBJ_id_pe OBJ_id_pkix,1L
-
-#define SN_id_qt "id-qt"
-#define NID_id_qt 259
-#define OBJ_id_qt OBJ_id_pkix,2L
-
-#define SN_id_kp "id-kp"
-#define NID_id_kp 128
-#define OBJ_id_kp OBJ_id_pkix,3L
-
-#define SN_id_it "id-it"
-#define NID_id_it 260
-#define OBJ_id_it OBJ_id_pkix,4L
-
-#define SN_id_pkip "id-pkip"
-#define NID_id_pkip 261
-#define OBJ_id_pkip OBJ_id_pkix,5L
-
-#define SN_id_alg "id-alg"
-#define NID_id_alg 262
-#define OBJ_id_alg OBJ_id_pkix,6L
-
-#define SN_id_cmc "id-cmc"
-#define NID_id_cmc 263
-#define OBJ_id_cmc OBJ_id_pkix,7L
-
-#define SN_id_on "id-on"
-#define NID_id_on 264
-#define OBJ_id_on OBJ_id_pkix,8L
-
-#define SN_id_pda "id-pda"
-#define NID_id_pda 265
-#define OBJ_id_pda OBJ_id_pkix,9L
-
-#define SN_id_aca "id-aca"
-#define NID_id_aca 266
-#define OBJ_id_aca OBJ_id_pkix,10L
-
-#define SN_id_qcs "id-qcs"
-#define NID_id_qcs 267
-#define OBJ_id_qcs OBJ_id_pkix,11L
-
-#define SN_id_cct "id-cct"
-#define NID_id_cct 268
-#define OBJ_id_cct OBJ_id_pkix,12L
-
-#define SN_id_ppl "id-ppl"
-#define NID_id_ppl 662
-#define OBJ_id_ppl OBJ_id_pkix,21L
-
-#define SN_id_ad "id-ad"
-#define NID_id_ad 176
-#define OBJ_id_ad OBJ_id_pkix,48L
-
-#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88"
-#define NID_id_pkix1_explicit_88 269
-#define OBJ_id_pkix1_explicit_88 OBJ_id_pkix_mod,1L
-
-#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88"
-#define NID_id_pkix1_implicit_88 270
-#define OBJ_id_pkix1_implicit_88 OBJ_id_pkix_mod,2L
-
-#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93"
-#define NID_id_pkix1_explicit_93 271
-#define OBJ_id_pkix1_explicit_93 OBJ_id_pkix_mod,3L
-
-#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93"
-#define NID_id_pkix1_implicit_93 272
-#define OBJ_id_pkix1_implicit_93 OBJ_id_pkix_mod,4L
-
-#define SN_id_mod_crmf "id-mod-crmf"
-#define NID_id_mod_crmf 273
-#define OBJ_id_mod_crmf OBJ_id_pkix_mod,5L
-
-#define SN_id_mod_cmc "id-mod-cmc"
-#define NID_id_mod_cmc 274
-#define OBJ_id_mod_cmc OBJ_id_pkix_mod,6L
-
-#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88"
-#define NID_id_mod_kea_profile_88 275
-#define OBJ_id_mod_kea_profile_88 OBJ_id_pkix_mod,7L
-
-#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93"
-#define NID_id_mod_kea_profile_93 276
-#define OBJ_id_mod_kea_profile_93 OBJ_id_pkix_mod,8L
-
-#define SN_id_mod_cmp "id-mod-cmp"
-#define NID_id_mod_cmp 277
-#define OBJ_id_mod_cmp OBJ_id_pkix_mod,9L
-
-#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88"
-#define NID_id_mod_qualified_cert_88 278
-#define OBJ_id_mod_qualified_cert_88 OBJ_id_pkix_mod,10L
-
-#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93"
-#define NID_id_mod_qualified_cert_93 279
-#define OBJ_id_mod_qualified_cert_93 OBJ_id_pkix_mod,11L
-
-#define SN_id_mod_attribute_cert "id-mod-attribute-cert"
-#define NID_id_mod_attribute_cert 280
-#define OBJ_id_mod_attribute_cert OBJ_id_pkix_mod,12L
-
-#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol"
-#define NID_id_mod_timestamp_protocol 281
-#define OBJ_id_mod_timestamp_protocol OBJ_id_pkix_mod,13L
-
-#define SN_id_mod_ocsp "id-mod-ocsp"
-#define NID_id_mod_ocsp 282
-#define OBJ_id_mod_ocsp OBJ_id_pkix_mod,14L
-
-#define SN_id_mod_dvcs "id-mod-dvcs"
-#define NID_id_mod_dvcs 283
-#define OBJ_id_mod_dvcs OBJ_id_pkix_mod,15L
-
-#define SN_id_mod_cmp2000 "id-mod-cmp2000"
-#define NID_id_mod_cmp2000 284
-#define OBJ_id_mod_cmp2000 OBJ_id_pkix_mod,16L
-
-#define SN_info_access "authorityInfoAccess"
-#define LN_info_access "Authority Information Access"
-#define NID_info_access 177
-#define OBJ_info_access OBJ_id_pe,1L
-
-#define SN_biometricInfo "biometricInfo"
-#define LN_biometricInfo "Biometric Info"
-#define NID_biometricInfo 285
-#define OBJ_biometricInfo OBJ_id_pe,2L
-
-#define SN_qcStatements "qcStatements"
-#define NID_qcStatements 286
-#define OBJ_qcStatements OBJ_id_pe,3L
-
-#define SN_ac_auditEntity "ac-auditEntity"
-#define NID_ac_auditEntity 287
-#define OBJ_ac_auditEntity OBJ_id_pe,4L
-
-#define SN_ac_targeting "ac-targeting"
-#define NID_ac_targeting 288
-#define OBJ_ac_targeting OBJ_id_pe,5L
-
-#define SN_aaControls "aaControls"
-#define NID_aaControls 289
-#define OBJ_aaControls OBJ_id_pe,6L
-
-#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock"
-#define NID_sbgp_ipAddrBlock 290
-#define OBJ_sbgp_ipAddrBlock OBJ_id_pe,7L
-
-#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum"
-#define NID_sbgp_autonomousSysNum 291
-#define OBJ_sbgp_autonomousSysNum OBJ_id_pe,8L
-
-#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier"
-#define NID_sbgp_routerIdentifier 292
-#define OBJ_sbgp_routerIdentifier OBJ_id_pe,9L
-
-#define SN_ac_proxying "ac-proxying"
-#define NID_ac_proxying 397
-#define OBJ_ac_proxying OBJ_id_pe,10L
-
-#define SN_sinfo_access "subjectInfoAccess"
-#define LN_sinfo_access "Subject Information Access"
-#define NID_sinfo_access 398
-#define OBJ_sinfo_access OBJ_id_pe,11L
-
-#define SN_proxyCertInfo "proxyCertInfo"
-#define LN_proxyCertInfo "Proxy Certificate Information"
-#define NID_proxyCertInfo 663
-#define OBJ_proxyCertInfo OBJ_id_pe,14L
-
-#define SN_id_qt_cps "id-qt-cps"
-#define LN_id_qt_cps "Policy Qualifier CPS"
-#define NID_id_qt_cps 164
-#define OBJ_id_qt_cps OBJ_id_qt,1L
-
-#define SN_id_qt_unotice "id-qt-unotice"
-#define LN_id_qt_unotice "Policy Qualifier User Notice"
-#define NID_id_qt_unotice 165
-#define OBJ_id_qt_unotice OBJ_id_qt,2L
-
-#define SN_textNotice "textNotice"
-#define NID_textNotice 293
-#define OBJ_textNotice OBJ_id_qt,3L
-
-#define SN_server_auth "serverAuth"
-#define LN_server_auth "TLS Web Server Authentication"
-#define NID_server_auth 129
-#define OBJ_server_auth OBJ_id_kp,1L
-
-#define SN_client_auth "clientAuth"
-#define LN_client_auth "TLS Web Client Authentication"
-#define NID_client_auth 130
-#define OBJ_client_auth OBJ_id_kp,2L
-
-#define SN_code_sign "codeSigning"
-#define LN_code_sign "Code Signing"
-#define NID_code_sign 131
-#define OBJ_code_sign OBJ_id_kp,3L
-
-#define SN_email_protect "emailProtection"
-#define LN_email_protect "E-mail Protection"
-#define NID_email_protect 132
-#define OBJ_email_protect OBJ_id_kp,4L
-
-#define SN_ipsecEndSystem "ipsecEndSystem"
-#define LN_ipsecEndSystem "IPSec End System"
-#define NID_ipsecEndSystem 294
-#define OBJ_ipsecEndSystem OBJ_id_kp,5L
-
-#define SN_ipsecTunnel "ipsecTunnel"
-#define LN_ipsecTunnel "IPSec Tunnel"
-#define NID_ipsecTunnel 295
-#define OBJ_ipsecTunnel OBJ_id_kp,6L
-
-#define SN_ipsecUser "ipsecUser"
-#define LN_ipsecUser "IPSec User"
-#define NID_ipsecUser 296
-#define OBJ_ipsecUser OBJ_id_kp,7L
-
-#define SN_time_stamp "timeStamping"
-#define LN_time_stamp "Time Stamping"
-#define NID_time_stamp 133
-#define OBJ_time_stamp OBJ_id_kp,8L
-
-#define SN_OCSP_sign "OCSPSigning"
-#define LN_OCSP_sign "OCSP Signing"
-#define NID_OCSP_sign 180
-#define OBJ_OCSP_sign OBJ_id_kp,9L
-
-#define SN_dvcs "DVCS"
-#define LN_dvcs "dvcs"
-#define NID_dvcs 297
-#define OBJ_dvcs OBJ_id_kp,10L
-
-#define SN_id_it_caProtEncCert "id-it-caProtEncCert"
-#define NID_id_it_caProtEncCert 298
-#define OBJ_id_it_caProtEncCert OBJ_id_it,1L
-
-#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes"
-#define NID_id_it_signKeyPairTypes 299
-#define OBJ_id_it_signKeyPairTypes OBJ_id_it,2L
-
-#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes"
-#define NID_id_it_encKeyPairTypes 300
-#define OBJ_id_it_encKeyPairTypes OBJ_id_it,3L
-
-#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg"
-#define NID_id_it_preferredSymmAlg 301
-#define OBJ_id_it_preferredSymmAlg OBJ_id_it,4L
-
-#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo"
-#define NID_id_it_caKeyUpdateInfo 302
-#define OBJ_id_it_caKeyUpdateInfo OBJ_id_it,5L
-
-#define SN_id_it_currentCRL "id-it-currentCRL"
-#define NID_id_it_currentCRL 303
-#define OBJ_id_it_currentCRL OBJ_id_it,6L
-
-#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs"
-#define NID_id_it_unsupportedOIDs 304
-#define OBJ_id_it_unsupportedOIDs OBJ_id_it,7L
-
-#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest"
-#define NID_id_it_subscriptionRequest 305
-#define OBJ_id_it_subscriptionRequest OBJ_id_it,8L
-
-#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse"
-#define NID_id_it_subscriptionResponse 306
-#define OBJ_id_it_subscriptionResponse OBJ_id_it,9L
-
-#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq"
-#define NID_id_it_keyPairParamReq 307
-#define OBJ_id_it_keyPairParamReq OBJ_id_it,10L
-
-#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep"
-#define NID_id_it_keyPairParamRep 308
-#define OBJ_id_it_keyPairParamRep OBJ_id_it,11L
-
-#define SN_id_it_revPassphrase "id-it-revPassphrase"
-#define NID_id_it_revPassphrase 309
-#define OBJ_id_it_revPassphrase OBJ_id_it,12L
-
-#define SN_id_it_implicitConfirm "id-it-implicitConfirm"
-#define NID_id_it_implicitConfirm 310
-#define OBJ_id_it_implicitConfirm OBJ_id_it,13L
-
-#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime"
-#define NID_id_it_confirmWaitTime 311
-#define OBJ_id_it_confirmWaitTime OBJ_id_it,14L
-
-#define SN_id_it_origPKIMessage "id-it-origPKIMessage"
-#define NID_id_it_origPKIMessage 312
-#define OBJ_id_it_origPKIMessage OBJ_id_it,15L
-
-#define SN_id_it_suppLangTags "id-it-suppLangTags"
-#define NID_id_it_suppLangTags 784
-#define OBJ_id_it_suppLangTags OBJ_id_it,16L
-
-#define SN_id_regCtrl "id-regCtrl"
-#define NID_id_regCtrl 313
-#define OBJ_id_regCtrl OBJ_id_pkip,1L
-
-#define SN_id_regInfo "id-regInfo"
-#define NID_id_regInfo 314
-#define OBJ_id_regInfo OBJ_id_pkip,2L
-
-#define SN_id_regCtrl_regToken "id-regCtrl-regToken"
-#define NID_id_regCtrl_regToken 315
-#define OBJ_id_regCtrl_regToken OBJ_id_regCtrl,1L
-
-#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator"
-#define NID_id_regCtrl_authenticator 316
-#define OBJ_id_regCtrl_authenticator OBJ_id_regCtrl,2L
-
-#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo"
-#define NID_id_regCtrl_pkiPublicationInfo 317
-#define OBJ_id_regCtrl_pkiPublicationInfo OBJ_id_regCtrl,3L
-
-#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions"
-#define NID_id_regCtrl_pkiArchiveOptions 318
-#define OBJ_id_regCtrl_pkiArchiveOptions OBJ_id_regCtrl,4L
-
-#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID"
-#define NID_id_regCtrl_oldCertID 319
-#define OBJ_id_regCtrl_oldCertID OBJ_id_regCtrl,5L
-
-#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey"
-#define NID_id_regCtrl_protocolEncrKey 320
-#define OBJ_id_regCtrl_protocolEncrKey OBJ_id_regCtrl,6L
-
-#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs"
-#define NID_id_regInfo_utf8Pairs 321
-#define OBJ_id_regInfo_utf8Pairs OBJ_id_regInfo,1L
-
-#define SN_id_regInfo_certReq "id-regInfo-certReq"
-#define NID_id_regInfo_certReq 322
-#define OBJ_id_regInfo_certReq OBJ_id_regInfo,2L
-
-#define SN_id_alg_des40 "id-alg-des40"
-#define NID_id_alg_des40 323
-#define OBJ_id_alg_des40 OBJ_id_alg,1L
-
-#define SN_id_alg_noSignature "id-alg-noSignature"
-#define NID_id_alg_noSignature 324
-#define OBJ_id_alg_noSignature OBJ_id_alg,2L
-
-#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1"
-#define NID_id_alg_dh_sig_hmac_sha1 325
-#define OBJ_id_alg_dh_sig_hmac_sha1 OBJ_id_alg,3L
-
-#define SN_id_alg_dh_pop "id-alg-dh-pop"
-#define NID_id_alg_dh_pop 326
-#define OBJ_id_alg_dh_pop OBJ_id_alg,4L
-
-#define SN_id_cmc_statusInfo "id-cmc-statusInfo"
-#define NID_id_cmc_statusInfo 327
-#define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L
-
-#define SN_id_cmc_identification "id-cmc-identification"
-#define NID_id_cmc_identification 328
-#define OBJ_id_cmc_identification OBJ_id_cmc,2L
-
-#define SN_id_cmc_identityProof "id-cmc-identityProof"
-#define NID_id_cmc_identityProof 329
-#define OBJ_id_cmc_identityProof OBJ_id_cmc,3L
-
-#define SN_id_cmc_dataReturn "id-cmc-dataReturn"
-#define NID_id_cmc_dataReturn 330
-#define OBJ_id_cmc_dataReturn OBJ_id_cmc,4L
-
-#define SN_id_cmc_transactionId "id-cmc-transactionId"
-#define NID_id_cmc_transactionId 331
-#define OBJ_id_cmc_transactionId OBJ_id_cmc,5L
-
-#define SN_id_cmc_senderNonce "id-cmc-senderNonce"
-#define NID_id_cmc_senderNonce 332
-#define OBJ_id_cmc_senderNonce OBJ_id_cmc,6L
-
-#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce"
-#define NID_id_cmc_recipientNonce 333
-#define OBJ_id_cmc_recipientNonce OBJ_id_cmc,7L
-
-#define SN_id_cmc_addExtensions "id-cmc-addExtensions"
-#define NID_id_cmc_addExtensions 334
-#define OBJ_id_cmc_addExtensions OBJ_id_cmc,8L
-
-#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP"
-#define NID_id_cmc_encryptedPOP 335
-#define OBJ_id_cmc_encryptedPOP OBJ_id_cmc,9L
-
-#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP"
-#define NID_id_cmc_decryptedPOP 336
-#define OBJ_id_cmc_decryptedPOP OBJ_id_cmc,10L
-
-#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness"
-#define NID_id_cmc_lraPOPWitness 337
-#define OBJ_id_cmc_lraPOPWitness OBJ_id_cmc,11L
-
-#define SN_id_cmc_getCert "id-cmc-getCert"
-#define NID_id_cmc_getCert 338
-#define OBJ_id_cmc_getCert OBJ_id_cmc,15L
-
-#define SN_id_cmc_getCRL "id-cmc-getCRL"
-#define NID_id_cmc_getCRL 339
-#define OBJ_id_cmc_getCRL OBJ_id_cmc,16L
-
-#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest"
-#define NID_id_cmc_revokeRequest 340
-#define OBJ_id_cmc_revokeRequest OBJ_id_cmc,17L
-
-#define SN_id_cmc_regInfo "id-cmc-regInfo"
-#define NID_id_cmc_regInfo 341
-#define OBJ_id_cmc_regInfo OBJ_id_cmc,18L
-
-#define SN_id_cmc_responseInfo "id-cmc-responseInfo"
-#define NID_id_cmc_responseInfo 342
-#define OBJ_id_cmc_responseInfo OBJ_id_cmc,19L
-
-#define SN_id_cmc_queryPending "id-cmc-queryPending"
-#define NID_id_cmc_queryPending 343
-#define OBJ_id_cmc_queryPending OBJ_id_cmc,21L
-
-#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom"
-#define NID_id_cmc_popLinkRandom 344
-#define OBJ_id_cmc_popLinkRandom OBJ_id_cmc,22L
-
-#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness"
-#define NID_id_cmc_popLinkWitness 345
-#define OBJ_id_cmc_popLinkWitness OBJ_id_cmc,23L
-
-#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance"
-#define NID_id_cmc_confirmCertAcceptance 346
-#define OBJ_id_cmc_confirmCertAcceptance OBJ_id_cmc,24L
-
-#define SN_id_on_personalData "id-on-personalData"
-#define NID_id_on_personalData 347
-#define OBJ_id_on_personalData OBJ_id_on,1L
-
-#define SN_id_on_permanentIdentifier "id-on-permanentIdentifier"
-#define LN_id_on_permanentIdentifier "Permanent Identifier"
-#define NID_id_on_permanentIdentifier 858
-#define OBJ_id_on_permanentIdentifier OBJ_id_on,3L
-
-#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth"
-#define NID_id_pda_dateOfBirth 348
-#define OBJ_id_pda_dateOfBirth OBJ_id_pda,1L
-
-#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth"
-#define NID_id_pda_placeOfBirth 349
-#define OBJ_id_pda_placeOfBirth OBJ_id_pda,2L
-
-#define SN_id_pda_gender "id-pda-gender"
-#define NID_id_pda_gender 351
-#define OBJ_id_pda_gender OBJ_id_pda,3L
-
-#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship"
-#define NID_id_pda_countryOfCitizenship 352
-#define OBJ_id_pda_countryOfCitizenship OBJ_id_pda,4L
-
-#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence"
-#define NID_id_pda_countryOfResidence 353
-#define OBJ_id_pda_countryOfResidence OBJ_id_pda,5L
-
-#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo"
-#define NID_id_aca_authenticationInfo 354
-#define OBJ_id_aca_authenticationInfo OBJ_id_aca,1L
-
-#define SN_id_aca_accessIdentity "id-aca-accessIdentity"
-#define NID_id_aca_accessIdentity 355
-#define OBJ_id_aca_accessIdentity OBJ_id_aca,2L
-
-#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity"
-#define NID_id_aca_chargingIdentity 356
-#define OBJ_id_aca_chargingIdentity OBJ_id_aca,3L
-
-#define SN_id_aca_group "id-aca-group"
-#define NID_id_aca_group 357
-#define OBJ_id_aca_group OBJ_id_aca,4L
-
-#define SN_id_aca_role "id-aca-role"
-#define NID_id_aca_role 358
-#define OBJ_id_aca_role OBJ_id_aca,5L
-
-#define SN_id_aca_encAttrs "id-aca-encAttrs"
-#define NID_id_aca_encAttrs 399
-#define OBJ_id_aca_encAttrs OBJ_id_aca,6L
-
-#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1"
-#define NID_id_qcs_pkixQCSyntax_v1 359
-#define OBJ_id_qcs_pkixQCSyntax_v1 OBJ_id_qcs,1L
-
-#define SN_id_cct_crs "id-cct-crs"
-#define NID_id_cct_crs 360
-#define OBJ_id_cct_crs OBJ_id_cct,1L
-
-#define SN_id_cct_PKIData "id-cct-PKIData"
-#define NID_id_cct_PKIData 361
-#define OBJ_id_cct_PKIData OBJ_id_cct,2L
-
-#define SN_id_cct_PKIResponse "id-cct-PKIResponse"
-#define NID_id_cct_PKIResponse 362
-#define OBJ_id_cct_PKIResponse OBJ_id_cct,3L
-
-#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage"
-#define LN_id_ppl_anyLanguage "Any language"
-#define NID_id_ppl_anyLanguage 664
-#define OBJ_id_ppl_anyLanguage OBJ_id_ppl,0L
-
-#define SN_id_ppl_inheritAll "id-ppl-inheritAll"
-#define LN_id_ppl_inheritAll "Inherit all"
-#define NID_id_ppl_inheritAll 665
-#define OBJ_id_ppl_inheritAll OBJ_id_ppl,1L
-
-#define SN_Independent "id-ppl-independent"
-#define LN_Independent "Independent"
-#define NID_Independent 667
-#define OBJ_Independent OBJ_id_ppl,2L
-
-#define SN_ad_OCSP "OCSP"
-#define LN_ad_OCSP "OCSP"
-#define NID_ad_OCSP 178
-#define OBJ_ad_OCSP OBJ_id_ad,1L
-
-#define SN_ad_ca_issuers "caIssuers"
-#define LN_ad_ca_issuers "CA Issuers"
-#define NID_ad_ca_issuers 179
-#define OBJ_ad_ca_issuers OBJ_id_ad,2L
-
-#define SN_ad_timeStamping "ad_timestamping"
-#define LN_ad_timeStamping "AD Time Stamping"
-#define NID_ad_timeStamping 363
-#define OBJ_ad_timeStamping OBJ_id_ad,3L
-
-#define SN_ad_dvcs "AD_DVCS"
-#define LN_ad_dvcs "ad dvcs"
-#define NID_ad_dvcs 364
-#define OBJ_ad_dvcs OBJ_id_ad,4L
-
-#define SN_caRepository "caRepository"
-#define LN_caRepository "CA Repository"
-#define NID_caRepository 785
-#define OBJ_caRepository OBJ_id_ad,5L
-
-#define OBJ_id_pkix_OCSP OBJ_ad_OCSP
-
-#define SN_id_pkix_OCSP_basic "basicOCSPResponse"
-#define LN_id_pkix_OCSP_basic "Basic OCSP Response"
-#define NID_id_pkix_OCSP_basic 365
-#define OBJ_id_pkix_OCSP_basic OBJ_id_pkix_OCSP,1L
-
-#define SN_id_pkix_OCSP_Nonce "Nonce"
-#define LN_id_pkix_OCSP_Nonce "OCSP Nonce"
-#define NID_id_pkix_OCSP_Nonce 366
-#define OBJ_id_pkix_OCSP_Nonce OBJ_id_pkix_OCSP,2L
-
-#define SN_id_pkix_OCSP_CrlID "CrlID"
-#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID"
-#define NID_id_pkix_OCSP_CrlID 367
-#define OBJ_id_pkix_OCSP_CrlID OBJ_id_pkix_OCSP,3L
-
-#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses"
-#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses"
-#define NID_id_pkix_OCSP_acceptableResponses 368
-#define OBJ_id_pkix_OCSP_acceptableResponses OBJ_id_pkix_OCSP,4L
-
-#define SN_id_pkix_OCSP_noCheck "noCheck"
-#define LN_id_pkix_OCSP_noCheck "OCSP No Check"
-#define NID_id_pkix_OCSP_noCheck 369
-#define OBJ_id_pkix_OCSP_noCheck OBJ_id_pkix_OCSP,5L
-
-#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff"
-#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff"
-#define NID_id_pkix_OCSP_archiveCutoff 370
-#define OBJ_id_pkix_OCSP_archiveCutoff OBJ_id_pkix_OCSP,6L
-
-#define SN_id_pkix_OCSP_serviceLocator "serviceLocator"
-#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator"
-#define NID_id_pkix_OCSP_serviceLocator 371
-#define OBJ_id_pkix_OCSP_serviceLocator OBJ_id_pkix_OCSP,7L
-
-#define SN_id_pkix_OCSP_extendedStatus "extendedStatus"
-#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status"
-#define NID_id_pkix_OCSP_extendedStatus 372
-#define OBJ_id_pkix_OCSP_extendedStatus OBJ_id_pkix_OCSP,8L
-
-#define SN_id_pkix_OCSP_valid "valid"
-#define NID_id_pkix_OCSP_valid 373
-#define OBJ_id_pkix_OCSP_valid OBJ_id_pkix_OCSP,9L
-
-#define SN_id_pkix_OCSP_path "path"
-#define NID_id_pkix_OCSP_path 374
-#define OBJ_id_pkix_OCSP_path OBJ_id_pkix_OCSP,10L
-
-#define SN_id_pkix_OCSP_trustRoot "trustRoot"
-#define LN_id_pkix_OCSP_trustRoot "Trust Root"
-#define NID_id_pkix_OCSP_trustRoot 375
-#define OBJ_id_pkix_OCSP_trustRoot OBJ_id_pkix_OCSP,11L
-
-#define SN_algorithm "algorithm"
-#define LN_algorithm "algorithm"
-#define NID_algorithm 376
-#define OBJ_algorithm 1L,3L,14L,3L,2L
-
-#define SN_md5WithRSA "RSA-NP-MD5"
-#define LN_md5WithRSA "md5WithRSA"
-#define NID_md5WithRSA 104
-#define OBJ_md5WithRSA OBJ_algorithm,3L
-
-#define SN_des_ecb "DES-ECB"
-#define LN_des_ecb "des-ecb"
-#define NID_des_ecb 29
-#define OBJ_des_ecb OBJ_algorithm,6L
-
-#define SN_des_cbc "DES-CBC"
-#define LN_des_cbc "des-cbc"
-#define NID_des_cbc 31
-#define OBJ_des_cbc OBJ_algorithm,7L
-
-#define SN_des_ofb64 "DES-OFB"
-#define LN_des_ofb64 "des-ofb"
-#define NID_des_ofb64 45
-#define OBJ_des_ofb64 OBJ_algorithm,8L
-
-#define SN_des_cfb64 "DES-CFB"
-#define LN_des_cfb64 "des-cfb"
-#define NID_des_cfb64 30
-#define OBJ_des_cfb64 OBJ_algorithm,9L
-
-#define SN_rsaSignature "rsaSignature"
-#define NID_rsaSignature 377
-#define OBJ_rsaSignature OBJ_algorithm,11L
-
-#define SN_dsa_2 "DSA-old"
-#define LN_dsa_2 "dsaEncryption-old"
-#define NID_dsa_2 67
-#define OBJ_dsa_2 OBJ_algorithm,12L
-
-#define SN_dsaWithSHA "DSA-SHA"
-#define LN_dsaWithSHA "dsaWithSHA"
-#define NID_dsaWithSHA 66
-#define OBJ_dsaWithSHA OBJ_algorithm,13L
-
-#define SN_shaWithRSAEncryption "RSA-SHA"
-#define LN_shaWithRSAEncryption "shaWithRSAEncryption"
-#define NID_shaWithRSAEncryption 42
-#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L
-
-#define SN_des_ede_ecb "DES-EDE"
-#define LN_des_ede_ecb "des-ede"
-#define NID_des_ede_ecb 32
-#define OBJ_des_ede_ecb OBJ_algorithm,17L
-
-#define SN_des_ede3_ecb "DES-EDE3"
-#define LN_des_ede3_ecb "des-ede3"
-#define NID_des_ede3_ecb 33
-
-#define SN_des_ede_cbc "DES-EDE-CBC"
-#define LN_des_ede_cbc "des-ede-cbc"
-#define NID_des_ede_cbc 43
-
-#define SN_des_ede_cfb64 "DES-EDE-CFB"
-#define LN_des_ede_cfb64 "des-ede-cfb"
-#define NID_des_ede_cfb64 60
-
-#define SN_des_ede3_cfb64 "DES-EDE3-CFB"
-#define LN_des_ede3_cfb64 "des-ede3-cfb"
-#define NID_des_ede3_cfb64 61
-
-#define SN_des_ede_ofb64 "DES-EDE-OFB"
-#define LN_des_ede_ofb64 "des-ede-ofb"
-#define NID_des_ede_ofb64 62
-
-#define SN_des_ede3_ofb64 "DES-EDE3-OFB"
-#define LN_des_ede3_ofb64 "des-ede3-ofb"
-#define NID_des_ede3_ofb64 63
-
-#define SN_desx_cbc "DESX-CBC"
-#define LN_desx_cbc "desx-cbc"
-#define NID_desx_cbc 80
-
-#define SN_sha "SHA"
-#define LN_sha "sha"
-#define NID_sha 41
-#define OBJ_sha OBJ_algorithm,18L
-
-#define SN_sha1 "SHA1"
-#define LN_sha1 "sha1"
-#define NID_sha1 64
-#define OBJ_sha1 OBJ_algorithm,26L
-
-#define SN_dsaWithSHA1_2 "DSA-SHA1-old"
-#define LN_dsaWithSHA1_2 "dsaWithSHA1-old"
-#define NID_dsaWithSHA1_2 70
-#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L
-
-#define SN_sha1WithRSA "RSA-SHA1-2"
-#define LN_sha1WithRSA "sha1WithRSA"
-#define NID_sha1WithRSA 115
-#define OBJ_sha1WithRSA OBJ_algorithm,29L
-
-#define SN_ripemd160 "RIPEMD160"
-#define LN_ripemd160 "ripemd160"
-#define NID_ripemd160 117
-#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L
-
-#define SN_ripemd160WithRSA "RSA-RIPEMD160"
-#define LN_ripemd160WithRSA "ripemd160WithRSA"
-#define NID_ripemd160WithRSA 119
-#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L
-
-#define SN_sxnet "SXNetID"
-#define LN_sxnet "Strong Extranet ID"
-#define NID_sxnet 143
-#define OBJ_sxnet 1L,3L,101L,1L,4L,1L
-
-#define SN_X500 "X500"
-#define LN_X500 "directory services (X.500)"
-#define NID_X500 11
-#define OBJ_X500 2L,5L
-
-#define SN_X509 "X509"
-#define NID_X509 12
-#define OBJ_X509 OBJ_X500,4L
-
-#define SN_commonName "CN"
-#define LN_commonName "commonName"
-#define NID_commonName 13
-#define OBJ_commonName OBJ_X509,3L
-
-#define SN_surname "SN"
-#define LN_surname "surname"
-#define NID_surname 100
-#define OBJ_surname OBJ_X509,4L
-
-#define LN_serialNumber "serialNumber"
-#define NID_serialNumber 105
-#define OBJ_serialNumber OBJ_X509,5L
-
-#define SN_countryName "C"
-#define LN_countryName "countryName"
-#define NID_countryName 14
-#define OBJ_countryName OBJ_X509,6L
-
-#define SN_localityName "L"
-#define LN_localityName "localityName"
-#define NID_localityName 15
-#define OBJ_localityName OBJ_X509,7L
-
-#define SN_stateOrProvinceName "ST"
-#define LN_stateOrProvinceName "stateOrProvinceName"
-#define NID_stateOrProvinceName 16
-#define OBJ_stateOrProvinceName OBJ_X509,8L
-
-#define SN_streetAddress "street"
-#define LN_streetAddress "streetAddress"
-#define NID_streetAddress 660
-#define OBJ_streetAddress OBJ_X509,9L
-
-#define SN_organizationName "O"
-#define LN_organizationName "organizationName"
-#define NID_organizationName 17
-#define OBJ_organizationName OBJ_X509,10L
-
-#define SN_organizationalUnitName "OU"
-#define LN_organizationalUnitName "organizationalUnitName"
-#define NID_organizationalUnitName 18
-#define OBJ_organizationalUnitName OBJ_X509,11L
-
-#define SN_title "title"
-#define LN_title "title"
-#define NID_title 106
-#define OBJ_title OBJ_X509,12L
-
-#define LN_description "description"
-#define NID_description 107
-#define OBJ_description OBJ_X509,13L
-
-#define LN_searchGuide "searchGuide"
-#define NID_searchGuide 859
-#define OBJ_searchGuide OBJ_X509,14L
-
-#define LN_businessCategory "businessCategory"
-#define NID_businessCategory 860
-#define OBJ_businessCategory OBJ_X509,15L
-
-#define LN_postalAddress "postalAddress"
-#define NID_postalAddress 861
-#define OBJ_postalAddress OBJ_X509,16L
-
-#define LN_postalCode "postalCode"
-#define NID_postalCode 661
-#define OBJ_postalCode OBJ_X509,17L
-
-#define LN_postOfficeBox "postOfficeBox"
-#define NID_postOfficeBox 862
-#define OBJ_postOfficeBox OBJ_X509,18L
-
-#define LN_physicalDeliveryOfficeName "physicalDeliveryOfficeName"
-#define NID_physicalDeliveryOfficeName 863
-#define OBJ_physicalDeliveryOfficeName OBJ_X509,19L
-
-#define LN_telephoneNumber "telephoneNumber"
-#define NID_telephoneNumber 864
-#define OBJ_telephoneNumber OBJ_X509,20L
-
-#define LN_telexNumber "telexNumber"
-#define NID_telexNumber 865
-#define OBJ_telexNumber OBJ_X509,21L
-
-#define LN_teletexTerminalIdentifier "teletexTerminalIdentifier"
-#define NID_teletexTerminalIdentifier 866
-#define OBJ_teletexTerminalIdentifier OBJ_X509,22L
-
-#define LN_facsimileTelephoneNumber "facsimileTelephoneNumber"
-#define NID_facsimileTelephoneNumber 867
-#define OBJ_facsimileTelephoneNumber OBJ_X509,23L
-
-#define LN_x121Address "x121Address"
-#define NID_x121Address 868
-#define OBJ_x121Address OBJ_X509,24L
-
-#define LN_internationaliSDNNumber "internationaliSDNNumber"
-#define NID_internationaliSDNNumber 869
-#define OBJ_internationaliSDNNumber OBJ_X509,25L
-
-#define LN_registeredAddress "registeredAddress"
-#define NID_registeredAddress 870
-#define OBJ_registeredAddress OBJ_X509,26L
-
-#define LN_destinationIndicator "destinationIndicator"
-#define NID_destinationIndicator 871
-#define OBJ_destinationIndicator OBJ_X509,27L
-
-#define LN_preferredDeliveryMethod "preferredDeliveryMethod"
-#define NID_preferredDeliveryMethod 872
-#define OBJ_preferredDeliveryMethod OBJ_X509,28L
-
-#define LN_presentationAddress "presentationAddress"
-#define NID_presentationAddress 873
-#define OBJ_presentationAddress OBJ_X509,29L
-
-#define LN_supportedApplicationContext "supportedApplicationContext"
-#define NID_supportedApplicationContext 874
-#define OBJ_supportedApplicationContext OBJ_X509,30L
-
-#define SN_member "member"
-#define NID_member 875
-#define OBJ_member OBJ_X509,31L
-
-#define SN_owner "owner"
-#define NID_owner 876
-#define OBJ_owner OBJ_X509,32L
-
-#define LN_roleOccupant "roleOccupant"
-#define NID_roleOccupant 877
-#define OBJ_roleOccupant OBJ_X509,33L
-
-#define SN_seeAlso "seeAlso"
-#define NID_seeAlso 878
-#define OBJ_seeAlso OBJ_X509,34L
-
-#define LN_userPassword "userPassword"
-#define NID_userPassword 879
-#define OBJ_userPassword OBJ_X509,35L
-
-#define LN_userCertificate "userCertificate"
-#define NID_userCertificate 880
-#define OBJ_userCertificate OBJ_X509,36L
-
-#define LN_cACertificate "cACertificate"
-#define NID_cACertificate 881
-#define OBJ_cACertificate OBJ_X509,37L
-
-#define LN_authorityRevocationList "authorityRevocationList"
-#define NID_authorityRevocationList 882
-#define OBJ_authorityRevocationList OBJ_X509,38L
-
-#define LN_certificateRevocationList "certificateRevocationList"
-#define NID_certificateRevocationList 883
-#define OBJ_certificateRevocationList OBJ_X509,39L
-
-#define LN_crossCertificatePair "crossCertificatePair"
-#define NID_crossCertificatePair 884
-#define OBJ_crossCertificatePair OBJ_X509,40L
-
-#define SN_name "name"
-#define LN_name "name"
-#define NID_name 173
-#define OBJ_name OBJ_X509,41L
-
-#define SN_givenName "GN"
-#define LN_givenName "givenName"
-#define NID_givenName 99
-#define OBJ_givenName OBJ_X509,42L
-
-#define SN_initials "initials"
-#define LN_initials "initials"
-#define NID_initials 101
-#define OBJ_initials OBJ_X509,43L
-
-#define LN_generationQualifier "generationQualifier"
-#define NID_generationQualifier 509
-#define OBJ_generationQualifier OBJ_X509,44L
-
-#define LN_x500UniqueIdentifier "x500UniqueIdentifier"
-#define NID_x500UniqueIdentifier 503
-#define OBJ_x500UniqueIdentifier OBJ_X509,45L
-
-#define SN_dnQualifier "dnQualifier"
-#define LN_dnQualifier "dnQualifier"
-#define NID_dnQualifier 174
-#define OBJ_dnQualifier OBJ_X509,46L
-
-#define LN_enhancedSearchGuide "enhancedSearchGuide"
-#define NID_enhancedSearchGuide 885
-#define OBJ_enhancedSearchGuide OBJ_X509,47L
-
-#define LN_protocolInformation "protocolInformation"
-#define NID_protocolInformation 886
-#define OBJ_protocolInformation OBJ_X509,48L
-
-#define LN_distinguishedName "distinguishedName"
-#define NID_distinguishedName 887
-#define OBJ_distinguishedName OBJ_X509,49L
-
-#define LN_uniqueMember "uniqueMember"
-#define NID_uniqueMember 888
-#define OBJ_uniqueMember OBJ_X509,50L
-
-#define LN_houseIdentifier "houseIdentifier"
-#define NID_houseIdentifier 889
-#define OBJ_houseIdentifier OBJ_X509,51L
-
-#define LN_supportedAlgorithms "supportedAlgorithms"
-#define NID_supportedAlgorithms 890
-#define OBJ_supportedAlgorithms OBJ_X509,52L
-
-#define LN_deltaRevocationList "deltaRevocationList"
-#define NID_deltaRevocationList 891
-#define OBJ_deltaRevocationList OBJ_X509,53L
-
-#define SN_dmdName "dmdName"
-#define NID_dmdName 892
-#define OBJ_dmdName OBJ_X509,54L
-
-#define LN_pseudonym "pseudonym"
-#define NID_pseudonym 510
-#define OBJ_pseudonym OBJ_X509,65L
-
-#define SN_role "role"
-#define LN_role "role"
-#define NID_role 400
-#define OBJ_role OBJ_X509,72L
-
-#define SN_X500algorithms "X500algorithms"
-#define LN_X500algorithms "directory services - algorithms"
-#define NID_X500algorithms 378
-#define OBJ_X500algorithms OBJ_X500,8L
-
-#define SN_rsa "RSA"
-#define LN_rsa "rsa"
-#define NID_rsa 19
-#define OBJ_rsa OBJ_X500algorithms,1L,1L
-
-#define SN_mdc2WithRSA "RSA-MDC2"
-#define LN_mdc2WithRSA "mdc2WithRSA"
-#define NID_mdc2WithRSA 96
-#define OBJ_mdc2WithRSA OBJ_X500algorithms,3L,100L
-
-#define SN_mdc2 "MDC2"
-#define LN_mdc2 "mdc2"
-#define NID_mdc2 95
-#define OBJ_mdc2 OBJ_X500algorithms,3L,101L
-
-#define SN_id_ce "id-ce"
-#define NID_id_ce 81
-#define OBJ_id_ce OBJ_X500,29L
-
-#define SN_subject_directory_attributes "subjectDirectoryAttributes"
-#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes"
-#define NID_subject_directory_attributes 769
-#define OBJ_subject_directory_attributes OBJ_id_ce,9L
-
-#define SN_subject_key_identifier "subjectKeyIdentifier"
-#define LN_subject_key_identifier "X509v3 Subject Key Identifier"
-#define NID_subject_key_identifier 82
-#define OBJ_subject_key_identifier OBJ_id_ce,14L
-
-#define SN_key_usage "keyUsage"
-#define LN_key_usage "X509v3 Key Usage"
-#define NID_key_usage 83
-#define OBJ_key_usage OBJ_id_ce,15L
-
-#define SN_private_key_usage_period "privateKeyUsagePeriod"
-#define LN_private_key_usage_period "X509v3 Private Key Usage Period"
-#define NID_private_key_usage_period 84
-#define OBJ_private_key_usage_period OBJ_id_ce,16L
-
-#define SN_subject_alt_name "subjectAltName"
-#define LN_subject_alt_name "X509v3 Subject Alternative Name"
-#define NID_subject_alt_name 85
-#define OBJ_subject_alt_name OBJ_id_ce,17L
-
-#define SN_issuer_alt_name "issuerAltName"
-#define LN_issuer_alt_name "X509v3 Issuer Alternative Name"
-#define NID_issuer_alt_name 86
-#define OBJ_issuer_alt_name OBJ_id_ce,18L
-
-#define SN_basic_constraints "basicConstraints"
-#define LN_basic_constraints "X509v3 Basic Constraints"
-#define NID_basic_constraints 87
-#define OBJ_basic_constraints OBJ_id_ce,19L
-
-#define SN_crl_number "crlNumber"
-#define LN_crl_number "X509v3 CRL Number"
-#define NID_crl_number 88
-#define OBJ_crl_number OBJ_id_ce,20L
-
-#define SN_crl_reason "CRLReason"
-#define LN_crl_reason "X509v3 CRL Reason Code"
-#define NID_crl_reason 141
-#define OBJ_crl_reason OBJ_id_ce,21L
-
-#define SN_invalidity_date "invalidityDate"
-#define LN_invalidity_date "Invalidity Date"
-#define NID_invalidity_date 142
-#define OBJ_invalidity_date OBJ_id_ce,24L
-
-#define SN_delta_crl "deltaCRL"
-#define LN_delta_crl "X509v3 Delta CRL Indicator"
-#define NID_delta_crl 140
-#define OBJ_delta_crl OBJ_id_ce,27L
-
-#define SN_issuing_distribution_point "issuingDistributionPoint"
-#define LN_issuing_distribution_point "X509v3 Issuing Distrubution Point"
-#define NID_issuing_distribution_point 770
-#define OBJ_issuing_distribution_point OBJ_id_ce,28L
-
-#define SN_certificate_issuer "certificateIssuer"
-#define LN_certificate_issuer "X509v3 Certificate Issuer"
-#define NID_certificate_issuer 771
-#define OBJ_certificate_issuer OBJ_id_ce,29L
-
-#define SN_name_constraints "nameConstraints"
-#define LN_name_constraints "X509v3 Name Constraints"
-#define NID_name_constraints 666
-#define OBJ_name_constraints OBJ_id_ce,30L
-
-#define SN_crl_distribution_points "crlDistributionPoints"
-#define LN_crl_distribution_points "X509v3 CRL Distribution Points"
-#define NID_crl_distribution_points 103
-#define OBJ_crl_distribution_points OBJ_id_ce,31L
-
-#define SN_certificate_policies "certificatePolicies"
-#define LN_certificate_policies "X509v3 Certificate Policies"
-#define NID_certificate_policies 89
-#define OBJ_certificate_policies OBJ_id_ce,32L
-
-#define SN_any_policy "anyPolicy"
-#define LN_any_policy "X509v3 Any Policy"
-#define NID_any_policy 746
-#define OBJ_any_policy OBJ_certificate_policies,0L
-
-#define SN_policy_mappings "policyMappings"
-#define LN_policy_mappings "X509v3 Policy Mappings"
-#define NID_policy_mappings 747
-#define OBJ_policy_mappings OBJ_id_ce,33L
-
-#define SN_authority_key_identifier "authorityKeyIdentifier"
-#define LN_authority_key_identifier "X509v3 Authority Key Identifier"
-#define NID_authority_key_identifier 90
-#define OBJ_authority_key_identifier OBJ_id_ce,35L
-
-#define SN_policy_constraints "policyConstraints"
-#define LN_policy_constraints "X509v3 Policy Constraints"
-#define NID_policy_constraints 401
-#define OBJ_policy_constraints OBJ_id_ce,36L
-
-#define SN_ext_key_usage "extendedKeyUsage"
-#define LN_ext_key_usage "X509v3 Extended Key Usage"
-#define NID_ext_key_usage 126
-#define OBJ_ext_key_usage OBJ_id_ce,37L
-
-#define SN_freshest_crl "freshestCRL"
-#define LN_freshest_crl "X509v3 Freshest CRL"
-#define NID_freshest_crl 857
-#define OBJ_freshest_crl OBJ_id_ce,46L
-
-#define SN_inhibit_any_policy "inhibitAnyPolicy"
-#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy"
-#define NID_inhibit_any_policy 748
-#define OBJ_inhibit_any_policy OBJ_id_ce,54L
-
-#define SN_target_information "targetInformation"
-#define LN_target_information "X509v3 AC Targeting"
-#define NID_target_information 402
-#define OBJ_target_information OBJ_id_ce,55L
-
-#define SN_no_rev_avail "noRevAvail"
-#define LN_no_rev_avail "X509v3 No Revocation Available"
-#define NID_no_rev_avail 403
-#define OBJ_no_rev_avail OBJ_id_ce,56L
-
-#define SN_anyExtendedKeyUsage "anyExtendedKeyUsage"
-#define LN_anyExtendedKeyUsage "Any Extended Key Usage"
-#define NID_anyExtendedKeyUsage 910
-#define OBJ_anyExtendedKeyUsage OBJ_ext_key_usage,0L
-
-#define SN_netscape "Netscape"
-#define LN_netscape "Netscape Communications Corp."
-#define NID_netscape 57
-#define OBJ_netscape 2L,16L,840L,1L,113730L
-
-#define SN_netscape_cert_extension "nsCertExt"
-#define LN_netscape_cert_extension "Netscape Certificate Extension"
-#define NID_netscape_cert_extension 58
-#define OBJ_netscape_cert_extension OBJ_netscape,1L
-
-#define SN_netscape_data_type "nsDataType"
-#define LN_netscape_data_type "Netscape Data Type"
-#define NID_netscape_data_type 59
-#define OBJ_netscape_data_type OBJ_netscape,2L
-
-#define SN_netscape_cert_type "nsCertType"
-#define LN_netscape_cert_type "Netscape Cert Type"
-#define NID_netscape_cert_type 71
-#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L
-
-#define SN_netscape_base_url "nsBaseUrl"
-#define LN_netscape_base_url "Netscape Base Url"
-#define NID_netscape_base_url 72
-#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L
-
-#define SN_netscape_revocation_url "nsRevocationUrl"
-#define LN_netscape_revocation_url "Netscape Revocation Url"
-#define NID_netscape_revocation_url 73
-#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L
-
-#define SN_netscape_ca_revocation_url "nsCaRevocationUrl"
-#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url"
-#define NID_netscape_ca_revocation_url 74
-#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L
-
-#define SN_netscape_renewal_url "nsRenewalUrl"
-#define LN_netscape_renewal_url "Netscape Renewal Url"
-#define NID_netscape_renewal_url 75
-#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L
-
-#define SN_netscape_ca_policy_url "nsCaPolicyUrl"
-#define LN_netscape_ca_policy_url "Netscape CA Policy Url"
-#define NID_netscape_ca_policy_url 76
-#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L
-
-#define SN_netscape_ssl_server_name "nsSslServerName"
-#define LN_netscape_ssl_server_name "Netscape SSL Server Name"
-#define NID_netscape_ssl_server_name 77
-#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L
-
-#define SN_netscape_comment "nsComment"
-#define LN_netscape_comment "Netscape Comment"
-#define NID_netscape_comment 78
-#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L
-
-#define SN_netscape_cert_sequence "nsCertSequence"
-#define LN_netscape_cert_sequence "Netscape Certificate Sequence"
-#define NID_netscape_cert_sequence 79
-#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L
-
-#define SN_ns_sgc "nsSGC"
-#define LN_ns_sgc "Netscape Server Gated Crypto"
-#define NID_ns_sgc 139
-#define OBJ_ns_sgc OBJ_netscape,4L,1L
-
-#define SN_org "ORG"
-#define LN_org "org"
-#define NID_org 379
-#define OBJ_org OBJ_iso,3L
-
-#define SN_dod "DOD"
-#define LN_dod "dod"
-#define NID_dod 380
-#define OBJ_dod OBJ_org,6L
-
-#define SN_iana "IANA"
-#define LN_iana "iana"
-#define NID_iana 381
-#define OBJ_iana OBJ_dod,1L
-
-#define OBJ_internet OBJ_iana
-
-#define SN_Directory "directory"
-#define LN_Directory "Directory"
-#define NID_Directory 382
-#define OBJ_Directory OBJ_internet,1L
-
-#define SN_Management "mgmt"
-#define LN_Management "Management"
-#define NID_Management 383
-#define OBJ_Management OBJ_internet,2L
-
-#define SN_Experimental "experimental"
-#define LN_Experimental "Experimental"
-#define NID_Experimental 384
-#define OBJ_Experimental OBJ_internet,3L
-
-#define SN_Private "private"
-#define LN_Private "Private"
-#define NID_Private 385
-#define OBJ_Private OBJ_internet,4L
-
-#define SN_Security "security"
-#define LN_Security "Security"
-#define NID_Security 386
-#define OBJ_Security OBJ_internet,5L
-
-#define SN_SNMPv2 "snmpv2"
-#define LN_SNMPv2 "SNMPv2"
-#define NID_SNMPv2 387
-#define OBJ_SNMPv2 OBJ_internet,6L
-
-#define LN_Mail "Mail"
-#define NID_Mail 388
-#define OBJ_Mail OBJ_internet,7L
-
-#define SN_Enterprises "enterprises"
-#define LN_Enterprises "Enterprises"
-#define NID_Enterprises 389
-#define OBJ_Enterprises OBJ_Private,1L
-
-#define SN_dcObject "dcobject"
-#define LN_dcObject "dcObject"
-#define NID_dcObject 390
-#define OBJ_dcObject OBJ_Enterprises,1466L,344L
-
-#define SN_mime_mhs "mime-mhs"
-#define LN_mime_mhs "MIME MHS"
-#define NID_mime_mhs 504
-#define OBJ_mime_mhs OBJ_Mail,1L
-
-#define SN_mime_mhs_headings "mime-mhs-headings"
-#define LN_mime_mhs_headings "mime-mhs-headings"
-#define NID_mime_mhs_headings 505
-#define OBJ_mime_mhs_headings OBJ_mime_mhs,1L
-
-#define SN_mime_mhs_bodies "mime-mhs-bodies"
-#define LN_mime_mhs_bodies "mime-mhs-bodies"
-#define NID_mime_mhs_bodies 506
-#define OBJ_mime_mhs_bodies OBJ_mime_mhs,2L
-
-#define SN_id_hex_partial_message "id-hex-partial-message"
-#define LN_id_hex_partial_message "id-hex-partial-message"
-#define NID_id_hex_partial_message 507
-#define OBJ_id_hex_partial_message OBJ_mime_mhs_headings,1L
-
-#define SN_id_hex_multipart_message "id-hex-multipart-message"
-#define LN_id_hex_multipart_message "id-hex-multipart-message"
-#define NID_id_hex_multipart_message 508
-#define OBJ_id_hex_multipart_message OBJ_mime_mhs_headings,2L
-
-#define SN_rle_compression "RLE"
-#define LN_rle_compression "run length compression"
-#define NID_rle_compression 124
-#define OBJ_rle_compression 1L,1L,1L,1L,666L,1L
-
-#define SN_zlib_compression "ZLIB"
-#define LN_zlib_compression "zlib compression"
-#define NID_zlib_compression 125
-#define OBJ_zlib_compression OBJ_id_smime_alg,8L
-
-#define OBJ_csor 2L,16L,840L,1L,101L,3L
-
-#define OBJ_nistAlgorithms OBJ_csor,4L
-
-#define OBJ_aes OBJ_nistAlgorithms,1L
-
-#define SN_aes_128_ecb "AES-128-ECB"
-#define LN_aes_128_ecb "aes-128-ecb"
-#define NID_aes_128_ecb 418
-#define OBJ_aes_128_ecb OBJ_aes,1L
-
-#define SN_aes_128_cbc "AES-128-CBC"
-#define LN_aes_128_cbc "aes-128-cbc"
-#define NID_aes_128_cbc 419
-#define OBJ_aes_128_cbc OBJ_aes,2L
-
-#define SN_aes_128_ofb128 "AES-128-OFB"
-#define LN_aes_128_ofb128 "aes-128-ofb"
-#define NID_aes_128_ofb128 420
-#define OBJ_aes_128_ofb128 OBJ_aes,3L
-
-#define SN_aes_128_cfb128 "AES-128-CFB"
-#define LN_aes_128_cfb128 "aes-128-cfb"
-#define NID_aes_128_cfb128 421
-#define OBJ_aes_128_cfb128 OBJ_aes,4L
-
-#define SN_id_aes128_wrap "id-aes128-wrap"
-#define NID_id_aes128_wrap 788
-#define OBJ_id_aes128_wrap OBJ_aes,5L
-
-#define SN_aes_128_gcm "id-aes128-GCM"
-#define LN_aes_128_gcm "aes-128-gcm"
-#define NID_aes_128_gcm 895
-#define OBJ_aes_128_gcm OBJ_aes,6L
-
-#define SN_aes_128_ccm "id-aes128-CCM"
-#define LN_aes_128_ccm "aes-128-ccm"
-#define NID_aes_128_ccm 896
-#define OBJ_aes_128_ccm OBJ_aes,7L
-
-#define SN_id_aes128_wrap_pad "id-aes128-wrap-pad"
-#define NID_id_aes128_wrap_pad 897
-#define OBJ_id_aes128_wrap_pad OBJ_aes,8L
-
-#define SN_aes_192_ecb "AES-192-ECB"
-#define LN_aes_192_ecb "aes-192-ecb"
-#define NID_aes_192_ecb 422
-#define OBJ_aes_192_ecb OBJ_aes,21L
-
-#define SN_aes_192_cbc "AES-192-CBC"
-#define LN_aes_192_cbc "aes-192-cbc"
-#define NID_aes_192_cbc 423
-#define OBJ_aes_192_cbc OBJ_aes,22L
-
-#define SN_aes_192_ofb128 "AES-192-OFB"
-#define LN_aes_192_ofb128 "aes-192-ofb"
-#define NID_aes_192_ofb128 424
-#define OBJ_aes_192_ofb128 OBJ_aes,23L
-
-#define SN_aes_192_cfb128 "AES-192-CFB"
-#define LN_aes_192_cfb128 "aes-192-cfb"
-#define NID_aes_192_cfb128 425
-#define OBJ_aes_192_cfb128 OBJ_aes,24L
-
-#define SN_id_aes192_wrap "id-aes192-wrap"
-#define NID_id_aes192_wrap 789
-#define OBJ_id_aes192_wrap OBJ_aes,25L
-
-#define SN_aes_192_gcm "id-aes192-GCM"
-#define LN_aes_192_gcm "aes-192-gcm"
-#define NID_aes_192_gcm 898
-#define OBJ_aes_192_gcm OBJ_aes,26L
-
-#define SN_aes_192_ccm "id-aes192-CCM"
-#define LN_aes_192_ccm "aes-192-ccm"
-#define NID_aes_192_ccm 899
-#define OBJ_aes_192_ccm OBJ_aes,27L
-
-#define SN_id_aes192_wrap_pad "id-aes192-wrap-pad"
-#define NID_id_aes192_wrap_pad 900
-#define OBJ_id_aes192_wrap_pad OBJ_aes,28L
-
-#define SN_aes_256_ecb "AES-256-ECB"
-#define LN_aes_256_ecb "aes-256-ecb"
-#define NID_aes_256_ecb 426
-#define OBJ_aes_256_ecb OBJ_aes,41L
-
-#define SN_aes_256_cbc "AES-256-CBC"
-#define LN_aes_256_cbc "aes-256-cbc"
-#define NID_aes_256_cbc 427
-#define OBJ_aes_256_cbc OBJ_aes,42L
-
-#define SN_aes_256_ofb128 "AES-256-OFB"
-#define LN_aes_256_ofb128 "aes-256-ofb"
-#define NID_aes_256_ofb128 428
-#define OBJ_aes_256_ofb128 OBJ_aes,43L
-
-#define SN_aes_256_cfb128 "AES-256-CFB"
-#define LN_aes_256_cfb128 "aes-256-cfb"
-#define NID_aes_256_cfb128 429
-#define OBJ_aes_256_cfb128 OBJ_aes,44L
-
-#define SN_id_aes256_wrap "id-aes256-wrap"
-#define NID_id_aes256_wrap 790
-#define OBJ_id_aes256_wrap OBJ_aes,45L
-
-#define SN_aes_256_gcm "id-aes256-GCM"
-#define LN_aes_256_gcm "aes-256-gcm"
-#define NID_aes_256_gcm 901
-#define OBJ_aes_256_gcm OBJ_aes,46L
-
-#define SN_aes_256_ccm "id-aes256-CCM"
-#define LN_aes_256_ccm "aes-256-ccm"
-#define NID_aes_256_ccm 902
-#define OBJ_aes_256_ccm OBJ_aes,47L
-
-#define SN_id_aes256_wrap_pad "id-aes256-wrap-pad"
-#define NID_id_aes256_wrap_pad 903
-#define OBJ_id_aes256_wrap_pad OBJ_aes,48L
-
-#define SN_aes_128_cfb1 "AES-128-CFB1"
-#define LN_aes_128_cfb1 "aes-128-cfb1"
-#define NID_aes_128_cfb1 650
-
-#define SN_aes_192_cfb1 "AES-192-CFB1"
-#define LN_aes_192_cfb1 "aes-192-cfb1"
-#define NID_aes_192_cfb1 651
-
-#define SN_aes_256_cfb1 "AES-256-CFB1"
-#define LN_aes_256_cfb1 "aes-256-cfb1"
-#define NID_aes_256_cfb1 652
-
-#define SN_aes_128_cfb8 "AES-128-CFB8"
-#define LN_aes_128_cfb8 "aes-128-cfb8"
-#define NID_aes_128_cfb8 653
-
-#define SN_aes_192_cfb8 "AES-192-CFB8"
-#define LN_aes_192_cfb8 "aes-192-cfb8"
-#define NID_aes_192_cfb8 654
-
-#define SN_aes_256_cfb8 "AES-256-CFB8"
-#define LN_aes_256_cfb8 "aes-256-cfb8"
-#define NID_aes_256_cfb8 655
-
-#define SN_aes_128_ctr "AES-128-CTR"
-#define LN_aes_128_ctr "aes-128-ctr"
-#define NID_aes_128_ctr 904
-
-#define SN_aes_192_ctr "AES-192-CTR"
-#define LN_aes_192_ctr "aes-192-ctr"
-#define NID_aes_192_ctr 905
-
-#define SN_aes_256_ctr "AES-256-CTR"
-#define LN_aes_256_ctr "aes-256-ctr"
-#define NID_aes_256_ctr 906
-
-#define SN_aes_128_xts "AES-128-XTS"
-#define LN_aes_128_xts "aes-128-xts"
-#define NID_aes_128_xts 913
-
-#define SN_aes_256_xts "AES-256-XTS"
-#define LN_aes_256_xts "aes-256-xts"
-#define NID_aes_256_xts 914
-
-#define SN_des_cfb1 "DES-CFB1"
-#define LN_des_cfb1 "des-cfb1"
-#define NID_des_cfb1 656
-
-#define SN_des_cfb8 "DES-CFB8"
-#define LN_des_cfb8 "des-cfb8"
-#define NID_des_cfb8 657
-
-#define SN_des_ede3_cfb1 "DES-EDE3-CFB1"
-#define LN_des_ede3_cfb1 "des-ede3-cfb1"
-#define NID_des_ede3_cfb1 658
-
-#define SN_des_ede3_cfb8 "DES-EDE3-CFB8"
-#define LN_des_ede3_cfb8 "des-ede3-cfb8"
-#define NID_des_ede3_cfb8 659
-
-#define OBJ_nist_hashalgs OBJ_nistAlgorithms,2L
-
-#define SN_sha256 "SHA256"
-#define LN_sha256 "sha256"
-#define NID_sha256 672
-#define OBJ_sha256 OBJ_nist_hashalgs,1L
-
-#define SN_sha384 "SHA384"
-#define LN_sha384 "sha384"
-#define NID_sha384 673
-#define OBJ_sha384 OBJ_nist_hashalgs,2L
-
-#define SN_sha512 "SHA512"
-#define LN_sha512 "sha512"
-#define NID_sha512 674
-#define OBJ_sha512 OBJ_nist_hashalgs,3L
-
-#define SN_sha224 "SHA224"
-#define LN_sha224 "sha224"
-#define NID_sha224 675
-#define OBJ_sha224 OBJ_nist_hashalgs,4L
-
-#define OBJ_dsa_with_sha2 OBJ_nistAlgorithms,3L
-
-#define SN_dsa_with_SHA224 "dsa_with_SHA224"
-#define NID_dsa_with_SHA224 802
-#define OBJ_dsa_with_SHA224 OBJ_dsa_with_sha2,1L
-
-#define SN_dsa_with_SHA256 "dsa_with_SHA256"
-#define NID_dsa_with_SHA256 803
-#define OBJ_dsa_with_SHA256 OBJ_dsa_with_sha2,2L
-
-#define SN_hold_instruction_code "holdInstructionCode"
-#define LN_hold_instruction_code "Hold Instruction Code"
-#define NID_hold_instruction_code 430
-#define OBJ_hold_instruction_code OBJ_id_ce,23L
-
-#define OBJ_holdInstruction OBJ_X9_57,2L
-
-#define SN_hold_instruction_none "holdInstructionNone"
-#define LN_hold_instruction_none "Hold Instruction None"
-#define NID_hold_instruction_none 431
-#define OBJ_hold_instruction_none OBJ_holdInstruction,1L
-
-#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer"
-#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer"
-#define NID_hold_instruction_call_issuer 432
-#define OBJ_hold_instruction_call_issuer OBJ_holdInstruction,2L
-
-#define SN_hold_instruction_reject "holdInstructionReject"
-#define LN_hold_instruction_reject "Hold Instruction Reject"
-#define NID_hold_instruction_reject 433
-#define OBJ_hold_instruction_reject OBJ_holdInstruction,3L
-
-#define SN_data "data"
-#define NID_data 434
-#define OBJ_data OBJ_itu_t,9L
-
-#define SN_pss "pss"
-#define NID_pss 435
-#define OBJ_pss OBJ_data,2342L
-
-#define SN_ucl "ucl"
-#define NID_ucl 436
-#define OBJ_ucl OBJ_pss,19200300L
-
-#define SN_pilot "pilot"
-#define NID_pilot 437
-#define OBJ_pilot OBJ_ucl,100L
-
-#define LN_pilotAttributeType "pilotAttributeType"
-#define NID_pilotAttributeType 438
-#define OBJ_pilotAttributeType OBJ_pilot,1L
-
-#define LN_pilotAttributeSyntax "pilotAttributeSyntax"
-#define NID_pilotAttributeSyntax 439
-#define OBJ_pilotAttributeSyntax OBJ_pilot,3L
-
-#define LN_pilotObjectClass "pilotObjectClass"
-#define NID_pilotObjectClass 440
-#define OBJ_pilotObjectClass OBJ_pilot,4L
-
-#define LN_pilotGroups "pilotGroups"
-#define NID_pilotGroups 441
-#define OBJ_pilotGroups OBJ_pilot,10L
-
-#define LN_iA5StringSyntax "iA5StringSyntax"
-#define NID_iA5StringSyntax 442
-#define OBJ_iA5StringSyntax OBJ_pilotAttributeSyntax,4L
-
-#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax"
-#define NID_caseIgnoreIA5StringSyntax 443
-#define OBJ_caseIgnoreIA5StringSyntax OBJ_pilotAttributeSyntax,5L
-
-#define LN_pilotObject "pilotObject"
-#define NID_pilotObject 444
-#define OBJ_pilotObject OBJ_pilotObjectClass,3L
-
-#define LN_pilotPerson "pilotPerson"
-#define NID_pilotPerson 445
-#define OBJ_pilotPerson OBJ_pilotObjectClass,4L
-
-#define SN_account "account"
-#define NID_account 446
-#define OBJ_account OBJ_pilotObjectClass,5L
-
-#define SN_document "document"
-#define NID_document 447
-#define OBJ_document OBJ_pilotObjectClass,6L
-
-#define SN_room "room"
-#define NID_room 448
-#define OBJ_room OBJ_pilotObjectClass,7L
-
-#define LN_documentSeries "documentSeries"
-#define NID_documentSeries 449
-#define OBJ_documentSeries OBJ_pilotObjectClass,9L
-
-#define SN_Domain "domain"
-#define LN_Domain "Domain"
-#define NID_Domain 392
-#define OBJ_Domain OBJ_pilotObjectClass,13L
-
-#define LN_rFC822localPart "rFC822localPart"
-#define NID_rFC822localPart 450
-#define OBJ_rFC822localPart OBJ_pilotObjectClass,14L
-
-#define LN_dNSDomain "dNSDomain"
-#define NID_dNSDomain 451
-#define OBJ_dNSDomain OBJ_pilotObjectClass,15L
-
-#define LN_domainRelatedObject "domainRelatedObject"
-#define NID_domainRelatedObject 452
-#define OBJ_domainRelatedObject OBJ_pilotObjectClass,17L
-
-#define LN_friendlyCountry "friendlyCountry"
-#define NID_friendlyCountry 453
-#define OBJ_friendlyCountry OBJ_pilotObjectClass,18L
-
-#define LN_simpleSecurityObject "simpleSecurityObject"
-#define NID_simpleSecurityObject 454
-#define OBJ_simpleSecurityObject OBJ_pilotObjectClass,19L
-
-#define LN_pilotOrganization "pilotOrganization"
-#define NID_pilotOrganization 455
-#define OBJ_pilotOrganization OBJ_pilotObjectClass,20L
-
-#define LN_pilotDSA "pilotDSA"
-#define NID_pilotDSA 456
-#define OBJ_pilotDSA OBJ_pilotObjectClass,21L
-
-#define LN_qualityLabelledData "qualityLabelledData"
-#define NID_qualityLabelledData 457
-#define OBJ_qualityLabelledData OBJ_pilotObjectClass,22L
-
-#define SN_userId "UID"
-#define LN_userId "userId"
-#define NID_userId 458
-#define OBJ_userId OBJ_pilotAttributeType,1L
-
-#define LN_textEncodedORAddress "textEncodedORAddress"
-#define NID_textEncodedORAddress 459
-#define OBJ_textEncodedORAddress OBJ_pilotAttributeType,2L
-
-#define SN_rfc822Mailbox "mail"
-#define LN_rfc822Mailbox "rfc822Mailbox"
-#define NID_rfc822Mailbox 460
-#define OBJ_rfc822Mailbox OBJ_pilotAttributeType,3L
-
-#define SN_info "info"
-#define NID_info 461
-#define OBJ_info OBJ_pilotAttributeType,4L
-
-#define LN_favouriteDrink "favouriteDrink"
-#define NID_favouriteDrink 462
-#define OBJ_favouriteDrink OBJ_pilotAttributeType,5L
-
-#define LN_roomNumber "roomNumber"
-#define NID_roomNumber 463
-#define OBJ_roomNumber OBJ_pilotAttributeType,6L
-
-#define SN_photo "photo"
-#define NID_photo 464
-#define OBJ_photo OBJ_pilotAttributeType,7L
-
-#define LN_userClass "userClass"
-#define NID_userClass 465
-#define OBJ_userClass OBJ_pilotAttributeType,8L
-
-#define SN_host "host"
-#define NID_host 466
-#define OBJ_host OBJ_pilotAttributeType,9L
-
-#define SN_manager "manager"
-#define NID_manager 467
-#define OBJ_manager OBJ_pilotAttributeType,10L
-
-#define LN_documentIdentifier "documentIdentifier"
-#define NID_documentIdentifier 468
-#define OBJ_documentIdentifier OBJ_pilotAttributeType,11L
-
-#define LN_documentTitle "documentTitle"
-#define NID_documentTitle 469
-#define OBJ_documentTitle OBJ_pilotAttributeType,12L
-
-#define LN_documentVersion "documentVersion"
-#define NID_documentVersion 470
-#define OBJ_documentVersion OBJ_pilotAttributeType,13L
-
-#define LN_documentAuthor "documentAuthor"
-#define NID_documentAuthor 471
-#define OBJ_documentAuthor OBJ_pilotAttributeType,14L
-
-#define LN_documentLocation "documentLocation"
-#define NID_documentLocation 472
-#define OBJ_documentLocation OBJ_pilotAttributeType,15L
-
-#define LN_homeTelephoneNumber "homeTelephoneNumber"
-#define NID_homeTelephoneNumber 473
-#define OBJ_homeTelephoneNumber OBJ_pilotAttributeType,20L
-
-#define SN_secretary "secretary"
-#define NID_secretary 474
-#define OBJ_secretary OBJ_pilotAttributeType,21L
-
-#define LN_otherMailbox "otherMailbox"
-#define NID_otherMailbox 475
-#define OBJ_otherMailbox OBJ_pilotAttributeType,22L
-
-#define LN_lastModifiedTime "lastModifiedTime"
-#define NID_lastModifiedTime 476
-#define OBJ_lastModifiedTime OBJ_pilotAttributeType,23L
-
-#define LN_lastModifiedBy "lastModifiedBy"
-#define NID_lastModifiedBy 477
-#define OBJ_lastModifiedBy OBJ_pilotAttributeType,24L
-
-#define SN_domainComponent "DC"
-#define LN_domainComponent "domainComponent"
-#define NID_domainComponent 391
-#define OBJ_domainComponent OBJ_pilotAttributeType,25L
-
-#define LN_aRecord "aRecord"
-#define NID_aRecord 478
-#define OBJ_aRecord OBJ_pilotAttributeType,26L
-
-#define LN_pilotAttributeType27 "pilotAttributeType27"
-#define NID_pilotAttributeType27 479
-#define OBJ_pilotAttributeType27 OBJ_pilotAttributeType,27L
-
-#define LN_mXRecord "mXRecord"
-#define NID_mXRecord 480
-#define OBJ_mXRecord OBJ_pilotAttributeType,28L
-
-#define LN_nSRecord "nSRecord"
-#define NID_nSRecord 481
-#define OBJ_nSRecord OBJ_pilotAttributeType,29L
-
-#define LN_sOARecord "sOARecord"
-#define NID_sOARecord 482
-#define OBJ_sOARecord OBJ_pilotAttributeType,30L
-
-#define LN_cNAMERecord "cNAMERecord"
-#define NID_cNAMERecord 483
-#define OBJ_cNAMERecord OBJ_pilotAttributeType,31L
-
-#define LN_associatedDomain "associatedDomain"
-#define NID_associatedDomain 484
-#define OBJ_associatedDomain OBJ_pilotAttributeType,37L
-
-#define LN_associatedName "associatedName"
-#define NID_associatedName 485
-#define OBJ_associatedName OBJ_pilotAttributeType,38L
-
-#define LN_homePostalAddress "homePostalAddress"
-#define NID_homePostalAddress 486
-#define OBJ_homePostalAddress OBJ_pilotAttributeType,39L
-
-#define LN_personalTitle "personalTitle"
-#define NID_personalTitle 487
-#define OBJ_personalTitle OBJ_pilotAttributeType,40L
-
-#define LN_mobileTelephoneNumber "mobileTelephoneNumber"
-#define NID_mobileTelephoneNumber 488
-#define OBJ_mobileTelephoneNumber OBJ_pilotAttributeType,41L
-
-#define LN_pagerTelephoneNumber "pagerTelephoneNumber"
-#define NID_pagerTelephoneNumber 489
-#define OBJ_pagerTelephoneNumber OBJ_pilotAttributeType,42L
-
-#define LN_friendlyCountryName "friendlyCountryName"
-#define NID_friendlyCountryName 490
-#define OBJ_friendlyCountryName OBJ_pilotAttributeType,43L
-
-#define LN_organizationalStatus "organizationalStatus"
-#define NID_organizationalStatus 491
-#define OBJ_organizationalStatus OBJ_pilotAttributeType,45L
-
-#define LN_janetMailbox "janetMailbox"
-#define NID_janetMailbox 492
-#define OBJ_janetMailbox OBJ_pilotAttributeType,46L
-
-#define LN_mailPreferenceOption "mailPreferenceOption"
-#define NID_mailPreferenceOption 493
-#define OBJ_mailPreferenceOption OBJ_pilotAttributeType,47L
-
-#define LN_buildingName "buildingName"
-#define NID_buildingName 494
-#define OBJ_buildingName OBJ_pilotAttributeType,48L
-
-#define LN_dSAQuality "dSAQuality"
-#define NID_dSAQuality 495
-#define OBJ_dSAQuality OBJ_pilotAttributeType,49L
-
-#define LN_singleLevelQuality "singleLevelQuality"
-#define NID_singleLevelQuality 496
-#define OBJ_singleLevelQuality OBJ_pilotAttributeType,50L
-
-#define LN_subtreeMinimumQuality "subtreeMinimumQuality"
-#define NID_subtreeMinimumQuality 497
-#define OBJ_subtreeMinimumQuality OBJ_pilotAttributeType,51L
-
-#define LN_subtreeMaximumQuality "subtreeMaximumQuality"
-#define NID_subtreeMaximumQuality 498
-#define OBJ_subtreeMaximumQuality OBJ_pilotAttributeType,52L
-
-#define LN_personalSignature "personalSignature"
-#define NID_personalSignature 499
-#define OBJ_personalSignature OBJ_pilotAttributeType,53L
-
-#define LN_dITRedirect "dITRedirect"
-#define NID_dITRedirect 500
-#define OBJ_dITRedirect OBJ_pilotAttributeType,54L
-
-#define SN_audio "audio"
-#define NID_audio 501
-#define OBJ_audio OBJ_pilotAttributeType,55L
-
-#define LN_documentPublisher "documentPublisher"
-#define NID_documentPublisher 502
-#define OBJ_documentPublisher OBJ_pilotAttributeType,56L
-
-#define SN_id_set "id-set"
-#define LN_id_set "Secure Electronic Transactions"
-#define NID_id_set 512
-#define OBJ_id_set OBJ_international_organizations,42L
-
-#define SN_set_ctype "set-ctype"
-#define LN_set_ctype "content types"
-#define NID_set_ctype 513
-#define OBJ_set_ctype OBJ_id_set,0L
-
-#define SN_set_msgExt "set-msgExt"
-#define LN_set_msgExt "message extensions"
-#define NID_set_msgExt 514
-#define OBJ_set_msgExt OBJ_id_set,1L
-
-#define SN_set_attr "set-attr"
-#define NID_set_attr 515
-#define OBJ_set_attr OBJ_id_set,3L
-
-#define SN_set_policy "set-policy"
-#define NID_set_policy 516
-#define OBJ_set_policy OBJ_id_set,5L
-
-#define SN_set_certExt "set-certExt"
-#define LN_set_certExt "certificate extensions"
-#define NID_set_certExt 517
-#define OBJ_set_certExt OBJ_id_set,7L
-
-#define SN_set_brand "set-brand"
-#define NID_set_brand 518
-#define OBJ_set_brand OBJ_id_set,8L
-
-#define SN_setct_PANData "setct-PANData"
-#define NID_setct_PANData 519
-#define OBJ_setct_PANData OBJ_set_ctype,0L
-
-#define SN_setct_PANToken "setct-PANToken"
-#define NID_setct_PANToken 520
-#define OBJ_setct_PANToken OBJ_set_ctype,1L
-
-#define SN_setct_PANOnly "setct-PANOnly"
-#define NID_setct_PANOnly 521
-#define OBJ_setct_PANOnly OBJ_set_ctype,2L
-
-#define SN_setct_OIData "setct-OIData"
-#define NID_setct_OIData 522
-#define OBJ_setct_OIData OBJ_set_ctype,3L
-
-#define SN_setct_PI "setct-PI"
-#define NID_setct_PI 523
-#define OBJ_setct_PI OBJ_set_ctype,4L
-
-#define SN_setct_PIData "setct-PIData"
-#define NID_setct_PIData 524
-#define OBJ_setct_PIData OBJ_set_ctype,5L
-
-#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned"
-#define NID_setct_PIDataUnsigned 525
-#define OBJ_setct_PIDataUnsigned OBJ_set_ctype,6L
-
-#define SN_setct_HODInput "setct-HODInput"
-#define NID_setct_HODInput 526
-#define OBJ_setct_HODInput OBJ_set_ctype,7L
-
-#define SN_setct_AuthResBaggage "setct-AuthResBaggage"
-#define NID_setct_AuthResBaggage 527
-#define OBJ_setct_AuthResBaggage OBJ_set_ctype,8L
-
-#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage"
-#define NID_setct_AuthRevReqBaggage 528
-#define OBJ_setct_AuthRevReqBaggage OBJ_set_ctype,9L
-
-#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage"
-#define NID_setct_AuthRevResBaggage 529
-#define OBJ_setct_AuthRevResBaggage OBJ_set_ctype,10L
-
-#define SN_setct_CapTokenSeq "setct-CapTokenSeq"
-#define NID_setct_CapTokenSeq 530
-#define OBJ_setct_CapTokenSeq OBJ_set_ctype,11L
-
-#define SN_setct_PInitResData "setct-PInitResData"
-#define NID_setct_PInitResData 531
-#define OBJ_setct_PInitResData OBJ_set_ctype,12L
-
-#define SN_setct_PI_TBS "setct-PI-TBS"
-#define NID_setct_PI_TBS 532
-#define OBJ_setct_PI_TBS OBJ_set_ctype,13L
-
-#define SN_setct_PResData "setct-PResData"
-#define NID_setct_PResData 533
-#define OBJ_setct_PResData OBJ_set_ctype,14L
-
-#define SN_setct_AuthReqTBS "setct-AuthReqTBS"
-#define NID_setct_AuthReqTBS 534
-#define OBJ_setct_AuthReqTBS OBJ_set_ctype,16L
-
-#define SN_setct_AuthResTBS "setct-AuthResTBS"
-#define NID_setct_AuthResTBS 535
-#define OBJ_setct_AuthResTBS OBJ_set_ctype,17L
-
-#define SN_setct_AuthResTBSX "setct-AuthResTBSX"
-#define NID_setct_AuthResTBSX 536
-#define OBJ_setct_AuthResTBSX OBJ_set_ctype,18L
-
-#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS"
-#define NID_setct_AuthTokenTBS 537
-#define OBJ_setct_AuthTokenTBS OBJ_set_ctype,19L
-
-#define SN_setct_CapTokenData "setct-CapTokenData"
-#define NID_setct_CapTokenData 538
-#define OBJ_setct_CapTokenData OBJ_set_ctype,20L
-
-#define SN_setct_CapTokenTBS "setct-CapTokenTBS"
-#define NID_setct_CapTokenTBS 539
-#define OBJ_setct_CapTokenTBS OBJ_set_ctype,21L
-
-#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg"
-#define NID_setct_AcqCardCodeMsg 540
-#define OBJ_setct_AcqCardCodeMsg OBJ_set_ctype,22L
-
-#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS"
-#define NID_setct_AuthRevReqTBS 541
-#define OBJ_setct_AuthRevReqTBS OBJ_set_ctype,23L
-
-#define SN_setct_AuthRevResData "setct-AuthRevResData"
-#define NID_setct_AuthRevResData 542
-#define OBJ_setct_AuthRevResData OBJ_set_ctype,24L
-
-#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS"
-#define NID_setct_AuthRevResTBS 543
-#define OBJ_setct_AuthRevResTBS OBJ_set_ctype,25L
-
-#define SN_setct_CapReqTBS "setct-CapReqTBS"
-#define NID_setct_CapReqTBS 544
-#define OBJ_setct_CapReqTBS OBJ_set_ctype,26L
-
-#define SN_setct_CapReqTBSX "setct-CapReqTBSX"
-#define NID_setct_CapReqTBSX 545
-#define OBJ_setct_CapReqTBSX OBJ_set_ctype,27L
-
-#define SN_setct_CapResData "setct-CapResData"
-#define NID_setct_CapResData 546
-#define OBJ_setct_CapResData OBJ_set_ctype,28L
-
-#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS"
-#define NID_setct_CapRevReqTBS 547
-#define OBJ_setct_CapRevReqTBS OBJ_set_ctype,29L
-
-#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX"
-#define NID_setct_CapRevReqTBSX 548
-#define OBJ_setct_CapRevReqTBSX OBJ_set_ctype,30L
-
-#define SN_setct_CapRevResData "setct-CapRevResData"
-#define NID_setct_CapRevResData 549
-#define OBJ_setct_CapRevResData OBJ_set_ctype,31L
-
-#define SN_setct_CredReqTBS "setct-CredReqTBS"
-#define NID_setct_CredReqTBS 550
-#define OBJ_setct_CredReqTBS OBJ_set_ctype,32L
-
-#define SN_setct_CredReqTBSX "setct-CredReqTBSX"
-#define NID_setct_CredReqTBSX 551
-#define OBJ_setct_CredReqTBSX OBJ_set_ctype,33L
-
-#define SN_setct_CredResData "setct-CredResData"
-#define NID_setct_CredResData 552
-#define OBJ_setct_CredResData OBJ_set_ctype,34L
-
-#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS"
-#define NID_setct_CredRevReqTBS 553
-#define OBJ_setct_CredRevReqTBS OBJ_set_ctype,35L
-
-#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX"
-#define NID_setct_CredRevReqTBSX 554
-#define OBJ_setct_CredRevReqTBSX OBJ_set_ctype,36L
-
-#define SN_setct_CredRevResData "setct-CredRevResData"
-#define NID_setct_CredRevResData 555
-#define OBJ_setct_CredRevResData OBJ_set_ctype,37L
-
-#define SN_setct_PCertReqData "setct-PCertReqData"
-#define NID_setct_PCertReqData 556
-#define OBJ_setct_PCertReqData OBJ_set_ctype,38L
-
-#define SN_setct_PCertResTBS "setct-PCertResTBS"
-#define NID_setct_PCertResTBS 557
-#define OBJ_setct_PCertResTBS OBJ_set_ctype,39L
-
-#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData"
-#define NID_setct_BatchAdminReqData 558
-#define OBJ_setct_BatchAdminReqData OBJ_set_ctype,40L
-
-#define SN_setct_BatchAdminResData "setct-BatchAdminResData"
-#define NID_setct_BatchAdminResData 559
-#define OBJ_setct_BatchAdminResData OBJ_set_ctype,41L
-
-#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS"
-#define NID_setct_CardCInitResTBS 560
-#define OBJ_setct_CardCInitResTBS OBJ_set_ctype,42L
-
-#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS"
-#define NID_setct_MeAqCInitResTBS 561
-#define OBJ_setct_MeAqCInitResTBS OBJ_set_ctype,43L
-
-#define SN_setct_RegFormResTBS "setct-RegFormResTBS"
-#define NID_setct_RegFormResTBS 562
-#define OBJ_setct_RegFormResTBS OBJ_set_ctype,44L
-
-#define SN_setct_CertReqData "setct-CertReqData"
-#define NID_setct_CertReqData 563
-#define OBJ_setct_CertReqData OBJ_set_ctype,45L
-
-#define SN_setct_CertReqTBS "setct-CertReqTBS"
-#define NID_setct_CertReqTBS 564
-#define OBJ_setct_CertReqTBS OBJ_set_ctype,46L
-
-#define SN_setct_CertResData "setct-CertResData"
-#define NID_setct_CertResData 565
-#define OBJ_setct_CertResData OBJ_set_ctype,47L
-
-#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS"
-#define NID_setct_CertInqReqTBS 566
-#define OBJ_setct_CertInqReqTBS OBJ_set_ctype,48L
-
-#define SN_setct_ErrorTBS "setct-ErrorTBS"
-#define NID_setct_ErrorTBS 567
-#define OBJ_setct_ErrorTBS OBJ_set_ctype,49L
-
-#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE"
-#define NID_setct_PIDualSignedTBE 568
-#define OBJ_setct_PIDualSignedTBE OBJ_set_ctype,50L
-
-#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE"
-#define NID_setct_PIUnsignedTBE 569
-#define OBJ_setct_PIUnsignedTBE OBJ_set_ctype,51L
-
-#define SN_setct_AuthReqTBE "setct-AuthReqTBE"
-#define NID_setct_AuthReqTBE 570
-#define OBJ_setct_AuthReqTBE OBJ_set_ctype,52L
-
-#define SN_setct_AuthResTBE "setct-AuthResTBE"
-#define NID_setct_AuthResTBE 571
-#define OBJ_setct_AuthResTBE OBJ_set_ctype,53L
-
-#define SN_setct_AuthResTBEX "setct-AuthResTBEX"
-#define NID_setct_AuthResTBEX 572
-#define OBJ_setct_AuthResTBEX OBJ_set_ctype,54L
-
-#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE"
-#define NID_setct_AuthTokenTBE 573
-#define OBJ_setct_AuthTokenTBE OBJ_set_ctype,55L
-
-#define SN_setct_CapTokenTBE "setct-CapTokenTBE"
-#define NID_setct_CapTokenTBE 574
-#define OBJ_setct_CapTokenTBE OBJ_set_ctype,56L
-
-#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX"
-#define NID_setct_CapTokenTBEX 575
-#define OBJ_setct_CapTokenTBEX OBJ_set_ctype,57L
-
-#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE"
-#define NID_setct_AcqCardCodeMsgTBE 576
-#define OBJ_setct_AcqCardCodeMsgTBE OBJ_set_ctype,58L
-
-#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE"
-#define NID_setct_AuthRevReqTBE 577
-#define OBJ_setct_AuthRevReqTBE OBJ_set_ctype,59L
-
-#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE"
-#define NID_setct_AuthRevResTBE 578
-#define OBJ_setct_AuthRevResTBE OBJ_set_ctype,60L
-
-#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB"
-#define NID_setct_AuthRevResTBEB 579
-#define OBJ_setct_AuthRevResTBEB OBJ_set_ctype,61L
-
-#define SN_setct_CapReqTBE "setct-CapReqTBE"
-#define NID_setct_CapReqTBE 580
-#define OBJ_setct_CapReqTBE OBJ_set_ctype,62L
-
-#define SN_setct_CapReqTBEX "setct-CapReqTBEX"
-#define NID_setct_CapReqTBEX 581
-#define OBJ_setct_CapReqTBEX OBJ_set_ctype,63L
-
-#define SN_setct_CapResTBE "setct-CapResTBE"
-#define NID_setct_CapResTBE 582
-#define OBJ_setct_CapResTBE OBJ_set_ctype,64L
-
-#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE"
-#define NID_setct_CapRevReqTBE 583
-#define OBJ_setct_CapRevReqTBE OBJ_set_ctype,65L
-
-#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX"
-#define NID_setct_CapRevReqTBEX 584
-#define OBJ_setct_CapRevReqTBEX OBJ_set_ctype,66L
-
-#define SN_setct_CapRevResTBE "setct-CapRevResTBE"
-#define NID_setct_CapRevResTBE 585
-#define OBJ_setct_CapRevResTBE OBJ_set_ctype,67L
-
-#define SN_setct_CredReqTBE "setct-CredReqTBE"
-#define NID_setct_CredReqTBE 586
-#define OBJ_setct_CredReqTBE OBJ_set_ctype,68L
-
-#define SN_setct_CredReqTBEX "setct-CredReqTBEX"
-#define NID_setct_CredReqTBEX 587
-#define OBJ_setct_CredReqTBEX OBJ_set_ctype,69L
-
-#define SN_setct_CredResTBE "setct-CredResTBE"
-#define NID_setct_CredResTBE 588
-#define OBJ_setct_CredResTBE OBJ_set_ctype,70L
-
-#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE"
-#define NID_setct_CredRevReqTBE 589
-#define OBJ_setct_CredRevReqTBE OBJ_set_ctype,71L
-
-#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX"
-#define NID_setct_CredRevReqTBEX 590
-#define OBJ_setct_CredRevReqTBEX OBJ_set_ctype,72L
-
-#define SN_setct_CredRevResTBE "setct-CredRevResTBE"
-#define NID_setct_CredRevResTBE 591
-#define OBJ_setct_CredRevResTBE OBJ_set_ctype,73L
-
-#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE"
-#define NID_setct_BatchAdminReqTBE 592
-#define OBJ_setct_BatchAdminReqTBE OBJ_set_ctype,74L
-
-#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE"
-#define NID_setct_BatchAdminResTBE 593
-#define OBJ_setct_BatchAdminResTBE OBJ_set_ctype,75L
-
-#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE"
-#define NID_setct_RegFormReqTBE 594
-#define OBJ_setct_RegFormReqTBE OBJ_set_ctype,76L
-
-#define SN_setct_CertReqTBE "setct-CertReqTBE"
-#define NID_setct_CertReqTBE 595
-#define OBJ_setct_CertReqTBE OBJ_set_ctype,77L
-
-#define SN_setct_CertReqTBEX "setct-CertReqTBEX"
-#define NID_setct_CertReqTBEX 596
-#define OBJ_setct_CertReqTBEX OBJ_set_ctype,78L
-
-#define SN_setct_CertResTBE "setct-CertResTBE"
-#define NID_setct_CertResTBE 597
-#define OBJ_setct_CertResTBE OBJ_set_ctype,79L
-
-#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS"
-#define NID_setct_CRLNotificationTBS 598
-#define OBJ_setct_CRLNotificationTBS OBJ_set_ctype,80L
-
-#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS"
-#define NID_setct_CRLNotificationResTBS 599
-#define OBJ_setct_CRLNotificationResTBS OBJ_set_ctype,81L
-
-#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS"
-#define NID_setct_BCIDistributionTBS 600
-#define OBJ_setct_BCIDistributionTBS OBJ_set_ctype,82L
-
-#define SN_setext_genCrypt "setext-genCrypt"
-#define LN_setext_genCrypt "generic cryptogram"
-#define NID_setext_genCrypt 601
-#define OBJ_setext_genCrypt OBJ_set_msgExt,1L
-
-#define SN_setext_miAuth "setext-miAuth"
-#define LN_setext_miAuth "merchant initiated auth"
-#define NID_setext_miAuth 602
-#define OBJ_setext_miAuth OBJ_set_msgExt,3L
-
-#define SN_setext_pinSecure "setext-pinSecure"
-#define NID_setext_pinSecure 603
-#define OBJ_setext_pinSecure OBJ_set_msgExt,4L
-
-#define SN_setext_pinAny "setext-pinAny"
-#define NID_setext_pinAny 604
-#define OBJ_setext_pinAny OBJ_set_msgExt,5L
-
-#define SN_setext_track2 "setext-track2"
-#define NID_setext_track2 605
-#define OBJ_setext_track2 OBJ_set_msgExt,7L
-
-#define SN_setext_cv "setext-cv"
-#define LN_setext_cv "additional verification"
-#define NID_setext_cv 606
-#define OBJ_setext_cv OBJ_set_msgExt,8L
-
-#define SN_set_policy_root "set-policy-root"
-#define NID_set_policy_root 607
-#define OBJ_set_policy_root OBJ_set_policy,0L
-
-#define SN_setCext_hashedRoot "setCext-hashedRoot"
-#define NID_setCext_hashedRoot 608
-#define OBJ_setCext_hashedRoot OBJ_set_certExt,0L
-
-#define SN_setCext_certType "setCext-certType"
-#define NID_setCext_certType 609
-#define OBJ_setCext_certType OBJ_set_certExt,1L
-
-#define SN_setCext_merchData "setCext-merchData"
-#define NID_setCext_merchData 610
-#define OBJ_setCext_merchData OBJ_set_certExt,2L
-
-#define SN_setCext_cCertRequired "setCext-cCertRequired"
-#define NID_setCext_cCertRequired 611
-#define OBJ_setCext_cCertRequired OBJ_set_certExt,3L
-
-#define SN_setCext_tunneling "setCext-tunneling"
-#define NID_setCext_tunneling 612
-#define OBJ_setCext_tunneling OBJ_set_certExt,4L
-
-#define SN_setCext_setExt "setCext-setExt"
-#define NID_setCext_setExt 613
-#define OBJ_setCext_setExt OBJ_set_certExt,5L
-
-#define SN_setCext_setQualf "setCext-setQualf"
-#define NID_setCext_setQualf 614
-#define OBJ_setCext_setQualf OBJ_set_certExt,6L
-
-#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities"
-#define NID_setCext_PGWYcapabilities 615
-#define OBJ_setCext_PGWYcapabilities OBJ_set_certExt,7L
-
-#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier"
-#define NID_setCext_TokenIdentifier 616
-#define OBJ_setCext_TokenIdentifier OBJ_set_certExt,8L
-
-#define SN_setCext_Track2Data "setCext-Track2Data"
-#define NID_setCext_Track2Data 617
-#define OBJ_setCext_Track2Data OBJ_set_certExt,9L
-
-#define SN_setCext_TokenType "setCext-TokenType"
-#define NID_setCext_TokenType 618
-#define OBJ_setCext_TokenType OBJ_set_certExt,10L
-
-#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities"
-#define NID_setCext_IssuerCapabilities 619
-#define OBJ_setCext_IssuerCapabilities OBJ_set_certExt,11L
-
-#define SN_setAttr_Cert "setAttr-Cert"
-#define NID_setAttr_Cert 620
-#define OBJ_setAttr_Cert OBJ_set_attr,0L
-
-#define SN_setAttr_PGWYcap "setAttr-PGWYcap"
-#define LN_setAttr_PGWYcap "payment gateway capabilities"
-#define NID_setAttr_PGWYcap 621
-#define OBJ_setAttr_PGWYcap OBJ_set_attr,1L
-
-#define SN_setAttr_TokenType "setAttr-TokenType"
-#define NID_setAttr_TokenType 622
-#define OBJ_setAttr_TokenType OBJ_set_attr,2L
-
-#define SN_setAttr_IssCap "setAttr-IssCap"
-#define LN_setAttr_IssCap "issuer capabilities"
-#define NID_setAttr_IssCap 623
-#define OBJ_setAttr_IssCap OBJ_set_attr,3L
-
-#define SN_set_rootKeyThumb "set-rootKeyThumb"
-#define NID_set_rootKeyThumb 624
-#define OBJ_set_rootKeyThumb OBJ_setAttr_Cert,0L
-
-#define SN_set_addPolicy "set-addPolicy"
-#define NID_set_addPolicy 625
-#define OBJ_set_addPolicy OBJ_setAttr_Cert,1L
-
-#define SN_setAttr_Token_EMV "setAttr-Token-EMV"
-#define NID_setAttr_Token_EMV 626
-#define OBJ_setAttr_Token_EMV OBJ_setAttr_TokenType,1L
-
-#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime"
-#define NID_setAttr_Token_B0Prime 627
-#define OBJ_setAttr_Token_B0Prime OBJ_setAttr_TokenType,2L
-
-#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM"
-#define NID_setAttr_IssCap_CVM 628
-#define OBJ_setAttr_IssCap_CVM OBJ_setAttr_IssCap,3L
-
-#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2"
-#define NID_setAttr_IssCap_T2 629
-#define OBJ_setAttr_IssCap_T2 OBJ_setAttr_IssCap,4L
-
-#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig"
-#define NID_setAttr_IssCap_Sig 630
-#define OBJ_setAttr_IssCap_Sig OBJ_setAttr_IssCap,5L
-
-#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm"
-#define LN_setAttr_GenCryptgrm "generate cryptogram"
-#define NID_setAttr_GenCryptgrm 631
-#define OBJ_setAttr_GenCryptgrm OBJ_setAttr_IssCap_CVM,1L
-
-#define SN_setAttr_T2Enc "setAttr-T2Enc"
-#define LN_setAttr_T2Enc "encrypted track 2"
-#define NID_setAttr_T2Enc 632
-#define OBJ_setAttr_T2Enc OBJ_setAttr_IssCap_T2,1L
-
-#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt"
-#define LN_setAttr_T2cleartxt "cleartext track 2"
-#define NID_setAttr_T2cleartxt 633
-#define OBJ_setAttr_T2cleartxt OBJ_setAttr_IssCap_T2,2L
-
-#define SN_setAttr_TokICCsig "setAttr-TokICCsig"
-#define LN_setAttr_TokICCsig "ICC or token signature"
-#define NID_setAttr_TokICCsig 634
-#define OBJ_setAttr_TokICCsig OBJ_setAttr_IssCap_Sig,1L
-
-#define SN_setAttr_SecDevSig "setAttr-SecDevSig"
-#define LN_setAttr_SecDevSig "secure device signature"
-#define NID_setAttr_SecDevSig 635
-#define OBJ_setAttr_SecDevSig OBJ_setAttr_IssCap_Sig,2L
-
-#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA"
-#define NID_set_brand_IATA_ATA 636
-#define OBJ_set_brand_IATA_ATA OBJ_set_brand,1L
-
-#define SN_set_brand_Diners "set-brand-Diners"
-#define NID_set_brand_Diners 637
-#define OBJ_set_brand_Diners OBJ_set_brand,30L
-
-#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress"
-#define NID_set_brand_AmericanExpress 638
-#define OBJ_set_brand_AmericanExpress OBJ_set_brand,34L
-
-#define SN_set_brand_JCB "set-brand-JCB"
-#define NID_set_brand_JCB 639
-#define OBJ_set_brand_JCB OBJ_set_brand,35L
-
-#define SN_set_brand_Visa "set-brand-Visa"
-#define NID_set_brand_Visa 640
-#define OBJ_set_brand_Visa OBJ_set_brand,4L
-
-#define SN_set_brand_MasterCard "set-brand-MasterCard"
-#define NID_set_brand_MasterCard 641
-#define OBJ_set_brand_MasterCard OBJ_set_brand,5L
-
-#define SN_set_brand_Novus "set-brand-Novus"
-#define NID_set_brand_Novus 642
-#define OBJ_set_brand_Novus OBJ_set_brand,6011L
-
-#define SN_des_cdmf "DES-CDMF"
-#define LN_des_cdmf "des-cdmf"
-#define NID_des_cdmf 643
-#define OBJ_des_cdmf OBJ_rsadsi,3L,10L
-
-#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET"
-#define NID_rsaOAEPEncryptionSET 644
-#define OBJ_rsaOAEPEncryptionSET OBJ_rsadsi,1L,1L,6L
-
-#define SN_ipsec3 "Oakley-EC2N-3"
-#define LN_ipsec3 "ipsec3"
-#define NID_ipsec3 749
-
-#define SN_ipsec4 "Oakley-EC2N-4"
-#define LN_ipsec4 "ipsec4"
-#define NID_ipsec4 750
-
-#define SN_whirlpool "whirlpool"
-#define NID_whirlpool 804
-#define OBJ_whirlpool OBJ_iso,0L,10118L,3L,0L,55L
-
-#define SN_cryptopro "cryptopro"
-#define NID_cryptopro 805
-#define OBJ_cryptopro OBJ_member_body,643L,2L,2L
-
-#define SN_cryptocom "cryptocom"
-#define NID_cryptocom 806
-#define OBJ_cryptocom OBJ_member_body,643L,2L,9L
-
-#define SN_id_GostR3411_94_with_GostR3410_2001 "id-GostR3411-94-with-GostR3410-2001"
-#define LN_id_GostR3411_94_with_GostR3410_2001 "GOST R 34.11-94 with GOST R 34.10-2001"
-#define NID_id_GostR3411_94_with_GostR3410_2001 807
-#define OBJ_id_GostR3411_94_with_GostR3410_2001 OBJ_cryptopro,3L
-
-#define SN_id_GostR3411_94_with_GostR3410_94 "id-GostR3411-94-with-GostR3410-94"
-#define LN_id_GostR3411_94_with_GostR3410_94 "GOST R 34.11-94 with GOST R 34.10-94"
-#define NID_id_GostR3411_94_with_GostR3410_94 808
-#define OBJ_id_GostR3411_94_with_GostR3410_94 OBJ_cryptopro,4L
-
-#define SN_id_GostR3411_94 "md_gost94"
-#define LN_id_GostR3411_94 "GOST R 34.11-94"
-#define NID_id_GostR3411_94 809
-#define OBJ_id_GostR3411_94 OBJ_cryptopro,9L
-
-#define SN_id_HMACGostR3411_94 "id-HMACGostR3411-94"
-#define LN_id_HMACGostR3411_94 "HMAC GOST 34.11-94"
-#define NID_id_HMACGostR3411_94 810
-#define OBJ_id_HMACGostR3411_94 OBJ_cryptopro,10L
-
-#define SN_id_GostR3410_2001 "gost2001"
-#define LN_id_GostR3410_2001 "GOST R 34.10-2001"
-#define NID_id_GostR3410_2001 811
-#define OBJ_id_GostR3410_2001 OBJ_cryptopro,19L
-
-#define SN_id_GostR3410_94 "gost94"
-#define LN_id_GostR3410_94 "GOST R 34.10-94"
-#define NID_id_GostR3410_94 812
-#define OBJ_id_GostR3410_94 OBJ_cryptopro,20L
-
-#define SN_id_Gost28147_89 "gost89"
-#define LN_id_Gost28147_89 "GOST 28147-89"
-#define NID_id_Gost28147_89 813
-#define OBJ_id_Gost28147_89 OBJ_cryptopro,21L
-
-#define SN_gost89_cnt "gost89-cnt"
-#define NID_gost89_cnt 814
-
-#define SN_id_Gost28147_89_MAC "gost-mac"
-#define LN_id_Gost28147_89_MAC "GOST 28147-89 MAC"
-#define NID_id_Gost28147_89_MAC 815
-#define OBJ_id_Gost28147_89_MAC OBJ_cryptopro,22L
-
-#define SN_id_GostR3411_94_prf "prf-gostr3411-94"
-#define LN_id_GostR3411_94_prf "GOST R 34.11-94 PRF"
-#define NID_id_GostR3411_94_prf 816
-#define OBJ_id_GostR3411_94_prf OBJ_cryptopro,23L
-
-#define SN_id_GostR3410_2001DH "id-GostR3410-2001DH"
-#define LN_id_GostR3410_2001DH "GOST R 34.10-2001 DH"
-#define NID_id_GostR3410_2001DH 817
-#define OBJ_id_GostR3410_2001DH OBJ_cryptopro,98L
-
-#define SN_id_GostR3410_94DH "id-GostR3410-94DH"
-#define LN_id_GostR3410_94DH "GOST R 34.10-94 DH"
-#define NID_id_GostR3410_94DH 818
-#define OBJ_id_GostR3410_94DH OBJ_cryptopro,99L
-
-#define SN_id_Gost28147_89_CryptoPro_KeyMeshing "id-Gost28147-89-CryptoPro-KeyMeshing"
-#define NID_id_Gost28147_89_CryptoPro_KeyMeshing 819
-#define OBJ_id_Gost28147_89_CryptoPro_KeyMeshing OBJ_cryptopro,14L,1L
-
-#define SN_id_Gost28147_89_None_KeyMeshing "id-Gost28147-89-None-KeyMeshing"
-#define NID_id_Gost28147_89_None_KeyMeshing 820
-#define OBJ_id_Gost28147_89_None_KeyMeshing OBJ_cryptopro,14L,0L
-
-#define SN_id_GostR3411_94_TestParamSet "id-GostR3411-94-TestParamSet"
-#define NID_id_GostR3411_94_TestParamSet 821
-#define OBJ_id_GostR3411_94_TestParamSet OBJ_cryptopro,30L,0L
-
-#define SN_id_GostR3411_94_CryptoProParamSet "id-GostR3411-94-CryptoProParamSet"
-#define NID_id_GostR3411_94_CryptoProParamSet 822
-#define OBJ_id_GostR3411_94_CryptoProParamSet OBJ_cryptopro,30L,1L
-
-#define SN_id_Gost28147_89_TestParamSet "id-Gost28147-89-TestParamSet"
-#define NID_id_Gost28147_89_TestParamSet 823
-#define OBJ_id_Gost28147_89_TestParamSet OBJ_cryptopro,31L,0L
-
-#define SN_id_Gost28147_89_CryptoPro_A_ParamSet "id-Gost28147-89-CryptoPro-A-ParamSet"
-#define NID_id_Gost28147_89_CryptoPro_A_ParamSet 824
-#define OBJ_id_Gost28147_89_CryptoPro_A_ParamSet OBJ_cryptopro,31L,1L
-
-#define SN_id_Gost28147_89_CryptoPro_B_ParamSet "id-Gost28147-89-CryptoPro-B-ParamSet"
-#define NID_id_Gost28147_89_CryptoPro_B_ParamSet 825
-#define OBJ_id_Gost28147_89_CryptoPro_B_ParamSet OBJ_cryptopro,31L,2L
-
-#define SN_id_Gost28147_89_CryptoPro_C_ParamSet "id-Gost28147-89-CryptoPro-C-ParamSet"
-#define NID_id_Gost28147_89_CryptoPro_C_ParamSet 826
-#define OBJ_id_Gost28147_89_CryptoPro_C_ParamSet OBJ_cryptopro,31L,3L
-
-#define SN_id_Gost28147_89_CryptoPro_D_ParamSet "id-Gost28147-89-CryptoPro-D-ParamSet"
-#define NID_id_Gost28147_89_CryptoPro_D_ParamSet 827
-#define OBJ_id_Gost28147_89_CryptoPro_D_ParamSet OBJ_cryptopro,31L,4L
-
-#define SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet"
-#define NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 828
-#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet OBJ_cryptopro,31L,5L
-
-#define SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet"
-#define NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 829
-#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet OBJ_cryptopro,31L,6L
-
-#define SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet "id-Gost28147-89-CryptoPro-RIC-1-ParamSet"
-#define NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 830
-#define OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet OBJ_cryptopro,31L,7L
-
-#define SN_id_GostR3410_94_TestParamSet "id-GostR3410-94-TestParamSet"
-#define NID_id_GostR3410_94_TestParamSet 831
-#define OBJ_id_GostR3410_94_TestParamSet OBJ_cryptopro,32L,0L
-
-#define SN_id_GostR3410_94_CryptoPro_A_ParamSet "id-GostR3410-94-CryptoPro-A-ParamSet"
-#define NID_id_GostR3410_94_CryptoPro_A_ParamSet 832
-#define OBJ_id_GostR3410_94_CryptoPro_A_ParamSet OBJ_cryptopro,32L,2L
-
-#define SN_id_GostR3410_94_CryptoPro_B_ParamSet "id-GostR3410-94-CryptoPro-B-ParamSet"
-#define NID_id_GostR3410_94_CryptoPro_B_ParamSet 833
-#define OBJ_id_GostR3410_94_CryptoPro_B_ParamSet OBJ_cryptopro,32L,3L
-
-#define SN_id_GostR3410_94_CryptoPro_C_ParamSet "id-GostR3410-94-CryptoPro-C-ParamSet"
-#define NID_id_GostR3410_94_CryptoPro_C_ParamSet 834
-#define OBJ_id_GostR3410_94_CryptoPro_C_ParamSet OBJ_cryptopro,32L,4L
-
-#define SN_id_GostR3410_94_CryptoPro_D_ParamSet "id-GostR3410-94-CryptoPro-D-ParamSet"
-#define NID_id_GostR3410_94_CryptoPro_D_ParamSet 835
-#define OBJ_id_GostR3410_94_CryptoPro_D_ParamSet OBJ_cryptopro,32L,5L
-
-#define SN_id_GostR3410_94_CryptoPro_XchA_ParamSet "id-GostR3410-94-CryptoPro-XchA-ParamSet"
-#define NID_id_GostR3410_94_CryptoPro_XchA_ParamSet 836
-#define OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet OBJ_cryptopro,33L,1L
-
-#define SN_id_GostR3410_94_CryptoPro_XchB_ParamSet "id-GostR3410-94-CryptoPro-XchB-ParamSet"
-#define NID_id_GostR3410_94_CryptoPro_XchB_ParamSet 837
-#define OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet OBJ_cryptopro,33L,2L
-
-#define SN_id_GostR3410_94_CryptoPro_XchC_ParamSet "id-GostR3410-94-CryptoPro-XchC-ParamSet"
-#define NID_id_GostR3410_94_CryptoPro_XchC_ParamSet 838
-#define OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet OBJ_cryptopro,33L,3L
-
-#define SN_id_GostR3410_2001_TestParamSet "id-GostR3410-2001-TestParamSet"
-#define NID_id_GostR3410_2001_TestParamSet 839
-#define OBJ_id_GostR3410_2001_TestParamSet OBJ_cryptopro,35L,0L
-
-#define SN_id_GostR3410_2001_CryptoPro_A_ParamSet "id-GostR3410-2001-CryptoPro-A-ParamSet"
-#define NID_id_GostR3410_2001_CryptoPro_A_ParamSet 840
-#define OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet OBJ_cryptopro,35L,1L
-
-#define SN_id_GostR3410_2001_CryptoPro_B_ParamSet "id-GostR3410-2001-CryptoPro-B-ParamSet"
-#define NID_id_GostR3410_2001_CryptoPro_B_ParamSet 841
-#define OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet OBJ_cryptopro,35L,2L
-
-#define SN_id_GostR3410_2001_CryptoPro_C_ParamSet "id-GostR3410-2001-CryptoPro-C-ParamSet"
-#define NID_id_GostR3410_2001_CryptoPro_C_ParamSet 842
-#define OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet OBJ_cryptopro,35L,3L
-
-#define SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet "id-GostR3410-2001-CryptoPro-XchA-ParamSet"
-#define NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet 843
-#define OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet OBJ_cryptopro,36L,0L
-
-#define SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet "id-GostR3410-2001-CryptoPro-XchB-ParamSet"
-#define NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet 844
-#define OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet OBJ_cryptopro,36L,1L
-
-#define SN_id_GostR3410_94_a "id-GostR3410-94-a"
-#define NID_id_GostR3410_94_a 845
-#define OBJ_id_GostR3410_94_a OBJ_id_GostR3410_94,1L
-
-#define SN_id_GostR3410_94_aBis "id-GostR3410-94-aBis"
-#define NID_id_GostR3410_94_aBis 846
-#define OBJ_id_GostR3410_94_aBis OBJ_id_GostR3410_94,2L
-
-#define SN_id_GostR3410_94_b "id-GostR3410-94-b"
-#define NID_id_GostR3410_94_b 847
-#define OBJ_id_GostR3410_94_b OBJ_id_GostR3410_94,3L
-
-#define SN_id_GostR3410_94_bBis "id-GostR3410-94-bBis"
-#define NID_id_GostR3410_94_bBis 848
-#define OBJ_id_GostR3410_94_bBis OBJ_id_GostR3410_94,4L
-
-#define SN_id_Gost28147_89_cc "id-Gost28147-89-cc"
-#define LN_id_Gost28147_89_cc "GOST 28147-89 Cryptocom ParamSet"
-#define NID_id_Gost28147_89_cc 849
-#define OBJ_id_Gost28147_89_cc OBJ_cryptocom,1L,6L,1L
-
-#define SN_id_GostR3410_94_cc "gost94cc"
-#define LN_id_GostR3410_94_cc "GOST 34.10-94 Cryptocom"
-#define NID_id_GostR3410_94_cc 850
-#define OBJ_id_GostR3410_94_cc OBJ_cryptocom,1L,5L,3L
-
-#define SN_id_GostR3410_2001_cc "gost2001cc"
-#define LN_id_GostR3410_2001_cc "GOST 34.10-2001 Cryptocom"
-#define NID_id_GostR3410_2001_cc 851
-#define OBJ_id_GostR3410_2001_cc OBJ_cryptocom,1L,5L,4L
-
-#define SN_id_GostR3411_94_with_GostR3410_94_cc "id-GostR3411-94-with-GostR3410-94-cc"
-#define LN_id_GostR3411_94_with_GostR3410_94_cc "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom"
-#define NID_id_GostR3411_94_with_GostR3410_94_cc 852
-#define OBJ_id_GostR3411_94_with_GostR3410_94_cc OBJ_cryptocom,1L,3L,3L
-
-#define SN_id_GostR3411_94_with_GostR3410_2001_cc "id-GostR3411-94-with-GostR3410-2001-cc"
-#define LN_id_GostR3411_94_with_GostR3410_2001_cc "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom"
-#define NID_id_GostR3411_94_with_GostR3410_2001_cc 853
-#define OBJ_id_GostR3411_94_with_GostR3410_2001_cc OBJ_cryptocom,1L,3L,4L
-
-#define SN_id_GostR3410_2001_ParamSet_cc "id-GostR3410-2001-ParamSet-cc"
-#define LN_id_GostR3410_2001_ParamSet_cc "GOST R 3410-2001 Parameter Set Cryptocom"
-#define NID_id_GostR3410_2001_ParamSet_cc 854
-#define OBJ_id_GostR3410_2001_ParamSet_cc OBJ_cryptocom,1L,8L,1L
-
-#define SN_camellia_128_cbc "CAMELLIA-128-CBC"
-#define LN_camellia_128_cbc "camellia-128-cbc"
-#define NID_camellia_128_cbc 751
-#define OBJ_camellia_128_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,2L
-
-#define SN_camellia_192_cbc "CAMELLIA-192-CBC"
-#define LN_camellia_192_cbc "camellia-192-cbc"
-#define NID_camellia_192_cbc 752
-#define OBJ_camellia_192_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,3L
-
-#define SN_camellia_256_cbc "CAMELLIA-256-CBC"
-#define LN_camellia_256_cbc "camellia-256-cbc"
-#define NID_camellia_256_cbc 753
-#define OBJ_camellia_256_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,4L
-
-#define SN_id_camellia128_wrap "id-camellia128-wrap"
-#define NID_id_camellia128_wrap 907
-#define OBJ_id_camellia128_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,2L
-
-#define SN_id_camellia192_wrap "id-camellia192-wrap"
-#define NID_id_camellia192_wrap 908
-#define OBJ_id_camellia192_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,3L
-
-#define SN_id_camellia256_wrap "id-camellia256-wrap"
-#define NID_id_camellia256_wrap 909
-#define OBJ_id_camellia256_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,4L
-
-#define OBJ_ntt_ds 0L,3L,4401L,5L
-
-#define OBJ_camellia OBJ_ntt_ds,3L,1L,9L
-
-#define SN_camellia_128_ecb "CAMELLIA-128-ECB"
-#define LN_camellia_128_ecb "camellia-128-ecb"
-#define NID_camellia_128_ecb 754
-#define OBJ_camellia_128_ecb OBJ_camellia,1L
-
-#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB"
-#define LN_camellia_128_ofb128 "camellia-128-ofb"
-#define NID_camellia_128_ofb128 766
-#define OBJ_camellia_128_ofb128 OBJ_camellia,3L
-
-#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB"
-#define LN_camellia_128_cfb128 "camellia-128-cfb"
-#define NID_camellia_128_cfb128 757
-#define OBJ_camellia_128_cfb128 OBJ_camellia,4L
-
-#define SN_camellia_192_ecb "CAMELLIA-192-ECB"
-#define LN_camellia_192_ecb "camellia-192-ecb"
-#define NID_camellia_192_ecb 755
-#define OBJ_camellia_192_ecb OBJ_camellia,21L
-
-#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB"
-#define LN_camellia_192_ofb128 "camellia-192-ofb"
-#define NID_camellia_192_ofb128 767
-#define OBJ_camellia_192_ofb128 OBJ_camellia,23L
-
-#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB"
-#define LN_camellia_192_cfb128 "camellia-192-cfb"
-#define NID_camellia_192_cfb128 758
-#define OBJ_camellia_192_cfb128 OBJ_camellia,24L
-
-#define SN_camellia_256_ecb "CAMELLIA-256-ECB"
-#define LN_camellia_256_ecb "camellia-256-ecb"
-#define NID_camellia_256_ecb 756
-#define OBJ_camellia_256_ecb OBJ_camellia,41L
-
-#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB"
-#define LN_camellia_256_ofb128 "camellia-256-ofb"
-#define NID_camellia_256_ofb128 768
-#define OBJ_camellia_256_ofb128 OBJ_camellia,43L
-
-#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB"
-#define LN_camellia_256_cfb128 "camellia-256-cfb"
-#define NID_camellia_256_cfb128 759
-#define OBJ_camellia_256_cfb128 OBJ_camellia,44L
-
-#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1"
-#define LN_camellia_128_cfb1 "camellia-128-cfb1"
-#define NID_camellia_128_cfb1 760
-
-#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1"
-#define LN_camellia_192_cfb1 "camellia-192-cfb1"
-#define NID_camellia_192_cfb1 761
-
-#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1"
-#define LN_camellia_256_cfb1 "camellia-256-cfb1"
-#define NID_camellia_256_cfb1 762
-
-#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8"
-#define LN_camellia_128_cfb8 "camellia-128-cfb8"
-#define NID_camellia_128_cfb8 763
-
-#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8"
-#define LN_camellia_192_cfb8 "camellia-192-cfb8"
-#define NID_camellia_192_cfb8 764
-
-#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8"
-#define LN_camellia_256_cfb8 "camellia-256-cfb8"
-#define NID_camellia_256_cfb8 765
-
-#define SN_kisa "KISA"
-#define LN_kisa "kisa"
-#define NID_kisa 773
-#define OBJ_kisa OBJ_member_body,410L,200004L
-
-#define SN_seed_ecb "SEED-ECB"
-#define LN_seed_ecb "seed-ecb"
-#define NID_seed_ecb 776
-#define OBJ_seed_ecb OBJ_kisa,1L,3L
-
-#define SN_seed_cbc "SEED-CBC"
-#define LN_seed_cbc "seed-cbc"
-#define NID_seed_cbc 777
-#define OBJ_seed_cbc OBJ_kisa,1L,4L
-
-#define SN_seed_cfb128 "SEED-CFB"
-#define LN_seed_cfb128 "seed-cfb"
-#define NID_seed_cfb128 779
-#define OBJ_seed_cfb128 OBJ_kisa,1L,5L
-
-#define SN_seed_ofb128 "SEED-OFB"
-#define LN_seed_ofb128 "seed-ofb"
-#define NID_seed_ofb128 778
-#define OBJ_seed_ofb128 OBJ_kisa,1L,6L
-
-#define SN_hmac "HMAC"
-#define LN_hmac "hmac"
-#define NID_hmac 855
-
-#define SN_cmac "CMAC"
-#define LN_cmac "cmac"
-#define NID_cmac 894
-
-#define SN_rc4_hmac_md5 "RC4-HMAC-MD5"
-#define LN_rc4_hmac_md5 "rc4-hmac-md5"
-#define NID_rc4_hmac_md5 915
-
-#define SN_aes_128_cbc_hmac_sha1 "AES-128-CBC-HMAC-SHA1"
-#define LN_aes_128_cbc_hmac_sha1 "aes-128-cbc-hmac-sha1"
-#define NID_aes_128_cbc_hmac_sha1 916
-
-#define SN_aes_192_cbc_hmac_sha1 "AES-192-CBC-HMAC-SHA1"
-#define LN_aes_192_cbc_hmac_sha1 "aes-192-cbc-hmac-sha1"
-#define NID_aes_192_cbc_hmac_sha1 917
-
-#define SN_aes_256_cbc_hmac_sha1 "AES-256-CBC-HMAC-SHA1"
-#define LN_aes_256_cbc_hmac_sha1 "aes-256-cbc-hmac-sha1"
-#define NID_aes_256_cbc_hmac_sha1 918
-
diff --git a/drivers/builtin_openssl/openssl/objects.h b/drivers/builtin_openssl/openssl/objects.h
deleted file mode 100644
index bd0ee52feb..0000000000
--- a/drivers/builtin_openssl/openssl/objects.h
+++ /dev/null
@@ -1,1138 +0,0 @@
-/* crypto/objects/objects.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_OBJECTS_H
-#define HEADER_OBJECTS_H
-
-#define USE_OBJ_MAC
-
-#ifdef USE_OBJ_MAC
-#include <openssl/obj_mac.h>
-#else
-#define SN_undef "UNDEF"
-#define LN_undef "undefined"
-#define NID_undef 0
-#define OBJ_undef 0L
-
-#define SN_Algorithm "Algorithm"
-#define LN_algorithm "algorithm"
-#define NID_algorithm 38
-#define OBJ_algorithm 1L,3L,14L,3L,2L
-
-#define LN_rsadsi "rsadsi"
-#define NID_rsadsi 1
-#define OBJ_rsadsi 1L,2L,840L,113549L
-
-#define LN_pkcs "pkcs"
-#define NID_pkcs 2
-#define OBJ_pkcs OBJ_rsadsi,1L
-
-#define SN_md2 "MD2"
-#define LN_md2 "md2"
-#define NID_md2 3
-#define OBJ_md2 OBJ_rsadsi,2L,2L
-
-#define SN_md5 "MD5"
-#define LN_md5 "md5"
-#define NID_md5 4
-#define OBJ_md5 OBJ_rsadsi,2L,5L
-
-#define SN_rc4 "RC4"
-#define LN_rc4 "rc4"
-#define NID_rc4 5
-#define OBJ_rc4 OBJ_rsadsi,3L,4L
-
-#define LN_rsaEncryption "rsaEncryption"
-#define NID_rsaEncryption 6
-#define OBJ_rsaEncryption OBJ_pkcs,1L,1L
-
-#define SN_md2WithRSAEncryption "RSA-MD2"
-#define LN_md2WithRSAEncryption "md2WithRSAEncryption"
-#define NID_md2WithRSAEncryption 7
-#define OBJ_md2WithRSAEncryption OBJ_pkcs,1L,2L
-
-#define SN_md5WithRSAEncryption "RSA-MD5"
-#define LN_md5WithRSAEncryption "md5WithRSAEncryption"
-#define NID_md5WithRSAEncryption 8
-#define OBJ_md5WithRSAEncryption OBJ_pkcs,1L,4L
-
-#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES"
-#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC"
-#define NID_pbeWithMD2AndDES_CBC 9
-#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs,5L,1L
-
-#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES"
-#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC"
-#define NID_pbeWithMD5AndDES_CBC 10
-#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs,5L,3L
-
-#define LN_X500 "X500"
-#define NID_X500 11
-#define OBJ_X500 2L,5L
-
-#define LN_X509 "X509"
-#define NID_X509 12
-#define OBJ_X509 OBJ_X500,4L
-
-#define SN_commonName "CN"
-#define LN_commonName "commonName"
-#define NID_commonName 13
-#define OBJ_commonName OBJ_X509,3L
-
-#define SN_countryName "C"
-#define LN_countryName "countryName"
-#define NID_countryName 14
-#define OBJ_countryName OBJ_X509,6L
-
-#define SN_localityName "L"
-#define LN_localityName "localityName"
-#define NID_localityName 15
-#define OBJ_localityName OBJ_X509,7L
-
-/* Postal Address? PA */
-
-/* should be "ST" (rfc1327) but MS uses 'S' */
-#define SN_stateOrProvinceName "ST"
-#define LN_stateOrProvinceName "stateOrProvinceName"
-#define NID_stateOrProvinceName 16
-#define OBJ_stateOrProvinceName OBJ_X509,8L
-
-#define SN_organizationName "O"
-#define LN_organizationName "organizationName"
-#define NID_organizationName 17
-#define OBJ_organizationName OBJ_X509,10L
-
-#define SN_organizationalUnitName "OU"
-#define LN_organizationalUnitName "organizationalUnitName"
-#define NID_organizationalUnitName 18
-#define OBJ_organizationalUnitName OBJ_X509,11L
-
-#define SN_rsa "RSA"
-#define LN_rsa "rsa"
-#define NID_rsa 19
-#define OBJ_rsa OBJ_X500,8L,1L,1L
-
-#define LN_pkcs7 "pkcs7"
-#define NID_pkcs7 20
-#define OBJ_pkcs7 OBJ_pkcs,7L
-
-#define LN_pkcs7_data "pkcs7-data"
-#define NID_pkcs7_data 21
-#define OBJ_pkcs7_data OBJ_pkcs7,1L
-
-#define LN_pkcs7_signed "pkcs7-signedData"
-#define NID_pkcs7_signed 22
-#define OBJ_pkcs7_signed OBJ_pkcs7,2L
-
-#define LN_pkcs7_enveloped "pkcs7-envelopedData"
-#define NID_pkcs7_enveloped 23
-#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L
-
-#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData"
-#define NID_pkcs7_signedAndEnveloped 24
-#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L
-
-#define LN_pkcs7_digest "pkcs7-digestData"
-#define NID_pkcs7_digest 25
-#define OBJ_pkcs7_digest OBJ_pkcs7,5L
-
-#define LN_pkcs7_encrypted "pkcs7-encryptedData"
-#define NID_pkcs7_encrypted 26
-#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L
-
-#define LN_pkcs3 "pkcs3"
-#define NID_pkcs3 27
-#define OBJ_pkcs3 OBJ_pkcs,3L
-
-#define LN_dhKeyAgreement "dhKeyAgreement"
-#define NID_dhKeyAgreement 28
-#define OBJ_dhKeyAgreement OBJ_pkcs3,1L
-
-#define SN_des_ecb "DES-ECB"
-#define LN_des_ecb "des-ecb"
-#define NID_des_ecb 29
-#define OBJ_des_ecb OBJ_algorithm,6L
-
-#define SN_des_cfb64 "DES-CFB"
-#define LN_des_cfb64 "des-cfb"
-#define NID_des_cfb64 30
-/* IV + num */
-#define OBJ_des_cfb64 OBJ_algorithm,9L
-
-#define SN_des_cbc "DES-CBC"
-#define LN_des_cbc "des-cbc"
-#define NID_des_cbc 31
-/* IV */
-#define OBJ_des_cbc OBJ_algorithm,7L
-
-#define SN_des_ede "DES-EDE"
-#define LN_des_ede "des-ede"
-#define NID_des_ede 32
-/* ?? */
-#define OBJ_des_ede OBJ_algorithm,17L
-
-#define SN_des_ede3 "DES-EDE3"
-#define LN_des_ede3 "des-ede3"
-#define NID_des_ede3 33
-
-#define SN_idea_cbc "IDEA-CBC"
-#define LN_idea_cbc "idea-cbc"
-#define NID_idea_cbc 34
-#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L
-
-#define SN_idea_cfb64 "IDEA-CFB"
-#define LN_idea_cfb64 "idea-cfb"
-#define NID_idea_cfb64 35
-
-#define SN_idea_ecb "IDEA-ECB"
-#define LN_idea_ecb "idea-ecb"
-#define NID_idea_ecb 36
-
-#define SN_rc2_cbc "RC2-CBC"
-#define LN_rc2_cbc "rc2-cbc"
-#define NID_rc2_cbc 37
-#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L
-
-#define SN_rc2_ecb "RC2-ECB"
-#define LN_rc2_ecb "rc2-ecb"
-#define NID_rc2_ecb 38
-
-#define SN_rc2_cfb64 "RC2-CFB"
-#define LN_rc2_cfb64 "rc2-cfb"
-#define NID_rc2_cfb64 39
-
-#define SN_rc2_ofb64 "RC2-OFB"
-#define LN_rc2_ofb64 "rc2-ofb"
-#define NID_rc2_ofb64 40
-
-#define SN_sha "SHA"
-#define LN_sha "sha"
-#define NID_sha 41
-#define OBJ_sha OBJ_algorithm,18L
-
-#define SN_shaWithRSAEncryption "RSA-SHA"
-#define LN_shaWithRSAEncryption "shaWithRSAEncryption"
-#define NID_shaWithRSAEncryption 42
-#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L
-
-#define SN_des_ede_cbc "DES-EDE-CBC"
-#define LN_des_ede_cbc "des-ede-cbc"
-#define NID_des_ede_cbc 43
-
-#define SN_des_ede3_cbc "DES-EDE3-CBC"
-#define LN_des_ede3_cbc "des-ede3-cbc"
-#define NID_des_ede3_cbc 44
-#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L
-
-#define SN_des_ofb64 "DES-OFB"
-#define LN_des_ofb64 "des-ofb"
-#define NID_des_ofb64 45
-#define OBJ_des_ofb64 OBJ_algorithm,8L
-
-#define SN_idea_ofb64 "IDEA-OFB"
-#define LN_idea_ofb64 "idea-ofb"
-#define NID_idea_ofb64 46
-
-#define LN_pkcs9 "pkcs9"
-#define NID_pkcs9 47
-#define OBJ_pkcs9 OBJ_pkcs,9L
-
-#define SN_pkcs9_emailAddress "Email"
-#define LN_pkcs9_emailAddress "emailAddress"
-#define NID_pkcs9_emailAddress 48
-#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L
-
-#define LN_pkcs9_unstructuredName "unstructuredName"
-#define NID_pkcs9_unstructuredName 49
-#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L
-
-#define LN_pkcs9_contentType "contentType"
-#define NID_pkcs9_contentType 50
-#define OBJ_pkcs9_contentType OBJ_pkcs9,3L
-
-#define LN_pkcs9_messageDigest "messageDigest"
-#define NID_pkcs9_messageDigest 51
-#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L
-
-#define LN_pkcs9_signingTime "signingTime"
-#define NID_pkcs9_signingTime 52
-#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L
-
-#define LN_pkcs9_countersignature "countersignature"
-#define NID_pkcs9_countersignature 53
-#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L
-
-#define LN_pkcs9_challengePassword "challengePassword"
-#define NID_pkcs9_challengePassword 54
-#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L
-
-#define LN_pkcs9_unstructuredAddress "unstructuredAddress"
-#define NID_pkcs9_unstructuredAddress 55
-#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L
-
-#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes"
-#define NID_pkcs9_extCertAttributes 56
-#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L
-
-#define SN_netscape "Netscape"
-#define LN_netscape "Netscape Communications Corp."
-#define NID_netscape 57
-#define OBJ_netscape 2L,16L,840L,1L,113730L
-
-#define SN_netscape_cert_extension "nsCertExt"
-#define LN_netscape_cert_extension "Netscape Certificate Extension"
-#define NID_netscape_cert_extension 58
-#define OBJ_netscape_cert_extension OBJ_netscape,1L
-
-#define SN_netscape_data_type "nsDataType"
-#define LN_netscape_data_type "Netscape Data Type"
-#define NID_netscape_data_type 59
-#define OBJ_netscape_data_type OBJ_netscape,2L
-
-#define SN_des_ede_cfb64 "DES-EDE-CFB"
-#define LN_des_ede_cfb64 "des-ede-cfb"
-#define NID_des_ede_cfb64 60
-
-#define SN_des_ede3_cfb64 "DES-EDE3-CFB"
-#define LN_des_ede3_cfb64 "des-ede3-cfb"
-#define NID_des_ede3_cfb64 61
-
-#define SN_des_ede_ofb64 "DES-EDE-OFB"
-#define LN_des_ede_ofb64 "des-ede-ofb"
-#define NID_des_ede_ofb64 62
-
-#define SN_des_ede3_ofb64 "DES-EDE3-OFB"
-#define LN_des_ede3_ofb64 "des-ede3-ofb"
-#define NID_des_ede3_ofb64 63
-
-/* I'm not sure about the object ID */
-#define SN_sha1 "SHA1"
-#define LN_sha1 "sha1"
-#define NID_sha1 64
-#define OBJ_sha1 OBJ_algorithm,26L
-/* 28 Jun 1996 - eay */
-/* #define OBJ_sha1 1L,3L,14L,2L,26L,05L <- wrong */
-
-#define SN_sha1WithRSAEncryption "RSA-SHA1"
-#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption"
-#define NID_sha1WithRSAEncryption 65
-#define OBJ_sha1WithRSAEncryption OBJ_pkcs,1L,5L
-
-#define SN_dsaWithSHA "DSA-SHA"
-#define LN_dsaWithSHA "dsaWithSHA"
-#define NID_dsaWithSHA 66
-#define OBJ_dsaWithSHA OBJ_algorithm,13L
-
-#define SN_dsa_2 "DSA-old"
-#define LN_dsa_2 "dsaEncryption-old"
-#define NID_dsa_2 67
-#define OBJ_dsa_2 OBJ_algorithm,12L
-
-/* proposed by microsoft to RSA */
-#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64"
-#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC"
-#define NID_pbeWithSHA1AndRC2_CBC 68
-#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs,5L,11L
-
-/* proposed by microsoft to RSA as pbeWithSHA1AndRC4: it is now
- * defined explicitly in PKCS#5 v2.0 as id-PBKDF2 which is something
- * completely different.
- */
-#define LN_id_pbkdf2 "PBKDF2"
-#define NID_id_pbkdf2 69
-#define OBJ_id_pbkdf2 OBJ_pkcs,5L,12L
-
-#define SN_dsaWithSHA1_2 "DSA-SHA1-old"
-#define LN_dsaWithSHA1_2 "dsaWithSHA1-old"
-#define NID_dsaWithSHA1_2 70
-/* Got this one from 'sdn706r20.pdf' which is actually an NSA document :-) */
-#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L
-
-#define SN_netscape_cert_type "nsCertType"
-#define LN_netscape_cert_type "Netscape Cert Type"
-#define NID_netscape_cert_type 71
-#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L
-
-#define SN_netscape_base_url "nsBaseUrl"
-#define LN_netscape_base_url "Netscape Base Url"
-#define NID_netscape_base_url 72
-#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L
-
-#define SN_netscape_revocation_url "nsRevocationUrl"
-#define LN_netscape_revocation_url "Netscape Revocation Url"
-#define NID_netscape_revocation_url 73
-#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L
-
-#define SN_netscape_ca_revocation_url "nsCaRevocationUrl"
-#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url"
-#define NID_netscape_ca_revocation_url 74
-#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L
-
-#define SN_netscape_renewal_url "nsRenewalUrl"
-#define LN_netscape_renewal_url "Netscape Renewal Url"
-#define NID_netscape_renewal_url 75
-#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L
-
-#define SN_netscape_ca_policy_url "nsCaPolicyUrl"
-#define LN_netscape_ca_policy_url "Netscape CA Policy Url"
-#define NID_netscape_ca_policy_url 76
-#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L
-
-#define SN_netscape_ssl_server_name "nsSslServerName"
-#define LN_netscape_ssl_server_name "Netscape SSL Server Name"
-#define NID_netscape_ssl_server_name 77
-#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L
-
-#define SN_netscape_comment "nsComment"
-#define LN_netscape_comment "Netscape Comment"
-#define NID_netscape_comment 78
-#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L
-
-#define SN_netscape_cert_sequence "nsCertSequence"
-#define LN_netscape_cert_sequence "Netscape Certificate Sequence"
-#define NID_netscape_cert_sequence 79
-#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L
-
-#define SN_desx_cbc "DESX-CBC"
-#define LN_desx_cbc "desx-cbc"
-#define NID_desx_cbc 80
-
-#define SN_id_ce "id-ce"
-#define NID_id_ce 81
-#define OBJ_id_ce 2L,5L,29L
-
-#define SN_subject_key_identifier "subjectKeyIdentifier"
-#define LN_subject_key_identifier "X509v3 Subject Key Identifier"
-#define NID_subject_key_identifier 82
-#define OBJ_subject_key_identifier OBJ_id_ce,14L
-
-#define SN_key_usage "keyUsage"
-#define LN_key_usage "X509v3 Key Usage"
-#define NID_key_usage 83
-#define OBJ_key_usage OBJ_id_ce,15L
-
-#define SN_private_key_usage_period "privateKeyUsagePeriod"
-#define LN_private_key_usage_period "X509v3 Private Key Usage Period"
-#define NID_private_key_usage_period 84
-#define OBJ_private_key_usage_period OBJ_id_ce,16L
-
-#define SN_subject_alt_name "subjectAltName"
-#define LN_subject_alt_name "X509v3 Subject Alternative Name"
-#define NID_subject_alt_name 85
-#define OBJ_subject_alt_name OBJ_id_ce,17L
-
-#define SN_issuer_alt_name "issuerAltName"
-#define LN_issuer_alt_name "X509v3 Issuer Alternative Name"
-#define NID_issuer_alt_name 86
-#define OBJ_issuer_alt_name OBJ_id_ce,18L
-
-#define SN_basic_constraints "basicConstraints"
-#define LN_basic_constraints "X509v3 Basic Constraints"
-#define NID_basic_constraints 87
-#define OBJ_basic_constraints OBJ_id_ce,19L
-
-#define SN_crl_number "crlNumber"
-#define LN_crl_number "X509v3 CRL Number"
-#define NID_crl_number 88
-#define OBJ_crl_number OBJ_id_ce,20L
-
-#define SN_certificate_policies "certificatePolicies"
-#define LN_certificate_policies "X509v3 Certificate Policies"
-#define NID_certificate_policies 89
-#define OBJ_certificate_policies OBJ_id_ce,32L
-
-#define SN_authority_key_identifier "authorityKeyIdentifier"
-#define LN_authority_key_identifier "X509v3 Authority Key Identifier"
-#define NID_authority_key_identifier 90
-#define OBJ_authority_key_identifier OBJ_id_ce,35L
-
-#define SN_bf_cbc "BF-CBC"
-#define LN_bf_cbc "bf-cbc"
-#define NID_bf_cbc 91
-#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L
-
-#define SN_bf_ecb "BF-ECB"
-#define LN_bf_ecb "bf-ecb"
-#define NID_bf_ecb 92
-
-#define SN_bf_cfb64 "BF-CFB"
-#define LN_bf_cfb64 "bf-cfb"
-#define NID_bf_cfb64 93
-
-#define SN_bf_ofb64 "BF-OFB"
-#define LN_bf_ofb64 "bf-ofb"
-#define NID_bf_ofb64 94
-
-#define SN_mdc2 "MDC2"
-#define LN_mdc2 "mdc2"
-#define NID_mdc2 95
-#define OBJ_mdc2 2L,5L,8L,3L,101L
-/* An alternative? 1L,3L,14L,3L,2L,19L */
-
-#define SN_mdc2WithRSA "RSA-MDC2"
-#define LN_mdc2WithRSA "mdc2withRSA"
-#define NID_mdc2WithRSA 96
-#define OBJ_mdc2WithRSA 2L,5L,8L,3L,100L
-
-#define SN_rc4_40 "RC4-40"
-#define LN_rc4_40 "rc4-40"
-#define NID_rc4_40 97
-
-#define SN_rc2_40_cbc "RC2-40-CBC"
-#define LN_rc2_40_cbc "rc2-40-cbc"
-#define NID_rc2_40_cbc 98
-
-#define SN_givenName "G"
-#define LN_givenName "givenName"
-#define NID_givenName 99
-#define OBJ_givenName OBJ_X509,42L
-
-#define SN_surname "S"
-#define LN_surname "surname"
-#define NID_surname 100
-#define OBJ_surname OBJ_X509,4L
-
-#define SN_initials "I"
-#define LN_initials "initials"
-#define NID_initials 101
-#define OBJ_initials OBJ_X509,43L
-
-#define SN_uniqueIdentifier "UID"
-#define LN_uniqueIdentifier "uniqueIdentifier"
-#define NID_uniqueIdentifier 102
-#define OBJ_uniqueIdentifier OBJ_X509,45L
-
-#define SN_crl_distribution_points "crlDistributionPoints"
-#define LN_crl_distribution_points "X509v3 CRL Distribution Points"
-#define NID_crl_distribution_points 103
-#define OBJ_crl_distribution_points OBJ_id_ce,31L
-
-#define SN_md5WithRSA "RSA-NP-MD5"
-#define LN_md5WithRSA "md5WithRSA"
-#define NID_md5WithRSA 104
-#define OBJ_md5WithRSA OBJ_algorithm,3L
-
-#define SN_serialNumber "SN"
-#define LN_serialNumber "serialNumber"
-#define NID_serialNumber 105
-#define OBJ_serialNumber OBJ_X509,5L
-
-#define SN_title "T"
-#define LN_title "title"
-#define NID_title 106
-#define OBJ_title OBJ_X509,12L
-
-#define SN_description "D"
-#define LN_description "description"
-#define NID_description 107
-#define OBJ_description OBJ_X509,13L
-
-/* CAST5 is CAST-128, I'm just sticking with the documentation */
-#define SN_cast5_cbc "CAST5-CBC"
-#define LN_cast5_cbc "cast5-cbc"
-#define NID_cast5_cbc 108
-#define OBJ_cast5_cbc 1L,2L,840L,113533L,7L,66L,10L
-
-#define SN_cast5_ecb "CAST5-ECB"
-#define LN_cast5_ecb "cast5-ecb"
-#define NID_cast5_ecb 109
-
-#define SN_cast5_cfb64 "CAST5-CFB"
-#define LN_cast5_cfb64 "cast5-cfb"
-#define NID_cast5_cfb64 110
-
-#define SN_cast5_ofb64 "CAST5-OFB"
-#define LN_cast5_ofb64 "cast5-ofb"
-#define NID_cast5_ofb64 111
-
-#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC"
-#define NID_pbeWithMD5AndCast5_CBC 112
-#define OBJ_pbeWithMD5AndCast5_CBC 1L,2L,840L,113533L,7L,66L,12L
-
-/* This is one sun will soon be using :-(
- * id-dsa-with-sha1 ID ::= {
- * iso(1) member-body(2) us(840) x9-57 (10040) x9cm(4) 3 }
- */
-#define SN_dsaWithSHA1 "DSA-SHA1"
-#define LN_dsaWithSHA1 "dsaWithSHA1"
-#define NID_dsaWithSHA1 113
-#define OBJ_dsaWithSHA1 1L,2L,840L,10040L,4L,3L
-
-#define NID_md5_sha1 114
-#define SN_md5_sha1 "MD5-SHA1"
-#define LN_md5_sha1 "md5-sha1"
-
-#define SN_sha1WithRSA "RSA-SHA1-2"
-#define LN_sha1WithRSA "sha1WithRSA"
-#define NID_sha1WithRSA 115
-#define OBJ_sha1WithRSA OBJ_algorithm,29L
-
-#define SN_dsa "DSA"
-#define LN_dsa "dsaEncryption"
-#define NID_dsa 116
-#define OBJ_dsa 1L,2L,840L,10040L,4L,1L
-
-#define SN_ripemd160 "RIPEMD160"
-#define LN_ripemd160 "ripemd160"
-#define NID_ripemd160 117
-#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L
-
-/* The name should actually be rsaSignatureWithripemd160, but I'm going
- * to continue using the convention I'm using with the other ciphers */
-#define SN_ripemd160WithRSA "RSA-RIPEMD160"
-#define LN_ripemd160WithRSA "ripemd160WithRSA"
-#define NID_ripemd160WithRSA 119
-#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L
-
-/* Taken from rfc2040
- * RC5_CBC_Parameters ::= SEQUENCE {
- * version INTEGER (v1_0(16)),
- * rounds INTEGER (8..127),
- * blockSizeInBits INTEGER (64, 128),
- * iv OCTET STRING OPTIONAL
- * }
- */
-#define SN_rc5_cbc "RC5-CBC"
-#define LN_rc5_cbc "rc5-cbc"
-#define NID_rc5_cbc 120
-#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L
-
-#define SN_rc5_ecb "RC5-ECB"
-#define LN_rc5_ecb "rc5-ecb"
-#define NID_rc5_ecb 121
-
-#define SN_rc5_cfb64 "RC5-CFB"
-#define LN_rc5_cfb64 "rc5-cfb"
-#define NID_rc5_cfb64 122
-
-#define SN_rc5_ofb64 "RC5-OFB"
-#define LN_rc5_ofb64 "rc5-ofb"
-#define NID_rc5_ofb64 123
-
-#define SN_rle_compression "RLE"
-#define LN_rle_compression "run length compression"
-#define NID_rle_compression 124
-#define OBJ_rle_compression 1L,1L,1L,1L,666L,1L
-
-#define SN_zlib_compression "ZLIB"
-#define LN_zlib_compression "zlib compression"
-#define NID_zlib_compression 125
-#define OBJ_zlib_compression 1L,1L,1L,1L,666L,2L
-
-#define SN_ext_key_usage "extendedKeyUsage"
-#define LN_ext_key_usage "X509v3 Extended Key Usage"
-#define NID_ext_key_usage 126
-#define OBJ_ext_key_usage OBJ_id_ce,37
-
-#define SN_id_pkix "PKIX"
-#define NID_id_pkix 127
-#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L
-
-#define SN_id_kp "id-kp"
-#define NID_id_kp 128
-#define OBJ_id_kp OBJ_id_pkix,3L
-
-/* PKIX extended key usage OIDs */
-
-#define SN_server_auth "serverAuth"
-#define LN_server_auth "TLS Web Server Authentication"
-#define NID_server_auth 129
-#define OBJ_server_auth OBJ_id_kp,1L
-
-#define SN_client_auth "clientAuth"
-#define LN_client_auth "TLS Web Client Authentication"
-#define NID_client_auth 130
-#define OBJ_client_auth OBJ_id_kp,2L
-
-#define SN_code_sign "codeSigning"
-#define LN_code_sign "Code Signing"
-#define NID_code_sign 131
-#define OBJ_code_sign OBJ_id_kp,3L
-
-#define SN_email_protect "emailProtection"
-#define LN_email_protect "E-mail Protection"
-#define NID_email_protect 132
-#define OBJ_email_protect OBJ_id_kp,4L
-
-#define SN_time_stamp "timeStamping"
-#define LN_time_stamp "Time Stamping"
-#define NID_time_stamp 133
-#define OBJ_time_stamp OBJ_id_kp,8L
-
-/* Additional extended key usage OIDs: Microsoft */
-
-#define SN_ms_code_ind "msCodeInd"
-#define LN_ms_code_ind "Microsoft Individual Code Signing"
-#define NID_ms_code_ind 134
-#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L
-
-#define SN_ms_code_com "msCodeCom"
-#define LN_ms_code_com "Microsoft Commercial Code Signing"
-#define NID_ms_code_com 135
-#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L
-
-#define SN_ms_ctl_sign "msCTLSign"
-#define LN_ms_ctl_sign "Microsoft Trust List Signing"
-#define NID_ms_ctl_sign 136
-#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L
-
-#define SN_ms_sgc "msSGC"
-#define LN_ms_sgc "Microsoft Server Gated Crypto"
-#define NID_ms_sgc 137
-#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L
-
-#define SN_ms_efs "msEFS"
-#define LN_ms_efs "Microsoft Encrypted File System"
-#define NID_ms_efs 138
-#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L
-
-/* Additional usage: Netscape */
-
-#define SN_ns_sgc "nsSGC"
-#define LN_ns_sgc "Netscape Server Gated Crypto"
-#define NID_ns_sgc 139
-#define OBJ_ns_sgc OBJ_netscape,4L,1L
-
-#define SN_delta_crl "deltaCRL"
-#define LN_delta_crl "X509v3 Delta CRL Indicator"
-#define NID_delta_crl 140
-#define OBJ_delta_crl OBJ_id_ce,27L
-
-#define SN_crl_reason "CRLReason"
-#define LN_crl_reason "CRL Reason Code"
-#define NID_crl_reason 141
-#define OBJ_crl_reason OBJ_id_ce,21L
-
-#define SN_invalidity_date "invalidityDate"
-#define LN_invalidity_date "Invalidity Date"
-#define NID_invalidity_date 142
-#define OBJ_invalidity_date OBJ_id_ce,24L
-
-#define SN_sxnet "SXNetID"
-#define LN_sxnet "Strong Extranet ID"
-#define NID_sxnet 143
-#define OBJ_sxnet 1L,3L,101L,1L,4L,1L
-
-/* PKCS12 and related OBJECT IDENTIFIERS */
-
-#define OBJ_pkcs12 OBJ_pkcs,12L
-#define OBJ_pkcs12_pbeids OBJ_pkcs12, 1
-
-#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128"
-#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4"
-#define NID_pbe_WithSHA1And128BitRC4 144
-#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids, 1L
-
-#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40"
-#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4"
-#define NID_pbe_WithSHA1And40BitRC4 145
-#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids, 2L
-
-#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES"
-#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC"
-#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146
-#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids, 3L
-
-#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES"
-#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC"
-#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147
-#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids, 4L
-
-#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128"
-#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC"
-#define NID_pbe_WithSHA1And128BitRC2_CBC 148
-#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids, 5L
-
-#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40"
-#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC"
-#define NID_pbe_WithSHA1And40BitRC2_CBC 149
-#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids, 6L
-
-#define OBJ_pkcs12_Version1 OBJ_pkcs12, 10L
-
-#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1, 1L
-
-#define LN_keyBag "keyBag"
-#define NID_keyBag 150
-#define OBJ_keyBag OBJ_pkcs12_BagIds, 1L
-
-#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag"
-#define NID_pkcs8ShroudedKeyBag 151
-#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds, 2L
-
-#define LN_certBag "certBag"
-#define NID_certBag 152
-#define OBJ_certBag OBJ_pkcs12_BagIds, 3L
-
-#define LN_crlBag "crlBag"
-#define NID_crlBag 153
-#define OBJ_crlBag OBJ_pkcs12_BagIds, 4L
-
-#define LN_secretBag "secretBag"
-#define NID_secretBag 154
-#define OBJ_secretBag OBJ_pkcs12_BagIds, 5L
-
-#define LN_safeContentsBag "safeContentsBag"
-#define NID_safeContentsBag 155
-#define OBJ_safeContentsBag OBJ_pkcs12_BagIds, 6L
-
-#define LN_friendlyName "friendlyName"
-#define NID_friendlyName 156
-#define OBJ_friendlyName OBJ_pkcs9, 20L
-
-#define LN_localKeyID "localKeyID"
-#define NID_localKeyID 157
-#define OBJ_localKeyID OBJ_pkcs9, 21L
-
-#define OBJ_certTypes OBJ_pkcs9, 22L
-
-#define LN_x509Certificate "x509Certificate"
-#define NID_x509Certificate 158
-#define OBJ_x509Certificate OBJ_certTypes, 1L
-
-#define LN_sdsiCertificate "sdsiCertificate"
-#define NID_sdsiCertificate 159
-#define OBJ_sdsiCertificate OBJ_certTypes, 2L
-
-#define OBJ_crlTypes OBJ_pkcs9, 23L
-
-#define LN_x509Crl "x509Crl"
-#define NID_x509Crl 160
-#define OBJ_x509Crl OBJ_crlTypes, 1L
-
-/* PKCS#5 v2 OIDs */
-
-#define LN_pbes2 "PBES2"
-#define NID_pbes2 161
-#define OBJ_pbes2 OBJ_pkcs,5L,13L
-
-#define LN_pbmac1 "PBMAC1"
-#define NID_pbmac1 162
-#define OBJ_pbmac1 OBJ_pkcs,5L,14L
-
-#define LN_hmacWithSHA1 "hmacWithSHA1"
-#define NID_hmacWithSHA1 163
-#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L
-
-/* Policy Qualifier Ids */
-
-#define LN_id_qt_cps "Policy Qualifier CPS"
-#define SN_id_qt_cps "id-qt-cps"
-#define NID_id_qt_cps 164
-#define OBJ_id_qt_cps OBJ_id_pkix,2L,1L
-
-#define LN_id_qt_unotice "Policy Qualifier User Notice"
-#define SN_id_qt_unotice "id-qt-unotice"
-#define NID_id_qt_unotice 165
-#define OBJ_id_qt_unotice OBJ_id_pkix,2L,2L
-
-#define SN_rc2_64_cbc "RC2-64-CBC"
-#define LN_rc2_64_cbc "rc2-64-cbc"
-#define NID_rc2_64_cbc 166
-
-#define SN_SMIMECapabilities "SMIME-CAPS"
-#define LN_SMIMECapabilities "S/MIME Capabilities"
-#define NID_SMIMECapabilities 167
-#define OBJ_SMIMECapabilities OBJ_pkcs9,15L
-
-#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64"
-#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC"
-#define NID_pbeWithMD2AndRC2_CBC 168
-#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs,5L,4L
-
-#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64"
-#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC"
-#define NID_pbeWithMD5AndRC2_CBC 169
-#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs,5L,6L
-
-#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES"
-#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC"
-#define NID_pbeWithSHA1AndDES_CBC 170
-#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs,5L,10L
-
-/* Extension request OIDs */
-
-#define LN_ms_ext_req "Microsoft Extension Request"
-#define SN_ms_ext_req "msExtReq"
-#define NID_ms_ext_req 171
-#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L
-
-#define LN_ext_req "Extension Request"
-#define SN_ext_req "extReq"
-#define NID_ext_req 172
-#define OBJ_ext_req OBJ_pkcs9,14L
-
-#define SN_name "name"
-#define LN_name "name"
-#define NID_name 173
-#define OBJ_name OBJ_X509,41L
-
-#define SN_dnQualifier "dnQualifier"
-#define LN_dnQualifier "dnQualifier"
-#define NID_dnQualifier 174
-#define OBJ_dnQualifier OBJ_X509,46L
-
-#define SN_id_pe "id-pe"
-#define NID_id_pe 175
-#define OBJ_id_pe OBJ_id_pkix,1L
-
-#define SN_id_ad "id-ad"
-#define NID_id_ad 176
-#define OBJ_id_ad OBJ_id_pkix,48L
-
-#define SN_info_access "authorityInfoAccess"
-#define LN_info_access "Authority Information Access"
-#define NID_info_access 177
-#define OBJ_info_access OBJ_id_pe,1L
-
-#define SN_ad_OCSP "OCSP"
-#define LN_ad_OCSP "OCSP"
-#define NID_ad_OCSP 178
-#define OBJ_ad_OCSP OBJ_id_ad,1L
-
-#define SN_ad_ca_issuers "caIssuers"
-#define LN_ad_ca_issuers "CA Issuers"
-#define NID_ad_ca_issuers 179
-#define OBJ_ad_ca_issuers OBJ_id_ad,2L
-
-#define SN_OCSP_sign "OCSPSigning"
-#define LN_OCSP_sign "OCSP Signing"
-#define NID_OCSP_sign 180
-#define OBJ_OCSP_sign OBJ_id_kp,9L
-#endif /* USE_OBJ_MAC */
-
-#include <openssl/bio.h>
-#include <openssl/asn1.h>
-
-#define OBJ_NAME_TYPE_UNDEF 0x00
-#define OBJ_NAME_TYPE_MD_METH 0x01
-#define OBJ_NAME_TYPE_CIPHER_METH 0x02
-#define OBJ_NAME_TYPE_PKEY_METH 0x03
-#define OBJ_NAME_TYPE_COMP_METH 0x04
-#define OBJ_NAME_TYPE_NUM 0x05
-
-#define OBJ_NAME_ALIAS 0x8000
-
-#define OBJ_BSEARCH_VALUE_ON_NOMATCH 0x01
-#define OBJ_BSEARCH_FIRST_VALUE_ON_MATCH 0x02
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct obj_name_st
- {
- int type;
- int alias;
- const char *name;
- const char *data;
- } OBJ_NAME;
-
-#define OBJ_create_and_add_object(a,b,c) OBJ_create(a,b,c)
-
-
-int OBJ_NAME_init(void);
-int OBJ_NAME_new_index(unsigned long (*hash_func)(const char *),
- int (*cmp_func)(const char *, const char *),
- void (*free_func)(const char *, int, const char *));
-const char *OBJ_NAME_get(const char *name,int type);
-int OBJ_NAME_add(const char *name,int type,const char *data);
-int OBJ_NAME_remove(const char *name,int type);
-void OBJ_NAME_cleanup(int type); /* -1 for everything */
-void OBJ_NAME_do_all(int type,void (*fn)(const OBJ_NAME *,void *arg),
- void *arg);
-void OBJ_NAME_do_all_sorted(int type,void (*fn)(const OBJ_NAME *,void *arg),
- void *arg);
-
-ASN1_OBJECT * OBJ_dup(const ASN1_OBJECT *o);
-ASN1_OBJECT * OBJ_nid2obj(int n);
-const char * OBJ_nid2ln(int n);
-const char * OBJ_nid2sn(int n);
-int OBJ_obj2nid(const ASN1_OBJECT *o);
-ASN1_OBJECT * OBJ_txt2obj(const char *s, int no_name);
-int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name);
-int OBJ_txt2nid(const char *s);
-int OBJ_ln2nid(const char *s);
-int OBJ_sn2nid(const char *s);
-int OBJ_cmp(const ASN1_OBJECT *a,const ASN1_OBJECT *b);
-const void * OBJ_bsearch_(const void *key,const void *base,int num,int size,
- int (*cmp)(const void *, const void *));
-const void * OBJ_bsearch_ex_(const void *key,const void *base,int num,
- int size,
- int (*cmp)(const void *, const void *),
- int flags);
-
-#define _DECLARE_OBJ_BSEARCH_CMP_FN(scope, type1, type2, nm) \
- static int nm##_cmp_BSEARCH_CMP_FN(const void *, const void *); \
- static int nm##_cmp(type1 const *, type2 const *); \
- scope type2 * OBJ_bsearch_##nm(type1 *key, type2 const *base, int num)
-
-#define DECLARE_OBJ_BSEARCH_CMP_FN(type1, type2, cmp) \
- _DECLARE_OBJ_BSEARCH_CMP_FN(static, type1, type2, cmp)
-#define DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(type1, type2, nm) \
- type2 * OBJ_bsearch_##nm(type1 *key, type2 const *base, int num)
-
-/*
- * Unsolved problem: if a type is actually a pointer type, like
- * nid_triple is, then its impossible to get a const where you need
- * it. Consider:
- *
- * typedef int nid_triple[3];
- * const void *a_;
- * const nid_triple const *a = a_;
- *
- * The assignement discards a const because what you really want is:
- *
- * const int const * const *a = a_;
- *
- * But if you do that, you lose the fact that a is an array of 3 ints,
- * which breaks comparison functions.
- *
- * Thus we end up having to cast, sadly, or unpack the
- * declarations. Or, as I finally did in this case, delcare nid_triple
- * to be a struct, which it should have been in the first place.
- *
- * Ben, August 2008.
- *
- * Also, strictly speaking not all types need be const, but handling
- * the non-constness means a lot of complication, and in practice
- * comparison routines do always not touch their arguments.
- */
-
-#define IMPLEMENT_OBJ_BSEARCH_CMP_FN(type1, type2, nm) \
- static int nm##_cmp_BSEARCH_CMP_FN(const void *a_, const void *b_) \
- { \
- type1 const *a = a_; \
- type2 const *b = b_; \
- return nm##_cmp(a,b); \
- } \
- static type2 *OBJ_bsearch_##nm(type1 *key, type2 const *base, int num) \
- { \
- return (type2 *)OBJ_bsearch_(key, base, num, sizeof(type2), \
- nm##_cmp_BSEARCH_CMP_FN); \
- } \
- extern void dummy_prototype(void)
-
-#define IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(type1, type2, nm) \
- static int nm##_cmp_BSEARCH_CMP_FN(const void *a_, const void *b_) \
- { \
- type1 const *a = a_; \
- type2 const *b = b_; \
- return nm##_cmp(a,b); \
- } \
- type2 *OBJ_bsearch_##nm(type1 *key, type2 const *base, int num) \
- { \
- return (type2 *)OBJ_bsearch_(key, base, num, sizeof(type2), \
- nm##_cmp_BSEARCH_CMP_FN); \
- } \
- extern void dummy_prototype(void)
-
-#define OBJ_bsearch(type1,key,type2,base,num,cmp) \
- ((type2 *)OBJ_bsearch_(CHECKED_PTR_OF(type1,key),CHECKED_PTR_OF(type2,base), \
- num,sizeof(type2), \
- ((void)CHECKED_PTR_OF(type1,cmp##_type_1), \
- (void)CHECKED_PTR_OF(type2,cmp##_type_2), \
- cmp##_BSEARCH_CMP_FN)))
-
-#define OBJ_bsearch_ex(type1,key,type2,base,num,cmp,flags) \
- ((type2 *)OBJ_bsearch_ex_(CHECKED_PTR_OF(type1,key),CHECKED_PTR_OF(type2,base), \
- num,sizeof(type2), \
- ((void)CHECKED_PTR_OF(type1,cmp##_type_1), \
- (void)type_2=CHECKED_PTR_OF(type2,cmp##_type_2), \
- cmp##_BSEARCH_CMP_FN)),flags)
-
-int OBJ_new_nid(int num);
-int OBJ_add_object(const ASN1_OBJECT *obj);
-int OBJ_create(const char *oid,const char *sn,const char *ln);
-void OBJ_cleanup(void );
-int OBJ_create_objects(BIO *in);
-
-int OBJ_find_sigid_algs(int signid, int *pdig_nid, int *ppkey_nid);
-int OBJ_find_sigid_by_algs(int *psignid, int dig_nid, int pkey_nid);
-int OBJ_add_sigid(int signid, int dig_id, int pkey_id);
-void OBJ_sigid_free(void);
-
-extern int obj_cleanup_defer;
-void check_defer(int nid);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_OBJ_strings(void);
-
-/* Error codes for the OBJ functions. */
-
-/* Function codes. */
-#define OBJ_F_OBJ_ADD_OBJECT 105
-#define OBJ_F_OBJ_CREATE 100
-#define OBJ_F_OBJ_DUP 101
-#define OBJ_F_OBJ_NAME_NEW_INDEX 106
-#define OBJ_F_OBJ_NID2LN 102
-#define OBJ_F_OBJ_NID2OBJ 103
-#define OBJ_F_OBJ_NID2SN 104
-
-/* Reason codes. */
-#define OBJ_R_MALLOC_FAILURE 100
-#define OBJ_R_UNKNOWN_NID 101
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/ocsp.h b/drivers/builtin_openssl/openssl/ocsp.h
deleted file mode 100644
index 31e45744ba..0000000000
--- a/drivers/builtin_openssl/openssl/ocsp.h
+++ /dev/null
@@ -1,623 +0,0 @@
-/* ocsp.h */
-/* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
- * project. */
-
-/* History:
- This file was transfered to Richard Levitte from CertCo by Kathy
- Weinhold in mid-spring 2000 to be included in OpenSSL or released
- as a patch kit. */
-
-/* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_OCSP_H
-#define HEADER_OCSP_H
-
-#include <openssl/ossl_typ.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/safestack.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Various flags and values */
-
-#define OCSP_DEFAULT_NONCE_LENGTH 16
-
-#define OCSP_NOCERTS 0x1
-#define OCSP_NOINTERN 0x2
-#define OCSP_NOSIGS 0x4
-#define OCSP_NOCHAIN 0x8
-#define OCSP_NOVERIFY 0x10
-#define OCSP_NOEXPLICIT 0x20
-#define OCSP_NOCASIGN 0x40
-#define OCSP_NODELEGATED 0x80
-#define OCSP_NOCHECKS 0x100
-#define OCSP_TRUSTOTHER 0x200
-#define OCSP_RESPID_KEY 0x400
-#define OCSP_NOTIME 0x800
-
-/* CertID ::= SEQUENCE {
- * hashAlgorithm AlgorithmIdentifier,
- * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
- * issuerKeyHash OCTET STRING, -- Hash of Issuers public key (excluding the tag & length fields)
- * serialNumber CertificateSerialNumber }
- */
-typedef struct ocsp_cert_id_st
- {
- X509_ALGOR *hashAlgorithm;
- ASN1_OCTET_STRING *issuerNameHash;
- ASN1_OCTET_STRING *issuerKeyHash;
- ASN1_INTEGER *serialNumber;
- } OCSP_CERTID;
-
-DECLARE_STACK_OF(OCSP_CERTID)
-
-/* Request ::= SEQUENCE {
- * reqCert CertID,
- * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
- */
-typedef struct ocsp_one_request_st
- {
- OCSP_CERTID *reqCert;
- STACK_OF(X509_EXTENSION) *singleRequestExtensions;
- } OCSP_ONEREQ;
-
-DECLARE_STACK_OF(OCSP_ONEREQ)
-DECLARE_ASN1_SET_OF(OCSP_ONEREQ)
-
-
-/* TBSRequest ::= SEQUENCE {
- * version [0] EXPLICIT Version DEFAULT v1,
- * requestorName [1] EXPLICIT GeneralName OPTIONAL,
- * requestList SEQUENCE OF Request,
- * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
- */
-typedef struct ocsp_req_info_st
- {
- ASN1_INTEGER *version;
- GENERAL_NAME *requestorName;
- STACK_OF(OCSP_ONEREQ) *requestList;
- STACK_OF(X509_EXTENSION) *requestExtensions;
- } OCSP_REQINFO;
-
-/* Signature ::= SEQUENCE {
- * signatureAlgorithm AlgorithmIdentifier,
- * signature BIT STRING,
- * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
- */
-typedef struct ocsp_signature_st
- {
- X509_ALGOR *signatureAlgorithm;
- ASN1_BIT_STRING *signature;
- STACK_OF(X509) *certs;
- } OCSP_SIGNATURE;
-
-/* OCSPRequest ::= SEQUENCE {
- * tbsRequest TBSRequest,
- * optionalSignature [0] EXPLICIT Signature OPTIONAL }
- */
-typedef struct ocsp_request_st
- {
- OCSP_REQINFO *tbsRequest;
- OCSP_SIGNATURE *optionalSignature; /* OPTIONAL */
- } OCSP_REQUEST;
-
-/* OCSPResponseStatus ::= ENUMERATED {
- * successful (0), --Response has valid confirmations
- * malformedRequest (1), --Illegal confirmation request
- * internalError (2), --Internal error in issuer
- * tryLater (3), --Try again later
- * --(4) is not used
- * sigRequired (5), --Must sign the request
- * unauthorized (6) --Request unauthorized
- * }
- */
-#define OCSP_RESPONSE_STATUS_SUCCESSFUL 0
-#define OCSP_RESPONSE_STATUS_MALFORMEDREQUEST 1
-#define OCSP_RESPONSE_STATUS_INTERNALERROR 2
-#define OCSP_RESPONSE_STATUS_TRYLATER 3
-#define OCSP_RESPONSE_STATUS_SIGREQUIRED 5
-#define OCSP_RESPONSE_STATUS_UNAUTHORIZED 6
-
-/* ResponseBytes ::= SEQUENCE {
- * responseType OBJECT IDENTIFIER,
- * response OCTET STRING }
- */
-typedef struct ocsp_resp_bytes_st
- {
- ASN1_OBJECT *responseType;
- ASN1_OCTET_STRING *response;
- } OCSP_RESPBYTES;
-
-/* OCSPResponse ::= SEQUENCE {
- * responseStatus OCSPResponseStatus,
- * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
- */
-struct ocsp_response_st
- {
- ASN1_ENUMERATED *responseStatus;
- OCSP_RESPBYTES *responseBytes;
- };
-
-/* ResponderID ::= CHOICE {
- * byName [1] Name,
- * byKey [2] KeyHash }
- */
-#define V_OCSP_RESPID_NAME 0
-#define V_OCSP_RESPID_KEY 1
-struct ocsp_responder_id_st
- {
- int type;
- union {
- X509_NAME* byName;
- ASN1_OCTET_STRING *byKey;
- } value;
- };
-
-DECLARE_STACK_OF(OCSP_RESPID)
-DECLARE_ASN1_FUNCTIONS(OCSP_RESPID)
-
-/* KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
- * --(excluding the tag and length fields)
- */
-
-/* RevokedInfo ::= SEQUENCE {
- * revocationTime GeneralizedTime,
- * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
- */
-typedef struct ocsp_revoked_info_st
- {
- ASN1_GENERALIZEDTIME *revocationTime;
- ASN1_ENUMERATED *revocationReason;
- } OCSP_REVOKEDINFO;
-
-/* CertStatus ::= CHOICE {
- * good [0] IMPLICIT NULL,
- * revoked [1] IMPLICIT RevokedInfo,
- * unknown [2] IMPLICIT UnknownInfo }
- */
-#define V_OCSP_CERTSTATUS_GOOD 0
-#define V_OCSP_CERTSTATUS_REVOKED 1
-#define V_OCSP_CERTSTATUS_UNKNOWN 2
-typedef struct ocsp_cert_status_st
- {
- int type;
- union {
- ASN1_NULL *good;
- OCSP_REVOKEDINFO *revoked;
- ASN1_NULL *unknown;
- } value;
- } OCSP_CERTSTATUS;
-
-/* SingleResponse ::= SEQUENCE {
- * certID CertID,
- * certStatus CertStatus,
- * thisUpdate GeneralizedTime,
- * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
- * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
- */
-typedef struct ocsp_single_response_st
- {
- OCSP_CERTID *certId;
- OCSP_CERTSTATUS *certStatus;
- ASN1_GENERALIZEDTIME *thisUpdate;
- ASN1_GENERALIZEDTIME *nextUpdate;
- STACK_OF(X509_EXTENSION) *singleExtensions;
- } OCSP_SINGLERESP;
-
-DECLARE_STACK_OF(OCSP_SINGLERESP)
-DECLARE_ASN1_SET_OF(OCSP_SINGLERESP)
-
-/* ResponseData ::= SEQUENCE {
- * version [0] EXPLICIT Version DEFAULT v1,
- * responderID ResponderID,
- * producedAt GeneralizedTime,
- * responses SEQUENCE OF SingleResponse,
- * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
- */
-typedef struct ocsp_response_data_st
- {
- ASN1_INTEGER *version;
- OCSP_RESPID *responderId;
- ASN1_GENERALIZEDTIME *producedAt;
- STACK_OF(OCSP_SINGLERESP) *responses;
- STACK_OF(X509_EXTENSION) *responseExtensions;
- } OCSP_RESPDATA;
-
-/* BasicOCSPResponse ::= SEQUENCE {
- * tbsResponseData ResponseData,
- * signatureAlgorithm AlgorithmIdentifier,
- * signature BIT STRING,
- * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
- */
- /* Note 1:
- The value for "signature" is specified in the OCSP rfc2560 as follows:
- "The value for the signature SHALL be computed on the hash of the DER
- encoding ResponseData." This means that you must hash the DER-encoded
- tbsResponseData, and then run it through a crypto-signing function, which
- will (at least w/RSA) do a hash-'n'-private-encrypt operation. This seems
- a bit odd, but that's the spec. Also note that the data structures do not
- leave anywhere to independently specify the algorithm used for the initial
- hash. So, we look at the signature-specification algorithm, and try to do
- something intelligent. -- Kathy Weinhold, CertCo */
- /* Note 2:
- It seems that the mentioned passage from RFC 2560 (section 4.2.1) is open
- for interpretation. I've done tests against another responder, and found
- that it doesn't do the double hashing that the RFC seems to say one
- should. Therefore, all relevant functions take a flag saying which
- variant should be used. -- Richard Levitte, OpenSSL team and CeloCom */
-typedef struct ocsp_basic_response_st
- {
- OCSP_RESPDATA *tbsResponseData;
- X509_ALGOR *signatureAlgorithm;
- ASN1_BIT_STRING *signature;
- STACK_OF(X509) *certs;
- } OCSP_BASICRESP;
-
-/*
- * CRLReason ::= ENUMERATED {
- * unspecified (0),
- * keyCompromise (1),
- * cACompromise (2),
- * affiliationChanged (3),
- * superseded (4),
- * cessationOfOperation (5),
- * certificateHold (6),
- * removeFromCRL (8) }
- */
-#define OCSP_REVOKED_STATUS_NOSTATUS -1
-#define OCSP_REVOKED_STATUS_UNSPECIFIED 0
-#define OCSP_REVOKED_STATUS_KEYCOMPROMISE 1
-#define OCSP_REVOKED_STATUS_CACOMPROMISE 2
-#define OCSP_REVOKED_STATUS_AFFILIATIONCHANGED 3
-#define OCSP_REVOKED_STATUS_SUPERSEDED 4
-#define OCSP_REVOKED_STATUS_CESSATIONOFOPERATION 5
-#define OCSP_REVOKED_STATUS_CERTIFICATEHOLD 6
-#define OCSP_REVOKED_STATUS_REMOVEFROMCRL 8
-
-/* CrlID ::= SEQUENCE {
- * crlUrl [0] EXPLICIT IA5String OPTIONAL,
- * crlNum [1] EXPLICIT INTEGER OPTIONAL,
- * crlTime [2] EXPLICIT GeneralizedTime OPTIONAL }
- */
-typedef struct ocsp_crl_id_st
- {
- ASN1_IA5STRING *crlUrl;
- ASN1_INTEGER *crlNum;
- ASN1_GENERALIZEDTIME *crlTime;
- } OCSP_CRLID;
-
-/* ServiceLocator ::= SEQUENCE {
- * issuer Name,
- * locator AuthorityInfoAccessSyntax OPTIONAL }
- */
-typedef struct ocsp_service_locator_st
- {
- X509_NAME* issuer;
- STACK_OF(ACCESS_DESCRIPTION) *locator;
- } OCSP_SERVICELOC;
-
-#define PEM_STRING_OCSP_REQUEST "OCSP REQUEST"
-#define PEM_STRING_OCSP_RESPONSE "OCSP RESPONSE"
-
-#define d2i_OCSP_REQUEST_bio(bp,p) ASN1_d2i_bio_of(OCSP_REQUEST,OCSP_REQUEST_new,d2i_OCSP_REQUEST,bp,p)
-
-#define d2i_OCSP_RESPONSE_bio(bp,p) ASN1_d2i_bio_of(OCSP_RESPONSE,OCSP_RESPONSE_new,d2i_OCSP_RESPONSE,bp,p)
-
-#define PEM_read_bio_OCSP_REQUEST(bp,x,cb) (OCSP_REQUEST *)PEM_ASN1_read_bio( \
- (char *(*)())d2i_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,bp,(char **)x,cb,NULL)
-
-#define PEM_read_bio_OCSP_RESPONSE(bp,x,cb)(OCSP_RESPONSE *)PEM_ASN1_read_bio(\
- (char *(*)())d2i_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,bp,(char **)x,cb,NULL)
-
-#define PEM_write_bio_OCSP_REQUEST(bp,o) \
- PEM_ASN1_write_bio((int (*)())i2d_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,\
- bp,(char *)o, NULL,NULL,0,NULL,NULL)
-
-#define PEM_write_bio_OCSP_RESPONSE(bp,o) \
- PEM_ASN1_write_bio((int (*)())i2d_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,\
- bp,(char *)o, NULL,NULL,0,NULL,NULL)
-
-#define i2d_OCSP_RESPONSE_bio(bp,o) ASN1_i2d_bio_of(OCSP_RESPONSE,i2d_OCSP_RESPONSE,bp,o)
-
-#define i2d_OCSP_REQUEST_bio(bp,o) ASN1_i2d_bio_of(OCSP_REQUEST,i2d_OCSP_REQUEST,bp,o)
-
-#define OCSP_REQUEST_sign(o,pkey,md) \
- ASN1_item_sign(ASN1_ITEM_rptr(OCSP_REQINFO),\
- o->optionalSignature->signatureAlgorithm,NULL,\
- o->optionalSignature->signature,o->tbsRequest,pkey,md)
-
-#define OCSP_BASICRESP_sign(o,pkey,md,d) \
- ASN1_item_sign(ASN1_ITEM_rptr(OCSP_RESPDATA),o->signatureAlgorithm,NULL,\
- o->signature,o->tbsResponseData,pkey,md)
-
-#define OCSP_REQUEST_verify(a,r) ASN1_item_verify(ASN1_ITEM_rptr(OCSP_REQINFO),\
- a->optionalSignature->signatureAlgorithm,\
- a->optionalSignature->signature,a->tbsRequest,r)
-
-#define OCSP_BASICRESP_verify(a,r,d) ASN1_item_verify(ASN1_ITEM_rptr(OCSP_RESPDATA),\
- a->signatureAlgorithm,a->signature,a->tbsResponseData,r)
-
-#define ASN1_BIT_STRING_digest(data,type,md,len) \
- ASN1_item_digest(ASN1_ITEM_rptr(ASN1_BIT_STRING),type,data,md,len)
-
-#define OCSP_CERTSTATUS_dup(cs)\
- (OCSP_CERTSTATUS*)ASN1_dup((int(*)())i2d_OCSP_CERTSTATUS,\
- (char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
-
-OCSP_CERTID *OCSP_CERTID_dup(OCSP_CERTID *id);
-
-OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req);
-OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
- int maxline);
-int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx);
-void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx);
-int OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX *rctx, OCSP_REQUEST *req);
-int OCSP_REQ_CTX_add1_header(OCSP_REQ_CTX *rctx,
- const char *name, const char *value);
-
-OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
-
-OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst,
- X509_NAME *issuerName,
- ASN1_BIT_STRING* issuerKey,
- ASN1_INTEGER *serialNumber);
-
-OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid);
-
-int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len);
-int OCSP_basic_add1_nonce(OCSP_BASICRESP *resp, unsigned char *val, int len);
-int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs);
-int OCSP_copy_nonce(OCSP_BASICRESP *resp, OCSP_REQUEST *req);
-
-int OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm);
-int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert);
-
-int OCSP_request_sign(OCSP_REQUEST *req,
- X509 *signer,
- EVP_PKEY *key,
- const EVP_MD *dgst,
- STACK_OF(X509) *certs,
- unsigned long flags);
-
-int OCSP_response_status(OCSP_RESPONSE *resp);
-OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp);
-
-int OCSP_resp_count(OCSP_BASICRESP *bs);
-OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx);
-int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last);
-int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
- ASN1_GENERALIZEDTIME **revtime,
- ASN1_GENERALIZEDTIME **thisupd,
- ASN1_GENERALIZEDTIME **nextupd);
-int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
- int *reason,
- ASN1_GENERALIZEDTIME **revtime,
- ASN1_GENERALIZEDTIME **thisupd,
- ASN1_GENERALIZEDTIME **nextupd);
-int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd,
- ASN1_GENERALIZEDTIME *nextupd,
- long sec, long maxsec);
-
-int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, X509_STORE *store, unsigned long flags);
-
-int OCSP_parse_url(char *url, char **phost, char **pport, char **ppath, int *pssl);
-
-int OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
-int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
-
-int OCSP_request_onereq_count(OCSP_REQUEST *req);
-OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *req, int i);
-OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *one);
-int OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd,
- ASN1_OCTET_STRING **pikeyHash,
- ASN1_INTEGER **pserial, OCSP_CERTID *cid);
-int OCSP_request_is_signed(OCSP_REQUEST *req);
-OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs);
-OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *rsp,
- OCSP_CERTID *cid,
- int status, int reason,
- ASN1_TIME *revtime,
- ASN1_TIME *thisupd, ASN1_TIME *nextupd);
-int OCSP_basic_add1_cert(OCSP_BASICRESP *resp, X509 *cert);
-int OCSP_basic_sign(OCSP_BASICRESP *brsp,
- X509 *signer, EVP_PKEY *key, const EVP_MD *dgst,
- STACK_OF(X509) *certs, unsigned long flags);
-
-X509_EXTENSION *OCSP_crlID_new(char *url, long *n, char *tim);
-
-X509_EXTENSION *OCSP_accept_responses_new(char **oids);
-
-X509_EXTENSION *OCSP_archive_cutoff_new(char* tim);
-
-X509_EXTENSION *OCSP_url_svcloc_new(X509_NAME* issuer, char **urls);
-
-int OCSP_REQUEST_get_ext_count(OCSP_REQUEST *x);
-int OCSP_REQUEST_get_ext_by_NID(OCSP_REQUEST *x, int nid, int lastpos);
-int OCSP_REQUEST_get_ext_by_OBJ(OCSP_REQUEST *x, ASN1_OBJECT *obj, int lastpos);
-int OCSP_REQUEST_get_ext_by_critical(OCSP_REQUEST *x, int crit, int lastpos);
-X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *x, int loc);
-X509_EXTENSION *OCSP_REQUEST_delete_ext(OCSP_REQUEST *x, int loc);
-void *OCSP_REQUEST_get1_ext_d2i(OCSP_REQUEST *x, int nid, int *crit, int *idx);
-int OCSP_REQUEST_add1_ext_i2d(OCSP_REQUEST *x, int nid, void *value, int crit,
- unsigned long flags);
-int OCSP_REQUEST_add_ext(OCSP_REQUEST *x, X509_EXTENSION *ex, int loc);
-
-int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *x);
-int OCSP_ONEREQ_get_ext_by_NID(OCSP_ONEREQ *x, int nid, int lastpos);
-int OCSP_ONEREQ_get_ext_by_OBJ(OCSP_ONEREQ *x, ASN1_OBJECT *obj, int lastpos);
-int OCSP_ONEREQ_get_ext_by_critical(OCSP_ONEREQ *x, int crit, int lastpos);
-X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *x, int loc);
-X509_EXTENSION *OCSP_ONEREQ_delete_ext(OCSP_ONEREQ *x, int loc);
-void *OCSP_ONEREQ_get1_ext_d2i(OCSP_ONEREQ *x, int nid, int *crit, int *idx);
-int OCSP_ONEREQ_add1_ext_i2d(OCSP_ONEREQ *x, int nid, void *value, int crit,
- unsigned long flags);
-int OCSP_ONEREQ_add_ext(OCSP_ONEREQ *x, X509_EXTENSION *ex, int loc);
-
-int OCSP_BASICRESP_get_ext_count(OCSP_BASICRESP *x);
-int OCSP_BASICRESP_get_ext_by_NID(OCSP_BASICRESP *x, int nid, int lastpos);
-int OCSP_BASICRESP_get_ext_by_OBJ(OCSP_BASICRESP *x, ASN1_OBJECT *obj, int lastpos);
-int OCSP_BASICRESP_get_ext_by_critical(OCSP_BASICRESP *x, int crit, int lastpos);
-X509_EXTENSION *OCSP_BASICRESP_get_ext(OCSP_BASICRESP *x, int loc);
-X509_EXTENSION *OCSP_BASICRESP_delete_ext(OCSP_BASICRESP *x, int loc);
-void *OCSP_BASICRESP_get1_ext_d2i(OCSP_BASICRESP *x, int nid, int *crit, int *idx);
-int OCSP_BASICRESP_add1_ext_i2d(OCSP_BASICRESP *x, int nid, void *value, int crit,
- unsigned long flags);
-int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *x, X509_EXTENSION *ex, int loc);
-
-int OCSP_SINGLERESP_get_ext_count(OCSP_SINGLERESP *x);
-int OCSP_SINGLERESP_get_ext_by_NID(OCSP_SINGLERESP *x, int nid, int lastpos);
-int OCSP_SINGLERESP_get_ext_by_OBJ(OCSP_SINGLERESP *x, ASN1_OBJECT *obj, int lastpos);
-int OCSP_SINGLERESP_get_ext_by_critical(OCSP_SINGLERESP *x, int crit, int lastpos);
-X509_EXTENSION *OCSP_SINGLERESP_get_ext(OCSP_SINGLERESP *x, int loc);
-X509_EXTENSION *OCSP_SINGLERESP_delete_ext(OCSP_SINGLERESP *x, int loc);
-void *OCSP_SINGLERESP_get1_ext_d2i(OCSP_SINGLERESP *x, int nid, int *crit, int *idx);
-int OCSP_SINGLERESP_add1_ext_i2d(OCSP_SINGLERESP *x, int nid, void *value, int crit,
- unsigned long flags);
-int OCSP_SINGLERESP_add_ext(OCSP_SINGLERESP *x, X509_EXTENSION *ex, int loc);
-
-DECLARE_ASN1_FUNCTIONS(OCSP_SINGLERESP)
-DECLARE_ASN1_FUNCTIONS(OCSP_CERTSTATUS)
-DECLARE_ASN1_FUNCTIONS(OCSP_REVOKEDINFO)
-DECLARE_ASN1_FUNCTIONS(OCSP_BASICRESP)
-DECLARE_ASN1_FUNCTIONS(OCSP_RESPDATA)
-DECLARE_ASN1_FUNCTIONS(OCSP_RESPID)
-DECLARE_ASN1_FUNCTIONS(OCSP_RESPONSE)
-DECLARE_ASN1_FUNCTIONS(OCSP_RESPBYTES)
-DECLARE_ASN1_FUNCTIONS(OCSP_ONEREQ)
-DECLARE_ASN1_FUNCTIONS(OCSP_CERTID)
-DECLARE_ASN1_FUNCTIONS(OCSP_REQUEST)
-DECLARE_ASN1_FUNCTIONS(OCSP_SIGNATURE)
-DECLARE_ASN1_FUNCTIONS(OCSP_REQINFO)
-DECLARE_ASN1_FUNCTIONS(OCSP_CRLID)
-DECLARE_ASN1_FUNCTIONS(OCSP_SERVICELOC)
-
-const char *OCSP_response_status_str(long s);
-const char *OCSP_cert_status_str(long s);
-const char *OCSP_crl_reason_str(long s);
-
-int OCSP_REQUEST_print(BIO *bp, OCSP_REQUEST* a, unsigned long flags);
-int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* o, unsigned long flags);
-
-int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
- X509_STORE *st, unsigned long flags);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_OCSP_strings(void);
-
-/* Error codes for the OCSP functions. */
-
-/* Function codes. */
-#define OCSP_F_ASN1_STRING_ENCODE 100
-#define OCSP_F_D2I_OCSP_NONCE 102
-#define OCSP_F_OCSP_BASIC_ADD1_STATUS 103
-#define OCSP_F_OCSP_BASIC_SIGN 104
-#define OCSP_F_OCSP_BASIC_VERIFY 105
-#define OCSP_F_OCSP_CERT_ID_NEW 101
-#define OCSP_F_OCSP_CHECK_DELEGATED 106
-#define OCSP_F_OCSP_CHECK_IDS 107
-#define OCSP_F_OCSP_CHECK_ISSUER 108
-#define OCSP_F_OCSP_CHECK_VALIDITY 115
-#define OCSP_F_OCSP_MATCH_ISSUERID 109
-#define OCSP_F_OCSP_PARSE_URL 114
-#define OCSP_F_OCSP_REQUEST_SIGN 110
-#define OCSP_F_OCSP_REQUEST_VERIFY 116
-#define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111
-#define OCSP_F_OCSP_SENDREQ_BIO 112
-#define OCSP_F_OCSP_SENDREQ_NBIO 117
-#define OCSP_F_PARSE_HTTP_LINE1 118
-#define OCSP_F_REQUEST_VERIFY 113
-
-/* Reason codes. */
-#define OCSP_R_BAD_DATA 100
-#define OCSP_R_CERTIFICATE_VERIFY_ERROR 101
-#define OCSP_R_DIGEST_ERR 102
-#define OCSP_R_ERROR_IN_NEXTUPDATE_FIELD 122
-#define OCSP_R_ERROR_IN_THISUPDATE_FIELD 123
-#define OCSP_R_ERROR_PARSING_URL 121
-#define OCSP_R_MISSING_OCSPSIGNING_USAGE 103
-#define OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE 124
-#define OCSP_R_NOT_BASIC_RESPONSE 104
-#define OCSP_R_NO_CERTIFICATES_IN_CHAIN 105
-#define OCSP_R_NO_CONTENT 106
-#define OCSP_R_NO_PUBLIC_KEY 107
-#define OCSP_R_NO_RESPONSE_DATA 108
-#define OCSP_R_NO_REVOKED_TIME 109
-#define OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 110
-#define OCSP_R_REQUEST_NOT_SIGNED 128
-#define OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA 111
-#define OCSP_R_ROOT_CA_NOT_TRUSTED 112
-#define OCSP_R_SERVER_READ_ERROR 113
-#define OCSP_R_SERVER_RESPONSE_ERROR 114
-#define OCSP_R_SERVER_RESPONSE_PARSE_ERROR 115
-#define OCSP_R_SERVER_WRITE_ERROR 116
-#define OCSP_R_SIGNATURE_FAILURE 117
-#define OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND 118
-#define OCSP_R_STATUS_EXPIRED 125
-#define OCSP_R_STATUS_NOT_YET_VALID 126
-#define OCSP_R_STATUS_TOO_OLD 127
-#define OCSP_R_UNKNOWN_MESSAGE_DIGEST 119
-#define OCSP_R_UNKNOWN_NID 120
-#define OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE 129
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/opensslv.h b/drivers/builtin_openssl/openssl/opensslv.h
deleted file mode 100644
index ebe7180723..0000000000
--- a/drivers/builtin_openssl/openssl/opensslv.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef HEADER_OPENSSLV_H
-#define HEADER_OPENSSLV_H
-
-/* Numeric release version identifier:
- * MNNFFPPS: major minor fix patch status
- * The status nibble has one of the values 0 for development, 1 to e for betas
- * 1 to 14, and f for release. The patch level is exactly that.
- * For example:
- * 0.9.3-dev 0x00903000
- * 0.9.3-beta1 0x00903001
- * 0.9.3-beta2-dev 0x00903002
- * 0.9.3-beta2 0x00903002 (same as ...beta2-dev)
- * 0.9.3 0x0090300f
- * 0.9.3a 0x0090301f
- * 0.9.4 0x0090400f
- * 1.2.3z 0x102031af
- *
- * For continuity reasons (because 0.9.5 is already out, and is coded
- * 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level
- * part is slightly different, by setting the highest bit. This means
- * that 0.9.5a looks like this: 0x0090581f. At 0.9.6, we can start
- * with 0x0090600S...
- *
- * (Prior to 0.9.3-dev a different scheme was used: 0.9.2b is 0x0922.)
- * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
- * major minor fix final patch/beta)
- */
-#define OPENSSL_VERSION_NUMBER 0x1000107fL
-#ifdef OPENSSL_FIPS
-#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.1g-fips 7 Apr 2014"
-#else
-#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.1g 7 Apr 2014"
-#endif
-#define OPENSSL_VERSION_PTEXT " part of " OPENSSL_VERSION_TEXT
-
-
-/* The macros below are to be used for shared library (.so, .dll, ...)
- * versioning. That kind of versioning works a bit differently between
- * operating systems. The most usual scheme is to set a major and a minor
- * number, and have the runtime loader check that the major number is equal
- * to what it was at application link time, while the minor number has to
- * be greater or equal to what it was at application link time. With this
- * scheme, the version number is usually part of the file name, like this:
- *
- * libcrypto.so.0.9
- *
- * Some unixen also make a softlink with the major verson number only:
- *
- * libcrypto.so.0
- *
- * On Tru64 and IRIX 6.x it works a little bit differently. There, the
- * shared library version is stored in the file, and is actually a series
- * of versions, separated by colons. The rightmost version present in the
- * library when linking an application is stored in the application to be
- * matched at run time. When the application is run, a check is done to
- * see if the library version stored in the application matches any of the
- * versions in the version string of the library itself.
- * This version string can be constructed in any way, depending on what
- * kind of matching is desired. However, to implement the same scheme as
- * the one used in the other unixen, all compatible versions, from lowest
- * to highest, should be part of the string. Consecutive builds would
- * give the following versions strings:
- *
- * 3.0
- * 3.0:3.1
- * 3.0:3.1:3.2
- * 4.0
- * 4.0:4.1
- *
- * Notice how version 4 is completely incompatible with version, and
- * therefore give the breach you can see.
- *
- * There may be other schemes as well that I haven't yet discovered.
- *
- * So, here's the way it works here: first of all, the library version
- * number doesn't need at all to match the overall OpenSSL version.
- * However, it's nice and more understandable if it actually does.
- * The current library version is stored in the macro SHLIB_VERSION_NUMBER,
- * which is just a piece of text in the format "M.m.e" (Major, minor, edit).
- * For the sake of Tru64, IRIX, and any other OS that behaves in similar ways,
- * we need to keep a history of version numbers, which is done in the
- * macro SHLIB_VERSION_HISTORY. The numbers are separated by colons and
- * should only keep the versions that are binary compatible with the current.
- */
-#define SHLIB_VERSION_HISTORY ""
-#define SHLIB_VERSION_NUMBER "1.0.0"
-
-
-#endif /* HEADER_OPENSSLV_H */
diff --git a/drivers/builtin_openssl/openssl/ossl_typ.h b/drivers/builtin_openssl/openssl/ossl_typ.h
deleted file mode 100644
index ea9227f6f9..0000000000
--- a/drivers/builtin_openssl/openssl/ossl_typ.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/* ====================================================================
- * Copyright (c) 1998-2001 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_OPENSSL_TYPES_H
-#define HEADER_OPENSSL_TYPES_H
-
-#include <openssl/e_os2.h>
-
-#ifdef NO_ASN1_TYPEDEFS
-#define ASN1_INTEGER ASN1_STRING
-#define ASN1_ENUMERATED ASN1_STRING
-#define ASN1_BIT_STRING ASN1_STRING
-#define ASN1_OCTET_STRING ASN1_STRING
-#define ASN1_PRINTABLESTRING ASN1_STRING
-#define ASN1_T61STRING ASN1_STRING
-#define ASN1_IA5STRING ASN1_STRING
-#define ASN1_UTCTIME ASN1_STRING
-#define ASN1_GENERALIZEDTIME ASN1_STRING
-#define ASN1_TIME ASN1_STRING
-#define ASN1_GENERALSTRING ASN1_STRING
-#define ASN1_UNIVERSALSTRING ASN1_STRING
-#define ASN1_BMPSTRING ASN1_STRING
-#define ASN1_VISIBLESTRING ASN1_STRING
-#define ASN1_UTF8STRING ASN1_STRING
-#define ASN1_BOOLEAN int
-#define ASN1_NULL int
-#else
-typedef struct asn1_string_st ASN1_INTEGER;
-typedef struct asn1_string_st ASN1_ENUMERATED;
-typedef struct asn1_string_st ASN1_BIT_STRING;
-typedef struct asn1_string_st ASN1_OCTET_STRING;
-typedef struct asn1_string_st ASN1_PRINTABLESTRING;
-typedef struct asn1_string_st ASN1_T61STRING;
-typedef struct asn1_string_st ASN1_IA5STRING;
-typedef struct asn1_string_st ASN1_GENERALSTRING;
-typedef struct asn1_string_st ASN1_UNIVERSALSTRING;
-typedef struct asn1_string_st ASN1_BMPSTRING;
-typedef struct asn1_string_st ASN1_UTCTIME;
-typedef struct asn1_string_st ASN1_TIME;
-typedef struct asn1_string_st ASN1_GENERALIZEDTIME;
-typedef struct asn1_string_st ASN1_VISIBLESTRING;
-typedef struct asn1_string_st ASN1_UTF8STRING;
-typedef struct asn1_string_st ASN1_STRING;
-typedef int ASN1_BOOLEAN;
-typedef int ASN1_NULL;
-#endif
-
-typedef struct ASN1_ITEM_st ASN1_ITEM;
-typedef struct asn1_pctx_st ASN1_PCTX;
-
-#ifdef OPENSSL_SYS_WIN32
-#undef X509_NAME
-#undef X509_EXTENSIONS
-#undef X509_CERT_PAIR
-#undef PKCS7_ISSUER_AND_SERIAL
-#undef OCSP_REQUEST
-#undef OCSP_RESPONSE
-#endif
-
-#ifdef BIGNUM
-#undef BIGNUM
-#endif
-typedef struct bignum_st BIGNUM;
-typedef struct bignum_ctx BN_CTX;
-typedef struct bn_blinding_st BN_BLINDING;
-typedef struct bn_mont_ctx_st BN_MONT_CTX;
-typedef struct bn_recp_ctx_st BN_RECP_CTX;
-typedef struct bn_gencb_st BN_GENCB;
-
-typedef struct buf_mem_st BUF_MEM;
-
-typedef struct evp_cipher_st EVP_CIPHER;
-typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
-typedef struct env_md_st EVP_MD;
-typedef struct env_md_ctx_st EVP_MD_CTX;
-typedef struct evp_pkey_st EVP_PKEY;
-
-typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD;
-
-typedef struct evp_pkey_method_st EVP_PKEY_METHOD;
-typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
-
-typedef struct dh_st DH;
-typedef struct dh_method DH_METHOD;
-
-typedef struct dsa_st DSA;
-typedef struct dsa_method DSA_METHOD;
-
-typedef struct rsa_st RSA;
-typedef struct rsa_meth_st RSA_METHOD;
-
-typedef struct rand_meth_st RAND_METHOD;
-
-typedef struct ecdh_method ECDH_METHOD;
-typedef struct ecdsa_method ECDSA_METHOD;
-
-typedef struct x509_st X509;
-typedef struct X509_algor_st X509_ALGOR;
-typedef struct X509_crl_st X509_CRL;
-typedef struct x509_crl_method_st X509_CRL_METHOD;
-typedef struct x509_revoked_st X509_REVOKED;
-typedef struct X509_name_st X509_NAME;
-typedef struct X509_pubkey_st X509_PUBKEY;
-typedef struct x509_store_st X509_STORE;
-typedef struct x509_store_ctx_st X509_STORE_CTX;
-
-typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO;
-
-typedef struct v3_ext_ctx X509V3_CTX;
-typedef struct conf_st CONF;
-
-typedef struct store_st STORE;
-typedef struct store_method_st STORE_METHOD;
-
-typedef struct ui_st UI;
-typedef struct ui_method_st UI_METHOD;
-
-typedef struct st_ERR_FNS ERR_FNS;
-
-typedef struct engine_st ENGINE;
-typedef struct ssl_st SSL;
-typedef struct ssl_ctx_st SSL_CTX;
-
-typedef struct X509_POLICY_NODE_st X509_POLICY_NODE;
-typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL;
-typedef struct X509_POLICY_TREE_st X509_POLICY_TREE;
-typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE;
-
-typedef struct AUTHORITY_KEYID_st AUTHORITY_KEYID;
-typedef struct DIST_POINT_st DIST_POINT;
-typedef struct ISSUING_DIST_POINT_st ISSUING_DIST_POINT;
-typedef struct NAME_CONSTRAINTS_st NAME_CONSTRAINTS;
-
- /* If placed in pkcs12.h, we end up with a circular depency with pkcs7.h */
-#define DECLARE_PKCS12_STACK_OF(type) /* Nothing */
-#define IMPLEMENT_PKCS12_STACK_OF(type) /* Nothing */
-
-typedef struct crypto_ex_data_st CRYPTO_EX_DATA;
-/* Callback types for crypto.h */
-typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
- int idx, long argl, void *argp);
-typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
- int idx, long argl, void *argp);
-typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d,
- int idx, long argl, void *argp);
-
-typedef struct ocsp_req_ctx_st OCSP_REQ_CTX;
-typedef struct ocsp_response_st OCSP_RESPONSE;
-typedef struct ocsp_responder_id_st OCSP_RESPID;
-
-#endif /* def HEADER_OPENSSL_TYPES_H */
diff --git a/drivers/builtin_openssl/openssl/pem.h b/drivers/builtin_openssl/openssl/pem.h
deleted file mode 100644
index 8a6ababe3a..0000000000
--- a/drivers/builtin_openssl/openssl/pem.h
+++ /dev/null
@@ -1,641 +0,0 @@
-/* crypto/pem/pem.h */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_PEM_H
-#define HEADER_PEM_H
-
-#include <openssl/e_os2.h>
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#ifndef OPENSSL_NO_STACK
-#include <openssl/stack.h>
-#endif
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-#include <openssl/pem2.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PEM_BUFSIZE 1024
-
-#define PEM_OBJ_UNDEF 0
-#define PEM_OBJ_X509 1
-#define PEM_OBJ_X509_REQ 2
-#define PEM_OBJ_CRL 3
-#define PEM_OBJ_SSL_SESSION 4
-#define PEM_OBJ_PRIV_KEY 10
-#define PEM_OBJ_PRIV_RSA 11
-#define PEM_OBJ_PRIV_DSA 12
-#define PEM_OBJ_PRIV_DH 13
-#define PEM_OBJ_PUB_RSA 14
-#define PEM_OBJ_PUB_DSA 15
-#define PEM_OBJ_PUB_DH 16
-#define PEM_OBJ_DHPARAMS 17
-#define PEM_OBJ_DSAPARAMS 18
-#define PEM_OBJ_PRIV_RSA_PUBLIC 19
-#define PEM_OBJ_PRIV_ECDSA 20
-#define PEM_OBJ_PUB_ECDSA 21
-#define PEM_OBJ_ECPARAMETERS 22
-
-#define PEM_ERROR 30
-#define PEM_DEK_DES_CBC 40
-#define PEM_DEK_IDEA_CBC 45
-#define PEM_DEK_DES_EDE 50
-#define PEM_DEK_DES_ECB 60
-#define PEM_DEK_RSA 70
-#define PEM_DEK_RSA_MD2 80
-#define PEM_DEK_RSA_MD5 90
-
-#define PEM_MD_MD2 NID_md2
-#define PEM_MD_MD5 NID_md5
-#define PEM_MD_SHA NID_sha
-#define PEM_MD_MD2_RSA NID_md2WithRSAEncryption
-#define PEM_MD_MD5_RSA NID_md5WithRSAEncryption
-#define PEM_MD_SHA_RSA NID_sha1WithRSAEncryption
-
-#define PEM_STRING_X509_OLD "X509 CERTIFICATE"
-#define PEM_STRING_X509 "CERTIFICATE"
-#define PEM_STRING_X509_PAIR "CERTIFICATE PAIR"
-#define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE"
-#define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST"
-#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST"
-#define PEM_STRING_X509_CRL "X509 CRL"
-#define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY"
-#define PEM_STRING_PUBLIC "PUBLIC KEY"
-#define PEM_STRING_RSA "RSA PRIVATE KEY"
-#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY"
-#define PEM_STRING_DSA "DSA PRIVATE KEY"
-#define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY"
-#define PEM_STRING_PKCS7 "PKCS7"
-#define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA"
-#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY"
-#define PEM_STRING_PKCS8INF "PRIVATE KEY"
-#define PEM_STRING_DHPARAMS "DH PARAMETERS"
-#define PEM_STRING_SSL_SESSION "SSL SESSION PARAMETERS"
-#define PEM_STRING_DSAPARAMS "DSA PARAMETERS"
-#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY"
-#define PEM_STRING_ECPARAMETERS "EC PARAMETERS"
-#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY"
-#define PEM_STRING_PARAMETERS "PARAMETERS"
-#define PEM_STRING_CMS "CMS"
-
- /* Note that this structure is initialised by PEM_SealInit and cleaned up
- by PEM_SealFinal (at least for now) */
-typedef struct PEM_Encode_Seal_st
- {
- EVP_ENCODE_CTX encode;
- EVP_MD_CTX md;
- EVP_CIPHER_CTX cipher;
- } PEM_ENCODE_SEAL_CTX;
-
-/* enc_type is one off */
-#define PEM_TYPE_ENCRYPTED 10
-#define PEM_TYPE_MIC_ONLY 20
-#define PEM_TYPE_MIC_CLEAR 30
-#define PEM_TYPE_CLEAR 40
-
-typedef struct pem_recip_st
- {
- char *name;
- X509_NAME *dn;
-
- int cipher;
- int key_enc;
- /* char iv[8]; unused and wrong size */
- } PEM_USER;
-
-typedef struct pem_ctx_st
- {
- int type; /* what type of object */
-
- struct {
- int version;
- int mode;
- } proc_type;
-
- char *domain;
-
- struct {
- int cipher;
- /* unused, and wrong size
- unsigned char iv[8]; */
- } DEK_info;
-
- PEM_USER *originator;
-
- int num_recipient;
- PEM_USER **recipient;
-
- /* XXX(ben): don#t think this is used!
- STACK *x509_chain; / * certificate chain */
- EVP_MD *md; /* signature type */
-
- int md_enc; /* is the md encrypted or not? */
- int md_len; /* length of md_data */
- char *md_data; /* message digest, could be pkey encrypted */
-
- EVP_CIPHER *dec; /* date encryption cipher */
- int key_len; /* key length */
- unsigned char *key; /* key */
- /* unused, and wrong size
- unsigned char iv[8]; */
-
-
- int data_enc; /* is the data encrypted */
- int data_len;
- unsigned char *data;
- } PEM_CTX;
-
-/* These macros make the PEM_read/PEM_write functions easier to maintain and
- * write. Now they are all implemented with either:
- * IMPLEMENT_PEM_rw(...) or IMPLEMENT_PEM_rw_cb(...)
- */
-
-#ifdef OPENSSL_NO_FP_API
-
-#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) /**/
-#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) /**/
-#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) /**/
-#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) /**/
-#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) /**/
-
-#else
-
-#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \
-type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\
-{ \
-return PEM_ASN1_read((d2i_of_void *)d2i_##asn1, str,fp,(void **)x,cb,u); \
-}
-
-#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \
-int PEM_write_##name(FILE *fp, type *x) \
-{ \
-return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL); \
-}
-
-#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \
-int PEM_write_##name(FILE *fp, const type *x) \
-{ \
-return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,(void *)x,NULL,NULL,0,NULL,NULL); \
-}
-
-#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \
-int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
- unsigned char *kstr, int klen, pem_password_cb *cb, \
- void *u) \
- { \
- return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \
- }
-
-#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \
-int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
- unsigned char *kstr, int klen, pem_password_cb *cb, \
- void *u) \
- { \
- return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \
- }
-
-#endif
-
-#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
-type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\
-{ \
-return PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \
-}
-
-#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \
-int PEM_write_bio_##name(BIO *bp, type *x) \
-{ \
-return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL); \
-}
-
-#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \
-int PEM_write_bio_##name(BIO *bp, const type *x) \
-{ \
-return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,NULL,NULL,0,NULL,NULL); \
-}
-
-#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \
-int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
- unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \
- { \
- return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u); \
- }
-
-#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \
-int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
- unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \
- { \
- return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,enc,kstr,klen,cb,u); \
- }
-
-#define IMPLEMENT_PEM_write(name, type, str, asn1) \
- IMPLEMENT_PEM_write_bio(name, type, str, asn1) \
- IMPLEMENT_PEM_write_fp(name, type, str, asn1)
-
-#define IMPLEMENT_PEM_write_const(name, type, str, asn1) \
- IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \
- IMPLEMENT_PEM_write_fp_const(name, type, str, asn1)
-
-#define IMPLEMENT_PEM_write_cb(name, type, str, asn1) \
- IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \
- IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1)
-
-#define IMPLEMENT_PEM_write_cb_const(name, type, str, asn1) \
- IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \
- IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1)
-
-#define IMPLEMENT_PEM_read(name, type, str, asn1) \
- IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
- IMPLEMENT_PEM_read_fp(name, type, str, asn1)
-
-#define IMPLEMENT_PEM_rw(name, type, str, asn1) \
- IMPLEMENT_PEM_read(name, type, str, asn1) \
- IMPLEMENT_PEM_write(name, type, str, asn1)
-
-#define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \
- IMPLEMENT_PEM_read(name, type, str, asn1) \
- IMPLEMENT_PEM_write_const(name, type, str, asn1)
-
-#define IMPLEMENT_PEM_rw_cb(name, type, str, asn1) \
- IMPLEMENT_PEM_read(name, type, str, asn1) \
- IMPLEMENT_PEM_write_cb(name, type, str, asn1)
-
-/* These are the same except they are for the declarations */
-
-#if defined(OPENSSL_NO_FP_API)
-
-#define DECLARE_PEM_read_fp(name, type) /**/
-#define DECLARE_PEM_write_fp(name, type) /**/
-#define DECLARE_PEM_write_cb_fp(name, type) /**/
-
-#else
-
-#define DECLARE_PEM_read_fp(name, type) \
- type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u);
-
-#define DECLARE_PEM_write_fp(name, type) \
- int PEM_write_##name(FILE *fp, type *x);
-
-#define DECLARE_PEM_write_fp_const(name, type) \
- int PEM_write_##name(FILE *fp, const type *x);
-
-#define DECLARE_PEM_write_cb_fp(name, type) \
- int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
- unsigned char *kstr, int klen, pem_password_cb *cb, void *u);
-
-#endif
-
-#ifndef OPENSSL_NO_BIO
-#define DECLARE_PEM_read_bio(name, type) \
- type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u);
-
-#define DECLARE_PEM_write_bio(name, type) \
- int PEM_write_bio_##name(BIO *bp, type *x);
-
-#define DECLARE_PEM_write_bio_const(name, type) \
- int PEM_write_bio_##name(BIO *bp, const type *x);
-
-#define DECLARE_PEM_write_cb_bio(name, type) \
- int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
- unsigned char *kstr, int klen, pem_password_cb *cb, void *u);
-
-#else
-
-#define DECLARE_PEM_read_bio(name, type) /**/
-#define DECLARE_PEM_write_bio(name, type) /**/
-#define DECLARE_PEM_write_bio_const(name, type) /**/
-#define DECLARE_PEM_write_cb_bio(name, type) /**/
-
-#endif
-
-#define DECLARE_PEM_write(name, type) \
- DECLARE_PEM_write_bio(name, type) \
- DECLARE_PEM_write_fp(name, type)
-
-#define DECLARE_PEM_write_const(name, type) \
- DECLARE_PEM_write_bio_const(name, type) \
- DECLARE_PEM_write_fp_const(name, type)
-
-#define DECLARE_PEM_write_cb(name, type) \
- DECLARE_PEM_write_cb_bio(name, type) \
- DECLARE_PEM_write_cb_fp(name, type)
-
-#define DECLARE_PEM_read(name, type) \
- DECLARE_PEM_read_bio(name, type) \
- DECLARE_PEM_read_fp(name, type)
-
-#define DECLARE_PEM_rw(name, type) \
- DECLARE_PEM_read(name, type) \
- DECLARE_PEM_write(name, type)
-
-#define DECLARE_PEM_rw_const(name, type) \
- DECLARE_PEM_read(name, type) \
- DECLARE_PEM_write_const(name, type)
-
-#define DECLARE_PEM_rw_cb(name, type) \
- DECLARE_PEM_read(name, type) \
- DECLARE_PEM_write_cb(name, type)
-
-#if 1
-/* "userdata": new with OpenSSL 0.9.4 */
-typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
-#else
-/* OpenSSL 0.9.3, 0.9.3a */
-typedef int pem_password_cb(char *buf, int size, int rwflag);
-#endif
-
-int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher);
-int PEM_do_header (EVP_CIPHER_INFO *cipher, unsigned char *data,long *len,
- pem_password_cb *callback,void *u);
-
-#ifndef OPENSSL_NO_BIO
-int PEM_read_bio(BIO *bp, char **name, char **header,
- unsigned char **data,long *len);
-int PEM_write_bio(BIO *bp,const char *name,char *hdr,unsigned char *data,
- long len);
-int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp,
- pem_password_cb *cb, void *u);
-void * PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp,
- void **x, pem_password_cb *cb, void *u);
-int PEM_ASN1_write_bio(i2d_of_void *i2d,const char *name,BIO *bp, void *x,
- const EVP_CIPHER *enc,unsigned char *kstr,int klen,
- pem_password_cb *cb, void *u);
-
-STACK_OF(X509_INFO) * PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u);
-int PEM_X509_INFO_write_bio(BIO *bp,X509_INFO *xi, EVP_CIPHER *enc,
- unsigned char *kstr, int klen, pem_password_cb *cd, void *u);
-#endif
-
-int PEM_read(FILE *fp, char **name, char **header,
- unsigned char **data,long *len);
-int PEM_write(FILE *fp,char *name,char *hdr,unsigned char *data,long len);
-void * PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
- pem_password_cb *cb, void *u);
-int PEM_ASN1_write(i2d_of_void *i2d,const char *name,FILE *fp,
- void *x,const EVP_CIPHER *enc,unsigned char *kstr,
- int klen,pem_password_cb *callback, void *u);
-STACK_OF(X509_INFO) * PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
- pem_password_cb *cb, void *u);
-
-int PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type,
- EVP_MD *md_type, unsigned char **ek, int *ekl,
- unsigned char *iv, EVP_PKEY **pubk, int npubk);
-void PEM_SealUpdate(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *out, int *outl,
- unsigned char *in, int inl);
-int PEM_SealFinal(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *sig,int *sigl,
- unsigned char *out, int *outl, EVP_PKEY *priv);
-
-void PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type);
-void PEM_SignUpdate(EVP_MD_CTX *ctx,unsigned char *d,unsigned int cnt);
-int PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
- unsigned int *siglen, EVP_PKEY *pkey);
-
-int PEM_def_callback(char *buf, int num, int w, void *key);
-void PEM_proc_type(char *buf, int type);
-void PEM_dek_info(char *buf, const char *type, int len, char *str);
-
-
-#include <openssl/symhacks.h>
-
-DECLARE_PEM_rw(X509, X509)
-
-DECLARE_PEM_rw(X509_AUX, X509)
-
-DECLARE_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR)
-
-DECLARE_PEM_rw(X509_REQ, X509_REQ)
-DECLARE_PEM_write(X509_REQ_NEW, X509_REQ)
-
-DECLARE_PEM_rw(X509_CRL, X509_CRL)
-
-DECLARE_PEM_rw(PKCS7, PKCS7)
-
-DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE)
-
-DECLARE_PEM_rw(PKCS8, X509_SIG)
-
-DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
-
-#ifndef OPENSSL_NO_RSA
-
-DECLARE_PEM_rw_cb(RSAPrivateKey, RSA)
-
-DECLARE_PEM_rw_const(RSAPublicKey, RSA)
-DECLARE_PEM_rw(RSA_PUBKEY, RSA)
-
-#endif
-
-#ifndef OPENSSL_NO_DSA
-
-DECLARE_PEM_rw_cb(DSAPrivateKey, DSA)
-
-DECLARE_PEM_rw(DSA_PUBKEY, DSA)
-
-DECLARE_PEM_rw_const(DSAparams, DSA)
-
-#endif
-
-#ifndef OPENSSL_NO_EC
-DECLARE_PEM_rw_const(ECPKParameters, EC_GROUP)
-DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY)
-DECLARE_PEM_rw(EC_PUBKEY, EC_KEY)
-#endif
-
-#ifndef OPENSSL_NO_DH
-
-DECLARE_PEM_rw_const(DHparams, DH)
-
-#endif
-
-DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY)
-
-DECLARE_PEM_rw(PUBKEY, EVP_PKEY)
-
-int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid,
- char *kstr, int klen,
- pem_password_cb *cb, void *u);
-int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *,
- char *, int, pem_password_cb *, void *);
-int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
- char *kstr, int klen,
- pem_password_cb *cb, void *u);
-int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid,
- char *kstr, int klen,
- pem_password_cb *cb, void *u);
-EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);
-
-int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
- char *kstr, int klen,
- pem_password_cb *cb, void *u);
-int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid,
- char *kstr, int klen,
- pem_password_cb *cb, void *u);
-int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid,
- char *kstr, int klen,
- pem_password_cb *cb, void *u);
-
-EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u);
-
-int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc,
- char *kstr,int klen, pem_password_cb *cd, void *u);
-
-EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x);
-int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x);
-
-
-EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length);
-EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length);
-EVP_PKEY *b2i_PrivateKey_bio(BIO *in);
-EVP_PKEY *b2i_PublicKey_bio(BIO *in);
-int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk);
-int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk);
-#ifndef OPENSSL_NO_RC4
-EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u);
-int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel,
- pem_password_cb *cb, void *u);
-#endif
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_PEM_strings(void);
-
-/* Error codes for the PEM functions. */
-
-/* Function codes. */
-#define PEM_F_B2I_DSS 127
-#define PEM_F_B2I_PVK_BIO 128
-#define PEM_F_B2I_RSA 129
-#define PEM_F_CHECK_BITLEN_DSA 130
-#define PEM_F_CHECK_BITLEN_RSA 131
-#define PEM_F_D2I_PKCS8PRIVATEKEY_BIO 120
-#define PEM_F_D2I_PKCS8PRIVATEKEY_FP 121
-#define PEM_F_DO_B2I 132
-#define PEM_F_DO_B2I_BIO 133
-#define PEM_F_DO_BLOB_HEADER 134
-#define PEM_F_DO_PK8PKEY 126
-#define PEM_F_DO_PK8PKEY_FP 125
-#define PEM_F_DO_PVK_BODY 135
-#define PEM_F_DO_PVK_HEADER 136
-#define PEM_F_I2B_PVK 137
-#define PEM_F_I2B_PVK_BIO 138
-#define PEM_F_LOAD_IV 101
-#define PEM_F_PEM_ASN1_READ 102
-#define PEM_F_PEM_ASN1_READ_BIO 103
-#define PEM_F_PEM_ASN1_WRITE 104
-#define PEM_F_PEM_ASN1_WRITE_BIO 105
-#define PEM_F_PEM_DEF_CALLBACK 100
-#define PEM_F_PEM_DO_HEADER 106
-#define PEM_F_PEM_F_PEM_WRITE_PKCS8PRIVATEKEY 118
-#define PEM_F_PEM_GET_EVP_CIPHER_INFO 107
-#define PEM_F_PEM_PK8PKEY 119
-#define PEM_F_PEM_READ 108
-#define PEM_F_PEM_READ_BIO 109
-#define PEM_F_PEM_READ_BIO_PARAMETERS 140
-#define PEM_F_PEM_READ_BIO_PRIVATEKEY 123
-#define PEM_F_PEM_READ_PRIVATEKEY 124
-#define PEM_F_PEM_SEALFINAL 110
-#define PEM_F_PEM_SEALINIT 111
-#define PEM_F_PEM_SIGNFINAL 112
-#define PEM_F_PEM_WRITE 113
-#define PEM_F_PEM_WRITE_BIO 114
-#define PEM_F_PEM_WRITE_PRIVATEKEY 139
-#define PEM_F_PEM_X509_INFO_READ 115
-#define PEM_F_PEM_X509_INFO_READ_BIO 116
-#define PEM_F_PEM_X509_INFO_WRITE_BIO 117
-
-/* Reason codes. */
-#define PEM_R_BAD_BASE64_DECODE 100
-#define PEM_R_BAD_DECRYPT 101
-#define PEM_R_BAD_END_LINE 102
-#define PEM_R_BAD_IV_CHARS 103
-#define PEM_R_BAD_MAGIC_NUMBER 116
-#define PEM_R_BAD_PASSWORD_READ 104
-#define PEM_R_BAD_VERSION_NUMBER 117
-#define PEM_R_BIO_WRITE_FAILURE 118
-#define PEM_R_CIPHER_IS_NULL 127
-#define PEM_R_ERROR_CONVERTING_PRIVATE_KEY 115
-#define PEM_R_EXPECTING_PRIVATE_KEY_BLOB 119
-#define PEM_R_EXPECTING_PUBLIC_KEY_BLOB 120
-#define PEM_R_INCONSISTENT_HEADER 121
-#define PEM_R_KEYBLOB_HEADER_PARSE_ERROR 122
-#define PEM_R_KEYBLOB_TOO_SHORT 123
-#define PEM_R_NOT_DEK_INFO 105
-#define PEM_R_NOT_ENCRYPTED 106
-#define PEM_R_NOT_PROC_TYPE 107
-#define PEM_R_NO_START_LINE 108
-#define PEM_R_PROBLEMS_GETTING_PASSWORD 109
-#define PEM_R_PUBLIC_KEY_NO_RSA 110
-#define PEM_R_PVK_DATA_TOO_SHORT 124
-#define PEM_R_PVK_TOO_SHORT 125
-#define PEM_R_READ_KEY 111
-#define PEM_R_SHORT_HEADER 112
-#define PEM_R_UNSUPPORTED_CIPHER 113
-#define PEM_R_UNSUPPORTED_ENCRYPTION 114
-#define PEM_R_UNSUPPORTED_KEY_COMPONENTS 126
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/pem2.h b/drivers/builtin_openssl/openssl/pem2.h
deleted file mode 100644
index f31790d69c..0000000000
--- a/drivers/builtin_openssl/openssl/pem2.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ====================================================================
- * Copyright (c) 1999 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-/*
- * This header only exists to break a circular dependency between pem and err
- * Ben 30 Jan 1999.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef HEADER_PEM_H
-void ERR_load_PEM_strings(void);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/drivers/builtin_openssl/openssl/pkcs12.h b/drivers/builtin_openssl/openssl/pkcs12.h
deleted file mode 100644
index b17eb9f42b..0000000000
--- a/drivers/builtin_openssl/openssl/pkcs12.h
+++ /dev/null
@@ -1,331 +0,0 @@
-/* pkcs12.h */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 1999.
- */
-/* ====================================================================
- * Copyright (c) 1999 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_PKCS12_H
-#define HEADER_PKCS12_H
-
-#include <openssl/bio.h>
-#include <openssl/x509.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PKCS12_KEY_ID 1
-#define PKCS12_IV_ID 2
-#define PKCS12_MAC_ID 3
-
-/* Default iteration count */
-#ifndef PKCS12_DEFAULT_ITER
-#define PKCS12_DEFAULT_ITER PKCS5_DEFAULT_ITER
-#endif
-
-#define PKCS12_MAC_KEY_LENGTH 20
-
-#define PKCS12_SALT_LEN 8
-
-/* Uncomment out next line for unicode password and names, otherwise ASCII */
-
-/*#define PBE_UNICODE*/
-
-#ifdef PBE_UNICODE
-#define PKCS12_key_gen PKCS12_key_gen_uni
-#define PKCS12_add_friendlyname PKCS12_add_friendlyname_uni
-#else
-#define PKCS12_key_gen PKCS12_key_gen_asc
-#define PKCS12_add_friendlyname PKCS12_add_friendlyname_asc
-#endif
-
-/* MS key usage constants */
-
-#define KEY_EX 0x10
-#define KEY_SIG 0x80
-
-typedef struct {
-X509_SIG *dinfo;
-ASN1_OCTET_STRING *salt;
-ASN1_INTEGER *iter; /* defaults to 1 */
-} PKCS12_MAC_DATA;
-
-typedef struct {
-ASN1_INTEGER *version;
-PKCS12_MAC_DATA *mac;
-PKCS7 *authsafes;
-} PKCS12;
-
-typedef struct {
-ASN1_OBJECT *type;
-union {
- struct pkcs12_bag_st *bag; /* secret, crl and certbag */
- struct pkcs8_priv_key_info_st *keybag; /* keybag */
- X509_SIG *shkeybag; /* shrouded key bag */
- STACK_OF(PKCS12_SAFEBAG) *safes;
- ASN1_TYPE *other;
-}value;
-STACK_OF(X509_ATTRIBUTE) *attrib;
-} PKCS12_SAFEBAG;
-
-DECLARE_STACK_OF(PKCS12_SAFEBAG)
-DECLARE_ASN1_SET_OF(PKCS12_SAFEBAG)
-DECLARE_PKCS12_STACK_OF(PKCS12_SAFEBAG)
-
-typedef struct pkcs12_bag_st {
-ASN1_OBJECT *type;
-union {
- ASN1_OCTET_STRING *x509cert;
- ASN1_OCTET_STRING *x509crl;
- ASN1_OCTET_STRING *octet;
- ASN1_IA5STRING *sdsicert;
- ASN1_TYPE *other; /* Secret or other bag */
-}value;
-} PKCS12_BAGS;
-
-#define PKCS12_ERROR 0
-#define PKCS12_OK 1
-
-/* Compatibility macros */
-
-#define M_PKCS12_x5092certbag PKCS12_x5092certbag
-#define M_PKCS12_x509crl2certbag PKCS12_x509crl2certbag
-
-#define M_PKCS12_certbag2x509 PKCS12_certbag2x509
-#define M_PKCS12_certbag2x509crl PKCS12_certbag2x509crl
-
-#define M_PKCS12_unpack_p7data PKCS12_unpack_p7data
-#define M_PKCS12_pack_authsafes PKCS12_pack_authsafes
-#define M_PKCS12_unpack_authsafes PKCS12_unpack_authsafes
-#define M_PKCS12_unpack_p7encdata PKCS12_unpack_p7encdata
-
-#define M_PKCS12_decrypt_skey PKCS12_decrypt_skey
-#define M_PKCS8_decrypt PKCS8_decrypt
-
-#define M_PKCS12_bag_type(bg) OBJ_obj2nid((bg)->type)
-#define M_PKCS12_cert_bag_type(bg) OBJ_obj2nid((bg)->value.bag->type)
-#define M_PKCS12_crl_bag_type M_PKCS12_cert_bag_type
-
-#define PKCS12_get_attr(bag, attr_nid) \
- PKCS12_get_attr_gen(bag->attrib, attr_nid)
-
-#define PKCS8_get_attr(p8, attr_nid) \
- PKCS12_get_attr_gen(p8->attributes, attr_nid)
-
-#define PKCS12_mac_present(p12) ((p12)->mac ? 1 : 0)
-
-
-PKCS12_SAFEBAG *PKCS12_x5092certbag(X509 *x509);
-PKCS12_SAFEBAG *PKCS12_x509crl2certbag(X509_CRL *crl);
-X509 *PKCS12_certbag2x509(PKCS12_SAFEBAG *bag);
-X509_CRL *PKCS12_certbag2x509crl(PKCS12_SAFEBAG *bag);
-
-PKCS12_SAFEBAG *PKCS12_item_pack_safebag(void *obj, const ASN1_ITEM *it, int nid1,
- int nid2);
-PKCS12_SAFEBAG *PKCS12_MAKE_KEYBAG(PKCS8_PRIV_KEY_INFO *p8);
-PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *p8, const char *pass, int passlen);
-PKCS8_PRIV_KEY_INFO *PKCS12_decrypt_skey(PKCS12_SAFEBAG *bag, const char *pass,
- int passlen);
-X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher,
- const char *pass, int passlen,
- unsigned char *salt, int saltlen, int iter,
- PKCS8_PRIV_KEY_INFO *p8);
-PKCS12_SAFEBAG *PKCS12_MAKE_SHKEYBAG(int pbe_nid, const char *pass,
- int passlen, unsigned char *salt,
- int saltlen, int iter,
- PKCS8_PRIV_KEY_INFO *p8);
-PKCS7 *PKCS12_pack_p7data(STACK_OF(PKCS12_SAFEBAG) *sk);
-STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7data(PKCS7 *p7);
-PKCS7 *PKCS12_pack_p7encdata(int pbe_nid, const char *pass, int passlen,
- unsigned char *salt, int saltlen, int iter,
- STACK_OF(PKCS12_SAFEBAG) *bags);
-STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7encdata(PKCS7 *p7, const char *pass, int passlen);
-
-int PKCS12_pack_authsafes(PKCS12 *p12, STACK_OF(PKCS7) *safes);
-STACK_OF(PKCS7) *PKCS12_unpack_authsafes(PKCS12 *p12);
-
-int PKCS12_add_localkeyid(PKCS12_SAFEBAG *bag, unsigned char *name, int namelen);
-int PKCS12_add_friendlyname_asc(PKCS12_SAFEBAG *bag, const char *name,
- int namelen);
-int PKCS12_add_CSPName_asc(PKCS12_SAFEBAG *bag, const char *name,
- int namelen);
-int PKCS12_add_friendlyname_uni(PKCS12_SAFEBAG *bag, const unsigned char *name,
- int namelen);
-int PKCS8_add_keyusage(PKCS8_PRIV_KEY_INFO *p8, int usage);
-ASN1_TYPE *PKCS12_get_attr_gen(STACK_OF(X509_ATTRIBUTE) *attrs, int attr_nid);
-char *PKCS12_get_friendlyname(PKCS12_SAFEBAG *bag);
-unsigned char *PKCS12_pbe_crypt(X509_ALGOR *algor, const char *pass,
- int passlen, unsigned char *in, int inlen,
- unsigned char **data, int *datalen, int en_de);
-void * PKCS12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it,
- const char *pass, int passlen, ASN1_OCTET_STRING *oct, int zbuf);
-ASN1_OCTET_STRING *PKCS12_item_i2d_encrypt(X509_ALGOR *algor, const ASN1_ITEM *it,
- const char *pass, int passlen,
- void *obj, int zbuf);
-PKCS12 *PKCS12_init(int mode);
-int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt,
- int saltlen, int id, int iter, int n,
- unsigned char *out, const EVP_MD *md_type);
-int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type);
-int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
- ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md_type,
- int en_de);
-int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
- unsigned char *mac, unsigned int *maclen);
-int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen);
-int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen,
- unsigned char *salt, int saltlen, int iter,
- const EVP_MD *md_type);
-int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt,
- int saltlen, const EVP_MD *md_type);
-unsigned char *OPENSSL_asc2uni(const char *asc, int asclen, unsigned char **uni, int *unilen);
-char *OPENSSL_uni2asc(unsigned char *uni, int unilen);
-
-DECLARE_ASN1_FUNCTIONS(PKCS12)
-DECLARE_ASN1_FUNCTIONS(PKCS12_MAC_DATA)
-DECLARE_ASN1_FUNCTIONS(PKCS12_SAFEBAG)
-DECLARE_ASN1_FUNCTIONS(PKCS12_BAGS)
-
-DECLARE_ASN1_ITEM(PKCS12_SAFEBAGS)
-DECLARE_ASN1_ITEM(PKCS12_AUTHSAFES)
-
-void PKCS12_PBE_add(void);
-int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert,
- STACK_OF(X509) **ca);
-PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert,
- STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter,
- int mac_iter, int keytype);
-
-PKCS12_SAFEBAG *PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert);
-PKCS12_SAFEBAG *PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags, EVP_PKEY *key,
- int key_usage, int iter,
- int key_nid, char *pass);
-int PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags,
- int safe_nid, int iter, char *pass);
-PKCS12 *PKCS12_add_safes(STACK_OF(PKCS7) *safes, int p7_nid);
-
-int i2d_PKCS12_bio(BIO *bp, PKCS12 *p12);
-int i2d_PKCS12_fp(FILE *fp, PKCS12 *p12);
-PKCS12 *d2i_PKCS12_bio(BIO *bp, PKCS12 **p12);
-PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12);
-int PKCS12_newpass(PKCS12 *p12, char *oldpass, char *newpass);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_PKCS12_strings(void);
-
-/* Error codes for the PKCS12 functions. */
-
-/* Function codes. */
-#define PKCS12_F_PARSE_BAG 129
-#define PKCS12_F_PARSE_BAGS 103
-#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME 100
-#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME_ASC 127
-#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME_UNI 102
-#define PKCS12_F_PKCS12_ADD_LOCALKEYID 104
-#define PKCS12_F_PKCS12_CREATE 105
-#define PKCS12_F_PKCS12_GEN_MAC 107
-#define PKCS12_F_PKCS12_INIT 109
-#define PKCS12_F_PKCS12_ITEM_DECRYPT_D2I 106
-#define PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT 108
-#define PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG 117
-#define PKCS12_F_PKCS12_KEY_GEN_ASC 110
-#define PKCS12_F_PKCS12_KEY_GEN_UNI 111
-#define PKCS12_F_PKCS12_MAKE_KEYBAG 112
-#define PKCS12_F_PKCS12_MAKE_SHKEYBAG 113
-#define PKCS12_F_PKCS12_NEWPASS 128
-#define PKCS12_F_PKCS12_PACK_P7DATA 114
-#define PKCS12_F_PKCS12_PACK_P7ENCDATA 115
-#define PKCS12_F_PKCS12_PARSE 118
-#define PKCS12_F_PKCS12_PBE_CRYPT 119
-#define PKCS12_F_PKCS12_PBE_KEYIVGEN 120
-#define PKCS12_F_PKCS12_SETUP_MAC 122
-#define PKCS12_F_PKCS12_SET_MAC 123
-#define PKCS12_F_PKCS12_UNPACK_AUTHSAFES 130
-#define PKCS12_F_PKCS12_UNPACK_P7DATA 131
-#define PKCS12_F_PKCS12_VERIFY_MAC 126
-#define PKCS12_F_PKCS8_ADD_KEYUSAGE 124
-#define PKCS12_F_PKCS8_ENCRYPT 125
-
-/* Reason codes. */
-#define PKCS12_R_CANT_PACK_STRUCTURE 100
-#define PKCS12_R_CONTENT_TYPE_NOT_DATA 121
-#define PKCS12_R_DECODE_ERROR 101
-#define PKCS12_R_ENCODE_ERROR 102
-#define PKCS12_R_ENCRYPT_ERROR 103
-#define PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE 120
-#define PKCS12_R_INVALID_NULL_ARGUMENT 104
-#define PKCS12_R_INVALID_NULL_PKCS12_POINTER 105
-#define PKCS12_R_IV_GEN_ERROR 106
-#define PKCS12_R_KEY_GEN_ERROR 107
-#define PKCS12_R_MAC_ABSENT 108
-#define PKCS12_R_MAC_GENERATION_ERROR 109
-#define PKCS12_R_MAC_SETUP_ERROR 110
-#define PKCS12_R_MAC_STRING_SET_ERROR 111
-#define PKCS12_R_MAC_VERIFY_ERROR 112
-#define PKCS12_R_MAC_VERIFY_FAILURE 113
-#define PKCS12_R_PARSE_ERROR 114
-#define PKCS12_R_PKCS12_ALGOR_CIPHERINIT_ERROR 115
-#define PKCS12_R_PKCS12_CIPHERFINAL_ERROR 116
-#define PKCS12_R_PKCS12_PBE_CRYPT_ERROR 117
-#define PKCS12_R_UNKNOWN_DIGEST_ALGORITHM 118
-#define PKCS12_R_UNSUPPORTED_PKCS12_MODE 119
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/pkcs7.h b/drivers/builtin_openssl/openssl/pkcs7.h
deleted file mode 100644
index e4d443193c..0000000000
--- a/drivers/builtin_openssl/openssl/pkcs7.h
+++ /dev/null
@@ -1,499 +0,0 @@
-/* crypto/pkcs7/pkcs7.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_PKCS7_H
-#define HEADER_PKCS7_H
-
-#include <openssl/asn1.h>
-#include <openssl/bio.h>
-#include <openssl/e_os2.h>
-
-#include <openssl/symhacks.h>
-#include <openssl/ossl_typ.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_SYS_WIN32
-/* Under Win32 thes are defined in wincrypt.h */
-#undef PKCS7_ISSUER_AND_SERIAL
-#undef PKCS7_SIGNER_INFO
-#endif
-
-/*
-Encryption_ID DES-CBC
-Digest_ID MD5
-Digest_Encryption_ID rsaEncryption
-Key_Encryption_ID rsaEncryption
-*/
-
-typedef struct pkcs7_issuer_and_serial_st
- {
- X509_NAME *issuer;
- ASN1_INTEGER *serial;
- } PKCS7_ISSUER_AND_SERIAL;
-
-typedef struct pkcs7_signer_info_st
- {
- ASN1_INTEGER *version; /* version 1 */
- PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;
- X509_ALGOR *digest_alg;
- STACK_OF(X509_ATTRIBUTE) *auth_attr; /* [ 0 ] */
- X509_ALGOR *digest_enc_alg;
- ASN1_OCTET_STRING *enc_digest;
- STACK_OF(X509_ATTRIBUTE) *unauth_attr; /* [ 1 ] */
-
- /* The private key to sign with */
- EVP_PKEY *pkey;
- } PKCS7_SIGNER_INFO;
-
-DECLARE_STACK_OF(PKCS7_SIGNER_INFO)
-DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO)
-
-typedef struct pkcs7_recip_info_st
- {
- ASN1_INTEGER *version; /* version 0 */
- PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;
- X509_ALGOR *key_enc_algor;
- ASN1_OCTET_STRING *enc_key;
- X509 *cert; /* get the pub-key from this */
- } PKCS7_RECIP_INFO;
-
-DECLARE_STACK_OF(PKCS7_RECIP_INFO)
-DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO)
-
-typedef struct pkcs7_signed_st
- {
- ASN1_INTEGER *version; /* version 1 */
- STACK_OF(X509_ALGOR) *md_algs; /* md used */
- STACK_OF(X509) *cert; /* [ 0 ] */
- STACK_OF(X509_CRL) *crl; /* [ 1 ] */
- STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
-
- struct pkcs7_st *contents;
- } PKCS7_SIGNED;
-/* The above structure is very very similar to PKCS7_SIGN_ENVELOPE.
- * How about merging the two */
-
-typedef struct pkcs7_enc_content_st
- {
- ASN1_OBJECT *content_type;
- X509_ALGOR *algorithm;
- ASN1_OCTET_STRING *enc_data; /* [ 0 ] */
- const EVP_CIPHER *cipher;
- } PKCS7_ENC_CONTENT;
-
-typedef struct pkcs7_enveloped_st
- {
- ASN1_INTEGER *version; /* version 0 */
- STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
- PKCS7_ENC_CONTENT *enc_data;
- } PKCS7_ENVELOPE;
-
-typedef struct pkcs7_signedandenveloped_st
- {
- ASN1_INTEGER *version; /* version 1 */
- STACK_OF(X509_ALGOR) *md_algs; /* md used */
- STACK_OF(X509) *cert; /* [ 0 ] */
- STACK_OF(X509_CRL) *crl; /* [ 1 ] */
- STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
-
- PKCS7_ENC_CONTENT *enc_data;
- STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
- } PKCS7_SIGN_ENVELOPE;
-
-typedef struct pkcs7_digest_st
- {
- ASN1_INTEGER *version; /* version 0 */
- X509_ALGOR *md; /* md used */
- struct pkcs7_st *contents;
- ASN1_OCTET_STRING *digest;
- } PKCS7_DIGEST;
-
-typedef struct pkcs7_encrypted_st
- {
- ASN1_INTEGER *version; /* version 0 */
- PKCS7_ENC_CONTENT *enc_data;
- } PKCS7_ENCRYPT;
-
-typedef struct pkcs7_st
- {
- /* The following is non NULL if it contains ASN1 encoding of
- * this structure */
- unsigned char *asn1;
- long length;
-
-#define PKCS7_S_HEADER 0
-#define PKCS7_S_BODY 1
-#define PKCS7_S_TAIL 2
- int state; /* used during processing */
-
- int detached;
-
- ASN1_OBJECT *type;
- /* content as defined by the type */
- /* all encryption/message digests are applied to the 'contents',
- * leaving out the 'type' field. */
- union {
- char *ptr;
-
- /* NID_pkcs7_data */
- ASN1_OCTET_STRING *data;
-
- /* NID_pkcs7_signed */
- PKCS7_SIGNED *sign;
-
- /* NID_pkcs7_enveloped */
- PKCS7_ENVELOPE *enveloped;
-
- /* NID_pkcs7_signedAndEnveloped */
- PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
-
- /* NID_pkcs7_digest */
- PKCS7_DIGEST *digest;
-
- /* NID_pkcs7_encrypted */
- PKCS7_ENCRYPT *encrypted;
-
- /* Anything else */
- ASN1_TYPE *other;
- } d;
- } PKCS7;
-
-DECLARE_STACK_OF(PKCS7)
-DECLARE_ASN1_SET_OF(PKCS7)
-DECLARE_PKCS12_STACK_OF(PKCS7)
-
-#define PKCS7_OP_SET_DETACHED_SIGNATURE 1
-#define PKCS7_OP_GET_DETACHED_SIGNATURE 2
-
-#define PKCS7_get_signed_attributes(si) ((si)->auth_attr)
-#define PKCS7_get_attributes(si) ((si)->unauth_attr)
-
-#define PKCS7_type_is_signed(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_signed)
-#define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
-#define PKCS7_type_is_enveloped(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_enveloped)
-#define PKCS7_type_is_signedAndEnveloped(a) \
- (OBJ_obj2nid((a)->type) == NID_pkcs7_signedAndEnveloped)
-#define PKCS7_type_is_data(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_data)
-#define PKCS7_type_is_digest(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
-#define PKCS7_type_is_encrypted(a) \
- (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
-
-#define PKCS7_type_is_digest(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
-
-#define PKCS7_set_detached(p,v) \
- PKCS7_ctrl(p,PKCS7_OP_SET_DETACHED_SIGNATURE,v,NULL)
-#define PKCS7_get_detached(p) \
- PKCS7_ctrl(p,PKCS7_OP_GET_DETACHED_SIGNATURE,0,NULL)
-
-#define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7))
-
-/* S/MIME related flags */
-
-#define PKCS7_TEXT 0x1
-#define PKCS7_NOCERTS 0x2
-#define PKCS7_NOSIGS 0x4
-#define PKCS7_NOCHAIN 0x8
-#define PKCS7_NOINTERN 0x10
-#define PKCS7_NOVERIFY 0x20
-#define PKCS7_DETACHED 0x40
-#define PKCS7_BINARY 0x80
-#define PKCS7_NOATTR 0x100
-#define PKCS7_NOSMIMECAP 0x200
-#define PKCS7_NOOLDMIMETYPE 0x400
-#define PKCS7_CRLFEOL 0x800
-#define PKCS7_STREAM 0x1000
-#define PKCS7_NOCRL 0x2000
-#define PKCS7_PARTIAL 0x4000
-#define PKCS7_REUSE_DIGEST 0x8000
-
-/* Flags: for compatibility with older code */
-
-#define SMIME_TEXT PKCS7_TEXT
-#define SMIME_NOCERTS PKCS7_NOCERTS
-#define SMIME_NOSIGS PKCS7_NOSIGS
-#define SMIME_NOCHAIN PKCS7_NOCHAIN
-#define SMIME_NOINTERN PKCS7_NOINTERN
-#define SMIME_NOVERIFY PKCS7_NOVERIFY
-#define SMIME_DETACHED PKCS7_DETACHED
-#define SMIME_BINARY PKCS7_BINARY
-#define SMIME_NOATTR PKCS7_NOATTR
-
-DECLARE_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL)
-
-int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data,const EVP_MD *type,
- unsigned char *md,unsigned int *len);
-#ifndef OPENSSL_NO_FP_API
-PKCS7 *d2i_PKCS7_fp(FILE *fp,PKCS7 **p7);
-int i2d_PKCS7_fp(FILE *fp,PKCS7 *p7);
-#endif
-PKCS7 *PKCS7_dup(PKCS7 *p7);
-PKCS7 *d2i_PKCS7_bio(BIO *bp,PKCS7 **p7);
-int i2d_PKCS7_bio(BIO *bp,PKCS7 *p7);
-int i2d_PKCS7_bio_stream(BIO *out, PKCS7 *p7, BIO *in, int flags);
-int PEM_write_bio_PKCS7_stream(BIO *out, PKCS7 *p7, BIO *in, int flags);
-
-DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNER_INFO)
-DECLARE_ASN1_FUNCTIONS(PKCS7_RECIP_INFO)
-DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNED)
-DECLARE_ASN1_FUNCTIONS(PKCS7_ENC_CONTENT)
-DECLARE_ASN1_FUNCTIONS(PKCS7_ENVELOPE)
-DECLARE_ASN1_FUNCTIONS(PKCS7_SIGN_ENVELOPE)
-DECLARE_ASN1_FUNCTIONS(PKCS7_DIGEST)
-DECLARE_ASN1_FUNCTIONS(PKCS7_ENCRYPT)
-DECLARE_ASN1_FUNCTIONS(PKCS7)
-
-DECLARE_ASN1_ITEM(PKCS7_ATTR_SIGN)
-DECLARE_ASN1_ITEM(PKCS7_ATTR_VERIFY)
-
-DECLARE_ASN1_NDEF_FUNCTION(PKCS7)
-DECLARE_ASN1_PRINT_FUNCTION(PKCS7)
-
-long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg);
-
-int PKCS7_set_type(PKCS7 *p7, int type);
-int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other);
-int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data);
-int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey,
- const EVP_MD *dgst);
-int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si);
-int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *p7i);
-int PKCS7_add_certificate(PKCS7 *p7, X509 *x509);
-int PKCS7_add_crl(PKCS7 *p7, X509_CRL *x509);
-int PKCS7_content_new(PKCS7 *p7, int nid);
-int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx,
- BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si);
-int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
- X509 *x509);
-
-BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio);
-int PKCS7_dataFinal(PKCS7 *p7, BIO *bio);
-BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert);
-
-
-PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509,
- EVP_PKEY *pkey, const EVP_MD *dgst);
-X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
-int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md);
-STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7);
-
-PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509);
-void PKCS7_SIGNER_INFO_get0_algs(PKCS7_SIGNER_INFO *si, EVP_PKEY **pk,
- X509_ALGOR **pdig, X509_ALGOR **psig);
-void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc);
-int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri);
-int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509);
-int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher);
-int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7);
-
-PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx);
-ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk);
-int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si,int nid,int type,
- void *data);
-int PKCS7_add_attribute (PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
- void *value);
-ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid);
-ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid);
-int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
- STACK_OF(X509_ATTRIBUTE) *sk);
-int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,STACK_OF(X509_ATTRIBUTE) *sk);
-
-
-PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
- BIO *data, int flags);
-
-PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7,
- X509 *signcert, EVP_PKEY *pkey, const EVP_MD *md,
- int flags);
-
-int PKCS7_final(PKCS7 *p7, BIO *data, int flags);
-int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
- BIO *indata, BIO *out, int flags);
-STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags);
-PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
- int flags);
-int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags);
-
-int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si,
- STACK_OF(X509_ALGOR) *cap);
-STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si);
-int PKCS7_simple_smimecap(STACK_OF(X509_ALGOR) *sk, int nid, int arg);
-
-int PKCS7_add_attrib_content_type(PKCS7_SIGNER_INFO *si, ASN1_OBJECT *coid);
-int PKCS7_add0_attrib_signing_time(PKCS7_SIGNER_INFO *si, ASN1_TIME *t);
-int PKCS7_add1_attrib_digest(PKCS7_SIGNER_INFO *si,
- const unsigned char *md, int mdlen);
-
-int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags);
-PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont);
-
-BIO *BIO_new_PKCS7(BIO *out, PKCS7 *p7);
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_PKCS7_strings(void);
-
-/* Error codes for the PKCS7 functions. */
-
-/* Function codes. */
-#define PKCS7_F_B64_READ_PKCS7 120
-#define PKCS7_F_B64_WRITE_PKCS7 121
-#define PKCS7_F_DO_PKCS7_SIGNED_ATTRIB 136
-#define PKCS7_F_I2D_PKCS7_BIO_STREAM 140
-#define PKCS7_F_PKCS7_ADD0_ATTRIB_SIGNING_TIME 135
-#define PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP 118
-#define PKCS7_F_PKCS7_ADD_CERTIFICATE 100
-#define PKCS7_F_PKCS7_ADD_CRL 101
-#define PKCS7_F_PKCS7_ADD_RECIPIENT_INFO 102
-#define PKCS7_F_PKCS7_ADD_SIGNATURE 131
-#define PKCS7_F_PKCS7_ADD_SIGNER 103
-#define PKCS7_F_PKCS7_BIO_ADD_DIGEST 125
-#define PKCS7_F_PKCS7_COPY_EXISTING_DIGEST 138
-#define PKCS7_F_PKCS7_CTRL 104
-#define PKCS7_F_PKCS7_DATADECODE 112
-#define PKCS7_F_PKCS7_DATAFINAL 128
-#define PKCS7_F_PKCS7_DATAINIT 105
-#define PKCS7_F_PKCS7_DATASIGN 106
-#define PKCS7_F_PKCS7_DATAVERIFY 107
-#define PKCS7_F_PKCS7_DECRYPT 114
-#define PKCS7_F_PKCS7_DECRYPT_RINFO 133
-#define PKCS7_F_PKCS7_ENCODE_RINFO 132
-#define PKCS7_F_PKCS7_ENCRYPT 115
-#define PKCS7_F_PKCS7_FINAL 134
-#define PKCS7_F_PKCS7_FIND_DIGEST 127
-#define PKCS7_F_PKCS7_GET0_SIGNERS 124
-#define PKCS7_F_PKCS7_RECIP_INFO_SET 130
-#define PKCS7_F_PKCS7_SET_CIPHER 108
-#define PKCS7_F_PKCS7_SET_CONTENT 109
-#define PKCS7_F_PKCS7_SET_DIGEST 126
-#define PKCS7_F_PKCS7_SET_TYPE 110
-#define PKCS7_F_PKCS7_SIGN 116
-#define PKCS7_F_PKCS7_SIGNATUREVERIFY 113
-#define PKCS7_F_PKCS7_SIGNER_INFO_SET 129
-#define PKCS7_F_PKCS7_SIGNER_INFO_SIGN 139
-#define PKCS7_F_PKCS7_SIGN_ADD_SIGNER 137
-#define PKCS7_F_PKCS7_SIMPLE_SMIMECAP 119
-#define PKCS7_F_PKCS7_VERIFY 117
-#define PKCS7_F_SMIME_READ_PKCS7 122
-#define PKCS7_F_SMIME_TEXT 123
-
-/* Reason codes. */
-#define PKCS7_R_CERTIFICATE_VERIFY_ERROR 117
-#define PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 144
-#define PKCS7_R_CIPHER_NOT_INITIALIZED 116
-#define PKCS7_R_CONTENT_AND_DATA_PRESENT 118
-#define PKCS7_R_CTRL_ERROR 152
-#define PKCS7_R_DECODE_ERROR 130
-#define PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH 100
-#define PKCS7_R_DECRYPT_ERROR 119
-#define PKCS7_R_DIGEST_FAILURE 101
-#define PKCS7_R_ENCRYPTION_CTRL_FAILURE 149
-#define PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 150
-#define PKCS7_R_ERROR_ADDING_RECIPIENT 120
-#define PKCS7_R_ERROR_SETTING_CIPHER 121
-#define PKCS7_R_INVALID_MIME_TYPE 131
-#define PKCS7_R_INVALID_NULL_POINTER 143
-#define PKCS7_R_MIME_NO_CONTENT_TYPE 132
-#define PKCS7_R_MIME_PARSE_ERROR 133
-#define PKCS7_R_MIME_SIG_PARSE_ERROR 134
-#define PKCS7_R_MISSING_CERIPEND_INFO 103
-#define PKCS7_R_NO_CONTENT 122
-#define PKCS7_R_NO_CONTENT_TYPE 135
-#define PKCS7_R_NO_DEFAULT_DIGEST 151
-#define PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND 154
-#define PKCS7_R_NO_MULTIPART_BODY_FAILURE 136
-#define PKCS7_R_NO_MULTIPART_BOUNDARY 137
-#define PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE 115
-#define PKCS7_R_NO_RECIPIENT_MATCHES_KEY 146
-#define PKCS7_R_NO_SIGNATURES_ON_DATA 123
-#define PKCS7_R_NO_SIGNERS 142
-#define PKCS7_R_NO_SIG_CONTENT_TYPE 138
-#define PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE 104
-#define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR 124
-#define PKCS7_R_PKCS7_ADD_SIGNER_ERROR 153
-#define PKCS7_R_PKCS7_DATAFINAL 126
-#define PKCS7_R_PKCS7_DATAFINAL_ERROR 125
-#define PKCS7_R_PKCS7_DATASIGN 145
-#define PKCS7_R_PKCS7_PARSE_ERROR 139
-#define PKCS7_R_PKCS7_SIG_PARSE_ERROR 140
-#define PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 127
-#define PKCS7_R_SIGNATURE_FAILURE 105
-#define PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND 128
-#define PKCS7_R_SIGNING_CTRL_FAILURE 147
-#define PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 148
-#define PKCS7_R_SIG_INVALID_MIME_TYPE 141
-#define PKCS7_R_SMIME_TEXT_ERROR 129
-#define PKCS7_R_UNABLE_TO_FIND_CERTIFICATE 106
-#define PKCS7_R_UNABLE_TO_FIND_MEM_BIO 107
-#define PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST 108
-#define PKCS7_R_UNKNOWN_DIGEST_TYPE 109
-#define PKCS7_R_UNKNOWN_OPERATION 110
-#define PKCS7_R_UNSUPPORTED_CIPHER_TYPE 111
-#define PKCS7_R_UNSUPPORTED_CONTENT_TYPE 112
-#define PKCS7_R_WRONG_CONTENT_TYPE 113
-#define PKCS7_R_WRONG_PKCS7_TYPE 114
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/pqueue.h b/drivers/builtin_openssl/openssl/pqueue.h
deleted file mode 100644
index 87fc9037c8..0000000000
--- a/drivers/builtin_openssl/openssl/pqueue.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* crypto/pqueue/pqueue.h */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_PQUEUE_H
-#define HEADER_PQUEUE_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-typedef struct _pqueue *pqueue;
-
-typedef struct _pitem
- {
- unsigned char priority[8]; /* 64-bit value in big-endian encoding */
- void *data;
- struct _pitem *next;
- } pitem;
-
-typedef struct _pitem *piterator;
-
-pitem *pitem_new(unsigned char *prio64be, void *data);
-void pitem_free(pitem *item);
-
-pqueue pqueue_new(void);
-void pqueue_free(pqueue pq);
-
-pitem *pqueue_insert(pqueue pq, pitem *item);
-pitem *pqueue_peek(pqueue pq);
-pitem *pqueue_pop(pqueue pq);
-pitem *pqueue_find(pqueue pq, unsigned char *prio64be);
-pitem *pqueue_iterator(pqueue pq);
-pitem *pqueue_next(piterator *iter);
-
-void pqueue_print(pqueue pq);
-int pqueue_size(pqueue pq);
-
-#endif /* ! HEADER_PQUEUE_H */
diff --git a/drivers/builtin_openssl/openssl/rand.h b/drivers/builtin_openssl/openssl/rand.h
deleted file mode 100644
index 367ece93c7..0000000000
--- a/drivers/builtin_openssl/openssl/rand.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* crypto/rand/rand.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_RAND_H
-#define HEADER_RAND_H
-
-#include <stdlib.h>
-#include <openssl/ossl_typ.h>
-#include <openssl/e_os2.h>
-
-#if defined(OPENSSL_SYS_WINDOWS)
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(OPENSSL_FIPS)
-#define FIPS_RAND_SIZE_T size_t
-#endif
-
-/* Already defined in ossl_typ.h */
-/* typedef struct rand_meth_st RAND_METHOD; */
-
-struct rand_meth_st
- {
- void (*seed)(const void *buf, int num);
- int (*bytes)(unsigned char *buf, int num);
- void (*cleanup)(void);
- void (*add)(const void *buf, int num, double entropy);
- int (*pseudorand)(unsigned char *buf, int num);
- int (*status)(void);
- };
-
-#ifdef BN_DEBUG
-extern int rand_predictable;
-#endif
-
-int RAND_set_rand_method(const RAND_METHOD *meth);
-const RAND_METHOD *RAND_get_rand_method(void);
-#ifndef OPENSSL_NO_ENGINE
-int RAND_set_rand_engine(ENGINE *engine);
-#endif
-RAND_METHOD *RAND_SSLeay(void);
-void RAND_cleanup(void );
-int RAND_bytes(unsigned char *buf,int num);
-int RAND_pseudo_bytes(unsigned char *buf,int num);
-void RAND_seed(const void *buf,int num);
-void RAND_add(const void *buf,int num,double entropy);
-int RAND_load_file(const char *file,long max_bytes);
-int RAND_write_file(const char *file);
-const char *RAND_file_name(char *file,size_t num);
-int RAND_status(void);
-int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes);
-int RAND_egd(const char *path);
-int RAND_egd_bytes(const char *path,int bytes);
-int RAND_poll(void);
-
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-
-void RAND_screen(void);
-int RAND_event(UINT, WPARAM, LPARAM);
-
-#endif
-
-#ifdef OPENSSL_FIPS
-void RAND_set_fips_drbg_type(int type, int flags);
-int RAND_init_fips(void);
-#endif
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_RAND_strings(void);
-
-/* Error codes for the RAND functions. */
-
-/* Function codes. */
-#define RAND_F_RAND_GET_RAND_METHOD 101
-#define RAND_F_RAND_INIT_FIPS 102
-#define RAND_F_SSLEAY_RAND_BYTES 100
-
-/* Reason codes. */
-#define RAND_R_DUAL_EC_DRBG_DISABLED 104
-#define RAND_R_ERROR_INITIALISING_DRBG 102
-#define RAND_R_ERROR_INSTANTIATING_DRBG 103
-#define RAND_R_NO_FIPS_RANDOM_METHOD_SET 101
-#define RAND_R_PRNG_NOT_SEEDED 100
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/rc2.h b/drivers/builtin_openssl/openssl/rc2.h
deleted file mode 100644
index e542ec94ff..0000000000
--- a/drivers/builtin_openssl/openssl/rc2.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* crypto/rc2/rc2.h */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_RC2_H
-#define HEADER_RC2_H
-
-#include <openssl/opensslconf.h> /* OPENSSL_NO_RC2, RC2_INT */
-#ifdef OPENSSL_NO_RC2
-#error RC2 is disabled.
-#endif
-
-#define RC2_ENCRYPT 1
-#define RC2_DECRYPT 0
-
-#define RC2_BLOCK 8
-#define RC2_KEY_LENGTH 16
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct rc2_key_st
- {
- RC2_INT data[64];
- } RC2_KEY;
-
-#ifdef OPENSSL_FIPS
-void private_RC2_set_key(RC2_KEY *key, int len, const unsigned char *data,int bits);
-#endif
-void RC2_set_key(RC2_KEY *key, int len, const unsigned char *data,int bits);
-void RC2_ecb_encrypt(const unsigned char *in,unsigned char *out,RC2_KEY *key,
- int enc);
-void RC2_encrypt(unsigned long *data,RC2_KEY *key);
-void RC2_decrypt(unsigned long *data,RC2_KEY *key);
-void RC2_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
- RC2_KEY *ks, unsigned char *iv, int enc);
-void RC2_cfb64_encrypt(const unsigned char *in, unsigned char *out,
- long length, RC2_KEY *schedule, unsigned char *ivec,
- int *num, int enc);
-void RC2_ofb64_encrypt(const unsigned char *in, unsigned char *out,
- long length, RC2_KEY *schedule, unsigned char *ivec,
- int *num);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/rc4.h b/drivers/builtin_openssl/openssl/rc4.h
deleted file mode 100644
index 88ceb46bc5..0000000000
--- a/drivers/builtin_openssl/openssl/rc4.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* crypto/rc4/rc4.h */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_RC4_H
-#define HEADER_RC4_H
-
-#include <openssl/opensslconf.h> /* OPENSSL_NO_RC4, RC4_INT */
-#ifdef OPENSSL_NO_RC4
-#error RC4 is disabled.
-#endif
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct rc4_key_st
- {
- RC4_INT x,y;
- RC4_INT data[256];
- } RC4_KEY;
-
-
-const char *RC4_options(void);
-void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data);
-void private_RC4_set_key(RC4_KEY *key, int len, const unsigned char *data);
-void RC4(RC4_KEY *key, size_t len, const unsigned char *indata,
- unsigned char *outdata);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/ripemd.h b/drivers/builtin_openssl/openssl/ripemd.h
deleted file mode 100644
index 189bd8c90e..0000000000
--- a/drivers/builtin_openssl/openssl/ripemd.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* crypto/ripemd/ripemd.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_RIPEMD_H
-#define HEADER_RIPEMD_H
-
-#include <openssl/e_os2.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_NO_RIPEMD
-#error RIPEMD is disabled.
-#endif
-
-#if defined(__LP32__)
-#define RIPEMD160_LONG unsigned long
-#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
-#define RIPEMD160_LONG unsigned long
-#define RIPEMD160_LONG_LOG2 3
-#else
-#define RIPEMD160_LONG unsigned int
-#endif
-
-#define RIPEMD160_CBLOCK 64
-#define RIPEMD160_LBLOCK (RIPEMD160_CBLOCK/4)
-#define RIPEMD160_DIGEST_LENGTH 20
-
-typedef struct RIPEMD160state_st
- {
- RIPEMD160_LONG A,B,C,D,E;
- RIPEMD160_LONG Nl,Nh;
- RIPEMD160_LONG data[RIPEMD160_LBLOCK];
- unsigned int num;
- } RIPEMD160_CTX;
-
-#ifdef OPENSSL_FIPS
-int private_RIPEMD160_Init(RIPEMD160_CTX *c);
-#endif
-int RIPEMD160_Init(RIPEMD160_CTX *c);
-int RIPEMD160_Update(RIPEMD160_CTX *c, const void *data, size_t len);
-int RIPEMD160_Final(unsigned char *md, RIPEMD160_CTX *c);
-unsigned char *RIPEMD160(const unsigned char *d, size_t n,
- unsigned char *md);
-void RIPEMD160_Transform(RIPEMD160_CTX *c, const unsigned char *b);
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/rsa.h b/drivers/builtin_openssl/openssl/rsa.h
deleted file mode 100644
index 5f269e577a..0000000000
--- a/drivers/builtin_openssl/openssl/rsa.h
+++ /dev/null
@@ -1,582 +0,0 @@
-/* crypto/rsa/rsa.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_RSA_H
-#define HEADER_RSA_H
-
-#include <openssl/asn1.h>
-
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#include <openssl/crypto.h>
-#include <openssl/ossl_typ.h>
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/bn.h>
-#endif
-
-#ifdef OPENSSL_NO_RSA
-#error RSA is disabled.
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Declared already in ossl_typ.h */
-/* typedef struct rsa_st RSA; */
-/* typedef struct rsa_meth_st RSA_METHOD; */
-
-struct rsa_meth_st
- {
- const char *name;
- int (*rsa_pub_enc)(int flen,const unsigned char *from,
- unsigned char *to,
- RSA *rsa,int padding);
- int (*rsa_pub_dec)(int flen,const unsigned char *from,
- unsigned char *to,
- RSA *rsa,int padding);
- int (*rsa_priv_enc)(int flen,const unsigned char *from,
- unsigned char *to,
- RSA *rsa,int padding);
- int (*rsa_priv_dec)(int flen,const unsigned char *from,
- unsigned char *to,
- RSA *rsa,int padding);
- int (*rsa_mod_exp)(BIGNUM *r0,const BIGNUM *I,RSA *rsa,BN_CTX *ctx); /* Can be null */
- int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx,
- BN_MONT_CTX *m_ctx); /* Can be null */
- int (*init)(RSA *rsa); /* called at new */
- int (*finish)(RSA *rsa); /* called at free */
- int flags; /* RSA_METHOD_FLAG_* things */
- char *app_data; /* may be needed! */
-/* New sign and verify functions: some libraries don't allow arbitrary data
- * to be signed/verified: this allows them to be used. Note: for this to work
- * the RSA_public_decrypt() and RSA_private_encrypt() should *NOT* be used
- * RSA_sign(), RSA_verify() should be used instead. Note: for backwards
- * compatibility this functionality is only enabled if the RSA_FLAG_SIGN_VER
- * option is set in 'flags'.
- */
- int (*rsa_sign)(int type,
- const unsigned char *m, unsigned int m_length,
- unsigned char *sigret, unsigned int *siglen, const RSA *rsa);
- int (*rsa_verify)(int dtype,
- const unsigned char *m, unsigned int m_length,
- const unsigned char *sigbuf, unsigned int siglen,
- const RSA *rsa);
-/* If this callback is NULL, the builtin software RSA key-gen will be used. This
- * is for behavioural compatibility whilst the code gets rewired, but one day
- * it would be nice to assume there are no such things as "builtin software"
- * implementations. */
- int (*rsa_keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
- };
-
-struct rsa_st
- {
- /* The first parameter is used to pickup errors where
- * this is passed instead of aEVP_PKEY, it is set to 0 */
- int pad;
- long version;
- const RSA_METHOD *meth;
- /* functional reference if 'meth' is ENGINE-provided */
- ENGINE *engine;
- BIGNUM *n;
- BIGNUM *e;
- BIGNUM *d;
- BIGNUM *p;
- BIGNUM *q;
- BIGNUM *dmp1;
- BIGNUM *dmq1;
- BIGNUM *iqmp;
- /* be careful using this if the RSA structure is shared */
- CRYPTO_EX_DATA ex_data;
- int references;
- int flags;
-
- /* Used to cache montgomery values */
- BN_MONT_CTX *_method_mod_n;
- BN_MONT_CTX *_method_mod_p;
- BN_MONT_CTX *_method_mod_q;
-
- /* all BIGNUM values are actually in the following data, if it is not
- * NULL */
- char *bignum_data;
- BN_BLINDING *blinding;
- BN_BLINDING *mt_blinding;
- };
-
-#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
-# define OPENSSL_RSA_MAX_MODULUS_BITS 16384
-#endif
-
-#ifndef OPENSSL_RSA_SMALL_MODULUS_BITS
-# define OPENSSL_RSA_SMALL_MODULUS_BITS 3072
-#endif
-#ifndef OPENSSL_RSA_MAX_PUBEXP_BITS
-# define OPENSSL_RSA_MAX_PUBEXP_BITS 64 /* exponent limit enforced for "large" modulus only */
-#endif
-
-#define RSA_3 0x3L
-#define RSA_F4 0x10001L
-
-#define RSA_METHOD_FLAG_NO_CHECK 0x0001 /* don't check pub/private match */
-
-#define RSA_FLAG_CACHE_PUBLIC 0x0002
-#define RSA_FLAG_CACHE_PRIVATE 0x0004
-#define RSA_FLAG_BLINDING 0x0008
-#define RSA_FLAG_THREAD_SAFE 0x0010
-/* This flag means the private key operations will be handled by rsa_mod_exp
- * and that they do not depend on the private key components being present:
- * for example a key stored in external hardware. Without this flag bn_mod_exp
- * gets called when private key components are absent.
- */
-#define RSA_FLAG_EXT_PKEY 0x0020
-
-/* This flag in the RSA_METHOD enables the new rsa_sign, rsa_verify functions.
- */
-#define RSA_FLAG_SIGN_VER 0x0040
-
-#define RSA_FLAG_NO_BLINDING 0x0080 /* new with 0.9.6j and 0.9.7b; the built-in
- * RSA implementation now uses blinding by
- * default (ignoring RSA_FLAG_BLINDING),
- * but other engines might not need it
- */
-#define RSA_FLAG_NO_CONSTTIME 0x0100 /* new with 0.9.8f; the built-in RSA
- * implementation now uses constant time
- * operations by default in private key operations,
- * e.g., constant time modular exponentiation,
- * modular inverse without leaking branches,
- * division without leaking branches. This
- * flag disables these constant time
- * operations and results in faster RSA
- * private key operations.
- */
-#ifndef OPENSSL_NO_DEPRECATED
-#define RSA_FLAG_NO_EXP_CONSTTIME RSA_FLAG_NO_CONSTTIME /* deprecated name for the flag*/
- /* new with 0.9.7h; the built-in RSA
- * implementation now uses constant time
- * modular exponentiation for secret exponents
- * by default. This flag causes the
- * faster variable sliding window method to
- * be used for all exponents.
- */
-#endif
-
-
-#define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, \
- pad, NULL)
-
-#define EVP_PKEY_CTX_get_rsa_padding(ctx, ppad) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, \
- EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad)
-
-#define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, \
- (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \
- EVP_PKEY_CTRL_RSA_PSS_SALTLEN, \
- len, NULL)
-
-#define EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx, plen) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, \
- (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \
- EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, \
- 0, plen)
-
-#define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, \
- EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL)
-
-#define EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, pubexp) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, \
- EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp)
-
-#define EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_SIG, \
- EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)md)
-
-#define EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, pmd) \
- EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_SIG, \
- EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void *)pmd)
-
-#define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1)
-#define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 2)
-
-#define EVP_PKEY_CTRL_RSA_KEYGEN_BITS (EVP_PKEY_ALG_CTRL + 3)
-#define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP (EVP_PKEY_ALG_CTRL + 4)
-#define EVP_PKEY_CTRL_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 5)
-
-#define EVP_PKEY_CTRL_GET_RSA_PADDING (EVP_PKEY_ALG_CTRL + 6)
-#define EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 7)
-#define EVP_PKEY_CTRL_GET_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 8)
-
-#define RSA_PKCS1_PADDING 1
-#define RSA_SSLV23_PADDING 2
-#define RSA_NO_PADDING 3
-#define RSA_PKCS1_OAEP_PADDING 4
-#define RSA_X931_PADDING 5
-/* EVP_PKEY_ only */
-#define RSA_PKCS1_PSS_PADDING 6
-
-#define RSA_PKCS1_PADDING_SIZE 11
-
-#define RSA_set_app_data(s,arg) RSA_set_ex_data(s,0,arg)
-#define RSA_get_app_data(s) RSA_get_ex_data(s,0)
-
-RSA * RSA_new(void);
-RSA * RSA_new_method(ENGINE *engine);
-int RSA_size(const RSA *rsa);
-
-/* Deprecated version */
-#ifndef OPENSSL_NO_DEPRECATED
-RSA * RSA_generate_key(int bits, unsigned long e,void
- (*callback)(int,int,void *),void *cb_arg);
-#endif /* !defined(OPENSSL_NO_DEPRECATED) */
-
-/* New version */
-int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
-
-int RSA_check_key(const RSA *);
- /* next 4 return -1 on error */
-int RSA_public_encrypt(int flen, const unsigned char *from,
- unsigned char *to, RSA *rsa,int padding);
-int RSA_private_encrypt(int flen, const unsigned char *from,
- unsigned char *to, RSA *rsa,int padding);
-int RSA_public_decrypt(int flen, const unsigned char *from,
- unsigned char *to, RSA *rsa,int padding);
-int RSA_private_decrypt(int flen, const unsigned char *from,
- unsigned char *to, RSA *rsa,int padding);
-void RSA_free (RSA *r);
-/* "up" the RSA object's reference count */
-int RSA_up_ref(RSA *r);
-
-int RSA_flags(const RSA *r);
-
-void RSA_set_default_method(const RSA_METHOD *meth);
-const RSA_METHOD *RSA_get_default_method(void);
-const RSA_METHOD *RSA_get_method(const RSA *rsa);
-int RSA_set_method(RSA *rsa, const RSA_METHOD *meth);
-
-/* This function needs the memory locking malloc callbacks to be installed */
-int RSA_memory_lock(RSA *r);
-
-/* these are the actual SSLeay RSA functions */
-const RSA_METHOD *RSA_PKCS1_SSLeay(void);
-
-const RSA_METHOD *RSA_null_method(void);
-
-DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPublicKey)
-DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPrivateKey)
-
-typedef struct rsa_pss_params_st
- {
- X509_ALGOR *hashAlgorithm;
- X509_ALGOR *maskGenAlgorithm;
- ASN1_INTEGER *saltLength;
- ASN1_INTEGER *trailerField;
- } RSA_PSS_PARAMS;
-
-DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS)
-
-#ifndef OPENSSL_NO_FP_API
-int RSA_print_fp(FILE *fp, const RSA *r,int offset);
-#endif
-
-#ifndef OPENSSL_NO_BIO
-int RSA_print(BIO *bp, const RSA *r,int offset);
-#endif
-
-#ifndef OPENSSL_NO_RC4
-int i2d_RSA_NET(const RSA *a, unsigned char **pp,
- int (*cb)(char *buf, int len, const char *prompt, int verify),
- int sgckey);
-RSA *d2i_RSA_NET(RSA **a, const unsigned char **pp, long length,
- int (*cb)(char *buf, int len, const char *prompt, int verify),
- int sgckey);
-
-int i2d_Netscape_RSA(const RSA *a, unsigned char **pp,
- int (*cb)(char *buf, int len, const char *prompt,
- int verify));
-RSA *d2i_Netscape_RSA(RSA **a, const unsigned char **pp, long length,
- int (*cb)(char *buf, int len, const char *prompt,
- int verify));
-#endif
-
-/* The following 2 functions sign and verify a X509_SIG ASN1 object
- * inside PKCS#1 padded RSA encryption */
-int RSA_sign(int type, const unsigned char *m, unsigned int m_length,
- unsigned char *sigret, unsigned int *siglen, RSA *rsa);
-int RSA_verify(int type, const unsigned char *m, unsigned int m_length,
- const unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
-
-/* The following 2 function sign and verify a ASN1_OCTET_STRING
- * object inside PKCS#1 padded RSA encryption */
-int RSA_sign_ASN1_OCTET_STRING(int type,
- const unsigned char *m, unsigned int m_length,
- unsigned char *sigret, unsigned int *siglen, RSA *rsa);
-int RSA_verify_ASN1_OCTET_STRING(int type,
- const unsigned char *m, unsigned int m_length,
- unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
-
-int RSA_blinding_on(RSA *rsa, BN_CTX *ctx);
-void RSA_blinding_off(RSA *rsa);
-BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *ctx);
-
-int RSA_padding_add_PKCS1_type_1(unsigned char *to,int tlen,
- const unsigned char *f,int fl);
-int RSA_padding_check_PKCS1_type_1(unsigned char *to,int tlen,
- const unsigned char *f,int fl,int rsa_len);
-int RSA_padding_add_PKCS1_type_2(unsigned char *to,int tlen,
- const unsigned char *f,int fl);
-int RSA_padding_check_PKCS1_type_2(unsigned char *to,int tlen,
- const unsigned char *f,int fl,int rsa_len);
-int PKCS1_MGF1(unsigned char *mask, long len,
- const unsigned char *seed, long seedlen, const EVP_MD *dgst);
-int RSA_padding_add_PKCS1_OAEP(unsigned char *to,int tlen,
- const unsigned char *f,int fl,
- const unsigned char *p,int pl);
-int RSA_padding_check_PKCS1_OAEP(unsigned char *to,int tlen,
- const unsigned char *f,int fl,int rsa_len,
- const unsigned char *p,int pl);
-int RSA_padding_add_SSLv23(unsigned char *to,int tlen,
- const unsigned char *f,int fl);
-int RSA_padding_check_SSLv23(unsigned char *to,int tlen,
- const unsigned char *f,int fl,int rsa_len);
-int RSA_padding_add_none(unsigned char *to,int tlen,
- const unsigned char *f,int fl);
-int RSA_padding_check_none(unsigned char *to,int tlen,
- const unsigned char *f,int fl,int rsa_len);
-int RSA_padding_add_X931(unsigned char *to,int tlen,
- const unsigned char *f,int fl);
-int RSA_padding_check_X931(unsigned char *to,int tlen,
- const unsigned char *f,int fl,int rsa_len);
-int RSA_X931_hash_id(int nid);
-
-int RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash,
- const EVP_MD *Hash, const unsigned char *EM, int sLen);
-int RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM,
- const unsigned char *mHash,
- const EVP_MD *Hash, int sLen);
-
-int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const unsigned char *mHash,
- const EVP_MD *Hash, const EVP_MD *mgf1Hash,
- const unsigned char *EM, int sLen);
-
-int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
- const unsigned char *mHash,
- const EVP_MD *Hash, const EVP_MD *mgf1Hash, int sLen);
-
-int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int RSA_set_ex_data(RSA *r,int idx,void *arg);
-void *RSA_get_ex_data(const RSA *r, int idx);
-
-RSA *RSAPublicKey_dup(RSA *rsa);
-RSA *RSAPrivateKey_dup(RSA *rsa);
-
-/* If this flag is set the RSA method is FIPS compliant and can be used
- * in FIPS mode. This is set in the validated module method. If an
- * application sets this flag in its own methods it is its responsibility
- * to ensure the result is compliant.
- */
-
-#define RSA_FLAG_FIPS_METHOD 0x0400
-
-/* If this flag is set the operations normally disabled in FIPS mode are
- * permitted it is then the applications responsibility to ensure that the
- * usage is compliant.
- */
-
-#define RSA_FLAG_NON_FIPS_ALLOW 0x0400
-/* Application has decided PRNG is good enough to generate a key: don't
- * check.
- */
-#define RSA_FLAG_CHECKED 0x0800
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_RSA_strings(void);
-
-/* Error codes for the RSA functions. */
-
-/* Function codes. */
-#define RSA_F_CHECK_PADDING_MD 140
-#define RSA_F_DO_RSA_PRINT 146
-#define RSA_F_INT_RSA_VERIFY 145
-#define RSA_F_MEMORY_LOCK 100
-#define RSA_F_OLD_RSA_PRIV_DECODE 147
-#define RSA_F_PKEY_RSA_CTRL 143
-#define RSA_F_PKEY_RSA_CTRL_STR 144
-#define RSA_F_PKEY_RSA_SIGN 142
-#define RSA_F_PKEY_RSA_VERIFY 154
-#define RSA_F_PKEY_RSA_VERIFYRECOVER 141
-#define RSA_F_RSA_BUILTIN_KEYGEN 129
-#define RSA_F_RSA_CHECK_KEY 123
-#define RSA_F_RSA_EAY_PRIVATE_DECRYPT 101
-#define RSA_F_RSA_EAY_PRIVATE_ENCRYPT 102
-#define RSA_F_RSA_EAY_PUBLIC_DECRYPT 103
-#define RSA_F_RSA_EAY_PUBLIC_ENCRYPT 104
-#define RSA_F_RSA_GENERATE_KEY 105
-#define RSA_F_RSA_GENERATE_KEY_EX 155
-#define RSA_F_RSA_ITEM_VERIFY 156
-#define RSA_F_RSA_MEMORY_LOCK 130
-#define RSA_F_RSA_NEW_METHOD 106
-#define RSA_F_RSA_NULL 124
-#define RSA_F_RSA_NULL_MOD_EXP 131
-#define RSA_F_RSA_NULL_PRIVATE_DECRYPT 132
-#define RSA_F_RSA_NULL_PRIVATE_ENCRYPT 133
-#define RSA_F_RSA_NULL_PUBLIC_DECRYPT 134
-#define RSA_F_RSA_NULL_PUBLIC_ENCRYPT 135
-#define RSA_F_RSA_PADDING_ADD_NONE 107
-#define RSA_F_RSA_PADDING_ADD_PKCS1_OAEP 121
-#define RSA_F_RSA_PADDING_ADD_PKCS1_PSS 125
-#define RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1 148
-#define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1 108
-#define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2 109
-#define RSA_F_RSA_PADDING_ADD_SSLV23 110
-#define RSA_F_RSA_PADDING_ADD_X931 127
-#define RSA_F_RSA_PADDING_CHECK_NONE 111
-#define RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP 122
-#define RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1 112
-#define RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2 113
-#define RSA_F_RSA_PADDING_CHECK_SSLV23 114
-#define RSA_F_RSA_PADDING_CHECK_X931 128
-#define RSA_F_RSA_PRINT 115
-#define RSA_F_RSA_PRINT_FP 116
-#define RSA_F_RSA_PRIVATE_DECRYPT 150
-#define RSA_F_RSA_PRIVATE_ENCRYPT 151
-#define RSA_F_RSA_PRIV_DECODE 137
-#define RSA_F_RSA_PRIV_ENCODE 138
-#define RSA_F_RSA_PUBLIC_DECRYPT 152
-#define RSA_F_RSA_PUBLIC_ENCRYPT 153
-#define RSA_F_RSA_PUB_DECODE 139
-#define RSA_F_RSA_SETUP_BLINDING 136
-#define RSA_F_RSA_SIGN 117
-#define RSA_F_RSA_SIGN_ASN1_OCTET_STRING 118
-#define RSA_F_RSA_VERIFY 119
-#define RSA_F_RSA_VERIFY_ASN1_OCTET_STRING 120
-#define RSA_F_RSA_VERIFY_PKCS1_PSS 126
-#define RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1 149
-
-/* Reason codes. */
-#define RSA_R_ALGORITHM_MISMATCH 100
-#define RSA_R_BAD_E_VALUE 101
-#define RSA_R_BAD_FIXED_HEADER_DECRYPT 102
-#define RSA_R_BAD_PAD_BYTE_COUNT 103
-#define RSA_R_BAD_SIGNATURE 104
-#define RSA_R_BLOCK_TYPE_IS_NOT_01 106
-#define RSA_R_BLOCK_TYPE_IS_NOT_02 107
-#define RSA_R_DATA_GREATER_THAN_MOD_LEN 108
-#define RSA_R_DATA_TOO_LARGE 109
-#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 110
-#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 132
-#define RSA_R_DATA_TOO_SMALL 111
-#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 122
-#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 112
-#define RSA_R_DMP1_NOT_CONGRUENT_TO_D 124
-#define RSA_R_DMQ1_NOT_CONGRUENT_TO_D 125
-#define RSA_R_D_E_NOT_CONGRUENT_TO_1 123
-#define RSA_R_FIRST_OCTET_INVALID 133
-#define RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 144
-#define RSA_R_INVALID_DIGEST_LENGTH 143
-#define RSA_R_INVALID_HEADER 137
-#define RSA_R_INVALID_KEYBITS 145
-#define RSA_R_INVALID_MESSAGE_LENGTH 131
-#define RSA_R_INVALID_MGF1_MD 156
-#define RSA_R_INVALID_PADDING 138
-#define RSA_R_INVALID_PADDING_MODE 141
-#define RSA_R_INVALID_PSS_PARAMETERS 149
-#define RSA_R_INVALID_PSS_SALTLEN 146
-#define RSA_R_INVALID_SALT_LENGTH 150
-#define RSA_R_INVALID_TRAILER 139
-#define RSA_R_INVALID_X931_DIGEST 142
-#define RSA_R_IQMP_NOT_INVERSE_OF_Q 126
-#define RSA_R_KEY_SIZE_TOO_SMALL 120
-#define RSA_R_LAST_OCTET_INVALID 134
-#define RSA_R_MODULUS_TOO_LARGE 105
-#define RSA_R_NON_FIPS_RSA_METHOD 157
-#define RSA_R_NO_PUBLIC_EXPONENT 140
-#define RSA_R_NULL_BEFORE_BLOCK_MISSING 113
-#define RSA_R_N_DOES_NOT_EQUAL_P_Q 127
-#define RSA_R_OAEP_DECODING_ERROR 121
-#define RSA_R_OPERATION_NOT_ALLOWED_IN_FIPS_MODE 158
-#define RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 148
-#define RSA_R_PADDING_CHECK_FAILED 114
-#define RSA_R_P_NOT_PRIME 128
-#define RSA_R_Q_NOT_PRIME 129
-#define RSA_R_RSA_OPERATIONS_NOT_SUPPORTED 130
-#define RSA_R_SLEN_CHECK_FAILED 136
-#define RSA_R_SLEN_RECOVERY_FAILED 135
-#define RSA_R_SSLV3_ROLLBACK_ATTACK 115
-#define RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 116
-#define RSA_R_UNKNOWN_ALGORITHM_TYPE 117
-#define RSA_R_UNKNOWN_MASK_DIGEST 151
-#define RSA_R_UNKNOWN_PADDING_TYPE 118
-#define RSA_R_UNKNOWN_PSS_DIGEST 152
-#define RSA_R_UNSUPPORTED_MASK_ALGORITHM 153
-#define RSA_R_UNSUPPORTED_MASK_PARAMETER 154
-#define RSA_R_UNSUPPORTED_SIGNATURE_TYPE 155
-#define RSA_R_VALUE_MISSING 147
-#define RSA_R_WRONG_SIGNATURE_LENGTH 119
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/safestack.h b/drivers/builtin_openssl/openssl/safestack.h
deleted file mode 100644
index ea3aa0d800..0000000000
--- a/drivers/builtin_openssl/openssl/safestack.h
+++ /dev/null
@@ -1,2663 +0,0 @@
-/* ====================================================================
- * Copyright (c) 1999 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_SAFESTACK_H
-#define HEADER_SAFESTACK_H
-
-#include <openssl/stack.h>
-
-#ifndef CHECKED_PTR_OF
-#define CHECKED_PTR_OF(type, p) \
- ((void*) (1 ? p : (type*)0))
-#endif
-
-/* In C++ we get problems because an explicit cast is needed from (void *)
- * we use CHECKED_STACK_OF to ensure the correct type is passed in the macros
- * below.
- */
-
-#define CHECKED_STACK_OF(type, p) \
- ((_STACK*) (1 ? p : (STACK_OF(type)*)0))
-
-#define CHECKED_SK_FREE_FUNC(type, p) \
- ((void (*)(void *)) ((1 ? p : (void (*)(type *))0)))
-
-#define CHECKED_SK_FREE_FUNC2(type, p) \
- ((void (*)(void *)) ((1 ? p : (void (*)(type))0)))
-
-#define CHECKED_SK_CMP_FUNC(type, p) \
- ((int (*)(const void *, const void *)) \
- ((1 ? p : (int (*)(const type * const *, const type * const *))0)))
-
-#define STACK_OF(type) struct stack_st_##type
-#define PREDECLARE_STACK_OF(type) STACK_OF(type);
-
-#define DECLARE_STACK_OF(type) \
-STACK_OF(type) \
- { \
- _STACK stack; \
- };
-#define DECLARE_SPECIAL_STACK_OF(type, type2) \
-STACK_OF(type) \
- { \
- _STACK stack; \
- };
-
-#define IMPLEMENT_STACK_OF(type) /* nada (obsolete in new safestack approach)*/
-
-
-/* Strings are special: normally an lhash entry will point to a single
- * (somewhat) mutable object. In the case of strings:
- *
- * a) Instead of a single char, there is an array of chars, NUL-terminated.
- * b) The string may have be immutable.
- *
- * So, they need their own declarations. Especially important for
- * type-checking tools, such as Deputy.
- *
-o * In practice, however, it appears to be hard to have a const
- * string. For now, I'm settling for dealing with the fact it is a
- * string at all.
- */
-typedef char *OPENSSL_STRING;
-
-typedef const char *OPENSSL_CSTRING;
-
-/* Confusingly, LHASH_OF(STRING) deals with char ** throughout, but
- * STACK_OF(STRING) is really more like STACK_OF(char), only, as
- * mentioned above, instead of a single char each entry is a
- * NUL-terminated array of chars. So, we have to implement STRING
- * specially for STACK_OF. This is dealt with in the autogenerated
- * macros below.
- */
-
-DECLARE_SPECIAL_STACK_OF(OPENSSL_STRING, char)
-
-/* Similarly, we sometimes use a block of characters, NOT
- * nul-terminated. These should also be distinguished from "normal"
- * stacks. */
-
-typedef void *OPENSSL_BLOCK;
-DECLARE_SPECIAL_STACK_OF(OPENSSL_BLOCK, void)
-
-/* SKM_sk_... stack macros are internal to safestack.h:
- * never use them directly, use sk_<type>_... instead */
-#define SKM_sk_new(type, cmp) \
- ((STACK_OF(type) *)sk_new(CHECKED_SK_CMP_FUNC(type, cmp)))
-#define SKM_sk_new_null(type) \
- ((STACK_OF(type) *)sk_new_null())
-#define SKM_sk_free(type, st) \
- sk_free(CHECKED_STACK_OF(type, st))
-#define SKM_sk_num(type, st) \
- sk_num(CHECKED_STACK_OF(type, st))
-#define SKM_sk_value(type, st,i) \
- ((type *)sk_value(CHECKED_STACK_OF(type, st), i))
-#define SKM_sk_set(type, st,i,val) \
- sk_set(CHECKED_STACK_OF(type, st), i, CHECKED_PTR_OF(type, val))
-#define SKM_sk_zero(type, st) \
- sk_zero(CHECKED_STACK_OF(type, st))
-#define SKM_sk_push(type, st, val) \
- sk_push(CHECKED_STACK_OF(type, st), CHECKED_PTR_OF(type, val))
-#define SKM_sk_unshift(type, st, val) \
- sk_unshift(CHECKED_STACK_OF(type, st), CHECKED_PTR_OF(type, val))
-#define SKM_sk_find(type, st, val) \
- sk_find(CHECKED_STACK_OF(type, st), CHECKED_PTR_OF(type, val))
-#define SKM_sk_find_ex(type, st, val) \
- sk_find_ex(CHECKED_STACK_OF(type, st), \
- CHECKED_PTR_OF(type, val))
-#define SKM_sk_delete(type, st, i) \
- (type *)sk_delete(CHECKED_STACK_OF(type, st), i)
-#define SKM_sk_delete_ptr(type, st, ptr) \
- (type *)sk_delete_ptr(CHECKED_STACK_OF(type, st), CHECKED_PTR_OF(type, ptr))
-#define SKM_sk_insert(type, st,val, i) \
- sk_insert(CHECKED_STACK_OF(type, st), CHECKED_PTR_OF(type, val), i)
-#define SKM_sk_set_cmp_func(type, st, cmp) \
- ((int (*)(const type * const *,const type * const *)) \
- sk_set_cmp_func(CHECKED_STACK_OF(type, st), CHECKED_SK_CMP_FUNC(type, cmp)))
-#define SKM_sk_dup(type, st) \
- (STACK_OF(type) *)sk_dup(CHECKED_STACK_OF(type, st))
-#define SKM_sk_pop_free(type, st, free_func) \
- sk_pop_free(CHECKED_STACK_OF(type, st), CHECKED_SK_FREE_FUNC(type, free_func))
-#define SKM_sk_shift(type, st) \
- (type *)sk_shift(CHECKED_STACK_OF(type, st))
-#define SKM_sk_pop(type, st) \
- (type *)sk_pop(CHECKED_STACK_OF(type, st))
-#define SKM_sk_sort(type, st) \
- sk_sort(CHECKED_STACK_OF(type, st))
-#define SKM_sk_is_sorted(type, st) \
- sk_is_sorted(CHECKED_STACK_OF(type, st))
-
-#define SKM_ASN1_SET_OF_d2i(type, st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- (STACK_OF(type) *)d2i_ASN1_SET( \
- (STACK_OF(OPENSSL_BLOCK) **)CHECKED_PTR_OF(STACK_OF(type)*, st), \
- pp, length, \
- CHECKED_D2I_OF(type, d2i_func), \
- CHECKED_SK_FREE_FUNC(type, free_func), \
- ex_tag, ex_class)
-
-#define SKM_ASN1_SET_OF_i2d(type, st, pp, i2d_func, ex_tag, ex_class, is_set) \
- i2d_ASN1_SET((STACK_OF(OPENSSL_BLOCK) *)CHECKED_STACK_OF(type, st), pp, \
- CHECKED_I2D_OF(type, i2d_func), \
- ex_tag, ex_class, is_set)
-
-#define SKM_ASN1_seq_pack(type, st, i2d_func, buf, len) \
- ASN1_seq_pack(CHECKED_PTR_OF(STACK_OF(type), st), \
- CHECKED_I2D_OF(type, i2d_func), buf, len)
-
-#define SKM_ASN1_seq_unpack(type, buf, len, d2i_func, free_func) \
- (STACK_OF(type) *)ASN1_seq_unpack(buf, len, CHECKED_D2I_OF(type, d2i_func), CHECKED_SK_FREE_FUNC(type, free_func))
-
-#define SKM_PKCS12_decrypt_d2i(type, algor, d2i_func, free_func, pass, passlen, oct, seq) \
- (STACK_OF(type) *)PKCS12_decrypt_d2i(algor, \
- CHECKED_D2I_OF(type, d2i_func), \
- CHECKED_SK_FREE_FUNC(type, free_func), \
- pass, passlen, oct, seq)
-
-/* This block of defines is updated by util/mkstack.pl, please do not touch! */
-#define sk_ACCESS_DESCRIPTION_new(cmp) SKM_sk_new(ACCESS_DESCRIPTION, (cmp))
-#define sk_ACCESS_DESCRIPTION_new_null() SKM_sk_new_null(ACCESS_DESCRIPTION)
-#define sk_ACCESS_DESCRIPTION_free(st) SKM_sk_free(ACCESS_DESCRIPTION, (st))
-#define sk_ACCESS_DESCRIPTION_num(st) SKM_sk_num(ACCESS_DESCRIPTION, (st))
-#define sk_ACCESS_DESCRIPTION_value(st, i) SKM_sk_value(ACCESS_DESCRIPTION, (st), (i))
-#define sk_ACCESS_DESCRIPTION_set(st, i, val) SKM_sk_set(ACCESS_DESCRIPTION, (st), (i), (val))
-#define sk_ACCESS_DESCRIPTION_zero(st) SKM_sk_zero(ACCESS_DESCRIPTION, (st))
-#define sk_ACCESS_DESCRIPTION_push(st, val) SKM_sk_push(ACCESS_DESCRIPTION, (st), (val))
-#define sk_ACCESS_DESCRIPTION_unshift(st, val) SKM_sk_unshift(ACCESS_DESCRIPTION, (st), (val))
-#define sk_ACCESS_DESCRIPTION_find(st, val) SKM_sk_find(ACCESS_DESCRIPTION, (st), (val))
-#define sk_ACCESS_DESCRIPTION_find_ex(st, val) SKM_sk_find_ex(ACCESS_DESCRIPTION, (st), (val))
-#define sk_ACCESS_DESCRIPTION_delete(st, i) SKM_sk_delete(ACCESS_DESCRIPTION, (st), (i))
-#define sk_ACCESS_DESCRIPTION_delete_ptr(st, ptr) SKM_sk_delete_ptr(ACCESS_DESCRIPTION, (st), (ptr))
-#define sk_ACCESS_DESCRIPTION_insert(st, val, i) SKM_sk_insert(ACCESS_DESCRIPTION, (st), (val), (i))
-#define sk_ACCESS_DESCRIPTION_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ACCESS_DESCRIPTION, (st), (cmp))
-#define sk_ACCESS_DESCRIPTION_dup(st) SKM_sk_dup(ACCESS_DESCRIPTION, st)
-#define sk_ACCESS_DESCRIPTION_pop_free(st, free_func) SKM_sk_pop_free(ACCESS_DESCRIPTION, (st), (free_func))
-#define sk_ACCESS_DESCRIPTION_shift(st) SKM_sk_shift(ACCESS_DESCRIPTION, (st))
-#define sk_ACCESS_DESCRIPTION_pop(st) SKM_sk_pop(ACCESS_DESCRIPTION, (st))
-#define sk_ACCESS_DESCRIPTION_sort(st) SKM_sk_sort(ACCESS_DESCRIPTION, (st))
-#define sk_ACCESS_DESCRIPTION_is_sorted(st) SKM_sk_is_sorted(ACCESS_DESCRIPTION, (st))
-
-#define sk_ASIdOrRange_new(cmp) SKM_sk_new(ASIdOrRange, (cmp))
-#define sk_ASIdOrRange_new_null() SKM_sk_new_null(ASIdOrRange)
-#define sk_ASIdOrRange_free(st) SKM_sk_free(ASIdOrRange, (st))
-#define sk_ASIdOrRange_num(st) SKM_sk_num(ASIdOrRange, (st))
-#define sk_ASIdOrRange_value(st, i) SKM_sk_value(ASIdOrRange, (st), (i))
-#define sk_ASIdOrRange_set(st, i, val) SKM_sk_set(ASIdOrRange, (st), (i), (val))
-#define sk_ASIdOrRange_zero(st) SKM_sk_zero(ASIdOrRange, (st))
-#define sk_ASIdOrRange_push(st, val) SKM_sk_push(ASIdOrRange, (st), (val))
-#define sk_ASIdOrRange_unshift(st, val) SKM_sk_unshift(ASIdOrRange, (st), (val))
-#define sk_ASIdOrRange_find(st, val) SKM_sk_find(ASIdOrRange, (st), (val))
-#define sk_ASIdOrRange_find_ex(st, val) SKM_sk_find_ex(ASIdOrRange, (st), (val))
-#define sk_ASIdOrRange_delete(st, i) SKM_sk_delete(ASIdOrRange, (st), (i))
-#define sk_ASIdOrRange_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASIdOrRange, (st), (ptr))
-#define sk_ASIdOrRange_insert(st, val, i) SKM_sk_insert(ASIdOrRange, (st), (val), (i))
-#define sk_ASIdOrRange_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASIdOrRange, (st), (cmp))
-#define sk_ASIdOrRange_dup(st) SKM_sk_dup(ASIdOrRange, st)
-#define sk_ASIdOrRange_pop_free(st, free_func) SKM_sk_pop_free(ASIdOrRange, (st), (free_func))
-#define sk_ASIdOrRange_shift(st) SKM_sk_shift(ASIdOrRange, (st))
-#define sk_ASIdOrRange_pop(st) SKM_sk_pop(ASIdOrRange, (st))
-#define sk_ASIdOrRange_sort(st) SKM_sk_sort(ASIdOrRange, (st))
-#define sk_ASIdOrRange_is_sorted(st) SKM_sk_is_sorted(ASIdOrRange, (st))
-
-#define sk_ASN1_GENERALSTRING_new(cmp) SKM_sk_new(ASN1_GENERALSTRING, (cmp))
-#define sk_ASN1_GENERALSTRING_new_null() SKM_sk_new_null(ASN1_GENERALSTRING)
-#define sk_ASN1_GENERALSTRING_free(st) SKM_sk_free(ASN1_GENERALSTRING, (st))
-#define sk_ASN1_GENERALSTRING_num(st) SKM_sk_num(ASN1_GENERALSTRING, (st))
-#define sk_ASN1_GENERALSTRING_value(st, i) SKM_sk_value(ASN1_GENERALSTRING, (st), (i))
-#define sk_ASN1_GENERALSTRING_set(st, i, val) SKM_sk_set(ASN1_GENERALSTRING, (st), (i), (val))
-#define sk_ASN1_GENERALSTRING_zero(st) SKM_sk_zero(ASN1_GENERALSTRING, (st))
-#define sk_ASN1_GENERALSTRING_push(st, val) SKM_sk_push(ASN1_GENERALSTRING, (st), (val))
-#define sk_ASN1_GENERALSTRING_unshift(st, val) SKM_sk_unshift(ASN1_GENERALSTRING, (st), (val))
-#define sk_ASN1_GENERALSTRING_find(st, val) SKM_sk_find(ASN1_GENERALSTRING, (st), (val))
-#define sk_ASN1_GENERALSTRING_find_ex(st, val) SKM_sk_find_ex(ASN1_GENERALSTRING, (st), (val))
-#define sk_ASN1_GENERALSTRING_delete(st, i) SKM_sk_delete(ASN1_GENERALSTRING, (st), (i))
-#define sk_ASN1_GENERALSTRING_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_GENERALSTRING, (st), (ptr))
-#define sk_ASN1_GENERALSTRING_insert(st, val, i) SKM_sk_insert(ASN1_GENERALSTRING, (st), (val), (i))
-#define sk_ASN1_GENERALSTRING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_GENERALSTRING, (st), (cmp))
-#define sk_ASN1_GENERALSTRING_dup(st) SKM_sk_dup(ASN1_GENERALSTRING, st)
-#define sk_ASN1_GENERALSTRING_pop_free(st, free_func) SKM_sk_pop_free(ASN1_GENERALSTRING, (st), (free_func))
-#define sk_ASN1_GENERALSTRING_shift(st) SKM_sk_shift(ASN1_GENERALSTRING, (st))
-#define sk_ASN1_GENERALSTRING_pop(st) SKM_sk_pop(ASN1_GENERALSTRING, (st))
-#define sk_ASN1_GENERALSTRING_sort(st) SKM_sk_sort(ASN1_GENERALSTRING, (st))
-#define sk_ASN1_GENERALSTRING_is_sorted(st) SKM_sk_is_sorted(ASN1_GENERALSTRING, (st))
-
-#define sk_ASN1_INTEGER_new(cmp) SKM_sk_new(ASN1_INTEGER, (cmp))
-#define sk_ASN1_INTEGER_new_null() SKM_sk_new_null(ASN1_INTEGER)
-#define sk_ASN1_INTEGER_free(st) SKM_sk_free(ASN1_INTEGER, (st))
-#define sk_ASN1_INTEGER_num(st) SKM_sk_num(ASN1_INTEGER, (st))
-#define sk_ASN1_INTEGER_value(st, i) SKM_sk_value(ASN1_INTEGER, (st), (i))
-#define sk_ASN1_INTEGER_set(st, i, val) SKM_sk_set(ASN1_INTEGER, (st), (i), (val))
-#define sk_ASN1_INTEGER_zero(st) SKM_sk_zero(ASN1_INTEGER, (st))
-#define sk_ASN1_INTEGER_push(st, val) SKM_sk_push(ASN1_INTEGER, (st), (val))
-#define sk_ASN1_INTEGER_unshift(st, val) SKM_sk_unshift(ASN1_INTEGER, (st), (val))
-#define sk_ASN1_INTEGER_find(st, val) SKM_sk_find(ASN1_INTEGER, (st), (val))
-#define sk_ASN1_INTEGER_find_ex(st, val) SKM_sk_find_ex(ASN1_INTEGER, (st), (val))
-#define sk_ASN1_INTEGER_delete(st, i) SKM_sk_delete(ASN1_INTEGER, (st), (i))
-#define sk_ASN1_INTEGER_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_INTEGER, (st), (ptr))
-#define sk_ASN1_INTEGER_insert(st, val, i) SKM_sk_insert(ASN1_INTEGER, (st), (val), (i))
-#define sk_ASN1_INTEGER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_INTEGER, (st), (cmp))
-#define sk_ASN1_INTEGER_dup(st) SKM_sk_dup(ASN1_INTEGER, st)
-#define sk_ASN1_INTEGER_pop_free(st, free_func) SKM_sk_pop_free(ASN1_INTEGER, (st), (free_func))
-#define sk_ASN1_INTEGER_shift(st) SKM_sk_shift(ASN1_INTEGER, (st))
-#define sk_ASN1_INTEGER_pop(st) SKM_sk_pop(ASN1_INTEGER, (st))
-#define sk_ASN1_INTEGER_sort(st) SKM_sk_sort(ASN1_INTEGER, (st))
-#define sk_ASN1_INTEGER_is_sorted(st) SKM_sk_is_sorted(ASN1_INTEGER, (st))
-
-#define sk_ASN1_OBJECT_new(cmp) SKM_sk_new(ASN1_OBJECT, (cmp))
-#define sk_ASN1_OBJECT_new_null() SKM_sk_new_null(ASN1_OBJECT)
-#define sk_ASN1_OBJECT_free(st) SKM_sk_free(ASN1_OBJECT, (st))
-#define sk_ASN1_OBJECT_num(st) SKM_sk_num(ASN1_OBJECT, (st))
-#define sk_ASN1_OBJECT_value(st, i) SKM_sk_value(ASN1_OBJECT, (st), (i))
-#define sk_ASN1_OBJECT_set(st, i, val) SKM_sk_set(ASN1_OBJECT, (st), (i), (val))
-#define sk_ASN1_OBJECT_zero(st) SKM_sk_zero(ASN1_OBJECT, (st))
-#define sk_ASN1_OBJECT_push(st, val) SKM_sk_push(ASN1_OBJECT, (st), (val))
-#define sk_ASN1_OBJECT_unshift(st, val) SKM_sk_unshift(ASN1_OBJECT, (st), (val))
-#define sk_ASN1_OBJECT_find(st, val) SKM_sk_find(ASN1_OBJECT, (st), (val))
-#define sk_ASN1_OBJECT_find_ex(st, val) SKM_sk_find_ex(ASN1_OBJECT, (st), (val))
-#define sk_ASN1_OBJECT_delete(st, i) SKM_sk_delete(ASN1_OBJECT, (st), (i))
-#define sk_ASN1_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_OBJECT, (st), (ptr))
-#define sk_ASN1_OBJECT_insert(st, val, i) SKM_sk_insert(ASN1_OBJECT, (st), (val), (i))
-#define sk_ASN1_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_OBJECT, (st), (cmp))
-#define sk_ASN1_OBJECT_dup(st) SKM_sk_dup(ASN1_OBJECT, st)
-#define sk_ASN1_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(ASN1_OBJECT, (st), (free_func))
-#define sk_ASN1_OBJECT_shift(st) SKM_sk_shift(ASN1_OBJECT, (st))
-#define sk_ASN1_OBJECT_pop(st) SKM_sk_pop(ASN1_OBJECT, (st))
-#define sk_ASN1_OBJECT_sort(st) SKM_sk_sort(ASN1_OBJECT, (st))
-#define sk_ASN1_OBJECT_is_sorted(st) SKM_sk_is_sorted(ASN1_OBJECT, (st))
-
-#define sk_ASN1_STRING_TABLE_new(cmp) SKM_sk_new(ASN1_STRING_TABLE, (cmp))
-#define sk_ASN1_STRING_TABLE_new_null() SKM_sk_new_null(ASN1_STRING_TABLE)
-#define sk_ASN1_STRING_TABLE_free(st) SKM_sk_free(ASN1_STRING_TABLE, (st))
-#define sk_ASN1_STRING_TABLE_num(st) SKM_sk_num(ASN1_STRING_TABLE, (st))
-#define sk_ASN1_STRING_TABLE_value(st, i) SKM_sk_value(ASN1_STRING_TABLE, (st), (i))
-#define sk_ASN1_STRING_TABLE_set(st, i, val) SKM_sk_set(ASN1_STRING_TABLE, (st), (i), (val))
-#define sk_ASN1_STRING_TABLE_zero(st) SKM_sk_zero(ASN1_STRING_TABLE, (st))
-#define sk_ASN1_STRING_TABLE_push(st, val) SKM_sk_push(ASN1_STRING_TABLE, (st), (val))
-#define sk_ASN1_STRING_TABLE_unshift(st, val) SKM_sk_unshift(ASN1_STRING_TABLE, (st), (val))
-#define sk_ASN1_STRING_TABLE_find(st, val) SKM_sk_find(ASN1_STRING_TABLE, (st), (val))
-#define sk_ASN1_STRING_TABLE_find_ex(st, val) SKM_sk_find_ex(ASN1_STRING_TABLE, (st), (val))
-#define sk_ASN1_STRING_TABLE_delete(st, i) SKM_sk_delete(ASN1_STRING_TABLE, (st), (i))
-#define sk_ASN1_STRING_TABLE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_STRING_TABLE, (st), (ptr))
-#define sk_ASN1_STRING_TABLE_insert(st, val, i) SKM_sk_insert(ASN1_STRING_TABLE, (st), (val), (i))
-#define sk_ASN1_STRING_TABLE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_STRING_TABLE, (st), (cmp))
-#define sk_ASN1_STRING_TABLE_dup(st) SKM_sk_dup(ASN1_STRING_TABLE, st)
-#define sk_ASN1_STRING_TABLE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_STRING_TABLE, (st), (free_func))
-#define sk_ASN1_STRING_TABLE_shift(st) SKM_sk_shift(ASN1_STRING_TABLE, (st))
-#define sk_ASN1_STRING_TABLE_pop(st) SKM_sk_pop(ASN1_STRING_TABLE, (st))
-#define sk_ASN1_STRING_TABLE_sort(st) SKM_sk_sort(ASN1_STRING_TABLE, (st))
-#define sk_ASN1_STRING_TABLE_is_sorted(st) SKM_sk_is_sorted(ASN1_STRING_TABLE, (st))
-
-#define sk_ASN1_TYPE_new(cmp) SKM_sk_new(ASN1_TYPE, (cmp))
-#define sk_ASN1_TYPE_new_null() SKM_sk_new_null(ASN1_TYPE)
-#define sk_ASN1_TYPE_free(st) SKM_sk_free(ASN1_TYPE, (st))
-#define sk_ASN1_TYPE_num(st) SKM_sk_num(ASN1_TYPE, (st))
-#define sk_ASN1_TYPE_value(st, i) SKM_sk_value(ASN1_TYPE, (st), (i))
-#define sk_ASN1_TYPE_set(st, i, val) SKM_sk_set(ASN1_TYPE, (st), (i), (val))
-#define sk_ASN1_TYPE_zero(st) SKM_sk_zero(ASN1_TYPE, (st))
-#define sk_ASN1_TYPE_push(st, val) SKM_sk_push(ASN1_TYPE, (st), (val))
-#define sk_ASN1_TYPE_unshift(st, val) SKM_sk_unshift(ASN1_TYPE, (st), (val))
-#define sk_ASN1_TYPE_find(st, val) SKM_sk_find(ASN1_TYPE, (st), (val))
-#define sk_ASN1_TYPE_find_ex(st, val) SKM_sk_find_ex(ASN1_TYPE, (st), (val))
-#define sk_ASN1_TYPE_delete(st, i) SKM_sk_delete(ASN1_TYPE, (st), (i))
-#define sk_ASN1_TYPE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_TYPE, (st), (ptr))
-#define sk_ASN1_TYPE_insert(st, val, i) SKM_sk_insert(ASN1_TYPE, (st), (val), (i))
-#define sk_ASN1_TYPE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_TYPE, (st), (cmp))
-#define sk_ASN1_TYPE_dup(st) SKM_sk_dup(ASN1_TYPE, st)
-#define sk_ASN1_TYPE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_TYPE, (st), (free_func))
-#define sk_ASN1_TYPE_shift(st) SKM_sk_shift(ASN1_TYPE, (st))
-#define sk_ASN1_TYPE_pop(st) SKM_sk_pop(ASN1_TYPE, (st))
-#define sk_ASN1_TYPE_sort(st) SKM_sk_sort(ASN1_TYPE, (st))
-#define sk_ASN1_TYPE_is_sorted(st) SKM_sk_is_sorted(ASN1_TYPE, (st))
-
-#define sk_ASN1_UTF8STRING_new(cmp) SKM_sk_new(ASN1_UTF8STRING, (cmp))
-#define sk_ASN1_UTF8STRING_new_null() SKM_sk_new_null(ASN1_UTF8STRING)
-#define sk_ASN1_UTF8STRING_free(st) SKM_sk_free(ASN1_UTF8STRING, (st))
-#define sk_ASN1_UTF8STRING_num(st) SKM_sk_num(ASN1_UTF8STRING, (st))
-#define sk_ASN1_UTF8STRING_value(st, i) SKM_sk_value(ASN1_UTF8STRING, (st), (i))
-#define sk_ASN1_UTF8STRING_set(st, i, val) SKM_sk_set(ASN1_UTF8STRING, (st), (i), (val))
-#define sk_ASN1_UTF8STRING_zero(st) SKM_sk_zero(ASN1_UTF8STRING, (st))
-#define sk_ASN1_UTF8STRING_push(st, val) SKM_sk_push(ASN1_UTF8STRING, (st), (val))
-#define sk_ASN1_UTF8STRING_unshift(st, val) SKM_sk_unshift(ASN1_UTF8STRING, (st), (val))
-#define sk_ASN1_UTF8STRING_find(st, val) SKM_sk_find(ASN1_UTF8STRING, (st), (val))
-#define sk_ASN1_UTF8STRING_find_ex(st, val) SKM_sk_find_ex(ASN1_UTF8STRING, (st), (val))
-#define sk_ASN1_UTF8STRING_delete(st, i) SKM_sk_delete(ASN1_UTF8STRING, (st), (i))
-#define sk_ASN1_UTF8STRING_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_UTF8STRING, (st), (ptr))
-#define sk_ASN1_UTF8STRING_insert(st, val, i) SKM_sk_insert(ASN1_UTF8STRING, (st), (val), (i))
-#define sk_ASN1_UTF8STRING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_UTF8STRING, (st), (cmp))
-#define sk_ASN1_UTF8STRING_dup(st) SKM_sk_dup(ASN1_UTF8STRING, st)
-#define sk_ASN1_UTF8STRING_pop_free(st, free_func) SKM_sk_pop_free(ASN1_UTF8STRING, (st), (free_func))
-#define sk_ASN1_UTF8STRING_shift(st) SKM_sk_shift(ASN1_UTF8STRING, (st))
-#define sk_ASN1_UTF8STRING_pop(st) SKM_sk_pop(ASN1_UTF8STRING, (st))
-#define sk_ASN1_UTF8STRING_sort(st) SKM_sk_sort(ASN1_UTF8STRING, (st))
-#define sk_ASN1_UTF8STRING_is_sorted(st) SKM_sk_is_sorted(ASN1_UTF8STRING, (st))
-
-#define sk_ASN1_VALUE_new(cmp) SKM_sk_new(ASN1_VALUE, (cmp))
-#define sk_ASN1_VALUE_new_null() SKM_sk_new_null(ASN1_VALUE)
-#define sk_ASN1_VALUE_free(st) SKM_sk_free(ASN1_VALUE, (st))
-#define sk_ASN1_VALUE_num(st) SKM_sk_num(ASN1_VALUE, (st))
-#define sk_ASN1_VALUE_value(st, i) SKM_sk_value(ASN1_VALUE, (st), (i))
-#define sk_ASN1_VALUE_set(st, i, val) SKM_sk_set(ASN1_VALUE, (st), (i), (val))
-#define sk_ASN1_VALUE_zero(st) SKM_sk_zero(ASN1_VALUE, (st))
-#define sk_ASN1_VALUE_push(st, val) SKM_sk_push(ASN1_VALUE, (st), (val))
-#define sk_ASN1_VALUE_unshift(st, val) SKM_sk_unshift(ASN1_VALUE, (st), (val))
-#define sk_ASN1_VALUE_find(st, val) SKM_sk_find(ASN1_VALUE, (st), (val))
-#define sk_ASN1_VALUE_find_ex(st, val) SKM_sk_find_ex(ASN1_VALUE, (st), (val))
-#define sk_ASN1_VALUE_delete(st, i) SKM_sk_delete(ASN1_VALUE, (st), (i))
-#define sk_ASN1_VALUE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_VALUE, (st), (ptr))
-#define sk_ASN1_VALUE_insert(st, val, i) SKM_sk_insert(ASN1_VALUE, (st), (val), (i))
-#define sk_ASN1_VALUE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_VALUE, (st), (cmp))
-#define sk_ASN1_VALUE_dup(st) SKM_sk_dup(ASN1_VALUE, st)
-#define sk_ASN1_VALUE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_VALUE, (st), (free_func))
-#define sk_ASN1_VALUE_shift(st) SKM_sk_shift(ASN1_VALUE, (st))
-#define sk_ASN1_VALUE_pop(st) SKM_sk_pop(ASN1_VALUE, (st))
-#define sk_ASN1_VALUE_sort(st) SKM_sk_sort(ASN1_VALUE, (st))
-#define sk_ASN1_VALUE_is_sorted(st) SKM_sk_is_sorted(ASN1_VALUE, (st))
-
-#define sk_BIO_new(cmp) SKM_sk_new(BIO, (cmp))
-#define sk_BIO_new_null() SKM_sk_new_null(BIO)
-#define sk_BIO_free(st) SKM_sk_free(BIO, (st))
-#define sk_BIO_num(st) SKM_sk_num(BIO, (st))
-#define sk_BIO_value(st, i) SKM_sk_value(BIO, (st), (i))
-#define sk_BIO_set(st, i, val) SKM_sk_set(BIO, (st), (i), (val))
-#define sk_BIO_zero(st) SKM_sk_zero(BIO, (st))
-#define sk_BIO_push(st, val) SKM_sk_push(BIO, (st), (val))
-#define sk_BIO_unshift(st, val) SKM_sk_unshift(BIO, (st), (val))
-#define sk_BIO_find(st, val) SKM_sk_find(BIO, (st), (val))
-#define sk_BIO_find_ex(st, val) SKM_sk_find_ex(BIO, (st), (val))
-#define sk_BIO_delete(st, i) SKM_sk_delete(BIO, (st), (i))
-#define sk_BIO_delete_ptr(st, ptr) SKM_sk_delete_ptr(BIO, (st), (ptr))
-#define sk_BIO_insert(st, val, i) SKM_sk_insert(BIO, (st), (val), (i))
-#define sk_BIO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(BIO, (st), (cmp))
-#define sk_BIO_dup(st) SKM_sk_dup(BIO, st)
-#define sk_BIO_pop_free(st, free_func) SKM_sk_pop_free(BIO, (st), (free_func))
-#define sk_BIO_shift(st) SKM_sk_shift(BIO, (st))
-#define sk_BIO_pop(st) SKM_sk_pop(BIO, (st))
-#define sk_BIO_sort(st) SKM_sk_sort(BIO, (st))
-#define sk_BIO_is_sorted(st) SKM_sk_is_sorted(BIO, (st))
-
-#define sk_BY_DIR_ENTRY_new(cmp) SKM_sk_new(BY_DIR_ENTRY, (cmp))
-#define sk_BY_DIR_ENTRY_new_null() SKM_sk_new_null(BY_DIR_ENTRY)
-#define sk_BY_DIR_ENTRY_free(st) SKM_sk_free(BY_DIR_ENTRY, (st))
-#define sk_BY_DIR_ENTRY_num(st) SKM_sk_num(BY_DIR_ENTRY, (st))
-#define sk_BY_DIR_ENTRY_value(st, i) SKM_sk_value(BY_DIR_ENTRY, (st), (i))
-#define sk_BY_DIR_ENTRY_set(st, i, val) SKM_sk_set(BY_DIR_ENTRY, (st), (i), (val))
-#define sk_BY_DIR_ENTRY_zero(st) SKM_sk_zero(BY_DIR_ENTRY, (st))
-#define sk_BY_DIR_ENTRY_push(st, val) SKM_sk_push(BY_DIR_ENTRY, (st), (val))
-#define sk_BY_DIR_ENTRY_unshift(st, val) SKM_sk_unshift(BY_DIR_ENTRY, (st), (val))
-#define sk_BY_DIR_ENTRY_find(st, val) SKM_sk_find(BY_DIR_ENTRY, (st), (val))
-#define sk_BY_DIR_ENTRY_find_ex(st, val) SKM_sk_find_ex(BY_DIR_ENTRY, (st), (val))
-#define sk_BY_DIR_ENTRY_delete(st, i) SKM_sk_delete(BY_DIR_ENTRY, (st), (i))
-#define sk_BY_DIR_ENTRY_delete_ptr(st, ptr) SKM_sk_delete_ptr(BY_DIR_ENTRY, (st), (ptr))
-#define sk_BY_DIR_ENTRY_insert(st, val, i) SKM_sk_insert(BY_DIR_ENTRY, (st), (val), (i))
-#define sk_BY_DIR_ENTRY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(BY_DIR_ENTRY, (st), (cmp))
-#define sk_BY_DIR_ENTRY_dup(st) SKM_sk_dup(BY_DIR_ENTRY, st)
-#define sk_BY_DIR_ENTRY_pop_free(st, free_func) SKM_sk_pop_free(BY_DIR_ENTRY, (st), (free_func))
-#define sk_BY_DIR_ENTRY_shift(st) SKM_sk_shift(BY_DIR_ENTRY, (st))
-#define sk_BY_DIR_ENTRY_pop(st) SKM_sk_pop(BY_DIR_ENTRY, (st))
-#define sk_BY_DIR_ENTRY_sort(st) SKM_sk_sort(BY_DIR_ENTRY, (st))
-#define sk_BY_DIR_ENTRY_is_sorted(st) SKM_sk_is_sorted(BY_DIR_ENTRY, (st))
-
-#define sk_BY_DIR_HASH_new(cmp) SKM_sk_new(BY_DIR_HASH, (cmp))
-#define sk_BY_DIR_HASH_new_null() SKM_sk_new_null(BY_DIR_HASH)
-#define sk_BY_DIR_HASH_free(st) SKM_sk_free(BY_DIR_HASH, (st))
-#define sk_BY_DIR_HASH_num(st) SKM_sk_num(BY_DIR_HASH, (st))
-#define sk_BY_DIR_HASH_value(st, i) SKM_sk_value(BY_DIR_HASH, (st), (i))
-#define sk_BY_DIR_HASH_set(st, i, val) SKM_sk_set(BY_DIR_HASH, (st), (i), (val))
-#define sk_BY_DIR_HASH_zero(st) SKM_sk_zero(BY_DIR_HASH, (st))
-#define sk_BY_DIR_HASH_push(st, val) SKM_sk_push(BY_DIR_HASH, (st), (val))
-#define sk_BY_DIR_HASH_unshift(st, val) SKM_sk_unshift(BY_DIR_HASH, (st), (val))
-#define sk_BY_DIR_HASH_find(st, val) SKM_sk_find(BY_DIR_HASH, (st), (val))
-#define sk_BY_DIR_HASH_find_ex(st, val) SKM_sk_find_ex(BY_DIR_HASH, (st), (val))
-#define sk_BY_DIR_HASH_delete(st, i) SKM_sk_delete(BY_DIR_HASH, (st), (i))
-#define sk_BY_DIR_HASH_delete_ptr(st, ptr) SKM_sk_delete_ptr(BY_DIR_HASH, (st), (ptr))
-#define sk_BY_DIR_HASH_insert(st, val, i) SKM_sk_insert(BY_DIR_HASH, (st), (val), (i))
-#define sk_BY_DIR_HASH_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(BY_DIR_HASH, (st), (cmp))
-#define sk_BY_DIR_HASH_dup(st) SKM_sk_dup(BY_DIR_HASH, st)
-#define sk_BY_DIR_HASH_pop_free(st, free_func) SKM_sk_pop_free(BY_DIR_HASH, (st), (free_func))
-#define sk_BY_DIR_HASH_shift(st) SKM_sk_shift(BY_DIR_HASH, (st))
-#define sk_BY_DIR_HASH_pop(st) SKM_sk_pop(BY_DIR_HASH, (st))
-#define sk_BY_DIR_HASH_sort(st) SKM_sk_sort(BY_DIR_HASH, (st))
-#define sk_BY_DIR_HASH_is_sorted(st) SKM_sk_is_sorted(BY_DIR_HASH, (st))
-
-#define sk_CMS_CertificateChoices_new(cmp) SKM_sk_new(CMS_CertificateChoices, (cmp))
-#define sk_CMS_CertificateChoices_new_null() SKM_sk_new_null(CMS_CertificateChoices)
-#define sk_CMS_CertificateChoices_free(st) SKM_sk_free(CMS_CertificateChoices, (st))
-#define sk_CMS_CertificateChoices_num(st) SKM_sk_num(CMS_CertificateChoices, (st))
-#define sk_CMS_CertificateChoices_value(st, i) SKM_sk_value(CMS_CertificateChoices, (st), (i))
-#define sk_CMS_CertificateChoices_set(st, i, val) SKM_sk_set(CMS_CertificateChoices, (st), (i), (val))
-#define sk_CMS_CertificateChoices_zero(st) SKM_sk_zero(CMS_CertificateChoices, (st))
-#define sk_CMS_CertificateChoices_push(st, val) SKM_sk_push(CMS_CertificateChoices, (st), (val))
-#define sk_CMS_CertificateChoices_unshift(st, val) SKM_sk_unshift(CMS_CertificateChoices, (st), (val))
-#define sk_CMS_CertificateChoices_find(st, val) SKM_sk_find(CMS_CertificateChoices, (st), (val))
-#define sk_CMS_CertificateChoices_find_ex(st, val) SKM_sk_find_ex(CMS_CertificateChoices, (st), (val))
-#define sk_CMS_CertificateChoices_delete(st, i) SKM_sk_delete(CMS_CertificateChoices, (st), (i))
-#define sk_CMS_CertificateChoices_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_CertificateChoices, (st), (ptr))
-#define sk_CMS_CertificateChoices_insert(st, val, i) SKM_sk_insert(CMS_CertificateChoices, (st), (val), (i))
-#define sk_CMS_CertificateChoices_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_CertificateChoices, (st), (cmp))
-#define sk_CMS_CertificateChoices_dup(st) SKM_sk_dup(CMS_CertificateChoices, st)
-#define sk_CMS_CertificateChoices_pop_free(st, free_func) SKM_sk_pop_free(CMS_CertificateChoices, (st), (free_func))
-#define sk_CMS_CertificateChoices_shift(st) SKM_sk_shift(CMS_CertificateChoices, (st))
-#define sk_CMS_CertificateChoices_pop(st) SKM_sk_pop(CMS_CertificateChoices, (st))
-#define sk_CMS_CertificateChoices_sort(st) SKM_sk_sort(CMS_CertificateChoices, (st))
-#define sk_CMS_CertificateChoices_is_sorted(st) SKM_sk_is_sorted(CMS_CertificateChoices, (st))
-
-#define sk_CMS_RecipientInfo_new(cmp) SKM_sk_new(CMS_RecipientInfo, (cmp))
-#define sk_CMS_RecipientInfo_new_null() SKM_sk_new_null(CMS_RecipientInfo)
-#define sk_CMS_RecipientInfo_free(st) SKM_sk_free(CMS_RecipientInfo, (st))
-#define sk_CMS_RecipientInfo_num(st) SKM_sk_num(CMS_RecipientInfo, (st))
-#define sk_CMS_RecipientInfo_value(st, i) SKM_sk_value(CMS_RecipientInfo, (st), (i))
-#define sk_CMS_RecipientInfo_set(st, i, val) SKM_sk_set(CMS_RecipientInfo, (st), (i), (val))
-#define sk_CMS_RecipientInfo_zero(st) SKM_sk_zero(CMS_RecipientInfo, (st))
-#define sk_CMS_RecipientInfo_push(st, val) SKM_sk_push(CMS_RecipientInfo, (st), (val))
-#define sk_CMS_RecipientInfo_unshift(st, val) SKM_sk_unshift(CMS_RecipientInfo, (st), (val))
-#define sk_CMS_RecipientInfo_find(st, val) SKM_sk_find(CMS_RecipientInfo, (st), (val))
-#define sk_CMS_RecipientInfo_find_ex(st, val) SKM_sk_find_ex(CMS_RecipientInfo, (st), (val))
-#define sk_CMS_RecipientInfo_delete(st, i) SKM_sk_delete(CMS_RecipientInfo, (st), (i))
-#define sk_CMS_RecipientInfo_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_RecipientInfo, (st), (ptr))
-#define sk_CMS_RecipientInfo_insert(st, val, i) SKM_sk_insert(CMS_RecipientInfo, (st), (val), (i))
-#define sk_CMS_RecipientInfo_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_RecipientInfo, (st), (cmp))
-#define sk_CMS_RecipientInfo_dup(st) SKM_sk_dup(CMS_RecipientInfo, st)
-#define sk_CMS_RecipientInfo_pop_free(st, free_func) SKM_sk_pop_free(CMS_RecipientInfo, (st), (free_func))
-#define sk_CMS_RecipientInfo_shift(st) SKM_sk_shift(CMS_RecipientInfo, (st))
-#define sk_CMS_RecipientInfo_pop(st) SKM_sk_pop(CMS_RecipientInfo, (st))
-#define sk_CMS_RecipientInfo_sort(st) SKM_sk_sort(CMS_RecipientInfo, (st))
-#define sk_CMS_RecipientInfo_is_sorted(st) SKM_sk_is_sorted(CMS_RecipientInfo, (st))
-
-#define sk_CMS_RevocationInfoChoice_new(cmp) SKM_sk_new(CMS_RevocationInfoChoice, (cmp))
-#define sk_CMS_RevocationInfoChoice_new_null() SKM_sk_new_null(CMS_RevocationInfoChoice)
-#define sk_CMS_RevocationInfoChoice_free(st) SKM_sk_free(CMS_RevocationInfoChoice, (st))
-#define sk_CMS_RevocationInfoChoice_num(st) SKM_sk_num(CMS_RevocationInfoChoice, (st))
-#define sk_CMS_RevocationInfoChoice_value(st, i) SKM_sk_value(CMS_RevocationInfoChoice, (st), (i))
-#define sk_CMS_RevocationInfoChoice_set(st, i, val) SKM_sk_set(CMS_RevocationInfoChoice, (st), (i), (val))
-#define sk_CMS_RevocationInfoChoice_zero(st) SKM_sk_zero(CMS_RevocationInfoChoice, (st))
-#define sk_CMS_RevocationInfoChoice_push(st, val) SKM_sk_push(CMS_RevocationInfoChoice, (st), (val))
-#define sk_CMS_RevocationInfoChoice_unshift(st, val) SKM_sk_unshift(CMS_RevocationInfoChoice, (st), (val))
-#define sk_CMS_RevocationInfoChoice_find(st, val) SKM_sk_find(CMS_RevocationInfoChoice, (st), (val))
-#define sk_CMS_RevocationInfoChoice_find_ex(st, val) SKM_sk_find_ex(CMS_RevocationInfoChoice, (st), (val))
-#define sk_CMS_RevocationInfoChoice_delete(st, i) SKM_sk_delete(CMS_RevocationInfoChoice, (st), (i))
-#define sk_CMS_RevocationInfoChoice_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_RevocationInfoChoice, (st), (ptr))
-#define sk_CMS_RevocationInfoChoice_insert(st, val, i) SKM_sk_insert(CMS_RevocationInfoChoice, (st), (val), (i))
-#define sk_CMS_RevocationInfoChoice_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_RevocationInfoChoice, (st), (cmp))
-#define sk_CMS_RevocationInfoChoice_dup(st) SKM_sk_dup(CMS_RevocationInfoChoice, st)
-#define sk_CMS_RevocationInfoChoice_pop_free(st, free_func) SKM_sk_pop_free(CMS_RevocationInfoChoice, (st), (free_func))
-#define sk_CMS_RevocationInfoChoice_shift(st) SKM_sk_shift(CMS_RevocationInfoChoice, (st))
-#define sk_CMS_RevocationInfoChoice_pop(st) SKM_sk_pop(CMS_RevocationInfoChoice, (st))
-#define sk_CMS_RevocationInfoChoice_sort(st) SKM_sk_sort(CMS_RevocationInfoChoice, (st))
-#define sk_CMS_RevocationInfoChoice_is_sorted(st) SKM_sk_is_sorted(CMS_RevocationInfoChoice, (st))
-
-#define sk_CMS_SignerInfo_new(cmp) SKM_sk_new(CMS_SignerInfo, (cmp))
-#define sk_CMS_SignerInfo_new_null() SKM_sk_new_null(CMS_SignerInfo)
-#define sk_CMS_SignerInfo_free(st) SKM_sk_free(CMS_SignerInfo, (st))
-#define sk_CMS_SignerInfo_num(st) SKM_sk_num(CMS_SignerInfo, (st))
-#define sk_CMS_SignerInfo_value(st, i) SKM_sk_value(CMS_SignerInfo, (st), (i))
-#define sk_CMS_SignerInfo_set(st, i, val) SKM_sk_set(CMS_SignerInfo, (st), (i), (val))
-#define sk_CMS_SignerInfo_zero(st) SKM_sk_zero(CMS_SignerInfo, (st))
-#define sk_CMS_SignerInfo_push(st, val) SKM_sk_push(CMS_SignerInfo, (st), (val))
-#define sk_CMS_SignerInfo_unshift(st, val) SKM_sk_unshift(CMS_SignerInfo, (st), (val))
-#define sk_CMS_SignerInfo_find(st, val) SKM_sk_find(CMS_SignerInfo, (st), (val))
-#define sk_CMS_SignerInfo_find_ex(st, val) SKM_sk_find_ex(CMS_SignerInfo, (st), (val))
-#define sk_CMS_SignerInfo_delete(st, i) SKM_sk_delete(CMS_SignerInfo, (st), (i))
-#define sk_CMS_SignerInfo_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_SignerInfo, (st), (ptr))
-#define sk_CMS_SignerInfo_insert(st, val, i) SKM_sk_insert(CMS_SignerInfo, (st), (val), (i))
-#define sk_CMS_SignerInfo_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_SignerInfo, (st), (cmp))
-#define sk_CMS_SignerInfo_dup(st) SKM_sk_dup(CMS_SignerInfo, st)
-#define sk_CMS_SignerInfo_pop_free(st, free_func) SKM_sk_pop_free(CMS_SignerInfo, (st), (free_func))
-#define sk_CMS_SignerInfo_shift(st) SKM_sk_shift(CMS_SignerInfo, (st))
-#define sk_CMS_SignerInfo_pop(st) SKM_sk_pop(CMS_SignerInfo, (st))
-#define sk_CMS_SignerInfo_sort(st) SKM_sk_sort(CMS_SignerInfo, (st))
-#define sk_CMS_SignerInfo_is_sorted(st) SKM_sk_is_sorted(CMS_SignerInfo, (st))
-
-#define sk_CONF_IMODULE_new(cmp) SKM_sk_new(CONF_IMODULE, (cmp))
-#define sk_CONF_IMODULE_new_null() SKM_sk_new_null(CONF_IMODULE)
-#define sk_CONF_IMODULE_free(st) SKM_sk_free(CONF_IMODULE, (st))
-#define sk_CONF_IMODULE_num(st) SKM_sk_num(CONF_IMODULE, (st))
-#define sk_CONF_IMODULE_value(st, i) SKM_sk_value(CONF_IMODULE, (st), (i))
-#define sk_CONF_IMODULE_set(st, i, val) SKM_sk_set(CONF_IMODULE, (st), (i), (val))
-#define sk_CONF_IMODULE_zero(st) SKM_sk_zero(CONF_IMODULE, (st))
-#define sk_CONF_IMODULE_push(st, val) SKM_sk_push(CONF_IMODULE, (st), (val))
-#define sk_CONF_IMODULE_unshift(st, val) SKM_sk_unshift(CONF_IMODULE, (st), (val))
-#define sk_CONF_IMODULE_find(st, val) SKM_sk_find(CONF_IMODULE, (st), (val))
-#define sk_CONF_IMODULE_find_ex(st, val) SKM_sk_find_ex(CONF_IMODULE, (st), (val))
-#define sk_CONF_IMODULE_delete(st, i) SKM_sk_delete(CONF_IMODULE, (st), (i))
-#define sk_CONF_IMODULE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_IMODULE, (st), (ptr))
-#define sk_CONF_IMODULE_insert(st, val, i) SKM_sk_insert(CONF_IMODULE, (st), (val), (i))
-#define sk_CONF_IMODULE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_IMODULE, (st), (cmp))
-#define sk_CONF_IMODULE_dup(st) SKM_sk_dup(CONF_IMODULE, st)
-#define sk_CONF_IMODULE_pop_free(st, free_func) SKM_sk_pop_free(CONF_IMODULE, (st), (free_func))
-#define sk_CONF_IMODULE_shift(st) SKM_sk_shift(CONF_IMODULE, (st))
-#define sk_CONF_IMODULE_pop(st) SKM_sk_pop(CONF_IMODULE, (st))
-#define sk_CONF_IMODULE_sort(st) SKM_sk_sort(CONF_IMODULE, (st))
-#define sk_CONF_IMODULE_is_sorted(st) SKM_sk_is_sorted(CONF_IMODULE, (st))
-
-#define sk_CONF_MODULE_new(cmp) SKM_sk_new(CONF_MODULE, (cmp))
-#define sk_CONF_MODULE_new_null() SKM_sk_new_null(CONF_MODULE)
-#define sk_CONF_MODULE_free(st) SKM_sk_free(CONF_MODULE, (st))
-#define sk_CONF_MODULE_num(st) SKM_sk_num(CONF_MODULE, (st))
-#define sk_CONF_MODULE_value(st, i) SKM_sk_value(CONF_MODULE, (st), (i))
-#define sk_CONF_MODULE_set(st, i, val) SKM_sk_set(CONF_MODULE, (st), (i), (val))
-#define sk_CONF_MODULE_zero(st) SKM_sk_zero(CONF_MODULE, (st))
-#define sk_CONF_MODULE_push(st, val) SKM_sk_push(CONF_MODULE, (st), (val))
-#define sk_CONF_MODULE_unshift(st, val) SKM_sk_unshift(CONF_MODULE, (st), (val))
-#define sk_CONF_MODULE_find(st, val) SKM_sk_find(CONF_MODULE, (st), (val))
-#define sk_CONF_MODULE_find_ex(st, val) SKM_sk_find_ex(CONF_MODULE, (st), (val))
-#define sk_CONF_MODULE_delete(st, i) SKM_sk_delete(CONF_MODULE, (st), (i))
-#define sk_CONF_MODULE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_MODULE, (st), (ptr))
-#define sk_CONF_MODULE_insert(st, val, i) SKM_sk_insert(CONF_MODULE, (st), (val), (i))
-#define sk_CONF_MODULE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_MODULE, (st), (cmp))
-#define sk_CONF_MODULE_dup(st) SKM_sk_dup(CONF_MODULE, st)
-#define sk_CONF_MODULE_pop_free(st, free_func) SKM_sk_pop_free(CONF_MODULE, (st), (free_func))
-#define sk_CONF_MODULE_shift(st) SKM_sk_shift(CONF_MODULE, (st))
-#define sk_CONF_MODULE_pop(st) SKM_sk_pop(CONF_MODULE, (st))
-#define sk_CONF_MODULE_sort(st) SKM_sk_sort(CONF_MODULE, (st))
-#define sk_CONF_MODULE_is_sorted(st) SKM_sk_is_sorted(CONF_MODULE, (st))
-
-#define sk_CONF_VALUE_new(cmp) SKM_sk_new(CONF_VALUE, (cmp))
-#define sk_CONF_VALUE_new_null() SKM_sk_new_null(CONF_VALUE)
-#define sk_CONF_VALUE_free(st) SKM_sk_free(CONF_VALUE, (st))
-#define sk_CONF_VALUE_num(st) SKM_sk_num(CONF_VALUE, (st))
-#define sk_CONF_VALUE_value(st, i) SKM_sk_value(CONF_VALUE, (st), (i))
-#define sk_CONF_VALUE_set(st, i, val) SKM_sk_set(CONF_VALUE, (st), (i), (val))
-#define sk_CONF_VALUE_zero(st) SKM_sk_zero(CONF_VALUE, (st))
-#define sk_CONF_VALUE_push(st, val) SKM_sk_push(CONF_VALUE, (st), (val))
-#define sk_CONF_VALUE_unshift(st, val) SKM_sk_unshift(CONF_VALUE, (st), (val))
-#define sk_CONF_VALUE_find(st, val) SKM_sk_find(CONF_VALUE, (st), (val))
-#define sk_CONF_VALUE_find_ex(st, val) SKM_sk_find_ex(CONF_VALUE, (st), (val))
-#define sk_CONF_VALUE_delete(st, i) SKM_sk_delete(CONF_VALUE, (st), (i))
-#define sk_CONF_VALUE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_VALUE, (st), (ptr))
-#define sk_CONF_VALUE_insert(st, val, i) SKM_sk_insert(CONF_VALUE, (st), (val), (i))
-#define sk_CONF_VALUE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_VALUE, (st), (cmp))
-#define sk_CONF_VALUE_dup(st) SKM_sk_dup(CONF_VALUE, st)
-#define sk_CONF_VALUE_pop_free(st, free_func) SKM_sk_pop_free(CONF_VALUE, (st), (free_func))
-#define sk_CONF_VALUE_shift(st) SKM_sk_shift(CONF_VALUE, (st))
-#define sk_CONF_VALUE_pop(st) SKM_sk_pop(CONF_VALUE, (st))
-#define sk_CONF_VALUE_sort(st) SKM_sk_sort(CONF_VALUE, (st))
-#define sk_CONF_VALUE_is_sorted(st) SKM_sk_is_sorted(CONF_VALUE, (st))
-
-#define sk_CRYPTO_EX_DATA_FUNCS_new(cmp) SKM_sk_new(CRYPTO_EX_DATA_FUNCS, (cmp))
-#define sk_CRYPTO_EX_DATA_FUNCS_new_null() SKM_sk_new_null(CRYPTO_EX_DATA_FUNCS)
-#define sk_CRYPTO_EX_DATA_FUNCS_free(st) SKM_sk_free(CRYPTO_EX_DATA_FUNCS, (st))
-#define sk_CRYPTO_EX_DATA_FUNCS_num(st) SKM_sk_num(CRYPTO_EX_DATA_FUNCS, (st))
-#define sk_CRYPTO_EX_DATA_FUNCS_value(st, i) SKM_sk_value(CRYPTO_EX_DATA_FUNCS, (st), (i))
-#define sk_CRYPTO_EX_DATA_FUNCS_set(st, i, val) SKM_sk_set(CRYPTO_EX_DATA_FUNCS, (st), (i), (val))
-#define sk_CRYPTO_EX_DATA_FUNCS_zero(st) SKM_sk_zero(CRYPTO_EX_DATA_FUNCS, (st))
-#define sk_CRYPTO_EX_DATA_FUNCS_push(st, val) SKM_sk_push(CRYPTO_EX_DATA_FUNCS, (st), (val))
-#define sk_CRYPTO_EX_DATA_FUNCS_unshift(st, val) SKM_sk_unshift(CRYPTO_EX_DATA_FUNCS, (st), (val))
-#define sk_CRYPTO_EX_DATA_FUNCS_find(st, val) SKM_sk_find(CRYPTO_EX_DATA_FUNCS, (st), (val))
-#define sk_CRYPTO_EX_DATA_FUNCS_find_ex(st, val) SKM_sk_find_ex(CRYPTO_EX_DATA_FUNCS, (st), (val))
-#define sk_CRYPTO_EX_DATA_FUNCS_delete(st, i) SKM_sk_delete(CRYPTO_EX_DATA_FUNCS, (st), (i))
-#define sk_CRYPTO_EX_DATA_FUNCS_delete_ptr(st, ptr) SKM_sk_delete_ptr(CRYPTO_EX_DATA_FUNCS, (st), (ptr))
-#define sk_CRYPTO_EX_DATA_FUNCS_insert(st, val, i) SKM_sk_insert(CRYPTO_EX_DATA_FUNCS, (st), (val), (i))
-#define sk_CRYPTO_EX_DATA_FUNCS_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CRYPTO_EX_DATA_FUNCS, (st), (cmp))
-#define sk_CRYPTO_EX_DATA_FUNCS_dup(st) SKM_sk_dup(CRYPTO_EX_DATA_FUNCS, st)
-#define sk_CRYPTO_EX_DATA_FUNCS_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_EX_DATA_FUNCS, (st), (free_func))
-#define sk_CRYPTO_EX_DATA_FUNCS_shift(st) SKM_sk_shift(CRYPTO_EX_DATA_FUNCS, (st))
-#define sk_CRYPTO_EX_DATA_FUNCS_pop(st) SKM_sk_pop(CRYPTO_EX_DATA_FUNCS, (st))
-#define sk_CRYPTO_EX_DATA_FUNCS_sort(st) SKM_sk_sort(CRYPTO_EX_DATA_FUNCS, (st))
-#define sk_CRYPTO_EX_DATA_FUNCS_is_sorted(st) SKM_sk_is_sorted(CRYPTO_EX_DATA_FUNCS, (st))
-
-#define sk_CRYPTO_dynlock_new(cmp) SKM_sk_new(CRYPTO_dynlock, (cmp))
-#define sk_CRYPTO_dynlock_new_null() SKM_sk_new_null(CRYPTO_dynlock)
-#define sk_CRYPTO_dynlock_free(st) SKM_sk_free(CRYPTO_dynlock, (st))
-#define sk_CRYPTO_dynlock_num(st) SKM_sk_num(CRYPTO_dynlock, (st))
-#define sk_CRYPTO_dynlock_value(st, i) SKM_sk_value(CRYPTO_dynlock, (st), (i))
-#define sk_CRYPTO_dynlock_set(st, i, val) SKM_sk_set(CRYPTO_dynlock, (st), (i), (val))
-#define sk_CRYPTO_dynlock_zero(st) SKM_sk_zero(CRYPTO_dynlock, (st))
-#define sk_CRYPTO_dynlock_push(st, val) SKM_sk_push(CRYPTO_dynlock, (st), (val))
-#define sk_CRYPTO_dynlock_unshift(st, val) SKM_sk_unshift(CRYPTO_dynlock, (st), (val))
-#define sk_CRYPTO_dynlock_find(st, val) SKM_sk_find(CRYPTO_dynlock, (st), (val))
-#define sk_CRYPTO_dynlock_find_ex(st, val) SKM_sk_find_ex(CRYPTO_dynlock, (st), (val))
-#define sk_CRYPTO_dynlock_delete(st, i) SKM_sk_delete(CRYPTO_dynlock, (st), (i))
-#define sk_CRYPTO_dynlock_delete_ptr(st, ptr) SKM_sk_delete_ptr(CRYPTO_dynlock, (st), (ptr))
-#define sk_CRYPTO_dynlock_insert(st, val, i) SKM_sk_insert(CRYPTO_dynlock, (st), (val), (i))
-#define sk_CRYPTO_dynlock_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CRYPTO_dynlock, (st), (cmp))
-#define sk_CRYPTO_dynlock_dup(st) SKM_sk_dup(CRYPTO_dynlock, st)
-#define sk_CRYPTO_dynlock_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_dynlock, (st), (free_func))
-#define sk_CRYPTO_dynlock_shift(st) SKM_sk_shift(CRYPTO_dynlock, (st))
-#define sk_CRYPTO_dynlock_pop(st) SKM_sk_pop(CRYPTO_dynlock, (st))
-#define sk_CRYPTO_dynlock_sort(st) SKM_sk_sort(CRYPTO_dynlock, (st))
-#define sk_CRYPTO_dynlock_is_sorted(st) SKM_sk_is_sorted(CRYPTO_dynlock, (st))
-
-#define sk_DIST_POINT_new(cmp) SKM_sk_new(DIST_POINT, (cmp))
-#define sk_DIST_POINT_new_null() SKM_sk_new_null(DIST_POINT)
-#define sk_DIST_POINT_free(st) SKM_sk_free(DIST_POINT, (st))
-#define sk_DIST_POINT_num(st) SKM_sk_num(DIST_POINT, (st))
-#define sk_DIST_POINT_value(st, i) SKM_sk_value(DIST_POINT, (st), (i))
-#define sk_DIST_POINT_set(st, i, val) SKM_sk_set(DIST_POINT, (st), (i), (val))
-#define sk_DIST_POINT_zero(st) SKM_sk_zero(DIST_POINT, (st))
-#define sk_DIST_POINT_push(st, val) SKM_sk_push(DIST_POINT, (st), (val))
-#define sk_DIST_POINT_unshift(st, val) SKM_sk_unshift(DIST_POINT, (st), (val))
-#define sk_DIST_POINT_find(st, val) SKM_sk_find(DIST_POINT, (st), (val))
-#define sk_DIST_POINT_find_ex(st, val) SKM_sk_find_ex(DIST_POINT, (st), (val))
-#define sk_DIST_POINT_delete(st, i) SKM_sk_delete(DIST_POINT, (st), (i))
-#define sk_DIST_POINT_delete_ptr(st, ptr) SKM_sk_delete_ptr(DIST_POINT, (st), (ptr))
-#define sk_DIST_POINT_insert(st, val, i) SKM_sk_insert(DIST_POINT, (st), (val), (i))
-#define sk_DIST_POINT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(DIST_POINT, (st), (cmp))
-#define sk_DIST_POINT_dup(st) SKM_sk_dup(DIST_POINT, st)
-#define sk_DIST_POINT_pop_free(st, free_func) SKM_sk_pop_free(DIST_POINT, (st), (free_func))
-#define sk_DIST_POINT_shift(st) SKM_sk_shift(DIST_POINT, (st))
-#define sk_DIST_POINT_pop(st) SKM_sk_pop(DIST_POINT, (st))
-#define sk_DIST_POINT_sort(st) SKM_sk_sort(DIST_POINT, (st))
-#define sk_DIST_POINT_is_sorted(st) SKM_sk_is_sorted(DIST_POINT, (st))
-
-#define sk_ENGINE_new(cmp) SKM_sk_new(ENGINE, (cmp))
-#define sk_ENGINE_new_null() SKM_sk_new_null(ENGINE)
-#define sk_ENGINE_free(st) SKM_sk_free(ENGINE, (st))
-#define sk_ENGINE_num(st) SKM_sk_num(ENGINE, (st))
-#define sk_ENGINE_value(st, i) SKM_sk_value(ENGINE, (st), (i))
-#define sk_ENGINE_set(st, i, val) SKM_sk_set(ENGINE, (st), (i), (val))
-#define sk_ENGINE_zero(st) SKM_sk_zero(ENGINE, (st))
-#define sk_ENGINE_push(st, val) SKM_sk_push(ENGINE, (st), (val))
-#define sk_ENGINE_unshift(st, val) SKM_sk_unshift(ENGINE, (st), (val))
-#define sk_ENGINE_find(st, val) SKM_sk_find(ENGINE, (st), (val))
-#define sk_ENGINE_find_ex(st, val) SKM_sk_find_ex(ENGINE, (st), (val))
-#define sk_ENGINE_delete(st, i) SKM_sk_delete(ENGINE, (st), (i))
-#define sk_ENGINE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ENGINE, (st), (ptr))
-#define sk_ENGINE_insert(st, val, i) SKM_sk_insert(ENGINE, (st), (val), (i))
-#define sk_ENGINE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ENGINE, (st), (cmp))
-#define sk_ENGINE_dup(st) SKM_sk_dup(ENGINE, st)
-#define sk_ENGINE_pop_free(st, free_func) SKM_sk_pop_free(ENGINE, (st), (free_func))
-#define sk_ENGINE_shift(st) SKM_sk_shift(ENGINE, (st))
-#define sk_ENGINE_pop(st) SKM_sk_pop(ENGINE, (st))
-#define sk_ENGINE_sort(st) SKM_sk_sort(ENGINE, (st))
-#define sk_ENGINE_is_sorted(st) SKM_sk_is_sorted(ENGINE, (st))
-
-#define sk_ENGINE_CLEANUP_ITEM_new(cmp) SKM_sk_new(ENGINE_CLEANUP_ITEM, (cmp))
-#define sk_ENGINE_CLEANUP_ITEM_new_null() SKM_sk_new_null(ENGINE_CLEANUP_ITEM)
-#define sk_ENGINE_CLEANUP_ITEM_free(st) SKM_sk_free(ENGINE_CLEANUP_ITEM, (st))
-#define sk_ENGINE_CLEANUP_ITEM_num(st) SKM_sk_num(ENGINE_CLEANUP_ITEM, (st))
-#define sk_ENGINE_CLEANUP_ITEM_value(st, i) SKM_sk_value(ENGINE_CLEANUP_ITEM, (st), (i))
-#define sk_ENGINE_CLEANUP_ITEM_set(st, i, val) SKM_sk_set(ENGINE_CLEANUP_ITEM, (st), (i), (val))
-#define sk_ENGINE_CLEANUP_ITEM_zero(st) SKM_sk_zero(ENGINE_CLEANUP_ITEM, (st))
-#define sk_ENGINE_CLEANUP_ITEM_push(st, val) SKM_sk_push(ENGINE_CLEANUP_ITEM, (st), (val))
-#define sk_ENGINE_CLEANUP_ITEM_unshift(st, val) SKM_sk_unshift(ENGINE_CLEANUP_ITEM, (st), (val))
-#define sk_ENGINE_CLEANUP_ITEM_find(st, val) SKM_sk_find(ENGINE_CLEANUP_ITEM, (st), (val))
-#define sk_ENGINE_CLEANUP_ITEM_find_ex(st, val) SKM_sk_find_ex(ENGINE_CLEANUP_ITEM, (st), (val))
-#define sk_ENGINE_CLEANUP_ITEM_delete(st, i) SKM_sk_delete(ENGINE_CLEANUP_ITEM, (st), (i))
-#define sk_ENGINE_CLEANUP_ITEM_delete_ptr(st, ptr) SKM_sk_delete_ptr(ENGINE_CLEANUP_ITEM, (st), (ptr))
-#define sk_ENGINE_CLEANUP_ITEM_insert(st, val, i) SKM_sk_insert(ENGINE_CLEANUP_ITEM, (st), (val), (i))
-#define sk_ENGINE_CLEANUP_ITEM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ENGINE_CLEANUP_ITEM, (st), (cmp))
-#define sk_ENGINE_CLEANUP_ITEM_dup(st) SKM_sk_dup(ENGINE_CLEANUP_ITEM, st)
-#define sk_ENGINE_CLEANUP_ITEM_pop_free(st, free_func) SKM_sk_pop_free(ENGINE_CLEANUP_ITEM, (st), (free_func))
-#define sk_ENGINE_CLEANUP_ITEM_shift(st) SKM_sk_shift(ENGINE_CLEANUP_ITEM, (st))
-#define sk_ENGINE_CLEANUP_ITEM_pop(st) SKM_sk_pop(ENGINE_CLEANUP_ITEM, (st))
-#define sk_ENGINE_CLEANUP_ITEM_sort(st) SKM_sk_sort(ENGINE_CLEANUP_ITEM, (st))
-#define sk_ENGINE_CLEANUP_ITEM_is_sorted(st) SKM_sk_is_sorted(ENGINE_CLEANUP_ITEM, (st))
-
-#define sk_ESS_CERT_ID_new(cmp) SKM_sk_new(ESS_CERT_ID, (cmp))
-#define sk_ESS_CERT_ID_new_null() SKM_sk_new_null(ESS_CERT_ID)
-#define sk_ESS_CERT_ID_free(st) SKM_sk_free(ESS_CERT_ID, (st))
-#define sk_ESS_CERT_ID_num(st) SKM_sk_num(ESS_CERT_ID, (st))
-#define sk_ESS_CERT_ID_value(st, i) SKM_sk_value(ESS_CERT_ID, (st), (i))
-#define sk_ESS_CERT_ID_set(st, i, val) SKM_sk_set(ESS_CERT_ID, (st), (i), (val))
-#define sk_ESS_CERT_ID_zero(st) SKM_sk_zero(ESS_CERT_ID, (st))
-#define sk_ESS_CERT_ID_push(st, val) SKM_sk_push(ESS_CERT_ID, (st), (val))
-#define sk_ESS_CERT_ID_unshift(st, val) SKM_sk_unshift(ESS_CERT_ID, (st), (val))
-#define sk_ESS_CERT_ID_find(st, val) SKM_sk_find(ESS_CERT_ID, (st), (val))
-#define sk_ESS_CERT_ID_find_ex(st, val) SKM_sk_find_ex(ESS_CERT_ID, (st), (val))
-#define sk_ESS_CERT_ID_delete(st, i) SKM_sk_delete(ESS_CERT_ID, (st), (i))
-#define sk_ESS_CERT_ID_delete_ptr(st, ptr) SKM_sk_delete_ptr(ESS_CERT_ID, (st), (ptr))
-#define sk_ESS_CERT_ID_insert(st, val, i) SKM_sk_insert(ESS_CERT_ID, (st), (val), (i))
-#define sk_ESS_CERT_ID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ESS_CERT_ID, (st), (cmp))
-#define sk_ESS_CERT_ID_dup(st) SKM_sk_dup(ESS_CERT_ID, st)
-#define sk_ESS_CERT_ID_pop_free(st, free_func) SKM_sk_pop_free(ESS_CERT_ID, (st), (free_func))
-#define sk_ESS_CERT_ID_shift(st) SKM_sk_shift(ESS_CERT_ID, (st))
-#define sk_ESS_CERT_ID_pop(st) SKM_sk_pop(ESS_CERT_ID, (st))
-#define sk_ESS_CERT_ID_sort(st) SKM_sk_sort(ESS_CERT_ID, (st))
-#define sk_ESS_CERT_ID_is_sorted(st) SKM_sk_is_sorted(ESS_CERT_ID, (st))
-
-#define sk_EVP_MD_new(cmp) SKM_sk_new(EVP_MD, (cmp))
-#define sk_EVP_MD_new_null() SKM_sk_new_null(EVP_MD)
-#define sk_EVP_MD_free(st) SKM_sk_free(EVP_MD, (st))
-#define sk_EVP_MD_num(st) SKM_sk_num(EVP_MD, (st))
-#define sk_EVP_MD_value(st, i) SKM_sk_value(EVP_MD, (st), (i))
-#define sk_EVP_MD_set(st, i, val) SKM_sk_set(EVP_MD, (st), (i), (val))
-#define sk_EVP_MD_zero(st) SKM_sk_zero(EVP_MD, (st))
-#define sk_EVP_MD_push(st, val) SKM_sk_push(EVP_MD, (st), (val))
-#define sk_EVP_MD_unshift(st, val) SKM_sk_unshift(EVP_MD, (st), (val))
-#define sk_EVP_MD_find(st, val) SKM_sk_find(EVP_MD, (st), (val))
-#define sk_EVP_MD_find_ex(st, val) SKM_sk_find_ex(EVP_MD, (st), (val))
-#define sk_EVP_MD_delete(st, i) SKM_sk_delete(EVP_MD, (st), (i))
-#define sk_EVP_MD_delete_ptr(st, ptr) SKM_sk_delete_ptr(EVP_MD, (st), (ptr))
-#define sk_EVP_MD_insert(st, val, i) SKM_sk_insert(EVP_MD, (st), (val), (i))
-#define sk_EVP_MD_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(EVP_MD, (st), (cmp))
-#define sk_EVP_MD_dup(st) SKM_sk_dup(EVP_MD, st)
-#define sk_EVP_MD_pop_free(st, free_func) SKM_sk_pop_free(EVP_MD, (st), (free_func))
-#define sk_EVP_MD_shift(st) SKM_sk_shift(EVP_MD, (st))
-#define sk_EVP_MD_pop(st) SKM_sk_pop(EVP_MD, (st))
-#define sk_EVP_MD_sort(st) SKM_sk_sort(EVP_MD, (st))
-#define sk_EVP_MD_is_sorted(st) SKM_sk_is_sorted(EVP_MD, (st))
-
-#define sk_EVP_PBE_CTL_new(cmp) SKM_sk_new(EVP_PBE_CTL, (cmp))
-#define sk_EVP_PBE_CTL_new_null() SKM_sk_new_null(EVP_PBE_CTL)
-#define sk_EVP_PBE_CTL_free(st) SKM_sk_free(EVP_PBE_CTL, (st))
-#define sk_EVP_PBE_CTL_num(st) SKM_sk_num(EVP_PBE_CTL, (st))
-#define sk_EVP_PBE_CTL_value(st, i) SKM_sk_value(EVP_PBE_CTL, (st), (i))
-#define sk_EVP_PBE_CTL_set(st, i, val) SKM_sk_set(EVP_PBE_CTL, (st), (i), (val))
-#define sk_EVP_PBE_CTL_zero(st) SKM_sk_zero(EVP_PBE_CTL, (st))
-#define sk_EVP_PBE_CTL_push(st, val) SKM_sk_push(EVP_PBE_CTL, (st), (val))
-#define sk_EVP_PBE_CTL_unshift(st, val) SKM_sk_unshift(EVP_PBE_CTL, (st), (val))
-#define sk_EVP_PBE_CTL_find(st, val) SKM_sk_find(EVP_PBE_CTL, (st), (val))
-#define sk_EVP_PBE_CTL_find_ex(st, val) SKM_sk_find_ex(EVP_PBE_CTL, (st), (val))
-#define sk_EVP_PBE_CTL_delete(st, i) SKM_sk_delete(EVP_PBE_CTL, (st), (i))
-#define sk_EVP_PBE_CTL_delete_ptr(st, ptr) SKM_sk_delete_ptr(EVP_PBE_CTL, (st), (ptr))
-#define sk_EVP_PBE_CTL_insert(st, val, i) SKM_sk_insert(EVP_PBE_CTL, (st), (val), (i))
-#define sk_EVP_PBE_CTL_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(EVP_PBE_CTL, (st), (cmp))
-#define sk_EVP_PBE_CTL_dup(st) SKM_sk_dup(EVP_PBE_CTL, st)
-#define sk_EVP_PBE_CTL_pop_free(st, free_func) SKM_sk_pop_free(EVP_PBE_CTL, (st), (free_func))
-#define sk_EVP_PBE_CTL_shift(st) SKM_sk_shift(EVP_PBE_CTL, (st))
-#define sk_EVP_PBE_CTL_pop(st) SKM_sk_pop(EVP_PBE_CTL, (st))
-#define sk_EVP_PBE_CTL_sort(st) SKM_sk_sort(EVP_PBE_CTL, (st))
-#define sk_EVP_PBE_CTL_is_sorted(st) SKM_sk_is_sorted(EVP_PBE_CTL, (st))
-
-#define sk_EVP_PKEY_ASN1_METHOD_new(cmp) SKM_sk_new(EVP_PKEY_ASN1_METHOD, (cmp))
-#define sk_EVP_PKEY_ASN1_METHOD_new_null() SKM_sk_new_null(EVP_PKEY_ASN1_METHOD)
-#define sk_EVP_PKEY_ASN1_METHOD_free(st) SKM_sk_free(EVP_PKEY_ASN1_METHOD, (st))
-#define sk_EVP_PKEY_ASN1_METHOD_num(st) SKM_sk_num(EVP_PKEY_ASN1_METHOD, (st))
-#define sk_EVP_PKEY_ASN1_METHOD_value(st, i) SKM_sk_value(EVP_PKEY_ASN1_METHOD, (st), (i))
-#define sk_EVP_PKEY_ASN1_METHOD_set(st, i, val) SKM_sk_set(EVP_PKEY_ASN1_METHOD, (st), (i), (val))
-#define sk_EVP_PKEY_ASN1_METHOD_zero(st) SKM_sk_zero(EVP_PKEY_ASN1_METHOD, (st))
-#define sk_EVP_PKEY_ASN1_METHOD_push(st, val) SKM_sk_push(EVP_PKEY_ASN1_METHOD, (st), (val))
-#define sk_EVP_PKEY_ASN1_METHOD_unshift(st, val) SKM_sk_unshift(EVP_PKEY_ASN1_METHOD, (st), (val))
-#define sk_EVP_PKEY_ASN1_METHOD_find(st, val) SKM_sk_find(EVP_PKEY_ASN1_METHOD, (st), (val))
-#define sk_EVP_PKEY_ASN1_METHOD_find_ex(st, val) SKM_sk_find_ex(EVP_PKEY_ASN1_METHOD, (st), (val))
-#define sk_EVP_PKEY_ASN1_METHOD_delete(st, i) SKM_sk_delete(EVP_PKEY_ASN1_METHOD, (st), (i))
-#define sk_EVP_PKEY_ASN1_METHOD_delete_ptr(st, ptr) SKM_sk_delete_ptr(EVP_PKEY_ASN1_METHOD, (st), (ptr))
-#define sk_EVP_PKEY_ASN1_METHOD_insert(st, val, i) SKM_sk_insert(EVP_PKEY_ASN1_METHOD, (st), (val), (i))
-#define sk_EVP_PKEY_ASN1_METHOD_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(EVP_PKEY_ASN1_METHOD, (st), (cmp))
-#define sk_EVP_PKEY_ASN1_METHOD_dup(st) SKM_sk_dup(EVP_PKEY_ASN1_METHOD, st)
-#define sk_EVP_PKEY_ASN1_METHOD_pop_free(st, free_func) SKM_sk_pop_free(EVP_PKEY_ASN1_METHOD, (st), (free_func))
-#define sk_EVP_PKEY_ASN1_METHOD_shift(st) SKM_sk_shift(EVP_PKEY_ASN1_METHOD, (st))
-#define sk_EVP_PKEY_ASN1_METHOD_pop(st) SKM_sk_pop(EVP_PKEY_ASN1_METHOD, (st))
-#define sk_EVP_PKEY_ASN1_METHOD_sort(st) SKM_sk_sort(EVP_PKEY_ASN1_METHOD, (st))
-#define sk_EVP_PKEY_ASN1_METHOD_is_sorted(st) SKM_sk_is_sorted(EVP_PKEY_ASN1_METHOD, (st))
-
-#define sk_EVP_PKEY_METHOD_new(cmp) SKM_sk_new(EVP_PKEY_METHOD, (cmp))
-#define sk_EVP_PKEY_METHOD_new_null() SKM_sk_new_null(EVP_PKEY_METHOD)
-#define sk_EVP_PKEY_METHOD_free(st) SKM_sk_free(EVP_PKEY_METHOD, (st))
-#define sk_EVP_PKEY_METHOD_num(st) SKM_sk_num(EVP_PKEY_METHOD, (st))
-#define sk_EVP_PKEY_METHOD_value(st, i) SKM_sk_value(EVP_PKEY_METHOD, (st), (i))
-#define sk_EVP_PKEY_METHOD_set(st, i, val) SKM_sk_set(EVP_PKEY_METHOD, (st), (i), (val))
-#define sk_EVP_PKEY_METHOD_zero(st) SKM_sk_zero(EVP_PKEY_METHOD, (st))
-#define sk_EVP_PKEY_METHOD_push(st, val) SKM_sk_push(EVP_PKEY_METHOD, (st), (val))
-#define sk_EVP_PKEY_METHOD_unshift(st, val) SKM_sk_unshift(EVP_PKEY_METHOD, (st), (val))
-#define sk_EVP_PKEY_METHOD_find(st, val) SKM_sk_find(EVP_PKEY_METHOD, (st), (val))
-#define sk_EVP_PKEY_METHOD_find_ex(st, val) SKM_sk_find_ex(EVP_PKEY_METHOD, (st), (val))
-#define sk_EVP_PKEY_METHOD_delete(st, i) SKM_sk_delete(EVP_PKEY_METHOD, (st), (i))
-#define sk_EVP_PKEY_METHOD_delete_ptr(st, ptr) SKM_sk_delete_ptr(EVP_PKEY_METHOD, (st), (ptr))
-#define sk_EVP_PKEY_METHOD_insert(st, val, i) SKM_sk_insert(EVP_PKEY_METHOD, (st), (val), (i))
-#define sk_EVP_PKEY_METHOD_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(EVP_PKEY_METHOD, (st), (cmp))
-#define sk_EVP_PKEY_METHOD_dup(st) SKM_sk_dup(EVP_PKEY_METHOD, st)
-#define sk_EVP_PKEY_METHOD_pop_free(st, free_func) SKM_sk_pop_free(EVP_PKEY_METHOD, (st), (free_func))
-#define sk_EVP_PKEY_METHOD_shift(st) SKM_sk_shift(EVP_PKEY_METHOD, (st))
-#define sk_EVP_PKEY_METHOD_pop(st) SKM_sk_pop(EVP_PKEY_METHOD, (st))
-#define sk_EVP_PKEY_METHOD_sort(st) SKM_sk_sort(EVP_PKEY_METHOD, (st))
-#define sk_EVP_PKEY_METHOD_is_sorted(st) SKM_sk_is_sorted(EVP_PKEY_METHOD, (st))
-
-#define sk_GENERAL_NAME_new(cmp) SKM_sk_new(GENERAL_NAME, (cmp))
-#define sk_GENERAL_NAME_new_null() SKM_sk_new_null(GENERAL_NAME)
-#define sk_GENERAL_NAME_free(st) SKM_sk_free(GENERAL_NAME, (st))
-#define sk_GENERAL_NAME_num(st) SKM_sk_num(GENERAL_NAME, (st))
-#define sk_GENERAL_NAME_value(st, i) SKM_sk_value(GENERAL_NAME, (st), (i))
-#define sk_GENERAL_NAME_set(st, i, val) SKM_sk_set(GENERAL_NAME, (st), (i), (val))
-#define sk_GENERAL_NAME_zero(st) SKM_sk_zero(GENERAL_NAME, (st))
-#define sk_GENERAL_NAME_push(st, val) SKM_sk_push(GENERAL_NAME, (st), (val))
-#define sk_GENERAL_NAME_unshift(st, val) SKM_sk_unshift(GENERAL_NAME, (st), (val))
-#define sk_GENERAL_NAME_find(st, val) SKM_sk_find(GENERAL_NAME, (st), (val))
-#define sk_GENERAL_NAME_find_ex(st, val) SKM_sk_find_ex(GENERAL_NAME, (st), (val))
-#define sk_GENERAL_NAME_delete(st, i) SKM_sk_delete(GENERAL_NAME, (st), (i))
-#define sk_GENERAL_NAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_NAME, (st), (ptr))
-#define sk_GENERAL_NAME_insert(st, val, i) SKM_sk_insert(GENERAL_NAME, (st), (val), (i))
-#define sk_GENERAL_NAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_NAME, (st), (cmp))
-#define sk_GENERAL_NAME_dup(st) SKM_sk_dup(GENERAL_NAME, st)
-#define sk_GENERAL_NAME_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_NAME, (st), (free_func))
-#define sk_GENERAL_NAME_shift(st) SKM_sk_shift(GENERAL_NAME, (st))
-#define sk_GENERAL_NAME_pop(st) SKM_sk_pop(GENERAL_NAME, (st))
-#define sk_GENERAL_NAME_sort(st) SKM_sk_sort(GENERAL_NAME, (st))
-#define sk_GENERAL_NAME_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAME, (st))
-
-#define sk_GENERAL_NAMES_new(cmp) SKM_sk_new(GENERAL_NAMES, (cmp))
-#define sk_GENERAL_NAMES_new_null() SKM_sk_new_null(GENERAL_NAMES)
-#define sk_GENERAL_NAMES_free(st) SKM_sk_free(GENERAL_NAMES, (st))
-#define sk_GENERAL_NAMES_num(st) SKM_sk_num(GENERAL_NAMES, (st))
-#define sk_GENERAL_NAMES_value(st, i) SKM_sk_value(GENERAL_NAMES, (st), (i))
-#define sk_GENERAL_NAMES_set(st, i, val) SKM_sk_set(GENERAL_NAMES, (st), (i), (val))
-#define sk_GENERAL_NAMES_zero(st) SKM_sk_zero(GENERAL_NAMES, (st))
-#define sk_GENERAL_NAMES_push(st, val) SKM_sk_push(GENERAL_NAMES, (st), (val))
-#define sk_GENERAL_NAMES_unshift(st, val) SKM_sk_unshift(GENERAL_NAMES, (st), (val))
-#define sk_GENERAL_NAMES_find(st, val) SKM_sk_find(GENERAL_NAMES, (st), (val))
-#define sk_GENERAL_NAMES_find_ex(st, val) SKM_sk_find_ex(GENERAL_NAMES, (st), (val))
-#define sk_GENERAL_NAMES_delete(st, i) SKM_sk_delete(GENERAL_NAMES, (st), (i))
-#define sk_GENERAL_NAMES_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_NAMES, (st), (ptr))
-#define sk_GENERAL_NAMES_insert(st, val, i) SKM_sk_insert(GENERAL_NAMES, (st), (val), (i))
-#define sk_GENERAL_NAMES_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_NAMES, (st), (cmp))
-#define sk_GENERAL_NAMES_dup(st) SKM_sk_dup(GENERAL_NAMES, st)
-#define sk_GENERAL_NAMES_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_NAMES, (st), (free_func))
-#define sk_GENERAL_NAMES_shift(st) SKM_sk_shift(GENERAL_NAMES, (st))
-#define sk_GENERAL_NAMES_pop(st) SKM_sk_pop(GENERAL_NAMES, (st))
-#define sk_GENERAL_NAMES_sort(st) SKM_sk_sort(GENERAL_NAMES, (st))
-#define sk_GENERAL_NAMES_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAMES, (st))
-
-#define sk_GENERAL_SUBTREE_new(cmp) SKM_sk_new(GENERAL_SUBTREE, (cmp))
-#define sk_GENERAL_SUBTREE_new_null() SKM_sk_new_null(GENERAL_SUBTREE)
-#define sk_GENERAL_SUBTREE_free(st) SKM_sk_free(GENERAL_SUBTREE, (st))
-#define sk_GENERAL_SUBTREE_num(st) SKM_sk_num(GENERAL_SUBTREE, (st))
-#define sk_GENERAL_SUBTREE_value(st, i) SKM_sk_value(GENERAL_SUBTREE, (st), (i))
-#define sk_GENERAL_SUBTREE_set(st, i, val) SKM_sk_set(GENERAL_SUBTREE, (st), (i), (val))
-#define sk_GENERAL_SUBTREE_zero(st) SKM_sk_zero(GENERAL_SUBTREE, (st))
-#define sk_GENERAL_SUBTREE_push(st, val) SKM_sk_push(GENERAL_SUBTREE, (st), (val))
-#define sk_GENERAL_SUBTREE_unshift(st, val) SKM_sk_unshift(GENERAL_SUBTREE, (st), (val))
-#define sk_GENERAL_SUBTREE_find(st, val) SKM_sk_find(GENERAL_SUBTREE, (st), (val))
-#define sk_GENERAL_SUBTREE_find_ex(st, val) SKM_sk_find_ex(GENERAL_SUBTREE, (st), (val))
-#define sk_GENERAL_SUBTREE_delete(st, i) SKM_sk_delete(GENERAL_SUBTREE, (st), (i))
-#define sk_GENERAL_SUBTREE_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_SUBTREE, (st), (ptr))
-#define sk_GENERAL_SUBTREE_insert(st, val, i) SKM_sk_insert(GENERAL_SUBTREE, (st), (val), (i))
-#define sk_GENERAL_SUBTREE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_SUBTREE, (st), (cmp))
-#define sk_GENERAL_SUBTREE_dup(st) SKM_sk_dup(GENERAL_SUBTREE, st)
-#define sk_GENERAL_SUBTREE_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_SUBTREE, (st), (free_func))
-#define sk_GENERAL_SUBTREE_shift(st) SKM_sk_shift(GENERAL_SUBTREE, (st))
-#define sk_GENERAL_SUBTREE_pop(st) SKM_sk_pop(GENERAL_SUBTREE, (st))
-#define sk_GENERAL_SUBTREE_sort(st) SKM_sk_sort(GENERAL_SUBTREE, (st))
-#define sk_GENERAL_SUBTREE_is_sorted(st) SKM_sk_is_sorted(GENERAL_SUBTREE, (st))
-
-#define sk_IPAddressFamily_new(cmp) SKM_sk_new(IPAddressFamily, (cmp))
-#define sk_IPAddressFamily_new_null() SKM_sk_new_null(IPAddressFamily)
-#define sk_IPAddressFamily_free(st) SKM_sk_free(IPAddressFamily, (st))
-#define sk_IPAddressFamily_num(st) SKM_sk_num(IPAddressFamily, (st))
-#define sk_IPAddressFamily_value(st, i) SKM_sk_value(IPAddressFamily, (st), (i))
-#define sk_IPAddressFamily_set(st, i, val) SKM_sk_set(IPAddressFamily, (st), (i), (val))
-#define sk_IPAddressFamily_zero(st) SKM_sk_zero(IPAddressFamily, (st))
-#define sk_IPAddressFamily_push(st, val) SKM_sk_push(IPAddressFamily, (st), (val))
-#define sk_IPAddressFamily_unshift(st, val) SKM_sk_unshift(IPAddressFamily, (st), (val))
-#define sk_IPAddressFamily_find(st, val) SKM_sk_find(IPAddressFamily, (st), (val))
-#define sk_IPAddressFamily_find_ex(st, val) SKM_sk_find_ex(IPAddressFamily, (st), (val))
-#define sk_IPAddressFamily_delete(st, i) SKM_sk_delete(IPAddressFamily, (st), (i))
-#define sk_IPAddressFamily_delete_ptr(st, ptr) SKM_sk_delete_ptr(IPAddressFamily, (st), (ptr))
-#define sk_IPAddressFamily_insert(st, val, i) SKM_sk_insert(IPAddressFamily, (st), (val), (i))
-#define sk_IPAddressFamily_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(IPAddressFamily, (st), (cmp))
-#define sk_IPAddressFamily_dup(st) SKM_sk_dup(IPAddressFamily, st)
-#define sk_IPAddressFamily_pop_free(st, free_func) SKM_sk_pop_free(IPAddressFamily, (st), (free_func))
-#define sk_IPAddressFamily_shift(st) SKM_sk_shift(IPAddressFamily, (st))
-#define sk_IPAddressFamily_pop(st) SKM_sk_pop(IPAddressFamily, (st))
-#define sk_IPAddressFamily_sort(st) SKM_sk_sort(IPAddressFamily, (st))
-#define sk_IPAddressFamily_is_sorted(st) SKM_sk_is_sorted(IPAddressFamily, (st))
-
-#define sk_IPAddressOrRange_new(cmp) SKM_sk_new(IPAddressOrRange, (cmp))
-#define sk_IPAddressOrRange_new_null() SKM_sk_new_null(IPAddressOrRange)
-#define sk_IPAddressOrRange_free(st) SKM_sk_free(IPAddressOrRange, (st))
-#define sk_IPAddressOrRange_num(st) SKM_sk_num(IPAddressOrRange, (st))
-#define sk_IPAddressOrRange_value(st, i) SKM_sk_value(IPAddressOrRange, (st), (i))
-#define sk_IPAddressOrRange_set(st, i, val) SKM_sk_set(IPAddressOrRange, (st), (i), (val))
-#define sk_IPAddressOrRange_zero(st) SKM_sk_zero(IPAddressOrRange, (st))
-#define sk_IPAddressOrRange_push(st, val) SKM_sk_push(IPAddressOrRange, (st), (val))
-#define sk_IPAddressOrRange_unshift(st, val) SKM_sk_unshift(IPAddressOrRange, (st), (val))
-#define sk_IPAddressOrRange_find(st, val) SKM_sk_find(IPAddressOrRange, (st), (val))
-#define sk_IPAddressOrRange_find_ex(st, val) SKM_sk_find_ex(IPAddressOrRange, (st), (val))
-#define sk_IPAddressOrRange_delete(st, i) SKM_sk_delete(IPAddressOrRange, (st), (i))
-#define sk_IPAddressOrRange_delete_ptr(st, ptr) SKM_sk_delete_ptr(IPAddressOrRange, (st), (ptr))
-#define sk_IPAddressOrRange_insert(st, val, i) SKM_sk_insert(IPAddressOrRange, (st), (val), (i))
-#define sk_IPAddressOrRange_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(IPAddressOrRange, (st), (cmp))
-#define sk_IPAddressOrRange_dup(st) SKM_sk_dup(IPAddressOrRange, st)
-#define sk_IPAddressOrRange_pop_free(st, free_func) SKM_sk_pop_free(IPAddressOrRange, (st), (free_func))
-#define sk_IPAddressOrRange_shift(st) SKM_sk_shift(IPAddressOrRange, (st))
-#define sk_IPAddressOrRange_pop(st) SKM_sk_pop(IPAddressOrRange, (st))
-#define sk_IPAddressOrRange_sort(st) SKM_sk_sort(IPAddressOrRange, (st))
-#define sk_IPAddressOrRange_is_sorted(st) SKM_sk_is_sorted(IPAddressOrRange, (st))
-
-#define sk_KRB5_APREQBODY_new(cmp) SKM_sk_new(KRB5_APREQBODY, (cmp))
-#define sk_KRB5_APREQBODY_new_null() SKM_sk_new_null(KRB5_APREQBODY)
-#define sk_KRB5_APREQBODY_free(st) SKM_sk_free(KRB5_APREQBODY, (st))
-#define sk_KRB5_APREQBODY_num(st) SKM_sk_num(KRB5_APREQBODY, (st))
-#define sk_KRB5_APREQBODY_value(st, i) SKM_sk_value(KRB5_APREQBODY, (st), (i))
-#define sk_KRB5_APREQBODY_set(st, i, val) SKM_sk_set(KRB5_APREQBODY, (st), (i), (val))
-#define sk_KRB5_APREQBODY_zero(st) SKM_sk_zero(KRB5_APREQBODY, (st))
-#define sk_KRB5_APREQBODY_push(st, val) SKM_sk_push(KRB5_APREQBODY, (st), (val))
-#define sk_KRB5_APREQBODY_unshift(st, val) SKM_sk_unshift(KRB5_APREQBODY, (st), (val))
-#define sk_KRB5_APREQBODY_find(st, val) SKM_sk_find(KRB5_APREQBODY, (st), (val))
-#define sk_KRB5_APREQBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_APREQBODY, (st), (val))
-#define sk_KRB5_APREQBODY_delete(st, i) SKM_sk_delete(KRB5_APREQBODY, (st), (i))
-#define sk_KRB5_APREQBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_APREQBODY, (st), (ptr))
-#define sk_KRB5_APREQBODY_insert(st, val, i) SKM_sk_insert(KRB5_APREQBODY, (st), (val), (i))
-#define sk_KRB5_APREQBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_APREQBODY, (st), (cmp))
-#define sk_KRB5_APREQBODY_dup(st) SKM_sk_dup(KRB5_APREQBODY, st)
-#define sk_KRB5_APREQBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_APREQBODY, (st), (free_func))
-#define sk_KRB5_APREQBODY_shift(st) SKM_sk_shift(KRB5_APREQBODY, (st))
-#define sk_KRB5_APREQBODY_pop(st) SKM_sk_pop(KRB5_APREQBODY, (st))
-#define sk_KRB5_APREQBODY_sort(st) SKM_sk_sort(KRB5_APREQBODY, (st))
-#define sk_KRB5_APREQBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_APREQBODY, (st))
-
-#define sk_KRB5_AUTHDATA_new(cmp) SKM_sk_new(KRB5_AUTHDATA, (cmp))
-#define sk_KRB5_AUTHDATA_new_null() SKM_sk_new_null(KRB5_AUTHDATA)
-#define sk_KRB5_AUTHDATA_free(st) SKM_sk_free(KRB5_AUTHDATA, (st))
-#define sk_KRB5_AUTHDATA_num(st) SKM_sk_num(KRB5_AUTHDATA, (st))
-#define sk_KRB5_AUTHDATA_value(st, i) SKM_sk_value(KRB5_AUTHDATA, (st), (i))
-#define sk_KRB5_AUTHDATA_set(st, i, val) SKM_sk_set(KRB5_AUTHDATA, (st), (i), (val))
-#define sk_KRB5_AUTHDATA_zero(st) SKM_sk_zero(KRB5_AUTHDATA, (st))
-#define sk_KRB5_AUTHDATA_push(st, val) SKM_sk_push(KRB5_AUTHDATA, (st), (val))
-#define sk_KRB5_AUTHDATA_unshift(st, val) SKM_sk_unshift(KRB5_AUTHDATA, (st), (val))
-#define sk_KRB5_AUTHDATA_find(st, val) SKM_sk_find(KRB5_AUTHDATA, (st), (val))
-#define sk_KRB5_AUTHDATA_find_ex(st, val) SKM_sk_find_ex(KRB5_AUTHDATA, (st), (val))
-#define sk_KRB5_AUTHDATA_delete(st, i) SKM_sk_delete(KRB5_AUTHDATA, (st), (i))
-#define sk_KRB5_AUTHDATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_AUTHDATA, (st), (ptr))
-#define sk_KRB5_AUTHDATA_insert(st, val, i) SKM_sk_insert(KRB5_AUTHDATA, (st), (val), (i))
-#define sk_KRB5_AUTHDATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_AUTHDATA, (st), (cmp))
-#define sk_KRB5_AUTHDATA_dup(st) SKM_sk_dup(KRB5_AUTHDATA, st)
-#define sk_KRB5_AUTHDATA_pop_free(st, free_func) SKM_sk_pop_free(KRB5_AUTHDATA, (st), (free_func))
-#define sk_KRB5_AUTHDATA_shift(st) SKM_sk_shift(KRB5_AUTHDATA, (st))
-#define sk_KRB5_AUTHDATA_pop(st) SKM_sk_pop(KRB5_AUTHDATA, (st))
-#define sk_KRB5_AUTHDATA_sort(st) SKM_sk_sort(KRB5_AUTHDATA, (st))
-#define sk_KRB5_AUTHDATA_is_sorted(st) SKM_sk_is_sorted(KRB5_AUTHDATA, (st))
-
-#define sk_KRB5_AUTHENTBODY_new(cmp) SKM_sk_new(KRB5_AUTHENTBODY, (cmp))
-#define sk_KRB5_AUTHENTBODY_new_null() SKM_sk_new_null(KRB5_AUTHENTBODY)
-#define sk_KRB5_AUTHENTBODY_free(st) SKM_sk_free(KRB5_AUTHENTBODY, (st))
-#define sk_KRB5_AUTHENTBODY_num(st) SKM_sk_num(KRB5_AUTHENTBODY, (st))
-#define sk_KRB5_AUTHENTBODY_value(st, i) SKM_sk_value(KRB5_AUTHENTBODY, (st), (i))
-#define sk_KRB5_AUTHENTBODY_set(st, i, val) SKM_sk_set(KRB5_AUTHENTBODY, (st), (i), (val))
-#define sk_KRB5_AUTHENTBODY_zero(st) SKM_sk_zero(KRB5_AUTHENTBODY, (st))
-#define sk_KRB5_AUTHENTBODY_push(st, val) SKM_sk_push(KRB5_AUTHENTBODY, (st), (val))
-#define sk_KRB5_AUTHENTBODY_unshift(st, val) SKM_sk_unshift(KRB5_AUTHENTBODY, (st), (val))
-#define sk_KRB5_AUTHENTBODY_find(st, val) SKM_sk_find(KRB5_AUTHENTBODY, (st), (val))
-#define sk_KRB5_AUTHENTBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_AUTHENTBODY, (st), (val))
-#define sk_KRB5_AUTHENTBODY_delete(st, i) SKM_sk_delete(KRB5_AUTHENTBODY, (st), (i))
-#define sk_KRB5_AUTHENTBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_AUTHENTBODY, (st), (ptr))
-#define sk_KRB5_AUTHENTBODY_insert(st, val, i) SKM_sk_insert(KRB5_AUTHENTBODY, (st), (val), (i))
-#define sk_KRB5_AUTHENTBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_AUTHENTBODY, (st), (cmp))
-#define sk_KRB5_AUTHENTBODY_dup(st) SKM_sk_dup(KRB5_AUTHENTBODY, st)
-#define sk_KRB5_AUTHENTBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_AUTHENTBODY, (st), (free_func))
-#define sk_KRB5_AUTHENTBODY_shift(st) SKM_sk_shift(KRB5_AUTHENTBODY, (st))
-#define sk_KRB5_AUTHENTBODY_pop(st) SKM_sk_pop(KRB5_AUTHENTBODY, (st))
-#define sk_KRB5_AUTHENTBODY_sort(st) SKM_sk_sort(KRB5_AUTHENTBODY, (st))
-#define sk_KRB5_AUTHENTBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_AUTHENTBODY, (st))
-
-#define sk_KRB5_CHECKSUM_new(cmp) SKM_sk_new(KRB5_CHECKSUM, (cmp))
-#define sk_KRB5_CHECKSUM_new_null() SKM_sk_new_null(KRB5_CHECKSUM)
-#define sk_KRB5_CHECKSUM_free(st) SKM_sk_free(KRB5_CHECKSUM, (st))
-#define sk_KRB5_CHECKSUM_num(st) SKM_sk_num(KRB5_CHECKSUM, (st))
-#define sk_KRB5_CHECKSUM_value(st, i) SKM_sk_value(KRB5_CHECKSUM, (st), (i))
-#define sk_KRB5_CHECKSUM_set(st, i, val) SKM_sk_set(KRB5_CHECKSUM, (st), (i), (val))
-#define sk_KRB5_CHECKSUM_zero(st) SKM_sk_zero(KRB5_CHECKSUM, (st))
-#define sk_KRB5_CHECKSUM_push(st, val) SKM_sk_push(KRB5_CHECKSUM, (st), (val))
-#define sk_KRB5_CHECKSUM_unshift(st, val) SKM_sk_unshift(KRB5_CHECKSUM, (st), (val))
-#define sk_KRB5_CHECKSUM_find(st, val) SKM_sk_find(KRB5_CHECKSUM, (st), (val))
-#define sk_KRB5_CHECKSUM_find_ex(st, val) SKM_sk_find_ex(KRB5_CHECKSUM, (st), (val))
-#define sk_KRB5_CHECKSUM_delete(st, i) SKM_sk_delete(KRB5_CHECKSUM, (st), (i))
-#define sk_KRB5_CHECKSUM_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_CHECKSUM, (st), (ptr))
-#define sk_KRB5_CHECKSUM_insert(st, val, i) SKM_sk_insert(KRB5_CHECKSUM, (st), (val), (i))
-#define sk_KRB5_CHECKSUM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_CHECKSUM, (st), (cmp))
-#define sk_KRB5_CHECKSUM_dup(st) SKM_sk_dup(KRB5_CHECKSUM, st)
-#define sk_KRB5_CHECKSUM_pop_free(st, free_func) SKM_sk_pop_free(KRB5_CHECKSUM, (st), (free_func))
-#define sk_KRB5_CHECKSUM_shift(st) SKM_sk_shift(KRB5_CHECKSUM, (st))
-#define sk_KRB5_CHECKSUM_pop(st) SKM_sk_pop(KRB5_CHECKSUM, (st))
-#define sk_KRB5_CHECKSUM_sort(st) SKM_sk_sort(KRB5_CHECKSUM, (st))
-#define sk_KRB5_CHECKSUM_is_sorted(st) SKM_sk_is_sorted(KRB5_CHECKSUM, (st))
-
-#define sk_KRB5_ENCDATA_new(cmp) SKM_sk_new(KRB5_ENCDATA, (cmp))
-#define sk_KRB5_ENCDATA_new_null() SKM_sk_new_null(KRB5_ENCDATA)
-#define sk_KRB5_ENCDATA_free(st) SKM_sk_free(KRB5_ENCDATA, (st))
-#define sk_KRB5_ENCDATA_num(st) SKM_sk_num(KRB5_ENCDATA, (st))
-#define sk_KRB5_ENCDATA_value(st, i) SKM_sk_value(KRB5_ENCDATA, (st), (i))
-#define sk_KRB5_ENCDATA_set(st, i, val) SKM_sk_set(KRB5_ENCDATA, (st), (i), (val))
-#define sk_KRB5_ENCDATA_zero(st) SKM_sk_zero(KRB5_ENCDATA, (st))
-#define sk_KRB5_ENCDATA_push(st, val) SKM_sk_push(KRB5_ENCDATA, (st), (val))
-#define sk_KRB5_ENCDATA_unshift(st, val) SKM_sk_unshift(KRB5_ENCDATA, (st), (val))
-#define sk_KRB5_ENCDATA_find(st, val) SKM_sk_find(KRB5_ENCDATA, (st), (val))
-#define sk_KRB5_ENCDATA_find_ex(st, val) SKM_sk_find_ex(KRB5_ENCDATA, (st), (val))
-#define sk_KRB5_ENCDATA_delete(st, i) SKM_sk_delete(KRB5_ENCDATA, (st), (i))
-#define sk_KRB5_ENCDATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_ENCDATA, (st), (ptr))
-#define sk_KRB5_ENCDATA_insert(st, val, i) SKM_sk_insert(KRB5_ENCDATA, (st), (val), (i))
-#define sk_KRB5_ENCDATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_ENCDATA, (st), (cmp))
-#define sk_KRB5_ENCDATA_dup(st) SKM_sk_dup(KRB5_ENCDATA, st)
-#define sk_KRB5_ENCDATA_pop_free(st, free_func) SKM_sk_pop_free(KRB5_ENCDATA, (st), (free_func))
-#define sk_KRB5_ENCDATA_shift(st) SKM_sk_shift(KRB5_ENCDATA, (st))
-#define sk_KRB5_ENCDATA_pop(st) SKM_sk_pop(KRB5_ENCDATA, (st))
-#define sk_KRB5_ENCDATA_sort(st) SKM_sk_sort(KRB5_ENCDATA, (st))
-#define sk_KRB5_ENCDATA_is_sorted(st) SKM_sk_is_sorted(KRB5_ENCDATA, (st))
-
-#define sk_KRB5_ENCKEY_new(cmp) SKM_sk_new(KRB5_ENCKEY, (cmp))
-#define sk_KRB5_ENCKEY_new_null() SKM_sk_new_null(KRB5_ENCKEY)
-#define sk_KRB5_ENCKEY_free(st) SKM_sk_free(KRB5_ENCKEY, (st))
-#define sk_KRB5_ENCKEY_num(st) SKM_sk_num(KRB5_ENCKEY, (st))
-#define sk_KRB5_ENCKEY_value(st, i) SKM_sk_value(KRB5_ENCKEY, (st), (i))
-#define sk_KRB5_ENCKEY_set(st, i, val) SKM_sk_set(KRB5_ENCKEY, (st), (i), (val))
-#define sk_KRB5_ENCKEY_zero(st) SKM_sk_zero(KRB5_ENCKEY, (st))
-#define sk_KRB5_ENCKEY_push(st, val) SKM_sk_push(KRB5_ENCKEY, (st), (val))
-#define sk_KRB5_ENCKEY_unshift(st, val) SKM_sk_unshift(KRB5_ENCKEY, (st), (val))
-#define sk_KRB5_ENCKEY_find(st, val) SKM_sk_find(KRB5_ENCKEY, (st), (val))
-#define sk_KRB5_ENCKEY_find_ex(st, val) SKM_sk_find_ex(KRB5_ENCKEY, (st), (val))
-#define sk_KRB5_ENCKEY_delete(st, i) SKM_sk_delete(KRB5_ENCKEY, (st), (i))
-#define sk_KRB5_ENCKEY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_ENCKEY, (st), (ptr))
-#define sk_KRB5_ENCKEY_insert(st, val, i) SKM_sk_insert(KRB5_ENCKEY, (st), (val), (i))
-#define sk_KRB5_ENCKEY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_ENCKEY, (st), (cmp))
-#define sk_KRB5_ENCKEY_dup(st) SKM_sk_dup(KRB5_ENCKEY, st)
-#define sk_KRB5_ENCKEY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_ENCKEY, (st), (free_func))
-#define sk_KRB5_ENCKEY_shift(st) SKM_sk_shift(KRB5_ENCKEY, (st))
-#define sk_KRB5_ENCKEY_pop(st) SKM_sk_pop(KRB5_ENCKEY, (st))
-#define sk_KRB5_ENCKEY_sort(st) SKM_sk_sort(KRB5_ENCKEY, (st))
-#define sk_KRB5_ENCKEY_is_sorted(st) SKM_sk_is_sorted(KRB5_ENCKEY, (st))
-
-#define sk_KRB5_PRINCNAME_new(cmp) SKM_sk_new(KRB5_PRINCNAME, (cmp))
-#define sk_KRB5_PRINCNAME_new_null() SKM_sk_new_null(KRB5_PRINCNAME)
-#define sk_KRB5_PRINCNAME_free(st) SKM_sk_free(KRB5_PRINCNAME, (st))
-#define sk_KRB5_PRINCNAME_num(st) SKM_sk_num(KRB5_PRINCNAME, (st))
-#define sk_KRB5_PRINCNAME_value(st, i) SKM_sk_value(KRB5_PRINCNAME, (st), (i))
-#define sk_KRB5_PRINCNAME_set(st, i, val) SKM_sk_set(KRB5_PRINCNAME, (st), (i), (val))
-#define sk_KRB5_PRINCNAME_zero(st) SKM_sk_zero(KRB5_PRINCNAME, (st))
-#define sk_KRB5_PRINCNAME_push(st, val) SKM_sk_push(KRB5_PRINCNAME, (st), (val))
-#define sk_KRB5_PRINCNAME_unshift(st, val) SKM_sk_unshift(KRB5_PRINCNAME, (st), (val))
-#define sk_KRB5_PRINCNAME_find(st, val) SKM_sk_find(KRB5_PRINCNAME, (st), (val))
-#define sk_KRB5_PRINCNAME_find_ex(st, val) SKM_sk_find_ex(KRB5_PRINCNAME, (st), (val))
-#define sk_KRB5_PRINCNAME_delete(st, i) SKM_sk_delete(KRB5_PRINCNAME, (st), (i))
-#define sk_KRB5_PRINCNAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_PRINCNAME, (st), (ptr))
-#define sk_KRB5_PRINCNAME_insert(st, val, i) SKM_sk_insert(KRB5_PRINCNAME, (st), (val), (i))
-#define sk_KRB5_PRINCNAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_PRINCNAME, (st), (cmp))
-#define sk_KRB5_PRINCNAME_dup(st) SKM_sk_dup(KRB5_PRINCNAME, st)
-#define sk_KRB5_PRINCNAME_pop_free(st, free_func) SKM_sk_pop_free(KRB5_PRINCNAME, (st), (free_func))
-#define sk_KRB5_PRINCNAME_shift(st) SKM_sk_shift(KRB5_PRINCNAME, (st))
-#define sk_KRB5_PRINCNAME_pop(st) SKM_sk_pop(KRB5_PRINCNAME, (st))
-#define sk_KRB5_PRINCNAME_sort(st) SKM_sk_sort(KRB5_PRINCNAME, (st))
-#define sk_KRB5_PRINCNAME_is_sorted(st) SKM_sk_is_sorted(KRB5_PRINCNAME, (st))
-
-#define sk_KRB5_TKTBODY_new(cmp) SKM_sk_new(KRB5_TKTBODY, (cmp))
-#define sk_KRB5_TKTBODY_new_null() SKM_sk_new_null(KRB5_TKTBODY)
-#define sk_KRB5_TKTBODY_free(st) SKM_sk_free(KRB5_TKTBODY, (st))
-#define sk_KRB5_TKTBODY_num(st) SKM_sk_num(KRB5_TKTBODY, (st))
-#define sk_KRB5_TKTBODY_value(st, i) SKM_sk_value(KRB5_TKTBODY, (st), (i))
-#define sk_KRB5_TKTBODY_set(st, i, val) SKM_sk_set(KRB5_TKTBODY, (st), (i), (val))
-#define sk_KRB5_TKTBODY_zero(st) SKM_sk_zero(KRB5_TKTBODY, (st))
-#define sk_KRB5_TKTBODY_push(st, val) SKM_sk_push(KRB5_TKTBODY, (st), (val))
-#define sk_KRB5_TKTBODY_unshift(st, val) SKM_sk_unshift(KRB5_TKTBODY, (st), (val))
-#define sk_KRB5_TKTBODY_find(st, val) SKM_sk_find(KRB5_TKTBODY, (st), (val))
-#define sk_KRB5_TKTBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_TKTBODY, (st), (val))
-#define sk_KRB5_TKTBODY_delete(st, i) SKM_sk_delete(KRB5_TKTBODY, (st), (i))
-#define sk_KRB5_TKTBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_TKTBODY, (st), (ptr))
-#define sk_KRB5_TKTBODY_insert(st, val, i) SKM_sk_insert(KRB5_TKTBODY, (st), (val), (i))
-#define sk_KRB5_TKTBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_TKTBODY, (st), (cmp))
-#define sk_KRB5_TKTBODY_dup(st) SKM_sk_dup(KRB5_TKTBODY, st)
-#define sk_KRB5_TKTBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_TKTBODY, (st), (free_func))
-#define sk_KRB5_TKTBODY_shift(st) SKM_sk_shift(KRB5_TKTBODY, (st))
-#define sk_KRB5_TKTBODY_pop(st) SKM_sk_pop(KRB5_TKTBODY, (st))
-#define sk_KRB5_TKTBODY_sort(st) SKM_sk_sort(KRB5_TKTBODY, (st))
-#define sk_KRB5_TKTBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_TKTBODY, (st))
-
-#define sk_MEM_OBJECT_DATA_new(cmp) SKM_sk_new(MEM_OBJECT_DATA, (cmp))
-#define sk_MEM_OBJECT_DATA_new_null() SKM_sk_new_null(MEM_OBJECT_DATA)
-#define sk_MEM_OBJECT_DATA_free(st) SKM_sk_free(MEM_OBJECT_DATA, (st))
-#define sk_MEM_OBJECT_DATA_num(st) SKM_sk_num(MEM_OBJECT_DATA, (st))
-#define sk_MEM_OBJECT_DATA_value(st, i) SKM_sk_value(MEM_OBJECT_DATA, (st), (i))
-#define sk_MEM_OBJECT_DATA_set(st, i, val) SKM_sk_set(MEM_OBJECT_DATA, (st), (i), (val))
-#define sk_MEM_OBJECT_DATA_zero(st) SKM_sk_zero(MEM_OBJECT_DATA, (st))
-#define sk_MEM_OBJECT_DATA_push(st, val) SKM_sk_push(MEM_OBJECT_DATA, (st), (val))
-#define sk_MEM_OBJECT_DATA_unshift(st, val) SKM_sk_unshift(MEM_OBJECT_DATA, (st), (val))
-#define sk_MEM_OBJECT_DATA_find(st, val) SKM_sk_find(MEM_OBJECT_DATA, (st), (val))
-#define sk_MEM_OBJECT_DATA_find_ex(st, val) SKM_sk_find_ex(MEM_OBJECT_DATA, (st), (val))
-#define sk_MEM_OBJECT_DATA_delete(st, i) SKM_sk_delete(MEM_OBJECT_DATA, (st), (i))
-#define sk_MEM_OBJECT_DATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(MEM_OBJECT_DATA, (st), (ptr))
-#define sk_MEM_OBJECT_DATA_insert(st, val, i) SKM_sk_insert(MEM_OBJECT_DATA, (st), (val), (i))
-#define sk_MEM_OBJECT_DATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(MEM_OBJECT_DATA, (st), (cmp))
-#define sk_MEM_OBJECT_DATA_dup(st) SKM_sk_dup(MEM_OBJECT_DATA, st)
-#define sk_MEM_OBJECT_DATA_pop_free(st, free_func) SKM_sk_pop_free(MEM_OBJECT_DATA, (st), (free_func))
-#define sk_MEM_OBJECT_DATA_shift(st) SKM_sk_shift(MEM_OBJECT_DATA, (st))
-#define sk_MEM_OBJECT_DATA_pop(st) SKM_sk_pop(MEM_OBJECT_DATA, (st))
-#define sk_MEM_OBJECT_DATA_sort(st) SKM_sk_sort(MEM_OBJECT_DATA, (st))
-#define sk_MEM_OBJECT_DATA_is_sorted(st) SKM_sk_is_sorted(MEM_OBJECT_DATA, (st))
-
-#define sk_MIME_HEADER_new(cmp) SKM_sk_new(MIME_HEADER, (cmp))
-#define sk_MIME_HEADER_new_null() SKM_sk_new_null(MIME_HEADER)
-#define sk_MIME_HEADER_free(st) SKM_sk_free(MIME_HEADER, (st))
-#define sk_MIME_HEADER_num(st) SKM_sk_num(MIME_HEADER, (st))
-#define sk_MIME_HEADER_value(st, i) SKM_sk_value(MIME_HEADER, (st), (i))
-#define sk_MIME_HEADER_set(st, i, val) SKM_sk_set(MIME_HEADER, (st), (i), (val))
-#define sk_MIME_HEADER_zero(st) SKM_sk_zero(MIME_HEADER, (st))
-#define sk_MIME_HEADER_push(st, val) SKM_sk_push(MIME_HEADER, (st), (val))
-#define sk_MIME_HEADER_unshift(st, val) SKM_sk_unshift(MIME_HEADER, (st), (val))
-#define sk_MIME_HEADER_find(st, val) SKM_sk_find(MIME_HEADER, (st), (val))
-#define sk_MIME_HEADER_find_ex(st, val) SKM_sk_find_ex(MIME_HEADER, (st), (val))
-#define sk_MIME_HEADER_delete(st, i) SKM_sk_delete(MIME_HEADER, (st), (i))
-#define sk_MIME_HEADER_delete_ptr(st, ptr) SKM_sk_delete_ptr(MIME_HEADER, (st), (ptr))
-#define sk_MIME_HEADER_insert(st, val, i) SKM_sk_insert(MIME_HEADER, (st), (val), (i))
-#define sk_MIME_HEADER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(MIME_HEADER, (st), (cmp))
-#define sk_MIME_HEADER_dup(st) SKM_sk_dup(MIME_HEADER, st)
-#define sk_MIME_HEADER_pop_free(st, free_func) SKM_sk_pop_free(MIME_HEADER, (st), (free_func))
-#define sk_MIME_HEADER_shift(st) SKM_sk_shift(MIME_HEADER, (st))
-#define sk_MIME_HEADER_pop(st) SKM_sk_pop(MIME_HEADER, (st))
-#define sk_MIME_HEADER_sort(st) SKM_sk_sort(MIME_HEADER, (st))
-#define sk_MIME_HEADER_is_sorted(st) SKM_sk_is_sorted(MIME_HEADER, (st))
-
-#define sk_MIME_PARAM_new(cmp) SKM_sk_new(MIME_PARAM, (cmp))
-#define sk_MIME_PARAM_new_null() SKM_sk_new_null(MIME_PARAM)
-#define sk_MIME_PARAM_free(st) SKM_sk_free(MIME_PARAM, (st))
-#define sk_MIME_PARAM_num(st) SKM_sk_num(MIME_PARAM, (st))
-#define sk_MIME_PARAM_value(st, i) SKM_sk_value(MIME_PARAM, (st), (i))
-#define sk_MIME_PARAM_set(st, i, val) SKM_sk_set(MIME_PARAM, (st), (i), (val))
-#define sk_MIME_PARAM_zero(st) SKM_sk_zero(MIME_PARAM, (st))
-#define sk_MIME_PARAM_push(st, val) SKM_sk_push(MIME_PARAM, (st), (val))
-#define sk_MIME_PARAM_unshift(st, val) SKM_sk_unshift(MIME_PARAM, (st), (val))
-#define sk_MIME_PARAM_find(st, val) SKM_sk_find(MIME_PARAM, (st), (val))
-#define sk_MIME_PARAM_find_ex(st, val) SKM_sk_find_ex(MIME_PARAM, (st), (val))
-#define sk_MIME_PARAM_delete(st, i) SKM_sk_delete(MIME_PARAM, (st), (i))
-#define sk_MIME_PARAM_delete_ptr(st, ptr) SKM_sk_delete_ptr(MIME_PARAM, (st), (ptr))
-#define sk_MIME_PARAM_insert(st, val, i) SKM_sk_insert(MIME_PARAM, (st), (val), (i))
-#define sk_MIME_PARAM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(MIME_PARAM, (st), (cmp))
-#define sk_MIME_PARAM_dup(st) SKM_sk_dup(MIME_PARAM, st)
-#define sk_MIME_PARAM_pop_free(st, free_func) SKM_sk_pop_free(MIME_PARAM, (st), (free_func))
-#define sk_MIME_PARAM_shift(st) SKM_sk_shift(MIME_PARAM, (st))
-#define sk_MIME_PARAM_pop(st) SKM_sk_pop(MIME_PARAM, (st))
-#define sk_MIME_PARAM_sort(st) SKM_sk_sort(MIME_PARAM, (st))
-#define sk_MIME_PARAM_is_sorted(st) SKM_sk_is_sorted(MIME_PARAM, (st))
-
-#define sk_NAME_FUNCS_new(cmp) SKM_sk_new(NAME_FUNCS, (cmp))
-#define sk_NAME_FUNCS_new_null() SKM_sk_new_null(NAME_FUNCS)
-#define sk_NAME_FUNCS_free(st) SKM_sk_free(NAME_FUNCS, (st))
-#define sk_NAME_FUNCS_num(st) SKM_sk_num(NAME_FUNCS, (st))
-#define sk_NAME_FUNCS_value(st, i) SKM_sk_value(NAME_FUNCS, (st), (i))
-#define sk_NAME_FUNCS_set(st, i, val) SKM_sk_set(NAME_FUNCS, (st), (i), (val))
-#define sk_NAME_FUNCS_zero(st) SKM_sk_zero(NAME_FUNCS, (st))
-#define sk_NAME_FUNCS_push(st, val) SKM_sk_push(NAME_FUNCS, (st), (val))
-#define sk_NAME_FUNCS_unshift(st, val) SKM_sk_unshift(NAME_FUNCS, (st), (val))
-#define sk_NAME_FUNCS_find(st, val) SKM_sk_find(NAME_FUNCS, (st), (val))
-#define sk_NAME_FUNCS_find_ex(st, val) SKM_sk_find_ex(NAME_FUNCS, (st), (val))
-#define sk_NAME_FUNCS_delete(st, i) SKM_sk_delete(NAME_FUNCS, (st), (i))
-#define sk_NAME_FUNCS_delete_ptr(st, ptr) SKM_sk_delete_ptr(NAME_FUNCS, (st), (ptr))
-#define sk_NAME_FUNCS_insert(st, val, i) SKM_sk_insert(NAME_FUNCS, (st), (val), (i))
-#define sk_NAME_FUNCS_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(NAME_FUNCS, (st), (cmp))
-#define sk_NAME_FUNCS_dup(st) SKM_sk_dup(NAME_FUNCS, st)
-#define sk_NAME_FUNCS_pop_free(st, free_func) SKM_sk_pop_free(NAME_FUNCS, (st), (free_func))
-#define sk_NAME_FUNCS_shift(st) SKM_sk_shift(NAME_FUNCS, (st))
-#define sk_NAME_FUNCS_pop(st) SKM_sk_pop(NAME_FUNCS, (st))
-#define sk_NAME_FUNCS_sort(st) SKM_sk_sort(NAME_FUNCS, (st))
-#define sk_NAME_FUNCS_is_sorted(st) SKM_sk_is_sorted(NAME_FUNCS, (st))
-
-#define sk_OCSP_CERTID_new(cmp) SKM_sk_new(OCSP_CERTID, (cmp))
-#define sk_OCSP_CERTID_new_null() SKM_sk_new_null(OCSP_CERTID)
-#define sk_OCSP_CERTID_free(st) SKM_sk_free(OCSP_CERTID, (st))
-#define sk_OCSP_CERTID_num(st) SKM_sk_num(OCSP_CERTID, (st))
-#define sk_OCSP_CERTID_value(st, i) SKM_sk_value(OCSP_CERTID, (st), (i))
-#define sk_OCSP_CERTID_set(st, i, val) SKM_sk_set(OCSP_CERTID, (st), (i), (val))
-#define sk_OCSP_CERTID_zero(st) SKM_sk_zero(OCSP_CERTID, (st))
-#define sk_OCSP_CERTID_push(st, val) SKM_sk_push(OCSP_CERTID, (st), (val))
-#define sk_OCSP_CERTID_unshift(st, val) SKM_sk_unshift(OCSP_CERTID, (st), (val))
-#define sk_OCSP_CERTID_find(st, val) SKM_sk_find(OCSP_CERTID, (st), (val))
-#define sk_OCSP_CERTID_find_ex(st, val) SKM_sk_find_ex(OCSP_CERTID, (st), (val))
-#define sk_OCSP_CERTID_delete(st, i) SKM_sk_delete(OCSP_CERTID, (st), (i))
-#define sk_OCSP_CERTID_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_CERTID, (st), (ptr))
-#define sk_OCSP_CERTID_insert(st, val, i) SKM_sk_insert(OCSP_CERTID, (st), (val), (i))
-#define sk_OCSP_CERTID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_CERTID, (st), (cmp))
-#define sk_OCSP_CERTID_dup(st) SKM_sk_dup(OCSP_CERTID, st)
-#define sk_OCSP_CERTID_pop_free(st, free_func) SKM_sk_pop_free(OCSP_CERTID, (st), (free_func))
-#define sk_OCSP_CERTID_shift(st) SKM_sk_shift(OCSP_CERTID, (st))
-#define sk_OCSP_CERTID_pop(st) SKM_sk_pop(OCSP_CERTID, (st))
-#define sk_OCSP_CERTID_sort(st) SKM_sk_sort(OCSP_CERTID, (st))
-#define sk_OCSP_CERTID_is_sorted(st) SKM_sk_is_sorted(OCSP_CERTID, (st))
-
-#define sk_OCSP_ONEREQ_new(cmp) SKM_sk_new(OCSP_ONEREQ, (cmp))
-#define sk_OCSP_ONEREQ_new_null() SKM_sk_new_null(OCSP_ONEREQ)
-#define sk_OCSP_ONEREQ_free(st) SKM_sk_free(OCSP_ONEREQ, (st))
-#define sk_OCSP_ONEREQ_num(st) SKM_sk_num(OCSP_ONEREQ, (st))
-#define sk_OCSP_ONEREQ_value(st, i) SKM_sk_value(OCSP_ONEREQ, (st), (i))
-#define sk_OCSP_ONEREQ_set(st, i, val) SKM_sk_set(OCSP_ONEREQ, (st), (i), (val))
-#define sk_OCSP_ONEREQ_zero(st) SKM_sk_zero(OCSP_ONEREQ, (st))
-#define sk_OCSP_ONEREQ_push(st, val) SKM_sk_push(OCSP_ONEREQ, (st), (val))
-#define sk_OCSP_ONEREQ_unshift(st, val) SKM_sk_unshift(OCSP_ONEREQ, (st), (val))
-#define sk_OCSP_ONEREQ_find(st, val) SKM_sk_find(OCSP_ONEREQ, (st), (val))
-#define sk_OCSP_ONEREQ_find_ex(st, val) SKM_sk_find_ex(OCSP_ONEREQ, (st), (val))
-#define sk_OCSP_ONEREQ_delete(st, i) SKM_sk_delete(OCSP_ONEREQ, (st), (i))
-#define sk_OCSP_ONEREQ_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_ONEREQ, (st), (ptr))
-#define sk_OCSP_ONEREQ_insert(st, val, i) SKM_sk_insert(OCSP_ONEREQ, (st), (val), (i))
-#define sk_OCSP_ONEREQ_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_ONEREQ, (st), (cmp))
-#define sk_OCSP_ONEREQ_dup(st) SKM_sk_dup(OCSP_ONEREQ, st)
-#define sk_OCSP_ONEREQ_pop_free(st, free_func) SKM_sk_pop_free(OCSP_ONEREQ, (st), (free_func))
-#define sk_OCSP_ONEREQ_shift(st) SKM_sk_shift(OCSP_ONEREQ, (st))
-#define sk_OCSP_ONEREQ_pop(st) SKM_sk_pop(OCSP_ONEREQ, (st))
-#define sk_OCSP_ONEREQ_sort(st) SKM_sk_sort(OCSP_ONEREQ, (st))
-#define sk_OCSP_ONEREQ_is_sorted(st) SKM_sk_is_sorted(OCSP_ONEREQ, (st))
-
-#define sk_OCSP_RESPID_new(cmp) SKM_sk_new(OCSP_RESPID, (cmp))
-#define sk_OCSP_RESPID_new_null() SKM_sk_new_null(OCSP_RESPID)
-#define sk_OCSP_RESPID_free(st) SKM_sk_free(OCSP_RESPID, (st))
-#define sk_OCSP_RESPID_num(st) SKM_sk_num(OCSP_RESPID, (st))
-#define sk_OCSP_RESPID_value(st, i) SKM_sk_value(OCSP_RESPID, (st), (i))
-#define sk_OCSP_RESPID_set(st, i, val) SKM_sk_set(OCSP_RESPID, (st), (i), (val))
-#define sk_OCSP_RESPID_zero(st) SKM_sk_zero(OCSP_RESPID, (st))
-#define sk_OCSP_RESPID_push(st, val) SKM_sk_push(OCSP_RESPID, (st), (val))
-#define sk_OCSP_RESPID_unshift(st, val) SKM_sk_unshift(OCSP_RESPID, (st), (val))
-#define sk_OCSP_RESPID_find(st, val) SKM_sk_find(OCSP_RESPID, (st), (val))
-#define sk_OCSP_RESPID_find_ex(st, val) SKM_sk_find_ex(OCSP_RESPID, (st), (val))
-#define sk_OCSP_RESPID_delete(st, i) SKM_sk_delete(OCSP_RESPID, (st), (i))
-#define sk_OCSP_RESPID_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_RESPID, (st), (ptr))
-#define sk_OCSP_RESPID_insert(st, val, i) SKM_sk_insert(OCSP_RESPID, (st), (val), (i))
-#define sk_OCSP_RESPID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_RESPID, (st), (cmp))
-#define sk_OCSP_RESPID_dup(st) SKM_sk_dup(OCSP_RESPID, st)
-#define sk_OCSP_RESPID_pop_free(st, free_func) SKM_sk_pop_free(OCSP_RESPID, (st), (free_func))
-#define sk_OCSP_RESPID_shift(st) SKM_sk_shift(OCSP_RESPID, (st))
-#define sk_OCSP_RESPID_pop(st) SKM_sk_pop(OCSP_RESPID, (st))
-#define sk_OCSP_RESPID_sort(st) SKM_sk_sort(OCSP_RESPID, (st))
-#define sk_OCSP_RESPID_is_sorted(st) SKM_sk_is_sorted(OCSP_RESPID, (st))
-
-#define sk_OCSP_SINGLERESP_new(cmp) SKM_sk_new(OCSP_SINGLERESP, (cmp))
-#define sk_OCSP_SINGLERESP_new_null() SKM_sk_new_null(OCSP_SINGLERESP)
-#define sk_OCSP_SINGLERESP_free(st) SKM_sk_free(OCSP_SINGLERESP, (st))
-#define sk_OCSP_SINGLERESP_num(st) SKM_sk_num(OCSP_SINGLERESP, (st))
-#define sk_OCSP_SINGLERESP_value(st, i) SKM_sk_value(OCSP_SINGLERESP, (st), (i))
-#define sk_OCSP_SINGLERESP_set(st, i, val) SKM_sk_set(OCSP_SINGLERESP, (st), (i), (val))
-#define sk_OCSP_SINGLERESP_zero(st) SKM_sk_zero(OCSP_SINGLERESP, (st))
-#define sk_OCSP_SINGLERESP_push(st, val) SKM_sk_push(OCSP_SINGLERESP, (st), (val))
-#define sk_OCSP_SINGLERESP_unshift(st, val) SKM_sk_unshift(OCSP_SINGLERESP, (st), (val))
-#define sk_OCSP_SINGLERESP_find(st, val) SKM_sk_find(OCSP_SINGLERESP, (st), (val))
-#define sk_OCSP_SINGLERESP_find_ex(st, val) SKM_sk_find_ex(OCSP_SINGLERESP, (st), (val))
-#define sk_OCSP_SINGLERESP_delete(st, i) SKM_sk_delete(OCSP_SINGLERESP, (st), (i))
-#define sk_OCSP_SINGLERESP_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_SINGLERESP, (st), (ptr))
-#define sk_OCSP_SINGLERESP_insert(st, val, i) SKM_sk_insert(OCSP_SINGLERESP, (st), (val), (i))
-#define sk_OCSP_SINGLERESP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_SINGLERESP, (st), (cmp))
-#define sk_OCSP_SINGLERESP_dup(st) SKM_sk_dup(OCSP_SINGLERESP, st)
-#define sk_OCSP_SINGLERESP_pop_free(st, free_func) SKM_sk_pop_free(OCSP_SINGLERESP, (st), (free_func))
-#define sk_OCSP_SINGLERESP_shift(st) SKM_sk_shift(OCSP_SINGLERESP, (st))
-#define sk_OCSP_SINGLERESP_pop(st) SKM_sk_pop(OCSP_SINGLERESP, (st))
-#define sk_OCSP_SINGLERESP_sort(st) SKM_sk_sort(OCSP_SINGLERESP, (st))
-#define sk_OCSP_SINGLERESP_is_sorted(st) SKM_sk_is_sorted(OCSP_SINGLERESP, (st))
-
-#define sk_PKCS12_SAFEBAG_new(cmp) SKM_sk_new(PKCS12_SAFEBAG, (cmp))
-#define sk_PKCS12_SAFEBAG_new_null() SKM_sk_new_null(PKCS12_SAFEBAG)
-#define sk_PKCS12_SAFEBAG_free(st) SKM_sk_free(PKCS12_SAFEBAG, (st))
-#define sk_PKCS12_SAFEBAG_num(st) SKM_sk_num(PKCS12_SAFEBAG, (st))
-#define sk_PKCS12_SAFEBAG_value(st, i) SKM_sk_value(PKCS12_SAFEBAG, (st), (i))
-#define sk_PKCS12_SAFEBAG_set(st, i, val) SKM_sk_set(PKCS12_SAFEBAG, (st), (i), (val))
-#define sk_PKCS12_SAFEBAG_zero(st) SKM_sk_zero(PKCS12_SAFEBAG, (st))
-#define sk_PKCS12_SAFEBAG_push(st, val) SKM_sk_push(PKCS12_SAFEBAG, (st), (val))
-#define sk_PKCS12_SAFEBAG_unshift(st, val) SKM_sk_unshift(PKCS12_SAFEBAG, (st), (val))
-#define sk_PKCS12_SAFEBAG_find(st, val) SKM_sk_find(PKCS12_SAFEBAG, (st), (val))
-#define sk_PKCS12_SAFEBAG_find_ex(st, val) SKM_sk_find_ex(PKCS12_SAFEBAG, (st), (val))
-#define sk_PKCS12_SAFEBAG_delete(st, i) SKM_sk_delete(PKCS12_SAFEBAG, (st), (i))
-#define sk_PKCS12_SAFEBAG_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS12_SAFEBAG, (st), (ptr))
-#define sk_PKCS12_SAFEBAG_insert(st, val, i) SKM_sk_insert(PKCS12_SAFEBAG, (st), (val), (i))
-#define sk_PKCS12_SAFEBAG_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS12_SAFEBAG, (st), (cmp))
-#define sk_PKCS12_SAFEBAG_dup(st) SKM_sk_dup(PKCS12_SAFEBAG, st)
-#define sk_PKCS12_SAFEBAG_pop_free(st, free_func) SKM_sk_pop_free(PKCS12_SAFEBAG, (st), (free_func))
-#define sk_PKCS12_SAFEBAG_shift(st) SKM_sk_shift(PKCS12_SAFEBAG, (st))
-#define sk_PKCS12_SAFEBAG_pop(st) SKM_sk_pop(PKCS12_SAFEBAG, (st))
-#define sk_PKCS12_SAFEBAG_sort(st) SKM_sk_sort(PKCS12_SAFEBAG, (st))
-#define sk_PKCS12_SAFEBAG_is_sorted(st) SKM_sk_is_sorted(PKCS12_SAFEBAG, (st))
-
-#define sk_PKCS7_new(cmp) SKM_sk_new(PKCS7, (cmp))
-#define sk_PKCS7_new_null() SKM_sk_new_null(PKCS7)
-#define sk_PKCS7_free(st) SKM_sk_free(PKCS7, (st))
-#define sk_PKCS7_num(st) SKM_sk_num(PKCS7, (st))
-#define sk_PKCS7_value(st, i) SKM_sk_value(PKCS7, (st), (i))
-#define sk_PKCS7_set(st, i, val) SKM_sk_set(PKCS7, (st), (i), (val))
-#define sk_PKCS7_zero(st) SKM_sk_zero(PKCS7, (st))
-#define sk_PKCS7_push(st, val) SKM_sk_push(PKCS7, (st), (val))
-#define sk_PKCS7_unshift(st, val) SKM_sk_unshift(PKCS7, (st), (val))
-#define sk_PKCS7_find(st, val) SKM_sk_find(PKCS7, (st), (val))
-#define sk_PKCS7_find_ex(st, val) SKM_sk_find_ex(PKCS7, (st), (val))
-#define sk_PKCS7_delete(st, i) SKM_sk_delete(PKCS7, (st), (i))
-#define sk_PKCS7_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7, (st), (ptr))
-#define sk_PKCS7_insert(st, val, i) SKM_sk_insert(PKCS7, (st), (val), (i))
-#define sk_PKCS7_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7, (st), (cmp))
-#define sk_PKCS7_dup(st) SKM_sk_dup(PKCS7, st)
-#define sk_PKCS7_pop_free(st, free_func) SKM_sk_pop_free(PKCS7, (st), (free_func))
-#define sk_PKCS7_shift(st) SKM_sk_shift(PKCS7, (st))
-#define sk_PKCS7_pop(st) SKM_sk_pop(PKCS7, (st))
-#define sk_PKCS7_sort(st) SKM_sk_sort(PKCS7, (st))
-#define sk_PKCS7_is_sorted(st) SKM_sk_is_sorted(PKCS7, (st))
-
-#define sk_PKCS7_RECIP_INFO_new(cmp) SKM_sk_new(PKCS7_RECIP_INFO, (cmp))
-#define sk_PKCS7_RECIP_INFO_new_null() SKM_sk_new_null(PKCS7_RECIP_INFO)
-#define sk_PKCS7_RECIP_INFO_free(st) SKM_sk_free(PKCS7_RECIP_INFO, (st))
-#define sk_PKCS7_RECIP_INFO_num(st) SKM_sk_num(PKCS7_RECIP_INFO, (st))
-#define sk_PKCS7_RECIP_INFO_value(st, i) SKM_sk_value(PKCS7_RECIP_INFO, (st), (i))
-#define sk_PKCS7_RECIP_INFO_set(st, i, val) SKM_sk_set(PKCS7_RECIP_INFO, (st), (i), (val))
-#define sk_PKCS7_RECIP_INFO_zero(st) SKM_sk_zero(PKCS7_RECIP_INFO, (st))
-#define sk_PKCS7_RECIP_INFO_push(st, val) SKM_sk_push(PKCS7_RECIP_INFO, (st), (val))
-#define sk_PKCS7_RECIP_INFO_unshift(st, val) SKM_sk_unshift(PKCS7_RECIP_INFO, (st), (val))
-#define sk_PKCS7_RECIP_INFO_find(st, val) SKM_sk_find(PKCS7_RECIP_INFO, (st), (val))
-#define sk_PKCS7_RECIP_INFO_find_ex(st, val) SKM_sk_find_ex(PKCS7_RECIP_INFO, (st), (val))
-#define sk_PKCS7_RECIP_INFO_delete(st, i) SKM_sk_delete(PKCS7_RECIP_INFO, (st), (i))
-#define sk_PKCS7_RECIP_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7_RECIP_INFO, (st), (ptr))
-#define sk_PKCS7_RECIP_INFO_insert(st, val, i) SKM_sk_insert(PKCS7_RECIP_INFO, (st), (val), (i))
-#define sk_PKCS7_RECIP_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7_RECIP_INFO, (st), (cmp))
-#define sk_PKCS7_RECIP_INFO_dup(st) SKM_sk_dup(PKCS7_RECIP_INFO, st)
-#define sk_PKCS7_RECIP_INFO_pop_free(st, free_func) SKM_sk_pop_free(PKCS7_RECIP_INFO, (st), (free_func))
-#define sk_PKCS7_RECIP_INFO_shift(st) SKM_sk_shift(PKCS7_RECIP_INFO, (st))
-#define sk_PKCS7_RECIP_INFO_pop(st) SKM_sk_pop(PKCS7_RECIP_INFO, (st))
-#define sk_PKCS7_RECIP_INFO_sort(st) SKM_sk_sort(PKCS7_RECIP_INFO, (st))
-#define sk_PKCS7_RECIP_INFO_is_sorted(st) SKM_sk_is_sorted(PKCS7_RECIP_INFO, (st))
-
-#define sk_PKCS7_SIGNER_INFO_new(cmp) SKM_sk_new(PKCS7_SIGNER_INFO, (cmp))
-#define sk_PKCS7_SIGNER_INFO_new_null() SKM_sk_new_null(PKCS7_SIGNER_INFO)
-#define sk_PKCS7_SIGNER_INFO_free(st) SKM_sk_free(PKCS7_SIGNER_INFO, (st))
-#define sk_PKCS7_SIGNER_INFO_num(st) SKM_sk_num(PKCS7_SIGNER_INFO, (st))
-#define sk_PKCS7_SIGNER_INFO_value(st, i) SKM_sk_value(PKCS7_SIGNER_INFO, (st), (i))
-#define sk_PKCS7_SIGNER_INFO_set(st, i, val) SKM_sk_set(PKCS7_SIGNER_INFO, (st), (i), (val))
-#define sk_PKCS7_SIGNER_INFO_zero(st) SKM_sk_zero(PKCS7_SIGNER_INFO, (st))
-#define sk_PKCS7_SIGNER_INFO_push(st, val) SKM_sk_push(PKCS7_SIGNER_INFO, (st), (val))
-#define sk_PKCS7_SIGNER_INFO_unshift(st, val) SKM_sk_unshift(PKCS7_SIGNER_INFO, (st), (val))
-#define sk_PKCS7_SIGNER_INFO_find(st, val) SKM_sk_find(PKCS7_SIGNER_INFO, (st), (val))
-#define sk_PKCS7_SIGNER_INFO_find_ex(st, val) SKM_sk_find_ex(PKCS7_SIGNER_INFO, (st), (val))
-#define sk_PKCS7_SIGNER_INFO_delete(st, i) SKM_sk_delete(PKCS7_SIGNER_INFO, (st), (i))
-#define sk_PKCS7_SIGNER_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7_SIGNER_INFO, (st), (ptr))
-#define sk_PKCS7_SIGNER_INFO_insert(st, val, i) SKM_sk_insert(PKCS7_SIGNER_INFO, (st), (val), (i))
-#define sk_PKCS7_SIGNER_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7_SIGNER_INFO, (st), (cmp))
-#define sk_PKCS7_SIGNER_INFO_dup(st) SKM_sk_dup(PKCS7_SIGNER_INFO, st)
-#define sk_PKCS7_SIGNER_INFO_pop_free(st, free_func) SKM_sk_pop_free(PKCS7_SIGNER_INFO, (st), (free_func))
-#define sk_PKCS7_SIGNER_INFO_shift(st) SKM_sk_shift(PKCS7_SIGNER_INFO, (st))
-#define sk_PKCS7_SIGNER_INFO_pop(st) SKM_sk_pop(PKCS7_SIGNER_INFO, (st))
-#define sk_PKCS7_SIGNER_INFO_sort(st) SKM_sk_sort(PKCS7_SIGNER_INFO, (st))
-#define sk_PKCS7_SIGNER_INFO_is_sorted(st) SKM_sk_is_sorted(PKCS7_SIGNER_INFO, (st))
-
-#define sk_POLICYINFO_new(cmp) SKM_sk_new(POLICYINFO, (cmp))
-#define sk_POLICYINFO_new_null() SKM_sk_new_null(POLICYINFO)
-#define sk_POLICYINFO_free(st) SKM_sk_free(POLICYINFO, (st))
-#define sk_POLICYINFO_num(st) SKM_sk_num(POLICYINFO, (st))
-#define sk_POLICYINFO_value(st, i) SKM_sk_value(POLICYINFO, (st), (i))
-#define sk_POLICYINFO_set(st, i, val) SKM_sk_set(POLICYINFO, (st), (i), (val))
-#define sk_POLICYINFO_zero(st) SKM_sk_zero(POLICYINFO, (st))
-#define sk_POLICYINFO_push(st, val) SKM_sk_push(POLICYINFO, (st), (val))
-#define sk_POLICYINFO_unshift(st, val) SKM_sk_unshift(POLICYINFO, (st), (val))
-#define sk_POLICYINFO_find(st, val) SKM_sk_find(POLICYINFO, (st), (val))
-#define sk_POLICYINFO_find_ex(st, val) SKM_sk_find_ex(POLICYINFO, (st), (val))
-#define sk_POLICYINFO_delete(st, i) SKM_sk_delete(POLICYINFO, (st), (i))
-#define sk_POLICYINFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICYINFO, (st), (ptr))
-#define sk_POLICYINFO_insert(st, val, i) SKM_sk_insert(POLICYINFO, (st), (val), (i))
-#define sk_POLICYINFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICYINFO, (st), (cmp))
-#define sk_POLICYINFO_dup(st) SKM_sk_dup(POLICYINFO, st)
-#define sk_POLICYINFO_pop_free(st, free_func) SKM_sk_pop_free(POLICYINFO, (st), (free_func))
-#define sk_POLICYINFO_shift(st) SKM_sk_shift(POLICYINFO, (st))
-#define sk_POLICYINFO_pop(st) SKM_sk_pop(POLICYINFO, (st))
-#define sk_POLICYINFO_sort(st) SKM_sk_sort(POLICYINFO, (st))
-#define sk_POLICYINFO_is_sorted(st) SKM_sk_is_sorted(POLICYINFO, (st))
-
-#define sk_POLICYQUALINFO_new(cmp) SKM_sk_new(POLICYQUALINFO, (cmp))
-#define sk_POLICYQUALINFO_new_null() SKM_sk_new_null(POLICYQUALINFO)
-#define sk_POLICYQUALINFO_free(st) SKM_sk_free(POLICYQUALINFO, (st))
-#define sk_POLICYQUALINFO_num(st) SKM_sk_num(POLICYQUALINFO, (st))
-#define sk_POLICYQUALINFO_value(st, i) SKM_sk_value(POLICYQUALINFO, (st), (i))
-#define sk_POLICYQUALINFO_set(st, i, val) SKM_sk_set(POLICYQUALINFO, (st), (i), (val))
-#define sk_POLICYQUALINFO_zero(st) SKM_sk_zero(POLICYQUALINFO, (st))
-#define sk_POLICYQUALINFO_push(st, val) SKM_sk_push(POLICYQUALINFO, (st), (val))
-#define sk_POLICYQUALINFO_unshift(st, val) SKM_sk_unshift(POLICYQUALINFO, (st), (val))
-#define sk_POLICYQUALINFO_find(st, val) SKM_sk_find(POLICYQUALINFO, (st), (val))
-#define sk_POLICYQUALINFO_find_ex(st, val) SKM_sk_find_ex(POLICYQUALINFO, (st), (val))
-#define sk_POLICYQUALINFO_delete(st, i) SKM_sk_delete(POLICYQUALINFO, (st), (i))
-#define sk_POLICYQUALINFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICYQUALINFO, (st), (ptr))
-#define sk_POLICYQUALINFO_insert(st, val, i) SKM_sk_insert(POLICYQUALINFO, (st), (val), (i))
-#define sk_POLICYQUALINFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICYQUALINFO, (st), (cmp))
-#define sk_POLICYQUALINFO_dup(st) SKM_sk_dup(POLICYQUALINFO, st)
-#define sk_POLICYQUALINFO_pop_free(st, free_func) SKM_sk_pop_free(POLICYQUALINFO, (st), (free_func))
-#define sk_POLICYQUALINFO_shift(st) SKM_sk_shift(POLICYQUALINFO, (st))
-#define sk_POLICYQUALINFO_pop(st) SKM_sk_pop(POLICYQUALINFO, (st))
-#define sk_POLICYQUALINFO_sort(st) SKM_sk_sort(POLICYQUALINFO, (st))
-#define sk_POLICYQUALINFO_is_sorted(st) SKM_sk_is_sorted(POLICYQUALINFO, (st))
-
-#define sk_POLICY_MAPPING_new(cmp) SKM_sk_new(POLICY_MAPPING, (cmp))
-#define sk_POLICY_MAPPING_new_null() SKM_sk_new_null(POLICY_MAPPING)
-#define sk_POLICY_MAPPING_free(st) SKM_sk_free(POLICY_MAPPING, (st))
-#define sk_POLICY_MAPPING_num(st) SKM_sk_num(POLICY_MAPPING, (st))
-#define sk_POLICY_MAPPING_value(st, i) SKM_sk_value(POLICY_MAPPING, (st), (i))
-#define sk_POLICY_MAPPING_set(st, i, val) SKM_sk_set(POLICY_MAPPING, (st), (i), (val))
-#define sk_POLICY_MAPPING_zero(st) SKM_sk_zero(POLICY_MAPPING, (st))
-#define sk_POLICY_MAPPING_push(st, val) SKM_sk_push(POLICY_MAPPING, (st), (val))
-#define sk_POLICY_MAPPING_unshift(st, val) SKM_sk_unshift(POLICY_MAPPING, (st), (val))
-#define sk_POLICY_MAPPING_find(st, val) SKM_sk_find(POLICY_MAPPING, (st), (val))
-#define sk_POLICY_MAPPING_find_ex(st, val) SKM_sk_find_ex(POLICY_MAPPING, (st), (val))
-#define sk_POLICY_MAPPING_delete(st, i) SKM_sk_delete(POLICY_MAPPING, (st), (i))
-#define sk_POLICY_MAPPING_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICY_MAPPING, (st), (ptr))
-#define sk_POLICY_MAPPING_insert(st, val, i) SKM_sk_insert(POLICY_MAPPING, (st), (val), (i))
-#define sk_POLICY_MAPPING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICY_MAPPING, (st), (cmp))
-#define sk_POLICY_MAPPING_dup(st) SKM_sk_dup(POLICY_MAPPING, st)
-#define sk_POLICY_MAPPING_pop_free(st, free_func) SKM_sk_pop_free(POLICY_MAPPING, (st), (free_func))
-#define sk_POLICY_MAPPING_shift(st) SKM_sk_shift(POLICY_MAPPING, (st))
-#define sk_POLICY_MAPPING_pop(st) SKM_sk_pop(POLICY_MAPPING, (st))
-#define sk_POLICY_MAPPING_sort(st) SKM_sk_sort(POLICY_MAPPING, (st))
-#define sk_POLICY_MAPPING_is_sorted(st) SKM_sk_is_sorted(POLICY_MAPPING, (st))
-
-#define sk_SRP_gN_new(cmp) SKM_sk_new(SRP_gN, (cmp))
-#define sk_SRP_gN_new_null() SKM_sk_new_null(SRP_gN)
-#define sk_SRP_gN_free(st) SKM_sk_free(SRP_gN, (st))
-#define sk_SRP_gN_num(st) SKM_sk_num(SRP_gN, (st))
-#define sk_SRP_gN_value(st, i) SKM_sk_value(SRP_gN, (st), (i))
-#define sk_SRP_gN_set(st, i, val) SKM_sk_set(SRP_gN, (st), (i), (val))
-#define sk_SRP_gN_zero(st) SKM_sk_zero(SRP_gN, (st))
-#define sk_SRP_gN_push(st, val) SKM_sk_push(SRP_gN, (st), (val))
-#define sk_SRP_gN_unshift(st, val) SKM_sk_unshift(SRP_gN, (st), (val))
-#define sk_SRP_gN_find(st, val) SKM_sk_find(SRP_gN, (st), (val))
-#define sk_SRP_gN_find_ex(st, val) SKM_sk_find_ex(SRP_gN, (st), (val))
-#define sk_SRP_gN_delete(st, i) SKM_sk_delete(SRP_gN, (st), (i))
-#define sk_SRP_gN_delete_ptr(st, ptr) SKM_sk_delete_ptr(SRP_gN, (st), (ptr))
-#define sk_SRP_gN_insert(st, val, i) SKM_sk_insert(SRP_gN, (st), (val), (i))
-#define sk_SRP_gN_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SRP_gN, (st), (cmp))
-#define sk_SRP_gN_dup(st) SKM_sk_dup(SRP_gN, st)
-#define sk_SRP_gN_pop_free(st, free_func) SKM_sk_pop_free(SRP_gN, (st), (free_func))
-#define sk_SRP_gN_shift(st) SKM_sk_shift(SRP_gN, (st))
-#define sk_SRP_gN_pop(st) SKM_sk_pop(SRP_gN, (st))
-#define sk_SRP_gN_sort(st) SKM_sk_sort(SRP_gN, (st))
-#define sk_SRP_gN_is_sorted(st) SKM_sk_is_sorted(SRP_gN, (st))
-
-#define sk_SRP_gN_cache_new(cmp) SKM_sk_new(SRP_gN_cache, (cmp))
-#define sk_SRP_gN_cache_new_null() SKM_sk_new_null(SRP_gN_cache)
-#define sk_SRP_gN_cache_free(st) SKM_sk_free(SRP_gN_cache, (st))
-#define sk_SRP_gN_cache_num(st) SKM_sk_num(SRP_gN_cache, (st))
-#define sk_SRP_gN_cache_value(st, i) SKM_sk_value(SRP_gN_cache, (st), (i))
-#define sk_SRP_gN_cache_set(st, i, val) SKM_sk_set(SRP_gN_cache, (st), (i), (val))
-#define sk_SRP_gN_cache_zero(st) SKM_sk_zero(SRP_gN_cache, (st))
-#define sk_SRP_gN_cache_push(st, val) SKM_sk_push(SRP_gN_cache, (st), (val))
-#define sk_SRP_gN_cache_unshift(st, val) SKM_sk_unshift(SRP_gN_cache, (st), (val))
-#define sk_SRP_gN_cache_find(st, val) SKM_sk_find(SRP_gN_cache, (st), (val))
-#define sk_SRP_gN_cache_find_ex(st, val) SKM_sk_find_ex(SRP_gN_cache, (st), (val))
-#define sk_SRP_gN_cache_delete(st, i) SKM_sk_delete(SRP_gN_cache, (st), (i))
-#define sk_SRP_gN_cache_delete_ptr(st, ptr) SKM_sk_delete_ptr(SRP_gN_cache, (st), (ptr))
-#define sk_SRP_gN_cache_insert(st, val, i) SKM_sk_insert(SRP_gN_cache, (st), (val), (i))
-#define sk_SRP_gN_cache_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SRP_gN_cache, (st), (cmp))
-#define sk_SRP_gN_cache_dup(st) SKM_sk_dup(SRP_gN_cache, st)
-#define sk_SRP_gN_cache_pop_free(st, free_func) SKM_sk_pop_free(SRP_gN_cache, (st), (free_func))
-#define sk_SRP_gN_cache_shift(st) SKM_sk_shift(SRP_gN_cache, (st))
-#define sk_SRP_gN_cache_pop(st) SKM_sk_pop(SRP_gN_cache, (st))
-#define sk_SRP_gN_cache_sort(st) SKM_sk_sort(SRP_gN_cache, (st))
-#define sk_SRP_gN_cache_is_sorted(st) SKM_sk_is_sorted(SRP_gN_cache, (st))
-
-#define sk_SRP_user_pwd_new(cmp) SKM_sk_new(SRP_user_pwd, (cmp))
-#define sk_SRP_user_pwd_new_null() SKM_sk_new_null(SRP_user_pwd)
-#define sk_SRP_user_pwd_free(st) SKM_sk_free(SRP_user_pwd, (st))
-#define sk_SRP_user_pwd_num(st) SKM_sk_num(SRP_user_pwd, (st))
-#define sk_SRP_user_pwd_value(st, i) SKM_sk_value(SRP_user_pwd, (st), (i))
-#define sk_SRP_user_pwd_set(st, i, val) SKM_sk_set(SRP_user_pwd, (st), (i), (val))
-#define sk_SRP_user_pwd_zero(st) SKM_sk_zero(SRP_user_pwd, (st))
-#define sk_SRP_user_pwd_push(st, val) SKM_sk_push(SRP_user_pwd, (st), (val))
-#define sk_SRP_user_pwd_unshift(st, val) SKM_sk_unshift(SRP_user_pwd, (st), (val))
-#define sk_SRP_user_pwd_find(st, val) SKM_sk_find(SRP_user_pwd, (st), (val))
-#define sk_SRP_user_pwd_find_ex(st, val) SKM_sk_find_ex(SRP_user_pwd, (st), (val))
-#define sk_SRP_user_pwd_delete(st, i) SKM_sk_delete(SRP_user_pwd, (st), (i))
-#define sk_SRP_user_pwd_delete_ptr(st, ptr) SKM_sk_delete_ptr(SRP_user_pwd, (st), (ptr))
-#define sk_SRP_user_pwd_insert(st, val, i) SKM_sk_insert(SRP_user_pwd, (st), (val), (i))
-#define sk_SRP_user_pwd_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SRP_user_pwd, (st), (cmp))
-#define sk_SRP_user_pwd_dup(st) SKM_sk_dup(SRP_user_pwd, st)
-#define sk_SRP_user_pwd_pop_free(st, free_func) SKM_sk_pop_free(SRP_user_pwd, (st), (free_func))
-#define sk_SRP_user_pwd_shift(st) SKM_sk_shift(SRP_user_pwd, (st))
-#define sk_SRP_user_pwd_pop(st) SKM_sk_pop(SRP_user_pwd, (st))
-#define sk_SRP_user_pwd_sort(st) SKM_sk_sort(SRP_user_pwd, (st))
-#define sk_SRP_user_pwd_is_sorted(st) SKM_sk_is_sorted(SRP_user_pwd, (st))
-
-#define sk_SRTP_PROTECTION_PROFILE_new(cmp) SKM_sk_new(SRTP_PROTECTION_PROFILE, (cmp))
-#define sk_SRTP_PROTECTION_PROFILE_new_null() SKM_sk_new_null(SRTP_PROTECTION_PROFILE)
-#define sk_SRTP_PROTECTION_PROFILE_free(st) SKM_sk_free(SRTP_PROTECTION_PROFILE, (st))
-#define sk_SRTP_PROTECTION_PROFILE_num(st) SKM_sk_num(SRTP_PROTECTION_PROFILE, (st))
-#define sk_SRTP_PROTECTION_PROFILE_value(st, i) SKM_sk_value(SRTP_PROTECTION_PROFILE, (st), (i))
-#define sk_SRTP_PROTECTION_PROFILE_set(st, i, val) SKM_sk_set(SRTP_PROTECTION_PROFILE, (st), (i), (val))
-#define sk_SRTP_PROTECTION_PROFILE_zero(st) SKM_sk_zero(SRTP_PROTECTION_PROFILE, (st))
-#define sk_SRTP_PROTECTION_PROFILE_push(st, val) SKM_sk_push(SRTP_PROTECTION_PROFILE, (st), (val))
-#define sk_SRTP_PROTECTION_PROFILE_unshift(st, val) SKM_sk_unshift(SRTP_PROTECTION_PROFILE, (st), (val))
-#define sk_SRTP_PROTECTION_PROFILE_find(st, val) SKM_sk_find(SRTP_PROTECTION_PROFILE, (st), (val))
-#define sk_SRTP_PROTECTION_PROFILE_find_ex(st, val) SKM_sk_find_ex(SRTP_PROTECTION_PROFILE, (st), (val))
-#define sk_SRTP_PROTECTION_PROFILE_delete(st, i) SKM_sk_delete(SRTP_PROTECTION_PROFILE, (st), (i))
-#define sk_SRTP_PROTECTION_PROFILE_delete_ptr(st, ptr) SKM_sk_delete_ptr(SRTP_PROTECTION_PROFILE, (st), (ptr))
-#define sk_SRTP_PROTECTION_PROFILE_insert(st, val, i) SKM_sk_insert(SRTP_PROTECTION_PROFILE, (st), (val), (i))
-#define sk_SRTP_PROTECTION_PROFILE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SRTP_PROTECTION_PROFILE, (st), (cmp))
-#define sk_SRTP_PROTECTION_PROFILE_dup(st) SKM_sk_dup(SRTP_PROTECTION_PROFILE, st)
-#define sk_SRTP_PROTECTION_PROFILE_pop_free(st, free_func) SKM_sk_pop_free(SRTP_PROTECTION_PROFILE, (st), (free_func))
-#define sk_SRTP_PROTECTION_PROFILE_shift(st) SKM_sk_shift(SRTP_PROTECTION_PROFILE, (st))
-#define sk_SRTP_PROTECTION_PROFILE_pop(st) SKM_sk_pop(SRTP_PROTECTION_PROFILE, (st))
-#define sk_SRTP_PROTECTION_PROFILE_sort(st) SKM_sk_sort(SRTP_PROTECTION_PROFILE, (st))
-#define sk_SRTP_PROTECTION_PROFILE_is_sorted(st) SKM_sk_is_sorted(SRTP_PROTECTION_PROFILE, (st))
-
-#define sk_SSL_CIPHER_new(cmp) SKM_sk_new(SSL_CIPHER, (cmp))
-#define sk_SSL_CIPHER_new_null() SKM_sk_new_null(SSL_CIPHER)
-#define sk_SSL_CIPHER_free(st) SKM_sk_free(SSL_CIPHER, (st))
-#define sk_SSL_CIPHER_num(st) SKM_sk_num(SSL_CIPHER, (st))
-#define sk_SSL_CIPHER_value(st, i) SKM_sk_value(SSL_CIPHER, (st), (i))
-#define sk_SSL_CIPHER_set(st, i, val) SKM_sk_set(SSL_CIPHER, (st), (i), (val))
-#define sk_SSL_CIPHER_zero(st) SKM_sk_zero(SSL_CIPHER, (st))
-#define sk_SSL_CIPHER_push(st, val) SKM_sk_push(SSL_CIPHER, (st), (val))
-#define sk_SSL_CIPHER_unshift(st, val) SKM_sk_unshift(SSL_CIPHER, (st), (val))
-#define sk_SSL_CIPHER_find(st, val) SKM_sk_find(SSL_CIPHER, (st), (val))
-#define sk_SSL_CIPHER_find_ex(st, val) SKM_sk_find_ex(SSL_CIPHER, (st), (val))
-#define sk_SSL_CIPHER_delete(st, i) SKM_sk_delete(SSL_CIPHER, (st), (i))
-#define sk_SSL_CIPHER_delete_ptr(st, ptr) SKM_sk_delete_ptr(SSL_CIPHER, (st), (ptr))
-#define sk_SSL_CIPHER_insert(st, val, i) SKM_sk_insert(SSL_CIPHER, (st), (val), (i))
-#define sk_SSL_CIPHER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SSL_CIPHER, (st), (cmp))
-#define sk_SSL_CIPHER_dup(st) SKM_sk_dup(SSL_CIPHER, st)
-#define sk_SSL_CIPHER_pop_free(st, free_func) SKM_sk_pop_free(SSL_CIPHER, (st), (free_func))
-#define sk_SSL_CIPHER_shift(st) SKM_sk_shift(SSL_CIPHER, (st))
-#define sk_SSL_CIPHER_pop(st) SKM_sk_pop(SSL_CIPHER, (st))
-#define sk_SSL_CIPHER_sort(st) SKM_sk_sort(SSL_CIPHER, (st))
-#define sk_SSL_CIPHER_is_sorted(st) SKM_sk_is_sorted(SSL_CIPHER, (st))
-
-#define sk_SSL_COMP_new(cmp) SKM_sk_new(SSL_COMP, (cmp))
-#define sk_SSL_COMP_new_null() SKM_sk_new_null(SSL_COMP)
-#define sk_SSL_COMP_free(st) SKM_sk_free(SSL_COMP, (st))
-#define sk_SSL_COMP_num(st) SKM_sk_num(SSL_COMP, (st))
-#define sk_SSL_COMP_value(st, i) SKM_sk_value(SSL_COMP, (st), (i))
-#define sk_SSL_COMP_set(st, i, val) SKM_sk_set(SSL_COMP, (st), (i), (val))
-#define sk_SSL_COMP_zero(st) SKM_sk_zero(SSL_COMP, (st))
-#define sk_SSL_COMP_push(st, val) SKM_sk_push(SSL_COMP, (st), (val))
-#define sk_SSL_COMP_unshift(st, val) SKM_sk_unshift(SSL_COMP, (st), (val))
-#define sk_SSL_COMP_find(st, val) SKM_sk_find(SSL_COMP, (st), (val))
-#define sk_SSL_COMP_find_ex(st, val) SKM_sk_find_ex(SSL_COMP, (st), (val))
-#define sk_SSL_COMP_delete(st, i) SKM_sk_delete(SSL_COMP, (st), (i))
-#define sk_SSL_COMP_delete_ptr(st, ptr) SKM_sk_delete_ptr(SSL_COMP, (st), (ptr))
-#define sk_SSL_COMP_insert(st, val, i) SKM_sk_insert(SSL_COMP, (st), (val), (i))
-#define sk_SSL_COMP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SSL_COMP, (st), (cmp))
-#define sk_SSL_COMP_dup(st) SKM_sk_dup(SSL_COMP, st)
-#define sk_SSL_COMP_pop_free(st, free_func) SKM_sk_pop_free(SSL_COMP, (st), (free_func))
-#define sk_SSL_COMP_shift(st) SKM_sk_shift(SSL_COMP, (st))
-#define sk_SSL_COMP_pop(st) SKM_sk_pop(SSL_COMP, (st))
-#define sk_SSL_COMP_sort(st) SKM_sk_sort(SSL_COMP, (st))
-#define sk_SSL_COMP_is_sorted(st) SKM_sk_is_sorted(SSL_COMP, (st))
-
-#define sk_STACK_OF_X509_NAME_ENTRY_new(cmp) SKM_sk_new(STACK_OF_X509_NAME_ENTRY, (cmp))
-#define sk_STACK_OF_X509_NAME_ENTRY_new_null() SKM_sk_new_null(STACK_OF_X509_NAME_ENTRY)
-#define sk_STACK_OF_X509_NAME_ENTRY_free(st) SKM_sk_free(STACK_OF_X509_NAME_ENTRY, (st))
-#define sk_STACK_OF_X509_NAME_ENTRY_num(st) SKM_sk_num(STACK_OF_X509_NAME_ENTRY, (st))
-#define sk_STACK_OF_X509_NAME_ENTRY_value(st, i) SKM_sk_value(STACK_OF_X509_NAME_ENTRY, (st), (i))
-#define sk_STACK_OF_X509_NAME_ENTRY_set(st, i, val) SKM_sk_set(STACK_OF_X509_NAME_ENTRY, (st), (i), (val))
-#define sk_STACK_OF_X509_NAME_ENTRY_zero(st) SKM_sk_zero(STACK_OF_X509_NAME_ENTRY, (st))
-#define sk_STACK_OF_X509_NAME_ENTRY_push(st, val) SKM_sk_push(STACK_OF_X509_NAME_ENTRY, (st), (val))
-#define sk_STACK_OF_X509_NAME_ENTRY_unshift(st, val) SKM_sk_unshift(STACK_OF_X509_NAME_ENTRY, (st), (val))
-#define sk_STACK_OF_X509_NAME_ENTRY_find(st, val) SKM_sk_find(STACK_OF_X509_NAME_ENTRY, (st), (val))
-#define sk_STACK_OF_X509_NAME_ENTRY_find_ex(st, val) SKM_sk_find_ex(STACK_OF_X509_NAME_ENTRY, (st), (val))
-#define sk_STACK_OF_X509_NAME_ENTRY_delete(st, i) SKM_sk_delete(STACK_OF_X509_NAME_ENTRY, (st), (i))
-#define sk_STACK_OF_X509_NAME_ENTRY_delete_ptr(st, ptr) SKM_sk_delete_ptr(STACK_OF_X509_NAME_ENTRY, (st), (ptr))
-#define sk_STACK_OF_X509_NAME_ENTRY_insert(st, val, i) SKM_sk_insert(STACK_OF_X509_NAME_ENTRY, (st), (val), (i))
-#define sk_STACK_OF_X509_NAME_ENTRY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(STACK_OF_X509_NAME_ENTRY, (st), (cmp))
-#define sk_STACK_OF_X509_NAME_ENTRY_dup(st) SKM_sk_dup(STACK_OF_X509_NAME_ENTRY, st)
-#define sk_STACK_OF_X509_NAME_ENTRY_pop_free(st, free_func) SKM_sk_pop_free(STACK_OF_X509_NAME_ENTRY, (st), (free_func))
-#define sk_STACK_OF_X509_NAME_ENTRY_shift(st) SKM_sk_shift(STACK_OF_X509_NAME_ENTRY, (st))
-#define sk_STACK_OF_X509_NAME_ENTRY_pop(st) SKM_sk_pop(STACK_OF_X509_NAME_ENTRY, (st))
-#define sk_STACK_OF_X509_NAME_ENTRY_sort(st) SKM_sk_sort(STACK_OF_X509_NAME_ENTRY, (st))
-#define sk_STACK_OF_X509_NAME_ENTRY_is_sorted(st) SKM_sk_is_sorted(STACK_OF_X509_NAME_ENTRY, (st))
-
-#define sk_STORE_ATTR_INFO_new(cmp) SKM_sk_new(STORE_ATTR_INFO, (cmp))
-#define sk_STORE_ATTR_INFO_new_null() SKM_sk_new_null(STORE_ATTR_INFO)
-#define sk_STORE_ATTR_INFO_free(st) SKM_sk_free(STORE_ATTR_INFO, (st))
-#define sk_STORE_ATTR_INFO_num(st) SKM_sk_num(STORE_ATTR_INFO, (st))
-#define sk_STORE_ATTR_INFO_value(st, i) SKM_sk_value(STORE_ATTR_INFO, (st), (i))
-#define sk_STORE_ATTR_INFO_set(st, i, val) SKM_sk_set(STORE_ATTR_INFO, (st), (i), (val))
-#define sk_STORE_ATTR_INFO_zero(st) SKM_sk_zero(STORE_ATTR_INFO, (st))
-#define sk_STORE_ATTR_INFO_push(st, val) SKM_sk_push(STORE_ATTR_INFO, (st), (val))
-#define sk_STORE_ATTR_INFO_unshift(st, val) SKM_sk_unshift(STORE_ATTR_INFO, (st), (val))
-#define sk_STORE_ATTR_INFO_find(st, val) SKM_sk_find(STORE_ATTR_INFO, (st), (val))
-#define sk_STORE_ATTR_INFO_find_ex(st, val) SKM_sk_find_ex(STORE_ATTR_INFO, (st), (val))
-#define sk_STORE_ATTR_INFO_delete(st, i) SKM_sk_delete(STORE_ATTR_INFO, (st), (i))
-#define sk_STORE_ATTR_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(STORE_ATTR_INFO, (st), (ptr))
-#define sk_STORE_ATTR_INFO_insert(st, val, i) SKM_sk_insert(STORE_ATTR_INFO, (st), (val), (i))
-#define sk_STORE_ATTR_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(STORE_ATTR_INFO, (st), (cmp))
-#define sk_STORE_ATTR_INFO_dup(st) SKM_sk_dup(STORE_ATTR_INFO, st)
-#define sk_STORE_ATTR_INFO_pop_free(st, free_func) SKM_sk_pop_free(STORE_ATTR_INFO, (st), (free_func))
-#define sk_STORE_ATTR_INFO_shift(st) SKM_sk_shift(STORE_ATTR_INFO, (st))
-#define sk_STORE_ATTR_INFO_pop(st) SKM_sk_pop(STORE_ATTR_INFO, (st))
-#define sk_STORE_ATTR_INFO_sort(st) SKM_sk_sort(STORE_ATTR_INFO, (st))
-#define sk_STORE_ATTR_INFO_is_sorted(st) SKM_sk_is_sorted(STORE_ATTR_INFO, (st))
-
-#define sk_STORE_OBJECT_new(cmp) SKM_sk_new(STORE_OBJECT, (cmp))
-#define sk_STORE_OBJECT_new_null() SKM_sk_new_null(STORE_OBJECT)
-#define sk_STORE_OBJECT_free(st) SKM_sk_free(STORE_OBJECT, (st))
-#define sk_STORE_OBJECT_num(st) SKM_sk_num(STORE_OBJECT, (st))
-#define sk_STORE_OBJECT_value(st, i) SKM_sk_value(STORE_OBJECT, (st), (i))
-#define sk_STORE_OBJECT_set(st, i, val) SKM_sk_set(STORE_OBJECT, (st), (i), (val))
-#define sk_STORE_OBJECT_zero(st) SKM_sk_zero(STORE_OBJECT, (st))
-#define sk_STORE_OBJECT_push(st, val) SKM_sk_push(STORE_OBJECT, (st), (val))
-#define sk_STORE_OBJECT_unshift(st, val) SKM_sk_unshift(STORE_OBJECT, (st), (val))
-#define sk_STORE_OBJECT_find(st, val) SKM_sk_find(STORE_OBJECT, (st), (val))
-#define sk_STORE_OBJECT_find_ex(st, val) SKM_sk_find_ex(STORE_OBJECT, (st), (val))
-#define sk_STORE_OBJECT_delete(st, i) SKM_sk_delete(STORE_OBJECT, (st), (i))
-#define sk_STORE_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(STORE_OBJECT, (st), (ptr))
-#define sk_STORE_OBJECT_insert(st, val, i) SKM_sk_insert(STORE_OBJECT, (st), (val), (i))
-#define sk_STORE_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(STORE_OBJECT, (st), (cmp))
-#define sk_STORE_OBJECT_dup(st) SKM_sk_dup(STORE_OBJECT, st)
-#define sk_STORE_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(STORE_OBJECT, (st), (free_func))
-#define sk_STORE_OBJECT_shift(st) SKM_sk_shift(STORE_OBJECT, (st))
-#define sk_STORE_OBJECT_pop(st) SKM_sk_pop(STORE_OBJECT, (st))
-#define sk_STORE_OBJECT_sort(st) SKM_sk_sort(STORE_OBJECT, (st))
-#define sk_STORE_OBJECT_is_sorted(st) SKM_sk_is_sorted(STORE_OBJECT, (st))
-
-#define sk_SXNETID_new(cmp) SKM_sk_new(SXNETID, (cmp))
-#define sk_SXNETID_new_null() SKM_sk_new_null(SXNETID)
-#define sk_SXNETID_free(st) SKM_sk_free(SXNETID, (st))
-#define sk_SXNETID_num(st) SKM_sk_num(SXNETID, (st))
-#define sk_SXNETID_value(st, i) SKM_sk_value(SXNETID, (st), (i))
-#define sk_SXNETID_set(st, i, val) SKM_sk_set(SXNETID, (st), (i), (val))
-#define sk_SXNETID_zero(st) SKM_sk_zero(SXNETID, (st))
-#define sk_SXNETID_push(st, val) SKM_sk_push(SXNETID, (st), (val))
-#define sk_SXNETID_unshift(st, val) SKM_sk_unshift(SXNETID, (st), (val))
-#define sk_SXNETID_find(st, val) SKM_sk_find(SXNETID, (st), (val))
-#define sk_SXNETID_find_ex(st, val) SKM_sk_find_ex(SXNETID, (st), (val))
-#define sk_SXNETID_delete(st, i) SKM_sk_delete(SXNETID, (st), (i))
-#define sk_SXNETID_delete_ptr(st, ptr) SKM_sk_delete_ptr(SXNETID, (st), (ptr))
-#define sk_SXNETID_insert(st, val, i) SKM_sk_insert(SXNETID, (st), (val), (i))
-#define sk_SXNETID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SXNETID, (st), (cmp))
-#define sk_SXNETID_dup(st) SKM_sk_dup(SXNETID, st)
-#define sk_SXNETID_pop_free(st, free_func) SKM_sk_pop_free(SXNETID, (st), (free_func))
-#define sk_SXNETID_shift(st) SKM_sk_shift(SXNETID, (st))
-#define sk_SXNETID_pop(st) SKM_sk_pop(SXNETID, (st))
-#define sk_SXNETID_sort(st) SKM_sk_sort(SXNETID, (st))
-#define sk_SXNETID_is_sorted(st) SKM_sk_is_sorted(SXNETID, (st))
-
-#define sk_UI_STRING_new(cmp) SKM_sk_new(UI_STRING, (cmp))
-#define sk_UI_STRING_new_null() SKM_sk_new_null(UI_STRING)
-#define sk_UI_STRING_free(st) SKM_sk_free(UI_STRING, (st))
-#define sk_UI_STRING_num(st) SKM_sk_num(UI_STRING, (st))
-#define sk_UI_STRING_value(st, i) SKM_sk_value(UI_STRING, (st), (i))
-#define sk_UI_STRING_set(st, i, val) SKM_sk_set(UI_STRING, (st), (i), (val))
-#define sk_UI_STRING_zero(st) SKM_sk_zero(UI_STRING, (st))
-#define sk_UI_STRING_push(st, val) SKM_sk_push(UI_STRING, (st), (val))
-#define sk_UI_STRING_unshift(st, val) SKM_sk_unshift(UI_STRING, (st), (val))
-#define sk_UI_STRING_find(st, val) SKM_sk_find(UI_STRING, (st), (val))
-#define sk_UI_STRING_find_ex(st, val) SKM_sk_find_ex(UI_STRING, (st), (val))
-#define sk_UI_STRING_delete(st, i) SKM_sk_delete(UI_STRING, (st), (i))
-#define sk_UI_STRING_delete_ptr(st, ptr) SKM_sk_delete_ptr(UI_STRING, (st), (ptr))
-#define sk_UI_STRING_insert(st, val, i) SKM_sk_insert(UI_STRING, (st), (val), (i))
-#define sk_UI_STRING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(UI_STRING, (st), (cmp))
-#define sk_UI_STRING_dup(st) SKM_sk_dup(UI_STRING, st)
-#define sk_UI_STRING_pop_free(st, free_func) SKM_sk_pop_free(UI_STRING, (st), (free_func))
-#define sk_UI_STRING_shift(st) SKM_sk_shift(UI_STRING, (st))
-#define sk_UI_STRING_pop(st) SKM_sk_pop(UI_STRING, (st))
-#define sk_UI_STRING_sort(st) SKM_sk_sort(UI_STRING, (st))
-#define sk_UI_STRING_is_sorted(st) SKM_sk_is_sorted(UI_STRING, (st))
-
-#define sk_X509_new(cmp) SKM_sk_new(X509, (cmp))
-#define sk_X509_new_null() SKM_sk_new_null(X509)
-#define sk_X509_free(st) SKM_sk_free(X509, (st))
-#define sk_X509_num(st) SKM_sk_num(X509, (st))
-#define sk_X509_value(st, i) SKM_sk_value(X509, (st), (i))
-#define sk_X509_set(st, i, val) SKM_sk_set(X509, (st), (i), (val))
-#define sk_X509_zero(st) SKM_sk_zero(X509, (st))
-#define sk_X509_push(st, val) SKM_sk_push(X509, (st), (val))
-#define sk_X509_unshift(st, val) SKM_sk_unshift(X509, (st), (val))
-#define sk_X509_find(st, val) SKM_sk_find(X509, (st), (val))
-#define sk_X509_find_ex(st, val) SKM_sk_find_ex(X509, (st), (val))
-#define sk_X509_delete(st, i) SKM_sk_delete(X509, (st), (i))
-#define sk_X509_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509, (st), (ptr))
-#define sk_X509_insert(st, val, i) SKM_sk_insert(X509, (st), (val), (i))
-#define sk_X509_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509, (st), (cmp))
-#define sk_X509_dup(st) SKM_sk_dup(X509, st)
-#define sk_X509_pop_free(st, free_func) SKM_sk_pop_free(X509, (st), (free_func))
-#define sk_X509_shift(st) SKM_sk_shift(X509, (st))
-#define sk_X509_pop(st) SKM_sk_pop(X509, (st))
-#define sk_X509_sort(st) SKM_sk_sort(X509, (st))
-#define sk_X509_is_sorted(st) SKM_sk_is_sorted(X509, (st))
-
-#define sk_X509V3_EXT_METHOD_new(cmp) SKM_sk_new(X509V3_EXT_METHOD, (cmp))
-#define sk_X509V3_EXT_METHOD_new_null() SKM_sk_new_null(X509V3_EXT_METHOD)
-#define sk_X509V3_EXT_METHOD_free(st) SKM_sk_free(X509V3_EXT_METHOD, (st))
-#define sk_X509V3_EXT_METHOD_num(st) SKM_sk_num(X509V3_EXT_METHOD, (st))
-#define sk_X509V3_EXT_METHOD_value(st, i) SKM_sk_value(X509V3_EXT_METHOD, (st), (i))
-#define sk_X509V3_EXT_METHOD_set(st, i, val) SKM_sk_set(X509V3_EXT_METHOD, (st), (i), (val))
-#define sk_X509V3_EXT_METHOD_zero(st) SKM_sk_zero(X509V3_EXT_METHOD, (st))
-#define sk_X509V3_EXT_METHOD_push(st, val) SKM_sk_push(X509V3_EXT_METHOD, (st), (val))
-#define sk_X509V3_EXT_METHOD_unshift(st, val) SKM_sk_unshift(X509V3_EXT_METHOD, (st), (val))
-#define sk_X509V3_EXT_METHOD_find(st, val) SKM_sk_find(X509V3_EXT_METHOD, (st), (val))
-#define sk_X509V3_EXT_METHOD_find_ex(st, val) SKM_sk_find_ex(X509V3_EXT_METHOD, (st), (val))
-#define sk_X509V3_EXT_METHOD_delete(st, i) SKM_sk_delete(X509V3_EXT_METHOD, (st), (i))
-#define sk_X509V3_EXT_METHOD_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509V3_EXT_METHOD, (st), (ptr))
-#define sk_X509V3_EXT_METHOD_insert(st, val, i) SKM_sk_insert(X509V3_EXT_METHOD, (st), (val), (i))
-#define sk_X509V3_EXT_METHOD_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509V3_EXT_METHOD, (st), (cmp))
-#define sk_X509V3_EXT_METHOD_dup(st) SKM_sk_dup(X509V3_EXT_METHOD, st)
-#define sk_X509V3_EXT_METHOD_pop_free(st, free_func) SKM_sk_pop_free(X509V3_EXT_METHOD, (st), (free_func))
-#define sk_X509V3_EXT_METHOD_shift(st) SKM_sk_shift(X509V3_EXT_METHOD, (st))
-#define sk_X509V3_EXT_METHOD_pop(st) SKM_sk_pop(X509V3_EXT_METHOD, (st))
-#define sk_X509V3_EXT_METHOD_sort(st) SKM_sk_sort(X509V3_EXT_METHOD, (st))
-#define sk_X509V3_EXT_METHOD_is_sorted(st) SKM_sk_is_sorted(X509V3_EXT_METHOD, (st))
-
-#define sk_X509_ALGOR_new(cmp) SKM_sk_new(X509_ALGOR, (cmp))
-#define sk_X509_ALGOR_new_null() SKM_sk_new_null(X509_ALGOR)
-#define sk_X509_ALGOR_free(st) SKM_sk_free(X509_ALGOR, (st))
-#define sk_X509_ALGOR_num(st) SKM_sk_num(X509_ALGOR, (st))
-#define sk_X509_ALGOR_value(st, i) SKM_sk_value(X509_ALGOR, (st), (i))
-#define sk_X509_ALGOR_set(st, i, val) SKM_sk_set(X509_ALGOR, (st), (i), (val))
-#define sk_X509_ALGOR_zero(st) SKM_sk_zero(X509_ALGOR, (st))
-#define sk_X509_ALGOR_push(st, val) SKM_sk_push(X509_ALGOR, (st), (val))
-#define sk_X509_ALGOR_unshift(st, val) SKM_sk_unshift(X509_ALGOR, (st), (val))
-#define sk_X509_ALGOR_find(st, val) SKM_sk_find(X509_ALGOR, (st), (val))
-#define sk_X509_ALGOR_find_ex(st, val) SKM_sk_find_ex(X509_ALGOR, (st), (val))
-#define sk_X509_ALGOR_delete(st, i) SKM_sk_delete(X509_ALGOR, (st), (i))
-#define sk_X509_ALGOR_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_ALGOR, (st), (ptr))
-#define sk_X509_ALGOR_insert(st, val, i) SKM_sk_insert(X509_ALGOR, (st), (val), (i))
-#define sk_X509_ALGOR_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_ALGOR, (st), (cmp))
-#define sk_X509_ALGOR_dup(st) SKM_sk_dup(X509_ALGOR, st)
-#define sk_X509_ALGOR_pop_free(st, free_func) SKM_sk_pop_free(X509_ALGOR, (st), (free_func))
-#define sk_X509_ALGOR_shift(st) SKM_sk_shift(X509_ALGOR, (st))
-#define sk_X509_ALGOR_pop(st) SKM_sk_pop(X509_ALGOR, (st))
-#define sk_X509_ALGOR_sort(st) SKM_sk_sort(X509_ALGOR, (st))
-#define sk_X509_ALGOR_is_sorted(st) SKM_sk_is_sorted(X509_ALGOR, (st))
-
-#define sk_X509_ATTRIBUTE_new(cmp) SKM_sk_new(X509_ATTRIBUTE, (cmp))
-#define sk_X509_ATTRIBUTE_new_null() SKM_sk_new_null(X509_ATTRIBUTE)
-#define sk_X509_ATTRIBUTE_free(st) SKM_sk_free(X509_ATTRIBUTE, (st))
-#define sk_X509_ATTRIBUTE_num(st) SKM_sk_num(X509_ATTRIBUTE, (st))
-#define sk_X509_ATTRIBUTE_value(st, i) SKM_sk_value(X509_ATTRIBUTE, (st), (i))
-#define sk_X509_ATTRIBUTE_set(st, i, val) SKM_sk_set(X509_ATTRIBUTE, (st), (i), (val))
-#define sk_X509_ATTRIBUTE_zero(st) SKM_sk_zero(X509_ATTRIBUTE, (st))
-#define sk_X509_ATTRIBUTE_push(st, val) SKM_sk_push(X509_ATTRIBUTE, (st), (val))
-#define sk_X509_ATTRIBUTE_unshift(st, val) SKM_sk_unshift(X509_ATTRIBUTE, (st), (val))
-#define sk_X509_ATTRIBUTE_find(st, val) SKM_sk_find(X509_ATTRIBUTE, (st), (val))
-#define sk_X509_ATTRIBUTE_find_ex(st, val) SKM_sk_find_ex(X509_ATTRIBUTE, (st), (val))
-#define sk_X509_ATTRIBUTE_delete(st, i) SKM_sk_delete(X509_ATTRIBUTE, (st), (i))
-#define sk_X509_ATTRIBUTE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_ATTRIBUTE, (st), (ptr))
-#define sk_X509_ATTRIBUTE_insert(st, val, i) SKM_sk_insert(X509_ATTRIBUTE, (st), (val), (i))
-#define sk_X509_ATTRIBUTE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_ATTRIBUTE, (st), (cmp))
-#define sk_X509_ATTRIBUTE_dup(st) SKM_sk_dup(X509_ATTRIBUTE, st)
-#define sk_X509_ATTRIBUTE_pop_free(st, free_func) SKM_sk_pop_free(X509_ATTRIBUTE, (st), (free_func))
-#define sk_X509_ATTRIBUTE_shift(st) SKM_sk_shift(X509_ATTRIBUTE, (st))
-#define sk_X509_ATTRIBUTE_pop(st) SKM_sk_pop(X509_ATTRIBUTE, (st))
-#define sk_X509_ATTRIBUTE_sort(st) SKM_sk_sort(X509_ATTRIBUTE, (st))
-#define sk_X509_ATTRIBUTE_is_sorted(st) SKM_sk_is_sorted(X509_ATTRIBUTE, (st))
-
-#define sk_X509_CRL_new(cmp) SKM_sk_new(X509_CRL, (cmp))
-#define sk_X509_CRL_new_null() SKM_sk_new_null(X509_CRL)
-#define sk_X509_CRL_free(st) SKM_sk_free(X509_CRL, (st))
-#define sk_X509_CRL_num(st) SKM_sk_num(X509_CRL, (st))
-#define sk_X509_CRL_value(st, i) SKM_sk_value(X509_CRL, (st), (i))
-#define sk_X509_CRL_set(st, i, val) SKM_sk_set(X509_CRL, (st), (i), (val))
-#define sk_X509_CRL_zero(st) SKM_sk_zero(X509_CRL, (st))
-#define sk_X509_CRL_push(st, val) SKM_sk_push(X509_CRL, (st), (val))
-#define sk_X509_CRL_unshift(st, val) SKM_sk_unshift(X509_CRL, (st), (val))
-#define sk_X509_CRL_find(st, val) SKM_sk_find(X509_CRL, (st), (val))
-#define sk_X509_CRL_find_ex(st, val) SKM_sk_find_ex(X509_CRL, (st), (val))
-#define sk_X509_CRL_delete(st, i) SKM_sk_delete(X509_CRL, (st), (i))
-#define sk_X509_CRL_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_CRL, (st), (ptr))
-#define sk_X509_CRL_insert(st, val, i) SKM_sk_insert(X509_CRL, (st), (val), (i))
-#define sk_X509_CRL_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_CRL, (st), (cmp))
-#define sk_X509_CRL_dup(st) SKM_sk_dup(X509_CRL, st)
-#define sk_X509_CRL_pop_free(st, free_func) SKM_sk_pop_free(X509_CRL, (st), (free_func))
-#define sk_X509_CRL_shift(st) SKM_sk_shift(X509_CRL, (st))
-#define sk_X509_CRL_pop(st) SKM_sk_pop(X509_CRL, (st))
-#define sk_X509_CRL_sort(st) SKM_sk_sort(X509_CRL, (st))
-#define sk_X509_CRL_is_sorted(st) SKM_sk_is_sorted(X509_CRL, (st))
-
-#define sk_X509_EXTENSION_new(cmp) SKM_sk_new(X509_EXTENSION, (cmp))
-#define sk_X509_EXTENSION_new_null() SKM_sk_new_null(X509_EXTENSION)
-#define sk_X509_EXTENSION_free(st) SKM_sk_free(X509_EXTENSION, (st))
-#define sk_X509_EXTENSION_num(st) SKM_sk_num(X509_EXTENSION, (st))
-#define sk_X509_EXTENSION_value(st, i) SKM_sk_value(X509_EXTENSION, (st), (i))
-#define sk_X509_EXTENSION_set(st, i, val) SKM_sk_set(X509_EXTENSION, (st), (i), (val))
-#define sk_X509_EXTENSION_zero(st) SKM_sk_zero(X509_EXTENSION, (st))
-#define sk_X509_EXTENSION_push(st, val) SKM_sk_push(X509_EXTENSION, (st), (val))
-#define sk_X509_EXTENSION_unshift(st, val) SKM_sk_unshift(X509_EXTENSION, (st), (val))
-#define sk_X509_EXTENSION_find(st, val) SKM_sk_find(X509_EXTENSION, (st), (val))
-#define sk_X509_EXTENSION_find_ex(st, val) SKM_sk_find_ex(X509_EXTENSION, (st), (val))
-#define sk_X509_EXTENSION_delete(st, i) SKM_sk_delete(X509_EXTENSION, (st), (i))
-#define sk_X509_EXTENSION_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_EXTENSION, (st), (ptr))
-#define sk_X509_EXTENSION_insert(st, val, i) SKM_sk_insert(X509_EXTENSION, (st), (val), (i))
-#define sk_X509_EXTENSION_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_EXTENSION, (st), (cmp))
-#define sk_X509_EXTENSION_dup(st) SKM_sk_dup(X509_EXTENSION, st)
-#define sk_X509_EXTENSION_pop_free(st, free_func) SKM_sk_pop_free(X509_EXTENSION, (st), (free_func))
-#define sk_X509_EXTENSION_shift(st) SKM_sk_shift(X509_EXTENSION, (st))
-#define sk_X509_EXTENSION_pop(st) SKM_sk_pop(X509_EXTENSION, (st))
-#define sk_X509_EXTENSION_sort(st) SKM_sk_sort(X509_EXTENSION, (st))
-#define sk_X509_EXTENSION_is_sorted(st) SKM_sk_is_sorted(X509_EXTENSION, (st))
-
-#define sk_X509_INFO_new(cmp) SKM_sk_new(X509_INFO, (cmp))
-#define sk_X509_INFO_new_null() SKM_sk_new_null(X509_INFO)
-#define sk_X509_INFO_free(st) SKM_sk_free(X509_INFO, (st))
-#define sk_X509_INFO_num(st) SKM_sk_num(X509_INFO, (st))
-#define sk_X509_INFO_value(st, i) SKM_sk_value(X509_INFO, (st), (i))
-#define sk_X509_INFO_set(st, i, val) SKM_sk_set(X509_INFO, (st), (i), (val))
-#define sk_X509_INFO_zero(st) SKM_sk_zero(X509_INFO, (st))
-#define sk_X509_INFO_push(st, val) SKM_sk_push(X509_INFO, (st), (val))
-#define sk_X509_INFO_unshift(st, val) SKM_sk_unshift(X509_INFO, (st), (val))
-#define sk_X509_INFO_find(st, val) SKM_sk_find(X509_INFO, (st), (val))
-#define sk_X509_INFO_find_ex(st, val) SKM_sk_find_ex(X509_INFO, (st), (val))
-#define sk_X509_INFO_delete(st, i) SKM_sk_delete(X509_INFO, (st), (i))
-#define sk_X509_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_INFO, (st), (ptr))
-#define sk_X509_INFO_insert(st, val, i) SKM_sk_insert(X509_INFO, (st), (val), (i))
-#define sk_X509_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_INFO, (st), (cmp))
-#define sk_X509_INFO_dup(st) SKM_sk_dup(X509_INFO, st)
-#define sk_X509_INFO_pop_free(st, free_func) SKM_sk_pop_free(X509_INFO, (st), (free_func))
-#define sk_X509_INFO_shift(st) SKM_sk_shift(X509_INFO, (st))
-#define sk_X509_INFO_pop(st) SKM_sk_pop(X509_INFO, (st))
-#define sk_X509_INFO_sort(st) SKM_sk_sort(X509_INFO, (st))
-#define sk_X509_INFO_is_sorted(st) SKM_sk_is_sorted(X509_INFO, (st))
-
-#define sk_X509_LOOKUP_new(cmp) SKM_sk_new(X509_LOOKUP, (cmp))
-#define sk_X509_LOOKUP_new_null() SKM_sk_new_null(X509_LOOKUP)
-#define sk_X509_LOOKUP_free(st) SKM_sk_free(X509_LOOKUP, (st))
-#define sk_X509_LOOKUP_num(st) SKM_sk_num(X509_LOOKUP, (st))
-#define sk_X509_LOOKUP_value(st, i) SKM_sk_value(X509_LOOKUP, (st), (i))
-#define sk_X509_LOOKUP_set(st, i, val) SKM_sk_set(X509_LOOKUP, (st), (i), (val))
-#define sk_X509_LOOKUP_zero(st) SKM_sk_zero(X509_LOOKUP, (st))
-#define sk_X509_LOOKUP_push(st, val) SKM_sk_push(X509_LOOKUP, (st), (val))
-#define sk_X509_LOOKUP_unshift(st, val) SKM_sk_unshift(X509_LOOKUP, (st), (val))
-#define sk_X509_LOOKUP_find(st, val) SKM_sk_find(X509_LOOKUP, (st), (val))
-#define sk_X509_LOOKUP_find_ex(st, val) SKM_sk_find_ex(X509_LOOKUP, (st), (val))
-#define sk_X509_LOOKUP_delete(st, i) SKM_sk_delete(X509_LOOKUP, (st), (i))
-#define sk_X509_LOOKUP_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_LOOKUP, (st), (ptr))
-#define sk_X509_LOOKUP_insert(st, val, i) SKM_sk_insert(X509_LOOKUP, (st), (val), (i))
-#define sk_X509_LOOKUP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_LOOKUP, (st), (cmp))
-#define sk_X509_LOOKUP_dup(st) SKM_sk_dup(X509_LOOKUP, st)
-#define sk_X509_LOOKUP_pop_free(st, free_func) SKM_sk_pop_free(X509_LOOKUP, (st), (free_func))
-#define sk_X509_LOOKUP_shift(st) SKM_sk_shift(X509_LOOKUP, (st))
-#define sk_X509_LOOKUP_pop(st) SKM_sk_pop(X509_LOOKUP, (st))
-#define sk_X509_LOOKUP_sort(st) SKM_sk_sort(X509_LOOKUP, (st))
-#define sk_X509_LOOKUP_is_sorted(st) SKM_sk_is_sorted(X509_LOOKUP, (st))
-
-#define sk_X509_NAME_new(cmp) SKM_sk_new(X509_NAME, (cmp))
-#define sk_X509_NAME_new_null() SKM_sk_new_null(X509_NAME)
-#define sk_X509_NAME_free(st) SKM_sk_free(X509_NAME, (st))
-#define sk_X509_NAME_num(st) SKM_sk_num(X509_NAME, (st))
-#define sk_X509_NAME_value(st, i) SKM_sk_value(X509_NAME, (st), (i))
-#define sk_X509_NAME_set(st, i, val) SKM_sk_set(X509_NAME, (st), (i), (val))
-#define sk_X509_NAME_zero(st) SKM_sk_zero(X509_NAME, (st))
-#define sk_X509_NAME_push(st, val) SKM_sk_push(X509_NAME, (st), (val))
-#define sk_X509_NAME_unshift(st, val) SKM_sk_unshift(X509_NAME, (st), (val))
-#define sk_X509_NAME_find(st, val) SKM_sk_find(X509_NAME, (st), (val))
-#define sk_X509_NAME_find_ex(st, val) SKM_sk_find_ex(X509_NAME, (st), (val))
-#define sk_X509_NAME_delete(st, i) SKM_sk_delete(X509_NAME, (st), (i))
-#define sk_X509_NAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_NAME, (st), (ptr))
-#define sk_X509_NAME_insert(st, val, i) SKM_sk_insert(X509_NAME, (st), (val), (i))
-#define sk_X509_NAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_NAME, (st), (cmp))
-#define sk_X509_NAME_dup(st) SKM_sk_dup(X509_NAME, st)
-#define sk_X509_NAME_pop_free(st, free_func) SKM_sk_pop_free(X509_NAME, (st), (free_func))
-#define sk_X509_NAME_shift(st) SKM_sk_shift(X509_NAME, (st))
-#define sk_X509_NAME_pop(st) SKM_sk_pop(X509_NAME, (st))
-#define sk_X509_NAME_sort(st) SKM_sk_sort(X509_NAME, (st))
-#define sk_X509_NAME_is_sorted(st) SKM_sk_is_sorted(X509_NAME, (st))
-
-#define sk_X509_NAME_ENTRY_new(cmp) SKM_sk_new(X509_NAME_ENTRY, (cmp))
-#define sk_X509_NAME_ENTRY_new_null() SKM_sk_new_null(X509_NAME_ENTRY)
-#define sk_X509_NAME_ENTRY_free(st) SKM_sk_free(X509_NAME_ENTRY, (st))
-#define sk_X509_NAME_ENTRY_num(st) SKM_sk_num(X509_NAME_ENTRY, (st))
-#define sk_X509_NAME_ENTRY_value(st, i) SKM_sk_value(X509_NAME_ENTRY, (st), (i))
-#define sk_X509_NAME_ENTRY_set(st, i, val) SKM_sk_set(X509_NAME_ENTRY, (st), (i), (val))
-#define sk_X509_NAME_ENTRY_zero(st) SKM_sk_zero(X509_NAME_ENTRY, (st))
-#define sk_X509_NAME_ENTRY_push(st, val) SKM_sk_push(X509_NAME_ENTRY, (st), (val))
-#define sk_X509_NAME_ENTRY_unshift(st, val) SKM_sk_unshift(X509_NAME_ENTRY, (st), (val))
-#define sk_X509_NAME_ENTRY_find(st, val) SKM_sk_find(X509_NAME_ENTRY, (st), (val))
-#define sk_X509_NAME_ENTRY_find_ex(st, val) SKM_sk_find_ex(X509_NAME_ENTRY, (st), (val))
-#define sk_X509_NAME_ENTRY_delete(st, i) SKM_sk_delete(X509_NAME_ENTRY, (st), (i))
-#define sk_X509_NAME_ENTRY_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_NAME_ENTRY, (st), (ptr))
-#define sk_X509_NAME_ENTRY_insert(st, val, i) SKM_sk_insert(X509_NAME_ENTRY, (st), (val), (i))
-#define sk_X509_NAME_ENTRY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_NAME_ENTRY, (st), (cmp))
-#define sk_X509_NAME_ENTRY_dup(st) SKM_sk_dup(X509_NAME_ENTRY, st)
-#define sk_X509_NAME_ENTRY_pop_free(st, free_func) SKM_sk_pop_free(X509_NAME_ENTRY, (st), (free_func))
-#define sk_X509_NAME_ENTRY_shift(st) SKM_sk_shift(X509_NAME_ENTRY, (st))
-#define sk_X509_NAME_ENTRY_pop(st) SKM_sk_pop(X509_NAME_ENTRY, (st))
-#define sk_X509_NAME_ENTRY_sort(st) SKM_sk_sort(X509_NAME_ENTRY, (st))
-#define sk_X509_NAME_ENTRY_is_sorted(st) SKM_sk_is_sorted(X509_NAME_ENTRY, (st))
-
-#define sk_X509_OBJECT_new(cmp) SKM_sk_new(X509_OBJECT, (cmp))
-#define sk_X509_OBJECT_new_null() SKM_sk_new_null(X509_OBJECT)
-#define sk_X509_OBJECT_free(st) SKM_sk_free(X509_OBJECT, (st))
-#define sk_X509_OBJECT_num(st) SKM_sk_num(X509_OBJECT, (st))
-#define sk_X509_OBJECT_value(st, i) SKM_sk_value(X509_OBJECT, (st), (i))
-#define sk_X509_OBJECT_set(st, i, val) SKM_sk_set(X509_OBJECT, (st), (i), (val))
-#define sk_X509_OBJECT_zero(st) SKM_sk_zero(X509_OBJECT, (st))
-#define sk_X509_OBJECT_push(st, val) SKM_sk_push(X509_OBJECT, (st), (val))
-#define sk_X509_OBJECT_unshift(st, val) SKM_sk_unshift(X509_OBJECT, (st), (val))
-#define sk_X509_OBJECT_find(st, val) SKM_sk_find(X509_OBJECT, (st), (val))
-#define sk_X509_OBJECT_find_ex(st, val) SKM_sk_find_ex(X509_OBJECT, (st), (val))
-#define sk_X509_OBJECT_delete(st, i) SKM_sk_delete(X509_OBJECT, (st), (i))
-#define sk_X509_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_OBJECT, (st), (ptr))
-#define sk_X509_OBJECT_insert(st, val, i) SKM_sk_insert(X509_OBJECT, (st), (val), (i))
-#define sk_X509_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_OBJECT, (st), (cmp))
-#define sk_X509_OBJECT_dup(st) SKM_sk_dup(X509_OBJECT, st)
-#define sk_X509_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(X509_OBJECT, (st), (free_func))
-#define sk_X509_OBJECT_shift(st) SKM_sk_shift(X509_OBJECT, (st))
-#define sk_X509_OBJECT_pop(st) SKM_sk_pop(X509_OBJECT, (st))
-#define sk_X509_OBJECT_sort(st) SKM_sk_sort(X509_OBJECT, (st))
-#define sk_X509_OBJECT_is_sorted(st) SKM_sk_is_sorted(X509_OBJECT, (st))
-
-#define sk_X509_POLICY_DATA_new(cmp) SKM_sk_new(X509_POLICY_DATA, (cmp))
-#define sk_X509_POLICY_DATA_new_null() SKM_sk_new_null(X509_POLICY_DATA)
-#define sk_X509_POLICY_DATA_free(st) SKM_sk_free(X509_POLICY_DATA, (st))
-#define sk_X509_POLICY_DATA_num(st) SKM_sk_num(X509_POLICY_DATA, (st))
-#define sk_X509_POLICY_DATA_value(st, i) SKM_sk_value(X509_POLICY_DATA, (st), (i))
-#define sk_X509_POLICY_DATA_set(st, i, val) SKM_sk_set(X509_POLICY_DATA, (st), (i), (val))
-#define sk_X509_POLICY_DATA_zero(st) SKM_sk_zero(X509_POLICY_DATA, (st))
-#define sk_X509_POLICY_DATA_push(st, val) SKM_sk_push(X509_POLICY_DATA, (st), (val))
-#define sk_X509_POLICY_DATA_unshift(st, val) SKM_sk_unshift(X509_POLICY_DATA, (st), (val))
-#define sk_X509_POLICY_DATA_find(st, val) SKM_sk_find(X509_POLICY_DATA, (st), (val))
-#define sk_X509_POLICY_DATA_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_DATA, (st), (val))
-#define sk_X509_POLICY_DATA_delete(st, i) SKM_sk_delete(X509_POLICY_DATA, (st), (i))
-#define sk_X509_POLICY_DATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_DATA, (st), (ptr))
-#define sk_X509_POLICY_DATA_insert(st, val, i) SKM_sk_insert(X509_POLICY_DATA, (st), (val), (i))
-#define sk_X509_POLICY_DATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_DATA, (st), (cmp))
-#define sk_X509_POLICY_DATA_dup(st) SKM_sk_dup(X509_POLICY_DATA, st)
-#define sk_X509_POLICY_DATA_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_DATA, (st), (free_func))
-#define sk_X509_POLICY_DATA_shift(st) SKM_sk_shift(X509_POLICY_DATA, (st))
-#define sk_X509_POLICY_DATA_pop(st) SKM_sk_pop(X509_POLICY_DATA, (st))
-#define sk_X509_POLICY_DATA_sort(st) SKM_sk_sort(X509_POLICY_DATA, (st))
-#define sk_X509_POLICY_DATA_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_DATA, (st))
-
-#define sk_X509_POLICY_NODE_new(cmp) SKM_sk_new(X509_POLICY_NODE, (cmp))
-#define sk_X509_POLICY_NODE_new_null() SKM_sk_new_null(X509_POLICY_NODE)
-#define sk_X509_POLICY_NODE_free(st) SKM_sk_free(X509_POLICY_NODE, (st))
-#define sk_X509_POLICY_NODE_num(st) SKM_sk_num(X509_POLICY_NODE, (st))
-#define sk_X509_POLICY_NODE_value(st, i) SKM_sk_value(X509_POLICY_NODE, (st), (i))
-#define sk_X509_POLICY_NODE_set(st, i, val) SKM_sk_set(X509_POLICY_NODE, (st), (i), (val))
-#define sk_X509_POLICY_NODE_zero(st) SKM_sk_zero(X509_POLICY_NODE, (st))
-#define sk_X509_POLICY_NODE_push(st, val) SKM_sk_push(X509_POLICY_NODE, (st), (val))
-#define sk_X509_POLICY_NODE_unshift(st, val) SKM_sk_unshift(X509_POLICY_NODE, (st), (val))
-#define sk_X509_POLICY_NODE_find(st, val) SKM_sk_find(X509_POLICY_NODE, (st), (val))
-#define sk_X509_POLICY_NODE_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_NODE, (st), (val))
-#define sk_X509_POLICY_NODE_delete(st, i) SKM_sk_delete(X509_POLICY_NODE, (st), (i))
-#define sk_X509_POLICY_NODE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_NODE, (st), (ptr))
-#define sk_X509_POLICY_NODE_insert(st, val, i) SKM_sk_insert(X509_POLICY_NODE, (st), (val), (i))
-#define sk_X509_POLICY_NODE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_NODE, (st), (cmp))
-#define sk_X509_POLICY_NODE_dup(st) SKM_sk_dup(X509_POLICY_NODE, st)
-#define sk_X509_POLICY_NODE_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_NODE, (st), (free_func))
-#define sk_X509_POLICY_NODE_shift(st) SKM_sk_shift(X509_POLICY_NODE, (st))
-#define sk_X509_POLICY_NODE_pop(st) SKM_sk_pop(X509_POLICY_NODE, (st))
-#define sk_X509_POLICY_NODE_sort(st) SKM_sk_sort(X509_POLICY_NODE, (st))
-#define sk_X509_POLICY_NODE_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_NODE, (st))
-
-#define sk_X509_PURPOSE_new(cmp) SKM_sk_new(X509_PURPOSE, (cmp))
-#define sk_X509_PURPOSE_new_null() SKM_sk_new_null(X509_PURPOSE)
-#define sk_X509_PURPOSE_free(st) SKM_sk_free(X509_PURPOSE, (st))
-#define sk_X509_PURPOSE_num(st) SKM_sk_num(X509_PURPOSE, (st))
-#define sk_X509_PURPOSE_value(st, i) SKM_sk_value(X509_PURPOSE, (st), (i))
-#define sk_X509_PURPOSE_set(st, i, val) SKM_sk_set(X509_PURPOSE, (st), (i), (val))
-#define sk_X509_PURPOSE_zero(st) SKM_sk_zero(X509_PURPOSE, (st))
-#define sk_X509_PURPOSE_push(st, val) SKM_sk_push(X509_PURPOSE, (st), (val))
-#define sk_X509_PURPOSE_unshift(st, val) SKM_sk_unshift(X509_PURPOSE, (st), (val))
-#define sk_X509_PURPOSE_find(st, val) SKM_sk_find(X509_PURPOSE, (st), (val))
-#define sk_X509_PURPOSE_find_ex(st, val) SKM_sk_find_ex(X509_PURPOSE, (st), (val))
-#define sk_X509_PURPOSE_delete(st, i) SKM_sk_delete(X509_PURPOSE, (st), (i))
-#define sk_X509_PURPOSE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_PURPOSE, (st), (ptr))
-#define sk_X509_PURPOSE_insert(st, val, i) SKM_sk_insert(X509_PURPOSE, (st), (val), (i))
-#define sk_X509_PURPOSE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_PURPOSE, (st), (cmp))
-#define sk_X509_PURPOSE_dup(st) SKM_sk_dup(X509_PURPOSE, st)
-#define sk_X509_PURPOSE_pop_free(st, free_func) SKM_sk_pop_free(X509_PURPOSE, (st), (free_func))
-#define sk_X509_PURPOSE_shift(st) SKM_sk_shift(X509_PURPOSE, (st))
-#define sk_X509_PURPOSE_pop(st) SKM_sk_pop(X509_PURPOSE, (st))
-#define sk_X509_PURPOSE_sort(st) SKM_sk_sort(X509_PURPOSE, (st))
-#define sk_X509_PURPOSE_is_sorted(st) SKM_sk_is_sorted(X509_PURPOSE, (st))
-
-#define sk_X509_REVOKED_new(cmp) SKM_sk_new(X509_REVOKED, (cmp))
-#define sk_X509_REVOKED_new_null() SKM_sk_new_null(X509_REVOKED)
-#define sk_X509_REVOKED_free(st) SKM_sk_free(X509_REVOKED, (st))
-#define sk_X509_REVOKED_num(st) SKM_sk_num(X509_REVOKED, (st))
-#define sk_X509_REVOKED_value(st, i) SKM_sk_value(X509_REVOKED, (st), (i))
-#define sk_X509_REVOKED_set(st, i, val) SKM_sk_set(X509_REVOKED, (st), (i), (val))
-#define sk_X509_REVOKED_zero(st) SKM_sk_zero(X509_REVOKED, (st))
-#define sk_X509_REVOKED_push(st, val) SKM_sk_push(X509_REVOKED, (st), (val))
-#define sk_X509_REVOKED_unshift(st, val) SKM_sk_unshift(X509_REVOKED, (st), (val))
-#define sk_X509_REVOKED_find(st, val) SKM_sk_find(X509_REVOKED, (st), (val))
-#define sk_X509_REVOKED_find_ex(st, val) SKM_sk_find_ex(X509_REVOKED, (st), (val))
-#define sk_X509_REVOKED_delete(st, i) SKM_sk_delete(X509_REVOKED, (st), (i))
-#define sk_X509_REVOKED_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_REVOKED, (st), (ptr))
-#define sk_X509_REVOKED_insert(st, val, i) SKM_sk_insert(X509_REVOKED, (st), (val), (i))
-#define sk_X509_REVOKED_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_REVOKED, (st), (cmp))
-#define sk_X509_REVOKED_dup(st) SKM_sk_dup(X509_REVOKED, st)
-#define sk_X509_REVOKED_pop_free(st, free_func) SKM_sk_pop_free(X509_REVOKED, (st), (free_func))
-#define sk_X509_REVOKED_shift(st) SKM_sk_shift(X509_REVOKED, (st))
-#define sk_X509_REVOKED_pop(st) SKM_sk_pop(X509_REVOKED, (st))
-#define sk_X509_REVOKED_sort(st) SKM_sk_sort(X509_REVOKED, (st))
-#define sk_X509_REVOKED_is_sorted(st) SKM_sk_is_sorted(X509_REVOKED, (st))
-
-#define sk_X509_TRUST_new(cmp) SKM_sk_new(X509_TRUST, (cmp))
-#define sk_X509_TRUST_new_null() SKM_sk_new_null(X509_TRUST)
-#define sk_X509_TRUST_free(st) SKM_sk_free(X509_TRUST, (st))
-#define sk_X509_TRUST_num(st) SKM_sk_num(X509_TRUST, (st))
-#define sk_X509_TRUST_value(st, i) SKM_sk_value(X509_TRUST, (st), (i))
-#define sk_X509_TRUST_set(st, i, val) SKM_sk_set(X509_TRUST, (st), (i), (val))
-#define sk_X509_TRUST_zero(st) SKM_sk_zero(X509_TRUST, (st))
-#define sk_X509_TRUST_push(st, val) SKM_sk_push(X509_TRUST, (st), (val))
-#define sk_X509_TRUST_unshift(st, val) SKM_sk_unshift(X509_TRUST, (st), (val))
-#define sk_X509_TRUST_find(st, val) SKM_sk_find(X509_TRUST, (st), (val))
-#define sk_X509_TRUST_find_ex(st, val) SKM_sk_find_ex(X509_TRUST, (st), (val))
-#define sk_X509_TRUST_delete(st, i) SKM_sk_delete(X509_TRUST, (st), (i))
-#define sk_X509_TRUST_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_TRUST, (st), (ptr))
-#define sk_X509_TRUST_insert(st, val, i) SKM_sk_insert(X509_TRUST, (st), (val), (i))
-#define sk_X509_TRUST_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_TRUST, (st), (cmp))
-#define sk_X509_TRUST_dup(st) SKM_sk_dup(X509_TRUST, st)
-#define sk_X509_TRUST_pop_free(st, free_func) SKM_sk_pop_free(X509_TRUST, (st), (free_func))
-#define sk_X509_TRUST_shift(st) SKM_sk_shift(X509_TRUST, (st))
-#define sk_X509_TRUST_pop(st) SKM_sk_pop(X509_TRUST, (st))
-#define sk_X509_TRUST_sort(st) SKM_sk_sort(X509_TRUST, (st))
-#define sk_X509_TRUST_is_sorted(st) SKM_sk_is_sorted(X509_TRUST, (st))
-
-#define sk_X509_VERIFY_PARAM_new(cmp) SKM_sk_new(X509_VERIFY_PARAM, (cmp))
-#define sk_X509_VERIFY_PARAM_new_null() SKM_sk_new_null(X509_VERIFY_PARAM)
-#define sk_X509_VERIFY_PARAM_free(st) SKM_sk_free(X509_VERIFY_PARAM, (st))
-#define sk_X509_VERIFY_PARAM_num(st) SKM_sk_num(X509_VERIFY_PARAM, (st))
-#define sk_X509_VERIFY_PARAM_value(st, i) SKM_sk_value(X509_VERIFY_PARAM, (st), (i))
-#define sk_X509_VERIFY_PARAM_set(st, i, val) SKM_sk_set(X509_VERIFY_PARAM, (st), (i), (val))
-#define sk_X509_VERIFY_PARAM_zero(st) SKM_sk_zero(X509_VERIFY_PARAM, (st))
-#define sk_X509_VERIFY_PARAM_push(st, val) SKM_sk_push(X509_VERIFY_PARAM, (st), (val))
-#define sk_X509_VERIFY_PARAM_unshift(st, val) SKM_sk_unshift(X509_VERIFY_PARAM, (st), (val))
-#define sk_X509_VERIFY_PARAM_find(st, val) SKM_sk_find(X509_VERIFY_PARAM, (st), (val))
-#define sk_X509_VERIFY_PARAM_find_ex(st, val) SKM_sk_find_ex(X509_VERIFY_PARAM, (st), (val))
-#define sk_X509_VERIFY_PARAM_delete(st, i) SKM_sk_delete(X509_VERIFY_PARAM, (st), (i))
-#define sk_X509_VERIFY_PARAM_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_VERIFY_PARAM, (st), (ptr))
-#define sk_X509_VERIFY_PARAM_insert(st, val, i) SKM_sk_insert(X509_VERIFY_PARAM, (st), (val), (i))
-#define sk_X509_VERIFY_PARAM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_VERIFY_PARAM, (st), (cmp))
-#define sk_X509_VERIFY_PARAM_dup(st) SKM_sk_dup(X509_VERIFY_PARAM, st)
-#define sk_X509_VERIFY_PARAM_pop_free(st, free_func) SKM_sk_pop_free(X509_VERIFY_PARAM, (st), (free_func))
-#define sk_X509_VERIFY_PARAM_shift(st) SKM_sk_shift(X509_VERIFY_PARAM, (st))
-#define sk_X509_VERIFY_PARAM_pop(st) SKM_sk_pop(X509_VERIFY_PARAM, (st))
-#define sk_X509_VERIFY_PARAM_sort(st) SKM_sk_sort(X509_VERIFY_PARAM, (st))
-#define sk_X509_VERIFY_PARAM_is_sorted(st) SKM_sk_is_sorted(X509_VERIFY_PARAM, (st))
-
-#define sk_nid_triple_new(cmp) SKM_sk_new(nid_triple, (cmp))
-#define sk_nid_triple_new_null() SKM_sk_new_null(nid_triple)
-#define sk_nid_triple_free(st) SKM_sk_free(nid_triple, (st))
-#define sk_nid_triple_num(st) SKM_sk_num(nid_triple, (st))
-#define sk_nid_triple_value(st, i) SKM_sk_value(nid_triple, (st), (i))
-#define sk_nid_triple_set(st, i, val) SKM_sk_set(nid_triple, (st), (i), (val))
-#define sk_nid_triple_zero(st) SKM_sk_zero(nid_triple, (st))
-#define sk_nid_triple_push(st, val) SKM_sk_push(nid_triple, (st), (val))
-#define sk_nid_triple_unshift(st, val) SKM_sk_unshift(nid_triple, (st), (val))
-#define sk_nid_triple_find(st, val) SKM_sk_find(nid_triple, (st), (val))
-#define sk_nid_triple_find_ex(st, val) SKM_sk_find_ex(nid_triple, (st), (val))
-#define sk_nid_triple_delete(st, i) SKM_sk_delete(nid_triple, (st), (i))
-#define sk_nid_triple_delete_ptr(st, ptr) SKM_sk_delete_ptr(nid_triple, (st), (ptr))
-#define sk_nid_triple_insert(st, val, i) SKM_sk_insert(nid_triple, (st), (val), (i))
-#define sk_nid_triple_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(nid_triple, (st), (cmp))
-#define sk_nid_triple_dup(st) SKM_sk_dup(nid_triple, st)
-#define sk_nid_triple_pop_free(st, free_func) SKM_sk_pop_free(nid_triple, (st), (free_func))
-#define sk_nid_triple_shift(st) SKM_sk_shift(nid_triple, (st))
-#define sk_nid_triple_pop(st) SKM_sk_pop(nid_triple, (st))
-#define sk_nid_triple_sort(st) SKM_sk_sort(nid_triple, (st))
-#define sk_nid_triple_is_sorted(st) SKM_sk_is_sorted(nid_triple, (st))
-
-#define sk_void_new(cmp) SKM_sk_new(void, (cmp))
-#define sk_void_new_null() SKM_sk_new_null(void)
-#define sk_void_free(st) SKM_sk_free(void, (st))
-#define sk_void_num(st) SKM_sk_num(void, (st))
-#define sk_void_value(st, i) SKM_sk_value(void, (st), (i))
-#define sk_void_set(st, i, val) SKM_sk_set(void, (st), (i), (val))
-#define sk_void_zero(st) SKM_sk_zero(void, (st))
-#define sk_void_push(st, val) SKM_sk_push(void, (st), (val))
-#define sk_void_unshift(st, val) SKM_sk_unshift(void, (st), (val))
-#define sk_void_find(st, val) SKM_sk_find(void, (st), (val))
-#define sk_void_find_ex(st, val) SKM_sk_find_ex(void, (st), (val))
-#define sk_void_delete(st, i) SKM_sk_delete(void, (st), (i))
-#define sk_void_delete_ptr(st, ptr) SKM_sk_delete_ptr(void, (st), (ptr))
-#define sk_void_insert(st, val, i) SKM_sk_insert(void, (st), (val), (i))
-#define sk_void_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(void, (st), (cmp))
-#define sk_void_dup(st) SKM_sk_dup(void, st)
-#define sk_void_pop_free(st, free_func) SKM_sk_pop_free(void, (st), (free_func))
-#define sk_void_shift(st) SKM_sk_shift(void, (st))
-#define sk_void_pop(st) SKM_sk_pop(void, (st))
-#define sk_void_sort(st) SKM_sk_sort(void, (st))
-#define sk_void_is_sorted(st) SKM_sk_is_sorted(void, (st))
-
-#define sk_OPENSSL_STRING_new(cmp) ((STACK_OF(OPENSSL_STRING) *)sk_new(CHECKED_SK_CMP_FUNC(char, cmp)))
-#define sk_OPENSSL_STRING_new_null() ((STACK_OF(OPENSSL_STRING) *)sk_new_null())
-#define sk_OPENSSL_STRING_push(st, val) sk_push(CHECKED_STACK_OF(OPENSSL_STRING, st), CHECKED_PTR_OF(char, val))
-#define sk_OPENSSL_STRING_find(st, val) sk_find(CHECKED_STACK_OF(OPENSSL_STRING, st), CHECKED_PTR_OF(char, val))
-#define sk_OPENSSL_STRING_value(st, i) ((OPENSSL_STRING)sk_value(CHECKED_STACK_OF(OPENSSL_STRING, st), i))
-#define sk_OPENSSL_STRING_num(st) SKM_sk_num(OPENSSL_STRING, st)
-#define sk_OPENSSL_STRING_pop_free(st, free_func) sk_pop_free(CHECKED_STACK_OF(OPENSSL_STRING, st), CHECKED_SK_FREE_FUNC2(OPENSSL_STRING, free_func))
-#define sk_OPENSSL_STRING_insert(st, val, i) sk_insert(CHECKED_STACK_OF(OPENSSL_STRING, st), CHECKED_PTR_OF(char, val), i)
-#define sk_OPENSSL_STRING_free(st) SKM_sk_free(OPENSSL_STRING, st)
-#define sk_OPENSSL_STRING_set(st, i, val) sk_set(CHECKED_STACK_OF(OPENSSL_STRING, st), i, CHECKED_PTR_OF(char, val))
-#define sk_OPENSSL_STRING_zero(st) SKM_sk_zero(OPENSSL_STRING, (st))
-#define sk_OPENSSL_STRING_unshift(st, val) sk_unshift(CHECKED_STACK_OF(OPENSSL_STRING, st), CHECKED_PTR_OF(char, val))
-#define sk_OPENSSL_STRING_find_ex(st, val) sk_find_ex((_STACK *)CHECKED_CONST_PTR_OF(STACK_OF(OPENSSL_STRING), st), CHECKED_CONST_PTR_OF(char, val))
-#define sk_OPENSSL_STRING_delete(st, i) SKM_sk_delete(OPENSSL_STRING, (st), (i))
-#define sk_OPENSSL_STRING_delete_ptr(st, ptr) (OPENSSL_STRING *)sk_delete_ptr(CHECKED_STACK_OF(OPENSSL_STRING, st), CHECKED_PTR_OF(char, ptr))
-#define sk_OPENSSL_STRING_set_cmp_func(st, cmp) \
- ((int (*)(const char * const *,const char * const *)) \
- sk_set_cmp_func(CHECKED_STACK_OF(OPENSSL_STRING, st), CHECKED_SK_CMP_FUNC(char, cmp)))
-#define sk_OPENSSL_STRING_dup(st) SKM_sk_dup(OPENSSL_STRING, st)
-#define sk_OPENSSL_STRING_shift(st) SKM_sk_shift(OPENSSL_STRING, (st))
-#define sk_OPENSSL_STRING_pop(st) (char *)sk_pop(CHECKED_STACK_OF(OPENSSL_STRING, st))
-#define sk_OPENSSL_STRING_sort(st) SKM_sk_sort(OPENSSL_STRING, (st))
-#define sk_OPENSSL_STRING_is_sorted(st) SKM_sk_is_sorted(OPENSSL_STRING, (st))
-
-
-#define sk_OPENSSL_BLOCK_new(cmp) ((STACK_OF(OPENSSL_BLOCK) *)sk_new(CHECKED_SK_CMP_FUNC(void, cmp)))
-#define sk_OPENSSL_BLOCK_new_null() ((STACK_OF(OPENSSL_BLOCK) *)sk_new_null())
-#define sk_OPENSSL_BLOCK_push(st, val) sk_push(CHECKED_STACK_OF(OPENSSL_BLOCK, st), CHECKED_PTR_OF(void, val))
-#define sk_OPENSSL_BLOCK_find(st, val) sk_find(CHECKED_STACK_OF(OPENSSL_BLOCK, st), CHECKED_PTR_OF(void, val))
-#define sk_OPENSSL_BLOCK_value(st, i) ((OPENSSL_BLOCK)sk_value(CHECKED_STACK_OF(OPENSSL_BLOCK, st), i))
-#define sk_OPENSSL_BLOCK_num(st) SKM_sk_num(OPENSSL_BLOCK, st)
-#define sk_OPENSSL_BLOCK_pop_free(st, free_func) sk_pop_free(CHECKED_STACK_OF(OPENSSL_BLOCK, st), CHECKED_SK_FREE_FUNC2(OPENSSL_BLOCK, free_func))
-#define sk_OPENSSL_BLOCK_insert(st, val, i) sk_insert(CHECKED_STACK_OF(OPENSSL_BLOCK, st), CHECKED_PTR_OF(void, val), i)
-#define sk_OPENSSL_BLOCK_free(st) SKM_sk_free(OPENSSL_BLOCK, st)
-#define sk_OPENSSL_BLOCK_set(st, i, val) sk_set(CHECKED_STACK_OF(OPENSSL_BLOCK, st), i, CHECKED_PTR_OF(void, val))
-#define sk_OPENSSL_BLOCK_zero(st) SKM_sk_zero(OPENSSL_BLOCK, (st))
-#define sk_OPENSSL_BLOCK_unshift(st, val) sk_unshift(CHECKED_STACK_OF(OPENSSL_BLOCK, st), CHECKED_PTR_OF(void, val))
-#define sk_OPENSSL_BLOCK_find_ex(st, val) sk_find_ex((_STACK *)CHECKED_CONST_PTR_OF(STACK_OF(OPENSSL_BLOCK), st), CHECKED_CONST_PTR_OF(void, val))
-#define sk_OPENSSL_BLOCK_delete(st, i) SKM_sk_delete(OPENSSL_BLOCK, (st), (i))
-#define sk_OPENSSL_BLOCK_delete_ptr(st, ptr) (OPENSSL_BLOCK *)sk_delete_ptr(CHECKED_STACK_OF(OPENSSL_BLOCK, st), CHECKED_PTR_OF(void, ptr))
-#define sk_OPENSSL_BLOCK_set_cmp_func(st, cmp) \
- ((int (*)(const void * const *,const void * const *)) \
- sk_set_cmp_func(CHECKED_STACK_OF(OPENSSL_BLOCK, st), CHECKED_SK_CMP_FUNC(void, cmp)))
-#define sk_OPENSSL_BLOCK_dup(st) SKM_sk_dup(OPENSSL_BLOCK, st)
-#define sk_OPENSSL_BLOCK_shift(st) SKM_sk_shift(OPENSSL_BLOCK, (st))
-#define sk_OPENSSL_BLOCK_pop(st) (void *)sk_pop(CHECKED_STACK_OF(OPENSSL_BLOCK, st))
-#define sk_OPENSSL_BLOCK_sort(st) SKM_sk_sort(OPENSSL_BLOCK, (st))
-#define sk_OPENSSL_BLOCK_is_sorted(st) SKM_sk_is_sorted(OPENSSL_BLOCK, (st))
-
-
-#define sk_OPENSSL_PSTRING_new(cmp) ((STACK_OF(OPENSSL_PSTRING) *)sk_new(CHECKED_SK_CMP_FUNC(OPENSSL_STRING, cmp)))
-#define sk_OPENSSL_PSTRING_new_null() ((STACK_OF(OPENSSL_PSTRING) *)sk_new_null())
-#define sk_OPENSSL_PSTRING_push(st, val) sk_push(CHECKED_STACK_OF(OPENSSL_PSTRING, st), CHECKED_PTR_OF(OPENSSL_STRING, val))
-#define sk_OPENSSL_PSTRING_find(st, val) sk_find(CHECKED_STACK_OF(OPENSSL_PSTRING, st), CHECKED_PTR_OF(OPENSSL_STRING, val))
-#define sk_OPENSSL_PSTRING_value(st, i) ((OPENSSL_PSTRING)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, st), i))
-#define sk_OPENSSL_PSTRING_num(st) SKM_sk_num(OPENSSL_PSTRING, st)
-#define sk_OPENSSL_PSTRING_pop_free(st, free_func) sk_pop_free(CHECKED_STACK_OF(OPENSSL_PSTRING, st), CHECKED_SK_FREE_FUNC2(OPENSSL_PSTRING, free_func))
-#define sk_OPENSSL_PSTRING_insert(st, val, i) sk_insert(CHECKED_STACK_OF(OPENSSL_PSTRING, st), CHECKED_PTR_OF(OPENSSL_STRING, val), i)
-#define sk_OPENSSL_PSTRING_free(st) SKM_sk_free(OPENSSL_PSTRING, st)
-#define sk_OPENSSL_PSTRING_set(st, i, val) sk_set(CHECKED_STACK_OF(OPENSSL_PSTRING, st), i, CHECKED_PTR_OF(OPENSSL_STRING, val))
-#define sk_OPENSSL_PSTRING_zero(st) SKM_sk_zero(OPENSSL_PSTRING, (st))
-#define sk_OPENSSL_PSTRING_unshift(st, val) sk_unshift(CHECKED_STACK_OF(OPENSSL_PSTRING, st), CHECKED_PTR_OF(OPENSSL_STRING, val))
-#define sk_OPENSSL_PSTRING_find_ex(st, val) sk_find_ex((_STACK *)CHECKED_CONST_PTR_OF(STACK_OF(OPENSSL_PSTRING), st), CHECKED_CONST_PTR_OF(OPENSSL_STRING, val))
-#define sk_OPENSSL_PSTRING_delete(st, i) SKM_sk_delete(OPENSSL_PSTRING, (st), (i))
-#define sk_OPENSSL_PSTRING_delete_ptr(st, ptr) (OPENSSL_PSTRING *)sk_delete_ptr(CHECKED_STACK_OF(OPENSSL_PSTRING, st), CHECKED_PTR_OF(OPENSSL_STRING, ptr))
-#define sk_OPENSSL_PSTRING_set_cmp_func(st, cmp) \
- ((int (*)(const OPENSSL_STRING * const *,const OPENSSL_STRING * const *)) \
- sk_set_cmp_func(CHECKED_STACK_OF(OPENSSL_PSTRING, st), CHECKED_SK_CMP_FUNC(OPENSSL_STRING, cmp)))
-#define sk_OPENSSL_PSTRING_dup(st) SKM_sk_dup(OPENSSL_PSTRING, st)
-#define sk_OPENSSL_PSTRING_shift(st) SKM_sk_shift(OPENSSL_PSTRING, (st))
-#define sk_OPENSSL_PSTRING_pop(st) (OPENSSL_STRING *)sk_pop(CHECKED_STACK_OF(OPENSSL_PSTRING, st))
-#define sk_OPENSSL_PSTRING_sort(st) SKM_sk_sort(OPENSSL_PSTRING, (st))
-#define sk_OPENSSL_PSTRING_is_sorted(st) SKM_sk_is_sorted(OPENSSL_PSTRING, (st))
-
-
-#define d2i_ASN1_SET_OF_ACCESS_DESCRIPTION(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(ACCESS_DESCRIPTION, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_ACCESS_DESCRIPTION(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(ACCESS_DESCRIPTION, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_ACCESS_DESCRIPTION(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(ACCESS_DESCRIPTION, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_ACCESS_DESCRIPTION(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(ACCESS_DESCRIPTION, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_ASN1_INTEGER(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(ASN1_INTEGER, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_ASN1_INTEGER(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(ASN1_INTEGER, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_ASN1_INTEGER(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(ASN1_INTEGER, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_ASN1_INTEGER(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(ASN1_INTEGER, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_ASN1_OBJECT(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(ASN1_OBJECT, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_ASN1_OBJECT(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(ASN1_OBJECT, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_ASN1_OBJECT(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(ASN1_OBJECT, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_ASN1_OBJECT(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(ASN1_OBJECT, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_ASN1_TYPE(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(ASN1_TYPE, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_ASN1_TYPE(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(ASN1_TYPE, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_ASN1_TYPE(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(ASN1_TYPE, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_ASN1_TYPE(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(ASN1_TYPE, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_ASN1_UTF8STRING(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(ASN1_UTF8STRING, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_ASN1_UTF8STRING(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(ASN1_UTF8STRING, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_ASN1_UTF8STRING(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(ASN1_UTF8STRING, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_ASN1_UTF8STRING(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(ASN1_UTF8STRING, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_DIST_POINT(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(DIST_POINT, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_DIST_POINT(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(DIST_POINT, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_DIST_POINT(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(DIST_POINT, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_DIST_POINT(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(DIST_POINT, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_ESS_CERT_ID(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(ESS_CERT_ID, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_ESS_CERT_ID(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(ESS_CERT_ID, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_ESS_CERT_ID(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(ESS_CERT_ID, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_ESS_CERT_ID(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(ESS_CERT_ID, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_EVP_MD(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(EVP_MD, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_EVP_MD(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(EVP_MD, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_EVP_MD(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(EVP_MD, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_EVP_MD(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(EVP_MD, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_GENERAL_NAME(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(GENERAL_NAME, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_GENERAL_NAME(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(GENERAL_NAME, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_GENERAL_NAME(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(GENERAL_NAME, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_GENERAL_NAME(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(GENERAL_NAME, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_OCSP_ONEREQ(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(OCSP_ONEREQ, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_OCSP_ONEREQ(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(OCSP_ONEREQ, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_OCSP_ONEREQ(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(OCSP_ONEREQ, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_OCSP_ONEREQ(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(OCSP_ONEREQ, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_OCSP_SINGLERESP(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(OCSP_SINGLERESP, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_OCSP_SINGLERESP(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(OCSP_SINGLERESP, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_OCSP_SINGLERESP(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(OCSP_SINGLERESP, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_OCSP_SINGLERESP(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(OCSP_SINGLERESP, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_PKCS12_SAFEBAG(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(PKCS12_SAFEBAG, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_PKCS12_SAFEBAG(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(PKCS12_SAFEBAG, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_PKCS12_SAFEBAG(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(PKCS12_SAFEBAG, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_PKCS12_SAFEBAG(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(PKCS12_SAFEBAG, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_PKCS7(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(PKCS7, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_PKCS7(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(PKCS7, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_PKCS7(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(PKCS7, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_PKCS7(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(PKCS7, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_PKCS7_RECIP_INFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(PKCS7_RECIP_INFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_PKCS7_RECIP_INFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(PKCS7_RECIP_INFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_PKCS7_RECIP_INFO(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(PKCS7_RECIP_INFO, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_PKCS7_RECIP_INFO(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(PKCS7_RECIP_INFO, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(PKCS7_SIGNER_INFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(PKCS7_SIGNER_INFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_PKCS7_SIGNER_INFO(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(PKCS7_SIGNER_INFO, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_PKCS7_SIGNER_INFO(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(PKCS7_SIGNER_INFO, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_POLICYINFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(POLICYINFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_POLICYINFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(POLICYINFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_POLICYINFO(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(POLICYINFO, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_POLICYINFO(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(POLICYINFO, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_POLICYQUALINFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(POLICYQUALINFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_POLICYQUALINFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(POLICYQUALINFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_POLICYQUALINFO(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(POLICYQUALINFO, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_POLICYQUALINFO(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(POLICYQUALINFO, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_SXNETID(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(SXNETID, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_SXNETID(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(SXNETID, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_SXNETID(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(SXNETID, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_SXNETID(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(SXNETID, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_X509(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(X509, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_X509(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(X509, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_X509(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(X509, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_X509(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(X509, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_X509_ALGOR(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(X509_ALGOR, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_X509_ALGOR(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(X509_ALGOR, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_X509_ALGOR(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(X509_ALGOR, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_X509_ALGOR(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(X509_ALGOR, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_X509_ATTRIBUTE(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(X509_ATTRIBUTE, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_X509_ATTRIBUTE(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(X509_ATTRIBUTE, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_X509_ATTRIBUTE(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(X509_ATTRIBUTE, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_X509_ATTRIBUTE(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(X509_ATTRIBUTE, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_X509_CRL(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(X509_CRL, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_X509_CRL(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(X509_CRL, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_X509_CRL(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(X509_CRL, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_X509_CRL(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(X509_CRL, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_X509_EXTENSION(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(X509_EXTENSION, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_X509_EXTENSION(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(X509_EXTENSION, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_X509_EXTENSION(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(X509_EXTENSION, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_X509_EXTENSION(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(X509_EXTENSION, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_X509_NAME_ENTRY(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(X509_NAME_ENTRY, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_X509_NAME_ENTRY(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(X509_NAME_ENTRY, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_X509_NAME_ENTRY(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(X509_NAME_ENTRY, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_X509_NAME_ENTRY(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(X509_NAME_ENTRY, (buf), (len), (d2i_func), (free_func))
-
-#define d2i_ASN1_SET_OF_X509_REVOKED(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
- SKM_ASN1_SET_OF_d2i(X509_REVOKED, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
-#define i2d_ASN1_SET_OF_X509_REVOKED(st, pp, i2d_func, ex_tag, ex_class, is_set) \
- SKM_ASN1_SET_OF_i2d(X509_REVOKED, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
-#define ASN1_seq_pack_X509_REVOKED(st, i2d_func, buf, len) \
- SKM_ASN1_seq_pack(X509_REVOKED, (st), (i2d_func), (buf), (len))
-#define ASN1_seq_unpack_X509_REVOKED(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(X509_REVOKED, (buf), (len), (d2i_func), (free_func))
-
-#define PKCS12_decrypt_d2i_PKCS12_SAFEBAG(algor, d2i_func, free_func, pass, passlen, oct, seq) \
- SKM_PKCS12_decrypt_d2i(PKCS12_SAFEBAG, (algor), (d2i_func), (free_func), (pass), (passlen), (oct), (seq))
-
-#define PKCS12_decrypt_d2i_PKCS7(algor, d2i_func, free_func, pass, passlen, oct, seq) \
- SKM_PKCS12_decrypt_d2i(PKCS7, (algor), (d2i_func), (free_func), (pass), (passlen), (oct), (seq))
-
-#define lh_ADDED_OBJ_new() LHM_lh_new(ADDED_OBJ,added_obj)
-#define lh_ADDED_OBJ_insert(lh,inst) LHM_lh_insert(ADDED_OBJ,lh,inst)
-#define lh_ADDED_OBJ_retrieve(lh,inst) LHM_lh_retrieve(ADDED_OBJ,lh,inst)
-#define lh_ADDED_OBJ_delete(lh,inst) LHM_lh_delete(ADDED_OBJ,lh,inst)
-#define lh_ADDED_OBJ_doall(lh,fn) LHM_lh_doall(ADDED_OBJ,lh,fn)
-#define lh_ADDED_OBJ_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(ADDED_OBJ,lh,fn,arg_type,arg)
-#define lh_ADDED_OBJ_error(lh) LHM_lh_error(ADDED_OBJ,lh)
-#define lh_ADDED_OBJ_num_items(lh) LHM_lh_num_items(ADDED_OBJ,lh)
-#define lh_ADDED_OBJ_down_load(lh) LHM_lh_down_load(ADDED_OBJ,lh)
-#define lh_ADDED_OBJ_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(ADDED_OBJ,lh,out)
-#define lh_ADDED_OBJ_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(ADDED_OBJ,lh,out)
-#define lh_ADDED_OBJ_stats_bio(lh,out) \
- LHM_lh_stats_bio(ADDED_OBJ,lh,out)
-#define lh_ADDED_OBJ_free(lh) LHM_lh_free(ADDED_OBJ,lh)
-
-#define lh_APP_INFO_new() LHM_lh_new(APP_INFO,app_info)
-#define lh_APP_INFO_insert(lh,inst) LHM_lh_insert(APP_INFO,lh,inst)
-#define lh_APP_INFO_retrieve(lh,inst) LHM_lh_retrieve(APP_INFO,lh,inst)
-#define lh_APP_INFO_delete(lh,inst) LHM_lh_delete(APP_INFO,lh,inst)
-#define lh_APP_INFO_doall(lh,fn) LHM_lh_doall(APP_INFO,lh,fn)
-#define lh_APP_INFO_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(APP_INFO,lh,fn,arg_type,arg)
-#define lh_APP_INFO_error(lh) LHM_lh_error(APP_INFO,lh)
-#define lh_APP_INFO_num_items(lh) LHM_lh_num_items(APP_INFO,lh)
-#define lh_APP_INFO_down_load(lh) LHM_lh_down_load(APP_INFO,lh)
-#define lh_APP_INFO_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(APP_INFO,lh,out)
-#define lh_APP_INFO_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(APP_INFO,lh,out)
-#define lh_APP_INFO_stats_bio(lh,out) \
- LHM_lh_stats_bio(APP_INFO,lh,out)
-#define lh_APP_INFO_free(lh) LHM_lh_free(APP_INFO,lh)
-
-#define lh_CONF_VALUE_new() LHM_lh_new(CONF_VALUE,conf_value)
-#define lh_CONF_VALUE_insert(lh,inst) LHM_lh_insert(CONF_VALUE,lh,inst)
-#define lh_CONF_VALUE_retrieve(lh,inst) LHM_lh_retrieve(CONF_VALUE,lh,inst)
-#define lh_CONF_VALUE_delete(lh,inst) LHM_lh_delete(CONF_VALUE,lh,inst)
-#define lh_CONF_VALUE_doall(lh,fn) LHM_lh_doall(CONF_VALUE,lh,fn)
-#define lh_CONF_VALUE_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(CONF_VALUE,lh,fn,arg_type,arg)
-#define lh_CONF_VALUE_error(lh) LHM_lh_error(CONF_VALUE,lh)
-#define lh_CONF_VALUE_num_items(lh) LHM_lh_num_items(CONF_VALUE,lh)
-#define lh_CONF_VALUE_down_load(lh) LHM_lh_down_load(CONF_VALUE,lh)
-#define lh_CONF_VALUE_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(CONF_VALUE,lh,out)
-#define lh_CONF_VALUE_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(CONF_VALUE,lh,out)
-#define lh_CONF_VALUE_stats_bio(lh,out) \
- LHM_lh_stats_bio(CONF_VALUE,lh,out)
-#define lh_CONF_VALUE_free(lh) LHM_lh_free(CONF_VALUE,lh)
-
-#define lh_ENGINE_PILE_new() LHM_lh_new(ENGINE_PILE,engine_pile)
-#define lh_ENGINE_PILE_insert(lh,inst) LHM_lh_insert(ENGINE_PILE,lh,inst)
-#define lh_ENGINE_PILE_retrieve(lh,inst) LHM_lh_retrieve(ENGINE_PILE,lh,inst)
-#define lh_ENGINE_PILE_delete(lh,inst) LHM_lh_delete(ENGINE_PILE,lh,inst)
-#define lh_ENGINE_PILE_doall(lh,fn) LHM_lh_doall(ENGINE_PILE,lh,fn)
-#define lh_ENGINE_PILE_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(ENGINE_PILE,lh,fn,arg_type,arg)
-#define lh_ENGINE_PILE_error(lh) LHM_lh_error(ENGINE_PILE,lh)
-#define lh_ENGINE_PILE_num_items(lh) LHM_lh_num_items(ENGINE_PILE,lh)
-#define lh_ENGINE_PILE_down_load(lh) LHM_lh_down_load(ENGINE_PILE,lh)
-#define lh_ENGINE_PILE_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(ENGINE_PILE,lh,out)
-#define lh_ENGINE_PILE_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(ENGINE_PILE,lh,out)
-#define lh_ENGINE_PILE_stats_bio(lh,out) \
- LHM_lh_stats_bio(ENGINE_PILE,lh,out)
-#define lh_ENGINE_PILE_free(lh) LHM_lh_free(ENGINE_PILE,lh)
-
-#define lh_ERR_STATE_new() LHM_lh_new(ERR_STATE,err_state)
-#define lh_ERR_STATE_insert(lh,inst) LHM_lh_insert(ERR_STATE,lh,inst)
-#define lh_ERR_STATE_retrieve(lh,inst) LHM_lh_retrieve(ERR_STATE,lh,inst)
-#define lh_ERR_STATE_delete(lh,inst) LHM_lh_delete(ERR_STATE,lh,inst)
-#define lh_ERR_STATE_doall(lh,fn) LHM_lh_doall(ERR_STATE,lh,fn)
-#define lh_ERR_STATE_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(ERR_STATE,lh,fn,arg_type,arg)
-#define lh_ERR_STATE_error(lh) LHM_lh_error(ERR_STATE,lh)
-#define lh_ERR_STATE_num_items(lh) LHM_lh_num_items(ERR_STATE,lh)
-#define lh_ERR_STATE_down_load(lh) LHM_lh_down_load(ERR_STATE,lh)
-#define lh_ERR_STATE_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(ERR_STATE,lh,out)
-#define lh_ERR_STATE_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(ERR_STATE,lh,out)
-#define lh_ERR_STATE_stats_bio(lh,out) \
- LHM_lh_stats_bio(ERR_STATE,lh,out)
-#define lh_ERR_STATE_free(lh) LHM_lh_free(ERR_STATE,lh)
-
-#define lh_ERR_STRING_DATA_new() LHM_lh_new(ERR_STRING_DATA,err_string_data)
-#define lh_ERR_STRING_DATA_insert(lh,inst) LHM_lh_insert(ERR_STRING_DATA,lh,inst)
-#define lh_ERR_STRING_DATA_retrieve(lh,inst) LHM_lh_retrieve(ERR_STRING_DATA,lh,inst)
-#define lh_ERR_STRING_DATA_delete(lh,inst) LHM_lh_delete(ERR_STRING_DATA,lh,inst)
-#define lh_ERR_STRING_DATA_doall(lh,fn) LHM_lh_doall(ERR_STRING_DATA,lh,fn)
-#define lh_ERR_STRING_DATA_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(ERR_STRING_DATA,lh,fn,arg_type,arg)
-#define lh_ERR_STRING_DATA_error(lh) LHM_lh_error(ERR_STRING_DATA,lh)
-#define lh_ERR_STRING_DATA_num_items(lh) LHM_lh_num_items(ERR_STRING_DATA,lh)
-#define lh_ERR_STRING_DATA_down_load(lh) LHM_lh_down_load(ERR_STRING_DATA,lh)
-#define lh_ERR_STRING_DATA_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(ERR_STRING_DATA,lh,out)
-#define lh_ERR_STRING_DATA_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(ERR_STRING_DATA,lh,out)
-#define lh_ERR_STRING_DATA_stats_bio(lh,out) \
- LHM_lh_stats_bio(ERR_STRING_DATA,lh,out)
-#define lh_ERR_STRING_DATA_free(lh) LHM_lh_free(ERR_STRING_DATA,lh)
-
-#define lh_EX_CLASS_ITEM_new() LHM_lh_new(EX_CLASS_ITEM,ex_class_item)
-#define lh_EX_CLASS_ITEM_insert(lh,inst) LHM_lh_insert(EX_CLASS_ITEM,lh,inst)
-#define lh_EX_CLASS_ITEM_retrieve(lh,inst) LHM_lh_retrieve(EX_CLASS_ITEM,lh,inst)
-#define lh_EX_CLASS_ITEM_delete(lh,inst) LHM_lh_delete(EX_CLASS_ITEM,lh,inst)
-#define lh_EX_CLASS_ITEM_doall(lh,fn) LHM_lh_doall(EX_CLASS_ITEM,lh,fn)
-#define lh_EX_CLASS_ITEM_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(EX_CLASS_ITEM,lh,fn,arg_type,arg)
-#define lh_EX_CLASS_ITEM_error(lh) LHM_lh_error(EX_CLASS_ITEM,lh)
-#define lh_EX_CLASS_ITEM_num_items(lh) LHM_lh_num_items(EX_CLASS_ITEM,lh)
-#define lh_EX_CLASS_ITEM_down_load(lh) LHM_lh_down_load(EX_CLASS_ITEM,lh)
-#define lh_EX_CLASS_ITEM_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(EX_CLASS_ITEM,lh,out)
-#define lh_EX_CLASS_ITEM_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(EX_CLASS_ITEM,lh,out)
-#define lh_EX_CLASS_ITEM_stats_bio(lh,out) \
- LHM_lh_stats_bio(EX_CLASS_ITEM,lh,out)
-#define lh_EX_CLASS_ITEM_free(lh) LHM_lh_free(EX_CLASS_ITEM,lh)
-
-#define lh_FUNCTION_new() LHM_lh_new(FUNCTION,function)
-#define lh_FUNCTION_insert(lh,inst) LHM_lh_insert(FUNCTION,lh,inst)
-#define lh_FUNCTION_retrieve(lh,inst) LHM_lh_retrieve(FUNCTION,lh,inst)
-#define lh_FUNCTION_delete(lh,inst) LHM_lh_delete(FUNCTION,lh,inst)
-#define lh_FUNCTION_doall(lh,fn) LHM_lh_doall(FUNCTION,lh,fn)
-#define lh_FUNCTION_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(FUNCTION,lh,fn,arg_type,arg)
-#define lh_FUNCTION_error(lh) LHM_lh_error(FUNCTION,lh)
-#define lh_FUNCTION_num_items(lh) LHM_lh_num_items(FUNCTION,lh)
-#define lh_FUNCTION_down_load(lh) LHM_lh_down_load(FUNCTION,lh)
-#define lh_FUNCTION_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(FUNCTION,lh,out)
-#define lh_FUNCTION_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(FUNCTION,lh,out)
-#define lh_FUNCTION_stats_bio(lh,out) \
- LHM_lh_stats_bio(FUNCTION,lh,out)
-#define lh_FUNCTION_free(lh) LHM_lh_free(FUNCTION,lh)
-
-#define lh_MEM_new() LHM_lh_new(MEM,mem)
-#define lh_MEM_insert(lh,inst) LHM_lh_insert(MEM,lh,inst)
-#define lh_MEM_retrieve(lh,inst) LHM_lh_retrieve(MEM,lh,inst)
-#define lh_MEM_delete(lh,inst) LHM_lh_delete(MEM,lh,inst)
-#define lh_MEM_doall(lh,fn) LHM_lh_doall(MEM,lh,fn)
-#define lh_MEM_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(MEM,lh,fn,arg_type,arg)
-#define lh_MEM_error(lh) LHM_lh_error(MEM,lh)
-#define lh_MEM_num_items(lh) LHM_lh_num_items(MEM,lh)
-#define lh_MEM_down_load(lh) LHM_lh_down_load(MEM,lh)
-#define lh_MEM_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(MEM,lh,out)
-#define lh_MEM_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(MEM,lh,out)
-#define lh_MEM_stats_bio(lh,out) \
- LHM_lh_stats_bio(MEM,lh,out)
-#define lh_MEM_free(lh) LHM_lh_free(MEM,lh)
-
-#define lh_OBJ_NAME_new() LHM_lh_new(OBJ_NAME,obj_name)
-#define lh_OBJ_NAME_insert(lh,inst) LHM_lh_insert(OBJ_NAME,lh,inst)
-#define lh_OBJ_NAME_retrieve(lh,inst) LHM_lh_retrieve(OBJ_NAME,lh,inst)
-#define lh_OBJ_NAME_delete(lh,inst) LHM_lh_delete(OBJ_NAME,lh,inst)
-#define lh_OBJ_NAME_doall(lh,fn) LHM_lh_doall(OBJ_NAME,lh,fn)
-#define lh_OBJ_NAME_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(OBJ_NAME,lh,fn,arg_type,arg)
-#define lh_OBJ_NAME_error(lh) LHM_lh_error(OBJ_NAME,lh)
-#define lh_OBJ_NAME_num_items(lh) LHM_lh_num_items(OBJ_NAME,lh)
-#define lh_OBJ_NAME_down_load(lh) LHM_lh_down_load(OBJ_NAME,lh)
-#define lh_OBJ_NAME_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(OBJ_NAME,lh,out)
-#define lh_OBJ_NAME_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(OBJ_NAME,lh,out)
-#define lh_OBJ_NAME_stats_bio(lh,out) \
- LHM_lh_stats_bio(OBJ_NAME,lh,out)
-#define lh_OBJ_NAME_free(lh) LHM_lh_free(OBJ_NAME,lh)
-
-#define lh_OPENSSL_CSTRING_new() LHM_lh_new(OPENSSL_CSTRING,openssl_cstring)
-#define lh_OPENSSL_CSTRING_insert(lh,inst) LHM_lh_insert(OPENSSL_CSTRING,lh,inst)
-#define lh_OPENSSL_CSTRING_retrieve(lh,inst) LHM_lh_retrieve(OPENSSL_CSTRING,lh,inst)
-#define lh_OPENSSL_CSTRING_delete(lh,inst) LHM_lh_delete(OPENSSL_CSTRING,lh,inst)
-#define lh_OPENSSL_CSTRING_doall(lh,fn) LHM_lh_doall(OPENSSL_CSTRING,lh,fn)
-#define lh_OPENSSL_CSTRING_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(OPENSSL_CSTRING,lh,fn,arg_type,arg)
-#define lh_OPENSSL_CSTRING_error(lh) LHM_lh_error(OPENSSL_CSTRING,lh)
-#define lh_OPENSSL_CSTRING_num_items(lh) LHM_lh_num_items(OPENSSL_CSTRING,lh)
-#define lh_OPENSSL_CSTRING_down_load(lh) LHM_lh_down_load(OPENSSL_CSTRING,lh)
-#define lh_OPENSSL_CSTRING_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(OPENSSL_CSTRING,lh,out)
-#define lh_OPENSSL_CSTRING_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(OPENSSL_CSTRING,lh,out)
-#define lh_OPENSSL_CSTRING_stats_bio(lh,out) \
- LHM_lh_stats_bio(OPENSSL_CSTRING,lh,out)
-#define lh_OPENSSL_CSTRING_free(lh) LHM_lh_free(OPENSSL_CSTRING,lh)
-
-#define lh_OPENSSL_STRING_new() LHM_lh_new(OPENSSL_STRING,openssl_string)
-#define lh_OPENSSL_STRING_insert(lh,inst) LHM_lh_insert(OPENSSL_STRING,lh,inst)
-#define lh_OPENSSL_STRING_retrieve(lh,inst) LHM_lh_retrieve(OPENSSL_STRING,lh,inst)
-#define lh_OPENSSL_STRING_delete(lh,inst) LHM_lh_delete(OPENSSL_STRING,lh,inst)
-#define lh_OPENSSL_STRING_doall(lh,fn) LHM_lh_doall(OPENSSL_STRING,lh,fn)
-#define lh_OPENSSL_STRING_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(OPENSSL_STRING,lh,fn,arg_type,arg)
-#define lh_OPENSSL_STRING_error(lh) LHM_lh_error(OPENSSL_STRING,lh)
-#define lh_OPENSSL_STRING_num_items(lh) LHM_lh_num_items(OPENSSL_STRING,lh)
-#define lh_OPENSSL_STRING_down_load(lh) LHM_lh_down_load(OPENSSL_STRING,lh)
-#define lh_OPENSSL_STRING_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(OPENSSL_STRING,lh,out)
-#define lh_OPENSSL_STRING_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(OPENSSL_STRING,lh,out)
-#define lh_OPENSSL_STRING_stats_bio(lh,out) \
- LHM_lh_stats_bio(OPENSSL_STRING,lh,out)
-#define lh_OPENSSL_STRING_free(lh) LHM_lh_free(OPENSSL_STRING,lh)
-
-#define lh_SSL_SESSION_new() LHM_lh_new(SSL_SESSION,ssl_session)
-#define lh_SSL_SESSION_insert(lh,inst) LHM_lh_insert(SSL_SESSION,lh,inst)
-#define lh_SSL_SESSION_retrieve(lh,inst) LHM_lh_retrieve(SSL_SESSION,lh,inst)
-#define lh_SSL_SESSION_delete(lh,inst) LHM_lh_delete(SSL_SESSION,lh,inst)
-#define lh_SSL_SESSION_doall(lh,fn) LHM_lh_doall(SSL_SESSION,lh,fn)
-#define lh_SSL_SESSION_doall_arg(lh,fn,arg_type,arg) \
- LHM_lh_doall_arg(SSL_SESSION,lh,fn,arg_type,arg)
-#define lh_SSL_SESSION_error(lh) LHM_lh_error(SSL_SESSION,lh)
-#define lh_SSL_SESSION_num_items(lh) LHM_lh_num_items(SSL_SESSION,lh)
-#define lh_SSL_SESSION_down_load(lh) LHM_lh_down_load(SSL_SESSION,lh)
-#define lh_SSL_SESSION_node_stats_bio(lh,out) \
- LHM_lh_node_stats_bio(SSL_SESSION,lh,out)
-#define lh_SSL_SESSION_node_usage_stats_bio(lh,out) \
- LHM_lh_node_usage_stats_bio(SSL_SESSION,lh,out)
-#define lh_SSL_SESSION_stats_bio(lh,out) \
- LHM_lh_stats_bio(SSL_SESSION,lh,out)
-#define lh_SSL_SESSION_free(lh) LHM_lh_free(SSL_SESSION,lh)
-/* End of util/mkstack.pl block, you may now edit :-) */
-
-#endif /* !defined HEADER_SAFESTACK_H */
diff --git a/drivers/builtin_openssl/openssl/seed.h b/drivers/builtin_openssl/openssl/seed.h
deleted file mode 100644
index c50fdd3607..0000000000
--- a/drivers/builtin_openssl/openssl/seed.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2007 KISA(Korea Information Security Agency). All rights reserved.
- *
- * 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. Neither the name of 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-
-#ifndef HEADER_SEED_H
-#define HEADER_SEED_H
-
-#include <openssl/opensslconf.h>
-#include <openssl/e_os2.h>
-#include <openssl/crypto.h>
-
-#ifdef OPENSSL_NO_SEED
-#error SEED is disabled.
-#endif
-
-#ifdef AES_LONG /* look whether we need 'long' to get 32 bits */
-# ifndef SEED_LONG
-# define SEED_LONG 1
-# endif
-#endif
-
-#if !defined(NO_SYS_TYPES_H)
-# include <sys/types.h>
-#endif
-
-#define SEED_BLOCK_SIZE 16
-#define SEED_KEY_LENGTH 16
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-typedef struct seed_key_st {
-#ifdef SEED_LONG
- unsigned long data[32];
-#else
- unsigned int data[32];
-#endif
-} SEED_KEY_SCHEDULE;
-
-#ifdef OPENSSL_FIPS
-void private_SEED_set_key(const unsigned char rawkey[SEED_KEY_LENGTH], SEED_KEY_SCHEDULE *ks);
-#endif
-void SEED_set_key(const unsigned char rawkey[SEED_KEY_LENGTH], SEED_KEY_SCHEDULE *ks);
-
-void SEED_encrypt(const unsigned char s[SEED_BLOCK_SIZE], unsigned char d[SEED_BLOCK_SIZE], const SEED_KEY_SCHEDULE *ks);
-void SEED_decrypt(const unsigned char s[SEED_BLOCK_SIZE], unsigned char d[SEED_BLOCK_SIZE], const SEED_KEY_SCHEDULE *ks);
-
-void SEED_ecb_encrypt(const unsigned char *in, unsigned char *out, const SEED_KEY_SCHEDULE *ks, int enc);
-void SEED_cbc_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const SEED_KEY_SCHEDULE *ks, unsigned char ivec[SEED_BLOCK_SIZE], int enc);
-void SEED_cfb128_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const SEED_KEY_SCHEDULE *ks, unsigned char ivec[SEED_BLOCK_SIZE], int *num, int enc);
-void SEED_ofb128_encrypt(const unsigned char *in, unsigned char *out,
- size_t len, const SEED_KEY_SCHEDULE *ks, unsigned char ivec[SEED_BLOCK_SIZE], int *num);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* HEADER_SEED_H */
diff --git a/drivers/builtin_openssl/openssl/sha.h b/drivers/builtin_openssl/openssl/sha.h
deleted file mode 100644
index 8a6bf4bbbb..0000000000
--- a/drivers/builtin_openssl/openssl/sha.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/* crypto/sha/sha.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_SHA_H
-#define HEADER_SHA_H
-
-#include <openssl/e_os2.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(OPENSSL_NO_SHA) || (defined(OPENSSL_NO_SHA0) && defined(OPENSSL_NO_SHA1))
-#error SHA is disabled.
-#endif
-
-#if defined(OPENSSL_FIPS)
-#define FIPS_SHA_SIZE_T size_t
-#endif
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * ! SHA_LONG has to be at least 32 bits wide. If it's wider, then !
- * ! SHA_LONG_LOG2 has to be defined along. !
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- */
-
-#if defined(__LP32__)
-#define SHA_LONG unsigned long
-#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
-#define SHA_LONG unsigned long
-#define SHA_LONG_LOG2 3
-#else
-#define SHA_LONG unsigned int
-#endif
-
-#define SHA_LBLOCK 16
-#define SHA_CBLOCK (SHA_LBLOCK*4) /* SHA treats input data as a
- * contiguous array of 32 bit
- * wide big-endian values. */
-#define SHA_LAST_BLOCK (SHA_CBLOCK-8)
-#define SHA_DIGEST_LENGTH 20
-
-typedef struct SHAstate_st
- {
- SHA_LONG h0,h1,h2,h3,h4;
- SHA_LONG Nl,Nh;
- SHA_LONG data[SHA_LBLOCK];
- unsigned int num;
- } SHA_CTX;
-
-#ifndef OPENSSL_NO_SHA0
-#ifdef OPENSSL_FIPS
-int private_SHA_Init(SHA_CTX *c);
-#endif
-int SHA_Init(SHA_CTX *c);
-int SHA_Update(SHA_CTX *c, const void *data, size_t len);
-int SHA_Final(unsigned char *md, SHA_CTX *c);
-unsigned char *SHA(const unsigned char *d, size_t n, unsigned char *md);
-void SHA_Transform(SHA_CTX *c, const unsigned char *data);
-#endif
-#ifndef OPENSSL_NO_SHA1
-#ifdef OPENSSL_FIPS
-int private_SHA1_Init(SHA_CTX *c);
-#endif
-int SHA1_Init(SHA_CTX *c);
-int SHA1_Update(SHA_CTX *c, const void *data, size_t len);
-int SHA1_Final(unsigned char *md, SHA_CTX *c);
-unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md);
-void SHA1_Transform(SHA_CTX *c, const unsigned char *data);
-#endif
-
-#define SHA256_CBLOCK (SHA_LBLOCK*4) /* SHA-256 treats input data as a
- * contiguous array of 32 bit
- * wide big-endian values. */
-#define SHA224_DIGEST_LENGTH 28
-#define SHA256_DIGEST_LENGTH 32
-
-typedef struct SHA256state_st
- {
- SHA_LONG h[8];
- SHA_LONG Nl,Nh;
- SHA_LONG data[SHA_LBLOCK];
- unsigned int num,md_len;
- } SHA256_CTX;
-
-#ifndef OPENSSL_NO_SHA256
-#ifdef OPENSSL_FIPS
-int private_SHA224_Init(SHA256_CTX *c);
-int private_SHA256_Init(SHA256_CTX *c);
-#endif
-int SHA224_Init(SHA256_CTX *c);
-int SHA224_Update(SHA256_CTX *c, const void *data, size_t len);
-int SHA224_Final(unsigned char *md, SHA256_CTX *c);
-unsigned char *SHA224(const unsigned char *d, size_t n,unsigned char *md);
-int SHA256_Init(SHA256_CTX *c);
-int SHA256_Update(SHA256_CTX *c, const void *data, size_t len);
-int SHA256_Final(unsigned char *md, SHA256_CTX *c);
-unsigned char *SHA256(const unsigned char *d, size_t n,unsigned char *md);
-void SHA256_Transform(SHA256_CTX *c, const unsigned char *data);
-#endif
-
-#define SHA384_DIGEST_LENGTH 48
-#define SHA512_DIGEST_LENGTH 64
-
-#ifndef OPENSSL_NO_SHA512
-/*
- * Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64
- * being exactly 64-bit wide. See Implementation Notes in sha512.c
- * for further details.
- */
-#define SHA512_CBLOCK (SHA_LBLOCK*8) /* SHA-512 treats input data as a
- * contiguous array of 64 bit
- * wide big-endian values. */
-#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
-#define SHA_LONG64 unsigned __int64
-#define U64(C) C##UI64
-#elif defined(__arch64__)
-#define SHA_LONG64 unsigned long
-#define U64(C) C##UL
-#else
-#define SHA_LONG64 unsigned long long
-#define U64(C) C##ULL
-#endif
-
-typedef struct SHA512state_st
- {
- SHA_LONG64 h[8];
- SHA_LONG64 Nl,Nh;
- union {
- SHA_LONG64 d[SHA_LBLOCK];
- unsigned char p[SHA512_CBLOCK];
- } u;
- unsigned int num,md_len;
- } SHA512_CTX;
-#endif
-
-#ifndef OPENSSL_NO_SHA512
-#ifdef OPENSSL_FIPS
-int private_SHA384_Init(SHA512_CTX *c);
-int private_SHA512_Init(SHA512_CTX *c);
-#endif
-int SHA384_Init(SHA512_CTX *c);
-int SHA384_Update(SHA512_CTX *c, const void *data, size_t len);
-int SHA384_Final(unsigned char *md, SHA512_CTX *c);
-unsigned char *SHA384(const unsigned char *d, size_t n,unsigned char *md);
-int SHA512_Init(SHA512_CTX *c);
-int SHA512_Update(SHA512_CTX *c, const void *data, size_t len);
-int SHA512_Final(unsigned char *md, SHA512_CTX *c);
-unsigned char *SHA512(const unsigned char *d, size_t n,unsigned char *md);
-void SHA512_Transform(SHA512_CTX *c, const unsigned char *data);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/srp.h b/drivers/builtin_openssl/openssl/srp.h
deleted file mode 100644
index 7ec7825cad..0000000000
--- a/drivers/builtin_openssl/openssl/srp.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* crypto/srp/srp.h */
-/* Written by Christophe Renou (christophe.renou@edelweb.fr) with
- * the precious help of Peter Sylvester (peter.sylvester@edelweb.fr)
- * for the EdelKey project and contributed to the OpenSSL project 2004.
- */
-/* ====================================================================
- * Copyright (c) 2004 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-#ifndef __SRP_H__
-#define __SRP_H__
-
-#ifndef OPENSSL_NO_SRP
-
-#include <stdio.h>
-#include <string.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <openssl/safestack.h>
-#include <openssl/bn.h>
-#include <openssl/crypto.h>
-
-typedef struct SRP_gN_cache_st
- {
- char *b64_bn;
- BIGNUM *bn;
- } SRP_gN_cache;
-
-
-DECLARE_STACK_OF(SRP_gN_cache)
-
-typedef struct SRP_user_pwd_st
- {
- char *id;
- BIGNUM *s;
- BIGNUM *v;
- const BIGNUM *g;
- const BIGNUM *N;
- char *info;
- } SRP_user_pwd;
-
-DECLARE_STACK_OF(SRP_user_pwd)
-
-typedef struct SRP_VBASE_st
- {
- STACK_OF(SRP_user_pwd) *users_pwd;
- STACK_OF(SRP_gN_cache) *gN_cache;
-/* to simulate a user */
- char *seed_key;
- BIGNUM *default_g;
- BIGNUM *default_N;
- } SRP_VBASE;
-
-
-/*Structure interne pour retenir les couples N et g*/
-typedef struct SRP_gN_st
- {
- char *id;
- BIGNUM *g;
- BIGNUM *N;
- } SRP_gN;
-
-DECLARE_STACK_OF(SRP_gN)
-
-SRP_VBASE *SRP_VBASE_new(char *seed_key);
-int SRP_VBASE_free(SRP_VBASE *vb);
-int SRP_VBASE_init(SRP_VBASE *vb, char * verifier_file);
-SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username);
-char *SRP_create_verifier(const char *user, const char *pass, char **salt,
- char **verifier, const char *N, const char *g);
-int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, BIGNUM **verifier, BIGNUM *N, BIGNUM *g);
-
-
-#define SRP_NO_ERROR 0
-#define SRP_ERR_VBASE_INCOMPLETE_FILE 1
-#define SRP_ERR_VBASE_BN_LIB 2
-#define SRP_ERR_OPEN_FILE 3
-#define SRP_ERR_MEMORY 4
-
-#define DB_srptype 0
-#define DB_srpverifier 1
-#define DB_srpsalt 2
-#define DB_srpid 3
-#define DB_srpgN 4
-#define DB_srpinfo 5
-#undef DB_NUMBER
-#define DB_NUMBER 6
-
-#define DB_SRP_INDEX 'I'
-#define DB_SRP_VALID 'V'
-#define DB_SRP_REVOKED 'R'
-#define DB_SRP_MODIF 'v'
-
-
-/* see srp.c */
-char * SRP_check_known_gN_param(BIGNUM* g, BIGNUM* N);
-SRP_gN *SRP_get_default_gN(const char * id) ;
-
-/* server side .... */
-BIGNUM *SRP_Calc_server_key(BIGNUM *A, BIGNUM *v, BIGNUM *u, BIGNUM *b, BIGNUM *N);
-BIGNUM *SRP_Calc_B(BIGNUM *b, BIGNUM *N, BIGNUM *g, BIGNUM *v);
-int SRP_Verify_A_mod_N(BIGNUM *A, BIGNUM *N);
-BIGNUM *SRP_Calc_u(BIGNUM *A, BIGNUM *B, BIGNUM *N) ;
-
-
-
-/* client side .... */
-BIGNUM *SRP_Calc_x(BIGNUM *s, const char *user, const char *pass);
-BIGNUM *SRP_Calc_A(BIGNUM *a, BIGNUM *N, BIGNUM *g);
-BIGNUM *SRP_Calc_client_key(BIGNUM *N, BIGNUM *B, BIGNUM *g, BIGNUM *x, BIGNUM *a, BIGNUM *u);
-int SRP_Verify_B_mod_N(BIGNUM *B, BIGNUM *N);
-
-#define SRP_MINIMAL_N 1024
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/ssl.h b/drivers/builtin_openssl/openssl/ssl.h
deleted file mode 100644
index 7219a0e64b..0000000000
--- a/drivers/builtin_openssl/openssl/ssl.h
+++ /dev/null
@@ -1,2588 +0,0 @@
-/* ssl/ssl.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECC cipher suite support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#ifndef HEADER_SSL_H
-#define HEADER_SSL_H
-
-#include <openssl/e_os2.h>
-
-#ifndef OPENSSL_NO_COMP
-#include <openssl/comp.h>
-#endif
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#ifndef OPENSSL_NO_DEPRECATED
-#ifndef OPENSSL_NO_X509
-#include <openssl/x509.h>
-#endif
-#include <openssl/crypto.h>
-#include <openssl/lhash.h>
-#include <openssl/buffer.h>
-#endif
-#include <openssl/pem.h>
-#include <openssl/hmac.h>
-
-#include <openssl/kssl.h>
-#include <openssl/safestack.h>
-#include <openssl/symhacks.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* SSLeay version number for ASN.1 encoding of the session information */
-/* Version 0 - initial version
- * Version 1 - added the optional peer certificate
- */
-#define SSL_SESSION_ASN1_VERSION 0x0001
-
-/* text strings for the ciphers */
-#define SSL_TXT_NULL_WITH_MD5 SSL2_TXT_NULL_WITH_MD5
-#define SSL_TXT_RC4_128_WITH_MD5 SSL2_TXT_RC4_128_WITH_MD5
-#define SSL_TXT_RC4_128_EXPORT40_WITH_MD5 SSL2_TXT_RC4_128_EXPORT40_WITH_MD5
-#define SSL_TXT_RC2_128_CBC_WITH_MD5 SSL2_TXT_RC2_128_CBC_WITH_MD5
-#define SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5
-#define SSL_TXT_IDEA_128_CBC_WITH_MD5 SSL2_TXT_IDEA_128_CBC_WITH_MD5
-#define SSL_TXT_DES_64_CBC_WITH_MD5 SSL2_TXT_DES_64_CBC_WITH_MD5
-#define SSL_TXT_DES_64_CBC_WITH_SHA SSL2_TXT_DES_64_CBC_WITH_SHA
-#define SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5
-#define SSL_TXT_DES_192_EDE3_CBC_WITH_SHA SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA
-
-/* VRS Additional Kerberos5 entries
- */
-#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA
-#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
-#define SSL_TXT_KRB5_RC4_128_SHA SSL3_TXT_KRB5_RC4_128_SHA
-#define SSL_TXT_KRB5_IDEA_128_CBC_SHA SSL3_TXT_KRB5_IDEA_128_CBC_SHA
-#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5
-#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5
-#define SSL_TXT_KRB5_RC4_128_MD5 SSL3_TXT_KRB5_RC4_128_MD5
-#define SSL_TXT_KRB5_IDEA_128_CBC_MD5 SSL3_TXT_KRB5_IDEA_128_CBC_MD5
-
-#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA
-#define SSL_TXT_KRB5_RC2_40_CBC_SHA SSL3_TXT_KRB5_RC2_40_CBC_SHA
-#define SSL_TXT_KRB5_RC4_40_SHA SSL3_TXT_KRB5_RC4_40_SHA
-#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5
-#define SSL_TXT_KRB5_RC2_40_CBC_MD5 SSL3_TXT_KRB5_RC2_40_CBC_MD5
-#define SSL_TXT_KRB5_RC4_40_MD5 SSL3_TXT_KRB5_RC4_40_MD5
-
-#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA
-#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5
-#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA
-#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5
-#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
-#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5
-#define SSL_MAX_KRB5_PRINCIPAL_LENGTH 256
-
-#define SSL_MAX_SSL_SESSION_ID_LENGTH 32
-#define SSL_MAX_SID_CTX_LENGTH 32
-
-#define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES (512/8)
-#define SSL_MAX_KEY_ARG_LENGTH 8
-#define SSL_MAX_MASTER_KEY_LENGTH 48
-
-
-/* These are used to specify which ciphers to use and not to use */
-
-#define SSL_TXT_EXP40 "EXPORT40"
-#define SSL_TXT_EXP56 "EXPORT56"
-#define SSL_TXT_LOW "LOW"
-#define SSL_TXT_MEDIUM "MEDIUM"
-#define SSL_TXT_HIGH "HIGH"
-#define SSL_TXT_FIPS "FIPS"
-
-#define SSL_TXT_kFZA "kFZA" /* unused! */
-#define SSL_TXT_aFZA "aFZA" /* unused! */
-#define SSL_TXT_eFZA "eFZA" /* unused! */
-#define SSL_TXT_FZA "FZA" /* unused! */
-
-#define SSL_TXT_aNULL "aNULL"
-#define SSL_TXT_eNULL "eNULL"
-#define SSL_TXT_NULL "NULL"
-
-#define SSL_TXT_kRSA "kRSA"
-#define SSL_TXT_kDHr "kDHr" /* no such ciphersuites supported! */
-#define SSL_TXT_kDHd "kDHd" /* no such ciphersuites supported! */
-#define SSL_TXT_kDH "kDH" /* no such ciphersuites supported! */
-#define SSL_TXT_kEDH "kEDH"
-#define SSL_TXT_kKRB5 "kKRB5"
-#define SSL_TXT_kECDHr "kECDHr"
-#define SSL_TXT_kECDHe "kECDHe"
-#define SSL_TXT_kECDH "kECDH"
-#define SSL_TXT_kEECDH "kEECDH"
-#define SSL_TXT_kPSK "kPSK"
-#define SSL_TXT_kGOST "kGOST"
-#define SSL_TXT_kSRP "kSRP"
-
-#define SSL_TXT_aRSA "aRSA"
-#define SSL_TXT_aDSS "aDSS"
-#define SSL_TXT_aDH "aDH" /* no such ciphersuites supported! */
-#define SSL_TXT_aECDH "aECDH"
-#define SSL_TXT_aKRB5 "aKRB5"
-#define SSL_TXT_aECDSA "aECDSA"
-#define SSL_TXT_aPSK "aPSK"
-#define SSL_TXT_aGOST94 "aGOST94"
-#define SSL_TXT_aGOST01 "aGOST01"
-#define SSL_TXT_aGOST "aGOST"
-
-#define SSL_TXT_DSS "DSS"
-#define SSL_TXT_DH "DH"
-#define SSL_TXT_EDH "EDH" /* same as "kEDH:-ADH" */
-#define SSL_TXT_ADH "ADH"
-#define SSL_TXT_RSA "RSA"
-#define SSL_TXT_ECDH "ECDH"
-#define SSL_TXT_EECDH "EECDH" /* same as "kEECDH:-AECDH" */
-#define SSL_TXT_AECDH "AECDH"
-#define SSL_TXT_ECDSA "ECDSA"
-#define SSL_TXT_KRB5 "KRB5"
-#define SSL_TXT_PSK "PSK"
-#define SSL_TXT_SRP "SRP"
-
-#define SSL_TXT_DES "DES"
-#define SSL_TXT_3DES "3DES"
-#define SSL_TXT_RC4 "RC4"
-#define SSL_TXT_RC2 "RC2"
-#define SSL_TXT_IDEA "IDEA"
-#define SSL_TXT_SEED "SEED"
-#define SSL_TXT_AES128 "AES128"
-#define SSL_TXT_AES256 "AES256"
-#define SSL_TXT_AES "AES"
-#define SSL_TXT_AES_GCM "AESGCM"
-#define SSL_TXT_CAMELLIA128 "CAMELLIA128"
-#define SSL_TXT_CAMELLIA256 "CAMELLIA256"
-#define SSL_TXT_CAMELLIA "CAMELLIA"
-
-#define SSL_TXT_MD5 "MD5"
-#define SSL_TXT_SHA1 "SHA1"
-#define SSL_TXT_SHA "SHA" /* same as "SHA1" */
-#define SSL_TXT_GOST94 "GOST94"
-#define SSL_TXT_GOST89MAC "GOST89MAC"
-#define SSL_TXT_SHA256 "SHA256"
-#define SSL_TXT_SHA384 "SHA384"
-
-#define SSL_TXT_SSLV2 "SSLv2"
-#define SSL_TXT_SSLV3 "SSLv3"
-#define SSL_TXT_TLSV1 "TLSv1"
-#define SSL_TXT_TLSV1_1 "TLSv1.1"
-#define SSL_TXT_TLSV1_2 "TLSv1.2"
-
-#define SSL_TXT_EXP "EXP"
-#define SSL_TXT_EXPORT "EXPORT"
-
-#define SSL_TXT_ALL "ALL"
-
-/*
- * COMPLEMENTOF* definitions. These identifiers are used to (de-select)
- * ciphers normally not being used.
- * Example: "RC4" will activate all ciphers using RC4 including ciphers
- * without authentication, which would normally disabled by DEFAULT (due
- * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT"
- * will make sure that it is also disabled in the specific selection.
- * COMPLEMENTOF* identifiers are portable between version, as adjustments
- * to the default cipher setup will also be included here.
- *
- * COMPLEMENTOFDEFAULT does not experience the same special treatment that
- * DEFAULT gets, as only selection is being done and no sorting as needed
- * for DEFAULT.
- */
-#define SSL_TXT_CMPALL "COMPLEMENTOFALL"
-#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT"
-
-/* The following cipher list is used by default.
- * It also is substituted when an application-defined cipher list string
- * starts with 'DEFAULT'. */
-#define SSL_DEFAULT_CIPHER_LIST "ALL:!aNULL:!eNULL:!SSLv2"
-/* As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always
- * starts with a reasonable order, and all we have to do for DEFAULT is
- * throwing out anonymous and unencrypted ciphersuites!
- * (The latter are not actually enabled by ALL, but "ALL:RSA" would enable
- * some of them.)
- */
-
-/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
-#define SSL_SENT_SHUTDOWN 1
-#define SSL_RECEIVED_SHUTDOWN 2
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if (defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_MD5)) && !defined(OPENSSL_NO_SSL2)
-#define OPENSSL_NO_SSL2
-#endif
-
-#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1
-#define SSL_FILETYPE_PEM X509_FILETYPE_PEM
-
-/* This is needed to stop compilers complaining about the
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
-typedef struct ssl_st *ssl_crock_st;
-typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
-typedef struct ssl_method_st SSL_METHOD;
-typedef struct ssl_cipher_st SSL_CIPHER;
-typedef struct ssl_session_st SSL_SESSION;
-
-DECLARE_STACK_OF(SSL_CIPHER)
-
-/* SRTP protection profiles for use with the use_srtp extension (RFC 5764)*/
-typedef struct srtp_protection_profile_st
- {
- const char *name;
- unsigned long id;
- } SRTP_PROTECTION_PROFILE;
-
-DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE)
-
-typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
-typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-/* used to hold info on the particular ciphers used */
-struct ssl_cipher_st
- {
- int valid;
- const char *name; /* text name */
- unsigned long id; /* id, 4 bytes, first is version */
-
- /* changed in 0.9.9: these four used to be portions of a single value 'algorithms' */
- unsigned long algorithm_mkey; /* key exchange algorithm */
- unsigned long algorithm_auth; /* server authentication */
- unsigned long algorithm_enc; /* symmetric encryption */
- unsigned long algorithm_mac; /* symmetric authentication */
- unsigned long algorithm_ssl; /* (major) protocol version */
-
- unsigned long algo_strength; /* strength and export flags */
- unsigned long algorithm2; /* Extra flags */
- int strength_bits; /* Number of bits really used */
- int alg_bits; /* Number of bits for algorithm */
- };
-
-
-/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
-struct ssl_method_st
- {
- int version;
- int (*ssl_new)(SSL *s);
- void (*ssl_clear)(SSL *s);
- void (*ssl_free)(SSL *s);
- int (*ssl_accept)(SSL *s);
- int (*ssl_connect)(SSL *s);
- int (*ssl_read)(SSL *s,void *buf,int len);
- int (*ssl_peek)(SSL *s,void *buf,int len);
- int (*ssl_write)(SSL *s,const void *buf,int len);
- int (*ssl_shutdown)(SSL *s);
- int (*ssl_renegotiate)(SSL *s);
- int (*ssl_renegotiate_check)(SSL *s);
- long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
- max, int *ok);
- int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len,
- int peek);
- int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
- int (*ssl_dispatch_alert)(SSL *s);
- long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
- long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
- const SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
- int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
- int (*ssl_pending)(const SSL *s);
- int (*num_ciphers)(void);
- const SSL_CIPHER *(*get_cipher)(unsigned ncipher);
- const struct ssl_method_st *(*get_ssl_method)(int version);
- long (*get_timeout)(void);
- struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
- int (*ssl_version)(void);
- long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void));
- long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
- };
-
-/* Lets make this into an ASN.1 type structure as follows
- * SSL_SESSION_ID ::= SEQUENCE {
- * version INTEGER, -- structure version number
- * SSLversion INTEGER, -- SSL version number
- * Cipher OCTET STRING, -- the 3 byte cipher ID
- * Session_ID OCTET STRING, -- the Session ID
- * Master_key OCTET STRING, -- the master key
- * KRB5_principal OCTET STRING -- optional Kerberos principal
- * Key_Arg [ 0 ] IMPLICIT OCTET STRING, -- the optional Key argument
- * Time [ 1 ] EXPLICIT INTEGER, -- optional Start Time
- * Timeout [ 2 ] EXPLICIT INTEGER, -- optional Timeout ins seconds
- * Peer [ 3 ] EXPLICIT X509, -- optional Peer Certificate
- * Session_ID_context [ 4 ] EXPLICIT OCTET STRING, -- the Session ID context
- * Verify_result [ 5 ] EXPLICIT INTEGER, -- X509_V_... code for `Peer'
- * HostName [ 6 ] EXPLICIT OCTET STRING, -- optional HostName from servername TLS extension
- * PSK_identity_hint [ 7 ] EXPLICIT OCTET STRING, -- optional PSK identity hint
- * PSK_identity [ 8 ] EXPLICIT OCTET STRING, -- optional PSK identity
- * Ticket_lifetime_hint [9] EXPLICIT INTEGER, -- server's lifetime hint for session ticket
- * Ticket [10] EXPLICIT OCTET STRING, -- session ticket (clients only)
- * Compression_meth [11] EXPLICIT OCTET STRING, -- optional compression method
- * SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username
- * }
- * Look in ssl/ssl_asn1.c for more details
- * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
- */
-struct ssl_session_st
- {
- int ssl_version; /* what ssl version session info is
- * being kept in here? */
-
- /* only really used in SSLv2 */
- unsigned int key_arg_length;
- unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH];
- int master_key_length;
- unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
- /* session_id - valid? */
- unsigned int session_id_length;
- unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
- /* this is used to determine whether the session is being reused in
- * the appropriate context. It is up to the application to set this,
- * via SSL_new */
- unsigned int sid_ctx_length;
- unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
-
-#ifndef OPENSSL_NO_KRB5
- unsigned int krb5_client_princ_len;
- unsigned char krb5_client_princ[SSL_MAX_KRB5_PRINCIPAL_LENGTH];
-#endif /* OPENSSL_NO_KRB5 */
-#ifndef OPENSSL_NO_PSK
- char *psk_identity_hint;
- char *psk_identity;
-#endif
- /* Used to indicate that session resumption is not allowed.
- * Applications can also set this bit for a new session via
- * not_resumable_session_cb to disable session caching and tickets. */
- int not_resumable;
-
- /* The cert is the certificate used to establish this connection */
- struct sess_cert_st /* SESS_CERT */ *sess_cert;
-
- /* This is the cert for the other end.
- * On clients, it will be the same as sess_cert->peer_key->x509
- * (the latter is not enough as sess_cert is not retained
- * in the external representation of sessions, see ssl_asn1.c). */
- X509 *peer;
- /* when app_verify_callback accepts a session where the peer's certificate
- * is not ok, we must remember the error for session reuse: */
- long verify_result; /* only for servers */
-
- int references;
- long timeout;
- long time;
-
- unsigned int compress_meth; /* Need to lookup the method */
-
- const SSL_CIPHER *cipher;
- unsigned long cipher_id; /* when ASN.1 loaded, this
- * needs to be used to load
- * the 'cipher' structure */
-
- STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */
-
- CRYPTO_EX_DATA ex_data; /* application specific data */
-
- /* These are used to make removal of session-ids more
- * efficient and to implement a maximum cache size. */
- struct ssl_session_st *prev,*next;
-#ifndef OPENSSL_NO_TLSEXT
- char *tlsext_hostname;
-#ifndef OPENSSL_NO_EC
- size_t tlsext_ecpointformatlist_length;
- unsigned char *tlsext_ecpointformatlist; /* peer's list */
- size_t tlsext_ellipticcurvelist_length;
- unsigned char *tlsext_ellipticcurvelist; /* peer's list */
-#endif /* OPENSSL_NO_EC */
- /* RFC4507 info */
- unsigned char *tlsext_tick; /* Session ticket */
- size_t tlsext_ticklen; /* Session ticket length */
- long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */
-#endif
-#ifndef OPENSSL_NO_SRP
- char *srp_username;
-#endif
- };
-
-#endif
-
-#define SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001L
-#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002L
-/* Allow initial connection to servers that don't support RI */
-#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L
-#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L
-#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x00000010L
-#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L
-#define SSL_OP_SAFARI_ECDHE_ECDSA_BUG 0x00000040L
-#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080L
-#define SSL_OP_TLS_D5_BUG 0x00000100L
-#define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L
-
-/* Hasn't done anything since OpenSSL 0.9.7h, retained for compatibility */
-#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0x0
-
-/* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added
- * in OpenSSL 0.9.6d. Usually (depending on the application protocol)
- * the workaround is not needed. Unfortunately some broken SSL/TLS
- * implementations cannot handle it at all, which is why we include
- * it in SSL_OP_ALL. */
-#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800L /* added in 0.9.6e */
-
-/* SSL_OP_ALL: various bug workarounds that should be rather harmless.
- * This used to be 0x000FFFFFL before 0.9.7. */
-#define SSL_OP_ALL 0x80000BFFL
-
-/* DTLS options */
-#define SSL_OP_NO_QUERY_MTU 0x00001000L
-/* Turn on Cookie Exchange (on relevant for servers) */
-#define SSL_OP_COOKIE_EXCHANGE 0x00002000L
-/* Don't use RFC4507 ticket extension */
-#define SSL_OP_NO_TICKET 0x00004000L
-/* Use Cisco's "speshul" version of DTLS_BAD_VER (as client) */
-#define SSL_OP_CISCO_ANYCONNECT 0x00008000L
-
-/* As server, disallow session resumption on renegotiation */
-#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L
-/* Don't use compression even if supported */
-#define SSL_OP_NO_COMPRESSION 0x00020000L
-/* Permit unsafe legacy renegotiation */
-#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L
-/* If set, always create a new key when using tmp_ecdh parameters */
-#define SSL_OP_SINGLE_ECDH_USE 0x00080000L
-/* If set, always create a new key when using tmp_dh parameters */
-#define SSL_OP_SINGLE_DH_USE 0x00100000L
-/* Set to always use the tmp_rsa key when doing RSA operations,
- * even when this violates protocol specs */
-#define SSL_OP_EPHEMERAL_RSA 0x00200000L
-/* Set on servers to choose the cipher according to the server's
- * preferences */
-#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L
-/* If set, a server will allow a client to issue a SSLv3.0 version number
- * as latest version supported in the premaster secret, even when TLSv1.0
- * (version 3.1) was announced in the client hello. Normally this is
- * forbidden to prevent version rollback attacks. */
-#define SSL_OP_TLS_ROLLBACK_BUG 0x00800000L
-
-#define SSL_OP_NO_SSLv2 0x01000000L
-#define SSL_OP_NO_SSLv3 0x02000000L
-#define SSL_OP_NO_TLSv1 0x04000000L
-#define SSL_OP_NO_TLSv1_2 0x08000000L
-#define SSL_OP_NO_TLSv1_1 0x10000000L
-
-/* These next two were never actually used for anything since SSLeay
- * zap so we have some more flags.
- */
-/* The next flag deliberately changes the ciphertest, this is a check
- * for the PKCS#1 attack */
-#define SSL_OP_PKCS1_CHECK_1 0x0
-#define SSL_OP_PKCS1_CHECK_2 0x0
-
-#define SSL_OP_NETSCAPE_CA_DN_BUG 0x20000000L
-#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x40000000L
-/* Make server add server-hello extension from early version of
- * cryptopro draft, when GOST ciphersuite is negotiated.
- * Required for interoperability with CryptoPro CSP 3.x
- */
-#define SSL_OP_CRYPTOPRO_TLSEXT_BUG 0x80000000L
-
-/* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
- * when just a single record has been written): */
-#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L
-/* Make it possible to retry SSL_write() with changed buffer location
- * (buffer contents must stay the same!); this is not the default to avoid
- * the misconception that non-blocking SSL_write() behaves like
- * non-blocking write(): */
-#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
-/* Never bother the application with retries if the transport
- * is blocking: */
-#define SSL_MODE_AUTO_RETRY 0x00000004L
-/* Don't attempt to automatically build certificate chain */
-#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
-/* Save RAM by releasing read and write buffers when they're empty. (SSL3 and
- * TLS only.) "Released" buffers are put onto a free-list in the context
- * or just freed (depending on the context's setting for freelist_max_len). */
-#define SSL_MODE_RELEASE_BUFFERS 0x00000010L
-/* Send the current time in the Random fields of the ClientHello and
- * ServerHello records for compatibility with hypothetical implementations
- * that require it.
- */
-#define SSL_MODE_SEND_CLIENTHELLO_TIME 0x00000020L
-#define SSL_MODE_SEND_SERVERHELLO_TIME 0x00000040L
-
-/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
- * they cannot be used to clear bits. */
-
-#define SSL_CTX_set_options(ctx,op) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
-#define SSL_CTX_clear_options(ctx,op) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
-#define SSL_CTX_get_options(ctx) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
-#define SSL_set_options(ssl,op) \
- SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL)
-#define SSL_clear_options(ssl,op) \
- SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
-#define SSL_get_options(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL)
-
-#define SSL_CTX_set_mode(ctx,op) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
-#define SSL_CTX_clear_mode(ctx,op) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL)
-#define SSL_CTX_get_mode(ctx) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL)
-#define SSL_clear_mode(ssl,op) \
- SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL)
-#define SSL_set_mode(ssl,op) \
- SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
-#define SSL_get_mode(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL)
-#define SSL_set_mtu(ssl, mtu) \
- SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL)
-
-#define SSL_get_secure_renegotiation_support(ssl) \
- SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL)
-
-#ifndef OPENSSL_NO_HEARTBEATS
-#define SSL_heartbeat(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_TLS_EXT_SEND_HEARTBEAT,0,NULL)
-#endif
-
-void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
-void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
-#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
-#define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
-
-#ifndef OPENSSL_NO_SRP
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-typedef struct srp_ctx_st
- {
- /* param for all the callbacks */
- void *SRP_cb_arg;
- /* set client Hello login callback */
- int (*TLS_ext_srp_username_callback)(SSL *, int *, void *);
- /* set SRP N/g param callback for verification */
- int (*SRP_verify_param_callback)(SSL *, void *);
- /* set SRP client passwd callback */
- char *(*SRP_give_srp_client_pwd_callback)(SSL *, void *);
-
- char *login;
- BIGNUM *N,*g,*s,*B,*A;
- BIGNUM *a,*b,*v;
- char *info;
- int strength;
-
- unsigned long srp_Mask;
- } SRP_CTX;
-
-#endif
-
-/* see tls_srp.c */
-int SSL_SRP_CTX_init(SSL *s);
-int SSL_CTX_SRP_CTX_init(SSL_CTX *ctx);
-int SSL_SRP_CTX_free(SSL *ctx);
-int SSL_CTX_SRP_CTX_free(SSL_CTX *ctx);
-int SSL_srp_server_param_with_username(SSL *s, int *ad);
-int SRP_generate_server_master_secret(SSL *s,unsigned char *master_key);
-int SRP_Calc_A_param(SSL *s);
-int SRP_generate_client_master_secret(SSL *s,unsigned char *master_key);
-
-#endif
-
-#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)
-#define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */
-#else
-#define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */
-#endif
-
-#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024*20)
-
-/* This callback type is used inside SSL_CTX, SSL, and in the functions that set
- * them. It is used to override the generation of SSL/TLS session IDs in a
- * server. Return value should be zero on an error, non-zero to proceed. Also,
- * callbacks should themselves check if the id they generate is unique otherwise
- * the SSL handshake will fail with an error - callbacks can do this using the
- * 'ssl' value they're passed by;
- * SSL_has_matching_session_id(ssl, id, *id_len)
- * The length value passed in is set at the maximum size the session ID can be.
- * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback
- * can alter this length to be less if desired, but under SSLv2 session IDs are
- * supposed to be fixed at 16 bytes so the id will be padded after the callback
- * returns in this case. It is also an error for the callback to set the size to
- * zero. */
-typedef int (*GEN_SESSION_CB)(const SSL *ssl, unsigned char *id,
- unsigned int *id_len);
-
-typedef struct ssl_comp_st SSL_COMP;
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-struct ssl_comp_st
- {
- int id;
- const char *name;
-#ifndef OPENSSL_NO_COMP
- COMP_METHOD *method;
-#else
- char *method;
-#endif
- };
-
-DECLARE_STACK_OF(SSL_COMP)
-DECLARE_LHASH_OF(SSL_SESSION);
-
-struct ssl_ctx_st
- {
- const SSL_METHOD *method;
-
- STACK_OF(SSL_CIPHER) *cipher_list;
- /* same as above but sorted for lookup */
- STACK_OF(SSL_CIPHER) *cipher_list_by_id;
-
- struct x509_store_st /* X509_STORE */ *cert_store;
- LHASH_OF(SSL_SESSION) *sessions;
- /* Most session-ids that will be cached, default is
- * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */
- unsigned long session_cache_size;
- struct ssl_session_st *session_cache_head;
- struct ssl_session_st *session_cache_tail;
-
- /* This can have one of 2 values, ored together,
- * SSL_SESS_CACHE_CLIENT,
- * SSL_SESS_CACHE_SERVER,
- * Default is SSL_SESSION_CACHE_SERVER, which means only
- * SSL_accept which cache SSL_SESSIONS. */
- int session_cache_mode;
-
- /* If timeout is not 0, it is the default timeout value set
- * when SSL_new() is called. This has been put in to make
- * life easier to set things up */
- long session_timeout;
-
- /* If this callback is not null, it will be called each
- * time a session id is added to the cache. If this function
- * returns 1, it means that the callback will do a
- * SSL_SESSION_free() when it has finished using it. Otherwise,
- * on 0, it means the callback has finished with it.
- * If remove_session_cb is not null, it will be called when
- * a session-id is removed from the cache. After the call,
- * OpenSSL will SSL_SESSION_free() it. */
- int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess);
- void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess);
- SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl,
- unsigned char *data,int len,int *copy);
-
- struct
- {
- int sess_connect; /* SSL new conn - started */
- int sess_connect_renegotiate;/* SSL reneg - requested */
- int sess_connect_good; /* SSL new conne/reneg - finished */
- int sess_accept; /* SSL new accept - started */
- int sess_accept_renegotiate;/* SSL reneg - requested */
- int sess_accept_good; /* SSL accept/reneg - finished */
- int sess_miss; /* session lookup misses */
- int sess_timeout; /* reuse attempt on timeouted session */
- int sess_cache_full; /* session removed due to full cache */
- int sess_hit; /* session reuse actually done */
- int sess_cb_hit; /* session-id that was not
- * in the cache was
- * passed back via the callback. This
- * indicates that the application is
- * supplying session-id's from other
- * processes - spooky :-) */
- } stats;
-
- int references;
-
- /* if defined, these override the X509_verify_cert() calls */
- int (*app_verify_callback)(X509_STORE_CTX *, void *);
- void *app_verify_arg;
- /* before OpenSSL 0.9.7, 'app_verify_arg' was ignored
- * ('app_verify_callback' was called with just one argument) */
-
- /* Default password callback. */
- pem_password_cb *default_passwd_callback;
-
- /* Default password callback user data. */
- void *default_passwd_callback_userdata;
-
- /* get client cert callback */
- int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
-
- /* cookie generate callback */
- int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie,
- unsigned int *cookie_len);
-
- /* verify cookie callback */
- int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie,
- unsigned int cookie_len);
-
- CRYPTO_EX_DATA ex_data;
-
- const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */
- const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */
- const EVP_MD *sha1; /* For SSLv3/TLSv1 'ssl3->sha1' */
-
- STACK_OF(X509) *extra_certs;
- STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */
-
-
- /* Default values used when no per-SSL value is defined follow */
-
- void (*info_callback)(const SSL *ssl,int type,int val); /* used if SSL's info_callback is NULL */
-
- /* what we put in client cert requests */
- STACK_OF(X509_NAME) *client_CA;
-
-
- /* Default values to use in SSL structures follow (these are copied by SSL_new) */
-
- unsigned long options;
- unsigned long mode;
- long max_cert_list;
-
- struct cert_st /* CERT */ *cert;
- int read_ahead;
-
- /* callback that allows applications to peek at protocol messages */
- void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
- void *msg_callback_arg;
-
- int verify_mode;
- unsigned int sid_ctx_length;
- unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
- int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */
-
- /* Default generate session ID callback. */
- GEN_SESSION_CB generate_session_id;
-
- X509_VERIFY_PARAM *param;
-
-#if 0
- int purpose; /* Purpose setting */
- int trust; /* Trust setting */
-#endif
-
- int quiet_shutdown;
-
- /* Maximum amount of data to send in one fragment.
- * actual record size can be more than this due to
- * padding and MAC overheads.
- */
- unsigned int max_send_fragment;
-
-#ifndef OPENSSL_NO_ENGINE
- /* Engine to pass requests for client certs to
- */
- ENGINE *client_cert_engine;
-#endif
-
-#ifndef OPENSSL_NO_TLSEXT
- /* TLS extensions servername callback */
- int (*tlsext_servername_callback)(SSL*, int *, void *);
- void *tlsext_servername_arg;
- /* RFC 4507 session ticket keys */
- unsigned char tlsext_tick_key_name[16];
- unsigned char tlsext_tick_hmac_key[16];
- unsigned char tlsext_tick_aes_key[16];
- /* Callback to support customisation of ticket key setting */
- int (*tlsext_ticket_key_cb)(SSL *ssl,
- unsigned char *name, unsigned char *iv,
- EVP_CIPHER_CTX *ectx,
- HMAC_CTX *hctx, int enc);
-
- /* certificate status request info */
- /* Callback for status request */
- int (*tlsext_status_cb)(SSL *ssl, void *arg);
- void *tlsext_status_arg;
-
- /* draft-rescorla-tls-opaque-prf-input-00.txt information */
- int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg);
- void *tlsext_opaque_prf_input_callback_arg;
-#endif
-
-#ifndef OPENSSL_NO_PSK
- char *psk_identity_hint;
- unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
- unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len);
- unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len);
-#endif
-
-#ifndef OPENSSL_NO_BUF_FREELISTS
-#define SSL_MAX_BUF_FREELIST_LEN_DEFAULT 32
- unsigned int freelist_max_len;
- struct ssl3_buf_freelist_st *wbuf_freelist;
- struct ssl3_buf_freelist_st *rbuf_freelist;
-#endif
-#ifndef OPENSSL_NO_SRP
- SRP_CTX srp_ctx; /* ctx for SRP authentication */
-#endif
-
-#ifndef OPENSSL_NO_TLSEXT
-
-# ifndef OPENSSL_NO_NEXTPROTONEG
- /* Next protocol negotiation information */
- /* (for experimental NPN extension). */
-
- /* For a server, this contains a callback function by which the set of
- * advertised protocols can be provided. */
- int (*next_protos_advertised_cb)(SSL *s, const unsigned char **buf,
- unsigned int *len, void *arg);
- void *next_protos_advertised_cb_arg;
- /* For a client, this contains a callback function that selects the
- * next protocol from the list provided by the server. */
- int (*next_proto_select_cb)(SSL *s, unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen,
- void *arg);
- void *next_proto_select_cb_arg;
-# endif
- /* SRTP profiles we are willing to do from RFC 5764 */
- STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
-#endif
- };
-
-#endif
-
-#define SSL_SESS_CACHE_OFF 0x0000
-#define SSL_SESS_CACHE_CLIENT 0x0001
-#define SSL_SESS_CACHE_SERVER 0x0002
-#define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER)
-#define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080
-/* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */
-#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100
-#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200
-#define SSL_SESS_CACHE_NO_INTERNAL \
- (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE)
-
-LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx);
-#define SSL_CTX_sess_number(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL)
-#define SSL_CTX_sess_connect(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL)
-#define SSL_CTX_sess_connect_good(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL)
-#define SSL_CTX_sess_connect_renegotiate(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL)
-#define SSL_CTX_sess_accept(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL)
-#define SSL_CTX_sess_accept_renegotiate(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL)
-#define SSL_CTX_sess_accept_good(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL)
-#define SSL_CTX_sess_hits(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL)
-#define SSL_CTX_sess_cb_hits(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL)
-#define SSL_CTX_sess_misses(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL)
-#define SSL_CTX_sess_timeouts(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL)
-#define SSL_CTX_sess_cache_full(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL)
-
-void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess));
-int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(struct ssl_st *ssl, SSL_SESSION *sess);
-void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess));
-void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(struct ssl_ctx_st *ctx, SSL_SESSION *sess);
-void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, unsigned char *data,int len,int *copy));
-SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(struct ssl_st *ssl, unsigned char *Data, int len, int *copy);
-void SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb)(const SSL *ssl,int type,int val));
-void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val);
-void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey));
-int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
-#ifndef OPENSSL_NO_ENGINE
-int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e);
-#endif
-void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len));
-void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len));
-#ifndef OPENSSL_NO_NEXTPROTONEG
-void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s,
- int (*cb) (SSL *ssl,
- const unsigned char **out,
- unsigned int *outlen,
- void *arg),
- void *arg);
-void SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
- int (*cb) (SSL *ssl,
- unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen,
- void *arg),
- void *arg);
-
-int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen,
- const unsigned char *client, unsigned int client_len);
-void SSL_get0_next_proto_negotiated(const SSL *s,
- const unsigned char **data, unsigned *len);
-
-#define OPENSSL_NPN_UNSUPPORTED 0
-#define OPENSSL_NPN_NEGOTIATED 1
-#define OPENSSL_NPN_NO_OVERLAP 2
-#endif
-
-#ifndef OPENSSL_NO_PSK
-/* the maximum length of the buffer given to callbacks containing the
- * resulting identity/psk */
-#define PSK_MAX_IDENTITY_LEN 128
-#define PSK_MAX_PSK_LEN 256
-void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx,
- unsigned int (*psk_client_callback)(SSL *ssl, const char *hint,
- char *identity, unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len));
-void SSL_set_psk_client_callback(SSL *ssl,
- unsigned int (*psk_client_callback)(SSL *ssl, const char *hint,
- char *identity, unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len));
-void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx,
- unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len));
-void SSL_set_psk_server_callback(SSL *ssl,
- unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len));
-int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint);
-int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint);
-const char *SSL_get_psk_identity_hint(const SSL *s);
-const char *SSL_get_psk_identity(const SSL *s);
-#endif
-
-#define SSL_NOTHING 1
-#define SSL_WRITING 2
-#define SSL_READING 3
-#define SSL_X509_LOOKUP 4
-
-/* These will only be used when doing non-blocking IO */
-#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING)
-#define SSL_want_read(s) (SSL_want(s) == SSL_READING)
-#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING)
-#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP)
-
-#define SSL_MAC_FLAG_READ_MAC_STREAM 1
-#define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-struct ssl_st
- {
- /* protocol version
- * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
- */
- int version;
- int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
-
- const SSL_METHOD *method; /* SSLv3 */
-
- /* There are 2 BIO's even though they are normally both the
- * same. This is so data can be read and written to different
- * handlers */
-
-#ifndef OPENSSL_NO_BIO
- BIO *rbio; /* used by SSL_read */
- BIO *wbio; /* used by SSL_write */
- BIO *bbio; /* used during session-id reuse to concatenate
- * messages */
-#else
- char *rbio; /* used by SSL_read */
- char *wbio; /* used by SSL_write */
- char *bbio;
-#endif
- /* This holds a variable that indicates what we were doing
- * when a 0 or -1 is returned. This is needed for
- * non-blocking IO so we know what request needs re-doing when
- * in SSL_accept or SSL_connect */
- int rwstate;
-
- /* true when we are actually in SSL_accept() or SSL_connect() */
- int in_handshake;
- int (*handshake_func)(SSL *);
-
- /* Imagine that here's a boolean member "init" that is
- * switched as soon as SSL_set_{accept/connect}_state
- * is called for the first time, so that "state" and
- * "handshake_func" are properly initialized. But as
- * handshake_func is == 0 until then, we use this
- * test instead of an "init" member.
- */
-
- int server; /* are we the server side? - mostly used by SSL_clear*/
-
- int new_session;/* Generate a new session or reuse an old one.
- * NB: For servers, the 'new' session may actually be a previously
- * cached session or even the previous session unless
- * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
- int quiet_shutdown;/* don't send shutdown packets */
- int shutdown; /* we have shut things down, 0x01 sent, 0x02
- * for received */
- int state; /* where we are */
- int rstate; /* where we are when reading */
-
- BUF_MEM *init_buf; /* buffer used during init */
- void *init_msg; /* pointer to handshake message body, set by ssl3_get_message() */
- int init_num; /* amount read/written */
- int init_off; /* amount read/written */
-
- /* used internally to point at a raw packet */
- unsigned char *packet;
- unsigned int packet_length;
-
- struct ssl2_state_st *s2; /* SSLv2 variables */
- struct ssl3_state_st *s3; /* SSLv3 variables */
- struct dtls1_state_st *d1; /* DTLSv1 variables */
-
- int read_ahead; /* Read as many input bytes as possible
- * (for non-blocking reads) */
-
- /* callback that allows applications to peek at protocol messages */
- void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
- void *msg_callback_arg;
-
- int hit; /* reusing a previous session */
-
- X509_VERIFY_PARAM *param;
-
-#if 0
- int purpose; /* Purpose setting */
- int trust; /* Trust setting */
-#endif
-
- /* crypto */
- STACK_OF(SSL_CIPHER) *cipher_list;
- STACK_OF(SSL_CIPHER) *cipher_list_by_id;
-
- /* These are the ones being used, the ones in SSL_SESSION are
- * the ones to be 'copied' into these ones */
- int mac_flags;
- EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
- EVP_MD_CTX *read_hash; /* used for mac generation */
-#ifndef OPENSSL_NO_COMP
- COMP_CTX *expand; /* uncompress */
-#else
- char *expand;
-#endif
-
- EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
- EVP_MD_CTX *write_hash; /* used for mac generation */
-#ifndef OPENSSL_NO_COMP
- COMP_CTX *compress; /* compression */
-#else
- char *compress;
-#endif
-
- /* session info */
-
- /* client cert? */
- /* This is used to hold the server certificate used */
- struct cert_st /* CERT */ *cert;
-
- /* the session_id_context is used to ensure sessions are only reused
- * in the appropriate context */
- unsigned int sid_ctx_length;
- unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
-
- /* This can also be in the session once a session is established */
- SSL_SESSION *session;
-
- /* Default generate session ID callback. */
- GEN_SESSION_CB generate_session_id;
-
- /* Used in SSL2 and SSL3 */
- int verify_mode; /* 0 don't care about verify failure.
- * 1 fail if verify fails */
- int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */
-
- void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */
-
- int error; /* error bytes to be written */
- int error_code; /* actual code */
-
-#ifndef OPENSSL_NO_KRB5
- KSSL_CTX *kssl_ctx; /* Kerberos 5 context */
-#endif /* OPENSSL_NO_KRB5 */
-
-#ifndef OPENSSL_NO_PSK
- unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
- unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len);
- unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len);
-#endif
-
- SSL_CTX *ctx;
- /* set this flag to 1 and a sleep(1) is put into all SSL_read()
- * and SSL_write() calls, good for nbio debuging :-) */
- int debug;
-
- /* extra application data */
- long verify_result;
- CRYPTO_EX_DATA ex_data;
-
- /* for server side, keep the list of CA_dn we can use */
- STACK_OF(X509_NAME) *client_CA;
-
- int references;
- unsigned long options; /* protocol behaviour */
- unsigned long mode; /* API behaviour */
- long max_cert_list;
- int first_packet;
- int client_version; /* what was passed, used for
- * SSLv3/TLS rollback check */
- unsigned int max_send_fragment;
-#ifndef OPENSSL_NO_TLSEXT
- /* TLS extension debug callback */
- void (*tlsext_debug_cb)(SSL *s, int client_server, int type,
- unsigned char *data, int len,
- void *arg);
- void *tlsext_debug_arg;
- char *tlsext_hostname;
- int servername_done; /* no further mod of servername
- 0 : call the servername extension callback.
- 1 : prepare 2, allow last ack just after in server callback.
- 2 : don't call servername callback, no ack in server hello
- */
- /* certificate status request info */
- /* Status type or -1 if no status type */
- int tlsext_status_type;
- /* Expect OCSP CertificateStatus message */
- int tlsext_status_expected;
- /* OCSP status request only */
- STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
- X509_EXTENSIONS *tlsext_ocsp_exts;
- /* OCSP response received or to be sent */
- unsigned char *tlsext_ocsp_resp;
- int tlsext_ocsp_resplen;
-
- /* RFC4507 session ticket expected to be received or sent */
- int tlsext_ticket_expected;
-#ifndef OPENSSL_NO_EC
- size_t tlsext_ecpointformatlist_length;
- unsigned char *tlsext_ecpointformatlist; /* our list */
- size_t tlsext_ellipticcurvelist_length;
- unsigned char *tlsext_ellipticcurvelist; /* our list */
-#endif /* OPENSSL_NO_EC */
-
- /* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */
- void *tlsext_opaque_prf_input;
- size_t tlsext_opaque_prf_input_len;
-
- /* TLS Session Ticket extension override */
- TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
-
- /* TLS Session Ticket extension callback */
- tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
- void *tls_session_ticket_ext_cb_arg;
-
- /* TLS pre-shared secret session resumption */
- tls_session_secret_cb_fn tls_session_secret_cb;
- void *tls_session_secret_cb_arg;
-
- SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- /* Next protocol negotiation. For the client, this is the protocol that
- * we sent in NextProtocol and is set when handling ServerHello
- * extensions.
- *
- * For a server, this is the client's selected_protocol from
- * NextProtocol and is set when handling the NextProtocol message,
- * before the Finished message. */
- unsigned char *next_proto_negotiated;
- unsigned char next_proto_negotiated_len;
-#endif
-
-#define session_ctx initial_ctx
-
- STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; /* What we'll do */
- SRTP_PROTECTION_PROFILE *srtp_profile; /* What's been chosen */
-
- unsigned int tlsext_heartbeat; /* Is use of the Heartbeat extension negotiated?
- 0: disabled
- 1: enabled
- 2: enabled, but not allowed to send Requests
- */
- unsigned int tlsext_hb_pending; /* Indicates if a HeartbeatRequest is in flight */
- unsigned int tlsext_hb_seq; /* HeartbeatRequest sequence number */
-#else
-#define session_ctx ctx
-#endif /* OPENSSL_NO_TLSEXT */
-
- int renegotiate;/* 1 if we are renegotiating.
- * 2 if we are a server and are inside a handshake
- * (i.e. not just sending a HelloRequest) */
-
-#ifndef OPENSSL_NO_SRP
- SRP_CTX srp_ctx; /* ctx for SRP authentication */
-#endif
- };
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#include <openssl/ssl2.h>
-#include <openssl/ssl3.h>
-#include <openssl/tls1.h> /* This is mostly sslv3 with a few tweaks */
-#include <openssl/dtls1.h> /* Datagram TLS */
-#include <openssl/ssl23.h>
-#include <openssl/srtp.h> /* Support for the use_srtp extension */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* compatibility */
-#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
-#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
-#define SSL_SESSION_set_app_data(s,a) (SSL_SESSION_set_ex_data(s,0,(char *)a))
-#define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s,0))
-#define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx,0))
-#define SSL_CTX_set_app_data(ctx,arg) (SSL_CTX_set_ex_data(ctx,0,(char *)arg))
-
-/* The following are the possible values for ssl->state are are
- * used to indicate where we are up to in the SSL connection establishment.
- * The macros that follow are about the only things you should need to use
- * and even then, only when using non-blocking IO.
- * It can also be useful to work out where you were when the connection
- * failed */
-
-#define SSL_ST_CONNECT 0x1000
-#define SSL_ST_ACCEPT 0x2000
-#define SSL_ST_MASK 0x0FFF
-#define SSL_ST_INIT (SSL_ST_CONNECT|SSL_ST_ACCEPT)
-#define SSL_ST_BEFORE 0x4000
-#define SSL_ST_OK 0x03
-#define SSL_ST_RENEGOTIATE (0x04|SSL_ST_INIT)
-
-#define SSL_CB_LOOP 0x01
-#define SSL_CB_EXIT 0x02
-#define SSL_CB_READ 0x04
-#define SSL_CB_WRITE 0x08
-#define SSL_CB_ALERT 0x4000 /* used in callback */
-#define SSL_CB_READ_ALERT (SSL_CB_ALERT|SSL_CB_READ)
-#define SSL_CB_WRITE_ALERT (SSL_CB_ALERT|SSL_CB_WRITE)
-#define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT|SSL_CB_LOOP)
-#define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT|SSL_CB_EXIT)
-#define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT|SSL_CB_LOOP)
-#define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT|SSL_CB_EXIT)
-#define SSL_CB_HANDSHAKE_START 0x10
-#define SSL_CB_HANDSHAKE_DONE 0x20
-
-/* Is the SSL_connection established? */
-#define SSL_get_state(a) SSL_state(a)
-#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK)
-#define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT)
-#define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE)
-#define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT)
-#define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT)
-
-/* The following 2 states are kept in ssl->rstate when reads fail,
- * you should not need these */
-#define SSL_ST_READ_HEADER 0xF0
-#define SSL_ST_READ_BODY 0xF1
-#define SSL_ST_READ_DONE 0xF2
-
-/* Obtain latest Finished message
- * -- that we sent (SSL_get_finished)
- * -- that we expected from peer (SSL_get_peer_finished).
- * Returns length (0 == no Finished so far), copies up to 'count' bytes. */
-size_t SSL_get_finished(const SSL *s, void *buf, size_t count);
-size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
-
-/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options
- * are 'ored' with SSL_VERIFY_PEER if they are desired */
-#define SSL_VERIFY_NONE 0x00
-#define SSL_VERIFY_PEER 0x01
-#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
-#define SSL_VERIFY_CLIENT_ONCE 0x04
-
-#define OpenSSL_add_ssl_algorithms() SSL_library_init()
-#define SSLeay_add_ssl_algorithms() SSL_library_init()
-
-/* this is for backward compatibility */
-#if 0 /* NEW_SSLEAY */
-#define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c)
-#define SSL_set_pref_cipher(c,n) SSL_set_cipher_list(c,n)
-#define SSL_add_session(a,b) SSL_CTX_add_session((a),(b))
-#define SSL_remove_session(a,b) SSL_CTX_remove_session((a),(b))
-#define SSL_flush_sessions(a,b) SSL_CTX_flush_sessions((a),(b))
-#endif
-/* More backward compatibility */
-#define SSL_get_cipher(s) \
- SSL_CIPHER_get_name(SSL_get_current_cipher(s))
-#define SSL_get_cipher_bits(s,np) \
- SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np)
-#define SSL_get_cipher_version(s) \
- SSL_CIPHER_get_version(SSL_get_current_cipher(s))
-#define SSL_get_cipher_name(s) \
- SSL_CIPHER_get_name(SSL_get_current_cipher(s))
-#define SSL_get_time(a) SSL_SESSION_get_time(a)
-#define SSL_set_time(a,b) SSL_SESSION_set_time((a),(b))
-#define SSL_get_timeout(a) SSL_SESSION_get_timeout(a)
-#define SSL_set_timeout(a,b) SSL_SESSION_set_timeout((a),(b))
-
-#define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id)
-#define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id)
-
-DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
-
-#define SSL_AD_REASON_OFFSET 1000 /* offset to get SSL_R_... value from SSL_AD_... */
-
-/* These alert types are for SSLv3 and TLSv1 */
-#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY
-#define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE /* fatal */
-#define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC /* fatal */
-#define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED
-#define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW
-#define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE/* fatal */
-#define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE/* fatal */
-#define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE /* Not for TLS */
-#define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE
-#define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE
-#define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED
-#define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED
-#define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN
-#define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER /* fatal */
-#define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA /* fatal */
-#define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED /* fatal */
-#define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR /* fatal */
-#define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR
-#define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION/* fatal */
-#define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION /* fatal */
-#define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY/* fatal */
-#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR /* fatal */
-#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED
-#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION
-#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION
-#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
-#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME
-#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE
-#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE
-#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */
-
-#define SSL_ERROR_NONE 0
-#define SSL_ERROR_SSL 1
-#define SSL_ERROR_WANT_READ 2
-#define SSL_ERROR_WANT_WRITE 3
-#define SSL_ERROR_WANT_X509_LOOKUP 4
-#define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */
-#define SSL_ERROR_ZERO_RETURN 6
-#define SSL_ERROR_WANT_CONNECT 7
-#define SSL_ERROR_WANT_ACCEPT 8
-
-#define SSL_CTRL_NEED_TMP_RSA 1
-#define SSL_CTRL_SET_TMP_RSA 2
-#define SSL_CTRL_SET_TMP_DH 3
-#define SSL_CTRL_SET_TMP_ECDH 4
-#define SSL_CTRL_SET_TMP_RSA_CB 5
-#define SSL_CTRL_SET_TMP_DH_CB 6
-#define SSL_CTRL_SET_TMP_ECDH_CB 7
-
-#define SSL_CTRL_GET_SESSION_REUSED 8
-#define SSL_CTRL_GET_CLIENT_CERT_REQUEST 9
-#define SSL_CTRL_GET_NUM_RENEGOTIATIONS 10
-#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11
-#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12
-#define SSL_CTRL_GET_FLAGS 13
-#define SSL_CTRL_EXTRA_CHAIN_CERT 14
-
-#define SSL_CTRL_SET_MSG_CALLBACK 15
-#define SSL_CTRL_SET_MSG_CALLBACK_ARG 16
-
-/* only applies to datagram connections */
-#define SSL_CTRL_SET_MTU 17
-/* Stats */
-#define SSL_CTRL_SESS_NUMBER 20
-#define SSL_CTRL_SESS_CONNECT 21
-#define SSL_CTRL_SESS_CONNECT_GOOD 22
-#define SSL_CTRL_SESS_CONNECT_RENEGOTIATE 23
-#define SSL_CTRL_SESS_ACCEPT 24
-#define SSL_CTRL_SESS_ACCEPT_GOOD 25
-#define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE 26
-#define SSL_CTRL_SESS_HIT 27
-#define SSL_CTRL_SESS_CB_HIT 28
-#define SSL_CTRL_SESS_MISSES 29
-#define SSL_CTRL_SESS_TIMEOUTS 30
-#define SSL_CTRL_SESS_CACHE_FULL 31
-#define SSL_CTRL_OPTIONS 32
-#define SSL_CTRL_MODE 33
-
-#define SSL_CTRL_GET_READ_AHEAD 40
-#define SSL_CTRL_SET_READ_AHEAD 41
-#define SSL_CTRL_SET_SESS_CACHE_SIZE 42
-#define SSL_CTRL_GET_SESS_CACHE_SIZE 43
-#define SSL_CTRL_SET_SESS_CACHE_MODE 44
-#define SSL_CTRL_GET_SESS_CACHE_MODE 45
-
-#define SSL_CTRL_GET_MAX_CERT_LIST 50
-#define SSL_CTRL_SET_MAX_CERT_LIST 51
-
-#define SSL_CTRL_SET_MAX_SEND_FRAGMENT 52
-
-/* see tls1.h for macros based on these */
-#ifndef OPENSSL_NO_TLSEXT
-#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
-#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
-#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
-#define SSL_CTRL_SET_TLSEXT_DEBUG_CB 56
-#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57
-#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58
-#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59
-#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60
-#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61
-#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71
-
-#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72
-
-#define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB 75
-#define SSL_CTRL_SET_SRP_VERIFY_PARAM_CB 76
-#define SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB 77
-
-#define SSL_CTRL_SET_SRP_ARG 78
-#define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME 79
-#define SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH 80
-#define SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD 81
-#ifndef OPENSSL_NO_HEARTBEATS
-#define SSL_CTRL_TLS_EXT_SEND_HEARTBEAT 85
-#define SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING 86
-#define SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS 87
-#endif
-#endif
-
-#define DTLS_CTRL_GET_TIMEOUT 73
-#define DTLS_CTRL_HANDLE_TIMEOUT 74
-#define DTLS_CTRL_LISTEN 75
-
-#define SSL_CTRL_GET_RI_SUPPORT 76
-#define SSL_CTRL_CLEAR_OPTIONS 77
-#define SSL_CTRL_CLEAR_MODE 78
-
-#define SSL_CTRL_GET_EXTRA_CHAIN_CERTS 82
-#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS 83
-
-#define DTLSv1_get_timeout(ssl, arg) \
- SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
-#define DTLSv1_handle_timeout(ssl) \
- SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL)
-#define DTLSv1_listen(ssl, peer) \
- SSL_ctrl(ssl,DTLS_CTRL_LISTEN,0, (void *)peer)
-
-#define SSL_session_reused(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
-#define SSL_num_renegotiations(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL)
-#define SSL_clear_num_renegotiations(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL)
-#define SSL_total_renegotiations(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL)
-
-#define SSL_CTX_need_tmp_RSA(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_NEED_TMP_RSA,0,NULL)
-#define SSL_CTX_set_tmp_rsa(ctx,rsa) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
-#define SSL_CTX_set_tmp_dh(ctx,dh) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
-#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
-
-#define SSL_need_tmp_RSA(ssl) \
- SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL)
-#define SSL_set_tmp_rsa(ssl,rsa) \
- SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
-#define SSL_set_tmp_dh(ssl,dh) \
- SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
-#define SSL_set_tmp_ecdh(ssl,ecdh) \
- SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
-
-#define SSL_CTX_add_extra_chain_cert(ctx,x509) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
-#define SSL_CTX_get_extra_chain_certs(ctx,px509) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_EXTRA_CHAIN_CERTS,0,px509)
-#define SSL_CTX_clear_extra_chain_certs(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS,0,NULL)
-
-#ifndef OPENSSL_NO_BIO
-BIO_METHOD *BIO_f_ssl(void);
-BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
-BIO *BIO_new_ssl_connect(SSL_CTX *ctx);
-BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx);
-int BIO_ssl_copy_session_id(BIO *to,BIO *from);
-void BIO_ssl_shutdown(BIO *ssl_bio);
-
-#endif
-
-int SSL_CTX_set_cipher_list(SSL_CTX *,const char *str);
-SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth);
-void SSL_CTX_free(SSL_CTX *);
-long SSL_CTX_set_timeout(SSL_CTX *ctx,long t);
-long SSL_CTX_get_timeout(const SSL_CTX *ctx);
-X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *);
-void SSL_CTX_set_cert_store(SSL_CTX *,X509_STORE *);
-int SSL_want(const SSL *s);
-int SSL_clear(SSL *s);
-
-void SSL_CTX_flush_sessions(SSL_CTX *ctx,long tm);
-
-const SSL_CIPHER *SSL_get_current_cipher(const SSL *s);
-int SSL_CIPHER_get_bits(const SSL_CIPHER *c,int *alg_bits);
-char * SSL_CIPHER_get_version(const SSL_CIPHER *c);
-const char * SSL_CIPHER_get_name(const SSL_CIPHER *c);
-unsigned long SSL_CIPHER_get_id(const SSL_CIPHER *c);
-
-int SSL_get_fd(const SSL *s);
-int SSL_get_rfd(const SSL *s);
-int SSL_get_wfd(const SSL *s);
-const char * SSL_get_cipher_list(const SSL *s,int n);
-char * SSL_get_shared_ciphers(const SSL *s, char *buf, int len);
-int SSL_get_read_ahead(const SSL * s);
-int SSL_pending(const SSL *s);
-#ifndef OPENSSL_NO_SOCK
-int SSL_set_fd(SSL *s, int fd);
-int SSL_set_rfd(SSL *s, int fd);
-int SSL_set_wfd(SSL *s, int fd);
-#endif
-#ifndef OPENSSL_NO_BIO
-void SSL_set_bio(SSL *s, BIO *rbio,BIO *wbio);
-BIO * SSL_get_rbio(const SSL *s);
-BIO * SSL_get_wbio(const SSL *s);
-#endif
-int SSL_set_cipher_list(SSL *s, const char *str);
-void SSL_set_read_ahead(SSL *s, int yes);
-int SSL_get_verify_mode(const SSL *s);
-int SSL_get_verify_depth(const SSL *s);
-int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *);
-void SSL_set_verify(SSL *s, int mode,
- int (*callback)(int ok,X509_STORE_CTX *ctx));
-void SSL_set_verify_depth(SSL *s, int depth);
-#ifndef OPENSSL_NO_RSA
-int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa);
-#endif
-int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len);
-int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey);
-int SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len);
-int SSL_use_certificate(SSL *ssl, X509 *x);
-int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
-
-#ifndef OPENSSL_NO_STDIO
-int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
-int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type);
-int SSL_use_certificate_file(SSL *ssl, const char *file, int type);
-int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type);
-int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
-int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
-int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); /* PEM type */
-STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file);
-int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
- const char *file);
-#ifndef OPENSSL_SYS_VMS
-#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! [was: #ifndef MAC_OS_pre_X] */
-int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
- const char *dir);
-#endif
-#endif
-
-#endif
-
-void SSL_load_error_strings(void );
-const char *SSL_state_string(const SSL *s);
-const char *SSL_rstate_string(const SSL *s);
-const char *SSL_state_string_long(const SSL *s);
-const char *SSL_rstate_string_long(const SSL *s);
-long SSL_SESSION_get_time(const SSL_SESSION *s);
-long SSL_SESSION_set_time(SSL_SESSION *s, long t);
-long SSL_SESSION_get_timeout(const SSL_SESSION *s);
-long SSL_SESSION_set_timeout(SSL_SESSION *s, long t);
-void SSL_copy_session_id(SSL *to,const SSL *from);
-X509 *SSL_SESSION_get0_peer(SSL_SESSION *s);
-int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx,
- unsigned int sid_ctx_len);
-
-SSL_SESSION *SSL_SESSION_new(void);
-const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s,
- unsigned int *len);
-unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s);
-#ifndef OPENSSL_NO_FP_API
-int SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses);
-#endif
-#ifndef OPENSSL_NO_BIO
-int SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses);
-#endif
-void SSL_SESSION_free(SSL_SESSION *ses);
-int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp);
-int SSL_set_session(SSL *to, SSL_SESSION *session);
-int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c);
-int SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c);
-int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB);
-int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB);
-int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
- unsigned int id_len);
-SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp,
- long length);
-
-#ifdef HEADER_X509_H
-X509 * SSL_get_peer_certificate(const SSL *s);
-#endif
-
-STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s);
-
-int SSL_CTX_get_verify_mode(const SSL_CTX *ctx);
-int SSL_CTX_get_verify_depth(const SSL_CTX *ctx);
-int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *);
-void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,
- int (*callback)(int, X509_STORE_CTX *));
-void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth);
-void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg);
-#ifndef OPENSSL_NO_RSA
-int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa);
-#endif
-int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len);
-int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
-int SSL_CTX_use_PrivateKey_ASN1(int pk,SSL_CTX *ctx,
- const unsigned char *d, long len);
-int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);
-int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d);
-
-void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb);
-void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u);
-
-int SSL_CTX_check_private_key(const SSL_CTX *ctx);
-int SSL_check_private_key(const SSL *ctx);
-
-int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
- unsigned int sid_ctx_len);
-
-SSL * SSL_new(SSL_CTX *ctx);
-int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
- unsigned int sid_ctx_len);
-
-int SSL_CTX_set_purpose(SSL_CTX *s, int purpose);
-int SSL_set_purpose(SSL *s, int purpose);
-int SSL_CTX_set_trust(SSL_CTX *s, int trust);
-int SSL_set_trust(SSL *s, int trust);
-
-int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm);
-int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm);
-
-#ifndef OPENSSL_NO_SRP
-int SSL_CTX_set_srp_username(SSL_CTX *ctx,char *name);
-int SSL_CTX_set_srp_password(SSL_CTX *ctx,char *password);
-int SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength);
-int SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx,
- char *(*cb)(SSL *,void *));
-int SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx,
- int (*cb)(SSL *,void *));
-int SSL_CTX_set_srp_username_callback(SSL_CTX *ctx,
- int (*cb)(SSL *,int *,void *));
-int SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg);
-
-int SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g,
- BIGNUM *sa, BIGNUM *v, char *info);
-int SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass,
- const char *grp);
-
-BIGNUM *SSL_get_srp_g(SSL *s);
-BIGNUM *SSL_get_srp_N(SSL *s);
-
-char *SSL_get_srp_username(SSL *s);
-char *SSL_get_srp_userinfo(SSL *s);
-#endif
-
-void SSL_free(SSL *ssl);
-int SSL_accept(SSL *ssl);
-int SSL_connect(SSL *ssl);
-int SSL_read(SSL *ssl,void *buf,int num);
-int SSL_peek(SSL *ssl,void *buf,int num);
-int SSL_write(SSL *ssl,const void *buf,int num);
-long SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
-long SSL_callback_ctrl(SSL *, int, void (*)(void));
-long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, void *parg);
-long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void));
-
-int SSL_get_error(const SSL *s,int ret_code);
-const char *SSL_get_version(const SSL *s);
-
-/* This sets the 'default' SSL version that SSL_new() will create */
-int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth);
-
-#ifndef OPENSSL_NO_SSL2
-const SSL_METHOD *SSLv2_method(void); /* SSLv2 */
-const SSL_METHOD *SSLv2_server_method(void); /* SSLv2 */
-const SSL_METHOD *SSLv2_client_method(void); /* SSLv2 */
-#endif
-
-const SSL_METHOD *SSLv3_method(void); /* SSLv3 */
-const SSL_METHOD *SSLv3_server_method(void); /* SSLv3 */
-const SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */
-
-const SSL_METHOD *SSLv23_method(void); /* SSLv3 but can rollback to v2 */
-const SSL_METHOD *SSLv23_server_method(void); /* SSLv3 but can rollback to v2 */
-const SSL_METHOD *SSLv23_client_method(void); /* SSLv3 but can rollback to v2 */
-
-const SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */
-const SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */
-const SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */
-
-const SSL_METHOD *TLSv1_1_method(void); /* TLSv1.1 */
-const SSL_METHOD *TLSv1_1_server_method(void); /* TLSv1.1 */
-const SSL_METHOD *TLSv1_1_client_method(void); /* TLSv1.1 */
-
-const SSL_METHOD *TLSv1_2_method(void); /* TLSv1.2 */
-const SSL_METHOD *TLSv1_2_server_method(void); /* TLSv1.2 */
-const SSL_METHOD *TLSv1_2_client_method(void); /* TLSv1.2 */
-
-
-const SSL_METHOD *DTLSv1_method(void); /* DTLSv1.0 */
-const SSL_METHOD *DTLSv1_server_method(void); /* DTLSv1.0 */
-const SSL_METHOD *DTLSv1_client_method(void); /* DTLSv1.0 */
-
-STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
-
-int SSL_do_handshake(SSL *s);
-int SSL_renegotiate(SSL *s);
-int SSL_renegotiate_abbreviated(SSL *s);
-int SSL_renegotiate_pending(SSL *s);
-int SSL_shutdown(SSL *s);
-
-const SSL_METHOD *SSL_get_ssl_method(SSL *s);
-int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method);
-const char *SSL_alert_type_string_long(int value);
-const char *SSL_alert_type_string(int value);
-const char *SSL_alert_desc_string_long(int value);
-const char *SSL_alert_desc_string(int value);
-
-void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list);
-void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list);
-STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s);
-STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s);
-int SSL_add_client_CA(SSL *ssl,X509 *x);
-int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x);
-
-void SSL_set_connect_state(SSL *s);
-void SSL_set_accept_state(SSL *s);
-
-long SSL_get_default_timeout(const SSL *s);
-
-int SSL_library_init(void );
-
-char *SSL_CIPHER_description(const SSL_CIPHER *,char *buf,int size);
-STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk);
-
-SSL *SSL_dup(SSL *ssl);
-
-X509 *SSL_get_certificate(const SSL *ssl);
-/* EVP_PKEY */ struct evp_pkey_st *SSL_get_privatekey(SSL *ssl);
-
-void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode);
-int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx);
-void SSL_set_quiet_shutdown(SSL *ssl,int mode);
-int SSL_get_quiet_shutdown(const SSL *ssl);
-void SSL_set_shutdown(SSL *ssl,int mode);
-int SSL_get_shutdown(const SSL *ssl);
-int SSL_version(const SSL *ssl);
-int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx);
-int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
- const char *CApath);
-#define SSL_get0_session SSL_get_session /* just peek at pointer */
-SSL_SESSION *SSL_get_session(const SSL *ssl);
-SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */
-SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl);
-SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx);
-void SSL_set_info_callback(SSL *ssl,
- void (*cb)(const SSL *ssl,int type,int val));
-void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl,int type,int val);
-int SSL_state(const SSL *ssl);
-void SSL_set_state(SSL *ssl, int state);
-
-void SSL_set_verify_result(SSL *ssl,long v);
-long SSL_get_verify_result(const SSL *ssl);
-
-int SSL_set_ex_data(SSL *ssl,int idx,void *data);
-void *SSL_get_ex_data(const SSL *ssl,int idx);
-int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-
-int SSL_SESSION_set_ex_data(SSL_SESSION *ss,int idx,void *data);
-void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss,int idx);
-int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-
-int SSL_CTX_set_ex_data(SSL_CTX *ssl,int idx,void *data);
-void *SSL_CTX_get_ex_data(const SSL_CTX *ssl,int idx);
-int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-
-int SSL_get_ex_data_X509_STORE_CTX_idx(void );
-
-#define SSL_CTX_sess_set_cache_size(ctx,t) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL)
-#define SSL_CTX_sess_get_cache_size(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL)
-#define SSL_CTX_set_session_cache_mode(ctx,m) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
-#define SSL_CTX_get_session_cache_mode(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL)
-
-#define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx)
-#define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m)
-#define SSL_CTX_get_read_ahead(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL)
-#define SSL_CTX_set_read_ahead(ctx,m) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL)
-#define SSL_CTX_get_max_cert_list(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
-#define SSL_CTX_set_max_cert_list(ctx,m) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
-#define SSL_get_max_cert_list(ssl) \
- SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
-#define SSL_set_max_cert_list(ssl,m) \
- SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
-
-#define SSL_CTX_set_max_send_fragment(ctx,m) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
-#define SSL_set_max_send_fragment(ssl,m) \
- SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
-
- /* NB: the keylength is only applicable when is_export is true */
-#ifndef OPENSSL_NO_RSA
-void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,
- RSA *(*cb)(SSL *ssl,int is_export,
- int keylength));
-
-void SSL_set_tmp_rsa_callback(SSL *ssl,
- RSA *(*cb)(SSL *ssl,int is_export,
- int keylength));
-#endif
-#ifndef OPENSSL_NO_DH
-void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
- DH *(*dh)(SSL *ssl,int is_export,
- int keylength));
-void SSL_set_tmp_dh_callback(SSL *ssl,
- DH *(*dh)(SSL *ssl,int is_export,
- int keylength));
-#endif
-#ifndef OPENSSL_NO_ECDH
-void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,
- EC_KEY *(*ecdh)(SSL *ssl,int is_export,
- int keylength));
-void SSL_set_tmp_ecdh_callback(SSL *ssl,
- EC_KEY *(*ecdh)(SSL *ssl,int is_export,
- int keylength));
-#endif
-
-#ifndef OPENSSL_NO_COMP
-const COMP_METHOD *SSL_get_current_compression(SSL *s);
-const COMP_METHOD *SSL_get_current_expansion(SSL *s);
-const char *SSL_COMP_get_name(const COMP_METHOD *comp);
-STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void);
-int SSL_COMP_add_compression_method(int id,COMP_METHOD *cm);
-#else
-const void *SSL_get_current_compression(SSL *s);
-const void *SSL_get_current_expansion(SSL *s);
-const char *SSL_COMP_get_name(const void *comp);
-void *SSL_COMP_get_compression_methods(void);
-int SSL_COMP_add_compression_method(int id,void *cm);
-#endif
-
-/* TLS extensions functions */
-int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
-
-int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
- void *arg);
-
-/* Pre-shared secret session resumption functions */
-int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-
-void SSL_set_debug(SSL *s, int debug);
-int SSL_cache_hit(SSL *s);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_SSL_strings(void);
-
-/* Error codes for the SSL functions. */
-
-/* Function codes. */
-#define SSL_F_CLIENT_CERTIFICATE 100
-#define SSL_F_CLIENT_FINISHED 167
-#define SSL_F_CLIENT_HELLO 101
-#define SSL_F_CLIENT_MASTER_KEY 102
-#define SSL_F_D2I_SSL_SESSION 103
-#define SSL_F_DO_DTLS1_WRITE 245
-#define SSL_F_DO_SSL3_WRITE 104
-#define SSL_F_DTLS1_ACCEPT 246
-#define SSL_F_DTLS1_ADD_CERT_TO_BUF 295
-#define SSL_F_DTLS1_BUFFER_RECORD 247
-#define SSL_F_DTLS1_CHECK_TIMEOUT_NUM 316
-#define SSL_F_DTLS1_CLIENT_HELLO 248
-#define SSL_F_DTLS1_CONNECT 249
-#define SSL_F_DTLS1_ENC 250
-#define SSL_F_DTLS1_GET_HELLO_VERIFY 251
-#define SSL_F_DTLS1_GET_MESSAGE 252
-#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253
-#define SSL_F_DTLS1_GET_RECORD 254
-#define SSL_F_DTLS1_HANDLE_TIMEOUT 297
-#define SSL_F_DTLS1_HEARTBEAT 305
-#define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255
-#define SSL_F_DTLS1_PREPROCESS_FRAGMENT 288
-#define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256
-#define SSL_F_DTLS1_PROCESS_RECORD 257
-#define SSL_F_DTLS1_READ_BYTES 258
-#define SSL_F_DTLS1_READ_FAILED 259
-#define SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST 260
-#define SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE 261
-#define SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE 262
-#define SSL_F_DTLS1_SEND_CLIENT_VERIFY 263
-#define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST 264
-#define SSL_F_DTLS1_SEND_SERVER_CERTIFICATE 265
-#define SSL_F_DTLS1_SEND_SERVER_HELLO 266
-#define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE 267
-#define SSL_F_DTLS1_WRITE_APP_DATA_BYTES 268
-#define SSL_F_GET_CLIENT_FINISHED 105
-#define SSL_F_GET_CLIENT_HELLO 106
-#define SSL_F_GET_CLIENT_MASTER_KEY 107
-#define SSL_F_GET_SERVER_FINISHED 108
-#define SSL_F_GET_SERVER_HELLO 109
-#define SSL_F_GET_SERVER_VERIFY 110
-#define SSL_F_I2D_SSL_SESSION 111
-#define SSL_F_READ_N 112
-#define SSL_F_REQUEST_CERTIFICATE 113
-#define SSL_F_SERVER_FINISH 239
-#define SSL_F_SERVER_HELLO 114
-#define SSL_F_SERVER_VERIFY 240
-#define SSL_F_SSL23_ACCEPT 115
-#define SSL_F_SSL23_CLIENT_HELLO 116
-#define SSL_F_SSL23_CONNECT 117
-#define SSL_F_SSL23_GET_CLIENT_HELLO 118
-#define SSL_F_SSL23_GET_SERVER_HELLO 119
-#define SSL_F_SSL23_PEEK 237
-#define SSL_F_SSL23_READ 120
-#define SSL_F_SSL23_WRITE 121
-#define SSL_F_SSL2_ACCEPT 122
-#define SSL_F_SSL2_CONNECT 123
-#define SSL_F_SSL2_ENC_INIT 124
-#define SSL_F_SSL2_GENERATE_KEY_MATERIAL 241
-#define SSL_F_SSL2_PEEK 234
-#define SSL_F_SSL2_READ 125
-#define SSL_F_SSL2_READ_INTERNAL 236
-#define SSL_F_SSL2_SET_CERTIFICATE 126
-#define SSL_F_SSL2_WRITE 127
-#define SSL_F_SSL3_ACCEPT 128
-#define SSL_F_SSL3_ADD_CERT_TO_BUF 296
-#define SSL_F_SSL3_CALLBACK_CTRL 233
-#define SSL_F_SSL3_CHANGE_CIPHER_STATE 129
-#define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130
-#define SSL_F_SSL3_CHECK_CLIENT_HELLO 304
-#define SSL_F_SSL3_CLIENT_HELLO 131
-#define SSL_F_SSL3_CONNECT 132
-#define SSL_F_SSL3_CTRL 213
-#define SSL_F_SSL3_CTX_CTRL 133
-#define SSL_F_SSL3_DIGEST_CACHED_RECORDS 293
-#define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC 292
-#define SSL_F_SSL3_ENC 134
-#define SSL_F_SSL3_GENERATE_KEY_BLOCK 238
-#define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135
-#define SSL_F_SSL3_GET_CERT_STATUS 289
-#define SSL_F_SSL3_GET_CERT_VERIFY 136
-#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137
-#define SSL_F_SSL3_GET_CLIENT_HELLO 138
-#define SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE 139
-#define SSL_F_SSL3_GET_FINISHED 140
-#define SSL_F_SSL3_GET_KEY_EXCHANGE 141
-#define SSL_F_SSL3_GET_MESSAGE 142
-#define SSL_F_SSL3_GET_NEW_SESSION_TICKET 283
-#define SSL_F_SSL3_GET_NEXT_PROTO 306
-#define SSL_F_SSL3_GET_RECORD 143
-#define SSL_F_SSL3_GET_SERVER_CERTIFICATE 144
-#define SSL_F_SSL3_GET_SERVER_DONE 145
-#define SSL_F_SSL3_GET_SERVER_HELLO 146
-#define SSL_F_SSL3_HANDSHAKE_MAC 285
-#define SSL_F_SSL3_NEW_SESSION_TICKET 287
-#define SSL_F_SSL3_OUTPUT_CERT_CHAIN 147
-#define SSL_F_SSL3_PEEK 235
-#define SSL_F_SSL3_READ_BYTES 148
-#define SSL_F_SSL3_READ_N 149
-#define SSL_F_SSL3_SEND_CERTIFICATE_REQUEST 150
-#define SSL_F_SSL3_SEND_CLIENT_CERTIFICATE 151
-#define SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE 152
-#define SSL_F_SSL3_SEND_CLIENT_VERIFY 153
-#define SSL_F_SSL3_SEND_SERVER_CERTIFICATE 154
-#define SSL_F_SSL3_SEND_SERVER_HELLO 242
-#define SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE 155
-#define SSL_F_SSL3_SETUP_KEY_BLOCK 157
-#define SSL_F_SSL3_SETUP_READ_BUFFER 156
-#define SSL_F_SSL3_SETUP_WRITE_BUFFER 291
-#define SSL_F_SSL3_WRITE_BYTES 158
-#define SSL_F_SSL3_WRITE_PENDING 159
-#define SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT 298
-#define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 277
-#define SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT 307
-#define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215
-#define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216
-#define SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT 299
-#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 278
-#define SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT 308
-#define SSL_F_SSL_BAD_METHOD 160
-#define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161
-#define SSL_F_SSL_CERT_DUP 221
-#define SSL_F_SSL_CERT_INST 222
-#define SSL_F_SSL_CERT_INSTANTIATE 214
-#define SSL_F_SSL_CERT_NEW 162
-#define SSL_F_SSL_CHECK_PRIVATE_KEY 163
-#define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 280
-#define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG 279
-#define SSL_F_SSL_CIPHER_PROCESS_RULESTR 230
-#define SSL_F_SSL_CIPHER_STRENGTH_SORT 231
-#define SSL_F_SSL_CLEAR 164
-#define SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD 165
-#define SSL_F_SSL_CREATE_CIPHER_LIST 166
-#define SSL_F_SSL_CTRL 232
-#define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY 168
-#define SSL_F_SSL_CTX_MAKE_PROFILES 309
-#define SSL_F_SSL_CTX_NEW 169
-#define SSL_F_SSL_CTX_SET_CIPHER_LIST 269
-#define SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE 290
-#define SSL_F_SSL_CTX_SET_PURPOSE 226
-#define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219
-#define SSL_F_SSL_CTX_SET_SSL_VERSION 170
-#define SSL_F_SSL_CTX_SET_TRUST 229
-#define SSL_F_SSL_CTX_USE_CERTIFICATE 171
-#define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172
-#define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE 220
-#define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173
-#define SSL_F_SSL_CTX_USE_PRIVATEKEY 174
-#define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175
-#define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE 176
-#define SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT 272
-#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY 177
-#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1 178
-#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179
-#define SSL_F_SSL_DO_HANDSHAKE 180
-#define SSL_F_SSL_GET_NEW_SESSION 181
-#define SSL_F_SSL_GET_PREV_SESSION 217
-#define SSL_F_SSL_GET_SERVER_SEND_CERT 182
-#define SSL_F_SSL_GET_SERVER_SEND_PKEY 317
-#define SSL_F_SSL_GET_SIGN_PKEY 183
-#define SSL_F_SSL_INIT_WBIO_BUFFER 184
-#define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185
-#define SSL_F_SSL_NEW 186
-#define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 300
-#define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 302
-#define SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT 310
-#define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 301
-#define SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT 303
-#define SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT 311
-#define SSL_F_SSL_PEEK 270
-#define SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT 281
-#define SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT 282
-#define SSL_F_SSL_READ 223
-#define SSL_F_SSL_RSA_PRIVATE_DECRYPT 187
-#define SSL_F_SSL_RSA_PUBLIC_ENCRYPT 188
-#define SSL_F_SSL_SESSION_NEW 189
-#define SSL_F_SSL_SESSION_PRINT_FP 190
-#define SSL_F_SSL_SESSION_SET1_ID_CONTEXT 312
-#define SSL_F_SSL_SESS_CERT_NEW 225
-#define SSL_F_SSL_SET_CERT 191
-#define SSL_F_SSL_SET_CIPHER_LIST 271
-#define SSL_F_SSL_SET_FD 192
-#define SSL_F_SSL_SET_PKEY 193
-#define SSL_F_SSL_SET_PURPOSE 227
-#define SSL_F_SSL_SET_RFD 194
-#define SSL_F_SSL_SET_SESSION 195
-#define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218
-#define SSL_F_SSL_SET_SESSION_TICKET_EXT 294
-#define SSL_F_SSL_SET_TRUST 228
-#define SSL_F_SSL_SET_WFD 196
-#define SSL_F_SSL_SHUTDOWN 224
-#define SSL_F_SSL_SRP_CTX_INIT 313
-#define SSL_F_SSL_UNDEFINED_CONST_FUNCTION 243
-#define SSL_F_SSL_UNDEFINED_FUNCTION 197
-#define SSL_F_SSL_UNDEFINED_VOID_FUNCTION 244
-#define SSL_F_SSL_USE_CERTIFICATE 198
-#define SSL_F_SSL_USE_CERTIFICATE_ASN1 199
-#define SSL_F_SSL_USE_CERTIFICATE_FILE 200
-#define SSL_F_SSL_USE_PRIVATEKEY 201
-#define SSL_F_SSL_USE_PRIVATEKEY_ASN1 202
-#define SSL_F_SSL_USE_PRIVATEKEY_FILE 203
-#define SSL_F_SSL_USE_PSK_IDENTITY_HINT 273
-#define SSL_F_SSL_USE_RSAPRIVATEKEY 204
-#define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1 205
-#define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206
-#define SSL_F_SSL_VERIFY_CERT_CHAIN 207
-#define SSL_F_SSL_WRITE 208
-#define SSL_F_TLS1_CERT_VERIFY_MAC 286
-#define SSL_F_TLS1_CHANGE_CIPHER_STATE 209
-#define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274
-#define SSL_F_TLS1_ENC 210
-#define SSL_F_TLS1_EXPORT_KEYING_MATERIAL 314
-#define SSL_F_TLS1_HEARTBEAT 315
-#define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT 275
-#define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT 276
-#define SSL_F_TLS1_PRF 284
-#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
-#define SSL_F_WRITE_PENDING 212
-
-/* Reason codes. */
-#define SSL_R_APP_DATA_IN_HANDSHAKE 100
-#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
-#define SSL_R_BAD_ALERT_RECORD 101
-#define SSL_R_BAD_AUTHENTICATION_TYPE 102
-#define SSL_R_BAD_CHANGE_CIPHER_SPEC 103
-#define SSL_R_BAD_CHECKSUM 104
-#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106
-#define SSL_R_BAD_DECOMPRESSION 107
-#define SSL_R_BAD_DH_G_LENGTH 108
-#define SSL_R_BAD_DH_PUB_KEY_LENGTH 109
-#define SSL_R_BAD_DH_P_LENGTH 110
-#define SSL_R_BAD_DIGEST_LENGTH 111
-#define SSL_R_BAD_DSA_SIGNATURE 112
-#define SSL_R_BAD_ECC_CERT 304
-#define SSL_R_BAD_ECDSA_SIGNATURE 305
-#define SSL_R_BAD_ECPOINT 306
-#define SSL_R_BAD_HANDSHAKE_LENGTH 332
-#define SSL_R_BAD_HELLO_REQUEST 105
-#define SSL_R_BAD_LENGTH 271
-#define SSL_R_BAD_MAC_DECODE 113
-#define SSL_R_BAD_MAC_LENGTH 333
-#define SSL_R_BAD_MESSAGE_TYPE 114
-#define SSL_R_BAD_PACKET_LENGTH 115
-#define SSL_R_BAD_PROTOCOL_VERSION_NUMBER 116
-#define SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH 316
-#define SSL_R_BAD_RESPONSE_ARGUMENT 117
-#define SSL_R_BAD_RSA_DECRYPT 118
-#define SSL_R_BAD_RSA_ENCRYPT 119
-#define SSL_R_BAD_RSA_E_LENGTH 120
-#define SSL_R_BAD_RSA_MODULUS_LENGTH 121
-#define SSL_R_BAD_RSA_SIGNATURE 122
-#define SSL_R_BAD_SIGNATURE 123
-#define SSL_R_BAD_SRP_A_LENGTH 347
-#define SSL_R_BAD_SRP_B_LENGTH 348
-#define SSL_R_BAD_SRP_G_LENGTH 349
-#define SSL_R_BAD_SRP_N_LENGTH 350
-#define SSL_R_BAD_SRP_S_LENGTH 351
-#define SSL_R_BAD_SRTP_MKI_VALUE 352
-#define SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST 353
-#define SSL_R_BAD_SSL_FILETYPE 124
-#define SSL_R_BAD_SSL_SESSION_ID_LENGTH 125
-#define SSL_R_BAD_STATE 126
-#define SSL_R_BAD_WRITE_RETRY 127
-#define SSL_R_BIO_NOT_SET 128
-#define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 129
-#define SSL_R_BN_LIB 130
-#define SSL_R_CA_DN_LENGTH_MISMATCH 131
-#define SSL_R_CA_DN_TOO_LONG 132
-#define SSL_R_CCS_RECEIVED_EARLY 133
-#define SSL_R_CERTIFICATE_VERIFY_FAILED 134
-#define SSL_R_CERT_LENGTH_MISMATCH 135
-#define SSL_R_CHALLENGE_IS_DIFFERENT 136
-#define SSL_R_CIPHER_CODE_WRONG_LENGTH 137
-#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 138
-#define SSL_R_CIPHER_TABLE_SRC_ERROR 139
-#define SSL_R_CLIENTHELLO_TLSEXT 226
-#define SSL_R_COMPRESSED_LENGTH_TOO_LONG 140
-#define SSL_R_COMPRESSION_DISABLED 343
-#define SSL_R_COMPRESSION_FAILURE 141
-#define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307
-#define SSL_R_COMPRESSION_LIBRARY_ERROR 142
-#define SSL_R_CONNECTION_ID_IS_DIFFERENT 143
-#define SSL_R_CONNECTION_TYPE_NOT_SET 144
-#define SSL_R_COOKIE_MISMATCH 308
-#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145
-#define SSL_R_DATA_LENGTH_TOO_LONG 146
-#define SSL_R_DECRYPTION_FAILED 147
-#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281
-#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148
-#define SSL_R_DIGEST_CHECK_FAILED 149
-#define SSL_R_DTLS_MESSAGE_TOO_BIG 334
-#define SSL_R_DUPLICATE_COMPRESSION_ID 309
-#define SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT 317
-#define SSL_R_ECC_CERT_NOT_FOR_SIGNING 318
-#define SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE 322
-#define SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE 323
-#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310
-#define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354
-#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150
-#define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 282
-#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151
-#define SSL_R_EXCESSIVE_MESSAGE_SIZE 152
-#define SSL_R_EXTRA_DATA_IN_MESSAGE 153
-#define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154
-#define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 355
-#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 356
-#define SSL_R_HTTPS_PROXY_REQUEST 155
-#define SSL_R_HTTP_REQUEST 156
-#define SSL_R_ILLEGAL_PADDING 283
-#define SSL_R_INCONSISTENT_COMPRESSION 340
-#define SSL_R_INVALID_CHALLENGE_LENGTH 158
-#define SSL_R_INVALID_COMMAND 280
-#define SSL_R_INVALID_COMPRESSION_ALGORITHM 341
-#define SSL_R_INVALID_PURPOSE 278
-#define SSL_R_INVALID_SRP_USERNAME 357
-#define SSL_R_INVALID_STATUS_RESPONSE 328
-#define SSL_R_INVALID_TICKET_KEYS_LENGTH 325
-#define SSL_R_INVALID_TRUST 279
-#define SSL_R_KEY_ARG_TOO_LONG 284
-#define SSL_R_KRB5 285
-#define SSL_R_KRB5_C_CC_PRINC 286
-#define SSL_R_KRB5_C_GET_CRED 287
-#define SSL_R_KRB5_C_INIT 288
-#define SSL_R_KRB5_C_MK_REQ 289
-#define SSL_R_KRB5_S_BAD_TICKET 290
-#define SSL_R_KRB5_S_INIT 291
-#define SSL_R_KRB5_S_RD_REQ 292
-#define SSL_R_KRB5_S_TKT_EXPIRED 293
-#define SSL_R_KRB5_S_TKT_NYV 294
-#define SSL_R_KRB5_S_TKT_SKEW 295
-#define SSL_R_LENGTH_MISMATCH 159
-#define SSL_R_LENGTH_TOO_SHORT 160
-#define SSL_R_LIBRARY_BUG 274
-#define SSL_R_LIBRARY_HAS_NO_CIPHERS 161
-#define SSL_R_MESSAGE_TOO_LONG 296
-#define SSL_R_MISSING_DH_DSA_CERT 162
-#define SSL_R_MISSING_DH_KEY 163
-#define SSL_R_MISSING_DH_RSA_CERT 164
-#define SSL_R_MISSING_DSA_SIGNING_CERT 165
-#define SSL_R_MISSING_EXPORT_TMP_DH_KEY 166
-#define SSL_R_MISSING_EXPORT_TMP_RSA_KEY 167
-#define SSL_R_MISSING_RSA_CERTIFICATE 168
-#define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169
-#define SSL_R_MISSING_RSA_SIGNING_CERT 170
-#define SSL_R_MISSING_SRP_PARAM 358
-#define SSL_R_MISSING_TMP_DH_KEY 171
-#define SSL_R_MISSING_TMP_ECDH_KEY 311
-#define SSL_R_MISSING_TMP_RSA_KEY 172
-#define SSL_R_MISSING_TMP_RSA_PKEY 173
-#define SSL_R_MISSING_VERIFY_MESSAGE 174
-#define SSL_R_MULTIPLE_SGC_RESTARTS 346
-#define SSL_R_NON_SSLV2_INITIAL_PACKET 175
-#define SSL_R_NO_CERTIFICATES_RETURNED 176
-#define SSL_R_NO_CERTIFICATE_ASSIGNED 177
-#define SSL_R_NO_CERTIFICATE_RETURNED 178
-#define SSL_R_NO_CERTIFICATE_SET 179
-#define SSL_R_NO_CERTIFICATE_SPECIFIED 180
-#define SSL_R_NO_CIPHERS_AVAILABLE 181
-#define SSL_R_NO_CIPHERS_PASSED 182
-#define SSL_R_NO_CIPHERS_SPECIFIED 183
-#define SSL_R_NO_CIPHER_LIST 184
-#define SSL_R_NO_CIPHER_MATCH 185
-#define SSL_R_NO_CLIENT_CERT_METHOD 331
-#define SSL_R_NO_CLIENT_CERT_RECEIVED 186
-#define SSL_R_NO_COMPRESSION_SPECIFIED 187
-#define SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER 330
-#define SSL_R_NO_METHOD_SPECIFIED 188
-#define SSL_R_NO_PRIVATEKEY 189
-#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190
-#define SSL_R_NO_PROTOCOLS_AVAILABLE 191
-#define SSL_R_NO_PUBLICKEY 192
-#define SSL_R_NO_RENEGOTIATION 339
-#define SSL_R_NO_REQUIRED_DIGEST 324
-#define SSL_R_NO_SHARED_CIPHER 193
-#define SSL_R_NO_SRTP_PROFILES 359
-#define SSL_R_NO_VERIFY_CALLBACK 194
-#define SSL_R_NULL_SSL_CTX 195
-#define SSL_R_NULL_SSL_METHOD_PASSED 196
-#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197
-#define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344
-#define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297
-#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 327
-#define SSL_R_PACKET_LENGTH_TOO_LONG 198
-#define SSL_R_PARSE_TLSEXT 227
-#define SSL_R_PATH_TOO_LONG 270
-#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199
-#define SSL_R_PEER_ERROR 200
-#define SSL_R_PEER_ERROR_CERTIFICATE 201
-#define SSL_R_PEER_ERROR_NO_CERTIFICATE 202
-#define SSL_R_PEER_ERROR_NO_CIPHER 203
-#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 204
-#define SSL_R_PRE_MAC_LENGTH_TOO_LONG 205
-#define SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS 206
-#define SSL_R_PROTOCOL_IS_SHUTDOWN 207
-#define SSL_R_PSK_IDENTITY_NOT_FOUND 223
-#define SSL_R_PSK_NO_CLIENT_CB 224
-#define SSL_R_PSK_NO_SERVER_CB 225
-#define SSL_R_PUBLIC_KEY_ENCRYPT_ERROR 208
-#define SSL_R_PUBLIC_KEY_IS_NOT_RSA 209
-#define SSL_R_PUBLIC_KEY_NOT_RSA 210
-#define SSL_R_READ_BIO_NOT_SET 211
-#define SSL_R_READ_TIMEOUT_EXPIRED 312
-#define SSL_R_READ_WRONG_PACKET_TYPE 212
-#define SSL_R_RECORD_LENGTH_MISMATCH 213
-#define SSL_R_RECORD_TOO_LARGE 214
-#define SSL_R_RECORD_TOO_SMALL 298
-#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 335
-#define SSL_R_RENEGOTIATION_ENCODING_ERR 336
-#define SSL_R_RENEGOTIATION_MISMATCH 337
-#define SSL_R_REQUIRED_CIPHER_MISSING 215
-#define SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING 342
-#define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216
-#define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217
-#define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 218
-#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 345
-#define SSL_R_SERVERHELLO_TLSEXT 275
-#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277
-#define SSL_R_SHORT_READ 219
-#define SSL_R_SIGNATURE_ALGORITHMS_ERROR 360
-#define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220
-#define SSL_R_SRP_A_CALC 361
-#define SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES 362
-#define SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG 363
-#define SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE 364
-#define SSL_R_SSL23_DOING_SESSION_ID_REUSE 221
-#define SSL_R_SSL2_CONNECTION_ID_TOO_LONG 299
-#define SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT 321
-#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 319
-#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 320
-#define SSL_R_SSL3_SESSION_ID_TOO_LONG 300
-#define SSL_R_SSL3_SESSION_ID_TOO_SHORT 222
-#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042
-#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
-#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045
-#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044
-#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046
-#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030
-#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040
-#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047
-#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041
-#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
-#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043
-#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 228
-#define SSL_R_SSL_HANDSHAKE_FAILURE 229
-#define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS 230
-#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 301
-#define SSL_R_SSL_SESSION_ID_CONFLICT 302
-#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273
-#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303
-#define SSL_R_SSL_SESSION_ID_IS_DIFFERENT 231
-#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049
-#define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050
-#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021
-#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051
-#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060
-#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071
-#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080
-#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100
-#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070
-#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022
-#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048
-#define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090
-#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114
-#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113
-#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111
-#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112
-#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110
-#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232
-#define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT 365
-#define SSL_R_TLS_HEARTBEAT_PENDING 366
-#define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 367
-#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157
-#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
-#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234
-#define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 235
-#define SSL_R_UNABLE_TO_DECODE_DH_CERTS 236
-#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 313
-#define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY 237
-#define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS 238
-#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 314
-#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239
-#define SSL_R_UNABLE_TO_FIND_SSL_METHOD 240
-#define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 241
-#define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242
-#define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243
-#define SSL_R_UNEXPECTED_MESSAGE 244
-#define SSL_R_UNEXPECTED_RECORD 245
-#define SSL_R_UNINITIALIZED 276
-#define SSL_R_UNKNOWN_ALERT_TYPE 246
-#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247
-#define SSL_R_UNKNOWN_CIPHER_RETURNED 248
-#define SSL_R_UNKNOWN_CIPHER_TYPE 249
-#define SSL_R_UNKNOWN_DIGEST 368
-#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250
-#define SSL_R_UNKNOWN_PKEY_TYPE 251
-#define SSL_R_UNKNOWN_PROTOCOL 252
-#define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253
-#define SSL_R_UNKNOWN_SSL_VERSION 254
-#define SSL_R_UNKNOWN_STATE 255
-#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 338
-#define SSL_R_UNSUPPORTED_CIPHER 256
-#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257
-#define SSL_R_UNSUPPORTED_DIGEST_TYPE 326
-#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315
-#define SSL_R_UNSUPPORTED_PROTOCOL 258
-#define SSL_R_UNSUPPORTED_SSL_VERSION 259
-#define SSL_R_UNSUPPORTED_STATUS_TYPE 329
-#define SSL_R_USE_SRTP_NOT_NEGOTIATED 369
-#define SSL_R_WRITE_BIO_NOT_SET 260
-#define SSL_R_WRONG_CIPHER_RETURNED 261
-#define SSL_R_WRONG_MESSAGE_TYPE 262
-#define SSL_R_WRONG_NUMBER_OF_KEY_BITS 263
-#define SSL_R_WRONG_SIGNATURE_LENGTH 264
-#define SSL_R_WRONG_SIGNATURE_SIZE 265
-#define SSL_R_WRONG_SIGNATURE_TYPE 370
-#define SSL_R_WRONG_SSL_VERSION 266
-#define SSL_R_WRONG_VERSION_NUMBER 267
-#define SSL_R_X509_LIB 268
-#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/ssl3.h b/drivers/builtin_openssl/openssl/ssl3.h
deleted file mode 100644
index cb8b2492ec..0000000000
--- a/drivers/builtin_openssl/openssl/ssl3.h
+++ /dev/null
@@ -1,693 +0,0 @@
-/* ssl/ssl3.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECC cipher suite support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-
-#ifndef HEADER_SSL3_H
-#define HEADER_SSL3_H
-
-#ifndef OPENSSL_NO_COMP
-#include <openssl/comp.h>
-#endif
-#include <openssl/buffer.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Signalling cipher suite value: from draft-ietf-tls-renegotiation-03.txt */
-#define SSL3_CK_SCSV 0x030000FF
-
-#define SSL3_CK_RSA_NULL_MD5 0x03000001
-#define SSL3_CK_RSA_NULL_SHA 0x03000002
-#define SSL3_CK_RSA_RC4_40_MD5 0x03000003
-#define SSL3_CK_RSA_RC4_128_MD5 0x03000004
-#define SSL3_CK_RSA_RC4_128_SHA 0x03000005
-#define SSL3_CK_RSA_RC2_40_MD5 0x03000006
-#define SSL3_CK_RSA_IDEA_128_SHA 0x03000007
-#define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008
-#define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009
-#define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A
-
-#define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B
-#define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C
-#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D
-#define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E
-#define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F
-#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010
-
-#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011
-#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012
-#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013
-#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014
-#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015
-#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016
-
-#define SSL3_CK_ADH_RC4_40_MD5 0x03000017
-#define SSL3_CK_ADH_RC4_128_MD5 0x03000018
-#define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019
-#define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A
-#define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B
-
-#if 0
- #define SSL3_CK_FZA_DMS_NULL_SHA 0x0300001C
- #define SSL3_CK_FZA_DMS_FZA_SHA 0x0300001D
- #if 0 /* Because it clashes with KRB5, is never used any more, and is safe
- to remove according to David Hopwood <david.hopwood@zetnet.co.uk>
- of the ietf-tls list */
- #define SSL3_CK_FZA_DMS_RC4_SHA 0x0300001E
- #endif
-#endif
-
-/* VRS Additional Kerberos5 entries
- */
-#define SSL3_CK_KRB5_DES_64_CBC_SHA 0x0300001E
-#define SSL3_CK_KRB5_DES_192_CBC3_SHA 0x0300001F
-#define SSL3_CK_KRB5_RC4_128_SHA 0x03000020
-#define SSL3_CK_KRB5_IDEA_128_CBC_SHA 0x03000021
-#define SSL3_CK_KRB5_DES_64_CBC_MD5 0x03000022
-#define SSL3_CK_KRB5_DES_192_CBC3_MD5 0x03000023
-#define SSL3_CK_KRB5_RC4_128_MD5 0x03000024
-#define SSL3_CK_KRB5_IDEA_128_CBC_MD5 0x03000025
-
-#define SSL3_CK_KRB5_DES_40_CBC_SHA 0x03000026
-#define SSL3_CK_KRB5_RC2_40_CBC_SHA 0x03000027
-#define SSL3_CK_KRB5_RC4_40_SHA 0x03000028
-#define SSL3_CK_KRB5_DES_40_CBC_MD5 0x03000029
-#define SSL3_CK_KRB5_RC2_40_CBC_MD5 0x0300002A
-#define SSL3_CK_KRB5_RC4_40_MD5 0x0300002B
-
-#define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5"
-#define SSL3_TXT_RSA_NULL_SHA "NULL-SHA"
-#define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5"
-#define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5"
-#define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA"
-#define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5"
-#define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA"
-#define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA"
-#define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA"
-#define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA"
-
-#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA"
-#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA"
-#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA"
-#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA"
-#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA"
-#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA"
-
-#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA"
-#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA"
-#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA"
-#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA"
-#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA"
-#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA"
-
-#define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5"
-#define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5"
-#define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA"
-#define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA"
-#define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA"
-
-#if 0
- #define SSL3_TXT_FZA_DMS_NULL_SHA "FZA-NULL-SHA"
- #define SSL3_TXT_FZA_DMS_FZA_SHA "FZA-FZA-CBC-SHA"
- #define SSL3_TXT_FZA_DMS_RC4_SHA "FZA-RC4-SHA"
-#endif
-
-#define SSL3_TXT_KRB5_DES_64_CBC_SHA "KRB5-DES-CBC-SHA"
-#define SSL3_TXT_KRB5_DES_192_CBC3_SHA "KRB5-DES-CBC3-SHA"
-#define SSL3_TXT_KRB5_RC4_128_SHA "KRB5-RC4-SHA"
-#define SSL3_TXT_KRB5_IDEA_128_CBC_SHA "KRB5-IDEA-CBC-SHA"
-#define SSL3_TXT_KRB5_DES_64_CBC_MD5 "KRB5-DES-CBC-MD5"
-#define SSL3_TXT_KRB5_DES_192_CBC3_MD5 "KRB5-DES-CBC3-MD5"
-#define SSL3_TXT_KRB5_RC4_128_MD5 "KRB5-RC4-MD5"
-#define SSL3_TXT_KRB5_IDEA_128_CBC_MD5 "KRB5-IDEA-CBC-MD5"
-
-#define SSL3_TXT_KRB5_DES_40_CBC_SHA "EXP-KRB5-DES-CBC-SHA"
-#define SSL3_TXT_KRB5_RC2_40_CBC_SHA "EXP-KRB5-RC2-CBC-SHA"
-#define SSL3_TXT_KRB5_RC4_40_SHA "EXP-KRB5-RC4-SHA"
-#define SSL3_TXT_KRB5_DES_40_CBC_MD5 "EXP-KRB5-DES-CBC-MD5"
-#define SSL3_TXT_KRB5_RC2_40_CBC_MD5 "EXP-KRB5-RC2-CBC-MD5"
-#define SSL3_TXT_KRB5_RC4_40_MD5 "EXP-KRB5-RC4-MD5"
-
-#define SSL3_SSL_SESSION_ID_LENGTH 32
-#define SSL3_MAX_SSL_SESSION_ID_LENGTH 32
-
-#define SSL3_MASTER_SECRET_SIZE 48
-#define SSL3_RANDOM_SIZE 32
-#define SSL3_SESSION_ID_SIZE 32
-#define SSL3_RT_HEADER_LENGTH 5
-
-#ifndef SSL3_ALIGN_PAYLOAD
- /* Some will argue that this increases memory footprint, but it's
- * not actually true. Point is that malloc has to return at least
- * 64-bit aligned pointers, meaning that allocating 5 bytes wastes
- * 3 bytes in either case. Suggested pre-gaping simply moves these
- * wasted bytes from the end of allocated region to its front,
- * but makes data payload aligned, which improves performance:-) */
-# define SSL3_ALIGN_PAYLOAD 8
-#else
-# if (SSL3_ALIGN_PAYLOAD&(SSL3_ALIGN_PAYLOAD-1))!=0
-# error "insane SSL3_ALIGN_PAYLOAD"
-# undef SSL3_ALIGN_PAYLOAD
-# endif
-#endif
-
-/* This is the maximum MAC (digest) size used by the SSL library.
- * Currently maximum of 20 is used by SHA1, but we reserve for
- * future extension for 512-bit hashes.
- */
-
-#define SSL3_RT_MAX_MD_SIZE 64
-
-/* Maximum block size used in all ciphersuites. Currently 16 for AES.
- */
-
-#define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16
-
-#define SSL3_RT_MAX_EXTRA (16384)
-
-/* Maximum plaintext length: defined by SSL/TLS standards */
-#define SSL3_RT_MAX_PLAIN_LENGTH 16384
-/* Maximum compression overhead: defined by SSL/TLS standards */
-#define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024
-
-/* The standards give a maximum encryption overhead of 1024 bytes.
- * In practice the value is lower than this. The overhead is the maximum
- * number of padding bytes (256) plus the mac size.
- */
-#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE)
-
-/* OpenSSL currently only uses a padding length of at most one block so
- * the send overhead is smaller.
- */
-
-#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \
- (SSL_RT_MAX_CIPHER_BLOCK_SIZE + SSL3_RT_MAX_MD_SIZE)
-
-/* If compression isn't used don't include the compression overhead */
-
-#ifdef OPENSSL_NO_COMP
-#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH
-#else
-#define SSL3_RT_MAX_COMPRESSED_LENGTH \
- (SSL3_RT_MAX_PLAIN_LENGTH+SSL3_RT_MAX_COMPRESSED_OVERHEAD)
-#endif
-#define SSL3_RT_MAX_ENCRYPTED_LENGTH \
- (SSL3_RT_MAX_ENCRYPTED_OVERHEAD+SSL3_RT_MAX_COMPRESSED_LENGTH)
-#define SSL3_RT_MAX_PACKET_SIZE \
- (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
-
-#define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54"
-#define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52"
-
-#define SSL3_VERSION 0x0300
-#define SSL3_VERSION_MAJOR 0x03
-#define SSL3_VERSION_MINOR 0x00
-
-#define SSL3_RT_CHANGE_CIPHER_SPEC 20
-#define SSL3_RT_ALERT 21
-#define SSL3_RT_HANDSHAKE 22
-#define SSL3_RT_APPLICATION_DATA 23
-#define TLS1_RT_HEARTBEAT 24
-
-#define SSL3_AL_WARNING 1
-#define SSL3_AL_FATAL 2
-
-#define SSL3_AD_CLOSE_NOTIFY 0
-#define SSL3_AD_UNEXPECTED_MESSAGE 10 /* fatal */
-#define SSL3_AD_BAD_RECORD_MAC 20 /* fatal */
-#define SSL3_AD_DECOMPRESSION_FAILURE 30 /* fatal */
-#define SSL3_AD_HANDSHAKE_FAILURE 40 /* fatal */
-#define SSL3_AD_NO_CERTIFICATE 41
-#define SSL3_AD_BAD_CERTIFICATE 42
-#define SSL3_AD_UNSUPPORTED_CERTIFICATE 43
-#define SSL3_AD_CERTIFICATE_REVOKED 44
-#define SSL3_AD_CERTIFICATE_EXPIRED 45
-#define SSL3_AD_CERTIFICATE_UNKNOWN 46
-#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */
-
-#define TLS1_HB_REQUEST 1
-#define TLS1_HB_RESPONSE 2
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-typedef struct ssl3_record_st
- {
-/*r */ int type; /* type of record */
-/*rw*/ unsigned int length; /* How many bytes available */
-/*r */ unsigned int off; /* read/write offset into 'buf' */
-/*rw*/ unsigned char *data; /* pointer to the record data */
-/*rw*/ unsigned char *input; /* where the decode bytes are */
-/*r */ unsigned char *comp; /* only used with decompression - malloc()ed */
-/*r */ unsigned long epoch; /* epoch number, needed by DTLS1 */
-/*r */ unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
- } SSL3_RECORD;
-
-typedef struct ssl3_buffer_st
- {
- unsigned char *buf; /* at least SSL3_RT_MAX_PACKET_SIZE bytes,
- * see ssl3_setup_buffers() */
- size_t len; /* buffer size */
- int offset; /* where to 'copy from' */
- int left; /* how many bytes left */
- } SSL3_BUFFER;
-
-#endif
-
-#define SSL3_CT_RSA_SIGN 1
-#define SSL3_CT_DSS_SIGN 2
-#define SSL3_CT_RSA_FIXED_DH 3
-#define SSL3_CT_DSS_FIXED_DH 4
-#define SSL3_CT_RSA_EPHEMERAL_DH 5
-#define SSL3_CT_DSS_EPHEMERAL_DH 6
-#define SSL3_CT_FORTEZZA_DMS 20
-/* SSL3_CT_NUMBER is used to size arrays and it must be large
- * enough to contain all of the cert types defined either for
- * SSLv3 and TLSv1.
- */
-#define SSL3_CT_NUMBER 9
-
-
-#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001
-#define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002
-#define SSL3_FLAGS_POP_BUFFER 0x0004
-#define TLS1_FLAGS_TLS_PADDING_BUG 0x0008
-#define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010
-#define TLS1_FLAGS_KEEP_HANDSHAKE 0x0020
-
-/* SSL3_FLAGS_SGC_RESTART_DONE is set when we
- * restart a handshake because of MS SGC and so prevents us
- * from restarting the handshake in a loop. It's reset on a
- * renegotiation, so effectively limits the client to one restart
- * per negotiation. This limits the possibility of a DDoS
- * attack where the client handshakes in a loop using SGC to
- * restart. Servers which permit renegotiation can still be
- * effected, but we can't prevent that.
- */
-#define SSL3_FLAGS_SGC_RESTART_DONE 0x0040
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-typedef struct ssl3_state_st
- {
- long flags;
- int delay_buf_pop_ret;
-
- unsigned char read_sequence[8];
- int read_mac_secret_size;
- unsigned char read_mac_secret[EVP_MAX_MD_SIZE];
- unsigned char write_sequence[8];
- int write_mac_secret_size;
- unsigned char write_mac_secret[EVP_MAX_MD_SIZE];
-
- unsigned char server_random[SSL3_RANDOM_SIZE];
- unsigned char client_random[SSL3_RANDOM_SIZE];
-
- /* flags for countermeasure against known-IV weakness */
- int need_empty_fragments;
- int empty_fragment_done;
-
- /* The value of 'extra' when the buffers were initialized */
- int init_extra;
-
- SSL3_BUFFER rbuf; /* read IO goes into here */
- SSL3_BUFFER wbuf; /* write IO goes into here */
-
- SSL3_RECORD rrec; /* each decoded record goes in here */
- SSL3_RECORD wrec; /* goes out from here */
-
- /* storage for Alert/Handshake protocol data received but not
- * yet processed by ssl3_read_bytes: */
- unsigned char alert_fragment[2];
- unsigned int alert_fragment_len;
- unsigned char handshake_fragment[4];
- unsigned int handshake_fragment_len;
-
- /* partial write - check the numbers match */
- unsigned int wnum; /* number of bytes sent so far */
- int wpend_tot; /* number bytes written */
- int wpend_type;
- int wpend_ret; /* number of bytes submitted */
- const unsigned char *wpend_buf;
-
- /* used during startup, digest all incoming/outgoing packets */
- BIO *handshake_buffer;
- /* When set of handshake digests is determined, buffer is hashed
- * and freed and MD_CTX-es for all required digests are stored in
- * this array */
- EVP_MD_CTX **handshake_dgst;
- /* this is set whenerver we see a change_cipher_spec message
- * come in when we are not looking for one */
- int change_cipher_spec;
-
- int warn_alert;
- int fatal_alert;
- /* we allow one fatal and one warning alert to be outstanding,
- * send close alert via the warning alert */
- int alert_dispatch;
- unsigned char send_alert[2];
-
- /* This flag is set when we should renegotiate ASAP, basically when
- * there is no more data in the read or write buffers */
- int renegotiate;
- int total_renegotiations;
- int num_renegotiations;
-
- int in_read_app_data;
-
- /* Opaque PRF input as used for the current handshake.
- * These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined
- * (otherwise, they are merely present to improve binary compatibility) */
- void *client_opaque_prf_input;
- size_t client_opaque_prf_input_len;
- void *server_opaque_prf_input;
- size_t server_opaque_prf_input_len;
-
- struct {
- /* actually only needs to be 16+20 */
- unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
-
- /* actually only need to be 16+20 for SSLv3 and 12 for TLS */
- unsigned char finish_md[EVP_MAX_MD_SIZE*2];
- int finish_md_len;
- unsigned char peer_finish_md[EVP_MAX_MD_SIZE*2];
- int peer_finish_md_len;
-
- unsigned long message_size;
- int message_type;
-
- /* used to hold the new cipher we are going to use */
- const SSL_CIPHER *new_cipher;
-#ifndef OPENSSL_NO_DH
- DH *dh;
-#endif
-
-#ifndef OPENSSL_NO_ECDH
- EC_KEY *ecdh; /* holds short lived ECDH key */
-#endif
-
- /* used when SSL_ST_FLUSH_DATA is entered */
- int next_state;
-
- int reuse_message;
-
- /* used for certificate requests */
- int cert_req;
- int ctype_num;
- char ctype[SSL3_CT_NUMBER];
- STACK_OF(X509_NAME) *ca_names;
-
- int use_rsa_tmp;
-
- int key_block_length;
- unsigned char *key_block;
-
- const EVP_CIPHER *new_sym_enc;
- const EVP_MD *new_hash;
- int new_mac_pkey_type;
- int new_mac_secret_size;
-#ifndef OPENSSL_NO_COMP
- const SSL_COMP *new_compression;
-#else
- char *new_compression;
-#endif
- int cert_request;
- } tmp;
-
- /* Connection binding to prevent renegotiation attacks */
- unsigned char previous_client_finished[EVP_MAX_MD_SIZE];
- unsigned char previous_client_finished_len;
- unsigned char previous_server_finished[EVP_MAX_MD_SIZE];
- unsigned char previous_server_finished_len;
- int send_connection_binding; /* TODOEKR */
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- /* Set if we saw the Next Protocol Negotiation extension from our peer. */
- int next_proto_neg_seen;
-#endif
-
-#ifndef OPENSSL_NO_TLSEXT
-#ifndef OPENSSL_NO_EC
- /* This is set to true if we believe that this is a version of Safari
- * running on OS X 10.6 or newer. We wish to know this because Safari
- * on 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */
- char is_probably_safari;
-#endif /* !OPENSSL_NO_EC */
-#endif /* !OPENSSL_NO_TLSEXT */
- } SSL3_STATE;
-
-#endif
-
-/* SSLv3 */
-/*client */
-/* extra state */
-#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT)
-#ifndef OPENSSL_NO_SCTP
-#define DTLS1_SCTP_ST_CW_WRITE_SOCK (0x310|SSL_ST_CONNECT)
-#define DTLS1_SCTP_ST_CR_READ_SOCK (0x320|SSL_ST_CONNECT)
-#endif
-/* write to server */
-#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT)
-/* read from server */
-#define SSL3_ST_CR_SRVR_HELLO_A (0x120|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SRVR_HELLO_B (0x121|SSL_ST_CONNECT)
-#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT)
-#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_A (0x130|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_B (0x131|SSL_ST_CONNECT)
-#define SSL3_ST_CR_KEY_EXCH_A (0x140|SSL_ST_CONNECT)
-#define SSL3_ST_CR_KEY_EXCH_B (0x141|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_REQ_A (0x150|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_REQ_B (0x151|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SRVR_DONE_A (0x160|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SRVR_DONE_B (0x161|SSL_ST_CONNECT)
-/* write to server */
-#define SSL3_ST_CW_CERT_A (0x170|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_B (0x171|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_C (0x172|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_D (0x173|SSL_ST_CONNECT)
-#define SSL3_ST_CW_KEY_EXCH_A (0x180|SSL_ST_CONNECT)
-#define SSL3_ST_CW_KEY_EXCH_B (0x181|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_VRFY_A (0x190|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_VRFY_B (0x191|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CHANGE_A (0x1A0|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CHANGE_B (0x1A1|SSL_ST_CONNECT)
-#ifndef OPENSSL_NO_NEXTPROTONEG
-#define SSL3_ST_CW_NEXT_PROTO_A (0x200|SSL_ST_CONNECT)
-#define SSL3_ST_CW_NEXT_PROTO_B (0x201|SSL_ST_CONNECT)
-#endif
-#define SSL3_ST_CW_FINISHED_A (0x1B0|SSL_ST_CONNECT)
-#define SSL3_ST_CW_FINISHED_B (0x1B1|SSL_ST_CONNECT)
-/* read from server */
-#define SSL3_ST_CR_CHANGE_A (0x1C0|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CHANGE_B (0x1C1|SSL_ST_CONNECT)
-#define SSL3_ST_CR_FINISHED_A (0x1D0|SSL_ST_CONNECT)
-#define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_STATUS_A (0x1F0|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_STATUS_B (0x1F1|SSL_ST_CONNECT)
-
-/* server */
-/* extra state */
-#define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT)
-#ifndef OPENSSL_NO_SCTP
-#define DTLS1_SCTP_ST_SW_WRITE_SOCK (0x310|SSL_ST_ACCEPT)
-#define DTLS1_SCTP_ST_SR_READ_SOCK (0x320|SSL_ST_ACCEPT)
-#endif
-/* read from client */
-/* Do not change the number values, they do matter */
-#define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CLNT_HELLO_B (0x111|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CLNT_HELLO_C (0x112|SSL_ST_ACCEPT)
-/* write to client */
-#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT)
-#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_HELLO_REQ_A (0x120|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_HELLO_REQ_B (0x121|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_HELLO_REQ_C (0x122|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SRVR_HELLO_A (0x130|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SRVR_HELLO_B (0x131|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_A (0x140|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_B (0x141|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_KEY_EXCH_A (0x150|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_KEY_EXCH_B (0x151|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_REQ_A (0x160|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_REQ_B (0x161|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SRVR_DONE_A (0x170|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SRVR_DONE_B (0x171|SSL_ST_ACCEPT)
-/* read from client */
-#define SSL3_ST_SR_CERT_A (0x180|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CERT_B (0x181|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_KEY_EXCH_A (0x190|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_KEY_EXCH_B (0x191|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CERT_VRFY_A (0x1A0|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CERT_VRFY_B (0x1A1|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CHANGE_A (0x1B0|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CHANGE_B (0x1B1|SSL_ST_ACCEPT)
-#ifndef OPENSSL_NO_NEXTPROTONEG
-#define SSL3_ST_SR_NEXT_PROTO_A (0x210|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_NEXT_PROTO_B (0x211|SSL_ST_ACCEPT)
-#endif
-#define SSL3_ST_SR_FINISHED_A (0x1C0|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_FINISHED_B (0x1C1|SSL_ST_ACCEPT)
-/* write to client */
-#define SSL3_ST_SW_CHANGE_A (0x1D0|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CHANGE_B (0x1D1|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_FINISHED_A (0x1E0|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_STATUS_A (0x200|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_STATUS_B (0x201|SSL_ST_ACCEPT)
-
-#define SSL3_MT_HELLO_REQUEST 0
-#define SSL3_MT_CLIENT_HELLO 1
-#define SSL3_MT_SERVER_HELLO 2
-#define SSL3_MT_NEWSESSION_TICKET 4
-#define SSL3_MT_CERTIFICATE 11
-#define SSL3_MT_SERVER_KEY_EXCHANGE 12
-#define SSL3_MT_CERTIFICATE_REQUEST 13
-#define SSL3_MT_SERVER_DONE 14
-#define SSL3_MT_CERTIFICATE_VERIFY 15
-#define SSL3_MT_CLIENT_KEY_EXCHANGE 16
-#define SSL3_MT_FINISHED 20
-#define SSL3_MT_CERTIFICATE_STATUS 22
-#ifndef OPENSSL_NO_NEXTPROTONEG
-#define SSL3_MT_NEXT_PROTO 67
-#endif
-#define DTLS1_MT_HELLO_VERIFY_REQUEST 3
-
-
-#define SSL3_MT_CCS 1
-
-/* These are used when changing over to a new cipher */
-#define SSL3_CC_READ 0x01
-#define SSL3_CC_WRITE 0x02
-#define SSL3_CC_CLIENT 0x10
-#define SSL3_CC_SERVER 0x20
-#define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE)
-#define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ)
-#define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ)
-#define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER|SSL3_CC_WRITE)
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/openssl/stack.h b/drivers/builtin_openssl/openssl/stack.h
deleted file mode 100644
index ce35e554eb..0000000000
--- a/drivers/builtin_openssl/openssl/stack.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* crypto/stack/stack.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_STACK_H
-#define HEADER_STACK_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct stack_st
- {
- int num;
- char **data;
- int sorted;
-
- int num_alloc;
- int (*comp)(const void *, const void *);
- } _STACK; /* Use STACK_OF(...) instead */
-
-#define M_sk_num(sk) ((sk) ? (sk)->num:-1)
-#define M_sk_value(sk,n) ((sk) ? (sk)->data[n] : NULL)
-
-int sk_num(const _STACK *);
-void *sk_value(const _STACK *, int);
-
-void *sk_set(_STACK *, int, void *);
-
-_STACK *sk_new(int (*cmp)(const void *, const void *));
-_STACK *sk_new_null(void);
-void sk_free(_STACK *);
-void sk_pop_free(_STACK *st, void (*func)(void *));
-int sk_insert(_STACK *sk, void *data, int where);
-void *sk_delete(_STACK *st, int loc);
-void *sk_delete_ptr(_STACK *st, void *p);
-int sk_find(_STACK *st, void *data);
-int sk_find_ex(_STACK *st, void *data);
-int sk_push(_STACK *st, void *data);
-int sk_unshift(_STACK *st, void *data);
-void *sk_shift(_STACK *st);
-void *sk_pop(_STACK *st);
-void sk_zero(_STACK *st);
-int (*sk_set_cmp_func(_STACK *sk, int (*c)(const void *, const void *)))
- (const void *, const void *);
-_STACK *sk_dup(_STACK *st);
-void sk_sort(_STACK *st);
-int sk_is_sorted(const _STACK *st);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/symhacks.h b/drivers/builtin_openssl/openssl/symhacks.h
deleted file mode 100644
index bd2f000d59..0000000000
--- a/drivers/builtin_openssl/openssl/symhacks.h
+++ /dev/null
@@ -1,481 +0,0 @@
-/* ====================================================================
- * Copyright (c) 1999 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_SYMHACKS_H
-#define HEADER_SYMHACKS_H
-
-#include <openssl/e_os2.h>
-
-/* Hacks to solve the problem with linkers incapable of handling very long
- symbol names. In the case of VMS, the limit is 31 characters on VMS for
- VAX. */
-/* Note that this affects util/libeay.num and util/ssleay.num... you may
- change those manually, but that's not recommended, as those files are
- controlled centrally and updated on Unix, and the central definition
- may disagree with yours, which in turn may come with shareable library
- incompatibilities. */
-#ifdef OPENSSL_SYS_VMS
-
-/* Hack a long name in crypto/ex_data.c */
-#undef CRYPTO_get_ex_data_implementation
-#define CRYPTO_get_ex_data_implementation CRYPTO_get_ex_data_impl
-#undef CRYPTO_set_ex_data_implementation
-#define CRYPTO_set_ex_data_implementation CRYPTO_set_ex_data_impl
-
-/* Hack a long name in crypto/asn1/a_mbstr.c */
-#undef ASN1_STRING_set_default_mask_asc
-#define ASN1_STRING_set_default_mask_asc ASN1_STRING_set_def_mask_asc
-
-#if 0 /* No longer needed, since safestack macro magic does the job */
-/* Hack the names created with DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO) */
-#undef i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO
-#define i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO i2d_ASN1_SET_OF_PKCS7_SIGINF
-#undef d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO
-#define d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO d2i_ASN1_SET_OF_PKCS7_SIGINF
-#endif
-
-#if 0 /* No longer needed, since safestack macro magic does the job */
-/* Hack the names created with DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO) */
-#undef i2d_ASN1_SET_OF_PKCS7_RECIP_INFO
-#define i2d_ASN1_SET_OF_PKCS7_RECIP_INFO i2d_ASN1_SET_OF_PKCS7_RECINF
-#undef d2i_ASN1_SET_OF_PKCS7_RECIP_INFO
-#define d2i_ASN1_SET_OF_PKCS7_RECIP_INFO d2i_ASN1_SET_OF_PKCS7_RECINF
-#endif
-
-#if 0 /* No longer needed, since safestack macro magic does the job */
-/* Hack the names created with DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION) */
-#undef i2d_ASN1_SET_OF_ACCESS_DESCRIPTION
-#define i2d_ASN1_SET_OF_ACCESS_DESCRIPTION i2d_ASN1_SET_OF_ACC_DESC
-#undef d2i_ASN1_SET_OF_ACCESS_DESCRIPTION
-#define d2i_ASN1_SET_OF_ACCESS_DESCRIPTION d2i_ASN1_SET_OF_ACC_DESC
-#endif
-
-/* Hack the names created with DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE) */
-#undef PEM_read_NETSCAPE_CERT_SEQUENCE
-#define PEM_read_NETSCAPE_CERT_SEQUENCE PEM_read_NS_CERT_SEQ
-#undef PEM_write_NETSCAPE_CERT_SEQUENCE
-#define PEM_write_NETSCAPE_CERT_SEQUENCE PEM_write_NS_CERT_SEQ
-#undef PEM_read_bio_NETSCAPE_CERT_SEQUENCE
-#define PEM_read_bio_NETSCAPE_CERT_SEQUENCE PEM_read_bio_NS_CERT_SEQ
-#undef PEM_write_bio_NETSCAPE_CERT_SEQUENCE
-#define PEM_write_bio_NETSCAPE_CERT_SEQUENCE PEM_write_bio_NS_CERT_SEQ
-#undef PEM_write_cb_bio_NETSCAPE_CERT_SEQUENCE
-#define PEM_write_cb_bio_NETSCAPE_CERT_SEQUENCE PEM_write_cb_bio_NS_CERT_SEQ
-
-/* Hack the names created with DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO) */
-#undef PEM_read_PKCS8_PRIV_KEY_INFO
-#define PEM_read_PKCS8_PRIV_KEY_INFO PEM_read_P8_PRIV_KEY_INFO
-#undef PEM_write_PKCS8_PRIV_KEY_INFO
-#define PEM_write_PKCS8_PRIV_KEY_INFO PEM_write_P8_PRIV_KEY_INFO
-#undef PEM_read_bio_PKCS8_PRIV_KEY_INFO
-#define PEM_read_bio_PKCS8_PRIV_KEY_INFO PEM_read_bio_P8_PRIV_KEY_INFO
-#undef PEM_write_bio_PKCS8_PRIV_KEY_INFO
-#define PEM_write_bio_PKCS8_PRIV_KEY_INFO PEM_write_bio_P8_PRIV_KEY_INFO
-#undef PEM_write_cb_bio_PKCS8_PRIV_KEY_INFO
-#define PEM_write_cb_bio_PKCS8_PRIV_KEY_INFO PEM_wrt_cb_bio_P8_PRIV_KEY_INFO
-
-/* Hack other PEM names */
-#undef PEM_write_bio_PKCS8PrivateKey_nid
-#define PEM_write_bio_PKCS8PrivateKey_nid PEM_write_bio_PKCS8PrivKey_nid
-
-/* Hack some long X509 names */
-#undef X509_REVOKED_get_ext_by_critical
-#define X509_REVOKED_get_ext_by_critical X509_REVOKED_get_ext_by_critic
-#undef X509_policy_tree_get0_user_policies
-#define X509_policy_tree_get0_user_policies X509_pcy_tree_get0_usr_policies
-#undef X509_policy_node_get0_qualifiers
-#define X509_policy_node_get0_qualifiers X509_pcy_node_get0_qualifiers
-#undef X509_STORE_CTX_get_explicit_policy
-#define X509_STORE_CTX_get_explicit_policy X509_STORE_CTX_get_expl_policy
-#undef X509_STORE_CTX_get0_current_issuer
-#define X509_STORE_CTX_get0_current_issuer X509_STORE_CTX_get0_cur_issuer
-
-/* Hack some long CRYPTO names */
-#undef CRYPTO_set_dynlock_destroy_callback
-#define CRYPTO_set_dynlock_destroy_callback CRYPTO_set_dynlock_destroy_cb
-#undef CRYPTO_set_dynlock_create_callback
-#define CRYPTO_set_dynlock_create_callback CRYPTO_set_dynlock_create_cb
-#undef CRYPTO_set_dynlock_lock_callback
-#define CRYPTO_set_dynlock_lock_callback CRYPTO_set_dynlock_lock_cb
-#undef CRYPTO_get_dynlock_lock_callback
-#define CRYPTO_get_dynlock_lock_callback CRYPTO_get_dynlock_lock_cb
-#undef CRYPTO_get_dynlock_destroy_callback
-#define CRYPTO_get_dynlock_destroy_callback CRYPTO_get_dynlock_destroy_cb
-#undef CRYPTO_get_dynlock_create_callback
-#define CRYPTO_get_dynlock_create_callback CRYPTO_get_dynlock_create_cb
-#undef CRYPTO_set_locked_mem_ex_functions
-#define CRYPTO_set_locked_mem_ex_functions CRYPTO_set_locked_mem_ex_funcs
-#undef CRYPTO_get_locked_mem_ex_functions
-#define CRYPTO_get_locked_mem_ex_functions CRYPTO_get_locked_mem_ex_funcs
-
-/* Hack some long SSL names */
-#undef SSL_CTX_set_default_verify_paths
-#define SSL_CTX_set_default_verify_paths SSL_CTX_set_def_verify_paths
-#undef SSL_get_ex_data_X509_STORE_CTX_idx
-#define SSL_get_ex_data_X509_STORE_CTX_idx SSL_get_ex_d_X509_STORE_CTX_idx
-#undef SSL_add_file_cert_subjects_to_stack
-#define SSL_add_file_cert_subjects_to_stack SSL_add_file_cert_subjs_to_stk
-#undef SSL_add_dir_cert_subjects_to_stack
-#define SSL_add_dir_cert_subjects_to_stack SSL_add_dir_cert_subjs_to_stk
-#undef SSL_CTX_use_certificate_chain_file
-#define SSL_CTX_use_certificate_chain_file SSL_CTX_use_cert_chain_file
-#undef SSL_CTX_set_cert_verify_callback
-#define SSL_CTX_set_cert_verify_callback SSL_CTX_set_cert_verify_cb
-#undef SSL_CTX_set_default_passwd_cb_userdata
-#define SSL_CTX_set_default_passwd_cb_userdata SSL_CTX_set_def_passwd_cb_ud
-#undef SSL_COMP_get_compression_methods
-#define SSL_COMP_get_compression_methods SSL_COMP_get_compress_methods
-#undef ssl_add_clienthello_renegotiate_ext
-#define ssl_add_clienthello_renegotiate_ext ssl_add_clienthello_reneg_ext
-#undef ssl_add_serverhello_renegotiate_ext
-#define ssl_add_serverhello_renegotiate_ext ssl_add_serverhello_reneg_ext
-#undef ssl_parse_clienthello_renegotiate_ext
-#define ssl_parse_clienthello_renegotiate_ext ssl_parse_clienthello_reneg_ext
-#undef ssl_parse_serverhello_renegotiate_ext
-#define ssl_parse_serverhello_renegotiate_ext ssl_parse_serverhello_reneg_ext
-#undef SSL_srp_server_param_with_username
-#define SSL_srp_server_param_with_username SSL_srp_server_param_with_un
-#undef SSL_CTX_set_srp_client_pwd_callback
-#define SSL_CTX_set_srp_client_pwd_callback SSL_CTX_set_srp_client_pwd_cb
-#undef SSL_CTX_set_srp_verify_param_callback
-#define SSL_CTX_set_srp_verify_param_callback SSL_CTX_set_srp_vfy_param_cb
-#undef SSL_CTX_set_srp_username_callback
-#define SSL_CTX_set_srp_username_callback SSL_CTX_set_srp_un_cb
-#undef ssl_add_clienthello_use_srtp_ext
-#define ssl_add_clienthello_use_srtp_ext ssl_add_clihello_use_srtp_ext
-#undef ssl_add_serverhello_use_srtp_ext
-#define ssl_add_serverhello_use_srtp_ext ssl_add_serhello_use_srtp_ext
-#undef ssl_parse_clienthello_use_srtp_ext
-#define ssl_parse_clienthello_use_srtp_ext ssl_parse_clihello_use_srtp_ext
-#undef ssl_parse_serverhello_use_srtp_ext
-#define ssl_parse_serverhello_use_srtp_ext ssl_parse_serhello_use_srtp_ext
-#undef SSL_CTX_set_next_protos_advertised_cb
-#define SSL_CTX_set_next_protos_advertised_cb SSL_CTX_set_next_protos_adv_cb
-#undef SSL_CTX_set_next_proto_select_cb
-#define SSL_CTX_set_next_proto_select_cb SSL_CTX_set_next_proto_sel_cb
-#undef ssl3_cbc_record_digest_supported
-#define ssl3_cbc_record_digest_supported ssl3_cbc_record_digest_support
-#undef ssl_check_clienthello_tlsext_late
-#define ssl_check_clienthello_tlsext_late ssl_check_clihello_tlsext_late
-#undef ssl_check_clienthello_tlsext_early
-#define ssl_check_clienthello_tlsext_early ssl_check_clihello_tlsext_early
-
-/* Hack some long ENGINE names */
-#undef ENGINE_get_default_BN_mod_exp_crt
-#define ENGINE_get_default_BN_mod_exp_crt ENGINE_get_def_BN_mod_exp_crt
-#undef ENGINE_set_default_BN_mod_exp_crt
-#define ENGINE_set_default_BN_mod_exp_crt ENGINE_set_def_BN_mod_exp_crt
-#undef ENGINE_set_load_privkey_function
-#define ENGINE_set_load_privkey_function ENGINE_set_load_privkey_fn
-#undef ENGINE_get_load_privkey_function
-#define ENGINE_get_load_privkey_function ENGINE_get_load_privkey_fn
-#undef ENGINE_unregister_pkey_asn1_meths
-#define ENGINE_unregister_pkey_asn1_meths ENGINE_unreg_pkey_asn1_meths
-#undef ENGINE_register_all_pkey_asn1_meths
-#define ENGINE_register_all_pkey_asn1_meths ENGINE_reg_all_pkey_asn1_meths
-#undef ENGINE_set_default_pkey_asn1_meths
-#define ENGINE_set_default_pkey_asn1_meths ENGINE_set_def_pkey_asn1_meths
-#undef ENGINE_get_pkey_asn1_meth_engine
-#define ENGINE_get_pkey_asn1_meth_engine ENGINE_get_pkey_asn1_meth_eng
-#undef ENGINE_set_load_ssl_client_cert_function
-#define ENGINE_set_load_ssl_client_cert_function \
- ENGINE_set_ld_ssl_clnt_cert_fn
-#undef ENGINE_get_ssl_client_cert_function
-#define ENGINE_get_ssl_client_cert_function ENGINE_get_ssl_client_cert_fn
-
-/* Hack some long OCSP names */
-#undef OCSP_REQUEST_get_ext_by_critical
-#define OCSP_REQUEST_get_ext_by_critical OCSP_REQUEST_get_ext_by_crit
-#undef OCSP_BASICRESP_get_ext_by_critical
-#define OCSP_BASICRESP_get_ext_by_critical OCSP_BASICRESP_get_ext_by_crit
-#undef OCSP_SINGLERESP_get_ext_by_critical
-#define OCSP_SINGLERESP_get_ext_by_critical OCSP_SINGLERESP_get_ext_by_crit
-
-/* Hack some long DES names */
-#undef _ossl_old_des_ede3_cfb64_encrypt
-#define _ossl_old_des_ede3_cfb64_encrypt _ossl_odes_ede3_cfb64_encrypt
-#undef _ossl_old_des_ede3_ofb64_encrypt
-#define _ossl_old_des_ede3_ofb64_encrypt _ossl_odes_ede3_ofb64_encrypt
-
-/* Hack some long EVP names */
-#undef OPENSSL_add_all_algorithms_noconf
-#define OPENSSL_add_all_algorithms_noconf OPENSSL_add_all_algo_noconf
-#undef OPENSSL_add_all_algorithms_conf
-#define OPENSSL_add_all_algorithms_conf OPENSSL_add_all_algo_conf
-#undef EVP_PKEY_meth_set_verify_recover
-#define EVP_PKEY_meth_set_verify_recover EVP_PKEY_meth_set_vrfy_recover
-
-/* Hack some long EC names */
-#undef EC_GROUP_set_point_conversion_form
-#define EC_GROUP_set_point_conversion_form EC_GROUP_set_point_conv_form
-#undef EC_GROUP_get_point_conversion_form
-#define EC_GROUP_get_point_conversion_form EC_GROUP_get_point_conv_form
-#undef EC_GROUP_clear_free_all_extra_data
-#define EC_GROUP_clear_free_all_extra_data EC_GROUP_clr_free_all_xtra_data
-#undef EC_KEY_set_public_key_affine_coordinates
-#define EC_KEY_set_public_key_affine_coordinates \
- EC_KEY_set_pub_key_aff_coords
-#undef EC_POINT_set_Jprojective_coordinates_GFp
-#define EC_POINT_set_Jprojective_coordinates_GFp \
- EC_POINT_set_Jproj_coords_GFp
-#undef EC_POINT_get_Jprojective_coordinates_GFp
-#define EC_POINT_get_Jprojective_coordinates_GFp \
- EC_POINT_get_Jproj_coords_GFp
-#undef EC_POINT_set_affine_coordinates_GFp
-#define EC_POINT_set_affine_coordinates_GFp EC_POINT_set_affine_coords_GFp
-#undef EC_POINT_get_affine_coordinates_GFp
-#define EC_POINT_get_affine_coordinates_GFp EC_POINT_get_affine_coords_GFp
-#undef EC_POINT_set_compressed_coordinates_GFp
-#define EC_POINT_set_compressed_coordinates_GFp EC_POINT_set_compr_coords_GFp
-#undef EC_POINT_set_affine_coordinates_GF2m
-#define EC_POINT_set_affine_coordinates_GF2m EC_POINT_set_affine_coords_GF2m
-#undef EC_POINT_get_affine_coordinates_GF2m
-#define EC_POINT_get_affine_coordinates_GF2m EC_POINT_get_affine_coords_GF2m
-#undef EC_POINT_set_compressed_coordinates_GF2m
-#define EC_POINT_set_compressed_coordinates_GF2m \
- EC_POINT_set_compr_coords_GF2m
-#undef ec_GF2m_simple_group_clear_finish
-#define ec_GF2m_simple_group_clear_finish ec_GF2m_simple_grp_clr_finish
-#undef ec_GF2m_simple_group_check_discriminant
-#define ec_GF2m_simple_group_check_discriminant ec_GF2m_simple_grp_chk_discrim
-#undef ec_GF2m_simple_point_clear_finish
-#define ec_GF2m_simple_point_clear_finish ec_GF2m_simple_pt_clr_finish
-#undef ec_GF2m_simple_point_set_to_infinity
-#define ec_GF2m_simple_point_set_to_infinity ec_GF2m_simple_pt_set_to_inf
-#undef ec_GF2m_simple_points_make_affine
-#define ec_GF2m_simple_points_make_affine ec_GF2m_simple_pts_make_affine
-#undef ec_GF2m_simple_point_set_affine_coordinates
-#define ec_GF2m_simple_point_set_affine_coordinates \
- ec_GF2m_smp_pt_set_af_coords
-#undef ec_GF2m_simple_point_get_affine_coordinates
-#define ec_GF2m_simple_point_get_affine_coordinates \
- ec_GF2m_smp_pt_get_af_coords
-#undef ec_GF2m_simple_set_compressed_coordinates
-#define ec_GF2m_simple_set_compressed_coordinates \
- ec_GF2m_smp_set_compr_coords
-#undef ec_GFp_simple_group_set_curve_GFp
-#define ec_GFp_simple_group_set_curve_GFp ec_GFp_simple_grp_set_curve_GFp
-#undef ec_GFp_simple_group_get_curve_GFp
-#define ec_GFp_simple_group_get_curve_GFp ec_GFp_simple_grp_get_curve_GFp
-#undef ec_GFp_simple_group_clear_finish
-#define ec_GFp_simple_group_clear_finish ec_GFp_simple_grp_clear_finish
-#undef ec_GFp_simple_group_set_generator
-#define ec_GFp_simple_group_set_generator ec_GFp_simple_grp_set_generator
-#undef ec_GFp_simple_group_get0_generator
-#define ec_GFp_simple_group_get0_generator ec_GFp_simple_grp_gt0_generator
-#undef ec_GFp_simple_group_get_cofactor
-#define ec_GFp_simple_group_get_cofactor ec_GFp_simple_grp_get_cofactor
-#undef ec_GFp_simple_point_clear_finish
-#define ec_GFp_simple_point_clear_finish ec_GFp_simple_pt_clear_finish
-#undef ec_GFp_simple_point_set_to_infinity
-#define ec_GFp_simple_point_set_to_infinity ec_GFp_simple_pt_set_to_inf
-#undef ec_GFp_simple_points_make_affine
-#define ec_GFp_simple_points_make_affine ec_GFp_simple_pts_make_affine
-#undef ec_GFp_simple_set_Jprojective_coordinates_GFp
-#define ec_GFp_simple_set_Jprojective_coordinates_GFp \
- ec_GFp_smp_set_Jproj_coords_GFp
-#undef ec_GFp_simple_get_Jprojective_coordinates_GFp
-#define ec_GFp_simple_get_Jprojective_coordinates_GFp \
- ec_GFp_smp_get_Jproj_coords_GFp
-#undef ec_GFp_simple_point_set_affine_coordinates_GFp
-#define ec_GFp_simple_point_set_affine_coordinates_GFp \
- ec_GFp_smp_pt_set_af_coords_GFp
-#undef ec_GFp_simple_point_get_affine_coordinates_GFp
-#define ec_GFp_simple_point_get_affine_coordinates_GFp \
- ec_GFp_smp_pt_get_af_coords_GFp
-#undef ec_GFp_simple_set_compressed_coordinates_GFp
-#define ec_GFp_simple_set_compressed_coordinates_GFp \
- ec_GFp_smp_set_compr_coords_GFp
-#undef ec_GFp_simple_point_set_affine_coordinates
-#define ec_GFp_simple_point_set_affine_coordinates \
- ec_GFp_smp_pt_set_af_coords
-#undef ec_GFp_simple_point_get_affine_coordinates
-#define ec_GFp_simple_point_get_affine_coordinates \
- ec_GFp_smp_pt_get_af_coords
-#undef ec_GFp_simple_set_compressed_coordinates
-#define ec_GFp_simple_set_compressed_coordinates \
- ec_GFp_smp_set_compr_coords
-#undef ec_GFp_simple_group_check_discriminant
-#define ec_GFp_simple_group_check_discriminant ec_GFp_simple_grp_chk_discrim
-
-/* Hack som long STORE names */
-#undef STORE_method_set_initialise_function
-#define STORE_method_set_initialise_function STORE_meth_set_initialise_fn
-#undef STORE_method_set_cleanup_function
-#define STORE_method_set_cleanup_function STORE_meth_set_cleanup_fn
-#undef STORE_method_set_generate_function
-#define STORE_method_set_generate_function STORE_meth_set_generate_fn
-#undef STORE_method_set_modify_function
-#define STORE_method_set_modify_function STORE_meth_set_modify_fn
-#undef STORE_method_set_revoke_function
-#define STORE_method_set_revoke_function STORE_meth_set_revoke_fn
-#undef STORE_method_set_delete_function
-#define STORE_method_set_delete_function STORE_meth_set_delete_fn
-#undef STORE_method_set_list_start_function
-#define STORE_method_set_list_start_function STORE_meth_set_list_start_fn
-#undef STORE_method_set_list_next_function
-#define STORE_method_set_list_next_function STORE_meth_set_list_next_fn
-#undef STORE_method_set_list_end_function
-#define STORE_method_set_list_end_function STORE_meth_set_list_end_fn
-#undef STORE_method_set_update_store_function
-#define STORE_method_set_update_store_function STORE_meth_set_update_store_fn
-#undef STORE_method_set_lock_store_function
-#define STORE_method_set_lock_store_function STORE_meth_set_lock_store_fn
-#undef STORE_method_set_unlock_store_function
-#define STORE_method_set_unlock_store_function STORE_meth_set_unlock_store_fn
-#undef STORE_method_get_initialise_function
-#define STORE_method_get_initialise_function STORE_meth_get_initialise_fn
-#undef STORE_method_get_cleanup_function
-#define STORE_method_get_cleanup_function STORE_meth_get_cleanup_fn
-#undef STORE_method_get_generate_function
-#define STORE_method_get_generate_function STORE_meth_get_generate_fn
-#undef STORE_method_get_modify_function
-#define STORE_method_get_modify_function STORE_meth_get_modify_fn
-#undef STORE_method_get_revoke_function
-#define STORE_method_get_revoke_function STORE_meth_get_revoke_fn
-#undef STORE_method_get_delete_function
-#define STORE_method_get_delete_function STORE_meth_get_delete_fn
-#undef STORE_method_get_list_start_function
-#define STORE_method_get_list_start_function STORE_meth_get_list_start_fn
-#undef STORE_method_get_list_next_function
-#define STORE_method_get_list_next_function STORE_meth_get_list_next_fn
-#undef STORE_method_get_list_end_function
-#define STORE_method_get_list_end_function STORE_meth_get_list_end_fn
-#undef STORE_method_get_update_store_function
-#define STORE_method_get_update_store_function STORE_meth_get_update_store_fn
-#undef STORE_method_get_lock_store_function
-#define STORE_method_get_lock_store_function STORE_meth_get_lock_store_fn
-#undef STORE_method_get_unlock_store_function
-#define STORE_method_get_unlock_store_function STORE_meth_get_unlock_store_fn
-
-/* Hack some long TS names */
-#undef TS_RESP_CTX_set_status_info_cond
-#define TS_RESP_CTX_set_status_info_cond TS_RESP_CTX_set_stat_info_cond
-#undef TS_RESP_CTX_set_clock_precision_digits
-#define TS_RESP_CTX_set_clock_precision_digits TS_RESP_CTX_set_clk_prec_digits
-#undef TS_CONF_set_clock_precision_digits
-#define TS_CONF_set_clock_precision_digits TS_CONF_set_clk_prec_digits
-
-/* Hack some long CMS names */
-#undef CMS_RecipientInfo_ktri_get0_algs
-#define CMS_RecipientInfo_ktri_get0_algs CMS_RecipInfo_ktri_get0_algs
-#undef CMS_RecipientInfo_ktri_get0_signer_id
-#define CMS_RecipientInfo_ktri_get0_signer_id CMS_RecipInfo_ktri_get0_sigr_id
-#undef CMS_OtherRevocationInfoFormat_it
-#define CMS_OtherRevocationInfoFormat_it CMS_OtherRevocInfoFormat_it
-#undef CMS_KeyAgreeRecipientIdentifier_it
-#define CMS_KeyAgreeRecipientIdentifier_it CMS_KeyAgreeRecipIdentifier_it
-#undef CMS_OriginatorIdentifierOrKey_it
-#define CMS_OriginatorIdentifierOrKey_it CMS_OriginatorIdOrKey_it
-#undef cms_SignerIdentifier_get0_signer_id
-#define cms_SignerIdentifier_get0_signer_id cms_SignerId_get0_signer_id
-
-/* Hack some long DTLS1 names */
-#undef dtls1_retransmit_buffered_messages
-#define dtls1_retransmit_buffered_messages dtls1_retransmit_buffered_msgs
-
-/* Hack some long SRP names */
-#undef SRP_generate_server_master_secret
-#define SRP_generate_server_master_secret SRP_gen_server_master_secret
-#undef SRP_generate_client_master_secret
-#define SRP_generate_client_master_secret SRP_gen_client_master_secret
-
-/* Hack some long UI names */
-#undef UI_method_get_prompt_constructor
-#define UI_method_get_prompt_constructor UI_method_get_prompt_constructr
-#undef UI_method_set_prompt_constructor
-#define UI_method_set_prompt_constructor UI_method_set_prompt_constructr
-
-#endif /* defined OPENSSL_SYS_VMS */
-
-
-/* Case insensitive linking causes problems.... */
-#if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2)
-#undef ERR_load_CRYPTO_strings
-#define ERR_load_CRYPTO_strings ERR_load_CRYPTOlib_strings
-#undef OCSP_crlID_new
-#define OCSP_crlID_new OCSP_crlID2_new
-
-#undef d2i_ECPARAMETERS
-#define d2i_ECPARAMETERS d2i_UC_ECPARAMETERS
-#undef i2d_ECPARAMETERS
-#define i2d_ECPARAMETERS i2d_UC_ECPARAMETERS
-#undef d2i_ECPKPARAMETERS
-#define d2i_ECPKPARAMETERS d2i_UC_ECPKPARAMETERS
-#undef i2d_ECPKPARAMETERS
-#define i2d_ECPKPARAMETERS i2d_UC_ECPKPARAMETERS
-
-/* These functions do not seem to exist! However, I'm paranoid...
- Original command in x509v3.h:
- These functions are being redefined in another directory,
- and clash when the linker is case-insensitive, so let's
- hide them a little, by giving them an extra 'o' at the
- beginning of the name... */
-#undef X509v3_cleanup_extensions
-#define X509v3_cleanup_extensions oX509v3_cleanup_extensions
-#undef X509v3_add_extension
-#define X509v3_add_extension oX509v3_add_extension
-#undef X509v3_add_netscape_extensions
-#define X509v3_add_netscape_extensions oX509v3_add_netscape_extensions
-#undef X509v3_add_standard_extensions
-#define X509v3_add_standard_extensions oX509v3_add_standard_extensions
-
-/* This one clashes with CMS_data_create */
-#undef cms_Data_create
-#define cms_Data_create priv_cms_Data_create
-
-#endif
-
-
-#endif /* ! defined HEADER_VMS_IDHACKS_H */
diff --git a/drivers/builtin_openssl/openssl/ts.h b/drivers/builtin_openssl/openssl/ts.h
deleted file mode 100644
index c2448e3c3b..0000000000
--- a/drivers/builtin_openssl/openssl/ts.h
+++ /dev/null
@@ -1,858 +0,0 @@
-/* crypto/ts/ts.h */
-/* Written by Zoltan Glozik (zglozik@opentsa.org) for the OpenSSL
- * project 2002, 2003, 2004.
- */
-/* ====================================================================
- * Copyright (c) 2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_TS_H
-#define HEADER_TS_H
-
-#include <openssl/opensslconf.h>
-#include <openssl/symhacks.h>
-#ifndef OPENSSL_NO_BUFFER
-#include <openssl/buffer.h>
-#endif
-#ifndef OPENSSL_NO_EVP
-#include <openssl/evp.h>
-#endif
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#include <openssl/stack.h>
-#include <openssl/asn1.h>
-#include <openssl/safestack.h>
-
-#ifndef OPENSSL_NO_RSA
-#include <openssl/rsa.h>
-#endif
-
-#ifndef OPENSSL_NO_DSA
-#include <openssl/dsa.h>
-#endif
-
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef WIN32
-/* Under Win32 this is defined in wincrypt.h */
-#undef X509_NAME
-#endif
-
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-
-/*
-MessageImprint ::= SEQUENCE {
- hashAlgorithm AlgorithmIdentifier,
- hashedMessage OCTET STRING }
-*/
-
-typedef struct TS_msg_imprint_st
- {
- X509_ALGOR *hash_algo;
- ASN1_OCTET_STRING *hashed_msg;
- } TS_MSG_IMPRINT;
-
-/*
-TimeStampReq ::= SEQUENCE {
- version INTEGER { v1(1) },
- messageImprint MessageImprint,
- --a hash algorithm OID and the hash value of the data to be
- --time-stamped
- reqPolicy TSAPolicyId OPTIONAL,
- nonce INTEGER OPTIONAL,
- certReq BOOLEAN DEFAULT FALSE,
- extensions [0] IMPLICIT Extensions OPTIONAL }
-*/
-
-typedef struct TS_req_st
- {
- ASN1_INTEGER *version;
- TS_MSG_IMPRINT *msg_imprint;
- ASN1_OBJECT *policy_id; /* OPTIONAL */
- ASN1_INTEGER *nonce; /* OPTIONAL */
- ASN1_BOOLEAN cert_req; /* DEFAULT FALSE */
- STACK_OF(X509_EXTENSION) *extensions; /* [0] OPTIONAL */
- } TS_REQ;
-
-/*
-Accuracy ::= SEQUENCE {
- seconds INTEGER OPTIONAL,
- millis [0] INTEGER (1..999) OPTIONAL,
- micros [1] INTEGER (1..999) OPTIONAL }
-*/
-
-typedef struct TS_accuracy_st
- {
- ASN1_INTEGER *seconds;
- ASN1_INTEGER *millis;
- ASN1_INTEGER *micros;
- } TS_ACCURACY;
-
-/*
-TSTInfo ::= SEQUENCE {
- version INTEGER { v1(1) },
- policy TSAPolicyId,
- messageImprint MessageImprint,
- -- MUST have the same value as the similar field in
- -- TimeStampReq
- serialNumber INTEGER,
- -- Time-Stamping users MUST be ready to accommodate integers
- -- up to 160 bits.
- genTime GeneralizedTime,
- accuracy Accuracy OPTIONAL,
- ordering BOOLEAN DEFAULT FALSE,
- nonce INTEGER OPTIONAL,
- -- MUST be present if the similar field was present
- -- in TimeStampReq. In that case it MUST have the same value.
- tsa [0] GeneralName OPTIONAL,
- extensions [1] IMPLICIT Extensions OPTIONAL }
-*/
-
-typedef struct TS_tst_info_st
- {
- ASN1_INTEGER *version;
- ASN1_OBJECT *policy_id;
- TS_MSG_IMPRINT *msg_imprint;
- ASN1_INTEGER *serial;
- ASN1_GENERALIZEDTIME *time;
- TS_ACCURACY *accuracy;
- ASN1_BOOLEAN ordering;
- ASN1_INTEGER *nonce;
- GENERAL_NAME *tsa;
- STACK_OF(X509_EXTENSION) *extensions;
- } TS_TST_INFO;
-
-/*
-PKIStatusInfo ::= SEQUENCE {
- status PKIStatus,
- statusString PKIFreeText OPTIONAL,
- failInfo PKIFailureInfo OPTIONAL }
-
-From RFC 1510 - section 3.1.1:
-PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
- -- text encoded as UTF-8 String (note: each UTF8String SHOULD
- -- include an RFC 1766 language tag to indicate the language
- -- of the contained text)
-*/
-
-/* Possible values for status. See ts_resp_print.c && ts_resp_verify.c. */
-
-#define TS_STATUS_GRANTED 0
-#define TS_STATUS_GRANTED_WITH_MODS 1
-#define TS_STATUS_REJECTION 2
-#define TS_STATUS_WAITING 3
-#define TS_STATUS_REVOCATION_WARNING 4
-#define TS_STATUS_REVOCATION_NOTIFICATION 5
-
-/* Possible values for failure_info. See ts_resp_print.c && ts_resp_verify.c */
-
-#define TS_INFO_BAD_ALG 0
-#define TS_INFO_BAD_REQUEST 2
-#define TS_INFO_BAD_DATA_FORMAT 5
-#define TS_INFO_TIME_NOT_AVAILABLE 14
-#define TS_INFO_UNACCEPTED_POLICY 15
-#define TS_INFO_UNACCEPTED_EXTENSION 16
-#define TS_INFO_ADD_INFO_NOT_AVAILABLE 17
-#define TS_INFO_SYSTEM_FAILURE 25
-
-typedef struct TS_status_info_st
- {
- ASN1_INTEGER *status;
- STACK_OF(ASN1_UTF8STRING) *text;
- ASN1_BIT_STRING *failure_info;
- } TS_STATUS_INFO;
-
-DECLARE_STACK_OF(ASN1_UTF8STRING)
-DECLARE_ASN1_SET_OF(ASN1_UTF8STRING)
-
-/*
-TimeStampResp ::= SEQUENCE {
- status PKIStatusInfo,
- timeStampToken TimeStampToken OPTIONAL }
-*/
-
-typedef struct TS_resp_st
- {
- TS_STATUS_INFO *status_info;
- PKCS7 *token;
- TS_TST_INFO *tst_info;
- } TS_RESP;
-
-/* The structure below would belong to the ESS component. */
-
-/*
-IssuerSerial ::= SEQUENCE {
- issuer GeneralNames,
- serialNumber CertificateSerialNumber
- }
-*/
-
-typedef struct ESS_issuer_serial
- {
- STACK_OF(GENERAL_NAME) *issuer;
- ASN1_INTEGER *serial;
- } ESS_ISSUER_SERIAL;
-
-/*
-ESSCertID ::= SEQUENCE {
- certHash Hash,
- issuerSerial IssuerSerial OPTIONAL
-}
-*/
-
-typedef struct ESS_cert_id
- {
- ASN1_OCTET_STRING *hash; /* Always SHA-1 digest. */
- ESS_ISSUER_SERIAL *issuer_serial;
- } ESS_CERT_ID;
-
-DECLARE_STACK_OF(ESS_CERT_ID)
-DECLARE_ASN1_SET_OF(ESS_CERT_ID)
-
-/*
-SigningCertificate ::= SEQUENCE {
- certs SEQUENCE OF ESSCertID,
- policies SEQUENCE OF PolicyInformation OPTIONAL
-}
-*/
-
-typedef struct ESS_signing_cert
- {
- STACK_OF(ESS_CERT_ID) *cert_ids;
- STACK_OF(POLICYINFO) *policy_info;
- } ESS_SIGNING_CERT;
-
-
-TS_REQ *TS_REQ_new(void);
-void TS_REQ_free(TS_REQ *a);
-int i2d_TS_REQ(const TS_REQ *a, unsigned char **pp);
-TS_REQ *d2i_TS_REQ(TS_REQ **a, const unsigned char **pp, long length);
-
-TS_REQ *TS_REQ_dup(TS_REQ *a);
-
-TS_REQ *d2i_TS_REQ_fp(FILE *fp, TS_REQ **a);
-int i2d_TS_REQ_fp(FILE *fp, TS_REQ *a);
-TS_REQ *d2i_TS_REQ_bio(BIO *fp, TS_REQ **a);
-int i2d_TS_REQ_bio(BIO *fp, TS_REQ *a);
-
-TS_MSG_IMPRINT *TS_MSG_IMPRINT_new(void);
-void TS_MSG_IMPRINT_free(TS_MSG_IMPRINT *a);
-int i2d_TS_MSG_IMPRINT(const TS_MSG_IMPRINT *a, unsigned char **pp);
-TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT(TS_MSG_IMPRINT **a,
- const unsigned char **pp, long length);
-
-TS_MSG_IMPRINT *TS_MSG_IMPRINT_dup(TS_MSG_IMPRINT *a);
-
-TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT **a);
-int i2d_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT *a);
-TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_bio(BIO *fp, TS_MSG_IMPRINT **a);
-int i2d_TS_MSG_IMPRINT_bio(BIO *fp, TS_MSG_IMPRINT *a);
-
-TS_RESP *TS_RESP_new(void);
-void TS_RESP_free(TS_RESP *a);
-int i2d_TS_RESP(const TS_RESP *a, unsigned char **pp);
-TS_RESP *d2i_TS_RESP(TS_RESP **a, const unsigned char **pp, long length);
-TS_TST_INFO *PKCS7_to_TS_TST_INFO(PKCS7 *token);
-TS_RESP *TS_RESP_dup(TS_RESP *a);
-
-TS_RESP *d2i_TS_RESP_fp(FILE *fp, TS_RESP **a);
-int i2d_TS_RESP_fp(FILE *fp, TS_RESP *a);
-TS_RESP *d2i_TS_RESP_bio(BIO *fp, TS_RESP **a);
-int i2d_TS_RESP_bio(BIO *fp, TS_RESP *a);
-
-TS_STATUS_INFO *TS_STATUS_INFO_new(void);
-void TS_STATUS_INFO_free(TS_STATUS_INFO *a);
-int i2d_TS_STATUS_INFO(const TS_STATUS_INFO *a, unsigned char **pp);
-TS_STATUS_INFO *d2i_TS_STATUS_INFO(TS_STATUS_INFO **a,
- const unsigned char **pp, long length);
-TS_STATUS_INFO *TS_STATUS_INFO_dup(TS_STATUS_INFO *a);
-
-TS_TST_INFO *TS_TST_INFO_new(void);
-void TS_TST_INFO_free(TS_TST_INFO *a);
-int i2d_TS_TST_INFO(const TS_TST_INFO *a, unsigned char **pp);
-TS_TST_INFO *d2i_TS_TST_INFO(TS_TST_INFO **a, const unsigned char **pp,
- long length);
-TS_TST_INFO *TS_TST_INFO_dup(TS_TST_INFO *a);
-
-TS_TST_INFO *d2i_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO **a);
-int i2d_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO *a);
-TS_TST_INFO *d2i_TS_TST_INFO_bio(BIO *fp, TS_TST_INFO **a);
-int i2d_TS_TST_INFO_bio(BIO *fp, TS_TST_INFO *a);
-
-TS_ACCURACY *TS_ACCURACY_new(void);
-void TS_ACCURACY_free(TS_ACCURACY *a);
-int i2d_TS_ACCURACY(const TS_ACCURACY *a, unsigned char **pp);
-TS_ACCURACY *d2i_TS_ACCURACY(TS_ACCURACY **a, const unsigned char **pp,
- long length);
-TS_ACCURACY *TS_ACCURACY_dup(TS_ACCURACY *a);
-
-ESS_ISSUER_SERIAL *ESS_ISSUER_SERIAL_new(void);
-void ESS_ISSUER_SERIAL_free(ESS_ISSUER_SERIAL *a);
-int i2d_ESS_ISSUER_SERIAL(const ESS_ISSUER_SERIAL *a,
- unsigned char **pp);
-ESS_ISSUER_SERIAL *d2i_ESS_ISSUER_SERIAL(ESS_ISSUER_SERIAL **a,
- const unsigned char **pp, long length);
-ESS_ISSUER_SERIAL *ESS_ISSUER_SERIAL_dup(ESS_ISSUER_SERIAL *a);
-
-ESS_CERT_ID *ESS_CERT_ID_new(void);
-void ESS_CERT_ID_free(ESS_CERT_ID *a);
-int i2d_ESS_CERT_ID(const ESS_CERT_ID *a, unsigned char **pp);
-ESS_CERT_ID *d2i_ESS_CERT_ID(ESS_CERT_ID **a, const unsigned char **pp,
- long length);
-ESS_CERT_ID *ESS_CERT_ID_dup(ESS_CERT_ID *a);
-
-ESS_SIGNING_CERT *ESS_SIGNING_CERT_new(void);
-void ESS_SIGNING_CERT_free(ESS_SIGNING_CERT *a);
-int i2d_ESS_SIGNING_CERT(const ESS_SIGNING_CERT *a,
- unsigned char **pp);
-ESS_SIGNING_CERT *d2i_ESS_SIGNING_CERT(ESS_SIGNING_CERT **a,
- const unsigned char **pp, long length);
-ESS_SIGNING_CERT *ESS_SIGNING_CERT_dup(ESS_SIGNING_CERT *a);
-
-void ERR_load_TS_strings(void);
-
-int TS_REQ_set_version(TS_REQ *a, long version);
-long TS_REQ_get_version(const TS_REQ *a);
-
-int TS_REQ_set_msg_imprint(TS_REQ *a, TS_MSG_IMPRINT *msg_imprint);
-TS_MSG_IMPRINT *TS_REQ_get_msg_imprint(TS_REQ *a);
-
-int TS_MSG_IMPRINT_set_algo(TS_MSG_IMPRINT *a, X509_ALGOR *alg);
-X509_ALGOR *TS_MSG_IMPRINT_get_algo(TS_MSG_IMPRINT *a);
-
-int TS_MSG_IMPRINT_set_msg(TS_MSG_IMPRINT *a, unsigned char *d, int len);
-ASN1_OCTET_STRING *TS_MSG_IMPRINT_get_msg(TS_MSG_IMPRINT *a);
-
-int TS_REQ_set_policy_id(TS_REQ *a, ASN1_OBJECT *policy);
-ASN1_OBJECT *TS_REQ_get_policy_id(TS_REQ *a);
-
-int TS_REQ_set_nonce(TS_REQ *a, const ASN1_INTEGER *nonce);
-const ASN1_INTEGER *TS_REQ_get_nonce(const TS_REQ *a);
-
-int TS_REQ_set_cert_req(TS_REQ *a, int cert_req);
-int TS_REQ_get_cert_req(const TS_REQ *a);
-
-STACK_OF(X509_EXTENSION) *TS_REQ_get_exts(TS_REQ *a);
-void TS_REQ_ext_free(TS_REQ *a);
-int TS_REQ_get_ext_count(TS_REQ *a);
-int TS_REQ_get_ext_by_NID(TS_REQ *a, int nid, int lastpos);
-int TS_REQ_get_ext_by_OBJ(TS_REQ *a, ASN1_OBJECT *obj, int lastpos);
-int TS_REQ_get_ext_by_critical(TS_REQ *a, int crit, int lastpos);
-X509_EXTENSION *TS_REQ_get_ext(TS_REQ *a, int loc);
-X509_EXTENSION *TS_REQ_delete_ext(TS_REQ *a, int loc);
-int TS_REQ_add_ext(TS_REQ *a, X509_EXTENSION *ex, int loc);
-void *TS_REQ_get_ext_d2i(TS_REQ *a, int nid, int *crit, int *idx);
-
-/* Function declarations for TS_REQ defined in ts/ts_req_print.c */
-
-int TS_REQ_print_bio(BIO *bio, TS_REQ *a);
-
-/* Function declarations for TS_RESP defined in ts/ts_resp_utils.c */
-
-int TS_RESP_set_status_info(TS_RESP *a, TS_STATUS_INFO *info);
-TS_STATUS_INFO *TS_RESP_get_status_info(TS_RESP *a);
-
-/* Caller loses ownership of PKCS7 and TS_TST_INFO objects. */
-void TS_RESP_set_tst_info(TS_RESP *a, PKCS7 *p7, TS_TST_INFO *tst_info);
-PKCS7 *TS_RESP_get_token(TS_RESP *a);
-TS_TST_INFO *TS_RESP_get_tst_info(TS_RESP *a);
-
-int TS_TST_INFO_set_version(TS_TST_INFO *a, long version);
-long TS_TST_INFO_get_version(const TS_TST_INFO *a);
-
-int TS_TST_INFO_set_policy_id(TS_TST_INFO *a, ASN1_OBJECT *policy_id);
-ASN1_OBJECT *TS_TST_INFO_get_policy_id(TS_TST_INFO *a);
-
-int TS_TST_INFO_set_msg_imprint(TS_TST_INFO *a, TS_MSG_IMPRINT *msg_imprint);
-TS_MSG_IMPRINT *TS_TST_INFO_get_msg_imprint(TS_TST_INFO *a);
-
-int TS_TST_INFO_set_serial(TS_TST_INFO *a, const ASN1_INTEGER *serial);
-const ASN1_INTEGER *TS_TST_INFO_get_serial(const TS_TST_INFO *a);
-
-int TS_TST_INFO_set_time(TS_TST_INFO *a, const ASN1_GENERALIZEDTIME *gtime);
-const ASN1_GENERALIZEDTIME *TS_TST_INFO_get_time(const TS_TST_INFO *a);
-
-int TS_TST_INFO_set_accuracy(TS_TST_INFO *a, TS_ACCURACY *accuracy);
-TS_ACCURACY *TS_TST_INFO_get_accuracy(TS_TST_INFO *a);
-
-int TS_ACCURACY_set_seconds(TS_ACCURACY *a, const ASN1_INTEGER *seconds);
-const ASN1_INTEGER *TS_ACCURACY_get_seconds(const TS_ACCURACY *a);
-
-int TS_ACCURACY_set_millis(TS_ACCURACY *a, const ASN1_INTEGER *millis);
-const ASN1_INTEGER *TS_ACCURACY_get_millis(const TS_ACCURACY *a);
-
-int TS_ACCURACY_set_micros(TS_ACCURACY *a, const ASN1_INTEGER *micros);
-const ASN1_INTEGER *TS_ACCURACY_get_micros(const TS_ACCURACY *a);
-
-int TS_TST_INFO_set_ordering(TS_TST_INFO *a, int ordering);
-int TS_TST_INFO_get_ordering(const TS_TST_INFO *a);
-
-int TS_TST_INFO_set_nonce(TS_TST_INFO *a, const ASN1_INTEGER *nonce);
-const ASN1_INTEGER *TS_TST_INFO_get_nonce(const TS_TST_INFO *a);
-
-int TS_TST_INFO_set_tsa(TS_TST_INFO *a, GENERAL_NAME *tsa);
-GENERAL_NAME *TS_TST_INFO_get_tsa(TS_TST_INFO *a);
-
-STACK_OF(X509_EXTENSION) *TS_TST_INFO_get_exts(TS_TST_INFO *a);
-void TS_TST_INFO_ext_free(TS_TST_INFO *a);
-int TS_TST_INFO_get_ext_count(TS_TST_INFO *a);
-int TS_TST_INFO_get_ext_by_NID(TS_TST_INFO *a, int nid, int lastpos);
-int TS_TST_INFO_get_ext_by_OBJ(TS_TST_INFO *a, ASN1_OBJECT *obj, int lastpos);
-int TS_TST_INFO_get_ext_by_critical(TS_TST_INFO *a, int crit, int lastpos);
-X509_EXTENSION *TS_TST_INFO_get_ext(TS_TST_INFO *a, int loc);
-X509_EXTENSION *TS_TST_INFO_delete_ext(TS_TST_INFO *a, int loc);
-int TS_TST_INFO_add_ext(TS_TST_INFO *a, X509_EXTENSION *ex, int loc);
-void *TS_TST_INFO_get_ext_d2i(TS_TST_INFO *a, int nid, int *crit, int *idx);
-
-/* Declarations related to response generation, defined in ts/ts_resp_sign.c. */
-
-/* Optional flags for response generation. */
-
-/* Don't include the TSA name in response. */
-#define TS_TSA_NAME 0x01
-
-/* Set ordering to true in response. */
-#define TS_ORDERING 0x02
-
-/*
- * Include the signer certificate and the other specified certificates in
- * the ESS signing certificate attribute beside the PKCS7 signed data.
- * Only the signer certificates is included by default.
- */
-#define TS_ESS_CERT_ID_CHAIN 0x04
-
-/* Forward declaration. */
-struct TS_resp_ctx;
-
-/* This must return a unique number less than 160 bits long. */
-typedef ASN1_INTEGER *(*TS_serial_cb)(struct TS_resp_ctx *, void *);
-
-/* This must return the seconds and microseconds since Jan 1, 1970 in
- the sec and usec variables allocated by the caller.
- Return non-zero for success and zero for failure. */
-typedef int (*TS_time_cb)(struct TS_resp_ctx *, void *, long *sec, long *usec);
-
-/* This must process the given extension.
- * It can modify the TS_TST_INFO object of the context.
- * Return values: !0 (processed), 0 (error, it must set the
- * status info/failure info of the response).
- */
-typedef int (*TS_extension_cb)(struct TS_resp_ctx *, X509_EXTENSION *, void *);
-
-typedef struct TS_resp_ctx
- {
- X509 *signer_cert;
- EVP_PKEY *signer_key;
- STACK_OF(X509) *certs; /* Certs to include in signed data. */
- STACK_OF(ASN1_OBJECT) *policies; /* Acceptable policies. */
- ASN1_OBJECT *default_policy; /* It may appear in policies, too. */
- STACK_OF(EVP_MD) *mds; /* Acceptable message digests. */
- ASN1_INTEGER *seconds; /* accuracy, 0 means not specified. */
- ASN1_INTEGER *millis; /* accuracy, 0 means not specified. */
- ASN1_INTEGER *micros; /* accuracy, 0 means not specified. */
- unsigned clock_precision_digits; /* fraction of seconds in
- time stamp token. */
- unsigned flags; /* Optional info, see values above. */
-
- /* Callback functions. */
- TS_serial_cb serial_cb;
- void *serial_cb_data; /* User data for serial_cb. */
-
- TS_time_cb time_cb;
- void *time_cb_data; /* User data for time_cb. */
-
- TS_extension_cb extension_cb;
- void *extension_cb_data; /* User data for extension_cb. */
-
- /* These members are used only while creating the response. */
- TS_REQ *request;
- TS_RESP *response;
- TS_TST_INFO *tst_info;
- } TS_RESP_CTX;
-
-DECLARE_STACK_OF(EVP_MD)
-DECLARE_ASN1_SET_OF(EVP_MD)
-
-/* Creates a response context that can be used for generating responses. */
-TS_RESP_CTX *TS_RESP_CTX_new(void);
-void TS_RESP_CTX_free(TS_RESP_CTX *ctx);
-
-/* This parameter must be set. */
-int TS_RESP_CTX_set_signer_cert(TS_RESP_CTX *ctx, X509 *signer);
-
-/* This parameter must be set. */
-int TS_RESP_CTX_set_signer_key(TS_RESP_CTX *ctx, EVP_PKEY *key);
-
-/* This parameter must be set. */
-int TS_RESP_CTX_set_def_policy(TS_RESP_CTX *ctx, ASN1_OBJECT *def_policy);
-
-/* No additional certs are included in the response by default. */
-int TS_RESP_CTX_set_certs(TS_RESP_CTX *ctx, STACK_OF(X509) *certs);
-
-/* Adds a new acceptable policy, only the default policy
- is accepted by default. */
-int TS_RESP_CTX_add_policy(TS_RESP_CTX *ctx, ASN1_OBJECT *policy);
-
-/* Adds a new acceptable message digest. Note that no message digests
- are accepted by default. The md argument is shared with the caller. */
-int TS_RESP_CTX_add_md(TS_RESP_CTX *ctx, const EVP_MD *md);
-
-/* Accuracy is not included by default. */
-int TS_RESP_CTX_set_accuracy(TS_RESP_CTX *ctx,
- int secs, int millis, int micros);
-
-/* Clock precision digits, i.e. the number of decimal digits:
- '0' means sec, '3' msec, '6' usec, and so on. Default is 0. */
-int TS_RESP_CTX_set_clock_precision_digits(TS_RESP_CTX *ctx,
- unsigned clock_precision_digits);
-/* At most we accept usec precision. */
-#define TS_MAX_CLOCK_PRECISION_DIGITS 6
-
-/* No flags are set by default. */
-void TS_RESP_CTX_add_flags(TS_RESP_CTX *ctx, int flags);
-
-/* Default callback always returns a constant. */
-void TS_RESP_CTX_set_serial_cb(TS_RESP_CTX *ctx, TS_serial_cb cb, void *data);
-
-/* Default callback uses the gettimeofday() and gmtime() system calls. */
-void TS_RESP_CTX_set_time_cb(TS_RESP_CTX *ctx, TS_time_cb cb, void *data);
-
-/* Default callback rejects all extensions. The extension callback is called
- * when the TS_TST_INFO object is already set up and not signed yet. */
-/* FIXME: extension handling is not tested yet. */
-void TS_RESP_CTX_set_extension_cb(TS_RESP_CTX *ctx,
- TS_extension_cb cb, void *data);
-
-/* The following methods can be used in the callbacks. */
-int TS_RESP_CTX_set_status_info(TS_RESP_CTX *ctx,
- int status, const char *text);
-
-/* Sets the status info only if it is still TS_STATUS_GRANTED. */
-int TS_RESP_CTX_set_status_info_cond(TS_RESP_CTX *ctx,
- int status, const char *text);
-
-int TS_RESP_CTX_add_failure_info(TS_RESP_CTX *ctx, int failure);
-
-/* The get methods below can be used in the extension callback. */
-TS_REQ *TS_RESP_CTX_get_request(TS_RESP_CTX *ctx);
-
-TS_TST_INFO *TS_RESP_CTX_get_tst_info(TS_RESP_CTX *ctx);
-
-/*
- * Creates the signed TS_TST_INFO and puts it in TS_RESP.
- * In case of errors it sets the status info properly.
- * Returns NULL only in case of memory allocation/fatal error.
- */
-TS_RESP *TS_RESP_create_response(TS_RESP_CTX *ctx, BIO *req_bio);
-
-/*
- * Declarations related to response verification,
- * they are defined in ts/ts_resp_verify.c.
- */
-
-int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs,
- X509_STORE *store, X509 **signer_out);
-
-/* Context structure for the generic verify method. */
-
-/* Verify the signer's certificate and the signature of the response. */
-#define TS_VFY_SIGNATURE (1u << 0)
-/* Verify the version number of the response. */
-#define TS_VFY_VERSION (1u << 1)
-/* Verify if the policy supplied by the user matches the policy of the TSA. */
-#define TS_VFY_POLICY (1u << 2)
-/* Verify the message imprint provided by the user. This flag should not be
- specified with TS_VFY_DATA. */
-#define TS_VFY_IMPRINT (1u << 3)
-/* Verify the message imprint computed by the verify method from the user
- provided data and the MD algorithm of the response. This flag should not be
- specified with TS_VFY_IMPRINT. */
-#define TS_VFY_DATA (1u << 4)
-/* Verify the nonce value. */
-#define TS_VFY_NONCE (1u << 5)
-/* Verify if the TSA name field matches the signer certificate. */
-#define TS_VFY_SIGNER (1u << 6)
-/* Verify if the TSA name field equals to the user provided name. */
-#define TS_VFY_TSA_NAME (1u << 7)
-
-/* You can use the following convenience constants. */
-#define TS_VFY_ALL_IMPRINT (TS_VFY_SIGNATURE \
- | TS_VFY_VERSION \
- | TS_VFY_POLICY \
- | TS_VFY_IMPRINT \
- | TS_VFY_NONCE \
- | TS_VFY_SIGNER \
- | TS_VFY_TSA_NAME)
-#define TS_VFY_ALL_DATA (TS_VFY_SIGNATURE \
- | TS_VFY_VERSION \
- | TS_VFY_POLICY \
- | TS_VFY_DATA \
- | TS_VFY_NONCE \
- | TS_VFY_SIGNER \
- | TS_VFY_TSA_NAME)
-
-typedef struct TS_verify_ctx
- {
- /* Set this to the union of TS_VFY_... flags you want to carry out. */
- unsigned flags;
-
- /* Must be set only with TS_VFY_SIGNATURE. certs is optional. */
- X509_STORE *store;
- STACK_OF(X509) *certs;
-
- /* Must be set only with TS_VFY_POLICY. */
- ASN1_OBJECT *policy;
-
- /* Must be set only with TS_VFY_IMPRINT. If md_alg is NULL,
- the algorithm from the response is used. */
- X509_ALGOR *md_alg;
- unsigned char *imprint;
- unsigned imprint_len;
-
- /* Must be set only with TS_VFY_DATA. */
- BIO *data;
-
- /* Must be set only with TS_VFY_TSA_NAME. */
- ASN1_INTEGER *nonce;
-
- /* Must be set only with TS_VFY_TSA_NAME. */
- GENERAL_NAME *tsa_name;
- } TS_VERIFY_CTX;
-
-int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response);
-int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token);
-
-/*
- * Declarations related to response verification context,
- * they are defined in ts/ts_verify_ctx.c.
- */
-
-/* Set all fields to zero. */
-TS_VERIFY_CTX *TS_VERIFY_CTX_new(void);
-void TS_VERIFY_CTX_init(TS_VERIFY_CTX *ctx);
-void TS_VERIFY_CTX_free(TS_VERIFY_CTX *ctx);
-void TS_VERIFY_CTX_cleanup(TS_VERIFY_CTX *ctx);
-
-/*
- * If ctx is NULL, it allocates and returns a new object, otherwise
- * it returns ctx. It initialises all the members as follows:
- * flags = TS_VFY_ALL_IMPRINT & ~(TS_VFY_TSA_NAME | TS_VFY_SIGNATURE)
- * certs = NULL
- * store = NULL
- * policy = policy from the request or NULL if absent (in this case
- * TS_VFY_POLICY is cleared from flags as well)
- * md_alg = MD algorithm from request
- * imprint, imprint_len = imprint from request
- * data = NULL
- * nonce, nonce_len = nonce from the request or NULL if absent (in this case
- * TS_VFY_NONCE is cleared from flags as well)
- * tsa_name = NULL
- * Important: after calling this method TS_VFY_SIGNATURE should be added!
- */
-TS_VERIFY_CTX *TS_REQ_to_TS_VERIFY_CTX(TS_REQ *req, TS_VERIFY_CTX *ctx);
-
-/* Function declarations for TS_RESP defined in ts/ts_resp_print.c */
-
-int TS_RESP_print_bio(BIO *bio, TS_RESP *a);
-int TS_STATUS_INFO_print_bio(BIO *bio, TS_STATUS_INFO *a);
-int TS_TST_INFO_print_bio(BIO *bio, TS_TST_INFO *a);
-
-/* Common utility functions defined in ts/ts_lib.c */
-
-int TS_ASN1_INTEGER_print_bio(BIO *bio, const ASN1_INTEGER *num);
-int TS_OBJ_print_bio(BIO *bio, const ASN1_OBJECT *obj);
-int TS_ext_print_bio(BIO *bio, const STACK_OF(X509_EXTENSION) *extensions);
-int TS_X509_ALGOR_print_bio(BIO *bio, const X509_ALGOR *alg);
-int TS_MSG_IMPRINT_print_bio(BIO *bio, TS_MSG_IMPRINT *msg);
-
-/* Function declarations for handling configuration options,
- defined in ts/ts_conf.c */
-
-X509 *TS_CONF_load_cert(const char *file);
-STACK_OF(X509) *TS_CONF_load_certs(const char *file);
-EVP_PKEY *TS_CONF_load_key(const char *file, const char *pass);
-const char *TS_CONF_get_tsa_section(CONF *conf, const char *section);
-int TS_CONF_set_serial(CONF *conf, const char *section, TS_serial_cb cb,
- TS_RESP_CTX *ctx);
-int TS_CONF_set_crypto_device(CONF *conf, const char *section,
- const char *device);
-int TS_CONF_set_default_engine(const char *name);
-int TS_CONF_set_signer_cert(CONF *conf, const char *section,
- const char *cert, TS_RESP_CTX *ctx);
-int TS_CONF_set_certs(CONF *conf, const char *section, const char *certs,
- TS_RESP_CTX *ctx);
-int TS_CONF_set_signer_key(CONF *conf, const char *section,
- const char *key, const char *pass, TS_RESP_CTX *ctx);
-int TS_CONF_set_def_policy(CONF *conf, const char *section,
- const char *policy, TS_RESP_CTX *ctx);
-int TS_CONF_set_policies(CONF *conf, const char *section, TS_RESP_CTX *ctx);
-int TS_CONF_set_digests(CONF *conf, const char *section, TS_RESP_CTX *ctx);
-int TS_CONF_set_accuracy(CONF *conf, const char *section, TS_RESP_CTX *ctx);
-int TS_CONF_set_clock_precision_digits(CONF *conf, const char *section,
- TS_RESP_CTX *ctx);
-int TS_CONF_set_ordering(CONF *conf, const char *section, TS_RESP_CTX *ctx);
-int TS_CONF_set_tsa_name(CONF *conf, const char *section, TS_RESP_CTX *ctx);
-int TS_CONF_set_ess_cert_id_chain(CONF *conf, const char *section,
- TS_RESP_CTX *ctx);
-
-/* -------------------------------------------------- */
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_TS_strings(void);
-
-/* Error codes for the TS functions. */
-
-/* Function codes. */
-#define TS_F_D2I_TS_RESP 147
-#define TS_F_DEF_SERIAL_CB 110
-#define TS_F_DEF_TIME_CB 111
-#define TS_F_ESS_ADD_SIGNING_CERT 112
-#define TS_F_ESS_CERT_ID_NEW_INIT 113
-#define TS_F_ESS_SIGNING_CERT_NEW_INIT 114
-#define TS_F_INT_TS_RESP_VERIFY_TOKEN 149
-#define TS_F_PKCS7_TO_TS_TST_INFO 148
-#define TS_F_TS_ACCURACY_SET_MICROS 115
-#define TS_F_TS_ACCURACY_SET_MILLIS 116
-#define TS_F_TS_ACCURACY_SET_SECONDS 117
-#define TS_F_TS_CHECK_IMPRINTS 100
-#define TS_F_TS_CHECK_NONCES 101
-#define TS_F_TS_CHECK_POLICY 102
-#define TS_F_TS_CHECK_SIGNING_CERTS 103
-#define TS_F_TS_CHECK_STATUS_INFO 104
-#define TS_F_TS_COMPUTE_IMPRINT 145
-#define TS_F_TS_CONF_SET_DEFAULT_ENGINE 146
-#define TS_F_TS_GET_STATUS_TEXT 105
-#define TS_F_TS_MSG_IMPRINT_SET_ALGO 118
-#define TS_F_TS_REQ_SET_MSG_IMPRINT 119
-#define TS_F_TS_REQ_SET_NONCE 120
-#define TS_F_TS_REQ_SET_POLICY_ID 121
-#define TS_F_TS_RESP_CREATE_RESPONSE 122
-#define TS_F_TS_RESP_CREATE_TST_INFO 123
-#define TS_F_TS_RESP_CTX_ADD_FAILURE_INFO 124
-#define TS_F_TS_RESP_CTX_ADD_MD 125
-#define TS_F_TS_RESP_CTX_ADD_POLICY 126
-#define TS_F_TS_RESP_CTX_NEW 127
-#define TS_F_TS_RESP_CTX_SET_ACCURACY 128
-#define TS_F_TS_RESP_CTX_SET_CERTS 129
-#define TS_F_TS_RESP_CTX_SET_DEF_POLICY 130
-#define TS_F_TS_RESP_CTX_SET_SIGNER_CERT 131
-#define TS_F_TS_RESP_CTX_SET_STATUS_INFO 132
-#define TS_F_TS_RESP_GET_POLICY 133
-#define TS_F_TS_RESP_SET_GENTIME_WITH_PRECISION 134
-#define TS_F_TS_RESP_SET_STATUS_INFO 135
-#define TS_F_TS_RESP_SET_TST_INFO 150
-#define TS_F_TS_RESP_SIGN 136
-#define TS_F_TS_RESP_VERIFY_SIGNATURE 106
-#define TS_F_TS_RESP_VERIFY_TOKEN 107
-#define TS_F_TS_TST_INFO_SET_ACCURACY 137
-#define TS_F_TS_TST_INFO_SET_MSG_IMPRINT 138
-#define TS_F_TS_TST_INFO_SET_NONCE 139
-#define TS_F_TS_TST_INFO_SET_POLICY_ID 140
-#define TS_F_TS_TST_INFO_SET_SERIAL 141
-#define TS_F_TS_TST_INFO_SET_TIME 142
-#define TS_F_TS_TST_INFO_SET_TSA 143
-#define TS_F_TS_VERIFY 108
-#define TS_F_TS_VERIFY_CERT 109
-#define TS_F_TS_VERIFY_CTX_NEW 144
-
-/* Reason codes. */
-#define TS_R_BAD_PKCS7_TYPE 132
-#define TS_R_BAD_TYPE 133
-#define TS_R_CERTIFICATE_VERIFY_ERROR 100
-#define TS_R_COULD_NOT_SET_ENGINE 127
-#define TS_R_COULD_NOT_SET_TIME 115
-#define TS_R_D2I_TS_RESP_INT_FAILED 128
-#define TS_R_DETACHED_CONTENT 134
-#define TS_R_ESS_ADD_SIGNING_CERT_ERROR 116
-#define TS_R_ESS_SIGNING_CERTIFICATE_ERROR 101
-#define TS_R_INVALID_NULL_POINTER 102
-#define TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE 117
-#define TS_R_MESSAGE_IMPRINT_MISMATCH 103
-#define TS_R_NONCE_MISMATCH 104
-#define TS_R_NONCE_NOT_RETURNED 105
-#define TS_R_NO_CONTENT 106
-#define TS_R_NO_TIME_STAMP_TOKEN 107
-#define TS_R_PKCS7_ADD_SIGNATURE_ERROR 118
-#define TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR 119
-#define TS_R_PKCS7_TO_TS_TST_INFO_FAILED 129
-#define TS_R_POLICY_MISMATCH 108
-#define TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 120
-#define TS_R_RESPONSE_SETUP_ERROR 121
-#define TS_R_SIGNATURE_FAILURE 109
-#define TS_R_THERE_MUST_BE_ONE_SIGNER 110
-#define TS_R_TIME_SYSCALL_ERROR 122
-#define TS_R_TOKEN_NOT_PRESENT 130
-#define TS_R_TOKEN_PRESENT 131
-#define TS_R_TSA_NAME_MISMATCH 111
-#define TS_R_TSA_UNTRUSTED 112
-#define TS_R_TST_INFO_SETUP_ERROR 123
-#define TS_R_TS_DATASIGN 124
-#define TS_R_UNACCEPTABLE_POLICY 125
-#define TS_R_UNSUPPORTED_MD_ALGORITHM 126
-#define TS_R_UNSUPPORTED_VERSION 113
-#define TS_R_WRONG_CONTENT_TYPE 114
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/txt_db.h b/drivers/builtin_openssl/openssl/txt_db.h
deleted file mode 100644
index 6abe435bc8..0000000000
--- a/drivers/builtin_openssl/openssl/txt_db.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* crypto/txt_db/txt_db.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_TXT_DB_H
-#define HEADER_TXT_DB_H
-
-#include <openssl/opensslconf.h>
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#include <openssl/stack.h>
-#include <openssl/lhash.h>
-
-#define DB_ERROR_OK 0
-#define DB_ERROR_MALLOC 1
-#define DB_ERROR_INDEX_CLASH 2
-#define DB_ERROR_INDEX_OUT_OF_RANGE 3
-#define DB_ERROR_NO_INDEX 4
-#define DB_ERROR_INSERT_INDEX_CLASH 5
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef OPENSSL_STRING *OPENSSL_PSTRING;
-DECLARE_SPECIAL_STACK_OF(OPENSSL_PSTRING, OPENSSL_STRING)
-
-typedef struct txt_db_st
- {
- int num_fields;
- STACK_OF(OPENSSL_PSTRING) *data;
- LHASH_OF(OPENSSL_STRING) **index;
- int (**qual)(OPENSSL_STRING *);
- long error;
- long arg1;
- long arg2;
- OPENSSL_STRING *arg_row;
- } TXT_DB;
-
-#ifndef OPENSSL_NO_BIO
-TXT_DB *TXT_DB_read(BIO *in, int num);
-long TXT_DB_write(BIO *out, TXT_DB *db);
-#else
-TXT_DB *TXT_DB_read(char *in, int num);
-long TXT_DB_write(char *out, TXT_DB *db);
-#endif
-int TXT_DB_create_index(TXT_DB *db,int field,int (*qual)(OPENSSL_STRING *),
- LHASH_HASH_FN_TYPE hash, LHASH_COMP_FN_TYPE cmp);
-void TXT_DB_free(TXT_DB *db);
-OPENSSL_STRING *TXT_DB_get_by_index(TXT_DB *db, int idx, OPENSSL_STRING *value);
-int TXT_DB_insert(TXT_DB *db, OPENSSL_STRING *value);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/ui.h b/drivers/builtin_openssl/openssl/ui.h
deleted file mode 100644
index bd78aa413f..0000000000
--- a/drivers/builtin_openssl/openssl/ui.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */
-/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
- * project 2001.
- */
-/* ====================================================================
- * Copyright (c) 2001 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_UI_H
-#define HEADER_UI_H
-
-#ifndef OPENSSL_NO_DEPRECATED
-#include <openssl/crypto.h>
-#endif
-#include <openssl/safestack.h>
-#include <openssl/ossl_typ.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Declared already in ossl_typ.h */
-/* typedef struct ui_st UI; */
-/* typedef struct ui_method_st UI_METHOD; */
-
-
-/* All the following functions return -1 or NULL on error and in some cases
- (UI_process()) -2 if interrupted or in some other way cancelled.
- When everything is fine, they return 0, a positive value or a non-NULL
- pointer, all depending on their purpose. */
-
-/* Creators and destructor. */
-UI *UI_new(void);
-UI *UI_new_method(const UI_METHOD *method);
-void UI_free(UI *ui);
-
-/* The following functions are used to add strings to be printed and prompt
- strings to prompt for data. The names are UI_{add,dup}_<function>_string
- and UI_{add,dup}_input_boolean.
-
- UI_{add,dup}_<function>_string have the following meanings:
- add add a text or prompt string. The pointers given to these
- functions are used verbatim, no copying is done.
- dup make a copy of the text or prompt string, then add the copy
- to the collection of strings in the user interface.
- <function>
- The function is a name for the functionality that the given
- string shall be used for. It can be one of:
- input use the string as data prompt.
- verify use the string as verification prompt. This
- is used to verify a previous input.
- info use the string for informational output.
- error use the string for error output.
- Honestly, there's currently no difference between info and error for the
- moment.
-
- UI_{add,dup}_input_boolean have the same semantics for "add" and "dup",
- and are typically used when one wants to prompt for a yes/no response.
-
-
- All of the functions in this group take a UI and a prompt string.
- The string input and verify addition functions also take a flag argument,
- a buffer for the result to end up with, a minimum input size and a maximum
- input size (the result buffer MUST be large enough to be able to contain
- the maximum number of characters). Additionally, the verify addition
- functions takes another buffer to compare the result against.
- The boolean input functions take an action description string (which should
- be safe to ignore if the expected user action is obvious, for example with
- a dialog box with an OK button and a Cancel button), a string of acceptable
- characters to mean OK and to mean Cancel. The two last strings are checked
- to make sure they don't have common characters. Additionally, the same
- flag argument as for the string input is taken, as well as a result buffer.
- The result buffer is required to be at least one byte long. Depending on
- the answer, the first character from the OK or the Cancel character strings
- will be stored in the first byte of the result buffer. No NUL will be
- added, so the result is *not* a string.
-
- On success, the all return an index of the added information. That index
- is usefull when retrieving results with UI_get0_result(). */
-int UI_add_input_string(UI *ui, const char *prompt, int flags,
- char *result_buf, int minsize, int maxsize);
-int UI_dup_input_string(UI *ui, const char *prompt, int flags,
- char *result_buf, int minsize, int maxsize);
-int UI_add_verify_string(UI *ui, const char *prompt, int flags,
- char *result_buf, int minsize, int maxsize, const char *test_buf);
-int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
- char *result_buf, int minsize, int maxsize, const char *test_buf);
-int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
- const char *ok_chars, const char *cancel_chars,
- int flags, char *result_buf);
-int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
- const char *ok_chars, const char *cancel_chars,
- int flags, char *result_buf);
-int UI_add_info_string(UI *ui, const char *text);
-int UI_dup_info_string(UI *ui, const char *text);
-int UI_add_error_string(UI *ui, const char *text);
-int UI_dup_error_string(UI *ui, const char *text);
-
-/* These are the possible flags. They can be or'ed together. */
-/* Use to have echoing of input */
-#define UI_INPUT_FLAG_ECHO 0x01
-/* Use a default password. Where that password is found is completely
- up to the application, it might for example be in the user data set
- with UI_add_user_data(). It is not recommended to have more than
- one input in each UI being marked with this flag, or the application
- might get confused. */
-#define UI_INPUT_FLAG_DEFAULT_PWD 0x02
-
-/* The user of these routines may want to define flags of their own. The core
- UI won't look at those, but will pass them on to the method routines. They
- must use higher bits so they don't get confused with the UI bits above.
- UI_INPUT_FLAG_USER_BASE tells which is the lowest bit to use. A good
- example of use is this:
-
- #define MY_UI_FLAG1 (0x01 << UI_INPUT_FLAG_USER_BASE)
-
-*/
-#define UI_INPUT_FLAG_USER_BASE 16
-
-
-/* The following function helps construct a prompt. object_desc is a
- textual short description of the object, for example "pass phrase",
- and object_name is the name of the object (might be a card name or
- a file name.
- The returned string shall always be allocated on the heap with
- OPENSSL_malloc(), and need to be free'd with OPENSSL_free().
-
- If the ui_method doesn't contain a pointer to a user-defined prompt
- constructor, a default string is built, looking like this:
-
- "Enter {object_desc} for {object_name}:"
-
- So, if object_desc has the value "pass phrase" and object_name has
- the value "foo.key", the resulting string is:
-
- "Enter pass phrase for foo.key:"
-*/
-char *UI_construct_prompt(UI *ui_method,
- const char *object_desc, const char *object_name);
-
-
-/* The following function is used to store a pointer to user-specific data.
- Any previous such pointer will be returned and replaced.
-
- For callback purposes, this function makes a lot more sense than using
- ex_data, since the latter requires that different parts of OpenSSL or
- applications share the same ex_data index.
-
- Note that the UI_OpenSSL() method completely ignores the user data.
- Other methods may not, however. */
-void *UI_add_user_data(UI *ui, void *user_data);
-/* We need a user data retrieving function as well. */
-void *UI_get0_user_data(UI *ui);
-
-/* Return the result associated with a prompt given with the index i. */
-const char *UI_get0_result(UI *ui, int i);
-
-/* When all strings have been added, process the whole thing. */
-int UI_process(UI *ui);
-
-/* Give a user interface parametrised control commands. This can be used to
- send down an integer, a data pointer or a function pointer, as well as
- be used to get information from a UI. */
-int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f)(void));
-
-/* The commands */
-/* Use UI_CONTROL_PRINT_ERRORS with the value 1 to have UI_process print the
- OpenSSL error stack before printing any info or added error messages and
- before any prompting. */
-#define UI_CTRL_PRINT_ERRORS 1
-/* Check if a UI_process() is possible to do again with the same instance of
- a user interface. This makes UI_ctrl() return 1 if it is redoable, and 0
- if not. */
-#define UI_CTRL_IS_REDOABLE 2
-
-
-/* Some methods may use extra data */
-#define UI_set_app_data(s,arg) UI_set_ex_data(s,0,arg)
-#define UI_get_app_data(s) UI_get_ex_data(s,0)
-int UI_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int UI_set_ex_data(UI *r,int idx,void *arg);
-void *UI_get_ex_data(UI *r, int idx);
-
-/* Use specific methods instead of the built-in one */
-void UI_set_default_method(const UI_METHOD *meth);
-const UI_METHOD *UI_get_default_method(void);
-const UI_METHOD *UI_get_method(UI *ui);
-const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth);
-
-/* The method with all the built-in thingies */
-UI_METHOD *UI_OpenSSL(void);
-
-
-/* ---------- For method writers ---------- */
-/* A method contains a number of functions that implement the low level
- of the User Interface. The functions are:
-
- an opener This function starts a session, maybe by opening
- a channel to a tty, or by opening a window.
- a writer This function is called to write a given string,
- maybe to the tty, maybe as a field label in a
- window.
- a flusher This function is called to flush everything that
- has been output so far. It can be used to actually
- display a dialog box after it has been built.
- a reader This function is called to read a given prompt,
- maybe from the tty, maybe from a field in a
- window. Note that it's called wth all string
- structures, not only the prompt ones, so it must
- check such things itself.
- a closer This function closes the session, maybe by closing
- the channel to the tty, or closing the window.
-
- All these functions are expected to return:
-
- 0 on error.
- 1 on success.
- -1 on out-of-band events, for example if some prompting has
- been canceled (by pressing Ctrl-C, for example). This is
- only checked when returned by the flusher or the reader.
-
- The way this is used, the opener is first called, then the writer for all
- strings, then the flusher, then the reader for all strings and finally the
- closer. Note that if you want to prompt from a terminal or other command
- line interface, the best is to have the reader also write the prompts
- instead of having the writer do it. If you want to prompt from a dialog
- box, the writer can be used to build up the contents of the box, and the
- flusher to actually display the box and run the event loop until all data
- has been given, after which the reader only grabs the given data and puts
- them back into the UI strings.
-
- All method functions take a UI as argument. Additionally, the writer and
- the reader take a UI_STRING.
-*/
-
-/* The UI_STRING type is the data structure that contains all the needed info
- about a string or a prompt, including test data for a verification prompt.
-*/
-typedef struct ui_string_st UI_STRING;
-DECLARE_STACK_OF(UI_STRING)
-
-/* The different types of strings that are currently supported.
- This is only needed by method authors. */
-enum UI_string_types
- {
- UIT_NONE=0,
- UIT_PROMPT, /* Prompt for a string */
- UIT_VERIFY, /* Prompt for a string and verify */
- UIT_BOOLEAN, /* Prompt for a yes/no response */
- UIT_INFO, /* Send info to the user */
- UIT_ERROR /* Send an error message to the user */
- };
-
-/* Create and manipulate methods */
-UI_METHOD *UI_create_method(char *name);
-void UI_destroy_method(UI_METHOD *ui_method);
-int UI_method_set_opener(UI_METHOD *method, int (*opener)(UI *ui));
-int UI_method_set_writer(UI_METHOD *method, int (*writer)(UI *ui, UI_STRING *uis));
-int UI_method_set_flusher(UI_METHOD *method, int (*flusher)(UI *ui));
-int UI_method_set_reader(UI_METHOD *method, int (*reader)(UI *ui, UI_STRING *uis));
-int UI_method_set_closer(UI_METHOD *method, int (*closer)(UI *ui));
-int UI_method_set_prompt_constructor(UI_METHOD *method, char *(*prompt_constructor)(UI* ui, const char* object_desc, const char* object_name));
-int (*UI_method_get_opener(UI_METHOD *method))(UI*);
-int (*UI_method_get_writer(UI_METHOD *method))(UI*,UI_STRING*);
-int (*UI_method_get_flusher(UI_METHOD *method))(UI*);
-int (*UI_method_get_reader(UI_METHOD *method))(UI*,UI_STRING*);
-int (*UI_method_get_closer(UI_METHOD *method))(UI*);
-char * (*UI_method_get_prompt_constructor(UI_METHOD *method))(UI*, const char*, const char*);
-
-/* The following functions are helpers for method writers to access relevant
- data from a UI_STRING. */
-
-/* Return type of the UI_STRING */
-enum UI_string_types UI_get_string_type(UI_STRING *uis);
-/* Return input flags of the UI_STRING */
-int UI_get_input_flags(UI_STRING *uis);
-/* Return the actual string to output (the prompt, info or error) */
-const char *UI_get0_output_string(UI_STRING *uis);
-/* Return the optional action string to output (the boolean promtp instruction) */
-const char *UI_get0_action_string(UI_STRING *uis);
-/* Return the result of a prompt */
-const char *UI_get0_result_string(UI_STRING *uis);
-/* Return the string to test the result against. Only useful with verifies. */
-const char *UI_get0_test_string(UI_STRING *uis);
-/* Return the required minimum size of the result */
-int UI_get_result_minsize(UI_STRING *uis);
-/* Return the required maximum size of the result */
-int UI_get_result_maxsize(UI_STRING *uis);
-/* Set the result of a UI_STRING. */
-int UI_set_result(UI *ui, UI_STRING *uis, const char *result);
-
-
-/* A couple of popular utility functions */
-int UI_UTIL_read_pw_string(char *buf,int length,const char *prompt,int verify);
-int UI_UTIL_read_pw(char *buf,char *buff,int size,const char *prompt,int verify);
-
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_UI_strings(void);
-
-/* Error codes for the UI functions. */
-
-/* Function codes. */
-#define UI_F_GENERAL_ALLOCATE_BOOLEAN 108
-#define UI_F_GENERAL_ALLOCATE_PROMPT 109
-#define UI_F_GENERAL_ALLOCATE_STRING 100
-#define UI_F_UI_CTRL 111
-#define UI_F_UI_DUP_ERROR_STRING 101
-#define UI_F_UI_DUP_INFO_STRING 102
-#define UI_F_UI_DUP_INPUT_BOOLEAN 110
-#define UI_F_UI_DUP_INPUT_STRING 103
-#define UI_F_UI_DUP_VERIFY_STRING 106
-#define UI_F_UI_GET0_RESULT 107
-#define UI_F_UI_NEW_METHOD 104
-#define UI_F_UI_SET_RESULT 105
-
-/* Reason codes. */
-#define UI_R_COMMON_OK_AND_CANCEL_CHARACTERS 104
-#define UI_R_INDEX_TOO_LARGE 102
-#define UI_R_INDEX_TOO_SMALL 103
-#define UI_R_NO_RESULT_BUFFER 105
-#define UI_R_RESULT_TOO_LARGE 100
-#define UI_R_RESULT_TOO_SMALL 101
-#define UI_R_UNKNOWN_CONTROL_COMMAND 106
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/ui_compat.h b/drivers/builtin_openssl/openssl/ui_compat.h
deleted file mode 100644
index b35c9bb7fd..0000000000
--- a/drivers/builtin_openssl/openssl/ui_compat.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */
-/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
- * project 2001.
- */
-/* ====================================================================
- * Copyright (c) 2001 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_UI_COMPAT_H
-#define HEADER_UI_COMPAT_H
-
-#include <openssl/opensslconf.h>
-#include <openssl/ui.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The following functions were previously part of the DES section,
- and are provided here for backward compatibility reasons. */
-
-#define des_read_pw_string(b,l,p,v) \
- _ossl_old_des_read_pw_string((b),(l),(p),(v))
-#define des_read_pw(b,bf,s,p,v) \
- _ossl_old_des_read_pw((b),(bf),(s),(p),(v))
-
-int _ossl_old_des_read_pw_string(char *buf,int length,const char *prompt,int verify);
-int _ossl_old_des_read_pw(char *buf,char *buff,int size,const char *prompt,int verify);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/whrlpool.h b/drivers/builtin_openssl/openssl/whrlpool.h
deleted file mode 100644
index 9e01f5b076..0000000000
--- a/drivers/builtin_openssl/openssl/whrlpool.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef HEADER_WHRLPOOL_H
-#define HEADER_WHRLPOOL_H
-
-#include <openssl/e_os2.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define WHIRLPOOL_DIGEST_LENGTH (512/8)
-#define WHIRLPOOL_BBLOCK 512
-#define WHIRLPOOL_COUNTER (256/8)
-
-typedef struct {
- union {
- unsigned char c[WHIRLPOOL_DIGEST_LENGTH];
- /* double q is here to ensure 64-bit alignment */
- double q[WHIRLPOOL_DIGEST_LENGTH/sizeof(double)];
- } H;
- unsigned char data[WHIRLPOOL_BBLOCK/8];
- unsigned int bitoff;
- size_t bitlen[WHIRLPOOL_COUNTER/sizeof(size_t)];
- } WHIRLPOOL_CTX;
-
-#ifndef OPENSSL_NO_WHIRLPOOL
-#ifdef OPENSSL_FIPS
-int private_WHIRLPOOL_Init(WHIRLPOOL_CTX *c);
-#endif
-int WHIRLPOOL_Init (WHIRLPOOL_CTX *c);
-int WHIRLPOOL_Update (WHIRLPOOL_CTX *c,const void *inp,size_t bytes);
-void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c,const void *inp,size_t bits);
-int WHIRLPOOL_Final (unsigned char *md,WHIRLPOOL_CTX *c);
-unsigned char *WHIRLPOOL(const void *inp,size_t bytes,unsigned char *md);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/builtin_openssl/openssl/x509.h b/drivers/builtin_openssl/openssl/x509.h
deleted file mode 100644
index 092dd7450d..0000000000
--- a/drivers/builtin_openssl/openssl/x509.h
+++ /dev/null
@@ -1,1297 +0,0 @@
-/* crypto/x509/x509.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECDH support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-
-#ifndef HEADER_X509_H
-#define HEADER_X509_H
-
-#include <openssl/e_os2.h>
-#include <openssl/symhacks.h>
-#ifndef OPENSSL_NO_BUFFER
-#include <openssl/buffer.h>
-#endif
-#ifndef OPENSSL_NO_EVP
-#include <openssl/evp.h>
-#endif
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#include <openssl/stack.h>
-#include <openssl/asn1.h>
-#include <openssl/safestack.h>
-
-#ifndef OPENSSL_NO_EC
-#include <openssl/ec.h>
-#endif
-
-#ifndef OPENSSL_NO_ECDSA
-#include <openssl/ecdsa.h>
-#endif
-
-#ifndef OPENSSL_NO_ECDH
-#include <openssl/ecdh.h>
-#endif
-
-#ifndef OPENSSL_NO_DEPRECATED
-#ifndef OPENSSL_NO_RSA
-#include <openssl/rsa.h>
-#endif
-#ifndef OPENSSL_NO_DSA
-#include <openssl/dsa.h>
-#endif
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#endif
-#endif
-
-#ifndef OPENSSL_NO_SHA
-#include <openssl/sha.h>
-#endif
-#include <openssl/ossl_typ.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef OPENSSL_SYS_WIN32
-/* Under Win32 these are defined in wincrypt.h */
-#undef X509_NAME
-#undef X509_CERT_PAIR
-#undef X509_EXTENSIONS
-#endif
-
-#define X509_FILETYPE_PEM 1
-#define X509_FILETYPE_ASN1 2
-#define X509_FILETYPE_DEFAULT 3
-
-#define X509v3_KU_DIGITAL_SIGNATURE 0x0080
-#define X509v3_KU_NON_REPUDIATION 0x0040
-#define X509v3_KU_KEY_ENCIPHERMENT 0x0020
-#define X509v3_KU_DATA_ENCIPHERMENT 0x0010
-#define X509v3_KU_KEY_AGREEMENT 0x0008
-#define X509v3_KU_KEY_CERT_SIGN 0x0004
-#define X509v3_KU_CRL_SIGN 0x0002
-#define X509v3_KU_ENCIPHER_ONLY 0x0001
-#define X509v3_KU_DECIPHER_ONLY 0x8000
-#define X509v3_KU_UNDEF 0xffff
-
-typedef struct X509_objects_st
- {
- int nid;
- int (*a2i)(void);
- int (*i2a)(void);
- } X509_OBJECTS;
-
-struct X509_algor_st
- {
- ASN1_OBJECT *algorithm;
- ASN1_TYPE *parameter;
- } /* X509_ALGOR */;
-
-DECLARE_ASN1_SET_OF(X509_ALGOR)
-
-typedef STACK_OF(X509_ALGOR) X509_ALGORS;
-
-typedef struct X509_val_st
- {
- ASN1_TIME *notBefore;
- ASN1_TIME *notAfter;
- } X509_VAL;
-
-struct X509_pubkey_st
- {
- X509_ALGOR *algor;
- ASN1_BIT_STRING *public_key;
- EVP_PKEY *pkey;
- };
-
-typedef struct X509_sig_st
- {
- X509_ALGOR *algor;
- ASN1_OCTET_STRING *digest;
- } X509_SIG;
-
-typedef struct X509_name_entry_st
- {
- ASN1_OBJECT *object;
- ASN1_STRING *value;
- int set;
- int size; /* temp variable */
- } X509_NAME_ENTRY;
-
-DECLARE_STACK_OF(X509_NAME_ENTRY)
-DECLARE_ASN1_SET_OF(X509_NAME_ENTRY)
-
-/* we always keep X509_NAMEs in 2 forms. */
-struct X509_name_st
- {
- STACK_OF(X509_NAME_ENTRY) *entries;
- int modified; /* true if 'bytes' needs to be built */
-#ifndef OPENSSL_NO_BUFFER
- BUF_MEM *bytes;
-#else
- char *bytes;
-#endif
-/* unsigned long hash; Keep the hash around for lookups */
- unsigned char *canon_enc;
- int canon_enclen;
- } /* X509_NAME */;
-
-DECLARE_STACK_OF(X509_NAME)
-
-#define X509_EX_V_NETSCAPE_HACK 0x8000
-#define X509_EX_V_INIT 0x0001
-typedef struct X509_extension_st
- {
- ASN1_OBJECT *object;
- ASN1_BOOLEAN critical;
- ASN1_OCTET_STRING *value;
- } X509_EXTENSION;
-
-typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
-
-DECLARE_STACK_OF(X509_EXTENSION)
-DECLARE_ASN1_SET_OF(X509_EXTENSION)
-
-/* a sequence of these are used */
-typedef struct x509_attributes_st
- {
- ASN1_OBJECT *object;
- int single; /* 0 for a set, 1 for a single item (which is wrong) */
- union {
- char *ptr;
-/* 0 */ STACK_OF(ASN1_TYPE) *set;
-/* 1 */ ASN1_TYPE *single;
- } value;
- } X509_ATTRIBUTE;
-
-DECLARE_STACK_OF(X509_ATTRIBUTE)
-DECLARE_ASN1_SET_OF(X509_ATTRIBUTE)
-
-
-typedef struct X509_req_info_st
- {
- ASN1_ENCODING enc;
- ASN1_INTEGER *version;
- X509_NAME *subject;
- X509_PUBKEY *pubkey;
- /* d=2 hl=2 l= 0 cons: cont: 00 */
- STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
- } X509_REQ_INFO;
-
-typedef struct X509_req_st
- {
- X509_REQ_INFO *req_info;
- X509_ALGOR *sig_alg;
- ASN1_BIT_STRING *signature;
- int references;
- } X509_REQ;
-
-typedef struct x509_cinf_st
- {
- ASN1_INTEGER *version; /* [ 0 ] default of v1 */
- ASN1_INTEGER *serialNumber;
- X509_ALGOR *signature;
- X509_NAME *issuer;
- X509_VAL *validity;
- X509_NAME *subject;
- X509_PUBKEY *key;
- ASN1_BIT_STRING *issuerUID; /* [ 1 ] optional in v2 */
- ASN1_BIT_STRING *subjectUID; /* [ 2 ] optional in v2 */
- STACK_OF(X509_EXTENSION) *extensions; /* [ 3 ] optional in v3 */
- ASN1_ENCODING enc;
- } X509_CINF;
-
-/* This stuff is certificate "auxiliary info"
- * it contains details which are useful in certificate
- * stores and databases. When used this is tagged onto
- * the end of the certificate itself
- */
-
-typedef struct x509_cert_aux_st
- {
- STACK_OF(ASN1_OBJECT) *trust; /* trusted uses */
- STACK_OF(ASN1_OBJECT) *reject; /* rejected uses */
- ASN1_UTF8STRING *alias; /* "friendly name" */
- ASN1_OCTET_STRING *keyid; /* key id of private key */
- STACK_OF(X509_ALGOR) *other; /* other unspecified info */
- } X509_CERT_AUX;
-
-struct x509_st
- {
- X509_CINF *cert_info;
- X509_ALGOR *sig_alg;
- ASN1_BIT_STRING *signature;
- int valid;
- int references;
- char *name;
- CRYPTO_EX_DATA ex_data;
- /* These contain copies of various extension values */
- long ex_pathlen;
- long ex_pcpathlen;
- unsigned long ex_flags;
- unsigned long ex_kusage;
- unsigned long ex_xkusage;
- unsigned long ex_nscert;
- ASN1_OCTET_STRING *skid;
- AUTHORITY_KEYID *akid;
- X509_POLICY_CACHE *policy_cache;
- STACK_OF(DIST_POINT) *crldp;
- STACK_OF(GENERAL_NAME) *altname;
- NAME_CONSTRAINTS *nc;
-#ifndef OPENSSL_NO_RFC3779
- STACK_OF(IPAddressFamily) *rfc3779_addr;
- struct ASIdentifiers_st *rfc3779_asid;
-#endif
-#ifndef OPENSSL_NO_SHA
- unsigned char sha1_hash[SHA_DIGEST_LENGTH];
-#endif
- X509_CERT_AUX *aux;
- } /* X509 */;
-
-DECLARE_STACK_OF(X509)
-DECLARE_ASN1_SET_OF(X509)
-
-/* This is used for a table of trust checking functions */
-
-typedef struct x509_trust_st {
- int trust;
- int flags;
- int (*check_trust)(struct x509_trust_st *, X509 *, int);
- char *name;
- int arg1;
- void *arg2;
-} X509_TRUST;
-
-DECLARE_STACK_OF(X509_TRUST)
-
-typedef struct x509_cert_pair_st {
- X509 *forward;
- X509 *reverse;
-} X509_CERT_PAIR;
-
-/* standard trust ids */
-
-#define X509_TRUST_DEFAULT -1 /* Only valid in purpose settings */
-
-#define X509_TRUST_COMPAT 1
-#define X509_TRUST_SSL_CLIENT 2
-#define X509_TRUST_SSL_SERVER 3
-#define X509_TRUST_EMAIL 4
-#define X509_TRUST_OBJECT_SIGN 5
-#define X509_TRUST_OCSP_SIGN 6
-#define X509_TRUST_OCSP_REQUEST 7
-#define X509_TRUST_TSA 8
-
-/* Keep these up to date! */
-#define X509_TRUST_MIN 1
-#define X509_TRUST_MAX 8
-
-
-/* trust_flags values */
-#define X509_TRUST_DYNAMIC 1
-#define X509_TRUST_DYNAMIC_NAME 2
-
-/* check_trust return codes */
-
-#define X509_TRUST_TRUSTED 1
-#define X509_TRUST_REJECTED 2
-#define X509_TRUST_UNTRUSTED 3
-
-/* Flags for X509_print_ex() */
-
-#define X509_FLAG_COMPAT 0
-#define X509_FLAG_NO_HEADER 1L
-#define X509_FLAG_NO_VERSION (1L << 1)
-#define X509_FLAG_NO_SERIAL (1L << 2)
-#define X509_FLAG_NO_SIGNAME (1L << 3)
-#define X509_FLAG_NO_ISSUER (1L << 4)
-#define X509_FLAG_NO_VALIDITY (1L << 5)
-#define X509_FLAG_NO_SUBJECT (1L << 6)
-#define X509_FLAG_NO_PUBKEY (1L << 7)
-#define X509_FLAG_NO_EXTENSIONS (1L << 8)
-#define X509_FLAG_NO_SIGDUMP (1L << 9)
-#define X509_FLAG_NO_AUX (1L << 10)
-#define X509_FLAG_NO_ATTRIBUTES (1L << 11)
-
-/* Flags specific to X509_NAME_print_ex() */
-
-/* The field separator information */
-
-#define XN_FLAG_SEP_MASK (0xf << 16)
-
-#define XN_FLAG_COMPAT 0 /* Traditional SSLeay: use old X509_NAME_print */
-#define XN_FLAG_SEP_COMMA_PLUS (1 << 16) /* RFC2253 ,+ */
-#define XN_FLAG_SEP_CPLUS_SPC (2 << 16) /* ,+ spaced: more readable */
-#define XN_FLAG_SEP_SPLUS_SPC (3 << 16) /* ;+ spaced */
-#define XN_FLAG_SEP_MULTILINE (4 << 16) /* One line per field */
-
-#define XN_FLAG_DN_REV (1 << 20) /* Reverse DN order */
-
-/* How the field name is shown */
-
-#define XN_FLAG_FN_MASK (0x3 << 21)
-
-#define XN_FLAG_FN_SN 0 /* Object short name */
-#define XN_FLAG_FN_LN (1 << 21) /* Object long name */
-#define XN_FLAG_FN_OID (2 << 21) /* Always use OIDs */
-#define XN_FLAG_FN_NONE (3 << 21) /* No field names */
-
-#define XN_FLAG_SPC_EQ (1 << 23) /* Put spaces round '=' */
-
-/* This determines if we dump fields we don't recognise:
- * RFC2253 requires this.
- */
-
-#define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24)
-
-#define XN_FLAG_FN_ALIGN (1 << 25) /* Align field names to 20 characters */
-
-/* Complete set of RFC2253 flags */
-
-#define XN_FLAG_RFC2253 (ASN1_STRFLGS_RFC2253 | \
- XN_FLAG_SEP_COMMA_PLUS | \
- XN_FLAG_DN_REV | \
- XN_FLAG_FN_SN | \
- XN_FLAG_DUMP_UNKNOWN_FIELDS)
-
-/* readable oneline form */
-
-#define XN_FLAG_ONELINE (ASN1_STRFLGS_RFC2253 | \
- ASN1_STRFLGS_ESC_QUOTE | \
- XN_FLAG_SEP_CPLUS_SPC | \
- XN_FLAG_SPC_EQ | \
- XN_FLAG_FN_SN)
-
-/* readable multiline form */
-
-#define XN_FLAG_MULTILINE (ASN1_STRFLGS_ESC_CTRL | \
- ASN1_STRFLGS_ESC_MSB | \
- XN_FLAG_SEP_MULTILINE | \
- XN_FLAG_SPC_EQ | \
- XN_FLAG_FN_LN | \
- XN_FLAG_FN_ALIGN)
-
-struct x509_revoked_st
- {
- ASN1_INTEGER *serialNumber;
- ASN1_TIME *revocationDate;
- STACK_OF(X509_EXTENSION) /* optional */ *extensions;
- /* Set up if indirect CRL */
- STACK_OF(GENERAL_NAME) *issuer;
- /* Revocation reason */
- int reason;
- int sequence; /* load sequence */
- };
-
-DECLARE_STACK_OF(X509_REVOKED)
-DECLARE_ASN1_SET_OF(X509_REVOKED)
-
-typedef struct X509_crl_info_st
- {
- ASN1_INTEGER *version;
- X509_ALGOR *sig_alg;
- X509_NAME *issuer;
- ASN1_TIME *lastUpdate;
- ASN1_TIME *nextUpdate;
- STACK_OF(X509_REVOKED) *revoked;
- STACK_OF(X509_EXTENSION) /* [0] */ *extensions;
- ASN1_ENCODING enc;
- } X509_CRL_INFO;
-
-struct X509_crl_st
- {
- /* actual signature */
- X509_CRL_INFO *crl;
- X509_ALGOR *sig_alg;
- ASN1_BIT_STRING *signature;
- int references;
- int flags;
- /* Copies of various extensions */
- AUTHORITY_KEYID *akid;
- ISSUING_DIST_POINT *idp;
- /* Convenient breakdown of IDP */
- int idp_flags;
- int idp_reasons;
- /* CRL and base CRL numbers for delta processing */
- ASN1_INTEGER *crl_number;
- ASN1_INTEGER *base_crl_number;
-#ifndef OPENSSL_NO_SHA
- unsigned char sha1_hash[SHA_DIGEST_LENGTH];
-#endif
- STACK_OF(GENERAL_NAMES) *issuers;
- const X509_CRL_METHOD *meth;
- void *meth_data;
- } /* X509_CRL */;
-
-DECLARE_STACK_OF(X509_CRL)
-DECLARE_ASN1_SET_OF(X509_CRL)
-
-typedef struct private_key_st
- {
- int version;
- /* The PKCS#8 data types */
- X509_ALGOR *enc_algor;
- ASN1_OCTET_STRING *enc_pkey; /* encrypted pub key */
-
- /* When decrypted, the following will not be NULL */
- EVP_PKEY *dec_pkey;
-
- /* used to encrypt and decrypt */
- int key_length;
- char *key_data;
- int key_free; /* true if we should auto free key_data */
-
- /* expanded version of 'enc_algor' */
- EVP_CIPHER_INFO cipher;
-
- int references;
- } X509_PKEY;
-
-#ifndef OPENSSL_NO_EVP
-typedef struct X509_info_st
- {
- X509 *x509;
- X509_CRL *crl;
- X509_PKEY *x_pkey;
-
- EVP_CIPHER_INFO enc_cipher;
- int enc_len;
- char *enc_data;
-
- int references;
- } X509_INFO;
-
-DECLARE_STACK_OF(X509_INFO)
-#endif
-
-/* The next 2 structures and their 8 routines were sent to me by
- * Pat Richard <patr@x509.com> and are used to manipulate
- * Netscapes spki structures - useful if you are writing a CA web page
- */
-typedef struct Netscape_spkac_st
- {
- X509_PUBKEY *pubkey;
- ASN1_IA5STRING *challenge; /* challenge sent in atlas >= PR2 */
- } NETSCAPE_SPKAC;
-
-typedef struct Netscape_spki_st
- {
- NETSCAPE_SPKAC *spkac; /* signed public key and challenge */
- X509_ALGOR *sig_algor;
- ASN1_BIT_STRING *signature;
- } NETSCAPE_SPKI;
-
-/* Netscape certificate sequence structure */
-typedef struct Netscape_certificate_sequence
- {
- ASN1_OBJECT *type;
- STACK_OF(X509) *certs;
- } NETSCAPE_CERT_SEQUENCE;
-
-/* Unused (and iv length is wrong)
-typedef struct CBCParameter_st
- {
- unsigned char iv[8];
- } CBC_PARAM;
-*/
-
-/* Password based encryption structure */
-
-typedef struct PBEPARAM_st {
-ASN1_OCTET_STRING *salt;
-ASN1_INTEGER *iter;
-} PBEPARAM;
-
-/* Password based encryption V2 structures */
-
-typedef struct PBE2PARAM_st {
-X509_ALGOR *keyfunc;
-X509_ALGOR *encryption;
-} PBE2PARAM;
-
-typedef struct PBKDF2PARAM_st {
-ASN1_TYPE *salt; /* Usually OCTET STRING but could be anything */
-ASN1_INTEGER *iter;
-ASN1_INTEGER *keylength;
-X509_ALGOR *prf;
-} PBKDF2PARAM;
-
-
-/* PKCS#8 private key info structure */
-
-struct pkcs8_priv_key_info_st
- {
- int broken; /* Flag for various broken formats */
-#define PKCS8_OK 0
-#define PKCS8_NO_OCTET 1
-#define PKCS8_EMBEDDED_PARAM 2
-#define PKCS8_NS_DB 3
-#define PKCS8_NEG_PRIVKEY 4
- ASN1_INTEGER *version;
- X509_ALGOR *pkeyalg;
- ASN1_TYPE *pkey; /* Should be OCTET STRING but some are broken */
- STACK_OF(X509_ATTRIBUTE) *attributes;
- };
-
-#ifdef __cplusplus
-}
-#endif
-
-#include <openssl/x509_vfy.h>
-#include <openssl/pkcs7.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define X509_EXT_PACK_UNKNOWN 1
-#define X509_EXT_PACK_STRING 2
-
-#define X509_get_version(x) ASN1_INTEGER_get((x)->cert_info->version)
-/* #define X509_get_serialNumber(x) ((x)->cert_info->serialNumber) */
-#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
-#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
-#define X509_extract_key(x) X509_get_pubkey(x) /*****/
-#define X509_REQ_get_version(x) ASN1_INTEGER_get((x)->req_info->version)
-#define X509_REQ_get_subject_name(x) ((x)->req_info->subject)
-#define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a)
-#define X509_name_cmp(a,b) X509_NAME_cmp((a),(b))
-#define X509_get_signature_type(x) EVP_PKEY_type(OBJ_obj2nid((x)->sig_alg->algorithm))
-
-#define X509_CRL_get_version(x) ASN1_INTEGER_get((x)->crl->version)
-#define X509_CRL_get_lastUpdate(x) ((x)->crl->lastUpdate)
-#define X509_CRL_get_nextUpdate(x) ((x)->crl->nextUpdate)
-#define X509_CRL_get_issuer(x) ((x)->crl->issuer)
-#define X509_CRL_get_REVOKED(x) ((x)->crl->revoked)
-
-void X509_CRL_set_default_method(const X509_CRL_METHOD *meth);
-X509_CRL_METHOD *X509_CRL_METHOD_new(
- int (*crl_init)(X509_CRL *crl),
- int (*crl_free)(X509_CRL *crl),
- int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
- ASN1_INTEGER *ser, X509_NAME *issuer),
- int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk));
-void X509_CRL_METHOD_free(X509_CRL_METHOD *m);
-
-void X509_CRL_set_meth_data(X509_CRL *crl, void *dat);
-void *X509_CRL_get_meth_data(X509_CRL *crl);
-
-/* This one is only used so that a binary form can output, as in
- * i2d_X509_NAME(X509_get_X509_PUBKEY(x),&buf) */
-#define X509_get_X509_PUBKEY(x) ((x)->cert_info->key)
-
-
-const char *X509_verify_cert_error_string(long n);
-
-#ifndef OPENSSL_NO_EVP
-int X509_verify(X509 *a, EVP_PKEY *r);
-
-int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r);
-int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r);
-int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r);
-
-NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len);
-char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *x);
-EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x);
-int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey);
-
-int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki);
-
-int X509_signature_dump(BIO *bp,const ASN1_STRING *sig, int indent);
-int X509_signature_print(BIO *bp,X509_ALGOR *alg, ASN1_STRING *sig);
-
-int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
-int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx);
-int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md);
-int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx);
-int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md);
-int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx);
-int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md);
-
-int X509_pubkey_digest(const X509 *data,const EVP_MD *type,
- unsigned char *md, unsigned int *len);
-int X509_digest(const X509 *data,const EVP_MD *type,
- unsigned char *md, unsigned int *len);
-int X509_CRL_digest(const X509_CRL *data,const EVP_MD *type,
- unsigned char *md, unsigned int *len);
-int X509_REQ_digest(const X509_REQ *data,const EVP_MD *type,
- unsigned char *md, unsigned int *len);
-int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type,
- unsigned char *md, unsigned int *len);
-#endif
-
-#ifndef OPENSSL_NO_FP_API
-X509 *d2i_X509_fp(FILE *fp, X509 **x509);
-int i2d_X509_fp(FILE *fp,X509 *x509);
-X509_CRL *d2i_X509_CRL_fp(FILE *fp,X509_CRL **crl);
-int i2d_X509_CRL_fp(FILE *fp,X509_CRL *crl);
-X509_REQ *d2i_X509_REQ_fp(FILE *fp,X509_REQ **req);
-int i2d_X509_REQ_fp(FILE *fp,X509_REQ *req);
-#ifndef OPENSSL_NO_RSA
-RSA *d2i_RSAPrivateKey_fp(FILE *fp,RSA **rsa);
-int i2d_RSAPrivateKey_fp(FILE *fp,RSA *rsa);
-RSA *d2i_RSAPublicKey_fp(FILE *fp,RSA **rsa);
-int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa);
-RSA *d2i_RSA_PUBKEY_fp(FILE *fp,RSA **rsa);
-int i2d_RSA_PUBKEY_fp(FILE *fp,RSA *rsa);
-#endif
-#ifndef OPENSSL_NO_DSA
-DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa);
-int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa);
-DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa);
-int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa);
-#endif
-#ifndef OPENSSL_NO_EC
-EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey);
-int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey);
-EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey);
-int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey);
-#endif
-X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8);
-int i2d_PKCS8_fp(FILE *fp,X509_SIG *p8);
-PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
- PKCS8_PRIV_KEY_INFO **p8inf);
-int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf);
-int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key);
-int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey);
-EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a);
-int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey);
-EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a);
-#endif
-
-#ifndef OPENSSL_NO_BIO
-X509 *d2i_X509_bio(BIO *bp,X509 **x509);
-int i2d_X509_bio(BIO *bp,X509 *x509);
-X509_CRL *d2i_X509_CRL_bio(BIO *bp,X509_CRL **crl);
-int i2d_X509_CRL_bio(BIO *bp,X509_CRL *crl);
-X509_REQ *d2i_X509_REQ_bio(BIO *bp,X509_REQ **req);
-int i2d_X509_REQ_bio(BIO *bp,X509_REQ *req);
-#ifndef OPENSSL_NO_RSA
-RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **rsa);
-int i2d_RSAPrivateKey_bio(BIO *bp,RSA *rsa);
-RSA *d2i_RSAPublicKey_bio(BIO *bp,RSA **rsa);
-int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa);
-RSA *d2i_RSA_PUBKEY_bio(BIO *bp,RSA **rsa);
-int i2d_RSA_PUBKEY_bio(BIO *bp,RSA *rsa);
-#endif
-#ifndef OPENSSL_NO_DSA
-DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa);
-int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa);
-DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa);
-int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa);
-#endif
-#ifndef OPENSSL_NO_EC
-EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey);
-int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey);
-EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey);
-int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey);
-#endif
-X509_SIG *d2i_PKCS8_bio(BIO *bp,X509_SIG **p8);
-int i2d_PKCS8_bio(BIO *bp,X509_SIG *p8);
-PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,
- PKCS8_PRIV_KEY_INFO **p8inf);
-int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf);
-int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key);
-int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey);
-EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a);
-int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey);
-EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a);
-#endif
-
-X509 *X509_dup(X509 *x509);
-X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa);
-X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex);
-X509_CRL *X509_CRL_dup(X509_CRL *crl);
-X509_REQ *X509_REQ_dup(X509_REQ *req);
-X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn);
-int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *aobj, int ptype, void *pval);
-void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval,
- X509_ALGOR *algor);
-void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md);
-
-X509_NAME *X509_NAME_dup(X509_NAME *xn);
-X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne);
-
-int X509_cmp_time(const ASN1_TIME *s, time_t *t);
-int X509_cmp_current_time(const ASN1_TIME *s);
-ASN1_TIME * X509_time_adj(ASN1_TIME *s, long adj, time_t *t);
-ASN1_TIME * X509_time_adj_ex(ASN1_TIME *s,
- int offset_day, long offset_sec, time_t *t);
-ASN1_TIME * X509_gmtime_adj(ASN1_TIME *s, long adj);
-
-const char * X509_get_default_cert_area(void );
-const char * X509_get_default_cert_dir(void );
-const char * X509_get_default_cert_file(void );
-const char * X509_get_default_cert_dir_env(void );
-const char * X509_get_default_cert_file_env(void );
-const char * X509_get_default_private_dir(void );
-
-X509_REQ * X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
-X509 * X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY *pkey);
-
-DECLARE_ASN1_FUNCTIONS(X509_ALGOR)
-DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS)
-DECLARE_ASN1_FUNCTIONS(X509_VAL)
-
-DECLARE_ASN1_FUNCTIONS(X509_PUBKEY)
-
-int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
-EVP_PKEY * X509_PUBKEY_get(X509_PUBKEY *key);
-int X509_get_pubkey_parameters(EVP_PKEY *pkey,
- STACK_OF(X509) *chain);
-int i2d_PUBKEY(EVP_PKEY *a,unsigned char **pp);
-EVP_PKEY * d2i_PUBKEY(EVP_PKEY **a,const unsigned char **pp,
- long length);
-#ifndef OPENSSL_NO_RSA
-int i2d_RSA_PUBKEY(RSA *a,unsigned char **pp);
-RSA * d2i_RSA_PUBKEY(RSA **a,const unsigned char **pp,
- long length);
-#endif
-#ifndef OPENSSL_NO_DSA
-int i2d_DSA_PUBKEY(DSA *a,unsigned char **pp);
-DSA * d2i_DSA_PUBKEY(DSA **a,const unsigned char **pp,
- long length);
-#endif
-#ifndef OPENSSL_NO_EC
-int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp);
-EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp,
- long length);
-#endif
-
-DECLARE_ASN1_FUNCTIONS(X509_SIG)
-DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO)
-DECLARE_ASN1_FUNCTIONS(X509_REQ)
-
-DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE)
-X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value);
-
-DECLARE_ASN1_FUNCTIONS(X509_EXTENSION)
-DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
-
-DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY)
-
-DECLARE_ASN1_FUNCTIONS(X509_NAME)
-
-int X509_NAME_set(X509_NAME **xn, X509_NAME *name);
-
-DECLARE_ASN1_FUNCTIONS(X509_CINF)
-
-DECLARE_ASN1_FUNCTIONS(X509)
-DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX)
-
-DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR)
-
-int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int X509_set_ex_data(X509 *r, int idx, void *arg);
-void *X509_get_ex_data(X509 *r, int idx);
-int i2d_X509_AUX(X509 *a,unsigned char **pp);
-X509 * d2i_X509_AUX(X509 **a,const unsigned char **pp,long length);
-
-int X509_alias_set1(X509 *x, unsigned char *name, int len);
-int X509_keyid_set1(X509 *x, unsigned char *id, int len);
-unsigned char * X509_alias_get0(X509 *x, int *len);
-unsigned char * X509_keyid_get0(X509 *x, int *len);
-int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int);
-int X509_TRUST_set(int *t, int trust);
-int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj);
-int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj);
-void X509_trust_clear(X509 *x);
-void X509_reject_clear(X509 *x);
-
-DECLARE_ASN1_FUNCTIONS(X509_REVOKED)
-DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO)
-DECLARE_ASN1_FUNCTIONS(X509_CRL)
-
-int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
-int X509_CRL_get0_by_serial(X509_CRL *crl,
- X509_REVOKED **ret, ASN1_INTEGER *serial);
-int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x);
-
-X509_PKEY * X509_PKEY_new(void );
-void X509_PKEY_free(X509_PKEY *a);
-int i2d_X509_PKEY(X509_PKEY *a,unsigned char **pp);
-X509_PKEY * d2i_X509_PKEY(X509_PKEY **a,const unsigned char **pp,long length);
-
-DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI)
-DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC)
-DECLARE_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE)
-
-#ifndef OPENSSL_NO_EVP
-X509_INFO * X509_INFO_new(void);
-void X509_INFO_free(X509_INFO *a);
-char * X509_NAME_oneline(X509_NAME *a,char *buf,int size);
-
-int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *algor1,
- ASN1_BIT_STRING *signature,char *data,EVP_PKEY *pkey);
-
-int ASN1_digest(i2d_of_void *i2d,const EVP_MD *type,char *data,
- unsigned char *md,unsigned int *len);
-
-int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1,
- X509_ALGOR *algor2, ASN1_BIT_STRING *signature,
- char *data,EVP_PKEY *pkey, const EVP_MD *type);
-
-int ASN1_item_digest(const ASN1_ITEM *it,const EVP_MD *type,void *data,
- unsigned char *md,unsigned int *len);
-
-int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1,
- ASN1_BIT_STRING *signature,void *data,EVP_PKEY *pkey);
-
-int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
- ASN1_BIT_STRING *signature,
- void *data, EVP_PKEY *pkey, const EVP_MD *type);
-int ASN1_item_sign_ctx(const ASN1_ITEM *it,
- X509_ALGOR *algor1, X509_ALGOR *algor2,
- ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx);
-#endif
-
-int X509_set_version(X509 *x,long version);
-int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial);
-ASN1_INTEGER * X509_get_serialNumber(X509 *x);
-int X509_set_issuer_name(X509 *x, X509_NAME *name);
-X509_NAME * X509_get_issuer_name(X509 *a);
-int X509_set_subject_name(X509 *x, X509_NAME *name);
-X509_NAME * X509_get_subject_name(X509 *a);
-int X509_set_notBefore(X509 *x, const ASN1_TIME *tm);
-int X509_set_notAfter(X509 *x, const ASN1_TIME *tm);
-int X509_set_pubkey(X509 *x, EVP_PKEY *pkey);
-EVP_PKEY * X509_get_pubkey(X509 *x);
-ASN1_BIT_STRING * X509_get0_pubkey_bitstr(const X509 *x);
-int X509_certificate_type(X509 *x,EVP_PKEY *pubkey /* optional */);
-
-int X509_REQ_set_version(X509_REQ *x,long version);
-int X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name);
-int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
-EVP_PKEY * X509_REQ_get_pubkey(X509_REQ *req);
-int X509_REQ_extension_nid(int nid);
-int * X509_REQ_get_extension_nids(void);
-void X509_REQ_set_extension_nids(int *nids);
-STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req);
-int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts,
- int nid);
-int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts);
-int X509_REQ_get_attr_count(const X509_REQ *req);
-int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid,
- int lastpos);
-int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj,
- int lastpos);
-X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc);
-X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc);
-int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr);
-int X509_REQ_add1_attr_by_OBJ(X509_REQ *req,
- const ASN1_OBJECT *obj, int type,
- const unsigned char *bytes, int len);
-int X509_REQ_add1_attr_by_NID(X509_REQ *req,
- int nid, int type,
- const unsigned char *bytes, int len);
-int X509_REQ_add1_attr_by_txt(X509_REQ *req,
- const char *attrname, int type,
- const unsigned char *bytes, int len);
-
-int X509_CRL_set_version(X509_CRL *x, long version);
-int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name);
-int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm);
-int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm);
-int X509_CRL_sort(X509_CRL *crl);
-
-int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial);
-int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm);
-
-int X509_REQ_check_private_key(X509_REQ *x509,EVP_PKEY *pkey);
-
-int X509_check_private_key(X509 *x509,EVP_PKEY *pkey);
-
-int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b);
-unsigned long X509_issuer_and_serial_hash(X509 *a);
-
-int X509_issuer_name_cmp(const X509 *a, const X509 *b);
-unsigned long X509_issuer_name_hash(X509 *a);
-
-int X509_subject_name_cmp(const X509 *a, const X509 *b);
-unsigned long X509_subject_name_hash(X509 *x);
-
-#ifndef OPENSSL_NO_MD5
-unsigned long X509_issuer_name_hash_old(X509 *a);
-unsigned long X509_subject_name_hash_old(X509 *x);
-#endif
-
-int X509_cmp(const X509 *a, const X509 *b);
-int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b);
-unsigned long X509_NAME_hash(X509_NAME *x);
-unsigned long X509_NAME_hash_old(X509_NAME *x);
-
-int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b);
-int X509_CRL_match(const X509_CRL *a, const X509_CRL *b);
-#ifndef OPENSSL_NO_FP_API
-int X509_print_ex_fp(FILE *bp,X509 *x, unsigned long nmflag, unsigned long cflag);
-int X509_print_fp(FILE *bp,X509 *x);
-int X509_CRL_print_fp(FILE *bp,X509_CRL *x);
-int X509_REQ_print_fp(FILE *bp,X509_REQ *req);
-int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags);
-#endif
-
-#ifndef OPENSSL_NO_BIO
-int X509_NAME_print(BIO *bp, X509_NAME *name, int obase);
-int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags);
-int X509_print_ex(BIO *bp,X509 *x, unsigned long nmflag, unsigned long cflag);
-int X509_print(BIO *bp,X509 *x);
-int X509_ocspid_print(BIO *bp,X509 *x);
-int X509_CERT_AUX_print(BIO *bp,X509_CERT_AUX *x, int indent);
-int X509_CRL_print(BIO *bp,X509_CRL *x);
-int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag);
-int X509_REQ_print(BIO *bp,X509_REQ *req);
-#endif
-
-int X509_NAME_entry_count(X509_NAME *name);
-int X509_NAME_get_text_by_NID(X509_NAME *name, int nid,
- char *buf,int len);
-int X509_NAME_get_text_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj,
- char *buf,int len);
-
-/* NOTE: you should be passsing -1, not 0 as lastpos. The functions that use
- * lastpos, search after that position on. */
-int X509_NAME_get_index_by_NID(X509_NAME *name,int nid,int lastpos);
-int X509_NAME_get_index_by_OBJ(X509_NAME *name,ASN1_OBJECT *obj,
- int lastpos);
-X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc);
-X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc);
-int X509_NAME_add_entry(X509_NAME *name,X509_NAME_ENTRY *ne,
- int loc, int set);
-int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type,
- unsigned char *bytes, int len, int loc, int set);
-int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type,
- unsigned char *bytes, int len, int loc, int set);
-X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne,
- const char *field, int type, const unsigned char *bytes, int len);
-X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid,
- int type,unsigned char *bytes, int len);
-int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type,
- const unsigned char *bytes, int len, int loc, int set);
-X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne,
- ASN1_OBJECT *obj, int type,const unsigned char *bytes,
- int len);
-int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne,
- ASN1_OBJECT *obj);
-int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type,
- const unsigned char *bytes, int len);
-ASN1_OBJECT * X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne);
-ASN1_STRING * X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne);
-
-int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x);
-int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x,
- int nid, int lastpos);
-int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x,
- ASN1_OBJECT *obj,int lastpos);
-int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x,
- int crit, int lastpos);
-X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc);
-X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc);
-STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x,
- X509_EXTENSION *ex, int loc);
-
-int X509_get_ext_count(X509 *x);
-int X509_get_ext_by_NID(X509 *x, int nid, int lastpos);
-int X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos);
-int X509_get_ext_by_critical(X509 *x, int crit, int lastpos);
-X509_EXTENSION *X509_get_ext(X509 *x, int loc);
-X509_EXTENSION *X509_delete_ext(X509 *x, int loc);
-int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
-void * X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx);
-int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit,
- unsigned long flags);
-
-int X509_CRL_get_ext_count(X509_CRL *x);
-int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos);
-int X509_CRL_get_ext_by_OBJ(X509_CRL *x,ASN1_OBJECT *obj,int lastpos);
-int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos);
-X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc);
-X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc);
-int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc);
-void * X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx);
-int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit,
- unsigned long flags);
-
-int X509_REVOKED_get_ext_count(X509_REVOKED *x);
-int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos);
-int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x,ASN1_OBJECT *obj,int lastpos);
-int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos);
-X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc);
-X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc);
-int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc);
-void * X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx);
-int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit,
- unsigned long flags);
-
-X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex,
- int nid, int crit, ASN1_OCTET_STRING *data);
-X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex,
- ASN1_OBJECT *obj,int crit,ASN1_OCTET_STRING *data);
-int X509_EXTENSION_set_object(X509_EXTENSION *ex,ASN1_OBJECT *obj);
-int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit);
-int X509_EXTENSION_set_data(X509_EXTENSION *ex,
- ASN1_OCTET_STRING *data);
-ASN1_OBJECT * X509_EXTENSION_get_object(X509_EXTENSION *ex);
-ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne);
-int X509_EXTENSION_get_critical(X509_EXTENSION *ex);
-
-int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x);
-int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid,
- int lastpos);
-int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, ASN1_OBJECT *obj,
- int lastpos);
-X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc);
-X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc);
-STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
- X509_ATTRIBUTE *attr);
-STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x,
- const ASN1_OBJECT *obj, int type,
- const unsigned char *bytes, int len);
-STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x,
- int nid, int type,
- const unsigned char *bytes, int len);
-STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x,
- const char *attrname, int type,
- const unsigned char *bytes, int len);
-void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x,
- ASN1_OBJECT *obj, int lastpos, int type);
-X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
- int atrtype, const void *data, int len);
-X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
- const ASN1_OBJECT *obj, int atrtype, const void *data, int len);
-X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr,
- const char *atrname, int type, const unsigned char *bytes, int len);
-int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj);
-int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len);
-void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx,
- int atrtype, void *data);
-int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr);
-ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr);
-ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx);
-
-int EVP_PKEY_get_attr_count(const EVP_PKEY *key);
-int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid,
- int lastpos);
-int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj,
- int lastpos);
-X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc);
-X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc);
-int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr);
-int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key,
- const ASN1_OBJECT *obj, int type,
- const unsigned char *bytes, int len);
-int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key,
- int nid, int type,
- const unsigned char *bytes, int len);
-int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key,
- const char *attrname, int type,
- const unsigned char *bytes, int len);
-
-int X509_verify_cert(X509_STORE_CTX *ctx);
-
-/* lookup a cert from a X509 STACK */
-X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk,X509_NAME *name,
- ASN1_INTEGER *serial);
-X509 *X509_find_by_subject(STACK_OF(X509) *sk,X509_NAME *name);
-
-DECLARE_ASN1_FUNCTIONS(PBEPARAM)
-DECLARE_ASN1_FUNCTIONS(PBE2PARAM)
-DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM)
-
-int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter,
- const unsigned char *salt, int saltlen);
-
-X509_ALGOR *PKCS5_pbe_set(int alg, int iter,
- const unsigned char *salt, int saltlen);
-X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
- unsigned char *salt, int saltlen);
-X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
- unsigned char *salt, int saltlen,
- unsigned char *aiv, int prf_nid);
-
-X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen,
- int prf_nid, int keylen);
-
-/* PKCS#8 utilities */
-
-DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
-
-EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8);
-PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey);
-PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken);
-PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken);
-
-int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj,
- int version, int ptype, void *pval,
- unsigned char *penc, int penclen);
-int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg,
- const unsigned char **pk, int *ppklen,
- X509_ALGOR **pa,
- PKCS8_PRIV_KEY_INFO *p8);
-
-int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj,
- int ptype, void *pval,
- unsigned char *penc, int penclen);
-int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
- const unsigned char **pk, int *ppklen,
- X509_ALGOR **pa,
- X509_PUBKEY *pub);
-
-int X509_check_trust(X509 *x, int id, int flags);
-int X509_TRUST_get_count(void);
-X509_TRUST * X509_TRUST_get0(int idx);
-int X509_TRUST_get_by_id(int id);
-int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int),
- char *name, int arg1, void *arg2);
-void X509_TRUST_cleanup(void);
-int X509_TRUST_get_flags(X509_TRUST *xp);
-char *X509_TRUST_get0_name(X509_TRUST *xp);
-int X509_TRUST_get_trust(X509_TRUST *xp);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_X509_strings(void);
-
-/* Error codes for the X509 functions. */
-
-/* Function codes. */
-#define X509_F_ADD_CERT_DIR 100
-#define X509_F_BY_FILE_CTRL 101
-#define X509_F_CHECK_POLICY 145
-#define X509_F_DIR_CTRL 102
-#define X509_F_GET_CERT_BY_SUBJECT 103
-#define X509_F_NETSCAPE_SPKI_B64_DECODE 129
-#define X509_F_NETSCAPE_SPKI_B64_ENCODE 130
-#define X509_F_X509AT_ADD1_ATTR 135
-#define X509_F_X509V3_ADD_EXT 104
-#define X509_F_X509_ATTRIBUTE_CREATE_BY_NID 136
-#define X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ 137
-#define X509_F_X509_ATTRIBUTE_CREATE_BY_TXT 140
-#define X509_F_X509_ATTRIBUTE_GET0_DATA 139
-#define X509_F_X509_ATTRIBUTE_SET1_DATA 138
-#define X509_F_X509_CHECK_PRIVATE_KEY 128
-#define X509_F_X509_CRL_PRINT_FP 147
-#define X509_F_X509_EXTENSION_CREATE_BY_NID 108
-#define X509_F_X509_EXTENSION_CREATE_BY_OBJ 109
-#define X509_F_X509_GET_PUBKEY_PARAMETERS 110
-#define X509_F_X509_LOAD_CERT_CRL_FILE 132
-#define X509_F_X509_LOAD_CERT_FILE 111
-#define X509_F_X509_LOAD_CRL_FILE 112
-#define X509_F_X509_NAME_ADD_ENTRY 113
-#define X509_F_X509_NAME_ENTRY_CREATE_BY_NID 114
-#define X509_F_X509_NAME_ENTRY_CREATE_BY_TXT 131
-#define X509_F_X509_NAME_ENTRY_SET_OBJECT 115
-#define X509_F_X509_NAME_ONELINE 116
-#define X509_F_X509_NAME_PRINT 117
-#define X509_F_X509_PRINT_EX_FP 118
-#define X509_F_X509_PUBKEY_GET 119
-#define X509_F_X509_PUBKEY_SET 120
-#define X509_F_X509_REQ_CHECK_PRIVATE_KEY 144
-#define X509_F_X509_REQ_PRINT_EX 121
-#define X509_F_X509_REQ_PRINT_FP 122
-#define X509_F_X509_REQ_TO_X509 123
-#define X509_F_X509_STORE_ADD_CERT 124
-#define X509_F_X509_STORE_ADD_CRL 125
-#define X509_F_X509_STORE_CTX_GET1_ISSUER 146
-#define X509_F_X509_STORE_CTX_INIT 143
-#define X509_F_X509_STORE_CTX_NEW 142
-#define X509_F_X509_STORE_CTX_PURPOSE_INHERIT 134
-#define X509_F_X509_TO_X509_REQ 126
-#define X509_F_X509_TRUST_ADD 133
-#define X509_F_X509_TRUST_SET 141
-#define X509_F_X509_VERIFY_CERT 127
-
-/* Reason codes. */
-#define X509_R_BAD_X509_FILETYPE 100
-#define X509_R_BASE64_DECODE_ERROR 118
-#define X509_R_CANT_CHECK_DH_KEY 114
-#define X509_R_CERT_ALREADY_IN_HASH_TABLE 101
-#define X509_R_ERR_ASN1_LIB 102
-#define X509_R_INVALID_DIRECTORY 113
-#define X509_R_INVALID_FIELD_NAME 119
-#define X509_R_INVALID_TRUST 123
-#define X509_R_KEY_TYPE_MISMATCH 115
-#define X509_R_KEY_VALUES_MISMATCH 116
-#define X509_R_LOADING_CERT_DIR 103
-#define X509_R_LOADING_DEFAULTS 104
-#define X509_R_METHOD_NOT_SUPPORTED 124
-#define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY 105
-#define X509_R_PUBLIC_KEY_DECODE_ERROR 125
-#define X509_R_PUBLIC_KEY_ENCODE_ERROR 126
-#define X509_R_SHOULD_RETRY 106
-#define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN 107
-#define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY 108
-#define X509_R_UNKNOWN_KEY_TYPE 117
-#define X509_R_UNKNOWN_NID 109
-#define X509_R_UNKNOWN_PURPOSE_ID 121
-#define X509_R_UNKNOWN_TRUST_ID 120
-#define X509_R_UNSUPPORTED_ALGORITHM 111
-#define X509_R_WRONG_LOOKUP_TYPE 112
-#define X509_R_WRONG_TYPE 122
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/openssl/x509_vfy.h b/drivers/builtin_openssl/openssl/x509_vfy.h
deleted file mode 100644
index fe09b30aaa..0000000000
--- a/drivers/builtin_openssl/openssl/x509_vfy.h
+++ /dev/null
@@ -1,567 +0,0 @@
-/* crypto/x509/x509_vfy.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_X509_H
-#include <openssl/x509.h>
-/* openssl/x509.h ends up #include-ing this file at about the only
- * appropriate moment. */
-#endif
-
-#ifndef HEADER_X509_VFY_H
-#define HEADER_X509_VFY_H
-
-#include <openssl/opensslconf.h>
-#ifndef OPENSSL_NO_LHASH
-#include <openssl/lhash.h>
-#endif
-#include <openssl/bio.h>
-#include <openssl/crypto.h>
-#include <openssl/symhacks.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if 0
-/* Outer object */
-typedef struct x509_hash_dir_st
- {
- int num_dirs;
- char **dirs;
- int *dirs_type;
- int num_dirs_alloced;
- } X509_HASH_DIR_CTX;
-#endif
-
-typedef struct x509_file_st
- {
- int num_paths; /* number of paths to files or directories */
- int num_alloced;
- char **paths; /* the list of paths or directories */
- int *path_type;
- } X509_CERT_FILE_CTX;
-
-/*******************************/
-/*
-SSL_CTX -> X509_STORE
- -> X509_LOOKUP
- ->X509_LOOKUP_METHOD
- -> X509_LOOKUP
- ->X509_LOOKUP_METHOD
-
-SSL -> X509_STORE_CTX
- ->X509_STORE
-
-The X509_STORE holds the tables etc for verification stuff.
-A X509_STORE_CTX is used while validating a single certificate.
-The X509_STORE has X509_LOOKUPs for looking up certs.
-The X509_STORE then calls a function to actually verify the
-certificate chain.
-*/
-
-#define X509_LU_RETRY -1
-#define X509_LU_FAIL 0
-#define X509_LU_X509 1
-#define X509_LU_CRL 2
-#define X509_LU_PKEY 3
-
-typedef struct x509_object_st
- {
- /* one of the above types */
- int type;
- union {
- char *ptr;
- X509 *x509;
- X509_CRL *crl;
- EVP_PKEY *pkey;
- } data;
- } X509_OBJECT;
-
-typedef struct x509_lookup_st X509_LOOKUP;
-
-DECLARE_STACK_OF(X509_LOOKUP)
-DECLARE_STACK_OF(X509_OBJECT)
-
-/* This is a static that defines the function interface */
-typedef struct x509_lookup_method_st
- {
- const char *name;
- int (*new_item)(X509_LOOKUP *ctx);
- void (*free)(X509_LOOKUP *ctx);
- int (*init)(X509_LOOKUP *ctx);
- int (*shutdown)(X509_LOOKUP *ctx);
- int (*ctrl)(X509_LOOKUP *ctx,int cmd,const char *argc,long argl,
- char **ret);
- int (*get_by_subject)(X509_LOOKUP *ctx,int type,X509_NAME *name,
- X509_OBJECT *ret);
- int (*get_by_issuer_serial)(X509_LOOKUP *ctx,int type,X509_NAME *name,
- ASN1_INTEGER *serial,X509_OBJECT *ret);
- int (*get_by_fingerprint)(X509_LOOKUP *ctx,int type,
- unsigned char *bytes,int len,
- X509_OBJECT *ret);
- int (*get_by_alias)(X509_LOOKUP *ctx,int type,char *str,int len,
- X509_OBJECT *ret);
- } X509_LOOKUP_METHOD;
-
-/* This structure hold all parameters associated with a verify operation
- * by including an X509_VERIFY_PARAM structure in related structures the
- * parameters used can be customized
- */
-
-typedef struct X509_VERIFY_PARAM_st
- {
- char *name;
- time_t check_time; /* Time to use */
- unsigned long inh_flags; /* Inheritance flags */
- unsigned long flags; /* Various verify flags */
- int purpose; /* purpose to check untrusted certificates */
- int trust; /* trust setting to check */
- int depth; /* Verify depth */
- STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */
- } X509_VERIFY_PARAM;
-
-DECLARE_STACK_OF(X509_VERIFY_PARAM)
-
-/* This is used to hold everything. It is used for all certificate
- * validation. Once we have a certificate chain, the 'verify'
- * function is then called to actually check the cert chain. */
-struct x509_store_st
- {
- /* The following is a cache of trusted certs */
- int cache; /* if true, stash any hits */
- STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */
-
- /* These are external lookup methods */
- STACK_OF(X509_LOOKUP) *get_cert_methods;
-
- X509_VERIFY_PARAM *param;
-
- /* Callbacks for various operations */
- int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */
- int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */
- int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */
- int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */
- int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */
- int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */
- int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
- int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
- STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm);
- STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm);
- int (*cleanup)(X509_STORE_CTX *ctx);
-
- CRYPTO_EX_DATA ex_data;
- int references;
- } /* X509_STORE */;
-
-int X509_STORE_set_depth(X509_STORE *store, int depth);
-
-#define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func))
-#define X509_STORE_set_verify_func(ctx,func) ((ctx)->verify=(func))
-
-/* This is the functions plus an instance of the local variables. */
-struct x509_lookup_st
- {
- int init; /* have we been started */
- int skip; /* don't use us. */
- X509_LOOKUP_METHOD *method; /* the functions */
- char *method_data; /* method data */
-
- X509_STORE *store_ctx; /* who owns us */
- } /* X509_LOOKUP */;
-
-/* This is a used when verifying cert chains. Since the
- * gathering of the cert chain can take some time (and have to be
- * 'retried', this needs to be kept and passed around. */
-struct x509_store_ctx_st /* X509_STORE_CTX */
- {
- X509_STORE *ctx;
- int current_method; /* used when looking up certs */
-
- /* The following are set by the caller */
- X509 *cert; /* The cert to check */
- STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */
- STACK_OF(X509_CRL) *crls; /* set of CRLs passed in */
-
- X509_VERIFY_PARAM *param;
- void *other_ctx; /* Other info for use with get_issuer() */
-
- /* Callbacks for various operations */
- int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */
- int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */
- int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */
- int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */
- int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */
- int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */
- int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
- int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
- int (*check_policy)(X509_STORE_CTX *ctx);
- STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm);
- STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm);
- int (*cleanup)(X509_STORE_CTX *ctx);
-
- /* The following is built up */
- int valid; /* if 0, rebuild chain */
- int last_untrusted; /* index of last untrusted cert */
- STACK_OF(X509) *chain; /* chain of X509s - built up and trusted */
- X509_POLICY_TREE *tree; /* Valid policy tree */
-
- int explicit_policy; /* Require explicit policy value */
-
- /* When something goes wrong, this is why */
- int error_depth;
- int error;
- X509 *current_cert;
- X509 *current_issuer; /* cert currently being tested as valid issuer */
- X509_CRL *current_crl; /* current CRL */
-
- int current_crl_score; /* score of current CRL */
- unsigned int current_reasons; /* Reason mask */
-
- X509_STORE_CTX *parent; /* For CRL path validation: parent context */
-
- CRYPTO_EX_DATA ex_data;
- } /* X509_STORE_CTX */;
-
-void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
-
-#define X509_STORE_CTX_set_app_data(ctx,data) \
- X509_STORE_CTX_set_ex_data(ctx,0,data)
-#define X509_STORE_CTX_get_app_data(ctx) \
- X509_STORE_CTX_get_ex_data(ctx,0)
-
-#define X509_L_FILE_LOAD 1
-#define X509_L_ADD_DIR 2
-
-#define X509_LOOKUP_load_file(x,name,type) \
- X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL)
-
-#define X509_LOOKUP_add_dir(x,name,type) \
- X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL)
-
-#define X509_V_OK 0
-/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */
-
-#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2
-#define X509_V_ERR_UNABLE_TO_GET_CRL 3
-#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4
-#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5
-#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6
-#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7
-#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8
-#define X509_V_ERR_CERT_NOT_YET_VALID 9
-#define X509_V_ERR_CERT_HAS_EXPIRED 10
-#define X509_V_ERR_CRL_NOT_YET_VALID 11
-#define X509_V_ERR_CRL_HAS_EXPIRED 12
-#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13
-#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14
-#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15
-#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16
-#define X509_V_ERR_OUT_OF_MEM 17
-#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18
-#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19
-#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20
-#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21
-#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22
-#define X509_V_ERR_CERT_REVOKED 23
-#define X509_V_ERR_INVALID_CA 24
-#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25
-#define X509_V_ERR_INVALID_PURPOSE 26
-#define X509_V_ERR_CERT_UNTRUSTED 27
-#define X509_V_ERR_CERT_REJECTED 28
-/* These are 'informational' when looking for issuer cert */
-#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29
-#define X509_V_ERR_AKID_SKID_MISMATCH 30
-#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31
-#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
-
-#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33
-#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34
-#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35
-#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36
-#define X509_V_ERR_INVALID_NON_CA 37
-#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38
-#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39
-#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40
-
-#define X509_V_ERR_INVALID_EXTENSION 41
-#define X509_V_ERR_INVALID_POLICY_EXTENSION 42
-#define X509_V_ERR_NO_EXPLICIT_POLICY 43
-#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44
-#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45
-
-#define X509_V_ERR_UNNESTED_RESOURCE 46
-
-#define X509_V_ERR_PERMITTED_VIOLATION 47
-#define X509_V_ERR_EXCLUDED_VIOLATION 48
-#define X509_V_ERR_SUBTREE_MINMAX 49
-#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51
-#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52
-#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53
-#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54
-
-/* The application is not happy */
-#define X509_V_ERR_APPLICATION_VERIFICATION 50
-
-/* Certificate verify flags */
-
-/* Send issuer+subject checks to verify_cb */
-#define X509_V_FLAG_CB_ISSUER_CHECK 0x1
-/* Use check time instead of current time */
-#define X509_V_FLAG_USE_CHECK_TIME 0x2
-/* Lookup CRLs */
-#define X509_V_FLAG_CRL_CHECK 0x4
-/* Lookup CRLs for whole chain */
-#define X509_V_FLAG_CRL_CHECK_ALL 0x8
-/* Ignore unhandled critical extensions */
-#define X509_V_FLAG_IGNORE_CRITICAL 0x10
-/* Disable workarounds for broken certificates */
-#define X509_V_FLAG_X509_STRICT 0x20
-/* Enable proxy certificate validation */
-#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40
-/* Enable policy checking */
-#define X509_V_FLAG_POLICY_CHECK 0x80
-/* Policy variable require-explicit-policy */
-#define X509_V_FLAG_EXPLICIT_POLICY 0x100
-/* Policy variable inhibit-any-policy */
-#define X509_V_FLAG_INHIBIT_ANY 0x200
-/* Policy variable inhibit-policy-mapping */
-#define X509_V_FLAG_INHIBIT_MAP 0x400
-/* Notify callback that policy is OK */
-#define X509_V_FLAG_NOTIFY_POLICY 0x800
-/* Extended CRL features such as indirect CRLs, alternate CRL signing keys */
-#define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000
-/* Delta CRL support */
-#define X509_V_FLAG_USE_DELTAS 0x2000
-/* Check selfsigned CA signature */
-#define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000
-
-
-#define X509_VP_FLAG_DEFAULT 0x1
-#define X509_VP_FLAG_OVERWRITE 0x2
-#define X509_VP_FLAG_RESET_FLAGS 0x4
-#define X509_VP_FLAG_LOCKED 0x8
-#define X509_VP_FLAG_ONCE 0x10
-
-/* Internal use: mask of policy related options */
-#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \
- | X509_V_FLAG_EXPLICIT_POLICY \
- | X509_V_FLAG_INHIBIT_ANY \
- | X509_V_FLAG_INHIBIT_MAP)
-
-int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
- X509_NAME *name);
-X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name);
-X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x);
-void X509_OBJECT_up_ref_count(X509_OBJECT *a);
-void X509_OBJECT_free_contents(X509_OBJECT *a);
-X509_STORE *X509_STORE_new(void );
-void X509_STORE_free(X509_STORE *v);
-
-STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *st, X509_NAME *nm);
-STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *st, X509_NAME *nm);
-int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags);
-int X509_STORE_set_purpose(X509_STORE *ctx, int purpose);
-int X509_STORE_set_trust(X509_STORE *ctx, int trust);
-int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm);
-
-void X509_STORE_set_verify_cb(X509_STORE *ctx,
- int (*verify_cb)(int, X509_STORE_CTX *));
-
-X509_STORE_CTX *X509_STORE_CTX_new(void);
-
-int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
-
-void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
-int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
- X509 *x509, STACK_OF(X509) *chain);
-void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk);
-void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
-
-X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m);
-
-X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void);
-X509_LOOKUP_METHOD *X509_LOOKUP_file(void);
-
-int X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
-int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
-
-int X509_STORE_get_by_subject(X509_STORE_CTX *vs,int type,X509_NAME *name,
- X509_OBJECT *ret);
-
-int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,
- long argl, char **ret);
-
-#ifndef OPENSSL_NO_STDIO
-int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type);
-int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type);
-int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type);
-#endif
-
-
-X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method);
-void X509_LOOKUP_free(X509_LOOKUP *ctx);
-int X509_LOOKUP_init(X509_LOOKUP *ctx);
-int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name,
- X509_OBJECT *ret);
-int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name,
- ASN1_INTEGER *serial, X509_OBJECT *ret);
-int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type,
- unsigned char *bytes, int len, X509_OBJECT *ret);
-int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str,
- int len, X509_OBJECT *ret);
-int X509_LOOKUP_shutdown(X509_LOOKUP *ctx);
-
-#ifndef OPENSSL_NO_STDIO
-int X509_STORE_load_locations (X509_STORE *ctx,
- const char *file, const char *dir);
-int X509_STORE_set_default_paths(X509_STORE *ctx);
-#endif
-
-int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data);
-void * X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx);
-int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
-void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s);
-int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
-X509 * X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
-X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx);
-X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx);
-X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx);
-STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
-STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx);
-void X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x);
-void X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk);
-void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,STACK_OF(X509_CRL) *sk);
-int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
-int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust);
-int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
- int purpose, int trust);
-void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags);
-void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags,
- time_t t);
-void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
- int (*verify_cb)(int, X509_STORE_CTX *));
-
-X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx);
-int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx);
-
-X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx);
-void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param);
-int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name);
-
-/* X509_VERIFY_PARAM functions */
-
-X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
-void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param);
-int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to,
- const X509_VERIFY_PARAM *from);
-int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
- const X509_VERIFY_PARAM *from);
-int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name);
-int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags);
-int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param,
- unsigned long flags);
-unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param);
-int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose);
-int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust);
-void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth);
-void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t);
-int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
- ASN1_OBJECT *policy);
-int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
- STACK_OF(ASN1_OBJECT) *policies);
-int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param);
-
-int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param);
-const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name);
-void X509_VERIFY_PARAM_table_cleanup(void);
-
-int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
- STACK_OF(X509) *certs,
- STACK_OF(ASN1_OBJECT) *policy_oids,
- unsigned int flags);
-
-void X509_policy_tree_free(X509_POLICY_TREE *tree);
-
-int X509_policy_tree_level_count(const X509_POLICY_TREE *tree);
-X509_POLICY_LEVEL *
- X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i);
-
-STACK_OF(X509_POLICY_NODE) *
- X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree);
-
-STACK_OF(X509_POLICY_NODE) *
- X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree);
-
-int X509_policy_level_node_count(X509_POLICY_LEVEL *level);
-
-X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i);
-
-const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node);
-
-STACK_OF(POLICYQUALINFO) *
- X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node);
-const X509_POLICY_NODE *
- X509_policy_node_get0_parent(const X509_POLICY_NODE *node);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/openssl/x509v3.h b/drivers/builtin_openssl/openssl/x509v3.h
deleted file mode 100644
index 40d8e5c770..0000000000
--- a/drivers/builtin_openssl/openssl/x509v3.h
+++ /dev/null
@@ -1,1011 +0,0 @@
-/* x509v3.h */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 1999.
- */
-/* ====================================================================
- * Copyright (c) 1999-2004 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-#ifndef HEADER_X509V3_H
-#define HEADER_X509V3_H
-
-#include <openssl/bio.h>
-#include <openssl/conf.h>
-#include <openssl/x509.h>
-#include <openssl/ossl_typ.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef X509_NAME
-#undef X509_NAME
-#endif
-/* Forward reference */
-struct v3_ext_method;
-struct v3_ext_ctx;
-
-/* Useful typedefs */
-
-typedef void * (*X509V3_EXT_NEW)(void);
-typedef void (*X509V3_EXT_FREE)(void *);
-typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char ** , long);
-typedef int (*X509V3_EXT_I2D)(void *, unsigned char **);
-typedef STACK_OF(CONF_VALUE) *
- (*X509V3_EXT_I2V)(const struct v3_ext_method *method, void *ext,
- STACK_OF(CONF_VALUE) *extlist);
-typedef void * (*X509V3_EXT_V2I)(const struct v3_ext_method *method,
- struct v3_ext_ctx *ctx,
- STACK_OF(CONF_VALUE) *values);
-typedef char * (*X509V3_EXT_I2S)(const struct v3_ext_method *method, void *ext);
-typedef void * (*X509V3_EXT_S2I)(const struct v3_ext_method *method,
- struct v3_ext_ctx *ctx, const char *str);
-typedef int (*X509V3_EXT_I2R)(const struct v3_ext_method *method, void *ext,
- BIO *out, int indent);
-typedef void * (*X509V3_EXT_R2I)(const struct v3_ext_method *method,
- struct v3_ext_ctx *ctx, const char *str);
-
-/* V3 extension structure */
-
-struct v3_ext_method {
-int ext_nid;
-int ext_flags;
-/* If this is set the following four fields are ignored */
-ASN1_ITEM_EXP *it;
-/* Old style ASN1 calls */
-X509V3_EXT_NEW ext_new;
-X509V3_EXT_FREE ext_free;
-X509V3_EXT_D2I d2i;
-X509V3_EXT_I2D i2d;
-
-/* The following pair is used for string extensions */
-X509V3_EXT_I2S i2s;
-X509V3_EXT_S2I s2i;
-
-/* The following pair is used for multi-valued extensions */
-X509V3_EXT_I2V i2v;
-X509V3_EXT_V2I v2i;
-
-/* The following are used for raw extensions */
-X509V3_EXT_I2R i2r;
-X509V3_EXT_R2I r2i;
-
-void *usr_data; /* Any extension specific data */
-};
-
-typedef struct X509V3_CONF_METHOD_st {
-char * (*get_string)(void *db, char *section, char *value);
-STACK_OF(CONF_VALUE) * (*get_section)(void *db, char *section);
-void (*free_string)(void *db, char * string);
-void (*free_section)(void *db, STACK_OF(CONF_VALUE) *section);
-} X509V3_CONF_METHOD;
-
-/* Context specific info */
-struct v3_ext_ctx {
-#define CTX_TEST 0x1
-int flags;
-X509 *issuer_cert;
-X509 *subject_cert;
-X509_REQ *subject_req;
-X509_CRL *crl;
-X509V3_CONF_METHOD *db_meth;
-void *db;
-/* Maybe more here */
-};
-
-typedef struct v3_ext_method X509V3_EXT_METHOD;
-
-DECLARE_STACK_OF(X509V3_EXT_METHOD)
-
-/* ext_flags values */
-#define X509V3_EXT_DYNAMIC 0x1
-#define X509V3_EXT_CTX_DEP 0x2
-#define X509V3_EXT_MULTILINE 0x4
-
-typedef BIT_STRING_BITNAME ENUMERATED_NAMES;
-
-typedef struct BASIC_CONSTRAINTS_st {
-int ca;
-ASN1_INTEGER *pathlen;
-} BASIC_CONSTRAINTS;
-
-
-typedef struct PKEY_USAGE_PERIOD_st {
-ASN1_GENERALIZEDTIME *notBefore;
-ASN1_GENERALIZEDTIME *notAfter;
-} PKEY_USAGE_PERIOD;
-
-typedef struct otherName_st {
-ASN1_OBJECT *type_id;
-ASN1_TYPE *value;
-} OTHERNAME;
-
-typedef struct EDIPartyName_st {
- ASN1_STRING *nameAssigner;
- ASN1_STRING *partyName;
-} EDIPARTYNAME;
-
-typedef struct GENERAL_NAME_st {
-
-#define GEN_OTHERNAME 0
-#define GEN_EMAIL 1
-#define GEN_DNS 2
-#define GEN_X400 3
-#define GEN_DIRNAME 4
-#define GEN_EDIPARTY 5
-#define GEN_URI 6
-#define GEN_IPADD 7
-#define GEN_RID 8
-
-int type;
-union {
- char *ptr;
- OTHERNAME *otherName; /* otherName */
- ASN1_IA5STRING *rfc822Name;
- ASN1_IA5STRING *dNSName;
- ASN1_TYPE *x400Address;
- X509_NAME *directoryName;
- EDIPARTYNAME *ediPartyName;
- ASN1_IA5STRING *uniformResourceIdentifier;
- ASN1_OCTET_STRING *iPAddress;
- ASN1_OBJECT *registeredID;
-
- /* Old names */
- ASN1_OCTET_STRING *ip; /* iPAddress */
- X509_NAME *dirn; /* dirn */
- ASN1_IA5STRING *ia5;/* rfc822Name, dNSName, uniformResourceIdentifier */
- ASN1_OBJECT *rid; /* registeredID */
- ASN1_TYPE *other; /* x400Address */
-} d;
-} GENERAL_NAME;
-
-typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES;
-
-typedef struct ACCESS_DESCRIPTION_st {
- ASN1_OBJECT *method;
- GENERAL_NAME *location;
-} ACCESS_DESCRIPTION;
-
-typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS;
-
-typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE;
-
-DECLARE_STACK_OF(GENERAL_NAME)
-DECLARE_ASN1_SET_OF(GENERAL_NAME)
-
-DECLARE_STACK_OF(ACCESS_DESCRIPTION)
-DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION)
-
-typedef struct DIST_POINT_NAME_st {
-int type;
-union {
- GENERAL_NAMES *fullname;
- STACK_OF(X509_NAME_ENTRY) *relativename;
-} name;
-/* If relativename then this contains the full distribution point name */
-X509_NAME *dpname;
-} DIST_POINT_NAME;
-/* All existing reasons */
-#define CRLDP_ALL_REASONS 0x807f
-
-#define CRL_REASON_NONE -1
-#define CRL_REASON_UNSPECIFIED 0
-#define CRL_REASON_KEY_COMPROMISE 1
-#define CRL_REASON_CA_COMPROMISE 2
-#define CRL_REASON_AFFILIATION_CHANGED 3
-#define CRL_REASON_SUPERSEDED 4
-#define CRL_REASON_CESSATION_OF_OPERATION 5
-#define CRL_REASON_CERTIFICATE_HOLD 6
-#define CRL_REASON_REMOVE_FROM_CRL 8
-#define CRL_REASON_PRIVILEGE_WITHDRAWN 9
-#define CRL_REASON_AA_COMPROMISE 10
-
-struct DIST_POINT_st {
-DIST_POINT_NAME *distpoint;
-ASN1_BIT_STRING *reasons;
-GENERAL_NAMES *CRLissuer;
-int dp_reasons;
-};
-
-typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS;
-
-DECLARE_STACK_OF(DIST_POINT)
-DECLARE_ASN1_SET_OF(DIST_POINT)
-
-struct AUTHORITY_KEYID_st {
-ASN1_OCTET_STRING *keyid;
-GENERAL_NAMES *issuer;
-ASN1_INTEGER *serial;
-};
-
-/* Strong extranet structures */
-
-typedef struct SXNET_ID_st {
- ASN1_INTEGER *zone;
- ASN1_OCTET_STRING *user;
-} SXNETID;
-
-DECLARE_STACK_OF(SXNETID)
-DECLARE_ASN1_SET_OF(SXNETID)
-
-typedef struct SXNET_st {
- ASN1_INTEGER *version;
- STACK_OF(SXNETID) *ids;
-} SXNET;
-
-typedef struct NOTICEREF_st {
- ASN1_STRING *organization;
- STACK_OF(ASN1_INTEGER) *noticenos;
-} NOTICEREF;
-
-typedef struct USERNOTICE_st {
- NOTICEREF *noticeref;
- ASN1_STRING *exptext;
-} USERNOTICE;
-
-typedef struct POLICYQUALINFO_st {
- ASN1_OBJECT *pqualid;
- union {
- ASN1_IA5STRING *cpsuri;
- USERNOTICE *usernotice;
- ASN1_TYPE *other;
- } d;
-} POLICYQUALINFO;
-
-DECLARE_STACK_OF(POLICYQUALINFO)
-DECLARE_ASN1_SET_OF(POLICYQUALINFO)
-
-typedef struct POLICYINFO_st {
- ASN1_OBJECT *policyid;
- STACK_OF(POLICYQUALINFO) *qualifiers;
-} POLICYINFO;
-
-typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES;
-
-DECLARE_STACK_OF(POLICYINFO)
-DECLARE_ASN1_SET_OF(POLICYINFO)
-
-typedef struct POLICY_MAPPING_st {
- ASN1_OBJECT *issuerDomainPolicy;
- ASN1_OBJECT *subjectDomainPolicy;
-} POLICY_MAPPING;
-
-DECLARE_STACK_OF(POLICY_MAPPING)
-
-typedef STACK_OF(POLICY_MAPPING) POLICY_MAPPINGS;
-
-typedef struct GENERAL_SUBTREE_st {
- GENERAL_NAME *base;
- ASN1_INTEGER *minimum;
- ASN1_INTEGER *maximum;
-} GENERAL_SUBTREE;
-
-DECLARE_STACK_OF(GENERAL_SUBTREE)
-
-struct NAME_CONSTRAINTS_st {
- STACK_OF(GENERAL_SUBTREE) *permittedSubtrees;
- STACK_OF(GENERAL_SUBTREE) *excludedSubtrees;
-};
-
-typedef struct POLICY_CONSTRAINTS_st {
- ASN1_INTEGER *requireExplicitPolicy;
- ASN1_INTEGER *inhibitPolicyMapping;
-} POLICY_CONSTRAINTS;
-
-/* Proxy certificate structures, see RFC 3820 */
-typedef struct PROXY_POLICY_st
- {
- ASN1_OBJECT *policyLanguage;
- ASN1_OCTET_STRING *policy;
- } PROXY_POLICY;
-
-typedef struct PROXY_CERT_INFO_EXTENSION_st
- {
- ASN1_INTEGER *pcPathLengthConstraint;
- PROXY_POLICY *proxyPolicy;
- } PROXY_CERT_INFO_EXTENSION;
-
-DECLARE_ASN1_FUNCTIONS(PROXY_POLICY)
-DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION)
-
-struct ISSUING_DIST_POINT_st
- {
- DIST_POINT_NAME *distpoint;
- int onlyuser;
- int onlyCA;
- ASN1_BIT_STRING *onlysomereasons;
- int indirectCRL;
- int onlyattr;
- };
-
-/* Values in idp_flags field */
-/* IDP present */
-#define IDP_PRESENT 0x1
-/* IDP values inconsistent */
-#define IDP_INVALID 0x2
-/* onlyuser true */
-#define IDP_ONLYUSER 0x4
-/* onlyCA true */
-#define IDP_ONLYCA 0x8
-/* onlyattr true */
-#define IDP_ONLYATTR 0x10
-/* indirectCRL true */
-#define IDP_INDIRECT 0x20
-/* onlysomereasons present */
-#define IDP_REASONS 0x40
-
-#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \
-",name:", val->name, ",value:", val->value);
-
-#define X509V3_set_ctx_test(ctx) \
- X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST)
-#define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL;
-
-#define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \
- 0,0,0,0, \
- 0,0, \
- (X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \
- (X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \
- NULL, NULL, \
- table}
-
-#define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \
- 0,0,0,0, \
- (X509V3_EXT_I2S)i2s_ASN1_IA5STRING, \
- (X509V3_EXT_S2I)s2i_ASN1_IA5STRING, \
- 0,0,0,0, \
- NULL}
-
-#define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-
-
-/* X509_PURPOSE stuff */
-
-#define EXFLAG_BCONS 0x1
-#define EXFLAG_KUSAGE 0x2
-#define EXFLAG_XKUSAGE 0x4
-#define EXFLAG_NSCERT 0x8
-
-#define EXFLAG_CA 0x10
-/* Really self issued not necessarily self signed */
-#define EXFLAG_SI 0x20
-#define EXFLAG_SS 0x20
-#define EXFLAG_V1 0x40
-#define EXFLAG_INVALID 0x80
-#define EXFLAG_SET 0x100
-#define EXFLAG_CRITICAL 0x200
-#define EXFLAG_PROXY 0x400
-
-#define EXFLAG_INVALID_POLICY 0x800
-#define EXFLAG_FRESHEST 0x1000
-
-#define KU_DIGITAL_SIGNATURE 0x0080
-#define KU_NON_REPUDIATION 0x0040
-#define KU_KEY_ENCIPHERMENT 0x0020
-#define KU_DATA_ENCIPHERMENT 0x0010
-#define KU_KEY_AGREEMENT 0x0008
-#define KU_KEY_CERT_SIGN 0x0004
-#define KU_CRL_SIGN 0x0002
-#define KU_ENCIPHER_ONLY 0x0001
-#define KU_DECIPHER_ONLY 0x8000
-
-#define NS_SSL_CLIENT 0x80
-#define NS_SSL_SERVER 0x40
-#define NS_SMIME 0x20
-#define NS_OBJSIGN 0x10
-#define NS_SSL_CA 0x04
-#define NS_SMIME_CA 0x02
-#define NS_OBJSIGN_CA 0x01
-#define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA)
-
-#define XKU_SSL_SERVER 0x1
-#define XKU_SSL_CLIENT 0x2
-#define XKU_SMIME 0x4
-#define XKU_CODE_SIGN 0x8
-#define XKU_SGC 0x10
-#define XKU_OCSP_SIGN 0x20
-#define XKU_TIMESTAMP 0x40
-#define XKU_DVCS 0x80
-
-#define X509_PURPOSE_DYNAMIC 0x1
-#define X509_PURPOSE_DYNAMIC_NAME 0x2
-
-typedef struct x509_purpose_st {
- int purpose;
- int trust; /* Default trust ID */
- int flags;
- int (*check_purpose)(const struct x509_purpose_st *,
- const X509 *, int);
- char *name;
- char *sname;
- void *usr_data;
-} X509_PURPOSE;
-
-#define X509_PURPOSE_SSL_CLIENT 1
-#define X509_PURPOSE_SSL_SERVER 2
-#define X509_PURPOSE_NS_SSL_SERVER 3
-#define X509_PURPOSE_SMIME_SIGN 4
-#define X509_PURPOSE_SMIME_ENCRYPT 5
-#define X509_PURPOSE_CRL_SIGN 6
-#define X509_PURPOSE_ANY 7
-#define X509_PURPOSE_OCSP_HELPER 8
-#define X509_PURPOSE_TIMESTAMP_SIGN 9
-
-#define X509_PURPOSE_MIN 1
-#define X509_PURPOSE_MAX 9
-
-/* Flags for X509V3_EXT_print() */
-
-#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16)
-/* Return error for unknown extensions */
-#define X509V3_EXT_DEFAULT 0
-/* Print error for unknown extensions */
-#define X509V3_EXT_ERROR_UNKNOWN (1L << 16)
-/* ASN1 parse unknown extensions */
-#define X509V3_EXT_PARSE_UNKNOWN (2L << 16)
-/* BIO_dump unknown extensions */
-#define X509V3_EXT_DUMP_UNKNOWN (3L << 16)
-
-/* Flags for X509V3_add1_i2d */
-
-#define X509V3_ADD_OP_MASK 0xfL
-#define X509V3_ADD_DEFAULT 0L
-#define X509V3_ADD_APPEND 1L
-#define X509V3_ADD_REPLACE 2L
-#define X509V3_ADD_REPLACE_EXISTING 3L
-#define X509V3_ADD_KEEP_EXISTING 4L
-#define X509V3_ADD_DELETE 5L
-#define X509V3_ADD_SILENT 0x10
-
-DECLARE_STACK_OF(X509_PURPOSE)
-
-DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS)
-
-DECLARE_ASN1_FUNCTIONS(SXNET)
-DECLARE_ASN1_FUNCTIONS(SXNETID)
-
-int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, int userlen);
-int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, int userlen);
-int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *izone, char *user, int userlen);
-
-ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone);
-ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone);
-ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone);
-
-DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID)
-
-DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD)
-
-DECLARE_ASN1_FUNCTIONS(GENERAL_NAME)
-GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a);
-int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b);
-
-
-
-ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
- X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
-STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
- ASN1_BIT_STRING *bits,
- STACK_OF(CONF_VALUE) *extlist);
-
-STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret);
-int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen);
-
-DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES)
-
-STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
- GENERAL_NAMES *gen, STACK_OF(CONF_VALUE) *extlist);
-GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method,
- X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
-
-DECLARE_ASN1_FUNCTIONS(OTHERNAME)
-DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME)
-int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b);
-void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value);
-void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype);
-int GENERAL_NAME_set0_othername(GENERAL_NAME *gen,
- ASN1_OBJECT *oid, ASN1_TYPE *value);
-int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen,
- ASN1_OBJECT **poid, ASN1_TYPE **pvalue);
-
-char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5);
-ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str);
-
-DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE)
-int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a);
-
-DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
-DECLARE_ASN1_FUNCTIONS(POLICYINFO)
-DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO)
-DECLARE_ASN1_FUNCTIONS(USERNOTICE)
-DECLARE_ASN1_FUNCTIONS(NOTICEREF)
-
-DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS)
-DECLARE_ASN1_FUNCTIONS(DIST_POINT)
-DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME)
-DECLARE_ASN1_FUNCTIONS(ISSUING_DIST_POINT)
-
-int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname);
-
-int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc);
-
-DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION)
-DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS)
-
-DECLARE_ASN1_ITEM(POLICY_MAPPING)
-DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING)
-DECLARE_ASN1_ITEM(POLICY_MAPPINGS)
-
-DECLARE_ASN1_ITEM(GENERAL_SUBTREE)
-DECLARE_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE)
-
-DECLARE_ASN1_ITEM(NAME_CONSTRAINTS)
-DECLARE_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS)
-
-DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS)
-DECLARE_ASN1_ITEM(POLICY_CONSTRAINTS)
-
-GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out,
- const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
- int gen_type, char *value, int is_nc);
-
-#ifdef HEADER_CONF_H
-GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
- CONF_VALUE *cnf);
-GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out,
- const X509V3_EXT_METHOD *method,
- X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc);
-void X509V3_conf_free(CONF_VALUE *val);
-
-X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value);
-X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value);
-int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk);
-int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509 *cert);
-int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_REQ *req);
-int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl);
-
-X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
- int ext_nid, char *value);
-X509_EXTENSION *X509V3_EXT_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
- char *name, char *value);
-int X509V3_EXT_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
- char *section, X509 *cert);
-int X509V3_EXT_REQ_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
- char *section, X509_REQ *req);
-int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
- char *section, X509_CRL *crl);
-
-int X509V3_add_value_bool_nf(char *name, int asn1_bool,
- STACK_OF(CONF_VALUE) **extlist);
-int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool);
-int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint);
-void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf);
-void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash);
-#endif
-
-char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section);
-STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section);
-void X509V3_string_free(X509V3_CTX *ctx, char *str);
-void X509V3_section_free( X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section);
-void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
- X509_REQ *req, X509_CRL *crl, int flags);
-
-int X509V3_add_value(const char *name, const char *value,
- STACK_OF(CONF_VALUE) **extlist);
-int X509V3_add_value_uchar(const char *name, const unsigned char *value,
- STACK_OF(CONF_VALUE) **extlist);
-int X509V3_add_value_bool(const char *name, int asn1_bool,
- STACK_OF(CONF_VALUE) **extlist);
-int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
- STACK_OF(CONF_VALUE) **extlist);
-char * i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint);
-ASN1_INTEGER * s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, char *value);
-char * i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint);
-char * i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint);
-int X509V3_EXT_add(X509V3_EXT_METHOD *ext);
-int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist);
-int X509V3_EXT_add_alias(int nid_to, int nid_from);
-void X509V3_EXT_cleanup(void);
-
-const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext);
-const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid);
-int X509V3_add_standard_extensions(void);
-STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line);
-void *X509V3_EXT_d2i(X509_EXTENSION *ext);
-void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx);
-
-
-X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc);
-int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, int crit, unsigned long flags);
-
-char *hex_to_string(const unsigned char *buffer, long len);
-unsigned char *string_to_hex(const char *str, long *len);
-int name_cmp(const char *name, const char *cmp);
-
-void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent,
- int ml);
-int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent);
-int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);
-
-int X509V3_extensions_print(BIO *out, char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent);
-
-int X509_check_ca(X509 *x);
-int X509_check_purpose(X509 *x, int id, int ca);
-int X509_supported_extension(X509_EXTENSION *ex);
-int X509_PURPOSE_set(int *p, int purpose);
-int X509_check_issued(X509 *issuer, X509 *subject);
-int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid);
-int X509_PURPOSE_get_count(void);
-X509_PURPOSE * X509_PURPOSE_get0(int idx);
-int X509_PURPOSE_get_by_sname(char *sname);
-int X509_PURPOSE_get_by_id(int id);
-int X509_PURPOSE_add(int id, int trust, int flags,
- int (*ck)(const X509_PURPOSE *, const X509 *, int),
- char *name, char *sname, void *arg);
-char *X509_PURPOSE_get0_name(X509_PURPOSE *xp);
-char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp);
-int X509_PURPOSE_get_trust(X509_PURPOSE *xp);
-void X509_PURPOSE_cleanup(void);
-int X509_PURPOSE_get_id(X509_PURPOSE *);
-
-STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x);
-STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x);
-void X509_email_free(STACK_OF(OPENSSL_STRING) *sk);
-STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x);
-
-ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
-ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
-int a2i_ipadd(unsigned char *ipout, const char *ipasc);
-int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk,
- unsigned long chtype);
-
-void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent);
-DECLARE_STACK_OF(X509_POLICY_NODE)
-
-#ifndef OPENSSL_NO_RFC3779
-
-typedef struct ASRange_st {
- ASN1_INTEGER *min, *max;
-} ASRange;
-
-#define ASIdOrRange_id 0
-#define ASIdOrRange_range 1
-
-typedef struct ASIdOrRange_st {
- int type;
- union {
- ASN1_INTEGER *id;
- ASRange *range;
- } u;
-} ASIdOrRange;
-
-typedef STACK_OF(ASIdOrRange) ASIdOrRanges;
-DECLARE_STACK_OF(ASIdOrRange)
-
-#define ASIdentifierChoice_inherit 0
-#define ASIdentifierChoice_asIdsOrRanges 1
-
-typedef struct ASIdentifierChoice_st {
- int type;
- union {
- ASN1_NULL *inherit;
- ASIdOrRanges *asIdsOrRanges;
- } u;
-} ASIdentifierChoice;
-
-typedef struct ASIdentifiers_st {
- ASIdentifierChoice *asnum, *rdi;
-} ASIdentifiers;
-
-DECLARE_ASN1_FUNCTIONS(ASRange)
-DECLARE_ASN1_FUNCTIONS(ASIdOrRange)
-DECLARE_ASN1_FUNCTIONS(ASIdentifierChoice)
-DECLARE_ASN1_FUNCTIONS(ASIdentifiers)
-
-
-typedef struct IPAddressRange_st {
- ASN1_BIT_STRING *min, *max;
-} IPAddressRange;
-
-#define IPAddressOrRange_addressPrefix 0
-#define IPAddressOrRange_addressRange 1
-
-typedef struct IPAddressOrRange_st {
- int type;
- union {
- ASN1_BIT_STRING *addressPrefix;
- IPAddressRange *addressRange;
- } u;
-} IPAddressOrRange;
-
-typedef STACK_OF(IPAddressOrRange) IPAddressOrRanges;
-DECLARE_STACK_OF(IPAddressOrRange)
-
-#define IPAddressChoice_inherit 0
-#define IPAddressChoice_addressesOrRanges 1
-
-typedef struct IPAddressChoice_st {
- int type;
- union {
- ASN1_NULL *inherit;
- IPAddressOrRanges *addressesOrRanges;
- } u;
-} IPAddressChoice;
-
-typedef struct IPAddressFamily_st {
- ASN1_OCTET_STRING *addressFamily;
- IPAddressChoice *ipAddressChoice;
-} IPAddressFamily;
-
-typedef STACK_OF(IPAddressFamily) IPAddrBlocks;
-DECLARE_STACK_OF(IPAddressFamily)
-
-DECLARE_ASN1_FUNCTIONS(IPAddressRange)
-DECLARE_ASN1_FUNCTIONS(IPAddressOrRange)
-DECLARE_ASN1_FUNCTIONS(IPAddressChoice)
-DECLARE_ASN1_FUNCTIONS(IPAddressFamily)
-
-/*
- * API tag for elements of the ASIdentifer SEQUENCE.
- */
-#define V3_ASID_ASNUM 0
-#define V3_ASID_RDI 1
-
-/*
- * AFI values, assigned by IANA. It'd be nice to make the AFI
- * handling code totally generic, but there are too many little things
- * that would need to be defined for other address families for it to
- * be worth the trouble.
- */
-#define IANA_AFI_IPV4 1
-#define IANA_AFI_IPV6 2
-
-/*
- * Utilities to construct and extract values from RFC3779 extensions,
- * since some of the encodings (particularly for IP address prefixes
- * and ranges) are a bit tedious to work with directly.
- */
-int v3_asid_add_inherit(ASIdentifiers *asid, int which);
-int v3_asid_add_id_or_range(ASIdentifiers *asid, int which,
- ASN1_INTEGER *min, ASN1_INTEGER *max);
-int v3_addr_add_inherit(IPAddrBlocks *addr,
- const unsigned afi, const unsigned *safi);
-int v3_addr_add_prefix(IPAddrBlocks *addr,
- const unsigned afi, const unsigned *safi,
- unsigned char *a, const int prefixlen);
-int v3_addr_add_range(IPAddrBlocks *addr,
- const unsigned afi, const unsigned *safi,
- unsigned char *min, unsigned char *max);
-unsigned v3_addr_get_afi(const IPAddressFamily *f);
-int v3_addr_get_range(IPAddressOrRange *aor, const unsigned afi,
- unsigned char *min, unsigned char *max,
- const int length);
-
-/*
- * Canonical forms.
- */
-int v3_asid_is_canonical(ASIdentifiers *asid);
-int v3_addr_is_canonical(IPAddrBlocks *addr);
-int v3_asid_canonize(ASIdentifiers *asid);
-int v3_addr_canonize(IPAddrBlocks *addr);
-
-/*
- * Tests for inheritance and containment.
- */
-int v3_asid_inherits(ASIdentifiers *asid);
-int v3_addr_inherits(IPAddrBlocks *addr);
-int v3_asid_subset(ASIdentifiers *a, ASIdentifiers *b);
-int v3_addr_subset(IPAddrBlocks *a, IPAddrBlocks *b);
-
-/*
- * Check whether RFC 3779 extensions nest properly in chains.
- */
-int v3_asid_validate_path(X509_STORE_CTX *);
-int v3_addr_validate_path(X509_STORE_CTX *);
-int v3_asid_validate_resource_set(STACK_OF(X509) *chain,
- ASIdentifiers *ext,
- int allow_inheritance);
-int v3_addr_validate_resource_set(STACK_OF(X509) *chain,
- IPAddrBlocks *ext,
- int allow_inheritance);
-
-#endif /* OPENSSL_NO_RFC3779 */
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_X509V3_strings(void);
-
-/* Error codes for the X509V3 functions. */
-
-/* Function codes. */
-#define X509V3_F_A2I_GENERAL_NAME 164
-#define X509V3_F_ASIDENTIFIERCHOICE_CANONIZE 161
-#define X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL 162
-#define X509V3_F_COPY_EMAIL 122
-#define X509V3_F_COPY_ISSUER 123
-#define X509V3_F_DO_DIRNAME 144
-#define X509V3_F_DO_EXT_CONF 124
-#define X509V3_F_DO_EXT_I2D 135
-#define X509V3_F_DO_EXT_NCONF 151
-#define X509V3_F_DO_I2V_NAME_CONSTRAINTS 148
-#define X509V3_F_GNAMES_FROM_SECTNAME 156
-#define X509V3_F_HEX_TO_STRING 111
-#define X509V3_F_I2S_ASN1_ENUMERATED 121
-#define X509V3_F_I2S_ASN1_IA5STRING 149
-#define X509V3_F_I2S_ASN1_INTEGER 120
-#define X509V3_F_I2V_AUTHORITY_INFO_ACCESS 138
-#define X509V3_F_NOTICE_SECTION 132
-#define X509V3_F_NREF_NOS 133
-#define X509V3_F_POLICY_SECTION 131
-#define X509V3_F_PROCESS_PCI_VALUE 150
-#define X509V3_F_R2I_CERTPOL 130
-#define X509V3_F_R2I_PCI 155
-#define X509V3_F_S2I_ASN1_IA5STRING 100
-#define X509V3_F_S2I_ASN1_INTEGER 108
-#define X509V3_F_S2I_ASN1_OCTET_STRING 112
-#define X509V3_F_S2I_ASN1_SKEY_ID 114
-#define X509V3_F_S2I_SKEY_ID 115
-#define X509V3_F_SET_DIST_POINT_NAME 158
-#define X509V3_F_STRING_TO_HEX 113
-#define X509V3_F_SXNET_ADD_ID_ASC 125
-#define X509V3_F_SXNET_ADD_ID_INTEGER 126
-#define X509V3_F_SXNET_ADD_ID_ULONG 127
-#define X509V3_F_SXNET_GET_ID_ASC 128
-#define X509V3_F_SXNET_GET_ID_ULONG 129
-#define X509V3_F_V2I_ASIDENTIFIERS 163
-#define X509V3_F_V2I_ASN1_BIT_STRING 101
-#define X509V3_F_V2I_AUTHORITY_INFO_ACCESS 139
-#define X509V3_F_V2I_AUTHORITY_KEYID 119
-#define X509V3_F_V2I_BASIC_CONSTRAINTS 102
-#define X509V3_F_V2I_CRLD 134
-#define X509V3_F_V2I_EXTENDED_KEY_USAGE 103
-#define X509V3_F_V2I_GENERAL_NAMES 118
-#define X509V3_F_V2I_GENERAL_NAME_EX 117
-#define X509V3_F_V2I_IDP 157
-#define X509V3_F_V2I_IPADDRBLOCKS 159
-#define X509V3_F_V2I_ISSUER_ALT 153
-#define X509V3_F_V2I_NAME_CONSTRAINTS 147
-#define X509V3_F_V2I_POLICY_CONSTRAINTS 146
-#define X509V3_F_V2I_POLICY_MAPPINGS 145
-#define X509V3_F_V2I_SUBJECT_ALT 154
-#define X509V3_F_V3_ADDR_VALIDATE_PATH_INTERNAL 160
-#define X509V3_F_V3_GENERIC_EXTENSION 116
-#define X509V3_F_X509V3_ADD1_I2D 140
-#define X509V3_F_X509V3_ADD_VALUE 105
-#define X509V3_F_X509V3_EXT_ADD 104
-#define X509V3_F_X509V3_EXT_ADD_ALIAS 106
-#define X509V3_F_X509V3_EXT_CONF 107
-#define X509V3_F_X509V3_EXT_I2D 136
-#define X509V3_F_X509V3_EXT_NCONF 152
-#define X509V3_F_X509V3_GET_SECTION 142
-#define X509V3_F_X509V3_GET_STRING 143
-#define X509V3_F_X509V3_GET_VALUE_BOOL 110
-#define X509V3_F_X509V3_PARSE_LIST 109
-#define X509V3_F_X509_PURPOSE_ADD 137
-#define X509V3_F_X509_PURPOSE_SET 141
-
-/* Reason codes. */
-#define X509V3_R_BAD_IP_ADDRESS 118
-#define X509V3_R_BAD_OBJECT 119
-#define X509V3_R_BN_DEC2BN_ERROR 100
-#define X509V3_R_BN_TO_ASN1_INTEGER_ERROR 101
-#define X509V3_R_DIRNAME_ERROR 149
-#define X509V3_R_DISTPOINT_ALREADY_SET 160
-#define X509V3_R_DUPLICATE_ZONE_ID 133
-#define X509V3_R_ERROR_CONVERTING_ZONE 131
-#define X509V3_R_ERROR_CREATING_EXTENSION 144
-#define X509V3_R_ERROR_IN_EXTENSION 128
-#define X509V3_R_EXPECTED_A_SECTION_NAME 137
-#define X509V3_R_EXTENSION_EXISTS 145
-#define X509V3_R_EXTENSION_NAME_ERROR 115
-#define X509V3_R_EXTENSION_NOT_FOUND 102
-#define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED 103
-#define X509V3_R_EXTENSION_VALUE_ERROR 116
-#define X509V3_R_ILLEGAL_EMPTY_EXTENSION 151
-#define X509V3_R_ILLEGAL_HEX_DIGIT 113
-#define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG 152
-#define X509V3_R_INVALID_MULTIPLE_RDNS 161
-#define X509V3_R_INVALID_ASNUMBER 162
-#define X509V3_R_INVALID_ASRANGE 163
-#define X509V3_R_INVALID_BOOLEAN_STRING 104
-#define X509V3_R_INVALID_EXTENSION_STRING 105
-#define X509V3_R_INVALID_INHERITANCE 165
-#define X509V3_R_INVALID_IPADDRESS 166
-#define X509V3_R_INVALID_NAME 106
-#define X509V3_R_INVALID_NULL_ARGUMENT 107
-#define X509V3_R_INVALID_NULL_NAME 108
-#define X509V3_R_INVALID_NULL_VALUE 109
-#define X509V3_R_INVALID_NUMBER 140
-#define X509V3_R_INVALID_NUMBERS 141
-#define X509V3_R_INVALID_OBJECT_IDENTIFIER 110
-#define X509V3_R_INVALID_OPTION 138
-#define X509V3_R_INVALID_POLICY_IDENTIFIER 134
-#define X509V3_R_INVALID_PROXY_POLICY_SETTING 153
-#define X509V3_R_INVALID_PURPOSE 146
-#define X509V3_R_INVALID_SAFI 164
-#define X509V3_R_INVALID_SECTION 135
-#define X509V3_R_INVALID_SYNTAX 143
-#define X509V3_R_ISSUER_DECODE_ERROR 126
-#define X509V3_R_MISSING_VALUE 124
-#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS 142
-#define X509V3_R_NO_CONFIG_DATABASE 136
-#define X509V3_R_NO_ISSUER_CERTIFICATE 121
-#define X509V3_R_NO_ISSUER_DETAILS 127
-#define X509V3_R_NO_POLICY_IDENTIFIER 139
-#define X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED 154
-#define X509V3_R_NO_PUBLIC_KEY 114
-#define X509V3_R_NO_SUBJECT_DETAILS 125
-#define X509V3_R_ODD_NUMBER_OF_DIGITS 112
-#define X509V3_R_OPERATION_NOT_DEFINED 148
-#define X509V3_R_OTHERNAME_ERROR 147
-#define X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED 155
-#define X509V3_R_POLICY_PATH_LENGTH 156
-#define X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED 157
-#define X509V3_R_POLICY_SYNTAX_NOT_CURRENTLY_SUPPORTED 158
-#define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 159
-#define X509V3_R_SECTION_NOT_FOUND 150
-#define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 122
-#define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 123
-#define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT 111
-#define X509V3_R_UNKNOWN_EXTENSION 129
-#define X509V3_R_UNKNOWN_EXTENSION_NAME 130
-#define X509V3_R_UNKNOWN_OPTION 120
-#define X509V3_R_UNSUPPORTED_OPTION 117
-#define X509V3_R_UNSUPPORTED_TYPE 167
-#define X509V3_R_USER_TOO_LONG 132
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/ssl/Makefile b/drivers/builtin_openssl/ssl/Makefile
deleted file mode 100644
index debe07405b..0000000000
--- a/drivers/builtin_openssl/ssl/Makefile
+++ /dev/null
@@ -1,1061 +0,0 @@
-#
-# OpenSSL/ssl/Makefile
-#
-
-DIR= ssl
-TOP= ..
-CC= cc
-INCLUDES= -I../crypto -I$(TOP) -I../include $(KRB5_INCLUDES)
-CFLAG=-g
-MAKEFILE= Makefile
-AR= ar r
-# KRB5 stuff
-KRB5_INCLUDES=
-
-CFLAGS= $(INCLUDES) $(CFLAG)
-
-GENERAL=Makefile README ssl-lib.com install.com
-TEST=ssltest.c
-APPS=
-
-LIB=$(TOP)/libssl.a
-SHARED_LIB= libssl$(SHLIB_EXT)
-LIBSRC= \
- s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
- s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c s3_cbc.c \
- s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
- d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
- d1_both.c d1_enc.c d1_srtp.c \
- ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
- ssl_ciph.c ssl_stat.c ssl_rsa.c \
- ssl_asn1.c ssl_txt.c ssl_algs.c \
- bio_ssl.c ssl_err.c kssl.c tls_srp.c t1_reneg.c
-LIBOBJ= \
- s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
- s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o s3_cbc.o \
- s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
- d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
- d1_both.o d1_enc.o d1_srtp.o\
- ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
- ssl_ciph.o ssl_stat.o ssl_rsa.o \
- ssl_asn1.o ssl_txt.o ssl_algs.o \
- bio_ssl.o ssl_err.o kssl.o tls_srp.o t1_reneg.o
-
-SRC= $(LIBSRC)
-
-EXHEADER= ssl.h ssl2.h ssl3.h ssl23.h tls1.h dtls1.h kssl.h srtp.h
-HEADER= $(EXHEADER) ssl_locl.h kssl_lcl.h
-
-ALL= $(GENERAL) $(SRC) $(HEADER)
-
-top:
- (cd ..; $(MAKE) DIRS=$(DIR) all)
-
-all: shared
-
-lib: $(LIBOBJ)
- $(AR) $(LIB) $(LIBOBJ)
- $(RANLIB) $(LIB) || echo Never mind.
- @touch lib
-
-shared: lib
- if [ -n "$(SHARED_LIBS)" ]; then \
- (cd ..; $(MAKE) $(SHARED_LIB)); \
- fi
-
-files:
- $(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO
-
-links:
- @$(PERL) $(TOP)/util/mklink.pl ../include/openssl $(EXHEADER)
- @$(PERL) $(TOP)/util/mklink.pl ../test $(TEST)
- @$(PERL) $(TOP)/util/mklink.pl ../apps $(APPS)
-
-install:
- @[ -n "$(INSTALLTOP)" ] # should be set by top Makefile...
- @headerlist="$(EXHEADER)"; for i in $$headerlist ; \
- do \
- (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
- done;
-
-tags:
- ctags $(SRC)
-
-tests:
-
-lint:
- lint -DLINT $(INCLUDES) $(SRC)>fluff
-
-depend:
- @if [ -z "$(THIS)" ]; then \
- $(MAKE) -f $(TOP)/Makefile reflect THIS=$@; \
- else \
- $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(LIBSRC); \
- fi
-
-dclean:
- $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
- mv -f Makefile.new $(MAKEFILE)
-
-clean:
- rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-
-bio_ssl.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-bio_ssl.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-bio_ssl.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
-bio_ssl.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-bio_ssl.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-bio_ssl.o: ../include/openssl/err.h ../include/openssl/evp.h
-bio_ssl.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-bio_ssl.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-bio_ssl.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-bio_ssl.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-bio_ssl.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-bio_ssl.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-bio_ssl.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-bio_ssl.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-bio_ssl.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-bio_ssl.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-bio_ssl.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-bio_ssl.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h bio_ssl.c
-d1_both.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_both.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_both.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_both.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_both.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_both.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_both.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_both.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_both.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_both.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_both.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_both.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_both.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_both.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_both.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_both.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_both.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-d1_both.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-d1_both.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-d1_both.o: ../include/openssl/x509_vfy.h d1_both.c ssl_locl.h
-d1_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_clnt.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-d1_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_clnt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_clnt.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-d1_clnt.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-d1_clnt.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-d1_clnt.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-d1_clnt.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-d1_clnt.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-d1_clnt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_clnt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_clnt.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_clnt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_clnt.c
-d1_clnt.o: kssl_lcl.h ssl_locl.h
-d1_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_enc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_enc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_enc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_enc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_enc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_enc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_enc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_enc.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-d1_enc.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-d1_enc.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-d1_enc.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-d1_enc.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-d1_enc.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-d1_enc.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_enc.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_enc.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_enc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_enc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_enc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_enc.c
-d1_enc.o: ssl_locl.h
-d1_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_lib.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_lib.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_lib.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_lib.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_lib.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_lib.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_lib.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_lib.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_lib.c
-d1_lib.o: ssl_locl.h
-d1_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_meth.c
-d1_meth.o: ssl_locl.h
-d1_pkt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_pkt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_pkt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_pkt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_pkt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_pkt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_pkt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_pkt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_pkt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_pkt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_pkt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_pkt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_pkt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_pkt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_pkt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_pkt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_pkt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-d1_pkt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-d1_pkt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-d1_pkt.o: ../include/openssl/x509_vfy.h d1_pkt.c ssl_locl.h
-d1_srtp.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_srtp.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_srtp.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_srtp.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_srtp.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_srtp.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_srtp.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_srtp.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_srtp.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_srtp.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_srtp.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_srtp.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_srtp.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_srtp.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_srtp.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_srtp.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_srtp.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_srtp.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_srtp.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_srtp.c
-d1_srtp.o: srtp.h ssl_locl.h
-d1_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-d1_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_srvr.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_srvr.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-d1_srvr.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-d1_srvr.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-d1_srvr.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-d1_srvr.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-d1_srvr.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-d1_srvr.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_srvr.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_srvr.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_srvr.c
-d1_srvr.o: ssl_locl.h
-kssl.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-kssl.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-kssl.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
-kssl.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-kssl.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-kssl.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-kssl.o: ../include/openssl/krb5_asn.h ../include/openssl/kssl.h
-kssl.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-kssl.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-kssl.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-kssl.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-kssl.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-kssl.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-kssl.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-kssl.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-kssl.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-kssl.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-kssl.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h kssl.c
-kssl.o: kssl_lcl.h
-s23_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_clnt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_clnt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s23_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s23_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s23_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s23_clnt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s23_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s23_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s23_clnt.o: ../include/openssl/x509_vfy.h s23_clnt.c ssl_locl.h
-s23_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_lib.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_lib.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_lib.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_lib.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_lib.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_lib.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s23_lib.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s23_lib.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s23_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s23_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s23_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s23_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s23_lib.c
-s23_lib.o: ssl_locl.h
-s23_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s23_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s23_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s23_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s23_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s23_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s23_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s23_meth.c
-s23_meth.o: ssl_locl.h
-s23_pkt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_pkt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_pkt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_pkt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_pkt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_pkt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_pkt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_pkt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_pkt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_pkt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_pkt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_pkt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_pkt.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s23_pkt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s23_pkt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s23_pkt.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s23_pkt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s23_pkt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s23_pkt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s23_pkt.c
-s23_pkt.o: ssl_locl.h
-s23_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_srvr.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_srvr.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_srvr.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s23_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s23_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s23_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s23_srvr.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s23_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s23_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s23_srvr.o: ../include/openssl/x509_vfy.h s23_srvr.c ssl_locl.h
-s2_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_clnt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_clnt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s2_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s2_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s2_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s2_clnt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s2_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s2_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s2_clnt.o: ../include/openssl/x509_vfy.h s2_clnt.c ssl_locl.h
-s2_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_enc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_enc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_enc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_enc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_enc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_enc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_enc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_enc.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_enc.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_enc.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_enc.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_enc.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s2_enc.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s2_enc.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s2_enc.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s2_enc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s2_enc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s2_enc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s2_enc.c
-s2_enc.o: ssl_locl.h
-s2_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_lib.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_lib.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_lib.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_lib.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_lib.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-s2_lib.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-s2_lib.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s2_lib.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s2_lib.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-s2_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s2_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s2_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s2_lib.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s2_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s2_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s2_lib.o: ../include/openssl/x509_vfy.h s2_lib.c ssl_locl.h
-s2_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s2_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s2_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s2_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s2_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s2_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s2_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s2_meth.c
-s2_meth.o: ssl_locl.h
-s2_pkt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_pkt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_pkt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_pkt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_pkt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_pkt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_pkt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_pkt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_pkt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_pkt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_pkt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_pkt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_pkt.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s2_pkt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s2_pkt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s2_pkt.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s2_pkt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s2_pkt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s2_pkt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s2_pkt.c
-s2_pkt.o: ssl_locl.h
-s2_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_srvr.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_srvr.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_srvr.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s2_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s2_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s2_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s2_srvr.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s2_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s2_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s2_srvr.o: ../include/openssl/x509_vfy.h s2_srvr.c ssl_locl.h
-s3_both.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_both.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_both.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_both.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_both.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_both.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_both.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_both.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_both.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_both.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_both.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_both.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_both.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_both.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_both.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_both.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_both.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_both.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_both.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_both.o: ../include/openssl/x509_vfy.h s3_both.c ssl_locl.h
-s3_cbc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_cbc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_cbc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_cbc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_cbc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_cbc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_cbc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_cbc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_cbc.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-s3_cbc.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-s3_cbc.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s3_cbc.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s3_cbc.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-s3_cbc.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_cbc.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_cbc.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_cbc.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_cbc.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_cbc.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_cbc.o: ../include/openssl/x509_vfy.h s3_cbc.c ssl_locl.h
-s3_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_clnt.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-s3_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-s3_clnt.o: ../include/openssl/err.h ../include/openssl/evp.h
-s3_clnt.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-s3_clnt.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-s3_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_clnt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_clnt.o: ../include/openssl/x509_vfy.h kssl_lcl.h s3_clnt.c ssl_locl.h
-s3_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_enc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_enc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_enc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_enc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_enc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_enc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_enc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_enc.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-s3_enc.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-s3_enc.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s3_enc.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s3_enc.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-s3_enc.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_enc.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_enc.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_enc.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_enc.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_enc.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_enc.o: ../include/openssl/x509_vfy.h s3_enc.c ssl_locl.h
-s3_lib.o: ../crypto/ec/ec_lcl.h ../e_os.h ../include/openssl/asn1.h
-s3_lib.o: ../include/openssl/bio.h ../include/openssl/bn.h
-s3_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_lib.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-s3_lib.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-s3_lib.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-s3_lib.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-s3_lib.o: ../include/openssl/err.h ../include/openssl/evp.h
-s3_lib.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-s3_lib.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-s3_lib.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_lib.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s3_lib.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s3_lib.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s3_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s3_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s3_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s3_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h kssl_lcl.h
-s3_lib.o: s3_lib.c ssl_locl.h
-s3_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s3_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s3_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s3_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s3_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s3_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s3_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s3_meth.c
-s3_meth.o: ssl_locl.h
-s3_pkt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_pkt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_pkt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_pkt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_pkt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_pkt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_pkt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_pkt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_pkt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_pkt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_pkt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_pkt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_pkt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_pkt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_pkt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_pkt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_pkt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_pkt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_pkt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_pkt.o: ../include/openssl/x509_vfy.h s3_pkt.c ssl_locl.h
-s3_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-s3_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_srvr.o: ../include/openssl/krb5_asn.h ../include/openssl/kssl.h
-s3_srvr.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-s3_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_srvr.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_srvr.o: ../include/openssl/x509_vfy.h kssl_lcl.h s3_srvr.c ssl_locl.h
-ssl_algs.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_algs.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_algs.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_algs.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_algs.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_algs.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_algs.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_algs.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_algs.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_algs.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_algs.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_algs.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_algs.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_algs.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_algs.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_algs.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_algs.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_algs.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_algs.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_algs.c
-ssl_algs.o: ssl_locl.h
-ssl_asn1.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/asn1_mac.h
-ssl_asn1.o: ../include/openssl/bio.h ../include/openssl/buffer.h
-ssl_asn1.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-ssl_asn1.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-ssl_asn1.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-ssl_asn1.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-ssl_asn1.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_asn1.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_asn1.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_asn1.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_asn1.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_asn1.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_asn1.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_asn1.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-ssl_asn1.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-ssl_asn1.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-ssl_asn1.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-ssl_asn1.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-ssl_asn1.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-ssl_asn1.o: ../include/openssl/x509_vfy.h ssl_asn1.c ssl_locl.h
-ssl_cert.o: ../crypto/o_dir.h ../e_os.h ../include/openssl/asn1.h
-ssl_cert.o: ../include/openssl/bio.h ../include/openssl/bn.h
-ssl_cert.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_cert.o: ../include/openssl/conf.h ../include/openssl/crypto.h
-ssl_cert.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-ssl_cert.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_cert.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_cert.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_cert.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_cert.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_cert.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_cert.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_cert.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_cert.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_cert.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_cert.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_cert.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_cert.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_cert.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_cert.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_cert.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-ssl_cert.o: ../include/openssl/x509v3.h ssl_cert.c ssl_locl.h
-ssl_ciph.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_ciph.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_ciph.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_ciph.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_ciph.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_ciph.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-ssl_ciph.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_ciph.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_ciph.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_ciph.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_ciph.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_ciph.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_ciph.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_ciph.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-ssl_ciph.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-ssl_ciph.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-ssl_ciph.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-ssl_ciph.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-ssl_ciph.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-ssl_ciph.o: ../include/openssl/x509_vfy.h ssl_ciph.c ssl_locl.h
-ssl_err.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_err.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_err.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
-ssl_err.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-ssl_err.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-ssl_err.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_err.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_err.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_err.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_err.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_err.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_err.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_err.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_err.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_err.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_err.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_err.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_err.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_err.c
-ssl_err2.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_err2.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_err2.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
-ssl_err2.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-ssl_err2.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-ssl_err2.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_err2.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_err2.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_err2.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_err2.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_err2.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_err2.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_err2.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_err2.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_err2.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_err2.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_err2.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_err2.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_err2.c
-ssl_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_lib.o: ../include/openssl/conf.h ../include/openssl/crypto.h
-ssl_lib.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-ssl_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_lib.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-ssl_lib.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_lib.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_lib.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_lib.o: ../include/openssl/objects.h ../include/openssl/ocsp.h
-ssl_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_lib.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-ssl_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-ssl_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-ssl_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-ssl_lib.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-ssl_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-ssl_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-ssl_lib.o: ../include/openssl/x509_vfy.h ../include/openssl/x509v3.h kssl_lcl.h
-ssl_lib.o: ssl_lib.c ssl_locl.h
-ssl_rsa.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_rsa.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_rsa.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_rsa.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_rsa.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_rsa.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_rsa.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_rsa.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_rsa.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_rsa.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_rsa.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_rsa.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_rsa.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_rsa.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_rsa.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_rsa.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_rsa.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_rsa.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_rsa.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-ssl_rsa.o: ssl_rsa.c
-ssl_sess.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_sess.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_sess.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_sess.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_sess.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_sess.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-ssl_sess.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_sess.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_sess.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_sess.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_sess.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_sess.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_sess.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_sess.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-ssl_sess.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_sess.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_sess.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_sess.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_sess.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_sess.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-ssl_sess.o: ssl_sess.c
-ssl_stat.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_stat.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_stat.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_stat.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_stat.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_stat.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_stat.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_stat.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_stat.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_stat.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_stat.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_stat.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_stat.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_stat.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_stat.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_stat.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_stat.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_stat.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_stat.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-ssl_stat.o: ssl_stat.c
-ssl_txt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_txt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_txt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_txt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_txt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_txt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_txt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_txt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_txt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_txt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_txt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_txt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_txt.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_txt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_txt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_txt.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_txt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_txt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_txt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-ssl_txt.o: ssl_txt.c
-t1_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_clnt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_clnt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_clnt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-t1_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-t1_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-t1_clnt.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_clnt.c
-t1_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_enc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_enc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_enc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_enc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_enc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_enc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_enc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_enc.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-t1_enc.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-t1_enc.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-t1_enc.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-t1_enc.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-t1_enc.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-t1_enc.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-t1_enc.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-t1_enc.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-t1_enc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_enc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_enc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-t1_enc.o: t1_enc.c
-t1_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_lib.o: ../include/openssl/conf.h ../include/openssl/crypto.h
-t1_lib.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-t1_lib.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-t1_lib.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-t1_lib.o: ../include/openssl/err.h ../include/openssl/evp.h
-t1_lib.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-t1_lib.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-t1_lib.o: ../include/openssl/objects.h ../include/openssl/ocsp.h
-t1_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_lib.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_lib.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-t1_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-t1_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-t1_lib.o: ../include/openssl/x509_vfy.h ../include/openssl/x509v3.h ssl_locl.h
-t1_lib.o: t1_lib.c
-t1_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-t1_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-t1_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-t1_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-t1_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-t1_meth.o: t1_meth.c
-t1_reneg.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_reneg.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_reneg.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_reneg.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_reneg.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_reneg.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_reneg.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_reneg.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_reneg.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_reneg.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_reneg.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_reneg.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_reneg.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-t1_reneg.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-t1_reneg.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-t1_reneg.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-t1_reneg.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_reneg.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_reneg.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-t1_reneg.o: t1_reneg.c
-t1_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_srvr.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_srvr.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_srvr.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_srvr.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
-tls_srp.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-tls_srp.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-tls_srp.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-tls_srp.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-tls_srp.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-tls_srp.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-tls_srp.o: ../include/openssl/err.h ../include/openssl/evp.h
-tls_srp.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-tls_srp.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-tls_srp.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-tls_srp.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-tls_srp.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-tls_srp.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-tls_srp.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-tls_srp.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-tls_srp.o: ../include/openssl/srp.h ../include/openssl/srtp.h
-tls_srp.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-tls_srp.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-tls_srp.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-tls_srp.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-tls_srp.o: ../include/openssl/x509_vfy.h ssl_locl.h tls_srp.c
diff --git a/drivers/builtin_openssl/ssl/Makefile.save b/drivers/builtin_openssl/ssl/Makefile.save
deleted file mode 100644
index debe07405b..0000000000
--- a/drivers/builtin_openssl/ssl/Makefile.save
+++ /dev/null
@@ -1,1061 +0,0 @@
-#
-# OpenSSL/ssl/Makefile
-#
-
-DIR= ssl
-TOP= ..
-CC= cc
-INCLUDES= -I../crypto -I$(TOP) -I../include $(KRB5_INCLUDES)
-CFLAG=-g
-MAKEFILE= Makefile
-AR= ar r
-# KRB5 stuff
-KRB5_INCLUDES=
-
-CFLAGS= $(INCLUDES) $(CFLAG)
-
-GENERAL=Makefile README ssl-lib.com install.com
-TEST=ssltest.c
-APPS=
-
-LIB=$(TOP)/libssl.a
-SHARED_LIB= libssl$(SHLIB_EXT)
-LIBSRC= \
- s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
- s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c s3_cbc.c \
- s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
- d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
- d1_both.c d1_enc.c d1_srtp.c \
- ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
- ssl_ciph.c ssl_stat.c ssl_rsa.c \
- ssl_asn1.c ssl_txt.c ssl_algs.c \
- bio_ssl.c ssl_err.c kssl.c tls_srp.c t1_reneg.c
-LIBOBJ= \
- s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
- s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o s3_cbc.o \
- s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
- d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
- d1_both.o d1_enc.o d1_srtp.o\
- ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
- ssl_ciph.o ssl_stat.o ssl_rsa.o \
- ssl_asn1.o ssl_txt.o ssl_algs.o \
- bio_ssl.o ssl_err.o kssl.o tls_srp.o t1_reneg.o
-
-SRC= $(LIBSRC)
-
-EXHEADER= ssl.h ssl2.h ssl3.h ssl23.h tls1.h dtls1.h kssl.h srtp.h
-HEADER= $(EXHEADER) ssl_locl.h kssl_lcl.h
-
-ALL= $(GENERAL) $(SRC) $(HEADER)
-
-top:
- (cd ..; $(MAKE) DIRS=$(DIR) all)
-
-all: shared
-
-lib: $(LIBOBJ)
- $(AR) $(LIB) $(LIBOBJ)
- $(RANLIB) $(LIB) || echo Never mind.
- @touch lib
-
-shared: lib
- if [ -n "$(SHARED_LIBS)" ]; then \
- (cd ..; $(MAKE) $(SHARED_LIB)); \
- fi
-
-files:
- $(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO
-
-links:
- @$(PERL) $(TOP)/util/mklink.pl ../include/openssl $(EXHEADER)
- @$(PERL) $(TOP)/util/mklink.pl ../test $(TEST)
- @$(PERL) $(TOP)/util/mklink.pl ../apps $(APPS)
-
-install:
- @[ -n "$(INSTALLTOP)" ] # should be set by top Makefile...
- @headerlist="$(EXHEADER)"; for i in $$headerlist ; \
- do \
- (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
- done;
-
-tags:
- ctags $(SRC)
-
-tests:
-
-lint:
- lint -DLINT $(INCLUDES) $(SRC)>fluff
-
-depend:
- @if [ -z "$(THIS)" ]; then \
- $(MAKE) -f $(TOP)/Makefile reflect THIS=$@; \
- else \
- $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(LIBSRC); \
- fi
-
-dclean:
- $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
- mv -f Makefile.new $(MAKEFILE)
-
-clean:
- rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-
-bio_ssl.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-bio_ssl.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-bio_ssl.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
-bio_ssl.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-bio_ssl.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-bio_ssl.o: ../include/openssl/err.h ../include/openssl/evp.h
-bio_ssl.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-bio_ssl.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-bio_ssl.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-bio_ssl.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-bio_ssl.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-bio_ssl.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-bio_ssl.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-bio_ssl.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-bio_ssl.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-bio_ssl.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-bio_ssl.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-bio_ssl.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h bio_ssl.c
-d1_both.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_both.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_both.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_both.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_both.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_both.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_both.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_both.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_both.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_both.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_both.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_both.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_both.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_both.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_both.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_both.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_both.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-d1_both.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-d1_both.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-d1_both.o: ../include/openssl/x509_vfy.h d1_both.c ssl_locl.h
-d1_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_clnt.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-d1_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_clnt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_clnt.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-d1_clnt.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-d1_clnt.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-d1_clnt.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-d1_clnt.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-d1_clnt.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-d1_clnt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_clnt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_clnt.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_clnt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_clnt.c
-d1_clnt.o: kssl_lcl.h ssl_locl.h
-d1_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_enc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_enc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_enc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_enc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_enc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_enc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_enc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_enc.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-d1_enc.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-d1_enc.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-d1_enc.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-d1_enc.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-d1_enc.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-d1_enc.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_enc.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_enc.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_enc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_enc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_enc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_enc.c
-d1_enc.o: ssl_locl.h
-d1_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_lib.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_lib.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_lib.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_lib.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_lib.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_lib.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_lib.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_lib.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_lib.c
-d1_lib.o: ssl_locl.h
-d1_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_meth.c
-d1_meth.o: ssl_locl.h
-d1_pkt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_pkt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_pkt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_pkt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_pkt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_pkt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_pkt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_pkt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_pkt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_pkt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_pkt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_pkt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_pkt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_pkt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_pkt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_pkt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_pkt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-d1_pkt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-d1_pkt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-d1_pkt.o: ../include/openssl/x509_vfy.h d1_pkt.c ssl_locl.h
-d1_srtp.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_srtp.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-d1_srtp.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-d1_srtp.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_srtp.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_srtp.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_srtp.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_srtp.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_srtp.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_srtp.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_srtp.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_srtp.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_srtp.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_srtp.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_srtp.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_srtp.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_srtp.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_srtp.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_srtp.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_srtp.c
-d1_srtp.o: srtp.h ssl_locl.h
-d1_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-d1_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_srvr.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-d1_srvr.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-d1_srvr.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-d1_srvr.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-d1_srvr.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-d1_srvr.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-d1_srvr.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-d1_srvr.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_srvr.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_srvr.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-d1_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_srvr.c
-d1_srvr.o: ssl_locl.h
-kssl.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-kssl.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-kssl.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
-kssl.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-kssl.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-kssl.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-kssl.o: ../include/openssl/krb5_asn.h ../include/openssl/kssl.h
-kssl.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-kssl.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-kssl.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-kssl.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-kssl.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-kssl.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-kssl.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-kssl.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-kssl.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-kssl.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-kssl.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h kssl.c
-kssl.o: kssl_lcl.h
-s23_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_clnt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_clnt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s23_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s23_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s23_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s23_clnt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s23_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s23_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s23_clnt.o: ../include/openssl/x509_vfy.h s23_clnt.c ssl_locl.h
-s23_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_lib.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_lib.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_lib.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_lib.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_lib.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_lib.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s23_lib.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s23_lib.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s23_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s23_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s23_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s23_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s23_lib.c
-s23_lib.o: ssl_locl.h
-s23_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s23_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s23_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s23_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s23_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s23_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s23_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s23_meth.c
-s23_meth.o: ssl_locl.h
-s23_pkt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_pkt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_pkt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_pkt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_pkt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_pkt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_pkt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_pkt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_pkt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_pkt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_pkt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_pkt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_pkt.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s23_pkt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s23_pkt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s23_pkt.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s23_pkt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s23_pkt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s23_pkt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s23_pkt.c
-s23_pkt.o: ssl_locl.h
-s23_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s23_srvr.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s23_srvr.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s23_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s23_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s23_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s23_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s23_srvr.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s23_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s23_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s23_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s23_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s23_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s23_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s23_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s23_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s23_srvr.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s23_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s23_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s23_srvr.o: ../include/openssl/x509_vfy.h s23_srvr.c ssl_locl.h
-s2_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_clnt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_clnt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s2_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s2_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s2_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s2_clnt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s2_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s2_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s2_clnt.o: ../include/openssl/x509_vfy.h s2_clnt.c ssl_locl.h
-s2_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_enc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_enc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_enc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_enc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_enc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_enc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_enc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_enc.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_enc.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_enc.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_enc.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_enc.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s2_enc.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s2_enc.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s2_enc.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s2_enc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s2_enc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s2_enc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s2_enc.c
-s2_enc.o: ssl_locl.h
-s2_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_lib.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_lib.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_lib.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_lib.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_lib.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-s2_lib.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-s2_lib.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s2_lib.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s2_lib.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-s2_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s2_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s2_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s2_lib.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s2_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s2_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s2_lib.o: ../include/openssl/x509_vfy.h s2_lib.c ssl_locl.h
-s2_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s2_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s2_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s2_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s2_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s2_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s2_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s2_meth.c
-s2_meth.o: ssl_locl.h
-s2_pkt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_pkt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_pkt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_pkt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_pkt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_pkt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_pkt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_pkt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_pkt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_pkt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_pkt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_pkt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_pkt.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s2_pkt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s2_pkt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s2_pkt.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s2_pkt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s2_pkt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s2_pkt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s2_pkt.c
-s2_pkt.o: ssl_locl.h
-s2_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s2_srvr.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s2_srvr.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s2_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s2_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s2_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s2_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s2_srvr.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s2_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s2_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s2_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s2_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s2_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s2_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s2_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s2_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s2_srvr.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s2_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s2_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s2_srvr.o: ../include/openssl/x509_vfy.h s2_srvr.c ssl_locl.h
-s3_both.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_both.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_both.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_both.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_both.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_both.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_both.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_both.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_both.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_both.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_both.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_both.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_both.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_both.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_both.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_both.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_both.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_both.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_both.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_both.o: ../include/openssl/x509_vfy.h s3_both.c ssl_locl.h
-s3_cbc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_cbc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_cbc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_cbc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_cbc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_cbc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_cbc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_cbc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_cbc.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-s3_cbc.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-s3_cbc.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s3_cbc.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s3_cbc.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-s3_cbc.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_cbc.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_cbc.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_cbc.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_cbc.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_cbc.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_cbc.o: ../include/openssl/x509_vfy.h s3_cbc.c ssl_locl.h
-s3_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_clnt.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-s3_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-s3_clnt.o: ../include/openssl/err.h ../include/openssl/evp.h
-s3_clnt.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-s3_clnt.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-s3_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_clnt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_clnt.o: ../include/openssl/x509_vfy.h kssl_lcl.h s3_clnt.c ssl_locl.h
-s3_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_enc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_enc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_enc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_enc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_enc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_enc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_enc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_enc.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-s3_enc.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-s3_enc.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s3_enc.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s3_enc.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-s3_enc.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_enc.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_enc.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_enc.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_enc.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_enc.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_enc.o: ../include/openssl/x509_vfy.h s3_enc.c ssl_locl.h
-s3_lib.o: ../crypto/ec/ec_lcl.h ../e_os.h ../include/openssl/asn1.h
-s3_lib.o: ../include/openssl/bio.h ../include/openssl/bn.h
-s3_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_lib.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-s3_lib.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-s3_lib.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-s3_lib.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-s3_lib.o: ../include/openssl/err.h ../include/openssl/evp.h
-s3_lib.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-s3_lib.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-s3_lib.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_lib.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s3_lib.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s3_lib.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s3_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s3_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s3_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s3_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h kssl_lcl.h
-s3_lib.o: s3_lib.c ssl_locl.h
-s3_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-s3_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s3_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s3_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-s3_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s3_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s3_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h s3_meth.c
-s3_meth.o: ssl_locl.h
-s3_pkt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_pkt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-s3_pkt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-s3_pkt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_pkt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_pkt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_pkt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_pkt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-s3_pkt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_pkt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_pkt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_pkt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_pkt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_pkt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_pkt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_pkt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_pkt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_pkt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_pkt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_pkt.o: ../include/openssl/x509_vfy.h s3_pkt.c ssl_locl.h
-s3_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-s3_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_srvr.o: ../include/openssl/krb5_asn.h ../include/openssl/kssl.h
-s3_srvr.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-s3_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_srvr.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-s3_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_srvr.o: ../include/openssl/x509_vfy.h kssl_lcl.h s3_srvr.c ssl_locl.h
-ssl_algs.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_algs.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_algs.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_algs.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_algs.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_algs.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_algs.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_algs.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_algs.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_algs.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_algs.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_algs.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_algs.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_algs.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_algs.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_algs.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_algs.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_algs.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_algs.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_algs.c
-ssl_algs.o: ssl_locl.h
-ssl_asn1.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/asn1_mac.h
-ssl_asn1.o: ../include/openssl/bio.h ../include/openssl/buffer.h
-ssl_asn1.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-ssl_asn1.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-ssl_asn1.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-ssl_asn1.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-ssl_asn1.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_asn1.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_asn1.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_asn1.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_asn1.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_asn1.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_asn1.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_asn1.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-ssl_asn1.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-ssl_asn1.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-ssl_asn1.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-ssl_asn1.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-ssl_asn1.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-ssl_asn1.o: ../include/openssl/x509_vfy.h ssl_asn1.c ssl_locl.h
-ssl_cert.o: ../crypto/o_dir.h ../e_os.h ../include/openssl/asn1.h
-ssl_cert.o: ../include/openssl/bio.h ../include/openssl/bn.h
-ssl_cert.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_cert.o: ../include/openssl/conf.h ../include/openssl/crypto.h
-ssl_cert.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-ssl_cert.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_cert.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_cert.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_cert.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_cert.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_cert.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_cert.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_cert.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_cert.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_cert.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_cert.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_cert.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_cert.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_cert.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_cert.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_cert.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-ssl_cert.o: ../include/openssl/x509v3.h ssl_cert.c ssl_locl.h
-ssl_ciph.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_ciph.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_ciph.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_ciph.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_ciph.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_ciph.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-ssl_ciph.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_ciph.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_ciph.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_ciph.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_ciph.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_ciph.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_ciph.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_ciph.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-ssl_ciph.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-ssl_ciph.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-ssl_ciph.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-ssl_ciph.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-ssl_ciph.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-ssl_ciph.o: ../include/openssl/x509_vfy.h ssl_ciph.c ssl_locl.h
-ssl_err.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_err.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_err.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
-ssl_err.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-ssl_err.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-ssl_err.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_err.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_err.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_err.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_err.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_err.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_err.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_err.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_err.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_err.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_err.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_err.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_err.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_err.c
-ssl_err2.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_err2.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_err2.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
-ssl_err2.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-ssl_err2.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-ssl_err2.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_err2.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_err2.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_err2.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_err2.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_err2.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_err2.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_err2.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_err2.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_err2.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_err2.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_err2.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_err2.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_err2.c
-ssl_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_lib.o: ../include/openssl/conf.h ../include/openssl/crypto.h
-ssl_lib.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-ssl_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_lib.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-ssl_lib.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_lib.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_lib.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_lib.o: ../include/openssl/objects.h ../include/openssl/ocsp.h
-ssl_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_lib.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-ssl_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-ssl_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-ssl_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-ssl_lib.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-ssl_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-ssl_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-ssl_lib.o: ../include/openssl/x509_vfy.h ../include/openssl/x509v3.h kssl_lcl.h
-ssl_lib.o: ssl_lib.c ssl_locl.h
-ssl_rsa.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_rsa.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_rsa.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_rsa.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_rsa.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_rsa.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_rsa.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_rsa.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_rsa.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_rsa.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_rsa.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_rsa.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_rsa.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_rsa.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_rsa.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_rsa.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_rsa.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_rsa.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_rsa.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-ssl_rsa.o: ssl_rsa.c
-ssl_sess.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_sess.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_sess.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_sess.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_sess.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_sess.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-ssl_sess.o: ../include/openssl/err.h ../include/openssl/evp.h
-ssl_sess.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-ssl_sess.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-ssl_sess.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-ssl_sess.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-ssl_sess.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-ssl_sess.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-ssl_sess.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-ssl_sess.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_sess.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_sess.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_sess.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_sess.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_sess.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-ssl_sess.o: ssl_sess.c
-ssl_stat.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_stat.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_stat.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_stat.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_stat.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_stat.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_stat.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_stat.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_stat.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_stat.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_stat.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_stat.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_stat.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_stat.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_stat.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_stat.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_stat.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_stat.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_stat.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-ssl_stat.o: ssl_stat.c
-ssl_txt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-ssl_txt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-ssl_txt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-ssl_txt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-ssl_txt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-ssl_txt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-ssl_txt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-ssl_txt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-ssl_txt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-ssl_txt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-ssl_txt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-ssl_txt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-ssl_txt.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-ssl_txt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-ssl_txt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-ssl_txt.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-ssl_txt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-ssl_txt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-ssl_txt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-ssl_txt.o: ssl_txt.c
-t1_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_clnt.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_clnt.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_clnt.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-t1_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-t1_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-t1_clnt.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_clnt.c
-t1_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_enc.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_enc.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_enc.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_enc.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_enc.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_enc.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_enc.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_enc.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-t1_enc.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-t1_enc.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-t1_enc.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-t1_enc.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-t1_enc.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-t1_enc.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-t1_enc.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-t1_enc.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-t1_enc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_enc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_enc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-t1_enc.o: t1_enc.c
-t1_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_lib.o: ../include/openssl/conf.h ../include/openssl/crypto.h
-t1_lib.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-t1_lib.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-t1_lib.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-t1_lib.o: ../include/openssl/err.h ../include/openssl/evp.h
-t1_lib.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-t1_lib.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-t1_lib.o: ../include/openssl/objects.h ../include/openssl/ocsp.h
-t1_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_lib.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_lib.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-t1_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-t1_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-t1_lib.o: ../include/openssl/x509_vfy.h ../include/openssl/x509v3.h ssl_locl.h
-t1_lib.o: t1_lib.c
-t1_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_meth.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_meth.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_meth.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_meth.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_meth.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_meth.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_meth.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-t1_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-t1_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-t1_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-t1_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-t1_meth.o: t1_meth.c
-t1_reneg.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_reneg.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_reneg.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_reneg.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_reneg.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_reneg.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_reneg.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_reneg.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_reneg.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_reneg.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_reneg.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_reneg.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_reneg.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-t1_reneg.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-t1_reneg.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-t1_reneg.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
-t1_reneg.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_reneg.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_reneg.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
-t1_reneg.o: t1_reneg.c
-t1_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_srvr.o: ../include/openssl/buffer.h ../include/openssl/comp.h
-t1_srvr.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
-t1_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-t1_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-t1_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-t1_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-t1_srvr.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
-t1_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_srvr.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
-tls_srp.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-tls_srp.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-tls_srp.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-tls_srp.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-tls_srp.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-tls_srp.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-tls_srp.o: ../include/openssl/err.h ../include/openssl/evp.h
-tls_srp.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
-tls_srp.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-tls_srp.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-tls_srp.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-tls_srp.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-tls_srp.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-tls_srp.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-tls_srp.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-tls_srp.o: ../include/openssl/srp.h ../include/openssl/srtp.h
-tls_srp.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-tls_srp.o: ../include/openssl/ssl23.h ../include/openssl/ssl3.h
-tls_srp.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-tls_srp.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-tls_srp.o: ../include/openssl/x509_vfy.h ssl_locl.h tls_srp.c
diff --git a/drivers/builtin_openssl/ssl/d1_both.c b/drivers/builtin_openssl/ssl/d1_both.c
deleted file mode 100644
index 2e8cf681ed..0000000000
--- a/drivers/builtin_openssl/ssl/d1_both.c
+++ /dev/null
@@ -1,1608 +0,0 @@
-/* ssl/d1_both.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1998-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <limits.h>
-#include <string.h>
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
-#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8)
-
-#define RSMBLY_BITMASK_MARK(bitmask, start, end) { \
- if ((end) - (start) <= 8) { \
- long ii; \
- for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \
- } else { \
- long ii; \
- bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \
- for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \
- bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \
- } }
-
-#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \
- long ii; \
- OPENSSL_assert((msg_len) > 0); \
- is_complete = 1; \
- if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \
- if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \
- if (bitmask[ii] != 0xff) { is_complete = 0; break; } }
-
-#if 0
-#define RSMBLY_BITMASK_PRINT(bitmask, msg_len) { \
- long ii; \
- printf("bitmask: "); for (ii = 0; ii < (msg_len); ii++) \
- printf("%d ", (bitmask[ii >> 3] & (1 << (ii & 7))) >> (ii & 7)); \
- printf("\n"); }
-#endif
-
-static unsigned char bitmask_start_values[] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
-static unsigned char bitmask_end_values[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
-
-/* XDTLS: figure out the right values */
-static unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28};
-
-static unsigned int dtls1_guess_mtu(unsigned int curr_mtu);
-static void dtls1_fix_message_header(SSL *s, unsigned long frag_off,
- unsigned long frag_len);
-static unsigned char *dtls1_write_message_header(SSL *s,
- unsigned char *p);
-static void dtls1_set_message_header_int(SSL *s, unsigned char mt,
- unsigned long len, unsigned short seq_num, unsigned long frag_off,
- unsigned long frag_len);
-static long dtls1_get_message_fragment(SSL *s, int st1, int stn,
- long max, int *ok);
-
-static hm_fragment *
-dtls1_hm_fragment_new(unsigned long frag_len, int reassembly)
- {
- hm_fragment *frag = NULL;
- unsigned char *buf = NULL;
- unsigned char *bitmask = NULL;
-
- frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
- if ( frag == NULL)
- return NULL;
-
- if (frag_len)
- {
- buf = (unsigned char *)OPENSSL_malloc(frag_len);
- if ( buf == NULL)
- {
- OPENSSL_free(frag);
- return NULL;
- }
- }
-
- /* zero length fragment gets zero frag->fragment */
- frag->fragment = buf;
-
- /* Initialize reassembly bitmask if necessary */
- if (reassembly)
- {
- bitmask = (unsigned char *)OPENSSL_malloc(RSMBLY_BITMASK_SIZE(frag_len));
- if (bitmask == NULL)
- {
- if (buf != NULL) OPENSSL_free(buf);
- OPENSSL_free(frag);
- return NULL;
- }
- memset(bitmask, 0, RSMBLY_BITMASK_SIZE(frag_len));
- }
-
- frag->reassembly = bitmask;
-
- return frag;
- }
-
-static void
-dtls1_hm_fragment_free(hm_fragment *frag)
- {
-
- if (frag->msg_header.is_ccs)
- {
- EVP_CIPHER_CTX_free(frag->msg_header.saved_retransmit_state.enc_write_ctx);
- EVP_MD_CTX_destroy(frag->msg_header.saved_retransmit_state.write_hash);
- }
- if (frag->fragment) OPENSSL_free(frag->fragment);
- if (frag->reassembly) OPENSSL_free(frag->reassembly);
- OPENSSL_free(frag);
- }
-
-/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
-int dtls1_do_write(SSL *s, int type)
- {
- int ret;
- int curr_mtu;
- unsigned int len, frag_off, mac_size, blocksize;
-
- /* AHA! Figure out the MTU, and stick to the right size */
- if (s->d1->mtu < dtls1_min_mtu() && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
- {
- s->d1->mtu =
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
-
- /* I've seen the kernel return bogus numbers when it doesn't know
- * (initial write), so just make sure we have a reasonable number */
- if (s->d1->mtu < dtls1_min_mtu())
- {
- s->d1->mtu = 0;
- s->d1->mtu = dtls1_guess_mtu(s->d1->mtu);
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
- s->d1->mtu, NULL);
- }
- }
-#if 0
- mtu = s->d1->mtu;
-
- fprintf(stderr, "using MTU = %d\n", mtu);
-
- mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
-
- curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s));
-
- if ( curr_mtu > 0)
- mtu = curr_mtu;
- else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0)
- return ret;
-
- if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu)
- {
- ret = BIO_flush(SSL_get_wbio(s));
- if ( ret <= 0)
- return ret;
- mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
- }
-#endif
-
- OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu()); /* should have something reasonable now */
-
- if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE)
- OPENSSL_assert(s->init_num ==
- (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);
-
- if (s->write_hash)
- mac_size = EVP_MD_CTX_size(s->write_hash);
- else
- mac_size = 0;
-
- if (s->enc_write_ctx &&
- (EVP_CIPHER_mode( s->enc_write_ctx->cipher) & EVP_CIPH_CBC_MODE))
- blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
- else
- blocksize = 0;
-
- frag_off = 0;
- while( s->init_num)
- {
- curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) -
- DTLS1_RT_HEADER_LENGTH - mac_size - blocksize;
-
- if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH)
- {
- /* grr.. we could get an error if MTU picked was wrong */
- ret = BIO_flush(SSL_get_wbio(s));
- if ( ret <= 0)
- return ret;
- curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH -
- mac_size - blocksize;
- }
-
- if ( s->init_num > curr_mtu)
- len = curr_mtu;
- else
- len = s->init_num;
-
-
- /* XDTLS: this function is too long. split out the CCS part */
- if ( type == SSL3_RT_HANDSHAKE)
- {
- if ( s->init_off != 0)
- {
- OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH);
- s->init_off -= DTLS1_HM_HEADER_LENGTH;
- s->init_num += DTLS1_HM_HEADER_LENGTH;
-
- if ( s->init_num > curr_mtu)
- len = curr_mtu;
- else
- len = s->init_num;
- }
-
- dtls1_fix_message_header(s, frag_off,
- len - DTLS1_HM_HEADER_LENGTH);
-
- dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]);
-
- OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH);
- }
-
- ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off],
- len);
- if (ret < 0)
- {
- /* might need to update MTU here, but we don't know
- * which previous packet caused the failure -- so can't
- * really retransmit anything. continue as if everything
- * is fine and wait for an alert to handle the
- * retransmit
- */
- if ( BIO_ctrl(SSL_get_wbio(s),
- BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 )
- s->d1->mtu = BIO_ctrl(SSL_get_wbio(s),
- BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
- else
- return(-1);
- }
- else
- {
-
- /* bad if this assert fails, only part of the handshake
- * message got sent. but why would this happen? */
- OPENSSL_assert(len == (unsigned int)ret);
-
- if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
- {
- /* should not be done for 'Hello Request's, but in that case
- * we'll ignore the result anyway */
- unsigned char *p = (unsigned char *)&s->init_buf->data[s->init_off];
- const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
- int xlen;
-
- if (frag_off == 0 && s->version != DTLS1_BAD_VER)
- {
- /* reconstruct message header is if it
- * is being sent in single fragment */
- *p++ = msg_hdr->type;
- l2n3(msg_hdr->msg_len,p);
- s2n (msg_hdr->seq,p);
- l2n3(0,p);
- l2n3(msg_hdr->msg_len,p);
- p -= DTLS1_HM_HEADER_LENGTH;
- xlen = ret;
- }
- else
- {
- p += DTLS1_HM_HEADER_LENGTH;
- xlen = ret - DTLS1_HM_HEADER_LENGTH;
- }
-
- ssl3_finish_mac(s, p, xlen);
- }
-
- if (ret == s->init_num)
- {
- if (s->msg_callback)
- s->msg_callback(1, s->version, type, s->init_buf->data,
- (size_t)(s->init_off + s->init_num), s,
- s->msg_callback_arg);
-
- s->init_off = 0; /* done writing this message */
- s->init_num = 0;
-
- return(1);
- }
- s->init_off+=ret;
- s->init_num-=ret;
- frag_off += (ret -= DTLS1_HM_HEADER_LENGTH);
- }
- }
- return(0);
- }
-
-
-/* Obtain handshake message of message type 'mt' (any if mt == -1),
- * maximum acceptable body length 'max'.
- * Read an entire handshake message. Handshake messages arrive in
- * fragments.
- */
-long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
- {
- int i, al;
- struct hm_header_st *msg_hdr;
- unsigned char *p;
- unsigned long msg_len;
-
- /* s3->tmp is used to store messages that are unexpected, caused
- * by the absence of an optional handshake message */
- if (s->s3->tmp.reuse_message)
- {
- s->s3->tmp.reuse_message=0;
- if ((mt >= 0) && (s->s3->tmp.message_type != mt))
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE);
- goto f_err;
- }
- *ok=1;
- s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
- s->init_num = (int)s->s3->tmp.message_size;
- return s->init_num;
- }
-
- msg_hdr = &s->d1->r_msg_hdr;
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
-
-again:
- i = dtls1_get_message_fragment(s, st1, stn, max, ok);
- if ( i == DTLS1_HM_BAD_FRAGMENT ||
- i == DTLS1_HM_FRAGMENT_RETRY) /* bad fragment received */
- goto again;
- else if ( i <= 0 && !*ok)
- return i;
-
- p = (unsigned char *)s->init_buf->data;
- msg_len = msg_hdr->msg_len;
-
- /* reconstruct message header */
- *(p++) = msg_hdr->type;
- l2n3(msg_len,p);
- s2n (msg_hdr->seq,p);
- l2n3(0,p);
- l2n3(msg_len,p);
- if (s->version != DTLS1_BAD_VER) {
- p -= DTLS1_HM_HEADER_LENGTH;
- msg_len += DTLS1_HM_HEADER_LENGTH;
- }
-
- ssl3_finish_mac(s, p, msg_len);
- if (s->msg_callback)
- s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
- p, msg_len,
- s, s->msg_callback_arg);
-
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
-
- /* Don't change sequence numbers while listening */
- if (!s->d1->listen)
- s->d1->handshake_read_seq++;
-
- s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
- return s->init_num;
-
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- *ok = 0;
- return -1;
- }
-
-
-static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max)
- {
- size_t frag_off,frag_len,msg_len;
-
- msg_len = msg_hdr->msg_len;
- frag_off = msg_hdr->frag_off;
- frag_len = msg_hdr->frag_len;
-
- /* sanity checking */
- if ( (frag_off+frag_len) > msg_len)
- {
- SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
- return SSL_AD_ILLEGAL_PARAMETER;
- }
-
- if ( (frag_off+frag_len) > (unsigned long)max)
- {
- SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
- return SSL_AD_ILLEGAL_PARAMETER;
- }
-
- if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
- {
- /* msg_len is limited to 2^24, but is effectively checked
- * against max above */
- if (!BUF_MEM_grow_clean(s->init_buf,msg_len+DTLS1_HM_HEADER_LENGTH))
- {
- SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB);
- return SSL_AD_INTERNAL_ERROR;
- }
-
- s->s3->tmp.message_size = msg_len;
- s->d1->r_msg_hdr.msg_len = msg_len;
- s->s3->tmp.message_type = msg_hdr->type;
- s->d1->r_msg_hdr.type = msg_hdr->type;
- s->d1->r_msg_hdr.seq = msg_hdr->seq;
- }
- else if (msg_len != s->d1->r_msg_hdr.msg_len)
- {
- /* They must be playing with us! BTW, failure to enforce
- * upper limit would open possibility for buffer overrun. */
- SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
- return SSL_AD_ILLEGAL_PARAMETER;
- }
-
- return 0; /* no error */
- }
-
-
-static int
-dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
- {
- /* (0) check whether the desired fragment is available
- * if so:
- * (1) copy over the fragment to s->init_buf->data[]
- * (2) update s->init_num
- */
- pitem *item;
- hm_fragment *frag;
- int al;
-
- *ok = 0;
- item = pqueue_peek(s->d1->buffered_messages);
- if ( item == NULL)
- return 0;
-
- frag = (hm_fragment *)item->data;
-
- /* Don't return if reassembly still in progress */
- if (frag->reassembly != NULL)
- return 0;
-
- if ( s->d1->handshake_read_seq == frag->msg_header.seq)
- {
- unsigned long frag_len = frag->msg_header.frag_len;
- pqueue_pop(s->d1->buffered_messages);
-
- al=dtls1_preprocess_fragment(s,&frag->msg_header,max);
-
- if (al==0) /* no alert */
- {
- unsigned char *p = (unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
- memcpy(&p[frag->msg_header.frag_off],
- frag->fragment,frag->msg_header.frag_len);
- }
-
- dtls1_hm_fragment_free(frag);
- pitem_free(item);
-
- if (al==0)
- {
- *ok = 1;
- return frag_len;
- }
-
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- s->init_num = 0;
- *ok = 0;
- return -1;
- }
- else
- return 0;
- }
-
-
-static int
-dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
- {
- hm_fragment *frag = NULL;
- pitem *item = NULL;
- int i = -1, is_complete;
- unsigned char seq64be[8];
- unsigned long frag_len = msg_hdr->frag_len, max_len;
-
- if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
- goto err;
-
- /* Determine maximum allowed message size. Depends on (user set)
- * maximum certificate length, but 16k is minimum.
- */
- if (DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH < s->max_cert_list)
- max_len = s->max_cert_list;
- else
- max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
-
- if ((msg_hdr->frag_off+frag_len) > max_len)
- goto err;
-
- /* Try to find item in queue */
- memset(seq64be,0,sizeof(seq64be));
- seq64be[6] = (unsigned char) (msg_hdr->seq>>8);
- seq64be[7] = (unsigned char) msg_hdr->seq;
- item = pqueue_find(s->d1->buffered_messages, seq64be);
-
- if (item == NULL)
- {
- frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1);
- if ( frag == NULL)
- goto err;
- memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
- frag->msg_header.frag_len = frag->msg_header.msg_len;
- frag->msg_header.frag_off = 0;
- }
- else
- frag = (hm_fragment*) item->data;
-
- /* If message is already reassembled, this must be a
- * retransmit and can be dropped.
- */
- if (frag->reassembly == NULL)
- {
- unsigned char devnull [256];
-
- while (frag_len)
- {
- i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
- devnull,
- frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
- if (i<=0) goto err;
- frag_len -= i;
- }
- return DTLS1_HM_FRAGMENT_RETRY;
- }
-
- /* read the body of the fragment (header has already been read */
- i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
- frag->fragment + msg_hdr->frag_off,frag_len,0);
- if (i<=0 || (unsigned long)i!=frag_len)
- goto err;
-
- RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off,
- (long)(msg_hdr->frag_off + frag_len));
-
- RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len,
- is_complete);
-
- if (is_complete)
- {
- OPENSSL_free(frag->reassembly);
- frag->reassembly = NULL;
- }
-
- if (item == NULL)
- {
- memset(seq64be,0,sizeof(seq64be));
- seq64be[6] = (unsigned char)(msg_hdr->seq>>8);
- seq64be[7] = (unsigned char)(msg_hdr->seq);
-
- item = pitem_new(seq64be, frag);
- if (item == NULL)
- {
- goto err;
- i = -1;
- }
-
- pqueue_insert(s->d1->buffered_messages, item);
- }
-
- return DTLS1_HM_FRAGMENT_RETRY;
-
-err:
- if (frag != NULL) dtls1_hm_fragment_free(frag);
- if (item != NULL) OPENSSL_free(item);
- *ok = 0;
- return i;
- }
-
-
-static int
-dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
-{
- int i=-1;
- hm_fragment *frag = NULL;
- pitem *item = NULL;
- unsigned char seq64be[8];
- unsigned long frag_len = msg_hdr->frag_len;
-
- if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
- goto err;
-
- /* Try to find item in queue, to prevent duplicate entries */
- memset(seq64be,0,sizeof(seq64be));
- seq64be[6] = (unsigned char) (msg_hdr->seq>>8);
- seq64be[7] = (unsigned char) msg_hdr->seq;
- item = pqueue_find(s->d1->buffered_messages, seq64be);
-
- /* If we already have an entry and this one is a fragment,
- * don't discard it and rather try to reassemble it.
- */
- if (item != NULL && frag_len < msg_hdr->msg_len)
- item = NULL;
-
- /* Discard the message if sequence number was already there, is
- * too far in the future, already in the queue or if we received
- * a FINISHED before the SERVER_HELLO, which then must be a stale
- * retransmit.
- */
- if (msg_hdr->seq <= s->d1->handshake_read_seq ||
- msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL ||
- (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED))
- {
- unsigned char devnull [256];
-
- while (frag_len)
- {
- i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
- devnull,
- frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
- if (i<=0) goto err;
- frag_len -= i;
- }
- }
- else
- {
- if (frag_len && frag_len < msg_hdr->msg_len)
- return dtls1_reassemble_fragment(s, msg_hdr, ok);
-
- frag = dtls1_hm_fragment_new(frag_len, 0);
- if ( frag == NULL)
- goto err;
-
- memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
-
- if (frag_len)
- {
- /* read the body of the fragment (header has already been read */
- i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
- frag->fragment,frag_len,0);
- if (i<=0 || (unsigned long)i!=frag_len)
- goto err;
- }
-
- memset(seq64be,0,sizeof(seq64be));
- seq64be[6] = (unsigned char)(msg_hdr->seq>>8);
- seq64be[7] = (unsigned char)(msg_hdr->seq);
-
- item = pitem_new(seq64be, frag);
- if ( item == NULL)
- goto err;
-
- pqueue_insert(s->d1->buffered_messages, item);
- }
-
- return DTLS1_HM_FRAGMENT_RETRY;
-
-err:
- if ( frag != NULL) dtls1_hm_fragment_free(frag);
- if ( item != NULL) OPENSSL_free(item);
- *ok = 0;
- return i;
- }
-
-
-static long
-dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
- {
- unsigned char wire[DTLS1_HM_HEADER_LENGTH];
- unsigned long len, frag_off, frag_len;
- int i,al;
- struct hm_header_st msg_hdr;
-
- /* see if we have the required fragment already */
- if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok)
- {
- if (*ok) s->init_num = frag_len;
- return frag_len;
- }
-
- /* read handshake message header */
- i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,wire,
- DTLS1_HM_HEADER_LENGTH, 0);
- if (i <= 0) /* nbio, or an error */
- {
- s->rwstate=SSL_READING;
- *ok = 0;
- return i;
- }
- /* Handshake fails if message header is incomplete */
- if (i != DTLS1_HM_HEADER_LENGTH)
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
- goto f_err;
- }
-
- /* parse the message fragment header */
- dtls1_get_message_header(wire, &msg_hdr);
-
- /*
- * if this is a future (or stale) message it gets buffered
- * (or dropped)--no further processing at this time
- * While listening, we accept seq 1 (ClientHello with cookie)
- * although we're still expecting seq 0 (ClientHello)
- */
- if (msg_hdr.seq != s->d1->handshake_read_seq && !(s->d1->listen && msg_hdr.seq == 1))
- return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
-
- len = msg_hdr.msg_len;
- frag_off = msg_hdr.frag_off;
- frag_len = msg_hdr.frag_len;
-
- if (frag_len && frag_len < len)
- return dtls1_reassemble_fragment(s, &msg_hdr, ok);
-
- if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
- wire[0] == SSL3_MT_HELLO_REQUEST)
- {
- /* The server may always send 'Hello Request' messages --
- * we are doing a handshake anyway now, so ignore them
- * if their format is correct. Does not count for
- * 'Finished' MAC. */
- if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0)
- {
- if (s->msg_callback)
- s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
- wire, DTLS1_HM_HEADER_LENGTH, s,
- s->msg_callback_arg);
-
- s->init_num = 0;
- return dtls1_get_message_fragment(s, st1, stn,
- max, ok);
- }
- else /* Incorrectly formated Hello request */
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
- goto f_err;
- }
- }
-
- if ((al=dtls1_preprocess_fragment(s,&msg_hdr,max)))
- goto f_err;
-
- /* XDTLS: ressurect this when restart is in place */
- s->state=stn;
-
- if ( frag_len > 0)
- {
- unsigned char *p=(unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
-
- i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
- &p[frag_off],frag_len,0);
- /* XDTLS: fix this--message fragments cannot span multiple packets */
- if (i <= 0)
- {
- s->rwstate=SSL_READING;
- *ok = 0;
- return i;
- }
- }
- else
- i = 0;
-
- /* XDTLS: an incorrectly formatted fragment should cause the
- * handshake to fail */
- if (i != (int)frag_len)
- {
- al=SSL3_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL3_AD_ILLEGAL_PARAMETER);
- goto f_err;
- }
-
- *ok = 1;
-
- /* Note that s->init_num is *not* used as current offset in
- * s->init_buf->data, but as a counter summing up fragments'
- * lengths: as soon as they sum up to handshake packet
- * length, we assume we have got all the fragments. */
- s->init_num = frag_len;
- return frag_len;
-
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- s->init_num = 0;
-
- *ok=0;
- return(-1);
- }
-
-int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen)
- {
- unsigned char *p,*d;
- int i;
- unsigned long l;
-
- if (s->state == a)
- {
- d=(unsigned char *)s->init_buf->data;
- p= &(d[DTLS1_HM_HEADER_LENGTH]);
-
- i=s->method->ssl3_enc->final_finish_mac(s,
- sender,slen,s->s3->tmp.finish_md);
- s->s3->tmp.finish_md_len = i;
- memcpy(p, s->s3->tmp.finish_md, i);
- p+=i;
- l=i;
-
- /* Copy the finished so we can use it for
- * renegotiation checks
- */
- if(s->type == SSL_ST_CONNECT)
- {
- OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
- memcpy(s->s3->previous_client_finished,
- s->s3->tmp.finish_md, i);
- s->s3->previous_client_finished_len=i;
- }
- else
- {
- OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
- memcpy(s->s3->previous_server_finished,
- s->s3->tmp.finish_md, i);
- s->s3->previous_server_finished_len=i;
- }
-
-#ifdef OPENSSL_SYS_WIN16
- /* MSVC 1.5 does not clear the top bytes of the word unless
- * I do this.
- */
- l&=0xffff;
-#endif
-
- d = dtls1_set_message_header(s, d, SSL3_MT_FINISHED, l, 0, l);
- s->init_num=(int)l+DTLS1_HM_HEADER_LENGTH;
- s->init_off=0;
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
-
- s->state=b;
- }
-
- /* SSL3_ST_SEND_xxxxxx_HELLO_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-/* for these 2 messages, we need to
- * ssl->enc_read_ctx re-init
- * ssl->s3->read_sequence zero
- * ssl->s3->read_mac_secret re-init
- * ssl->session->read_sym_enc assign
- * ssl->session->read_compression assign
- * ssl->session->read_hash assign
- */
-int dtls1_send_change_cipher_spec(SSL *s, int a, int b)
- {
- unsigned char *p;
-
- if (s->state == a)
- {
- p=(unsigned char *)s->init_buf->data;
- *p++=SSL3_MT_CCS;
- s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
- s->init_num=DTLS1_CCS_HEADER_LENGTH;
-
- if (s->version == DTLS1_BAD_VER) {
- s->d1->next_handshake_write_seq++;
- s2n(s->d1->handshake_write_seq,p);
- s->init_num+=2;
- }
-
- s->init_off=0;
-
- dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
- s->d1->handshake_write_seq, 0, 0);
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 1);
-
- s->state=b;
- }
-
- /* SSL3_ST_CW_CHANGE_B */
- return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
- }
-
-static int dtls1_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x)
- {
- int n;
- unsigned char *p;
-
- n=i2d_X509(x,NULL);
- if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3)))
- {
- SSLerr(SSL_F_DTLS1_ADD_CERT_TO_BUF,ERR_R_BUF_LIB);
- return 0;
- }
- p=(unsigned char *)&(buf->data[*l]);
- l2n3(n,p);
- i2d_X509(x,&p);
- *l+=n+3;
-
- return 1;
- }
-unsigned long dtls1_output_cert_chain(SSL *s, X509 *x)
- {
- unsigned char *p;
- int i;
- unsigned long l= 3 + DTLS1_HM_HEADER_LENGTH;
- BUF_MEM *buf;
-
- /* TLSv1 sends a chain with nothing in it, instead of an alert */
- buf=s->init_buf;
- if (!BUF_MEM_grow_clean(buf,10))
- {
- SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
- return(0);
- }
- if (x != NULL)
- {
- X509_STORE_CTX xs_ctx;
-
- if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL))
- {
- SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB);
- return(0);
- }
-
- X509_verify_cert(&xs_ctx);
- /* Don't leave errors in the queue */
- ERR_clear_error();
- for (i=0; i < sk_X509_num(xs_ctx.chain); i++)
- {
- x = sk_X509_value(xs_ctx.chain, i);
-
- if (!dtls1_add_cert_to_buf(buf, &l, x))
- {
- X509_STORE_CTX_cleanup(&xs_ctx);
- return 0;
- }
- }
- X509_STORE_CTX_cleanup(&xs_ctx);
- }
- /* Thawte special :-) */
- for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++)
- {
- x=sk_X509_value(s->ctx->extra_certs,i);
- if (!dtls1_add_cert_to_buf(buf, &l, x))
- return 0;
- }
-
- l-= (3 + DTLS1_HM_HEADER_LENGTH);
-
- p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]);
- l2n3(l,p);
- l+=3;
- p=(unsigned char *)&(buf->data[0]);
- p = dtls1_set_message_header(s, p, SSL3_MT_CERTIFICATE, l, 0, l);
-
- l+=DTLS1_HM_HEADER_LENGTH;
- return(l);
- }
-
-int dtls1_read_failed(SSL *s, int code)
- {
- if ( code > 0)
- {
- fprintf( stderr, "invalid state reached %s:%d", __FILE__, __LINE__);
- return 1;
- }
-
- if (!dtls1_is_timer_expired(s))
- {
- /* not a timeout, none of our business,
- let higher layers handle this. in fact it's probably an error */
- return code;
- }
-
-#ifndef OPENSSL_NO_HEARTBEATS
- if (!SSL_in_init(s) && !s->tlsext_hb_pending) /* done, no need to send a retransmit */
-#else
- if (!SSL_in_init(s)) /* done, no need to send a retransmit */
-#endif
- {
- BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
- return code;
- }
-
-#if 0 /* for now, each alert contains only one record number */
- item = pqueue_peek(state->rcvd_records);
- if ( item )
- {
- /* send an alert immediately for all the missing records */
- }
- else
-#endif
-
-#if 0 /* no more alert sending, just retransmit the last set of messages */
- if ( state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT)
- ssl3_send_alert(s,SSL3_AL_WARNING,
- DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
-#endif
-
- return dtls1_handle_timeout(s);
- }
-
-int
-dtls1_get_queue_priority(unsigned short seq, int is_ccs)
- {
- /* The index of the retransmission queue actually is the message sequence number,
- * since the queue only contains messages of a single handshake. However, the
- * ChangeCipherSpec has no message sequence number and so using only the sequence
- * will result in the CCS and Finished having the same index. To prevent this,
- * the sequence number is multiplied by 2. In case of a CCS 1 is subtracted.
- * This does not only differ CSS and Finished, it also maintains the order of the
- * index (important for priority queues) and fits in the unsigned short variable.
- */
- return seq * 2 - is_ccs;
- }
-
-int
-dtls1_retransmit_buffered_messages(SSL *s)
- {
- pqueue sent = s->d1->sent_messages;
- piterator iter;
- pitem *item;
- hm_fragment *frag;
- int found = 0;
-
- iter = pqueue_iterator(sent);
-
- for ( item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter))
- {
- frag = (hm_fragment *)item->data;
- if ( dtls1_retransmit_message(s,
- (unsigned short)dtls1_get_queue_priority(frag->msg_header.seq, frag->msg_header.is_ccs),
- 0, &found) <= 0 && found)
- {
- fprintf(stderr, "dtls1_retransmit_message() failed\n");
- return -1;
- }
- }
-
- return 1;
- }
-
-int
-dtls1_buffer_message(SSL *s, int is_ccs)
- {
- pitem *item;
- hm_fragment *frag;
- unsigned char seq64be[8];
-
- /* this function is called immediately after a message has
- * been serialized */
- OPENSSL_assert(s->init_off == 0);
-
- frag = dtls1_hm_fragment_new(s->init_num, 0);
-
- memcpy(frag->fragment, s->init_buf->data, s->init_num);
-
- if ( is_ccs)
- {
- OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
- ((s->version==DTLS1_VERSION)?DTLS1_CCS_HEADER_LENGTH:3) == (unsigned int)s->init_num);
- }
- else
- {
- OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
- DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num);
- }
-
- frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len;
- frag->msg_header.seq = s->d1->w_msg_hdr.seq;
- frag->msg_header.type = s->d1->w_msg_hdr.type;
- frag->msg_header.frag_off = 0;
- frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
- frag->msg_header.is_ccs = is_ccs;
-
- /* save current state*/
- frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx;
- frag->msg_header.saved_retransmit_state.write_hash = s->write_hash;
- frag->msg_header.saved_retransmit_state.compress = s->compress;
- frag->msg_header.saved_retransmit_state.session = s->session;
- frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch;
-
- memset(seq64be,0,sizeof(seq64be));
- seq64be[6] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq,
- frag->msg_header.is_ccs)>>8);
- seq64be[7] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq,
- frag->msg_header.is_ccs));
-
- item = pitem_new(seq64be, frag);
- if ( item == NULL)
- {
- dtls1_hm_fragment_free(frag);
- return 0;
- }
-
-#if 0
- fprintf( stderr, "buffered messge: \ttype = %xx\n", msg_buf->type);
- fprintf( stderr, "\t\t\t\t\tlen = %d\n", msg_buf->len);
- fprintf( stderr, "\t\t\t\t\tseq_num = %d\n", msg_buf->seq_num);
-#endif
-
- pqueue_insert(s->d1->sent_messages, item);
- return 1;
- }
-
-int
-dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
- int *found)
- {
- int ret;
- /* XDTLS: for now assuming that read/writes are blocking */
- pitem *item;
- hm_fragment *frag ;
- unsigned long header_length;
- unsigned char seq64be[8];
- struct dtls1_retransmit_state saved_state;
- unsigned char save_write_sequence[8];
-
- /*
- OPENSSL_assert(s->init_num == 0);
- OPENSSL_assert(s->init_off == 0);
- */
-
- /* XDTLS: the requested message ought to be found, otherwise error */
- memset(seq64be,0,sizeof(seq64be));
- seq64be[6] = (unsigned char)(seq>>8);
- seq64be[7] = (unsigned char)seq;
-
- item = pqueue_find(s->d1->sent_messages, seq64be);
- if ( item == NULL)
- {
- fprintf(stderr, "retransmit: message %d non-existant\n", seq);
- *found = 0;
- return 0;
- }
-
- *found = 1;
- frag = (hm_fragment *)item->data;
-
- if ( frag->msg_header.is_ccs)
- header_length = DTLS1_CCS_HEADER_LENGTH;
- else
- header_length = DTLS1_HM_HEADER_LENGTH;
-
- memcpy(s->init_buf->data, frag->fragment,
- frag->msg_header.msg_len + header_length);
- s->init_num = frag->msg_header.msg_len + header_length;
-
- dtls1_set_message_header_int(s, frag->msg_header.type,
- frag->msg_header.msg_len, frag->msg_header.seq, 0,
- frag->msg_header.frag_len);
-
- /* save current state */
- saved_state.enc_write_ctx = s->enc_write_ctx;
- saved_state.write_hash = s->write_hash;
- saved_state.compress = s->compress;
- saved_state.session = s->session;
- saved_state.epoch = s->d1->w_epoch;
- saved_state.epoch = s->d1->w_epoch;
-
- s->d1->retransmitting = 1;
-
- /* restore state in which the message was originally sent */
- s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx;
- s->write_hash = frag->msg_header.saved_retransmit_state.write_hash;
- s->compress = frag->msg_header.saved_retransmit_state.compress;
- s->session = frag->msg_header.saved_retransmit_state.session;
- s->d1->w_epoch = frag->msg_header.saved_retransmit_state.epoch;
-
- if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1)
- {
- memcpy(save_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence));
- memcpy(s->s3->write_sequence, s->d1->last_write_sequence, sizeof(s->s3->write_sequence));
- }
-
- ret = dtls1_do_write(s, frag->msg_header.is_ccs ?
- SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
-
- /* restore current state */
- s->enc_write_ctx = saved_state.enc_write_ctx;
- s->write_hash = saved_state.write_hash;
- s->compress = saved_state.compress;
- s->session = saved_state.session;
- s->d1->w_epoch = saved_state.epoch;
-
- if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1)
- {
- memcpy(s->d1->last_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence));
- memcpy(s->s3->write_sequence, save_write_sequence, sizeof(s->s3->write_sequence));
- }
-
- s->d1->retransmitting = 0;
-
- (void)BIO_flush(SSL_get_wbio(s));
- return ret;
- }
-
-/* call this function when the buffered messages are no longer needed */
-void
-dtls1_clear_record_buffer(SSL *s)
- {
- pitem *item;
-
- for(item = pqueue_pop(s->d1->sent_messages);
- item != NULL; item = pqueue_pop(s->d1->sent_messages))
- {
- dtls1_hm_fragment_free((hm_fragment *)item->data);
- pitem_free(item);
- }
- }
-
-
-unsigned char *
-dtls1_set_message_header(SSL *s, unsigned char *p, unsigned char mt,
- unsigned long len, unsigned long frag_off, unsigned long frag_len)
- {
- /* Don't change sequence numbers while listening */
- if (frag_off == 0 && !s->d1->listen)
- {
- s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
- s->d1->next_handshake_write_seq++;
- }
-
- dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq,
- frag_off, frag_len);
-
- return p += DTLS1_HM_HEADER_LENGTH;
- }
-
-
-/* don't actually do the writing, wait till the MTU has been retrieved */
-static void
-dtls1_set_message_header_int(SSL *s, unsigned char mt,
- unsigned long len, unsigned short seq_num, unsigned long frag_off,
- unsigned long frag_len)
- {
- struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
-
- msg_hdr->type = mt;
- msg_hdr->msg_len = len;
- msg_hdr->seq = seq_num;
- msg_hdr->frag_off = frag_off;
- msg_hdr->frag_len = frag_len;
- }
-
-static void
-dtls1_fix_message_header(SSL *s, unsigned long frag_off,
- unsigned long frag_len)
- {
- struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
-
- msg_hdr->frag_off = frag_off;
- msg_hdr->frag_len = frag_len;
- }
-
-static unsigned char *
-dtls1_write_message_header(SSL *s, unsigned char *p)
- {
- struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
-
- *p++ = msg_hdr->type;
- l2n3(msg_hdr->msg_len, p);
-
- s2n(msg_hdr->seq, p);
- l2n3(msg_hdr->frag_off, p);
- l2n3(msg_hdr->frag_len, p);
-
- return p;
- }
-
-unsigned int
-dtls1_min_mtu(void)
- {
- return (g_probable_mtu[(sizeof(g_probable_mtu) /
- sizeof(g_probable_mtu[0])) - 1]);
- }
-
-static unsigned int
-dtls1_guess_mtu(unsigned int curr_mtu)
- {
- unsigned int i;
-
- if ( curr_mtu == 0 )
- return g_probable_mtu[0] ;
-
- for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++)
- if ( curr_mtu > g_probable_mtu[i])
- return g_probable_mtu[i];
-
- return curr_mtu;
- }
-
-void
-dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
- {
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
- msg_hdr->type = *(data++);
- n2l3(data, msg_hdr->msg_len);
-
- n2s(data, msg_hdr->seq);
- n2l3(data, msg_hdr->frag_off);
- n2l3(data, msg_hdr->frag_len);
- }
-
-void
-dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr)
- {
- memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st));
-
- ccs_hdr->type = *(data++);
- }
-
-int dtls1_shutdown(SSL *s)
- {
- int ret;
-#ifndef OPENSSL_NO_SCTP
- if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
- !(s->shutdown & SSL_SENT_SHUTDOWN))
- {
- ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
- if (ret < 0) return -1;
-
- if (ret == 0)
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1, NULL);
- }
-#endif
- ret = ssl3_shutdown(s);
-#ifndef OPENSSL_NO_SCTP
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
-#endif
- return ret;
- }
-
-#ifndef OPENSSL_NO_HEARTBEATS
-int
-dtls1_process_heartbeat(SSL *s)
- {
- unsigned char *p = &s->s3->rrec.data[0], *pl;
- unsigned short hbtype;
- unsigned int payload;
- unsigned int padding = 16; /* Use minimum padding */
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
- &s->s3->rrec.data[0], s->s3->rrec.length,
- s, s->msg_callback_arg);
-
- /* Read type and payload length first */
- if (1 + 2 + 16 > s->s3->rrec.length)
- return 0; /* silently discard */
- hbtype = *p++;
- n2s(p, payload);
- if (1 + 2 + payload + 16 > s->s3->rrec.length)
- return 0; /* silently discard per RFC 6520 sec. 4 */
- pl = p;
-
- if (hbtype == TLS1_HB_REQUEST)
- {
- unsigned char *buffer, *bp;
- unsigned int write_length = 1 /* heartbeat type */ +
- 2 /* heartbeat length */ +
- payload + padding;
- int r;
-
- if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
- return 0;
-
- /* Allocate memory for the response, size is 1 byte
- * message type, plus 2 bytes payload length, plus
- * payload, plus padding
- */
- buffer = OPENSSL_malloc(write_length);
- bp = buffer;
-
- /* Enter response type, length and copy payload */
- *bp++ = TLS1_HB_RESPONSE;
- s2n(payload, bp);
- memcpy(bp, pl, payload);
- bp += payload;
- /* Random padding */
- RAND_pseudo_bytes(bp, padding);
-
- r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
-
- if (r >= 0 && s->msg_callback)
- s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
- buffer, write_length,
- s, s->msg_callback_arg);
-
- OPENSSL_free(buffer);
-
- if (r < 0)
- return r;
- }
- else if (hbtype == TLS1_HB_RESPONSE)
- {
- unsigned int seq;
-
- /* We only send sequence numbers (2 bytes unsigned int),
- * and 16 random bytes, so we just try to read the
- * sequence number */
- n2s(pl, seq);
-
- if (payload == 18 && seq == s->tlsext_hb_seq)
- {
- dtls1_stop_timer(s);
- s->tlsext_hb_seq++;
- s->tlsext_hb_pending = 0;
- }
- }
-
- return 0;
- }
-
-int
-dtls1_heartbeat(SSL *s)
- {
- unsigned char *buf, *p;
- int ret;
- unsigned int payload = 18; /* Sequence number + random bytes */
- unsigned int padding = 16; /* Use minimum padding */
-
- /* Only send if peer supports and accepts HB requests... */
- if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
- s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS)
- {
- SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
- return -1;
- }
-
- /* ...and there is none in flight yet... */
- if (s->tlsext_hb_pending)
- {
- SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING);
- return -1;
- }
-
- /* ...and no handshake in progress. */
- if (SSL_in_init(s) || s->in_handshake)
- {
- SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- /* Check if padding is too long, payload and padding
- * must not exceed 2^14 - 3 = 16381 bytes in total.
- */
- OPENSSL_assert(payload + padding <= 16381);
-
- /* Create HeartBeat message, we just use a sequence number
- * as payload to distuingish different messages and add
- * some random stuff.
- * - Message Type, 1 byte
- * - Payload Length, 2 bytes (unsigned int)
- * - Payload, the sequence number (2 bytes uint)
- * - Payload, random bytes (16 bytes uint)
- * - Padding
- */
- buf = OPENSSL_malloc(1 + 2 + payload + padding);
- p = buf;
- /* Message Type */
- *p++ = TLS1_HB_REQUEST;
- /* Payload length (18 bytes here) */
- s2n(payload, p);
- /* Sequence number */
- s2n(s->tlsext_hb_seq, p);
- /* 16 random bytes */
- RAND_pseudo_bytes(p, 16);
- p += 16;
- /* Random padding */
- RAND_pseudo_bytes(p, padding);
-
- ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
- if (ret >= 0)
- {
- if (s->msg_callback)
- s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
- buf, 3 + payload + padding,
- s, s->msg_callback_arg);
-
- dtls1_start_timer(s);
- s->tlsext_hb_pending = 1;
- }
-
- OPENSSL_free(buf);
-
- return ret;
- }
-#endif
diff --git a/drivers/builtin_openssl/ssl/d1_lib.c b/drivers/builtin_openssl/ssl/d1_lib.c
deleted file mode 100644
index 106939f241..0000000000
--- a/drivers/builtin_openssl/ssl/d1_lib.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/* ssl/d1_lib.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#define USE_SOCKETS
-#include <openssl/objects.h>
-#include "ssl_locl.h"
-
-#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS)
-#include <sys/timeb.h>
-#endif
-
-static void get_current_time(struct timeval *t);
-const char dtls1_version_str[]="DTLSv1" OPENSSL_VERSION_PTEXT;
-int dtls1_listen(SSL *s, struct sockaddr *client);
-
-SSL3_ENC_METHOD DTLSv1_enc_data={
- dtls1_enc,
- tls1_mac,
- tls1_setup_key_block,
- tls1_generate_master_secret,
- tls1_change_cipher_state,
- tls1_final_finish_mac,
- TLS1_FINISH_MAC_LENGTH,
- tls1_cert_verify_mac,
- TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
- TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
- tls1_alert_code,
- tls1_export_keying_material,
- };
-
-long dtls1_default_timeout(void)
- {
- /* 2 hours, the 24 hours mentioned in the DTLSv1 spec
- * is way too long for http, the cache would over fill */
- return(60*60*2);
- }
-
-int dtls1_new(SSL *s)
- {
- DTLS1_STATE *d1;
-
- if (!ssl3_new(s)) return(0);
- if ((d1=OPENSSL_malloc(sizeof *d1)) == NULL) return (0);
- memset(d1,0, sizeof *d1);
-
- /* d1->handshake_epoch=0; */
-
- d1->unprocessed_rcds.q=pqueue_new();
- d1->processed_rcds.q=pqueue_new();
- d1->buffered_messages = pqueue_new();
- d1->sent_messages=pqueue_new();
- d1->buffered_app_data.q=pqueue_new();
-
- if ( s->server)
- {
- d1->cookie_len = sizeof(s->d1->cookie);
- }
-
- if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q
- || ! d1->buffered_messages || ! d1->sent_messages || ! d1->buffered_app_data.q)
- {
- if ( d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q);
- if ( d1->processed_rcds.q) pqueue_free(d1->processed_rcds.q);
- if ( d1->buffered_messages) pqueue_free(d1->buffered_messages);
- if ( d1->sent_messages) pqueue_free(d1->sent_messages);
- if ( d1->buffered_app_data.q) pqueue_free(d1->buffered_app_data.q);
- OPENSSL_free(d1);
- return (0);
- }
-
- s->d1=d1;
- s->method->ssl_clear(s);
- return(1);
- }
-
-static void dtls1_clear_queues(SSL *s)
- {
- pitem *item = NULL;
- hm_fragment *frag = NULL;
- DTLS1_RECORD_DATA *rdata;
-
- while( (item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL)
- {
- rdata = (DTLS1_RECORD_DATA *) item->data;
- if (rdata->rbuf.buf)
- {
- OPENSSL_free(rdata->rbuf.buf);
- }
- OPENSSL_free(item->data);
- pitem_free(item);
- }
-
- while( (item = pqueue_pop(s->d1->processed_rcds.q)) != NULL)
- {
- rdata = (DTLS1_RECORD_DATA *) item->data;
- if (rdata->rbuf.buf)
- {
- OPENSSL_free(rdata->rbuf.buf);
- }
- OPENSSL_free(item->data);
- pitem_free(item);
- }
-
- while( (item = pqueue_pop(s->d1->buffered_messages)) != NULL)
- {
- frag = (hm_fragment *)item->data;
- OPENSSL_free(frag->fragment);
- OPENSSL_free(frag);
- pitem_free(item);
- }
-
- while ( (item = pqueue_pop(s->d1->sent_messages)) != NULL)
- {
- frag = (hm_fragment *)item->data;
- OPENSSL_free(frag->fragment);
- OPENSSL_free(frag);
- pitem_free(item);
- }
-
- while ( (item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL)
- {
- frag = (hm_fragment *)item->data;
- OPENSSL_free(frag->fragment);
- OPENSSL_free(frag);
- pitem_free(item);
- }
- }
-
-void dtls1_free(SSL *s)
- {
- ssl3_free(s);
-
- dtls1_clear_queues(s);
-
- pqueue_free(s->d1->unprocessed_rcds.q);
- pqueue_free(s->d1->processed_rcds.q);
- pqueue_free(s->d1->buffered_messages);
- pqueue_free(s->d1->sent_messages);
- pqueue_free(s->d1->buffered_app_data.q);
-
- OPENSSL_free(s->d1);
- s->d1 = NULL;
- }
-
-void dtls1_clear(SSL *s)
- {
- pqueue unprocessed_rcds;
- pqueue processed_rcds;
- pqueue buffered_messages;
- pqueue sent_messages;
- pqueue buffered_app_data;
- unsigned int mtu;
-
- if (s->d1)
- {
- unprocessed_rcds = s->d1->unprocessed_rcds.q;
- processed_rcds = s->d1->processed_rcds.q;
- buffered_messages = s->d1->buffered_messages;
- sent_messages = s->d1->sent_messages;
- buffered_app_data = s->d1->buffered_app_data.q;
- mtu = s->d1->mtu;
-
- dtls1_clear_queues(s);
-
- memset(s->d1, 0, sizeof(*(s->d1)));
-
- if (s->server)
- {
- s->d1->cookie_len = sizeof(s->d1->cookie);
- }
-
- if (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)
- {
- s->d1->mtu = mtu;
- }
-
- s->d1->unprocessed_rcds.q = unprocessed_rcds;
- s->d1->processed_rcds.q = processed_rcds;
- s->d1->buffered_messages = buffered_messages;
- s->d1->sent_messages = sent_messages;
- s->d1->buffered_app_data.q = buffered_app_data;
- }
-
- ssl3_clear(s);
- if (s->options & SSL_OP_CISCO_ANYCONNECT)
- s->version=DTLS1_BAD_VER;
- else
- s->version=DTLS1_VERSION;
- }
-
-long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
- {
- int ret=0;
-
- switch (cmd)
- {
- case DTLS_CTRL_GET_TIMEOUT:
- if (dtls1_get_timeout(s, (struct timeval*) parg) != NULL)
- {
- ret = 1;
- }
- break;
- case DTLS_CTRL_HANDLE_TIMEOUT:
- ret = dtls1_handle_timeout(s);
- break;
- case DTLS_CTRL_LISTEN:
- ret = dtls1_listen(s, parg);
- break;
-
- default:
- ret = ssl3_ctrl(s, cmd, larg, parg);
- break;
- }
- return(ret);
- }
-
-/*
- * As it's impossible to use stream ciphers in "datagram" mode, this
- * simple filter is designed to disengage them in DTLS. Unfortunately
- * there is no universal way to identify stream SSL_CIPHER, so we have
- * to explicitly list their SSL_* codes. Currently RC4 is the only one
- * available, but if new ones emerge, they will have to be added...
- */
-const SSL_CIPHER *dtls1_get_cipher(unsigned int u)
- {
- const SSL_CIPHER *ciph = ssl3_get_cipher(u);
-
- if (ciph != NULL)
- {
- if (ciph->algorithm_enc == SSL_RC4)
- return NULL;
- }
-
- return ciph;
- }
-
-void dtls1_start_timer(SSL *s)
- {
-#ifndef OPENSSL_NO_SCTP
- /* Disable timer for SCTP */
- if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
- {
- memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
- return;
- }
-#endif
-
- /* If timer is not set, initialize duration with 1 second */
- if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
- {
- s->d1->timeout_duration = 1;
- }
-
- /* Set timeout to current time */
- get_current_time(&(s->d1->next_timeout));
-
- /* Add duration to current time */
- s->d1->next_timeout.tv_sec += s->d1->timeout_duration;
- BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
- }
-
-struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft)
- {
- struct timeval timenow;
-
- /* If no timeout is set, just return NULL */
- if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
- {
- return NULL;
- }
-
- /* Get current time */
- get_current_time(&timenow);
-
- /* If timer already expired, set remaining time to 0 */
- if (s->d1->next_timeout.tv_sec < timenow.tv_sec ||
- (s->d1->next_timeout.tv_sec == timenow.tv_sec &&
- s->d1->next_timeout.tv_usec <= timenow.tv_usec))
- {
- memset(timeleft, 0, sizeof(struct timeval));
- return timeleft;
- }
-
- /* Calculate time left until timer expires */
- memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval));
- timeleft->tv_sec -= timenow.tv_sec;
- timeleft->tv_usec -= timenow.tv_usec;
- if (timeleft->tv_usec < 0)
- {
- timeleft->tv_sec--;
- timeleft->tv_usec += 1000000;
- }
-
- /* If remaining time is less than 15 ms, set it to 0
- * to prevent issues because of small devergences with
- * socket timeouts.
- */
- if (timeleft->tv_sec == 0 && timeleft->tv_usec < 15000)
- {
- memset(timeleft, 0, sizeof(struct timeval));
- }
-
-
- return timeleft;
- }
-
-int dtls1_is_timer_expired(SSL *s)
- {
- struct timeval timeleft;
-
- /* Get time left until timeout, return false if no timer running */
- if (dtls1_get_timeout(s, &timeleft) == NULL)
- {
- return 0;
- }
-
- /* Return false if timer is not expired yet */
- if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0)
- {
- return 0;
- }
-
- /* Timer expired, so return true */
- return 1;
- }
-
-void dtls1_double_timeout(SSL *s)
- {
- s->d1->timeout_duration *= 2;
- if (s->d1->timeout_duration > 60)
- s->d1->timeout_duration = 60;
- dtls1_start_timer(s);
- }
-
-void dtls1_stop_timer(SSL *s)
- {
- /* Reset everything */
- memset(&(s->d1->timeout), 0, sizeof(struct dtls1_timeout_st));
- memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
- s->d1->timeout_duration = 1;
- BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
- /* Clear retransmission buffer */
- dtls1_clear_record_buffer(s);
- }
-
-int dtls1_check_timeout_num(SSL *s)
- {
- s->d1->timeout.num_alerts++;
-
- /* Reduce MTU after 2 unsuccessful retransmissions */
- if (s->d1->timeout.num_alerts > 2)
- {
- s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
- }
-
- if (s->d1->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
- {
- /* fail the connection, enough alerts have been sent */
- SSLerr(SSL_F_DTLS1_CHECK_TIMEOUT_NUM,SSL_R_READ_TIMEOUT_EXPIRED);
- return -1;
- }
-
- return 0;
- }
-
-int dtls1_handle_timeout(SSL *s)
- {
- /* if no timer is expired, don't do anything */
- if (!dtls1_is_timer_expired(s))
- {
- return 0;
- }
-
- dtls1_double_timeout(s);
-
- if (dtls1_check_timeout_num(s) < 0)
- return -1;
-
- s->d1->timeout.read_timeouts++;
- if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT)
- {
- s->d1->timeout.read_timeouts = 1;
- }
-
-#ifndef OPENSSL_NO_HEARTBEATS
- if (s->tlsext_hb_pending)
- {
- s->tlsext_hb_pending = 0;
- return dtls1_heartbeat(s);
- }
-#endif
-
- dtls1_start_timer(s);
- return dtls1_retransmit_buffered_messages(s);
- }
-
-static void get_current_time(struct timeval *t)
-{
-#ifdef OPENSSL_SYS_WIN32
- struct _timeb tb;
- _ftime(&tb);
- t->tv_sec = (long)tb.time;
- t->tv_usec = (long)tb.millitm * 1000;
-#elif defined(OPENSSL_SYS_VMS)
- struct timeb tb;
- ftime(&tb);
- t->tv_sec = (long)tb.time;
- t->tv_usec = (long)tb.millitm * 1000;
-#else
- gettimeofday(t, NULL);
-#endif
-}
-
-int dtls1_listen(SSL *s, struct sockaddr *client)
- {
- int ret;
-
- SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
- s->d1->listen = 1;
-
- ret = SSL_accept(s);
- if (ret <= 0) return ret;
-
- (void) BIO_dgram_get_peer(SSL_get_rbio(s), client);
- return 1;
- }
diff --git a/drivers/builtin_openssl/ssl/d1_pkt.c b/drivers/builtin_openssl/ssl/d1_pkt.c
deleted file mode 100644
index 8186462d4a..0000000000
--- a/drivers/builtin_openssl/ssl/d1_pkt.c
+++ /dev/null
@@ -1,1900 +0,0 @@
-/* ssl/d1_pkt.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1998-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include <errno.h>
-#define USE_SOCKETS
-#include "ssl_locl.h"
-#include <openssl/evp.h>
-#include <openssl/buffer.h>
-#include <openssl/pqueue.h>
-#include <openssl/rand.h>
-
-/* mod 128 saturating subtract of two 64-bit values in big-endian order */
-static int satsub64be(const unsigned char *v1,const unsigned char *v2)
-{ int ret,sat,brw,i;
-
- if (sizeof(long) == 8) do
- { const union { long one; char little; } is_endian = {1};
- long l;
-
- if (is_endian.little) break;
- /* not reached on little-endians */
- /* following test is redundant, because input is
- * always aligned, but I take no chances... */
- if (((size_t)v1|(size_t)v2)&0x7) break;
-
- l = *((long *)v1);
- l -= *((long *)v2);
- if (l>128) return 128;
- else if (l<-128) return -128;
- else return (int)l;
- } while (0);
-
- ret = (int)v1[7]-(int)v2[7];
- sat = 0;
- brw = ret>>8; /* brw is either 0 or -1 */
- if (ret & 0x80)
- { for (i=6;i>=0;i--)
- { brw += (int)v1[i]-(int)v2[i];
- sat |= ~brw;
- brw >>= 8;
- }
- }
- else
- { for (i=6;i>=0;i--)
- { brw += (int)v1[i]-(int)v2[i];
- sat |= brw;
- brw >>= 8;
- }
- }
- brw <<= 8; /* brw is either 0 or -256 */
-
- if (sat&0xff) return brw | 0x80;
- else return brw + (ret&0xFF);
-}
-
-static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
- int len, int peek);
-static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap);
-static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
-static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
- unsigned int *is_next_epoch);
-#if 0
-static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
- unsigned short *priority, unsigned long *offset);
-#endif
-static int dtls1_buffer_record(SSL *s, record_pqueue *q,
- unsigned char *priority);
-static int dtls1_process_record(SSL *s);
-
-/* copy buffered record into SSL structure */
-static int
-dtls1_copy_record(SSL *s, pitem *item)
- {
- DTLS1_RECORD_DATA *rdata;
-
- rdata = (DTLS1_RECORD_DATA *)item->data;
-
- if (s->s3->rbuf.buf != NULL)
- OPENSSL_free(s->s3->rbuf.buf);
-
- s->packet = rdata->packet;
- s->packet_length = rdata->packet_length;
- memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
- memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
-
- /* Set proper sequence number for mac calculation */
- memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6);
-
- return(1);
- }
-
-
-static int
-dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
- {
- DTLS1_RECORD_DATA *rdata;
- pitem *item;
-
- /* Limit the size of the queue to prevent DOS attacks */
- if (pqueue_size(queue->q) >= 100)
- return 0;
-
- rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA));
- item = pitem_new(priority, rdata);
- if (rdata == NULL || item == NULL)
- {
- if (rdata != NULL) OPENSSL_free(rdata);
- if (item != NULL) pitem_free(item);
-
- SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
- return(0);
- }
-
- rdata->packet = s->packet;
- rdata->packet_length = s->packet_length;
- memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER));
- memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD));
-
- item->data = rdata;
-
-#ifndef OPENSSL_NO_SCTP
- /* Store bio_dgram_sctp_rcvinfo struct */
- if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
- (s->state == SSL3_ST_SR_FINISHED_A || s->state == SSL3_ST_CR_FINISHED_A)) {
- BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_GET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
- }
-#endif
-
- /* insert should not fail, since duplicates are dropped */
- if (pqueue_insert(queue->q, item) == NULL)
- {
- OPENSSL_free(rdata);
- pitem_free(item);
- return(0);
- }
-
- s->packet = NULL;
- s->packet_length = 0;
- memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER));
- memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD));
-
- if (!ssl3_setup_buffers(s))
- {
- SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
- OPENSSL_free(rdata);
- pitem_free(item);
- return(0);
- }
-
- return(1);
- }
-
-
-static int
-dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
- {
- pitem *item;
-
- item = pqueue_pop(queue->q);
- if (item)
- {
- dtls1_copy_record(s, item);
-
- OPENSSL_free(item->data);
- pitem_free(item);
-
- return(1);
- }
-
- return(0);
- }
-
-
-/* retrieve a buffered record that belongs to the new epoch, i.e., not processed
- * yet */
-#define dtls1_get_unprocessed_record(s) \
- dtls1_retrieve_buffered_record((s), \
- &((s)->d1->unprocessed_rcds))
-
-/* retrieve a buffered record that belongs to the current epoch, ie, processed */
-#define dtls1_get_processed_record(s) \
- dtls1_retrieve_buffered_record((s), \
- &((s)->d1->processed_rcds))
-
-static int
-dtls1_process_buffered_records(SSL *s)
- {
- pitem *item;
-
- item = pqueue_peek(s->d1->unprocessed_rcds.q);
- if (item)
- {
- /* Check if epoch is current. */
- if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
- return(1); /* Nothing to do. */
-
- /* Process all the records. */
- while (pqueue_peek(s->d1->unprocessed_rcds.q))
- {
- dtls1_get_unprocessed_record(s);
- if ( ! dtls1_process_record(s))
- return(0);
- dtls1_buffer_record(s, &(s->d1->processed_rcds),
- s->s3->rrec.seq_num);
- }
- }
-
- /* sync epoch numbers once all the unprocessed records
- * have been processed */
- s->d1->processed_rcds.epoch = s->d1->r_epoch;
- s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1;
-
- return(1);
- }
-
-
-#if 0
-
-static int
-dtls1_get_buffered_record(SSL *s)
- {
- pitem *item;
- PQ_64BIT priority =
- (((PQ_64BIT)s->d1->handshake_read_seq) << 32) |
- ((PQ_64BIT)s->d1->r_msg_hdr.frag_off);
-
- if ( ! SSL_in_init(s)) /* if we're not (re)negotiating,
- nothing buffered */
- return 0;
-
-
- item = pqueue_peek(s->d1->rcvd_records);
- if (item && item->priority == priority)
- {
- /* Check if we've received the record of interest. It must be
- * a handshake record, since data records as passed up without
- * buffering */
- DTLS1_RECORD_DATA *rdata;
- item = pqueue_pop(s->d1->rcvd_records);
- rdata = (DTLS1_RECORD_DATA *)item->data;
-
- if (s->s3->rbuf.buf != NULL)
- OPENSSL_free(s->s3->rbuf.buf);
-
- s->packet = rdata->packet;
- s->packet_length = rdata->packet_length;
- memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
- memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
-
- OPENSSL_free(item->data);
- pitem_free(item);
-
- /* s->d1->next_expected_seq_num++; */
- return(1);
- }
-
- return 0;
- }
-
-#endif
-
-static int
-dtls1_process_record(SSL *s)
-{
- int i,al;
- int enc_err;
- SSL_SESSION *sess;
- SSL3_RECORD *rr;
- unsigned int mac_size, orig_len;
- unsigned char md[EVP_MAX_MD_SIZE];
-
- rr= &(s->s3->rrec);
- sess = s->session;
-
- /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
- * and we have that many bytes in s->packet
- */
- rr->input= &(s->packet[DTLS1_RT_HEADER_LENGTH]);
-
- /* ok, we can now read from 's->packet' data into 'rr'
- * rr->input points at rr->length bytes, which
- * need to be copied into rr->data by either
- * the decryption or by the decompression
- * When the data is 'copied' into the rr->data buffer,
- * rr->input will be pointed at the new buffer */
-
- /* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
- * rr->length bytes of encrypted compressed stuff. */
-
- /* check is not needed I believe */
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
- {
- al=SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- /* decrypt in place in 'rr->input' */
- rr->data=rr->input;
-
- enc_err = s->method->ssl3_enc->enc(s,0);
- /* enc_err is:
- * 0: (in non-constant time) if the record is publically invalid.
- * 1: if the padding is valid
- * -1: if the padding is invalid */
- if (enc_err == 0)
- {
- /* For DTLS we simply ignore bad packets. */
- rr->length = 0;
- s->packet_length = 0;
- goto err;
- }
-
-#ifdef TLS_DEBUG
-printf("dec %d\n",rr->length);
-{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
-printf("\n");
-#endif
-
- /* r->length is now the compressed data plus mac */
- if ((sess != NULL) &&
- (s->enc_read_ctx != NULL) &&
- (EVP_MD_CTX_md(s->read_hash) != NULL))
- {
- /* s->read_hash != NULL => mac_size != -1 */
- unsigned char *mac = NULL;
- unsigned char mac_tmp[EVP_MAX_MD_SIZE];
- mac_size=EVP_MD_CTX_size(s->read_hash);
- OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
-
- /* kludge: *_cbc_remove_padding passes padding length in rr->type */
- orig_len = rr->length+((unsigned int)rr->type>>8);
-
- /* orig_len is the length of the record before any padding was
- * removed. This is public information, as is the MAC in use,
- * therefore we can safely process the record in a different
- * amount of time if it's too short to possibly contain a MAC.
- */
- if (orig_len < mac_size ||
- /* CBC records must have a padding length byte too. */
- (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
- orig_len < mac_size+1))
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT);
- goto f_err;
- }
-
- if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
- {
- /* We update the length so that the TLS header bytes
- * can be constructed correctly but we need to extract
- * the MAC in constant time from within the record,
- * without leaking the contents of the padding bytes.
- * */
- mac = mac_tmp;
- ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
- rr->length -= mac_size;
- }
- else
- {
- /* In this case there's no padding, so |orig_len|
- * equals |rec->length| and we checked that there's
- * enough bytes for |mac_size| above. */
- rr->length -= mac_size;
- mac = &rr->data[rr->length];
- }
-
- i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
- if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
- enc_err = -1;
- if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
- enc_err = -1;
- }
-
- if (enc_err < 0)
- {
- /* decryption failed, silently discard message */
- rr->length = 0;
- s->packet_length = 0;
- goto err;
- }
-
- /* r->length is now just compressed */
- if (s->expand != NULL)
- {
- if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH)
- {
- al=SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
- goto f_err;
- }
- if (!ssl3_do_uncompress(s))
- {
- al=SSL_AD_DECOMPRESSION_FAILURE;
- SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_BAD_DECOMPRESSION);
- goto f_err;
- }
- }
-
- if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH)
- {
- al=SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- rr->off=0;
- /* So at this point the following is true
- * ssl->s3->rrec.type is the type of record
- * ssl->s3->rrec.length == number of bytes in record
- * ssl->s3->rrec.off == offset to first valid byte
- * ssl->s3->rrec.data == where to take bytes from, increment
- * after use :-).
- */
-
- /* we have pulled in a full packet so zero things */
- s->packet_length=0;
- dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
- return(1);
-
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
- return(0);
-}
-
-
-/* Call this to get a new input record.
- * It will return <= 0 if more data is needed, normally due to an error
- * or non-blocking IO.
- * When it finishes, one packet has been decoded and can be found in
- * ssl->s3->rrec.type - is the type of record
- * ssl->s3->rrec.data, - data
- * ssl->s3->rrec.length, - number of bytes
- */
-/* used only by dtls1_read_bytes */
-int dtls1_get_record(SSL *s)
- {
- int ssl_major,ssl_minor;
- int i,n;
- SSL3_RECORD *rr;
- unsigned char *p = NULL;
- unsigned short version;
- DTLS1_BITMAP *bitmap;
- unsigned int is_next_epoch;
-
- rr= &(s->s3->rrec);
-
- /* The epoch may have changed. If so, process all the
- * pending records. This is a non-blocking operation. */
- dtls1_process_buffered_records(s);
-
- /* if we're renegotiating, then there may be buffered records */
- if (dtls1_get_processed_record(s))
- return 1;
-
- /* get something from the wire */
-again:
- /* check if we have the header */
- if ( (s->rstate != SSL_ST_READ_BODY) ||
- (s->packet_length < DTLS1_RT_HEADER_LENGTH))
- {
- n=ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
- /* read timeout is handled by dtls1_read_bytes */
- if (n <= 0) return(n); /* error or non-blocking */
-
- /* this packet contained a partial record, dump it */
- if (s->packet_length != DTLS1_RT_HEADER_LENGTH)
- {
- s->packet_length = 0;
- goto again;
- }
-
- s->rstate=SSL_ST_READ_BODY;
-
- p=s->packet;
-
- /* Pull apart the header into the DTLS1_RECORD */
- rr->type= *(p++);
- ssl_major= *(p++);
- ssl_minor= *(p++);
- version=(ssl_major<<8)|ssl_minor;
-
- /* sequence number is 64 bits, with top 2 bytes = epoch */
- n2s(p,rr->epoch);
-
- memcpy(&(s->s3->read_sequence[2]), p, 6);
- p+=6;
-
- n2s(p,rr->length);
-
- /* Lets check version */
- if (!s->first_packet)
- {
- if (version != s->version)
- {
- /* unexpected version, silently discard */
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
- }
-
- if ((version & 0xff00) != (s->version & 0xff00))
- {
- /* wrong version, silently discard record */
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
-
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
- {
- /* record too long, silently discard it */
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
-
- /* now s->rstate == SSL_ST_READ_BODY */
- }
-
- /* s->rstate == SSL_ST_READ_BODY, get and decode the data */
-
- if (rr->length > s->packet_length-DTLS1_RT_HEADER_LENGTH)
- {
- /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
- i=rr->length;
- n=ssl3_read_n(s,i,i,1);
- if (n <= 0) return(n); /* error or non-blocking io */
-
- /* this packet contained a partial record, dump it */
- if ( n != i)
- {
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
-
- /* now n == rr->length,
- * and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length */
- }
- s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
-
- /* match epochs. NULL means the packet is dropped on the floor */
- bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
- if ( bitmap == NULL)
- {
- rr->length = 0;
- s->packet_length = 0; /* dump this record */
- goto again; /* get another record */
- }
-
-#ifndef OPENSSL_NO_SCTP
- /* Only do replay check if no SCTP bio */
- if (!BIO_dgram_is_sctp(SSL_get_rbio(s)))
- {
-#endif
- /* Check whether this is a repeat, or aged record.
- * Don't check if we're listening and this message is
- * a ClientHello. They can look as if they're replayed,
- * since they arrive from different connections and
- * would be dropped unnecessarily.
- */
- if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
- *p == SSL3_MT_CLIENT_HELLO) &&
- !dtls1_record_replay_check(s, bitmap))
- {
- rr->length = 0;
- s->packet_length=0; /* dump this record */
- goto again; /* get another record */
- }
-#ifndef OPENSSL_NO_SCTP
- }
-#endif
-
- /* just read a 0 length packet */
- if (rr->length == 0) goto again;
-
- /* If this record is from the next epoch (either HM or ALERT),
- * and a handshake is currently in progress, buffer it since it
- * cannot be processed at this time. However, do not buffer
- * anything while listening.
- */
- if (is_next_epoch)
- {
- if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen)
- {
- dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
- }
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
-
- if (!dtls1_process_record(s))
- {
- rr->length = 0;
- s->packet_length = 0; /* dump this record */
- goto again; /* get another record */
- }
-
- return(1);
-
- }
-
-/* Return up to 'len' payload bytes received in 'type' records.
- * 'type' is one of the following:
- *
- * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
- * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
- * - 0 (during a shutdown, no data has to be returned)
- *
- * If we don't have stored data to work from, read a SSL/TLS record first
- * (possibly multiple records if we still don't have anything to return).
- *
- * This function must handle any surprises the peer may have for us, such as
- * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
- * a surprise, but handled as if it were), or renegotiation requests.
- * Also if record payloads contain fragments too small to process, we store
- * them until there is enough for the respective protocol (the record protocol
- * may use arbitrary fragmentation and even interleaving):
- * Change cipher spec protocol
- * just 1 byte needed, no need for keeping anything stored
- * Alert protocol
- * 2 bytes needed (AlertLevel, AlertDescription)
- * Handshake protocol
- * 4 bytes needed (HandshakeType, uint24 length) -- we just have
- * to detect unexpected Client Hello and Hello Request messages
- * here, anything else is handled by higher layers
- * Application data protocol
- * none of our business
- */
-int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
- {
- int al,i,j,ret;
- unsigned int n;
- SSL3_RECORD *rr;
- void (*cb)(const SSL *ssl,int type2,int val)=NULL;
-
- if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
- if (!ssl3_setup_buffers(s))
- return(-1);
-
- /* XXX: check what the second '&& type' is about */
- if ((type && (type != SSL3_RT_APPLICATION_DATA) &&
- (type != SSL3_RT_HANDSHAKE) && type) ||
- (peek && (type != SSL3_RT_APPLICATION_DATA)))
- {
- SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- /* check whether there's a handshake message (client hello?) waiting */
- if ( (ret = have_handshake_fragment(s, type, buf, len, peek)))
- return ret;
-
- /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
-
-#ifndef OPENSSL_NO_SCTP
- /* Continue handshake if it had to be interrupted to read
- * app data with SCTP.
- */
- if ((!s->in_handshake && SSL_in_init(s)) ||
- (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
- (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK) &&
- s->s3->in_read_app_data != 2))
-#else
- if (!s->in_handshake && SSL_in_init(s))
-#endif
- {
- /* type == SSL3_RT_APPLICATION_DATA */
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return(-1);
- }
- }
-
-start:
- s->rwstate=SSL_NOTHING;
-
- /* s->s3->rrec.type - is the type of record
- * s->s3->rrec.data, - data
- * s->s3->rrec.off, - offset into 'data' for next read
- * s->s3->rrec.length, - number of bytes. */
- rr = &(s->s3->rrec);
-
- /* We are not handshaking and have no data yet,
- * so process data buffered during the last handshake
- * in advance, if any.
- */
- if (s->state == SSL_ST_OK && rr->length == 0)
- {
- pitem *item;
- item = pqueue_pop(s->d1->buffered_app_data.q);
- if (item)
- {
-#ifndef OPENSSL_NO_SCTP
- /* Restore bio_dgram_sctp_rcvinfo struct */
- if (BIO_dgram_is_sctp(SSL_get_rbio(s)))
- {
- DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *) item->data;
- BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
- }
-#endif
-
- dtls1_copy_record(s, item);
-
- OPENSSL_free(item->data);
- pitem_free(item);
- }
- }
-
- /* Check for timeout */
- if (dtls1_handle_timeout(s) > 0)
- goto start;
-
- /* get new packet if necessary */
- if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
- {
- ret=dtls1_get_record(s);
- if (ret <= 0)
- {
- ret = dtls1_read_failed(s, ret);
- /* anything other than a timeout is an error */
- if (ret <= 0)
- return(ret);
- else
- goto start;
- }
- }
-
- if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE)
- {
- rr->length = 0;
- goto start;
- }
-
- /* we now have a packet which can be read and processed */
-
- if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
- * reset by ssl3_get_finished */
- && (rr->type != SSL3_RT_HANDSHAKE))
- {
- /* We now have application data between CCS and Finished.
- * Most likely the packets were reordered on their way, so
- * buffer the application data for later processing rather
- * than dropping the connection.
- */
- dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num);
- rr->length = 0;
- goto start;
- }
-
- /* If the other end has shut down, throw anything we read away
- * (even in 'peek' mode) */
- if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
- {
- rr->length=0;
- s->rwstate=SSL_NOTHING;
- return(0);
- }
-
-
- if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
- {
- /* make sure that we are not getting application data when we
- * are doing a handshake for the first time */
- if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
- (s->enc_read_ctx == NULL))
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE);
- goto f_err;
- }
-
- if (len <= 0) return(len);
-
- if ((unsigned int)len > rr->length)
- n = rr->length;
- else
- n = (unsigned int)len;
-
- memcpy(buf,&(rr->data[rr->off]),n);
- if (!peek)
- {
- rr->length-=n;
- rr->off+=n;
- if (rr->length == 0)
- {
- s->rstate=SSL_ST_READ_HEADER;
- rr->off=0;
- }
- }
-
-#ifndef OPENSSL_NO_SCTP
- /* We were about to renegotiate but had to read
- * belated application data first, so retry.
- */
- if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
- rr->type == SSL3_RT_APPLICATION_DATA &&
- (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK))
- {
- s->rwstate=SSL_READING;
- BIO_clear_retry_flags(SSL_get_rbio(s));
- BIO_set_retry_read(SSL_get_rbio(s));
- }
-
- /* We might had to delay a close_notify alert because
- * of reordered app data. If there was an alert and there
- * is no message to read anymore, finally set shutdown.
- */
- if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
- s->d1->shutdown_received && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
- {
- s->shutdown |= SSL_RECEIVED_SHUTDOWN;
- return(0);
- }
-#endif
- return(n);
- }
-
-
- /* If we get here, then type != rr->type; if we have a handshake
- * message, then it was unexpected (Hello Request or Client Hello). */
-
- /* In case of record types for which we have 'fragment' storage,
- * fill that so that we can process the data at a fixed place.
- */
- {
- unsigned int k, dest_maxlen = 0;
- unsigned char *dest = NULL;
- unsigned int *dest_len = NULL;
-
- if (rr->type == SSL3_RT_HANDSHAKE)
- {
- dest_maxlen = sizeof s->d1->handshake_fragment;
- dest = s->d1->handshake_fragment;
- dest_len = &s->d1->handshake_fragment_len;
- }
- else if (rr->type == SSL3_RT_ALERT)
- {
- dest_maxlen = sizeof(s->d1->alert_fragment);
- dest = s->d1->alert_fragment;
- dest_len = &s->d1->alert_fragment_len;
- }
-#ifndef OPENSSL_NO_HEARTBEATS
- else if (rr->type == TLS1_RT_HEARTBEAT)
- {
- dtls1_process_heartbeat(s);
-
- /* Exit and notify application to read again */
- rr->length = 0;
- s->rwstate=SSL_READING;
- BIO_clear_retry_flags(SSL_get_rbio(s));
- BIO_set_retry_read(SSL_get_rbio(s));
- return(-1);
- }
-#endif
- /* else it's a CCS message, or application data or wrong */
- else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
- {
- /* Application data while renegotiating
- * is allowed. Try again reading.
- */
- if (rr->type == SSL3_RT_APPLICATION_DATA)
- {
- BIO *bio;
- s->s3->in_read_app_data=2;
- bio=SSL_get_rbio(s);
- s->rwstate=SSL_READING;
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return(-1);
- }
-
- /* Not certain if this is the right error handling */
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
- goto f_err;
- }
-
- if (dest_maxlen > 0)
- {
- /* XDTLS: In a pathalogical case, the Client Hello
- * may be fragmented--don't always expect dest_maxlen bytes */
- if ( rr->length < dest_maxlen)
- {
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
- /*
- * for normal alerts rr->length is 2, while
- * dest_maxlen is 7 if we were to handle this
- * non-existing alert...
- */
- FIX ME
-#endif
- s->rstate=SSL_ST_READ_HEADER;
- rr->length = 0;
- goto start;
- }
-
- /* now move 'n' bytes: */
- for ( k = 0; k < dest_maxlen; k++)
- {
- dest[k] = rr->data[rr->off++];
- rr->length--;
- }
- *dest_len = dest_maxlen;
- }
- }
-
- /* s->d1->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE;
- * s->d1->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT.
- * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
-
- /* If we are a client, check for an incoming 'Hello Request': */
- if ((!s->server) &&
- (s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
- (s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
- (s->session != NULL) && (s->session->cipher != NULL))
- {
- s->d1->handshake_fragment_len = 0;
-
- if ((s->d1->handshake_fragment[1] != 0) ||
- (s->d1->handshake_fragment[2] != 0) ||
- (s->d1->handshake_fragment[3] != 0))
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
- goto err;
- }
-
- /* no need to check sequence number on HELLO REQUEST messages */
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
- s->d1->handshake_fragment, 4, s, s->msg_callback_arg);
-
- if (SSL_is_init_finished(s) &&
- !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
- !s->s3->renegotiate)
- {
- s->d1->handshake_read_seq++;
- s->new_session = 1;
- ssl3_renegotiate(s);
- if (ssl3_renegotiate_check(s))
- {
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return(-1);
- }
-
- if (!(s->mode & SSL_MODE_AUTO_RETRY))
- {
- if (s->s3->rbuf.left == 0) /* no read-ahead left? */
- {
- BIO *bio;
- /* In the case where we try to read application data,
- * but we trigger an SSL handshake, we return -1 with
- * the retry option set. Otherwise renegotiation may
- * cause nasty problems in the blocking world */
- s->rwstate=SSL_READING;
- bio=SSL_get_rbio(s);
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return(-1);
- }
- }
- }
- }
- /* we either finished a handshake or ignored the request,
- * now try again to obtain the (application) data we were asked for */
- goto start;
- }
-
- if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH)
- {
- int alert_level = s->d1->alert_fragment[0];
- int alert_descr = s->d1->alert_fragment[1];
-
- s->d1->alert_fragment_len = 0;
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, SSL3_RT_ALERT,
- s->d1->alert_fragment, 2, s, s->msg_callback_arg);
-
- if (s->info_callback != NULL)
- cb=s->info_callback;
- else if (s->ctx->info_callback != NULL)
- cb=s->ctx->info_callback;
-
- if (cb != NULL)
- {
- j = (alert_level << 8) | alert_descr;
- cb(s, SSL_CB_READ_ALERT, j);
- }
-
- if (alert_level == 1) /* warning */
- {
- s->s3->warn_alert = alert_descr;
- if (alert_descr == SSL_AD_CLOSE_NOTIFY)
- {
-#ifndef OPENSSL_NO_SCTP
- /* With SCTP and streams the socket may deliver app data
- * after a close_notify alert. We have to check this
- * first so that nothing gets discarded.
- */
- if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
- BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
- {
- s->d1->shutdown_received = 1;
- s->rwstate=SSL_READING;
- BIO_clear_retry_flags(SSL_get_rbio(s));
- BIO_set_retry_read(SSL_get_rbio(s));
- return -1;
- }
-#endif
- s->shutdown |= SSL_RECEIVED_SHUTDOWN;
- return(0);
- }
-#if 0
- /* XXX: this is a possible improvement in the future */
- /* now check if it's a missing record */
- if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
- {
- unsigned short seq;
- unsigned int frag_off;
- unsigned char *p = &(s->d1->alert_fragment[2]);
-
- n2s(p, seq);
- n2l3(p, frag_off);
-
- dtls1_retransmit_message(s,
- dtls1_get_queue_priority(frag->msg_header.seq, 0),
- frag_off, &found);
- if ( ! found && SSL_in_init(s))
- {
- /* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */
- /* requested a message not yet sent,
- send an alert ourselves */
- ssl3_send_alert(s,SSL3_AL_WARNING,
- DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
- }
- }
-#endif
- }
- else if (alert_level == 2) /* fatal */
- {
- char tmp[16];
-
- s->rwstate=SSL_NOTHING;
- s->s3->fatal_alert = alert_descr;
- SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);
- BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
- ERR_add_error_data(2,"SSL alert number ",tmp);
- s->shutdown|=SSL_RECEIVED_SHUTDOWN;
- SSL_CTX_remove_session(s->ctx,s->session);
- return(0);
- }
- else
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE);
- goto f_err;
- }
-
- goto start;
- }
-
- if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
- {
- s->rwstate=SSL_NOTHING;
- rr->length=0;
- return(0);
- }
-
- if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
- {
- struct ccs_header_st ccs_hdr;
- unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH;
-
- dtls1_get_ccs_header(rr->data, &ccs_hdr);
-
- if (s->version == DTLS1_BAD_VER)
- ccs_hdr_len = 3;
-
- /* 'Change Cipher Spec' is just a single byte, so we know
- * exactly what the record payload has to look like */
- /* XDTLS: check that epoch is consistent */
- if ( (rr->length != ccs_hdr_len) ||
- (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
- {
- i=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
- goto err;
- }
-
- rr->length=0;
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
- rr->data, 1, s, s->msg_callback_arg);
-
- /* We can't process a CCS now, because previous handshake
- * messages are still missing, so just drop it.
- */
- if (!s->d1->change_cipher_spec_ok)
- {
- goto start;
- }
-
- s->d1->change_cipher_spec_ok = 0;
-
- s->s3->change_cipher_spec=1;
- if (!ssl3_do_change_cipher_spec(s))
- goto err;
-
- /* do this whenever CCS is processed */
- dtls1_reset_seq_numbers(s, SSL3_CC_READ);
-
- if (s->version == DTLS1_BAD_VER)
- s->d1->handshake_read_seq++;
-
-#ifndef OPENSSL_NO_SCTP
- /* Remember that a CCS has been received,
- * so that an old key of SCTP-Auth can be
- * deleted when a CCS is sent. Will be ignored
- * if no SCTP is used
- */
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL);
-#endif
-
- goto start;
- }
-
- /* Unexpected handshake message (Client Hello, or protocol violation) */
- if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
- !s->in_handshake)
- {
- struct hm_header_st msg_hdr;
-
- /* this may just be a stale retransmit */
- dtls1_get_message_header(rr->data, &msg_hdr);
- if( rr->epoch != s->d1->r_epoch)
- {
- rr->length = 0;
- goto start;
- }
-
- /* If we are server, we may have a repeated FINISHED of the
- * client here, then retransmit our CCS and FINISHED.
- */
- if (msg_hdr.type == SSL3_MT_FINISHED)
- {
- if (dtls1_check_timeout_num(s) < 0)
- return -1;
-
- dtls1_retransmit_buffered_messages(s);
- rr->length = 0;
- goto start;
- }
-
- if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
- !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
- {
-#if 0 /* worked only because C operator preferences are not as expected (and
- * because this is not really needed for clients except for detecting
- * protocol violations): */
- s->state=SSL_ST_BEFORE|(s->server)
- ?SSL_ST_ACCEPT
- :SSL_ST_CONNECT;
-#else
- s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
-#endif
- s->renegotiate=1;
- s->new_session=1;
- }
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return(-1);
- }
-
- if (!(s->mode & SSL_MODE_AUTO_RETRY))
- {
- if (s->s3->rbuf.left == 0) /* no read-ahead left? */
- {
- BIO *bio;
- /* In the case where we try to read application data,
- * but we trigger an SSL handshake, we return -1 with
- * the retry option set. Otherwise renegotiation may
- * cause nasty problems in the blocking world */
- s->rwstate=SSL_READING;
- bio=SSL_get_rbio(s);
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return(-1);
- }
- }
- goto start;
- }
-
- switch (rr->type)
- {
- default:
-#ifndef OPENSSL_NO_TLS
- /* TLS just ignores unknown message types */
- if (s->version == TLS1_VERSION)
- {
- rr->length = 0;
- goto start;
- }
-#endif
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
- goto f_err;
- case SSL3_RT_CHANGE_CIPHER_SPEC:
- case SSL3_RT_ALERT:
- case SSL3_RT_HANDSHAKE:
- /* we already handled all of these, with the possible exception
- * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that
- * should not happen when type != rr->type */
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_READ_BYTES,ERR_R_INTERNAL_ERROR);
- goto f_err;
- case SSL3_RT_APPLICATION_DATA:
- /* At this point, we were expecting handshake data,
- * but have application data. If the library was
- * running inside ssl3_read() (i.e. in_read_app_data
- * is set) and it makes sense to read application data
- * at this point (session renegotiation not yet started),
- * we will indulge it.
- */
- if (s->s3->in_read_app_data &&
- (s->s3->total_renegotiations != 0) &&
- ((
- (s->state & SSL_ST_CONNECT) &&
- (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
- (s->state <= SSL3_ST_CR_SRVR_HELLO_A)
- ) || (
- (s->state & SSL_ST_ACCEPT) &&
- (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
- (s->state >= SSL3_ST_SR_CLNT_HELLO_A)
- )
- ))
- {
- s->s3->in_read_app_data=2;
- return(-1);
- }
- else
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
- goto f_err;
- }
- }
- /* not reached */
-
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
- return(-1);
- }
-
-int
-dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
- {
- int i;
-
-#ifndef OPENSSL_NO_SCTP
- /* Check if we have to continue an interrupted handshake
- * for reading belated app data with SCTP.
- */
- if ((SSL_in_init(s) && !s->in_handshake) ||
- (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
- (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)))
-#else
- if (SSL_in_init(s) && !s->in_handshake)
-#endif
- {
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
- }
-
- if (len > SSL3_RT_MAX_PLAIN_LENGTH)
- {
- SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_DTLS_MESSAGE_TOO_BIG);
- return -1;
- }
-
- i = dtls1_write_bytes(s, type, buf_, len);
- return i;
- }
-
-
- /* this only happens when a client hello is received and a handshake
- * is started. */
-static int
-have_handshake_fragment(SSL *s, int type, unsigned char *buf,
- int len, int peek)
- {
-
- if ((type == SSL3_RT_HANDSHAKE) && (s->d1->handshake_fragment_len > 0))
- /* (partially) satisfy request from storage */
- {
- unsigned char *src = s->d1->handshake_fragment;
- unsigned char *dst = buf;
- unsigned int k,n;
-
- /* peek == 0 */
- n = 0;
- while ((len > 0) && (s->d1->handshake_fragment_len > 0))
- {
- *dst++ = *src++;
- len--; s->d1->handshake_fragment_len--;
- n++;
- }
- /* move any remaining fragment bytes: */
- for (k = 0; k < s->d1->handshake_fragment_len; k++)
- s->d1->handshake_fragment[k] = *src++;
- return n;
- }
-
- return 0;
- }
-
-
-
-
-/* Call this to write data in records of type 'type'
- * It will return <= 0 if not all data has been sent or non-blocking IO.
- */
-int dtls1_write_bytes(SSL *s, int type, const void *buf, int len)
- {
- int i;
-
- OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH);
- s->rwstate=SSL_NOTHING;
- i=do_dtls1_write(s, type, buf, len, 0);
- return i;
- }
-
-int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment)
- {
- unsigned char *p,*pseq;
- int i,mac_size,clear=0;
- int prefix_len = 0;
- SSL3_RECORD *wr;
- SSL3_BUFFER *wb;
- SSL_SESSION *sess;
- int bs;
-
- /* first check if there is a SSL3_BUFFER still being written
- * out. This will happen with non blocking IO */
- if (s->s3->wbuf.left != 0)
- {
- OPENSSL_assert(0); /* XDTLS: want to see if we ever get here */
- return(ssl3_write_pending(s,type,buf,len));
- }
-
- /* If we have an alert to send, lets send it */
- if (s->s3->alert_dispatch)
- {
- i=s->method->ssl_dispatch_alert(s);
- if (i <= 0)
- return(i);
- /* if it went, fall through and send more stuff */
- }
-
- if (len == 0 && !create_empty_fragment)
- return 0;
-
- wr= &(s->s3->wrec);
- wb= &(s->s3->wbuf);
- sess=s->session;
-
- if ( (sess == NULL) ||
- (s->enc_write_ctx == NULL) ||
- (EVP_MD_CTX_md(s->write_hash) == NULL))
- clear=1;
-
- if (clear)
- mac_size=0;
- else
- {
- mac_size=EVP_MD_CTX_size(s->write_hash);
- if (mac_size < 0)
- goto err;
- }
-
- /* DTLS implements explicit IV, so no need for empty fragments */
-#if 0
- /* 'create_empty_fragment' is true only when this function calls itself */
- if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done
- && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
- {
- /* countermeasure against known-IV weakness in CBC ciphersuites
- * (see http://www.openssl.org/~bodo/tls-cbc.txt)
- */
-
- if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
- {
- /* recursive function call with 'create_empty_fragment' set;
- * this prepares and buffers the data for an empty fragment
- * (these 'prefix_len' bytes are sent out later
- * together with the actual payload) */
- prefix_len = s->method->do_ssl_write(s, type, buf, 0, 1);
- if (prefix_len <= 0)
- goto err;
-
- if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
- {
- /* insufficient space */
- SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- }
-
- s->s3->empty_fragment_done = 1;
- }
-#endif
- p = wb->buf + prefix_len;
-
- /* write the header */
-
- *(p++)=type&0xff;
- wr->type=type;
-
- *(p++)=(s->version>>8);
- *(p++)=s->version&0xff;
-
- /* field where we are to write out packet epoch, seq num and len */
- pseq=p;
- p+=10;
-
- /* lets setup the record stuff. */
-
- /* Make space for the explicit IV in case of CBC.
- * (this is a bit of a boundary violation, but what the heck).
- */
- if ( s->enc_write_ctx &&
- (EVP_CIPHER_mode( s->enc_write_ctx->cipher ) & EVP_CIPH_CBC_MODE))
- bs = EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
- else
- bs = 0;
-
- wr->data=p + bs; /* make room for IV in case of CBC */
- wr->length=(int)len;
- wr->input=(unsigned char *)buf;
-
- /* we now 'read' from wr->input, wr->length bytes into
- * wr->data */
-
- /* first we compress */
- if (s->compress != NULL)
- {
- if (!ssl3_do_compress(s))
- {
- SSLerr(SSL_F_DO_DTLS1_WRITE,SSL_R_COMPRESSION_FAILURE);
- goto err;
- }
- }
- else
- {
- memcpy(wr->data,wr->input,wr->length);
- wr->input=wr->data;
- }
-
- /* we should still have the output to wr->data and the input
- * from wr->input. Length should be wr->length.
- * wr->data still points in the wb->buf */
-
- if (mac_size != 0)
- {
- if(s->method->ssl3_enc->mac(s,&(p[wr->length + bs]),1) < 0)
- goto err;
- wr->length+=mac_size;
- }
-
- /* this is true regardless of mac size */
- wr->input=p;
- wr->data=p;
-
-
- /* ssl3_enc can only have an error on read */
- if (bs) /* bs != 0 in case of CBC */
- {
- RAND_pseudo_bytes(p,bs);
- /* master IV and last CBC residue stand for
- * the rest of randomness */
- wr->length += bs;
- }
-
- s->method->ssl3_enc->enc(s,1);
-
- /* record length after mac and block padding */
-/* if (type == SSL3_RT_APPLICATION_DATA ||
- (type == SSL3_RT_ALERT && ! SSL_in_init(s))) */
-
- /* there's only one epoch between handshake and app data */
-
- s2n(s->d1->w_epoch, pseq);
-
- /* XDTLS: ?? */
-/* else
- s2n(s->d1->handshake_epoch, pseq); */
-
- memcpy(pseq, &(s->s3->write_sequence[2]), 6);
- pseq+=6;
- s2n(wr->length,pseq);
-
- /* we should now have
- * wr->data pointing to the encrypted data, which is
- * wr->length long */
- wr->type=type; /* not needed but helps for debugging */
- wr->length+=DTLS1_RT_HEADER_LENGTH;
-
-#if 0 /* this is now done at the message layer */
- /* buffer the record, making it easy to handle retransmits */
- if ( type == SSL3_RT_HANDSHAKE || type == SSL3_RT_CHANGE_CIPHER_SPEC)
- dtls1_buffer_record(s, wr->data, wr->length,
- *((PQ_64BIT *)&(s->s3->write_sequence[0])));
-#endif
-
- ssl3_record_sequence_update(&(s->s3->write_sequence[0]));
-
- if (create_empty_fragment)
- {
- /* we are in a recursive call;
- * just return the length, don't write out anything here
- */
- return wr->length;
- }
-
- /* now let's set up wb */
- wb->left = prefix_len + wr->length;
- wb->offset = 0;
-
- /* memorize arguments so that ssl3_write_pending can detect bad write retries later */
- s->s3->wpend_tot=len;
- s->s3->wpend_buf=buf;
- s->s3->wpend_type=type;
- s->s3->wpend_ret=len;
-
- /* we now just need to write the buffer */
- return ssl3_write_pending(s,type,buf,len);
-err:
- return -1;
- }
-
-
-
-static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap)
- {
- int cmp;
- unsigned int shift;
- const unsigned char *seq = s->s3->read_sequence;
-
- cmp = satsub64be(seq,bitmap->max_seq_num);
- if (cmp > 0)
- {
- memcpy (s->s3->rrec.seq_num,seq,8);
- return 1; /* this record in new */
- }
- shift = -cmp;
- if (shift >= sizeof(bitmap->map)*8)
- return 0; /* stale, outside the window */
- else if (bitmap->map & (1UL<<shift))
- return 0; /* record previously received */
-
- memcpy (s->s3->rrec.seq_num,seq,8);
- return 1;
- }
-
-
-static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap)
- {
- int cmp;
- unsigned int shift;
- const unsigned char *seq = s->s3->read_sequence;
-
- cmp = satsub64be(seq,bitmap->max_seq_num);
- if (cmp > 0)
- {
- shift = cmp;
- if (shift < sizeof(bitmap->map)*8)
- bitmap->map <<= shift, bitmap->map |= 1UL;
- else
- bitmap->map = 1UL;
- memcpy(bitmap->max_seq_num,seq,8);
- }
- else {
- shift = -cmp;
- if (shift < sizeof(bitmap->map)*8)
- bitmap->map |= 1UL<<shift;
- }
- }
-
-
-int dtls1_dispatch_alert(SSL *s)
- {
- int i,j;
- void (*cb)(const SSL *ssl,int type,int val)=NULL;
- unsigned char buf[DTLS1_AL_HEADER_LENGTH];
- unsigned char *ptr = &buf[0];
-
- s->s3->alert_dispatch=0;
-
- memset(buf, 0x00, sizeof(buf));
- *ptr++ = s->s3->send_alert[0];
- *ptr++ = s->s3->send_alert[1];
-
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
- if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
- {
- s2n(s->d1->handshake_read_seq, ptr);
-#if 0
- if ( s->d1->r_msg_hdr.frag_off == 0) /* waiting for a new msg */
-
- else
- s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */
-#endif
-
-#if 0
- fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n",s->d1->handshake_read_seq,s->d1->r_msg_hdr.seq);
-#endif
- l2n3(s->d1->r_msg_hdr.frag_off, ptr);
- }
-#endif
-
- i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0);
- if (i <= 0)
- {
- s->s3->alert_dispatch=1;
- /* fprintf( stderr, "not done with alert\n" ); */
- }
- else
- {
- if (s->s3->send_alert[0] == SSL3_AL_FATAL
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
- || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
-#endif
- )
- (void)BIO_flush(s->wbio);
-
- if (s->msg_callback)
- s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert,
- 2, s, s->msg_callback_arg);
-
- if (s->info_callback != NULL)
- cb=s->info_callback;
- else if (s->ctx->info_callback != NULL)
- cb=s->ctx->info_callback;
-
- if (cb != NULL)
- {
- j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1];
- cb(s,SSL_CB_WRITE_ALERT,j);
- }
- }
- return(i);
- }
-
-
-static DTLS1_BITMAP *
-dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, unsigned int *is_next_epoch)
- {
-
- *is_next_epoch = 0;
-
- /* In current epoch, accept HM, CCS, DATA, & ALERT */
- if (rr->epoch == s->d1->r_epoch)
- return &s->d1->bitmap;
-
- /* Only HM and ALERT messages can be from the next epoch */
- else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) &&
- (rr->type == SSL3_RT_HANDSHAKE ||
- rr->type == SSL3_RT_ALERT))
- {
- *is_next_epoch = 1;
- return &s->d1->next_bitmap;
- }
-
- return NULL;
- }
-
-#if 0
-static int
-dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, unsigned short *priority,
- unsigned long *offset)
- {
-
- /* alerts are passed up immediately */
- if ( rr->type == SSL3_RT_APPLICATION_DATA ||
- rr->type == SSL3_RT_ALERT)
- return 0;
-
- /* Only need to buffer if a handshake is underway.
- * (this implies that Hello Request and Client Hello are passed up
- * immediately) */
- if ( SSL_in_init(s))
- {
- unsigned char *data = rr->data;
- /* need to extract the HM/CCS sequence number here */
- if ( rr->type == SSL3_RT_HANDSHAKE ||
- rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
- {
- unsigned short seq_num;
- struct hm_header_st msg_hdr;
- struct ccs_header_st ccs_hdr;
-
- if ( rr->type == SSL3_RT_HANDSHAKE)
- {
- dtls1_get_message_header(data, &msg_hdr);
- seq_num = msg_hdr.seq;
- *offset = msg_hdr.frag_off;
- }
- else
- {
- dtls1_get_ccs_header(data, &ccs_hdr);
- seq_num = ccs_hdr.seq;
- *offset = 0;
- }
-
- /* this is either a record we're waiting for, or a
- * retransmit of something we happened to previously
- * receive (higher layers will drop the repeat silently */
- if ( seq_num < s->d1->handshake_read_seq)
- return 0;
- if (rr->type == SSL3_RT_HANDSHAKE &&
- seq_num == s->d1->handshake_read_seq &&
- msg_hdr.frag_off < s->d1->r_msg_hdr.frag_off)
- return 0;
- else if ( seq_num == s->d1->handshake_read_seq &&
- (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC ||
- msg_hdr.frag_off == s->d1->r_msg_hdr.frag_off))
- return 0;
- else
- {
- *priority = seq_num;
- return 1;
- }
- }
- else /* unknown record type */
- return 0;
- }
-
- return 0;
- }
-#endif
-
-void
-dtls1_reset_seq_numbers(SSL *s, int rw)
- {
- unsigned char *seq;
- unsigned int seq_bytes = sizeof(s->s3->read_sequence);
-
- if ( rw & SSL3_CC_READ)
- {
- seq = s->s3->read_sequence;
- s->d1->r_epoch++;
- memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP));
- memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP));
- }
- else
- {
- seq = s->s3->write_sequence;
- memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence));
- s->d1->w_epoch++;
- }
-
- memset(seq, 0x00, seq_bytes);
- }
diff --git a/drivers/builtin_openssl/ssl/d1_srvr.c b/drivers/builtin_openssl/ssl/d1_srvr.c
deleted file mode 100644
index 9975e20873..0000000000
--- a/drivers/builtin_openssl/ssl/d1_srvr.c
+++ /dev/null
@@ -1,1722 +0,0 @@
-/* ssl/d1_srvr.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-#include <openssl/md5.h>
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#endif
-
-static const SSL_METHOD *dtls1_get_server_method(int ver);
-static int dtls1_send_hello_verify_request(SSL *s);
-
-static const SSL_METHOD *dtls1_get_server_method(int ver)
- {
- if (ver == DTLS1_VERSION)
- return(DTLSv1_server_method());
- else
- return(NULL);
- }
-
-IMPLEMENT_dtls1_meth_func(DTLSv1_server_method,
- dtls1_accept,
- ssl_undefined_function,
- dtls1_get_server_method)
-
-int dtls1_accept(SSL *s)
- {
- BUF_MEM *buf;
- unsigned long Time=(unsigned long)time(NULL);
- void (*cb)(const SSL *ssl,int type,int val)=NULL;
- unsigned long alg_k;
- int ret= -1;
- int new_state,state,skip=0;
- int listen;
-#ifndef OPENSSL_NO_SCTP
- unsigned char sctpauthkey[64];
- char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
-#endif
-
- RAND_add(&Time,sizeof(Time),0);
- ERR_clear_error();
- clear_sys_error();
-
- if (s->info_callback != NULL)
- cb=s->info_callback;
- else if (s->ctx->info_callback != NULL)
- cb=s->ctx->info_callback;
-
- listen = s->d1->listen;
-
- /* init things to blank */
- s->in_handshake++;
- if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
-
- s->d1->listen = listen;
-#ifndef OPENSSL_NO_SCTP
- /* Notify SCTP BIO socket to enter handshake
- * mode and prevent stream identifier other
- * than 0. Will be ignored if no SCTP is used.
- */
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
-#endif
-
- if (s->cert == NULL)
- {
- SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
- return(-1);
- }
-
-#ifndef OPENSSL_NO_HEARTBEATS
- /* If we're awaiting a HeartbeatResponse, pretend we
- * already got and don't await it anymore, because
- * Heartbeats don't make sense during handshakes anyway.
- */
- if (s->tlsext_hb_pending)
- {
- dtls1_stop_timer(s);
- s->tlsext_hb_pending = 0;
- s->tlsext_hb_seq++;
- }
-#endif
-
- for (;;)
- {
- state=s->state;
-
- switch (s->state)
- {
- case SSL_ST_RENEGOTIATE:
- s->renegotiate=1;
- /* s->state=SSL_ST_ACCEPT; */
-
- case SSL_ST_BEFORE:
- case SSL_ST_ACCEPT:
- case SSL_ST_BEFORE|SSL_ST_ACCEPT:
- case SSL_ST_OK|SSL_ST_ACCEPT:
-
- s->server=1;
- if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
-
- if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00))
- {
- SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
- return -1;
- }
- s->type=SSL_ST_ACCEPT;
-
- if (s->init_buf == NULL)
- {
- if ((buf=BUF_MEM_new()) == NULL)
- {
- ret= -1;
- goto end;
- }
- if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
- {
- ret= -1;
- goto end;
- }
- s->init_buf=buf;
- }
-
- if (!ssl3_setup_buffers(s))
- {
- ret= -1;
- goto end;
- }
-
- s->init_num=0;
-
- if (s->state != SSL_ST_RENEGOTIATE)
- {
- /* Ok, we now need to push on a buffering BIO so that
- * the output is sent in a way that TCP likes :-)
- * ...but not with SCTP :-)
- */
-#ifndef OPENSSL_NO_SCTP
- if (!BIO_dgram_is_sctp(SSL_get_wbio(s)))
-#endif
- if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }
-
- ssl3_init_finished_mac(s);
- s->state=SSL3_ST_SR_CLNT_HELLO_A;
- s->ctx->stats.sess_accept++;
- }
- else
- {
- /* s->state == SSL_ST_RENEGOTIATE,
- * we will just send a HelloRequest */
- s->ctx->stats.sess_accept_renegotiate++;
- s->state=SSL3_ST_SW_HELLO_REQ_A;
- }
-
- break;
-
- case SSL3_ST_SW_HELLO_REQ_A:
- case SSL3_ST_SW_HELLO_REQ_B:
-
- s->shutdown=0;
- dtls1_clear_record_buffer(s);
- dtls1_start_timer(s);
- ret=dtls1_send_hello_request(s);
- if (ret <= 0) goto end;
- s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
- s->state=SSL3_ST_SW_FLUSH;
- s->init_num=0;
-
- ssl3_init_finished_mac(s);
- break;
-
- case SSL3_ST_SW_HELLO_REQ_C:
- s->state=SSL_ST_OK;
- break;
-
- case SSL3_ST_SR_CLNT_HELLO_A:
- case SSL3_ST_SR_CLNT_HELLO_B:
- case SSL3_ST_SR_CLNT_HELLO_C:
-
- s->shutdown=0;
- ret=ssl3_get_client_hello(s);
- if (ret <= 0) goto end;
- dtls1_stop_timer(s);
-
- if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
- s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
- else
- s->state = SSL3_ST_SW_SRVR_HELLO_A;
-
- s->init_num=0;
-
- /* Reflect ClientHello sequence to remain stateless while listening */
- if (listen)
- {
- memcpy(s->s3->write_sequence, s->s3->read_sequence, sizeof(s->s3->write_sequence));
- }
-
- /* If we're just listening, stop here */
- if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A)
- {
- ret = 2;
- s->d1->listen = 0;
- /* Set expected sequence numbers
- * to continue the handshake.
- */
- s->d1->handshake_read_seq = 2;
- s->d1->handshake_write_seq = 1;
- s->d1->next_handshake_write_seq = 1;
- goto end;
- }
-
- break;
-
- case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
- case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
-
- ret = dtls1_send_hello_verify_request(s);
- if ( ret <= 0) goto end;
- s->state=SSL3_ST_SW_FLUSH;
- s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
-
- /* HelloVerifyRequest resets Finished MAC */
- if (s->version != DTLS1_BAD_VER)
- ssl3_init_finished_mac(s);
- break;
-
-#ifndef OPENSSL_NO_SCTP
- case DTLS1_SCTP_ST_SR_READ_SOCK:
-
- if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
- {
- s->s3->in_read_app_data=2;
- s->rwstate=SSL_READING;
- BIO_clear_retry_flags(SSL_get_rbio(s));
- BIO_set_retry_read(SSL_get_rbio(s));
- ret = -1;
- goto end;
- }
-
- s->state=SSL3_ST_SR_FINISHED_A;
- break;
-
- case DTLS1_SCTP_ST_SW_WRITE_SOCK:
- ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
- if (ret < 0) goto end;
-
- if (ret == 0)
- {
- if (s->d1->next_state != SSL_ST_OK)
- {
- s->s3->in_read_app_data=2;
- s->rwstate=SSL_READING;
- BIO_clear_retry_flags(SSL_get_rbio(s));
- BIO_set_retry_read(SSL_get_rbio(s));
- ret = -1;
- goto end;
- }
- }
-
- s->state=s->d1->next_state;
- break;
-#endif
-
- case SSL3_ST_SW_SRVR_HELLO_A:
- case SSL3_ST_SW_SRVR_HELLO_B:
- s->renegotiate = 2;
- dtls1_start_timer(s);
- ret=dtls1_send_server_hello(s);
- if (ret <= 0) goto end;
-
- if (s->hit)
- {
-#ifndef OPENSSL_NO_SCTP
- /* Add new shared key for SCTP-Auth,
- * will be ignored if no SCTP used.
- */
- snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
- DTLS1_SCTP_AUTH_LABEL);
-
- SSL_export_keying_material(s, sctpauthkey,
- sizeof(sctpauthkey), labelbuffer,
- sizeof(labelbuffer), NULL, 0, 0);
-
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
- sizeof(sctpauthkey), sctpauthkey);
-#endif
-#ifndef OPENSSL_NO_TLSEXT
- if (s->tlsext_ticket_expected)
- s->state=SSL3_ST_SW_SESSION_TICKET_A;
- else
- s->state=SSL3_ST_SW_CHANGE_A;
-#else
- s->state=SSL3_ST_SW_CHANGE_A;
-#endif
- }
- else
- s->state=SSL3_ST_SW_CERT_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_CERT_A:
- case SSL3_ST_SW_CERT_B:
- /* Check if it is anon DH or normal PSK */
- if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
- && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
- {
- dtls1_start_timer(s);
- ret=dtls1_send_server_certificate(s);
- if (ret <= 0) goto end;
-#ifndef OPENSSL_NO_TLSEXT
- if (s->tlsext_status_expected)
- s->state=SSL3_ST_SW_CERT_STATUS_A;
- else
- s->state=SSL3_ST_SW_KEY_EXCH_A;
- }
- else
- {
- skip = 1;
- s->state=SSL3_ST_SW_KEY_EXCH_A;
- }
-#else
- }
- else
- skip=1;
-
- s->state=SSL3_ST_SW_KEY_EXCH_A;
-#endif
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_KEY_EXCH_A:
- case SSL3_ST_SW_KEY_EXCH_B:
- alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
- /* clear this, it may get reset by
- * send_server_key_exchange */
- if ((s->options & SSL_OP_EPHEMERAL_RSA)
-#ifndef OPENSSL_NO_KRB5
- && !(alg_k & SSL_kKRB5)
-#endif /* OPENSSL_NO_KRB5 */
- )
- /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
- * even when forbidden by protocol specs
- * (handshake may fail as clients are not required to
- * be able to handle this) */
- s->s3->tmp.use_rsa_tmp=1;
- else
- s->s3->tmp.use_rsa_tmp=0;
-
- /* only send if a DH key exchange or
- * RSA but we have a sign only certificate */
- if (s->s3->tmp.use_rsa_tmp
- /* PSK: send ServerKeyExchange if PSK identity
- * hint if provided */
-#ifndef OPENSSL_NO_PSK
- || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
-#endif
- || (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
- || (alg_k & SSL_kEECDH)
- || ((alg_k & SSL_kRSA)
- && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
- || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
- && EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
- )
- )
- )
- )
- {
- dtls1_start_timer(s);
- ret=dtls1_send_server_key_exchange(s);
- if (ret <= 0) goto end;
- }
- else
- skip=1;
-
- s->state=SSL3_ST_SW_CERT_REQ_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_CERT_REQ_A:
- case SSL3_ST_SW_CERT_REQ_B:
- if (/* don't request cert unless asked for it: */
- !(s->verify_mode & SSL_VERIFY_PEER) ||
- /* if SSL_VERIFY_CLIENT_ONCE is set,
- * don't request cert during re-negotiation: */
- ((s->session->peer != NULL) &&
- (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
- /* never request cert in anonymous ciphersuites
- * (see section "Certificate request" in SSL 3 drafts
- * and in RFC 2246): */
- ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
- /* ... except when the application insists on verification
- * (against the specs, but s3_clnt.c accepts this for SSL 3) */
- !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
- /* never request cert in Kerberos ciphersuites */
- (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
- /* With normal PSK Certificates and
- * Certificate Requests are omitted */
- || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
- {
- /* no cert request */
- skip=1;
- s->s3->tmp.cert_request=0;
- s->state=SSL3_ST_SW_SRVR_DONE_A;
-#ifndef OPENSSL_NO_SCTP
- if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
- {
- s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
- s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
- }
-#endif
- }
- else
- {
- s->s3->tmp.cert_request=1;
- dtls1_start_timer(s);
- ret=dtls1_send_certificate_request(s);
- if (ret <= 0) goto end;
-#ifndef NETSCAPE_HANG_BUG
- s->state=SSL3_ST_SW_SRVR_DONE_A;
-#ifndef OPENSSL_NO_SCTP
- if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
- {
- s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
- s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
- }
-#endif
-#else
- s->state=SSL3_ST_SW_FLUSH;
- s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
-#ifndef OPENSSL_NO_SCTP
- if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
- {
- s->d1->next_state = s->s3->tmp.next_state;
- s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK;
- }
-#endif
-#endif
- s->init_num=0;
- }
- break;
-
- case SSL3_ST_SW_SRVR_DONE_A:
- case SSL3_ST_SW_SRVR_DONE_B:
- dtls1_start_timer(s);
- ret=dtls1_send_server_done(s);
- if (ret <= 0) goto end;
- s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
- s->state=SSL3_ST_SW_FLUSH;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_FLUSH:
- s->rwstate=SSL_WRITING;
- if (BIO_flush(s->wbio) <= 0)
- {
- /* If the write error was fatal, stop trying */
- if (!BIO_should_retry(s->wbio))
- {
- s->rwstate=SSL_NOTHING;
- s->state=s->s3->tmp.next_state;
- }
-
- ret= -1;
- goto end;
- }
- s->rwstate=SSL_NOTHING;
- s->state=s->s3->tmp.next_state;
- break;
-
- case SSL3_ST_SR_CERT_A:
- case SSL3_ST_SR_CERT_B:
- /* Check for second client hello (MS SGC) */
- ret = ssl3_check_client_hello(s);
- if (ret <= 0)
- goto end;
- if (ret == 2)
- {
- dtls1_stop_timer(s);
- s->state = SSL3_ST_SR_CLNT_HELLO_C;
- }
- else {
- /* could be sent for a DH cert, even if we
- * have not asked for it :-) */
- ret=ssl3_get_client_certificate(s);
- if (ret <= 0) goto end;
- s->init_num=0;
- s->state=SSL3_ST_SR_KEY_EXCH_A;
- }
- break;
-
- case SSL3_ST_SR_KEY_EXCH_A:
- case SSL3_ST_SR_KEY_EXCH_B:
- ret=ssl3_get_client_key_exchange(s);
- if (ret <= 0) goto end;
-#ifndef OPENSSL_NO_SCTP
- /* Add new shared key for SCTP-Auth,
- * will be ignored if no SCTP used.
- */
- snprintf((char *) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
- DTLS1_SCTP_AUTH_LABEL);
-
- SSL_export_keying_material(s, sctpauthkey,
- sizeof(sctpauthkey), labelbuffer,
- sizeof(labelbuffer), NULL, 0, 0);
-
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
- sizeof(sctpauthkey), sctpauthkey);
-#endif
-
- s->state=SSL3_ST_SR_CERT_VRFY_A;
- s->init_num=0;
-
- if (ret == 2)
- {
- /* For the ECDH ciphersuites when
- * the client sends its ECDH pub key in
- * a certificate, the CertificateVerify
- * message is not sent.
- */
- s->state=SSL3_ST_SR_FINISHED_A;
- s->init_num = 0;
- }
- else
- {
- s->state=SSL3_ST_SR_CERT_VRFY_A;
- s->init_num=0;
-
- /* We need to get hashes here so if there is
- * a client cert, it can be verified */
- s->method->ssl3_enc->cert_verify_mac(s,
- NID_md5,
- &(s->s3->tmp.cert_verify_md[0]));
- s->method->ssl3_enc->cert_verify_mac(s,
- NID_sha1,
- &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
- }
- break;
-
- case SSL3_ST_SR_CERT_VRFY_A:
- case SSL3_ST_SR_CERT_VRFY_B:
-
- s->d1->change_cipher_spec_ok = 1;
- /* we should decide if we expected this one */
- ret=ssl3_get_cert_verify(s);
- if (ret <= 0) goto end;
-#ifndef OPENSSL_NO_SCTP
- if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
- state == SSL_ST_RENEGOTIATE)
- s->state=DTLS1_SCTP_ST_SR_READ_SOCK;
- else
-#endif
- s->state=SSL3_ST_SR_FINISHED_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_SR_FINISHED_A:
- case SSL3_ST_SR_FINISHED_B:
- s->d1->change_cipher_spec_ok = 1;
- ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
- SSL3_ST_SR_FINISHED_B);
- if (ret <= 0) goto end;
- dtls1_stop_timer(s);
- if (s->hit)
- s->state=SSL_ST_OK;
-#ifndef OPENSSL_NO_TLSEXT
- else if (s->tlsext_ticket_expected)
- s->state=SSL3_ST_SW_SESSION_TICKET_A;
-#endif
- else
- s->state=SSL3_ST_SW_CHANGE_A;
- s->init_num=0;
- break;
-
-#ifndef OPENSSL_NO_TLSEXT
- case SSL3_ST_SW_SESSION_TICKET_A:
- case SSL3_ST_SW_SESSION_TICKET_B:
- ret=dtls1_send_newsession_ticket(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_SW_CHANGE_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_CERT_STATUS_A:
- case SSL3_ST_SW_CERT_STATUS_B:
- ret=ssl3_send_cert_status(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_SW_KEY_EXCH_A;
- s->init_num=0;
- break;
-
-#endif
-
- case SSL3_ST_SW_CHANGE_A:
- case SSL3_ST_SW_CHANGE_B:
-
- s->session->cipher=s->s3->tmp.new_cipher;
- if (!s->method->ssl3_enc->setup_key_block(s))
- { ret= -1; goto end; }
-
- ret=dtls1_send_change_cipher_spec(s,
- SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);
-
- if (ret <= 0) goto end;
-
-#ifndef OPENSSL_NO_SCTP
- if (!s->hit)
- {
- /* Change to new shared key of SCTP-Auth,
- * will be ignored if no SCTP used.
- */
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
- }
-#endif
-
- s->state=SSL3_ST_SW_FINISHED_A;
- s->init_num=0;
-
- if (!s->method->ssl3_enc->change_cipher_state(s,
- SSL3_CHANGE_CIPHER_SERVER_WRITE))
- {
- ret= -1;
- goto end;
- }
-
- dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
- break;
-
- case SSL3_ST_SW_FINISHED_A:
- case SSL3_ST_SW_FINISHED_B:
- ret=dtls1_send_finished(s,
- SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
- s->method->ssl3_enc->server_finished_label,
- s->method->ssl3_enc->server_finished_label_len);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_SW_FLUSH;
- if (s->hit)
- {
- s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
-
-#ifndef OPENSSL_NO_SCTP
- /* Change to new shared key of SCTP-Auth,
- * will be ignored if no SCTP used.
- */
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
-#endif
- }
- else
- {
- s->s3->tmp.next_state=SSL_ST_OK;
-#ifndef OPENSSL_NO_SCTP
- if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
- {
- s->d1->next_state = s->s3->tmp.next_state;
- s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK;
- }
-#endif
- }
- s->init_num=0;
- break;
-
- case SSL_ST_OK:
- /* clean a few things up */
- ssl3_cleanup_key_block(s);
-
-#if 0
- BUF_MEM_free(s->init_buf);
- s->init_buf=NULL;
-#endif
-
- /* remove buffering on output */
- ssl_free_wbio_buffer(s);
-
- s->init_num=0;
-
- if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
- {
- s->renegotiate=0;
- s->new_session=0;
-
- ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
-
- s->ctx->stats.sess_accept_good++;
- /* s->server=1; */
- s->handshake_func=dtls1_accept;
-
- if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
- }
-
- ret = 1;
-
- /* done handshaking, next message is client hello */
- s->d1->handshake_read_seq = 0;
- /* next message is server hello */
- s->d1->handshake_write_seq = 0;
- s->d1->next_handshake_write_seq = 0;
- goto end;
- /* break; */
-
- default:
- SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_UNKNOWN_STATE);
- ret= -1;
- goto end;
- /* break; */
- }
-
- if (!s->s3->tmp.reuse_message && !skip)
- {
- if (s->debug)
- {
- if ((ret=BIO_flush(s->wbio)) <= 0)
- goto end;
- }
-
-
- if ((cb != NULL) && (s->state != state))
- {
- new_state=s->state;
- s->state=state;
- cb(s,SSL_CB_ACCEPT_LOOP,1);
- s->state=new_state;
- }
- }
- skip=0;
- }
-end:
- /* BIO_flush(s->wbio); */
-
- s->in_handshake--;
-#ifndef OPENSSL_NO_SCTP
- /* Notify SCTP BIO socket to leave handshake
- * mode and prevent stream identifier other
- * than 0. Will be ignored if no SCTP is used.
- */
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
-#endif
-
- if (cb != NULL)
- cb(s,SSL_CB_ACCEPT_EXIT,ret);
- return(ret);
- }
-
-int dtls1_send_hello_request(SSL *s)
- {
- unsigned char *p;
-
- if (s->state == SSL3_ST_SW_HELLO_REQ_A)
- {
- p=(unsigned char *)s->init_buf->data;
- p = dtls1_set_message_header(s, p, SSL3_MT_HELLO_REQUEST, 0, 0, 0);
-
- s->state=SSL3_ST_SW_HELLO_REQ_B;
- /* number of bytes to write */
- s->init_num=DTLS1_HM_HEADER_LENGTH;
- s->init_off=0;
-
- /* no need to buffer this message, since there are no retransmit
- * requests for it */
- }
-
- /* SSL3_ST_SW_HELLO_REQ_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-int dtls1_send_hello_verify_request(SSL *s)
- {
- unsigned int msg_len;
- unsigned char *msg, *buf, *p;
-
- if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A)
- {
- buf = (unsigned char *)s->init_buf->data;
-
- msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
- *(p++) = s->version >> 8;
- *(p++) = s->version & 0xFF;
-
- if (s->ctx->app_gen_cookie_cb == NULL ||
- s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
- &(s->d1->cookie_len)) == 0)
- {
- SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- *(p++) = (unsigned char) s->d1->cookie_len;
- memcpy(p, s->d1->cookie, s->d1->cookie_len);
- p += s->d1->cookie_len;
- msg_len = p - msg;
-
- dtls1_set_message_header(s, buf,
- DTLS1_MT_HELLO_VERIFY_REQUEST, msg_len, 0, msg_len);
-
- s->state=DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
- /* number of bytes to write */
- s->init_num=p-buf;
- s->init_off=0;
- }
-
- /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-int dtls1_send_server_hello(SSL *s)
- {
- unsigned char *buf;
- unsigned char *p,*d;
- int i;
- unsigned int sl;
- unsigned long l;
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
- {
- buf=(unsigned char *)s->init_buf->data;
- p=s->s3->server_random;
- ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE);
- /* Do the message type and length last */
- d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
-
- *(p++)=s->version>>8;
- *(p++)=s->version&0xff;
-
- /* Random stuff */
- memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
- p+=SSL3_RANDOM_SIZE;
-
- /* now in theory we have 3 options to sending back the
- * session id. If it is a re-use, we send back the
- * old session-id, if it is a new session, we send
- * back the new session-id or we send back a 0 length
- * session-id if we want it to be single use.
- * Currently I will not implement the '0' length session-id
- * 12-Jan-98 - I'll now support the '0' length stuff.
- */
- if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER))
- s->session->session_id_length=0;
-
- sl=s->session->session_id_length;
- if (sl > sizeof s->session->session_id)
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
- return -1;
- }
- *(p++)=sl;
- memcpy(p,s->session->session_id,sl);
- p+=sl;
-
- /* put the cipher */
- if (s->s3->tmp.new_cipher == NULL)
- return -1;
- i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
- p+=i;
-
- /* put the compression method */
-#ifdef OPENSSL_NO_COMP
- *(p++)=0;
-#else
- if (s->s3->tmp.new_compression == NULL)
- *(p++)=0;
- else
- *(p++)=s->s3->tmp.new_compression->id;
-#endif
-
-#ifndef OPENSSL_NO_TLSEXT
- if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
- return -1;
- }
-#endif
-
- /* do the header */
- l=(p-d);
- d=buf;
-
- d = dtls1_set_message_header(s, d, SSL3_MT_SERVER_HELLO, l, 0, l);
-
- s->state=SSL3_ST_SW_SRVR_HELLO_B;
- /* number of bytes to write */
- s->init_num=p-buf;
- s->init_off=0;
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
- }
-
- /* SSL3_ST_SW_SRVR_HELLO_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-int dtls1_send_server_done(SSL *s)
- {
- unsigned char *p;
-
- if (s->state == SSL3_ST_SW_SRVR_DONE_A)
- {
- p=(unsigned char *)s->init_buf->data;
-
- /* do the header */
- p = dtls1_set_message_header(s, p, SSL3_MT_SERVER_DONE, 0, 0, 0);
-
- s->state=SSL3_ST_SW_SRVR_DONE_B;
- /* number of bytes to write */
- s->init_num=DTLS1_HM_HEADER_LENGTH;
- s->init_off=0;
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
- }
-
- /* SSL3_ST_SW_SRVR_DONE_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-int dtls1_send_server_key_exchange(SSL *s)
- {
-#ifndef OPENSSL_NO_RSA
- unsigned char *q;
- int j,num;
- RSA *rsa;
- unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
- unsigned int u;
-#endif
-#ifndef OPENSSL_NO_DH
- DH *dh=NULL,*dhp;
-#endif
-#ifndef OPENSSL_NO_ECDH
- EC_KEY *ecdh=NULL, *ecdhp;
- unsigned char *encodedPoint = NULL;
- int encodedlen = 0;
- int curve_id = 0;
- BN_CTX *bn_ctx = NULL;
-#endif
- EVP_PKEY *pkey;
- unsigned char *p,*d;
- int al,i;
- unsigned long type;
- int n;
- CERT *cert;
- BIGNUM *r[4];
- int nr[4],kn;
- BUF_MEM *buf;
- EVP_MD_CTX md_ctx;
-
- EVP_MD_CTX_init(&md_ctx);
- if (s->state == SSL3_ST_SW_KEY_EXCH_A)
- {
- type=s->s3->tmp.new_cipher->algorithm_mkey;
- cert=s->cert;
-
- buf=s->init_buf;
-
- r[0]=r[1]=r[2]=r[3]=NULL;
- n=0;
-#ifndef OPENSSL_NO_RSA
- if (type & SSL_kRSA)
- {
- rsa=cert->rsa_tmp;
- if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
- {
- rsa=s->cert->rsa_tmp_cb(s,
- SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
- SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
- if(rsa == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
- goto f_err;
- }
- RSA_up_ref(rsa);
- cert->rsa_tmp=rsa;
- }
- if (rsa == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_KEY);
- goto f_err;
- }
- r[0]=rsa->n;
- r[1]=rsa->e;
- s->s3->tmp.use_rsa_tmp=1;
- }
- else
-#endif
-#ifndef OPENSSL_NO_DH
- if (type & SSL_kEDH)
- {
- dhp=cert->dh_tmp;
- if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
- dhp=s->cert->dh_tmp_cb(s,
- SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
- SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
- if (dhp == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
- goto f_err;
- }
-
- if (s->s3->tmp.dh != NULL)
- {
- DH_free(dh);
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- if ((dh=DHparams_dup(dhp)) == NULL)
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
- goto err;
- }
-
- s->s3->tmp.dh=dh;
- if ((dhp->pub_key == NULL ||
- dhp->priv_key == NULL ||
- (s->options & SSL_OP_SINGLE_DH_USE)))
- {
- if(!DH_generate_key(dh))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,
- ERR_R_DH_LIB);
- goto err;
- }
- }
- else
- {
- dh->pub_key=BN_dup(dhp->pub_key);
- dh->priv_key=BN_dup(dhp->priv_key);
- if ((dh->pub_key == NULL) ||
- (dh->priv_key == NULL))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
- goto err;
- }
- }
- r[0]=dh->p;
- r[1]=dh->g;
- r[2]=dh->pub_key;
- }
- else
-#endif
-#ifndef OPENSSL_NO_ECDH
- if (type & SSL_kEECDH)
- {
- const EC_GROUP *group;
-
- ecdhp=cert->ecdh_tmp;
- if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
- {
- ecdhp=s->cert->ecdh_tmp_cb(s,
- SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
- SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
- }
- if (ecdhp == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
- goto f_err;
- }
-
- if (s->s3->tmp.ecdh != NULL)
- {
- EC_KEY_free(s->s3->tmp.ecdh);
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- /* Duplicate the ECDH structure. */
- if (ecdhp == NULL)
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
- if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
-
- s->s3->tmp.ecdh=ecdh;
- if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
- (EC_KEY_get0_private_key(ecdh) == NULL) ||
- (s->options & SSL_OP_SINGLE_ECDH_USE))
- {
- if(!EC_KEY_generate_key(ecdh))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
- }
-
- if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
- (EC_KEY_get0_public_key(ecdh) == NULL) ||
- (EC_KEY_get0_private_key(ecdh) == NULL))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
-
- if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
- (EC_GROUP_get_degree(group) > 163))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
- goto err;
- }
-
- /* XXX: For now, we only support ephemeral ECDH
- * keys over named (not generic) curves. For
- * supported named curves, curve_id is non-zero.
- */
- if ((curve_id =
- tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
- == 0)
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
- goto err;
- }
-
- /* Encode the public key.
- * First check the size of encoding and
- * allocate memory accordingly.
- */
- encodedlen = EC_POINT_point2oct(group,
- EC_KEY_get0_public_key(ecdh),
- POINT_CONVERSION_UNCOMPRESSED,
- NULL, 0, NULL);
-
- encodedPoint = (unsigned char *)
- OPENSSL_malloc(encodedlen*sizeof(unsigned char));
- bn_ctx = BN_CTX_new();
- if ((encodedPoint == NULL) || (bn_ctx == NULL))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
-
- encodedlen = EC_POINT_point2oct(group,
- EC_KEY_get0_public_key(ecdh),
- POINT_CONVERSION_UNCOMPRESSED,
- encodedPoint, encodedlen, bn_ctx);
-
- if (encodedlen == 0)
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
-
- BN_CTX_free(bn_ctx); bn_ctx=NULL;
-
- /* XXX: For now, we only support named (not
- * generic) curves in ECDH ephemeral key exchanges.
- * In this situation, we need four additional bytes
- * to encode the entire ServerECDHParams
- * structure.
- */
- n = 4 + encodedlen;
-
- /* We'll generate the serverKeyExchange message
- * explicitly so we can set these to NULLs
- */
- r[0]=NULL;
- r[1]=NULL;
- r[2]=NULL;
- r[3]=NULL;
- }
- else
-#endif /* !OPENSSL_NO_ECDH */
-#ifndef OPENSSL_NO_PSK
- if (type & SSL_kPSK)
- {
- /* reserve size for record length and PSK identity hint*/
- n+=2+strlen(s->ctx->psk_identity_hint);
- }
- else
-#endif /* !OPENSSL_NO_PSK */
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
- goto f_err;
- }
- for (i=0; r[i] != NULL; i++)
- {
- nr[i]=BN_num_bytes(r[i]);
- n+=2+nr[i];
- }
-
- if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
- && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
- {
- if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher, NULL))
- == NULL)
- {
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- kn=EVP_PKEY_size(pkey);
- }
- else
- {
- pkey=NULL;
- kn=0;
- }
-
- if (!BUF_MEM_grow_clean(buf,n+DTLS1_HM_HEADER_LENGTH+kn))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF);
- goto err;
- }
- d=(unsigned char *)s->init_buf->data;
- p= &(d[DTLS1_HM_HEADER_LENGTH]);
-
- for (i=0; r[i] != NULL; i++)
- {
- s2n(nr[i],p);
- BN_bn2bin(r[i],p);
- p+=nr[i];
- }
-
-#ifndef OPENSSL_NO_ECDH
- if (type & SSL_kEECDH)
- {
- /* XXX: For now, we only support named (not generic) curves.
- * In this situation, the serverKeyExchange message has:
- * [1 byte CurveType], [2 byte CurveName]
- * [1 byte length of encoded point], followed by
- * the actual encoded point itself
- */
- *p = NAMED_CURVE_TYPE;
- p += 1;
- *p = 0;
- p += 1;
- *p = curve_id;
- p += 1;
- *p = encodedlen;
- p += 1;
- memcpy((unsigned char*)p,
- (unsigned char *)encodedPoint,
- encodedlen);
- OPENSSL_free(encodedPoint);
- p += encodedlen;
- }
-#endif
-
-#ifndef OPENSSL_NO_PSK
- if (type & SSL_kPSK)
- {
- /* copy PSK identity hint */
- s2n(strlen(s->ctx->psk_identity_hint), p);
- strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
- p+=strlen(s->ctx->psk_identity_hint);
- }
-#endif
-
- /* not anonymous */
- if (pkey != NULL)
- {
- /* n is the length of the params, they start at
- * &(d[DTLS1_HM_HEADER_LENGTH]) and p points to the space
- * at the end. */
-#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA)
- {
- q=md_buf;
- j=0;
- for (num=2; num > 0; num--)
- {
- EVP_DigestInit_ex(&md_ctx,(num == 2)
- ?s->ctx->md5:s->ctx->sha1, NULL);
- EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_DigestUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
- EVP_DigestFinal_ex(&md_ctx,q,
- (unsigned int *)&i);
- q+=i;
- j+=i;
- }
- if (RSA_sign(NID_md5_sha1, md_buf, j,
- &(p[2]), &u, pkey->pkey.rsa) <= 0)
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
- goto err;
- }
- s2n(u,p);
- n+=u+2;
- }
- else
-#endif
-#if !defined(OPENSSL_NO_DSA)
- if (pkey->type == EVP_PKEY_DSA)
- {
- /* lets do DSS */
- EVP_SignInit_ex(&md_ctx,EVP_dss1(), NULL);
- EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
- if (!EVP_SignFinal(&md_ctx,&(p[2]),
- (unsigned int *)&i,pkey))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_DSA);
- goto err;
- }
- s2n(i,p);
- n+=i+2;
- }
- else
-#endif
-#if !defined(OPENSSL_NO_ECDSA)
- if (pkey->type == EVP_PKEY_EC)
- {
- /* let's do ECDSA */
- EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL);
- EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
- if (!EVP_SignFinal(&md_ctx,&(p[2]),
- (unsigned int *)&i,pkey))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA);
- goto err;
- }
- s2n(i,p);
- n+=i+2;
- }
- else
-#endif
- {
- /* Is this error check actually needed? */
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
- goto f_err;
- }
- }
-
- d = dtls1_set_message_header(s, d,
- SSL3_MT_SERVER_KEY_EXCHANGE, n, 0, n);
-
- /* we should now have things packed up, so lets send
- * it off */
- s->init_num=n+DTLS1_HM_HEADER_LENGTH;
- s->init_off=0;
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
- }
-
- s->state = SSL3_ST_SW_KEY_EXCH_B;
- EVP_MD_CTX_cleanup(&md_ctx);
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
-#ifndef OPENSSL_NO_ECDH
- if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
- BN_CTX_free(bn_ctx);
-#endif
- EVP_MD_CTX_cleanup(&md_ctx);
- return(-1);
- }
-
-int dtls1_send_certificate_request(SSL *s)
- {
- unsigned char *p,*d;
- int i,j,nl,off,n;
- STACK_OF(X509_NAME) *sk=NULL;
- X509_NAME *name;
- BUF_MEM *buf;
- unsigned int msg_len;
-
- if (s->state == SSL3_ST_SW_CERT_REQ_A)
- {
- buf=s->init_buf;
-
- d=p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]);
-
- /* get the list of acceptable cert types */
- p++;
- n=ssl3_get_req_cert_type(s,p);
- d[0]=n;
- p+=n;
- n++;
-
- off=n;
- p+=2;
- n+=2;
-
- sk=SSL_get_client_CA_list(s);
- nl=0;
- if (sk != NULL)
- {
- for (i=0; i<sk_X509_NAME_num(sk); i++)
- {
- name=sk_X509_NAME_value(sk,i);
- j=i2d_X509_NAME(name,NULL);
- if (!BUF_MEM_grow_clean(buf,DTLS1_HM_HEADER_LENGTH+n+j+2))
- {
- SSLerr(SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
- goto err;
- }
- p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+n]);
- if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
- {
- s2n(j,p);
- i2d_X509_NAME(name,&p);
- n+=2+j;
- nl+=2+j;
- }
- else
- {
- d=p;
- i2d_X509_NAME(name,&p);
- j-=2; s2n(j,d); j+=2;
- n+=j;
- nl+=j;
- }
- }
- }
- /* else no CA names */
- p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+off]);
- s2n(nl,p);
-
- d=(unsigned char *)buf->data;
- *(d++)=SSL3_MT_CERTIFICATE_REQUEST;
- l2n3(n,d);
- s2n(s->d1->handshake_write_seq,d);
- s->d1->handshake_write_seq++;
-
- /* we should now have things packed up, so lets send
- * it off */
-
- s->init_num=n+DTLS1_HM_HEADER_LENGTH;
- s->init_off=0;
-#ifdef NETSCAPE_HANG_BUG
-/* XXX: what to do about this? */
- p=(unsigned char *)s->init_buf->data + s->init_num;
-
- /* do the header */
- *(p++)=SSL3_MT_SERVER_DONE;
- *(p++)=0;
- *(p++)=0;
- *(p++)=0;
- s->init_num += 4;
-#endif
-
- /* XDTLS: set message header ? */
- msg_len = s->init_num - DTLS1_HM_HEADER_LENGTH;
- dtls1_set_message_header(s, (void *)s->init_buf->data,
- SSL3_MT_CERTIFICATE_REQUEST, msg_len, 0, msg_len);
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
-
- s->state = SSL3_ST_SW_CERT_REQ_B;
- }
-
- /* SSL3_ST_SW_CERT_REQ_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
-err:
- return(-1);
- }
-
-int dtls1_send_server_certificate(SSL *s)
- {
- unsigned long l;
- X509 *x;
-
- if (s->state == SSL3_ST_SW_CERT_A)
- {
- x=ssl_get_server_send_cert(s);
- if (x == NULL)
- {
- /* VRS: allow null cert if auth == KRB5 */
- if ((s->s3->tmp.new_cipher->algorithm_mkey != SSL_kKRB5) ||
- (s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5))
- {
- SSLerr(SSL_F_DTLS1_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR);
- return(0);
- }
- }
-
- l=dtls1_output_cert_chain(s,x);
- s->state=SSL3_ST_SW_CERT_B;
- s->init_num=(int)l;
- s->init_off=0;
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
- }
-
- /* SSL3_ST_SW_CERT_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-#ifndef OPENSSL_NO_TLSEXT
-int dtls1_send_newsession_ticket(SSL *s)
- {
- if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
- {
- unsigned char *p, *senc, *macstart;
- int len, slen;
- unsigned int hlen, msg_len;
- EVP_CIPHER_CTX ctx;
- HMAC_CTX hctx;
- SSL_CTX *tctx = s->initial_ctx;
- unsigned char iv[EVP_MAX_IV_LENGTH];
- unsigned char key_name[16];
-
- /* get session encoding length */
- slen = i2d_SSL_SESSION(s->session, NULL);
- /* Some length values are 16 bits, so forget it if session is
- * too long
- */
- if (slen > 0xFF00)
- return -1;
- /* Grow buffer if need be: the length calculation is as
- * follows 12 (DTLS handshake message header) +
- * 4 (ticket lifetime hint) + 2 (ticket length) +
- * 16 (key name) + max_iv_len (iv length) +
- * session_length + max_enc_block_size (max encrypted session
- * length) + max_md_size (HMAC).
- */
- if (!BUF_MEM_grow(s->init_buf,
- DTLS1_HM_HEADER_LENGTH + 22 + EVP_MAX_IV_LENGTH +
- EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
- return -1;
- senc = OPENSSL_malloc(slen);
- if (!senc)
- return -1;
- p = senc;
- i2d_SSL_SESSION(s->session, &p);
-
- p=(unsigned char *)&(s->init_buf->data[DTLS1_HM_HEADER_LENGTH]);
- EVP_CIPHER_CTX_init(&ctx);
- HMAC_CTX_init(&hctx);
- /* Initialize HMAC and cipher contexts. If callback present
- * it does all the work otherwise use generated values
- * from parent ctx.
- */
- if (tctx->tlsext_ticket_key_cb)
- {
- if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
- &hctx, 1) < 0)
- {
- OPENSSL_free(senc);
- return -1;
- }
- }
- else
- {
- RAND_pseudo_bytes(iv, 16);
- EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
- tctx->tlsext_tick_aes_key, iv);
- HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
- tlsext_tick_md(), NULL);
- memcpy(key_name, tctx->tlsext_tick_key_name, 16);
- }
- l2n(s->session->tlsext_tick_lifetime_hint, p);
- /* Skip ticket length for now */
- p += 2;
- /* Output key name */
- macstart = p;
- memcpy(p, key_name, 16);
- p += 16;
- /* output IV */
- memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
- p += EVP_CIPHER_CTX_iv_length(&ctx);
- /* Encrypt session data */
- EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
- p += len;
- EVP_EncryptFinal(&ctx, p, &len);
- p += len;
- EVP_CIPHER_CTX_cleanup(&ctx);
-
- HMAC_Update(&hctx, macstart, p - macstart);
- HMAC_Final(&hctx, p, &hlen);
- HMAC_CTX_cleanup(&hctx);
-
- p += hlen;
- /* Now write out lengths: p points to end of data written */
- /* Total length */
- len = p - (unsigned char *)(s->init_buf->data);
- /* Ticket length */
- p=(unsigned char *)&(s->init_buf->data[DTLS1_HM_HEADER_LENGTH]) + 4;
- s2n(len - DTLS1_HM_HEADER_LENGTH - 6, p);
-
- /* number of bytes to write */
- s->init_num= len;
- s->state=SSL3_ST_SW_SESSION_TICKET_B;
- s->init_off=0;
- OPENSSL_free(senc);
-
- /* XDTLS: set message header ? */
- msg_len = s->init_num - DTLS1_HM_HEADER_LENGTH;
- dtls1_set_message_header(s, (void *)s->init_buf->data,
- SSL3_MT_NEWSESSION_TICKET, msg_len, 0, msg_len);
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
- }
-
- /* SSL3_ST_SW_SESSION_TICKET_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
- }
-#endif
diff --git a/drivers/builtin_openssl/ssl/dtls1.h b/drivers/builtin_openssl/ssl/dtls1.h
deleted file mode 100644
index e65d501191..0000000000
--- a/drivers/builtin_openssl/ssl/dtls1.h
+++ /dev/null
@@ -1,287 +0,0 @@
-/* ssl/dtls1.h */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#ifndef HEADER_DTLS1_H
-#define HEADER_DTLS1_H
-
-#include <openssl/buffer.h>
-#include <openssl/pqueue.h>
-#ifdef OPENSSL_SYS_VMS
-#include <resource.h>
-#include <sys/timeb.h>
-#endif
-#ifdef OPENSSL_SYS_WIN32
-/* Needed for struct timeval */
-#include <winsock.h>
-#elif defined(OPENSSL_SYS_NETWARE) && !defined(_WINSOCK2API_)
-#include <sys/timeval.h>
-#else
-#if defined(OPENSSL_SYS_VXWORKS)
-#include <sys/times.h>
-#else
-#include <sys/time.h>
-#endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DTLS1_VERSION 0xFEFF
-#define DTLS1_BAD_VER 0x0100
-
-#if 0
-/* this alert description is not specified anywhere... */
-#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE 110
-#endif
-
-/* lengths of messages */
-#define DTLS1_COOKIE_LENGTH 256
-
-#define DTLS1_RT_HEADER_LENGTH 13
-
-#define DTLS1_HM_HEADER_LENGTH 12
-
-#define DTLS1_HM_BAD_FRAGMENT -2
-#define DTLS1_HM_FRAGMENT_RETRY -3
-
-#define DTLS1_CCS_HEADER_LENGTH 1
-
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
-#define DTLS1_AL_HEADER_LENGTH 7
-#else
-#define DTLS1_AL_HEADER_LENGTH 2
-#endif
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-#ifndef OPENSSL_NO_SCTP
-#define DTLS1_SCTP_AUTH_LABEL "EXPORTER_DTLS_OVER_SCTP"
-#endif
-
-typedef struct dtls1_bitmap_st
- {
- unsigned long map; /* track 32 packets on 32-bit systems
- and 64 - on 64-bit systems */
- unsigned char max_seq_num[8]; /* max record number seen so far,
- 64-bit value in big-endian
- encoding */
- } DTLS1_BITMAP;
-
-struct dtls1_retransmit_state
- {
- EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
- EVP_MD_CTX *write_hash; /* used for mac generation */
-#ifndef OPENSSL_NO_COMP
- COMP_CTX *compress; /* compression */
-#else
- char *compress;
-#endif
- SSL_SESSION *session;
- unsigned short epoch;
- };
-
-struct hm_header_st
- {
- unsigned char type;
- unsigned long msg_len;
- unsigned short seq;
- unsigned long frag_off;
- unsigned long frag_len;
- unsigned int is_ccs;
- struct dtls1_retransmit_state saved_retransmit_state;
- };
-
-struct ccs_header_st
- {
- unsigned char type;
- unsigned short seq;
- };
-
-struct dtls1_timeout_st
- {
- /* Number of read timeouts so far */
- unsigned int read_timeouts;
-
- /* Number of write timeouts so far */
- unsigned int write_timeouts;
-
- /* Number of alerts received so far */
- unsigned int num_alerts;
- };
-
-typedef struct record_pqueue_st
- {
- unsigned short epoch;
- pqueue q;
- } record_pqueue;
-
-typedef struct hm_fragment_st
- {
- struct hm_header_st msg_header;
- unsigned char *fragment;
- unsigned char *reassembly;
- } hm_fragment;
-
-typedef struct dtls1_state_st
- {
- unsigned int send_cookie;
- unsigned char cookie[DTLS1_COOKIE_LENGTH];
- unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH];
- unsigned int cookie_len;
-
- /*
- * The current data and handshake epoch. This is initially
- * undefined, and starts at zero once the initial handshake is
- * completed
- */
- unsigned short r_epoch;
- unsigned short w_epoch;
-
- /* records being received in the current epoch */
- DTLS1_BITMAP bitmap;
-
- /* renegotiation starts a new set of sequence numbers */
- DTLS1_BITMAP next_bitmap;
-
- /* handshake message numbers */
- unsigned short handshake_write_seq;
- unsigned short next_handshake_write_seq;
-
- unsigned short handshake_read_seq;
-
- /* save last sequence number for retransmissions */
- unsigned char last_write_sequence[8];
-
- /* Received handshake records (processed and unprocessed) */
- record_pqueue unprocessed_rcds;
- record_pqueue processed_rcds;
-
- /* Buffered handshake messages */
- pqueue buffered_messages;
-
- /* Buffered (sent) handshake records */
- pqueue sent_messages;
-
- /* Buffered application records.
- * Only for records between CCS and Finished
- * to prevent either protocol violation or
- * unnecessary message loss.
- */
- record_pqueue buffered_app_data;
-
- /* Is set when listening for new connections with dtls1_listen() */
- unsigned int listen;
-
- unsigned int mtu; /* max DTLS packet size */
-
- struct hm_header_st w_msg_hdr;
- struct hm_header_st r_msg_hdr;
-
- struct dtls1_timeout_st timeout;
-
- /* Indicates when the last handshake msg or heartbeat sent will timeout */
- struct timeval next_timeout;
-
- /* Timeout duration */
- unsigned short timeout_duration;
-
- /* storage for Alert/Handshake protocol data received but not
- * yet processed by ssl3_read_bytes: */
- unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
- unsigned int alert_fragment_len;
- unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH];
- unsigned int handshake_fragment_len;
-
- unsigned int retransmitting;
- unsigned int change_cipher_spec_ok;
-
-#ifndef OPENSSL_NO_SCTP
- /* used when SSL_ST_XX_FLUSH is entered */
- int next_state;
-
- int shutdown_received;
-#endif
-
- } DTLS1_STATE;
-
-typedef struct dtls1_record_data_st
- {
- unsigned char *packet;
- unsigned int packet_length;
- SSL3_BUFFER rbuf;
- SSL3_RECORD rrec;
-#ifndef OPENSSL_NO_SCTP
- struct bio_dgram_sctp_rcvinfo recordinfo;
-#endif
- } DTLS1_RECORD_DATA;
-
-#endif
-
-/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
-#define DTLS1_TMO_READ_COUNT 2
-#define DTLS1_TMO_WRITE_COUNT 2
-
-#define DTLS1_TMO_ALERT_COUNT 12
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/ssl/kssl.h b/drivers/builtin_openssl/ssl/kssl.h
deleted file mode 100644
index e4df843073..0000000000
--- a/drivers/builtin_openssl/ssl/kssl.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/* ssl/kssl.h -*- mode: C; c-file-style: "eay" -*- */
-/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000.
- * project 2000.
- */
-/* ====================================================================
- * Copyright (c) 2000 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-/*
-** 19990701 VRS Started.
-*/
-
-#ifndef KSSL_H
-#define KSSL_H
-
-#include <openssl/opensslconf.h>
-
-#ifndef OPENSSL_NO_KRB5
-
-#include <stdio.h>
-#include <ctype.h>
-#include <krb5.h>
-#ifdef OPENSSL_SYS_WIN32
-/* These can sometimes get redefined indirectly by krb5 header files
- * after they get undefed in ossl_typ.h
- */
-#undef X509_NAME
-#undef X509_EXTENSIONS
-#undef OCSP_REQUEST
-#undef OCSP_RESPONSE
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-** Depending on which KRB5 implementation used, some types from
-** the other may be missing. Resolve that here and now
-*/
-#ifdef KRB5_HEIMDAL
-typedef unsigned char krb5_octet;
-#define FAR
-#else
-
-#ifndef FAR
-#define FAR
-#endif
-
-#endif
-
-/* Uncomment this to debug kssl problems or
-** to trace usage of the Kerberos session key
-**
-** #define KSSL_DEBUG
-*/
-
-#ifndef KRB5SVC
-#define KRB5SVC "host"
-#endif
-
-#ifndef KRB5KEYTAB
-#define KRB5KEYTAB "/etc/krb5.keytab"
-#endif
-
-#ifndef KRB5SENDAUTH
-#define KRB5SENDAUTH 1
-#endif
-
-#ifndef KRB5CHECKAUTH
-#define KRB5CHECKAUTH 1
-#endif
-
-#ifndef KSSL_CLOCKSKEW
-#define KSSL_CLOCKSKEW 300;
-#endif
-
-#define KSSL_ERR_MAX 255
-typedef struct kssl_err_st {
- int reason;
- char text[KSSL_ERR_MAX+1];
- } KSSL_ERR;
-
-
-/* Context for passing
-** (1) Kerberos session key to SSL, and
-** (2) Config data between application and SSL lib
-*/
-typedef struct kssl_ctx_st
- {
- /* used by: disposition: */
- char *service_name; /* C,S default ok (kssl) */
- char *service_host; /* C input, REQUIRED */
- char *client_princ; /* S output from krb5 ticket */
- char *keytab_file; /* S NULL (/etc/krb5.keytab) */
- char *cred_cache; /* C NULL (default) */
- krb5_enctype enctype;
- int length;
- krb5_octet FAR *key;
- } KSSL_CTX;
-
-#define KSSL_CLIENT 1
-#define KSSL_SERVER 2
-#define KSSL_SERVICE 3
-#define KSSL_KEYTAB 4
-
-#define KSSL_CTX_OK 0
-#define KSSL_CTX_ERR 1
-#define KSSL_NOMEM 2
-
-/* Public (for use by applications that use OpenSSL with Kerberos 5 support */
-krb5_error_code kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text);
-KSSL_CTX *kssl_ctx_new(void);
-KSSL_CTX *kssl_ctx_free(KSSL_CTX *kssl_ctx);
-void kssl_ctx_show(KSSL_CTX *kssl_ctx);
-krb5_error_code kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
- krb5_data *realm, krb5_data *entity, int nentities);
-krb5_error_code kssl_cget_tkt(KSSL_CTX *kssl_ctx, krb5_data **enc_tktp,
- krb5_data *authenp, KSSL_ERR *kssl_err);
-krb5_error_code kssl_sget_tkt(KSSL_CTX *kssl_ctx, krb5_data *indata,
- krb5_ticket_times *ttimes, KSSL_ERR *kssl_err);
-krb5_error_code kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session);
-void kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text);
-void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data);
-krb5_error_code kssl_build_principal_2(krb5_context context,
- krb5_principal *princ, int rlen, const char *realm,
- int slen, const char *svc, int hlen, const char *host);
-krb5_error_code kssl_validate_times(krb5_timestamp atime,
- krb5_ticket_times *ttimes);
-krb5_error_code kssl_check_authent(KSSL_CTX *kssl_ctx, krb5_data *authentp,
- krb5_timestamp *atimep, KSSL_ERR *kssl_err);
-unsigned char *kssl_skip_confound(krb5_enctype enctype, unsigned char *authn);
-
-void SSL_set0_kssl_ctx(SSL *s, KSSL_CTX *kctx);
-KSSL_CTX * SSL_get0_kssl_ctx(SSL *s);
-char *kssl_ctx_get0_client_princ(KSSL_CTX *kctx);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* OPENSSL_NO_KRB5 */
-#endif /* KSSL_H */
diff --git a/drivers/builtin_openssl/ssl/s3_clnt.c b/drivers/builtin_openssl/ssl/s3_clnt.c
deleted file mode 100644
index a6b3c01afa..0000000000
--- a/drivers/builtin_openssl/ssl/s3_clnt.c
+++ /dev/null
@@ -1,3372 +0,0 @@
-/* ssl/s3_clnt.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the OpenSSL open source
- * license provided above.
- *
- * ECC cipher suite support in OpenSSL originally written by
- * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
- *
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include "kssl_lcl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/md5.h>
-#ifdef OPENSSL_FIPS
-#include <openssl/fips.h>
-#endif
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#endif
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_ENGINE
-#include <openssl/engine.h>
-#endif
-
-static const SSL_METHOD *ssl3_get_client_method(int ver);
-static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
-
-static const SSL_METHOD *ssl3_get_client_method(int ver)
- {
- if (ver == SSL3_VERSION)
- return(SSLv3_client_method());
- else
- return(NULL);
- }
-
-IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
- ssl_undefined_function,
- ssl3_connect,
- ssl3_get_client_method)
-
-int ssl3_connect(SSL *s)
- {
- BUF_MEM *buf=NULL;
- unsigned long Time=(unsigned long)time(NULL);
- void (*cb)(const SSL *ssl,int type,int val)=NULL;
- int ret= -1;
- int new_state,state,skip=0;
-
- RAND_add(&Time,sizeof(Time),0);
- ERR_clear_error();
- clear_sys_error();
-
- if (s->info_callback != NULL)
- cb=s->info_callback;
- else if (s->ctx->info_callback != NULL)
- cb=s->ctx->info_callback;
-
- s->in_handshake++;
- if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
-
-#ifndef OPENSSL_NO_HEARTBEATS
- /* If we're awaiting a HeartbeatResponse, pretend we
- * already got and don't await it anymore, because
- * Heartbeats don't make sense during handshakes anyway.
- */
- if (s->tlsext_hb_pending)
- {
- s->tlsext_hb_pending = 0;
- s->tlsext_hb_seq++;
- }
-#endif
-
- for (;;)
- {
- state=s->state;
-
- switch(s->state)
- {
- case SSL_ST_RENEGOTIATE:
- s->renegotiate=1;
- s->state=SSL_ST_CONNECT;
- s->ctx->stats.sess_connect_renegotiate++;
- /* break */
- case SSL_ST_BEFORE:
- case SSL_ST_CONNECT:
- case SSL_ST_BEFORE|SSL_ST_CONNECT:
- case SSL_ST_OK|SSL_ST_CONNECT:
-
- s->server=0;
- if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
-
- if ((s->version & 0xff00 ) != 0x0300)
- {
- SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR);
- ret = -1;
- goto end;
- }
-
- /* s->version=SSL3_VERSION; */
- s->type=SSL_ST_CONNECT;
-
- if (s->init_buf == NULL)
- {
- if ((buf=BUF_MEM_new()) == NULL)
- {
- ret= -1;
- goto end;
- }
- if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
- {
- ret= -1;
- goto end;
- }
- s->init_buf=buf;
- buf=NULL;
- }
-
- if (!ssl3_setup_buffers(s)) { ret= -1; goto end; }
-
- /* setup buffing BIO */
- if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; }
-
- /* don't push the buffering BIO quite yet */
-
- ssl3_init_finished_mac(s);
-
- s->state=SSL3_ST_CW_CLNT_HELLO_A;
- s->ctx->stats.sess_connect++;
- s->init_num=0;
- break;
-
- case SSL3_ST_CW_CLNT_HELLO_A:
- case SSL3_ST_CW_CLNT_HELLO_B:
-
- s->shutdown=0;
- ret=ssl3_client_hello(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CR_SRVR_HELLO_A;
- s->init_num=0;
-
- /* turn on buffering for the next lot of output */
- if (s->bbio != s->wbio)
- s->wbio=BIO_push(s->bbio,s->wbio);
-
- break;
-
- case SSL3_ST_CR_SRVR_HELLO_A:
- case SSL3_ST_CR_SRVR_HELLO_B:
- ret=ssl3_get_server_hello(s);
- if (ret <= 0) goto end;
-
- if (s->hit)
- {
- s->state=SSL3_ST_CR_FINISHED_A;
-#ifndef OPENSSL_NO_TLSEXT
- if (s->tlsext_ticket_expected)
- {
- /* receive renewed session ticket */
- s->state=SSL3_ST_CR_SESSION_TICKET_A;
- }
-#endif
- }
- else
- s->state=SSL3_ST_CR_CERT_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_CR_CERT_A:
- case SSL3_ST_CR_CERT_B:
-#ifndef OPENSSL_NO_TLSEXT
- ret=ssl3_check_finished(s);
- if (ret <= 0) goto end;
- if (ret == 2)
- {
- s->hit = 1;
- if (s->tlsext_ticket_expected)
- s->state=SSL3_ST_CR_SESSION_TICKET_A;
- else
- s->state=SSL3_ST_CR_FINISHED_A;
- s->init_num=0;
- break;
- }
-#endif
- /* Check if it is anon DH/ECDH */
- /* or PSK */
- if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
- !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
- {
- ret=ssl3_get_server_certificate(s);
- if (ret <= 0) goto end;
-#ifndef OPENSSL_NO_TLSEXT
- if (s->tlsext_status_expected)
- s->state=SSL3_ST_CR_CERT_STATUS_A;
- else
- s->state=SSL3_ST_CR_KEY_EXCH_A;
- }
- else
- {
- skip = 1;
- s->state=SSL3_ST_CR_KEY_EXCH_A;
- }
-#else
- }
- else
- skip=1;
-
- s->state=SSL3_ST_CR_KEY_EXCH_A;
-#endif
- s->init_num=0;
- break;
-
- case SSL3_ST_CR_KEY_EXCH_A:
- case SSL3_ST_CR_KEY_EXCH_B:
- ret=ssl3_get_key_exchange(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CR_CERT_REQ_A;
- s->init_num=0;
-
- /* at this point we check that we have the
- * required stuff from the server */
- if (!ssl3_check_cert_and_algorithm(s))
- {
- ret= -1;
- goto end;
- }
- break;
-
- case SSL3_ST_CR_CERT_REQ_A:
- case SSL3_ST_CR_CERT_REQ_B:
- ret=ssl3_get_certificate_request(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CR_SRVR_DONE_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_CR_SRVR_DONE_A:
- case SSL3_ST_CR_SRVR_DONE_B:
- ret=ssl3_get_server_done(s);
- if (ret <= 0) goto end;
-#ifndef OPENSSL_NO_SRP
- if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP)
- {
- if ((ret = SRP_Calc_A_param(s))<=0)
- {
- SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SRP_A_CALC);
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
- goto end;
- }
- }
-#endif
- if (s->s3->tmp.cert_req)
- s->state=SSL3_ST_CW_CERT_A;
- else
- s->state=SSL3_ST_CW_KEY_EXCH_A;
- s->init_num=0;
-
- break;
-
- case SSL3_ST_CW_CERT_A:
- case SSL3_ST_CW_CERT_B:
- case SSL3_ST_CW_CERT_C:
- case SSL3_ST_CW_CERT_D:
- ret=ssl3_send_client_certificate(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CW_KEY_EXCH_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_CW_KEY_EXCH_A:
- case SSL3_ST_CW_KEY_EXCH_B:
- ret=ssl3_send_client_key_exchange(s);
- if (ret <= 0) goto end;
- /* EAY EAY EAY need to check for DH fix cert
- * sent back */
- /* For TLS, cert_req is set to 2, so a cert chain
- * of nothing is sent, but no verify packet is sent */
- /* XXX: For now, we do not support client
- * authentication in ECDH cipher suites with
- * ECDH (rather than ECDSA) certificates.
- * We need to skip the certificate verify
- * message when client's ECDH public key is sent
- * inside the client certificate.
- */
- if (s->s3->tmp.cert_req == 1)
- {
- s->state=SSL3_ST_CW_CERT_VRFY_A;
- }
- else
- {
- s->state=SSL3_ST_CW_CHANGE_A;
- s->s3->change_cipher_spec=0;
- }
- if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
- {
- s->state=SSL3_ST_CW_CHANGE_A;
- s->s3->change_cipher_spec=0;
- }
-
- s->init_num=0;
- break;
-
- case SSL3_ST_CW_CERT_VRFY_A:
- case SSL3_ST_CW_CERT_VRFY_B:
- ret=ssl3_send_client_verify(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CW_CHANGE_A;
- s->init_num=0;
- s->s3->change_cipher_spec=0;
- break;
-
- case SSL3_ST_CW_CHANGE_A:
- case SSL3_ST_CW_CHANGE_B:
- ret=ssl3_send_change_cipher_spec(s,
- SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
- if (ret <= 0) goto end;
-
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
- s->state=SSL3_ST_CW_FINISHED_A;
-#else
- if (s->s3->next_proto_neg_seen)
- s->state=SSL3_ST_CW_NEXT_PROTO_A;
- else
- s->state=SSL3_ST_CW_FINISHED_A;
-#endif
- s->init_num=0;
-
- s->session->cipher=s->s3->tmp.new_cipher;
-#ifdef OPENSSL_NO_COMP
- s->session->compress_meth=0;
-#else
- if (s->s3->tmp.new_compression == NULL)
- s->session->compress_meth=0;
- else
- s->session->compress_meth=
- s->s3->tmp.new_compression->id;
-#endif
- if (!s->method->ssl3_enc->setup_key_block(s))
- {
- ret= -1;
- goto end;
- }
-
- if (!s->method->ssl3_enc->change_cipher_state(s,
- SSL3_CHANGE_CIPHER_CLIENT_WRITE))
- {
- ret= -1;
- goto end;
- }
-
- break;
-
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
- case SSL3_ST_CW_NEXT_PROTO_A:
- case SSL3_ST_CW_NEXT_PROTO_B:
- ret=ssl3_send_next_proto(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CW_FINISHED_A;
- break;
-#endif
-
- case SSL3_ST_CW_FINISHED_A:
- case SSL3_ST_CW_FINISHED_B:
- ret=ssl3_send_finished(s,
- SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B,
- s->method->ssl3_enc->client_finished_label,
- s->method->ssl3_enc->client_finished_label_len);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CW_FLUSH;
-
- /* clear flags */
- s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER;
- if (s->hit)
- {
- s->s3->tmp.next_state=SSL_ST_OK;
- if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)
- {
- s->state=SSL_ST_OK;
- s->s3->flags|=SSL3_FLAGS_POP_BUFFER;
- s->s3->delay_buf_pop_ret=0;
- }
- }
- else
- {
-#ifndef OPENSSL_NO_TLSEXT
- /* Allow NewSessionTicket if ticket expected */
- if (s->tlsext_ticket_expected)
- s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
- else
-#endif
-
- s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
- }
- s->init_num=0;
- break;
-
-#ifndef OPENSSL_NO_TLSEXT
- case SSL3_ST_CR_SESSION_TICKET_A:
- case SSL3_ST_CR_SESSION_TICKET_B:
- ret=ssl3_get_new_session_ticket(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CR_FINISHED_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_CR_CERT_STATUS_A:
- case SSL3_ST_CR_CERT_STATUS_B:
- ret=ssl3_get_cert_status(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_CR_KEY_EXCH_A;
- s->init_num=0;
- break;
-#endif
-
- case SSL3_ST_CR_FINISHED_A:
- case SSL3_ST_CR_FINISHED_B:
-
- ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
- SSL3_ST_CR_FINISHED_B);
- if (ret <= 0) goto end;
-
- if (s->hit)
- s->state=SSL3_ST_CW_CHANGE_A;
- else
- s->state=SSL_ST_OK;
- s->init_num=0;
- break;
-
- case SSL3_ST_CW_FLUSH:
- s->rwstate=SSL_WRITING;
- if (BIO_flush(s->wbio) <= 0)
- {
- ret= -1;
- goto end;
- }
- s->rwstate=SSL_NOTHING;
- s->state=s->s3->tmp.next_state;
- break;
-
- case SSL_ST_OK:
- /* clean a few things up */
- ssl3_cleanup_key_block(s);
-
- if (s->init_buf != NULL)
- {
- BUF_MEM_free(s->init_buf);
- s->init_buf=NULL;
- }
-
- /* If we are not 'joining' the last two packets,
- * remove the buffering now */
- if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER))
- ssl_free_wbio_buffer(s);
- /* else do it later in ssl3_write */
-
- s->init_num=0;
- s->renegotiate=0;
- s->new_session=0;
-
- ssl_update_cache(s,SSL_SESS_CACHE_CLIENT);
- if (s->hit) s->ctx->stats.sess_hit++;
-
- ret=1;
- /* s->server=0; */
- s->handshake_func=ssl3_connect;
- s->ctx->stats.sess_connect_good++;
-
- if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
-
- goto end;
- /* break; */
-
- default:
- SSLerr(SSL_F_SSL3_CONNECT,SSL_R_UNKNOWN_STATE);
- ret= -1;
- goto end;
- /* break; */
- }
-
- /* did we do anything */
- if (!s->s3->tmp.reuse_message && !skip)
- {
- if (s->debug)
- {
- if ((ret=BIO_flush(s->wbio)) <= 0)
- goto end;
- }
-
- if ((cb != NULL) && (s->state != state))
- {
- new_state=s->state;
- s->state=state;
- cb(s,SSL_CB_CONNECT_LOOP,1);
- s->state=new_state;
- }
- }
- skip=0;
- }
-end:
- s->in_handshake--;
- if (buf != NULL)
- BUF_MEM_free(buf);
- if (cb != NULL)
- cb(s,SSL_CB_CONNECT_EXIT,ret);
- return(ret);
- }
-
-
-int ssl3_client_hello(SSL *s)
- {
- unsigned char *buf;
- unsigned char *p,*d;
- int i;
- unsigned long l;
-#ifndef OPENSSL_NO_COMP
- int j;
- SSL_COMP *comp;
-#endif
-
- buf=(unsigned char *)s->init_buf->data;
- if (s->state == SSL3_ST_CW_CLNT_HELLO_A)
- {
- SSL_SESSION *sess = s->session;
- if ((sess == NULL) ||
- (sess->ssl_version != s->version) ||
-#ifdef OPENSSL_NO_TLSEXT
- !sess->session_id_length ||
-#else
- (!sess->session_id_length && !sess->tlsext_tick) ||
-#endif
- (sess->not_resumable))
- {
- if (!ssl_get_new_session(s,0))
- goto err;
- }
- /* else use the pre-loaded session */
-
- p=s->s3->client_random;
-
- if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0)
- goto err;
-
- /* Do the message type and length last */
- d=p= &(buf[4]);
-
- /* version indicates the negotiated version: for example from
- * an SSLv2/v3 compatible client hello). The client_version
- * field is the maximum version we permit and it is also
- * used in RSA encrypted premaster secrets. Some servers can
- * choke if we initially report a higher version then
- * renegotiate to a lower one in the premaster secret. This
- * didn't happen with TLS 1.0 as most servers supported it
- * but it can with TLS 1.1 or later if the server only supports
- * 1.0.
- *
- * Possible scenario with previous logic:
- * 1. Client hello indicates TLS 1.2
- * 2. Server hello says TLS 1.0
- * 3. RSA encrypted premaster secret uses 1.2.
- * 4. Handhaked proceeds using TLS 1.0.
- * 5. Server sends hello request to renegotiate.
- * 6. Client hello indicates TLS v1.0 as we now
- * know that is maximum server supports.
- * 7. Server chokes on RSA encrypted premaster secret
- * containing version 1.0.
- *
- * For interoperability it should be OK to always use the
- * maximum version we support in client hello and then rely
- * on the checking of version to ensure the servers isn't
- * being inconsistent: for example initially negotiating with
- * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
- * client_version in client hello and not resetting it to
- * the negotiated version.
- */
-#if 0
- *(p++)=s->version>>8;
- *(p++)=s->version&0xff;
- s->client_version=s->version;
-#else
- *(p++)=s->client_version>>8;
- *(p++)=s->client_version&0xff;
-#endif
-
- /* Random stuff */
- memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
- p+=SSL3_RANDOM_SIZE;
-
- /* Session ID */
- if (s->new_session)
- i=0;
- else
- i=s->session->session_id_length;
- *(p++)=i;
- if (i != 0)
- {
- if (i > (int)sizeof(s->session->session_id))
- {
- SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- memcpy(p,s->session->session_id,i);
- p+=i;
- }
-
- /* Ciphers supported */
- i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),0);
- if (i == 0)
- {
- SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
- goto err;
- }
-#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
- /* Some servers hang if client hello > 256 bytes
- * as hack workaround chop number of supported ciphers
- * to keep it well below this if we use TLS v1.2
- */
- if (TLS1_get_version(s) >= TLS1_2_VERSION
- && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
- i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
-#endif
- s2n(i,p);
- p+=i;
-
- /* COMPRESSION */
-#ifdef OPENSSL_NO_COMP
- *(p++)=1;
-#else
-
- if ((s->options & SSL_OP_NO_COMPRESSION)
- || !s->ctx->comp_methods)
- j=0;
- else
- j=sk_SSL_COMP_num(s->ctx->comp_methods);
- *(p++)=1+j;
- for (i=0; i<j; i++)
- {
- comp=sk_SSL_COMP_value(s->ctx->comp_methods,i);
- *(p++)=comp->id;
- }
-#endif
- *(p++)=0; /* Add the NULL method */
-
-#ifndef OPENSSL_NO_TLSEXT
- /* TLS extensions*/
- if (ssl_prepare_clienthello_tlsext(s) <= 0)
- {
- SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
- if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
- {
- SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
- goto err;
- }
-#endif
-
- l=(p-d);
- d=buf;
- *(d++)=SSL3_MT_CLIENT_HELLO;
- l2n3(l,d);
-
- s->state=SSL3_ST_CW_CLNT_HELLO_B;
- /* number of bytes to write */
- s->init_num=p-buf;
- s->init_off=0;
- }
-
- /* SSL3_ST_CW_CLNT_HELLO_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
-err:
- return(-1);
- }
-
-int ssl3_get_server_hello(SSL *s)
- {
- STACK_OF(SSL_CIPHER) *sk;
- const SSL_CIPHER *c;
- unsigned char *p,*d;
- int i,al,ok;
- unsigned int j;
- long n;
-#ifndef OPENSSL_NO_COMP
- SSL_COMP *comp;
-#endif
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_CR_SRVR_HELLO_A,
- SSL3_ST_CR_SRVR_HELLO_B,
- -1,
- 20000, /* ?? */
- &ok);
-
- if (!ok) return((int)n);
-
- if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
- {
- if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
- {
- if ( s->d1->send_cookie == 0)
- {
- s->s3->tmp.reuse_message = 1;
- return 1;
- }
- else /* already sent a cookie */
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_MESSAGE_TYPE);
- goto f_err;
- }
- }
- }
-
- if ( s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO)
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_MESSAGE_TYPE);
- goto f_err;
- }
-
- d=p=(unsigned char *)s->init_msg;
-
- if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff)))
- {
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_SSL_VERSION);
- s->version=(s->version&0xff00)|p[1];
- al=SSL_AD_PROTOCOL_VERSION;
- goto f_err;
- }
- p+=2;
-
- /* load the server hello data */
- /* load the server random */
- memcpy(s->s3->server_random,p,SSL3_RANDOM_SIZE);
- p+=SSL3_RANDOM_SIZE;
-
- /* get the session-id */
- j= *(p++);
-
- if ((j > sizeof s->session->session_id) || (j > SSL3_SESSION_ID_SIZE))
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SSL3_SESSION_ID_TOO_LONG);
- goto f_err;
- }
-
-#ifndef OPENSSL_NO_TLSEXT
- /* check if we want to resume the session based on external pre-shared secret */
- if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
- {
- SSL_CIPHER *pref_cipher=NULL;
- s->session->master_key_length=sizeof(s->session->master_key);
- if (s->tls_session_secret_cb(s, s->session->master_key,
- &s->session->master_key_length,
- NULL, &pref_cipher,
- s->tls_session_secret_cb_arg))
- {
- s->session->cipher = pref_cipher ?
- pref_cipher : ssl_get_cipher_by_char(s, p+j);
- }
- }
-#endif /* OPENSSL_NO_TLSEXT */
-
- if (j != 0 && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
- if(s->sid_ctx_length != s->session->sid_ctx_length
- || memcmp(s->session->sid_ctx,s->sid_ctx,s->sid_ctx_length))
- {
- /* actually a client application bug */
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
- goto f_err;
- }
- s->hit=1;
- }
- else /* a miss or crap from the other end */
- {
- /* If we were trying for session-id reuse, make a new
- * SSL_SESSION so we don't stuff up other people */
- s->hit=0;
- if (s->session->session_id_length > 0)
- {
- if (!ssl_get_new_session(s,0))
- {
- al=SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
- }
- s->session->session_id_length=j;
- memcpy(s->session->session_id,p,j); /* j could be 0 */
- }
- p+=j;
- c=ssl_get_cipher_by_char(s,p);
- if (c == NULL)
- {
- /* unknown cipher */
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
- goto f_err;
- }
- /* TLS v1.2 only ciphersuites require v1.2 or later */
- if ((c->algorithm_ssl & SSL_TLSV1_2) &&
- (TLS1_get_version(s) < TLS1_2_VERSION))
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
- goto f_err;
- }
- p+=ssl_put_cipher_by_char(s,NULL,NULL);
-
- sk=ssl_get_ciphers_by_id(s);
- i=sk_SSL_CIPHER_find(sk,c);
- if (i < 0)
- {
- /* we did not say we would use this cipher */
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
- goto f_err;
- }
-
- /* Depending on the session caching (internal/external), the cipher
- and/or cipher_id values may not be set. Make sure that
- cipher_id is set and use it for comparison. */
- if (s->session->cipher)
- s->session->cipher_id = s->session->cipher->id;
- if (s->hit && (s->session->cipher_id != c->id))
- {
-/* Workaround is now obsolete */
-#if 0
- if (!(s->options &
- SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG))
-#endif
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
- goto f_err;
- }
- }
- s->s3->tmp.new_cipher=c;
- /* Don't digest cached records if TLS v1.2: we may need them for
- * client authentication.
- */
- if (TLS1_get_version(s) < TLS1_2_VERSION && !ssl3_digest_cached_records(s))
- {
- al = SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
- /* lets get the compression algorithm */
- /* COMPRESSION */
-#ifdef OPENSSL_NO_COMP
- if (*(p++) != 0)
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
- goto f_err;
- }
- /* If compression is disabled we'd better not try to resume a session
- * using compression.
- */
- if (s->session->compress_meth != 0)
- {
- al=SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
- goto f_err;
- }
-#else
- j= *(p++);
- if (s->hit && j != s->session->compress_meth)
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
- goto f_err;
- }
- if (j == 0)
- comp=NULL;
- else if (s->options & SSL_OP_NO_COMPRESSION)
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_COMPRESSION_DISABLED);
- goto f_err;
- }
- else
- comp=ssl3_comp_find(s->ctx->comp_methods,j);
-
- if ((j != 0) && (comp == NULL))
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
- goto f_err;
- }
- else
- {
- s->s3->tmp.new_compression=comp;
- }
-#endif
-
-#ifndef OPENSSL_NO_TLSEXT
- /* TLS extensions*/
- if (s->version >= SSL3_VERSION)
- {
- if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
- {
- /* 'al' set by ssl_parse_serverhello_tlsext */
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
- goto f_err;
- }
- if (ssl_check_serverhello_tlsext(s) <= 0)
- {
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
- goto err;
- }
- }
-#endif
-
- if (p != (d+n))
- {
- /* wrong packet length */
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_PACKET_LENGTH);
- goto f_err;
- }
-
- return(1);
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
- return(-1);
- }
-
-int ssl3_get_server_certificate(SSL *s)
- {
- int al,i,ok,ret= -1;
- unsigned long n,nc,llen,l;
- X509 *x=NULL;
- const unsigned char *q,*p;
- unsigned char *d;
- STACK_OF(X509) *sk=NULL;
- SESS_CERT *sc;
- EVP_PKEY *pkey=NULL;
- int need_cert = 1; /* VRS: 0=> will allow null cert if auth == KRB5 */
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_CR_CERT_A,
- SSL3_ST_CR_CERT_B,
- -1,
- s->max_cert_list,
- &ok);
-
- if (!ok) return((int)n);
-
- if ((s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) ||
- ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) &&
- (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)))
- {
- s->s3->tmp.reuse_message=1;
- return(1);
- }
-
- if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_BAD_MESSAGE_TYPE);
- goto f_err;
- }
- p=d=(unsigned char *)s->init_msg;
-
- if ((sk=sk_X509_new_null()) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- n2l3(p,llen);
- if (llen+3 != n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
- for (nc=0; nc<llen; )
- {
- n2l3(p,l);
- if ((l+nc+3) > llen)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
- goto f_err;
- }
-
- q=p;
- x=d2i_X509(NULL,&q,l);
- if (x == NULL)
- {
- al=SSL_AD_BAD_CERTIFICATE;
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,ERR_R_ASN1_LIB);
- goto f_err;
- }
- if (q != (p+l))
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
- goto f_err;
- }
- if (!sk_X509_push(sk,x))
- {
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- x=NULL;
- nc+=l+3;
- p=q;
- }
-
- i=ssl_verify_cert_chain(s,sk);
- if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0)
-#ifndef OPENSSL_NO_KRB5
- && !((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
- (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
-#endif /* OPENSSL_NO_KRB5 */
- )
- {
- al=ssl_verify_alarm_type(s->verify_result);
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_CERTIFICATE_VERIFY_FAILED);
- goto f_err;
- }
- ERR_clear_error(); /* but we keep s->verify_result */
-
- sc=ssl_sess_cert_new();
- if (sc == NULL) goto err;
-
- if (s->session->sess_cert) ssl_sess_cert_free(s->session->sess_cert);
- s->session->sess_cert=sc;
-
- sc->cert_chain=sk;
- /* Inconsistency alert: cert_chain does include the peer's
- * certificate, which we don't include in s3_srvr.c */
- x=sk_X509_value(sk,0);
- sk=NULL;
- /* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end*/
-
- pkey=X509_get_pubkey(x);
-
- /* VRS: allow null cert if auth == KRB5 */
- need_cert = ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
- (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
- ? 0 : 1;
-
-#ifdef KSSL_DEBUG
- printf("pkey,x = %p, %p\n", pkey,x);
- printf("ssl_cert_type(x,pkey) = %d\n", ssl_cert_type(x,pkey));
- printf("cipher, alg, nc = %s, %lx, %lx, %d\n", s->s3->tmp.new_cipher->name,
- s->s3->tmp.new_cipher->algorithm_mkey, s->s3->tmp.new_cipher->algorithm_auth, need_cert);
-#endif /* KSSL_DEBUG */
-
- if (need_cert && ((pkey == NULL) || EVP_PKEY_missing_parameters(pkey)))
- {
- x=NULL;
- al=SSL3_AL_FATAL;
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
- SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
- goto f_err;
- }
-
- i=ssl_cert_type(x,pkey);
- if (need_cert && i < 0)
- {
- x=NULL;
- al=SSL3_AL_FATAL;
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
- SSL_R_UNKNOWN_CERTIFICATE_TYPE);
- goto f_err;
- }
-
- if (need_cert)
- {
- sc->peer_cert_type=i;
- CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
- /* Why would the following ever happen?
- * We just created sc a couple of lines ago. */
- if (sc->peer_pkeys[i].x509 != NULL)
- X509_free(sc->peer_pkeys[i].x509);
- sc->peer_pkeys[i].x509=x;
- sc->peer_key= &(sc->peer_pkeys[i]);
-
- if (s->session->peer != NULL)
- X509_free(s->session->peer);
- CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
- s->session->peer=x;
- }
- else
- {
- sc->peer_cert_type=i;
- sc->peer_key= NULL;
-
- if (s->session->peer != NULL)
- X509_free(s->session->peer);
- s->session->peer=NULL;
- }
- s->session->verify_result = s->verify_result;
-
- x=NULL;
- ret=1;
-
- if (0)
- {
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- }
-err:
- EVP_PKEY_free(pkey);
- X509_free(x);
- sk_X509_pop_free(sk,X509_free);
- return(ret);
- }
-
-int ssl3_get_key_exchange(SSL *s)
- {
-#ifndef OPENSSL_NO_RSA
- unsigned char *q,md_buf[EVP_MAX_MD_SIZE*2];
-#endif
- EVP_MD_CTX md_ctx;
- unsigned char *param,*p;
- int al,i,j,param_len,ok;
- long n,alg_k,alg_a;
- EVP_PKEY *pkey=NULL;
- const EVP_MD *md = NULL;
-#ifndef OPENSSL_NO_RSA
- RSA *rsa=NULL;
-#endif
-#ifndef OPENSSL_NO_DH
- DH *dh=NULL;
-#endif
-#ifndef OPENSSL_NO_ECDH
- EC_KEY *ecdh = NULL;
- BN_CTX *bn_ctx = NULL;
- EC_POINT *srvr_ecpoint = NULL;
- int curve_nid = 0;
- int encoded_pt_len = 0;
-#endif
-
- /* use same message size as in ssl3_get_certificate_request()
- * as ServerKeyExchange message may be skipped */
- n=s->method->ssl_get_message(s,
- SSL3_ST_CR_KEY_EXCH_A,
- SSL3_ST_CR_KEY_EXCH_B,
- -1,
- s->max_cert_list,
- &ok);
- if (!ok) return((int)n);
-
- if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE)
- {
-#ifndef OPENSSL_NO_PSK
- /* In plain PSK ciphersuite, ServerKeyExchange can be
- omitted if no identity hint is sent. Set
- session->sess_cert anyway to avoid problems
- later.*/
- if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
- {
- s->session->sess_cert=ssl_sess_cert_new();
- if (s->ctx->psk_identity_hint)
- OPENSSL_free(s->ctx->psk_identity_hint);
- s->ctx->psk_identity_hint = NULL;
- }
-#endif
- s->s3->tmp.reuse_message=1;
- return(1);
- }
-
- param=p=(unsigned char *)s->init_msg;
- if (s->session->sess_cert != NULL)
- {
-#ifndef OPENSSL_NO_RSA
- if (s->session->sess_cert->peer_rsa_tmp != NULL)
- {
- RSA_free(s->session->sess_cert->peer_rsa_tmp);
- s->session->sess_cert->peer_rsa_tmp=NULL;
- }
-#endif
-#ifndef OPENSSL_NO_DH
- if (s->session->sess_cert->peer_dh_tmp)
- {
- DH_free(s->session->sess_cert->peer_dh_tmp);
- s->session->sess_cert->peer_dh_tmp=NULL;
- }
-#endif
-#ifndef OPENSSL_NO_ECDH
- if (s->session->sess_cert->peer_ecdh_tmp)
- {
- EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
- s->session->sess_cert->peer_ecdh_tmp=NULL;
- }
-#endif
- }
- else
- {
- s->session->sess_cert=ssl_sess_cert_new();
- }
-
- param_len=0;
- alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
- alg_a=s->s3->tmp.new_cipher->algorithm_auth;
- EVP_MD_CTX_init(&md_ctx);
-
-#ifndef OPENSSL_NO_PSK
- if (alg_k & SSL_kPSK)
- {
- char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1];
-
- al=SSL_AD_HANDSHAKE_FAILURE;
- n2s(p,i);
- param_len=i+2;
- /* Store PSK identity hint for later use, hint is used
- * in ssl3_send_client_key_exchange. Assume that the
- * maximum length of a PSK identity hint can be as
- * long as the maximum length of a PSK identity. */
- if (i > PSK_MAX_IDENTITY_LEN)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
- SSL_R_DATA_LENGTH_TOO_LONG);
- goto f_err;
- }
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
- SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH);
- goto f_err;
- }
- /* If received PSK identity hint contains NULL
- * characters, the hint is truncated from the first
- * NULL. p may not be ending with NULL, so create a
- * NULL-terminated string. */
- memcpy(tmp_id_hint, p, i);
- memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
- if (s->ctx->psk_identity_hint != NULL)
- OPENSSL_free(s->ctx->psk_identity_hint);
- s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
- if (s->ctx->psk_identity_hint == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
- goto f_err;
- }
-
- p+=i;
- n-=param_len;
- }
- else
-#endif /* !OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_SRP
- if (alg_k & SSL_kSRP)
- {
- n2s(p,i);
- param_len=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_N_LENGTH);
- goto f_err;
- }
- if (!(s->srp_ctx.N=BN_bin2bn(p,i,NULL)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
-
- n2s(p,i);
- param_len+=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_G_LENGTH);
- goto f_err;
- }
- if (!(s->srp_ctx.g=BN_bin2bn(p,i,NULL)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
-
- i = (unsigned int)(p[0]);
- p++;
- param_len+=i+1;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_S_LENGTH);
- goto f_err;
- }
- if (!(s->srp_ctx.s=BN_bin2bn(p,i,NULL)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
-
- n2s(p,i);
- param_len+=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_B_LENGTH);
- goto f_err;
- }
- if (!(s->srp_ctx.B=BN_bin2bn(p,i,NULL)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
- n-=param_len;
-
-/* We must check if there is a certificate */
-#ifndef OPENSSL_NO_RSA
- if (alg_a & SSL_aRSA)
- pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
-#else
- if (0)
- ;
-#endif
-#ifndef OPENSSL_NO_DSA
- else if (alg_a & SSL_aDSS)
- pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
-#endif
- }
- else
-#endif /* !OPENSSL_NO_SRP */
-#ifndef OPENSSL_NO_RSA
- if (alg_k & SSL_kRSA)
- {
- if ((rsa=RSA_new()) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- n2s(p,i);
- param_len=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_MODULUS_LENGTH);
- goto f_err;
- }
- if (!(rsa->n=BN_bin2bn(p,i,rsa->n)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
-
- n2s(p,i);
- param_len+=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_E_LENGTH);
- goto f_err;
- }
- if (!(rsa->e=BN_bin2bn(p,i,rsa->e)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
- n-=param_len;
-
- /* this should be because we are using an export cipher */
- if (alg_a & SSL_aRSA)
- pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
- else
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto err;
- }
- s->session->sess_cert->peer_rsa_tmp=rsa;
- rsa=NULL;
- }
-#else /* OPENSSL_NO_RSA */
- if (0)
- ;
-#endif
-#ifndef OPENSSL_NO_DH
- else if (alg_k & SSL_kEDH)
- {
- if ((dh=DH_new()) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_DH_LIB);
- goto err;
- }
- n2s(p,i);
- param_len=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_P_LENGTH);
- goto f_err;
- }
- if (!(dh->p=BN_bin2bn(p,i,NULL)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
-
- n2s(p,i);
- param_len+=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_G_LENGTH);
- goto f_err;
- }
- if (!(dh->g=BN_bin2bn(p,i,NULL)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
-
- n2s(p,i);
- param_len+=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_PUB_KEY_LENGTH);
- goto f_err;
- }
- if (!(dh->pub_key=BN_bin2bn(p,i,NULL)))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- p+=i;
- n-=param_len;
-
-#ifndef OPENSSL_NO_RSA
- if (alg_a & SSL_aRSA)
- pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
-#else
- if (0)
- ;
-#endif
-#ifndef OPENSSL_NO_DSA
- else if (alg_a & SSL_aDSS)
- pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
-#endif
- /* else anonymous DH, so no certificate or pkey. */
-
- s->session->sess_cert->peer_dh_tmp=dh;
- dh=NULL;
- }
- else if ((alg_k & SSL_kDHr) || (alg_k & SSL_kDHd))
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER);
- goto f_err;
- }
-#endif /* !OPENSSL_NO_DH */
-
-#ifndef OPENSSL_NO_ECDH
- else if (alg_k & SSL_kEECDH)
- {
- EC_GROUP *ngroup;
- const EC_GROUP *group;
-
- if ((ecdh=EC_KEY_new()) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* Extract elliptic curve parameters and the
- * server's ephemeral ECDH public key.
- * Keep accumulating lengths of various components in
- * param_len and make sure it never exceeds n.
- */
-
- /* XXX: For now we only support named (not generic) curves
- * and the ECParameters in this case is just three bytes.
- */
- param_len=3;
- if ((param_len > n) ||
- (*p != NAMED_CURVE_TYPE) ||
- ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0))
- {
- al=SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
- goto f_err;
- }
-
- ngroup = EC_GROUP_new_by_curve_name(curve_nid);
- if (ngroup == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_EC_LIB);
- goto err;
- }
- if (EC_KEY_set_group(ecdh, ngroup) == 0)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_EC_LIB);
- goto err;
- }
- EC_GROUP_free(ngroup);
-
- group = EC_KEY_get0_group(ecdh);
-
- if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
- (EC_GROUP_get_degree(group) > 163))
- {
- al=SSL_AD_EXPORT_RESTRICTION;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
- goto f_err;
- }
-
- p+=3;
-
- /* Next, get the encoded ECPoint */
- if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) ||
- ((bn_ctx = BN_CTX_new()) == NULL))
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- encoded_pt_len = *p; /* length of encoded point */
- p+=1;
- param_len += (1 + encoded_pt_len);
- if ((param_len > n) ||
- (EC_POINT_oct2point(group, srvr_ecpoint,
- p, encoded_pt_len, bn_ctx) == 0))
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_ECPOINT);
- goto f_err;
- }
-
- n-=param_len;
- p+=encoded_pt_len;
-
- /* The ECC/TLS specification does not mention
- * the use of DSA to sign ECParameters in the server
- * key exchange message. We do support RSA and ECDSA.
- */
- if (0) ;
-#ifndef OPENSSL_NO_RSA
- else if (alg_a & SSL_aRSA)
- pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
-#endif
-#ifndef OPENSSL_NO_ECDSA
- else if (alg_a & SSL_aECDSA)
- pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
-#endif
- /* else anonymous ECDH, so no certificate or pkey. */
- EC_KEY_set_public_key(ecdh, srvr_ecpoint);
- s->session->sess_cert->peer_ecdh_tmp=ecdh;
- ecdh=NULL;
- BN_CTX_free(bn_ctx);
- bn_ctx = NULL;
- EC_POINT_free(srvr_ecpoint);
- srvr_ecpoint = NULL;
- }
- else if (alg_k)
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
- goto f_err;
- }
-#endif /* !OPENSSL_NO_ECDH */
-
-
- /* p points to the next byte, there are 'n' bytes left */
-
- /* if it was signed, check the signature */
- if (pkey != NULL)
- {
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- {
- int sigalg = tls12_get_sigid(pkey);
- /* Should never happen */
- if (sigalg == -1)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto err;
- }
- /* Check key type is consistent with signature */
- if (sigalg != (int)p[1])
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE);
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- md = tls12_get_hash(p[0]);
- if (md == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
-#ifdef SSL_DEBUG
-fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
-#endif
- p += 2;
- n -= 2;
- }
- else
- md = EVP_sha1();
-
- n2s(p,i);
- n-=2;
- j=EVP_PKEY_size(pkey);
-
- if ((i != n) || (n > j) || (n <= 0))
- {
- /* wrong packet length */
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_LENGTH);
- goto f_err;
- }
-
-#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA && TLS1_get_version(s) < TLS1_2_VERSION)
- {
- int num;
-
- j=0;
- q=md_buf;
- for (num=2; num > 0; num--)
- {
- EVP_MD_CTX_set_flags(&md_ctx,
- EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
- EVP_DigestInit_ex(&md_ctx,(num == 2)
- ?s->ctx->md5:s->ctx->sha1, NULL);
- EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_DigestUpdate(&md_ctx,param,param_len);
- EVP_DigestFinal_ex(&md_ctx,q,(unsigned int *)&i);
- q+=i;
- j+=i;
- }
- i=RSA_verify(NID_md5_sha1, md_buf, j, p, n,
- pkey->pkey.rsa);
- if (i < 0)
- {
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT);
- goto f_err;
- }
- if (i == 0)
- {
- /* bad signature */
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE);
- goto f_err;
- }
- }
- else
-#endif
- {
- EVP_VerifyInit_ex(&md_ctx, md, NULL);
- EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_VerifyUpdate(&md_ctx,param,param_len);
- if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0)
- {
- /* bad signature */
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE);
- goto f_err;
- }
- }
- }
- else
- {
- if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
- /* aNULL or kPSK do not need public keys */
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto err;
- }
- /* still data left over */
- if (n != 0)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_EXTRA_DATA_IN_MESSAGE);
- goto f_err;
- }
- }
- EVP_PKEY_free(pkey);
- EVP_MD_CTX_cleanup(&md_ctx);
- return(1);
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
- EVP_PKEY_free(pkey);
-#ifndef OPENSSL_NO_RSA
- if (rsa != NULL)
- RSA_free(rsa);
-#endif
-#ifndef OPENSSL_NO_DH
- if (dh != NULL)
- DH_free(dh);
-#endif
-#ifndef OPENSSL_NO_ECDH
- BN_CTX_free(bn_ctx);
- EC_POINT_free(srvr_ecpoint);
- if (ecdh != NULL)
- EC_KEY_free(ecdh);
-#endif
- EVP_MD_CTX_cleanup(&md_ctx);
- return(-1);
- }
-
-int ssl3_get_certificate_request(SSL *s)
- {
- int ok,ret=0;
- unsigned long n,nc,l;
- unsigned int llen, ctype_num,i;
- X509_NAME *xn=NULL;
- const unsigned char *p,*q;
- unsigned char *d;
- STACK_OF(X509_NAME) *ca_sk=NULL;
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_CR_CERT_REQ_A,
- SSL3_ST_CR_CERT_REQ_B,
- -1,
- s->max_cert_list,
- &ok);
-
- if (!ok) return((int)n);
-
- s->s3->tmp.cert_req=0;
-
- if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)
- {
- s->s3->tmp.reuse_message=1;
- /* If we get here we don't need any cached handshake records
- * as we wont be doing client auth.
- */
- if (s->s3->handshake_buffer)
- {
- if (!ssl3_digest_cached_records(s))
- goto err;
- }
- return(1);
- }
-
- if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST)
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_WRONG_MESSAGE_TYPE);
- goto err;
- }
-
- /* TLS does not like anon-DH with client cert */
- if (s->version > SSL3_VERSION)
- {
- if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER);
- goto err;
- }
- }
-
- p=d=(unsigned char *)s->init_msg;
-
- if ((ca_sk=sk_X509_NAME_new(ca_dn_cmp)) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* get the certificate types */
- ctype_num= *(p++);
- if (ctype_num > SSL3_CT_NUMBER)
- ctype_num=SSL3_CT_NUMBER;
- for (i=0; i<ctype_num; i++)
- s->s3->tmp.ctype[i]= p[i];
- p+=ctype_num;
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- {
- n2s(p, llen);
- /* Check we have enough room for signature algorithms and
- * following length value.
- */
- if ((unsigned long)(p - d + llen + 2) > n)
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_DATA_LENGTH_TOO_LONG);
- goto err;
- }
- if ((llen & 1) || !tls1_process_sigalgs(s, p, llen))
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_SIGNATURE_ALGORITHMS_ERROR);
- goto err;
- }
- p += llen;
- }
-
- /* get the CA RDNs */
- n2s(p,llen);
-#if 0
-{
-FILE *out;
-out=fopen("/tmp/vsign.der","w");
-fwrite(p,1,llen,out);
-fclose(out);
-}
-#endif
-
- if ((unsigned long)(p - d + llen) != n)
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_LENGTH_MISMATCH);
- goto err;
- }
-
- for (nc=0; nc<llen; )
- {
- n2s(p,l);
- if ((l+nc+2) > llen)
- {
- if ((s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
- goto cont; /* netscape bugs */
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_CA_DN_TOO_LONG);
- goto err;
- }
-
- q=p;
-
- if ((xn=d2i_X509_NAME(NULL,&q,l)) == NULL)
- {
- /* If netscape tolerance is on, ignore errors */
- if (s->options & SSL_OP_NETSCAPE_CA_DN_BUG)
- goto cont;
- else
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,ERR_R_ASN1_LIB);
- goto err;
- }
- }
-
- if (q != (p+l))
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_CA_DN_LENGTH_MISMATCH);
- goto err;
- }
- if (!sk_X509_NAME_push(ca_sk,xn))
- {
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- p+=l;
- nc+=l+2;
- }
-
- if (0)
- {
-cont:
- ERR_clear_error();
- }
-
- /* we should setup a certificate to return.... */
- s->s3->tmp.cert_req=1;
- s->s3->tmp.ctype_num=ctype_num;
- if (s->s3->tmp.ca_names != NULL)
- sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
- s->s3->tmp.ca_names=ca_sk;
- ca_sk=NULL;
-
- ret=1;
-err:
- if (ca_sk != NULL) sk_X509_NAME_pop_free(ca_sk,X509_NAME_free);
- return(ret);
- }
-
-static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
- {
- return(X509_NAME_cmp(*a,*b));
- }
-#ifndef OPENSSL_NO_TLSEXT
-int ssl3_get_new_session_ticket(SSL *s)
- {
- int ok,al,ret=0, ticklen;
- long n;
- const unsigned char *p;
- unsigned char *d;
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_CR_SESSION_TICKET_A,
- SSL3_ST_CR_SESSION_TICKET_B,
- -1,
- 16384,
- &ok);
-
- if (!ok)
- return((int)n);
-
- if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
- {
- s->s3->tmp.reuse_message=1;
- return(1);
- }
- if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET)
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_BAD_MESSAGE_TYPE);
- goto f_err;
- }
- if (n < 6)
- {
- /* need at least ticket_lifetime_hint + ticket length */
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
-
- p=d=(unsigned char *)s->init_msg;
- n2l(p, s->session->tlsext_tick_lifetime_hint);
- n2s(p, ticklen);
- /* ticket_lifetime_hint + ticket_length + ticket */
- if (ticklen + 6 != n)
- {
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
- if (s->session->tlsext_tick)
- {
- OPENSSL_free(s->session->tlsext_tick);
- s->session->tlsext_ticklen = 0;
- }
- s->session->tlsext_tick = OPENSSL_malloc(ticklen);
- if (!s->session->tlsext_tick)
- {
- SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- memcpy(s->session->tlsext_tick, p, ticklen);
- s->session->tlsext_ticklen = ticklen;
- /* There are two ways to detect a resumed ticket sesion.
- * One is to set an appropriate session ID and then the server
- * must return a match in ServerHello. This allows the normal
- * client session ID matching to work and we know much
- * earlier that the ticket has been accepted.
- *
- * The other way is to set zero length session ID when the
- * ticket is presented and rely on the handshake to determine
- * session resumption.
- *
- * We choose the former approach because this fits in with
- * assumptions elsewhere in OpenSSL. The session ID is set
- * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the
- * ticket.
- */
- EVP_Digest(p, ticklen,
- s->session->session_id, &s->session->session_id_length,
-#ifndef OPENSSL_NO_SHA256
- EVP_sha256(), NULL);
-#else
- EVP_sha1(), NULL);
-#endif
- ret=1;
- return(ret);
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
- return(-1);
- }
-
-int ssl3_get_cert_status(SSL *s)
- {
- int ok, al;
- unsigned long resplen,n;
- const unsigned char *p;
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_CR_CERT_STATUS_A,
- SSL3_ST_CR_CERT_STATUS_B,
- SSL3_MT_CERTIFICATE_STATUS,
- 16384,
- &ok);
-
- if (!ok) return((int)n);
- if (n < 4)
- {
- /* need at least status type + length */
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
- p = (unsigned char *)s->init_msg;
- if (*p++ != TLSEXT_STATUSTYPE_ocsp)
- {
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_UNSUPPORTED_STATUS_TYPE);
- goto f_err;
- }
- n2l3(p, resplen);
- if (resplen + 4 != n)
- {
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
- if (s->tlsext_ocsp_resp)
- OPENSSL_free(s->tlsext_ocsp_resp);
- s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
- if (!s->tlsext_ocsp_resp)
- {
- al = SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
- goto f_err;
- }
- s->tlsext_ocsp_resplen = resplen;
- if (s->ctx->tlsext_status_cb)
- {
- int ret;
- ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- if (ret == 0)
- {
- al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
- SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_INVALID_STATUS_RESPONSE);
- goto f_err;
- }
- if (ret < 0)
- {
- al = SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
- goto f_err;
- }
- }
- return 1;
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- return(-1);
- }
-#endif
-
-int ssl3_get_server_done(SSL *s)
- {
- int ok,ret=0;
- long n;
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_CR_SRVR_DONE_A,
- SSL3_ST_CR_SRVR_DONE_B,
- SSL3_MT_SERVER_DONE,
- 30, /* should be very small, like 0 :-) */
- &ok);
-
- if (!ok) return((int)n);
- if (n > 0)
- {
- /* should contain no data */
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
- SSLerr(SSL_F_SSL3_GET_SERVER_DONE,SSL_R_LENGTH_MISMATCH);
- return -1;
- }
- ret=1;
- return(ret);
- }
-
-
-int ssl3_send_client_key_exchange(SSL *s)
- {
- unsigned char *p,*d;
- int n;
- unsigned long alg_k;
-#ifndef OPENSSL_NO_RSA
- unsigned char *q;
- EVP_PKEY *pkey=NULL;
-#endif
-#ifndef OPENSSL_NO_KRB5
- KSSL_ERR kssl_err;
-#endif /* OPENSSL_NO_KRB5 */
-#ifndef OPENSSL_NO_ECDH
- EC_KEY *clnt_ecdh = NULL;
- const EC_POINT *srvr_ecpoint = NULL;
- EVP_PKEY *srvr_pub_pkey = NULL;
- unsigned char *encodedPoint = NULL;
- int encoded_pt_len = 0;
- BN_CTX * bn_ctx = NULL;
-#endif
-
- if (s->state == SSL3_ST_CW_KEY_EXCH_A)
- {
- d=(unsigned char *)s->init_buf->data;
- p= &(d[4]);
-
- alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
-
- /* Fool emacs indentation */
- if (0) {}
-#ifndef OPENSSL_NO_RSA
- else if (alg_k & SSL_kRSA)
- {
- RSA *rsa;
- unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
-
- if (s->session->sess_cert->peer_rsa_tmp != NULL)
- rsa=s->session->sess_cert->peer_rsa_tmp;
- else
- {
- pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
- if ((pkey == NULL) ||
- (pkey->type != EVP_PKEY_RSA) ||
- (pkey->pkey.rsa == NULL))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto err;
- }
- rsa=pkey->pkey.rsa;
- EVP_PKEY_free(pkey);
- }
-
- tmp_buf[0]=s->client_version>>8;
- tmp_buf[1]=s->client_version&0xff;
- if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
- goto err;
-
- s->session->master_key_length=sizeof tmp_buf;
-
- q=p;
- /* Fix buf for TLS and beyond */
- if (s->version > SSL3_VERSION)
- p+=2;
- n=RSA_public_encrypt(sizeof tmp_buf,
- tmp_buf,p,rsa,RSA_PKCS1_PADDING);
-#ifdef PKCS1_CHECK
- if (s->options & SSL_OP_PKCS1_CHECK_1) p[1]++;
- if (s->options & SSL_OP_PKCS1_CHECK_2) tmp_buf[0]=0x70;
-#endif
- if (n <= 0)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_ENCRYPT);
- goto err;
- }
-
- /* Fix buf for TLS and beyond */
- if (s->version > SSL3_VERSION)
- {
- s2n(n,q);
- n+=2;
- }
-
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,
- tmp_buf,sizeof tmp_buf);
- OPENSSL_cleanse(tmp_buf,sizeof tmp_buf);
- }
-#endif
-#ifndef OPENSSL_NO_KRB5
- else if (alg_k & SSL_kKRB5)
- {
- krb5_error_code krb5rc;
- KSSL_CTX *kssl_ctx = s->kssl_ctx;
- /* krb5_data krb5_ap_req; */
- krb5_data *enc_ticket;
- krb5_data authenticator, *authp = NULL;
- EVP_CIPHER_CTX ciph_ctx;
- const EVP_CIPHER *enc = NULL;
- unsigned char iv[EVP_MAX_IV_LENGTH];
- unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
- unsigned char epms[SSL_MAX_MASTER_KEY_LENGTH
- + EVP_MAX_IV_LENGTH];
- int padl, outl = sizeof(epms);
-
- EVP_CIPHER_CTX_init(&ciph_ctx);
-
-#ifdef KSSL_DEBUG
- printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
- alg_k, SSL_kKRB5);
-#endif /* KSSL_DEBUG */
-
- authp = NULL;
-#ifdef KRB5SENDAUTH
- if (KRB5SENDAUTH) authp = &authenticator;
-#endif /* KRB5SENDAUTH */
-
- krb5rc = kssl_cget_tkt(kssl_ctx, &enc_ticket, authp,
- &kssl_err);
- enc = kssl_map_enc(kssl_ctx->enctype);
- if (enc == NULL)
- goto err;
-#ifdef KSSL_DEBUG
- {
- printf("kssl_cget_tkt rtn %d\n", krb5rc);
- if (krb5rc && kssl_err.text)
- printf("kssl_cget_tkt kssl_err=%s\n", kssl_err.text);
- }
-#endif /* KSSL_DEBUG */
-
- if (krb5rc)
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,
- SSL_AD_HANDSHAKE_FAILURE);
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- kssl_err.reason);
- goto err;
- }
-
- /* 20010406 VRS - Earlier versions used KRB5 AP_REQ
- ** in place of RFC 2712 KerberosWrapper, as in:
- **
- ** Send ticket (copy to *p, set n = length)
- ** n = krb5_ap_req.length;
- ** memcpy(p, krb5_ap_req.data, krb5_ap_req.length);
- ** if (krb5_ap_req.data)
- ** kssl_krb5_free_data_contents(NULL,&krb5_ap_req);
- **
- ** Now using real RFC 2712 KerberosWrapper
- ** (Thanks to Simon Wilkinson <sxw@sxw.org.uk>)
- ** Note: 2712 "opaque" types are here replaced
- ** with a 2-byte length followed by the value.
- ** Example:
- ** KerberosWrapper= xx xx asn1ticket 0 0 xx xx encpms
- ** Where "xx xx" = length bytes. Shown here with
- ** optional authenticator omitted.
- */
-
- /* KerberosWrapper.Ticket */
- s2n(enc_ticket->length,p);
- memcpy(p, enc_ticket->data, enc_ticket->length);
- p+= enc_ticket->length;
- n = enc_ticket->length + 2;
-
- /* KerberosWrapper.Authenticator */
- if (authp && authp->length)
- {
- s2n(authp->length,p);
- memcpy(p, authp->data, authp->length);
- p+= authp->length;
- n+= authp->length + 2;
-
- free(authp->data);
- authp->data = NULL;
- authp->length = 0;
- }
- else
- {
- s2n(0,p);/* null authenticator length */
- n+=2;
- }
-
- tmp_buf[0]=s->client_version>>8;
- tmp_buf[1]=s->client_version&0xff;
- if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
- goto err;
-
- /* 20010420 VRS. Tried it this way; failed.
- ** EVP_EncryptInit_ex(&ciph_ctx,enc, NULL,NULL);
- ** EVP_CIPHER_CTX_set_key_length(&ciph_ctx,
- ** kssl_ctx->length);
- ** EVP_EncryptInit_ex(&ciph_ctx,NULL, key,iv);
- */
-
- memset(iv, 0, sizeof iv); /* per RFC 1510 */
- EVP_EncryptInit_ex(&ciph_ctx,enc, NULL,
- kssl_ctx->key,iv);
- EVP_EncryptUpdate(&ciph_ctx,epms,&outl,tmp_buf,
- sizeof tmp_buf);
- EVP_EncryptFinal_ex(&ciph_ctx,&(epms[outl]),&padl);
- outl += padl;
- if (outl > (int)sizeof epms)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- EVP_CIPHER_CTX_cleanup(&ciph_ctx);
-
- /* KerberosWrapper.EncryptedPreMasterSecret */
- s2n(outl,p);
- memcpy(p, epms, outl);
- p+=outl;
- n+=outl + 2;
-
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,
- tmp_buf, sizeof tmp_buf);
-
- OPENSSL_cleanse(tmp_buf, sizeof tmp_buf);
- OPENSSL_cleanse(epms, outl);
- }
-#endif
-#ifndef OPENSSL_NO_DH
- else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
- {
- DH *dh_srvr,*dh_clnt;
-
- if (s->session->sess_cert == NULL)
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
- goto err;
- }
-
- if (s->session->sess_cert->peer_dh_tmp != NULL)
- dh_srvr=s->session->sess_cert->peer_dh_tmp;
- else
- {
- /* we get them from the cert */
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
- goto err;
- }
-
- /* generate a new random key */
- if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
- goto err;
- }
- if (!DH_generate_key(dh_clnt))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
- DH_free(dh_clnt);
- goto err;
- }
-
- /* use the 'p' output buffer for the DH key, but
- * make sure to clear it out afterwards */
-
- n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
-
- if (n <= 0)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
- DH_free(dh_clnt);
- goto err;
- }
-
- /* generate master key from the result */
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,p,n);
- /* clean up */
- memset(p,0,n);
-
- /* send off the data */
- n=BN_num_bytes(dh_clnt->pub_key);
- s2n(n,p);
- BN_bn2bin(dh_clnt->pub_key,p);
- n+=2;
-
- DH_free(dh_clnt);
-
- /* perhaps clean things up a bit EAY EAY EAY EAY*/
- }
-#endif
-
-#ifndef OPENSSL_NO_ECDH
- else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
- {
- const EC_GROUP *srvr_group = NULL;
- EC_KEY *tkey;
- int ecdh_clnt_cert = 0;
- int field_size = 0;
-
- /* Did we send out the client's
- * ECDH share for use in premaster
- * computation as part of client certificate?
- * If so, set ecdh_clnt_cert to 1.
- */
- if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->cert != NULL))
- {
- /* XXX: For now, we do not support client
- * authentication using ECDH certificates.
- * To add such support, one needs to add
- * code that checks for appropriate
- * conditions and sets ecdh_clnt_cert to 1.
- * For example, the cert have an ECC
- * key on the same curve as the server's
- * and the key should be authorized for
- * key agreement.
- *
- * One also needs to add code in ssl3_connect
- * to skip sending the certificate verify
- * message.
- *
- * if ((s->cert->key->privatekey != NULL) &&
- * (s->cert->key->privatekey->type ==
- * EVP_PKEY_EC) && ...)
- * ecdh_clnt_cert = 1;
- */
- }
-
- if (s->session->sess_cert->peer_ecdh_tmp != NULL)
- {
- tkey = s->session->sess_cert->peer_ecdh_tmp;
- }
- else
- {
- /* Get the Server Public Key from Cert */
- srvr_pub_pkey = X509_get_pubkey(s->session-> \
- sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
- if ((srvr_pub_pkey == NULL) ||
- (srvr_pub_pkey->type != EVP_PKEY_EC) ||
- (srvr_pub_pkey->pkey.ec == NULL))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- tkey = srvr_pub_pkey->pkey.ec;
- }
-
- srvr_group = EC_KEY_get0_group(tkey);
- srvr_ecpoint = EC_KEY_get0_public_key(tkey);
-
- if ((srvr_group == NULL) || (srvr_ecpoint == NULL))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- if ((clnt_ecdh=EC_KEY_new()) == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!EC_KEY_set_group(clnt_ecdh, srvr_group))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_EC_LIB);
- goto err;
- }
- if (ecdh_clnt_cert)
- {
- /* Reuse key info from our certificate
- * We only need our private key to perform
- * the ECDH computation.
- */
- const BIGNUM *priv_key;
- tkey = s->cert->key->privatekey->pkey.ec;
- priv_key = EC_KEY_get0_private_key(tkey);
- if (priv_key == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (!EC_KEY_set_private_key(clnt_ecdh, priv_key))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_EC_LIB);
- goto err;
- }
- }
- else
- {
- /* Generate a new ECDH key pair */
- if (!(EC_KEY_generate_key(clnt_ecdh)))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
- goto err;
- }
- }
-
- /* use the 'p' output buffer for the ECDH key, but
- * make sure to clear it out afterwards
- */
-
- field_size = EC_GROUP_get_degree(srvr_group);
- if (field_size <= 0)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_ECDH_LIB);
- goto err;
- }
- n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL);
- if (n <= 0)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_ECDH_LIB);
- goto err;
- }
-
- /* generate master key from the result */
- s->session->master_key_length = s->method->ssl3_enc \
- -> generate_master_secret(s,
- s->session->master_key,
- p, n);
-
- memset(p, 0, n); /* clean up */
-
- if (ecdh_clnt_cert)
- {
- /* Send empty client key exch message */
- n = 0;
- }
- else
- {
- /* First check the size of encoding and
- * allocate memory accordingly.
- */
- encoded_pt_len =
- EC_POINT_point2oct(srvr_group,
- EC_KEY_get0_public_key(clnt_ecdh),
- POINT_CONVERSION_UNCOMPRESSED,
- NULL, 0, NULL);
-
- encodedPoint = (unsigned char *)
- OPENSSL_malloc(encoded_pt_len *
- sizeof(unsigned char));
- bn_ctx = BN_CTX_new();
- if ((encodedPoint == NULL) ||
- (bn_ctx == NULL))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* Encode the public key */
- n = EC_POINT_point2oct(srvr_group,
- EC_KEY_get0_public_key(clnt_ecdh),
- POINT_CONVERSION_UNCOMPRESSED,
- encodedPoint, encoded_pt_len, bn_ctx);
-
- *p = n; /* length of encoded point */
- /* Encoded point will be copied here */
- p += 1;
- /* copy the point */
- memcpy((unsigned char *)p, encodedPoint, n);
- /* increment n to account for length field */
- n += 1;
- }
-
- /* Free allocated memory */
- BN_CTX_free(bn_ctx);
- if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
- if (clnt_ecdh != NULL)
- EC_KEY_free(clnt_ecdh);
- EVP_PKEY_free(srvr_pub_pkey);
- }
-#endif /* !OPENSSL_NO_ECDH */
- else if (alg_k & SSL_kGOST)
- {
- /* GOST key exchange message creation */
- EVP_PKEY_CTX *pkey_ctx;
- X509 *peer_cert;
- size_t msglen;
- unsigned int md_len;
- int keytype;
- unsigned char premaster_secret[32],shared_ukm[32], tmp[256];
- EVP_MD_CTX *ukm_hash;
- EVP_PKEY *pub_key;
-
- /* Get server sertificate PKEY and create ctx from it */
- peer_cert=s->session->sess_cert->peer_pkeys[(keytype=SSL_PKEY_GOST01)].x509;
- if (!peer_cert)
- peer_cert=s->session->sess_cert->peer_pkeys[(keytype=SSL_PKEY_GOST94)].x509;
- if (!peer_cert) {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
- goto err;
- }
-
- pkey_ctx=EVP_PKEY_CTX_new(pub_key=X509_get_pubkey(peer_cert),NULL);
- /* If we have send a certificate, and certificate key
-
- * parameters match those of server certificate, use
- * certificate key for key exchange
- */
-
- /* Otherwise, generate ephemeral key pair */
-
- EVP_PKEY_encrypt_init(pkey_ctx);
- /* Generate session key */
- RAND_bytes(premaster_secret,32);
- /* If we have client certificate, use its secret as peer key */
- if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
- if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <=0) {
- /* If there was an error - just ignore it. Ephemeral key
- * would be used
- */
- ERR_clear_error();
- }
- }
- /* Compute shared IV and store it in algorithm-specific
- * context data */
- ukm_hash = EVP_MD_CTX_create();
- EVP_DigestInit(ukm_hash,EVP_get_digestbynid(NID_id_GostR3411_94));
- EVP_DigestUpdate(ukm_hash,s->s3->client_random,SSL3_RANDOM_SIZE);
- EVP_DigestUpdate(ukm_hash,s->s3->server_random,SSL3_RANDOM_SIZE);
- EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
- EVP_MD_CTX_destroy(ukm_hash);
- if (EVP_PKEY_CTX_ctrl(pkey_ctx,-1,EVP_PKEY_OP_ENCRYPT,EVP_PKEY_CTRL_SET_IV,
- 8,shared_ukm)<0) {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- SSL_R_LIBRARY_BUG);
- goto err;
- }
- /* Make GOST keytransport blob message */
- /*Encapsulate it into sequence */
- *(p++)=V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
- msglen=255;
- if (EVP_PKEY_encrypt(pkey_ctx,tmp,&msglen,premaster_secret,32)<0) {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- SSL_R_LIBRARY_BUG);
- goto err;
- }
- if (msglen >= 0x80)
- {
- *(p++)=0x81;
- *(p++)= msglen & 0xff;
- n=msglen+3;
- }
- else
- {
- *(p++)= msglen & 0xff;
- n=msglen+2;
- }
- memcpy(p, tmp, msglen);
- /* Check if pubkey from client certificate was used */
- if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
- {
- /* Set flag "skip certificate verify" */
- s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
- }
- EVP_PKEY_CTX_free(pkey_ctx);
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,premaster_secret,32);
- EVP_PKEY_free(pub_key);
-
- }
-#ifndef OPENSSL_NO_SRP
- else if (alg_k & SSL_kSRP)
- {
- if (s->srp_ctx.A != NULL)
- {
- /* send off the data */
- n=BN_num_bytes(s->srp_ctx.A);
- s2n(n,p);
- BN_bn2bin(s->srp_ctx.A,p);
- n+=2;
- }
- else
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto err;
- }
- if (s->session->srp_username != NULL)
- OPENSSL_free(s->session->srp_username);
- s->session->srp_username = BUF_strdup(s->srp_ctx.login);
- if (s->session->srp_username == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if ((s->session->master_key_length = SRP_generate_client_master_secret(s,s->session->master_key))<0)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto err;
- }
- }
-#endif
-#ifndef OPENSSL_NO_PSK
- else if (alg_k & SSL_kPSK)
- {
- char identity[PSK_MAX_IDENTITY_LEN];
- unsigned char *t = NULL;
- unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
- unsigned int pre_ms_len = 0, psk_len = 0;
- int psk_err = 1;
-
- n = 0;
- if (s->psk_client_callback == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- SSL_R_PSK_NO_CLIENT_CB);
- goto err;
- }
-
- psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
- identity, PSK_MAX_IDENTITY_LEN,
- psk_or_pre_ms, sizeof(psk_or_pre_ms));
- if (psk_len > PSK_MAX_PSK_LEN)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_INTERNAL_ERROR);
- goto psk_err;
- }
- else if (psk_len == 0)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- SSL_R_PSK_IDENTITY_NOT_FOUND);
- goto psk_err;
- }
-
- /* create PSK pre_master_secret */
- pre_ms_len = 2+psk_len+2+psk_len;
- t = psk_or_pre_ms;
- memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
- s2n(psk_len, t);
- memset(t, 0, psk_len);
- t+=psk_len;
- s2n(psk_len, t);
-
- if (s->session->psk_identity_hint != NULL)
- OPENSSL_free(s->session->psk_identity_hint);
- s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
- if (s->ctx->psk_identity_hint != NULL &&
- s->session->psk_identity_hint == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto psk_err;
- }
-
- if (s->session->psk_identity != NULL)
- OPENSSL_free(s->session->psk_identity);
- s->session->psk_identity = BUF_strdup(identity);
- if (s->session->psk_identity == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto psk_err;
- }
-
- s->session->master_key_length =
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,
- psk_or_pre_ms, pre_ms_len);
- n = strlen(identity);
- s2n(n, p);
- memcpy(p, identity, n);
- n+=2;
- psk_err = 0;
- psk_err:
- OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
- OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
- if (psk_err != 0)
- {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- goto err;
- }
- }
-#endif
- else
- {
- ssl3_send_alert(s, SSL3_AL_FATAL,
- SSL_AD_HANDSHAKE_FAILURE);
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- *(d++)=SSL3_MT_CLIENT_KEY_EXCHANGE;
- l2n3(n,d);
-
- s->state=SSL3_ST_CW_KEY_EXCH_B;
- /* number of bytes to write */
- s->init_num=n+4;
- s->init_off=0;
- }
-
- /* SSL3_ST_CW_KEY_EXCH_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
-err:
-#ifndef OPENSSL_NO_ECDH
- BN_CTX_free(bn_ctx);
- if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
- if (clnt_ecdh != NULL)
- EC_KEY_free(clnt_ecdh);
- EVP_PKEY_free(srvr_pub_pkey);
-#endif
- return(-1);
- }
-
-int ssl3_send_client_verify(SSL *s)
- {
- unsigned char *p,*d;
- unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
- EVP_PKEY *pkey;
- EVP_PKEY_CTX *pctx=NULL;
- EVP_MD_CTX mctx;
- unsigned u=0;
- unsigned long n;
- int j;
-
- EVP_MD_CTX_init(&mctx);
-
- if (s->state == SSL3_ST_CW_CERT_VRFY_A)
- {
- d=(unsigned char *)s->init_buf->data;
- p= &(d[4]);
- pkey=s->cert->key->privatekey;
-/* Create context from key and test if sha1 is allowed as digest */
- pctx = EVP_PKEY_CTX_new(pkey,NULL);
- EVP_PKEY_sign_init(pctx);
- if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0)
- {
- if (TLS1_get_version(s) < TLS1_2_VERSION)
- s->method->ssl3_enc->cert_verify_mac(s,
- NID_sha1,
- &(data[MD5_DIGEST_LENGTH]));
- }
- else
- {
- ERR_clear_error();
- }
- /* For TLS v1.2 send signature algorithm and signature
- * using agreed digest and cached handshake records.
- */
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- {
- long hdatalen = 0;
- void *hdata;
- const EVP_MD *md = s->cert->key->digest;
- hdatalen = BIO_get_mem_data(s->s3->handshake_buffer,
- &hdata);
- if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
- p += 2;
-#ifdef SSL_DEBUG
- fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
- EVP_MD_name(md));
-#endif
- if (!EVP_SignInit_ex(&mctx, md, NULL)
- || !EVP_SignUpdate(&mctx, hdata, hdatalen)
- || !EVP_SignFinal(&mctx, p + 2, &u, pkey))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
- ERR_R_EVP_LIB);
- goto err;
- }
- s2n(u,p);
- n = u + 4;
- if (!ssl3_digest_cached_records(s))
- goto err;
- }
- else
-#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA)
- {
- s->method->ssl3_enc->cert_verify_mac(s,
- NID_md5,
- &(data[0]));
- if (RSA_sign(NID_md5_sha1, data,
- MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
- &(p[2]), &u, pkey->pkey.rsa) <= 0 )
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_RSA_LIB);
- goto err;
- }
- s2n(u,p);
- n=u+2;
- }
- else
-#endif
-#ifndef OPENSSL_NO_DSA
- if (pkey->type == EVP_PKEY_DSA)
- {
- if (!DSA_sign(pkey->save_type,
- &(data[MD5_DIGEST_LENGTH]),
- SHA_DIGEST_LENGTH,&(p[2]),
- (unsigned int *)&j,pkey->pkey.dsa))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_DSA_LIB);
- goto err;
- }
- s2n(j,p);
- n=j+2;
- }
- else
-#endif
-#ifndef OPENSSL_NO_ECDSA
- if (pkey->type == EVP_PKEY_EC)
- {
- if (!ECDSA_sign(pkey->save_type,
- &(data[MD5_DIGEST_LENGTH]),
- SHA_DIGEST_LENGTH,&(p[2]),
- (unsigned int *)&j,pkey->pkey.ec))
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
- ERR_R_ECDSA_LIB);
- goto err;
- }
- s2n(j,p);
- n=j+2;
- }
- else
-#endif
- if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001)
- {
- unsigned char signbuf[64];
- int i;
- size_t sigsize=64;
- s->method->ssl3_enc->cert_verify_mac(s,
- NID_id_GostR3411_94,
- data);
- if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
- for (i=63,j=0; i>=0; j++, i--) {
- p[2+j]=signbuf[i];
- }
- s2n(j,p);
- n=j+2;
- }
- else
- {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
- goto err;
- }
- *(d++)=SSL3_MT_CERTIFICATE_VERIFY;
- l2n3(n,d);
-
- s->state=SSL3_ST_CW_CERT_VRFY_B;
- s->init_num=(int)n+4;
- s->init_off=0;
- }
- EVP_MD_CTX_cleanup(&mctx);
- EVP_PKEY_CTX_free(pctx);
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
-err:
- EVP_MD_CTX_cleanup(&mctx);
- EVP_PKEY_CTX_free(pctx);
- return(-1);
- }
-
-int ssl3_send_client_certificate(SSL *s)
- {
- X509 *x509=NULL;
- EVP_PKEY *pkey=NULL;
- int i;
- unsigned long l;
-
- if (s->state == SSL3_ST_CW_CERT_A)
- {
- if ((s->cert == NULL) ||
- (s->cert->key->x509 == NULL) ||
- (s->cert->key->privatekey == NULL))
- s->state=SSL3_ST_CW_CERT_B;
- else
- s->state=SSL3_ST_CW_CERT_C;
- }
-
- /* We need to get a client cert */
- if (s->state == SSL3_ST_CW_CERT_B)
- {
- /* If we get an error, we need to
- * ssl->rwstate=SSL_X509_LOOKUP; return(-1);
- * We then get retied later */
- i=0;
- i = ssl_do_client_cert_cb(s, &x509, &pkey);
- if (i < 0)
- {
- s->rwstate=SSL_X509_LOOKUP;
- return(-1);
- }
- s->rwstate=SSL_NOTHING;
- if ((i == 1) && (pkey != NULL) && (x509 != NULL))
- {
- s->state=SSL3_ST_CW_CERT_B;
- if ( !SSL_use_certificate(s,x509) ||
- !SSL_use_PrivateKey(s,pkey))
- i=0;
- }
- else if (i == 1)
- {
- i=0;
- SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE,SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
- }
-
- if (x509 != NULL) X509_free(x509);
- if (pkey != NULL) EVP_PKEY_free(pkey);
- if (i == 0)
- {
- if (s->version == SSL3_VERSION)
- {
- s->s3->tmp.cert_req=0;
- ssl3_send_alert(s,SSL3_AL_WARNING,SSL_AD_NO_CERTIFICATE);
- return(1);
- }
- else
- {
- s->s3->tmp.cert_req=2;
- }
- }
-
- /* Ok, we have a cert */
- s->state=SSL3_ST_CW_CERT_C;
- }
-
- if (s->state == SSL3_ST_CW_CERT_C)
- {
- s->state=SSL3_ST_CW_CERT_D;
- l=ssl3_output_cert_chain(s,
- (s->s3->tmp.cert_req == 2)?NULL:s->cert->key->x509);
- s->init_num=(int)l;
- s->init_off=0;
- }
- /* SSL3_ST_CW_CERT_D */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-#define has_bits(i,m) (((i)&(m)) == (m))
-
-int ssl3_check_cert_and_algorithm(SSL *s)
- {
- int i,idx;
- long alg_k,alg_a;
- EVP_PKEY *pkey=NULL;
- SESS_CERT *sc;
-#ifndef OPENSSL_NO_RSA
- RSA *rsa;
-#endif
-#ifndef OPENSSL_NO_DH
- DH *dh;
-#endif
-
- alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
- alg_a=s->s3->tmp.new_cipher->algorithm_auth;
-
- /* we don't have a certificate */
- if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
- return(1);
-
- sc=s->session->sess_cert;
- if (sc == NULL)
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
-#ifndef OPENSSL_NO_RSA
- rsa=s->session->sess_cert->peer_rsa_tmp;
-#endif
-#ifndef OPENSSL_NO_DH
- dh=s->session->sess_cert->peer_dh_tmp;
-#endif
-
- /* This is the passed certificate */
-
- idx=sc->peer_cert_type;
-#ifndef OPENSSL_NO_ECDH
- if (idx == SSL_PKEY_ECC)
- {
- if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
- s) == 0)
- { /* check failed */
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT);
- goto f_err;
- }
- else
- {
- return 1;
- }
- }
-#endif
- pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509);
- i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey);
- EVP_PKEY_free(pkey);
-
-
- /* Check that we have a certificate if we require one */
- if ((alg_a & SSL_aRSA) && !has_bits(i,EVP_PK_RSA|EVP_PKT_SIGN))
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_SIGNING_CERT);
- goto f_err;
- }
-#ifndef OPENSSL_NO_DSA
- else if ((alg_a & SSL_aDSS) && !has_bits(i,EVP_PK_DSA|EVP_PKT_SIGN))
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DSA_SIGNING_CERT);
- goto f_err;
- }
-#endif
-#ifndef OPENSSL_NO_RSA
- if ((alg_k & SSL_kRSA) &&
- !(has_bits(i,EVP_PK_RSA|EVP_PKT_ENC) || (rsa != NULL)))
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_ENCRYPTING_CERT);
- goto f_err;
- }
-#endif
-#ifndef OPENSSL_NO_DH
- if ((alg_k & SSL_kEDH) &&
- !(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL)))
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_KEY);
- goto f_err;
- }
- else if ((alg_k & SSL_kDHr) && !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_RSA_CERT);
- goto f_err;
- }
-#ifndef OPENSSL_NO_DSA
- else if ((alg_k & SSL_kDHd) && !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_DSA_CERT);
- goto f_err;
- }
-#endif
-#endif
-
- if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i,EVP_PKT_EXP))
- {
-#ifndef OPENSSL_NO_RSA
- if (alg_k & SSL_kRSA)
- {
- if (rsa == NULL
- || RSA_size(rsa)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
- goto f_err;
- }
- }
- else
-#endif
-#ifndef OPENSSL_NO_DH
- if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
- {
- if (dh == NULL
- || DH_size(dh)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_EXPORT_TMP_DH_KEY);
- goto f_err;
- }
- }
- else
-#endif
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
- goto f_err;
- }
- }
- return(1);
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
-err:
- return(0);
- }
-
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
-int ssl3_send_next_proto(SSL *s)
- {
- unsigned int len, padding_len;
- unsigned char *d;
-
- if (s->state == SSL3_ST_CW_NEXT_PROTO_A)
- {
- len = s->next_proto_negotiated_len;
- padding_len = 32 - ((len + 2) % 32);
- d = (unsigned char *)s->init_buf->data;
- d[4] = len;
- memcpy(d + 5, s->next_proto_negotiated, len);
- d[5 + len] = padding_len;
- memset(d + 6 + len, 0, padding_len);
- *(d++)=SSL3_MT_NEXT_PROTO;
- l2n3(2 + len + padding_len, d);
- s->state = SSL3_ST_CW_NEXT_PROTO_B;
- s->init_num = 4 + 2 + len + padding_len;
- s->init_off = 0;
- }
-
- return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
-}
-#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
-
-/* Check to see if handshake is full or resumed. Usually this is just a
- * case of checking to see if a cache hit has occurred. In the case of
- * session tickets we have to check the next message to be sure.
- */
-
-#ifndef OPENSSL_NO_TLSEXT
-int ssl3_check_finished(SSL *s)
- {
- int ok;
- long n;
- /* If we have no ticket it cannot be a resumed session. */
- if (!s->session->tlsext_tick)
- return 1;
- /* this function is called when we really expect a Certificate
- * message, so permit appropriate message length */
- n=s->method->ssl_get_message(s,
- SSL3_ST_CR_CERT_A,
- SSL3_ST_CR_CERT_B,
- -1,
- s->max_cert_list,
- &ok);
- if (!ok) return((int)n);
- s->s3->tmp.reuse_message = 1;
- if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
- || (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
- return 2;
-
- return 1;
- }
-#endif
-
-int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
- {
- int i = 0;
-#ifndef OPENSSL_NO_ENGINE
- if (s->ctx->client_cert_engine)
- {
- i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s,
- SSL_get_client_CA_list(s),
- px509, ppkey, NULL, NULL, NULL);
- if (i != 0)
- return i;
- }
-#endif
- if (s->ctx->client_cert_cb)
- i = s->ctx->client_cert_cb(s,px509,ppkey);
- return i;
- }
diff --git a/drivers/builtin_openssl/ssl/s3_pkt.c b/drivers/builtin_openssl/ssl/s3_pkt.c
deleted file mode 100644
index 96ba63262e..0000000000
--- a/drivers/builtin_openssl/ssl/s3_pkt.c
+++ /dev/null
@@ -1,1529 +0,0 @@
-/* ssl/s3_pkt.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#define USE_SOCKETS
-#include "ssl_locl.h"
-#include <openssl/evp.h>
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-
-static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
- unsigned int len, int create_empty_fragment);
-static int ssl3_get_record(SSL *s);
-
-int ssl3_read_n(SSL *s, int n, int max, int extend)
- {
- /* If extend == 0, obtain new n-byte packet; if extend == 1, increase
- * packet by another n bytes.
- * The packet will be in the sub-array of s->s3->rbuf.buf specified
- * by s->packet and s->packet_length.
- * (If s->read_ahead is set, 'max' bytes may be stored in rbuf
- * [plus s->packet_length bytes if extend == 1].)
- */
- int i,len,left;
- long align=0;
- unsigned char *pkt;
- SSL3_BUFFER *rb;
-
- if (n <= 0) return n;
-
- rb = &(s->s3->rbuf);
- if (rb->buf == NULL)
- if (!ssl3_setup_read_buffer(s))
- return -1;
-
- left = rb->left;
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
- align = (long)rb->buf + SSL3_RT_HEADER_LENGTH;
- align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
-#endif
-
- if (!extend)
- {
- /* start with empty packet ... */
- if (left == 0)
- rb->offset = align;
- else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH)
- {
- /* check if next packet length is large
- * enough to justify payload alignment... */
- pkt = rb->buf + rb->offset;
- if (pkt[0] == SSL3_RT_APPLICATION_DATA
- && (pkt[3]<<8|pkt[4]) >= 128)
- {
- /* Note that even if packet is corrupted
- * and its length field is insane, we can
- * only be led to wrong decision about
- * whether memmove will occur or not.
- * Header values has no effect on memmove
- * arguments and therefore no buffer
- * overrun can be triggered. */
- memmove (rb->buf+align,pkt,left);
- rb->offset = align;
- }
- }
- s->packet = rb->buf + rb->offset;
- s->packet_length = 0;
- /* ... now we can act as if 'extend' was set */
- }
-
- /* For DTLS/UDP reads should not span multiple packets
- * because the read operation returns the whole packet
- * at once (as long as it fits into the buffer). */
- if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
- {
- if (left > 0 && n > left)
- n = left;
- }
-
- /* if there is enough in the buffer from a previous read, take some */
- if (left >= n)
- {
- s->packet_length+=n;
- rb->left=left-n;
- rb->offset+=n;
- return(n);
- }
-
- /* else we need to read more data */
-
- len = s->packet_length;
- pkt = rb->buf+align;
- /* Move any available bytes to front of buffer:
- * 'len' bytes already pointed to by 'packet',
- * 'left' extra ones at the end */
- if (s->packet != pkt) /* len > 0 */
- {
- memmove(pkt, s->packet, len+left);
- s->packet = pkt;
- rb->offset = len + align;
- }
-
- if (n > (int)(rb->len - rb->offset)) /* does not happen */
- {
- SSLerr(SSL_F_SSL3_READ_N,ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- if (!s->read_ahead)
- /* ignore max parameter */
- max = n;
- else
- {
- if (max < n)
- max = n;
- if (max > (int)(rb->len - rb->offset))
- max = rb->len - rb->offset;
- }
-
- while (left < n)
- {
- /* Now we have len+left bytes at the front of s->s3->rbuf.buf
- * and need to read in more until we have len+n (up to
- * len+max if possible) */
-
- clear_sys_error();
- if (s->rbio != NULL)
- {
- s->rwstate=SSL_READING;
- i=BIO_read(s->rbio,pkt+len+left, max-left);
- }
- else
- {
- SSLerr(SSL_F_SSL3_READ_N,SSL_R_READ_BIO_NOT_SET);
- i = -1;
- }
-
- if (i <= 0)
- {
- rb->left = left;
- if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
- SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
- if (len+left == 0)
- ssl3_release_read_buffer(s);
- return(i);
- }
- left+=i;
- /* reads should *never* span multiple packets for DTLS because
- * the underlying transport protocol is message oriented as opposed
- * to byte oriented as in the TLS case. */
- if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
- {
- if (n > left)
- n = left; /* makes the while condition false */
- }
- }
-
- /* done reading, now the book-keeping */
- rb->offset += n;
- rb->left = left - n;
- s->packet_length += n;
- s->rwstate=SSL_NOTHING;
- return(n);
- }
-
-/* Call this to get a new input record.
- * It will return <= 0 if more data is needed, normally due to an error
- * or non-blocking IO.
- * When it finishes, one packet has been decoded and can be found in
- * ssl->s3->rrec.type - is the type of record
- * ssl->s3->rrec.data, - data
- * ssl->s3->rrec.length, - number of bytes
- */
-/* used only by ssl3_read_bytes */
-static int ssl3_get_record(SSL *s)
- {
- int ssl_major,ssl_minor,al;
- int enc_err,n,i,ret= -1;
- SSL3_RECORD *rr;
- SSL_SESSION *sess;
- unsigned char *p;
- unsigned char md[EVP_MAX_MD_SIZE];
- short version;
- unsigned mac_size, orig_len;
- size_t extra;
-
- rr= &(s->s3->rrec);
- sess=s->session;
-
- if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
- extra=SSL3_RT_MAX_EXTRA;
- else
- extra=0;
- if (extra && !s->s3->init_extra)
- {
- /* An application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
- * set after ssl3_setup_buffers() was done */
- SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
-again:
- /* check if we have the header */
- if ( (s->rstate != SSL_ST_READ_BODY) ||
- (s->packet_length < SSL3_RT_HEADER_LENGTH))
- {
- n=ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
- if (n <= 0) return(n); /* error or non-blocking */
- s->rstate=SSL_ST_READ_BODY;
-
- p=s->packet;
-
- /* Pull apart the header into the SSL3_RECORD */
- rr->type= *(p++);
- ssl_major= *(p++);
- ssl_minor= *(p++);
- version=(ssl_major<<8)|ssl_minor;
- n2s(p,rr->length);
-#if 0
-fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
-#endif
-
- /* Lets check version */
- if (!s->first_packet)
- {
- if (version != s->version)
- {
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
- if ((s->version & 0xFF00) == (version & 0xFF00) && !s->enc_write_ctx && !s->write_hash)
- /* Send back error using their minor version number :-) */
- s->version = (unsigned short)version;
- al=SSL_AD_PROTOCOL_VERSION;
- goto f_err;
- }
- }
-
- if ((version>>8) != SSL3_VERSION_MAJOR)
- {
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
- goto err;
- }
-
- if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH)
- {
- al=SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- /* now s->rstate == SSL_ST_READ_BODY */
- }
-
- /* s->rstate == SSL_ST_READ_BODY, get and decode the data */
-
- if (rr->length > s->packet_length-SSL3_RT_HEADER_LENGTH)
- {
- /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
- i=rr->length;
- n=ssl3_read_n(s,i,i,1);
- if (n <= 0) return(n); /* error or non-blocking io */
- /* now n == rr->length,
- * and s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length */
- }
-
- s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
-
- /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
- * and we have that many bytes in s->packet
- */
- rr->input= &(s->packet[SSL3_RT_HEADER_LENGTH]);
-
- /* ok, we can now read from 's->packet' data into 'rr'
- * rr->input points at rr->length bytes, which
- * need to be copied into rr->data by either
- * the decryption or by the decompression
- * When the data is 'copied' into the rr->data buffer,
- * rr->input will be pointed at the new buffer */
-
- /* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
- * rr->length bytes of encrypted compressed stuff. */
-
- /* check is not needed I believe */
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
- {
- al=SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- /* decrypt in place in 'rr->input' */
- rr->data=rr->input;
-
- enc_err = s->method->ssl3_enc->enc(s,0);
- /* enc_err is:
- * 0: (in non-constant time) if the record is publically invalid.
- * 1: if the padding is valid
- * -1: if the padding is invalid */
- if (enc_err == 0)
- {
- al=SSL_AD_DECRYPTION_FAILED;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
- goto f_err;
- }
-
-#ifdef TLS_DEBUG
-printf("dec %d\n",rr->length);
-{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
-printf("\n");
-#endif
-
- /* r->length is now the compressed data plus mac */
- if ((sess != NULL) &&
- (s->enc_read_ctx != NULL) &&
- (EVP_MD_CTX_md(s->read_hash) != NULL))
- {
- /* s->read_hash != NULL => mac_size != -1 */
- unsigned char *mac = NULL;
- unsigned char mac_tmp[EVP_MAX_MD_SIZE];
- mac_size=EVP_MD_CTX_size(s->read_hash);
- OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
-
- /* kludge: *_cbc_remove_padding passes padding length in rr->type */
- orig_len = rr->length+((unsigned int)rr->type>>8);
-
- /* orig_len is the length of the record before any padding was
- * removed. This is public information, as is the MAC in use,
- * therefore we can safely process the record in a different
- * amount of time if it's too short to possibly contain a MAC.
- */
- if (orig_len < mac_size ||
- /* CBC records must have a padding length byte too. */
- (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
- orig_len < mac_size+1))
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
- goto f_err;
- }
-
- if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
- {
- /* We update the length so that the TLS header bytes
- * can be constructed correctly but we need to extract
- * the MAC in constant time from within the record,
- * without leaking the contents of the padding bytes.
- * */
- mac = mac_tmp;
- ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
- rr->length -= mac_size;
- }
- else
- {
- /* In this case there's no padding, so |orig_len|
- * equals |rec->length| and we checked that there's
- * enough bytes for |mac_size| above. */
- rr->length -= mac_size;
- mac = &rr->data[rr->length];
- }
-
- i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
- if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
- enc_err = -1;
- if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
- enc_err = -1;
- }
-
- if (enc_err < 0)
- {
- /* A separate 'decryption_failed' alert was introduced with TLS 1.0,
- * SSL 3.0 only has 'bad_record_mac'. But unless a decryption
- * failure is directly visible from the ciphertext anyway,
- * we should not reveal which kind of error occured -- this
- * might become visible to an attacker (e.g. via a logfile) */
- al=SSL_AD_BAD_RECORD_MAC;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
- goto f_err;
- }
-
- /* r->length is now just compressed */
- if (s->expand != NULL)
- {
- if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra)
- {
- al=SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
- goto f_err;
- }
- if (!ssl3_do_uncompress(s))
- {
- al=SSL_AD_DECOMPRESSION_FAILURE;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
- goto f_err;
- }
- }
-
- if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH+extra)
- {
- al=SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- rr->off=0;
- /* So at this point the following is true
- * ssl->s3->rrec.type is the type of record
- * ssl->s3->rrec.length == number of bytes in record
- * ssl->s3->rrec.off == offset to first valid byte
- * ssl->s3->rrec.data == where to take bytes from, increment
- * after use :-).
- */
-
- /* we have pulled in a full packet so zero things */
- s->packet_length=0;
-
- /* just read a 0 length packet */
- if (rr->length == 0) goto again;
-
-#if 0
-fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, rr->length);
-#endif
-
- return(1);
-
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
- return(ret);
- }
-
-int ssl3_do_uncompress(SSL *ssl)
- {
-#ifndef OPENSSL_NO_COMP
- int i;
- SSL3_RECORD *rr;
-
- rr= &(ssl->s3->rrec);
- i=COMP_expand_block(ssl->expand,rr->comp,
- SSL3_RT_MAX_PLAIN_LENGTH,rr->data,(int)rr->length);
- if (i < 0)
- return(0);
- else
- rr->length=i;
- rr->data=rr->comp;
-#endif
- return(1);
- }
-
-int ssl3_do_compress(SSL *ssl)
- {
-#ifndef OPENSSL_NO_COMP
- int i;
- SSL3_RECORD *wr;
-
- wr= &(ssl->s3->wrec);
- i=COMP_compress_block(ssl->compress,wr->data,
- SSL3_RT_MAX_COMPRESSED_LENGTH,
- wr->input,(int)wr->length);
- if (i < 0)
- return(0);
- else
- wr->length=i;
-
- wr->input=wr->data;
-#endif
- return(1);
- }
-
-/* Call this to write data in records of type 'type'
- * It will return <= 0 if not all data has been sent or non-blocking IO.
- */
-int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
- {
- const unsigned char *buf=buf_;
- unsigned int tot,n,nw;
- int i;
-
- s->rwstate=SSL_NOTHING;
- tot=s->s3->wnum;
- s->s3->wnum=0;
-
- if (SSL_in_init(s) && !s->in_handshake)
- {
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_SSL3_WRITE_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
- }
-
- n=(len-tot);
- for (;;)
- {
- if (n > s->max_send_fragment)
- nw=s->max_send_fragment;
- else
- nw=n;
-
- i=do_ssl3_write(s, type, &(buf[tot]), nw, 0);
- if (i <= 0)
- {
- s->s3->wnum=tot;
- return i;
- }
-
- if ((i == (int)n) ||
- (type == SSL3_RT_APPLICATION_DATA &&
- (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)))
- {
- /* next chunk of data should get another prepended empty fragment
- * in ciphersuites with known-IV weakness: */
- s->s3->empty_fragment_done = 0;
-
- return tot+i;
- }
-
- n-=i;
- tot+=i;
- }
- }
-
-static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
- unsigned int len, int create_empty_fragment)
- {
- unsigned char *p,*plen;
- int i,mac_size,clear=0;
- int prefix_len=0;
- int eivlen;
- long align=0;
- SSL3_RECORD *wr;
- SSL3_BUFFER *wb=&(s->s3->wbuf);
- SSL_SESSION *sess;
-
- if (wb->buf == NULL)
- if (!ssl3_setup_write_buffer(s))
- return -1;
-
- /* first check if there is a SSL3_BUFFER still being written
- * out. This will happen with non blocking IO */
- if (wb->left != 0)
- return(ssl3_write_pending(s,type,buf,len));
-
- /* If we have an alert to send, lets send it */
- if (s->s3->alert_dispatch)
- {
- i=s->method->ssl_dispatch_alert(s);
- if (i <= 0)
- return(i);
- /* if it went, fall through and send more stuff */
- }
-
- if (len == 0 && !create_empty_fragment)
- return 0;
-
- wr= &(s->s3->wrec);
- sess=s->session;
-
- if ( (sess == NULL) ||
- (s->enc_write_ctx == NULL) ||
- (EVP_MD_CTX_md(s->write_hash) == NULL))
- {
-#if 1
- clear=s->enc_write_ctx?0:1; /* must be AEAD cipher */
-#else
- clear=1;
-#endif
- mac_size=0;
- }
- else
- {
- mac_size=EVP_MD_CTX_size(s->write_hash);
- if (mac_size < 0)
- goto err;
- }
-
- /* 'create_empty_fragment' is true only when this function calls itself */
- if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
- {
- /* countermeasure against known-IV weakness in CBC ciphersuites
- * (see http://www.openssl.org/~bodo/tls-cbc.txt) */
-
- if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
- {
- /* recursive function call with 'create_empty_fragment' set;
- * this prepares and buffers the data for an empty fragment
- * (these 'prefix_len' bytes are sent out later
- * together with the actual payload) */
- prefix_len = do_ssl3_write(s, type, buf, 0, 1);
- if (prefix_len <= 0)
- goto err;
-
- if (prefix_len >
- (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD))
- {
- /* insufficient space */
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- }
-
- s->s3->empty_fragment_done = 1;
- }
-
- if (create_empty_fragment)
- {
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
- /* extra fragment would be couple of cipher blocks,
- * which would be multiple of SSL3_ALIGN_PAYLOAD, so
- * if we want to align the real payload, then we can
- * just pretent we simply have two headers. */
- align = (long)wb->buf + 2*SSL3_RT_HEADER_LENGTH;
- align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
-#endif
- p = wb->buf + align;
- wb->offset = align;
- }
- else if (prefix_len)
- {
- p = wb->buf + wb->offset + prefix_len;
- }
- else
- {
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
- align = (long)wb->buf + SSL3_RT_HEADER_LENGTH;
- align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
-#endif
- p = wb->buf + align;
- wb->offset = align;
- }
-
- /* write the header */
-
- *(p++)=type&0xff;
- wr->type=type;
-
- *(p++)=(s->version>>8);
- /* Some servers hang if iniatial client hello is larger than 256
- * bytes and record version number > TLS 1.0
- */
- if (s->state == SSL3_ST_CW_CLNT_HELLO_B
- && !s->renegotiate
- && TLS1_get_version(s) > TLS1_VERSION)
- *(p++) = 0x1;
- else
- *(p++)=s->version&0xff;
-
- /* field where we are to write out packet length */
- plen=p;
- p+=2;
- /* Explicit IV length, block ciphers and TLS version 1.1 or later */
- if (s->enc_write_ctx && s->version >= TLS1_1_VERSION)
- {
- int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
- if (mode == EVP_CIPH_CBC_MODE)
- {
- eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
- if (eivlen <= 1)
- eivlen = 0;
- }
- /* Need explicit part of IV for GCM mode */
- else if (mode == EVP_CIPH_GCM_MODE)
- eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
- else
- eivlen = 0;
- }
- else
- eivlen = 0;
-
- /* lets setup the record stuff. */
- wr->data=p + eivlen;
- wr->length=(int)len;
- wr->input=(unsigned char *)buf;
-
- /* we now 'read' from wr->input, wr->length bytes into
- * wr->data */
-
- /* first we compress */
- if (s->compress != NULL)
- {
- if (!ssl3_do_compress(s))
- {
- SSLerr(SSL_F_DO_SSL3_WRITE,SSL_R_COMPRESSION_FAILURE);
- goto err;
- }
- }
- else
- {
- memcpy(wr->data,wr->input,wr->length);
- wr->input=wr->data;
- }
-
- /* we should still have the output to wr->data and the input
- * from wr->input. Length should be wr->length.
- * wr->data still points in the wb->buf */
-
- if (mac_size != 0)
- {
- if (s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0)
- goto err;
- wr->length+=mac_size;
- }
-
- wr->input=p;
- wr->data=p;
-
- if (eivlen)
- {
- /* if (RAND_pseudo_bytes(p, eivlen) <= 0)
- goto err; */
- wr->length += eivlen;
- }
-
- /* ssl3_enc can only have an error on read */
- s->method->ssl3_enc->enc(s,1);
-
- /* record length after mac and block padding */
- s2n(wr->length,plen);
-
- /* we should now have
- * wr->data pointing to the encrypted data, which is
- * wr->length long */
- wr->type=type; /* not needed but helps for debugging */
- wr->length+=SSL3_RT_HEADER_LENGTH;
-
- if (create_empty_fragment)
- {
- /* we are in a recursive call;
- * just return the length, don't write out anything here
- */
- return wr->length;
- }
-
- /* now let's set up wb */
- wb->left = prefix_len + wr->length;
-
- /* memorize arguments so that ssl3_write_pending can detect bad write retries later */
- s->s3->wpend_tot=len;
- s->s3->wpend_buf=buf;
- s->s3->wpend_type=type;
- s->s3->wpend_ret=len;
-
- /* we now just need to write the buffer */
- return ssl3_write_pending(s,type,buf,len);
-err:
- return -1;
- }
-
-/* if s->s3->wbuf.left != 0, we need to call this */
-int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
- unsigned int len)
- {
- int i;
- SSL3_BUFFER *wb=&(s->s3->wbuf);
-
-/* XXXX */
- if ((s->s3->wpend_tot > (int)len)
- || ((s->s3->wpend_buf != buf) &&
- !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))
- || (s->s3->wpend_type != type))
- {
- SSLerr(SSL_F_SSL3_WRITE_PENDING,SSL_R_BAD_WRITE_RETRY);
- return(-1);
- }
-
- for (;;)
- {
- clear_sys_error();
- if (s->wbio != NULL)
- {
- s->rwstate=SSL_WRITING;
- i=BIO_write(s->wbio,
- (char *)&(wb->buf[wb->offset]),
- (unsigned int)wb->left);
- }
- else
- {
- SSLerr(SSL_F_SSL3_WRITE_PENDING,SSL_R_BIO_NOT_SET);
- i= -1;
- }
- if (i == wb->left)
- {
- wb->left=0;
- wb->offset+=i;
- if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
- SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
- ssl3_release_write_buffer(s);
- s->rwstate=SSL_NOTHING;
- return(s->s3->wpend_ret);
- }
- else if (i <= 0) {
- if (s->version == DTLS1_VERSION ||
- s->version == DTLS1_BAD_VER) {
- /* For DTLS, just drop it. That's kind of the whole
- point in using a datagram service */
- wb->left = 0;
- }
- return(i);
- }
- wb->offset+=i;
- wb->left-=i;
- }
- }
-
-/* Return up to 'len' payload bytes received in 'type' records.
- * 'type' is one of the following:
- *
- * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
- * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
- * - 0 (during a shutdown, no data has to be returned)
- *
- * If we don't have stored data to work from, read a SSL/TLS record first
- * (possibly multiple records if we still don't have anything to return).
- *
- * This function must handle any surprises the peer may have for us, such as
- * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
- * a surprise, but handled as if it were), or renegotiation requests.
- * Also if record payloads contain fragments too small to process, we store
- * them until there is enough for the respective protocol (the record protocol
- * may use arbitrary fragmentation and even interleaving):
- * Change cipher spec protocol
- * just 1 byte needed, no need for keeping anything stored
- * Alert protocol
- * 2 bytes needed (AlertLevel, AlertDescription)
- * Handshake protocol
- * 4 bytes needed (HandshakeType, uint24 length) -- we just have
- * to detect unexpected Client Hello and Hello Request messages
- * here, anything else is handled by higher layers
- * Application data protocol
- * none of our business
- */
-int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
- {
- int al,i,j,ret;
- unsigned int n;
- SSL3_RECORD *rr;
- void (*cb)(const SSL *ssl,int type2,int val)=NULL;
-
- if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
- if (!ssl3_setup_read_buffer(s))
- return(-1);
-
- if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) ||
- (peek && (type != SSL3_RT_APPLICATION_DATA)))
- {
- SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- if ((type == SSL3_RT_HANDSHAKE) && (s->s3->handshake_fragment_len > 0))
- /* (partially) satisfy request from storage */
- {
- unsigned char *src = s->s3->handshake_fragment;
- unsigned char *dst = buf;
- unsigned int k;
-
- /* peek == 0 */
- n = 0;
- while ((len > 0) && (s->s3->handshake_fragment_len > 0))
- {
- *dst++ = *src++;
- len--; s->s3->handshake_fragment_len--;
- n++;
- }
- /* move any remaining fragment bytes: */
- for (k = 0; k < s->s3->handshake_fragment_len; k++)
- s->s3->handshake_fragment[k] = *src++;
- return n;
- }
-
- /* Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
-
- if (!s->in_handshake && SSL_in_init(s))
- {
- /* type == SSL3_RT_APPLICATION_DATA */
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return(-1);
- }
- }
-start:
- s->rwstate=SSL_NOTHING;
-
- /* s->s3->rrec.type - is the type of record
- * s->s3->rrec.data, - data
- * s->s3->rrec.off, - offset into 'data' for next read
- * s->s3->rrec.length, - number of bytes. */
- rr = &(s->s3->rrec);
-
- /* get new packet if necessary */
- if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
- {
- ret=ssl3_get_record(s);
- if (ret <= 0) return(ret);
- }
-
- /* we now have a packet which can be read and processed */
-
- if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
- * reset by ssl3_get_finished */
- && (rr->type != SSL3_RT_HANDSHAKE))
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
- goto f_err;
- }
-
- /* If the other end has shut down, throw anything we read away
- * (even in 'peek' mode) */
- if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
- {
- rr->length=0;
- s->rwstate=SSL_NOTHING;
- return(0);
- }
-
-
- if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
- {
- /* make sure that we are not getting application data when we
- * are doing a handshake for the first time */
- if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
- (s->enc_read_ctx == NULL))
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE);
- goto f_err;
- }
-
- if (len <= 0) return(len);
-
- if ((unsigned int)len > rr->length)
- n = rr->length;
- else
- n = (unsigned int)len;
-
- memcpy(buf,&(rr->data[rr->off]),n);
- if (!peek)
- {
- rr->length-=n;
- rr->off+=n;
- if (rr->length == 0)
- {
- s->rstate=SSL_ST_READ_HEADER;
- rr->off=0;
- if (s->mode & SSL_MODE_RELEASE_BUFFERS)
- ssl3_release_read_buffer(s);
- }
- }
- return(n);
- }
-
-
- /* If we get here, then type != rr->type; if we have a handshake
- * message, then it was unexpected (Hello Request or Client Hello). */
-
- /* In case of record types for which we have 'fragment' storage,
- * fill that so that we can process the data at a fixed place.
- */
- {
- unsigned int dest_maxlen = 0;
- unsigned char *dest = NULL;
- unsigned int *dest_len = NULL;
-
- if (rr->type == SSL3_RT_HANDSHAKE)
- {
- dest_maxlen = sizeof s->s3->handshake_fragment;
- dest = s->s3->handshake_fragment;
- dest_len = &s->s3->handshake_fragment_len;
- }
- else if (rr->type == SSL3_RT_ALERT)
- {
- dest_maxlen = sizeof s->s3->alert_fragment;
- dest = s->s3->alert_fragment;
- dest_len = &s->s3->alert_fragment_len;
- }
-#ifndef OPENSSL_NO_HEARTBEATS
- else if (rr->type == TLS1_RT_HEARTBEAT)
- {
- tls1_process_heartbeat(s);
-
- /* Exit and notify application to read again */
- rr->length = 0;
- s->rwstate=SSL_READING;
- BIO_clear_retry_flags(SSL_get_rbio(s));
- BIO_set_retry_read(SSL_get_rbio(s));
- return(-1);
- }
-#endif
-
- if (dest_maxlen > 0)
- {
- n = dest_maxlen - *dest_len; /* available space in 'dest' */
- if (rr->length < n)
- n = rr->length; /* available bytes */
-
- /* now move 'n' bytes: */
- while (n-- > 0)
- {
- dest[(*dest_len)++] = rr->data[rr->off++];
- rr->length--;
- }
-
- if (*dest_len < dest_maxlen)
- goto start; /* fragment was too small */
- }
- }
-
- /* s->s3->handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE;
- * s->s3->alert_fragment_len == 2 iff rr->type == SSL3_RT_ALERT.
- * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
-
- /* If we are a client, check for an incoming 'Hello Request': */
- if ((!s->server) &&
- (s->s3->handshake_fragment_len >= 4) &&
- (s->s3->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
- (s->session != NULL) && (s->session->cipher != NULL))
- {
- s->s3->handshake_fragment_len = 0;
-
- if ((s->s3->handshake_fragment[1] != 0) ||
- (s->s3->handshake_fragment[2] != 0) ||
- (s->s3->handshake_fragment[3] != 0))
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
- goto f_err;
- }
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->s3->handshake_fragment, 4, s, s->msg_callback_arg);
-
- if (SSL_is_init_finished(s) &&
- !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
- !s->s3->renegotiate)
- {
- ssl3_renegotiate(s);
- if (ssl3_renegotiate_check(s))
- {
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return(-1);
- }
-
- if (!(s->mode & SSL_MODE_AUTO_RETRY))
- {
- if (s->s3->rbuf.left == 0) /* no read-ahead left? */
- {
- BIO *bio;
- /* In the case where we try to read application data,
- * but we trigger an SSL handshake, we return -1 with
- * the retry option set. Otherwise renegotiation may
- * cause nasty problems in the blocking world */
- s->rwstate=SSL_READING;
- bio=SSL_get_rbio(s);
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return(-1);
- }
- }
- }
- }
- /* we either finished a handshake or ignored the request,
- * now try again to obtain the (application) data we were asked for */
- goto start;
- }
- /* If we are a server and get a client hello when renegotiation isn't
- * allowed send back a no renegotiation alert and carry on.
- * WARNING: experimental code, needs reviewing (steve)
- */
- if (s->server &&
- SSL_is_init_finished(s) &&
- !s->s3->send_connection_binding &&
- (s->version > SSL3_VERSION) &&
- (s->s3->handshake_fragment_len >= 4) &&
- (s->s3->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) &&
- (s->session != NULL) && (s->session->cipher != NULL) &&
- !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
-
- {
- /*s->s3->handshake_fragment_len = 0;*/
- rr->length = 0;
- ssl3_send_alert(s,SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
- goto start;
- }
- if (s->s3->alert_fragment_len >= 2)
- {
- int alert_level = s->s3->alert_fragment[0];
- int alert_descr = s->s3->alert_fragment[1];
-
- s->s3->alert_fragment_len = 0;
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, SSL3_RT_ALERT, s->s3->alert_fragment, 2, s, s->msg_callback_arg);
-
- if (s->info_callback != NULL)
- cb=s->info_callback;
- else if (s->ctx->info_callback != NULL)
- cb=s->ctx->info_callback;
-
- if (cb != NULL)
- {
- j = (alert_level << 8) | alert_descr;
- cb(s, SSL_CB_READ_ALERT, j);
- }
-
- if (alert_level == 1) /* warning */
- {
- s->s3->warn_alert = alert_descr;
- if (alert_descr == SSL_AD_CLOSE_NOTIFY)
- {
- s->shutdown |= SSL_RECEIVED_SHUTDOWN;
- return(0);
- }
- /* This is a warning but we receive it if we requested
- * renegotiation and the peer denied it. Terminate with
- * a fatal alert because if application tried to
- * renegotiatie it presumably had a good reason and
- * expects it to succeed.
- *
- * In future we might have a renegotiation where we
- * don't care if the peer refused it where we carry on.
- */
- else if (alert_descr == SSL_AD_NO_RENEGOTIATION)
- {
- al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_NO_RENEGOTIATION);
- goto f_err;
- }
-#ifdef SSL_AD_MISSING_SRP_USERNAME
- else if (alert_descr == SSL_AD_MISSING_SRP_USERNAME)
- return(0);
-#endif
- }
- else if (alert_level == 2) /* fatal */
- {
- char tmp[16];
-
- s->rwstate=SSL_NOTHING;
- s->s3->fatal_alert = alert_descr;
- SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);
- BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
- ERR_add_error_data(2,"SSL alert number ",tmp);
- s->shutdown|=SSL_RECEIVED_SHUTDOWN;
- SSL_CTX_remove_session(s->ctx,s->session);
- return(0);
- }
- else
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE);
- goto f_err;
- }
-
- goto start;
- }
-
- if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
- {
- s->rwstate=SSL_NOTHING;
- rr->length=0;
- return(0);
- }
-
- if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
- {
- /* 'Change Cipher Spec' is just a single byte, so we know
- * exactly what the record payload has to look like */
- if ( (rr->length != 1) || (rr->off != 0) ||
- (rr->data[0] != SSL3_MT_CCS))
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
- goto f_err;
- }
-
- /* Check we have a cipher to change to */
- if (s->s3->tmp.new_cipher == NULL)
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_CCS_RECEIVED_EARLY);
- goto f_err;
- }
-
- rr->length=0;
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
-
- s->s3->change_cipher_spec=1;
- if (!ssl3_do_change_cipher_spec(s))
- goto err;
- else
- goto start;
- }
-
- /* Unexpected handshake message (Client Hello, or protocol violation) */
- if ((s->s3->handshake_fragment_len >= 4) && !s->in_handshake)
- {
- if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
- !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
- {
-#if 0 /* worked only because C operator preferences are not as expected (and
- * because this is not really needed for clients except for detecting
- * protocol violations): */
- s->state=SSL_ST_BEFORE|(s->server)
- ?SSL_ST_ACCEPT
- :SSL_ST_CONNECT;
-#else
- s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
-#endif
- s->renegotiate=1;
- s->new_session=1;
- }
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return(-1);
- }
-
- if (!(s->mode & SSL_MODE_AUTO_RETRY))
- {
- if (s->s3->rbuf.left == 0) /* no read-ahead left? */
- {
- BIO *bio;
- /* In the case where we try to read application data,
- * but we trigger an SSL handshake, we return -1 with
- * the retry option set. Otherwise renegotiation may
- * cause nasty problems in the blocking world */
- s->rwstate=SSL_READING;
- bio=SSL_get_rbio(s);
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return(-1);
- }
- }
- goto start;
- }
-
- switch (rr->type)
- {
- default:
-#ifndef OPENSSL_NO_TLS
- /* TLS up to v1.1 just ignores unknown message types:
- * TLS v1.2 give an unexpected message alert.
- */
- if (s->version >= TLS1_VERSION && s->version <= TLS1_1_VERSION)
- {
- rr->length = 0;
- goto start;
- }
-#endif
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
- goto f_err;
- case SSL3_RT_CHANGE_CIPHER_SPEC:
- case SSL3_RT_ALERT:
- case SSL3_RT_HANDSHAKE:
- /* we already handled all of these, with the possible exception
- * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that
- * should not happen when type != rr->type */
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_READ_BYTES,ERR_R_INTERNAL_ERROR);
- goto f_err;
- case SSL3_RT_APPLICATION_DATA:
- /* At this point, we were expecting handshake data,
- * but have application data. If the library was
- * running inside ssl3_read() (i.e. in_read_app_data
- * is set) and it makes sense to read application data
- * at this point (session renegotiation not yet started),
- * we will indulge it.
- */
- if (s->s3->in_read_app_data &&
- (s->s3->total_renegotiations != 0) &&
- ((
- (s->state & SSL_ST_CONNECT) &&
- (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
- (s->state <= SSL3_ST_CR_SRVR_HELLO_A)
- ) || (
- (s->state & SSL_ST_ACCEPT) &&
- (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
- (s->state >= SSL3_ST_SR_CLNT_HELLO_A)
- )
- ))
- {
- s->s3->in_read_app_data=2;
- return(-1);
- }
- else
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
- goto f_err;
- }
- }
- /* not reached */
-
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
- return(-1);
- }
-
-int ssl3_do_change_cipher_spec(SSL *s)
- {
- int i;
- const char *sender;
- int slen;
-
- if (s->state & SSL_ST_ACCEPT)
- i=SSL3_CHANGE_CIPHER_SERVER_READ;
- else
- i=SSL3_CHANGE_CIPHER_CLIENT_READ;
-
- if (s->s3->tmp.key_block == NULL)
- {
- if (s->session == NULL)
- {
- /* might happen if dtls1_read_bytes() calls this */
- SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC,SSL_R_CCS_RECEIVED_EARLY);
- return (0);
- }
-
- s->session->cipher=s->s3->tmp.new_cipher;
- if (!s->method->ssl3_enc->setup_key_block(s)) return(0);
- }
-
- if (!s->method->ssl3_enc->change_cipher_state(s,i))
- return(0);
-
- /* we have to record the message digest at
- * this point so we can get it before we read
- * the finished message */
- if (s->state & SSL_ST_CONNECT)
- {
- sender=s->method->ssl3_enc->server_finished_label;
- slen=s->method->ssl3_enc->server_finished_label_len;
- }
- else
- {
- sender=s->method->ssl3_enc->client_finished_label;
- slen=s->method->ssl3_enc->client_finished_label_len;
- }
-
- i = s->method->ssl3_enc->final_finish_mac(s,
- sender,slen,s->s3->tmp.peer_finish_md);
- if (i == 0)
- {
- SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- s->s3->tmp.peer_finish_md_len = i;
-
- return(1);
- }
-
-int ssl3_send_alert(SSL *s, int level, int desc)
- {
- /* Map tls/ssl alert value to correct one */
- desc=s->method->ssl3_enc->alert_value(desc);
- if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
- desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have protocol_version alerts */
- if (desc < 0) return -1;
- /* If a fatal one, remove from cache */
- if ((level == 2) && (s->session != NULL))
- SSL_CTX_remove_session(s->ctx,s->session);
-
- s->s3->alert_dispatch=1;
- s->s3->send_alert[0]=level;
- s->s3->send_alert[1]=desc;
- if (s->s3->wbuf.left == 0) /* data still being written out? */
- return s->method->ssl_dispatch_alert(s);
- /* else data is still being written out, we will get written
- * some time in the future */
- return -1;
- }
-
-int ssl3_dispatch_alert(SSL *s)
- {
- int i,j;
- void (*cb)(const SSL *ssl,int type,int val)=NULL;
-
- s->s3->alert_dispatch=0;
- i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0);
- if (i <= 0)
- {
- s->s3->alert_dispatch=1;
- }
- else
- {
- /* Alert sent to BIO. If it is important, flush it now.
- * If the message does not get sent due to non-blocking IO,
- * we will not worry too much. */
- if (s->s3->send_alert[0] == SSL3_AL_FATAL)
- (void)BIO_flush(s->wbio);
-
- if (s->msg_callback)
- s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 2, s, s->msg_callback_arg);
-
- if (s->info_callback != NULL)
- cb=s->info_callback;
- else if (s->ctx->info_callback != NULL)
- cb=s->ctx->info_callback;
-
- if (cb != NULL)
- {
- j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1];
- cb(s,SSL_CB_WRITE_ALERT,j);
- }
- }
- return(i);
- }
diff --git a/drivers/builtin_openssl/ssl/s3_srvr.c b/drivers/builtin_openssl/ssl/s3_srvr.c
deleted file mode 100644
index 9ac19c05f2..0000000000
--- a/drivers/builtin_openssl/ssl/s3_srvr.c
+++ /dev/null
@@ -1,3593 +0,0 @@
-/* ssl/s3_srvr.c -*- mode:C; c-file-style: "eay" -*- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the OpenSSL open source
- * license provided above.
- *
- * ECC cipher suite support in OpenSSL originally written by
- * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
- *
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#define REUSE_CIPHER_BUG
-#define NETSCAPE_HANG_BUG
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include "kssl_lcl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/x509.h>
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#endif
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_KRB5
-#include <openssl/krb5_asn.h>
-#endif
-#include <openssl/md5.h>
-
-static const SSL_METHOD *ssl3_get_server_method(int ver);
-
-static const SSL_METHOD *ssl3_get_server_method(int ver)
- {
- if (ver == SSL3_VERSION)
- return(SSLv3_server_method());
- else
- return(NULL);
- }
-
-#ifndef OPENSSL_NO_SRP
-static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
- {
- int ret = SSL_ERROR_NONE;
-
- *al = SSL_AD_UNRECOGNIZED_NAME;
-
- if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
- (s->srp_ctx.TLS_ext_srp_username_callback != NULL))
- {
- if(s->srp_ctx.login == NULL)
- {
- /* RFC 5054 says SHOULD reject,
- we do so if There is no srp login name */
- ret = SSL3_AL_FATAL;
- *al = SSL_AD_UNKNOWN_PSK_IDENTITY;
- }
- else
- {
- ret = SSL_srp_server_param_with_username(s,al);
- }
- }
- return ret;
- }
-#endif
-
-IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
- ssl3_accept,
- ssl_undefined_function,
- ssl3_get_server_method)
-
-int ssl3_accept(SSL *s)
- {
- BUF_MEM *buf;
- unsigned long alg_k,Time=(unsigned long)time(NULL);
- void (*cb)(const SSL *ssl,int type,int val)=NULL;
- int ret= -1;
- int new_state,state,skip=0;
-
- RAND_add(&Time,sizeof(Time),0);
- ERR_clear_error();
- clear_sys_error();
-
- if (s->info_callback != NULL)
- cb=s->info_callback;
- else if (s->ctx->info_callback != NULL)
- cb=s->ctx->info_callback;
-
- /* init things to blank */
- s->in_handshake++;
- if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
-
- if (s->cert == NULL)
- {
- SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
- return(-1);
- }
-
-#ifndef OPENSSL_NO_HEARTBEATS
- /* If we're awaiting a HeartbeatResponse, pretend we
- * already got and don't await it anymore, because
- * Heartbeats don't make sense during handshakes anyway.
- */
- if (s->tlsext_hb_pending)
- {
- s->tlsext_hb_pending = 0;
- s->tlsext_hb_seq++;
- }
-#endif
-
- for (;;)
- {
- state=s->state;
-
- switch (s->state)
- {
- case SSL_ST_RENEGOTIATE:
- s->renegotiate=1;
- /* s->state=SSL_ST_ACCEPT; */
-
- case SSL_ST_BEFORE:
- case SSL_ST_ACCEPT:
- case SSL_ST_BEFORE|SSL_ST_ACCEPT:
- case SSL_ST_OK|SSL_ST_ACCEPT:
-
- s->server=1;
- if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
-
- if ((s->version>>8) != 3)
- {
- SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
- return -1;
- }
- s->type=SSL_ST_ACCEPT;
-
- if (s->init_buf == NULL)
- {
- if ((buf=BUF_MEM_new()) == NULL)
- {
- ret= -1;
- goto end;
- }
- if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
- {
- ret= -1;
- goto end;
- }
- s->init_buf=buf;
- }
-
- if (!ssl3_setup_buffers(s))
- {
- ret= -1;
- goto end;
- }
-
- s->init_num=0;
- s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
-
- if (s->state != SSL_ST_RENEGOTIATE)
- {
- /* Ok, we now need to push on a buffering BIO so that
- * the output is sent in a way that TCP likes :-)
- */
- if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }
-
- ssl3_init_finished_mac(s);
- s->state=SSL3_ST_SR_CLNT_HELLO_A;
- s->ctx->stats.sess_accept++;
- }
- else if (!s->s3->send_connection_binding &&
- !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
- {
- /* Server attempting to renegotiate with
- * client that doesn't support secure
- * renegotiation.
- */
- SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
- ret = -1;
- goto end;
- }
- else
- {
- /* s->state == SSL_ST_RENEGOTIATE,
- * we will just send a HelloRequest */
- s->ctx->stats.sess_accept_renegotiate++;
- s->state=SSL3_ST_SW_HELLO_REQ_A;
- }
- break;
-
- case SSL3_ST_SW_HELLO_REQ_A:
- case SSL3_ST_SW_HELLO_REQ_B:
-
- s->shutdown=0;
- ret=ssl3_send_hello_request(s);
- if (ret <= 0) goto end;
- s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
- s->state=SSL3_ST_SW_FLUSH;
- s->init_num=0;
-
- ssl3_init_finished_mac(s);
- break;
-
- case SSL3_ST_SW_HELLO_REQ_C:
- s->state=SSL_ST_OK;
- break;
-
- case SSL3_ST_SR_CLNT_HELLO_A:
- case SSL3_ST_SR_CLNT_HELLO_B:
- case SSL3_ST_SR_CLNT_HELLO_C:
-
- s->shutdown=0;
- if (s->rwstate != SSL_X509_LOOKUP)
- {
- ret=ssl3_get_client_hello(s);
- if (ret <= 0) goto end;
- }
-#ifndef OPENSSL_NO_SRP
- {
- int al;
- if ((ret = ssl_check_srp_ext_ClientHello(s,&al)) < 0)
- {
- /* callback indicates firther work to be done */
- s->rwstate=SSL_X509_LOOKUP;
- goto end;
- }
- if (ret != SSL_ERROR_NONE)
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- /* This is not really an error but the only means to
- for a client to detect whether srp is supported. */
- if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
- SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT);
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- ret= -1;
- goto end;
- }
- }
-#endif
-
- s->renegotiate = 2;
- s->state=SSL3_ST_SW_SRVR_HELLO_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_SRVR_HELLO_A:
- case SSL3_ST_SW_SRVR_HELLO_B:
- ret=ssl3_send_server_hello(s);
- if (ret <= 0) goto end;
-#ifndef OPENSSL_NO_TLSEXT
- if (s->hit)
- {
- if (s->tlsext_ticket_expected)
- s->state=SSL3_ST_SW_SESSION_TICKET_A;
- else
- s->state=SSL3_ST_SW_CHANGE_A;
- }
-#else
- if (s->hit)
- s->state=SSL3_ST_SW_CHANGE_A;
-#endif
- else
- s->state=SSL3_ST_SW_CERT_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_CERT_A:
- case SSL3_ST_SW_CERT_B:
- /* Check if it is anon DH or anon ECDH, */
- /* normal PSK or KRB5 or SRP */
- if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
- && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
- && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
- {
- ret=ssl3_send_server_certificate(s);
- if (ret <= 0) goto end;
-#ifndef OPENSSL_NO_TLSEXT
- if (s->tlsext_status_expected)
- s->state=SSL3_ST_SW_CERT_STATUS_A;
- else
- s->state=SSL3_ST_SW_KEY_EXCH_A;
- }
- else
- {
- skip = 1;
- s->state=SSL3_ST_SW_KEY_EXCH_A;
- }
-#else
- }
- else
- skip=1;
-
- s->state=SSL3_ST_SW_KEY_EXCH_A;
-#endif
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_KEY_EXCH_A:
- case SSL3_ST_SW_KEY_EXCH_B:
- alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
- /* clear this, it may get reset by
- * send_server_key_exchange */
- if ((s->options & SSL_OP_EPHEMERAL_RSA)
-#ifndef OPENSSL_NO_KRB5
- && !(alg_k & SSL_kKRB5)
-#endif /* OPENSSL_NO_KRB5 */
- )
- /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
- * even when forbidden by protocol specs
- * (handshake may fail as clients are not required to
- * be able to handle this) */
- s->s3->tmp.use_rsa_tmp=1;
- else
- s->s3->tmp.use_rsa_tmp=0;
-
-
- /* only send if a DH key exchange, fortezza or
- * RSA but we have a sign only certificate
- *
- * PSK: may send PSK identity hints
- *
- * For ECC ciphersuites, we send a serverKeyExchange
- * message only if the cipher suite is either
- * ECDH-anon or ECDHE. In other cases, the
- * server certificate contains the server's
- * public key for key exchange.
- */
- if (s->s3->tmp.use_rsa_tmp
- /* PSK: send ServerKeyExchange if PSK identity
- * hint if provided */
-#ifndef OPENSSL_NO_PSK
- || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
-#endif
-#ifndef OPENSSL_NO_SRP
- /* SRP: send ServerKeyExchange */
- || (alg_k & SSL_kSRP)
-#endif
- || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH))
- || (alg_k & SSL_kEECDH)
- || ((alg_k & SSL_kRSA)
- && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
- || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
- && EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
- )
- )
- )
- )
- {
- ret=ssl3_send_server_key_exchange(s);
- if (ret <= 0) goto end;
- }
- else
- skip=1;
-
- s->state=SSL3_ST_SW_CERT_REQ_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_CERT_REQ_A:
- case SSL3_ST_SW_CERT_REQ_B:
- if (/* don't request cert unless asked for it: */
- !(s->verify_mode & SSL_VERIFY_PEER) ||
- /* if SSL_VERIFY_CLIENT_ONCE is set,
- * don't request cert during re-negotiation: */
- ((s->session->peer != NULL) &&
- (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
- /* never request cert in anonymous ciphersuites
- * (see section "Certificate request" in SSL 3 drafts
- * and in RFC 2246): */
- ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
- /* ... except when the application insists on verification
- * (against the specs, but s3_clnt.c accepts this for SSL 3) */
- !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
- /* never request cert in Kerberos ciphersuites */
- (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
- /* With normal PSK Certificates and
- * Certificate Requests are omitted */
- || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
- {
- /* no cert request */
- skip=1;
- s->s3->tmp.cert_request=0;
- s->state=SSL3_ST_SW_SRVR_DONE_A;
- if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
- return -1;
- }
- else
- {
- s->s3->tmp.cert_request=1;
- ret=ssl3_send_certificate_request(s);
- if (ret <= 0) goto end;
-#ifndef NETSCAPE_HANG_BUG
- s->state=SSL3_ST_SW_SRVR_DONE_A;
-#else
- s->state=SSL3_ST_SW_FLUSH;
- s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
-#endif
- s->init_num=0;
- }
- break;
-
- case SSL3_ST_SW_SRVR_DONE_A:
- case SSL3_ST_SW_SRVR_DONE_B:
- ret=ssl3_send_server_done(s);
- if (ret <= 0) goto end;
- s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
- s->state=SSL3_ST_SW_FLUSH;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_FLUSH:
-
- /* This code originally checked to see if
- * any data was pending using BIO_CTRL_INFO
- * and then flushed. This caused problems
- * as documented in PR#1939. The proposed
- * fix doesn't completely resolve this issue
- * as buggy implementations of BIO_CTRL_PENDING
- * still exist. So instead we just flush
- * unconditionally.
- */
-
- s->rwstate=SSL_WRITING;
- if (BIO_flush(s->wbio) <= 0)
- {
- ret= -1;
- goto end;
- }
- s->rwstate=SSL_NOTHING;
-
- s->state=s->s3->tmp.next_state;
- break;
-
- case SSL3_ST_SR_CERT_A:
- case SSL3_ST_SR_CERT_B:
- /* Check for second client hello (MS SGC) */
- ret = ssl3_check_client_hello(s);
- if (ret <= 0)
- goto end;
- if (ret == 2)
- s->state = SSL3_ST_SR_CLNT_HELLO_C;
- else {
- if (s->s3->tmp.cert_request)
- {
- ret=ssl3_get_client_certificate(s);
- if (ret <= 0) goto end;
- }
- s->init_num=0;
- s->state=SSL3_ST_SR_KEY_EXCH_A;
- }
- break;
-
- case SSL3_ST_SR_KEY_EXCH_A:
- case SSL3_ST_SR_KEY_EXCH_B:
- ret=ssl3_get_client_key_exchange(s);
- if (ret <= 0)
- goto end;
- if (ret == 2)
- {
- /* For the ECDH ciphersuites when
- * the client sends its ECDH pub key in
- * a certificate, the CertificateVerify
- * message is not sent.
- * Also for GOST ciphersuites when
- * the client uses its key from the certificate
- * for key exchange.
- */
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
- s->state=SSL3_ST_SR_FINISHED_A;
-#else
- if (s->s3->next_proto_neg_seen)
- s->state=SSL3_ST_SR_NEXT_PROTO_A;
- else
- s->state=SSL3_ST_SR_FINISHED_A;
-#endif
- s->init_num = 0;
- }
- else if (TLS1_get_version(s) >= TLS1_2_VERSION)
- {
- s->state=SSL3_ST_SR_CERT_VRFY_A;
- s->init_num=0;
- if (!s->session->peer)
- break;
- /* For TLS v1.2 freeze the handshake buffer
- * at this point and digest cached records.
- */
- if (!s->s3->handshake_buffer)
- {
- SSLerr(SSL_F_SSL3_ACCEPT,ERR_R_INTERNAL_ERROR);
- return -1;
- }
- s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
- if (!ssl3_digest_cached_records(s))
- return -1;
- }
- else
- {
- int offset=0;
- int dgst_num;
-
- s->state=SSL3_ST_SR_CERT_VRFY_A;
- s->init_num=0;
-
- /* We need to get hashes here so if there is
- * a client cert, it can be verified
- * FIXME - digest processing for CertificateVerify
- * should be generalized. But it is next step
- */
- if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
- return -1;
- for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++)
- if (s->s3->handshake_dgst[dgst_num])
- {
- int dgst_size;
-
- s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset]));
- dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
- if (dgst_size < 0)
- {
- ret = -1;
- goto end;
- }
- offset+=dgst_size;
- }
- }
- break;
-
- case SSL3_ST_SR_CERT_VRFY_A:
- case SSL3_ST_SR_CERT_VRFY_B:
-
- /* we should decide if we expected this one */
- ret=ssl3_get_cert_verify(s);
- if (ret <= 0) goto end;
-
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
- s->state=SSL3_ST_SR_FINISHED_A;
-#else
- if (s->s3->next_proto_neg_seen)
- s->state=SSL3_ST_SR_NEXT_PROTO_A;
- else
- s->state=SSL3_ST_SR_FINISHED_A;
-#endif
- s->init_num=0;
- break;
-
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
- case SSL3_ST_SR_NEXT_PROTO_A:
- case SSL3_ST_SR_NEXT_PROTO_B:
- ret=ssl3_get_next_proto(s);
- if (ret <= 0) goto end;
- s->init_num = 0;
- s->state=SSL3_ST_SR_FINISHED_A;
- break;
-#endif
-
- case SSL3_ST_SR_FINISHED_A:
- case SSL3_ST_SR_FINISHED_B:
- ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
- SSL3_ST_SR_FINISHED_B);
- if (ret <= 0) goto end;
- if (s->hit)
- s->state=SSL_ST_OK;
-#ifndef OPENSSL_NO_TLSEXT
- else if (s->tlsext_ticket_expected)
- s->state=SSL3_ST_SW_SESSION_TICKET_A;
-#endif
- else
- s->state=SSL3_ST_SW_CHANGE_A;
- s->init_num=0;
- break;
-
-#ifndef OPENSSL_NO_TLSEXT
- case SSL3_ST_SW_SESSION_TICKET_A:
- case SSL3_ST_SW_SESSION_TICKET_B:
- ret=ssl3_send_newsession_ticket(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_SW_CHANGE_A;
- s->init_num=0;
- break;
-
- case SSL3_ST_SW_CERT_STATUS_A:
- case SSL3_ST_SW_CERT_STATUS_B:
- ret=ssl3_send_cert_status(s);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_SW_KEY_EXCH_A;
- s->init_num=0;
- break;
-
-#endif
-
- case SSL3_ST_SW_CHANGE_A:
- case SSL3_ST_SW_CHANGE_B:
-
- s->session->cipher=s->s3->tmp.new_cipher;
- if (!s->method->ssl3_enc->setup_key_block(s))
- { ret= -1; goto end; }
-
- ret=ssl3_send_change_cipher_spec(s,
- SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);
-
- if (ret <= 0) goto end;
- s->state=SSL3_ST_SW_FINISHED_A;
- s->init_num=0;
-
- if (!s->method->ssl3_enc->change_cipher_state(s,
- SSL3_CHANGE_CIPHER_SERVER_WRITE))
- {
- ret= -1;
- goto end;
- }
-
- break;
-
- case SSL3_ST_SW_FINISHED_A:
- case SSL3_ST_SW_FINISHED_B:
- ret=ssl3_send_finished(s,
- SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
- s->method->ssl3_enc->server_finished_label,
- s->method->ssl3_enc->server_finished_label_len);
- if (ret <= 0) goto end;
- s->state=SSL3_ST_SW_FLUSH;
- if (s->hit)
- {
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
- s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
-#else
- if (s->s3->next_proto_neg_seen)
- s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PROTO_A;
- else
- s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
-#endif
- }
- else
- s->s3->tmp.next_state=SSL_ST_OK;
- s->init_num=0;
- break;
-
- case SSL_ST_OK:
- /* clean a few things up */
- ssl3_cleanup_key_block(s);
-
- BUF_MEM_free(s->init_buf);
- s->init_buf=NULL;
-
- /* remove buffering on output */
- ssl_free_wbio_buffer(s);
-
- s->init_num=0;
-
- if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
- {
- s->renegotiate=0;
- s->new_session=0;
-
- ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
-
- s->ctx->stats.sess_accept_good++;
- /* s->server=1; */
- s->handshake_func=ssl3_accept;
-
- if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
- }
-
- ret = 1;
- goto end;
- /* break; */
-
- default:
- SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_UNKNOWN_STATE);
- ret= -1;
- goto end;
- /* break; */
- }
-
- if (!s->s3->tmp.reuse_message && !skip)
- {
- if (s->debug)
- {
- if ((ret=BIO_flush(s->wbio)) <= 0)
- goto end;
- }
-
-
- if ((cb != NULL) && (s->state != state))
- {
- new_state=s->state;
- s->state=state;
- cb(s,SSL_CB_ACCEPT_LOOP,1);
- s->state=new_state;
- }
- }
- skip=0;
- }
-end:
- /* BIO_flush(s->wbio); */
-
- s->in_handshake--;
- if (cb != NULL)
- cb(s,SSL_CB_ACCEPT_EXIT,ret);
- return(ret);
- }
-
-int ssl3_send_hello_request(SSL *s)
- {
- unsigned char *p;
-
- if (s->state == SSL3_ST_SW_HELLO_REQ_A)
- {
- p=(unsigned char *)s->init_buf->data;
- *(p++)=SSL3_MT_HELLO_REQUEST;
- *(p++)=0;
- *(p++)=0;
- *(p++)=0;
-
- s->state=SSL3_ST_SW_HELLO_REQ_B;
- /* number of bytes to write */
- s->init_num=4;
- s->init_off=0;
- }
-
- /* SSL3_ST_SW_HELLO_REQ_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-int ssl3_check_client_hello(SSL *s)
- {
- int ok;
- long n;
-
- /* this function is called when we really expect a Certificate message,
- * so permit appropriate message length */
- n=s->method->ssl_get_message(s,
- SSL3_ST_SR_CERT_A,
- SSL3_ST_SR_CERT_B,
- -1,
- s->max_cert_list,
- &ok);
- if (!ok) return((int)n);
- s->s3->tmp.reuse_message = 1;
- if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
- {
- /* We only allow the client to restart the handshake once per
- * negotiation. */
- if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
- {
- SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS);
- return -1;
- }
- /* Throw away what we have done so far in the current handshake,
- * which will now be aborted. (A full SSL_clear would be too much.) */
-#ifndef OPENSSL_NO_DH
- if (s->s3->tmp.dh != NULL)
- {
- DH_free(s->s3->tmp.dh);
- s->s3->tmp.dh = NULL;
- }
-#endif
-#ifndef OPENSSL_NO_ECDH
- if (s->s3->tmp.ecdh != NULL)
- {
- EC_KEY_free(s->s3->tmp.ecdh);
- s->s3->tmp.ecdh = NULL;
- }
-#endif
- s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
- return 2;
- }
- return 1;
-}
-
-int ssl3_get_client_hello(SSL *s)
- {
- int i,j,ok,al,ret= -1;
- unsigned int cookie_len;
- long n;
- unsigned long id;
- unsigned char *p,*d,*q;
- SSL_CIPHER *c;
-#ifndef OPENSSL_NO_COMP
- SSL_COMP *comp=NULL;
-#endif
- STACK_OF(SSL_CIPHER) *ciphers=NULL;
-
- /* We do this so that we will respond with our native type.
- * If we are TLSv1 and we get SSLv3, we will respond with TLSv1,
- * This down switching should be handled by a different method.
- * If we are SSLv3, we will respond with SSLv3, even if prompted with
- * TLSv1.
- */
- if (s->state == SSL3_ST_SR_CLNT_HELLO_A
- )
- {
- s->state=SSL3_ST_SR_CLNT_HELLO_B;
- }
- s->first_packet=1;
- n=s->method->ssl_get_message(s,
- SSL3_ST_SR_CLNT_HELLO_B,
- SSL3_ST_SR_CLNT_HELLO_C,
- SSL3_MT_CLIENT_HELLO,
- SSL3_RT_MAX_PLAIN_LENGTH,
- &ok);
-
- if (!ok) return((int)n);
- s->first_packet=0;
- d=p=(unsigned char *)s->init_msg;
-
- /* use version from inside client hello, not from record header
- * (may differ: see RFC 2246, Appendix E, second paragraph) */
- s->client_version=(((int)p[0])<<8)|(int)p[1];
- p+=2;
-
- if ((s->version == DTLS1_VERSION && s->client_version > s->version) ||
- (s->version != DTLS1_VERSION && s->client_version < s->version))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
- if ((s->client_version>>8) == SSL3_VERSION_MAJOR &&
- !s->enc_write_ctx && !s->write_hash)
- {
- /* similar to ssl3_get_record, send alert using remote version number */
- s->version = s->client_version;
- }
- al = SSL_AD_PROTOCOL_VERSION;
- goto f_err;
- }
-
- /* If we require cookies and this ClientHello doesn't
- * contain one, just return since we do not want to
- * allocate any memory yet. So check cookie length...
- */
- if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)
- {
- unsigned int session_length, cookie_length;
-
- session_length = *(p + SSL3_RANDOM_SIZE);
- cookie_length = *(p + SSL3_RANDOM_SIZE + session_length + 1);
-
- if (cookie_length == 0)
- return 1;
- }
-
- /* load the client random */
- memcpy(s->s3->client_random,p,SSL3_RANDOM_SIZE);
- p+=SSL3_RANDOM_SIZE;
-
- /* get the session-id */
- j= *(p++);
-
- s->hit=0;
- /* Versions before 0.9.7 always allow clients to resume sessions in renegotiation.
- * 0.9.7 and later allow this by default, but optionally ignore resumption requests
- * with flag SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather
- * than a change to default behavior so that applications relying on this for security
- * won't even compile against older library versions).
- *
- * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to request
- * renegotiation but not a new session (s->new_session remains unset): for servers,
- * this essentially just means that the SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
- * setting will be ignored.
- */
- if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
- {
- if (!ssl_get_new_session(s,1))
- goto err;
- }
- else
- {
- i=ssl_get_prev_session(s, p, j, d + n);
- if (i == 1)
- { /* previous session */
- s->hit=1;
- }
- else if (i == -1)
- goto err;
- else /* i == 0 */
- {
- if (!ssl_get_new_session(s,1))
- goto err;
- }
- }
-
- p+=j;
-
- if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
- {
- /* cookie stuff */
- cookie_len = *(p++);
-
- /*
- * The ClientHello may contain a cookie even if the
- * HelloVerify message has not been sent--make sure that it
- * does not cause an overflow.
- */
- if ( cookie_len > sizeof(s->d1->rcvd_cookie))
- {
- /* too much data */
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
- goto f_err;
- }
-
- /* verify the cookie if appropriate option is set. */
- if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
- cookie_len > 0)
- {
- memcpy(s->d1->rcvd_cookie, p, cookie_len);
-
- if ( s->ctx->app_verify_cookie_cb != NULL)
- {
- if ( s->ctx->app_verify_cookie_cb(s, s->d1->rcvd_cookie,
- cookie_len) == 0)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
- SSL_R_COOKIE_MISMATCH);
- goto f_err;
- }
- /* else cookie verification succeeded */
- }
- else if ( memcmp(s->d1->rcvd_cookie, s->d1->cookie,
- s->d1->cookie_len) != 0) /* default verification */
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
- SSL_R_COOKIE_MISMATCH);
- goto f_err;
- }
-
- ret = 2;
- }
-
- p += cookie_len;
- }
-
- n2s(p,i);
- if ((i == 0) && (j != 0))
- {
- /* we need a cipher if we are not resuming a session */
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_SPECIFIED);
- goto f_err;
- }
- if ((p+i) >= (d+n))
- {
- /* not enough data */
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
- if ((i > 0) && (ssl_bytes_to_cipher_list(s,p,i,&(ciphers))
- == NULL))
- {
- goto err;
- }
- p+=i;
-
- /* If it is a hit, check that the cipher is in the list */
- if ((s->hit) && (i > 0))
- {
- j=0;
- id=s->session->cipher->id;
-
-#ifdef CIPHER_DEBUG
- printf("client sent %d ciphers\n",sk_num(ciphers));
-#endif
- for (i=0; i<sk_SSL_CIPHER_num(ciphers); i++)
- {
- c=sk_SSL_CIPHER_value(ciphers,i);
-#ifdef CIPHER_DEBUG
- printf("client [%2d of %2d]:%s\n",
- i,sk_num(ciphers),SSL_CIPHER_get_name(c));
-#endif
- if (c->id == id)
- {
- j=1;
- break;
- }
- }
-/* Disabled because it can be used in a ciphersuite downgrade
- * attack: CVE-2010-4180.
- */
-#if 0
- if (j == 0 && (s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1))
- {
- /* Special case as client bug workaround: the previously used cipher may
- * not be in the current list, the client instead might be trying to
- * continue using a cipher that before wasn't chosen due to server
- * preferences. We'll have to reject the connection if the cipher is not
- * enabled, though. */
- c = sk_SSL_CIPHER_value(ciphers, 0);
- if (sk_SSL_CIPHER_find(SSL_get_ciphers(s), c) >= 0)
- {
- s->session->cipher = c;
- j = 1;
- }
- }
-#endif
- if (j == 0)
- {
- /* we need to have the cipher in the cipher
- * list if we are asked to reuse it */
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_REQUIRED_CIPHER_MISSING);
- goto f_err;
- }
- }
-
- /* compression */
- i= *(p++);
- if ((p+i) > (d+n))
- {
- /* not enough data */
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
- q=p;
- for (j=0; j<i; j++)
- {
- if (p[j] == 0) break;
- }
-
- p+=i;
- if (j >= i)
- {
- /* no compress */
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_COMPRESSION_SPECIFIED);
- goto f_err;
- }
-
-#ifndef OPENSSL_NO_TLSEXT
- /* TLS extensions*/
- if (s->version >= SSL3_VERSION)
- {
- if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
- {
- /* 'al' set by ssl_parse_clienthello_tlsext */
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
- goto f_err;
- }
- }
- if (ssl_check_clienthello_tlsext_early(s) <= 0) {
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
-
- /* Check if we want to use external pre-shared secret for this
- * handshake for not reused session only. We need to generate
- * server_random before calling tls_session_secret_cb in order to allow
- * SessionTicket processing to use it in key derivation. */
- {
- unsigned char *pos;
- pos=s->s3->server_random;
- if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0)
- {
- al=SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
- }
-
- if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
- {
- SSL_CIPHER *pref_cipher=NULL;
-
- s->session->master_key_length=sizeof(s->session->master_key);
- if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
- ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
- {
- s->hit=1;
- s->session->ciphers=ciphers;
- s->session->verify_result=X509_V_OK;
-
- ciphers=NULL;
-
- /* check if some cipher was preferred by call back */
- pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
- if (pref_cipher == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
- goto f_err;
- }
-
- s->session->cipher=pref_cipher;
-
- if (s->cipher_list)
- sk_SSL_CIPHER_free(s->cipher_list);
-
- if (s->cipher_list_by_id)
- sk_SSL_CIPHER_free(s->cipher_list_by_id);
-
- s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
- s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
- }
- }
-#endif
-
- /* Worst case, we will use the NULL compression, but if we have other
- * options, we will now look for them. We have i-1 compression
- * algorithms from the client, starting at q. */
- s->s3->tmp.new_compression=NULL;
-#ifndef OPENSSL_NO_COMP
- /* This only happens if we have a cache hit */
- if (s->session->compress_meth != 0)
- {
- int m, comp_id = s->session->compress_meth;
- /* Perform sanity checks on resumed compression algorithm */
- /* Can't disable compression */
- if (s->options & SSL_OP_NO_COMPRESSION)
- {
- al=SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
- goto f_err;
- }
- /* Look for resumed compression method */
- for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++)
- {
- comp=sk_SSL_COMP_value(s->ctx->comp_methods,m);
- if (comp_id == comp->id)
- {
- s->s3->tmp.new_compression=comp;
- break;
- }
- }
- if (s->s3->tmp.new_compression == NULL)
- {
- al=SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INVALID_COMPRESSION_ALGORITHM);
- goto f_err;
- }
- /* Look for resumed method in compression list */
- for (m = 0; m < i; m++)
- {
- if (q[m] == comp_id)
- break;
- }
- if (m >= i)
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING);
- goto f_err;
- }
- }
- else if (s->hit)
- comp = NULL;
- else if (!(s->options & SSL_OP_NO_COMPRESSION) && s->ctx->comp_methods)
- { /* See if we have a match */
- int m,nn,o,v,done=0;
-
- nn=sk_SSL_COMP_num(s->ctx->comp_methods);
- for (m=0; m<nn; m++)
- {
- comp=sk_SSL_COMP_value(s->ctx->comp_methods,m);
- v=comp->id;
- for (o=0; o<i; o++)
- {
- if (v == q[o])
- {
- done=1;
- break;
- }
- }
- if (done) break;
- }
- if (done)
- s->s3->tmp.new_compression=comp;
- else
- comp=NULL;
- }
-#else
- /* If compression is disabled we'd better not try to resume a session
- * using compression.
- */
- if (s->session->compress_meth != 0)
- {
- al=SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
- goto f_err;
- }
-#endif
-
- /* Given s->session->ciphers and SSL_get_ciphers, we must
- * pick a cipher */
-
- if (!s->hit)
- {
-#ifdef OPENSSL_NO_COMP
- s->session->compress_meth=0;
-#else
- s->session->compress_meth=(comp == NULL)?0:comp->id;
-#endif
- if (s->session->ciphers != NULL)
- sk_SSL_CIPHER_free(s->session->ciphers);
- s->session->ciphers=ciphers;
- if (ciphers == NULL)
- {
- al=SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_PASSED);
- goto f_err;
- }
- ciphers=NULL;
- c=ssl3_choose_cipher(s,s->session->ciphers,
- SSL_get_ciphers(s));
-
- if (c == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
- goto f_err;
- }
- s->s3->tmp.new_cipher=c;
- }
- else
- {
- /* Session-id reuse */
-#ifdef REUSE_CIPHER_BUG
- STACK_OF(SSL_CIPHER) *sk;
- SSL_CIPHER *nc=NULL;
- SSL_CIPHER *ec=NULL;
-
- if (s->options & SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG)
- {
- sk=s->session->ciphers;
- for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
- {
- c=sk_SSL_CIPHER_value(sk,i);
- if (c->algorithm_enc & SSL_eNULL)
- nc=c;
- if (SSL_C_IS_EXPORT(c))
- ec=c;
- }
- if (nc != NULL)
- s->s3->tmp.new_cipher=nc;
- else if (ec != NULL)
- s->s3->tmp.new_cipher=ec;
- else
- s->s3->tmp.new_cipher=s->session->cipher;
- }
- else
-#endif
- s->s3->tmp.new_cipher=s->session->cipher;
- }
-
- if (TLS1_get_version(s) < TLS1_2_VERSION || !(s->verify_mode & SSL_VERIFY_PEER))
- {
- if (!ssl3_digest_cached_records(s))
- {
- al = SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
- }
-
- /* we now have the following setup.
- * client_random
- * cipher_list - our prefered list of ciphers
- * ciphers - the clients prefered list of ciphers
- * compression - basically ignored right now
- * ssl version is set - sslv3
- * s->session - The ssl session has been setup.
- * s->hit - session reuse flag
- * s->tmp.new_cipher - the new cipher to use.
- */
-
- /* Handles TLS extensions that we couldn't check earlier */
- if (s->version >= SSL3_VERSION)
- {
- if (ssl_check_clienthello_tlsext_late(s) <= 0)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
- }
-
- if (ret < 0) ret=1;
- if (0)
- {
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- }
-err:
- if (ciphers != NULL) sk_SSL_CIPHER_free(ciphers);
- return(ret);
- }
-
-int ssl3_send_server_hello(SSL *s)
- {
- unsigned char *buf;
- unsigned char *p,*d;
- int i,sl;
- unsigned long l;
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
- {
- buf=(unsigned char *)s->init_buf->data;
-#ifdef OPENSSL_NO_TLSEXT
- p=s->s3->server_random;
- if (ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE) <= 0)
- return -1;
-#endif
- /* Do the message type and length last */
- d=p= &(buf[4]);
-
- *(p++)=s->version>>8;
- *(p++)=s->version&0xff;
-
- /* Random stuff */
- memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
- p+=SSL3_RANDOM_SIZE;
-
- /* There are several cases for the session ID to send
- * back in the server hello:
- * - For session reuse from the session cache,
- * we send back the old session ID.
- * - If stateless session reuse (using a session ticket)
- * is successful, we send back the client's "session ID"
- * (which doesn't actually identify the session).
- * - If it is a new session, we send back the new
- * session ID.
- * - However, if we want the new session to be single-use,
- * we send back a 0-length session ID.
- * s->hit is non-zero in either case of session reuse,
- * so the following won't overwrite an ID that we're supposed
- * to send back.
- */
- if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
- && !s->hit)
- s->session->session_id_length=0;
-
- sl=s->session->session_id_length;
- if (sl > (int)sizeof(s->session->session_id))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
- return -1;
- }
- *(p++)=sl;
- memcpy(p,s->session->session_id,sl);
- p+=sl;
-
- /* put the cipher */
- i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
- p+=i;
-
- /* put the compression method */
-#ifdef OPENSSL_NO_COMP
- *(p++)=0;
-#else
- if (s->s3->tmp.new_compression == NULL)
- *(p++)=0;
- else
- *(p++)=s->s3->tmp.new_compression->id;
-#endif
-#ifndef OPENSSL_NO_TLSEXT
- if (ssl_prepare_serverhello_tlsext(s) <= 0)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
- return -1;
- }
- if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
- return -1;
- }
-#endif
- /* do the header */
- l=(p-d);
- d=buf;
- *(d++)=SSL3_MT_SERVER_HELLO;
- l2n3(l,d);
-
- s->state=SSL3_ST_SW_SRVR_HELLO_B;
- /* number of bytes to write */
- s->init_num=p-buf;
- s->init_off=0;
- }
-
- /* SSL3_ST_SW_SRVR_HELLO_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-int ssl3_send_server_done(SSL *s)
- {
- unsigned char *p;
-
- if (s->state == SSL3_ST_SW_SRVR_DONE_A)
- {
- p=(unsigned char *)s->init_buf->data;
-
- /* do the header */
- *(p++)=SSL3_MT_SERVER_DONE;
- *(p++)=0;
- *(p++)=0;
- *(p++)=0;
-
- s->state=SSL3_ST_SW_SRVR_DONE_B;
- /* number of bytes to write */
- s->init_num=4;
- s->init_off=0;
- }
-
- /* SSL3_ST_SW_SRVR_DONE_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-int ssl3_send_server_key_exchange(SSL *s)
- {
-#ifndef OPENSSL_NO_RSA
- unsigned char *q;
- int j,num;
- RSA *rsa;
- unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
- unsigned int u;
-#endif
-#ifndef OPENSSL_NO_DH
- DH *dh=NULL,*dhp;
-#endif
-#ifndef OPENSSL_NO_ECDH
- EC_KEY *ecdh=NULL, *ecdhp;
- unsigned char *encodedPoint = NULL;
- int encodedlen = 0;
- int curve_id = 0;
- BN_CTX *bn_ctx = NULL;
-#endif
- EVP_PKEY *pkey;
- const EVP_MD *md = NULL;
- unsigned char *p,*d;
- int al,i;
- unsigned long type;
- int n;
- CERT *cert;
- BIGNUM *r[4];
- int nr[4],kn;
- BUF_MEM *buf;
- EVP_MD_CTX md_ctx;
-
- EVP_MD_CTX_init(&md_ctx);
- if (s->state == SSL3_ST_SW_KEY_EXCH_A)
- {
- type=s->s3->tmp.new_cipher->algorithm_mkey;
- cert=s->cert;
-
- buf=s->init_buf;
-
- r[0]=r[1]=r[2]=r[3]=NULL;
- n=0;
-#ifndef OPENSSL_NO_RSA
- if (type & SSL_kRSA)
- {
- rsa=cert->rsa_tmp;
- if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
- {
- rsa=s->cert->rsa_tmp_cb(s,
- SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
- SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
- if(rsa == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
- goto f_err;
- }
- RSA_up_ref(rsa);
- cert->rsa_tmp=rsa;
- }
- if (rsa == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_KEY);
- goto f_err;
- }
- r[0]=rsa->n;
- r[1]=rsa->e;
- s->s3->tmp.use_rsa_tmp=1;
- }
- else
-#endif
-#ifndef OPENSSL_NO_DH
- if (type & SSL_kEDH)
- {
- dhp=cert->dh_tmp;
- if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
- dhp=s->cert->dh_tmp_cb(s,
- SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
- SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
- if (dhp == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
- goto f_err;
- }
-
- if (s->s3->tmp.dh != NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- if ((dh=DHparams_dup(dhp)) == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
- goto err;
- }
-
- s->s3->tmp.dh=dh;
- if ((dhp->pub_key == NULL ||
- dhp->priv_key == NULL ||
- (s->options & SSL_OP_SINGLE_DH_USE)))
- {
- if(!DH_generate_key(dh))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
- ERR_R_DH_LIB);
- goto err;
- }
- }
- else
- {
- dh->pub_key=BN_dup(dhp->pub_key);
- dh->priv_key=BN_dup(dhp->priv_key);
- if ((dh->pub_key == NULL) ||
- (dh->priv_key == NULL))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
- goto err;
- }
- }
- r[0]=dh->p;
- r[1]=dh->g;
- r[2]=dh->pub_key;
- }
- else
-#endif
-#ifndef OPENSSL_NO_ECDH
- if (type & SSL_kEECDH)
- {
- const EC_GROUP *group;
-
- ecdhp=cert->ecdh_tmp;
- if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
- {
- ecdhp=s->cert->ecdh_tmp_cb(s,
- SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
- SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
- }
- if (ecdhp == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
- goto f_err;
- }
-
- if (s->s3->tmp.ecdh != NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- /* Duplicate the ECDH structure. */
- if (ecdhp == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
- if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
-
- s->s3->tmp.ecdh=ecdh;
- if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
- (EC_KEY_get0_private_key(ecdh) == NULL) ||
- (s->options & SSL_OP_SINGLE_ECDH_USE))
- {
- if(!EC_KEY_generate_key(ecdh))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
- }
-
- if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
- (EC_KEY_get0_public_key(ecdh) == NULL) ||
- (EC_KEY_get0_private_key(ecdh) == NULL))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
-
- if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
- (EC_GROUP_get_degree(group) > 163))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
- goto err;
- }
-
- /* XXX: For now, we only support ephemeral ECDH
- * keys over named (not generic) curves. For
- * supported named curves, curve_id is non-zero.
- */
- if ((curve_id =
- tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
- == 0)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
- goto err;
- }
-
- /* Encode the public key.
- * First check the size of encoding and
- * allocate memory accordingly.
- */
- encodedlen = EC_POINT_point2oct(group,
- EC_KEY_get0_public_key(ecdh),
- POINT_CONVERSION_UNCOMPRESSED,
- NULL, 0, NULL);
-
- encodedPoint = (unsigned char *)
- OPENSSL_malloc(encodedlen*sizeof(unsigned char));
- bn_ctx = BN_CTX_new();
- if ((encodedPoint == NULL) || (bn_ctx == NULL))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
-
- encodedlen = EC_POINT_point2oct(group,
- EC_KEY_get0_public_key(ecdh),
- POINT_CONVERSION_UNCOMPRESSED,
- encodedPoint, encodedlen, bn_ctx);
-
- if (encodedlen == 0)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
- goto err;
- }
-
- BN_CTX_free(bn_ctx); bn_ctx=NULL;
-
- /* XXX: For now, we only support named (not
- * generic) curves in ECDH ephemeral key exchanges.
- * In this situation, we need four additional bytes
- * to encode the entire ServerECDHParams
- * structure.
- */
- n = 4 + encodedlen;
-
- /* We'll generate the serverKeyExchange message
- * explicitly so we can set these to NULLs
- */
- r[0]=NULL;
- r[1]=NULL;
- r[2]=NULL;
- r[3]=NULL;
- }
- else
-#endif /* !OPENSSL_NO_ECDH */
-#ifndef OPENSSL_NO_PSK
- if (type & SSL_kPSK)
- {
- /* reserve size for record length and PSK identity hint*/
- n+=2+strlen(s->ctx->psk_identity_hint);
- }
- else
-#endif /* !OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_SRP
- if (type & SSL_kSRP)
- {
- if ((s->srp_ctx.N == NULL) ||
- (s->srp_ctx.g == NULL) ||
- (s->srp_ctx.s == NULL) ||
- (s->srp_ctx.B == NULL))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_SRP_PARAM);
- goto err;
- }
- r[0]=s->srp_ctx.N;
- r[1]=s->srp_ctx.g;
- r[2]=s->srp_ctx.s;
- r[3]=s->srp_ctx.B;
- }
- else
-#endif
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
- goto f_err;
- }
- for (i=0; i < 4 && r[i] != NULL; i++)
- {
- nr[i]=BN_num_bytes(r[i]);
-#ifndef OPENSSL_NO_SRP
- if ((i == 2) && (type & SSL_kSRP))
- n+=1+nr[i];
- else
-#endif
- n+=2+nr[i];
- }
-
- if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
- && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
- {
- if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher,&md))
- == NULL)
- {
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- kn=EVP_PKEY_size(pkey);
- }
- else
- {
- pkey=NULL;
- kn=0;
- }
-
- if (!BUF_MEM_grow_clean(buf,n+4+kn))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF);
- goto err;
- }
- d=(unsigned char *)s->init_buf->data;
- p= &(d[4]);
-
- for (i=0; i < 4 && r[i] != NULL; i++)
- {
-#ifndef OPENSSL_NO_SRP
- if ((i == 2) && (type & SSL_kSRP))
- {
- *p = nr[i];
- p++;
- }
- else
-#endif
- s2n(nr[i],p);
- BN_bn2bin(r[i],p);
- p+=nr[i];
- }
-
-#ifndef OPENSSL_NO_ECDH
- if (type & SSL_kEECDH)
- {
- /* XXX: For now, we only support named (not generic) curves.
- * In this situation, the serverKeyExchange message has:
- * [1 byte CurveType], [2 byte CurveName]
- * [1 byte length of encoded point], followed by
- * the actual encoded point itself
- */
- *p = NAMED_CURVE_TYPE;
- p += 1;
- *p = 0;
- p += 1;
- *p = curve_id;
- p += 1;
- *p = encodedlen;
- p += 1;
- memcpy((unsigned char*)p,
- (unsigned char *)encodedPoint,
- encodedlen);
- OPENSSL_free(encodedPoint);
- encodedPoint = NULL;
- p += encodedlen;
- }
-#endif
-
-#ifndef OPENSSL_NO_PSK
- if (type & SSL_kPSK)
- {
- /* copy PSK identity hint */
- s2n(strlen(s->ctx->psk_identity_hint), p);
- strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
- p+=strlen(s->ctx->psk_identity_hint);
- }
-#endif
-
- /* not anonymous */
- if (pkey != NULL)
- {
- /* n is the length of the params, they start at &(d[4])
- * and p points to the space at the end. */
-#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA
- && TLS1_get_version(s) < TLS1_2_VERSION)
- {
- q=md_buf;
- j=0;
- for (num=2; num > 0; num--)
- {
- EVP_MD_CTX_set_flags(&md_ctx,
- EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
- EVP_DigestInit_ex(&md_ctx,(num == 2)
- ?s->ctx->md5:s->ctx->sha1, NULL);
- EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_DigestUpdate(&md_ctx,&(d[4]),n);
- EVP_DigestFinal_ex(&md_ctx,q,
- (unsigned int *)&i);
- q+=i;
- j+=i;
- }
- if (RSA_sign(NID_md5_sha1, md_buf, j,
- &(p[2]), &u, pkey->pkey.rsa) <= 0)
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
- goto err;
- }
- s2n(u,p);
- n+=u+2;
- }
- else
-#endif
- if (md)
- {
- /* For TLS1.2 and later send signature
- * algorithm */
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- {
- if (!tls12_get_sigandhash(p, pkey, md))
- {
- /* Should never happen */
- al=SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto f_err;
- }
- p+=2;
- }
-#ifdef SSL_DEBUG
- fprintf(stderr, "Using hash %s\n",
- EVP_MD_name(md));
-#endif
- EVP_SignInit_ex(&md_ctx, md, NULL);
- EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(d[4]),n);
- if (!EVP_SignFinal(&md_ctx,&(p[2]),
- (unsigned int *)&i,pkey))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_EVP);
- goto err;
- }
- s2n(i,p);
- n+=i+2;
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- n+= 2;
- }
- else
- {
- /* Is this error check actually needed? */
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
- goto f_err;
- }
- }
-
- *(d++)=SSL3_MT_SERVER_KEY_EXCHANGE;
- l2n3(n,d);
-
- /* we should now have things packed up, so lets send
- * it off */
- s->init_num=n+4;
- s->init_off=0;
- }
-
- s->state = SSL3_ST_SW_KEY_EXCH_B;
- EVP_MD_CTX_cleanup(&md_ctx);
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
-#ifndef OPENSSL_NO_ECDH
- if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
- BN_CTX_free(bn_ctx);
-#endif
- EVP_MD_CTX_cleanup(&md_ctx);
- return(-1);
- }
-
-int ssl3_send_certificate_request(SSL *s)
- {
- unsigned char *p,*d;
- int i,j,nl,off,n;
- STACK_OF(X509_NAME) *sk=NULL;
- X509_NAME *name;
- BUF_MEM *buf;
-
- if (s->state == SSL3_ST_SW_CERT_REQ_A)
- {
- buf=s->init_buf;
-
- d=p=(unsigned char *)&(buf->data[4]);
-
- /* get the list of acceptable cert types */
- p++;
- n=ssl3_get_req_cert_type(s,p);
- d[0]=n;
- p+=n;
- n++;
-
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- {
- nl = tls12_get_req_sig_algs(s, p + 2);
- s2n(nl, p);
- p += nl + 2;
- n += nl + 2;
- }
-
- off=n;
- p+=2;
- n+=2;
-
- sk=SSL_get_client_CA_list(s);
- nl=0;
- if (sk != NULL)
- {
- for (i=0; i<sk_X509_NAME_num(sk); i++)
- {
- name=sk_X509_NAME_value(sk,i);
- j=i2d_X509_NAME(name,NULL);
- if (!BUF_MEM_grow_clean(buf,4+n+j+2))
- {
- SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
- goto err;
- }
- p=(unsigned char *)&(buf->data[4+n]);
- if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
- {
- s2n(j,p);
- i2d_X509_NAME(name,&p);
- n+=2+j;
- nl+=2+j;
- }
- else
- {
- d=p;
- i2d_X509_NAME(name,&p);
- j-=2; s2n(j,d); j+=2;
- n+=j;
- nl+=j;
- }
- }
- }
- /* else no CA names */
- p=(unsigned char *)&(buf->data[4+off]);
- s2n(nl,p);
-
- d=(unsigned char *)buf->data;
- *(d++)=SSL3_MT_CERTIFICATE_REQUEST;
- l2n3(n,d);
-
- /* we should now have things packed up, so lets send
- * it off */
-
- s->init_num=n+4;
- s->init_off=0;
-#ifdef NETSCAPE_HANG_BUG
- p=(unsigned char *)s->init_buf->data + s->init_num;
-
- /* do the header */
- *(p++)=SSL3_MT_SERVER_DONE;
- *(p++)=0;
- *(p++)=0;
- *(p++)=0;
- s->init_num += 4;
-#endif
-
- s->state = SSL3_ST_SW_CERT_REQ_B;
- }
-
- /* SSL3_ST_SW_CERT_REQ_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
-err:
- return(-1);
- }
-
-int ssl3_get_client_key_exchange(SSL *s)
- {
- int i,al,ok;
- long n;
- unsigned long alg_k;
- unsigned char *p;
-#ifndef OPENSSL_NO_RSA
- RSA *rsa=NULL;
- EVP_PKEY *pkey=NULL;
-#endif
-#ifndef OPENSSL_NO_DH
- BIGNUM *pub=NULL;
- DH *dh_srvr;
-#endif
-#ifndef OPENSSL_NO_KRB5
- KSSL_ERR kssl_err;
-#endif /* OPENSSL_NO_KRB5 */
-
-#ifndef OPENSSL_NO_ECDH
- EC_KEY *srvr_ecdh = NULL;
- EVP_PKEY *clnt_pub_pkey = NULL;
- EC_POINT *clnt_ecpoint = NULL;
- BN_CTX *bn_ctx = NULL;
-#endif
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_SR_KEY_EXCH_A,
- SSL3_ST_SR_KEY_EXCH_B,
- SSL3_MT_CLIENT_KEY_EXCHANGE,
- 2048, /* ??? */
- &ok);
-
- if (!ok) return((int)n);
- p=(unsigned char *)s->init_msg;
-
- alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
-
-#ifndef OPENSSL_NO_RSA
- if (alg_k & SSL_kRSA)
- {
- /* FIX THIS UP EAY EAY EAY EAY */
- if (s->s3->tmp.use_rsa_tmp)
- {
- if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL))
- rsa=s->cert->rsa_tmp;
- /* Don't do a callback because rsa_tmp should
- * be sent already */
- if (rsa == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_PKEY);
- goto f_err;
-
- }
- }
- else
- {
- pkey=s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
- if ( (pkey == NULL) ||
- (pkey->type != EVP_PKEY_RSA) ||
- (pkey->pkey.rsa == NULL))
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_RSA_CERTIFICATE);
- goto f_err;
- }
- rsa=pkey->pkey.rsa;
- }
-
- /* TLS and [incidentally] DTLS{0xFEFF} */
- if (s->version > SSL3_VERSION && s->version != DTLS1_BAD_VER)
- {
- n2s(p,i);
- if (n != i+2)
- {
- if (!(s->options & SSL_OP_TLS_D5_BUG))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
- goto err;
- }
- else
- p-=2;
- }
- else
- n=i;
- }
-
- i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
-
- al = -1;
-
- if (i != SSL_MAX_MASTER_KEY_LENGTH)
- {
- al=SSL_AD_DECODE_ERROR;
- /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */
- }
-
- if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
- {
- /* The premaster secret must contain the same version number as the
- * ClientHello to detect version rollback attacks (strangely, the
- * protocol does not offer such protection for DH ciphersuites).
- * However, buggy clients exist that send the negotiated protocol
- * version instead if the server does not support the requested
- * protocol version.
- * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
- if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
- (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
- {
- al=SSL_AD_DECODE_ERROR;
- /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
-
- /* The Klima-Pokorny-Rosa extension of Bleichenbacher's attack
- * (http://eprint.iacr.org/2003/052/) exploits the version
- * number check as a "bad version oracle" -- an alert would
- * reveal that the plaintext corresponding to some ciphertext
- * made up by the adversary is properly formatted except
- * that the version number is wrong. To avoid such attacks,
- * we should treat this just like any other decryption error. */
- }
- }
-
- if (al != -1)
- {
- /* Some decryption failure -- use random value instead as countermeasure
- * against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding
- * (see RFC 2246, section 7.4.7.1). */
- ERR_clear_error();
- i = SSL_MAX_MASTER_KEY_LENGTH;
- p[0] = s->client_version >> 8;
- p[1] = s->client_version & 0xff;
- if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */
- goto err;
- }
-
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,
- p,i);
- OPENSSL_cleanse(p,i);
- }
- else
-#endif
-#ifndef OPENSSL_NO_DH
- if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
- {
- n2s(p,i);
- if (n != i+2)
- {
- if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
- goto err;
- }
- else
- {
- p-=2;
- i=(int)n;
- }
- }
-
- if (n == 0L) /* the parameters are in the cert */
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_DECODE_DH_CERTS);
- goto f_err;
- }
- else
- {
- if (s->s3->tmp.dh == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
- goto f_err;
- }
- else
- dh_srvr=s->s3->tmp.dh;
- }
-
- pub=BN_bin2bn(p,i,NULL);
- if (pub == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BN_LIB);
- goto err;
- }
-
- i=DH_compute_key(p,pub,dh_srvr);
-
- if (i <= 0)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
- BN_clear_free(pub);
- goto err;
- }
-
- DH_free(s->s3->tmp.dh);
- s->s3->tmp.dh=NULL;
-
- BN_clear_free(pub);
- pub=NULL;
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,p,i);
- OPENSSL_cleanse(p,i);
- }
- else
-#endif
-#ifndef OPENSSL_NO_KRB5
- if (alg_k & SSL_kKRB5)
- {
- krb5_error_code krb5rc;
- krb5_data enc_ticket;
- krb5_data authenticator;
- krb5_data enc_pms;
- KSSL_CTX *kssl_ctx = s->kssl_ctx;
- EVP_CIPHER_CTX ciph_ctx;
- const EVP_CIPHER *enc = NULL;
- unsigned char iv[EVP_MAX_IV_LENGTH];
- unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH
- + EVP_MAX_BLOCK_LENGTH];
- int padl, outl;
- krb5_timestamp authtime = 0;
- krb5_ticket_times ttimes;
-
- EVP_CIPHER_CTX_init(&ciph_ctx);
-
- if (!kssl_ctx) kssl_ctx = kssl_ctx_new();
-
- n2s(p,i);
- enc_ticket.length = i;
-
- if (n < (long)(enc_ticket.length + 6))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DATA_LENGTH_TOO_LONG);
- goto err;
- }
-
- enc_ticket.data = (char *)p;
- p+=enc_ticket.length;
-
- n2s(p,i);
- authenticator.length = i;
-
- if (n < (long)(enc_ticket.length + authenticator.length + 6))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DATA_LENGTH_TOO_LONG);
- goto err;
- }
-
- authenticator.data = (char *)p;
- p+=authenticator.length;
-
- n2s(p,i);
- enc_pms.length = i;
- enc_pms.data = (char *)p;
- p+=enc_pms.length;
-
- /* Note that the length is checked again below,
- ** after decryption
- */
- if(enc_pms.length > sizeof pms)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DATA_LENGTH_TOO_LONG);
- goto err;
- }
-
- if (n != (long)(enc_ticket.length + authenticator.length +
- enc_pms.length + 6))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DATA_LENGTH_TOO_LONG);
- goto err;
- }
-
- if ((krb5rc = kssl_sget_tkt(kssl_ctx, &enc_ticket, &ttimes,
- &kssl_err)) != 0)
- {
-#ifdef KSSL_DEBUG
- printf("kssl_sget_tkt rtn %d [%d]\n",
- krb5rc, kssl_err.reason);
- if (kssl_err.text)
- printf("kssl_err text= %s\n", kssl_err.text);
-#endif /* KSSL_DEBUG */
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- kssl_err.reason);
- goto err;
- }
-
- /* Note: no authenticator is not considered an error,
- ** but will return authtime == 0.
- */
- if ((krb5rc = kssl_check_authent(kssl_ctx, &authenticator,
- &authtime, &kssl_err)) != 0)
- {
-#ifdef KSSL_DEBUG
- printf("kssl_check_authent rtn %d [%d]\n",
- krb5rc, kssl_err.reason);
- if (kssl_err.text)
- printf("kssl_err text= %s\n", kssl_err.text);
-#endif /* KSSL_DEBUG */
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- kssl_err.reason);
- goto err;
- }
-
- if ((krb5rc = kssl_validate_times(authtime, &ttimes)) != 0)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, krb5rc);
- goto err;
- }
-
-#ifdef KSSL_DEBUG
- kssl_ctx_show(kssl_ctx);
-#endif /* KSSL_DEBUG */
-
- enc = kssl_map_enc(kssl_ctx->enctype);
- if (enc == NULL)
- goto err;
-
- memset(iv, 0, sizeof iv); /* per RFC 1510 */
-
- if (!EVP_DecryptInit_ex(&ciph_ctx,enc,NULL,kssl_ctx->key,iv))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DECRYPTION_FAILED);
- goto err;
- }
- if (!EVP_DecryptUpdate(&ciph_ctx, pms,&outl,
- (unsigned char *)enc_pms.data, enc_pms.length))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DECRYPTION_FAILED);
- goto err;
- }
- if (outl > SSL_MAX_MASTER_KEY_LENGTH)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DATA_LENGTH_TOO_LONG);
- goto err;
- }
- if (!EVP_DecryptFinal_ex(&ciph_ctx,&(pms[outl]),&padl))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DECRYPTION_FAILED);
- goto err;
- }
- outl += padl;
- if (outl > SSL_MAX_MASTER_KEY_LENGTH)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DATA_LENGTH_TOO_LONG);
- goto err;
- }
- if (!((pms[0] == (s->client_version>>8)) && (pms[1] == (s->client_version & 0xff))))
- {
- /* The premaster secret must contain the same version number as the
- * ClientHello to detect version rollback attacks (strangely, the
- * protocol does not offer such protection for DH ciphersuites).
- * However, buggy clients exist that send random bytes instead of
- * the protocol version.
- * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients.
- * (Perhaps we should have a separate BUG value for the Kerberos cipher)
- */
- if (!(s->options & SSL_OP_TLS_ROLLBACK_BUG))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_AD_DECODE_ERROR);
- goto err;
- }
- }
-
- EVP_CIPHER_CTX_cleanup(&ciph_ctx);
-
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key, pms, outl);
-
- if (kssl_ctx->client_princ)
- {
- size_t len = strlen(kssl_ctx->client_princ);
- if ( len < SSL_MAX_KRB5_PRINCIPAL_LENGTH )
- {
- s->session->krb5_client_princ_len = len;
- memcpy(s->session->krb5_client_princ,kssl_ctx->client_princ,len);
- }
- }
-
-
- /* Was doing kssl_ctx_free() here,
- ** but it caused problems for apache.
- ** kssl_ctx = kssl_ctx_free(kssl_ctx);
- ** if (s->kssl_ctx) s->kssl_ctx = NULL;
- */
- }
- else
-#endif /* OPENSSL_NO_KRB5 */
-
-#ifndef OPENSSL_NO_ECDH
- if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
- {
- int ret = 1;
- int field_size = 0;
- const EC_KEY *tkey;
- const EC_GROUP *group;
- const BIGNUM *priv_key;
-
- /* initialize structures for server's ECDH key pair */
- if ((srvr_ecdh = EC_KEY_new()) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* Let's get server private key and group information */
- if (alg_k & (SSL_kECDHr|SSL_kECDHe))
- {
- /* use the certificate */
- tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
- }
- else
- {
- /* use the ephermeral values we saved when
- * generating the ServerKeyExchange msg.
- */
- tkey = s->s3->tmp.ecdh;
- }
-
- group = EC_KEY_get0_group(tkey);
- priv_key = EC_KEY_get0_private_key(tkey);
-
- if (!EC_KEY_set_group(srvr_ecdh, group) ||
- !EC_KEY_set_private_key(srvr_ecdh, priv_key))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_EC_LIB);
- goto err;
- }
-
- /* Let's get client's public key */
- if ((clnt_ecpoint = EC_POINT_new(group)) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (n == 0L)
- {
- /* Client Publickey was in Client Certificate */
-
- if (alg_k & SSL_kEECDH)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
- goto f_err;
- }
- if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer))
- == NULL) ||
- (clnt_pub_pkey->type != EVP_PKEY_EC))
- {
- /* XXX: For now, we do not support client
- * authentication using ECDH certificates
- * so this branch (n == 0L) of the code is
- * never executed. When that support is
- * added, we ought to ensure the key
- * received in the certificate is
- * authorized for key agreement.
- * ECDH_compute_key implicitly checks that
- * the two ECDH shares are for the same
- * group.
- */
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
- goto f_err;
- }
-
- if (EC_POINT_copy(clnt_ecpoint,
- EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) == 0)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_EC_LIB);
- goto err;
- }
- ret = 2; /* Skip certificate verify processing */
- }
- else
- {
- /* Get client's public key from encoded point
- * in the ClientKeyExchange message.
- */
- if ((bn_ctx = BN_CTX_new()) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* Get encoded point length */
- i = *p;
- p += 1;
- if (n != 1 + i)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_EC_LIB);
- goto err;
- }
- if (EC_POINT_oct2point(group,
- clnt_ecpoint, p, i, bn_ctx) == 0)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_EC_LIB);
- goto err;
- }
- /* p is pointing to somewhere in the buffer
- * currently, so set it to the start
- */
- p=(unsigned char *)s->init_buf->data;
- }
-
- /* Compute the shared pre-master secret */
- field_size = EC_GROUP_get_degree(group);
- if (field_size <= 0)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_ECDH_LIB);
- goto err;
- }
- i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL);
- if (i <= 0)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_ECDH_LIB);
- goto err;
- }
-
- EVP_PKEY_free(clnt_pub_pkey);
- EC_POINT_free(clnt_ecpoint);
- EC_KEY_free(srvr_ecdh);
- BN_CTX_free(bn_ctx);
- EC_KEY_free(s->s3->tmp.ecdh);
- s->s3->tmp.ecdh = NULL;
-
- /* Compute the master secret */
- s->session->master_key_length = s->method->ssl3_enc-> \
- generate_master_secret(s, s->session->master_key, p, i);
-
- OPENSSL_cleanse(p, i);
- return (ret);
- }
- else
-#endif
-#ifndef OPENSSL_NO_PSK
- if (alg_k & SSL_kPSK)
- {
- unsigned char *t = NULL;
- unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
- unsigned int pre_ms_len = 0, psk_len = 0;
- int psk_err = 1;
- char tmp_id[PSK_MAX_IDENTITY_LEN+1];
-
- al=SSL_AD_HANDSHAKE_FAILURE;
-
- n2s(p,i);
- if (n != i+2)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_LENGTH_MISMATCH);
- goto psk_err;
- }
- if (i > PSK_MAX_IDENTITY_LEN)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_DATA_LENGTH_TOO_LONG);
- goto psk_err;
- }
- if (s->psk_server_callback == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_PSK_NO_SERVER_CB);
- goto psk_err;
- }
-
- /* Create guaranteed NULL-terminated identity
- * string for the callback */
- memcpy(tmp_id, p, i);
- memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
- psk_len = s->psk_server_callback(s, tmp_id,
- psk_or_pre_ms, sizeof(psk_or_pre_ms));
- OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1);
-
- if (psk_len > PSK_MAX_PSK_LEN)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_INTERNAL_ERROR);
- goto psk_err;
- }
- else if (psk_len == 0)
- {
- /* PSK related to the given identity not found */
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_PSK_IDENTITY_NOT_FOUND);
- al=SSL_AD_UNKNOWN_PSK_IDENTITY;
- goto psk_err;
- }
-
- /* create PSK pre_master_secret */
- pre_ms_len=2+psk_len+2+psk_len;
- t = psk_or_pre_ms;
- memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
- s2n(psk_len, t);
- memset(t, 0, psk_len);
- t+=psk_len;
- s2n(psk_len, t);
-
- if (s->session->psk_identity != NULL)
- OPENSSL_free(s->session->psk_identity);
- s->session->psk_identity = BUF_strdup((char *)p);
- if (s->session->psk_identity == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto psk_err;
- }
-
- if (s->session->psk_identity_hint != NULL)
- OPENSSL_free(s->session->psk_identity_hint);
- s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
- if (s->ctx->psk_identity_hint != NULL &&
- s->session->psk_identity_hint == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto psk_err;
- }
-
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key, psk_or_pre_ms, pre_ms_len);
- psk_err = 0;
- psk_err:
- OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
- if (psk_err != 0)
- goto f_err;
- }
- else
-#endif
-#ifndef OPENSSL_NO_SRP
- if (alg_k & SSL_kSRP)
- {
- int param_len;
-
- n2s(p,i);
- param_len=i+2;
- if (param_len > n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_SRP_A_LENGTH);
- goto f_err;
- }
- if (!(s->srp_ctx.A=BN_bin2bn(p,i,NULL)))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_BN_LIB);
- goto err;
- }
- if (s->session->srp_username != NULL)
- OPENSSL_free(s->session->srp_username);
- s->session->srp_username = BUF_strdup(s->srp_ctx.login);
- if (s->session->srp_username == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if ((s->session->master_key_length = SRP_generate_server_master_secret(s,s->session->master_key))<0)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- p+=i;
- }
- else
-#endif /* OPENSSL_NO_SRP */
- if (alg_k & SSL_kGOST)
- {
- int ret = 0;
- EVP_PKEY_CTX *pkey_ctx;
- EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
- unsigned char premaster_secret[32], *start;
- size_t outlen=32, inlen;
- unsigned long alg_a;
-
- /* Get our certificate private key*/
- alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- if (alg_a & SSL_aGOST94)
- pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey;
- else if (alg_a & SSL_aGOST01)
- pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
-
- pkey_ctx = EVP_PKEY_CTX_new(pk,NULL);
- EVP_PKEY_decrypt_init(pkey_ctx);
- /* If client certificate is present and is of the same type, maybe
- * use it for key exchange. Don't mind errors from
- * EVP_PKEY_derive_set_peer, because it is completely valid to use
- * a client certificate for authorization only. */
- client_pub_pkey = X509_get_pubkey(s->session->peer);
- if (client_pub_pkey)
- {
- if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
- ERR_clear_error();
- }
- /* Decrypt session key */
- if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED)))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
- goto gerr;
- }
- if (p[1] == 0x81)
- {
- start = p+3;
- inlen = p[2];
- }
- else if (p[1] < 0x80)
- {
- start = p+2;
- inlen = p[1];
- }
- else
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
- goto gerr;
- }
- if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0)
-
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
- goto gerr;
- }
- /* Generate master secret */
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,premaster_secret,32);
- /* Check if pubkey from client certificate was used */
- if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
- ret = 2;
- else
- ret = 1;
- gerr:
- EVP_PKEY_free(client_pub_pkey);
- EVP_PKEY_CTX_free(pkey_ctx);
- if (ret)
- return ret;
- else
- goto err;
- }
- else
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
- SSL_R_UNKNOWN_CIPHER_TYPE);
- goto f_err;
- }
-
- return(1);
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_ECDH) || defined(OPENSSL_NO_SRP)
-err:
-#endif
-#ifndef OPENSSL_NO_ECDH
- EVP_PKEY_free(clnt_pub_pkey);
- EC_POINT_free(clnt_ecpoint);
- if (srvr_ecdh != NULL)
- EC_KEY_free(srvr_ecdh);
- BN_CTX_free(bn_ctx);
-#endif
- return(-1);
- }
-
-int ssl3_get_cert_verify(SSL *s)
- {
- EVP_PKEY *pkey=NULL;
- unsigned char *p;
- int al,ok,ret=0;
- long n;
- int type=0,i,j;
- X509 *peer;
- const EVP_MD *md = NULL;
- EVP_MD_CTX mctx;
- EVP_MD_CTX_init(&mctx);
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_SR_CERT_VRFY_A,
- SSL3_ST_SR_CERT_VRFY_B,
- -1,
- 516, /* Enough for 4096 bit RSA key with TLS v1.2 */
- &ok);
-
- if (!ok) return((int)n);
-
- if (s->session->peer != NULL)
- {
- peer=s->session->peer;
- pkey=X509_get_pubkey(peer);
- type=X509_certificate_type(peer,pkey);
- }
- else
- {
- peer=NULL;
- pkey=NULL;
- }
-
- if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY)
- {
- s->s3->tmp.reuse_message=1;
- if ((peer != NULL) && (type & EVP_PKT_SIGN))
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_MISSING_VERIFY_MESSAGE);
- goto f_err;
- }
- ret=1;
- goto end;
- }
-
- if (peer == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_NO_CLIENT_CERT_RECEIVED);
- al=SSL_AD_UNEXPECTED_MESSAGE;
- goto f_err;
- }
-
- if (!(type & EVP_PKT_SIGN))
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
- al=SSL_AD_ILLEGAL_PARAMETER;
- goto f_err;
- }
-
- if (s->s3->change_cipher_spec)
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_CCS_RECEIVED_EARLY);
- al=SSL_AD_UNEXPECTED_MESSAGE;
- goto f_err;
- }
-
- /* we now have a signature that we need to verify */
- p=(unsigned char *)s->init_msg;
- /* Check for broken implementations of GOST ciphersuites */
- /* If key is GOST and n is exactly 64, it is bare
- * signature without length field */
- if (n==64 && (pkey->type==NID_id_GostR3410_94 ||
- pkey->type == NID_id_GostR3410_2001) )
- {
- i=64;
- }
- else
- {
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- {
- int sigalg = tls12_get_sigid(pkey);
- /* Should never happen */
- if (sigalg == -1)
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
- al=SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
- /* Check key type is consistent with signature */
- if (sigalg != (int)p[1])
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_WRONG_SIGNATURE_TYPE);
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- md = tls12_get_hash(p[0]);
- if (md == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_UNKNOWN_DIGEST);
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
-#ifdef SSL_DEBUG
-fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
-#endif
- p += 2;
- n -= 2;
- }
- n2s(p,i);
- n-=2;
- if (i > n)
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH);
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- }
- j=EVP_PKEY_size(pkey);
- if ((i > j) || (n > j) || (n <= 0))
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_WRONG_SIGNATURE_SIZE);
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
-
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- {
- long hdatalen = 0;
- void *hdata;
- hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
- if (hdatalen <= 0)
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
- al=SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
-#ifdef SSL_DEBUG
- fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
- EVP_MD_name(md));
-#endif
- if (!EVP_VerifyInit_ex(&mctx, md, NULL)
- || !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_EVP_LIB);
- al=SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
-
- if (EVP_VerifyFinal(&mctx, p , i, pkey) <= 0)
- {
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_SIGNATURE);
- goto f_err;
- }
- }
- else
-#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA)
- {
- i=RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
- MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH, p, i,
- pkey->pkey.rsa);
- if (i < 0)
- {
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_RSA_DECRYPT);
- goto f_err;
- }
- if (i == 0)
- {
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_RSA_SIGNATURE);
- goto f_err;
- }
- }
- else
-#endif
-#ifndef OPENSSL_NO_DSA
- if (pkey->type == EVP_PKEY_DSA)
- {
- j=DSA_verify(pkey->save_type,
- &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
- SHA_DIGEST_LENGTH,p,i,pkey->pkey.dsa);
- if (j <= 0)
- {
- /* bad signature */
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_DSA_SIGNATURE);
- goto f_err;
- }
- }
- else
-#endif
-#ifndef OPENSSL_NO_ECDSA
- if (pkey->type == EVP_PKEY_EC)
- {
- j=ECDSA_verify(pkey->save_type,
- &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
- SHA_DIGEST_LENGTH,p,i,pkey->pkey.ec);
- if (j <= 0)
- {
- /* bad signature */
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,
- SSL_R_BAD_ECDSA_SIGNATURE);
- goto f_err;
- }
- }
- else
-#endif
- if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001)
- { unsigned char signature[64];
- int idx;
- EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey,NULL);
- EVP_PKEY_verify_init(pctx);
- if (i!=64) {
- fprintf(stderr,"GOST signature length is %d",i);
- }
- for (idx=0;idx<64;idx++) {
- signature[63-idx]=p[idx];
- }
- j=EVP_PKEY_verify(pctx,signature,64,s->s3->tmp.cert_verify_md,32);
- EVP_PKEY_CTX_free(pctx);
- if (j<=0)
- {
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,
- SSL_R_BAD_ECDSA_SIGNATURE);
- goto f_err;
- }
- }
- else
- {
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
- al=SSL_AD_UNSUPPORTED_CERTIFICATE;
- goto f_err;
- }
-
-
- ret=1;
- if (0)
- {
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- }
-end:
- if (s->s3->handshake_buffer)
- {
- BIO_free(s->s3->handshake_buffer);
- s->s3->handshake_buffer = NULL;
- s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
- }
- EVP_MD_CTX_cleanup(&mctx);
- EVP_PKEY_free(pkey);
- return(ret);
- }
-
-int ssl3_get_client_certificate(SSL *s)
- {
- int i,ok,al,ret= -1;
- X509 *x=NULL;
- unsigned long l,nc,llen,n;
- const unsigned char *p,*q;
- unsigned char *d;
- STACK_OF(X509) *sk=NULL;
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_SR_CERT_A,
- SSL3_ST_SR_CERT_B,
- -1,
- s->max_cert_list,
- &ok);
-
- if (!ok) return((int)n);
-
- if (s->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE)
- {
- if ( (s->verify_mode & SSL_VERIFY_PEER) &&
- (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
- al=SSL_AD_HANDSHAKE_FAILURE;
- goto f_err;
- }
- /* If tls asked for a client cert, the client must return a 0 list */
- if ((s->version > SSL3_VERSION) && s->s3->tmp.cert_request)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST);
- al=SSL_AD_UNEXPECTED_MESSAGE;
- goto f_err;
- }
- s->s3->tmp.reuse_message=1;
- return(1);
- }
-
- if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_WRONG_MESSAGE_TYPE);
- goto f_err;
- }
- p=d=(unsigned char *)s->init_msg;
-
- if ((sk=sk_X509_new_null()) == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- n2l3(p,llen);
- if (llen+3 != n)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
- for (nc=0; nc<llen; )
- {
- n2l3(p,l);
- if ((l+nc+3) > llen)
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
- goto f_err;
- }
-
- q=p;
- x=d2i_X509(NULL,&p,l);
- if (x == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_ASN1_LIB);
- goto err;
- }
- if (p != (q+l))
- {
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
- goto f_err;
- }
- if (!sk_X509_push(sk,x))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- x=NULL;
- nc+=l+3;
- }
-
- if (sk_X509_num(sk) <= 0)
- {
- /* TLS does not mind 0 certs returned */
- if (s->version == SSL3_VERSION)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATES_RETURNED);
- goto f_err;
- }
- /* Fail for TLS only if we required a certificate */
- else if ((s->verify_mode & SSL_VERIFY_PEER) &&
- (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
- al=SSL_AD_HANDSHAKE_FAILURE;
- goto f_err;
- }
- /* No client certificate so digest cached records */
- if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
- {
- al=SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
- }
- else
- {
- i=ssl_verify_cert_chain(s,sk);
- if (i <= 0)
- {
- al=ssl_verify_alarm_type(s->verify_result);
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATE_RETURNED);
- goto f_err;
- }
- }
-
- if (s->session->peer != NULL) /* This should not be needed */
- X509_free(s->session->peer);
- s->session->peer=sk_X509_shift(sk);
- s->session->verify_result = s->verify_result;
-
- /* With the current implementation, sess_cert will always be NULL
- * when we arrive here. */
- if (s->session->sess_cert == NULL)
- {
- s->session->sess_cert = ssl_sess_cert_new();
- if (s->session->sess_cert == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- }
- if (s->session->sess_cert->cert_chain != NULL)
- sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free);
- s->session->sess_cert->cert_chain=sk;
- /* Inconsistency alert: cert_chain does *not* include the
- * peer's own certificate, while we do include it in s3_clnt.c */
-
- sk=NULL;
-
- ret=1;
- if (0)
- {
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- }
-err:
- if (x != NULL) X509_free(x);
- if (sk != NULL) sk_X509_pop_free(sk,X509_free);
- return(ret);
- }
-
-int ssl3_send_server_certificate(SSL *s)
- {
- unsigned long l;
- X509 *x;
-
- if (s->state == SSL3_ST_SW_CERT_A)
- {
- x=ssl_get_server_send_cert(s);
- if (x == NULL)
- {
- /* VRS: allow null cert if auth == KRB5 */
- if ((s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5) ||
- (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5))
- {
- SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR);
- return(0);
- }
- }
-
- l=ssl3_output_cert_chain(s,x);
- s->state=SSL3_ST_SW_CERT_B;
- s->init_num=(int)l;
- s->init_off=0;
- }
-
- /* SSL3_ST_SW_CERT_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-#ifndef OPENSSL_NO_TLSEXT
-/* send a new session ticket (not necessarily for a new session) */
-int ssl3_send_newsession_ticket(SSL *s)
- {
- if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
- {
- unsigned char *p, *senc, *macstart;
- const unsigned char *const_p;
- int len, slen_full, slen;
- SSL_SESSION *sess;
- unsigned int hlen;
- EVP_CIPHER_CTX ctx;
- HMAC_CTX hctx;
- SSL_CTX *tctx = s->initial_ctx;
- unsigned char iv[EVP_MAX_IV_LENGTH];
- unsigned char key_name[16];
-
- /* get session encoding length */
- slen_full = i2d_SSL_SESSION(s->session, NULL);
- /* Some length values are 16 bits, so forget it if session is
- * too long
- */
- if (slen_full > 0xFF00)
- return -1;
- senc = OPENSSL_malloc(slen_full);
- if (!senc)
- return -1;
- p = senc;
- i2d_SSL_SESSION(s->session, &p);
-
- /* create a fresh copy (not shared with other threads) to clean up */
- const_p = senc;
- sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
- if (sess == NULL)
- {
- OPENSSL_free(senc);
- return -1;
- }
- sess->session_id_length = 0; /* ID is irrelevant for the ticket */
-
- slen = i2d_SSL_SESSION(sess, NULL);
- if (slen > slen_full) /* shouldn't ever happen */
- {
- OPENSSL_free(senc);
- return -1;
- }
- p = senc;
- i2d_SSL_SESSION(sess, &p);
- SSL_SESSION_free(sess);
-
- /* Grow buffer if need be: the length calculation is as
- * follows 1 (size of message name) + 3 (message length
- * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) +
- * 16 (key name) + max_iv_len (iv length) +
- * session_length + max_enc_block_size (max encrypted session
- * length) + max_md_size (HMAC).
- */
- if (!BUF_MEM_grow(s->init_buf,
- 26 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH +
- EVP_MAX_MD_SIZE + slen))
- return -1;
-
- p=(unsigned char *)s->init_buf->data;
- /* do the header */
- *(p++)=SSL3_MT_NEWSESSION_TICKET;
- /* Skip message length for now */
- p += 3;
- EVP_CIPHER_CTX_init(&ctx);
- HMAC_CTX_init(&hctx);
- /* Initialize HMAC and cipher contexts. If callback present
- * it does all the work otherwise use generated values
- * from parent ctx.
- */
- if (tctx->tlsext_ticket_key_cb)
- {
- if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
- &hctx, 1) < 0)
- {
- OPENSSL_free(senc);
- return -1;
- }
- }
- else
- {
- RAND_pseudo_bytes(iv, 16);
- EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
- tctx->tlsext_tick_aes_key, iv);
- HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
- tlsext_tick_md(), NULL);
- memcpy(key_name, tctx->tlsext_tick_key_name, 16);
- }
-
- /* Ticket lifetime hint (advisory only):
- * We leave this unspecified for resumed session (for simplicity),
- * and guess that tickets for new sessions will live as long
- * as their sessions. */
- l2n(s->hit ? 0 : s->session->timeout, p);
-
- /* Skip ticket length for now */
- p += 2;
- /* Output key name */
- macstart = p;
- memcpy(p, key_name, 16);
- p += 16;
- /* output IV */
- memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
- p += EVP_CIPHER_CTX_iv_length(&ctx);
- /* Encrypt session data */
- EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
- p += len;
- EVP_EncryptFinal(&ctx, p, &len);
- p += len;
- EVP_CIPHER_CTX_cleanup(&ctx);
-
- HMAC_Update(&hctx, macstart, p - macstart);
- HMAC_Final(&hctx, p, &hlen);
- HMAC_CTX_cleanup(&hctx);
-
- p += hlen;
- /* Now write out lengths: p points to end of data written */
- /* Total length */
- len = p - (unsigned char *)s->init_buf->data;
- p=(unsigned char *)s->init_buf->data + 1;
- l2n3(len - 4, p); /* Message length */
- p += 4;
- s2n(len - 10, p); /* Ticket length */
-
- /* number of bytes to write */
- s->init_num= len;
- s->state=SSL3_ST_SW_SESSION_TICKET_B;
- s->init_off=0;
- OPENSSL_free(senc);
- }
-
- /* SSL3_ST_SW_SESSION_TICKET_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-int ssl3_send_cert_status(SSL *s)
- {
- if (s->state == SSL3_ST_SW_CERT_STATUS_A)
- {
- unsigned char *p;
- /* Grow buffer if need be: the length calculation is as
- * follows 1 (message type) + 3 (message length) +
- * 1 (ocsp response type) + 3 (ocsp response length)
- * + (ocsp response)
- */
- if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen))
- return -1;
-
- p=(unsigned char *)s->init_buf->data;
-
- /* do the header */
- *(p++)=SSL3_MT_CERTIFICATE_STATUS;
- /* message length */
- l2n3(s->tlsext_ocsp_resplen + 4, p);
- /* status type */
- *(p++)= s->tlsext_status_type;
- /* length of OCSP response */
- l2n3(s->tlsext_ocsp_resplen, p);
- /* actual response */
- memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
- /* number of bytes to write */
- s->init_num = 8 + s->tlsext_ocsp_resplen;
- s->state=SSL3_ST_SW_CERT_STATUS_B;
- s->init_off = 0;
- }
-
- /* SSL3_ST_SW_CERT_STATUS_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
- }
-
-# ifndef OPENSSL_NO_NEXTPROTONEG
-/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
- * sets the next_proto member in s if found */
-int ssl3_get_next_proto(SSL *s)
- {
- int ok;
- int proto_len, padding_len;
- long n;
- const unsigned char *p;
-
- /* Clients cannot send a NextProtocol message if we didn't see the
- * extension in their ClientHello */
- if (!s->s3->next_proto_neg_seen)
- {
- SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
- return -1;
- }
-
- n=s->method->ssl_get_message(s,
- SSL3_ST_SR_NEXT_PROTO_A,
- SSL3_ST_SR_NEXT_PROTO_B,
- SSL3_MT_NEXT_PROTO,
- 514, /* See the payload format below */
- &ok);
-
- if (!ok)
- return((int)n);
-
- /* s->state doesn't reflect whether ChangeCipherSpec has been received
- * in this handshake, but s->s3->change_cipher_spec does (will be reset
- * by ssl3_get_finished). */
- if (!s->s3->change_cipher_spec)
- {
- SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
- return -1;
- }
-
- if (n < 2)
- return 0; /* The body must be > 1 bytes long */
-
- p=(unsigned char *)s->init_msg;
-
- /* The payload looks like:
- * uint8 proto_len;
- * uint8 proto[proto_len];
- * uint8 padding_len;
- * uint8 padding[padding_len];
- */
- proto_len = p[0];
- if (proto_len + 2 > s->init_num)
- return 0;
- padding_len = p[proto_len + 1];
- if (proto_len + padding_len + 2 != s->init_num)
- return 0;
-
- s->next_proto_negotiated = OPENSSL_malloc(proto_len);
- if (!s->next_proto_negotiated)
- {
- SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,ERR_R_MALLOC_FAILURE);
- return 0;
- }
- memcpy(s->next_proto_negotiated, p + 1, proto_len);
- s->next_proto_negotiated_len = proto_len;
-
- return 1;
- }
-# endif
-#endif
diff --git a/drivers/builtin_openssl/ssl/srtp.h b/drivers/builtin_openssl/ssl/srtp.h
deleted file mode 100644
index c0cf33ef28..0000000000
--- a/drivers/builtin_openssl/ssl/srtp.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/* ssl/tls1.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/*
- DTLS code by Eric Rescorla <ekr@rtfm.com>
-
- Copyright (C) 2006, Network Resonance, Inc.
- Copyright (C) 2011, RTFM, Inc.
-*/
-
-#ifndef HEADER_D1_SRTP_H
-#define HEADER_D1_SRTP_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#define SRTP_AES128_CM_SHA1_80 0x0001
-#define SRTP_AES128_CM_SHA1_32 0x0002
-#define SRTP_AES128_F8_SHA1_80 0x0003
-#define SRTP_AES128_F8_SHA1_32 0x0004
-#define SRTP_NULL_SHA1_80 0x0005
-#define SRTP_NULL_SHA1_32 0x0006
-
-int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles);
-int SSL_set_tlsext_use_srtp(SSL *ctx, const char *profiles);
-SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
-
-STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *ssl);
-SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/drivers/builtin_openssl/ssl/ssl-lib.com b/drivers/builtin_openssl/ssl/ssl-lib.com
deleted file mode 100644
index c7bc6fbd70..0000000000
--- a/drivers/builtin_openssl/ssl/ssl-lib.com
+++ /dev/null
@@ -1,1214 +0,0 @@
-$!
-$! SSL-LIB.COM
-$! Written By: Robert Byer
-$! Vice-President
-$! A-Com Computing, Inc.
-$! byer@mail.all-net.net
-$!
-$! Changes by Richard Levitte <richard@levitte.org>
-$!
-$! This command file compiles and creates the "[.xxx.EXE.SSL]LIBSSL.OLB"
-$! library for OpenSSL. The "xxx" denotes the machine architecture of
-$! ALPHA, IA64 or VAX.
-$!
-$! It is written to detect what type of machine you are compiling on
-$! (i.e. ALPHA or VAX) and which "C" compiler you have (i.e. VAXC, DECC
-$! or GNU C) or you can specify which compiler to use.
-$!
-$! Specify the following as P1 to build just that part or ALL to just
-$! build everything.
-$!
-$! LIBRARY To just compile the [.xxx.EXE.SSL]LIBSSL.OLB Library.
-$! SSL_TASK To just compile the [.xxx.EXE.SSL]SSL_TASK.EXE
-$!
-$! Specify DEBUG or NODEBUG as P2 to compile with or without debugger
-$! information.
-$!
-$! Specify which compiler at P3 to try to compile under.
-$!
-$! VAXC For VAX C.
-$! DECC For DEC C.
-$! GNUC For GNU C.
-$!
-$! If you don't specify a compiler, it will try to determine which
-$! "C" compiler to use.
-$!
-$! P4, if defined, sets a TCP/IP library to use, through one of the following
-$! keywords:
-$!
-$! UCX for UCX
-$! TCPIP for TCPIP (post UCX)
-$! SOCKETSHR for SOCKETSHR+NETLIB
-$!
-$! P5, if defined, sets a compiler thread NOT needed on OpenVMS 7.1 (and up)
-$!
-$! P6, if defined, specifies the C pointer size. Ignored on VAX.
-$! ("64=ARGV" gives more efficient code with HP C V7.3 or newer.)
-$! Supported values are:
-$!
-$! "" Compile with default (/NOPOINTER_SIZE)
-$! 32 Compile with /POINTER_SIZE=32 (SHORT)
-$! 64 Compile with /POINTER_SIZE=64[=ARGV] (LONG[=ARGV])
-$! (Automatically select ARGV if compiler supports it.)
-$! 64= Compile with /POINTER_SIZE=64 (LONG).
-$! 64=ARGV Compile with /POINTER_SIZE=64=ARGV (LONG=ARGV).
-$!
-$! P7, if defined, specifies a directory where ZLIB files (zlib.h,
-$! libz.olb) may be found. Optionally, a non-default object library
-$! name may be included ("dev:[dir]libz_64.olb", for example).
-$!
-$!
-$! Announce/identify.
-$!
-$ proc = f$environment( "procedure")
-$ write sys$output "@@@ "+ -
- f$parse( proc, , , "name")+ f$parse( proc, , , "type")
-$!
-$! Define A TCP/IP Library That We Will Need To Link To.
-$! (That Is, If We Need To Link To One.)
-$!
-$ TCPIP_LIB = ""
-$ ZLIB_LIB = ""
-$!
-$! Check What Architecture We Are Using.
-$!
-$ IF (F$GETSYI("CPU").LT.128)
-$ THEN
-$!
-$! The Architecture Is VAX.
-$!
-$ ARCH = "VAX"
-$!
-$! Else...
-$!
-$ ELSE
-$!
-$! The Architecture Is Alpha, IA64 or whatever comes in the future.
-$!
-$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE")
-$ IF (ARCH .EQS. "") THEN ARCH = "UNK"
-$!
-$! End The Architecture Check.
-$!
-$ ENDIF
-$!
-$ ARCHD = ARCH
-$ LIB32 = "32"
-$ OPT_FILE = ""
-$ POINTER_SIZE = ""
-$!
-$! Check To Make Sure We Have Valid Command Line Parameters.
-$!
-$ GOSUB CHECK_OPTIONS
-$!
-$! Define The OBJ and EXE Directories.
-$!
-$ OBJ_DIR := SYS$DISK:[-.'ARCHD'.OBJ.SSL]
-$ EXE_DIR := SYS$DISK:[-.'ARCHD'.EXE.SSL]
-$!
-$! Specify the destination directory in any /MAP option.
-$!
-$ if (LINKMAP .eqs. "MAP")
-$ then
-$ LINKMAP = LINKMAP+ "=''EXE_DIR'"
-$ endif
-$!
-$! Add the location prefix to the linker options file name.
-$!
-$ if (OPT_FILE .nes. "")
-$ then
-$ OPT_FILE = EXE_DIR+ OPT_FILE
-$ endif
-$!
-$! Initialise logical names and such
-$!
-$ GOSUB INITIALISE
-$!
-$! Tell The User What Kind of Machine We Run On.
-$!
-$ WRITE SYS$OUTPUT "Host system architecture: ''ARCHD'"
-$!
-$! Check To See If The Architecture Specific OBJ Directory Exists.
-$!
-$ IF (F$PARSE(OBJ_DIR).EQS."")
-$ THEN
-$!
-$! It Dosen't Exist, So Create It.
-$!
-$ CREATE/DIR 'OBJ_DIR'
-$!
-$! End The Architecture Specific OBJ Directory Check.
-$!
-$ ENDIF
-$!
-$! Check To See If The Architecture Specific Directory Exists.
-$!
-$ IF (F$PARSE(EXE_DIR).EQS."")
-$ THEN
-$!
-$! It Dosen't Exist, So Create It.
-$!
-$ CREATE/DIR 'EXE_DIR'
-$!
-$! End The Architecture Specific Directory Check.
-$!
-$ ENDIF
-$!
-$! Define The Library Name.
-$!
-$ SSL_LIB := 'EXE_DIR'SSL_LIBSSL'LIB32'.OLB
-$!
-$! Define The CRYPTO-LIB We Are To Use.
-$!
-$ CRYPTO_LIB := SYS$DISK:[-.'ARCHD'.EXE.CRYPTO]SSL_LIBCRYPTO'LIB32'.OLB
-$!
-$! Set up exceptional compilations.
-$!
-$ CC5_SHOWN = 0
-$!
-$! Check To See What We Are To Do.
-$!
-$ IF (BUILDALL.EQS."TRUE")
-$ THEN
-$!
-$! Since Nothing Special Was Specified, Do Everything.
-$!
-$ GOSUB LIBRARY
-$ GOSUB SSL_TASK
-$!
-$! Else...
-$!
-$ ELSE
-$!
-$! Build Just What The User Wants Us To Build.
-$!
-$ GOSUB 'BUILDALL'
-$!
-$! End The BUILDALL Check.
-$!
-$ ENDIF
-$!
-$! Time To EXIT.
-$!
-$ EXIT:
-$ GOSUB CLEANUP
-$ EXIT
-$!
-$! Compile The Library.
-$!
-$ LIBRARY:
-$!
-$! Check To See If We Already Have A "[.xxx.EXE.SSL]SSL_LIBSSL''LIB32'.OLB" Library...
-$!
-$ IF (F$SEARCH(SSL_LIB).EQS."")
-$ THEN
-$!
-$! Guess Not, Create The Library.
-$!
-$ LIBRARY/CREATE/OBJECT 'SSL_LIB'
-$!
-$! End The Library Exist Check.
-$!
-$ ENDIF
-$!
-$! Define The Different SSL "library" Files.
-$!
-$ LIB_SSL = "s2_meth,s2_srvr,s2_clnt,s2_lib,s2_enc,s2_pkt,"+ -
- "s3_meth,s3_srvr,s3_clnt,s3_lib,s3_enc,s3_pkt,s3_both,s3_cbc,"+ -
- "s23_meth,s23_srvr,s23_clnt,s23_lib,s23_pkt,"+ -
- "t1_meth,t1_srvr,t1_clnt,t1_lib,t1_enc,"+ -
- "d1_meth,d1_srvr,d1_clnt,d1_lib,d1_pkt,"+ -
- "d1_both,d1_enc,d1_srtp,"+ -
- "ssl_lib,ssl_err2,ssl_cert,ssl_sess,"+ -
- "ssl_ciph,ssl_stat,ssl_rsa,"+ -
- "ssl_asn1,ssl_txt,ssl_algs,"+ -
- "bio_ssl,ssl_err,kssl,tls_srp,t1_reneg"
-$!
-$ COMPILEWITH_CC5 = ""
-$!
-$! Tell The User That We Are Compiling The Library.
-$!
-$ WRITE SYS$OUTPUT "Building The ",SSL_LIB," Library."
-$!
-$! Define A File Counter And Set It To "0"
-$!
-$ FILE_COUNTER = 0
-$!
-$! Top Of The File Loop.
-$!
-$ NEXT_FILE:
-$!
-$! O.K, Extract The File Name From The File List.
-$!
-$ FILE_NAME = F$ELEMENT(FILE_COUNTER,",",LIB_SSL)
-$!
-$! Check To See If We Are At The End Of The File List.
-$!
-$ IF (FILE_NAME.EQS.",") THEN GOTO FILE_DONE
-$!
-$! Increment The Counter.
-$!
-$ FILE_COUNTER = FILE_COUNTER + 1
-$!
-$! Create The Source File Name.
-$!
-$ SOURCE_FILE = "SYS$DISK:[]" + FILE_NAME + ".C"
-$!
-$! Create The Object File Name.
-$!
-$ OBJECT_FILE = OBJ_DIR + FILE_NAME + ".OBJ"
-$ ON WARNING THEN GOTO NEXT_FILE
-$!
-$! Check To See If The File We Want To Compile Is Actually There.
-$!
-$ IF (F$SEARCH(SOURCE_FILE).EQS."")
-$ THEN
-$!
-$! Tell The User That The File Dosen't Exist.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The File ",SOURCE_FILE," Dosen't Exist."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Exit The Build.
-$!
-$ EXIT
-$!
-$! End The File Exists Check.
-$!
-$ ENDIF
-$!
-$! Tell The User What File We Are Compiling.
-$!
-$ WRITE SYS$OUTPUT " ",FILE_NAME,".c"
-$!
-$! Compile The File.
-$!
-$ ON ERROR THEN GOTO NEXT_FILE
-$ CC/OBJECT='OBJECT_FILE' 'SOURCE_FILE'
-$!
-$! Add It To The Library.
-$!
-$ LIBRARY/REPLACE/OBJECT 'SSL_LIB' 'OBJECT_FILE'
-$!
-$! Time To Clean Up The Object File.
-$!
-$ DELETE 'OBJECT_FILE';*
-$!
-$! Go Back And Get The Next File Name.
-$!
-$ GOTO NEXT_FILE
-$!
-$! All Done With This Library.
-$!
-$ FILE_DONE:
-$!
-$! Tell The User That We Are All Done.
-$!
-$ WRITE SYS$OUTPUT "Library ",SSL_LIB," Compiled."
-$!
-$! Time To RETURN.
-$!
-$ RETURN
-$ SSL_TASK:
-$!
-$! Check To See If We Have The Proper Libraries.
-$!
-$ GOSUB LIB_CHECK
-$!
-$! Check To See If We Have A Linker Option File.
-$!
-$ GOSUB CHECK_OPT_FILE
-$!
-$! Check To See If The File We Want To Compile Is Actually There.
-$!
-$ IF (F$SEARCH("SYS$DISK:[]SSL_TASK.C").EQS."")
-$ THEN
-$!
-$! Tell The User That The File Dosen't Exist.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The File SSL_TASK.C Dosen't Exist."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Exit The Build.
-$!
-$ EXIT
-$!
-$! End The SSL_TASK.C File Check.
-$!
-$ ENDIF
-$!
-$ COMPILEWITH_CC5 = "" !!! ",ssl_task,"
-$!
-$! Tell The User We Are Creating The SSL_TASK.
-$!
-$! Tell The User We Are Creating The SSL_TASK.
-$!
-$ WRITE SYS$OUTPUT "Creating SSL_TASK OSU HTTP SSL Engine."
-$!
-$! Tell The User What File We Are Compiling.
-$!
-$ FILE_NAME = "ssl_task"
-$ WRITE SYS$OUTPUT " ",FILE_NAME,".c"
-$!
-$! Compile The File.
-$!
-$ ON ERROR THEN GOTO SSL_TASK_END
-$!
-$ FILE_NAME0 = ","+ F$ELEMENT(0,".",FILE_NAME)+ ","
-$ IF COMPILEWITH_CC5 - FILE_NAME0 .NES. COMPILEWITH_CC5
-$ THEN
-$ if (.not. CC5_SHOWN)
-$ then
-$ CC5_SHOWN = 1
-$ write sys$output " \Using special rule (5)"
-$ x = " "+ CC5
-$ write /symbol sys$output x
-$ endif
-$ CC5 /OBJECT='OBJ_DIR''FILE_NAME'.OBJ SYS$DISK:[]'FILE_NAME'.C
-$ ELSE
-$ CC /OBJECT='OBJ_DIR''FILE_NAME'.OBJ SYS$DISK:[]'FILE_NAME'.C
-$ ENDIF
-$!
-$! Link The Program.
-$!
-$ LINK /'DEBUGGER' /'LINKMAP' /'TRACEBACK' /EXE='EXE_DIR'SSL_TASK.EXE -
- 'OBJ_DIR'SSL_TASK.OBJ, -
- 'SSL_LIB'/LIBRARY, -
- 'CRYPTO_LIB'/LIBRARY -
- 'TCPIP_LIB' -
- 'ZLIB_LIB' -
- ,'OPT_FILE' /OPTIONS
-$!
-$! Time To Return.
-$!
-$SSL_TASK_END:
-$ RETURN
-$!
-$! Check For The Link Option FIle.
-$!
-$ CHECK_OPT_FILE:
-$!
-$! Check To See If We Need To Make A VAX C Option File.
-$!
-$ IF (COMPILER.EQS."VAXC")
-$ THEN
-$!
-$! Check To See If We Already Have A VAX C Linker Option File.
-$!
-$ IF (F$SEARCH(OPT_FILE).EQS."")
-$ THEN
-$!
-$! We Need A VAX C Linker Option File.
-$!
-$ CREATE 'OPT_FILE'
-$DECK
-!
-! Default System Options File To Link Against
-! The Sharable VAX C Runtime Library.
-!
-SYS$SHARE:VAXCRTL.EXE/SHARE
-$EOD
-$!
-$! End The Option File Check.
-$!
-$ ENDIF
-$!
-$! End The VAXC Check.
-$!
-$ ENDIF
-$!
-$! Check To See If We Need A GNU C Option File.
-$!
-$ IF (COMPILER.EQS."GNUC")
-$ THEN
-$!
-$! Check To See If We Already Have A GNU C Linker Option File.
-$!
-$ IF (F$SEARCH(OPT_FILE).EQS."")
-$ THEN
-$!
-$! We Need A GNU C Linker Option File.
-$!
-$ CREATE 'OPT_FILE'
-$DECK
-!
-! Default System Options File To Link Against
-! The Sharable C Runtime Library.
-!
-GNU_CC:[000000]GCCLIB/LIBRARY
-SYS$SHARE:VAXCRTL/SHARE
-$EOD
-$!
-$! End The Option File Check.
-$!
-$ ENDIF
-$!
-$! End The GNU C Check.
-$!
-$ ENDIF
-$!
-$! Check To See If We Need A DEC C Option File.
-$!
-$ IF (COMPILER.EQS."DECC")
-$ THEN
-$!
-$! Check To See If We Already Have A DEC C Linker Option File.
-$!
-$ IF (F$SEARCH(OPT_FILE).EQS."")
-$ THEN
-$!
-$! Figure Out If We Need A non-VAX Or A VAX Linker Option File.
-$!
-$ IF (ARCH.EQS."VAX")
-$ THEN
-$!
-$! We Need A DEC C Linker Option File For VAX.
-$!
-$ CREATE 'OPT_FILE'
-$DECK
-!
-! Default System Options File To Link Against
-! The Sharable DEC C Runtime Library.
-!
-SYS$SHARE:DECC$SHR.EXE/SHARE
-$EOD
-$!
-$! Else...
-$!
-$ ELSE
-$!
-$! Create The non-VAX Linker Option File.
-$!
-$ CREATE 'OPT_FILE'
-$DECK
-!
-! Default System Options File For non-VAX To Link Against
-! The Sharable C Runtime Library.
-!
-SYS$SHARE:CMA$OPEN_LIB_SHR/SHARE
-SYS$SHARE:CMA$OPEN_RTL/SHARE
-$EOD
-$!
-$! End The DEC C Option File Check.
-$!
-$ ENDIF
-$!
-$! End The Option File Search.
-$!
-$ ENDIF
-$!
-$! End The DEC C Check.
-$!
-$ ENDIF
-$!
-$! Tell The User What Linker Option File We Are Using.
-$!
-$ WRITE SYS$OUTPUT "Using Linker Option File ",OPT_FILE,"."
-$!
-$! Time To RETURN.
-$!
-$ RETURN
-$ LIB_CHECK:
-$!
-$! Look For The VAX Library LIBSSL.OLB.
-$!
-$ IF (F$SEARCH(SSL_LIB).EQS."")
-$ THEN
-$!
-$! Tell The User We Can't Find The LIBSSL.OLB Library.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "Can't Find The Library ",SSL_LIB,"."
-$ WRITE SYS$OUTPUT "We Can't Link Without It."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Since We Can't Link Without It, Exit.
-$!
-$ EXIT
-$!
-$! End The LIBSSL.OLB Library Check.
-$!
-$ ENDIF
-$!
-$! Look For The Library LIBCRYPTO.OLB.
-$!
-$ IF (F$SEARCH(CRYPTO_LIB).EQS."")
-$ THEN
-$!
-$! Tell The User We Can't Find The LIBCRYPTO.OLB Library.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "Can't Find The Library ",CRYPTO_LIB,"."
-$ WRITE SYS$OUTPUT "We Can't Link Without It."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Since We Can't Link Without It, Exit.
-$!
-$ EXIT
-$!
-$! End The LIBCRYPTO.OLB Library Check.
-$!
-$ ENDIF
-$!
-$! Time To Return.
-$!
-$ RETURN
-$!
-$! Check The User's Options.
-$!
-$ CHECK_OPTIONS:
-$!
-$! Check To See If P1 Is Blank.
-$!
-$ IF (P1.EQS."ALL")
-$ THEN
-$!
-$! P1 Is Blank, So Build Everything.
-$!
-$ BUILDALL = "TRUE"
-$!
-$! Else...
-$!
-$ ELSE
-$!
-$! Else, Check To See If P1 Has A Valid Argument.
-$!
-$ IF (P1.EQS."LIBRARY").OR.(P1.EQS."SSL_TASK")
-$ THEN
-$!
-$! A Valid Argument.
-$!
-$ BUILDALL = P1
-$!
-$! Else...
-$!
-$ ELSE
-$!
-$! Tell The User We Don't Know What They Want.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The Option ",P1," Is Invalid. The Valid Options Are:"
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT " ALL : Just Build Everything."
-$ WRITE SYS$OUTPUT " LIBRARY : To Compile Just The [.xxx.EXE.SSL]LIBSSL.OLB Library."
-$ WRITE SYS$OUTPUT " SSL_TASK : To Compile Just The [.xxx.EXE.SSL]SSL_TASK.EXE Program."
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT " Where 'xxx' Stands For:"
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT " ALPHA[64]: Alpha Architecture."
-$ WRITE SYS$OUTPUT " IA64[64] : IA64 Architecture."
-$ WRITE SYS$OUTPUT " VAX : VAX Architecture."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Time To EXIT.
-$!
-$ EXIT
-$!
-$! End The Valid Argument Check.
-$!
-$ ENDIF
-$!
-$! End The P1 Check.
-$!
-$ ENDIF
-$!
-$! Check To See If P2 Is Blank.
-$!
-$ IF (P2.EQS."NODEBUG")
-$ THEN
-$!
-$! P2 Is NODEBUG, So Compile Without Debugger Information.
-$!
-$ DEBUGGER = "NODEBUG"
-$ LINKMAP = "NOMAP"
-$ TRACEBACK = "NOTRACEBACK"
-$ GCC_OPTIMIZE = "OPTIMIZE"
-$ CC_OPTIMIZE = "OPTIMIZE"
-$ WRITE SYS$OUTPUT "No Debugger Information Will Be Produced During Compile."
-$ WRITE SYS$OUTPUT "Compiling With Compiler Optimization."
-$!
-$! Else...
-$!
-$ ELSE
-$!
-$! Check To See If We Are To Compile With Debugger Information.
-$!
-$ IF (P2.EQS."DEBUG")
-$ THEN
-$!
-$! Compile With Debugger Information.
-$!
-$ DEBUGGER = "DEBUG"
-$ LINKMAP = "MAP"
-$ TRACEBACK = "TRACEBACK"
-$ GCC_OPTIMIZE = "NOOPTIMIZE"
-$ CC_OPTIMIZE = "NOOPTIMIZE"
-$ WRITE SYS$OUTPUT "Debugger Information Will Be Produced During Compile."
-$ WRITE SYS$OUTPUT "Compiling Without Compiler Optimization."
-$ ELSE
-$!
-$! Tell The User Entered An Invalid Option.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The Option ",P2," Is Invalid. The Valid Options Are:"
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT " DEBUG : Compile With The Debugger Information."
-$ WRITE SYS$OUTPUT " NODEBUG : Compile Without The Debugger Information."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Time To EXIT.
-$!
-$ EXIT
-$!
-$! End The Valid Argument Check.
-$!
-$ ENDIF
-$!
-$! End The P2 Check.
-$!
-$ ENDIF
-$!
-$! Special Threads For OpenVMS v7.1 Or Later
-$!
-$! Written By: Richard Levitte
-$! richard@levitte.org
-$!
-$!
-$! Check To See If We Have A Option For P5.
-$!
-$ IF (P5.EQS."")
-$ THEN
-$!
-$! Get The Version Of VMS We Are Using.
-$!
-$ ISSEVEN :=
-$ TMP = F$ELEMENT(0,"-",F$EXTRACT(1,4,F$GETSYI("VERSION")))
-$ TMP = F$INTEGER(F$ELEMENT(0,".",TMP)+F$ELEMENT(1,".",TMP))
-$!
-$! Check To See If The VMS Version Is v7.1 Or Later.
-$!
-$ IF (TMP.GE.71)
-$ THEN
-$!
-$! We Have OpenVMS v7.1 Or Later, So Use The Special Threads.
-$!
-$ ISSEVEN := ,PTHREAD_USE_D4
-$!
-$! End The VMS Version Check.
-$!
-$ ENDIF
-$!
-$! End The P5 Check.
-$!
-$ ENDIF
-$!
-$! Check P6 (POINTER_SIZE).
-$!
-$ IF (P6 .NES. "") .AND. (ARCH .NES. "VAX")
-$ THEN
-$!
-$ IF (P6 .EQS. "32")
-$ THEN
-$ POINTER_SIZE = " /POINTER_SIZE=32"
-$ ELSE
-$ POINTER_SIZE = F$EDIT( P6, "COLLAPSE, UPCASE")
-$ IF ((POINTER_SIZE .EQS. "64") .OR. -
- (POINTER_SIZE .EQS. "64=") .OR. -
- (POINTER_SIZE .EQS. "64=ARGV"))
-$ THEN
-$ ARCHD = ARCH+ "_64"
-$ LIB32 = ""
-$ POINTER_SIZE = " /POINTER_SIZE=64"
-$ ELSE
-$!
-$! Tell The User Entered An Invalid Option.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The Option ", P6, -
- " Is Invalid. The Valid Options Are:"
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT -
- " """" : Compile with default (short) pointers."
-$ WRITE SYS$OUTPUT -
- " 32 : Compile with 32-bit (short) pointers."
-$ WRITE SYS$OUTPUT -
- " 64 : Compile with 64-bit (long) pointers (auto ARGV)."
-$ WRITE SYS$OUTPUT -
- " 64= : Compile with 64-bit (long) pointers (no ARGV)."
-$ WRITE SYS$OUTPUT -
- " 64=ARGV : Compile with 64-bit (long) pointers (ARGV)."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Time To EXIT.
-$!
-$ EXIT
-$!
-$ ENDIF
-$!
-$ ENDIF
-$!
-$! End The P6 (POINTER_SIZE) Check.
-$!
-$ ENDIF
-$!
-$! Set basic C compiler /INCLUDE directories.
-$!
-$ CC_INCLUDES = "SYS$DISK:[-.CRYPTO],SYS$DISK:[-]"
-$!
-$! Check To See If P3 Is Blank.
-$!
-$ IF (P3.EQS."")
-$ THEN
-$!
-$! O.K., The User Didn't Specify A Compiler, Let's Try To
-$! Find Out Which One To Use.
-$!
-$! Check To See If We Have GNU C.
-$!
-$ IF (F$TRNLNM("GNU_CC").NES."")
-$ THEN
-$!
-$! Looks Like GNUC, Set To Use GNUC.
-$!
-$ P3 = "GNUC"
-$!
-$! End The GNU C Compiler Check.
-$!
-$ ELSE
-$!
-$! Check To See If We Have VAXC Or DECC.
-$!
-$ IF (ARCH.NES."VAX").OR.(F$TRNLNM("DECC$CC_DEFAULT").NES."")
-$ THEN
-$!
-$! Looks Like DECC, Set To Use DECC.
-$!
-$ P3 = "DECC"
-$!
-$! Else...
-$!
-$ ELSE
-$!
-$! Looks Like VAXC, Set To Use VAXC.
-$!
-$ P3 = "VAXC"
-$!
-$! End The VAXC Compiler Check.
-$!
-$ ENDIF
-$!
-$! End The DECC & VAXC Compiler Check.
-$!
-$ ENDIF
-$!
-$! End The Compiler Check.
-$!
-$ ENDIF
-$!
-$! Check To See If We Have A Option For P4.
-$!
-$ IF (P4.EQS."")
-$ THEN
-$!
-$! Find out what socket library we have available
-$!
-$ IF F$PARSE("SOCKETSHR:") .NES. ""
-$ THEN
-$!
-$! We have SOCKETSHR, and it is my opinion that it's the best to use.
-$!
-$ P4 = "SOCKETSHR"
-$!
-$! Tell the user
-$!
-$ WRITE SYS$OUTPUT "Using SOCKETSHR for TCP/IP"
-$!
-$! Else, let's look for something else
-$!
-$ ELSE
-$!
-$! Like UCX (the reason to do this before Multinet is that the UCX
-$! emulation is easier to use...)
-$!
-$ IF F$TRNLNM("UCX$IPC_SHR") .NES. "" -
- .OR. F$PARSE("SYS$SHARE:UCX$IPC_SHR.EXE") .NES. "" -
- .OR. F$PARSE("SYS$LIBRARY:UCX$IPC.OLB") .NES. ""
-$ THEN
-$!
-$! Last resort: a UCX or UCX-compatible library
-$!
-$ P4 = "UCX"
-$!
-$! Tell the user
-$!
-$ WRITE SYS$OUTPUT "Using UCX or an emulation thereof for TCP/IP"
-$!
-$! That was all...
-$!
-$ ENDIF
-$ ENDIF
-$ ENDIF
-$!
-$! Set Up Initial CC Definitions, Possibly With User Ones
-$!
-$ CCDEFS = "TCPIP_TYPE_''P4'"
-$ IF F$TYPE(USER_CCDEFS) .NES. "" THEN CCDEFS = CCDEFS + "," + USER_CCDEFS
-$ CCEXTRAFLAGS = ""
-$ IF F$TYPE(USER_CCFLAGS) .NES. "" THEN CCEXTRAFLAGS = USER_CCFLAGS
-$ CCDISABLEWARNINGS = "MAYLOSEDATA3" !!! "LONGLONGTYPE,LONGLONGSUFX,FOUNDCR"
-$ IF F$TYPE(USER_CCDISABLEWARNINGS) .NES. "" THEN -
- CCDISABLEWARNINGS = CCDISABLEWARNINGS + "," + USER_CCDISABLEWARNINGS
-$!
-$! Check To See If We Have A ZLIB Option.
-$!
-$ ZLIB = P7
-$ IF (ZLIB .NES. "")
-$ THEN
-$!
-$! Check for expected ZLIB files.
-$!
-$ err = 0
-$ file1 = f$parse( "zlib.h", ZLIB, , , "SYNTAX_ONLY")
-$ if (f$search( file1) .eqs. "")
-$ then
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The Option ", ZLIB, " Is Invalid."
-$ WRITE SYS$OUTPUT " Can't find header: ''file1'"
-$ err = 1
-$ endif
-$ file1 = f$parse( "A.;", ZLIB)- "A.;"
-$!
-$ file2 = f$parse( ZLIB, "libz.olb", , , "SYNTAX_ONLY")
-$ if (f$search( file2) .eqs. "")
-$ then
-$ if (err .eq. 0)
-$ then
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The Option ", ZLIB, " Is Invalid."
-$ endif
-$ WRITE SYS$OUTPUT " Can't find library: ''file2'"
-$ WRITE SYS$OUTPUT ""
-$ err = err+ 2
-$ endif
-$ if (err .eq. 1)
-$ then
-$ WRITE SYS$OUTPUT ""
-$ endif
-$!
-$ if (err .ne. 0)
-$ then
-$ EXIT
-$ endif
-$!
-$ CCDEFS = """ZLIB=1"", "+ CCDEFS
-$ CC_INCLUDES = CC_INCLUDES+ ", "+ file1
-$ ZLIB_LIB = ", ''file2' /library"
-$!
-$! Print info
-$!
-$ WRITE SYS$OUTPUT "ZLIB library spec: ", file2
-$!
-$! End The ZLIB Check.
-$!
-$ ENDIF
-$!
-$! Check To See If The User Entered A Valid Parameter.
-$!
-$ IF (P3.EQS."VAXC").OR.(P3.EQS."DECC").OR.(P3.EQS."GNUC")
-$ THEN
-$!
-$! Check To See If The User Wanted DECC.
-$!
-$ IF (P3.EQS."DECC")
-$ THEN
-$!
-$! Looks Like DECC, Set To Use DECC.
-$!
-$ COMPILER = "DECC"
-$!
-$! Tell The User We Are Using DECC.
-$!
-$ WRITE SYS$OUTPUT "Using DECC 'C' Compiler."
-$!
-$! Use DECC...
-$!
-$ CC = "CC"
-$ IF ARCH.EQS."VAX" .AND. F$TRNLNM("DECC$CC_DEFAULT").NES."/DECC" -
- THEN CC = "CC/DECC"
-$ CC = CC + " /''CC_OPTIMIZE' /''DEBUGGER' /STANDARD=RELAXED"+ -
- "''POINTER_SIZE' /NOLIST /PREFIX=ALL" + -
- " /INCLUDE=(''CC_INCLUDES') " + CCEXTRAFLAGS
-$!
-$! Define The Linker Options File Name.
-$!
-$ OPT_FILE = "VAX_DECC_OPTIONS.OPT"
-$!
-$! End DECC Check.
-$!
-$ ENDIF
-$!
-$! Check To See If We Are To Use VAXC.
-$!
-$ IF (P3.EQS."VAXC")
-$ THEN
-$!
-$! Looks Like VAXC, Set To Use VAXC.
-$!
-$ COMPILER = "VAXC"
-$!
-$! Tell The User We Are Using VAX C.
-$!
-$ WRITE SYS$OUTPUT "Using VAXC 'C' Compiler."
-$!
-$! Compile Using VAXC.
-$!
-$ CC = "CC"
-$ IF ARCH.NES."VAX"
-$ THEN
-$ WRITE SYS$OUTPUT "There is no VAX C on ''ARCH'!"
-$ EXIT
-$ ENDIF
-$ IF F$TRNLNM("DECC$CC_DEFAULT").EQS."/DECC" THEN CC = "CC/VAXC"
-$ CC = CC + "/''CC_OPTIMIZE'/''DEBUGGER'/NOLIST" + -
- "/INCLUDE=(''CC_INCLUDES')" + CCEXTRAFLAGS
-$ CCDEFS = CCDEFS + ",""VAXC"""
-$!
-$! Define <sys> As SYS$COMMON:[SYSLIB]
-$!
-$ DEFINE/NOLOG SYS SYS$COMMON:[SYSLIB]
-$!
-$! Define The Linker Options File Name.
-$!
-$ OPT_FILE = "VAX_VAXC_OPTIONS.OPT"
-$!
-$! End VAXC Check
-$!
-$ ENDIF
-$!
-$! Check To See If We Are To Use GNU C.
-$!
-$ IF (P3.EQS."GNUC")
-$ THEN
-$!
-$! Looks Like GNUC, Set To Use GNUC.
-$!
-$ COMPILER = "GNUC"
-$!
-$! Tell The User We Are Using GNUC.
-$!
-$ WRITE SYS$OUTPUT "Using GNU 'C' Compiler."
-$!
-$! Use GNU C...
-$!
-$ IF F$TYPE(GCC) .EQS. "" THEN GCC := GCC
-$ CC = GCC+"/NOCASE_HACK/''GCC_OPTIMIZE'/''DEBUGGER'/NOLIST" + -
- "/INCLUDE=(''CC_INCLUDES')" + CCEXTRAFLAGS
-$!
-$! Define The Linker Options File Name.
-$!
-$ OPT_FILE = "VAX_GNUC_OPTIONS.OPT"
-$!
-$! End The GNU C Check.
-$!
-$ ENDIF
-$!
-$! Set up default defines
-$!
-$ CCDEFS = """FLAT_INC=1""," + CCDEFS
-$!
-$! Finish up the definition of CC.
-$!
-$ IF COMPILER .EQS. "DECC"
-$ THEN
-$ IF CCDISABLEWARNINGS .EQS. ""
-$ THEN
-$ CC4DISABLEWARNINGS = "DOLLARID"
-$ ELSE
-$ CC4DISABLEWARNINGS = CCDISABLEWARNINGS + ",DOLLARID"
-$ CCDISABLEWARNINGS = " /WARNING=(DISABLE=(" + CCDISABLEWARNINGS + "))"
-$ ENDIF
-$ CC4DISABLEWARNINGS = " /WARNING=(DISABLE=(" + CC4DISABLEWARNINGS + "))"
-$ ELSE
-$ CCDISABLEWARNINGS = ""
-$ CC4DISABLEWARNINGS = ""
-$ ENDIF
-$ CC2 = CC + " /DEFINE=(" + CCDEFS + ",_POSIX_C_SOURCE)" + CCDISABLEWARNINGS
-$ CC3 = CC + " /DEFINE=(" + CCDEFS + ISSEVEN + ")" + CCDISABLEWARNINGS
-$ CC = CC + " /DEFINE=(" + CCDEFS + ")" + CCDISABLEWARNINGS
-$ IF COMPILER .EQS. "DECC"
-$ THEN
-$ CC4 = CC - CCDISABLEWARNINGS + CC4DISABLEWARNINGS
-$ CC5 = CC3 - CCDISABLEWARNINGS + CC4DISABLEWARNINGS
-$ ELSE
-$ CC4 = CC
-$ CC5 = CC3
-$ ENDIF
-$!
-$! Show user the result
-$!
-$ WRITE/SYMBOL SYS$OUTPUT "Main Compiling Command: ",CC
-$!
-$! Else The User Entered An Invalid Argument.
-$!
-$ ELSE
-$!
-$! Tell The User We Don't Know What They Want.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The Option ",P3," Is Invalid. The Valid Options Are:"
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT " VAXC : To Compile With VAX C."
-$ WRITE SYS$OUTPUT " DECC : To Compile With DEC C."
-$ WRITE SYS$OUTPUT " GNUC : To Compile With GNU C."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Time To EXIT.
-$!
-$ EXIT
-$ ENDIF
-$!
-$! Time to check the contents, and to make sure we get the correct library.
-$!
-$ IF P4.EQS."SOCKETSHR" .OR. P4.EQS."MULTINET" .OR. P4.EQS."UCX" -
- .OR. P4.EQS."TCPIP" .OR. P4.EQS."NONE"
-$ THEN
-$!
-$! Check to see if SOCKETSHR was chosen
-$!
-$ IF P4.EQS."SOCKETSHR"
-$ THEN
-$!
-$! Set the library to use SOCKETSHR
-$!
-$ TCPIP_LIB = ",SYS$DISK:[-.VMS]SOCKETSHR_SHR.OPT /OPTIONS"
-$!
-$! Done with SOCKETSHR
-$!
-$ ENDIF
-$!
-$! Check to see if MULTINET was chosen
-$!
-$ IF P4.EQS."MULTINET"
-$ THEN
-$!
-$! Set the library to use UCX emulation.
-$!
-$ P4 = "UCX"
-$!
-$! Done with MULTINET
-$!
-$ ENDIF
-$!
-$! Check to see if UCX was chosen
-$!
-$ IF P4.EQS."UCX"
-$ THEN
-$!
-$! Set the library to use UCX.
-$!
-$ TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_DECC.OPT /OPTIONS"
-$ IF F$TRNLNM("UCX$IPC_SHR") .NES. ""
-$ THEN
-$ TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_DECC_LOG.OPT /OPTIONS"
-$ ELSE
-$ IF COMPILER .NES. "DECC" .AND. ARCH .EQS. "VAX" THEN -
- TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_VAXC.OPT /OPTIONS"
-$ ENDIF
-$!
-$! Done with UCX
-$!
-$ ENDIF
-$!
-$! Check to see if TCPIP was chosen
-$!
-$ IF P4.EQS."TCPIP"
-$ THEN
-$!
-$! Set the library to use TCPIP (post UCX).
-$!
-$ TCPIP_LIB = ",SYS$DISK:[-.VMS]TCPIP_SHR_DECC.OPT /OPTIONS"
-$!
-$! Done with TCPIP
-$!
-$ ENDIF
-$!
-$! Check to see if NONE was chosen
-$!
-$ IF P4.EQS."NONE"
-$ THEN
-$!
-$! Do not use a TCPIP library.
-$!
-$ TCPIP_LIB = ""
-$!
-$! Done with NONE
-$!
-$ ENDIF
-$!
-$! Print info
-$!
-$ WRITE SYS$OUTPUT "TCP/IP library spec: ", TCPIP_LIB- ","
-$!
-$! Else The User Entered An Invalid Argument.
-$!
-$ ELSE
-$!
-$! Tell The User We Don't Know What They Want.
-$!
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT "The Option ",P4," Is Invalid. The Valid Options Are:"
-$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT " SOCKETSHR : To link with SOCKETSHR TCP/IP library."
-$ WRITE SYS$OUTPUT " UCX : To link with UCX TCP/IP library."
-$ WRITE SYS$OUTPUT " TCPIP : To link with TCPIP (post UCX) TCP/IP library."
-$ WRITE SYS$OUTPUT ""
-$!
-$! Time To EXIT.
-$!
-$ EXIT
-$!
-$! Done with TCP/IP libraries
-$!
-$ ENDIF
-$!
-$! Time To RETURN...
-$!
-$ RETURN
-$!
-$ INITIALISE:
-$!
-$! Save old value of the logical name OPENSSL
-$!
-$ __SAVE_OPENSSL = F$TRNLNM("OPENSSL","LNM$PROCESS_TABLE")
-$!
-$! Save directory information
-$!
-$ __HERE = F$PARSE(F$PARSE("A.;",F$ENVIRONMENT("PROCEDURE"))-"A.;","[]A.;") - "A.;"
-$ __HERE = F$EDIT(__HERE,"UPCASE")
-$ __TOP = __HERE - "SSL]"
-$ __INCLUDE = __TOP + "INCLUDE.OPENSSL]"
-$!
-$! Set up the logical name OPENSSL to point at the include directory
-$!
-$ DEFINE OPENSSL/NOLOG '__INCLUDE'
-$!
-$! Done
-$!
-$ RETURN
-$!
-$ CLEANUP:
-$!
-$! Restore the logical name OPENSSL if it had a value
-$!
-$ IF __SAVE_OPENSSL .EQS. ""
-$ THEN
-$ DEASSIGN OPENSSL
-$ ELSE
-$ DEFINE/NOLOG OPENSSL '__SAVE_OPENSSL'
-$ ENDIF
-$!
-$! Done
-$!
-$ RETURN
diff --git a/drivers/builtin_openssl/ssl/ssl.h b/drivers/builtin_openssl/ssl/ssl.h
deleted file mode 100644
index 7219a0e64b..0000000000
--- a/drivers/builtin_openssl/ssl/ssl.h
+++ /dev/null
@@ -1,2588 +0,0 @@
-/* ssl/ssl.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECC cipher suite support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#ifndef HEADER_SSL_H
-#define HEADER_SSL_H
-
-#include <openssl/e_os2.h>
-
-#ifndef OPENSSL_NO_COMP
-#include <openssl/comp.h>
-#endif
-#ifndef OPENSSL_NO_BIO
-#include <openssl/bio.h>
-#endif
-#ifndef OPENSSL_NO_DEPRECATED
-#ifndef OPENSSL_NO_X509
-#include <openssl/x509.h>
-#endif
-#include <openssl/crypto.h>
-#include <openssl/lhash.h>
-#include <openssl/buffer.h>
-#endif
-#include <openssl/pem.h>
-#include <openssl/hmac.h>
-
-#include <openssl/kssl.h>
-#include <openssl/safestack.h>
-#include <openssl/symhacks.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* SSLeay version number for ASN.1 encoding of the session information */
-/* Version 0 - initial version
- * Version 1 - added the optional peer certificate
- */
-#define SSL_SESSION_ASN1_VERSION 0x0001
-
-/* text strings for the ciphers */
-#define SSL_TXT_NULL_WITH_MD5 SSL2_TXT_NULL_WITH_MD5
-#define SSL_TXT_RC4_128_WITH_MD5 SSL2_TXT_RC4_128_WITH_MD5
-#define SSL_TXT_RC4_128_EXPORT40_WITH_MD5 SSL2_TXT_RC4_128_EXPORT40_WITH_MD5
-#define SSL_TXT_RC2_128_CBC_WITH_MD5 SSL2_TXT_RC2_128_CBC_WITH_MD5
-#define SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5
-#define SSL_TXT_IDEA_128_CBC_WITH_MD5 SSL2_TXT_IDEA_128_CBC_WITH_MD5
-#define SSL_TXT_DES_64_CBC_WITH_MD5 SSL2_TXT_DES_64_CBC_WITH_MD5
-#define SSL_TXT_DES_64_CBC_WITH_SHA SSL2_TXT_DES_64_CBC_WITH_SHA
-#define SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5
-#define SSL_TXT_DES_192_EDE3_CBC_WITH_SHA SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA
-
-/* VRS Additional Kerberos5 entries
- */
-#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA
-#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
-#define SSL_TXT_KRB5_RC4_128_SHA SSL3_TXT_KRB5_RC4_128_SHA
-#define SSL_TXT_KRB5_IDEA_128_CBC_SHA SSL3_TXT_KRB5_IDEA_128_CBC_SHA
-#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5
-#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5
-#define SSL_TXT_KRB5_RC4_128_MD5 SSL3_TXT_KRB5_RC4_128_MD5
-#define SSL_TXT_KRB5_IDEA_128_CBC_MD5 SSL3_TXT_KRB5_IDEA_128_CBC_MD5
-
-#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA
-#define SSL_TXT_KRB5_RC2_40_CBC_SHA SSL3_TXT_KRB5_RC2_40_CBC_SHA
-#define SSL_TXT_KRB5_RC4_40_SHA SSL3_TXT_KRB5_RC4_40_SHA
-#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5
-#define SSL_TXT_KRB5_RC2_40_CBC_MD5 SSL3_TXT_KRB5_RC2_40_CBC_MD5
-#define SSL_TXT_KRB5_RC4_40_MD5 SSL3_TXT_KRB5_RC4_40_MD5
-
-#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA
-#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5
-#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA
-#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5
-#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
-#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5
-#define SSL_MAX_KRB5_PRINCIPAL_LENGTH 256
-
-#define SSL_MAX_SSL_SESSION_ID_LENGTH 32
-#define SSL_MAX_SID_CTX_LENGTH 32
-
-#define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES (512/8)
-#define SSL_MAX_KEY_ARG_LENGTH 8
-#define SSL_MAX_MASTER_KEY_LENGTH 48
-
-
-/* These are used to specify which ciphers to use and not to use */
-
-#define SSL_TXT_EXP40 "EXPORT40"
-#define SSL_TXT_EXP56 "EXPORT56"
-#define SSL_TXT_LOW "LOW"
-#define SSL_TXT_MEDIUM "MEDIUM"
-#define SSL_TXT_HIGH "HIGH"
-#define SSL_TXT_FIPS "FIPS"
-
-#define SSL_TXT_kFZA "kFZA" /* unused! */
-#define SSL_TXT_aFZA "aFZA" /* unused! */
-#define SSL_TXT_eFZA "eFZA" /* unused! */
-#define SSL_TXT_FZA "FZA" /* unused! */
-
-#define SSL_TXT_aNULL "aNULL"
-#define SSL_TXT_eNULL "eNULL"
-#define SSL_TXT_NULL "NULL"
-
-#define SSL_TXT_kRSA "kRSA"
-#define SSL_TXT_kDHr "kDHr" /* no such ciphersuites supported! */
-#define SSL_TXT_kDHd "kDHd" /* no such ciphersuites supported! */
-#define SSL_TXT_kDH "kDH" /* no such ciphersuites supported! */
-#define SSL_TXT_kEDH "kEDH"
-#define SSL_TXT_kKRB5 "kKRB5"
-#define SSL_TXT_kECDHr "kECDHr"
-#define SSL_TXT_kECDHe "kECDHe"
-#define SSL_TXT_kECDH "kECDH"
-#define SSL_TXT_kEECDH "kEECDH"
-#define SSL_TXT_kPSK "kPSK"
-#define SSL_TXT_kGOST "kGOST"
-#define SSL_TXT_kSRP "kSRP"
-
-#define SSL_TXT_aRSA "aRSA"
-#define SSL_TXT_aDSS "aDSS"
-#define SSL_TXT_aDH "aDH" /* no such ciphersuites supported! */
-#define SSL_TXT_aECDH "aECDH"
-#define SSL_TXT_aKRB5 "aKRB5"
-#define SSL_TXT_aECDSA "aECDSA"
-#define SSL_TXT_aPSK "aPSK"
-#define SSL_TXT_aGOST94 "aGOST94"
-#define SSL_TXT_aGOST01 "aGOST01"
-#define SSL_TXT_aGOST "aGOST"
-
-#define SSL_TXT_DSS "DSS"
-#define SSL_TXT_DH "DH"
-#define SSL_TXT_EDH "EDH" /* same as "kEDH:-ADH" */
-#define SSL_TXT_ADH "ADH"
-#define SSL_TXT_RSA "RSA"
-#define SSL_TXT_ECDH "ECDH"
-#define SSL_TXT_EECDH "EECDH" /* same as "kEECDH:-AECDH" */
-#define SSL_TXT_AECDH "AECDH"
-#define SSL_TXT_ECDSA "ECDSA"
-#define SSL_TXT_KRB5 "KRB5"
-#define SSL_TXT_PSK "PSK"
-#define SSL_TXT_SRP "SRP"
-
-#define SSL_TXT_DES "DES"
-#define SSL_TXT_3DES "3DES"
-#define SSL_TXT_RC4 "RC4"
-#define SSL_TXT_RC2 "RC2"
-#define SSL_TXT_IDEA "IDEA"
-#define SSL_TXT_SEED "SEED"
-#define SSL_TXT_AES128 "AES128"
-#define SSL_TXT_AES256 "AES256"
-#define SSL_TXT_AES "AES"
-#define SSL_TXT_AES_GCM "AESGCM"
-#define SSL_TXT_CAMELLIA128 "CAMELLIA128"
-#define SSL_TXT_CAMELLIA256 "CAMELLIA256"
-#define SSL_TXT_CAMELLIA "CAMELLIA"
-
-#define SSL_TXT_MD5 "MD5"
-#define SSL_TXT_SHA1 "SHA1"
-#define SSL_TXT_SHA "SHA" /* same as "SHA1" */
-#define SSL_TXT_GOST94 "GOST94"
-#define SSL_TXT_GOST89MAC "GOST89MAC"
-#define SSL_TXT_SHA256 "SHA256"
-#define SSL_TXT_SHA384 "SHA384"
-
-#define SSL_TXT_SSLV2 "SSLv2"
-#define SSL_TXT_SSLV3 "SSLv3"
-#define SSL_TXT_TLSV1 "TLSv1"
-#define SSL_TXT_TLSV1_1 "TLSv1.1"
-#define SSL_TXT_TLSV1_2 "TLSv1.2"
-
-#define SSL_TXT_EXP "EXP"
-#define SSL_TXT_EXPORT "EXPORT"
-
-#define SSL_TXT_ALL "ALL"
-
-/*
- * COMPLEMENTOF* definitions. These identifiers are used to (de-select)
- * ciphers normally not being used.
- * Example: "RC4" will activate all ciphers using RC4 including ciphers
- * without authentication, which would normally disabled by DEFAULT (due
- * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT"
- * will make sure that it is also disabled in the specific selection.
- * COMPLEMENTOF* identifiers are portable between version, as adjustments
- * to the default cipher setup will also be included here.
- *
- * COMPLEMENTOFDEFAULT does not experience the same special treatment that
- * DEFAULT gets, as only selection is being done and no sorting as needed
- * for DEFAULT.
- */
-#define SSL_TXT_CMPALL "COMPLEMENTOFALL"
-#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT"
-
-/* The following cipher list is used by default.
- * It also is substituted when an application-defined cipher list string
- * starts with 'DEFAULT'. */
-#define SSL_DEFAULT_CIPHER_LIST "ALL:!aNULL:!eNULL:!SSLv2"
-/* As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always
- * starts with a reasonable order, and all we have to do for DEFAULT is
- * throwing out anonymous and unencrypted ciphersuites!
- * (The latter are not actually enabled by ALL, but "ALL:RSA" would enable
- * some of them.)
- */
-
-/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
-#define SSL_SENT_SHUTDOWN 1
-#define SSL_RECEIVED_SHUTDOWN 2
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if (defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_MD5)) && !defined(OPENSSL_NO_SSL2)
-#define OPENSSL_NO_SSL2
-#endif
-
-#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1
-#define SSL_FILETYPE_PEM X509_FILETYPE_PEM
-
-/* This is needed to stop compilers complaining about the
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
-typedef struct ssl_st *ssl_crock_st;
-typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
-typedef struct ssl_method_st SSL_METHOD;
-typedef struct ssl_cipher_st SSL_CIPHER;
-typedef struct ssl_session_st SSL_SESSION;
-
-DECLARE_STACK_OF(SSL_CIPHER)
-
-/* SRTP protection profiles for use with the use_srtp extension (RFC 5764)*/
-typedef struct srtp_protection_profile_st
- {
- const char *name;
- unsigned long id;
- } SRTP_PROTECTION_PROFILE;
-
-DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE)
-
-typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
-typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-/* used to hold info on the particular ciphers used */
-struct ssl_cipher_st
- {
- int valid;
- const char *name; /* text name */
- unsigned long id; /* id, 4 bytes, first is version */
-
- /* changed in 0.9.9: these four used to be portions of a single value 'algorithms' */
- unsigned long algorithm_mkey; /* key exchange algorithm */
- unsigned long algorithm_auth; /* server authentication */
- unsigned long algorithm_enc; /* symmetric encryption */
- unsigned long algorithm_mac; /* symmetric authentication */
- unsigned long algorithm_ssl; /* (major) protocol version */
-
- unsigned long algo_strength; /* strength and export flags */
- unsigned long algorithm2; /* Extra flags */
- int strength_bits; /* Number of bits really used */
- int alg_bits; /* Number of bits for algorithm */
- };
-
-
-/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
-struct ssl_method_st
- {
- int version;
- int (*ssl_new)(SSL *s);
- void (*ssl_clear)(SSL *s);
- void (*ssl_free)(SSL *s);
- int (*ssl_accept)(SSL *s);
- int (*ssl_connect)(SSL *s);
- int (*ssl_read)(SSL *s,void *buf,int len);
- int (*ssl_peek)(SSL *s,void *buf,int len);
- int (*ssl_write)(SSL *s,const void *buf,int len);
- int (*ssl_shutdown)(SSL *s);
- int (*ssl_renegotiate)(SSL *s);
- int (*ssl_renegotiate_check)(SSL *s);
- long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
- max, int *ok);
- int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len,
- int peek);
- int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
- int (*ssl_dispatch_alert)(SSL *s);
- long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
- long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
- const SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
- int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
- int (*ssl_pending)(const SSL *s);
- int (*num_ciphers)(void);
- const SSL_CIPHER *(*get_cipher)(unsigned ncipher);
- const struct ssl_method_st *(*get_ssl_method)(int version);
- long (*get_timeout)(void);
- struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
- int (*ssl_version)(void);
- long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void));
- long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
- };
-
-/* Lets make this into an ASN.1 type structure as follows
- * SSL_SESSION_ID ::= SEQUENCE {
- * version INTEGER, -- structure version number
- * SSLversion INTEGER, -- SSL version number
- * Cipher OCTET STRING, -- the 3 byte cipher ID
- * Session_ID OCTET STRING, -- the Session ID
- * Master_key OCTET STRING, -- the master key
- * KRB5_principal OCTET STRING -- optional Kerberos principal
- * Key_Arg [ 0 ] IMPLICIT OCTET STRING, -- the optional Key argument
- * Time [ 1 ] EXPLICIT INTEGER, -- optional Start Time
- * Timeout [ 2 ] EXPLICIT INTEGER, -- optional Timeout ins seconds
- * Peer [ 3 ] EXPLICIT X509, -- optional Peer Certificate
- * Session_ID_context [ 4 ] EXPLICIT OCTET STRING, -- the Session ID context
- * Verify_result [ 5 ] EXPLICIT INTEGER, -- X509_V_... code for `Peer'
- * HostName [ 6 ] EXPLICIT OCTET STRING, -- optional HostName from servername TLS extension
- * PSK_identity_hint [ 7 ] EXPLICIT OCTET STRING, -- optional PSK identity hint
- * PSK_identity [ 8 ] EXPLICIT OCTET STRING, -- optional PSK identity
- * Ticket_lifetime_hint [9] EXPLICIT INTEGER, -- server's lifetime hint for session ticket
- * Ticket [10] EXPLICIT OCTET STRING, -- session ticket (clients only)
- * Compression_meth [11] EXPLICIT OCTET STRING, -- optional compression method
- * SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username
- * }
- * Look in ssl/ssl_asn1.c for more details
- * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
- */
-struct ssl_session_st
- {
- int ssl_version; /* what ssl version session info is
- * being kept in here? */
-
- /* only really used in SSLv2 */
- unsigned int key_arg_length;
- unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH];
- int master_key_length;
- unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
- /* session_id - valid? */
- unsigned int session_id_length;
- unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
- /* this is used to determine whether the session is being reused in
- * the appropriate context. It is up to the application to set this,
- * via SSL_new */
- unsigned int sid_ctx_length;
- unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
-
-#ifndef OPENSSL_NO_KRB5
- unsigned int krb5_client_princ_len;
- unsigned char krb5_client_princ[SSL_MAX_KRB5_PRINCIPAL_LENGTH];
-#endif /* OPENSSL_NO_KRB5 */
-#ifndef OPENSSL_NO_PSK
- char *psk_identity_hint;
- char *psk_identity;
-#endif
- /* Used to indicate that session resumption is not allowed.
- * Applications can also set this bit for a new session via
- * not_resumable_session_cb to disable session caching and tickets. */
- int not_resumable;
-
- /* The cert is the certificate used to establish this connection */
- struct sess_cert_st /* SESS_CERT */ *sess_cert;
-
- /* This is the cert for the other end.
- * On clients, it will be the same as sess_cert->peer_key->x509
- * (the latter is not enough as sess_cert is not retained
- * in the external representation of sessions, see ssl_asn1.c). */
- X509 *peer;
- /* when app_verify_callback accepts a session where the peer's certificate
- * is not ok, we must remember the error for session reuse: */
- long verify_result; /* only for servers */
-
- int references;
- long timeout;
- long time;
-
- unsigned int compress_meth; /* Need to lookup the method */
-
- const SSL_CIPHER *cipher;
- unsigned long cipher_id; /* when ASN.1 loaded, this
- * needs to be used to load
- * the 'cipher' structure */
-
- STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */
-
- CRYPTO_EX_DATA ex_data; /* application specific data */
-
- /* These are used to make removal of session-ids more
- * efficient and to implement a maximum cache size. */
- struct ssl_session_st *prev,*next;
-#ifndef OPENSSL_NO_TLSEXT
- char *tlsext_hostname;
-#ifndef OPENSSL_NO_EC
- size_t tlsext_ecpointformatlist_length;
- unsigned char *tlsext_ecpointformatlist; /* peer's list */
- size_t tlsext_ellipticcurvelist_length;
- unsigned char *tlsext_ellipticcurvelist; /* peer's list */
-#endif /* OPENSSL_NO_EC */
- /* RFC4507 info */
- unsigned char *tlsext_tick; /* Session ticket */
- size_t tlsext_ticklen; /* Session ticket length */
- long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */
-#endif
-#ifndef OPENSSL_NO_SRP
- char *srp_username;
-#endif
- };
-
-#endif
-
-#define SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001L
-#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002L
-/* Allow initial connection to servers that don't support RI */
-#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L
-#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L
-#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x00000010L
-#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L
-#define SSL_OP_SAFARI_ECDHE_ECDSA_BUG 0x00000040L
-#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080L
-#define SSL_OP_TLS_D5_BUG 0x00000100L
-#define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L
-
-/* Hasn't done anything since OpenSSL 0.9.7h, retained for compatibility */
-#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0x0
-
-/* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added
- * in OpenSSL 0.9.6d. Usually (depending on the application protocol)
- * the workaround is not needed. Unfortunately some broken SSL/TLS
- * implementations cannot handle it at all, which is why we include
- * it in SSL_OP_ALL. */
-#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800L /* added in 0.9.6e */
-
-/* SSL_OP_ALL: various bug workarounds that should be rather harmless.
- * This used to be 0x000FFFFFL before 0.9.7. */
-#define SSL_OP_ALL 0x80000BFFL
-
-/* DTLS options */
-#define SSL_OP_NO_QUERY_MTU 0x00001000L
-/* Turn on Cookie Exchange (on relevant for servers) */
-#define SSL_OP_COOKIE_EXCHANGE 0x00002000L
-/* Don't use RFC4507 ticket extension */
-#define SSL_OP_NO_TICKET 0x00004000L
-/* Use Cisco's "speshul" version of DTLS_BAD_VER (as client) */
-#define SSL_OP_CISCO_ANYCONNECT 0x00008000L
-
-/* As server, disallow session resumption on renegotiation */
-#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L
-/* Don't use compression even if supported */
-#define SSL_OP_NO_COMPRESSION 0x00020000L
-/* Permit unsafe legacy renegotiation */
-#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L
-/* If set, always create a new key when using tmp_ecdh parameters */
-#define SSL_OP_SINGLE_ECDH_USE 0x00080000L
-/* If set, always create a new key when using tmp_dh parameters */
-#define SSL_OP_SINGLE_DH_USE 0x00100000L
-/* Set to always use the tmp_rsa key when doing RSA operations,
- * even when this violates protocol specs */
-#define SSL_OP_EPHEMERAL_RSA 0x00200000L
-/* Set on servers to choose the cipher according to the server's
- * preferences */
-#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L
-/* If set, a server will allow a client to issue a SSLv3.0 version number
- * as latest version supported in the premaster secret, even when TLSv1.0
- * (version 3.1) was announced in the client hello. Normally this is
- * forbidden to prevent version rollback attacks. */
-#define SSL_OP_TLS_ROLLBACK_BUG 0x00800000L
-
-#define SSL_OP_NO_SSLv2 0x01000000L
-#define SSL_OP_NO_SSLv3 0x02000000L
-#define SSL_OP_NO_TLSv1 0x04000000L
-#define SSL_OP_NO_TLSv1_2 0x08000000L
-#define SSL_OP_NO_TLSv1_1 0x10000000L
-
-/* These next two were never actually used for anything since SSLeay
- * zap so we have some more flags.
- */
-/* The next flag deliberately changes the ciphertest, this is a check
- * for the PKCS#1 attack */
-#define SSL_OP_PKCS1_CHECK_1 0x0
-#define SSL_OP_PKCS1_CHECK_2 0x0
-
-#define SSL_OP_NETSCAPE_CA_DN_BUG 0x20000000L
-#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x40000000L
-/* Make server add server-hello extension from early version of
- * cryptopro draft, when GOST ciphersuite is negotiated.
- * Required for interoperability with CryptoPro CSP 3.x
- */
-#define SSL_OP_CRYPTOPRO_TLSEXT_BUG 0x80000000L
-
-/* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
- * when just a single record has been written): */
-#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L
-/* Make it possible to retry SSL_write() with changed buffer location
- * (buffer contents must stay the same!); this is not the default to avoid
- * the misconception that non-blocking SSL_write() behaves like
- * non-blocking write(): */
-#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
-/* Never bother the application with retries if the transport
- * is blocking: */
-#define SSL_MODE_AUTO_RETRY 0x00000004L
-/* Don't attempt to automatically build certificate chain */
-#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
-/* Save RAM by releasing read and write buffers when they're empty. (SSL3 and
- * TLS only.) "Released" buffers are put onto a free-list in the context
- * or just freed (depending on the context's setting for freelist_max_len). */
-#define SSL_MODE_RELEASE_BUFFERS 0x00000010L
-/* Send the current time in the Random fields of the ClientHello and
- * ServerHello records for compatibility with hypothetical implementations
- * that require it.
- */
-#define SSL_MODE_SEND_CLIENTHELLO_TIME 0x00000020L
-#define SSL_MODE_SEND_SERVERHELLO_TIME 0x00000040L
-
-/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
- * they cannot be used to clear bits. */
-
-#define SSL_CTX_set_options(ctx,op) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
-#define SSL_CTX_clear_options(ctx,op) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
-#define SSL_CTX_get_options(ctx) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
-#define SSL_set_options(ssl,op) \
- SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL)
-#define SSL_clear_options(ssl,op) \
- SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
-#define SSL_get_options(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL)
-
-#define SSL_CTX_set_mode(ctx,op) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
-#define SSL_CTX_clear_mode(ctx,op) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL)
-#define SSL_CTX_get_mode(ctx) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL)
-#define SSL_clear_mode(ssl,op) \
- SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL)
-#define SSL_set_mode(ssl,op) \
- SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
-#define SSL_get_mode(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL)
-#define SSL_set_mtu(ssl, mtu) \
- SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL)
-
-#define SSL_get_secure_renegotiation_support(ssl) \
- SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL)
-
-#ifndef OPENSSL_NO_HEARTBEATS
-#define SSL_heartbeat(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_TLS_EXT_SEND_HEARTBEAT,0,NULL)
-#endif
-
-void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
-void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
-#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
-#define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
-
-#ifndef OPENSSL_NO_SRP
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-typedef struct srp_ctx_st
- {
- /* param for all the callbacks */
- void *SRP_cb_arg;
- /* set client Hello login callback */
- int (*TLS_ext_srp_username_callback)(SSL *, int *, void *);
- /* set SRP N/g param callback for verification */
- int (*SRP_verify_param_callback)(SSL *, void *);
- /* set SRP client passwd callback */
- char *(*SRP_give_srp_client_pwd_callback)(SSL *, void *);
-
- char *login;
- BIGNUM *N,*g,*s,*B,*A;
- BIGNUM *a,*b,*v;
- char *info;
- int strength;
-
- unsigned long srp_Mask;
- } SRP_CTX;
-
-#endif
-
-/* see tls_srp.c */
-int SSL_SRP_CTX_init(SSL *s);
-int SSL_CTX_SRP_CTX_init(SSL_CTX *ctx);
-int SSL_SRP_CTX_free(SSL *ctx);
-int SSL_CTX_SRP_CTX_free(SSL_CTX *ctx);
-int SSL_srp_server_param_with_username(SSL *s, int *ad);
-int SRP_generate_server_master_secret(SSL *s,unsigned char *master_key);
-int SRP_Calc_A_param(SSL *s);
-int SRP_generate_client_master_secret(SSL *s,unsigned char *master_key);
-
-#endif
-
-#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)
-#define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */
-#else
-#define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */
-#endif
-
-#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024*20)
-
-/* This callback type is used inside SSL_CTX, SSL, and in the functions that set
- * them. It is used to override the generation of SSL/TLS session IDs in a
- * server. Return value should be zero on an error, non-zero to proceed. Also,
- * callbacks should themselves check if the id they generate is unique otherwise
- * the SSL handshake will fail with an error - callbacks can do this using the
- * 'ssl' value they're passed by;
- * SSL_has_matching_session_id(ssl, id, *id_len)
- * The length value passed in is set at the maximum size the session ID can be.
- * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback
- * can alter this length to be less if desired, but under SSLv2 session IDs are
- * supposed to be fixed at 16 bytes so the id will be padded after the callback
- * returns in this case. It is also an error for the callback to set the size to
- * zero. */
-typedef int (*GEN_SESSION_CB)(const SSL *ssl, unsigned char *id,
- unsigned int *id_len);
-
-typedef struct ssl_comp_st SSL_COMP;
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-struct ssl_comp_st
- {
- int id;
- const char *name;
-#ifndef OPENSSL_NO_COMP
- COMP_METHOD *method;
-#else
- char *method;
-#endif
- };
-
-DECLARE_STACK_OF(SSL_COMP)
-DECLARE_LHASH_OF(SSL_SESSION);
-
-struct ssl_ctx_st
- {
- const SSL_METHOD *method;
-
- STACK_OF(SSL_CIPHER) *cipher_list;
- /* same as above but sorted for lookup */
- STACK_OF(SSL_CIPHER) *cipher_list_by_id;
-
- struct x509_store_st /* X509_STORE */ *cert_store;
- LHASH_OF(SSL_SESSION) *sessions;
- /* Most session-ids that will be cached, default is
- * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */
- unsigned long session_cache_size;
- struct ssl_session_st *session_cache_head;
- struct ssl_session_st *session_cache_tail;
-
- /* This can have one of 2 values, ored together,
- * SSL_SESS_CACHE_CLIENT,
- * SSL_SESS_CACHE_SERVER,
- * Default is SSL_SESSION_CACHE_SERVER, which means only
- * SSL_accept which cache SSL_SESSIONS. */
- int session_cache_mode;
-
- /* If timeout is not 0, it is the default timeout value set
- * when SSL_new() is called. This has been put in to make
- * life easier to set things up */
- long session_timeout;
-
- /* If this callback is not null, it will be called each
- * time a session id is added to the cache. If this function
- * returns 1, it means that the callback will do a
- * SSL_SESSION_free() when it has finished using it. Otherwise,
- * on 0, it means the callback has finished with it.
- * If remove_session_cb is not null, it will be called when
- * a session-id is removed from the cache. After the call,
- * OpenSSL will SSL_SESSION_free() it. */
- int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess);
- void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess);
- SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl,
- unsigned char *data,int len,int *copy);
-
- struct
- {
- int sess_connect; /* SSL new conn - started */
- int sess_connect_renegotiate;/* SSL reneg - requested */
- int sess_connect_good; /* SSL new conne/reneg - finished */
- int sess_accept; /* SSL new accept - started */
- int sess_accept_renegotiate;/* SSL reneg - requested */
- int sess_accept_good; /* SSL accept/reneg - finished */
- int sess_miss; /* session lookup misses */
- int sess_timeout; /* reuse attempt on timeouted session */
- int sess_cache_full; /* session removed due to full cache */
- int sess_hit; /* session reuse actually done */
- int sess_cb_hit; /* session-id that was not
- * in the cache was
- * passed back via the callback. This
- * indicates that the application is
- * supplying session-id's from other
- * processes - spooky :-) */
- } stats;
-
- int references;
-
- /* if defined, these override the X509_verify_cert() calls */
- int (*app_verify_callback)(X509_STORE_CTX *, void *);
- void *app_verify_arg;
- /* before OpenSSL 0.9.7, 'app_verify_arg' was ignored
- * ('app_verify_callback' was called with just one argument) */
-
- /* Default password callback. */
- pem_password_cb *default_passwd_callback;
-
- /* Default password callback user data. */
- void *default_passwd_callback_userdata;
-
- /* get client cert callback */
- int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
-
- /* cookie generate callback */
- int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie,
- unsigned int *cookie_len);
-
- /* verify cookie callback */
- int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie,
- unsigned int cookie_len);
-
- CRYPTO_EX_DATA ex_data;
-
- const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */
- const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */
- const EVP_MD *sha1; /* For SSLv3/TLSv1 'ssl3->sha1' */
-
- STACK_OF(X509) *extra_certs;
- STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */
-
-
- /* Default values used when no per-SSL value is defined follow */
-
- void (*info_callback)(const SSL *ssl,int type,int val); /* used if SSL's info_callback is NULL */
-
- /* what we put in client cert requests */
- STACK_OF(X509_NAME) *client_CA;
-
-
- /* Default values to use in SSL structures follow (these are copied by SSL_new) */
-
- unsigned long options;
- unsigned long mode;
- long max_cert_list;
-
- struct cert_st /* CERT */ *cert;
- int read_ahead;
-
- /* callback that allows applications to peek at protocol messages */
- void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
- void *msg_callback_arg;
-
- int verify_mode;
- unsigned int sid_ctx_length;
- unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
- int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */
-
- /* Default generate session ID callback. */
- GEN_SESSION_CB generate_session_id;
-
- X509_VERIFY_PARAM *param;
-
-#if 0
- int purpose; /* Purpose setting */
- int trust; /* Trust setting */
-#endif
-
- int quiet_shutdown;
-
- /* Maximum amount of data to send in one fragment.
- * actual record size can be more than this due to
- * padding and MAC overheads.
- */
- unsigned int max_send_fragment;
-
-#ifndef OPENSSL_NO_ENGINE
- /* Engine to pass requests for client certs to
- */
- ENGINE *client_cert_engine;
-#endif
-
-#ifndef OPENSSL_NO_TLSEXT
- /* TLS extensions servername callback */
- int (*tlsext_servername_callback)(SSL*, int *, void *);
- void *tlsext_servername_arg;
- /* RFC 4507 session ticket keys */
- unsigned char tlsext_tick_key_name[16];
- unsigned char tlsext_tick_hmac_key[16];
- unsigned char tlsext_tick_aes_key[16];
- /* Callback to support customisation of ticket key setting */
- int (*tlsext_ticket_key_cb)(SSL *ssl,
- unsigned char *name, unsigned char *iv,
- EVP_CIPHER_CTX *ectx,
- HMAC_CTX *hctx, int enc);
-
- /* certificate status request info */
- /* Callback for status request */
- int (*tlsext_status_cb)(SSL *ssl, void *arg);
- void *tlsext_status_arg;
-
- /* draft-rescorla-tls-opaque-prf-input-00.txt information */
- int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg);
- void *tlsext_opaque_prf_input_callback_arg;
-#endif
-
-#ifndef OPENSSL_NO_PSK
- char *psk_identity_hint;
- unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
- unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len);
- unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len);
-#endif
-
-#ifndef OPENSSL_NO_BUF_FREELISTS
-#define SSL_MAX_BUF_FREELIST_LEN_DEFAULT 32
- unsigned int freelist_max_len;
- struct ssl3_buf_freelist_st *wbuf_freelist;
- struct ssl3_buf_freelist_st *rbuf_freelist;
-#endif
-#ifndef OPENSSL_NO_SRP
- SRP_CTX srp_ctx; /* ctx for SRP authentication */
-#endif
-
-#ifndef OPENSSL_NO_TLSEXT
-
-# ifndef OPENSSL_NO_NEXTPROTONEG
- /* Next protocol negotiation information */
- /* (for experimental NPN extension). */
-
- /* For a server, this contains a callback function by which the set of
- * advertised protocols can be provided. */
- int (*next_protos_advertised_cb)(SSL *s, const unsigned char **buf,
- unsigned int *len, void *arg);
- void *next_protos_advertised_cb_arg;
- /* For a client, this contains a callback function that selects the
- * next protocol from the list provided by the server. */
- int (*next_proto_select_cb)(SSL *s, unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen,
- void *arg);
- void *next_proto_select_cb_arg;
-# endif
- /* SRTP profiles we are willing to do from RFC 5764 */
- STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
-#endif
- };
-
-#endif
-
-#define SSL_SESS_CACHE_OFF 0x0000
-#define SSL_SESS_CACHE_CLIENT 0x0001
-#define SSL_SESS_CACHE_SERVER 0x0002
-#define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER)
-#define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080
-/* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */
-#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100
-#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200
-#define SSL_SESS_CACHE_NO_INTERNAL \
- (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE)
-
-LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx);
-#define SSL_CTX_sess_number(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL)
-#define SSL_CTX_sess_connect(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL)
-#define SSL_CTX_sess_connect_good(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL)
-#define SSL_CTX_sess_connect_renegotiate(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL)
-#define SSL_CTX_sess_accept(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL)
-#define SSL_CTX_sess_accept_renegotiate(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL)
-#define SSL_CTX_sess_accept_good(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL)
-#define SSL_CTX_sess_hits(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL)
-#define SSL_CTX_sess_cb_hits(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL)
-#define SSL_CTX_sess_misses(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL)
-#define SSL_CTX_sess_timeouts(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL)
-#define SSL_CTX_sess_cache_full(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL)
-
-void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess));
-int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(struct ssl_st *ssl, SSL_SESSION *sess);
-void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess));
-void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(struct ssl_ctx_st *ctx, SSL_SESSION *sess);
-void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, unsigned char *data,int len,int *copy));
-SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(struct ssl_st *ssl, unsigned char *Data, int len, int *copy);
-void SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb)(const SSL *ssl,int type,int val));
-void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val);
-void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey));
-int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
-#ifndef OPENSSL_NO_ENGINE
-int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e);
-#endif
-void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len));
-void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len));
-#ifndef OPENSSL_NO_NEXTPROTONEG
-void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s,
- int (*cb) (SSL *ssl,
- const unsigned char **out,
- unsigned int *outlen,
- void *arg),
- void *arg);
-void SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
- int (*cb) (SSL *ssl,
- unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen,
- void *arg),
- void *arg);
-
-int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen,
- const unsigned char *client, unsigned int client_len);
-void SSL_get0_next_proto_negotiated(const SSL *s,
- const unsigned char **data, unsigned *len);
-
-#define OPENSSL_NPN_UNSUPPORTED 0
-#define OPENSSL_NPN_NEGOTIATED 1
-#define OPENSSL_NPN_NO_OVERLAP 2
-#endif
-
-#ifndef OPENSSL_NO_PSK
-/* the maximum length of the buffer given to callbacks containing the
- * resulting identity/psk */
-#define PSK_MAX_IDENTITY_LEN 128
-#define PSK_MAX_PSK_LEN 256
-void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx,
- unsigned int (*psk_client_callback)(SSL *ssl, const char *hint,
- char *identity, unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len));
-void SSL_set_psk_client_callback(SSL *ssl,
- unsigned int (*psk_client_callback)(SSL *ssl, const char *hint,
- char *identity, unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len));
-void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx,
- unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len));
-void SSL_set_psk_server_callback(SSL *ssl,
- unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len));
-int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint);
-int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint);
-const char *SSL_get_psk_identity_hint(const SSL *s);
-const char *SSL_get_psk_identity(const SSL *s);
-#endif
-
-#define SSL_NOTHING 1
-#define SSL_WRITING 2
-#define SSL_READING 3
-#define SSL_X509_LOOKUP 4
-
-/* These will only be used when doing non-blocking IO */
-#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING)
-#define SSL_want_read(s) (SSL_want(s) == SSL_READING)
-#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING)
-#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP)
-
-#define SSL_MAC_FLAG_READ_MAC_STREAM 1
-#define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-struct ssl_st
- {
- /* protocol version
- * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
- */
- int version;
- int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
-
- const SSL_METHOD *method; /* SSLv3 */
-
- /* There are 2 BIO's even though they are normally both the
- * same. This is so data can be read and written to different
- * handlers */
-
-#ifndef OPENSSL_NO_BIO
- BIO *rbio; /* used by SSL_read */
- BIO *wbio; /* used by SSL_write */
- BIO *bbio; /* used during session-id reuse to concatenate
- * messages */
-#else
- char *rbio; /* used by SSL_read */
- char *wbio; /* used by SSL_write */
- char *bbio;
-#endif
- /* This holds a variable that indicates what we were doing
- * when a 0 or -1 is returned. This is needed for
- * non-blocking IO so we know what request needs re-doing when
- * in SSL_accept or SSL_connect */
- int rwstate;
-
- /* true when we are actually in SSL_accept() or SSL_connect() */
- int in_handshake;
- int (*handshake_func)(SSL *);
-
- /* Imagine that here's a boolean member "init" that is
- * switched as soon as SSL_set_{accept/connect}_state
- * is called for the first time, so that "state" and
- * "handshake_func" are properly initialized. But as
- * handshake_func is == 0 until then, we use this
- * test instead of an "init" member.
- */
-
- int server; /* are we the server side? - mostly used by SSL_clear*/
-
- int new_session;/* Generate a new session or reuse an old one.
- * NB: For servers, the 'new' session may actually be a previously
- * cached session or even the previous session unless
- * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
- int quiet_shutdown;/* don't send shutdown packets */
- int shutdown; /* we have shut things down, 0x01 sent, 0x02
- * for received */
- int state; /* where we are */
- int rstate; /* where we are when reading */
-
- BUF_MEM *init_buf; /* buffer used during init */
- void *init_msg; /* pointer to handshake message body, set by ssl3_get_message() */
- int init_num; /* amount read/written */
- int init_off; /* amount read/written */
-
- /* used internally to point at a raw packet */
- unsigned char *packet;
- unsigned int packet_length;
-
- struct ssl2_state_st *s2; /* SSLv2 variables */
- struct ssl3_state_st *s3; /* SSLv3 variables */
- struct dtls1_state_st *d1; /* DTLSv1 variables */
-
- int read_ahead; /* Read as many input bytes as possible
- * (for non-blocking reads) */
-
- /* callback that allows applications to peek at protocol messages */
- void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
- void *msg_callback_arg;
-
- int hit; /* reusing a previous session */
-
- X509_VERIFY_PARAM *param;
-
-#if 0
- int purpose; /* Purpose setting */
- int trust; /* Trust setting */
-#endif
-
- /* crypto */
- STACK_OF(SSL_CIPHER) *cipher_list;
- STACK_OF(SSL_CIPHER) *cipher_list_by_id;
-
- /* These are the ones being used, the ones in SSL_SESSION are
- * the ones to be 'copied' into these ones */
- int mac_flags;
- EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
- EVP_MD_CTX *read_hash; /* used for mac generation */
-#ifndef OPENSSL_NO_COMP
- COMP_CTX *expand; /* uncompress */
-#else
- char *expand;
-#endif
-
- EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
- EVP_MD_CTX *write_hash; /* used for mac generation */
-#ifndef OPENSSL_NO_COMP
- COMP_CTX *compress; /* compression */
-#else
- char *compress;
-#endif
-
- /* session info */
-
- /* client cert? */
- /* This is used to hold the server certificate used */
- struct cert_st /* CERT */ *cert;
-
- /* the session_id_context is used to ensure sessions are only reused
- * in the appropriate context */
- unsigned int sid_ctx_length;
- unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
-
- /* This can also be in the session once a session is established */
- SSL_SESSION *session;
-
- /* Default generate session ID callback. */
- GEN_SESSION_CB generate_session_id;
-
- /* Used in SSL2 and SSL3 */
- int verify_mode; /* 0 don't care about verify failure.
- * 1 fail if verify fails */
- int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */
-
- void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */
-
- int error; /* error bytes to be written */
- int error_code; /* actual code */
-
-#ifndef OPENSSL_NO_KRB5
- KSSL_CTX *kssl_ctx; /* Kerberos 5 context */
-#endif /* OPENSSL_NO_KRB5 */
-
-#ifndef OPENSSL_NO_PSK
- unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
- unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len);
- unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len);
-#endif
-
- SSL_CTX *ctx;
- /* set this flag to 1 and a sleep(1) is put into all SSL_read()
- * and SSL_write() calls, good for nbio debuging :-) */
- int debug;
-
- /* extra application data */
- long verify_result;
- CRYPTO_EX_DATA ex_data;
-
- /* for server side, keep the list of CA_dn we can use */
- STACK_OF(X509_NAME) *client_CA;
-
- int references;
- unsigned long options; /* protocol behaviour */
- unsigned long mode; /* API behaviour */
- long max_cert_list;
- int first_packet;
- int client_version; /* what was passed, used for
- * SSLv3/TLS rollback check */
- unsigned int max_send_fragment;
-#ifndef OPENSSL_NO_TLSEXT
- /* TLS extension debug callback */
- void (*tlsext_debug_cb)(SSL *s, int client_server, int type,
- unsigned char *data, int len,
- void *arg);
- void *tlsext_debug_arg;
- char *tlsext_hostname;
- int servername_done; /* no further mod of servername
- 0 : call the servername extension callback.
- 1 : prepare 2, allow last ack just after in server callback.
- 2 : don't call servername callback, no ack in server hello
- */
- /* certificate status request info */
- /* Status type or -1 if no status type */
- int tlsext_status_type;
- /* Expect OCSP CertificateStatus message */
- int tlsext_status_expected;
- /* OCSP status request only */
- STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
- X509_EXTENSIONS *tlsext_ocsp_exts;
- /* OCSP response received or to be sent */
- unsigned char *tlsext_ocsp_resp;
- int tlsext_ocsp_resplen;
-
- /* RFC4507 session ticket expected to be received or sent */
- int tlsext_ticket_expected;
-#ifndef OPENSSL_NO_EC
- size_t tlsext_ecpointformatlist_length;
- unsigned char *tlsext_ecpointformatlist; /* our list */
- size_t tlsext_ellipticcurvelist_length;
- unsigned char *tlsext_ellipticcurvelist; /* our list */
-#endif /* OPENSSL_NO_EC */
-
- /* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */
- void *tlsext_opaque_prf_input;
- size_t tlsext_opaque_prf_input_len;
-
- /* TLS Session Ticket extension override */
- TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
-
- /* TLS Session Ticket extension callback */
- tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
- void *tls_session_ticket_ext_cb_arg;
-
- /* TLS pre-shared secret session resumption */
- tls_session_secret_cb_fn tls_session_secret_cb;
- void *tls_session_secret_cb_arg;
-
- SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- /* Next protocol negotiation. For the client, this is the protocol that
- * we sent in NextProtocol and is set when handling ServerHello
- * extensions.
- *
- * For a server, this is the client's selected_protocol from
- * NextProtocol and is set when handling the NextProtocol message,
- * before the Finished message. */
- unsigned char *next_proto_negotiated;
- unsigned char next_proto_negotiated_len;
-#endif
-
-#define session_ctx initial_ctx
-
- STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; /* What we'll do */
- SRTP_PROTECTION_PROFILE *srtp_profile; /* What's been chosen */
-
- unsigned int tlsext_heartbeat; /* Is use of the Heartbeat extension negotiated?
- 0: disabled
- 1: enabled
- 2: enabled, but not allowed to send Requests
- */
- unsigned int tlsext_hb_pending; /* Indicates if a HeartbeatRequest is in flight */
- unsigned int tlsext_hb_seq; /* HeartbeatRequest sequence number */
-#else
-#define session_ctx ctx
-#endif /* OPENSSL_NO_TLSEXT */
-
- int renegotiate;/* 1 if we are renegotiating.
- * 2 if we are a server and are inside a handshake
- * (i.e. not just sending a HelloRequest) */
-
-#ifndef OPENSSL_NO_SRP
- SRP_CTX srp_ctx; /* ctx for SRP authentication */
-#endif
- };
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#include <openssl/ssl2.h>
-#include <openssl/ssl3.h>
-#include <openssl/tls1.h> /* This is mostly sslv3 with a few tweaks */
-#include <openssl/dtls1.h> /* Datagram TLS */
-#include <openssl/ssl23.h>
-#include <openssl/srtp.h> /* Support for the use_srtp extension */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* compatibility */
-#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
-#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
-#define SSL_SESSION_set_app_data(s,a) (SSL_SESSION_set_ex_data(s,0,(char *)a))
-#define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s,0))
-#define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx,0))
-#define SSL_CTX_set_app_data(ctx,arg) (SSL_CTX_set_ex_data(ctx,0,(char *)arg))
-
-/* The following are the possible values for ssl->state are are
- * used to indicate where we are up to in the SSL connection establishment.
- * The macros that follow are about the only things you should need to use
- * and even then, only when using non-blocking IO.
- * It can also be useful to work out where you were when the connection
- * failed */
-
-#define SSL_ST_CONNECT 0x1000
-#define SSL_ST_ACCEPT 0x2000
-#define SSL_ST_MASK 0x0FFF
-#define SSL_ST_INIT (SSL_ST_CONNECT|SSL_ST_ACCEPT)
-#define SSL_ST_BEFORE 0x4000
-#define SSL_ST_OK 0x03
-#define SSL_ST_RENEGOTIATE (0x04|SSL_ST_INIT)
-
-#define SSL_CB_LOOP 0x01
-#define SSL_CB_EXIT 0x02
-#define SSL_CB_READ 0x04
-#define SSL_CB_WRITE 0x08
-#define SSL_CB_ALERT 0x4000 /* used in callback */
-#define SSL_CB_READ_ALERT (SSL_CB_ALERT|SSL_CB_READ)
-#define SSL_CB_WRITE_ALERT (SSL_CB_ALERT|SSL_CB_WRITE)
-#define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT|SSL_CB_LOOP)
-#define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT|SSL_CB_EXIT)
-#define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT|SSL_CB_LOOP)
-#define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT|SSL_CB_EXIT)
-#define SSL_CB_HANDSHAKE_START 0x10
-#define SSL_CB_HANDSHAKE_DONE 0x20
-
-/* Is the SSL_connection established? */
-#define SSL_get_state(a) SSL_state(a)
-#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK)
-#define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT)
-#define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE)
-#define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT)
-#define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT)
-
-/* The following 2 states are kept in ssl->rstate when reads fail,
- * you should not need these */
-#define SSL_ST_READ_HEADER 0xF0
-#define SSL_ST_READ_BODY 0xF1
-#define SSL_ST_READ_DONE 0xF2
-
-/* Obtain latest Finished message
- * -- that we sent (SSL_get_finished)
- * -- that we expected from peer (SSL_get_peer_finished).
- * Returns length (0 == no Finished so far), copies up to 'count' bytes. */
-size_t SSL_get_finished(const SSL *s, void *buf, size_t count);
-size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
-
-/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options
- * are 'ored' with SSL_VERIFY_PEER if they are desired */
-#define SSL_VERIFY_NONE 0x00
-#define SSL_VERIFY_PEER 0x01
-#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
-#define SSL_VERIFY_CLIENT_ONCE 0x04
-
-#define OpenSSL_add_ssl_algorithms() SSL_library_init()
-#define SSLeay_add_ssl_algorithms() SSL_library_init()
-
-/* this is for backward compatibility */
-#if 0 /* NEW_SSLEAY */
-#define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c)
-#define SSL_set_pref_cipher(c,n) SSL_set_cipher_list(c,n)
-#define SSL_add_session(a,b) SSL_CTX_add_session((a),(b))
-#define SSL_remove_session(a,b) SSL_CTX_remove_session((a),(b))
-#define SSL_flush_sessions(a,b) SSL_CTX_flush_sessions((a),(b))
-#endif
-/* More backward compatibility */
-#define SSL_get_cipher(s) \
- SSL_CIPHER_get_name(SSL_get_current_cipher(s))
-#define SSL_get_cipher_bits(s,np) \
- SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np)
-#define SSL_get_cipher_version(s) \
- SSL_CIPHER_get_version(SSL_get_current_cipher(s))
-#define SSL_get_cipher_name(s) \
- SSL_CIPHER_get_name(SSL_get_current_cipher(s))
-#define SSL_get_time(a) SSL_SESSION_get_time(a)
-#define SSL_set_time(a,b) SSL_SESSION_set_time((a),(b))
-#define SSL_get_timeout(a) SSL_SESSION_get_timeout(a)
-#define SSL_set_timeout(a,b) SSL_SESSION_set_timeout((a),(b))
-
-#define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id)
-#define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id)
-
-DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
-
-#define SSL_AD_REASON_OFFSET 1000 /* offset to get SSL_R_... value from SSL_AD_... */
-
-/* These alert types are for SSLv3 and TLSv1 */
-#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY
-#define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE /* fatal */
-#define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC /* fatal */
-#define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED
-#define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW
-#define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE/* fatal */
-#define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE/* fatal */
-#define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE /* Not for TLS */
-#define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE
-#define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE
-#define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED
-#define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED
-#define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN
-#define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER /* fatal */
-#define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA /* fatal */
-#define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED /* fatal */
-#define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR /* fatal */
-#define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR
-#define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION/* fatal */
-#define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION /* fatal */
-#define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY/* fatal */
-#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR /* fatal */
-#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED
-#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION
-#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION
-#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
-#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME
-#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE
-#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE
-#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */
-
-#define SSL_ERROR_NONE 0
-#define SSL_ERROR_SSL 1
-#define SSL_ERROR_WANT_READ 2
-#define SSL_ERROR_WANT_WRITE 3
-#define SSL_ERROR_WANT_X509_LOOKUP 4
-#define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */
-#define SSL_ERROR_ZERO_RETURN 6
-#define SSL_ERROR_WANT_CONNECT 7
-#define SSL_ERROR_WANT_ACCEPT 8
-
-#define SSL_CTRL_NEED_TMP_RSA 1
-#define SSL_CTRL_SET_TMP_RSA 2
-#define SSL_CTRL_SET_TMP_DH 3
-#define SSL_CTRL_SET_TMP_ECDH 4
-#define SSL_CTRL_SET_TMP_RSA_CB 5
-#define SSL_CTRL_SET_TMP_DH_CB 6
-#define SSL_CTRL_SET_TMP_ECDH_CB 7
-
-#define SSL_CTRL_GET_SESSION_REUSED 8
-#define SSL_CTRL_GET_CLIENT_CERT_REQUEST 9
-#define SSL_CTRL_GET_NUM_RENEGOTIATIONS 10
-#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11
-#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12
-#define SSL_CTRL_GET_FLAGS 13
-#define SSL_CTRL_EXTRA_CHAIN_CERT 14
-
-#define SSL_CTRL_SET_MSG_CALLBACK 15
-#define SSL_CTRL_SET_MSG_CALLBACK_ARG 16
-
-/* only applies to datagram connections */
-#define SSL_CTRL_SET_MTU 17
-/* Stats */
-#define SSL_CTRL_SESS_NUMBER 20
-#define SSL_CTRL_SESS_CONNECT 21
-#define SSL_CTRL_SESS_CONNECT_GOOD 22
-#define SSL_CTRL_SESS_CONNECT_RENEGOTIATE 23
-#define SSL_CTRL_SESS_ACCEPT 24
-#define SSL_CTRL_SESS_ACCEPT_GOOD 25
-#define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE 26
-#define SSL_CTRL_SESS_HIT 27
-#define SSL_CTRL_SESS_CB_HIT 28
-#define SSL_CTRL_SESS_MISSES 29
-#define SSL_CTRL_SESS_TIMEOUTS 30
-#define SSL_CTRL_SESS_CACHE_FULL 31
-#define SSL_CTRL_OPTIONS 32
-#define SSL_CTRL_MODE 33
-
-#define SSL_CTRL_GET_READ_AHEAD 40
-#define SSL_CTRL_SET_READ_AHEAD 41
-#define SSL_CTRL_SET_SESS_CACHE_SIZE 42
-#define SSL_CTRL_GET_SESS_CACHE_SIZE 43
-#define SSL_CTRL_SET_SESS_CACHE_MODE 44
-#define SSL_CTRL_GET_SESS_CACHE_MODE 45
-
-#define SSL_CTRL_GET_MAX_CERT_LIST 50
-#define SSL_CTRL_SET_MAX_CERT_LIST 51
-
-#define SSL_CTRL_SET_MAX_SEND_FRAGMENT 52
-
-/* see tls1.h for macros based on these */
-#ifndef OPENSSL_NO_TLSEXT
-#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
-#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
-#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
-#define SSL_CTRL_SET_TLSEXT_DEBUG_CB 56
-#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57
-#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58
-#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59
-#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60
-#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61
-#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71
-
-#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72
-
-#define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB 75
-#define SSL_CTRL_SET_SRP_VERIFY_PARAM_CB 76
-#define SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB 77
-
-#define SSL_CTRL_SET_SRP_ARG 78
-#define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME 79
-#define SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH 80
-#define SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD 81
-#ifndef OPENSSL_NO_HEARTBEATS
-#define SSL_CTRL_TLS_EXT_SEND_HEARTBEAT 85
-#define SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING 86
-#define SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS 87
-#endif
-#endif
-
-#define DTLS_CTRL_GET_TIMEOUT 73
-#define DTLS_CTRL_HANDLE_TIMEOUT 74
-#define DTLS_CTRL_LISTEN 75
-
-#define SSL_CTRL_GET_RI_SUPPORT 76
-#define SSL_CTRL_CLEAR_OPTIONS 77
-#define SSL_CTRL_CLEAR_MODE 78
-
-#define SSL_CTRL_GET_EXTRA_CHAIN_CERTS 82
-#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS 83
-
-#define DTLSv1_get_timeout(ssl, arg) \
- SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
-#define DTLSv1_handle_timeout(ssl) \
- SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL)
-#define DTLSv1_listen(ssl, peer) \
- SSL_ctrl(ssl,DTLS_CTRL_LISTEN,0, (void *)peer)
-
-#define SSL_session_reused(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
-#define SSL_num_renegotiations(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL)
-#define SSL_clear_num_renegotiations(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL)
-#define SSL_total_renegotiations(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL)
-
-#define SSL_CTX_need_tmp_RSA(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_NEED_TMP_RSA,0,NULL)
-#define SSL_CTX_set_tmp_rsa(ctx,rsa) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
-#define SSL_CTX_set_tmp_dh(ctx,dh) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
-#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
-
-#define SSL_need_tmp_RSA(ssl) \
- SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL)
-#define SSL_set_tmp_rsa(ssl,rsa) \
- SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
-#define SSL_set_tmp_dh(ssl,dh) \
- SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
-#define SSL_set_tmp_ecdh(ssl,ecdh) \
- SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
-
-#define SSL_CTX_add_extra_chain_cert(ctx,x509) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
-#define SSL_CTX_get_extra_chain_certs(ctx,px509) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_EXTRA_CHAIN_CERTS,0,px509)
-#define SSL_CTX_clear_extra_chain_certs(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS,0,NULL)
-
-#ifndef OPENSSL_NO_BIO
-BIO_METHOD *BIO_f_ssl(void);
-BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
-BIO *BIO_new_ssl_connect(SSL_CTX *ctx);
-BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx);
-int BIO_ssl_copy_session_id(BIO *to,BIO *from);
-void BIO_ssl_shutdown(BIO *ssl_bio);
-
-#endif
-
-int SSL_CTX_set_cipher_list(SSL_CTX *,const char *str);
-SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth);
-void SSL_CTX_free(SSL_CTX *);
-long SSL_CTX_set_timeout(SSL_CTX *ctx,long t);
-long SSL_CTX_get_timeout(const SSL_CTX *ctx);
-X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *);
-void SSL_CTX_set_cert_store(SSL_CTX *,X509_STORE *);
-int SSL_want(const SSL *s);
-int SSL_clear(SSL *s);
-
-void SSL_CTX_flush_sessions(SSL_CTX *ctx,long tm);
-
-const SSL_CIPHER *SSL_get_current_cipher(const SSL *s);
-int SSL_CIPHER_get_bits(const SSL_CIPHER *c,int *alg_bits);
-char * SSL_CIPHER_get_version(const SSL_CIPHER *c);
-const char * SSL_CIPHER_get_name(const SSL_CIPHER *c);
-unsigned long SSL_CIPHER_get_id(const SSL_CIPHER *c);
-
-int SSL_get_fd(const SSL *s);
-int SSL_get_rfd(const SSL *s);
-int SSL_get_wfd(const SSL *s);
-const char * SSL_get_cipher_list(const SSL *s,int n);
-char * SSL_get_shared_ciphers(const SSL *s, char *buf, int len);
-int SSL_get_read_ahead(const SSL * s);
-int SSL_pending(const SSL *s);
-#ifndef OPENSSL_NO_SOCK
-int SSL_set_fd(SSL *s, int fd);
-int SSL_set_rfd(SSL *s, int fd);
-int SSL_set_wfd(SSL *s, int fd);
-#endif
-#ifndef OPENSSL_NO_BIO
-void SSL_set_bio(SSL *s, BIO *rbio,BIO *wbio);
-BIO * SSL_get_rbio(const SSL *s);
-BIO * SSL_get_wbio(const SSL *s);
-#endif
-int SSL_set_cipher_list(SSL *s, const char *str);
-void SSL_set_read_ahead(SSL *s, int yes);
-int SSL_get_verify_mode(const SSL *s);
-int SSL_get_verify_depth(const SSL *s);
-int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *);
-void SSL_set_verify(SSL *s, int mode,
- int (*callback)(int ok,X509_STORE_CTX *ctx));
-void SSL_set_verify_depth(SSL *s, int depth);
-#ifndef OPENSSL_NO_RSA
-int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa);
-#endif
-int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len);
-int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey);
-int SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len);
-int SSL_use_certificate(SSL *ssl, X509 *x);
-int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
-
-#ifndef OPENSSL_NO_STDIO
-int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
-int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type);
-int SSL_use_certificate_file(SSL *ssl, const char *file, int type);
-int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type);
-int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
-int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
-int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); /* PEM type */
-STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file);
-int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
- const char *file);
-#ifndef OPENSSL_SYS_VMS
-#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! [was: #ifndef MAC_OS_pre_X] */
-int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
- const char *dir);
-#endif
-#endif
-
-#endif
-
-void SSL_load_error_strings(void );
-const char *SSL_state_string(const SSL *s);
-const char *SSL_rstate_string(const SSL *s);
-const char *SSL_state_string_long(const SSL *s);
-const char *SSL_rstate_string_long(const SSL *s);
-long SSL_SESSION_get_time(const SSL_SESSION *s);
-long SSL_SESSION_set_time(SSL_SESSION *s, long t);
-long SSL_SESSION_get_timeout(const SSL_SESSION *s);
-long SSL_SESSION_set_timeout(SSL_SESSION *s, long t);
-void SSL_copy_session_id(SSL *to,const SSL *from);
-X509 *SSL_SESSION_get0_peer(SSL_SESSION *s);
-int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx,
- unsigned int sid_ctx_len);
-
-SSL_SESSION *SSL_SESSION_new(void);
-const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s,
- unsigned int *len);
-unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s);
-#ifndef OPENSSL_NO_FP_API
-int SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses);
-#endif
-#ifndef OPENSSL_NO_BIO
-int SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses);
-#endif
-void SSL_SESSION_free(SSL_SESSION *ses);
-int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp);
-int SSL_set_session(SSL *to, SSL_SESSION *session);
-int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c);
-int SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c);
-int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB);
-int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB);
-int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
- unsigned int id_len);
-SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp,
- long length);
-
-#ifdef HEADER_X509_H
-X509 * SSL_get_peer_certificate(const SSL *s);
-#endif
-
-STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s);
-
-int SSL_CTX_get_verify_mode(const SSL_CTX *ctx);
-int SSL_CTX_get_verify_depth(const SSL_CTX *ctx);
-int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *);
-void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,
- int (*callback)(int, X509_STORE_CTX *));
-void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth);
-void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg);
-#ifndef OPENSSL_NO_RSA
-int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa);
-#endif
-int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len);
-int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
-int SSL_CTX_use_PrivateKey_ASN1(int pk,SSL_CTX *ctx,
- const unsigned char *d, long len);
-int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);
-int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d);
-
-void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb);
-void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u);
-
-int SSL_CTX_check_private_key(const SSL_CTX *ctx);
-int SSL_check_private_key(const SSL *ctx);
-
-int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
- unsigned int sid_ctx_len);
-
-SSL * SSL_new(SSL_CTX *ctx);
-int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
- unsigned int sid_ctx_len);
-
-int SSL_CTX_set_purpose(SSL_CTX *s, int purpose);
-int SSL_set_purpose(SSL *s, int purpose);
-int SSL_CTX_set_trust(SSL_CTX *s, int trust);
-int SSL_set_trust(SSL *s, int trust);
-
-int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm);
-int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm);
-
-#ifndef OPENSSL_NO_SRP
-int SSL_CTX_set_srp_username(SSL_CTX *ctx,char *name);
-int SSL_CTX_set_srp_password(SSL_CTX *ctx,char *password);
-int SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength);
-int SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx,
- char *(*cb)(SSL *,void *));
-int SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx,
- int (*cb)(SSL *,void *));
-int SSL_CTX_set_srp_username_callback(SSL_CTX *ctx,
- int (*cb)(SSL *,int *,void *));
-int SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg);
-
-int SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g,
- BIGNUM *sa, BIGNUM *v, char *info);
-int SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass,
- const char *grp);
-
-BIGNUM *SSL_get_srp_g(SSL *s);
-BIGNUM *SSL_get_srp_N(SSL *s);
-
-char *SSL_get_srp_username(SSL *s);
-char *SSL_get_srp_userinfo(SSL *s);
-#endif
-
-void SSL_free(SSL *ssl);
-int SSL_accept(SSL *ssl);
-int SSL_connect(SSL *ssl);
-int SSL_read(SSL *ssl,void *buf,int num);
-int SSL_peek(SSL *ssl,void *buf,int num);
-int SSL_write(SSL *ssl,const void *buf,int num);
-long SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
-long SSL_callback_ctrl(SSL *, int, void (*)(void));
-long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, void *parg);
-long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void));
-
-int SSL_get_error(const SSL *s,int ret_code);
-const char *SSL_get_version(const SSL *s);
-
-/* This sets the 'default' SSL version that SSL_new() will create */
-int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth);
-
-#ifndef OPENSSL_NO_SSL2
-const SSL_METHOD *SSLv2_method(void); /* SSLv2 */
-const SSL_METHOD *SSLv2_server_method(void); /* SSLv2 */
-const SSL_METHOD *SSLv2_client_method(void); /* SSLv2 */
-#endif
-
-const SSL_METHOD *SSLv3_method(void); /* SSLv3 */
-const SSL_METHOD *SSLv3_server_method(void); /* SSLv3 */
-const SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */
-
-const SSL_METHOD *SSLv23_method(void); /* SSLv3 but can rollback to v2 */
-const SSL_METHOD *SSLv23_server_method(void); /* SSLv3 but can rollback to v2 */
-const SSL_METHOD *SSLv23_client_method(void); /* SSLv3 but can rollback to v2 */
-
-const SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */
-const SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */
-const SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */
-
-const SSL_METHOD *TLSv1_1_method(void); /* TLSv1.1 */
-const SSL_METHOD *TLSv1_1_server_method(void); /* TLSv1.1 */
-const SSL_METHOD *TLSv1_1_client_method(void); /* TLSv1.1 */
-
-const SSL_METHOD *TLSv1_2_method(void); /* TLSv1.2 */
-const SSL_METHOD *TLSv1_2_server_method(void); /* TLSv1.2 */
-const SSL_METHOD *TLSv1_2_client_method(void); /* TLSv1.2 */
-
-
-const SSL_METHOD *DTLSv1_method(void); /* DTLSv1.0 */
-const SSL_METHOD *DTLSv1_server_method(void); /* DTLSv1.0 */
-const SSL_METHOD *DTLSv1_client_method(void); /* DTLSv1.0 */
-
-STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
-
-int SSL_do_handshake(SSL *s);
-int SSL_renegotiate(SSL *s);
-int SSL_renegotiate_abbreviated(SSL *s);
-int SSL_renegotiate_pending(SSL *s);
-int SSL_shutdown(SSL *s);
-
-const SSL_METHOD *SSL_get_ssl_method(SSL *s);
-int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method);
-const char *SSL_alert_type_string_long(int value);
-const char *SSL_alert_type_string(int value);
-const char *SSL_alert_desc_string_long(int value);
-const char *SSL_alert_desc_string(int value);
-
-void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list);
-void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list);
-STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s);
-STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s);
-int SSL_add_client_CA(SSL *ssl,X509 *x);
-int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x);
-
-void SSL_set_connect_state(SSL *s);
-void SSL_set_accept_state(SSL *s);
-
-long SSL_get_default_timeout(const SSL *s);
-
-int SSL_library_init(void );
-
-char *SSL_CIPHER_description(const SSL_CIPHER *,char *buf,int size);
-STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk);
-
-SSL *SSL_dup(SSL *ssl);
-
-X509 *SSL_get_certificate(const SSL *ssl);
-/* EVP_PKEY */ struct evp_pkey_st *SSL_get_privatekey(SSL *ssl);
-
-void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode);
-int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx);
-void SSL_set_quiet_shutdown(SSL *ssl,int mode);
-int SSL_get_quiet_shutdown(const SSL *ssl);
-void SSL_set_shutdown(SSL *ssl,int mode);
-int SSL_get_shutdown(const SSL *ssl);
-int SSL_version(const SSL *ssl);
-int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx);
-int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
- const char *CApath);
-#define SSL_get0_session SSL_get_session /* just peek at pointer */
-SSL_SESSION *SSL_get_session(const SSL *ssl);
-SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */
-SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl);
-SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx);
-void SSL_set_info_callback(SSL *ssl,
- void (*cb)(const SSL *ssl,int type,int val));
-void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl,int type,int val);
-int SSL_state(const SSL *ssl);
-void SSL_set_state(SSL *ssl, int state);
-
-void SSL_set_verify_result(SSL *ssl,long v);
-long SSL_get_verify_result(const SSL *ssl);
-
-int SSL_set_ex_data(SSL *ssl,int idx,void *data);
-void *SSL_get_ex_data(const SSL *ssl,int idx);
-int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-
-int SSL_SESSION_set_ex_data(SSL_SESSION *ss,int idx,void *data);
-void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss,int idx);
-int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-
-int SSL_CTX_set_ex_data(SSL_CTX *ssl,int idx,void *data);
-void *SSL_CTX_get_ex_data(const SSL_CTX *ssl,int idx);
-int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-
-int SSL_get_ex_data_X509_STORE_CTX_idx(void );
-
-#define SSL_CTX_sess_set_cache_size(ctx,t) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL)
-#define SSL_CTX_sess_get_cache_size(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL)
-#define SSL_CTX_set_session_cache_mode(ctx,m) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
-#define SSL_CTX_get_session_cache_mode(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL)
-
-#define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx)
-#define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m)
-#define SSL_CTX_get_read_ahead(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL)
-#define SSL_CTX_set_read_ahead(ctx,m) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL)
-#define SSL_CTX_get_max_cert_list(ctx) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
-#define SSL_CTX_set_max_cert_list(ctx,m) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
-#define SSL_get_max_cert_list(ssl) \
- SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
-#define SSL_set_max_cert_list(ssl,m) \
- SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
-
-#define SSL_CTX_set_max_send_fragment(ctx,m) \
- SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
-#define SSL_set_max_send_fragment(ssl,m) \
- SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
-
- /* NB: the keylength is only applicable when is_export is true */
-#ifndef OPENSSL_NO_RSA
-void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,
- RSA *(*cb)(SSL *ssl,int is_export,
- int keylength));
-
-void SSL_set_tmp_rsa_callback(SSL *ssl,
- RSA *(*cb)(SSL *ssl,int is_export,
- int keylength));
-#endif
-#ifndef OPENSSL_NO_DH
-void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
- DH *(*dh)(SSL *ssl,int is_export,
- int keylength));
-void SSL_set_tmp_dh_callback(SSL *ssl,
- DH *(*dh)(SSL *ssl,int is_export,
- int keylength));
-#endif
-#ifndef OPENSSL_NO_ECDH
-void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,
- EC_KEY *(*ecdh)(SSL *ssl,int is_export,
- int keylength));
-void SSL_set_tmp_ecdh_callback(SSL *ssl,
- EC_KEY *(*ecdh)(SSL *ssl,int is_export,
- int keylength));
-#endif
-
-#ifndef OPENSSL_NO_COMP
-const COMP_METHOD *SSL_get_current_compression(SSL *s);
-const COMP_METHOD *SSL_get_current_expansion(SSL *s);
-const char *SSL_COMP_get_name(const COMP_METHOD *comp);
-STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void);
-int SSL_COMP_add_compression_method(int id,COMP_METHOD *cm);
-#else
-const void *SSL_get_current_compression(SSL *s);
-const void *SSL_get_current_expansion(SSL *s);
-const char *SSL_COMP_get_name(const void *comp);
-void *SSL_COMP_get_compression_methods(void);
-int SSL_COMP_add_compression_method(int id,void *cm);
-#endif
-
-/* TLS extensions functions */
-int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
-
-int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
- void *arg);
-
-/* Pre-shared secret session resumption functions */
-int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-
-void SSL_set_debug(SSL *s, int debug);
-int SSL_cache_hit(SSL *s);
-
-/* BEGIN ERROR CODES */
-/* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_SSL_strings(void);
-
-/* Error codes for the SSL functions. */
-
-/* Function codes. */
-#define SSL_F_CLIENT_CERTIFICATE 100
-#define SSL_F_CLIENT_FINISHED 167
-#define SSL_F_CLIENT_HELLO 101
-#define SSL_F_CLIENT_MASTER_KEY 102
-#define SSL_F_D2I_SSL_SESSION 103
-#define SSL_F_DO_DTLS1_WRITE 245
-#define SSL_F_DO_SSL3_WRITE 104
-#define SSL_F_DTLS1_ACCEPT 246
-#define SSL_F_DTLS1_ADD_CERT_TO_BUF 295
-#define SSL_F_DTLS1_BUFFER_RECORD 247
-#define SSL_F_DTLS1_CHECK_TIMEOUT_NUM 316
-#define SSL_F_DTLS1_CLIENT_HELLO 248
-#define SSL_F_DTLS1_CONNECT 249
-#define SSL_F_DTLS1_ENC 250
-#define SSL_F_DTLS1_GET_HELLO_VERIFY 251
-#define SSL_F_DTLS1_GET_MESSAGE 252
-#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253
-#define SSL_F_DTLS1_GET_RECORD 254
-#define SSL_F_DTLS1_HANDLE_TIMEOUT 297
-#define SSL_F_DTLS1_HEARTBEAT 305
-#define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255
-#define SSL_F_DTLS1_PREPROCESS_FRAGMENT 288
-#define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256
-#define SSL_F_DTLS1_PROCESS_RECORD 257
-#define SSL_F_DTLS1_READ_BYTES 258
-#define SSL_F_DTLS1_READ_FAILED 259
-#define SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST 260
-#define SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE 261
-#define SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE 262
-#define SSL_F_DTLS1_SEND_CLIENT_VERIFY 263
-#define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST 264
-#define SSL_F_DTLS1_SEND_SERVER_CERTIFICATE 265
-#define SSL_F_DTLS1_SEND_SERVER_HELLO 266
-#define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE 267
-#define SSL_F_DTLS1_WRITE_APP_DATA_BYTES 268
-#define SSL_F_GET_CLIENT_FINISHED 105
-#define SSL_F_GET_CLIENT_HELLO 106
-#define SSL_F_GET_CLIENT_MASTER_KEY 107
-#define SSL_F_GET_SERVER_FINISHED 108
-#define SSL_F_GET_SERVER_HELLO 109
-#define SSL_F_GET_SERVER_VERIFY 110
-#define SSL_F_I2D_SSL_SESSION 111
-#define SSL_F_READ_N 112
-#define SSL_F_REQUEST_CERTIFICATE 113
-#define SSL_F_SERVER_FINISH 239
-#define SSL_F_SERVER_HELLO 114
-#define SSL_F_SERVER_VERIFY 240
-#define SSL_F_SSL23_ACCEPT 115
-#define SSL_F_SSL23_CLIENT_HELLO 116
-#define SSL_F_SSL23_CONNECT 117
-#define SSL_F_SSL23_GET_CLIENT_HELLO 118
-#define SSL_F_SSL23_GET_SERVER_HELLO 119
-#define SSL_F_SSL23_PEEK 237
-#define SSL_F_SSL23_READ 120
-#define SSL_F_SSL23_WRITE 121
-#define SSL_F_SSL2_ACCEPT 122
-#define SSL_F_SSL2_CONNECT 123
-#define SSL_F_SSL2_ENC_INIT 124
-#define SSL_F_SSL2_GENERATE_KEY_MATERIAL 241
-#define SSL_F_SSL2_PEEK 234
-#define SSL_F_SSL2_READ 125
-#define SSL_F_SSL2_READ_INTERNAL 236
-#define SSL_F_SSL2_SET_CERTIFICATE 126
-#define SSL_F_SSL2_WRITE 127
-#define SSL_F_SSL3_ACCEPT 128
-#define SSL_F_SSL3_ADD_CERT_TO_BUF 296
-#define SSL_F_SSL3_CALLBACK_CTRL 233
-#define SSL_F_SSL3_CHANGE_CIPHER_STATE 129
-#define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130
-#define SSL_F_SSL3_CHECK_CLIENT_HELLO 304
-#define SSL_F_SSL3_CLIENT_HELLO 131
-#define SSL_F_SSL3_CONNECT 132
-#define SSL_F_SSL3_CTRL 213
-#define SSL_F_SSL3_CTX_CTRL 133
-#define SSL_F_SSL3_DIGEST_CACHED_RECORDS 293
-#define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC 292
-#define SSL_F_SSL3_ENC 134
-#define SSL_F_SSL3_GENERATE_KEY_BLOCK 238
-#define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135
-#define SSL_F_SSL3_GET_CERT_STATUS 289
-#define SSL_F_SSL3_GET_CERT_VERIFY 136
-#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137
-#define SSL_F_SSL3_GET_CLIENT_HELLO 138
-#define SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE 139
-#define SSL_F_SSL3_GET_FINISHED 140
-#define SSL_F_SSL3_GET_KEY_EXCHANGE 141
-#define SSL_F_SSL3_GET_MESSAGE 142
-#define SSL_F_SSL3_GET_NEW_SESSION_TICKET 283
-#define SSL_F_SSL3_GET_NEXT_PROTO 306
-#define SSL_F_SSL3_GET_RECORD 143
-#define SSL_F_SSL3_GET_SERVER_CERTIFICATE 144
-#define SSL_F_SSL3_GET_SERVER_DONE 145
-#define SSL_F_SSL3_GET_SERVER_HELLO 146
-#define SSL_F_SSL3_HANDSHAKE_MAC 285
-#define SSL_F_SSL3_NEW_SESSION_TICKET 287
-#define SSL_F_SSL3_OUTPUT_CERT_CHAIN 147
-#define SSL_F_SSL3_PEEK 235
-#define SSL_F_SSL3_READ_BYTES 148
-#define SSL_F_SSL3_READ_N 149
-#define SSL_F_SSL3_SEND_CERTIFICATE_REQUEST 150
-#define SSL_F_SSL3_SEND_CLIENT_CERTIFICATE 151
-#define SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE 152
-#define SSL_F_SSL3_SEND_CLIENT_VERIFY 153
-#define SSL_F_SSL3_SEND_SERVER_CERTIFICATE 154
-#define SSL_F_SSL3_SEND_SERVER_HELLO 242
-#define SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE 155
-#define SSL_F_SSL3_SETUP_KEY_BLOCK 157
-#define SSL_F_SSL3_SETUP_READ_BUFFER 156
-#define SSL_F_SSL3_SETUP_WRITE_BUFFER 291
-#define SSL_F_SSL3_WRITE_BYTES 158
-#define SSL_F_SSL3_WRITE_PENDING 159
-#define SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT 298
-#define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 277
-#define SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT 307
-#define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215
-#define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216
-#define SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT 299
-#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 278
-#define SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT 308
-#define SSL_F_SSL_BAD_METHOD 160
-#define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161
-#define SSL_F_SSL_CERT_DUP 221
-#define SSL_F_SSL_CERT_INST 222
-#define SSL_F_SSL_CERT_INSTANTIATE 214
-#define SSL_F_SSL_CERT_NEW 162
-#define SSL_F_SSL_CHECK_PRIVATE_KEY 163
-#define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 280
-#define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG 279
-#define SSL_F_SSL_CIPHER_PROCESS_RULESTR 230
-#define SSL_F_SSL_CIPHER_STRENGTH_SORT 231
-#define SSL_F_SSL_CLEAR 164
-#define SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD 165
-#define SSL_F_SSL_CREATE_CIPHER_LIST 166
-#define SSL_F_SSL_CTRL 232
-#define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY 168
-#define SSL_F_SSL_CTX_MAKE_PROFILES 309
-#define SSL_F_SSL_CTX_NEW 169
-#define SSL_F_SSL_CTX_SET_CIPHER_LIST 269
-#define SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE 290
-#define SSL_F_SSL_CTX_SET_PURPOSE 226
-#define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219
-#define SSL_F_SSL_CTX_SET_SSL_VERSION 170
-#define SSL_F_SSL_CTX_SET_TRUST 229
-#define SSL_F_SSL_CTX_USE_CERTIFICATE 171
-#define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172
-#define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE 220
-#define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173
-#define SSL_F_SSL_CTX_USE_PRIVATEKEY 174
-#define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175
-#define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE 176
-#define SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT 272
-#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY 177
-#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1 178
-#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179
-#define SSL_F_SSL_DO_HANDSHAKE 180
-#define SSL_F_SSL_GET_NEW_SESSION 181
-#define SSL_F_SSL_GET_PREV_SESSION 217
-#define SSL_F_SSL_GET_SERVER_SEND_CERT 182
-#define SSL_F_SSL_GET_SERVER_SEND_PKEY 317
-#define SSL_F_SSL_GET_SIGN_PKEY 183
-#define SSL_F_SSL_INIT_WBIO_BUFFER 184
-#define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185
-#define SSL_F_SSL_NEW 186
-#define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 300
-#define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 302
-#define SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT 310
-#define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 301
-#define SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT 303
-#define SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT 311
-#define SSL_F_SSL_PEEK 270
-#define SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT 281
-#define SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT 282
-#define SSL_F_SSL_READ 223
-#define SSL_F_SSL_RSA_PRIVATE_DECRYPT 187
-#define SSL_F_SSL_RSA_PUBLIC_ENCRYPT 188
-#define SSL_F_SSL_SESSION_NEW 189
-#define SSL_F_SSL_SESSION_PRINT_FP 190
-#define SSL_F_SSL_SESSION_SET1_ID_CONTEXT 312
-#define SSL_F_SSL_SESS_CERT_NEW 225
-#define SSL_F_SSL_SET_CERT 191
-#define SSL_F_SSL_SET_CIPHER_LIST 271
-#define SSL_F_SSL_SET_FD 192
-#define SSL_F_SSL_SET_PKEY 193
-#define SSL_F_SSL_SET_PURPOSE 227
-#define SSL_F_SSL_SET_RFD 194
-#define SSL_F_SSL_SET_SESSION 195
-#define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218
-#define SSL_F_SSL_SET_SESSION_TICKET_EXT 294
-#define SSL_F_SSL_SET_TRUST 228
-#define SSL_F_SSL_SET_WFD 196
-#define SSL_F_SSL_SHUTDOWN 224
-#define SSL_F_SSL_SRP_CTX_INIT 313
-#define SSL_F_SSL_UNDEFINED_CONST_FUNCTION 243
-#define SSL_F_SSL_UNDEFINED_FUNCTION 197
-#define SSL_F_SSL_UNDEFINED_VOID_FUNCTION 244
-#define SSL_F_SSL_USE_CERTIFICATE 198
-#define SSL_F_SSL_USE_CERTIFICATE_ASN1 199
-#define SSL_F_SSL_USE_CERTIFICATE_FILE 200
-#define SSL_F_SSL_USE_PRIVATEKEY 201
-#define SSL_F_SSL_USE_PRIVATEKEY_ASN1 202
-#define SSL_F_SSL_USE_PRIVATEKEY_FILE 203
-#define SSL_F_SSL_USE_PSK_IDENTITY_HINT 273
-#define SSL_F_SSL_USE_RSAPRIVATEKEY 204
-#define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1 205
-#define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206
-#define SSL_F_SSL_VERIFY_CERT_CHAIN 207
-#define SSL_F_SSL_WRITE 208
-#define SSL_F_TLS1_CERT_VERIFY_MAC 286
-#define SSL_F_TLS1_CHANGE_CIPHER_STATE 209
-#define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274
-#define SSL_F_TLS1_ENC 210
-#define SSL_F_TLS1_EXPORT_KEYING_MATERIAL 314
-#define SSL_F_TLS1_HEARTBEAT 315
-#define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT 275
-#define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT 276
-#define SSL_F_TLS1_PRF 284
-#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
-#define SSL_F_WRITE_PENDING 212
-
-/* Reason codes. */
-#define SSL_R_APP_DATA_IN_HANDSHAKE 100
-#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
-#define SSL_R_BAD_ALERT_RECORD 101
-#define SSL_R_BAD_AUTHENTICATION_TYPE 102
-#define SSL_R_BAD_CHANGE_CIPHER_SPEC 103
-#define SSL_R_BAD_CHECKSUM 104
-#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106
-#define SSL_R_BAD_DECOMPRESSION 107
-#define SSL_R_BAD_DH_G_LENGTH 108
-#define SSL_R_BAD_DH_PUB_KEY_LENGTH 109
-#define SSL_R_BAD_DH_P_LENGTH 110
-#define SSL_R_BAD_DIGEST_LENGTH 111
-#define SSL_R_BAD_DSA_SIGNATURE 112
-#define SSL_R_BAD_ECC_CERT 304
-#define SSL_R_BAD_ECDSA_SIGNATURE 305
-#define SSL_R_BAD_ECPOINT 306
-#define SSL_R_BAD_HANDSHAKE_LENGTH 332
-#define SSL_R_BAD_HELLO_REQUEST 105
-#define SSL_R_BAD_LENGTH 271
-#define SSL_R_BAD_MAC_DECODE 113
-#define SSL_R_BAD_MAC_LENGTH 333
-#define SSL_R_BAD_MESSAGE_TYPE 114
-#define SSL_R_BAD_PACKET_LENGTH 115
-#define SSL_R_BAD_PROTOCOL_VERSION_NUMBER 116
-#define SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH 316
-#define SSL_R_BAD_RESPONSE_ARGUMENT 117
-#define SSL_R_BAD_RSA_DECRYPT 118
-#define SSL_R_BAD_RSA_ENCRYPT 119
-#define SSL_R_BAD_RSA_E_LENGTH 120
-#define SSL_R_BAD_RSA_MODULUS_LENGTH 121
-#define SSL_R_BAD_RSA_SIGNATURE 122
-#define SSL_R_BAD_SIGNATURE 123
-#define SSL_R_BAD_SRP_A_LENGTH 347
-#define SSL_R_BAD_SRP_B_LENGTH 348
-#define SSL_R_BAD_SRP_G_LENGTH 349
-#define SSL_R_BAD_SRP_N_LENGTH 350
-#define SSL_R_BAD_SRP_S_LENGTH 351
-#define SSL_R_BAD_SRTP_MKI_VALUE 352
-#define SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST 353
-#define SSL_R_BAD_SSL_FILETYPE 124
-#define SSL_R_BAD_SSL_SESSION_ID_LENGTH 125
-#define SSL_R_BAD_STATE 126
-#define SSL_R_BAD_WRITE_RETRY 127
-#define SSL_R_BIO_NOT_SET 128
-#define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 129
-#define SSL_R_BN_LIB 130
-#define SSL_R_CA_DN_LENGTH_MISMATCH 131
-#define SSL_R_CA_DN_TOO_LONG 132
-#define SSL_R_CCS_RECEIVED_EARLY 133
-#define SSL_R_CERTIFICATE_VERIFY_FAILED 134
-#define SSL_R_CERT_LENGTH_MISMATCH 135
-#define SSL_R_CHALLENGE_IS_DIFFERENT 136
-#define SSL_R_CIPHER_CODE_WRONG_LENGTH 137
-#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 138
-#define SSL_R_CIPHER_TABLE_SRC_ERROR 139
-#define SSL_R_CLIENTHELLO_TLSEXT 226
-#define SSL_R_COMPRESSED_LENGTH_TOO_LONG 140
-#define SSL_R_COMPRESSION_DISABLED 343
-#define SSL_R_COMPRESSION_FAILURE 141
-#define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307
-#define SSL_R_COMPRESSION_LIBRARY_ERROR 142
-#define SSL_R_CONNECTION_ID_IS_DIFFERENT 143
-#define SSL_R_CONNECTION_TYPE_NOT_SET 144
-#define SSL_R_COOKIE_MISMATCH 308
-#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145
-#define SSL_R_DATA_LENGTH_TOO_LONG 146
-#define SSL_R_DECRYPTION_FAILED 147
-#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281
-#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148
-#define SSL_R_DIGEST_CHECK_FAILED 149
-#define SSL_R_DTLS_MESSAGE_TOO_BIG 334
-#define SSL_R_DUPLICATE_COMPRESSION_ID 309
-#define SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT 317
-#define SSL_R_ECC_CERT_NOT_FOR_SIGNING 318
-#define SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE 322
-#define SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE 323
-#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310
-#define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354
-#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150
-#define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 282
-#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151
-#define SSL_R_EXCESSIVE_MESSAGE_SIZE 152
-#define SSL_R_EXTRA_DATA_IN_MESSAGE 153
-#define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154
-#define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 355
-#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 356
-#define SSL_R_HTTPS_PROXY_REQUEST 155
-#define SSL_R_HTTP_REQUEST 156
-#define SSL_R_ILLEGAL_PADDING 283
-#define SSL_R_INCONSISTENT_COMPRESSION 340
-#define SSL_R_INVALID_CHALLENGE_LENGTH 158
-#define SSL_R_INVALID_COMMAND 280
-#define SSL_R_INVALID_COMPRESSION_ALGORITHM 341
-#define SSL_R_INVALID_PURPOSE 278
-#define SSL_R_INVALID_SRP_USERNAME 357
-#define SSL_R_INVALID_STATUS_RESPONSE 328
-#define SSL_R_INVALID_TICKET_KEYS_LENGTH 325
-#define SSL_R_INVALID_TRUST 279
-#define SSL_R_KEY_ARG_TOO_LONG 284
-#define SSL_R_KRB5 285
-#define SSL_R_KRB5_C_CC_PRINC 286
-#define SSL_R_KRB5_C_GET_CRED 287
-#define SSL_R_KRB5_C_INIT 288
-#define SSL_R_KRB5_C_MK_REQ 289
-#define SSL_R_KRB5_S_BAD_TICKET 290
-#define SSL_R_KRB5_S_INIT 291
-#define SSL_R_KRB5_S_RD_REQ 292
-#define SSL_R_KRB5_S_TKT_EXPIRED 293
-#define SSL_R_KRB5_S_TKT_NYV 294
-#define SSL_R_KRB5_S_TKT_SKEW 295
-#define SSL_R_LENGTH_MISMATCH 159
-#define SSL_R_LENGTH_TOO_SHORT 160
-#define SSL_R_LIBRARY_BUG 274
-#define SSL_R_LIBRARY_HAS_NO_CIPHERS 161
-#define SSL_R_MESSAGE_TOO_LONG 296
-#define SSL_R_MISSING_DH_DSA_CERT 162
-#define SSL_R_MISSING_DH_KEY 163
-#define SSL_R_MISSING_DH_RSA_CERT 164
-#define SSL_R_MISSING_DSA_SIGNING_CERT 165
-#define SSL_R_MISSING_EXPORT_TMP_DH_KEY 166
-#define SSL_R_MISSING_EXPORT_TMP_RSA_KEY 167
-#define SSL_R_MISSING_RSA_CERTIFICATE 168
-#define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169
-#define SSL_R_MISSING_RSA_SIGNING_CERT 170
-#define SSL_R_MISSING_SRP_PARAM 358
-#define SSL_R_MISSING_TMP_DH_KEY 171
-#define SSL_R_MISSING_TMP_ECDH_KEY 311
-#define SSL_R_MISSING_TMP_RSA_KEY 172
-#define SSL_R_MISSING_TMP_RSA_PKEY 173
-#define SSL_R_MISSING_VERIFY_MESSAGE 174
-#define SSL_R_MULTIPLE_SGC_RESTARTS 346
-#define SSL_R_NON_SSLV2_INITIAL_PACKET 175
-#define SSL_R_NO_CERTIFICATES_RETURNED 176
-#define SSL_R_NO_CERTIFICATE_ASSIGNED 177
-#define SSL_R_NO_CERTIFICATE_RETURNED 178
-#define SSL_R_NO_CERTIFICATE_SET 179
-#define SSL_R_NO_CERTIFICATE_SPECIFIED 180
-#define SSL_R_NO_CIPHERS_AVAILABLE 181
-#define SSL_R_NO_CIPHERS_PASSED 182
-#define SSL_R_NO_CIPHERS_SPECIFIED 183
-#define SSL_R_NO_CIPHER_LIST 184
-#define SSL_R_NO_CIPHER_MATCH 185
-#define SSL_R_NO_CLIENT_CERT_METHOD 331
-#define SSL_R_NO_CLIENT_CERT_RECEIVED 186
-#define SSL_R_NO_COMPRESSION_SPECIFIED 187
-#define SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER 330
-#define SSL_R_NO_METHOD_SPECIFIED 188
-#define SSL_R_NO_PRIVATEKEY 189
-#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190
-#define SSL_R_NO_PROTOCOLS_AVAILABLE 191
-#define SSL_R_NO_PUBLICKEY 192
-#define SSL_R_NO_RENEGOTIATION 339
-#define SSL_R_NO_REQUIRED_DIGEST 324
-#define SSL_R_NO_SHARED_CIPHER 193
-#define SSL_R_NO_SRTP_PROFILES 359
-#define SSL_R_NO_VERIFY_CALLBACK 194
-#define SSL_R_NULL_SSL_CTX 195
-#define SSL_R_NULL_SSL_METHOD_PASSED 196
-#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197
-#define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344
-#define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297
-#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 327
-#define SSL_R_PACKET_LENGTH_TOO_LONG 198
-#define SSL_R_PARSE_TLSEXT 227
-#define SSL_R_PATH_TOO_LONG 270
-#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199
-#define SSL_R_PEER_ERROR 200
-#define SSL_R_PEER_ERROR_CERTIFICATE 201
-#define SSL_R_PEER_ERROR_NO_CERTIFICATE 202
-#define SSL_R_PEER_ERROR_NO_CIPHER 203
-#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 204
-#define SSL_R_PRE_MAC_LENGTH_TOO_LONG 205
-#define SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS 206
-#define SSL_R_PROTOCOL_IS_SHUTDOWN 207
-#define SSL_R_PSK_IDENTITY_NOT_FOUND 223
-#define SSL_R_PSK_NO_CLIENT_CB 224
-#define SSL_R_PSK_NO_SERVER_CB 225
-#define SSL_R_PUBLIC_KEY_ENCRYPT_ERROR 208
-#define SSL_R_PUBLIC_KEY_IS_NOT_RSA 209
-#define SSL_R_PUBLIC_KEY_NOT_RSA 210
-#define SSL_R_READ_BIO_NOT_SET 211
-#define SSL_R_READ_TIMEOUT_EXPIRED 312
-#define SSL_R_READ_WRONG_PACKET_TYPE 212
-#define SSL_R_RECORD_LENGTH_MISMATCH 213
-#define SSL_R_RECORD_TOO_LARGE 214
-#define SSL_R_RECORD_TOO_SMALL 298
-#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 335
-#define SSL_R_RENEGOTIATION_ENCODING_ERR 336
-#define SSL_R_RENEGOTIATION_MISMATCH 337
-#define SSL_R_REQUIRED_CIPHER_MISSING 215
-#define SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING 342
-#define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216
-#define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217
-#define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 218
-#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 345
-#define SSL_R_SERVERHELLO_TLSEXT 275
-#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277
-#define SSL_R_SHORT_READ 219
-#define SSL_R_SIGNATURE_ALGORITHMS_ERROR 360
-#define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220
-#define SSL_R_SRP_A_CALC 361
-#define SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES 362
-#define SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG 363
-#define SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE 364
-#define SSL_R_SSL23_DOING_SESSION_ID_REUSE 221
-#define SSL_R_SSL2_CONNECTION_ID_TOO_LONG 299
-#define SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT 321
-#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 319
-#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 320
-#define SSL_R_SSL3_SESSION_ID_TOO_LONG 300
-#define SSL_R_SSL3_SESSION_ID_TOO_SHORT 222
-#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042
-#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
-#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045
-#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044
-#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046
-#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030
-#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040
-#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047
-#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041
-#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
-#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043
-#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 228
-#define SSL_R_SSL_HANDSHAKE_FAILURE 229
-#define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS 230
-#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 301
-#define SSL_R_SSL_SESSION_ID_CONFLICT 302
-#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273
-#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303
-#define SSL_R_SSL_SESSION_ID_IS_DIFFERENT 231
-#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049
-#define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050
-#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021
-#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051
-#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060
-#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071
-#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080
-#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100
-#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070
-#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022
-#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048
-#define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090
-#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114
-#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113
-#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111
-#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112
-#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110
-#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232
-#define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT 365
-#define SSL_R_TLS_HEARTBEAT_PENDING 366
-#define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 367
-#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157
-#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
-#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234
-#define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 235
-#define SSL_R_UNABLE_TO_DECODE_DH_CERTS 236
-#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 313
-#define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY 237
-#define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS 238
-#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 314
-#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239
-#define SSL_R_UNABLE_TO_FIND_SSL_METHOD 240
-#define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 241
-#define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242
-#define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243
-#define SSL_R_UNEXPECTED_MESSAGE 244
-#define SSL_R_UNEXPECTED_RECORD 245
-#define SSL_R_UNINITIALIZED 276
-#define SSL_R_UNKNOWN_ALERT_TYPE 246
-#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247
-#define SSL_R_UNKNOWN_CIPHER_RETURNED 248
-#define SSL_R_UNKNOWN_CIPHER_TYPE 249
-#define SSL_R_UNKNOWN_DIGEST 368
-#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250
-#define SSL_R_UNKNOWN_PKEY_TYPE 251
-#define SSL_R_UNKNOWN_PROTOCOL 252
-#define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253
-#define SSL_R_UNKNOWN_SSL_VERSION 254
-#define SSL_R_UNKNOWN_STATE 255
-#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 338
-#define SSL_R_UNSUPPORTED_CIPHER 256
-#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257
-#define SSL_R_UNSUPPORTED_DIGEST_TYPE 326
-#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315
-#define SSL_R_UNSUPPORTED_PROTOCOL 258
-#define SSL_R_UNSUPPORTED_SSL_VERSION 259
-#define SSL_R_UNSUPPORTED_STATUS_TYPE 329
-#define SSL_R_USE_SRTP_NOT_NEGOTIATED 369
-#define SSL_R_WRITE_BIO_NOT_SET 260
-#define SSL_R_WRONG_CIPHER_RETURNED 261
-#define SSL_R_WRONG_MESSAGE_TYPE 262
-#define SSL_R_WRONG_NUMBER_OF_KEY_BITS 263
-#define SSL_R_WRONG_SIGNATURE_LENGTH 264
-#define SSL_R_WRONG_SIGNATURE_SIZE 265
-#define SSL_R_WRONG_SIGNATURE_TYPE 370
-#define SSL_R_WRONG_SSL_VERSION 266
-#define SSL_R_WRONG_VERSION_NUMBER 267
-#define SSL_R_X509_LIB 268
-#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl/ssl/ssl2.h b/drivers/builtin_openssl/ssl/ssl2.h
deleted file mode 100644
index eb25dcb0bf..0000000000
--- a/drivers/builtin_openssl/ssl/ssl2.h
+++ /dev/null
@@ -1,272 +0,0 @@
-/* ssl/ssl2.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_SSL2_H
-#define HEADER_SSL2_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Protocol Version Codes */
-#define SSL2_VERSION 0x0002
-#define SSL2_VERSION_MAJOR 0x00
-#define SSL2_VERSION_MINOR 0x02
-/* #define SSL2_CLIENT_VERSION 0x0002 */
-/* #define SSL2_SERVER_VERSION 0x0002 */
-
-/* Protocol Message Codes */
-#define SSL2_MT_ERROR 0
-#define SSL2_MT_CLIENT_HELLO 1
-#define SSL2_MT_CLIENT_MASTER_KEY 2
-#define SSL2_MT_CLIENT_FINISHED 3
-#define SSL2_MT_SERVER_HELLO 4
-#define SSL2_MT_SERVER_VERIFY 5
-#define SSL2_MT_SERVER_FINISHED 6
-#define SSL2_MT_REQUEST_CERTIFICATE 7
-#define SSL2_MT_CLIENT_CERTIFICATE 8
-
-/* Error Message Codes */
-#define SSL2_PE_UNDEFINED_ERROR 0x0000
-#define SSL2_PE_NO_CIPHER 0x0001
-#define SSL2_PE_NO_CERTIFICATE 0x0002
-#define SSL2_PE_BAD_CERTIFICATE 0x0004
-#define SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE 0x0006
-
-/* Cipher Kind Values */
-#define SSL2_CK_NULL_WITH_MD5 0x02000000 /* v3 */
-#define SSL2_CK_RC4_128_WITH_MD5 0x02010080
-#define SSL2_CK_RC4_128_EXPORT40_WITH_MD5 0x02020080
-#define SSL2_CK_RC2_128_CBC_WITH_MD5 0x02030080
-#define SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5 0x02040080
-#define SSL2_CK_IDEA_128_CBC_WITH_MD5 0x02050080
-#define SSL2_CK_DES_64_CBC_WITH_MD5 0x02060040
-#define SSL2_CK_DES_64_CBC_WITH_SHA 0x02060140 /* v3 */
-#define SSL2_CK_DES_192_EDE3_CBC_WITH_MD5 0x020700c0
-#define SSL2_CK_DES_192_EDE3_CBC_WITH_SHA 0x020701c0 /* v3 */
-#define SSL2_CK_RC4_64_WITH_MD5 0x02080080 /* MS hack */
-
-#define SSL2_CK_DES_64_CFB64_WITH_MD5_1 0x02ff0800 /* SSLeay */
-#define SSL2_CK_NULL 0x02ff0810 /* SSLeay */
-
-#define SSL2_TXT_DES_64_CFB64_WITH_MD5_1 "DES-CFB-M1"
-#define SSL2_TXT_NULL_WITH_MD5 "NULL-MD5"
-#define SSL2_TXT_RC4_128_WITH_MD5 "RC4-MD5"
-#define SSL2_TXT_RC4_128_EXPORT40_WITH_MD5 "EXP-RC4-MD5"
-#define SSL2_TXT_RC2_128_CBC_WITH_MD5 "RC2-CBC-MD5"
-#define SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 "EXP-RC2-CBC-MD5"
-#define SSL2_TXT_IDEA_128_CBC_WITH_MD5 "IDEA-CBC-MD5"
-#define SSL2_TXT_DES_64_CBC_WITH_MD5 "DES-CBC-MD5"
-#define SSL2_TXT_DES_64_CBC_WITH_SHA "DES-CBC-SHA"
-#define SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5 "DES-CBC3-MD5"
-#define SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA "DES-CBC3-SHA"
-#define SSL2_TXT_RC4_64_WITH_MD5 "RC4-64-MD5"
-
-#define SSL2_TXT_NULL "NULL"
-
-/* Flags for the SSL_CIPHER.algorithm2 field */
-#define SSL2_CF_5_BYTE_ENC 0x01
-#define SSL2_CF_8_BYTE_ENC 0x02
-
-/* Certificate Type Codes */
-#define SSL2_CT_X509_CERTIFICATE 0x01
-
-/* Authentication Type Code */
-#define SSL2_AT_MD5_WITH_RSA_ENCRYPTION 0x01
-
-#define SSL2_MAX_SSL_SESSION_ID_LENGTH 32
-
-/* Upper/Lower Bounds */
-#define SSL2_MAX_MASTER_KEY_LENGTH_IN_BITS 256
-#ifdef OPENSSL_SYS_MPE
-#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER 29998u
-#else
-#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER 32767u /* 2^15-1 */
-#endif
-#define SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER 16383 /* 2^14-1 */
-
-#define SSL2_CHALLENGE_LENGTH 16
-/*#define SSL2_CHALLENGE_LENGTH 32 */
-#define SSL2_MIN_CHALLENGE_LENGTH 16
-#define SSL2_MAX_CHALLENGE_LENGTH 32
-#define SSL2_CONNECTION_ID_LENGTH 16
-#define SSL2_MAX_CONNECTION_ID_LENGTH 16
-#define SSL2_SSL_SESSION_ID_LENGTH 16
-#define SSL2_MAX_CERT_CHALLENGE_LENGTH 32
-#define SSL2_MIN_CERT_CHALLENGE_LENGTH 16
-#define SSL2_MAX_KEY_MATERIAL_LENGTH 24
-
-#ifndef HEADER_SSL_LOCL_H
-#define CERT char
-#endif
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-typedef struct ssl2_state_st
- {
- int three_byte_header;
- int clear_text; /* clear text */
- int escape; /* not used in SSLv2 */
- int ssl2_rollback; /* used if SSLv23 rolled back to SSLv2 */
-
- /* non-blocking io info, used to make sure the same
- * args were passwd */
- unsigned int wnum; /* number of bytes sent so far */
- int wpend_tot;
- const unsigned char *wpend_buf;
-
- int wpend_off; /* offset to data to write */
- int wpend_len; /* number of bytes passwd to write */
- int wpend_ret; /* number of bytes to return to caller */
-
- /* buffer raw data */
- int rbuf_left;
- int rbuf_offs;
- unsigned char *rbuf;
- unsigned char *wbuf;
-
- unsigned char *write_ptr;/* used to point to the start due to
- * 2/3 byte header. */
-
- unsigned int padding;
- unsigned int rlength; /* passed to ssl2_enc */
- int ract_data_length; /* Set when things are encrypted. */
- unsigned int wlength; /* passed to ssl2_enc */
- int wact_data_length; /* Set when things are decrypted. */
- unsigned char *ract_data;
- unsigned char *wact_data;
- unsigned char *mac_data;
-
- unsigned char *read_key;
- unsigned char *write_key;
-
- /* Stuff specifically to do with this SSL session */
- unsigned int challenge_length;
- unsigned char challenge[SSL2_MAX_CHALLENGE_LENGTH];
- unsigned int conn_id_length;
- unsigned char conn_id[SSL2_MAX_CONNECTION_ID_LENGTH];
- unsigned int key_material_length;
- unsigned char key_material[SSL2_MAX_KEY_MATERIAL_LENGTH*2];
-
- unsigned long read_sequence;
- unsigned long write_sequence;
-
- struct {
- unsigned int conn_id_length;
- unsigned int cert_type;
- unsigned int cert_length;
- unsigned int csl;
- unsigned int clear;
- unsigned int enc;
- unsigned char ccl[SSL2_MAX_CERT_CHALLENGE_LENGTH];
- unsigned int cipher_spec_length;
- unsigned int session_id_length;
- unsigned int clen;
- unsigned int rlen;
- } tmp;
- } SSL2_STATE;
-
-#endif
-
-/* SSLv2 */
-/* client */
-#define SSL2_ST_SEND_CLIENT_HELLO_A (0x10|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_HELLO_B (0x11|SSL_ST_CONNECT)
-#define SSL2_ST_GET_SERVER_HELLO_A (0x20|SSL_ST_CONNECT)
-#define SSL2_ST_GET_SERVER_HELLO_B (0x21|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_MASTER_KEY_A (0x30|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_MASTER_KEY_B (0x31|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_FINISHED_A (0x40|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_FINISHED_B (0x41|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_CERTIFICATE_A (0x50|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_CERTIFICATE_B (0x51|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_CERTIFICATE_C (0x52|SSL_ST_CONNECT)
-#define SSL2_ST_SEND_CLIENT_CERTIFICATE_D (0x53|SSL_ST_CONNECT)
-#define SSL2_ST_GET_SERVER_VERIFY_A (0x60|SSL_ST_CONNECT)
-#define SSL2_ST_GET_SERVER_VERIFY_B (0x61|SSL_ST_CONNECT)
-#define SSL2_ST_GET_SERVER_FINISHED_A (0x70|SSL_ST_CONNECT)
-#define SSL2_ST_GET_SERVER_FINISHED_B (0x71|SSL_ST_CONNECT)
-#define SSL2_ST_CLIENT_START_ENCRYPTION (0x80|SSL_ST_CONNECT)
-#define SSL2_ST_X509_GET_CLIENT_CERTIFICATE (0x90|SSL_ST_CONNECT)
-/* server */
-#define SSL2_ST_GET_CLIENT_HELLO_A (0x10|SSL_ST_ACCEPT)
-#define SSL2_ST_GET_CLIENT_HELLO_B (0x11|SSL_ST_ACCEPT)
-#define SSL2_ST_GET_CLIENT_HELLO_C (0x12|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_SERVER_HELLO_A (0x20|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_SERVER_HELLO_B (0x21|SSL_ST_ACCEPT)
-#define SSL2_ST_GET_CLIENT_MASTER_KEY_A (0x30|SSL_ST_ACCEPT)
-#define SSL2_ST_GET_CLIENT_MASTER_KEY_B (0x31|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_SERVER_VERIFY_A (0x40|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_SERVER_VERIFY_B (0x41|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_SERVER_VERIFY_C (0x42|SSL_ST_ACCEPT)
-#define SSL2_ST_GET_CLIENT_FINISHED_A (0x50|SSL_ST_ACCEPT)
-#define SSL2_ST_GET_CLIENT_FINISHED_B (0x51|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_SERVER_FINISHED_A (0x60|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_SERVER_FINISHED_B (0x61|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_REQUEST_CERTIFICATE_A (0x70|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_REQUEST_CERTIFICATE_B (0x71|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_REQUEST_CERTIFICATE_C (0x72|SSL_ST_ACCEPT)
-#define SSL2_ST_SEND_REQUEST_CERTIFICATE_D (0x73|SSL_ST_ACCEPT)
-#define SSL2_ST_SERVER_START_ENCRYPTION (0x80|SSL_ST_ACCEPT)
-#define SSL2_ST_X509_GET_SERVER_CERTIFICATE (0x90|SSL_ST_ACCEPT)
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/ssl/ssl23.h b/drivers/builtin_openssl/ssl/ssl23.h
deleted file mode 100644
index d3228983c7..0000000000
--- a/drivers/builtin_openssl/ssl/ssl23.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* ssl/ssl23.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_SSL23_H
-#define HEADER_SSL23_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*client */
-/* write to server */
-#define SSL23_ST_CW_CLNT_HELLO_A (0x210|SSL_ST_CONNECT)
-#define SSL23_ST_CW_CLNT_HELLO_B (0x211|SSL_ST_CONNECT)
-/* read from server */
-#define SSL23_ST_CR_SRVR_HELLO_A (0x220|SSL_ST_CONNECT)
-#define SSL23_ST_CR_SRVR_HELLO_B (0x221|SSL_ST_CONNECT)
-
-/* server */
-/* read from client */
-#define SSL23_ST_SR_CLNT_HELLO_A (0x210|SSL_ST_ACCEPT)
-#define SSL23_ST_SR_CLNT_HELLO_B (0x211|SSL_ST_ACCEPT)
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/ssl/ssl3.h b/drivers/builtin_openssl/ssl/ssl3.h
deleted file mode 100644
index cb8b2492ec..0000000000
--- a/drivers/builtin_openssl/ssl/ssl3.h
+++ /dev/null
@@ -1,693 +0,0 @@
-/* ssl/ssl3.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECC cipher suite support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-
-#ifndef HEADER_SSL3_H
-#define HEADER_SSL3_H
-
-#ifndef OPENSSL_NO_COMP
-#include <openssl/comp.h>
-#endif
-#include <openssl/buffer.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Signalling cipher suite value: from draft-ietf-tls-renegotiation-03.txt */
-#define SSL3_CK_SCSV 0x030000FF
-
-#define SSL3_CK_RSA_NULL_MD5 0x03000001
-#define SSL3_CK_RSA_NULL_SHA 0x03000002
-#define SSL3_CK_RSA_RC4_40_MD5 0x03000003
-#define SSL3_CK_RSA_RC4_128_MD5 0x03000004
-#define SSL3_CK_RSA_RC4_128_SHA 0x03000005
-#define SSL3_CK_RSA_RC2_40_MD5 0x03000006
-#define SSL3_CK_RSA_IDEA_128_SHA 0x03000007
-#define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008
-#define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009
-#define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A
-
-#define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B
-#define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C
-#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D
-#define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E
-#define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F
-#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010
-
-#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011
-#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012
-#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013
-#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014
-#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015
-#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016
-
-#define SSL3_CK_ADH_RC4_40_MD5 0x03000017
-#define SSL3_CK_ADH_RC4_128_MD5 0x03000018
-#define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019
-#define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A
-#define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B
-
-#if 0
- #define SSL3_CK_FZA_DMS_NULL_SHA 0x0300001C
- #define SSL3_CK_FZA_DMS_FZA_SHA 0x0300001D
- #if 0 /* Because it clashes with KRB5, is never used any more, and is safe
- to remove according to David Hopwood <david.hopwood@zetnet.co.uk>
- of the ietf-tls list */
- #define SSL3_CK_FZA_DMS_RC4_SHA 0x0300001E
- #endif
-#endif
-
-/* VRS Additional Kerberos5 entries
- */
-#define SSL3_CK_KRB5_DES_64_CBC_SHA 0x0300001E
-#define SSL3_CK_KRB5_DES_192_CBC3_SHA 0x0300001F
-#define SSL3_CK_KRB5_RC4_128_SHA 0x03000020
-#define SSL3_CK_KRB5_IDEA_128_CBC_SHA 0x03000021
-#define SSL3_CK_KRB5_DES_64_CBC_MD5 0x03000022
-#define SSL3_CK_KRB5_DES_192_CBC3_MD5 0x03000023
-#define SSL3_CK_KRB5_RC4_128_MD5 0x03000024
-#define SSL3_CK_KRB5_IDEA_128_CBC_MD5 0x03000025
-
-#define SSL3_CK_KRB5_DES_40_CBC_SHA 0x03000026
-#define SSL3_CK_KRB5_RC2_40_CBC_SHA 0x03000027
-#define SSL3_CK_KRB5_RC4_40_SHA 0x03000028
-#define SSL3_CK_KRB5_DES_40_CBC_MD5 0x03000029
-#define SSL3_CK_KRB5_RC2_40_CBC_MD5 0x0300002A
-#define SSL3_CK_KRB5_RC4_40_MD5 0x0300002B
-
-#define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5"
-#define SSL3_TXT_RSA_NULL_SHA "NULL-SHA"
-#define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5"
-#define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5"
-#define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA"
-#define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5"
-#define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA"
-#define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA"
-#define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA"
-#define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA"
-
-#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA"
-#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA"
-#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA"
-#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA"
-#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA"
-#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA"
-
-#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA"
-#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA"
-#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA"
-#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA"
-#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA"
-#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA"
-
-#define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5"
-#define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5"
-#define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA"
-#define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA"
-#define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA"
-
-#if 0
- #define SSL3_TXT_FZA_DMS_NULL_SHA "FZA-NULL-SHA"
- #define SSL3_TXT_FZA_DMS_FZA_SHA "FZA-FZA-CBC-SHA"
- #define SSL3_TXT_FZA_DMS_RC4_SHA "FZA-RC4-SHA"
-#endif
-
-#define SSL3_TXT_KRB5_DES_64_CBC_SHA "KRB5-DES-CBC-SHA"
-#define SSL3_TXT_KRB5_DES_192_CBC3_SHA "KRB5-DES-CBC3-SHA"
-#define SSL3_TXT_KRB5_RC4_128_SHA "KRB5-RC4-SHA"
-#define SSL3_TXT_KRB5_IDEA_128_CBC_SHA "KRB5-IDEA-CBC-SHA"
-#define SSL3_TXT_KRB5_DES_64_CBC_MD5 "KRB5-DES-CBC-MD5"
-#define SSL3_TXT_KRB5_DES_192_CBC3_MD5 "KRB5-DES-CBC3-MD5"
-#define SSL3_TXT_KRB5_RC4_128_MD5 "KRB5-RC4-MD5"
-#define SSL3_TXT_KRB5_IDEA_128_CBC_MD5 "KRB5-IDEA-CBC-MD5"
-
-#define SSL3_TXT_KRB5_DES_40_CBC_SHA "EXP-KRB5-DES-CBC-SHA"
-#define SSL3_TXT_KRB5_RC2_40_CBC_SHA "EXP-KRB5-RC2-CBC-SHA"
-#define SSL3_TXT_KRB5_RC4_40_SHA "EXP-KRB5-RC4-SHA"
-#define SSL3_TXT_KRB5_DES_40_CBC_MD5 "EXP-KRB5-DES-CBC-MD5"
-#define SSL3_TXT_KRB5_RC2_40_CBC_MD5 "EXP-KRB5-RC2-CBC-MD5"
-#define SSL3_TXT_KRB5_RC4_40_MD5 "EXP-KRB5-RC4-MD5"
-
-#define SSL3_SSL_SESSION_ID_LENGTH 32
-#define SSL3_MAX_SSL_SESSION_ID_LENGTH 32
-
-#define SSL3_MASTER_SECRET_SIZE 48
-#define SSL3_RANDOM_SIZE 32
-#define SSL3_SESSION_ID_SIZE 32
-#define SSL3_RT_HEADER_LENGTH 5
-
-#ifndef SSL3_ALIGN_PAYLOAD
- /* Some will argue that this increases memory footprint, but it's
- * not actually true. Point is that malloc has to return at least
- * 64-bit aligned pointers, meaning that allocating 5 bytes wastes
- * 3 bytes in either case. Suggested pre-gaping simply moves these
- * wasted bytes from the end of allocated region to its front,
- * but makes data payload aligned, which improves performance:-) */
-# define SSL3_ALIGN_PAYLOAD 8
-#else
-# if (SSL3_ALIGN_PAYLOAD&(SSL3_ALIGN_PAYLOAD-1))!=0
-# error "insane SSL3_ALIGN_PAYLOAD"
-# undef SSL3_ALIGN_PAYLOAD
-# endif
-#endif
-
-/* This is the maximum MAC (digest) size used by the SSL library.
- * Currently maximum of 20 is used by SHA1, but we reserve for
- * future extension for 512-bit hashes.
- */
-
-#define SSL3_RT_MAX_MD_SIZE 64
-
-/* Maximum block size used in all ciphersuites. Currently 16 for AES.
- */
-
-#define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16
-
-#define SSL3_RT_MAX_EXTRA (16384)
-
-/* Maximum plaintext length: defined by SSL/TLS standards */
-#define SSL3_RT_MAX_PLAIN_LENGTH 16384
-/* Maximum compression overhead: defined by SSL/TLS standards */
-#define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024
-
-/* The standards give a maximum encryption overhead of 1024 bytes.
- * In practice the value is lower than this. The overhead is the maximum
- * number of padding bytes (256) plus the mac size.
- */
-#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE)
-
-/* OpenSSL currently only uses a padding length of at most one block so
- * the send overhead is smaller.
- */
-
-#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \
- (SSL_RT_MAX_CIPHER_BLOCK_SIZE + SSL3_RT_MAX_MD_SIZE)
-
-/* If compression isn't used don't include the compression overhead */
-
-#ifdef OPENSSL_NO_COMP
-#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH
-#else
-#define SSL3_RT_MAX_COMPRESSED_LENGTH \
- (SSL3_RT_MAX_PLAIN_LENGTH+SSL3_RT_MAX_COMPRESSED_OVERHEAD)
-#endif
-#define SSL3_RT_MAX_ENCRYPTED_LENGTH \
- (SSL3_RT_MAX_ENCRYPTED_OVERHEAD+SSL3_RT_MAX_COMPRESSED_LENGTH)
-#define SSL3_RT_MAX_PACKET_SIZE \
- (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
-
-#define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54"
-#define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52"
-
-#define SSL3_VERSION 0x0300
-#define SSL3_VERSION_MAJOR 0x03
-#define SSL3_VERSION_MINOR 0x00
-
-#define SSL3_RT_CHANGE_CIPHER_SPEC 20
-#define SSL3_RT_ALERT 21
-#define SSL3_RT_HANDSHAKE 22
-#define SSL3_RT_APPLICATION_DATA 23
-#define TLS1_RT_HEARTBEAT 24
-
-#define SSL3_AL_WARNING 1
-#define SSL3_AL_FATAL 2
-
-#define SSL3_AD_CLOSE_NOTIFY 0
-#define SSL3_AD_UNEXPECTED_MESSAGE 10 /* fatal */
-#define SSL3_AD_BAD_RECORD_MAC 20 /* fatal */
-#define SSL3_AD_DECOMPRESSION_FAILURE 30 /* fatal */
-#define SSL3_AD_HANDSHAKE_FAILURE 40 /* fatal */
-#define SSL3_AD_NO_CERTIFICATE 41
-#define SSL3_AD_BAD_CERTIFICATE 42
-#define SSL3_AD_UNSUPPORTED_CERTIFICATE 43
-#define SSL3_AD_CERTIFICATE_REVOKED 44
-#define SSL3_AD_CERTIFICATE_EXPIRED 45
-#define SSL3_AD_CERTIFICATE_UNKNOWN 46
-#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */
-
-#define TLS1_HB_REQUEST 1
-#define TLS1_HB_RESPONSE 2
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-typedef struct ssl3_record_st
- {
-/*r */ int type; /* type of record */
-/*rw*/ unsigned int length; /* How many bytes available */
-/*r */ unsigned int off; /* read/write offset into 'buf' */
-/*rw*/ unsigned char *data; /* pointer to the record data */
-/*rw*/ unsigned char *input; /* where the decode bytes are */
-/*r */ unsigned char *comp; /* only used with decompression - malloc()ed */
-/*r */ unsigned long epoch; /* epoch number, needed by DTLS1 */
-/*r */ unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
- } SSL3_RECORD;
-
-typedef struct ssl3_buffer_st
- {
- unsigned char *buf; /* at least SSL3_RT_MAX_PACKET_SIZE bytes,
- * see ssl3_setup_buffers() */
- size_t len; /* buffer size */
- int offset; /* where to 'copy from' */
- int left; /* how many bytes left */
- } SSL3_BUFFER;
-
-#endif
-
-#define SSL3_CT_RSA_SIGN 1
-#define SSL3_CT_DSS_SIGN 2
-#define SSL3_CT_RSA_FIXED_DH 3
-#define SSL3_CT_DSS_FIXED_DH 4
-#define SSL3_CT_RSA_EPHEMERAL_DH 5
-#define SSL3_CT_DSS_EPHEMERAL_DH 6
-#define SSL3_CT_FORTEZZA_DMS 20
-/* SSL3_CT_NUMBER is used to size arrays and it must be large
- * enough to contain all of the cert types defined either for
- * SSLv3 and TLSv1.
- */
-#define SSL3_CT_NUMBER 9
-
-
-#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001
-#define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002
-#define SSL3_FLAGS_POP_BUFFER 0x0004
-#define TLS1_FLAGS_TLS_PADDING_BUG 0x0008
-#define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010
-#define TLS1_FLAGS_KEEP_HANDSHAKE 0x0020
-
-/* SSL3_FLAGS_SGC_RESTART_DONE is set when we
- * restart a handshake because of MS SGC and so prevents us
- * from restarting the handshake in a loop. It's reset on a
- * renegotiation, so effectively limits the client to one restart
- * per negotiation. This limits the possibility of a DDoS
- * attack where the client handshakes in a loop using SGC to
- * restart. Servers which permit renegotiation can still be
- * effected, but we can't prevent that.
- */
-#define SSL3_FLAGS_SGC_RESTART_DONE 0x0040
-
-#ifndef OPENSSL_NO_SSL_INTERN
-
-typedef struct ssl3_state_st
- {
- long flags;
- int delay_buf_pop_ret;
-
- unsigned char read_sequence[8];
- int read_mac_secret_size;
- unsigned char read_mac_secret[EVP_MAX_MD_SIZE];
- unsigned char write_sequence[8];
- int write_mac_secret_size;
- unsigned char write_mac_secret[EVP_MAX_MD_SIZE];
-
- unsigned char server_random[SSL3_RANDOM_SIZE];
- unsigned char client_random[SSL3_RANDOM_SIZE];
-
- /* flags for countermeasure against known-IV weakness */
- int need_empty_fragments;
- int empty_fragment_done;
-
- /* The value of 'extra' when the buffers were initialized */
- int init_extra;
-
- SSL3_BUFFER rbuf; /* read IO goes into here */
- SSL3_BUFFER wbuf; /* write IO goes into here */
-
- SSL3_RECORD rrec; /* each decoded record goes in here */
- SSL3_RECORD wrec; /* goes out from here */
-
- /* storage for Alert/Handshake protocol data received but not
- * yet processed by ssl3_read_bytes: */
- unsigned char alert_fragment[2];
- unsigned int alert_fragment_len;
- unsigned char handshake_fragment[4];
- unsigned int handshake_fragment_len;
-
- /* partial write - check the numbers match */
- unsigned int wnum; /* number of bytes sent so far */
- int wpend_tot; /* number bytes written */
- int wpend_type;
- int wpend_ret; /* number of bytes submitted */
- const unsigned char *wpend_buf;
-
- /* used during startup, digest all incoming/outgoing packets */
- BIO *handshake_buffer;
- /* When set of handshake digests is determined, buffer is hashed
- * and freed and MD_CTX-es for all required digests are stored in
- * this array */
- EVP_MD_CTX **handshake_dgst;
- /* this is set whenerver we see a change_cipher_spec message
- * come in when we are not looking for one */
- int change_cipher_spec;
-
- int warn_alert;
- int fatal_alert;
- /* we allow one fatal and one warning alert to be outstanding,
- * send close alert via the warning alert */
- int alert_dispatch;
- unsigned char send_alert[2];
-
- /* This flag is set when we should renegotiate ASAP, basically when
- * there is no more data in the read or write buffers */
- int renegotiate;
- int total_renegotiations;
- int num_renegotiations;
-
- int in_read_app_data;
-
- /* Opaque PRF input as used for the current handshake.
- * These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined
- * (otherwise, they are merely present to improve binary compatibility) */
- void *client_opaque_prf_input;
- size_t client_opaque_prf_input_len;
- void *server_opaque_prf_input;
- size_t server_opaque_prf_input_len;
-
- struct {
- /* actually only needs to be 16+20 */
- unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
-
- /* actually only need to be 16+20 for SSLv3 and 12 for TLS */
- unsigned char finish_md[EVP_MAX_MD_SIZE*2];
- int finish_md_len;
- unsigned char peer_finish_md[EVP_MAX_MD_SIZE*2];
- int peer_finish_md_len;
-
- unsigned long message_size;
- int message_type;
-
- /* used to hold the new cipher we are going to use */
- const SSL_CIPHER *new_cipher;
-#ifndef OPENSSL_NO_DH
- DH *dh;
-#endif
-
-#ifndef OPENSSL_NO_ECDH
- EC_KEY *ecdh; /* holds short lived ECDH key */
-#endif
-
- /* used when SSL_ST_FLUSH_DATA is entered */
- int next_state;
-
- int reuse_message;
-
- /* used for certificate requests */
- int cert_req;
- int ctype_num;
- char ctype[SSL3_CT_NUMBER];
- STACK_OF(X509_NAME) *ca_names;
-
- int use_rsa_tmp;
-
- int key_block_length;
- unsigned char *key_block;
-
- const EVP_CIPHER *new_sym_enc;
- const EVP_MD *new_hash;
- int new_mac_pkey_type;
- int new_mac_secret_size;
-#ifndef OPENSSL_NO_COMP
- const SSL_COMP *new_compression;
-#else
- char *new_compression;
-#endif
- int cert_request;
- } tmp;
-
- /* Connection binding to prevent renegotiation attacks */
- unsigned char previous_client_finished[EVP_MAX_MD_SIZE];
- unsigned char previous_client_finished_len;
- unsigned char previous_server_finished[EVP_MAX_MD_SIZE];
- unsigned char previous_server_finished_len;
- int send_connection_binding; /* TODOEKR */
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- /* Set if we saw the Next Protocol Negotiation extension from our peer. */
- int next_proto_neg_seen;
-#endif
-
-#ifndef OPENSSL_NO_TLSEXT
-#ifndef OPENSSL_NO_EC
- /* This is set to true if we believe that this is a version of Safari
- * running on OS X 10.6 or newer. We wish to know this because Safari
- * on 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */
- char is_probably_safari;
-#endif /* !OPENSSL_NO_EC */
-#endif /* !OPENSSL_NO_TLSEXT */
- } SSL3_STATE;
-
-#endif
-
-/* SSLv3 */
-/*client */
-/* extra state */
-#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT)
-#ifndef OPENSSL_NO_SCTP
-#define DTLS1_SCTP_ST_CW_WRITE_SOCK (0x310|SSL_ST_CONNECT)
-#define DTLS1_SCTP_ST_CR_READ_SOCK (0x320|SSL_ST_CONNECT)
-#endif
-/* write to server */
-#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT)
-/* read from server */
-#define SSL3_ST_CR_SRVR_HELLO_A (0x120|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SRVR_HELLO_B (0x121|SSL_ST_CONNECT)
-#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT)
-#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_A (0x130|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_B (0x131|SSL_ST_CONNECT)
-#define SSL3_ST_CR_KEY_EXCH_A (0x140|SSL_ST_CONNECT)
-#define SSL3_ST_CR_KEY_EXCH_B (0x141|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_REQ_A (0x150|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_REQ_B (0x151|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SRVR_DONE_A (0x160|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SRVR_DONE_B (0x161|SSL_ST_CONNECT)
-/* write to server */
-#define SSL3_ST_CW_CERT_A (0x170|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_B (0x171|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_C (0x172|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_D (0x173|SSL_ST_CONNECT)
-#define SSL3_ST_CW_KEY_EXCH_A (0x180|SSL_ST_CONNECT)
-#define SSL3_ST_CW_KEY_EXCH_B (0x181|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_VRFY_A (0x190|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CERT_VRFY_B (0x191|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CHANGE_A (0x1A0|SSL_ST_CONNECT)
-#define SSL3_ST_CW_CHANGE_B (0x1A1|SSL_ST_CONNECT)
-#ifndef OPENSSL_NO_NEXTPROTONEG
-#define SSL3_ST_CW_NEXT_PROTO_A (0x200|SSL_ST_CONNECT)
-#define SSL3_ST_CW_NEXT_PROTO_B (0x201|SSL_ST_CONNECT)
-#endif
-#define SSL3_ST_CW_FINISHED_A (0x1B0|SSL_ST_CONNECT)
-#define SSL3_ST_CW_FINISHED_B (0x1B1|SSL_ST_CONNECT)
-/* read from server */
-#define SSL3_ST_CR_CHANGE_A (0x1C0|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CHANGE_B (0x1C1|SSL_ST_CONNECT)
-#define SSL3_ST_CR_FINISHED_A (0x1D0|SSL_ST_CONNECT)
-#define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT)
-#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_STATUS_A (0x1F0|SSL_ST_CONNECT)
-#define SSL3_ST_CR_CERT_STATUS_B (0x1F1|SSL_ST_CONNECT)
-
-/* server */
-/* extra state */
-#define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT)
-#ifndef OPENSSL_NO_SCTP
-#define DTLS1_SCTP_ST_SW_WRITE_SOCK (0x310|SSL_ST_ACCEPT)
-#define DTLS1_SCTP_ST_SR_READ_SOCK (0x320|SSL_ST_ACCEPT)
-#endif
-/* read from client */
-/* Do not change the number values, they do matter */
-#define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CLNT_HELLO_B (0x111|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CLNT_HELLO_C (0x112|SSL_ST_ACCEPT)
-/* write to client */
-#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT)
-#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_HELLO_REQ_A (0x120|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_HELLO_REQ_B (0x121|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_HELLO_REQ_C (0x122|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SRVR_HELLO_A (0x130|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SRVR_HELLO_B (0x131|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_A (0x140|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_B (0x141|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_KEY_EXCH_A (0x150|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_KEY_EXCH_B (0x151|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_REQ_A (0x160|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_REQ_B (0x161|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SRVR_DONE_A (0x170|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SRVR_DONE_B (0x171|SSL_ST_ACCEPT)
-/* read from client */
-#define SSL3_ST_SR_CERT_A (0x180|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CERT_B (0x181|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_KEY_EXCH_A (0x190|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_KEY_EXCH_B (0x191|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CERT_VRFY_A (0x1A0|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CERT_VRFY_B (0x1A1|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CHANGE_A (0x1B0|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CHANGE_B (0x1B1|SSL_ST_ACCEPT)
-#ifndef OPENSSL_NO_NEXTPROTONEG
-#define SSL3_ST_SR_NEXT_PROTO_A (0x210|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_NEXT_PROTO_B (0x211|SSL_ST_ACCEPT)
-#endif
-#define SSL3_ST_SR_FINISHED_A (0x1C0|SSL_ST_ACCEPT)
-#define SSL3_ST_SR_FINISHED_B (0x1C1|SSL_ST_ACCEPT)
-/* write to client */
-#define SSL3_ST_SW_CHANGE_A (0x1D0|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CHANGE_B (0x1D1|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_FINISHED_A (0x1E0|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_STATUS_A (0x200|SSL_ST_ACCEPT)
-#define SSL3_ST_SW_CERT_STATUS_B (0x201|SSL_ST_ACCEPT)
-
-#define SSL3_MT_HELLO_REQUEST 0
-#define SSL3_MT_CLIENT_HELLO 1
-#define SSL3_MT_SERVER_HELLO 2
-#define SSL3_MT_NEWSESSION_TICKET 4
-#define SSL3_MT_CERTIFICATE 11
-#define SSL3_MT_SERVER_KEY_EXCHANGE 12
-#define SSL3_MT_CERTIFICATE_REQUEST 13
-#define SSL3_MT_SERVER_DONE 14
-#define SSL3_MT_CERTIFICATE_VERIFY 15
-#define SSL3_MT_CLIENT_KEY_EXCHANGE 16
-#define SSL3_MT_FINISHED 20
-#define SSL3_MT_CERTIFICATE_STATUS 22
-#ifndef OPENSSL_NO_NEXTPROTONEG
-#define SSL3_MT_NEXT_PROTO 67
-#endif
-#define DTLS1_MT_HELLO_VERIFY_REQUEST 3
-
-
-#define SSL3_MT_CCS 1
-
-/* These are used when changing over to a new cipher */
-#define SSL3_CC_READ 0x01
-#define SSL3_CC_WRITE 0x02
-#define SSL3_CC_CLIENT 0x10
-#define SSL3_CC_SERVER 0x20
-#define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE)
-#define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ)
-#define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ)
-#define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER|SSL3_CC_WRITE)
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
diff --git a/drivers/builtin_openssl/ssl/ssl_asn1.c b/drivers/builtin_openssl/ssl/ssl_asn1.c
deleted file mode 100644
index 38540be1e5..0000000000
--- a/drivers/builtin_openssl/ssl/ssl_asn1.c
+++ /dev/null
@@ -1,642 +0,0 @@
-/* ssl/ssl_asn1.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "ssl_locl.h"
-#include <openssl/asn1_mac.h>
-#include <openssl/objects.h>
-#include <openssl/x509.h>
-
-typedef struct ssl_session_asn1_st
- {
- ASN1_INTEGER version;
- ASN1_INTEGER ssl_version;
- ASN1_OCTET_STRING cipher;
- ASN1_OCTET_STRING comp_id;
- ASN1_OCTET_STRING master_key;
- ASN1_OCTET_STRING session_id;
- ASN1_OCTET_STRING session_id_context;
- ASN1_OCTET_STRING key_arg;
-#ifndef OPENSSL_NO_KRB5
- ASN1_OCTET_STRING krb5_princ;
-#endif /* OPENSSL_NO_KRB5 */
- ASN1_INTEGER time;
- ASN1_INTEGER timeout;
- ASN1_INTEGER verify_result;
-#ifndef OPENSSL_NO_TLSEXT
- ASN1_OCTET_STRING tlsext_hostname;
- ASN1_INTEGER tlsext_tick_lifetime;
- ASN1_OCTET_STRING tlsext_tick;
-#endif /* OPENSSL_NO_TLSEXT */
-#ifndef OPENSSL_NO_PSK
- ASN1_OCTET_STRING psk_identity_hint;
- ASN1_OCTET_STRING psk_identity;
-#endif /* OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_SRP
- ASN1_OCTET_STRING srp_username;
-#endif /* OPENSSL_NO_SRP */
- } SSL_SESSION_ASN1;
-
-int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
- {
-#define LSIZE2 (sizeof(long)*2)
- int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0;
- unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
- unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
-#ifndef OPENSSL_NO_TLSEXT
- int v6=0,v9=0,v10=0;
- unsigned char ibuf6[LSIZE2];
-#endif
-#ifndef OPENSSL_NO_COMP
- unsigned char cbuf;
- int v11=0;
-#endif
-#ifndef OPENSSL_NO_SRP
- int v12=0;
-#endif
- long l;
- SSL_SESSION_ASN1 a;
- M_ASN1_I2D_vars(in);
-
- if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0)))
- return(0);
-
- /* Note that I cheat in the following 2 assignments. I know
- * that if the ASN1_INTEGER passed to ASN1_INTEGER_set
- * is > sizeof(long)+1, the buffer will not be re-OPENSSL_malloc()ed.
- * This is a bit evil but makes things simple, no dynamic allocation
- * to clean up :-) */
- a.version.length=LSIZE2;
- a.version.type=V_ASN1_INTEGER;
- a.version.data=ibuf1;
- ASN1_INTEGER_set(&(a.version),SSL_SESSION_ASN1_VERSION);
-
- a.ssl_version.length=LSIZE2;
- a.ssl_version.type=V_ASN1_INTEGER;
- a.ssl_version.data=ibuf2;
- ASN1_INTEGER_set(&(a.ssl_version),in->ssl_version);
-
- a.cipher.type=V_ASN1_OCTET_STRING;
- a.cipher.data=buf;
-
- if (in->cipher == NULL)
- l=in->cipher_id;
- else
- l=in->cipher->id;
- if (in->ssl_version == SSL2_VERSION)
- {
- a.cipher.length=3;
- buf[0]=((unsigned char)(l>>16L))&0xff;
- buf[1]=((unsigned char)(l>> 8L))&0xff;
- buf[2]=((unsigned char)(l ))&0xff;
- }
- else
- {
- a.cipher.length=2;
- buf[0]=((unsigned char)(l>>8L))&0xff;
- buf[1]=((unsigned char)(l ))&0xff;
- }
-
-#ifndef OPENSSL_NO_COMP
- if (in->compress_meth)
- {
- cbuf = (unsigned char)in->compress_meth;
- a.comp_id.length = 1;
- a.comp_id.type = V_ASN1_OCTET_STRING;
- a.comp_id.data = &cbuf;
- }
-#endif
-
- a.master_key.length=in->master_key_length;
- a.master_key.type=V_ASN1_OCTET_STRING;
- a.master_key.data=in->master_key;
-
- a.session_id.length=in->session_id_length;
- a.session_id.type=V_ASN1_OCTET_STRING;
- a.session_id.data=in->session_id;
-
- a.session_id_context.length=in->sid_ctx_length;
- a.session_id_context.type=V_ASN1_OCTET_STRING;
- a.session_id_context.data=in->sid_ctx;
-
- a.key_arg.length=in->key_arg_length;
- a.key_arg.type=V_ASN1_OCTET_STRING;
- a.key_arg.data=in->key_arg;
-
-#ifndef OPENSSL_NO_KRB5
- if (in->krb5_client_princ_len)
- {
- a.krb5_princ.length=in->krb5_client_princ_len;
- a.krb5_princ.type=V_ASN1_OCTET_STRING;
- a.krb5_princ.data=in->krb5_client_princ;
- }
-#endif /* OPENSSL_NO_KRB5 */
-
- if (in->time != 0L)
- {
- a.time.length=LSIZE2;
- a.time.type=V_ASN1_INTEGER;
- a.time.data=ibuf3;
- ASN1_INTEGER_set(&(a.time),in->time);
- }
-
- if (in->timeout != 0L)
- {
- a.timeout.length=LSIZE2;
- a.timeout.type=V_ASN1_INTEGER;
- a.timeout.data=ibuf4;
- ASN1_INTEGER_set(&(a.timeout),in->timeout);
- }
-
- if (in->verify_result != X509_V_OK)
- {
- a.verify_result.length=LSIZE2;
- a.verify_result.type=V_ASN1_INTEGER;
- a.verify_result.data=ibuf5;
- ASN1_INTEGER_set(&a.verify_result,in->verify_result);
- }
-
-#ifndef OPENSSL_NO_TLSEXT
- if (in->tlsext_hostname)
- {
- a.tlsext_hostname.length=strlen(in->tlsext_hostname);
- a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
- a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname;
- }
- if (in->tlsext_tick)
- {
- a.tlsext_tick.length= in->tlsext_ticklen;
- a.tlsext_tick.type=V_ASN1_OCTET_STRING;
- a.tlsext_tick.data=(unsigned char *)in->tlsext_tick;
- }
- if (in->tlsext_tick_lifetime_hint > 0)
- {
- a.tlsext_tick_lifetime.length=LSIZE2;
- a.tlsext_tick_lifetime.type=V_ASN1_INTEGER;
- a.tlsext_tick_lifetime.data=ibuf6;
- ASN1_INTEGER_set(&a.tlsext_tick_lifetime,in->tlsext_tick_lifetime_hint);
- }
-#endif /* OPENSSL_NO_TLSEXT */
-#ifndef OPENSSL_NO_PSK
- if (in->psk_identity_hint)
- {
- a.psk_identity_hint.length=strlen(in->psk_identity_hint);
- a.psk_identity_hint.type=V_ASN1_OCTET_STRING;
- a.psk_identity_hint.data=(unsigned char *)(in->psk_identity_hint);
- }
- if (in->psk_identity)
- {
- a.psk_identity.length=strlen(in->psk_identity);
- a.psk_identity.type=V_ASN1_OCTET_STRING;
- a.psk_identity.data=(unsigned char *)(in->psk_identity);
- }
-#endif /* OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_SRP
- if (in->srp_username)
- {
- a.srp_username.length=strlen(in->srp_username);
- a.srp_username.type=V_ASN1_OCTET_STRING;
- a.srp_username.data=(unsigned char *)(in->srp_username);
- }
-#endif /* OPENSSL_NO_SRP */
-
- M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER);
- M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER);
- M_ASN1_I2D_len(&(a.cipher), i2d_ASN1_OCTET_STRING);
- M_ASN1_I2D_len(&(a.session_id), i2d_ASN1_OCTET_STRING);
- M_ASN1_I2D_len(&(a.master_key), i2d_ASN1_OCTET_STRING);
-#ifndef OPENSSL_NO_KRB5
- if (in->krb5_client_princ_len)
- M_ASN1_I2D_len(&(a.krb5_princ), i2d_ASN1_OCTET_STRING);
-#endif /* OPENSSL_NO_KRB5 */
- if (in->key_arg_length > 0)
- M_ASN1_I2D_len_IMP_opt(&(a.key_arg),i2d_ASN1_OCTET_STRING);
- if (in->time != 0L)
- M_ASN1_I2D_len_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
- if (in->timeout != 0L)
- M_ASN1_I2D_len_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
- if (in->peer != NULL)
- M_ASN1_I2D_len_EXP_opt(in->peer,i2d_X509,3,v3);
- M_ASN1_I2D_len_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,v4);
- if (in->verify_result != X509_V_OK)
- M_ASN1_I2D_len_EXP_opt(&(a.verify_result),i2d_ASN1_INTEGER,5,v5);
-
-#ifndef OPENSSL_NO_TLSEXT
- if (in->tlsext_tick_lifetime_hint > 0)
- M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
- if (in->tlsext_tick)
- M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
- if (in->tlsext_hostname)
- M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
-#ifndef OPENSSL_NO_COMP
- if (in->compress_meth)
- M_ASN1_I2D_len_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING,11,v11);
-#endif
-#endif /* OPENSSL_NO_TLSEXT */
-#ifndef OPENSSL_NO_PSK
- if (in->psk_identity_hint)
- M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
- if (in->psk_identity)
- M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
-#endif /* OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_SRP
- if (in->srp_username)
- M_ASN1_I2D_len_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING,12,v12);
-#endif /* OPENSSL_NO_SRP */
-
- M_ASN1_I2D_seq_total();
-
- M_ASN1_I2D_put(&(a.version), i2d_ASN1_INTEGER);
- M_ASN1_I2D_put(&(a.ssl_version), i2d_ASN1_INTEGER);
- M_ASN1_I2D_put(&(a.cipher), i2d_ASN1_OCTET_STRING);
- M_ASN1_I2D_put(&(a.session_id), i2d_ASN1_OCTET_STRING);
- M_ASN1_I2D_put(&(a.master_key), i2d_ASN1_OCTET_STRING);
-#ifndef OPENSSL_NO_KRB5
- if (in->krb5_client_princ_len)
- M_ASN1_I2D_put(&(a.krb5_princ), i2d_ASN1_OCTET_STRING);
-#endif /* OPENSSL_NO_KRB5 */
- if (in->key_arg_length > 0)
- M_ASN1_I2D_put_IMP_opt(&(a.key_arg),i2d_ASN1_OCTET_STRING,0);
- if (in->time != 0L)
- M_ASN1_I2D_put_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
- if (in->timeout != 0L)
- M_ASN1_I2D_put_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
- if (in->peer != NULL)
- M_ASN1_I2D_put_EXP_opt(in->peer,i2d_X509,3,v3);
- M_ASN1_I2D_put_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,
- v4);
- if (in->verify_result != X509_V_OK)
- M_ASN1_I2D_put_EXP_opt(&a.verify_result,i2d_ASN1_INTEGER,5,v5);
-#ifndef OPENSSL_NO_TLSEXT
- if (in->tlsext_hostname)
- M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
-#endif /* OPENSSL_NO_TLSEXT */
-#ifndef OPENSSL_NO_PSK
- if (in->psk_identity_hint)
- M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
- if (in->psk_identity)
- M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
-#endif /* OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_TLSEXT
- if (in->tlsext_tick_lifetime_hint > 0)
- M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
- if (in->tlsext_tick)
- M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
-#endif /* OPENSSL_NO_TLSEXT */
-#ifndef OPENSSL_NO_COMP
- if (in->compress_meth)
- M_ASN1_I2D_put_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING,11,v11);
-#endif
-#ifndef OPENSSL_NO_SRP
- if (in->srp_username)
- M_ASN1_I2D_put_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING,12,v12);
-#endif /* OPENSSL_NO_SRP */
- M_ASN1_I2D_finish();
- }
-
-SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
- long length)
- {
- int ssl_version=0,i;
- long id;
- ASN1_INTEGER ai,*aip;
- ASN1_OCTET_STRING os,*osp;
- M_ASN1_D2I_vars(a,SSL_SESSION *,SSL_SESSION_new);
-
- aip= &ai;
- osp= &os;
-
- M_ASN1_D2I_Init();
- M_ASN1_D2I_start_sequence();
-
- ai.data=NULL; ai.length=0;
- M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
- if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
-
- /* we don't care about the version right now :-) */
- M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
- ssl_version=(int)ASN1_INTEGER_get(aip);
- ret->ssl_version=ssl_version;
- if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
-
- os.data=NULL; os.length=0;
- M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
- if (ssl_version == SSL2_VERSION)
- {
- if (os.length != 3)
- {
- c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
- goto err;
- }
- id=0x02000000L|
- ((unsigned long)os.data[0]<<16L)|
- ((unsigned long)os.data[1]<< 8L)|
- (unsigned long)os.data[2];
- }
- else if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
- {
- if (os.length != 2)
- {
- c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
- goto err;
- }
- id=0x03000000L|
- ((unsigned long)os.data[0]<<8L)|
- (unsigned long)os.data[1];
- }
- else
- {
- c.error=SSL_R_UNKNOWN_SSL_VERSION;
- goto err;
- }
-
- ret->cipher=NULL;
- ret->cipher_id=id;
-
- M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
- if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
- i=SSL3_MAX_SSL_SESSION_ID_LENGTH;
- else /* if (ssl_version>>8 == SSL2_VERSION_MAJOR) */
- i=SSL2_MAX_SSL_SESSION_ID_LENGTH;
-
- if (os.length > i)
- os.length = i;
- if (os.length > (int)sizeof(ret->session_id)) /* can't happen */
- os.length = sizeof(ret->session_id);
-
- ret->session_id_length=os.length;
- OPENSSL_assert(os.length <= (int)sizeof(ret->session_id));
- memcpy(ret->session_id,os.data,os.length);
-
- M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
- if (os.length > SSL_MAX_MASTER_KEY_LENGTH)
- ret->master_key_length=SSL_MAX_MASTER_KEY_LENGTH;
- else
- ret->master_key_length=os.length;
- memcpy(ret->master_key,os.data,ret->master_key_length);
-
- os.length=0;
-
-#ifndef OPENSSL_NO_KRB5
- os.length=0;
- M_ASN1_D2I_get_opt(osp,d2i_ASN1_OCTET_STRING,V_ASN1_OCTET_STRING);
- if (os.data)
- {
- if (os.length > SSL_MAX_KRB5_PRINCIPAL_LENGTH)
- ret->krb5_client_princ_len=0;
- else
- ret->krb5_client_princ_len=os.length;
- memcpy(ret->krb5_client_princ,os.data,ret->krb5_client_princ_len);
- OPENSSL_free(os.data);
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->krb5_client_princ_len=0;
-#endif /* OPENSSL_NO_KRB5 */
-
- M_ASN1_D2I_get_IMP_opt(osp,d2i_ASN1_OCTET_STRING,0,V_ASN1_OCTET_STRING);
- if (os.length > SSL_MAX_KEY_ARG_LENGTH)
- ret->key_arg_length=SSL_MAX_KEY_ARG_LENGTH;
- else
- ret->key_arg_length=os.length;
- memcpy(ret->key_arg,os.data,ret->key_arg_length);
- if (os.data != NULL) OPENSSL_free(os.data);
-
- ai.length=0;
- M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,1);
- if (ai.data != NULL)
- {
- ret->time=ASN1_INTEGER_get(aip);
- OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
- }
- else
- ret->time=(unsigned long)time(NULL);
-
- ai.length=0;
- M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,2);
- if (ai.data != NULL)
- {
- ret->timeout=ASN1_INTEGER_get(aip);
- OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
- }
- else
- ret->timeout=3;
-
- if (ret->peer != NULL)
- {
- X509_free(ret->peer);
- ret->peer=NULL;
- }
- M_ASN1_D2I_get_EXP_opt(ret->peer,d2i_X509,3);
-
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,4);
-
- if(os.data != NULL)
- {
- if (os.length > SSL_MAX_SID_CTX_LENGTH)
- {
- c.error=SSL_R_BAD_LENGTH;
- goto err;
- }
- else
- {
- ret->sid_ctx_length=os.length;
- memcpy(ret->sid_ctx,os.data,os.length);
- }
- OPENSSL_free(os.data); os.data=NULL; os.length=0;
- }
- else
- ret->sid_ctx_length=0;
-
- ai.length=0;
- M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,5);
- if (ai.data != NULL)
- {
- ret->verify_result=ASN1_INTEGER_get(aip);
- OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
- }
- else
- ret->verify_result=X509_V_OK;
-
-#ifndef OPENSSL_NO_TLSEXT
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
- if (os.data)
- {
- ret->tlsext_hostname = BUF_strndup((char *)os.data, os.length);
- OPENSSL_free(os.data);
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->tlsext_hostname=NULL;
-#endif /* OPENSSL_NO_TLSEXT */
-
-#ifndef OPENSSL_NO_PSK
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
- if (os.data)
- {
- ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length);
- OPENSSL_free(os.data);
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->psk_identity_hint=NULL;
-
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
- if (os.data)
- {
- ret->psk_identity = BUF_strndup((char *)os.data, os.length);
- OPENSSL_free(os.data);
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->psk_identity=NULL;
-#endif /* OPENSSL_NO_PSK */
-
-#ifndef OPENSSL_NO_TLSEXT
- ai.length=0;
- M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,9);
- if (ai.data != NULL)
- {
- ret->tlsext_tick_lifetime_hint=ASN1_INTEGER_get(aip);
- OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
- }
- else if (ret->tlsext_ticklen && ret->session_id_length)
- ret->tlsext_tick_lifetime_hint = -1;
- else
- ret->tlsext_tick_lifetime_hint=0;
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10);
- if (os.data)
- {
- ret->tlsext_tick = os.data;
- ret->tlsext_ticklen = os.length;
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->tlsext_tick=NULL;
-#endif /* OPENSSL_NO_TLSEXT */
-#ifndef OPENSSL_NO_COMP
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,11);
- if (os.data)
- {
- ret->compress_meth = os.data[0];
- OPENSSL_free(os.data);
- os.data = NULL;
- }
-#endif
-
-#ifndef OPENSSL_NO_SRP
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,12);
- if (os.data)
- {
- ret->srp_username = BUF_strndup((char *)os.data, os.length);
- OPENSSL_free(os.data);
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->srp_username=NULL;
-#endif /* OPENSSL_NO_SRP */
-
- M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
- }
diff --git a/drivers/builtin_openssl/ssl/ssl_cert.c b/drivers/builtin_openssl/ssl/ssl_cert.c
deleted file mode 100644
index d2d358a3e5..0000000000
--- a/drivers/builtin_openssl/ssl/ssl_cert.c
+++ /dev/null
@@ -1,863 +0,0 @@
-/*! \file ssl/ssl_cert.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECC cipher suite support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-
-#include <stdio.h>
-
-#include "e_os.h"
-#ifndef NO_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#define DISABLE_O_DIR
-
-#ifndef DISABLE_O_DIR
-#include "o_dir.h"
-#endif
-
-#include <openssl/objects.h>
-#include <openssl/bio.h>
-#include <openssl/pem.h>
-#include <openssl/x509v3.h>
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#endif
-#include <openssl/bn.h>
-#include "ssl_locl.h"
-
-int SSL_get_ex_data_X509_STORE_CTX_idx(void)
- {
- static volatile int ssl_x509_store_ctx_idx= -1;
- int got_write_lock = 0;
-
- CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
-
- if (ssl_x509_store_ctx_idx < 0)
- {
- CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
- CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
- got_write_lock = 1;
-
- if (ssl_x509_store_ctx_idx < 0)
- {
- ssl_x509_store_ctx_idx=X509_STORE_CTX_get_ex_new_index(
- 0,"SSL for verify callback",NULL,NULL,NULL);
- }
- }
-
- if (got_write_lock)
- CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
- else
- CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
-
- return ssl_x509_store_ctx_idx;
- }
-
-static void ssl_cert_set_default_md(CERT *cert)
- {
- /* Set digest values to defaults */
-#ifndef OPENSSL_NO_DSA
- cert->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
-#endif
-#ifndef OPENSSL_NO_RSA
- cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
- cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
-#endif
-#ifndef OPENSSL_NO_ECDSA
- cert->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
-#endif
- }
-
-CERT *ssl_cert_new(void)
- {
- CERT *ret;
-
- ret=(CERT *)OPENSSL_malloc(sizeof(CERT));
- if (ret == NULL)
- {
- SSLerr(SSL_F_SSL_CERT_NEW,ERR_R_MALLOC_FAILURE);
- return(NULL);
- }
- memset(ret,0,sizeof(CERT));
-
- ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]);
- ret->references=1;
- ssl_cert_set_default_md(ret);
- return(ret);
- }
-
-CERT *ssl_cert_dup(CERT *cert)
- {
- CERT *ret;
- int i;
-
- ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
- if (ret == NULL)
- {
- SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
- return(NULL);
- }
-
- memset(ret, 0, sizeof(CERT));
-
- ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]];
- /* or ret->key = ret->pkeys + (cert->key - cert->pkeys),
- * if you find that more readable */
-
- ret->valid = cert->valid;
- ret->mask_k = cert->mask_k;
- ret->mask_a = cert->mask_a;
- ret->export_mask_k = cert->export_mask_k;
- ret->export_mask_a = cert->export_mask_a;
-
-#ifndef OPENSSL_NO_RSA
- if (cert->rsa_tmp != NULL)
- {
- RSA_up_ref(cert->rsa_tmp);
- ret->rsa_tmp = cert->rsa_tmp;
- }
- ret->rsa_tmp_cb = cert->rsa_tmp_cb;
-#endif
-
-#ifndef OPENSSL_NO_DH
- if (cert->dh_tmp != NULL)
- {
- ret->dh_tmp = DHparams_dup(cert->dh_tmp);
- if (ret->dh_tmp == NULL)
- {
- SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_DH_LIB);
- goto err;
- }
- if (cert->dh_tmp->priv_key)
- {
- BIGNUM *b = BN_dup(cert->dh_tmp->priv_key);
- if (!b)
- {
- SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB);
- goto err;
- }
- ret->dh_tmp->priv_key = b;
- }
- if (cert->dh_tmp->pub_key)
- {
- BIGNUM *b = BN_dup(cert->dh_tmp->pub_key);
- if (!b)
- {
- SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB);
- goto err;
- }
- ret->dh_tmp->pub_key = b;
- }
- }
- ret->dh_tmp_cb = cert->dh_tmp_cb;
-#endif
-
-#ifndef OPENSSL_NO_ECDH
- if (cert->ecdh_tmp)
- {
- ret->ecdh_tmp = EC_KEY_dup(cert->ecdh_tmp);
- if (ret->ecdh_tmp == NULL)
- {
- SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_EC_LIB);
- goto err;
- }
- }
- ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
-#endif
-
- for (i = 0; i < SSL_PKEY_NUM; i++)
- {
- if (cert->pkeys[i].x509 != NULL)
- {
- ret->pkeys[i].x509 = cert->pkeys[i].x509;
- CRYPTO_add(&ret->pkeys[i].x509->references, 1,
- CRYPTO_LOCK_X509);
- }
-
- if (cert->pkeys[i].privatekey != NULL)
- {
- ret->pkeys[i].privatekey = cert->pkeys[i].privatekey;
- CRYPTO_add(&ret->pkeys[i].privatekey->references, 1,
- CRYPTO_LOCK_EVP_PKEY);
-
- switch(i)
- {
- /* If there was anything special to do for
- * certain types of keys, we'd do it here.
- * (Nothing at the moment, I think.) */
-
- case SSL_PKEY_RSA_ENC:
- case SSL_PKEY_RSA_SIGN:
- /* We have an RSA key. */
- break;
-
- case SSL_PKEY_DSA_SIGN:
- /* We have a DSA key. */
- break;
-
- case SSL_PKEY_DH_RSA:
- case SSL_PKEY_DH_DSA:
- /* We have a DH key. */
- break;
-
- case SSL_PKEY_ECC:
- /* We have an ECC key */
- break;
-
- default:
- /* Can't happen. */
- SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG);
- }
- }
- }
-
- /* ret->extra_certs *should* exist, but currently the own certificate
- * chain is held inside SSL_CTX */
-
- ret->references=1;
- /* Set digests to defaults. NB: we don't copy existing values as they
- * will be set during handshake.
- */
- ssl_cert_set_default_md(ret);
-
- return(ret);
-
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH)
-err:
-#endif
-#ifndef OPENSSL_NO_RSA
- if (ret->rsa_tmp != NULL)
- RSA_free(ret->rsa_tmp);
-#endif
-#ifndef OPENSSL_NO_DH
- if (ret->dh_tmp != NULL)
- DH_free(ret->dh_tmp);
-#endif
-#ifndef OPENSSL_NO_ECDH
- if (ret->ecdh_tmp != NULL)
- EC_KEY_free(ret->ecdh_tmp);
-#endif
-
- for (i = 0; i < SSL_PKEY_NUM; i++)
- {
- if (ret->pkeys[i].x509 != NULL)
- X509_free(ret->pkeys[i].x509);
- if (ret->pkeys[i].privatekey != NULL)
- EVP_PKEY_free(ret->pkeys[i].privatekey);
- }
-
- return NULL;
- }
-
-
-void ssl_cert_free(CERT *c)
- {
- int i;
-
- if(c == NULL)
- return;
-
- i=CRYPTO_add(&c->references,-1,CRYPTO_LOCK_SSL_CERT);
-#ifdef REF_PRINT
- REF_PRINT("CERT",c);
-#endif
- if (i > 0) return;
-#ifdef REF_CHECK
- if (i < 0)
- {
- fprintf(stderr,"ssl_cert_free, bad reference count\n");
- abort(); /* ok */
- }
-#endif
-
-#ifndef OPENSSL_NO_RSA
- if (c->rsa_tmp) RSA_free(c->rsa_tmp);
-#endif
-#ifndef OPENSSL_NO_DH
- if (c->dh_tmp) DH_free(c->dh_tmp);
-#endif
-#ifndef OPENSSL_NO_ECDH
- if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp);
-#endif
-
- for (i=0; i<SSL_PKEY_NUM; i++)
- {
- if (c->pkeys[i].x509 != NULL)
- X509_free(c->pkeys[i].x509);
- if (c->pkeys[i].privatekey != NULL)
- EVP_PKEY_free(c->pkeys[i].privatekey);
-#if 0
- if (c->pkeys[i].publickey != NULL)
- EVP_PKEY_free(c->pkeys[i].publickey);
-#endif
- }
- OPENSSL_free(c);
- }
-
-int ssl_cert_inst(CERT **o)
- {
- /* Create a CERT if there isn't already one
- * (which cannot really happen, as it is initially created in
- * SSL_CTX_new; but the earlier code usually allows for that one
- * being non-existant, so we follow that behaviour, as it might
- * turn out that there actually is a reason for it -- but I'm
- * not sure that *all* of the existing code could cope with
- * s->cert being NULL, otherwise we could do without the
- * initialization in SSL_CTX_new).
- */
-
- if (o == NULL)
- {
- SSLerr(SSL_F_SSL_CERT_INST, ERR_R_PASSED_NULL_PARAMETER);
- return(0);
- }
- if (*o == NULL)
- {
- if ((*o = ssl_cert_new()) == NULL)
- {
- SSLerr(SSL_F_SSL_CERT_INST, ERR_R_MALLOC_FAILURE);
- return(0);
- }
- }
- return(1);
- }
-
-
-SESS_CERT *ssl_sess_cert_new(void)
- {
- SESS_CERT *ret;
-
- ret = OPENSSL_malloc(sizeof *ret);
- if (ret == NULL)
- {
- SSLerr(SSL_F_SSL_SESS_CERT_NEW, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
-
- memset(ret, 0 ,sizeof *ret);
- ret->peer_key = &(ret->peer_pkeys[SSL_PKEY_RSA_ENC]);
- ret->references = 1;
-
- return ret;
- }
-
-void ssl_sess_cert_free(SESS_CERT *sc)
- {
- int i;
-
- if (sc == NULL)
- return;
-
- i = CRYPTO_add(&sc->references, -1, CRYPTO_LOCK_SSL_SESS_CERT);
-#ifdef REF_PRINT
- REF_PRINT("SESS_CERT", sc);
-#endif
- if (i > 0)
- return;
-#ifdef REF_CHECK
- if (i < 0)
- {
- fprintf(stderr,"ssl_sess_cert_free, bad reference count\n");
- abort(); /* ok */
- }
-#endif
-
- /* i == 0 */
- if (sc->cert_chain != NULL)
- sk_X509_pop_free(sc->cert_chain, X509_free);
- for (i = 0; i < SSL_PKEY_NUM; i++)
- {
- if (sc->peer_pkeys[i].x509 != NULL)
- X509_free(sc->peer_pkeys[i].x509);
-#if 0 /* We don't have the peer's private key. These lines are just
- * here as a reminder that we're still using a not-quite-appropriate
- * data structure. */
- if (sc->peer_pkeys[i].privatekey != NULL)
- EVP_PKEY_free(sc->peer_pkeys[i].privatekey);
-#endif
- }
-
-#ifndef OPENSSL_NO_RSA
- if (sc->peer_rsa_tmp != NULL)
- RSA_free(sc->peer_rsa_tmp);
-#endif
-#ifndef OPENSSL_NO_DH
- if (sc->peer_dh_tmp != NULL)
- DH_free(sc->peer_dh_tmp);
-#endif
-#ifndef OPENSSL_NO_ECDH
- if (sc->peer_ecdh_tmp != NULL)
- EC_KEY_free(sc->peer_ecdh_tmp);
-#endif
-
- OPENSSL_free(sc);
- }
-
-int ssl_set_peer_cert_type(SESS_CERT *sc,int type)
- {
- sc->peer_cert_type = type;
- return(1);
- }
-
-int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
- {
- X509 *x;
- int i;
- X509_STORE_CTX ctx;
-
- if ((sk == NULL) || (sk_X509_num(sk) == 0))
- return(0);
-
- x=sk_X509_value(sk,0);
- if(!X509_STORE_CTX_init(&ctx,s->ctx->cert_store,x,sk))
- {
- SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB);
- return(0);
- }
-#if 0
- if (SSL_get_verify_depth(s) >= 0)
- X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s));
-#endif
- X509_STORE_CTX_set_ex_data(&ctx,SSL_get_ex_data_X509_STORE_CTX_idx(),s);
-
- /* We need to inherit the verify parameters. These can be determined by
- * the context: if its a server it will verify SSL client certificates
- * or vice versa.
- */
-
- X509_STORE_CTX_set_default(&ctx,
- s->server ? "ssl_client" : "ssl_server");
- /* Anything non-default in "param" should overwrite anything in the
- * ctx.
- */
- X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param);
-
- if (s->verify_callback)
- X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback);
-
- if (s->ctx->app_verify_callback != NULL)
-#if 1 /* new with OpenSSL 0.9.7 */
- i=s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg);
-#else
- i=s->ctx->app_verify_callback(&ctx); /* should pass app_verify_arg */
-#endif
- else
- {
-#ifndef OPENSSL_NO_X509_VERIFY
- i=X509_verify_cert(&ctx);
-#else
- i=0;
- ctx.error=X509_V_ERR_APPLICATION_VERIFICATION;
- SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,SSL_R_NO_VERIFY_CALLBACK);
-#endif
- }
-
- s->verify_result=ctx.error;
- X509_STORE_CTX_cleanup(&ctx);
-
- return(i);
- }
-
-static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,STACK_OF(X509_NAME) *name_list)
- {
- if (*ca_list != NULL)
- sk_X509_NAME_pop_free(*ca_list,X509_NAME_free);
-
- *ca_list=name_list;
- }
-
-STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk)
- {
- int i;
- STACK_OF(X509_NAME) *ret;
- X509_NAME *name;
-
- ret=sk_X509_NAME_new_null();
- for (i=0; i<sk_X509_NAME_num(sk); i++)
- {
- name=X509_NAME_dup(sk_X509_NAME_value(sk,i));
- if ((name == NULL) || !sk_X509_NAME_push(ret,name))
- {
- sk_X509_NAME_pop_free(ret,X509_NAME_free);
- return(NULL);
- }
- }
- return(ret);
- }
-
-void SSL_set_client_CA_list(SSL *s,STACK_OF(X509_NAME) *name_list)
- {
- set_client_CA_list(&(s->client_CA),name_list);
- }
-
-void SSL_CTX_set_client_CA_list(SSL_CTX *ctx,STACK_OF(X509_NAME) *name_list)
- {
- set_client_CA_list(&(ctx->client_CA),name_list);
- }
-
-STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx)
- {
- return(ctx->client_CA);
- }
-
-STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s)
- {
- if (s->type == SSL_ST_CONNECT)
- { /* we are in the client */
- if (((s->version>>8) == SSL3_VERSION_MAJOR) &&
- (s->s3 != NULL))
- return(s->s3->tmp.ca_names);
- else
- return(NULL);
- }
- else
- {
- if (s->client_CA != NULL)
- return(s->client_CA);
- else
- return(s->ctx->client_CA);
- }
- }
-
-static int add_client_CA(STACK_OF(X509_NAME) **sk,X509 *x)
- {
- X509_NAME *name;
-
- if (x == NULL) return(0);
- if ((*sk == NULL) && ((*sk=sk_X509_NAME_new_null()) == NULL))
- return(0);
-
- if ((name=X509_NAME_dup(X509_get_subject_name(x))) == NULL)
- return(0);
-
- if (!sk_X509_NAME_push(*sk,name))
- {
- X509_NAME_free(name);
- return(0);
- }
- return(1);
- }
-
-int SSL_add_client_CA(SSL *ssl,X509 *x)
- {
- return(add_client_CA(&(ssl->client_CA),x));
- }
-
-int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x)
- {
- return(add_client_CA(&(ctx->client_CA),x));
- }
-
-static int xname_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
- {
- return(X509_NAME_cmp(*a,*b));
- }
-
-#ifndef OPENSSL_NO_STDIO
-/*!
- * Load CA certs from a file into a ::STACK. Note that it is somewhat misnamed;
- * it doesn't really have anything to do with clients (except that a common use
- * for a stack of CAs is to send it to the client). Actually, it doesn't have
- * much to do with CAs, either, since it will load any old cert.
- * \param file the file containing one or more certs.
- * \return a ::STACK containing the certs.
- */
-STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file)
- {
- BIO *in;
- X509 *x=NULL;
- X509_NAME *xn=NULL;
- STACK_OF(X509_NAME) *ret = NULL,*sk;
-
- sk=sk_X509_NAME_new(xname_cmp);
-
- in=BIO_new(BIO_s_file_internal());
-
- if ((sk == NULL) || (in == NULL))
- {
- SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!BIO_read_filename(in,file))
- goto err;
-
- for (;;)
- {
- if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL)
- break;
- if (ret == NULL)
- {
- ret = sk_X509_NAME_new_null();
- if (ret == NULL)
- {
- SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- }
- if ((xn=X509_get_subject_name(x)) == NULL) goto err;
- /* check for duplicates */
- xn=X509_NAME_dup(xn);
- if (xn == NULL) goto err;
- if (sk_X509_NAME_find(sk,xn) >= 0)
- X509_NAME_free(xn);
- else
- {
- sk_X509_NAME_push(sk,xn);
- sk_X509_NAME_push(ret,xn);
- }
- }
-
- if (0)
- {
-err:
- if (ret != NULL) sk_X509_NAME_pop_free(ret,X509_NAME_free);
- ret=NULL;
- }
- if (sk != NULL) sk_X509_NAME_free(sk);
- if (in != NULL) BIO_free(in);
- if (x != NULL) X509_free(x);
- if (ret != NULL)
- ERR_clear_error();
- return(ret);
- }
-#endif
-
-/*!
- * Add a file of certs to a stack.
- * \param stack the stack to add to.
- * \param file the file to add from. All certs in this file that are not
- * already in the stack will be added.
- * \return 1 for success, 0 for failure. Note that in the case of failure some
- * certs may have been added to \c stack.
- */
-
-int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
- const char *file)
- {
- BIO *in;
- X509 *x=NULL;
- X509_NAME *xn=NULL;
- int ret=1;
- int (*oldcmp)(const X509_NAME * const *a, const X509_NAME * const *b);
-
- oldcmp=sk_X509_NAME_set_cmp_func(stack,xname_cmp);
-
- in=BIO_new(BIO_s_file_internal());
-
- if (in == NULL)
- {
- SSLerr(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!BIO_read_filename(in,file))
- goto err;
-
- for (;;)
- {
- if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL)
- break;
- if ((xn=X509_get_subject_name(x)) == NULL) goto err;
- xn=X509_NAME_dup(xn);
- if (xn == NULL) goto err;
- if (sk_X509_NAME_find(stack,xn) >= 0)
- X509_NAME_free(xn);
- else
- sk_X509_NAME_push(stack,xn);
- }
-
- ERR_clear_error();
-
- if (0)
- {
-err:
- ret=0;
- }
- if(in != NULL)
- BIO_free(in);
- if(x != NULL)
- X509_free(x);
-
- (void)sk_X509_NAME_set_cmp_func(stack,oldcmp);
-
- return ret;
- }
-
-/*!
- * Add a directory of certs to a stack.
- * \param stack the stack to append to.
- * \param dir the directory to append from. All files in this directory will be
- * examined as potential certs. Any that are acceptable to
- * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will be
- * included.
- * \return 1 for success, 0 for failure. Note that in the case of failure some
- * certs may have been added to \c stack.
- */
-
-int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
- const char *dir)
- {
-
- return 0;
-
-#ifndef DISABLE_O_DIR
- OPENSSL_DIR_CTX *d = NULL;
- const char *filename;
- int ret = 0;
-
- CRYPTO_w_lock(CRYPTO_LOCK_READDIR);
-
- /* Note that a side effect is that the CAs will be sorted by name */
-
- while((filename = OPENSSL_DIR_read(&d, dir)))
- {
- char buf[1024];
- int r;
-
- if(strlen(dir)+strlen(filename)+2 > sizeof buf)
- {
- SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,SSL_R_PATH_TOO_LONG);
- goto err;
- }
-
-#ifdef OPENSSL_SYS_VMS
- r = BIO_snprintf(buf,sizeof buf,"%s%s",dir,filename);
-#else
- r = BIO_snprintf(buf,sizeof buf,"%s/%s",dir,filename);
-#endif
- if (r <= 0 || r >= (int)sizeof(buf))
- goto err;
- if(!SSL_add_file_cert_subjects_to_stack(stack,buf))
- goto err;
- }
-
- if (errno)
- {
- SYSerr(SYS_F_OPENDIR, get_last_sys_error());
- ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')");
- SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB);
- goto err;
- }
-
- ret = 1;
-
-err:
- if (d) OPENSSL_DIR_end(&d);
- CRYPTO_w_unlock(CRYPTO_LOCK_READDIR);
- return ret;
-#endif
- }
-
diff --git a/drivers/builtin_openssl/ssl/ssl_err.c b/drivers/builtin_openssl/ssl/ssl_err.c
deleted file mode 100644
index 370fb57e3b..0000000000
--- a/drivers/builtin_openssl/ssl/ssl_err.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/* ssl/ssl_err.c */
-/* ====================================================================
- * Copyright (c) 1999-2011 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-/* NOTE: this file was auto generated by the mkerr.pl script: any changes
- * made to it will be overwritten when the script next updates this file,
- * only reason strings will be preserved.
- */
-
-#include <stdio.h>
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-
-/* BEGIN ERROR CODES */
-#ifndef OPENSSL_NO_ERR
-
-#define ERR_FUNC(func) ERR_PACK(ERR_LIB_SSL,func,0)
-#define ERR_REASON(reason) ERR_PACK(ERR_LIB_SSL,0,reason)
-
-static ERR_STRING_DATA SSL_str_functs[]=
- {
-{ERR_FUNC(SSL_F_CLIENT_CERTIFICATE), "CLIENT_CERTIFICATE"},
-{ERR_FUNC(SSL_F_CLIENT_FINISHED), "CLIENT_FINISHED"},
-{ERR_FUNC(SSL_F_CLIENT_HELLO), "CLIENT_HELLO"},
-{ERR_FUNC(SSL_F_CLIENT_MASTER_KEY), "CLIENT_MASTER_KEY"},
-{ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"},
-{ERR_FUNC(SSL_F_DO_DTLS1_WRITE), "DO_DTLS1_WRITE"},
-{ERR_FUNC(SSL_F_DO_SSL3_WRITE), "DO_SSL3_WRITE"},
-{ERR_FUNC(SSL_F_DTLS1_ACCEPT), "DTLS1_ACCEPT"},
-{ERR_FUNC(SSL_F_DTLS1_ADD_CERT_TO_BUF), "DTLS1_ADD_CERT_TO_BUF"},
-{ERR_FUNC(SSL_F_DTLS1_BUFFER_RECORD), "DTLS1_BUFFER_RECORD"},
-{ERR_FUNC(SSL_F_DTLS1_CHECK_TIMEOUT_NUM), "DTLS1_CHECK_TIMEOUT_NUM"},
-{ERR_FUNC(SSL_F_DTLS1_CLIENT_HELLO), "DTLS1_CLIENT_HELLO"},
-{ERR_FUNC(SSL_F_DTLS1_CONNECT), "DTLS1_CONNECT"},
-{ERR_FUNC(SSL_F_DTLS1_ENC), "DTLS1_ENC"},
-{ERR_FUNC(SSL_F_DTLS1_GET_HELLO_VERIFY), "DTLS1_GET_HELLO_VERIFY"},
-{ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE), "DTLS1_GET_MESSAGE"},
-{ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT), "DTLS1_GET_MESSAGE_FRAGMENT"},
-{ERR_FUNC(SSL_F_DTLS1_GET_RECORD), "DTLS1_GET_RECORD"},
-{ERR_FUNC(SSL_F_DTLS1_HANDLE_TIMEOUT), "DTLS1_HANDLE_TIMEOUT"},
-{ERR_FUNC(SSL_F_DTLS1_HEARTBEAT), "DTLS1_HEARTBEAT"},
-{ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN), "DTLS1_OUTPUT_CERT_CHAIN"},
-{ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT), "DTLS1_PREPROCESS_FRAGMENT"},
-{ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE), "DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"},
-{ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD), "DTLS1_PROCESS_RECORD"},
-{ERR_FUNC(SSL_F_DTLS1_READ_BYTES), "DTLS1_READ_BYTES"},
-{ERR_FUNC(SSL_F_DTLS1_READ_FAILED), "DTLS1_READ_FAILED"},
-{ERR_FUNC(SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST), "DTLS1_SEND_CERTIFICATE_REQUEST"},
-{ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE), "DTLS1_SEND_CLIENT_CERTIFICATE"},
-{ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE), "DTLS1_SEND_CLIENT_KEY_EXCHANGE"},
-{ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_VERIFY), "DTLS1_SEND_CLIENT_VERIFY"},
-{ERR_FUNC(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST), "DTLS1_SEND_HELLO_VERIFY_REQUEST"},
-{ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_CERTIFICATE), "DTLS1_SEND_SERVER_CERTIFICATE"},
-{ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_HELLO), "DTLS1_SEND_SERVER_HELLO"},
-{ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE), "DTLS1_SEND_SERVER_KEY_EXCHANGE"},
-{ERR_FUNC(SSL_F_DTLS1_WRITE_APP_DATA_BYTES), "DTLS1_WRITE_APP_DATA_BYTES"},
-{ERR_FUNC(SSL_F_GET_CLIENT_FINISHED), "GET_CLIENT_FINISHED"},
-{ERR_FUNC(SSL_F_GET_CLIENT_HELLO), "GET_CLIENT_HELLO"},
-{ERR_FUNC(SSL_F_GET_CLIENT_MASTER_KEY), "GET_CLIENT_MASTER_KEY"},
-{ERR_FUNC(SSL_F_GET_SERVER_FINISHED), "GET_SERVER_FINISHED"},
-{ERR_FUNC(SSL_F_GET_SERVER_HELLO), "GET_SERVER_HELLO"},
-{ERR_FUNC(SSL_F_GET_SERVER_VERIFY), "GET_SERVER_VERIFY"},
-{ERR_FUNC(SSL_F_I2D_SSL_SESSION), "i2d_SSL_SESSION"},
-{ERR_FUNC(SSL_F_READ_N), "READ_N"},
-{ERR_FUNC(SSL_F_REQUEST_CERTIFICATE), "REQUEST_CERTIFICATE"},
-{ERR_FUNC(SSL_F_SERVER_FINISH), "SERVER_FINISH"},
-{ERR_FUNC(SSL_F_SERVER_HELLO), "SERVER_HELLO"},
-{ERR_FUNC(SSL_F_SERVER_VERIFY), "SERVER_VERIFY"},
-{ERR_FUNC(SSL_F_SSL23_ACCEPT), "SSL23_ACCEPT"},
-{ERR_FUNC(SSL_F_SSL23_CLIENT_HELLO), "SSL23_CLIENT_HELLO"},
-{ERR_FUNC(SSL_F_SSL23_CONNECT), "SSL23_CONNECT"},
-{ERR_FUNC(SSL_F_SSL23_GET_CLIENT_HELLO), "SSL23_GET_CLIENT_HELLO"},
-{ERR_FUNC(SSL_F_SSL23_GET_SERVER_HELLO), "SSL23_GET_SERVER_HELLO"},
-{ERR_FUNC(SSL_F_SSL23_PEEK), "SSL23_PEEK"},
-{ERR_FUNC(SSL_F_SSL23_READ), "SSL23_READ"},
-{ERR_FUNC(SSL_F_SSL23_WRITE), "SSL23_WRITE"},
-{ERR_FUNC(SSL_F_SSL2_ACCEPT), "SSL2_ACCEPT"},
-{ERR_FUNC(SSL_F_SSL2_CONNECT), "SSL2_CONNECT"},
-{ERR_FUNC(SSL_F_SSL2_ENC_INIT), "SSL2_ENC_INIT"},
-{ERR_FUNC(SSL_F_SSL2_GENERATE_KEY_MATERIAL), "SSL2_GENERATE_KEY_MATERIAL"},
-{ERR_FUNC(SSL_F_SSL2_PEEK), "SSL2_PEEK"},
-{ERR_FUNC(SSL_F_SSL2_READ), "SSL2_READ"},
-{ERR_FUNC(SSL_F_SSL2_READ_INTERNAL), "SSL2_READ_INTERNAL"},
-{ERR_FUNC(SSL_F_SSL2_SET_CERTIFICATE), "SSL2_SET_CERTIFICATE"},
-{ERR_FUNC(SSL_F_SSL2_WRITE), "SSL2_WRITE"},
-{ERR_FUNC(SSL_F_SSL3_ACCEPT), "SSL3_ACCEPT"},
-{ERR_FUNC(SSL_F_SSL3_ADD_CERT_TO_BUF), "SSL3_ADD_CERT_TO_BUF"},
-{ERR_FUNC(SSL_F_SSL3_CALLBACK_CTRL), "SSL3_CALLBACK_CTRL"},
-{ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "SSL3_CHANGE_CIPHER_STATE"},
-{ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM), "SSL3_CHECK_CERT_AND_ALGORITHM"},
-{ERR_FUNC(SSL_F_SSL3_CHECK_CLIENT_HELLO), "SSL3_CHECK_CLIENT_HELLO"},
-{ERR_FUNC(SSL_F_SSL3_CLIENT_HELLO), "SSL3_CLIENT_HELLO"},
-{ERR_FUNC(SSL_F_SSL3_CONNECT), "SSL3_CONNECT"},
-{ERR_FUNC(SSL_F_SSL3_CTRL), "SSL3_CTRL"},
-{ERR_FUNC(SSL_F_SSL3_CTX_CTRL), "SSL3_CTX_CTRL"},
-{ERR_FUNC(SSL_F_SSL3_DIGEST_CACHED_RECORDS), "SSL3_DIGEST_CACHED_RECORDS"},
-{ERR_FUNC(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC), "SSL3_DO_CHANGE_CIPHER_SPEC"},
-{ERR_FUNC(SSL_F_SSL3_ENC), "SSL3_ENC"},
-{ERR_FUNC(SSL_F_SSL3_GENERATE_KEY_BLOCK), "SSL3_GENERATE_KEY_BLOCK"},
-{ERR_FUNC(SSL_F_SSL3_GET_CERTIFICATE_REQUEST), "SSL3_GET_CERTIFICATE_REQUEST"},
-{ERR_FUNC(SSL_F_SSL3_GET_CERT_STATUS), "SSL3_GET_CERT_STATUS"},
-{ERR_FUNC(SSL_F_SSL3_GET_CERT_VERIFY), "SSL3_GET_CERT_VERIFY"},
-{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_CERTIFICATE), "SSL3_GET_CLIENT_CERTIFICATE"},
-{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_HELLO), "SSL3_GET_CLIENT_HELLO"},
-{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE), "SSL3_GET_CLIENT_KEY_EXCHANGE"},
-{ERR_FUNC(SSL_F_SSL3_GET_FINISHED), "SSL3_GET_FINISHED"},
-{ERR_FUNC(SSL_F_SSL3_GET_KEY_EXCHANGE), "SSL3_GET_KEY_EXCHANGE"},
-{ERR_FUNC(SSL_F_SSL3_GET_MESSAGE), "SSL3_GET_MESSAGE"},
-{ERR_FUNC(SSL_F_SSL3_GET_NEW_SESSION_TICKET), "SSL3_GET_NEW_SESSION_TICKET"},
-{ERR_FUNC(SSL_F_SSL3_GET_NEXT_PROTO), "SSL3_GET_NEXT_PROTO"},
-{ERR_FUNC(SSL_F_SSL3_GET_RECORD), "SSL3_GET_RECORD"},
-{ERR_FUNC(SSL_F_SSL3_GET_SERVER_CERTIFICATE), "SSL3_GET_SERVER_CERTIFICATE"},
-{ERR_FUNC(SSL_F_SSL3_GET_SERVER_DONE), "SSL3_GET_SERVER_DONE"},
-{ERR_FUNC(SSL_F_SSL3_GET_SERVER_HELLO), "SSL3_GET_SERVER_HELLO"},
-{ERR_FUNC(SSL_F_SSL3_HANDSHAKE_MAC), "ssl3_handshake_mac"},
-{ERR_FUNC(SSL_F_SSL3_NEW_SESSION_TICKET), "SSL3_NEW_SESSION_TICKET"},
-{ERR_FUNC(SSL_F_SSL3_OUTPUT_CERT_CHAIN), "SSL3_OUTPUT_CERT_CHAIN"},
-{ERR_FUNC(SSL_F_SSL3_PEEK), "SSL3_PEEK"},
-{ERR_FUNC(SSL_F_SSL3_READ_BYTES), "SSL3_READ_BYTES"},
-{ERR_FUNC(SSL_F_SSL3_READ_N), "SSL3_READ_N"},
-{ERR_FUNC(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST), "SSL3_SEND_CERTIFICATE_REQUEST"},
-{ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE), "SSL3_SEND_CLIENT_CERTIFICATE"},
-{ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE), "SSL3_SEND_CLIENT_KEY_EXCHANGE"},
-{ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_VERIFY), "SSL3_SEND_CLIENT_VERIFY"},
-{ERR_FUNC(SSL_F_SSL3_SEND_SERVER_CERTIFICATE), "SSL3_SEND_SERVER_CERTIFICATE"},
-{ERR_FUNC(SSL_F_SSL3_SEND_SERVER_HELLO), "SSL3_SEND_SERVER_HELLO"},
-{ERR_FUNC(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE), "SSL3_SEND_SERVER_KEY_EXCHANGE"},
-{ERR_FUNC(SSL_F_SSL3_SETUP_KEY_BLOCK), "SSL3_SETUP_KEY_BLOCK"},
-{ERR_FUNC(SSL_F_SSL3_SETUP_READ_BUFFER), "SSL3_SETUP_READ_BUFFER"},
-{ERR_FUNC(SSL_F_SSL3_SETUP_WRITE_BUFFER), "SSL3_SETUP_WRITE_BUFFER"},
-{ERR_FUNC(SSL_F_SSL3_WRITE_BYTES), "SSL3_WRITE_BYTES"},
-{ERR_FUNC(SSL_F_SSL3_WRITE_PENDING), "SSL3_WRITE_PENDING"},
-{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT"},
-{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT), "SSL_ADD_CLIENTHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT), "SSL_ADD_CLIENTHELLO_USE_SRTP_EXT"},
-{ERR_FUNC(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK), "SSL_add_dir_cert_subjects_to_stack"},
-{ERR_FUNC(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK), "SSL_add_file_cert_subjects_to_stack"},
-{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT), "SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT"},
-{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT), "SSL_ADD_SERVERHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT), "SSL_ADD_SERVERHELLO_USE_SRTP_EXT"},
-{ERR_FUNC(SSL_F_SSL_BAD_METHOD), "SSL_BAD_METHOD"},
-{ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST), "SSL_BYTES_TO_CIPHER_LIST"},
-{ERR_FUNC(SSL_F_SSL_CERT_DUP), "SSL_CERT_DUP"},
-{ERR_FUNC(SSL_F_SSL_CERT_INST), "SSL_CERT_INST"},
-{ERR_FUNC(SSL_F_SSL_CERT_INSTANTIATE), "SSL_CERT_INSTANTIATE"},
-{ERR_FUNC(SSL_F_SSL_CERT_NEW), "SSL_CERT_NEW"},
-{ERR_FUNC(SSL_F_SSL_CHECK_PRIVATE_KEY), "SSL_check_private_key"},
-{ERR_FUNC(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT), "SSL_CHECK_SERVERHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG), "SSL_CHECK_SRVR_ECC_CERT_AND_ALG"},
-{ERR_FUNC(SSL_F_SSL_CIPHER_PROCESS_RULESTR), "SSL_CIPHER_PROCESS_RULESTR"},
-{ERR_FUNC(SSL_F_SSL_CIPHER_STRENGTH_SORT), "SSL_CIPHER_STRENGTH_SORT"},
-{ERR_FUNC(SSL_F_SSL_CLEAR), "SSL_clear"},
-{ERR_FUNC(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD), "SSL_COMP_add_compression_method"},
-{ERR_FUNC(SSL_F_SSL_CREATE_CIPHER_LIST), "SSL_CREATE_CIPHER_LIST"},
-{ERR_FUNC(SSL_F_SSL_CTRL), "SSL_ctrl"},
-{ERR_FUNC(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY), "SSL_CTX_check_private_key"},
-{ERR_FUNC(SSL_F_SSL_CTX_MAKE_PROFILES), "SSL_CTX_MAKE_PROFILES"},
-{ERR_FUNC(SSL_F_SSL_CTX_NEW), "SSL_CTX_new"},
-{ERR_FUNC(SSL_F_SSL_CTX_SET_CIPHER_LIST), "SSL_CTX_set_cipher_list"},
-{ERR_FUNC(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE), "SSL_CTX_set_client_cert_engine"},
-{ERR_FUNC(SSL_F_SSL_CTX_SET_PURPOSE), "SSL_CTX_set_purpose"},
-{ERR_FUNC(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT), "SSL_CTX_set_session_id_context"},
-{ERR_FUNC(SSL_F_SSL_CTX_SET_SSL_VERSION), "SSL_CTX_set_ssl_version"},
-{ERR_FUNC(SSL_F_SSL_CTX_SET_TRUST), "SSL_CTX_set_trust"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE), "SSL_CTX_use_certificate"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1), "SSL_CTX_use_certificate_ASN1"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE), "SSL_CTX_use_certificate_chain_file"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE), "SSL_CTX_use_certificate_file"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY), "SSL_CTX_use_PrivateKey"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1), "SSL_CTX_use_PrivateKey_ASN1"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE), "SSL_CTX_use_PrivateKey_file"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT), "SSL_CTX_use_psk_identity_hint"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY), "SSL_CTX_use_RSAPrivateKey"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1), "SSL_CTX_use_RSAPrivateKey_ASN1"},
-{ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE), "SSL_CTX_use_RSAPrivateKey_file"},
-{ERR_FUNC(SSL_F_SSL_DO_HANDSHAKE), "SSL_do_handshake"},
-{ERR_FUNC(SSL_F_SSL_GET_NEW_SESSION), "SSL_GET_NEW_SESSION"},
-{ERR_FUNC(SSL_F_SSL_GET_PREV_SESSION), "SSL_GET_PREV_SESSION"},
-{ERR_FUNC(SSL_F_SSL_GET_SERVER_SEND_CERT), "SSL_GET_SERVER_SEND_CERT"},
-{ERR_FUNC(SSL_F_SSL_GET_SERVER_SEND_PKEY), "SSL_GET_SERVER_SEND_PKEY"},
-{ERR_FUNC(SSL_F_SSL_GET_SIGN_PKEY), "SSL_GET_SIGN_PKEY"},
-{ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "SSL_INIT_WBIO_BUFFER"},
-{ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE), "SSL_load_client_CA_file"},
-{ERR_FUNC(SSL_F_SSL_NEW), "SSL_new"},
-{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT"},
-{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT), "SSL_PARSE_CLIENTHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT), "SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT"},
-{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT), "SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT"},
-{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT), "SSL_PARSE_SERVERHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT), "SSL_PARSE_SERVERHELLO_USE_SRTP_EXT"},
-{ERR_FUNC(SSL_F_SSL_PEEK), "SSL_peek"},
-{ERR_FUNC(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT), "SSL_PREPARE_CLIENTHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT), "SSL_PREPARE_SERVERHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_SSL_READ), "SSL_read"},
-{ERR_FUNC(SSL_F_SSL_RSA_PRIVATE_DECRYPT), "SSL_RSA_PRIVATE_DECRYPT"},
-{ERR_FUNC(SSL_F_SSL_RSA_PUBLIC_ENCRYPT), "SSL_RSA_PUBLIC_ENCRYPT"},
-{ERR_FUNC(SSL_F_SSL_SESSION_NEW), "SSL_SESSION_new"},
-{ERR_FUNC(SSL_F_SSL_SESSION_PRINT_FP), "SSL_SESSION_print_fp"},
-{ERR_FUNC(SSL_F_SSL_SESSION_SET1_ID_CONTEXT), "SSL_SESSION_set1_id_context"},
-{ERR_FUNC(SSL_F_SSL_SESS_CERT_NEW), "SSL_SESS_CERT_NEW"},
-{ERR_FUNC(SSL_F_SSL_SET_CERT), "SSL_SET_CERT"},
-{ERR_FUNC(SSL_F_SSL_SET_CIPHER_LIST), "SSL_set_cipher_list"},
-{ERR_FUNC(SSL_F_SSL_SET_FD), "SSL_set_fd"},
-{ERR_FUNC(SSL_F_SSL_SET_PKEY), "SSL_SET_PKEY"},
-{ERR_FUNC(SSL_F_SSL_SET_PURPOSE), "SSL_set_purpose"},
-{ERR_FUNC(SSL_F_SSL_SET_RFD), "SSL_set_rfd"},
-{ERR_FUNC(SSL_F_SSL_SET_SESSION), "SSL_set_session"},
-{ERR_FUNC(SSL_F_SSL_SET_SESSION_ID_CONTEXT), "SSL_set_session_id_context"},
-{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
-{ERR_FUNC(SSL_F_SSL_SET_TRUST), "SSL_set_trust"},
-{ERR_FUNC(SSL_F_SSL_SET_WFD), "SSL_set_wfd"},
-{ERR_FUNC(SSL_F_SSL_SHUTDOWN), "SSL_shutdown"},
-{ERR_FUNC(SSL_F_SSL_SRP_CTX_INIT), "SSL_SRP_CTX_init"},
-{ERR_FUNC(SSL_F_SSL_UNDEFINED_CONST_FUNCTION), "SSL_UNDEFINED_CONST_FUNCTION"},
-{ERR_FUNC(SSL_F_SSL_UNDEFINED_FUNCTION), "SSL_UNDEFINED_FUNCTION"},
-{ERR_FUNC(SSL_F_SSL_UNDEFINED_VOID_FUNCTION), "SSL_UNDEFINED_VOID_FUNCTION"},
-{ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE), "SSL_use_certificate"},
-{ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_ASN1), "SSL_use_certificate_ASN1"},
-{ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_FILE), "SSL_use_certificate_file"},
-{ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY), "SSL_use_PrivateKey"},
-{ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY_ASN1), "SSL_use_PrivateKey_ASN1"},
-{ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY_FILE), "SSL_use_PrivateKey_file"},
-{ERR_FUNC(SSL_F_SSL_USE_PSK_IDENTITY_HINT), "SSL_use_psk_identity_hint"},
-{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY), "SSL_use_RSAPrivateKey"},
-{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1), "SSL_use_RSAPrivateKey_ASN1"},
-{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), "SSL_use_RSAPrivateKey_file"},
-{ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "SSL_VERIFY_CERT_CHAIN"},
-{ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"},
-{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"},
-{ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "TLS1_CHANGE_CIPHER_STATE"},
-{ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
-{ERR_FUNC(SSL_F_TLS1_EXPORT_KEYING_MATERIAL), "TLS1_EXPORT_KEYING_MATERIAL"},
-{ERR_FUNC(SSL_F_TLS1_HEARTBEAT), "SSL_F_TLS1_HEARTBEAT"},
-{ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), "TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), "TLS1_PREPARE_SERVERHELLO_TLSEXT"},
-{ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
-{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
-{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-{0,NULL}
- };
-
-static ERR_STRING_DATA SSL_str_reasons[]=
- {
-{ERR_REASON(SSL_R_APP_DATA_IN_HANDSHAKE) ,"app data in handshake"},
-{ERR_REASON(SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT),"attempt to reuse session in different context"},
-{ERR_REASON(SSL_R_BAD_ALERT_RECORD) ,"bad alert record"},
-{ERR_REASON(SSL_R_BAD_AUTHENTICATION_TYPE),"bad authentication type"},
-{ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC),"bad change cipher spec"},
-{ERR_REASON(SSL_R_BAD_CHECKSUM) ,"bad checksum"},
-{ERR_REASON(SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),"bad data returned by callback"},
-{ERR_REASON(SSL_R_BAD_DECOMPRESSION) ,"bad decompression"},
-{ERR_REASON(SSL_R_BAD_DH_G_LENGTH) ,"bad dh g length"},
-{ERR_REASON(SSL_R_BAD_DH_PUB_KEY_LENGTH) ,"bad dh pub key length"},
-{ERR_REASON(SSL_R_BAD_DH_P_LENGTH) ,"bad dh p length"},
-{ERR_REASON(SSL_R_BAD_DIGEST_LENGTH) ,"bad digest length"},
-{ERR_REASON(SSL_R_BAD_DSA_SIGNATURE) ,"bad dsa signature"},
-{ERR_REASON(SSL_R_BAD_ECC_CERT) ,"bad ecc cert"},
-{ERR_REASON(SSL_R_BAD_ECDSA_SIGNATURE) ,"bad ecdsa signature"},
-{ERR_REASON(SSL_R_BAD_ECPOINT) ,"bad ecpoint"},
-{ERR_REASON(SSL_R_BAD_HANDSHAKE_LENGTH) ,"bad handshake length"},
-{ERR_REASON(SSL_R_BAD_HELLO_REQUEST) ,"bad hello request"},
-{ERR_REASON(SSL_R_BAD_LENGTH) ,"bad length"},
-{ERR_REASON(SSL_R_BAD_MAC_DECODE) ,"bad mac decode"},
-{ERR_REASON(SSL_R_BAD_MAC_LENGTH) ,"bad mac length"},
-{ERR_REASON(SSL_R_BAD_MESSAGE_TYPE) ,"bad message type"},
-{ERR_REASON(SSL_R_BAD_PACKET_LENGTH) ,"bad packet length"},
-{ERR_REASON(SSL_R_BAD_PROTOCOL_VERSION_NUMBER),"bad protocol version number"},
-{ERR_REASON(SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH),"bad psk identity hint length"},
-{ERR_REASON(SSL_R_BAD_RESPONSE_ARGUMENT) ,"bad response argument"},
-{ERR_REASON(SSL_R_BAD_RSA_DECRYPT) ,"bad rsa decrypt"},
-{ERR_REASON(SSL_R_BAD_RSA_ENCRYPT) ,"bad rsa encrypt"},
-{ERR_REASON(SSL_R_BAD_RSA_E_LENGTH) ,"bad rsa e length"},
-{ERR_REASON(SSL_R_BAD_RSA_MODULUS_LENGTH),"bad rsa modulus length"},
-{ERR_REASON(SSL_R_BAD_RSA_SIGNATURE) ,"bad rsa signature"},
-{ERR_REASON(SSL_R_BAD_SIGNATURE) ,"bad signature"},
-{ERR_REASON(SSL_R_BAD_SRP_A_LENGTH) ,"bad srp a length"},
-{ERR_REASON(SSL_R_BAD_SRP_B_LENGTH) ,"bad srp b length"},
-{ERR_REASON(SSL_R_BAD_SRP_G_LENGTH) ,"bad srp g length"},
-{ERR_REASON(SSL_R_BAD_SRP_N_LENGTH) ,"bad srp n length"},
-{ERR_REASON(SSL_R_BAD_SRP_S_LENGTH) ,"bad srp s length"},
-{ERR_REASON(SSL_R_BAD_SRTP_MKI_VALUE) ,"bad srtp mki value"},
-{ERR_REASON(SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST),"bad srtp protection profile list"},
-{ERR_REASON(SSL_R_BAD_SSL_FILETYPE) ,"bad ssl filetype"},
-{ERR_REASON(SSL_R_BAD_SSL_SESSION_ID_LENGTH),"bad ssl session id length"},
-{ERR_REASON(SSL_R_BAD_STATE) ,"bad state"},
-{ERR_REASON(SSL_R_BAD_WRITE_RETRY) ,"bad write retry"},
-{ERR_REASON(SSL_R_BIO_NOT_SET) ,"bio not set"},
-{ERR_REASON(SSL_R_BLOCK_CIPHER_PAD_IS_WRONG),"block cipher pad is wrong"},
-{ERR_REASON(SSL_R_BN_LIB) ,"bn lib"},
-{ERR_REASON(SSL_R_CA_DN_LENGTH_MISMATCH) ,"ca dn length mismatch"},
-{ERR_REASON(SSL_R_CA_DN_TOO_LONG) ,"ca dn too long"},
-{ERR_REASON(SSL_R_CCS_RECEIVED_EARLY) ,"ccs received early"},
-{ERR_REASON(SSL_R_CERTIFICATE_VERIFY_FAILED),"certificate verify failed"},
-{ERR_REASON(SSL_R_CERT_LENGTH_MISMATCH) ,"cert length mismatch"},
-{ERR_REASON(SSL_R_CHALLENGE_IS_DIFFERENT),"challenge is different"},
-{ERR_REASON(SSL_R_CIPHER_CODE_WRONG_LENGTH),"cipher code wrong length"},
-{ERR_REASON(SSL_R_CIPHER_OR_HASH_UNAVAILABLE),"cipher or hash unavailable"},
-{ERR_REASON(SSL_R_CIPHER_TABLE_SRC_ERROR),"cipher table src error"},
-{ERR_REASON(SSL_R_CLIENTHELLO_TLSEXT) ,"clienthello tlsext"},
-{ERR_REASON(SSL_R_COMPRESSED_LENGTH_TOO_LONG),"compressed length too long"},
-{ERR_REASON(SSL_R_COMPRESSION_DISABLED) ,"compression disabled"},
-{ERR_REASON(SSL_R_COMPRESSION_FAILURE) ,"compression failure"},
-{ERR_REASON(SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE),"compression id not within private range"},
-{ERR_REASON(SSL_R_COMPRESSION_LIBRARY_ERROR),"compression library error"},
-{ERR_REASON(SSL_R_CONNECTION_ID_IS_DIFFERENT),"connection id is different"},
-{ERR_REASON(SSL_R_CONNECTION_TYPE_NOT_SET),"connection type not set"},
-{ERR_REASON(SSL_R_COOKIE_MISMATCH) ,"cookie mismatch"},
-{ERR_REASON(SSL_R_DATA_BETWEEN_CCS_AND_FINISHED),"data between ccs and finished"},
-{ERR_REASON(SSL_R_DATA_LENGTH_TOO_LONG) ,"data length too long"},
-{ERR_REASON(SSL_R_DECRYPTION_FAILED) ,"decryption failed"},
-{ERR_REASON(SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC),"decryption failed or bad record mac"},
-{ERR_REASON(SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG),"dh public value length is wrong"},
-{ERR_REASON(SSL_R_DIGEST_CHECK_FAILED) ,"digest check failed"},
-{ERR_REASON(SSL_R_DTLS_MESSAGE_TOO_BIG) ,"dtls message too big"},
-{ERR_REASON(SSL_R_DUPLICATE_COMPRESSION_ID),"duplicate compression id"},
-{ERR_REASON(SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT),"ecc cert not for key agreement"},
-{ERR_REASON(SSL_R_ECC_CERT_NOT_FOR_SIGNING),"ecc cert not for signing"},
-{ERR_REASON(SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE),"ecc cert should have rsa signature"},
-{ERR_REASON(SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE),"ecc cert should have sha1 signature"},
-{ERR_REASON(SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER),"ecgroup too large for cipher"},
-{ERR_REASON(SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST),"empty srtp protection profile list"},
-{ERR_REASON(SSL_R_ENCRYPTED_LENGTH_TOO_LONG),"encrypted length too long"},
-{ERR_REASON(SSL_R_ERROR_GENERATING_TMP_RSA_KEY),"error generating tmp rsa key"},
-{ERR_REASON(SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST),"error in received cipher list"},
-{ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE),"excessive message size"},
-{ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE) ,"extra data in message"},
-{ERR_REASON(SSL_R_GOT_A_FIN_BEFORE_A_CCS),"got a fin before a ccs"},
-{ERR_REASON(SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS),"got next proto before a ccs"},
-{ERR_REASON(SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION),"got next proto without seeing extension"},
-{ERR_REASON(SSL_R_HTTPS_PROXY_REQUEST) ,"https proxy request"},
-{ERR_REASON(SSL_R_HTTP_REQUEST) ,"http request"},
-{ERR_REASON(SSL_R_ILLEGAL_PADDING) ,"illegal padding"},
-{ERR_REASON(SSL_R_INCONSISTENT_COMPRESSION),"inconsistent compression"},
-{ERR_REASON(SSL_R_INVALID_CHALLENGE_LENGTH),"invalid challenge length"},
-{ERR_REASON(SSL_R_INVALID_COMMAND) ,"invalid command"},
-{ERR_REASON(SSL_R_INVALID_COMPRESSION_ALGORITHM),"invalid compression algorithm"},
-{ERR_REASON(SSL_R_INVALID_PURPOSE) ,"invalid purpose"},
-{ERR_REASON(SSL_R_INVALID_SRP_USERNAME) ,"invalid srp username"},
-{ERR_REASON(SSL_R_INVALID_STATUS_RESPONSE),"invalid status response"},
-{ERR_REASON(SSL_R_INVALID_TICKET_KEYS_LENGTH),"invalid ticket keys length"},
-{ERR_REASON(SSL_R_INVALID_TRUST) ,"invalid trust"},
-{ERR_REASON(SSL_R_KEY_ARG_TOO_LONG) ,"key arg too long"},
-{ERR_REASON(SSL_R_KRB5) ,"krb5"},
-{ERR_REASON(SSL_R_KRB5_C_CC_PRINC) ,"krb5 client cc principal (no tkt?)"},
-{ERR_REASON(SSL_R_KRB5_C_GET_CRED) ,"krb5 client get cred"},
-{ERR_REASON(SSL_R_KRB5_C_INIT) ,"krb5 client init"},
-{ERR_REASON(SSL_R_KRB5_C_MK_REQ) ,"krb5 client mk_req (expired tkt?)"},
-{ERR_REASON(SSL_R_KRB5_S_BAD_TICKET) ,"krb5 server bad ticket"},
-{ERR_REASON(SSL_R_KRB5_S_INIT) ,"krb5 server init"},
-{ERR_REASON(SSL_R_KRB5_S_RD_REQ) ,"krb5 server rd_req (keytab perms?)"},
-{ERR_REASON(SSL_R_KRB5_S_TKT_EXPIRED) ,"krb5 server tkt expired"},
-{ERR_REASON(SSL_R_KRB5_S_TKT_NYV) ,"krb5 server tkt not yet valid"},
-{ERR_REASON(SSL_R_KRB5_S_TKT_SKEW) ,"krb5 server tkt skew"},
-{ERR_REASON(SSL_R_LENGTH_MISMATCH) ,"length mismatch"},
-{ERR_REASON(SSL_R_LENGTH_TOO_SHORT) ,"length too short"},
-{ERR_REASON(SSL_R_LIBRARY_BUG) ,"library bug"},
-{ERR_REASON(SSL_R_LIBRARY_HAS_NO_CIPHERS),"library has no ciphers"},
-{ERR_REASON(SSL_R_MESSAGE_TOO_LONG) ,"message too long"},
-{ERR_REASON(SSL_R_MISSING_DH_DSA_CERT) ,"missing dh dsa cert"},
-{ERR_REASON(SSL_R_MISSING_DH_KEY) ,"missing dh key"},
-{ERR_REASON(SSL_R_MISSING_DH_RSA_CERT) ,"missing dh rsa cert"},
-{ERR_REASON(SSL_R_MISSING_DSA_SIGNING_CERT),"missing dsa signing cert"},
-{ERR_REASON(SSL_R_MISSING_EXPORT_TMP_DH_KEY),"missing export tmp dh key"},
-{ERR_REASON(SSL_R_MISSING_EXPORT_TMP_RSA_KEY),"missing export tmp rsa key"},
-{ERR_REASON(SSL_R_MISSING_RSA_CERTIFICATE),"missing rsa certificate"},
-{ERR_REASON(SSL_R_MISSING_RSA_ENCRYPTING_CERT),"missing rsa encrypting cert"},
-{ERR_REASON(SSL_R_MISSING_RSA_SIGNING_CERT),"missing rsa signing cert"},
-{ERR_REASON(SSL_R_MISSING_SRP_PARAM) ,"can't find SRP server param"},
-{ERR_REASON(SSL_R_MISSING_TMP_DH_KEY) ,"missing tmp dh key"},
-{ERR_REASON(SSL_R_MISSING_TMP_ECDH_KEY) ,"missing tmp ecdh key"},
-{ERR_REASON(SSL_R_MISSING_TMP_RSA_KEY) ,"missing tmp rsa key"},
-{ERR_REASON(SSL_R_MISSING_TMP_RSA_PKEY) ,"missing tmp rsa pkey"},
-{ERR_REASON(SSL_R_MISSING_VERIFY_MESSAGE),"missing verify message"},
-{ERR_REASON(SSL_R_MULTIPLE_SGC_RESTARTS) ,"multiple sgc restarts"},
-{ERR_REASON(SSL_R_NON_SSLV2_INITIAL_PACKET),"non sslv2 initial packet"},
-{ERR_REASON(SSL_R_NO_CERTIFICATES_RETURNED),"no certificates returned"},
-{ERR_REASON(SSL_R_NO_CERTIFICATE_ASSIGNED),"no certificate assigned"},
-{ERR_REASON(SSL_R_NO_CERTIFICATE_RETURNED),"no certificate returned"},
-{ERR_REASON(SSL_R_NO_CERTIFICATE_SET) ,"no certificate set"},
-{ERR_REASON(SSL_R_NO_CERTIFICATE_SPECIFIED),"no certificate specified"},
-{ERR_REASON(SSL_R_NO_CIPHERS_AVAILABLE) ,"no ciphers available"},
-{ERR_REASON(SSL_R_NO_CIPHERS_PASSED) ,"no ciphers passed"},
-{ERR_REASON(SSL_R_NO_CIPHERS_SPECIFIED) ,"no ciphers specified"},
-{ERR_REASON(SSL_R_NO_CIPHER_LIST) ,"no cipher list"},
-{ERR_REASON(SSL_R_NO_CIPHER_MATCH) ,"no cipher match"},
-{ERR_REASON(SSL_R_NO_CLIENT_CERT_METHOD) ,"no client cert method"},
-{ERR_REASON(SSL_R_NO_CLIENT_CERT_RECEIVED),"no client cert received"},
-{ERR_REASON(SSL_R_NO_COMPRESSION_SPECIFIED),"no compression specified"},
-{ERR_REASON(SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER),"Peer haven't sent GOST certificate, required for selected ciphersuite"},
-{ERR_REASON(SSL_R_NO_METHOD_SPECIFIED) ,"no method specified"},
-{ERR_REASON(SSL_R_NO_PRIVATEKEY) ,"no privatekey"},
-{ERR_REASON(SSL_R_NO_PRIVATE_KEY_ASSIGNED),"no private key assigned"},
-{ERR_REASON(SSL_R_NO_PROTOCOLS_AVAILABLE),"no protocols available"},
-{ERR_REASON(SSL_R_NO_PUBLICKEY) ,"no publickey"},
-{ERR_REASON(SSL_R_NO_RENEGOTIATION) ,"no renegotiation"},
-{ERR_REASON(SSL_R_NO_REQUIRED_DIGEST) ,"digest requred for handshake isn't computed"},
-{ERR_REASON(SSL_R_NO_SHARED_CIPHER) ,"no shared cipher"},
-{ERR_REASON(SSL_R_NO_SRTP_PROFILES) ,"no srtp profiles"},
-{ERR_REASON(SSL_R_NO_VERIFY_CALLBACK) ,"no verify callback"},
-{ERR_REASON(SSL_R_NULL_SSL_CTX) ,"null ssl ctx"},
-{ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED),"null ssl method passed"},
-{ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
-{ERR_REASON(SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED),"old session compression algorithm not returned"},
-{ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
-{ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG),"opaque PRF input too long"},
-{ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
-{ERR_REASON(SSL_R_PARSE_TLSEXT) ,"parse tlsext"},
-{ERR_REASON(SSL_R_PATH_TOO_LONG) ,"path too long"},
-{ERR_REASON(SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE),"peer did not return a certificate"},
-{ERR_REASON(SSL_R_PEER_ERROR) ,"peer error"},
-{ERR_REASON(SSL_R_PEER_ERROR_CERTIFICATE),"peer error certificate"},
-{ERR_REASON(SSL_R_PEER_ERROR_NO_CERTIFICATE),"peer error no certificate"},
-{ERR_REASON(SSL_R_PEER_ERROR_NO_CIPHER) ,"peer error no cipher"},
-{ERR_REASON(SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE),"peer error unsupported certificate type"},
-{ERR_REASON(SSL_R_PRE_MAC_LENGTH_TOO_LONG),"pre mac length too long"},
-{ERR_REASON(SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS),"problems mapping cipher functions"},
-{ERR_REASON(SSL_R_PROTOCOL_IS_SHUTDOWN) ,"protocol is shutdown"},
-{ERR_REASON(SSL_R_PSK_IDENTITY_NOT_FOUND),"psk identity not found"},
-{ERR_REASON(SSL_R_PSK_NO_CLIENT_CB) ,"psk no client cb"},
-{ERR_REASON(SSL_R_PSK_NO_SERVER_CB) ,"psk no server cb"},
-{ERR_REASON(SSL_R_PUBLIC_KEY_ENCRYPT_ERROR),"public key encrypt error"},
-{ERR_REASON(SSL_R_PUBLIC_KEY_IS_NOT_RSA) ,"public key is not rsa"},
-{ERR_REASON(SSL_R_PUBLIC_KEY_NOT_RSA) ,"public key not rsa"},
-{ERR_REASON(SSL_R_READ_BIO_NOT_SET) ,"read bio not set"},
-{ERR_REASON(SSL_R_READ_TIMEOUT_EXPIRED) ,"read timeout expired"},
-{ERR_REASON(SSL_R_READ_WRONG_PACKET_TYPE),"read wrong packet type"},
-{ERR_REASON(SSL_R_RECORD_LENGTH_MISMATCH),"record length mismatch"},
-{ERR_REASON(SSL_R_RECORD_TOO_LARGE) ,"record too large"},
-{ERR_REASON(SSL_R_RECORD_TOO_SMALL) ,"record too small"},
-{ERR_REASON(SSL_R_RENEGOTIATE_EXT_TOO_LONG),"renegotiate ext too long"},
-{ERR_REASON(SSL_R_RENEGOTIATION_ENCODING_ERR),"renegotiation encoding err"},
-{ERR_REASON(SSL_R_RENEGOTIATION_MISMATCH),"renegotiation mismatch"},
-{ERR_REASON(SSL_R_REQUIRED_CIPHER_MISSING),"required cipher missing"},
-{ERR_REASON(SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING),"required compresssion algorithm missing"},
-{ERR_REASON(SSL_R_REUSE_CERT_LENGTH_NOT_ZERO),"reuse cert length not zero"},
-{ERR_REASON(SSL_R_REUSE_CERT_TYPE_NOT_ZERO),"reuse cert type not zero"},
-{ERR_REASON(SSL_R_REUSE_CIPHER_LIST_NOT_ZERO),"reuse cipher list not zero"},
-{ERR_REASON(SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING),"scsv received when renegotiating"},
-{ERR_REASON(SSL_R_SERVERHELLO_TLSEXT) ,"serverhello tlsext"},
-{ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),"session id context uninitialized"},
-{ERR_REASON(SSL_R_SHORT_READ) ,"short read"},
-{ERR_REASON(SSL_R_SIGNATURE_ALGORITHMS_ERROR),"signature algorithms error"},
-{ERR_REASON(SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),"signature for non signing certificate"},
-{ERR_REASON(SSL_R_SRP_A_CALC) ,"error with the srp params"},
-{ERR_REASON(SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES),"srtp could not allocate profiles"},
-{ERR_REASON(SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG),"srtp protection profile list too long"},
-{ERR_REASON(SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE),"srtp unknown protection profile"},
-{ERR_REASON(SSL_R_SSL23_DOING_SESSION_ID_REUSE),"ssl23 doing session id reuse"},
-{ERR_REASON(SSL_R_SSL2_CONNECTION_ID_TOO_LONG),"ssl2 connection id too long"},
-{ERR_REASON(SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT),"ssl3 ext invalid ecpointformat"},
-{ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME),"ssl3 ext invalid servername"},
-{ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE),"ssl3 ext invalid servername type"},
-{ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_LONG),"ssl3 session id too long"},
-{ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_SHORT),"ssl3 session id too short"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_BAD_CERTIFICATE),"sslv3 alert bad certificate"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_BAD_RECORD_MAC),"sslv3 alert bad record mac"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED),"sslv3 alert certificate expired"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED),"sslv3 alert certificate revoked"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN),"sslv3 alert certificate unknown"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE),"sslv3 alert decompression failure"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE),"sslv3 alert handshake failure"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER),"sslv3 alert illegal parameter"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_NO_CERTIFICATE),"sslv3 alert no certificate"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE),"sslv3 alert unexpected message"},
-{ERR_REASON(SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE),"sslv3 alert unsupported certificate"},
-{ERR_REASON(SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION),"ssl ctx has no default ssl version"},
-{ERR_REASON(SSL_R_SSL_HANDSHAKE_FAILURE) ,"ssl handshake failure"},
-{ERR_REASON(SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS),"ssl library has no ciphers"},
-{ERR_REASON(SSL_R_SSL_SESSION_ID_CALLBACK_FAILED),"ssl session id callback failed"},
-{ERR_REASON(SSL_R_SSL_SESSION_ID_CONFLICT),"ssl session id conflict"},
-{ERR_REASON(SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG),"ssl session id context too long"},
-{ERR_REASON(SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH),"ssl session id has bad length"},
-{ERR_REASON(SSL_R_SSL_SESSION_ID_IS_DIFFERENT),"ssl session id is different"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_ACCESS_DENIED),"tlsv1 alert access denied"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_DECODE_ERROR),"tlsv1 alert decode error"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_DECRYPTION_FAILED),"tlsv1 alert decryption failed"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_DECRYPT_ERROR),"tlsv1 alert decrypt error"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION),"tlsv1 alert export restriction"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY),"tlsv1 alert insufficient security"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_INTERNAL_ERROR),"tlsv1 alert internal error"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION),"tlsv1 alert no renegotiation"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_PROTOCOL_VERSION),"tlsv1 alert protocol version"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_RECORD_OVERFLOW),"tlsv1 alert record overflow"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_UNKNOWN_CA),"tlsv1 alert unknown ca"},
-{ERR_REASON(SSL_R_TLSV1_ALERT_USER_CANCELLED),"tlsv1 alert user cancelled"},
-{ERR_REASON(SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE),"tlsv1 bad certificate hash value"},
-{ERR_REASON(SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE),"tlsv1 bad certificate status response"},
-{ERR_REASON(SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE),"tlsv1 certificate unobtainable"},
-{ERR_REASON(SSL_R_TLSV1_UNRECOGNIZED_NAME),"tlsv1 unrecognized name"},
-{ERR_REASON(SSL_R_TLSV1_UNSUPPORTED_EXTENSION),"tlsv1 unsupported extension"},
-{ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),"tls client cert req with anon cipher"},
-{ERR_REASON(SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT),"peer does not accept heartbearts"},
-{ERR_REASON(SSL_R_TLS_HEARTBEAT_PENDING) ,"heartbeat request already pending"},
-{ERR_REASON(SSL_R_TLS_ILLEGAL_EXPORTER_LABEL),"tls illegal exporter label"},
-{ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),"tls invalid ecpointformat list"},
-{ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST),"tls peer did not respond with certificate list"},
-{ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG),"tls rsa encrypted value length is wrong"},
-{ERR_REASON(SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER),"tried to use unsupported cipher"},
-{ERR_REASON(SSL_R_UNABLE_TO_DECODE_DH_CERTS),"unable to decode dh certs"},
-{ERR_REASON(SSL_R_UNABLE_TO_DECODE_ECDH_CERTS),"unable to decode ecdh certs"},
-{ERR_REASON(SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY),"unable to extract public key"},
-{ERR_REASON(SSL_R_UNABLE_TO_FIND_DH_PARAMETERS),"unable to find dh parameters"},
-{ERR_REASON(SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS),"unable to find ecdh parameters"},
-{ERR_REASON(SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS),"unable to find public key parameters"},
-{ERR_REASON(SSL_R_UNABLE_TO_FIND_SSL_METHOD),"unable to find ssl method"},
-{ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES),"unable to load ssl2 md5 routines"},
-{ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES),"unable to load ssl3 md5 routines"},
-{ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES),"unable to load ssl3 sha1 routines"},
-{ERR_REASON(SSL_R_UNEXPECTED_MESSAGE) ,"unexpected message"},
-{ERR_REASON(SSL_R_UNEXPECTED_RECORD) ,"unexpected record"},
-{ERR_REASON(SSL_R_UNINITIALIZED) ,"uninitialized"},
-{ERR_REASON(SSL_R_UNKNOWN_ALERT_TYPE) ,"unknown alert type"},
-{ERR_REASON(SSL_R_UNKNOWN_CERTIFICATE_TYPE),"unknown certificate type"},
-{ERR_REASON(SSL_R_UNKNOWN_CIPHER_RETURNED),"unknown cipher returned"},
-{ERR_REASON(SSL_R_UNKNOWN_CIPHER_TYPE) ,"unknown cipher type"},
-{ERR_REASON(SSL_R_UNKNOWN_DIGEST) ,"unknown digest"},
-{ERR_REASON(SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE),"unknown key exchange type"},
-{ERR_REASON(SSL_R_UNKNOWN_PKEY_TYPE) ,"unknown pkey type"},
-{ERR_REASON(SSL_R_UNKNOWN_PROTOCOL) ,"unknown protocol"},
-{ERR_REASON(SSL_R_UNKNOWN_REMOTE_ERROR_TYPE),"unknown remote error type"},
-{ERR_REASON(SSL_R_UNKNOWN_SSL_VERSION) ,"unknown ssl version"},
-{ERR_REASON(SSL_R_UNKNOWN_STATE) ,"unknown state"},
-{ERR_REASON(SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),"unsafe legacy renegotiation disabled"},
-{ERR_REASON(SSL_R_UNSUPPORTED_CIPHER) ,"unsupported cipher"},
-{ERR_REASON(SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"},
-{ERR_REASON(SSL_R_UNSUPPORTED_DIGEST_TYPE),"unsupported digest type"},
-{ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),"unsupported elliptic curve"},
-{ERR_REASON(SSL_R_UNSUPPORTED_PROTOCOL) ,"unsupported protocol"},
-{ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION),"unsupported ssl version"},
-{ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE),"unsupported status type"},
-{ERR_REASON(SSL_R_USE_SRTP_NOT_NEGOTIATED),"use srtp not negotiated"},
-{ERR_REASON(SSL_R_WRITE_BIO_NOT_SET) ,"write bio not set"},
-{ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED) ,"wrong cipher returned"},
-{ERR_REASON(SSL_R_WRONG_MESSAGE_TYPE) ,"wrong message type"},
-{ERR_REASON(SSL_R_WRONG_NUMBER_OF_KEY_BITS),"wrong number of key bits"},
-{ERR_REASON(SSL_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"},
-{ERR_REASON(SSL_R_WRONG_SIGNATURE_SIZE) ,"wrong signature size"},
-{ERR_REASON(SSL_R_WRONG_SIGNATURE_TYPE) ,"wrong signature type"},
-{ERR_REASON(SSL_R_WRONG_SSL_VERSION) ,"wrong ssl version"},
-{ERR_REASON(SSL_R_WRONG_VERSION_NUMBER) ,"wrong version number"},
-{ERR_REASON(SSL_R_X509_LIB) ,"x509 lib"},
-{ERR_REASON(SSL_R_X509_VERIFICATION_SETUP_PROBLEMS),"x509 verification setup problems"},
-{0,NULL}
- };
-
-#endif
-
-void ERR_load_SSL_strings(void)
- {
-#ifndef OPENSSL_NO_ERR
-
- if (ERR_func_error_string(SSL_str_functs[0].error) == NULL)
- {
- ERR_load_strings(0,SSL_str_functs);
- ERR_load_strings(0,SSL_str_reasons);
- }
-#endif
- }
diff --git a/drivers/builtin_openssl/ssl/ssl_lib.c b/drivers/builtin_openssl/ssl/ssl_lib.c
deleted file mode 100644
index 6dbc3c1f7d..0000000000
--- a/drivers/builtin_openssl/ssl/ssl_lib.c
+++ /dev/null
@@ -1,3265 +0,0 @@
-/*! \file ssl/ssl_lib.c
- * \brief Version independent SSL functions.
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECC cipher suite support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#ifdef REF_CHECK
-# include <assert.h>
-#endif
-#include <stdio.h>
-#include "ssl_locl.h"
-#include "kssl_lcl.h"
-#include <openssl/objects.h>
-#include <openssl/lhash.h>
-#include <openssl/x509v3.h>
-#include <openssl/rand.h>
-#include <openssl/ocsp.h>
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#endif
-#ifndef OPENSSL_NO_ENGINE
-#include <openssl/engine.h>
-#endif
-
-const char *SSL_version_str=OPENSSL_VERSION_TEXT;
-
-SSL3_ENC_METHOD ssl3_undef_enc_method={
- /* evil casts, but these functions are only called if there's a library bug */
- (int (*)(SSL *,int))ssl_undefined_function,
- (int (*)(SSL *, unsigned char *, int))ssl_undefined_function,
- ssl_undefined_function,
- (int (*)(SSL *, unsigned char *, unsigned char *, int))ssl_undefined_function,
- (int (*)(SSL*, int))ssl_undefined_function,
- (int (*)(SSL *, const char*, int, unsigned char *))ssl_undefined_function,
- 0, /* finish_mac_length */
- (int (*)(SSL *, int, unsigned char *))ssl_undefined_function,
- NULL, /* client_finished_label */
- 0, /* client_finished_label_len */
- NULL, /* server_finished_label */
- 0, /* server_finished_label_len */
- (int (*)(int))ssl_undefined_function,
- (int (*)(SSL *, unsigned char *, size_t, const char *,
- size_t, const unsigned char *, size_t,
- int use_context)) ssl_undefined_function,
- };
-
-int SSL_clear(SSL *s)
- {
-
- if (s->method == NULL)
- {
- SSLerr(SSL_F_SSL_CLEAR,SSL_R_NO_METHOD_SPECIFIED);
- return(0);
- }
-
- if (ssl_clear_bad_session(s))
- {
- SSL_SESSION_free(s->session);
- s->session=NULL;
- }
-
- s->error=0;
- s->hit=0;
- s->shutdown=0;
-
-#if 0 /* Disabled since version 1.10 of this file (early return not
- * needed because SSL_clear is not called when doing renegotiation) */
- /* This is set if we are doing dynamic renegotiation so keep
- * the old cipher. It is sort of a SSL_clear_lite :-) */
- if (s->renegotiate) return(1);
-#else
- if (s->renegotiate)
- {
- SSLerr(SSL_F_SSL_CLEAR,ERR_R_INTERNAL_ERROR);
- return 0;
- }
-#endif
-
- s->type=0;
-
- s->state=SSL_ST_BEFORE|((s->server)?SSL_ST_ACCEPT:SSL_ST_CONNECT);
-
- s->version=s->method->version;
- s->client_version=s->version;
- s->rwstate=SSL_NOTHING;
- s->rstate=SSL_ST_READ_HEADER;
-#if 0
- s->read_ahead=s->ctx->read_ahead;
-#endif
-
- if (s->init_buf != NULL)
- {
- BUF_MEM_free(s->init_buf);
- s->init_buf=NULL;
- }
-
- ssl_clear_cipher_ctx(s);
- ssl_clear_hash_ctx(&s->read_hash);
- ssl_clear_hash_ctx(&s->write_hash);
-
- s->first_packet=0;
-
-#if 1
- /* Check to see if we were changed into a different method, if
- * so, revert back if we are not doing session-id reuse. */
- if (!s->in_handshake && (s->session == NULL) && (s->method != s->ctx->method))
- {
- s->method->ssl_free(s);
- s->method=s->ctx->method;
- if (!s->method->ssl_new(s))
- return(0);
- }
- else
-#endif
- s->method->ssl_clear(s);
- return(1);
- }
-
-/** Used to change an SSL_CTXs default SSL method type */
-int SSL_CTX_set_ssl_version(SSL_CTX *ctx,const SSL_METHOD *meth)
- {
- STACK_OF(SSL_CIPHER) *sk;
-
- ctx->method=meth;
-
- sk=ssl_create_cipher_list(ctx->method,&(ctx->cipher_list),
- &(ctx->cipher_list_by_id),
- meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST);
- if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0))
- {
- SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION,SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
- return(0);
- }
- return(1);
- }
-
-SSL *SSL_new(SSL_CTX *ctx)
- {
- SSL *s;
-
- if (ctx == NULL)
- {
- SSLerr(SSL_F_SSL_NEW,SSL_R_NULL_SSL_CTX);
- return(NULL);
- }
- if (ctx->method == NULL)
- {
- SSLerr(SSL_F_SSL_NEW,SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
- return(NULL);
- }
-
- s=(SSL *)OPENSSL_malloc(sizeof(SSL));
- if (s == NULL) goto err;
- memset(s,0,sizeof(SSL));
-
-#ifndef OPENSSL_NO_KRB5
- s->kssl_ctx = kssl_ctx_new();
-#endif /* OPENSSL_NO_KRB5 */
-
- s->options=ctx->options;
- s->mode=ctx->mode;
- s->max_cert_list=ctx->max_cert_list;
-
- if (ctx->cert != NULL)
- {
- /* Earlier library versions used to copy the pointer to
- * the CERT, not its contents; only when setting new
- * parameters for the per-SSL copy, ssl_cert_new would be
- * called (and the direct reference to the per-SSL_CTX
- * settings would be lost, but those still were indirectly
- * accessed for various purposes, and for that reason they
- * used to be known as s->ctx->default_cert).
- * Now we don't look at the SSL_CTX's CERT after having
- * duplicated it once. */
-
- s->cert = ssl_cert_dup(ctx->cert);
- if (s->cert == NULL)
- goto err;
- }
- else
- s->cert=NULL; /* Cannot really happen (see SSL_CTX_new) */
-
- s->read_ahead=ctx->read_ahead;
- s->msg_callback=ctx->msg_callback;
- s->msg_callback_arg=ctx->msg_callback_arg;
- s->verify_mode=ctx->verify_mode;
-#if 0
- s->verify_depth=ctx->verify_depth;
-#endif
- s->sid_ctx_length=ctx->sid_ctx_length;
- OPENSSL_assert(s->sid_ctx_length <= sizeof s->sid_ctx);
- memcpy(&s->sid_ctx,&ctx->sid_ctx,sizeof(s->sid_ctx));
- s->verify_callback=ctx->default_verify_callback;
- s->generate_session_id=ctx->generate_session_id;
-
- s->param = X509_VERIFY_PARAM_new();
- if (!s->param)
- goto err;
- X509_VERIFY_PARAM_inherit(s->param, ctx->param);
-#if 0
- s->purpose = ctx->purpose;
- s->trust = ctx->trust;
-#endif
- s->quiet_shutdown=ctx->quiet_shutdown;
- s->max_send_fragment = ctx->max_send_fragment;
-
- CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
- s->ctx=ctx;
-#ifndef OPENSSL_NO_TLSEXT
- s->tlsext_debug_cb = 0;
- s->tlsext_debug_arg = NULL;
- s->tlsext_ticket_expected = 0;
- s->tlsext_status_type = -1;
- s->tlsext_status_expected = 0;
- s->tlsext_ocsp_ids = NULL;
- s->tlsext_ocsp_exts = NULL;
- s->tlsext_ocsp_resp = NULL;
- s->tlsext_ocsp_resplen = -1;
- CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
- s->initial_ctx=ctx;
-# ifndef OPENSSL_NO_NEXTPROTONEG
- s->next_proto_negotiated = NULL;
-# endif
-#endif
-
- s->verify_result=X509_V_OK;
-
- s->method=ctx->method;
-
- if (!s->method->ssl_new(s))
- goto err;
-
- s->references=1;
- s->server=(ctx->method->ssl_accept == ssl_undefined_function)?0:1;
-
- SSL_clear(s);
-
- CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
-
-#ifndef OPENSSL_NO_PSK
- s->psk_client_callback=ctx->psk_client_callback;
- s->psk_server_callback=ctx->psk_server_callback;
-#endif
-
- return(s);
-err:
- if (s != NULL)
- {
- if (s->cert != NULL)
- ssl_cert_free(s->cert);
- if (s->ctx != NULL)
- SSL_CTX_free(s->ctx); /* decrement reference count */
- OPENSSL_free(s);
- }
- SSLerr(SSL_F_SSL_NEW,ERR_R_MALLOC_FAILURE);
- return(NULL);
- }
-
-int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
- unsigned int sid_ctx_len)
- {
- if(sid_ctx_len > sizeof ctx->sid_ctx)
- {
- SSLerr(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
- return 0;
- }
- ctx->sid_ctx_length=sid_ctx_len;
- memcpy(ctx->sid_ctx,sid_ctx,sid_ctx_len);
-
- return 1;
- }
-
-int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
- unsigned int sid_ctx_len)
- {
- if(sid_ctx_len > SSL_MAX_SID_CTX_LENGTH)
- {
- SSLerr(SSL_F_SSL_SET_SESSION_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
- return 0;
- }
- ssl->sid_ctx_length=sid_ctx_len;
- memcpy(ssl->sid_ctx,sid_ctx,sid_ctx_len);
-
- return 1;
- }
-
-int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb)
- {
- CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
- ctx->generate_session_id = cb;
- CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
- return 1;
- }
-
-int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb)
- {
- CRYPTO_w_lock(CRYPTO_LOCK_SSL);
- ssl->generate_session_id = cb;
- CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
- return 1;
- }
-
-int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
- unsigned int id_len)
- {
- /* A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how
- * we can "construct" a session to give us the desired check - ie. to
- * find if there's a session in the hash table that would conflict with
- * any new session built out of this id/id_len and the ssl_version in
- * use by this SSL. */
- SSL_SESSION r, *p;
-
- if(id_len > sizeof r.session_id)
- return 0;
-
- r.ssl_version = ssl->version;
- r.session_id_length = id_len;
- memcpy(r.session_id, id, id_len);
- /* NB: SSLv2 always uses a fixed 16-byte session ID, so even if a
- * callback is calling us to check the uniqueness of a shorter ID, it
- * must be compared as a padded-out ID because that is what it will be
- * converted to when the callback has finished choosing it. */
- if((r.ssl_version == SSL2_VERSION) &&
- (id_len < SSL2_SSL_SESSION_ID_LENGTH))
- {
- memset(r.session_id + id_len, 0,
- SSL2_SSL_SESSION_ID_LENGTH - id_len);
- r.session_id_length = SSL2_SSL_SESSION_ID_LENGTH;
- }
-
- CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
- p = lh_SSL_SESSION_retrieve(ssl->ctx->sessions, &r);
- CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
- return (p != NULL);
- }
-
-int SSL_CTX_set_purpose(SSL_CTX *s, int purpose)
- {
- return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
- }
-
-int SSL_set_purpose(SSL *s, int purpose)
- {
- return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
- }
-
-int SSL_CTX_set_trust(SSL_CTX *s, int trust)
- {
- return X509_VERIFY_PARAM_set_trust(s->param, trust);
- }
-
-int SSL_set_trust(SSL *s, int trust)
- {
- return X509_VERIFY_PARAM_set_trust(s->param, trust);
- }
-
-int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm)
- {
- return X509_VERIFY_PARAM_set1(ctx->param, vpm);
- }
-
-int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm)
- {
- return X509_VERIFY_PARAM_set1(ssl->param, vpm);
- }
-
-void SSL_free(SSL *s)
- {
- int i;
-
- if(s == NULL)
- return;
-
- i=CRYPTO_add(&s->references,-1,CRYPTO_LOCK_SSL);
-#ifdef REF_PRINT
- REF_PRINT("SSL",s);
-#endif
- if (i > 0) return;
-#ifdef REF_CHECK
- if (i < 0)
- {
- fprintf(stderr,"SSL_free, bad reference count\n");
- abort(); /* ok */
- }
-#endif
-
- if (s->param)
- X509_VERIFY_PARAM_free(s->param);
-
- CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
-
- if (s->bbio != NULL)
- {
- /* If the buffering BIO is in place, pop it off */
- if (s->bbio == s->wbio)
- {
- s->wbio=BIO_pop(s->wbio);
- }
- BIO_free(s->bbio);
- s->bbio=NULL;
- }
- if (s->rbio != NULL)
- BIO_free_all(s->rbio);
- if ((s->wbio != NULL) && (s->wbio != s->rbio))
- BIO_free_all(s->wbio);
-
- if (s->init_buf != NULL) BUF_MEM_free(s->init_buf);
-
- /* add extra stuff */
- if (s->cipher_list != NULL) sk_SSL_CIPHER_free(s->cipher_list);
- if (s->cipher_list_by_id != NULL) sk_SSL_CIPHER_free(s->cipher_list_by_id);
-
- /* Make the next call work :-) */
- if (s->session != NULL)
- {
- ssl_clear_bad_session(s);
- SSL_SESSION_free(s->session);
- }
-
- ssl_clear_cipher_ctx(s);
- ssl_clear_hash_ctx(&s->read_hash);
- ssl_clear_hash_ctx(&s->write_hash);
-
- if (s->cert != NULL) ssl_cert_free(s->cert);
- /* Free up if allocated */
-
-#ifndef OPENSSL_NO_TLSEXT
- if (s->tlsext_hostname)
- OPENSSL_free(s->tlsext_hostname);
- if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
-#ifndef OPENSSL_NO_EC
- if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist);
- if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist);
-#endif /* OPENSSL_NO_EC */
- if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input);
- if (s->tlsext_ocsp_exts)
- sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
- X509_EXTENSION_free);
- if (s->tlsext_ocsp_ids)
- sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
- if (s->tlsext_ocsp_resp)
- OPENSSL_free(s->tlsext_ocsp_resp);
-#endif
-
- if (s->client_CA != NULL)
- sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
-
- if (s->method != NULL) s->method->ssl_free(s);
-
- if (s->ctx) SSL_CTX_free(s->ctx);
-
-#ifndef OPENSSL_NO_KRB5
- if (s->kssl_ctx != NULL)
- kssl_ctx_free(s->kssl_ctx);
-#endif /* OPENSSL_NO_KRB5 */
-
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
- if (s->next_proto_negotiated)
- OPENSSL_free(s->next_proto_negotiated);
-#endif
-
-#ifndef OPENSSL_NO_SRTP
- if (s->srtp_profiles)
- sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
-#endif
-
- OPENSSL_free(s);
- }
-
-void SSL_set_bio(SSL *s,BIO *rbio,BIO *wbio)
- {
- /* If the output buffering BIO is still in place, remove it
- */
- if (s->bbio != NULL)
- {
- if (s->wbio == s->bbio)
- {
- s->wbio=s->wbio->next_bio;
- s->bbio->next_bio=NULL;
- }
- }
- if ((s->rbio != NULL) && (s->rbio != rbio))
- BIO_free_all(s->rbio);
- if ((s->wbio != NULL) && (s->wbio != wbio) && (s->rbio != s->wbio))
- BIO_free_all(s->wbio);
- s->rbio=rbio;
- s->wbio=wbio;
- }
-
-BIO *SSL_get_rbio(const SSL *s)
- { return(s->rbio); }
-
-BIO *SSL_get_wbio(const SSL *s)
- { return(s->wbio); }
-
-int SSL_get_fd(const SSL *s)
- {
- return(SSL_get_rfd(s));
- }
-
-int SSL_get_rfd(const SSL *s)
- {
- int ret= -1;
- BIO *b,*r;
-
- b=SSL_get_rbio(s);
- r=BIO_find_type(b,BIO_TYPE_DESCRIPTOR);
- if (r != NULL)
- BIO_get_fd(r,&ret);
- return(ret);
- }
-
-int SSL_get_wfd(const SSL *s)
- {
- int ret= -1;
- BIO *b,*r;
-
- b=SSL_get_wbio(s);
- r=BIO_find_type(b,BIO_TYPE_DESCRIPTOR);
- if (r != NULL)
- BIO_get_fd(r,&ret);
- return(ret);
- }
-
-#ifndef OPENSSL_NO_SOCK
-int SSL_set_fd(SSL *s,int fd)
- {
- int ret=0;
- BIO *bio=NULL;
-
- bio=BIO_new(BIO_s_socket());
-
- if (bio == NULL)
- {
- SSLerr(SSL_F_SSL_SET_FD,ERR_R_BUF_LIB);
- goto err;
- }
- BIO_set_fd(bio,fd,BIO_NOCLOSE);
- SSL_set_bio(s,bio,bio);
- ret=1;
-err:
- return(ret);
- }
-
-int SSL_set_wfd(SSL *s,int fd)
- {
- int ret=0;
- BIO *bio=NULL;
-
- if ((s->rbio == NULL) || (BIO_method_type(s->rbio) != BIO_TYPE_SOCKET)
- || ((int)BIO_get_fd(s->rbio,NULL) != fd))
- {
- bio=BIO_new(BIO_s_socket());
-
- if (bio == NULL)
- { SSLerr(SSL_F_SSL_SET_WFD,ERR_R_BUF_LIB); goto err; }
- BIO_set_fd(bio,fd,BIO_NOCLOSE);
- SSL_set_bio(s,SSL_get_rbio(s),bio);
- }
- else
- SSL_set_bio(s,SSL_get_rbio(s),SSL_get_rbio(s));
- ret=1;
-err:
- return(ret);
- }
-
-int SSL_set_rfd(SSL *s,int fd)
- {
- int ret=0;
- BIO *bio=NULL;
-
- if ((s->wbio == NULL) || (BIO_method_type(s->wbio) != BIO_TYPE_SOCKET)
- || ((int)BIO_get_fd(s->wbio,NULL) != fd))
- {
- bio=BIO_new(BIO_s_socket());
-
- if (bio == NULL)
- {
- SSLerr(SSL_F_SSL_SET_RFD,ERR_R_BUF_LIB);
- goto err;
- }
- BIO_set_fd(bio,fd,BIO_NOCLOSE);
- SSL_set_bio(s,bio,SSL_get_wbio(s));
- }
- else
- SSL_set_bio(s,SSL_get_wbio(s),SSL_get_wbio(s));
- ret=1;
-err:
- return(ret);
- }
-#endif
-
-
-/* return length of latest Finished message we sent, copy to 'buf' */
-size_t SSL_get_finished(const SSL *s, void *buf, size_t count)
- {
- size_t ret = 0;
-
- if (s->s3 != NULL)
- {
- ret = s->s3->tmp.finish_md_len;
- if (count > ret)
- count = ret;
- memcpy(buf, s->s3->tmp.finish_md, count);
- }
- return ret;
- }
-
-/* return length of latest Finished message we expected, copy to 'buf' */
-size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count)
- {
- size_t ret = 0;
-
- if (s->s3 != NULL)
- {
- ret = s->s3->tmp.peer_finish_md_len;
- if (count > ret)
- count = ret;
- memcpy(buf, s->s3->tmp.peer_finish_md, count);
- }
- return ret;
- }
-
-
-int SSL_get_verify_mode(const SSL *s)
- {
- return(s->verify_mode);
- }
-
-int SSL_get_verify_depth(const SSL *s)
- {
- return X509_VERIFY_PARAM_get_depth(s->param);
- }
-
-int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *)
- {
- return(s->verify_callback);
- }
-
-int SSL_CTX_get_verify_mode(const SSL_CTX *ctx)
- {
- return(ctx->verify_mode);
- }
-
-int SSL_CTX_get_verify_depth(const SSL_CTX *ctx)
- {
- return X509_VERIFY_PARAM_get_depth(ctx->param);
- }
-
-int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *)
- {
- return(ctx->default_verify_callback);
- }
-
-void SSL_set_verify(SSL *s,int mode,
- int (*callback)(int ok,X509_STORE_CTX *ctx))
- {
- s->verify_mode=mode;
- if (callback != NULL)
- s->verify_callback=callback;
- }
-
-void SSL_set_verify_depth(SSL *s,int depth)
- {
- X509_VERIFY_PARAM_set_depth(s->param, depth);
- }
-
-void SSL_set_read_ahead(SSL *s,int yes)
- {
- s->read_ahead=yes;
- }
-
-int SSL_get_read_ahead(const SSL *s)
- {
- return(s->read_ahead);
- }
-
-int SSL_pending(const SSL *s)
- {
- /* SSL_pending cannot work properly if read-ahead is enabled
- * (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)),
- * and it is impossible to fix since SSL_pending cannot report
- * errors that may be observed while scanning the new data.
- * (Note that SSL_pending() is often used as a boolean value,
- * so we'd better not return -1.)
- */
- return(s->method->ssl_pending(s));
- }
-
-X509 *SSL_get_peer_certificate(const SSL *s)
- {
- X509 *r;
-
- if ((s == NULL) || (s->session == NULL))
- r=NULL;
- else
- r=s->session->peer;
-
- if (r == NULL) return(r);
-
- CRYPTO_add(&r->references,1,CRYPTO_LOCK_X509);
-
- return(r);
- }
-
-STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
- {
- STACK_OF(X509) *r;
-
- if ((s == NULL) || (s->session == NULL) || (s->session->sess_cert == NULL))
- r=NULL;
- else
- r=s->session->sess_cert->cert_chain;
-
- /* If we are a client, cert_chain includes the peer's own
- * certificate; if we are a server, it does not. */
-
- return(r);
- }
-
-/* Now in theory, since the calling process own 't' it should be safe to
- * modify. We need to be able to read f without being hassled */
-void SSL_copy_session_id(SSL *t,const SSL *f)
- {
- CERT *tmp;
-
- /* Do we need to to SSL locking? */
- SSL_set_session(t,SSL_get_session(f));
-
- /* what if we are setup as SSLv2 but want to talk SSLv3 or
- * vice-versa */
- if (t->method != f->method)
- {
- t->method->ssl_free(t); /* cleanup current */
- t->method=f->method; /* change method */
- t->method->ssl_new(t); /* setup new */
- }
-
- tmp=t->cert;
- if (f->cert != NULL)
- {
- CRYPTO_add(&f->cert->references,1,CRYPTO_LOCK_SSL_CERT);
- t->cert=f->cert;
- }
- else
- t->cert=NULL;
- if (tmp != NULL) ssl_cert_free(tmp);
- SSL_set_session_id_context(t,f->sid_ctx,f->sid_ctx_length);
- }
-
-/* Fix this so it checks all the valid key/cert options */
-int SSL_CTX_check_private_key(const SSL_CTX *ctx)
- {
- if ( (ctx == NULL) ||
- (ctx->cert == NULL) ||
- (ctx->cert->key->x509 == NULL))
- {
- SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
- return(0);
- }
- if (ctx->cert->key->privatekey == NULL)
- {
- SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY,SSL_R_NO_PRIVATE_KEY_ASSIGNED);
- return(0);
- }
- return(X509_check_private_key(ctx->cert->key->x509, ctx->cert->key->privatekey));
- }
-
-/* Fix this function so that it takes an optional type parameter */
-int SSL_check_private_key(const SSL *ssl)
- {
- if (ssl == NULL)
- {
- SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,ERR_R_PASSED_NULL_PARAMETER);
- return(0);
- }
- if (ssl->cert == NULL)
- {
- SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
- return 0;
- }
- if (ssl->cert->key->x509 == NULL)
- {
- SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
- return(0);
- }
- if (ssl->cert->key->privatekey == NULL)
- {
- SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_PRIVATE_KEY_ASSIGNED);
- return(0);
- }
- return(X509_check_private_key(ssl->cert->key->x509,
- ssl->cert->key->privatekey));
- }
-
-int SSL_accept(SSL *s)
- {
- if (s->handshake_func == 0)
- /* Not properly initialized yet */
- SSL_set_accept_state(s);
-
- return(s->method->ssl_accept(s));
- }
-
-int SSL_connect(SSL *s)
- {
- if (s->handshake_func == 0)
- /* Not properly initialized yet */
- SSL_set_connect_state(s);
-
- return(s->method->ssl_connect(s));
- }
-
-long SSL_get_default_timeout(const SSL *s)
- {
- return(s->method->get_timeout());
- }
-
-int SSL_read(SSL *s,void *buf,int num)
- {
- if (s->handshake_func == 0)
- {
- SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
- return -1;
- }
-
- if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
- {
- s->rwstate=SSL_NOTHING;
- return(0);
- }
- return(s->method->ssl_read(s,buf,num));
- }
-
-int SSL_peek(SSL *s,void *buf,int num)
- {
- if (s->handshake_func == 0)
- {
- SSLerr(SSL_F_SSL_PEEK, SSL_R_UNINITIALIZED);
- return -1;
- }
-
- if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
- {
- return(0);
- }
- return(s->method->ssl_peek(s,buf,num));
- }
-
-int SSL_write(SSL *s,const void *buf,int num)
- {
- if (s->handshake_func == 0)
- {
- SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED);
- return -1;
- }
-
- if (s->shutdown & SSL_SENT_SHUTDOWN)
- {
- s->rwstate=SSL_NOTHING;
- SSLerr(SSL_F_SSL_WRITE,SSL_R_PROTOCOL_IS_SHUTDOWN);
- return(-1);
- }
- return(s->method->ssl_write(s,buf,num));
- }
-
-int SSL_shutdown(SSL *s)
- {
- /* Note that this function behaves differently from what one might
- * expect. Return values are 0 for no success (yet),
- * 1 for success; but calling it once is usually not enough,
- * even if blocking I/O is used (see ssl3_shutdown).
- */
-
- if (s->handshake_func == 0)
- {
- SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_UNINITIALIZED);
- return -1;
- }
-
- if ((s != NULL) && !SSL_in_init(s))
- return(s->method->ssl_shutdown(s));
- else
- return(1);
- }
-
-int SSL_renegotiate(SSL *s)
- {
- if (s->renegotiate == 0)
- s->renegotiate=1;
-
- s->new_session=1;
-
- return(s->method->ssl_renegotiate(s));
- }
-
-int SSL_renegotiate_abbreviated(SSL *s)
- {
- if (s->renegotiate == 0)
- s->renegotiate=1;
-
- s->new_session=0;
-
- return(s->method->ssl_renegotiate(s));
- }
-
-int SSL_renegotiate_pending(SSL *s)
- {
- /* becomes true when negotiation is requested;
- * false again once a handshake has finished */
- return (s->renegotiate != 0);
- }
-
-long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
- {
- long l;
-
- switch (cmd)
- {
- case SSL_CTRL_GET_READ_AHEAD:
- return(s->read_ahead);
- case SSL_CTRL_SET_READ_AHEAD:
- l=s->read_ahead;
- s->read_ahead=larg;
- return(l);
-
- case SSL_CTRL_SET_MSG_CALLBACK_ARG:
- s->msg_callback_arg = parg;
- return 1;
-
- case SSL_CTRL_OPTIONS:
- return(s->options|=larg);
- case SSL_CTRL_CLEAR_OPTIONS:
- return(s->options&=~larg);
- case SSL_CTRL_MODE:
- return(s->mode|=larg);
- case SSL_CTRL_CLEAR_MODE:
- return(s->mode &=~larg);
- case SSL_CTRL_GET_MAX_CERT_LIST:
- return(s->max_cert_list);
- case SSL_CTRL_SET_MAX_CERT_LIST:
- l=s->max_cert_list;
- s->max_cert_list=larg;
- return(l);
- case SSL_CTRL_SET_MTU:
-#ifndef OPENSSL_NO_DTLS1
- if (larg < (long)dtls1_min_mtu())
- return 0;
-#endif
-
- if (SSL_version(s) == DTLS1_VERSION ||
- SSL_version(s) == DTLS1_BAD_VER)
- {
- s->d1->mtu = larg;
- return larg;
- }
- return 0;
- case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
- if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
- return 0;
- s->max_send_fragment = larg;
- return 1;
- case SSL_CTRL_GET_RI_SUPPORT:
- if (s->s3)
- return s->s3->send_connection_binding;
- else return 0;
- default:
- return(s->method->ssl_ctrl(s,cmd,larg,parg));
- }
- }
-
-long SSL_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
- {
- switch(cmd)
- {
- case SSL_CTRL_SET_MSG_CALLBACK:
- s->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
- return 1;
-
- default:
- return(s->method->ssl_callback_ctrl(s,cmd,fp));
- }
- }
-
-LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx)
- {
- return ctx->sessions;
- }
-
-long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,void *parg)
- {
- long l;
-
- switch (cmd)
- {
- case SSL_CTRL_GET_READ_AHEAD:
- return(ctx->read_ahead);
- case SSL_CTRL_SET_READ_AHEAD:
- l=ctx->read_ahead;
- ctx->read_ahead=larg;
- return(l);
-
- case SSL_CTRL_SET_MSG_CALLBACK_ARG:
- ctx->msg_callback_arg = parg;
- return 1;
-
- case SSL_CTRL_GET_MAX_CERT_LIST:
- return(ctx->max_cert_list);
- case SSL_CTRL_SET_MAX_CERT_LIST:
- l=ctx->max_cert_list;
- ctx->max_cert_list=larg;
- return(l);
-
- case SSL_CTRL_SET_SESS_CACHE_SIZE:
- l=ctx->session_cache_size;
- ctx->session_cache_size=larg;
- return(l);
- case SSL_CTRL_GET_SESS_CACHE_SIZE:
- return(ctx->session_cache_size);
- case SSL_CTRL_SET_SESS_CACHE_MODE:
- l=ctx->session_cache_mode;
- ctx->session_cache_mode=larg;
- return(l);
- case SSL_CTRL_GET_SESS_CACHE_MODE:
- return(ctx->session_cache_mode);
-
- case SSL_CTRL_SESS_NUMBER:
- return(lh_SSL_SESSION_num_items(ctx->sessions));
- case SSL_CTRL_SESS_CONNECT:
- return(ctx->stats.sess_connect);
- case SSL_CTRL_SESS_CONNECT_GOOD:
- return(ctx->stats.sess_connect_good);
- case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
- return(ctx->stats.sess_connect_renegotiate);
- case SSL_CTRL_SESS_ACCEPT:
- return(ctx->stats.sess_accept);
- case SSL_CTRL_SESS_ACCEPT_GOOD:
- return(ctx->stats.sess_accept_good);
- case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
- return(ctx->stats.sess_accept_renegotiate);
- case SSL_CTRL_SESS_HIT:
- return(ctx->stats.sess_hit);
- case SSL_CTRL_SESS_CB_HIT:
- return(ctx->stats.sess_cb_hit);
- case SSL_CTRL_SESS_MISSES:
- return(ctx->stats.sess_miss);
- case SSL_CTRL_SESS_TIMEOUTS:
- return(ctx->stats.sess_timeout);
- case SSL_CTRL_SESS_CACHE_FULL:
- return(ctx->stats.sess_cache_full);
- case SSL_CTRL_OPTIONS:
- return(ctx->options|=larg);
- case SSL_CTRL_CLEAR_OPTIONS:
- return(ctx->options&=~larg);
- case SSL_CTRL_MODE:
- return(ctx->mode|=larg);
- case SSL_CTRL_CLEAR_MODE:
- return(ctx->mode&=~larg);
- case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
- if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
- return 0;
- ctx->max_send_fragment = larg;
- return 1;
- default:
- return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg));
- }
- }
-
-long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
- {
- switch(cmd)
- {
- case SSL_CTRL_SET_MSG_CALLBACK:
- ctx->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
- return 1;
-
- default:
- return(ctx->method->ssl_ctx_callback_ctrl(ctx,cmd,fp));
- }
- }
-
-int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b)
- {
- long l;
-
- l=a->id-b->id;
- if (l == 0L)
- return(0);
- else
- return((l > 0)?1:-1);
- }
-
-int ssl_cipher_ptr_id_cmp(const SSL_CIPHER * const *ap,
- const SSL_CIPHER * const *bp)
- {
- long l;
-
- l=(*ap)->id-(*bp)->id;
- if (l == 0L)
- return(0);
- else
- return((l > 0)?1:-1);
- }
-
-/** return a STACK of the ciphers available for the SSL and in order of
- * preference */
-STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
- {
- if (s != NULL)
- {
- if (s->cipher_list != NULL)
- {
- return(s->cipher_list);
- }
- else if ((s->ctx != NULL) &&
- (s->ctx->cipher_list != NULL))
- {
- return(s->ctx->cipher_list);
- }
- }
- return(NULL);
- }
-
-/** return a STACK of the ciphers available for the SSL and in order of
- * algorithm id */
-STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s)
- {
- if (s != NULL)
- {
- if (s->cipher_list_by_id != NULL)
- {
- return(s->cipher_list_by_id);
- }
- else if ((s->ctx != NULL) &&
- (s->ctx->cipher_list_by_id != NULL))
- {
- return(s->ctx->cipher_list_by_id);
- }
- }
- return(NULL);
- }
-
-/** The old interface to get the same thing as SSL_get_ciphers() */
-const char *SSL_get_cipher_list(const SSL *s,int n)
- {
- SSL_CIPHER *c;
- STACK_OF(SSL_CIPHER) *sk;
-
- if (s == NULL) return(NULL);
- sk=SSL_get_ciphers(s);
- if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= n))
- return(NULL);
- c=sk_SSL_CIPHER_value(sk,n);
- if (c == NULL) return(NULL);
- return(c->name);
- }
-
-/** specify the ciphers to be used by default by the SSL_CTX */
-int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
- {
- STACK_OF(SSL_CIPHER) *sk;
-
- sk=ssl_create_cipher_list(ctx->method,&ctx->cipher_list,
- &ctx->cipher_list_by_id,str);
- /* ssl_create_cipher_list may return an empty stack if it
- * was unable to find a cipher matching the given rule string
- * (for example if the rule string specifies a cipher which
- * has been disabled). This is not an error as far as
- * ssl_create_cipher_list is concerned, and hence
- * ctx->cipher_list and ctx->cipher_list_by_id has been
- * updated. */
- if (sk == NULL)
- return 0;
- else if (sk_SSL_CIPHER_num(sk) == 0)
- {
- SSLerr(SSL_F_SSL_CTX_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
- return 0;
- }
- return 1;
- }
-
-/** specify the ciphers to be used by the SSL */
-int SSL_set_cipher_list(SSL *s,const char *str)
- {
- STACK_OF(SSL_CIPHER) *sk;
-
- sk=ssl_create_cipher_list(s->ctx->method,&s->cipher_list,
- &s->cipher_list_by_id,str);
- /* see comment in SSL_CTX_set_cipher_list */
- if (sk == NULL)
- return 0;
- else if (sk_SSL_CIPHER_num(sk) == 0)
- {
- SSLerr(SSL_F_SSL_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
- return 0;
- }
- return 1;
- }
-
-/* works well for SSLv2, not so good for SSLv3 */
-char *SSL_get_shared_ciphers(const SSL *s,char *buf,int len)
- {
- char *p;
- STACK_OF(SSL_CIPHER) *sk;
- SSL_CIPHER *c;
- int i;
-
- if ((s->session == NULL) || (s->session->ciphers == NULL) ||
- (len < 2))
- return(NULL);
-
- p=buf;
- sk=s->session->ciphers;
- for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
- {
- int n;
-
- c=sk_SSL_CIPHER_value(sk,i);
- n=strlen(c->name);
- if (n+1 > len)
- {
- if (p != buf)
- --p;
- *p='\0';
- return buf;
- }
- strcpy(p,c->name);
- p+=n;
- *(p++)=':';
- len-=n+1;
- }
- p[-1]='\0';
- return(buf);
- }
-
-int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
- int (*put_cb)(const SSL_CIPHER *, unsigned char *))
- {
- int i,j=0;
- SSL_CIPHER *c;
- unsigned char *q;
-#ifndef OPENSSL_NO_KRB5
- int nokrb5 = !kssl_tgt_is_available(s->kssl_ctx);
-#endif /* OPENSSL_NO_KRB5 */
-
- if (sk == NULL) return(0);
- q=p;
-
- for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
- {
- c=sk_SSL_CIPHER_value(sk,i);
- /* Skip TLS v1.2 only ciphersuites if lower than v1.2 */
- if ((c->algorithm_ssl & SSL_TLSV1_2) &&
- (TLS1_get_client_version(s) < TLS1_2_VERSION))
- continue;
-#ifndef OPENSSL_NO_KRB5
- if (((c->algorithm_mkey & SSL_kKRB5) || (c->algorithm_auth & SSL_aKRB5)) &&
- nokrb5)
- continue;
-#endif /* OPENSSL_NO_KRB5 */
-#ifndef OPENSSL_NO_PSK
- /* with PSK there must be client callback set */
- if (((c->algorithm_mkey & SSL_kPSK) || (c->algorithm_auth & SSL_aPSK)) &&
- s->psk_client_callback == NULL)
- continue;
-#endif /* OPENSSL_NO_PSK */
- j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p);
- p+=j;
- }
- /* If p == q, no ciphers and caller indicates an error. Otherwise
- * add SCSV if not renegotiating.
- */
- if (p != q && !s->renegotiate)
- {
- static SSL_CIPHER scsv =
- {
- 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- j = put_cb ? put_cb(&scsv,p) : ssl_put_cipher_by_char(s,&scsv,p);
- p+=j;
-#ifdef OPENSSL_RI_DEBUG
- fprintf(stderr, "SCSV sent by client\n");
-#endif
- }
-
- return(p-q);
- }
-
-STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
- STACK_OF(SSL_CIPHER) **skp)
- {
- const SSL_CIPHER *c;
- STACK_OF(SSL_CIPHER) *sk;
- int i,n;
- if (s->s3)
- s->s3->send_connection_binding = 0;
-
- n=ssl_put_cipher_by_char(s,NULL,NULL);
- if ((num%n) != 0)
- {
- SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
- return(NULL);
- }
- if ((skp == NULL) || (*skp == NULL))
- sk=sk_SSL_CIPHER_new_null(); /* change perhaps later */
- else
- {
- sk= *skp;
- sk_SSL_CIPHER_zero(sk);
- }
-
- for (i=0; i<num; i+=n)
- {
- /* Check for SCSV */
- if (s->s3 && (n != 3 || !p[0]) &&
- (p[n-2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
- (p[n-1] == (SSL3_CK_SCSV & 0xff)))
- {
- /* SCSV fatal if renegotiating */
- if (s->renegotiate)
- {
- SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
- goto err;
- }
- s->s3->send_connection_binding = 1;
- p += n;
-#ifdef OPENSSL_RI_DEBUG
- fprintf(stderr, "SCSV received by server\n");
-#endif
- continue;
- }
-
- c=ssl_get_cipher_by_char(s,p);
- p+=n;
- if (c != NULL)
- {
- if (!sk_SSL_CIPHER_push(sk,c))
- {
- SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- }
- }
-
- if (skp != NULL)
- *skp=sk;
- return(sk);
-err:
- if ((skp == NULL) || (*skp == NULL))
- sk_SSL_CIPHER_free(sk);
- return(NULL);
- }
-
-
-#ifndef OPENSSL_NO_TLSEXT
-/** return a servername extension value if provided in Client Hello, or NULL.
- * So far, only host_name types are defined (RFC 3546).
- */
-
-const char *SSL_get_servername(const SSL *s, const int type)
- {
- if (type != TLSEXT_NAMETYPE_host_name)
- return NULL;
-
- return s->session && !s->tlsext_hostname ?
- s->session->tlsext_hostname :
- s->tlsext_hostname;
- }
-
-int SSL_get_servername_type(const SSL *s)
- {
- if (s->session && (!s->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname))
- return TLSEXT_NAMETYPE_host_name;
- return -1;
- }
-
-# ifndef OPENSSL_NO_NEXTPROTONEG
-/* SSL_select_next_proto implements the standard protocol selection. It is
- * expected that this function is called from the callback set by
- * SSL_CTX_set_next_proto_select_cb.
- *
- * The protocol data is assumed to be a vector of 8-bit, length prefixed byte
- * strings. The length byte itself is not included in the length. A byte
- * string of length 0 is invalid. No byte string may be truncated.
- *
- * The current, but experimental algorithm for selecting the protocol is:
- *
- * 1) If the server doesn't support NPN then this is indicated to the
- * callback. In this case, the client application has to abort the connection
- * or have a default application level protocol.
- *
- * 2) If the server supports NPN, but advertises an empty list then the
- * client selects the first protcol in its list, but indicates via the
- * API that this fallback case was enacted.
- *
- * 3) Otherwise, the client finds the first protocol in the server's list
- * that it supports and selects this protocol. This is because it's
- * assumed that the server has better information about which protocol
- * a client should use.
- *
- * 4) If the client doesn't support any of the server's advertised
- * protocols, then this is treated the same as case 2.
- *
- * It returns either
- * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or
- * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached.
- */
-int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, const unsigned char *client, unsigned int client_len)
- {
- unsigned int i, j;
- const unsigned char *result;
- int status = OPENSSL_NPN_UNSUPPORTED;
-
- /* For each protocol in server preference order, see if we support it. */
- for (i = 0; i < server_len; )
- {
- for (j = 0; j < client_len; )
- {
- if (server[i] == client[j] &&
- memcmp(&server[i+1], &client[j+1], server[i]) == 0)
- {
- /* We found a match */
- result = &server[i];
- status = OPENSSL_NPN_NEGOTIATED;
- goto found;
- }
- j += client[j];
- j++;
- }
- i += server[i];
- i++;
- }
-
- /* There's no overlap between our protocols and the server's list. */
- result = client;
- status = OPENSSL_NPN_NO_OVERLAP;
-
- found:
- *out = (unsigned char *) result + 1;
- *outlen = result[0];
- return status;
- }
-
-/* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's
- * requested protocol for this connection and returns 0. If the client didn't
- * request any protocol, then *data is set to NULL.
- *
- * Note that the client can request any protocol it chooses. The value returned
- * from this function need not be a member of the list of supported protocols
- * provided by the callback.
- */
-void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, unsigned *len)
- {
- *data = s->next_proto_negotiated;
- if (!*data) {
- *len = 0;
- } else {
- *len = s->next_proto_negotiated_len;
- }
-}
-
-/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a
- * TLS server needs a list of supported protocols for Next Protocol
- * Negotiation. The returned list must be in wire format. The list is returned
- * by setting |out| to point to it and |outlen| to its length. This memory will
- * not be modified, but one should assume that the SSL* keeps a reference to
- * it.
- *
- * The callback should return SSL_TLSEXT_ERR_OK if it wishes to advertise. Otherwise, no
- * such extension will be included in the ServerHello. */
-void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *ctx, int (*cb) (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg), void *arg)
- {
- ctx->next_protos_advertised_cb = cb;
- ctx->next_protos_advertised_cb_arg = arg;
- }
-
-/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a
- * client needs to select a protocol from the server's provided list. |out|
- * must be set to point to the selected protocol (which may be within |in|).
- * The length of the protocol name must be written into |outlen|. The server's
- * advertised protocols are provided in |in| and |inlen|. The callback can
- * assume that |in| is syntactically valid.
- *
- * The client must select a protocol. It is fatal to the connection if this
- * callback returns a value other than SSL_TLSEXT_ERR_OK.
- */
-void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg), void *arg)
- {
- ctx->next_proto_select_cb = cb;
- ctx->next_proto_select_cb_arg = arg;
- }
-# endif
-#endif
-
-int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
- const char *label, size_t llen, const unsigned char *p, size_t plen,
- int use_context)
- {
- if (s->version < TLS1_VERSION)
- return -1;
-
- return s->method->ssl3_enc->export_keying_material(s, out, olen, label,
- llen, p, plen,
- use_context);
- }
-
-static unsigned long ssl_session_hash(const SSL_SESSION *a)
- {
- unsigned long l;
-
- l=(unsigned long)
- ((unsigned int) a->session_id[0] )|
- ((unsigned int) a->session_id[1]<< 8L)|
- ((unsigned long)a->session_id[2]<<16L)|
- ((unsigned long)a->session_id[3]<<24L);
- return(l);
- }
-
-/* NB: If this function (or indeed the hash function which uses a sort of
- * coarser function than this one) is changed, ensure
- * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being
- * able to construct an SSL_SESSION that will collide with any existing session
- * with a matching session ID. */
-static int ssl_session_cmp(const SSL_SESSION *a,const SSL_SESSION *b)
- {
- if (a->ssl_version != b->ssl_version)
- return(1);
- if (a->session_id_length != b->session_id_length)
- return(1);
- return(memcmp(a->session_id,b->session_id,a->session_id_length));
- }
-
-/* These wrapper functions should remain rather than redeclaring
- * SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each
- * variable. The reason is that the functions aren't static, they're exposed via
- * ssl.h. */
-static IMPLEMENT_LHASH_HASH_FN(ssl_session, SSL_SESSION)
-static IMPLEMENT_LHASH_COMP_FN(ssl_session, SSL_SESSION)
-
-SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
- {
- SSL_CTX *ret=NULL;
-
- if (meth == NULL)
- {
- SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_NULL_SSL_METHOD_PASSED);
- return(NULL);
- }
-
-#ifdef OPENSSL_FIPS
- if (FIPS_mode() && (meth->version < TLS1_VERSION))
- {
- SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
- return NULL;
- }
-#endif
-
- if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0)
- {
- SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
- goto err;
- }
- ret=(SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
- if (ret == NULL)
- goto err;
-
- memset(ret,0,sizeof(SSL_CTX));
-
- ret->method=meth;
-
- ret->cert_store=NULL;
- ret->session_cache_mode=SSL_SESS_CACHE_SERVER;
- ret->session_cache_size=SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
- ret->session_cache_head=NULL;
- ret->session_cache_tail=NULL;
-
- /* We take the system default */
- ret->session_timeout=meth->get_timeout();
-
- ret->new_session_cb=0;
- ret->remove_session_cb=0;
- ret->get_session_cb=0;
- ret->generate_session_id=0;
-
- memset((char *)&ret->stats,0,sizeof(ret->stats));
-
- ret->references=1;
- ret->quiet_shutdown=0;
-
-/* ret->cipher=NULL;*/
-/* ret->s2->challenge=NULL;
- ret->master_key=NULL;
- ret->key_arg=NULL;
- ret->s2->conn_id=NULL; */
-
- ret->info_callback=NULL;
-
- ret->app_verify_callback=0;
- ret->app_verify_arg=NULL;
-
- ret->max_cert_list=SSL_MAX_CERT_LIST_DEFAULT;
- ret->read_ahead=0;
- ret->msg_callback=0;
- ret->msg_callback_arg=NULL;
- ret->verify_mode=SSL_VERIFY_NONE;
-#if 0
- ret->verify_depth=-1; /* Don't impose a limit (but x509_lu.c does) */
-#endif
- ret->sid_ctx_length=0;
- ret->default_verify_callback=NULL;
- if ((ret->cert=ssl_cert_new()) == NULL)
- goto err;
-
- ret->default_passwd_callback=0;
- ret->default_passwd_callback_userdata=NULL;
- ret->client_cert_cb=0;
- ret->app_gen_cookie_cb=0;
- ret->app_verify_cookie_cb=0;
-
- ret->sessions=lh_SSL_SESSION_new();
- if (ret->sessions == NULL) goto err;
- ret->cert_store=X509_STORE_new();
- if (ret->cert_store == NULL) goto err;
-
- ssl_create_cipher_list(ret->method,
- &ret->cipher_list,&ret->cipher_list_by_id,
- meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST);
- if (ret->cipher_list == NULL
- || sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
- {
- SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_LIBRARY_HAS_NO_CIPHERS);
- goto err2;
- }
-
- ret->param = X509_VERIFY_PARAM_new();
- if (!ret->param)
- goto err;
-
- if ((ret->rsa_md5=EVP_get_digestbyname("ssl2-md5")) == NULL)
- {
- SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES);
- goto err2;
- }
- if ((ret->md5=EVP_get_digestbyname("ssl3-md5")) == NULL)
- {
- SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES);
- goto err2;
- }
- if ((ret->sha1=EVP_get_digestbyname("ssl3-sha1")) == NULL)
- {
- SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES);
- goto err2;
- }
-
- if ((ret->client_CA=sk_X509_NAME_new_null()) == NULL)
- goto err;
-
- CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data);
-
- ret->extra_certs=NULL;
- /* No compression for DTLS */
- if (meth->version != DTLS1_VERSION)
- ret->comp_methods=SSL_COMP_get_compression_methods();
-
- ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
-
-#ifndef OPENSSL_NO_TLSEXT
- ret->tlsext_servername_callback = 0;
- ret->tlsext_servername_arg = NULL;
- /* Setup RFC4507 ticket keys */
- if ((RAND_pseudo_bytes(ret->tlsext_tick_key_name, 16) <= 0)
- || (RAND_bytes(ret->tlsext_tick_hmac_key, 16) <= 0)
- || (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
- ret->options |= SSL_OP_NO_TICKET;
-
- ret->tlsext_status_cb = 0;
- ret->tlsext_status_arg = NULL;
-
-# ifndef OPENSSL_NO_NEXTPROTONEG
- ret->next_protos_advertised_cb = 0;
- ret->next_proto_select_cb = 0;
-# endif
-#endif
-#ifndef OPENSSL_NO_PSK
- ret->psk_identity_hint=NULL;
- ret->psk_client_callback=NULL;
- ret->psk_server_callback=NULL;
-#endif
-#ifndef OPENSSL_NO_SRP
- SSL_CTX_SRP_CTX_init(ret);
-#endif
-#ifndef OPENSSL_NO_BUF_FREELISTS
- ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT;
- ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
- if (!ret->rbuf_freelist)
- goto err;
- ret->rbuf_freelist->chunklen = 0;
- ret->rbuf_freelist->len = 0;
- ret->rbuf_freelist->head = NULL;
- ret->wbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
- if (!ret->wbuf_freelist)
- {
- OPENSSL_free(ret->rbuf_freelist);
- goto err;
- }
- ret->wbuf_freelist->chunklen = 0;
- ret->wbuf_freelist->len = 0;
- ret->wbuf_freelist->head = NULL;
-#endif
-#ifndef OPENSSL_NO_ENGINE
- ret->client_cert_engine = NULL;
-#ifdef OPENSSL_SSL_CLIENT_ENGINE_AUTO
-#define eng_strx(x) #x
-#define eng_str(x) eng_strx(x)
- /* Use specific client engine automatically... ignore errors */
- {
- ENGINE *eng;
- eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
- if (!eng)
- {
- ERR_clear_error();
- ENGINE_load_builtin_engines();
- eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
- }
- if (!eng || !SSL_CTX_set_client_cert_engine(ret, eng))
- ERR_clear_error();
- }
-#endif
-#endif
- /* Default is to connect to non-RI servers. When RI is more widely
- * deployed might change this.
- */
- ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
-
- return(ret);
-err:
- SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);
-err2:
- if (ret != NULL) SSL_CTX_free(ret);
- return(NULL);
- }
-
-#if 0
-static void SSL_COMP_free(SSL_COMP *comp)
- { OPENSSL_free(comp); }
-#endif
-
-#ifndef OPENSSL_NO_BUF_FREELISTS
-static void
-ssl_buf_freelist_free(SSL3_BUF_FREELIST *list)
- {
- SSL3_BUF_FREELIST_ENTRY *ent, *next;
- for (ent = list->head; ent; ent = next)
- {
- next = ent->next;
- OPENSSL_free(ent);
- }
- OPENSSL_free(list);
- }
-#endif
-
-void SSL_CTX_free(SSL_CTX *a)
- {
- int i;
-
- if (a == NULL) return;
-
- i=CRYPTO_add(&a->references,-1,CRYPTO_LOCK_SSL_CTX);
-#ifdef REF_PRINT
- REF_PRINT("SSL_CTX",a);
-#endif
- if (i > 0) return;
-#ifdef REF_CHECK
- if (i < 0)
- {
- fprintf(stderr,"SSL_CTX_free, bad reference count\n");
- abort(); /* ok */
- }
-#endif
-
- if (a->param)
- X509_VERIFY_PARAM_free(a->param);
-
- /*
- * Free internal session cache. However: the remove_cb() may reference
- * the ex_data of SSL_CTX, thus the ex_data store can only be removed
- * after the sessions were flushed.
- * As the ex_data handling routines might also touch the session cache,
- * the most secure solution seems to be: empty (flush) the cache, then
- * free ex_data, then finally free the cache.
- * (See ticket [openssl.org #212].)
- */
- if (a->sessions != NULL)
- SSL_CTX_flush_sessions(a,0);
-
- CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
-
- if (a->sessions != NULL)
- lh_SSL_SESSION_free(a->sessions);
-
- if (a->cert_store != NULL)
- X509_STORE_free(a->cert_store);
- if (a->cipher_list != NULL)
- sk_SSL_CIPHER_free(a->cipher_list);
- if (a->cipher_list_by_id != NULL)
- sk_SSL_CIPHER_free(a->cipher_list_by_id);
- if (a->cert != NULL)
- ssl_cert_free(a->cert);
- if (a->client_CA != NULL)
- sk_X509_NAME_pop_free(a->client_CA,X509_NAME_free);
- if (a->extra_certs != NULL)
- sk_X509_pop_free(a->extra_certs,X509_free);
-#if 0 /* This should never be done, since it removes a global database */
- if (a->comp_methods != NULL)
- sk_SSL_COMP_pop_free(a->comp_methods,SSL_COMP_free);
-#else
- a->comp_methods = NULL;
-#endif
-
-#ifndef OPENSSL_NO_SRTP
- if (a->srtp_profiles)
- sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles);
-#endif
-
-#ifndef OPENSSL_NO_PSK
- if (a->psk_identity_hint)
- OPENSSL_free(a->psk_identity_hint);
-#endif
-#ifndef OPENSSL_NO_SRP
- SSL_CTX_SRP_CTX_free(a);
-#endif
-#ifndef OPENSSL_NO_ENGINE
- if (a->client_cert_engine)
- ENGINE_finish(a->client_cert_engine);
-#endif
-
-#ifndef OPENSSL_NO_BUF_FREELISTS
- if (a->wbuf_freelist)
- ssl_buf_freelist_free(a->wbuf_freelist);
- if (a->rbuf_freelist)
- ssl_buf_freelist_free(a->rbuf_freelist);
-#endif
-
- OPENSSL_free(a);
- }
-
-void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb)
- {
- ctx->default_passwd_callback=cb;
- }
-
-void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx,void *u)
- {
- ctx->default_passwd_callback_userdata=u;
- }
-
-void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg)
- {
- ctx->app_verify_callback=cb;
- ctx->app_verify_arg=arg;
- }
-
-void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int (*cb)(int, X509_STORE_CTX *))
- {
- ctx->verify_mode=mode;
- ctx->default_verify_callback=cb;
- }
-
-void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth)
- {
- X509_VERIFY_PARAM_set_depth(ctx->param, depth);
- }
-
-void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
- {
- CERT_PKEY *cpk;
- int rsa_enc,rsa_tmp,rsa_sign,dh_tmp,dh_rsa,dh_dsa,dsa_sign;
- int rsa_enc_export,dh_rsa_export,dh_dsa_export;
- int rsa_tmp_export,dh_tmp_export,kl;
- unsigned long mask_k,mask_a,emask_k,emask_a;
- int have_ecc_cert, ecdh_ok, ecdsa_ok, ecc_pkey_size;
-#ifndef OPENSSL_NO_ECDH
- int have_ecdh_tmp;
-#endif
- X509 *x = NULL;
- EVP_PKEY *ecc_pkey = NULL;
- int signature_nid = 0, pk_nid = 0, md_nid = 0;
-
- if (c == NULL) return;
-
- kl=SSL_C_EXPORT_PKEYLENGTH(cipher);
-
-#ifndef OPENSSL_NO_RSA
- rsa_tmp=(c->rsa_tmp != NULL || c->rsa_tmp_cb != NULL);
- rsa_tmp_export=(c->rsa_tmp_cb != NULL ||
- (rsa_tmp && RSA_size(c->rsa_tmp)*8 <= kl));
-#else
- rsa_tmp=rsa_tmp_export=0;
-#endif
-#ifndef OPENSSL_NO_DH
- dh_tmp=(c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
- dh_tmp_export=(c->dh_tmp_cb != NULL ||
- (dh_tmp && DH_size(c->dh_tmp)*8 <= kl));
-#else
- dh_tmp=dh_tmp_export=0;
-#endif
-
-#ifndef OPENSSL_NO_ECDH
- have_ecdh_tmp=(c->ecdh_tmp != NULL || c->ecdh_tmp_cb != NULL);
-#endif
- cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
- rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL);
- rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
- cpk= &(c->pkeys[SSL_PKEY_RSA_SIGN]);
- rsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL);
- cpk= &(c->pkeys[SSL_PKEY_DSA_SIGN]);
- dsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL);
- cpk= &(c->pkeys[SSL_PKEY_DH_RSA]);
- dh_rsa= (cpk->x509 != NULL && cpk->privatekey != NULL);
- dh_rsa_export=(dh_rsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
- cpk= &(c->pkeys[SSL_PKEY_DH_DSA]);
-/* FIX THIS EAY EAY EAY */
- dh_dsa= (cpk->x509 != NULL && cpk->privatekey != NULL);
- dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
- cpk= &(c->pkeys[SSL_PKEY_ECC]);
- have_ecc_cert= (cpk->x509 != NULL && cpk->privatekey != NULL);
- mask_k=0;
- mask_a=0;
- emask_k=0;
- emask_a=0;
-
-
-
-#ifdef CIPHER_DEBUG
- printf("rt=%d rte=%d dht=%d ecdht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n",
- rsa_tmp,rsa_tmp_export,dh_tmp,have_ecdh_tmp,
- rsa_enc,rsa_enc_export,rsa_sign,dsa_sign,dh_rsa,dh_dsa);
-#endif
-
- cpk = &(c->pkeys[SSL_PKEY_GOST01]);
- if (cpk->x509 != NULL && cpk->privatekey !=NULL) {
- mask_k |= SSL_kGOST;
- mask_a |= SSL_aGOST01;
- }
- cpk = &(c->pkeys[SSL_PKEY_GOST94]);
- if (cpk->x509 != NULL && cpk->privatekey !=NULL) {
- mask_k |= SSL_kGOST;
- mask_a |= SSL_aGOST94;
- }
-
- if (rsa_enc || (rsa_tmp && rsa_sign))
- mask_k|=SSL_kRSA;
- if (rsa_enc_export || (rsa_tmp_export && (rsa_sign || rsa_enc)))
- emask_k|=SSL_kRSA;
-
-#if 0
- /* The match needs to be both kEDH and aRSA or aDSA, so don't worry */
- if ( (dh_tmp || dh_rsa || dh_dsa) &&
- (rsa_enc || rsa_sign || dsa_sign))
- mask_k|=SSL_kEDH;
- if ((dh_tmp_export || dh_rsa_export || dh_dsa_export) &&
- (rsa_enc || rsa_sign || dsa_sign))
- emask_k|=SSL_kEDH;
-#endif
-
- if (dh_tmp_export)
- emask_k|=SSL_kEDH;
-
- if (dh_tmp)
- mask_k|=SSL_kEDH;
-
- if (dh_rsa) mask_k|=SSL_kDHr;
- if (dh_rsa_export) emask_k|=SSL_kDHr;
-
- if (dh_dsa) mask_k|=SSL_kDHd;
- if (dh_dsa_export) emask_k|=SSL_kDHd;
-
- if (rsa_enc || rsa_sign)
- {
- mask_a|=SSL_aRSA;
- emask_a|=SSL_aRSA;
- }
-
- if (dsa_sign)
- {
- mask_a|=SSL_aDSS;
- emask_a|=SSL_aDSS;
- }
-
- mask_a|=SSL_aNULL;
- emask_a|=SSL_aNULL;
-
-#ifndef OPENSSL_NO_KRB5
- mask_k|=SSL_kKRB5;
- mask_a|=SSL_aKRB5;
- emask_k|=SSL_kKRB5;
- emask_a|=SSL_aKRB5;
-#endif
-
- /* An ECC certificate may be usable for ECDH and/or
- * ECDSA cipher suites depending on the key usage extension.
- */
- if (have_ecc_cert)
- {
- /* This call populates extension flags (ex_flags) */
- x = (c->pkeys[SSL_PKEY_ECC]).x509;
- X509_check_purpose(x, -1, 0);
- ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
- (x->ex_kusage & X509v3_KU_KEY_AGREEMENT) : 1;
- ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
- (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1;
- ecc_pkey = X509_get_pubkey(x);
- ecc_pkey_size = (ecc_pkey != NULL) ?
- EVP_PKEY_bits(ecc_pkey) : 0;
- EVP_PKEY_free(ecc_pkey);
- if ((x->sig_alg) && (x->sig_alg->algorithm))
- {
- signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
- OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
- }
-#ifndef OPENSSL_NO_ECDH
- if (ecdh_ok)
- {
-
- if (pk_nid == NID_rsaEncryption || pk_nid == NID_rsa)
- {
- mask_k|=SSL_kECDHr;
- mask_a|=SSL_aECDH;
- if (ecc_pkey_size <= 163)
- {
- emask_k|=SSL_kECDHr;
- emask_a|=SSL_aECDH;
- }
- }
-
- if (pk_nid == NID_X9_62_id_ecPublicKey)
- {
- mask_k|=SSL_kECDHe;
- mask_a|=SSL_aECDH;
- if (ecc_pkey_size <= 163)
- {
- emask_k|=SSL_kECDHe;
- emask_a|=SSL_aECDH;
- }
- }
- }
-#endif
-#ifndef OPENSSL_NO_ECDSA
- if (ecdsa_ok)
- {
- mask_a|=SSL_aECDSA;
- emask_a|=SSL_aECDSA;
- }
-#endif
- }
-
-#ifndef OPENSSL_NO_ECDH
- if (have_ecdh_tmp)
- {
- mask_k|=SSL_kEECDH;
- emask_k|=SSL_kEECDH;
- }
-#endif
-
-#ifndef OPENSSL_NO_PSK
- mask_k |= SSL_kPSK;
- mask_a |= SSL_aPSK;
- emask_k |= SSL_kPSK;
- emask_a |= SSL_aPSK;
-#endif
-
- c->mask_k=mask_k;
- c->mask_a=mask_a;
- c->export_mask_k=emask_k;
- c->export_mask_a=emask_a;
- c->valid=1;
- }
-
-/* This handy macro borrowed from crypto/x509v3/v3_purp.c */
-#define ku_reject(x, usage) \
- (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
-
-#ifndef OPENSSL_NO_EC
-
-int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
- {
- unsigned long alg_k, alg_a;
- EVP_PKEY *pkey = NULL;
- int keysize = 0;
- int signature_nid = 0, md_nid = 0, pk_nid = 0;
- const SSL_CIPHER *cs = s->s3->tmp.new_cipher;
-
- alg_k = cs->algorithm_mkey;
- alg_a = cs->algorithm_auth;
-
- if (SSL_C_IS_EXPORT(cs))
- {
- /* ECDH key length in export ciphers must be <= 163 bits */
- pkey = X509_get_pubkey(x);
- if (pkey == NULL) return 0;
- keysize = EVP_PKEY_bits(pkey);
- EVP_PKEY_free(pkey);
- if (keysize > 163) return 0;
- }
-
- /* This call populates the ex_flags field correctly */
- X509_check_purpose(x, -1, 0);
- if ((x->sig_alg) && (x->sig_alg->algorithm))
- {
- signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
- OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
- }
- if (alg_k & SSL_kECDHe || alg_k & SSL_kECDHr)
- {
- /* key usage, if present, must allow key agreement */
- if (ku_reject(x, X509v3_KU_KEY_AGREEMENT))
- {
- SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT);
- return 0;
- }
- if ((alg_k & SSL_kECDHe) && TLS1_get_version(s) < TLS1_2_VERSION)
- {
- /* signature alg must be ECDSA */
- if (pk_nid != NID_X9_62_id_ecPublicKey)
- {
- SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE);
- return 0;
- }
- }
- if ((alg_k & SSL_kECDHr) && TLS1_get_version(s) < TLS1_2_VERSION)
- {
- /* signature alg must be RSA */
-
- if (pk_nid != NID_rsaEncryption && pk_nid != NID_rsa)
- {
- SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE);
- return 0;
- }
- }
- }
- if (alg_a & SSL_aECDSA)
- {
- /* key usage, if present, must allow signing */
- if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
- {
- SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
- return 0;
- }
- }
-
- return 1; /* all checks are ok */
- }
-
-#endif
-
-/* THIS NEEDS CLEANING UP */
-CERT_PKEY *ssl_get_server_send_pkey(const SSL *s)
- {
- unsigned long alg_k,alg_a;
- CERT *c;
- int i;
-
- c=s->cert;
- ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
-
- alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-
- if (alg_k & (SSL_kECDHr|SSL_kECDHe))
- {
- /* we don't need to look at SSL_kEECDH
- * since no certificate is needed for
- * anon ECDH and for authenticated
- * EECDH, the check for the auth
- * algorithm will set i correctly
- * NOTE: For ECDH-RSA, we need an ECC
- * not an RSA cert but for EECDH-RSA
- * we need an RSA cert. Placing the
- * checks for SSL_kECDH before RSA
- * checks ensures the correct cert is chosen.
- */
- i=SSL_PKEY_ECC;
- }
- else if (alg_a & SSL_aECDSA)
- {
- i=SSL_PKEY_ECC;
- }
- else if (alg_k & SSL_kDHr)
- i=SSL_PKEY_DH_RSA;
- else if (alg_k & SSL_kDHd)
- i=SSL_PKEY_DH_DSA;
- else if (alg_a & SSL_aDSS)
- i=SSL_PKEY_DSA_SIGN;
- else if (alg_a & SSL_aRSA)
- {
- if (c->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL)
- i=SSL_PKEY_RSA_SIGN;
- else
- i=SSL_PKEY_RSA_ENC;
- }
- else if (alg_a & SSL_aKRB5)
- {
- /* VRS something else here? */
- return(NULL);
- }
- else if (alg_a & SSL_aGOST94)
- i=SSL_PKEY_GOST94;
- else if (alg_a & SSL_aGOST01)
- i=SSL_PKEY_GOST01;
- else /* if (alg_a & SSL_aNULL) */
- {
- SSLerr(SSL_F_SSL_GET_SERVER_SEND_PKEY,ERR_R_INTERNAL_ERROR);
- return(NULL);
- }
-
- return c->pkeys + i;
- }
-
-X509 *ssl_get_server_send_cert(const SSL *s)
- {
- CERT_PKEY *cpk;
- cpk = ssl_get_server_send_pkey(s);
- if (!cpk)
- return NULL;
- return cpk->x509;
- }
-
-EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
- {
- unsigned long alg_a;
- CERT *c;
- int idx = -1;
-
- alg_a = cipher->algorithm_auth;
- c=s->cert;
-
- if ((alg_a & SSL_aDSS) &&
- (c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL))
- idx = SSL_PKEY_DSA_SIGN;
- else if (alg_a & SSL_aRSA)
- {
- if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL)
- idx = SSL_PKEY_RSA_SIGN;
- else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL)
- idx = SSL_PKEY_RSA_ENC;
- }
- else if ((alg_a & SSL_aECDSA) &&
- (c->pkeys[SSL_PKEY_ECC].privatekey != NULL))
- idx = SSL_PKEY_ECC;
- if (idx == -1)
- {
- SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR);
- return(NULL);
- }
- if (pmd)
- *pmd = c->pkeys[idx].digest;
- return c->pkeys[idx].privatekey;
- }
-
-void ssl_update_cache(SSL *s,int mode)
- {
- int i;
-
- /* If the session_id_length is 0, we are not supposed to cache it,
- * and it would be rather hard to do anyway :-) */
- if (s->session->session_id_length == 0) return;
-
- i=s->session_ctx->session_cache_mode;
- if ((i & mode) && (!s->hit)
- && ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
- || SSL_CTX_add_session(s->session_ctx,s->session))
- && (s->session_ctx->new_session_cb != NULL))
- {
- CRYPTO_add(&s->session->references,1,CRYPTO_LOCK_SSL_SESSION);
- if (!s->session_ctx->new_session_cb(s,s->session))
- SSL_SESSION_free(s->session);
- }
-
- /* auto flush every 255 connections */
- if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) &&
- ((i & mode) == mode))
- {
- if ( (((mode & SSL_SESS_CACHE_CLIENT)
- ?s->session_ctx->stats.sess_connect_good
- :s->session_ctx->stats.sess_accept_good) & 0xff) == 0xff)
- {
- SSL_CTX_flush_sessions(s->session_ctx,(unsigned long)time(NULL));
- }
- }
- }
-
-const SSL_METHOD *SSL_get_ssl_method(SSL *s)
- {
- return(s->method);
- }
-
-int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth)
- {
- int conn= -1;
- int ret=1;
-
- if (s->method != meth)
- {
- if (s->handshake_func != NULL)
- conn=(s->handshake_func == s->method->ssl_connect);
-
- if (s->method->version == meth->version)
- s->method=meth;
- else
- {
- s->method->ssl_free(s);
- s->method=meth;
- ret=s->method->ssl_new(s);
- }
-
- if (conn == 1)
- s->handshake_func=meth->ssl_connect;
- else if (conn == 0)
- s->handshake_func=meth->ssl_accept;
- }
- return(ret);
- }
-
-int SSL_get_error(const SSL *s,int i)
- {
- int reason;
- unsigned long l;
- BIO *bio;
-
- if (i > 0) return(SSL_ERROR_NONE);
-
- /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake
- * etc, where we do encode the error */
- if ((l=ERR_peek_error()) != 0)
- {
- if (ERR_GET_LIB(l) == ERR_LIB_SYS)
- return(SSL_ERROR_SYSCALL);
- else
- return(SSL_ERROR_SSL);
- }
-
- if ((i < 0) && SSL_want_read(s))
- {
- bio=SSL_get_rbio(s);
- if (BIO_should_read(bio))
- return(SSL_ERROR_WANT_READ);
- else if (BIO_should_write(bio))
- /* This one doesn't make too much sense ... We never try
- * to write to the rbio, and an application program where
- * rbio and wbio are separate couldn't even know what it
- * should wait for.
- * However if we ever set s->rwstate incorrectly
- * (so that we have SSL_want_read(s) instead of
- * SSL_want_write(s)) and rbio and wbio *are* the same,
- * this test works around that bug; so it might be safer
- * to keep it. */
- return(SSL_ERROR_WANT_WRITE);
- else if (BIO_should_io_special(bio))
- {
- reason=BIO_get_retry_reason(bio);
- if (reason == BIO_RR_CONNECT)
- return(SSL_ERROR_WANT_CONNECT);
- else if (reason == BIO_RR_ACCEPT)
- return(SSL_ERROR_WANT_ACCEPT);
- else
- return(SSL_ERROR_SYSCALL); /* unknown */
- }
- }
-
- if ((i < 0) && SSL_want_write(s))
- {
- bio=SSL_get_wbio(s);
- if (BIO_should_write(bio))
- return(SSL_ERROR_WANT_WRITE);
- else if (BIO_should_read(bio))
- /* See above (SSL_want_read(s) with BIO_should_write(bio)) */
- return(SSL_ERROR_WANT_READ);
- else if (BIO_should_io_special(bio))
- {
- reason=BIO_get_retry_reason(bio);
- if (reason == BIO_RR_CONNECT)
- return(SSL_ERROR_WANT_CONNECT);
- else if (reason == BIO_RR_ACCEPT)
- return(SSL_ERROR_WANT_ACCEPT);
- else
- return(SSL_ERROR_SYSCALL);
- }
- }
- if ((i < 0) && SSL_want_x509_lookup(s))
- {
- return(SSL_ERROR_WANT_X509_LOOKUP);
- }
-
- if (i == 0)
- {
- if (s->version == SSL2_VERSION)
- {
- /* assume it is the socket being closed */
- return(SSL_ERROR_ZERO_RETURN);
- }
- else
- {
- if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) &&
- (s->s3->warn_alert == SSL_AD_CLOSE_NOTIFY))
- return(SSL_ERROR_ZERO_RETURN);
- }
- }
- return(SSL_ERROR_SYSCALL);
- }
-
-int SSL_do_handshake(SSL *s)
- {
- int ret=1;
-
- if (s->handshake_func == NULL)
- {
- SSLerr(SSL_F_SSL_DO_HANDSHAKE,SSL_R_CONNECTION_TYPE_NOT_SET);
- return(-1);
- }
-
- s->method->ssl_renegotiate_check(s);
-
- if (SSL_in_init(s) || SSL_in_before(s))
- {
- ret=s->handshake_func(s);
- }
- return(ret);
- }
-
-/* For the next 2 functions, SSL_clear() sets shutdown and so
- * one of these calls will reset it */
-void SSL_set_accept_state(SSL *s)
- {
- s->server=1;
- s->shutdown=0;
- s->state=SSL_ST_ACCEPT|SSL_ST_BEFORE;
- s->handshake_func=s->method->ssl_accept;
- /* clear the current cipher */
- ssl_clear_cipher_ctx(s);
- ssl_clear_hash_ctx(&s->read_hash);
- ssl_clear_hash_ctx(&s->write_hash);
- }
-
-void SSL_set_connect_state(SSL *s)
- {
- s->server=0;
- s->shutdown=0;
- s->state=SSL_ST_CONNECT|SSL_ST_BEFORE;
- s->handshake_func=s->method->ssl_connect;
- /* clear the current cipher */
- ssl_clear_cipher_ctx(s);
- ssl_clear_hash_ctx(&s->read_hash);
- ssl_clear_hash_ctx(&s->write_hash);
- }
-
-int ssl_undefined_function(SSL *s)
- {
- SSLerr(SSL_F_SSL_UNDEFINED_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return(0);
- }
-
-int ssl_undefined_void_function(void)
- {
- SSLerr(SSL_F_SSL_UNDEFINED_VOID_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return(0);
- }
-
-int ssl_undefined_const_function(const SSL *s)
- {
- SSLerr(SSL_F_SSL_UNDEFINED_CONST_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return(0);
- }
-
-SSL_METHOD *ssl_bad_method(int ver)
- {
- SSLerr(SSL_F_SSL_BAD_METHOD,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return(NULL);
- }
-
-const char *SSL_get_version(const SSL *s)
- {
- if (s->version == TLS1_2_VERSION)
- return("TLSv1.2");
- else if (s->version == TLS1_1_VERSION)
- return("TLSv1.1");
- else if (s->version == TLS1_VERSION)
- return("TLSv1");
- else if (s->version == SSL3_VERSION)
- return("SSLv3");
- else if (s->version == SSL2_VERSION)
- return("SSLv2");
- else
- return("unknown");
- }
-
-SSL *SSL_dup(SSL *s)
- {
- STACK_OF(X509_NAME) *sk;
- X509_NAME *xn;
- SSL *ret;
- int i;
-
- if ((ret=SSL_new(SSL_get_SSL_CTX(s))) == NULL)
- return(NULL);
-
- ret->version = s->version;
- ret->type = s->type;
- ret->method = s->method;
-
- if (s->session != NULL)
- {
- /* This copies session-id, SSL_METHOD, sid_ctx, and 'cert' */
- SSL_copy_session_id(ret,s);
- }
- else
- {
- /* No session has been established yet, so we have to expect
- * that s->cert or ret->cert will be changed later --
- * they should not both point to the same object,
- * and thus we can't use SSL_copy_session_id. */
-
- ret->method->ssl_free(ret);
- ret->method = s->method;
- ret->method->ssl_new(ret);
-
- if (s->cert != NULL)
- {
- if (ret->cert != NULL)
- {
- ssl_cert_free(ret->cert);
- }
- ret->cert = ssl_cert_dup(s->cert);
- if (ret->cert == NULL)
- goto err;
- }
-
- SSL_set_session_id_context(ret,
- s->sid_ctx, s->sid_ctx_length);
- }
-
- ret->options=s->options;
- ret->mode=s->mode;
- SSL_set_max_cert_list(ret,SSL_get_max_cert_list(s));
- SSL_set_read_ahead(ret,SSL_get_read_ahead(s));
- ret->msg_callback = s->msg_callback;
- ret->msg_callback_arg = s->msg_callback_arg;
- SSL_set_verify(ret,SSL_get_verify_mode(s),
- SSL_get_verify_callback(s));
- SSL_set_verify_depth(ret,SSL_get_verify_depth(s));
- ret->generate_session_id = s->generate_session_id;
-
- SSL_set_info_callback(ret,SSL_get_info_callback(s));
-
- ret->debug=s->debug;
-
- /* copy app data, a little dangerous perhaps */
- if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL, &ret->ex_data, &s->ex_data))
- goto err;
-
- /* setup rbio, and wbio */
- if (s->rbio != NULL)
- {
- if (!BIO_dup_state(s->rbio,(char *)&ret->rbio))
- goto err;
- }
- if (s->wbio != NULL)
- {
- if (s->wbio != s->rbio)
- {
- if (!BIO_dup_state(s->wbio,(char *)&ret->wbio))
- goto err;
- }
- else
- ret->wbio=ret->rbio;
- }
- ret->rwstate = s->rwstate;
- ret->in_handshake = s->in_handshake;
- ret->handshake_func = s->handshake_func;
- ret->server = s->server;
- ret->renegotiate = s->renegotiate;
- ret->new_session = s->new_session;
- ret->quiet_shutdown = s->quiet_shutdown;
- ret->shutdown=s->shutdown;
- ret->state=s->state; /* SSL_dup does not really work at any state, though */
- ret->rstate=s->rstate;
- ret->init_num = 0; /* would have to copy ret->init_buf, ret->init_msg, ret->init_num, ret->init_off */
- ret->hit=s->hit;
-
- X509_VERIFY_PARAM_inherit(ret->param, s->param);
-
- /* dup the cipher_list and cipher_list_by_id stacks */
- if (s->cipher_list != NULL)
- {
- if ((ret->cipher_list=sk_SSL_CIPHER_dup(s->cipher_list)) == NULL)
- goto err;
- }
- if (s->cipher_list_by_id != NULL)
- if ((ret->cipher_list_by_id=sk_SSL_CIPHER_dup(s->cipher_list_by_id))
- == NULL)
- goto err;
-
- /* Dup the client_CA list */
- if (s->client_CA != NULL)
- {
- if ((sk=sk_X509_NAME_dup(s->client_CA)) == NULL) goto err;
- ret->client_CA=sk;
- for (i=0; i<sk_X509_NAME_num(sk); i++)
- {
- xn=sk_X509_NAME_value(sk,i);
- if (sk_X509_NAME_set(sk,i,X509_NAME_dup(xn)) == NULL)
- {
- X509_NAME_free(xn);
- goto err;
- }
- }
- }
-
- if (0)
- {
-err:
- if (ret != NULL) SSL_free(ret);
- ret=NULL;
- }
- return(ret);
- }
-
-void ssl_clear_cipher_ctx(SSL *s)
- {
- if (s->enc_read_ctx != NULL)
- {
- EVP_CIPHER_CTX_cleanup(s->enc_read_ctx);
- OPENSSL_free(s->enc_read_ctx);
- s->enc_read_ctx=NULL;
- }
- if (s->enc_write_ctx != NULL)
- {
- EVP_CIPHER_CTX_cleanup(s->enc_write_ctx);
- OPENSSL_free(s->enc_write_ctx);
- s->enc_write_ctx=NULL;
- }
-#ifndef OPENSSL_NO_COMP
- if (s->expand != NULL)
- {
- COMP_CTX_free(s->expand);
- s->expand=NULL;
- }
- if (s->compress != NULL)
- {
- COMP_CTX_free(s->compress);
- s->compress=NULL;
- }
-#endif
- }
-
-/* Fix this function so that it takes an optional type parameter */
-X509 *SSL_get_certificate(const SSL *s)
- {
- if (s->cert != NULL)
- return(s->cert->key->x509);
- else
- return(NULL);
- }
-
-/* Fix this function so that it takes an optional type parameter */
-EVP_PKEY *SSL_get_privatekey(SSL *s)
- {
- if (s->cert != NULL)
- return(s->cert->key->privatekey);
- else
- return(NULL);
- }
-
-const SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
- {
- if ((s->session != NULL) && (s->session->cipher != NULL))
- return(s->session->cipher);
- return(NULL);
- }
-#ifdef OPENSSL_NO_COMP
-const void *SSL_get_current_compression(SSL *s)
- {
- return NULL;
- }
-const void *SSL_get_current_expansion(SSL *s)
- {
- return NULL;
- }
-#else
-
-const COMP_METHOD *SSL_get_current_compression(SSL *s)
- {
- if (s->compress != NULL)
- return(s->compress->meth);
- return(NULL);
- }
-
-const COMP_METHOD *SSL_get_current_expansion(SSL *s)
- {
- if (s->expand != NULL)
- return(s->expand->meth);
- return(NULL);
- }
-#endif
-
-int ssl_init_wbio_buffer(SSL *s,int push)
- {
- BIO *bbio;
-
- if (s->bbio == NULL)
- {
- bbio=BIO_new(BIO_f_buffer());
- if (bbio == NULL) return(0);
- s->bbio=bbio;
- }
- else
- {
- bbio=s->bbio;
- if (s->bbio == s->wbio)
- s->wbio=BIO_pop(s->wbio);
- }
- (void)BIO_reset(bbio);
-/* if (!BIO_set_write_buffer_size(bbio,16*1024)) */
- if (!BIO_set_read_buffer_size(bbio,1))
- {
- SSLerr(SSL_F_SSL_INIT_WBIO_BUFFER,ERR_R_BUF_LIB);
- return(0);
- }
- if (push)
- {
- if (s->wbio != bbio)
- s->wbio=BIO_push(bbio,s->wbio);
- }
- else
- {
- if (s->wbio == bbio)
- s->wbio=BIO_pop(bbio);
- }
- return(1);
- }
-
-void ssl_free_wbio_buffer(SSL *s)
- {
- if (s->bbio == NULL) return;
-
- if (s->bbio == s->wbio)
- {
- /* remove buffering */
- s->wbio=BIO_pop(s->wbio);
-#ifdef REF_CHECK /* not the usual REF_CHECK, but this avoids adding one more preprocessor symbol */
- assert(s->wbio != NULL);
-#endif
- }
- BIO_free(s->bbio);
- s->bbio=NULL;
- }
-
-void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode)
- {
- ctx->quiet_shutdown=mode;
- }
-
-int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx)
- {
- return(ctx->quiet_shutdown);
- }
-
-void SSL_set_quiet_shutdown(SSL *s,int mode)
- {
- s->quiet_shutdown=mode;
- }
-
-int SSL_get_quiet_shutdown(const SSL *s)
- {
- return(s->quiet_shutdown);
- }
-
-void SSL_set_shutdown(SSL *s,int mode)
- {
- s->shutdown=mode;
- }
-
-int SSL_get_shutdown(const SSL *s)
- {
- return(s->shutdown);
- }
-
-int SSL_version(const SSL *s)
- {
- return(s->version);
- }
-
-SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
- {
- return(ssl->ctx);
- }
-
-SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
- {
- if (ssl->ctx == ctx)
- return ssl->ctx;
-#ifndef OPENSSL_NO_TLSEXT
- if (ctx == NULL)
- ctx = ssl->initial_ctx;
-#endif
- if (ssl->cert != NULL)
- ssl_cert_free(ssl->cert);
- ssl->cert = ssl_cert_dup(ctx->cert);
- CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
- if (ssl->ctx != NULL)
- SSL_CTX_free(ssl->ctx); /* decrement reference count */
- ssl->ctx = ctx;
- return(ssl->ctx);
- }
-
-#ifndef OPENSSL_NO_STDIO
-int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
- {
- return(X509_STORE_set_default_paths(ctx->cert_store));
- }
-
-int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
- const char *CApath)
- {
- return(X509_STORE_load_locations(ctx->cert_store,CAfile,CApath));
- }
-#endif
-
-void SSL_set_info_callback(SSL *ssl,
- void (*cb)(const SSL *ssl,int type,int val))
- {
- ssl->info_callback=cb;
- }
-
-/* One compiler (Diab DCC) doesn't like argument names in returned
- function pointer. */
-void (*SSL_get_info_callback(const SSL *ssl))(const SSL * /*ssl*/,int /*type*/,int /*val*/)
- {
- return ssl->info_callback;
- }
-
-int SSL_state(const SSL *ssl)
- {
- return(ssl->state);
- }
-
-void SSL_set_state(SSL *ssl, int state)
- {
- ssl->state = state;
- }
-
-void SSL_set_verify_result(SSL *ssl,long arg)
- {
- ssl->verify_result=arg;
- }
-
-long SSL_get_verify_result(const SSL *ssl)
- {
- return(ssl->verify_result);
- }
-
-int SSL_get_ex_new_index(long argl,void *argp,CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func,CRYPTO_EX_free *free_func)
- {
- return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, argl, argp,
- new_func, dup_func, free_func);
- }
-
-int SSL_set_ex_data(SSL *s,int idx,void *arg)
- {
- return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
- }
-
-void *SSL_get_ex_data(const SSL *s,int idx)
- {
- return(CRYPTO_get_ex_data(&s->ex_data,idx));
- }
-
-int SSL_CTX_get_ex_new_index(long argl,void *argp,CRYPTO_EX_new *new_func,
- CRYPTO_EX_dup *dup_func,CRYPTO_EX_free *free_func)
- {
- return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, argl, argp,
- new_func, dup_func, free_func);
- }
-
-int SSL_CTX_set_ex_data(SSL_CTX *s,int idx,void *arg)
- {
- return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
- }
-
-void *SSL_CTX_get_ex_data(const SSL_CTX *s,int idx)
- {
- return(CRYPTO_get_ex_data(&s->ex_data,idx));
- }
-
-int ssl_ok(SSL *s)
- {
- return(1);
- }
-
-X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx)
- {
- return(ctx->cert_store);
- }
-
-void SSL_CTX_set_cert_store(SSL_CTX *ctx,X509_STORE *store)
- {
- if (ctx->cert_store != NULL)
- X509_STORE_free(ctx->cert_store);
- ctx->cert_store=store;
- }
-
-int SSL_want(const SSL *s)
- {
- return(s->rwstate);
- }
-
-/*!
- * \brief Set the callback for generating temporary RSA keys.
- * \param ctx the SSL context.
- * \param cb the callback
- */
-
-#ifndef OPENSSL_NO_RSA
-void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,RSA *(*cb)(SSL *ssl,
- int is_export,
- int keylength))
- {
- SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,(void (*)(void))cb);
- }
-
-void SSL_set_tmp_rsa_callback(SSL *ssl,RSA *(*cb)(SSL *ssl,
- int is_export,
- int keylength))
- {
- SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_RSA_CB,(void (*)(void))cb);
- }
-#endif
-
-#ifdef DOXYGEN
-/*!
- * \brief The RSA temporary key callback function.
- * \param ssl the SSL session.
- * \param is_export \c TRUE if the temp RSA key is for an export ciphersuite.
- * \param keylength if \c is_export is \c TRUE, then \c keylength is the size
- * of the required key in bits.
- * \return the temporary RSA key.
- * \sa SSL_CTX_set_tmp_rsa_callback, SSL_set_tmp_rsa_callback
- */
-
-RSA *cb(SSL *ssl,int is_export,int keylength)
- {}
-#endif
-
-/*!
- * \brief Set the callback for generating temporary DH keys.
- * \param ctx the SSL context.
- * \param dh the callback
- */
-
-#ifndef OPENSSL_NO_DH
-void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int is_export,
- int keylength))
- {
- SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
- }
-
-void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export,
- int keylength))
- {
- SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
- }
-#endif
-
-#ifndef OPENSSL_NO_ECDH
-void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
- int keylength))
- {
- SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
- }
-
-void SSL_set_tmp_ecdh_callback(SSL *ssl,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
- int keylength))
- {
- SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
- }
-#endif
-
-#ifndef OPENSSL_NO_PSK
-int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
- {
- if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN)
- {
- SSLerr(SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
- return 0;
- }
- if (ctx->psk_identity_hint != NULL)
- OPENSSL_free(ctx->psk_identity_hint);
- if (identity_hint != NULL)
- {
- ctx->psk_identity_hint = BUF_strdup(identity_hint);
- if (ctx->psk_identity_hint == NULL)
- return 0;
- }
- else
- ctx->psk_identity_hint = NULL;
- return 1;
- }
-
-int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint)
- {
- if (s == NULL)
- return 0;
-
- if (s->session == NULL)
- return 1; /* session not created yet, ignored */
-
- if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN)
- {
- SSLerr(SSL_F_SSL_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
- return 0;
- }
- if (s->session->psk_identity_hint != NULL)
- OPENSSL_free(s->session->psk_identity_hint);
- if (identity_hint != NULL)
- {
- s->session->psk_identity_hint = BUF_strdup(identity_hint);
- if (s->session->psk_identity_hint == NULL)
- return 0;
- }
- else
- s->session->psk_identity_hint = NULL;
- return 1;
- }
-
-const char *SSL_get_psk_identity_hint(const SSL *s)
- {
- if (s == NULL || s->session == NULL)
- return NULL;
- return(s->session->psk_identity_hint);
- }
-
-const char *SSL_get_psk_identity(const SSL *s)
- {
- if (s == NULL || s->session == NULL)
- return NULL;
- return(s->session->psk_identity);
- }
-
-void SSL_set_psk_client_callback(SSL *s,
- unsigned int (*cb)(SSL *ssl, const char *hint,
- char *identity, unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len))
- {
- s->psk_client_callback = cb;
- }
-
-void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx,
- unsigned int (*cb)(SSL *ssl, const char *hint,
- char *identity, unsigned int max_identity_len, unsigned char *psk,
- unsigned int max_psk_len))
- {
- ctx->psk_client_callback = cb;
- }
-
-void SSL_set_psk_server_callback(SSL *s,
- unsigned int (*cb)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len))
- {
- s->psk_server_callback = cb;
- }
-
-void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx,
- unsigned int (*cb)(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len))
- {
- ctx->psk_server_callback = cb;
- }
-#endif
-
-void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
- {
- SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
- }
-void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
- {
- SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
- }
-
-/* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
- * vairable, freeing EVP_MD_CTX previously stored in that variable, if
- * any. If EVP_MD pointer is passed, initializes ctx with this md
- * Returns newly allocated ctx;
- */
-
-EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md)
-{
- ssl_clear_hash_ctx(hash);
- *hash = EVP_MD_CTX_create();
- if (md) EVP_DigestInit_ex(*hash,md,NULL);
- return *hash;
-}
-void ssl_clear_hash_ctx(EVP_MD_CTX **hash)
-{
-
- if (*hash) EVP_MD_CTX_destroy(*hash);
- *hash=NULL;
-}
-
-void SSL_set_debug(SSL *s, int debug)
- {
- s->debug = debug;
- }
-
-int SSL_cache_hit(SSL *s)
- {
- return s->hit;
- }
-
-#if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
-#include "../crypto/bio/bss_file.c"
-#endif
-
-IMPLEMENT_STACK_OF(SSL_CIPHER)
-IMPLEMENT_STACK_OF(SSL_COMP)
-IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER,
- ssl_cipher_id);
diff --git a/drivers/builtin_openssl/ssl/t1_enc.c b/drivers/builtin_openssl/ssl/t1_enc.c
deleted file mode 100644
index 0c4cddedf8..0000000000
--- a/drivers/builtin_openssl/ssl/t1_enc.c
+++ /dev/null
@@ -1,1254 +0,0 @@
-/* ssl/t1_enc.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#ifndef OPENSSL_NO_COMP
-#include <openssl/comp.h>
-#endif
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/md5.h>
-#include <openssl/rand.h>
-#ifdef KSSL_DEBUG
-#include <openssl/des.h>
-#endif
-
-/* seed1 through seed5 are virtually concatenated */
-static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
- int sec_len,
- const void *seed1, int seed1_len,
- const void *seed2, int seed2_len,
- const void *seed3, int seed3_len,
- const void *seed4, int seed4_len,
- const void *seed5, int seed5_len,
- unsigned char *out, int olen)
- {
- int chunk;
- size_t j;
- EVP_MD_CTX ctx, ctx_tmp;
- EVP_PKEY *mac_key;
- unsigned char A1[EVP_MAX_MD_SIZE];
- size_t A1_len;
- int ret = 0;
-
- chunk=EVP_MD_size(md);
- OPENSSL_assert(chunk >= 0);
-
- EVP_MD_CTX_init(&ctx);
- EVP_MD_CTX_init(&ctx_tmp);
- EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
- EVP_MD_CTX_set_flags(&ctx_tmp, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
- mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len);
- if (!mac_key)
- goto err;
- if (!EVP_DigestSignInit(&ctx,NULL,md, NULL, mac_key))
- goto err;
- if (!EVP_DigestSignInit(&ctx_tmp,NULL,md, NULL, mac_key))
- goto err;
- if (seed1 && !EVP_DigestSignUpdate(&ctx,seed1,seed1_len))
- goto err;
- if (seed2 && !EVP_DigestSignUpdate(&ctx,seed2,seed2_len))
- goto err;
- if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
- goto err;
- if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
- goto err;
- if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
- goto err;
- if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
- goto err;
-
- for (;;)
- {
- /* Reinit mac contexts */
- if (!EVP_DigestSignInit(&ctx,NULL,md, NULL, mac_key))
- goto err;
- if (!EVP_DigestSignInit(&ctx_tmp,NULL,md, NULL, mac_key))
- goto err;
- if (!EVP_DigestSignUpdate(&ctx,A1,A1_len))
- goto err;
- if (!EVP_DigestSignUpdate(&ctx_tmp,A1,A1_len))
- goto err;
- if (seed1 && !EVP_DigestSignUpdate(&ctx,seed1,seed1_len))
- goto err;
- if (seed2 && !EVP_DigestSignUpdate(&ctx,seed2,seed2_len))
- goto err;
- if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
- goto err;
- if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
- goto err;
- if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
- goto err;
-
- if (olen > chunk)
- {
- if (!EVP_DigestSignFinal(&ctx,out,&j))
- goto err;
- out+=j;
- olen-=j;
- /* calc the next A1 value */
- if (!EVP_DigestSignFinal(&ctx_tmp,A1,&A1_len))
- goto err;
- }
- else /* last one */
- {
- if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
- goto err;
- memcpy(out,A1,olen);
- break;
- }
- }
- ret = 1;
-err:
- EVP_PKEY_free(mac_key);
- EVP_MD_CTX_cleanup(&ctx);
- EVP_MD_CTX_cleanup(&ctx_tmp);
- OPENSSL_cleanse(A1,sizeof(A1));
- return ret;
- }
-
-/* seed1 through seed5 are virtually concatenated */
-static int tls1_PRF(long digest_mask,
- const void *seed1, int seed1_len,
- const void *seed2, int seed2_len,
- const void *seed3, int seed3_len,
- const void *seed4, int seed4_len,
- const void *seed5, int seed5_len,
- const unsigned char *sec, int slen,
- unsigned char *out1,
- unsigned char *out2, int olen)
- {
- int len,i,idx,count;
- const unsigned char *S1;
- long m;
- const EVP_MD *md;
- int ret = 0;
-
- /* Count number of digests and partition sec evenly */
- count=0;
- for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
- if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) count++;
- }
- len=slen/count;
- if (count == 1)
- slen = 0;
- S1=sec;
- memset(out1,0,olen);
- for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
- if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) {
- if (!md) {
- SSLerr(SSL_F_TLS1_PRF,
- SSL_R_UNSUPPORTED_DIGEST_TYPE);
- goto err;
- }
- if (!tls1_P_hash(md ,S1,len+(slen&1),
- seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
- out2,olen))
- goto err;
- S1+=len;
- for (i=0; i<olen; i++)
- {
- out1[i]^=out2[i];
- }
- }
- }
- ret = 1;
-err:
- return ret;
-}
-static int tls1_generate_key_block(SSL *s, unsigned char *km,
- unsigned char *tmp, int num)
- {
- int ret;
- ret = tls1_PRF(ssl_get_algorithm2(s),
- TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
- s->s3->server_random,SSL3_RANDOM_SIZE,
- s->s3->client_random,SSL3_RANDOM_SIZE,
- NULL,0,NULL,0,
- s->session->master_key,s->session->master_key_length,
- km,tmp,num);
-#ifdef KSSL_DEBUG
- printf("tls1_generate_key_block() ==> %d byte master_key =\n\t",
- s->session->master_key_length);
- {
- int i;
- for (i=0; i < s->session->master_key_length; i++)
- {
- printf("%02X", s->session->master_key[i]);
- }
- printf("\n"); }
-#endif /* KSSL_DEBUG */
- return ret;
- }
-
-int tls1_change_cipher_state(SSL *s, int which)
- {
- static const unsigned char empty[]="";
- unsigned char *p,*mac_secret;
- unsigned char *exp_label;
- unsigned char tmp1[EVP_MAX_KEY_LENGTH];
- unsigned char tmp2[EVP_MAX_KEY_LENGTH];
- unsigned char iv1[EVP_MAX_IV_LENGTH*2];
- unsigned char iv2[EVP_MAX_IV_LENGTH*2];
- unsigned char *ms,*key,*iv;
- int client_write;
- EVP_CIPHER_CTX *dd;
- const EVP_CIPHER *c;
-#ifndef OPENSSL_NO_COMP
- const SSL_COMP *comp;
-#endif
- const EVP_MD *m;
- int mac_type;
- int *mac_secret_size;
- EVP_MD_CTX *mac_ctx;
- EVP_PKEY *mac_key;
- int is_export,n,i,j,k,exp_label_len,cl;
- int reuse_dd = 0;
-
- is_export=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
- c=s->s3->tmp.new_sym_enc;
- m=s->s3->tmp.new_hash;
- mac_type = s->s3->tmp.new_mac_pkey_type;
-#ifndef OPENSSL_NO_COMP
- comp=s->s3->tmp.new_compression;
-#endif
-
-#ifdef KSSL_DEBUG
- printf("tls1_change_cipher_state(which= %d) w/\n", which);
- printf("\talg= %ld/%ld, comp= %p\n",
- s->s3->tmp.new_cipher->algorithm_mkey,
- s->s3->tmp.new_cipher->algorithm_auth,
- comp);
- printf("\tevp_cipher == %p ==? &d_cbc_ede_cipher3\n", c);
- printf("\tevp_cipher: nid, blksz= %d, %d, keylen=%d, ivlen=%d\n",
- c->nid,c->block_size,c->key_len,c->iv_len);
- printf("\tkey_block: len= %d, data= ", s->s3->tmp.key_block_length);
- {
- int i;
- for (i=0; i<s->s3->tmp.key_block_length; i++)
- printf("%02x", s->s3->tmp.key_block[i]); printf("\n");
- }
-#endif /* KSSL_DEBUG */
-
- if (which & SSL3_CC_READ)
- {
- if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
- s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM;
- else
- s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM;
-
- if (s->enc_read_ctx != NULL)
- reuse_dd = 1;
- else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
- goto err;
- else
- /* make sure it's intialized in case we exit later with an error */
- EVP_CIPHER_CTX_init(s->enc_read_ctx);
- dd= s->enc_read_ctx;
- mac_ctx=ssl_replace_hash(&s->read_hash,NULL);
-#ifndef OPENSSL_NO_COMP
- if (s->expand != NULL)
- {
- COMP_CTX_free(s->expand);
- s->expand=NULL;
- }
- if (comp != NULL)
- {
- s->expand=COMP_CTX_new(comp->method);
- if (s->expand == NULL)
- {
- SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR);
- goto err2;
- }
- if (s->s3->rrec.comp == NULL)
- s->s3->rrec.comp=(unsigned char *)
- OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH);
- if (s->s3->rrec.comp == NULL)
- goto err;
- }
-#endif
- /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
- if (s->version != DTLS1_VERSION)
- memset(&(s->s3->read_sequence[0]),0,8);
- mac_secret= &(s->s3->read_mac_secret[0]);
- mac_secret_size=&(s->s3->read_mac_secret_size);
- }
- else
- {
- if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
- s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
- else
- s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM;
- if (s->enc_write_ctx != NULL && !SSL_IS_DTLS(s))
- reuse_dd = 1;
- else if ((s->enc_write_ctx=EVP_CIPHER_CTX_new()) == NULL)
- goto err;
- dd= s->enc_write_ctx;
- if (SSL_IS_DTLS(s))
- {
- mac_ctx = EVP_MD_CTX_create();
- if (!mac_ctx)
- goto err;
- s->write_hash = mac_ctx;
- }
- else
- mac_ctx = ssl_replace_hash(&s->write_hash,NULL);
-#ifndef OPENSSL_NO_COMP
- if (s->compress != NULL)
- {
- COMP_CTX_free(s->compress);
- s->compress=NULL;
- }
- if (comp != NULL)
- {
- s->compress=COMP_CTX_new(comp->method);
- if (s->compress == NULL)
- {
- SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR);
- goto err2;
- }
- }
-#endif
- /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
- if (s->version != DTLS1_VERSION)
- memset(&(s->s3->write_sequence[0]),0,8);
- mac_secret= &(s->s3->write_mac_secret[0]);
- mac_secret_size = &(s->s3->write_mac_secret_size);
- }
-
- if (reuse_dd)
- EVP_CIPHER_CTX_cleanup(dd);
-
- p=s->s3->tmp.key_block;
- i=*mac_secret_size=s->s3->tmp.new_mac_secret_size;
-
- cl=EVP_CIPHER_key_length(c);
- j=is_export ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
- cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
- /* Was j=(exp)?5:EVP_CIPHER_key_length(c); */
- /* If GCM mode only part of IV comes from PRF */
- if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
- k = EVP_GCM_TLS_FIXED_IV_LEN;
- else
- k=EVP_CIPHER_iv_length(c);
- if ( (which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
- (which == SSL3_CHANGE_CIPHER_SERVER_READ))
- {
- ms= &(p[ 0]); n=i+i;
- key= &(p[ n]); n+=j+j;
- iv= &(p[ n]); n+=k+k;
- exp_label=(unsigned char *)TLS_MD_CLIENT_WRITE_KEY_CONST;
- exp_label_len=TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE;
- client_write=1;
- }
- else
- {
- n=i;
- ms= &(p[ n]); n+=i+j;
- key= &(p[ n]); n+=j+k;
- iv= &(p[ n]); n+=k;
- exp_label=(unsigned char *)TLS_MD_SERVER_WRITE_KEY_CONST;
- exp_label_len=TLS_MD_SERVER_WRITE_KEY_CONST_SIZE;
- client_write=0;
- }
-
- if (n > s->s3->tmp.key_block_length)
- {
- SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,ERR_R_INTERNAL_ERROR);
- goto err2;
- }
-
- memcpy(mac_secret,ms,i);
-
- if (!(EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER))
- {
- mac_key = EVP_PKEY_new_mac_key(mac_type, NULL,
- mac_secret,*mac_secret_size);
- EVP_DigestSignInit(mac_ctx,NULL,m,NULL,mac_key);
- EVP_PKEY_free(mac_key);
- }
-#ifdef TLS_DEBUG
-printf("which = %04X\nmac key=",which);
-{ int z; for (z=0; z<i; z++) printf("%02X%c",ms[z],((z+1)%16)?' ':'\n'); }
-#endif
- if (is_export)
- {
- /* In here I set both the read and write key/iv to the
- * same value since only the correct one will be used :-).
- */
- if (!tls1_PRF(ssl_get_algorithm2(s),
- exp_label,exp_label_len,
- s->s3->client_random,SSL3_RANDOM_SIZE,
- s->s3->server_random,SSL3_RANDOM_SIZE,
- NULL,0,NULL,0,
- key,j,tmp1,tmp2,EVP_CIPHER_key_length(c)))
- goto err2;
- key=tmp1;
-
- if (k > 0)
- {
- if (!tls1_PRF(ssl_get_algorithm2(s),
- TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE,
- s->s3->client_random,SSL3_RANDOM_SIZE,
- s->s3->server_random,SSL3_RANDOM_SIZE,
- NULL,0,NULL,0,
- empty,0,iv1,iv2,k*2))
- goto err2;
- if (client_write)
- iv=iv1;
- else
- iv= &(iv1[k]);
- }
- }
-
- s->session->key_arg_length=0;
-#ifdef KSSL_DEBUG
- {
- int i;
- printf("EVP_CipherInit_ex(dd,c,key=,iv=,which)\n");
- printf("\tkey= "); for (i=0; i<c->key_len; i++) printf("%02x", key[i]);
- printf("\n");
- printf("\t iv= "); for (i=0; i<c->iv_len; i++) printf("%02x", iv[i]);
- printf("\n");
- }
-#endif /* KSSL_DEBUG */
-
- if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
- {
- EVP_CipherInit_ex(dd,c,NULL,key,NULL,(which & SSL3_CC_WRITE));
- EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GCM_SET_IV_FIXED, k, iv);
- }
- else
- EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE));
-
- /* Needed for "composite" AEADs, such as RC4-HMAC-MD5 */
- if ((EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER) && *mac_secret_size)
- EVP_CIPHER_CTX_ctrl(dd,EVP_CTRL_AEAD_SET_MAC_KEY,
- *mac_secret_size,mac_secret);
-
-#ifdef TLS_DEBUG
-printf("which = %04X\nkey=",which);
-{ int z; for (z=0; z<EVP_CIPHER_key_length(c); z++) printf("%02X%c",key[z],((z+1)%16)?' ':'\n'); }
-printf("\niv=");
-{ int z; for (z=0; z<k; z++) printf("%02X%c",iv[z],((z+1)%16)?' ':'\n'); }
-printf("\n");
-#endif
-
- OPENSSL_cleanse(tmp1,sizeof(tmp1));
- OPENSSL_cleanse(tmp2,sizeof(tmp1));
- OPENSSL_cleanse(iv1,sizeof(iv1));
- OPENSSL_cleanse(iv2,sizeof(iv2));
- return(1);
-err:
- SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,ERR_R_MALLOC_FAILURE);
-err2:
- return(0);
- }
-
-int tls1_setup_key_block(SSL *s)
- {
- unsigned char *p1,*p2=NULL;
- const EVP_CIPHER *c;
- const EVP_MD *hash;
- int num;
- SSL_COMP *comp;
- int mac_type= NID_undef,mac_secret_size=0;
- int ret=0;
-
-#ifdef KSSL_DEBUG
- printf ("tls1_setup_key_block()\n");
-#endif /* KSSL_DEBUG */
-
- if (s->s3->tmp.key_block_length != 0)
- return(1);
-
- if (!ssl_cipher_get_evp(s->session,&c,&hash,&mac_type,&mac_secret_size,&comp))
- {
- SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
- return(0);
- }
-
- s->s3->tmp.new_sym_enc=c;
- s->s3->tmp.new_hash=hash;
- s->s3->tmp.new_mac_pkey_type = mac_type;
- s->s3->tmp.new_mac_secret_size = mac_secret_size;
- num=EVP_CIPHER_key_length(c)+mac_secret_size+EVP_CIPHER_iv_length(c);
- num*=2;
-
- ssl3_cleanup_key_block(s);
-
- if ((p1=(unsigned char *)OPENSSL_malloc(num)) == NULL)
- {
- SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- s->s3->tmp.key_block_length=num;
- s->s3->tmp.key_block=p1;
-
- if ((p2=(unsigned char *)OPENSSL_malloc(num)) == NULL)
- {
- SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
-#ifdef TLS_DEBUG
-printf("client random\n");
-{ int z; for (z=0; z<SSL3_RANDOM_SIZE; z++) printf("%02X%c",s->s3->client_random[z],((z+1)%16)?' ':'\n'); }
-printf("server random\n");
-{ int z; for (z=0; z<SSL3_RANDOM_SIZE; z++) printf("%02X%c",s->s3->server_random[z],((z+1)%16)?' ':'\n'); }
-printf("pre-master\n");
-{ int z; for (z=0; z<s->session->master_key_length; z++) printf("%02X%c",s->session->master_key[z],((z+1)%16)?' ':'\n'); }
-#endif
- if (!tls1_generate_key_block(s,p1,p2,num))
- goto err;
-#ifdef TLS_DEBUG
-printf("\nkey block\n");
-{ int z; for (z=0; z<num; z++) printf("%02X%c",p1[z],((z+1)%16)?' ':'\n'); }
-#endif
-
- if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
- && s->method->version <= TLS1_VERSION)
- {
- /* enable vulnerability countermeasure for CBC ciphers with
- * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt)
- */
- s->s3->need_empty_fragments = 1;
-
- if (s->session->cipher != NULL)
- {
- if (s->session->cipher->algorithm_enc == SSL_eNULL)
- s->s3->need_empty_fragments = 0;
-
-#ifndef OPENSSL_NO_RC4
- if (s->session->cipher->algorithm_enc == SSL_RC4)
- s->s3->need_empty_fragments = 0;
-#endif
- }
- }
-
- ret = 1;
-err:
- if (p2)
- {
- OPENSSL_cleanse(p2,num);
- OPENSSL_free(p2);
- }
- return(ret);
- }
-
-/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
- *
- * Returns:
- * 0: (in non-constant time) if the record is publically invalid (i.e. too
- * short etc).
- * 1: if the record's padding is valid / the encryption was successful.
- * -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
- * an internal error occured.
- */
-int tls1_enc(SSL *s, int send)
- {
- SSL3_RECORD *rec;
- EVP_CIPHER_CTX *ds;
- unsigned long l;
- int bs,i,j,k,pad=0,ret,mac_size=0;
- const EVP_CIPHER *enc;
-
- if (send)
- {
- if (EVP_MD_CTX_md(s->write_hash))
- {
- int n=EVP_MD_CTX_size(s->write_hash);
- OPENSSL_assert(n >= 0);
- }
- ds=s->enc_write_ctx;
- rec= &(s->s3->wrec);
- if (s->enc_write_ctx == NULL)
- enc=NULL;
- else
- {
- int ivlen;
- enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
- /* For TLSv1.1 and later explicit IV */
- if (s->version >= TLS1_1_VERSION
- && EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE)
- ivlen = EVP_CIPHER_iv_length(enc);
- else
- ivlen = 0;
- if (ivlen > 1)
- {
- if ( rec->data != rec->input)
- /* we can't write into the input stream:
- * Can this ever happen?? (steve)
- */
- fprintf(stderr,
- "%s:%d: rec->data != rec->input\n",
- __FILE__, __LINE__);
- else if (RAND_bytes(rec->input, ivlen) <= 0)
- return -1;
- }
- }
- }
- else
- {
- if (EVP_MD_CTX_md(s->read_hash))
- {
- int n=EVP_MD_CTX_size(s->read_hash);
- OPENSSL_assert(n >= 0);
- }
- ds=s->enc_read_ctx;
- rec= &(s->s3->rrec);
- if (s->enc_read_ctx == NULL)
- enc=NULL;
- else
- enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
- }
-
-#ifdef KSSL_DEBUG
- printf("tls1_enc(%d)\n", send);
-#endif /* KSSL_DEBUG */
-
- if ((s->session == NULL) || (ds == NULL) || (enc == NULL))
- {
- memmove(rec->data,rec->input,rec->length);
- rec->input=rec->data;
- ret = 1;
- }
- else
- {
- l=rec->length;
- bs=EVP_CIPHER_block_size(ds->cipher);
-
- if (EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_AEAD_CIPHER)
- {
- unsigned char buf[13],*seq;
-
- seq = send?s->s3->write_sequence:s->s3->read_sequence;
-
- if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
- {
- unsigned char dtlsseq[9],*p=dtlsseq;
-
- s2n(send?s->d1->w_epoch:s->d1->r_epoch,p);
- memcpy(p,&seq[2],6);
- memcpy(buf,dtlsseq,8);
- }
- else
- {
- memcpy(buf,seq,8);
- for (i=7; i>=0; i--) /* increment */
- {
- ++seq[i];
- if (seq[i] != 0) break;
- }
- }
-
- buf[8]=rec->type;
- buf[9]=(unsigned char)(s->version>>8);
- buf[10]=(unsigned char)(s->version);
- buf[11]=rec->length>>8;
- buf[12]=rec->length&0xff;
- pad=EVP_CIPHER_CTX_ctrl(ds,EVP_CTRL_AEAD_TLS1_AAD,13,buf);
- if (send)
- {
- l+=pad;
- rec->length+=pad;
- }
- }
- else if ((bs != 1) && send)
- {
- i=bs-((int)l%bs);
-
- /* Add weird padding of upto 256 bytes */
-
- /* we need to add 'i' padding bytes of value j */
- j=i-1;
- if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
- {
- if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
- j++;
- }
- for (k=(int)l; k<(int)(l+i); k++)
- rec->input[k]=j;
- l+=i;
- rec->length+=i;
- }
-
-#ifdef KSSL_DEBUG
- {
- unsigned long ui;
- printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
- ds,rec->data,rec->input,l);
- printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
- ds->buf_len, ds->cipher->key_len,
- DES_KEY_SZ, DES_SCHEDULE_SZ,
- ds->cipher->iv_len);
- printf("\t\tIV: ");
- for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
- printf("\n");
- printf("\trec->input=");
- for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]);
- printf("\n");
- }
-#endif /* KSSL_DEBUG */
-
- if (!send)
- {
- if (l == 0 || l%bs != 0)
- return 0;
- }
-
- i = EVP_Cipher(ds,rec->data,rec->input,l);
- if ((EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_CUSTOM_CIPHER)
- ?(i<0)
- :(i==0))
- return -1; /* AEAD can fail to verify MAC */
- if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE && !send)
- {
- rec->data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
- rec->input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
- rec->length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
- }
-
-#ifdef KSSL_DEBUG
- {
- unsigned long i;
- printf("\trec->data=");
- for (i=0; i<l; i++)
- printf(" %02x", rec->data[i]); printf("\n");
- }
-#endif /* KSSL_DEBUG */
-
- ret = 1;
- if (EVP_MD_CTX_md(s->read_hash) != NULL)
- mac_size = EVP_MD_CTX_size(s->read_hash);
- if ((bs != 1) && !send)
- ret = tls1_cbc_remove_padding(s, rec, bs, mac_size);
- if (pad && !send)
- rec->length -= pad;
- }
- return ret;
- }
-
-int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out)
- {
- unsigned int ret;
- EVP_MD_CTX ctx, *d=NULL;
- int i;
-
- if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
- return 0;
-
- for (i=0;i<SSL_MAX_DIGEST;i++)
- {
- if (s->s3->handshake_dgst[i]&&EVP_MD_CTX_type(s->s3->handshake_dgst[i])==md_nid)
- {
- d=s->s3->handshake_dgst[i];
- break;
- }
- }
- if (!d) {
- SSLerr(SSL_F_TLS1_CERT_VERIFY_MAC,SSL_R_NO_REQUIRED_DIGEST);
- return 0;
- }
-
- EVP_MD_CTX_init(&ctx);
- EVP_MD_CTX_copy_ex(&ctx,d);
- EVP_DigestFinal_ex(&ctx,out,&ret);
- EVP_MD_CTX_cleanup(&ctx);
- return((int)ret);
- }
-
-int tls1_final_finish_mac(SSL *s,
- const char *str, int slen, unsigned char *out)
- {
- unsigned int i;
- EVP_MD_CTX ctx;
- unsigned char buf[2*EVP_MAX_MD_SIZE];
- unsigned char *q,buf2[12];
- int idx;
- long mask;
- int err=0;
- const EVP_MD *md;
-
- q=buf;
-
- if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
- return 0;
-
- EVP_MD_CTX_init(&ctx);
-
- for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++)
- {
- if (mask & ssl_get_algorithm2(s))
- {
- int hashsize = EVP_MD_size(md);
- EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx];
- if (!hdgst || hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf)))
- {
- /* internal error: 'buf' is too small for this cipersuite! */
- err = 1;
- }
- else
- {
- if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) ||
- !EVP_DigestFinal_ex(&ctx,q,&i) ||
- (i != (unsigned int)hashsize))
- err = 1;
- q+=hashsize;
- }
- }
- }
-
- if (!tls1_PRF(ssl_get_algorithm2(s),
- str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0,
- s->session->master_key,s->session->master_key_length,
- out,buf2,sizeof buf2))
- err = 1;
- EVP_MD_CTX_cleanup(&ctx);
-
- if (err)
- return 0;
- else
- return sizeof buf2;
- }
-
-int tls1_mac(SSL *ssl, unsigned char *md, int send)
- {
- SSL3_RECORD *rec;
- unsigned char *seq;
- EVP_MD_CTX *hash;
- size_t md_size, orig_len;
- int i;
- EVP_MD_CTX hmac, *mac_ctx;
- unsigned char header[13];
- int stream_mac = (send?(ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM):(ssl->mac_flags&SSL_MAC_FLAG_READ_MAC_STREAM));
- int t;
-
- if (send)
- {
- rec= &(ssl->s3->wrec);
- seq= &(ssl->s3->write_sequence[0]);
- hash=ssl->write_hash;
- }
- else
- {
- rec= &(ssl->s3->rrec);
- seq= &(ssl->s3->read_sequence[0]);
- hash=ssl->read_hash;
- }
-
- t=EVP_MD_CTX_size(hash);
- OPENSSL_assert(t >= 0);
- md_size=t;
-
- /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
- if (stream_mac)
- {
- mac_ctx = hash;
- }
- else
- {
- if (!EVP_MD_CTX_copy(&hmac,hash))
- return -1;
- mac_ctx = &hmac;
- }
-
- if (ssl->version == DTLS1_VERSION || ssl->version == DTLS1_BAD_VER)
- {
- unsigned char dtlsseq[8],*p=dtlsseq;
-
- s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p);
- memcpy (p,&seq[2],6);
-
- memcpy(header, dtlsseq, 8);
- }
- else
- memcpy(header, seq, 8);
-
- /* kludge: tls1_cbc_remove_padding passes padding length in rec->type */
- orig_len = rec->length+md_size+((unsigned int)rec->type>>8);
- rec->type &= 0xff;
-
- header[8]=rec->type;
- header[9]=(unsigned char)(ssl->version>>8);
- header[10]=(unsigned char)(ssl->version);
- header[11]=(rec->length)>>8;
- header[12]=(rec->length)&0xff;
-
- if (!send &&
- EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
- ssl3_cbc_record_digest_supported(mac_ctx))
- {
- /* This is a CBC-encrypted record. We must avoid leaking any
- * timing-side channel information about how many blocks of
- * data we are hashing because that gives an attacker a
- * timing-oracle. */
- ssl3_cbc_digest_record(
- mac_ctx,
- md, &md_size,
- header, rec->input,
- rec->length + md_size, orig_len,
- ssl->s3->read_mac_secret,
- ssl->s3->read_mac_secret_size,
- 0 /* not SSLv3 */);
- }
- else
- {
- EVP_DigestSignUpdate(mac_ctx,header,sizeof(header));
- EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length);
- t=EVP_DigestSignFinal(mac_ctx,md,&md_size);
- OPENSSL_assert(t > 0);
-#ifdef OPENSSL_FIPS
- if (!send && FIPS_mode())
- tls_fips_digest_extra(
- ssl->enc_read_ctx,
- mac_ctx, rec->input,
- rec->length, orig_len);
-#endif
- }
-
- if (!stream_mac)
- EVP_MD_CTX_cleanup(&hmac);
-#ifdef TLS_DEBUG
-printf("sec=");
-{unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",mac_sec[z]); printf("\n"); }
-printf("seq=");
-{int z; for (z=0; z<8; z++) printf("%02X ",seq[z]); printf("\n"); }
-printf("buf=");
-{int z; for (z=0; z<5; z++) printf("%02X ",buf[z]); printf("\n"); }
-printf("rec=");
-{unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
-#endif
-
- if (ssl->version != DTLS1_VERSION && ssl->version != DTLS1_BAD_VER)
- {
- for (i=7; i>=0; i--)
- {
- ++seq[i];
- if (seq[i] != 0) break;
- }
- }
-
-#ifdef TLS_DEBUG
-{unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",md[z]); printf("\n"); }
-#endif
- return(md_size);
- }
-
-int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
- int len)
- {
- unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
- const void *co = NULL, *so = NULL;
- int col = 0, sol = 0;
-
-
-#ifdef KSSL_DEBUG
- printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
-#endif /* KSSL_DEBUG */
-
-#ifdef TLSEXT_TYPE_opaque_prf_input
- if (s->s3->client_opaque_prf_input != NULL && s->s3->server_opaque_prf_input != NULL &&
- s->s3->client_opaque_prf_input_len > 0 &&
- s->s3->client_opaque_prf_input_len == s->s3->server_opaque_prf_input_len)
- {
- co = s->s3->client_opaque_prf_input;
- col = s->s3->server_opaque_prf_input_len;
- so = s->s3->server_opaque_prf_input;
- sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */
- }
-#endif
-
- tls1_PRF(ssl_get_algorithm2(s),
- TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
- s->s3->client_random,SSL3_RANDOM_SIZE,
- co, col,
- s->s3->server_random,SSL3_RANDOM_SIZE,
- so, sol,
- p,len,
- s->session->master_key,buff,sizeof buff);
-#ifdef SSL_DEBUG
- fprintf(stderr, "Premaster Secret:\n");
- BIO_dump_fp(stderr, (char *)p, len);
- fprintf(stderr, "Client Random:\n");
- BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE);
- fprintf(stderr, "Server Random:\n");
- BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE);
- fprintf(stderr, "Master Secret:\n");
- BIO_dump_fp(stderr, (char *)s->session->master_key, SSL3_MASTER_SECRET_SIZE);
-#endif
-
-#ifdef KSSL_DEBUG
- printf ("tls1_generate_master_secret() complete\n");
-#endif /* KSSL_DEBUG */
- return(SSL3_MASTER_SECRET_SIZE);
- }
-
-int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
- const char *label, size_t llen, const unsigned char *context,
- size_t contextlen, int use_context)
- {
- unsigned char *buff;
- unsigned char *val = NULL;
- size_t vallen, currentvalpos;
- int rv;
-
-#ifdef KSSL_DEBUG
- printf ("tls1_export_keying_material(%p,%p,%d,%s,%d,%p,%d)\n", s, out, olen, label, llen, p, plen);
-#endif /* KSSL_DEBUG */
-
- buff = OPENSSL_malloc(olen);
- if (buff == NULL) goto err2;
-
- /* construct PRF arguments
- * we construct the PRF argument ourself rather than passing separate
- * values into the TLS PRF to ensure that the concatenation of values
- * does not create a prohibited label.
- */
- vallen = llen + SSL3_RANDOM_SIZE * 2;
- if (use_context)
- {
- vallen += 2 + contextlen;
- }
-
- val = OPENSSL_malloc(vallen);
- if (val == NULL) goto err2;
- currentvalpos = 0;
- memcpy(val + currentvalpos, (unsigned char *) label, llen);
- currentvalpos += llen;
- memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE);
- currentvalpos += SSL3_RANDOM_SIZE;
- memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE);
- currentvalpos += SSL3_RANDOM_SIZE;
-
- if (use_context)
- {
- val[currentvalpos] = (contextlen >> 8) & 0xff;
- currentvalpos++;
- val[currentvalpos] = contextlen & 0xff;
- currentvalpos++;
- if ((contextlen > 0) || (context != NULL))
- {
- memcpy(val + currentvalpos, context, contextlen);
- }
- }
-
- /* disallow prohibited labels
- * note that SSL3_RANDOM_SIZE > max(prohibited label len) =
- * 15, so size of val > max(prohibited label len) = 15 and the
- * comparisons won't have buffer overflow
- */
- if (memcmp(val, TLS_MD_CLIENT_FINISH_CONST,
- TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0) goto err1;
- if (memcmp(val, TLS_MD_SERVER_FINISH_CONST,
- TLS_MD_SERVER_FINISH_CONST_SIZE) == 0) goto err1;
- if (memcmp(val, TLS_MD_MASTER_SECRET_CONST,
- TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) goto err1;
- if (memcmp(val, TLS_MD_KEY_EXPANSION_CONST,
- TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0) goto err1;
-
- rv = tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
- val, vallen,
- NULL, 0,
- NULL, 0,
- NULL, 0,
- NULL, 0,
- s->session->master_key,s->session->master_key_length,
- out,buff,olen);
-
-#ifdef KSSL_DEBUG
- printf ("tls1_export_keying_material() complete\n");
-#endif /* KSSL_DEBUG */
- goto ret;
-err1:
- SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL);
- rv = 0;
- goto ret;
-err2:
- SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, ERR_R_MALLOC_FAILURE);
- rv = 0;
-ret:
- if (buff != NULL) OPENSSL_free(buff);
- if (val != NULL) OPENSSL_free(val);
- return(rv);
- }
-
-int tls1_alert_code(int code)
- {
- switch (code)
- {
- case SSL_AD_CLOSE_NOTIFY: return(SSL3_AD_CLOSE_NOTIFY);
- case SSL_AD_UNEXPECTED_MESSAGE: return(SSL3_AD_UNEXPECTED_MESSAGE);
- case SSL_AD_BAD_RECORD_MAC: return(SSL3_AD_BAD_RECORD_MAC);
- case SSL_AD_DECRYPTION_FAILED: return(TLS1_AD_DECRYPTION_FAILED);
- case SSL_AD_RECORD_OVERFLOW: return(TLS1_AD_RECORD_OVERFLOW);
- case SSL_AD_DECOMPRESSION_FAILURE:return(SSL3_AD_DECOMPRESSION_FAILURE);
- case SSL_AD_HANDSHAKE_FAILURE: return(SSL3_AD_HANDSHAKE_FAILURE);
- case SSL_AD_NO_CERTIFICATE: return(-1);
- case SSL_AD_BAD_CERTIFICATE: return(SSL3_AD_BAD_CERTIFICATE);
- case SSL_AD_UNSUPPORTED_CERTIFICATE:return(SSL3_AD_UNSUPPORTED_CERTIFICATE);
- case SSL_AD_CERTIFICATE_REVOKED:return(SSL3_AD_CERTIFICATE_REVOKED);
- case SSL_AD_CERTIFICATE_EXPIRED:return(SSL3_AD_CERTIFICATE_EXPIRED);
- case SSL_AD_CERTIFICATE_UNKNOWN:return(SSL3_AD_CERTIFICATE_UNKNOWN);
- case SSL_AD_ILLEGAL_PARAMETER: return(SSL3_AD_ILLEGAL_PARAMETER);
- case SSL_AD_UNKNOWN_CA: return(TLS1_AD_UNKNOWN_CA);
- case SSL_AD_ACCESS_DENIED: return(TLS1_AD_ACCESS_DENIED);
- case SSL_AD_DECODE_ERROR: return(TLS1_AD_DECODE_ERROR);
- case SSL_AD_DECRYPT_ERROR: return(TLS1_AD_DECRYPT_ERROR);
- case SSL_AD_EXPORT_RESTRICTION: return(TLS1_AD_EXPORT_RESTRICTION);
- case SSL_AD_PROTOCOL_VERSION: return(TLS1_AD_PROTOCOL_VERSION);
- case SSL_AD_INSUFFICIENT_SECURITY:return(TLS1_AD_INSUFFICIENT_SECURITY);
- case SSL_AD_INTERNAL_ERROR: return(TLS1_AD_INTERNAL_ERROR);
- case SSL_AD_USER_CANCELLED: return(TLS1_AD_USER_CANCELLED);
- case SSL_AD_NO_RENEGOTIATION: return(TLS1_AD_NO_RENEGOTIATION);
- case SSL_AD_UNSUPPORTED_EXTENSION: return(TLS1_AD_UNSUPPORTED_EXTENSION);
- case SSL_AD_CERTIFICATE_UNOBTAINABLE: return(TLS1_AD_CERTIFICATE_UNOBTAINABLE);
- case SSL_AD_UNRECOGNIZED_NAME: return(TLS1_AD_UNRECOGNIZED_NAME);
- case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE);
- case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE);
- case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY);
-#if 0 /* not appropriate for TLS, not used for DTLS */
- case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return
- (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
-#endif
- default: return(-1);
- }
- }
diff --git a/drivers/builtin_openssl/ssl/t1_lib.c b/drivers/builtin_openssl/ssl/t1_lib.c
deleted file mode 100644
index 9fadf92e11..0000000000
--- a/drivers/builtin_openssl/ssl/t1_lib.c
+++ /dev/null
@@ -1,2729 +0,0 @@
-/* ssl/t1_lib.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include "ssl_locl.h"
-#include <stdio.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/ocsp.h>
-#include <openssl/rand.h>
-
-const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
-
-#ifndef OPENSSL_NO_TLSEXT
-static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
- const unsigned char *sess_id, int sesslen,
- SSL_SESSION **psess);
-#endif
-
-SSL3_ENC_METHOD TLSv1_enc_data={
- tls1_enc,
- tls1_mac,
- tls1_setup_key_block,
- tls1_generate_master_secret,
- tls1_change_cipher_state,
- tls1_final_finish_mac,
- TLS1_FINISH_MAC_LENGTH,
- tls1_cert_verify_mac,
- TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
- TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
- tls1_alert_code,
- tls1_export_keying_material,
- };
-
-long tls1_default_timeout(void)
- {
- /* 2 hours, the 24 hours mentioned in the TLSv1 spec
- * is way too long for http, the cache would over fill */
- return(60*60*2);
- }
-
-int tls1_new(SSL *s)
- {
- if (!ssl3_new(s)) return(0);
- s->method->ssl_clear(s);
- return(1);
- }
-
-void tls1_free(SSL *s)
- {
-#ifndef OPENSSL_NO_TLSEXT
- if (s->tlsext_session_ticket)
- {
- OPENSSL_free(s->tlsext_session_ticket);
- }
-#endif /* OPENSSL_NO_TLSEXT */
- ssl3_free(s);
- }
-
-void tls1_clear(SSL *s)
- {
- ssl3_clear(s);
- s->version = s->method->version;
- }
-
-#ifndef OPENSSL_NO_EC
-
-static int nid_list[] =
- {
- NID_sect163k1, /* sect163k1 (1) */
- NID_sect163r1, /* sect163r1 (2) */
- NID_sect163r2, /* sect163r2 (3) */
- NID_sect193r1, /* sect193r1 (4) */
- NID_sect193r2, /* sect193r2 (5) */
- NID_sect233k1, /* sect233k1 (6) */
- NID_sect233r1, /* sect233r1 (7) */
- NID_sect239k1, /* sect239k1 (8) */
- NID_sect283k1, /* sect283k1 (9) */
- NID_sect283r1, /* sect283r1 (10) */
- NID_sect409k1, /* sect409k1 (11) */
- NID_sect409r1, /* sect409r1 (12) */
- NID_sect571k1, /* sect571k1 (13) */
- NID_sect571r1, /* sect571r1 (14) */
- NID_secp160k1, /* secp160k1 (15) */
- NID_secp160r1, /* secp160r1 (16) */
- NID_secp160r2, /* secp160r2 (17) */
- NID_secp192k1, /* secp192k1 (18) */
- NID_X9_62_prime192v1, /* secp192r1 (19) */
- NID_secp224k1, /* secp224k1 (20) */
- NID_secp224r1, /* secp224r1 (21) */
- NID_secp256k1, /* secp256k1 (22) */
- NID_X9_62_prime256v1, /* secp256r1 (23) */
- NID_secp384r1, /* secp384r1 (24) */
- NID_secp521r1 /* secp521r1 (25) */
- };
-
-static int pref_list[] =
- {
- NID_sect571r1, /* sect571r1 (14) */
- NID_sect571k1, /* sect571k1 (13) */
- NID_secp521r1, /* secp521r1 (25) */
- NID_sect409k1, /* sect409k1 (11) */
- NID_sect409r1, /* sect409r1 (12) */
- NID_secp384r1, /* secp384r1 (24) */
- NID_sect283k1, /* sect283k1 (9) */
- NID_sect283r1, /* sect283r1 (10) */
- NID_secp256k1, /* secp256k1 (22) */
- NID_X9_62_prime256v1, /* secp256r1 (23) */
- NID_sect239k1, /* sect239k1 (8) */
- NID_sect233k1, /* sect233k1 (6) */
- NID_sect233r1, /* sect233r1 (7) */
- NID_secp224k1, /* secp224k1 (20) */
- NID_secp224r1, /* secp224r1 (21) */
- NID_sect193r1, /* sect193r1 (4) */
- NID_sect193r2, /* sect193r2 (5) */
- NID_secp192k1, /* secp192k1 (18) */
- NID_X9_62_prime192v1, /* secp192r1 (19) */
- NID_sect163k1, /* sect163k1 (1) */
- NID_sect163r1, /* sect163r1 (2) */
- NID_sect163r2, /* sect163r2 (3) */
- NID_secp160k1, /* secp160k1 (15) */
- NID_secp160r1, /* secp160r1 (16) */
- NID_secp160r2, /* secp160r2 (17) */
- };
-
-int tls1_ec_curve_id2nid(int curve_id)
- {
- /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
- if ((curve_id < 1) || ((unsigned int)curve_id >
- sizeof(nid_list)/sizeof(nid_list[0])))
- return 0;
- return nid_list[curve_id-1];
- }
-
-int tls1_ec_nid2curve_id(int nid)
- {
- /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
- switch (nid)
- {
- case NID_sect163k1: /* sect163k1 (1) */
- return 1;
- case NID_sect163r1: /* sect163r1 (2) */
- return 2;
- case NID_sect163r2: /* sect163r2 (3) */
- return 3;
- case NID_sect193r1: /* sect193r1 (4) */
- return 4;
- case NID_sect193r2: /* sect193r2 (5) */
- return 5;
- case NID_sect233k1: /* sect233k1 (6) */
- return 6;
- case NID_sect233r1: /* sect233r1 (7) */
- return 7;
- case NID_sect239k1: /* sect239k1 (8) */
- return 8;
- case NID_sect283k1: /* sect283k1 (9) */
- return 9;
- case NID_sect283r1: /* sect283r1 (10) */
- return 10;
- case NID_sect409k1: /* sect409k1 (11) */
- return 11;
- case NID_sect409r1: /* sect409r1 (12) */
- return 12;
- case NID_sect571k1: /* sect571k1 (13) */
- return 13;
- case NID_sect571r1: /* sect571r1 (14) */
- return 14;
- case NID_secp160k1: /* secp160k1 (15) */
- return 15;
- case NID_secp160r1: /* secp160r1 (16) */
- return 16;
- case NID_secp160r2: /* secp160r2 (17) */
- return 17;
- case NID_secp192k1: /* secp192k1 (18) */
- return 18;
- case NID_X9_62_prime192v1: /* secp192r1 (19) */
- return 19;
- case NID_secp224k1: /* secp224k1 (20) */
- return 20;
- case NID_secp224r1: /* secp224r1 (21) */
- return 21;
- case NID_secp256k1: /* secp256k1 (22) */
- return 22;
- case NID_X9_62_prime256v1: /* secp256r1 (23) */
- return 23;
- case NID_secp384r1: /* secp384r1 (24) */
- return 24;
- case NID_secp521r1: /* secp521r1 (25) */
- return 25;
- default:
- return 0;
- }
- }
-#endif /* OPENSSL_NO_EC */
-
-#ifndef OPENSSL_NO_TLSEXT
-
-/* List of supported signature algorithms and hashes. Should make this
- * customisable at some point, for now include everything we support.
- */
-
-#ifdef OPENSSL_NO_RSA
-#define tlsext_sigalg_rsa(md) /* */
-#else
-#define tlsext_sigalg_rsa(md) md, TLSEXT_signature_rsa,
-#endif
-
-#ifdef OPENSSL_NO_DSA
-#define tlsext_sigalg_dsa(md) /* */
-#else
-#define tlsext_sigalg_dsa(md) md, TLSEXT_signature_dsa,
-#endif
-
-#ifdef OPENSSL_NO_ECDSA
-#define tlsext_sigalg_ecdsa(md) /* */
-#else
-#define tlsext_sigalg_ecdsa(md) md, TLSEXT_signature_ecdsa,
-#endif
-
-#define tlsext_sigalg(md) \
- tlsext_sigalg_rsa(md) \
- tlsext_sigalg_dsa(md) \
- tlsext_sigalg_ecdsa(md)
-
-static unsigned char tls12_sigalgs[] = {
-#ifndef OPENSSL_NO_SHA512
- tlsext_sigalg(TLSEXT_hash_sha512)
- tlsext_sigalg(TLSEXT_hash_sha384)
-#endif
-#ifndef OPENSSL_NO_SHA256
- tlsext_sigalg(TLSEXT_hash_sha256)
- tlsext_sigalg(TLSEXT_hash_sha224)
-#endif
-#ifndef OPENSSL_NO_SHA
- tlsext_sigalg(TLSEXT_hash_sha1)
-#endif
-};
-
-int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
- {
- size_t slen = sizeof(tls12_sigalgs);
- if (p)
- memcpy(p, tls12_sigalgs, slen);
- return (int)slen;
- }
-
-unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
- {
- int extdatalen=0;
- unsigned char *ret = p;
-
- /* don't add extensions for SSLv3 unless doing secure renegotiation */
- if (s->client_version == SSL3_VERSION
- && !s->s3->send_connection_binding)
- return p;
-
- ret+=2;
-
- if (ret>=limit) return NULL; /* this really never occurs, but ... */
-
- if (s->tlsext_hostname != NULL)
- {
- /* Add TLS extension servername to the Client Hello message */
- unsigned long size_str;
- long lenmax;
-
- /* check for enough space.
- 4 for the servername type and entension length
- 2 for servernamelist length
- 1 for the hostname type
- 2 for hostname length
- + hostname length
- */
-
- if ((lenmax = limit - ret - 9) < 0
- || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
- return NULL;
-
- /* extension type and length */
- s2n(TLSEXT_TYPE_server_name,ret);
- s2n(size_str+5,ret);
-
- /* length of servername list */
- s2n(size_str+3,ret);
-
- /* hostname type, length and hostname */
- *(ret++) = (unsigned char) TLSEXT_NAMETYPE_host_name;
- s2n(size_str,ret);
- memcpy(ret, s->tlsext_hostname, size_str);
- ret+=size_str;
- }
-
- /* Add RI if renegotiating */
- if (s->renegotiate)
- {
- int el;
-
- if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
- {
- SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- if((limit - p - 4 - el) < 0) return NULL;
-
- s2n(TLSEXT_TYPE_renegotiate,ret);
- s2n(el,ret);
-
- if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el))
- {
- SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- ret += el;
- }
-
-#ifndef OPENSSL_NO_SRP
- /* Add SRP username if there is one */
- if (s->srp_ctx.login != NULL)
- { /* Add TLS extension SRP username to the Client Hello message */
-
- int login_len = strlen(s->srp_ctx.login);
- if (login_len > 255 || login_len == 0)
- {
- SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- /* check for enough space.
- 4 for the srp type type and entension length
- 1 for the srp user identity
- + srp user identity length
- */
- if ((limit - ret - 5 - login_len) < 0) return NULL;
-
- /* fill in the extension */
- s2n(TLSEXT_TYPE_srp,ret);
- s2n(login_len+1,ret);
- (*ret++) = (unsigned char) login_len;
- memcpy(ret, s->srp_ctx.login, login_len);
- ret+=login_len;
- }
-#endif
-
-#ifndef OPENSSL_NO_EC
- if (s->tlsext_ecpointformatlist != NULL &&
- s->version != DTLS1_VERSION)
- {
- /* Add TLS extension ECPointFormats to the ClientHello message */
- long lenmax;
-
- if ((lenmax = limit - ret - 5) < 0) return NULL;
- if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
- if (s->tlsext_ecpointformatlist_length > 255)
- {
- SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- s2n(TLSEXT_TYPE_ec_point_formats,ret);
- s2n(s->tlsext_ecpointformatlist_length + 1,ret);
- *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
- memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
- ret+=s->tlsext_ecpointformatlist_length;
- }
- if (s->tlsext_ellipticcurvelist != NULL &&
- s->version != DTLS1_VERSION)
- {
- /* Add TLS extension EllipticCurves to the ClientHello message */
- long lenmax;
-
- if ((lenmax = limit - ret - 6) < 0) return NULL;
- if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
- if (s->tlsext_ellipticcurvelist_length > 65532)
- {
- SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- s2n(TLSEXT_TYPE_elliptic_curves,ret);
- s2n(s->tlsext_ellipticcurvelist_length + 2, ret);
-
- /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
- * elliptic_curve_list, but the examples use two bytes.
- * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
- * resolves this to two bytes.
- */
- s2n(s->tlsext_ellipticcurvelist_length, ret);
- memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
- ret+=s->tlsext_ellipticcurvelist_length;
- }
-#endif /* OPENSSL_NO_EC */
-
- if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
- {
- int ticklen;
- if (!s->new_session && s->session && s->session->tlsext_tick)
- ticklen = s->session->tlsext_ticklen;
- else if (s->session && s->tlsext_session_ticket &&
- s->tlsext_session_ticket->data)
- {
- ticklen = s->tlsext_session_ticket->length;
- s->session->tlsext_tick = OPENSSL_malloc(ticklen);
- if (!s->session->tlsext_tick)
- return NULL;
- memcpy(s->session->tlsext_tick,
- s->tlsext_session_ticket->data,
- ticklen);
- s->session->tlsext_ticklen = ticklen;
- }
- else
- ticklen = 0;
- if (ticklen == 0 && s->tlsext_session_ticket &&
- s->tlsext_session_ticket->data == NULL)
- goto skip_ext;
- /* Check for enough room 2 for extension type, 2 for len
- * rest for ticket
- */
- if ((long)(limit - ret - 4 - ticklen) < 0) return NULL;
- s2n(TLSEXT_TYPE_session_ticket,ret);
- s2n(ticklen,ret);
- if (ticklen)
- {
- memcpy(ret, s->session->tlsext_tick, ticklen);
- ret += ticklen;
- }
- }
- skip_ext:
-
- if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
- {
- if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6)
- return NULL;
- s2n(TLSEXT_TYPE_signature_algorithms,ret);
- s2n(sizeof(tls12_sigalgs) + 2, ret);
- s2n(sizeof(tls12_sigalgs), ret);
- memcpy(ret, tls12_sigalgs, sizeof(tls12_sigalgs));
- ret += sizeof(tls12_sigalgs);
- }
-
-#ifdef TLSEXT_TYPE_opaque_prf_input
- if (s->s3->client_opaque_prf_input != NULL &&
- s->version != DTLS1_VERSION)
- {
- size_t col = s->s3->client_opaque_prf_input_len;
-
- if ((long)(limit - ret - 6 - col < 0))
- return NULL;
- if (col > 0xFFFD) /* can't happen */
- return NULL;
-
- s2n(TLSEXT_TYPE_opaque_prf_input, ret);
- s2n(col + 2, ret);
- s2n(col, ret);
- memcpy(ret, s->s3->client_opaque_prf_input, col);
- ret += col;
- }
-#endif
-
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
- s->version != DTLS1_VERSION)
- {
- int i;
- long extlen, idlen, itmp;
- OCSP_RESPID *id;
-
- idlen = 0;
- for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
- {
- id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
- itmp = i2d_OCSP_RESPID(id, NULL);
- if (itmp <= 0)
- return NULL;
- idlen += itmp + 2;
- }
-
- if (s->tlsext_ocsp_exts)
- {
- extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
- if (extlen < 0)
- return NULL;
- }
- else
- extlen = 0;
-
- if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL;
- s2n(TLSEXT_TYPE_status_request, ret);
- if (extlen + idlen > 0xFFF0)
- return NULL;
- s2n(extlen + idlen + 5, ret);
- *(ret++) = TLSEXT_STATUSTYPE_ocsp;
- s2n(idlen, ret);
- for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
- {
- /* save position of id len */
- unsigned char *q = ret;
- id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
- /* skip over id len */
- ret += 2;
- itmp = i2d_OCSP_RESPID(id, &ret);
- /* write id len */
- s2n(itmp, q);
- }
- s2n(extlen, ret);
- if (extlen > 0)
- i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
- }
-
-#ifndef OPENSSL_NO_HEARTBEATS
- /* Add Heartbeat extension */
- s2n(TLSEXT_TYPE_heartbeat,ret);
- s2n(1,ret);
- /* Set mode:
- * 1: peer may send requests
- * 2: peer not allowed to send requests
- */
- if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
- *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
- else
- *(ret++) = SSL_TLSEXT_HB_ENABLED;
-#endif
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
- {
- /* The client advertises an emtpy extension to indicate its
- * support for Next Protocol Negotiation */
- if (limit - ret - 4 < 0)
- return NULL;
- s2n(TLSEXT_TYPE_next_proto_neg,ret);
- s2n(0,ret);
- }
-#endif
-
-#ifndef OPENSSL_NO_SRTP
- if(SSL_get_srtp_profiles(s))
- {
- int el;
-
- ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
-
- if((limit - p - 4 - el) < 0) return NULL;
-
- s2n(TLSEXT_TYPE_use_srtp,ret);
- s2n(el,ret);
-
- if(ssl_add_clienthello_use_srtp_ext(s, ret, &el, el))
- {
- SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
- ret += el;
- }
-#endif
-
-#ifdef TLSEXT_TYPE_padding
- /* Add padding to workaround bugs in F5 terminators.
- * See https://tools.ietf.org/html/draft-agl-tls-padding-03
- *
- * NB: because this code works out the length of all existing
- * extensions it MUST always appear last.
- */
- {
- int hlen = ret - (unsigned char *)s->init_buf->data;
- /* The code in s23_clnt.c to build ClientHello messages includes the
- * 5-byte record header in the buffer, while the code in s3_clnt.c does
- * not. */
- if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
- hlen -= 5;
- if (hlen > 0xff && hlen < 0x200)
- {
- hlen = 0x200 - hlen;
- if (hlen >= 4)
- hlen -= 4;
- else
- hlen = 0;
-
- s2n(TLSEXT_TYPE_padding, ret);
- s2n(hlen, ret);
- memset(ret, 0, hlen);
- ret += hlen;
- }
- }
-#endif
-
- if ((extdatalen = ret-p-2)== 0)
- return p;
-
- s2n(extdatalen,p);
- return ret;
- }
-
-unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
- {
- int extdatalen=0;
- unsigned char *ret = p;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- int next_proto_neg_seen;
-#endif
-
- /* don't add extensions for SSLv3, unless doing secure renegotiation */
- if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
- return p;
-
- ret+=2;
- if (ret>=limit) return NULL; /* this really never occurs, but ... */
-
- if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
- {
- if ((long)(limit - ret - 4) < 0) return NULL;
-
- s2n(TLSEXT_TYPE_server_name,ret);
- s2n(0,ret);
- }
-
- if(s->s3->send_connection_binding)
- {
- int el;
-
- if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0))
- {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- if((limit - p - 4 - el) < 0) return NULL;
-
- s2n(TLSEXT_TYPE_renegotiate,ret);
- s2n(el,ret);
-
- if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el))
- {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- ret += el;
- }
-
-#ifndef OPENSSL_NO_EC
- if (s->tlsext_ecpointformatlist != NULL &&
- s->version != DTLS1_VERSION)
- {
- /* Add TLS extension ECPointFormats to the ServerHello message */
- long lenmax;
-
- if ((lenmax = limit - ret - 5) < 0) return NULL;
- if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
- if (s->tlsext_ecpointformatlist_length > 255)
- {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- s2n(TLSEXT_TYPE_ec_point_formats,ret);
- s2n(s->tlsext_ecpointformatlist_length + 1,ret);
- *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
- memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
- ret+=s->tlsext_ecpointformatlist_length;
-
- }
- /* Currently the server should not respond with a SupportedCurves extension */
-#endif /* OPENSSL_NO_EC */
-
- if (s->tlsext_ticket_expected
- && !(SSL_get_options(s) & SSL_OP_NO_TICKET))
- {
- if ((long)(limit - ret - 4) < 0) return NULL;
- s2n(TLSEXT_TYPE_session_ticket,ret);
- s2n(0,ret);
- }
-
- if (s->tlsext_status_expected)
- {
- if ((long)(limit - ret - 4) < 0) return NULL;
- s2n(TLSEXT_TYPE_status_request,ret);
- s2n(0,ret);
- }
-
-#ifdef TLSEXT_TYPE_opaque_prf_input
- if (s->s3->server_opaque_prf_input != NULL &&
- s->version != DTLS1_VERSION)
- {
- size_t sol = s->s3->server_opaque_prf_input_len;
-
- if ((long)(limit - ret - 6 - sol) < 0)
- return NULL;
- if (sol > 0xFFFD) /* can't happen */
- return NULL;
-
- s2n(TLSEXT_TYPE_opaque_prf_input, ret);
- s2n(sol + 2, ret);
- s2n(sol, ret);
- memcpy(ret, s->s3->server_opaque_prf_input, sol);
- ret += sol;
- }
-#endif
-
-#ifndef OPENSSL_NO_SRTP
- if(s->srtp_profile)
- {
- int el;
-
- ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
-
- if((limit - p - 4 - el) < 0) return NULL;
-
- s2n(TLSEXT_TYPE_use_srtp,ret);
- s2n(el,ret);
-
- if(ssl_add_serverhello_use_srtp_ext(s, ret, &el, el))
- {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
- ret+=el;
- }
-#endif
-
- if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81)
- && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG))
- { const unsigned char cryptopro_ext[36] = {
- 0xfd, 0xe8, /*65000*/
- 0x00, 0x20, /*32 bytes length*/
- 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
- 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
- 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
- 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17};
- if (limit-ret<36) return NULL;
- memcpy(ret,cryptopro_ext,36);
- ret+=36;
-
- }
-
-#ifndef OPENSSL_NO_HEARTBEATS
- /* Add Heartbeat extension if we've received one */
- if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED)
- {
- s2n(TLSEXT_TYPE_heartbeat,ret);
- s2n(1,ret);
- /* Set mode:
- * 1: peer may send requests
- * 2: peer not allowed to send requests
- */
- if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
- *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
- else
- *(ret++) = SSL_TLSEXT_HB_ENABLED;
-
- }
-#endif
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- next_proto_neg_seen = s->s3->next_proto_neg_seen;
- s->s3->next_proto_neg_seen = 0;
- if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb)
- {
- const unsigned char *npa;
- unsigned int npalen;
- int r;
-
- r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg);
- if (r == SSL_TLSEXT_ERR_OK)
- {
- if ((long)(limit - ret - 4 - npalen) < 0) return NULL;
- s2n(TLSEXT_TYPE_next_proto_neg,ret);
- s2n(npalen,ret);
- memcpy(ret, npa, npalen);
- ret += npalen;
- s->s3->next_proto_neg_seen = 1;
- }
- }
-#endif
-
- if ((extdatalen = ret-p-2)== 0)
- return p;
-
- s2n(extdatalen,p);
- return ret;
- }
-
-#ifndef OPENSSL_NO_EC
-/* ssl_check_for_safari attempts to fingerprint Safari using OS X
- * SecureTransport using the TLS extension block in |d|, of length |n|.
- * Safari, since 10.6, sends exactly these extensions, in this order:
- * SNI,
- * elliptic_curves
- * ec_point_formats
- *
- * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
- * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
- * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
- * 10.8..10.8.3 (which don't work).
- */
-static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsigned char *d, int n) {
- unsigned short type, size;
- static const unsigned char kSafariExtensionsBlock[] = {
- 0x00, 0x0a, /* elliptic_curves extension */
- 0x00, 0x08, /* 8 bytes */
- 0x00, 0x06, /* 6 bytes of curve ids */
- 0x00, 0x17, /* P-256 */
- 0x00, 0x18, /* P-384 */
- 0x00, 0x19, /* P-521 */
-
- 0x00, 0x0b, /* ec_point_formats */
- 0x00, 0x02, /* 2 bytes */
- 0x01, /* 1 point format */
- 0x00, /* uncompressed */
- };
-
- /* The following is only present in TLS 1.2 */
- static const unsigned char kSafariTLS12ExtensionsBlock[] = {
- 0x00, 0x0d, /* signature_algorithms */
- 0x00, 0x0c, /* 12 bytes */
- 0x00, 0x0a, /* 10 bytes */
- 0x05, 0x01, /* SHA-384/RSA */
- 0x04, 0x01, /* SHA-256/RSA */
- 0x02, 0x01, /* SHA-1/RSA */
- 0x04, 0x03, /* SHA-256/ECDSA */
- 0x02, 0x03, /* SHA-1/ECDSA */
- };
-
- if (data >= (d+n-2))
- return;
- data += 2;
-
- if (data > (d+n-4))
- return;
- n2s(data,type);
- n2s(data,size);
-
- if (type != TLSEXT_TYPE_server_name)
- return;
-
- if (data+size > d+n)
- return;
- data += size;
-
- if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
- {
- const size_t len1 = sizeof(kSafariExtensionsBlock);
- const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
-
- if (data + len1 + len2 != d+n)
- return;
- if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
- return;
- if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
- return;
- }
- else
- {
- const size_t len = sizeof(kSafariExtensionsBlock);
-
- if (data + len != d+n)
- return;
- if (memcmp(data, kSafariExtensionsBlock, len) != 0)
- return;
- }
-
- s->s3->is_probably_safari = 1;
-}
-#endif /* !OPENSSL_NO_EC */
-
-int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
- {
- unsigned short type;
- unsigned short size;
- unsigned short len;
- unsigned char *data = *p;
- int renegotiate_seen = 0;
- int sigalg_seen = 0;
-
- s->servername_done = 0;
- s->tlsext_status_type = -1;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- s->s3->next_proto_neg_seen = 0;
-#endif
-
-#ifndef OPENSSL_NO_HEARTBEATS
- s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
- SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
-#endif
-
-#ifndef OPENSSL_NO_EC
- if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
- ssl_check_for_safari(s, data, d, n);
-#endif /* !OPENSSL_NO_EC */
-
- if (data >= (d+n-2))
- goto ri_check;
- n2s(data,len);
-
- if (data > (d+n-len))
- goto ri_check;
-
- while (data <= (d+n-4))
- {
- n2s(data,type);
- n2s(data,size);
-
- if (data+size > (d+n))
- goto ri_check;
-#if 0
- fprintf(stderr,"Received extension type %d size %d\n",type,size);
-#endif
- if (s->tlsext_debug_cb)
- s->tlsext_debug_cb(s, 0, type, data, size,
- s->tlsext_debug_arg);
-/* The servername extension is treated as follows:
-
- - Only the hostname type is supported with a maximum length of 255.
- - The servername is rejected if too long or if it contains zeros,
- in which case an fatal alert is generated.
- - The servername field is maintained together with the session cache.
- - When a session is resumed, the servername call back invoked in order
- to allow the application to position itself to the right context.
- - The servername is acknowledged if it is new for a session or when
- it is identical to a previously used for the same session.
- Applications can control the behaviour. They can at any time
- set a 'desirable' servername for a new SSL object. This can be the
- case for example with HTTPS when a Host: header field is received and
- a renegotiation is requested. In this case, a possible servername
- presented in the new client hello is only acknowledged if it matches
- the value of the Host: field.
- - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
- if they provide for changing an explicit servername context for the session,
- i.e. when the session has been established with a servername extension.
- - On session reconnect, the servername extension may be absent.
-
-*/
-
- if (type == TLSEXT_TYPE_server_name)
- {
- unsigned char *sdata;
- int servname_type;
- int dsize;
-
- if (size < 2)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- n2s(data,dsize);
- size -= 2;
- if (dsize > size )
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- sdata = data;
- while (dsize > 3)
- {
- servname_type = *(sdata++);
- n2s(sdata,len);
- dsize -= 3;
-
- if (len > dsize)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (s->servername_done == 0)
- switch (servname_type)
- {
- case TLSEXT_NAMETYPE_host_name:
- if (!s->hit)
- {
- if(s->session->tlsext_hostname)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (len > TLSEXT_MAXLEN_host_name)
- {
- *al = TLS1_AD_UNRECOGNIZED_NAME;
- return 0;
- }
- if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- memcpy(s->session->tlsext_hostname, sdata, len);
- s->session->tlsext_hostname[len]='\0';
- if (strlen(s->session->tlsext_hostname) != len) {
- OPENSSL_free(s->session->tlsext_hostname);
- s->session->tlsext_hostname = NULL;
- *al = TLS1_AD_UNRECOGNIZED_NAME;
- return 0;
- }
- s->servername_done = 1;
-
- }
- else
- s->servername_done = s->session->tlsext_hostname
- && strlen(s->session->tlsext_hostname) == len
- && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
-
- break;
-
- default:
- break;
- }
-
- dsize -= len;
- }
- if (dsize != 0)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- }
-#ifndef OPENSSL_NO_SRP
- else if (type == TLSEXT_TYPE_srp)
- {
- if (size <= 0 || ((len = data[0])) != (size -1))
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (s->srp_ctx.login != NULL)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if ((s->srp_ctx.login = OPENSSL_malloc(len+1)) == NULL)
- return -1;
- memcpy(s->srp_ctx.login, &data[1], len);
- s->srp_ctx.login[len]='\0';
-
- if (strlen(s->srp_ctx.login) != len)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- }
-#endif
-
-#ifndef OPENSSL_NO_EC
- else if (type == TLSEXT_TYPE_ec_point_formats &&
- s->version != DTLS1_VERSION)
- {
- unsigned char *sdata = data;
- int ecpointformatlist_length = *(sdata++);
-
- if (ecpointformatlist_length != size - 1)
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
- if (!s->hit)
- {
- if(s->session->tlsext_ecpointformatlist)
- {
- OPENSSL_free(s->session->tlsext_ecpointformatlist);
- s->session->tlsext_ecpointformatlist = NULL;
- }
- s->session->tlsext_ecpointformatlist_length = 0;
- if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
- memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
- }
-#if 0
- fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
- sdata = s->session->tlsext_ecpointformatlist;
- for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
- fprintf(stderr,"%i ",*(sdata++));
- fprintf(stderr,"\n");
-#endif
- }
- else if (type == TLSEXT_TYPE_elliptic_curves &&
- s->version != DTLS1_VERSION)
- {
- unsigned char *sdata = data;
- int ellipticcurvelist_length = (*(sdata++) << 8);
- ellipticcurvelist_length += (*(sdata++));
-
- if (ellipticcurvelist_length != size - 2 ||
- ellipticcurvelist_length < 1)
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
- if (!s->hit)
- {
- if(s->session->tlsext_ellipticcurvelist)
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
- s->session->tlsext_ellipticcurvelist_length = 0;
- if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
- memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
- }
-#if 0
- fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length);
- sdata = s->session->tlsext_ellipticcurvelist;
- for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
- fprintf(stderr,"%i ",*(sdata++));
- fprintf(stderr,"\n");
-#endif
- }
-#endif /* OPENSSL_NO_EC */
-#ifdef TLSEXT_TYPE_opaque_prf_input
- else if (type == TLSEXT_TYPE_opaque_prf_input &&
- s->version != DTLS1_VERSION)
- {
- unsigned char *sdata = data;
-
- if (size < 2)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- n2s(sdata, s->s3->client_opaque_prf_input_len);
- if (s->s3->client_opaque_prf_input_len != size - 2)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
- OPENSSL_free(s->s3->client_opaque_prf_input);
- if (s->s3->client_opaque_prf_input_len == 0)
- s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
- else
- s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len);
- if (s->s3->client_opaque_prf_input == NULL)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- }
-#endif
- else if (type == TLSEXT_TYPE_session_ticket)
- {
- if (s->tls_session_ticket_ext_cb &&
- !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- }
- else if (type == TLSEXT_TYPE_renegotiate)
- {
- if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
- return 0;
- renegotiate_seen = 1;
- }
- else if (type == TLSEXT_TYPE_signature_algorithms)
- {
- int dsize;
- if (sigalg_seen || size < 2)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- sigalg_seen = 1;
- n2s(data,dsize);
- size -= 2;
- if (dsize != size || dsize & 1)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (!tls1_process_sigalgs(s, data, dsize))
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- }
- else if (type == TLSEXT_TYPE_status_request &&
- s->version != DTLS1_VERSION)
- {
-
- if (size < 5)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- s->tlsext_status_type = *data++;
- size--;
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
- {
- const unsigned char *sdata;
- int dsize;
- /* Read in responder_id_list */
- n2s(data,dsize);
- size -= 2;
- if (dsize > size )
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- while (dsize > 0)
- {
- OCSP_RESPID *id;
- int idsize;
- if (dsize < 4)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- n2s(data, idsize);
- dsize -= 2 + idsize;
- size -= 2 + idsize;
- if (dsize < 0)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- sdata = data;
- data += idsize;
- id = d2i_OCSP_RESPID(NULL,
- &sdata, idsize);
- if (!id)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (data != sdata)
- {
- OCSP_RESPID_free(id);
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (!s->tlsext_ocsp_ids
- && !(s->tlsext_ocsp_ids =
- sk_OCSP_RESPID_new_null()))
- {
- OCSP_RESPID_free(id);
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- if (!sk_OCSP_RESPID_push(
- s->tlsext_ocsp_ids, id))
- {
- OCSP_RESPID_free(id);
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- }
-
- /* Read in request_extensions */
- if (size < 2)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- n2s(data,dsize);
- size -= 2;
- if (dsize != size)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- sdata = data;
- if (dsize > 0)
- {
- if (s->tlsext_ocsp_exts)
- {
- sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
- X509_EXTENSION_free);
- }
-
- s->tlsext_ocsp_exts =
- d2i_X509_EXTENSIONS(NULL,
- &sdata, dsize);
- if (!s->tlsext_ocsp_exts
- || (data + dsize != sdata))
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- }
- }
- /* We don't know what to do with any other type
- * so ignore it.
- */
- else
- s->tlsext_status_type = -1;
- }
-#ifndef OPENSSL_NO_HEARTBEATS
- else if (type == TLSEXT_TYPE_heartbeat)
- {
- switch(data[0])
- {
- case 0x01: /* Client allows us to send HB requests */
- s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
- break;
- case 0x02: /* Client doesn't accept HB requests */
- s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
- s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
- break;
- default: *al = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
- }
-#endif
-#ifndef OPENSSL_NO_NEXTPROTONEG
- else if (type == TLSEXT_TYPE_next_proto_neg &&
- s->s3->tmp.finish_md_len == 0)
- {
- /* We shouldn't accept this extension on a
- * renegotiation.
- *
- * s->new_session will be set on renegotiation, but we
- * probably shouldn't rely that it couldn't be set on
- * the initial renegotation too in certain cases (when
- * there's some other reason to disallow resuming an
- * earlier session -- the current code won't be doing
- * anything like that, but this might change).
-
- * A valid sign that there's been a previous handshake
- * in this connection is if s->s3->tmp.finish_md_len >
- * 0. (We are talking about a check that will happen
- * in the Hello protocol round, well before a new
- * Finished message could have been computed.) */
- s->s3->next_proto_neg_seen = 1;
- }
-#endif
-
- /* session ticket processed earlier */
-#ifndef OPENSSL_NO_SRTP
- else if (type == TLSEXT_TYPE_use_srtp)
- {
- if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
- al))
- return 0;
- }
-#endif
-
- data+=size;
- }
-
- *p = data;
-
- ri_check:
-
- /* Need RI if renegotiating */
-
- if (!renegotiate_seen && s->renegotiate &&
- !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
- {
- *al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,
- SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
- return 0;
- }
-
- return 1;
- }
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
- * elements of zero length are allowed and the set of elements must exactly fill
- * the length of the block. */
-static char ssl_next_proto_validate(unsigned char *d, unsigned len)
- {
- unsigned int off = 0;
-
- while (off < len)
- {
- if (d[off] == 0)
- return 0;
- off += d[off];
- off++;
- }
-
- return off == len;
- }
-#endif
-
-int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
- {
- unsigned short length;
- unsigned short type;
- unsigned short size;
- unsigned char *data = *p;
- int tlsext_servername = 0;
- int renegotiate_seen = 0;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- s->s3->next_proto_neg_seen = 0;
-#endif
-
-#ifndef OPENSSL_NO_HEARTBEATS
- s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
- SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
-#endif
-
- if (data >= (d+n-2))
- goto ri_check;
-
- n2s(data,length);
- if (data+length != d+n)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- while(data <= (d+n-4))
- {
- n2s(data,type);
- n2s(data,size);
-
- if (data+size > (d+n))
- goto ri_check;
-
- if (s->tlsext_debug_cb)
- s->tlsext_debug_cb(s, 1, type, data, size,
- s->tlsext_debug_arg);
-
- if (type == TLSEXT_TYPE_server_name)
- {
- if (s->tlsext_hostname == NULL || size > 0)
- {
- *al = TLS1_AD_UNRECOGNIZED_NAME;
- return 0;
- }
- tlsext_servername = 1;
- }
-
-#ifndef OPENSSL_NO_EC
- else if (type == TLSEXT_TYPE_ec_point_formats &&
- s->version != DTLS1_VERSION)
- {
- unsigned char *sdata = data;
- int ecpointformatlist_length = *(sdata++);
-
- if (ecpointformatlist_length != size - 1 ||
- ecpointformatlist_length < 1)
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
- s->session->tlsext_ecpointformatlist_length = 0;
- if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
- if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
- memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
-#if 0
- fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
- sdata = s->session->tlsext_ecpointformatlist;
- for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
- fprintf(stderr,"%i ",*(sdata++));
- fprintf(stderr,"\n");
-#endif
- }
-#endif /* OPENSSL_NO_EC */
-
- else if (type == TLSEXT_TYPE_session_ticket)
- {
- if (s->tls_session_ticket_ext_cb &&
- !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
- || (size > 0))
- {
- *al = TLS1_AD_UNSUPPORTED_EXTENSION;
- return 0;
- }
- s->tlsext_ticket_expected = 1;
- }
-#ifdef TLSEXT_TYPE_opaque_prf_input
- else if (type == TLSEXT_TYPE_opaque_prf_input &&
- s->version != DTLS1_VERSION)
- {
- unsigned char *sdata = data;
-
- if (size < 2)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- n2s(sdata, s->s3->server_opaque_prf_input_len);
- if (s->s3->server_opaque_prf_input_len != size - 2)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
- OPENSSL_free(s->s3->server_opaque_prf_input);
- if (s->s3->server_opaque_prf_input_len == 0)
- s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
- else
- s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len);
-
- if (s->s3->server_opaque_prf_input == NULL)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- }
-#endif
- else if (type == TLSEXT_TYPE_status_request &&
- s->version != DTLS1_VERSION)
- {
- /* MUST be empty and only sent if we've requested
- * a status request message.
- */
- if ((s->tlsext_status_type == -1) || (size > 0))
- {
- *al = TLS1_AD_UNSUPPORTED_EXTENSION;
- return 0;
- }
- /* Set flag to expect CertificateStatus message */
- s->tlsext_status_expected = 1;
- }
-#ifndef OPENSSL_NO_NEXTPROTONEG
- else if (type == TLSEXT_TYPE_next_proto_neg &&
- s->s3->tmp.finish_md_len == 0)
- {
- unsigned char *selected;
- unsigned char selected_len;
-
- /* We must have requested it. */
- if (s->ctx->next_proto_select_cb == NULL)
- {
- *al = TLS1_AD_UNSUPPORTED_EXTENSION;
- return 0;
- }
- /* The data must be valid */
- if (!ssl_next_proto_validate(data, size))
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
- if (s->ctx->next_proto_select_cb(s, &selected, &selected_len, data, size, s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- s->next_proto_negotiated = OPENSSL_malloc(selected_len);
- if (!s->next_proto_negotiated)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- memcpy(s->next_proto_negotiated, selected, selected_len);
- s->next_proto_negotiated_len = selected_len;
- s->s3->next_proto_neg_seen = 1;
- }
-#endif
- else if (type == TLSEXT_TYPE_renegotiate)
- {
- if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
- return 0;
- renegotiate_seen = 1;
- }
-#ifndef OPENSSL_NO_HEARTBEATS
- else if (type == TLSEXT_TYPE_heartbeat)
- {
- switch(data[0])
- {
- case 0x01: /* Server allows us to send HB requests */
- s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
- break;
- case 0x02: /* Server doesn't accept HB requests */
- s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
- s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
- break;
- default: *al = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
- }
-#endif
-#ifndef OPENSSL_NO_SRTP
- else if (type == TLSEXT_TYPE_use_srtp)
- {
- if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
- al))
- return 0;
- }
-#endif
-
- data+=size;
- }
-
- if (data != d+n)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- if (!s->hit && tlsext_servername == 1)
- {
- if (s->tlsext_hostname)
- {
- if (s->session->tlsext_hostname == NULL)
- {
- s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
- if (!s->session->tlsext_hostname)
- {
- *al = SSL_AD_UNRECOGNIZED_NAME;
- return 0;
- }
- }
- else
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- }
- }
-
- *p = data;
-
- ri_check:
-
- /* Determine if we need to see RI. Strictly speaking if we want to
- * avoid an attack we should *always* see RI even on initial server
- * hello because the client doesn't see any renegotiation during an
- * attack. However this would mean we could not connect to any server
- * which doesn't support RI so for the immediate future tolerate RI
- * absence on initial connect only.
- */
- if (!renegotiate_seen
- && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
- && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
- {
- *al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,
- SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
- return 0;
- }
-
- return 1;
- }
-
-
-int ssl_prepare_clienthello_tlsext(SSL *s)
- {
-#ifndef OPENSSL_NO_EC
- /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats
- * and elliptic curves we support.
- */
- int using_ecc = 0;
- int i;
- unsigned char *j;
- unsigned long alg_k, alg_a;
- STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
-
- for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
- {
- SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
-
- alg_k = c->algorithm_mkey;
- alg_a = c->algorithm_auth;
- if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe) || (alg_a & SSL_aECDSA)))
- {
- using_ecc = 1;
- break;
- }
- }
- using_ecc = using_ecc && (s->version >= TLS1_VERSION);
- if (using_ecc)
- {
- if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
- if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
- {
- SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
- return -1;
- }
- s->tlsext_ecpointformatlist_length = 3;
- s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
- s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
- s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
-
- /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */
- if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist);
- s->tlsext_ellipticcurvelist_length = sizeof(pref_list)/sizeof(pref_list[0]) * 2;
- if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL)
- {
- s->tlsext_ellipticcurvelist_length = 0;
- SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
- return -1;
- }
- for (i = 0, j = s->tlsext_ellipticcurvelist; (unsigned int)i <
- sizeof(pref_list)/sizeof(pref_list[0]); i++)
- {
- int id = tls1_ec_nid2curve_id(pref_list[i]);
- s2n(id,j);
- }
- }
-#endif /* OPENSSL_NO_EC */
-
-#ifdef TLSEXT_TYPE_opaque_prf_input
- {
- int r = 1;
-
- if (s->ctx->tlsext_opaque_prf_input_callback != 0)
- {
- r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
- if (!r)
- return -1;
- }
-
- if (s->tlsext_opaque_prf_input != NULL)
- {
- if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
- OPENSSL_free(s->s3->client_opaque_prf_input);
-
- if (s->tlsext_opaque_prf_input_len == 0)
- s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
- else
- s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
- if (s->s3->client_opaque_prf_input == NULL)
- {
- SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
- return -1;
- }
- s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
- }
-
- if (r == 2)
- /* at callback's request, insist on receiving an appropriate server opaque PRF input */
- s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
- }
-#endif
-
- return 1;
- }
-
-int ssl_prepare_serverhello_tlsext(SSL *s)
- {
-#ifndef OPENSSL_NO_EC
- /* If we are server and using an ECC cipher suite, send the point formats we support
- * if the client sent us an ECPointsFormat extension. Note that the server is not
- * supposed to send an EllipticCurves extension.
- */
-
- unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
- using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
-
- if (using_ecc)
- {
- if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
- if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
- {
- SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
- return -1;
- }
- s->tlsext_ecpointformatlist_length = 3;
- s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
- s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
- s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
- }
-#endif /* OPENSSL_NO_EC */
-
- return 1;
- }
-
-int ssl_check_clienthello_tlsext_early(SSL *s)
- {
- int ret=SSL_TLSEXT_ERR_NOACK;
- int al = SSL_AD_UNRECOGNIZED_NAME;
-
-#ifndef OPENSSL_NO_EC
- /* The handling of the ECPointFormats extension is done elsewhere, namely in
- * ssl3_choose_cipher in s3_lib.c.
- */
- /* The handling of the EllipticCurves extension is done elsewhere, namely in
- * ssl3_choose_cipher in s3_lib.c.
- */
-#endif
-
- if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
- ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
- else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
- ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
-
-#ifdef TLSEXT_TYPE_opaque_prf_input
- {
- /* This sort of belongs into ssl_prepare_serverhello_tlsext(),
- * but we might be sending an alert in response to the client hello,
- * so this has to happen here in
- * ssl_check_clienthello_tlsext_early(). */
-
- int r = 1;
-
- if (s->ctx->tlsext_opaque_prf_input_callback != 0)
- {
- r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
- if (!r)
- {
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_INTERNAL_ERROR;
- goto err;
- }
- }
-
- if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
- OPENSSL_free(s->s3->server_opaque_prf_input);
- s->s3->server_opaque_prf_input = NULL;
-
- if (s->tlsext_opaque_prf_input != NULL)
- {
- if (s->s3->client_opaque_prf_input != NULL &&
- s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len)
- {
- /* can only use this extension if we have a server opaque PRF input
- * of the same length as the client opaque PRF input! */
-
- if (s->tlsext_opaque_prf_input_len == 0)
- s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
- else
- s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
- if (s->s3->server_opaque_prf_input == NULL)
- {
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_INTERNAL_ERROR;
- goto err;
- }
- s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
- }
- }
-
- if (r == 2 && s->s3->server_opaque_prf_input == NULL)
- {
- /* The callback wants to enforce use of the extension,
- * but we can't do that with the client opaque PRF input;
- * abort the handshake.
- */
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_HANDSHAKE_FAILURE;
- }
- }
-
- err:
-#endif
- switch (ret)
- {
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- return -1;
-
- case SSL_TLSEXT_ERR_ALERT_WARNING:
- ssl3_send_alert(s,SSL3_AL_WARNING,al);
- return 1;
-
- case SSL_TLSEXT_ERR_NOACK:
- s->servername_done=0;
- default:
- return 1;
- }
- }
-
-int ssl_check_clienthello_tlsext_late(SSL *s)
- {
- int ret = SSL_TLSEXT_ERR_OK;
- int al;
-
- /* If status request then ask callback what to do.
- * Note: this must be called after servername callbacks in case
- * the certificate has changed, and must be called after the cipher
- * has been chosen because this may influence which certificate is sent
- */
- if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
- {
- int r;
- CERT_PKEY *certpkey;
- certpkey = ssl_get_server_send_pkey(s);
- /* If no certificate can't return certificate status */
- if (certpkey == NULL)
- {
- s->tlsext_status_expected = 0;
- return 1;
- }
- /* Set current certificate to one we will use so
- * SSL_get_certificate et al can pick it up.
- */
- s->cert->key = certpkey;
- r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- switch (r)
- {
- /* We don't want to send a status request response */
- case SSL_TLSEXT_ERR_NOACK:
- s->tlsext_status_expected = 0;
- break;
- /* status request response should be sent */
- case SSL_TLSEXT_ERR_OK:
- if (s->tlsext_ocsp_resp)
- s->tlsext_status_expected = 1;
- else
- s->tlsext_status_expected = 0;
- break;
- /* something bad happened */
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_INTERNAL_ERROR;
- goto err;
- }
- }
- else
- s->tlsext_status_expected = 0;
-
- err:
- switch (ret)
- {
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- return -1;
-
- case SSL_TLSEXT_ERR_ALERT_WARNING:
- ssl3_send_alert(s,SSL3_AL_WARNING,al);
- return 1;
-
- default:
- return 1;
- }
- }
-
-int ssl_check_serverhello_tlsext(SSL *s)
- {
- int ret=SSL_TLSEXT_ERR_NOACK;
- int al = SSL_AD_UNRECOGNIZED_NAME;
-
-#ifndef OPENSSL_NO_EC
- /* If we are client and using an elliptic curve cryptography cipher
- * suite, then if server returns an EC point formats lists extension
- * it must contain uncompressed.
- */
- unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) &&
- (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) &&
- ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA)))
- {
- /* we are using an ECC cipher */
- size_t i;
- unsigned char *list;
- int found_uncompressed = 0;
- list = s->session->tlsext_ecpointformatlist;
- for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
- {
- if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed)
- {
- found_uncompressed = 1;
- break;
- }
- }
- if (!found_uncompressed)
- {
- SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
- return -1;
- }
- }
- ret = SSL_TLSEXT_ERR_OK;
-#endif /* OPENSSL_NO_EC */
-
- if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
- ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
- else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
- ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
-
-#ifdef TLSEXT_TYPE_opaque_prf_input
- if (s->s3->server_opaque_prf_input_len > 0)
- {
- /* This case may indicate that we, as a client, want to insist on using opaque PRF inputs.
- * So first verify that we really have a value from the server too. */
-
- if (s->s3->server_opaque_prf_input == NULL)
- {
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_HANDSHAKE_FAILURE;
- }
-
- /* Anytime the server *has* sent an opaque PRF input, we need to check
- * that we have a client opaque PRF input of the same size. */
- if (s->s3->client_opaque_prf_input == NULL ||
- s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len)
- {
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_ILLEGAL_PARAMETER;
- }
- }
-#endif
-
- /* If we've requested certificate status and we wont get one
- * tell the callback
- */
- if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
- && s->ctx && s->ctx->tlsext_status_cb)
- {
- int r;
- /* Set resp to NULL, resplen to -1 so callback knows
- * there is no response.
- */
- if (s->tlsext_ocsp_resp)
- {
- OPENSSL_free(s->tlsext_ocsp_resp);
- s->tlsext_ocsp_resp = NULL;
- }
- s->tlsext_ocsp_resplen = -1;
- r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- if (r == 0)
- {
- al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- }
- if (r < 0)
- {
- al = SSL_AD_INTERNAL_ERROR;
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- }
- }
-
- switch (ret)
- {
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- return -1;
-
- case SSL_TLSEXT_ERR_ALERT_WARNING:
- ssl3_send_alert(s,SSL3_AL_WARNING,al);
- return 1;
-
- case SSL_TLSEXT_ERR_NOACK:
- s->servername_done=0;
- default:
- return 1;
- }
- }
-
-/* Since the server cache lookup is done early on in the processing of the
- * ClientHello, and other operations depend on the result, we need to handle
- * any TLS session ticket extension at the same time.
- *
- * session_id: points at the session ID in the ClientHello. This code will
- * read past the end of this in order to parse out the session ticket
- * extension, if any.
- * len: the length of the session ID.
- * limit: a pointer to the first byte after the ClientHello.
- * ret: (output) on return, if a ticket was decrypted, then this is set to
- * point to the resulting session.
- *
- * If s->tls_session_secret_cb is set then we are expecting a pre-shared key
- * ciphersuite, in which case we have no use for session tickets and one will
- * never be decrypted, nor will s->tlsext_ticket_expected be set to 1.
- *
- * Returns:
- * -1: fatal error, either from parsing or decrypting the ticket.
- * 0: no ticket was found (or was ignored, based on settings).
- * 1: a zero length extension was found, indicating that the client supports
- * session tickets but doesn't currently have one to offer.
- * 2: either s->tls_session_secret_cb was set, or a ticket was offered but
- * couldn't be decrypted because of a non-fatal error.
- * 3: a ticket was successfully decrypted and *ret was set.
- *
- * Side effects:
- * Sets s->tlsext_ticket_expected to 1 if the server will have to issue
- * a new session ticket to the client because the client indicated support
- * (and s->tls_session_secret_cb is NULL) but the client either doesn't have
- * a session ticket or we couldn't use the one it gave us, or if
- * s->ctx->tlsext_ticket_key_cb asked to renew the client's ticket.
- * Otherwise, s->tlsext_ticket_expected is set to 0.
- */
-int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
- const unsigned char *limit, SSL_SESSION **ret)
- {
- /* Point after session ID in client hello */
- const unsigned char *p = session_id + len;
- unsigned short i;
-
- *ret = NULL;
- s->tlsext_ticket_expected = 0;
-
- /* If tickets disabled behave as if no ticket present
- * to permit stateful resumption.
- */
- if (SSL_get_options(s) & SSL_OP_NO_TICKET)
- return 0;
- if ((s->version <= SSL3_VERSION) || !limit)
- return 0;
- if (p >= limit)
- return -1;
- /* Skip past DTLS cookie */
- if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
- {
- i = *(p++);
- p+= i;
- if (p >= limit)
- return -1;
- }
- /* Skip past cipher list */
- n2s(p, i);
- p+= i;
- if (p >= limit)
- return -1;
- /* Skip past compression algorithm list */
- i = *(p++);
- p += i;
- if (p > limit)
- return -1;
- /* Now at start of extensions */
- if ((p + 2) >= limit)
- return 0;
- n2s(p, i);
- while ((p + 4) <= limit)
- {
- unsigned short type, size;
- n2s(p, type);
- n2s(p, size);
- if (p + size > limit)
- return 0;
- if (type == TLSEXT_TYPE_session_ticket)
- {
- int r;
- if (size == 0)
- {
- /* The client will accept a ticket but doesn't
- * currently have one. */
- s->tlsext_ticket_expected = 1;
- return 1;
- }
- if (s->tls_session_secret_cb)
- {
- /* Indicate that the ticket couldn't be
- * decrypted rather than generating the session
- * from ticket now, trigger abbreviated
- * handshake based on external mechanism to
- * calculate the master secret later. */
- return 2;
- }
- r = tls_decrypt_ticket(s, p, size, session_id, len, ret);
- switch (r)
- {
- case 2: /* ticket couldn't be decrypted */
- s->tlsext_ticket_expected = 1;
- return 2;
- case 3: /* ticket was decrypted */
- return r;
- case 4: /* ticket decrypted but need to renew */
- s->tlsext_ticket_expected = 1;
- return 3;
- default: /* fatal error */
- return -1;
- }
- }
- p += size;
- }
- return 0;
- }
-
-/* tls_decrypt_ticket attempts to decrypt a session ticket.
- *
- * etick: points to the body of the session ticket extension.
- * eticklen: the length of the session tickets extenion.
- * sess_id: points at the session ID.
- * sesslen: the length of the session ID.
- * psess: (output) on return, if a ticket was decrypted, then this is set to
- * point to the resulting session.
- *
- * Returns:
- * -1: fatal error, either from parsing or decrypting the ticket.
- * 2: the ticket couldn't be decrypted.
- * 3: a ticket was successfully decrypted and *psess was set.
- * 4: same as 3, but the ticket needs to be renewed.
- */
-static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
- const unsigned char *sess_id, int sesslen,
- SSL_SESSION **psess)
- {
- SSL_SESSION *sess;
- unsigned char *sdec;
- const unsigned char *p;
- int slen, mlen, renew_ticket = 0;
- unsigned char tick_hmac[EVP_MAX_MD_SIZE];
- HMAC_CTX hctx;
- EVP_CIPHER_CTX ctx;
- SSL_CTX *tctx = s->initial_ctx;
- /* Need at least keyname + iv + some encrypted data */
- if (eticklen < 48)
- return 2;
- /* Initialize session ticket encryption and HMAC contexts */
- HMAC_CTX_init(&hctx);
- EVP_CIPHER_CTX_init(&ctx);
- if (tctx->tlsext_ticket_key_cb)
- {
- unsigned char *nctick = (unsigned char *)etick;
- int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
- &ctx, &hctx, 0);
- if (rv < 0)
- return -1;
- if (rv == 0)
- return 2;
- if (rv == 2)
- renew_ticket = 1;
- }
- else
- {
- /* Check key name matches */
- if (memcmp(etick, tctx->tlsext_tick_key_name, 16))
- return 2;
- HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
- tlsext_tick_md(), NULL);
- EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
- tctx->tlsext_tick_aes_key, etick + 16);
- }
- /* Attempt to process session ticket, first conduct sanity and
- * integrity checks on ticket.
- */
- mlen = HMAC_size(&hctx);
- if (mlen < 0)
- {
- EVP_CIPHER_CTX_cleanup(&ctx);
- return -1;
- }
- eticklen -= mlen;
- /* Check HMAC of encrypted ticket */
- HMAC_Update(&hctx, etick, eticklen);
- HMAC_Final(&hctx, tick_hmac, NULL);
- HMAC_CTX_cleanup(&hctx);
- if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
- return 2;
- /* Attempt to decrypt session data */
- /* Move p after IV to start of encrypted ticket, update length */
- p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
- eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
- sdec = OPENSSL_malloc(eticklen);
- if (!sdec)
- {
- EVP_CIPHER_CTX_cleanup(&ctx);
- return -1;
- }
- EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
- if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
- return 2;
- slen += mlen;
- EVP_CIPHER_CTX_cleanup(&ctx);
- p = sdec;
-
- sess = d2i_SSL_SESSION(NULL, &p, slen);
- OPENSSL_free(sdec);
- if (sess)
- {
- /* The session ID, if non-empty, is used by some clients to
- * detect that the ticket has been accepted. So we copy it to
- * the session structure. If it is empty set length to zero
- * as required by standard.
- */
- if (sesslen)
- memcpy(sess->session_id, sess_id, sesslen);
- sess->session_id_length = sesslen;
- *psess = sess;
- if (renew_ticket)
- return 4;
- else
- return 3;
- }
- ERR_clear_error();
- /* For session parse failure, indicate that we need to send a new
- * ticket. */
- return 2;
- }
-
-/* Tables to translate from NIDs to TLS v1.2 ids */
-
-typedef struct
- {
- int nid;
- int id;
- } tls12_lookup;
-
-static tls12_lookup tls12_md[] = {
-#ifndef OPENSSL_NO_MD5
- {NID_md5, TLSEXT_hash_md5},
-#endif
-#ifndef OPENSSL_NO_SHA
- {NID_sha1, TLSEXT_hash_sha1},
-#endif
-#ifndef OPENSSL_NO_SHA256
- {NID_sha224, TLSEXT_hash_sha224},
- {NID_sha256, TLSEXT_hash_sha256},
-#endif
-#ifndef OPENSSL_NO_SHA512
- {NID_sha384, TLSEXT_hash_sha384},
- {NID_sha512, TLSEXT_hash_sha512}
-#endif
-};
-
-static tls12_lookup tls12_sig[] = {
-#ifndef OPENSSL_NO_RSA
- {EVP_PKEY_RSA, TLSEXT_signature_rsa},
-#endif
-#ifndef OPENSSL_NO_DSA
- {EVP_PKEY_DSA, TLSEXT_signature_dsa},
-#endif
-#ifndef OPENSSL_NO_ECDSA
- {EVP_PKEY_EC, TLSEXT_signature_ecdsa}
-#endif
-};
-
-static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
- {
- size_t i;
- for (i = 0; i < tlen; i++)
- {
- if (table[i].nid == nid)
- return table[i].id;
- }
- return -1;
- }
-#if 0
-static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
- {
- size_t i;
- for (i = 0; i < tlen; i++)
- {
- if (table[i].id == id)
- return table[i].nid;
- }
- return -1;
- }
-#endif
-
-int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md)
- {
- int sig_id, md_id;
- if (!md)
- return 0;
- md_id = tls12_find_id(EVP_MD_type(md), tls12_md,
- sizeof(tls12_md)/sizeof(tls12_lookup));
- if (md_id == -1)
- return 0;
- sig_id = tls12_get_sigid(pk);
- if (sig_id == -1)
- return 0;
- p[0] = (unsigned char)md_id;
- p[1] = (unsigned char)sig_id;
- return 1;
- }
-
-int tls12_get_sigid(const EVP_PKEY *pk)
- {
- return tls12_find_id(pk->type, tls12_sig,
- sizeof(tls12_sig)/sizeof(tls12_lookup));
- }
-
-const EVP_MD *tls12_get_hash(unsigned char hash_alg)
- {
- switch(hash_alg)
- {
-#ifndef OPENSSL_NO_SHA
- case TLSEXT_hash_sha1:
- return EVP_sha1();
-#endif
-#ifndef OPENSSL_NO_SHA256
- case TLSEXT_hash_sha224:
- return EVP_sha224();
-
- case TLSEXT_hash_sha256:
- return EVP_sha256();
-#endif
-#ifndef OPENSSL_NO_SHA512
- case TLSEXT_hash_sha384:
- return EVP_sha384();
-
- case TLSEXT_hash_sha512:
- return EVP_sha512();
-#endif
- default:
- return NULL;
-
- }
- }
-
-/* Set preferred digest for each key type */
-
-int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
- {
- int i, idx;
- const EVP_MD *md;
- CERT *c = s->cert;
- /* Extension ignored for TLS versions below 1.2 */
- if (TLS1_get_version(s) < TLS1_2_VERSION)
- return 1;
- /* Should never happen */
- if (!c)
- return 0;
-
- c->pkeys[SSL_PKEY_DSA_SIGN].digest = NULL;
- c->pkeys[SSL_PKEY_RSA_SIGN].digest = NULL;
- c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL;
- c->pkeys[SSL_PKEY_ECC].digest = NULL;
-
- for (i = 0; i < dsize; i += 2)
- {
- unsigned char hash_alg = data[i], sig_alg = data[i+1];
-
- switch(sig_alg)
- {
-#ifndef OPENSSL_NO_RSA
- case TLSEXT_signature_rsa:
- idx = SSL_PKEY_RSA_SIGN;
- break;
-#endif
-#ifndef OPENSSL_NO_DSA
- case TLSEXT_signature_dsa:
- idx = SSL_PKEY_DSA_SIGN;
- break;
-#endif
-#ifndef OPENSSL_NO_ECDSA
- case TLSEXT_signature_ecdsa:
- idx = SSL_PKEY_ECC;
- break;
-#endif
- default:
- continue;
- }
-
- if (c->pkeys[idx].digest == NULL)
- {
- md = tls12_get_hash(hash_alg);
- if (md)
- {
- c->pkeys[idx].digest = md;
- if (idx == SSL_PKEY_RSA_SIGN)
- c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
- }
- }
-
- }
-
-
- /* Set any remaining keys to default values. NOTE: if alg is not
- * supported it stays as NULL.
- */
-#ifndef OPENSSL_NO_DSA
- if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
- c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
-#endif
-#ifndef OPENSSL_NO_RSA
- if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
- {
- c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
- c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
- }
-#endif
-#ifndef OPENSSL_NO_ECDSA
- if (!c->pkeys[SSL_PKEY_ECC].digest)
- c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
-#endif
- return 1;
- }
-
-#endif
-
-#ifndef OPENSSL_NO_HEARTBEATS
-int
-tls1_process_heartbeat(SSL *s)
- {
- unsigned char *p = &s->s3->rrec.data[0], *pl;
- unsigned short hbtype;
- unsigned int payload;
- unsigned int padding = 16; /* Use minimum padding */
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
- &s->s3->rrec.data[0], s->s3->rrec.length,
- s, s->msg_callback_arg);
-
- /* Read type and payload length first */
- if (1 + 2 + 16 > s->s3->rrec.length)
- return 0; /* silently discard */
- hbtype = *p++;
- n2s(p, payload);
- if (1 + 2 + payload + 16 > s->s3->rrec.length)
- return 0; /* silently discard per RFC 6520 sec. 4 */
- pl = p;
-
- if (hbtype == TLS1_HB_REQUEST)
- {
- unsigned char *buffer, *bp;
- int r;
-
- /* Allocate memory for the response, size is 1 bytes
- * message type, plus 2 bytes payload length, plus
- * payload, plus padding
- */
- buffer = OPENSSL_malloc(1 + 2 + payload + padding);
- bp = buffer;
-
- /* Enter response type, length and copy payload */
- *bp++ = TLS1_HB_RESPONSE;
- s2n(payload, bp);
- memcpy(bp, pl, payload);
- bp += payload;
- /* Random padding */
- RAND_pseudo_bytes(bp, padding);
-
- r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
-
- if (r >= 0 && s->msg_callback)
- s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
- buffer, 3 + payload + padding,
- s, s->msg_callback_arg);
-
- OPENSSL_free(buffer);
-
- if (r < 0)
- return r;
- }
- else if (hbtype == TLS1_HB_RESPONSE)
- {
- unsigned int seq;
-
- /* We only send sequence numbers (2 bytes unsigned int),
- * and 16 random bytes, so we just try to read the
- * sequence number */
- n2s(pl, seq);
-
- if (payload == 18 && seq == s->tlsext_hb_seq)
- {
- s->tlsext_hb_seq++;
- s->tlsext_hb_pending = 0;
- }
- }
-
- return 0;
- }
-
-int
-tls1_heartbeat(SSL *s)
- {
- unsigned char *buf, *p;
- int ret;
- unsigned int payload = 18; /* Sequence number + random bytes */
- unsigned int padding = 16; /* Use minimum padding */
-
- /* Only send if peer supports and accepts HB requests... */
- if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
- s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS)
- {
- SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
- return -1;
- }
-
- /* ...and there is none in flight yet... */
- if (s->tlsext_hb_pending)
- {
- SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING);
- return -1;
- }
-
- /* ...and no handshake in progress. */
- if (SSL_in_init(s) || s->in_handshake)
- {
- SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- /* Check if padding is too long, payload and padding
- * must not exceed 2^14 - 3 = 16381 bytes in total.
- */
- OPENSSL_assert(payload + padding <= 16381);
-
- /* Create HeartBeat message, we just use a sequence number
- * as payload to distuingish different messages and add
- * some random stuff.
- * - Message Type, 1 byte
- * - Payload Length, 2 bytes (unsigned int)
- * - Payload, the sequence number (2 bytes uint)
- * - Payload, random bytes (16 bytes uint)
- * - Padding
- */
- buf = OPENSSL_malloc(1 + 2 + payload + padding);
- p = buf;
- /* Message Type */
- *p++ = TLS1_HB_REQUEST;
- /* Payload length (18 bytes here) */
- s2n(payload, p);
- /* Sequence number */
- s2n(s->tlsext_hb_seq, p);
- /* 16 random bytes */
- RAND_pseudo_bytes(p, 16);
- p += 16;
- /* Random padding */
- RAND_pseudo_bytes(p, padding);
-
- ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
- if (ret >= 0)
- {
- if (s->msg_callback)
- s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
- buf, 3 + payload + padding,
- s, s->msg_callback_arg);
-
- s->tlsext_hb_pending = 1;
- }
-
- OPENSSL_free(buf);
-
- return ret;
- }
-#endif
diff --git a/drivers/builtin_openssl/ssl/tls1.h b/drivers/builtin_openssl/ssl/tls1.h
deleted file mode 100644
index c992091e30..0000000000
--- a/drivers/builtin_openssl/ssl/tls1.h
+++ /dev/null
@@ -1,741 +0,0 @@
-/* ssl/tls1.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL 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:
- *
- * 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.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the OpenSSL open source
- * license provided above.
- *
- * ECC cipher suite support in OpenSSL originally written by
- * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
- *
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#ifndef HEADER_TLS1_H
-#define HEADER_TLS1_H
-
-#include <openssl/buffer.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0
-
-#define TLS1_2_VERSION 0x0303
-#define TLS1_2_VERSION_MAJOR 0x03
-#define TLS1_2_VERSION_MINOR 0x03
-
-#define TLS1_1_VERSION 0x0302
-#define TLS1_1_VERSION_MAJOR 0x03
-#define TLS1_1_VERSION_MINOR 0x02
-
-#define TLS1_VERSION 0x0301
-#define TLS1_VERSION_MAJOR 0x03
-#define TLS1_VERSION_MINOR 0x01
-
-#define TLS1_get_version(s) \
- ((s->version >> 8) == TLS1_VERSION_MAJOR ? s->version : 0)
-
-#define TLS1_get_client_version(s) \
- ((s->client_version >> 8) == TLS1_VERSION_MAJOR ? s->client_version : 0)
-
-#define TLS1_AD_DECRYPTION_FAILED 21
-#define TLS1_AD_RECORD_OVERFLOW 22
-#define TLS1_AD_UNKNOWN_CA 48 /* fatal */
-#define TLS1_AD_ACCESS_DENIED 49 /* fatal */
-#define TLS1_AD_DECODE_ERROR 50 /* fatal */
-#define TLS1_AD_DECRYPT_ERROR 51
-#define TLS1_AD_EXPORT_RESTRICTION 60 /* fatal */
-#define TLS1_AD_PROTOCOL_VERSION 70 /* fatal */
-#define TLS1_AD_INSUFFICIENT_SECURITY 71 /* fatal */
-#define TLS1_AD_INTERNAL_ERROR 80 /* fatal */
-#define TLS1_AD_USER_CANCELLED 90
-#define TLS1_AD_NO_RENEGOTIATION 100
-/* codes 110-114 are from RFC3546 */
-#define TLS1_AD_UNSUPPORTED_EXTENSION 110
-#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111
-#define TLS1_AD_UNRECOGNIZED_NAME 112
-#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113
-#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
-#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */
-
-/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */
-#define TLSEXT_TYPE_server_name 0
-#define TLSEXT_TYPE_max_fragment_length 1
-#define TLSEXT_TYPE_client_certificate_url 2
-#define TLSEXT_TYPE_trusted_ca_keys 3
-#define TLSEXT_TYPE_truncated_hmac 4
-#define TLSEXT_TYPE_status_request 5
-/* ExtensionType values from RFC4681 */
-#define TLSEXT_TYPE_user_mapping 6
-
-/* ExtensionType values from RFC5878 */
-#define TLSEXT_TYPE_client_authz 7
-#define TLSEXT_TYPE_server_authz 8
-
-/* ExtensionType values from RFC6091 */
-#define TLSEXT_TYPE_cert_type 9
-
-/* ExtensionType values from RFC4492 */
-#define TLSEXT_TYPE_elliptic_curves 10
-#define TLSEXT_TYPE_ec_point_formats 11
-
-/* ExtensionType value from RFC5054 */
-#define TLSEXT_TYPE_srp 12
-
-/* ExtensionType values from RFC5246 */
-#define TLSEXT_TYPE_signature_algorithms 13
-
-/* ExtensionType value from RFC5764 */
-#define TLSEXT_TYPE_use_srtp 14
-
-/* ExtensionType value from RFC5620 */
-#define TLSEXT_TYPE_heartbeat 15
-
-/* ExtensionType value for TLS padding extension.
- * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
- * http://tools.ietf.org/html/draft-agl-tls-padding-03
- */
-#define TLSEXT_TYPE_padding 21
-
-/* ExtensionType value from RFC4507 */
-#define TLSEXT_TYPE_session_ticket 35
-
-/* ExtensionType value from draft-rescorla-tls-opaque-prf-input-00.txt */
-#if 0 /* will have to be provided externally for now ,
- * i.e. build with -DTLSEXT_TYPE_opaque_prf_input=38183
- * using whatever extension number you'd like to try */
-# define TLSEXT_TYPE_opaque_prf_input ?? */
-#endif
-
-/* Temporary extension type */
-#define TLSEXT_TYPE_renegotiate 0xff01
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-/* This is not an IANA defined extension number */
-#define TLSEXT_TYPE_next_proto_neg 13172
-#endif
-
-/* NameType value from RFC 3546 */
-#define TLSEXT_NAMETYPE_host_name 0
-/* status request value from RFC 3546 */
-#define TLSEXT_STATUSTYPE_ocsp 1
-
-/* ECPointFormat values from draft-ietf-tls-ecc-12 */
-#define TLSEXT_ECPOINTFORMAT_first 0
-#define TLSEXT_ECPOINTFORMAT_uncompressed 0
-#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime 1
-#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2
-#define TLSEXT_ECPOINTFORMAT_last 2
-
-/* Signature and hash algorithms from RFC 5246 */
-
-#define TLSEXT_signature_anonymous 0
-#define TLSEXT_signature_rsa 1
-#define TLSEXT_signature_dsa 2
-#define TLSEXT_signature_ecdsa 3
-
-#define TLSEXT_hash_none 0
-#define TLSEXT_hash_md5 1
-#define TLSEXT_hash_sha1 2
-#define TLSEXT_hash_sha224 3
-#define TLSEXT_hash_sha256 4
-#define TLSEXT_hash_sha384 5
-#define TLSEXT_hash_sha512 6
-
-#ifndef OPENSSL_NO_TLSEXT
-
-#define TLSEXT_MAXLEN_host_name 255
-
-const char *SSL_get_servername(const SSL *s, const int type);
-int SSL_get_servername_type(const SSL *s);
-/* SSL_export_keying_material exports a value derived from the master secret,
- * as specified in RFC 5705. It writes |olen| bytes to |out| given a label and
- * optional context. (Since a zero length context is allowed, the |use_context|
- * flag controls whether a context is included.)
- *
- * It returns 1 on success and zero otherwise.
- */
-int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
- const char *label, size_t llen, const unsigned char *p, size_t plen,
- int use_context);
-
-#define SSL_set_tlsext_host_name(s,name) \
-SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
-
-#define SSL_set_tlsext_debug_callback(ssl, cb) \
-SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb)
-
-#define SSL_set_tlsext_debug_arg(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg)
-
-#define SSL_set_tlsext_status_type(ssl, type) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL)
-
-#define SSL_get_tlsext_status_exts(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
-
-#define SSL_set_tlsext_status_exts(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
-
-#define SSL_get_tlsext_status_ids(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
-
-#define SSL_set_tlsext_status_ids(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
-
-#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg)
-
-#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg)
-
-#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
-SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
-
-#define SSL_TLSEXT_ERR_OK 0
-#define SSL_TLSEXT_ERR_ALERT_WARNING 1
-#define SSL_TLSEXT_ERR_ALERT_FATAL 2
-#define SSL_TLSEXT_ERR_NOACK 3
-
-#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
-SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
-
-#define SSL_CTX_get_tlsext_ticket_keys(ctx, keys, keylen) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLSEXT_TICKET_KEYS,(keylen),(keys))
-#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLSEXT_TICKET_KEYS,(keylen),(keys))
-
-#define SSL_CTX_set_tlsext_status_cb(ssl, cb) \
-SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb)
-
-#define SSL_CTX_set_tlsext_status_arg(ssl, arg) \
-SSL_CTX_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg)
-
-#define SSL_set_tlsext_opaque_prf_input(s, src, len) \
-SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT, len, src)
-#define SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) \
-SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB, (void (*)(void))cb)
-#define SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg) \
-SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg)
-
-#define SSL_CTX_set_tlsext_ticket_key_cb(ssl, cb) \
-SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
-
-#ifndef OPENSSL_NO_HEARTBEATS
-#define SSL_TLSEXT_HB_ENABLED 0x01
-#define SSL_TLSEXT_HB_DONT_SEND_REQUESTS 0x02
-#define SSL_TLSEXT_HB_DONT_RECV_REQUESTS 0x04
-
-#define SSL_get_tlsext_heartbeat_pending(ssl) \
- SSL_ctrl((ssl),SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING,0,NULL)
-#define SSL_set_tlsext_heartbeat_no_requests(ssl, arg) \
- SSL_ctrl((ssl),SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS,arg,NULL)
-#endif
-#endif
-
-/* PSK ciphersuites from 4279 */
-#define TLS1_CK_PSK_WITH_RC4_128_SHA 0x0300008A
-#define TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA 0x0300008B
-#define TLS1_CK_PSK_WITH_AES_128_CBC_SHA 0x0300008C
-#define TLS1_CK_PSK_WITH_AES_256_CBC_SHA 0x0300008D
-
-/* Additional TLS ciphersuites from expired Internet Draft
- * draft-ietf-tls-56-bit-ciphersuites-01.txt
- * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see
- * s3_lib.c). We actually treat them like SSL 3.0 ciphers, which we probably
- * shouldn't. Note that the first two are actually not in the IDs. */
-#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5 0x03000060 /* not in ID */
-#define TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 0x03000061 /* not in ID */
-#define TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x03000062
-#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x03000063
-#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA 0x03000064
-#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x03000065
-#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA 0x03000066
-
-/* AES ciphersuites from RFC3268 */
-
-#define TLS1_CK_RSA_WITH_AES_128_SHA 0x0300002F
-#define TLS1_CK_DH_DSS_WITH_AES_128_SHA 0x03000030
-#define TLS1_CK_DH_RSA_WITH_AES_128_SHA 0x03000031
-#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA 0x03000032
-#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA 0x03000033
-#define TLS1_CK_ADH_WITH_AES_128_SHA 0x03000034
-
-#define TLS1_CK_RSA_WITH_AES_256_SHA 0x03000035
-#define TLS1_CK_DH_DSS_WITH_AES_256_SHA 0x03000036
-#define TLS1_CK_DH_RSA_WITH_AES_256_SHA 0x03000037
-#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA 0x03000038
-#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA 0x03000039
-#define TLS1_CK_ADH_WITH_AES_256_SHA 0x0300003A
-
-/* TLS v1.2 ciphersuites */
-#define TLS1_CK_RSA_WITH_NULL_SHA256 0x0300003B
-#define TLS1_CK_RSA_WITH_AES_128_SHA256 0x0300003C
-#define TLS1_CK_RSA_WITH_AES_256_SHA256 0x0300003D
-#define TLS1_CK_DH_DSS_WITH_AES_128_SHA256 0x0300003E
-#define TLS1_CK_DH_RSA_WITH_AES_128_SHA256 0x0300003F
-#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA256 0x03000040
-
-/* Camellia ciphersuites from RFC4132 */
-#define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000041
-#define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000042
-#define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000043
-#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000044
-#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000045
-#define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA 0x03000046
-
-/* TLS v1.2 ciphersuites */
-#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA256 0x03000067
-#define TLS1_CK_DH_DSS_WITH_AES_256_SHA256 0x03000068
-#define TLS1_CK_DH_RSA_WITH_AES_256_SHA256 0x03000069
-#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA256 0x0300006A
-#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA256 0x0300006B
-#define TLS1_CK_ADH_WITH_AES_128_SHA256 0x0300006C
-#define TLS1_CK_ADH_WITH_AES_256_SHA256 0x0300006D
-
-/* Camellia ciphersuites from RFC4132 */
-#define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000084
-#define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000085
-#define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000086
-#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000087
-#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000088
-#define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA 0x03000089
-
-/* SEED ciphersuites from RFC4162 */
-#define TLS1_CK_RSA_WITH_SEED_SHA 0x03000096
-#define TLS1_CK_DH_DSS_WITH_SEED_SHA 0x03000097
-#define TLS1_CK_DH_RSA_WITH_SEED_SHA 0x03000098
-#define TLS1_CK_DHE_DSS_WITH_SEED_SHA 0x03000099
-#define TLS1_CK_DHE_RSA_WITH_SEED_SHA 0x0300009A
-#define TLS1_CK_ADH_WITH_SEED_SHA 0x0300009B
-
-/* TLS v1.2 GCM ciphersuites from RFC5288 */
-#define TLS1_CK_RSA_WITH_AES_128_GCM_SHA256 0x0300009C
-#define TLS1_CK_RSA_WITH_AES_256_GCM_SHA384 0x0300009D
-#define TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 0x0300009E
-#define TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384 0x0300009F
-#define TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256 0x030000A0
-#define TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384 0x030000A1
-#define TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256 0x030000A2
-#define TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384 0x030000A3
-#define TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256 0x030000A4
-#define TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384 0x030000A5
-#define TLS1_CK_ADH_WITH_AES_128_GCM_SHA256 0x030000A6
-#define TLS1_CK_ADH_WITH_AES_256_GCM_SHA384 0x030000A7
-
-/* ECC ciphersuites from draft-ietf-tls-ecc-12.txt with changes soon to be in draft 13 */
-#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x0300C001
-#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x0300C002
-#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C003
-#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x0300C004
-#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x0300C005
-
-#define TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA 0x0300C006
-#define TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA 0x0300C007
-#define TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C008
-#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x0300C009
-#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0x0300C00A
-
-#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA 0x0300C00B
-#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA 0x0300C00C
-#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA 0x0300C00D
-#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA 0x0300C00E
-#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA 0x0300C00F
-
-#define TLS1_CK_ECDHE_RSA_WITH_NULL_SHA 0x0300C010
-#define TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA 0x0300C011
-#define TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA 0x0300C012
-#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0300C013
-#define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA 0x0300C014
-
-#define TLS1_CK_ECDH_anon_WITH_NULL_SHA 0x0300C015
-#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA 0x0300C016
-#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA 0x0300C017
-#define TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA 0x0300C018
-#define TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA 0x0300C019
-
-/* SRP ciphersuites from RFC 5054 */
-#define TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA 0x0300C01A
-#define TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA 0x0300C01B
-#define TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA 0x0300C01C
-#define TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA 0x0300C01D
-#define TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA 0x0300C01E
-#define TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA 0x0300C01F
-#define TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA 0x0300C020
-#define TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA 0x0300C021
-#define TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA 0x0300C022
-
-/* ECDH HMAC based ciphersuites from RFC5289 */
-
-#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256 0x0300C023
-#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384 0x0300C024
-#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256 0x0300C025
-#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384 0x0300C026
-#define TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256 0x0300C027
-#define TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384 0x0300C028
-#define TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256 0x0300C029
-#define TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384 0x0300C02A
-
-/* ECDH GCM based ciphersuites from RFC5289 */
-#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02B
-#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02C
-#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02D
-#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02E
-#define TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0x0300C02F
-#define TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0x0300C030
-#define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256 0x0300C031
-#define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384 0x0300C032
-
-/* XXX
- * Inconsistency alert:
- * The OpenSSL names of ciphers with ephemeral DH here include the string
- * "DHE", while elsewhere it has always been "EDH".
- * (The alias for the list of all such ciphers also is "EDH".)
- * The specifications speak of "EDH"; maybe we should allow both forms
- * for everything. */
-#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5 "EXP1024-RC4-MD5"
-#define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 "EXP1024-RC2-CBC-MD5"
-#define TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DES-CBC-SHA"
-#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DHE-DSS-DES-CBC-SHA"
-#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA "EXP1024-RC4-SHA"
-#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA "EXP1024-DHE-DSS-RC4-SHA"
-#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA "DHE-DSS-RC4-SHA"
-
-/* AES ciphersuites from RFC3268 */
-#define TLS1_TXT_RSA_WITH_AES_128_SHA "AES128-SHA"
-#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA "DH-DSS-AES128-SHA"
-#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA "DH-RSA-AES128-SHA"
-#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA "DHE-DSS-AES128-SHA"
-#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA "DHE-RSA-AES128-SHA"
-#define TLS1_TXT_ADH_WITH_AES_128_SHA "ADH-AES128-SHA"
-
-#define TLS1_TXT_RSA_WITH_AES_256_SHA "AES256-SHA"
-#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA "DH-DSS-AES256-SHA"
-#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA "DH-RSA-AES256-SHA"
-#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA "DHE-DSS-AES256-SHA"
-#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA"
-#define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA"
-
-/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */
-#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA"
-#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA"
-#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA"
-#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA "ECDH-ECDSA-AES128-SHA"
-#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA "ECDH-ECDSA-AES256-SHA"
-
-#define TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA "ECDHE-ECDSA-NULL-SHA"
-#define TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA "ECDHE-ECDSA-RC4-SHA"
-#define TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA "ECDHE-ECDSA-DES-CBC3-SHA"
-#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA "ECDHE-ECDSA-AES128-SHA"
-#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA "ECDHE-ECDSA-AES256-SHA"
-
-#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA "ECDH-RSA-NULL-SHA"
-#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA "ECDH-RSA-RC4-SHA"
-#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA "ECDH-RSA-DES-CBC3-SHA"
-#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA "ECDH-RSA-AES128-SHA"
-#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA "ECDH-RSA-AES256-SHA"
-
-#define TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA "ECDHE-RSA-NULL-SHA"
-#define TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA "ECDHE-RSA-RC4-SHA"
-#define TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA "ECDHE-RSA-DES-CBC3-SHA"
-#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA"
-#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA "ECDHE-RSA-AES256-SHA"
-
-#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA "AECDH-NULL-SHA"
-#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA "AECDH-RC4-SHA"
-#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA "AECDH-DES-CBC3-SHA"
-#define TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA "AECDH-AES128-SHA"
-#define TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA "AECDH-AES256-SHA"
-
-/* PSK ciphersuites from RFC 4279 */
-#define TLS1_TXT_PSK_WITH_RC4_128_SHA "PSK-RC4-SHA"
-#define TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA "PSK-3DES-EDE-CBC-SHA"
-#define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA "PSK-AES128-CBC-SHA"
-#define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA "PSK-AES256-CBC-SHA"
-
-/* SRP ciphersuite from RFC 5054 */
-#define TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA "SRP-3DES-EDE-CBC-SHA"
-#define TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA "SRP-RSA-3DES-EDE-CBC-SHA"
-#define TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA "SRP-DSS-3DES-EDE-CBC-SHA"
-#define TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA "SRP-AES-128-CBC-SHA"
-#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA "SRP-RSA-AES-128-CBC-SHA"
-#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA "SRP-DSS-AES-128-CBC-SHA"
-#define TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA "SRP-AES-256-CBC-SHA"
-#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA "SRP-RSA-AES-256-CBC-SHA"
-#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA "SRP-DSS-AES-256-CBC-SHA"
-
-/* Camellia ciphersuites from RFC4132 */
-#define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA "CAMELLIA128-SHA"
-#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA "DH-DSS-CAMELLIA128-SHA"
-#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA "DH-RSA-CAMELLIA128-SHA"
-#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA "DHE-DSS-CAMELLIA128-SHA"
-#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA "DHE-RSA-CAMELLIA128-SHA"
-#define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA "ADH-CAMELLIA128-SHA"
-
-#define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA "CAMELLIA256-SHA"
-#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA "DH-DSS-CAMELLIA256-SHA"
-#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA "DH-RSA-CAMELLIA256-SHA"
-#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA "DHE-DSS-CAMELLIA256-SHA"
-#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA "DHE-RSA-CAMELLIA256-SHA"
-#define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA "ADH-CAMELLIA256-SHA"
-
-/* SEED ciphersuites from RFC4162 */
-#define TLS1_TXT_RSA_WITH_SEED_SHA "SEED-SHA"
-#define TLS1_TXT_DH_DSS_WITH_SEED_SHA "DH-DSS-SEED-SHA"
-#define TLS1_TXT_DH_RSA_WITH_SEED_SHA "DH-RSA-SEED-SHA"
-#define TLS1_TXT_DHE_DSS_WITH_SEED_SHA "DHE-DSS-SEED-SHA"
-#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA"
-#define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA"
-
-/* TLS v1.2 ciphersuites */
-#define TLS1_TXT_RSA_WITH_NULL_SHA256 "NULL-SHA256"
-#define TLS1_TXT_RSA_WITH_AES_128_SHA256 "AES128-SHA256"
-#define TLS1_TXT_RSA_WITH_AES_256_SHA256 "AES256-SHA256"
-#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA256 "DH-DSS-AES128-SHA256"
-#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA256 "DH-RSA-AES128-SHA256"
-#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256 "DHE-DSS-AES128-SHA256"
-#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 "DHE-RSA-AES128-SHA256"
-#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA256 "DH-DSS-AES256-SHA256"
-#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA256 "DH-RSA-AES256-SHA256"
-#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256 "DHE-DSS-AES256-SHA256"
-#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 "DHE-RSA-AES256-SHA256"
-#define TLS1_TXT_ADH_WITH_AES_128_SHA256 "ADH-AES128-SHA256"
-#define TLS1_TXT_ADH_WITH_AES_256_SHA256 "ADH-AES256-SHA256"
-
-/* TLS v1.2 GCM ciphersuites from RFC5288 */
-#define TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256 "AES128-GCM-SHA256"
-#define TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 "AES256-GCM-SHA384"
-#define TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 "DHE-RSA-AES128-GCM-SHA256"
-#define TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 "DHE-RSA-AES256-GCM-SHA384"
-#define TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256 "DH-RSA-AES128-GCM-SHA256"
-#define TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384 "DH-RSA-AES256-GCM-SHA384"
-#define TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256 "DHE-DSS-AES128-GCM-SHA256"
-#define TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384 "DHE-DSS-AES256-GCM-SHA384"
-#define TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256 "DH-DSS-AES128-GCM-SHA256"
-#define TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384 "DH-DSS-AES256-GCM-SHA384"
-#define TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256 "ADH-AES128-GCM-SHA256"
-#define TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384 "ADH-AES256-GCM-SHA384"
-
-/* ECDH HMAC based ciphersuites from RFC5289 */
-
-#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256 "ECDHE-ECDSA-AES128-SHA256"
-#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384 "ECDHE-ECDSA-AES256-SHA384"
-#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256 "ECDH-ECDSA-AES128-SHA256"
-#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384 "ECDH-ECDSA-AES256-SHA384"
-#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 "ECDHE-RSA-AES128-SHA256"
-#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 "ECDHE-RSA-AES256-SHA384"
-#define TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256 "ECDH-RSA-AES128-SHA256"
-#define TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384 "ECDH-RSA-AES256-SHA384"
-
-/* ECDH GCM based ciphersuites from RFC5289 */
-#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 "ECDHE-ECDSA-AES128-GCM-SHA256"
-#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 "ECDHE-ECDSA-AES256-GCM-SHA384"
-#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 "ECDH-ECDSA-AES128-GCM-SHA256"
-#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 "ECDH-ECDSA-AES256-GCM-SHA384"
-#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 "ECDHE-RSA-AES128-GCM-SHA256"
-#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 "ECDHE-RSA-AES256-GCM-SHA384"
-#define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256 "ECDH-RSA-AES128-GCM-SHA256"
-#define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384 "ECDH-RSA-AES256-GCM-SHA384"
-
-#define TLS_CT_RSA_SIGN 1
-#define TLS_CT_DSS_SIGN 2
-#define TLS_CT_RSA_FIXED_DH 3
-#define TLS_CT_DSS_FIXED_DH 4
-#define TLS_CT_ECDSA_SIGN 64
-#define TLS_CT_RSA_FIXED_ECDH 65
-#define TLS_CT_ECDSA_FIXED_ECDH 66
-#define TLS_CT_GOST94_SIGN 21
-#define TLS_CT_GOST01_SIGN 22
-/* when correcting this number, correct also SSL3_CT_NUMBER in ssl3.h (see
- * comment there) */
-#define TLS_CT_NUMBER 9
-
-#define TLS1_FINISH_MAC_LENGTH 12
-
-#define TLS_MD_MAX_CONST_SIZE 20
-#define TLS_MD_CLIENT_FINISH_CONST "client finished"
-#define TLS_MD_CLIENT_FINISH_CONST_SIZE 15
-#define TLS_MD_SERVER_FINISH_CONST "server finished"
-#define TLS_MD_SERVER_FINISH_CONST_SIZE 15
-#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key"
-#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16
-#define TLS_MD_KEY_EXPANSION_CONST "key expansion"
-#define TLS_MD_KEY_EXPANSION_CONST_SIZE 13
-#define TLS_MD_CLIENT_WRITE_KEY_CONST "client write key"
-#define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE 16
-#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key"
-#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16
-#define TLS_MD_IV_BLOCK_CONST "IV block"
-#define TLS_MD_IV_BLOCK_CONST_SIZE 8
-#define TLS_MD_MASTER_SECRET_CONST "master secret"
-#define TLS_MD_MASTER_SECRET_CONST_SIZE 13
-
-#ifdef CHARSET_EBCDIC
-#undef TLS_MD_CLIENT_FINISH_CONST
-#define TLS_MD_CLIENT_FINISH_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x66\x69\x6e\x69\x73\x68\x65\x64" /*client finished*/
-#undef TLS_MD_SERVER_FINISH_CONST
-#define TLS_MD_SERVER_FINISH_CONST "\x73\x65\x72\x76\x65\x72\x20\x66\x69\x6e\x69\x73\x68\x65\x64" /*server finished*/
-#undef TLS_MD_SERVER_WRITE_KEY_CONST
-#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*server write key*/
-#undef TLS_MD_KEY_EXPANSION_CONST
-#define TLS_MD_KEY_EXPANSION_CONST "\x6b\x65\x79\x20\x65\x78\x70\x61\x6e\x73\x69\x6f\x6e" /*key expansion*/
-#undef TLS_MD_CLIENT_WRITE_KEY_CONST
-#define TLS_MD_CLIENT_WRITE_KEY_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*client write key*/
-#undef TLS_MD_SERVER_WRITE_KEY_CONST
-#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*server write key*/
-#undef TLS_MD_IV_BLOCK_CONST
-#define TLS_MD_IV_BLOCK_CONST "\x49\x56\x20\x62\x6c\x6f\x63\x6b" /*IV block*/
-#undef TLS_MD_MASTER_SECRET_CONST
-#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
-#endif
-
-/* TLS Session Ticket extension struct */
-struct tls_session_ticket_ext_st
- {
- unsigned short length;
- void *data;
- };
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/builtin_openssl2/SCsub b/drivers/builtin_openssl2/SCsub
new file mode 100644
index 0000000000..7f66b6397e
--- /dev/null
+++ b/drivers/builtin_openssl2/SCsub
@@ -0,0 +1,646 @@
+Import('env')
+
+openssl_sources = [
+"builtin_openssl2/nocpuid.c",
+"builtin_openssl2/ssl/t1_lib.c",
+"builtin_openssl2/ssl/s3_srvr.c",
+"builtin_openssl2/ssl/t1_enc.c",
+"builtin_openssl2/ssl/t1_meth.c",
+"builtin_openssl2/ssl/s23_clnt.c",
+"builtin_openssl2/ssl/ssl_asn1.c",
+"builtin_openssl2/ssl/tls_srp.c",
+"builtin_openssl2/ssl/kssl.c",
+"builtin_openssl2/ssl/d1_both.c",
+"builtin_openssl2/ssl/d1_enc.c",
+"builtin_openssl2/ssl/t1_clnt.c",
+"builtin_openssl2/ssl/bio_ssl.c",
+"builtin_openssl2/ssl/d1_srtp.c",
+"builtin_openssl2/ssl/t1_reneg.c",
+"builtin_openssl2/ssl/ssl_cert.c",
+"builtin_openssl2/ssl/s3_lib.c",
+"builtin_openssl2/ssl/d1_srvr.c",
+"builtin_openssl2/ssl/s23_meth.c",
+"builtin_openssl2/ssl/ssl_stat.c",
+"builtin_openssl2/ssl/ssl_err.c",
+"builtin_openssl2/ssl/ssl_algs.c",
+"builtin_openssl2/ssl/s3_cbc.c",
+"builtin_openssl2/ssl/d1_clnt.c",
+"builtin_openssl2/ssl/s3_pkt.c",
+"builtin_openssl2/ssl/d1_meth.c",
+"builtin_openssl2/ssl/s3_both.c",
+"builtin_openssl2/ssl/s2_enc.c",
+"builtin_openssl2/ssl/s3_meth.c",
+"builtin_openssl2/ssl/s3_enc.c",
+"builtin_openssl2/ssl/s23_pkt.c",
+"builtin_openssl2/ssl/s2_pkt.c",
+"builtin_openssl2/ssl/d1_pkt.c",
+"builtin_openssl2/ssl/ssl_rsa.c",
+"builtin_openssl2/ssl/s23_srvr.c",
+"builtin_openssl2/ssl/s2_meth.c",
+"builtin_openssl2/ssl/s3_clnt.c",
+"builtin_openssl2/ssl/s23_lib.c",
+"builtin_openssl2/ssl/t1_srvr.c",
+"builtin_openssl2/ssl/ssl_lib.c",
+"builtin_openssl2/ssl/ssl_txt.c",
+"builtin_openssl2/ssl/s2_srvr.c",
+"builtin_openssl2/ssl/ssl_sess.c",
+"builtin_openssl2/ssl/s2_clnt.c",
+"builtin_openssl2/ssl/d1_lib.c",
+"builtin_openssl2/ssl/s2_lib.c",
+"builtin_openssl2/ssl/ssl_err2.c",
+"builtin_openssl2/ssl/ssl_ciph.c",
+"builtin_openssl2/crypto/dsa/dsa_lib.c",
+"builtin_openssl2/crypto/dsa/dsa_pmeth.c",
+"builtin_openssl2/crypto/dsa/dsa_ossl.c",
+"builtin_openssl2/crypto/dsa/dsa_gen.c",
+"builtin_openssl2/crypto/dsa/dsa_asn1.c",
+"builtin_openssl2/crypto/dsa/dsa_prn.c",
+"builtin_openssl2/crypto/dsa/dsa_sign.c",
+"builtin_openssl2/crypto/dsa/dsa_key.c",
+"builtin_openssl2/crypto/dsa/dsa_vrf.c",
+"builtin_openssl2/crypto/dsa/dsa_err.c",
+"builtin_openssl2/crypto/dsa/dsa_ameth.c",
+"builtin_openssl2/crypto/dsa/dsa_depr.c",
+"builtin_openssl2/crypto/x509/x509_lu.c",
+"builtin_openssl2/crypto/x509/x509cset.c",
+"builtin_openssl2/crypto/x509/x509_set.c",
+"builtin_openssl2/crypto/x509/x509_d2.c",
+"builtin_openssl2/crypto/x509/x509_txt.c",
+"builtin_openssl2/crypto/x509/x509rset.c",
+"builtin_openssl2/crypto/x509/by_dir.c",
+"builtin_openssl2/crypto/x509/x509_vpm.c",
+"builtin_openssl2/crypto/x509/x509_vfy.c",
+"builtin_openssl2/crypto/x509/x509_trs.c",
+"builtin_openssl2/crypto/x509/by_file.c",
+"builtin_openssl2/crypto/x509/x509_obj.c",
+"builtin_openssl2/crypto/x509/x509spki.c",
+"builtin_openssl2/crypto/x509/x509_v3.c",
+"builtin_openssl2/crypto/x509/x509_req.c",
+"builtin_openssl2/crypto/x509/x509_att.c",
+"builtin_openssl2/crypto/x509/x_all.c",
+"builtin_openssl2/crypto/x509/x509_ext.c",
+"builtin_openssl2/crypto/x509/x509type.c",
+"builtin_openssl2/crypto/x509/x509_def.c",
+"builtin_openssl2/crypto/x509/x509_err.c",
+"builtin_openssl2/crypto/x509/x509name.c",
+"builtin_openssl2/crypto/x509/x509_r2x.c",
+"builtin_openssl2/crypto/x509/x509_cmp.c",
+"builtin_openssl2/crypto/asn1/x_pkey.c",
+"builtin_openssl2/crypto/asn1/a_gentm.c",
+"builtin_openssl2/crypto/asn1/x_sig.c",
+"builtin_openssl2/crypto/asn1/t_req.c",
+"builtin_openssl2/crypto/asn1/t_pkey.c",
+"builtin_openssl2/crypto/asn1/p8_pkey.c",
+"builtin_openssl2/crypto/asn1/a_i2d_fp.c",
+"builtin_openssl2/crypto/asn1/x_val.c",
+"builtin_openssl2/crypto/asn1/f_string.c",
+"builtin_openssl2/crypto/asn1/p5_pbe.c",
+"builtin_openssl2/crypto/asn1/bio_ndef.c",
+"builtin_openssl2/crypto/asn1/a_bool.c",
+"builtin_openssl2/crypto/asn1/asn1_gen.c",
+"builtin_openssl2/crypto/asn1/x_algor.c",
+"builtin_openssl2/crypto/asn1/bio_asn1.c",
+"builtin_openssl2/crypto/asn1/asn_mime.c",
+"builtin_openssl2/crypto/asn1/t_x509.c",
+"builtin_openssl2/crypto/asn1/a_strex.c",
+"builtin_openssl2/crypto/asn1/x_nx509.c",
+"builtin_openssl2/crypto/asn1/asn1_err.c",
+"builtin_openssl2/crypto/asn1/x_crl.c",
+"builtin_openssl2/crypto/asn1/a_print.c",
+"builtin_openssl2/crypto/asn1/a_type.c",
+"builtin_openssl2/crypto/asn1/tasn_new.c",
+"builtin_openssl2/crypto/asn1/n_pkey.c",
+"builtin_openssl2/crypto/asn1/x_bignum.c",
+"builtin_openssl2/crypto/asn1/asn_pack.c",
+"builtin_openssl2/crypto/asn1/evp_asn1.c",
+"builtin_openssl2/crypto/asn1/t_bitst.c",
+"builtin_openssl2/crypto/asn1/x_req.c",
+"builtin_openssl2/crypto/asn1/a_time.c",
+"builtin_openssl2/crypto/asn1/x_name.c",
+"builtin_openssl2/crypto/asn1/x_pubkey.c",
+"builtin_openssl2/crypto/asn1/tasn_typ.c",
+"builtin_openssl2/crypto/asn1/asn_moid.c",
+"builtin_openssl2/crypto/asn1/a_utctm.c",
+"builtin_openssl2/crypto/asn1/asn1_lib.c",
+"builtin_openssl2/crypto/asn1/x_x509a.c",
+"builtin_openssl2/crypto/asn1/a_set.c",
+"builtin_openssl2/crypto/asn1/t_crl.c",
+"builtin_openssl2/crypto/asn1/p5_pbev2.c",
+"builtin_openssl2/crypto/asn1/tasn_enc.c",
+"builtin_openssl2/crypto/asn1/a_mbstr.c",
+"builtin_openssl2/crypto/asn1/tasn_dec.c",
+"builtin_openssl2/crypto/asn1/x_x509.c",
+"builtin_openssl2/crypto/asn1/a_octet.c",
+"builtin_openssl2/crypto/asn1/x_long.c",
+"builtin_openssl2/crypto/asn1/a_bytes.c",
+"builtin_openssl2/crypto/asn1/t_x509a.c",
+"builtin_openssl2/crypto/asn1/a_enum.c",
+"builtin_openssl2/crypto/asn1/a_int.c",
+"builtin_openssl2/crypto/asn1/tasn_prn.c",
+"builtin_openssl2/crypto/asn1/i2d_pr.c",
+"builtin_openssl2/crypto/asn1/a_utf8.c",
+"builtin_openssl2/crypto/asn1/t_spki.c",
+"builtin_openssl2/crypto/asn1/a_digest.c",
+"builtin_openssl2/crypto/asn1/a_dup.c",
+"builtin_openssl2/crypto/asn1/i2d_pu.c",
+"builtin_openssl2/crypto/asn1/a_verify.c",
+"builtin_openssl2/crypto/asn1/f_enum.c",
+"builtin_openssl2/crypto/asn1/a_sign.c",
+"builtin_openssl2/crypto/asn1/d2i_pr.c",
+"builtin_openssl2/crypto/asn1/asn1_par.c",
+"builtin_openssl2/crypto/asn1/x_spki.c",
+"builtin_openssl2/crypto/asn1/a_d2i_fp.c",
+"builtin_openssl2/crypto/asn1/f_int.c",
+"builtin_openssl2/crypto/asn1/x_exten.c",
+"builtin_openssl2/crypto/asn1/tasn_utl.c",
+"builtin_openssl2/crypto/asn1/nsseq.c",
+"builtin_openssl2/crypto/asn1/a_bitstr.c",
+"builtin_openssl2/crypto/asn1/x_info.c",
+"builtin_openssl2/crypto/asn1/a_strnid.c",
+"builtin_openssl2/crypto/asn1/a_object.c",
+"builtin_openssl2/crypto/asn1/tasn_fre.c",
+"builtin_openssl2/crypto/asn1/d2i_pu.c",
+"builtin_openssl2/crypto/asn1/ameth_lib.c",
+"builtin_openssl2/crypto/asn1/x_attrib.c",
+"builtin_openssl2/crypto/evp/m_sha.c",
+"builtin_openssl2/crypto/evp/e_camellia.c",
+"builtin_openssl2/crypto/evp/e_aes.c",
+"builtin_openssl2/crypto/evp/bio_b64.c",
+"builtin_openssl2/crypto/evp/m_sigver.c",
+"builtin_openssl2/crypto/evp/m_wp.c",
+"builtin_openssl2/crypto/evp/m_sha1.c",
+"builtin_openssl2/crypto/evp/p_seal.c",
+"builtin_openssl2/crypto/evp/c_alld.c",
+"builtin_openssl2/crypto/evp/p5_crpt.c",
+"builtin_openssl2/crypto/evp/e_rc4.c",
+"builtin_openssl2/crypto/evp/m_ecdsa.c",
+"builtin_openssl2/crypto/evp/bio_enc.c",
+"builtin_openssl2/crypto/evp/e_des3.c",
+"builtin_openssl2/crypto/evp/m_null.c",
+"builtin_openssl2/crypto/evp/bio_ok.c",
+"builtin_openssl2/crypto/evp/pmeth_gn.c",
+"builtin_openssl2/crypto/evp/e_rc5.c",
+"builtin_openssl2/crypto/evp/e_rc2.c",
+"builtin_openssl2/crypto/evp/p_dec.c",
+"builtin_openssl2/crypto/evp/p_verify.c",
+"builtin_openssl2/crypto/evp/e_rc4_hmac_md5.c",
+"builtin_openssl2/crypto/evp/pmeth_lib.c",
+"builtin_openssl2/crypto/evp/m_ripemd.c",
+"builtin_openssl2/crypto/evp/m_md5.c",
+"builtin_openssl2/crypto/evp/e_bf.c",
+"builtin_openssl2/crypto/evp/p_enc.c",
+"builtin_openssl2/crypto/evp/m_dss.c",
+"builtin_openssl2/crypto/evp/bio_md.c",
+"builtin_openssl2/crypto/evp/evp_pbe.c",
+"builtin_openssl2/crypto/evp/e_seed.c",
+"builtin_openssl2/crypto/evp/e_cast.c",
+"builtin_openssl2/crypto/evp/p_open.c",
+"builtin_openssl2/crypto/evp/p5_crpt2.c",
+"builtin_openssl2/crypto/evp/m_dss1.c",
+"builtin_openssl2/crypto/evp/names.c",
+"builtin_openssl2/crypto/evp/evp_acnf.c",
+"builtin_openssl2/crypto/evp/e_des.c",
+"builtin_openssl2/crypto/evp/evp_cnf.c",
+"builtin_openssl2/crypto/evp/evp_lib.c",
+"builtin_openssl2/crypto/evp/digest.c",
+"builtin_openssl2/crypto/evp/evp_err.c",
+"builtin_openssl2/crypto/evp/evp_enc.c",
+"builtin_openssl2/crypto/evp/e_old.c",
+"builtin_openssl2/crypto/evp/c_all.c",
+"builtin_openssl2/crypto/evp/m_md2.c",
+"builtin_openssl2/crypto/evp/e_xcbc_d.c",
+"builtin_openssl2/crypto/evp/evp_fips.c",
+"builtin_openssl2/crypto/evp/pmeth_fn.c",
+"builtin_openssl2/crypto/evp/p_lib.c",
+"builtin_openssl2/crypto/evp/evp_key.c",
+"builtin_openssl2/crypto/evp/encode.c",
+"builtin_openssl2/crypto/evp/e_aes_cbc_hmac_sha1.c",
+"builtin_openssl2/crypto/evp/m_mdc2.c",
+"builtin_openssl2/crypto/evp/e_null.c",
+"builtin_openssl2/crypto/evp/p_sign.c",
+"builtin_openssl2/crypto/evp/e_idea.c",
+"builtin_openssl2/crypto/evp/c_allc.c",
+"builtin_openssl2/crypto/evp/evp_pkey.c",
+"builtin_openssl2/crypto/evp/m_md4.c",
+"builtin_openssl2/crypto/ex_data.c",
+"builtin_openssl2/crypto/pkcs12/p12_p8e.c",
+"builtin_openssl2/crypto/pkcs12/p12_crt.c",
+"builtin_openssl2/crypto/pkcs12/p12_utl.c",
+"builtin_openssl2/crypto/pkcs12/p12_attr.c",
+"builtin_openssl2/crypto/pkcs12/p12_npas.c",
+"builtin_openssl2/crypto/pkcs12/p12_decr.c",
+"builtin_openssl2/crypto/pkcs12/p12_init.c",
+"builtin_openssl2/crypto/pkcs12/p12_kiss.c",
+"builtin_openssl2/crypto/pkcs12/p12_add.c",
+"builtin_openssl2/crypto/pkcs12/p12_p8d.c",
+"builtin_openssl2/crypto/pkcs12/p12_mutl.c",
+"builtin_openssl2/crypto/pkcs12/p12_crpt.c",
+"builtin_openssl2/crypto/pkcs12/pk12err.c",
+"builtin_openssl2/crypto/pkcs12/p12_asn.c",
+"builtin_openssl2/crypto/pkcs12/p12_key.c",
+"builtin_openssl2/crypto/ecdh/ech_key.c",
+"builtin_openssl2/crypto/ecdh/ech_ossl.c",
+"builtin_openssl2/crypto/ecdh/ech_lib.c",
+"builtin_openssl2/crypto/ecdh/ech_err.c",
+"builtin_openssl2/crypto/o_str.c",
+"builtin_openssl2/crypto/conf/conf_api.c",
+"builtin_openssl2/crypto/conf/conf_err.c",
+"builtin_openssl2/crypto/conf/conf_def.c",
+"builtin_openssl2/crypto/conf/conf_lib.c",
+"builtin_openssl2/crypto/conf/conf_mall.c",
+"builtin_openssl2/crypto/conf/conf_sap.c",
+"builtin_openssl2/crypto/conf/conf_mod.c",
+"builtin_openssl2/crypto/ebcdic.c",
+"builtin_openssl2/crypto/ecdsa/ecs_lib.c",
+"builtin_openssl2/crypto/ecdsa/ecs_asn1.c",
+"builtin_openssl2/crypto/ecdsa/ecs_ossl.c",
+"builtin_openssl2/crypto/ecdsa/ecs_vrf.c",
+"builtin_openssl2/crypto/ecdsa/ecs_sign.c",
+"builtin_openssl2/crypto/ecdsa/ecs_err.c",
+"builtin_openssl2/crypto/dso/dso_win32.c",
+"builtin_openssl2/crypto/dso/dso_lib.c",
+"builtin_openssl2/crypto/dso/dso_dlfcn.c",
+"builtin_openssl2/crypto/dso/dso_dl.c",
+"builtin_openssl2/crypto/dso/dso_beos.c",
+"builtin_openssl2/crypto/dso/dso_null.c",
+"builtin_openssl2/crypto/dso/dso_vms.c",
+"builtin_openssl2/crypto/dso/dso_err.c",
+"builtin_openssl2/crypto/dso/dso_openssl.c",
+"builtin_openssl2/crypto/cryptlib.c",
+"builtin_openssl2/crypto/md5/md5_one.c",
+"builtin_openssl2/crypto/md5/md5_dgst.c",
+"builtin_openssl2/crypto/pkcs7/pkcs7err.c",
+"builtin_openssl2/crypto/pkcs7/pk7_smime.c",
+"builtin_openssl2/crypto/pkcs7/bio_pk7.c",
+"builtin_openssl2/crypto/pkcs7/pk7_mime.c",
+"builtin_openssl2/crypto/pkcs7/pk7_lib.c",
+"builtin_openssl2/crypto/pkcs7/pk7_asn1.c",
+"builtin_openssl2/crypto/pkcs7/pk7_doit.c",
+"builtin_openssl2/crypto/pkcs7/pk7_attr.c",
+"builtin_openssl2/crypto/md4/md4_one.c",
+"builtin_openssl2/crypto/md4/md4_dgst.c",
+"builtin_openssl2/crypto/o_dir.c",
+"builtin_openssl2/crypto/buffer/buf_err.c",
+"builtin_openssl2/crypto/buffer/buf_str.c",
+"builtin_openssl2/crypto/buffer/buffer.c",
+"builtin_openssl2/crypto/cms/cms_lib.c",
+"builtin_openssl2/crypto/cms/cms_io.c",
+"builtin_openssl2/crypto/cms/cms_err.c",
+"builtin_openssl2/crypto/cms/cms_dd.c",
+"builtin_openssl2/crypto/cms/cms_smime.c",
+"builtin_openssl2/crypto/cms/cms_att.c",
+"builtin_openssl2/crypto/cms/cms_pwri.c",
+"builtin_openssl2/crypto/cms/cms_cd.c",
+"builtin_openssl2/crypto/cms/cms_sd.c",
+"builtin_openssl2/crypto/cms/cms_asn1.c",
+"builtin_openssl2/crypto/cms/cms_env.c",
+"builtin_openssl2/crypto/cms/cms_enc.c",
+"builtin_openssl2/crypto/cms/cms_ess.c",
+"builtin_openssl2/crypto/mem_dbg.c",
+"builtin_openssl2/crypto/uid.c",
+"builtin_openssl2/crypto/stack/stack.c",
+"builtin_openssl2/crypto/ec/ec_ameth.c",
+"builtin_openssl2/crypto/ec/ec_err.c",
+"builtin_openssl2/crypto/ec/ec_lib.c",
+"builtin_openssl2/crypto/ec/ec_curve.c",
+"builtin_openssl2/crypto/ec/ec_oct.c",
+"builtin_openssl2/crypto/ec/ec_asn1.c",
+"builtin_openssl2/crypto/ec/ecp_oct.c",
+"builtin_openssl2/crypto/ec/ec_print.c",
+"builtin_openssl2/crypto/ec/ec2_smpl.c",
+"builtin_openssl2/crypto/ec/ecp_nistp224.c",
+"builtin_openssl2/crypto/ec/ec2_oct.c",
+"builtin_openssl2/crypto/ec/eck_prn.c",
+"builtin_openssl2/crypto/ec/ec_key.c",
+"builtin_openssl2/crypto/ec/ecp_nist.c",
+"builtin_openssl2/crypto/ec/ec_check.c",
+"builtin_openssl2/crypto/ec/ecp_smpl.c",
+"builtin_openssl2/crypto/ec/ec2_mult.c",
+"builtin_openssl2/crypto/ec/ecp_mont.c",
+"builtin_openssl2/crypto/ec/ecp_nistp521.c",
+"builtin_openssl2/crypto/ec/ec_mult.c",
+"builtin_openssl2/crypto/ec/ecp_nistputil.c",
+"builtin_openssl2/crypto/ec/ec_pmeth.c",
+"builtin_openssl2/crypto/ec/ec_cvt.c",
+"builtin_openssl2/crypto/ec/ecp_nistp256.c",
+"builtin_openssl2/crypto/krb5/krb5_asn.c",
+"builtin_openssl2/crypto/hmac/hmac.c",
+"builtin_openssl2/crypto/hmac/hm_ameth.c",
+"builtin_openssl2/crypto/hmac/hm_pmeth.c",
+"builtin_openssl2/crypto/comp/c_rle.c",
+"builtin_openssl2/crypto/comp/c_zlib.c",
+"builtin_openssl2/crypto/comp/comp_lib.c",
+"builtin_openssl2/crypto/comp/comp_err.c",
+"builtin_openssl2/crypto/des/fcrypt.c",
+"builtin_openssl2/crypto/des/str2key.c",
+"builtin_openssl2/crypto/des/cbc_cksm.c",
+"builtin_openssl2/crypto/des/des_enc.c",
+"builtin_openssl2/crypto/des/ofb_enc.c",
+"builtin_openssl2/crypto/des/read2pwd.c",
+"builtin_openssl2/crypto/des/ecb3_enc.c",
+"builtin_openssl2/crypto/des/rand_key.c",
+"builtin_openssl2/crypto/des/cfb64ede.c",
+"builtin_openssl2/crypto/des/rpc_enc.c",
+"builtin_openssl2/crypto/des/ofb64ede.c",
+"builtin_openssl2/crypto/des/qud_cksm.c",
+"builtin_openssl2/crypto/des/enc_writ.c",
+"builtin_openssl2/crypto/des/set_key.c",
+"builtin_openssl2/crypto/des/xcbc_enc.c",
+"builtin_openssl2/crypto/des/fcrypt_b.c",
+"builtin_openssl2/crypto/des/ede_cbcm_enc.c",
+"builtin_openssl2/crypto/des/des_old2.c",
+"builtin_openssl2/crypto/des/cfb_enc.c",
+"builtin_openssl2/crypto/des/ecb_enc.c",
+"builtin_openssl2/crypto/des/enc_read.c",
+"builtin_openssl2/crypto/des/des_old.c",
+"builtin_openssl2/crypto/des/ofb64enc.c",
+"builtin_openssl2/crypto/des/pcbc_enc.c",
+"builtin_openssl2/crypto/des/cbc_enc.c",
+"builtin_openssl2/crypto/des/cfb64enc.c",
+"builtin_openssl2/crypto/lhash/lh_stats.c",
+"builtin_openssl2/crypto/lhash/lhash.c",
+"builtin_openssl2/crypto/x509v3/v3_genn.c",
+"builtin_openssl2/crypto/x509v3/pcy_cache.c",
+"builtin_openssl2/crypto/x509v3/v3_sxnet.c",
+"builtin_openssl2/crypto/x509v3/v3err.c",
+"builtin_openssl2/crypto/x509v3/v3_conf.c",
+"builtin_openssl2/crypto/x509v3/v3_utl.c",
+"builtin_openssl2/crypto/x509v3/v3_akeya.c",
+"builtin_openssl2/crypto/x509v3/v3_lib.c",
+"builtin_openssl2/crypto/x509v3/pcy_lib.c",
+"builtin_openssl2/crypto/x509v3/v3_cpols.c",
+"builtin_openssl2/crypto/x509v3/v3_ia5.c",
+"builtin_openssl2/crypto/x509v3/v3_bitst.c",
+"builtin_openssl2/crypto/x509v3/v3_skey.c",
+"builtin_openssl2/crypto/x509v3/v3_info.c",
+"builtin_openssl2/crypto/x509v3/v3_asid.c",
+"builtin_openssl2/crypto/x509v3/pcy_tree.c",
+"builtin_openssl2/crypto/x509v3/v3_pcons.c",
+"builtin_openssl2/crypto/x509v3/v3_bcons.c",
+"builtin_openssl2/crypto/x509v3/v3_pku.c",
+"builtin_openssl2/crypto/x509v3/v3_ocsp.c",
+"builtin_openssl2/crypto/x509v3/pcy_map.c",
+"builtin_openssl2/crypto/x509v3/v3_ncons.c",
+"builtin_openssl2/crypto/x509v3/v3_purp.c",
+"builtin_openssl2/crypto/x509v3/v3_enum.c",
+"builtin_openssl2/crypto/x509v3/v3_pmaps.c",
+"builtin_openssl2/crypto/x509v3/pcy_node.c",
+"builtin_openssl2/crypto/x509v3/v3_pcia.c",
+"builtin_openssl2/crypto/x509v3/v3_crld.c",
+"builtin_openssl2/crypto/x509v3/v3_pci.c",
+"builtin_openssl2/crypto/x509v3/v3_akey.c",
+"builtin_openssl2/crypto/x509v3/v3_addr.c",
+"builtin_openssl2/crypto/x509v3/v3_int.c",
+"builtin_openssl2/crypto/x509v3/v3_alt.c",
+"builtin_openssl2/crypto/x509v3/v3_extku.c",
+"builtin_openssl2/crypto/x509v3/v3_prn.c",
+"builtin_openssl2/crypto/x509v3/pcy_data.c",
+"builtin_openssl2/crypto/aes/aes_ofb.c",
+"builtin_openssl2/crypto/aes/aes_ctr.c",
+"builtin_openssl2/crypto/aes/aes_ecb.c",
+"builtin_openssl2/crypto/aes/aes_cfb.c",
+"builtin_openssl2/crypto/aes/aes_wrap.c",
+"builtin_openssl2/crypto/aes/aes_ige.c",
+"builtin_openssl2/crypto/aes/aes_misc.c",
+"builtin_openssl2/crypto/pqueue/pqueue.c",
+"builtin_openssl2/crypto/sha/sha_one.c",
+"builtin_openssl2/crypto/sha/sha_dgst.c",
+"builtin_openssl2/crypto/sha/sha512.c",
+"builtin_openssl2/crypto/sha/sha1_one.c",
+"builtin_openssl2/crypto/sha/sha1dgst.c",
+"builtin_openssl2/crypto/sha/sha256.c",
+"builtin_openssl2/crypto/whrlpool/wp_dgst.c",
+"builtin_openssl2/crypto/objects/obj_xref.c",
+"builtin_openssl2/crypto/objects/o_names.c",
+"builtin_openssl2/crypto/objects/obj_err.c",
+"builtin_openssl2/crypto/objects/obj_dat.c",
+"builtin_openssl2/crypto/objects/obj_lib.c",
+"builtin_openssl2/crypto/mem.c",
+"builtin_openssl2/crypto/fips_ers.c",
+"builtin_openssl2/crypto/o_fips.c",
+"builtin_openssl2/crypto/engine/eng_rdrand.c",
+"builtin_openssl2/crypto/engine/eng_err.c",
+"builtin_openssl2/crypto/engine/eng_rsax.c",
+"builtin_openssl2/crypto/engine/tb_ecdsa.c",
+"builtin_openssl2/crypto/engine/tb_rsa.c",
+"builtin_openssl2/crypto/engine/tb_cipher.c",
+"builtin_openssl2/crypto/engine/tb_dsa.c",
+"builtin_openssl2/crypto/engine/eng_lib.c",
+"builtin_openssl2/crypto/engine/tb_asnmth.c",
+"builtin_openssl2/crypto/engine/tb_ecdh.c",
+"builtin_openssl2/crypto/engine/tb_dh.c",
+"builtin_openssl2/crypto/engine/tb_store.c",
+"builtin_openssl2/crypto/engine/eng_init.c",
+"builtin_openssl2/crypto/engine/eng_cnf.c",
+"builtin_openssl2/crypto/engine/eng_all.c",
+"builtin_openssl2/crypto/engine/tb_digest.c",
+"builtin_openssl2/crypto/engine/tb_pkmeth.c",
+"builtin_openssl2/crypto/engine/eng_table.c",
+"builtin_openssl2/crypto/engine/eng_ctrl.c",
+"builtin_openssl2/crypto/engine/eng_list.c",
+"builtin_openssl2/crypto/engine/eng_cryptodev.c",
+"builtin_openssl2/crypto/engine/eng_pkey.c",
+"builtin_openssl2/crypto/engine/tb_rand.c",
+"builtin_openssl2/crypto/engine/eng_openssl.c",
+"builtin_openssl2/crypto/engine/eng_fat.c",
+"builtin_openssl2/crypto/engine/eng_dyn.c",
+"builtin_openssl2/crypto/ts/ts_rsp_verify.c",
+"builtin_openssl2/crypto/ts/ts_req_print.c",
+"builtin_openssl2/crypto/ts/ts_verify_ctx.c",
+"builtin_openssl2/crypto/ts/ts_req_utils.c",
+"builtin_openssl2/crypto/ts/ts_err.c",
+"builtin_openssl2/crypto/ts/ts_rsp_print.c",
+"builtin_openssl2/crypto/ts/ts_rsp_utils.c",
+"builtin_openssl2/crypto/ts/ts_lib.c",
+"builtin_openssl2/crypto/ts/ts_conf.c",
+"builtin_openssl2/crypto/ts/ts_asn1.c",
+"builtin_openssl2/crypto/ts/ts_rsp_sign.c",
+"builtin_openssl2/crypto/ocsp/ocsp_ext.c",
+"builtin_openssl2/crypto/ocsp/ocsp_cl.c",
+"builtin_openssl2/crypto/ocsp/ocsp_ht.c",
+"builtin_openssl2/crypto/ocsp/ocsp_lib.c",
+"builtin_openssl2/crypto/ocsp/ocsp_srv.c",
+"builtin_openssl2/crypto/ocsp/ocsp_vfy.c",
+"builtin_openssl2/crypto/ocsp/ocsp_err.c",
+"builtin_openssl2/crypto/ocsp/ocsp_prn.c",
+"builtin_openssl2/crypto/ocsp/ocsp_asn.c",
+"builtin_openssl2/crypto/bf/bf_cfb64.c",
+"builtin_openssl2/crypto/bf/bf_ecb.c",
+"builtin_openssl2/crypto/bf/bf_enc.c",
+"builtin_openssl2/crypto/bf/bf_skey.c",
+"builtin_openssl2/crypto/bf/bf_ofb64.c",
+"builtin_openssl2/crypto/idea/i_skey.c",
+"builtin_openssl2/crypto/idea/i_ofb64.c",
+"builtin_openssl2/crypto/idea/i_cbc.c",
+"builtin_openssl2/crypto/idea/i_ecb.c",
+"builtin_openssl2/crypto/idea/i_cfb64.c",
+"builtin_openssl2/crypto/cmac/cm_ameth.c",
+"builtin_openssl2/crypto/cmac/cmac.c",
+"builtin_openssl2/crypto/cmac/cm_pmeth.c",
+"builtin_openssl2/crypto/dh/dh_lib.c",
+"builtin_openssl2/crypto/dh/dh_key.c",
+"builtin_openssl2/crypto/dh/dh_asn1.c",
+"builtin_openssl2/crypto/dh/dh_depr.c",
+"builtin_openssl2/crypto/dh/dh_pmeth.c",
+"builtin_openssl2/crypto/dh/dh_prn.c",
+"builtin_openssl2/crypto/dh/dh_gen.c",
+"builtin_openssl2/crypto/dh/dh_ameth.c",
+"builtin_openssl2/crypto/dh/dh_check.c",
+"builtin_openssl2/crypto/dh/dh_err.c",
+"builtin_openssl2/crypto/modes/ccm128.c",
+"builtin_openssl2/crypto/modes/ofb128.c",
+"builtin_openssl2/crypto/modes/cts128.c",
+"builtin_openssl2/crypto/modes/ctr128.c",
+"builtin_openssl2/crypto/modes/gcm128.c",
+"builtin_openssl2/crypto/modes/cbc128.c",
+"builtin_openssl2/crypto/modes/cfb128.c",
+"builtin_openssl2/crypto/modes/xts128.c",
+"builtin_openssl2/crypto/camellia/cmll_cfb.c",
+"builtin_openssl2/crypto/camellia/cmll_ecb.c",
+"builtin_openssl2/crypto/camellia/cmll_utl.c",
+"builtin_openssl2/crypto/camellia/cmll_misc.c",
+"builtin_openssl2/crypto/camellia/cmll_ofb.c",
+"builtin_openssl2/crypto/camellia/cmll_ctr.c",
+"builtin_openssl2/crypto/seed/seed_ecb.c",
+"builtin_openssl2/crypto/seed/seed_cbc.c",
+"builtin_openssl2/crypto/seed/seed.c",
+"builtin_openssl2/crypto/seed/seed_ofb.c",
+"builtin_openssl2/crypto/seed/seed_cfb.c",
+"builtin_openssl2/crypto/txt_db/txt_db.c",
+"builtin_openssl2/crypto/cpt_err.c",
+"builtin_openssl2/crypto/pem/pem_pk8.c",
+"builtin_openssl2/crypto/pem/pem_lib.c",
+"builtin_openssl2/crypto/pem/pem_sign.c",
+"builtin_openssl2/crypto/pem/pem_all.c",
+"builtin_openssl2/crypto/pem/pem_info.c",
+"builtin_openssl2/crypto/pem/pem_pkey.c",
+"builtin_openssl2/crypto/pem/pem_seal.c",
+"builtin_openssl2/crypto/pem/pem_err.c",
+"builtin_openssl2/crypto/pem/pem_xaux.c",
+"builtin_openssl2/crypto/pem/pvkfmt.c",
+"builtin_openssl2/crypto/pem/pem_x509.c",
+"builtin_openssl2/crypto/pem/pem_oth.c",
+"builtin_openssl2/crypto/rand/rand_lib.c",
+"builtin_openssl2/crypto/rand/randfile.c",
+"builtin_openssl2/crypto/rand/rand_os2.c",
+"builtin_openssl2/crypto/rand/rand_unix.c",
+"builtin_openssl2/crypto/rand/rand_nw.c",
+"builtin_openssl2/crypto/rand/md_rand.c",
+"builtin_openssl2/crypto/rand/rand_err.c",
+"builtin_openssl2/crypto/rand/rand_win.c",
+"builtin_openssl2/crypto/rand/rand_egd.c",
+"builtin_openssl2/crypto/cversion.c",
+"builtin_openssl2/crypto/cast/c_ecb.c",
+"builtin_openssl2/crypto/cast/c_skey.c",
+"builtin_openssl2/crypto/cast/c_ofb64.c",
+"builtin_openssl2/crypto/cast/c_enc.c",
+"builtin_openssl2/crypto/cast/c_cfb64.c",
+"builtin_openssl2/crypto/o_time.c",
+"builtin_openssl2/crypto/mdc2/mdc2dgst.c",
+"builtin_openssl2/crypto/mdc2/mdc2_one.c",
+"builtin_openssl2/crypto/rc4/rc4_utl.c",
+"builtin_openssl2/crypto/ui/ui_compat.c",
+"builtin_openssl2/crypto/ui/ui_util.c",
+"builtin_openssl2/crypto/ui/ui_lib.c",
+"builtin_openssl2/crypto/ui/ui_err.c",
+"builtin_openssl2/crypto/ui/ui_openssl.c",
+"builtin_openssl2/crypto/bio/bf_buff.c",
+"builtin_openssl2/crypto/bio/bss_null.c",
+"builtin_openssl2/crypto/bio/bss_acpt.c",
+"builtin_openssl2/crypto/bio/bss_conn.c",
+"builtin_openssl2/crypto/bio/bss_fd.c",
+"builtin_openssl2/crypto/bio/bf_null.c",
+"builtin_openssl2/crypto/bio/bio_err.c",
+"builtin_openssl2/crypto/bio/bss_sock.c",
+"builtin_openssl2/crypto/bio/bss_mem.c",
+"builtin_openssl2/crypto/bio/b_dump.c",
+"builtin_openssl2/crypto/bio/b_print.c",
+"builtin_openssl2/crypto/bio/b_sock.c",
+"builtin_openssl2/crypto/bio/bss_dgram.c",
+"builtin_openssl2/crypto/bio/bf_nbio.c",
+"builtin_openssl2/crypto/bio/bio_lib.c",
+"builtin_openssl2/crypto/bio/bss_file.c",
+"builtin_openssl2/crypto/bio/bss_bio.c",
+"builtin_openssl2/crypto/bio/bss_log.c",
+"builtin_openssl2/crypto/bio/bio_cb.c",
+"builtin_openssl2/crypto/o_init.c",
+"builtin_openssl2/crypto/rc2/rc2_skey.c",
+"builtin_openssl2/crypto/rc2/rc2_cbc.c",
+"builtin_openssl2/crypto/rc2/rc2cfb64.c",
+"builtin_openssl2/crypto/rc2/rc2_ecb.c",
+"builtin_openssl2/crypto/rc2/rc2ofb64.c",
+"builtin_openssl2/crypto/bn/bn_x931p.c",
+"builtin_openssl2/crypto/bn/bn_blind.c",
+"builtin_openssl2/crypto/bn/bn_gf2m.c",
+"builtin_openssl2/crypto/bn/bn_const.c",
+"builtin_openssl2/crypto/bn/bn_sqr.c",
+"builtin_openssl2/crypto/bn/bn_nist.c",
+"builtin_openssl2/crypto/bn/bn_rand.c",
+"builtin_openssl2/crypto/bn/bn_err.c",
+"builtin_openssl2/crypto/bn/bn_div.c",
+"builtin_openssl2/crypto/bn/bn_kron.c",
+"builtin_openssl2/crypto/bn/bn_ctx.c",
+"builtin_openssl2/crypto/bn/bn_shift.c",
+"builtin_openssl2/crypto/bn/bn_mod.c",
+"builtin_openssl2/crypto/bn/bn_exp2.c",
+"builtin_openssl2/crypto/bn/bn_word.c",
+"builtin_openssl2/crypto/bn/bn_add.c",
+"builtin_openssl2/crypto/bn/bn_exp.c",
+"builtin_openssl2/crypto/bn/bn_mont.c",
+"builtin_openssl2/crypto/bn/bn_print.c",
+"builtin_openssl2/crypto/bn/bn_mul.c",
+"builtin_openssl2/crypto/bn/bn_prime.c",
+"builtin_openssl2/crypto/bn/bn_depr.c",
+"builtin_openssl2/crypto/bn/bn_gcd.c",
+"builtin_openssl2/crypto/bn/bn_mpi.c",
+"builtin_openssl2/crypto/bn/bn_sqrt.c",
+"builtin_openssl2/crypto/bn/bn_recp.c",
+"builtin_openssl2/crypto/bn/bn_lib.c",
+"builtin_openssl2/crypto/ripemd/rmd_dgst.c",
+"builtin_openssl2/crypto/ripemd/rmd_one.c",
+"builtin_openssl2/crypto/rsa/rsa_x931.c",
+"builtin_openssl2/crypto/rsa/rsa_depr.c",
+"builtin_openssl2/crypto/rsa/rsa_saos.c",
+"builtin_openssl2/crypto/rsa/rsa_crpt.c",
+"builtin_openssl2/crypto/rsa/rsa_pss.c",
+"builtin_openssl2/crypto/rsa/rsa_oaep.c",
+"builtin_openssl2/crypto/rsa/rsa_null.c",
+"builtin_openssl2/crypto/rsa/rsa_gen.c",
+"builtin_openssl2/crypto/rsa/rsa_prn.c",
+"builtin_openssl2/crypto/rsa/rsa_pmeth.c",
+"builtin_openssl2/crypto/rsa/rsa_asn1.c",
+"builtin_openssl2/crypto/rsa/rsa_ssl.c",
+"builtin_openssl2/crypto/rsa/rsa_ameth.c",
+"builtin_openssl2/crypto/rsa/rsa_pk1.c",
+"builtin_openssl2/crypto/rsa/rsa_err.c",
+"builtin_openssl2/crypto/rsa/rsa_lib.c",
+"builtin_openssl2/crypto/rsa/rsa_none.c",
+"builtin_openssl2/crypto/rsa/rsa_chk.c",
+"builtin_openssl2/crypto/rsa/rsa_eay.c",
+"builtin_openssl2/crypto/rsa/rsa_sign.c",
+"builtin_openssl2/crypto/srp/srp_lib.c",
+"builtin_openssl2/crypto/srp/srp_vfy.c",
+"builtin_openssl2/crypto/err/err.c",
+"builtin_openssl2/crypto/err/err_prn.c",
+"builtin_openssl2/crypto/err/err_all.c",
+"builtin_openssl2/crypto/mem_clr.c",
+"builtin_openssl2/crypto/rc4/rc4_skey.c",
+"builtin_openssl2/crypto/rc4/rc4_enc.c",
+"builtin_openssl2/crypto/camellia/camellia.c",
+"builtin_openssl2/crypto/camellia/cmll_cbc.c",
+#"builtin_openssl2/crypto/aes/aes_x86core.c",
+"builtin_openssl2/crypto/aes/aes_core.c",
+"builtin_openssl2/crypto/aes/aes_cbc.c",
+"builtin_openssl2/crypto/whrlpool/wp_block.c",
+"builtin_openssl2/crypto/bn/bn_asm.c",
+]
+
+env.drivers_sources+=openssl_sources
+env.Append(CPPPATH=["#drivers/builtin_openssl2/crypto"])
+env.Append(CPPPATH=["#drivers/builtin_openssl2/openssl"])
+env.Append(CPPPATH=["#drivers/builtin_openssl2/crypto/evp"])
+env.Append(CPPPATH=["#drivers/builtin_openssl2/crypto/asn1"])
+env.Append(CPPPATH=["#drivers/builtin_openssl2/crypto/modes"])
+#env.Append(CPPPATH=["#drivers/builtin_openssl2/crypto/store"])
+env.Append(CPPFLAGS=["-DOPENSSL_NO_ASM","-DOPENSSL_THREADS","-DL_ENDIAN"])
+Export('env')
diff --git a/drivers/builtin_openssl/buildinf.h b/drivers/builtin_openssl2/buildinf.h
index 139597f9cb..139597f9cb 100644
--- a/drivers/builtin_openssl/buildinf.h
+++ b/drivers/builtin_openssl2/buildinf.h
diff --git a/drivers/builtin_openssl/crypto/LPdir_nyi.c b/drivers/builtin_openssl2/crypto/LPdir_nyi.c
index 6c1a50e6a8..6c1a50e6a8 100644
--- a/drivers/builtin_openssl/crypto/LPdir_nyi.c
+++ b/drivers/builtin_openssl2/crypto/LPdir_nyi.c
diff --git a/drivers/builtin_openssl/crypto/LPdir_unix.c b/drivers/builtin_openssl2/crypto/LPdir_unix.c
index b004cd99e8..b004cd99e8 100644
--- a/drivers/builtin_openssl/crypto/LPdir_unix.c
+++ b/drivers/builtin_openssl2/crypto/LPdir_unix.c
diff --git a/drivers/builtin_openssl/crypto/LPdir_vms.c b/drivers/builtin_openssl2/crypto/LPdir_vms.c
index 7613bd254e..7613bd254e 100644
--- a/drivers/builtin_openssl/crypto/LPdir_vms.c
+++ b/drivers/builtin_openssl2/crypto/LPdir_vms.c
diff --git a/drivers/builtin_openssl/crypto/LPdir_win.c b/drivers/builtin_openssl2/crypto/LPdir_win.c
index 702dbc730f..702dbc730f 100644
--- a/drivers/builtin_openssl/crypto/LPdir_win.c
+++ b/drivers/builtin_openssl2/crypto/LPdir_win.c
diff --git a/drivers/builtin_openssl/crypto/LPdir_win32.c b/drivers/builtin_openssl2/crypto/LPdir_win32.c
index e39872da52..e39872da52 100644
--- a/drivers/builtin_openssl/crypto/LPdir_win32.c
+++ b/drivers/builtin_openssl2/crypto/LPdir_win32.c
diff --git a/drivers/builtin_openssl/crypto/LPdir_wince.c b/drivers/builtin_openssl2/crypto/LPdir_wince.c
index ab0e1e6f4f..ab0e1e6f4f 100644
--- a/drivers/builtin_openssl/crypto/LPdir_wince.c
+++ b/drivers/builtin_openssl2/crypto/LPdir_wince.c
diff --git a/drivers/builtin_openssl/crypto/aes/README b/drivers/builtin_openssl2/crypto/aes/README
index 0f9620a80e..0f9620a80e 100644
--- a/drivers/builtin_openssl/crypto/aes/README
+++ b/drivers/builtin_openssl2/crypto/aes/README
diff --git a/drivers/builtin_openssl/crypto/aes/aes_cbc.c b/drivers/builtin_openssl2/crypto/aes/aes_cbc.c
index 227f75625d..227f75625d 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_cbc.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_cbc.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_cfb.c b/drivers/builtin_openssl2/crypto/aes/aes_cfb.c
index 0c6d058ce7..0c6d058ce7 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_cfb.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_cfb.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_core.c b/drivers/builtin_openssl2/crypto/aes/aes_core.c
index 8f5210ac70..8f5210ac70 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_core.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_core.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_ctr.c b/drivers/builtin_openssl2/crypto/aes/aes_ctr.c
index 7c9d165d8a..7c9d165d8a 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_ctr.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_ctr.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_ecb.c b/drivers/builtin_openssl2/crypto/aes/aes_ecb.c
index 28aa561c2d..28aa561c2d 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_ecb.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_ecb.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_ige.c b/drivers/builtin_openssl2/crypto/aes/aes_ige.c
index c161351e65..c161351e65 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_ige.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_ige.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_locl.h b/drivers/builtin_openssl2/crypto/aes/aes_locl.h
index 054b442d41..054b442d41 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_locl.h
+++ b/drivers/builtin_openssl2/crypto/aes/aes_locl.h
diff --git a/drivers/builtin_openssl/crypto/aes/aes_misc.c b/drivers/builtin_openssl2/crypto/aes/aes_misc.c
index f083488ecb..f083488ecb 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_misc.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_misc.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_ofb.c b/drivers/builtin_openssl2/crypto/aes/aes_ofb.c
index 50bf0b8325..50bf0b8325 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_ofb.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_ofb.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_wrap.c b/drivers/builtin_openssl2/crypto/aes/aes_wrap.c
index e2d73d37ce..e2d73d37ce 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_wrap.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_wrap.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes_x86core.c b/drivers/builtin_openssl2/crypto/aes/aes_x86core.c
index d323e265c0..d323e265c0 100644
--- a/drivers/builtin_openssl/crypto/aes/aes_x86core.c
+++ b/drivers/builtin_openssl2/crypto/aes/aes_x86core.c
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-586.pl b/drivers/builtin_openssl2/crypto/aes/asm/aes-586.pl
index 687ed811be..687ed811be 100755
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-586.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-586.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-armv4.pl b/drivers/builtin_openssl2/crypto/aes/asm/aes-armv4.pl
index 86b86c4a0f..86b86c4a0f 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-armv4.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-armv4.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-ia64.S b/drivers/builtin_openssl2/crypto/aes/asm/aes-ia64.S
index 7f6c4c3662..7f6c4c3662 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-ia64.S
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-ia64.S
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-mips.pl b/drivers/builtin_openssl2/crypto/aes/asm/aes-mips.pl
index e52395421b..e52395421b 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-mips.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-mips.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-parisc.pl b/drivers/builtin_openssl2/crypto/aes/asm/aes-parisc.pl
index 714dcfbbe3..714dcfbbe3 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-parisc.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-parisc.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-ppc.pl b/drivers/builtin_openssl2/crypto/aes/asm/aes-ppc.pl
index 7c52cbe5f9..7c52cbe5f9 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-ppc.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-ppc.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-s390x.pl b/drivers/builtin_openssl2/crypto/aes/asm/aes-s390x.pl
index e75dcd0315..e75dcd0315 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-s390x.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-s390x.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-sparcv9.pl b/drivers/builtin_openssl2/crypto/aes/asm/aes-sparcv9.pl
index 403c4d1290..403c4d1290 100755
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-sparcv9.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-sparcv9.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aes-x86_64.pl b/drivers/builtin_openssl2/crypto/aes/asm/aes-x86_64.pl
index 34cbb5d844..34cbb5d844 100755
--- a/drivers/builtin_openssl/crypto/aes/asm/aes-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aes-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aesni-sha1-x86_64.pl b/drivers/builtin_openssl2/crypto/aes/asm/aesni-sha1-x86_64.pl
index 3c8f6c19e7..3c8f6c19e7 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aesni-sha1-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aesni-sha1-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aesni-x86.pl b/drivers/builtin_openssl2/crypto/aes/asm/aesni-x86.pl
index 3dc345b585..3dc345b585 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aesni-x86.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aesni-x86.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/aesni-x86_64.pl b/drivers/builtin_openssl2/crypto/aes/asm/aesni-x86_64.pl
index 0dbb194b8d..0dbb194b8d 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/aesni-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/aesni-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/bsaes-x86_64.pl b/drivers/builtin_openssl2/crypto/aes/asm/bsaes-x86_64.pl
index 41b90f0844..41b90f0844 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/bsaes-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/bsaes-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/vpaes-x86.pl b/drivers/builtin_openssl2/crypto/aes/asm/vpaes-x86.pl
index 1533e2c304..1533e2c304 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/vpaes-x86.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/vpaes-x86.pl
diff --git a/drivers/builtin_openssl/crypto/aes/asm/vpaes-x86_64.pl b/drivers/builtin_openssl2/crypto/aes/asm/vpaes-x86_64.pl
index bd7f45b850..bd7f45b850 100644
--- a/drivers/builtin_openssl/crypto/aes/asm/vpaes-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/aes/asm/vpaes-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/alphacpuid.pl b/drivers/builtin_openssl2/crypto/alphacpuid.pl
index 4b3cbb9827..4b3cbb9827 100644
--- a/drivers/builtin_openssl/crypto/alphacpuid.pl
+++ b/drivers/builtin_openssl2/crypto/alphacpuid.pl
diff --git a/drivers/builtin_openssl/crypto/arm_arch.h b/drivers/builtin_openssl2/crypto/arm_arch.h
index 5a83107680..5a83107680 100644
--- a/drivers/builtin_openssl/crypto/arm_arch.h
+++ b/drivers/builtin_openssl2/crypto/arm_arch.h
diff --git a/drivers/builtin_openssl/crypto/armcap.c b/drivers/builtin_openssl2/crypto/armcap.c
index 9abaf396e5..9abaf396e5 100644
--- a/drivers/builtin_openssl/crypto/armcap.c
+++ b/drivers/builtin_openssl2/crypto/armcap.c
diff --git a/drivers/builtin_openssl/crypto/armv4cpuid.S b/drivers/builtin_openssl2/crypto/armv4cpuid.S
index 2d618deaa4..2d618deaa4 100644
--- a/drivers/builtin_openssl/crypto/armv4cpuid.S
+++ b/drivers/builtin_openssl2/crypto/armv4cpuid.S
diff --git a/drivers/builtin_openssl/crypto/asn1/a_bitstr.c b/drivers/builtin_openssl2/crypto/asn1/a_bitstr.c
index 34179960b8..34179960b8 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_bitstr.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_bitstr.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_bool.c b/drivers/builtin_openssl2/crypto/asn1/a_bool.c
index 331acdf053..331acdf053 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_bool.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_bool.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_bytes.c b/drivers/builtin_openssl2/crypto/asn1/a_bytes.c
index 92d630cdba..92d630cdba 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_bytes.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_bytes.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_d2i_fp.c b/drivers/builtin_openssl2/crypto/asn1/a_d2i_fp.c
index 52b2ebdb63..52b2ebdb63 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_d2i_fp.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_d2i_fp.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_digest.c b/drivers/builtin_openssl2/crypto/asn1/a_digest.c
index cbdeea6ac0..cbdeea6ac0 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_digest.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_digest.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_dup.c b/drivers/builtin_openssl2/crypto/asn1/a_dup.c
index d98992548a..d98992548a 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_dup.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_dup.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_enum.c b/drivers/builtin_openssl2/crypto/asn1/a_enum.c
index fe9aa13b9c..fe9aa13b9c 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_enum.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_enum.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_gentm.c b/drivers/builtin_openssl2/crypto/asn1/a_gentm.c
index c79c6f538c..c79c6f538c 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_gentm.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_gentm.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_i2d_fp.c b/drivers/builtin_openssl2/crypto/asn1/a_i2d_fp.c
index a3ad76d356..a3ad76d356 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_i2d_fp.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_i2d_fp.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_int.c b/drivers/builtin_openssl2/crypto/asn1/a_int.c
index 297c45a9ff..297c45a9ff 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_int.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_int.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_mbstr.c b/drivers/builtin_openssl2/crypto/asn1/a_mbstr.c
index 1538e0a4fc..1538e0a4fc 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_mbstr.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_mbstr.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_object.c b/drivers/builtin_openssl2/crypto/asn1/a_object.c
index 3978c9150d..3978c9150d 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_object.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_object.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_octet.c b/drivers/builtin_openssl2/crypto/asn1/a_octet.c
index e8725e44f1..e8725e44f1 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_octet.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_octet.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_print.c b/drivers/builtin_openssl2/crypto/asn1/a_print.c
index d18e772320..d18e772320 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_print.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_print.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_set.c b/drivers/builtin_openssl2/crypto/asn1/a_set.c
index d726c8d3a8..d726c8d3a8 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_set.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_set.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_sign.c b/drivers/builtin_openssl2/crypto/asn1/a_sign.c
index 7b4a193d6b..7b4a193d6b 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_sign.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_sign.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_strex.c b/drivers/builtin_openssl2/crypto/asn1/a_strex.c
index ead37ac325..ead37ac325 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_strex.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_strex.c
diff --git a/drivers/builtin_openssl2/crypto/asn1/a_strnid.c b/drivers/builtin_openssl2/crypto/asn1/a_strnid.c
new file mode 100644
index 0000000000..2afd5a4136
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/asn1/a_strnid.c
@@ -0,0 +1,290 @@
+/* a_strnid.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "cryptlib.h"
+#include <openssl/asn1.h>
+#include <openssl/objects.h>
+
+
+static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
+static void st_free(ASN1_STRING_TABLE *tbl);
+static int sk_table_cmp(const ASN1_STRING_TABLE * const *a,
+ const ASN1_STRING_TABLE * const *b);
+
+
+/* This is the global mask for the mbstring functions: this is use to
+ * mask out certain types (such as BMPString and UTF8String) because
+ * certain software (e.g. Netscape) has problems with them.
+ */
+
+static unsigned long global_mask = B_ASN1_UTF8STRING;
+
+void ASN1_STRING_set_default_mask(unsigned long mask)
+{
+ global_mask = mask;
+}
+
+unsigned long ASN1_STRING_get_default_mask(void)
+{
+ return global_mask;
+}
+
+/* This function sets the default to various "flavours" of configuration.
+ * based on an ASCII string. Currently this is:
+ * MASK:XXXX : a numerical mask value.
+ * nobmp : Don't use BMPStrings (just Printable, T61).
+ * pkix : PKIX recommendation in RFC2459.
+ * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004).
+ * default: the default value, Printable, T61, BMP.
+ */
+
+int ASN1_STRING_set_default_mask_asc(const char *p)
+{
+ unsigned long mask;
+ char *end;
+ if(!strncmp(p, "MASK:", 5)) {
+ if(!p[5]) return 0;
+ mask = strtoul(p + 5, &end, 0);
+ if(*end) return 0;
+ } else if(!strcmp(p, "nombstr"))
+ mask = ~((unsigned long)(B_ASN1_BMPSTRING|B_ASN1_UTF8STRING));
+ else if(!strcmp(p, "pkix"))
+ mask = ~((unsigned long)B_ASN1_T61STRING);
+ else if(!strcmp(p, "utf8only")) mask = B_ASN1_UTF8STRING;
+ else if(!strcmp(p, "default"))
+ mask = 0xFFFFFFFFL;
+ else return 0;
+ ASN1_STRING_set_default_mask(mask);
+ return 1;
+}
+
+/* The following function generates an ASN1_STRING based on limits in a table.
+ * Frequently the types and length of an ASN1_STRING are restricted by a
+ * corresponding OID. For example certificates and certificate requests.
+ */
+
+ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in,
+ int inlen, int inform, int nid)
+{
+ ASN1_STRING_TABLE *tbl;
+ ASN1_STRING *str = NULL;
+ unsigned long mask;
+ int ret;
+ if(!out) out = &str;
+ tbl = ASN1_STRING_TABLE_get(nid);
+ if(tbl) {
+ mask = tbl->mask;
+ if(!(tbl->flags & STABLE_NO_MASK)) mask &= global_mask;
+ ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask,
+ tbl->minsize, tbl->maxsize);
+ } else ret = ASN1_mbstring_copy(out, in, inlen, inform, DIRSTRING_TYPE & global_mask);
+ if(ret <= 0) return NULL;
+ return *out;
+}
+
+/* Now the tables and helper functions for the string table:
+ */
+
+/* size limits: this stuff is taken straight from RFC3280 */
+
+#define ub_name 32768
+#define ub_common_name 64
+#define ub_locality_name 128
+#define ub_state_name 128
+#define ub_organization_name 64
+#define ub_organization_unit_name 64
+#define ub_title 64
+#define ub_email_address 128
+#define ub_serial_number 64
+
+
+/* This table must be kept in NID order */
+
+static const ASN1_STRING_TABLE tbl_standard[] = {
+{NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0},
+{NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
+{NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0},
+{NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0},
+{NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0},
+{NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE, 0},
+{NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK},
+{NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0},
+{NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0},
+{NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0},
+{NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_surname, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_initials, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
+{NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
+{NID_name, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
+{NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK},
+{NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}
+};
+
+static int sk_table_cmp(const ASN1_STRING_TABLE * const *a,
+ const ASN1_STRING_TABLE * const *b)
+{
+ return (*a)->nid - (*b)->nid;
+}
+
+DECLARE_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
+
+static int table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b)
+{
+ return a->nid - b->nid;
+}
+
+IMPLEMENT_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
+
+ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
+{
+ int idx;
+ ASN1_STRING_TABLE *ttmp;
+ ASN1_STRING_TABLE fnd;
+ fnd.nid = nid;
+ ttmp = OBJ_bsearch_table(&fnd, tbl_standard,
+ sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE));
+ if(ttmp) return ttmp;
+ if(!stable) return NULL;
+ idx = sk_ASN1_STRING_TABLE_find(stable, &fnd);
+ if(idx < 0) return NULL;
+ return sk_ASN1_STRING_TABLE_value(stable, idx);
+}
+
+int ASN1_STRING_TABLE_add(int nid,
+ long minsize, long maxsize, unsigned long mask,
+ unsigned long flags)
+{
+ ASN1_STRING_TABLE *tmp;
+ char new_nid = 0;
+ flags &= ~STABLE_FLAGS_MALLOC;
+ if(!stable) stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp);
+ if(!stable) {
+ ASN1err(ASN1_F_ASN1_STRING_TABLE_ADD, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if(!(tmp = ASN1_STRING_TABLE_get(nid))) {
+ tmp = OPENSSL_malloc(sizeof(ASN1_STRING_TABLE));
+ if(!tmp) {
+ ASN1err(ASN1_F_ASN1_STRING_TABLE_ADD,
+ ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ tmp->flags = flags | STABLE_FLAGS_MALLOC;
+ tmp->nid = nid;
+ new_nid = 1;
+ } else tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags;
+ if(minsize != -1) tmp->minsize = minsize;
+ if(maxsize != -1) tmp->maxsize = maxsize;
+ tmp->mask = mask;
+ if(new_nid) sk_ASN1_STRING_TABLE_push(stable, tmp);
+ return 1;
+}
+
+void ASN1_STRING_TABLE_cleanup(void)
+{
+ STACK_OF(ASN1_STRING_TABLE) *tmp;
+ tmp = stable;
+ if(!tmp) return;
+ stable = NULL;
+ sk_ASN1_STRING_TABLE_pop_free(tmp, st_free);
+}
+
+static void st_free(ASN1_STRING_TABLE *tbl)
+{
+ if(tbl->flags & STABLE_FLAGS_MALLOC) OPENSSL_free(tbl);
+}
+
+
+IMPLEMENT_STACK_OF(ASN1_STRING_TABLE)
+
+#ifdef STRING_TABLE_TEST
+
+main()
+{
+ ASN1_STRING_TABLE *tmp;
+ int i, last_nid = -1;
+
+ for (tmp = tbl_standard, i = 0;
+ i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++)
+ {
+ if (tmp->nid < last_nid)
+ {
+ last_nid = 0;
+ break;
+ }
+ last_nid = tmp->nid;
+ }
+
+ if (last_nid != 0)
+ {
+ printf("Table order OK\n");
+ exit(0);
+ }
+
+ for (tmp = tbl_standard, i = 0;
+ i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++)
+ printf("Index %d, NID %d, Name=%s\n", i, tmp->nid,
+ OBJ_nid2ln(tmp->nid));
+
+}
+
+#endif
diff --git a/drivers/builtin_openssl/crypto/asn1/a_time.c b/drivers/builtin_openssl2/crypto/asn1/a_time.c
index e2eb9b243e..e2eb9b243e 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_time.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_time.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_type.c b/drivers/builtin_openssl2/crypto/asn1/a_type.c
index a45d2f9d12..a45d2f9d12 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_type.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_type.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_utctm.c b/drivers/builtin_openssl2/crypto/asn1/a_utctm.c
index 072e236592..072e236592 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_utctm.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_utctm.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_utf8.c b/drivers/builtin_openssl2/crypto/asn1/a_utf8.c
index 508e11e527..508e11e527 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_utf8.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_utf8.c
diff --git a/drivers/builtin_openssl/crypto/asn1/a_verify.c b/drivers/builtin_openssl2/crypto/asn1/a_verify.c
index fc84cd3d19..fc84cd3d19 100644
--- a/drivers/builtin_openssl/crypto/asn1/a_verify.c
+++ b/drivers/builtin_openssl2/crypto/asn1/a_verify.c
diff --git a/drivers/builtin_openssl/crypto/asn1/ameth_lib.c b/drivers/builtin_openssl2/crypto/asn1/ameth_lib.c
index a19e058fca..a19e058fca 100644
--- a/drivers/builtin_openssl/crypto/asn1/ameth_lib.c
+++ b/drivers/builtin_openssl2/crypto/asn1/ameth_lib.c
diff --git a/drivers/builtin_openssl/crypto/asn1/asn1_err.c b/drivers/builtin_openssl2/crypto/asn1/asn1_err.c
index aa60203ba8..aa60203ba8 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn1_err.c
+++ b/drivers/builtin_openssl2/crypto/asn1/asn1_err.c
diff --git a/drivers/builtin_openssl/crypto/asn1/asn1_gen.c b/drivers/builtin_openssl2/crypto/asn1/asn1_gen.c
index 4fc241908f..4fc241908f 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn1_gen.c
+++ b/drivers/builtin_openssl2/crypto/asn1/asn1_gen.c
diff --git a/drivers/builtin_openssl/crypto/asn1/asn1_lib.c b/drivers/builtin_openssl2/crypto/asn1/asn1_lib.c
index 1bcb44aee2..1bcb44aee2 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn1_lib.c
+++ b/drivers/builtin_openssl2/crypto/asn1/asn1_lib.c
diff --git a/drivers/builtin_openssl/crypto/asn1/asn1_locl.h b/drivers/builtin_openssl2/crypto/asn1/asn1_locl.h
index 9fcf0d9530..9fcf0d9530 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn1_locl.h
+++ b/drivers/builtin_openssl2/crypto/asn1/asn1_locl.h
diff --git a/drivers/builtin_openssl/crypto/asn1/asn1_par.c b/drivers/builtin_openssl2/crypto/asn1/asn1_par.c
index aaca69aebd..aaca69aebd 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn1_par.c
+++ b/drivers/builtin_openssl2/crypto/asn1/asn1_par.c
diff --git a/drivers/builtin_openssl/crypto/asn1/asn_mime.c b/drivers/builtin_openssl2/crypto/asn1/asn_mime.c
index 54a704a969..54a704a969 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn_mime.c
+++ b/drivers/builtin_openssl2/crypto/asn1/asn_mime.c
diff --git a/drivers/builtin_openssl/crypto/asn1/asn_moid.c b/drivers/builtin_openssl2/crypto/asn1/asn_moid.c
index 1ea6a59248..1ea6a59248 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn_moid.c
+++ b/drivers/builtin_openssl2/crypto/asn1/asn_moid.c
diff --git a/drivers/builtin_openssl/crypto/asn1/asn_pack.c b/drivers/builtin_openssl2/crypto/asn1/asn_pack.c
index ad738217d7..ad738217d7 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn_pack.c
+++ b/drivers/builtin_openssl2/crypto/asn1/asn_pack.c
diff --git a/drivers/builtin_openssl/crypto/asn1/bio_asn1.c b/drivers/builtin_openssl2/crypto/asn1/bio_asn1.c
index dc7efd551c..dc7efd551c 100644
--- a/drivers/builtin_openssl/crypto/asn1/bio_asn1.c
+++ b/drivers/builtin_openssl2/crypto/asn1/bio_asn1.c
diff --git a/drivers/builtin_openssl/crypto/asn1/bio_ndef.c b/drivers/builtin_openssl2/crypto/asn1/bio_ndef.c
index b91f97a1b1..b91f97a1b1 100644
--- a/drivers/builtin_openssl/crypto/asn1/bio_ndef.c
+++ b/drivers/builtin_openssl2/crypto/asn1/bio_ndef.c
diff --git a/drivers/builtin_openssl/crypto/asn1/charmap.h b/drivers/builtin_openssl2/crypto/asn1/charmap.h
index b55e638725..b55e638725 100644
--- a/drivers/builtin_openssl/crypto/asn1/charmap.h
+++ b/drivers/builtin_openssl2/crypto/asn1/charmap.h
diff --git a/drivers/builtin_openssl/crypto/asn1/charmap.pl b/drivers/builtin_openssl2/crypto/asn1/charmap.pl
index 2875c59867..2875c59867 100644
--- a/drivers/builtin_openssl/crypto/asn1/charmap.pl
+++ b/drivers/builtin_openssl2/crypto/asn1/charmap.pl
diff --git a/drivers/builtin_openssl/crypto/asn1/d2i_pr.c b/drivers/builtin_openssl2/crypto/asn1/d2i_pr.c
index 2828944777..2828944777 100644
--- a/drivers/builtin_openssl/crypto/asn1/d2i_pr.c
+++ b/drivers/builtin_openssl2/crypto/asn1/d2i_pr.c
diff --git a/drivers/builtin_openssl/crypto/asn1/d2i_pu.c b/drivers/builtin_openssl2/crypto/asn1/d2i_pu.c
index c8f39ceb03..c8f39ceb03 100644
--- a/drivers/builtin_openssl/crypto/asn1/d2i_pu.c
+++ b/drivers/builtin_openssl2/crypto/asn1/d2i_pu.c
diff --git a/drivers/builtin_openssl/crypto/asn1/evp_asn1.c b/drivers/builtin_openssl2/crypto/asn1/evp_asn1.c
index f3d9804860..f3d9804860 100644
--- a/drivers/builtin_openssl/crypto/asn1/evp_asn1.c
+++ b/drivers/builtin_openssl2/crypto/asn1/evp_asn1.c
diff --git a/drivers/builtin_openssl/crypto/asn1/f_enum.c b/drivers/builtin_openssl2/crypto/asn1/f_enum.c
index 56e3cc8df2..56e3cc8df2 100644
--- a/drivers/builtin_openssl/crypto/asn1/f_enum.c
+++ b/drivers/builtin_openssl2/crypto/asn1/f_enum.c
diff --git a/drivers/builtin_openssl/crypto/asn1/f_int.c b/drivers/builtin_openssl2/crypto/asn1/f_int.c
index 9494e597ab..9494e597ab 100644
--- a/drivers/builtin_openssl/crypto/asn1/f_int.c
+++ b/drivers/builtin_openssl2/crypto/asn1/f_int.c
diff --git a/drivers/builtin_openssl/crypto/asn1/f_string.c b/drivers/builtin_openssl2/crypto/asn1/f_string.c
index 968698a798..968698a798 100644
--- a/drivers/builtin_openssl/crypto/asn1/f_string.c
+++ b/drivers/builtin_openssl2/crypto/asn1/f_string.c
diff --git a/drivers/builtin_openssl/crypto/asn1/i2d_pr.c b/drivers/builtin_openssl2/crypto/asn1/i2d_pr.c
index e398b62666..e398b62666 100644
--- a/drivers/builtin_openssl/crypto/asn1/i2d_pr.c
+++ b/drivers/builtin_openssl2/crypto/asn1/i2d_pr.c
diff --git a/drivers/builtin_openssl/crypto/asn1/i2d_pu.c b/drivers/builtin_openssl2/crypto/asn1/i2d_pu.c
index 34286dbd35..34286dbd35 100644
--- a/drivers/builtin_openssl/crypto/asn1/i2d_pu.c
+++ b/drivers/builtin_openssl2/crypto/asn1/i2d_pu.c
diff --git a/drivers/builtin_openssl/crypto/asn1/n_pkey.c b/drivers/builtin_openssl2/crypto/asn1/n_pkey.c
index e251739933..e251739933 100644
--- a/drivers/builtin_openssl/crypto/asn1/n_pkey.c
+++ b/drivers/builtin_openssl2/crypto/asn1/n_pkey.c
diff --git a/drivers/builtin_openssl/crypto/asn1/nsseq.c b/drivers/builtin_openssl2/crypto/asn1/nsseq.c
index b8c4202230..b8c4202230 100644
--- a/drivers/builtin_openssl/crypto/asn1/nsseq.c
+++ b/drivers/builtin_openssl2/crypto/asn1/nsseq.c
diff --git a/drivers/builtin_openssl/crypto/asn1/p5_pbe.c b/drivers/builtin_openssl2/crypto/asn1/p5_pbe.c
index 94bc38b99f..94bc38b99f 100644
--- a/drivers/builtin_openssl/crypto/asn1/p5_pbe.c
+++ b/drivers/builtin_openssl2/crypto/asn1/p5_pbe.c
diff --git a/drivers/builtin_openssl/crypto/asn1/p5_pbev2.c b/drivers/builtin_openssl2/crypto/asn1/p5_pbev2.c
index 4ea683036b..4ea683036b 100644
--- a/drivers/builtin_openssl/crypto/asn1/p5_pbev2.c
+++ b/drivers/builtin_openssl2/crypto/asn1/p5_pbev2.c
diff --git a/drivers/builtin_openssl/crypto/asn1/p8_pkey.c b/drivers/builtin_openssl2/crypto/asn1/p8_pkey.c
index 17b68d386d..17b68d386d 100644
--- a/drivers/builtin_openssl/crypto/asn1/p8_pkey.c
+++ b/drivers/builtin_openssl2/crypto/asn1/p8_pkey.c
diff --git a/drivers/builtin_openssl/crypto/asn1/t_bitst.c b/drivers/builtin_openssl2/crypto/asn1/t_bitst.c
index 2e59a25fa1..2e59a25fa1 100644
--- a/drivers/builtin_openssl/crypto/asn1/t_bitst.c
+++ b/drivers/builtin_openssl2/crypto/asn1/t_bitst.c
diff --git a/drivers/builtin_openssl/crypto/asn1/t_crl.c b/drivers/builtin_openssl2/crypto/asn1/t_crl.c
index c61169208a..c61169208a 100644
--- a/drivers/builtin_openssl/crypto/asn1/t_crl.c
+++ b/drivers/builtin_openssl2/crypto/asn1/t_crl.c
diff --git a/drivers/builtin_openssl/crypto/asn1/t_pkey.c b/drivers/builtin_openssl2/crypto/asn1/t_pkey.c
index 9dd18f6579..9dd18f6579 100644
--- a/drivers/builtin_openssl/crypto/asn1/t_pkey.c
+++ b/drivers/builtin_openssl2/crypto/asn1/t_pkey.c
diff --git a/drivers/builtin_openssl/crypto/asn1/t_req.c b/drivers/builtin_openssl2/crypto/asn1/t_req.c
index ea1794e3e0..ea1794e3e0 100644
--- a/drivers/builtin_openssl/crypto/asn1/t_req.c
+++ b/drivers/builtin_openssl2/crypto/asn1/t_req.c
diff --git a/drivers/builtin_openssl/crypto/asn1/t_spki.c b/drivers/builtin_openssl2/crypto/asn1/t_spki.c
index 079c081a81..079c081a81 100644
--- a/drivers/builtin_openssl/crypto/asn1/t_spki.c
+++ b/drivers/builtin_openssl2/crypto/asn1/t_spki.c
diff --git a/drivers/builtin_openssl/crypto/asn1/t_x509.c b/drivers/builtin_openssl2/crypto/asn1/t_x509.c
index edbb39a02f..edbb39a02f 100644
--- a/drivers/builtin_openssl/crypto/asn1/t_x509.c
+++ b/drivers/builtin_openssl2/crypto/asn1/t_x509.c
diff --git a/drivers/builtin_openssl/crypto/asn1/t_x509a.c b/drivers/builtin_openssl2/crypto/asn1/t_x509a.c
index 8b18801a17..8b18801a17 100644
--- a/drivers/builtin_openssl/crypto/asn1/t_x509a.c
+++ b/drivers/builtin_openssl2/crypto/asn1/t_x509a.c
diff --git a/drivers/builtin_openssl/crypto/asn1/tasn_dec.c b/drivers/builtin_openssl2/crypto/asn1/tasn_dec.c
index 87d7dfdf5c..87d7dfdf5c 100644
--- a/drivers/builtin_openssl/crypto/asn1/tasn_dec.c
+++ b/drivers/builtin_openssl2/crypto/asn1/tasn_dec.c
diff --git a/drivers/builtin_openssl/crypto/asn1/tasn_enc.c b/drivers/builtin_openssl2/crypto/asn1/tasn_enc.c
index 936ad1f767..936ad1f767 100644
--- a/drivers/builtin_openssl/crypto/asn1/tasn_enc.c
+++ b/drivers/builtin_openssl2/crypto/asn1/tasn_enc.c
diff --git a/drivers/builtin_openssl/crypto/asn1/tasn_fre.c b/drivers/builtin_openssl2/crypto/asn1/tasn_fre.c
index 77d3092d31..77d3092d31 100644
--- a/drivers/builtin_openssl/crypto/asn1/tasn_fre.c
+++ b/drivers/builtin_openssl2/crypto/asn1/tasn_fre.c
diff --git a/drivers/builtin_openssl/crypto/asn1/tasn_new.c b/drivers/builtin_openssl2/crypto/asn1/tasn_new.c
index 0d9e78cc7c..0d9e78cc7c 100644
--- a/drivers/builtin_openssl/crypto/asn1/tasn_new.c
+++ b/drivers/builtin_openssl2/crypto/asn1/tasn_new.c
diff --git a/drivers/builtin_openssl/crypto/asn1/tasn_prn.c b/drivers/builtin_openssl2/crypto/asn1/tasn_prn.c
index 542a091a66..542a091a66 100644
--- a/drivers/builtin_openssl/crypto/asn1/tasn_prn.c
+++ b/drivers/builtin_openssl2/crypto/asn1/tasn_prn.c
diff --git a/drivers/builtin_openssl/crypto/asn1/tasn_typ.c b/drivers/builtin_openssl2/crypto/asn1/tasn_typ.c
index 6fb1c372da..6fb1c372da 100644
--- a/drivers/builtin_openssl/crypto/asn1/tasn_typ.c
+++ b/drivers/builtin_openssl2/crypto/asn1/tasn_typ.c
diff --git a/drivers/builtin_openssl/crypto/asn1/tasn_utl.c b/drivers/builtin_openssl2/crypto/asn1/tasn_utl.c
index ca9ec7a32f..ca9ec7a32f 100644
--- a/drivers/builtin_openssl/crypto/asn1/tasn_utl.c
+++ b/drivers/builtin_openssl2/crypto/asn1/tasn_utl.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_algor.c b/drivers/builtin_openssl2/crypto/asn1/x_algor.c
index 274e456c73..274e456c73 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_algor.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_algor.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_attrib.c b/drivers/builtin_openssl2/crypto/asn1/x_attrib.c
index 1e3713f18f..1e3713f18f 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_attrib.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_attrib.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_bignum.c b/drivers/builtin_openssl2/crypto/asn1/x_bignum.c
index 9cf3204a1b..9cf3204a1b 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_bignum.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_bignum.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_crl.c b/drivers/builtin_openssl2/crypto/asn1/x_crl.c
index c51c690ba9..c51c690ba9 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_crl.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_crl.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_exten.c b/drivers/builtin_openssl2/crypto/asn1/x_exten.c
index 3a21239926..3a21239926 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_exten.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_exten.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_info.c b/drivers/builtin_openssl2/crypto/asn1/x_info.c
index d44f6cdb01..d44f6cdb01 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_info.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_info.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_long.c b/drivers/builtin_openssl2/crypto/asn1/x_long.c
index 75317418e1..75317418e1 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_long.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_long.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_name.c b/drivers/builtin_openssl2/crypto/asn1/x_name.c
index d7c2318693..d7c2318693 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_name.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_name.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_nx509.c b/drivers/builtin_openssl2/crypto/asn1/x_nx509.c
index fbd9a22db3..fbd9a22db3 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_nx509.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_nx509.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_pkey.c b/drivers/builtin_openssl2/crypto/asn1/x_pkey.c
index 8453618426..8453618426 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_pkey.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_pkey.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_pubkey.c b/drivers/builtin_openssl2/crypto/asn1/x_pubkey.c
index b649e1fcf9..b649e1fcf9 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_pubkey.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_pubkey.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_req.c b/drivers/builtin_openssl2/crypto/asn1/x_req.c
index d57555827c..d57555827c 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_req.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_req.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_sig.c b/drivers/builtin_openssl2/crypto/asn1/x_sig.c
index 42efa86c1c..42efa86c1c 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_sig.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_sig.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_spki.c b/drivers/builtin_openssl2/crypto/asn1/x_spki.c
index 2aece077c5..2aece077c5 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_spki.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_spki.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_val.c b/drivers/builtin_openssl2/crypto/asn1/x_val.c
index dc17c67758..dc17c67758 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_val.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_val.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_x509.c b/drivers/builtin_openssl2/crypto/asn1/x_x509.c
index de3df9eb51..de3df9eb51 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_x509.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_x509.c
diff --git a/drivers/builtin_openssl/crypto/asn1/x_x509a.c b/drivers/builtin_openssl2/crypto/asn1/x_x509a.c
index b603f82de7..b603f82de7 100644
--- a/drivers/builtin_openssl/crypto/asn1/x_x509a.c
+++ b/drivers/builtin_openssl2/crypto/asn1/x_x509a.c
diff --git a/drivers/builtin_openssl/crypto/bf/COPYRIGHT b/drivers/builtin_openssl2/crypto/bf/COPYRIGHT
index 6857223506..6857223506 100644
--- a/drivers/builtin_openssl/crypto/bf/COPYRIGHT
+++ b/drivers/builtin_openssl2/crypto/bf/COPYRIGHT
diff --git a/drivers/builtin_openssl/crypto/bf/INSTALL b/drivers/builtin_openssl2/crypto/bf/INSTALL
index 3b25923532..3b25923532 100644
--- a/drivers/builtin_openssl/crypto/bf/INSTALL
+++ b/drivers/builtin_openssl2/crypto/bf/INSTALL
diff --git a/drivers/builtin_openssl/crypto/bf/README b/drivers/builtin_openssl2/crypto/bf/README
index f2712fd0e7..f2712fd0e7 100644
--- a/drivers/builtin_openssl/crypto/bf/README
+++ b/drivers/builtin_openssl2/crypto/bf/README
diff --git a/drivers/builtin_openssl/crypto/bf/VERSION b/drivers/builtin_openssl2/crypto/bf/VERSION
index be995855e4..be995855e4 100644
--- a/drivers/builtin_openssl/crypto/bf/VERSION
+++ b/drivers/builtin_openssl2/crypto/bf/VERSION
diff --git a/drivers/builtin_openssl/crypto/bf/asm/bf-586.pl b/drivers/builtin_openssl2/crypto/bf/asm/bf-586.pl
index b74cfbafd4..b74cfbafd4 100644
--- a/drivers/builtin_openssl/crypto/bf/asm/bf-586.pl
+++ b/drivers/builtin_openssl2/crypto/bf/asm/bf-586.pl
diff --git a/drivers/builtin_openssl/crypto/bf/asm/bf-686.pl b/drivers/builtin_openssl2/crypto/bf/asm/bf-686.pl
index 8e4c25f598..8e4c25f598 100644
--- a/drivers/builtin_openssl/crypto/bf/asm/bf-686.pl
+++ b/drivers/builtin_openssl2/crypto/bf/asm/bf-686.pl
diff --git a/drivers/builtin_openssl/crypto/bf/asm/readme b/drivers/builtin_openssl2/crypto/bf/asm/readme
index 2385fa3812..2385fa3812 100644
--- a/drivers/builtin_openssl/crypto/bf/asm/readme
+++ b/drivers/builtin_openssl2/crypto/bf/asm/readme
diff --git a/drivers/builtin_openssl/crypto/bf/bf_cbc.c b/drivers/builtin_openssl2/crypto/bf/bf_cbc.c
index f949629dc6..f949629dc6 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_cbc.c
+++ b/drivers/builtin_openssl2/crypto/bf/bf_cbc.c
diff --git a/drivers/builtin_openssl/crypto/bf/bf_cfb64.c b/drivers/builtin_openssl2/crypto/bf/bf_cfb64.c
index 6451c8d407..6451c8d407 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_cfb64.c
+++ b/drivers/builtin_openssl2/crypto/bf/bf_cfb64.c
diff --git a/drivers/builtin_openssl/crypto/bf/bf_ecb.c b/drivers/builtin_openssl2/crypto/bf/bf_ecb.c
index 1607cefa32..1607cefa32 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_ecb.c
+++ b/drivers/builtin_openssl2/crypto/bf/bf_ecb.c
diff --git a/drivers/builtin_openssl/crypto/bf/bf_enc.c b/drivers/builtin_openssl2/crypto/bf/bf_enc.c
index 2d21d09f42..2d21d09f42 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_enc.c
+++ b/drivers/builtin_openssl2/crypto/bf/bf_enc.c
diff --git a/drivers/builtin_openssl/crypto/bf/bf_locl.h b/drivers/builtin_openssl2/crypto/bf/bf_locl.h
index cc7c3ec992..cc7c3ec992 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_locl.h
+++ b/drivers/builtin_openssl2/crypto/bf/bf_locl.h
diff --git a/drivers/builtin_openssl/crypto/bf/bf_ofb64.c b/drivers/builtin_openssl2/crypto/bf/bf_ofb64.c
index f2a9ff6e41..f2a9ff6e41 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_ofb64.c
+++ b/drivers/builtin_openssl2/crypto/bf/bf_ofb64.c
diff --git a/drivers/builtin_openssl/crypto/bf/bf_opts.c b/drivers/builtin_openssl2/crypto/bf/bf_opts.c
index 1721bb99b4..1721bb99b4 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_opts.c
+++ b/drivers/builtin_openssl2/crypto/bf/bf_opts.c
diff --git a/drivers/builtin_openssl/crypto/bf/bf_pi.h b/drivers/builtin_openssl2/crypto/bf/bf_pi.h
index 9949513c68..9949513c68 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_pi.h
+++ b/drivers/builtin_openssl2/crypto/bf/bf_pi.h
diff --git a/drivers/builtin_openssl/crypto/bf/bf_skey.c b/drivers/builtin_openssl2/crypto/bf/bf_skey.c
index 3b0bca41ae..3b0bca41ae 100644
--- a/drivers/builtin_openssl/crypto/bf/bf_skey.c
+++ b/drivers/builtin_openssl2/crypto/bf/bf_skey.c
diff --git a/drivers/builtin_openssl/crypto/bf/bfs.cpp b/drivers/builtin_openssl2/crypto/bf/bfs.cpp
index d74c457760..d74c457760 100644
--- a/drivers/builtin_openssl/crypto/bf/bfs.cpp
+++ b/drivers/builtin_openssl2/crypto/bf/bfs.cpp
diff --git a/drivers/builtin_openssl/crypto/bf/bfspeed.c b/drivers/builtin_openssl2/crypto/bf/bfspeed.c
index c41ef3b403..c41ef3b403 100644
--- a/drivers/builtin_openssl/crypto/bf/bfspeed.c
+++ b/drivers/builtin_openssl2/crypto/bf/bfspeed.c
diff --git a/drivers/builtin_openssl/crypto/bf/bftest.c b/drivers/builtin_openssl2/crypto/bf/bftest.c
index 97e6634d37..97e6634d37 100644
--- a/drivers/builtin_openssl/crypto/bf/bftest.c
+++ b/drivers/builtin_openssl2/crypto/bf/bftest.c
diff --git a/drivers/builtin_openssl/crypto/bio/b_dump.c b/drivers/builtin_openssl2/crypto/bio/b_dump.c
index c80ecc4295..c80ecc4295 100644
--- a/drivers/builtin_openssl/crypto/bio/b_dump.c
+++ b/drivers/builtin_openssl2/crypto/bio/b_dump.c
diff --git a/drivers/builtin_openssl/crypto/bio/b_print.c b/drivers/builtin_openssl2/crypto/bio/b_print.c
index 143a7cfefa..143a7cfefa 100644
--- a/drivers/builtin_openssl/crypto/bio/b_print.c
+++ b/drivers/builtin_openssl2/crypto/bio/b_print.c
diff --git a/drivers/builtin_openssl/crypto/bio/b_sock.c b/drivers/builtin_openssl2/crypto/bio/b_sock.c
index 41f958be71..41f958be71 100644
--- a/drivers/builtin_openssl/crypto/bio/b_sock.c
+++ b/drivers/builtin_openssl2/crypto/bio/b_sock.c
diff --git a/drivers/builtin_openssl/crypto/bio/bf_buff.c b/drivers/builtin_openssl2/crypto/bio/bf_buff.c
index 4b5a132d8a..4b5a132d8a 100644
--- a/drivers/builtin_openssl/crypto/bio/bf_buff.c
+++ b/drivers/builtin_openssl2/crypto/bio/bf_buff.c
diff --git a/drivers/builtin_openssl/crypto/bio/bf_lbuf.c b/drivers/builtin_openssl2/crypto/bio/bf_lbuf.c
index ec0f7eb0b7..ec0f7eb0b7 100644
--- a/drivers/builtin_openssl/crypto/bio/bf_lbuf.c
+++ b/drivers/builtin_openssl2/crypto/bio/bf_lbuf.c
diff --git a/drivers/builtin_openssl/crypto/bio/bf_nbio.c b/drivers/builtin_openssl2/crypto/bio/bf_nbio.c
index 028616c064..028616c064 100644
--- a/drivers/builtin_openssl/crypto/bio/bf_nbio.c
+++ b/drivers/builtin_openssl2/crypto/bio/bf_nbio.c
diff --git a/drivers/builtin_openssl/crypto/bio/bf_null.c b/drivers/builtin_openssl2/crypto/bio/bf_null.c
index c1bf39a904..c1bf39a904 100644
--- a/drivers/builtin_openssl/crypto/bio/bf_null.c
+++ b/drivers/builtin_openssl2/crypto/bio/bf_null.c
diff --git a/drivers/builtin_openssl/crypto/bio/bio_cb.c b/drivers/builtin_openssl2/crypto/bio/bio_cb.c
index 9bcbc321d9..9bcbc321d9 100644
--- a/drivers/builtin_openssl/crypto/bio/bio_cb.c
+++ b/drivers/builtin_openssl2/crypto/bio/bio_cb.c
diff --git a/drivers/builtin_openssl/crypto/bio/bio_err.c b/drivers/builtin_openssl2/crypto/bio/bio_err.c
index 0dbfbd80d3..0dbfbd80d3 100644
--- a/drivers/builtin_openssl/crypto/bio/bio_err.c
+++ b/drivers/builtin_openssl2/crypto/bio/bio_err.c
diff --git a/drivers/builtin_openssl/crypto/bio/bio_lcl.h b/drivers/builtin_openssl2/crypto/bio/bio_lcl.h
index e7f7ec8d8b..e7f7ec8d8b 100644
--- a/drivers/builtin_openssl/crypto/bio/bio_lcl.h
+++ b/drivers/builtin_openssl2/crypto/bio/bio_lcl.h
diff --git a/drivers/builtin_openssl/crypto/bio/bio_lib.c b/drivers/builtin_openssl2/crypto/bio/bio_lib.c
index 9c9646afa8..9c9646afa8 100644
--- a/drivers/builtin_openssl/crypto/bio/bio_lib.c
+++ b/drivers/builtin_openssl2/crypto/bio/bio_lib.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_acpt.c b/drivers/builtin_openssl2/crypto/bio/bss_acpt.c
index 5d49e1a72b..5d49e1a72b 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_acpt.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_acpt.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_bio.c b/drivers/builtin_openssl2/crypto/bio/bss_bio.c
index 52ef0ebcb3..52ef0ebcb3 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_bio.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_bio.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_conn.c b/drivers/builtin_openssl2/crypto/bio/bss_conn.c
index c14727855b..c14727855b 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_conn.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_conn.c
diff --git a/drivers/builtin_openssl2/crypto/bio/bss_dgram.c b/drivers/builtin_openssl2/crypto/bio/bss_dgram.c
new file mode 100644
index 0000000000..d9967e7272
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/bio/bss_dgram.c
@@ -0,0 +1,1872 @@
+/* crypto/bio/bio_dgram.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#define USE_SOCKETS
+#include "cryptlib.h"
+
+#include <openssl/bio.h>
+#ifndef OPENSSL_NO_DGRAM
+
+#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS)
+#include <sys/timeb.h>
+#endif
+
+#ifndef OPENSSL_NO_SCTP
+#include <netinet/sctp.h>
+#include <fcntl.h>
+#define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00
+#define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0
+#endif
+
+#if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU)
+#define IP_MTU 14 /* linux is lame */
+#endif
+
+#if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED)
+/* Standard definition causes type-punning problems. */
+#undef IN6_IS_ADDR_V4MAPPED
+#define s6_addr32 __u6_addr.__u6_addr32
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == htonl(0x0000ffff)))
+#endif
+
+#ifdef WATT32
+#define sock_write SockWrite /* Watt-32 uses same names */
+#define sock_read SockRead
+#define sock_puts SockPuts
+#endif
+
+static int dgram_write(BIO *h, const char *buf, int num);
+static int dgram_read(BIO *h, char *buf, int size);
+static int dgram_puts(BIO *h, const char *str);
+static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2);
+static int dgram_new(BIO *h);
+static int dgram_free(BIO *data);
+static int dgram_clear(BIO *bio);
+
+#ifndef OPENSSL_NO_SCTP
+static int dgram_sctp_write(BIO *h, const char *buf, int num);
+static int dgram_sctp_read(BIO *h, char *buf, int size);
+static int dgram_sctp_puts(BIO *h, const char *str);
+static long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2);
+static int dgram_sctp_new(BIO *h);
+static int dgram_sctp_free(BIO *data);
+#ifdef SCTP_AUTHENTICATION_EVENT
+static void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp);
+#endif
+#endif
+
+static int BIO_dgram_should_retry(int s);
+
+static void get_current_time(struct timeval *t);
+
+static BIO_METHOD methods_dgramp=
+ {
+ BIO_TYPE_DGRAM,
+ "datagram socket",
+ dgram_write,
+ dgram_read,
+ dgram_puts,
+ NULL, /* dgram_gets, */
+ dgram_ctrl,
+ dgram_new,
+ dgram_free,
+ NULL,
+ };
+
+#ifndef OPENSSL_NO_SCTP
+static BIO_METHOD methods_dgramp_sctp=
+ {
+ BIO_TYPE_DGRAM_SCTP,
+ "datagram sctp socket",
+ dgram_sctp_write,
+ dgram_sctp_read,
+ dgram_sctp_puts,
+ NULL, /* dgram_gets, */
+ dgram_sctp_ctrl,
+ dgram_sctp_new,
+ dgram_sctp_free,
+ NULL,
+ };
+#endif
+
+typedef struct bio_dgram_data_st
+ {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in;
+#if OPENSSL_USE_IPV6
+ struct sockaddr_in6 sa_in6;
+#endif
+ } peer;
+ unsigned int connected;
+ unsigned int _errno;
+ unsigned int mtu;
+ struct timeval next_timeout;
+ struct timeval socket_timeout;
+ } bio_dgram_data;
+
+#ifndef OPENSSL_NO_SCTP
+typedef struct bio_dgram_sctp_save_message_st
+ {
+ BIO *bio;
+ char *data;
+ int length;
+ } bio_dgram_sctp_save_message;
+
+typedef struct bio_dgram_sctp_data_st
+ {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in;
+#if OPENSSL_USE_IPV6
+ struct sockaddr_in6 sa_in6;
+#endif
+ } peer;
+ unsigned int connected;
+ unsigned int _errno;
+ unsigned int mtu;
+ struct bio_dgram_sctp_sndinfo sndinfo;
+ struct bio_dgram_sctp_rcvinfo rcvinfo;
+ struct bio_dgram_sctp_prinfo prinfo;
+ void (*handle_notifications)(BIO *bio, void *context, void *buf);
+ void* notification_context;
+ int in_handshake;
+ int ccs_rcvd;
+ int ccs_sent;
+ int save_shutdown;
+ int peer_auth_tested;
+ bio_dgram_sctp_save_message saved_message;
+ } bio_dgram_sctp_data;
+#endif
+
+BIO_METHOD *BIO_s_datagram(void)
+ {
+ return(&methods_dgramp);
+ }
+
+BIO *BIO_new_dgram(int fd, int close_flag)
+ {
+ BIO *ret;
+
+ ret=BIO_new(BIO_s_datagram());
+ if (ret == NULL) return(NULL);
+ BIO_set_fd(ret,fd,close_flag);
+ return(ret);
+ }
+
+static int dgram_new(BIO *bi)
+ {
+ bio_dgram_data *data = NULL;
+
+ bi->init=0;
+ bi->num=0;
+ data = OPENSSL_malloc(sizeof(bio_dgram_data));
+ if (data == NULL)
+ return 0;
+ memset(data, 0x00, sizeof(bio_dgram_data));
+ bi->ptr = data;
+
+ bi->flags=0;
+ return(1);
+ }
+
+static int dgram_free(BIO *a)
+ {
+ bio_dgram_data *data;
+
+ if (a == NULL) return(0);
+ if ( ! dgram_clear(a))
+ return 0;
+
+ data = (bio_dgram_data *)a->ptr;
+ if(data != NULL) OPENSSL_free(data);
+
+ return(1);
+ }
+
+static int dgram_clear(BIO *a)
+ {
+ if (a == NULL) return(0);
+ if (a->shutdown)
+ {
+ if (a->init)
+ {
+ SHUTDOWN2(a->num);
+ }
+ a->init=0;
+ a->flags=0;
+ }
+ return(1);
+ }
+
+static void dgram_adjust_rcv_timeout(BIO *b)
+ {
+#if defined(SO_RCVTIMEO)
+ bio_dgram_data *data = (bio_dgram_data *)b->ptr;
+ union { size_t s; int i; } sz = {0};
+
+ /* Is a timer active? */
+ if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0)
+ {
+ struct timeval timenow, timeleft;
+
+ /* Read current socket timeout */
+#ifdef OPENSSL_SYS_WINDOWS
+ int timeout;
+
+ sz.i = sizeof(timeout);
+ if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
+ (void*)&timeout, &sz.i) < 0)
+ { perror("getsockopt"); }
+ else
+ {
+ data->socket_timeout.tv_sec = timeout / 1000;
+ data->socket_timeout.tv_usec = (timeout % 1000) * 1000;
+ }
+#else
+ sz.i = sizeof(data->socket_timeout);
+ if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
+ &(data->socket_timeout), (void *)&sz) < 0)
+ { perror("getsockopt"); }
+ else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
+ OPENSSL_assert(sz.s<=sizeof(data->socket_timeout));
+#endif
+
+ /* Get current time */
+ get_current_time(&timenow);
+
+ /* Calculate time left until timer expires */
+ memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval));
+ timeleft.tv_sec -= timenow.tv_sec;
+ timeleft.tv_usec -= timenow.tv_usec;
+ if (timeleft.tv_usec < 0)
+ {
+ timeleft.tv_sec--;
+ timeleft.tv_usec += 1000000;
+ }
+
+ if (timeleft.tv_sec < 0)
+ {
+ timeleft.tv_sec = 0;
+ timeleft.tv_usec = 1;
+ }
+
+ /* Adjust socket timeout if next handhake message timer
+ * will expire earlier.
+ */
+ if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) ||
+ (data->socket_timeout.tv_sec > timeleft.tv_sec) ||
+ (data->socket_timeout.tv_sec == timeleft.tv_sec &&
+ data->socket_timeout.tv_usec >= timeleft.tv_usec))
+ {
+#ifdef OPENSSL_SYS_WINDOWS
+ timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000;
+ if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
+ (void*)&timeout, sizeof(timeout)) < 0)
+ { perror("setsockopt"); }
+#else
+ if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft,
+ sizeof(struct timeval)) < 0)
+ { perror("setsockopt"); }
+#endif
+ }
+ }
+#endif
+ }
+
+static void dgram_reset_rcv_timeout(BIO *b)
+ {
+#if defined(SO_RCVTIMEO)
+ bio_dgram_data *data = (bio_dgram_data *)b->ptr;
+
+ /* Is a timer active? */
+ if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0)
+ {
+#ifdef OPENSSL_SYS_WINDOWS
+ int timeout = data->socket_timeout.tv_sec * 1000 +
+ data->socket_timeout.tv_usec / 1000;
+ if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
+ (void*)&timeout, sizeof(timeout)) < 0)
+ { perror("setsockopt"); }
+#else
+ if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout),
+ sizeof(struct timeval)) < 0)
+ { perror("setsockopt"); }
+#endif
+ }
+#endif
+ }
+
+static int dgram_read(BIO *b, char *out, int outl)
+ {
+ int ret=0;
+ bio_dgram_data *data = (bio_dgram_data *)b->ptr;
+
+ struct {
+ /*
+ * See commentary in b_sock.c. <appro>
+ */
+ union { size_t s; int i; } len;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in;
+#if OPENSSL_USE_IPV6
+ struct sockaddr_in6 sa_in6;
+#endif
+ } peer;
+ } sa;
+
+ sa.len.s=0;
+ sa.len.i=sizeof(sa.peer);
+
+ if (out != NULL)
+ {
+ clear_socket_error();
+ memset(&sa.peer, 0x00, sizeof(sa.peer));
+ dgram_adjust_rcv_timeout(b);
+ ret=recvfrom(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len);
+ if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0)
+ {
+ OPENSSL_assert(sa.len.s<=sizeof(sa.peer));
+ sa.len.i = (int)sa.len.s;
+ }
+
+ if ( ! data->connected && ret >= 0)
+ BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer);
+
+ BIO_clear_retry_flags(b);
+ if (ret < 0)
+ {
+ if (BIO_dgram_should_retry(ret))
+ {
+ BIO_set_retry_read(b);
+ data->_errno = get_last_socket_error();
+ }
+ }
+
+ dgram_reset_rcv_timeout(b);
+ }
+ return(ret);
+ }
+
+static int dgram_write(BIO *b, const char *in, int inl)
+ {
+ int ret;
+ bio_dgram_data *data = (bio_dgram_data *)b->ptr;
+ clear_socket_error();
+
+ if ( data->connected )
+ ret=writesocket(b->num,in,inl);
+ else
+ {
+ int peerlen = sizeof(data->peer);
+
+ if (data->peer.sa.sa_family == AF_INET)
+ peerlen = sizeof(data->peer.sa_in);
+#if OPENSSL_USE_IPV6
+ else if (data->peer.sa.sa_family == AF_INET6)
+ peerlen = sizeof(data->peer.sa_in6);
+#endif
+#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
+ ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen);
+#else
+ ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen);
+#endif
+ }
+
+ BIO_clear_retry_flags(b);
+ if (ret <= 0)
+ {
+ if (BIO_dgram_should_retry(ret))
+ {
+ BIO_set_retry_write(b);
+ data->_errno = get_last_socket_error();
+
+#if 0 /* higher layers are responsible for querying MTU, if necessary */
+ if ( data->_errno == EMSGSIZE)
+ /* retrieve the new MTU */
+ BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+#endif
+ }
+ }
+ return(ret);
+ }
+
+static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
+ {
+ long ret=1;
+ int *ip;
+ struct sockaddr *to = NULL;
+ bio_dgram_data *data = NULL;
+#if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
+ int sockopt_val = 0;
+ socklen_t sockopt_len; /* assume that system supporting IP_MTU is
+ * modern enough to define socklen_t */
+ socklen_t addr_len;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in s4;
+#if OPENSSL_USE_IPV6
+ struct sockaddr_in6 s6;
+#endif
+ } addr;
+#endif
+
+ data = (bio_dgram_data *)b->ptr;
+
+ switch (cmd)
+ {
+ case BIO_CTRL_RESET:
+ num=0;
+ case BIO_C_FILE_SEEK:
+ ret=0;
+ break;
+ case BIO_C_FILE_TELL:
+ case BIO_CTRL_INFO:
+ ret=0;
+ break;
+ case BIO_C_SET_FD:
+ dgram_clear(b);
+ b->num= *((int *)ptr);
+ b->shutdown=(int)num;
+ b->init=1;
+ break;
+ case BIO_C_GET_FD:
+ if (b->init)
+ {
+ ip=(int *)ptr;
+ if (ip != NULL) *ip=b->num;
+ ret=b->num;
+ }
+ else
+ ret= -1;
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret=b->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ b->shutdown=(int)num;
+ break;
+ case BIO_CTRL_PENDING:
+ case BIO_CTRL_WPENDING:
+ ret=0;
+ break;
+ case BIO_CTRL_DUP:
+ case BIO_CTRL_FLUSH:
+ ret=1;
+ break;
+ case BIO_CTRL_DGRAM_CONNECT:
+ to = (struct sockaddr *)ptr;
+#if 0
+ if (connect(b->num, to, sizeof(struct sockaddr)) < 0)
+ { perror("connect"); ret = 0; }
+ else
+ {
+#endif
+ switch (to->sa_family)
+ {
+ case AF_INET:
+ memcpy(&data->peer,to,sizeof(data->peer.sa_in));
+ break;
+#if OPENSSL_USE_IPV6
+ case AF_INET6:
+ memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
+ break;
+#endif
+ default:
+ memcpy(&data->peer,to,sizeof(data->peer.sa));
+ break;
+ }
+#if 0
+ }
+#endif
+ break;
+ /* (Linux)kernel sets DF bit on outgoing IP packets */
+ case BIO_CTRL_DGRAM_MTU_DISCOVER:
+#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
+ addr_len = (socklen_t)sizeof(addr);
+ memset((void *)&addr, 0, sizeof(addr));
+ if (getsockname(b->num, &addr.sa, &addr_len) < 0)
+ {
+ ret = 0;
+ break;
+ }
+ switch (addr.sa.sa_family)
+ {
+ case AF_INET:
+ sockopt_val = IP_PMTUDISC_DO;
+ if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
+ &sockopt_val, sizeof(sockopt_val))) < 0)
+ perror("setsockopt");
+ break;
+#if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
+ case AF_INET6:
+ sockopt_val = IPV6_PMTUDISC_DO;
+ if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
+ &sockopt_val, sizeof(sockopt_val))) < 0)
+ perror("setsockopt");
+ break;
+#endif
+ default:
+ ret = -1;
+ break;
+ }
+ ret = -1;
+#else
+ break;
+#endif
+ case BIO_CTRL_DGRAM_QUERY_MTU:
+#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU)
+ addr_len = (socklen_t)sizeof(addr);
+ memset((void *)&addr, 0, sizeof(addr));
+ if (getsockname(b->num, &addr.sa, &addr_len) < 0)
+ {
+ ret = 0;
+ break;
+ }
+ sockopt_len = sizeof(sockopt_val);
+ switch (addr.sa.sa_family)
+ {
+ case AF_INET:
+ if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val,
+ &sockopt_len)) < 0 || sockopt_val < 0)
+ {
+ ret = 0;
+ }
+ else
+ {
+ /* we assume that the transport protocol is UDP and no
+ * IP options are used.
+ */
+ data->mtu = sockopt_val - 8 - 20;
+ ret = data->mtu;
+ }
+ break;
+#if OPENSSL_USE_IPV6 && defined(IPV6_MTU)
+ case AF_INET6:
+ if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val,
+ &sockopt_len)) < 0 || sockopt_val < 0)
+ {
+ ret = 0;
+ }
+ else
+ {
+ /* we assume that the transport protocol is UDP and no
+ * IPV6 options are used.
+ */
+ data->mtu = sockopt_val - 8 - 40;
+ ret = data->mtu;
+ }
+ break;
+#endif
+ default:
+ ret = 0;
+ break;
+ }
+#else
+ ret = 0;
+#endif
+ break;
+ case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
+ switch (data->peer.sa.sa_family)
+ {
+ case AF_INET:
+ ret = 576 - 20 - 8;
+ break;
+#if OPENSSL_USE_IPV6
+ case AF_INET6:
+#ifdef IN6_IS_ADDR_V4MAPPED
+ if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr))
+ ret = 576 - 20 - 8;
+ else
+#endif
+ ret = 1280 - 40 - 8;
+ break;
+#endif
+ default:
+ ret = 576 - 20 - 8;
+ break;
+ }
+ break;
+ case BIO_CTRL_DGRAM_GET_MTU:
+ return data->mtu;
+ break;
+ case BIO_CTRL_DGRAM_SET_MTU:
+ data->mtu = num;
+ ret = num;
+ break;
+ case BIO_CTRL_DGRAM_SET_CONNECTED:
+ to = (struct sockaddr *)ptr;
+
+ if ( to != NULL)
+ {
+ data->connected = 1;
+ switch (to->sa_family)
+ {
+ case AF_INET:
+ memcpy(&data->peer,to,sizeof(data->peer.sa_in));
+ break;
+#if OPENSSL_USE_IPV6
+ case AF_INET6:
+ memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
+ break;
+#endif
+ default:
+ memcpy(&data->peer,to,sizeof(data->peer.sa));
+ break;
+ }
+ }
+ else
+ {
+ data->connected = 0;
+ memset(&(data->peer), 0x00, sizeof(data->peer));
+ }
+ break;
+ case BIO_CTRL_DGRAM_GET_PEER:
+ switch (data->peer.sa.sa_family)
+ {
+ case AF_INET:
+ ret=sizeof(data->peer.sa_in);
+ break;
+#if OPENSSL_USE_IPV6
+ case AF_INET6:
+ ret=sizeof(data->peer.sa_in6);
+ break;
+#endif
+ default:
+ ret=sizeof(data->peer.sa);
+ break;
+ }
+ if (num==0 || num>ret)
+ num=ret;
+ memcpy(ptr,&data->peer,(ret=num));
+ break;
+ case BIO_CTRL_DGRAM_SET_PEER:
+ to = (struct sockaddr *) ptr;
+ switch (to->sa_family)
+ {
+ case AF_INET:
+ memcpy(&data->peer,to,sizeof(data->peer.sa_in));
+ break;
+#if OPENSSL_USE_IPV6
+ case AF_INET6:
+ memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
+ break;
+#endif
+ default:
+ memcpy(&data->peer,to,sizeof(data->peer.sa));
+ break;
+ }
+ break;
+ case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
+ memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
+ break;
+#if defined(SO_RCVTIMEO)
+ case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
+#ifdef OPENSSL_SYS_WINDOWS
+ {
+ struct timeval *tv = (struct timeval *)ptr;
+ int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
+ if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
+ (void*)&timeout, sizeof(timeout)) < 0)
+ { perror("setsockopt"); ret = -1; }
+ }
+#else
+ if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
+ sizeof(struct timeval)) < 0)
+ { perror("setsockopt"); ret = -1; }
+#endif
+ break;
+ case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
+ {
+ union { size_t s; int i; } sz = {0};
+#ifdef OPENSSL_SYS_WINDOWS
+ int timeout;
+ struct timeval *tv = (struct timeval *)ptr;
+
+ sz.i = sizeof(timeout);
+ if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
+ (void*)&timeout, &sz.i) < 0)
+ { perror("getsockopt"); ret = -1; }
+ else
+ {
+ tv->tv_sec = timeout / 1000;
+ tv->tv_usec = (timeout % 1000) * 1000;
+ ret = sizeof(*tv);
+ }
+#else
+ sz.i = sizeof(struct timeval);
+ if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
+ ptr, (void *)&sz) < 0)
+ { perror("getsockopt"); ret = -1; }
+ else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
+ {
+ OPENSSL_assert(sz.s<=sizeof(struct timeval));
+ ret = (int)sz.s;
+ }
+ else
+ ret = sz.i;
+#endif
+ }
+ break;
+#endif
+#if defined(SO_SNDTIMEO)
+ case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
+#ifdef OPENSSL_SYS_WINDOWS
+ {
+ struct timeval *tv = (struct timeval *)ptr;
+ int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
+ if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
+ (void*)&timeout, sizeof(timeout)) < 0)
+ { perror("setsockopt"); ret = -1; }
+ }
+#else
+ if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
+ sizeof(struct timeval)) < 0)
+ { perror("setsockopt"); ret = -1; }
+#endif
+ break;
+ case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
+ {
+ union { size_t s; int i; } sz = {0};
+#ifdef OPENSSL_SYS_WINDOWS
+ int timeout;
+ struct timeval *tv = (struct timeval *)ptr;
+
+ sz.i = sizeof(timeout);
+ if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
+ (void*)&timeout, &sz.i) < 0)
+ { perror("getsockopt"); ret = -1; }
+ else
+ {
+ tv->tv_sec = timeout / 1000;
+ tv->tv_usec = (timeout % 1000) * 1000;
+ ret = sizeof(*tv);
+ }
+#else
+ sz.i = sizeof(struct timeval);
+ if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
+ ptr, (void *)&sz) < 0)
+ { perror("getsockopt"); ret = -1; }
+ else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
+ {
+ OPENSSL_assert(sz.s<=sizeof(struct timeval));
+ ret = (int)sz.s;
+ }
+ else
+ ret = sz.i;
+#endif
+ }
+ break;
+#endif
+ case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
+ /* fall-through */
+ case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
+#ifdef OPENSSL_SYS_WINDOWS
+ if ( data->_errno == WSAETIMEDOUT)
+#else
+ if ( data->_errno == EAGAIN)
+#endif
+ {
+ ret = 1;
+ data->_errno = 0;
+ }
+ else
+ ret = 0;
+ break;
+#ifdef EMSGSIZE
+ case BIO_CTRL_DGRAM_MTU_EXCEEDED:
+ if ( data->_errno == EMSGSIZE)
+ {
+ ret = 1;
+ data->_errno = 0;
+ }
+ else
+ ret = 0;
+ break;
+#endif
+ default:
+ ret=0;
+ break;
+ }
+ return(ret);
+ }
+
+static int dgram_puts(BIO *bp, const char *str)
+ {
+ int n,ret;
+
+ n=strlen(str);
+ ret=dgram_write(bp,str,n);
+ return(ret);
+ }
+
+#ifndef OPENSSL_NO_SCTP
+BIO_METHOD *BIO_s_datagram_sctp(void)
+ {
+ return(&methods_dgramp_sctp);
+ }
+
+BIO *BIO_new_dgram_sctp(int fd, int close_flag)
+ {
+ BIO *bio;
+ int ret, optval = 20000;
+ int auth_data = 0, auth_forward = 0;
+ unsigned char *p;
+ struct sctp_authchunk auth;
+ struct sctp_authchunks *authchunks;
+ socklen_t sockopt_len;
+#ifdef SCTP_AUTHENTICATION_EVENT
+#ifdef SCTP_EVENT
+ struct sctp_event event;
+#else
+ struct sctp_event_subscribe event;
+#endif
+#endif
+
+ bio=BIO_new(BIO_s_datagram_sctp());
+ if (bio == NULL) return(NULL);
+ BIO_set_fd(bio,fd,close_flag);
+
+ /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */
+ auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE;
+ ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk));
+ OPENSSL_assert(ret >= 0);
+ auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE;
+ ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk));
+ OPENSSL_assert(ret >= 0);
+
+ /* Test if activation was successful. When using accept(),
+ * SCTP-AUTH has to be activated for the listening socket
+ * already, otherwise the connected socket won't use it. */
+ sockopt_len = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
+ authchunks = OPENSSL_malloc(sockopt_len);
+ memset(authchunks, 0, sizeof(sockopt_len));
+ ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, &sockopt_len);
+ OPENSSL_assert(ret >= 0);
+
+ for (p = (unsigned char*) authchunks->gauth_chunks;
+ p < (unsigned char*) authchunks + sockopt_len;
+ p += sizeof(uint8_t))
+ {
+ if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1;
+ if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1;
+ }
+
+ OPENSSL_free(authchunks);
+
+ OPENSSL_assert(auth_data);
+ OPENSSL_assert(auth_forward);
+
+#ifdef SCTP_AUTHENTICATION_EVENT
+#ifdef SCTP_EVENT
+ memset(&event, 0, sizeof(struct sctp_event));
+ event.se_assoc_id = 0;
+ event.se_type = SCTP_AUTHENTICATION_EVENT;
+ event.se_on = 1;
+ ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
+ OPENSSL_assert(ret >= 0);
+#else
+ sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe);
+ ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len);
+ OPENSSL_assert(ret >= 0);
+
+ event.sctp_authentication_event = 1;
+
+ ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
+ OPENSSL_assert(ret >= 0);
+#endif
+#endif
+
+ /* Disable partial delivery by setting the min size
+ * larger than the max record size of 2^14 + 2048 + 13
+ */
+ ret = setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, sizeof(optval));
+ OPENSSL_assert(ret >= 0);
+
+ return(bio);
+ }
+
+int BIO_dgram_is_sctp(BIO *bio)
+ {
+ return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP);
+ }
+
+static int dgram_sctp_new(BIO *bi)
+ {
+ bio_dgram_sctp_data *data = NULL;
+
+ bi->init=0;
+ bi->num=0;
+ data = OPENSSL_malloc(sizeof(bio_dgram_sctp_data));
+ if (data == NULL)
+ return 0;
+ memset(data, 0x00, sizeof(bio_dgram_sctp_data));
+#ifdef SCTP_PR_SCTP_NONE
+ data->prinfo.pr_policy = SCTP_PR_SCTP_NONE;
+#endif
+ bi->ptr = data;
+
+ bi->flags=0;
+ return(1);
+ }
+
+static int dgram_sctp_free(BIO *a)
+ {
+ bio_dgram_sctp_data *data;
+
+ if (a == NULL) return(0);
+ if ( ! dgram_clear(a))
+ return 0;
+
+ data = (bio_dgram_sctp_data *)a->ptr;
+ if(data != NULL) OPENSSL_free(data);
+
+ return(1);
+ }
+
+#ifdef SCTP_AUTHENTICATION_EVENT
+void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp)
+ {
+ int ret;
+ struct sctp_authkey_event* authkeyevent = &snp->sn_auth_event;
+
+ if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY)
+ {
+ struct sctp_authkeyid authkeyid;
+
+ /* delete key */
+ authkeyid.scact_keynumber = authkeyevent->auth_keynumber;
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
+ &authkeyid, sizeof(struct sctp_authkeyid));
+ }
+ }
+#endif
+
+static int dgram_sctp_read(BIO *b, char *out, int outl)
+ {
+ int ret = 0, n = 0, i, optval;
+ socklen_t optlen;
+ bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
+ union sctp_notification *snp;
+ struct msghdr msg;
+ struct iovec iov;
+ struct cmsghdr *cmsg;
+ char cmsgbuf[512];
+
+ if (out != NULL)
+ {
+ clear_socket_error();
+
+ do
+ {
+ memset(&data->rcvinfo, 0x00, sizeof(struct bio_dgram_sctp_rcvinfo));
+ iov.iov_base = out;
+ iov.iov_len = outl;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = 512;
+ msg.msg_flags = 0;
+ n = recvmsg(b->num, &msg, 0);
+
+ if (msg.msg_controllen > 0)
+ {
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != IPPROTO_SCTP)
+ continue;
+#ifdef SCTP_RCVINFO
+ if (cmsg->cmsg_type == SCTP_RCVINFO)
+ {
+ struct sctp_rcvinfo *rcvinfo;
+
+ rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
+ data->rcvinfo.rcv_sid = rcvinfo->rcv_sid;
+ data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn;
+ data->rcvinfo.rcv_flags = rcvinfo->rcv_flags;
+ data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid;
+ data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn;
+ data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn;
+ data->rcvinfo.rcv_context = rcvinfo->rcv_context;
+ }
+#endif
+#ifdef SCTP_SNDRCV
+ if (cmsg->cmsg_type == SCTP_SNDRCV)
+ {
+ struct sctp_sndrcvinfo *sndrcvinfo;
+
+ sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream;
+ data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn;
+ data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags;
+ data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid;
+ data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn;
+ data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn;
+ data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context;
+ }
+#endif
+ }
+ }
+
+ if (n <= 0)
+ {
+ if (n < 0)
+ ret = n;
+ break;
+ }
+
+ if (msg.msg_flags & MSG_NOTIFICATION)
+ {
+ snp = (union sctp_notification*) out;
+ if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT)
+ {
+#ifdef SCTP_EVENT
+ struct sctp_event event;
+#else
+ struct sctp_event_subscribe event;
+ socklen_t eventsize;
+#endif
+ /* If a message has been delayed until the socket
+ * is dry, it can be sent now.
+ */
+ if (data->saved_message.length > 0)
+ {
+ dgram_sctp_write(data->saved_message.bio, data->saved_message.data,
+ data->saved_message.length);
+ OPENSSL_free(data->saved_message.data);
+ data->saved_message.length = 0;
+ }
+
+ /* disable sender dry event */
+#ifdef SCTP_EVENT
+ memset(&event, 0, sizeof(struct sctp_event));
+ event.se_assoc_id = 0;
+ event.se_type = SCTP_SENDER_DRY_EVENT;
+ event.se_on = 0;
+ i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
+ OPENSSL_assert(i >= 0);
+#else
+ eventsize = sizeof(struct sctp_event_subscribe);
+ i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
+ OPENSSL_assert(i >= 0);
+
+ event.sctp_sender_dry_event = 0;
+
+ i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
+ OPENSSL_assert(i >= 0);
+#endif
+ }
+
+#ifdef SCTP_AUTHENTICATION_EVENT
+ if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
+ dgram_sctp_handle_auth_free_key_event(b, snp);
+#endif
+
+ if (data->handle_notifications != NULL)
+ data->handle_notifications(b, data->notification_context, (void*) out);
+
+ memset(out, 0, outl);
+ }
+ else
+ ret += n;
+ }
+ while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) && (ret < outl));
+
+ if (ret > 0 && !(msg.msg_flags & MSG_EOR))
+ {
+ /* Partial message read, this should never happen! */
+
+ /* The buffer was too small, this means the peer sent
+ * a message that was larger than allowed. */
+ if (ret == outl)
+ return -1;
+
+ /* Test if socket buffer can handle max record
+ * size (2^14 + 2048 + 13)
+ */
+ optlen = (socklen_t) sizeof(int);
+ ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);
+ OPENSSL_assert(ret >= 0);
+ OPENSSL_assert(optval >= 18445);
+
+ /* Test if SCTP doesn't partially deliver below
+ * max record size (2^14 + 2048 + 13)
+ */
+ optlen = (socklen_t) sizeof(int);
+ ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
+ &optval, &optlen);
+ OPENSSL_assert(ret >= 0);
+ OPENSSL_assert(optval >= 18445);
+
+ /* Partially delivered notification??? Probably a bug.... */
+ OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION));
+
+ /* Everything seems ok till now, so it's most likely
+ * a message dropped by PR-SCTP.
+ */
+ memset(out, 0, outl);
+ BIO_set_retry_read(b);
+ return -1;
+ }
+
+ BIO_clear_retry_flags(b);
+ if (ret < 0)
+ {
+ if (BIO_dgram_should_retry(ret))
+ {
+ BIO_set_retry_read(b);
+ data->_errno = get_last_socket_error();
+ }
+ }
+
+ /* Test if peer uses SCTP-AUTH before continuing */
+ if (!data->peer_auth_tested)
+ {
+ int ii, auth_data = 0, auth_forward = 0;
+ unsigned char *p;
+ struct sctp_authchunks *authchunks;
+
+ optlen = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
+ authchunks = OPENSSL_malloc(optlen);
+ memset(authchunks, 0, sizeof(optlen));
+ ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, authchunks, &optlen);
+ OPENSSL_assert(ii >= 0);
+
+ for (p = (unsigned char*) authchunks->gauth_chunks;
+ p < (unsigned char*) authchunks + optlen;
+ p += sizeof(uint8_t))
+ {
+ if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1;
+ if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1;
+ }
+
+ OPENSSL_free(authchunks);
+
+ if (!auth_data || !auth_forward)
+ {
+ BIOerr(BIO_F_DGRAM_SCTP_READ,BIO_R_CONNECT_ERROR);
+ return -1;
+ }
+
+ data->peer_auth_tested = 1;
+ }
+ }
+ return(ret);
+ }
+
+static int dgram_sctp_write(BIO *b, const char *in, int inl)
+ {
+ int ret;
+ bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
+ struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo);
+ struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo);
+ struct bio_dgram_sctp_sndinfo handshake_sinfo;
+ struct iovec iov[1];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
+ char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo))];
+ struct sctp_sndinfo *sndinfo;
+ struct sctp_prinfo *prinfo;
+#else
+ char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct sctp_sndrcvinfo *sndrcvinfo;
+#endif
+
+ clear_socket_error();
+
+ /* If we're send anything else than application data,
+ * disable all user parameters and flags.
+ */
+ if (in[0] != 23) {
+ memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo));
+#ifdef SCTP_SACK_IMMEDIATELY
+ handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY;
+#endif
+ sinfo = &handshake_sinfo;
+ }
+
+ /* If we have to send a shutdown alert message and the
+ * socket is not dry yet, we have to save it and send it
+ * as soon as the socket gets dry.
+ */
+ if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b))
+ {
+ data->saved_message.bio = b;
+ data->saved_message.length = inl;
+ data->saved_message.data = OPENSSL_malloc(inl);
+ memcpy(data->saved_message.data, in, inl);
+ return inl;
+ }
+
+ iov[0].iov_base = (char *)in;
+ iov[0].iov_len = inl;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = (caddr_t)cmsgbuf;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
+ cmsg = (struct cmsghdr *)cmsgbuf;
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
+ sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg);
+ memset(sndinfo, 0, sizeof(struct sctp_sndinfo));
+ sndinfo->snd_sid = sinfo->snd_sid;
+ sndinfo->snd_flags = sinfo->snd_flags;
+ sndinfo->snd_ppid = sinfo->snd_ppid;
+ sndinfo->snd_context = sinfo->snd_context;
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
+
+ cmsg = (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))];
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_PRINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
+ prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg);
+ memset(prinfo, 0, sizeof(struct sctp_prinfo));
+ prinfo->pr_policy = pinfo->pr_policy;
+ prinfo->pr_value = pinfo->pr_value;
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
+#else
+ cmsg = (struct cmsghdr *)cmsgbuf;
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo));
+ sndrcvinfo->sinfo_stream = sinfo->snd_sid;
+ sndrcvinfo->sinfo_flags = sinfo->snd_flags;
+#ifdef __FreeBSD__
+ sndrcvinfo->sinfo_flags |= pinfo->pr_policy;
+#endif
+ sndrcvinfo->sinfo_ppid = sinfo->snd_ppid;
+ sndrcvinfo->sinfo_context = sinfo->snd_context;
+ sndrcvinfo->sinfo_timetolive = pinfo->pr_value;
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
+#endif
+
+ ret = sendmsg(b->num, &msg, 0);
+
+ BIO_clear_retry_flags(b);
+ if (ret <= 0)
+ {
+ if (BIO_dgram_should_retry(ret))
+ {
+ BIO_set_retry_write(b);
+ data->_errno = get_last_socket_error();
+ }
+ }
+ return(ret);
+ }
+
+static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr)
+ {
+ long ret=1;
+ bio_dgram_sctp_data *data = NULL;
+ socklen_t sockopt_len = 0;
+ struct sctp_authkeyid authkeyid;
+ struct sctp_authkey *authkey = NULL;
+
+ data = (bio_dgram_sctp_data *)b->ptr;
+
+ switch (cmd)
+ {
+ case BIO_CTRL_DGRAM_QUERY_MTU:
+ /* Set to maximum (2^14)
+ * and ignore user input to enable transport
+ * protocol fragmentation.
+ * Returns always 2^14.
+ */
+ data->mtu = 16384;
+ ret = data->mtu;
+ break;
+ case BIO_CTRL_DGRAM_SET_MTU:
+ /* Set to maximum (2^14)
+ * and ignore input to enable transport
+ * protocol fragmentation.
+ * Returns always 2^14.
+ */
+ data->mtu = 16384;
+ ret = data->mtu;
+ break;
+ case BIO_CTRL_DGRAM_SET_CONNECTED:
+ case BIO_CTRL_DGRAM_CONNECT:
+ /* Returns always -1. */
+ ret = -1;
+ break;
+ case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
+ /* SCTP doesn't need the DTLS timer
+ * Returns always 1.
+ */
+ break;
+ case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE:
+ if (num > 0)
+ data->in_handshake = 1;
+ else
+ data->in_handshake = 0;
+
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, &data->in_handshake, sizeof(int));
+ break;
+ case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY:
+ /* New shared key for SCTP AUTH.
+ * Returns 0 on success, -1 otherwise.
+ */
+
+ /* Get active key */
+ sockopt_len = sizeof(struct sctp_authkeyid);
+ ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
+ if (ret < 0) break;
+
+ /* Add new key */
+ sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t);
+ authkey = OPENSSL_malloc(sockopt_len);
+ if (authkey == NULL)
+ {
+ ret = -1;
+ break;
+ }
+ memset(authkey, 0x00, sockopt_len);
+ authkey->sca_keynumber = authkeyid.scact_keynumber + 1;
+#ifndef __FreeBSD__
+ /* This field is missing in FreeBSD 8.2 and earlier,
+ * and FreeBSD 8.3 and higher work without it.
+ */
+ authkey->sca_keylength = 64;
+#endif
+ memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t));
+
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, sockopt_len);
+ OPENSSL_free(authkey);
+ authkey = NULL;
+ if (ret < 0) break;
+
+ /* Reset active key */
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
+ &authkeyid, sizeof(struct sctp_authkeyid));
+ if (ret < 0) break;
+
+ break;
+ case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY:
+ /* Returns 0 on success, -1 otherwise. */
+
+ /* Get active key */
+ sockopt_len = sizeof(struct sctp_authkeyid);
+ ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
+ if (ret < 0) break;
+
+ /* Set active key */
+ authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1;
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
+ &authkeyid, sizeof(struct sctp_authkeyid));
+ if (ret < 0) break;
+
+ /* CCS has been sent, so remember that and fall through
+ * to check if we need to deactivate an old key
+ */
+ data->ccs_sent = 1;
+
+ case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD:
+ /* Returns 0 on success, -1 otherwise. */
+
+ /* Has this command really been called or is this just a fall-through? */
+ if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD)
+ data->ccs_rcvd = 1;
+
+ /* CSS has been both, received and sent, so deactivate an old key */
+ if (data->ccs_rcvd == 1 && data->ccs_sent == 1)
+ {
+ /* Get active key */
+ sockopt_len = sizeof(struct sctp_authkeyid);
+ ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
+ if (ret < 0) break;
+
+ /* Deactivate key or delete second last key if
+ * SCTP_AUTHENTICATION_EVENT is not available.
+ */
+ authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
+#ifdef SCTP_AUTH_DEACTIVATE_KEY
+ sockopt_len = sizeof(struct sctp_authkeyid);
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY,
+ &authkeyid, sockopt_len);
+ if (ret < 0) break;
+#endif
+#ifndef SCTP_AUTHENTICATION_EVENT
+ if (authkeyid.scact_keynumber > 0)
+ {
+ authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
+ &authkeyid, sizeof(struct sctp_authkeyid));
+ if (ret < 0) break;
+ }
+#endif
+
+ data->ccs_rcvd = 0;
+ data->ccs_sent = 0;
+ }
+ break;
+ case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO:
+ /* Returns the size of the copied struct. */
+ if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo))
+ num = sizeof(struct bio_dgram_sctp_sndinfo);
+
+ memcpy(ptr, &(data->sndinfo), num);
+ ret = num;
+ break;
+ case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO:
+ /* Returns the size of the copied struct. */
+ if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo))
+ num = sizeof(struct bio_dgram_sctp_sndinfo);
+
+ memcpy(&(data->sndinfo), ptr, num);
+ break;
+ case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO:
+ /* Returns the size of the copied struct. */
+ if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo))
+ num = sizeof(struct bio_dgram_sctp_rcvinfo);
+
+ memcpy(ptr, &data->rcvinfo, num);
+
+ ret = num;
+ break;
+ case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO:
+ /* Returns the size of the copied struct. */
+ if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo))
+ num = sizeof(struct bio_dgram_sctp_rcvinfo);
+
+ memcpy(&(data->rcvinfo), ptr, num);
+ break;
+ case BIO_CTRL_DGRAM_SCTP_GET_PRINFO:
+ /* Returns the size of the copied struct. */
+ if (num > (long) sizeof(struct bio_dgram_sctp_prinfo))
+ num = sizeof(struct bio_dgram_sctp_prinfo);
+
+ memcpy(ptr, &(data->prinfo), num);
+ ret = num;
+ break;
+ case BIO_CTRL_DGRAM_SCTP_SET_PRINFO:
+ /* Returns the size of the copied struct. */
+ if (num > (long) sizeof(struct bio_dgram_sctp_prinfo))
+ num = sizeof(struct bio_dgram_sctp_prinfo);
+
+ memcpy(&(data->prinfo), ptr, num);
+ break;
+ case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN:
+ /* Returns always 1. */
+ if (num > 0)
+ data->save_shutdown = 1;
+ else
+ data->save_shutdown = 0;
+ break;
+
+ default:
+ /* Pass to default ctrl function to
+ * process SCTP unspecific commands
+ */
+ ret=dgram_ctrl(b, cmd, num, ptr);
+ break;
+ }
+ return(ret);
+ }
+
+int BIO_dgram_sctp_notification_cb(BIO *b,
+ void (*handle_notifications)(BIO *bio, void *context, void *buf),
+ void *context)
+ {
+ bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
+
+ if (handle_notifications != NULL)
+ {
+ data->handle_notifications = handle_notifications;
+ data->notification_context = context;
+ }
+ else
+ return -1;
+
+ return 0;
+ }
+
+int BIO_dgram_sctp_wait_for_dry(BIO *b)
+{
+ int is_dry = 0;
+ int n, sockflags, ret;
+ union sctp_notification snp;
+ struct msghdr msg;
+ struct iovec iov;
+#ifdef SCTP_EVENT
+ struct sctp_event event;
+#else
+ struct sctp_event_subscribe event;
+ socklen_t eventsize;
+#endif
+ bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
+
+ /* set sender dry event */
+#ifdef SCTP_EVENT
+ memset(&event, 0, sizeof(struct sctp_event));
+ event.se_assoc_id = 0;
+ event.se_type = SCTP_SENDER_DRY_EVENT;
+ event.se_on = 1;
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
+#else
+ eventsize = sizeof(struct sctp_event_subscribe);
+ ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
+ if (ret < 0)
+ return -1;
+
+ event.sctp_sender_dry_event = 1;
+
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
+#endif
+ if (ret < 0)
+ return -1;
+
+ /* peek for notification */
+ memset(&snp, 0x00, sizeof(union sctp_notification));
+ iov.iov_base = (char *)&snp;
+ iov.iov_len = sizeof(union sctp_notification);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ n = recvmsg(b->num, &msg, MSG_PEEK);
+ if (n <= 0)
+ {
+ if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
+ return -1;
+ else
+ return 0;
+ }
+
+ /* if we find a notification, process it and try again if necessary */
+ while (msg.msg_flags & MSG_NOTIFICATION)
+ {
+ memset(&snp, 0x00, sizeof(union sctp_notification));
+ iov.iov_base = (char *)&snp;
+ iov.iov_len = sizeof(union sctp_notification);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ n = recvmsg(b->num, &msg, 0);
+ if (n <= 0)
+ {
+ if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
+ return -1;
+ else
+ return is_dry;
+ }
+
+ if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT)
+ {
+ is_dry = 1;
+
+ /* disable sender dry event */
+#ifdef SCTP_EVENT
+ memset(&event, 0, sizeof(struct sctp_event));
+ event.se_assoc_id = 0;
+ event.se_type = SCTP_SENDER_DRY_EVENT;
+ event.se_on = 0;
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
+#else
+ eventsize = (socklen_t) sizeof(struct sctp_event_subscribe);
+ ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
+ if (ret < 0)
+ return -1;
+
+ event.sctp_sender_dry_event = 0;
+
+ ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
+#endif
+ if (ret < 0)
+ return -1;
+ }
+
+#ifdef SCTP_AUTHENTICATION_EVENT
+ if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
+ dgram_sctp_handle_auth_free_key_event(b, &snp);
+#endif
+
+ if (data->handle_notifications != NULL)
+ data->handle_notifications(b, data->notification_context, (void*) &snp);
+
+ /* found notification, peek again */
+ memset(&snp, 0x00, sizeof(union sctp_notification));
+ iov.iov_base = (char *)&snp;
+ iov.iov_len = sizeof(union sctp_notification);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ /* if we have seen the dry already, don't wait */
+ if (is_dry)
+ {
+ sockflags = fcntl(b->num, F_GETFL, 0);
+ fcntl(b->num, F_SETFL, O_NONBLOCK);
+ }
+
+ n = recvmsg(b->num, &msg, MSG_PEEK);
+
+ if (is_dry)
+ {
+ fcntl(b->num, F_SETFL, sockflags);
+ }
+
+ if (n <= 0)
+ {
+ if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
+ return -1;
+ else
+ return is_dry;
+ }
+ }
+
+ /* read anything else */
+ return is_dry;
+}
+
+int BIO_dgram_sctp_msg_waiting(BIO *b)
+ {
+ int n, sockflags;
+ union sctp_notification snp;
+ struct msghdr msg;
+ struct iovec iov;
+ bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
+
+ /* Check if there are any messages waiting to be read */
+ do
+ {
+ memset(&snp, 0x00, sizeof(union sctp_notification));
+ iov.iov_base = (char *)&snp;
+ iov.iov_len = sizeof(union sctp_notification);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ sockflags = fcntl(b->num, F_GETFL, 0);
+ fcntl(b->num, F_SETFL, O_NONBLOCK);
+ n = recvmsg(b->num, &msg, MSG_PEEK);
+ fcntl(b->num, F_SETFL, sockflags);
+
+ /* if notification, process and try again */
+ if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION))
+ {
+#ifdef SCTP_AUTHENTICATION_EVENT
+ if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
+ dgram_sctp_handle_auth_free_key_event(b, &snp);
+#endif
+
+ memset(&snp, 0x00, sizeof(union sctp_notification));
+ iov.iov_base = (char *)&snp;
+ iov.iov_len = sizeof(union sctp_notification);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+ n = recvmsg(b->num, &msg, 0);
+
+ if (data->handle_notifications != NULL)
+ data->handle_notifications(b, data->notification_context, (void*) &snp);
+ }
+
+ } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION));
+
+ /* Return 1 if there is a message to be read, return 0 otherwise. */
+ if (n > 0)
+ return 1;
+ else
+ return 0;
+ }
+
+static int dgram_sctp_puts(BIO *bp, const char *str)
+ {
+ int n,ret;
+
+ n=strlen(str);
+ ret=dgram_sctp_write(bp,str,n);
+ return(ret);
+ }
+#endif
+
+static int BIO_dgram_should_retry(int i)
+ {
+ int err;
+
+ if ((i == 0) || (i == -1))
+ {
+ err=get_last_socket_error();
+
+#if defined(OPENSSL_SYS_WINDOWS)
+ /* If the socket return value (i) is -1
+ * and err is unexpectedly 0 at this point,
+ * the error code was overwritten by
+ * another system call before this error
+ * handling is called.
+ */
+#endif
+
+ return(BIO_dgram_non_fatal_error(err));
+ }
+ return(0);
+ }
+
+int BIO_dgram_non_fatal_error(int err)
+ {
+ switch (err)
+ {
+#if defined(OPENSSL_SYS_WINDOWS)
+# if defined(WSAEWOULDBLOCK)
+ case WSAEWOULDBLOCK:
+# endif
+
+# if 0 /* This appears to always be an error */
+# if defined(WSAENOTCONN)
+ case WSAENOTCONN:
+# endif
+# endif
+#endif
+
+#ifdef EWOULDBLOCK
+# ifdef WSAEWOULDBLOCK
+# if WSAEWOULDBLOCK != EWOULDBLOCK
+ case EWOULDBLOCK:
+# endif
+# else
+ case EWOULDBLOCK:
+# endif
+#endif
+
+#ifdef EINTR
+ case EINTR:
+#endif
+
+#ifdef EAGAIN
+#if EWOULDBLOCK != EAGAIN
+ case EAGAIN:
+# endif
+#endif
+
+#ifdef EPROTO
+ case EPROTO:
+#endif
+
+#ifdef EINPROGRESS
+ case EINPROGRESS:
+#endif
+
+#ifdef EALREADY
+ case EALREADY:
+#endif
+
+ return(1);
+ /* break; */
+ default:
+ break;
+ }
+ return(0);
+ }
+
+static void get_current_time(struct timeval *t)
+ {
+#ifdef OPENSSL_SYS_WIN32
+ struct _timeb tb;
+ _ftime(&tb);
+ t->tv_sec = (long)tb.time;
+ t->tv_usec = (long)tb.millitm * 1000;
+#elif defined(OPENSSL_SYS_VMS)
+ struct timeb tb;
+ ftime(&tb);
+ t->tv_sec = (long)tb.time;
+ t->tv_usec = (long)tb.millitm * 1000;
+#else
+ gettimeofday(t, NULL);
+#endif
+ }
+
+#endif
diff --git a/drivers/builtin_openssl/crypto/bio/bss_fd.c b/drivers/builtin_openssl2/crypto/bio/bss_fd.c
index d1bf85aae1..d1bf85aae1 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_fd.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_fd.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_file.c b/drivers/builtin_openssl2/crypto/bio/bss_file.c
index b954fe7ebc..b954fe7ebc 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_file.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_file.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_log.c b/drivers/builtin_openssl2/crypto/bio/bss_log.c
index 2227b2b52d..2227b2b52d 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_log.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_log.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_mem.c b/drivers/builtin_openssl2/crypto/bio/bss_mem.c
index 37d4194e4b..37d4194e4b 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_mem.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_mem.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_null.c b/drivers/builtin_openssl2/crypto/bio/bss_null.c
index 46b73339df..46b73339df 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_null.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_null.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_rtcp.c b/drivers/builtin_openssl2/crypto/bio/bss_rtcp.c
index 7dae485564..7dae485564 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_rtcp.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_rtcp.c
diff --git a/drivers/builtin_openssl/crypto/bio/bss_sock.c b/drivers/builtin_openssl2/crypto/bio/bss_sock.c
index 3df31938c1..3df31938c1 100644
--- a/drivers/builtin_openssl/crypto/bio/bss_sock.c
+++ b/drivers/builtin_openssl2/crypto/bio/bss_sock.c
diff --git a/drivers/builtin_openssl/crypto/bn/asm/README b/drivers/builtin_openssl2/crypto/bn/asm/README
index b0f3a68a06..b0f3a68a06 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/README
+++ b/drivers/builtin_openssl2/crypto/bn/asm/README
diff --git a/drivers/builtin_openssl/crypto/bn/asm/alpha-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/alpha-mont.pl
index 03596e2014..03596e2014 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/alpha-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/alpha-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/armv4-gf2m.pl b/drivers/builtin_openssl2/crypto/bn/asm/armv4-gf2m.pl
index c52e0b75b5..c52e0b75b5 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/armv4-gf2m.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/armv4-gf2m.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/armv4-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/armv4-mont.pl
index f78a8b5f0f..f78a8b5f0f 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/armv4-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/armv4-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/bn-586.pl b/drivers/builtin_openssl2/crypto/bn/asm/bn-586.pl
index 332ef3e91d..332ef3e91d 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/bn-586.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/bn-586.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/co-586.pl b/drivers/builtin_openssl2/crypto/bn/asm/co-586.pl
index 57101a6bd7..57101a6bd7 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/co-586.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/co-586.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/ia64-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/ia64-mont.pl
index e258658428..e258658428 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/ia64-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/ia64-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/ia64.S b/drivers/builtin_openssl2/crypto/bn/asm/ia64.S
index 951abc53ea..951abc53ea 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/ia64.S
+++ b/drivers/builtin_openssl2/crypto/bn/asm/ia64.S
diff --git a/drivers/builtin_openssl/crypto/bn/asm/mips-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/mips-mont.pl
index caae04ed3a..caae04ed3a 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/mips-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/mips-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/mips.pl b/drivers/builtin_openssl2/crypto/bn/asm/mips.pl
index d2f3ef7bbf..d2f3ef7bbf 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/mips.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/mips.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/mips3-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/mips3-mont.pl
index 8f9156e02a..8f9156e02a 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/mips3-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/mips3-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/mips3.s b/drivers/builtin_openssl2/crypto/bn/asm/mips3.s
index dca4105c7d..dca4105c7d 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/mips3.s
+++ b/drivers/builtin_openssl2/crypto/bn/asm/mips3.s
diff --git a/drivers/builtin_openssl/crypto/bn/asm/modexp512-x86_64.pl b/drivers/builtin_openssl2/crypto/bn/asm/modexp512-x86_64.pl
index bfd6e97541..bfd6e97541 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/modexp512-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/modexp512-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/pa-risc2.s b/drivers/builtin_openssl2/crypto/bn/asm/pa-risc2.s
index f3b16290eb..f3b16290eb 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/pa-risc2.s
+++ b/drivers/builtin_openssl2/crypto/bn/asm/pa-risc2.s
diff --git a/drivers/builtin_openssl/crypto/bn/asm/pa-risc2W.s b/drivers/builtin_openssl2/crypto/bn/asm/pa-risc2W.s
index a99545754d..a99545754d 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/pa-risc2W.s
+++ b/drivers/builtin_openssl2/crypto/bn/asm/pa-risc2W.s
diff --git a/drivers/builtin_openssl/crypto/bn/asm/parisc-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/parisc-mont.pl
index c02ef6f014..c02ef6f014 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/parisc-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/parisc-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/ppc-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/ppc-mont.pl
index f9b6992ccc..f9b6992ccc 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/ppc-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/ppc-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/ppc.pl b/drivers/builtin_openssl2/crypto/bn/asm/ppc.pl
index 1249ce2299..1249ce2299 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/ppc.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/ppc.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/ppc64-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/ppc64-mont.pl
index a14e769ad0..a14e769ad0 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/ppc64-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/ppc64-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/s390x-gf2m.pl b/drivers/builtin_openssl2/crypto/bn/asm/s390x-gf2m.pl
index cd9f13eca2..cd9f13eca2 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/s390x-gf2m.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/s390x-gf2m.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/s390x-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/s390x-mont.pl
index 9fd64e81ee..9fd64e81ee 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/s390x-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/s390x-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/s390x.S b/drivers/builtin_openssl2/crypto/bn/asm/s390x.S
index 43fcb79bc0..43fcb79bc0 100755
--- a/drivers/builtin_openssl/crypto/bn/asm/s390x.S
+++ b/drivers/builtin_openssl2/crypto/bn/asm/s390x.S
diff --git a/drivers/builtin_openssl/crypto/bn/asm/sparcv8.S b/drivers/builtin_openssl2/crypto/bn/asm/sparcv8.S
index 88c5dc480a..88c5dc480a 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/sparcv8.S
+++ b/drivers/builtin_openssl2/crypto/bn/asm/sparcv8.S
diff --git a/drivers/builtin_openssl/crypto/bn/asm/sparcv8plus.S b/drivers/builtin_openssl2/crypto/bn/asm/sparcv8plus.S
index 63de1860f2..63de1860f2 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/sparcv8plus.S
+++ b/drivers/builtin_openssl2/crypto/bn/asm/sparcv8plus.S
diff --git a/drivers/builtin_openssl/crypto/bn/asm/sparcv9-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/sparcv9-mont.pl
index b8fb1e8a25..b8fb1e8a25 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/sparcv9-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/sparcv9-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/sparcv9a-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/sparcv9a-mont.pl
index a14205f2f0..a14205f2f0 100755
--- a/drivers/builtin_openssl/crypto/bn/asm/sparcv9a-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/sparcv9a-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/via-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/via-mont.pl
index c046a514c8..c046a514c8 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/via-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/via-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/vms.mar b/drivers/builtin_openssl2/crypto/bn/asm/vms.mar
index aefab15cdb..aefab15cdb 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/vms.mar
+++ b/drivers/builtin_openssl2/crypto/bn/asm/vms.mar
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86-gf2m.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86-gf2m.pl
index 808a1e5969..808a1e5969 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86-gf2m.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86-gf2m.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86-mont.pl
index e8f6b05084..e8f6b05084 100755
--- a/drivers/builtin_openssl/crypto/bn/asm/x86-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86.pl
index 1bc4f1bb27..1bc4f1bb27 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86/add.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86/add.pl
index 0b5cf583e3..0b5cf583e3 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86/add.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86/add.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86/comba.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86/comba.pl
index 2291253629..2291253629 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86/comba.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86/comba.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86/div.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86/div.pl
index 0e90152caa..0e90152caa 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86/div.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86/div.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86/f b/drivers/builtin_openssl2/crypto/bn/asm/x86/f
index 22e4112224..22e4112224 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86/f
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86/f
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86/mul.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86/mul.pl
index 674cb9b055..674cb9b055 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86/mul.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86/mul.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86/mul_add.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86/mul_add.pl
index 61830d3a90..61830d3a90 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86/mul_add.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86/mul_add.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86/sqr.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86/sqr.pl
index 1f90993cf6..1f90993cf6 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86/sqr.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86/sqr.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86/sub.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86/sub.pl
index 837b0e1b07..837b0e1b07 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86/sub.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86/sub.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86_64-gcc.c b/drivers/builtin_openssl2/crypto/bn/asm/x86_64-gcc.c
index acb0b40118..acb0b40118 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86_64-gcc.c
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86_64-gcc.c
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86_64-gf2m.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86_64-gf2m.pl
index 226c66c35e..226c66c35e 100644
--- a/drivers/builtin_openssl/crypto/bn/asm/x86_64-gf2m.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86_64-gf2m.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86_64-mont.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86_64-mont.pl
index 17fb94c84c..17fb94c84c 100755
--- a/drivers/builtin_openssl/crypto/bn/asm/x86_64-mont.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86_64-mont.pl
diff --git a/drivers/builtin_openssl/crypto/bn/asm/x86_64-mont5.pl b/drivers/builtin_openssl2/crypto/bn/asm/x86_64-mont5.pl
index dae0fe2453..dae0fe2453 100755
--- a/drivers/builtin_openssl/crypto/bn/asm/x86_64-mont5.pl
+++ b/drivers/builtin_openssl2/crypto/bn/asm/x86_64-mont5.pl
diff --git a/drivers/builtin_openssl/crypto/bn/bn.mul b/drivers/builtin_openssl2/crypto/bn/bn.mul
index 9728870d38..9728870d38 100644
--- a/drivers/builtin_openssl/crypto/bn/bn.mul
+++ b/drivers/builtin_openssl2/crypto/bn/bn.mul
diff --git a/drivers/builtin_openssl/crypto/bn/bn_add.c b/drivers/builtin_openssl2/crypto/bn/bn_add.c
index 9405163706..9405163706 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_add.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_add.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_asm.c b/drivers/builtin_openssl2/crypto/bn/bn_asm.c
index c43c91cc09..c43c91cc09 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_asm.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_asm.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_blind.c b/drivers/builtin_openssl2/crypto/bn/bn_blind.c
index 9ed8bc2b40..9ed8bc2b40 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_blind.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_blind.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_const.c b/drivers/builtin_openssl2/crypto/bn/bn_const.c
index eb60a25b3c..eb60a25b3c 100755
--- a/drivers/builtin_openssl/crypto/bn/bn_const.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_const.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_ctx.c b/drivers/builtin_openssl2/crypto/bn/bn_ctx.c
index 3f2256f675..3f2256f675 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_ctx.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_ctx.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_depr.c b/drivers/builtin_openssl2/crypto/bn/bn_depr.c
index 27535e4fca..27535e4fca 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_depr.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_depr.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_div.c b/drivers/builtin_openssl2/crypto/bn/bn_div.c
index 7b2403185e..7b2403185e 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_div.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_div.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_err.c b/drivers/builtin_openssl2/crypto/bn/bn_err.c
index cfe2eb94a0..cfe2eb94a0 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_err.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_err.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_exp.c b/drivers/builtin_openssl2/crypto/bn/bn_exp.c
index 2abf6fd678..2abf6fd678 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_exp.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_exp.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_exp2.c b/drivers/builtin_openssl2/crypto/bn/bn_exp2.c
index bd0c34b91b..bd0c34b91b 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_exp2.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_exp2.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_gcd.c b/drivers/builtin_openssl2/crypto/bn/bn_gcd.c
index a808f53178..a808f53178 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_gcd.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_gcd.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_gf2m.c b/drivers/builtin_openssl2/crypto/bn/bn_gf2m.c
index 8a4dc20ad9..8a4dc20ad9 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_gf2m.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_gf2m.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_kron.c b/drivers/builtin_openssl2/crypto/bn/bn_kron.c
index 740359b752..740359b752 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_kron.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_kron.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_lcl.h b/drivers/builtin_openssl2/crypto/bn/bn_lcl.h
index 817c773b65..817c773b65 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_lcl.h
+++ b/drivers/builtin_openssl2/crypto/bn/bn_lcl.h
diff --git a/drivers/builtin_openssl/crypto/bn/bn_lib.c b/drivers/builtin_openssl2/crypto/bn/bn_lib.c
index 5461e6ee7d..5461e6ee7d 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_lib.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_lib.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_mod.c b/drivers/builtin_openssl2/crypto/bn/bn_mod.c
index 77d6ddb91a..77d6ddb91a 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_mod.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_mod.c
diff --git a/drivers/builtin_openssl2/crypto/bn/bn_mont.c b/drivers/builtin_openssl2/crypto/bn/bn_mont.c
new file mode 100644
index 0000000000..ee8532c7dc
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/bn/bn_mont.c
@@ -0,0 +1,515 @@
+/* crypto/bn/bn_mont.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*
+ * Details about Montgomery multiplication algorithms can be found at
+ * http://security.ece.orst.edu/publications.html, e.g.
+ * http://security.ece.orst.edu/koc/papers/j37acmon.pdf and
+ * sections 3.8 and 4.2 in http://security.ece.orst.edu/koc/papers/r01rsasw.pdf
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include "bn_lcl.h"
+
+#define MONT_WORD /* use the faster word-based algorithm */
+
+#ifdef MONT_WORD
+static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont);
+#endif
+
+int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ BN_MONT_CTX *mont, BN_CTX *ctx)
+ {
+ BIGNUM *tmp;
+ int ret=0;
+#if defined(OPENSSL_BN_ASM_MONT) && defined(MONT_WORD)
+ int num = mont->N.top;
+
+ if (num>1 && a->top==num && b->top==num)
+ {
+ if (bn_wexpand(r,num) == NULL) return(0);
+ if (bn_mul_mont(r->d,a->d,b->d,mont->N.d,mont->n0,num))
+ {
+ r->neg = a->neg^b->neg;
+ r->top = num;
+ bn_correct_top(r);
+ return(1);
+ }
+ }
+#endif
+
+ BN_CTX_start(ctx);
+ tmp = BN_CTX_get(ctx);
+ if (tmp == NULL) goto err;
+
+ bn_check_top(tmp);
+ if (a == b)
+ {
+ if (!BN_sqr(tmp,a,ctx)) goto err;
+ }
+ else
+ {
+ if (!BN_mul(tmp,a,b,ctx)) goto err;
+ }
+ /* reduce from aRR to aR */
+#ifdef MONT_WORD
+ if (!BN_from_montgomery_word(r,tmp,mont)) goto err;
+#else
+ if (!BN_from_montgomery(r,tmp,mont,ctx)) goto err;
+#endif
+ bn_check_top(r);
+ ret=1;
+err:
+ BN_CTX_end(ctx);
+ return(ret);
+ }
+
+#ifdef MONT_WORD
+static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
+ {
+ BIGNUM *n;
+ BN_ULONG *ap,*np,*rp,n0,v,carry;
+ int nl,max,i;
+
+ n= &(mont->N);
+ nl=n->top;
+ if (nl == 0) { ret->top=0; return(1); }
+
+ max=(2*nl); /* carry is stored separately */
+ if (bn_wexpand(r,max) == NULL) return(0);
+
+ r->neg^=n->neg;
+ np=n->d;
+ rp=r->d;
+
+ /* clear the top words of T */
+#if 1
+ for (i=r->top; i<max; i++) /* memset? XXX */
+ rp[i]=0;
+#else
+ memset(&(rp[r->top]),0,(max-r->top)*sizeof(BN_ULONG));
+#endif
+
+ r->top=max;
+ n0=mont->n0[0];
+
+#ifdef BN_COUNT
+ fprintf(stderr,"word BN_from_montgomery_word %d * %d\n",nl,nl);
+#endif
+ for (carry=0, i=0; i<nl; i++, rp++)
+ {
+#ifdef __TANDEM
+ {
+ long long t1;
+ long long t2;
+ long long t3;
+ t1 = rp[0] * (n0 & 0177777);
+ t2 = 037777600000l;
+ t2 = n0 & t2;
+ t3 = rp[0] & 0177777;
+ t2 = (t3 * t2) & BN_MASK2;
+ t1 = t1 + t2;
+ v=bn_mul_add_words(rp,np,nl,(BN_ULONG) t1);
+ }
+#else
+ v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2);
+#endif
+ v = (v+carry+rp[nl])&BN_MASK2;
+ carry |= (v != rp[nl]);
+ carry &= (v <= rp[nl]);
+ rp[nl]=v;
+ }
+
+ if (bn_wexpand(ret,nl) == NULL) return(0);
+ ret->top=nl;
+ ret->neg=r->neg;
+
+ rp=ret->d;
+ ap=&(r->d[nl]);
+
+#define BRANCH_FREE 1
+#if BRANCH_FREE
+ {
+ BN_ULONG *nrp;
+ size_t m;
+
+ v=bn_sub_words(rp,ap,np,nl)-carry;
+ /* if subtraction result is real, then
+ * trick unconditional memcpy below to perform in-place
+ * "refresh" instead of actual copy. */
+ m=(0-(size_t)v);
+ nrp=(BN_ULONG *)(((PTR_SIZE_INT)rp&~m)|((PTR_SIZE_INT)ap&m));
+
+ for (i=0,nl-=4; i<nl; i+=4)
+ {
+ BN_ULONG t1,t2,t3,t4;
+
+ t1=nrp[i+0];
+ t2=nrp[i+1];
+ t3=nrp[i+2]; ap[i+0]=0;
+ t4=nrp[i+3]; ap[i+1]=0;
+ rp[i+0]=t1; ap[i+2]=0;
+ rp[i+1]=t2; ap[i+3]=0;
+ rp[i+2]=t3;
+ rp[i+3]=t4;
+ }
+ for (nl+=4; i<nl; i++)
+ rp[i]=nrp[i], ap[i]=0;
+ }
+#else
+ if (bn_sub_words (rp,ap,np,nl)-carry)
+ memcpy(rp,ap,nl*sizeof(BN_ULONG));
+#endif
+ bn_correct_top(r);
+ bn_correct_top(ret);
+ bn_check_top(ret);
+
+ return(1);
+ }
+#endif /* MONT_WORD */
+
+int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont,
+ BN_CTX *ctx)
+ {
+ int retn=0;
+#ifdef MONT_WORD
+ BIGNUM *t;
+
+ BN_CTX_start(ctx);
+ if ((t = BN_CTX_get(ctx)) && BN_copy(t,a))
+ retn = BN_from_montgomery_word(ret,t,mont);
+ BN_CTX_end(ctx);
+#else /* !MONT_WORD */
+ BIGNUM *t1,*t2;
+
+ BN_CTX_start(ctx);
+ t1 = BN_CTX_get(ctx);
+ t2 = BN_CTX_get(ctx);
+ if (t1 == NULL || t2 == NULL) goto err;
+
+ if (!BN_copy(t1,a)) goto err;
+ BN_mask_bits(t1,mont->ri);
+
+ if (!BN_mul(t2,t1,&mont->Ni,ctx)) goto err;
+ BN_mask_bits(t2,mont->ri);
+
+ if (!BN_mul(t1,t2,&mont->N,ctx)) goto err;
+ if (!BN_add(t2,a,t1)) goto err;
+ if (!BN_rshift(ret,t2,mont->ri)) goto err;
+
+ if (BN_ucmp(ret, &(mont->N)) >= 0)
+ {
+ if (!BN_usub(ret,ret,&(mont->N))) goto err;
+ }
+ retn=1;
+ bn_check_top(ret);
+ err:
+ BN_CTX_end(ctx);
+#endif /* MONT_WORD */
+ return(retn);
+ }
+
+BN_MONT_CTX *BN_MONT_CTX_new(void)
+ {
+ BN_MONT_CTX *ret;
+
+ if ((ret=(BN_MONT_CTX *)OPENSSL_malloc(sizeof(BN_MONT_CTX))) == NULL)
+ return(NULL);
+
+ BN_MONT_CTX_init(ret);
+ ret->flags=BN_FLG_MALLOCED;
+ return(ret);
+ }
+
+void BN_MONT_CTX_init(BN_MONT_CTX *ctx)
+ {
+ ctx->ri=0;
+ BN_init(&(ctx->RR));
+ BN_init(&(ctx->N));
+ BN_init(&(ctx->Ni));
+ ctx->n0[0] = ctx->n0[1] = 0;
+ ctx->flags=0;
+ }
+
+void BN_MONT_CTX_free(BN_MONT_CTX *mont)
+ {
+ if(mont == NULL)
+ return;
+
+ BN_free(&(mont->RR));
+ BN_free(&(mont->N));
+ BN_free(&(mont->Ni));
+ if (mont->flags & BN_FLG_MALLOCED)
+ OPENSSL_free(mont);
+ }
+
+int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx)
+ {
+ int ret = 0;
+ BIGNUM *Ri,*R;
+
+ BN_CTX_start(ctx);
+ if((Ri = BN_CTX_get(ctx)) == NULL) goto err;
+ R= &(mont->RR); /* grab RR as a temp */
+ if (!BN_copy(&(mont->N),mod)) goto err; /* Set N */
+ mont->N.neg = 0;
+
+#ifdef MONT_WORD
+ {
+ BIGNUM tmod;
+ BN_ULONG buf[2];
+
+ BN_init(&tmod);
+ tmod.d=buf;
+ tmod.dmax=2;
+ tmod.neg=0;
+
+ mont->ri=(BN_num_bits(mod)+(BN_BITS2-1))/BN_BITS2*BN_BITS2;
+
+#if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2<=32)
+ /* Only certain BN_BITS2<=32 platforms actually make use of
+ * n0[1], and we could use the #else case (with a shorter R
+ * value) for the others. However, currently only the assembler
+ * files do know which is which. */
+
+ BN_zero(R);
+ if (!(BN_set_bit(R,2*BN_BITS2))) goto err;
+
+ tmod.top=0;
+ if ((buf[0] = mod->d[0])) tmod.top=1;
+ if ((buf[1] = mod->top>1 ? mod->d[1] : 0)) tmod.top=2;
+
+ if ((BN_mod_inverse(Ri,R,&tmod,ctx)) == NULL)
+ goto err;
+ if (!BN_lshift(Ri,Ri,2*BN_BITS2)) goto err; /* R*Ri */
+ if (!BN_is_zero(Ri))
+ {
+ if (!BN_sub_word(Ri,1)) goto err;
+ }
+ else /* if N mod word size == 1 */
+ {
+ if (bn_expand(Ri,(int)sizeof(BN_ULONG)*2) == NULL)
+ goto err;
+ /* Ri-- (mod double word size) */
+ Ri->neg=0;
+ Ri->d[0]=BN_MASK2;
+ Ri->d[1]=BN_MASK2;
+ Ri->top=2;
+ }
+ if (!BN_div(Ri,NULL,Ri,&tmod,ctx)) goto err;
+ /* Ni = (R*Ri-1)/N,
+ * keep only couple of least significant words: */
+ mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
+ mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0;
+#else
+ BN_zero(R);
+ if (!(BN_set_bit(R,BN_BITS2))) goto err; /* R */
+
+ buf[0]=mod->d[0]; /* tmod = N mod word size */
+ buf[1]=0;
+ tmod.top = buf[0] != 0 ? 1 : 0;
+ /* Ri = R^-1 mod N*/
+ if ((BN_mod_inverse(Ri,R,&tmod,ctx)) == NULL)
+ goto err;
+ if (!BN_lshift(Ri,Ri,BN_BITS2)) goto err; /* R*Ri */
+ if (!BN_is_zero(Ri))
+ {
+ if (!BN_sub_word(Ri,1)) goto err;
+ }
+ else /* if N mod word size == 1 */
+ {
+ if (!BN_set_word(Ri,BN_MASK2)) goto err; /* Ri-- (mod word size) */
+ }
+ if (!BN_div(Ri,NULL,Ri,&tmod,ctx)) goto err;
+ /* Ni = (R*Ri-1)/N,
+ * keep only least significant word: */
+ mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
+ mont->n0[1] = 0;
+#endif
+ }
+#else /* !MONT_WORD */
+ { /* bignum version */
+ mont->ri=BN_num_bits(&mont->N);
+ BN_zero(R);
+ if (!BN_set_bit(R,mont->ri)) goto err; /* R = 2^ri */
+ /* Ri = R^-1 mod N*/
+ if ((BN_mod_inverse(Ri,R,&mont->N,ctx)) == NULL)
+ goto err;
+ if (!BN_lshift(Ri,Ri,mont->ri)) goto err; /* R*Ri */
+ if (!BN_sub_word(Ri,1)) goto err;
+ /* Ni = (R*Ri-1) / N */
+ if (!BN_div(&(mont->Ni),NULL,Ri,&mont->N,ctx)) goto err;
+ }
+#endif
+
+ /* setup RR for conversions */
+ BN_zero(&(mont->RR));
+ if (!BN_set_bit(&(mont->RR),mont->ri*2)) goto err;
+ if (!BN_mod(&(mont->RR),&(mont->RR),&(mont->N),ctx)) goto err;
+
+ ret = 1;
+err:
+ BN_CTX_end(ctx);
+ return ret;
+ }
+
+BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from)
+ {
+ if (to == from) return(to);
+
+ if (!BN_copy(&(to->RR),&(from->RR))) return NULL;
+ if (!BN_copy(&(to->N),&(from->N))) return NULL;
+ if (!BN_copy(&(to->Ni),&(from->Ni))) return NULL;
+ to->ri=from->ri;
+ to->n0[0]=from->n0[0];
+ to->n0[1]=from->n0[1];
+ return(to);
+ }
+
+BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
+ const BIGNUM *mod, BN_CTX *ctx)
+ {
+ BN_MONT_CTX *ret;
+
+ CRYPTO_r_lock(lock);
+ ret = *pmont;
+ CRYPTO_r_unlock(lock);
+ if (ret)
+ return ret;
+
+ /* We don't want to serialise globally while doing our lazy-init math in
+ * BN_MONT_CTX_set. That punishes threads that are doing independent
+ * things. Instead, punish the case where more than one thread tries to
+ * lazy-init the same 'pmont', by having each do the lazy-init math work
+ * independently and only use the one from the thread that wins the race
+ * (the losers throw away the work they've done). */
+ ret = BN_MONT_CTX_new();
+ if (!ret)
+ return NULL;
+ if (!BN_MONT_CTX_set(ret, mod, ctx))
+ {
+ BN_MONT_CTX_free(ret);
+ return NULL;
+ }
+
+ /* The locked compare-and-set, after the local work is done. */
+ CRYPTO_w_lock(lock);
+ if (*pmont)
+ {
+ BN_MONT_CTX_free(ret);
+ ret = *pmont;
+ }
+ else
+ *pmont = ret;
+ CRYPTO_w_unlock(lock);
+ return ret;
+ }
diff --git a/drivers/builtin_openssl/crypto/bn/bn_mpi.c b/drivers/builtin_openssl2/crypto/bn/bn_mpi.c
index a054d21aed..a054d21aed 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_mpi.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_mpi.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_mul.c b/drivers/builtin_openssl2/crypto/bn/bn_mul.c
index 12e5be80eb..12e5be80eb 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_mul.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_mul.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_nist.c b/drivers/builtin_openssl2/crypto/bn/bn_nist.c
index e22968d4a3..e22968d4a3 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_nist.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_nist.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_prime.c b/drivers/builtin_openssl2/crypto/bn/bn_prime.c
index 7b25979dd1..7b25979dd1 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_prime.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_prime.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_prime.h b/drivers/builtin_openssl2/crypto/bn/bn_prime.h
index 51d2194feb..51d2194feb 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_prime.h
+++ b/drivers/builtin_openssl2/crypto/bn/bn_prime.h
diff --git a/drivers/builtin_openssl/crypto/bn/bn_prime.pl b/drivers/builtin_openssl2/crypto/bn/bn_prime.pl
index 3fafb6f3e9..3fafb6f3e9 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_prime.pl
+++ b/drivers/builtin_openssl2/crypto/bn/bn_prime.pl
diff --git a/drivers/builtin_openssl/crypto/bn/bn_print.c b/drivers/builtin_openssl2/crypto/bn/bn_print.c
index 1743b6a7e2..1743b6a7e2 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_print.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_print.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_rand.c b/drivers/builtin_openssl2/crypto/bn/bn_rand.c
index b376c28ff3..b376c28ff3 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_rand.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_rand.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_recp.c b/drivers/builtin_openssl2/crypto/bn/bn_recp.c
index 2e8efb8dae..2e8efb8dae 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_recp.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_recp.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_shift.c b/drivers/builtin_openssl2/crypto/bn/bn_shift.c
index a6fca2c424..a6fca2c424 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_shift.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_shift.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_sqr.c b/drivers/builtin_openssl2/crypto/bn/bn_sqr.c
index 270d0cd348..270d0cd348 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_sqr.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_sqr.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_sqrt.c b/drivers/builtin_openssl2/crypto/bn/bn_sqrt.c
index 6beaf9e5e5..6beaf9e5e5 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_sqrt.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_sqrt.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_word.c b/drivers/builtin_openssl2/crypto/bn/bn_word.c
index de83a15b99..de83a15b99 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_word.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_word.c
diff --git a/drivers/builtin_openssl/crypto/bn/bn_x931p.c b/drivers/builtin_openssl2/crypto/bn/bn_x931p.c
index 04c5c874ec..04c5c874ec 100644
--- a/drivers/builtin_openssl/crypto/bn/bn_x931p.c
+++ b/drivers/builtin_openssl2/crypto/bn/bn_x931p.c
diff --git a/drivers/builtin_openssl/crypto/bn/bnspeed.c b/drivers/builtin_openssl2/crypto/bn/bnspeed.c
index b554ac8cf8..b554ac8cf8 100644
--- a/drivers/builtin_openssl/crypto/bn/bnspeed.c
+++ b/drivers/builtin_openssl2/crypto/bn/bnspeed.c
diff --git a/drivers/builtin_openssl/crypto/bn/bntest.c b/drivers/builtin_openssl2/crypto/bn/bntest.c
index 06f5954acc..06f5954acc 100644
--- a/drivers/builtin_openssl/crypto/bn/bntest.c
+++ b/drivers/builtin_openssl2/crypto/bn/bntest.c
diff --git a/drivers/builtin_openssl/crypto/bn/divtest.c b/drivers/builtin_openssl2/crypto/bn/divtest.c
index d3fc688f33..d3fc688f33 100644
--- a/drivers/builtin_openssl/crypto/bn/divtest.c
+++ b/drivers/builtin_openssl2/crypto/bn/divtest.c
diff --git a/drivers/builtin_openssl/crypto/bn/exp.c b/drivers/builtin_openssl2/crypto/bn/exp.c
index 4865b0ef74..4865b0ef74 100644
--- a/drivers/builtin_openssl/crypto/bn/exp.c
+++ b/drivers/builtin_openssl2/crypto/bn/exp.c
diff --git a/drivers/builtin_openssl/crypto/bn/expspeed.c b/drivers/builtin_openssl2/crypto/bn/expspeed.c
index 4d5f221f33..4d5f221f33 100644
--- a/drivers/builtin_openssl/crypto/bn/expspeed.c
+++ b/drivers/builtin_openssl2/crypto/bn/expspeed.c
diff --git a/drivers/builtin_openssl/crypto/bn/exptest.c b/drivers/builtin_openssl2/crypto/bn/exptest.c
index 074a8e882a..074a8e882a 100644
--- a/drivers/builtin_openssl/crypto/bn/exptest.c
+++ b/drivers/builtin_openssl2/crypto/bn/exptest.c
diff --git a/drivers/builtin_openssl/crypto/bn/todo b/drivers/builtin_openssl2/crypto/bn/todo
index e47e381aea..e47e381aea 100644
--- a/drivers/builtin_openssl/crypto/bn/todo
+++ b/drivers/builtin_openssl2/crypto/bn/todo
diff --git a/drivers/builtin_openssl/crypto/bn/vms-helper.c b/drivers/builtin_openssl2/crypto/bn/vms-helper.c
index 4b63149bf3..4b63149bf3 100644
--- a/drivers/builtin_openssl/crypto/bn/vms-helper.c
+++ b/drivers/builtin_openssl2/crypto/bn/vms-helper.c
diff --git a/drivers/builtin_openssl/crypto/buffer/buf_err.c b/drivers/builtin_openssl2/crypto/buffer/buf_err.c
index 8f1de6192b..8f1de6192b 100644
--- a/drivers/builtin_openssl/crypto/buffer/buf_err.c
+++ b/drivers/builtin_openssl2/crypto/buffer/buf_err.c
diff --git a/drivers/builtin_openssl/crypto/buffer/buf_str.c b/drivers/builtin_openssl2/crypto/buffer/buf_str.c
index 151f5ea971..151f5ea971 100644
--- a/drivers/builtin_openssl/crypto/buffer/buf_str.c
+++ b/drivers/builtin_openssl2/crypto/buffer/buf_str.c
diff --git a/drivers/builtin_openssl/crypto/buffer/buffer.c b/drivers/builtin_openssl2/crypto/buffer/buffer.c
index d4a4ce43b3..d4a4ce43b3 100644
--- a/drivers/builtin_openssl/crypto/buffer/buffer.c
+++ b/drivers/builtin_openssl2/crypto/buffer/buffer.c
diff --git a/drivers/builtin_openssl/crypto/camellia/asm/cmll-x86.pl b/drivers/builtin_openssl2/crypto/camellia/asm/cmll-x86.pl
index c314d62312..c314d62312 100644
--- a/drivers/builtin_openssl/crypto/camellia/asm/cmll-x86.pl
+++ b/drivers/builtin_openssl2/crypto/camellia/asm/cmll-x86.pl
diff --git a/drivers/builtin_openssl/crypto/camellia/asm/cmll-x86_64.pl b/drivers/builtin_openssl2/crypto/camellia/asm/cmll-x86_64.pl
index 9f4b82fa48..9f4b82fa48 100644
--- a/drivers/builtin_openssl/crypto/camellia/asm/cmll-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/camellia/asm/cmll-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/camellia/camellia.c b/drivers/builtin_openssl2/crypto/camellia/camellia.c
index 75fc8991c0..75fc8991c0 100644
--- a/drivers/builtin_openssl/crypto/camellia/camellia.c
+++ b/drivers/builtin_openssl2/crypto/camellia/camellia.c
diff --git a/drivers/builtin_openssl/crypto/camellia/cmll_cbc.c b/drivers/builtin_openssl2/crypto/camellia/cmll_cbc.c
index 4c8d455ade..4c8d455ade 100644
--- a/drivers/builtin_openssl/crypto/camellia/cmll_cbc.c
+++ b/drivers/builtin_openssl2/crypto/camellia/cmll_cbc.c
diff --git a/drivers/builtin_openssl/crypto/camellia/cmll_cfb.c b/drivers/builtin_openssl2/crypto/camellia/cmll_cfb.c
index 3d81b51d3f..3d81b51d3f 100644
--- a/drivers/builtin_openssl/crypto/camellia/cmll_cfb.c
+++ b/drivers/builtin_openssl2/crypto/camellia/cmll_cfb.c
diff --git a/drivers/builtin_openssl/crypto/camellia/cmll_ctr.c b/drivers/builtin_openssl2/crypto/camellia/cmll_ctr.c
index 014e621a34..014e621a34 100644
--- a/drivers/builtin_openssl/crypto/camellia/cmll_ctr.c
+++ b/drivers/builtin_openssl2/crypto/camellia/cmll_ctr.c
diff --git a/drivers/builtin_openssl/crypto/camellia/cmll_ecb.c b/drivers/builtin_openssl2/crypto/camellia/cmll_ecb.c
index 70dc0e5632..70dc0e5632 100644
--- a/drivers/builtin_openssl/crypto/camellia/cmll_ecb.c
+++ b/drivers/builtin_openssl2/crypto/camellia/cmll_ecb.c
diff --git a/drivers/builtin_openssl/crypto/camellia/cmll_locl.h b/drivers/builtin_openssl2/crypto/camellia/cmll_locl.h
index 246b6ce1d8..246b6ce1d8 100644
--- a/drivers/builtin_openssl/crypto/camellia/cmll_locl.h
+++ b/drivers/builtin_openssl2/crypto/camellia/cmll_locl.h
diff --git a/drivers/builtin_openssl/crypto/camellia/cmll_misc.c b/drivers/builtin_openssl2/crypto/camellia/cmll_misc.c
index f44d48564c..f44d48564c 100644
--- a/drivers/builtin_openssl/crypto/camellia/cmll_misc.c
+++ b/drivers/builtin_openssl2/crypto/camellia/cmll_misc.c
diff --git a/drivers/builtin_openssl/crypto/camellia/cmll_ofb.c b/drivers/builtin_openssl2/crypto/camellia/cmll_ofb.c
index a482befc74..a482befc74 100644
--- a/drivers/builtin_openssl/crypto/camellia/cmll_ofb.c
+++ b/drivers/builtin_openssl2/crypto/camellia/cmll_ofb.c
diff --git a/drivers/builtin_openssl/crypto/camellia/cmll_utl.c b/drivers/builtin_openssl2/crypto/camellia/cmll_utl.c
index 7a35711ec1..7a35711ec1 100644
--- a/drivers/builtin_openssl/crypto/camellia/cmll_utl.c
+++ b/drivers/builtin_openssl2/crypto/camellia/cmll_utl.c
diff --git a/drivers/builtin_openssl/crypto/cast/asm/cast-586.pl b/drivers/builtin_openssl2/crypto/cast/asm/cast-586.pl
index bf6810d335..bf6810d335 100644
--- a/drivers/builtin_openssl/crypto/cast/asm/cast-586.pl
+++ b/drivers/builtin_openssl2/crypto/cast/asm/cast-586.pl
diff --git a/drivers/builtin_openssl/crypto/cast/asm/readme b/drivers/builtin_openssl2/crypto/cast/asm/readme
index fbcd76289e..fbcd76289e 100644
--- a/drivers/builtin_openssl/crypto/cast/asm/readme
+++ b/drivers/builtin_openssl2/crypto/cast/asm/readme
diff --git a/drivers/builtin_openssl/crypto/cast/c_cfb64.c b/drivers/builtin_openssl2/crypto/cast/c_cfb64.c
index dcec13a201..dcec13a201 100644
--- a/drivers/builtin_openssl/crypto/cast/c_cfb64.c
+++ b/drivers/builtin_openssl2/crypto/cast/c_cfb64.c
diff --git a/drivers/builtin_openssl/crypto/cast/c_ecb.c b/drivers/builtin_openssl2/crypto/cast/c_ecb.c
index b6a3b1fff9..b6a3b1fff9 100644
--- a/drivers/builtin_openssl/crypto/cast/c_ecb.c
+++ b/drivers/builtin_openssl2/crypto/cast/c_ecb.c
diff --git a/drivers/builtin_openssl/crypto/cast/c_enc.c b/drivers/builtin_openssl2/crypto/cast/c_enc.c
index 357c41ebf0..357c41ebf0 100644
--- a/drivers/builtin_openssl/crypto/cast/c_enc.c
+++ b/drivers/builtin_openssl2/crypto/cast/c_enc.c
diff --git a/drivers/builtin_openssl/crypto/cast/c_ofb64.c b/drivers/builtin_openssl2/crypto/cast/c_ofb64.c
index cb3222456c..cb3222456c 100644
--- a/drivers/builtin_openssl/crypto/cast/c_ofb64.c
+++ b/drivers/builtin_openssl2/crypto/cast/c_ofb64.c
diff --git a/drivers/builtin_openssl/crypto/cast/c_skey.c b/drivers/builtin_openssl2/crypto/cast/c_skey.c
index cb6bf9fee3..cb6bf9fee3 100644
--- a/drivers/builtin_openssl/crypto/cast/c_skey.c
+++ b/drivers/builtin_openssl2/crypto/cast/c_skey.c
diff --git a/drivers/builtin_openssl/crypto/cast/cast_lcl.h b/drivers/builtin_openssl2/crypto/cast/cast_lcl.h
index e756021a33..e756021a33 100644
--- a/drivers/builtin_openssl/crypto/cast/cast_lcl.h
+++ b/drivers/builtin_openssl2/crypto/cast/cast_lcl.h
diff --git a/drivers/builtin_openssl/crypto/cast/cast_s.h b/drivers/builtin_openssl2/crypto/cast/cast_s.h
index c483fd5e43..c483fd5e43 100644
--- a/drivers/builtin_openssl/crypto/cast/cast_s.h
+++ b/drivers/builtin_openssl2/crypto/cast/cast_s.h
diff --git a/drivers/builtin_openssl/crypto/cast/cast_spd.c b/drivers/builtin_openssl2/crypto/cast/cast_spd.c
index d650af475c..d650af475c 100644
--- a/drivers/builtin_openssl/crypto/cast/cast_spd.c
+++ b/drivers/builtin_openssl2/crypto/cast/cast_spd.c
diff --git a/drivers/builtin_openssl/crypto/cast/castopts.c b/drivers/builtin_openssl2/crypto/cast/castopts.c
index 33b2c7b06f..33b2c7b06f 100644
--- a/drivers/builtin_openssl/crypto/cast/castopts.c
+++ b/drivers/builtin_openssl2/crypto/cast/castopts.c
diff --git a/drivers/builtin_openssl/crypto/cast/casts.cpp b/drivers/builtin_openssl2/crypto/cast/casts.cpp
index 8d7bd468d2..8d7bd468d2 100644
--- a/drivers/builtin_openssl/crypto/cast/casts.cpp
+++ b/drivers/builtin_openssl2/crypto/cast/casts.cpp
diff --git a/drivers/builtin_openssl/crypto/cast/casttest.c b/drivers/builtin_openssl2/crypto/cast/casttest.c
index 0d020d6975..0d020d6975 100644
--- a/drivers/builtin_openssl/crypto/cast/casttest.c
+++ b/drivers/builtin_openssl2/crypto/cast/casttest.c
diff --git a/drivers/builtin_openssl/crypto/cmac/cm_ameth.c b/drivers/builtin_openssl2/crypto/cmac/cm_ameth.c
index 0b8e5670b0..0b8e5670b0 100644
--- a/drivers/builtin_openssl/crypto/cmac/cm_ameth.c
+++ b/drivers/builtin_openssl2/crypto/cmac/cm_ameth.c
diff --git a/drivers/builtin_openssl/crypto/cmac/cm_pmeth.c b/drivers/builtin_openssl2/crypto/cmac/cm_pmeth.c
index 072228ec7f..072228ec7f 100644
--- a/drivers/builtin_openssl/crypto/cmac/cm_pmeth.c
+++ b/drivers/builtin_openssl2/crypto/cmac/cm_pmeth.c
diff --git a/drivers/builtin_openssl/crypto/cmac/cmac.c b/drivers/builtin_openssl2/crypto/cmac/cmac.c
index 8b72b09681..8b72b09681 100644
--- a/drivers/builtin_openssl/crypto/cmac/cmac.c
+++ b/drivers/builtin_openssl2/crypto/cmac/cmac.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_asn1.c b/drivers/builtin_openssl2/crypto/cms/cms_asn1.c
index cfe67fb6c1..cfe67fb6c1 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_asn1.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_asn1.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_att.c b/drivers/builtin_openssl2/crypto/cms/cms_att.c
index 5b71722ebc..5b71722ebc 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_att.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_att.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_cd.c b/drivers/builtin_openssl2/crypto/cms/cms_cd.c
index 2021688101..2021688101 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_cd.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_cd.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_dd.c b/drivers/builtin_openssl2/crypto/cms/cms_dd.c
index 8919c15be1..8919c15be1 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_dd.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_dd.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_enc.c b/drivers/builtin_openssl2/crypto/cms/cms_enc.c
index bebeaf29c7..bebeaf29c7 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_enc.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_enc.c
diff --git a/drivers/builtin_openssl2/crypto/cms/cms_env.c b/drivers/builtin_openssl2/crypto/cms/cms_env.c
new file mode 100644
index 0000000000..add00bf99c
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/cms/cms_env.c
@@ -0,0 +1,878 @@
+/* crypto/cms/cms_env.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2008 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 "cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#include "cms_lcl.h"
+#include "asn1_locl.h"
+
+/* CMS EnvelopedData Utilities */
+
+DECLARE_ASN1_ITEM(CMS_EnvelopedData)
+DECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo)
+DECLARE_ASN1_ITEM(CMS_KEKRecipientInfo)
+DECLARE_ASN1_ITEM(CMS_OtherKeyAttribute)
+
+DECLARE_STACK_OF(CMS_RecipientInfo)
+
+CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
+ {
+ if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped)
+ {
+ CMSerr(CMS_F_CMS_GET0_ENVELOPED,
+ CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
+ return NULL;
+ }
+ return cms->d.envelopedData;
+ }
+
+static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
+ {
+ if (cms->d.other == NULL)
+ {
+ cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData);
+ if (!cms->d.envelopedData)
+ {
+ CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT,
+ ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ cms->d.envelopedData->version = 0;
+ cms->d.envelopedData->encryptedContentInfo->contentType =
+ OBJ_nid2obj(NID_pkcs7_data);
+ ASN1_OBJECT_free(cms->contentType);
+ cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped);
+ return cms->d.envelopedData;
+ }
+ return cms_get0_enveloped(cms);
+ }
+
+STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms)
+ {
+ CMS_EnvelopedData *env;
+ env = cms_get0_enveloped(cms);
+ if (!env)
+ return NULL;
+ return env->recipientInfos;
+ }
+
+int CMS_RecipientInfo_type(CMS_RecipientInfo *ri)
+ {
+ return ri->type;
+ }
+
+CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
+ {
+ CMS_ContentInfo *cms;
+ CMS_EnvelopedData *env;
+ cms = CMS_ContentInfo_new();
+ if (!cms)
+ goto merr;
+ env = cms_enveloped_data_init(cms);
+ if (!env)
+ goto merr;
+ if (!cms_EncryptedContent_init(env->encryptedContentInfo,
+ cipher, NULL, 0))
+ goto merr;
+ return cms;
+ merr:
+ if (cms)
+ CMS_ContentInfo_free(cms);
+ CMSerr(CMS_F_CMS_ENVELOPEDDATA_CREATE, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+/* Key Transport Recipient Info (KTRI) routines */
+
+/* Add a recipient certificate. For now only handle key transport.
+ * If we ever handle key agreement will need updating.
+ */
+
+CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
+ X509 *recip, unsigned int flags)
+ {
+ CMS_RecipientInfo *ri = NULL;
+ CMS_KeyTransRecipientInfo *ktri;
+ CMS_EnvelopedData *env;
+ EVP_PKEY *pk = NULL;
+ int i, type;
+ env = cms_get0_enveloped(cms);
+ if (!env)
+ goto err;
+
+ /* Initialize recipient info */
+ ri = M_ASN1_new_of(CMS_RecipientInfo);
+ if (!ri)
+ goto merr;
+
+ /* Initialize and add key transport recipient info */
+
+ ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo);
+ if (!ri->d.ktri)
+ goto merr;
+ ri->type = CMS_RECIPINFO_TRANS;
+
+ ktri = ri->d.ktri;
+
+ X509_check_purpose(recip, -1, -1);
+ pk = X509_get_pubkey(recip);
+ if (!pk)
+ {
+ CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
+ CMS_R_ERROR_GETTING_PUBLIC_KEY);
+ goto err;
+ }
+ CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509);
+ ktri->pkey = pk;
+ ktri->recip = recip;
+
+ if (flags & CMS_USE_KEYID)
+ {
+ ktri->version = 2;
+ if (env->version < 2)
+ env->version = 2;
+ type = CMS_RECIPINFO_KEYIDENTIFIER;
+ }
+ else
+ {
+ ktri->version = 0;
+ type = CMS_RECIPINFO_ISSUER_SERIAL;
+ }
+
+ /* Not a typo: RecipientIdentifier and SignerIdentifier are the
+ * same structure.
+ */
+
+ if (!cms_set1_SignerIdentifier(ktri->rid, recip, type))
+ goto err;
+
+ if (pk->ameth && pk->ameth->pkey_ctrl)
+ {
+ i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_ENVELOPE,
+ 0, ri);
+ if (i == -2)
+ {
+ CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
+ CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+ goto err;
+ }
+ if (i <= 0)
+ {
+ CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
+ CMS_R_CTRL_FAILURE);
+ goto err;
+ }
+ }
+
+ if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
+ goto merr;
+
+ return ri;
+
+ merr:
+ CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE);
+ err:
+ if (ri)
+ M_ASN1_free_of(ri, CMS_RecipientInfo);
+ return NULL;
+
+ }
+
+int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
+ EVP_PKEY **pk, X509 **recip,
+ X509_ALGOR **palg)
+ {
+ CMS_KeyTransRecipientInfo *ktri;
+ if (ri->type != CMS_RECIPINFO_TRANS)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS,
+ CMS_R_NOT_KEY_TRANSPORT);
+ return 0;
+ }
+
+ ktri = ri->d.ktri;
+
+ if (pk)
+ *pk = ktri->pkey;
+ if (recip)
+ *recip = ktri->recip;
+ if (palg)
+ *palg = ktri->keyEncryptionAlgorithm;
+ return 1;
+ }
+
+int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
+ ASN1_OCTET_STRING **keyid,
+ X509_NAME **issuer, ASN1_INTEGER **sno)
+ {
+ CMS_KeyTransRecipientInfo *ktri;
+ if (ri->type != CMS_RECIPINFO_TRANS)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID,
+ CMS_R_NOT_KEY_TRANSPORT);
+ return 0;
+ }
+ ktri = ri->d.ktri;
+
+ return cms_SignerIdentifier_get0_signer_id(ktri->rid,
+ keyid, issuer, sno);
+ }
+
+int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert)
+ {
+ if (ri->type != CMS_RECIPINFO_TRANS)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP,
+ CMS_R_NOT_KEY_TRANSPORT);
+ return -2;
+ }
+ return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert);
+ }
+
+int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey)
+ {
+ if (ri->type != CMS_RECIPINFO_TRANS)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY,
+ CMS_R_NOT_KEY_TRANSPORT);
+ return 0;
+ }
+ ri->d.ktri->pkey = pkey;
+ return 1;
+ }
+
+/* Encrypt content key in key transport recipient info */
+
+static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri)
+ {
+ CMS_KeyTransRecipientInfo *ktri;
+ CMS_EncryptedContentInfo *ec;
+ EVP_PKEY_CTX *pctx = NULL;
+ unsigned char *ek = NULL;
+ size_t eklen;
+
+ int ret = 0;
+
+ if (ri->type != CMS_RECIPINFO_TRANS)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT,
+ CMS_R_NOT_KEY_TRANSPORT);
+ return 0;
+ }
+ ktri = ri->d.ktri;
+ ec = cms->d.envelopedData->encryptedContentInfo;
+
+ pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
+ if (!pctx)
+ return 0;
+
+ if (EVP_PKEY_encrypt_init(pctx) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
+ EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_CTRL_ERROR);
+ goto err;
+ }
+
+ if (EVP_PKEY_encrypt(pctx, NULL, &eklen, ec->key, ec->keylen) <= 0)
+ goto err;
+
+ ek = OPENSSL_malloc(eklen);
+
+ if (ek == NULL)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (EVP_PKEY_encrypt(pctx, ek, &eklen, ec->key, ec->keylen) <= 0)
+ goto err;
+
+ ASN1_STRING_set0(ktri->encryptedKey, ek, eklen);
+ ek = NULL;
+
+ ret = 1;
+
+ err:
+ if (pctx)
+ EVP_PKEY_CTX_free(pctx);
+ if (ek)
+ OPENSSL_free(ek);
+ return ret;
+
+ }
+
+/* Decrypt content key from KTRI */
+
+static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri)
+ {
+ CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
+ EVP_PKEY_CTX *pctx = NULL;
+ unsigned char *ek = NULL;
+ size_t eklen;
+ int ret = 0;
+ CMS_EncryptedContentInfo *ec;
+ ec = cms->d.envelopedData->encryptedContentInfo;
+
+ if (ktri->pkey == NULL)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT,
+ CMS_R_NO_PRIVATE_KEY);
+ return 0;
+ }
+
+ pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
+ if (!pctx)
+ return 0;
+
+ if (EVP_PKEY_decrypt_init(pctx) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
+ EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR);
+ goto err;
+ }
+
+ if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
+ ktri->encryptedKey->data,
+ ktri->encryptedKey->length) <= 0)
+ goto err;
+
+ ek = OPENSSL_malloc(eklen);
+
+ if (ek == NULL)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (EVP_PKEY_decrypt(pctx, ek, &eklen,
+ ktri->encryptedKey->data,
+ ktri->encryptedKey->length) <= 0)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB);
+ goto err;
+ }
+
+ ret = 1;
+
+ if (ec->key)
+ {
+ OPENSSL_cleanse(ec->key, ec->keylen);
+ OPENSSL_free(ec->key);
+ }
+
+ ec->key = ek;
+ ec->keylen = eklen;
+
+ err:
+ if (pctx)
+ EVP_PKEY_CTX_free(pctx);
+ if (!ret && ek)
+ OPENSSL_free(ek);
+
+ return ret;
+ }
+
+/* Key Encrypted Key (KEK) RecipientInfo routines */
+
+int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri,
+ const unsigned char *id, size_t idlen)
+ {
+ ASN1_OCTET_STRING tmp_os;
+ CMS_KEKRecipientInfo *kekri;
+ if (ri->type != CMS_RECIPINFO_KEK)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP, CMS_R_NOT_KEK);
+ return -2;
+ }
+ kekri = ri->d.kekri;
+ tmp_os.type = V_ASN1_OCTET_STRING;
+ tmp_os.flags = 0;
+ tmp_os.data = (unsigned char *)id;
+ tmp_os.length = (int)idlen;
+ return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier);
+ }
+
+/* For now hard code AES key wrap info */
+
+static size_t aes_wrap_keylen(int nid)
+ {
+ switch (nid)
+ {
+ case NID_id_aes128_wrap:
+ return 16;
+
+ case NID_id_aes192_wrap:
+ return 24;
+
+ case NID_id_aes256_wrap:
+ return 32;
+
+ default:
+ return 0;
+ }
+ }
+
+CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
+ unsigned char *key, size_t keylen,
+ unsigned char *id, size_t idlen,
+ ASN1_GENERALIZEDTIME *date,
+ ASN1_OBJECT *otherTypeId,
+ ASN1_TYPE *otherType)
+ {
+ CMS_RecipientInfo *ri = NULL;
+ CMS_EnvelopedData *env;
+ CMS_KEKRecipientInfo *kekri;
+ env = cms_get0_enveloped(cms);
+ if (!env)
+ goto err;
+
+ if (nid == NID_undef)
+ {
+ switch (keylen)
+ {
+ case 16:
+ nid = NID_id_aes128_wrap;
+ break;
+
+ case 24:
+ nid = NID_id_aes192_wrap;
+ break;
+
+ case 32:
+ nid = NID_id_aes256_wrap;
+ break;
+
+ default:
+ CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
+ CMS_R_INVALID_KEY_LENGTH);
+ goto err;
+ }
+
+ }
+ else
+ {
+
+ size_t exp_keylen = aes_wrap_keylen(nid);
+
+ if (!exp_keylen)
+ {
+ CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
+ CMS_R_UNSUPPORTED_KEK_ALGORITHM);
+ goto err;
+ }
+
+ if (keylen != exp_keylen)
+ {
+ CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
+ CMS_R_INVALID_KEY_LENGTH);
+ goto err;
+ }
+
+ }
+
+ /* Initialize recipient info */
+ ri = M_ASN1_new_of(CMS_RecipientInfo);
+ if (!ri)
+ goto merr;
+
+ ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo);
+ if (!ri->d.kekri)
+ goto merr;
+ ri->type = CMS_RECIPINFO_KEK;
+
+ kekri = ri->d.kekri;
+
+ if (otherTypeId)
+ {
+ kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute);
+ if (kekri->kekid->other == NULL)
+ goto merr;
+ }
+
+ if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
+ goto merr;
+
+
+ /* After this point no calls can fail */
+
+ kekri->version = 4;
+
+ kekri->key = key;
+ kekri->keylen = keylen;
+
+ ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen);
+
+ kekri->kekid->date = date;
+
+ if (kekri->kekid->other)
+ {
+ kekri->kekid->other->keyAttrId = otherTypeId;
+ kekri->kekid->other->keyAttr = otherType;
+ }
+
+ X509_ALGOR_set0(kekri->keyEncryptionAlgorithm,
+ OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL);
+
+ return ri;
+
+ merr:
+ CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE);
+ err:
+ if (ri)
+ M_ASN1_free_of(ri, CMS_RecipientInfo);
+ return NULL;
+
+ }
+
+int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
+ X509_ALGOR **palg,
+ ASN1_OCTET_STRING **pid,
+ ASN1_GENERALIZEDTIME **pdate,
+ ASN1_OBJECT **potherid,
+ ASN1_TYPE **pothertype)
+ {
+ CMS_KEKIdentifier *rkid;
+ if (ri->type != CMS_RECIPINFO_KEK)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK);
+ return 0;
+ }
+ rkid = ri->d.kekri->kekid;
+ if (palg)
+ *palg = ri->d.kekri->keyEncryptionAlgorithm;
+ if (pid)
+ *pid = rkid->keyIdentifier;
+ if (pdate)
+ *pdate = rkid->date;
+ if (potherid)
+ {
+ if (rkid->other)
+ *potherid = rkid->other->keyAttrId;
+ else
+ *potherid = NULL;
+ }
+ if (pothertype)
+ {
+ if (rkid->other)
+ *pothertype = rkid->other->keyAttr;
+ else
+ *pothertype = NULL;
+ }
+ return 1;
+ }
+
+int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
+ unsigned char *key, size_t keylen)
+ {
+ CMS_KEKRecipientInfo *kekri;
+ if (ri->type != CMS_RECIPINFO_KEK)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK);
+ return 0;
+ }
+
+ kekri = ri->d.kekri;
+ kekri->key = key;
+ kekri->keylen = keylen;
+ return 1;
+ }
+
+
+/* Encrypt content key in KEK recipient info */
+
+static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri)
+ {
+ CMS_EncryptedContentInfo *ec;
+ CMS_KEKRecipientInfo *kekri;
+ AES_KEY actx;
+ unsigned char *wkey = NULL;
+ int wkeylen;
+ int r = 0;
+
+ ec = cms->d.envelopedData->encryptedContentInfo;
+
+ kekri = ri->d.kekri;
+
+ if (!kekri->key)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY);
+ return 0;
+ }
+
+ if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx))
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
+ CMS_R_ERROR_SETTING_KEY);
+ goto err;
+ }
+
+ wkey = OPENSSL_malloc(ec->keylen + 8);
+
+ if (!wkey)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen);
+
+ if (wkeylen <= 0)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR);
+ goto err;
+ }
+
+ ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen);
+
+ r = 1;
+
+ err:
+
+ if (!r && wkey)
+ OPENSSL_free(wkey);
+ OPENSSL_cleanse(&actx, sizeof(actx));
+
+ return r;
+
+ }
+
+/* Decrypt content key in KEK recipient info */
+
+static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri)
+ {
+ CMS_EncryptedContentInfo *ec;
+ CMS_KEKRecipientInfo *kekri;
+ AES_KEY actx;
+ unsigned char *ukey = NULL;
+ int ukeylen;
+ int r = 0, wrap_nid;
+
+ ec = cms->d.envelopedData->encryptedContentInfo;
+
+ kekri = ri->d.kekri;
+
+ if (!kekri->key)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY);
+ return 0;
+ }
+
+ wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm);
+ if (aes_wrap_keylen(wrap_nid) != kekri->keylen)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ CMS_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+
+ /* If encrypted key length is invalid don't bother */
+
+ if (kekri->encryptedKey->length < 16)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ CMS_R_INVALID_ENCRYPTED_KEY_LENGTH);
+ goto err;
+ }
+
+ if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx))
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ CMS_R_ERROR_SETTING_KEY);
+ goto err;
+ }
+
+ ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8);
+
+ if (!ukey)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ ukeylen = AES_unwrap_key(&actx, NULL, ukey,
+ kekri->encryptedKey->data,
+ kekri->encryptedKey->length);
+
+ if (ukeylen <= 0)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ CMS_R_UNWRAP_ERROR);
+ goto err;
+ }
+
+ ec->key = ukey;
+ ec->keylen = ukeylen;
+
+ r = 1;
+
+ err:
+
+ if (!r && ukey)
+ OPENSSL_free(ukey);
+ OPENSSL_cleanse(&actx, sizeof(actx));
+
+ return r;
+
+ }
+
+int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
+ {
+ switch(ri->type)
+ {
+ case CMS_RECIPINFO_TRANS:
+ return cms_RecipientInfo_ktri_decrypt(cms, ri);
+
+ case CMS_RECIPINFO_KEK:
+ return cms_RecipientInfo_kekri_decrypt(cms, ri);
+
+ case CMS_RECIPINFO_PASS:
+ return cms_RecipientInfo_pwri_crypt(cms, ri, 0);
+
+ default:
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT,
+ CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE);
+ return 0;
+ }
+ }
+
+BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
+ {
+ CMS_EncryptedContentInfo *ec;
+ STACK_OF(CMS_RecipientInfo) *rinfos;
+ CMS_RecipientInfo *ri;
+ int i, r, ok = 0;
+ BIO *ret;
+
+ /* Get BIO first to set up key */
+
+ ec = cms->d.envelopedData->encryptedContentInfo;
+ ret = cms_EncryptedContent_init_bio(ec);
+
+ /* If error or no cipher end of processing */
+
+ if (!ret || !ec->cipher)
+ return ret;
+
+ /* Now encrypt content key according to each RecipientInfo type */
+
+ rinfos = cms->d.envelopedData->recipientInfos;
+
+ for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++)
+ {
+ ri = sk_CMS_RecipientInfo_value(rinfos, i);
+
+ switch (ri->type)
+ {
+ case CMS_RECIPINFO_TRANS:
+ r = cms_RecipientInfo_ktri_encrypt(cms, ri);
+ break;
+
+ case CMS_RECIPINFO_KEK:
+ r = cms_RecipientInfo_kekri_encrypt(cms, ri);
+ break;
+
+ case CMS_RECIPINFO_PASS:
+ r = cms_RecipientInfo_pwri_crypt(cms, ri, 1);
+ break;
+
+ default:
+ CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
+ CMS_R_UNSUPPORTED_RECIPIENT_TYPE);
+ goto err;
+ }
+
+ if (r <= 0)
+ {
+ CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
+ CMS_R_ERROR_SETTING_RECIPIENTINFO);
+ goto err;
+ }
+ }
+
+ ok = 1;
+
+ err:
+ ec->cipher = NULL;
+ if (ec->key)
+ {
+ OPENSSL_cleanse(ec->key, ec->keylen);
+ OPENSSL_free(ec->key);
+ ec->key = NULL;
+ ec->keylen = 0;
+ }
+ if (ok)
+ return ret;
+ BIO_free(ret);
+ return NULL;
+
+ }
diff --git a/drivers/builtin_openssl/crypto/cms/cms_err.c b/drivers/builtin_openssl2/crypto/cms/cms_err.c
index 8330ead7ed..8330ead7ed 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_err.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_err.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_ess.c b/drivers/builtin_openssl2/crypto/cms/cms_ess.c
index 90c0b82fb5..90c0b82fb5 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_ess.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_ess.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_io.c b/drivers/builtin_openssl2/crypto/cms/cms_io.c
index 1cb0264cc5..1cb0264cc5 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_io.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_io.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_lcl.h b/drivers/builtin_openssl2/crypto/cms/cms_lcl.h
index a9f9730157..a9f9730157 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_lcl.h
+++ b/drivers/builtin_openssl2/crypto/cms/cms_lcl.h
diff --git a/drivers/builtin_openssl/crypto/cms/cms_lib.c b/drivers/builtin_openssl2/crypto/cms/cms_lib.c
index ba08279a04..ba08279a04 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_lib.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_lib.c
diff --git a/drivers/builtin_openssl/crypto/cms/cms_pwri.c b/drivers/builtin_openssl2/crypto/cms/cms_pwri.c
index b79612a12d..b79612a12d 100644
--- a/drivers/builtin_openssl/crypto/cms/cms_pwri.c
+++ b/drivers/builtin_openssl2/crypto/cms/cms_pwri.c
diff --git a/drivers/builtin_openssl2/crypto/cms/cms_sd.c b/drivers/builtin_openssl2/crypto/cms/cms_sd.c
new file mode 100644
index 0000000000..51dd33a1c3
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/cms/cms_sd.c
@@ -0,0 +1,985 @@
+/* crypto/cms/cms_sd.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2008 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 "cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include "cms_lcl.h"
+#include "asn1_locl.h"
+
+/* CMS SignedData Utilities */
+
+DECLARE_ASN1_ITEM(CMS_SignedData)
+
+static CMS_SignedData *cms_get0_signed(CMS_ContentInfo *cms)
+ {
+ if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_signed)
+ {
+ CMSerr(CMS_F_CMS_GET0_SIGNED, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA);
+ return NULL;
+ }
+ return cms->d.signedData;
+ }
+
+static CMS_SignedData *cms_signed_data_init(CMS_ContentInfo *cms)
+ {
+ if (cms->d.other == NULL)
+ {
+ cms->d.signedData = M_ASN1_new_of(CMS_SignedData);
+ if (!cms->d.signedData)
+ {
+ CMSerr(CMS_F_CMS_SIGNED_DATA_INIT, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ cms->d.signedData->version = 1;
+ cms->d.signedData->encapContentInfo->eContentType =
+ OBJ_nid2obj(NID_pkcs7_data);
+ cms->d.signedData->encapContentInfo->partial = 1;
+ ASN1_OBJECT_free(cms->contentType);
+ cms->contentType = OBJ_nid2obj(NID_pkcs7_signed);
+ return cms->d.signedData;
+ }
+ return cms_get0_signed(cms);
+ }
+
+/* Just initialize SignedData e.g. for certs only structure */
+
+int CMS_SignedData_init(CMS_ContentInfo *cms)
+ {
+ if (cms_signed_data_init(cms))
+ return 1;
+ else
+ return 0;
+ }
+
+/* Check structures and fixup version numbers (if necessary) */
+
+static void cms_sd_set_version(CMS_SignedData *sd)
+ {
+ int i;
+ CMS_CertificateChoices *cch;
+ CMS_RevocationInfoChoice *rch;
+ CMS_SignerInfo *si;
+
+ for (i = 0; i < sk_CMS_CertificateChoices_num(sd->certificates); i++)
+ {
+ cch = sk_CMS_CertificateChoices_value(sd->certificates, i);
+ if (cch->type == CMS_CERTCHOICE_OTHER)
+ {
+ if (sd->version < 5)
+ sd->version = 5;
+ }
+ else if (cch->type == CMS_CERTCHOICE_V2ACERT)
+ {
+ if (sd->version < 4)
+ sd->version = 4;
+ }
+ else if (cch->type == CMS_CERTCHOICE_V1ACERT)
+ {
+ if (sd->version < 3)
+ sd->version = 3;
+ }
+ }
+
+ for (i = 0; i < sk_CMS_RevocationInfoChoice_num(sd->crls); i++)
+ {
+ rch = sk_CMS_RevocationInfoChoice_value(sd->crls, i);
+ if (rch->type == CMS_REVCHOICE_OTHER)
+ {
+ if (sd->version < 5)
+ sd->version = 5;
+ }
+ }
+
+ if ((OBJ_obj2nid(sd->encapContentInfo->eContentType) != NID_pkcs7_data)
+ && (sd->version < 3))
+ sd->version = 3;
+
+ for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++)
+ {
+ si = sk_CMS_SignerInfo_value(sd->signerInfos, i);
+ if (si->sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
+ {
+ if (si->version < 3)
+ si->version = 3;
+ if (sd->version < 3)
+ sd->version = 3;
+ }
+ else if (si->version < 1)
+ si->version = 1;
+ }
+
+ if (sd->version < 1)
+ sd->version = 1;
+
+ }
+
+/* Copy an existing messageDigest value */
+
+static int cms_copy_messageDigest(CMS_ContentInfo *cms, CMS_SignerInfo *si)
+ {
+ STACK_OF(CMS_SignerInfo) *sinfos;
+ CMS_SignerInfo *sitmp;
+ int i;
+ sinfos = CMS_get0_SignerInfos(cms);
+ for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
+ {
+ ASN1_OCTET_STRING *messageDigest;
+ sitmp = sk_CMS_SignerInfo_value(sinfos, i);
+ if (sitmp == si)
+ continue;
+ if (CMS_signed_get_attr_count(sitmp) < 0)
+ continue;
+ if (OBJ_cmp(si->digestAlgorithm->algorithm,
+ sitmp->digestAlgorithm->algorithm))
+ continue;
+ messageDigest = CMS_signed_get0_data_by_OBJ(sitmp,
+ OBJ_nid2obj(NID_pkcs9_messageDigest),
+ -3, V_ASN1_OCTET_STRING);
+ if (!messageDigest)
+ {
+ CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST,
+ CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE);
+ return 0;
+ }
+
+ if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
+ V_ASN1_OCTET_STRING,
+ messageDigest, -1))
+ return 1;
+ else
+ return 0;
+ }
+ CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST, CMS_R_NO_MATCHING_DIGEST);
+ return 0;
+ }
+
+int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type)
+ {
+ switch(type)
+ {
+ case CMS_SIGNERINFO_ISSUER_SERIAL:
+ sid->d.issuerAndSerialNumber =
+ M_ASN1_new_of(CMS_IssuerAndSerialNumber);
+ if (!sid->d.issuerAndSerialNumber)
+ goto merr;
+ if (!X509_NAME_set(&sid->d.issuerAndSerialNumber->issuer,
+ X509_get_issuer_name(cert)))
+ goto merr;
+ if (!ASN1_STRING_copy(
+ sid->d.issuerAndSerialNumber->serialNumber,
+ X509_get_serialNumber(cert)))
+ goto merr;
+ break;
+
+ case CMS_SIGNERINFO_KEYIDENTIFIER:
+ if (!cert->skid)
+ {
+ CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER,
+ CMS_R_CERTIFICATE_HAS_NO_KEYID);
+ return 0;
+ }
+ sid->d.subjectKeyIdentifier = ASN1_STRING_dup(cert->skid);
+ if (!sid->d.subjectKeyIdentifier)
+ goto merr;
+ break;
+
+ default:
+ CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, CMS_R_UNKNOWN_ID);
+ return 0;
+ }
+
+ sid->type = type;
+
+ return 1;
+
+ merr:
+ CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, ERR_R_MALLOC_FAILURE);
+ return 0;
+
+ }
+
+int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
+ ASN1_OCTET_STRING **keyid,
+ X509_NAME **issuer, ASN1_INTEGER **sno)
+ {
+ if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
+ {
+ if (issuer)
+ *issuer = sid->d.issuerAndSerialNumber->issuer;
+ if (sno)
+ *sno = sid->d.issuerAndSerialNumber->serialNumber;
+ }
+ else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
+ {
+ if (keyid)
+ *keyid = sid->d.subjectKeyIdentifier;
+ }
+ else
+ return 0;
+ return 1;
+ }
+
+int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert)
+ {
+ int ret;
+ if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
+ {
+ ret = X509_NAME_cmp(sid->d.issuerAndSerialNumber->issuer,
+ X509_get_issuer_name(cert));
+ if (ret)
+ return ret;
+ return ASN1_INTEGER_cmp(sid->d.issuerAndSerialNumber->serialNumber,
+ X509_get_serialNumber(cert));
+ }
+ else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
+ {
+ X509_check_purpose(cert, -1, -1);
+ if (!cert->skid)
+ return -1;
+ return ASN1_OCTET_STRING_cmp(sid->d.subjectKeyIdentifier,
+ cert->skid);
+ }
+ else
+ return -1;
+ }
+
+CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
+ X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
+ unsigned int flags)
+ {
+ CMS_SignedData *sd;
+ CMS_SignerInfo *si = NULL;
+ X509_ALGOR *alg;
+ int i, type;
+ if(!X509_check_private_key(signer, pk))
+ {
+ CMSerr(CMS_F_CMS_ADD1_SIGNER,
+ CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
+ return NULL;
+ }
+ sd = cms_signed_data_init(cms);
+ if (!sd)
+ goto err;
+ si = M_ASN1_new_of(CMS_SignerInfo);
+ if (!si)
+ goto merr;
+ X509_check_purpose(signer, -1, -1);
+
+ CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
+
+ si->pkey = pk;
+ si->signer = signer;
+
+ if (flags & CMS_USE_KEYID)
+ {
+ si->version = 3;
+ if (sd->version < 3)
+ sd->version = 3;
+ type = CMS_SIGNERINFO_KEYIDENTIFIER;
+ }
+ else
+ {
+ type = CMS_SIGNERINFO_ISSUER_SERIAL;
+ si->version = 1;
+ }
+
+ if (!cms_set1_SignerIdentifier(si->sid, signer, type))
+ goto err;
+
+ if (md == NULL)
+ {
+ int def_nid;
+ if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0)
+ goto err;
+ md = EVP_get_digestbynid(def_nid);
+ if (md == NULL)
+ {
+ CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DEFAULT_DIGEST);
+ goto err;
+ }
+ }
+
+ if (!md)
+ {
+ CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DIGEST_SET);
+ goto err;
+ }
+
+ cms_DigestAlgorithm_set(si->digestAlgorithm, md);
+
+ /* See if digest is present in digestAlgorithms */
+ for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++)
+ {
+ ASN1_OBJECT *aoid;
+ alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
+ X509_ALGOR_get0(&aoid, NULL, NULL, alg);
+ if (OBJ_obj2nid(aoid) == EVP_MD_type(md))
+ break;
+ }
+
+ if (i == sk_X509_ALGOR_num(sd->digestAlgorithms))
+ {
+ alg = X509_ALGOR_new();
+ if (!alg)
+ goto merr;
+ cms_DigestAlgorithm_set(alg, md);
+ if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg))
+ {
+ X509_ALGOR_free(alg);
+ goto merr;
+ }
+ }
+
+ if (pk->ameth && pk->ameth->pkey_ctrl)
+ {
+ i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_SIGN,
+ 0, si);
+ if (i == -2)
+ {
+ CMSerr(CMS_F_CMS_ADD1_SIGNER,
+ CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+ goto err;
+ }
+ if (i <= 0)
+ {
+ CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_CTRL_FAILURE);
+ goto err;
+ }
+ }
+
+ if (!(flags & CMS_NOATTR))
+ {
+ /* Initialialize signed attributes strutucture so other
+ * attributes such as signing time etc are added later
+ * even if we add none here.
+ */
+ if (!si->signedAttrs)
+ {
+ si->signedAttrs = sk_X509_ATTRIBUTE_new_null();
+ if (!si->signedAttrs)
+ goto merr;
+ }
+
+ if (!(flags & CMS_NOSMIMECAP))
+ {
+ STACK_OF(X509_ALGOR) *smcap = NULL;
+ i = CMS_add_standard_smimecap(&smcap);
+ if (i)
+ i = CMS_add_smimecap(si, smcap);
+ sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
+ if (!i)
+ goto merr;
+ }
+ if (flags & CMS_REUSE_DIGEST)
+ {
+ if (!cms_copy_messageDigest(cms, si))
+ goto err;
+ if (!(flags & CMS_PARTIAL) &&
+ !CMS_SignerInfo_sign(si))
+ goto err;
+ }
+ }
+
+ if (!(flags & CMS_NOCERTS))
+ {
+ /* NB ignore -1 return for duplicate cert */
+ if (!CMS_add1_cert(cms, signer))
+ goto merr;
+ }
+
+ if (!sd->signerInfos)
+ sd->signerInfos = sk_CMS_SignerInfo_new_null();
+ if (!sd->signerInfos ||
+ !sk_CMS_SignerInfo_push(sd->signerInfos, si))
+ goto merr;
+
+ return si;
+
+ merr:
+ CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE);
+ err:
+ if (si)
+ M_ASN1_free_of(si, CMS_SignerInfo);
+ return NULL;
+
+ }
+
+static int cms_add1_signingTime(CMS_SignerInfo *si, ASN1_TIME *t)
+ {
+ ASN1_TIME *tt;
+ int r = 0;
+ if (t)
+ tt = t;
+ else
+ tt = X509_gmtime_adj(NULL, 0);
+
+ if (!tt)
+ goto merr;
+
+ if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_signingTime,
+ tt->type, tt, -1) <= 0)
+ goto merr;
+
+ r = 1;
+
+ merr:
+
+ if (!t)
+ ASN1_TIME_free(tt);
+
+ if (!r)
+ CMSerr(CMS_F_CMS_ADD1_SIGNINGTIME, ERR_R_MALLOC_FAILURE);
+
+ return r;
+
+ }
+
+STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms)
+ {
+ CMS_SignedData *sd;
+ sd = cms_get0_signed(cms);
+ if (!sd)
+ return NULL;
+ return sd->signerInfos;
+ }
+
+STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms)
+ {
+ STACK_OF(X509) *signers = NULL;
+ STACK_OF(CMS_SignerInfo) *sinfos;
+ CMS_SignerInfo *si;
+ int i;
+ sinfos = CMS_get0_SignerInfos(cms);
+ for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
+ {
+ si = sk_CMS_SignerInfo_value(sinfos, i);
+ if (si->signer)
+ {
+ if (!signers)
+ {
+ signers = sk_X509_new_null();
+ if (!signers)
+ return NULL;
+ }
+ if (!sk_X509_push(signers, si->signer))
+ {
+ sk_X509_free(signers);
+ return NULL;
+ }
+ }
+ }
+ return signers;
+ }
+
+void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer)
+ {
+ if (signer)
+ {
+ CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
+ if (si->pkey)
+ EVP_PKEY_free(si->pkey);
+ si->pkey = X509_get_pubkey(signer);
+ }
+ if (si->signer)
+ X509_free(si->signer);
+ si->signer = signer;
+ }
+
+int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si,
+ ASN1_OCTET_STRING **keyid,
+ X509_NAME **issuer, ASN1_INTEGER **sno)
+ {
+ return cms_SignerIdentifier_get0_signer_id(si->sid, keyid, issuer, sno);
+ }
+
+int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert)
+ {
+ return cms_SignerIdentifier_cert_cmp(si->sid, cert);
+ }
+
+int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *scerts,
+ unsigned int flags)
+ {
+ CMS_SignedData *sd;
+ CMS_SignerInfo *si;
+ CMS_CertificateChoices *cch;
+ STACK_OF(CMS_CertificateChoices) *certs;
+ X509 *x;
+ int i, j;
+ int ret = 0;
+ sd = cms_get0_signed(cms);
+ if (!sd)
+ return -1;
+ certs = sd->certificates;
+ for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++)
+ {
+ si = sk_CMS_SignerInfo_value(sd->signerInfos, i);
+ if (si->signer)
+ continue;
+
+ for (j = 0; j < sk_X509_num(scerts); j++)
+ {
+ x = sk_X509_value(scerts, j);
+ if (CMS_SignerInfo_cert_cmp(si, x) == 0)
+ {
+ CMS_SignerInfo_set1_signer_cert(si, x);
+ ret++;
+ break;
+ }
+ }
+
+ if (si->signer || (flags & CMS_NOINTERN))
+ continue;
+
+ for (j = 0; j < sk_CMS_CertificateChoices_num(certs); j++)
+ {
+ cch = sk_CMS_CertificateChoices_value(certs, j);
+ if (cch->type != 0)
+ continue;
+ x = cch->d.certificate;
+ if (CMS_SignerInfo_cert_cmp(si, x) == 0)
+ {
+ CMS_SignerInfo_set1_signer_cert(si, x);
+ ret++;
+ break;
+ }
+ }
+ }
+ return ret;
+ }
+
+void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, X509 **signer,
+ X509_ALGOR **pdig, X509_ALGOR **psig)
+ {
+ if (pk)
+ *pk = si->pkey;
+ if (signer)
+ *signer = si->signer;
+ if (pdig)
+ *pdig = si->digestAlgorithm;
+ if (psig)
+ *psig = si->signatureAlgorithm;
+ }
+
+static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
+ CMS_SignerInfo *si, BIO *chain)
+ {
+ EVP_MD_CTX mctx;
+ int r = 0;
+ EVP_MD_CTX_init(&mctx);
+
+
+ if (!si->pkey)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, CMS_R_NO_PRIVATE_KEY);
+ return 0;
+ }
+
+ if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm))
+ goto err;
+
+ /* If any signed attributes calculate and add messageDigest attribute */
+
+ if (CMS_signed_get_attr_count(si) >= 0)
+ {
+ ASN1_OBJECT *ctype =
+ cms->d.signedData->encapContentInfo->eContentType;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ unsigned int mdlen;
+ if (!EVP_DigestFinal_ex(&mctx, md, &mdlen))
+ goto err;
+ if (!CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
+ V_ASN1_OCTET_STRING,
+ md, mdlen))
+ goto err;
+ /* Copy content type across */
+ if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_contentType,
+ V_ASN1_OBJECT, ctype, -1) <= 0)
+ goto err;
+ if (!CMS_SignerInfo_sign(si))
+ goto err;
+ }
+ else
+ {
+ unsigned char *sig;
+ unsigned int siglen;
+ sig = OPENSSL_malloc(EVP_PKEY_size(si->pkey));
+ if (!sig)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!EVP_SignFinal(&mctx, sig, &siglen, si->pkey))
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN,
+ CMS_R_SIGNFINAL_ERROR);
+ OPENSSL_free(sig);
+ goto err;
+ }
+ ASN1_STRING_set0(si->signature, sig, siglen);
+ }
+
+ r = 1;
+
+ err:
+ EVP_MD_CTX_cleanup(&mctx);
+ return r;
+
+ }
+
+int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain)
+ {
+ STACK_OF(CMS_SignerInfo) *sinfos;
+ CMS_SignerInfo *si;
+ int i;
+ sinfos = CMS_get0_SignerInfos(cms);
+ for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
+ {
+ si = sk_CMS_SignerInfo_value(sinfos, i);
+ if (!cms_SignerInfo_content_sign(cms, si, chain))
+ return 0;
+ }
+ cms->d.signedData->encapContentInfo->partial = 0;
+ return 1;
+ }
+
+int CMS_SignerInfo_sign(CMS_SignerInfo *si)
+ {
+ EVP_MD_CTX mctx;
+ EVP_PKEY_CTX *pctx;
+ unsigned char *abuf = NULL;
+ int alen;
+ size_t siglen;
+ const EVP_MD *md = NULL;
+
+ md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
+ if (md == NULL)
+ return 0;
+
+ EVP_MD_CTX_init(&mctx);
+
+ if (CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0)
+ {
+ if (!cms_add1_signingTime(si, NULL))
+ goto err;
+ }
+
+ if (EVP_DigestSignInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
+ EVP_PKEY_CTRL_CMS_SIGN, 0, si) <= 0)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
+ goto err;
+ }
+
+ alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf,
+ ASN1_ITEM_rptr(CMS_Attributes_Sign));
+ if(!abuf)
+ goto err;
+ if (EVP_DigestSignUpdate(&mctx, abuf, alen) <= 0)
+ goto err;
+ if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0)
+ goto err;
+ OPENSSL_free(abuf);
+ abuf = OPENSSL_malloc(siglen);
+ if(!abuf)
+ goto err;
+ if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
+ EVP_PKEY_CTRL_CMS_SIGN, 1, si) <= 0)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
+ goto err;
+ }
+
+ EVP_MD_CTX_cleanup(&mctx);
+
+ ASN1_STRING_set0(si->signature, abuf, siglen);
+
+ return 1;
+
+ err:
+ if (abuf)
+ OPENSSL_free(abuf);
+ EVP_MD_CTX_cleanup(&mctx);
+ return 0;
+
+ }
+
+int CMS_SignerInfo_verify(CMS_SignerInfo *si)
+ {
+ EVP_MD_CTX mctx;
+ EVP_PKEY_CTX *pctx;
+ unsigned char *abuf = NULL;
+ int alen, r = -1;
+ const EVP_MD *md = NULL;
+
+ if (!si->pkey)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_NO_PUBLIC_KEY);
+ return -1;
+ }
+
+ md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
+ if (md == NULL)
+ return -1;
+ EVP_MD_CTX_init(&mctx);
+ if (EVP_DigestVerifyInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
+ goto err;
+
+ alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf,
+ ASN1_ITEM_rptr(CMS_Attributes_Verify));
+ if(!abuf)
+ goto err;
+ r = EVP_DigestVerifyUpdate(&mctx, abuf, alen);
+ OPENSSL_free(abuf);
+ if (r <= 0)
+ {
+ r = -1;
+ goto err;
+ }
+ r = EVP_DigestVerifyFinal(&mctx,
+ si->signature->data, si->signature->length);
+ if (r <= 0)
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_VERIFICATION_FAILURE);
+ err:
+ EVP_MD_CTX_cleanup(&mctx);
+ return r;
+ }
+
+/* Create a chain of digest BIOs from a CMS ContentInfo */
+
+BIO *cms_SignedData_init_bio(CMS_ContentInfo *cms)
+ {
+ int i;
+ CMS_SignedData *sd;
+ BIO *chain = NULL;
+ sd = cms_get0_signed(cms);
+ if (!sd)
+ return NULL;
+ if (cms->d.signedData->encapContentInfo->partial)
+ cms_sd_set_version(sd);
+ for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++)
+ {
+ X509_ALGOR *digestAlgorithm;
+ BIO *mdbio;
+ digestAlgorithm = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
+ mdbio = cms_DigestAlgorithm_init_bio(digestAlgorithm);
+ if (!mdbio)
+ goto err;
+ if (chain)
+ BIO_push(chain, mdbio);
+ else
+ chain = mdbio;
+ }
+ return chain;
+ err:
+ if (chain)
+ BIO_free_all(chain);
+ return NULL;
+ }
+
+int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
+ {
+ ASN1_OCTET_STRING *os = NULL;
+ EVP_MD_CTX mctx;
+ int r = -1;
+ EVP_MD_CTX_init(&mctx);
+ /* If we have any signed attributes look for messageDigest value */
+ if (CMS_signed_get_attr_count(si) >= 0)
+ {
+ os = CMS_signed_get0_data_by_OBJ(si,
+ OBJ_nid2obj(NID_pkcs9_messageDigest),
+ -3, V_ASN1_OCTET_STRING);
+ if (!os)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
+ CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE);
+ goto err;
+ }
+ }
+
+ if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm))
+ goto err;
+
+ /* If messageDigest found compare it */
+
+ if (os)
+ {
+ unsigned char mval[EVP_MAX_MD_SIZE];
+ unsigned int mlen;
+ if (EVP_DigestFinal_ex(&mctx, mval, &mlen) <= 0)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
+ CMS_R_UNABLE_TO_FINALIZE_CONTEXT);
+ goto err;
+ }
+ if (mlen != (unsigned int)os->length)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
+ CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH);
+ goto err;
+ }
+
+ if (memcmp(mval, os->data, mlen))
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
+ CMS_R_VERIFICATION_FAILURE);
+ r = 0;
+ }
+ else
+ r = 1;
+ }
+ else
+ {
+ r = EVP_VerifyFinal(&mctx, si->signature->data,
+ si->signature->length, si->pkey);
+ if (r <= 0)
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
+ CMS_R_VERIFICATION_FAILURE);
+ r = 0;
+ }
+ }
+
+ err:
+ EVP_MD_CTX_cleanup(&mctx);
+ return r;
+
+ }
+
+int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs)
+ {
+ unsigned char *smder = NULL;
+ int smderlen, r;
+ smderlen = i2d_X509_ALGORS(algs, &smder);
+ if (smderlen <= 0)
+ return 0;
+ r = CMS_signed_add1_attr_by_NID(si, NID_SMIMECapabilities,
+ V_ASN1_SEQUENCE, smder, smderlen);
+ OPENSSL_free(smder);
+ return r;
+ }
+
+int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs,
+ int algnid, int keysize)
+ {
+ X509_ALGOR *alg;
+ ASN1_INTEGER *key = NULL;
+ if (keysize > 0)
+ {
+ key = ASN1_INTEGER_new();
+ if (!key || !ASN1_INTEGER_set(key, keysize))
+ return 0;
+ }
+ alg = X509_ALGOR_new();
+ if (!alg)
+ {
+ if (key)
+ ASN1_INTEGER_free(key);
+ return 0;
+ }
+
+ X509_ALGOR_set0(alg, OBJ_nid2obj(algnid),
+ key ? V_ASN1_INTEGER : V_ASN1_UNDEF, key);
+ if (!*algs)
+ *algs = sk_X509_ALGOR_new_null();
+ if (!*algs || !sk_X509_ALGOR_push(*algs, alg))
+ {
+ X509_ALGOR_free(alg);
+ return 0;
+ }
+ return 1;
+ }
+
+/* Check to see if a cipher exists and if so add S/MIME capabilities */
+
+static int cms_add_cipher_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg)
+ {
+ if (EVP_get_cipherbynid(nid))
+ return CMS_add_simple_smimecap(sk, nid, arg);
+ return 1;
+ }
+
+static int cms_add_digest_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg)
+ {
+ if (EVP_get_digestbynid(nid))
+ return CMS_add_simple_smimecap(sk, nid, arg);
+ return 1;
+ }
+
+int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap)
+ {
+ if (!cms_add_cipher_smcap(smcap, NID_aes_256_cbc, -1)
+ || !cms_add_digest_smcap(smcap, NID_id_GostR3411_94, -1)
+ || !cms_add_cipher_smcap(smcap, NID_id_Gost28147_89, -1)
+ || !cms_add_cipher_smcap(smcap, NID_aes_192_cbc, -1)
+ || !cms_add_cipher_smcap(smcap, NID_aes_128_cbc, -1)
+ || !cms_add_cipher_smcap(smcap, NID_des_ede3_cbc, -1)
+ || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 128)
+ || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 64)
+ || !cms_add_cipher_smcap(smcap, NID_des_cbc, -1)
+ || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 40))
+ return 0;
+ return 1;
+ }
diff --git a/drivers/builtin_openssl2/crypto/cms/cms_smime.c b/drivers/builtin_openssl2/crypto/cms/cms_smime.c
new file mode 100644
index 0000000000..1af9f3a60f
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/cms/cms_smime.c
@@ -0,0 +1,851 @@
+/* crypto/cms/cms_smime.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2008 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 "cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include "cms_lcl.h"
+
+static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
+ {
+ unsigned char buf[4096];
+ int r = 0, i;
+ BIO *tmpout = NULL;
+
+ if (out == NULL)
+ tmpout = BIO_new(BIO_s_null());
+ else if (flags & CMS_TEXT)
+ {
+ tmpout = BIO_new(BIO_s_mem());
+ BIO_set_mem_eof_return(tmpout, 0);
+ }
+ else
+ tmpout = out;
+
+ if(!tmpout)
+ {
+ CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Read all content through chain to process digest, decrypt etc */
+ for (;;)
+ {
+ i=BIO_read(in,buf,sizeof(buf));
+ if (i <= 0)
+ {
+ if (BIO_method_type(in) == BIO_TYPE_CIPHER)
+ {
+ if (!BIO_get_cipher_status(in))
+ goto err;
+ }
+ if (i < 0)
+ goto err;
+ break;
+ }
+
+ if (tmpout && (BIO_write(tmpout, buf, i) != i))
+ goto err;
+ }
+
+ if(flags & CMS_TEXT)
+ {
+ if(!SMIME_text(tmpout, out))
+ {
+ CMSerr(CMS_F_CMS_COPY_CONTENT,CMS_R_SMIME_TEXT_ERROR);
+ goto err;
+ }
+ }
+
+ r = 1;
+
+ err:
+ if (tmpout && (tmpout != out))
+ BIO_free(tmpout);
+ return r;
+
+ }
+
+static int check_content(CMS_ContentInfo *cms)
+ {
+ ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
+ if (!pos || !*pos)
+ {
+ CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT);
+ return 0;
+ }
+ return 1;
+ }
+
+static void do_free_upto(BIO *f, BIO *upto)
+ {
+ if (upto)
+ {
+ BIO *tbio;
+ do
+ {
+ tbio = BIO_pop(f);
+ BIO_free(f);
+ f = tbio;
+ }
+ while (f != upto);
+ }
+ else
+ BIO_free_all(f);
+ }
+
+int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
+ {
+ BIO *cont;
+ int r;
+ if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data)
+ {
+ CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA);
+ return 0;
+ }
+ cont = CMS_dataInit(cms, NULL);
+ if (!cont)
+ return 0;
+ r = cms_copy_content(out, cont, flags);
+ BIO_free_all(cont);
+ return r;
+ }
+
+CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
+ {
+ CMS_ContentInfo *cms;
+ cms = cms_Data_create();
+ if (!cms)
+ return NULL;
+
+ if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
+ return cms;
+
+ CMS_ContentInfo_free(cms);
+
+ return NULL;
+ }
+
+int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
+ unsigned int flags)
+ {
+ BIO *cont;
+ int r;
+ if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest)
+ {
+ CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA);
+ return 0;
+ }
+
+ if (!dcont && !check_content(cms))
+ return 0;
+
+ cont = CMS_dataInit(cms, dcont);
+ if (!cont)
+ return 0;
+ r = cms_copy_content(out, cont, flags);
+ if (r)
+ r = cms_DigestedData_do_final(cms, cont, 1);
+ do_free_upto(cont, dcont);
+ return r;
+ }
+
+CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
+ unsigned int flags)
+ {
+ CMS_ContentInfo *cms;
+ if (!md)
+ md = EVP_sha1();
+ cms = cms_DigestedData_create(md);
+ if (!cms)
+ return NULL;
+
+ if(!(flags & CMS_DETACHED))
+ CMS_set_detached(cms, 0);
+
+ if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
+ return cms;
+
+ CMS_ContentInfo_free(cms);
+ return NULL;
+ }
+
+int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
+ const unsigned char *key, size_t keylen,
+ BIO *dcont, BIO *out, unsigned int flags)
+ {
+ BIO *cont;
+ int r;
+ if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted)
+ {
+ CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT,
+ CMS_R_TYPE_NOT_ENCRYPTED_DATA);
+ return 0;
+ }
+
+ if (!dcont && !check_content(cms))
+ return 0;
+
+ if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
+ return 0;
+ cont = CMS_dataInit(cms, dcont);
+ if (!cont)
+ return 0;
+ r = cms_copy_content(out, cont, flags);
+ do_free_upto(cont, dcont);
+ return r;
+ }
+
+CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
+ const unsigned char *key, size_t keylen,
+ unsigned int flags)
+ {
+ CMS_ContentInfo *cms;
+ if (!cipher)
+ {
+ CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER);
+ return NULL;
+ }
+ cms = CMS_ContentInfo_new();
+ if (!cms)
+ return NULL;
+ if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
+ return NULL;
+
+ if(!(flags & CMS_DETACHED))
+ CMS_set_detached(cms, 0);
+
+ if ((flags & (CMS_STREAM|CMS_PARTIAL))
+ || CMS_final(cms, in, NULL, flags))
+ return cms;
+
+ CMS_ContentInfo_free(cms);
+ return NULL;
+ }
+
+static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
+ X509_STORE *store,
+ STACK_OF(X509) *certs,
+ STACK_OF(X509_CRL) *crls,
+ unsigned int flags)
+ {
+ X509_STORE_CTX ctx;
+ X509 *signer;
+ int i, j, r = 0;
+ CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
+ if (!X509_STORE_CTX_init(&ctx, store, signer, certs))
+ {
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
+ CMS_R_STORE_INIT_ERROR);
+ goto err;
+ }
+ X509_STORE_CTX_set_default(&ctx, "smime_sign");
+ if (crls)
+ X509_STORE_CTX_set0_crls(&ctx, crls);
+
+ i = X509_verify_cert(&ctx);
+ if (i <= 0)
+ {
+ j = X509_STORE_CTX_get_error(&ctx);
+ CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
+ CMS_R_CERTIFICATE_VERIFY_ERROR);
+ ERR_add_error_data(2, "Verify error:",
+ X509_verify_cert_error_string(j));
+ goto err;
+ }
+ r = 1;
+ err:
+ X509_STORE_CTX_cleanup(&ctx);
+ return r;
+
+ }
+
+int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
+ X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags)
+ {
+ CMS_SignerInfo *si;
+ STACK_OF(CMS_SignerInfo) *sinfos;
+ STACK_OF(X509) *cms_certs = NULL;
+ STACK_OF(X509_CRL) *crls = NULL;
+ X509 *signer;
+ int i, scount = 0, ret = 0;
+ BIO *cmsbio = NULL, *tmpin = NULL;
+
+ if (!dcont && !check_content(cms))
+ return 0;
+
+ /* Attempt to find all signer certificates */
+
+ sinfos = CMS_get0_SignerInfos(cms);
+
+ if (sk_CMS_SignerInfo_num(sinfos) <= 0)
+ {
+ CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS);
+ goto err;
+ }
+
+ for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
+ {
+ si = sk_CMS_SignerInfo_value(sinfos, i);
+ CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
+ if (signer)
+ scount++;
+ }
+
+ if (scount != sk_CMS_SignerInfo_num(sinfos))
+ scount += CMS_set1_signers_certs(cms, certs, flags);
+
+ if (scount != sk_CMS_SignerInfo_num(sinfos))
+ {
+ CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
+ goto err;
+ }
+
+ /* Attempt to verify all signers certs */
+
+ if (!(flags & CMS_NO_SIGNER_CERT_VERIFY))
+ {
+ cms_certs = CMS_get1_certs(cms);
+ if (!(flags & CMS_NOCRL))
+ crls = CMS_get1_crls(cms);
+ for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
+ {
+ si = sk_CMS_SignerInfo_value(sinfos, i);
+ if (!cms_signerinfo_verify_cert(si, store,
+ cms_certs, crls, flags))
+ goto err;
+ }
+ }
+
+ /* Attempt to verify all SignerInfo signed attribute signatures */
+
+ if (!(flags & CMS_NO_ATTR_VERIFY))
+ {
+ for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
+ {
+ si = sk_CMS_SignerInfo_value(sinfos, i);
+ if (CMS_signed_get_attr_count(si) < 0)
+ continue;
+ if (CMS_SignerInfo_verify(si) <= 0)
+ goto err;
+ }
+ }
+
+ /* Performance optimization: if the content is a memory BIO then
+ * store its contents in a temporary read only memory BIO. This
+ * avoids potentially large numbers of slow copies of data which will
+ * occur when reading from a read write memory BIO when signatures
+ * are calculated.
+ */
+
+ if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM))
+ {
+ char *ptr;
+ long len;
+ len = BIO_get_mem_data(dcont, &ptr);
+ tmpin = BIO_new_mem_buf(ptr, len);
+ if (tmpin == NULL)
+ {
+ CMSerr(CMS_F_CMS_VERIFY,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ else
+ tmpin = dcont;
+
+
+ cmsbio=CMS_dataInit(cms, tmpin);
+ if (!cmsbio)
+ goto err;
+
+ if (!cms_copy_content(out, cmsbio, flags))
+ goto err;
+
+ if (!(flags & CMS_NO_CONTENT_VERIFY))
+ {
+ for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
+ {
+ si = sk_CMS_SignerInfo_value(sinfos, i);
+ if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0)
+ {
+ CMSerr(CMS_F_CMS_VERIFY,
+ CMS_R_CONTENT_VERIFY_ERROR);
+ goto err;
+ }
+ }
+ }
+
+ ret = 1;
+
+ err:
+
+ if (dcont && (tmpin == dcont))
+ do_free_upto(cmsbio, dcont);
+ else
+ BIO_free_all(cmsbio);
+
+ if (cms_certs)
+ sk_X509_pop_free(cms_certs, X509_free);
+ if (crls)
+ sk_X509_CRL_pop_free(crls, X509_CRL_free);
+
+ return ret;
+ }
+
+int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
+ STACK_OF(X509) *certs,
+ X509_STORE *store, unsigned int flags)
+ {
+ int r;
+ flags &= ~(CMS_DETACHED|CMS_TEXT);
+ r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
+ if (r <= 0)
+ return r;
+ return cms_Receipt_verify(rcms, ocms);
+ }
+
+CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
+ BIO *data, unsigned int flags)
+ {
+ CMS_ContentInfo *cms;
+ int i;
+
+ cms = CMS_ContentInfo_new();
+ if (!cms || !CMS_SignedData_init(cms))
+ goto merr;
+
+ if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags))
+ {
+ CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR);
+ goto err;
+ }
+
+ for (i = 0; i < sk_X509_num(certs); i++)
+ {
+ X509 *x = sk_X509_value(certs, i);
+ if (!CMS_add1_cert(cms, x))
+ goto merr;
+ }
+
+ if(!(flags & CMS_DETACHED))
+ CMS_set_detached(cms, 0);
+
+ if ((flags & (CMS_STREAM|CMS_PARTIAL))
+ || CMS_final(cms, data, NULL, flags))
+ return cms;
+ else
+ goto err;
+
+ merr:
+ CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE);
+
+ err:
+ if (cms)
+ CMS_ContentInfo_free(cms);
+ return NULL;
+ }
+
+CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
+ X509 *signcert, EVP_PKEY *pkey,
+ STACK_OF(X509) *certs,
+ unsigned int flags)
+ {
+ CMS_SignerInfo *rct_si;
+ CMS_ContentInfo *cms = NULL;
+ ASN1_OCTET_STRING **pos, *os;
+ BIO *rct_cont = NULL;
+ int r = 0;
+
+ flags &= ~(CMS_STREAM|CMS_TEXT);
+ /* Not really detached but avoids content being allocated */
+ flags |= CMS_PARTIAL|CMS_BINARY|CMS_DETACHED;
+ if (!pkey || !signcert)
+ {
+ CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT);
+ return NULL;
+ }
+
+ /* Initialize signed data */
+
+ cms = CMS_sign(NULL, NULL, certs, NULL, flags);
+ if (!cms)
+ goto err;
+
+ /* Set inner content type to signed receipt */
+ if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt)))
+ goto err;
+
+ rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
+ if (!rct_si)
+ {
+ CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR);
+ goto err;
+ }
+
+ os = cms_encode_Receipt(si);
+
+ if (!os)
+ goto err;
+
+ /* Set content to digest */
+ rct_cont = BIO_new_mem_buf(os->data, os->length);
+ if (!rct_cont)
+ goto err;
+
+ /* Add msgSigDigest attribute */
+
+ if (!cms_msgSigDigest_add1(rct_si, si))
+ goto err;
+
+ /* Finalize structure */
+ if (!CMS_final(cms, rct_cont, NULL, flags))
+ goto err;
+
+ /* Set embedded content */
+ pos = CMS_get0_content(cms);
+ *pos = os;
+
+ r = 1;
+
+ err:
+ if (rct_cont)
+ BIO_free(rct_cont);
+ if (r)
+ return cms;
+ CMS_ContentInfo_free(cms);
+ return NULL;
+
+ }
+
+CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
+ const EVP_CIPHER *cipher, unsigned int flags)
+ {
+ CMS_ContentInfo *cms;
+ int i;
+ X509 *recip;
+ cms = CMS_EnvelopedData_create(cipher);
+ if (!cms)
+ goto merr;
+ for (i = 0; i < sk_X509_num(certs); i++)
+ {
+ recip = sk_X509_value(certs, i);
+ if (!CMS_add1_recipient_cert(cms, recip, flags))
+ {
+ CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
+ goto err;
+ }
+ }
+
+ if(!(flags & CMS_DETACHED))
+ CMS_set_detached(cms, 0);
+
+ if ((flags & (CMS_STREAM|CMS_PARTIAL))
+ || CMS_final(cms, data, NULL, flags))
+ return cms;
+ else
+ goto err;
+
+ merr:
+ CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
+ err:
+ if (cms)
+ CMS_ContentInfo_free(cms);
+ return NULL;
+ }
+
+int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
+ {
+ STACK_OF(CMS_RecipientInfo) *ris;
+ CMS_RecipientInfo *ri;
+ int i, r;
+ int debug = 0, ri_match = 0;
+ ris = CMS_get0_RecipientInfos(cms);
+ if (ris)
+ debug = cms->d.envelopedData->encryptedContentInfo->debug;
+ for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+ {
+ ri = sk_CMS_RecipientInfo_value(ris, i);
+ if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
+ continue;
+ ri_match = 1;
+ /* If we have a cert try matching RecipientInfo
+ * otherwise try them all.
+ */
+ if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0))
+ {
+ CMS_RecipientInfo_set0_pkey(ri, pk);
+ r = CMS_RecipientInfo_decrypt(cms, ri);
+ CMS_RecipientInfo_set0_pkey(ri, NULL);
+ if (cert)
+ {
+ /* If not debugging clear any error and
+ * return success to avoid leaking of
+ * information useful to MMA
+ */
+ if (!debug)
+ {
+ ERR_clear_error();
+ return 1;
+ }
+ if (r > 0)
+ return 1;
+ CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY,
+ CMS_R_DECRYPT_ERROR);
+ return 0;
+ }
+ /* If no cert and not debugging don't leave loop
+ * after first successful decrypt. Always attempt
+ * to decrypt all recipients to avoid leaking timing
+ * of a successful decrypt.
+ */
+ else if (r > 0 && debug)
+ return 1;
+ }
+ }
+ /* If no cert and not debugging always return success */
+ if (ri_match && !cert && !debug)
+ {
+ ERR_clear_error();
+ return 1;
+ }
+
+ CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
+ return 0;
+
+ }
+
+int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
+ unsigned char *key, size_t keylen,
+ unsigned char *id, size_t idlen)
+ {
+ STACK_OF(CMS_RecipientInfo) *ris;
+ CMS_RecipientInfo *ri;
+ int i, r;
+ ris = CMS_get0_RecipientInfos(cms);
+ for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+ {
+ ri = sk_CMS_RecipientInfo_value(ris, i);
+ if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK)
+ continue;
+
+ /* If we have an id try matching RecipientInfo
+ * otherwise try them all.
+ */
+ if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0))
+ {
+ CMS_RecipientInfo_set0_key(ri, key, keylen);
+ r = CMS_RecipientInfo_decrypt(cms, ri);
+ CMS_RecipientInfo_set0_key(ri, NULL, 0);
+ if (r > 0)
+ return 1;
+ if (id)
+ {
+ CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY,
+ CMS_R_DECRYPT_ERROR);
+ return 0;
+ }
+ ERR_clear_error();
+ }
+ }
+
+ CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT);
+ return 0;
+
+ }
+
+int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
+ unsigned char *pass, ossl_ssize_t passlen)
+ {
+ STACK_OF(CMS_RecipientInfo) *ris;
+ CMS_RecipientInfo *ri;
+ int i, r;
+ ris = CMS_get0_RecipientInfos(cms);
+ for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+ {
+ ri = sk_CMS_RecipientInfo_value(ris, i);
+ if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS)
+ continue;
+ CMS_RecipientInfo_set0_password(ri, pass, passlen);
+ r = CMS_RecipientInfo_decrypt(cms, ri);
+ CMS_RecipientInfo_set0_password(ri, NULL, 0);
+ if (r > 0)
+ return 1;
+ }
+
+ CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT);
+ return 0;
+
+ }
+
+int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
+ BIO *dcont, BIO *out,
+ unsigned int flags)
+ {
+ int r;
+ BIO *cont;
+ if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped)
+ {
+ CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
+ return 0;
+ }
+ if (!dcont && !check_content(cms))
+ return 0;
+ if (flags & CMS_DEBUG_DECRYPT)
+ cms->d.envelopedData->encryptedContentInfo->debug = 1;
+ else
+ cms->d.envelopedData->encryptedContentInfo->debug = 0;
+ if (!pk && !cert && !dcont && !out)
+ return 1;
+ if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
+ return 0;
+ cont = CMS_dataInit(cms, dcont);
+ if (!cont)
+ return 0;
+ r = cms_copy_content(out, cont, flags);
+ do_free_upto(cont, dcont);
+ return r;
+ }
+
+int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
+ {
+ BIO *cmsbio;
+ int ret = 0;
+ if (!(cmsbio = CMS_dataInit(cms, dcont)))
+ {
+ CMSerr(CMS_F_CMS_FINAL,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ SMIME_crlf_copy(data, cmsbio, flags);
+
+ (void)BIO_flush(cmsbio);
+
+
+ if (!CMS_dataFinal(cms, cmsbio))
+ {
+ CMSerr(CMS_F_CMS_FINAL,CMS_R_CMS_DATAFINAL_ERROR);
+ goto err;
+ }
+
+ ret = 1;
+
+ err:
+ do_free_upto(cmsbio, dcont);
+
+ return ret;
+
+ }
+
+#ifdef ZLIB
+
+int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
+ unsigned int flags)
+ {
+ BIO *cont;
+ int r;
+ if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData)
+ {
+ CMSerr(CMS_F_CMS_UNCOMPRESS,
+ CMS_R_TYPE_NOT_COMPRESSED_DATA);
+ return 0;
+ }
+
+ if (!dcont && !check_content(cms))
+ return 0;
+
+ cont = CMS_dataInit(cms, dcont);
+ if (!cont)
+ return 0;
+ r = cms_copy_content(out, cont, flags);
+ do_free_upto(cont, dcont);
+ return r;
+ }
+
+CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
+ {
+ CMS_ContentInfo *cms;
+ if (comp_nid <= 0)
+ comp_nid = NID_zlib_compression;
+ cms = cms_CompressedData_create(comp_nid);
+ if (!cms)
+ return NULL;
+
+ if(!(flags & CMS_DETACHED))
+ CMS_set_detached(cms, 0);
+
+ if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
+ return cms;
+
+ CMS_ContentInfo_free(cms);
+ return NULL;
+ }
+
+#else
+
+int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
+ unsigned int flags)
+ {
+ CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+ return 0;
+ }
+
+CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
+ {
+ CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+ return NULL;
+ }
+
+#endif
diff --git a/drivers/builtin_openssl/crypto/comp/c_rle.c b/drivers/builtin_openssl2/crypto/comp/c_rle.c
index 47dfb67fbd..47dfb67fbd 100644
--- a/drivers/builtin_openssl/crypto/comp/c_rle.c
+++ b/drivers/builtin_openssl2/crypto/comp/c_rle.c
diff --git a/drivers/builtin_openssl/crypto/comp/c_zlib.c b/drivers/builtin_openssl2/crypto/comp/c_zlib.c
index 8adf35f3fc..8adf35f3fc 100644
--- a/drivers/builtin_openssl/crypto/comp/c_zlib.c
+++ b/drivers/builtin_openssl2/crypto/comp/c_zlib.c
diff --git a/drivers/builtin_openssl/crypto/comp/comp_err.c b/drivers/builtin_openssl2/crypto/comp/comp_err.c
index 661c94c3a4..661c94c3a4 100644
--- a/drivers/builtin_openssl/crypto/comp/comp_err.c
+++ b/drivers/builtin_openssl2/crypto/comp/comp_err.c
diff --git a/drivers/builtin_openssl/crypto/comp/comp_lib.c b/drivers/builtin_openssl2/crypto/comp/comp_lib.c
index b60ae371e8..b60ae371e8 100644
--- a/drivers/builtin_openssl/crypto/comp/comp_lib.c
+++ b/drivers/builtin_openssl2/crypto/comp/comp_lib.c
diff --git a/drivers/builtin_openssl/crypto/conf/README b/drivers/builtin_openssl2/crypto/conf/README
index 96e53b34ed..96e53b34ed 100644
--- a/drivers/builtin_openssl/crypto/conf/README
+++ b/drivers/builtin_openssl2/crypto/conf/README
diff --git a/drivers/builtin_openssl/crypto/conf/cnf_save.c b/drivers/builtin_openssl2/crypto/conf/cnf_save.c
index 1439487526..1439487526 100644
--- a/drivers/builtin_openssl/crypto/conf/cnf_save.c
+++ b/drivers/builtin_openssl2/crypto/conf/cnf_save.c
diff --git a/drivers/builtin_openssl/crypto/conf/conf_api.c b/drivers/builtin_openssl2/crypto/conf/conf_api.c
index f5fcbb9f6b..f5fcbb9f6b 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_api.c
+++ b/drivers/builtin_openssl2/crypto/conf/conf_api.c
diff --git a/drivers/builtin_openssl/crypto/conf/conf_def.c b/drivers/builtin_openssl2/crypto/conf/conf_def.c
index cf951320af..cf951320af 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_def.c
+++ b/drivers/builtin_openssl2/crypto/conf/conf_def.c
diff --git a/drivers/builtin_openssl/crypto/conf/conf_def.h b/drivers/builtin_openssl2/crypto/conf/conf_def.h
index 92a7d8ad77..92a7d8ad77 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_def.h
+++ b/drivers/builtin_openssl2/crypto/conf/conf_def.h
diff --git a/drivers/builtin_openssl/crypto/conf/conf_err.c b/drivers/builtin_openssl2/crypto/conf/conf_err.c
index 25bb5dc9aa..25bb5dc9aa 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_err.c
+++ b/drivers/builtin_openssl2/crypto/conf/conf_err.c
diff --git a/drivers/builtin_openssl/crypto/conf/conf_lib.c b/drivers/builtin_openssl2/crypto/conf/conf_lib.c
index 54046defca..54046defca 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_lib.c
+++ b/drivers/builtin_openssl2/crypto/conf/conf_lib.c
diff --git a/drivers/builtin_openssl/crypto/conf/conf_mall.c b/drivers/builtin_openssl2/crypto/conf/conf_mall.c
index 213890e0c2..213890e0c2 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_mall.c
+++ b/drivers/builtin_openssl2/crypto/conf/conf_mall.c
diff --git a/drivers/builtin_openssl/crypto/conf/conf_mod.c b/drivers/builtin_openssl2/crypto/conf/conf_mod.c
index df1642a0a5..df1642a0a5 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_mod.c
+++ b/drivers/builtin_openssl2/crypto/conf/conf_mod.c
diff --git a/drivers/builtin_openssl/crypto/conf/conf_sap.c b/drivers/builtin_openssl2/crypto/conf/conf_sap.c
index 760dc2632d..760dc2632d 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_sap.c
+++ b/drivers/builtin_openssl2/crypto/conf/conf_sap.c
diff --git a/drivers/builtin_openssl/crypto/conf/keysets.pl b/drivers/builtin_openssl2/crypto/conf/keysets.pl
index 50ed67fa52..50ed67fa52 100644
--- a/drivers/builtin_openssl/crypto/conf/keysets.pl
+++ b/drivers/builtin_openssl2/crypto/conf/keysets.pl
diff --git a/drivers/builtin_openssl/crypto/conf/ssleay.cnf b/drivers/builtin_openssl2/crypto/conf/ssleay.cnf
index ed33af601e..ed33af601e 100644
--- a/drivers/builtin_openssl/crypto/conf/ssleay.cnf
+++ b/drivers/builtin_openssl2/crypto/conf/ssleay.cnf
diff --git a/drivers/builtin_openssl/crypto/conf/test.c b/drivers/builtin_openssl2/crypto/conf/test.c
index 7fab85053e..7fab85053e 100644
--- a/drivers/builtin_openssl/crypto/conf/test.c
+++ b/drivers/builtin_openssl2/crypto/conf/test.c
diff --git a/drivers/builtin_openssl/crypto/cpt_err.c b/drivers/builtin_openssl2/crypto/cpt_err.c
index 289005f662..289005f662 100644
--- a/drivers/builtin_openssl/crypto/cpt_err.c
+++ b/drivers/builtin_openssl2/crypto/cpt_err.c
diff --git a/drivers/builtin_openssl/crypto/cryptlib.c b/drivers/builtin_openssl2/crypto/cryptlib.c
index 0b77d8b7d0..0b77d8b7d0 100644
--- a/drivers/builtin_openssl/crypto/cryptlib.c
+++ b/drivers/builtin_openssl2/crypto/cryptlib.c
diff --git a/drivers/builtin_openssl/crypto/cryptlib.h b/drivers/builtin_openssl2/crypto/cryptlib.h
index d26f9630ea..d26f9630ea 100644
--- a/drivers/builtin_openssl/crypto/cryptlib.h
+++ b/drivers/builtin_openssl2/crypto/cryptlib.h
diff --git a/drivers/builtin_openssl/crypto/crypto-lib.com b/drivers/builtin_openssl2/crypto/crypto-lib.com
index dc8a8c174c..dc8a8c174c 100644
--- a/drivers/builtin_openssl/crypto/crypto-lib.com
+++ b/drivers/builtin_openssl2/crypto/crypto-lib.com
diff --git a/drivers/builtin_openssl/crypto/cversion.c b/drivers/builtin_openssl2/crypto/cversion.c
index ea9f25fd16..ea9f25fd16 100644
--- a/drivers/builtin_openssl/crypto/cversion.c
+++ b/drivers/builtin_openssl2/crypto/cversion.c
diff --git a/drivers/builtin_openssl/crypto/des/COPYRIGHT b/drivers/builtin_openssl2/crypto/des/COPYRIGHT
index 5469e1e469..5469e1e469 100644
--- a/drivers/builtin_openssl/crypto/des/COPYRIGHT
+++ b/drivers/builtin_openssl2/crypto/des/COPYRIGHT
diff --git a/drivers/builtin_openssl/crypto/des/DES.pm b/drivers/builtin_openssl2/crypto/des/DES.pm
index 6a175b6ca4..6a175b6ca4 100644
--- a/drivers/builtin_openssl/crypto/des/DES.pm
+++ b/drivers/builtin_openssl2/crypto/des/DES.pm
diff --git a/drivers/builtin_openssl/crypto/des/DES.xs b/drivers/builtin_openssl2/crypto/des/DES.xs
index b8050b9edf..b8050b9edf 100644
--- a/drivers/builtin_openssl/crypto/des/DES.xs
+++ b/drivers/builtin_openssl2/crypto/des/DES.xs
diff --git a/drivers/builtin_openssl/crypto/des/FILES0 b/drivers/builtin_openssl2/crypto/des/FILES0
index 4c7ea2de7a..4c7ea2de7a 100644
--- a/drivers/builtin_openssl/crypto/des/FILES0
+++ b/drivers/builtin_openssl2/crypto/des/FILES0
diff --git a/drivers/builtin_openssl/crypto/des/INSTALL b/drivers/builtin_openssl2/crypto/des/INSTALL
index 8aebdfe110..8aebdfe110 100644
--- a/drivers/builtin_openssl/crypto/des/INSTALL
+++ b/drivers/builtin_openssl2/crypto/des/INSTALL
diff --git a/drivers/builtin_openssl2/crypto/des/Imakefile b/drivers/builtin_openssl2/crypto/des/Imakefile
new file mode 100644
index 0000000000..1b9b5629e1
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/des/Imakefile
@@ -0,0 +1,35 @@
+# This Imakefile has not been tested for a while but it should still
+# work when placed in the correct directory in the kerberos v 4 distribution
+
+SRCS= cbc_cksm.c cbc_enc.c ecb_enc.c pcbc_enc.c \
+ qud_cksm.c rand_key.c read_pwd.c set_key.c str2key.c \
+ enc_read.c enc_writ.c fcrypt.c cfb_enc.c \
+ ecb3_enc.c ofb_enc.c ofb64enc.c
+
+OBJS= cbc_cksm.o cbc_enc.o ecb_enc.o pcbc_enc.o \
+ qud_cksm.o rand_key.o read_pwd.o set_key.o str2key.o \
+ enc_read.o enc_writ.o fcrypt.o cfb_enc.o \
+ ecb3_enc.o ofb_enc.o ofb64enc.o
+
+GENERAL=COPYRIGHT FILES INSTALL Imakefile README VERSION makefile times \
+ vms.com KERBEROS
+DES= des.c des.man
+TESTING=destest.c speed.c rpw.c
+LIBDES= des_crypt.man des.h des_locl.h podd.h sk.h spr.h
+
+PERL= des.pl testdes.pl doIP doPC1 doPC2 PC1 PC2 shifts.pl
+
+CODE= $(GENERAL) $(DES) $(TESTING) $(SRCS) $(LIBDES) $(PERL)
+
+SRCDIR=$(SRCTOP)/lib/des
+
+DBG= -O
+INCLUDE= -I$(SRCDIR)
+CC= cc
+
+library_obj_rule()
+
+install_library_target(des,$(OBJS),$(SRCS),)
+
+test(destest,libdes.a,)
+test(rpw,libdes.a,)
diff --git a/drivers/builtin_openssl/crypto/des/KERBEROS b/drivers/builtin_openssl2/crypto/des/KERBEROS
index f401b10014..f401b10014 100644
--- a/drivers/builtin_openssl/crypto/des/KERBEROS
+++ b/drivers/builtin_openssl2/crypto/des/KERBEROS
diff --git a/drivers/builtin_openssl/crypto/des/README b/drivers/builtin_openssl2/crypto/des/README
index 621a5ab467..621a5ab467 100644
--- a/drivers/builtin_openssl/crypto/des/README
+++ b/drivers/builtin_openssl2/crypto/des/README
diff --git a/drivers/builtin_openssl/crypto/des/VERSION b/drivers/builtin_openssl2/crypto/des/VERSION
index c7d01542bc..c7d01542bc 100644
--- a/drivers/builtin_openssl/crypto/des/VERSION
+++ b/drivers/builtin_openssl2/crypto/des/VERSION
diff --git a/drivers/builtin_openssl/crypto/des/asm/crypt586.pl b/drivers/builtin_openssl2/crypto/des/asm/crypt586.pl
index e36f7d44bd..e36f7d44bd 100644
--- a/drivers/builtin_openssl/crypto/des/asm/crypt586.pl
+++ b/drivers/builtin_openssl2/crypto/des/asm/crypt586.pl
diff --git a/drivers/builtin_openssl/crypto/des/asm/des-586.pl b/drivers/builtin_openssl2/crypto/des/asm/des-586.pl
index 5b5f39cebd..5b5f39cebd 100644
--- a/drivers/builtin_openssl/crypto/des/asm/des-586.pl
+++ b/drivers/builtin_openssl2/crypto/des/asm/des-586.pl
diff --git a/drivers/builtin_openssl/crypto/des/asm/des_enc.m4 b/drivers/builtin_openssl2/crypto/des/asm/des_enc.m4
index 3280595478..3280595478 100644
--- a/drivers/builtin_openssl/crypto/des/asm/des_enc.m4
+++ b/drivers/builtin_openssl2/crypto/des/asm/des_enc.m4
diff --git a/drivers/builtin_openssl/crypto/des/asm/desboth.pl b/drivers/builtin_openssl2/crypto/des/asm/desboth.pl
index eec00886e4..eec00886e4 100644
--- a/drivers/builtin_openssl/crypto/des/asm/desboth.pl
+++ b/drivers/builtin_openssl2/crypto/des/asm/desboth.pl
diff --git a/drivers/builtin_openssl/crypto/des/asm/readme b/drivers/builtin_openssl2/crypto/des/asm/readme
index 1beafe253b..1beafe253b 100644
--- a/drivers/builtin_openssl/crypto/des/asm/readme
+++ b/drivers/builtin_openssl2/crypto/des/asm/readme
diff --git a/drivers/builtin_openssl/crypto/des/cbc3_enc.c b/drivers/builtin_openssl2/crypto/des/cbc3_enc.c
index b5db4e14f7..b5db4e14f7 100644
--- a/drivers/builtin_openssl/crypto/des/cbc3_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/cbc3_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/cbc_cksm.c b/drivers/builtin_openssl2/crypto/des/cbc_cksm.c
index 09a7ba56aa..09a7ba56aa 100644
--- a/drivers/builtin_openssl/crypto/des/cbc_cksm.c
+++ b/drivers/builtin_openssl2/crypto/des/cbc_cksm.c
diff --git a/drivers/builtin_openssl/crypto/des/cbc_enc.c b/drivers/builtin_openssl2/crypto/des/cbc_enc.c
index 677903ae4e..677903ae4e 100644
--- a/drivers/builtin_openssl/crypto/des/cbc_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/cbc_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/cfb64ede.c b/drivers/builtin_openssl2/crypto/des/cfb64ede.c
index de34ecceb9..de34ecceb9 100644
--- a/drivers/builtin_openssl/crypto/des/cfb64ede.c
+++ b/drivers/builtin_openssl2/crypto/des/cfb64ede.c
diff --git a/drivers/builtin_openssl/crypto/des/cfb64enc.c b/drivers/builtin_openssl2/crypto/des/cfb64enc.c
index 5ec8683e40..5ec8683e40 100644
--- a/drivers/builtin_openssl/crypto/des/cfb64enc.c
+++ b/drivers/builtin_openssl2/crypto/des/cfb64enc.c
diff --git a/drivers/builtin_openssl/crypto/des/cfb_enc.c b/drivers/builtin_openssl2/crypto/des/cfb_enc.c
index 720f29a28e..720f29a28e 100644
--- a/drivers/builtin_openssl/crypto/des/cfb_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/cfb_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/des-lib.com b/drivers/builtin_openssl2/crypto/des/des-lib.com
index 348f1c0470..348f1c0470 100644
--- a/drivers/builtin_openssl/crypto/des/des-lib.com
+++ b/drivers/builtin_openssl2/crypto/des/des-lib.com
diff --git a/drivers/builtin_openssl/crypto/des/des.c b/drivers/builtin_openssl2/crypto/des/des.c
index 343135ff9e..343135ff9e 100644
--- a/drivers/builtin_openssl/crypto/des/des.c
+++ b/drivers/builtin_openssl2/crypto/des/des.c
diff --git a/drivers/builtin_openssl/crypto/des/des.pod b/drivers/builtin_openssl2/crypto/des/des.pod
index bf479e83d2..bf479e83d2 100644
--- a/drivers/builtin_openssl/crypto/des/des.pod
+++ b/drivers/builtin_openssl2/crypto/des/des.pod
diff --git a/drivers/builtin_openssl/crypto/des/des3s.cpp b/drivers/builtin_openssl2/crypto/des/des3s.cpp
index 02d527c057..02d527c057 100644
--- a/drivers/builtin_openssl/crypto/des/des3s.cpp
+++ b/drivers/builtin_openssl2/crypto/des/des3s.cpp
diff --git a/drivers/builtin_openssl/crypto/des/des_enc.c b/drivers/builtin_openssl2/crypto/des/des_enc.c
index 828feba208..828feba208 100644
--- a/drivers/builtin_openssl/crypto/des/des_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/des_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/des_locl.h b/drivers/builtin_openssl2/crypto/des/des_locl.h
index a3b512e9b0..a3b512e9b0 100644
--- a/drivers/builtin_openssl/crypto/des/des_locl.h
+++ b/drivers/builtin_openssl2/crypto/des/des_locl.h
diff --git a/drivers/builtin_openssl/crypto/des/des_old.c b/drivers/builtin_openssl2/crypto/des/des_old.c
index 7c33ed7a93..7c33ed7a93 100644
--- a/drivers/builtin_openssl/crypto/des/des_old.c
+++ b/drivers/builtin_openssl2/crypto/des/des_old.c
diff --git a/drivers/builtin_openssl/crypto/des/des_old2.c b/drivers/builtin_openssl2/crypto/des/des_old2.c
index c8fa3ee135..c8fa3ee135 100644
--- a/drivers/builtin_openssl/crypto/des/des_old2.c
+++ b/drivers/builtin_openssl2/crypto/des/des_old2.c
diff --git a/drivers/builtin_openssl/crypto/des/des_opts.c b/drivers/builtin_openssl2/crypto/des/des_opts.c
index 2df82962c5..2df82962c5 100644
--- a/drivers/builtin_openssl/crypto/des/des_opts.c
+++ b/drivers/builtin_openssl2/crypto/des/des_opts.c
diff --git a/drivers/builtin_openssl/crypto/des/des_ver.h b/drivers/builtin_openssl2/crypto/des/des_ver.h
index d1ada258a6..d1ada258a6 100644
--- a/drivers/builtin_openssl/crypto/des/des_ver.h
+++ b/drivers/builtin_openssl2/crypto/des/des_ver.h
diff --git a/drivers/builtin_openssl/crypto/des/dess.cpp b/drivers/builtin_openssl2/crypto/des/dess.cpp
index 5549bab90a..5549bab90a 100644
--- a/drivers/builtin_openssl/crypto/des/dess.cpp
+++ b/drivers/builtin_openssl2/crypto/des/dess.cpp
diff --git a/drivers/builtin_openssl/crypto/des/destest.c b/drivers/builtin_openssl2/crypto/des/destest.c
index 64b92a34fe..64b92a34fe 100644
--- a/drivers/builtin_openssl/crypto/des/destest.c
+++ b/drivers/builtin_openssl2/crypto/des/destest.c
diff --git a/drivers/builtin_openssl/crypto/des/ecb3_enc.c b/drivers/builtin_openssl2/crypto/des/ecb3_enc.c
index c3437bc606..c3437bc606 100644
--- a/drivers/builtin_openssl/crypto/des/ecb3_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/ecb3_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/ecb_enc.c b/drivers/builtin_openssl2/crypto/des/ecb_enc.c
index 0684e769b3..0684e769b3 100644
--- a/drivers/builtin_openssl/crypto/des/ecb_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/ecb_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/ede_cbcm_enc.c b/drivers/builtin_openssl2/crypto/des/ede_cbcm_enc.c
index adfcb75cf3..adfcb75cf3 100644
--- a/drivers/builtin_openssl/crypto/des/ede_cbcm_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/ede_cbcm_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/enc_read.c b/drivers/builtin_openssl2/crypto/des/enc_read.c
index edb6620d08..edb6620d08 100644
--- a/drivers/builtin_openssl/crypto/des/enc_read.c
+++ b/drivers/builtin_openssl2/crypto/des/enc_read.c
diff --git a/drivers/builtin_openssl/crypto/des/enc_writ.c b/drivers/builtin_openssl2/crypto/des/enc_writ.c
index 2353ac1e89..2353ac1e89 100644
--- a/drivers/builtin_openssl/crypto/des/enc_writ.c
+++ b/drivers/builtin_openssl2/crypto/des/enc_writ.c
diff --git a/drivers/builtin_openssl/crypto/des/fcrypt.c b/drivers/builtin_openssl2/crypto/des/fcrypt.c
index ccbdff250f..ccbdff250f 100644
--- a/drivers/builtin_openssl/crypto/des/fcrypt.c
+++ b/drivers/builtin_openssl2/crypto/des/fcrypt.c
diff --git a/drivers/builtin_openssl/crypto/des/fcrypt_b.c b/drivers/builtin_openssl2/crypto/des/fcrypt_b.c
index 8822816938..8822816938 100644
--- a/drivers/builtin_openssl/crypto/des/fcrypt_b.c
+++ b/drivers/builtin_openssl2/crypto/des/fcrypt_b.c
diff --git a/drivers/builtin_openssl2/crypto/des/makefile.bc b/drivers/builtin_openssl2/crypto/des/makefile.bc
new file mode 100644
index 0000000000..1fe6d4915a
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/des/makefile.bc
@@ -0,0 +1,50 @@
+#
+# Origional BC Makefile from Teun <Teun.Nijssen@kub.nl>
+#
+#
+CC = bcc
+TLIB = tlib /0 /C
+# note: the -3 flag produces code for 386, 486, Pentium etc; omit it for 286s
+OPTIMIZE= -3 -O2
+#WINDOWS= -W
+CFLAGS = -c -ml -d $(OPTIMIZE) $(WINDOWS) -DMSDOS
+LFLAGS = -ml $(WINDOWS)
+
+.c.obj:
+ $(CC) $(CFLAGS) $*.c
+
+.obj.exe:
+ $(CC) $(LFLAGS) -e$*.exe $*.obj libdes.lib
+
+all: $(LIB) destest.exe rpw.exe des.exe speed.exe
+
+# "make clean": use a directory containing only libdes .exe and .obj files...
+clean:
+ del *.exe
+ del *.obj
+ del libdes.lib
+ del libdes.rsp
+
+OBJS= cbc_cksm.obj cbc_enc.obj ecb_enc.obj pcbc_enc.obj \
+ qud_cksm.obj rand_key.obj set_key.obj str2key.obj \
+ enc_read.obj enc_writ.obj fcrypt.obj cfb_enc.obj \
+ ecb3_enc.obj ofb_enc.obj cbc3_enc.obj read_pwd.obj\
+ cfb64enc.obj ofb64enc.obj ede_enc.obj cfb64ede.obj\
+ ofb64ede.obj supp.obj
+
+LIB= libdes.lib
+
+$(LIB): $(OBJS)
+ del $(LIB)
+ makersp "+%s &\n" &&|
+ $(OBJS)
+| >libdes.rsp
+ $(TLIB) libdes.lib @libdes.rsp,nul
+ del libdes.rsp
+
+destest.exe: destest.obj libdes.lib
+rpw.exe: rpw.obj libdes.lib
+speed.exe: speed.obj libdes.lib
+des.exe: des.obj libdes.lib
+
+
diff --git a/drivers/builtin_openssl/crypto/des/ncbc_enc.c b/drivers/builtin_openssl2/crypto/des/ncbc_enc.c
index fda23d522f..fda23d522f 100644
--- a/drivers/builtin_openssl/crypto/des/ncbc_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/ncbc_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/ofb64ede.c b/drivers/builtin_openssl2/crypto/des/ofb64ede.c
index 26bbf9a6a7..26bbf9a6a7 100644
--- a/drivers/builtin_openssl/crypto/des/ofb64ede.c
+++ b/drivers/builtin_openssl2/crypto/des/ofb64ede.c
diff --git a/drivers/builtin_openssl/crypto/des/ofb64enc.c b/drivers/builtin_openssl2/crypto/des/ofb64enc.c
index 8ca3d49dea..8ca3d49dea 100644
--- a/drivers/builtin_openssl/crypto/des/ofb64enc.c
+++ b/drivers/builtin_openssl2/crypto/des/ofb64enc.c
diff --git a/drivers/builtin_openssl/crypto/des/ofb_enc.c b/drivers/builtin_openssl2/crypto/des/ofb_enc.c
index e887a3c6f4..e887a3c6f4 100644
--- a/drivers/builtin_openssl/crypto/des/ofb_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/ofb_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/options.txt b/drivers/builtin_openssl2/crypto/des/options.txt
index 6e2b50f765..6e2b50f765 100644
--- a/drivers/builtin_openssl/crypto/des/options.txt
+++ b/drivers/builtin_openssl2/crypto/des/options.txt
diff --git a/drivers/builtin_openssl/crypto/des/pcbc_enc.c b/drivers/builtin_openssl2/crypto/des/pcbc_enc.c
index 17a40f9520..17a40f9520 100644
--- a/drivers/builtin_openssl/crypto/des/pcbc_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/pcbc_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/qud_cksm.c b/drivers/builtin_openssl2/crypto/des/qud_cksm.c
index dac201227e..dac201227e 100644
--- a/drivers/builtin_openssl/crypto/des/qud_cksm.c
+++ b/drivers/builtin_openssl2/crypto/des/qud_cksm.c
diff --git a/drivers/builtin_openssl/crypto/des/rand_key.c b/drivers/builtin_openssl2/crypto/des/rand_key.c
index 2398165568..2398165568 100644
--- a/drivers/builtin_openssl/crypto/des/rand_key.c
+++ b/drivers/builtin_openssl2/crypto/des/rand_key.c
diff --git a/drivers/builtin_openssl/crypto/des/read2pwd.c b/drivers/builtin_openssl2/crypto/des/read2pwd.c
index ee6969f76e..ee6969f76e 100644
--- a/drivers/builtin_openssl/crypto/des/read2pwd.c
+++ b/drivers/builtin_openssl2/crypto/des/read2pwd.c
diff --git a/drivers/builtin_openssl/crypto/des/read_pwd.c b/drivers/builtin_openssl2/crypto/des/read_pwd.c
index ce5fa00a37..ce5fa00a37 100644
--- a/drivers/builtin_openssl/crypto/des/read_pwd.c
+++ b/drivers/builtin_openssl2/crypto/des/read_pwd.c
diff --git a/drivers/builtin_openssl/crypto/des/rpc_des.h b/drivers/builtin_openssl2/crypto/des/rpc_des.h
index 41328d7965..41328d7965 100644
--- a/drivers/builtin_openssl/crypto/des/rpc_des.h
+++ b/drivers/builtin_openssl2/crypto/des/rpc_des.h
diff --git a/drivers/builtin_openssl/crypto/des/rpc_enc.c b/drivers/builtin_openssl2/crypto/des/rpc_enc.c
index d937d08da5..d937d08da5 100644
--- a/drivers/builtin_openssl/crypto/des/rpc_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/rpc_enc.c
diff --git a/drivers/builtin_openssl/crypto/des/rpw.c b/drivers/builtin_openssl2/crypto/des/rpw.c
index 8a9473c4f9..8a9473c4f9 100644
--- a/drivers/builtin_openssl/crypto/des/rpw.c
+++ b/drivers/builtin_openssl2/crypto/des/rpw.c
diff --git a/drivers/builtin_openssl/crypto/des/set_key.c b/drivers/builtin_openssl2/crypto/des/set_key.c
index da4d62e112..da4d62e112 100644
--- a/drivers/builtin_openssl/crypto/des/set_key.c
+++ b/drivers/builtin_openssl2/crypto/des/set_key.c
diff --git a/drivers/builtin_openssl/crypto/des/speed.c b/drivers/builtin_openssl2/crypto/des/speed.c
index 1616f4b7c9..1616f4b7c9 100644
--- a/drivers/builtin_openssl/crypto/des/speed.c
+++ b/drivers/builtin_openssl2/crypto/des/speed.c
diff --git a/drivers/builtin_openssl/crypto/des/spr.h b/drivers/builtin_openssl2/crypto/des/spr.h
index b91936a5a5..b91936a5a5 100644
--- a/drivers/builtin_openssl/crypto/des/spr.h
+++ b/drivers/builtin_openssl2/crypto/des/spr.h
diff --git a/drivers/builtin_openssl/crypto/des/str2key.c b/drivers/builtin_openssl2/crypto/des/str2key.c
index 1077f99d1b..1077f99d1b 100644
--- a/drivers/builtin_openssl/crypto/des/str2key.c
+++ b/drivers/builtin_openssl2/crypto/des/str2key.c
diff --git a/drivers/builtin_openssl/crypto/des/t/test b/drivers/builtin_openssl2/crypto/des/t/test
index 97acd0552e..97acd0552e 100644
--- a/drivers/builtin_openssl/crypto/des/t/test
+++ b/drivers/builtin_openssl2/crypto/des/t/test
diff --git a/drivers/builtin_openssl/crypto/des/times/486-50.sol b/drivers/builtin_openssl2/crypto/des/times/486-50.sol
index 0de62d6db3..0de62d6db3 100644
--- a/drivers/builtin_openssl/crypto/des/times/486-50.sol
+++ b/drivers/builtin_openssl2/crypto/des/times/486-50.sol
diff --git a/drivers/builtin_openssl/crypto/des/times/586-100.lnx b/drivers/builtin_openssl2/crypto/des/times/586-100.lnx
index 4323914a11..4323914a11 100644
--- a/drivers/builtin_openssl/crypto/des/times/586-100.lnx
+++ b/drivers/builtin_openssl2/crypto/des/times/586-100.lnx
diff --git a/drivers/builtin_openssl/crypto/des/times/686-200.fre b/drivers/builtin_openssl2/crypto/des/times/686-200.fre
index 7d83f6adee..7d83f6adee 100644
--- a/drivers/builtin_openssl/crypto/des/times/686-200.fre
+++ b/drivers/builtin_openssl2/crypto/des/times/686-200.fre
diff --git a/drivers/builtin_openssl/crypto/des/times/aix.cc b/drivers/builtin_openssl2/crypto/des/times/aix.cc
index d96b74e2ce..d96b74e2ce 100644
--- a/drivers/builtin_openssl/crypto/des/times/aix.cc
+++ b/drivers/builtin_openssl2/crypto/des/times/aix.cc
diff --git a/drivers/builtin_openssl/crypto/des/times/alpha.cc b/drivers/builtin_openssl2/crypto/des/times/alpha.cc
index 95c17efae7..95c17efae7 100644
--- a/drivers/builtin_openssl/crypto/des/times/alpha.cc
+++ b/drivers/builtin_openssl2/crypto/des/times/alpha.cc
diff --git a/drivers/builtin_openssl/crypto/des/times/hpux.cc b/drivers/builtin_openssl2/crypto/des/times/hpux.cc
index 3de856ddac..3de856ddac 100644
--- a/drivers/builtin_openssl/crypto/des/times/hpux.cc
+++ b/drivers/builtin_openssl2/crypto/des/times/hpux.cc
diff --git a/drivers/builtin_openssl/crypto/des/times/sparc.gcc b/drivers/builtin_openssl2/crypto/des/times/sparc.gcc
index 8eaa042104..8eaa042104 100644
--- a/drivers/builtin_openssl/crypto/des/times/sparc.gcc
+++ b/drivers/builtin_openssl2/crypto/des/times/sparc.gcc
diff --git a/drivers/builtin_openssl/crypto/des/times/usparc.cc b/drivers/builtin_openssl2/crypto/des/times/usparc.cc
index 0864285ef6..0864285ef6 100644
--- a/drivers/builtin_openssl/crypto/des/times/usparc.cc
+++ b/drivers/builtin_openssl2/crypto/des/times/usparc.cc
diff --git a/drivers/builtin_openssl/crypto/des/typemap b/drivers/builtin_openssl2/crypto/des/typemap
index a524f53634..a524f53634 100644
--- a/drivers/builtin_openssl/crypto/des/typemap
+++ b/drivers/builtin_openssl2/crypto/des/typemap
diff --git a/drivers/builtin_openssl/crypto/des/xcbc_enc.c b/drivers/builtin_openssl2/crypto/des/xcbc_enc.c
index 058cab6bce..058cab6bce 100644
--- a/drivers/builtin_openssl/crypto/des/xcbc_enc.c
+++ b/drivers/builtin_openssl2/crypto/des/xcbc_enc.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh1024.pem b/drivers/builtin_openssl2/crypto/dh/dh1024.pem
index 81d43f6a3e..81d43f6a3e 100644
--- a/drivers/builtin_openssl/crypto/dh/dh1024.pem
+++ b/drivers/builtin_openssl2/crypto/dh/dh1024.pem
diff --git a/drivers/builtin_openssl/crypto/dh/dh192.pem b/drivers/builtin_openssl2/crypto/dh/dh192.pem
index 521c07271d..521c07271d 100644
--- a/drivers/builtin_openssl/crypto/dh/dh192.pem
+++ b/drivers/builtin_openssl2/crypto/dh/dh192.pem
diff --git a/drivers/builtin_openssl/crypto/dh/dh2048.pem b/drivers/builtin_openssl2/crypto/dh/dh2048.pem
index 295460f508..295460f508 100644
--- a/drivers/builtin_openssl/crypto/dh/dh2048.pem
+++ b/drivers/builtin_openssl2/crypto/dh/dh2048.pem
diff --git a/drivers/builtin_openssl/crypto/dh/dh4096.pem b/drivers/builtin_openssl2/crypto/dh/dh4096.pem
index 390943a21d..390943a21d 100644
--- a/drivers/builtin_openssl/crypto/dh/dh4096.pem
+++ b/drivers/builtin_openssl2/crypto/dh/dh4096.pem
diff --git a/drivers/builtin_openssl/crypto/dh/dh512.pem b/drivers/builtin_openssl2/crypto/dh/dh512.pem
index 0a4d863ebe..0a4d863ebe 100644
--- a/drivers/builtin_openssl/crypto/dh/dh512.pem
+++ b/drivers/builtin_openssl2/crypto/dh/dh512.pem
diff --git a/drivers/builtin_openssl/crypto/dh/dh_ameth.c b/drivers/builtin_openssl2/crypto/dh/dh_ameth.c
index 02ec2d47b4..02ec2d47b4 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_ameth.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_ameth.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_asn1.c b/drivers/builtin_openssl2/crypto/dh/dh_asn1.c
index 0b4357d605..0b4357d605 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_asn1.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_asn1.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_check.c b/drivers/builtin_openssl2/crypto/dh/dh_check.c
index 066898174e..066898174e 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_check.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_check.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_depr.c b/drivers/builtin_openssl2/crypto/dh/dh_depr.c
index acc05f252c..acc05f252c 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_depr.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_depr.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_err.c b/drivers/builtin_openssl2/crypto/dh/dh_err.c
index 56d3df7356..56d3df7356 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_err.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_err.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_gen.c b/drivers/builtin_openssl2/crypto/dh/dh_gen.c
index 7b1fe9c9cb..7b1fe9c9cb 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_gen.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_gen.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_key.c b/drivers/builtin_openssl2/crypto/dh/dh_key.c
index 89a74db4e6..89a74db4e6 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_key.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_key.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_lib.c b/drivers/builtin_openssl2/crypto/dh/dh_lib.c
index 00218f2b92..00218f2b92 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_lib.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_lib.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_pmeth.c b/drivers/builtin_openssl2/crypto/dh/dh_pmeth.c
index 5ae72b7d4c..5ae72b7d4c 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_pmeth.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_pmeth.c
diff --git a/drivers/builtin_openssl/crypto/dh/dh_prn.c b/drivers/builtin_openssl2/crypto/dh/dh_prn.c
index ae58c2ac87..ae58c2ac87 100644
--- a/drivers/builtin_openssl/crypto/dh/dh_prn.c
+++ b/drivers/builtin_openssl2/crypto/dh/dh_prn.c
diff --git a/drivers/builtin_openssl/crypto/dh/dhtest.c b/drivers/builtin_openssl2/crypto/dh/dhtest.c
index 882f5c310a..882f5c310a 100644
--- a/drivers/builtin_openssl/crypto/dh/dhtest.c
+++ b/drivers/builtin_openssl2/crypto/dh/dhtest.c
diff --git a/drivers/builtin_openssl/crypto/dh/example b/drivers/builtin_openssl2/crypto/dh/example
index 16a33d2910..16a33d2910 100644
--- a/drivers/builtin_openssl/crypto/dh/example
+++ b/drivers/builtin_openssl2/crypto/dh/example
diff --git a/drivers/builtin_openssl/crypto/dh/generate b/drivers/builtin_openssl2/crypto/dh/generate
index 5d407231df..5d407231df 100644
--- a/drivers/builtin_openssl/crypto/dh/generate
+++ b/drivers/builtin_openssl2/crypto/dh/generate
diff --git a/drivers/builtin_openssl/crypto/dh/p1024.c b/drivers/builtin_openssl2/crypto/dh/p1024.c
index 368ceca4eb..368ceca4eb 100644
--- a/drivers/builtin_openssl/crypto/dh/p1024.c
+++ b/drivers/builtin_openssl2/crypto/dh/p1024.c
diff --git a/drivers/builtin_openssl/crypto/dh/p192.c b/drivers/builtin_openssl2/crypto/dh/p192.c
index 7bdf40410e..7bdf40410e 100644
--- a/drivers/builtin_openssl/crypto/dh/p192.c
+++ b/drivers/builtin_openssl2/crypto/dh/p192.c
diff --git a/drivers/builtin_openssl/crypto/dh/p512.c b/drivers/builtin_openssl2/crypto/dh/p512.c
index a9b6aa83f0..a9b6aa83f0 100644
--- a/drivers/builtin_openssl/crypto/dh/p512.c
+++ b/drivers/builtin_openssl2/crypto/dh/p512.c
diff --git a/drivers/builtin_openssl/crypto/dsa/README b/drivers/builtin_openssl2/crypto/dsa/README
index 6a7e9c170a..6a7e9c170a 100644
--- a/drivers/builtin_openssl/crypto/dsa/README
+++ b/drivers/builtin_openssl2/crypto/dsa/README
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_ameth.c b/drivers/builtin_openssl2/crypto/dsa/dsa_ameth.c
index 376156ec5e..376156ec5e 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_ameth.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_ameth.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_asn1.c b/drivers/builtin_openssl2/crypto/dsa/dsa_asn1.c
index 6058534374..6058534374 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_asn1.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_asn1.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_depr.c b/drivers/builtin_openssl2/crypto/dsa/dsa_depr.c
index f2da680eb4..f2da680eb4 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_depr.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_depr.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_err.c b/drivers/builtin_openssl2/crypto/dsa/dsa_err.c
index 00545b7b9f..00545b7b9f 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_err.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_err.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_gen.c b/drivers/builtin_openssl2/crypto/dsa/dsa_gen.c
index c398761d0d..c398761d0d 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_gen.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_gen.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_key.c b/drivers/builtin_openssl2/crypto/dsa/dsa_key.c
index 9cf669b921..9cf669b921 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_key.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_key.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_lib.c b/drivers/builtin_openssl2/crypto/dsa/dsa_lib.c
index 96d8d0c4b4..96d8d0c4b4 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_lib.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_lib.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_locl.h b/drivers/builtin_openssl2/crypto/dsa/dsa_locl.h
index 21e2e45242..21e2e45242 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_locl.h
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_locl.h
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_ossl.c b/drivers/builtin_openssl2/crypto/dsa/dsa_ossl.c
index b3d78e524c..b3d78e524c 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_ossl.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_ossl.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_pmeth.c b/drivers/builtin_openssl2/crypto/dsa/dsa_pmeth.c
index 715d8d675b..715d8d675b 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_pmeth.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_pmeth.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_prn.c b/drivers/builtin_openssl2/crypto/dsa/dsa_prn.c
index 6f29f5e240..6f29f5e240 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_prn.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_prn.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_sign.c b/drivers/builtin_openssl2/crypto/dsa/dsa_sign.c
index c3cc3642ce..c3cc3642ce 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_sign.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_sign.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa_vrf.c b/drivers/builtin_openssl2/crypto/dsa/dsa_vrf.c
index 674cb5fa5f..674cb5fa5f 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa_vrf.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsa_vrf.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsagen.c b/drivers/builtin_openssl2/crypto/dsa/dsagen.c
index 1b6a1cca0f..1b6a1cca0f 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsagen.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsagen.c
diff --git a/drivers/builtin_openssl/crypto/dsa/dsatest.c b/drivers/builtin_openssl2/crypto/dsa/dsatest.c
index edffd24e6b..edffd24e6b 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsatest.c
+++ b/drivers/builtin_openssl2/crypto/dsa/dsatest.c
diff --git a/drivers/builtin_openssl/crypto/dsa/fips186a.txt b/drivers/builtin_openssl2/crypto/dsa/fips186a.txt
index 3a2e0a0d51..3a2e0a0d51 100644
--- a/drivers/builtin_openssl/crypto/dsa/fips186a.txt
+++ b/drivers/builtin_openssl2/crypto/dsa/fips186a.txt
diff --git a/drivers/builtin_openssl/crypto/dso/README b/drivers/builtin_openssl2/crypto/dso/README
index d0bc9a89fb..d0bc9a89fb 100644
--- a/drivers/builtin_openssl/crypto/dso/README
+++ b/drivers/builtin_openssl2/crypto/dso/README
diff --git a/drivers/builtin_openssl/crypto/dso/dso_beos.c b/drivers/builtin_openssl2/crypto/dso/dso_beos.c
index 553966e699..553966e699 100644
--- a/drivers/builtin_openssl/crypto/dso/dso_beos.c
+++ b/drivers/builtin_openssl2/crypto/dso/dso_beos.c
diff --git a/drivers/builtin_openssl/crypto/dso/dso_dl.c b/drivers/builtin_openssl2/crypto/dso/dso_dl.c
index fc4236bd9a..fc4236bd9a 100644
--- a/drivers/builtin_openssl/crypto/dso/dso_dl.c
+++ b/drivers/builtin_openssl2/crypto/dso/dso_dl.c
diff --git a/drivers/builtin_openssl2/crypto/dso/dso_dlfcn.c b/drivers/builtin_openssl2/crypto/dso/dso_dlfcn.c
new file mode 100644
index 0000000000..4a56aace0e
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/dso/dso_dlfcn.c
@@ -0,0 +1,484 @@
+/* dso_dlfcn.c -*- mode:C; c-file-style: "eay" -*- */
+/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/* We need to do this early, because stdio.h includes the header files
+ that handle _GNU_SOURCE and other similar macros. Defining it later
+ is simply too late, because those headers are protected from re-
+ inclusion. */
+#ifdef __linux
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE /* make sure dladdr is declared */
+# endif
+#endif
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/dso.h>
+
+#ifndef DSO_DLFCN
+DSO_METHOD *DSO_METHOD_dlfcn(void)
+ {
+ return NULL;
+ }
+#else
+
+#ifdef HAVE_DLFCN_H
+# ifdef __osf__
+# define __EXTENSIONS__
+# endif
+# include <dlfcn.h>
+# define HAVE_DLINFO 1
+# if defined(_AIX) || defined(__CYGWIN__) || \
+ defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
+ (defined(__osf__) && !defined(RTLD_NEXT)) || \
+ (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
+ defined(__ANDROID__)
+# undef HAVE_DLINFO
+# endif
+#endif
+
+/* Part of the hack in "dlfcn_load" ... */
+#define DSO_MAX_TRANSLATED_SIZE 256
+
+static int dlfcn_load(DSO *dso);
+static int dlfcn_unload(DSO *dso);
+static void *dlfcn_bind_var(DSO *dso, const char *symname);
+static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
+#if 0
+static int dlfcn_unbind(DSO *dso, char *symname, void *symptr);
+static int dlfcn_init(DSO *dso);
+static int dlfcn_finish(DSO *dso);
+static long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg);
+#endif
+static char *dlfcn_name_converter(DSO *dso, const char *filename);
+static char *dlfcn_merger(DSO *dso, const char *filespec1,
+ const char *filespec2);
+static int dlfcn_pathbyaddr(void *addr,char *path,int sz);
+static void *dlfcn_globallookup(const char *name);
+
+static DSO_METHOD dso_meth_dlfcn = {
+ "OpenSSL 'dlfcn' shared library method",
+ dlfcn_load,
+ dlfcn_unload,
+ dlfcn_bind_var,
+ dlfcn_bind_func,
+/* For now, "unbind" doesn't exist */
+#if 0
+ NULL, /* unbind_var */
+ NULL, /* unbind_func */
+#endif
+ NULL, /* ctrl */
+ dlfcn_name_converter,
+ dlfcn_merger,
+ NULL, /* init */
+ NULL, /* finish */
+ dlfcn_pathbyaddr,
+ dlfcn_globallookup
+ };
+
+DSO_METHOD *DSO_METHOD_dlfcn(void)
+ {
+ return(&dso_meth_dlfcn);
+ }
+
+/* Prior to using the dlopen() function, we should decide on the flag
+ * we send. There's a few different ways of doing this and it's a
+ * messy venn-diagram to match up which platforms support what. So
+ * as we don't have autoconf yet, I'm implementing a hack that could
+ * be hacked further relatively easily to deal with cases as we find
+ * them. Initially this is to cope with OpenBSD. */
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+# ifdef DL_LAZY
+# define DLOPEN_FLAG DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define DLOPEN_FLAG RTLD_NOW
+# else
+# define DLOPEN_FLAG 0
+# endif
+# endif
+#else
+# ifdef OPENSSL_SYS_SUNOS
+# define DLOPEN_FLAG 1
+# else
+# define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */
+# endif
+#endif
+
+/* For this DSO_METHOD, our meth_data STACK will contain;
+ * (i) the handle (void*) returned from dlopen().
+ */
+
+static int dlfcn_load(DSO *dso)
+ {
+ void *ptr = NULL;
+ /* See applicable comments in dso_dl.c */
+ char *filename = DSO_convert_filename(dso, NULL);
+ int flags = DLOPEN_FLAG;
+
+ if(filename == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_LOAD,DSO_R_NO_FILENAME);
+ goto err;
+ }
+
+#ifdef RTLD_GLOBAL
+ if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS)
+ flags |= RTLD_GLOBAL;
+#endif
+ ptr = dlopen(filename, flags);
+ if(ptr == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_LOAD,DSO_R_LOAD_FAILED);
+ ERR_add_error_data(4, "filename(", filename, "): ", dlerror());
+ goto err;
+ }
+ if(!sk_void_push(dso->meth_data, (char *)ptr))
+ {
+ DSOerr(DSO_F_DLFCN_LOAD,DSO_R_STACK_ERROR);
+ goto err;
+ }
+ /* Success */
+ dso->loaded_filename = filename;
+ return(1);
+err:
+ /* Cleanup! */
+ if(filename != NULL)
+ OPENSSL_free(filename);
+ if(ptr != NULL)
+ dlclose(ptr);
+ return(0);
+}
+
+static int dlfcn_unload(DSO *dso)
+ {
+ void *ptr;
+ if(dso == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
+ return(0);
+ }
+ if(sk_void_num(dso->meth_data) < 1)
+ return(1);
+ ptr = sk_void_pop(dso->meth_data);
+ if(ptr == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_UNLOAD,DSO_R_NULL_HANDLE);
+ /* Should push the value back onto the stack in
+ * case of a retry. */
+ sk_void_push(dso->meth_data, ptr);
+ return(0);
+ }
+ /* For now I'm not aware of any errors associated with dlclose() */
+ dlclose(ptr);
+ return(1);
+ }
+
+static void *dlfcn_bind_var(DSO *dso, const char *symname)
+ {
+ void *ptr, *sym;
+
+ if((dso == NULL) || (symname == NULL))
+ {
+ DSOerr(DSO_F_DLFCN_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER);
+ return(NULL);
+ }
+ if(sk_void_num(dso->meth_data) < 1)
+ {
+ DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_STACK_ERROR);
+ return(NULL);
+ }
+ ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
+ if(ptr == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_NULL_HANDLE);
+ return(NULL);
+ }
+ sym = dlsym(ptr, symname);
+ if(sym == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_SYM_FAILURE);
+ ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
+ return(NULL);
+ }
+ return(sym);
+ }
+
+static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
+ {
+ void *ptr;
+ union {
+ DSO_FUNC_TYPE sym;
+ void *dlret;
+ } u;
+
+ if((dso == NULL) || (symname == NULL))
+ {
+ DSOerr(DSO_F_DLFCN_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER);
+ return(NULL);
+ }
+ if(sk_void_num(dso->meth_data) < 1)
+ {
+ DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_STACK_ERROR);
+ return(NULL);
+ }
+ ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
+ if(ptr == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_NULL_HANDLE);
+ return(NULL);
+ }
+ u.dlret = dlsym(ptr, symname);
+ if(u.dlret == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_SYM_FAILURE);
+ ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
+ return(NULL);
+ }
+ return u.sym;
+ }
+
+static char *dlfcn_merger(DSO *dso, const char *filespec1,
+ const char *filespec2)
+ {
+ char *merged;
+
+ if(!filespec1 && !filespec2)
+ {
+ DSOerr(DSO_F_DLFCN_MERGER,
+ ERR_R_PASSED_NULL_PARAMETER);
+ return(NULL);
+ }
+ /* If the first file specification is a rooted path, it rules.
+ same goes if the second file specification is missing. */
+ if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/'))
+ {
+ merged = OPENSSL_malloc(strlen(filespec1) + 1);
+ if(!merged)
+ {
+ DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ strcpy(merged, filespec1);
+ }
+ /* If the first file specification is missing, the second one rules. */
+ else if (!filespec1)
+ {
+ merged = OPENSSL_malloc(strlen(filespec2) + 1);
+ if(!merged)
+ {
+ DSOerr(DSO_F_DLFCN_MERGER,
+ ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ strcpy(merged, filespec2);
+ }
+ else
+ /* This part isn't as trivial as it looks. It assumes that
+ the second file specification really is a directory, and
+ makes no checks whatsoever. Therefore, the result becomes
+ the concatenation of filespec2 followed by a slash followed
+ by filespec1. */
+ {
+ int spec2len, len;
+
+ spec2len = strlen(filespec2);
+ len = spec2len + (filespec1 ? strlen(filespec1) : 0);
+
+ if(filespec2 && filespec2[spec2len - 1] == '/')
+ {
+ spec2len--;
+ len--;
+ }
+ merged = OPENSSL_malloc(len + 2);
+ if(!merged)
+ {
+ DSOerr(DSO_F_DLFCN_MERGER,
+ ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ strcpy(merged, filespec2);
+ merged[spec2len] = '/';
+ strcpy(&merged[spec2len + 1], filespec1);
+ }
+ return(merged);
+ }
+
+#ifdef OPENSSL_SYS_MACOSX
+#define DSO_ext ".dylib"
+#define DSO_extlen 6
+#else
+#define DSO_ext ".so"
+#define DSO_extlen 3
+#endif
+
+
+static char *dlfcn_name_converter(DSO *dso, const char *filename)
+ {
+ char *translated;
+ int len, rsize, transform;
+
+ len = strlen(filename);
+ rsize = len + 1;
+ transform = (strstr(filename, "/") == NULL);
+ if(transform)
+ {
+ /* We will convert this to "%s.so" or "lib%s.so" etc */
+ rsize += DSO_extlen; /* The length of ".so" */
+ if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
+ rsize += 3; /* The length of "lib" */
+ }
+ translated = OPENSSL_malloc(rsize);
+ if(translated == NULL)
+ {
+ DSOerr(DSO_F_DLFCN_NAME_CONVERTER,
+ DSO_R_NAME_TRANSLATION_FAILED);
+ return(NULL);
+ }
+ if(transform)
+ {
+ if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
+ sprintf(translated, "lib%s" DSO_ext, filename);
+ else
+ sprintf(translated, "%s" DSO_ext, filename);
+ }
+ else
+ sprintf(translated, "%s", filename);
+ return(translated);
+ }
+
+#ifdef __sgi
+/*
+This is a quote from IRIX manual for dladdr(3c):
+
+ <dlfcn.h> does not contain a prototype for dladdr or definition of
+ Dl_info. The #include <dlfcn.h> in the SYNOPSIS line is traditional,
+ but contains no dladdr prototype and no IRIX library contains an
+ implementation. Write your own declaration based on the code below.
+
+ The following code is dependent on internal interfaces that are not
+ part of the IRIX compatibility guarantee; however, there is no future
+ intention to change this interface, so on a practical level, the code
+ below is safe to use on IRIX.
+*/
+#include <rld_interface.h>
+#ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
+#define _RLD_INTERFACE_DLFCN_H_DLADDR
+typedef struct Dl_info {
+ const char * dli_fname;
+ void * dli_fbase;
+ const char * dli_sname;
+ void * dli_saddr;
+ int dli_version;
+ int dli_reserved1;
+ long dli_reserved[4];
+} Dl_info;
+#else
+typedef struct Dl_info Dl_info;
+#endif
+#define _RLD_DLADDR 14
+
+static int dladdr(void *address, Dl_info *dl)
+{
+ void *v;
+ v = _rld_new_interface(_RLD_DLADDR,address,dl);
+ return (int)v;
+}
+#endif /* __sgi */
+
+static int dlfcn_pathbyaddr(void *addr,char *path,int sz)
+ {
+#ifdef HAVE_DLINFO
+ Dl_info dli;
+ int len;
+
+ if (addr == NULL)
+ {
+ union { int(*f)(void*,char*,int); void *p; } t =
+ { dlfcn_pathbyaddr };
+ addr = t.p;
+ }
+
+ if (dladdr(addr,&dli))
+ {
+ len = (int)strlen(dli.dli_fname);
+ if (sz <= 0) return len+1;
+ if (len >= sz) len=sz-1;
+ memcpy(path,dli.dli_fname,len);
+ path[len++]=0;
+ return len;
+ }
+
+ ERR_add_error_data(2, "dlfcn_pathbyaddr(): ", dlerror());
+#endif
+ return -1;
+ }
+
+static void *dlfcn_globallookup(const char *name)
+ {
+ void *ret = NULL,*handle = dlopen(NULL,RTLD_LAZY);
+
+ if (handle)
+ {
+ ret = dlsym(handle,name);
+ dlclose(handle);
+ }
+
+ return ret;
+ }
+#endif /* DSO_DLFCN */
diff --git a/drivers/builtin_openssl/crypto/dso/dso_err.c b/drivers/builtin_openssl2/crypto/dso/dso_err.c
index 2bb07c2514..2bb07c2514 100644
--- a/drivers/builtin_openssl/crypto/dso/dso_err.c
+++ b/drivers/builtin_openssl2/crypto/dso/dso_err.c
diff --git a/drivers/builtin_openssl/crypto/dso/dso_lib.c b/drivers/builtin_openssl2/crypto/dso/dso_lib.c
index 8a15b794ab..8a15b794ab 100644
--- a/drivers/builtin_openssl/crypto/dso/dso_lib.c
+++ b/drivers/builtin_openssl2/crypto/dso/dso_lib.c
diff --git a/drivers/builtin_openssl/crypto/dso/dso_null.c b/drivers/builtin_openssl2/crypto/dso/dso_null.c
index 49d842d1f5..49d842d1f5 100644
--- a/drivers/builtin_openssl/crypto/dso/dso_null.c
+++ b/drivers/builtin_openssl2/crypto/dso/dso_null.c
diff --git a/drivers/builtin_openssl/crypto/dso/dso_openssl.c b/drivers/builtin_openssl2/crypto/dso/dso_openssl.c
index b17e8e8e9e..b17e8e8e9e 100644
--- a/drivers/builtin_openssl/crypto/dso/dso_openssl.c
+++ b/drivers/builtin_openssl2/crypto/dso/dso_openssl.c
diff --git a/drivers/builtin_openssl2/crypto/dso/dso_vms.c b/drivers/builtin_openssl2/crypto/dso/dso_vms.c
new file mode 100644
index 0000000000..868513c391
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/dso/dso_vms.c
@@ -0,0 +1,525 @@
+/* dso_vms.c -*- mode:C; c-file-style: "eay" -*- */
+/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "cryptlib.h"
+#include <openssl/dso.h>
+
+#ifndef OPENSSL_SYS_VMS
+DSO_METHOD *DSO_METHOD_vms(void)
+ {
+ return NULL;
+ }
+#else
+
+#pragma message disable DOLLARID
+#include <rms.h>
+#include <lib$routines.h>
+#include <stsdef.h>
+#include <descrip.h>
+#include <starlet.h>
+#include "vms_rms.h"
+
+/* Some compiler options may mask the declaration of "_malloc32". */
+#if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE
+# if __INITIAL_POINTER_SIZE == 64
+# pragma pointer_size save
+# pragma pointer_size 32
+ void * _malloc32 (__size_t);
+# pragma pointer_size restore
+# endif /* __INITIAL_POINTER_SIZE == 64 */
+#endif /* __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE */
+
+
+#pragma message disable DOLLARID
+
+static int vms_load(DSO *dso);
+static int vms_unload(DSO *dso);
+static void *vms_bind_var(DSO *dso, const char *symname);
+static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname);
+#if 0
+static int vms_unbind_var(DSO *dso, char *symname, void *symptr);
+static int vms_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
+static int vms_init(DSO *dso);
+static int vms_finish(DSO *dso);
+static long vms_ctrl(DSO *dso, int cmd, long larg, void *parg);
+#endif
+static char *vms_name_converter(DSO *dso, const char *filename);
+static char *vms_merger(DSO *dso, const char *filespec1,
+ const char *filespec2);
+
+static DSO_METHOD dso_meth_vms = {
+ "OpenSSL 'VMS' shared library method",
+ vms_load,
+ NULL, /* unload */
+ vms_bind_var,
+ vms_bind_func,
+/* For now, "unbind" doesn't exist */
+#if 0
+ NULL, /* unbind_var */
+ NULL, /* unbind_func */
+#endif
+ NULL, /* ctrl */
+ vms_name_converter,
+ vms_merger,
+ NULL, /* init */
+ NULL /* finish */
+ };
+
+/* On VMS, the only "handle" is the file name. LIB$FIND_IMAGE_SYMBOL depends
+ * on the reference to the file name being the same for all calls regarding
+ * one shared image, so we'll just store it in an instance of the following
+ * structure and put a pointer to that instance in the meth_data stack.
+ */
+typedef struct dso_internal_st
+ {
+ /* This should contain the name only, no directory,
+ * no extension, nothing but a name. */
+ struct dsc$descriptor_s filename_dsc;
+ char filename[ NAMX_MAXRSS+ 1];
+ /* This contains whatever is not in filename, if needed.
+ * Normally not defined. */
+ struct dsc$descriptor_s imagename_dsc;
+ char imagename[ NAMX_MAXRSS+ 1];
+ } DSO_VMS_INTERNAL;
+
+DSO_METHOD *DSO_METHOD_vms(void)
+ {
+ return(&dso_meth_vms);
+ }
+
+static int vms_load(DSO *dso)
+ {
+ void *ptr = NULL;
+ /* See applicable comments in dso_dl.c */
+ char *filename = DSO_convert_filename(dso, NULL);
+
+/* Ensure 32-bit pointer for "p", and appropriate malloc() function. */
+#if __INITIAL_POINTER_SIZE == 64
+# define DSO_MALLOC _malloc32
+# pragma pointer_size save
+# pragma pointer_size 32
+#else /* __INITIAL_POINTER_SIZE == 64 */
+# define DSO_MALLOC OPENSSL_malloc
+#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
+
+ DSO_VMS_INTERNAL *p = NULL;
+
+#if __INITIAL_POINTER_SIZE == 64
+# pragma pointer_size restore
+#endif /* __INITIAL_POINTER_SIZE == 64 */
+
+ const char *sp1, *sp2; /* Search result */
+
+ if(filename == NULL)
+ {
+ DSOerr(DSO_F_VMS_LOAD,DSO_R_NO_FILENAME);
+ goto err;
+ }
+
+ /* A file specification may look like this:
+ *
+ * node::dev:[dir-spec]name.type;ver
+ *
+ * or (for compatibility with TOPS-20):
+ *
+ * node::dev:<dir-spec>name.type;ver
+ *
+ * and the dir-spec uses '.' as separator. Also, a dir-spec
+ * may consist of several parts, with mixed use of [] and <>:
+ *
+ * [dir1.]<dir2>
+ *
+ * We need to split the file specification into the name and
+ * the rest (both before and after the name itself).
+ */
+ /* Start with trying to find the end of a dir-spec, and save the
+ position of the byte after in sp1 */
+ sp1 = strrchr(filename, ']');
+ sp2 = strrchr(filename, '>');
+ if (sp1 == NULL) sp1 = sp2;
+ if (sp2 != NULL && sp2 > sp1) sp1 = sp2;
+ if (sp1 == NULL) sp1 = strrchr(filename, ':');
+ if (sp1 == NULL)
+ sp1 = filename;
+ else
+ sp1++; /* The byte after the found character */
+ /* Now, let's see if there's a type, and save the position in sp2 */
+ sp2 = strchr(sp1, '.');
+ /* If we found it, that's where we'll cut. Otherwise, look for a
+ version number and save the position in sp2 */
+ if (sp2 == NULL) sp2 = strchr(sp1, ';');
+ /* If there was still nothing to find, set sp2 to point at the end of
+ the string */
+ if (sp2 == NULL) sp2 = sp1 + strlen(sp1);
+
+ /* Check that we won't get buffer overflows */
+ if (sp2 - sp1 > FILENAME_MAX
+ || (sp1 - filename) + strlen(sp2) > FILENAME_MAX)
+ {
+ DSOerr(DSO_F_VMS_LOAD,DSO_R_FILENAME_TOO_BIG);
+ goto err;
+ }
+
+ p = DSO_MALLOC(sizeof(DSO_VMS_INTERNAL));
+ if(p == NULL)
+ {
+ DSOerr(DSO_F_VMS_LOAD,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ strncpy(p->filename, sp1, sp2-sp1);
+ p->filename[sp2-sp1] = '\0';
+
+ strncpy(p->imagename, filename, sp1-filename);
+ p->imagename[sp1-filename] = '\0';
+ strcat(p->imagename, sp2);
+
+ p->filename_dsc.dsc$w_length = strlen(p->filename);
+ p->filename_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ p->filename_dsc.dsc$b_class = DSC$K_CLASS_S;
+ p->filename_dsc.dsc$a_pointer = p->filename;
+ p->imagename_dsc.dsc$w_length = strlen(p->imagename);
+ p->imagename_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ p->imagename_dsc.dsc$b_class = DSC$K_CLASS_S;
+ p->imagename_dsc.dsc$a_pointer = p->imagename;
+
+ if(!sk_void_push(dso->meth_data, (char *)p))
+ {
+ DSOerr(DSO_F_VMS_LOAD,DSO_R_STACK_ERROR);
+ goto err;
+ }
+
+ /* Success (for now, we lie. We actually do not know...) */
+ dso->loaded_filename = filename;
+ return(1);
+err:
+ /* Cleanup! */
+ if(p != NULL)
+ OPENSSL_free(p);
+ if(filename != NULL)
+ OPENSSL_free(filename);
+ return(0);
+ }
+
+/* Note that this doesn't actually unload the shared image, as there is no
+ * such thing in VMS. Next time it get loaded again, a new copy will
+ * actually be loaded.
+ */
+static int vms_unload(DSO *dso)
+ {
+ DSO_VMS_INTERNAL *p;
+ if(dso == NULL)
+ {
+ DSOerr(DSO_F_VMS_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
+ return(0);
+ }
+ if(sk_void_num(dso->meth_data) < 1)
+ return(1);
+ p = (DSO_VMS_INTERNAL *)sk_void_pop(dso->meth_data);
+ if(p == NULL)
+ {
+ DSOerr(DSO_F_VMS_UNLOAD,DSO_R_NULL_HANDLE);
+ return(0);
+ }
+ /* Cleanup */
+ OPENSSL_free(p);
+ return(1);
+ }
+
+/* We must do this in a separate function because of the way the exception
+ handler works (it makes this function return */
+static int do_find_symbol(DSO_VMS_INTERNAL *ptr,
+ struct dsc$descriptor_s *symname_dsc, void **sym,
+ unsigned long flags)
+ {
+ /* Make sure that signals are caught and returned instead of
+ aborting the program. The exception handler gets unestablished
+ automatically on return from this function. */
+ lib$establish(lib$sig_to_ret);
+
+ if(ptr->imagename_dsc.dsc$w_length)
+ return lib$find_image_symbol(&ptr->filename_dsc,
+ symname_dsc, sym,
+ &ptr->imagename_dsc, flags);
+ else
+ return lib$find_image_symbol(&ptr->filename_dsc,
+ symname_dsc, sym,
+ 0, flags);
+ }
+
+void vms_bind_sym(DSO *dso, const char *symname, void **sym)
+ {
+ DSO_VMS_INTERNAL *ptr;
+ int status;
+#if 0
+ int flags = (1<<4); /* LIB$M_FIS_MIXEDCASE, but this symbol isn't
+ defined in VMS older than 7.0 or so */
+#else
+ int flags = 0;
+#endif
+ struct dsc$descriptor_s symname_dsc;
+
+/* Arrange 32-bit pointer to (copied) string storage, if needed. */
+#if __INITIAL_POINTER_SIZE == 64
+# define SYMNAME symname_32p
+# pragma pointer_size save
+# pragma pointer_size 32
+ char *symname_32p;
+# pragma pointer_size restore
+ char symname_32[ NAMX_MAXRSS+ 1];
+#else /* __INITIAL_POINTER_SIZE == 64 */
+# define SYMNAME ((char *) symname)
+#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
+
+ *sym = NULL;
+
+ if((dso == NULL) || (symname == NULL))
+ {
+ DSOerr(DSO_F_VMS_BIND_SYM,ERR_R_PASSED_NULL_PARAMETER);
+ return;
+ }
+
+#if __INITIAL_POINTER_SIZE == 64
+ /* Copy the symbol name to storage with a 32-bit pointer. */
+ symname_32p = symname_32;
+ strcpy( symname_32p, symname);
+#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
+
+ symname_dsc.dsc$w_length = strlen(SYMNAME);
+ symname_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ symname_dsc.dsc$b_class = DSC$K_CLASS_S;
+ symname_dsc.dsc$a_pointer = SYMNAME;
+
+ if(sk_void_num(dso->meth_data) < 1)
+ {
+ DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_STACK_ERROR);
+ return;
+ }
+ ptr = (DSO_VMS_INTERNAL *)sk_void_value(dso->meth_data,
+ sk_void_num(dso->meth_data) - 1);
+ if(ptr == NULL)
+ {
+ DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_NULL_HANDLE);
+ return;
+ }
+
+ if(dso->flags & DSO_FLAG_UPCASE_SYMBOL) flags = 0;
+
+ status = do_find_symbol(ptr, &symname_dsc, sym, flags);
+
+ if(!$VMS_STATUS_SUCCESS(status))
+ {
+ unsigned short length;
+ char errstring[257];
+ struct dsc$descriptor_s errstring_dsc;
+
+ errstring_dsc.dsc$w_length = sizeof(errstring);
+ errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
+ errstring_dsc.dsc$a_pointer = errstring;
+
+ *sym = NULL;
+
+ status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
+
+ if (!$VMS_STATUS_SUCCESS(status))
+ lib$signal(status); /* This is really bad. Abort! */
+ else
+ {
+ errstring[length] = '\0';
+
+ DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_SYM_FAILURE);
+ if (ptr->imagename_dsc.dsc$w_length)
+ ERR_add_error_data(9,
+ "Symbol ", symname,
+ " in ", ptr->filename,
+ " (", ptr->imagename, ")",
+ ": ", errstring);
+ else
+ ERR_add_error_data(6,
+ "Symbol ", symname,
+ " in ", ptr->filename,
+ ": ", errstring);
+ }
+ return;
+ }
+ return;
+ }
+
+static void *vms_bind_var(DSO *dso, const char *symname)
+ {
+ void *sym = 0;
+ vms_bind_sym(dso, symname, &sym);
+ return sym;
+ }
+
+static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname)
+ {
+ DSO_FUNC_TYPE sym = 0;
+ vms_bind_sym(dso, symname, (void **)&sym);
+ return sym;
+ }
+
+
+static char *vms_merger(DSO *dso, const char *filespec1, const char *filespec2)
+ {
+ int status;
+ int filespec1len, filespec2len;
+ struct FAB fab;
+ struct NAMX_STRUCT nam;
+ char esa[ NAMX_MAXRSS+ 1];
+ char *merged;
+
+/* Arrange 32-bit pointer to (copied) string storage, if needed. */
+#if __INITIAL_POINTER_SIZE == 64
+# define FILESPEC1 filespec1_32p;
+# define FILESPEC2 filespec2_32p;
+# pragma pointer_size save
+# pragma pointer_size 32
+ char *filespec1_32p;
+ char *filespec2_32p;
+# pragma pointer_size restore
+ char filespec1_32[ NAMX_MAXRSS+ 1];
+ char filespec2_32[ NAMX_MAXRSS+ 1];
+#else /* __INITIAL_POINTER_SIZE == 64 */
+# define FILESPEC1 ((char *) filespec1)
+# define FILESPEC2 ((char *) filespec2)
+#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
+
+ if (!filespec1) filespec1 = "";
+ if (!filespec2) filespec2 = "";
+ filespec1len = strlen(filespec1);
+ filespec2len = strlen(filespec2);
+
+#if __INITIAL_POINTER_SIZE == 64
+ /* Copy the file names to storage with a 32-bit pointer. */
+ filespec1_32p = filespec1_32;
+ filespec2_32p = filespec2_32;
+ strcpy( filespec1_32p, filespec1);
+ strcpy( filespec2_32p, filespec2);
+#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
+
+ fab = cc$rms_fab;
+ nam = CC_RMS_NAMX;
+
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = FILESPEC1;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = filespec1len;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = FILESPEC2;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = filespec2len;
+ NAMX_DNA_FNA_SET( fab)
+
+ nam.NAMX_ESA = esa;
+ nam.NAMX_ESS = NAMX_MAXRSS;
+ nam.NAMX_NOP = NAM$M_SYNCHK | NAM$M_PWD;
+ SET_NAMX_NO_SHORT_UPCASE( nam);
+
+ fab.FAB_NAMX = &nam;
+
+ status = sys$parse(&fab, 0, 0);
+
+ if(!$VMS_STATUS_SUCCESS(status))
+ {
+ unsigned short length;
+ char errstring[257];
+ struct dsc$descriptor_s errstring_dsc;
+
+ errstring_dsc.dsc$w_length = sizeof(errstring);
+ errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
+ errstring_dsc.dsc$a_pointer = errstring;
+
+ status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
+
+ if (!$VMS_STATUS_SUCCESS(status))
+ lib$signal(status); /* This is really bad. Abort! */
+ else
+ {
+ errstring[length] = '\0';
+
+ DSOerr(DSO_F_VMS_MERGER,DSO_R_FAILURE);
+ ERR_add_error_data(7,
+ "filespec \"", filespec1, "\", ",
+ "defaults \"", filespec2, "\": ",
+ errstring);
+ }
+ return(NULL);
+ }
+
+ merged = OPENSSL_malloc( nam.NAMX_ESL+ 1);
+ if(!merged)
+ goto malloc_err;
+ strncpy( merged, nam.NAMX_ESA, nam.NAMX_ESL);
+ merged[ nam.NAMX_ESL] = '\0';
+ return(merged);
+ malloc_err:
+ DSOerr(DSO_F_VMS_MERGER,
+ ERR_R_MALLOC_FAILURE);
+ }
+
+static char *vms_name_converter(DSO *dso, const char *filename)
+ {
+ int len = strlen(filename);
+ char *not_translated = OPENSSL_malloc(len+1);
+ strcpy(not_translated,filename);
+ return(not_translated);
+ }
+
+#endif /* OPENSSL_SYS_VMS */
diff --git a/drivers/builtin_openssl/crypto/dso/dso_win32.c b/drivers/builtin_openssl2/crypto/dso/dso_win32.c
index 6fb6c54181..6fb6c54181 100644
--- a/drivers/builtin_openssl/crypto/dso/dso_win32.c
+++ b/drivers/builtin_openssl2/crypto/dso/dso_win32.c
diff --git a/drivers/builtin_openssl/crypto/ebcdic.c b/drivers/builtin_openssl2/crypto/ebcdic.c
index 43e53bcaf7..43e53bcaf7 100644
--- a/drivers/builtin_openssl/crypto/ebcdic.c
+++ b/drivers/builtin_openssl2/crypto/ebcdic.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec2_mult.c b/drivers/builtin_openssl2/crypto/ec/ec2_mult.c
index 1c575dc47a..1c575dc47a 100644
--- a/drivers/builtin_openssl/crypto/ec/ec2_mult.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec2_mult.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec2_oct.c b/drivers/builtin_openssl2/crypto/ec/ec2_oct.c
index f1d75e5ddf..f1d75e5ddf 100644
--- a/drivers/builtin_openssl/crypto/ec/ec2_oct.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec2_oct.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec2_smpl.c b/drivers/builtin_openssl2/crypto/ec/ec2_smpl.c
index e0e59c7d82..e0e59c7d82 100644
--- a/drivers/builtin_openssl/crypto/ec/ec2_smpl.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec2_smpl.c
diff --git a/drivers/builtin_openssl2/crypto/ec/ec_ameth.c b/drivers/builtin_openssl2/crypto/ec/ec_ameth.c
new file mode 100644
index 0000000000..f715a238a6
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/ec/ec_ameth.c
@@ -0,0 +1,661 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/x509.h>
+#include <openssl/ec.h>
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_CMS
+#include <openssl/cms.h>
+#endif
+#include "asn1_locl.h"
+
+static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key)
+ {
+ const EC_GROUP *group;
+ int nid;
+ if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL)
+ {
+ ECerr(EC_F_ECKEY_PARAM2TYPE, EC_R_MISSING_PARAMETERS);
+ return 0;
+ }
+ if (EC_GROUP_get_asn1_flag(group)
+ && (nid = EC_GROUP_get_curve_name(group)))
+ /* we have a 'named curve' => just set the OID */
+ {
+ *ppval = OBJ_nid2obj(nid);
+ *pptype = V_ASN1_OBJECT;
+ }
+ else /* explicit parameters */
+ {
+ ASN1_STRING *pstr = NULL;
+ pstr = ASN1_STRING_new();
+ if (!pstr)
+ return 0;
+ pstr->length = i2d_ECParameters(ec_key, &pstr->data);
+ if (pstr->length <= 0)
+ {
+ ASN1_STRING_free(pstr);
+ ECerr(EC_F_ECKEY_PARAM2TYPE, ERR_R_EC_LIB);
+ return 0;
+ }
+ *ppval = pstr;
+ *pptype = V_ASN1_SEQUENCE;
+ }
+ return 1;
+ }
+
+static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
+ {
+ EC_KEY *ec_key = pkey->pkey.ec;
+ void *pval = NULL;
+ int ptype;
+ unsigned char *penc = NULL, *p;
+ int penclen;
+
+ if (!eckey_param2type(&ptype, &pval, ec_key))
+ {
+ ECerr(EC_F_ECKEY_PUB_ENCODE, ERR_R_EC_LIB);
+ return 0;
+ }
+ penclen = i2o_ECPublicKey(ec_key, NULL);
+ if (penclen <= 0)
+ goto err;
+ penc = OPENSSL_malloc(penclen);
+ if (!penc)
+ goto err;
+ p = penc;
+ penclen = i2o_ECPublicKey(ec_key, &p);
+ if (penclen <= 0)
+ goto err;
+ if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC),
+ ptype, pval, penc, penclen))
+ return 1;
+ err:
+ if (ptype == V_ASN1_OBJECT)
+ ASN1_OBJECT_free(pval);
+ else
+ ASN1_STRING_free(pval);
+ if (penc)
+ OPENSSL_free(penc);
+ return 0;
+ }
+
+static EC_KEY *eckey_type2param(int ptype, void *pval)
+ {
+ EC_KEY *eckey = NULL;
+ if (ptype == V_ASN1_SEQUENCE)
+ {
+ ASN1_STRING *pstr = pval;
+ const unsigned char *pm = NULL;
+ int pmlen;
+ pm = pstr->data;
+ pmlen = pstr->length;
+ if (!(eckey = d2i_ECParameters(NULL, &pm, pmlen)))
+ {
+ ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR);
+ goto ecerr;
+ }
+ }
+ else if (ptype == V_ASN1_OBJECT)
+ {
+ ASN1_OBJECT *poid = pval;
+ EC_GROUP *group;
+
+ /* type == V_ASN1_OBJECT => the parameters are given
+ * by an asn1 OID
+ */
+ if ((eckey = EC_KEY_new()) == NULL)
+ {
+ ECerr(EC_F_ECKEY_TYPE2PARAM, ERR_R_MALLOC_FAILURE);
+ goto ecerr;
+ }
+ group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(poid));
+ if (group == NULL)
+ goto ecerr;
+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_set_group(eckey, group) == 0)
+ goto ecerr;
+ EC_GROUP_free(group);
+ }
+ else
+ {
+ ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR);
+ goto ecerr;
+ }
+
+ return eckey;
+
+ ecerr:
+ if (eckey)
+ EC_KEY_free(eckey);
+ return NULL;
+ }
+
+static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
+ {
+ const unsigned char *p = NULL;
+ void *pval;
+ int ptype, pklen;
+ EC_KEY *eckey = NULL;
+ X509_ALGOR *palg;
+
+ if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
+ return 0;
+ X509_ALGOR_get0(NULL, &ptype, &pval, palg);
+
+ eckey = eckey_type2param(ptype, pval);
+
+ if (!eckey)
+ {
+ ECerr(EC_F_ECKEY_PUB_DECODE, ERR_R_EC_LIB);
+ return 0;
+ }
+
+ /* We have parameters now set public key */
+ if (!o2i_ECPublicKey(&eckey, &p, pklen))
+ {
+ ECerr(EC_F_ECKEY_PUB_DECODE, EC_R_DECODE_ERROR);
+ goto ecerr;
+ }
+
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+
+ ecerr:
+ if (eckey)
+ EC_KEY_free(eckey);
+ return 0;
+ }
+
+static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
+ {
+ int r;
+ const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec);
+ const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec),
+ *pb = EC_KEY_get0_public_key(b->pkey.ec);
+ r = EC_POINT_cmp(group, pa, pb, NULL);
+ if (r == 0)
+ return 1;
+ if (r == 1)
+ return 0;
+ return -2;
+ }
+
+static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
+ {
+ const unsigned char *p = NULL;
+ void *pval;
+ int ptype, pklen;
+ EC_KEY *eckey = NULL;
+ X509_ALGOR *palg;
+
+ if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8))
+ return 0;
+ X509_ALGOR_get0(NULL, &ptype, &pval, palg);
+
+ eckey = eckey_type2param(ptype, pval);
+
+ if (!eckey)
+ goto ecliberr;
+
+ /* We have parameters now set private key */
+ if (!d2i_ECPrivateKey(&eckey, &p, pklen))
+ {
+ ECerr(EC_F_ECKEY_PRIV_DECODE, EC_R_DECODE_ERROR);
+ goto ecerr;
+ }
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(eckey) == NULL)
+ {
+ const BIGNUM *priv_key;
+ const EC_GROUP *group;
+ EC_POINT *pub_key;
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ group = EC_KEY_get0_group(eckey);
+ pub_key = EC_POINT_new(group);
+ if (pub_key == NULL)
+ {
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ goto ecliberr;
+ }
+ if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group)))
+ {
+ EC_POINT_free(pub_key);
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ goto ecliberr;
+ }
+ priv_key = EC_KEY_get0_private_key(eckey);
+ if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL))
+ {
+ EC_POINT_free(pub_key);
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ goto ecliberr;
+ }
+ if (EC_KEY_set_public_key(eckey, pub_key) == 0)
+ {
+ EC_POINT_free(pub_key);
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ goto ecliberr;
+ }
+ EC_POINT_free(pub_key);
+ }
+
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+
+ ecliberr:
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ ecerr:
+ if (eckey)
+ EC_KEY_free(eckey);
+ return 0;
+ }
+
+static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
+{
+ EC_KEY *ec_key;
+ unsigned char *ep, *p;
+ int eplen, ptype;
+ void *pval;
+ unsigned int tmp_flags, old_flags;
+
+ ec_key = pkey->pkey.ec;
+
+ if (!eckey_param2type(&ptype, &pval, ec_key))
+ {
+ ECerr(EC_F_ECKEY_PRIV_ENCODE, EC_R_DECODE_ERROR);
+ return 0;
+ }
+
+ /* set the private key */
+
+ /* do not include the parameters in the SEC1 private key
+ * see PKCS#11 12.11 */
+ old_flags = EC_KEY_get_enc_flags(ec_key);
+ tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS;
+ EC_KEY_set_enc_flags(ec_key, tmp_flags);
+ eplen = i2d_ECPrivateKey(ec_key, NULL);
+ if (!eplen)
+ {
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+ ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
+ return 0;
+ }
+ ep = (unsigned char *) OPENSSL_malloc(eplen);
+ if (!ep)
+ {
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+ ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ p = ep;
+ if (!i2d_ECPrivateKey(ec_key, &p))
+ {
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+ OPENSSL_free(ep);
+ ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
+ return 0;
+ }
+ /* restore old encoding flags */
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+
+ if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), 0,
+ ptype, pval, ep, eplen))
+ return 0;
+
+ return 1;
+}
+
+static int int_ec_size(const EVP_PKEY *pkey)
+ {
+ return ECDSA_size(pkey->pkey.ec);
+ }
+
+static int ec_bits(const EVP_PKEY *pkey)
+ {
+ BIGNUM *order = BN_new();
+ const EC_GROUP *group;
+ int ret;
+
+ if (!order)
+ {
+ ERR_clear_error();
+ return 0;
+ }
+ group = EC_KEY_get0_group(pkey->pkey.ec);
+ if (!EC_GROUP_get_order(group, order, NULL))
+ {
+ ERR_clear_error();
+ return 0;
+ }
+
+ ret = BN_num_bits(order);
+ BN_free(order);
+ return ret;
+ }
+
+static int ec_missing_parameters(const EVP_PKEY *pkey)
+ {
+ if (EC_KEY_get0_group(pkey->pkey.ec) == NULL)
+ return 1;
+ return 0;
+ }
+
+static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
+ {
+ EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec));
+ if (group == NULL)
+ return 0;
+ if (EC_KEY_set_group(to->pkey.ec, group) == 0)
+ return 0;
+ EC_GROUP_free(group);
+ return 1;
+ }
+
+static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
+ {
+ const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec),
+ *group_b = EC_KEY_get0_group(b->pkey.ec);
+ if (EC_GROUP_cmp(group_a, group_b, NULL))
+ return 0;
+ else
+ return 1;
+ }
+
+static void int_ec_free(EVP_PKEY *pkey)
+ {
+ EC_KEY_free(pkey->pkey.ec);
+ }
+
+static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype)
+ {
+ unsigned char *buffer=NULL;
+ const char *ecstr;
+ size_t buf_len=0, i;
+ int ret=0, reason=ERR_R_BIO_LIB;
+ BIGNUM *pub_key=NULL, *order=NULL;
+ BN_CTX *ctx=NULL;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ const BIGNUM *priv_key;
+
+ if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL)
+ {
+ reason = ERR_R_PASSED_NULL_PARAMETER;
+ goto err;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL)
+ {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+
+ if (ktype > 0)
+ {
+ public_key = EC_KEY_get0_public_key(x);
+ if ((pub_key = EC_POINT_point2bn(group, public_key,
+ EC_KEY_get_conv_form(x), NULL, ctx)) == NULL)
+ {
+ reason = ERR_R_EC_LIB;
+ goto err;
+ }
+ if (pub_key)
+ buf_len = (size_t)BN_num_bytes(pub_key);
+ }
+
+ if (ktype == 2)
+ {
+ priv_key = EC_KEY_get0_private_key(x);
+ if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len)
+ buf_len = i;
+ }
+ else
+ priv_key = NULL;
+
+ if (ktype > 0)
+ {
+ buf_len += 10;
+ if ((buffer = OPENSSL_malloc(buf_len)) == NULL)
+ {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ }
+ if (ktype == 2)
+ ecstr = "Private-Key";
+ else if (ktype == 1)
+ ecstr = "Public-Key";
+ else
+ ecstr = "ECDSA-Parameters";
+
+ if (!BIO_indent(bp, off, 128))
+ goto err;
+ if ((order = BN_new()) == NULL)
+ goto err;
+ if (!EC_GROUP_get_order(group, order, NULL))
+ goto err;
+ if (BIO_printf(bp, "%s: (%d bit)\n", ecstr,
+ BN_num_bits(order)) <= 0) goto err;
+
+ if ((priv_key != NULL) && !ASN1_bn_print(bp, "priv:", priv_key,
+ buffer, off))
+ goto err;
+ if ((pub_key != NULL) && !ASN1_bn_print(bp, "pub: ", pub_key,
+ buffer, off))
+ goto err;
+ if (!ECPKParameters_print(bp, group, off))
+ goto err;
+ ret=1;
+err:
+ if (!ret)
+ ECerr(EC_F_DO_EC_KEY_PRINT, reason);
+ if (pub_key)
+ BN_free(pub_key);
+ if (order)
+ BN_free(order);
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (buffer != NULL)
+ OPENSSL_free(buffer);
+ return(ret);
+ }
+
+static int eckey_param_decode(EVP_PKEY *pkey,
+ const unsigned char **pder, int derlen)
+ {
+ EC_KEY *eckey;
+ if (!(eckey = d2i_ECParameters(NULL, pder, derlen)))
+ {
+ ECerr(EC_F_ECKEY_PARAM_DECODE, ERR_R_EC_LIB);
+ return 0;
+ }
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+ }
+
+static int eckey_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
+ {
+ return i2d_ECParameters(pkey->pkey.ec, pder);
+ }
+
+static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx)
+ {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0);
+ }
+
+static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx)
+ {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1);
+ }
+
+
+static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx)
+ {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2);
+ }
+
+static int old_ec_priv_decode(EVP_PKEY *pkey,
+ const unsigned char **pder, int derlen)
+ {
+ EC_KEY *ec;
+ if (!(ec = d2i_ECPrivateKey (NULL, pder, derlen)))
+ {
+ ECerr(EC_F_OLD_EC_PRIV_DECODE, EC_R_DECODE_ERROR);
+ return 0;
+ }
+ EVP_PKEY_assign_EC_KEY(pkey, ec);
+ return 1;
+ }
+
+static int old_ec_priv_encode(const EVP_PKEY *pkey, unsigned char **pder)
+ {
+ return i2d_ECPrivateKey(pkey->pkey.ec, pder);
+ }
+
+static int ec_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
+ {
+ switch (op)
+ {
+ case ASN1_PKEY_CTRL_PKCS7_SIGN:
+ if (arg1 == 0)
+ {
+ int snid, hnid;
+ X509_ALGOR *alg1, *alg2;
+ PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, &alg1, &alg2);
+ if (alg1 == NULL || alg1->algorithm == NULL)
+ return -1;
+ hnid = OBJ_obj2nid(alg1->algorithm);
+ if (hnid == NID_undef)
+ return -1;
+ if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
+ return -1;
+ X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
+ }
+ return 1;
+#ifndef OPENSSL_NO_CMS
+ case ASN1_PKEY_CTRL_CMS_SIGN:
+ if (arg1 == 0)
+ {
+ int snid, hnid;
+ X509_ALGOR *alg1, *alg2;
+ CMS_SignerInfo_get0_algs(arg2, NULL, NULL,
+ &alg1, &alg2);
+ if (alg1 == NULL || alg1->algorithm == NULL)
+ return -1;
+ hnid = OBJ_obj2nid(alg1->algorithm);
+ if (hnid == NID_undef)
+ return -1;
+ if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
+ return -1;
+ X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
+ }
+ return 1;
+#endif
+
+ case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+ *(int *)arg2 = NID_sha1;
+ return 2;
+
+ default:
+ return -2;
+
+ }
+
+ }
+
+const EVP_PKEY_ASN1_METHOD eckey_asn1_meth =
+ {
+ EVP_PKEY_EC,
+ EVP_PKEY_EC,
+ 0,
+ "EC",
+ "OpenSSL EC algorithm",
+
+ eckey_pub_decode,
+ eckey_pub_encode,
+ eckey_pub_cmp,
+ eckey_pub_print,
+
+ eckey_priv_decode,
+ eckey_priv_encode,
+ eckey_priv_print,
+
+ int_ec_size,
+ ec_bits,
+
+ eckey_param_decode,
+ eckey_param_encode,
+ ec_missing_parameters,
+ ec_copy_parameters,
+ ec_cmp_parameters,
+ eckey_param_print,
+ 0,
+
+ int_ec_free,
+ ec_pkey_ctrl,
+ old_ec_priv_decode,
+ old_ec_priv_encode
+ };
diff --git a/drivers/builtin_openssl2/crypto/ec/ec_asn1.c b/drivers/builtin_openssl2/crypto/ec/ec_asn1.c
new file mode 100644
index 0000000000..e94f34e11b
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/ec/ec_asn1.c
@@ -0,0 +1,1448 @@
+/* crypto/ec/ec_asn1.c */
+/*
+ * Written by Nils Larsch for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2003 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <string.h>
+#include "ec_lcl.h"
+#include <openssl/err.h>
+#include <openssl/asn1t.h>
+#include <openssl/objects.h>
+
+
+int EC_GROUP_get_basis_type(const EC_GROUP *group)
+ {
+ int i=0;
+
+ if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
+ NID_X9_62_characteristic_two_field)
+ /* everything else is currently not supported */
+ return 0;
+
+ while (group->poly[i] != 0)
+ i++;
+
+ if (i == 4)
+ return NID_X9_62_ppBasis;
+ else if (i == 2)
+ return NID_X9_62_tpBasis;
+ else
+ /* everything else is currently not supported */
+ return 0;
+ }
+#ifndef OPENSSL_NO_EC2M
+int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k)
+ {
+ if (group == NULL)
+ return 0;
+
+ if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
+ NID_X9_62_characteristic_two_field
+ || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] == 0)))
+ {
+ ECerr(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ if (k)
+ *k = group->poly[1];
+
+ return 1;
+ }
+int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1,
+ unsigned int *k2, unsigned int *k3)
+ {
+ if (group == NULL)
+ return 0;
+
+ if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
+ NID_X9_62_characteristic_two_field
+ || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] != 0) && (group->poly[3] != 0) && (group->poly[4] == 0)))
+ {
+ ECerr(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ if (k1)
+ *k1 = group->poly[3];
+ if (k2)
+ *k2 = group->poly[2];
+ if (k3)
+ *k3 = group->poly[1];
+
+ return 1;
+ }
+#endif
+
+
+/* some structures needed for the asn1 encoding */
+typedef struct x9_62_pentanomial_st {
+ long k1;
+ long k2;
+ long k3;
+ } X9_62_PENTANOMIAL;
+
+typedef struct x9_62_characteristic_two_st {
+ long m;
+ ASN1_OBJECT *type;
+ union {
+ char *ptr;
+ /* NID_X9_62_onBasis */
+ ASN1_NULL *onBasis;
+ /* NID_X9_62_tpBasis */
+ ASN1_INTEGER *tpBasis;
+ /* NID_X9_62_ppBasis */
+ X9_62_PENTANOMIAL *ppBasis;
+ /* anything else */
+ ASN1_TYPE *other;
+ } p;
+ } X9_62_CHARACTERISTIC_TWO;
+
+typedef struct x9_62_fieldid_st {
+ ASN1_OBJECT *fieldType;
+ union {
+ char *ptr;
+ /* NID_X9_62_prime_field */
+ ASN1_INTEGER *prime;
+ /* NID_X9_62_characteristic_two_field */
+ X9_62_CHARACTERISTIC_TWO *char_two;
+ /* anything else */
+ ASN1_TYPE *other;
+ } p;
+ } X9_62_FIELDID;
+
+typedef struct x9_62_curve_st {
+ ASN1_OCTET_STRING *a;
+ ASN1_OCTET_STRING *b;
+ ASN1_BIT_STRING *seed;
+ } X9_62_CURVE;
+
+typedef struct ec_parameters_st {
+ long version;
+ X9_62_FIELDID *fieldID;
+ X9_62_CURVE *curve;
+ ASN1_OCTET_STRING *base;
+ ASN1_INTEGER *order;
+ ASN1_INTEGER *cofactor;
+ } ECPARAMETERS;
+
+struct ecpk_parameters_st {
+ int type;
+ union {
+ ASN1_OBJECT *named_curve;
+ ECPARAMETERS *parameters;
+ ASN1_NULL *implicitlyCA;
+ } value;
+ }/* ECPKPARAMETERS */;
+
+/* SEC1 ECPrivateKey */
+typedef struct ec_privatekey_st {
+ long version;
+ ASN1_OCTET_STRING *privateKey;
+ ECPKPARAMETERS *parameters;
+ ASN1_BIT_STRING *publicKey;
+ } EC_PRIVATEKEY;
+
+/* the OpenSSL ASN.1 definitions */
+ASN1_SEQUENCE(X9_62_PENTANOMIAL) = {
+ ASN1_SIMPLE(X9_62_PENTANOMIAL, k1, LONG),
+ ASN1_SIMPLE(X9_62_PENTANOMIAL, k2, LONG),
+ ASN1_SIMPLE(X9_62_PENTANOMIAL, k3, LONG)
+} ASN1_SEQUENCE_END(X9_62_PENTANOMIAL)
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL)
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL)
+
+ASN1_ADB_TEMPLATE(char_two_def) = ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.other, ASN1_ANY);
+
+ASN1_ADB(X9_62_CHARACTERISTIC_TWO) = {
+ ADB_ENTRY(NID_X9_62_onBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.onBasis, ASN1_NULL)),
+ ADB_ENTRY(NID_X9_62_tpBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.tpBasis, ASN1_INTEGER)),
+ ADB_ENTRY(NID_X9_62_ppBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.ppBasis, X9_62_PENTANOMIAL))
+} ASN1_ADB_END(X9_62_CHARACTERISTIC_TWO, 0, type, 0, &char_two_def_tt, NULL);
+
+ASN1_SEQUENCE(X9_62_CHARACTERISTIC_TWO) = {
+ ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, m, LONG),
+ ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, type, ASN1_OBJECT),
+ ASN1_ADB_OBJECT(X9_62_CHARACTERISTIC_TWO)
+} ASN1_SEQUENCE_END(X9_62_CHARACTERISTIC_TWO)
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO)
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO)
+
+ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY);
+
+ASN1_ADB(X9_62_FIELDID) = {
+ ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)),
+ ADB_ENTRY(NID_X9_62_characteristic_two_field, ASN1_SIMPLE(X9_62_FIELDID, p.char_two, X9_62_CHARACTERISTIC_TWO))
+} ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL);
+
+ASN1_SEQUENCE(X9_62_FIELDID) = {
+ ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT),
+ ASN1_ADB_OBJECT(X9_62_FIELDID)
+} ASN1_SEQUENCE_END(X9_62_FIELDID)
+
+ASN1_SEQUENCE(X9_62_CURVE) = {
+ ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING),
+ ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(X9_62_CURVE)
+
+ASN1_SEQUENCE(ECPARAMETERS) = {
+ ASN1_SIMPLE(ECPARAMETERS, version, LONG),
+ ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID),
+ ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE),
+ ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER),
+ ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(ECPARAMETERS)
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS)
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS)
+
+ASN1_CHOICE(ECPKPARAMETERS) = {
+ ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT),
+ ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS),
+ ASN1_SIMPLE(ECPKPARAMETERS, value.implicitlyCA, ASN1_NULL)
+} ASN1_CHOICE_END(ECPKPARAMETERS)
+
+DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS)
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS)
+IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS)
+
+ASN1_SEQUENCE(EC_PRIVATEKEY) = {
+ ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG),
+ ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING),
+ ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0),
+ ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1)
+} ASN1_SEQUENCE_END(EC_PRIVATEKEY)
+
+DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY)
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY)
+IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY)
+
+/* some declarations of internal function */
+
+/* ec_asn1_group2field() sets the values in a X9_62_FIELDID object */
+static int ec_asn1_group2fieldid(const EC_GROUP *, X9_62_FIELDID *);
+/* ec_asn1_group2curve() sets the values in a X9_62_CURVE object */
+static int ec_asn1_group2curve(const EC_GROUP *, X9_62_CURVE *);
+/* ec_asn1_parameters2group() creates a EC_GROUP object from a
+ * ECPARAMETERS object */
+static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *);
+/* ec_asn1_group2parameters() creates a ECPARAMETERS object from a
+ * EC_GROUP object */
+static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *,ECPARAMETERS *);
+/* ec_asn1_pkparameters2group() creates a EC_GROUP object from a
+ * ECPKPARAMETERS object */
+static EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *);
+/* ec_asn1_group2pkparameters() creates a ECPKPARAMETERS object from a
+ * EC_GROUP object */
+static ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *,
+ ECPKPARAMETERS *);
+
+
+/* the function definitions */
+
+static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
+ {
+ int ok=0, nid;
+ BIGNUM *tmp = NULL;
+
+ if (group == NULL || field == NULL)
+ return 0;
+
+ /* clear the old values (if necessary) */
+ if (field->fieldType != NULL)
+ ASN1_OBJECT_free(field->fieldType);
+ if (field->p.other != NULL)
+ ASN1_TYPE_free(field->p.other);
+
+ nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
+ /* set OID for the field */
+ if ((field->fieldType = OBJ_nid2obj(nid)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB);
+ goto err;
+ }
+
+ if (nid == NID_X9_62_prime_field)
+ {
+ if ((tmp = BN_new()) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ /* the parameters are specified by the prime number p */
+ if (!EC_GROUP_get_curve_GFp(group, tmp, NULL, NULL, NULL))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB);
+ goto err;
+ }
+ /* set the prime number */
+ field->p.prime = BN_to_ASN1_INTEGER(tmp,NULL);
+ if (field->p.prime == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ }
+ else /* nid == NID_X9_62_characteristic_two_field */
+#ifdef OPENSSL_NO_EC2M
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_GF2M_NOT_SUPPORTED);
+ goto err;
+ }
+#else
+ {
+ int field_type;
+ X9_62_CHARACTERISTIC_TWO *char_two;
+
+ field->p.char_two = X9_62_CHARACTERISTIC_TWO_new();
+ char_two = field->p.char_two;
+
+ if (char_two == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ char_two->m = (long)EC_GROUP_get_degree(group);
+
+ field_type = EC_GROUP_get_basis_type(group);
+
+ if (field_type == 0)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB);
+ goto err;
+ }
+ /* set base type OID */
+ if ((char_two->type = OBJ_nid2obj(field_type)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB);
+ goto err;
+ }
+
+ if (field_type == NID_X9_62_tpBasis)
+ {
+ unsigned int k;
+
+ if (!EC_GROUP_get_trinomial_basis(group, &k))
+ goto err;
+
+ char_two->p.tpBasis = ASN1_INTEGER_new();
+ if (!char_two->p.tpBasis)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!ASN1_INTEGER_set(char_two->p.tpBasis, (long)k))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID,
+ ERR_R_ASN1_LIB);
+ goto err;
+ }
+ }
+ else if (field_type == NID_X9_62_ppBasis)
+ {
+ unsigned int k1, k2, k3;
+
+ if (!EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3))
+ goto err;
+
+ char_two->p.ppBasis = X9_62_PENTANOMIAL_new();
+ if (!char_two->p.ppBasis)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* set k? values */
+ char_two->p.ppBasis->k1 = (long)k1;
+ char_two->p.ppBasis->k2 = (long)k2;
+ char_two->p.ppBasis->k3 = (long)k3;
+ }
+ else /* field_type == NID_X9_62_onBasis */
+ {
+ /* for ONB the parameters are (asn1) NULL */
+ char_two->p.onBasis = ASN1_NULL_new();
+ if (!char_two->p.onBasis)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ }
+#endif
+
+ ok = 1;
+
+err : if (tmp)
+ BN_free(tmp);
+ return(ok);
+}
+
+static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve)
+ {
+ int ok=0, nid;
+ BIGNUM *tmp_1=NULL, *tmp_2=NULL;
+ unsigned char *buffer_1=NULL, *buffer_2=NULL,
+ *a_buf=NULL, *b_buf=NULL;
+ size_t len_1, len_2;
+ unsigned char char_zero = 0;
+
+ if (!group || !curve || !curve->a || !curve->b)
+ return 0;
+
+ if ((tmp_1 = BN_new()) == NULL || (tmp_2 = BN_new()) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
+
+ /* get a and b */
+ if (nid == NID_X9_62_prime_field)
+ {
+ if (!EC_GROUP_get_curve_GFp(group, NULL, tmp_1, tmp_2, NULL))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB);
+ goto err;
+ }
+ }
+#ifndef OPENSSL_NO_EC2M
+ else /* nid == NID_X9_62_characteristic_two_field */
+ {
+ if (!EC_GROUP_get_curve_GF2m(group, NULL, tmp_1, tmp_2, NULL))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB);
+ goto err;
+ }
+ }
+#endif
+ len_1 = (size_t)BN_num_bytes(tmp_1);
+ len_2 = (size_t)BN_num_bytes(tmp_2);
+
+ if (len_1 == 0)
+ {
+ /* len_1 == 0 => a == 0 */
+ a_buf = &char_zero;
+ len_1 = 1;
+ }
+ else
+ {
+ if ((buffer_1 = OPENSSL_malloc(len_1)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if ( (len_1 = BN_bn2bin(tmp_1, buffer_1)) == 0)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB);
+ goto err;
+ }
+ a_buf = buffer_1;
+ }
+
+ if (len_2 == 0)
+ {
+ /* len_2 == 0 => b == 0 */
+ b_buf = &char_zero;
+ len_2 = 1;
+ }
+ else
+ {
+ if ((buffer_2 = OPENSSL_malloc(len_2)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if ( (len_2 = BN_bn2bin(tmp_2, buffer_2)) == 0)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB);
+ goto err;
+ }
+ b_buf = buffer_2;
+ }
+
+ /* set a and b */
+ if (!M_ASN1_OCTET_STRING_set(curve->a, a_buf, len_1) ||
+ !M_ASN1_OCTET_STRING_set(curve->b, b_buf, len_2))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB);
+ goto err;
+ }
+
+ /* set the seed (optional) */
+ if (group->seed)
+ {
+ if (!curve->seed)
+ if ((curve->seed = ASN1_BIT_STRING_new()) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ curve->seed->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+ curve->seed->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+ if (!ASN1_BIT_STRING_set(curve->seed, group->seed,
+ (int)group->seed_len))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ }
+ else
+ {
+ if (curve->seed)
+ {
+ ASN1_BIT_STRING_free(curve->seed);
+ curve->seed = NULL;
+ }
+ }
+
+ ok = 1;
+
+err: if (buffer_1)
+ OPENSSL_free(buffer_1);
+ if (buffer_2)
+ OPENSSL_free(buffer_2);
+ if (tmp_1)
+ BN_free(tmp_1);
+ if (tmp_2)
+ BN_free(tmp_2);
+ return(ok);
+ }
+
+static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *group,
+ ECPARAMETERS *param)
+ {
+ int ok=0;
+ size_t len=0;
+ ECPARAMETERS *ret=NULL;
+ BIGNUM *tmp=NULL;
+ unsigned char *buffer=NULL;
+ const EC_POINT *point=NULL;
+ point_conversion_form_t form;
+
+ if ((tmp = BN_new()) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (param == NULL)
+ {
+ if ((ret = ECPARAMETERS_new()) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ else
+ ret = param;
+
+ /* set the version (always one) */
+ ret->version = (long)0x1;
+
+ /* set the fieldID */
+ if (!ec_asn1_group2fieldid(group, ret->fieldID))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ /* set the curve */
+ if (!ec_asn1_group2curve(group, ret->curve))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ /* set the base point */
+ if ((point = EC_GROUP_get0_generator(group)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, EC_R_UNDEFINED_GENERATOR);
+ goto err;
+ }
+
+ form = EC_GROUP_get_point_conversion_form(group);
+
+ len = EC_POINT_point2oct(group, point, form, NULL, len, NULL);
+ if (len == 0)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+ goto err;
+ }
+ if ((buffer = OPENSSL_malloc(len)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!EC_POINT_point2oct(group, point, form, buffer, len, NULL))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+ goto err;
+ }
+ if (ret->base == NULL && (ret->base = ASN1_OCTET_STRING_new()) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!ASN1_OCTET_STRING_set(ret->base, buffer, len))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
+ goto err;
+ }
+
+ /* set the order */
+ if (!EC_GROUP_get_order(group, tmp, NULL))
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+ goto err;
+ }
+ ret->order = BN_to_ASN1_INTEGER(tmp, ret->order);
+ if (ret->order == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
+ goto err;
+ }
+
+ /* set the cofactor (optional) */
+ if (EC_GROUP_get_cofactor(group, tmp, NULL))
+ {
+ ret->cofactor = BN_to_ASN1_INTEGER(tmp, ret->cofactor);
+ if (ret->cofactor == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ }
+
+ ok = 1;
+
+err : if(!ok)
+ {
+ if (ret && !param)
+ ECPARAMETERS_free(ret);
+ ret = NULL;
+ }
+ if (tmp)
+ BN_free(tmp);
+ if (buffer)
+ OPENSSL_free(buffer);
+ return(ret);
+ }
+
+ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *group,
+ ECPKPARAMETERS *params)
+ {
+ int ok = 1, tmp;
+ ECPKPARAMETERS *ret = params;
+
+ if (ret == NULL)
+ {
+ if ((ret = ECPKPARAMETERS_new()) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2PKPARAMETERS,
+ ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ }
+ else
+ {
+ if (ret->type == 0 && ret->value.named_curve)
+ ASN1_OBJECT_free(ret->value.named_curve);
+ else if (ret->type == 1 && ret->value.parameters)
+ ECPARAMETERS_free(ret->value.parameters);
+ }
+
+ if (EC_GROUP_get_asn1_flag(group))
+ {
+ /* use the asn1 OID to describe the
+ * the elliptic curve parameters
+ */
+ tmp = EC_GROUP_get_curve_name(group);
+ if (tmp)
+ {
+ ret->type = 0;
+ if ((ret->value.named_curve = OBJ_nid2obj(tmp)) == NULL)
+ ok = 0;
+ }
+ else
+ /* we don't kmow the nid => ERROR */
+ ok = 0;
+ }
+ else
+ {
+ /* use the ECPARAMETERS structure */
+ ret->type = 1;
+ if ((ret->value.parameters = ec_asn1_group2parameters(
+ group, NULL)) == NULL)
+ ok = 0;
+ }
+
+ if (!ok)
+ {
+ ECPKPARAMETERS_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *params)
+ {
+ int ok = 0, tmp;
+ EC_GROUP *ret = NULL;
+ BIGNUM *p = NULL, *a = NULL, *b = NULL;
+ EC_POINT *point=NULL;
+ long field_bits;
+
+ if (!params->fieldID || !params->fieldID->fieldType ||
+ !params->fieldID->p.ptr)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+ goto err;
+ }
+
+ /* now extract the curve parameters a and b */
+ if (!params->curve || !params->curve->a ||
+ !params->curve->a->data || !params->curve->b ||
+ !params->curve->b->data)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+ goto err;
+ }
+ a = BN_bin2bn(params->curve->a->data, params->curve->a->length, NULL);
+ if (a == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_BN_LIB);
+ goto err;
+ }
+ b = BN_bin2bn(params->curve->b->data, params->curve->b->length, NULL);
+ if (b == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_BN_LIB);
+ goto err;
+ }
+
+ /* get the field parameters */
+ tmp = OBJ_obj2nid(params->fieldID->fieldType);
+ if (tmp == NID_X9_62_characteristic_two_field)
+#ifdef OPENSSL_NO_EC2M
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_GF2M_NOT_SUPPORTED);
+ goto err;
+ }
+#else
+ {
+ X9_62_CHARACTERISTIC_TWO *char_two;
+
+ char_two = params->fieldID->p.char_two;
+
+ field_bits = char_two->m;
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_FIELD_TOO_LARGE);
+ goto err;
+ }
+
+ if ((p = BN_new()) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* get the base type */
+ tmp = OBJ_obj2nid(char_two->type);
+
+ if (tmp == NID_X9_62_tpBasis)
+ {
+ long tmp_long;
+
+ if (!char_two->p.tpBasis)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+ goto err;
+ }
+
+ tmp_long = ASN1_INTEGER_get(char_two->p.tpBasis);
+
+ if (!(char_two->m > tmp_long && tmp_long > 0))
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_TRINOMIAL_BASIS);
+ goto err;
+ }
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)char_two->m))
+ goto err;
+ if (!BN_set_bit(p, (int)tmp_long))
+ goto err;
+ if (!BN_set_bit(p, 0))
+ goto err;
+ }
+ else if (tmp == NID_X9_62_ppBasis)
+ {
+ X9_62_PENTANOMIAL *penta;
+
+ penta = char_two->p.ppBasis;
+ if (!penta)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+ goto err;
+ }
+
+ if (!(char_two->m > penta->k3 && penta->k3 > penta->k2 && penta->k2 > penta->k1 && penta->k1 > 0))
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_PENTANOMIAL_BASIS);
+ goto err;
+ }
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)char_two->m)) goto err;
+ if (!BN_set_bit(p, (int)penta->k1)) goto err;
+ if (!BN_set_bit(p, (int)penta->k2)) goto err;
+ if (!BN_set_bit(p, (int)penta->k3)) goto err;
+ if (!BN_set_bit(p, 0)) goto err;
+ }
+ else if (tmp == NID_X9_62_onBasis)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_NOT_IMPLEMENTED);
+ goto err;
+ }
+ else /* error */
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+ goto err;
+ }
+
+ /* create the EC_GROUP structure */
+ ret = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
+ }
+#endif
+ else if (tmp == NID_X9_62_prime_field)
+ {
+ /* we have a curve over a prime field */
+ /* extract the prime number */
+ if (!params->fieldID->p.prime)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+ goto err;
+ }
+ p = ASN1_INTEGER_to_BN(params->fieldID->p.prime, NULL);
+ if (p == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
+ goto err;
+ }
+
+ if (BN_is_negative(p) || BN_is_zero(p))
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_FIELD);
+ goto err;
+ }
+
+ field_bits = BN_num_bits(p);
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_FIELD_TOO_LARGE);
+ goto err;
+ }
+
+ /* create the EC_GROUP structure */
+ ret = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+ }
+ else
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_FIELD);
+ goto err;
+ }
+
+ if (ret == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ /* extract seed (optional) */
+ if (params->curve->seed != NULL)
+ {
+ if (ret->seed != NULL)
+ OPENSSL_free(ret->seed);
+ if (!(ret->seed = OPENSSL_malloc(params->curve->seed->length)))
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memcpy(ret->seed, params->curve->seed->data,
+ params->curve->seed->length);
+ ret->seed_len = params->curve->seed->length;
+ }
+
+ if (!params->order || !params->base || !params->base->data)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+ goto err;
+ }
+
+ if ((point = EC_POINT_new(ret)) == NULL) goto err;
+
+ /* set the point conversion form */
+ EC_GROUP_set_point_conversion_form(ret, (point_conversion_form_t)
+ (params->base->data[0] & ~0x01));
+
+ /* extract the ec point */
+ if (!EC_POINT_oct2point(ret, point, params->base->data,
+ params->base->length, NULL))
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ /* extract the order */
+ if ((a = ASN1_INTEGER_to_BN(params->order, a)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ if (BN_is_negative(a) || BN_is_zero(a))
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_GROUP_ORDER);
+ goto err;
+ }
+ if (BN_num_bits(a) > (int)field_bits + 1) /* Hasse bound */
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_GROUP_ORDER);
+ goto err;
+ }
+
+ /* extract the cofactor (optional) */
+ if (params->cofactor == NULL)
+ {
+ if (b)
+ {
+ BN_free(b);
+ b = NULL;
+ }
+ }
+ else
+ if ((b = ASN1_INTEGER_to_BN(params->cofactor, b)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ /* set the generator, order and cofactor (if present) */
+ if (!EC_GROUP_set_generator(ret, point, a, b))
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ ok = 1;
+
+err: if (!ok)
+ {
+ if (ret)
+ EC_GROUP_clear_free(ret);
+ ret = NULL;
+ }
+
+ if (p)
+ BN_free(p);
+ if (a)
+ BN_free(a);
+ if (b)
+ BN_free(b);
+ if (point)
+ EC_POINT_free(point);
+ return(ret);
+}
+
+EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params)
+ {
+ EC_GROUP *ret=NULL;
+ int tmp=0;
+
+ if (params == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP,
+ EC_R_MISSING_PARAMETERS);
+ return NULL;
+ }
+
+ if (params->type == 0)
+ { /* the curve is given by an OID */
+ tmp = OBJ_obj2nid(params->value.named_curve);
+ if ((ret = EC_GROUP_new_by_curve_name(tmp)) == NULL)
+ {
+ ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP,
+ EC_R_EC_GROUP_NEW_BY_NAME_FAILURE);
+ return NULL;
+ }
+ EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_NAMED_CURVE);
+ }
+ else if (params->type == 1)
+ { /* the parameters are given by a ECPARAMETERS
+ * structure */
+ ret = ec_asn1_parameters2group(params->value.parameters);
+ if (!ret)
+ {
+ ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, ERR_R_EC_LIB);
+ return NULL;
+ }
+ EC_GROUP_set_asn1_flag(ret, 0x0);
+ }
+ else if (params->type == 2)
+ { /* implicitlyCA */
+ return NULL;
+ }
+ else
+ {
+ ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, EC_R_ASN1_ERROR);
+ return NULL;
+ }
+
+ return ret;
+ }
+
+/* EC_GROUP <-> DER encoding of ECPKPARAMETERS */
+
+EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len)
+ {
+ EC_GROUP *group = NULL;
+ ECPKPARAMETERS *params = NULL;
+
+ if ((params = d2i_ECPKPARAMETERS(NULL, in, len)) == NULL)
+ {
+ ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_D2I_ECPKPARAMETERS_FAILURE);
+ ECPKPARAMETERS_free(params);
+ return NULL;
+ }
+
+ if ((group = ec_asn1_pkparameters2group(params)) == NULL)
+ {
+ ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_PKPARAMETERS2GROUP_FAILURE);
+ ECPKPARAMETERS_free(params);
+ return NULL;
+ }
+
+
+ if (a && *a)
+ EC_GROUP_clear_free(*a);
+ if (a)
+ *a = group;
+
+ ECPKPARAMETERS_free(params);
+ return(group);
+ }
+
+int i2d_ECPKParameters(const EC_GROUP *a, unsigned char **out)
+ {
+ int ret=0;
+ ECPKPARAMETERS *tmp = ec_asn1_group2pkparameters(a, NULL);
+ if (tmp == NULL)
+ {
+ ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_GROUP2PKPARAMETERS_FAILURE);
+ return 0;
+ }
+ if ((ret = i2d_ECPKPARAMETERS(tmp, out)) == 0)
+ {
+ ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_I2D_ECPKPARAMETERS_FAILURE);
+ ECPKPARAMETERS_free(tmp);
+ return 0;
+ }
+ ECPKPARAMETERS_free(tmp);
+ return(ret);
+ }
+
+/* some EC_KEY functions */
+
+EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
+ {
+ int ok=0;
+ EC_KEY *ret=NULL;
+ EC_PRIVATEKEY *priv_key=NULL;
+
+ if ((priv_key = EC_PRIVATEKEY_new()) == NULL)
+ {
+ ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ if ((priv_key = d2i_EC_PRIVATEKEY(&priv_key, in, len)) == NULL)
+ {
+ ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+ EC_PRIVATEKEY_free(priv_key);
+ return NULL;
+ }
+
+ if (a == NULL || *a == NULL)
+ {
+ if ((ret = EC_KEY_new()) == NULL)
+ {
+ ECerr(EC_F_D2I_ECPRIVATEKEY,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (a)
+ *a = ret;
+ }
+ else
+ ret = *a;
+
+ if (priv_key->parameters)
+ {
+ if (ret->group)
+ EC_GROUP_clear_free(ret->group);
+ ret->group = ec_asn1_pkparameters2group(priv_key->parameters);
+ }
+
+ if (ret->group == NULL)
+ {
+ ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ ret->version = priv_key->version;
+
+ if (priv_key->privateKey)
+ {
+ ret->priv_key = BN_bin2bn(
+ M_ASN1_STRING_data(priv_key->privateKey),
+ M_ASN1_STRING_length(priv_key->privateKey),
+ ret->priv_key);
+ if (ret->priv_key == NULL)
+ {
+ ECerr(EC_F_D2I_ECPRIVATEKEY,
+ ERR_R_BN_LIB);
+ goto err;
+ }
+ }
+ else
+ {
+ ECerr(EC_F_D2I_ECPRIVATEKEY,
+ EC_R_MISSING_PRIVATE_KEY);
+ goto err;
+ }
+
+ if (priv_key->publicKey)
+ {
+ const unsigned char *pub_oct;
+ size_t pub_oct_len;
+
+ if (ret->pub_key)
+ EC_POINT_clear_free(ret->pub_key);
+ ret->pub_key = EC_POINT_new(ret->group);
+ if (ret->pub_key == NULL)
+ {
+ ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+ goto err;
+ }
+ pub_oct = M_ASN1_STRING_data(priv_key->publicKey);
+ pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey);
+ /* save the point conversion form */
+ ret->conv_form = (point_conversion_form_t)(pub_oct[0] & ~0x01);
+ if (!EC_POINT_oct2point(ret->group, ret->pub_key,
+ pub_oct, pub_oct_len, NULL))
+ {
+ ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+ goto err;
+ }
+ }
+
+ ok = 1;
+err:
+ if (!ok)
+ {
+ if (ret)
+ EC_KEY_free(ret);
+ ret = NULL;
+ }
+
+ if (priv_key)
+ EC_PRIVATEKEY_free(priv_key);
+
+ return(ret);
+ }
+
+int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out)
+ {
+ int ret=0, ok=0;
+ unsigned char *buffer=NULL;
+ size_t buf_len=0, tmp_len;
+ EC_PRIVATEKEY *priv_key=NULL;
+
+ if (a == NULL || a->group == NULL || a->priv_key == NULL)
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY,
+ ERR_R_PASSED_NULL_PARAMETER);
+ goto err;
+ }
+
+ if ((priv_key = EC_PRIVATEKEY_new()) == NULL)
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ priv_key->version = a->version;
+
+ buf_len = (size_t)BN_num_bytes(a->priv_key);
+ buffer = OPENSSL_malloc(buf_len);
+ if (buffer == NULL)
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BN_bn2bin(a->priv_key, buffer))
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len))
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB);
+ goto err;
+ }
+
+ if (!(a->enc_flag & EC_PKEY_NO_PARAMETERS))
+ {
+ if ((priv_key->parameters = ec_asn1_group2pkparameters(
+ a->group, priv_key->parameters)) == NULL)
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
+ goto err;
+ }
+ }
+
+ if (!(a->enc_flag & EC_PKEY_NO_PUBKEY))
+ {
+ priv_key->publicKey = M_ASN1_BIT_STRING_new();
+ if (priv_key->publicKey == NULL)
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ tmp_len = EC_POINT_point2oct(a->group, a->pub_key,
+ a->conv_form, NULL, 0, NULL);
+
+ if (tmp_len > buf_len)
+ {
+ unsigned char *tmp_buffer = OPENSSL_realloc(buffer, tmp_len);
+ if (!tmp_buffer)
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ buffer = tmp_buffer;
+ buf_len = tmp_len;
+ }
+
+ if (!EC_POINT_point2oct(a->group, a->pub_key,
+ a->conv_form, buffer, buf_len, NULL))
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+ priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+ if (!M_ASN1_BIT_STRING_set(priv_key->publicKey, buffer,
+ buf_len))
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ }
+
+ if ((ret = i2d_EC_PRIVATEKEY(priv_key, out)) == 0)
+ {
+ ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
+ goto err;
+ }
+ ok=1;
+err:
+ if (buffer)
+ OPENSSL_free(buffer);
+ if (priv_key)
+ EC_PRIVATEKEY_free(priv_key);
+ return(ok?ret:0);
+ }
+
+int i2d_ECParameters(EC_KEY *a, unsigned char **out)
+ {
+ if (a == NULL)
+ {
+ ECerr(EC_F_I2D_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ return i2d_ECPKParameters(a->group, out);
+ }
+
+EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len)
+ {
+ EC_KEY *ret;
+
+ if (in == NULL || *in == NULL)
+ {
+ ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+
+ if (a == NULL || *a == NULL)
+ {
+ if ((ret = EC_KEY_new()) == NULL)
+ {
+ ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ if (a)
+ *a = ret;
+ }
+ else
+ ret = *a;
+
+ if (!d2i_ECPKParameters(&ret->group, in, len))
+ {
+ ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_EC_LIB);
+ return NULL;
+ }
+
+ return ret;
+ }
+
+EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len)
+ {
+ EC_KEY *ret=NULL;
+
+ if (a == NULL || (*a) == NULL || (*a)->group == NULL)
+ {
+ /* sorry, but a EC_GROUP-structur is necessary
+ * to set the public key */
+ ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ ret = *a;
+ if (ret->pub_key == NULL &&
+ (ret->pub_key = EC_POINT_new(ret->group)) == NULL)
+ {
+ ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if (!EC_POINT_oct2point(ret->group, ret->pub_key, *in, len, NULL))
+ {
+ ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_EC_LIB);
+ return 0;
+ }
+ /* save the point conversion form */
+ ret->conv_form = (point_conversion_form_t)(*in[0] & ~0x01);
+ *in += len;
+ return ret;
+ }
+
+int i2o_ECPublicKey(EC_KEY *a, unsigned char **out)
+ {
+ size_t buf_len=0;
+ int new_buffer = 0;
+
+ if (a == NULL)
+ {
+ ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ buf_len = EC_POINT_point2oct(a->group, a->pub_key,
+ a->conv_form, NULL, 0, NULL);
+
+ if (out == NULL || buf_len == 0)
+ /* out == NULL => just return the length of the octet string */
+ return buf_len;
+
+ if (*out == NULL)
+ {
+ if ((*out = OPENSSL_malloc(buf_len)) == NULL)
+ {
+ ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ new_buffer = 1;
+ }
+ if (!EC_POINT_point2oct(a->group, a->pub_key, a->conv_form,
+ *out, buf_len, NULL))
+ {
+ ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_EC_LIB);
+ if (new_buffer)
+ {
+ OPENSSL_free(*out);
+ *out = NULL;
+ }
+ return 0;
+ }
+ if (!new_buffer)
+ *out += buf_len;
+ return buf_len;
+ }
diff --git a/drivers/builtin_openssl/crypto/ec/ec_check.c b/drivers/builtin_openssl2/crypto/ec/ec_check.c
index 0e316b4b3f..0e316b4b3f 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_check.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_check.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec_curve.c b/drivers/builtin_openssl2/crypto/ec/ec_curve.c
index c72fb2697c..c72fb2697c 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_curve.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_curve.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec_cvt.c b/drivers/builtin_openssl2/crypto/ec/ec_cvt.c
index bfcbab35fe..bfcbab35fe 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_cvt.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_cvt.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec_err.c b/drivers/builtin_openssl2/crypto/ec/ec_err.c
index 0d19398731..0d19398731 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_err.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_err.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec_key.c b/drivers/builtin_openssl2/crypto/ec/ec_key.c
index 7fa247593d..7fa247593d 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_key.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_key.c
diff --git a/drivers/builtin_openssl2/crypto/ec/ec_lcl.h b/drivers/builtin_openssl2/crypto/ec/ec_lcl.h
new file mode 100644
index 0000000000..b0d48b6b5c
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/ec/ec_lcl.h
@@ -0,0 +1,446 @@
+/* crypto/ec/ec_lcl.h */
+/*
+ * Originally written by Bodo Moeller for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2010 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <openssl/obj_mac.h>
+#include <openssl/ec.h>
+#include <openssl/bn.h>
+
+#if defined(__SUNPRO_C)
+# if __SUNPRO_C >= 0x520
+# pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
+# endif
+#endif
+
+/* Use default functions for poin2oct, oct2point and compressed coordinates */
+#define EC_FLAGS_DEFAULT_OCT 0x1
+
+/* Structure details are not part of the exported interface,
+ * so all this may change in future versions. */
+
+struct ec_method_st {
+ /* Various method flags */
+ int flags;
+ /* used by EC_METHOD_get_field_type: */
+ int field_type; /* a NID */
+
+ /* used by EC_GROUP_new, EC_GROUP_free, EC_GROUP_clear_free, EC_GROUP_copy: */
+ int (*group_init)(EC_GROUP *);
+ void (*group_finish)(EC_GROUP *);
+ void (*group_clear_finish)(EC_GROUP *);
+ int (*group_copy)(EC_GROUP *, const EC_GROUP *);
+
+ /* used by EC_GROUP_set_curve_GFp, EC_GROUP_get_curve_GFp, */
+ /* EC_GROUP_set_curve_GF2m, and EC_GROUP_get_curve_GF2m: */
+ int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+ int (*group_get_curve)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
+
+ /* used by EC_GROUP_get_degree: */
+ int (*group_get_degree)(const EC_GROUP *);
+
+ /* used by EC_GROUP_check: */
+ int (*group_check_discriminant)(const EC_GROUP *, BN_CTX *);
+
+ /* used by EC_POINT_new, EC_POINT_free, EC_POINT_clear_free, EC_POINT_copy: */
+ int (*point_init)(EC_POINT *);
+ void (*point_finish)(EC_POINT *);
+ void (*point_clear_finish)(EC_POINT *);
+ int (*point_copy)(EC_POINT *, const EC_POINT *);
+
+ /* used by EC_POINT_set_to_infinity,
+ * EC_POINT_set_Jprojective_coordinates_GFp,
+ * EC_POINT_get_Jprojective_coordinates_GFp,
+ * EC_POINT_set_affine_coordinates_GFp, ..._GF2m,
+ * EC_POINT_get_affine_coordinates_GFp, ..._GF2m,
+ * EC_POINT_set_compressed_coordinates_GFp, ..._GF2m:
+ */
+ int (*point_set_to_infinity)(const EC_GROUP *, EC_POINT *);
+ int (*point_set_Jprojective_coordinates_GFp)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *);
+ int (*point_get_Jprojective_coordinates_GFp)(const EC_GROUP *, const EC_POINT *,
+ BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *);
+ int (*point_set_affine_coordinates)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, const BIGNUM *y, BN_CTX *);
+ int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *,
+ BIGNUM *x, BIGNUM *y, BN_CTX *);
+ int (*point_set_compressed_coordinates)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, int y_bit, BN_CTX *);
+
+ /* used by EC_POINT_point2oct, EC_POINT_oct2point: */
+ size_t (*point2oct)(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
+ unsigned char *buf, size_t len, BN_CTX *);
+ int (*oct2point)(const EC_GROUP *, EC_POINT *,
+ const unsigned char *buf, size_t len, BN_CTX *);
+
+ /* used by EC_POINT_add, EC_POINT_dbl, ECP_POINT_invert: */
+ int (*add)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+ int (*dbl)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
+ int (*invert)(const EC_GROUP *, EC_POINT *, BN_CTX *);
+
+ /* used by EC_POINT_is_at_infinity, EC_POINT_is_on_curve, EC_POINT_cmp: */
+ int (*is_at_infinity)(const EC_GROUP *, const EC_POINT *);
+ int (*is_on_curve)(const EC_GROUP *, const EC_POINT *, BN_CTX *);
+ int (*point_cmp)(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+
+ /* used by EC_POINT_make_affine, EC_POINTs_make_affine: */
+ int (*make_affine)(const EC_GROUP *, EC_POINT *, BN_CTX *);
+ int (*points_make_affine)(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
+
+ /* used by EC_POINTs_mul, EC_POINT_mul, EC_POINT_precompute_mult, EC_POINT_have_precompute_mult
+ * (default implementations are used if the 'mul' pointer is 0): */
+ int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+ int (*precompute_mult)(EC_GROUP *group, BN_CTX *);
+ int (*have_precompute_mult)(const EC_GROUP *group);
+
+
+ /* internal functions */
+
+ /* 'field_mul', 'field_sqr', and 'field_div' can be used by 'add' and 'dbl' so that
+ * the same implementations of point operations can be used with different
+ * optimized implementations of expensive field operations: */
+ int (*field_mul)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+ int (*field_sqr)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
+ int (*field_div)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+
+ int (*field_encode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); /* e.g. to Montgomery */
+ int (*field_decode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); /* e.g. from Montgomery */
+ int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *);
+} /* EC_METHOD */;
+
+typedef struct ec_extra_data_st {
+ struct ec_extra_data_st *next;
+ void *data;
+ void *(*dup_func)(void *);
+ void (*free_func)(void *);
+ void (*clear_free_func)(void *);
+} EC_EXTRA_DATA; /* used in EC_GROUP */
+
+struct ec_group_st {
+ const EC_METHOD *meth;
+
+ EC_POINT *generator; /* optional */
+ BIGNUM order, cofactor;
+
+ int curve_name;/* optional NID for named curve */
+ int asn1_flag; /* flag to control the asn1 encoding */
+ point_conversion_form_t asn1_form;
+
+ unsigned char *seed; /* optional seed for parameters (appears in ASN1) */
+ size_t seed_len;
+
+ EC_EXTRA_DATA *extra_data; /* linked list */
+
+ /* The following members are handled by the method functions,
+ * even if they appear generic */
+
+ BIGNUM field; /* Field specification.
+ * For curves over GF(p), this is the modulus;
+ * for curves over GF(2^m), this is the
+ * irreducible polynomial defining the field.
+ */
+
+ int poly[6]; /* Field specification for curves over GF(2^m).
+ * The irreducible f(t) is then of the form:
+ * t^poly[0] + t^poly[1] + ... + t^poly[k]
+ * where m = poly[0] > poly[1] > ... > poly[k] = 0.
+ * The array is terminated with poly[k+1]=-1.
+ * All elliptic curve irreducibles have at most 5
+ * non-zero terms.
+ */
+
+ BIGNUM a, b; /* Curve coefficients.
+ * (Here the assumption is that BIGNUMs can be used
+ * or abused for all kinds of fields, not just GF(p).)
+ * For characteristic > 3, the curve is defined
+ * by a Weierstrass equation of the form
+ * y^2 = x^3 + a*x + b.
+ * For characteristic 2, the curve is defined by
+ * an equation of the form
+ * y^2 + x*y = x^3 + a*x^2 + b.
+ */
+
+ int a_is_minus3; /* enable optimized point arithmetics for special case */
+
+ void *field_data1; /* method-specific (e.g., Montgomery structure) */
+ void *field_data2; /* method-specific */
+ int (*field_mod_func)(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); /* method-specific */
+} /* EC_GROUP */;
+
+struct ec_key_st {
+ int version;
+
+ EC_GROUP *group;
+
+ EC_POINT *pub_key;
+ BIGNUM *priv_key;
+
+ unsigned int enc_flag;
+ point_conversion_form_t conv_form;
+
+ int references;
+ int flags;
+
+ EC_EXTRA_DATA *method_data;
+} /* EC_KEY */;
+
+/* Basically a 'mixin' for extra data, but available for EC_GROUPs/EC_KEYs only
+ * (with visibility limited to 'package' level for now).
+ * We use the function pointers as index for retrieval; this obviates
+ * global ex_data-style index tables.
+ */
+int EC_EX_DATA_set_data(EC_EXTRA_DATA **, void *data,
+ void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
+void *EC_EX_DATA_get_data(const EC_EXTRA_DATA *,
+ void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
+void EC_EX_DATA_free_data(EC_EXTRA_DATA **,
+ void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
+void EC_EX_DATA_clear_free_data(EC_EXTRA_DATA **,
+ void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
+void EC_EX_DATA_free_all_data(EC_EXTRA_DATA **);
+void EC_EX_DATA_clear_free_all_data(EC_EXTRA_DATA **);
+
+
+
+struct ec_point_st {
+ const EC_METHOD *meth;
+
+ /* All members except 'meth' are handled by the method functions,
+ * even if they appear generic */
+
+ BIGNUM X;
+ BIGNUM Y;
+ BIGNUM Z; /* Jacobian projective coordinates:
+ * (X, Y, Z) represents (X/Z^2, Y/Z^3) if Z != 0 */
+ int Z_is_one; /* enable optimized point arithmetics for special case */
+} /* EC_POINT */;
+
+
+
+/* method functions in ec_mult.c
+ * (ec_lib.c uses these as defaults if group->method->mul is 0) */
+int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *);
+int ec_wNAF_have_precompute_mult(const EC_GROUP *group);
+
+
+/* method functions in ecp_smpl.c */
+int ec_GFp_simple_group_init(EC_GROUP *);
+void ec_GFp_simple_group_finish(EC_GROUP *);
+void ec_GFp_simple_group_clear_finish(EC_GROUP *);
+int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *);
+int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
+int ec_GFp_simple_group_get_degree(const EC_GROUP *);
+int ec_GFp_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *);
+int ec_GFp_simple_point_init(EC_POINT *);
+void ec_GFp_simple_point_finish(EC_POINT *);
+void ec_GFp_simple_point_clear_finish(EC_POINT *);
+int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *);
+int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
+int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *);
+int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *, const EC_POINT *,
+ BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *);
+int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, const BIGNUM *y, BN_CTX *);
+int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *, const EC_POINT *,
+ BIGNUM *x, BIGNUM *y, BN_CTX *);
+int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, int y_bit, BN_CTX *);
+size_t ec_GFp_simple_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
+ unsigned char *buf, size_t len, BN_CTX *);
+int ec_GFp_simple_oct2point(const EC_GROUP *, EC_POINT *,
+ const unsigned char *buf, size_t len, BN_CTX *);
+int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
+int ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *);
+int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
+int ec_GFp_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+int ec_GFp_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int ec_GFp_simple_points_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
+int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
+
+
+/* method functions in ecp_mont.c */
+int ec_GFp_mont_group_init(EC_GROUP *);
+int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+void ec_GFp_mont_group_finish(EC_GROUP *);
+void ec_GFp_mont_group_clear_finish(EC_GROUP *);
+int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *);
+int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
+int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
+int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
+int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *);
+
+
+/* method functions in ecp_nist.c */
+int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src);
+int ec_GFp_nist_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int ec_GFp_nist_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int ec_GFp_nist_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
+
+
+/* method functions in ec2_smpl.c */
+int ec_GF2m_simple_group_init(EC_GROUP *);
+void ec_GF2m_simple_group_finish(EC_GROUP *);
+void ec_GF2m_simple_group_clear_finish(EC_GROUP *);
+int ec_GF2m_simple_group_copy(EC_GROUP *, const EC_GROUP *);
+int ec_GF2m_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int ec_GF2m_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
+int ec_GF2m_simple_group_get_degree(const EC_GROUP *);
+int ec_GF2m_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *);
+int ec_GF2m_simple_point_init(EC_POINT *);
+void ec_GF2m_simple_point_finish(EC_POINT *);
+void ec_GF2m_simple_point_clear_finish(EC_POINT *);
+int ec_GF2m_simple_point_copy(EC_POINT *, const EC_POINT *);
+int ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
+int ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, const BIGNUM *y, BN_CTX *);
+int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *, const EC_POINT *,
+ BIGNUM *x, BIGNUM *y, BN_CTX *);
+int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, int y_bit, BN_CTX *);
+size_t ec_GF2m_simple_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
+ unsigned char *buf, size_t len, BN_CTX *);
+int ec_GF2m_simple_oct2point(const EC_GROUP *, EC_POINT *,
+ const unsigned char *buf, size_t len, BN_CTX *);
+int ec_GF2m_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+int ec_GF2m_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
+int ec_GF2m_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int ec_GF2m_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *);
+int ec_GF2m_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
+int ec_GF2m_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+int ec_GF2m_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int ec_GF2m_simple_points_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
+int ec_GF2m_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int ec_GF2m_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
+int ec_GF2m_simple_field_div(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+
+
+/* method functions in ec2_mult.c */
+int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GF2m_have_precompute_mult(const EC_GROUP *group);
+
+/* method functions in ec2_mult.c */
+int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GF2m_have_precompute_mult(const EC_GROUP *group);
+
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+/* method functions in ecp_nistp224.c */
+int ec_GFp_nistp224_group_init(EC_GROUP *group);
+int ec_GFp_nistp224_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
+int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
+int ec_GFp_nistp224_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
+int ec_GFp_nistp224_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GFp_nistp224_have_precompute_mult(const EC_GROUP *group);
+
+/* method functions in ecp_nistp256.c */
+int ec_GFp_nistp256_group_init(EC_GROUP *group);
+int ec_GFp_nistp256_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
+int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
+int ec_GFp_nistp256_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
+int ec_GFp_nistp256_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GFp_nistp256_have_precompute_mult(const EC_GROUP *group);
+
+/* method functions in ecp_nistp521.c */
+int ec_GFp_nistp521_group_init(EC_GROUP *group);
+int ec_GFp_nistp521_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
+int ec_GFp_nistp521_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
+int ec_GFp_nistp521_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GFp_nistp521_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
+int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GFp_nistp521_have_precompute_mult(const EC_GROUP *group);
+
+/* utility functions in ecp_nistputil.c */
+void ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
+ size_t felem_size, void *tmp_felems,
+ void (*felem_one)(void *out),
+ int (*felem_is_zero)(const void *in),
+ void (*felem_assign)(void *out, const void *in),
+ void (*felem_square)(void *out, const void *in),
+ void (*felem_mul)(void *out, const void *in1, const void *in2),
+ void (*felem_inv)(void *out, const void *in),
+ void (*felem_contract)(void *out, const void *in));
+void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign, unsigned char *digit, unsigned char in);
+#endif
diff --git a/drivers/builtin_openssl/crypto/ec/ec_lib.c b/drivers/builtin_openssl2/crypto/ec/ec_lib.c
index de9a0cc2b3..de9a0cc2b3 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_lib.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_lib.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec_mult.c b/drivers/builtin_openssl2/crypto/ec/ec_mult.c
index 19f21675fb..19f21675fb 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_mult.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_mult.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec_oct.c b/drivers/builtin_openssl2/crypto/ec/ec_oct.c
index fd9db0798d..fd9db0798d 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_oct.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_oct.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec_pmeth.c b/drivers/builtin_openssl2/crypto/ec/ec_pmeth.c
index 66ee397d86..66ee397d86 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_pmeth.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_pmeth.c
diff --git a/drivers/builtin_openssl/crypto/ec/ec_print.c b/drivers/builtin_openssl2/crypto/ec/ec_print.c
index f7c8a303ac..f7c8a303ac 100644
--- a/drivers/builtin_openssl/crypto/ec/ec_print.c
+++ b/drivers/builtin_openssl2/crypto/ec/ec_print.c
diff --git a/drivers/builtin_openssl/crypto/ec/eck_prn.c b/drivers/builtin_openssl2/crypto/ec/eck_prn.c
index 06de8f3959..06de8f3959 100644
--- a/drivers/builtin_openssl/crypto/ec/eck_prn.c
+++ b/drivers/builtin_openssl2/crypto/ec/eck_prn.c
diff --git a/drivers/builtin_openssl/crypto/ec/ecp_mont.c b/drivers/builtin_openssl2/crypto/ec/ecp_mont.c
index f04f132c7a..f04f132c7a 100644
--- a/drivers/builtin_openssl/crypto/ec/ecp_mont.c
+++ b/drivers/builtin_openssl2/crypto/ec/ecp_mont.c
diff --git a/drivers/builtin_openssl/crypto/ec/ecp_nist.c b/drivers/builtin_openssl2/crypto/ec/ecp_nist.c
index aad2d5f443..aad2d5f443 100644
--- a/drivers/builtin_openssl/crypto/ec/ecp_nist.c
+++ b/drivers/builtin_openssl2/crypto/ec/ecp_nist.c
diff --git a/drivers/builtin_openssl/crypto/ec/ecp_nistp224.c b/drivers/builtin_openssl2/crypto/ec/ecp_nistp224.c
index b5ff56c252..b5ff56c252 100644
--- a/drivers/builtin_openssl/crypto/ec/ecp_nistp224.c
+++ b/drivers/builtin_openssl2/crypto/ec/ecp_nistp224.c
diff --git a/drivers/builtin_openssl/crypto/ec/ecp_nistp256.c b/drivers/builtin_openssl2/crypto/ec/ecp_nistp256.c
index 4bc0f5dce0..4bc0f5dce0 100644
--- a/drivers/builtin_openssl/crypto/ec/ecp_nistp256.c
+++ b/drivers/builtin_openssl2/crypto/ec/ecp_nistp256.c
diff --git a/drivers/builtin_openssl/crypto/ec/ecp_nistp521.c b/drivers/builtin_openssl2/crypto/ec/ecp_nistp521.c
index 178b655f7f..178b655f7f 100644
--- a/drivers/builtin_openssl/crypto/ec/ecp_nistp521.c
+++ b/drivers/builtin_openssl2/crypto/ec/ecp_nistp521.c
diff --git a/drivers/builtin_openssl/crypto/ec/ecp_nistputil.c b/drivers/builtin_openssl2/crypto/ec/ecp_nistputil.c
index c8140c807f..c8140c807f 100644
--- a/drivers/builtin_openssl/crypto/ec/ecp_nistputil.c
+++ b/drivers/builtin_openssl2/crypto/ec/ecp_nistputil.c
diff --git a/drivers/builtin_openssl/crypto/ec/ecp_oct.c b/drivers/builtin_openssl2/crypto/ec/ecp_oct.c
index 374a0ee731..374a0ee731 100644
--- a/drivers/builtin_openssl/crypto/ec/ecp_oct.c
+++ b/drivers/builtin_openssl2/crypto/ec/ecp_oct.c
diff --git a/drivers/builtin_openssl/crypto/ec/ecp_smpl.c b/drivers/builtin_openssl2/crypto/ec/ecp_smpl.c
index 7cbb321f9a..7cbb321f9a 100644
--- a/drivers/builtin_openssl/crypto/ec/ecp_smpl.c
+++ b/drivers/builtin_openssl2/crypto/ec/ecp_smpl.c
diff --git a/drivers/builtin_openssl/crypto/ec/ectest.c b/drivers/builtin_openssl2/crypto/ec/ectest.c
index 102eaa9b23..102eaa9b23 100644
--- a/drivers/builtin_openssl/crypto/ec/ectest.c
+++ b/drivers/builtin_openssl2/crypto/ec/ectest.c
diff --git a/drivers/builtin_openssl/crypto/ecdh/ecdhtest.c b/drivers/builtin_openssl2/crypto/ecdh/ecdhtest.c
index 823d7baa65..823d7baa65 100644
--- a/drivers/builtin_openssl/crypto/ecdh/ecdhtest.c
+++ b/drivers/builtin_openssl2/crypto/ecdh/ecdhtest.c
diff --git a/drivers/builtin_openssl/crypto/ecdh/ech_err.c b/drivers/builtin_openssl2/crypto/ecdh/ech_err.c
index 3bd247398d..3bd247398d 100644
--- a/drivers/builtin_openssl/crypto/ecdh/ech_err.c
+++ b/drivers/builtin_openssl2/crypto/ecdh/ech_err.c
diff --git a/drivers/builtin_openssl/crypto/ecdh/ech_key.c b/drivers/builtin_openssl2/crypto/ecdh/ech_key.c
index 2988899ea2..2988899ea2 100644
--- a/drivers/builtin_openssl/crypto/ecdh/ech_key.c
+++ b/drivers/builtin_openssl2/crypto/ecdh/ech_key.c
diff --git a/drivers/builtin_openssl/crypto/ecdh/ech_lib.c b/drivers/builtin_openssl2/crypto/ecdh/ech_lib.c
index 0644431b75..0644431b75 100644
--- a/drivers/builtin_openssl/crypto/ecdh/ech_lib.c
+++ b/drivers/builtin_openssl2/crypto/ecdh/ech_lib.c
diff --git a/drivers/builtin_openssl/crypto/ecdh/ech_locl.h b/drivers/builtin_openssl2/crypto/ecdh/ech_locl.h
index f6cad6a894..f6cad6a894 100644
--- a/drivers/builtin_openssl/crypto/ecdh/ech_locl.h
+++ b/drivers/builtin_openssl2/crypto/ecdh/ech_locl.h
diff --git a/drivers/builtin_openssl/crypto/ecdh/ech_ossl.c b/drivers/builtin_openssl2/crypto/ecdh/ech_ossl.c
index 4a30628fbc..4a30628fbc 100644
--- a/drivers/builtin_openssl/crypto/ecdh/ech_ossl.c
+++ b/drivers/builtin_openssl2/crypto/ecdh/ech_ossl.c
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecdsatest.c b/drivers/builtin_openssl2/crypto/ecdsa/ecdsatest.c
index 537bb30362..537bb30362 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecdsatest.c
+++ b/drivers/builtin_openssl2/crypto/ecdsa/ecdsatest.c
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecs_asn1.c b/drivers/builtin_openssl2/crypto/ecdsa/ecs_asn1.c
index b295489400..b295489400 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecs_asn1.c
+++ b/drivers/builtin_openssl2/crypto/ecdsa/ecs_asn1.c
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecs_err.c b/drivers/builtin_openssl2/crypto/ecdsa/ecs_err.c
index 81542e6d15..81542e6d15 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecs_err.c
+++ b/drivers/builtin_openssl2/crypto/ecdsa/ecs_err.c
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecs_lib.c b/drivers/builtin_openssl2/crypto/ecdsa/ecs_lib.c
index 814a6bf404..814a6bf404 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecs_lib.c
+++ b/drivers/builtin_openssl2/crypto/ecdsa/ecs_lib.c
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecs_locl.h b/drivers/builtin_openssl2/crypto/ecdsa/ecs_locl.h
index cb3be13cfc..cb3be13cfc 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecs_locl.h
+++ b/drivers/builtin_openssl2/crypto/ecdsa/ecs_locl.h
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecs_ossl.c b/drivers/builtin_openssl2/crypto/ecdsa/ecs_ossl.c
index 7725935610..7725935610 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecs_ossl.c
+++ b/drivers/builtin_openssl2/crypto/ecdsa/ecs_ossl.c
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecs_sign.c b/drivers/builtin_openssl2/crypto/ecdsa/ecs_sign.c
index 353d5af514..353d5af514 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecs_sign.c
+++ b/drivers/builtin_openssl2/crypto/ecdsa/ecs_sign.c
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecs_vrf.c b/drivers/builtin_openssl2/crypto/ecdsa/ecs_vrf.c
index ef9acf7b61..ef9acf7b61 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecs_vrf.c
+++ b/drivers/builtin_openssl2/crypto/ecdsa/ecs_vrf.c
diff --git a/drivers/builtin_openssl/crypto/engine/README b/drivers/builtin_openssl2/crypto/engine/README
index 6b69b70f57..6b69b70f57 100644
--- a/drivers/builtin_openssl/crypto/engine/README
+++ b/drivers/builtin_openssl2/crypto/engine/README
diff --git a/drivers/builtin_openssl/crypto/engine/eng_all.c b/drivers/builtin_openssl2/crypto/engine/eng_all.c
index 6093376df4..6093376df4 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_all.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_all.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_cnf.c b/drivers/builtin_openssl2/crypto/engine/eng_cnf.c
index 95c4070015..95c4070015 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_cnf.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_cnf.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_cryptodev.c b/drivers/builtin_openssl2/crypto/engine/eng_cryptodev.c
index 5a715aca4f..5a715aca4f 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_cryptodev.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_cryptodev.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_ctrl.c b/drivers/builtin_openssl2/crypto/engine/eng_ctrl.c
index 5ce25d92ec..5ce25d92ec 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_ctrl.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_ctrl.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_dyn.c b/drivers/builtin_openssl2/crypto/engine/eng_dyn.c
index 807da7a5eb..807da7a5eb 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_dyn.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_dyn.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_err.c b/drivers/builtin_openssl2/crypto/engine/eng_err.c
index 81c70acfa8..81c70acfa8 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_err.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_err.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_fat.c b/drivers/builtin_openssl2/crypto/engine/eng_fat.c
index 789b8d57e5..789b8d57e5 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_fat.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_fat.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_init.c b/drivers/builtin_openssl2/crypto/engine/eng_init.c
index 7633cf5f1d..7633cf5f1d 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_init.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_init.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_int.h b/drivers/builtin_openssl2/crypto/engine/eng_int.h
index 451ef8feb8..451ef8feb8 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_int.h
+++ b/drivers/builtin_openssl2/crypto/engine/eng_int.h
diff --git a/drivers/builtin_openssl/crypto/engine/eng_lib.c b/drivers/builtin_openssl2/crypto/engine/eng_lib.c
index 18a6664645..18a6664645 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_lib.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_lib.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_list.c b/drivers/builtin_openssl2/crypto/engine/eng_list.c
index 95c858960b..95c858960b 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_list.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_list.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_openssl.c b/drivers/builtin_openssl2/crypto/engine/eng_openssl.c
index 9abb95cc22..9abb95cc22 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_openssl.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_openssl.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_pkey.c b/drivers/builtin_openssl2/crypto/engine/eng_pkey.c
index 1dfa2e3664..1dfa2e3664 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_pkey.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_pkey.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_rdrand.c b/drivers/builtin_openssl2/crypto/engine/eng_rdrand.c
index 4e9e91d54b..4e9e91d54b 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_rdrand.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_rdrand.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_rsax.c b/drivers/builtin_openssl2/crypto/engine/eng_rsax.c
index 96e63477ee..96e63477ee 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_rsax.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_rsax.c
diff --git a/drivers/builtin_openssl/crypto/engine/eng_table.c b/drivers/builtin_openssl2/crypto/engine/eng_table.c
index 4fde948185..4fde948185 100644
--- a/drivers/builtin_openssl/crypto/engine/eng_table.c
+++ b/drivers/builtin_openssl2/crypto/engine/eng_table.c
diff --git a/drivers/builtin_openssl/crypto/engine/enginetest.c b/drivers/builtin_openssl2/crypto/engine/enginetest.c
index f4d70e7e0a..f4d70e7e0a 100644
--- a/drivers/builtin_openssl/crypto/engine/enginetest.c
+++ b/drivers/builtin_openssl2/crypto/engine/enginetest.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_asnmth.c b/drivers/builtin_openssl2/crypto/engine/tb_asnmth.c
index 75090339f7..75090339f7 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_asnmth.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_asnmth.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_cipher.c b/drivers/builtin_openssl2/crypto/engine/tb_cipher.c
index 177fc1fb73..177fc1fb73 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_cipher.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_cipher.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_dh.c b/drivers/builtin_openssl2/crypto/engine/tb_dh.c
index 6e9d428761..6e9d428761 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_dh.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_dh.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_digest.c b/drivers/builtin_openssl2/crypto/engine/tb_digest.c
index d3f4bb2747..d3f4bb2747 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_digest.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_digest.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_dsa.c b/drivers/builtin_openssl2/crypto/engine/tb_dsa.c
index e4674f5f07..e4674f5f07 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_dsa.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_dsa.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_ecdh.c b/drivers/builtin_openssl2/crypto/engine/tb_ecdh.c
index c8ec7812c5..c8ec7812c5 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_ecdh.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_ecdh.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_ecdsa.c b/drivers/builtin_openssl2/crypto/engine/tb_ecdsa.c
index 005ecb622c..005ecb622c 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_ecdsa.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_ecdsa.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_pkmeth.c b/drivers/builtin_openssl2/crypto/engine/tb_pkmeth.c
index 1cdb967f25..1cdb967f25 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_pkmeth.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_pkmeth.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_rand.c b/drivers/builtin_openssl2/crypto/engine/tb_rand.c
index f36f67c0f6..f36f67c0f6 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_rand.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_rand.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_rsa.c b/drivers/builtin_openssl2/crypto/engine/tb_rsa.c
index fbc707fd26..fbc707fd26 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_rsa.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_rsa.c
diff --git a/drivers/builtin_openssl/crypto/engine/tb_store.c b/drivers/builtin_openssl2/crypto/engine/tb_store.c
index 8cc435c935..8cc435c935 100644
--- a/drivers/builtin_openssl/crypto/engine/tb_store.c
+++ b/drivers/builtin_openssl2/crypto/engine/tb_store.c
diff --git a/drivers/builtin_openssl/crypto/err/err.c b/drivers/builtin_openssl2/crypto/err/err.c
index fcdb244008..fcdb244008 100644
--- a/drivers/builtin_openssl/crypto/err/err.c
+++ b/drivers/builtin_openssl2/crypto/err/err.c
diff --git a/drivers/builtin_openssl/crypto/err/err_all.c b/drivers/builtin_openssl2/crypto/err/err_all.c
index 8eb547d98d..8eb547d98d 100644
--- a/drivers/builtin_openssl/crypto/err/err_all.c
+++ b/drivers/builtin_openssl2/crypto/err/err_all.c
diff --git a/drivers/builtin_openssl/crypto/err/err_prn.c b/drivers/builtin_openssl2/crypto/err/err_prn.c
index a0168ac8ed..a0168ac8ed 100644
--- a/drivers/builtin_openssl/crypto/err/err_prn.c
+++ b/drivers/builtin_openssl2/crypto/err/err_prn.c
diff --git a/drivers/builtin_openssl/crypto/err/openssl.ec b/drivers/builtin_openssl2/crypto/err/openssl.ec
index e0554b4342..e0554b4342 100644
--- a/drivers/builtin_openssl/crypto/err/openssl.ec
+++ b/drivers/builtin_openssl2/crypto/err/openssl.ec
diff --git a/drivers/builtin_openssl2/crypto/evp/bio_b64.c b/drivers/builtin_openssl2/crypto/evp/bio_b64.c
new file mode 100644
index 0000000000..16863fe23f
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/evp/bio_b64.c
@@ -0,0 +1,599 @@
+/* crypto/evp/bio_b64.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "cryptlib.h"
+#include <openssl/buffer.h>
+#include <openssl/evp.h>
+
+static int b64_write(BIO *h, const char *buf, int num);
+static int b64_read(BIO *h, char *buf, int size);
+static int b64_puts(BIO *h, const char *str);
+/*static int b64_gets(BIO *h, char *str, int size); */
+static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2);
+static int b64_new(BIO *h);
+static int b64_free(BIO *data);
+static long b64_callback_ctrl(BIO *h,int cmd,bio_info_cb *fp);
+#define B64_BLOCK_SIZE 1024
+#define B64_BLOCK_SIZE2 768
+#define B64_NONE 0
+#define B64_ENCODE 1
+#define B64_DECODE 2
+
+typedef struct b64_struct
+ {
+ /*BIO *bio; moved to the BIO structure */
+ int buf_len;
+ int buf_off;
+ int tmp_len; /* used to find the start when decoding */
+ int tmp_nl; /* If true, scan until '\n' */
+ int encode;
+ int start; /* have we started decoding yet? */
+ int cont; /* <= 0 when finished */
+ EVP_ENCODE_CTX base64;
+ char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE)+10];
+ char tmp[B64_BLOCK_SIZE];
+ } BIO_B64_CTX;
+
+static BIO_METHOD methods_b64=
+ {
+ BIO_TYPE_BASE64,"base64 encoding",
+ b64_write,
+ b64_read,
+ b64_puts,
+ NULL, /* b64_gets, */
+ b64_ctrl,
+ b64_new,
+ b64_free,
+ b64_callback_ctrl,
+ };
+
+BIO_METHOD *BIO_f_base64(void)
+ {
+ return(&methods_b64);
+ }
+
+static int b64_new(BIO *bi)
+ {
+ BIO_B64_CTX *ctx;
+
+ ctx=(BIO_B64_CTX *)OPENSSL_malloc(sizeof(BIO_B64_CTX));
+ if (ctx == NULL) return(0);
+
+ ctx->buf_len=0;
+ ctx->tmp_len=0;
+ ctx->tmp_nl=0;
+ ctx->buf_off=0;
+ ctx->cont=1;
+ ctx->start=1;
+ ctx->encode=0;
+
+ bi->init=1;
+ bi->ptr=(char *)ctx;
+ bi->flags=0;
+ bi->num = 0;
+ return(1);
+ }
+
+static int b64_free(BIO *a)
+ {
+ if (a == NULL) return(0);
+ OPENSSL_free(a->ptr);
+ a->ptr=NULL;
+ a->init=0;
+ a->flags=0;
+ return(1);
+ }
+
+static int b64_read(BIO *b, char *out, int outl)
+ {
+ int ret=0,i,ii,j,k,x,n,num,ret_code=0;
+ BIO_B64_CTX *ctx;
+ unsigned char *p,*q;
+
+ if (out == NULL) return(0);
+ ctx=(BIO_B64_CTX *)b->ptr;
+
+ if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
+
+ BIO_clear_retry_flags(b);
+
+ if (ctx->encode != B64_DECODE)
+ {
+ ctx->encode=B64_DECODE;
+ ctx->buf_len=0;
+ ctx->buf_off=0;
+ ctx->tmp_len=0;
+ EVP_DecodeInit(&(ctx->base64));
+ }
+
+ /* First check if there are bytes decoded/encoded */
+ if (ctx->buf_len > 0)
+ {
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ i=ctx->buf_len-ctx->buf_off;
+ if (i > outl) i=outl;
+ OPENSSL_assert(ctx->buf_off+i < (int)sizeof(ctx->buf));
+ memcpy(out,&(ctx->buf[ctx->buf_off]),i);
+ ret=i;
+ out+=i;
+ outl-=i;
+ ctx->buf_off+=i;
+ if (ctx->buf_len == ctx->buf_off)
+ {
+ ctx->buf_len=0;
+ ctx->buf_off=0;
+ }
+ }
+
+ /* At this point, we have room of outl bytes and an empty
+ * buffer, so we should read in some more. */
+
+ ret_code=0;
+ while (outl > 0)
+ {
+ if (ctx->cont <= 0)
+ break;
+
+ i=BIO_read(b->next_bio,&(ctx->tmp[ctx->tmp_len]),
+ B64_BLOCK_SIZE-ctx->tmp_len);
+
+ if (i <= 0)
+ {
+ ret_code=i;
+
+ /* Should we continue next time we are called? */
+ if (!BIO_should_retry(b->next_bio))
+ {
+ ctx->cont=i;
+ /* If buffer empty break */
+ if(ctx->tmp_len == 0)
+ break;
+ /* Fall through and process what we have */
+ else
+ i = 0;
+ }
+ /* else we retry and add more data to buffer */
+ else
+ break;
+ }
+ i+=ctx->tmp_len;
+ ctx->tmp_len = i;
+
+ /* We need to scan, a line at a time until we
+ * have a valid line if we are starting. */
+ if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL))
+ {
+ /* ctx->start=1; */
+ ctx->tmp_len=0;
+ }
+ else if (ctx->start)
+ {
+ q=p=(unsigned char *)ctx->tmp;
+ num = 0;
+ for (j=0; j<i; j++)
+ {
+ if (*(q++) != '\n') continue;
+
+ /* due to a previous very long line,
+ * we need to keep on scanning for a '\n'
+ * before we even start looking for
+ * base64 encoded stuff. */
+ if (ctx->tmp_nl)
+ {
+ p=q;
+ ctx->tmp_nl=0;
+ continue;
+ }
+
+ k=EVP_DecodeUpdate(&(ctx->base64),
+ (unsigned char *)ctx->buf,
+ &num,p,q-p);
+ if ((k <= 0) && (num == 0) && (ctx->start))
+ EVP_DecodeInit(&ctx->base64);
+ else
+ {
+ if (p != (unsigned char *)
+ &(ctx->tmp[0]))
+ {
+ i-=(p- (unsigned char *)
+ &(ctx->tmp[0]));
+ for (x=0; x < i; x++)
+ ctx->tmp[x]=p[x];
+ }
+ EVP_DecodeInit(&ctx->base64);
+ ctx->start=0;
+ break;
+ }
+ p=q;
+ }
+
+ /* we fell off the end without starting */
+ if ((j == i) && (num == 0))
+ {
+ /* Is this is one long chunk?, if so, keep on
+ * reading until a new line. */
+ if (p == (unsigned char *)&(ctx->tmp[0]))
+ {
+ /* Check buffer full */
+ if (i == B64_BLOCK_SIZE)
+ {
+ ctx->tmp_nl=1;
+ ctx->tmp_len=0;
+ }
+ }
+ else if (p != q) /* finished on a '\n' */
+ {
+ n=q-p;
+ for (ii=0; ii<n; ii++)
+ ctx->tmp[ii]=p[ii];
+ ctx->tmp_len=n;
+ }
+ /* else finished on a '\n' */
+ continue;
+ }
+ else
+ {
+ ctx->tmp_len=0;
+ }
+ }
+ else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0))
+ {
+ /* If buffer isn't full and we can retry then
+ * restart to read in more data.
+ */
+ continue;
+ }
+
+ if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
+ {
+ int z,jj;
+
+#if 0
+ jj=(i>>2)<<2;
+#else
+ jj = i & ~3; /* process per 4 */
+#endif
+ z=EVP_DecodeBlock((unsigned char *)ctx->buf,
+ (unsigned char *)ctx->tmp,jj);
+ if (jj > 2)
+ {
+ if (ctx->tmp[jj-1] == '=')
+ {
+ z--;
+ if (ctx->tmp[jj-2] == '=')
+ z--;
+ }
+ }
+ /* z is now number of output bytes and jj is the
+ * number consumed */
+ if (jj != i)
+ {
+ memmove(ctx->tmp, &ctx->tmp[jj], i-jj);
+ ctx->tmp_len=i-jj;
+ }
+ ctx->buf_len=0;
+ if (z > 0)
+ {
+ ctx->buf_len=z;
+ }
+ i=z;
+ }
+ else
+ {
+ i=EVP_DecodeUpdate(&(ctx->base64),
+ (unsigned char *)ctx->buf,&ctx->buf_len,
+ (unsigned char *)ctx->tmp,i);
+ ctx->tmp_len = 0;
+ }
+ ctx->buf_off=0;
+ if (i < 0)
+ {
+ ret_code=0;
+ ctx->buf_len=0;
+ break;
+ }
+
+ if (ctx->buf_len <= outl)
+ i=ctx->buf_len;
+ else
+ i=outl;
+
+ memcpy(out,ctx->buf,i);
+ ret+=i;
+ ctx->buf_off=i;
+ if (ctx->buf_off == ctx->buf_len)
+ {
+ ctx->buf_len=0;
+ ctx->buf_off=0;
+ }
+ outl-=i;
+ out+=i;
+ }
+ /* BIO_clear_retry_flags(b); */
+ BIO_copy_next_retry(b);
+ return((ret == 0)?ret_code:ret);
+ }
+
+static int b64_write(BIO *b, const char *in, int inl)
+ {
+ int ret=0;
+ int n;
+ int i;
+ BIO_B64_CTX *ctx;
+
+ ctx=(BIO_B64_CTX *)b->ptr;
+ BIO_clear_retry_flags(b);
+
+ if (ctx->encode != B64_ENCODE)
+ {
+ ctx->encode=B64_ENCODE;
+ ctx->buf_len=0;
+ ctx->buf_off=0;
+ ctx->tmp_len=0;
+ EVP_EncodeInit(&(ctx->base64));
+ }
+
+ OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf));
+ OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ n=ctx->buf_len-ctx->buf_off;
+ while (n > 0)
+ {
+ i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
+ if (i <= 0)
+ {
+ BIO_copy_next_retry(b);
+ return(i);
+ }
+ OPENSSL_assert(i <= n);
+ ctx->buf_off+=i;
+ OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ n-=i;
+ }
+ /* at this point all pending data has been written */
+ ctx->buf_off=0;
+ ctx->buf_len=0;
+
+ if ((in == NULL) || (inl <= 0)) return(0);
+
+ while (inl > 0)
+ {
+ n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl;
+
+ if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
+ {
+ if (ctx->tmp_len > 0)
+ {
+ OPENSSL_assert(ctx->tmp_len <= 3);
+ n=3-ctx->tmp_len;
+ /* There's a theoretical possibility for this */
+ if (n > inl)
+ n=inl;
+ memcpy(&(ctx->tmp[ctx->tmp_len]),in,n);
+ ctx->tmp_len+=n;
+ ret += n;
+ if (ctx->tmp_len < 3)
+ break;
+ ctx->buf_len=EVP_EncodeBlock((unsigned char *)ctx->buf,(unsigned char *)ctx->tmp,ctx->tmp_len);
+ OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ /* Since we're now done using the temporary
+ buffer, the length should be 0'd */
+ ctx->tmp_len=0;
+ }
+ else
+ {
+ if (n < 3)
+ {
+ memcpy(ctx->tmp,in,n);
+ ctx->tmp_len=n;
+ ret += n;
+ break;
+ }
+ n-=n%3;
+ ctx->buf_len=EVP_EncodeBlock((unsigned char *)ctx->buf,(const unsigned char *)in,n);
+ OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ ret += n;
+ }
+ }
+ else
+ {
+ EVP_EncodeUpdate(&(ctx->base64),
+ (unsigned char *)ctx->buf,&ctx->buf_len,
+ (unsigned char *)in,n);
+ OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ ret += n;
+ }
+ inl-=n;
+ in+=n;
+
+ ctx->buf_off=0;
+ n=ctx->buf_len;
+ while (n > 0)
+ {
+ i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
+ if (i <= 0)
+ {
+ BIO_copy_next_retry(b);
+ return((ret == 0)?i:ret);
+ }
+ OPENSSL_assert(i <= n);
+ n-=i;
+ ctx->buf_off+=i;
+ OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ }
+ ctx->buf_len=0;
+ ctx->buf_off=0;
+ }
+ return(ret);
+ }
+
+static long b64_ctrl(BIO *b, int cmd, long num, void *ptr)
+ {
+ BIO_B64_CTX *ctx;
+ long ret=1;
+ int i;
+
+ ctx=(BIO_B64_CTX *)b->ptr;
+
+ switch (cmd)
+ {
+ case BIO_CTRL_RESET:
+ ctx->cont=1;
+ ctx->start=1;
+ ctx->encode=B64_NONE;
+ ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+ break;
+ case BIO_CTRL_EOF: /* More to read */
+ if (ctx->cont <= 0)
+ ret=1;
+ else
+ ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+ break;
+ case BIO_CTRL_WPENDING: /* More to write in buffer */
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ ret=ctx->buf_len-ctx->buf_off;
+ if ((ret == 0) && (ctx->encode != B64_NONE)
+ && (ctx->base64.num != 0))
+ ret=1;
+ else if (ret <= 0)
+ ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+ break;
+ case BIO_CTRL_PENDING: /* More to read in buffer */
+ OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
+ ret=ctx->buf_len-ctx->buf_off;
+ if (ret <= 0)
+ ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+ break;
+ case BIO_CTRL_FLUSH:
+ /* do a final write */
+again:
+ while (ctx->buf_len != ctx->buf_off)
+ {
+ i=b64_write(b,NULL,0);
+ if (i < 0)
+ return i;
+ }
+ if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
+ {
+ if (ctx->tmp_len != 0)
+ {
+ ctx->buf_len=EVP_EncodeBlock(
+ (unsigned char *)ctx->buf,
+ (unsigned char *)ctx->tmp,
+ ctx->tmp_len);
+ ctx->buf_off=0;
+ ctx->tmp_len=0;
+ goto again;
+ }
+ }
+ else if (ctx->encode != B64_NONE && ctx->base64.num != 0)
+ {
+ ctx->buf_off=0;
+ EVP_EncodeFinal(&(ctx->base64),
+ (unsigned char *)ctx->buf,
+ &(ctx->buf_len));
+ /* push out the bytes */
+ goto again;
+ }
+ /* Finally flush the underlying BIO */
+ ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+ break;
+
+ case BIO_C_DO_STATE_MACHINE:
+ BIO_clear_retry_flags(b);
+ ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+ BIO_copy_next_retry(b);
+ break;
+
+ case BIO_CTRL_DUP:
+ break;
+ case BIO_CTRL_INFO:
+ case BIO_CTRL_GET:
+ case BIO_CTRL_SET:
+ default:
+ ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
+ break;
+ }
+ return(ret);
+ }
+
+static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
+ {
+ long ret=1;
+
+ if (b->next_bio == NULL) return(0);
+ switch (cmd)
+ {
+ default:
+ ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
+ break;
+ }
+ return(ret);
+ }
+
+static int b64_puts(BIO *b, const char *str)
+ {
+ return b64_write(b,str,strlen(str));
+ }
diff --git a/drivers/builtin_openssl/crypto/evp/bio_enc.c b/drivers/builtin_openssl2/crypto/evp/bio_enc.c
index b6efb5fbc4..b6efb5fbc4 100644
--- a/drivers/builtin_openssl/crypto/evp/bio_enc.c
+++ b/drivers/builtin_openssl2/crypto/evp/bio_enc.c
diff --git a/drivers/builtin_openssl/crypto/evp/bio_md.c b/drivers/builtin_openssl2/crypto/evp/bio_md.c
index 144fdfd56a..144fdfd56a 100644
--- a/drivers/builtin_openssl/crypto/evp/bio_md.c
+++ b/drivers/builtin_openssl2/crypto/evp/bio_md.c
diff --git a/drivers/builtin_openssl/crypto/evp/bio_ok.c b/drivers/builtin_openssl2/crypto/evp/bio_ok.c
index e64335353f..e64335353f 100644
--- a/drivers/builtin_openssl/crypto/evp/bio_ok.c
+++ b/drivers/builtin_openssl2/crypto/evp/bio_ok.c
diff --git a/drivers/builtin_openssl/crypto/evp/c_all.c b/drivers/builtin_openssl2/crypto/evp/c_all.c
index 766c4cecdf..766c4cecdf 100644
--- a/drivers/builtin_openssl/crypto/evp/c_all.c
+++ b/drivers/builtin_openssl2/crypto/evp/c_all.c
diff --git a/drivers/builtin_openssl/crypto/evp/c_allc.c b/drivers/builtin_openssl2/crypto/evp/c_allc.c
index 2a45d435e5..2a45d435e5 100644
--- a/drivers/builtin_openssl/crypto/evp/c_allc.c
+++ b/drivers/builtin_openssl2/crypto/evp/c_allc.c
diff --git a/drivers/builtin_openssl/crypto/evp/c_alld.c b/drivers/builtin_openssl2/crypto/evp/c_alld.c
index 311e1fe2f8..311e1fe2f8 100644
--- a/drivers/builtin_openssl/crypto/evp/c_alld.c
+++ b/drivers/builtin_openssl2/crypto/evp/c_alld.c
diff --git a/drivers/builtin_openssl/crypto/evp/digest.c b/drivers/builtin_openssl2/crypto/evp/digest.c
index d14e8e48d5..d14e8e48d5 100644
--- a/drivers/builtin_openssl/crypto/evp/digest.c
+++ b/drivers/builtin_openssl2/crypto/evp/digest.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_aes.c b/drivers/builtin_openssl2/crypto/evp/e_aes.c
index c7869b69ef..c7869b69ef 100644
--- a/drivers/builtin_openssl/crypto/evp/e_aes.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_aes.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_aes_cbc_hmac_sha1.c b/drivers/builtin_openssl2/crypto/evp/e_aes_cbc_hmac_sha1.c
index fb2c884a78..fb2c884a78 100644
--- a/drivers/builtin_openssl/crypto/evp/e_aes_cbc_hmac_sha1.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_aes_cbc_hmac_sha1.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_bf.c b/drivers/builtin_openssl2/crypto/evp/e_bf.c
index cc224e5363..cc224e5363 100644
--- a/drivers/builtin_openssl/crypto/evp/e_bf.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_bf.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_camellia.c b/drivers/builtin_openssl2/crypto/evp/e_camellia.c
index a7b40d1c60..a7b40d1c60 100644
--- a/drivers/builtin_openssl/crypto/evp/e_camellia.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_camellia.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_cast.c b/drivers/builtin_openssl2/crypto/evp/e_cast.c
index d77bcd9298..d77bcd9298 100644
--- a/drivers/builtin_openssl/crypto/evp/e_cast.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_cast.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_des.c b/drivers/builtin_openssl2/crypto/evp/e_des.c
index ca009f2c52..ca009f2c52 100644
--- a/drivers/builtin_openssl/crypto/evp/e_des.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_des.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_des3.c b/drivers/builtin_openssl2/crypto/evp/e_des3.c
index 8d7b7de292..8d7b7de292 100644
--- a/drivers/builtin_openssl/crypto/evp/e_des3.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_des3.c
diff --git a/drivers/builtin_openssl2/crypto/evp/e_dsa.c b/drivers/builtin_openssl2/crypto/evp/e_dsa.c
new file mode 100644
index 0000000000..b96f2738b3
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/evp/e_dsa.c
@@ -0,0 +1,71 @@
+/* crypto/evp/e_dsa.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+
+static EVP_PKEY_METHOD dss_method=
+ {
+ DSA_sign,
+ DSA_verify,
+ {EVP_PKEY_DSA,EVP_PKEY_DSA2,EVP_PKEY_DSA3,NULL},
+ };
+
diff --git a/drivers/builtin_openssl/crypto/evp/e_idea.c b/drivers/builtin_openssl2/crypto/evp/e_idea.c
index 806b080360..806b080360 100644
--- a/drivers/builtin_openssl/crypto/evp/e_idea.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_idea.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_null.c b/drivers/builtin_openssl2/crypto/evp/e_null.c
index f0c1f78b5f..f0c1f78b5f 100644
--- a/drivers/builtin_openssl/crypto/evp/e_null.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_null.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_old.c b/drivers/builtin_openssl2/crypto/evp/e_old.c
index 1642af4869..1642af4869 100644
--- a/drivers/builtin_openssl/crypto/evp/e_old.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_old.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_rc2.c b/drivers/builtin_openssl2/crypto/evp/e_rc2.c
index d4c33b58d4..d4c33b58d4 100644
--- a/drivers/builtin_openssl/crypto/evp/e_rc2.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_rc2.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_rc4.c b/drivers/builtin_openssl2/crypto/evp/e_rc4.c
index b4f6bda82d..b4f6bda82d 100644
--- a/drivers/builtin_openssl/crypto/evp/e_rc4.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_rc4.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_rc4_hmac_md5.c b/drivers/builtin_openssl2/crypto/evp/e_rc4_hmac_md5.c
index 56563191ba..56563191ba 100644
--- a/drivers/builtin_openssl/crypto/evp/e_rc4_hmac_md5.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_rc4_hmac_md5.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_rc5.c b/drivers/builtin_openssl2/crypto/evp/e_rc5.c
index 19a10c6402..19a10c6402 100644
--- a/drivers/builtin_openssl/crypto/evp/e_rc5.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_rc5.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_seed.c b/drivers/builtin_openssl2/crypto/evp/e_seed.c
index 2d1759d276..2d1759d276 100644
--- a/drivers/builtin_openssl/crypto/evp/e_seed.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_seed.c
diff --git a/drivers/builtin_openssl/crypto/evp/e_xcbc_d.c b/drivers/builtin_openssl2/crypto/evp/e_xcbc_d.c
index 250e88c8c5..250e88c8c5 100644
--- a/drivers/builtin_openssl/crypto/evp/e_xcbc_d.c
+++ b/drivers/builtin_openssl2/crypto/evp/e_xcbc_d.c
diff --git a/drivers/builtin_openssl2/crypto/evp/encode.c b/drivers/builtin_openssl2/crypto/evp/encode.c
new file mode 100644
index 0000000000..4654bdc61a
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/evp/encode.c
@@ -0,0 +1,446 @@
+/* crypto/evp/encode.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/evp.h>
+
+#ifndef CHARSET_EBCDIC
+#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f])
+#define conv_ascii2bin(a) (data_ascii2bin[(a)&0x7f])
+#else
+/* We assume that PEM encoded files are EBCDIC files
+ * (i.e., printable text files). Convert them here while decoding.
+ * When encoding, output is EBCDIC (text) format again.
+ * (No need for conversion in the conv_bin2ascii macro, as the
+ * underlying textstring data_bin2ascii[] is already EBCDIC)
+ */
+#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f])
+#define conv_ascii2bin(a) (data_ascii2bin[os_toascii[a]&0x7f])
+#endif
+
+/* 64 char lines
+ * pad input with 0
+ * left over chars are set to =
+ * 1 byte => xx==
+ * 2 bytes => xxx=
+ * 3 bytes => xxxx
+ */
+#define BIN_PER_LINE (64/4*3)
+#define CHUNKS_PER_LINE (64/4)
+#define CHAR_PER_LINE (64+1)
+
+static const unsigned char data_bin2ascii[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+abcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* 0xF0 is a EOLN
+ * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
+ * 0xF2 is EOF
+ * 0xE0 is ignore at start of line.
+ * 0xFF is error
+ */
+
+#define B64_EOLN 0xF0
+#define B64_CR 0xF1
+#define B64_EOF 0xF2
+#define B64_WS 0xE0
+#define B64_ERROR 0xFF
+#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3)
+
+static const unsigned char data_ascii2bin[128]={
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xE0,0xF0,0xFF,0xFF,0xF1,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0x3E,0xFF,0xF2,0xFF,0x3F,
+ 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,
+ 0x3C,0x3D,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
+ 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,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,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,0xFF,0xFF,0xFF,0xFF,0xFF,
+ };
+
+void EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
+ {
+ ctx->length=48;
+ ctx->num=0;
+ ctx->line_num=0;
+ }
+
+void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
+ const unsigned char *in, int inl)
+ {
+ int i,j;
+ unsigned int total=0;
+
+ *outl=0;
+ if (inl == 0) return;
+ OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
+ if ((ctx->num+inl) < ctx->length)
+ {
+ memcpy(&(ctx->enc_data[ctx->num]),in,inl);
+ ctx->num+=inl;
+ return;
+ }
+ if (ctx->num != 0)
+ {
+ i=ctx->length-ctx->num;
+ memcpy(&(ctx->enc_data[ctx->num]),in,i);
+ in+=i;
+ inl-=i;
+ j=EVP_EncodeBlock(out,ctx->enc_data,ctx->length);
+ ctx->num=0;
+ out+=j;
+ *(out++)='\n';
+ *out='\0';
+ total=j+1;
+ }
+ while (inl >= ctx->length)
+ {
+ j=EVP_EncodeBlock(out,in,ctx->length);
+ in+=ctx->length;
+ inl-=ctx->length;
+ out+=j;
+ *(out++)='\n';
+ *out='\0';
+ total+=j+1;
+ }
+ if (inl != 0)
+ memcpy(&(ctx->enc_data[0]),in,inl);
+ ctx->num=inl;
+ *outl=total;
+ }
+
+void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
+ {
+ unsigned int ret=0;
+
+ if (ctx->num != 0)
+ {
+ ret=EVP_EncodeBlock(out,ctx->enc_data,ctx->num);
+ out[ret++]='\n';
+ out[ret]='\0';
+ ctx->num=0;
+ }
+ *outl=ret;
+ }
+
+int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
+ {
+ int i,ret=0;
+ unsigned long l;
+
+ for (i=dlen; i > 0; i-=3)
+ {
+ if (i >= 3)
+ {
+ l= (((unsigned long)f[0])<<16L)|
+ (((unsigned long)f[1])<< 8L)|f[2];
+ *(t++)=conv_bin2ascii(l>>18L);
+ *(t++)=conv_bin2ascii(l>>12L);
+ *(t++)=conv_bin2ascii(l>> 6L);
+ *(t++)=conv_bin2ascii(l );
+ }
+ else
+ {
+ l=((unsigned long)f[0])<<16L;
+ if (i == 2) l|=((unsigned long)f[1]<<8L);
+
+ *(t++)=conv_bin2ascii(l>>18L);
+ *(t++)=conv_bin2ascii(l>>12L);
+ *(t++)=(i == 1)?'=':conv_bin2ascii(l>> 6L);
+ *(t++)='=';
+ }
+ ret+=4;
+ f+=3;
+ }
+
+ *t='\0';
+ return(ret);
+ }
+
+void EVP_DecodeInit(EVP_ENCODE_CTX *ctx)
+ {
+ ctx->length=30;
+ ctx->num=0;
+ ctx->line_num=0;
+ ctx->expect_nl=0;
+ }
+
+/* -1 for error
+ * 0 for last line
+ * 1 for full line
+ */
+int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
+ const unsigned char *in, int inl)
+ {
+ int seof= -1,eof=0,rv= -1,ret=0,i,v,tmp,n,ln,exp_nl;
+ unsigned char *d;
+
+ n=ctx->num;
+ d=ctx->enc_data;
+ ln=ctx->line_num;
+ exp_nl=ctx->expect_nl;
+
+ /* last line of input. */
+ if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF)))
+ { rv=0; goto end; }
+
+ /* We parse the input data */
+ for (i=0; i<inl; i++)
+ {
+ /* If the current line is > 80 characters, scream alot */
+ if (ln >= 80) { rv= -1; goto end; }
+
+ /* Get char and put it into the buffer */
+ tmp= *(in++);
+ v=conv_ascii2bin(tmp);
+ /* only save the good data :-) */
+ if (!B64_NOT_BASE64(v))
+ {
+ OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
+ d[n++]=tmp;
+ ln++;
+ }
+ else if (v == B64_ERROR)
+ {
+ rv= -1;
+ goto end;
+ }
+
+ /* have we seen a '=' which is 'definitly' the last
+ * input line. seof will point to the character that
+ * holds it. and eof will hold how many characters to
+ * chop off. */
+ if (tmp == '=')
+ {
+ if (seof == -1) seof=n;
+ eof++;
+ }
+
+ if (v == B64_CR)
+ {
+ ln = 0;
+ if (exp_nl)
+ continue;
+ }
+
+ /* eoln */
+ if (v == B64_EOLN)
+ {
+ ln=0;
+ if (exp_nl)
+ {
+ exp_nl=0;
+ continue;
+ }
+ }
+ exp_nl=0;
+
+ /* If we are at the end of input and it looks like a
+ * line, process it. */
+ if (((i+1) == inl) && (((n&3) == 0) || eof))
+ {
+ v=B64_EOF;
+ /* In case things were given us in really small
+ records (so two '=' were given in separate
+ updates), eof may contain the incorrect number
+ of ending bytes to skip, so let's redo the count */
+ eof = 0;
+ if (d[n-1] == '=') eof++;
+ if (d[n-2] == '=') eof++;
+ /* There will never be more than two '=' */
+ }
+
+ if ((v == B64_EOF && (n&3) == 0) || (n >= 64))
+ {
+ /* This is needed to work correctly on 64 byte input
+ * lines. We process the line and then need to
+ * accept the '\n' */
+ if ((v != B64_EOF) && (n >= 64)) exp_nl=1;
+ if (n > 0)
+ {
+ v=EVP_DecodeBlock(out,d,n);
+ n=0;
+ if (v < 0) { rv=0; goto end; }
+ if (eof > v) { rv=-1; goto end; }
+ ret+=(v-eof);
+ }
+ else
+ {
+ eof=1;
+ v=0;
+ }
+
+ /* This is the case where we have had a short
+ * but valid input line */
+ if ((v < ctx->length) && eof)
+ {
+ rv=0;
+ goto end;
+ }
+ else
+ ctx->length=v;
+
+ if (seof >= 0) { rv=0; goto end; }
+ out+=v;
+ }
+ }
+ rv=1;
+end:
+ *outl=ret;
+ ctx->num=n;
+ ctx->line_num=ln;
+ ctx->expect_nl=exp_nl;
+ return(rv);
+ }
+
+int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n)
+ {
+ int i,ret=0,a,b,c,d;
+ unsigned long l;
+
+ /* trim white space from the start of the line. */
+ while ((conv_ascii2bin(*f) == B64_WS) && (n > 0))
+ {
+ f++;
+ n--;
+ }
+
+ /* strip off stuff at the end of the line
+ * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */
+ while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n-1]))))
+ n--;
+
+ if (n%4 != 0) return(-1);
+
+ for (i=0; i<n; i+=4)
+ {
+ a=conv_ascii2bin(*(f++));
+ b=conv_ascii2bin(*(f++));
+ c=conv_ascii2bin(*(f++));
+ d=conv_ascii2bin(*(f++));
+ if ( (a & 0x80) || (b & 0x80) ||
+ (c & 0x80) || (d & 0x80))
+ return(-1);
+ l=( (((unsigned long)a)<<18L)|
+ (((unsigned long)b)<<12L)|
+ (((unsigned long)c)<< 6L)|
+ (((unsigned long)d) ));
+ *(t++)=(unsigned char)(l>>16L)&0xff;
+ *(t++)=(unsigned char)(l>> 8L)&0xff;
+ *(t++)=(unsigned char)(l )&0xff;
+ ret+=3;
+ }
+ return(ret);
+ }
+
+int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
+ {
+ int i;
+
+ *outl=0;
+ if (ctx->num != 0)
+ {
+ i=EVP_DecodeBlock(out,ctx->enc_data,ctx->num);
+ if (i < 0) return(-1);
+ ctx->num=0;
+ *outl=i;
+ return(1);
+ }
+ else
+ return(1);
+ }
+
+#ifdef undef
+int EVP_DecodeValid(unsigned char *buf, int len)
+ {
+ int i,num=0,bad=0;
+
+ if (len == 0) return(-1);
+ while (conv_ascii2bin(*buf) == B64_WS)
+ {
+ buf++;
+ len--;
+ if (len == 0) return(-1);
+ }
+
+ for (i=len; i >= 4; i-=4)
+ {
+ if ( (conv_ascii2bin(buf[0]) >= 0x40) ||
+ (conv_ascii2bin(buf[1]) >= 0x40) ||
+ (conv_ascii2bin(buf[2]) >= 0x40) ||
+ (conv_ascii2bin(buf[3]) >= 0x40))
+ return(-1);
+ buf+=4;
+ num+=1+(buf[2] != '=')+(buf[3] != '=');
+ }
+ if ((i == 1) && (conv_ascii2bin(buf[0]) == B64_EOLN))
+ return(num);
+ if ((i == 2) && (conv_ascii2bin(buf[0]) == B64_EOLN) &&
+ (conv_ascii2bin(buf[0]) == B64_EOLN))
+ return(num);
+ return(1);
+ }
+#endif
diff --git a/drivers/builtin_openssl/crypto/evp/evp_acnf.c b/drivers/builtin_openssl2/crypto/evp/evp_acnf.c
index 643a1864e8..643a1864e8 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_acnf.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_acnf.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_cnf.c b/drivers/builtin_openssl2/crypto/evp/evp_cnf.c
index 2e4db30235..2e4db30235 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_cnf.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_cnf.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_enc.c b/drivers/builtin_openssl2/crypto/evp/evp_enc.c
index 0c54f05e6e..0c54f05e6e 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_enc.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_enc.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_err.c b/drivers/builtin_openssl2/crypto/evp/evp_err.c
index 08eab9882f..08eab9882f 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_err.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_err.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_fips.c b/drivers/builtin_openssl2/crypto/evp/evp_fips.c
index cb7f4fc0fa..cb7f4fc0fa 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_fips.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_fips.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_key.c b/drivers/builtin_openssl2/crypto/evp/evp_key.c
index 7961fbebf2..7961fbebf2 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_key.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_key.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_lib.c b/drivers/builtin_openssl2/crypto/evp/evp_lib.c
index b180e4828a..b180e4828a 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_lib.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_lib.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_locl.h b/drivers/builtin_openssl2/crypto/evp/evp_locl.h
index 08c0a66d39..08c0a66d39 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_locl.h
+++ b/drivers/builtin_openssl2/crypto/evp/evp_locl.h
diff --git a/drivers/builtin_openssl/crypto/evp/evp_pbe.c b/drivers/builtin_openssl2/crypto/evp/evp_pbe.c
index f8c32d825e..f8c32d825e 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_pbe.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_pbe.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_pkey.c b/drivers/builtin_openssl2/crypto/evp/evp_pkey.c
index ceebf69284..ceebf69284 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_pkey.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_pkey.c
diff --git a/drivers/builtin_openssl/crypto/evp/evp_test.c b/drivers/builtin_openssl2/crypto/evp/evp_test.c
index 55c7cdfdcc..55c7cdfdcc 100644
--- a/drivers/builtin_openssl/crypto/evp/evp_test.c
+++ b/drivers/builtin_openssl2/crypto/evp/evp_test.c
diff --git a/drivers/builtin_openssl/crypto/evp/evptests.txt b/drivers/builtin_openssl2/crypto/evp/evptests.txt
index c273707c14..c273707c14 100644
--- a/drivers/builtin_openssl/crypto/evp/evptests.txt
+++ b/drivers/builtin_openssl2/crypto/evp/evptests.txt
diff --git a/drivers/builtin_openssl/crypto/evp/m_dss.c b/drivers/builtin_openssl2/crypto/evp/m_dss.c
index 6fb7e9a861..6fb7e9a861 100644
--- a/drivers/builtin_openssl/crypto/evp/m_dss.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_dss.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_dss1.c b/drivers/builtin_openssl2/crypto/evp/m_dss1.c
index 2df362a670..2df362a670 100644
--- a/drivers/builtin_openssl/crypto/evp/m_dss1.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_dss1.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_ecdsa.c b/drivers/builtin_openssl2/crypto/evp/m_ecdsa.c
index 4b15fb0f6c..4b15fb0f6c 100644
--- a/drivers/builtin_openssl/crypto/evp/m_ecdsa.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_ecdsa.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_md2.c b/drivers/builtin_openssl2/crypto/evp/m_md2.c
index 5ce849f161..5ce849f161 100644
--- a/drivers/builtin_openssl/crypto/evp/m_md2.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_md2.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_md4.c b/drivers/builtin_openssl2/crypto/evp/m_md4.c
index 6d47f61b27..6d47f61b27 100644
--- a/drivers/builtin_openssl/crypto/evp/m_md4.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_md4.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_md5.c b/drivers/builtin_openssl2/crypto/evp/m_md5.c
index 9a8bae0258..9a8bae0258 100644
--- a/drivers/builtin_openssl/crypto/evp/m_md5.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_md5.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_mdc2.c b/drivers/builtin_openssl2/crypto/evp/m_mdc2.c
index 3602bed316..3602bed316 100644
--- a/drivers/builtin_openssl/crypto/evp/m_mdc2.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_mdc2.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_null.c b/drivers/builtin_openssl2/crypto/evp/m_null.c
index cb0721699d..cb0721699d 100644
--- a/drivers/builtin_openssl/crypto/evp/m_null.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_null.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_ripemd.c b/drivers/builtin_openssl2/crypto/evp/m_ripemd.c
index 7bf4804cf8..7bf4804cf8 100644
--- a/drivers/builtin_openssl/crypto/evp/m_ripemd.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_ripemd.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_sha.c b/drivers/builtin_openssl2/crypto/evp/m_sha.c
index 8769cdd42f..8769cdd42f 100644
--- a/drivers/builtin_openssl/crypto/evp/m_sha.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_sha.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_sha1.c b/drivers/builtin_openssl2/crypto/evp/m_sha1.c
index bd0c01ad3c..bd0c01ad3c 100644
--- a/drivers/builtin_openssl/crypto/evp/m_sha1.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_sha1.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_sigver.c b/drivers/builtin_openssl2/crypto/evp/m_sigver.c
index 7e2731f4a4..7e2731f4a4 100644
--- a/drivers/builtin_openssl/crypto/evp/m_sigver.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_sigver.c
diff --git a/drivers/builtin_openssl/crypto/evp/m_wp.c b/drivers/builtin_openssl2/crypto/evp/m_wp.c
index c51bc2d5d1..c51bc2d5d1 100644
--- a/drivers/builtin_openssl/crypto/evp/m_wp.c
+++ b/drivers/builtin_openssl2/crypto/evp/m_wp.c
diff --git a/drivers/builtin_openssl/crypto/evp/names.c b/drivers/builtin_openssl2/crypto/evp/names.c
index 6311ad7cfb..6311ad7cfb 100644
--- a/drivers/builtin_openssl/crypto/evp/names.c
+++ b/drivers/builtin_openssl2/crypto/evp/names.c
diff --git a/drivers/builtin_openssl/crypto/evp/openbsd_hw.c b/drivers/builtin_openssl2/crypto/evp/openbsd_hw.c
index 3831a5731e..3831a5731e 100644
--- a/drivers/builtin_openssl/crypto/evp/openbsd_hw.c
+++ b/drivers/builtin_openssl2/crypto/evp/openbsd_hw.c
diff --git a/drivers/builtin_openssl/crypto/evp/p5_crpt.c b/drivers/builtin_openssl2/crypto/evp/p5_crpt.c
index 294cc90d87..294cc90d87 100644
--- a/drivers/builtin_openssl/crypto/evp/p5_crpt.c
+++ b/drivers/builtin_openssl2/crypto/evp/p5_crpt.c
diff --git a/drivers/builtin_openssl/crypto/evp/p5_crpt2.c b/drivers/builtin_openssl2/crypto/evp/p5_crpt2.c
index fe3c6c8813..fe3c6c8813 100644
--- a/drivers/builtin_openssl/crypto/evp/p5_crpt2.c
+++ b/drivers/builtin_openssl2/crypto/evp/p5_crpt2.c
diff --git a/drivers/builtin_openssl/crypto/evp/p_dec.c b/drivers/builtin_openssl2/crypto/evp/p_dec.c
index 4201dcbad9..4201dcbad9 100644
--- a/drivers/builtin_openssl/crypto/evp/p_dec.c
+++ b/drivers/builtin_openssl2/crypto/evp/p_dec.c
diff --git a/drivers/builtin_openssl/crypto/evp/p_enc.c b/drivers/builtin_openssl2/crypto/evp/p_enc.c
index b5a3a84c41..b5a3a84c41 100644
--- a/drivers/builtin_openssl/crypto/evp/p_enc.c
+++ b/drivers/builtin_openssl2/crypto/evp/p_enc.c
diff --git a/drivers/builtin_openssl/crypto/evp/p_lib.c b/drivers/builtin_openssl2/crypto/evp/p_lib.c
index e26ccd0d08..e26ccd0d08 100644
--- a/drivers/builtin_openssl/crypto/evp/p_lib.c
+++ b/drivers/builtin_openssl2/crypto/evp/p_lib.c
diff --git a/drivers/builtin_openssl/crypto/evp/p_open.c b/drivers/builtin_openssl2/crypto/evp/p_open.c
index c748fbea87..c748fbea87 100644
--- a/drivers/builtin_openssl/crypto/evp/p_open.c
+++ b/drivers/builtin_openssl2/crypto/evp/p_open.c
diff --git a/drivers/builtin_openssl/crypto/evp/p_seal.c b/drivers/builtin_openssl2/crypto/evp/p_seal.c
index e5919b0fbf..e5919b0fbf 100644
--- a/drivers/builtin_openssl/crypto/evp/p_seal.c
+++ b/drivers/builtin_openssl2/crypto/evp/p_seal.c
diff --git a/drivers/builtin_openssl/crypto/evp/p_sign.c b/drivers/builtin_openssl2/crypto/evp/p_sign.c
index 8afb664306..8afb664306 100644
--- a/drivers/builtin_openssl/crypto/evp/p_sign.c
+++ b/drivers/builtin_openssl2/crypto/evp/p_sign.c
diff --git a/drivers/builtin_openssl/crypto/evp/p_verify.c b/drivers/builtin_openssl2/crypto/evp/p_verify.c
index c66d63ccf8..c66d63ccf8 100644
--- a/drivers/builtin_openssl/crypto/evp/p_verify.c
+++ b/drivers/builtin_openssl2/crypto/evp/p_verify.c
diff --git a/drivers/builtin_openssl/crypto/evp/pmeth_fn.c b/drivers/builtin_openssl2/crypto/evp/pmeth_fn.c
index c4676f2f8d..c4676f2f8d 100644
--- a/drivers/builtin_openssl/crypto/evp/pmeth_fn.c
+++ b/drivers/builtin_openssl2/crypto/evp/pmeth_fn.c
diff --git a/drivers/builtin_openssl/crypto/evp/pmeth_gn.c b/drivers/builtin_openssl2/crypto/evp/pmeth_gn.c
index 4651c81370..4651c81370 100644
--- a/drivers/builtin_openssl/crypto/evp/pmeth_gn.c
+++ b/drivers/builtin_openssl2/crypto/evp/pmeth_gn.c
diff --git a/drivers/builtin_openssl/crypto/evp/pmeth_lib.c b/drivers/builtin_openssl2/crypto/evp/pmeth_lib.c
index acfa7b6f87..acfa7b6f87 100644
--- a/drivers/builtin_openssl/crypto/evp/pmeth_lib.c
+++ b/drivers/builtin_openssl2/crypto/evp/pmeth_lib.c
diff --git a/drivers/builtin_openssl/crypto/ex_data.c b/drivers/builtin_openssl2/crypto/ex_data.c
index e2bc8298d0..e2bc8298d0 100644
--- a/drivers/builtin_openssl/crypto/ex_data.c
+++ b/drivers/builtin_openssl2/crypto/ex_data.c
diff --git a/drivers/builtin_openssl/crypto/fips_err.h b/drivers/builtin_openssl2/crypto/fips_err.h
index c671691b47..c671691b47 100644
--- a/drivers/builtin_openssl/crypto/fips_err.h
+++ b/drivers/builtin_openssl2/crypto/fips_err.h
diff --git a/drivers/builtin_openssl/crypto/fips_ers.c b/drivers/builtin_openssl2/crypto/fips_ers.c
index 09f11748f6..09f11748f6 100644
--- a/drivers/builtin_openssl/crypto/fips_ers.c
+++ b/drivers/builtin_openssl2/crypto/fips_ers.c
diff --git a/drivers/builtin_openssl/crypto/hmac/hm_ameth.c b/drivers/builtin_openssl2/crypto/hmac/hm_ameth.c
index e03f24aeda..e03f24aeda 100644
--- a/drivers/builtin_openssl/crypto/hmac/hm_ameth.c
+++ b/drivers/builtin_openssl2/crypto/hmac/hm_ameth.c
diff --git a/drivers/builtin_openssl/crypto/hmac/hm_pmeth.c b/drivers/builtin_openssl2/crypto/hmac/hm_pmeth.c
index 0daa44511d..0daa44511d 100644
--- a/drivers/builtin_openssl/crypto/hmac/hm_pmeth.c
+++ b/drivers/builtin_openssl2/crypto/hmac/hm_pmeth.c
diff --git a/drivers/builtin_openssl/crypto/hmac/hmac.c b/drivers/builtin_openssl2/crypto/hmac/hmac.c
index ba27cbf56f..ba27cbf56f 100644
--- a/drivers/builtin_openssl/crypto/hmac/hmac.c
+++ b/drivers/builtin_openssl2/crypto/hmac/hmac.c
diff --git a/drivers/builtin_openssl/crypto/hmac/hmactest.c b/drivers/builtin_openssl2/crypto/hmac/hmactest.c
index 1b906b81af..1b906b81af 100644
--- a/drivers/builtin_openssl/crypto/hmac/hmactest.c
+++ b/drivers/builtin_openssl2/crypto/hmac/hmactest.c
diff --git a/drivers/builtin_openssl/crypto/ia64cpuid.S b/drivers/builtin_openssl2/crypto/ia64cpuid.S
index 7832b9b640..7832b9b640 100644
--- a/drivers/builtin_openssl/crypto/ia64cpuid.S
+++ b/drivers/builtin_openssl2/crypto/ia64cpuid.S
diff --git a/drivers/builtin_openssl/crypto/idea/i_cbc.c b/drivers/builtin_openssl2/crypto/idea/i_cbc.c
index ecb9cb8b83..ecb9cb8b83 100644
--- a/drivers/builtin_openssl/crypto/idea/i_cbc.c
+++ b/drivers/builtin_openssl2/crypto/idea/i_cbc.c
diff --git a/drivers/builtin_openssl/crypto/idea/i_cfb64.c b/drivers/builtin_openssl2/crypto/idea/i_cfb64.c
index 66d49d520e..66d49d520e 100644
--- a/drivers/builtin_openssl/crypto/idea/i_cfb64.c
+++ b/drivers/builtin_openssl2/crypto/idea/i_cfb64.c
diff --git a/drivers/builtin_openssl/crypto/idea/i_ecb.c b/drivers/builtin_openssl2/crypto/idea/i_ecb.c
index fef38230a7..fef38230a7 100644
--- a/drivers/builtin_openssl/crypto/idea/i_ecb.c
+++ b/drivers/builtin_openssl2/crypto/idea/i_ecb.c
diff --git a/drivers/builtin_openssl/crypto/idea/i_ofb64.c b/drivers/builtin_openssl2/crypto/idea/i_ofb64.c
index e749e88e34..e749e88e34 100644
--- a/drivers/builtin_openssl/crypto/idea/i_ofb64.c
+++ b/drivers/builtin_openssl2/crypto/idea/i_ofb64.c
diff --git a/drivers/builtin_openssl/crypto/idea/i_skey.c b/drivers/builtin_openssl2/crypto/idea/i_skey.c
index afb830964d..afb830964d 100644
--- a/drivers/builtin_openssl/crypto/idea/i_skey.c
+++ b/drivers/builtin_openssl2/crypto/idea/i_skey.c
diff --git a/drivers/builtin_openssl/crypto/idea/idea_lcl.h b/drivers/builtin_openssl2/crypto/idea/idea_lcl.h
index f3dbfa67e9..f3dbfa67e9 100644
--- a/drivers/builtin_openssl/crypto/idea/idea_lcl.h
+++ b/drivers/builtin_openssl2/crypto/idea/idea_lcl.h
diff --git a/drivers/builtin_openssl/crypto/idea/idea_spd.c b/drivers/builtin_openssl2/crypto/idea/idea_spd.c
index 699353e871..699353e871 100644
--- a/drivers/builtin_openssl/crypto/idea/idea_spd.c
+++ b/drivers/builtin_openssl2/crypto/idea/idea_spd.c
diff --git a/drivers/builtin_openssl/crypto/idea/ideatest.c b/drivers/builtin_openssl2/crypto/idea/ideatest.c
index e6ffc7025e..e6ffc7025e 100644
--- a/drivers/builtin_openssl/crypto/idea/ideatest.c
+++ b/drivers/builtin_openssl2/crypto/idea/ideatest.c
diff --git a/drivers/builtin_openssl/crypto/idea/version b/drivers/builtin_openssl2/crypto/idea/version
index 3f22293795..3f22293795 100644
--- a/drivers/builtin_openssl/crypto/idea/version
+++ b/drivers/builtin_openssl2/crypto/idea/version
diff --git a/drivers/builtin_openssl/crypto/install-crypto.com b/drivers/builtin_openssl2/crypto/install-crypto.com
index 85b3d583cf..85b3d583cf 100755
--- a/drivers/builtin_openssl/crypto/install-crypto.com
+++ b/drivers/builtin_openssl2/crypto/install-crypto.com
diff --git a/drivers/builtin_openssl/crypto/jpake/jpake.c b/drivers/builtin_openssl2/crypto/jpake/jpake.c
index 8e4b633ccc..8e4b633ccc 100644
--- a/drivers/builtin_openssl/crypto/jpake/jpake.c
+++ b/drivers/builtin_openssl2/crypto/jpake/jpake.c
diff --git a/drivers/builtin_openssl/crypto/jpake/jpake.h b/drivers/builtin_openssl2/crypto/jpake/jpake.h
index fd143b4d9b..fd143b4d9b 100644
--- a/drivers/builtin_openssl/crypto/jpake/jpake.h
+++ b/drivers/builtin_openssl2/crypto/jpake/jpake.h
diff --git a/drivers/builtin_openssl/crypto/jpake/jpake_err.c b/drivers/builtin_openssl2/crypto/jpake/jpake_err.c
index a9a9dee75c..a9a9dee75c 100644
--- a/drivers/builtin_openssl/crypto/jpake/jpake_err.c
+++ b/drivers/builtin_openssl2/crypto/jpake/jpake_err.c
diff --git a/drivers/builtin_openssl/crypto/jpake/jpaketest.c b/drivers/builtin_openssl2/crypto/jpake/jpaketest.c
index eaba75ed8a..eaba75ed8a 100644
--- a/drivers/builtin_openssl/crypto/jpake/jpaketest.c
+++ b/drivers/builtin_openssl2/crypto/jpake/jpaketest.c
diff --git a/drivers/builtin_openssl/crypto/krb5/krb5_asn.c b/drivers/builtin_openssl2/crypto/krb5/krb5_asn.c
index 1fb741d2a0..1fb741d2a0 100644
--- a/drivers/builtin_openssl/crypto/krb5/krb5_asn.c
+++ b/drivers/builtin_openssl2/crypto/krb5/krb5_asn.c
diff --git a/drivers/builtin_openssl/crypto/lhash/lh_stats.c b/drivers/builtin_openssl2/crypto/lhash/lh_stats.c
index 815615e338..815615e338 100644
--- a/drivers/builtin_openssl/crypto/lhash/lh_stats.c
+++ b/drivers/builtin_openssl2/crypto/lhash/lh_stats.c
diff --git a/drivers/builtin_openssl/crypto/lhash/lh_test.c b/drivers/builtin_openssl2/crypto/lhash/lh_test.c
index 85700c859b..85700c859b 100644
--- a/drivers/builtin_openssl/crypto/lhash/lh_test.c
+++ b/drivers/builtin_openssl2/crypto/lhash/lh_test.c
diff --git a/drivers/builtin_openssl/crypto/lhash/lhash.c b/drivers/builtin_openssl2/crypto/lhash/lhash.c
index 47f748081b..47f748081b 100644
--- a/drivers/builtin_openssl/crypto/lhash/lhash.c
+++ b/drivers/builtin_openssl2/crypto/lhash/lhash.c
diff --git a/drivers/builtin_openssl/crypto/lhash/num.pl b/drivers/builtin_openssl2/crypto/lhash/num.pl
index 30fedf9cd5..30fedf9cd5 100644
--- a/drivers/builtin_openssl/crypto/lhash/num.pl
+++ b/drivers/builtin_openssl2/crypto/lhash/num.pl
diff --git a/drivers/builtin_openssl/crypto/md2/md2.c b/drivers/builtin_openssl2/crypto/md2/md2.c
index f4d6f62264..f4d6f62264 100644
--- a/drivers/builtin_openssl/crypto/md2/md2.c
+++ b/drivers/builtin_openssl2/crypto/md2/md2.c
diff --git a/drivers/builtin_openssl/crypto/md2/md2.h b/drivers/builtin_openssl2/crypto/md2/md2.h
index d59c9f2593..d59c9f2593 100644
--- a/drivers/builtin_openssl/crypto/md2/md2.h
+++ b/drivers/builtin_openssl2/crypto/md2/md2.h
diff --git a/drivers/builtin_openssl/crypto/md2/md2_dgst.c b/drivers/builtin_openssl2/crypto/md2/md2_dgst.c
index bf89def73e..bf89def73e 100644
--- a/drivers/builtin_openssl/crypto/md2/md2_dgst.c
+++ b/drivers/builtin_openssl2/crypto/md2/md2_dgst.c
diff --git a/drivers/builtin_openssl/crypto/md2/md2_one.c b/drivers/builtin_openssl2/crypto/md2/md2_one.c
index f7fef5cc0a..f7fef5cc0a 100644
--- a/drivers/builtin_openssl/crypto/md2/md2_one.c
+++ b/drivers/builtin_openssl2/crypto/md2/md2_one.c
diff --git a/drivers/builtin_openssl/crypto/md2/md2test.c b/drivers/builtin_openssl2/crypto/md2/md2test.c
index db5f5bc6d2..db5f5bc6d2 100644
--- a/drivers/builtin_openssl/crypto/md2/md2test.c
+++ b/drivers/builtin_openssl2/crypto/md2/md2test.c
diff --git a/drivers/builtin_openssl/crypto/md32_common.h b/drivers/builtin_openssl2/crypto/md32_common.h
index bb7381952a..bb7381952a 100644
--- a/drivers/builtin_openssl/crypto/md32_common.h
+++ b/drivers/builtin_openssl2/crypto/md32_common.h
diff --git a/drivers/builtin_openssl/crypto/md4/md4.c b/drivers/builtin_openssl2/crypto/md4/md4.c
index 141415ad4d..141415ad4d 100644
--- a/drivers/builtin_openssl/crypto/md4/md4.c
+++ b/drivers/builtin_openssl2/crypto/md4/md4.c
diff --git a/drivers/builtin_openssl/crypto/md4/md4_dgst.c b/drivers/builtin_openssl2/crypto/md4/md4_dgst.c
index b5b165b052..b5b165b052 100644
--- a/drivers/builtin_openssl/crypto/md4/md4_dgst.c
+++ b/drivers/builtin_openssl2/crypto/md4/md4_dgst.c
diff --git a/drivers/builtin_openssl/crypto/md4/md4_locl.h b/drivers/builtin_openssl2/crypto/md4/md4_locl.h
index 99c3e5004c..99c3e5004c 100644
--- a/drivers/builtin_openssl/crypto/md4/md4_locl.h
+++ b/drivers/builtin_openssl2/crypto/md4/md4_locl.h
diff --git a/drivers/builtin_openssl/crypto/md4/md4_one.c b/drivers/builtin_openssl2/crypto/md4/md4_one.c
index bb64362638..bb64362638 100644
--- a/drivers/builtin_openssl/crypto/md4/md4_one.c
+++ b/drivers/builtin_openssl2/crypto/md4/md4_one.c
diff --git a/drivers/builtin_openssl/crypto/md4/md4s.cpp b/drivers/builtin_openssl2/crypto/md4/md4s.cpp
index c0ec97fc9f..c0ec97fc9f 100644
--- a/drivers/builtin_openssl/crypto/md4/md4s.cpp
+++ b/drivers/builtin_openssl2/crypto/md4/md4s.cpp
diff --git a/drivers/builtin_openssl/crypto/md4/md4test.c b/drivers/builtin_openssl2/crypto/md4/md4test.c
index 56591728a1..56591728a1 100644
--- a/drivers/builtin_openssl/crypto/md4/md4test.c
+++ b/drivers/builtin_openssl2/crypto/md4/md4test.c
diff --git a/drivers/builtin_openssl/crypto/md5/asm/md5-586.pl b/drivers/builtin_openssl2/crypto/md5/asm/md5-586.pl
index 6cb66bb499..6cb66bb499 100644
--- a/drivers/builtin_openssl/crypto/md5/asm/md5-586.pl
+++ b/drivers/builtin_openssl2/crypto/md5/asm/md5-586.pl
diff --git a/drivers/builtin_openssl/crypto/md5/asm/md5-ia64.S b/drivers/builtin_openssl2/crypto/md5/asm/md5-ia64.S
index e7de08d46a..e7de08d46a 100644
--- a/drivers/builtin_openssl/crypto/md5/asm/md5-ia64.S
+++ b/drivers/builtin_openssl2/crypto/md5/asm/md5-ia64.S
diff --git a/drivers/builtin_openssl/crypto/md5/asm/md5-x86_64.pl b/drivers/builtin_openssl2/crypto/md5/asm/md5-x86_64.pl
index f11224d172..f11224d172 100755
--- a/drivers/builtin_openssl/crypto/md5/asm/md5-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/md5/asm/md5-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/md5/md5.c b/drivers/builtin_openssl2/crypto/md5/md5.c
index 563733abc5..563733abc5 100644
--- a/drivers/builtin_openssl/crypto/md5/md5.c
+++ b/drivers/builtin_openssl2/crypto/md5/md5.c
diff --git a/drivers/builtin_openssl/crypto/md5/md5_dgst.c b/drivers/builtin_openssl2/crypto/md5/md5_dgst.c
index 265890de52..265890de52 100644
--- a/drivers/builtin_openssl/crypto/md5/md5_dgst.c
+++ b/drivers/builtin_openssl2/crypto/md5/md5_dgst.c
diff --git a/drivers/builtin_openssl2/crypto/md5/md5_locl.h b/drivers/builtin_openssl2/crypto/md5/md5_locl.h
new file mode 100644
index 0000000000..74d63d1f9c
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/md5/md5_locl.h
@@ -0,0 +1,130 @@
+/* crypto/md5/md5_locl.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/e_os2.h>
+#include <openssl/md5.h>
+
+#ifndef MD5_LONG_LOG2
+#define MD5_LONG_LOG2 2 /* default to 32 bits */
+#endif
+
+#ifdef MD5_ASM
+# if defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(__INTEL__) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
+# define md5_block_data_order md5_block_asm_data_order
+# elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+# define md5_block_data_order md5_block_asm_data_order
+# endif
+#endif
+
+void md5_block_data_order (MD5_CTX *c, const void *p,size_t num);
+
+#define DATA_ORDER_IS_LITTLE_ENDIAN
+
+#define HASH_LONG MD5_LONG
+#define HASH_CTX MD5_CTX
+#define HASH_CBLOCK MD5_CBLOCK
+#define HASH_UPDATE MD5_Update
+#define HASH_TRANSFORM MD5_Transform
+#define HASH_FINAL MD5_Final
+#define HASH_MAKE_STRING(c,s) do { \
+ unsigned long ll; \
+ ll=(c)->A; (void)HOST_l2c(ll,(s)); \
+ ll=(c)->B; (void)HOST_l2c(ll,(s)); \
+ ll=(c)->C; (void)HOST_l2c(ll,(s)); \
+ ll=(c)->D; (void)HOST_l2c(ll,(s)); \
+ } while (0)
+#define HASH_BLOCK_DATA_ORDER md5_block_data_order
+
+#include "md32_common.h"
+
+/*
+#define F(x,y,z) (((x) & (y)) | ((~(x)) & (z)))
+#define G(x,y,z) (((x) & (z)) | ((y) & (~(z))))
+*/
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
+ * simplified to the code below. Wei attributes these optimizations
+ * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
+ */
+#define F(b,c,d) ((((c) ^ (d)) & (b)) ^ (d))
+#define G(b,c,d) ((((b) ^ (c)) & (d)) ^ (c))
+#define H(b,c,d) ((b) ^ (c) ^ (d))
+#define I(b,c,d) (((~(d)) | (b)) ^ (c))
+
+#define R0(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+F((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };\
+
+#define R1(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+G((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#define R2(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+H((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#define R3(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+I((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
diff --git a/drivers/builtin_openssl/crypto/md5/md5_one.c b/drivers/builtin_openssl2/crypto/md5/md5_one.c
index 43fee89379..43fee89379 100644
--- a/drivers/builtin_openssl/crypto/md5/md5_one.c
+++ b/drivers/builtin_openssl2/crypto/md5/md5_one.c
diff --git a/drivers/builtin_openssl/crypto/md5/md5s.cpp b/drivers/builtin_openssl2/crypto/md5/md5s.cpp
index dd343fd4e6..dd343fd4e6 100644
--- a/drivers/builtin_openssl/crypto/md5/md5s.cpp
+++ b/drivers/builtin_openssl2/crypto/md5/md5s.cpp
diff --git a/drivers/builtin_openssl/crypto/md5/md5test.c b/drivers/builtin_openssl2/crypto/md5/md5test.c
index 2b37190e32..2b37190e32 100644
--- a/drivers/builtin_openssl/crypto/md5/md5test.c
+++ b/drivers/builtin_openssl2/crypto/md5/md5test.c
diff --git a/drivers/builtin_openssl/crypto/mdc2/mdc2_one.c b/drivers/builtin_openssl2/crypto/mdc2/mdc2_one.c
index 72647f67ed..72647f67ed 100644
--- a/drivers/builtin_openssl/crypto/mdc2/mdc2_one.c
+++ b/drivers/builtin_openssl2/crypto/mdc2/mdc2_one.c
diff --git a/drivers/builtin_openssl/crypto/mdc2/mdc2dgst.c b/drivers/builtin_openssl2/crypto/mdc2/mdc2dgst.c
index d66ed6a1c6..d66ed6a1c6 100644
--- a/drivers/builtin_openssl/crypto/mdc2/mdc2dgst.c
+++ b/drivers/builtin_openssl2/crypto/mdc2/mdc2dgst.c
diff --git a/drivers/builtin_openssl/crypto/mdc2/mdc2test.c b/drivers/builtin_openssl2/crypto/mdc2/mdc2test.c
index 017b31add2..017b31add2 100644
--- a/drivers/builtin_openssl/crypto/mdc2/mdc2test.c
+++ b/drivers/builtin_openssl2/crypto/mdc2/mdc2test.c
diff --git a/drivers/builtin_openssl/crypto/mem.c b/drivers/builtin_openssl2/crypto/mem.c
index 1cc62eafd1..1cc62eafd1 100644
--- a/drivers/builtin_openssl/crypto/mem.c
+++ b/drivers/builtin_openssl2/crypto/mem.c
diff --git a/drivers/builtin_openssl/crypto/mem_clr.c b/drivers/builtin_openssl2/crypto/mem_clr.c
index add1f78020..add1f78020 100644
--- a/drivers/builtin_openssl/crypto/mem_clr.c
+++ b/drivers/builtin_openssl2/crypto/mem_clr.c
diff --git a/drivers/builtin_openssl/crypto/mem_dbg.c b/drivers/builtin_openssl2/crypto/mem_dbg.c
index ac793397f1..ac793397f1 100644
--- a/drivers/builtin_openssl/crypto/mem_dbg.c
+++ b/drivers/builtin_openssl2/crypto/mem_dbg.c
diff --git a/drivers/builtin_openssl/crypto/modes/asm/ghash-alpha.pl b/drivers/builtin_openssl2/crypto/modes/asm/ghash-alpha.pl
index aa36029386..aa36029386 100644
--- a/drivers/builtin_openssl/crypto/modes/asm/ghash-alpha.pl
+++ b/drivers/builtin_openssl2/crypto/modes/asm/ghash-alpha.pl
diff --git a/drivers/builtin_openssl/crypto/modes/asm/ghash-armv4.pl b/drivers/builtin_openssl2/crypto/modes/asm/ghash-armv4.pl
index d91586ee29..d91586ee29 100644
--- a/drivers/builtin_openssl/crypto/modes/asm/ghash-armv4.pl
+++ b/drivers/builtin_openssl2/crypto/modes/asm/ghash-armv4.pl
diff --git a/drivers/builtin_openssl/crypto/modes/asm/ghash-ia64.pl b/drivers/builtin_openssl2/crypto/modes/asm/ghash-ia64.pl
index 0354c95444..0354c95444 100755
--- a/drivers/builtin_openssl/crypto/modes/asm/ghash-ia64.pl
+++ b/drivers/builtin_openssl2/crypto/modes/asm/ghash-ia64.pl
diff --git a/drivers/builtin_openssl/crypto/modes/asm/ghash-parisc.pl b/drivers/builtin_openssl2/crypto/modes/asm/ghash-parisc.pl
index d5ad96b403..d5ad96b403 100644
--- a/drivers/builtin_openssl/crypto/modes/asm/ghash-parisc.pl
+++ b/drivers/builtin_openssl2/crypto/modes/asm/ghash-parisc.pl
diff --git a/drivers/builtin_openssl/crypto/modes/asm/ghash-s390x.pl b/drivers/builtin_openssl2/crypto/modes/asm/ghash-s390x.pl
index 6a40d5d89c..6a40d5d89c 100644
--- a/drivers/builtin_openssl/crypto/modes/asm/ghash-s390x.pl
+++ b/drivers/builtin_openssl2/crypto/modes/asm/ghash-s390x.pl
diff --git a/drivers/builtin_openssl/crypto/modes/asm/ghash-sparcv9.pl b/drivers/builtin_openssl2/crypto/modes/asm/ghash-sparcv9.pl
index 70e7b044a3..70e7b044a3 100644
--- a/drivers/builtin_openssl/crypto/modes/asm/ghash-sparcv9.pl
+++ b/drivers/builtin_openssl2/crypto/modes/asm/ghash-sparcv9.pl
diff --git a/drivers/builtin_openssl/crypto/modes/asm/ghash-x86.pl b/drivers/builtin_openssl2/crypto/modes/asm/ghash-x86.pl
index 83c727e07f..83c727e07f 100644
--- a/drivers/builtin_openssl/crypto/modes/asm/ghash-x86.pl
+++ b/drivers/builtin_openssl2/crypto/modes/asm/ghash-x86.pl
diff --git a/drivers/builtin_openssl/crypto/modes/asm/ghash-x86_64.pl b/drivers/builtin_openssl2/crypto/modes/asm/ghash-x86_64.pl
index 38d779edbc..38d779edbc 100644
--- a/drivers/builtin_openssl/crypto/modes/asm/ghash-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/modes/asm/ghash-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/modes/cbc128.c b/drivers/builtin_openssl2/crypto/modes/cbc128.c
index 0e54f75470..0e54f75470 100644
--- a/drivers/builtin_openssl/crypto/modes/cbc128.c
+++ b/drivers/builtin_openssl2/crypto/modes/cbc128.c
diff --git a/drivers/builtin_openssl/crypto/modes/ccm128.c b/drivers/builtin_openssl2/crypto/modes/ccm128.c
index 3ce11d0d98..3ce11d0d98 100644
--- a/drivers/builtin_openssl/crypto/modes/ccm128.c
+++ b/drivers/builtin_openssl2/crypto/modes/ccm128.c
diff --git a/drivers/builtin_openssl/crypto/modes/cfb128.c b/drivers/builtin_openssl2/crypto/modes/cfb128.c
index 4e6f5d35e1..4e6f5d35e1 100644
--- a/drivers/builtin_openssl/crypto/modes/cfb128.c
+++ b/drivers/builtin_openssl2/crypto/modes/cfb128.c
diff --git a/drivers/builtin_openssl/crypto/modes/ctr128.c b/drivers/builtin_openssl2/crypto/modes/ctr128.c
index ee642c5863..ee642c5863 100644
--- a/drivers/builtin_openssl/crypto/modes/ctr128.c
+++ b/drivers/builtin_openssl2/crypto/modes/ctr128.c
diff --git a/drivers/builtin_openssl/crypto/modes/cts128.c b/drivers/builtin_openssl2/crypto/modes/cts128.c
index 2d583de6f6..2d583de6f6 100644
--- a/drivers/builtin_openssl/crypto/modes/cts128.c
+++ b/drivers/builtin_openssl2/crypto/modes/cts128.c
diff --git a/drivers/builtin_openssl/crypto/modes/gcm128.c b/drivers/builtin_openssl2/crypto/modes/gcm128.c
index e1dc2b0f47..e1dc2b0f47 100644
--- a/drivers/builtin_openssl/crypto/modes/gcm128.c
+++ b/drivers/builtin_openssl2/crypto/modes/gcm128.c
diff --git a/drivers/builtin_openssl/crypto/modes/modes_lcl.h b/drivers/builtin_openssl2/crypto/modes/modes_lcl.h
index 9d83e12844..9d83e12844 100644
--- a/drivers/builtin_openssl/crypto/modes/modes_lcl.h
+++ b/drivers/builtin_openssl2/crypto/modes/modes_lcl.h
diff --git a/drivers/builtin_openssl/crypto/modes/ofb128.c b/drivers/builtin_openssl2/crypto/modes/ofb128.c
index 01c01702c4..01c01702c4 100644
--- a/drivers/builtin_openssl/crypto/modes/ofb128.c
+++ b/drivers/builtin_openssl2/crypto/modes/ofb128.c
diff --git a/drivers/builtin_openssl/crypto/modes/xts128.c b/drivers/builtin_openssl2/crypto/modes/xts128.c
index 9cf27a25e9..9cf27a25e9 100644
--- a/drivers/builtin_openssl/crypto/modes/xts128.c
+++ b/drivers/builtin_openssl2/crypto/modes/xts128.c
diff --git a/drivers/builtin_openssl/crypto/o_dir.c b/drivers/builtin_openssl2/crypto/o_dir.c
index 42891ea459..42891ea459 100644
--- a/drivers/builtin_openssl/crypto/o_dir.c
+++ b/drivers/builtin_openssl2/crypto/o_dir.c
diff --git a/drivers/builtin_openssl/crypto/o_dir.h b/drivers/builtin_openssl2/crypto/o_dir.h
index 4b725c0312..4b725c0312 100644
--- a/drivers/builtin_openssl/crypto/o_dir.h
+++ b/drivers/builtin_openssl2/crypto/o_dir.h
diff --git a/drivers/builtin_openssl/crypto/o_dir_test.c b/drivers/builtin_openssl2/crypto/o_dir_test.c
index 3d75ecb005..3d75ecb005 100644
--- a/drivers/builtin_openssl/crypto/o_dir_test.c
+++ b/drivers/builtin_openssl2/crypto/o_dir_test.c
diff --git a/drivers/builtin_openssl/crypto/o_fips.c b/drivers/builtin_openssl2/crypto/o_fips.c
index f6d1b21855..f6d1b21855 100644
--- a/drivers/builtin_openssl/crypto/o_fips.c
+++ b/drivers/builtin_openssl2/crypto/o_fips.c
diff --git a/drivers/builtin_openssl/crypto/o_init.c b/drivers/builtin_openssl2/crypto/o_init.c
index db4cdc443b..db4cdc443b 100644
--- a/drivers/builtin_openssl/crypto/o_init.c
+++ b/drivers/builtin_openssl2/crypto/o_init.c
diff --git a/drivers/builtin_openssl2/crypto/o_str.c b/drivers/builtin_openssl2/crypto/o_str.c
new file mode 100644
index 0000000000..d233afd46b
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/o_str.c
@@ -0,0 +1,115 @@
+/* crypto/o_str.c -*- mode:C; c-file-style: "eay" -*- */
+/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
+ * project 2003.
+ */
+/* ====================================================================
+ * Copyright (c) 2003 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <ctype.h>
+#include <e_os.h>
+#include "o_str.h"
+
+#if !defined(OPENSSL_IMPLEMENTS_strncasecmp) && \
+ !defined(OPENSSL_SYSNAME_WIN32) && \
+ !defined(NETWARE_CLIB)
+#ifdef _WIN32
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#endif
+
+int OPENSSL_strncasecmp(const char *str1, const char *str2, size_t n)
+ {
+#if defined(OPENSSL_IMPLEMENTS_strncasecmp)
+ while (*str1 && *str2 && n)
+ {
+ int res = toupper(*str1) - toupper(*str2);
+ if (res) return res < 0 ? -1 : 1;
+ str1++;
+ str2++;
+ n--;
+ }
+ if (n == 0)
+ return 0;
+ if (*str1)
+ return 1;
+ if (*str2)
+ return -1;
+ return 0;
+#else
+ /* Recursion hazard warning! Whenever strncasecmp is #defined as
+ * OPENSSL_strncasecmp, OPENSSL_IMPLEMENTS_strncasecmp must be
+ * defined as well. */
+ return strncasecmp(str1, str2, n);
+#endif
+ }
+int OPENSSL_strcasecmp(const char *str1, const char *str2)
+ {
+#if defined(OPENSSL_IMPLEMENTS_strncasecmp)
+ return OPENSSL_strncasecmp(str1, str2, (size_t)-1);
+#else
+ return strcasecmp(str1, str2);
+#endif
+ }
+
+int OPENSSL_memcmp(const void *v1,const void *v2,size_t n)
+ {
+ const unsigned char *c1=v1,*c2=v2;
+ int ret=0;
+
+ while(n && (ret=*c1-*c2)==0) n--,c1++,c2++;
+
+ return ret;
+ }
diff --git a/drivers/builtin_openssl/crypto/o_str.h b/drivers/builtin_openssl2/crypto/o_str.h
index dfc98494c6..dfc98494c6 100644
--- a/drivers/builtin_openssl/crypto/o_str.h
+++ b/drivers/builtin_openssl2/crypto/o_str.h
diff --git a/drivers/builtin_openssl/crypto/o_time.c b/drivers/builtin_openssl2/crypto/o_time.c
index 9030fdef7a..9030fdef7a 100644
--- a/drivers/builtin_openssl/crypto/o_time.c
+++ b/drivers/builtin_openssl2/crypto/o_time.c
diff --git a/drivers/builtin_openssl/crypto/o_time.h b/drivers/builtin_openssl2/crypto/o_time.h
index e391da7508..e391da7508 100644
--- a/drivers/builtin_openssl/crypto/o_time.h
+++ b/drivers/builtin_openssl2/crypto/o_time.h
diff --git a/drivers/builtin_openssl/crypto/objects/o_names.c b/drivers/builtin_openssl2/crypto/objects/o_names.c
index 4a548c2ed4..4a548c2ed4 100644
--- a/drivers/builtin_openssl/crypto/objects/o_names.c
+++ b/drivers/builtin_openssl2/crypto/objects/o_names.c
diff --git a/drivers/builtin_openssl/crypto/objects/obj_dat.c b/drivers/builtin_openssl2/crypto/objects/obj_dat.c
index 8a342ba3eb..8a342ba3eb 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_dat.c
+++ b/drivers/builtin_openssl2/crypto/objects/obj_dat.c
diff --git a/drivers/builtin_openssl/crypto/objects/obj_dat.h b/drivers/builtin_openssl2/crypto/objects/obj_dat.h
index d404ad07c9..d404ad07c9 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_dat.h
+++ b/drivers/builtin_openssl2/crypto/objects/obj_dat.h
diff --git a/drivers/builtin_openssl/crypto/objects/obj_dat.pl b/drivers/builtin_openssl2/crypto/objects/obj_dat.pl
index c67f71c327..c67f71c327 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_dat.pl
+++ b/drivers/builtin_openssl2/crypto/objects/obj_dat.pl
diff --git a/drivers/builtin_openssl/crypto/objects/obj_err.c b/drivers/builtin_openssl2/crypto/objects/obj_err.c
index 2e7a034c3f..2e7a034c3f 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_err.c
+++ b/drivers/builtin_openssl2/crypto/objects/obj_err.c
diff --git a/drivers/builtin_openssl/crypto/objects/obj_lib.c b/drivers/builtin_openssl2/crypto/objects/obj_lib.c
index 23e9d48cdf..23e9d48cdf 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_lib.c
+++ b/drivers/builtin_openssl2/crypto/objects/obj_lib.c
diff --git a/drivers/builtin_openssl/crypto/objects/obj_mac.num b/drivers/builtin_openssl2/crypto/objects/obj_mac.num
index 1d0a7c802d..1d0a7c802d 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_mac.num
+++ b/drivers/builtin_openssl2/crypto/objects/obj_mac.num
diff --git a/drivers/builtin_openssl/crypto/objects/obj_xref.c b/drivers/builtin_openssl2/crypto/objects/obj_xref.c
index 9f744bcede..9f744bcede 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_xref.c
+++ b/drivers/builtin_openssl2/crypto/objects/obj_xref.c
diff --git a/drivers/builtin_openssl/crypto/objects/obj_xref.h b/drivers/builtin_openssl2/crypto/objects/obj_xref.h
index e23938c296..e23938c296 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_xref.h
+++ b/drivers/builtin_openssl2/crypto/objects/obj_xref.h
diff --git a/drivers/builtin_openssl/crypto/objects/obj_xref.txt b/drivers/builtin_openssl2/crypto/objects/obj_xref.txt
index cb917182ee..cb917182ee 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_xref.txt
+++ b/drivers/builtin_openssl2/crypto/objects/obj_xref.txt
diff --git a/drivers/builtin_openssl/crypto/objects/objects.README b/drivers/builtin_openssl2/crypto/objects/objects.README
index 4d745508d8..4d745508d8 100644
--- a/drivers/builtin_openssl/crypto/objects/objects.README
+++ b/drivers/builtin_openssl2/crypto/objects/objects.README
diff --git a/drivers/builtin_openssl/crypto/objects/objects.pl b/drivers/builtin_openssl2/crypto/objects/objects.pl
index 15c00bbd52..15c00bbd52 100644
--- a/drivers/builtin_openssl/crypto/objects/objects.pl
+++ b/drivers/builtin_openssl2/crypto/objects/objects.pl
diff --git a/drivers/builtin_openssl/crypto/objects/objects.txt b/drivers/builtin_openssl2/crypto/objects/objects.txt
index d3bfad72a2..d3bfad72a2 100644
--- a/drivers/builtin_openssl/crypto/objects/objects.txt
+++ b/drivers/builtin_openssl2/crypto/objects/objects.txt
diff --git a/drivers/builtin_openssl/crypto/objects/objxref.pl b/drivers/builtin_openssl2/crypto/objects/objxref.pl
index 731d3ae22c..731d3ae22c 100644
--- a/drivers/builtin_openssl/crypto/objects/objxref.pl
+++ b/drivers/builtin_openssl2/crypto/objects/objxref.pl
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_asn.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_asn.c
index bfe892ac70..bfe892ac70 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_asn.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_asn.c
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_cl.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_cl.c
index 9c14d9da27..9c14d9da27 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_cl.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_cl.c
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_err.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_err.c
index 0cedcea682..0cedcea682 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_err.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_err.c
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_ext.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_ext.c
index ec884cb08f..ec884cb08f 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_ext.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_ext.c
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_ht.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_ht.c
index af5fc16691..af5fc16691 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_ht.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_ht.c
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_lib.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_lib.c
index a94dc838ee..a94dc838ee 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_lib.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_lib.c
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_prn.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_prn.c
index 87608ff399..87608ff399 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_prn.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_prn.c
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_srv.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_srv.c
index 1c606dd0b6..1c606dd0b6 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_srv.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_srv.c
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp_vfy.c b/drivers/builtin_openssl2/crypto/ocsp/ocsp_vfy.c
index 276718304d..276718304d 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp_vfy.c
+++ b/drivers/builtin_openssl2/crypto/ocsp/ocsp_vfy.c
diff --git a/drivers/builtin_openssl/crypto/opensslconf.h.bak b/drivers/builtin_openssl2/crypto/opensslconf.h.bak
index b18f4da496..b18f4da496 100644
--- a/drivers/builtin_openssl/crypto/opensslconf.h.bak
+++ b/drivers/builtin_openssl2/crypto/opensslconf.h.bak
diff --git a/drivers/builtin_openssl/crypto/opensslconf.h.in b/drivers/builtin_openssl2/crypto/opensslconf.h.in
index 97e3745563..97e3745563 100644
--- a/drivers/builtin_openssl/crypto/opensslconf.h.in
+++ b/drivers/builtin_openssl2/crypto/opensslconf.h.in
diff --git a/drivers/builtin_openssl/crypto/pariscid.pl b/drivers/builtin_openssl2/crypto/pariscid.pl
index bfc56fdc7f..bfc56fdc7f 100644
--- a/drivers/builtin_openssl/crypto/pariscid.pl
+++ b/drivers/builtin_openssl2/crypto/pariscid.pl
diff --git a/drivers/builtin_openssl/crypto/pem/message b/drivers/builtin_openssl2/crypto/pem/message
index e8bf9d7592..e8bf9d7592 100644
--- a/drivers/builtin_openssl/crypto/pem/message
+++ b/drivers/builtin_openssl2/crypto/pem/message
diff --git a/drivers/builtin_openssl/crypto/pem/pem_all.c b/drivers/builtin_openssl2/crypto/pem/pem_all.c
index eac0460e3e..eac0460e3e 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_all.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_all.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_err.c b/drivers/builtin_openssl2/crypto/pem/pem_err.c
index d644aeedd4..d644aeedd4 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_err.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_err.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_info.c b/drivers/builtin_openssl2/crypto/pem/pem_info.c
index cc7f24a9c1..cc7f24a9c1 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_info.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_info.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_lib.c b/drivers/builtin_openssl2/crypto/pem/pem_lib.c
index 5a421fc4b6..5a421fc4b6 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_lib.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_lib.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_oth.c b/drivers/builtin_openssl2/crypto/pem/pem_oth.c
index b33868d25a..b33868d25a 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_oth.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_oth.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_pk8.c b/drivers/builtin_openssl2/crypto/pem/pem_pk8.c
index 6deab8c338..6deab8c338 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_pk8.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_pk8.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_pkey.c b/drivers/builtin_openssl2/crypto/pem/pem_pkey.c
index 8ecf24903b..8ecf24903b 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_pkey.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_pkey.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_seal.c b/drivers/builtin_openssl2/crypto/pem/pem_seal.c
index b6b4e13498..b6b4e13498 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_seal.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_seal.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_sign.c b/drivers/builtin_openssl2/crypto/pem/pem_sign.c
index c3b9808cb2..c3b9808cb2 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_sign.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_sign.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_x509.c b/drivers/builtin_openssl2/crypto/pem/pem_x509.c
index b531057dc9..b531057dc9 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_x509.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_x509.c
diff --git a/drivers/builtin_openssl/crypto/pem/pem_xaux.c b/drivers/builtin_openssl2/crypto/pem/pem_xaux.c
index 328f796200..328f796200 100644
--- a/drivers/builtin_openssl/crypto/pem/pem_xaux.c
+++ b/drivers/builtin_openssl2/crypto/pem/pem_xaux.c
diff --git a/drivers/builtin_openssl/crypto/pem/pkcs7.lis b/drivers/builtin_openssl2/crypto/pem/pkcs7.lis
index be90c5d87f..be90c5d87f 100644
--- a/drivers/builtin_openssl/crypto/pem/pkcs7.lis
+++ b/drivers/builtin_openssl2/crypto/pem/pkcs7.lis
diff --git a/drivers/builtin_openssl/crypto/pem/pvkfmt.c b/drivers/builtin_openssl2/crypto/pem/pvkfmt.c
index b1bf71a5da..b1bf71a5da 100644
--- a/drivers/builtin_openssl/crypto/pem/pvkfmt.c
+++ b/drivers/builtin_openssl2/crypto/pem/pvkfmt.c
diff --git a/drivers/builtin_openssl/crypto/perlasm/cbc.pl b/drivers/builtin_openssl2/crypto/perlasm/cbc.pl
index 24561e759a..24561e759a 100644
--- a/drivers/builtin_openssl/crypto/perlasm/cbc.pl
+++ b/drivers/builtin_openssl2/crypto/perlasm/cbc.pl
diff --git a/drivers/builtin_openssl/crypto/perlasm/ppc-xlate.pl b/drivers/builtin_openssl2/crypto/perlasm/ppc-xlate.pl
index a3edd982b6..a3edd982b6 100755
--- a/drivers/builtin_openssl/crypto/perlasm/ppc-xlate.pl
+++ b/drivers/builtin_openssl2/crypto/perlasm/ppc-xlate.pl
diff --git a/drivers/builtin_openssl/crypto/perlasm/readme b/drivers/builtin_openssl2/crypto/perlasm/readme
index f02bbee75a..f02bbee75a 100644
--- a/drivers/builtin_openssl/crypto/perlasm/readme
+++ b/drivers/builtin_openssl2/crypto/perlasm/readme
diff --git a/drivers/builtin_openssl/crypto/perlasm/x86_64-xlate.pl b/drivers/builtin_openssl2/crypto/perlasm/x86_64-xlate.pl
index 56d9b64b6f..56d9b64b6f 100755
--- a/drivers/builtin_openssl/crypto/perlasm/x86_64-xlate.pl
+++ b/drivers/builtin_openssl2/crypto/perlasm/x86_64-xlate.pl
diff --git a/drivers/builtin_openssl/crypto/perlasm/x86asm.pl b/drivers/builtin_openssl2/crypto/perlasm/x86asm.pl
index eb543db2f6..eb543db2f6 100644
--- a/drivers/builtin_openssl/crypto/perlasm/x86asm.pl
+++ b/drivers/builtin_openssl2/crypto/perlasm/x86asm.pl
diff --git a/drivers/builtin_openssl/crypto/perlasm/x86gas.pl b/drivers/builtin_openssl2/crypto/perlasm/x86gas.pl
index 682a3a3163..682a3a3163 100644
--- a/drivers/builtin_openssl/crypto/perlasm/x86gas.pl
+++ b/drivers/builtin_openssl2/crypto/perlasm/x86gas.pl
diff --git a/drivers/builtin_openssl/crypto/perlasm/x86masm.pl b/drivers/builtin_openssl2/crypto/perlasm/x86masm.pl
index f937d07c87..f937d07c87 100644
--- a/drivers/builtin_openssl/crypto/perlasm/x86masm.pl
+++ b/drivers/builtin_openssl2/crypto/perlasm/x86masm.pl
diff --git a/drivers/builtin_openssl/crypto/perlasm/x86nasm.pl b/drivers/builtin_openssl2/crypto/perlasm/x86nasm.pl
index ca2511c9eb..ca2511c9eb 100644
--- a/drivers/builtin_openssl/crypto/perlasm/x86nasm.pl
+++ b/drivers/builtin_openssl2/crypto/perlasm/x86nasm.pl
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_add.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_add.c
index 27ac5facfa..27ac5facfa 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_add.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_add.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_asn.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_asn.c
index 6e27633817..6e27633817 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_asn.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_asn.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_attr.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_attr.c
index e4d9c25647..e4d9c25647 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_attr.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_attr.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_crpt.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_crpt.c
index b71d07b4d0..b71d07b4d0 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_crpt.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_crpt.c
diff --git a/drivers/builtin_openssl2/crypto/pkcs12/p12_crt.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_crt.c
new file mode 100644
index 0000000000..35e8a4a8d4
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_crt.c
@@ -0,0 +1,374 @@
+/* p12_crt.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2002 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/pkcs12.h>
+
+
+static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, PKCS12_SAFEBAG *bag);
+
+static int copy_bag_attr(PKCS12_SAFEBAG *bag, EVP_PKEY *pkey, int nid)
+ {
+ int idx;
+ X509_ATTRIBUTE *attr;
+ idx = EVP_PKEY_get_attr_by_NID(pkey, nid, -1);
+ if (idx < 0)
+ return 1;
+ attr = EVP_PKEY_get_attr(pkey, idx);
+ if (!X509at_add1_attr(&bag->attrib, attr))
+ return 0;
+ return 1;
+ }
+
+PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert,
+ STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter, int mac_iter,
+ int keytype)
+{
+ PKCS12 *p12 = NULL;
+ STACK_OF(PKCS7) *safes = NULL;
+ STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
+ PKCS12_SAFEBAG *bag = NULL;
+ int i;
+ unsigned char keyid[EVP_MAX_MD_SIZE];
+ unsigned int keyidlen = 0;
+
+ /* Set defaults */
+ if (!nid_cert)
+ {
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode())
+ nid_cert = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
+ else
+#endif
+#ifdef OPENSSL_NO_RC2
+ nid_cert = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
+#else
+ nid_cert = NID_pbe_WithSHA1And40BitRC2_CBC;
+#endif
+ }
+ if (!nid_key)
+ nid_key = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
+ if (!iter)
+ iter = PKCS12_DEFAULT_ITER;
+ if (!mac_iter)
+ mac_iter = 1;
+
+ if(!pkey && !cert && !ca)
+ {
+ PKCS12err(PKCS12_F_PKCS12_CREATE,PKCS12_R_INVALID_NULL_ARGUMENT);
+ return NULL;
+ }
+
+ if (pkey && cert)
+ {
+ if(!X509_check_private_key(cert, pkey))
+ return NULL;
+ X509_digest(cert, EVP_sha1(), keyid, &keyidlen);
+ }
+
+ if (cert)
+ {
+ bag = PKCS12_add_cert(&bags, cert);
+ if(name && !PKCS12_add_friendlyname(bag, name, -1))
+ goto err;
+ if(keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
+ goto err;
+ }
+
+ /* Add all other certificates */
+ for(i = 0; i < sk_X509_num(ca); i++)
+ {
+ if (!PKCS12_add_cert(&bags, sk_X509_value(ca, i)))
+ goto err;
+ }
+
+ if (bags && !PKCS12_add_safe(&safes, bags, nid_cert, iter, pass))
+ goto err;
+
+ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+ bags = NULL;
+
+ if (pkey)
+ {
+ bag = PKCS12_add_key(&bags, pkey, keytype, iter, nid_key, pass);
+
+ if (!bag)
+ goto err;
+
+ if (!copy_bag_attr(bag, pkey, NID_ms_csp_name))
+ goto err;
+ if (!copy_bag_attr(bag, pkey, NID_LocalKeySet))
+ goto err;
+
+ if(name && !PKCS12_add_friendlyname(bag, name, -1))
+ goto err;
+ if(keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
+ goto err;
+ }
+
+ if (bags && !PKCS12_add_safe(&safes, bags, -1, 0, NULL))
+ goto err;
+
+ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+ bags = NULL;
+
+ p12 = PKCS12_add_safes(safes, 0);
+
+ if (!p12)
+ goto err;
+
+ sk_PKCS7_pop_free(safes, PKCS7_free);
+
+ safes = NULL;
+
+ if ((mac_iter != -1) &&
+ !PKCS12_set_mac(p12, pass, -1, NULL, 0, mac_iter, NULL))
+ goto err;
+
+ return p12;
+
+ err:
+
+ if (p12)
+ PKCS12_free(p12);
+ if (safes)
+ sk_PKCS7_pop_free(safes, PKCS7_free);
+ if (bags)
+ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+ return NULL;
+
+}
+
+PKCS12_SAFEBAG *PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert)
+ {
+ PKCS12_SAFEBAG *bag = NULL;
+ char *name;
+ int namelen = -1;
+ unsigned char *keyid;
+ int keyidlen = -1;
+
+ /* Add user certificate */
+ if(!(bag = PKCS12_x5092certbag(cert)))
+ goto err;
+
+ /* Use friendlyName and localKeyID in certificate.
+ * (if present)
+ */
+
+ name = (char *)X509_alias_get0(cert, &namelen);
+
+ if(name && !PKCS12_add_friendlyname(bag, name, namelen))
+ goto err;
+
+ keyid = X509_keyid_get0(cert, &keyidlen);
+
+ if(keyid && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
+ goto err;
+
+ if (!pkcs12_add_bag(pbags, bag))
+ goto err;
+
+ return bag;
+
+ err:
+
+ if (bag)
+ PKCS12_SAFEBAG_free(bag);
+
+ return NULL;
+
+ }
+
+PKCS12_SAFEBAG *PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags, EVP_PKEY *key,
+ int key_usage, int iter,
+ int nid_key, char *pass)
+ {
+
+ PKCS12_SAFEBAG *bag = NULL;
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
+
+ /* Make a PKCS#8 structure */
+ if(!(p8 = EVP_PKEY2PKCS8(key)))
+ goto err;
+ if(key_usage && !PKCS8_add_keyusage(p8, key_usage))
+ goto err;
+ if (nid_key != -1)
+ {
+ bag = PKCS12_MAKE_SHKEYBAG(nid_key, pass, -1, NULL, 0, iter, p8);
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ }
+ else
+ bag = PKCS12_MAKE_KEYBAG(p8);
+
+ if(!bag)
+ goto err;
+
+ if (!pkcs12_add_bag(pbags, bag))
+ goto err;
+
+ return bag;
+
+ err:
+
+ if (bag)
+ PKCS12_SAFEBAG_free(bag);
+
+ return NULL;
+
+ }
+
+int PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags,
+ int nid_safe, int iter, char *pass)
+ {
+ PKCS7 *p7 = NULL;
+ int free_safes = 0;
+
+ if (!*psafes)
+ {
+ *psafes = sk_PKCS7_new_null();
+ if (!*psafes)
+ return 0;
+ free_safes = 1;
+ }
+ else
+ free_safes = 0;
+
+ if (nid_safe == 0)
+#ifdef OPENSSL_NO_RC2
+ nid_safe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
+#else
+ nid_safe = NID_pbe_WithSHA1And40BitRC2_CBC;
+#endif
+
+ if (nid_safe == -1)
+ p7 = PKCS12_pack_p7data(bags);
+ else
+ p7 = PKCS12_pack_p7encdata(nid_safe, pass, -1, NULL, 0,
+ iter, bags);
+ if (!p7)
+ goto err;
+
+ if (!sk_PKCS7_push(*psafes, p7))
+ goto err;
+
+ return 1;
+
+ err:
+ if (free_safes)
+ {
+ sk_PKCS7_free(*psafes);
+ *psafes = NULL;
+ }
+
+ if (p7)
+ PKCS7_free(p7);
+
+ return 0;
+
+ }
+
+static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, PKCS12_SAFEBAG *bag)
+ {
+ int free_bags;
+ if (!pbags)
+ return 1;
+ if (!*pbags)
+ {
+ *pbags = sk_PKCS12_SAFEBAG_new_null();
+ if (!*pbags)
+ return 0;
+ free_bags = 1;
+ }
+ else
+ free_bags = 0;
+
+ if (!sk_PKCS12_SAFEBAG_push(*pbags, bag))
+ {
+ if (free_bags)
+ {
+ sk_PKCS12_SAFEBAG_free(*pbags);
+ *pbags = NULL;
+ }
+ return 0;
+ }
+
+ return 1;
+
+ }
+
+
+PKCS12 *PKCS12_add_safes(STACK_OF(PKCS7) *safes, int nid_p7)
+ {
+ PKCS12 *p12;
+ if (nid_p7 <= 0)
+ nid_p7 = NID_pkcs7_data;
+ p12 = PKCS12_init(nid_p7);
+
+ if (!p12)
+ return NULL;
+
+ if(!PKCS12_pack_authsafes(p12, safes))
+ {
+ PKCS12_free(p12);
+ return NULL;
+ }
+
+ return p12;
+
+ }
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_decr.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_decr.c
index 9d3557e8d7..9d3557e8d7 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_decr.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_decr.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_init.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_init.c
index d4d84b056a..d4d84b056a 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_init.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_init.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_key.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_key.c
index 61d58502fd..61d58502fd 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_key.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_key.c
diff --git a/drivers/builtin_openssl2/crypto/pkcs12/p12_kiss.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_kiss.c
new file mode 100644
index 0000000000..c9b7ab61d1
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_kiss.c
@@ -0,0 +1,302 @@
+/* p12_kiss.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/pkcs12.h>
+
+/* Simplified PKCS#12 routines */
+
+static int parse_pk12( PKCS12 *p12, const char *pass, int passlen,
+ EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
+
+static int parse_bags( STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass,
+ int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
+
+static int parse_bag( PKCS12_SAFEBAG *bag, const char *pass, int passlen,
+ EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
+
+/* Parse and decrypt a PKCS#12 structure returning user key, user cert
+ * and other (CA) certs. Note either ca should be NULL, *ca should be NULL,
+ * or it should point to a valid STACK structure. pkey and cert can be
+ * passed unitialised.
+ */
+
+int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert,
+ STACK_OF(X509) **ca)
+{
+ STACK_OF(X509) *ocerts = NULL;
+ X509 *x = NULL;
+ /* Check for NULL PKCS12 structure */
+
+ if(!p12)
+ {
+ PKCS12err(PKCS12_F_PKCS12_PARSE,PKCS12_R_INVALID_NULL_PKCS12_POINTER);
+ return 0;
+ }
+
+ if(pkey)
+ *pkey = NULL;
+ if(cert)
+ *cert = NULL;
+
+ /* Check the mac */
+
+ /* If password is zero length or NULL then try verifying both cases
+ * to determine which password is correct. The reason for this is that
+ * under PKCS#12 password based encryption no password and a zero length
+ * password are two different things...
+ */
+
+ if(!pass || !*pass) {
+ if(PKCS12_verify_mac(p12, NULL, 0)) pass = NULL;
+ else if(PKCS12_verify_mac(p12, "", 0)) pass = "";
+ else {
+ PKCS12err(PKCS12_F_PKCS12_PARSE,PKCS12_R_MAC_VERIFY_FAILURE);
+ goto err;
+ }
+ } else if (!PKCS12_verify_mac(p12, pass, -1)) {
+ PKCS12err(PKCS12_F_PKCS12_PARSE,PKCS12_R_MAC_VERIFY_FAILURE);
+ goto err;
+ }
+
+ /* Allocate stack for other certificates */
+ ocerts = sk_X509_new_null();
+
+ if (!ocerts)
+ {
+ PKCS12err(PKCS12_F_PKCS12_PARSE,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (!parse_pk12 (p12, pass, -1, pkey, ocerts))
+ {
+ PKCS12err(PKCS12_F_PKCS12_PARSE,PKCS12_R_PARSE_ERROR);
+ goto err;
+ }
+
+ while ((x = sk_X509_pop(ocerts)))
+ {
+ if (pkey && *pkey && cert && !*cert)
+ {
+ if (X509_check_private_key(x, *pkey))
+ {
+ *cert = x;
+ x = NULL;
+ }
+ }
+
+ if (ca && x)
+ {
+ if (!*ca)
+ *ca = sk_X509_new_null();
+ if (!*ca)
+ goto err;
+ if (!sk_X509_push(*ca, x))
+ goto err;
+ x = NULL;
+ }
+ if (x)
+ X509_free(x);
+ }
+
+ if (ocerts)
+ sk_X509_pop_free(ocerts, X509_free);
+
+ return 1;
+
+ err:
+
+ if (pkey && *pkey)
+ EVP_PKEY_free(*pkey);
+ if (cert && *cert)
+ X509_free(*cert);
+ if (x)
+ X509_free(x);
+ if (ocerts)
+ sk_X509_pop_free(ocerts, X509_free);
+ return 0;
+
+}
+
+/* Parse the outer PKCS#12 structure */
+
+static int parse_pk12(PKCS12 *p12, const char *pass, int passlen,
+ EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
+{
+ STACK_OF(PKCS7) *asafes;
+ STACK_OF(PKCS12_SAFEBAG) *bags;
+ int i, bagnid;
+ PKCS7 *p7;
+
+ if (!(asafes = PKCS12_unpack_authsafes (p12))) return 0;
+ for (i = 0; i < sk_PKCS7_num (asafes); i++) {
+ p7 = sk_PKCS7_value (asafes, i);
+ bagnid = OBJ_obj2nid (p7->type);
+ if (bagnid == NID_pkcs7_data) {
+ bags = PKCS12_unpack_p7data(p7);
+ } else if (bagnid == NID_pkcs7_encrypted) {
+ bags = PKCS12_unpack_p7encdata(p7, pass, passlen);
+ } else continue;
+ if (!bags) {
+ sk_PKCS7_pop_free(asafes, PKCS7_free);
+ return 0;
+ }
+ if (!parse_bags(bags, pass, passlen, pkey, ocerts)) {
+ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+ sk_PKCS7_pop_free(asafes, PKCS7_free);
+ return 0;
+ }
+ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+ }
+ sk_PKCS7_pop_free(asafes, PKCS7_free);
+ return 1;
+}
+
+
+static int parse_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass,
+ int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
+{
+ int i;
+ for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
+ if (!parse_bag(sk_PKCS12_SAFEBAG_value (bags, i),
+ pass, passlen, pkey, ocerts))
+ return 0;
+ }
+ return 1;
+}
+
+static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen,
+ EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
+{
+ PKCS8_PRIV_KEY_INFO *p8;
+ X509 *x509;
+ ASN1_TYPE *attrib;
+ ASN1_BMPSTRING *fname = NULL;
+ ASN1_OCTET_STRING *lkid = NULL;
+
+ if ((attrib = PKCS12_get_attr (bag, NID_friendlyName)))
+ fname = attrib->value.bmpstring;
+
+ if ((attrib = PKCS12_get_attr (bag, NID_localKeyID)))
+ lkid = attrib->value.octet_string;
+
+ switch (M_PKCS12_bag_type(bag))
+ {
+ case NID_keyBag:
+ if (!pkey || *pkey)
+ return 1;
+ if (!(*pkey = EVP_PKCS82PKEY(bag->value.keybag)))
+ return 0;
+ break;
+
+ case NID_pkcs8ShroudedKeyBag:
+ if (!pkey || *pkey)
+ return 1;
+ if (!(p8 = PKCS12_decrypt_skey(bag, pass, passlen)))
+ return 0;
+ *pkey = EVP_PKCS82PKEY(p8);
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ if (!(*pkey)) return 0;
+ break;
+
+ case NID_certBag:
+ if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate )
+ return 1;
+ if (!(x509 = PKCS12_certbag2x509(bag)))
+ return 0;
+ if(lkid && !X509_keyid_set1(x509, lkid->data, lkid->length))
+ {
+ X509_free(x509);
+ return 0;
+ }
+ if(fname) {
+ int len, r;
+ unsigned char *data;
+ len = ASN1_STRING_to_UTF8(&data, fname);
+ if(len >= 0) {
+ r = X509_alias_set1(x509, data, len);
+ OPENSSL_free(data);
+ if (!r)
+ {
+ X509_free(x509);
+ return 0;
+ }
+ }
+ }
+
+ if(!sk_X509_push(ocerts, x509))
+ {
+ X509_free(x509);
+ return 0;
+ }
+
+ break;
+
+ case NID_safeContentsBag:
+ return parse_bags(bag->value.safes, pass, passlen,
+ pkey, ocerts);
+ break;
+
+ default:
+ return 1;
+ break;
+ }
+ return 1;
+}
+
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_mutl.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_mutl.c
index 96de1bd11e..96de1bd11e 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_mutl.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_mutl.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_npas.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_npas.c
index 2f71355150..2f71355150 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_npas.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_npas.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_p8d.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_p8d.c
index deba81e4a9..deba81e4a9 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_p8d.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_p8d.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_p8e.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_p8e.c
index bf20a77b4c..bf20a77b4c 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_p8e.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_p8e.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/p12_utl.c b/drivers/builtin_openssl2/crypto/pkcs12/p12_utl.c
index 59c6f453f6..59c6f453f6 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/p12_utl.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/p12_utl.c
diff --git a/drivers/builtin_openssl/crypto/pkcs12/pk12err.c b/drivers/builtin_openssl2/crypto/pkcs12/pk12err.c
index f6ddf2df12..f6ddf2df12 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/pk12err.c
+++ b/drivers/builtin_openssl2/crypto/pkcs12/pk12err.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/bio_ber.c b/drivers/builtin_openssl2/crypto/pkcs7/bio_ber.c
index 31973fcd1f..31973fcd1f 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/bio_ber.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/bio_ber.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/bio_pk7.c b/drivers/builtin_openssl2/crypto/pkcs7/bio_pk7.c
index 0fd31e730f..0fd31e730f 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/bio_pk7.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/bio_pk7.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/dec.c b/drivers/builtin_openssl2/crypto/pkcs7/dec.c
index 6752ec568a..6752ec568a 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/dec.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/dec.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/des.pem b/drivers/builtin_openssl2/crypto/pkcs7/des.pem
index 62d1657e3e..62d1657e3e 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/des.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/des.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/doc b/drivers/builtin_openssl2/crypto/pkcs7/doc
index d2e8b7b2a3..d2e8b7b2a3 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/doc
+++ b/drivers/builtin_openssl2/crypto/pkcs7/doc
diff --git a/drivers/builtin_openssl/crypto/pkcs7/enc.c b/drivers/builtin_openssl2/crypto/pkcs7/enc.c
index 7417f8a4e0..7417f8a4e0 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/enc.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/enc.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/es1.pem b/drivers/builtin_openssl2/crypto/pkcs7/es1.pem
index 47112a238f..47112a238f 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/es1.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/es1.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/example.c b/drivers/builtin_openssl2/crypto/pkcs7/example.c
index 2953d04b5c..2953d04b5c 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/example.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/example.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/example.h b/drivers/builtin_openssl2/crypto/pkcs7/example.h
index 96167de188..96167de188 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/example.h
+++ b/drivers/builtin_openssl2/crypto/pkcs7/example.h
diff --git a/drivers/builtin_openssl/crypto/pkcs7/info.pem b/drivers/builtin_openssl2/crypto/pkcs7/info.pem
index 989baf8709..989baf8709 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/info.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/info.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/infokey.pem b/drivers/builtin_openssl2/crypto/pkcs7/infokey.pem
index 1e2acc954d..1e2acc954d 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/infokey.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/infokey.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/p7/a1 b/drivers/builtin_openssl2/crypto/pkcs7/p7/a1
index 56ca943762..56ca943762 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/p7/a1
+++ b/drivers/builtin_openssl2/crypto/pkcs7/p7/a1
diff --git a/drivers/builtin_openssl/crypto/pkcs7/p7/a2 b/drivers/builtin_openssl2/crypto/pkcs7/p7/a2
index 23d8fb5e93..23d8fb5e93 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/p7/a2
+++ b/drivers/builtin_openssl2/crypto/pkcs7/p7/a2
diff --git a/drivers/builtin_openssl/crypto/pkcs7/p7/cert.p7c b/drivers/builtin_openssl2/crypto/pkcs7/p7/cert.p7c
index 2b75ec05f7..2b75ec05f7 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/p7/cert.p7c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/p7/cert.p7c
Binary files differ
diff --git a/drivers/builtin_openssl/crypto/pkcs7/p7/smime.p7m b/drivers/builtin_openssl2/crypto/pkcs7/p7/smime.p7m
index 2b6e6f82ba..2b6e6f82ba 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/p7/smime.p7m
+++ b/drivers/builtin_openssl2/crypto/pkcs7/p7/smime.p7m
Binary files differ
diff --git a/drivers/builtin_openssl/crypto/pkcs7/p7/smime.p7s b/drivers/builtin_openssl2/crypto/pkcs7/p7/smime.p7s
index 2b5d4fb0e3..2b5d4fb0e3 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/p7/smime.p7s
+++ b/drivers/builtin_openssl2/crypto/pkcs7/p7/smime.p7s
Binary files differ
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pk7_asn1.c b/drivers/builtin_openssl2/crypto/pkcs7/pk7_asn1.c
index b7ec2883cb..b7ec2883cb 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/pk7_asn1.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pk7_asn1.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pk7_attr.c b/drivers/builtin_openssl2/crypto/pkcs7/pk7_attr.c
index a97db51210..a97db51210 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/pk7_attr.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pk7_attr.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pk7_dgst.c b/drivers/builtin_openssl2/crypto/pkcs7/pk7_dgst.c
index 90edfa5001..90edfa5001 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/pk7_dgst.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pk7_dgst.c
diff --git a/drivers/builtin_openssl2/crypto/pkcs7/pk7_doit.c b/drivers/builtin_openssl2/crypto/pkcs7/pk7_doit.c
new file mode 100644
index 0000000000..d91aa116a9
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pk7_doit.c
@@ -0,0 +1,1305 @@
+/* crypto/pkcs7/pk7_doit.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+
+static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
+ void *value);
+static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid);
+
+static int PKCS7_type_is_other(PKCS7* p7)
+ {
+ int isOther=1;
+
+ int nid=OBJ_obj2nid(p7->type);
+
+ switch( nid )
+ {
+ case NID_pkcs7_data:
+ case NID_pkcs7_signed:
+ case NID_pkcs7_enveloped:
+ case NID_pkcs7_signedAndEnveloped:
+ case NID_pkcs7_digest:
+ case NID_pkcs7_encrypted:
+ isOther=0;
+ break;
+ default:
+ isOther=1;
+ }
+
+ return isOther;
+
+ }
+
+static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7)
+ {
+ if ( PKCS7_type_is_data(p7))
+ return p7->d.data;
+ if ( PKCS7_type_is_other(p7) && p7->d.other
+ && (p7->d.other->type == V_ASN1_OCTET_STRING))
+ return p7->d.other->value.octet_string;
+ return NULL;
+ }
+
+static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg)
+ {
+ BIO *btmp;
+ const EVP_MD *md;
+ if ((btmp=BIO_new(BIO_f_md())) == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB);
+ goto err;
+ }
+
+ md=EVP_get_digestbyobj(alg->algorithm);
+ if (md == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,PKCS7_R_UNKNOWN_DIGEST_TYPE);
+ goto err;
+ }
+
+ BIO_set_md(btmp,md);
+ if (*pbio == NULL)
+ *pbio=btmp;
+ else if (!BIO_push(*pbio,btmp))
+ {
+ PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB);
+ goto err;
+ }
+ btmp=NULL;
+
+ return 1;
+
+ err:
+ if (btmp)
+ BIO_free(btmp);
+ return 0;
+
+ }
+
+static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri,
+ unsigned char *key, int keylen)
+ {
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_PKEY *pkey = NULL;
+ unsigned char *ek = NULL;
+ int ret = 0;
+ size_t eklen;
+
+ pkey = X509_get_pubkey(ri->cert);
+
+ if (!pkey)
+ return 0;
+
+ pctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!pctx)
+ return 0;
+
+ if (EVP_PKEY_encrypt_init(pctx) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
+ EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri) <= 0)
+ {
+ PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, PKCS7_R_CTRL_ERROR);
+ goto err;
+ }
+
+ if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0)
+ goto err;
+
+ ek = OPENSSL_malloc(eklen);
+
+ if (ek == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0)
+ goto err;
+
+ ASN1_STRING_set0(ri->enc_key, ek, eklen);
+ ek = NULL;
+
+ ret = 1;
+
+ err:
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ if (pctx)
+ EVP_PKEY_CTX_free(pctx);
+ if (ek)
+ OPENSSL_free(ek);
+ return ret;
+
+ }
+
+
+static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
+ PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey)
+ {
+ EVP_PKEY_CTX *pctx = NULL;
+ unsigned char *ek = NULL;
+ size_t eklen;
+
+ int ret = -1;
+
+ pctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!pctx)
+ return -1;
+
+ if (EVP_PKEY_decrypt_init(pctx) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
+ EVP_PKEY_CTRL_PKCS7_DECRYPT, 0, ri) <= 0)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, PKCS7_R_CTRL_ERROR);
+ goto err;
+ }
+
+ if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
+ ri->enc_key->data, ri->enc_key->length) <= 0)
+ goto err;
+
+ ek = OPENSSL_malloc(eklen);
+
+ if (ek == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (EVP_PKEY_decrypt(pctx, ek, &eklen,
+ ri->enc_key->data, ri->enc_key->length) <= 0)
+ {
+ ret = 0;
+ PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ ret = 1;
+
+ if (*pek)
+ {
+ OPENSSL_cleanse(*pek, *peklen);
+ OPENSSL_free(*pek);
+ }
+
+ *pek = ek;
+ *peklen = eklen;
+
+ err:
+ if (pctx)
+ EVP_PKEY_CTX_free(pctx);
+ if (!ret && ek)
+ OPENSSL_free(ek);
+
+ return ret;
+ }
+
+BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
+ {
+ int i;
+ BIO *out=NULL,*btmp=NULL;
+ X509_ALGOR *xa = NULL;
+ const EVP_CIPHER *evp_cipher=NULL;
+ STACK_OF(X509_ALGOR) *md_sk=NULL;
+ STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
+ X509_ALGOR *xalg=NULL;
+ PKCS7_RECIP_INFO *ri=NULL;
+ ASN1_OCTET_STRING *os=NULL;
+
+ i=OBJ_obj2nid(p7->type);
+ p7->state=PKCS7_S_HEADER;
+
+ switch (i)
+ {
+ case NID_pkcs7_signed:
+ md_sk=p7->d.sign->md_algs;
+ os = PKCS7_get_octet_string(p7->d.sign->contents);
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ rsk=p7->d.signed_and_enveloped->recipientinfo;
+ md_sk=p7->d.signed_and_enveloped->md_algs;
+ xalg=p7->d.signed_and_enveloped->enc_data->algorithm;
+ evp_cipher=p7->d.signed_and_enveloped->enc_data->cipher;
+ if (evp_cipher == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAINIT,
+ PKCS7_R_CIPHER_NOT_INITIALIZED);
+ goto err;
+ }
+ break;
+ case NID_pkcs7_enveloped:
+ rsk=p7->d.enveloped->recipientinfo;
+ xalg=p7->d.enveloped->enc_data->algorithm;
+ evp_cipher=p7->d.enveloped->enc_data->cipher;
+ if (evp_cipher == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAINIT,
+ PKCS7_R_CIPHER_NOT_INITIALIZED);
+ goto err;
+ }
+ break;
+ case NID_pkcs7_digest:
+ xa = p7->d.digest->md;
+ os = PKCS7_get_octet_string(p7->d.digest->contents);
+ break;
+ case NID_pkcs7_data:
+ break;
+ default:
+ PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
+ goto err;
+ }
+
+ for (i=0; i<sk_X509_ALGOR_num(md_sk); i++)
+ if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i)))
+ goto err;
+
+ if (xa && !PKCS7_bio_add_digest(&out, xa))
+ goto err;
+
+ if (evp_cipher != NULL)
+ {
+ unsigned char key[EVP_MAX_KEY_LENGTH];
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ int keylen,ivlen;
+ EVP_CIPHER_CTX *ctx;
+
+ if ((btmp=BIO_new(BIO_f_cipher())) == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_BIO_LIB);
+ goto err;
+ }
+ BIO_get_cipher_ctx(btmp, &ctx);
+ keylen=EVP_CIPHER_key_length(evp_cipher);
+ ivlen=EVP_CIPHER_iv_length(evp_cipher);
+ xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
+ if (ivlen > 0)
+ if (RAND_pseudo_bytes(iv,ivlen) <= 0)
+ goto err;
+ if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0)
+ goto err;
+ if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
+ goto err;
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0)
+ goto err;
+
+ if (ivlen > 0) {
+ if (xalg->parameter == NULL) {
+ xalg->parameter = ASN1_TYPE_new();
+ if (xalg->parameter == NULL)
+ goto err;
+ }
+ if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0)
+ goto err;
+ }
+
+ /* Lets do the pub key stuff :-) */
+ for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
+ {
+ ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
+ if (pkcs7_encode_rinfo(ri, key, keylen) <= 0)
+ goto err;
+ }
+ OPENSSL_cleanse(key, keylen);
+
+ if (out == NULL)
+ out=btmp;
+ else
+ BIO_push(out,btmp);
+ btmp=NULL;
+ }
+
+ if (bio == NULL)
+ {
+ if (PKCS7_is_detached(p7))
+ bio=BIO_new(BIO_s_null());
+ else if (os && os->length > 0)
+ bio = BIO_new_mem_buf(os->data, os->length);
+ if(bio == NULL)
+ {
+ bio=BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ goto err;
+ BIO_set_mem_eof_return(bio,0);
+ }
+ }
+ if (out)
+ BIO_push(out,bio);
+ else
+ out = bio;
+ bio=NULL;
+ if (0)
+ {
+err:
+ if (out != NULL)
+ BIO_free_all(out);
+ if (btmp != NULL)
+ BIO_free_all(btmp);
+ out=NULL;
+ }
+ return(out);
+ }
+
+static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert)
+ {
+ int ret;
+ ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
+ pcert->cert_info->issuer);
+ if (ret)
+ return ret;
+ return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber,
+ ri->issuer_and_serial->serial);
+ }
+
+/* int */
+BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
+ {
+ int i,j;
+ BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL;
+ X509_ALGOR *xa;
+ ASN1_OCTET_STRING *data_body=NULL;
+ const EVP_MD *evp_md;
+ const EVP_CIPHER *evp_cipher=NULL;
+ EVP_CIPHER_CTX *evp_ctx=NULL;
+ X509_ALGOR *enc_alg=NULL;
+ STACK_OF(X509_ALGOR) *md_sk=NULL;
+ STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
+ PKCS7_RECIP_INFO *ri=NULL;
+ unsigned char *ek = NULL, *tkey = NULL;
+ int eklen = 0, tkeylen = 0;
+
+ i=OBJ_obj2nid(p7->type);
+ p7->state=PKCS7_S_HEADER;
+
+ switch (i)
+ {
+ case NID_pkcs7_signed:
+ data_body=PKCS7_get_octet_string(p7->d.sign->contents);
+ if (!PKCS7_is_detached(p7) && data_body == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_INVALID_SIGNED_DATA_TYPE);
+ goto err;
+ }
+ md_sk=p7->d.sign->md_algs;
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ rsk=p7->d.signed_and_enveloped->recipientinfo;
+ md_sk=p7->d.signed_and_enveloped->md_algs;
+ data_body=p7->d.signed_and_enveloped->enc_data->enc_data;
+ enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm;
+ evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
+ if (evp_cipher == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
+ goto err;
+ }
+ break;
+ case NID_pkcs7_enveloped:
+ rsk=p7->d.enveloped->recipientinfo;
+ enc_alg=p7->d.enveloped->enc_data->algorithm;
+ data_body=p7->d.enveloped->enc_data->enc_data;
+ evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
+ if (evp_cipher == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
+ goto err;
+ }
+ break;
+ default:
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
+ goto err;
+ }
+
+ /* We will be checking the signature */
+ if (md_sk != NULL)
+ {
+ for (i=0; i<sk_X509_ALGOR_num(md_sk); i++)
+ {
+ xa=sk_X509_ALGOR_value(md_sk,i);
+ if ((btmp=BIO_new(BIO_f_md())) == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
+ goto err;
+ }
+
+ j=OBJ_obj2nid(xa->algorithm);
+ evp_md=EVP_get_digestbynid(j);
+ if (evp_md == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE);
+ goto err;
+ }
+
+ BIO_set_md(btmp,evp_md);
+ if (out == NULL)
+ out=btmp;
+ else
+ BIO_push(out,btmp);
+ btmp=NULL;
+ }
+ }
+
+ if (evp_cipher != NULL)
+ {
+#if 0
+ unsigned char key[EVP_MAX_KEY_LENGTH];
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char *p;
+ int keylen,ivlen;
+ int max;
+ X509_OBJECT ret;
+#endif
+
+ if ((etmp=BIO_new(BIO_f_cipher())) == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
+ goto err;
+ }
+
+ /* It was encrypted, we need to decrypt the secret key
+ * with the private key */
+
+ /* Find the recipientInfo which matches the passed certificate
+ * (if any)
+ */
+
+ if (pcert)
+ {
+ for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
+ {
+ ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
+ if (!pkcs7_cmp_ri(ri, pcert))
+ break;
+ ri=NULL;
+ }
+ if (ri == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE,
+ PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
+ goto err;
+ }
+ }
+
+ /* If we haven't got a certificate try each ri in turn */
+ if (pcert == NULL)
+ {
+ /* Always attempt to decrypt all rinfo even
+ * after sucess as a defence against MMA timing
+ * attacks.
+ */
+ for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
+ {
+ ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
+
+ if (pkcs7_decrypt_rinfo(&ek, &eklen,
+ ri, pkey) < 0)
+ goto err;
+ ERR_clear_error();
+ }
+ }
+ else
+ {
+ /* Only exit on fatal errors, not decrypt failure */
+ if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
+ goto err;
+ ERR_clear_error();
+ }
+
+ evp_ctx=NULL;
+ BIO_get_cipher_ctx(etmp,&evp_ctx);
+ if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
+ goto err;
+ if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
+ goto err;
+ /* Generate random key as MMA defence */
+ tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
+ tkey = OPENSSL_malloc(tkeylen);
+ if (!tkey)
+ goto err;
+ if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
+ goto err;
+ if (ek == NULL)
+ {
+ ek = tkey;
+ eklen = tkeylen;
+ tkey = NULL;
+ }
+
+ if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) {
+ /* Some S/MIME clients don't use the same key
+ * and effective key length. The key length is
+ * determined by the size of the decrypted RSA key.
+ */
+ if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen))
+ {
+ /* Use random key as MMA defence */
+ OPENSSL_cleanse(ek, eklen);
+ OPENSSL_free(ek);
+ ek = tkey;
+ eklen = tkeylen;
+ tkey = NULL;
+ }
+ }
+ /* Clear errors so we don't leak information useful in MMA */
+ ERR_clear_error();
+ if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0)
+ goto err;
+
+ if (ek)
+ {
+ OPENSSL_cleanse(ek,eklen);
+ OPENSSL_free(ek);
+ ek = NULL;
+ }
+ if (tkey)
+ {
+ OPENSSL_cleanse(tkey,tkeylen);
+ OPENSSL_free(tkey);
+ tkey = NULL;
+ }
+
+ if (out == NULL)
+ out=etmp;
+ else
+ BIO_push(out,etmp);
+ etmp=NULL;
+ }
+
+#if 1
+ if (PKCS7_is_detached(p7) || (in_bio != NULL))
+ {
+ bio=in_bio;
+ }
+ else
+ {
+#if 0
+ bio=BIO_new(BIO_s_mem());
+ /* We need to set this so that when we have read all
+ * the data, the encrypt BIO, if present, will read
+ * EOF and encode the last few bytes */
+ BIO_set_mem_eof_return(bio,0);
+
+ if (data_body->length > 0)
+ BIO_write(bio,(char *)data_body->data,data_body->length);
+#else
+ if (data_body->length > 0)
+ bio = BIO_new_mem_buf(data_body->data,data_body->length);
+ else {
+ bio=BIO_new(BIO_s_mem());
+ BIO_set_mem_eof_return(bio,0);
+ }
+ if (bio == NULL)
+ goto err;
+#endif
+ }
+ BIO_push(out,bio);
+ bio=NULL;
+#endif
+ if (0)
+ {
+err:
+ if (ek)
+ {
+ OPENSSL_cleanse(ek,eklen);
+ OPENSSL_free(ek);
+ }
+ if (tkey)
+ {
+ OPENSSL_cleanse(tkey,tkeylen);
+ OPENSSL_free(tkey);
+ }
+ if (out != NULL) BIO_free_all(out);
+ if (btmp != NULL) BIO_free_all(btmp);
+ if (etmp != NULL) BIO_free_all(etmp);
+ if (bio != NULL) BIO_free_all(bio);
+ out=NULL;
+ }
+ return(out);
+ }
+
+static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid)
+ {
+ for (;;)
+ {
+ bio=BIO_find_type(bio,BIO_TYPE_MD);
+ if (bio == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
+ return NULL;
+ }
+ BIO_get_md_ctx(bio,pmd);
+ if (*pmd == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+ if (EVP_MD_CTX_type(*pmd) == nid)
+ return bio;
+ bio=BIO_next(bio);
+ }
+ return NULL;
+ }
+
+static int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx)
+ {
+ unsigned char md_data[EVP_MAX_MD_SIZE];
+ unsigned int md_len;
+
+ /* Add signing time if not already present */
+ if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime))
+ {
+ if (!PKCS7_add0_attrib_signing_time(si, NULL))
+ {
+ PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB,
+ ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+
+ /* Add digest */
+ if (!EVP_DigestFinal_ex(mctx, md_data,&md_len))
+ {
+ PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_EVP_LIB);
+ return 0;
+ }
+ if (!PKCS7_add1_attrib_digest(si, md_data, md_len))
+ {
+ PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* Now sign the attributes */
+ if (!PKCS7_SIGNER_INFO_sign(si))
+ return 0;
+
+ return 1;
+ }
+
+
+int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
+ {
+ int ret=0;
+ int i,j;
+ BIO *btmp;
+ PKCS7_SIGNER_INFO *si;
+ EVP_MD_CTX *mdc,ctx_tmp;
+ STACK_OF(X509_ATTRIBUTE) *sk;
+ STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL;
+ ASN1_OCTET_STRING *os=NULL;
+
+ EVP_MD_CTX_init(&ctx_tmp);
+ i=OBJ_obj2nid(p7->type);
+ p7->state=PKCS7_S_HEADER;
+
+ switch (i)
+ {
+ case NID_pkcs7_data:
+ os = p7->d.data;
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ /* XXXXXXXXXXXXXXXX */
+ si_sk=p7->d.signed_and_enveloped->signer_info;
+ os = p7->d.signed_and_enveloped->enc_data->enc_data;
+ if (!os)
+ {
+ os=M_ASN1_OCTET_STRING_new();
+ if (!os)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ p7->d.signed_and_enveloped->enc_data->enc_data=os;
+ }
+ break;
+ case NID_pkcs7_enveloped:
+ /* XXXXXXXXXXXXXXXX */
+ os = p7->d.enveloped->enc_data->enc_data;
+ if (!os)
+ {
+ os=M_ASN1_OCTET_STRING_new();
+ if (!os)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ p7->d.enveloped->enc_data->enc_data=os;
+ }
+ break;
+ case NID_pkcs7_signed:
+ si_sk=p7->d.sign->signer_info;
+ os=PKCS7_get_octet_string(p7->d.sign->contents);
+ /* If detached data then the content is excluded */
+ if(PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) {
+ M_ASN1_OCTET_STRING_free(os);
+ p7->d.sign->contents->d.data = NULL;
+ }
+ break;
+
+ case NID_pkcs7_digest:
+ os=PKCS7_get_octet_string(p7->d.digest->contents);
+ /* If detached data then the content is excluded */
+ if(PKCS7_type_is_data(p7->d.digest->contents) && p7->detached)
+ {
+ M_ASN1_OCTET_STRING_free(os);
+ p7->d.digest->contents->d.data = NULL;
+ }
+ break;
+
+ default:
+ PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
+ goto err;
+ }
+
+ if (si_sk != NULL)
+ {
+ for (i=0; i<sk_PKCS7_SIGNER_INFO_num(si_sk); i++)
+ {
+ si=sk_PKCS7_SIGNER_INFO_value(si_sk,i);
+ if (si->pkey == NULL)
+ continue;
+
+ j = OBJ_obj2nid(si->digest_alg->algorithm);
+
+ btmp=bio;
+
+ btmp = PKCS7_find_digest(&mdc, btmp, j);
+
+ if (btmp == NULL)
+ goto err;
+
+ /* We now have the EVP_MD_CTX, lets do the
+ * signing. */
+ if (!EVP_MD_CTX_copy_ex(&ctx_tmp,mdc))
+ goto err;
+
+ sk=si->auth_attr;
+
+ /* If there are attributes, we add the digest
+ * attribute and only sign the attributes */
+ if (sk_X509_ATTRIBUTE_num(sk) > 0)
+ {
+ if (!do_pkcs7_signed_attrib(si, &ctx_tmp))
+ goto err;
+ }
+ else
+ {
+ unsigned char *abuf = NULL;
+ unsigned int abuflen;
+ abuflen = EVP_PKEY_size(si->pkey);
+ abuf = OPENSSL_malloc(abuflen);
+ if (!abuf)
+ goto err;
+
+ if (!EVP_SignFinal(&ctx_tmp, abuf, &abuflen,
+ si->pkey))
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAFINAL,
+ ERR_R_EVP_LIB);
+ goto err;
+ }
+ ASN1_STRING_set0(si->enc_digest, abuf, abuflen);
+ }
+ }
+ }
+ else if (i == NID_pkcs7_digest)
+ {
+ unsigned char md_data[EVP_MAX_MD_SIZE];
+ unsigned int md_len;
+ if (!PKCS7_find_digest(&mdc, bio,
+ OBJ_obj2nid(p7->d.digest->md->algorithm)))
+ goto err;
+ if (!EVP_DigestFinal_ex(mdc,md_data,&md_len))
+ goto err;
+ M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
+ }
+
+ if (!PKCS7_is_detached(p7) && !(os->flags & ASN1_STRING_FLAG_NDEF))
+ {
+ char *cont;
+ long contlen;
+ btmp=BIO_find_type(bio,BIO_TYPE_MEM);
+ if (btmp == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
+ goto err;
+ }
+ contlen = BIO_get_mem_data(btmp, &cont);
+ /* Mark the BIO read only then we can use its copy of the data
+ * instead of making an extra copy.
+ */
+ BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
+ BIO_set_mem_eof_return(btmp, 0);
+ ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
+ }
+ ret=1;
+err:
+ EVP_MD_CTX_cleanup(&ctx_tmp);
+ return(ret);
+ }
+
+int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si)
+ {
+ EVP_MD_CTX mctx;
+ EVP_PKEY_CTX *pctx;
+ unsigned char *abuf = NULL;
+ int alen;
+ size_t siglen;
+ const EVP_MD *md = NULL;
+
+ md = EVP_get_digestbyobj(si->digest_alg->algorithm);
+ if (md == NULL)
+ return 0;
+
+ EVP_MD_CTX_init(&mctx);
+ if (EVP_DigestSignInit(&mctx, &pctx, md,NULL, si->pkey) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
+ EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0)
+ {
+ PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
+ goto err;
+ }
+
+ alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr,&abuf,
+ ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
+ if(!abuf)
+ goto err;
+ if (EVP_DigestSignUpdate(&mctx,abuf,alen) <= 0)
+ goto err;
+ OPENSSL_free(abuf);
+ abuf = NULL;
+ if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0)
+ goto err;
+ abuf = OPENSSL_malloc(siglen);
+ if(!abuf)
+ goto err;
+ if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
+ EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0)
+ {
+ PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
+ goto err;
+ }
+
+ EVP_MD_CTX_cleanup(&mctx);
+
+ ASN1_STRING_set0(si->enc_digest, abuf, siglen);
+
+ return 1;
+
+ err:
+ if (abuf)
+ OPENSSL_free(abuf);
+ EVP_MD_CTX_cleanup(&mctx);
+ return 0;
+
+ }
+
+int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
+ PKCS7 *p7, PKCS7_SIGNER_INFO *si)
+ {
+ PKCS7_ISSUER_AND_SERIAL *ias;
+ int ret=0,i;
+ STACK_OF(X509) *cert;
+ X509 *x509;
+
+ if (PKCS7_type_is_signed(p7))
+ {
+ cert=p7->d.sign->cert;
+ }
+ else if (PKCS7_type_is_signedAndEnveloped(p7))
+ {
+ cert=p7->d.signed_and_enveloped->cert;
+ }
+ else
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE);
+ goto err;
+ }
+ /* XXXXXXXXXXXXXXXXXXXXXXX */
+ ias=si->issuer_and_serial;
+
+ x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial);
+
+ /* were we able to find the cert in passed to us */
+ if (x509 == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_UNABLE_TO_FIND_CERTIFICATE);
+ goto err;
+ }
+
+ /* Lets verify */
+ if(!X509_STORE_CTX_init(ctx,cert_store,x509,cert))
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB);
+ goto err;
+ }
+ X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN);
+ i=X509_verify_cert(ctx);
+ if (i <= 0)
+ {
+ PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB);
+ X509_STORE_CTX_cleanup(ctx);
+ goto err;
+ }
+ X509_STORE_CTX_cleanup(ctx);
+
+ return PKCS7_signatureVerify(bio, p7, si, x509);
+ err:
+ return ret;
+ }
+
+int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
+ X509 *x509)
+ {
+ ASN1_OCTET_STRING *os;
+ EVP_MD_CTX mdc_tmp,*mdc;
+ int ret=0,i;
+ int md_type;
+ STACK_OF(X509_ATTRIBUTE) *sk;
+ BIO *btmp;
+ EVP_PKEY *pkey;
+
+ EVP_MD_CTX_init(&mdc_tmp);
+
+ if (!PKCS7_type_is_signed(p7) &&
+ !PKCS7_type_is_signedAndEnveloped(p7)) {
+ PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
+ PKCS7_R_WRONG_PKCS7_TYPE);
+ goto err;
+ }
+
+ md_type=OBJ_obj2nid(si->digest_alg->algorithm);
+
+ btmp=bio;
+ for (;;)
+ {
+ if ((btmp == NULL) ||
+ ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL))
+ {
+ PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
+ PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
+ goto err;
+ }
+ BIO_get_md_ctx(btmp,&mdc);
+ if (mdc == NULL)
+ {
+ PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if (EVP_MD_CTX_type(mdc) == md_type)
+ break;
+ /* Workaround for some broken clients that put the signature
+ * OID instead of the digest OID in digest_alg->algorithm
+ */
+ if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type)
+ break;
+ btmp=BIO_next(btmp);
+ }
+
+ /* mdc is the digest ctx that we want, unless there are attributes,
+ * in which case the digest is the signed attributes */
+ if (!EVP_MD_CTX_copy_ex(&mdc_tmp,mdc))
+ goto err;
+
+ sk=si->auth_attr;
+ if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0))
+ {
+ unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL;
+ unsigned int md_len;
+ int alen;
+ ASN1_OCTET_STRING *message_digest;
+
+ if (!EVP_DigestFinal_ex(&mdc_tmp,md_dat,&md_len))
+ goto err;
+ message_digest=PKCS7_digest_from_attributes(sk);
+ if (!message_digest)
+ {
+ PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
+ PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
+ goto err;
+ }
+ if ((message_digest->length != (int)md_len) ||
+ (memcmp(message_digest->data,md_dat,md_len)))
+ {
+#if 0
+{
+int ii;
+for (ii=0; ii<message_digest->length; ii++)
+ printf("%02X",message_digest->data[ii]); printf(" sent\n");
+for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n");
+}
+#endif
+ PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
+ PKCS7_R_DIGEST_FAILURE);
+ ret= -1;
+ goto err;
+ }
+
+ if (!EVP_VerifyInit_ex(&mdc_tmp,EVP_get_digestbynid(md_type), NULL))
+ goto err;
+
+ alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
+ ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
+ if (alen <= 0)
+ {
+ PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,ERR_R_ASN1_LIB);
+ ret = -1;
+ goto err;
+ }
+ if (!EVP_VerifyUpdate(&mdc_tmp, abuf, alen))
+ goto err;
+
+ OPENSSL_free(abuf);
+ }
+
+ os=si->enc_digest;
+ pkey = X509_get_pubkey(x509);
+ if (!pkey)
+ {
+ ret = -1;
+ goto err;
+ }
+
+ i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey);
+ EVP_PKEY_free(pkey);
+ if (i <= 0)
+ {
+ PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
+ PKCS7_R_SIGNATURE_FAILURE);
+ ret= -1;
+ goto err;
+ }
+ else
+ ret=1;
+err:
+ EVP_MD_CTX_cleanup(&mdc_tmp);
+ return(ret);
+ }
+
+PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx)
+ {
+ STACK_OF(PKCS7_RECIP_INFO) *rsk;
+ PKCS7_RECIP_INFO *ri;
+ int i;
+
+ i=OBJ_obj2nid(p7->type);
+ if (i != NID_pkcs7_signedAndEnveloped)
+ return NULL;
+ if (p7->d.signed_and_enveloped == NULL)
+ return NULL;
+ rsk=p7->d.signed_and_enveloped->recipientinfo;
+ if (rsk == NULL)
+ return NULL;
+ ri=sk_PKCS7_RECIP_INFO_value(rsk,0);
+ if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return(NULL);
+ ri=sk_PKCS7_RECIP_INFO_value(rsk,idx);
+ return(ri->issuer_and_serial);
+ }
+
+ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid)
+ {
+ return(get_attribute(si->auth_attr,nid));
+ }
+
+ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid)
+ {
+ return(get_attribute(si->unauth_attr,nid));
+ }
+
+static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid)
+ {
+ int i;
+ X509_ATTRIBUTE *xa;
+ ASN1_OBJECT *o;
+
+ o=OBJ_nid2obj(nid);
+ if (!o || !sk) return(NULL);
+ for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++)
+ {
+ xa=sk_X509_ATTRIBUTE_value(sk,i);
+ if (OBJ_cmp(xa->object,o) == 0)
+ {
+ if (!xa->single && sk_ASN1_TYPE_num(xa->value.set))
+ return(sk_ASN1_TYPE_value(xa->value.set,0));
+ else
+ return(NULL);
+ }
+ }
+ return(NULL);
+ }
+
+ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk)
+{
+ ASN1_TYPE *astype;
+ if(!(astype = get_attribute(sk, NID_pkcs9_messageDigest))) return NULL;
+ return astype->value.octet_string;
+}
+
+int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
+ STACK_OF(X509_ATTRIBUTE) *sk)
+ {
+ int i;
+
+ if (p7si->auth_attr != NULL)
+ sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr,X509_ATTRIBUTE_free);
+ p7si->auth_attr=sk_X509_ATTRIBUTE_dup(sk);
+ if (p7si->auth_attr == NULL)
+ return 0;
+ for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++)
+ {
+ if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr,i,
+ X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i))))
+ == NULL)
+ return(0);
+ }
+ return(1);
+ }
+
+int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk)
+ {
+ int i;
+
+ if (p7si->unauth_attr != NULL)
+ sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr,
+ X509_ATTRIBUTE_free);
+ p7si->unauth_attr=sk_X509_ATTRIBUTE_dup(sk);
+ if (p7si->unauth_attr == NULL)
+ return 0;
+ for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++)
+ {
+ if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr,i,
+ X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i))))
+ == NULL)
+ return(0);
+ }
+ return(1);
+ }
+
+int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
+ void *value)
+ {
+ return(add_attribute(&(p7si->auth_attr),nid,atrtype,value));
+ }
+
+int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
+ void *value)
+ {
+ return(add_attribute(&(p7si->unauth_attr),nid,atrtype,value));
+ }
+
+static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
+ void *value)
+ {
+ X509_ATTRIBUTE *attr=NULL;
+
+ if (*sk == NULL)
+ {
+ *sk = sk_X509_ATTRIBUTE_new_null();
+ if (*sk == NULL)
+ return 0;
+new_attrib:
+ if (!(attr=X509_ATTRIBUTE_create(nid,atrtype,value)))
+ return 0;
+ if (!sk_X509_ATTRIBUTE_push(*sk,attr))
+ {
+ X509_ATTRIBUTE_free(attr);
+ return 0;
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i=0; i<sk_X509_ATTRIBUTE_num(*sk); i++)
+ {
+ attr=sk_X509_ATTRIBUTE_value(*sk,i);
+ if (OBJ_obj2nid(attr->object) == nid)
+ {
+ X509_ATTRIBUTE_free(attr);
+ attr=X509_ATTRIBUTE_create(nid,atrtype,value);
+ if (attr == NULL)
+ return 0;
+ if (!sk_X509_ATTRIBUTE_set(*sk,i,attr))
+ {
+ X509_ATTRIBUTE_free(attr);
+ return 0;
+ }
+ goto end;
+ }
+ }
+ goto new_attrib;
+ }
+end:
+ return(1);
+ }
+
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pk7_enc.c b/drivers/builtin_openssl2/crypto/pkcs7/pk7_enc.c
index acbb189c59..acbb189c59 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/pk7_enc.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pk7_enc.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pk7_lib.c b/drivers/builtin_openssl2/crypto/pkcs7/pk7_lib.c
index d411269b50..d411269b50 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/pk7_lib.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pk7_lib.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pk7_mime.c b/drivers/builtin_openssl2/crypto/pkcs7/pk7_mime.c
index 938f79a646..938f79a646 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/pk7_mime.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pk7_mime.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/pk7_smime.c b/drivers/builtin_openssl2/crypto/pkcs7/pk7_smime.c
index a5104f8d05..a5104f8d05 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/pk7_smime.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pk7_smime.c
diff --git a/drivers/builtin_openssl2/crypto/pkcs7/pkcs7err.c b/drivers/builtin_openssl2/crypto/pkcs7/pkcs7err.c
new file mode 100644
index 0000000000..f3db08e007
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/pkcs7/pkcs7err.c
@@ -0,0 +1,188 @@
+/* crypto/pkcs7/pkcs7err.c */
+/* ====================================================================
+ * Copyright (c) 1999-2014 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/* NOTE: this file was auto generated by the mkerr.pl script: any changes
+ * made to it will be overwritten when the script next updates this file,
+ * only reason strings will be preserved.
+ */
+
+#include <stdio.h>
+#include <openssl/err.h>
+#include <openssl/pkcs7.h>
+
+/* BEGIN ERROR CODES */
+#ifndef OPENSSL_NO_ERR
+
+#define ERR_FUNC(func) ERR_PACK(ERR_LIB_PKCS7,func,0)
+#define ERR_REASON(reason) ERR_PACK(ERR_LIB_PKCS7,0,reason)
+
+static ERR_STRING_DATA PKCS7_str_functs[]=
+ {
+{ERR_FUNC(PKCS7_F_B64_READ_PKCS7), "B64_READ_PKCS7"},
+{ERR_FUNC(PKCS7_F_B64_WRITE_PKCS7), "B64_WRITE_PKCS7"},
+{ERR_FUNC(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB), "DO_PKCS7_SIGNED_ATTRIB"},
+{ERR_FUNC(PKCS7_F_I2D_PKCS7_BIO_STREAM), "i2d_PKCS7_bio_stream"},
+{ERR_FUNC(PKCS7_F_PKCS7_ADD0_ATTRIB_SIGNING_TIME), "PKCS7_add0_attrib_signing_time"},
+{ERR_FUNC(PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP), "PKCS7_add_attrib_smimecap"},
+{ERR_FUNC(PKCS7_F_PKCS7_ADD_CERTIFICATE), "PKCS7_add_certificate"},
+{ERR_FUNC(PKCS7_F_PKCS7_ADD_CRL), "PKCS7_add_crl"},
+{ERR_FUNC(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO), "PKCS7_add_recipient_info"},
+{ERR_FUNC(PKCS7_F_PKCS7_ADD_SIGNATURE), "PKCS7_add_signature"},
+{ERR_FUNC(PKCS7_F_PKCS7_ADD_SIGNER), "PKCS7_add_signer"},
+{ERR_FUNC(PKCS7_F_PKCS7_BIO_ADD_DIGEST), "PKCS7_BIO_ADD_DIGEST"},
+{ERR_FUNC(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST), "PKCS7_COPY_EXISTING_DIGEST"},
+{ERR_FUNC(PKCS7_F_PKCS7_CTRL), "PKCS7_ctrl"},
+{ERR_FUNC(PKCS7_F_PKCS7_DATADECODE), "PKCS7_dataDecode"},
+{ERR_FUNC(PKCS7_F_PKCS7_DATAFINAL), "PKCS7_dataFinal"},
+{ERR_FUNC(PKCS7_F_PKCS7_DATAINIT), "PKCS7_dataInit"},
+{ERR_FUNC(PKCS7_F_PKCS7_DATASIGN), "PKCS7_DATASIGN"},
+{ERR_FUNC(PKCS7_F_PKCS7_DATAVERIFY), "PKCS7_dataVerify"},
+{ERR_FUNC(PKCS7_F_PKCS7_DECRYPT), "PKCS7_decrypt"},
+{ERR_FUNC(PKCS7_F_PKCS7_DECRYPT_RINFO), "PKCS7_DECRYPT_RINFO"},
+{ERR_FUNC(PKCS7_F_PKCS7_ENCODE_RINFO), "PKCS7_ENCODE_RINFO"},
+{ERR_FUNC(PKCS7_F_PKCS7_ENCRYPT), "PKCS7_encrypt"},
+{ERR_FUNC(PKCS7_F_PKCS7_FINAL), "PKCS7_final"},
+{ERR_FUNC(PKCS7_F_PKCS7_FIND_DIGEST), "PKCS7_FIND_DIGEST"},
+{ERR_FUNC(PKCS7_F_PKCS7_GET0_SIGNERS), "PKCS7_get0_signers"},
+{ERR_FUNC(PKCS7_F_PKCS7_RECIP_INFO_SET), "PKCS7_RECIP_INFO_set"},
+{ERR_FUNC(PKCS7_F_PKCS7_SET_CIPHER), "PKCS7_set_cipher"},
+{ERR_FUNC(PKCS7_F_PKCS7_SET_CONTENT), "PKCS7_set_content"},
+{ERR_FUNC(PKCS7_F_PKCS7_SET_DIGEST), "PKCS7_set_digest"},
+{ERR_FUNC(PKCS7_F_PKCS7_SET_TYPE), "PKCS7_set_type"},
+{ERR_FUNC(PKCS7_F_PKCS7_SIGN), "PKCS7_sign"},
+{ERR_FUNC(PKCS7_F_PKCS7_SIGNATUREVERIFY), "PKCS7_signatureVerify"},
+{ERR_FUNC(PKCS7_F_PKCS7_SIGNER_INFO_SET), "PKCS7_SIGNER_INFO_set"},
+{ERR_FUNC(PKCS7_F_PKCS7_SIGNER_INFO_SIGN), "PKCS7_SIGNER_INFO_sign"},
+{ERR_FUNC(PKCS7_F_PKCS7_SIGN_ADD_SIGNER), "PKCS7_sign_add_signer"},
+{ERR_FUNC(PKCS7_F_PKCS7_SIMPLE_SMIMECAP), "PKCS7_simple_smimecap"},
+{ERR_FUNC(PKCS7_F_PKCS7_VERIFY), "PKCS7_verify"},
+{ERR_FUNC(PKCS7_F_SMIME_READ_PKCS7), "SMIME_read_PKCS7"},
+{ERR_FUNC(PKCS7_F_SMIME_TEXT), "SMIME_text"},
+{0,NULL}
+ };
+
+static ERR_STRING_DATA PKCS7_str_reasons[]=
+ {
+{ERR_REASON(PKCS7_R_CERTIFICATE_VERIFY_ERROR),"certificate verify error"},
+{ERR_REASON(PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER),"cipher has no object identifier"},
+{ERR_REASON(PKCS7_R_CIPHER_NOT_INITIALIZED),"cipher not initialized"},
+{ERR_REASON(PKCS7_R_CONTENT_AND_DATA_PRESENT),"content and data present"},
+{ERR_REASON(PKCS7_R_CTRL_ERROR) ,"ctrl error"},
+{ERR_REASON(PKCS7_R_DECODE_ERROR) ,"decode error"},
+{ERR_REASON(PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH),"decrypted key is wrong length"},
+{ERR_REASON(PKCS7_R_DECRYPT_ERROR) ,"decrypt error"},
+{ERR_REASON(PKCS7_R_DIGEST_FAILURE) ,"digest failure"},
+{ERR_REASON(PKCS7_R_ENCRYPTION_CTRL_FAILURE),"encryption ctrl failure"},
+{ERR_REASON(PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"encryption not supported for this key type"},
+{ERR_REASON(PKCS7_R_ERROR_ADDING_RECIPIENT),"error adding recipient"},
+{ERR_REASON(PKCS7_R_ERROR_SETTING_CIPHER),"error setting cipher"},
+{ERR_REASON(PKCS7_R_INVALID_MIME_TYPE) ,"invalid mime type"},
+{ERR_REASON(PKCS7_R_INVALID_NULL_POINTER),"invalid null pointer"},
+{ERR_REASON(PKCS7_R_INVALID_SIGNED_DATA_TYPE),"invalid signed data type"},
+{ERR_REASON(PKCS7_R_MIME_NO_CONTENT_TYPE),"mime no content type"},
+{ERR_REASON(PKCS7_R_MIME_PARSE_ERROR) ,"mime parse error"},
+{ERR_REASON(PKCS7_R_MIME_SIG_PARSE_ERROR),"mime sig parse error"},
+{ERR_REASON(PKCS7_R_MISSING_CERIPEND_INFO),"missing ceripend info"},
+{ERR_REASON(PKCS7_R_NO_CONTENT) ,"no content"},
+{ERR_REASON(PKCS7_R_NO_CONTENT_TYPE) ,"no content type"},
+{ERR_REASON(PKCS7_R_NO_DEFAULT_DIGEST) ,"no default digest"},
+{ERR_REASON(PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND),"no matching digest type found"},
+{ERR_REASON(PKCS7_R_NO_MULTIPART_BODY_FAILURE),"no multipart body failure"},
+{ERR_REASON(PKCS7_R_NO_MULTIPART_BOUNDARY),"no multipart boundary"},
+{ERR_REASON(PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE),"no recipient matches certificate"},
+{ERR_REASON(PKCS7_R_NO_RECIPIENT_MATCHES_KEY),"no recipient matches key"},
+{ERR_REASON(PKCS7_R_NO_SIGNATURES_ON_DATA),"no signatures on data"},
+{ERR_REASON(PKCS7_R_NO_SIGNERS) ,"no signers"},
+{ERR_REASON(PKCS7_R_NO_SIG_CONTENT_TYPE) ,"no sig content type"},
+{ERR_REASON(PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE),"operation not supported on this type"},
+{ERR_REASON(PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR),"pkcs7 add signature error"},
+{ERR_REASON(PKCS7_R_PKCS7_ADD_SIGNER_ERROR),"pkcs7 add signer error"},
+{ERR_REASON(PKCS7_R_PKCS7_DATAFINAL) ,"pkcs7 datafinal"},
+{ERR_REASON(PKCS7_R_PKCS7_DATAFINAL_ERROR),"pkcs7 datafinal error"},
+{ERR_REASON(PKCS7_R_PKCS7_DATASIGN) ,"pkcs7 datasign"},
+{ERR_REASON(PKCS7_R_PKCS7_PARSE_ERROR) ,"pkcs7 parse error"},
+{ERR_REASON(PKCS7_R_PKCS7_SIG_PARSE_ERROR),"pkcs7 sig parse error"},
+{ERR_REASON(PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),"private key does not match certificate"},
+{ERR_REASON(PKCS7_R_SIGNATURE_FAILURE) ,"signature failure"},
+{ERR_REASON(PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND),"signer certificate not found"},
+{ERR_REASON(PKCS7_R_SIGNING_CTRL_FAILURE),"signing ctrl failure"},
+{ERR_REASON(PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"signing not supported for this key type"},
+{ERR_REASON(PKCS7_R_SIG_INVALID_MIME_TYPE),"sig invalid mime type"},
+{ERR_REASON(PKCS7_R_SMIME_TEXT_ERROR) ,"smime text error"},
+{ERR_REASON(PKCS7_R_UNABLE_TO_FIND_CERTIFICATE),"unable to find certificate"},
+{ERR_REASON(PKCS7_R_UNABLE_TO_FIND_MEM_BIO),"unable to find mem bio"},
+{ERR_REASON(PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST),"unable to find message digest"},
+{ERR_REASON(PKCS7_R_UNKNOWN_DIGEST_TYPE) ,"unknown digest type"},
+{ERR_REASON(PKCS7_R_UNKNOWN_OPERATION) ,"unknown operation"},
+{ERR_REASON(PKCS7_R_UNSUPPORTED_CIPHER_TYPE),"unsupported cipher type"},
+{ERR_REASON(PKCS7_R_UNSUPPORTED_CONTENT_TYPE),"unsupported content type"},
+{ERR_REASON(PKCS7_R_WRONG_CONTENT_TYPE) ,"wrong content type"},
+{ERR_REASON(PKCS7_R_WRONG_PKCS7_TYPE) ,"wrong pkcs7 type"},
+{0,NULL}
+ };
+
+#endif
+
+void ERR_load_PKCS7_strings(void)
+ {
+#ifndef OPENSSL_NO_ERR
+
+ if (ERR_func_error_string(PKCS7_str_functs[0].error) == NULL)
+ {
+ ERR_load_strings(0,PKCS7_str_functs);
+ ERR_load_strings(0,PKCS7_str_reasons);
+ }
+#endif
+ }
diff --git a/drivers/builtin_openssl/crypto/pkcs7/server.pem b/drivers/builtin_openssl2/crypto/pkcs7/server.pem
index 750aac2094..750aac2094 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/server.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/server.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/sign.c b/drivers/builtin_openssl2/crypto/pkcs7/sign.c
index 8b59885f7e..8b59885f7e 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/sign.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/sign.c
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/3des.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/3des.pem
index b2b5081a10..b2b5081a10 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/3des.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/3des.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/3dess.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/3dess.pem
index 23f013516a..23f013516a 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/3dess.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/3dess.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/c.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/c.pem
index a4b55e321a..a4b55e321a 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/c.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/c.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/ff b/drivers/builtin_openssl2/crypto/pkcs7/t/ff
index 23f013516a..23f013516a 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/ff
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/ff
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/msie-e b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-e
index aafae69fc9..aafae69fc9 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/msie-e
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-e
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/msie-e.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-e.pem
index a2a5e24e74..a2a5e24e74 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/msie-e.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-e.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-01 b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-01
index 2c93ab6462..2c93ab6462 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-01
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-01
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-01.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-01.pem
index 9abf00b2f2..9abf00b2f2 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-01.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-01.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-02 b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-02
index 7017055965..7017055965 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-02
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-02
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-02.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-02.pem
index 279c5d830b..279c5d830b 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/msie-enc-02.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-enc-02.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/msie-s-a-e b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-s-a-e
index 0067794d70..0067794d70 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/msie-s-a-e
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-s-a-e
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/msie-s-a-e.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-s-a-e.pem
index 55dbd8f80b..55dbd8f80b 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/msie-s-a-e.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/msie-s-a-e.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/nav-smime b/drivers/builtin_openssl2/crypto/pkcs7/t/nav-smime
index 6ee4b597a1..6ee4b597a1 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/nav-smime
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/nav-smime
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/s.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/s.pem
index 4fa925b182..4fa925b182 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/s.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/s.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/t/server.pem b/drivers/builtin_openssl2/crypto/pkcs7/t/server.pem
index 989baf8709..989baf8709 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/t/server.pem
+++ b/drivers/builtin_openssl2/crypto/pkcs7/t/server.pem
diff --git a/drivers/builtin_openssl/crypto/pkcs7/verify.c b/drivers/builtin_openssl2/crypto/pkcs7/verify.c
index b40f26032e..b40f26032e 100644
--- a/drivers/builtin_openssl/crypto/pkcs7/verify.c
+++ b/drivers/builtin_openssl2/crypto/pkcs7/verify.c
diff --git a/drivers/builtin_openssl/crypto/ppccap.c b/drivers/builtin_openssl2/crypto/ppccap.c
index f71ba66aa3..f71ba66aa3 100644
--- a/drivers/builtin_openssl/crypto/ppccap.c
+++ b/drivers/builtin_openssl2/crypto/ppccap.c
diff --git a/drivers/builtin_openssl/crypto/ppccpuid.pl b/drivers/builtin_openssl2/crypto/ppccpuid.pl
index 4ba736a1d1..4ba736a1d1 100755
--- a/drivers/builtin_openssl/crypto/ppccpuid.pl
+++ b/drivers/builtin_openssl2/crypto/ppccpuid.pl
diff --git a/drivers/builtin_openssl/crypto/pqueue/pq_test.c b/drivers/builtin_openssl2/crypto/pqueue/pq_test.c
index 8d496dfc65..8d496dfc65 100644
--- a/drivers/builtin_openssl/crypto/pqueue/pq_test.c
+++ b/drivers/builtin_openssl2/crypto/pqueue/pq_test.c
diff --git a/drivers/builtin_openssl/crypto/pqueue/pqueue.c b/drivers/builtin_openssl2/crypto/pqueue/pqueue.c
index eab13a1250..eab13a1250 100644
--- a/drivers/builtin_openssl/crypto/pqueue/pqueue.c
+++ b/drivers/builtin_openssl2/crypto/pqueue/pqueue.c
diff --git a/drivers/builtin_openssl/crypto/rand/md_rand.c b/drivers/builtin_openssl2/crypto/rand/md_rand.c
index aee1c30b0a..aee1c30b0a 100644
--- a/drivers/builtin_openssl/crypto/rand/md_rand.c
+++ b/drivers/builtin_openssl2/crypto/rand/md_rand.c
diff --git a/drivers/builtin_openssl/crypto/rand/rand_egd.c b/drivers/builtin_openssl2/crypto/rand/rand_egd.c
index d53b916ebe..d53b916ebe 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_egd.c
+++ b/drivers/builtin_openssl2/crypto/rand/rand_egd.c
diff --git a/drivers/builtin_openssl/crypto/rand/rand_err.c b/drivers/builtin_openssl2/crypto/rand/rand_err.c
index c4c80fc8cc..c4c80fc8cc 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_err.c
+++ b/drivers/builtin_openssl2/crypto/rand/rand_err.c
diff --git a/drivers/builtin_openssl/crypto/rand/rand_lcl.h b/drivers/builtin_openssl2/crypto/rand/rand_lcl.h
index 618a8ec899..618a8ec899 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_lcl.h
+++ b/drivers/builtin_openssl2/crypto/rand/rand_lcl.h
diff --git a/drivers/builtin_openssl/crypto/rand/rand_lib.c b/drivers/builtin_openssl2/crypto/rand/rand_lib.c
index 5ac0e14caf..5ac0e14caf 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_lib.c
+++ b/drivers/builtin_openssl2/crypto/rand/rand_lib.c
diff --git a/drivers/builtin_openssl/crypto/rand/rand_nw.c b/drivers/builtin_openssl2/crypto/rand/rand_nw.c
index 8d5b8d2e32..8d5b8d2e32 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_nw.c
+++ b/drivers/builtin_openssl2/crypto/rand/rand_nw.c
diff --git a/drivers/builtin_openssl/crypto/rand/rand_os2.c b/drivers/builtin_openssl2/crypto/rand/rand_os2.c
index fc1e78b179..fc1e78b179 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_os2.c
+++ b/drivers/builtin_openssl2/crypto/rand/rand_os2.c
diff --git a/drivers/builtin_openssl/crypto/rand/rand_unix.c b/drivers/builtin_openssl2/crypto/rand/rand_unix.c
index e3a65571c8..e3a65571c8 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_unix.c
+++ b/drivers/builtin_openssl2/crypto/rand/rand_unix.c
diff --git a/drivers/builtin_openssl/crypto/rand/rand_vms.c b/drivers/builtin_openssl2/crypto/rand/rand_vms.c
index 0bfd8ff7e4..0bfd8ff7e4 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_vms.c
+++ b/drivers/builtin_openssl2/crypto/rand/rand_vms.c
diff --git a/drivers/builtin_openssl/crypto/rand/rand_win.c b/drivers/builtin_openssl2/crypto/rand/rand_win.c
index 34ffcd23f9..34ffcd23f9 100644
--- a/drivers/builtin_openssl/crypto/rand/rand_win.c
+++ b/drivers/builtin_openssl2/crypto/rand/rand_win.c
diff --git a/drivers/builtin_openssl/crypto/rand/randfile.c b/drivers/builtin_openssl2/crypto/rand/randfile.c
index 7f1428072d..7f1428072d 100644
--- a/drivers/builtin_openssl/crypto/rand/randfile.c
+++ b/drivers/builtin_openssl2/crypto/rand/randfile.c
diff --git a/drivers/builtin_openssl/crypto/rand/randtest.c b/drivers/builtin_openssl2/crypto/rand/randtest.c
index 9e92a70b03..9e92a70b03 100644
--- a/drivers/builtin_openssl/crypto/rand/randtest.c
+++ b/drivers/builtin_openssl2/crypto/rand/randtest.c
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2_cbc.c b/drivers/builtin_openssl2/crypto/rc2/rc2_cbc.c
index 74f48d3d87..74f48d3d87 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2_cbc.c
+++ b/drivers/builtin_openssl2/crypto/rc2/rc2_cbc.c
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2_ecb.c b/drivers/builtin_openssl2/crypto/rc2/rc2_ecb.c
index fff86c7af8..fff86c7af8 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2_ecb.c
+++ b/drivers/builtin_openssl2/crypto/rc2/rc2_ecb.c
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2_locl.h b/drivers/builtin_openssl2/crypto/rc2/rc2_locl.h
index 565cd17619..565cd17619 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2_locl.h
+++ b/drivers/builtin_openssl2/crypto/rc2/rc2_locl.h
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2_skey.c b/drivers/builtin_openssl2/crypto/rc2/rc2_skey.c
index 6668ac011f..6668ac011f 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2_skey.c
+++ b/drivers/builtin_openssl2/crypto/rc2/rc2_skey.c
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2cfb64.c b/drivers/builtin_openssl2/crypto/rc2/rc2cfb64.c
index b3a0158a6e..b3a0158a6e 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2cfb64.c
+++ b/drivers/builtin_openssl2/crypto/rc2/rc2cfb64.c
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2ofb64.c b/drivers/builtin_openssl2/crypto/rc2/rc2ofb64.c
index 9e297867ed..9e297867ed 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2ofb64.c
+++ b/drivers/builtin_openssl2/crypto/rc2/rc2ofb64.c
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2speed.c b/drivers/builtin_openssl2/crypto/rc2/rc2speed.c
index 85cf6f65bf..85cf6f65bf 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2speed.c
+++ b/drivers/builtin_openssl2/crypto/rc2/rc2speed.c
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2test.c b/drivers/builtin_openssl2/crypto/rc2/rc2test.c
index 0e117436bb..0e117436bb 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2test.c
+++ b/drivers/builtin_openssl2/crypto/rc2/rc2test.c
diff --git a/drivers/builtin_openssl/crypto/rc2/rrc2.doc b/drivers/builtin_openssl2/crypto/rc2/rrc2.doc
index f93ee003d2..f93ee003d2 100644
--- a/drivers/builtin_openssl/crypto/rc2/rrc2.doc
+++ b/drivers/builtin_openssl2/crypto/rc2/rrc2.doc
diff --git a/drivers/builtin_openssl/crypto/rc2/tab.c b/drivers/builtin_openssl2/crypto/rc2/tab.c
index 25dc14eeba..25dc14eeba 100644
--- a/drivers/builtin_openssl/crypto/rc2/tab.c
+++ b/drivers/builtin_openssl2/crypto/rc2/tab.c
diff --git a/drivers/builtin_openssl/crypto/rc2/version b/drivers/builtin_openssl2/crypto/rc2/version
index 6f89d595f1..6f89d595f1 100644
--- a/drivers/builtin_openssl/crypto/rc2/version
+++ b/drivers/builtin_openssl2/crypto/rc2/version
diff --git a/drivers/builtin_openssl/crypto/rc4/asm/rc4-586.pl b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-586.pl
index 5c9ac6ad28..5c9ac6ad28 100644
--- a/drivers/builtin_openssl/crypto/rc4/asm/rc4-586.pl
+++ b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-586.pl
diff --git a/drivers/builtin_openssl/crypto/rc4/asm/rc4-ia64.pl b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-ia64.pl
index 49cd5b5e69..49cd5b5e69 100644
--- a/drivers/builtin_openssl/crypto/rc4/asm/rc4-ia64.pl
+++ b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-ia64.pl
diff --git a/drivers/builtin_openssl/crypto/rc4/asm/rc4-md5-x86_64.pl b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-md5-x86_64.pl
index 272fa91e1a..272fa91e1a 100644
--- a/drivers/builtin_openssl/crypto/rc4/asm/rc4-md5-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-md5-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/rc4/asm/rc4-parisc.pl b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-parisc.pl
index ad7e65651c..ad7e65651c 100644
--- a/drivers/builtin_openssl/crypto/rc4/asm/rc4-parisc.pl
+++ b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-parisc.pl
diff --git a/drivers/builtin_openssl/crypto/rc4/asm/rc4-s390x.pl b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-s390x.pl
index 7528ece13c..7528ece13c 100644
--- a/drivers/builtin_openssl/crypto/rc4/asm/rc4-s390x.pl
+++ b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-s390x.pl
diff --git a/drivers/builtin_openssl/crypto/rc4/asm/rc4-x86_64.pl b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-x86_64.pl
index 75750dbf33..75750dbf33 100755
--- a/drivers/builtin_openssl/crypto/rc4/asm/rc4-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/rc4/asm/rc4-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4.c b/drivers/builtin_openssl2/crypto/rc4/rc4.c
index c900b26055..c900b26055 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4.c
+++ b/drivers/builtin_openssl2/crypto/rc4/rc4.c
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4_enc.c b/drivers/builtin_openssl2/crypto/rc4/rc4_enc.c
index 8c4fc6c7a3..8c4fc6c7a3 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4_enc.c
+++ b/drivers/builtin_openssl2/crypto/rc4/rc4_enc.c
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4_locl.h b/drivers/builtin_openssl2/crypto/rc4/rc4_locl.h
index c712e1632e..c712e1632e 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4_locl.h
+++ b/drivers/builtin_openssl2/crypto/rc4/rc4_locl.h
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4_skey.c b/drivers/builtin_openssl2/crypto/rc4/rc4_skey.c
index fda27636e7..fda27636e7 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4_skey.c
+++ b/drivers/builtin_openssl2/crypto/rc4/rc4_skey.c
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4_utl.c b/drivers/builtin_openssl2/crypto/rc4/rc4_utl.c
index ab3f02fe6a..ab3f02fe6a 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4_utl.c
+++ b/drivers/builtin_openssl2/crypto/rc4/rc4_utl.c
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4s.cpp b/drivers/builtin_openssl2/crypto/rc4/rc4s.cpp
index 3814fde997..3814fde997 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4s.cpp
+++ b/drivers/builtin_openssl2/crypto/rc4/rc4s.cpp
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4speed.c b/drivers/builtin_openssl2/crypto/rc4/rc4speed.c
index 0ebd38123d..0ebd38123d 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4speed.c
+++ b/drivers/builtin_openssl2/crypto/rc4/rc4speed.c
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4test.c b/drivers/builtin_openssl2/crypto/rc4/rc4test.c
index 4312605ccb..4312605ccb 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4test.c
+++ b/drivers/builtin_openssl2/crypto/rc4/rc4test.c
diff --git a/drivers/builtin_openssl/crypto/rc4/rrc4.doc b/drivers/builtin_openssl2/crypto/rc4/rrc4.doc
index 2f9a953c12..2f9a953c12 100644
--- a/drivers/builtin_openssl/crypto/rc4/rrc4.doc
+++ b/drivers/builtin_openssl2/crypto/rc4/rrc4.doc
diff --git a/drivers/builtin_openssl/crypto/rc5/asm/rc5-586.pl b/drivers/builtin_openssl2/crypto/rc5/asm/rc5-586.pl
index 61ac6effc6..61ac6effc6 100644
--- a/drivers/builtin_openssl/crypto/rc5/asm/rc5-586.pl
+++ b/drivers/builtin_openssl2/crypto/rc5/asm/rc5-586.pl
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5.h b/drivers/builtin_openssl2/crypto/rc5/rc5.h
index 4b3c153b50..4b3c153b50 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5.h
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5.h
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5_ecb.c b/drivers/builtin_openssl2/crypto/rc5/rc5_ecb.c
index e72b535507..e72b535507 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5_ecb.c
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5_ecb.c
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5_enc.c b/drivers/builtin_openssl2/crypto/rc5/rc5_enc.c
index f327d32a76..f327d32a76 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5_enc.c
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5_enc.c
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5_locl.h b/drivers/builtin_openssl2/crypto/rc5/rc5_locl.h
index d337f73fad..d337f73fad 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5_locl.h
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5_locl.h
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5_skey.c b/drivers/builtin_openssl2/crypto/rc5/rc5_skey.c
index a2e00a41c5..a2e00a41c5 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5_skey.c
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5_skey.c
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5cfb64.c b/drivers/builtin_openssl2/crypto/rc5/rc5cfb64.c
index 3a8b60bc7a..3a8b60bc7a 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5cfb64.c
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5cfb64.c
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5ofb64.c b/drivers/builtin_openssl2/crypto/rc5/rc5ofb64.c
index d412215f3c..d412215f3c 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5ofb64.c
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5ofb64.c
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5s.cpp b/drivers/builtin_openssl2/crypto/rc5/rc5s.cpp
index 1c5518bc80..1c5518bc80 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5s.cpp
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5s.cpp
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5speed.c b/drivers/builtin_openssl2/crypto/rc5/rc5speed.c
index 8e363be535..8e363be535 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5speed.c
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5speed.c
diff --git a/drivers/builtin_openssl/crypto/rc5/rc5test.c b/drivers/builtin_openssl2/crypto/rc5/rc5test.c
index ce3d0cc16f..ce3d0cc16f 100644
--- a/drivers/builtin_openssl/crypto/rc5/rc5test.c
+++ b/drivers/builtin_openssl2/crypto/rc5/rc5test.c
diff --git a/drivers/builtin_openssl/crypto/ripemd/README b/drivers/builtin_openssl2/crypto/ripemd/README
index f1ffc8b134..f1ffc8b134 100644
--- a/drivers/builtin_openssl/crypto/ripemd/README
+++ b/drivers/builtin_openssl2/crypto/ripemd/README
diff --git a/drivers/builtin_openssl/crypto/ripemd/asm/rips.cpp b/drivers/builtin_openssl2/crypto/ripemd/asm/rips.cpp
index f7a13677a9..f7a13677a9 100644
--- a/drivers/builtin_openssl/crypto/ripemd/asm/rips.cpp
+++ b/drivers/builtin_openssl2/crypto/ripemd/asm/rips.cpp
diff --git a/drivers/builtin_openssl/crypto/ripemd/asm/rmd-586.pl b/drivers/builtin_openssl2/crypto/ripemd/asm/rmd-586.pl
index e8b2bc2db2..e8b2bc2db2 100644
--- a/drivers/builtin_openssl/crypto/ripemd/asm/rmd-586.pl
+++ b/drivers/builtin_openssl2/crypto/ripemd/asm/rmd-586.pl
diff --git a/drivers/builtin_openssl/crypto/ripemd/rmd160.c b/drivers/builtin_openssl2/crypto/ripemd/rmd160.c
index b0ec574498..b0ec574498 100644
--- a/drivers/builtin_openssl/crypto/ripemd/rmd160.c
+++ b/drivers/builtin_openssl2/crypto/ripemd/rmd160.c
diff --git a/drivers/builtin_openssl/crypto/ripemd/rmd_dgst.c b/drivers/builtin_openssl2/crypto/ripemd/rmd_dgst.c
index d8e72da51b..d8e72da51b 100644
--- a/drivers/builtin_openssl/crypto/ripemd/rmd_dgst.c
+++ b/drivers/builtin_openssl2/crypto/ripemd/rmd_dgst.c
diff --git a/drivers/builtin_openssl/crypto/ripemd/rmd_locl.h b/drivers/builtin_openssl2/crypto/ripemd/rmd_locl.h
index 2bd8957d14..2bd8957d14 100644
--- a/drivers/builtin_openssl/crypto/ripemd/rmd_locl.h
+++ b/drivers/builtin_openssl2/crypto/ripemd/rmd_locl.h
diff --git a/drivers/builtin_openssl/crypto/ripemd/rmd_one.c b/drivers/builtin_openssl2/crypto/ripemd/rmd_one.c
index 3efb13758f..3efb13758f 100644
--- a/drivers/builtin_openssl/crypto/ripemd/rmd_one.c
+++ b/drivers/builtin_openssl2/crypto/ripemd/rmd_one.c
diff --git a/drivers/builtin_openssl/crypto/ripemd/rmdconst.h b/drivers/builtin_openssl2/crypto/ripemd/rmdconst.h
index 59c48dead1..59c48dead1 100644
--- a/drivers/builtin_openssl/crypto/ripemd/rmdconst.h
+++ b/drivers/builtin_openssl2/crypto/ripemd/rmdconst.h
diff --git a/drivers/builtin_openssl/crypto/ripemd/rmdtest.c b/drivers/builtin_openssl2/crypto/ripemd/rmdtest.c
index fb34e0e836..fb34e0e836 100644
--- a/drivers/builtin_openssl/crypto/ripemd/rmdtest.c
+++ b/drivers/builtin_openssl2/crypto/ripemd/rmdtest.c
diff --git a/drivers/builtin_openssl2/crypto/rsa/rsa_ameth.c b/drivers/builtin_openssl2/crypto/rsa/rsa_ameth.c
new file mode 100644
index 0000000000..4c8ecd9233
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_ameth.c
@@ -0,0 +1,698 @@
+/* crypto/rsa/rsa_ameth.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/rsa.h>
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_CMS
+#include <openssl/cms.h>
+#endif
+#include "asn1_locl.h"
+
+static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
+ {
+ unsigned char *penc = NULL;
+ int penclen;
+ penclen = i2d_RSAPublicKey(pkey->pkey.rsa, &penc);
+ if (penclen <= 0)
+ return 0;
+ if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA),
+ V_ASN1_NULL, NULL, penc, penclen))
+ return 1;
+
+ OPENSSL_free(penc);
+ return 0;
+ }
+
+static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
+ {
+ const unsigned char *p;
+ int pklen;
+ RSA *rsa = NULL;
+ if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey))
+ return 0;
+ if (!(rsa = d2i_RSAPublicKey(NULL, &p, pklen)))
+ {
+ RSAerr(RSA_F_RSA_PUB_DECODE, ERR_R_RSA_LIB);
+ return 0;
+ }
+ EVP_PKEY_assign_RSA (pkey, rsa);
+ return 1;
+ }
+
+static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
+ {
+ if (BN_cmp(b->pkey.rsa->n,a->pkey.rsa->n) != 0
+ || BN_cmp(b->pkey.rsa->e,a->pkey.rsa->e) != 0)
+ return 0;
+ return 1;
+ }
+
+static int old_rsa_priv_decode(EVP_PKEY *pkey,
+ const unsigned char **pder, int derlen)
+ {
+ RSA *rsa;
+ if (!(rsa = d2i_RSAPrivateKey (NULL, pder, derlen)))
+ {
+ RSAerr(RSA_F_OLD_RSA_PRIV_DECODE, ERR_R_RSA_LIB);
+ return 0;
+ }
+ EVP_PKEY_assign_RSA(pkey, rsa);
+ return 1;
+ }
+
+static int old_rsa_priv_encode(const EVP_PKEY *pkey, unsigned char **pder)
+ {
+ return i2d_RSAPrivateKey(pkey->pkey.rsa, pder);
+ }
+
+static int rsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
+ {
+ unsigned char *rk = NULL;
+ int rklen;
+ rklen = i2d_RSAPrivateKey(pkey->pkey.rsa, &rk);
+
+ if (rklen <= 0)
+ {
+ RSAerr(RSA_F_RSA_PRIV_ENCODE,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_rsaEncryption), 0,
+ V_ASN1_NULL, NULL, rk, rklen))
+ {
+ RSAerr(RSA_F_RSA_PRIV_ENCODE,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ return 1;
+ }
+
+static int rsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
+ {
+ const unsigned char *p;
+ int pklen;
+ if (!PKCS8_pkey_get0(NULL, &p, &pklen, NULL, p8))
+ return 0;
+ return old_rsa_priv_decode(pkey, &p, pklen);
+ }
+
+static int int_rsa_size(const EVP_PKEY *pkey)
+ {
+ return RSA_size(pkey->pkey.rsa);
+ }
+
+static int rsa_bits(const EVP_PKEY *pkey)
+ {
+ return BN_num_bits(pkey->pkey.rsa->n);
+ }
+
+static void int_rsa_free(EVP_PKEY *pkey)
+ {
+ RSA_free(pkey->pkey.rsa);
+ }
+
+
+static void update_buflen(const BIGNUM *b, size_t *pbuflen)
+ {
+ size_t i;
+ if (!b)
+ return;
+ if (*pbuflen < (i = (size_t)BN_num_bytes(b)))
+ *pbuflen = i;
+ }
+
+static int do_rsa_print(BIO *bp, const RSA *x, int off, int priv)
+ {
+ char *str;
+ const char *s;
+ unsigned char *m=NULL;
+ int ret=0, mod_len = 0;
+ size_t buf_len=0;
+
+ update_buflen(x->n, &buf_len);
+ update_buflen(x->e, &buf_len);
+
+ if (priv)
+ {
+ update_buflen(x->d, &buf_len);
+ update_buflen(x->p, &buf_len);
+ update_buflen(x->q, &buf_len);
+ update_buflen(x->dmp1, &buf_len);
+ update_buflen(x->dmq1, &buf_len);
+ update_buflen(x->iqmp, &buf_len);
+ }
+
+ m=(unsigned char *)OPENSSL_malloc(buf_len+10);
+ if (m == NULL)
+ {
+ RSAerr(RSA_F_DO_RSA_PRINT,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (x->n != NULL)
+ mod_len = BN_num_bits(x->n);
+
+ if(!BIO_indent(bp,off,128))
+ goto err;
+
+ if (priv && x->d)
+ {
+ if (BIO_printf(bp,"Private-Key: (%d bit)\n", mod_len)
+ <= 0) goto err;
+ str = "modulus:";
+ s = "publicExponent:";
+ }
+ else
+ {
+ if (BIO_printf(bp,"Public-Key: (%d bit)\n", mod_len)
+ <= 0) goto err;
+ str = "Modulus:";
+ s= "Exponent:";
+ }
+ if (!ASN1_bn_print(bp,str,x->n,m,off)) goto err;
+ if (!ASN1_bn_print(bp,s,x->e,m,off))
+ goto err;
+ if (priv)
+ {
+ if (!ASN1_bn_print(bp,"privateExponent:",x->d,m,off))
+ goto err;
+ if (!ASN1_bn_print(bp,"prime1:",x->p,m,off))
+ goto err;
+ if (!ASN1_bn_print(bp,"prime2:",x->q,m,off))
+ goto err;
+ if (!ASN1_bn_print(bp,"exponent1:",x->dmp1,m,off))
+ goto err;
+ if (!ASN1_bn_print(bp,"exponent2:",x->dmq1,m,off))
+ goto err;
+ if (!ASN1_bn_print(bp,"coefficient:",x->iqmp,m,off))
+ goto err;
+ }
+ ret=1;
+err:
+ if (m != NULL) OPENSSL_free(m);
+ return(ret);
+ }
+
+static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx)
+ {
+ return do_rsa_print(bp, pkey->pkey.rsa, indent, 0);
+ }
+
+
+static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx)
+ {
+ return do_rsa_print(bp, pkey->pkey.rsa, indent, 1);
+ }
+
+static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg,
+ X509_ALGOR **pmaskHash)
+ {
+ const unsigned char *p;
+ int plen;
+ RSA_PSS_PARAMS *pss;
+
+ *pmaskHash = NULL;
+
+ if (!alg->parameter || alg->parameter->type != V_ASN1_SEQUENCE)
+ return NULL;
+ p = alg->parameter->value.sequence->data;
+ plen = alg->parameter->value.sequence->length;
+ pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen);
+
+ if (!pss)
+ return NULL;
+
+ if (pss->maskGenAlgorithm)
+ {
+ ASN1_TYPE *param = pss->maskGenAlgorithm->parameter;
+ if (OBJ_obj2nid(pss->maskGenAlgorithm->algorithm) == NID_mgf1
+ && param->type == V_ASN1_SEQUENCE)
+ {
+ p = param->value.sequence->data;
+ plen = param->value.sequence->length;
+ *pmaskHash = d2i_X509_ALGOR(NULL, &p, plen);
+ }
+ }
+
+ return pss;
+ }
+
+static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss,
+ X509_ALGOR *maskHash, int indent)
+ {
+ int rv = 0;
+ if (!pss)
+ {
+ if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0)
+ return 0;
+ return 1;
+ }
+ if (BIO_puts(bp, "\n") <= 0)
+ goto err;
+ if (!BIO_indent(bp, indent, 128))
+ goto err;
+ if (BIO_puts(bp, "Hash Algorithm: ") <= 0)
+ goto err;
+
+ if (pss->hashAlgorithm)
+ {
+ if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0)
+ goto err;
+ }
+ else if (BIO_puts(bp, "sha1 (default)") <= 0)
+ goto err;
+
+ if (BIO_puts(bp, "\n") <= 0)
+ goto err;
+
+ if (!BIO_indent(bp, indent, 128))
+ goto err;
+
+ if (BIO_puts(bp, "Mask Algorithm: ") <= 0)
+ goto err;
+ if (pss->maskGenAlgorithm)
+ {
+ if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0)
+ goto err;
+ if (BIO_puts(bp, " with ") <= 0)
+ goto err;
+ if (maskHash)
+ {
+ if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0)
+ goto err;
+ }
+ else if (BIO_puts(bp, "INVALID") <= 0)
+ goto err;
+ }
+ else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0)
+ goto err;
+ BIO_puts(bp, "\n");
+
+ if (!BIO_indent(bp, indent, 128))
+ goto err;
+ if (BIO_puts(bp, "Salt Length: 0x") <= 0)
+ goto err;
+ if (pss->saltLength)
+ {
+ if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0)
+ goto err;
+ }
+ else if (BIO_puts(bp, "14 (default)") <= 0)
+ goto err;
+ BIO_puts(bp, "\n");
+
+ if (!BIO_indent(bp, indent, 128))
+ goto err;
+ if (BIO_puts(bp, "Trailer Field: 0x") <= 0)
+ goto err;
+ if (pss->trailerField)
+ {
+ if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0)
+ goto err;
+ }
+ else if (BIO_puts(bp, "BC (default)") <= 0)
+ goto err;
+ BIO_puts(bp, "\n");
+
+ rv = 1;
+
+ err:
+ return rv;
+
+ }
+
+static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
+ const ASN1_STRING *sig,
+ int indent, ASN1_PCTX *pctx)
+ {
+ if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss)
+ {
+ int rv;
+ RSA_PSS_PARAMS *pss;
+ X509_ALGOR *maskHash;
+ pss = rsa_pss_decode(sigalg, &maskHash);
+ rv = rsa_pss_param_print(bp, pss, maskHash, indent);
+ if (pss)
+ RSA_PSS_PARAMS_free(pss);
+ if (maskHash)
+ X509_ALGOR_free(maskHash);
+ if (!rv)
+ return 0;
+ }
+ else if (!sig && BIO_puts(bp, "\n") <= 0)
+ return 0;
+ if (sig)
+ return X509_signature_dump(bp, sig, indent);
+ return 1;
+ }
+
+static int rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
+ {
+ X509_ALGOR *alg = NULL;
+ switch (op)
+ {
+
+ case ASN1_PKEY_CTRL_PKCS7_SIGN:
+ if (arg1 == 0)
+ PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, NULL, &alg);
+ break;
+
+ case ASN1_PKEY_CTRL_PKCS7_ENCRYPT:
+ if (arg1 == 0)
+ PKCS7_RECIP_INFO_get0_alg(arg2, &alg);
+ break;
+#ifndef OPENSSL_NO_CMS
+ case ASN1_PKEY_CTRL_CMS_SIGN:
+ if (arg1 == 0)
+ CMS_SignerInfo_get0_algs(arg2, NULL, NULL, NULL, &alg);
+ break;
+
+ case ASN1_PKEY_CTRL_CMS_ENVELOPE:
+ if (arg1 == 0)
+ CMS_RecipientInfo_ktri_get0_algs(arg2, NULL, NULL, &alg);
+ break;
+#endif
+
+ case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+ *(int *)arg2 = NID_sha1;
+ return 1;
+
+ default:
+ return -2;
+
+ }
+
+ if (alg)
+ X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption),
+ V_ASN1_NULL, 0);
+
+ return 1;
+
+ }
+
+/* Customised RSA item verification routine. This is called
+ * when a signature is encountered requiring special handling. We
+ * currently only handle PSS.
+ */
+
+
+static int rsa_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+ X509_ALGOR *sigalg, ASN1_BIT_STRING *sig,
+ EVP_PKEY *pkey)
+ {
+ int rv = -1;
+ int saltlen;
+ const EVP_MD *mgf1md = NULL, *md = NULL;
+ RSA_PSS_PARAMS *pss;
+ X509_ALGOR *maskHash;
+ EVP_PKEY_CTX *pkctx;
+ /* Sanity check: make sure it is PSS */
+ if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss)
+ {
+ RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_SIGNATURE_TYPE);
+ return -1;
+ }
+ /* Decode PSS parameters */
+ pss = rsa_pss_decode(sigalg, &maskHash);
+
+ if (pss == NULL)
+ {
+ RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_INVALID_PSS_PARAMETERS);
+ goto err;
+ }
+ /* Check mask and lookup mask hash algorithm */
+ if (pss->maskGenAlgorithm)
+ {
+ if (OBJ_obj2nid(pss->maskGenAlgorithm->algorithm) != NID_mgf1)
+ {
+ RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_MASK_ALGORITHM);
+ goto err;
+ }
+ if (!maskHash)
+ {
+ RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_MASK_PARAMETER);
+ goto err;
+ }
+ mgf1md = EVP_get_digestbyobj(maskHash->algorithm);
+ if (mgf1md == NULL)
+ {
+ RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNKNOWN_MASK_DIGEST);
+ goto err;
+ }
+ }
+ else
+ mgf1md = EVP_sha1();
+
+ if (pss->hashAlgorithm)
+ {
+ md = EVP_get_digestbyobj(pss->hashAlgorithm->algorithm);
+ if (md == NULL)
+ {
+ RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNKNOWN_PSS_DIGEST);
+ goto err;
+ }
+ }
+ else
+ md = EVP_sha1();
+
+ if (pss->saltLength)
+ {
+ saltlen = ASN1_INTEGER_get(pss->saltLength);
+
+ /* Could perform more salt length sanity checks but the main
+ * RSA routines will trap other invalid values anyway.
+ */
+ if (saltlen < 0)
+ {
+ RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_INVALID_SALT_LENGTH);
+ goto err;
+ }
+ }
+ else
+ saltlen = 20;
+
+ /* low-level routines support only trailer field 0xbc (value 1)
+ * and PKCS#1 says we should reject any other value anyway.
+ */
+ if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1)
+ {
+ RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_INVALID_TRAILER);
+ goto err;
+ }
+
+ /* We have all parameters now set up context */
+
+ if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey))
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0)
+ goto err;
+ /* Carry on */
+ rv = 2;
+
+ err:
+ RSA_PSS_PARAMS_free(pss);
+ if (maskHash)
+ X509_ALGOR_free(maskHash);
+ return rv;
+ }
+
+static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+ X509_ALGOR *alg1, X509_ALGOR *alg2,
+ ASN1_BIT_STRING *sig)
+ {
+ int pad_mode;
+ EVP_PKEY_CTX *pkctx = ctx->pctx;
+ if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
+ return 0;
+ if (pad_mode == RSA_PKCS1_PADDING)
+ return 2;
+ if (pad_mode == RSA_PKCS1_PSS_PADDING)
+ {
+ const EVP_MD *sigmd, *mgf1md;
+ RSA_PSS_PARAMS *pss = NULL;
+ X509_ALGOR *mgf1alg = NULL;
+ ASN1_STRING *os1 = NULL, *os2 = NULL;
+ EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx);
+ int saltlen, rv = 0;
+ sigmd = EVP_MD_CTX_md(ctx);
+ if (EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0)
+ goto err;
+ if (!EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen))
+ goto err;
+ if (saltlen == -1)
+ saltlen = EVP_MD_size(sigmd);
+ else if (saltlen == -2)
+ {
+ saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2;
+ if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0)
+ saltlen--;
+ }
+ pss = RSA_PSS_PARAMS_new();
+ if (!pss)
+ goto err;
+ if (saltlen != 20)
+ {
+ pss->saltLength = ASN1_INTEGER_new();
+ if (!pss->saltLength)
+ goto err;
+ if (!ASN1_INTEGER_set(pss->saltLength, saltlen))
+ goto err;
+ }
+ if (EVP_MD_type(sigmd) != NID_sha1)
+ {
+ pss->hashAlgorithm = X509_ALGOR_new();
+ if (!pss->hashAlgorithm)
+ goto err;
+ X509_ALGOR_set_md(pss->hashAlgorithm, sigmd);
+ }
+ if (EVP_MD_type(mgf1md) != NID_sha1)
+ {
+ ASN1_STRING *stmp = NULL;
+ /* need to embed algorithm ID inside another */
+ mgf1alg = X509_ALGOR_new();
+ X509_ALGOR_set_md(mgf1alg, mgf1md);
+ if (!ASN1_item_pack(mgf1alg, ASN1_ITEM_rptr(X509_ALGOR),
+ &stmp))
+ goto err;
+ pss->maskGenAlgorithm = X509_ALGOR_new();
+ if (!pss->maskGenAlgorithm)
+ goto err;
+ X509_ALGOR_set0(pss->maskGenAlgorithm,
+ OBJ_nid2obj(NID_mgf1),
+ V_ASN1_SEQUENCE, stmp);
+ }
+ /* Finally create string with pss parameter encoding. */
+ if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os1))
+ goto err;
+ if (alg2)
+ {
+ os2 = ASN1_STRING_dup(os1);
+ if (!os2)
+ goto err;
+ X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_rsassaPss),
+ V_ASN1_SEQUENCE, os2);
+ }
+ X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_rsassaPss),
+ V_ASN1_SEQUENCE, os1);
+ os1 = os2 = NULL;
+ rv = 3;
+ err:
+ if (mgf1alg)
+ X509_ALGOR_free(mgf1alg);
+ if (pss)
+ RSA_PSS_PARAMS_free(pss);
+ if (os1)
+ ASN1_STRING_free(os1);
+ return rv;
+
+ }
+ return 2;
+ }
+
+const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] =
+ {
+ {
+ EVP_PKEY_RSA,
+ EVP_PKEY_RSA,
+ ASN1_PKEY_SIGPARAM_NULL,
+
+ "RSA",
+ "OpenSSL RSA method",
+
+ rsa_pub_decode,
+ rsa_pub_encode,
+ rsa_pub_cmp,
+ rsa_pub_print,
+
+ rsa_priv_decode,
+ rsa_priv_encode,
+ rsa_priv_print,
+
+ int_rsa_size,
+ rsa_bits,
+
+ 0,0,0,0,0,0,
+
+ rsa_sig_print,
+ int_rsa_free,
+ rsa_pkey_ctrl,
+ old_rsa_priv_decode,
+ old_rsa_priv_encode,
+ rsa_item_verify,
+ rsa_item_sign
+ },
+
+ {
+ EVP_PKEY_RSA2,
+ EVP_PKEY_RSA,
+ ASN1_PKEY_ALIAS
+ }
+ };
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_asn1.c b/drivers/builtin_openssl2/crypto/rsa/rsa_asn1.c
index 6ed5de3db4..6ed5de3db4 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_asn1.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_asn1.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_chk.c b/drivers/builtin_openssl2/crypto/rsa/rsa_chk.c
index cc30e77132..cc30e77132 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_chk.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_chk.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_crpt.c b/drivers/builtin_openssl2/crypto/rsa/rsa_crpt.c
index d3e44785dc..d3e44785dc 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_crpt.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_crpt.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_depr.c b/drivers/builtin_openssl2/crypto/rsa/rsa_depr.c
index a859ded987..a859ded987 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_depr.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_depr.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_eay.c b/drivers/builtin_openssl2/crypto/rsa/rsa_eay.c
index 88ee2cb557..88ee2cb557 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_eay.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_eay.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_err.c b/drivers/builtin_openssl2/crypto/rsa/rsa_err.c
index 46e0bf9980..46e0bf9980 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_err.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_err.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_gen.c b/drivers/builtin_openssl2/crypto/rsa/rsa_gen.c
index 42290cce66..42290cce66 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_gen.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_gen.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_lib.c b/drivers/builtin_openssl2/crypto/rsa/rsa_lib.c
index c95ceafc82..c95ceafc82 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_lib.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_lib.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_locl.h b/drivers/builtin_openssl2/crypto/rsa/rsa_locl.h
index f5d2d56628..f5d2d56628 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_locl.h
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_locl.h
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_none.c b/drivers/builtin_openssl2/crypto/rsa/rsa_none.c
index e6f3e627ca..e6f3e627ca 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_none.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_none.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_null.c b/drivers/builtin_openssl2/crypto/rsa/rsa_null.c
index 2f2202f142..2f2202f142 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_null.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_null.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_oaep.c b/drivers/builtin_openssl2/crypto/rsa/rsa_oaep.c
index af4d24a56e..af4d24a56e 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_oaep.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_oaep.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_pk1.c b/drivers/builtin_openssl2/crypto/rsa/rsa_pk1.c
index 8560755f1d..8560755f1d 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_pk1.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_pk1.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_pmeth.c b/drivers/builtin_openssl2/crypto/rsa/rsa_pmeth.c
index 157aa5c41d..157aa5c41d 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_pmeth.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_pmeth.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_prn.c b/drivers/builtin_openssl2/crypto/rsa/rsa_prn.c
index 224db0fae5..224db0fae5 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_prn.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_prn.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_pss.c b/drivers/builtin_openssl2/crypto/rsa/rsa_pss.c
index 5f9f533d0c..5f9f533d0c 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_pss.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_pss.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_saos.c b/drivers/builtin_openssl2/crypto/rsa/rsa_saos.c
index f98e0a80a6..f98e0a80a6 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_saos.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_saos.c
diff --git a/drivers/builtin_openssl2/crypto/rsa/rsa_sign.c b/drivers/builtin_openssl2/crypto/rsa/rsa_sign.c
new file mode 100644
index 0000000000..b6f6037ae0
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_sign.c
@@ -0,0 +1,318 @@
+/* crypto/rsa/rsa_sign.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include "rsa_locl.h"
+
+/* Size of an SSL signature: MD5+SHA1 */
+#define SSL_SIG_LENGTH 36
+
+int RSA_sign(int type, const unsigned char *m, unsigned int m_len,
+ unsigned char *sigret, unsigned int *siglen, RSA *rsa)
+ {
+ X509_SIG sig;
+ ASN1_TYPE parameter;
+ int i,j,ret=1;
+ unsigned char *p, *tmps = NULL;
+ const unsigned char *s = NULL;
+ X509_ALGOR algor;
+ ASN1_OCTET_STRING digest;
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode() && !(rsa->meth->flags & RSA_FLAG_FIPS_METHOD)
+ && !(rsa->flags & RSA_FLAG_NON_FIPS_ALLOW))
+ {
+ RSAerr(RSA_F_RSA_SIGN, RSA_R_NON_FIPS_RSA_METHOD);
+ return 0;
+ }
+#endif
+ if((rsa->flags & RSA_FLAG_SIGN_VER) && rsa->meth->rsa_sign)
+ {
+ return rsa->meth->rsa_sign(type, m, m_len,
+ sigret, siglen, rsa);
+ }
+ /* Special case: SSL signature, just check the length */
+ if(type == NID_md5_sha1) {
+ if(m_len != SSL_SIG_LENGTH) {
+ RSAerr(RSA_F_RSA_SIGN,RSA_R_INVALID_MESSAGE_LENGTH);
+ return(0);
+ }
+ i = SSL_SIG_LENGTH;
+ s = m;
+ } else {
+ sig.algor= &algor;
+ sig.algor->algorithm=OBJ_nid2obj(type);
+ if (sig.algor->algorithm == NULL)
+ {
+ RSAerr(RSA_F_RSA_SIGN,RSA_R_UNKNOWN_ALGORITHM_TYPE);
+ return(0);
+ }
+ if (sig.algor->algorithm->length == 0)
+ {
+ RSAerr(RSA_F_RSA_SIGN,RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD);
+ return(0);
+ }
+ parameter.type=V_ASN1_NULL;
+ parameter.value.ptr=NULL;
+ sig.algor->parameter= &parameter;
+
+ sig.digest= &digest;
+ sig.digest->data=(unsigned char *)m; /* TMP UGLY CAST */
+ sig.digest->length=m_len;
+
+ i=i2d_X509_SIG(&sig,NULL);
+ }
+ j=RSA_size(rsa);
+ if (i > (j-RSA_PKCS1_PADDING_SIZE))
+ {
+ RSAerr(RSA_F_RSA_SIGN,RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
+ return(0);
+ }
+ if(type != NID_md5_sha1) {
+ tmps=(unsigned char *)OPENSSL_malloc((unsigned int)j+1);
+ if (tmps == NULL)
+ {
+ RSAerr(RSA_F_RSA_SIGN,ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+ p=tmps;
+ i2d_X509_SIG(&sig,&p);
+ s=tmps;
+ }
+ i=RSA_private_encrypt(i,s,sigret,rsa,RSA_PKCS1_PADDING);
+ if (i <= 0)
+ ret=0;
+ else
+ *siglen=i;
+
+ if(type != NID_md5_sha1) {
+ OPENSSL_cleanse(tmps,(unsigned int)j+1);
+ OPENSSL_free(tmps);
+ }
+ return(ret);
+ }
+
+int int_rsa_verify(int dtype, const unsigned char *m,
+ unsigned int m_len,
+ unsigned char *rm, size_t *prm_len,
+ const unsigned char *sigbuf, size_t siglen,
+ RSA *rsa)
+ {
+ int i,ret=0,sigtype;
+ unsigned char *s;
+ X509_SIG *sig=NULL;
+
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode() && !(rsa->meth->flags & RSA_FLAG_FIPS_METHOD)
+ && !(rsa->flags & RSA_FLAG_NON_FIPS_ALLOW))
+ {
+ RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_NON_FIPS_RSA_METHOD);
+ return 0;
+ }
+#endif
+
+ if (siglen != (unsigned int)RSA_size(rsa))
+ {
+ RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_WRONG_SIGNATURE_LENGTH);
+ return(0);
+ }
+
+ if((dtype == NID_md5_sha1) && rm)
+ {
+ i = RSA_public_decrypt((int)siglen,
+ sigbuf,rm,rsa,RSA_PKCS1_PADDING);
+ if (i <= 0)
+ return 0;
+ *prm_len = i;
+ return 1;
+ }
+
+ s=(unsigned char *)OPENSSL_malloc((unsigned int)siglen);
+ if (s == NULL)
+ {
+ RSAerr(RSA_F_INT_RSA_VERIFY,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if((dtype == NID_md5_sha1) && (m_len != SSL_SIG_LENGTH) ) {
+ RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_INVALID_MESSAGE_LENGTH);
+ goto err;
+ }
+ i=RSA_public_decrypt((int)siglen,sigbuf,s,rsa,RSA_PKCS1_PADDING);
+
+ if (i <= 0) goto err;
+ /* Oddball MDC2 case: signature can be OCTET STRING.
+ * check for correct tag and length octets.
+ */
+ if (dtype == NID_mdc2 && i == 18 && s[0] == 0x04 && s[1] == 0x10)
+ {
+ if (rm)
+ {
+ memcpy(rm, s + 2, 16);
+ *prm_len = 16;
+ ret = 1;
+ }
+ else if(memcmp(m, s + 2, 16))
+ RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
+ else
+ ret = 1;
+ }
+
+ /* Special case: SSL signature */
+ if(dtype == NID_md5_sha1) {
+ if((i != SSL_SIG_LENGTH) || memcmp(s, m, SSL_SIG_LENGTH))
+ RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
+ else ret = 1;
+ } else {
+ const unsigned char *p=s;
+ sig=d2i_X509_SIG(NULL,&p,(long)i);
+
+ if (sig == NULL) goto err;
+
+ /* Excess data can be used to create forgeries */
+ if(p != s+i)
+ {
+ RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
+ goto err;
+ }
+
+ /* Parameters to the signature algorithm can also be used to
+ create forgeries */
+ if(sig->algor->parameter
+ && ASN1_TYPE_get(sig->algor->parameter) != V_ASN1_NULL)
+ {
+ RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
+ goto err;
+ }
+
+ sigtype=OBJ_obj2nid(sig->algor->algorithm);
+
+
+ #ifdef RSA_DEBUG
+ /* put a backward compatibility flag in EAY */
+ fprintf(stderr,"in(%s) expect(%s)\n",OBJ_nid2ln(sigtype),
+ OBJ_nid2ln(dtype));
+ #endif
+ if (sigtype != dtype)
+ {
+ if (((dtype == NID_md5) &&
+ (sigtype == NID_md5WithRSAEncryption)) ||
+ ((dtype == NID_md2) &&
+ (sigtype == NID_md2WithRSAEncryption)))
+ {
+ /* ok, we will let it through */
+#if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)
+ fprintf(stderr,"signature has problems, re-make with post SSLeay045\n");
+#endif
+ }
+ else
+ {
+ RSAerr(RSA_F_INT_RSA_VERIFY,
+ RSA_R_ALGORITHM_MISMATCH);
+ goto err;
+ }
+ }
+ if (rm)
+ {
+ const EVP_MD *md;
+ md = EVP_get_digestbynid(dtype);
+ if (md && (EVP_MD_size(md) != sig->digest->length))
+ RSAerr(RSA_F_INT_RSA_VERIFY,
+ RSA_R_INVALID_DIGEST_LENGTH);
+ else
+ {
+ memcpy(rm, sig->digest->data,
+ sig->digest->length);
+ *prm_len = sig->digest->length;
+ ret = 1;
+ }
+ }
+ else if (((unsigned int)sig->digest->length != m_len) ||
+ (memcmp(m,sig->digest->data,m_len) != 0))
+ {
+ RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
+ }
+ else
+ ret=1;
+ }
+err:
+ if (sig != NULL) X509_SIG_free(sig);
+ if (s != NULL)
+ {
+ OPENSSL_cleanse(s,(unsigned int)siglen);
+ OPENSSL_free(s);
+ }
+ return(ret);
+ }
+
+int RSA_verify(int dtype, const unsigned char *m, unsigned int m_len,
+ const unsigned char *sigbuf, unsigned int siglen,
+ RSA *rsa)
+ {
+
+ if((rsa->flags & RSA_FLAG_SIGN_VER) && rsa->meth->rsa_verify)
+ {
+ return rsa->meth->rsa_verify(dtype, m, m_len,
+ sigbuf, siglen, rsa);
+ }
+
+ return int_rsa_verify(dtype, m, m_len, NULL, NULL, sigbuf, siglen, rsa);
+ }
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_ssl.c b/drivers/builtin_openssl2/crypto/rsa/rsa_ssl.c
index cfeff15bc9..cfeff15bc9 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_ssl.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_ssl.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_test.c b/drivers/builtin_openssl2/crypto/rsa/rsa_test.c
index c8705a0f6e..c8705a0f6e 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_test.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_test.c
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa_x931.c b/drivers/builtin_openssl2/crypto/rsa/rsa_x931.c
index 21548e37ed..21548e37ed 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa_x931.c
+++ b/drivers/builtin_openssl2/crypto/rsa/rsa_x931.c
diff --git a/drivers/builtin_openssl/crypto/s390xcap.c b/drivers/builtin_openssl2/crypto/s390xcap.c
index f2e94ef47e..f2e94ef47e 100644
--- a/drivers/builtin_openssl/crypto/s390xcap.c
+++ b/drivers/builtin_openssl2/crypto/s390xcap.c
diff --git a/drivers/builtin_openssl/crypto/s390xcpuid.S b/drivers/builtin_openssl2/crypto/s390xcpuid.S
index 06815347e6..06815347e6 100644
--- a/drivers/builtin_openssl/crypto/s390xcpuid.S
+++ b/drivers/builtin_openssl2/crypto/s390xcpuid.S
diff --git a/drivers/builtin_openssl/crypto/seed/seed.c b/drivers/builtin_openssl2/crypto/seed/seed.c
index 3e675a8d75..3e675a8d75 100644
--- a/drivers/builtin_openssl/crypto/seed/seed.c
+++ b/drivers/builtin_openssl2/crypto/seed/seed.c
diff --git a/drivers/builtin_openssl/crypto/seed/seed_cbc.c b/drivers/builtin_openssl2/crypto/seed/seed_cbc.c
index 6c3f9b527a..6c3f9b527a 100644
--- a/drivers/builtin_openssl/crypto/seed/seed_cbc.c
+++ b/drivers/builtin_openssl2/crypto/seed/seed_cbc.c
diff --git a/drivers/builtin_openssl/crypto/seed/seed_cfb.c b/drivers/builtin_openssl2/crypto/seed/seed_cfb.c
index 694597dd06..694597dd06 100644
--- a/drivers/builtin_openssl/crypto/seed/seed_cfb.c
+++ b/drivers/builtin_openssl2/crypto/seed/seed_cfb.c
diff --git a/drivers/builtin_openssl/crypto/seed/seed_ecb.c b/drivers/builtin_openssl2/crypto/seed/seed_ecb.c
index e63f5ae14e..e63f5ae14e 100644
--- a/drivers/builtin_openssl/crypto/seed/seed_ecb.c
+++ b/drivers/builtin_openssl2/crypto/seed/seed_ecb.c
diff --git a/drivers/builtin_openssl/crypto/seed/seed_locl.h b/drivers/builtin_openssl2/crypto/seed/seed_locl.h
index fd456b6422..fd456b6422 100644
--- a/drivers/builtin_openssl/crypto/seed/seed_locl.h
+++ b/drivers/builtin_openssl2/crypto/seed/seed_locl.h
diff --git a/drivers/builtin_openssl/crypto/seed/seed_ofb.c b/drivers/builtin_openssl2/crypto/seed/seed_ofb.c
index 3c8ba33bb9..3c8ba33bb9 100644
--- a/drivers/builtin_openssl/crypto/seed/seed_ofb.c
+++ b/drivers/builtin_openssl2/crypto/seed/seed_ofb.c
diff --git a/drivers/builtin_openssl/crypto/sha/asm/README b/drivers/builtin_openssl2/crypto/sha/asm/README
index b7e755765f..b7e755765f 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/README
+++ b/drivers/builtin_openssl2/crypto/sha/asm/README
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-586.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-586.pl
index 1084d227fe..1084d227fe 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-586.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-586.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-alpha.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-alpha.pl
index 6c4b9251fd..6c4b9251fd 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-alpha.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-alpha.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-armv4-large.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-armv4-large.pl
index 33da3e0e3c..33da3e0e3c 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-armv4-large.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-armv4-large.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-ia64.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-ia64.pl
index 02d35d1614..02d35d1614 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-ia64.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-ia64.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-mips.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-mips.pl
index f1a702f38f..f1a702f38f 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-mips.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-mips.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-parisc.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-parisc.pl
index 6e5a328a6f..6e5a328a6f 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-parisc.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-parisc.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-ppc.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-ppc.pl
index 2140dd2f8d..2140dd2f8d 100755
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-ppc.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-ppc.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-s390x.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-s390x.pl
index 9193dda45e..9193dda45e 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-s390x.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-s390x.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-sparcv9.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-sparcv9.pl
index 5c161cecd6..5c161cecd6 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-sparcv9.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-sparcv9.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-sparcv9a.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-sparcv9a.pl
index e65291bbd9..e65291bbd9 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-sparcv9a.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-sparcv9a.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-thumb.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-thumb.pl
index 7c9ea9b029..7c9ea9b029 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-thumb.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-thumb.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha1-x86_64.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha1-x86_64.pl
index f15c7ec39b..f15c7ec39b 100755
--- a/drivers/builtin_openssl/crypto/sha/asm/sha1-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha1-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha256-586.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha256-586.pl
index 928ec53123..928ec53123 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha256-586.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha256-586.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha256-armv4.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha256-armv4.pl
index 9c84e8d93c..9c84e8d93c 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha256-armv4.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha256-armv4.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-586.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-586.pl
index 7eab6a5b88..7eab6a5b88 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-586.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-586.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-armv4.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-armv4.pl
index 7faf37b147..7faf37b147 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-armv4.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-armv4.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-ia64.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-ia64.pl
index 1c6ce56522..1c6ce56522 100755
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-ia64.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-ia64.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-mips.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-mips.pl
index ffa053bb7d..ffa053bb7d 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-mips.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-mips.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-parisc.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-parisc.pl
index fc0e15b3c0..fc0e15b3c0 100755
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-parisc.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-parisc.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-ppc.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-ppc.pl
index 6b44a68e59..6b44a68e59 100755
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-ppc.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-ppc.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-s390x.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-s390x.pl
index 079a3fc78a..079a3fc78a 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-s390x.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-s390x.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-sparcv9.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-sparcv9.pl
index 585740789e..585740789e 100644
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-sparcv9.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-sparcv9.pl
diff --git a/drivers/builtin_openssl/crypto/sha/asm/sha512-x86_64.pl b/drivers/builtin_openssl2/crypto/sha/asm/sha512-x86_64.pl
index 8d51678557..8d51678557 100755
--- a/drivers/builtin_openssl/crypto/sha/asm/sha512-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/sha/asm/sha512-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/sha/sha.c b/drivers/builtin_openssl2/crypto/sha/sha.c
index 42126551d1..42126551d1 100644
--- a/drivers/builtin_openssl/crypto/sha/sha.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha1.c b/drivers/builtin_openssl2/crypto/sha/sha1.c
index d350c88ee4..d350c88ee4 100644
--- a/drivers/builtin_openssl/crypto/sha/sha1.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha1.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha1_one.c b/drivers/builtin_openssl2/crypto/sha/sha1_one.c
index c56ec94020..c56ec94020 100644
--- a/drivers/builtin_openssl/crypto/sha/sha1_one.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha1_one.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha1dgst.c b/drivers/builtin_openssl2/crypto/sha/sha1dgst.c
index a98690225f..a98690225f 100644
--- a/drivers/builtin_openssl/crypto/sha/sha1dgst.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha1dgst.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha1test.c b/drivers/builtin_openssl2/crypto/sha/sha1test.c
index 6feb3964c7..6feb3964c7 100644
--- a/drivers/builtin_openssl/crypto/sha/sha1test.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha1test.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha256.c b/drivers/builtin_openssl2/crypto/sha/sha256.c
index 4eae074849..4eae074849 100644
--- a/drivers/builtin_openssl/crypto/sha/sha256.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha256.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha256t.c b/drivers/builtin_openssl2/crypto/sha/sha256t.c
index 6b4a3bd001..6b4a3bd001 100644
--- a/drivers/builtin_openssl/crypto/sha/sha256t.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha256t.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha512.c b/drivers/builtin_openssl2/crypto/sha/sha512.c
index 50c229ddeb..50c229ddeb 100644
--- a/drivers/builtin_openssl/crypto/sha/sha512.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha512.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha512t.c b/drivers/builtin_openssl2/crypto/sha/sha512t.c
index 210041d435..210041d435 100644
--- a/drivers/builtin_openssl/crypto/sha/sha512t.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha512t.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha_dgst.c b/drivers/builtin_openssl2/crypto/sha/sha_dgst.c
index fb63b17ff2..fb63b17ff2 100644
--- a/drivers/builtin_openssl/crypto/sha/sha_dgst.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha_dgst.c
diff --git a/drivers/builtin_openssl/crypto/sha/sha_locl.h b/drivers/builtin_openssl2/crypto/sha/sha_locl.h
index d673255f78..d673255f78 100644
--- a/drivers/builtin_openssl/crypto/sha/sha_locl.h
+++ b/drivers/builtin_openssl2/crypto/sha/sha_locl.h
diff --git a/drivers/builtin_openssl/crypto/sha/sha_one.c b/drivers/builtin_openssl2/crypto/sha/sha_one.c
index 3bae623ce8..3bae623ce8 100644
--- a/drivers/builtin_openssl/crypto/sha/sha_one.c
+++ b/drivers/builtin_openssl2/crypto/sha/sha_one.c
diff --git a/drivers/builtin_openssl/crypto/sha/shatest.c b/drivers/builtin_openssl2/crypto/sha/shatest.c
index 27614646d1..27614646d1 100644
--- a/drivers/builtin_openssl/crypto/sha/shatest.c
+++ b/drivers/builtin_openssl2/crypto/sha/shatest.c
diff --git a/drivers/builtin_openssl/crypto/sparccpuid.S b/drivers/builtin_openssl2/crypto/sparccpuid.S
index 0cc247e489..0cc247e489 100644
--- a/drivers/builtin_openssl/crypto/sparccpuid.S
+++ b/drivers/builtin_openssl2/crypto/sparccpuid.S
diff --git a/drivers/builtin_openssl/crypto/sparcv9cap.c b/drivers/builtin_openssl2/crypto/sparcv9cap.c
index 43b3ac6f81..43b3ac6f81 100644
--- a/drivers/builtin_openssl/crypto/sparcv9cap.c
+++ b/drivers/builtin_openssl2/crypto/sparcv9cap.c
diff --git a/drivers/builtin_openssl/crypto/srp/srp_grps.h b/drivers/builtin_openssl2/crypto/srp/srp_grps.h
index 8e3c35e3f5..8e3c35e3f5 100644
--- a/drivers/builtin_openssl/crypto/srp/srp_grps.h
+++ b/drivers/builtin_openssl2/crypto/srp/srp_grps.h
diff --git a/drivers/builtin_openssl/crypto/srp/srp_lcl.h b/drivers/builtin_openssl2/crypto/srp/srp_lcl.h
index 42bda3f148..42bda3f148 100644
--- a/drivers/builtin_openssl/crypto/srp/srp_lcl.h
+++ b/drivers/builtin_openssl2/crypto/srp/srp_lcl.h
diff --git a/drivers/builtin_openssl/crypto/srp/srp_lib.c b/drivers/builtin_openssl2/crypto/srp/srp_lib.c
index 7c1dcc5111..7c1dcc5111 100644
--- a/drivers/builtin_openssl/crypto/srp/srp_lib.c
+++ b/drivers/builtin_openssl2/crypto/srp/srp_lib.c
diff --git a/drivers/builtin_openssl2/crypto/srp/srp_vfy.c b/drivers/builtin_openssl2/crypto/srp/srp_vfy.c
new file mode 100644
index 0000000000..fdca19ff7c
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/srp/srp_vfy.c
@@ -0,0 +1,661 @@
+/* crypto/srp/srp_vfy.c */
+/* Written by Christophe Renou (christophe.renou@edelweb.fr) with
+ * the precious help of Peter Sylvester (peter.sylvester@edelweb.fr)
+ * for the EdelKey project and contributed to the OpenSSL project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#ifndef OPENSSL_NO_SRP
+#include "cryptlib.h"
+#include "srp_lcl.h"
+#include <openssl/srp.h>
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/txt_db.h>
+
+#define SRP_RANDOM_SALT_LEN 20
+#define MAX_LEN 2500
+
+static char b64table[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
+
+/* the following two conversion routines have been inspired by code from Stanford */
+
+/*
+ * Convert a base64 string into raw byte array representation.
+ */
+static int t_fromb64(unsigned char *a, const char *src)
+ {
+ char *loc;
+ int i, j;
+ int size;
+
+ while(*src && (*src == ' ' || *src == '\t' || *src == '\n'))
+ ++src;
+ size = strlen(src);
+ i = 0;
+ while(i < size)
+ {
+ loc = strchr(b64table, src[i]);
+ if(loc == (char *) 0) break;
+ else a[i] = loc - b64table;
+ ++i;
+ }
+ /* if nothing valid to process we have a zero length response */
+ if (i == 0)
+ return 0;
+ size = i;
+ i = size - 1;
+ j = size;
+ while(1)
+ {
+ a[j] = a[i];
+ if(--i < 0) break;
+ a[j] |= (a[i] & 3) << 6;
+ --j;
+ a[j] = (unsigned char) ((a[i] & 0x3c) >> 2);
+ if(--i < 0) break;
+ a[j] |= (a[i] & 0xf) << 4;
+ --j;
+ a[j] = (unsigned char) ((a[i] & 0x30) >> 4);
+ if(--i < 0) break;
+ a[j] |= (a[i] << 2);
+
+ a[--j] = 0;
+ if(--i < 0) break;
+ }
+ while(a[j] == 0 && j <= size) ++j;
+ i = 0;
+ while (j <= size) a[i++] = a[j++];
+ return i;
+ }
+
+
+/*
+ * Convert a raw byte string into a null-terminated base64 ASCII string.
+ */
+static char *t_tob64(char *dst, const unsigned char *src, int size)
+ {
+ int c, pos = size % 3;
+ unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0;
+ char *olddst = dst;
+
+ switch(pos)
+ {
+ case 1:
+ b2 = src[0];
+ break;
+ case 2:
+ b1 = src[0];
+ b2 = src[1];
+ break;
+ }
+
+ while(1)
+ {
+ c = (b0 & 0xfc) >> 2;
+ if(notleading || c != 0)
+ {
+ *dst++ = b64table[c];
+ notleading = 1;
+ }
+ c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4);
+ if(notleading || c != 0)
+ {
+ *dst++ = b64table[c];
+ notleading = 1;
+ }
+ c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6);
+ if(notleading || c != 0)
+ {
+ *dst++ = b64table[c];
+ notleading = 1;
+ }
+ c = b2 & 0x3f;
+ if(notleading || c != 0)
+ {
+ *dst++ = b64table[c];
+ notleading = 1;
+ }
+ if(pos >= size) break;
+ else
+ {
+ b0 = src[pos++];
+ b1 = src[pos++];
+ b2 = src[pos++];
+ }
+ }
+
+ *dst++ = '\0';
+ return olddst;
+ }
+
+static void SRP_user_pwd_free(SRP_user_pwd *user_pwd)
+ {
+ if (user_pwd == NULL)
+ return;
+ BN_free(user_pwd->s);
+ BN_clear_free(user_pwd->v);
+ OPENSSL_free(user_pwd->id);
+ OPENSSL_free(user_pwd->info);
+ OPENSSL_free(user_pwd);
+ }
+
+static SRP_user_pwd *SRP_user_pwd_new()
+ {
+ SRP_user_pwd *ret = OPENSSL_malloc(sizeof(SRP_user_pwd));
+ if (ret == NULL)
+ return NULL;
+ ret->N = NULL;
+ ret->g = NULL;
+ ret->s = NULL;
+ ret->v = NULL;
+ ret->id = NULL ;
+ ret->info = NULL;
+ return ret;
+ }
+
+static void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g,
+ const BIGNUM *N)
+ {
+ vinfo->N = N;
+ vinfo->g = g;
+ }
+
+static int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id,
+ const char *info)
+ {
+ if (id != NULL && NULL == (vinfo->id = BUF_strdup(id)))
+ return 0;
+ return (info == NULL || NULL != (vinfo->info = BUF_strdup(info))) ;
+ }
+
+static int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s,
+ const char *v)
+ {
+ unsigned char tmp[MAX_LEN];
+ int len;
+
+ if (strlen(s) > MAX_LEN || strlen(v) > MAX_LEN)
+ return 0;
+ len = t_fromb64(tmp, v);
+ if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL)) )
+ return 0;
+ len = t_fromb64(tmp, s);
+ return ((vinfo->s = BN_bin2bn(tmp, len, NULL)) != NULL) ;
+ }
+
+static int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v)
+ {
+ vinfo->v = v;
+ vinfo->s = s;
+ return (vinfo->s != NULL && vinfo->v != NULL) ;
+ }
+
+SRP_VBASE *SRP_VBASE_new(char *seed_key)
+ {
+ SRP_VBASE *vb = (SRP_VBASE *) OPENSSL_malloc(sizeof(SRP_VBASE));
+
+ if (vb == NULL)
+ return NULL;
+ if (!(vb->users_pwd = sk_SRP_user_pwd_new_null()) ||
+ !(vb->gN_cache = sk_SRP_gN_cache_new_null()))
+ {
+ OPENSSL_free(vb);
+ return NULL;
+ }
+ vb->default_g = NULL;
+ vb->default_N = NULL;
+ vb->seed_key = NULL;
+ if ((seed_key != NULL) &&
+ (vb->seed_key = BUF_strdup(seed_key)) == NULL)
+ {
+ sk_SRP_user_pwd_free(vb->users_pwd);
+ sk_SRP_gN_cache_free(vb->gN_cache);
+ OPENSSL_free(vb);
+ return NULL;
+ }
+ return vb;
+ }
+
+
+int SRP_VBASE_free(SRP_VBASE *vb)
+ {
+ sk_SRP_user_pwd_pop_free(vb->users_pwd,SRP_user_pwd_free);
+ sk_SRP_gN_cache_free(vb->gN_cache);
+ OPENSSL_free(vb->seed_key);
+ OPENSSL_free(vb);
+ return 0;
+ }
+
+
+static SRP_gN_cache *SRP_gN_new_init(const char *ch)
+ {
+ unsigned char tmp[MAX_LEN];
+ int len;
+
+ SRP_gN_cache *newgN = (SRP_gN_cache *)OPENSSL_malloc(sizeof(SRP_gN_cache));
+ if (newgN == NULL)
+ return NULL;
+
+ if ((newgN->b64_bn = BUF_strdup(ch)) == NULL)
+ goto err;
+
+ len = t_fromb64(tmp, ch);
+ if ((newgN->bn = BN_bin2bn(tmp, len, NULL)))
+ return newgN;
+
+ OPENSSL_free(newgN->b64_bn);
+err:
+ OPENSSL_free(newgN);
+ return NULL;
+ }
+
+
+static void SRP_gN_free(SRP_gN_cache *gN_cache)
+ {
+ if (gN_cache == NULL)
+ return;
+ OPENSSL_free(gN_cache->b64_bn);
+ BN_free(gN_cache->bn);
+ OPENSSL_free(gN_cache);
+ }
+
+static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab)
+ {
+ int i;
+
+ SRP_gN *gN;
+ if (gN_tab != NULL)
+ for(i = 0; i < sk_SRP_gN_num(gN_tab); i++)
+ {
+ gN = sk_SRP_gN_value(gN_tab, i);
+ if (gN && (id == NULL || strcmp(gN->id,id)==0))
+ return gN;
+ }
+
+ return SRP_get_default_gN(id);
+ }
+
+static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch)
+ {
+ int i;
+ if (gN_cache == NULL)
+ return NULL;
+
+ /* search if we have already one... */
+ for(i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++)
+ {
+ SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i);
+ if (strcmp(cache->b64_bn,ch)==0)
+ return cache->bn;
+ }
+ { /* it is the first time that we find it */
+ SRP_gN_cache *newgN = SRP_gN_new_init(ch);
+ if (newgN)
+ {
+ if (sk_SRP_gN_cache_insert(gN_cache,newgN,0)>0)
+ return newgN->bn;
+ SRP_gN_free(newgN);
+ }
+ }
+ return NULL;
+ }
+
+/* this function parses verifier file. Format is:
+ * string(index):base64(N):base64(g):0
+ * string(username):base64(v):base64(salt):int(index)
+ */
+
+
+int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file)
+ {
+ int error_code ;
+ STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null();
+ char *last_index = NULL;
+ int i;
+ char **pp;
+
+ SRP_gN *gN = NULL;
+ SRP_user_pwd *user_pwd = NULL ;
+
+ TXT_DB *tmpdb = NULL;
+ BIO *in = BIO_new(BIO_s_file());
+
+ error_code = SRP_ERR_OPEN_FILE;
+
+ if (in == NULL || BIO_read_filename(in,verifier_file) <= 0)
+ goto err;
+
+ error_code = SRP_ERR_VBASE_INCOMPLETE_FILE;
+
+ if ((tmpdb =TXT_DB_read(in,DB_NUMBER)) == NULL)
+ goto err;
+
+ error_code = SRP_ERR_MEMORY;
+
+
+ if (vb->seed_key)
+ {
+ last_index = SRP_get_default_gN(NULL)->id;
+ }
+ for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++)
+ {
+ pp = sk_OPENSSL_PSTRING_value(tmpdb->data,i);
+ if (pp[DB_srptype][0] == DB_SRP_INDEX)
+ {
+ /*we add this couple in the internal Stack */
+
+ if ((gN = (SRP_gN *)OPENSSL_malloc(sizeof(SRP_gN))) == NULL)
+ goto err;
+
+ if (!(gN->id = BUF_strdup(pp[DB_srpid]))
+ || !(gN->N = SRP_gN_place_bn(vb->gN_cache,pp[DB_srpverifier]))
+ || !(gN->g = SRP_gN_place_bn(vb->gN_cache,pp[DB_srpsalt]))
+ || sk_SRP_gN_insert(SRP_gN_tab,gN,0) == 0)
+ goto err;
+
+ gN = NULL;
+
+ if (vb->seed_key != NULL)
+ {
+ last_index = pp[DB_srpid];
+ }
+ }
+ else if (pp[DB_srptype][0] == DB_SRP_VALID)
+ {
+ /* it is a user .... */
+ SRP_gN *lgN;
+ if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN],SRP_gN_tab))!=NULL)
+ {
+ error_code = SRP_ERR_MEMORY;
+ if ((user_pwd = SRP_user_pwd_new()) == NULL)
+ goto err;
+
+ SRP_user_pwd_set_gN(user_pwd,lgN->g,lgN->N);
+ if (!SRP_user_pwd_set_ids(user_pwd, pp[DB_srpid],pp[DB_srpinfo]))
+ goto err;
+
+ error_code = SRP_ERR_VBASE_BN_LIB;
+ if (!SRP_user_pwd_set_sv(user_pwd, pp[DB_srpsalt],pp[DB_srpverifier]))
+ goto err;
+
+ if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0)
+ goto err;
+ user_pwd = NULL; /* abandon responsability */
+ }
+ }
+ }
+
+ if (last_index != NULL)
+ {
+ /* this means that we want to simulate a default user */
+
+ if (((gN = SRP_get_gN_by_id(last_index,SRP_gN_tab))==NULL))
+ {
+ error_code = SRP_ERR_VBASE_BN_LIB;
+ goto err;
+ }
+ vb->default_g = gN->g ;
+ vb->default_N = gN->N ;
+ gN = NULL ;
+ }
+ error_code = SRP_NO_ERROR;
+
+ err:
+ /* there may be still some leaks to fix, if this fails, the application terminates most likely */
+
+ if (gN != NULL)
+ {
+ OPENSSL_free(gN->id);
+ OPENSSL_free(gN);
+ }
+
+ SRP_user_pwd_free(user_pwd);
+
+ if (tmpdb) TXT_DB_free(tmpdb);
+ if (in) BIO_free_all(in);
+
+ sk_SRP_gN_free(SRP_gN_tab);
+
+ return error_code;
+
+ }
+
+
+SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username)
+ {
+ int i;
+ SRP_user_pwd *user;
+ unsigned char digv[SHA_DIGEST_LENGTH];
+ unsigned char digs[SHA_DIGEST_LENGTH];
+ EVP_MD_CTX ctxt;
+
+ if (vb == NULL)
+ return NULL;
+ for(i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++)
+ {
+ user = sk_SRP_user_pwd_value(vb->users_pwd, i);
+ if (strcmp(user->id,username)==0)
+ return user;
+ }
+ if ((vb->seed_key == NULL) ||
+ (vb->default_g == NULL) ||
+ (vb->default_N == NULL))
+ return NULL;
+
+/* if the user is unknown we set parameters as well if we have a seed_key */
+
+ if ((user = SRP_user_pwd_new()) == NULL)
+ return NULL;
+
+ SRP_user_pwd_set_gN(user,vb->default_g,vb->default_N);
+
+ if (!SRP_user_pwd_set_ids(user,username,NULL))
+ goto err;
+
+ RAND_pseudo_bytes(digv, SHA_DIGEST_LENGTH);
+ EVP_MD_CTX_init(&ctxt);
+ EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL);
+ EVP_DigestUpdate(&ctxt, vb->seed_key, strlen(vb->seed_key));
+ EVP_DigestUpdate(&ctxt, username, strlen(username));
+ EVP_DigestFinal_ex(&ctxt, digs, NULL);
+ EVP_MD_CTX_cleanup(&ctxt);
+ if (SRP_user_pwd_set_sv_BN(user, BN_bin2bn(digs,SHA_DIGEST_LENGTH,NULL), BN_bin2bn(digv,SHA_DIGEST_LENGTH, NULL)))
+ return user;
+
+err: SRP_user_pwd_free(user);
+ return NULL;
+ }
+
+
+/*
+ create a verifier (*salt,*verifier,g and N are in base64)
+*/
+char *SRP_create_verifier(const char *user, const char *pass, char **salt,
+ char **verifier, const char *N, const char *g)
+ {
+ int len;
+ char * result=NULL;
+ char *vf;
+ BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL;
+ unsigned char tmp[MAX_LEN];
+ unsigned char tmp2[MAX_LEN];
+ char * defgNid = NULL;
+
+ if ((user == NULL)||
+ (pass == NULL)||
+ (salt == NULL)||
+ (verifier == NULL))
+ goto err;
+
+ if (N)
+ {
+ if (!(len = t_fromb64(tmp, N))) goto err;
+ N_bn = BN_bin2bn(tmp, len, NULL);
+ if (!(len = t_fromb64(tmp, g))) goto err;
+ g_bn = BN_bin2bn(tmp, len, NULL);
+ defgNid = "*";
+ }
+ else
+ {
+ SRP_gN * gN = SRP_get_gN_by_id(g, NULL) ;
+ if (gN == NULL)
+ goto err;
+ N_bn = gN->N;
+ g_bn = gN->g;
+ defgNid = gN->id;
+ }
+
+ if (*salt == NULL)
+ {
+ RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN);
+
+ s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL);
+ }
+ else
+ {
+ if (!(len = t_fromb64(tmp2, *salt)))
+ goto err;
+ s = BN_bin2bn(tmp2, len, NULL);
+ }
+
+
+ if(!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn)) goto err;
+
+ BN_bn2bin(v,tmp);
+ if (((vf = OPENSSL_malloc(BN_num_bytes(v)*2)) == NULL))
+ goto err;
+ t_tob64(vf, tmp, BN_num_bytes(v));
+
+ *verifier = vf;
+ if (*salt == NULL)
+ {
+ char *tmp_salt;
+
+ if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL)
+ {
+ OPENSSL_free(vf);
+ goto err;
+ }
+ t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN);
+ *salt = tmp_salt;
+ }
+
+ result=defgNid;
+
+err:
+ if(N)
+ {
+ BN_free(N_bn);
+ BN_free(g_bn);
+ }
+ return result;
+ }
+
+/*
+ create a verifier (*salt,*verifier,g and N are BIGNUMs)
+*/
+int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, BIGNUM **verifier, BIGNUM *N, BIGNUM *g)
+ {
+ int result=0;
+ BIGNUM *x = NULL;
+ BN_CTX *bn_ctx = BN_CTX_new();
+ unsigned char tmp2[MAX_LEN];
+
+ if ((user == NULL)||
+ (pass == NULL)||
+ (salt == NULL)||
+ (verifier == NULL)||
+ (N == NULL)||
+ (g == NULL)||
+ (bn_ctx == NULL))
+ goto err;
+
+ srp_bn_print(N);
+ srp_bn_print(g);
+
+ if (*salt == NULL)
+ {
+ RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN);
+
+ *salt = BN_bin2bn(tmp2,SRP_RANDOM_SALT_LEN,NULL);
+ }
+
+ x = SRP_Calc_x(*salt,user,pass);
+
+ *verifier = BN_new();
+ if(*verifier == NULL) goto err;
+
+ if (!BN_mod_exp(*verifier,g,x,N,bn_ctx))
+ {
+ BN_clear_free(*verifier);
+ goto err;
+ }
+
+ srp_bn_print(*verifier);
+
+ result=1;
+
+err:
+
+ BN_clear_free(x);
+ BN_CTX_free(bn_ctx);
+ return result;
+ }
+
+
+
+#endif
diff --git a/drivers/builtin_openssl/crypto/srp/srptest.c b/drivers/builtin_openssl2/crypto/srp/srptest.c
index 04b66b4544..04b66b4544 100644
--- a/drivers/builtin_openssl/crypto/srp/srptest.c
+++ b/drivers/builtin_openssl2/crypto/srp/srptest.c
diff --git a/drivers/builtin_openssl/crypto/stack/stack.c b/drivers/builtin_openssl2/crypto/stack/stack.c
index 76cf1a1168..76cf1a1168 100644
--- a/drivers/builtin_openssl/crypto/stack/stack.c
+++ b/drivers/builtin_openssl2/crypto/stack/stack.c
diff --git a/drivers/builtin_openssl/crypto/store/README b/drivers/builtin_openssl2/crypto/store/README
index 966168f6a5..966168f6a5 100644
--- a/drivers/builtin_openssl/crypto/store/README
+++ b/drivers/builtin_openssl2/crypto/store/README
diff --git a/drivers/builtin_openssl/crypto/store/store.h b/drivers/builtin_openssl2/crypto/store/store.h
index 0a28c7d5a2..0a28c7d5a2 100644
--- a/drivers/builtin_openssl/crypto/store/store.h
+++ b/drivers/builtin_openssl2/crypto/store/store.h
diff --git a/drivers/builtin_openssl/crypto/store/str_err.c b/drivers/builtin_openssl2/crypto/store/str_err.c
index 924edf0505..924edf0505 100644
--- a/drivers/builtin_openssl/crypto/store/str_err.c
+++ b/drivers/builtin_openssl2/crypto/store/str_err.c
diff --git a/drivers/builtin_openssl/crypto/store/str_lib.c b/drivers/builtin_openssl2/crypto/store/str_lib.c
index f1dbcbd0e0..f1dbcbd0e0 100644
--- a/drivers/builtin_openssl/crypto/store/str_lib.c
+++ b/drivers/builtin_openssl2/crypto/store/str_lib.c
diff --git a/drivers/builtin_openssl/crypto/store/str_locl.h b/drivers/builtin_openssl2/crypto/store/str_locl.h
index 3f8cb75619..3f8cb75619 100644
--- a/drivers/builtin_openssl/crypto/store/str_locl.h
+++ b/drivers/builtin_openssl2/crypto/store/str_locl.h
diff --git a/drivers/builtin_openssl/crypto/store/str_mem.c b/drivers/builtin_openssl2/crypto/store/str_mem.c
index 8ac4f7e55c..8ac4f7e55c 100644
--- a/drivers/builtin_openssl/crypto/store/str_mem.c
+++ b/drivers/builtin_openssl2/crypto/store/str_mem.c
diff --git a/drivers/builtin_openssl/crypto/store/str_meth.c b/drivers/builtin_openssl2/crypto/store/str_meth.c
index a46de03a26..a46de03a26 100644
--- a/drivers/builtin_openssl/crypto/store/str_meth.c
+++ b/drivers/builtin_openssl2/crypto/store/str_meth.c
diff --git a/drivers/builtin_openssl/crypto/threads/README b/drivers/builtin_openssl2/crypto/threads/README
index df6b26e146..df6b26e146 100644
--- a/drivers/builtin_openssl/crypto/threads/README
+++ b/drivers/builtin_openssl2/crypto/threads/README
diff --git a/drivers/builtin_openssl/crypto/threads/mttest.c b/drivers/builtin_openssl2/crypto/threads/mttest.c
index eba7aa8a6e..eba7aa8a6e 100644
--- a/drivers/builtin_openssl/crypto/threads/mttest.c
+++ b/drivers/builtin_openssl2/crypto/threads/mttest.c
diff --git a/drivers/builtin_openssl/crypto/threads/netware.bat b/drivers/builtin_openssl2/crypto/threads/netware.bat
index 0b3eca3caf..0b3eca3caf 100644
--- a/drivers/builtin_openssl/crypto/threads/netware.bat
+++ b/drivers/builtin_openssl2/crypto/threads/netware.bat
diff --git a/drivers/builtin_openssl/crypto/threads/profile.sh b/drivers/builtin_openssl2/crypto/threads/profile.sh
index 6e3e342fc0..6e3e342fc0 100644
--- a/drivers/builtin_openssl/crypto/threads/profile.sh
+++ b/drivers/builtin_openssl2/crypto/threads/profile.sh
diff --git a/drivers/builtin_openssl/crypto/threads/ptest.bat b/drivers/builtin_openssl2/crypto/threads/ptest.bat
index 4071b5ffea..4071b5ffea 100755
--- a/drivers/builtin_openssl/crypto/threads/ptest.bat
+++ b/drivers/builtin_openssl2/crypto/threads/ptest.bat
diff --git a/drivers/builtin_openssl/crypto/threads/pthread.sh b/drivers/builtin_openssl2/crypto/threads/pthread.sh
index f1c49821d2..f1c49821d2 100644
--- a/drivers/builtin_openssl/crypto/threads/pthread.sh
+++ b/drivers/builtin_openssl2/crypto/threads/pthread.sh
diff --git a/drivers/builtin_openssl/crypto/threads/pthread2.sh b/drivers/builtin_openssl2/crypto/threads/pthread2.sh
index 41264c6a50..41264c6a50 100755
--- a/drivers/builtin_openssl/crypto/threads/pthread2.sh
+++ b/drivers/builtin_openssl2/crypto/threads/pthread2.sh
diff --git a/drivers/builtin_openssl/crypto/threads/pthreads-vms.com b/drivers/builtin_openssl2/crypto/threads/pthreads-vms.com
index 1cf92bdf57..1cf92bdf57 100644
--- a/drivers/builtin_openssl/crypto/threads/pthreads-vms.com
+++ b/drivers/builtin_openssl2/crypto/threads/pthreads-vms.com
diff --git a/drivers/builtin_openssl/crypto/threads/purify.sh b/drivers/builtin_openssl2/crypto/threads/purify.sh
index 6d44fe26b7..6d44fe26b7 100644
--- a/drivers/builtin_openssl/crypto/threads/purify.sh
+++ b/drivers/builtin_openssl2/crypto/threads/purify.sh
diff --git a/drivers/builtin_openssl/crypto/threads/solaris.sh b/drivers/builtin_openssl2/crypto/threads/solaris.sh
index bc93094a27..bc93094a27 100644
--- a/drivers/builtin_openssl/crypto/threads/solaris.sh
+++ b/drivers/builtin_openssl2/crypto/threads/solaris.sh
diff --git a/drivers/builtin_openssl/crypto/threads/th-lock.c b/drivers/builtin_openssl2/crypto/threads/th-lock.c
index 14aae5f912..14aae5f912 100644
--- a/drivers/builtin_openssl/crypto/threads/th-lock.c
+++ b/drivers/builtin_openssl2/crypto/threads/th-lock.c
diff --git a/drivers/builtin_openssl/crypto/threads/win32.bat b/drivers/builtin_openssl2/crypto/threads/win32.bat
index ee6da80a07..ee6da80a07 100755
--- a/drivers/builtin_openssl/crypto/threads/win32.bat
+++ b/drivers/builtin_openssl2/crypto/threads/win32.bat
diff --git a/drivers/builtin_openssl/crypto/ts/ts_asn1.c b/drivers/builtin_openssl2/crypto/ts/ts_asn1.c
index 40b730c5e2..40b730c5e2 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_asn1.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_asn1.c
diff --git a/drivers/builtin_openssl/crypto/ts/ts_conf.c b/drivers/builtin_openssl2/crypto/ts/ts_conf.c
index c39be76f28..c39be76f28 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_conf.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_conf.c
diff --git a/drivers/builtin_openssl/crypto/ts/ts_err.c b/drivers/builtin_openssl2/crypto/ts/ts_err.c
index a08b0ffa23..a08b0ffa23 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_err.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_err.c
diff --git a/drivers/builtin_openssl/crypto/ts/ts_lib.c b/drivers/builtin_openssl2/crypto/ts/ts_lib.c
index e8608dbf71..e8608dbf71 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_lib.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_lib.c
diff --git a/drivers/builtin_openssl/crypto/ts/ts_req_print.c b/drivers/builtin_openssl2/crypto/ts/ts_req_print.c
index eba12c3824..eba12c3824 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_req_print.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_req_print.c
diff --git a/drivers/builtin_openssl/crypto/ts/ts_req_utils.c b/drivers/builtin_openssl2/crypto/ts/ts_req_utils.c
index 43280c1587..43280c1587 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_req_utils.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_req_utils.c
diff --git a/drivers/builtin_openssl/crypto/ts/ts_rsp_print.c b/drivers/builtin_openssl2/crypto/ts/ts_rsp_print.c
index 21062517ba..21062517ba 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_rsp_print.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_rsp_print.c
diff --git a/drivers/builtin_openssl/crypto/ts/ts_rsp_sign.c b/drivers/builtin_openssl2/crypto/ts/ts_rsp_sign.c
index b0f023c9d2..b0f023c9d2 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_rsp_sign.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_rsp_sign.c
diff --git a/drivers/builtin_openssl/crypto/ts/ts_rsp_utils.c b/drivers/builtin_openssl2/crypto/ts/ts_rsp_utils.c
index 401c1fdc51..401c1fdc51 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_rsp_utils.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_rsp_utils.c
diff --git a/drivers/builtin_openssl2/crypto/ts/ts_rsp_verify.c b/drivers/builtin_openssl2/crypto/ts/ts_rsp_verify.c
new file mode 100644
index 0000000000..b7d170afac
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/ts/ts_rsp_verify.c
@@ -0,0 +1,729 @@
+/* crypto/ts/ts_resp_verify.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/ts.h>
+#include <openssl/pkcs7.h>
+
+/* Private function declarations. */
+
+static int TS_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
+ X509 *signer, STACK_OF(X509) **chain);
+static int TS_check_signing_certs(PKCS7_SIGNER_INFO *si, STACK_OF(X509) *chain);
+static ESS_SIGNING_CERT *ESS_get_signing_cert(PKCS7_SIGNER_INFO *si);
+static int TS_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert);
+static int TS_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509_CINF *cinfo);
+static int int_TS_RESP_verify_token(TS_VERIFY_CTX *ctx,
+ PKCS7 *token, TS_TST_INFO *tst_info);
+static int TS_check_status_info(TS_RESP *response);
+static char *TS_get_status_text(STACK_OF(ASN1_UTF8STRING) *text);
+static int TS_check_policy(ASN1_OBJECT *req_oid, TS_TST_INFO *tst_info);
+static int TS_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
+ X509_ALGOR **md_alg,
+ unsigned char **imprint, unsigned *imprint_len);
+static int TS_check_imprints(X509_ALGOR *algor_a,
+ unsigned char *imprint_a, unsigned len_a,
+ TS_TST_INFO *tst_info);
+static int TS_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info);
+static int TS_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer);
+static int TS_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name);
+
+/*
+ * Local mapping between response codes and descriptions.
+ * Don't forget to change TS_STATUS_BUF_SIZE when modifying
+ * the elements of this array.
+ */
+static const char *TS_status_text[] =
+ { "granted",
+ "grantedWithMods",
+ "rejection",
+ "waiting",
+ "revocationWarning",
+ "revocationNotification" };
+
+#define TS_STATUS_TEXT_SIZE (sizeof(TS_status_text)/sizeof(*TS_status_text))
+
+/*
+ * This must be greater or equal to the sum of the strings in TS_status_text
+ * plus the number of its elements.
+ */
+#define TS_STATUS_BUF_SIZE 256
+
+static struct
+ {
+ int code;
+ const char *text;
+ } TS_failure_info[] =
+ { { TS_INFO_BAD_ALG, "badAlg" },
+ { TS_INFO_BAD_REQUEST, "badRequest" },
+ { TS_INFO_BAD_DATA_FORMAT, "badDataFormat" },
+ { TS_INFO_TIME_NOT_AVAILABLE, "timeNotAvailable" },
+ { TS_INFO_UNACCEPTED_POLICY, "unacceptedPolicy" },
+ { TS_INFO_UNACCEPTED_EXTENSION, "unacceptedExtension" },
+ { TS_INFO_ADD_INFO_NOT_AVAILABLE, "addInfoNotAvailable" },
+ { TS_INFO_SYSTEM_FAILURE, "systemFailure" } };
+
+#define TS_FAILURE_INFO_SIZE (sizeof(TS_failure_info) / \
+ sizeof(*TS_failure_info))
+
+/* Functions for verifying a signed TS_TST_INFO structure. */
+
+/*
+ * This function carries out the following tasks:
+ * - Checks if there is one and only one signer.
+ * - Search for the signing certificate in 'certs' and in the response.
+ * - Check the extended key usage and key usage fields of the signer
+ * certificate (done by the path validation).
+ * - Build and validate the certificate path.
+ * - Check if the certificate path meets the requirements of the
+ * SigningCertificate ESS signed attribute.
+ * - Verify the signature value.
+ * - Returns the signer certificate in 'signer', if 'signer' is not NULL.
+ */
+int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs,
+ X509_STORE *store, X509 **signer_out)
+ {
+ STACK_OF(PKCS7_SIGNER_INFO) *sinfos = NULL;
+ PKCS7_SIGNER_INFO *si;
+ STACK_OF(X509) *signers = NULL;
+ X509 *signer;
+ STACK_OF(X509) *chain = NULL;
+ char buf[4096];
+ int i, j = 0, ret = 0;
+ BIO *p7bio = NULL;
+
+ /* Some sanity checks first. */
+ if (!token)
+ {
+ TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_INVALID_NULL_POINTER);
+ goto err;
+ }
+
+ /* Check for the correct content type */
+ if(!PKCS7_type_is_signed(token))
+ {
+ TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_WRONG_CONTENT_TYPE);
+ goto err;
+ }
+
+ /* Check if there is one and only one signer. */
+ sinfos = PKCS7_get_signer_info(token);
+ if (!sinfos || sk_PKCS7_SIGNER_INFO_num(sinfos) != 1)
+ {
+ TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE,
+ TS_R_THERE_MUST_BE_ONE_SIGNER);
+ goto err;
+ }
+ si = sk_PKCS7_SIGNER_INFO_value(sinfos, 0);
+
+ /* Check for no content: no data to verify signature. */
+ if (PKCS7_get_detached(token))
+ {
+ TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_NO_CONTENT);
+ goto err;
+ }
+
+ /* Get hold of the signer certificate, search only internal
+ certificates if it was requested. */
+ signers = PKCS7_get0_signers(token, certs, 0);
+ if (!signers || sk_X509_num(signers) != 1) goto err;
+ signer = sk_X509_value(signers, 0);
+
+ /* Now verify the certificate. */
+ if (!TS_verify_cert(store, certs, signer, &chain)) goto err;
+
+ /* Check if the signer certificate is consistent with the
+ ESS extension. */
+ if (!TS_check_signing_certs(si, chain)) goto err;
+
+ /* Creating the message digest. */
+ p7bio = PKCS7_dataInit(token, NULL);
+
+ /* We now have to 'read' from p7bio to calculate digests etc. */
+ while ((i = BIO_read(p7bio,buf,sizeof(buf))) > 0);
+
+ /* Verifying the signature. */
+ j = PKCS7_signatureVerify(p7bio, token, si, signer);
+ if (j <= 0)
+ {
+ TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_SIGNATURE_FAILURE);
+ goto err;
+ }
+
+ /* Return the signer certificate if needed. */
+ if (signer_out)
+ {
+ *signer_out = signer;
+ CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
+ }
+
+ ret = 1;
+
+ err:
+ BIO_free_all(p7bio);
+ sk_X509_pop_free(chain, X509_free);
+ sk_X509_free(signers);
+
+ return ret;
+ }
+
+/*
+ * The certificate chain is returned in chain. Caller is responsible for
+ * freeing the vector.
+ */
+static int TS_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
+ X509 *signer, STACK_OF(X509) **chain)
+ {
+ X509_STORE_CTX cert_ctx;
+ int i;
+ int ret = 1;
+
+ /* chain is an out argument. */
+ *chain = NULL;
+ X509_STORE_CTX_init(&cert_ctx, store, signer, untrusted);
+ X509_STORE_CTX_set_purpose(&cert_ctx, X509_PURPOSE_TIMESTAMP_SIGN);
+ i = X509_verify_cert(&cert_ctx);
+ if (i <= 0)
+ {
+ int j = X509_STORE_CTX_get_error(&cert_ctx);
+ TSerr(TS_F_TS_VERIFY_CERT, TS_R_CERTIFICATE_VERIFY_ERROR);
+ ERR_add_error_data(2, "Verify error:",
+ X509_verify_cert_error_string(j));
+ ret = 0;
+ }
+ else
+ {
+ /* Get a copy of the certificate chain. */
+ *chain = X509_STORE_CTX_get1_chain(&cert_ctx);
+ }
+
+ X509_STORE_CTX_cleanup(&cert_ctx);
+
+ return ret;
+ }
+
+static int TS_check_signing_certs(PKCS7_SIGNER_INFO *si, STACK_OF(X509) *chain)
+ {
+ ESS_SIGNING_CERT *ss = ESS_get_signing_cert(si);
+ STACK_OF(ESS_CERT_ID) *cert_ids = NULL;
+ X509 *cert;
+ int i = 0;
+ int ret = 0;
+
+ if (!ss) goto err;
+ cert_ids = ss->cert_ids;
+ /* The signer certificate must be the first in cert_ids. */
+ cert = sk_X509_value(chain, 0);
+ if (TS_find_cert(cert_ids, cert) != 0) goto err;
+
+ /* Check the other certificates of the chain if there are more
+ than one certificate ids in cert_ids. */
+ if (sk_ESS_CERT_ID_num(cert_ids) > 1)
+ {
+ /* All the certificates of the chain must be in cert_ids. */
+ for (i = 1; i < sk_X509_num(chain); ++i)
+ {
+ cert = sk_X509_value(chain, i);
+ if (TS_find_cert(cert_ids, cert) < 0) goto err;
+ }
+ }
+ ret = 1;
+ err:
+ if (!ret)
+ TSerr(TS_F_TS_CHECK_SIGNING_CERTS,
+ TS_R_ESS_SIGNING_CERTIFICATE_ERROR);
+ ESS_SIGNING_CERT_free(ss);
+ return ret;
+ }
+
+static ESS_SIGNING_CERT *ESS_get_signing_cert(PKCS7_SIGNER_INFO *si)
+ {
+ ASN1_TYPE *attr;
+ const unsigned char *p;
+ attr = PKCS7_get_signed_attribute(si,
+ NID_id_smime_aa_signingCertificate);
+ if (!attr) return NULL;
+ p = attr->value.sequence->data;
+ return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
+ }
+
+/* Returns < 0 if certificate is not found, certificate index otherwise. */
+static int TS_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert)
+ {
+ int i;
+
+ if (!cert_ids || !cert) return -1;
+
+ /* Recompute SHA1 hash of certificate if necessary (side effect). */
+ X509_check_purpose(cert, -1, 0);
+
+ /* Look for cert in the cert_ids vector. */
+ for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i)
+ {
+ ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i);
+
+ /* Check the SHA-1 hash first. */
+ if (cid->hash->length == sizeof(cert->sha1_hash)
+ && !memcmp(cid->hash->data, cert->sha1_hash,
+ sizeof(cert->sha1_hash)))
+ {
+ /* Check the issuer/serial as well if specified. */
+ ESS_ISSUER_SERIAL *is = cid->issuer_serial;
+ if (!is || !TS_issuer_serial_cmp(is, cert->cert_info))
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+static int TS_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509_CINF *cinfo)
+ {
+ GENERAL_NAME *issuer;
+
+ if (!is || !cinfo || sk_GENERAL_NAME_num(is->issuer) != 1) return -1;
+
+ /* Check the issuer first. It must be a directory name. */
+ issuer = sk_GENERAL_NAME_value(is->issuer, 0);
+ if (issuer->type != GEN_DIRNAME
+ || X509_NAME_cmp(issuer->d.dirn, cinfo->issuer))
+ return -1;
+
+ /* Check the serial number, too. */
+ if (ASN1_INTEGER_cmp(is->serial, cinfo->serialNumber))
+ return -1;
+
+ return 0;
+ }
+
+/*
+ * Verifies whether 'response' contains a valid response with regards
+ * to the settings of the context:
+ * - Gives an error message if the TS_TST_INFO is not present.
+ * - Calls _TS_RESP_verify_token to verify the token content.
+ */
+int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response)
+ {
+ PKCS7 *token = TS_RESP_get_token(response);
+ TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
+ int ret = 0;
+
+ /* Check if we have a successful TS_TST_INFO object in place. */
+ if (!TS_check_status_info(response)) goto err;
+
+ /* Check the contents of the time stamp token. */
+ if (!int_TS_RESP_verify_token(ctx, token, tst_info))
+ goto err;
+
+ ret = 1;
+ err:
+ return ret;
+ }
+
+/*
+ * Tries to extract a TS_TST_INFO structure from the PKCS7 token and
+ * calls the internal int_TS_RESP_verify_token function for verifying it.
+ */
+int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token)
+ {
+ TS_TST_INFO *tst_info = PKCS7_to_TS_TST_INFO(token);
+ int ret = 0;
+ if (tst_info)
+ {
+ ret = int_TS_RESP_verify_token(ctx, token, tst_info);
+ TS_TST_INFO_free(tst_info);
+ }
+ return ret;
+ }
+
+/*
+ * Verifies whether the 'token' contains a valid time stamp token
+ * with regards to the settings of the context. Only those checks are
+ * carried out that are specified in the context:
+ * - Verifies the signature of the TS_TST_INFO.
+ * - Checks the version number of the response.
+ * - Check if the requested and returned policies math.
+ * - Check if the message imprints are the same.
+ * - Check if the nonces are the same.
+ * - Check if the TSA name matches the signer.
+ * - Check if the TSA name is the expected TSA.
+ */
+static int int_TS_RESP_verify_token(TS_VERIFY_CTX *ctx,
+ PKCS7 *token, TS_TST_INFO *tst_info)
+ {
+ X509 *signer = NULL;
+ GENERAL_NAME *tsa_name = TS_TST_INFO_get_tsa(tst_info);
+ X509_ALGOR *md_alg = NULL;
+ unsigned char *imprint = NULL;
+ unsigned imprint_len = 0;
+ int ret = 0;
+
+ /* Verify the signature. */
+ if ((ctx->flags & TS_VFY_SIGNATURE)
+ && !TS_RESP_verify_signature(token, ctx->certs, ctx->store,
+ &signer))
+ goto err;
+
+ /* Check version number of response. */
+ if ((ctx->flags & TS_VFY_VERSION)
+ && TS_TST_INFO_get_version(tst_info) != 1)
+ {
+ TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_UNSUPPORTED_VERSION);
+ goto err;
+ }
+
+ /* Check policies. */
+ if ((ctx->flags & TS_VFY_POLICY)
+ && !TS_check_policy(ctx->policy, tst_info))
+ goto err;
+
+ /* Check message imprints. */
+ if ((ctx->flags & TS_VFY_IMPRINT)
+ && !TS_check_imprints(ctx->md_alg, ctx->imprint, ctx->imprint_len,
+ tst_info))
+ goto err;
+
+ /* Compute and check message imprints. */
+ if ((ctx->flags & TS_VFY_DATA)
+ && (!TS_compute_imprint(ctx->data, tst_info,
+ &md_alg, &imprint, &imprint_len)
+ || !TS_check_imprints(md_alg, imprint, imprint_len, tst_info)))
+ goto err;
+
+ /* Check nonces. */
+ if ((ctx->flags & TS_VFY_NONCE)
+ && !TS_check_nonces(ctx->nonce, tst_info))
+ goto err;
+
+ /* Check whether TSA name and signer certificate match. */
+ if ((ctx->flags & TS_VFY_SIGNER)
+ && tsa_name && !TS_check_signer_name(tsa_name, signer))
+ {
+ TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_NAME_MISMATCH);
+ goto err;
+ }
+
+ /* Check whether the TSA is the expected one. */
+ if ((ctx->flags & TS_VFY_TSA_NAME)
+ && !TS_check_signer_name(ctx->tsa_name, signer))
+ {
+ TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_UNTRUSTED);
+ goto err;
+ }
+
+ ret = 1;
+ err:
+ X509_free(signer);
+ X509_ALGOR_free(md_alg);
+ OPENSSL_free(imprint);
+ return ret;
+ }
+
+static int TS_check_status_info(TS_RESP *response)
+ {
+ TS_STATUS_INFO *info = TS_RESP_get_status_info(response);
+ long status = ASN1_INTEGER_get(info->status);
+ const char *status_text = NULL;
+ char *embedded_status_text = NULL;
+ char failure_text[TS_STATUS_BUF_SIZE] = "";
+
+ /* Check if everything went fine. */
+ if (status == 0 || status == 1) return 1;
+
+ /* There was an error, get the description in status_text. */
+ if (0 <= status && status < (long)TS_STATUS_TEXT_SIZE)
+ status_text = TS_status_text[status];
+ else
+ status_text = "unknown code";
+
+ /* Set the embedded_status_text to the returned description. */
+ if (sk_ASN1_UTF8STRING_num(info->text) > 0
+ && !(embedded_status_text = TS_get_status_text(info->text)))
+ return 0;
+
+ /* Filling in failure_text with the failure information. */
+ if (info->failure_info)
+ {
+ int i;
+ int first = 1;
+ for (i = 0; i < (int)TS_FAILURE_INFO_SIZE; ++i)
+ {
+ if (ASN1_BIT_STRING_get_bit(info->failure_info,
+ TS_failure_info[i].code))
+ {
+ if (!first)
+ strcpy(failure_text, ",");
+ else
+ first = 0;
+ strcat(failure_text, TS_failure_info[i].text);
+ }
+ }
+ }
+ if (failure_text[0] == '\0')
+ strcpy(failure_text, "unspecified");
+
+ /* Making up the error string. */
+ TSerr(TS_F_TS_CHECK_STATUS_INFO, TS_R_NO_TIME_STAMP_TOKEN);
+ ERR_add_error_data(6,
+ "status code: ", status_text,
+ ", status text: ", embedded_status_text ?
+ embedded_status_text : "unspecified",
+ ", failure codes: ", failure_text);
+ OPENSSL_free(embedded_status_text);
+
+ return 0;
+ }
+
+static char *TS_get_status_text(STACK_OF(ASN1_UTF8STRING) *text)
+ {
+ int i;
+ unsigned int length = 0;
+ char *result = NULL;
+ char *p;
+
+ /* Determine length first. */
+ for (i = 0; i < sk_ASN1_UTF8STRING_num(text); ++i)
+ {
+ ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
+ length += ASN1_STRING_length(current);
+ length += 1; /* separator character */
+ }
+ /* Allocate memory (closing '\0' included). */
+ if (!(result = OPENSSL_malloc(length)))
+ {
+ TSerr(TS_F_TS_GET_STATUS_TEXT, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ /* Concatenate the descriptions. */
+ for (i = 0, p = result; i < sk_ASN1_UTF8STRING_num(text); ++i)
+ {
+ ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
+ length = ASN1_STRING_length(current);
+ if (i > 0) *p++ = '/';
+ strncpy(p, (const char *)ASN1_STRING_data(current), length);
+ p += length;
+ }
+ /* We do have space for this, too. */
+ *p = '\0';
+
+ return result;
+ }
+
+static int TS_check_policy(ASN1_OBJECT *req_oid, TS_TST_INFO *tst_info)
+ {
+ ASN1_OBJECT *resp_oid = TS_TST_INFO_get_policy_id(tst_info);
+
+ if (OBJ_cmp(req_oid, resp_oid) != 0)
+ {
+ TSerr(TS_F_TS_CHECK_POLICY, TS_R_POLICY_MISMATCH);
+ return 0;
+ }
+
+ return 1;
+ }
+
+static int TS_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
+ X509_ALGOR **md_alg,
+ unsigned char **imprint, unsigned *imprint_len)
+ {
+ TS_MSG_IMPRINT *msg_imprint = TS_TST_INFO_get_msg_imprint(tst_info);
+ X509_ALGOR *md_alg_resp = TS_MSG_IMPRINT_get_algo(msg_imprint);
+ const EVP_MD *md;
+ EVP_MD_CTX md_ctx;
+ unsigned char buffer[4096];
+ int length;
+
+ *md_alg = NULL;
+ *imprint = NULL;
+
+ /* Return the MD algorithm of the response. */
+ if (!(*md_alg = X509_ALGOR_dup(md_alg_resp))) goto err;
+
+ /* Getting the MD object. */
+ if (!(md = EVP_get_digestbyobj((*md_alg)->algorithm)))
+ {
+ TSerr(TS_F_TS_COMPUTE_IMPRINT, TS_R_UNSUPPORTED_MD_ALGORITHM);
+ goto err;
+ }
+
+ /* Compute message digest. */
+ length = EVP_MD_size(md);
+ if (length < 0)
+ goto err;
+ *imprint_len = length;
+ if (!(*imprint = OPENSSL_malloc(*imprint_len)))
+ {
+ TSerr(TS_F_TS_COMPUTE_IMPRINT, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!EVP_DigestInit(&md_ctx, md))
+ goto err;
+ while ((length = BIO_read(data, buffer, sizeof(buffer))) > 0)
+ {
+ if (!EVP_DigestUpdate(&md_ctx, buffer, length))
+ goto err;
+ }
+ if (!EVP_DigestFinal(&md_ctx, *imprint, NULL))
+ goto err;
+
+ return 1;
+ err:
+ X509_ALGOR_free(*md_alg);
+ OPENSSL_free(*imprint);
+ *imprint_len = 0;
+ *imprint = NULL;
+ return 0;
+ }
+
+static int TS_check_imprints(X509_ALGOR *algor_a,
+ unsigned char *imprint_a, unsigned len_a,
+ TS_TST_INFO *tst_info)
+ {
+ TS_MSG_IMPRINT *b = TS_TST_INFO_get_msg_imprint(tst_info);
+ X509_ALGOR *algor_b = TS_MSG_IMPRINT_get_algo(b);
+ int ret = 0;
+
+ /* algor_a is optional. */
+ if (algor_a)
+ {
+ /* Compare algorithm OIDs. */
+ if (OBJ_cmp(algor_a->algorithm, algor_b->algorithm)) goto err;
+
+ /* The parameter must be NULL in both. */
+ if ((algor_a->parameter
+ && ASN1_TYPE_get(algor_a->parameter) != V_ASN1_NULL)
+ || (algor_b->parameter
+ && ASN1_TYPE_get(algor_b->parameter) != V_ASN1_NULL))
+ goto err;
+ }
+
+ /* Compare octet strings. */
+ ret = len_a == (unsigned) ASN1_STRING_length(b->hashed_msg) &&
+ memcmp(imprint_a, ASN1_STRING_data(b->hashed_msg), len_a) == 0;
+ err:
+ if (!ret)
+ TSerr(TS_F_TS_CHECK_IMPRINTS, TS_R_MESSAGE_IMPRINT_MISMATCH);
+ return ret;
+ }
+
+static int TS_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info)
+ {
+ const ASN1_INTEGER *b = TS_TST_INFO_get_nonce(tst_info);
+
+ /* Error if nonce is missing. */
+ if (!b)
+ {
+ TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_NOT_RETURNED);
+ return 0;
+ }
+
+ /* No error if a nonce is returned without being requested. */
+ if (ASN1_INTEGER_cmp(a, b) != 0)
+ {
+ TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_MISMATCH);
+ return 0;
+ }
+
+ return 1;
+ }
+
+/* Check if the specified TSA name matches either the subject
+ or one of the subject alternative names of the TSA certificate. */
+static int TS_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer)
+ {
+ STACK_OF(GENERAL_NAME) *gen_names = NULL;
+ int idx = -1;
+ int found = 0;
+
+ /* Check the subject name first. */
+ if (tsa_name->type == GEN_DIRNAME
+ && X509_name_cmp(tsa_name->d.dirn, signer->cert_info->subject) == 0)
+ return 1;
+
+ /* Check all the alternative names. */
+ gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name,
+ NULL, &idx);
+ while (gen_names != NULL
+ && !(found = TS_find_name(gen_names, tsa_name) >= 0))
+ {
+ /* Get the next subject alternative name,
+ although there should be no more than one. */
+ GENERAL_NAMES_free(gen_names);
+ gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name,
+ NULL, &idx);
+ }
+ if (gen_names) GENERAL_NAMES_free(gen_names);
+
+ return found;
+ }
+
+/* Returns 1 if name is in gen_names, 0 otherwise. */
+static int TS_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name)
+ {
+ int i, found;
+ for (i = 0, found = 0; !found && i < sk_GENERAL_NAME_num(gen_names);
+ ++i)
+ {
+ GENERAL_NAME *current = sk_GENERAL_NAME_value(gen_names, i);
+ found = GENERAL_NAME_cmp(current, name) == 0;
+ }
+ return found ? i - 1 : -1;
+ }
diff --git a/drivers/builtin_openssl/crypto/ts/ts_verify_ctx.c b/drivers/builtin_openssl2/crypto/ts/ts_verify_ctx.c
index 609b7735d4..609b7735d4 100644
--- a/drivers/builtin_openssl/crypto/ts/ts_verify_ctx.c
+++ b/drivers/builtin_openssl2/crypto/ts/ts_verify_ctx.c
diff --git a/drivers/builtin_openssl/crypto/txt_db/txt_db.c b/drivers/builtin_openssl2/crypto/txt_db/txt_db.c
index 6f2ce3b5a4..6f2ce3b5a4 100644
--- a/drivers/builtin_openssl/crypto/txt_db/txt_db.c
+++ b/drivers/builtin_openssl2/crypto/txt_db/txt_db.c
diff --git a/drivers/builtin_openssl/crypto/ui/ui_compat.c b/drivers/builtin_openssl2/crypto/ui/ui_compat.c
index 13e0f70d90..13e0f70d90 100644
--- a/drivers/builtin_openssl/crypto/ui/ui_compat.c
+++ b/drivers/builtin_openssl2/crypto/ui/ui_compat.c
diff --git a/drivers/builtin_openssl/crypto/ui/ui_err.c b/drivers/builtin_openssl2/crypto/ui/ui_err.c
index a6b96299a0..a6b96299a0 100644
--- a/drivers/builtin_openssl/crypto/ui/ui_err.c
+++ b/drivers/builtin_openssl2/crypto/ui/ui_err.c
diff --git a/drivers/builtin_openssl/crypto/ui/ui_lib.c b/drivers/builtin_openssl2/crypto/ui/ui_lib.c
index a8abc27064..a8abc27064 100644
--- a/drivers/builtin_openssl/crypto/ui/ui_lib.c
+++ b/drivers/builtin_openssl2/crypto/ui/ui_lib.c
diff --git a/drivers/builtin_openssl/crypto/ui/ui_locl.h b/drivers/builtin_openssl2/crypto/ui/ui_locl.h
index aa4a55637d..aa4a55637d 100644
--- a/drivers/builtin_openssl/crypto/ui/ui_locl.h
+++ b/drivers/builtin_openssl2/crypto/ui/ui_locl.h
diff --git a/drivers/builtin_openssl/crypto/ui/ui_openssl.c b/drivers/builtin_openssl2/crypto/ui/ui_openssl.c
index a38c7581e6..a38c7581e6 100644
--- a/drivers/builtin_openssl/crypto/ui/ui_openssl.c
+++ b/drivers/builtin_openssl2/crypto/ui/ui_openssl.c
diff --git a/drivers/builtin_openssl/crypto/ui/ui_util.c b/drivers/builtin_openssl2/crypto/ui/ui_util.c
index 5d9760bb7b..5d9760bb7b 100644
--- a/drivers/builtin_openssl/crypto/ui/ui_util.c
+++ b/drivers/builtin_openssl2/crypto/ui/ui_util.c
diff --git a/drivers/builtin_openssl/crypto/uid.c b/drivers/builtin_openssl2/crypto/uid.c
index b1fd52bada..b1fd52bada 100644
--- a/drivers/builtin_openssl/crypto/uid.c
+++ b/drivers/builtin_openssl2/crypto/uid.c
diff --git a/drivers/builtin_openssl/crypto/vms_rms.h b/drivers/builtin_openssl2/crypto/vms_rms.h
index 00a00d993f..00a00d993f 100755
--- a/drivers/builtin_openssl/crypto/vms_rms.h
+++ b/drivers/builtin_openssl2/crypto/vms_rms.h
diff --git a/drivers/builtin_openssl/crypto/whrlpool/asm/wp-mmx.pl b/drivers/builtin_openssl2/crypto/whrlpool/asm/wp-mmx.pl
index cb2381c22b..cb2381c22b 100644
--- a/drivers/builtin_openssl/crypto/whrlpool/asm/wp-mmx.pl
+++ b/drivers/builtin_openssl2/crypto/whrlpool/asm/wp-mmx.pl
diff --git a/drivers/builtin_openssl/crypto/whrlpool/asm/wp-x86_64.pl b/drivers/builtin_openssl2/crypto/whrlpool/asm/wp-x86_64.pl
index 24b2ff60c3..24b2ff60c3 100644
--- a/drivers/builtin_openssl/crypto/whrlpool/asm/wp-x86_64.pl
+++ b/drivers/builtin_openssl2/crypto/whrlpool/asm/wp-x86_64.pl
diff --git a/drivers/builtin_openssl/crypto/whrlpool/wp_block.c b/drivers/builtin_openssl2/crypto/whrlpool/wp_block.c
index 824ed1827c..824ed1827c 100644
--- a/drivers/builtin_openssl/crypto/whrlpool/wp_block.c
+++ b/drivers/builtin_openssl2/crypto/whrlpool/wp_block.c
diff --git a/drivers/builtin_openssl/crypto/whrlpool/wp_dgst.c b/drivers/builtin_openssl2/crypto/whrlpool/wp_dgst.c
index 7e28bef51d..7e28bef51d 100644
--- a/drivers/builtin_openssl/crypto/whrlpool/wp_dgst.c
+++ b/drivers/builtin_openssl2/crypto/whrlpool/wp_dgst.c
diff --git a/drivers/builtin_openssl/crypto/whrlpool/wp_locl.h b/drivers/builtin_openssl2/crypto/whrlpool/wp_locl.h
index 94e56a39f1..94e56a39f1 100644
--- a/drivers/builtin_openssl/crypto/whrlpool/wp_locl.h
+++ b/drivers/builtin_openssl2/crypto/whrlpool/wp_locl.h
diff --git a/drivers/builtin_openssl/crypto/whrlpool/wp_test.c b/drivers/builtin_openssl2/crypto/whrlpool/wp_test.c
index c68c2c62ca..c68c2c62ca 100644
--- a/drivers/builtin_openssl/crypto/whrlpool/wp_test.c
+++ b/drivers/builtin_openssl2/crypto/whrlpool/wp_test.c
diff --git a/drivers/builtin_openssl/crypto/x509/by_dir.c b/drivers/builtin_openssl2/crypto/x509/by_dir.c
index c6602dae4f..c6602dae4f 100644
--- a/drivers/builtin_openssl/crypto/x509/by_dir.c
+++ b/drivers/builtin_openssl2/crypto/x509/by_dir.c
diff --git a/drivers/builtin_openssl/crypto/x509/by_file.c b/drivers/builtin_openssl2/crypto/x509/by_file.c
index 57b08ee094..57b08ee094 100644
--- a/drivers/builtin_openssl/crypto/x509/by_file.c
+++ b/drivers/builtin_openssl2/crypto/x509/by_file.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_att.c b/drivers/builtin_openssl2/crypto/x509/x509_att.c
index 98460e8921..98460e8921 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_att.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_att.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_cmp.c b/drivers/builtin_openssl2/crypto/x509/x509_cmp.c
index 352aa37434..352aa37434 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_cmp.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_cmp.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_d2.c b/drivers/builtin_openssl2/crypto/x509/x509_d2.c
index 51410cfd1a..51410cfd1a 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_d2.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_d2.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_def.c b/drivers/builtin_openssl2/crypto/x509/x509_def.c
index e0ac151a76..e0ac151a76 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_def.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_def.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_err.c b/drivers/builtin_openssl2/crypto/x509/x509_err.c
index a01402f416..a01402f416 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_err.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_err.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_ext.c b/drivers/builtin_openssl2/crypto/x509/x509_ext.c
index e7fdacb5e4..e7fdacb5e4 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_ext.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_ext.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_lu.c b/drivers/builtin_openssl2/crypto/x509/x509_lu.c
index 38525a8cdd..38525a8cdd 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_lu.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_lu.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_obj.c b/drivers/builtin_openssl2/crypto/x509/x509_obj.c
index 21fed9f838..21fed9f838 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_obj.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_obj.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_r2x.c b/drivers/builtin_openssl2/crypto/x509/x509_r2x.c
index 254a14693d..254a14693d 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_r2x.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_r2x.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_req.c b/drivers/builtin_openssl2/crypto/x509/x509_req.c
index 48183dc00c..48183dc00c 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_req.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_req.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_set.c b/drivers/builtin_openssl2/crypto/x509/x509_set.c
index 4b94fc5847..4b94fc5847 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_set.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_set.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_trs.c b/drivers/builtin_openssl2/crypto/x509/x509_trs.c
index a6cb9c8b1b..a6cb9c8b1b 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_trs.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_trs.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_txt.c b/drivers/builtin_openssl2/crypto/x509/x509_txt.c
index c44f753c46..c44f753c46 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_txt.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_txt.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_v3.c b/drivers/builtin_openssl2/crypto/x509/x509_v3.c
index 42e6f0ab05..42e6f0ab05 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_v3.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_v3.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_vfy.c b/drivers/builtin_openssl2/crypto/x509/x509_vfy.c
index 920066aeba..920066aeba 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_vfy.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_vfy.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509_vpm.c b/drivers/builtin_openssl2/crypto/x509/x509_vpm.c
index dfd89d89fa..dfd89d89fa 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_vpm.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_vpm.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509cset.c b/drivers/builtin_openssl2/crypto/x509/x509cset.c
index 3109defb0b..3109defb0b 100644
--- a/drivers/builtin_openssl/crypto/x509/x509cset.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509cset.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509name.c b/drivers/builtin_openssl2/crypto/x509/x509name.c
index 27bc4dc9a3..27bc4dc9a3 100644
--- a/drivers/builtin_openssl/crypto/x509/x509name.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509name.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509rset.c b/drivers/builtin_openssl2/crypto/x509/x509rset.c
index d9f6b57372..d9f6b57372 100644
--- a/drivers/builtin_openssl/crypto/x509/x509rset.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509rset.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509spki.c b/drivers/builtin_openssl2/crypto/x509/x509spki.c
index 02a203d72c..02a203d72c 100644
--- a/drivers/builtin_openssl/crypto/x509/x509spki.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509spki.c
diff --git a/drivers/builtin_openssl/crypto/x509/x509type.c b/drivers/builtin_openssl2/crypto/x509/x509type.c
index 9702ec5310..9702ec5310 100644
--- a/drivers/builtin_openssl/crypto/x509/x509type.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509type.c
diff --git a/drivers/builtin_openssl/crypto/x509/x_all.c b/drivers/builtin_openssl2/crypto/x509/x_all.c
index e06602d65a..e06602d65a 100644
--- a/drivers/builtin_openssl/crypto/x509/x_all.c
+++ b/drivers/builtin_openssl2/crypto/x509/x_all.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/ext_dat.h b/drivers/builtin_openssl2/crypto/x509v3/ext_dat.h
index 76daee6fcd..76daee6fcd 100644
--- a/drivers/builtin_openssl/crypto/x509v3/ext_dat.h
+++ b/drivers/builtin_openssl2/crypto/x509v3/ext_dat.h
diff --git a/drivers/builtin_openssl/crypto/x509v3/pcy_cache.c b/drivers/builtin_openssl2/crypto/x509v3/pcy_cache.c
index 172b7e7ee4..172b7e7ee4 100644
--- a/drivers/builtin_openssl/crypto/x509v3/pcy_cache.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/pcy_cache.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/pcy_data.c b/drivers/builtin_openssl2/crypto/x509v3/pcy_data.c
index 3444b03195..3444b03195 100644
--- a/drivers/builtin_openssl/crypto/x509v3/pcy_data.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/pcy_data.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/pcy_int.h b/drivers/builtin_openssl2/crypto/x509v3/pcy_int.h
index ccff92846e..ccff92846e 100644
--- a/drivers/builtin_openssl/crypto/x509v3/pcy_int.h
+++ b/drivers/builtin_openssl2/crypto/x509v3/pcy_int.h
diff --git a/drivers/builtin_openssl/crypto/x509v3/pcy_lib.c b/drivers/builtin_openssl2/crypto/x509v3/pcy_lib.c
index 93bfd92703..93bfd92703 100644
--- a/drivers/builtin_openssl/crypto/x509v3/pcy_lib.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/pcy_lib.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/pcy_map.c b/drivers/builtin_openssl2/crypto/x509v3/pcy_map.c
index 21163b529d..21163b529d 100644
--- a/drivers/builtin_openssl/crypto/x509v3/pcy_map.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/pcy_map.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/pcy_node.c b/drivers/builtin_openssl2/crypto/x509v3/pcy_node.c
index bd1e7f1ae8..bd1e7f1ae8 100644
--- a/drivers/builtin_openssl/crypto/x509v3/pcy_node.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/pcy_node.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/pcy_tree.c b/drivers/builtin_openssl2/crypto/x509v3/pcy_tree.c
index bb9777348f..bb9777348f 100644
--- a/drivers/builtin_openssl/crypto/x509v3/pcy_tree.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/pcy_tree.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/tabtest.c b/drivers/builtin_openssl2/crypto/x509v3/tabtest.c
index 5ed6eb6891..5ed6eb6891 100644
--- a/drivers/builtin_openssl/crypto/x509v3/tabtest.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/tabtest.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_addr.c b/drivers/builtin_openssl2/crypto/x509v3/v3_addr.c
index df46a4983b..df46a4983b 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_addr.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_addr.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_akey.c b/drivers/builtin_openssl2/crypto/x509v3/v3_akey.c
index c6b68ee221..c6b68ee221 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_akey.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_akey.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_akeya.c b/drivers/builtin_openssl2/crypto/x509v3/v3_akeya.c
index 2c50f7360e..2c50f7360e 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_akeya.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_akeya.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_alt.c b/drivers/builtin_openssl2/crypto/x509v3/v3_alt.c
index d29d94338e..d29d94338e 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_alt.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_alt.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_asid.c b/drivers/builtin_openssl2/crypto/x509v3/v3_asid.c
index 1587e8ed72..1587e8ed72 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_asid.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_asid.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_bcons.c b/drivers/builtin_openssl2/crypto/x509v3/v3_bcons.c
index 82aa488f75..82aa488f75 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_bcons.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_bcons.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_bitst.c b/drivers/builtin_openssl2/crypto/x509v3/v3_bitst.c
index 058d0d4dce..058d0d4dce 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_bitst.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_bitst.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_conf.c b/drivers/builtin_openssl2/crypto/x509v3/v3_conf.c
index 6730f9a6ee..6730f9a6ee 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_conf.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_conf.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_cpols.c b/drivers/builtin_openssl2/crypto/x509v3/v3_cpols.c
index 1f0798b946..1f0798b946 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_cpols.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_cpols.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_crld.c b/drivers/builtin_openssl2/crypto/x509v3/v3_crld.c
index 790a6dd032..790a6dd032 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_crld.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_crld.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_enum.c b/drivers/builtin_openssl2/crypto/x509v3/v3_enum.c
index c0575e368d..c0575e368d 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_enum.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_enum.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_extku.c b/drivers/builtin_openssl2/crypto/x509v3/v3_extku.c
index 1c66532757..1c66532757 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_extku.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_extku.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_genn.c b/drivers/builtin_openssl2/crypto/x509v3/v3_genn.c
index b628357301..b628357301 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_genn.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_genn.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_ia5.c b/drivers/builtin_openssl2/crypto/x509v3/v3_ia5.c
index 4ff12b52b5..4ff12b52b5 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_ia5.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_ia5.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_info.c b/drivers/builtin_openssl2/crypto/x509v3/v3_info.c
index e1b8699f92..e1b8699f92 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_info.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_info.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_int.c b/drivers/builtin_openssl2/crypto/x509v3/v3_int.c
index 4bfd14cf46..4bfd14cf46 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_int.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_int.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_lib.c b/drivers/builtin_openssl2/crypto/x509v3/v3_lib.c
index 0f1e1d4422..0f1e1d4422 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_lib.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_lib.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_ncons.c b/drivers/builtin_openssl2/crypto/x509v3/v3_ncons.c
index a01dc64dd2..a01dc64dd2 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_ncons.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_ncons.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_ocsp.c b/drivers/builtin_openssl2/crypto/x509v3/v3_ocsp.c
index 0c165af314..0c165af314 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_ocsp.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_ocsp.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_pci.c b/drivers/builtin_openssl2/crypto/x509v3/v3_pci.c
index 0dcfa004fe..0dcfa004fe 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_pci.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_pci.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_pcia.c b/drivers/builtin_openssl2/crypto/x509v3/v3_pcia.c
index bb362e0e5a..bb362e0e5a 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_pcia.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_pcia.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_pcons.c b/drivers/builtin_openssl2/crypto/x509v3/v3_pcons.c
index 30ca652351..30ca652351 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_pcons.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_pcons.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_pku.c b/drivers/builtin_openssl2/crypto/x509v3/v3_pku.c
index 076f3ff48e..076f3ff48e 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_pku.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_pku.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_pmaps.c b/drivers/builtin_openssl2/crypto/x509v3/v3_pmaps.c
index 865bcd3980..865bcd3980 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_pmaps.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_pmaps.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_prn.c b/drivers/builtin_openssl2/crypto/x509v3/v3_prn.c
index 3146218708..3146218708 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_prn.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_prn.c
diff --git a/drivers/builtin_openssl2/crypto/x509v3/v3_purp.c b/drivers/builtin_openssl2/crypto/x509v3/v3_purp.c
new file mode 100644
index 0000000000..f59bfc1844
--- /dev/null
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_purp.c
@@ -0,0 +1,767 @@
+/* v3_purp.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2001.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2004 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+
+static void x509v3_cache_extensions(X509 *x);
+
+static int check_ssl_ca(const X509 *x);
+static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int purpose_smime(const X509 *x, int ca);
+static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
+
+static int xp_cmp(const X509_PURPOSE * const *a,
+ const X509_PURPOSE * const *b);
+static void xptable_free(X509_PURPOSE *p);
+
+static X509_PURPOSE xstandard[] = {
+ {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, "SSL client", "sslclient", NULL},
+ {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ssl_server, "SSL server", "sslserver", NULL},
+ {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
+ {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, "S/MIME signing", "smimesign", NULL},
+ {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
+ {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL},
+ {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", NULL},
+ {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL},
+ {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", NULL},
+};
+
+#define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
+
+IMPLEMENT_STACK_OF(X509_PURPOSE)
+
+static STACK_OF(X509_PURPOSE) *xptable = NULL;
+
+static int xp_cmp(const X509_PURPOSE * const *a,
+ const X509_PURPOSE * const *b)
+{
+ return (*a)->purpose - (*b)->purpose;
+}
+
+/* As much as I'd like to make X509_check_purpose use a "const" X509*
+ * I really can't because it does recalculate hashes and do other non-const
+ * things. */
+int X509_check_purpose(X509 *x, int id, int ca)
+{
+ int idx;
+ const X509_PURPOSE *pt;
+ if(!(x->ex_flags & EXFLAG_SET)) {
+ CRYPTO_w_lock(CRYPTO_LOCK_X509);
+ x509v3_cache_extensions(x);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+ }
+ if(id == -1) return 1;
+ idx = X509_PURPOSE_get_by_id(id);
+ if(idx == -1) return -1;
+ pt = X509_PURPOSE_get0(idx);
+ return pt->check_purpose(pt, x, ca);
+}
+
+int X509_PURPOSE_set(int *p, int purpose)
+{
+ if(X509_PURPOSE_get_by_id(purpose) == -1) {
+ X509V3err(X509V3_F_X509_PURPOSE_SET, X509V3_R_INVALID_PURPOSE);
+ return 0;
+ }
+ *p = purpose;
+ return 1;
+}
+
+int X509_PURPOSE_get_count(void)
+{
+ if(!xptable) return X509_PURPOSE_COUNT;
+ return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
+}
+
+X509_PURPOSE * X509_PURPOSE_get0(int idx)
+{
+ if(idx < 0) return NULL;
+ if(idx < (int)X509_PURPOSE_COUNT) return xstandard + idx;
+ return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
+}
+
+int X509_PURPOSE_get_by_sname(char *sname)
+{
+ int i;
+ X509_PURPOSE *xptmp;
+ for(i = 0; i < X509_PURPOSE_get_count(); i++) {
+ xptmp = X509_PURPOSE_get0(i);
+ if(!strcmp(xptmp->sname, sname)) return i;
+ }
+ return -1;
+}
+
+int X509_PURPOSE_get_by_id(int purpose)
+{
+ X509_PURPOSE tmp;
+ int idx;
+ if((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX))
+ return purpose - X509_PURPOSE_MIN;
+ tmp.purpose = purpose;
+ if(!xptable) return -1;
+ idx = sk_X509_PURPOSE_find(xptable, &tmp);
+ if(idx == -1) return -1;
+ return idx + X509_PURPOSE_COUNT;
+}
+
+int X509_PURPOSE_add(int id, int trust, int flags,
+ int (*ck)(const X509_PURPOSE *, const X509 *, int),
+ char *name, char *sname, void *arg)
+{
+ int idx;
+ X509_PURPOSE *ptmp;
+ /* This is set according to what we change: application can't set it */
+ flags &= ~X509_PURPOSE_DYNAMIC;
+ /* This will always be set for application modified trust entries */
+ flags |= X509_PURPOSE_DYNAMIC_NAME;
+ /* Get existing entry if any */
+ idx = X509_PURPOSE_get_by_id(id);
+ /* Need a new entry */
+ if(idx == -1) {
+ if(!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) {
+ X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ptmp->flags = X509_PURPOSE_DYNAMIC;
+ } else ptmp = X509_PURPOSE_get0(idx);
+
+ /* OPENSSL_free existing name if dynamic */
+ if(ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
+ OPENSSL_free(ptmp->name);
+ OPENSSL_free(ptmp->sname);
+ }
+ /* dup supplied name */
+ ptmp->name = BUF_strdup(name);
+ ptmp->sname = BUF_strdup(sname);
+ if(!ptmp->name || !ptmp->sname) {
+ X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ /* Keep the dynamic flag of existing entry */
+ ptmp->flags &= X509_PURPOSE_DYNAMIC;
+ /* Set all other flags */
+ ptmp->flags |= flags;
+
+ ptmp->purpose = id;
+ ptmp->trust = trust;
+ ptmp->check_purpose = ck;
+ ptmp->usr_data = arg;
+
+ /* If its a new entry manage the dynamic table */
+ if(idx == -1) {
+ if(!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) {
+ X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
+ X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void xptable_free(X509_PURPOSE *p)
+ {
+ if(!p) return;
+ if (p->flags & X509_PURPOSE_DYNAMIC)
+ {
+ if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
+ OPENSSL_free(p->name);
+ OPENSSL_free(p->sname);
+ }
+ OPENSSL_free(p);
+ }
+ }
+
+void X509_PURPOSE_cleanup(void)
+{
+ unsigned int i;
+ sk_X509_PURPOSE_pop_free(xptable, xptable_free);
+ for(i = 0; i < X509_PURPOSE_COUNT; i++) xptable_free(xstandard + i);
+ xptable = NULL;
+}
+
+int X509_PURPOSE_get_id(X509_PURPOSE *xp)
+{
+ return xp->purpose;
+}
+
+char *X509_PURPOSE_get0_name(X509_PURPOSE *xp)
+{
+ return xp->name;
+}
+
+char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp)
+{
+ return xp->sname;
+}
+
+int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
+{
+ return xp->trust;
+}
+
+static int nid_cmp(const int *a, const int *b)
+ {
+ return *a - *b;
+ }
+
+DECLARE_OBJ_BSEARCH_CMP_FN(int, int, nid);
+IMPLEMENT_OBJ_BSEARCH_CMP_FN(int, int, nid);
+
+int X509_supported_extension(X509_EXTENSION *ex)
+ {
+ /* This table is a list of the NIDs of supported extensions:
+ * that is those which are used by the verify process. If
+ * an extension is critical and doesn't appear in this list
+ * then the verify process will normally reject the certificate.
+ * The list must be kept in numerical order because it will be
+ * searched using bsearch.
+ */
+
+ static const int supported_nids[] = {
+ NID_netscape_cert_type, /* 71 */
+ NID_key_usage, /* 83 */
+ NID_subject_alt_name, /* 85 */
+ NID_basic_constraints, /* 87 */
+ NID_certificate_policies, /* 89 */
+ NID_ext_key_usage, /* 126 */
+#ifndef OPENSSL_NO_RFC3779
+ NID_sbgp_ipAddrBlock, /* 290 */
+ NID_sbgp_autonomousSysNum, /* 291 */
+#endif
+ NID_policy_constraints, /* 401 */
+ NID_proxyCertInfo, /* 663 */
+ NID_name_constraints, /* 666 */
+ NID_policy_mappings, /* 747 */
+ NID_inhibit_any_policy /* 748 */
+ };
+
+ int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
+
+ if (ex_nid == NID_undef)
+ return 0;
+
+ if (OBJ_bsearch_nid(&ex_nid, supported_nids,
+ sizeof(supported_nids)/sizeof(int)))
+ return 1;
+ return 0;
+ }
+
+static void setup_dp(X509 *x, DIST_POINT *dp)
+ {
+ X509_NAME *iname = NULL;
+ int i;
+ if (dp->reasons)
+ {
+ if (dp->reasons->length > 0)
+ dp->dp_reasons = dp->reasons->data[0];
+ if (dp->reasons->length > 1)
+ dp->dp_reasons |= (dp->reasons->data[1] << 8);
+ dp->dp_reasons &= CRLDP_ALL_REASONS;
+ }
+ else
+ dp->dp_reasons = CRLDP_ALL_REASONS;
+ if (!dp->distpoint || (dp->distpoint->type != 1))
+ return;
+ for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++)
+ {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
+ if (gen->type == GEN_DIRNAME)
+ {
+ iname = gen->d.directoryName;
+ break;
+ }
+ }
+ if (!iname)
+ iname = X509_get_issuer_name(x);
+
+ DIST_POINT_set_dpname(dp->distpoint, iname);
+
+ }
+
+static void setup_crldp(X509 *x)
+ {
+ int i;
+ x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL);
+ for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++)
+ setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
+ }
+
+static void x509v3_cache_extensions(X509 *x)
+{
+ BASIC_CONSTRAINTS *bs;
+ PROXY_CERT_INFO_EXTENSION *pci;
+ ASN1_BIT_STRING *usage;
+ ASN1_BIT_STRING *ns;
+ EXTENDED_KEY_USAGE *extusage;
+ X509_EXTENSION *ex;
+
+ int i;
+ if(x->ex_flags & EXFLAG_SET) return;
+#ifndef OPENSSL_NO_SHA
+ X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
+#endif
+ /* Does subject name match issuer ? */
+ if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
+ x->ex_flags |= EXFLAG_SI;
+ /* V1 should mean no extensions ... */
+ if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;
+ /* Handle basic constraints */
+ if((bs=X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) {
+ if(bs->ca) x->ex_flags |= EXFLAG_CA;
+ if(bs->pathlen) {
+ if((bs->pathlen->type == V_ASN1_NEG_INTEGER)
+ || !bs->ca) {
+ x->ex_flags |= EXFLAG_INVALID;
+ x->ex_pathlen = 0;
+ } else x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
+ } else x->ex_pathlen = -1;
+ BASIC_CONSTRAINTS_free(bs);
+ x->ex_flags |= EXFLAG_BCONS;
+ }
+ /* Handle proxy certificates */
+ if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
+ if (x->ex_flags & EXFLAG_CA
+ || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0
+ || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) {
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+ if (pci->pcPathLengthConstraint) {
+ x->ex_pcpathlen =
+ ASN1_INTEGER_get(pci->pcPathLengthConstraint);
+ } else x->ex_pcpathlen = -1;
+ PROXY_CERT_INFO_EXTENSION_free(pci);
+ x->ex_flags |= EXFLAG_PROXY;
+ }
+ /* Handle key usage */
+ if((usage=X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
+ if(usage->length > 0) {
+ x->ex_kusage = usage->data[0];
+ if(usage->length > 1)
+ x->ex_kusage |= usage->data[1] << 8;
+ } else x->ex_kusage = 0;
+ x->ex_flags |= EXFLAG_KUSAGE;
+ ASN1_BIT_STRING_free(usage);
+ }
+ x->ex_xkusage = 0;
+ if((extusage=X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) {
+ x->ex_flags |= EXFLAG_XKUSAGE;
+ for(i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
+ switch(OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage,i))) {
+ case NID_server_auth:
+ x->ex_xkusage |= XKU_SSL_SERVER;
+ break;
+
+ case NID_client_auth:
+ x->ex_xkusage |= XKU_SSL_CLIENT;
+ break;
+
+ case NID_email_protect:
+ x->ex_xkusage |= XKU_SMIME;
+ break;
+
+ case NID_code_sign:
+ x->ex_xkusage |= XKU_CODE_SIGN;
+ break;
+
+ case NID_ms_sgc:
+ case NID_ns_sgc:
+ x->ex_xkusage |= XKU_SGC;
+ break;
+
+ case NID_OCSP_sign:
+ x->ex_xkusage |= XKU_OCSP_SIGN;
+ break;
+
+ case NID_time_stamp:
+ x->ex_xkusage |= XKU_TIMESTAMP;
+ break;
+
+ case NID_dvcs:
+ x->ex_xkusage |= XKU_DVCS;
+ break;
+ }
+ }
+ sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
+ }
+
+ if((ns=X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) {
+ if(ns->length > 0) x->ex_nscert = ns->data[0];
+ else x->ex_nscert = 0;
+ x->ex_flags |= EXFLAG_NSCERT;
+ ASN1_BIT_STRING_free(ns);
+ }
+ x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
+ x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
+ x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+ x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL);
+ if (!x->nc && (i != -1))
+ x->ex_flags |= EXFLAG_INVALID;
+ setup_crldp(x);
+
+#ifndef OPENSSL_NO_RFC3779
+ x->rfc3779_addr =X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
+ x->rfc3779_asid =X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum,
+ NULL, NULL);
+#endif
+ for (i = 0; i < X509_get_ext_count(x); i++)
+ {
+ ex = X509_get_ext(x, i);
+ if (OBJ_obj2nid(X509_EXTENSION_get_object(ex))
+ == NID_freshest_crl)
+ x->ex_flags |= EXFLAG_FRESHEST;
+ if (!X509_EXTENSION_get_critical(ex))
+ continue;
+ if (!X509_supported_extension(ex))
+ {
+ x->ex_flags |= EXFLAG_CRITICAL;
+ break;
+ }
+ }
+ x->ex_flags |= EXFLAG_SET;
+}
+
+/* CA checks common to all purposes
+ * return codes:
+ * 0 not a CA
+ * 1 is a CA
+ * 2 basicConstraints absent so "maybe" a CA
+ * 3 basicConstraints absent but self signed V1.
+ * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
+ */
+
+#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
+#define ku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
+#define xku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
+#define ns_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
+
+static int check_ca(const X509 *x)
+{
+ /* keyUsage if present should allow cert signing */
+ if(ku_reject(x, KU_KEY_CERT_SIGN)) return 0;
+ if(x->ex_flags & EXFLAG_BCONS) {
+ if(x->ex_flags & EXFLAG_CA) return 1;
+ /* If basicConstraints says not a CA then say so */
+ else return 0;
+ } else {
+ /* we support V1 roots for... uh, I don't really know why. */
+ if((x->ex_flags & V1_ROOT) == V1_ROOT) return 3;
+ /* If key usage present it must have certSign so tolerate it */
+ else if (x->ex_flags & EXFLAG_KUSAGE) return 4;
+ /* Older certificates could have Netscape-specific CA types */
+ else if (x->ex_flags & EXFLAG_NSCERT
+ && x->ex_nscert & NS_ANY_CA) return 5;
+ /* can this still be regarded a CA certificate? I doubt it */
+ return 0;
+ }
+}
+
+int X509_check_ca(X509 *x)
+{
+ if(!(x->ex_flags & EXFLAG_SET)) {
+ CRYPTO_w_lock(CRYPTO_LOCK_X509);
+ x509v3_cache_extensions(x);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+ }
+
+ return check_ca(x);
+}
+
+/* Check SSL CA: common checks for SSL client and server */
+static int check_ssl_ca(const X509 *x)
+{
+ int ca_ret;
+ ca_ret = check_ca(x);
+ if(!ca_ret) return 0;
+ /* check nsCertType if present */
+ if(ca_ret != 5 || x->ex_nscert & NS_SSL_CA) return ca_ret;
+ else return 0;
+}
+
+
+static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ if(xku_reject(x,XKU_SSL_CLIENT)) return 0;
+ if(ca) return check_ssl_ca(x);
+ /* We need to do digital signatures with it */
+ if(ku_reject(x,KU_DIGITAL_SIGNATURE)) return 0;
+ /* nsCertType if present should allow SSL client use */
+ if(ns_reject(x, NS_SSL_CLIENT)) return 0;
+ return 1;
+}
+
+static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ if(xku_reject(x,XKU_SSL_SERVER|XKU_SGC)) return 0;
+ if(ca) return check_ssl_ca(x);
+
+ if(ns_reject(x, NS_SSL_SERVER)) return 0;
+ /* Now as for keyUsage: we'll at least need to sign OR encipher */
+ if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT)) return 0;
+
+ return 1;
+
+}
+
+static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ int ret;
+ ret = check_purpose_ssl_server(xp, x, ca);
+ if(!ret || ca) return ret;
+ /* We need to encipher or Netscape complains */
+ if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0;
+ return ret;
+}
+
+/* common S/MIME checks */
+static int purpose_smime(const X509 *x, int ca)
+{
+ if(xku_reject(x,XKU_SMIME)) return 0;
+ if(ca) {
+ int ca_ret;
+ ca_ret = check_ca(x);
+ if(!ca_ret) return 0;
+ /* check nsCertType if present */
+ if(ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) return ca_ret;
+ else return 0;
+ }
+ if(x->ex_flags & EXFLAG_NSCERT) {
+ if(x->ex_nscert & NS_SMIME) return 1;
+ /* Workaround for some buggy certificates */
+ if(x->ex_nscert & NS_SSL_CLIENT) return 2;
+ return 0;
+ }
+ return 1;
+}
+
+static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ int ret;
+ ret = purpose_smime(x, ca);
+ if(!ret || ca) return ret;
+ if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_NON_REPUDIATION)) return 0;
+ return ret;
+}
+
+static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ int ret;
+ ret = purpose_smime(x, ca);
+ if(!ret || ca) return ret;
+ if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0;
+ return ret;
+}
+
+static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ if(ca) {
+ int ca_ret;
+ if((ca_ret = check_ca(x)) != 2) return ca_ret;
+ else return 0;
+ }
+ if(ku_reject(x, KU_CRL_SIGN)) return 0;
+ return 1;
+}
+
+/* OCSP helper: this is *not* a full OCSP check. It just checks that
+ * each CA is valid. Additional checks must be made on the chain.
+ */
+
+static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ /* Must be a valid CA. Should we really support the "I don't know"
+ value (2)? */
+ if(ca) return check_ca(x);
+ /* leaf certificate is checked in OCSP_verify() */
+ return 1;
+}
+
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
+ int ca)
+{
+ int i_ext;
+
+ /* If ca is true we must return if this is a valid CA certificate. */
+ if (ca) return check_ca(x);
+
+ /*
+ * Check the optional key usage field:
+ * if Key Usage is present, it must be one of digitalSignature
+ * and/or nonRepudiation (other values are not consistent and shall
+ * be rejected).
+ */
+ if ((x->ex_flags & EXFLAG_KUSAGE)
+ && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) ||
+ !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE))))
+ return 0;
+
+ /* Only time stamp key usage is permitted and it's required. */
+ if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP)
+ return 0;
+
+ /* Extended Key Usage MUST be critical */
+ i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, -1);
+ if (i_ext >= 0)
+ {
+ X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext);
+ if (!X509_EXTENSION_get_critical(ext))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ return 1;
+}
+
+/* Various checks to see if one certificate issued the second.
+ * This can be used to prune a set of possible issuer certificates
+ * which have been looked up using some simple method such as by
+ * subject name.
+ * These are:
+ * 1. Check issuer_name(subject) == subject_name(issuer)
+ * 2. If akid(subject) exists check it matches issuer
+ * 3. If key_usage(issuer) exists check it supports certificate signing
+ * returns 0 for OK, positive for reason for mismatch, reasons match
+ * codes for X509_verify_cert()
+ */
+
+int X509_check_issued(X509 *issuer, X509 *subject)
+{
+ if(X509_NAME_cmp(X509_get_subject_name(issuer),
+ X509_get_issuer_name(subject)))
+ return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
+ x509v3_cache_extensions(issuer);
+ x509v3_cache_extensions(subject);
+
+ if(subject->akid)
+ {
+ int ret = X509_check_akid(issuer, subject->akid);
+ if (ret != X509_V_OK)
+ return ret;
+ }
+
+ if(subject->ex_flags & EXFLAG_PROXY)
+ {
+ if(ku_reject(issuer, KU_DIGITAL_SIGNATURE))
+ return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
+ }
+ else if(ku_reject(issuer, KU_KEY_CERT_SIGN))
+ return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
+ return X509_V_OK;
+}
+
+int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
+ {
+
+ if(!akid)
+ return X509_V_OK;
+
+ /* Check key ids (if present) */
+ if(akid->keyid && issuer->skid &&
+ ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) )
+ return X509_V_ERR_AKID_SKID_MISMATCH;
+ /* Check serial number */
+ if(akid->serial &&
+ ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial))
+ return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+ /* Check issuer name */
+ if(akid->issuer)
+ {
+ /* Ugh, for some peculiar reason AKID includes
+ * SEQUENCE OF GeneralName. So look for a DirName.
+ * There may be more than one but we only take any
+ * notice of the first.
+ */
+ GENERAL_NAMES *gens;
+ GENERAL_NAME *gen;
+ X509_NAME *nm = NULL;
+ int i;
+ gens = akid->issuer;
+ for(i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+ {
+ gen = sk_GENERAL_NAME_value(gens, i);
+ if(gen->type == GEN_DIRNAME)
+ {
+ nm = gen->d.dirn;
+ break;
+ }
+ }
+ if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
+ return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+ }
+ return X509_V_OK;
+ }
+
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_skey.c b/drivers/builtin_openssl2/crypto/x509v3/v3_skey.c
index 0a984fbaa8..0a984fbaa8 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_skey.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_skey.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_sxnet.c b/drivers/builtin_openssl2/crypto/x509v3/v3_sxnet.c
index 2a6bf11b65..2a6bf11b65 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_sxnet.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_sxnet.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3_utl.c b/drivers/builtin_openssl2/crypto/x509v3/v3_utl.c
index e030234540..e030234540 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3_utl.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3_utl.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3conf.c b/drivers/builtin_openssl2/crypto/x509v3/v3conf.c
index a9e6ca3542..a9e6ca3542 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3conf.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3conf.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3err.c b/drivers/builtin_openssl2/crypto/x509v3/v3err.c
index f9f6f1f91f..f9f6f1f91f 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3err.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3err.c
diff --git a/drivers/builtin_openssl/crypto/x509v3/v3prin.c b/drivers/builtin_openssl2/crypto/x509v3/v3prin.c
index d5ff268296..d5ff268296 100644
--- a/drivers/builtin_openssl/crypto/x509v3/v3prin.c
+++ b/drivers/builtin_openssl2/crypto/x509v3/v3prin.c
diff --git a/drivers/builtin_openssl/crypto/x86_64cpuid.pl b/drivers/builtin_openssl2/crypto/x86_64cpuid.pl
index 6ebfd017ea..6ebfd017ea 100644
--- a/drivers/builtin_openssl/crypto/x86_64cpuid.pl
+++ b/drivers/builtin_openssl2/crypto/x86_64cpuid.pl
diff --git a/drivers/builtin_openssl/crypto/x86cpuid.pl b/drivers/builtin_openssl2/crypto/x86cpuid.pl
index b270b44337..b270b44337 100644
--- a/drivers/builtin_openssl/crypto/x86cpuid.pl
+++ b/drivers/builtin_openssl2/crypto/x86cpuid.pl
diff --git a/drivers/builtin_openssl2/e_os.h b/drivers/builtin_openssl2/e_os.h
new file mode 100644
index 0000000000..7323a7b4bf
--- /dev/null
+++ b/drivers/builtin_openssl2/e_os.h
@@ -0,0 +1,753 @@
+/* e_os.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_E_OS_H
+#define HEADER_E_OS_H
+
+#include <openssl/opensslconf.h>
+
+#include <openssl/e_os2.h>
+/* <openssl/e_os2.h> contains what we can justify to make visible
+ * to the outside; this file e_os.h is not part of the exported
+ * interface. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Used to checking reference counts, most while doing perl5 stuff :-) */
+#ifdef REF_PRINT
+#undef REF_PRINT
+#define REF_PRINT(a,b) fprintf(stderr,"%08X:%4d:%s\n",(int)b,b->references,a)
+#endif
+
+#ifndef DEVRANDOM
+/* set this to a comma-separated list of 'random' device files to try out.
+ * My default, we will try to read at least one of these files */
+#define DEVRANDOM "/dev/urandom","/dev/random","/dev/srandom"
+#endif
+#ifndef DEVRANDOM_EGD
+/* set this to a comma-seperated list of 'egd' sockets to try out. These
+ * sockets will be tried in the order listed in case accessing the device files
+ * listed in DEVRANDOM did not return enough entropy. */
+#define DEVRANDOM_EGD "/var/run/egd-pool","/dev/egd-pool","/etc/egd-pool","/etc/entropy"
+#endif
+
+#if defined(OPENSSL_SYS_VXWORKS)
+# define NO_SYS_PARAM_H
+# define NO_CHMOD
+# define NO_SYSLOG
+#endif
+
+#if defined(OPENSSL_SYS_MACINTOSH_CLASSIC)
+# if macintosh==1
+# ifndef MAC_OS_GUSI_SOURCE
+# define MAC_OS_pre_X
+# define NO_SYS_TYPES_H
+# endif
+# define NO_SYS_PARAM_H
+# define NO_CHMOD
+# define NO_SYSLOG
+# undef DEVRANDOM
+# define GETPID_IS_MEANINGLESS
+# endif
+#endif
+
+/********************************************************************
+ The Microsoft section
+ ********************************************************************/
+/* The following is used because of the small stack in some
+ * Microsoft operating systems */
+#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYSNAME_WIN32)
+# define MS_STATIC static
+#else
+# define MS_STATIC
+#endif
+
+#if defined(OPENSSL_SYS_WIN32) && !defined(WIN32)
+# define WIN32
+#endif
+#if defined(OPENSSL_SYS_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(OPENSSL_SYS_MSDOS) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+#if defined(MSDOS) && !defined(GETPID_IS_MEANINGLESS)
+# define GETPID_IS_MEANINGLESS
+#endif
+
+#ifdef WIN32
+#define get_last_sys_error() GetLastError()
+#define clear_sys_error() SetLastError(0)
+#if !defined(WINNT)
+#define WIN_CONSOLE_BUG
+#endif
+#else
+#define get_last_sys_error() errno
+#define clear_sys_error() errno=0
+#endif
+
+#if defined(WINDOWS)
+#define get_last_socket_error() WSAGetLastError()
+#define clear_socket_error() WSASetLastError(0)
+#define readsocket(s,b,n) recv((s),(b),(n),0)
+#define writesocket(s,b,n) send((s),(b),(n),0)
+#elif defined(__DJGPP__)
+#define WATT32
+#define get_last_socket_error() errno
+#define clear_socket_error() errno=0
+#define closesocket(s) close_s(s)
+#define readsocket(s,b,n) read_s(s,b,n)
+#define writesocket(s,b,n) send(s,b,n,0)
+#elif defined(MAC_OS_pre_X)
+#define get_last_socket_error() errno
+#define clear_socket_error() errno=0
+#define closesocket(s) MacSocket_close(s)
+#define readsocket(s,b,n) MacSocket_recv((s),(b),(n),true)
+#define writesocket(s,b,n) MacSocket_send((s),(b),(n))
+#elif defined(OPENSSL_SYS_VMS)
+#define get_last_socket_error() errno
+#define clear_socket_error() errno=0
+#define ioctlsocket(a,b,c) ioctl(a,b,c)
+#define closesocket(s) close(s)
+#define readsocket(s,b,n) recv((s),(b),(n),0)
+#define writesocket(s,b,n) send((s),(b),(n),0)
+#elif defined(OPENSSL_SYS_VXWORKS)
+#define get_last_socket_error() errno
+#define clear_socket_error() errno=0
+#define ioctlsocket(a,b,c) ioctl((a),(b),(int)(c))
+#define closesocket(s) close(s)
+#define readsocket(s,b,n) read((s),(b),(n))
+#define writesocket(s,b,n) write((s),(char *)(b),(n))
+#elif defined(OPENSSL_SYS_BEOS_R5)
+#define get_last_socket_error() errno
+#define clear_socket_error() errno=0
+#define FIONBIO SO_NONBLOCK
+#define ioctlsocket(a,b,c) setsockopt((a),SOL_SOCKET,(b),(c),sizeof(*(c)))
+#define readsocket(s,b,n) recv((s),(b),(n),0)
+#define writesocket(s,b,n) send((s),(b),(n),0)
+#elif defined(OPENSSL_SYS_NETWARE)
+#if defined(NETWARE_BSDSOCK)
+#define get_last_socket_error() errno
+#define clear_socket_error() errno=0
+#define closesocket(s) close(s)
+#define ioctlsocket(a,b,c) ioctl(a,b,c)
+#if defined(NETWARE_LIBC)
+#define readsocket(s,b,n) recv((s),(b),(n),0)
+#define writesocket(s,b,n) send((s),(b),(n),0)
+#else
+#define readsocket(s,b,n) recv((s),(char*)(b),(n),0)
+#define writesocket(s,b,n) send((s),(char*)(b),(n),0)
+#endif
+#else
+#define get_last_socket_error() WSAGetLastError()
+#define clear_socket_error() WSASetLastError(0)
+#define readsocket(s,b,n) recv((s),(b),(n),0)
+#define writesocket(s,b,n) send((s),(b),(n),0)
+#endif
+#else
+#define get_last_socket_error() errno
+#define clear_socket_error() errno=0
+#define ioctlsocket(a,b,c) ioctl(a,b,c)
+#define closesocket(s) close(s)
+#define readsocket(s,b,n) read((s),(b),(n))
+#define writesocket(s,b,n) write((s),(b),(n))
+#endif
+
+#ifdef WIN16 /* never the case */
+# define MS_CALLBACK _far _loadds
+# define MS_FAR _far
+#else
+# define MS_CALLBACK
+# define MS_FAR
+#endif
+
+#ifdef OPENSSL_NO_STDIO
+# undef OPENSSL_NO_FP_API
+# define OPENSSL_NO_FP_API
+#endif
+
+#if (defined(WINDOWS) || defined(MSDOS))
+
+# ifdef __DJGPP__
+# include <unistd.h>
+# include <sys/stat.h>
+# include <sys/socket.h>
+# include <tcp.h>
+# include <netdb.h>
+# define _setmode setmode
+# define _O_TEXT O_TEXT
+# define _O_BINARY O_BINARY
+# undef DEVRANDOM
+# define DEVRANDOM "/dev/urandom\x24"
+# endif /* __DJGPP__ */
+
+# ifndef S_IFDIR
+# define S_IFDIR _S_IFDIR
+# endif
+
+# ifndef S_IFMT
+# define S_IFMT _S_IFMT
+# endif
+
+# if !defined(WINNT) && !defined(__DJGPP__)
+# define NO_SYSLOG
+# endif
+# define NO_DIRENT
+
+# ifdef WINDOWS
+# if !defined(_WIN32_WCE) && !defined(_WIN32_WINNT)
+ /*
+ * Defining _WIN32_WINNT here in e_os.h implies certain "discipline."
+ * Most notably we ought to check for availability of each specific
+ * routine with GetProcAddress() and/or guard NT-specific calls with
+ * GetVersion() < 0x80000000. One can argue that in latter "or" case
+ * we ought to /DELAYLOAD some .DLLs in order to protect ourselves
+ * against run-time link errors. This doesn't seem to be necessary,
+ * because it turned out that already Windows 95, first non-NT Win32
+ * implementation, is equipped with at least NT 3.51 stubs, dummy
+ * routines with same name, but which do nothing. Meaning that it's
+ * apparently sufficient to guard "vanilla" NT calls with GetVersion
+ * alone, while NT 4.0 and above interfaces ought to be linked with
+ * GetProcAddress at run-time.
+ */
+# define _WIN32_WINNT 0x0400
+# endif
+# if !defined(OPENSSL_NO_SOCK) && defined(_WIN32_WINNT)
+ /*
+ * Just like defining _WIN32_WINNT including winsock2.h implies
+ * certain "discipline" for maintaining [broad] binary compatibility.
+ * As long as structures are invariant among Winsock versions,
+ * it's sufficient to check for specific Winsock2 API availability
+ * at run-time [DSO_global_lookup is recommended]...
+ */
+# include <winsock2.h>
+# include <ws2tcpip.h>
+ /* yes, they have to be #included prior to <windows.h> */
+# endif
+# include <windows.h>
+# include <stdio.h>
+# include <stddef.h>
+# include <errno.h>
+# include <string.h>
+
+
+#ifdef X509_NAME
+#undef X509_NAME
+#undef X509_NAME
+#undef X509_EXTENSIONS
+#undef X509_CERT_PAIR
+#undef PKCS7_ISSUER_AND_SERIAL
+#undef OCSP_REQUEST
+#undef OCSP_RESPONSE
+#endif
+
+# ifdef _WIN64
+# define strlen(s) _strlen31(s)
+/* cut strings to 2GB */
+static unsigned int _strlen31(const char *str)
+ {
+ unsigned int len=0;
+ while (*str && len<0x80000000U) str++, len++;
+ return len&0x7FFFFFFF;
+ }
+# endif
+# include <malloc.h>
+# if defined(_MSC_VER) && _MSC_VER<=1200 && defined(_MT) && defined(isspace)
+ /* compensate for bug in VC6 ctype.h */
+# undef isspace
+# undef isdigit
+# undef isalnum
+# undef isupper
+# undef isxdigit
+# endif
+# if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(_DLL) && defined(stdin)
+# if _MSC_VER>=1300 && _MSC_VER<1600
+# undef stdin
+# undef stdout
+# undef stderr
+ FILE *__iob_func();
+# define stdin (&__iob_func()[0])
+# define stdout (&__iob_func()[1])
+# define stderr (&__iob_func()[2])
+# elif _MSC_VER<1300 && defined(I_CAN_LIVE_WITH_LNK4049)
+# undef stdin
+# undef stdout
+# undef stderr
+ /* pre-1300 has __p__iob(), but it's available only in msvcrt.lib,
+ * or in other words with /MD. Declaring implicit import, i.e.
+ * with _imp_ prefix, works correctly with all compiler options,
+ * but without /MD results in LINK warning LNK4049:
+ * 'locally defined symbol "__iob" imported'.
+ */
+ extern FILE *_imp___iob;
+# define stdin (&_imp___iob[0])
+# define stdout (&_imp___iob[1])
+# define stderr (&_imp___iob[2])
+# endif
+# endif
+# endif
+# include <io.h>
+# include <fcntl.h>
+
+# ifdef OPENSSL_SYS_WINCE
+# define OPENSSL_NO_POSIX_IO
+# endif
+
+# if defined (__BORLANDC__)
+# define _setmode setmode
+# define _O_TEXT O_TEXT
+# define _O_BINARY O_BINARY
+# define _int64 __int64
+# define _kbhit kbhit
+# endif
+
+# define EXIT(n) exit(n)
+# define LIST_SEPARATOR_CHAR ';'
+# ifndef X_OK
+# define X_OK 0
+# endif
+# ifndef W_OK
+# define W_OK 2
+# endif
+# ifndef R_OK
+# define R_OK 4
+# endif
+# define OPENSSL_CONF "openssl.cnf"
+# define SSLEAY_CONF OPENSSL_CONF
+# define NUL_DEV "nul"
+# define RFILE ".rnd"
+# ifdef OPENSSL_SYS_WINCE
+# define DEFAULT_HOME ""
+# else
+# define DEFAULT_HOME "C:"
+# endif
+
+/* Avoid Windows 8 SDK GetVersion deprecated problems */
+#if defined(_MSC_VER) && _MSC_VER>=1800
+# define check_winnt() (1)
+#else
+# define check_winnt() (GetVersion() < 0x80000000)
+#endif
+
+#else /* The non-microsoft world */
+
+# ifdef OPENSSL_SYS_VMS
+# define VMS 1
+ /* some programs don't include stdlib, so exit() and others give implicit
+ function warnings */
+# include <stdlib.h>
+# if defined(__DECC)
+# include <unistd.h>
+# else
+# include <unixlib.h>
+# endif
+# define OPENSSL_CONF "openssl.cnf"
+# define SSLEAY_CONF OPENSSL_CONF
+# define RFILE ".rnd"
+# define LIST_SEPARATOR_CHAR ','
+# define NUL_DEV "NLA0:"
+ /* We don't have any well-defined random devices on VMS, yet... */
+# undef DEVRANDOM
+ /* We need to do this since VMS has the following coding on status codes:
+
+ Bits 0-2: status type: 0 = warning, 1 = success, 2 = error, 3 = info ...
+ The important thing to know is that odd numbers are considered
+ good, while even ones are considered errors.
+ Bits 3-15: actual status number
+ Bits 16-27: facility number. 0 is considered "unknown"
+ Bits 28-31: control bits. If bit 28 is set, the shell won't try to
+ output the message (which, for random codes, just looks ugly)
+
+ So, what we do here is to change 0 to 1 to get the default success status,
+ and everything else is shifted up to fit into the status number field, and
+ the status is tagged as an error, which I believe is what is wanted here.
+ -- Richard Levitte
+ */
+# define EXIT(n) do { int __VMS_EXIT = n; \
+ if (__VMS_EXIT == 0) \
+ __VMS_EXIT = 1; \
+ else \
+ __VMS_EXIT = (n << 3) | 2; \
+ __VMS_EXIT |= 0x10000000; \
+ exit(__VMS_EXIT); } while(0)
+# define NO_SYS_PARAM_H
+
+# elif defined(OPENSSL_SYS_NETWARE)
+# include <fcntl.h>
+# include <unistd.h>
+# define NO_SYS_TYPES_H
+# undef DEVRANDOM
+# ifdef NETWARE_CLIB
+# define getpid GetThreadID
+ extern int GetThreadID(void);
+/* # include <conio.h> */
+ extern int kbhit(void);
+# else
+# include <screen.h>
+# endif
+# define NO_SYSLOG
+# define _setmode setmode
+# define _kbhit kbhit
+# define _O_TEXT O_TEXT
+# define _O_BINARY O_BINARY
+# define OPENSSL_CONF "openssl.cnf"
+# define SSLEAY_CONF OPENSSL_CONF
+# define RFILE ".rnd"
+# define LIST_SEPARATOR_CHAR ';'
+# define EXIT(n) { if (n) printf("ERROR: %d\n", (int)n); exit(n); }
+
+# else
+ /* !defined VMS */
+# ifdef OPENSSL_SYS_MPE
+# define NO_SYS_PARAM_H
+# endif
+# ifdef OPENSSL_UNISTD
+# include OPENSSL_UNISTD
+# else
+# include <unistd.h>
+# endif
+# ifndef NO_SYS_TYPES_H
+# include <sys/types.h>
+# endif
+# if defined(NeXT) || defined(OPENSSL_SYS_NEWS4)
+# define pid_t int /* pid_t is missing on NEXTSTEP/OPENSTEP
+ * (unless when compiling with -D_POSIX_SOURCE,
+ * which doesn't work for us) */
+# endif
+# ifdef OPENSSL_SYS_NEWS4 /* setvbuf is missing on mips-sony-bsd */
+# define setvbuf(a, b, c, d) setbuffer((a), (b), (d))
+ typedef unsigned long clock_t;
+# endif
+# ifdef OPENSSL_SYS_WIN32_CYGWIN
+# include <io.h>
+# include <fcntl.h>
+# endif
+
+# define OPENSSL_CONF "openssl.cnf"
+# define SSLEAY_CONF OPENSSL_CONF
+# define RFILE ".rnd"
+# define LIST_SEPARATOR_CHAR ':'
+# define NUL_DEV "/dev/null"
+# define EXIT(n) exit(n)
+# endif
+
+# define SSLeay_getpid() getpid()
+
+#endif
+
+
+/*************/
+
+#ifdef USE_SOCKETS
+# if defined(WINDOWS) || defined(MSDOS)
+ /* windows world */
+
+# ifdef OPENSSL_NO_SOCK
+# define SSLeay_Write(a,b,c) (-1)
+# define SSLeay_Read(a,b,c) (-1)
+# define SHUTDOWN(fd) close(fd)
+# define SHUTDOWN2(fd) close(fd)
+# elif !defined(__DJGPP__)
+# if defined(_WIN32_WCE) && _WIN32_WCE<410
+# define getservbyname _masked_declaration_getservbyname
+# endif
+# if !defined(IPPROTO_IP)
+ /* winsock[2].h was included already? */
+# include <winsock.h>
+# endif
+# ifdef getservbyname
+# undef getservbyname
+ /* this is used to be wcecompat/include/winsock_extras.h */
+ struct servent* PASCAL getservbyname(const char*,const char*);
+# endif
+
+# ifdef _WIN64
+/*
+ * Even though sizeof(SOCKET) is 8, it's safe to cast it to int, because
+ * the value constitutes an index in per-process table of limited size
+ * and not a real pointer.
+ */
+# define socket(d,t,p) ((int)socket(d,t,p))
+# define accept(s,f,l) ((int)accept(s,f,l))
+# endif
+# define SSLeay_Write(a,b,c) send((a),(b),(c),0)
+# define SSLeay_Read(a,b,c) recv((a),(b),(c),0)
+# define SHUTDOWN(fd) { shutdown((fd),0); closesocket(fd); }
+# define SHUTDOWN2(fd) { shutdown((fd),2); closesocket(fd); }
+# else
+# define SSLeay_Write(a,b,c) write_s(a,b,c,0)
+# define SSLeay_Read(a,b,c) read_s(a,b,c)
+# define SHUTDOWN(fd) close_s(fd)
+# define SHUTDOWN2(fd) close_s(fd)
+# endif
+
+# elif defined(MAC_OS_pre_X)
+
+# include "MacSocket.h"
+# define SSLeay_Write(a,b,c) MacSocket_send((a),(b),(c))
+# define SSLeay_Read(a,b,c) MacSocket_recv((a),(b),(c),true)
+# define SHUTDOWN(fd) MacSocket_close(fd)
+# define SHUTDOWN2(fd) MacSocket_close(fd)
+
+# elif defined(OPENSSL_SYS_NETWARE)
+ /* NetWare uses the WinSock2 interfaces by default, but can be configured for BSD
+ */
+# if defined(NETWARE_BSDSOCK)
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <sys/time.h>
+# if defined(NETWARE_CLIB)
+# include <sys/bsdskt.h>
+# else
+# include <sys/select.h>
+# endif
+# define INVALID_SOCKET (int)(~0)
+# else
+# include <novsock2.h>
+# endif
+# define SSLeay_Write(a,b,c) send((a),(b),(c),0)
+# define SSLeay_Read(a,b,c) recv((a),(b),(c),0)
+# define SHUTDOWN(fd) { shutdown((fd),0); closesocket(fd); }
+# define SHUTDOWN2(fd) { shutdown((fd),2); closesocket(fd); }
+
+# else
+
+# ifndef NO_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef OPENSSL_SYS_VXWORKS
+# include <time.h>
+# elif !defined(OPENSSL_SYS_MPE)
+# include <sys/time.h> /* Needed under linux for FD_XXX */
+# endif
+
+# include <netdb.h>
+# if defined(OPENSSL_SYS_VMS_NODECC)
+# include <socket.h>
+# include <in.h>
+# include <inet.h>
+# else
+# include <sys/socket.h>
+# ifdef FILIO_H
+# include <sys/filio.h> /* Added for FIONBIO under unixware */
+# endif
+# include <netinet/in.h>
+# if !defined(OPENSSL_SYS_BEOS_R5)
+# include <arpa/inet.h>
+# endif
+# endif
+
+# if defined(NeXT) || defined(_NEXT_SOURCE)
+# include <sys/fcntl.h>
+# include <sys/types.h>
+# endif
+
+# ifdef OPENSSL_SYS_AIX
+# include <sys/select.h>
+# endif
+
+# ifdef __QNX__
+# include <sys/select.h>
+# endif
+
+# if defined(sun)
+# include <sys/filio.h>
+# else
+# ifndef VMS
+# include <sys/ioctl.h>
+# else
+ /* ioctl is only in VMS > 7.0 and when socketshr is not used */
+# if !defined(TCPIP_TYPE_SOCKETSHR) && defined(__VMS_VER) && (__VMS_VER > 70000000)
+# include <sys/ioctl.h>
+# endif
+# endif
+# endif
+
+# ifdef VMS
+# include <unixio.h>
+# if defined(TCPIP_TYPE_SOCKETSHR)
+# include <socketshr.h>
+# endif
+# endif
+
+# define SSLeay_Read(a,b,c) read((a),(b),(c))
+# define SSLeay_Write(a,b,c) write((a),(b),(c))
+# define SHUTDOWN(fd) { shutdown((fd),0); closesocket((fd)); }
+# define SHUTDOWN2(fd) { shutdown((fd),2); closesocket((fd)); }
+# ifndef INVALID_SOCKET
+# define INVALID_SOCKET (-1)
+# endif /* INVALID_SOCKET */
+# endif
+
+/* Some IPv6 implementations are broken, disable them in known bad
+ * versions.
+ */
+# if !defined(OPENSSL_USE_IPV6)
+# if defined(AF_INET6) && !defined(OPENSSL_SYS_BEOS_BONE) && !defined(NETWARE_CLIB)
+# define OPENSSL_USE_IPV6 1
+# else
+# define OPENSSL_USE_IPV6 0
+# endif
+# endif
+
+#endif
+
+#if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
+ /* include headers first, so our defines don't break it */
+#include <stdlib.h>
+#include <string.h>
+ /* bcopy can handle overlapping moves according to SunOS 4.1.4 manpage */
+# define memmove(s1,s2,n) bcopy((s2),(s1),(n))
+# define strtoul(s,e,b) ((unsigned long int)strtol((s),(e),(b)))
+extern char *sys_errlist[]; extern int sys_nerr;
+# define strerror(errnum) \
+ (((errnum)<0 || (errnum)>=sys_nerr) ? NULL : sys_errlist[errnum])
+ /* Being signed SunOS 4.x memcpy breaks ASN1_OBJECT table lookup */
+#include "crypto/o_str.h"
+# define memcmp OPENSSL_memcmp
+#endif
+
+#ifndef OPENSSL_EXIT
+# if defined(MONOLITH) && !defined(OPENSSL_C)
+# define OPENSSL_EXIT(n) return(n)
+# else
+# define OPENSSL_EXIT(n) do { EXIT(n); return(n); } while(0)
+# endif
+#endif
+
+/***********************************************/
+
+#define DG_GCC_BUG /* gcc < 2.6.3 on DGUX */
+
+#ifdef sgi
+#define IRIX_CC_BUG /* all version of IRIX I've tested (4.* 5.*) */
+#endif
+#ifdef OPENSSL_SYS_SNI
+#define IRIX_CC_BUG /* CDS++ up to V2.0Bsomething suffered from the same bug.*/
+#endif
+
+#if defined(OPENSSL_SYS_WINDOWS)
+# define strcasecmp _stricmp
+# define strncasecmp _strnicmp
+#elif defined(OPENSSL_SYS_VMS)
+/* VMS below version 7.0 doesn't have strcasecmp() */
+# include "o_str.h"
+# define strcasecmp OPENSSL_strcasecmp
+# define strncasecmp OPENSSL_strncasecmp
+# define OPENSSL_IMPLEMENTS_strncasecmp
+#elif defined(OPENSSL_SYS_OS2) && defined(__EMX__)
+# define strcasecmp stricmp
+# define strncasecmp strnicmp
+#elif defined(OPENSSL_SYS_NETWARE)
+# include <string.h>
+# if defined(NETWARE_CLIB)
+# define strcasecmp stricmp
+# define strncasecmp strnicmp
+# endif /* NETWARE_CLIB */
+#endif
+
+#if defined(OPENSSL_SYS_OS2) && defined(__EMX__)
+# include <io.h>
+# include <fcntl.h>
+# define NO_SYSLOG
+#endif
+
+/* vxworks */
+#if defined(OPENSSL_SYS_VXWORKS)
+#include <ioLib.h>
+#include <tickLib.h>
+#include <sysLib.h>
+
+#define TTY_STRUCT int
+
+#define sleep(a) taskDelay((a) * sysClkRateGet())
+
+#include <vxWorks.h>
+#include <sockLib.h>
+#include <taskLib.h>
+
+#define getpid taskIdSelf
+
+/* NOTE: these are implemented by helpers in database app!
+ * if the database is not linked, we need to implement them
+ * elswhere */
+struct hostent *gethostbyname(const char *name);
+struct hostent *gethostbyaddr(const char *addr, int length, int type);
+struct servent *getservbyname(const char *name, const char *proto);
+
+#endif
+/* end vxworks */
+
+/* beos */
+#if defined(OPENSSL_SYS_BEOS_R5)
+#define SO_ERROR 0
+#define NO_SYS_UN
+#define IPPROTO_IP 0
+#include <OS.h>
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/drivers/builtin_openssl/nocpuid.c b/drivers/builtin_openssl2/nocpuid.c
index 88246067bd..88246067bd 100644
--- a/drivers/builtin_openssl/nocpuid.c
+++ b/drivers/builtin_openssl2/nocpuid.c
diff --git a/drivers/builtin_openssl/crypto/aes/aes.h b/drivers/builtin_openssl2/openssl/aes.h
index 031abf01b5..031abf01b5 100644
--- a/drivers/builtin_openssl/crypto/aes/aes.h
+++ b/drivers/builtin_openssl2/openssl/aes.h
diff --git a/drivers/builtin_openssl/crypto/asn1/asn1.h b/drivers/builtin_openssl2/openssl/asn1.h
index 220a0c8c63..220a0c8c63 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn1.h
+++ b/drivers/builtin_openssl2/openssl/asn1.h
diff --git a/drivers/builtin_openssl/crypto/asn1/asn1_mac.h b/drivers/builtin_openssl2/openssl/asn1_mac.h
index 87bd0e9e1d..87bd0e9e1d 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn1_mac.h
+++ b/drivers/builtin_openssl2/openssl/asn1_mac.h
diff --git a/drivers/builtin_openssl/crypto/asn1/asn1t.h b/drivers/builtin_openssl2/openssl/asn1t.h
index d230e4bf70..d230e4bf70 100644
--- a/drivers/builtin_openssl/crypto/asn1/asn1t.h
+++ b/drivers/builtin_openssl2/openssl/asn1t.h
diff --git a/drivers/builtin_openssl/crypto/bio/bio.h b/drivers/builtin_openssl2/openssl/bio.h
index 05699ab212..05699ab212 100644
--- a/drivers/builtin_openssl/crypto/bio/bio.h
+++ b/drivers/builtin_openssl2/openssl/bio.h
diff --git a/drivers/builtin_openssl/crypto/bf/blowfish.h b/drivers/builtin_openssl2/openssl/blowfish.h
index 4b6c8920a4..4b6c8920a4 100644
--- a/drivers/builtin_openssl/crypto/bf/blowfish.h
+++ b/drivers/builtin_openssl2/openssl/blowfish.h
diff --git a/drivers/builtin_openssl/crypto/bn/bn.h b/drivers/builtin_openssl2/openssl/bn.h
index 21a1a3fe35..21a1a3fe35 100644
--- a/drivers/builtin_openssl/crypto/bn/bn.h
+++ b/drivers/builtin_openssl2/openssl/bn.h
diff --git a/drivers/builtin_openssl/crypto/buffer/buffer.h b/drivers/builtin_openssl2/openssl/buffer.h
index f8da32b485..f8da32b485 100644
--- a/drivers/builtin_openssl/crypto/buffer/buffer.h
+++ b/drivers/builtin_openssl2/openssl/buffer.h
diff --git a/drivers/builtin_openssl/crypto/camellia/camellia.h b/drivers/builtin_openssl2/openssl/camellia.h
index 67911e0adf..67911e0adf 100644
--- a/drivers/builtin_openssl/crypto/camellia/camellia.h
+++ b/drivers/builtin_openssl2/openssl/camellia.h
diff --git a/drivers/builtin_openssl/crypto/cast/cast.h b/drivers/builtin_openssl2/openssl/cast.h
index 203922ea2b..203922ea2b 100644
--- a/drivers/builtin_openssl/crypto/cast/cast.h
+++ b/drivers/builtin_openssl2/openssl/cast.h
diff --git a/drivers/builtin_openssl/crypto/cmac/cmac.h b/drivers/builtin_openssl2/openssl/cmac.h
index 712e92dced..712e92dced 100644
--- a/drivers/builtin_openssl/crypto/cmac/cmac.h
+++ b/drivers/builtin_openssl2/openssl/cmac.h
diff --git a/drivers/builtin_openssl/crypto/cms/cms.h b/drivers/builtin_openssl2/openssl/cms.h
index 36994fa6a2..36994fa6a2 100644
--- a/drivers/builtin_openssl/crypto/cms/cms.h
+++ b/drivers/builtin_openssl2/openssl/cms.h
diff --git a/drivers/builtin_openssl/crypto/comp/comp.h b/drivers/builtin_openssl2/openssl/comp.h
index 4b405c7d49..4b405c7d49 100644
--- a/drivers/builtin_openssl/crypto/comp/comp.h
+++ b/drivers/builtin_openssl2/openssl/comp.h
diff --git a/drivers/builtin_openssl/crypto/conf/conf.h b/drivers/builtin_openssl2/openssl/conf.h
index c2199978a3..c2199978a3 100644
--- a/drivers/builtin_openssl/crypto/conf/conf.h
+++ b/drivers/builtin_openssl2/openssl/conf.h
diff --git a/drivers/builtin_openssl/crypto/conf/conf_api.h b/drivers/builtin_openssl2/openssl/conf_api.h
index 87a954aff6..87a954aff6 100644
--- a/drivers/builtin_openssl/crypto/conf/conf_api.h
+++ b/drivers/builtin_openssl2/openssl/conf_api.h
diff --git a/drivers/builtin_openssl/crypto/crypto.h b/drivers/builtin_openssl2/openssl/crypto.h
index f92fc5182d..f92fc5182d 100644
--- a/drivers/builtin_openssl/crypto/crypto.h
+++ b/drivers/builtin_openssl2/openssl/crypto.h
diff --git a/drivers/builtin_openssl/crypto/des/des.h b/drivers/builtin_openssl2/openssl/des.h
index 1eaedcbd24..1eaedcbd24 100644
--- a/drivers/builtin_openssl/crypto/des/des.h
+++ b/drivers/builtin_openssl2/openssl/des.h
diff --git a/drivers/builtin_openssl/crypto/des/des_old.h b/drivers/builtin_openssl2/openssl/des_old.h
index 2b2c372354..2b2c372354 100644
--- a/drivers/builtin_openssl/crypto/des/des_old.h
+++ b/drivers/builtin_openssl2/openssl/des_old.h
diff --git a/drivers/builtin_openssl/crypto/dh/dh.h b/drivers/builtin_openssl2/openssl/dh.h
index ea59e610ef..ea59e610ef 100644
--- a/drivers/builtin_openssl/crypto/dh/dh.h
+++ b/drivers/builtin_openssl2/openssl/dh.h
diff --git a/drivers/builtin_openssl/crypto/dsa/dsa.h b/drivers/builtin_openssl2/openssl/dsa.h
index a6f6d0b0b2..a6f6d0b0b2 100644
--- a/drivers/builtin_openssl/crypto/dsa/dsa.h
+++ b/drivers/builtin_openssl2/openssl/dsa.h
diff --git a/drivers/builtin_openssl/crypto/dso/dso.h b/drivers/builtin_openssl2/openssl/dso.h
index 839f2e0617..839f2e0617 100644
--- a/drivers/builtin_openssl/crypto/dso/dso.h
+++ b/drivers/builtin_openssl2/openssl/dso.h
diff --git a/drivers/builtin_openssl2/openssl/dtls1.h b/drivers/builtin_openssl2/openssl/dtls1.h
new file mode 100644
index 0000000000..35c2e6ac20
--- /dev/null
+++ b/drivers/builtin_openssl2/openssl/dtls1.h
@@ -0,0 +1,290 @@
+/* ssl/dtls1.h */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_DTLS1_H
+#define HEADER_DTLS1_H
+
+#include <openssl/buffer.h>
+#include <openssl/pqueue.h>
+#ifdef OPENSSL_SYS_VMS
+#include <resource.h>
+#include <sys/timeb.h>
+#endif
+#ifdef OPENSSL_SYS_WIN32
+/* Needed for struct timeval */
+#include <winsock.h>
+#ifdef X509_NAME
+#undef X509_NAME
+#endif
+#elif defined(OPENSSL_SYS_NETWARE) && !defined(_WINSOCK2API_)
+#include <sys/timeval.h>
+#else
+#if defined(OPENSSL_SYS_VXWORKS)
+#include <sys/times.h>
+#else
+#include <sys/time.h>
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DTLS1_VERSION 0xFEFF
+#define DTLS1_BAD_VER 0x0100
+
+#if 0
+/* this alert description is not specified anywhere... */
+#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE 110
+#endif
+
+/* lengths of messages */
+#define DTLS1_COOKIE_LENGTH 256
+
+#define DTLS1_RT_HEADER_LENGTH 13
+
+#define DTLS1_HM_HEADER_LENGTH 12
+
+#define DTLS1_HM_BAD_FRAGMENT -2
+#define DTLS1_HM_FRAGMENT_RETRY -3
+
+#define DTLS1_CCS_HEADER_LENGTH 1
+
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+#define DTLS1_AL_HEADER_LENGTH 7
+#else
+#define DTLS1_AL_HEADER_LENGTH 2
+#endif
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+#ifndef OPENSSL_NO_SCTP
+#define DTLS1_SCTP_AUTH_LABEL "EXPORTER_DTLS_OVER_SCTP"
+#endif
+
+typedef struct dtls1_bitmap_st
+ {
+ unsigned long map; /* track 32 packets on 32-bit systems
+ and 64 - on 64-bit systems */
+ unsigned char max_seq_num[8]; /* max record number seen so far,
+ 64-bit value in big-endian
+ encoding */
+ } DTLS1_BITMAP;
+
+struct dtls1_retransmit_state
+ {
+ EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
+ EVP_MD_CTX *write_hash; /* used for mac generation */
+#ifndef OPENSSL_NO_COMP
+ COMP_CTX *compress; /* compression */
+#else
+ char *compress;
+#endif
+ SSL_SESSION *session;
+ unsigned short epoch;
+ };
+
+struct hm_header_st
+ {
+ unsigned char type;
+ unsigned long msg_len;
+ unsigned short seq;
+ unsigned long frag_off;
+ unsigned long frag_len;
+ unsigned int is_ccs;
+ struct dtls1_retransmit_state saved_retransmit_state;
+ };
+
+struct ccs_header_st
+ {
+ unsigned char type;
+ unsigned short seq;
+ };
+
+struct dtls1_timeout_st
+ {
+ /* Number of read timeouts so far */
+ unsigned int read_timeouts;
+
+ /* Number of write timeouts so far */
+ unsigned int write_timeouts;
+
+ /* Number of alerts received so far */
+ unsigned int num_alerts;
+ };
+
+typedef struct record_pqueue_st
+ {
+ unsigned short epoch;
+ pqueue q;
+ } record_pqueue;
+
+typedef struct hm_fragment_st
+ {
+ struct hm_header_st msg_header;
+ unsigned char *fragment;
+ unsigned char *reassembly;
+ } hm_fragment;
+
+typedef struct dtls1_state_st
+ {
+ unsigned int send_cookie;
+ unsigned char cookie[DTLS1_COOKIE_LENGTH];
+ unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH];
+ unsigned int cookie_len;
+
+ /*
+ * The current data and handshake epoch. This is initially
+ * undefined, and starts at zero once the initial handshake is
+ * completed
+ */
+ unsigned short r_epoch;
+ unsigned short w_epoch;
+
+ /* records being received in the current epoch */
+ DTLS1_BITMAP bitmap;
+
+ /* renegotiation starts a new set of sequence numbers */
+ DTLS1_BITMAP next_bitmap;
+
+ /* handshake message numbers */
+ unsigned short handshake_write_seq;
+ unsigned short next_handshake_write_seq;
+
+ unsigned short handshake_read_seq;
+
+ /* save last sequence number for retransmissions */
+ unsigned char last_write_sequence[8];
+
+ /* Received handshake records (processed and unprocessed) */
+ record_pqueue unprocessed_rcds;
+ record_pqueue processed_rcds;
+
+ /* Buffered handshake messages */
+ pqueue buffered_messages;
+
+ /* Buffered (sent) handshake records */
+ pqueue sent_messages;
+
+ /* Buffered application records.
+ * Only for records between CCS and Finished
+ * to prevent either protocol violation or
+ * unnecessary message loss.
+ */
+ record_pqueue buffered_app_data;
+
+ /* Is set when listening for new connections with dtls1_listen() */
+ unsigned int listen;
+
+ unsigned int mtu; /* max DTLS packet size */
+
+ struct hm_header_st w_msg_hdr;
+ struct hm_header_st r_msg_hdr;
+
+ struct dtls1_timeout_st timeout;
+
+ /* Indicates when the last handshake msg or heartbeat sent will timeout */
+ struct timeval next_timeout;
+
+ /* Timeout duration */
+ unsigned short timeout_duration;
+
+ /* storage for Alert/Handshake protocol data received but not
+ * yet processed by ssl3_read_bytes: */
+ unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
+ unsigned int alert_fragment_len;
+ unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH];
+ unsigned int handshake_fragment_len;
+
+ unsigned int retransmitting;
+ unsigned int change_cipher_spec_ok;
+
+#ifndef OPENSSL_NO_SCTP
+ /* used when SSL_ST_XX_FLUSH is entered */
+ int next_state;
+
+ int shutdown_received;
+#endif
+
+ } DTLS1_STATE;
+
+typedef struct dtls1_record_data_st
+ {
+ unsigned char *packet;
+ unsigned int packet_length;
+ SSL3_BUFFER rbuf;
+ SSL3_RECORD rrec;
+#ifndef OPENSSL_NO_SCTP
+ struct bio_dgram_sctp_rcvinfo recordinfo;
+#endif
+ } DTLS1_RECORD_DATA;
+
+#endif
+
+/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
+#define DTLS1_TMO_READ_COUNT 2
+#define DTLS1_TMO_WRITE_COUNT 2
+
+#define DTLS1_TMO_ALERT_COUNT 12
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/drivers/builtin_openssl/e_os2.h b/drivers/builtin_openssl2/openssl/e_os2.h
index d22c0368f8..d22c0368f8 100644
--- a/drivers/builtin_openssl/e_os2.h
+++ b/drivers/builtin_openssl2/openssl/e_os2.h
diff --git a/drivers/builtin_openssl/crypto/ebcdic.h b/drivers/builtin_openssl2/openssl/ebcdic.h
index 6d65afcf9e..6d65afcf9e 100644
--- a/drivers/builtin_openssl/crypto/ebcdic.h
+++ b/drivers/builtin_openssl2/openssl/ebcdic.h
diff --git a/drivers/builtin_openssl/crypto/ec/ec.h b/drivers/builtin_openssl2/openssl/ec.h
index dfe8710d33..dfe8710d33 100644
--- a/drivers/builtin_openssl/crypto/ec/ec.h
+++ b/drivers/builtin_openssl2/openssl/ec.h
diff --git a/drivers/builtin_openssl/crypto/ecdh/ecdh.h b/drivers/builtin_openssl2/openssl/ecdh.h
index 8887102c0b..8887102c0b 100644
--- a/drivers/builtin_openssl/crypto/ecdh/ecdh.h
+++ b/drivers/builtin_openssl2/openssl/ecdh.h
diff --git a/drivers/builtin_openssl/crypto/ecdsa/ecdsa.h b/drivers/builtin_openssl2/openssl/ecdsa.h
index 7fb5254b62..7fb5254b62 100644
--- a/drivers/builtin_openssl/crypto/ecdsa/ecdsa.h
+++ b/drivers/builtin_openssl2/openssl/ecdsa.h
diff --git a/drivers/builtin_openssl/crypto/engine/engine.h b/drivers/builtin_openssl2/openssl/engine.h
index f8be497724..f8be497724 100644
--- a/drivers/builtin_openssl/crypto/engine/engine.h
+++ b/drivers/builtin_openssl2/openssl/engine.h
diff --git a/drivers/builtin_openssl/crypto/err/err.h b/drivers/builtin_openssl2/openssl/err.h
index 974cc9cc6f..974cc9cc6f 100644
--- a/drivers/builtin_openssl/crypto/err/err.h
+++ b/drivers/builtin_openssl2/openssl/err.h
diff --git a/drivers/builtin_openssl/crypto/evp/evp.h b/drivers/builtin_openssl2/openssl/evp.h
index faeb3c24e6..faeb3c24e6 100644
--- a/drivers/builtin_openssl/crypto/evp/evp.h
+++ b/drivers/builtin_openssl2/openssl/evp.h
diff --git a/drivers/builtin_openssl/crypto/hmac/hmac.h b/drivers/builtin_openssl2/openssl/hmac.h
index 1be0022190..1be0022190 100644
--- a/drivers/builtin_openssl/crypto/hmac/hmac.h
+++ b/drivers/builtin_openssl2/openssl/hmac.h
diff --git a/drivers/builtin_openssl/crypto/idea/idea.h b/drivers/builtin_openssl2/openssl/idea.h
index e9a1e7f1a5..e9a1e7f1a5 100644
--- a/drivers/builtin_openssl/crypto/idea/idea.h
+++ b/drivers/builtin_openssl2/openssl/idea.h
diff --git a/drivers/builtin_openssl/crypto/krb5/krb5_asn.h b/drivers/builtin_openssl2/openssl/krb5_asn.h
index 41725d0dc4..41725d0dc4 100644
--- a/drivers/builtin_openssl/crypto/krb5/krb5_asn.h
+++ b/drivers/builtin_openssl2/openssl/krb5_asn.h
diff --git a/drivers/builtin_openssl/openssl/kssl.h b/drivers/builtin_openssl2/openssl/kssl.h
index e4df843073..e4df843073 100644
--- a/drivers/builtin_openssl/openssl/kssl.h
+++ b/drivers/builtin_openssl2/openssl/kssl.h
diff --git a/drivers/builtin_openssl/crypto/lhash/lhash.h b/drivers/builtin_openssl2/openssl/lhash.h
index e7d8763591..e7d8763591 100644
--- a/drivers/builtin_openssl/crypto/lhash/lhash.h
+++ b/drivers/builtin_openssl2/openssl/lhash.h
diff --git a/drivers/builtin_openssl/crypto/md4/md4.h b/drivers/builtin_openssl2/openssl/md4.h
index a55368a790..a55368a790 100644
--- a/drivers/builtin_openssl/crypto/md4/md4.h
+++ b/drivers/builtin_openssl2/openssl/md4.h
diff --git a/drivers/builtin_openssl2/openssl/md5.h b/drivers/builtin_openssl2/openssl/md5.h
new file mode 100644
index 0000000000..765be94335
--- /dev/null
+++ b/drivers/builtin_openssl2/openssl/md5.h
@@ -0,0 +1,127 @@
+/* crypto/md5/md5.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_MD5_H
+#define HEADER_MD5_H
+
+#include <openssl/e_os2.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_NO_MD5
+#error MD5 is disabled.
+#endif
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! MD5_LONG has to be at least 32 bits wide. If it's wider, then !
+ * ! MD5_LONG_LOG2 has to be defined along. !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+#if defined(__LP32__)
+#define MD5_LONG unsigned long
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
+#define MD5_LONG unsigned long
+#define MD5_LONG_LOG2 3
+/*
+ * _CRAY note. I could declare short, but I have no idea what impact
+ * does it have on performance on none-T3E machines. I could declare
+ * int, but at least on C90 sizeof(int) can be chosen at compile time.
+ * So I've chosen long...
+ * <appro@fy.chalmers.se>
+ */
+#else
+#define MD5_LONG unsigned int
+#endif
+
+#define MD5_CBLOCK 64
+#define MD5_LBLOCK (MD5_CBLOCK/4)
+#define MD5_DIGEST_LENGTH 16
+
+typedef struct MD5state_st
+ {
+ MD5_LONG A,B,C,D;
+ MD5_LONG Nl,Nh;
+ MD5_LONG data[MD5_LBLOCK];
+ unsigned int num;
+ } MD5_CTX;
+
+//#ifdef OPENSSL_FIPS
+int private_MD5_Init(MD5_CTX *c);
+//#endif
+
+//#define MD5_Init _SSL_MD5_Init
+#define MD5_Final _SSL_MD5_Final
+#define MD5_Update _SSL_MD5_Update
+#define MD5_Transform _SSL_MD5_Transform
+#define MD5_Init private_MD5_Init
+
+int _SSL_MD5_Init(MD5_CTX *c);
+int _SSL_MD5_Update(MD5_CTX *c, const void *data, size_t len);
+int _SSL_MD5_Final(unsigned char *md, MD5_CTX *c);
+unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);
+void _SSL_MD5_Transform(MD5_CTX *c, const unsigned char *b);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/builtin_openssl/crypto/mdc2/mdc2.h b/drivers/builtin_openssl2/openssl/mdc2.h
index f3e8e579d2..f3e8e579d2 100644
--- a/drivers/builtin_openssl/crypto/mdc2/mdc2.h
+++ b/drivers/builtin_openssl2/openssl/mdc2.h
diff --git a/drivers/builtin_openssl/crypto/modes/modes.h b/drivers/builtin_openssl2/openssl/modes.h
index f18215bb2b..f18215bb2b 100644
--- a/drivers/builtin_openssl/crypto/modes/modes.h
+++ b/drivers/builtin_openssl2/openssl/modes.h
diff --git a/drivers/builtin_openssl/crypto/objects/obj_mac.h b/drivers/builtin_openssl2/openssl/obj_mac.h
index b5ea7cdab4..b5ea7cdab4 100644
--- a/drivers/builtin_openssl/crypto/objects/obj_mac.h
+++ b/drivers/builtin_openssl2/openssl/obj_mac.h
diff --git a/drivers/builtin_openssl/crypto/objects/objects.h b/drivers/builtin_openssl2/openssl/objects.h
index bd0ee52feb..bd0ee52feb 100644
--- a/drivers/builtin_openssl/crypto/objects/objects.h
+++ b/drivers/builtin_openssl2/openssl/objects.h
diff --git a/drivers/builtin_openssl/crypto/ocsp/ocsp.h b/drivers/builtin_openssl2/openssl/ocsp.h
index 31e45744ba..31e45744ba 100644
--- a/drivers/builtin_openssl/crypto/ocsp/ocsp.h
+++ b/drivers/builtin_openssl2/openssl/ocsp.h
diff --git a/drivers/builtin_openssl/openssl/opensslconf.h b/drivers/builtin_openssl2/openssl/opensslconf.h
index 212c2ede7f..212c2ede7f 100644
--- a/drivers/builtin_openssl/openssl/opensslconf.h
+++ b/drivers/builtin_openssl2/openssl/opensslconf.h
diff --git a/drivers/builtin_openssl2/openssl/opensslv.h b/drivers/builtin_openssl2/openssl/opensslv.h
new file mode 100644
index 0000000000..c3b6acec75
--- /dev/null
+++ b/drivers/builtin_openssl2/openssl/opensslv.h
@@ -0,0 +1,89 @@
+#ifndef HEADER_OPENSSLV_H
+#define HEADER_OPENSSLV_H
+
+/* Numeric release version identifier:
+ * MNNFFPPS: major minor fix patch status
+ * The status nibble has one of the values 0 for development, 1 to e for betas
+ * 1 to 14, and f for release. The patch level is exactly that.
+ * For example:
+ * 0.9.3-dev 0x00903000
+ * 0.9.3-beta1 0x00903001
+ * 0.9.3-beta2-dev 0x00903002
+ * 0.9.3-beta2 0x00903002 (same as ...beta2-dev)
+ * 0.9.3 0x0090300f
+ * 0.9.3a 0x0090301f
+ * 0.9.4 0x0090400f
+ * 1.2.3z 0x102031af
+ *
+ * For continuity reasons (because 0.9.5 is already out, and is coded
+ * 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level
+ * part is slightly different, by setting the highest bit. This means
+ * that 0.9.5a looks like this: 0x0090581f. At 0.9.6, we can start
+ * with 0x0090600S...
+ *
+ * (Prior to 0.9.3-dev a different scheme was used: 0.9.2b is 0x0922.)
+ * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
+ * major minor fix final patch/beta)
+ */
+#define OPENSSL_VERSION_NUMBER 0x1000108fL
+#ifdef OPENSSL_FIPS
+#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.1h-fips 5 Jun 2014"
+#else
+#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.1h 5 Jun 2014"
+#endif
+#define OPENSSL_VERSION_PTEXT " part of " OPENSSL_VERSION_TEXT
+
+
+/* The macros below are to be used for shared library (.so, .dll, ...)
+ * versioning. That kind of versioning works a bit differently between
+ * operating systems. The most usual scheme is to set a major and a minor
+ * number, and have the runtime loader check that the major number is equal
+ * to what it was at application link time, while the minor number has to
+ * be greater or equal to what it was at application link time. With this
+ * scheme, the version number is usually part of the file name, like this:
+ *
+ * libcrypto.so.0.9
+ *
+ * Some unixen also make a softlink with the major verson number only:
+ *
+ * libcrypto.so.0
+ *
+ * On Tru64 and IRIX 6.x it works a little bit differently. There, the
+ * shared library version is stored in the file, and is actually a series
+ * of versions, separated by colons. The rightmost version present in the
+ * library when linking an application is stored in the application to be
+ * matched at run time. When the application is run, a check is done to
+ * see if the library version stored in the application matches any of the
+ * versions in the version string of the library itself.
+ * This version string can be constructed in any way, depending on what
+ * kind of matching is desired. However, to implement the same scheme as
+ * the one used in the other unixen, all compatible versions, from lowest
+ * to highest, should be part of the string. Consecutive builds would
+ * give the following versions strings:
+ *
+ * 3.0
+ * 3.0:3.1
+ * 3.0:3.1:3.2
+ * 4.0
+ * 4.0:4.1
+ *
+ * Notice how version 4 is completely incompatible with version, and
+ * therefore give the breach you can see.
+ *
+ * There may be other schemes as well that I haven't yet discovered.
+ *
+ * So, here's the way it works here: first of all, the library version
+ * number doesn't need at all to match the overall OpenSSL version.
+ * However, it's nice and more understandable if it actually does.
+ * The current library version is stored in the macro SHLIB_VERSION_NUMBER,
+ * which is just a piece of text in the format "M.m.e" (Major, minor, edit).
+ * For the sake of Tru64, IRIX, and any other OS that behaves in similar ways,
+ * we need to keep a history of version numbers, which is done in the
+ * macro SHLIB_VERSION_HISTORY. The numbers are separated by colons and
+ * should only keep the versions that are binary compatible with the current.
+ */
+#define SHLIB_VERSION_HISTORY ""
+#define SHLIB_VERSION_NUMBER "1.0.0"
+
+
+#endif /* HEADER_OPENSSLV_H */
diff --git a/drivers/builtin_openssl/crypto/ossl_typ.h b/drivers/builtin_openssl2/openssl/ossl_typ.h
index ea9227f6f9..ea9227f6f9 100644
--- a/drivers/builtin_openssl/crypto/ossl_typ.h
+++ b/drivers/builtin_openssl2/openssl/ossl_typ.h
diff --git a/drivers/builtin_openssl/crypto/pem/pem.h b/drivers/builtin_openssl2/openssl/pem.h
index 8a6ababe3a..8a6ababe3a 100644
--- a/drivers/builtin_openssl/crypto/pem/pem.h
+++ b/drivers/builtin_openssl2/openssl/pem.h
diff --git a/drivers/builtin_openssl/crypto/pem/pem2.h b/drivers/builtin_openssl2/openssl/pem2.h
index f31790d69c..f31790d69c 100644
--- a/drivers/builtin_openssl/crypto/pem/pem2.h
+++ b/drivers/builtin_openssl2/openssl/pem2.h
diff --git a/drivers/builtin_openssl/crypto/pkcs12/pkcs12.h b/drivers/builtin_openssl2/openssl/pkcs12.h
index b17eb9f42b..b17eb9f42b 100644
--- a/drivers/builtin_openssl/crypto/pkcs12/pkcs12.h
+++ b/drivers/builtin_openssl2/openssl/pkcs12.h
diff --git a/drivers/builtin_openssl2/openssl/pkcs7.h b/drivers/builtin_openssl2/openssl/pkcs7.h
new file mode 100644
index 0000000000..04f60379fb
--- /dev/null
+++ b/drivers/builtin_openssl2/openssl/pkcs7.h
@@ -0,0 +1,500 @@
+/* crypto/pkcs7/pkcs7.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_PKCS7_H
+#define HEADER_PKCS7_H
+
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/e_os2.h>
+
+#include <openssl/symhacks.h>
+#include <openssl/ossl_typ.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_SYS_WIN32
+/* Under Win32 thes are defined in wincrypt.h */
+#undef PKCS7_ISSUER_AND_SERIAL
+#undef PKCS7_SIGNER_INFO
+#endif
+
+/*
+Encryption_ID DES-CBC
+Digest_ID MD5
+Digest_Encryption_ID rsaEncryption
+Key_Encryption_ID rsaEncryption
+*/
+
+typedef struct pkcs7_issuer_and_serial_st
+ {
+ X509_NAME *issuer;
+ ASN1_INTEGER *serial;
+ } PKCS7_ISSUER_AND_SERIAL;
+
+typedef struct pkcs7_signer_info_st
+ {
+ ASN1_INTEGER *version; /* version 1 */
+ PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;
+ X509_ALGOR *digest_alg;
+ STACK_OF(X509_ATTRIBUTE) *auth_attr; /* [ 0 ] */
+ X509_ALGOR *digest_enc_alg;
+ ASN1_OCTET_STRING *enc_digest;
+ STACK_OF(X509_ATTRIBUTE) *unauth_attr; /* [ 1 ] */
+
+ /* The private key to sign with */
+ EVP_PKEY *pkey;
+ } PKCS7_SIGNER_INFO;
+
+DECLARE_STACK_OF(PKCS7_SIGNER_INFO)
+DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO)
+
+typedef struct pkcs7_recip_info_st
+ {
+ ASN1_INTEGER *version; /* version 0 */
+ PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;
+ X509_ALGOR *key_enc_algor;
+ ASN1_OCTET_STRING *enc_key;
+ X509 *cert; /* get the pub-key from this */
+ } PKCS7_RECIP_INFO;
+
+DECLARE_STACK_OF(PKCS7_RECIP_INFO)
+DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO)
+
+typedef struct pkcs7_signed_st
+ {
+ ASN1_INTEGER *version; /* version 1 */
+ STACK_OF(X509_ALGOR) *md_algs; /* md used */
+ STACK_OF(X509) *cert; /* [ 0 ] */
+ STACK_OF(X509_CRL) *crl; /* [ 1 ] */
+ STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
+
+ struct pkcs7_st *contents;
+ } PKCS7_SIGNED;
+/* The above structure is very very similar to PKCS7_SIGN_ENVELOPE.
+ * How about merging the two */
+
+typedef struct pkcs7_enc_content_st
+ {
+ ASN1_OBJECT *content_type;
+ X509_ALGOR *algorithm;
+ ASN1_OCTET_STRING *enc_data; /* [ 0 ] */
+ const EVP_CIPHER *cipher;
+ } PKCS7_ENC_CONTENT;
+
+typedef struct pkcs7_enveloped_st
+ {
+ ASN1_INTEGER *version; /* version 0 */
+ STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
+ PKCS7_ENC_CONTENT *enc_data;
+ } PKCS7_ENVELOPE;
+
+typedef struct pkcs7_signedandenveloped_st
+ {
+ ASN1_INTEGER *version; /* version 1 */
+ STACK_OF(X509_ALGOR) *md_algs; /* md used */
+ STACK_OF(X509) *cert; /* [ 0 ] */
+ STACK_OF(X509_CRL) *crl; /* [ 1 ] */
+ STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
+
+ PKCS7_ENC_CONTENT *enc_data;
+ STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
+ } PKCS7_SIGN_ENVELOPE;
+
+typedef struct pkcs7_digest_st
+ {
+ ASN1_INTEGER *version; /* version 0 */
+ X509_ALGOR *md; /* md used */
+ struct pkcs7_st *contents;
+ ASN1_OCTET_STRING *digest;
+ } PKCS7_DIGEST;
+
+typedef struct pkcs7_encrypted_st
+ {
+ ASN1_INTEGER *version; /* version 0 */
+ PKCS7_ENC_CONTENT *enc_data;
+ } PKCS7_ENCRYPT;
+
+typedef struct pkcs7_st
+ {
+ /* The following is non NULL if it contains ASN1 encoding of
+ * this structure */
+ unsigned char *asn1;
+ long length;
+
+#define PKCS7_S_HEADER 0
+#define PKCS7_S_BODY 1
+#define PKCS7_S_TAIL 2
+ int state; /* used during processing */
+
+ int detached;
+
+ ASN1_OBJECT *type;
+ /* content as defined by the type */
+ /* all encryption/message digests are applied to the 'contents',
+ * leaving out the 'type' field. */
+ union {
+ char *ptr;
+
+ /* NID_pkcs7_data */
+ ASN1_OCTET_STRING *data;
+
+ /* NID_pkcs7_signed */
+ PKCS7_SIGNED *sign;
+
+ /* NID_pkcs7_enveloped */
+ PKCS7_ENVELOPE *enveloped;
+
+ /* NID_pkcs7_signedAndEnveloped */
+ PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
+
+ /* NID_pkcs7_digest */
+ PKCS7_DIGEST *digest;
+
+ /* NID_pkcs7_encrypted */
+ PKCS7_ENCRYPT *encrypted;
+
+ /* Anything else */
+ ASN1_TYPE *other;
+ } d;
+ } PKCS7;
+
+DECLARE_STACK_OF(PKCS7)
+DECLARE_ASN1_SET_OF(PKCS7)
+DECLARE_PKCS12_STACK_OF(PKCS7)
+
+#define PKCS7_OP_SET_DETACHED_SIGNATURE 1
+#define PKCS7_OP_GET_DETACHED_SIGNATURE 2
+
+#define PKCS7_get_signed_attributes(si) ((si)->auth_attr)
+#define PKCS7_get_attributes(si) ((si)->unauth_attr)
+
+#define PKCS7_type_is_signed(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_signed)
+#define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
+#define PKCS7_type_is_enveloped(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_enveloped)
+#define PKCS7_type_is_signedAndEnveloped(a) \
+ (OBJ_obj2nid((a)->type) == NID_pkcs7_signedAndEnveloped)
+#define PKCS7_type_is_data(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_data)
+#define PKCS7_type_is_digest(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
+#define PKCS7_type_is_encrypted(a) \
+ (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
+
+#define PKCS7_type_is_digest(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
+
+#define PKCS7_set_detached(p,v) \
+ PKCS7_ctrl(p,PKCS7_OP_SET_DETACHED_SIGNATURE,v,NULL)
+#define PKCS7_get_detached(p) \
+ PKCS7_ctrl(p,PKCS7_OP_GET_DETACHED_SIGNATURE,0,NULL)
+
+#define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7))
+
+/* S/MIME related flags */
+
+#define PKCS7_TEXT 0x1
+#define PKCS7_NOCERTS 0x2
+#define PKCS7_NOSIGS 0x4
+#define PKCS7_NOCHAIN 0x8
+#define PKCS7_NOINTERN 0x10
+#define PKCS7_NOVERIFY 0x20
+#define PKCS7_DETACHED 0x40
+#define PKCS7_BINARY 0x80
+#define PKCS7_NOATTR 0x100
+#define PKCS7_NOSMIMECAP 0x200
+#define PKCS7_NOOLDMIMETYPE 0x400
+#define PKCS7_CRLFEOL 0x800
+#define PKCS7_STREAM 0x1000
+#define PKCS7_NOCRL 0x2000
+#define PKCS7_PARTIAL 0x4000
+#define PKCS7_REUSE_DIGEST 0x8000
+
+/* Flags: for compatibility with older code */
+
+#define SMIME_TEXT PKCS7_TEXT
+#define SMIME_NOCERTS PKCS7_NOCERTS
+#define SMIME_NOSIGS PKCS7_NOSIGS
+#define SMIME_NOCHAIN PKCS7_NOCHAIN
+#define SMIME_NOINTERN PKCS7_NOINTERN
+#define SMIME_NOVERIFY PKCS7_NOVERIFY
+#define SMIME_DETACHED PKCS7_DETACHED
+#define SMIME_BINARY PKCS7_BINARY
+#define SMIME_NOATTR PKCS7_NOATTR
+
+DECLARE_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL)
+
+int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data,const EVP_MD *type,
+ unsigned char *md,unsigned int *len);
+#ifndef OPENSSL_NO_FP_API
+PKCS7 *d2i_PKCS7_fp(FILE *fp,PKCS7 **p7);
+int i2d_PKCS7_fp(FILE *fp,PKCS7 *p7);
+#endif
+PKCS7 *PKCS7_dup(PKCS7 *p7);
+PKCS7 *d2i_PKCS7_bio(BIO *bp,PKCS7 **p7);
+int i2d_PKCS7_bio(BIO *bp,PKCS7 *p7);
+int i2d_PKCS7_bio_stream(BIO *out, PKCS7 *p7, BIO *in, int flags);
+int PEM_write_bio_PKCS7_stream(BIO *out, PKCS7 *p7, BIO *in, int flags);
+
+DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNER_INFO)
+DECLARE_ASN1_FUNCTIONS(PKCS7_RECIP_INFO)
+DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNED)
+DECLARE_ASN1_FUNCTIONS(PKCS7_ENC_CONTENT)
+DECLARE_ASN1_FUNCTIONS(PKCS7_ENVELOPE)
+DECLARE_ASN1_FUNCTIONS(PKCS7_SIGN_ENVELOPE)
+DECLARE_ASN1_FUNCTIONS(PKCS7_DIGEST)
+DECLARE_ASN1_FUNCTIONS(PKCS7_ENCRYPT)
+DECLARE_ASN1_FUNCTIONS(PKCS7)
+
+DECLARE_ASN1_ITEM(PKCS7_ATTR_SIGN)
+DECLARE_ASN1_ITEM(PKCS7_ATTR_VERIFY)
+
+DECLARE_ASN1_NDEF_FUNCTION(PKCS7)
+DECLARE_ASN1_PRINT_FUNCTION(PKCS7)
+
+long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg);
+
+int PKCS7_set_type(PKCS7 *p7, int type);
+int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other);
+int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data);
+int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey,
+ const EVP_MD *dgst);
+int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si);
+int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *p7i);
+int PKCS7_add_certificate(PKCS7 *p7, X509 *x509);
+int PKCS7_add_crl(PKCS7 *p7, X509_CRL *x509);
+int PKCS7_content_new(PKCS7 *p7, int nid);
+int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx,
+ BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si);
+int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
+ X509 *x509);
+
+BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio);
+int PKCS7_dataFinal(PKCS7 *p7, BIO *bio);
+BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert);
+
+
+PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509,
+ EVP_PKEY *pkey, const EVP_MD *dgst);
+X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
+int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md);
+STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7);
+
+PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509);
+void PKCS7_SIGNER_INFO_get0_algs(PKCS7_SIGNER_INFO *si, EVP_PKEY **pk,
+ X509_ALGOR **pdig, X509_ALGOR **psig);
+void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc);
+int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri);
+int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509);
+int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher);
+int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7);
+
+PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx);
+ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk);
+int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si,int nid,int type,
+ void *data);
+int PKCS7_add_attribute (PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
+ void *value);
+ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid);
+ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid);
+int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
+ STACK_OF(X509_ATTRIBUTE) *sk);
+int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,STACK_OF(X509_ATTRIBUTE) *sk);
+
+
+PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
+ BIO *data, int flags);
+
+PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7,
+ X509 *signcert, EVP_PKEY *pkey, const EVP_MD *md,
+ int flags);
+
+int PKCS7_final(PKCS7 *p7, BIO *data, int flags);
+int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
+ BIO *indata, BIO *out, int flags);
+STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags);
+PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
+ int flags);
+int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags);
+
+int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si,
+ STACK_OF(X509_ALGOR) *cap);
+STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si);
+int PKCS7_simple_smimecap(STACK_OF(X509_ALGOR) *sk, int nid, int arg);
+
+int PKCS7_add_attrib_content_type(PKCS7_SIGNER_INFO *si, ASN1_OBJECT *coid);
+int PKCS7_add0_attrib_signing_time(PKCS7_SIGNER_INFO *si, ASN1_TIME *t);
+int PKCS7_add1_attrib_digest(PKCS7_SIGNER_INFO *si,
+ const unsigned char *md, int mdlen);
+
+int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags);
+PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont);
+
+BIO *BIO_new_PKCS7(BIO *out, PKCS7 *p7);
+
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_PKCS7_strings(void);
+
+/* Error codes for the PKCS7 functions. */
+
+/* Function codes. */
+#define PKCS7_F_B64_READ_PKCS7 120
+#define PKCS7_F_B64_WRITE_PKCS7 121
+#define PKCS7_F_DO_PKCS7_SIGNED_ATTRIB 136
+#define PKCS7_F_I2D_PKCS7_BIO_STREAM 140
+#define PKCS7_F_PKCS7_ADD0_ATTRIB_SIGNING_TIME 135
+#define PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP 118
+#define PKCS7_F_PKCS7_ADD_CERTIFICATE 100
+#define PKCS7_F_PKCS7_ADD_CRL 101
+#define PKCS7_F_PKCS7_ADD_RECIPIENT_INFO 102
+#define PKCS7_F_PKCS7_ADD_SIGNATURE 131
+#define PKCS7_F_PKCS7_ADD_SIGNER 103
+#define PKCS7_F_PKCS7_BIO_ADD_DIGEST 125
+#define PKCS7_F_PKCS7_COPY_EXISTING_DIGEST 138
+#define PKCS7_F_PKCS7_CTRL 104
+#define PKCS7_F_PKCS7_DATADECODE 112
+#define PKCS7_F_PKCS7_DATAFINAL 128
+#define PKCS7_F_PKCS7_DATAINIT 105
+#define PKCS7_F_PKCS7_DATASIGN 106
+#define PKCS7_F_PKCS7_DATAVERIFY 107
+#define PKCS7_F_PKCS7_DECRYPT 114
+#define PKCS7_F_PKCS7_DECRYPT_RINFO 133
+#define PKCS7_F_PKCS7_ENCODE_RINFO 132
+#define PKCS7_F_PKCS7_ENCRYPT 115
+#define PKCS7_F_PKCS7_FINAL 134
+#define PKCS7_F_PKCS7_FIND_DIGEST 127
+#define PKCS7_F_PKCS7_GET0_SIGNERS 124
+#define PKCS7_F_PKCS7_RECIP_INFO_SET 130
+#define PKCS7_F_PKCS7_SET_CIPHER 108
+#define PKCS7_F_PKCS7_SET_CONTENT 109
+#define PKCS7_F_PKCS7_SET_DIGEST 126
+#define PKCS7_F_PKCS7_SET_TYPE 110
+#define PKCS7_F_PKCS7_SIGN 116
+#define PKCS7_F_PKCS7_SIGNATUREVERIFY 113
+#define PKCS7_F_PKCS7_SIGNER_INFO_SET 129
+#define PKCS7_F_PKCS7_SIGNER_INFO_SIGN 139
+#define PKCS7_F_PKCS7_SIGN_ADD_SIGNER 137
+#define PKCS7_F_PKCS7_SIMPLE_SMIMECAP 119
+#define PKCS7_F_PKCS7_VERIFY 117
+#define PKCS7_F_SMIME_READ_PKCS7 122
+#define PKCS7_F_SMIME_TEXT 123
+
+/* Reason codes. */
+#define PKCS7_R_CERTIFICATE_VERIFY_ERROR 117
+#define PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 144
+#define PKCS7_R_CIPHER_NOT_INITIALIZED 116
+#define PKCS7_R_CONTENT_AND_DATA_PRESENT 118
+#define PKCS7_R_CTRL_ERROR 152
+#define PKCS7_R_DECODE_ERROR 130
+#define PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH 100
+#define PKCS7_R_DECRYPT_ERROR 119
+#define PKCS7_R_DIGEST_FAILURE 101
+#define PKCS7_R_ENCRYPTION_CTRL_FAILURE 149
+#define PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 150
+#define PKCS7_R_ERROR_ADDING_RECIPIENT 120
+#define PKCS7_R_ERROR_SETTING_CIPHER 121
+#define PKCS7_R_INVALID_MIME_TYPE 131
+#define PKCS7_R_INVALID_NULL_POINTER 143
+#define PKCS7_R_INVALID_SIGNED_DATA_TYPE 155
+#define PKCS7_R_MIME_NO_CONTENT_TYPE 132
+#define PKCS7_R_MIME_PARSE_ERROR 133
+#define PKCS7_R_MIME_SIG_PARSE_ERROR 134
+#define PKCS7_R_MISSING_CERIPEND_INFO 103
+#define PKCS7_R_NO_CONTENT 122
+#define PKCS7_R_NO_CONTENT_TYPE 135
+#define PKCS7_R_NO_DEFAULT_DIGEST 151
+#define PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND 154
+#define PKCS7_R_NO_MULTIPART_BODY_FAILURE 136
+#define PKCS7_R_NO_MULTIPART_BOUNDARY 137
+#define PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE 115
+#define PKCS7_R_NO_RECIPIENT_MATCHES_KEY 146
+#define PKCS7_R_NO_SIGNATURES_ON_DATA 123
+#define PKCS7_R_NO_SIGNERS 142
+#define PKCS7_R_NO_SIG_CONTENT_TYPE 138
+#define PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE 104
+#define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR 124
+#define PKCS7_R_PKCS7_ADD_SIGNER_ERROR 153
+#define PKCS7_R_PKCS7_DATAFINAL 126
+#define PKCS7_R_PKCS7_DATAFINAL_ERROR 125
+#define PKCS7_R_PKCS7_DATASIGN 145
+#define PKCS7_R_PKCS7_PARSE_ERROR 139
+#define PKCS7_R_PKCS7_SIG_PARSE_ERROR 140
+#define PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 127
+#define PKCS7_R_SIGNATURE_FAILURE 105
+#define PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND 128
+#define PKCS7_R_SIGNING_CTRL_FAILURE 147
+#define PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 148
+#define PKCS7_R_SIG_INVALID_MIME_TYPE 141
+#define PKCS7_R_SMIME_TEXT_ERROR 129
+#define PKCS7_R_UNABLE_TO_FIND_CERTIFICATE 106
+#define PKCS7_R_UNABLE_TO_FIND_MEM_BIO 107
+#define PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST 108
+#define PKCS7_R_UNKNOWN_DIGEST_TYPE 109
+#define PKCS7_R_UNKNOWN_OPERATION 110
+#define PKCS7_R_UNSUPPORTED_CIPHER_TYPE 111
+#define PKCS7_R_UNSUPPORTED_CONTENT_TYPE 112
+#define PKCS7_R_WRONG_CONTENT_TYPE 113
+#define PKCS7_R_WRONG_PKCS7_TYPE 114
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/drivers/builtin_openssl/crypto/pqueue/pqueue.h b/drivers/builtin_openssl2/openssl/pqueue.h
index 87fc9037c8..87fc9037c8 100644
--- a/drivers/builtin_openssl/crypto/pqueue/pqueue.h
+++ b/drivers/builtin_openssl2/openssl/pqueue.h
diff --git a/drivers/builtin_openssl2/openssl/rand.h b/drivers/builtin_openssl2/openssl/rand.h
new file mode 100644
index 0000000000..b5adb825fd
--- /dev/null
+++ b/drivers/builtin_openssl2/openssl/rand.h
@@ -0,0 +1,166 @@
+/* crypto/rand/rand.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_RAND_H
+#define HEADER_RAND_H
+
+#include <stdlib.h>
+#include <openssl/ossl_typ.h>
+#include <openssl/e_os2.h>
+
+#if defined(OPENSSL_SYS_WINDOWS)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#ifdef OCSP_RESPONSE
+#undef OCSP_RESPONSE
+#endif
+#ifdef OCSP_REQUEST
+#undef OCSP_REQUEST
+#endif
+#ifdef X509_NAME
+#undef X509_NAME
+#undef X509_NAME
+#undef X509_EXTENSIONS
+#undef X509_CERT_PAIR
+#undef PKCS7_ISSUER_AND_SERIAL
+#endif
+
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(OPENSSL_FIPS)
+#define FIPS_RAND_SIZE_T size_t
+#endif
+
+/* Already defined in ossl_typ.h */
+/* typedef struct rand_meth_st RAND_METHOD; */
+
+struct rand_meth_st
+ {
+ void (*seed)(const void *buf, int num);
+ int (*bytes)(unsigned char *buf, int num);
+ void (*cleanup)(void);
+ void (*add)(const void *buf, int num, double entropy);
+ int (*pseudorand)(unsigned char *buf, int num);
+ int (*status)(void);
+ };
+
+#ifdef BN_DEBUG
+extern int rand_predictable;
+#endif
+
+int RAND_set_rand_method(const RAND_METHOD *meth);
+const RAND_METHOD *RAND_get_rand_method(void);
+#ifndef OPENSSL_NO_ENGINE
+int RAND_set_rand_engine(ENGINE *engine);
+#endif
+RAND_METHOD *RAND_SSLeay(void);
+void RAND_cleanup(void );
+int RAND_bytes(unsigned char *buf,int num);
+int RAND_pseudo_bytes(unsigned char *buf,int num);
+void RAND_seed(const void *buf,int num);
+void RAND_add(const void *buf,int num,double entropy);
+int RAND_load_file(const char *file,long max_bytes);
+int RAND_write_file(const char *file);
+const char *RAND_file_name(char *file,size_t num);
+int RAND_status(void);
+int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes);
+int RAND_egd(const char *path);
+int RAND_egd_bytes(const char *path,int bytes);
+int RAND_poll(void);
+
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
+
+void RAND_screen(void);
+int RAND_event(UINT, WPARAM, LPARAM);
+
+#endif
+
+#ifdef OPENSSL_FIPS
+void RAND_set_fips_drbg_type(int type, int flags);
+int RAND_init_fips(void);
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_RAND_strings(void);
+
+/* Error codes for the RAND functions. */
+
+/* Function codes. */
+#define RAND_F_RAND_GET_RAND_METHOD 101
+#define RAND_F_RAND_INIT_FIPS 102
+#define RAND_F_SSLEAY_RAND_BYTES 100
+
+/* Reason codes. */
+#define RAND_R_DUAL_EC_DRBG_DISABLED 104
+#define RAND_R_ERROR_INITIALISING_DRBG 102
+#define RAND_R_ERROR_INSTANTIATING_DRBG 103
+#define RAND_R_NO_FIPS_RANDOM_METHOD_SET 101
+#define RAND_R_PRNG_NOT_SEEDED 100
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/drivers/builtin_openssl/crypto/rc2/rc2.h b/drivers/builtin_openssl2/openssl/rc2.h
index e542ec94ff..e542ec94ff 100644
--- a/drivers/builtin_openssl/crypto/rc2/rc2.h
+++ b/drivers/builtin_openssl2/openssl/rc2.h
diff --git a/drivers/builtin_openssl/crypto/rc4/rc4.h b/drivers/builtin_openssl2/openssl/rc4.h
index 88ceb46bc5..88ceb46bc5 100644
--- a/drivers/builtin_openssl/crypto/rc4/rc4.h
+++ b/drivers/builtin_openssl2/openssl/rc4.h
diff --git a/drivers/builtin_openssl/crypto/ripemd/ripemd.h b/drivers/builtin_openssl2/openssl/ripemd.h
index 189bd8c90e..189bd8c90e 100644
--- a/drivers/builtin_openssl/crypto/ripemd/ripemd.h
+++ b/drivers/builtin_openssl2/openssl/ripemd.h
diff --git a/drivers/builtin_openssl/crypto/rsa/rsa.h b/drivers/builtin_openssl2/openssl/rsa.h
index 5f269e577a..5f269e577a 100644
--- a/drivers/builtin_openssl/crypto/rsa/rsa.h
+++ b/drivers/builtin_openssl2/openssl/rsa.h
diff --git a/drivers/builtin_openssl/crypto/stack/safestack.h b/drivers/builtin_openssl2/openssl/safestack.h
index ea3aa0d800..ea3aa0d800 100644
--- a/drivers/builtin_openssl/crypto/stack/safestack.h
+++ b/drivers/builtin_openssl2/openssl/safestack.h
diff --git a/drivers/builtin_openssl/crypto/seed/seed.h b/drivers/builtin_openssl2/openssl/seed.h
index c50fdd3607..c50fdd3607 100644
--- a/drivers/builtin_openssl/crypto/seed/seed.h
+++ b/drivers/builtin_openssl2/openssl/seed.h
diff --git a/drivers/builtin_openssl/crypto/sha/sha.h b/drivers/builtin_openssl2/openssl/sha.h
index 8a6bf4bbbb..8a6bf4bbbb 100644
--- a/drivers/builtin_openssl/crypto/sha/sha.h
+++ b/drivers/builtin_openssl2/openssl/sha.h
diff --git a/drivers/builtin_openssl/crypto/srp/srp.h b/drivers/builtin_openssl2/openssl/srp.h
index 7ec7825cad..7ec7825cad 100644
--- a/drivers/builtin_openssl/crypto/srp/srp.h
+++ b/drivers/builtin_openssl2/openssl/srp.h
diff --git a/drivers/builtin_openssl/openssl/srtp.h b/drivers/builtin_openssl2/openssl/srtp.h
index c0cf33ef28..c0cf33ef28 100644
--- a/drivers/builtin_openssl/openssl/srtp.h
+++ b/drivers/builtin_openssl2/openssl/srtp.h
diff --git a/drivers/builtin_openssl2/openssl/ssl.h b/drivers/builtin_openssl2/openssl/ssl.h
new file mode 100644
index 0000000000..4c1242c9d2
--- /dev/null
+++ b/drivers/builtin_openssl2/openssl/ssl.h
@@ -0,0 +1,2590 @@
+/* ssl/ssl.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#ifndef HEADER_SSL_H
+#define HEADER_SSL_H
+
+#include <openssl/e_os2.h>
+
+#ifndef OPENSSL_NO_COMP
+#include <openssl/comp.h>
+#endif
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#ifndef OPENSSL_NO_DEPRECATED
+#ifndef OPENSSL_NO_X509
+#include <openssl/x509.h>
+#endif
+#include <openssl/crypto.h>
+#include <openssl/lhash.h>
+#include <openssl/buffer.h>
+#endif
+#include <openssl/pem.h>
+#include <openssl/hmac.h>
+
+#include <openssl/kssl.h>
+#include <openssl/safestack.h>
+#include <openssl/symhacks.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* SSLeay version number for ASN.1 encoding of the session information */
+/* Version 0 - initial version
+ * Version 1 - added the optional peer certificate
+ */
+#define SSL_SESSION_ASN1_VERSION 0x0001
+
+/* text strings for the ciphers */
+#define SSL_TXT_NULL_WITH_MD5 SSL2_TXT_NULL_WITH_MD5
+#define SSL_TXT_RC4_128_WITH_MD5 SSL2_TXT_RC4_128_WITH_MD5
+#define SSL_TXT_RC4_128_EXPORT40_WITH_MD5 SSL2_TXT_RC4_128_EXPORT40_WITH_MD5
+#define SSL_TXT_RC2_128_CBC_WITH_MD5 SSL2_TXT_RC2_128_CBC_WITH_MD5
+#define SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5
+#define SSL_TXT_IDEA_128_CBC_WITH_MD5 SSL2_TXT_IDEA_128_CBC_WITH_MD5
+#define SSL_TXT_DES_64_CBC_WITH_MD5 SSL2_TXT_DES_64_CBC_WITH_MD5
+#define SSL_TXT_DES_64_CBC_WITH_SHA SSL2_TXT_DES_64_CBC_WITH_SHA
+#define SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5
+#define SSL_TXT_DES_192_EDE3_CBC_WITH_SHA SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA
+
+/* VRS Additional Kerberos5 entries
+ */
+#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA
+#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
+#define SSL_TXT_KRB5_RC4_128_SHA SSL3_TXT_KRB5_RC4_128_SHA
+#define SSL_TXT_KRB5_IDEA_128_CBC_SHA SSL3_TXT_KRB5_IDEA_128_CBC_SHA
+#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5
+#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5
+#define SSL_TXT_KRB5_RC4_128_MD5 SSL3_TXT_KRB5_RC4_128_MD5
+#define SSL_TXT_KRB5_IDEA_128_CBC_MD5 SSL3_TXT_KRB5_IDEA_128_CBC_MD5
+
+#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA
+#define SSL_TXT_KRB5_RC2_40_CBC_SHA SSL3_TXT_KRB5_RC2_40_CBC_SHA
+#define SSL_TXT_KRB5_RC4_40_SHA SSL3_TXT_KRB5_RC4_40_SHA
+#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5
+#define SSL_TXT_KRB5_RC2_40_CBC_MD5 SSL3_TXT_KRB5_RC2_40_CBC_MD5
+#define SSL_TXT_KRB5_RC4_40_MD5 SSL3_TXT_KRB5_RC4_40_MD5
+
+#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA
+#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5
+#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA
+#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5
+#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
+#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5
+#define SSL_MAX_KRB5_PRINCIPAL_LENGTH 256
+
+#define SSL_MAX_SSL_SESSION_ID_LENGTH 32
+#define SSL_MAX_SID_CTX_LENGTH 32
+
+#define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES (512/8)
+#define SSL_MAX_KEY_ARG_LENGTH 8
+#define SSL_MAX_MASTER_KEY_LENGTH 48
+
+
+/* These are used to specify which ciphers to use and not to use */
+
+#define SSL_TXT_EXP40 "EXPORT40"
+#define SSL_TXT_EXP56 "EXPORT56"
+#define SSL_TXT_LOW "LOW"
+#define SSL_TXT_MEDIUM "MEDIUM"
+#define SSL_TXT_HIGH "HIGH"
+#define SSL_TXT_FIPS "FIPS"
+
+#define SSL_TXT_kFZA "kFZA" /* unused! */
+#define SSL_TXT_aFZA "aFZA" /* unused! */
+#define SSL_TXT_eFZA "eFZA" /* unused! */
+#define SSL_TXT_FZA "FZA" /* unused! */
+
+#define SSL_TXT_aNULL "aNULL"
+#define SSL_TXT_eNULL "eNULL"
+#define SSL_TXT_NULL "NULL"
+
+#define SSL_TXT_kRSA "kRSA"
+#define SSL_TXT_kDHr "kDHr" /* no such ciphersuites supported! */
+#define SSL_TXT_kDHd "kDHd" /* no such ciphersuites supported! */
+#define SSL_TXT_kDH "kDH" /* no such ciphersuites supported! */
+#define SSL_TXT_kEDH "kEDH"
+#define SSL_TXT_kKRB5 "kKRB5"
+#define SSL_TXT_kECDHr "kECDHr"
+#define SSL_TXT_kECDHe "kECDHe"
+#define SSL_TXT_kECDH "kECDH"
+#define SSL_TXT_kEECDH "kEECDH"
+#define SSL_TXT_kPSK "kPSK"
+#define SSL_TXT_kGOST "kGOST"
+#define SSL_TXT_kSRP "kSRP"
+
+#define SSL_TXT_aRSA "aRSA"
+#define SSL_TXT_aDSS "aDSS"
+#define SSL_TXT_aDH "aDH" /* no such ciphersuites supported! */
+#define SSL_TXT_aECDH "aECDH"
+#define SSL_TXT_aKRB5 "aKRB5"
+#define SSL_TXT_aECDSA "aECDSA"
+#define SSL_TXT_aPSK "aPSK"
+#define SSL_TXT_aGOST94 "aGOST94"
+#define SSL_TXT_aGOST01 "aGOST01"
+#define SSL_TXT_aGOST "aGOST"
+
+#define SSL_TXT_DSS "DSS"
+#define SSL_TXT_DH "DH"
+#define SSL_TXT_EDH "EDH" /* same as "kEDH:-ADH" */
+#define SSL_TXT_ADH "ADH"
+#define SSL_TXT_RSA "RSA"
+#define SSL_TXT_ECDH "ECDH"
+#define SSL_TXT_EECDH "EECDH" /* same as "kEECDH:-AECDH" */
+#define SSL_TXT_AECDH "AECDH"
+#define SSL_TXT_ECDSA "ECDSA"
+#define SSL_TXT_KRB5 "KRB5"
+#define SSL_TXT_PSK "PSK"
+#define SSL_TXT_SRP "SRP"
+
+#define SSL_TXT_DES "DES"
+#define SSL_TXT_3DES "3DES"
+#define SSL_TXT_RC4 "RC4"
+#define SSL_TXT_RC2 "RC2"
+#define SSL_TXT_IDEA "IDEA"
+#define SSL_TXT_SEED "SEED"
+#define SSL_TXT_AES128 "AES128"
+#define SSL_TXT_AES256 "AES256"
+#define SSL_TXT_AES "AES"
+#define SSL_TXT_AES_GCM "AESGCM"
+#define SSL_TXT_CAMELLIA128 "CAMELLIA128"
+#define SSL_TXT_CAMELLIA256 "CAMELLIA256"
+#define SSL_TXT_CAMELLIA "CAMELLIA"
+
+#define SSL_TXT_MD5 "MD5"
+#define SSL_TXT_SHA1 "SHA1"
+#define SSL_TXT_SHA "SHA" /* same as "SHA1" */
+#define SSL_TXT_GOST94 "GOST94"
+#define SSL_TXT_GOST89MAC "GOST89MAC"
+#define SSL_TXT_SHA256 "SHA256"
+#define SSL_TXT_SHA384 "SHA384"
+
+#define SSL_TXT_SSLV2 "SSLv2"
+#define SSL_TXT_SSLV3 "SSLv3"
+#define SSL_TXT_TLSV1 "TLSv1"
+#define SSL_TXT_TLSV1_1 "TLSv1.1"
+#define SSL_TXT_TLSV1_2 "TLSv1.2"
+
+#define SSL_TXT_EXP "EXP"
+#define SSL_TXT_EXPORT "EXPORT"
+
+#define SSL_TXT_ALL "ALL"
+
+/*
+ * COMPLEMENTOF* definitions. These identifiers are used to (de-select)
+ * ciphers normally not being used.
+ * Example: "RC4" will activate all ciphers using RC4 including ciphers
+ * without authentication, which would normally disabled by DEFAULT (due
+ * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT"
+ * will make sure that it is also disabled in the specific selection.
+ * COMPLEMENTOF* identifiers are portable between version, as adjustments
+ * to the default cipher setup will also be included here.
+ *
+ * COMPLEMENTOFDEFAULT does not experience the same special treatment that
+ * DEFAULT gets, as only selection is being done and no sorting as needed
+ * for DEFAULT.
+ */
+#define SSL_TXT_CMPALL "COMPLEMENTOFALL"
+#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT"
+
+/* The following cipher list is used by default.
+ * It also is substituted when an application-defined cipher list string
+ * starts with 'DEFAULT'. */
+#define SSL_DEFAULT_CIPHER_LIST "ALL:!aNULL:!eNULL:!SSLv2"
+/* As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always
+ * starts with a reasonable order, and all we have to do for DEFAULT is
+ * throwing out anonymous and unencrypted ciphersuites!
+ * (The latter are not actually enabled by ALL, but "ALL:RSA" would enable
+ * some of them.)
+ */
+
+/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
+#define SSL_SENT_SHUTDOWN 1
+#define SSL_RECEIVED_SHUTDOWN 2
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_MD5)) && !defined(OPENSSL_NO_SSL2)
+#define OPENSSL_NO_SSL2
+#endif
+
+#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1
+#define SSL_FILETYPE_PEM X509_FILETYPE_PEM
+
+/* This is needed to stop compilers complaining about the
+ * 'struct ssl_st *' function parameters used to prototype callbacks
+ * in SSL_CTX. */
+typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
+typedef struct ssl_method_st SSL_METHOD;
+typedef struct ssl_cipher_st SSL_CIPHER;
+typedef struct ssl_session_st SSL_SESSION;
+
+DECLARE_STACK_OF(SSL_CIPHER)
+
+/* SRTP protection profiles for use with the use_srtp extension (RFC 5764)*/
+typedef struct srtp_protection_profile_st
+ {
+ const char *name;
+ unsigned long id;
+ } SRTP_PROTECTION_PROFILE;
+
+DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE)
+
+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+/* used to hold info on the particular ciphers used */
+struct ssl_cipher_st
+ {
+ int valid;
+ const char *name; /* text name */
+ unsigned long id; /* id, 4 bytes, first is version */
+
+ /* changed in 0.9.9: these four used to be portions of a single value 'algorithms' */
+ unsigned long algorithm_mkey; /* key exchange algorithm */
+ unsigned long algorithm_auth; /* server authentication */
+ unsigned long algorithm_enc; /* symmetric encryption */
+ unsigned long algorithm_mac; /* symmetric authentication */
+ unsigned long algorithm_ssl; /* (major) protocol version */
+
+ unsigned long algo_strength; /* strength and export flags */
+ unsigned long algorithm2; /* Extra flags */
+ int strength_bits; /* Number of bits really used */
+ int alg_bits; /* Number of bits for algorithm */
+ };
+
+
+/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+struct ssl_method_st
+ {
+ int version;
+ int (*ssl_new)(SSL *s);
+ void (*ssl_clear)(SSL *s);
+ void (*ssl_free)(SSL *s);
+ int (*ssl_accept)(SSL *s);
+ int (*ssl_connect)(SSL *s);
+ int (*ssl_read)(SSL *s,void *buf,int len);
+ int (*ssl_peek)(SSL *s,void *buf,int len);
+ int (*ssl_write)(SSL *s,const void *buf,int len);
+ int (*ssl_shutdown)(SSL *s);
+ int (*ssl_renegotiate)(SSL *s);
+ int (*ssl_renegotiate_check)(SSL *s);
+ long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
+ max, int *ok);
+ int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len,
+ int peek);
+ int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
+ int (*ssl_dispatch_alert)(SSL *s);
+ long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
+ long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
+ const SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
+ int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
+ int (*ssl_pending)(const SSL *s);
+ int (*num_ciphers)(void);
+ const SSL_CIPHER *(*get_cipher)(unsigned ncipher);
+ const struct ssl_method_st *(*get_ssl_method)(int version);
+ long (*get_timeout)(void);
+ struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
+ int (*ssl_version)(void);
+ long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void));
+ long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
+ };
+
+/* Lets make this into an ASN.1 type structure as follows
+ * SSL_SESSION_ID ::= SEQUENCE {
+ * version INTEGER, -- structure version number
+ * SSLversion INTEGER, -- SSL version number
+ * Cipher OCTET STRING, -- the 3 byte cipher ID
+ * Session_ID OCTET STRING, -- the Session ID
+ * Master_key OCTET STRING, -- the master key
+ * KRB5_principal OCTET STRING -- optional Kerberos principal
+ * Key_Arg [ 0 ] IMPLICIT OCTET STRING, -- the optional Key argument
+ * Time [ 1 ] EXPLICIT INTEGER, -- optional Start Time
+ * Timeout [ 2 ] EXPLICIT INTEGER, -- optional Timeout ins seconds
+ * Peer [ 3 ] EXPLICIT X509, -- optional Peer Certificate
+ * Session_ID_context [ 4 ] EXPLICIT OCTET STRING, -- the Session ID context
+ * Verify_result [ 5 ] EXPLICIT INTEGER, -- X509_V_... code for `Peer'
+ * HostName [ 6 ] EXPLICIT OCTET STRING, -- optional HostName from servername TLS extension
+ * PSK_identity_hint [ 7 ] EXPLICIT OCTET STRING, -- optional PSK identity hint
+ * PSK_identity [ 8 ] EXPLICIT OCTET STRING, -- optional PSK identity
+ * Ticket_lifetime_hint [9] EXPLICIT INTEGER, -- server's lifetime hint for session ticket
+ * Ticket [10] EXPLICIT OCTET STRING, -- session ticket (clients only)
+ * Compression_meth [11] EXPLICIT OCTET STRING, -- optional compression method
+ * SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username
+ * }
+ * Look in ssl/ssl_asn1.c for more details
+ * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
+ */
+struct ssl_session_st
+ {
+ int ssl_version; /* what ssl version session info is
+ * being kept in here? */
+
+ /* only really used in SSLv2 */
+ unsigned int key_arg_length;
+ unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH];
+ int master_key_length;
+ unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+ /* session_id - valid? */
+ unsigned int session_id_length;
+ unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
+ /* this is used to determine whether the session is being reused in
+ * the appropriate context. It is up to the application to set this,
+ * via SSL_new */
+ unsigned int sid_ctx_length;
+ unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+
+#ifndef OPENSSL_NO_KRB5
+ unsigned int krb5_client_princ_len;
+ unsigned char krb5_client_princ[SSL_MAX_KRB5_PRINCIPAL_LENGTH];
+#endif /* OPENSSL_NO_KRB5 */
+#ifndef OPENSSL_NO_PSK
+ char *psk_identity_hint;
+ char *psk_identity;
+#endif
+ /* Used to indicate that session resumption is not allowed.
+ * Applications can also set this bit for a new session via
+ * not_resumable_session_cb to disable session caching and tickets. */
+ int not_resumable;
+
+ /* The cert is the certificate used to establish this connection */
+ struct sess_cert_st /* SESS_CERT */ *sess_cert;
+
+ /* This is the cert for the other end.
+ * On clients, it will be the same as sess_cert->peer_key->x509
+ * (the latter is not enough as sess_cert is not retained
+ * in the external representation of sessions, see ssl_asn1.c). */
+ X509 *peer;
+ /* when app_verify_callback accepts a session where the peer's certificate
+ * is not ok, we must remember the error for session reuse: */
+ long verify_result; /* only for servers */
+
+ int references;
+ long timeout;
+ long time;
+
+ unsigned int compress_meth; /* Need to lookup the method */
+
+ const SSL_CIPHER *cipher;
+ unsigned long cipher_id; /* when ASN.1 loaded, this
+ * needs to be used to load
+ * the 'cipher' structure */
+
+ STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */
+
+ CRYPTO_EX_DATA ex_data; /* application specific data */
+
+ /* These are used to make removal of session-ids more
+ * efficient and to implement a maximum cache size. */
+ struct ssl_session_st *prev,*next;
+#ifndef OPENSSL_NO_TLSEXT
+ char *tlsext_hostname;
+#ifndef OPENSSL_NO_EC
+ size_t tlsext_ecpointformatlist_length;
+ unsigned char *tlsext_ecpointformatlist; /* peer's list */
+ size_t tlsext_ellipticcurvelist_length;
+ unsigned char *tlsext_ellipticcurvelist; /* peer's list */
+#endif /* OPENSSL_NO_EC */
+ /* RFC4507 info */
+ unsigned char *tlsext_tick; /* Session ticket */
+ size_t tlsext_ticklen; /* Session ticket length */
+ long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */
+#endif
+#ifndef OPENSSL_NO_SRP
+ char *srp_username;
+#endif
+ };
+
+#endif
+
+#define SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001L
+#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002L
+/* Allow initial connection to servers that don't support RI */
+#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L
+#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L
+#define SSL_OP_TLSEXT_PADDING 0x00000010L
+#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L
+#define SSL_OP_SAFARI_ECDHE_ECDSA_BUG 0x00000040L
+#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080L
+#define SSL_OP_TLS_D5_BUG 0x00000100L
+#define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L
+
+/* Hasn't done anything since OpenSSL 0.9.7h, retained for compatibility */
+#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0x0
+/* Refers to ancient SSLREF and SSLv2, retained for compatibility */
+#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x0
+
+/* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added
+ * in OpenSSL 0.9.6d. Usually (depending on the application protocol)
+ * the workaround is not needed. Unfortunately some broken SSL/TLS
+ * implementations cannot handle it at all, which is why we include
+ * it in SSL_OP_ALL. */
+#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800L /* added in 0.9.6e */
+
+/* SSL_OP_ALL: various bug workarounds that should be rather harmless.
+ * This used to be 0x000FFFFFL before 0.9.7. */
+#define SSL_OP_ALL 0x80000BFFL
+
+/* DTLS options */
+#define SSL_OP_NO_QUERY_MTU 0x00001000L
+/* Turn on Cookie Exchange (on relevant for servers) */
+#define SSL_OP_COOKIE_EXCHANGE 0x00002000L
+/* Don't use RFC4507 ticket extension */
+#define SSL_OP_NO_TICKET 0x00004000L
+/* Use Cisco's "speshul" version of DTLS_BAD_VER (as client) */
+#define SSL_OP_CISCO_ANYCONNECT 0x00008000L
+
+/* As server, disallow session resumption on renegotiation */
+#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L
+/* Don't use compression even if supported */
+#define SSL_OP_NO_COMPRESSION 0x00020000L
+/* Permit unsafe legacy renegotiation */
+#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L
+/* If set, always create a new key when using tmp_ecdh parameters */
+#define SSL_OP_SINGLE_ECDH_USE 0x00080000L
+/* If set, always create a new key when using tmp_dh parameters */
+#define SSL_OP_SINGLE_DH_USE 0x00100000L
+/* Set to always use the tmp_rsa key when doing RSA operations,
+ * even when this violates protocol specs */
+#define SSL_OP_EPHEMERAL_RSA 0x00200000L
+/* Set on servers to choose the cipher according to the server's
+ * preferences */
+#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L
+/* If set, a server will allow a client to issue a SSLv3.0 version number
+ * as latest version supported in the premaster secret, even when TLSv1.0
+ * (version 3.1) was announced in the client hello. Normally this is
+ * forbidden to prevent version rollback attacks. */
+#define SSL_OP_TLS_ROLLBACK_BUG 0x00800000L
+
+#define SSL_OP_NO_SSLv2 0x01000000L
+#define SSL_OP_NO_SSLv3 0x02000000L
+#define SSL_OP_NO_TLSv1 0x04000000L
+#define SSL_OP_NO_TLSv1_2 0x08000000L
+#define SSL_OP_NO_TLSv1_1 0x10000000L
+
+/* These next two were never actually used for anything since SSLeay
+ * zap so we have some more flags.
+ */
+/* The next flag deliberately changes the ciphertest, this is a check
+ * for the PKCS#1 attack */
+#define SSL_OP_PKCS1_CHECK_1 0x0
+#define SSL_OP_PKCS1_CHECK_2 0x0
+
+#define SSL_OP_NETSCAPE_CA_DN_BUG 0x20000000L
+#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x40000000L
+/* Make server add server-hello extension from early version of
+ * cryptopro draft, when GOST ciphersuite is negotiated.
+ * Required for interoperability with CryptoPro CSP 3.x
+ */
+#define SSL_OP_CRYPTOPRO_TLSEXT_BUG 0x80000000L
+
+/* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
+ * when just a single record has been written): */
+#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L
+/* Make it possible to retry SSL_write() with changed buffer location
+ * (buffer contents must stay the same!); this is not the default to avoid
+ * the misconception that non-blocking SSL_write() behaves like
+ * non-blocking write(): */
+#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
+/* Never bother the application with retries if the transport
+ * is blocking: */
+#define SSL_MODE_AUTO_RETRY 0x00000004L
+/* Don't attempt to automatically build certificate chain */
+#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
+/* Save RAM by releasing read and write buffers when they're empty. (SSL3 and
+ * TLS only.) "Released" buffers are put onto a free-list in the context
+ * or just freed (depending on the context's setting for freelist_max_len). */
+#define SSL_MODE_RELEASE_BUFFERS 0x00000010L
+/* Send the current time in the Random fields of the ClientHello and
+ * ServerHello records for compatibility with hypothetical implementations
+ * that require it.
+ */
+#define SSL_MODE_SEND_CLIENTHELLO_TIME 0x00000020L
+#define SSL_MODE_SEND_SERVERHELLO_TIME 0x00000040L
+
+/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
+ * they cannot be used to clear bits. */
+
+#define SSL_CTX_set_options(ctx,op) \
+ SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
+#define SSL_CTX_clear_options(ctx,op) \
+ SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
+#define SSL_CTX_get_options(ctx) \
+ SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
+#define SSL_set_options(ssl,op) \
+ SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL)
+#define SSL_clear_options(ssl,op) \
+ SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
+#define SSL_get_options(ssl) \
+ SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL)
+
+#define SSL_CTX_set_mode(ctx,op) \
+ SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
+#define SSL_CTX_clear_mode(ctx,op) \
+ SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL)
+#define SSL_CTX_get_mode(ctx) \
+ SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL)
+#define SSL_clear_mode(ssl,op) \
+ SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL)
+#define SSL_set_mode(ssl,op) \
+ SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
+#define SSL_get_mode(ssl) \
+ SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL)
+#define SSL_set_mtu(ssl, mtu) \
+ SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL)
+
+#define SSL_get_secure_renegotiation_support(ssl) \
+ SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL)
+
+#ifndef OPENSSL_NO_HEARTBEATS
+#define SSL_heartbeat(ssl) \
+ SSL_ctrl((ssl),SSL_CTRL_TLS_EXT_SEND_HEARTBEAT,0,NULL)
+#endif
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
+void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
+#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
+#define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
+
+#ifndef OPENSSL_NO_SRP
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+typedef struct srp_ctx_st
+ {
+ /* param for all the callbacks */
+ void *SRP_cb_arg;
+ /* set client Hello login callback */
+ int (*TLS_ext_srp_username_callback)(SSL *, int *, void *);
+ /* set SRP N/g param callback for verification */
+ int (*SRP_verify_param_callback)(SSL *, void *);
+ /* set SRP client passwd callback */
+ char *(*SRP_give_srp_client_pwd_callback)(SSL *, void *);
+
+ char *login;
+ BIGNUM *N,*g,*s,*B,*A;
+ BIGNUM *a,*b,*v;
+ char *info;
+ int strength;
+
+ unsigned long srp_Mask;
+ } SRP_CTX;
+
+#endif
+
+/* see tls_srp.c */
+int SSL_SRP_CTX_init(SSL *s);
+int SSL_CTX_SRP_CTX_init(SSL_CTX *ctx);
+int SSL_SRP_CTX_free(SSL *ctx);
+int SSL_CTX_SRP_CTX_free(SSL_CTX *ctx);
+int SSL_srp_server_param_with_username(SSL *s, int *ad);
+int SRP_generate_server_master_secret(SSL *s,unsigned char *master_key);
+int SRP_Calc_A_param(SSL *s);
+int SRP_generate_client_master_secret(SSL *s,unsigned char *master_key);
+
+#endif
+
+#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)
+#define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */
+#else
+#define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */
+#endif
+
+#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024*20)
+
+/* This callback type is used inside SSL_CTX, SSL, and in the functions that set
+ * them. It is used to override the generation of SSL/TLS session IDs in a
+ * server. Return value should be zero on an error, non-zero to proceed. Also,
+ * callbacks should themselves check if the id they generate is unique otherwise
+ * the SSL handshake will fail with an error - callbacks can do this using the
+ * 'ssl' value they're passed by;
+ * SSL_has_matching_session_id(ssl, id, *id_len)
+ * The length value passed in is set at the maximum size the session ID can be.
+ * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback
+ * can alter this length to be less if desired, but under SSLv2 session IDs are
+ * supposed to be fixed at 16 bytes so the id will be padded after the callback
+ * returns in this case. It is also an error for the callback to set the size to
+ * zero. */
+typedef int (*GEN_SESSION_CB)(const SSL *ssl, unsigned char *id,
+ unsigned int *id_len);
+
+typedef struct ssl_comp_st SSL_COMP;
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+struct ssl_comp_st
+ {
+ int id;
+ const char *name;
+#ifndef OPENSSL_NO_COMP
+ COMP_METHOD *method;
+#else
+ char *method;
+#endif
+ };
+
+DECLARE_STACK_OF(SSL_COMP)
+DECLARE_LHASH_OF(SSL_SESSION);
+
+struct ssl_ctx_st
+ {
+ const SSL_METHOD *method;
+
+ STACK_OF(SSL_CIPHER) *cipher_list;
+ /* same as above but sorted for lookup */
+ STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+
+ struct x509_store_st /* X509_STORE */ *cert_store;
+ LHASH_OF(SSL_SESSION) *sessions;
+ /* Most session-ids that will be cached, default is
+ * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */
+ unsigned long session_cache_size;
+ struct ssl_session_st *session_cache_head;
+ struct ssl_session_st *session_cache_tail;
+
+ /* This can have one of 2 values, ored together,
+ * SSL_SESS_CACHE_CLIENT,
+ * SSL_SESS_CACHE_SERVER,
+ * Default is SSL_SESSION_CACHE_SERVER, which means only
+ * SSL_accept which cache SSL_SESSIONS. */
+ int session_cache_mode;
+
+ /* If timeout is not 0, it is the default timeout value set
+ * when SSL_new() is called. This has been put in to make
+ * life easier to set things up */
+ long session_timeout;
+
+ /* If this callback is not null, it will be called each
+ * time a session id is added to the cache. If this function
+ * returns 1, it means that the callback will do a
+ * SSL_SESSION_free() when it has finished using it. Otherwise,
+ * on 0, it means the callback has finished with it.
+ * If remove_session_cb is not null, it will be called when
+ * a session-id is removed from the cache. After the call,
+ * OpenSSL will SSL_SESSION_free() it. */
+ int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess);
+ void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess);
+ SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl,
+ unsigned char *data,int len,int *copy);
+
+ struct
+ {
+ int sess_connect; /* SSL new conn - started */
+ int sess_connect_renegotiate;/* SSL reneg - requested */
+ int sess_connect_good; /* SSL new conne/reneg - finished */
+ int sess_accept; /* SSL new accept - started */
+ int sess_accept_renegotiate;/* SSL reneg - requested */
+ int sess_accept_good; /* SSL accept/reneg - finished */
+ int sess_miss; /* session lookup misses */
+ int sess_timeout; /* reuse attempt on timeouted session */
+ int sess_cache_full; /* session removed due to full cache */
+ int sess_hit; /* session reuse actually done */
+ int sess_cb_hit; /* session-id that was not
+ * in the cache was
+ * passed back via the callback. This
+ * indicates that the application is
+ * supplying session-id's from other
+ * processes - spooky :-) */
+ } stats;
+
+ int references;
+
+ /* if defined, these override the X509_verify_cert() calls */
+ int (*app_verify_callback)(X509_STORE_CTX *, void *);
+ void *app_verify_arg;
+ /* before OpenSSL 0.9.7, 'app_verify_arg' was ignored
+ * ('app_verify_callback' was called with just one argument) */
+
+ /* Default password callback. */
+ pem_password_cb *default_passwd_callback;
+
+ /* Default password callback user data. */
+ void *default_passwd_callback_userdata;
+
+ /* get client cert callback */
+ int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
+
+ /* cookie generate callback */
+ int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie,
+ unsigned int *cookie_len);
+
+ /* verify cookie callback */
+ int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie,
+ unsigned int cookie_len);
+
+ CRYPTO_EX_DATA ex_data;
+
+ const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */
+ const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */
+ const EVP_MD *sha1; /* For SSLv3/TLSv1 'ssl3->sha1' */
+
+ STACK_OF(X509) *extra_certs;
+ STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */
+
+
+ /* Default values used when no per-SSL value is defined follow */
+
+ void (*info_callback)(const SSL *ssl,int type,int val); /* used if SSL's info_callback is NULL */
+
+ /* what we put in client cert requests */
+ STACK_OF(X509_NAME) *client_CA;
+
+
+ /* Default values to use in SSL structures follow (these are copied by SSL_new) */
+
+ unsigned long options;
+ unsigned long mode;
+ long max_cert_list;
+
+ struct cert_st /* CERT */ *cert;
+ int read_ahead;
+
+ /* callback that allows applications to peek at protocol messages */
+ void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
+ void *msg_callback_arg;
+
+ int verify_mode;
+ unsigned int sid_ctx_length;
+ unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+ int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */
+
+ /* Default generate session ID callback. */
+ GEN_SESSION_CB generate_session_id;
+
+ X509_VERIFY_PARAM *param;
+
+#if 0
+ int purpose; /* Purpose setting */
+ int trust; /* Trust setting */
+#endif
+
+ int quiet_shutdown;
+
+ /* Maximum amount of data to send in one fragment.
+ * actual record size can be more than this due to
+ * padding and MAC overheads.
+ */
+ unsigned int max_send_fragment;
+
+#ifndef OPENSSL_NO_ENGINE
+ /* Engine to pass requests for client certs to
+ */
+ ENGINE *client_cert_engine;
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+ /* TLS extensions servername callback */
+ int (*tlsext_servername_callback)(SSL*, int *, void *);
+ void *tlsext_servername_arg;
+ /* RFC 4507 session ticket keys */
+ unsigned char tlsext_tick_key_name[16];
+ unsigned char tlsext_tick_hmac_key[16];
+ unsigned char tlsext_tick_aes_key[16];
+ /* Callback to support customisation of ticket key setting */
+ int (*tlsext_ticket_key_cb)(SSL *ssl,
+ unsigned char *name, unsigned char *iv,
+ EVP_CIPHER_CTX *ectx,
+ HMAC_CTX *hctx, int enc);
+
+ /* certificate status request info */
+ /* Callback for status request */
+ int (*tlsext_status_cb)(SSL *ssl, void *arg);
+ void *tlsext_status_arg;
+
+ /* draft-rescorla-tls-opaque-prf-input-00.txt information */
+ int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg);
+ void *tlsext_opaque_prf_input_callback_arg;
+#endif
+
+#ifndef OPENSSL_NO_PSK
+ char *psk_identity_hint;
+ unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
+ unsigned int max_identity_len, unsigned char *psk,
+ unsigned int max_psk_len);
+ unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len);
+#endif
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+#define SSL_MAX_BUF_FREELIST_LEN_DEFAULT 32
+ unsigned int freelist_max_len;
+ struct ssl3_buf_freelist_st *wbuf_freelist;
+ struct ssl3_buf_freelist_st *rbuf_freelist;
+#endif
+#ifndef OPENSSL_NO_SRP
+ SRP_CTX srp_ctx; /* ctx for SRP authentication */
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ /* Next protocol negotiation information */
+ /* (for experimental NPN extension). */
+
+ /* For a server, this contains a callback function by which the set of
+ * advertised protocols can be provided. */
+ int (*next_protos_advertised_cb)(SSL *s, const unsigned char **buf,
+ unsigned int *len, void *arg);
+ void *next_protos_advertised_cb_arg;
+ /* For a client, this contains a callback function that selects the
+ * next protocol from the list provided by the server. */
+ int (*next_proto_select_cb)(SSL *s, unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen,
+ void *arg);
+ void *next_proto_select_cb_arg;
+# endif
+ /* SRTP profiles we are willing to do from RFC 5764 */
+ STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
+#endif
+ };
+
+#endif
+
+#define SSL_SESS_CACHE_OFF 0x0000
+#define SSL_SESS_CACHE_CLIENT 0x0001
+#define SSL_SESS_CACHE_SERVER 0x0002
+#define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER)
+#define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080
+/* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */
+#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100
+#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200
+#define SSL_SESS_CACHE_NO_INTERNAL \
+ (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE)
+
+LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx);
+#define SSL_CTX_sess_number(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL)
+#define SSL_CTX_sess_connect(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL)
+#define SSL_CTX_sess_connect_good(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL)
+#define SSL_CTX_sess_connect_renegotiate(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL)
+#define SSL_CTX_sess_accept(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL)
+#define SSL_CTX_sess_accept_renegotiate(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL)
+#define SSL_CTX_sess_accept_good(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL)
+#define SSL_CTX_sess_hits(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL)
+#define SSL_CTX_sess_cb_hits(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL)
+#define SSL_CTX_sess_misses(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL)
+#define SSL_CTX_sess_timeouts(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL)
+#define SSL_CTX_sess_cache_full(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL)
+
+void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess));
+int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(struct ssl_st *ssl, SSL_SESSION *sess);
+void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess));
+void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(struct ssl_ctx_st *ctx, SSL_SESSION *sess);
+void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, unsigned char *data,int len,int *copy));
+SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(struct ssl_st *ssl, unsigned char *Data, int len, int *copy);
+void SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb)(const SSL *ssl,int type,int val));
+void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val);
+void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey));
+int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
+#ifndef OPENSSL_NO_ENGINE
+int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e);
+#endif
+void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len));
+void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len));
+#ifndef OPENSSL_NO_NEXTPROTONEG
+void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s,
+ int (*cb) (SSL *ssl,
+ const unsigned char **out,
+ unsigned int *outlen,
+ void *arg),
+ void *arg);
+void SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
+ int (*cb) (SSL *ssl,
+ unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen,
+ void *arg),
+ void *arg);
+
+int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen,
+ const unsigned char *client, unsigned int client_len);
+void SSL_get0_next_proto_negotiated(const SSL *s,
+ const unsigned char **data, unsigned *len);
+
+#define OPENSSL_NPN_UNSUPPORTED 0
+#define OPENSSL_NPN_NEGOTIATED 1
+#define OPENSSL_NPN_NO_OVERLAP 2
+#endif
+
+#ifndef OPENSSL_NO_PSK
+/* the maximum length of the buffer given to callbacks containing the
+ * resulting identity/psk */
+#define PSK_MAX_IDENTITY_LEN 128
+#define PSK_MAX_PSK_LEN 256
+void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx,
+ unsigned int (*psk_client_callback)(SSL *ssl, const char *hint,
+ char *identity, unsigned int max_identity_len, unsigned char *psk,
+ unsigned int max_psk_len));
+void SSL_set_psk_client_callback(SSL *ssl,
+ unsigned int (*psk_client_callback)(SSL *ssl, const char *hint,
+ char *identity, unsigned int max_identity_len, unsigned char *psk,
+ unsigned int max_psk_len));
+void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx,
+ unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len));
+void SSL_set_psk_server_callback(SSL *ssl,
+ unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len));
+int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint);
+int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint);
+const char *SSL_get_psk_identity_hint(const SSL *s);
+const char *SSL_get_psk_identity(const SSL *s);
+#endif
+
+#define SSL_NOTHING 1
+#define SSL_WRITING 2
+#define SSL_READING 3
+#define SSL_X509_LOOKUP 4
+
+/* These will only be used when doing non-blocking IO */
+#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING)
+#define SSL_want_read(s) (SSL_want(s) == SSL_READING)
+#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING)
+#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP)
+
+#define SSL_MAC_FLAG_READ_MAC_STREAM 1
+#define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+struct ssl_st
+ {
+ /* protocol version
+ * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
+ */
+ int version;
+ int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
+
+ const SSL_METHOD *method; /* SSLv3 */
+
+ /* There are 2 BIO's even though they are normally both the
+ * same. This is so data can be read and written to different
+ * handlers */
+
+#ifndef OPENSSL_NO_BIO
+ BIO *rbio; /* used by SSL_read */
+ BIO *wbio; /* used by SSL_write */
+ BIO *bbio; /* used during session-id reuse to concatenate
+ * messages */
+#else
+ char *rbio; /* used by SSL_read */
+ char *wbio; /* used by SSL_write */
+ char *bbio;
+#endif
+ /* This holds a variable that indicates what we were doing
+ * when a 0 or -1 is returned. This is needed for
+ * non-blocking IO so we know what request needs re-doing when
+ * in SSL_accept or SSL_connect */
+ int rwstate;
+
+ /* true when we are actually in SSL_accept() or SSL_connect() */
+ int in_handshake;
+ int (*handshake_func)(SSL *);
+
+ /* Imagine that here's a boolean member "init" that is
+ * switched as soon as SSL_set_{accept/connect}_state
+ * is called for the first time, so that "state" and
+ * "handshake_func" are properly initialized. But as
+ * handshake_func is == 0 until then, we use this
+ * test instead of an "init" member.
+ */
+
+ int server; /* are we the server side? - mostly used by SSL_clear*/
+
+ int new_session;/* Generate a new session or reuse an old one.
+ * NB: For servers, the 'new' session may actually be a previously
+ * cached session or even the previous session unless
+ * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
+ int quiet_shutdown;/* don't send shutdown packets */
+ int shutdown; /* we have shut things down, 0x01 sent, 0x02
+ * for received */
+ int state; /* where we are */
+ int rstate; /* where we are when reading */
+
+ BUF_MEM *init_buf; /* buffer used during init */
+ void *init_msg; /* pointer to handshake message body, set by ssl3_get_message() */
+ int init_num; /* amount read/written */
+ int init_off; /* amount read/written */
+
+ /* used internally to point at a raw packet */
+ unsigned char *packet;
+ unsigned int packet_length;
+
+ struct ssl2_state_st *s2; /* SSLv2 variables */
+ struct ssl3_state_st *s3; /* SSLv3 variables */
+ struct dtls1_state_st *d1; /* DTLSv1 variables */
+
+ int read_ahead; /* Read as many input bytes as possible
+ * (for non-blocking reads) */
+
+ /* callback that allows applications to peek at protocol messages */
+ void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
+ void *msg_callback_arg;
+
+ int hit; /* reusing a previous session */
+
+ X509_VERIFY_PARAM *param;
+
+#if 0
+ int purpose; /* Purpose setting */
+ int trust; /* Trust setting */
+#endif
+
+ /* crypto */
+ STACK_OF(SSL_CIPHER) *cipher_list;
+ STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+
+ /* These are the ones being used, the ones in SSL_SESSION are
+ * the ones to be 'copied' into these ones */
+ int mac_flags;
+ EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
+ EVP_MD_CTX *read_hash; /* used for mac generation */
+#ifndef OPENSSL_NO_COMP
+ COMP_CTX *expand; /* uncompress */
+#else
+ char *expand;
+#endif
+
+ EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
+ EVP_MD_CTX *write_hash; /* used for mac generation */
+#ifndef OPENSSL_NO_COMP
+ COMP_CTX *compress; /* compression */
+#else
+ char *compress;
+#endif
+
+ /* session info */
+
+ /* client cert? */
+ /* This is used to hold the server certificate used */
+ struct cert_st /* CERT */ *cert;
+
+ /* the session_id_context is used to ensure sessions are only reused
+ * in the appropriate context */
+ unsigned int sid_ctx_length;
+ unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+
+ /* This can also be in the session once a session is established */
+ SSL_SESSION *session;
+
+ /* Default generate session ID callback. */
+ GEN_SESSION_CB generate_session_id;
+
+ /* Used in SSL2 and SSL3 */
+ int verify_mode; /* 0 don't care about verify failure.
+ * 1 fail if verify fails */
+ int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */
+
+ void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */
+
+ int error; /* error bytes to be written */
+ int error_code; /* actual code */
+
+#ifndef OPENSSL_NO_KRB5
+ KSSL_CTX *kssl_ctx; /* Kerberos 5 context */
+#endif /* OPENSSL_NO_KRB5 */
+
+#ifndef OPENSSL_NO_PSK
+ unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
+ unsigned int max_identity_len, unsigned char *psk,
+ unsigned int max_psk_len);
+ unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len);
+#endif
+
+ SSL_CTX *ctx;
+ /* set this flag to 1 and a sleep(1) is put into all SSL_read()
+ * and SSL_write() calls, good for nbio debuging :-) */
+ int debug;
+
+ /* extra application data */
+ long verify_result;
+ CRYPTO_EX_DATA ex_data;
+
+ /* for server side, keep the list of CA_dn we can use */
+ STACK_OF(X509_NAME) *client_CA;
+
+ int references;
+ unsigned long options; /* protocol behaviour */
+ unsigned long mode; /* API behaviour */
+ long max_cert_list;
+ int first_packet;
+ int client_version; /* what was passed, used for
+ * SSLv3/TLS rollback check */
+ unsigned int max_send_fragment;
+#ifndef OPENSSL_NO_TLSEXT
+ /* TLS extension debug callback */
+ void (*tlsext_debug_cb)(SSL *s, int client_server, int type,
+ unsigned char *data, int len,
+ void *arg);
+ void *tlsext_debug_arg;
+ char *tlsext_hostname;
+ int servername_done; /* no further mod of servername
+ 0 : call the servername extension callback.
+ 1 : prepare 2, allow last ack just after in server callback.
+ 2 : don't call servername callback, no ack in server hello
+ */
+ /* certificate status request info */
+ /* Status type or -1 if no status type */
+ int tlsext_status_type;
+ /* Expect OCSP CertificateStatus message */
+ int tlsext_status_expected;
+ /* OCSP status request only */
+ STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
+ X509_EXTENSIONS *tlsext_ocsp_exts;
+ /* OCSP response received or to be sent */
+ unsigned char *tlsext_ocsp_resp;
+ int tlsext_ocsp_resplen;
+
+ /* RFC4507 session ticket expected to be received or sent */
+ int tlsext_ticket_expected;
+#ifndef OPENSSL_NO_EC
+ size_t tlsext_ecpointformatlist_length;
+ unsigned char *tlsext_ecpointformatlist; /* our list */
+ size_t tlsext_ellipticcurvelist_length;
+ unsigned char *tlsext_ellipticcurvelist; /* our list */
+#endif /* OPENSSL_NO_EC */
+
+ /* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */
+ void *tlsext_opaque_prf_input;
+ size_t tlsext_opaque_prf_input_len;
+
+ /* TLS Session Ticket extension override */
+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
+
+ /* TLS Session Ticket extension callback */
+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
+ void *tls_session_ticket_ext_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
+
+ SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ /* Next protocol negotiation. For the client, this is the protocol that
+ * we sent in NextProtocol and is set when handling ServerHello
+ * extensions.
+ *
+ * For a server, this is the client's selected_protocol from
+ * NextProtocol and is set when handling the NextProtocol message,
+ * before the Finished message. */
+ unsigned char *next_proto_negotiated;
+ unsigned char next_proto_negotiated_len;
+#endif
+
+#define session_ctx initial_ctx
+
+ STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; /* What we'll do */
+ SRTP_PROTECTION_PROFILE *srtp_profile; /* What's been chosen */
+
+ unsigned int tlsext_heartbeat; /* Is use of the Heartbeat extension negotiated?
+ 0: disabled
+ 1: enabled
+ 2: enabled, but not allowed to send Requests
+ */
+ unsigned int tlsext_hb_pending; /* Indicates if a HeartbeatRequest is in flight */
+ unsigned int tlsext_hb_seq; /* HeartbeatRequest sequence number */
+#else
+#define session_ctx ctx
+#endif /* OPENSSL_NO_TLSEXT */
+
+ int renegotiate;/* 1 if we are renegotiating.
+ * 2 if we are a server and are inside a handshake
+ * (i.e. not just sending a HelloRequest) */
+
+#ifndef OPENSSL_NO_SRP
+ SRP_CTX srp_ctx; /* ctx for SRP authentication */
+#endif
+ };
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <openssl/ssl2.h>
+#include <openssl/ssl3.h>
+#include <openssl/tls1.h> /* This is mostly sslv3 with a few tweaks */
+#include <openssl/dtls1.h> /* Datagram TLS */
+#include <openssl/ssl23.h>
+#include <openssl/srtp.h> /* Support for the use_srtp extension */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* compatibility */
+#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
+#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
+#define SSL_SESSION_set_app_data(s,a) (SSL_SESSION_set_ex_data(s,0,(char *)a))
+#define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s,0))
+#define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx,0))
+#define SSL_CTX_set_app_data(ctx,arg) (SSL_CTX_set_ex_data(ctx,0,(char *)arg))
+
+/* The following are the possible values for ssl->state are are
+ * used to indicate where we are up to in the SSL connection establishment.
+ * The macros that follow are about the only things you should need to use
+ * and even then, only when using non-blocking IO.
+ * It can also be useful to work out where you were when the connection
+ * failed */
+
+#define SSL_ST_CONNECT 0x1000
+#define SSL_ST_ACCEPT 0x2000
+#define SSL_ST_MASK 0x0FFF
+#define SSL_ST_INIT (SSL_ST_CONNECT|SSL_ST_ACCEPT)
+#define SSL_ST_BEFORE 0x4000
+#define SSL_ST_OK 0x03
+#define SSL_ST_RENEGOTIATE (0x04|SSL_ST_INIT)
+
+#define SSL_CB_LOOP 0x01
+#define SSL_CB_EXIT 0x02
+#define SSL_CB_READ 0x04
+#define SSL_CB_WRITE 0x08
+#define SSL_CB_ALERT 0x4000 /* used in callback */
+#define SSL_CB_READ_ALERT (SSL_CB_ALERT|SSL_CB_READ)
+#define SSL_CB_WRITE_ALERT (SSL_CB_ALERT|SSL_CB_WRITE)
+#define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT|SSL_CB_LOOP)
+#define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT|SSL_CB_EXIT)
+#define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT|SSL_CB_LOOP)
+#define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT|SSL_CB_EXIT)
+#define SSL_CB_HANDSHAKE_START 0x10
+#define SSL_CB_HANDSHAKE_DONE 0x20
+
+/* Is the SSL_connection established? */
+#define SSL_get_state(a) SSL_state(a)
+#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK)
+#define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT)
+#define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE)
+#define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT)
+#define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT)
+
+/* The following 2 states are kept in ssl->rstate when reads fail,
+ * you should not need these */
+#define SSL_ST_READ_HEADER 0xF0
+#define SSL_ST_READ_BODY 0xF1
+#define SSL_ST_READ_DONE 0xF2
+
+/* Obtain latest Finished message
+ * -- that we sent (SSL_get_finished)
+ * -- that we expected from peer (SSL_get_peer_finished).
+ * Returns length (0 == no Finished so far), copies up to 'count' bytes. */
+size_t SSL_get_finished(const SSL *s, void *buf, size_t count);
+size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
+
+/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options
+ * are 'ored' with SSL_VERIFY_PEER if they are desired */
+#define SSL_VERIFY_NONE 0x00
+#define SSL_VERIFY_PEER 0x01
+#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
+#define SSL_VERIFY_CLIENT_ONCE 0x04
+
+#define OpenSSL_add_ssl_algorithms() SSL_library_init()
+#define SSLeay_add_ssl_algorithms() SSL_library_init()
+
+/* this is for backward compatibility */
+#if 0 /* NEW_SSLEAY */
+#define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c)
+#define SSL_set_pref_cipher(c,n) SSL_set_cipher_list(c,n)
+#define SSL_add_session(a,b) SSL_CTX_add_session((a),(b))
+#define SSL_remove_session(a,b) SSL_CTX_remove_session((a),(b))
+#define SSL_flush_sessions(a,b) SSL_CTX_flush_sessions((a),(b))
+#endif
+/* More backward compatibility */
+#define SSL_get_cipher(s) \
+ SSL_CIPHER_get_name(SSL_get_current_cipher(s))
+#define SSL_get_cipher_bits(s,np) \
+ SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np)
+#define SSL_get_cipher_version(s) \
+ SSL_CIPHER_get_version(SSL_get_current_cipher(s))
+#define SSL_get_cipher_name(s) \
+ SSL_CIPHER_get_name(SSL_get_current_cipher(s))
+#define SSL_get_time(a) SSL_SESSION_get_time(a)
+#define SSL_set_time(a,b) SSL_SESSION_set_time((a),(b))
+#define SSL_get_timeout(a) SSL_SESSION_get_timeout(a)
+#define SSL_set_timeout(a,b) SSL_SESSION_set_timeout((a),(b))
+
+#define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id)
+#define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id)
+
+DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
+
+#define SSL_AD_REASON_OFFSET 1000 /* offset to get SSL_R_... value from SSL_AD_... */
+
+/* These alert types are for SSLv3 and TLSv1 */
+#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY
+#define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE /* fatal */
+#define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC /* fatal */
+#define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED
+#define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW
+#define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE/* fatal */
+#define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE/* fatal */
+#define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE /* Not for TLS */
+#define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE
+#define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE
+#define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED
+#define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED
+#define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN
+#define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER /* fatal */
+#define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA /* fatal */
+#define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED /* fatal */
+#define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR /* fatal */
+#define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR
+#define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION/* fatal */
+#define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION /* fatal */
+#define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY/* fatal */
+#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR /* fatal */
+#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED
+#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION
+#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION
+#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
+#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME
+#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE
+#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE
+#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */
+
+#define SSL_ERROR_NONE 0
+#define SSL_ERROR_SSL 1
+#define SSL_ERROR_WANT_READ 2
+#define SSL_ERROR_WANT_WRITE 3
+#define SSL_ERROR_WANT_X509_LOOKUP 4
+#define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */
+#define SSL_ERROR_ZERO_RETURN 6
+#define SSL_ERROR_WANT_CONNECT 7
+#define SSL_ERROR_WANT_ACCEPT 8
+
+#define SSL_CTRL_NEED_TMP_RSA 1
+#define SSL_CTRL_SET_TMP_RSA 2
+#define SSL_CTRL_SET_TMP_DH 3
+#define SSL_CTRL_SET_TMP_ECDH 4
+#define SSL_CTRL_SET_TMP_RSA_CB 5
+#define SSL_CTRL_SET_TMP_DH_CB 6
+#define SSL_CTRL_SET_TMP_ECDH_CB 7
+
+#define SSL_CTRL_GET_SESSION_REUSED 8
+#define SSL_CTRL_GET_CLIENT_CERT_REQUEST 9
+#define SSL_CTRL_GET_NUM_RENEGOTIATIONS 10
+#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11
+#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12
+#define SSL_CTRL_GET_FLAGS 13
+#define SSL_CTRL_EXTRA_CHAIN_CERT 14
+
+#define SSL_CTRL_SET_MSG_CALLBACK 15
+#define SSL_CTRL_SET_MSG_CALLBACK_ARG 16
+
+/* only applies to datagram connections */
+#define SSL_CTRL_SET_MTU 17
+/* Stats */
+#define SSL_CTRL_SESS_NUMBER 20
+#define SSL_CTRL_SESS_CONNECT 21
+#define SSL_CTRL_SESS_CONNECT_GOOD 22
+#define SSL_CTRL_SESS_CONNECT_RENEGOTIATE 23
+#define SSL_CTRL_SESS_ACCEPT 24
+#define SSL_CTRL_SESS_ACCEPT_GOOD 25
+#define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE 26
+#define SSL_CTRL_SESS_HIT 27
+#define SSL_CTRL_SESS_CB_HIT 28
+#define SSL_CTRL_SESS_MISSES 29
+#define SSL_CTRL_SESS_TIMEOUTS 30
+#define SSL_CTRL_SESS_CACHE_FULL 31
+#define SSL_CTRL_OPTIONS 32
+#define SSL_CTRL_MODE 33
+
+#define SSL_CTRL_GET_READ_AHEAD 40
+#define SSL_CTRL_SET_READ_AHEAD 41
+#define SSL_CTRL_SET_SESS_CACHE_SIZE 42
+#define SSL_CTRL_GET_SESS_CACHE_SIZE 43
+#define SSL_CTRL_SET_SESS_CACHE_MODE 44
+#define SSL_CTRL_GET_SESS_CACHE_MODE 45
+
+#define SSL_CTRL_GET_MAX_CERT_LIST 50
+#define SSL_CTRL_SET_MAX_CERT_LIST 51
+
+#define SSL_CTRL_SET_MAX_SEND_FRAGMENT 52
+
+/* see tls1.h for macros based on these */
+#ifndef OPENSSL_NO_TLSEXT
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
+#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
+#define SSL_CTRL_SET_TLSEXT_DEBUG_CB 56
+#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57
+#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58
+#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71
+
+#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72
+
+#define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB 75
+#define SSL_CTRL_SET_SRP_VERIFY_PARAM_CB 76
+#define SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB 77
+
+#define SSL_CTRL_SET_SRP_ARG 78
+#define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME 79
+#define SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH 80
+#define SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD 81
+#ifndef OPENSSL_NO_HEARTBEATS
+#define SSL_CTRL_TLS_EXT_SEND_HEARTBEAT 85
+#define SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING 86
+#define SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS 87
+#endif
+#endif
+
+#define DTLS_CTRL_GET_TIMEOUT 73
+#define DTLS_CTRL_HANDLE_TIMEOUT 74
+#define DTLS_CTRL_LISTEN 75
+
+#define SSL_CTRL_GET_RI_SUPPORT 76
+#define SSL_CTRL_CLEAR_OPTIONS 77
+#define SSL_CTRL_CLEAR_MODE 78
+
+#define SSL_CTRL_GET_EXTRA_CHAIN_CERTS 82
+#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS 83
+
+#define DTLSv1_get_timeout(ssl, arg) \
+ SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
+#define DTLSv1_handle_timeout(ssl) \
+ SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL)
+#define DTLSv1_listen(ssl, peer) \
+ SSL_ctrl(ssl,DTLS_CTRL_LISTEN,0, (void *)peer)
+
+#define SSL_session_reused(ssl) \
+ SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
+#define SSL_num_renegotiations(ssl) \
+ SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL)
+#define SSL_clear_num_renegotiations(ssl) \
+ SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL)
+#define SSL_total_renegotiations(ssl) \
+ SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL)
+
+#define SSL_CTX_need_tmp_RSA(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_NEED_TMP_RSA,0,NULL)
+#define SSL_CTX_set_tmp_rsa(ctx,rsa) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
+#define SSL_CTX_set_tmp_dh(ctx,dh) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
+#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
+
+#define SSL_need_tmp_RSA(ssl) \
+ SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL)
+#define SSL_set_tmp_rsa(ssl,rsa) \
+ SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
+#define SSL_set_tmp_dh(ssl,dh) \
+ SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
+#define SSL_set_tmp_ecdh(ssl,ecdh) \
+ SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
+
+#define SSL_CTX_add_extra_chain_cert(ctx,x509) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
+#define SSL_CTX_get_extra_chain_certs(ctx,px509) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_EXTRA_CHAIN_CERTS,0,px509)
+#define SSL_CTX_clear_extra_chain_certs(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS,0,NULL)
+
+#ifndef OPENSSL_NO_BIO
+BIO_METHOD *BIO_f_ssl(void);
+BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
+BIO *BIO_new_ssl_connect(SSL_CTX *ctx);
+BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx);
+int BIO_ssl_copy_session_id(BIO *to,BIO *from);
+void BIO_ssl_shutdown(BIO *ssl_bio);
+
+#endif
+
+int SSL_CTX_set_cipher_list(SSL_CTX *,const char *str);
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth);
+void SSL_CTX_free(SSL_CTX *);
+long SSL_CTX_set_timeout(SSL_CTX *ctx,long t);
+long SSL_CTX_get_timeout(const SSL_CTX *ctx);
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *);
+void SSL_CTX_set_cert_store(SSL_CTX *,X509_STORE *);
+int SSL_want(const SSL *s);
+int SSL_clear(SSL *s);
+
+void SSL_CTX_flush_sessions(SSL_CTX *ctx,long tm);
+
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *s);
+int SSL_CIPHER_get_bits(const SSL_CIPHER *c,int *alg_bits);
+char * SSL_CIPHER_get_version(const SSL_CIPHER *c);
+const char * SSL_CIPHER_get_name(const SSL_CIPHER *c);
+unsigned long SSL_CIPHER_get_id(const SSL_CIPHER *c);
+
+int SSL_get_fd(const SSL *s);
+int SSL_get_rfd(const SSL *s);
+int SSL_get_wfd(const SSL *s);
+const char * SSL_get_cipher_list(const SSL *s,int n);
+char * SSL_get_shared_ciphers(const SSL *s, char *buf, int len);
+int SSL_get_read_ahead(const SSL * s);
+int SSL_pending(const SSL *s);
+#ifndef OPENSSL_NO_SOCK
+int SSL_set_fd(SSL *s, int fd);
+int SSL_set_rfd(SSL *s, int fd);
+int SSL_set_wfd(SSL *s, int fd);
+#endif
+#ifndef OPENSSL_NO_BIO
+void SSL_set_bio(SSL *s, BIO *rbio,BIO *wbio);
+BIO * SSL_get_rbio(const SSL *s);
+BIO * SSL_get_wbio(const SSL *s);
+#endif
+int SSL_set_cipher_list(SSL *s, const char *str);
+void SSL_set_read_ahead(SSL *s, int yes);
+int SSL_get_verify_mode(const SSL *s);
+int SSL_get_verify_depth(const SSL *s);
+int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *);
+void SSL_set_verify(SSL *s, int mode,
+ int (*callback)(int ok,X509_STORE_CTX *ctx));
+void SSL_set_verify_depth(SSL *s, int depth);
+#ifndef OPENSSL_NO_RSA
+int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa);
+#endif
+int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len);
+int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey);
+int SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len);
+int SSL_use_certificate(SSL *ssl, X509 *x);
+int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
+int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type);
+int SSL_use_certificate_file(SSL *ssl, const char *file, int type);
+int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type);
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
+int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); /* PEM type */
+STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file);
+int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
+ const char *file);
+#ifndef OPENSSL_SYS_VMS
+#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! [was: #ifndef MAC_OS_pre_X] */
+int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
+ const char *dir);
+#endif
+#endif
+
+#endif
+
+void SSL_load_error_strings(void );
+const char *SSL_state_string(const SSL *s);
+const char *SSL_rstate_string(const SSL *s);
+const char *SSL_state_string_long(const SSL *s);
+const char *SSL_rstate_string_long(const SSL *s);
+long SSL_SESSION_get_time(const SSL_SESSION *s);
+long SSL_SESSION_set_time(SSL_SESSION *s, long t);
+long SSL_SESSION_get_timeout(const SSL_SESSION *s);
+long SSL_SESSION_set_timeout(SSL_SESSION *s, long t);
+void SSL_copy_session_id(SSL *to,const SSL *from);
+X509 *SSL_SESSION_get0_peer(SSL_SESSION *s);
+int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx,
+ unsigned int sid_ctx_len);
+
+SSL_SESSION *SSL_SESSION_new(void);
+const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s,
+ unsigned int *len);
+unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s);
+#ifndef OPENSSL_NO_FP_API
+int SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses);
+#endif
+#ifndef OPENSSL_NO_BIO
+int SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses);
+#endif
+void SSL_SESSION_free(SSL_SESSION *ses);
+int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp);
+int SSL_set_session(SSL *to, SSL_SESSION *session);
+int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c);
+int SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c);
+int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB);
+int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB);
+int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
+ unsigned int id_len);
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp,
+ long length);
+
+#ifdef HEADER_X509_H
+X509 * SSL_get_peer_certificate(const SSL *s);
+#endif
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s);
+
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx);
+int SSL_CTX_get_verify_depth(const SSL_CTX *ctx);
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *);
+void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,
+ int (*callback)(int, X509_STORE_CTX *));
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth);
+void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg);
+#ifndef OPENSSL_NO_RSA
+int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa);
+#endif
+int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len);
+int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
+int SSL_CTX_use_PrivateKey_ASN1(int pk,SSL_CTX *ctx,
+ const unsigned char *d, long len);
+int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);
+int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d);
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb);
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u);
+
+int SSL_CTX_check_private_key(const SSL_CTX *ctx);
+int SSL_check_private_key(const SSL *ctx);
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
+ unsigned int sid_ctx_len);
+
+SSL * SSL_new(SSL_CTX *ctx);
+int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
+ unsigned int sid_ctx_len);
+
+int SSL_CTX_set_purpose(SSL_CTX *s, int purpose);
+int SSL_set_purpose(SSL *s, int purpose);
+int SSL_CTX_set_trust(SSL_CTX *s, int trust);
+int SSL_set_trust(SSL *s, int trust);
+
+int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm);
+int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm);
+
+#ifndef OPENSSL_NO_SRP
+int SSL_CTX_set_srp_username(SSL_CTX *ctx,char *name);
+int SSL_CTX_set_srp_password(SSL_CTX *ctx,char *password);
+int SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength);
+int SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx,
+ char *(*cb)(SSL *,void *));
+int SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx,
+ int (*cb)(SSL *,void *));
+int SSL_CTX_set_srp_username_callback(SSL_CTX *ctx,
+ int (*cb)(SSL *,int *,void *));
+int SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg);
+
+int SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g,
+ BIGNUM *sa, BIGNUM *v, char *info);
+int SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass,
+ const char *grp);
+
+BIGNUM *SSL_get_srp_g(SSL *s);
+BIGNUM *SSL_get_srp_N(SSL *s);
+
+char *SSL_get_srp_username(SSL *s);
+char *SSL_get_srp_userinfo(SSL *s);
+#endif
+
+void SSL_free(SSL *ssl);
+int SSL_accept(SSL *ssl);
+int SSL_connect(SSL *ssl);
+int SSL_read(SSL *ssl,void *buf,int num);
+int SSL_peek(SSL *ssl,void *buf,int num);
+int SSL_write(SSL *ssl,const void *buf,int num);
+long SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
+long SSL_callback_ctrl(SSL *, int, void (*)(void));
+long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, void *parg);
+long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void));
+
+int SSL_get_error(const SSL *s,int ret_code);
+const char *SSL_get_version(const SSL *s);
+
+/* This sets the 'default' SSL version that SSL_new() will create */
+int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth);
+
+#ifndef OPENSSL_NO_SSL2
+const SSL_METHOD *SSLv2_method(void); /* SSLv2 */
+const SSL_METHOD *SSLv2_server_method(void); /* SSLv2 */
+const SSL_METHOD *SSLv2_client_method(void); /* SSLv2 */
+#endif
+
+const SSL_METHOD *SSLv3_method(void); /* SSLv3 */
+const SSL_METHOD *SSLv3_server_method(void); /* SSLv3 */
+const SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */
+
+const SSL_METHOD *SSLv23_method(void); /* SSLv3 but can rollback to v2 */
+const SSL_METHOD *SSLv23_server_method(void); /* SSLv3 but can rollback to v2 */
+const SSL_METHOD *SSLv23_client_method(void); /* SSLv3 but can rollback to v2 */
+
+const SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */
+const SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */
+const SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */
+
+const SSL_METHOD *TLSv1_1_method(void); /* TLSv1.1 */
+const SSL_METHOD *TLSv1_1_server_method(void); /* TLSv1.1 */
+const SSL_METHOD *TLSv1_1_client_method(void); /* TLSv1.1 */
+
+const SSL_METHOD *TLSv1_2_method(void); /* TLSv1.2 */
+const SSL_METHOD *TLSv1_2_server_method(void); /* TLSv1.2 */
+const SSL_METHOD *TLSv1_2_client_method(void); /* TLSv1.2 */
+
+
+const SSL_METHOD *DTLSv1_method(void); /* DTLSv1.0 */
+const SSL_METHOD *DTLSv1_server_method(void); /* DTLSv1.0 */
+const SSL_METHOD *DTLSv1_client_method(void); /* DTLSv1.0 */
+
+STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
+
+int SSL_do_handshake(SSL *s);
+int SSL_renegotiate(SSL *s);
+int SSL_renegotiate_abbreviated(SSL *s);
+int SSL_renegotiate_pending(SSL *s);
+int SSL_shutdown(SSL *s);
+
+const SSL_METHOD *SSL_get_ssl_method(SSL *s);
+int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method);
+const char *SSL_alert_type_string_long(int value);
+const char *SSL_alert_type_string(int value);
+const char *SSL_alert_desc_string_long(int value);
+const char *SSL_alert_desc_string(int value);
+
+void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list);
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list);
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s);
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s);
+int SSL_add_client_CA(SSL *ssl,X509 *x);
+int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x);
+
+void SSL_set_connect_state(SSL *s);
+void SSL_set_accept_state(SSL *s);
+
+long SSL_get_default_timeout(const SSL *s);
+
+int SSL_library_init(void );
+
+char *SSL_CIPHER_description(const SSL_CIPHER *,char *buf,int size);
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk);
+
+SSL *SSL_dup(SSL *ssl);
+
+X509 *SSL_get_certificate(const SSL *ssl);
+/* EVP_PKEY */ struct evp_pkey_st *SSL_get_privatekey(SSL *ssl);
+
+void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode);
+int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx);
+void SSL_set_quiet_shutdown(SSL *ssl,int mode);
+int SSL_get_quiet_shutdown(const SSL *ssl);
+void SSL_set_shutdown(SSL *ssl,int mode);
+int SSL_get_shutdown(const SSL *ssl);
+int SSL_version(const SSL *ssl);
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx);
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+ const char *CApath);
+#define SSL_get0_session SSL_get_session /* just peek at pointer */
+SSL_SESSION *SSL_get_session(const SSL *ssl);
+SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl);
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx);
+void SSL_set_info_callback(SSL *ssl,
+ void (*cb)(const SSL *ssl,int type,int val));
+void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl,int type,int val);
+int SSL_state(const SSL *ssl);
+void SSL_set_state(SSL *ssl, int state);
+
+void SSL_set_verify_result(SSL *ssl,long v);
+long SSL_get_verify_result(const SSL *ssl);
+
+int SSL_set_ex_data(SSL *ssl,int idx,void *data);
+void *SSL_get_ex_data(const SSL *ssl,int idx);
+int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_SESSION_set_ex_data(SSL_SESSION *ss,int idx,void *data);
+void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss,int idx);
+int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_CTX_set_ex_data(SSL_CTX *ssl,int idx,void *data);
+void *SSL_CTX_get_ex_data(const SSL_CTX *ssl,int idx);
+int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void );
+
+#define SSL_CTX_sess_set_cache_size(ctx,t) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL)
+#define SSL_CTX_sess_get_cache_size(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL)
+#define SSL_CTX_set_session_cache_mode(ctx,m) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
+#define SSL_CTX_get_session_cache_mode(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL)
+
+#define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx)
+#define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m)
+#define SSL_CTX_get_read_ahead(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL)
+#define SSL_CTX_set_read_ahead(ctx,m) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL)
+#define SSL_CTX_get_max_cert_list(ctx) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
+#define SSL_CTX_set_max_cert_list(ctx,m) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
+#define SSL_get_max_cert_list(ssl) \
+ SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
+#define SSL_set_max_cert_list(ssl,m) \
+ SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
+
+#define SSL_CTX_set_max_send_fragment(ctx,m) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
+#define SSL_set_max_send_fragment(ssl,m) \
+ SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
+
+ /* NB: the keylength is only applicable when is_export is true */
+#ifndef OPENSSL_NO_RSA
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,
+ RSA *(*cb)(SSL *ssl,int is_export,
+ int keylength));
+
+void SSL_set_tmp_rsa_callback(SSL *ssl,
+ RSA *(*cb)(SSL *ssl,int is_export,
+ int keylength));
+#endif
+#ifndef OPENSSL_NO_DH
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
+ DH *(*dh)(SSL *ssl,int is_export,
+ int keylength));
+void SSL_set_tmp_dh_callback(SSL *ssl,
+ DH *(*dh)(SSL *ssl,int is_export,
+ int keylength));
+#endif
+#ifndef OPENSSL_NO_ECDH
+void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,
+ EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+ int keylength));
+void SSL_set_tmp_ecdh_callback(SSL *ssl,
+ EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+ int keylength));
+#endif
+
+#ifndef OPENSSL_NO_COMP
+const COMP_METHOD *SSL_get_current_compression(SSL *s);
+const COMP_METHOD *SSL_get_current_expansion(SSL *s);
+const char *SSL_COMP_get_name(const COMP_METHOD *comp);
+STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void);
+int SSL_COMP_add_compression_method(int id,COMP_METHOD *cm);
+#else
+const void *SSL_get_current_compression(SSL *s);
+const void *SSL_get_current_expansion(SSL *s);
+const char *SSL_COMP_get_name(const void *comp);
+void *SSL_COMP_get_compression_methods(void);
+int SSL_COMP_add_compression_method(int id,void *cm);
+#endif
+
+/* TLS extensions functions */
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+ void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
+void SSL_set_debug(SSL *s, int debug);
+int SSL_cache_hit(SSL *s);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_SSL_strings(void);
+
+/* Error codes for the SSL functions. */
+
+/* Function codes. */
+#define SSL_F_CLIENT_CERTIFICATE 100
+#define SSL_F_CLIENT_FINISHED 167
+#define SSL_F_CLIENT_HELLO 101
+#define SSL_F_CLIENT_MASTER_KEY 102
+#define SSL_F_D2I_SSL_SESSION 103
+#define SSL_F_DO_DTLS1_WRITE 245
+#define SSL_F_DO_SSL3_WRITE 104
+#define SSL_F_DTLS1_ACCEPT 246
+#define SSL_F_DTLS1_ADD_CERT_TO_BUF 295
+#define SSL_F_DTLS1_BUFFER_RECORD 247
+#define SSL_F_DTLS1_CHECK_TIMEOUT_NUM 316
+#define SSL_F_DTLS1_CLIENT_HELLO 248
+#define SSL_F_DTLS1_CONNECT 249
+#define SSL_F_DTLS1_ENC 250
+#define SSL_F_DTLS1_GET_HELLO_VERIFY 251
+#define SSL_F_DTLS1_GET_MESSAGE 252
+#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253
+#define SSL_F_DTLS1_GET_RECORD 254
+#define SSL_F_DTLS1_HANDLE_TIMEOUT 297
+#define SSL_F_DTLS1_HEARTBEAT 305
+#define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255
+#define SSL_F_DTLS1_PREPROCESS_FRAGMENT 288
+#define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256
+#define SSL_F_DTLS1_PROCESS_RECORD 257
+#define SSL_F_DTLS1_READ_BYTES 258
+#define SSL_F_DTLS1_READ_FAILED 259
+#define SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST 260
+#define SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE 261
+#define SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE 262
+#define SSL_F_DTLS1_SEND_CLIENT_VERIFY 263
+#define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST 264
+#define SSL_F_DTLS1_SEND_SERVER_CERTIFICATE 265
+#define SSL_F_DTLS1_SEND_SERVER_HELLO 266
+#define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE 267
+#define SSL_F_DTLS1_WRITE_APP_DATA_BYTES 268
+#define SSL_F_GET_CLIENT_FINISHED 105
+#define SSL_F_GET_CLIENT_HELLO 106
+#define SSL_F_GET_CLIENT_MASTER_KEY 107
+#define SSL_F_GET_SERVER_FINISHED 108
+#define SSL_F_GET_SERVER_HELLO 109
+#define SSL_F_GET_SERVER_VERIFY 110
+#define SSL_F_I2D_SSL_SESSION 111
+#define SSL_F_READ_N 112
+#define SSL_F_REQUEST_CERTIFICATE 113
+#define SSL_F_SERVER_FINISH 239
+#define SSL_F_SERVER_HELLO 114
+#define SSL_F_SERVER_VERIFY 240
+#define SSL_F_SSL23_ACCEPT 115
+#define SSL_F_SSL23_CLIENT_HELLO 116
+#define SSL_F_SSL23_CONNECT 117
+#define SSL_F_SSL23_GET_CLIENT_HELLO 118
+#define SSL_F_SSL23_GET_SERVER_HELLO 119
+#define SSL_F_SSL23_PEEK 237
+#define SSL_F_SSL23_READ 120
+#define SSL_F_SSL23_WRITE 121
+#define SSL_F_SSL2_ACCEPT 122
+#define SSL_F_SSL2_CONNECT 123
+#define SSL_F_SSL2_ENC_INIT 124
+#define SSL_F_SSL2_GENERATE_KEY_MATERIAL 241
+#define SSL_F_SSL2_PEEK 234
+#define SSL_F_SSL2_READ 125
+#define SSL_F_SSL2_READ_INTERNAL 236
+#define SSL_F_SSL2_SET_CERTIFICATE 126
+#define SSL_F_SSL2_WRITE 127
+#define SSL_F_SSL3_ACCEPT 128
+#define SSL_F_SSL3_ADD_CERT_TO_BUF 296
+#define SSL_F_SSL3_CALLBACK_CTRL 233
+#define SSL_F_SSL3_CHANGE_CIPHER_STATE 129
+#define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130
+#define SSL_F_SSL3_CHECK_CLIENT_HELLO 304
+#define SSL_F_SSL3_CLIENT_HELLO 131
+#define SSL_F_SSL3_CONNECT 132
+#define SSL_F_SSL3_CTRL 213
+#define SSL_F_SSL3_CTX_CTRL 133
+#define SSL_F_SSL3_DIGEST_CACHED_RECORDS 293
+#define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC 292
+#define SSL_F_SSL3_ENC 134
+#define SSL_F_SSL3_GENERATE_KEY_BLOCK 238
+#define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135
+#define SSL_F_SSL3_GET_CERT_STATUS 289
+#define SSL_F_SSL3_GET_CERT_VERIFY 136
+#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137
+#define SSL_F_SSL3_GET_CLIENT_HELLO 138
+#define SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE 139
+#define SSL_F_SSL3_GET_FINISHED 140
+#define SSL_F_SSL3_GET_KEY_EXCHANGE 141
+#define SSL_F_SSL3_GET_MESSAGE 142
+#define SSL_F_SSL3_GET_NEW_SESSION_TICKET 283
+#define SSL_F_SSL3_GET_NEXT_PROTO 306
+#define SSL_F_SSL3_GET_RECORD 143
+#define SSL_F_SSL3_GET_SERVER_CERTIFICATE 144
+#define SSL_F_SSL3_GET_SERVER_DONE 145
+#define SSL_F_SSL3_GET_SERVER_HELLO 146
+#define SSL_F_SSL3_HANDSHAKE_MAC 285
+#define SSL_F_SSL3_NEW_SESSION_TICKET 287
+#define SSL_F_SSL3_OUTPUT_CERT_CHAIN 147
+#define SSL_F_SSL3_PEEK 235
+#define SSL_F_SSL3_READ_BYTES 148
+#define SSL_F_SSL3_READ_N 149
+#define SSL_F_SSL3_SEND_CERTIFICATE_REQUEST 150
+#define SSL_F_SSL3_SEND_CLIENT_CERTIFICATE 151
+#define SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE 152
+#define SSL_F_SSL3_SEND_CLIENT_VERIFY 153
+#define SSL_F_SSL3_SEND_SERVER_CERTIFICATE 154
+#define SSL_F_SSL3_SEND_SERVER_HELLO 242
+#define SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE 155
+#define SSL_F_SSL3_SETUP_KEY_BLOCK 157
+#define SSL_F_SSL3_SETUP_READ_BUFFER 156
+#define SSL_F_SSL3_SETUP_WRITE_BUFFER 291
+#define SSL_F_SSL3_WRITE_BYTES 158
+#define SSL_F_SSL3_WRITE_PENDING 159
+#define SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT 298
+#define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 277
+#define SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT 307
+#define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215
+#define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216
+#define SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT 299
+#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 278
+#define SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT 308
+#define SSL_F_SSL_BAD_METHOD 160
+#define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161
+#define SSL_F_SSL_CERT_DUP 221
+#define SSL_F_SSL_CERT_INST 222
+#define SSL_F_SSL_CERT_INSTANTIATE 214
+#define SSL_F_SSL_CERT_NEW 162
+#define SSL_F_SSL_CHECK_PRIVATE_KEY 163
+#define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 280
+#define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG 279
+#define SSL_F_SSL_CIPHER_PROCESS_RULESTR 230
+#define SSL_F_SSL_CIPHER_STRENGTH_SORT 231
+#define SSL_F_SSL_CLEAR 164
+#define SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD 165
+#define SSL_F_SSL_CREATE_CIPHER_LIST 166
+#define SSL_F_SSL_CTRL 232
+#define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY 168
+#define SSL_F_SSL_CTX_MAKE_PROFILES 309
+#define SSL_F_SSL_CTX_NEW 169
+#define SSL_F_SSL_CTX_SET_CIPHER_LIST 269
+#define SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE 290
+#define SSL_F_SSL_CTX_SET_PURPOSE 226
+#define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219
+#define SSL_F_SSL_CTX_SET_SSL_VERSION 170
+#define SSL_F_SSL_CTX_SET_TRUST 229
+#define SSL_F_SSL_CTX_USE_CERTIFICATE 171
+#define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172
+#define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE 220
+#define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173
+#define SSL_F_SSL_CTX_USE_PRIVATEKEY 174
+#define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175
+#define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE 176
+#define SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT 272
+#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY 177
+#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1 178
+#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179
+#define SSL_F_SSL_DO_HANDSHAKE 180
+#define SSL_F_SSL_GET_NEW_SESSION 181
+#define SSL_F_SSL_GET_PREV_SESSION 217
+#define SSL_F_SSL_GET_SERVER_SEND_CERT 182
+#define SSL_F_SSL_GET_SERVER_SEND_PKEY 317
+#define SSL_F_SSL_GET_SIGN_PKEY 183
+#define SSL_F_SSL_INIT_WBIO_BUFFER 184
+#define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185
+#define SSL_F_SSL_NEW 186
+#define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 300
+#define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 302
+#define SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT 310
+#define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 301
+#define SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT 303
+#define SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT 311
+#define SSL_F_SSL_PEEK 270
+#define SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT 281
+#define SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT 282
+#define SSL_F_SSL_READ 223
+#define SSL_F_SSL_RSA_PRIVATE_DECRYPT 187
+#define SSL_F_SSL_RSA_PUBLIC_ENCRYPT 188
+#define SSL_F_SSL_SESSION_NEW 189
+#define SSL_F_SSL_SESSION_PRINT_FP 190
+#define SSL_F_SSL_SESSION_SET1_ID_CONTEXT 312
+#define SSL_F_SSL_SESS_CERT_NEW 225
+#define SSL_F_SSL_SET_CERT 191
+#define SSL_F_SSL_SET_CIPHER_LIST 271
+#define SSL_F_SSL_SET_FD 192
+#define SSL_F_SSL_SET_PKEY 193
+#define SSL_F_SSL_SET_PURPOSE 227
+#define SSL_F_SSL_SET_RFD 194
+#define SSL_F_SSL_SET_SESSION 195
+#define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218
+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 294
+#define SSL_F_SSL_SET_TRUST 228
+#define SSL_F_SSL_SET_WFD 196
+#define SSL_F_SSL_SHUTDOWN 224
+#define SSL_F_SSL_SRP_CTX_INIT 313
+#define SSL_F_SSL_UNDEFINED_CONST_FUNCTION 243
+#define SSL_F_SSL_UNDEFINED_FUNCTION 197
+#define SSL_F_SSL_UNDEFINED_VOID_FUNCTION 244
+#define SSL_F_SSL_USE_CERTIFICATE 198
+#define SSL_F_SSL_USE_CERTIFICATE_ASN1 199
+#define SSL_F_SSL_USE_CERTIFICATE_FILE 200
+#define SSL_F_SSL_USE_PRIVATEKEY 201
+#define SSL_F_SSL_USE_PRIVATEKEY_ASN1 202
+#define SSL_F_SSL_USE_PRIVATEKEY_FILE 203
+#define SSL_F_SSL_USE_PSK_IDENTITY_HINT 273
+#define SSL_F_SSL_USE_RSAPRIVATEKEY 204
+#define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1 205
+#define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206
+#define SSL_F_SSL_VERIFY_CERT_CHAIN 207
+#define SSL_F_SSL_WRITE 208
+#define SSL_F_TLS1_CERT_VERIFY_MAC 286
+#define SSL_F_TLS1_CHANGE_CIPHER_STATE 209
+#define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274
+#define SSL_F_TLS1_ENC 210
+#define SSL_F_TLS1_EXPORT_KEYING_MATERIAL 314
+#define SSL_F_TLS1_HEARTBEAT 315
+#define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT 275
+#define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT 276
+#define SSL_F_TLS1_PRF 284
+#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
+#define SSL_F_WRITE_PENDING 212
+
+/* Reason codes. */
+#define SSL_R_APP_DATA_IN_HANDSHAKE 100
+#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
+#define SSL_R_BAD_ALERT_RECORD 101
+#define SSL_R_BAD_AUTHENTICATION_TYPE 102
+#define SSL_R_BAD_CHANGE_CIPHER_SPEC 103
+#define SSL_R_BAD_CHECKSUM 104
+#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106
+#define SSL_R_BAD_DECOMPRESSION 107
+#define SSL_R_BAD_DH_G_LENGTH 108
+#define SSL_R_BAD_DH_PUB_KEY_LENGTH 109
+#define SSL_R_BAD_DH_P_LENGTH 110
+#define SSL_R_BAD_DIGEST_LENGTH 111
+#define SSL_R_BAD_DSA_SIGNATURE 112
+#define SSL_R_BAD_ECC_CERT 304
+#define SSL_R_BAD_ECDSA_SIGNATURE 305
+#define SSL_R_BAD_ECPOINT 306
+#define SSL_R_BAD_HANDSHAKE_LENGTH 332
+#define SSL_R_BAD_HELLO_REQUEST 105
+#define SSL_R_BAD_LENGTH 271
+#define SSL_R_BAD_MAC_DECODE 113
+#define SSL_R_BAD_MAC_LENGTH 333
+#define SSL_R_BAD_MESSAGE_TYPE 114
+#define SSL_R_BAD_PACKET_LENGTH 115
+#define SSL_R_BAD_PROTOCOL_VERSION_NUMBER 116
+#define SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH 316
+#define SSL_R_BAD_RESPONSE_ARGUMENT 117
+#define SSL_R_BAD_RSA_DECRYPT 118
+#define SSL_R_BAD_RSA_ENCRYPT 119
+#define SSL_R_BAD_RSA_E_LENGTH 120
+#define SSL_R_BAD_RSA_MODULUS_LENGTH 121
+#define SSL_R_BAD_RSA_SIGNATURE 122
+#define SSL_R_BAD_SIGNATURE 123
+#define SSL_R_BAD_SRP_A_LENGTH 347
+#define SSL_R_BAD_SRP_B_LENGTH 348
+#define SSL_R_BAD_SRP_G_LENGTH 349
+#define SSL_R_BAD_SRP_N_LENGTH 350
+#define SSL_R_BAD_SRP_S_LENGTH 351
+#define SSL_R_BAD_SRTP_MKI_VALUE 352
+#define SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST 353
+#define SSL_R_BAD_SSL_FILETYPE 124
+#define SSL_R_BAD_SSL_SESSION_ID_LENGTH 125
+#define SSL_R_BAD_STATE 126
+#define SSL_R_BAD_WRITE_RETRY 127
+#define SSL_R_BIO_NOT_SET 128
+#define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 129
+#define SSL_R_BN_LIB 130
+#define SSL_R_CA_DN_LENGTH_MISMATCH 131
+#define SSL_R_CA_DN_TOO_LONG 132
+#define SSL_R_CCS_RECEIVED_EARLY 133
+#define SSL_R_CERTIFICATE_VERIFY_FAILED 134
+#define SSL_R_CERT_LENGTH_MISMATCH 135
+#define SSL_R_CHALLENGE_IS_DIFFERENT 136
+#define SSL_R_CIPHER_CODE_WRONG_LENGTH 137
+#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 138
+#define SSL_R_CIPHER_TABLE_SRC_ERROR 139
+#define SSL_R_CLIENTHELLO_TLSEXT 226
+#define SSL_R_COMPRESSED_LENGTH_TOO_LONG 140
+#define SSL_R_COMPRESSION_DISABLED 343
+#define SSL_R_COMPRESSION_FAILURE 141
+#define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307
+#define SSL_R_COMPRESSION_LIBRARY_ERROR 142
+#define SSL_R_CONNECTION_ID_IS_DIFFERENT 143
+#define SSL_R_CONNECTION_TYPE_NOT_SET 144
+#define SSL_R_COOKIE_MISMATCH 308
+#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145
+#define SSL_R_DATA_LENGTH_TOO_LONG 146
+#define SSL_R_DECRYPTION_FAILED 147
+#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281
+#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148
+#define SSL_R_DIGEST_CHECK_FAILED 149
+#define SSL_R_DTLS_MESSAGE_TOO_BIG 334
+#define SSL_R_DUPLICATE_COMPRESSION_ID 309
+#define SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT 317
+#define SSL_R_ECC_CERT_NOT_FOR_SIGNING 318
+#define SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE 322
+#define SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE 323
+#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310
+#define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354
+#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150
+#define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 282
+#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151
+#define SSL_R_EXCESSIVE_MESSAGE_SIZE 152
+#define SSL_R_EXTRA_DATA_IN_MESSAGE 153
+#define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154
+#define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 355
+#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 356
+#define SSL_R_HTTPS_PROXY_REQUEST 155
+#define SSL_R_HTTP_REQUEST 156
+#define SSL_R_ILLEGAL_PADDING 283
+#define SSL_R_INCONSISTENT_COMPRESSION 340
+#define SSL_R_INVALID_CHALLENGE_LENGTH 158
+#define SSL_R_INVALID_COMMAND 280
+#define SSL_R_INVALID_COMPRESSION_ALGORITHM 341
+#define SSL_R_INVALID_PURPOSE 278
+#define SSL_R_INVALID_SRP_USERNAME 357
+#define SSL_R_INVALID_STATUS_RESPONSE 328
+#define SSL_R_INVALID_TICKET_KEYS_LENGTH 325
+#define SSL_R_INVALID_TRUST 279
+#define SSL_R_KEY_ARG_TOO_LONG 284
+#define SSL_R_KRB5 285
+#define SSL_R_KRB5_C_CC_PRINC 286
+#define SSL_R_KRB5_C_GET_CRED 287
+#define SSL_R_KRB5_C_INIT 288
+#define SSL_R_KRB5_C_MK_REQ 289
+#define SSL_R_KRB5_S_BAD_TICKET 290
+#define SSL_R_KRB5_S_INIT 291
+#define SSL_R_KRB5_S_RD_REQ 292
+#define SSL_R_KRB5_S_TKT_EXPIRED 293
+#define SSL_R_KRB5_S_TKT_NYV 294
+#define SSL_R_KRB5_S_TKT_SKEW 295
+#define SSL_R_LENGTH_MISMATCH 159
+#define SSL_R_LENGTH_TOO_SHORT 160
+#define SSL_R_LIBRARY_BUG 274
+#define SSL_R_LIBRARY_HAS_NO_CIPHERS 161
+#define SSL_R_MESSAGE_TOO_LONG 296
+#define SSL_R_MISSING_DH_DSA_CERT 162
+#define SSL_R_MISSING_DH_KEY 163
+#define SSL_R_MISSING_DH_RSA_CERT 164
+#define SSL_R_MISSING_DSA_SIGNING_CERT 165
+#define SSL_R_MISSING_EXPORT_TMP_DH_KEY 166
+#define SSL_R_MISSING_EXPORT_TMP_RSA_KEY 167
+#define SSL_R_MISSING_RSA_CERTIFICATE 168
+#define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169
+#define SSL_R_MISSING_RSA_SIGNING_CERT 170
+#define SSL_R_MISSING_SRP_PARAM 358
+#define SSL_R_MISSING_TMP_DH_KEY 171
+#define SSL_R_MISSING_TMP_ECDH_KEY 311
+#define SSL_R_MISSING_TMP_RSA_KEY 172
+#define SSL_R_MISSING_TMP_RSA_PKEY 173
+#define SSL_R_MISSING_VERIFY_MESSAGE 174
+#define SSL_R_MULTIPLE_SGC_RESTARTS 346
+#define SSL_R_NON_SSLV2_INITIAL_PACKET 175
+#define SSL_R_NO_CERTIFICATES_RETURNED 176
+#define SSL_R_NO_CERTIFICATE_ASSIGNED 177
+#define SSL_R_NO_CERTIFICATE_RETURNED 178
+#define SSL_R_NO_CERTIFICATE_SET 179
+#define SSL_R_NO_CERTIFICATE_SPECIFIED 180
+#define SSL_R_NO_CIPHERS_AVAILABLE 181
+#define SSL_R_NO_CIPHERS_PASSED 182
+#define SSL_R_NO_CIPHERS_SPECIFIED 183
+#define SSL_R_NO_CIPHER_LIST 184
+#define SSL_R_NO_CIPHER_MATCH 185
+#define SSL_R_NO_CLIENT_CERT_METHOD 331
+#define SSL_R_NO_CLIENT_CERT_RECEIVED 186
+#define SSL_R_NO_COMPRESSION_SPECIFIED 187
+#define SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER 330
+#define SSL_R_NO_METHOD_SPECIFIED 188
+#define SSL_R_NO_PRIVATEKEY 189
+#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190
+#define SSL_R_NO_PROTOCOLS_AVAILABLE 191
+#define SSL_R_NO_PUBLICKEY 192
+#define SSL_R_NO_RENEGOTIATION 339
+#define SSL_R_NO_REQUIRED_DIGEST 324
+#define SSL_R_NO_SHARED_CIPHER 193
+#define SSL_R_NO_SRTP_PROFILES 359
+#define SSL_R_NO_VERIFY_CALLBACK 194
+#define SSL_R_NULL_SSL_CTX 195
+#define SSL_R_NULL_SSL_METHOD_PASSED 196
+#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197
+#define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344
+#define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297
+#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 327
+#define SSL_R_PACKET_LENGTH_TOO_LONG 198
+#define SSL_R_PARSE_TLSEXT 227
+#define SSL_R_PATH_TOO_LONG 270
+#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199
+#define SSL_R_PEER_ERROR 200
+#define SSL_R_PEER_ERROR_CERTIFICATE 201
+#define SSL_R_PEER_ERROR_NO_CERTIFICATE 202
+#define SSL_R_PEER_ERROR_NO_CIPHER 203
+#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 204
+#define SSL_R_PRE_MAC_LENGTH_TOO_LONG 205
+#define SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS 206
+#define SSL_R_PROTOCOL_IS_SHUTDOWN 207
+#define SSL_R_PSK_IDENTITY_NOT_FOUND 223
+#define SSL_R_PSK_NO_CLIENT_CB 224
+#define SSL_R_PSK_NO_SERVER_CB 225
+#define SSL_R_PUBLIC_KEY_ENCRYPT_ERROR 208
+#define SSL_R_PUBLIC_KEY_IS_NOT_RSA 209
+#define SSL_R_PUBLIC_KEY_NOT_RSA 210
+#define SSL_R_READ_BIO_NOT_SET 211
+#define SSL_R_READ_TIMEOUT_EXPIRED 312
+#define SSL_R_READ_WRONG_PACKET_TYPE 212
+#define SSL_R_RECORD_LENGTH_MISMATCH 213
+#define SSL_R_RECORD_TOO_LARGE 214
+#define SSL_R_RECORD_TOO_SMALL 298
+#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 335
+#define SSL_R_RENEGOTIATION_ENCODING_ERR 336
+#define SSL_R_RENEGOTIATION_MISMATCH 337
+#define SSL_R_REQUIRED_CIPHER_MISSING 215
+#define SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING 342
+#define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216
+#define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217
+#define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 218
+#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 345
+#define SSL_R_SERVERHELLO_TLSEXT 275
+#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277
+#define SSL_R_SHORT_READ 219
+#define SSL_R_SIGNATURE_ALGORITHMS_ERROR 360
+#define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220
+#define SSL_R_SRP_A_CALC 361
+#define SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES 362
+#define SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG 363
+#define SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE 364
+#define SSL_R_SSL23_DOING_SESSION_ID_REUSE 221
+#define SSL_R_SSL2_CONNECTION_ID_TOO_LONG 299
+#define SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT 321
+#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 319
+#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 320
+#define SSL_R_SSL3_SESSION_ID_TOO_LONG 300
+#define SSL_R_SSL3_SESSION_ID_TOO_SHORT 222
+#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042
+#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046
+#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030
+#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040
+#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047
+#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041
+#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
+#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043
+#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 228
+#define SSL_R_SSL_HANDSHAKE_FAILURE 229
+#define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS 230
+#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 301
+#define SSL_R_SSL_SESSION_ID_CONFLICT 302
+#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273
+#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303
+#define SSL_R_SSL_SESSION_ID_IS_DIFFERENT 231
+#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049
+#define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050
+#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021
+#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051
+#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060
+#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071
+#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080
+#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100
+#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070
+#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022
+#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048
+#define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090
+#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114
+#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113
+#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111
+#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112
+#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110
+#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232
+#define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT 365
+#define SSL_R_TLS_HEARTBEAT_PENDING 366
+#define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 367
+#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157
+#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
+#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234
+#define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 235
+#define SSL_R_UNABLE_TO_DECODE_DH_CERTS 236
+#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 313
+#define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY 237
+#define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS 238
+#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 314
+#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239
+#define SSL_R_UNABLE_TO_FIND_SSL_METHOD 240
+#define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 241
+#define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242
+#define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243
+#define SSL_R_UNEXPECTED_MESSAGE 244
+#define SSL_R_UNEXPECTED_RECORD 245
+#define SSL_R_UNINITIALIZED 276
+#define SSL_R_UNKNOWN_ALERT_TYPE 246
+#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247
+#define SSL_R_UNKNOWN_CIPHER_RETURNED 248
+#define SSL_R_UNKNOWN_CIPHER_TYPE 249
+#define SSL_R_UNKNOWN_DIGEST 368
+#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250
+#define SSL_R_UNKNOWN_PKEY_TYPE 251
+#define SSL_R_UNKNOWN_PROTOCOL 252
+#define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253
+#define SSL_R_UNKNOWN_SSL_VERSION 254
+#define SSL_R_UNKNOWN_STATE 255
+#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 338
+#define SSL_R_UNSUPPORTED_CIPHER 256
+#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257
+#define SSL_R_UNSUPPORTED_DIGEST_TYPE 326
+#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315
+#define SSL_R_UNSUPPORTED_PROTOCOL 258
+#define SSL_R_UNSUPPORTED_SSL_VERSION 259
+#define SSL_R_UNSUPPORTED_STATUS_TYPE 329
+#define SSL_R_USE_SRTP_NOT_NEGOTIATED 369
+#define SSL_R_WRITE_BIO_NOT_SET 260
+#define SSL_R_WRONG_CIPHER_RETURNED 261
+#define SSL_R_WRONG_MESSAGE_TYPE 262
+#define SSL_R_WRONG_NUMBER_OF_KEY_BITS 263
+#define SSL_R_WRONG_SIGNATURE_LENGTH 264
+#define SSL_R_WRONG_SIGNATURE_SIZE 265
+#define SSL_R_WRONG_SIGNATURE_TYPE 370
+#define SSL_R_WRONG_SSL_VERSION 266
+#define SSL_R_WRONG_VERSION_NUMBER 267
+#define SSL_R_X509_LIB 268
+#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/drivers/builtin_openssl/openssl/ssl2.h b/drivers/builtin_openssl2/openssl/ssl2.h
index eb25dcb0bf..eb25dcb0bf 100644
--- a/drivers/builtin_openssl/openssl/ssl2.h
+++ b/drivers/builtin_openssl2/openssl/ssl2.h
diff --git a/drivers/builtin_openssl/openssl/ssl23.h b/drivers/builtin_openssl2/openssl/ssl23.h
index d3228983c7..d3228983c7 100644
--- a/drivers/builtin_openssl/openssl/ssl23.h
+++ b/drivers/builtin_openssl2/openssl/ssl23.h
diff --git a/drivers/builtin_openssl2/openssl/ssl3.h b/drivers/builtin_openssl2/openssl/ssl3.h
new file mode 100644
index 0000000000..37f19e3ab5
--- /dev/null
+++ b/drivers/builtin_openssl2/openssl/ssl3.h
@@ -0,0 +1,694 @@
+/* ssl/ssl3.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#ifndef HEADER_SSL3_H
+#define HEADER_SSL3_H
+
+#ifndef OPENSSL_NO_COMP
+#include <openssl/comp.h>
+#endif
+#include <openssl/buffer.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Signalling cipher suite value: from draft-ietf-tls-renegotiation-03.txt */
+#define SSL3_CK_SCSV 0x030000FF
+
+#define SSL3_CK_RSA_NULL_MD5 0x03000001
+#define SSL3_CK_RSA_NULL_SHA 0x03000002
+#define SSL3_CK_RSA_RC4_40_MD5 0x03000003
+#define SSL3_CK_RSA_RC4_128_MD5 0x03000004
+#define SSL3_CK_RSA_RC4_128_SHA 0x03000005
+#define SSL3_CK_RSA_RC2_40_MD5 0x03000006
+#define SSL3_CK_RSA_IDEA_128_SHA 0x03000007
+#define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008
+#define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009
+#define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A
+
+#define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B
+#define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C
+#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D
+#define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E
+#define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F
+#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010
+
+#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011
+#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012
+#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013
+#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014
+#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015
+#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016
+
+#define SSL3_CK_ADH_RC4_40_MD5 0x03000017
+#define SSL3_CK_ADH_RC4_128_MD5 0x03000018
+#define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019
+#define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A
+#define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B
+
+#if 0
+ #define SSL3_CK_FZA_DMS_NULL_SHA 0x0300001C
+ #define SSL3_CK_FZA_DMS_FZA_SHA 0x0300001D
+ #if 0 /* Because it clashes with KRB5, is never used any more, and is safe
+ to remove according to David Hopwood <david.hopwood@zetnet.co.uk>
+ of the ietf-tls list */
+ #define SSL3_CK_FZA_DMS_RC4_SHA 0x0300001E
+ #endif
+#endif
+
+/* VRS Additional Kerberos5 entries
+ */
+#define SSL3_CK_KRB5_DES_64_CBC_SHA 0x0300001E
+#define SSL3_CK_KRB5_DES_192_CBC3_SHA 0x0300001F
+#define SSL3_CK_KRB5_RC4_128_SHA 0x03000020
+#define SSL3_CK_KRB5_IDEA_128_CBC_SHA 0x03000021
+#define SSL3_CK_KRB5_DES_64_CBC_MD5 0x03000022
+#define SSL3_CK_KRB5_DES_192_CBC3_MD5 0x03000023
+#define SSL3_CK_KRB5_RC4_128_MD5 0x03000024
+#define SSL3_CK_KRB5_IDEA_128_CBC_MD5 0x03000025
+
+#define SSL3_CK_KRB5_DES_40_CBC_SHA 0x03000026
+#define SSL3_CK_KRB5_RC2_40_CBC_SHA 0x03000027
+#define SSL3_CK_KRB5_RC4_40_SHA 0x03000028
+#define SSL3_CK_KRB5_DES_40_CBC_MD5 0x03000029
+#define SSL3_CK_KRB5_RC2_40_CBC_MD5 0x0300002A
+#define SSL3_CK_KRB5_RC4_40_MD5 0x0300002B
+
+#define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5"
+#define SSL3_TXT_RSA_NULL_SHA "NULL-SHA"
+#define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5"
+#define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5"
+#define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA"
+#define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5"
+#define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA"
+#define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA"
+#define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA"
+#define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA"
+
+#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA"
+#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA"
+
+#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA"
+#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA"
+
+#define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5"
+#define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5"
+#define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA"
+#define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA"
+#define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA"
+
+#if 0
+ #define SSL3_TXT_FZA_DMS_NULL_SHA "FZA-NULL-SHA"
+ #define SSL3_TXT_FZA_DMS_FZA_SHA "FZA-FZA-CBC-SHA"
+ #define SSL3_TXT_FZA_DMS_RC4_SHA "FZA-RC4-SHA"
+#endif
+
+#define SSL3_TXT_KRB5_DES_64_CBC_SHA "KRB5-DES-CBC-SHA"
+#define SSL3_TXT_KRB5_DES_192_CBC3_SHA "KRB5-DES-CBC3-SHA"
+#define SSL3_TXT_KRB5_RC4_128_SHA "KRB5-RC4-SHA"
+#define SSL3_TXT_KRB5_IDEA_128_CBC_SHA "KRB5-IDEA-CBC-SHA"
+#define SSL3_TXT_KRB5_DES_64_CBC_MD5 "KRB5-DES-CBC-MD5"
+#define SSL3_TXT_KRB5_DES_192_CBC3_MD5 "KRB5-DES-CBC3-MD5"
+#define SSL3_TXT_KRB5_RC4_128_MD5 "KRB5-RC4-MD5"
+#define SSL3_TXT_KRB5_IDEA_128_CBC_MD5 "KRB5-IDEA-CBC-MD5"
+
+#define SSL3_TXT_KRB5_DES_40_CBC_SHA "EXP-KRB5-DES-CBC-SHA"
+#define SSL3_TXT_KRB5_RC2_40_CBC_SHA "EXP-KRB5-RC2-CBC-SHA"
+#define SSL3_TXT_KRB5_RC4_40_SHA "EXP-KRB5-RC4-SHA"
+#define SSL3_TXT_KRB5_DES_40_CBC_MD5 "EXP-KRB5-DES-CBC-MD5"
+#define SSL3_TXT_KRB5_RC2_40_CBC_MD5 "EXP-KRB5-RC2-CBC-MD5"
+#define SSL3_TXT_KRB5_RC4_40_MD5 "EXP-KRB5-RC4-MD5"
+
+#define SSL3_SSL_SESSION_ID_LENGTH 32
+#define SSL3_MAX_SSL_SESSION_ID_LENGTH 32
+
+#define SSL3_MASTER_SECRET_SIZE 48
+#define SSL3_RANDOM_SIZE 32
+#define SSL3_SESSION_ID_SIZE 32
+#define SSL3_RT_HEADER_LENGTH 5
+
+#ifndef SSL3_ALIGN_PAYLOAD
+ /* Some will argue that this increases memory footprint, but it's
+ * not actually true. Point is that malloc has to return at least
+ * 64-bit aligned pointers, meaning that allocating 5 bytes wastes
+ * 3 bytes in either case. Suggested pre-gaping simply moves these
+ * wasted bytes from the end of allocated region to its front,
+ * but makes data payload aligned, which improves performance:-) */
+# define SSL3_ALIGN_PAYLOAD 8
+#else
+# if (SSL3_ALIGN_PAYLOAD&(SSL3_ALIGN_PAYLOAD-1))!=0
+# error "insane SSL3_ALIGN_PAYLOAD"
+# undef SSL3_ALIGN_PAYLOAD
+# endif
+#endif
+
+/* This is the maximum MAC (digest) size used by the SSL library.
+ * Currently maximum of 20 is used by SHA1, but we reserve for
+ * future extension for 512-bit hashes.
+ */
+
+#define SSL3_RT_MAX_MD_SIZE 64
+
+/* Maximum block size used in all ciphersuites. Currently 16 for AES.
+ */
+
+#define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16
+
+#define SSL3_RT_MAX_EXTRA (16384)
+
+/* Maximum plaintext length: defined by SSL/TLS standards */
+#define SSL3_RT_MAX_PLAIN_LENGTH 16384
+/* Maximum compression overhead: defined by SSL/TLS standards */
+#define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024
+
+/* The standards give a maximum encryption overhead of 1024 bytes.
+ * In practice the value is lower than this. The overhead is the maximum
+ * number of padding bytes (256) plus the mac size.
+ */
+#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE)
+
+/* OpenSSL currently only uses a padding length of at most one block so
+ * the send overhead is smaller.
+ */
+
+#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \
+ (SSL_RT_MAX_CIPHER_BLOCK_SIZE + SSL3_RT_MAX_MD_SIZE)
+
+/* If compression isn't used don't include the compression overhead */
+
+#ifdef OPENSSL_NO_COMP
+#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH
+#else
+#define SSL3_RT_MAX_COMPRESSED_LENGTH \
+ (SSL3_RT_MAX_PLAIN_LENGTH+SSL3_RT_MAX_COMPRESSED_OVERHEAD)
+#endif
+#define SSL3_RT_MAX_ENCRYPTED_LENGTH \
+ (SSL3_RT_MAX_ENCRYPTED_OVERHEAD+SSL3_RT_MAX_COMPRESSED_LENGTH)
+#define SSL3_RT_MAX_PACKET_SIZE \
+ (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
+
+#define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54"
+#define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52"
+
+#define SSL3_VERSION 0x0300
+#define SSL3_VERSION_MAJOR 0x03
+#define SSL3_VERSION_MINOR 0x00
+
+#define SSL3_RT_CHANGE_CIPHER_SPEC 20
+#define SSL3_RT_ALERT 21
+#define SSL3_RT_HANDSHAKE 22
+#define SSL3_RT_APPLICATION_DATA 23
+#define TLS1_RT_HEARTBEAT 24
+
+#define SSL3_AL_WARNING 1
+#define SSL3_AL_FATAL 2
+
+#define SSL3_AD_CLOSE_NOTIFY 0
+#define SSL3_AD_UNEXPECTED_MESSAGE 10 /* fatal */
+#define SSL3_AD_BAD_RECORD_MAC 20 /* fatal */
+#define SSL3_AD_DECOMPRESSION_FAILURE 30 /* fatal */
+#define SSL3_AD_HANDSHAKE_FAILURE 40 /* fatal */
+#define SSL3_AD_NO_CERTIFICATE 41
+#define SSL3_AD_BAD_CERTIFICATE 42
+#define SSL3_AD_UNSUPPORTED_CERTIFICATE 43
+#define SSL3_AD_CERTIFICATE_REVOKED 44
+#define SSL3_AD_CERTIFICATE_EXPIRED 45
+#define SSL3_AD_CERTIFICATE_UNKNOWN 46
+#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */
+
+#define TLS1_HB_REQUEST 1
+#define TLS1_HB_RESPONSE 2
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+typedef struct ssl3_record_st
+ {
+/*r */ int type; /* type of record */
+/*rw*/ unsigned int length; /* How many bytes available */
+/*r */ unsigned int off; /* read/write offset into 'buf' */
+/*rw*/ unsigned char *data; /* pointer to the record data */
+/*rw*/ unsigned char *input; /* where the decode bytes are */
+/*r */ unsigned char *comp; /* only used with decompression - malloc()ed */
+/*r */ unsigned long epoch; /* epoch number, needed by DTLS1 */
+/*r */ unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
+ } SSL3_RECORD;
+
+typedef struct ssl3_buffer_st
+ {
+ unsigned char *buf; /* at least SSL3_RT_MAX_PACKET_SIZE bytes,
+ * see ssl3_setup_buffers() */
+ size_t len; /* buffer size */
+ int offset; /* where to 'copy from' */
+ int left; /* how many bytes left */
+ } SSL3_BUFFER;
+
+#endif
+
+#define SSL3_CT_RSA_SIGN 1
+#define SSL3_CT_DSS_SIGN 2
+#define SSL3_CT_RSA_FIXED_DH 3
+#define SSL3_CT_DSS_FIXED_DH 4
+#define SSL3_CT_RSA_EPHEMERAL_DH 5
+#define SSL3_CT_DSS_EPHEMERAL_DH 6
+#define SSL3_CT_FORTEZZA_DMS 20
+/* SSL3_CT_NUMBER is used to size arrays and it must be large
+ * enough to contain all of the cert types defined either for
+ * SSLv3 and TLSv1.
+ */
+#define SSL3_CT_NUMBER 9
+
+
+#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001
+#define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002
+#define SSL3_FLAGS_POP_BUFFER 0x0004
+#define TLS1_FLAGS_TLS_PADDING_BUG 0x0008
+#define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010
+#define TLS1_FLAGS_KEEP_HANDSHAKE 0x0020
+#define SSL3_FLAGS_CCS_OK 0x0080
+
+/* SSL3_FLAGS_SGC_RESTART_DONE is set when we
+ * restart a handshake because of MS SGC and so prevents us
+ * from restarting the handshake in a loop. It's reset on a
+ * renegotiation, so effectively limits the client to one restart
+ * per negotiation. This limits the possibility of a DDoS
+ * attack where the client handshakes in a loop using SGC to
+ * restart. Servers which permit renegotiation can still be
+ * effected, but we can't prevent that.
+ */
+#define SSL3_FLAGS_SGC_RESTART_DONE 0x0040
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+typedef struct ssl3_state_st
+ {
+ long flags;
+ int delay_buf_pop_ret;
+
+ unsigned char read_sequence[8];
+ int read_mac_secret_size;
+ unsigned char read_mac_secret[EVP_MAX_MD_SIZE];
+ unsigned char write_sequence[8];
+ int write_mac_secret_size;
+ unsigned char write_mac_secret[EVP_MAX_MD_SIZE];
+
+ unsigned char server_random[SSL3_RANDOM_SIZE];
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+
+ /* flags for countermeasure against known-IV weakness */
+ int need_empty_fragments;
+ int empty_fragment_done;
+
+ /* The value of 'extra' when the buffers were initialized */
+ int init_extra;
+
+ SSL3_BUFFER rbuf; /* read IO goes into here */
+ SSL3_BUFFER wbuf; /* write IO goes into here */
+
+ SSL3_RECORD rrec; /* each decoded record goes in here */
+ SSL3_RECORD wrec; /* goes out from here */
+
+ /* storage for Alert/Handshake protocol data received but not
+ * yet processed by ssl3_read_bytes: */
+ unsigned char alert_fragment[2];
+ unsigned int alert_fragment_len;
+ unsigned char handshake_fragment[4];
+ unsigned int handshake_fragment_len;
+
+ /* partial write - check the numbers match */
+ unsigned int wnum; /* number of bytes sent so far */
+ int wpend_tot; /* number bytes written */
+ int wpend_type;
+ int wpend_ret; /* number of bytes submitted */
+ const unsigned char *wpend_buf;
+
+ /* used during startup, digest all incoming/outgoing packets */
+ BIO *handshake_buffer;
+ /* When set of handshake digests is determined, buffer is hashed
+ * and freed and MD_CTX-es for all required digests are stored in
+ * this array */
+ EVP_MD_CTX **handshake_dgst;
+ /* this is set whenerver we see a change_cipher_spec message
+ * come in when we are not looking for one */
+ int change_cipher_spec;
+
+ int warn_alert;
+ int fatal_alert;
+ /* we allow one fatal and one warning alert to be outstanding,
+ * send close alert via the warning alert */
+ int alert_dispatch;
+ unsigned char send_alert[2];
+
+ /* This flag is set when we should renegotiate ASAP, basically when
+ * there is no more data in the read or write buffers */
+ int renegotiate;
+ int total_renegotiations;
+ int num_renegotiations;
+
+ int in_read_app_data;
+
+ /* Opaque PRF input as used for the current handshake.
+ * These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined
+ * (otherwise, they are merely present to improve binary compatibility) */
+ void *client_opaque_prf_input;
+ size_t client_opaque_prf_input_len;
+ void *server_opaque_prf_input;
+ size_t server_opaque_prf_input_len;
+
+ struct {
+ /* actually only needs to be 16+20 */
+ unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
+
+ /* actually only need to be 16+20 for SSLv3 and 12 for TLS */
+ unsigned char finish_md[EVP_MAX_MD_SIZE*2];
+ int finish_md_len;
+ unsigned char peer_finish_md[EVP_MAX_MD_SIZE*2];
+ int peer_finish_md_len;
+
+ unsigned long message_size;
+ int message_type;
+
+ /* used to hold the new cipher we are going to use */
+ const SSL_CIPHER *new_cipher;
+#ifndef OPENSSL_NO_DH
+ DH *dh;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+ EC_KEY *ecdh; /* holds short lived ECDH key */
+#endif
+
+ /* used when SSL_ST_FLUSH_DATA is entered */
+ int next_state;
+
+ int reuse_message;
+
+ /* used for certificate requests */
+ int cert_req;
+ int ctype_num;
+ char ctype[SSL3_CT_NUMBER];
+ STACK_OF(X509_NAME) *ca_names;
+
+ int use_rsa_tmp;
+
+ int key_block_length;
+ unsigned char *key_block;
+
+ const EVP_CIPHER *new_sym_enc;
+ const EVP_MD *new_hash;
+ int new_mac_pkey_type;
+ int new_mac_secret_size;
+#ifndef OPENSSL_NO_COMP
+ const SSL_COMP *new_compression;
+#else
+ char *new_compression;
+#endif
+ int cert_request;
+ } tmp;
+
+ /* Connection binding to prevent renegotiation attacks */
+ unsigned char previous_client_finished[EVP_MAX_MD_SIZE];
+ unsigned char previous_client_finished_len;
+ unsigned char previous_server_finished[EVP_MAX_MD_SIZE];
+ unsigned char previous_server_finished_len;
+ int send_connection_binding; /* TODOEKR */
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ /* Set if we saw the Next Protocol Negotiation extension from our peer. */
+ int next_proto_neg_seen;
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef OPENSSL_NO_EC
+ /* This is set to true if we believe that this is a version of Safari
+ * running on OS X 10.6 or newer. We wish to know this because Safari
+ * on 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */
+ char is_probably_safari;
+#endif /* !OPENSSL_NO_EC */
+#endif /* !OPENSSL_NO_TLSEXT */
+ } SSL3_STATE;
+
+#endif
+
+/* SSLv3 */
+/*client */
+/* extra state */
+#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT)
+#ifndef OPENSSL_NO_SCTP
+#define DTLS1_SCTP_ST_CW_WRITE_SOCK (0x310|SSL_ST_CONNECT)
+#define DTLS1_SCTP_ST_CR_READ_SOCK (0x320|SSL_ST_CONNECT)
+#endif
+/* write to server */
+#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT)
+/* read from server */
+#define SSL3_ST_CR_SRVR_HELLO_A (0x120|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SRVR_HELLO_B (0x121|SSL_ST_CONNECT)
+#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT)
+#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_A (0x130|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_B (0x131|SSL_ST_CONNECT)
+#define SSL3_ST_CR_KEY_EXCH_A (0x140|SSL_ST_CONNECT)
+#define SSL3_ST_CR_KEY_EXCH_B (0x141|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_REQ_A (0x150|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_REQ_B (0x151|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SRVR_DONE_A (0x160|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SRVR_DONE_B (0x161|SSL_ST_CONNECT)
+/* write to server */
+#define SSL3_ST_CW_CERT_A (0x170|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_B (0x171|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_C (0x172|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_D (0x173|SSL_ST_CONNECT)
+#define SSL3_ST_CW_KEY_EXCH_A (0x180|SSL_ST_CONNECT)
+#define SSL3_ST_CW_KEY_EXCH_B (0x181|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_VRFY_A (0x190|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_VRFY_B (0x191|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CHANGE_A (0x1A0|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CHANGE_B (0x1A1|SSL_ST_CONNECT)
+#ifndef OPENSSL_NO_NEXTPROTONEG
+#define SSL3_ST_CW_NEXT_PROTO_A (0x200|SSL_ST_CONNECT)
+#define SSL3_ST_CW_NEXT_PROTO_B (0x201|SSL_ST_CONNECT)
+#endif
+#define SSL3_ST_CW_FINISHED_A (0x1B0|SSL_ST_CONNECT)
+#define SSL3_ST_CW_FINISHED_B (0x1B1|SSL_ST_CONNECT)
+/* read from server */
+#define SSL3_ST_CR_CHANGE_A (0x1C0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CHANGE_B (0x1C1|SSL_ST_CONNECT)
+#define SSL3_ST_CR_FINISHED_A (0x1D0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_STATUS_A (0x1F0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_STATUS_B (0x1F1|SSL_ST_CONNECT)
+
+/* server */
+/* extra state */
+#define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT)
+#ifndef OPENSSL_NO_SCTP
+#define DTLS1_SCTP_ST_SW_WRITE_SOCK (0x310|SSL_ST_ACCEPT)
+#define DTLS1_SCTP_ST_SR_READ_SOCK (0x320|SSL_ST_ACCEPT)
+#endif
+/* read from client */
+/* Do not change the number values, they do matter */
+#define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CLNT_HELLO_B (0x111|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CLNT_HELLO_C (0x112|SSL_ST_ACCEPT)
+/* write to client */
+#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT)
+#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_HELLO_REQ_A (0x120|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_HELLO_REQ_B (0x121|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_HELLO_REQ_C (0x122|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SRVR_HELLO_A (0x130|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SRVR_HELLO_B (0x131|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_A (0x140|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_B (0x141|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_KEY_EXCH_A (0x150|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_KEY_EXCH_B (0x151|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_REQ_A (0x160|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_REQ_B (0x161|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SRVR_DONE_A (0x170|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SRVR_DONE_B (0x171|SSL_ST_ACCEPT)
+/* read from client */
+#define SSL3_ST_SR_CERT_A (0x180|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CERT_B (0x181|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_KEY_EXCH_A (0x190|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_KEY_EXCH_B (0x191|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CERT_VRFY_A (0x1A0|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CERT_VRFY_B (0x1A1|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CHANGE_A (0x1B0|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CHANGE_B (0x1B1|SSL_ST_ACCEPT)
+#ifndef OPENSSL_NO_NEXTPROTONEG
+#define SSL3_ST_SR_NEXT_PROTO_A (0x210|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_NEXT_PROTO_B (0x211|SSL_ST_ACCEPT)
+#endif
+#define SSL3_ST_SR_FINISHED_A (0x1C0|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_FINISHED_B (0x1C1|SSL_ST_ACCEPT)
+/* write to client */
+#define SSL3_ST_SW_CHANGE_A (0x1D0|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CHANGE_B (0x1D1|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_FINISHED_A (0x1E0|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_STATUS_A (0x200|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_STATUS_B (0x201|SSL_ST_ACCEPT)
+
+#define SSL3_MT_HELLO_REQUEST 0
+#define SSL3_MT_CLIENT_HELLO 1
+#define SSL3_MT_SERVER_HELLO 2
+#define SSL3_MT_NEWSESSION_TICKET 4
+#define SSL3_MT_CERTIFICATE 11
+#define SSL3_MT_SERVER_KEY_EXCHANGE 12
+#define SSL3_MT_CERTIFICATE_REQUEST 13
+#define SSL3_MT_SERVER_DONE 14
+#define SSL3_MT_CERTIFICATE_VERIFY 15
+#define SSL3_MT_CLIENT_KEY_EXCHANGE 16
+#define SSL3_MT_FINISHED 20
+#define SSL3_MT_CERTIFICATE_STATUS 22
+#ifndef OPENSSL_NO_NEXTPROTONEG
+#define SSL3_MT_NEXT_PROTO 67
+#endif
+#define DTLS1_MT_HELLO_VERIFY_REQUEST 3
+
+
+#define SSL3_MT_CCS 1
+
+/* These are used when changing over to a new cipher */
+#define SSL3_CC_READ 0x01
+#define SSL3_CC_WRITE 0x02
+#define SSL3_CC_CLIENT 0x10
+#define SSL3_CC_SERVER 0x20
+#define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE)
+#define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ)
+#define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ)
+#define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER|SSL3_CC_WRITE)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/drivers/builtin_openssl/crypto/stack/stack.h b/drivers/builtin_openssl2/openssl/stack.h
index ce35e554eb..ce35e554eb 100644
--- a/drivers/builtin_openssl/crypto/stack/stack.h
+++ b/drivers/builtin_openssl2/openssl/stack.h
diff --git a/drivers/builtin_openssl/crypto/symhacks.h b/drivers/builtin_openssl2/openssl/symhacks.h
index bd2f000d59..bd2f000d59 100644
--- a/drivers/builtin_openssl/crypto/symhacks.h
+++ b/drivers/builtin_openssl2/openssl/symhacks.h
diff --git a/drivers/builtin_openssl/openssl/tls1.h b/drivers/builtin_openssl2/openssl/tls1.h
index c992091e30..c992091e30 100644
--- a/drivers/builtin_openssl/openssl/tls1.h
+++ b/drivers/builtin_openssl2/openssl/tls1.h
diff --git a/drivers/builtin_openssl/crypto/ts/ts.h b/drivers/builtin_openssl2/openssl/ts.h
index c2448e3c3b..c2448e3c3b 100644
--- a/drivers/builtin_openssl/crypto/ts/ts.h
+++ b/drivers/builtin_openssl2/openssl/ts.h
diff --git a/drivers/builtin_openssl/crypto/txt_db/txt_db.h b/drivers/builtin_openssl2/openssl/txt_db.h
index 6abe435bc8..6abe435bc8 100644
--- a/drivers/builtin_openssl/crypto/txt_db/txt_db.h
+++ b/drivers/builtin_openssl2/openssl/txt_db.h
diff --git a/drivers/builtin_openssl/crypto/ui/ui.h b/drivers/builtin_openssl2/openssl/ui.h
index bd78aa413f..bd78aa413f 100644
--- a/drivers/builtin_openssl/crypto/ui/ui.h
+++ b/drivers/builtin_openssl2/openssl/ui.h
diff --git a/drivers/builtin_openssl/crypto/ui/ui_compat.h b/drivers/builtin_openssl2/openssl/ui_compat.h
index b35c9bb7fd..b35c9bb7fd 100644
--- a/drivers/builtin_openssl/crypto/ui/ui_compat.h
+++ b/drivers/builtin_openssl2/openssl/ui_compat.h
diff --git a/drivers/builtin_openssl/crypto/whrlpool/whrlpool.h b/drivers/builtin_openssl2/openssl/whrlpool.h
index 9e01f5b076..9e01f5b076 100644
--- a/drivers/builtin_openssl/crypto/whrlpool/whrlpool.h
+++ b/drivers/builtin_openssl2/openssl/whrlpool.h
diff --git a/drivers/builtin_openssl/crypto/x509/x509.h b/drivers/builtin_openssl2/openssl/x509.h
index 092dd7450d..092dd7450d 100644
--- a/drivers/builtin_openssl/crypto/x509/x509.h
+++ b/drivers/builtin_openssl2/openssl/x509.h
diff --git a/drivers/builtin_openssl/crypto/x509/x509_vfy.h b/drivers/builtin_openssl2/openssl/x509_vfy.h
index fe09b30aaa..fe09b30aaa 100644
--- a/drivers/builtin_openssl/crypto/x509/x509_vfy.h
+++ b/drivers/builtin_openssl2/openssl/x509_vfy.h
diff --git a/drivers/builtin_openssl/crypto/x509v3/x509v3.h b/drivers/builtin_openssl2/openssl/x509v3.h
index b308abe7cd..b308abe7cd 100644
--- a/drivers/builtin_openssl/crypto/x509v3/x509v3.h
+++ b/drivers/builtin_openssl2/openssl/x509v3.h
diff --git a/drivers/builtin_openssl/ssl/bio_ssl.c b/drivers/builtin_openssl2/ssl/bio_ssl.c
index e9552caee2..e9552caee2 100644
--- a/drivers/builtin_openssl/ssl/bio_ssl.c
+++ b/drivers/builtin_openssl2/ssl/bio_ssl.c
diff --git a/drivers/builtin_openssl2/ssl/d1_both.c b/drivers/builtin_openssl2/ssl/d1_both.c
new file mode 100644
index 0000000000..04aa23107e
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/d1_both.c
@@ -0,0 +1,1617 @@
+/* ssl/d1_both.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8)
+
+#define RSMBLY_BITMASK_MARK(bitmask, start, end) { \
+ if ((end) - (start) <= 8) { \
+ long ii; \
+ for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \
+ } else { \
+ long ii; \
+ bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \
+ for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \
+ bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \
+ } }
+
+#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \
+ long ii; \
+ OPENSSL_assert((msg_len) > 0); \
+ is_complete = 1; \
+ if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \
+ if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \
+ if (bitmask[ii] != 0xff) { is_complete = 0; break; } }
+
+#if 0
+#define RSMBLY_BITMASK_PRINT(bitmask, msg_len) { \
+ long ii; \
+ printf("bitmask: "); for (ii = 0; ii < (msg_len); ii++) \
+ printf("%d ", (bitmask[ii >> 3] & (1 << (ii & 7))) >> (ii & 7)); \
+ printf("\n"); }
+#endif
+
+static unsigned char bitmask_start_values[] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
+static unsigned char bitmask_end_values[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
+
+/* XDTLS: figure out the right values */
+static unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28};
+
+static unsigned int dtls1_guess_mtu(unsigned int curr_mtu);
+static void dtls1_fix_message_header(SSL *s, unsigned long frag_off,
+ unsigned long frag_len);
+static unsigned char *dtls1_write_message_header(SSL *s,
+ unsigned char *p);
+static void dtls1_set_message_header_int(SSL *s, unsigned char mt,
+ unsigned long len, unsigned short seq_num, unsigned long frag_off,
+ unsigned long frag_len);
+static long dtls1_get_message_fragment(SSL *s, int st1, int stn,
+ long max, int *ok);
+
+static hm_fragment *
+dtls1_hm_fragment_new(unsigned long frag_len, int reassembly)
+ {
+ hm_fragment *frag = NULL;
+ unsigned char *buf = NULL;
+ unsigned char *bitmask = NULL;
+
+ frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
+ if ( frag == NULL)
+ return NULL;
+
+ if (frag_len)
+ {
+ buf = (unsigned char *)OPENSSL_malloc(frag_len);
+ if ( buf == NULL)
+ {
+ OPENSSL_free(frag);
+ return NULL;
+ }
+ }
+
+ /* zero length fragment gets zero frag->fragment */
+ frag->fragment = buf;
+
+ /* Initialize reassembly bitmask if necessary */
+ if (reassembly)
+ {
+ bitmask = (unsigned char *)OPENSSL_malloc(RSMBLY_BITMASK_SIZE(frag_len));
+ if (bitmask == NULL)
+ {
+ if (buf != NULL) OPENSSL_free(buf);
+ OPENSSL_free(frag);
+ return NULL;
+ }
+ memset(bitmask, 0, RSMBLY_BITMASK_SIZE(frag_len));
+ }
+
+ frag->reassembly = bitmask;
+
+ return frag;
+ }
+
+static void
+dtls1_hm_fragment_free(hm_fragment *frag)
+ {
+
+ if (frag->msg_header.is_ccs)
+ {
+ EVP_CIPHER_CTX_free(frag->msg_header.saved_retransmit_state.enc_write_ctx);
+ EVP_MD_CTX_destroy(frag->msg_header.saved_retransmit_state.write_hash);
+ }
+ if (frag->fragment) OPENSSL_free(frag->fragment);
+ if (frag->reassembly) OPENSSL_free(frag->reassembly);
+ OPENSSL_free(frag);
+ }
+
+/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
+int dtls1_do_write(SSL *s, int type)
+ {
+ int ret;
+ int curr_mtu;
+ unsigned int len, frag_off, mac_size, blocksize;
+
+ /* AHA! Figure out the MTU, and stick to the right size */
+ if (s->d1->mtu < dtls1_min_mtu() && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
+ {
+ s->d1->mtu =
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+
+ /* I've seen the kernel return bogus numbers when it doesn't know
+ * (initial write), so just make sure we have a reasonable number */
+ if (s->d1->mtu < dtls1_min_mtu())
+ {
+ s->d1->mtu = 0;
+ s->d1->mtu = dtls1_guess_mtu(s->d1->mtu);
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
+ s->d1->mtu, NULL);
+ }
+ }
+#if 0
+ mtu = s->d1->mtu;
+
+ fprintf(stderr, "using MTU = %d\n", mtu);
+
+ mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
+
+ curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s));
+
+ if ( curr_mtu > 0)
+ mtu = curr_mtu;
+ else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0)
+ return ret;
+
+ if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu)
+ {
+ ret = BIO_flush(SSL_get_wbio(s));
+ if ( ret <= 0)
+ return ret;
+ mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
+ }
+#endif
+
+ OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu()); /* should have something reasonable now */
+
+ if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE)
+ OPENSSL_assert(s->init_num ==
+ (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);
+
+ if (s->write_hash)
+ mac_size = EVP_MD_CTX_size(s->write_hash);
+ else
+ mac_size = 0;
+
+ if (s->enc_write_ctx &&
+ (EVP_CIPHER_mode( s->enc_write_ctx->cipher) & EVP_CIPH_CBC_MODE))
+ blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
+ else
+ blocksize = 0;
+
+ frag_off = 0;
+ while( s->init_num)
+ {
+ curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) -
+ DTLS1_RT_HEADER_LENGTH - mac_size - blocksize;
+
+ if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH)
+ {
+ /* grr.. we could get an error if MTU picked was wrong */
+ ret = BIO_flush(SSL_get_wbio(s));
+ if ( ret <= 0)
+ return ret;
+ curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH -
+ mac_size - blocksize;
+ }
+
+ if ( s->init_num > curr_mtu)
+ len = curr_mtu;
+ else
+ len = s->init_num;
+
+
+ /* XDTLS: this function is too long. split out the CCS part */
+ if ( type == SSL3_RT_HANDSHAKE)
+ {
+ if ( s->init_off != 0)
+ {
+ OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH);
+ s->init_off -= DTLS1_HM_HEADER_LENGTH;
+ s->init_num += DTLS1_HM_HEADER_LENGTH;
+
+ if ( s->init_num > curr_mtu)
+ len = curr_mtu;
+ else
+ len = s->init_num;
+ }
+
+ dtls1_fix_message_header(s, frag_off,
+ len - DTLS1_HM_HEADER_LENGTH);
+
+ dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]);
+
+ OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH);
+ }
+
+ ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off],
+ len);
+ if (ret < 0)
+ {
+ /* might need to update MTU here, but we don't know
+ * which previous packet caused the failure -- so can't
+ * really retransmit anything. continue as if everything
+ * is fine and wait for an alert to handle the
+ * retransmit
+ */
+ if ( BIO_ctrl(SSL_get_wbio(s),
+ BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 )
+ s->d1->mtu = BIO_ctrl(SSL_get_wbio(s),
+ BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+ else
+ return(-1);
+ }
+ else
+ {
+
+ /* bad if this assert fails, only part of the handshake
+ * message got sent. but why would this happen? */
+ OPENSSL_assert(len == (unsigned int)ret);
+
+ if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
+ {
+ /* should not be done for 'Hello Request's, but in that case
+ * we'll ignore the result anyway */
+ unsigned char *p = (unsigned char *)&s->init_buf->data[s->init_off];
+ const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+ int xlen;
+
+ if (frag_off == 0 && s->version != DTLS1_BAD_VER)
+ {
+ /* reconstruct message header is if it
+ * is being sent in single fragment */
+ *p++ = msg_hdr->type;
+ l2n3(msg_hdr->msg_len,p);
+ s2n (msg_hdr->seq,p);
+ l2n3(0,p);
+ l2n3(msg_hdr->msg_len,p);
+ p -= DTLS1_HM_HEADER_LENGTH;
+ xlen = ret;
+ }
+ else
+ {
+ p += DTLS1_HM_HEADER_LENGTH;
+ xlen = ret - DTLS1_HM_HEADER_LENGTH;
+ }
+
+ ssl3_finish_mac(s, p, xlen);
+ }
+
+ if (ret == s->init_num)
+ {
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, type, s->init_buf->data,
+ (size_t)(s->init_off + s->init_num), s,
+ s->msg_callback_arg);
+
+ s->init_off = 0; /* done writing this message */
+ s->init_num = 0;
+
+ return(1);
+ }
+ s->init_off+=ret;
+ s->init_num-=ret;
+ frag_off += (ret -= DTLS1_HM_HEADER_LENGTH);
+ }
+ }
+ return(0);
+ }
+
+
+/* Obtain handshake message of message type 'mt' (any if mt == -1),
+ * maximum acceptable body length 'max'.
+ * Read an entire handshake message. Handshake messages arrive in
+ * fragments.
+ */
+long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
+ {
+ int i, al;
+ struct hm_header_st *msg_hdr;
+ unsigned char *p;
+ unsigned long msg_len;
+
+ /* s3->tmp is used to store messages that are unexpected, caused
+ * by the absence of an optional handshake message */
+ if (s->s3->tmp.reuse_message)
+ {
+ s->s3->tmp.reuse_message=0;
+ if ((mt >= 0) && (s->s3->tmp.message_type != mt))
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+ *ok=1;
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+ s->init_num = (int)s->s3->tmp.message_size;
+ return s->init_num;
+ }
+
+ msg_hdr = &s->d1->r_msg_hdr;
+ memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+
+again:
+ i = dtls1_get_message_fragment(s, st1, stn, max, ok);
+ if ( i == DTLS1_HM_BAD_FRAGMENT ||
+ i == DTLS1_HM_FRAGMENT_RETRY) /* bad fragment received */
+ goto again;
+ else if ( i <= 0 && !*ok)
+ return i;
+
+ p = (unsigned char *)s->init_buf->data;
+ msg_len = msg_hdr->msg_len;
+
+ /* reconstruct message header */
+ *(p++) = msg_hdr->type;
+ l2n3(msg_len,p);
+ s2n (msg_hdr->seq,p);
+ l2n3(0,p);
+ l2n3(msg_len,p);
+ if (s->version != DTLS1_BAD_VER) {
+ p -= DTLS1_HM_HEADER_LENGTH;
+ msg_len += DTLS1_HM_HEADER_LENGTH;
+ }
+
+ ssl3_finish_mac(s, p, msg_len);
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+ p, msg_len,
+ s, s->msg_callback_arg);
+
+ memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+
+ /* Don't change sequence numbers while listening */
+ if (!s->d1->listen)
+ s->d1->handshake_read_seq++;
+
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+ return s->init_num;
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ *ok = 0;
+ return -1;
+ }
+
+
+static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max)
+ {
+ size_t frag_off,frag_len,msg_len;
+
+ msg_len = msg_hdr->msg_len;
+ frag_off = msg_hdr->frag_off;
+ frag_len = msg_hdr->frag_len;
+
+ /* sanity checking */
+ if ( (frag_off+frag_len) > msg_len)
+ {
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return SSL_AD_ILLEGAL_PARAMETER;
+ }
+
+ if ( (frag_off+frag_len) > (unsigned long)max)
+ {
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return SSL_AD_ILLEGAL_PARAMETER;
+ }
+
+ if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
+ {
+ /* msg_len is limited to 2^24, but is effectively checked
+ * against max above */
+ if (!BUF_MEM_grow_clean(s->init_buf,msg_len+DTLS1_HM_HEADER_LENGTH))
+ {
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB);
+ return SSL_AD_INTERNAL_ERROR;
+ }
+
+ s->s3->tmp.message_size = msg_len;
+ s->d1->r_msg_hdr.msg_len = msg_len;
+ s->s3->tmp.message_type = msg_hdr->type;
+ s->d1->r_msg_hdr.type = msg_hdr->type;
+ s->d1->r_msg_hdr.seq = msg_hdr->seq;
+ }
+ else if (msg_len != s->d1->r_msg_hdr.msg_len)
+ {
+ /* They must be playing with us! BTW, failure to enforce
+ * upper limit would open possibility for buffer overrun. */
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return SSL_AD_ILLEGAL_PARAMETER;
+ }
+
+ return 0; /* no error */
+ }
+
+
+static int
+dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
+ {
+ /* (0) check whether the desired fragment is available
+ * if so:
+ * (1) copy over the fragment to s->init_buf->data[]
+ * (2) update s->init_num
+ */
+ pitem *item;
+ hm_fragment *frag;
+ int al;
+
+ *ok = 0;
+ item = pqueue_peek(s->d1->buffered_messages);
+ if ( item == NULL)
+ return 0;
+
+ frag = (hm_fragment *)item->data;
+
+ /* Don't return if reassembly still in progress */
+ if (frag->reassembly != NULL)
+ return 0;
+
+ if ( s->d1->handshake_read_seq == frag->msg_header.seq)
+ {
+ unsigned long frag_len = frag->msg_header.frag_len;
+ pqueue_pop(s->d1->buffered_messages);
+
+ al=dtls1_preprocess_fragment(s,&frag->msg_header,max);
+
+ if (al==0) /* no alert */
+ {
+ unsigned char *p = (unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
+ memcpy(&p[frag->msg_header.frag_off],
+ frag->fragment,frag->msg_header.frag_len);
+ }
+
+ dtls1_hm_fragment_free(frag);
+ pitem_free(item);
+
+ if (al==0)
+ {
+ *ok = 1;
+ return frag_len;
+ }
+
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ s->init_num = 0;
+ *ok = 0;
+ return -1;
+ }
+ else
+ return 0;
+ }
+
+
+static int
+dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
+ {
+ hm_fragment *frag = NULL;
+ pitem *item = NULL;
+ int i = -1, is_complete;
+ unsigned char seq64be[8];
+ unsigned long frag_len = msg_hdr->frag_len, max_len;
+
+ if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
+ goto err;
+
+ /* Determine maximum allowed message size. Depends on (user set)
+ * maximum certificate length, but 16k is minimum.
+ */
+ if (DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH < s->max_cert_list)
+ max_len = s->max_cert_list;
+ else
+ max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
+
+ if ((msg_hdr->frag_off+frag_len) > max_len)
+ goto err;
+
+ /* Try to find item in queue */
+ memset(seq64be,0,sizeof(seq64be));
+ seq64be[6] = (unsigned char) (msg_hdr->seq>>8);
+ seq64be[7] = (unsigned char) msg_hdr->seq;
+ item = pqueue_find(s->d1->buffered_messages, seq64be);
+
+ if (item == NULL)
+ {
+ frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1);
+ if ( frag == NULL)
+ goto err;
+ memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+ frag->msg_header.frag_len = frag->msg_header.msg_len;
+ frag->msg_header.frag_off = 0;
+ }
+ else
+ {
+ frag = (hm_fragment*) item->data;
+ if (frag->msg_header.msg_len != msg_hdr->msg_len)
+ {
+ item = NULL;
+ frag = NULL;
+ goto err;
+ }
+ }
+
+
+ /* If message is already reassembled, this must be a
+ * retransmit and can be dropped.
+ */
+ if (frag->reassembly == NULL)
+ {
+ unsigned char devnull [256];
+
+ while (frag_len)
+ {
+ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+ devnull,
+ frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
+ if (i<=0) goto err;
+ frag_len -= i;
+ }
+ return DTLS1_HM_FRAGMENT_RETRY;
+ }
+
+ /* read the body of the fragment (header has already been read */
+ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+ frag->fragment + msg_hdr->frag_off,frag_len,0);
+ if (i<=0 || (unsigned long)i!=frag_len)
+ goto err;
+
+ RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off,
+ (long)(msg_hdr->frag_off + frag_len));
+
+ RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len,
+ is_complete);
+
+ if (is_complete)
+ {
+ OPENSSL_free(frag->reassembly);
+ frag->reassembly = NULL;
+ }
+
+ if (item == NULL)
+ {
+ memset(seq64be,0,sizeof(seq64be));
+ seq64be[6] = (unsigned char)(msg_hdr->seq>>8);
+ seq64be[7] = (unsigned char)(msg_hdr->seq);
+
+ item = pitem_new(seq64be, frag);
+ if (item == NULL)
+ {
+ i = -1;
+ goto err;
+ }
+
+ pqueue_insert(s->d1->buffered_messages, item);
+ }
+
+ return DTLS1_HM_FRAGMENT_RETRY;
+
+err:
+ if (frag != NULL) dtls1_hm_fragment_free(frag);
+ if (item != NULL) OPENSSL_free(item);
+ *ok = 0;
+ return i;
+ }
+
+
+static int
+dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
+{
+ int i=-1;
+ hm_fragment *frag = NULL;
+ pitem *item = NULL;
+ unsigned char seq64be[8];
+ unsigned long frag_len = msg_hdr->frag_len;
+
+ if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
+ goto err;
+
+ /* Try to find item in queue, to prevent duplicate entries */
+ memset(seq64be,0,sizeof(seq64be));
+ seq64be[6] = (unsigned char) (msg_hdr->seq>>8);
+ seq64be[7] = (unsigned char) msg_hdr->seq;
+ item = pqueue_find(s->d1->buffered_messages, seq64be);
+
+ /* If we already have an entry and this one is a fragment,
+ * don't discard it and rather try to reassemble it.
+ */
+ if (item != NULL && frag_len < msg_hdr->msg_len)
+ item = NULL;
+
+ /* Discard the message if sequence number was already there, is
+ * too far in the future, already in the queue or if we received
+ * a FINISHED before the SERVER_HELLO, which then must be a stale
+ * retransmit.
+ */
+ if (msg_hdr->seq <= s->d1->handshake_read_seq ||
+ msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL ||
+ (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED))
+ {
+ unsigned char devnull [256];
+
+ while (frag_len)
+ {
+ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+ devnull,
+ frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
+ if (i<=0) goto err;
+ frag_len -= i;
+ }
+ }
+ else
+ {
+ if (frag_len && frag_len < msg_hdr->msg_len)
+ return dtls1_reassemble_fragment(s, msg_hdr, ok);
+
+ frag = dtls1_hm_fragment_new(frag_len, 0);
+ if ( frag == NULL)
+ goto err;
+
+ memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+
+ if (frag_len)
+ {
+ /* read the body of the fragment (header has already been read */
+ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+ frag->fragment,frag_len,0);
+ if (i<=0 || (unsigned long)i!=frag_len)
+ goto err;
+ }
+
+ memset(seq64be,0,sizeof(seq64be));
+ seq64be[6] = (unsigned char)(msg_hdr->seq>>8);
+ seq64be[7] = (unsigned char)(msg_hdr->seq);
+
+ item = pitem_new(seq64be, frag);
+ if ( item == NULL)
+ goto err;
+
+ pqueue_insert(s->d1->buffered_messages, item);
+ }
+
+ return DTLS1_HM_FRAGMENT_RETRY;
+
+err:
+ if ( frag != NULL) dtls1_hm_fragment_free(frag);
+ if ( item != NULL) OPENSSL_free(item);
+ *ok = 0;
+ return i;
+ }
+
+
+static long
+dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
+ {
+ unsigned char wire[DTLS1_HM_HEADER_LENGTH];
+ unsigned long len, frag_off, frag_len;
+ int i,al;
+ struct hm_header_st msg_hdr;
+
+ redo:
+ /* see if we have the required fragment already */
+ if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok)
+ {
+ if (*ok) s->init_num = frag_len;
+ return frag_len;
+ }
+
+ /* read handshake message header */
+ i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,wire,
+ DTLS1_HM_HEADER_LENGTH, 0);
+ if (i <= 0) /* nbio, or an error */
+ {
+ s->rwstate=SSL_READING;
+ *ok = 0;
+ return i;
+ }
+ /* Handshake fails if message header is incomplete */
+ if (i != DTLS1_HM_HEADER_LENGTH)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+
+ /* parse the message fragment header */
+ dtls1_get_message_header(wire, &msg_hdr);
+
+ /*
+ * if this is a future (or stale) message it gets buffered
+ * (or dropped)--no further processing at this time
+ * While listening, we accept seq 1 (ClientHello with cookie)
+ * although we're still expecting seq 0 (ClientHello)
+ */
+ if (msg_hdr.seq != s->d1->handshake_read_seq && !(s->d1->listen && msg_hdr.seq == 1))
+ return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
+
+ len = msg_hdr.msg_len;
+ frag_off = msg_hdr.frag_off;
+ frag_len = msg_hdr.frag_len;
+
+ if (frag_len && frag_len < len)
+ return dtls1_reassemble_fragment(s, &msg_hdr, ok);
+
+ if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
+ wire[0] == SSL3_MT_HELLO_REQUEST)
+ {
+ /* The server may always send 'Hello Request' messages --
+ * we are doing a handshake anyway now, so ignore them
+ * if their format is correct. Does not count for
+ * 'Finished' MAC. */
+ if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0)
+ {
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+ wire, DTLS1_HM_HEADER_LENGTH, s,
+ s->msg_callback_arg);
+
+ s->init_num = 0;
+ goto redo;
+ }
+ else /* Incorrectly formated Hello request */
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+ }
+
+ if ((al=dtls1_preprocess_fragment(s,&msg_hdr,max)))
+ goto f_err;
+
+ /* XDTLS: ressurect this when restart is in place */
+ s->state=stn;
+
+ if ( frag_len > 0)
+ {
+ unsigned char *p=(unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
+
+ i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+ &p[frag_off],frag_len,0);
+ /* XDTLS: fix this--message fragments cannot span multiple packets */
+ if (i <= 0)
+ {
+ s->rwstate=SSL_READING;
+ *ok = 0;
+ return i;
+ }
+ }
+ else
+ i = 0;
+
+ /* XDTLS: an incorrectly formatted fragment should cause the
+ * handshake to fail */
+ if (i != (int)frag_len)
+ {
+ al=SSL3_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL3_AD_ILLEGAL_PARAMETER);
+ goto f_err;
+ }
+
+ *ok = 1;
+
+ /* Note that s->init_num is *not* used as current offset in
+ * s->init_buf->data, but as a counter summing up fragments'
+ * lengths: as soon as they sum up to handshake packet
+ * length, we assume we have got all the fragments. */
+ s->init_num = frag_len;
+ return frag_len;
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ s->init_num = 0;
+
+ *ok=0;
+ return(-1);
+ }
+
+int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen)
+ {
+ unsigned char *p,*d;
+ int i;
+ unsigned long l;
+
+ if (s->state == a)
+ {
+ d=(unsigned char *)s->init_buf->data;
+ p= &(d[DTLS1_HM_HEADER_LENGTH]);
+
+ i=s->method->ssl3_enc->final_finish_mac(s,
+ sender,slen,s->s3->tmp.finish_md);
+ s->s3->tmp.finish_md_len = i;
+ memcpy(p, s->s3->tmp.finish_md, i);
+ p+=i;
+ l=i;
+
+ /* Copy the finished so we can use it for
+ * renegotiation checks
+ */
+ if(s->type == SSL_ST_CONNECT)
+ {
+ OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_client_finished,
+ s->s3->tmp.finish_md, i);
+ s->s3->previous_client_finished_len=i;
+ }
+ else
+ {
+ OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_server_finished,
+ s->s3->tmp.finish_md, i);
+ s->s3->previous_server_finished_len=i;
+ }
+
+#ifdef OPENSSL_SYS_WIN16
+ /* MSVC 1.5 does not clear the top bytes of the word unless
+ * I do this.
+ */
+ l&=0xffff;
+#endif
+
+ d = dtls1_set_message_header(s, d, SSL3_MT_FINISHED, l, 0, l);
+ s->init_num=(int)l+DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+
+ s->state=b;
+ }
+
+ /* SSL3_ST_SEND_xxxxxx_HELLO_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+/* for these 2 messages, we need to
+ * ssl->enc_read_ctx re-init
+ * ssl->s3->read_sequence zero
+ * ssl->s3->read_mac_secret re-init
+ * ssl->session->read_sym_enc assign
+ * ssl->session->read_compression assign
+ * ssl->session->read_hash assign
+ */
+int dtls1_send_change_cipher_spec(SSL *s, int a, int b)
+ {
+ unsigned char *p;
+
+ if (s->state == a)
+ {
+ p=(unsigned char *)s->init_buf->data;
+ *p++=SSL3_MT_CCS;
+ s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+ s->init_num=DTLS1_CCS_HEADER_LENGTH;
+
+ if (s->version == DTLS1_BAD_VER) {
+ s->d1->next_handshake_write_seq++;
+ s2n(s->d1->handshake_write_seq,p);
+ s->init_num+=2;
+ }
+
+ s->init_off=0;
+
+ dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
+ s->d1->handshake_write_seq, 0, 0);
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 1);
+
+ s->state=b;
+ }
+
+ /* SSL3_ST_CW_CHANGE_B */
+ return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
+ }
+
+static int dtls1_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x)
+ {
+ int n;
+ unsigned char *p;
+
+ n=i2d_X509(x,NULL);
+ if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3)))
+ {
+ SSLerr(SSL_F_DTLS1_ADD_CERT_TO_BUF,ERR_R_BUF_LIB);
+ return 0;
+ }
+ p=(unsigned char *)&(buf->data[*l]);
+ l2n3(n,p);
+ i2d_X509(x,&p);
+ *l+=n+3;
+
+ return 1;
+ }
+unsigned long dtls1_output_cert_chain(SSL *s, X509 *x)
+ {
+ unsigned char *p;
+ int i;
+ unsigned long l= 3 + DTLS1_HM_HEADER_LENGTH;
+ BUF_MEM *buf;
+
+ /* TLSv1 sends a chain with nothing in it, instead of an alert */
+ buf=s->init_buf;
+ if (!BUF_MEM_grow_clean(buf,10))
+ {
+ SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
+ return(0);
+ }
+ if (x != NULL)
+ {
+ X509_STORE_CTX xs_ctx;
+
+ if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL))
+ {
+ SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB);
+ return(0);
+ }
+
+ X509_verify_cert(&xs_ctx);
+ /* Don't leave errors in the queue */
+ ERR_clear_error();
+ for (i=0; i < sk_X509_num(xs_ctx.chain); i++)
+ {
+ x = sk_X509_value(xs_ctx.chain, i);
+
+ if (!dtls1_add_cert_to_buf(buf, &l, x))
+ {
+ X509_STORE_CTX_cleanup(&xs_ctx);
+ return 0;
+ }
+ }
+ X509_STORE_CTX_cleanup(&xs_ctx);
+ }
+ /* Thawte special :-) */
+ for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++)
+ {
+ x=sk_X509_value(s->ctx->extra_certs,i);
+ if (!dtls1_add_cert_to_buf(buf, &l, x))
+ return 0;
+ }
+
+ l-= (3 + DTLS1_HM_HEADER_LENGTH);
+
+ p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]);
+ l2n3(l,p);
+ l+=3;
+ p=(unsigned char *)&(buf->data[0]);
+ p = dtls1_set_message_header(s, p, SSL3_MT_CERTIFICATE, l, 0, l);
+
+ l+=DTLS1_HM_HEADER_LENGTH;
+ return(l);
+ }
+
+int dtls1_read_failed(SSL *s, int code)
+ {
+ if ( code > 0)
+ {
+ fprintf( stderr, "invalid state reached %s:%d", __FILE__, __LINE__);
+ return 1;
+ }
+
+ if (!dtls1_is_timer_expired(s))
+ {
+ /* not a timeout, none of our business,
+ let higher layers handle this. in fact it's probably an error */
+ return code;
+ }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ if (!SSL_in_init(s) && !s->tlsext_hb_pending) /* done, no need to send a retransmit */
+#else
+ if (!SSL_in_init(s)) /* done, no need to send a retransmit */
+#endif
+ {
+ BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
+ return code;
+ }
+
+#if 0 /* for now, each alert contains only one record number */
+ item = pqueue_peek(state->rcvd_records);
+ if ( item )
+ {
+ /* send an alert immediately for all the missing records */
+ }
+ else
+#endif
+
+#if 0 /* no more alert sending, just retransmit the last set of messages */
+ if ( state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT)
+ ssl3_send_alert(s,SSL3_AL_WARNING,
+ DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+#endif
+
+ return dtls1_handle_timeout(s);
+ }
+
+int
+dtls1_get_queue_priority(unsigned short seq, int is_ccs)
+ {
+ /* The index of the retransmission queue actually is the message sequence number,
+ * since the queue only contains messages of a single handshake. However, the
+ * ChangeCipherSpec has no message sequence number and so using only the sequence
+ * will result in the CCS and Finished having the same index. To prevent this,
+ * the sequence number is multiplied by 2. In case of a CCS 1 is subtracted.
+ * This does not only differ CSS and Finished, it also maintains the order of the
+ * index (important for priority queues) and fits in the unsigned short variable.
+ */
+ return seq * 2 - is_ccs;
+ }
+
+int
+dtls1_retransmit_buffered_messages(SSL *s)
+ {
+ pqueue sent = s->d1->sent_messages;
+ piterator iter;
+ pitem *item;
+ hm_fragment *frag;
+ int found = 0;
+
+ iter = pqueue_iterator(sent);
+
+ for ( item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter))
+ {
+ frag = (hm_fragment *)item->data;
+ if ( dtls1_retransmit_message(s,
+ (unsigned short)dtls1_get_queue_priority(frag->msg_header.seq, frag->msg_header.is_ccs),
+ 0, &found) <= 0 && found)
+ {
+ fprintf(stderr, "dtls1_retransmit_message() failed\n");
+ return -1;
+ }
+ }
+
+ return 1;
+ }
+
+int
+dtls1_buffer_message(SSL *s, int is_ccs)
+ {
+ pitem *item;
+ hm_fragment *frag;
+ unsigned char seq64be[8];
+
+ /* this function is called immediately after a message has
+ * been serialized */
+ OPENSSL_assert(s->init_off == 0);
+
+ frag = dtls1_hm_fragment_new(s->init_num, 0);
+
+ memcpy(frag->fragment, s->init_buf->data, s->init_num);
+
+ if ( is_ccs)
+ {
+ OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
+ ((s->version==DTLS1_VERSION)?DTLS1_CCS_HEADER_LENGTH:3) == (unsigned int)s->init_num);
+ }
+ else
+ {
+ OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
+ DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num);
+ }
+
+ frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len;
+ frag->msg_header.seq = s->d1->w_msg_hdr.seq;
+ frag->msg_header.type = s->d1->w_msg_hdr.type;
+ frag->msg_header.frag_off = 0;
+ frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
+ frag->msg_header.is_ccs = is_ccs;
+
+ /* save current state*/
+ frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx;
+ frag->msg_header.saved_retransmit_state.write_hash = s->write_hash;
+ frag->msg_header.saved_retransmit_state.compress = s->compress;
+ frag->msg_header.saved_retransmit_state.session = s->session;
+ frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch;
+
+ memset(seq64be,0,sizeof(seq64be));
+ seq64be[6] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq,
+ frag->msg_header.is_ccs)>>8);
+ seq64be[7] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq,
+ frag->msg_header.is_ccs));
+
+ item = pitem_new(seq64be, frag);
+ if ( item == NULL)
+ {
+ dtls1_hm_fragment_free(frag);
+ return 0;
+ }
+
+#if 0
+ fprintf( stderr, "buffered messge: \ttype = %xx\n", msg_buf->type);
+ fprintf( stderr, "\t\t\t\t\tlen = %d\n", msg_buf->len);
+ fprintf( stderr, "\t\t\t\t\tseq_num = %d\n", msg_buf->seq_num);
+#endif
+
+ pqueue_insert(s->d1->sent_messages, item);
+ return 1;
+ }
+
+int
+dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
+ int *found)
+ {
+ int ret;
+ /* XDTLS: for now assuming that read/writes are blocking */
+ pitem *item;
+ hm_fragment *frag ;
+ unsigned long header_length;
+ unsigned char seq64be[8];
+ struct dtls1_retransmit_state saved_state;
+ unsigned char save_write_sequence[8];
+
+ /*
+ OPENSSL_assert(s->init_num == 0);
+ OPENSSL_assert(s->init_off == 0);
+ */
+
+ /* XDTLS: the requested message ought to be found, otherwise error */
+ memset(seq64be,0,sizeof(seq64be));
+ seq64be[6] = (unsigned char)(seq>>8);
+ seq64be[7] = (unsigned char)seq;
+
+ item = pqueue_find(s->d1->sent_messages, seq64be);
+ if ( item == NULL)
+ {
+ fprintf(stderr, "retransmit: message %d non-existant\n", seq);
+ *found = 0;
+ return 0;
+ }
+
+ *found = 1;
+ frag = (hm_fragment *)item->data;
+
+ if ( frag->msg_header.is_ccs)
+ header_length = DTLS1_CCS_HEADER_LENGTH;
+ else
+ header_length = DTLS1_HM_HEADER_LENGTH;
+
+ memcpy(s->init_buf->data, frag->fragment,
+ frag->msg_header.msg_len + header_length);
+ s->init_num = frag->msg_header.msg_len + header_length;
+
+ dtls1_set_message_header_int(s, frag->msg_header.type,
+ frag->msg_header.msg_len, frag->msg_header.seq, 0,
+ frag->msg_header.frag_len);
+
+ /* save current state */
+ saved_state.enc_write_ctx = s->enc_write_ctx;
+ saved_state.write_hash = s->write_hash;
+ saved_state.compress = s->compress;
+ saved_state.session = s->session;
+ saved_state.epoch = s->d1->w_epoch;
+ saved_state.epoch = s->d1->w_epoch;
+
+ s->d1->retransmitting = 1;
+
+ /* restore state in which the message was originally sent */
+ s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx;
+ s->write_hash = frag->msg_header.saved_retransmit_state.write_hash;
+ s->compress = frag->msg_header.saved_retransmit_state.compress;
+ s->session = frag->msg_header.saved_retransmit_state.session;
+ s->d1->w_epoch = frag->msg_header.saved_retransmit_state.epoch;
+
+ if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1)
+ {
+ memcpy(save_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence));
+ memcpy(s->s3->write_sequence, s->d1->last_write_sequence, sizeof(s->s3->write_sequence));
+ }
+
+ ret = dtls1_do_write(s, frag->msg_header.is_ccs ?
+ SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
+
+ /* restore current state */
+ s->enc_write_ctx = saved_state.enc_write_ctx;
+ s->write_hash = saved_state.write_hash;
+ s->compress = saved_state.compress;
+ s->session = saved_state.session;
+ s->d1->w_epoch = saved_state.epoch;
+
+ if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1)
+ {
+ memcpy(s->d1->last_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence));
+ memcpy(s->s3->write_sequence, save_write_sequence, sizeof(s->s3->write_sequence));
+ }
+
+ s->d1->retransmitting = 0;
+
+ (void)BIO_flush(SSL_get_wbio(s));
+ return ret;
+ }
+
+/* call this function when the buffered messages are no longer needed */
+void
+dtls1_clear_record_buffer(SSL *s)
+ {
+ pitem *item;
+
+ for(item = pqueue_pop(s->d1->sent_messages);
+ item != NULL; item = pqueue_pop(s->d1->sent_messages))
+ {
+ dtls1_hm_fragment_free((hm_fragment *)item->data);
+ pitem_free(item);
+ }
+ }
+
+
+unsigned char *
+dtls1_set_message_header(SSL *s, unsigned char *p, unsigned char mt,
+ unsigned long len, unsigned long frag_off, unsigned long frag_len)
+ {
+ /* Don't change sequence numbers while listening */
+ if (frag_off == 0 && !s->d1->listen)
+ {
+ s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+ s->d1->next_handshake_write_seq++;
+ }
+
+ dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq,
+ frag_off, frag_len);
+
+ return p += DTLS1_HM_HEADER_LENGTH;
+ }
+
+
+/* don't actually do the writing, wait till the MTU has been retrieved */
+static void
+dtls1_set_message_header_int(SSL *s, unsigned char mt,
+ unsigned long len, unsigned short seq_num, unsigned long frag_off,
+ unsigned long frag_len)
+ {
+ struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+ msg_hdr->type = mt;
+ msg_hdr->msg_len = len;
+ msg_hdr->seq = seq_num;
+ msg_hdr->frag_off = frag_off;
+ msg_hdr->frag_len = frag_len;
+ }
+
+static void
+dtls1_fix_message_header(SSL *s, unsigned long frag_off,
+ unsigned long frag_len)
+ {
+ struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+ msg_hdr->frag_off = frag_off;
+ msg_hdr->frag_len = frag_len;
+ }
+
+static unsigned char *
+dtls1_write_message_header(SSL *s, unsigned char *p)
+ {
+ struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+ *p++ = msg_hdr->type;
+ l2n3(msg_hdr->msg_len, p);
+
+ s2n(msg_hdr->seq, p);
+ l2n3(msg_hdr->frag_off, p);
+ l2n3(msg_hdr->frag_len, p);
+
+ return p;
+ }
+
+unsigned int
+dtls1_min_mtu(void)
+ {
+ return (g_probable_mtu[(sizeof(g_probable_mtu) /
+ sizeof(g_probable_mtu[0])) - 1]);
+ }
+
+static unsigned int
+dtls1_guess_mtu(unsigned int curr_mtu)
+ {
+ unsigned int i;
+
+ if ( curr_mtu == 0 )
+ return g_probable_mtu[0] ;
+
+ for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++)
+ if ( curr_mtu > g_probable_mtu[i])
+ return g_probable_mtu[i];
+
+ return curr_mtu;
+ }
+
+void
+dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
+ {
+ memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+ msg_hdr->type = *(data++);
+ n2l3(data, msg_hdr->msg_len);
+
+ n2s(data, msg_hdr->seq);
+ n2l3(data, msg_hdr->frag_off);
+ n2l3(data, msg_hdr->frag_len);
+ }
+
+void
+dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr)
+ {
+ memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st));
+
+ ccs_hdr->type = *(data++);
+ }
+
+int dtls1_shutdown(SSL *s)
+ {
+ int ret;
+#ifndef OPENSSL_NO_SCTP
+ if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
+ !(s->shutdown & SSL_SENT_SHUTDOWN))
+ {
+ ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
+ if (ret < 0) return -1;
+
+ if (ret == 0)
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1, NULL);
+ }
+#endif
+ ret = ssl3_shutdown(s);
+#ifndef OPENSSL_NO_SCTP
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
+#endif
+ return ret;
+ }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int
+dtls1_process_heartbeat(SSL *s)
+ {
+ unsigned char *p = &s->s3->rrec.data[0], *pl;
+ unsigned short hbtype;
+ unsigned int payload;
+ unsigned int padding = 16; /* Use minimum padding */
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+ &s->s3->rrec.data[0], s->s3->rrec.length,
+ s, s->msg_callback_arg);
+
+ /* Read type and payload length first */
+ if (1 + 2 + 16 > s->s3->rrec.length)
+ return 0; /* silently discard */
+ hbtype = *p++;
+ n2s(p, payload);
+ if (1 + 2 + payload + 16 > s->s3->rrec.length)
+ return 0; /* silently discard per RFC 6520 sec. 4 */
+ pl = p;
+
+ if (hbtype == TLS1_HB_REQUEST)
+ {
+ unsigned char *buffer, *bp;
+ unsigned int write_length = 1 /* heartbeat type */ +
+ 2 /* heartbeat length */ +
+ payload + padding;
+ int r;
+
+ if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
+ return 0;
+
+ /* Allocate memory for the response, size is 1 byte
+ * message type, plus 2 bytes payload length, plus
+ * payload, plus padding
+ */
+ buffer = OPENSSL_malloc(write_length);
+ bp = buffer;
+
+ /* Enter response type, length and copy payload */
+ *bp++ = TLS1_HB_RESPONSE;
+ s2n(payload, bp);
+ memcpy(bp, pl, payload);
+ bp += payload;
+ /* Random padding */
+ RAND_pseudo_bytes(bp, padding);
+
+ r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
+
+ if (r >= 0 && s->msg_callback)
+ s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buffer, write_length,
+ s, s->msg_callback_arg);
+
+ OPENSSL_free(buffer);
+
+ if (r < 0)
+ return r;
+ }
+ else if (hbtype == TLS1_HB_RESPONSE)
+ {
+ unsigned int seq;
+
+ /* We only send sequence numbers (2 bytes unsigned int),
+ * and 16 random bytes, so we just try to read the
+ * sequence number */
+ n2s(pl, seq);
+
+ if (payload == 18 && seq == s->tlsext_hb_seq)
+ {
+ dtls1_stop_timer(s);
+ s->tlsext_hb_seq++;
+ s->tlsext_hb_pending = 0;
+ }
+ }
+
+ return 0;
+ }
+
+int
+dtls1_heartbeat(SSL *s)
+ {
+ unsigned char *buf, *p;
+ int ret;
+ unsigned int payload = 18; /* Sequence number + random bytes */
+ unsigned int padding = 16; /* Use minimum padding */
+
+ /* Only send if peer supports and accepts HB requests... */
+ if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
+ s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS)
+ {
+ SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+ return -1;
+ }
+
+ /* ...and there is none in flight yet... */
+ if (s->tlsext_hb_pending)
+ {
+ SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING);
+ return -1;
+ }
+
+ /* ...and no handshake in progress. */
+ if (SSL_in_init(s) || s->in_handshake)
+ {
+ SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ /* Check if padding is too long, payload and padding
+ * must not exceed 2^14 - 3 = 16381 bytes in total.
+ */
+ OPENSSL_assert(payload + padding <= 16381);
+
+ /* Create HeartBeat message, we just use a sequence number
+ * as payload to distuingish different messages and add
+ * some random stuff.
+ * - Message Type, 1 byte
+ * - Payload Length, 2 bytes (unsigned int)
+ * - Payload, the sequence number (2 bytes uint)
+ * - Payload, random bytes (16 bytes uint)
+ * - Padding
+ */
+ buf = OPENSSL_malloc(1 + 2 + payload + padding);
+ p = buf;
+ /* Message Type */
+ *p++ = TLS1_HB_REQUEST;
+ /* Payload length (18 bytes here) */
+ s2n(payload, p);
+ /* Sequence number */
+ s2n(s->tlsext_hb_seq, p);
+ /* 16 random bytes */
+ RAND_pseudo_bytes(p, 16);
+ p += 16;
+ /* Random padding */
+ RAND_pseudo_bytes(p, padding);
+
+ ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+ if (ret >= 0)
+ {
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buf, 3 + payload + padding,
+ s, s->msg_callback_arg);
+
+ dtls1_start_timer(s);
+ s->tlsext_hb_pending = 1;
+ }
+
+ OPENSSL_free(buf);
+
+ return ret;
+ }
+#endif
diff --git a/drivers/builtin_openssl/ssl/d1_clnt.c b/drivers/builtin_openssl2/ssl/d1_clnt.c
index 48e5e06bde..48e5e06bde 100644
--- a/drivers/builtin_openssl/ssl/d1_clnt.c
+++ b/drivers/builtin_openssl2/ssl/d1_clnt.c
diff --git a/drivers/builtin_openssl/ssl/d1_enc.c b/drivers/builtin_openssl2/ssl/d1_enc.c
index 712c4647f2..712c4647f2 100644
--- a/drivers/builtin_openssl/ssl/d1_enc.c
+++ b/drivers/builtin_openssl2/ssl/d1_enc.c
diff --git a/drivers/builtin_openssl2/ssl/d1_lib.c b/drivers/builtin_openssl2/ssl/d1_lib.c
new file mode 100644
index 0000000000..6bde16fa21
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/d1_lib.c
@@ -0,0 +1,486 @@
+/* ssl/d1_lib.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#define USE_SOCKETS
+#include <openssl/objects.h>
+#include "ssl_locl.h"
+
+#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS)
+#include <sys/timeb.h>
+#endif
+
+static void get_current_time(struct timeval *t);
+const char dtls1_version_str[]="DTLSv1" OPENSSL_VERSION_PTEXT;
+int dtls1_listen(SSL *s, struct sockaddr *client);
+
+SSL3_ENC_METHOD DTLSv1_enc_data={
+ dtls1_enc,
+ tls1_mac,
+ tls1_setup_key_block,
+ tls1_generate_master_secret,
+ tls1_change_cipher_state,
+ tls1_final_finish_mac,
+ TLS1_FINISH_MAC_LENGTH,
+ tls1_cert_verify_mac,
+ TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+ TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+ tls1_alert_code,
+ tls1_export_keying_material,
+ };
+
+long dtls1_default_timeout(void)
+ {
+ /* 2 hours, the 24 hours mentioned in the DTLSv1 spec
+ * is way too long for http, the cache would over fill */
+ return(60*60*2);
+ }
+
+int dtls1_new(SSL *s)
+ {
+ DTLS1_STATE *d1;
+
+ if (!ssl3_new(s)) return(0);
+ if ((d1=OPENSSL_malloc(sizeof *d1)) == NULL) return (0);
+ memset(d1,0, sizeof *d1);
+
+ /* d1->handshake_epoch=0; */
+
+ d1->unprocessed_rcds.q=pqueue_new();
+ d1->processed_rcds.q=pqueue_new();
+ d1->buffered_messages = pqueue_new();
+ d1->sent_messages=pqueue_new();
+ d1->buffered_app_data.q=pqueue_new();
+
+ if ( s->server)
+ {
+ d1->cookie_len = sizeof(s->d1->cookie);
+ }
+
+ if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q
+ || ! d1->buffered_messages || ! d1->sent_messages || ! d1->buffered_app_data.q)
+ {
+ if ( d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q);
+ if ( d1->processed_rcds.q) pqueue_free(d1->processed_rcds.q);
+ if ( d1->buffered_messages) pqueue_free(d1->buffered_messages);
+ if ( d1->sent_messages) pqueue_free(d1->sent_messages);
+ if ( d1->buffered_app_data.q) pqueue_free(d1->buffered_app_data.q);
+ OPENSSL_free(d1);
+ return (0);
+ }
+
+ s->d1=d1;
+ s->method->ssl_clear(s);
+ return(1);
+ }
+
+static void dtls1_clear_queues(SSL *s)
+ {
+ pitem *item = NULL;
+ hm_fragment *frag = NULL;
+ DTLS1_RECORD_DATA *rdata;
+
+ while( (item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL)
+ {
+ rdata = (DTLS1_RECORD_DATA *) item->data;
+ if (rdata->rbuf.buf)
+ {
+ OPENSSL_free(rdata->rbuf.buf);
+ }
+ OPENSSL_free(item->data);
+ pitem_free(item);
+ }
+
+ while( (item = pqueue_pop(s->d1->processed_rcds.q)) != NULL)
+ {
+ rdata = (DTLS1_RECORD_DATA *) item->data;
+ if (rdata->rbuf.buf)
+ {
+ OPENSSL_free(rdata->rbuf.buf);
+ }
+ OPENSSL_free(item->data);
+ pitem_free(item);
+ }
+
+ while( (item = pqueue_pop(s->d1->buffered_messages)) != NULL)
+ {
+ frag = (hm_fragment *)item->data;
+ OPENSSL_free(frag->fragment);
+ OPENSSL_free(frag);
+ pitem_free(item);
+ }
+
+ while ( (item = pqueue_pop(s->d1->sent_messages)) != NULL)
+ {
+ frag = (hm_fragment *)item->data;
+ OPENSSL_free(frag->fragment);
+ OPENSSL_free(frag);
+ pitem_free(item);
+ }
+
+ while ( (item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL)
+ {
+ rdata = (DTLS1_RECORD_DATA *) item->data;
+ if (rdata->rbuf.buf)
+ {
+ OPENSSL_free(rdata->rbuf.buf);
+ }
+ OPENSSL_free(item->data);
+ pitem_free(item);
+ }
+ }
+
+void dtls1_free(SSL *s)
+ {
+ ssl3_free(s);
+
+ dtls1_clear_queues(s);
+
+ pqueue_free(s->d1->unprocessed_rcds.q);
+ pqueue_free(s->d1->processed_rcds.q);
+ pqueue_free(s->d1->buffered_messages);
+ pqueue_free(s->d1->sent_messages);
+ pqueue_free(s->d1->buffered_app_data.q);
+
+ OPENSSL_free(s->d1);
+ s->d1 = NULL;
+ }
+
+void dtls1_clear(SSL *s)
+ {
+ pqueue unprocessed_rcds;
+ pqueue processed_rcds;
+ pqueue buffered_messages;
+ pqueue sent_messages;
+ pqueue buffered_app_data;
+ unsigned int mtu;
+
+ if (s->d1)
+ {
+ unprocessed_rcds = s->d1->unprocessed_rcds.q;
+ processed_rcds = s->d1->processed_rcds.q;
+ buffered_messages = s->d1->buffered_messages;
+ sent_messages = s->d1->sent_messages;
+ buffered_app_data = s->d1->buffered_app_data.q;
+ mtu = s->d1->mtu;
+
+ dtls1_clear_queues(s);
+
+ memset(s->d1, 0, sizeof(*(s->d1)));
+
+ if (s->server)
+ {
+ s->d1->cookie_len = sizeof(s->d1->cookie);
+ }
+
+ if (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)
+ {
+ s->d1->mtu = mtu;
+ }
+
+ s->d1->unprocessed_rcds.q = unprocessed_rcds;
+ s->d1->processed_rcds.q = processed_rcds;
+ s->d1->buffered_messages = buffered_messages;
+ s->d1->sent_messages = sent_messages;
+ s->d1->buffered_app_data.q = buffered_app_data;
+ }
+
+ ssl3_clear(s);
+ if (s->options & SSL_OP_CISCO_ANYCONNECT)
+ s->version=DTLS1_BAD_VER;
+ else
+ s->version=DTLS1_VERSION;
+ }
+
+long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
+ {
+ int ret=0;
+
+ switch (cmd)
+ {
+ case DTLS_CTRL_GET_TIMEOUT:
+ if (dtls1_get_timeout(s, (struct timeval*) parg) != NULL)
+ {
+ ret = 1;
+ }
+ break;
+ case DTLS_CTRL_HANDLE_TIMEOUT:
+ ret = dtls1_handle_timeout(s);
+ break;
+ case DTLS_CTRL_LISTEN:
+ ret = dtls1_listen(s, parg);
+ break;
+
+ default:
+ ret = ssl3_ctrl(s, cmd, larg, parg);
+ break;
+ }
+ return(ret);
+ }
+
+/*
+ * As it's impossible to use stream ciphers in "datagram" mode, this
+ * simple filter is designed to disengage them in DTLS. Unfortunately
+ * there is no universal way to identify stream SSL_CIPHER, so we have
+ * to explicitly list their SSL_* codes. Currently RC4 is the only one
+ * available, but if new ones emerge, they will have to be added...
+ */
+const SSL_CIPHER *dtls1_get_cipher(unsigned int u)
+ {
+ const SSL_CIPHER *ciph = ssl3_get_cipher(u);
+
+ if (ciph != NULL)
+ {
+ if (ciph->algorithm_enc == SSL_RC4)
+ return NULL;
+ }
+
+ return ciph;
+ }
+
+void dtls1_start_timer(SSL *s)
+ {
+#ifndef OPENSSL_NO_SCTP
+ /* Disable timer for SCTP */
+ if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
+ {
+ memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
+ return;
+ }
+#endif
+
+ /* If timer is not set, initialize duration with 1 second */
+ if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
+ {
+ s->d1->timeout_duration = 1;
+ }
+
+ /* Set timeout to current time */
+ get_current_time(&(s->d1->next_timeout));
+
+ /* Add duration to current time */
+ s->d1->next_timeout.tv_sec += s->d1->timeout_duration;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
+ }
+
+struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft)
+ {
+ struct timeval timenow;
+
+ /* If no timeout is set, just return NULL */
+ if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
+ {
+ return NULL;
+ }
+
+ /* Get current time */
+ get_current_time(&timenow);
+
+ /* If timer already expired, set remaining time to 0 */
+ if (s->d1->next_timeout.tv_sec < timenow.tv_sec ||
+ (s->d1->next_timeout.tv_sec == timenow.tv_sec &&
+ s->d1->next_timeout.tv_usec <= timenow.tv_usec))
+ {
+ memset(timeleft, 0, sizeof(struct timeval));
+ return timeleft;
+ }
+
+ /* Calculate time left until timer expires */
+ memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval));
+ timeleft->tv_sec -= timenow.tv_sec;
+ timeleft->tv_usec -= timenow.tv_usec;
+ if (timeleft->tv_usec < 0)
+ {
+ timeleft->tv_sec--;
+ timeleft->tv_usec += 1000000;
+ }
+
+ /* If remaining time is less than 15 ms, set it to 0
+ * to prevent issues because of small devergences with
+ * socket timeouts.
+ */
+ if (timeleft->tv_sec == 0 && timeleft->tv_usec < 15000)
+ {
+ memset(timeleft, 0, sizeof(struct timeval));
+ }
+
+
+ return timeleft;
+ }
+
+int dtls1_is_timer_expired(SSL *s)
+ {
+ struct timeval timeleft;
+
+ /* Get time left until timeout, return false if no timer running */
+ if (dtls1_get_timeout(s, &timeleft) == NULL)
+ {
+ return 0;
+ }
+
+ /* Return false if timer is not expired yet */
+ if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0)
+ {
+ return 0;
+ }
+
+ /* Timer expired, so return true */
+ return 1;
+ }
+
+void dtls1_double_timeout(SSL *s)
+ {
+ s->d1->timeout_duration *= 2;
+ if (s->d1->timeout_duration > 60)
+ s->d1->timeout_duration = 60;
+ dtls1_start_timer(s);
+ }
+
+void dtls1_stop_timer(SSL *s)
+ {
+ /* Reset everything */
+ memset(&(s->d1->timeout), 0, sizeof(struct dtls1_timeout_st));
+ memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
+ s->d1->timeout_duration = 1;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
+ /* Clear retransmission buffer */
+ dtls1_clear_record_buffer(s);
+ }
+
+int dtls1_check_timeout_num(SSL *s)
+ {
+ s->d1->timeout.num_alerts++;
+
+ /* Reduce MTU after 2 unsuccessful retransmissions */
+ if (s->d1->timeout.num_alerts > 2)
+ {
+ s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
+ }
+
+ if (s->d1->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
+ {
+ /* fail the connection, enough alerts have been sent */
+ SSLerr(SSL_F_DTLS1_CHECK_TIMEOUT_NUM,SSL_R_READ_TIMEOUT_EXPIRED);
+ return -1;
+ }
+
+ return 0;
+ }
+
+int dtls1_handle_timeout(SSL *s)
+ {
+ /* if no timer is expired, don't do anything */
+ if (!dtls1_is_timer_expired(s))
+ {
+ return 0;
+ }
+
+ dtls1_double_timeout(s);
+
+ if (dtls1_check_timeout_num(s) < 0)
+ return -1;
+
+ s->d1->timeout.read_timeouts++;
+ if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT)
+ {
+ s->d1->timeout.read_timeouts = 1;
+ }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ if (s->tlsext_hb_pending)
+ {
+ s->tlsext_hb_pending = 0;
+ return dtls1_heartbeat(s);
+ }
+#endif
+
+ dtls1_start_timer(s);
+ return dtls1_retransmit_buffered_messages(s);
+ }
+
+static void get_current_time(struct timeval *t)
+{
+#ifdef OPENSSL_SYS_WIN32
+ struct _timeb tb;
+ _ftime(&tb);
+ t->tv_sec = (long)tb.time;
+ t->tv_usec = (long)tb.millitm * 1000;
+#elif defined(OPENSSL_SYS_VMS)
+ struct timeb tb;
+ ftime(&tb);
+ t->tv_sec = (long)tb.time;
+ t->tv_usec = (long)tb.millitm * 1000;
+#else
+ gettimeofday(t, NULL);
+#endif
+}
+
+int dtls1_listen(SSL *s, struct sockaddr *client)
+ {
+ int ret;
+
+ SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
+ s->d1->listen = 1;
+
+ ret = SSL_accept(s);
+ if (ret <= 0) return ret;
+
+ (void) BIO_dgram_get_peer(SSL_get_rbio(s), client);
+ return 1;
+ }
diff --git a/drivers/builtin_openssl/ssl/d1_meth.c b/drivers/builtin_openssl2/ssl/d1_meth.c
index 5c4004bfe3..5c4004bfe3 100644
--- a/drivers/builtin_openssl/ssl/d1_meth.c
+++ b/drivers/builtin_openssl2/ssl/d1_meth.c
diff --git a/drivers/builtin_openssl2/ssl/d1_pkt.c b/drivers/builtin_openssl2/ssl/d1_pkt.c
new file mode 100644
index 0000000000..438c0913d2
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/d1_pkt.c
@@ -0,0 +1,1901 @@
+/* ssl/d1_pkt.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#define USE_SOCKETS
+#include "ssl_locl.h"
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+#include <openssl/pqueue.h>
+#include <openssl/rand.h>
+
+/* mod 128 saturating subtract of two 64-bit values in big-endian order */
+static int satsub64be(const unsigned char *v1,const unsigned char *v2)
+{ int ret,sat,brw,i;
+
+ if (sizeof(long) == 8) do
+ { const union { long one; char little; } is_endian = {1};
+ long l;
+
+ if (is_endian.little) break;
+ /* not reached on little-endians */
+ /* following test is redundant, because input is
+ * always aligned, but I take no chances... */
+ if (((size_t)v1|(size_t)v2)&0x7) break;
+
+ l = *((long *)v1);
+ l -= *((long *)v2);
+ if (l>128) return 128;
+ else if (l<-128) return -128;
+ else return (int)l;
+ } while (0);
+
+ ret = (int)v1[7]-(int)v2[7];
+ sat = 0;
+ brw = ret>>8; /* brw is either 0 or -1 */
+ if (ret & 0x80)
+ { for (i=6;i>=0;i--)
+ { brw += (int)v1[i]-(int)v2[i];
+ sat |= ~brw;
+ brw >>= 8;
+ }
+ }
+ else
+ { for (i=6;i>=0;i--)
+ { brw += (int)v1[i]-(int)v2[i];
+ sat |= brw;
+ brw >>= 8;
+ }
+ }
+ brw <<= 8; /* brw is either 0 or -256 */
+
+ if (sat&0xff) return brw | 0x80;
+ else return brw + (ret&0xFF);
+}
+
+static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
+ int len, int peek);
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap);
+static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
+static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
+ unsigned int *is_next_epoch);
+#if 0
+static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
+ unsigned short *priority, unsigned long *offset);
+#endif
+static int dtls1_buffer_record(SSL *s, record_pqueue *q,
+ unsigned char *priority);
+static int dtls1_process_record(SSL *s);
+
+/* copy buffered record into SSL structure */
+static int
+dtls1_copy_record(SSL *s, pitem *item)
+ {
+ DTLS1_RECORD_DATA *rdata;
+
+ rdata = (DTLS1_RECORD_DATA *)item->data;
+
+ if (s->s3->rbuf.buf != NULL)
+ OPENSSL_free(s->s3->rbuf.buf);
+
+ s->packet = rdata->packet;
+ s->packet_length = rdata->packet_length;
+ memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
+ memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+
+ /* Set proper sequence number for mac calculation */
+ memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6);
+
+ return(1);
+ }
+
+
+static int
+dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
+ {
+ DTLS1_RECORD_DATA *rdata;
+ pitem *item;
+
+ /* Limit the size of the queue to prevent DOS attacks */
+ if (pqueue_size(queue->q) >= 100)
+ return 0;
+
+ rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA));
+ item = pitem_new(priority, rdata);
+ if (rdata == NULL || item == NULL)
+ {
+ if (rdata != NULL) OPENSSL_free(rdata);
+ if (item != NULL) pitem_free(item);
+
+ SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
+ return(0);
+ }
+
+ rdata->packet = s->packet;
+ rdata->packet_length = s->packet_length;
+ memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER));
+ memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD));
+
+ item->data = rdata;
+
+#ifndef OPENSSL_NO_SCTP
+ /* Store bio_dgram_sctp_rcvinfo struct */
+ if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+ (s->state == SSL3_ST_SR_FINISHED_A || s->state == SSL3_ST_CR_FINISHED_A)) {
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_GET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
+ }
+#endif
+
+ s->packet = NULL;
+ s->packet_length = 0;
+ memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER));
+ memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD));
+
+ if (!ssl3_setup_buffers(s))
+ {
+ SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(rdata);
+ pitem_free(item);
+ return(0);
+ }
+
+ /* insert should not fail, since duplicates are dropped */
+ if (pqueue_insert(queue->q, item) == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(rdata);
+ pitem_free(item);
+ return(0);
+ }
+
+ return(1);
+ }
+
+
+static int
+dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
+ {
+ pitem *item;
+
+ item = pqueue_pop(queue->q);
+ if (item)
+ {
+ dtls1_copy_record(s, item);
+
+ OPENSSL_free(item->data);
+ pitem_free(item);
+
+ return(1);
+ }
+
+ return(0);
+ }
+
+
+/* retrieve a buffered record that belongs to the new epoch, i.e., not processed
+ * yet */
+#define dtls1_get_unprocessed_record(s) \
+ dtls1_retrieve_buffered_record((s), \
+ &((s)->d1->unprocessed_rcds))
+
+/* retrieve a buffered record that belongs to the current epoch, ie, processed */
+#define dtls1_get_processed_record(s) \
+ dtls1_retrieve_buffered_record((s), \
+ &((s)->d1->processed_rcds))
+
+static int
+dtls1_process_buffered_records(SSL *s)
+ {
+ pitem *item;
+
+ item = pqueue_peek(s->d1->unprocessed_rcds.q);
+ if (item)
+ {
+ /* Check if epoch is current. */
+ if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
+ return(1); /* Nothing to do. */
+
+ /* Process all the records. */
+ while (pqueue_peek(s->d1->unprocessed_rcds.q))
+ {
+ dtls1_get_unprocessed_record(s);
+ if ( ! dtls1_process_record(s))
+ return(0);
+ dtls1_buffer_record(s, &(s->d1->processed_rcds),
+ s->s3->rrec.seq_num);
+ }
+ }
+
+ /* sync epoch numbers once all the unprocessed records
+ * have been processed */
+ s->d1->processed_rcds.epoch = s->d1->r_epoch;
+ s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1;
+
+ return(1);
+ }
+
+
+#if 0
+
+static int
+dtls1_get_buffered_record(SSL *s)
+ {
+ pitem *item;
+ PQ_64BIT priority =
+ (((PQ_64BIT)s->d1->handshake_read_seq) << 32) |
+ ((PQ_64BIT)s->d1->r_msg_hdr.frag_off);
+
+ if ( ! SSL_in_init(s)) /* if we're not (re)negotiating,
+ nothing buffered */
+ return 0;
+
+
+ item = pqueue_peek(s->d1->rcvd_records);
+ if (item && item->priority == priority)
+ {
+ /* Check if we've received the record of interest. It must be
+ * a handshake record, since data records as passed up without
+ * buffering */
+ DTLS1_RECORD_DATA *rdata;
+ item = pqueue_pop(s->d1->rcvd_records);
+ rdata = (DTLS1_RECORD_DATA *)item->data;
+
+ if (s->s3->rbuf.buf != NULL)
+ OPENSSL_free(s->s3->rbuf.buf);
+
+ s->packet = rdata->packet;
+ s->packet_length = rdata->packet_length;
+ memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
+ memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+
+ OPENSSL_free(item->data);
+ pitem_free(item);
+
+ /* s->d1->next_expected_seq_num++; */
+ return(1);
+ }
+
+ return 0;
+ }
+
+#endif
+
+static int
+dtls1_process_record(SSL *s)
+{
+ int i,al;
+ int enc_err;
+ SSL_SESSION *sess;
+ SSL3_RECORD *rr;
+ unsigned int mac_size, orig_len;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+ rr= &(s->s3->rrec);
+ sess = s->session;
+
+ /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
+ * and we have that many bytes in s->packet
+ */
+ rr->input= &(s->packet[DTLS1_RT_HEADER_LENGTH]);
+
+ /* ok, we can now read from 's->packet' data into 'rr'
+ * rr->input points at rr->length bytes, which
+ * need to be copied into rr->data by either
+ * the decryption or by the decompression
+ * When the data is 'copied' into the rr->data buffer,
+ * rr->input will be pointed at the new buffer */
+
+ /* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
+ * rr->length bytes of encrypted compressed stuff. */
+
+ /* check is not needed I believe */
+ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+
+ /* decrypt in place in 'rr->input' */
+ rr->data=rr->input;
+
+ enc_err = s->method->ssl3_enc->enc(s,0);
+ /* enc_err is:
+ * 0: (in non-constant time) if the record is publically invalid.
+ * 1: if the padding is valid
+ * -1: if the padding is invalid */
+ if (enc_err == 0)
+ {
+ /* For DTLS we simply ignore bad packets. */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto err;
+ }
+
+#ifdef TLS_DEBUG
+printf("dec %d\n",rr->length);
+{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
+printf("\n");
+#endif
+
+ /* r->length is now the compressed data plus mac */
+ if ((sess != NULL) &&
+ (s->enc_read_ctx != NULL) &&
+ (EVP_MD_CTX_md(s->read_hash) != NULL))
+ {
+ /* s->read_hash != NULL => mac_size != -1 */
+ unsigned char *mac = NULL;
+ unsigned char mac_tmp[EVP_MAX_MD_SIZE];
+ mac_size=EVP_MD_CTX_size(s->read_hash);
+ OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
+
+ /* kludge: *_cbc_remove_padding passes padding length in rr->type */
+ orig_len = rr->length+((unsigned int)rr->type>>8);
+
+ /* orig_len is the length of the record before any padding was
+ * removed. This is public information, as is the MAC in use,
+ * therefore we can safely process the record in a different
+ * amount of time if it's too short to possibly contain a MAC.
+ */
+ if (orig_len < mac_size ||
+ /* CBC records must have a padding length byte too. */
+ (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+ orig_len < mac_size+1))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT);
+ goto f_err;
+ }
+
+ if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
+ {
+ /* We update the length so that the TLS header bytes
+ * can be constructed correctly but we need to extract
+ * the MAC in constant time from within the record,
+ * without leaking the contents of the padding bytes.
+ * */
+ mac = mac_tmp;
+ ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
+ rr->length -= mac_size;
+ }
+ else
+ {
+ /* In this case there's no padding, so |orig_len|
+ * equals |rec->length| and we checked that there's
+ * enough bytes for |mac_size| above. */
+ rr->length -= mac_size;
+ mac = &rr->data[rr->length];
+ }
+
+ i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
+ if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+ enc_err = -1;
+ if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
+ enc_err = -1;
+ }
+
+ if (enc_err < 0)
+ {
+ /* decryption failed, silently discard message */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto err;
+ }
+
+ /* r->length is now just compressed */
+ if (s->expand != NULL)
+ {
+ if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+ if (!ssl3_do_uncompress(s))
+ {
+ al=SSL_AD_DECOMPRESSION_FAILURE;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_BAD_DECOMPRESSION);
+ goto f_err;
+ }
+ }
+
+ if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+
+ rr->off=0;
+ /* So at this point the following is true
+ * ssl->s3->rrec.type is the type of record
+ * ssl->s3->rrec.length == number of bytes in record
+ * ssl->s3->rrec.off == offset to first valid byte
+ * ssl->s3->rrec.data == where to take bytes from, increment
+ * after use :-).
+ */
+
+ /* we have pulled in a full packet so zero things */
+ s->packet_length=0;
+ dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
+ return(1);
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(0);
+}
+
+
+/* Call this to get a new input record.
+ * It will return <= 0 if more data is needed, normally due to an error
+ * or non-blocking IO.
+ * When it finishes, one packet has been decoded and can be found in
+ * ssl->s3->rrec.type - is the type of record
+ * ssl->s3->rrec.data, - data
+ * ssl->s3->rrec.length, - number of bytes
+ */
+/* used only by dtls1_read_bytes */
+int dtls1_get_record(SSL *s)
+ {
+ int ssl_major,ssl_minor;
+ int i,n;
+ SSL3_RECORD *rr;
+ unsigned char *p = NULL;
+ unsigned short version;
+ DTLS1_BITMAP *bitmap;
+ unsigned int is_next_epoch;
+
+ rr= &(s->s3->rrec);
+
+ /* The epoch may have changed. If so, process all the
+ * pending records. This is a non-blocking operation. */
+ dtls1_process_buffered_records(s);
+
+ /* if we're renegotiating, then there may be buffered records */
+ if (dtls1_get_processed_record(s))
+ return 1;
+
+ /* get something from the wire */
+again:
+ /* check if we have the header */
+ if ( (s->rstate != SSL_ST_READ_BODY) ||
+ (s->packet_length < DTLS1_RT_HEADER_LENGTH))
+ {
+ n=ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
+ /* read timeout is handled by dtls1_read_bytes */
+ if (n <= 0) return(n); /* error or non-blocking */
+
+ /* this packet contained a partial record, dump it */
+ if (s->packet_length != DTLS1_RT_HEADER_LENGTH)
+ {
+ s->packet_length = 0;
+ goto again;
+ }
+
+ s->rstate=SSL_ST_READ_BODY;
+
+ p=s->packet;
+
+ /* Pull apart the header into the DTLS1_RECORD */
+ rr->type= *(p++);
+ ssl_major= *(p++);
+ ssl_minor= *(p++);
+ version=(ssl_major<<8)|ssl_minor;
+
+ /* sequence number is 64 bits, with top 2 bytes = epoch */
+ n2s(p,rr->epoch);
+
+ memcpy(&(s->s3->read_sequence[2]), p, 6);
+ p+=6;
+
+ n2s(p,rr->length);
+
+ /* Lets check version */
+ if (!s->first_packet)
+ {
+ if (version != s->version)
+ {
+ /* unexpected version, silently discard */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+ }
+
+ if ((version & 0xff00) != (s->version & 0xff00))
+ {
+ /* wrong version, silently discard record */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+
+ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
+ {
+ /* record too long, silently discard it */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+
+ /* now s->rstate == SSL_ST_READ_BODY */
+ }
+
+ /* s->rstate == SSL_ST_READ_BODY, get and decode the data */
+
+ if (rr->length > s->packet_length-DTLS1_RT_HEADER_LENGTH)
+ {
+ /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
+ i=rr->length;
+ n=ssl3_read_n(s,i,i,1);
+ if (n <= 0) return(n); /* error or non-blocking io */
+
+ /* this packet contained a partial record, dump it */
+ if ( n != i)
+ {
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+
+ /* now n == rr->length,
+ * and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length */
+ }
+ s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
+
+ /* match epochs. NULL means the packet is dropped on the floor */
+ bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+ if ( bitmap == NULL)
+ {
+ rr->length = 0;
+ s->packet_length = 0; /* dump this record */
+ goto again; /* get another record */
+ }
+
+#ifndef OPENSSL_NO_SCTP
+ /* Only do replay check if no SCTP bio */
+ if (!BIO_dgram_is_sctp(SSL_get_rbio(s)))
+ {
+#endif
+ /* Check whether this is a repeat, or aged record.
+ * Don't check if we're listening and this message is
+ * a ClientHello. They can look as if they're replayed,
+ * since they arrive from different connections and
+ * would be dropped unnecessarily.
+ */
+ if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
+ *p == SSL3_MT_CLIENT_HELLO) &&
+ !dtls1_record_replay_check(s, bitmap))
+ {
+ rr->length = 0;
+ s->packet_length=0; /* dump this record */
+ goto again; /* get another record */
+ }
+#ifndef OPENSSL_NO_SCTP
+ }
+#endif
+
+ /* just read a 0 length packet */
+ if (rr->length == 0) goto again;
+
+ /* If this record is from the next epoch (either HM or ALERT),
+ * and a handshake is currently in progress, buffer it since it
+ * cannot be processed at this time. However, do not buffer
+ * anything while listening.
+ */
+ if (is_next_epoch)
+ {
+ if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen)
+ {
+ dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+ }
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+
+ if (!dtls1_process_record(s))
+ {
+ rr->length = 0;
+ s->packet_length = 0; /* dump this record */
+ goto again; /* get another record */
+ }
+
+ return(1);
+
+ }
+
+/* Return up to 'len' payload bytes received in 'type' records.
+ * 'type' is one of the following:
+ *
+ * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
+ * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
+ * - 0 (during a shutdown, no data has to be returned)
+ *
+ * If we don't have stored data to work from, read a SSL/TLS record first
+ * (possibly multiple records if we still don't have anything to return).
+ *
+ * This function must handle any surprises the peer may have for us, such as
+ * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
+ * a surprise, but handled as if it were), or renegotiation requests.
+ * Also if record payloads contain fragments too small to process, we store
+ * them until there is enough for the respective protocol (the record protocol
+ * may use arbitrary fragmentation and even interleaving):
+ * Change cipher spec protocol
+ * just 1 byte needed, no need for keeping anything stored
+ * Alert protocol
+ * 2 bytes needed (AlertLevel, AlertDescription)
+ * Handshake protocol
+ * 4 bytes needed (HandshakeType, uint24 length) -- we just have
+ * to detect unexpected Client Hello and Hello Request messages
+ * here, anything else is handled by higher layers
+ * Application data protocol
+ * none of our business
+ */
+int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
+ {
+ int al,i,j,ret;
+ unsigned int n;
+ SSL3_RECORD *rr;
+ void (*cb)(const SSL *ssl,int type2,int val)=NULL;
+
+ if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
+ if (!ssl3_setup_buffers(s))
+ return(-1);
+
+ /* XXX: check what the second '&& type' is about */
+ if ((type && (type != SSL3_RT_APPLICATION_DATA) &&
+ (type != SSL3_RT_HANDSHAKE) && type) ||
+ (peek && (type != SSL3_RT_APPLICATION_DATA)))
+ {
+ SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* check whether there's a handshake message (client hello?) waiting */
+ if ( (ret = have_handshake_fragment(s, type, buf, len, peek)))
+ return ret;
+
+ /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
+
+#ifndef OPENSSL_NO_SCTP
+ /* Continue handshake if it had to be interrupted to read
+ * app data with SCTP.
+ */
+ if ((!s->in_handshake && SSL_in_init(s)) ||
+ (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+ (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK) &&
+ s->s3->in_read_app_data != 2))
+#else
+ if (!s->in_handshake && SSL_in_init(s))
+#endif
+ {
+ /* type == SSL3_RT_APPLICATION_DATA */
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+ }
+
+start:
+ s->rwstate=SSL_NOTHING;
+
+ /* s->s3->rrec.type - is the type of record
+ * s->s3->rrec.data, - data
+ * s->s3->rrec.off, - offset into 'data' for next read
+ * s->s3->rrec.length, - number of bytes. */
+ rr = &(s->s3->rrec);
+
+ /* We are not handshaking and have no data yet,
+ * so process data buffered during the last handshake
+ * in advance, if any.
+ */
+ if (s->state == SSL_ST_OK && rr->length == 0)
+ {
+ pitem *item;
+ item = pqueue_pop(s->d1->buffered_app_data.q);
+ if (item)
+ {
+#ifndef OPENSSL_NO_SCTP
+ /* Restore bio_dgram_sctp_rcvinfo struct */
+ if (BIO_dgram_is_sctp(SSL_get_rbio(s)))
+ {
+ DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *) item->data;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
+ }
+#endif
+
+ dtls1_copy_record(s, item);
+
+ OPENSSL_free(item->data);
+ pitem_free(item);
+ }
+ }
+
+ /* Check for timeout */
+ if (dtls1_handle_timeout(s) > 0)
+ goto start;
+
+ /* get new packet if necessary */
+ if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
+ {
+ ret=dtls1_get_record(s);
+ if (ret <= 0)
+ {
+ ret = dtls1_read_failed(s, ret);
+ /* anything other than a timeout is an error */
+ if (ret <= 0)
+ return(ret);
+ else
+ goto start;
+ }
+ }
+
+ if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE)
+ {
+ rr->length = 0;
+ goto start;
+ }
+
+ /* we now have a packet which can be read and processed */
+
+ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
+ * reset by ssl3_get_finished */
+ && (rr->type != SSL3_RT_HANDSHAKE))
+ {
+ /* We now have application data between CCS and Finished.
+ * Most likely the packets were reordered on their way, so
+ * buffer the application data for later processing rather
+ * than dropping the connection.
+ */
+ dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num);
+ rr->length = 0;
+ goto start;
+ }
+
+ /* If the other end has shut down, throw anything we read away
+ * (even in 'peek' mode) */
+ if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+ {
+ rr->length=0;
+ s->rwstate=SSL_NOTHING;
+ return(0);
+ }
+
+
+ if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
+ {
+ /* make sure that we are not getting application data when we
+ * are doing a handshake for the first time */
+ if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
+ (s->enc_read_ctx == NULL))
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE);
+ goto f_err;
+ }
+
+ if (len <= 0) return(len);
+
+ if ((unsigned int)len > rr->length)
+ n = rr->length;
+ else
+ n = (unsigned int)len;
+
+ memcpy(buf,&(rr->data[rr->off]),n);
+ if (!peek)
+ {
+ rr->length-=n;
+ rr->off+=n;
+ if (rr->length == 0)
+ {
+ s->rstate=SSL_ST_READ_HEADER;
+ rr->off=0;
+ }
+ }
+
+#ifndef OPENSSL_NO_SCTP
+ /* We were about to renegotiate but had to read
+ * belated application data first, so retry.
+ */
+ if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+ rr->type == SSL3_RT_APPLICATION_DATA &&
+ (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK))
+ {
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ }
+
+ /* We might had to delay a close_notify alert because
+ * of reordered app data. If there was an alert and there
+ * is no message to read anymore, finally set shutdown.
+ */
+ if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+ s->d1->shutdown_received && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
+ {
+ s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ return(0);
+ }
+#endif
+ return(n);
+ }
+
+
+ /* If we get here, then type != rr->type; if we have a handshake
+ * message, then it was unexpected (Hello Request or Client Hello). */
+
+ /* In case of record types for which we have 'fragment' storage,
+ * fill that so that we can process the data at a fixed place.
+ */
+ {
+ unsigned int k, dest_maxlen = 0;
+ unsigned char *dest = NULL;
+ unsigned int *dest_len = NULL;
+
+ if (rr->type == SSL3_RT_HANDSHAKE)
+ {
+ dest_maxlen = sizeof s->d1->handshake_fragment;
+ dest = s->d1->handshake_fragment;
+ dest_len = &s->d1->handshake_fragment_len;
+ }
+ else if (rr->type == SSL3_RT_ALERT)
+ {
+ dest_maxlen = sizeof(s->d1->alert_fragment);
+ dest = s->d1->alert_fragment;
+ dest_len = &s->d1->alert_fragment_len;
+ }
+#ifndef OPENSSL_NO_HEARTBEATS
+ else if (rr->type == TLS1_RT_HEARTBEAT)
+ {
+ dtls1_process_heartbeat(s);
+
+ /* Exit and notify application to read again */
+ rr->length = 0;
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ return(-1);
+ }
+#endif
+ /* else it's a CCS message, or application data or wrong */
+ else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
+ {
+ /* Application data while renegotiating
+ * is allowed. Try again reading.
+ */
+ if (rr->type == SSL3_RT_APPLICATION_DATA)
+ {
+ BIO *bio;
+ s->s3->in_read_app_data=2;
+ bio=SSL_get_rbio(s);
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+
+ /* Not certain if this is the right error handling */
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+ goto f_err;
+ }
+
+ if (dest_maxlen > 0)
+ {
+ /* XDTLS: In a pathalogical case, the Client Hello
+ * may be fragmented--don't always expect dest_maxlen bytes */
+ if ( rr->length < dest_maxlen)
+ {
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+ /*
+ * for normal alerts rr->length is 2, while
+ * dest_maxlen is 7 if we were to handle this
+ * non-existing alert...
+ */
+ FIX ME
+#endif
+ s->rstate=SSL_ST_READ_HEADER;
+ rr->length = 0;
+ goto start;
+ }
+
+ /* now move 'n' bytes: */
+ for ( k = 0; k < dest_maxlen; k++)
+ {
+ dest[k] = rr->data[rr->off++];
+ rr->length--;
+ }
+ *dest_len = dest_maxlen;
+ }
+ }
+
+ /* s->d1->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE;
+ * s->d1->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT.
+ * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
+
+ /* If we are a client, check for an incoming 'Hello Request': */
+ if ((!s->server) &&
+ (s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
+ (s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
+ (s->session != NULL) && (s->session->cipher != NULL))
+ {
+ s->d1->handshake_fragment_len = 0;
+
+ if ((s->d1->handshake_fragment[1] != 0) ||
+ (s->d1->handshake_fragment[2] != 0) ||
+ (s->d1->handshake_fragment[3] != 0))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
+ goto err;
+ }
+
+ /* no need to check sequence number on HELLO REQUEST messages */
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+ s->d1->handshake_fragment, 4, s, s->msg_callback_arg);
+
+ if (SSL_is_init_finished(s) &&
+ !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
+ !s->s3->renegotiate)
+ {
+ s->d1->handshake_read_seq++;
+ s->new_session = 1;
+ ssl3_renegotiate(s);
+ if (ssl3_renegotiate_check(s))
+ {
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+
+ if (!(s->mode & SSL_MODE_AUTO_RETRY))
+ {
+ if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ {
+ BIO *bio;
+ /* In the case where we try to read application data,
+ * but we trigger an SSL handshake, we return -1 with
+ * the retry option set. Otherwise renegotiation may
+ * cause nasty problems in the blocking world */
+ s->rwstate=SSL_READING;
+ bio=SSL_get_rbio(s);
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+ }
+ }
+ }
+ /* we either finished a handshake or ignored the request,
+ * now try again to obtain the (application) data we were asked for */
+ goto start;
+ }
+
+ if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH)
+ {
+ int alert_level = s->d1->alert_fragment[0];
+ int alert_descr = s->d1->alert_fragment[1];
+
+ s->d1->alert_fragment_len = 0;
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_ALERT,
+ s->d1->alert_fragment, 2, s, s->msg_callback_arg);
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ if (cb != NULL)
+ {
+ j = (alert_level << 8) | alert_descr;
+ cb(s, SSL_CB_READ_ALERT, j);
+ }
+
+ if (alert_level == 1) /* warning */
+ {
+ s->s3->warn_alert = alert_descr;
+ if (alert_descr == SSL_AD_CLOSE_NOTIFY)
+ {
+#ifndef OPENSSL_NO_SCTP
+ /* With SCTP and streams the socket may deliver app data
+ * after a close_notify alert. We have to check this
+ * first so that nothing gets discarded.
+ */
+ if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+ BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
+ {
+ s->d1->shutdown_received = 1;
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ return -1;
+ }
+#endif
+ s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ return(0);
+ }
+#if 0
+ /* XXX: this is a possible improvement in the future */
+ /* now check if it's a missing record */
+ if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+ {
+ unsigned short seq;
+ unsigned int frag_off;
+ unsigned char *p = &(s->d1->alert_fragment[2]);
+
+ n2s(p, seq);
+ n2l3(p, frag_off);
+
+ dtls1_retransmit_message(s,
+ dtls1_get_queue_priority(frag->msg_header.seq, 0),
+ frag_off, &found);
+ if ( ! found && SSL_in_init(s))
+ {
+ /* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */
+ /* requested a message not yet sent,
+ send an alert ourselves */
+ ssl3_send_alert(s,SSL3_AL_WARNING,
+ DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+ }
+ }
+#endif
+ }
+ else if (alert_level == 2) /* fatal */
+ {
+ char tmp[16];
+
+ s->rwstate=SSL_NOTHING;
+ s->s3->fatal_alert = alert_descr;
+ SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);
+ BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
+ ERR_add_error_data(2,"SSL alert number ",tmp);
+ s->shutdown|=SSL_RECEIVED_SHUTDOWN;
+ SSL_CTX_remove_session(s->ctx,s->session);
+ return(0);
+ }
+ else
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE);
+ goto f_err;
+ }
+
+ goto start;
+ }
+
+ if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
+ {
+ s->rwstate=SSL_NOTHING;
+ rr->length=0;
+ return(0);
+ }
+
+ if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+ {
+ struct ccs_header_st ccs_hdr;
+ unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH;
+
+ dtls1_get_ccs_header(rr->data, &ccs_hdr);
+
+ if (s->version == DTLS1_BAD_VER)
+ ccs_hdr_len = 3;
+
+ /* 'Change Cipher Spec' is just a single byte, so we know
+ * exactly what the record payload has to look like */
+ /* XDTLS: check that epoch is consistent */
+ if ( (rr->length != ccs_hdr_len) ||
+ (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
+ {
+ i=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ goto err;
+ }
+
+ rr->length=0;
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
+ rr->data, 1, s, s->msg_callback_arg);
+
+ /* We can't process a CCS now, because previous handshake
+ * messages are still missing, so just drop it.
+ */
+ if (!s->d1->change_cipher_spec_ok)
+ {
+ goto start;
+ }
+
+ s->d1->change_cipher_spec_ok = 0;
+
+ s->s3->change_cipher_spec=1;
+ if (!ssl3_do_change_cipher_spec(s))
+ goto err;
+
+ /* do this whenever CCS is processed */
+ dtls1_reset_seq_numbers(s, SSL3_CC_READ);
+
+ if (s->version == DTLS1_BAD_VER)
+ s->d1->handshake_read_seq++;
+
+#ifndef OPENSSL_NO_SCTP
+ /* Remember that a CCS has been received,
+ * so that an old key of SCTP-Auth can be
+ * deleted when a CCS is sent. Will be ignored
+ * if no SCTP is used
+ */
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL);
+#endif
+
+ goto start;
+ }
+
+ /* Unexpected handshake message (Client Hello, or protocol violation) */
+ if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
+ !s->in_handshake)
+ {
+ struct hm_header_st msg_hdr;
+
+ /* this may just be a stale retransmit */
+ dtls1_get_message_header(rr->data, &msg_hdr);
+ if( rr->epoch != s->d1->r_epoch)
+ {
+ rr->length = 0;
+ goto start;
+ }
+
+ /* If we are server, we may have a repeated FINISHED of the
+ * client here, then retransmit our CCS and FINISHED.
+ */
+ if (msg_hdr.type == SSL3_MT_FINISHED)
+ {
+ if (dtls1_check_timeout_num(s) < 0)
+ return -1;
+
+ dtls1_retransmit_buffered_messages(s);
+ rr->length = 0;
+ goto start;
+ }
+
+ if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
+ !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
+ {
+#if 0 /* worked only because C operator preferences are not as expected (and
+ * because this is not really needed for clients except for detecting
+ * protocol violations): */
+ s->state=SSL_ST_BEFORE|(s->server)
+ ?SSL_ST_ACCEPT
+ :SSL_ST_CONNECT;
+#else
+ s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
+#endif
+ s->renegotiate=1;
+ s->new_session=1;
+ }
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+
+ if (!(s->mode & SSL_MODE_AUTO_RETRY))
+ {
+ if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ {
+ BIO *bio;
+ /* In the case where we try to read application data,
+ * but we trigger an SSL handshake, we return -1 with
+ * the retry option set. Otherwise renegotiation may
+ * cause nasty problems in the blocking world */
+ s->rwstate=SSL_READING;
+ bio=SSL_get_rbio(s);
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+ }
+ goto start;
+ }
+
+ switch (rr->type)
+ {
+ default:
+#ifndef OPENSSL_NO_TLS
+ /* TLS just ignores unknown message types */
+ if (s->version == TLS1_VERSION)
+ {
+ rr->length = 0;
+ goto start;
+ }
+#endif
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+ goto f_err;
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ case SSL3_RT_ALERT:
+ case SSL3_RT_HANDSHAKE:
+ /* we already handled all of these, with the possible exception
+ * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that
+ * should not happen when type != rr->type */
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ case SSL3_RT_APPLICATION_DATA:
+ /* At this point, we were expecting handshake data,
+ * but have application data. If the library was
+ * running inside ssl3_read() (i.e. in_read_app_data
+ * is set) and it makes sense to read application data
+ * at this point (session renegotiation not yet started),
+ * we will indulge it.
+ */
+ if (s->s3->in_read_app_data &&
+ (s->s3->total_renegotiations != 0) &&
+ ((
+ (s->state & SSL_ST_CONNECT) &&
+ (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
+ (s->state <= SSL3_ST_CR_SRVR_HELLO_A)
+ ) || (
+ (s->state & SSL_ST_ACCEPT) &&
+ (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
+ (s->state >= SSL3_ST_SR_CLNT_HELLO_A)
+ )
+ ))
+ {
+ s->s3->in_read_app_data=2;
+ return(-1);
+ }
+ else
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+ goto f_err;
+ }
+ }
+ /* not reached */
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(-1);
+ }
+
+int
+dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
+ {
+ int i;
+
+#ifndef OPENSSL_NO_SCTP
+ /* Check if we have to continue an interrupted handshake
+ * for reading belated app data with SCTP.
+ */
+ if ((SSL_in_init(s) && !s->in_handshake) ||
+ (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
+ (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)))
+#else
+ if (SSL_in_init(s) && !s->in_handshake)
+#endif
+ {
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ }
+
+ if (len > SSL3_RT_MAX_PLAIN_LENGTH)
+ {
+ SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_DTLS_MESSAGE_TOO_BIG);
+ return -1;
+ }
+
+ i = dtls1_write_bytes(s, type, buf_, len);
+ return i;
+ }
+
+
+ /* this only happens when a client hello is received and a handshake
+ * is started. */
+static int
+have_handshake_fragment(SSL *s, int type, unsigned char *buf,
+ int len, int peek)
+ {
+
+ if ((type == SSL3_RT_HANDSHAKE) && (s->d1->handshake_fragment_len > 0))
+ /* (partially) satisfy request from storage */
+ {
+ unsigned char *src = s->d1->handshake_fragment;
+ unsigned char *dst = buf;
+ unsigned int k,n;
+
+ /* peek == 0 */
+ n = 0;
+ while ((len > 0) && (s->d1->handshake_fragment_len > 0))
+ {
+ *dst++ = *src++;
+ len--; s->d1->handshake_fragment_len--;
+ n++;
+ }
+ /* move any remaining fragment bytes: */
+ for (k = 0; k < s->d1->handshake_fragment_len; k++)
+ s->d1->handshake_fragment[k] = *src++;
+ return n;
+ }
+
+ return 0;
+ }
+
+
+
+
+/* Call this to write data in records of type 'type'
+ * It will return <= 0 if not all data has been sent or non-blocking IO.
+ */
+int dtls1_write_bytes(SSL *s, int type, const void *buf, int len)
+ {
+ int i;
+
+ OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH);
+ s->rwstate=SSL_NOTHING;
+ i=do_dtls1_write(s, type, buf, len, 0);
+ return i;
+ }
+
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment)
+ {
+ unsigned char *p,*pseq;
+ int i,mac_size,clear=0;
+ int prefix_len = 0;
+ SSL3_RECORD *wr;
+ SSL3_BUFFER *wb;
+ SSL_SESSION *sess;
+ int bs;
+
+ /* first check if there is a SSL3_BUFFER still being written
+ * out. This will happen with non blocking IO */
+ if (s->s3->wbuf.left != 0)
+ {
+ OPENSSL_assert(0); /* XDTLS: want to see if we ever get here */
+ return(ssl3_write_pending(s,type,buf,len));
+ }
+
+ /* If we have an alert to send, lets send it */
+ if (s->s3->alert_dispatch)
+ {
+ i=s->method->ssl_dispatch_alert(s);
+ if (i <= 0)
+ return(i);
+ /* if it went, fall through and send more stuff */
+ }
+
+ if (len == 0 && !create_empty_fragment)
+ return 0;
+
+ wr= &(s->s3->wrec);
+ wb= &(s->s3->wbuf);
+ sess=s->session;
+
+ if ( (sess == NULL) ||
+ (s->enc_write_ctx == NULL) ||
+ (EVP_MD_CTX_md(s->write_hash) == NULL))
+ clear=1;
+
+ if (clear)
+ mac_size=0;
+ else
+ {
+ mac_size=EVP_MD_CTX_size(s->write_hash);
+ if (mac_size < 0)
+ goto err;
+ }
+
+ /* DTLS implements explicit IV, so no need for empty fragments */
+#if 0
+ /* 'create_empty_fragment' is true only when this function calls itself */
+ if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done
+ && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
+ {
+ /* countermeasure against known-IV weakness in CBC ciphersuites
+ * (see http://www.openssl.org/~bodo/tls-cbc.txt)
+ */
+
+ if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
+ {
+ /* recursive function call with 'create_empty_fragment' set;
+ * this prepares and buffers the data for an empty fragment
+ * (these 'prefix_len' bytes are sent out later
+ * together with the actual payload) */
+ prefix_len = s->method->do_ssl_write(s, type, buf, 0, 1);
+ if (prefix_len <= 0)
+ goto err;
+
+ if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+ {
+ /* insufficient space */
+ SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ s->s3->empty_fragment_done = 1;
+ }
+#endif
+ p = wb->buf + prefix_len;
+
+ /* write the header */
+
+ *(p++)=type&0xff;
+ wr->type=type;
+
+ *(p++)=(s->version>>8);
+ *(p++)=s->version&0xff;
+
+ /* field where we are to write out packet epoch, seq num and len */
+ pseq=p;
+ p+=10;
+
+ /* lets setup the record stuff. */
+
+ /* Make space for the explicit IV in case of CBC.
+ * (this is a bit of a boundary violation, but what the heck).
+ */
+ if ( s->enc_write_ctx &&
+ (EVP_CIPHER_mode( s->enc_write_ctx->cipher ) & EVP_CIPH_CBC_MODE))
+ bs = EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
+ else
+ bs = 0;
+
+ wr->data=p + bs; /* make room for IV in case of CBC */
+ wr->length=(int)len;
+ wr->input=(unsigned char *)buf;
+
+ /* we now 'read' from wr->input, wr->length bytes into
+ * wr->data */
+
+ /* first we compress */
+ if (s->compress != NULL)
+ {
+ if (!ssl3_do_compress(s))
+ {
+ SSLerr(SSL_F_DO_DTLS1_WRITE,SSL_R_COMPRESSION_FAILURE);
+ goto err;
+ }
+ }
+ else
+ {
+ memcpy(wr->data,wr->input,wr->length);
+ wr->input=wr->data;
+ }
+
+ /* we should still have the output to wr->data and the input
+ * from wr->input. Length should be wr->length.
+ * wr->data still points in the wb->buf */
+
+ if (mac_size != 0)
+ {
+ if(s->method->ssl3_enc->mac(s,&(p[wr->length + bs]),1) < 0)
+ goto err;
+ wr->length+=mac_size;
+ }
+
+ /* this is true regardless of mac size */
+ wr->input=p;
+ wr->data=p;
+
+
+ /* ssl3_enc can only have an error on read */
+ if (bs) /* bs != 0 in case of CBC */
+ {
+ RAND_pseudo_bytes(p,bs);
+ /* master IV and last CBC residue stand for
+ * the rest of randomness */
+ wr->length += bs;
+ }
+
+ s->method->ssl3_enc->enc(s,1);
+
+ /* record length after mac and block padding */
+/* if (type == SSL3_RT_APPLICATION_DATA ||
+ (type == SSL3_RT_ALERT && ! SSL_in_init(s))) */
+
+ /* there's only one epoch between handshake and app data */
+
+ s2n(s->d1->w_epoch, pseq);
+
+ /* XDTLS: ?? */
+/* else
+ s2n(s->d1->handshake_epoch, pseq); */
+
+ memcpy(pseq, &(s->s3->write_sequence[2]), 6);
+ pseq+=6;
+ s2n(wr->length,pseq);
+
+ /* we should now have
+ * wr->data pointing to the encrypted data, which is
+ * wr->length long */
+ wr->type=type; /* not needed but helps for debugging */
+ wr->length+=DTLS1_RT_HEADER_LENGTH;
+
+#if 0 /* this is now done at the message layer */
+ /* buffer the record, making it easy to handle retransmits */
+ if ( type == SSL3_RT_HANDSHAKE || type == SSL3_RT_CHANGE_CIPHER_SPEC)
+ dtls1_buffer_record(s, wr->data, wr->length,
+ *((PQ_64BIT *)&(s->s3->write_sequence[0])));
+#endif
+
+ ssl3_record_sequence_update(&(s->s3->write_sequence[0]));
+
+ if (create_empty_fragment)
+ {
+ /* we are in a recursive call;
+ * just return the length, don't write out anything here
+ */
+ return wr->length;
+ }
+
+ /* now let's set up wb */
+ wb->left = prefix_len + wr->length;
+ wb->offset = 0;
+
+ /* memorize arguments so that ssl3_write_pending can detect bad write retries later */
+ s->s3->wpend_tot=len;
+ s->s3->wpend_buf=buf;
+ s->s3->wpend_type=type;
+ s->s3->wpend_ret=len;
+
+ /* we now just need to write the buffer */
+ return ssl3_write_pending(s,type,buf,len);
+err:
+ return -1;
+ }
+
+
+
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap)
+ {
+ int cmp;
+ unsigned int shift;
+ const unsigned char *seq = s->s3->read_sequence;
+
+ cmp = satsub64be(seq,bitmap->max_seq_num);
+ if (cmp > 0)
+ {
+ memcpy (s->s3->rrec.seq_num,seq,8);
+ return 1; /* this record in new */
+ }
+ shift = -cmp;
+ if (shift >= sizeof(bitmap->map)*8)
+ return 0; /* stale, outside the window */
+ else if (bitmap->map & (1UL<<shift))
+ return 0; /* record previously received */
+
+ memcpy (s->s3->rrec.seq_num,seq,8);
+ return 1;
+ }
+
+
+static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap)
+ {
+ int cmp;
+ unsigned int shift;
+ const unsigned char *seq = s->s3->read_sequence;
+
+ cmp = satsub64be(seq,bitmap->max_seq_num);
+ if (cmp > 0)
+ {
+ shift = cmp;
+ if (shift < sizeof(bitmap->map)*8)
+ bitmap->map <<= shift, bitmap->map |= 1UL;
+ else
+ bitmap->map = 1UL;
+ memcpy(bitmap->max_seq_num,seq,8);
+ }
+ else {
+ shift = -cmp;
+ if (shift < sizeof(bitmap->map)*8)
+ bitmap->map |= 1UL<<shift;
+ }
+ }
+
+
+int dtls1_dispatch_alert(SSL *s)
+ {
+ int i,j;
+ void (*cb)(const SSL *ssl,int type,int val)=NULL;
+ unsigned char buf[DTLS1_AL_HEADER_LENGTH];
+ unsigned char *ptr = &buf[0];
+
+ s->s3->alert_dispatch=0;
+
+ memset(buf, 0x00, sizeof(buf));
+ *ptr++ = s->s3->send_alert[0];
+ *ptr++ = s->s3->send_alert[1];
+
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+ if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+ {
+ s2n(s->d1->handshake_read_seq, ptr);
+#if 0
+ if ( s->d1->r_msg_hdr.frag_off == 0) /* waiting for a new msg */
+
+ else
+ s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */
+#endif
+
+#if 0
+ fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n",s->d1->handshake_read_seq,s->d1->r_msg_hdr.seq);
+#endif
+ l2n3(s->d1->r_msg_hdr.frag_off, ptr);
+ }
+#endif
+
+ i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0);
+ if (i <= 0)
+ {
+ s->s3->alert_dispatch=1;
+ /* fprintf( stderr, "not done with alert\n" ); */
+ }
+ else
+ {
+ if (s->s3->send_alert[0] == SSL3_AL_FATAL
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+ || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+#endif
+ )
+ (void)BIO_flush(s->wbio);
+
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert,
+ 2, s, s->msg_callback_arg);
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ if (cb != NULL)
+ {
+ j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1];
+ cb(s,SSL_CB_WRITE_ALERT,j);
+ }
+ }
+ return(i);
+ }
+
+
+static DTLS1_BITMAP *
+dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, unsigned int *is_next_epoch)
+ {
+
+ *is_next_epoch = 0;
+
+ /* In current epoch, accept HM, CCS, DATA, & ALERT */
+ if (rr->epoch == s->d1->r_epoch)
+ return &s->d1->bitmap;
+
+ /* Only HM and ALERT messages can be from the next epoch */
+ else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) &&
+ (rr->type == SSL3_RT_HANDSHAKE ||
+ rr->type == SSL3_RT_ALERT))
+ {
+ *is_next_epoch = 1;
+ return &s->d1->next_bitmap;
+ }
+
+ return NULL;
+ }
+
+#if 0
+static int
+dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, unsigned short *priority,
+ unsigned long *offset)
+ {
+
+ /* alerts are passed up immediately */
+ if ( rr->type == SSL3_RT_APPLICATION_DATA ||
+ rr->type == SSL3_RT_ALERT)
+ return 0;
+
+ /* Only need to buffer if a handshake is underway.
+ * (this implies that Hello Request and Client Hello are passed up
+ * immediately) */
+ if ( SSL_in_init(s))
+ {
+ unsigned char *data = rr->data;
+ /* need to extract the HM/CCS sequence number here */
+ if ( rr->type == SSL3_RT_HANDSHAKE ||
+ rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+ {
+ unsigned short seq_num;
+ struct hm_header_st msg_hdr;
+ struct ccs_header_st ccs_hdr;
+
+ if ( rr->type == SSL3_RT_HANDSHAKE)
+ {
+ dtls1_get_message_header(data, &msg_hdr);
+ seq_num = msg_hdr.seq;
+ *offset = msg_hdr.frag_off;
+ }
+ else
+ {
+ dtls1_get_ccs_header(data, &ccs_hdr);
+ seq_num = ccs_hdr.seq;
+ *offset = 0;
+ }
+
+ /* this is either a record we're waiting for, or a
+ * retransmit of something we happened to previously
+ * receive (higher layers will drop the repeat silently */
+ if ( seq_num < s->d1->handshake_read_seq)
+ return 0;
+ if (rr->type == SSL3_RT_HANDSHAKE &&
+ seq_num == s->d1->handshake_read_seq &&
+ msg_hdr.frag_off < s->d1->r_msg_hdr.frag_off)
+ return 0;
+ else if ( seq_num == s->d1->handshake_read_seq &&
+ (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC ||
+ msg_hdr.frag_off == s->d1->r_msg_hdr.frag_off))
+ return 0;
+ else
+ {
+ *priority = seq_num;
+ return 1;
+ }
+ }
+ else /* unknown record type */
+ return 0;
+ }
+
+ return 0;
+ }
+#endif
+
+void
+dtls1_reset_seq_numbers(SSL *s, int rw)
+ {
+ unsigned char *seq;
+ unsigned int seq_bytes = sizeof(s->s3->read_sequence);
+
+ if ( rw & SSL3_CC_READ)
+ {
+ seq = s->s3->read_sequence;
+ s->d1->r_epoch++;
+ memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP));
+ memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP));
+ }
+ else
+ {
+ seq = s->s3->write_sequence;
+ memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence));
+ s->d1->w_epoch++;
+ }
+
+ memset(seq, 0x00, seq_bytes);
+ }
diff --git a/drivers/builtin_openssl/ssl/d1_srtp.c b/drivers/builtin_openssl2/ssl/d1_srtp.c
index ab9c41922c..ab9c41922c 100644
--- a/drivers/builtin_openssl/ssl/d1_srtp.c
+++ b/drivers/builtin_openssl2/ssl/d1_srtp.c
diff --git a/drivers/builtin_openssl2/ssl/d1_srvr.c b/drivers/builtin_openssl2/ssl/d1_srvr.c
new file mode 100644
index 0000000000..1384ab0cbf
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/d1_srvr.c
@@ -0,0 +1,1723 @@
+/* ssl/d1_srvr.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2007 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/md5.h>
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+
+static const SSL_METHOD *dtls1_get_server_method(int ver);
+static int dtls1_send_hello_verify_request(SSL *s);
+
+static const SSL_METHOD *dtls1_get_server_method(int ver)
+ {
+ if (ver == DTLS1_VERSION)
+ return(DTLSv1_server_method());
+ else
+ return(NULL);
+ }
+
+IMPLEMENT_dtls1_meth_func(DTLSv1_server_method,
+ dtls1_accept,
+ ssl_undefined_function,
+ dtls1_get_server_method)
+
+int dtls1_accept(SSL *s)
+ {
+ BUF_MEM *buf;
+ unsigned long Time=(unsigned long)time(NULL);
+ void (*cb)(const SSL *ssl,int type,int val)=NULL;
+ unsigned long alg_k;
+ int ret= -1;
+ int new_state,state,skip=0;
+ int listen;
+#ifndef OPENSSL_NO_SCTP
+ unsigned char sctpauthkey[64];
+ char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+#endif
+
+ RAND_add(&Time,sizeof(Time),0);
+ ERR_clear_error();
+ clear_sys_error();
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ listen = s->d1->listen;
+
+ /* init things to blank */
+ s->in_handshake++;
+ if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+
+ s->d1->listen = listen;
+#ifndef OPENSSL_NO_SCTP
+ /* Notify SCTP BIO socket to enter handshake
+ * mode and prevent stream identifier other
+ * than 0. Will be ignored if no SCTP is used.
+ */
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
+#endif
+
+ if (s->cert == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
+ return(-1);
+ }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ dtls1_stop_timer(s);
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
+ for (;;)
+ {
+ state=s->state;
+
+ switch (s->state)
+ {
+ case SSL_ST_RENEGOTIATE:
+ s->renegotiate=1;
+ /* s->state=SSL_ST_ACCEPT; */
+
+ case SSL_ST_BEFORE:
+ case SSL_ST_ACCEPT:
+ case SSL_ST_BEFORE|SSL_ST_ACCEPT:
+ case SSL_ST_OK|SSL_ST_ACCEPT:
+
+ s->server=1;
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+ if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00))
+ {
+ SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ s->type=SSL_ST_ACCEPT;
+
+ if (s->init_buf == NULL)
+ {
+ if ((buf=BUF_MEM_new()) == NULL)
+ {
+ ret= -1;
+ goto end;
+ }
+ if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+ {
+ ret= -1;
+ goto end;
+ }
+ s->init_buf=buf;
+ }
+
+ if (!ssl3_setup_buffers(s))
+ {
+ ret= -1;
+ goto end;
+ }
+
+ s->init_num=0;
+
+ if (s->state != SSL_ST_RENEGOTIATE)
+ {
+ /* Ok, we now need to push on a buffering BIO so that
+ * the output is sent in a way that TCP likes :-)
+ * ...but not with SCTP :-)
+ */
+#ifndef OPENSSL_NO_SCTP
+ if (!BIO_dgram_is_sctp(SSL_get_wbio(s)))
+#endif
+ if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }
+
+ ssl3_init_finished_mac(s);
+ s->state=SSL3_ST_SR_CLNT_HELLO_A;
+ s->ctx->stats.sess_accept++;
+ }
+ else
+ {
+ /* s->state == SSL_ST_RENEGOTIATE,
+ * we will just send a HelloRequest */
+ s->ctx->stats.sess_accept_renegotiate++;
+ s->state=SSL3_ST_SW_HELLO_REQ_A;
+ }
+
+ break;
+
+ case SSL3_ST_SW_HELLO_REQ_A:
+ case SSL3_ST_SW_HELLO_REQ_B:
+
+ s->shutdown=0;
+ dtls1_clear_record_buffer(s);
+ dtls1_start_timer(s);
+ ret=dtls1_send_hello_request(s);
+ if (ret <= 0) goto end;
+ s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->init_num=0;
+
+ ssl3_init_finished_mac(s);
+ break;
+
+ case SSL3_ST_SW_HELLO_REQ_C:
+ s->state=SSL_ST_OK;
+ break;
+
+ case SSL3_ST_SR_CLNT_HELLO_A:
+ case SSL3_ST_SR_CLNT_HELLO_B:
+ case SSL3_ST_SR_CLNT_HELLO_C:
+
+ s->shutdown=0;
+ ret=ssl3_get_client_hello(s);
+ if (ret <= 0) goto end;
+ dtls1_stop_timer(s);
+
+ if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
+ s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
+ else
+ s->state = SSL3_ST_SW_SRVR_HELLO_A;
+
+ s->init_num=0;
+
+ /* Reflect ClientHello sequence to remain stateless while listening */
+ if (listen)
+ {
+ memcpy(s->s3->write_sequence, s->s3->read_sequence, sizeof(s->s3->write_sequence));
+ }
+
+ /* If we're just listening, stop here */
+ if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ {
+ ret = 2;
+ s->d1->listen = 0;
+ /* Set expected sequence numbers
+ * to continue the handshake.
+ */
+ s->d1->handshake_read_seq = 2;
+ s->d1->handshake_write_seq = 1;
+ s->d1->next_handshake_write_seq = 1;
+ goto end;
+ }
+
+ break;
+
+ case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
+ case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
+
+ ret = dtls1_send_hello_verify_request(s);
+ if ( ret <= 0) goto end;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
+
+ /* HelloVerifyRequest resets Finished MAC */
+ if (s->version != DTLS1_BAD_VER)
+ ssl3_init_finished_mac(s);
+ break;
+
+#ifndef OPENSSL_NO_SCTP
+ case DTLS1_SCTP_ST_SR_READ_SOCK:
+
+ if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
+ {
+ s->s3->in_read_app_data=2;
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ ret = -1;
+ goto end;
+ }
+
+ s->state=SSL3_ST_SR_FINISHED_A;
+ break;
+
+ case DTLS1_SCTP_ST_SW_WRITE_SOCK:
+ ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
+ if (ret < 0) goto end;
+
+ if (ret == 0)
+ {
+ if (s->d1->next_state != SSL_ST_OK)
+ {
+ s->s3->in_read_app_data=2;
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ ret = -1;
+ goto end;
+ }
+ }
+
+ s->state=s->d1->next_state;
+ break;
+#endif
+
+ case SSL3_ST_SW_SRVR_HELLO_A:
+ case SSL3_ST_SW_SRVR_HELLO_B:
+ s->renegotiate = 2;
+ dtls1_start_timer(s);
+ ret=dtls1_send_server_hello(s);
+ if (ret <= 0) goto end;
+
+ if (s->hit)
+ {
+#ifndef OPENSSL_NO_SCTP
+ /* Add new shared key for SCTP-Auth,
+ * will be ignored if no SCTP used.
+ */
+ snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
+ DTLS1_SCTP_AUTH_LABEL);
+
+ SSL_export_keying_material(s, sctpauthkey,
+ sizeof(sctpauthkey), labelbuffer,
+ sizeof(labelbuffer), NULL, 0, 0);
+
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+ sizeof(sctpauthkey), sctpauthkey);
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_SW_SESSION_TICKET_A;
+ else
+ s->state=SSL3_ST_SW_CHANGE_A;
+#else
+ s->state=SSL3_ST_SW_CHANGE_A;
+#endif
+ }
+ else
+ s->state=SSL3_ST_SW_CERT_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_A:
+ case SSL3_ST_SW_CERT_B:
+ /* Check if it is anon DH or normal PSK */
+ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+ {
+ dtls1_start_timer(s);
+ ret=dtls1_send_server_certificate(s);
+ if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_SW_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+ else
+ {
+ skip = 1;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+#else
+ }
+ else
+ skip=1;
+
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+#endif
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_KEY_EXCH_A:
+ case SSL3_ST_SW_KEY_EXCH_B:
+ alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+ /* clear this, it may get reset by
+ * send_server_key_exchange */
+ if ((s->options & SSL_OP_EPHEMERAL_RSA)
+#ifndef OPENSSL_NO_KRB5
+ && !(alg_k & SSL_kKRB5)
+#endif /* OPENSSL_NO_KRB5 */
+ )
+ /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
+ * even when forbidden by protocol specs
+ * (handshake may fail as clients are not required to
+ * be able to handle this) */
+ s->s3->tmp.use_rsa_tmp=1;
+ else
+ s->s3->tmp.use_rsa_tmp=0;
+
+ /* only send if a DH key exchange or
+ * RSA but we have a sign only certificate */
+ if (s->s3->tmp.use_rsa_tmp
+ /* PSK: send ServerKeyExchange if PSK identity
+ * hint if provided */
+#ifndef OPENSSL_NO_PSK
+ || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
+#endif
+ || (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+ || (alg_k & SSL_kEECDH)
+ || ((alg_k & SSL_kRSA)
+ && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
+ || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
+ && EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
+ )
+ )
+ )
+ )
+ {
+ dtls1_start_timer(s);
+ ret=dtls1_send_server_key_exchange(s);
+ if (ret <= 0) goto end;
+ }
+ else
+ skip=1;
+
+ s->state=SSL3_ST_SW_CERT_REQ_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_REQ_A:
+ case SSL3_ST_SW_CERT_REQ_B:
+ if (/* don't request cert unless asked for it: */
+ !(s->verify_mode & SSL_VERIFY_PEER) ||
+ /* if SSL_VERIFY_CLIENT_ONCE is set,
+ * don't request cert during re-negotiation: */
+ ((s->session->peer != NULL) &&
+ (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
+ /* never request cert in anonymous ciphersuites
+ * (see section "Certificate request" in SSL 3 drafts
+ * and in RFC 2246): */
+ ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
+ /* ... except when the application insists on verification
+ * (against the specs, but s3_clnt.c accepts this for SSL 3) */
+ !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
+ /* never request cert in Kerberos ciphersuites */
+ (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
+ /* With normal PSK Certificates and
+ * Certificate Requests are omitted */
+ || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+ {
+ /* no cert request */
+ skip=1;
+ s->s3->tmp.cert_request=0;
+ s->state=SSL3_ST_SW_SRVR_DONE_A;
+#ifndef OPENSSL_NO_SCTP
+ if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
+ {
+ s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
+ s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
+ }
+#endif
+ }
+ else
+ {
+ s->s3->tmp.cert_request=1;
+ dtls1_start_timer(s);
+ ret=dtls1_send_certificate_request(s);
+ if (ret <= 0) goto end;
+#ifndef NETSCAPE_HANG_BUG
+ s->state=SSL3_ST_SW_SRVR_DONE_A;
+#ifndef OPENSSL_NO_SCTP
+ if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
+ {
+ s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
+ s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
+ }
+#endif
+#else
+ s->state=SSL3_ST_SW_FLUSH;
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+#ifndef OPENSSL_NO_SCTP
+ if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
+ {
+ s->d1->next_state = s->s3->tmp.next_state;
+ s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK;
+ }
+#endif
+#endif
+ s->init_num=0;
+ }
+ break;
+
+ case SSL3_ST_SW_SRVR_DONE_A:
+ case SSL3_ST_SW_SRVR_DONE_B:
+ dtls1_start_timer(s);
+ ret=dtls1_send_server_done(s);
+ if (ret <= 0) goto end;
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_FLUSH:
+ s->rwstate=SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0)
+ {
+ /* If the write error was fatal, stop trying */
+ if (!BIO_should_retry(s->wbio))
+ {
+ s->rwstate=SSL_NOTHING;
+ s->state=s->s3->tmp.next_state;
+ }
+
+ ret= -1;
+ goto end;
+ }
+ s->rwstate=SSL_NOTHING;
+ s->state=s->s3->tmp.next_state;
+ break;
+
+ case SSL3_ST_SR_CERT_A:
+ case SSL3_ST_SR_CERT_B:
+ /* Check for second client hello (MS SGC) */
+ ret = ssl3_check_client_hello(s);
+ if (ret <= 0)
+ goto end;
+ if (ret == 2)
+ {
+ dtls1_stop_timer(s);
+ s->state = SSL3_ST_SR_CLNT_HELLO_C;
+ }
+ else {
+ /* could be sent for a DH cert, even if we
+ * have not asked for it :-) */
+ ret=ssl3_get_client_certificate(s);
+ if (ret <= 0) goto end;
+ s->init_num=0;
+ s->state=SSL3_ST_SR_KEY_EXCH_A;
+ }
+ break;
+
+ case SSL3_ST_SR_KEY_EXCH_A:
+ case SSL3_ST_SR_KEY_EXCH_B:
+ ret=ssl3_get_client_key_exchange(s);
+ if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_SCTP
+ /* Add new shared key for SCTP-Auth,
+ * will be ignored if no SCTP used.
+ */
+ snprintf((char *) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
+ DTLS1_SCTP_AUTH_LABEL);
+
+ SSL_export_keying_material(s, sctpauthkey,
+ sizeof(sctpauthkey), labelbuffer,
+ sizeof(labelbuffer), NULL, 0, 0);
+
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+ sizeof(sctpauthkey), sctpauthkey);
+#endif
+
+ s->state=SSL3_ST_SR_CERT_VRFY_A;
+ s->init_num=0;
+
+ if (ret == 2)
+ {
+ /* For the ECDH ciphersuites when
+ * the client sends its ECDH pub key in
+ * a certificate, the CertificateVerify
+ * message is not sent.
+ */
+ s->state=SSL3_ST_SR_FINISHED_A;
+ s->init_num = 0;
+ }
+ else
+ {
+ s->state=SSL3_ST_SR_CERT_VRFY_A;
+ s->init_num=0;
+
+ /* We need to get hashes here so if there is
+ * a client cert, it can be verified */
+ s->method->ssl3_enc->cert_verify_mac(s,
+ NID_md5,
+ &(s->s3->tmp.cert_verify_md[0]));
+ s->method->ssl3_enc->cert_verify_mac(s,
+ NID_sha1,
+ &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
+ }
+ break;
+
+ case SSL3_ST_SR_CERT_VRFY_A:
+ case SSL3_ST_SR_CERT_VRFY_B:
+
+ s->d1->change_cipher_spec_ok = 1;
+ /* we should decide if we expected this one */
+ ret=ssl3_get_cert_verify(s);
+ if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_SCTP
+ if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
+ state == SSL_ST_RENEGOTIATE)
+ s->state=DTLS1_SCTP_ST_SR_READ_SOCK;
+ else
+#endif
+ s->state=SSL3_ST_SR_FINISHED_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SR_FINISHED_A:
+ case SSL3_ST_SR_FINISHED_B:
+ s->d1->change_cipher_spec_ok = 1;
+ ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
+ SSL3_ST_SR_FINISHED_B);
+ if (ret <= 0) goto end;
+ dtls1_stop_timer(s);
+ if (s->hit)
+ s->state=SSL_ST_OK;
+#ifndef OPENSSL_NO_TLSEXT
+ else if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_SW_SESSION_TICKET_A;
+#endif
+ else
+ s->state=SSL3_ST_SW_CHANGE_A;
+ s->init_num=0;
+ break;
+
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_SW_SESSION_TICKET_A:
+ case SSL3_ST_SW_SESSION_TICKET_B:
+ ret=dtls1_send_newsession_ticket(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_CHANGE_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_STATUS_A:
+ case SSL3_ST_SW_CERT_STATUS_B:
+ ret=ssl3_send_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+
+#endif
+
+ case SSL3_ST_SW_CHANGE_A:
+ case SSL3_ST_SW_CHANGE_B:
+
+ s->session->cipher=s->s3->tmp.new_cipher;
+ if (!s->method->ssl3_enc->setup_key_block(s))
+ { ret= -1; goto end; }
+
+ ret=dtls1_send_change_cipher_spec(s,
+ SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);
+
+ if (ret <= 0) goto end;
+
+#ifndef OPENSSL_NO_SCTP
+ if (!s->hit)
+ {
+ /* Change to new shared key of SCTP-Auth,
+ * will be ignored if no SCTP used.
+ */
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
+ }
+#endif
+
+ s->state=SSL3_ST_SW_FINISHED_A;
+ s->init_num=0;
+
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CHANGE_CIPHER_SERVER_WRITE))
+ {
+ ret= -1;
+ goto end;
+ }
+
+ dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+ break;
+
+ case SSL3_ST_SW_FINISHED_A:
+ case SSL3_ST_SW_FINISHED_B:
+ ret=dtls1_send_finished(s,
+ SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
+ s->method->ssl3_enc->server_finished_label,
+ s->method->ssl3_enc->server_finished_label_len);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_FLUSH;
+ if (s->hit)
+ {
+ s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+
+#ifndef OPENSSL_NO_SCTP
+ /* Change to new shared key of SCTP-Auth,
+ * will be ignored if no SCTP used.
+ */
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
+#endif
+ }
+ else
+ {
+ s->s3->tmp.next_state=SSL_ST_OK;
+#ifndef OPENSSL_NO_SCTP
+ if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
+ {
+ s->d1->next_state = s->s3->tmp.next_state;
+ s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK;
+ }
+#endif
+ }
+ s->init_num=0;
+ break;
+
+ case SSL_ST_OK:
+ /* clean a few things up */
+ ssl3_cleanup_key_block(s);
+
+#if 0
+ BUF_MEM_free(s->init_buf);
+ s->init_buf=NULL;
+#endif
+
+ /* remove buffering on output */
+ ssl_free_wbio_buffer(s);
+
+ s->init_num=0;
+
+ if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
+ {
+ s->renegotiate=0;
+ s->new_session=0;
+
+ ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
+
+ s->ctx->stats.sess_accept_good++;
+ /* s->server=1; */
+ s->handshake_func=dtls1_accept;
+
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+ }
+
+ ret = 1;
+
+ /* done handshaking, next message is client hello */
+ s->d1->handshake_read_seq = 0;
+ /* next message is server hello */
+ s->d1->handshake_write_seq = 0;
+ s->d1->next_handshake_write_seq = 0;
+ goto end;
+ /* break; */
+
+ default:
+ SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_UNKNOWN_STATE);
+ ret= -1;
+ goto end;
+ /* break; */
+ }
+
+ if (!s->s3->tmp.reuse_message && !skip)
+ {
+ if (s->debug)
+ {
+ if ((ret=BIO_flush(s->wbio)) <= 0)
+ goto end;
+ }
+
+
+ if ((cb != NULL) && (s->state != state))
+ {
+ new_state=s->state;
+ s->state=state;
+ cb(s,SSL_CB_ACCEPT_LOOP,1);
+ s->state=new_state;
+ }
+ }
+ skip=0;
+ }
+end:
+ /* BIO_flush(s->wbio); */
+
+ s->in_handshake--;
+#ifndef OPENSSL_NO_SCTP
+ /* Notify SCTP BIO socket to leave handshake
+ * mode and prevent stream identifier other
+ * than 0. Will be ignored if no SCTP is used.
+ */
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
+#endif
+
+ if (cb != NULL)
+ cb(s,SSL_CB_ACCEPT_EXIT,ret);
+ return(ret);
+ }
+
+int dtls1_send_hello_request(SSL *s)
+ {
+ unsigned char *p;
+
+ if (s->state == SSL3_ST_SW_HELLO_REQ_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+ p = dtls1_set_message_header(s, p, SSL3_MT_HELLO_REQUEST, 0, 0, 0);
+
+ s->state=SSL3_ST_SW_HELLO_REQ_B;
+ /* number of bytes to write */
+ s->init_num=DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+
+ /* no need to buffer this message, since there are no retransmit
+ * requests for it */
+ }
+
+ /* SSL3_ST_SW_HELLO_REQ_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int dtls1_send_hello_verify_request(SSL *s)
+ {
+ unsigned int msg_len;
+ unsigned char *msg, *buf, *p;
+
+ if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A)
+ {
+ buf = (unsigned char *)s->init_buf->data;
+
+ msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
+ *(p++) = s->version >> 8;
+ *(p++) = s->version & 0xFF;
+
+ if (s->ctx->app_gen_cookie_cb == NULL ||
+ s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+ &(s->d1->cookie_len)) == 0)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ *(p++) = (unsigned char) s->d1->cookie_len;
+ memcpy(p, s->d1->cookie, s->d1->cookie_len);
+ p += s->d1->cookie_len;
+ msg_len = p - msg;
+
+ dtls1_set_message_header(s, buf,
+ DTLS1_MT_HELLO_VERIFY_REQUEST, msg_len, 0, msg_len);
+
+ s->state=DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
+ /* number of bytes to write */
+ s->init_num=p-buf;
+ s->init_off=0;
+ }
+
+ /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int dtls1_send_server_hello(SSL *s)
+ {
+ unsigned char *buf;
+ unsigned char *p,*d;
+ int i;
+ unsigned int sl;
+ unsigned long l;
+
+ if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ {
+ buf=(unsigned char *)s->init_buf->data;
+ p=s->s3->server_random;
+ ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE);
+ /* Do the message type and length last */
+ d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
+
+ *(p++)=s->version>>8;
+ *(p++)=s->version&0xff;
+
+ /* Random stuff */
+ memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
+ p+=SSL3_RANDOM_SIZE;
+
+ /* now in theory we have 3 options to sending back the
+ * session id. If it is a re-use, we send back the
+ * old session-id, if it is a new session, we send
+ * back the new session-id or we send back a 0 length
+ * session-id if we want it to be single use.
+ * Currently I will not implement the '0' length session-id
+ * 12-Jan-98 - I'll now support the '0' length stuff.
+ */
+ if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER))
+ s->session->session_id_length=0;
+
+ sl=s->session->session_id_length;
+ if (sl > sizeof s->session->session_id)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ *(p++)=sl;
+ memcpy(p,s->session->session_id,sl);
+ p+=sl;
+
+ /* put the cipher */
+ if (s->s3->tmp.new_cipher == NULL)
+ return -1;
+ i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
+ p+=i;
+
+ /* put the compression method */
+#ifdef OPENSSL_NO_COMP
+ *(p++)=0;
+#else
+ if (s->s3->tmp.new_compression == NULL)
+ *(p++)=0;
+ else
+ *(p++)=s->s3->tmp.new_compression->id;
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+ if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+#endif
+
+ /* do the header */
+ l=(p-d);
+ d=buf;
+
+ d = dtls1_set_message_header(s, d, SSL3_MT_SERVER_HELLO, l, 0, l);
+
+ s->state=SSL3_ST_SW_SRVR_HELLO_B;
+ /* number of bytes to write */
+ s->init_num=p-buf;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* SSL3_ST_SW_SRVR_HELLO_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int dtls1_send_server_done(SSL *s)
+ {
+ unsigned char *p;
+
+ if (s->state == SSL3_ST_SW_SRVR_DONE_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+
+ /* do the header */
+ p = dtls1_set_message_header(s, p, SSL3_MT_SERVER_DONE, 0, 0, 0);
+
+ s->state=SSL3_ST_SW_SRVR_DONE_B;
+ /* number of bytes to write */
+ s->init_num=DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* SSL3_ST_SW_SRVR_DONE_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int dtls1_send_server_key_exchange(SSL *s)
+ {
+#ifndef OPENSSL_NO_RSA
+ unsigned char *q;
+ int j,num;
+ RSA *rsa;
+ unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+ unsigned int u;
+#endif
+#ifndef OPENSSL_NO_DH
+ DH *dh=NULL,*dhp;
+#endif
+#ifndef OPENSSL_NO_ECDH
+ EC_KEY *ecdh=NULL, *ecdhp;
+ unsigned char *encodedPoint = NULL;
+ int encodedlen = 0;
+ int curve_id = 0;
+ BN_CTX *bn_ctx = NULL;
+#endif
+ EVP_PKEY *pkey;
+ unsigned char *p,*d;
+ int al,i;
+ unsigned long type;
+ int n;
+ CERT *cert;
+ BIGNUM *r[4];
+ int nr[4],kn;
+ BUF_MEM *buf;
+ EVP_MD_CTX md_ctx;
+
+ EVP_MD_CTX_init(&md_ctx);
+ if (s->state == SSL3_ST_SW_KEY_EXCH_A)
+ {
+ type=s->s3->tmp.new_cipher->algorithm_mkey;
+ cert=s->cert;
+
+ buf=s->init_buf;
+
+ r[0]=r[1]=r[2]=r[3]=NULL;
+ n=0;
+#ifndef OPENSSL_NO_RSA
+ if (type & SSL_kRSA)
+ {
+ rsa=cert->rsa_tmp;
+ if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
+ {
+ rsa=s->cert->rsa_tmp_cb(s,
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ if(rsa == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
+ goto f_err;
+ }
+ RSA_up_ref(rsa);
+ cert->rsa_tmp=rsa;
+ }
+ if (rsa == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_KEY);
+ goto f_err;
+ }
+ r[0]=rsa->n;
+ r[1]=rsa->e;
+ s->s3->tmp.use_rsa_tmp=1;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_DH
+ if (type & SSL_kEDH)
+ {
+ dhp=cert->dh_tmp;
+ if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
+ dhp=s->cert->dh_tmp_cb(s,
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ if (dhp == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
+ goto f_err;
+ }
+
+ if (s->s3->tmp.dh != NULL)
+ {
+ DH_free(dh);
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if ((dh=DHparams_dup(dhp)) == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+
+ s->s3->tmp.dh=dh;
+ if ((dhp->pub_key == NULL ||
+ dhp->priv_key == NULL ||
+ (s->options & SSL_OP_SINGLE_DH_USE)))
+ {
+ if(!DH_generate_key(dh))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,
+ ERR_R_DH_LIB);
+ goto err;
+ }
+ }
+ else
+ {
+ dh->pub_key=BN_dup(dhp->pub_key);
+ dh->priv_key=BN_dup(dhp->priv_key);
+ if ((dh->pub_key == NULL) ||
+ (dh->priv_key == NULL))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+ }
+ r[0]=dh->p;
+ r[1]=dh->g;
+ r[2]=dh->pub_key;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_ECDH
+ if (type & SSL_kEECDH)
+ {
+ const EC_GROUP *group;
+
+ ecdhp=cert->ecdh_tmp;
+ if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+ {
+ ecdhp=s->cert->ecdh_tmp_cb(s,
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ }
+ if (ecdhp == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+ goto f_err;
+ }
+
+ if (s->s3->tmp.ecdh != NULL)
+ {
+ EC_KEY_free(s->s3->tmp.ecdh);
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* Duplicate the ECDH structure. */
+ if (ecdhp == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+ if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ s->s3->tmp.ecdh=ecdh;
+ if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
+ (EC_KEY_get0_private_key(ecdh) == NULL) ||
+ (s->options & SSL_OP_SINGLE_ECDH_USE))
+ {
+ if(!EC_KEY_generate_key(ecdh))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+ }
+
+ if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
+ (EC_KEY_get0_public_key(ecdh) == NULL) ||
+ (EC_KEY_get0_private_key(ecdh) == NULL))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+ (EC_GROUP_get_degree(group) > 163))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+ goto err;
+ }
+
+ /* XXX: For now, we only support ephemeral ECDH
+ * keys over named (not generic) curves. For
+ * supported named curves, curve_id is non-zero.
+ */
+ if ((curve_id =
+ tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
+ == 0)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+ goto err;
+ }
+
+ /* Encode the public key.
+ * First check the size of encoding and
+ * allocate memory accordingly.
+ */
+ encodedlen = EC_POINT_point2oct(group,
+ EC_KEY_get0_public_key(ecdh),
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, NULL);
+
+ encodedPoint = (unsigned char *)
+ OPENSSL_malloc(encodedlen*sizeof(unsigned char));
+ bn_ctx = BN_CTX_new();
+ if ((encodedPoint == NULL) || (bn_ctx == NULL))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+
+ encodedlen = EC_POINT_point2oct(group,
+ EC_KEY_get0_public_key(ecdh),
+ POINT_CONVERSION_UNCOMPRESSED,
+ encodedPoint, encodedlen, bn_ctx);
+
+ if (encodedlen == 0)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ BN_CTX_free(bn_ctx); bn_ctx=NULL;
+
+ /* XXX: For now, we only support named (not
+ * generic) curves in ECDH ephemeral key exchanges.
+ * In this situation, we need four additional bytes
+ * to encode the entire ServerECDHParams
+ * structure.
+ */
+ n = 4 + encodedlen;
+
+ /* We'll generate the serverKeyExchange message
+ * explicitly so we can set these to NULLs
+ */
+ r[0]=NULL;
+ r[1]=NULL;
+ r[2]=NULL;
+ r[3]=NULL;
+ }
+ else
+#endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_PSK
+ if (type & SSL_kPSK)
+ {
+ /* reserve size for record length and PSK identity hint*/
+ n+=2+strlen(s->ctx->psk_identity_hint);
+ }
+ else
+#endif /* !OPENSSL_NO_PSK */
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+ goto f_err;
+ }
+ for (i=0; r[i] != NULL; i++)
+ {
+ nr[i]=BN_num_bytes(r[i]);
+ n+=2+nr[i];
+ }
+
+ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+ {
+ if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher, NULL))
+ == NULL)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ kn=EVP_PKEY_size(pkey);
+ }
+ else
+ {
+ pkey=NULL;
+ kn=0;
+ }
+
+ if (!BUF_MEM_grow_clean(buf,n+DTLS1_HM_HEADER_LENGTH+kn))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF);
+ goto err;
+ }
+ d=(unsigned char *)s->init_buf->data;
+ p= &(d[DTLS1_HM_HEADER_LENGTH]);
+
+ for (i=0; r[i] != NULL; i++)
+ {
+ s2n(nr[i],p);
+ BN_bn2bin(r[i],p);
+ p+=nr[i];
+ }
+
+#ifndef OPENSSL_NO_ECDH
+ if (type & SSL_kEECDH)
+ {
+ /* XXX: For now, we only support named (not generic) curves.
+ * In this situation, the serverKeyExchange message has:
+ * [1 byte CurveType], [2 byte CurveName]
+ * [1 byte length of encoded point], followed by
+ * the actual encoded point itself
+ */
+ *p = NAMED_CURVE_TYPE;
+ p += 1;
+ *p = 0;
+ p += 1;
+ *p = curve_id;
+ p += 1;
+ *p = encodedlen;
+ p += 1;
+ memcpy((unsigned char*)p,
+ (unsigned char *)encodedPoint,
+ encodedlen);
+ OPENSSL_free(encodedPoint);
+ encodedPoint = NULL;
+ p += encodedlen;
+ }
+#endif
+
+#ifndef OPENSSL_NO_PSK
+ if (type & SSL_kPSK)
+ {
+ /* copy PSK identity hint */
+ s2n(strlen(s->ctx->psk_identity_hint), p);
+ strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
+ p+=strlen(s->ctx->psk_identity_hint);
+ }
+#endif
+
+ /* not anonymous */
+ if (pkey != NULL)
+ {
+ /* n is the length of the params, they start at
+ * &(d[DTLS1_HM_HEADER_LENGTH]) and p points to the space
+ * at the end. */
+#ifndef OPENSSL_NO_RSA
+ if (pkey->type == EVP_PKEY_RSA)
+ {
+ q=md_buf;
+ j=0;
+ for (num=2; num > 0; num--)
+ {
+ EVP_DigestInit_ex(&md_ctx,(num == 2)
+ ?s->ctx->md5:s->ctx->sha1, NULL);
+ EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
+ EVP_DigestFinal_ex(&md_ctx,q,
+ (unsigned int *)&i);
+ q+=i;
+ j+=i;
+ }
+ if (RSA_sign(NID_md5_sha1, md_buf, j,
+ &(p[2]), &u, pkey->pkey.rsa) <= 0)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
+ goto err;
+ }
+ s2n(u,p);
+ n+=u+2;
+ }
+ else
+#endif
+#if !defined(OPENSSL_NO_DSA)
+ if (pkey->type == EVP_PKEY_DSA)
+ {
+ /* lets do DSS */
+ EVP_SignInit_ex(&md_ctx,EVP_dss1(), NULL);
+ EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
+ if (!EVP_SignFinal(&md_ctx,&(p[2]),
+ (unsigned int *)&i,pkey))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_DSA);
+ goto err;
+ }
+ s2n(i,p);
+ n+=i+2;
+ }
+ else
+#endif
+#if !defined(OPENSSL_NO_ECDSA)
+ if (pkey->type == EVP_PKEY_EC)
+ {
+ /* let's do ECDSA */
+ EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+ EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
+ if (!EVP_SignFinal(&md_ctx,&(p[2]),
+ (unsigned int *)&i,pkey))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA);
+ goto err;
+ }
+ s2n(i,p);
+ n+=i+2;
+ }
+ else
+#endif
+ {
+ /* Is this error check actually needed? */
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
+ goto f_err;
+ }
+ }
+
+ d = dtls1_set_message_header(s, d,
+ SSL3_MT_SERVER_KEY_EXCHANGE, n, 0, n);
+
+ /* we should now have things packed up, so lets send
+ * it off */
+ s->init_num=n+DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ s->state = SSL3_ST_SW_KEY_EXCH_B;
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+#ifndef OPENSSL_NO_ECDH
+ if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+ BN_CTX_free(bn_ctx);
+#endif
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return(-1);
+ }
+
+int dtls1_send_certificate_request(SSL *s)
+ {
+ unsigned char *p,*d;
+ int i,j,nl,off,n;
+ STACK_OF(X509_NAME) *sk=NULL;
+ X509_NAME *name;
+ BUF_MEM *buf;
+ unsigned int msg_len;
+
+ if (s->state == SSL3_ST_SW_CERT_REQ_A)
+ {
+ buf=s->init_buf;
+
+ d=p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]);
+
+ /* get the list of acceptable cert types */
+ p++;
+ n=ssl3_get_req_cert_type(s,p);
+ d[0]=n;
+ p+=n;
+ n++;
+
+ off=n;
+ p+=2;
+ n+=2;
+
+ sk=SSL_get_client_CA_list(s);
+ nl=0;
+ if (sk != NULL)
+ {
+ for (i=0; i<sk_X509_NAME_num(sk); i++)
+ {
+ name=sk_X509_NAME_value(sk,i);
+ j=i2d_X509_NAME(name,NULL);
+ if (!BUF_MEM_grow_clean(buf,DTLS1_HM_HEADER_LENGTH+n+j+2))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
+ goto err;
+ }
+ p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+n]);
+ if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
+ {
+ s2n(j,p);
+ i2d_X509_NAME(name,&p);
+ n+=2+j;
+ nl+=2+j;
+ }
+ else
+ {
+ d=p;
+ i2d_X509_NAME(name,&p);
+ j-=2; s2n(j,d); j+=2;
+ n+=j;
+ nl+=j;
+ }
+ }
+ }
+ /* else no CA names */
+ p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+off]);
+ s2n(nl,p);
+
+ d=(unsigned char *)buf->data;
+ *(d++)=SSL3_MT_CERTIFICATE_REQUEST;
+ l2n3(n,d);
+ s2n(s->d1->handshake_write_seq,d);
+ s->d1->handshake_write_seq++;
+
+ /* we should now have things packed up, so lets send
+ * it off */
+
+ s->init_num=n+DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+#ifdef NETSCAPE_HANG_BUG
+/* XXX: what to do about this? */
+ p=(unsigned char *)s->init_buf->data + s->init_num;
+
+ /* do the header */
+ *(p++)=SSL3_MT_SERVER_DONE;
+ *(p++)=0;
+ *(p++)=0;
+ *(p++)=0;
+ s->init_num += 4;
+#endif
+
+ /* XDTLS: set message header ? */
+ msg_len = s->init_num - DTLS1_HM_HEADER_LENGTH;
+ dtls1_set_message_header(s, (void *)s->init_buf->data,
+ SSL3_MT_CERTIFICATE_REQUEST, msg_len, 0, msg_len);
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+
+ s->state = SSL3_ST_SW_CERT_REQ_B;
+ }
+
+ /* SSL3_ST_SW_CERT_REQ_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+ return(-1);
+ }
+
+int dtls1_send_server_certificate(SSL *s)
+ {
+ unsigned long l;
+ X509 *x;
+
+ if (s->state == SSL3_ST_SW_CERT_A)
+ {
+ x=ssl_get_server_send_cert(s);
+ if (x == NULL)
+ {
+ /* VRS: allow null cert if auth == KRB5 */
+ if ((s->s3->tmp.new_cipher->algorithm_mkey != SSL_kKRB5) ||
+ (s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5))
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR);
+ return(0);
+ }
+ }
+
+ l=dtls1_output_cert_chain(s,x);
+ s->state=SSL3_ST_SW_CERT_B;
+ s->init_num=(int)l;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* SSL3_ST_SW_CERT_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+#ifndef OPENSSL_NO_TLSEXT
+int dtls1_send_newsession_ticket(SSL *s)
+ {
+ if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
+ {
+ unsigned char *p, *senc, *macstart;
+ int len, slen;
+ unsigned int hlen, msg_len;
+ EVP_CIPHER_CTX ctx;
+ HMAC_CTX hctx;
+ SSL_CTX *tctx = s->initial_ctx;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char key_name[16];
+
+ /* get session encoding length */
+ slen = i2d_SSL_SESSION(s->session, NULL);
+ /* Some length values are 16 bits, so forget it if session is
+ * too long
+ */
+ if (slen > 0xFF00)
+ return -1;
+ /* Grow buffer if need be: the length calculation is as
+ * follows 12 (DTLS handshake message header) +
+ * 4 (ticket lifetime hint) + 2 (ticket length) +
+ * 16 (key name) + max_iv_len (iv length) +
+ * session_length + max_enc_block_size (max encrypted session
+ * length) + max_md_size (HMAC).
+ */
+ if (!BUF_MEM_grow(s->init_buf,
+ DTLS1_HM_HEADER_LENGTH + 22 + EVP_MAX_IV_LENGTH +
+ EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
+ return -1;
+ senc = OPENSSL_malloc(slen);
+ if (!senc)
+ return -1;
+ p = senc;
+ i2d_SSL_SESSION(s->session, &p);
+
+ p=(unsigned char *)&(s->init_buf->data[DTLS1_HM_HEADER_LENGTH]);
+ EVP_CIPHER_CTX_init(&ctx);
+ HMAC_CTX_init(&hctx);
+ /* Initialize HMAC and cipher contexts. If callback present
+ * it does all the work otherwise use generated values
+ * from parent ctx.
+ */
+ if (tctx->tlsext_ticket_key_cb)
+ {
+ if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
+ &hctx, 1) < 0)
+ {
+ OPENSSL_free(senc);
+ return -1;
+ }
+ }
+ else
+ {
+ RAND_pseudo_bytes(iv, 16);
+ EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ tctx->tlsext_tick_aes_key, iv);
+ HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+ tlsext_tick_md(), NULL);
+ memcpy(key_name, tctx->tlsext_tick_key_name, 16);
+ }
+ l2n(s->session->tlsext_tick_lifetime_hint, p);
+ /* Skip ticket length for now */
+ p += 2;
+ /* Output key name */
+ macstart = p;
+ memcpy(p, key_name, 16);
+ p += 16;
+ /* output IV */
+ memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
+ p += EVP_CIPHER_CTX_iv_length(&ctx);
+ /* Encrypt session data */
+ EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
+ p += len;
+ EVP_EncryptFinal(&ctx, p, &len);
+ p += len;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ HMAC_Update(&hctx, macstart, p - macstart);
+ HMAC_Final(&hctx, p, &hlen);
+ HMAC_CTX_cleanup(&hctx);
+
+ p += hlen;
+ /* Now write out lengths: p points to end of data written */
+ /* Total length */
+ len = p - (unsigned char *)(s->init_buf->data);
+ /* Ticket length */
+ p=(unsigned char *)&(s->init_buf->data[DTLS1_HM_HEADER_LENGTH]) + 4;
+ s2n(len - DTLS1_HM_HEADER_LENGTH - 6, p);
+
+ /* number of bytes to write */
+ s->init_num= len;
+ s->state=SSL3_ST_SW_SESSION_TICKET_B;
+ s->init_off=0;
+ OPENSSL_free(senc);
+
+ /* XDTLS: set message header ? */
+ msg_len = s->init_num - DTLS1_HM_HEADER_LENGTH;
+ dtls1_set_message_header(s, (void *)s->init_buf->data,
+ SSL3_MT_NEWSESSION_TICKET, msg_len, 0, msg_len);
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* SSL3_ST_SW_SESSION_TICKET_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+#endif
diff --git a/drivers/builtin_openssl2/ssl/heartbeat_test.c b/drivers/builtin_openssl2/ssl/heartbeat_test.c
new file mode 100644
index 0000000000..d8cc559981
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/heartbeat_test.c
@@ -0,0 +1,465 @@
+/* test/heartbeat_test.c */
+/*
+ * Unit test for TLS heartbeats.
+ *
+ * Acts as a regression test against the Heartbleed bug (CVE-2014-0160).
+ *
+ * Author: Mike Bland (mbland@acm.org, http://mike-bland.com/)
+ * Date: 2014-04-12
+ * License: Creative Commons Attribution 4.0 International (CC By 4.0)
+ * http://creativecommons.org/licenses/by/4.0/deed.en_US
+ *
+ * OUTPUT
+ * ------
+ * The program returns zero on success. It will print a message with a count
+ * of the number of failed tests and return nonzero if any tests fail.
+ *
+ * It will print the contents of the request and response buffers for each
+ * failing test. In a "fixed" version, all the tests should pass and there
+ * should be no output.
+ *
+ * In a "bleeding" version, you'll see:
+ *
+ * test_dtls1_heartbleed failed:
+ * expected payload len: 0
+ * received: 1024
+ * sent 26 characters
+ * "HEARTBLEED "
+ * received 1024 characters
+ * "HEARTBLEED \xde\xad\xbe\xef..."
+ * ** test_dtls1_heartbleed failed **
+ *
+ * The contents of the returned buffer in the failing test will depend on the
+ * contents of memory on your machine.
+ *
+ * MORE INFORMATION
+ * ----------------
+ * http://mike-bland.com/2014/04/12/heartbleed.html
+ * http://mike-bland.com/tags/heartbleed.html
+ */
+
+#include "../ssl/ssl_locl.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(OPENSSL_NO_HEARTBEATS) && !defined(OPENSSL_SYS_WINDOWS)
+
+/* As per https://tools.ietf.org/html/rfc6520#section-4 */
+#define MIN_PADDING_SIZE 16
+
+/* Maximum number of payload characters to print as test output */
+#define MAX_PRINTABLE_CHARACTERS 1024
+
+typedef struct heartbeat_test_fixture
+ {
+ SSL_CTX *ctx;
+ SSL *s;
+ const char* test_case_name;
+ int (*process_heartbeat)(SSL* s);
+ unsigned char* payload;
+ int sent_payload_len;
+ int expected_return_value;
+ int return_payload_offset;
+ int expected_payload_len;
+ const char* expected_return_payload;
+ } HEARTBEAT_TEST_FIXTURE;
+
+static HEARTBEAT_TEST_FIXTURE set_up(const char* const test_case_name,
+ const SSL_METHOD* meth)
+ {
+ HEARTBEAT_TEST_FIXTURE fixture;
+ int setup_ok = 1;
+ memset(&fixture, 0, sizeof(fixture));
+ fixture.test_case_name = test_case_name;
+
+ fixture.ctx = SSL_CTX_new(meth);
+ if (!fixture.ctx)
+ {
+ fprintf(stderr, "Failed to allocate SSL_CTX for test: %s\n",
+ test_case_name);
+ setup_ok = 0;
+ goto fail;
+ }
+
+ fixture.s = SSL_new(fixture.ctx);
+ if (!fixture.s)
+ {
+ fprintf(stderr, "Failed to allocate SSL for test: %s\n", test_case_name);
+ setup_ok = 0;
+ goto fail;
+ }
+
+ if (!ssl_init_wbio_buffer(fixture.s, 1))
+ {
+ fprintf(stderr, "Failed to set up wbio buffer for test: %s\n",
+ test_case_name);
+ setup_ok = 0;
+ goto fail;
+ }
+
+ if (!ssl3_setup_buffers(fixture.s))
+ {
+ fprintf(stderr, "Failed to setup buffers for test: %s\n",
+ test_case_name);
+ setup_ok = 0;
+ goto fail;
+ }
+
+ /* Clear the memory for the return buffer, since this isn't automatically
+ * zeroed in opt mode and will cause spurious test failures that will change
+ * with each execution.
+ */
+ memset(fixture.s->s3->wbuf.buf, 0, fixture.s->s3->wbuf.len);
+
+ fail:
+ if (!setup_ok)
+ {
+ ERR_print_errors_fp(stderr);
+ exit(EXIT_FAILURE);
+ }
+ return fixture;
+ }
+
+static HEARTBEAT_TEST_FIXTURE set_up_dtls(const char* const test_case_name)
+ {
+ HEARTBEAT_TEST_FIXTURE fixture = set_up(test_case_name,
+ DTLSv1_server_method());
+ fixture.process_heartbeat = dtls1_process_heartbeat;
+
+ /* As per dtls1_get_record(), skipping the following from the beginning of
+ * the returned heartbeat message:
+ * type-1 byte; version-2 bytes; sequence number-8 bytes; length-2 bytes
+ *
+ * And then skipping the 1-byte type encoded by process_heartbeat for
+ * a total of 14 bytes, at which point we can grab the length and the
+ * payload we seek.
+ */
+ fixture.return_payload_offset = 14;
+ return fixture;
+ }
+
+/* Needed by ssl3_write_bytes() */
+static int dummy_handshake(SSL* s)
+ {
+ return 1;
+ }
+
+static HEARTBEAT_TEST_FIXTURE set_up_tls(const char* const test_case_name)
+ {
+ HEARTBEAT_TEST_FIXTURE fixture = set_up(test_case_name,
+ TLSv1_server_method());
+ fixture.process_heartbeat = tls1_process_heartbeat;
+ fixture.s->handshake_func = dummy_handshake;
+
+ /* As per do_ssl3_write(), skipping the following from the beginning of
+ * the returned heartbeat message:
+ * type-1 byte; version-2 bytes; length-2 bytes
+ *
+ * And then skipping the 1-byte type encoded by process_heartbeat for
+ * a total of 6 bytes, at which point we can grab the length and the payload
+ * we seek.
+ */
+ fixture.return_payload_offset = 6;
+ return fixture;
+ }
+
+static void tear_down(HEARTBEAT_TEST_FIXTURE fixture)
+ {
+ ERR_print_errors_fp(stderr);
+ SSL_free(fixture.s);
+ SSL_CTX_free(fixture.ctx);
+ }
+
+static void print_payload(const char* const prefix,
+ const unsigned char *payload, const int n)
+ {
+ const int end = n < MAX_PRINTABLE_CHARACTERS ? n
+ : MAX_PRINTABLE_CHARACTERS;
+ int i = 0;
+
+ printf("%s %d character%s", prefix, n, n == 1 ? "" : "s");
+ if (end != n) printf(" (first %d shown)", end);
+ printf("\n \"");
+
+ for (; i != end; ++i)
+ {
+ const unsigned char c = payload[i];
+ if (isprint(c)) fputc(c, stdout);
+ else printf("\\x%02x", c);
+ }
+ printf("\"\n");
+ }
+
+static int execute_heartbeat(HEARTBEAT_TEST_FIXTURE fixture)
+ {
+ int result = 0;
+ SSL* s = fixture.s;
+ unsigned char *payload = fixture.payload;
+ unsigned char sent_buf[MAX_PRINTABLE_CHARACTERS + 1];
+ int return_value;
+ unsigned const char *p;
+ int actual_payload_len;
+
+ s->s3->rrec.data = payload;
+ s->s3->rrec.length = strlen((const char*)payload);
+ *payload++ = TLS1_HB_REQUEST;
+ s2n(fixture.sent_payload_len, payload);
+
+ /* Make a local copy of the request, since it gets overwritten at some
+ * point */
+ memcpy((char *)sent_buf, (const char*)payload, sizeof(sent_buf));
+
+ return_value = fixture.process_heartbeat(s);
+
+ if (return_value != fixture.expected_return_value)
+ {
+ printf("%s failed: expected return value %d, received %d\n",
+ fixture.test_case_name, fixture.expected_return_value,
+ return_value);
+ result = 1;
+ }
+
+ /* If there is any byte alignment, it will be stored in wbuf.offset. */
+ p = &(s->s3->wbuf.buf[
+ fixture.return_payload_offset + s->s3->wbuf.offset]);
+ actual_payload_len = 0;
+ n2s(p, actual_payload_len);
+
+ if (actual_payload_len != fixture.expected_payload_len)
+ {
+ printf("%s failed:\n expected payload len: %d\n received: %d\n",
+ fixture.test_case_name, fixture.expected_payload_len,
+ actual_payload_len);
+ print_payload("sent", sent_buf, strlen((const char*)sent_buf));
+ print_payload("received", p, actual_payload_len);
+ result = 1;
+ }
+ else
+ {
+ char* actual_payload = BUF_strndup((const char*)p, actual_payload_len);
+ if (strcmp(actual_payload, fixture.expected_return_payload) != 0)
+ {
+ printf("%s failed:\n expected payload: \"%s\"\n received: \"%s\"\n",
+ fixture.test_case_name, fixture.expected_return_payload,
+ actual_payload);
+ result = 1;
+ }
+ OPENSSL_free(actual_payload);
+ }
+
+ if (result != 0)
+ {
+ printf("** %s failed **\n--------\n", fixture.test_case_name);
+ }
+ return result;
+ }
+
+static int honest_payload_size(unsigned char payload_buf[])
+ {
+ /* Omit three-byte pad at the beginning for type and payload length */
+ return strlen((const char*)&payload_buf[3]) - MIN_PADDING_SIZE;
+ }
+
+#define SETUP_HEARTBEAT_TEST_FIXTURE(type)\
+ HEARTBEAT_TEST_FIXTURE fixture = set_up_##type(__func__);\
+ int result = 0
+
+#define EXECUTE_HEARTBEAT_TEST()\
+ if (execute_heartbeat(fixture) != 0) result = 1;\
+ tear_down(fixture);\
+ return result
+
+static int test_dtls1_not_bleeding()
+ {
+ SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
+ /* Three-byte pad at the beginning for type and payload length */
+ unsigned char payload_buf[] = " Not bleeding, sixteen spaces of padding"
+ " ";
+ const int payload_buf_len = honest_payload_size(payload_buf);
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = payload_buf_len;
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = payload_buf_len;
+ fixture.expected_return_payload = "Not bleeding, sixteen spaces of padding";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+static int test_dtls1_not_bleeding_empty_payload()
+ {
+ int payload_buf_len;
+
+ SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
+ /* Three-byte pad at the beginning for type and payload length, plus a NUL
+ * at the end */
+ unsigned char payload_buf[4 + MIN_PADDING_SIZE];
+ memset(payload_buf, ' ', sizeof(payload_buf));
+ payload_buf[sizeof(payload_buf) - 1] = '\0';
+ payload_buf_len = honest_payload_size(payload_buf);
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = payload_buf_len;
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = payload_buf_len;
+ fixture.expected_return_payload = "";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+static int test_dtls1_heartbleed()
+ {
+ SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
+ /* Three-byte pad at the beginning for type and payload length */
+ unsigned char payload_buf[] = " HEARTBLEED ";
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS;
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = 0;
+ fixture.expected_return_payload = "";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+static int test_dtls1_heartbleed_empty_payload()
+ {
+ SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
+ /* Excluding the NUL at the end, one byte short of type + payload length +
+ * minimum padding */
+ unsigned char payload_buf[MIN_PADDING_SIZE + 3];
+ memset(payload_buf, ' ', sizeof(payload_buf));
+ payload_buf[sizeof(payload_buf) - 1] = '\0';
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS;
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = 0;
+ fixture.expected_return_payload = "";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+static int test_dtls1_heartbleed_excessive_plaintext_length()
+ {
+ SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
+ /* Excluding the NUL at the end, one byte in excess of maximum allowed
+ * heartbeat message length */
+ unsigned char payload_buf[SSL3_RT_MAX_PLAIN_LENGTH + 2];
+ memset(payload_buf, ' ', sizeof(payload_buf));
+ payload_buf[sizeof(payload_buf) - 1] = '\0';
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = honest_payload_size(payload_buf);
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = 0;
+ fixture.expected_return_payload = "";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+static int test_tls1_not_bleeding()
+ {
+ SETUP_HEARTBEAT_TEST_FIXTURE(tls);
+ /* Three-byte pad at the beginning for type and payload length */
+ unsigned char payload_buf[] = " Not bleeding, sixteen spaces of padding"
+ " ";
+ const int payload_buf_len = honest_payload_size(payload_buf);
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = payload_buf_len;
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = payload_buf_len;
+ fixture.expected_return_payload = "Not bleeding, sixteen spaces of padding";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+static int test_tls1_not_bleeding_empty_payload()
+ {
+ int payload_buf_len;
+
+ SETUP_HEARTBEAT_TEST_FIXTURE(tls);
+ /* Three-byte pad at the beginning for type and payload length, plus a NUL
+ * at the end */
+ unsigned char payload_buf[4 + MIN_PADDING_SIZE];
+ memset(payload_buf, ' ', sizeof(payload_buf));
+ payload_buf[sizeof(payload_buf) - 1] = '\0';
+ payload_buf_len = honest_payload_size(payload_buf);
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = payload_buf_len;
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = payload_buf_len;
+ fixture.expected_return_payload = "";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+static int test_tls1_heartbleed()
+ {
+ SETUP_HEARTBEAT_TEST_FIXTURE(tls);
+ /* Three-byte pad at the beginning for type and payload length */
+ unsigned char payload_buf[] = " HEARTBLEED ";
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS;
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = 0;
+ fixture.expected_return_payload = "";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+static int test_tls1_heartbleed_empty_payload()
+ {
+ SETUP_HEARTBEAT_TEST_FIXTURE(tls);
+ /* Excluding the NUL at the end, one byte short of type + payload length +
+ * minimum padding */
+ unsigned char payload_buf[MIN_PADDING_SIZE + 3];
+ memset(payload_buf, ' ', sizeof(payload_buf));
+ payload_buf[sizeof(payload_buf) - 1] = '\0';
+
+ fixture.payload = &payload_buf[0];
+ fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS;
+ fixture.expected_return_value = 0;
+ fixture.expected_payload_len = 0;
+ fixture.expected_return_payload = "";
+ EXECUTE_HEARTBEAT_TEST();
+ }
+
+#undef EXECUTE_HEARTBEAT_TEST
+#undef SETUP_HEARTBEAT_TEST_FIXTURE
+
+int main(int argc, char *argv[])
+ {
+ int num_failed;
+
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ num_failed = test_dtls1_not_bleeding() +
+ test_dtls1_not_bleeding_empty_payload() +
+ test_dtls1_heartbleed() +
+ test_dtls1_heartbleed_empty_payload() +
+ /* The following test causes an assertion failure at
+ * ssl/d1_pkt.c:dtls1_write_bytes() in versions prior to 1.0.1g: */
+ (OPENSSL_VERSION_NUMBER >= 0x1000107fL ?
+ test_dtls1_heartbleed_excessive_plaintext_length() : 0) +
+ test_tls1_not_bleeding() +
+ test_tls1_not_bleeding_empty_payload() +
+ test_tls1_heartbleed() +
+ test_tls1_heartbleed_empty_payload() +
+ 0;
+
+ ERR_print_errors_fp(stderr);
+
+ if (num_failed != 0)
+ {
+ printf("%d test%s failed\n", num_failed, num_failed != 1 ? "s" : "");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ }
+
+#else /* OPENSSL_NO_HEARTBEATS*/
+
+int main(int argc, char *argv[])
+ {
+ return EXIT_SUCCESS;
+ }
+#endif /* OPENSSL_NO_HEARTBEATS */
diff --git a/drivers/builtin_openssl/ssl/install-ssl.com b/drivers/builtin_openssl2/ssl/install-ssl.com
index afe6967f85..afe6967f85 100755
--- a/drivers/builtin_openssl/ssl/install-ssl.com
+++ b/drivers/builtin_openssl2/ssl/install-ssl.com
diff --git a/drivers/builtin_openssl/ssl/kssl.c b/drivers/builtin_openssl2/ssl/kssl.c
index fd7c67bb1f..fd7c67bb1f 100644
--- a/drivers/builtin_openssl/ssl/kssl.c
+++ b/drivers/builtin_openssl2/ssl/kssl.c
diff --git a/drivers/builtin_openssl/ssl/kssl_lcl.h b/drivers/builtin_openssl2/ssl/kssl_lcl.h
index c039c91b4e..c039c91b4e 100644
--- a/drivers/builtin_openssl/ssl/kssl_lcl.h
+++ b/drivers/builtin_openssl2/ssl/kssl_lcl.h
diff --git a/drivers/builtin_openssl/ssl/s23_clnt.c b/drivers/builtin_openssl2/ssl/s23_clnt.c
index 2b93c639dd..2b93c639dd 100644
--- a/drivers/builtin_openssl/ssl/s23_clnt.c
+++ b/drivers/builtin_openssl2/ssl/s23_clnt.c
diff --git a/drivers/builtin_openssl/ssl/s23_lib.c b/drivers/builtin_openssl2/ssl/s23_lib.c
index 3bf728318a..3bf728318a 100644
--- a/drivers/builtin_openssl/ssl/s23_lib.c
+++ b/drivers/builtin_openssl2/ssl/s23_lib.c
diff --git a/drivers/builtin_openssl/ssl/s23_meth.c b/drivers/builtin_openssl2/ssl/s23_meth.c
index 40eae0f0be..40eae0f0be 100644
--- a/drivers/builtin_openssl/ssl/s23_meth.c
+++ b/drivers/builtin_openssl2/ssl/s23_meth.c
diff --git a/drivers/builtin_openssl/ssl/s23_pkt.c b/drivers/builtin_openssl2/ssl/s23_pkt.c
index 4ca6a1b258..4ca6a1b258 100644
--- a/drivers/builtin_openssl/ssl/s23_pkt.c
+++ b/drivers/builtin_openssl2/ssl/s23_pkt.c
diff --git a/drivers/builtin_openssl/ssl/s23_srvr.c b/drivers/builtin_openssl2/ssl/s23_srvr.c
index 4877849013..4877849013 100644
--- a/drivers/builtin_openssl/ssl/s23_srvr.c
+++ b/drivers/builtin_openssl2/ssl/s23_srvr.c
diff --git a/drivers/builtin_openssl/ssl/s2_clnt.c b/drivers/builtin_openssl2/ssl/s2_clnt.c
index 03b6cf9673..03b6cf9673 100644
--- a/drivers/builtin_openssl/ssl/s2_clnt.c
+++ b/drivers/builtin_openssl2/ssl/s2_clnt.c
diff --git a/drivers/builtin_openssl/ssl/s2_enc.c b/drivers/builtin_openssl2/ssl/s2_enc.c
index ff3395f459..ff3395f459 100644
--- a/drivers/builtin_openssl/ssl/s2_enc.c
+++ b/drivers/builtin_openssl2/ssl/s2_enc.c
diff --git a/drivers/builtin_openssl/ssl/s2_lib.c b/drivers/builtin_openssl2/ssl/s2_lib.c
index 9914604109..9914604109 100644
--- a/drivers/builtin_openssl/ssl/s2_lib.c
+++ b/drivers/builtin_openssl2/ssl/s2_lib.c
diff --git a/drivers/builtin_openssl/ssl/s2_meth.c b/drivers/builtin_openssl2/ssl/s2_meth.c
index f0e8ca593d..f0e8ca593d 100644
--- a/drivers/builtin_openssl/ssl/s2_meth.c
+++ b/drivers/builtin_openssl2/ssl/s2_meth.c
diff --git a/drivers/builtin_openssl/ssl/s2_pkt.c b/drivers/builtin_openssl2/ssl/s2_pkt.c
index 8bb6ab8baa..8bb6ab8baa 100644
--- a/drivers/builtin_openssl/ssl/s2_pkt.c
+++ b/drivers/builtin_openssl2/ssl/s2_pkt.c
diff --git a/drivers/builtin_openssl/ssl/s2_srvr.c b/drivers/builtin_openssl2/ssl/s2_srvr.c
index 2cba426bb7..2cba426bb7 100644
--- a/drivers/builtin_openssl/ssl/s2_srvr.c
+++ b/drivers/builtin_openssl2/ssl/s2_srvr.c
diff --git a/drivers/builtin_openssl/ssl/s3_both.c b/drivers/builtin_openssl2/ssl/s3_both.c
index 53b9390fdd..53b9390fdd 100644
--- a/drivers/builtin_openssl/ssl/s3_both.c
+++ b/drivers/builtin_openssl2/ssl/s3_both.c
diff --git a/drivers/builtin_openssl/ssl/s3_cbc.c b/drivers/builtin_openssl2/ssl/s3_cbc.c
index 443a31e746..443a31e746 100644
--- a/drivers/builtin_openssl/ssl/s3_cbc.c
+++ b/drivers/builtin_openssl2/ssl/s3_cbc.c
diff --git a/drivers/builtin_openssl2/ssl/s3_clnt.c b/drivers/builtin_openssl2/ssl/s3_clnt.c
new file mode 100644
index 0000000000..0457af8789
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/s3_clnt.c
@@ -0,0 +1,3381 @@
+/* ssl/s3_clnt.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#include "kssl_lcl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
+
+static const SSL_METHOD *ssl3_get_client_method(int ver);
+static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
+
+static const SSL_METHOD *ssl3_get_client_method(int ver)
+ {
+ if (ver == SSL3_VERSION)
+ return(SSLv3_client_method());
+ else
+ return(NULL);
+ }
+
+IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
+ ssl_undefined_function,
+ ssl3_connect,
+ ssl3_get_client_method)
+
+int ssl3_connect(SSL *s)
+ {
+ BUF_MEM *buf=NULL;
+ unsigned long Time=(unsigned long)time(NULL);
+ void (*cb)(const SSL *ssl,int type,int val)=NULL;
+ int ret= -1;
+ int new_state,state,skip=0;
+
+ RAND_add(&Time,sizeof(Time),0);
+ ERR_clear_error();
+ clear_sys_error();
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ s->in_handshake++;
+ if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
+ for (;;)
+ {
+ state=s->state;
+
+ switch(s->state)
+ {
+ case SSL_ST_RENEGOTIATE:
+ s->renegotiate=1;
+ s->state=SSL_ST_CONNECT;
+ s->ctx->stats.sess_connect_renegotiate++;
+ /* break */
+ case SSL_ST_BEFORE:
+ case SSL_ST_CONNECT:
+ case SSL_ST_BEFORE|SSL_ST_CONNECT:
+ case SSL_ST_OK|SSL_ST_CONNECT:
+
+ s->server=0;
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+ if ((s->version & 0xff00 ) != 0x0300)
+ {
+ SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR);
+ ret = -1;
+ goto end;
+ }
+
+ /* s->version=SSL3_VERSION; */
+ s->type=SSL_ST_CONNECT;
+
+ if (s->init_buf == NULL)
+ {
+ if ((buf=BUF_MEM_new()) == NULL)
+ {
+ ret= -1;
+ goto end;
+ }
+ if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+ {
+ ret= -1;
+ goto end;
+ }
+ s->init_buf=buf;
+ buf=NULL;
+ }
+
+ if (!ssl3_setup_buffers(s)) { ret= -1; goto end; }
+
+ /* setup buffing BIO */
+ if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; }
+
+ /* don't push the buffering BIO quite yet */
+
+ ssl3_init_finished_mac(s);
+
+ s->state=SSL3_ST_CW_CLNT_HELLO_A;
+ s->ctx->stats.sess_connect++;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CW_CLNT_HELLO_A:
+ case SSL3_ST_CW_CLNT_HELLO_B:
+
+ s->shutdown=0;
+ ret=ssl3_client_hello(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_SRVR_HELLO_A;
+ s->init_num=0;
+
+ /* turn on buffering for the next lot of output */
+ if (s->bbio != s->wbio)
+ s->wbio=BIO_push(s->bbio,s->wbio);
+
+ break;
+
+ case SSL3_ST_CR_SRVR_HELLO_A:
+ case SSL3_ST_CR_SRVR_HELLO_B:
+ ret=ssl3_get_server_hello(s);
+ if (ret <= 0) goto end;
+
+ if (s->hit)
+ {
+ s->state=SSL3_ST_CR_FINISHED_A;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_ticket_expected)
+ {
+ /* receive renewed session ticket */
+ s->state=SSL3_ST_CR_SESSION_TICKET_A;
+ }
+#endif
+ }
+ else
+ s->state=SSL3_ST_CR_CERT_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CR_CERT_A:
+ case SSL3_ST_CR_CERT_B:
+#ifndef OPENSSL_NO_TLSEXT
+ ret=ssl3_check_finished(s);
+ if (ret <= 0) goto end;
+ if (ret == 2)
+ {
+ s->hit = 1;
+ if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_CR_SESSION_TICKET_A;
+ else
+ s->state=SSL3_ST_CR_FINISHED_A;
+ s->init_num=0;
+ break;
+ }
+#endif
+ /* Check if it is anon DH/ECDH */
+ /* or PSK */
+ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
+ !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+ {
+ ret=ssl3_get_server_certificate(s);
+ if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_CR_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ }
+ else
+ {
+ skip = 1;
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ }
+#else
+ }
+ else
+ skip=1;
+
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+#endif
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CR_KEY_EXCH_A:
+ case SSL3_ST_CR_KEY_EXCH_B:
+ ret=ssl3_get_key_exchange(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_CERT_REQ_A;
+ s->init_num=0;
+
+ /* at this point we check that we have the
+ * required stuff from the server */
+ if (!ssl3_check_cert_and_algorithm(s))
+ {
+ ret= -1;
+ goto end;
+ }
+ break;
+
+ case SSL3_ST_CR_CERT_REQ_A:
+ case SSL3_ST_CR_CERT_REQ_B:
+ ret=ssl3_get_certificate_request(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_SRVR_DONE_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CR_SRVR_DONE_A:
+ case SSL3_ST_CR_SRVR_DONE_B:
+ ret=ssl3_get_server_done(s);
+ if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_SRP
+ if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP)
+ {
+ if ((ret = SRP_Calc_A_param(s))<=0)
+ {
+ SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SRP_A_CALC);
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
+ goto end;
+ }
+ }
+#endif
+ if (s->s3->tmp.cert_req)
+ s->state=SSL3_ST_CW_CERT_A;
+ else
+ s->state=SSL3_ST_CW_KEY_EXCH_A;
+ s->init_num=0;
+
+ break;
+
+ case SSL3_ST_CW_CERT_A:
+ case SSL3_ST_CW_CERT_B:
+ case SSL3_ST_CW_CERT_C:
+ case SSL3_ST_CW_CERT_D:
+ ret=ssl3_send_client_certificate(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CW_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CW_KEY_EXCH_A:
+ case SSL3_ST_CW_KEY_EXCH_B:
+ ret=ssl3_send_client_key_exchange(s);
+ if (ret <= 0) goto end;
+ /* EAY EAY EAY need to check for DH fix cert
+ * sent back */
+ /* For TLS, cert_req is set to 2, so a cert chain
+ * of nothing is sent, but no verify packet is sent */
+ /* XXX: For now, we do not support client
+ * authentication in ECDH cipher suites with
+ * ECDH (rather than ECDSA) certificates.
+ * We need to skip the certificate verify
+ * message when client's ECDH public key is sent
+ * inside the client certificate.
+ */
+ if (s->s3->tmp.cert_req == 1)
+ {
+ s->state=SSL3_ST_CW_CERT_VRFY_A;
+ }
+ else
+ {
+ s->state=SSL3_ST_CW_CHANGE_A;
+ s->s3->change_cipher_spec=0;
+ }
+ if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
+ {
+ s->state=SSL3_ST_CW_CHANGE_A;
+ s->s3->change_cipher_spec=0;
+ }
+
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CW_CERT_VRFY_A:
+ case SSL3_ST_CW_CERT_VRFY_B:
+ ret=ssl3_send_client_verify(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CW_CHANGE_A;
+ s->init_num=0;
+ s->s3->change_cipher_spec=0;
+ break;
+
+ case SSL3_ST_CW_CHANGE_A:
+ case SSL3_ST_CW_CHANGE_B:
+ ret=ssl3_send_change_cipher_spec(s,
+ SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
+ if (ret <= 0) goto end;
+
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
+ s->state=SSL3_ST_CW_FINISHED_A;
+#else
+ if (s->s3->next_proto_neg_seen)
+ s->state=SSL3_ST_CW_NEXT_PROTO_A;
+ else
+ s->state=SSL3_ST_CW_FINISHED_A;
+#endif
+ s->init_num=0;
+
+ s->session->cipher=s->s3->tmp.new_cipher;
+#ifdef OPENSSL_NO_COMP
+ s->session->compress_meth=0;
+#else
+ if (s->s3->tmp.new_compression == NULL)
+ s->session->compress_meth=0;
+ else
+ s->session->compress_meth=
+ s->s3->tmp.new_compression->id;
+#endif
+ if (!s->method->ssl3_enc->setup_key_block(s))
+ {
+ ret= -1;
+ goto end;
+ }
+
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+ {
+ ret= -1;
+ goto end;
+ }
+
+ break;
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ case SSL3_ST_CW_NEXT_PROTO_A:
+ case SSL3_ST_CW_NEXT_PROTO_B:
+ ret=ssl3_send_next_proto(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CW_FINISHED_A;
+ break;
+#endif
+
+ case SSL3_ST_CW_FINISHED_A:
+ case SSL3_ST_CW_FINISHED_B:
+ ret=ssl3_send_finished(s,
+ SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B,
+ s->method->ssl3_enc->client_finished_label,
+ s->method->ssl3_enc->client_finished_label_len);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CW_FLUSH;
+
+ /* clear flags */
+ s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER;
+ if (s->hit)
+ {
+ s->s3->tmp.next_state=SSL_ST_OK;
+ if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)
+ {
+ s->state=SSL_ST_OK;
+ s->s3->flags|=SSL3_FLAGS_POP_BUFFER;
+ s->s3->delay_buf_pop_ret=0;
+ }
+ }
+ else
+ {
+#ifndef OPENSSL_NO_TLSEXT
+ /* Allow NewSessionTicket if ticket expected */
+ if (s->tlsext_ticket_expected)
+ s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+ else
+#endif
+
+ s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
+ }
+ s->init_num=0;
+ break;
+
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_CR_SESSION_TICKET_A:
+ case SSL3_ST_CR_SESSION_TICKET_B:
+ ret=ssl3_get_new_session_ticket(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_FINISHED_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CR_CERT_STATUS_A:
+ case SSL3_ST_CR_CERT_STATUS_B:
+ ret=ssl3_get_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+#endif
+
+ case SSL3_ST_CR_FINISHED_A:
+ case SSL3_ST_CR_FINISHED_B:
+
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
+ SSL3_ST_CR_FINISHED_B);
+ if (ret <= 0) goto end;
+
+ if (s->hit)
+ s->state=SSL3_ST_CW_CHANGE_A;
+ else
+ s->state=SSL_ST_OK;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CW_FLUSH:
+ s->rwstate=SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0)
+ {
+ ret= -1;
+ goto end;
+ }
+ s->rwstate=SSL_NOTHING;
+ s->state=s->s3->tmp.next_state;
+ break;
+
+ case SSL_ST_OK:
+ /* clean a few things up */
+ ssl3_cleanup_key_block(s);
+
+ if (s->init_buf != NULL)
+ {
+ BUF_MEM_free(s->init_buf);
+ s->init_buf=NULL;
+ }
+
+ /* If we are not 'joining' the last two packets,
+ * remove the buffering now */
+ if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER))
+ ssl_free_wbio_buffer(s);
+ /* else do it later in ssl3_write */
+
+ s->init_num=0;
+ s->renegotiate=0;
+ s->new_session=0;
+
+ ssl_update_cache(s,SSL_SESS_CACHE_CLIENT);
+ if (s->hit) s->ctx->stats.sess_hit++;
+
+ ret=1;
+ /* s->server=0; */
+ s->handshake_func=ssl3_connect;
+ s->ctx->stats.sess_connect_good++;
+
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+
+ goto end;
+ /* break; */
+
+ default:
+ SSLerr(SSL_F_SSL3_CONNECT,SSL_R_UNKNOWN_STATE);
+ ret= -1;
+ goto end;
+ /* break; */
+ }
+
+ /* did we do anything */
+ if (!s->s3->tmp.reuse_message && !skip)
+ {
+ if (s->debug)
+ {
+ if ((ret=BIO_flush(s->wbio)) <= 0)
+ goto end;
+ }
+
+ if ((cb != NULL) && (s->state != state))
+ {
+ new_state=s->state;
+ s->state=state;
+ cb(s,SSL_CB_CONNECT_LOOP,1);
+ s->state=new_state;
+ }
+ }
+ skip=0;
+ }
+end:
+ s->in_handshake--;
+ if (buf != NULL)
+ BUF_MEM_free(buf);
+ if (cb != NULL)
+ cb(s,SSL_CB_CONNECT_EXIT,ret);
+ return(ret);
+ }
+
+
+int ssl3_client_hello(SSL *s)
+ {
+ unsigned char *buf;
+ unsigned char *p,*d;
+ int i;
+ unsigned long l;
+#ifndef OPENSSL_NO_COMP
+ int j;
+ SSL_COMP *comp;
+#endif
+
+ buf=(unsigned char *)s->init_buf->data;
+ if (s->state == SSL3_ST_CW_CLNT_HELLO_A)
+ {
+ SSL_SESSION *sess = s->session;
+ if ((sess == NULL) ||
+ (sess->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+ !sess->session_id_length ||
+#else
+ (!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
+ (sess->not_resumable))
+ {
+ if (!ssl_get_new_session(s,0))
+ goto err;
+ }
+ /* else use the pre-loaded session */
+
+ p=s->s3->client_random;
+
+ if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0)
+ goto err;
+
+ /* Do the message type and length last */
+ d=p= &(buf[4]);
+
+ /* version indicates the negotiated version: for example from
+ * an SSLv2/v3 compatible client hello). The client_version
+ * field is the maximum version we permit and it is also
+ * used in RSA encrypted premaster secrets. Some servers can
+ * choke if we initially report a higher version then
+ * renegotiate to a lower one in the premaster secret. This
+ * didn't happen with TLS 1.0 as most servers supported it
+ * but it can with TLS 1.1 or later if the server only supports
+ * 1.0.
+ *
+ * Possible scenario with previous logic:
+ * 1. Client hello indicates TLS 1.2
+ * 2. Server hello says TLS 1.0
+ * 3. RSA encrypted premaster secret uses 1.2.
+ * 4. Handhaked proceeds using TLS 1.0.
+ * 5. Server sends hello request to renegotiate.
+ * 6. Client hello indicates TLS v1.0 as we now
+ * know that is maximum server supports.
+ * 7. Server chokes on RSA encrypted premaster secret
+ * containing version 1.0.
+ *
+ * For interoperability it should be OK to always use the
+ * maximum version we support in client hello and then rely
+ * on the checking of version to ensure the servers isn't
+ * being inconsistent: for example initially negotiating with
+ * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
+ * client_version in client hello and not resetting it to
+ * the negotiated version.
+ */
+#if 0
+ *(p++)=s->version>>8;
+ *(p++)=s->version&0xff;
+ s->client_version=s->version;
+#else
+ *(p++)=s->client_version>>8;
+ *(p++)=s->client_version&0xff;
+#endif
+
+ /* Random stuff */
+ memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
+ p+=SSL3_RANDOM_SIZE;
+
+ /* Session ID */
+ if (s->new_session)
+ i=0;
+ else
+ i=s->session->session_id_length;
+ *(p++)=i;
+ if (i != 0)
+ {
+ if (i > (int)sizeof(s->session->session_id))
+ {
+ SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ memcpy(p,s->session->session_id,i);
+ p+=i;
+ }
+
+ /* Ciphers supported */
+ i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),0);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
+ goto err;
+ }
+#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
+ /* Some servers hang if client hello > 256 bytes
+ * as hack workaround chop number of supported ciphers
+ * to keep it well below this if we use TLS v1.2
+ */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION
+ && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
+ i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+#endif
+ s2n(i,p);
+ p+=i;
+
+ /* COMPRESSION */
+#ifdef OPENSSL_NO_COMP
+ *(p++)=1;
+#else
+
+ if ((s->options & SSL_OP_NO_COMPRESSION)
+ || !s->ctx->comp_methods)
+ j=0;
+ else
+ j=sk_SSL_COMP_num(s->ctx->comp_methods);
+ *(p++)=1+j;
+ for (i=0; i<j; i++)
+ {
+ comp=sk_SSL_COMP_value(s->ctx->comp_methods,i);
+ *(p++)=comp->id;
+ }
+#endif
+ *(p++)=0; /* Add the NULL method */
+
+#ifndef OPENSSL_NO_TLSEXT
+ /* TLS extensions*/
+ if (ssl_prepare_clienthello_tlsext(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
+ if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+#endif
+
+ l=(p-d);
+ d=buf;
+ *(d++)=SSL3_MT_CLIENT_HELLO;
+ l2n3(l,d);
+
+ s->state=SSL3_ST_CW_CLNT_HELLO_B;
+ /* number of bytes to write */
+ s->init_num=p-buf;
+ s->init_off=0;
+ }
+
+ /* SSL3_ST_CW_CLNT_HELLO_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+ return(-1);
+ }
+
+int ssl3_get_server_hello(SSL *s)
+ {
+ STACK_OF(SSL_CIPHER) *sk;
+ const SSL_CIPHER *c;
+ unsigned char *p,*d;
+ int i,al,ok;
+ unsigned int j;
+ long n;
+#ifndef OPENSSL_NO_COMP
+ SSL_COMP *comp;
+#endif
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_SRVR_HELLO_A,
+ SSL3_ST_CR_SRVR_HELLO_B,
+ -1,
+ 20000, /* ?? */
+ &ok);
+
+ if (!ok) return((int)n);
+
+ if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+ {
+ if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
+ {
+ if ( s->d1->send_cookie == 0)
+ {
+ s->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+ else /* already sent a cookie */
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_MESSAGE_TYPE);
+ goto f_err;
+ }
+ }
+ }
+
+ if ( s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_MESSAGE_TYPE);
+ goto f_err;
+ }
+
+ d=p=(unsigned char *)s->init_msg;
+
+ if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff)))
+ {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_SSL_VERSION);
+ s->version=(s->version&0xff00)|p[1];
+ al=SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+ p+=2;
+
+ /* load the server hello data */
+ /* load the server random */
+ memcpy(s->s3->server_random,p,SSL3_RANDOM_SIZE);
+ p+=SSL3_RANDOM_SIZE;
+
+ /* get the session-id */
+ j= *(p++);
+
+ if ((j > sizeof s->session->session_id) || (j > SSL3_SESSION_ID_SIZE))
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SSL3_SESSION_ID_TOO_LONG);
+ goto f_err;
+ }
+
+#ifndef OPENSSL_NO_TLSEXT
+ /* check if we want to resume the session based on external pre-shared secret */
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key,
+ &s->session->master_key_length,
+ NULL, &pref_cipher,
+ s->tls_session_secret_cb_arg))
+ {
+ s->session->cipher = pref_cipher ?
+ pref_cipher : ssl_get_cipher_by_char(s, p+j);
+ }
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
+ if (j != 0 && j == s->session->session_id_length
+ && memcmp(p,s->session->session_id,j) == 0)
+ {
+ if(s->sid_ctx_length != s->session->sid_ctx_length
+ || memcmp(s->session->sid_ctx,s->sid_ctx,s->sid_ctx_length))
+ {
+ /* actually a client application bug */
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
+ goto f_err;
+ }
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ s->hit=1;
+ }
+ else /* a miss or crap from the other end */
+ {
+ /* If we were trying for session-id reuse, make a new
+ * SSL_SESSION so we don't stuff up other people */
+ s->hit=0;
+ if (s->session->session_id_length > 0)
+ {
+ if (!ssl_get_new_session(s,0))
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+ s->session->session_id_length=j;
+ memcpy(s->session->session_id,p,j); /* j could be 0 */
+ }
+ p+=j;
+ c=ssl_get_cipher_by_char(s,p);
+ if (c == NULL)
+ {
+ /* unknown cipher */
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
+ goto f_err;
+ }
+ /* TLS v1.2 only ciphersuites require v1.2 or later */
+ if ((c->algorithm_ssl & SSL_TLSV1_2) &&
+ (TLS1_get_version(s) < TLS1_2_VERSION))
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
+ goto f_err;
+ }
+ p+=ssl_put_cipher_by_char(s,NULL,NULL);
+
+ sk=ssl_get_ciphers_by_id(s);
+ i=sk_SSL_CIPHER_find(sk,c);
+ if (i < 0)
+ {
+ /* we did not say we would use this cipher */
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
+ goto f_err;
+ }
+
+ /* Depending on the session caching (internal/external), the cipher
+ and/or cipher_id values may not be set. Make sure that
+ cipher_id is set and use it for comparison. */
+ if (s->session->cipher)
+ s->session->cipher_id = s->session->cipher->id;
+ if (s->hit && (s->session->cipher_id != c->id))
+ {
+/* Workaround is now obsolete */
+#if 0
+ if (!(s->options &
+ SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG))
+#endif
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+ goto f_err;
+ }
+ }
+ s->s3->tmp.new_cipher=c;
+ /* Don't digest cached records if TLS v1.2: we may need them for
+ * client authentication.
+ */
+ if (TLS1_get_version(s) < TLS1_2_VERSION && !ssl3_digest_cached_records(s))
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ /* lets get the compression algorithm */
+ /* COMPRESSION */
+#ifdef OPENSSL_NO_COMP
+ if (*(p++) != 0)
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+ goto f_err;
+ }
+ /* If compression is disabled we'd better not try to resume a session
+ * using compression.
+ */
+ if (s->session->compress_meth != 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
+ goto f_err;
+ }
+#else
+ j= *(p++);
+ if (s->hit && j != s->session->compress_meth)
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
+ goto f_err;
+ }
+ if (j == 0)
+ comp=NULL;
+ else if (s->options & SSL_OP_NO_COMPRESSION)
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_COMPRESSION_DISABLED);
+ goto f_err;
+ }
+ else
+ comp=ssl3_comp_find(s->ctx->comp_methods,j);
+
+ if ((j != 0) && (comp == NULL))
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+ goto f_err;
+ }
+ else
+ {
+ s->s3->tmp.new_compression=comp;
+ }
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+ /* TLS extensions*/
+ if (s->version >= SSL3_VERSION)
+ {
+ if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
+ {
+ /* 'al' set by ssl_parse_serverhello_tlsext */
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
+ goto f_err;
+ }
+ if (ssl_check_serverhello_tlsext(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
+ goto err;
+ }
+ }
+#endif
+
+ if (p != (d+n))
+ {
+ /* wrong packet length */
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_PACKET_LENGTH);
+ goto f_err;
+ }
+
+ return(1);
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(-1);
+ }
+
+int ssl3_get_server_certificate(SSL *s)
+ {
+ int al,i,ok,ret= -1;
+ unsigned long n,nc,llen,l;
+ X509 *x=NULL;
+ const unsigned char *q,*p;
+ unsigned char *d;
+ STACK_OF(X509) *sk=NULL;
+ SESS_CERT *sc;
+ EVP_PKEY *pkey=NULL;
+ int need_cert = 1; /* VRS: 0=> will allow null cert if auth == KRB5 */
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_CERT_A,
+ SSL3_ST_CR_CERT_B,
+ -1,
+ s->max_cert_list,
+ &ok);
+
+ if (!ok) return((int)n);
+
+ if ((s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) ||
+ ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) &&
+ (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)))
+ {
+ s->s3->tmp.reuse_message=1;
+ return(1);
+ }
+
+ if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_BAD_MESSAGE_TYPE);
+ goto f_err;
+ }
+ p=d=(unsigned char *)s->init_msg;
+
+ if ((sk=sk_X509_new_null()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ n2l3(p,llen);
+ if (llen+3 != n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ for (nc=0; nc<llen; )
+ {
+ n2l3(p,l);
+ if ((l+nc+3) > llen)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
+ goto f_err;
+ }
+
+ q=p;
+ x=d2i_X509(NULL,&q,l);
+ if (x == NULL)
+ {
+ al=SSL_AD_BAD_CERTIFICATE;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,ERR_R_ASN1_LIB);
+ goto f_err;
+ }
+ if (q != (p+l))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if (!sk_X509_push(sk,x))
+ {
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ x=NULL;
+ nc+=l+3;
+ p=q;
+ }
+
+ i=ssl_verify_cert_chain(s,sk);
+ if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0)
+#ifndef OPENSSL_NO_KRB5
+ && !((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
+ (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
+#endif /* OPENSSL_NO_KRB5 */
+ )
+ {
+ al=ssl_verify_alarm_type(s->verify_result);
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_CERTIFICATE_VERIFY_FAILED);
+ goto f_err;
+ }
+ ERR_clear_error(); /* but we keep s->verify_result */
+
+ sc=ssl_sess_cert_new();
+ if (sc == NULL) goto err;
+
+ if (s->session->sess_cert) ssl_sess_cert_free(s->session->sess_cert);
+ s->session->sess_cert=sc;
+
+ sc->cert_chain=sk;
+ /* Inconsistency alert: cert_chain does include the peer's
+ * certificate, which we don't include in s3_srvr.c */
+ x=sk_X509_value(sk,0);
+ sk=NULL;
+ /* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end*/
+
+ pkey=X509_get_pubkey(x);
+
+ /* VRS: allow null cert if auth == KRB5 */
+ need_cert = ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
+ (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
+ ? 0 : 1;
+
+#ifdef KSSL_DEBUG
+ printf("pkey,x = %p, %p\n", pkey,x);
+ printf("ssl_cert_type(x,pkey) = %d\n", ssl_cert_type(x,pkey));
+ printf("cipher, alg, nc = %s, %lx, %lx, %d\n", s->s3->tmp.new_cipher->name,
+ s->s3->tmp.new_cipher->algorithm_mkey, s->s3->tmp.new_cipher->algorithm_auth, need_cert);
+#endif /* KSSL_DEBUG */
+
+ if (need_cert && ((pkey == NULL) || EVP_PKEY_missing_parameters(pkey)))
+ {
+ x=NULL;
+ al=SSL3_AL_FATAL;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+ SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
+ goto f_err;
+ }
+
+ i=ssl_cert_type(x,pkey);
+ if (need_cert && i < 0)
+ {
+ x=NULL;
+ al=SSL3_AL_FATAL;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+ SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+ goto f_err;
+ }
+
+ if (need_cert)
+ {
+ sc->peer_cert_type=i;
+ CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
+ /* Why would the following ever happen?
+ * We just created sc a couple of lines ago. */
+ if (sc->peer_pkeys[i].x509 != NULL)
+ X509_free(sc->peer_pkeys[i].x509);
+ sc->peer_pkeys[i].x509=x;
+ sc->peer_key= &(sc->peer_pkeys[i]);
+
+ if (s->session->peer != NULL)
+ X509_free(s->session->peer);
+ CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
+ s->session->peer=x;
+ }
+ else
+ {
+ sc->peer_cert_type=i;
+ sc->peer_key= NULL;
+
+ if (s->session->peer != NULL)
+ X509_free(s->session->peer);
+ s->session->peer=NULL;
+ }
+ s->session->verify_result = s->verify_result;
+
+ x=NULL;
+ ret=1;
+
+ if (0)
+ {
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ }
+err:
+ EVP_PKEY_free(pkey);
+ X509_free(x);
+ sk_X509_pop_free(sk,X509_free);
+ return(ret);
+ }
+
+int ssl3_get_key_exchange(SSL *s)
+ {
+#ifndef OPENSSL_NO_RSA
+ unsigned char *q,md_buf[EVP_MAX_MD_SIZE*2];
+#endif
+ EVP_MD_CTX md_ctx;
+ unsigned char *param,*p;
+ int al,i,j,param_len,ok;
+ long n,alg_k,alg_a;
+ EVP_PKEY *pkey=NULL;
+ const EVP_MD *md = NULL;
+#ifndef OPENSSL_NO_RSA
+ RSA *rsa=NULL;
+#endif
+#ifndef OPENSSL_NO_DH
+ DH *dh=NULL;
+#endif
+#ifndef OPENSSL_NO_ECDH
+ EC_KEY *ecdh = NULL;
+ BN_CTX *bn_ctx = NULL;
+ EC_POINT *srvr_ecpoint = NULL;
+ int curve_nid = 0;
+ int encoded_pt_len = 0;
+#endif
+
+ /* use same message size as in ssl3_get_certificate_request()
+ * as ServerKeyExchange message may be skipped */
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_KEY_EXCH_A,
+ SSL3_ST_CR_KEY_EXCH_B,
+ -1,
+ s->max_cert_list,
+ &ok);
+ if (!ok) return((int)n);
+
+ if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE)
+ {
+#ifndef OPENSSL_NO_PSK
+ /* In plain PSK ciphersuite, ServerKeyExchange can be
+ omitted if no identity hint is sent. Set
+ session->sess_cert anyway to avoid problems
+ later.*/
+ if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
+ {
+ s->session->sess_cert=ssl_sess_cert_new();
+ if (s->ctx->psk_identity_hint)
+ OPENSSL_free(s->ctx->psk_identity_hint);
+ s->ctx->psk_identity_hint = NULL;
+ }
+#endif
+ s->s3->tmp.reuse_message=1;
+ return(1);
+ }
+
+ param=p=(unsigned char *)s->init_msg;
+ if (s->session->sess_cert != NULL)
+ {
+#ifndef OPENSSL_NO_RSA
+ if (s->session->sess_cert->peer_rsa_tmp != NULL)
+ {
+ RSA_free(s->session->sess_cert->peer_rsa_tmp);
+ s->session->sess_cert->peer_rsa_tmp=NULL;
+ }
+#endif
+#ifndef OPENSSL_NO_DH
+ if (s->session->sess_cert->peer_dh_tmp)
+ {
+ DH_free(s->session->sess_cert->peer_dh_tmp);
+ s->session->sess_cert->peer_dh_tmp=NULL;
+ }
+#endif
+#ifndef OPENSSL_NO_ECDH
+ if (s->session->sess_cert->peer_ecdh_tmp)
+ {
+ EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
+ s->session->sess_cert->peer_ecdh_tmp=NULL;
+ }
+#endif
+ }
+ else
+ {
+ s->session->sess_cert=ssl_sess_cert_new();
+ }
+
+ param_len=0;
+ alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+ alg_a=s->s3->tmp.new_cipher->algorithm_auth;
+ EVP_MD_CTX_init(&md_ctx);
+
+#ifndef OPENSSL_NO_PSK
+ if (alg_k & SSL_kPSK)
+ {
+ char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1];
+
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ n2s(p,i);
+ param_len=i+2;
+ /* Store PSK identity hint for later use, hint is used
+ * in ssl3_send_client_key_exchange. Assume that the
+ * maximum length of a PSK identity hint can be as
+ * long as the maximum length of a PSK identity. */
+ if (i > PSK_MAX_IDENTITY_LEN)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+ SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH);
+ goto f_err;
+ }
+ /* If received PSK identity hint contains NULL
+ * characters, the hint is truncated from the first
+ * NULL. p may not be ending with NULL, so create a
+ * NULL-terminated string. */
+ memcpy(tmp_id_hint, p, i);
+ memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+ if (s->ctx->psk_identity_hint != NULL)
+ OPENSSL_free(s->ctx->psk_identity_hint);
+ s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
+ if (s->ctx->psk_identity_hint == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+
+ p+=i;
+ n-=param_len;
+ }
+ else
+#endif /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+ if (alg_k & SSL_kSRP)
+ {
+ n2s(p,i);
+ param_len=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_N_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.N=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ n2s(p,i);
+ param_len+=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_G_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.g=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ i = (unsigned int)(p[0]);
+ p++;
+ param_len+=i+1;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_S_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.s=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ n2s(p,i);
+ param_len+=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_B_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.B=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+ n-=param_len;
+
+/* We must check if there is a certificate */
+#ifndef OPENSSL_NO_RSA
+ if (alg_a & SSL_aRSA)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+#else
+ if (0)
+ ;
+#endif
+#ifndef OPENSSL_NO_DSA
+ else if (alg_a & SSL_aDSS)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
+#endif
+ }
+ else
+#endif /* !OPENSSL_NO_SRP */
+#ifndef OPENSSL_NO_RSA
+ if (alg_k & SSL_kRSA)
+ {
+ if ((rsa=RSA_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ n2s(p,i);
+ param_len=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_MODULUS_LENGTH);
+ goto f_err;
+ }
+ if (!(rsa->n=BN_bin2bn(p,i,rsa->n)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ n2s(p,i);
+ param_len+=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_E_LENGTH);
+ goto f_err;
+ }
+ if (!(rsa->e=BN_bin2bn(p,i,rsa->e)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+ n-=param_len;
+
+ /* this should be because we are using an export cipher */
+ if (alg_a & SSL_aRSA)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+ else
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ s->session->sess_cert->peer_rsa_tmp=rsa;
+ rsa=NULL;
+ }
+#else /* OPENSSL_NO_RSA */
+ if (0)
+ ;
+#endif
+#ifndef OPENSSL_NO_DH
+ else if (alg_k & SSL_kEDH)
+ {
+ if ((dh=DH_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+ n2s(p,i);
+ param_len=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_P_LENGTH);
+ goto f_err;
+ }
+ if (!(dh->p=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ n2s(p,i);
+ param_len+=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_G_LENGTH);
+ goto f_err;
+ }
+ if (!(dh->g=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ n2s(p,i);
+ param_len+=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_PUB_KEY_LENGTH);
+ goto f_err;
+ }
+ if (!(dh->pub_key=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+ n-=param_len;
+
+#ifndef OPENSSL_NO_RSA
+ if (alg_a & SSL_aRSA)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+#else
+ if (0)
+ ;
+#endif
+#ifndef OPENSSL_NO_DSA
+ else if (alg_a & SSL_aDSS)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
+#endif
+ /* else anonymous DH, so no certificate or pkey. */
+
+ s->session->sess_cert->peer_dh_tmp=dh;
+ dh=NULL;
+ }
+ else if ((alg_k & SSL_kDHr) || (alg_k & SSL_kDHd))
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER);
+ goto f_err;
+ }
+#endif /* !OPENSSL_NO_DH */
+
+#ifndef OPENSSL_NO_ECDH
+ else if (alg_k & SSL_kEECDH)
+ {
+ EC_GROUP *ngroup;
+ const EC_GROUP *group;
+
+ if ((ecdh=EC_KEY_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Extract elliptic curve parameters and the
+ * server's ephemeral ECDH public key.
+ * Keep accumulating lengths of various components in
+ * param_len and make sure it never exceeds n.
+ */
+
+ /* XXX: For now we only support named (not generic) curves
+ * and the ECParameters in this case is just three bytes.
+ */
+ param_len=3;
+ if ((param_len > n) ||
+ (*p != NAMED_CURVE_TYPE) ||
+ ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0))
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+ goto f_err;
+ }
+
+ ngroup = EC_GROUP_new_by_curve_name(curve_nid);
+ if (ngroup == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_EC_LIB);
+ goto err;
+ }
+ if (EC_KEY_set_group(ecdh, ngroup) == 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_EC_LIB);
+ goto err;
+ }
+ EC_GROUP_free(ngroup);
+
+ group = EC_KEY_get0_group(ecdh);
+
+ if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+ (EC_GROUP_get_degree(group) > 163))
+ {
+ al=SSL_AD_EXPORT_RESTRICTION;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+ goto f_err;
+ }
+
+ p+=3;
+
+ /* Next, get the encoded ECPoint */
+ if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) ||
+ ((bn_ctx = BN_CTX_new()) == NULL))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ encoded_pt_len = *p; /* length of encoded point */
+ p+=1;
+ param_len += (1 + encoded_pt_len);
+ if ((param_len > n) ||
+ (EC_POINT_oct2point(group, srvr_ecpoint,
+ p, encoded_pt_len, bn_ctx) == 0))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_ECPOINT);
+ goto f_err;
+ }
+
+ n-=param_len;
+ p+=encoded_pt_len;
+
+ /* The ECC/TLS specification does not mention
+ * the use of DSA to sign ECParameters in the server
+ * key exchange message. We do support RSA and ECDSA.
+ */
+ if (0) ;
+#ifndef OPENSSL_NO_RSA
+ else if (alg_a & SSL_aRSA)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ else if (alg_a & SSL_aECDSA)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
+#endif
+ /* else anonymous ECDH, so no certificate or pkey. */
+ EC_KEY_set_public_key(ecdh, srvr_ecpoint);
+ s->session->sess_cert->peer_ecdh_tmp=ecdh;
+ ecdh=NULL;
+ BN_CTX_free(bn_ctx);
+ bn_ctx = NULL;
+ EC_POINT_free(srvr_ecpoint);
+ srvr_ecpoint = NULL;
+ }
+ else if (alg_k)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+#endif /* !OPENSSL_NO_ECDH */
+
+
+ /* p points to the next byte, there are 'n' bytes left */
+
+ /* if it was signed, check the signature */
+ if (pkey != NULL)
+ {
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ int sigalg = tls12_get_sigid(pkey);
+ /* Should never happen */
+ if (sigalg == -1)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ /* Check key type is consistent with signature */
+ if (sigalg != (int)p[1])
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ md = tls12_get_hash(p[0]);
+ if (md == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+#ifdef SSL_DEBUG
+fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+ p += 2;
+ n -= 2;
+ }
+ else
+ md = EVP_sha1();
+
+ n2s(p,i);
+ n-=2;
+ j=EVP_PKEY_size(pkey);
+
+ if ((i != n) || (n > j) || (n <= 0))
+ {
+ /* wrong packet length */
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_LENGTH);
+ goto f_err;
+ }
+
+#ifndef OPENSSL_NO_RSA
+ if (pkey->type == EVP_PKEY_RSA && TLS1_get_version(s) < TLS1_2_VERSION)
+ {
+ int num;
+
+ j=0;
+ q=md_buf;
+ for (num=2; num > 0; num--)
+ {
+ EVP_MD_CTX_set_flags(&md_ctx,
+ EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ EVP_DigestInit_ex(&md_ctx,(num == 2)
+ ?s->ctx->md5:s->ctx->sha1, NULL);
+ EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md_ctx,param,param_len);
+ EVP_DigestFinal_ex(&md_ctx,q,(unsigned int *)&i);
+ q+=i;
+ j+=i;
+ }
+ i=RSA_verify(NID_md5_sha1, md_buf, j, p, n,
+ pkey->pkey.rsa);
+ if (i < 0)
+ {
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT);
+ goto f_err;
+ }
+ if (i == 0)
+ {
+ /* bad signature */
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE);
+ goto f_err;
+ }
+ }
+ else
+#endif
+ {
+ EVP_VerifyInit_ex(&md_ctx, md, NULL);
+ EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_VerifyUpdate(&md_ctx,param,param_len);
+ if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0)
+ {
+ /* bad signature */
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE);
+ goto f_err;
+ }
+ }
+ }
+ else
+ {
+ if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
+ /* aNULL or kPSK do not need public keys */
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ /* still data left over */
+ if (n != 0)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_EXTRA_DATA_IN_MESSAGE);
+ goto f_err;
+ }
+ }
+ EVP_PKEY_free(pkey);
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return(1);
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ EVP_PKEY_free(pkey);
+#ifndef OPENSSL_NO_RSA
+ if (rsa != NULL)
+ RSA_free(rsa);
+#endif
+#ifndef OPENSSL_NO_DH
+ if (dh != NULL)
+ DH_free(dh);
+#endif
+#ifndef OPENSSL_NO_ECDH
+ BN_CTX_free(bn_ctx);
+ EC_POINT_free(srvr_ecpoint);
+ if (ecdh != NULL)
+ EC_KEY_free(ecdh);
+#endif
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return(-1);
+ }
+
+int ssl3_get_certificate_request(SSL *s)
+ {
+ int ok,ret=0;
+ unsigned long n,nc,l;
+ unsigned int llen, ctype_num,i;
+ X509_NAME *xn=NULL;
+ const unsigned char *p,*q;
+ unsigned char *d;
+ STACK_OF(X509_NAME) *ca_sk=NULL;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_CERT_REQ_A,
+ SSL3_ST_CR_CERT_REQ_B,
+ -1,
+ s->max_cert_list,
+ &ok);
+
+ if (!ok) return((int)n);
+
+ s->s3->tmp.cert_req=0;
+
+ if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)
+ {
+ s->s3->tmp.reuse_message=1;
+ /* If we get here we don't need any cached handshake records
+ * as we wont be doing client auth.
+ */
+ if (s->s3->handshake_buffer)
+ {
+ if (!ssl3_digest_cached_records(s))
+ goto err;
+ }
+ return(1);
+ }
+
+ if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_WRONG_MESSAGE_TYPE);
+ goto err;
+ }
+
+ /* TLS does not like anon-DH with client cert */
+ if (s->version > SSL3_VERSION)
+ {
+ if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER);
+ goto err;
+ }
+ }
+
+ p=d=(unsigned char *)s->init_msg;
+
+ if ((ca_sk=sk_X509_NAME_new(ca_dn_cmp)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* get the certificate types */
+ ctype_num= *(p++);
+ if (ctype_num > SSL3_CT_NUMBER)
+ ctype_num=SSL3_CT_NUMBER;
+ for (i=0; i<ctype_num; i++)
+ s->s3->tmp.ctype[i]= p[i];
+ p+=ctype_num;
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ n2s(p, llen);
+ /* Check we have enough room for signature algorithms and
+ * following length value.
+ */
+ if ((unsigned long)(p - d + llen + 2) > n)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_DATA_LENGTH_TOO_LONG);
+ goto err;
+ }
+ if ((llen & 1) || !tls1_process_sigalgs(s, p, llen))
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_SIGNATURE_ALGORITHMS_ERROR);
+ goto err;
+ }
+ p += llen;
+ }
+
+ /* get the CA RDNs */
+ n2s(p,llen);
+#if 0
+{
+FILE *out;
+out=fopen("/tmp/vsign.der","w");
+fwrite(p,1,llen,out);
+fclose(out);
+}
+#endif
+
+ if ((unsigned long)(p - d + llen) != n)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ for (nc=0; nc<llen; )
+ {
+ n2s(p,l);
+ if ((l+nc+2) > llen)
+ {
+ if ((s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
+ goto cont; /* netscape bugs */
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_CA_DN_TOO_LONG);
+ goto err;
+ }
+
+ q=p;
+
+ if ((xn=d2i_X509_NAME(NULL,&q,l)) == NULL)
+ {
+ /* If netscape tolerance is on, ignore errors */
+ if (s->options & SSL_OP_NETSCAPE_CA_DN_BUG)
+ goto cont;
+ else
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,ERR_R_ASN1_LIB);
+ goto err;
+ }
+ }
+
+ if (q != (p+l))
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_CA_DN_LENGTH_MISMATCH);
+ goto err;
+ }
+ if (!sk_X509_NAME_push(ca_sk,xn))
+ {
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ p+=l;
+ nc+=l+2;
+ }
+
+ if (0)
+ {
+cont:
+ ERR_clear_error();
+ }
+
+ /* we should setup a certificate to return.... */
+ s->s3->tmp.cert_req=1;
+ s->s3->tmp.ctype_num=ctype_num;
+ if (s->s3->tmp.ca_names != NULL)
+ sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
+ s->s3->tmp.ca_names=ca_sk;
+ ca_sk=NULL;
+
+ ret=1;
+err:
+ if (ca_sk != NULL) sk_X509_NAME_pop_free(ca_sk,X509_NAME_free);
+ return(ret);
+ }
+
+static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
+ {
+ return(X509_NAME_cmp(*a,*b));
+ }
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_get_new_session_ticket(SSL *s)
+ {
+ int ok,al,ret=0, ticklen;
+ long n;
+ const unsigned char *p;
+ unsigned char *d;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_SESSION_TICKET_A,
+ SSL3_ST_CR_SESSION_TICKET_B,
+ -1,
+ 16384,
+ &ok);
+
+ if (!ok)
+ return((int)n);
+
+ if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
+ {
+ s->s3->tmp.reuse_message=1;
+ return(1);
+ }
+ if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_BAD_MESSAGE_TYPE);
+ goto f_err;
+ }
+ if (n < 6)
+ {
+ /* need at least ticket_lifetime_hint + ticket length */
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+
+ p=d=(unsigned char *)s->init_msg;
+ n2l(p, s->session->tlsext_tick_lifetime_hint);
+ n2s(p, ticklen);
+ /* ticket_lifetime_hint + ticket_length + ticket */
+ if (ticklen + 6 != n)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if (s->session->tlsext_tick)
+ {
+ OPENSSL_free(s->session->tlsext_tick);
+ s->session->tlsext_ticklen = 0;
+ }
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ {
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memcpy(s->session->tlsext_tick, p, ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ /* There are two ways to detect a resumed ticket sesion.
+ * One is to set an appropriate session ID and then the server
+ * must return a match in ServerHello. This allows the normal
+ * client session ID matching to work and we know much
+ * earlier that the ticket has been accepted.
+ *
+ * The other way is to set zero length session ID when the
+ * ticket is presented and rely on the handshake to determine
+ * session resumption.
+ *
+ * We choose the former approach because this fits in with
+ * assumptions elsewhere in OpenSSL. The session ID is set
+ * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the
+ * ticket.
+ */
+ EVP_Digest(p, ticklen,
+ s->session->session_id, &s->session->session_id_length,
+#ifndef OPENSSL_NO_SHA256
+ EVP_sha256(), NULL);
+#else
+ EVP_sha1(), NULL);
+#endif
+ ret=1;
+ return(ret);
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(-1);
+ }
+
+int ssl3_get_cert_status(SSL *s)
+ {
+ int ok, al;
+ unsigned long resplen,n;
+ const unsigned char *p;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_CERT_STATUS_A,
+ SSL3_ST_CR_CERT_STATUS_B,
+ SSL3_MT_CERTIFICATE_STATUS,
+ 16384,
+ &ok);
+
+ if (!ok) return((int)n);
+ if (n < 4)
+ {
+ /* need at least status type + length */
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ p = (unsigned char *)s->init_msg;
+ if (*p++ != TLSEXT_STATUSTYPE_ocsp)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_UNSUPPORTED_STATUS_TYPE);
+ goto f_err;
+ }
+ n2l3(p, resplen);
+ if (resplen + 4 != n)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if (s->tlsext_ocsp_resp)
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
+ if (!s->tlsext_ocsp_resp)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ s->tlsext_ocsp_resplen = resplen;
+ if (s->ctx->tlsext_status_cb)
+ {
+ int ret;
+ ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ if (ret == 0)
+ {
+ al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_INVALID_STATUS_RESPONSE);
+ goto f_err;
+ }
+ if (ret < 0)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ }
+ return 1;
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return(-1);
+ }
+#endif
+
+int ssl3_get_server_done(SSL *s)
+ {
+ int ok,ret=0;
+ long n;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_SRVR_DONE_A,
+ SSL3_ST_CR_SRVR_DONE_B,
+ SSL3_MT_SERVER_DONE,
+ 30, /* should be very small, like 0 :-) */
+ &ok);
+
+ if (!ok) return((int)n);
+ if (n > 0)
+ {
+ /* should contain no data */
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_SERVER_DONE,SSL_R_LENGTH_MISMATCH);
+ return -1;
+ }
+ ret=1;
+ return(ret);
+ }
+
+
+int ssl3_send_client_key_exchange(SSL *s)
+ {
+ unsigned char *p,*d;
+ int n;
+ unsigned long alg_k;
+#ifndef OPENSSL_NO_RSA
+ unsigned char *q;
+ EVP_PKEY *pkey=NULL;
+#endif
+#ifndef OPENSSL_NO_KRB5
+ KSSL_ERR kssl_err;
+#endif /* OPENSSL_NO_KRB5 */
+#ifndef OPENSSL_NO_ECDH
+ EC_KEY *clnt_ecdh = NULL;
+ const EC_POINT *srvr_ecpoint = NULL;
+ EVP_PKEY *srvr_pub_pkey = NULL;
+ unsigned char *encodedPoint = NULL;
+ int encoded_pt_len = 0;
+ BN_CTX * bn_ctx = NULL;
+#endif
+
+ if (s->state == SSL3_ST_CW_KEY_EXCH_A)
+ {
+ d=(unsigned char *)s->init_buf->data;
+ p= &(d[4]);
+
+ alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+
+ /* Fool emacs indentation */
+ if (0) {}
+#ifndef OPENSSL_NO_RSA
+ else if (alg_k & SSL_kRSA)
+ {
+ RSA *rsa;
+ unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+
+ if (s->session->sess_cert->peer_rsa_tmp != NULL)
+ rsa=s->session->sess_cert->peer_rsa_tmp;
+ else
+ {
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+ if ((pkey == NULL) ||
+ (pkey->type != EVP_PKEY_RSA) ||
+ (pkey->pkey.rsa == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ rsa=pkey->pkey.rsa;
+ EVP_PKEY_free(pkey);
+ }
+
+ tmp_buf[0]=s->client_version>>8;
+ tmp_buf[1]=s->client_version&0xff;
+ if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
+ goto err;
+
+ s->session->master_key_length=sizeof tmp_buf;
+
+ q=p;
+ /* Fix buf for TLS and beyond */
+ if (s->version > SSL3_VERSION)
+ p+=2;
+ n=RSA_public_encrypt(sizeof tmp_buf,
+ tmp_buf,p,rsa,RSA_PKCS1_PADDING);
+#ifdef PKCS1_CHECK
+ if (s->options & SSL_OP_PKCS1_CHECK_1) p[1]++;
+ if (s->options & SSL_OP_PKCS1_CHECK_2) tmp_buf[0]=0x70;
+#endif
+ if (n <= 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_ENCRYPT);
+ goto err;
+ }
+
+ /* Fix buf for TLS and beyond */
+ if (s->version > SSL3_VERSION)
+ {
+ s2n(n,q);
+ n+=2;
+ }
+
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,
+ tmp_buf,sizeof tmp_buf);
+ OPENSSL_cleanse(tmp_buf,sizeof tmp_buf);
+ }
+#endif
+#ifndef OPENSSL_NO_KRB5
+ else if (alg_k & SSL_kKRB5)
+ {
+ krb5_error_code krb5rc;
+ KSSL_CTX *kssl_ctx = s->kssl_ctx;
+ /* krb5_data krb5_ap_req; */
+ krb5_data *enc_ticket;
+ krb5_data authenticator, *authp = NULL;
+ EVP_CIPHER_CTX ciph_ctx;
+ const EVP_CIPHER *enc = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+ unsigned char epms[SSL_MAX_MASTER_KEY_LENGTH
+ + EVP_MAX_IV_LENGTH];
+ int padl, outl = sizeof(epms);
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+#ifdef KSSL_DEBUG
+ printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
+ alg_k, SSL_kKRB5);
+#endif /* KSSL_DEBUG */
+
+ authp = NULL;
+#ifdef KRB5SENDAUTH
+ if (KRB5SENDAUTH) authp = &authenticator;
+#endif /* KRB5SENDAUTH */
+
+ krb5rc = kssl_cget_tkt(kssl_ctx, &enc_ticket, authp,
+ &kssl_err);
+ enc = kssl_map_enc(kssl_ctx->enctype);
+ if (enc == NULL)
+ goto err;
+#ifdef KSSL_DEBUG
+ {
+ printf("kssl_cget_tkt rtn %d\n", krb5rc);
+ if (krb5rc && kssl_err.text)
+ printf("kssl_cget_tkt kssl_err=%s\n", kssl_err.text);
+ }
+#endif /* KSSL_DEBUG */
+
+ if (krb5rc)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,
+ SSL_AD_HANDSHAKE_FAILURE);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ kssl_err.reason);
+ goto err;
+ }
+
+ /* 20010406 VRS - Earlier versions used KRB5 AP_REQ
+ ** in place of RFC 2712 KerberosWrapper, as in:
+ **
+ ** Send ticket (copy to *p, set n = length)
+ ** n = krb5_ap_req.length;
+ ** memcpy(p, krb5_ap_req.data, krb5_ap_req.length);
+ ** if (krb5_ap_req.data)
+ ** kssl_krb5_free_data_contents(NULL,&krb5_ap_req);
+ **
+ ** Now using real RFC 2712 KerberosWrapper
+ ** (Thanks to Simon Wilkinson <sxw@sxw.org.uk>)
+ ** Note: 2712 "opaque" types are here replaced
+ ** with a 2-byte length followed by the value.
+ ** Example:
+ ** KerberosWrapper= xx xx asn1ticket 0 0 xx xx encpms
+ ** Where "xx xx" = length bytes. Shown here with
+ ** optional authenticator omitted.
+ */
+
+ /* KerberosWrapper.Ticket */
+ s2n(enc_ticket->length,p);
+ memcpy(p, enc_ticket->data, enc_ticket->length);
+ p+= enc_ticket->length;
+ n = enc_ticket->length + 2;
+
+ /* KerberosWrapper.Authenticator */
+ if (authp && authp->length)
+ {
+ s2n(authp->length,p);
+ memcpy(p, authp->data, authp->length);
+ p+= authp->length;
+ n+= authp->length + 2;
+
+ free(authp->data);
+ authp->data = NULL;
+ authp->length = 0;
+ }
+ else
+ {
+ s2n(0,p);/* null authenticator length */
+ n+=2;
+ }
+
+ tmp_buf[0]=s->client_version>>8;
+ tmp_buf[1]=s->client_version&0xff;
+ if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
+ goto err;
+
+ /* 20010420 VRS. Tried it this way; failed.
+ ** EVP_EncryptInit_ex(&ciph_ctx,enc, NULL,NULL);
+ ** EVP_CIPHER_CTX_set_key_length(&ciph_ctx,
+ ** kssl_ctx->length);
+ ** EVP_EncryptInit_ex(&ciph_ctx,NULL, key,iv);
+ */
+
+ memset(iv, 0, sizeof iv); /* per RFC 1510 */
+ EVP_EncryptInit_ex(&ciph_ctx,enc, NULL,
+ kssl_ctx->key,iv);
+ EVP_EncryptUpdate(&ciph_ctx,epms,&outl,tmp_buf,
+ sizeof tmp_buf);
+ EVP_EncryptFinal_ex(&ciph_ctx,&(epms[outl]),&padl);
+ outl += padl;
+ if (outl > (int)sizeof epms)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ /* KerberosWrapper.EncryptedPreMasterSecret */
+ s2n(outl,p);
+ memcpy(p, epms, outl);
+ p+=outl;
+ n+=outl + 2;
+
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,
+ tmp_buf, sizeof tmp_buf);
+
+ OPENSSL_cleanse(tmp_buf, sizeof tmp_buf);
+ OPENSSL_cleanse(epms, outl);
+ }
+#endif
+#ifndef OPENSSL_NO_DH
+ else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+ {
+ DH *dh_srvr,*dh_clnt;
+
+ if (s->session->sess_cert == NULL)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
+ goto err;
+ }
+
+ if (s->session->sess_cert->peer_dh_tmp != NULL)
+ dh_srvr=s->session->sess_cert->peer_dh_tmp;
+ else
+ {
+ /* we get them from the cert */
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
+ goto err;
+ }
+
+ /* generate a new random key */
+ if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+ if (!DH_generate_key(dh_clnt))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ DH_free(dh_clnt);
+ goto err;
+ }
+
+ /* use the 'p' output buffer for the DH key, but
+ * make sure to clear it out afterwards */
+
+ n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
+
+ if (n <= 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ DH_free(dh_clnt);
+ goto err;
+ }
+
+ /* generate master key from the result */
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,p,n);
+ /* clean up */
+ memset(p,0,n);
+
+ /* send off the data */
+ n=BN_num_bytes(dh_clnt->pub_key);
+ s2n(n,p);
+ BN_bn2bin(dh_clnt->pub_key,p);
+ n+=2;
+
+ DH_free(dh_clnt);
+
+ /* perhaps clean things up a bit EAY EAY EAY EAY*/
+ }
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+ else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+ {
+ const EC_GROUP *srvr_group = NULL;
+ EC_KEY *tkey;
+ int ecdh_clnt_cert = 0;
+ int field_size = 0;
+
+ if (s->session->sess_cert == NULL)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
+ goto err;
+ }
+
+ /* Did we send out the client's
+ * ECDH share for use in premaster
+ * computation as part of client certificate?
+ * If so, set ecdh_clnt_cert to 1.
+ */
+ if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->cert != NULL))
+ {
+ /* XXX: For now, we do not support client
+ * authentication using ECDH certificates.
+ * To add such support, one needs to add
+ * code that checks for appropriate
+ * conditions and sets ecdh_clnt_cert to 1.
+ * For example, the cert have an ECC
+ * key on the same curve as the server's
+ * and the key should be authorized for
+ * key agreement.
+ *
+ * One also needs to add code in ssl3_connect
+ * to skip sending the certificate verify
+ * message.
+ *
+ * if ((s->cert->key->privatekey != NULL) &&
+ * (s->cert->key->privatekey->type ==
+ * EVP_PKEY_EC) && ...)
+ * ecdh_clnt_cert = 1;
+ */
+ }
+
+ if (s->session->sess_cert->peer_ecdh_tmp != NULL)
+ {
+ tkey = s->session->sess_cert->peer_ecdh_tmp;
+ }
+ else
+ {
+ /* Get the Server Public Key from Cert */
+ srvr_pub_pkey = X509_get_pubkey(s->session-> \
+ sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
+ if ((srvr_pub_pkey == NULL) ||
+ (srvr_pub_pkey->type != EVP_PKEY_EC) ||
+ (srvr_pub_pkey->pkey.ec == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ tkey = srvr_pub_pkey->pkey.ec;
+ }
+
+ srvr_group = EC_KEY_get0_group(tkey);
+ srvr_ecpoint = EC_KEY_get0_public_key(tkey);
+
+ if ((srvr_group == NULL) || (srvr_ecpoint == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if ((clnt_ecdh=EC_KEY_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!EC_KEY_set_group(clnt_ecdh, srvr_group))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_EC_LIB);
+ goto err;
+ }
+ if (ecdh_clnt_cert)
+ {
+ /* Reuse key info from our certificate
+ * We only need our private key to perform
+ * the ECDH computation.
+ */
+ const BIGNUM *priv_key;
+ tkey = s->cert->key->privatekey->pkey.ec;
+ priv_key = EC_KEY_get0_private_key(tkey);
+ if (priv_key == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!EC_KEY_set_private_key(clnt_ecdh, priv_key))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_EC_LIB);
+ goto err;
+ }
+ }
+ else
+ {
+ /* Generate a new ECDH key pair */
+ if (!(EC_KEY_generate_key(clnt_ecdh)))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+ goto err;
+ }
+ }
+
+ /* use the 'p' output buffer for the ECDH key, but
+ * make sure to clear it out afterwards
+ */
+
+ field_size = EC_GROUP_get_degree(srvr_group);
+ if (field_size <= 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_ECDH_LIB);
+ goto err;
+ }
+ n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL);
+ if (n <= 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ /* generate master key from the result */
+ s->session->master_key_length = s->method->ssl3_enc \
+ -> generate_master_secret(s,
+ s->session->master_key,
+ p, n);
+
+ memset(p, 0, n); /* clean up */
+
+ if (ecdh_clnt_cert)
+ {
+ /* Send empty client key exch message */
+ n = 0;
+ }
+ else
+ {
+ /* First check the size of encoding and
+ * allocate memory accordingly.
+ */
+ encoded_pt_len =
+ EC_POINT_point2oct(srvr_group,
+ EC_KEY_get0_public_key(clnt_ecdh),
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, NULL);
+
+ encodedPoint = (unsigned char *)
+ OPENSSL_malloc(encoded_pt_len *
+ sizeof(unsigned char));
+ bn_ctx = BN_CTX_new();
+ if ((encodedPoint == NULL) ||
+ (bn_ctx == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Encode the public key */
+ n = EC_POINT_point2oct(srvr_group,
+ EC_KEY_get0_public_key(clnt_ecdh),
+ POINT_CONVERSION_UNCOMPRESSED,
+ encodedPoint, encoded_pt_len, bn_ctx);
+
+ *p = n; /* length of encoded point */
+ /* Encoded point will be copied here */
+ p += 1;
+ /* copy the point */
+ memcpy((unsigned char *)p, encodedPoint, n);
+ /* increment n to account for length field */
+ n += 1;
+ }
+
+ /* Free allocated memory */
+ BN_CTX_free(bn_ctx);
+ if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+ if (clnt_ecdh != NULL)
+ EC_KEY_free(clnt_ecdh);
+ EVP_PKEY_free(srvr_pub_pkey);
+ }
+#endif /* !OPENSSL_NO_ECDH */
+ else if (alg_k & SSL_kGOST)
+ {
+ /* GOST key exchange message creation */
+ EVP_PKEY_CTX *pkey_ctx;
+ X509 *peer_cert;
+ size_t msglen;
+ unsigned int md_len;
+ int keytype;
+ unsigned char premaster_secret[32],shared_ukm[32], tmp[256];
+ EVP_MD_CTX *ukm_hash;
+ EVP_PKEY *pub_key;
+
+ /* Get server sertificate PKEY and create ctx from it */
+ peer_cert=s->session->sess_cert->peer_pkeys[(keytype=SSL_PKEY_GOST01)].x509;
+ if (!peer_cert)
+ peer_cert=s->session->sess_cert->peer_pkeys[(keytype=SSL_PKEY_GOST94)].x509;
+ if (!peer_cert) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
+ goto err;
+ }
+
+ pkey_ctx=EVP_PKEY_CTX_new(pub_key=X509_get_pubkey(peer_cert),NULL);
+ /* If we have send a certificate, and certificate key
+
+ * parameters match those of server certificate, use
+ * certificate key for key exchange
+ */
+
+ /* Otherwise, generate ephemeral key pair */
+
+ EVP_PKEY_encrypt_init(pkey_ctx);
+ /* Generate session key */
+ RAND_bytes(premaster_secret,32);
+ /* If we have client certificate, use its secret as peer key */
+ if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
+ if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <=0) {
+ /* If there was an error - just ignore it. Ephemeral key
+ * would be used
+ */
+ ERR_clear_error();
+ }
+ }
+ /* Compute shared IV and store it in algorithm-specific
+ * context data */
+ ukm_hash = EVP_MD_CTX_create();
+ EVP_DigestInit(ukm_hash,EVP_get_digestbynid(NID_id_GostR3411_94));
+ EVP_DigestUpdate(ukm_hash,s->s3->client_random,SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(ukm_hash,s->s3->server_random,SSL3_RANDOM_SIZE);
+ EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
+ EVP_MD_CTX_destroy(ukm_hash);
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx,-1,EVP_PKEY_OP_ENCRYPT,EVP_PKEY_CTRL_SET_IV,
+ 8,shared_ukm)<0) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_LIBRARY_BUG);
+ goto err;
+ }
+ /* Make GOST keytransport blob message */
+ /*Encapsulate it into sequence */
+ *(p++)=V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
+ msglen=255;
+ if (EVP_PKEY_encrypt(pkey_ctx,tmp,&msglen,premaster_secret,32)<0) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_LIBRARY_BUG);
+ goto err;
+ }
+ if (msglen >= 0x80)
+ {
+ *(p++)=0x81;
+ *(p++)= msglen & 0xff;
+ n=msglen+3;
+ }
+ else
+ {
+ *(p++)= msglen & 0xff;
+ n=msglen+2;
+ }
+ memcpy(p, tmp, msglen);
+ /* Check if pubkey from client certificate was used */
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
+ {
+ /* Set flag "skip certificate verify" */
+ s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+ }
+ EVP_PKEY_CTX_free(pkey_ctx);
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,premaster_secret,32);
+ EVP_PKEY_free(pub_key);
+
+ }
+#ifndef OPENSSL_NO_SRP
+ else if (alg_k & SSL_kSRP)
+ {
+ if (s->srp_ctx.A != NULL)
+ {
+ /* send off the data */
+ n=BN_num_bytes(s->srp_ctx.A);
+ s2n(n,p);
+ BN_bn2bin(s->srp_ctx.A,p);
+ n+=2;
+ }
+ else
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if (s->session->srp_username != NULL)
+ OPENSSL_free(s->session->srp_username);
+ s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+ if (s->session->srp_username == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((s->session->master_key_length = SRP_generate_client_master_secret(s,s->session->master_key))<0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+#endif
+#ifndef OPENSSL_NO_PSK
+ else if (alg_k & SSL_kPSK)
+ {
+ char identity[PSK_MAX_IDENTITY_LEN];
+ unsigned char *t = NULL;
+ unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
+ unsigned int pre_ms_len = 0, psk_len = 0;
+ int psk_err = 1;
+
+ n = 0;
+ if (s->psk_client_callback == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_PSK_NO_CLIENT_CB);
+ goto err;
+ }
+
+ psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
+ identity, PSK_MAX_IDENTITY_LEN,
+ psk_or_pre_ms, sizeof(psk_or_pre_ms));
+ if (psk_len > PSK_MAX_PSK_LEN)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto psk_err;
+ }
+ else if (psk_len == 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_PSK_IDENTITY_NOT_FOUND);
+ goto psk_err;
+ }
+
+ /* create PSK pre_master_secret */
+ pre_ms_len = 2+psk_len+2+psk_len;
+ t = psk_or_pre_ms;
+ memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
+ s2n(psk_len, t);
+ memset(t, 0, psk_len);
+ t+=psk_len;
+ s2n(psk_len, t);
+
+ if (s->session->psk_identity_hint != NULL)
+ OPENSSL_free(s->session->psk_identity_hint);
+ s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+ if (s->ctx->psk_identity_hint != NULL &&
+ s->session->psk_identity_hint == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto psk_err;
+ }
+
+ if (s->session->psk_identity != NULL)
+ OPENSSL_free(s->session->psk_identity);
+ s->session->psk_identity = BUF_strdup(identity);
+ if (s->session->psk_identity == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto psk_err;
+ }
+
+ s->session->master_key_length =
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,
+ psk_or_pre_ms, pre_ms_len);
+ n = strlen(identity);
+ s2n(n, p);
+ memcpy(p, identity, n);
+ n+=2;
+ psk_err = 0;
+ psk_err:
+ OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
+ OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
+ if (psk_err != 0)
+ {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
+ }
+ }
+#endif
+ else
+ {
+ ssl3_send_alert(s, SSL3_AL_FATAL,
+ SSL_AD_HANDSHAKE_FAILURE);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ *(d++)=SSL3_MT_CLIENT_KEY_EXCHANGE;
+ l2n3(n,d);
+
+ s->state=SSL3_ST_CW_KEY_EXCH_B;
+ /* number of bytes to write */
+ s->init_num=n+4;
+ s->init_off=0;
+ }
+
+ /* SSL3_ST_CW_KEY_EXCH_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+#ifndef OPENSSL_NO_ECDH
+ BN_CTX_free(bn_ctx);
+ if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+ if (clnt_ecdh != NULL)
+ EC_KEY_free(clnt_ecdh);
+ EVP_PKEY_free(srvr_pub_pkey);
+#endif
+ return(-1);
+ }
+
+int ssl3_send_client_verify(SSL *s)
+ {
+ unsigned char *p,*d;
+ unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+ EVP_PKEY *pkey;
+ EVP_PKEY_CTX *pctx=NULL;
+ EVP_MD_CTX mctx;
+ unsigned u=0;
+ unsigned long n;
+ int j;
+
+ EVP_MD_CTX_init(&mctx);
+
+ if (s->state == SSL3_ST_CW_CERT_VRFY_A)
+ {
+ d=(unsigned char *)s->init_buf->data;
+ p= &(d[4]);
+ pkey=s->cert->key->privatekey;
+/* Create context from key and test if sha1 is allowed as digest */
+ pctx = EVP_PKEY_CTX_new(pkey,NULL);
+ EVP_PKEY_sign_init(pctx);
+ if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0)
+ {
+ if (TLS1_get_version(s) < TLS1_2_VERSION)
+ s->method->ssl3_enc->cert_verify_mac(s,
+ NID_sha1,
+ &(data[MD5_DIGEST_LENGTH]));
+ }
+ else
+ {
+ ERR_clear_error();
+ }
+ /* For TLS v1.2 send signature algorithm and signature
+ * using agreed digest and cached handshake records.
+ */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ long hdatalen = 0;
+ void *hdata;
+ const EVP_MD *md = s->cert->key->digest;
+ hdatalen = BIO_get_mem_data(s->s3->handshake_buffer,
+ &hdata);
+ if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ p += 2;
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
+ EVP_MD_name(md));
+#endif
+ if (!EVP_SignInit_ex(&mctx, md, NULL)
+ || !EVP_SignUpdate(&mctx, hdata, hdatalen)
+ || !EVP_SignFinal(&mctx, p + 2, &u, pkey))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+ ERR_R_EVP_LIB);
+ goto err;
+ }
+ s2n(u,p);
+ n = u + 4;
+ if (!ssl3_digest_cached_records(s))
+ goto err;
+ }
+ else
+#ifndef OPENSSL_NO_RSA
+ if (pkey->type == EVP_PKEY_RSA)
+ {
+ s->method->ssl3_enc->cert_verify_mac(s,
+ NID_md5,
+ &(data[0]));
+ if (RSA_sign(NID_md5_sha1, data,
+ MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
+ &(p[2]), &u, pkey->pkey.rsa) <= 0 )
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_RSA_LIB);
+ goto err;
+ }
+ s2n(u,p);
+ n=u+2;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_DSA
+ if (pkey->type == EVP_PKEY_DSA)
+ {
+ if (!DSA_sign(pkey->save_type,
+ &(data[MD5_DIGEST_LENGTH]),
+ SHA_DIGEST_LENGTH,&(p[2]),
+ (unsigned int *)&j,pkey->pkey.dsa))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_DSA_LIB);
+ goto err;
+ }
+ s2n(j,p);
+ n=j+2;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (pkey->type == EVP_PKEY_EC)
+ {
+ if (!ECDSA_sign(pkey->save_type,
+ &(data[MD5_DIGEST_LENGTH]),
+ SHA_DIGEST_LENGTH,&(p[2]),
+ (unsigned int *)&j,pkey->pkey.ec))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+ ERR_R_ECDSA_LIB);
+ goto err;
+ }
+ s2n(j,p);
+ n=j+2;
+ }
+ else
+#endif
+ if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001)
+ {
+ unsigned char signbuf[64];
+ int i;
+ size_t sigsize=64;
+ s->method->ssl3_enc->cert_verify_mac(s,
+ NID_id_GostR3411_94,
+ data);
+ if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ for (i=63,j=0; i>=0; j++, i--) {
+ p[2+j]=signbuf[i];
+ }
+ s2n(j,p);
+ n=j+2;
+ }
+ else
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ *(d++)=SSL3_MT_CERTIFICATE_VERIFY;
+ l2n3(n,d);
+
+ s->state=SSL3_ST_CW_CERT_VRFY_B;
+ s->init_num=(int)n+4;
+ s->init_off=0;
+ }
+ EVP_MD_CTX_cleanup(&mctx);
+ EVP_PKEY_CTX_free(pctx);
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+ EVP_MD_CTX_cleanup(&mctx);
+ EVP_PKEY_CTX_free(pctx);
+ return(-1);
+ }
+
+int ssl3_send_client_certificate(SSL *s)
+ {
+ X509 *x509=NULL;
+ EVP_PKEY *pkey=NULL;
+ int i;
+ unsigned long l;
+
+ if (s->state == SSL3_ST_CW_CERT_A)
+ {
+ if ((s->cert == NULL) ||
+ (s->cert->key->x509 == NULL) ||
+ (s->cert->key->privatekey == NULL))
+ s->state=SSL3_ST_CW_CERT_B;
+ else
+ s->state=SSL3_ST_CW_CERT_C;
+ }
+
+ /* We need to get a client cert */
+ if (s->state == SSL3_ST_CW_CERT_B)
+ {
+ /* If we get an error, we need to
+ * ssl->rwstate=SSL_X509_LOOKUP; return(-1);
+ * We then get retied later */
+ i=0;
+ i = ssl_do_client_cert_cb(s, &x509, &pkey);
+ if (i < 0)
+ {
+ s->rwstate=SSL_X509_LOOKUP;
+ return(-1);
+ }
+ s->rwstate=SSL_NOTHING;
+ if ((i == 1) && (pkey != NULL) && (x509 != NULL))
+ {
+ s->state=SSL3_ST_CW_CERT_B;
+ if ( !SSL_use_certificate(s,x509) ||
+ !SSL_use_PrivateKey(s,pkey))
+ i=0;
+ }
+ else if (i == 1)
+ {
+ i=0;
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE,SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
+ }
+
+ if (x509 != NULL) X509_free(x509);
+ if (pkey != NULL) EVP_PKEY_free(pkey);
+ if (i == 0)
+ {
+ if (s->version == SSL3_VERSION)
+ {
+ s->s3->tmp.cert_req=0;
+ ssl3_send_alert(s,SSL3_AL_WARNING,SSL_AD_NO_CERTIFICATE);
+ return(1);
+ }
+ else
+ {
+ s->s3->tmp.cert_req=2;
+ }
+ }
+
+ /* Ok, we have a cert */
+ s->state=SSL3_ST_CW_CERT_C;
+ }
+
+ if (s->state == SSL3_ST_CW_CERT_C)
+ {
+ s->state=SSL3_ST_CW_CERT_D;
+ l=ssl3_output_cert_chain(s,
+ (s->s3->tmp.cert_req == 2)?NULL:s->cert->key->x509);
+ s->init_num=(int)l;
+ s->init_off=0;
+ }
+ /* SSL3_ST_CW_CERT_D */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+#define has_bits(i,m) (((i)&(m)) == (m))
+
+int ssl3_check_cert_and_algorithm(SSL *s)
+ {
+ int i,idx;
+ long alg_k,alg_a;
+ EVP_PKEY *pkey=NULL;
+ SESS_CERT *sc;
+#ifndef OPENSSL_NO_RSA
+ RSA *rsa;
+#endif
+#ifndef OPENSSL_NO_DH
+ DH *dh;
+#endif
+
+ alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+ alg_a=s->s3->tmp.new_cipher->algorithm_auth;
+
+ /* we don't have a certificate */
+ if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
+ return(1);
+
+ sc=s->session->sess_cert;
+ if (sc == NULL)
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+#ifndef OPENSSL_NO_RSA
+ rsa=s->session->sess_cert->peer_rsa_tmp;
+#endif
+#ifndef OPENSSL_NO_DH
+ dh=s->session->sess_cert->peer_dh_tmp;
+#endif
+
+ /* This is the passed certificate */
+
+ idx=sc->peer_cert_type;
+#ifndef OPENSSL_NO_ECDH
+ if (idx == SSL_PKEY_ECC)
+ {
+ if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
+ s) == 0)
+ { /* check failed */
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT);
+ goto f_err;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+#endif
+ pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509);
+ i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey);
+ EVP_PKEY_free(pkey);
+
+
+ /* Check that we have a certificate if we require one */
+ if ((alg_a & SSL_aRSA) && !has_bits(i,EVP_PK_RSA|EVP_PKT_SIGN))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_SIGNING_CERT);
+ goto f_err;
+ }
+#ifndef OPENSSL_NO_DSA
+ else if ((alg_a & SSL_aDSS) && !has_bits(i,EVP_PK_DSA|EVP_PKT_SIGN))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DSA_SIGNING_CERT);
+ goto f_err;
+ }
+#endif
+#ifndef OPENSSL_NO_RSA
+ if ((alg_k & SSL_kRSA) &&
+ !(has_bits(i,EVP_PK_RSA|EVP_PKT_ENC) || (rsa != NULL)))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+ goto f_err;
+ }
+#endif
+#ifndef OPENSSL_NO_DH
+ if ((alg_k & SSL_kEDH) &&
+ !(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL)))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_KEY);
+ goto f_err;
+ }
+ else if ((alg_k & SSL_kDHr) && !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_RSA_CERT);
+ goto f_err;
+ }
+#ifndef OPENSSL_NO_DSA
+ else if ((alg_k & SSL_kDHd) && !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_DSA_CERT);
+ goto f_err;
+ }
+#endif
+#endif
+
+ if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i,EVP_PKT_EXP))
+ {
+#ifndef OPENSSL_NO_RSA
+ if (alg_k & SSL_kRSA)
+ {
+ if (rsa == NULL
+ || RSA_size(rsa)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
+ goto f_err;
+ }
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_DH
+ if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+ {
+ if (dh == NULL
+ || DH_size(dh)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_EXPORT_TMP_DH_KEY);
+ goto f_err;
+ }
+ }
+ else
+#endif
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+ goto f_err;
+ }
+ }
+ return(1);
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+err:
+ return(0);
+ }
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+int ssl3_send_next_proto(SSL *s)
+ {
+ unsigned int len, padding_len;
+ unsigned char *d;
+
+ if (s->state == SSL3_ST_CW_NEXT_PROTO_A)
+ {
+ len = s->next_proto_negotiated_len;
+ padding_len = 32 - ((len + 2) % 32);
+ d = (unsigned char *)s->init_buf->data;
+ d[4] = len;
+ memcpy(d + 5, s->next_proto_negotiated, len);
+ d[5 + len] = padding_len;
+ memset(d + 6 + len, 0, padding_len);
+ *(d++)=SSL3_MT_NEXT_PROTO;
+ l2n3(2 + len + padding_len, d);
+ s->state = SSL3_ST_CW_NEXT_PROTO_B;
+ s->init_num = 4 + 2 + len + padding_len;
+ s->init_off = 0;
+ }
+
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+}
+#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
+
+/* Check to see if handshake is full or resumed. Usually this is just a
+ * case of checking to see if a cache hit has occurred. In the case of
+ * session tickets we have to check the next message to be sure.
+ */
+
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_check_finished(SSL *s)
+ {
+ int ok;
+ long n;
+ /* If we have no ticket it cannot be a resumed session. */
+ if (!s->session->tlsext_tick)
+ return 1;
+ /* this function is called when we really expect a Certificate
+ * message, so permit appropriate message length */
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_CERT_A,
+ SSL3_ST_CR_CERT_B,
+ -1,
+ s->max_cert_list,
+ &ok);
+ if (!ok) return((int)n);
+ s->s3->tmp.reuse_message = 1;
+ if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
+ || (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
+ return 2;
+
+ return 1;
+ }
+#endif
+
+int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
+ {
+ int i = 0;
+#ifndef OPENSSL_NO_ENGINE
+ if (s->ctx->client_cert_engine)
+ {
+ i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s,
+ SSL_get_client_CA_list(s),
+ px509, ppkey, NULL, NULL, NULL);
+ if (i != 0)
+ return i;
+ }
+#endif
+ if (s->ctx->client_cert_cb)
+ i = s->ctx->client_cert_cb(s,px509,ppkey);
+ return i;
+ }
diff --git a/drivers/builtin_openssl/ssl/s3_enc.c b/drivers/builtin_openssl2/ssl/s3_enc.c
index e3cd4f062c..e3cd4f062c 100644
--- a/drivers/builtin_openssl/ssl/s3_enc.c
+++ b/drivers/builtin_openssl2/ssl/s3_enc.c
diff --git a/drivers/builtin_openssl/ssl/s3_lib.c b/drivers/builtin_openssl2/ssl/s3_lib.c
index c4ef2738d7..c4ef2738d7 100644
--- a/drivers/builtin_openssl/ssl/s3_lib.c
+++ b/drivers/builtin_openssl2/ssl/s3_lib.c
diff --git a/drivers/builtin_openssl/ssl/s3_meth.c b/drivers/builtin_openssl2/ssl/s3_meth.c
index cdddb17b62..cdddb17b62 100644
--- a/drivers/builtin_openssl/ssl/s3_meth.c
+++ b/drivers/builtin_openssl2/ssl/s3_meth.c
diff --git a/drivers/builtin_openssl2/ssl/s3_pkt.c b/drivers/builtin_openssl2/ssl/s3_pkt.c
new file mode 100644
index 0000000000..59011e39c6
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/s3_pkt.c
@@ -0,0 +1,1557 @@
+/* ssl/s3_pkt.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <errno.h>
+#define USE_SOCKETS
+#include "ssl_locl.h"
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+
+static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ unsigned int len, int create_empty_fragment);
+static int ssl3_get_record(SSL *s);
+
+int ssl3_read_n(SSL *s, int n, int max, int extend)
+ {
+ /* If extend == 0, obtain new n-byte packet; if extend == 1, increase
+ * packet by another n bytes.
+ * The packet will be in the sub-array of s->s3->rbuf.buf specified
+ * by s->packet and s->packet_length.
+ * (If s->read_ahead is set, 'max' bytes may be stored in rbuf
+ * [plus s->packet_length bytes if extend == 1].)
+ */
+ int i,len,left;
+ long align=0;
+ unsigned char *pkt;
+ SSL3_BUFFER *rb;
+
+ if (n <= 0) return n;
+
+ rb = &(s->s3->rbuf);
+ if (rb->buf == NULL)
+ if (!ssl3_setup_read_buffer(s))
+ return -1;
+
+ left = rb->left;
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+ align = (long)rb->buf + SSL3_RT_HEADER_LENGTH;
+ align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+
+ if (!extend)
+ {
+ /* start with empty packet ... */
+ if (left == 0)
+ rb->offset = align;
+ else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH)
+ {
+ /* check if next packet length is large
+ * enough to justify payload alignment... */
+ pkt = rb->buf + rb->offset;
+ if (pkt[0] == SSL3_RT_APPLICATION_DATA
+ && (pkt[3]<<8|pkt[4]) >= 128)
+ {
+ /* Note that even if packet is corrupted
+ * and its length field is insane, we can
+ * only be led to wrong decision about
+ * whether memmove will occur or not.
+ * Header values has no effect on memmove
+ * arguments and therefore no buffer
+ * overrun can be triggered. */
+ memmove (rb->buf+align,pkt,left);
+ rb->offset = align;
+ }
+ }
+ s->packet = rb->buf + rb->offset;
+ s->packet_length = 0;
+ /* ... now we can act as if 'extend' was set */
+ }
+
+ /* For DTLS/UDP reads should not span multiple packets
+ * because the read operation returns the whole packet
+ * at once (as long as it fits into the buffer). */
+ if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+ {
+ if (left > 0 && n > left)
+ n = left;
+ }
+
+ /* if there is enough in the buffer from a previous read, take some */
+ if (left >= n)
+ {
+ s->packet_length+=n;
+ rb->left=left-n;
+ rb->offset+=n;
+ return(n);
+ }
+
+ /* else we need to read more data */
+
+ len = s->packet_length;
+ pkt = rb->buf+align;
+ /* Move any available bytes to front of buffer:
+ * 'len' bytes already pointed to by 'packet',
+ * 'left' extra ones at the end */
+ if (s->packet != pkt) /* len > 0 */
+ {
+ memmove(pkt, s->packet, len+left);
+ s->packet = pkt;
+ rb->offset = len + align;
+ }
+
+ if (n > (int)(rb->len - rb->offset)) /* does not happen */
+ {
+ SSLerr(SSL_F_SSL3_READ_N,ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (!s->read_ahead)
+ /* ignore max parameter */
+ max = n;
+ else
+ {
+ if (max < n)
+ max = n;
+ if (max > (int)(rb->len - rb->offset))
+ max = rb->len - rb->offset;
+ }
+
+ while (left < n)
+ {
+ /* Now we have len+left bytes at the front of s->s3->rbuf.buf
+ * and need to read in more until we have len+n (up to
+ * len+max if possible) */
+
+ clear_sys_error();
+ if (s->rbio != NULL)
+ {
+ s->rwstate=SSL_READING;
+ i=BIO_read(s->rbio,pkt+len+left, max-left);
+ }
+ else
+ {
+ SSLerr(SSL_F_SSL3_READ_N,SSL_R_READ_BIO_NOT_SET);
+ i = -1;
+ }
+
+ if (i <= 0)
+ {
+ rb->left = left;
+ if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
+ SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
+ if (len+left == 0)
+ ssl3_release_read_buffer(s);
+ return(i);
+ }
+ left+=i;
+ /* reads should *never* span multiple packets for DTLS because
+ * the underlying transport protocol is message oriented as opposed
+ * to byte oriented as in the TLS case. */
+ if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+ {
+ if (n > left)
+ n = left; /* makes the while condition false */
+ }
+ }
+
+ /* done reading, now the book-keeping */
+ rb->offset += n;
+ rb->left = left - n;
+ s->packet_length += n;
+ s->rwstate=SSL_NOTHING;
+ return(n);
+ }
+
+/* Call this to get a new input record.
+ * It will return <= 0 if more data is needed, normally due to an error
+ * or non-blocking IO.
+ * When it finishes, one packet has been decoded and can be found in
+ * ssl->s3->rrec.type - is the type of record
+ * ssl->s3->rrec.data, - data
+ * ssl->s3->rrec.length, - number of bytes
+ */
+/* used only by ssl3_read_bytes */
+static int ssl3_get_record(SSL *s)
+ {
+ int ssl_major,ssl_minor,al;
+ int enc_err,n,i,ret= -1;
+ SSL3_RECORD *rr;
+ SSL_SESSION *sess;
+ unsigned char *p;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ short version;
+ unsigned mac_size, orig_len;
+ size_t extra;
+
+ rr= &(s->s3->rrec);
+ sess=s->session;
+
+ if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
+ extra=SSL3_RT_MAX_EXTRA;
+ else
+ extra=0;
+ if (extra && !s->s3->init_extra)
+ {
+ /* An application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
+ * set after ssl3_setup_buffers() was done */
+ SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+again:
+ /* check if we have the header */
+ if ( (s->rstate != SSL_ST_READ_BODY) ||
+ (s->packet_length < SSL3_RT_HEADER_LENGTH))
+ {
+ n=ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
+ if (n <= 0) return(n); /* error or non-blocking */
+ s->rstate=SSL_ST_READ_BODY;
+
+ p=s->packet;
+
+ /* Pull apart the header into the SSL3_RECORD */
+ rr->type= *(p++);
+ ssl_major= *(p++);
+ ssl_minor= *(p++);
+ version=(ssl_major<<8)|ssl_minor;
+ n2s(p,rr->length);
+#if 0
+fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
+#endif
+
+ /* Lets check version */
+ if (!s->first_packet)
+ {
+ if (version != s->version)
+ {
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
+ if ((s->version & 0xFF00) == (version & 0xFF00) && !s->enc_write_ctx && !s->write_hash)
+ /* Send back error using their minor version number :-) */
+ s->version = (unsigned short)version;
+ al=SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+ }
+
+ if ((version>>8) != SSL3_VERSION_MAJOR)
+ {
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
+ goto err;
+ }
+
+ if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+
+ /* now s->rstate == SSL_ST_READ_BODY */
+ }
+
+ /* s->rstate == SSL_ST_READ_BODY, get and decode the data */
+
+ if (rr->length > s->packet_length-SSL3_RT_HEADER_LENGTH)
+ {
+ /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
+ i=rr->length;
+ n=ssl3_read_n(s,i,i,1);
+ if (n <= 0) return(n); /* error or non-blocking io */
+ /* now n == rr->length,
+ * and s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length */
+ }
+
+ s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
+
+ /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
+ * and we have that many bytes in s->packet
+ */
+ rr->input= &(s->packet[SSL3_RT_HEADER_LENGTH]);
+
+ /* ok, we can now read from 's->packet' data into 'rr'
+ * rr->input points at rr->length bytes, which
+ * need to be copied into rr->data by either
+ * the decryption or by the decompression
+ * When the data is 'copied' into the rr->data buffer,
+ * rr->input will be pointed at the new buffer */
+
+ /* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
+ * rr->length bytes of encrypted compressed stuff. */
+
+ /* check is not needed I believe */
+ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+
+ /* decrypt in place in 'rr->input' */
+ rr->data=rr->input;
+
+ enc_err = s->method->ssl3_enc->enc(s,0);
+ /* enc_err is:
+ * 0: (in non-constant time) if the record is publically invalid.
+ * 1: if the padding is valid
+ * -1: if the padding is invalid */
+ if (enc_err == 0)
+ {
+ al=SSL_AD_DECRYPTION_FAILED;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
+ goto f_err;
+ }
+
+#ifdef TLS_DEBUG
+printf("dec %d\n",rr->length);
+{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
+printf("\n");
+#endif
+
+ /* r->length is now the compressed data plus mac */
+ if ((sess != NULL) &&
+ (s->enc_read_ctx != NULL) &&
+ (EVP_MD_CTX_md(s->read_hash) != NULL))
+ {
+ /* s->read_hash != NULL => mac_size != -1 */
+ unsigned char *mac = NULL;
+ unsigned char mac_tmp[EVP_MAX_MD_SIZE];
+ mac_size=EVP_MD_CTX_size(s->read_hash);
+ OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
+
+ /* kludge: *_cbc_remove_padding passes padding length in rr->type */
+ orig_len = rr->length+((unsigned int)rr->type>>8);
+
+ /* orig_len is the length of the record before any padding was
+ * removed. This is public information, as is the MAC in use,
+ * therefore we can safely process the record in a different
+ * amount of time if it's too short to possibly contain a MAC.
+ */
+ if (orig_len < mac_size ||
+ /* CBC records must have a padding length byte too. */
+ (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+ orig_len < mac_size+1))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
+ goto f_err;
+ }
+
+ if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
+ {
+ /* We update the length so that the TLS header bytes
+ * can be constructed correctly but we need to extract
+ * the MAC in constant time from within the record,
+ * without leaking the contents of the padding bytes.
+ * */
+ mac = mac_tmp;
+ ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
+ rr->length -= mac_size;
+ }
+ else
+ {
+ /* In this case there's no padding, so |orig_len|
+ * equals |rec->length| and we checked that there's
+ * enough bytes for |mac_size| above. */
+ rr->length -= mac_size;
+ mac = &rr->data[rr->length];
+ }
+
+ i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
+ if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+ enc_err = -1;
+ if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
+ enc_err = -1;
+ }
+
+ if (enc_err < 0)
+ {
+ /* A separate 'decryption_failed' alert was introduced with TLS 1.0,
+ * SSL 3.0 only has 'bad_record_mac'. But unless a decryption
+ * failure is directly visible from the ciphertext anyway,
+ * we should not reveal which kind of error occured -- this
+ * might become visible to an attacker (e.g. via a logfile) */
+ al=SSL_AD_BAD_RECORD_MAC;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+ goto f_err;
+ }
+
+ /* r->length is now just compressed */
+ if (s->expand != NULL)
+ {
+ if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+ if (!ssl3_do_uncompress(s))
+ {
+ al=SSL_AD_DECOMPRESSION_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
+ goto f_err;
+ }
+ }
+
+ if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH+extra)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+
+ rr->off=0;
+ /* So at this point the following is true
+ * ssl->s3->rrec.type is the type of record
+ * ssl->s3->rrec.length == number of bytes in record
+ * ssl->s3->rrec.off == offset to first valid byte
+ * ssl->s3->rrec.data == where to take bytes from, increment
+ * after use :-).
+ */
+
+ /* we have pulled in a full packet so zero things */
+ s->packet_length=0;
+
+ /* just read a 0 length packet */
+ if (rr->length == 0) goto again;
+
+#if 0
+fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, rr->length);
+#endif
+
+ return(1);
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(ret);
+ }
+
+int ssl3_do_uncompress(SSL *ssl)
+ {
+#ifndef OPENSSL_NO_COMP
+ int i;
+ SSL3_RECORD *rr;
+
+ rr= &(ssl->s3->rrec);
+ i=COMP_expand_block(ssl->expand,rr->comp,
+ SSL3_RT_MAX_PLAIN_LENGTH,rr->data,(int)rr->length);
+ if (i < 0)
+ return(0);
+ else
+ rr->length=i;
+ rr->data=rr->comp;
+#endif
+ return(1);
+ }
+
+int ssl3_do_compress(SSL *ssl)
+ {
+#ifndef OPENSSL_NO_COMP
+ int i;
+ SSL3_RECORD *wr;
+
+ wr= &(ssl->s3->wrec);
+ i=COMP_compress_block(ssl->compress,wr->data,
+ SSL3_RT_MAX_COMPRESSED_LENGTH,
+ wr->input,(int)wr->length);
+ if (i < 0)
+ return(0);
+ else
+ wr->length=i;
+
+ wr->input=wr->data;
+#endif
+ return(1);
+ }
+
+/* Call this to write data in records of type 'type'
+ * It will return <= 0 if not all data has been sent or non-blocking IO.
+ */
+int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
+ {
+ const unsigned char *buf=buf_;
+ unsigned int n,nw;
+ int i,tot;
+
+ s->rwstate=SSL_NOTHING;
+ OPENSSL_assert(s->s3->wnum <= INT_MAX);
+ tot=s->s3->wnum;
+ s->s3->wnum=0;
+
+ if (SSL_in_init(s) && !s->in_handshake)
+ {
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_SSL3_WRITE_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ }
+
+ /* ensure that if we end up with a smaller value of data to write
+ * out than the the original len from a write which didn't complete
+ * for non-blocking I/O and also somehow ended up avoiding
+ * the check for this in ssl3_write_pending/SSL_R_BAD_WRITE_RETRY as
+ * it must never be possible to end up with (len-tot) as a large
+ * number that will then promptly send beyond the end of the users
+ * buffer ... so we trap and report the error in a way the user
+ * will notice
+ */
+ if (len < tot)
+ {
+ SSLerr(SSL_F_SSL3_WRITE_BYTES,SSL_R_BAD_LENGTH);
+ return(-1);
+ }
+
+
+ n=(len-tot);
+ for (;;)
+ {
+ if (n > s->max_send_fragment)
+ nw=s->max_send_fragment;
+ else
+ nw=n;
+
+ i=do_ssl3_write(s, type, &(buf[tot]), nw, 0);
+ if (i <= 0)
+ {
+ s->s3->wnum=tot;
+ return i;
+ }
+
+ if ((i == (int)n) ||
+ (type == SSL3_RT_APPLICATION_DATA &&
+ (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)))
+ {
+ /* next chunk of data should get another prepended empty fragment
+ * in ciphersuites with known-IV weakness: */
+ s->s3->empty_fragment_done = 0;
+
+ return tot+i;
+ }
+
+ n-=i;
+ tot+=i;
+ }
+ }
+
+static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ unsigned int len, int create_empty_fragment)
+ {
+ unsigned char *p,*plen;
+ int i,mac_size,clear=0;
+ int prefix_len=0;
+ int eivlen;
+ long align=0;
+ SSL3_RECORD *wr;
+ SSL3_BUFFER *wb=&(s->s3->wbuf);
+ SSL_SESSION *sess;
+
+
+ /* first check if there is a SSL3_BUFFER still being written
+ * out. This will happen with non blocking IO */
+ if (wb->left != 0)
+ return(ssl3_write_pending(s,type,buf,len));
+
+ /* If we have an alert to send, lets send it */
+ if (s->s3->alert_dispatch)
+ {
+ i=s->method->ssl_dispatch_alert(s);
+ if (i <= 0)
+ return(i);
+ /* if it went, fall through and send more stuff */
+ }
+
+ if (wb->buf == NULL)
+ if (!ssl3_setup_write_buffer(s))
+ return -1;
+
+ if (len == 0 && !create_empty_fragment)
+ return 0;
+
+ wr= &(s->s3->wrec);
+ sess=s->session;
+
+ if ( (sess == NULL) ||
+ (s->enc_write_ctx == NULL) ||
+ (EVP_MD_CTX_md(s->write_hash) == NULL))
+ {
+#if 1
+ clear=s->enc_write_ctx?0:1; /* must be AEAD cipher */
+#else
+ clear=1;
+#endif
+ mac_size=0;
+ }
+ else
+ {
+ mac_size=EVP_MD_CTX_size(s->write_hash);
+ if (mac_size < 0)
+ goto err;
+ }
+
+ /* 'create_empty_fragment' is true only when this function calls itself */
+ if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
+ {
+ /* countermeasure against known-IV weakness in CBC ciphersuites
+ * (see http://www.openssl.org/~bodo/tls-cbc.txt) */
+
+ if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
+ {
+ /* recursive function call with 'create_empty_fragment' set;
+ * this prepares and buffers the data for an empty fragment
+ * (these 'prefix_len' bytes are sent out later
+ * together with the actual payload) */
+ prefix_len = do_ssl3_write(s, type, buf, 0, 1);
+ if (prefix_len <= 0)
+ goto err;
+
+ if (prefix_len >
+ (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD))
+ {
+ /* insufficient space */
+ SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ s->s3->empty_fragment_done = 1;
+ }
+
+ if (create_empty_fragment)
+ {
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+ /* extra fragment would be couple of cipher blocks,
+ * which would be multiple of SSL3_ALIGN_PAYLOAD, so
+ * if we want to align the real payload, then we can
+ * just pretent we simply have two headers. */
+ align = (long)wb->buf + 2*SSL3_RT_HEADER_LENGTH;
+ align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+ p = wb->buf + align;
+ wb->offset = align;
+ }
+ else if (prefix_len)
+ {
+ p = wb->buf + wb->offset + prefix_len;
+ }
+ else
+ {
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+ align = (long)wb->buf + SSL3_RT_HEADER_LENGTH;
+ align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+ p = wb->buf + align;
+ wb->offset = align;
+ }
+
+ /* write the header */
+
+ *(p++)=type&0xff;
+ wr->type=type;
+
+ *(p++)=(s->version>>8);
+ /* Some servers hang if iniatial client hello is larger than 256
+ * bytes and record version number > TLS 1.0
+ */
+ if (s->state == SSL3_ST_CW_CLNT_HELLO_B
+ && !s->renegotiate
+ && TLS1_get_version(s) > TLS1_VERSION)
+ *(p++) = 0x1;
+ else
+ *(p++)=s->version&0xff;
+
+ /* field where we are to write out packet length */
+ plen=p;
+ p+=2;
+ /* Explicit IV length, block ciphers and TLS version 1.1 or later */
+ if (s->enc_write_ctx && s->version >= TLS1_1_VERSION)
+ {
+ int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
+ if (mode == EVP_CIPH_CBC_MODE)
+ {
+ eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
+ if (eivlen <= 1)
+ eivlen = 0;
+ }
+ /* Need explicit part of IV for GCM mode */
+ else if (mode == EVP_CIPH_GCM_MODE)
+ eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ else
+ eivlen = 0;
+ }
+ else
+ eivlen = 0;
+
+ /* lets setup the record stuff. */
+ wr->data=p + eivlen;
+ wr->length=(int)len;
+ wr->input=(unsigned char *)buf;
+
+ /* we now 'read' from wr->input, wr->length bytes into
+ * wr->data */
+
+ /* first we compress */
+ if (s->compress != NULL)
+ {
+ if (!ssl3_do_compress(s))
+ {
+ SSLerr(SSL_F_DO_SSL3_WRITE,SSL_R_COMPRESSION_FAILURE);
+ goto err;
+ }
+ }
+ else
+ {
+ memcpy(wr->data,wr->input,wr->length);
+ wr->input=wr->data;
+ }
+
+ /* we should still have the output to wr->data and the input
+ * from wr->input. Length should be wr->length.
+ * wr->data still points in the wb->buf */
+
+ if (mac_size != 0)
+ {
+ if (s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0)
+ goto err;
+ wr->length+=mac_size;
+ }
+
+ wr->input=p;
+ wr->data=p;
+
+ if (eivlen)
+ {
+ /* if (RAND_pseudo_bytes(p, eivlen) <= 0)
+ goto err; */
+ wr->length += eivlen;
+ }
+
+ /* ssl3_enc can only have an error on read */
+ s->method->ssl3_enc->enc(s,1);
+
+ /* record length after mac and block padding */
+ s2n(wr->length,plen);
+
+ /* we should now have
+ * wr->data pointing to the encrypted data, which is
+ * wr->length long */
+ wr->type=type; /* not needed but helps for debugging */
+ wr->length+=SSL3_RT_HEADER_LENGTH;
+
+ if (create_empty_fragment)
+ {
+ /* we are in a recursive call;
+ * just return the length, don't write out anything here
+ */
+ return wr->length;
+ }
+
+ /* now let's set up wb */
+ wb->left = prefix_len + wr->length;
+
+ /* memorize arguments so that ssl3_write_pending can detect bad write retries later */
+ s->s3->wpend_tot=len;
+ s->s3->wpend_buf=buf;
+ s->s3->wpend_type=type;
+ s->s3->wpend_ret=len;
+
+ /* we now just need to write the buffer */
+ return ssl3_write_pending(s,type,buf,len);
+err:
+ return -1;
+ }
+
+/* if s->s3->wbuf.left != 0, we need to call this */
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+ unsigned int len)
+ {
+ int i;
+ SSL3_BUFFER *wb=&(s->s3->wbuf);
+
+/* XXXX */
+ if ((s->s3->wpend_tot > (int)len)
+ || ((s->s3->wpend_buf != buf) &&
+ !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))
+ || (s->s3->wpend_type != type))
+ {
+ SSLerr(SSL_F_SSL3_WRITE_PENDING,SSL_R_BAD_WRITE_RETRY);
+ return(-1);
+ }
+
+ for (;;)
+ {
+ clear_sys_error();
+ if (s->wbio != NULL)
+ {
+ s->rwstate=SSL_WRITING;
+ i=BIO_write(s->wbio,
+ (char *)&(wb->buf[wb->offset]),
+ (unsigned int)wb->left);
+ }
+ else
+ {
+ SSLerr(SSL_F_SSL3_WRITE_PENDING,SSL_R_BIO_NOT_SET);
+ i= -1;
+ }
+ if (i == wb->left)
+ {
+ wb->left=0;
+ wb->offset+=i;
+ if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
+ SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
+ ssl3_release_write_buffer(s);
+ s->rwstate=SSL_NOTHING;
+ return(s->s3->wpend_ret);
+ }
+ else if (i <= 0) {
+ if (s->version == DTLS1_VERSION ||
+ s->version == DTLS1_BAD_VER) {
+ /* For DTLS, just drop it. That's kind of the whole
+ point in using a datagram service */
+ wb->left = 0;
+ }
+ return(i);
+ }
+ wb->offset+=i;
+ wb->left-=i;
+ }
+ }
+
+/* Return up to 'len' payload bytes received in 'type' records.
+ * 'type' is one of the following:
+ *
+ * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
+ * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
+ * - 0 (during a shutdown, no data has to be returned)
+ *
+ * If we don't have stored data to work from, read a SSL/TLS record first
+ * (possibly multiple records if we still don't have anything to return).
+ *
+ * This function must handle any surprises the peer may have for us, such as
+ * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
+ * a surprise, but handled as if it were), or renegotiation requests.
+ * Also if record payloads contain fragments too small to process, we store
+ * them until there is enough for the respective protocol (the record protocol
+ * may use arbitrary fragmentation and even interleaving):
+ * Change cipher spec protocol
+ * just 1 byte needed, no need for keeping anything stored
+ * Alert protocol
+ * 2 bytes needed (AlertLevel, AlertDescription)
+ * Handshake protocol
+ * 4 bytes needed (HandshakeType, uint24 length) -- we just have
+ * to detect unexpected Client Hello and Hello Request messages
+ * here, anything else is handled by higher layers
+ * Application data protocol
+ * none of our business
+ */
+int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
+ {
+ int al,i,j,ret;
+ unsigned int n;
+ SSL3_RECORD *rr;
+ void (*cb)(const SSL *ssl,int type2,int val)=NULL;
+
+ if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
+ if (!ssl3_setup_read_buffer(s))
+ return(-1);
+
+ if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) ||
+ (peek && (type != SSL3_RT_APPLICATION_DATA)))
+ {
+ SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if ((type == SSL3_RT_HANDSHAKE) && (s->s3->handshake_fragment_len > 0))
+ /* (partially) satisfy request from storage */
+ {
+ unsigned char *src = s->s3->handshake_fragment;
+ unsigned char *dst = buf;
+ unsigned int k;
+
+ /* peek == 0 */
+ n = 0;
+ while ((len > 0) && (s->s3->handshake_fragment_len > 0))
+ {
+ *dst++ = *src++;
+ len--; s->s3->handshake_fragment_len--;
+ n++;
+ }
+ /* move any remaining fragment bytes: */
+ for (k = 0; k < s->s3->handshake_fragment_len; k++)
+ s->s3->handshake_fragment[k] = *src++;
+ return n;
+ }
+
+ /* Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
+
+ if (!s->in_handshake && SSL_in_init(s))
+ {
+ /* type == SSL3_RT_APPLICATION_DATA */
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+ }
+start:
+ s->rwstate=SSL_NOTHING;
+
+ /* s->s3->rrec.type - is the type of record
+ * s->s3->rrec.data, - data
+ * s->s3->rrec.off, - offset into 'data' for next read
+ * s->s3->rrec.length, - number of bytes. */
+ rr = &(s->s3->rrec);
+
+ /* get new packet if necessary */
+ if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
+ {
+ ret=ssl3_get_record(s);
+ if (ret <= 0) return(ret);
+ }
+
+ /* we now have a packet which can be read and processed */
+
+ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
+ * reset by ssl3_get_finished */
+ && (rr->type != SSL3_RT_HANDSHAKE))
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
+ goto f_err;
+ }
+
+ /* If the other end has shut down, throw anything we read away
+ * (even in 'peek' mode) */
+ if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+ {
+ rr->length=0;
+ s->rwstate=SSL_NOTHING;
+ return(0);
+ }
+
+
+ if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
+ {
+ /* make sure that we are not getting application data when we
+ * are doing a handshake for the first time */
+ if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
+ (s->enc_read_ctx == NULL))
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE);
+ goto f_err;
+ }
+
+ if (len <= 0) return(len);
+
+ if ((unsigned int)len > rr->length)
+ n = rr->length;
+ else
+ n = (unsigned int)len;
+
+ memcpy(buf,&(rr->data[rr->off]),n);
+ if (!peek)
+ {
+ rr->length-=n;
+ rr->off+=n;
+ if (rr->length == 0)
+ {
+ s->rstate=SSL_ST_READ_HEADER;
+ rr->off=0;
+ if (s->mode & SSL_MODE_RELEASE_BUFFERS && s->s3->rbuf.left == 0)
+ ssl3_release_read_buffer(s);
+ }
+ }
+ return(n);
+ }
+
+
+ /* If we get here, then type != rr->type; if we have a handshake
+ * message, then it was unexpected (Hello Request or Client Hello). */
+
+ /* In case of record types for which we have 'fragment' storage,
+ * fill that so that we can process the data at a fixed place.
+ */
+ {
+ unsigned int dest_maxlen = 0;
+ unsigned char *dest = NULL;
+ unsigned int *dest_len = NULL;
+
+ if (rr->type == SSL3_RT_HANDSHAKE)
+ {
+ dest_maxlen = sizeof s->s3->handshake_fragment;
+ dest = s->s3->handshake_fragment;
+ dest_len = &s->s3->handshake_fragment_len;
+ }
+ else if (rr->type == SSL3_RT_ALERT)
+ {
+ dest_maxlen = sizeof s->s3->alert_fragment;
+ dest = s->s3->alert_fragment;
+ dest_len = &s->s3->alert_fragment_len;
+ }
+#ifndef OPENSSL_NO_HEARTBEATS
+ else if (rr->type == TLS1_RT_HEARTBEAT)
+ {
+ tls1_process_heartbeat(s);
+
+ /* Exit and notify application to read again */
+ rr->length = 0;
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ return(-1);
+ }
+#endif
+
+ if (dest_maxlen > 0)
+ {
+ n = dest_maxlen - *dest_len; /* available space in 'dest' */
+ if (rr->length < n)
+ n = rr->length; /* available bytes */
+
+ /* now move 'n' bytes: */
+ while (n-- > 0)
+ {
+ dest[(*dest_len)++] = rr->data[rr->off++];
+ rr->length--;
+ }
+
+ if (*dest_len < dest_maxlen)
+ goto start; /* fragment was too small */
+ }
+ }
+
+ /* s->s3->handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE;
+ * s->s3->alert_fragment_len == 2 iff rr->type == SSL3_RT_ALERT.
+ * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
+
+ /* If we are a client, check for an incoming 'Hello Request': */
+ if ((!s->server) &&
+ (s->s3->handshake_fragment_len >= 4) &&
+ (s->s3->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
+ (s->session != NULL) && (s->session->cipher != NULL))
+ {
+ s->s3->handshake_fragment_len = 0;
+
+ if ((s->s3->handshake_fragment[1] != 0) ||
+ (s->s3->handshake_fragment[2] != 0) ||
+ (s->s3->handshake_fragment[3] != 0))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
+ goto f_err;
+ }
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->s3->handshake_fragment, 4, s, s->msg_callback_arg);
+
+ if (SSL_is_init_finished(s) &&
+ !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
+ !s->s3->renegotiate)
+ {
+ ssl3_renegotiate(s);
+ if (ssl3_renegotiate_check(s))
+ {
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+
+ if (!(s->mode & SSL_MODE_AUTO_RETRY))
+ {
+ if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ {
+ BIO *bio;
+ /* In the case where we try to read application data,
+ * but we trigger an SSL handshake, we return -1 with
+ * the retry option set. Otherwise renegotiation may
+ * cause nasty problems in the blocking world */
+ s->rwstate=SSL_READING;
+ bio=SSL_get_rbio(s);
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+ }
+ }
+ }
+ /* we either finished a handshake or ignored the request,
+ * now try again to obtain the (application) data we were asked for */
+ goto start;
+ }
+ /* If we are a server and get a client hello when renegotiation isn't
+ * allowed send back a no renegotiation alert and carry on.
+ * WARNING: experimental code, needs reviewing (steve)
+ */
+ if (s->server &&
+ SSL_is_init_finished(s) &&
+ !s->s3->send_connection_binding &&
+ (s->version > SSL3_VERSION) &&
+ (s->s3->handshake_fragment_len >= 4) &&
+ (s->s3->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) &&
+ (s->session != NULL) && (s->session->cipher != NULL) &&
+ !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+
+ {
+ /*s->s3->handshake_fragment_len = 0;*/
+ rr->length = 0;
+ ssl3_send_alert(s,SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
+ goto start;
+ }
+ if (s->s3->alert_fragment_len >= 2)
+ {
+ int alert_level = s->s3->alert_fragment[0];
+ int alert_descr = s->s3->alert_fragment[1];
+
+ s->s3->alert_fragment_len = 0;
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_ALERT, s->s3->alert_fragment, 2, s, s->msg_callback_arg);
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ if (cb != NULL)
+ {
+ j = (alert_level << 8) | alert_descr;
+ cb(s, SSL_CB_READ_ALERT, j);
+ }
+
+ if (alert_level == 1) /* warning */
+ {
+ s->s3->warn_alert = alert_descr;
+ if (alert_descr == SSL_AD_CLOSE_NOTIFY)
+ {
+ s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ return(0);
+ }
+ /* This is a warning but we receive it if we requested
+ * renegotiation and the peer denied it. Terminate with
+ * a fatal alert because if application tried to
+ * renegotiatie it presumably had a good reason and
+ * expects it to succeed.
+ *
+ * In future we might have a renegotiation where we
+ * don't care if the peer refused it where we carry on.
+ */
+ else if (alert_descr == SSL_AD_NO_RENEGOTIATION)
+ {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_NO_RENEGOTIATION);
+ goto f_err;
+ }
+#ifdef SSL_AD_MISSING_SRP_USERNAME
+ else if (alert_descr == SSL_AD_MISSING_SRP_USERNAME)
+ return(0);
+#endif
+ }
+ else if (alert_level == 2) /* fatal */
+ {
+ char tmp[16];
+
+ s->rwstate=SSL_NOTHING;
+ s->s3->fatal_alert = alert_descr;
+ SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);
+ BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
+ ERR_add_error_data(2,"SSL alert number ",tmp);
+ s->shutdown|=SSL_RECEIVED_SHUTDOWN;
+ SSL_CTX_remove_session(s->ctx,s->session);
+ return(0);
+ }
+ else
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE);
+ goto f_err;
+ }
+
+ goto start;
+ }
+
+ if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
+ {
+ s->rwstate=SSL_NOTHING;
+ rr->length=0;
+ return(0);
+ }
+
+ if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+ {
+ /* 'Change Cipher Spec' is just a single byte, so we know
+ * exactly what the record payload has to look like */
+ if ( (rr->length != 1) || (rr->off != 0) ||
+ (rr->data[0] != SSL3_MT_CCS))
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ goto f_err;
+ }
+
+ /* Check we have a cipher to change to */
+ if (s->s3->tmp.new_cipher == NULL)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_CCS_RECEIVED_EARLY);
+ goto f_err;
+ }
+
+ if (!(s->s3->flags & SSL3_FLAGS_CCS_OK))
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_CCS_RECEIVED_EARLY);
+ goto f_err;
+ }
+
+ s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
+
+ rr->length=0;
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
+
+ s->s3->change_cipher_spec=1;
+ if (!ssl3_do_change_cipher_spec(s))
+ goto err;
+ else
+ goto start;
+ }
+
+ /* Unexpected handshake message (Client Hello, or protocol violation) */
+ if ((s->s3->handshake_fragment_len >= 4) && !s->in_handshake)
+ {
+ if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
+ !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
+ {
+#if 0 /* worked only because C operator preferences are not as expected (and
+ * because this is not really needed for clients except for detecting
+ * protocol violations): */
+ s->state=SSL_ST_BEFORE|(s->server)
+ ?SSL_ST_ACCEPT
+ :SSL_ST_CONNECT;
+#else
+ s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
+#endif
+ s->renegotiate=1;
+ s->new_session=1;
+ }
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+
+ if (!(s->mode & SSL_MODE_AUTO_RETRY))
+ {
+ if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ {
+ BIO *bio;
+ /* In the case where we try to read application data,
+ * but we trigger an SSL handshake, we return -1 with
+ * the retry option set. Otherwise renegotiation may
+ * cause nasty problems in the blocking world */
+ s->rwstate=SSL_READING;
+ bio=SSL_get_rbio(s);
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+ }
+ goto start;
+ }
+
+ switch (rr->type)
+ {
+ default:
+#ifndef OPENSSL_NO_TLS
+ /* TLS up to v1.1 just ignores unknown message types:
+ * TLS v1.2 give an unexpected message alert.
+ */
+ if (s->version >= TLS1_VERSION && s->version <= TLS1_1_VERSION)
+ {
+ rr->length = 0;
+ goto start;
+ }
+#endif
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+ goto f_err;
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ case SSL3_RT_ALERT:
+ case SSL3_RT_HANDSHAKE:
+ /* we already handled all of these, with the possible exception
+ * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that
+ * should not happen when type != rr->type */
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ case SSL3_RT_APPLICATION_DATA:
+ /* At this point, we were expecting handshake data,
+ * but have application data. If the library was
+ * running inside ssl3_read() (i.e. in_read_app_data
+ * is set) and it makes sense to read application data
+ * at this point (session renegotiation not yet started),
+ * we will indulge it.
+ */
+ if (s->s3->in_read_app_data &&
+ (s->s3->total_renegotiations != 0) &&
+ ((
+ (s->state & SSL_ST_CONNECT) &&
+ (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
+ (s->state <= SSL3_ST_CR_SRVR_HELLO_A)
+ ) || (
+ (s->state & SSL_ST_ACCEPT) &&
+ (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
+ (s->state >= SSL3_ST_SR_CLNT_HELLO_A)
+ )
+ ))
+ {
+ s->s3->in_read_app_data=2;
+ return(-1);
+ }
+ else
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+ goto f_err;
+ }
+ }
+ /* not reached */
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(-1);
+ }
+
+int ssl3_do_change_cipher_spec(SSL *s)
+ {
+ int i;
+ const char *sender;
+ int slen;
+
+ if (s->state & SSL_ST_ACCEPT)
+ i=SSL3_CHANGE_CIPHER_SERVER_READ;
+ else
+ i=SSL3_CHANGE_CIPHER_CLIENT_READ;
+
+ if (s->s3->tmp.key_block == NULL)
+ {
+ if (s->session == NULL || s->session->master_key_length == 0)
+ {
+ /* might happen if dtls1_read_bytes() calls this */
+ SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC,SSL_R_CCS_RECEIVED_EARLY);
+ return (0);
+ }
+
+ s->session->cipher=s->s3->tmp.new_cipher;
+ if (!s->method->ssl3_enc->setup_key_block(s)) return(0);
+ }
+
+ if (!s->method->ssl3_enc->change_cipher_state(s,i))
+ return(0);
+
+ /* we have to record the message digest at
+ * this point so we can get it before we read
+ * the finished message */
+ if (s->state & SSL_ST_CONNECT)
+ {
+ sender=s->method->ssl3_enc->server_finished_label;
+ slen=s->method->ssl3_enc->server_finished_label_len;
+ }
+ else
+ {
+ sender=s->method->ssl3_enc->client_finished_label;
+ slen=s->method->ssl3_enc->client_finished_label_len;
+ }
+
+ i = s->method->ssl3_enc->final_finish_mac(s,
+ sender,slen,s->s3->tmp.peer_finish_md);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ s->s3->tmp.peer_finish_md_len = i;
+
+ return(1);
+ }
+
+int ssl3_send_alert(SSL *s, int level, int desc)
+ {
+ /* Map tls/ssl alert value to correct one */
+ desc=s->method->ssl3_enc->alert_value(desc);
+ if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
+ desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have protocol_version alerts */
+ if (desc < 0) return -1;
+ /* If a fatal one, remove from cache */
+ if ((level == 2) && (s->session != NULL))
+ SSL_CTX_remove_session(s->ctx,s->session);
+
+ s->s3->alert_dispatch=1;
+ s->s3->send_alert[0]=level;
+ s->s3->send_alert[1]=desc;
+ if (s->s3->wbuf.left == 0) /* data still being written out? */
+ return s->method->ssl_dispatch_alert(s);
+ /* else data is still being written out, we will get written
+ * some time in the future */
+ return -1;
+ }
+
+int ssl3_dispatch_alert(SSL *s)
+ {
+ int i,j;
+ void (*cb)(const SSL *ssl,int type,int val)=NULL;
+
+ s->s3->alert_dispatch=0;
+ i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0);
+ if (i <= 0)
+ {
+ s->s3->alert_dispatch=1;
+ }
+ else
+ {
+ /* Alert sent to BIO. If it is important, flush it now.
+ * If the message does not get sent due to non-blocking IO,
+ * we will not worry too much. */
+ if (s->s3->send_alert[0] == SSL3_AL_FATAL)
+ (void)BIO_flush(s->wbio);
+
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 2, s, s->msg_callback_arg);
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ if (cb != NULL)
+ {
+ j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1];
+ cb(s,SSL_CB_WRITE_ALERT,j);
+ }
+ }
+ return(i);
+ }
diff --git a/drivers/builtin_openssl2/ssl/s3_srvr.c b/drivers/builtin_openssl2/ssl/s3_srvr.c
new file mode 100644
index 0000000000..503bed3fe0
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/s3_srvr.c
@@ -0,0 +1,3594 @@
+/* ssl/s3_srvr.c -*- mode:C; c-file-style: "eay" -*- */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#define REUSE_CIPHER_BUG
+#define NETSCAPE_HANG_BUG
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#include "kssl_lcl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/x509.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_KRB5
+#include <openssl/krb5_asn.h>
+#endif
+#include <openssl/md5.h>
+
+static const SSL_METHOD *ssl3_get_server_method(int ver);
+
+static const SSL_METHOD *ssl3_get_server_method(int ver)
+ {
+ if (ver == SSL3_VERSION)
+ return(SSLv3_server_method());
+ else
+ return(NULL);
+ }
+
+#ifndef OPENSSL_NO_SRP
+static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
+ {
+ int ret = SSL_ERROR_NONE;
+
+ *al = SSL_AD_UNRECOGNIZED_NAME;
+
+ if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
+ (s->srp_ctx.TLS_ext_srp_username_callback != NULL))
+ {
+ if(s->srp_ctx.login == NULL)
+ {
+ /* RFC 5054 says SHOULD reject,
+ we do so if There is no srp login name */
+ ret = SSL3_AL_FATAL;
+ *al = SSL_AD_UNKNOWN_PSK_IDENTITY;
+ }
+ else
+ {
+ ret = SSL_srp_server_param_with_username(s,al);
+ }
+ }
+ return ret;
+ }
+#endif
+
+IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
+ ssl3_accept,
+ ssl_undefined_function,
+ ssl3_get_server_method)
+
+int ssl3_accept(SSL *s)
+ {
+ BUF_MEM *buf;
+ unsigned long alg_k,Time=(unsigned long)time(NULL);
+ void (*cb)(const SSL *ssl,int type,int val)=NULL;
+ int ret= -1;
+ int new_state,state,skip=0;
+
+ RAND_add(&Time,sizeof(Time),0);
+ ERR_clear_error();
+ clear_sys_error();
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ /* init things to blank */
+ s->in_handshake++;
+ if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+
+ if (s->cert == NULL)
+ {
+ SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
+ return(-1);
+ }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
+ for (;;)
+ {
+ state=s->state;
+
+ switch (s->state)
+ {
+ case SSL_ST_RENEGOTIATE:
+ s->renegotiate=1;
+ /* s->state=SSL_ST_ACCEPT; */
+
+ case SSL_ST_BEFORE:
+ case SSL_ST_ACCEPT:
+ case SSL_ST_BEFORE|SSL_ST_ACCEPT:
+ case SSL_ST_OK|SSL_ST_ACCEPT:
+
+ s->server=1;
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+ if ((s->version>>8) != 3)
+ {
+ SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ s->type=SSL_ST_ACCEPT;
+
+ if (s->init_buf == NULL)
+ {
+ if ((buf=BUF_MEM_new()) == NULL)
+ {
+ ret= -1;
+ goto end;
+ }
+ if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+ {
+ ret= -1;
+ goto end;
+ }
+ s->init_buf=buf;
+ }
+
+ if (!ssl3_setup_buffers(s))
+ {
+ ret= -1;
+ goto end;
+ }
+
+ s->init_num=0;
+ s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
+
+ if (s->state != SSL_ST_RENEGOTIATE)
+ {
+ /* Ok, we now need to push on a buffering BIO so that
+ * the output is sent in a way that TCP likes :-)
+ */
+ if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }
+
+ ssl3_init_finished_mac(s);
+ s->state=SSL3_ST_SR_CLNT_HELLO_A;
+ s->ctx->stats.sess_accept++;
+ }
+ else if (!s->s3->send_connection_binding &&
+ !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+ {
+ /* Server attempting to renegotiate with
+ * client that doesn't support secure
+ * renegotiation.
+ */
+ SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+ ret = -1;
+ goto end;
+ }
+ else
+ {
+ /* s->state == SSL_ST_RENEGOTIATE,
+ * we will just send a HelloRequest */
+ s->ctx->stats.sess_accept_renegotiate++;
+ s->state=SSL3_ST_SW_HELLO_REQ_A;
+ }
+ break;
+
+ case SSL3_ST_SW_HELLO_REQ_A:
+ case SSL3_ST_SW_HELLO_REQ_B:
+
+ s->shutdown=0;
+ ret=ssl3_send_hello_request(s);
+ if (ret <= 0) goto end;
+ s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->init_num=0;
+
+ ssl3_init_finished_mac(s);
+ break;
+
+ case SSL3_ST_SW_HELLO_REQ_C:
+ s->state=SSL_ST_OK;
+ break;
+
+ case SSL3_ST_SR_CLNT_HELLO_A:
+ case SSL3_ST_SR_CLNT_HELLO_B:
+ case SSL3_ST_SR_CLNT_HELLO_C:
+
+ s->shutdown=0;
+ if (s->rwstate != SSL_X509_LOOKUP)
+ {
+ ret=ssl3_get_client_hello(s);
+ if (ret <= 0) goto end;
+ }
+#ifndef OPENSSL_NO_SRP
+ {
+ int al;
+ if ((ret = ssl_check_srp_ext_ClientHello(s,&al)) < 0)
+ {
+ /* callback indicates firther work to be done */
+ s->rwstate=SSL_X509_LOOKUP;
+ goto end;
+ }
+ if (ret != SSL_ERROR_NONE)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ /* This is not really an error but the only means to
+ for a client to detect whether srp is supported. */
+ if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
+ SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT);
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ ret= -1;
+ goto end;
+ }
+ }
+#endif
+
+ s->renegotiate = 2;
+ s->state=SSL3_ST_SW_SRVR_HELLO_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_SRVR_HELLO_A:
+ case SSL3_ST_SW_SRVR_HELLO_B:
+ ret=ssl3_send_server_hello(s);
+ if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->hit)
+ {
+ if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_SW_SESSION_TICKET_A;
+ else
+ s->state=SSL3_ST_SW_CHANGE_A;
+ }
+#else
+ if (s->hit)
+ s->state=SSL3_ST_SW_CHANGE_A;
+#endif
+ else
+ s->state=SSL3_ST_SW_CERT_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_A:
+ case SSL3_ST_SW_CERT_B:
+ /* Check if it is anon DH or anon ECDH, */
+ /* normal PSK or KRB5 or SRP */
+ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
+ && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
+ {
+ ret=ssl3_send_server_certificate(s);
+ if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_SW_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+ else
+ {
+ skip = 1;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+#else
+ }
+ else
+ skip=1;
+
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+#endif
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_KEY_EXCH_A:
+ case SSL3_ST_SW_KEY_EXCH_B:
+ alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+ /* clear this, it may get reset by
+ * send_server_key_exchange */
+ if ((s->options & SSL_OP_EPHEMERAL_RSA)
+#ifndef OPENSSL_NO_KRB5
+ && !(alg_k & SSL_kKRB5)
+#endif /* OPENSSL_NO_KRB5 */
+ )
+ /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
+ * even when forbidden by protocol specs
+ * (handshake may fail as clients are not required to
+ * be able to handle this) */
+ s->s3->tmp.use_rsa_tmp=1;
+ else
+ s->s3->tmp.use_rsa_tmp=0;
+
+
+ /* only send if a DH key exchange, fortezza or
+ * RSA but we have a sign only certificate
+ *
+ * PSK: may send PSK identity hints
+ *
+ * For ECC ciphersuites, we send a serverKeyExchange
+ * message only if the cipher suite is either
+ * ECDH-anon or ECDHE. In other cases, the
+ * server certificate contains the server's
+ * public key for key exchange.
+ */
+ if (s->s3->tmp.use_rsa_tmp
+ /* PSK: send ServerKeyExchange if PSK identity
+ * hint if provided */
+#ifndef OPENSSL_NO_PSK
+ || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
+#endif
+#ifndef OPENSSL_NO_SRP
+ /* SRP: send ServerKeyExchange */
+ || (alg_k & SSL_kSRP)
+#endif
+ || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH))
+ || (alg_k & SSL_kEECDH)
+ || ((alg_k & SSL_kRSA)
+ && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
+ || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
+ && EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
+ )
+ )
+ )
+ )
+ {
+ ret=ssl3_send_server_key_exchange(s);
+ if (ret <= 0) goto end;
+ }
+ else
+ skip=1;
+
+ s->state=SSL3_ST_SW_CERT_REQ_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_REQ_A:
+ case SSL3_ST_SW_CERT_REQ_B:
+ if (/* don't request cert unless asked for it: */
+ !(s->verify_mode & SSL_VERIFY_PEER) ||
+ /* if SSL_VERIFY_CLIENT_ONCE is set,
+ * don't request cert during re-negotiation: */
+ ((s->session->peer != NULL) &&
+ (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
+ /* never request cert in anonymous ciphersuites
+ * (see section "Certificate request" in SSL 3 drafts
+ * and in RFC 2246): */
+ ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
+ /* ... except when the application insists on verification
+ * (against the specs, but s3_clnt.c accepts this for SSL 3) */
+ !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
+ /* never request cert in Kerberos ciphersuites */
+ (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
+ /* With normal PSK Certificates and
+ * Certificate Requests are omitted */
+ || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+ {
+ /* no cert request */
+ skip=1;
+ s->s3->tmp.cert_request=0;
+ s->state=SSL3_ST_SW_SRVR_DONE_A;
+ if (s->s3->handshake_buffer)
+ if (!ssl3_digest_cached_records(s))
+ return -1;
+ }
+ else
+ {
+ s->s3->tmp.cert_request=1;
+ ret=ssl3_send_certificate_request(s);
+ if (ret <= 0) goto end;
+#ifndef NETSCAPE_HANG_BUG
+ s->state=SSL3_ST_SW_SRVR_DONE_A;
+#else
+ s->state=SSL3_ST_SW_FLUSH;
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+#endif
+ s->init_num=0;
+ }
+ break;
+
+ case SSL3_ST_SW_SRVR_DONE_A:
+ case SSL3_ST_SW_SRVR_DONE_B:
+ ret=ssl3_send_server_done(s);
+ if (ret <= 0) goto end;
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_FLUSH:
+
+ /* This code originally checked to see if
+ * any data was pending using BIO_CTRL_INFO
+ * and then flushed. This caused problems
+ * as documented in PR#1939. The proposed
+ * fix doesn't completely resolve this issue
+ * as buggy implementations of BIO_CTRL_PENDING
+ * still exist. So instead we just flush
+ * unconditionally.
+ */
+
+ s->rwstate=SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0)
+ {
+ ret= -1;
+ goto end;
+ }
+ s->rwstate=SSL_NOTHING;
+
+ s->state=s->s3->tmp.next_state;
+ break;
+
+ case SSL3_ST_SR_CERT_A:
+ case SSL3_ST_SR_CERT_B:
+ /* Check for second client hello (MS SGC) */
+ ret = ssl3_check_client_hello(s);
+ if (ret <= 0)
+ goto end;
+ if (ret == 2)
+ s->state = SSL3_ST_SR_CLNT_HELLO_C;
+ else {
+ if (s->s3->tmp.cert_request)
+ {
+ ret=ssl3_get_client_certificate(s);
+ if (ret <= 0) goto end;
+ }
+ s->init_num=0;
+ s->state=SSL3_ST_SR_KEY_EXCH_A;
+ }
+ break;
+
+ case SSL3_ST_SR_KEY_EXCH_A:
+ case SSL3_ST_SR_KEY_EXCH_B:
+ ret=ssl3_get_client_key_exchange(s);
+ if (ret <= 0)
+ goto end;
+ if (ret == 2)
+ {
+ /* For the ECDH ciphersuites when
+ * the client sends its ECDH pub key in
+ * a certificate, the CertificateVerify
+ * message is not sent.
+ * Also for GOST ciphersuites when
+ * the client uses its key from the certificate
+ * for key exchange.
+ */
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
+ s->state=SSL3_ST_SR_FINISHED_A;
+#else
+ if (s->s3->next_proto_neg_seen)
+ s->state=SSL3_ST_SR_NEXT_PROTO_A;
+ else
+ s->state=SSL3_ST_SR_FINISHED_A;
+#endif
+ s->init_num = 0;
+ }
+ else if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ s->state=SSL3_ST_SR_CERT_VRFY_A;
+ s->init_num=0;
+ if (!s->session->peer)
+ break;
+ /* For TLS v1.2 freeze the handshake buffer
+ * at this point and digest cached records.
+ */
+ if (!s->s3->handshake_buffer)
+ {
+ SSLerr(SSL_F_SSL3_ACCEPT,ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
+ if (!ssl3_digest_cached_records(s))
+ return -1;
+ }
+ else
+ {
+ int offset=0;
+ int dgst_num;
+
+ s->state=SSL3_ST_SR_CERT_VRFY_A;
+ s->init_num=0;
+
+ /* We need to get hashes here so if there is
+ * a client cert, it can be verified
+ * FIXME - digest processing for CertificateVerify
+ * should be generalized. But it is next step
+ */
+ if (s->s3->handshake_buffer)
+ if (!ssl3_digest_cached_records(s))
+ return -1;
+ for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++)
+ if (s->s3->handshake_dgst[dgst_num])
+ {
+ int dgst_size;
+
+ s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset]));
+ dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
+ if (dgst_size < 0)
+ {
+ ret = -1;
+ goto end;
+ }
+ offset+=dgst_size;
+ }
+ }
+ break;
+
+ case SSL3_ST_SR_CERT_VRFY_A:
+ case SSL3_ST_SR_CERT_VRFY_B:
+
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ /* we should decide if we expected this one */
+ ret=ssl3_get_cert_verify(s);
+ if (ret <= 0) goto end;
+
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
+ s->state=SSL3_ST_SR_FINISHED_A;
+#else
+ if (s->s3->next_proto_neg_seen)
+ s->state=SSL3_ST_SR_NEXT_PROTO_A;
+ else
+ s->state=SSL3_ST_SR_FINISHED_A;
+#endif
+ s->init_num=0;
+ break;
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ case SSL3_ST_SR_NEXT_PROTO_A:
+ case SSL3_ST_SR_NEXT_PROTO_B:
+ ret=ssl3_get_next_proto(s);
+ if (ret <= 0) goto end;
+ s->init_num = 0;
+ s->state=SSL3_ST_SR_FINISHED_A;
+ break;
+#endif
+
+ case SSL3_ST_SR_FINISHED_A:
+ case SSL3_ST_SR_FINISHED_B:
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
+ SSL3_ST_SR_FINISHED_B);
+ if (ret <= 0) goto end;
+ if (s->hit)
+ s->state=SSL_ST_OK;
+#ifndef OPENSSL_NO_TLSEXT
+ else if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_SW_SESSION_TICKET_A;
+#endif
+ else
+ s->state=SSL3_ST_SW_CHANGE_A;
+ s->init_num=0;
+ break;
+
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_SW_SESSION_TICKET_A:
+ case SSL3_ST_SW_SESSION_TICKET_B:
+ ret=ssl3_send_newsession_ticket(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_CHANGE_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_STATUS_A:
+ case SSL3_ST_SW_CERT_STATUS_B:
+ ret=ssl3_send_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+
+#endif
+
+ case SSL3_ST_SW_CHANGE_A:
+ case SSL3_ST_SW_CHANGE_B:
+
+ s->session->cipher=s->s3->tmp.new_cipher;
+ if (!s->method->ssl3_enc->setup_key_block(s))
+ { ret= -1; goto end; }
+
+ ret=ssl3_send_change_cipher_spec(s,
+ SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);
+
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_FINISHED_A;
+ s->init_num=0;
+
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CHANGE_CIPHER_SERVER_WRITE))
+ {
+ ret= -1;
+ goto end;
+ }
+
+ break;
+
+ case SSL3_ST_SW_FINISHED_A:
+ case SSL3_ST_SW_FINISHED_B:
+ ret=ssl3_send_finished(s,
+ SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
+ s->method->ssl3_enc->server_finished_label,
+ s->method->ssl3_enc->server_finished_label_len);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_FLUSH;
+ if (s->hit)
+ {
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
+ s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+#else
+ if (s->s3->next_proto_neg_seen)
+ {
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PROTO_A;
+ }
+ else
+ s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+#endif
+ }
+ else
+ s->s3->tmp.next_state=SSL_ST_OK;
+ s->init_num=0;
+ break;
+
+ case SSL_ST_OK:
+ /* clean a few things up */
+ ssl3_cleanup_key_block(s);
+
+ BUF_MEM_free(s->init_buf);
+ s->init_buf=NULL;
+
+ /* remove buffering on output */
+ ssl_free_wbio_buffer(s);
+
+ s->init_num=0;
+
+ if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
+ {
+ s->renegotiate=0;
+ s->new_session=0;
+
+ ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
+
+ s->ctx->stats.sess_accept_good++;
+ /* s->server=1; */
+ s->handshake_func=ssl3_accept;
+
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+ }
+
+ ret = 1;
+ goto end;
+ /* break; */
+
+ default:
+ SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_UNKNOWN_STATE);
+ ret= -1;
+ goto end;
+ /* break; */
+ }
+
+ if (!s->s3->tmp.reuse_message && !skip)
+ {
+ if (s->debug)
+ {
+ if ((ret=BIO_flush(s->wbio)) <= 0)
+ goto end;
+ }
+
+
+ if ((cb != NULL) && (s->state != state))
+ {
+ new_state=s->state;
+ s->state=state;
+ cb(s,SSL_CB_ACCEPT_LOOP,1);
+ s->state=new_state;
+ }
+ }
+ skip=0;
+ }
+end:
+ /* BIO_flush(s->wbio); */
+
+ s->in_handshake--;
+ if (cb != NULL)
+ cb(s,SSL_CB_ACCEPT_EXIT,ret);
+ return(ret);
+ }
+
+int ssl3_send_hello_request(SSL *s)
+ {
+ unsigned char *p;
+
+ if (s->state == SSL3_ST_SW_HELLO_REQ_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+ *(p++)=SSL3_MT_HELLO_REQUEST;
+ *(p++)=0;
+ *(p++)=0;
+ *(p++)=0;
+
+ s->state=SSL3_ST_SW_HELLO_REQ_B;
+ /* number of bytes to write */
+ s->init_num=4;
+ s->init_off=0;
+ }
+
+ /* SSL3_ST_SW_HELLO_REQ_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int ssl3_check_client_hello(SSL *s)
+ {
+ int ok;
+ long n;
+
+ /* this function is called when we really expect a Certificate message,
+ * so permit appropriate message length */
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_SR_CERT_A,
+ SSL3_ST_SR_CERT_B,
+ -1,
+ s->max_cert_list,
+ &ok);
+ if (!ok) return((int)n);
+ s->s3->tmp.reuse_message = 1;
+ if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
+ {
+ /* We only allow the client to restart the handshake once per
+ * negotiation. */
+ if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS);
+ return -1;
+ }
+ /* Throw away what we have done so far in the current handshake,
+ * which will now be aborted. (A full SSL_clear would be too much.) */
+#ifndef OPENSSL_NO_DH
+ if (s->s3->tmp.dh != NULL)
+ {
+ DH_free(s->s3->tmp.dh);
+ s->s3->tmp.dh = NULL;
+ }
+#endif
+#ifndef OPENSSL_NO_ECDH
+ if (s->s3->tmp.ecdh != NULL)
+ {
+ EC_KEY_free(s->s3->tmp.ecdh);
+ s->s3->tmp.ecdh = NULL;
+ }
+#endif
+ s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
+ return 2;
+ }
+ return 1;
+}
+
+int ssl3_get_client_hello(SSL *s)
+ {
+ int i,j,ok,al,ret= -1;
+ unsigned int cookie_len;
+ long n;
+ unsigned long id;
+ unsigned char *p,*d,*q;
+ SSL_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
+ SSL_COMP *comp=NULL;
+#endif
+ STACK_OF(SSL_CIPHER) *ciphers=NULL;
+
+ /* We do this so that we will respond with our native type.
+ * If we are TLSv1 and we get SSLv3, we will respond with TLSv1,
+ * This down switching should be handled by a different method.
+ * If we are SSLv3, we will respond with SSLv3, even if prompted with
+ * TLSv1.
+ */
+ if (s->state == SSL3_ST_SR_CLNT_HELLO_A
+ )
+ {
+ s->state=SSL3_ST_SR_CLNT_HELLO_B;
+ }
+ s->first_packet=1;
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_SR_CLNT_HELLO_B,
+ SSL3_ST_SR_CLNT_HELLO_C,
+ SSL3_MT_CLIENT_HELLO,
+ SSL3_RT_MAX_PLAIN_LENGTH,
+ &ok);
+
+ if (!ok) return((int)n);
+ s->first_packet=0;
+ d=p=(unsigned char *)s->init_msg;
+
+ /* use version from inside client hello, not from record header
+ * (may differ: see RFC 2246, Appendix E, second paragraph) */
+ s->client_version=(((int)p[0])<<8)|(int)p[1];
+ p+=2;
+
+ if ((s->version == DTLS1_VERSION && s->client_version > s->version) ||
+ (s->version != DTLS1_VERSION && s->client_version < s->version))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
+ if ((s->client_version>>8) == SSL3_VERSION_MAJOR &&
+ !s->enc_write_ctx && !s->write_hash)
+ {
+ /* similar to ssl3_get_record, send alert using remote version number */
+ s->version = s->client_version;
+ }
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+
+ /* If we require cookies and this ClientHello doesn't
+ * contain one, just return since we do not want to
+ * allocate any memory yet. So check cookie length...
+ */
+ if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)
+ {
+ unsigned int session_length, cookie_length;
+
+ session_length = *(p + SSL3_RANDOM_SIZE);
+ cookie_length = *(p + SSL3_RANDOM_SIZE + session_length + 1);
+
+ if (cookie_length == 0)
+ return 1;
+ }
+
+ /* load the client random */
+ memcpy(s->s3->client_random,p,SSL3_RANDOM_SIZE);
+ p+=SSL3_RANDOM_SIZE;
+
+ /* get the session-id */
+ j= *(p++);
+
+ s->hit=0;
+ /* Versions before 0.9.7 always allow clients to resume sessions in renegotiation.
+ * 0.9.7 and later allow this by default, but optionally ignore resumption requests
+ * with flag SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather
+ * than a change to default behavior so that applications relying on this for security
+ * won't even compile against older library versions).
+ *
+ * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to request
+ * renegotiation but not a new session (s->new_session remains unset): for servers,
+ * this essentially just means that the SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ * setting will be ignored.
+ */
+ if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
+ {
+ if (!ssl_get_new_session(s,1))
+ goto err;
+ }
+ else
+ {
+ i=ssl_get_prev_session(s, p, j, d + n);
+ if (i == 1)
+ { /* previous session */
+ s->hit=1;
+ }
+ else if (i == -1)
+ goto err;
+ else /* i == 0 */
+ {
+ if (!ssl_get_new_session(s,1))
+ goto err;
+ }
+ }
+
+ p+=j;
+
+ if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+ {
+ /* cookie stuff */
+ cookie_len = *(p++);
+
+ /*
+ * The ClientHello may contain a cookie even if the
+ * HelloVerify message has not been sent--make sure that it
+ * does not cause an overflow.
+ */
+ if ( cookie_len > sizeof(s->d1->rcvd_cookie))
+ {
+ /* too much data */
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+ goto f_err;
+ }
+
+ /* verify the cookie if appropriate option is set. */
+ if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+ cookie_len > 0)
+ {
+ memcpy(s->d1->rcvd_cookie, p, cookie_len);
+
+ if ( s->ctx->app_verify_cookie_cb != NULL)
+ {
+ if ( s->ctx->app_verify_cookie_cb(s, s->d1->rcvd_cookie,
+ cookie_len) == 0)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
+ SSL_R_COOKIE_MISMATCH);
+ goto f_err;
+ }
+ /* else cookie verification succeeded */
+ }
+ else if ( memcmp(s->d1->rcvd_cookie, s->d1->cookie,
+ s->d1->cookie_len) != 0) /* default verification */
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
+ SSL_R_COOKIE_MISMATCH);
+ goto f_err;
+ }
+
+ ret = 2;
+ }
+
+ p += cookie_len;
+ }
+
+ n2s(p,i);
+ if ((i == 0) && (j != 0))
+ {
+ /* we need a cipher if we are not resuming a session */
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_SPECIFIED);
+ goto f_err;
+ }
+ if ((p+i) >= (d+n))
+ {
+ /* not enough data */
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if ((i > 0) && (ssl_bytes_to_cipher_list(s,p,i,&(ciphers))
+ == NULL))
+ {
+ goto err;
+ }
+ p+=i;
+
+ /* If it is a hit, check that the cipher is in the list */
+ if ((s->hit) && (i > 0))
+ {
+ j=0;
+ id=s->session->cipher->id;
+
+#ifdef CIPHER_DEBUG
+ printf("client sent %d ciphers\n",sk_num(ciphers));
+#endif
+ for (i=0; i<sk_SSL_CIPHER_num(ciphers); i++)
+ {
+ c=sk_SSL_CIPHER_value(ciphers,i);
+#ifdef CIPHER_DEBUG
+ printf("client [%2d of %2d]:%s\n",
+ i,sk_num(ciphers),SSL_CIPHER_get_name(c));
+#endif
+ if (c->id == id)
+ {
+ j=1;
+ break;
+ }
+ }
+/* Disabled because it can be used in a ciphersuite downgrade
+ * attack: CVE-2010-4180.
+ */
+#if 0
+ if (j == 0 && (s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1))
+ {
+ /* Special case as client bug workaround: the previously used cipher may
+ * not be in the current list, the client instead might be trying to
+ * continue using a cipher that before wasn't chosen due to server
+ * preferences. We'll have to reject the connection if the cipher is not
+ * enabled, though. */
+ c = sk_SSL_CIPHER_value(ciphers, 0);
+ if (sk_SSL_CIPHER_find(SSL_get_ciphers(s), c) >= 0)
+ {
+ s->session->cipher = c;
+ j = 1;
+ }
+ }
+#endif
+ if (j == 0)
+ {
+ /* we need to have the cipher in the cipher
+ * list if we are asked to reuse it */
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_REQUIRED_CIPHER_MISSING);
+ goto f_err;
+ }
+ }
+
+ /* compression */
+ i= *(p++);
+ if ((p+i) > (d+n))
+ {
+ /* not enough data */
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ q=p;
+ for (j=0; j<i; j++)
+ {
+ if (p[j] == 0) break;
+ }
+
+ p+=i;
+ if (j >= i)
+ {
+ /* no compress */
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_COMPRESSION_SPECIFIED);
+ goto f_err;
+ }
+
+#ifndef OPENSSL_NO_TLSEXT
+ /* TLS extensions*/
+ if (s->version >= SSL3_VERSION)
+ {
+ if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
+ {
+ /* 'al' set by ssl_parse_clienthello_tlsext */
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
+ goto f_err;
+ }
+ }
+ if (ssl_check_clienthello_tlsext_early(s) <= 0) {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
+
+ /* Check if we want to use external pre-shared secret for this
+ * handshake for not reused session only. We need to generate
+ * server_random before calling tls_session_secret_cb in order to allow
+ * SessionTicket processing to use it in key derivation. */
+ {
+ unsigned char *pos;
+ pos=s->s3->server_random;
+ if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
+#endif
+
+ /* Worst case, we will use the NULL compression, but if we have other
+ * options, we will now look for them. We have i-1 compression
+ * algorithms from the client, starting at q. */
+ s->s3->tmp.new_compression=NULL;
+#ifndef OPENSSL_NO_COMP
+ /* This only happens if we have a cache hit */
+ if (s->session->compress_meth != 0)
+ {
+ int m, comp_id = s->session->compress_meth;
+ /* Perform sanity checks on resumed compression algorithm */
+ /* Can't disable compression */
+ if (s->options & SSL_OP_NO_COMPRESSION)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
+ goto f_err;
+ }
+ /* Look for resumed compression method */
+ for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++)
+ {
+ comp=sk_SSL_COMP_value(s->ctx->comp_methods,m);
+ if (comp_id == comp->id)
+ {
+ s->s3->tmp.new_compression=comp;
+ break;
+ }
+ }
+ if (s->s3->tmp.new_compression == NULL)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INVALID_COMPRESSION_ALGORITHM);
+ goto f_err;
+ }
+ /* Look for resumed method in compression list */
+ for (m = 0; m < i; m++)
+ {
+ if (q[m] == comp_id)
+ break;
+ }
+ if (m >= i)
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING);
+ goto f_err;
+ }
+ }
+ else if (s->hit)
+ comp = NULL;
+ else if (!(s->options & SSL_OP_NO_COMPRESSION) && s->ctx->comp_methods)
+ { /* See if we have a match */
+ int m,nn,o,v,done=0;
+
+ nn=sk_SSL_COMP_num(s->ctx->comp_methods);
+ for (m=0; m<nn; m++)
+ {
+ comp=sk_SSL_COMP_value(s->ctx->comp_methods,m);
+ v=comp->id;
+ for (o=0; o<i; o++)
+ {
+ if (v == q[o])
+ {
+ done=1;
+ break;
+ }
+ }
+ if (done) break;
+ }
+ if (done)
+ s->s3->tmp.new_compression=comp;
+ else
+ comp=NULL;
+ }
+#else
+ /* If compression is disabled we'd better not try to resume a session
+ * using compression.
+ */
+ if (s->session->compress_meth != 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
+ goto f_err;
+ }
+#endif
+
+ /* Given s->session->ciphers and SSL_get_ciphers, we must
+ * pick a cipher */
+
+ if (!s->hit)
+ {
+#ifdef OPENSSL_NO_COMP
+ s->session->compress_meth=0;
+#else
+ s->session->compress_meth=(comp == NULL)?0:comp->id;
+#endif
+ if (s->session->ciphers != NULL)
+ sk_SSL_CIPHER_free(s->session->ciphers);
+ s->session->ciphers=ciphers;
+ if (ciphers == NULL)
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_PASSED);
+ goto f_err;
+ }
+ ciphers=NULL;
+ c=ssl3_choose_cipher(s,s->session->ciphers,
+ SSL_get_ciphers(s));
+
+ if (c == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+ s->s3->tmp.new_cipher=c;
+ }
+ else
+ {
+ /* Session-id reuse */
+#ifdef REUSE_CIPHER_BUG
+ STACK_OF(SSL_CIPHER) *sk;
+ SSL_CIPHER *nc=NULL;
+ SSL_CIPHER *ec=NULL;
+
+ if (s->options & SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG)
+ {
+ sk=s->session->ciphers;
+ for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+ {
+ c=sk_SSL_CIPHER_value(sk,i);
+ if (c->algorithm_enc & SSL_eNULL)
+ nc=c;
+ if (SSL_C_IS_EXPORT(c))
+ ec=c;
+ }
+ if (nc != NULL)
+ s->s3->tmp.new_cipher=nc;
+ else if (ec != NULL)
+ s->s3->tmp.new_cipher=ec;
+ else
+ s->s3->tmp.new_cipher=s->session->cipher;
+ }
+ else
+#endif
+ s->s3->tmp.new_cipher=s->session->cipher;
+ }
+
+ if (TLS1_get_version(s) < TLS1_2_VERSION || !(s->verify_mode & SSL_VERIFY_PEER))
+ {
+ if (!ssl3_digest_cached_records(s))
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ /* we now have the following setup.
+ * client_random
+ * cipher_list - our prefered list of ciphers
+ * ciphers - the clients prefered list of ciphers
+ * compression - basically ignored right now
+ * ssl version is set - sslv3
+ * s->session - The ssl session has been setup.
+ * s->hit - session reuse flag
+ * s->tmp.new_cipher - the new cipher to use.
+ */
+
+ /* Handles TLS extensions that we couldn't check earlier */
+ if (s->version >= SSL3_VERSION)
+ {
+ if (ssl_check_clienthello_tlsext_late(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
+ }
+
+ if (ret < 0) ret=1;
+ if (0)
+ {
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ }
+err:
+ if (ciphers != NULL) sk_SSL_CIPHER_free(ciphers);
+ return(ret);
+ }
+
+int ssl3_send_server_hello(SSL *s)
+ {
+ unsigned char *buf;
+ unsigned char *p,*d;
+ int i,sl;
+ unsigned long l;
+
+ if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ {
+ buf=(unsigned char *)s->init_buf->data;
+#ifdef OPENSSL_NO_TLSEXT
+ p=s->s3->server_random;
+ if (ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE) <= 0)
+ return -1;
+#endif
+ /* Do the message type and length last */
+ d=p= &(buf[4]);
+
+ *(p++)=s->version>>8;
+ *(p++)=s->version&0xff;
+
+ /* Random stuff */
+ memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
+ p+=SSL3_RANDOM_SIZE;
+
+ /* There are several cases for the session ID to send
+ * back in the server hello:
+ * - For session reuse from the session cache,
+ * we send back the old session ID.
+ * - If stateless session reuse (using a session ticket)
+ * is successful, we send back the client's "session ID"
+ * (which doesn't actually identify the session).
+ * - If it is a new session, we send back the new
+ * session ID.
+ * - However, if we want the new session to be single-use,
+ * we send back a 0-length session ID.
+ * s->hit is non-zero in either case of session reuse,
+ * so the following won't overwrite an ID that we're supposed
+ * to send back.
+ */
+ if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
+ && !s->hit)
+ s->session->session_id_length=0;
+
+ sl=s->session->session_id_length;
+ if (sl > (int)sizeof(s->session->session_id))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ *(p++)=sl;
+ memcpy(p,s->session->session_id,sl);
+ p+=sl;
+
+ /* put the cipher */
+ i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
+ p+=i;
+
+ /* put the compression method */
+#ifdef OPENSSL_NO_COMP
+ *(p++)=0;
+#else
+ if (s->s3->tmp.new_compression == NULL)
+ *(p++)=0;
+ else
+ *(p++)=s->s3->tmp.new_compression->id;
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+ if (ssl_prepare_serverhello_tlsext(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
+ return -1;
+ }
+ if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+#endif
+ /* do the header */
+ l=(p-d);
+ d=buf;
+ *(d++)=SSL3_MT_SERVER_HELLO;
+ l2n3(l,d);
+
+ s->state=SSL3_ST_SW_SRVR_HELLO_B;
+ /* number of bytes to write */
+ s->init_num=p-buf;
+ s->init_off=0;
+ }
+
+ /* SSL3_ST_SW_SRVR_HELLO_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int ssl3_send_server_done(SSL *s)
+ {
+ unsigned char *p;
+
+ if (s->state == SSL3_ST_SW_SRVR_DONE_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+
+ /* do the header */
+ *(p++)=SSL3_MT_SERVER_DONE;
+ *(p++)=0;
+ *(p++)=0;
+ *(p++)=0;
+
+ s->state=SSL3_ST_SW_SRVR_DONE_B;
+ /* number of bytes to write */
+ s->init_num=4;
+ s->init_off=0;
+ }
+
+ /* SSL3_ST_SW_SRVR_DONE_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int ssl3_send_server_key_exchange(SSL *s)
+ {
+#ifndef OPENSSL_NO_RSA
+ unsigned char *q;
+ int j,num;
+ RSA *rsa;
+ unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+ unsigned int u;
+#endif
+#ifndef OPENSSL_NO_DH
+ DH *dh=NULL,*dhp;
+#endif
+#ifndef OPENSSL_NO_ECDH
+ EC_KEY *ecdh=NULL, *ecdhp;
+ unsigned char *encodedPoint = NULL;
+ int encodedlen = 0;
+ int curve_id = 0;
+ BN_CTX *bn_ctx = NULL;
+#endif
+ EVP_PKEY *pkey;
+ const EVP_MD *md = NULL;
+ unsigned char *p,*d;
+ int al,i;
+ unsigned long type;
+ int n;
+ CERT *cert;
+ BIGNUM *r[4];
+ int nr[4],kn;
+ BUF_MEM *buf;
+ EVP_MD_CTX md_ctx;
+
+ EVP_MD_CTX_init(&md_ctx);
+ if (s->state == SSL3_ST_SW_KEY_EXCH_A)
+ {
+ type=s->s3->tmp.new_cipher->algorithm_mkey;
+ cert=s->cert;
+
+ buf=s->init_buf;
+
+ r[0]=r[1]=r[2]=r[3]=NULL;
+ n=0;
+#ifndef OPENSSL_NO_RSA
+ if (type & SSL_kRSA)
+ {
+ rsa=cert->rsa_tmp;
+ if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
+ {
+ rsa=s->cert->rsa_tmp_cb(s,
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ if(rsa == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
+ goto f_err;
+ }
+ RSA_up_ref(rsa);
+ cert->rsa_tmp=rsa;
+ }
+ if (rsa == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_KEY);
+ goto f_err;
+ }
+ r[0]=rsa->n;
+ r[1]=rsa->e;
+ s->s3->tmp.use_rsa_tmp=1;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_DH
+ if (type & SSL_kEDH)
+ {
+ dhp=cert->dh_tmp;
+ if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
+ dhp=s->cert->dh_tmp_cb(s,
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ if (dhp == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
+ goto f_err;
+ }
+
+ if (s->s3->tmp.dh != NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if ((dh=DHparams_dup(dhp)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+
+ s->s3->tmp.dh=dh;
+ if ((dhp->pub_key == NULL ||
+ dhp->priv_key == NULL ||
+ (s->options & SSL_OP_SINGLE_DH_USE)))
+ {
+ if(!DH_generate_key(dh))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
+ ERR_R_DH_LIB);
+ goto err;
+ }
+ }
+ else
+ {
+ dh->pub_key=BN_dup(dhp->pub_key);
+ dh->priv_key=BN_dup(dhp->priv_key);
+ if ((dh->pub_key == NULL) ||
+ (dh->priv_key == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+ }
+ r[0]=dh->p;
+ r[1]=dh->g;
+ r[2]=dh->pub_key;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_ECDH
+ if (type & SSL_kEECDH)
+ {
+ const EC_GROUP *group;
+
+ ecdhp=cert->ecdh_tmp;
+ if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+ {
+ ecdhp=s->cert->ecdh_tmp_cb(s,
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ }
+ if (ecdhp == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+ goto f_err;
+ }
+
+ if (s->s3->tmp.ecdh != NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* Duplicate the ECDH structure. */
+ if (ecdhp == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+ if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ s->s3->tmp.ecdh=ecdh;
+ if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
+ (EC_KEY_get0_private_key(ecdh) == NULL) ||
+ (s->options & SSL_OP_SINGLE_ECDH_USE))
+ {
+ if(!EC_KEY_generate_key(ecdh))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+ }
+
+ if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
+ (EC_KEY_get0_public_key(ecdh) == NULL) ||
+ (EC_KEY_get0_private_key(ecdh) == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+ (EC_GROUP_get_degree(group) > 163))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+ goto err;
+ }
+
+ /* XXX: For now, we only support ephemeral ECDH
+ * keys over named (not generic) curves. For
+ * supported named curves, curve_id is non-zero.
+ */
+ if ((curve_id =
+ tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
+ == 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+ goto err;
+ }
+
+ /* Encode the public key.
+ * First check the size of encoding and
+ * allocate memory accordingly.
+ */
+ encodedlen = EC_POINT_point2oct(group,
+ EC_KEY_get0_public_key(ecdh),
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, NULL);
+
+ encodedPoint = (unsigned char *)
+ OPENSSL_malloc(encodedlen*sizeof(unsigned char));
+ bn_ctx = BN_CTX_new();
+ if ((encodedPoint == NULL) || (bn_ctx == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+
+ encodedlen = EC_POINT_point2oct(group,
+ EC_KEY_get0_public_key(ecdh),
+ POINT_CONVERSION_UNCOMPRESSED,
+ encodedPoint, encodedlen, bn_ctx);
+
+ if (encodedlen == 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ BN_CTX_free(bn_ctx); bn_ctx=NULL;
+
+ /* XXX: For now, we only support named (not
+ * generic) curves in ECDH ephemeral key exchanges.
+ * In this situation, we need four additional bytes
+ * to encode the entire ServerECDHParams
+ * structure.
+ */
+ n = 4 + encodedlen;
+
+ /* We'll generate the serverKeyExchange message
+ * explicitly so we can set these to NULLs
+ */
+ r[0]=NULL;
+ r[1]=NULL;
+ r[2]=NULL;
+ r[3]=NULL;
+ }
+ else
+#endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_PSK
+ if (type & SSL_kPSK)
+ {
+ /* reserve size for record length and PSK identity hint*/
+ n+=2+strlen(s->ctx->psk_identity_hint);
+ }
+ else
+#endif /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+ if (type & SSL_kSRP)
+ {
+ if ((s->srp_ctx.N == NULL) ||
+ (s->srp_ctx.g == NULL) ||
+ (s->srp_ctx.s == NULL) ||
+ (s->srp_ctx.B == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_SRP_PARAM);
+ goto err;
+ }
+ r[0]=s->srp_ctx.N;
+ r[1]=s->srp_ctx.g;
+ r[2]=s->srp_ctx.s;
+ r[3]=s->srp_ctx.B;
+ }
+ else
+#endif
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+ goto f_err;
+ }
+ for (i=0; i < 4 && r[i] != NULL; i++)
+ {
+ nr[i]=BN_num_bytes(r[i]);
+#ifndef OPENSSL_NO_SRP
+ if ((i == 2) && (type & SSL_kSRP))
+ n+=1+nr[i];
+ else
+#endif
+ n+=2+nr[i];
+ }
+
+ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+ {
+ if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher,&md))
+ == NULL)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ kn=EVP_PKEY_size(pkey);
+ }
+ else
+ {
+ pkey=NULL;
+ kn=0;
+ }
+
+ if (!BUF_MEM_grow_clean(buf,n+4+kn))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF);
+ goto err;
+ }
+ d=(unsigned char *)s->init_buf->data;
+ p= &(d[4]);
+
+ for (i=0; i < 4 && r[i] != NULL; i++)
+ {
+#ifndef OPENSSL_NO_SRP
+ if ((i == 2) && (type & SSL_kSRP))
+ {
+ *p = nr[i];
+ p++;
+ }
+ else
+#endif
+ s2n(nr[i],p);
+ BN_bn2bin(r[i],p);
+ p+=nr[i];
+ }
+
+#ifndef OPENSSL_NO_ECDH
+ if (type & SSL_kEECDH)
+ {
+ /* XXX: For now, we only support named (not generic) curves.
+ * In this situation, the serverKeyExchange message has:
+ * [1 byte CurveType], [2 byte CurveName]
+ * [1 byte length of encoded point], followed by
+ * the actual encoded point itself
+ */
+ *p = NAMED_CURVE_TYPE;
+ p += 1;
+ *p = 0;
+ p += 1;
+ *p = curve_id;
+ p += 1;
+ *p = encodedlen;
+ p += 1;
+ memcpy((unsigned char*)p,
+ (unsigned char *)encodedPoint,
+ encodedlen);
+ OPENSSL_free(encodedPoint);
+ encodedPoint = NULL;
+ p += encodedlen;
+ }
+#endif
+
+#ifndef OPENSSL_NO_PSK
+ if (type & SSL_kPSK)
+ {
+ /* copy PSK identity hint */
+ s2n(strlen(s->ctx->psk_identity_hint), p);
+ strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
+ p+=strlen(s->ctx->psk_identity_hint);
+ }
+#endif
+
+ /* not anonymous */
+ if (pkey != NULL)
+ {
+ /* n is the length of the params, they start at &(d[4])
+ * and p points to the space at the end. */
+#ifndef OPENSSL_NO_RSA
+ if (pkey->type == EVP_PKEY_RSA
+ && TLS1_get_version(s) < TLS1_2_VERSION)
+ {
+ q=md_buf;
+ j=0;
+ for (num=2; num > 0; num--)
+ {
+ EVP_MD_CTX_set_flags(&md_ctx,
+ EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ EVP_DigestInit_ex(&md_ctx,(num == 2)
+ ?s->ctx->md5:s->ctx->sha1, NULL);
+ EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md_ctx,&(d[4]),n);
+ EVP_DigestFinal_ex(&md_ctx,q,
+ (unsigned int *)&i);
+ q+=i;
+ j+=i;
+ }
+ if (RSA_sign(NID_md5_sha1, md_buf, j,
+ &(p[2]), &u, pkey->pkey.rsa) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
+ goto err;
+ }
+ s2n(u,p);
+ n+=u+2;
+ }
+ else
+#endif
+ if (md)
+ {
+ /* For TLS1.2 and later send signature
+ * algorithm */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ if (!tls12_get_sigandhash(p, pkey, md))
+ {
+ /* Should never happen */
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ }
+ p+=2;
+ }
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Using hash %s\n",
+ EVP_MD_name(md));
+#endif
+ EVP_SignInit_ex(&md_ctx, md, NULL);
+ EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(d[4]),n);
+ if (!EVP_SignFinal(&md_ctx,&(p[2]),
+ (unsigned int *)&i,pkey))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_EVP);
+ goto err;
+ }
+ s2n(i,p);
+ n+=i+2;
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ n+= 2;
+ }
+ else
+ {
+ /* Is this error check actually needed? */
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
+ goto f_err;
+ }
+ }
+
+ *(d++)=SSL3_MT_SERVER_KEY_EXCHANGE;
+ l2n3(n,d);
+
+ /* we should now have things packed up, so lets send
+ * it off */
+ s->init_num=n+4;
+ s->init_off=0;
+ }
+
+ s->state = SSL3_ST_SW_KEY_EXCH_B;
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+#ifndef OPENSSL_NO_ECDH
+ if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+ BN_CTX_free(bn_ctx);
+#endif
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return(-1);
+ }
+
+int ssl3_send_certificate_request(SSL *s)
+ {
+ unsigned char *p,*d;
+ int i,j,nl,off,n;
+ STACK_OF(X509_NAME) *sk=NULL;
+ X509_NAME *name;
+ BUF_MEM *buf;
+
+ if (s->state == SSL3_ST_SW_CERT_REQ_A)
+ {
+ buf=s->init_buf;
+
+ d=p=(unsigned char *)&(buf->data[4]);
+
+ /* get the list of acceptable cert types */
+ p++;
+ n=ssl3_get_req_cert_type(s,p);
+ d[0]=n;
+ p+=n;
+ n++;
+
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ nl = tls12_get_req_sig_algs(s, p + 2);
+ s2n(nl, p);
+ p += nl + 2;
+ n += nl + 2;
+ }
+
+ off=n;
+ p+=2;
+ n+=2;
+
+ sk=SSL_get_client_CA_list(s);
+ nl=0;
+ if (sk != NULL)
+ {
+ for (i=0; i<sk_X509_NAME_num(sk); i++)
+ {
+ name=sk_X509_NAME_value(sk,i);
+ j=i2d_X509_NAME(name,NULL);
+ if (!BUF_MEM_grow_clean(buf,4+n+j+2))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
+ goto err;
+ }
+ p=(unsigned char *)&(buf->data[4+n]);
+ if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
+ {
+ s2n(j,p);
+ i2d_X509_NAME(name,&p);
+ n+=2+j;
+ nl+=2+j;
+ }
+ else
+ {
+ d=p;
+ i2d_X509_NAME(name,&p);
+ j-=2; s2n(j,d); j+=2;
+ n+=j;
+ nl+=j;
+ }
+ }
+ }
+ /* else no CA names */
+ p=(unsigned char *)&(buf->data[4+off]);
+ s2n(nl,p);
+
+ d=(unsigned char *)buf->data;
+ *(d++)=SSL3_MT_CERTIFICATE_REQUEST;
+ l2n3(n,d);
+
+ /* we should now have things packed up, so lets send
+ * it off */
+
+ s->init_num=n+4;
+ s->init_off=0;
+#ifdef NETSCAPE_HANG_BUG
+ if (!BUF_MEM_grow_clean(buf, s->init_num + 4))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
+ goto err;
+ }
+ p=(unsigned char *)s->init_buf->data + s->init_num;
+
+ /* do the header */
+ *(p++)=SSL3_MT_SERVER_DONE;
+ *(p++)=0;
+ *(p++)=0;
+ *(p++)=0;
+ s->init_num += 4;
+#endif
+
+ s->state = SSL3_ST_SW_CERT_REQ_B;
+ }
+
+ /* SSL3_ST_SW_CERT_REQ_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+ return(-1);
+ }
+
+int ssl3_get_client_key_exchange(SSL *s)
+ {
+ int i,al,ok;
+ long n;
+ unsigned long alg_k;
+ unsigned char *p;
+#ifndef OPENSSL_NO_RSA
+ RSA *rsa=NULL;
+ EVP_PKEY *pkey=NULL;
+#endif
+#ifndef OPENSSL_NO_DH
+ BIGNUM *pub=NULL;
+ DH *dh_srvr;
+#endif
+#ifndef OPENSSL_NO_KRB5
+ KSSL_ERR kssl_err;
+#endif /* OPENSSL_NO_KRB5 */
+
+#ifndef OPENSSL_NO_ECDH
+ EC_KEY *srvr_ecdh = NULL;
+ EVP_PKEY *clnt_pub_pkey = NULL;
+ EC_POINT *clnt_ecpoint = NULL;
+ BN_CTX *bn_ctx = NULL;
+#endif
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_SR_KEY_EXCH_A,
+ SSL3_ST_SR_KEY_EXCH_B,
+ SSL3_MT_CLIENT_KEY_EXCHANGE,
+ 2048, /* ??? */
+ &ok);
+
+ if (!ok) return((int)n);
+ p=(unsigned char *)s->init_msg;
+
+ alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+
+#ifndef OPENSSL_NO_RSA
+ if (alg_k & SSL_kRSA)
+ {
+ /* FIX THIS UP EAY EAY EAY EAY */
+ if (s->s3->tmp.use_rsa_tmp)
+ {
+ if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL))
+ rsa=s->cert->rsa_tmp;
+ /* Don't do a callback because rsa_tmp should
+ * be sent already */
+ if (rsa == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_PKEY);
+ goto f_err;
+
+ }
+ }
+ else
+ {
+ pkey=s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
+ if ( (pkey == NULL) ||
+ (pkey->type != EVP_PKEY_RSA) ||
+ (pkey->pkey.rsa == NULL))
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_RSA_CERTIFICATE);
+ goto f_err;
+ }
+ rsa=pkey->pkey.rsa;
+ }
+
+ /* TLS and [incidentally] DTLS{0xFEFF} */
+ if (s->version > SSL3_VERSION && s->version != DTLS1_BAD_VER)
+ {
+ n2s(p,i);
+ if (n != i+2)
+ {
+ if (!(s->options & SSL_OP_TLS_D5_BUG))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
+ goto err;
+ }
+ else
+ p-=2;
+ }
+ else
+ n=i;
+ }
+
+ i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
+
+ al = -1;
+
+ if (i != SSL_MAX_MASTER_KEY_LENGTH)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */
+ }
+
+ if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
+ {
+ /* The premaster secret must contain the same version number as the
+ * ClientHello to detect version rollback attacks (strangely, the
+ * protocol does not offer such protection for DH ciphersuites).
+ * However, buggy clients exist that send the negotiated protocol
+ * version instead if the server does not support the requested
+ * protocol version.
+ * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
+ if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
+ (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
+
+ /* The Klima-Pokorny-Rosa extension of Bleichenbacher's attack
+ * (http://eprint.iacr.org/2003/052/) exploits the version
+ * number check as a "bad version oracle" -- an alert would
+ * reveal that the plaintext corresponding to some ciphertext
+ * made up by the adversary is properly formatted except
+ * that the version number is wrong. To avoid such attacks,
+ * we should treat this just like any other decryption error. */
+ }
+ }
+
+ if (al != -1)
+ {
+ /* Some decryption failure -- use random value instead as countermeasure
+ * against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding
+ * (see RFC 2246, section 7.4.7.1). */
+ ERR_clear_error();
+ i = SSL_MAX_MASTER_KEY_LENGTH;
+ p[0] = s->client_version >> 8;
+ p[1] = s->client_version & 0xff;
+ if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */
+ goto err;
+ }
+
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,
+ p,i);
+ OPENSSL_cleanse(p,i);
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_DH
+ if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+ {
+ n2s(p,i);
+ if (n != i+2)
+ {
+ if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+ goto err;
+ }
+ else
+ {
+ p-=2;
+ i=(int)n;
+ }
+ }
+
+ if (n == 0L) /* the parameters are in the cert */
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_DECODE_DH_CERTS);
+ goto f_err;
+ }
+ else
+ {
+ if (s->s3->tmp.dh == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
+ goto f_err;
+ }
+ else
+ dh_srvr=s->s3->tmp.dh;
+ }
+
+ pub=BN_bin2bn(p,i,NULL);
+ if (pub == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BN_LIB);
+ goto err;
+ }
+
+ i=DH_compute_key(p,pub,dh_srvr);
+
+ if (i <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ BN_clear_free(pub);
+ goto err;
+ }
+
+ DH_free(s->s3->tmp.dh);
+ s->s3->tmp.dh=NULL;
+
+ BN_clear_free(pub);
+ pub=NULL;
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,p,i);
+ OPENSSL_cleanse(p,i);
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_KRB5
+ if (alg_k & SSL_kKRB5)
+ {
+ krb5_error_code krb5rc;
+ krb5_data enc_ticket;
+ krb5_data authenticator;
+ krb5_data enc_pms;
+ KSSL_CTX *kssl_ctx = s->kssl_ctx;
+ EVP_CIPHER_CTX ciph_ctx;
+ const EVP_CIPHER *enc = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH
+ + EVP_MAX_BLOCK_LENGTH];
+ int padl, outl;
+ krb5_timestamp authtime = 0;
+ krb5_ticket_times ttimes;
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+ if (!kssl_ctx) kssl_ctx = kssl_ctx_new();
+
+ n2s(p,i);
+ enc_ticket.length = i;
+
+ if (n < (long)(enc_ticket.length + 6))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto err;
+ }
+
+ enc_ticket.data = (char *)p;
+ p+=enc_ticket.length;
+
+ n2s(p,i);
+ authenticator.length = i;
+
+ if (n < (long)(enc_ticket.length + authenticator.length + 6))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto err;
+ }
+
+ authenticator.data = (char *)p;
+ p+=authenticator.length;
+
+ n2s(p,i);
+ enc_pms.length = i;
+ enc_pms.data = (char *)p;
+ p+=enc_pms.length;
+
+ /* Note that the length is checked again below,
+ ** after decryption
+ */
+ if(enc_pms.length > sizeof pms)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto err;
+ }
+
+ if (n != (long)(enc_ticket.length + authenticator.length +
+ enc_pms.length + 6))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto err;
+ }
+
+ if ((krb5rc = kssl_sget_tkt(kssl_ctx, &enc_ticket, &ttimes,
+ &kssl_err)) != 0)
+ {
+#ifdef KSSL_DEBUG
+ printf("kssl_sget_tkt rtn %d [%d]\n",
+ krb5rc, kssl_err.reason);
+ if (kssl_err.text)
+ printf("kssl_err text= %s\n", kssl_err.text);
+#endif /* KSSL_DEBUG */
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ kssl_err.reason);
+ goto err;
+ }
+
+ /* Note: no authenticator is not considered an error,
+ ** but will return authtime == 0.
+ */
+ if ((krb5rc = kssl_check_authent(kssl_ctx, &authenticator,
+ &authtime, &kssl_err)) != 0)
+ {
+#ifdef KSSL_DEBUG
+ printf("kssl_check_authent rtn %d [%d]\n",
+ krb5rc, kssl_err.reason);
+ if (kssl_err.text)
+ printf("kssl_err text= %s\n", kssl_err.text);
+#endif /* KSSL_DEBUG */
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ kssl_err.reason);
+ goto err;
+ }
+
+ if ((krb5rc = kssl_validate_times(authtime, &ttimes)) != 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, krb5rc);
+ goto err;
+ }
+
+#ifdef KSSL_DEBUG
+ kssl_ctx_show(kssl_ctx);
+#endif /* KSSL_DEBUG */
+
+ enc = kssl_map_enc(kssl_ctx->enctype);
+ if (enc == NULL)
+ goto err;
+
+ memset(iv, 0, sizeof iv); /* per RFC 1510 */
+
+ if (!EVP_DecryptInit_ex(&ciph_ctx,enc,NULL,kssl_ctx->key,iv))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ if (!EVP_DecryptUpdate(&ciph_ctx, pms,&outl,
+ (unsigned char *)enc_pms.data, enc_pms.length))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ if (outl > SSL_MAX_MASTER_KEY_LENGTH)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto err;
+ }
+ if (!EVP_DecryptFinal_ex(&ciph_ctx,&(pms[outl]),&padl))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ outl += padl;
+ if (outl > SSL_MAX_MASTER_KEY_LENGTH)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto err;
+ }
+ if (!((pms[0] == (s->client_version>>8)) && (pms[1] == (s->client_version & 0xff))))
+ {
+ /* The premaster secret must contain the same version number as the
+ * ClientHello to detect version rollback attacks (strangely, the
+ * protocol does not offer such protection for DH ciphersuites).
+ * However, buggy clients exist that send random bytes instead of
+ * the protocol version.
+ * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients.
+ * (Perhaps we should have a separate BUG value for the Kerberos cipher)
+ */
+ if (!(s->options & SSL_OP_TLS_ROLLBACK_BUG))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+ }
+
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key, pms, outl);
+
+ if (kssl_ctx->client_princ)
+ {
+ size_t len = strlen(kssl_ctx->client_princ);
+ if ( len < SSL_MAX_KRB5_PRINCIPAL_LENGTH )
+ {
+ s->session->krb5_client_princ_len = len;
+ memcpy(s->session->krb5_client_princ,kssl_ctx->client_princ,len);
+ }
+ }
+
+
+ /* Was doing kssl_ctx_free() here,
+ ** but it caused problems for apache.
+ ** kssl_ctx = kssl_ctx_free(kssl_ctx);
+ ** if (s->kssl_ctx) s->kssl_ctx = NULL;
+ */
+ }
+ else
+#endif /* OPENSSL_NO_KRB5 */
+
+#ifndef OPENSSL_NO_ECDH
+ if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+ {
+ int ret = 1;
+ int field_size = 0;
+ const EC_KEY *tkey;
+ const EC_GROUP *group;
+ const BIGNUM *priv_key;
+
+ /* initialize structures for server's ECDH key pair */
+ if ((srvr_ecdh = EC_KEY_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Let's get server private key and group information */
+ if (alg_k & (SSL_kECDHr|SSL_kECDHe))
+ {
+ /* use the certificate */
+ tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
+ }
+ else
+ {
+ /* use the ephermeral values we saved when
+ * generating the ServerKeyExchange msg.
+ */
+ tkey = s->s3->tmp.ecdh;
+ }
+
+ group = EC_KEY_get0_group(tkey);
+ priv_key = EC_KEY_get0_private_key(tkey);
+
+ if (!EC_KEY_set_group(srvr_ecdh, group) ||
+ !EC_KEY_set_private_key(srvr_ecdh, priv_key))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
+
+ /* Let's get client's public key */
+ if ((clnt_ecpoint = EC_POINT_new(group)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (n == 0L)
+ {
+ /* Client Publickey was in Client Certificate */
+
+ if (alg_k & SSL_kEECDH)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+ goto f_err;
+ }
+ if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer))
+ == NULL) ||
+ (clnt_pub_pkey->type != EVP_PKEY_EC))
+ {
+ /* XXX: For now, we do not support client
+ * authentication using ECDH certificates
+ * so this branch (n == 0L) of the code is
+ * never executed. When that support is
+ * added, we ought to ensure the key
+ * received in the certificate is
+ * authorized for key agreement.
+ * ECDH_compute_key implicitly checks that
+ * the two ECDH shares are for the same
+ * group.
+ */
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
+ goto f_err;
+ }
+
+ if (EC_POINT_copy(clnt_ecpoint,
+ EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) == 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
+ ret = 2; /* Skip certificate verify processing */
+ }
+ else
+ {
+ /* Get client's public key from encoded point
+ * in the ClientKeyExchange message.
+ */
+ if ((bn_ctx = BN_CTX_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Get encoded point length */
+ i = *p;
+ p += 1;
+ if (n != 1 + i)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
+ if (EC_POINT_oct2point(group,
+ clnt_ecpoint, p, i, bn_ctx) == 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
+ /* p is pointing to somewhere in the buffer
+ * currently, so set it to the start
+ */
+ p=(unsigned char *)s->init_buf->data;
+ }
+
+ /* Compute the shared pre-master secret */
+ field_size = EC_GROUP_get_degree(group);
+ if (field_size <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_ECDH_LIB);
+ goto err;
+ }
+ i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL);
+ if (i <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ EVP_PKEY_free(clnt_pub_pkey);
+ EC_POINT_free(clnt_ecpoint);
+ EC_KEY_free(srvr_ecdh);
+ BN_CTX_free(bn_ctx);
+ EC_KEY_free(s->s3->tmp.ecdh);
+ s->s3->tmp.ecdh = NULL;
+
+ /* Compute the master secret */
+ s->session->master_key_length = s->method->ssl3_enc-> \
+ generate_master_secret(s, s->session->master_key, p, i);
+
+ OPENSSL_cleanse(p, i);
+ return (ret);
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_PSK
+ if (alg_k & SSL_kPSK)
+ {
+ unsigned char *t = NULL;
+ unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
+ unsigned int pre_ms_len = 0, psk_len = 0;
+ int psk_err = 1;
+ char tmp_id[PSK_MAX_IDENTITY_LEN+1];
+
+ al=SSL_AD_HANDSHAKE_FAILURE;
+
+ n2s(p,i);
+ if (n != i+2)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_LENGTH_MISMATCH);
+ goto psk_err;
+ }
+ if (i > PSK_MAX_IDENTITY_LEN)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto psk_err;
+ }
+ if (s->psk_server_callback == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_PSK_NO_SERVER_CB);
+ goto psk_err;
+ }
+
+ /* Create guaranteed NULL-terminated identity
+ * string for the callback */
+ memcpy(tmp_id, p, i);
+ memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+ psk_len = s->psk_server_callback(s, tmp_id,
+ psk_or_pre_ms, sizeof(psk_or_pre_ms));
+ OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1);
+
+ if (psk_len > PSK_MAX_PSK_LEN)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto psk_err;
+ }
+ else if (psk_len == 0)
+ {
+ /* PSK related to the given identity not found */
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_PSK_IDENTITY_NOT_FOUND);
+ al=SSL_AD_UNKNOWN_PSK_IDENTITY;
+ goto psk_err;
+ }
+
+ /* create PSK pre_master_secret */
+ pre_ms_len=2+psk_len+2+psk_len;
+ t = psk_or_pre_ms;
+ memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
+ s2n(psk_len, t);
+ memset(t, 0, psk_len);
+ t+=psk_len;
+ s2n(psk_len, t);
+
+ if (s->session->psk_identity != NULL)
+ OPENSSL_free(s->session->psk_identity);
+ s->session->psk_identity = BUF_strdup((char *)p);
+ if (s->session->psk_identity == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto psk_err;
+ }
+
+ if (s->session->psk_identity_hint != NULL)
+ OPENSSL_free(s->session->psk_identity_hint);
+ s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+ if (s->ctx->psk_identity_hint != NULL &&
+ s->session->psk_identity_hint == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto psk_err;
+ }
+
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key, psk_or_pre_ms, pre_ms_len);
+ psk_err = 0;
+ psk_err:
+ OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
+ if (psk_err != 0)
+ goto f_err;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_SRP
+ if (alg_k & SSL_kSRP)
+ {
+ int param_len;
+
+ n2s(p,i);
+ param_len=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_SRP_A_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.A=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ if (s->session->srp_username != NULL)
+ OPENSSL_free(s->session->srp_username);
+ s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+ if (s->session->srp_username == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((s->session->master_key_length = SRP_generate_server_master_secret(s,s->session->master_key))<0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ p+=i;
+ }
+ else
+#endif /* OPENSSL_NO_SRP */
+ if (alg_k & SSL_kGOST)
+ {
+ int ret = 0;
+ EVP_PKEY_CTX *pkey_ctx;
+ EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
+ unsigned char premaster_secret[32], *start;
+ size_t outlen=32, inlen;
+ unsigned long alg_a;
+ int Ttag, Tclass;
+ long Tlen;
+
+ /* Get our certificate private key*/
+ alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ if (alg_a & SSL_aGOST94)
+ pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey;
+ else if (alg_a & SSL_aGOST01)
+ pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+
+ pkey_ctx = EVP_PKEY_CTX_new(pk,NULL);
+ EVP_PKEY_decrypt_init(pkey_ctx);
+ /* If client certificate is present and is of the same type, maybe
+ * use it for key exchange. Don't mind errors from
+ * EVP_PKEY_derive_set_peer, because it is completely valid to use
+ * a client certificate for authorization only. */
+ client_pub_pkey = X509_get_pubkey(s->session->peer);
+ if (client_pub_pkey)
+ {
+ if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
+ ERR_clear_error();
+ }
+ /* Decrypt session key */
+ if (ASN1_get_object((const unsigned char **)&p, &Tlen, &Ttag, &Tclass, n) != V_ASN1_CONSTRUCTED ||
+ Ttag != V_ASN1_SEQUENCE ||
+ Tclass != V_ASN1_UNIVERSAL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+ goto gerr;
+ }
+ start = p;
+ inlen = Tlen;
+ if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0)
+
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+ goto gerr;
+ }
+ /* Generate master secret */
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,premaster_secret,32);
+ /* Check if pubkey from client certificate was used */
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
+ ret = 2;
+ else
+ ret = 1;
+ gerr:
+ EVP_PKEY_free(client_pub_pkey);
+ EVP_PKEY_CTX_free(pkey_ctx);
+ if (ret)
+ return ret;
+ else
+ goto err;
+ }
+ else
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_UNKNOWN_CIPHER_TYPE);
+ goto f_err;
+ }
+
+ return(1);
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_ECDH) || defined(OPENSSL_NO_SRP)
+err:
+#endif
+#ifndef OPENSSL_NO_ECDH
+ EVP_PKEY_free(clnt_pub_pkey);
+ EC_POINT_free(clnt_ecpoint);
+ if (srvr_ecdh != NULL)
+ EC_KEY_free(srvr_ecdh);
+ BN_CTX_free(bn_ctx);
+#endif
+ return(-1);
+ }
+
+int ssl3_get_cert_verify(SSL *s)
+ {
+ EVP_PKEY *pkey=NULL;
+ unsigned char *p;
+ int al,ok,ret=0;
+ long n;
+ int type=0,i,j;
+ X509 *peer;
+ const EVP_MD *md = NULL;
+ EVP_MD_CTX mctx;
+ EVP_MD_CTX_init(&mctx);
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_SR_CERT_VRFY_A,
+ SSL3_ST_SR_CERT_VRFY_B,
+ -1,
+ 516, /* Enough for 4096 bit RSA key with TLS v1.2 */
+ &ok);
+
+ if (!ok) return((int)n);
+
+ if (s->session->peer != NULL)
+ {
+ peer=s->session->peer;
+ pkey=X509_get_pubkey(peer);
+ type=X509_certificate_type(peer,pkey);
+ }
+ else
+ {
+ peer=NULL;
+ pkey=NULL;
+ }
+
+ if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY)
+ {
+ s->s3->tmp.reuse_message=1;
+ if ((peer != NULL) && (type & EVP_PKT_SIGN))
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_MISSING_VERIFY_MESSAGE);
+ goto f_err;
+ }
+ ret=1;
+ goto end;
+ }
+
+ if (peer == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_NO_CLIENT_CERT_RECEIVED);
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ goto f_err;
+ }
+
+ if (!(type & EVP_PKT_SIGN))
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ goto f_err;
+ }
+
+ if (s->s3->change_cipher_spec)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_CCS_RECEIVED_EARLY);
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ goto f_err;
+ }
+
+ /* we now have a signature that we need to verify */
+ p=(unsigned char *)s->init_msg;
+ /* Check for broken implementations of GOST ciphersuites */
+ /* If key is GOST and n is exactly 64, it is bare
+ * signature without length field */
+ if (n==64 && (pkey->type==NID_id_GostR3410_94 ||
+ pkey->type == NID_id_GostR3410_2001) )
+ {
+ i=64;
+ }
+ else
+ {
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ int sigalg = tls12_get_sigid(pkey);
+ /* Should never happen */
+ if (sigalg == -1)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ /* Check key type is consistent with signature */
+ if (sigalg != (int)p[1])
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_WRONG_SIGNATURE_TYPE);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ md = tls12_get_hash(p[0]);
+ if (md == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_UNKNOWN_DIGEST);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+#ifdef SSL_DEBUG
+fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+ p += 2;
+ n -= 2;
+ }
+ n2s(p,i);
+ n-=2;
+ if (i > n)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ }
+ j=EVP_PKEY_size(pkey);
+ if ((i > j) || (n > j) || (n <= 0))
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_WRONG_SIGNATURE_SIZE);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ long hdatalen = 0;
+ void *hdata;
+ hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+ if (hdatalen <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
+ EVP_MD_name(md));
+#endif
+ if (!EVP_VerifyInit_ex(&mctx, md, NULL)
+ || !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_EVP_LIB);
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+
+ if (EVP_VerifyFinal(&mctx, p , i, pkey) <= 0)
+ {
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_SIGNATURE);
+ goto f_err;
+ }
+ }
+ else
+#ifndef OPENSSL_NO_RSA
+ if (pkey->type == EVP_PKEY_RSA)
+ {
+ i=RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
+ MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH, p, i,
+ pkey->pkey.rsa);
+ if (i < 0)
+ {
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_RSA_DECRYPT);
+ goto f_err;
+ }
+ if (i == 0)
+ {
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_RSA_SIGNATURE);
+ goto f_err;
+ }
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_DSA
+ if (pkey->type == EVP_PKEY_DSA)
+ {
+ j=DSA_verify(pkey->save_type,
+ &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+ SHA_DIGEST_LENGTH,p,i,pkey->pkey.dsa);
+ if (j <= 0)
+ {
+ /* bad signature */
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_DSA_SIGNATURE);
+ goto f_err;
+ }
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (pkey->type == EVP_PKEY_EC)
+ {
+ j=ECDSA_verify(pkey->save_type,
+ &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+ SHA_DIGEST_LENGTH,p,i,pkey->pkey.ec);
+ if (j <= 0)
+ {
+ /* bad signature */
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,
+ SSL_R_BAD_ECDSA_SIGNATURE);
+ goto f_err;
+ }
+ }
+ else
+#endif
+ if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001)
+ { unsigned char signature[64];
+ int idx;
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey,NULL);
+ EVP_PKEY_verify_init(pctx);
+ if (i!=64) {
+ fprintf(stderr,"GOST signature length is %d",i);
+ }
+ for (idx=0;idx<64;idx++) {
+ signature[63-idx]=p[idx];
+ }
+ j=EVP_PKEY_verify(pctx,signature,64,s->s3->tmp.cert_verify_md,32);
+ EVP_PKEY_CTX_free(pctx);
+ if (j<=0)
+ {
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,
+ SSL_R_BAD_ECDSA_SIGNATURE);
+ goto f_err;
+ }
+ }
+ else
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
+ al=SSL_AD_UNSUPPORTED_CERTIFICATE;
+ goto f_err;
+ }
+
+
+ ret=1;
+ if (0)
+ {
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ }
+end:
+ if (s->s3->handshake_buffer)
+ {
+ BIO_free(s->s3->handshake_buffer);
+ s->s3->handshake_buffer = NULL;
+ s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
+ }
+ EVP_MD_CTX_cleanup(&mctx);
+ EVP_PKEY_free(pkey);
+ return(ret);
+ }
+
+int ssl3_get_client_certificate(SSL *s)
+ {
+ int i,ok,al,ret= -1;
+ X509 *x=NULL;
+ unsigned long l,nc,llen,n;
+ const unsigned char *p,*q;
+ unsigned char *d;
+ STACK_OF(X509) *sk=NULL;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_SR_CERT_A,
+ SSL3_ST_SR_CERT_B,
+ -1,
+ s->max_cert_list,
+ &ok);
+
+ if (!ok) return((int)n);
+
+ if (s->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE)
+ {
+ if ( (s->verify_mode & SSL_VERIFY_PEER) &&
+ (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ goto f_err;
+ }
+ /* If tls asked for a client cert, the client must return a 0 list */
+ if ((s->version > SSL3_VERSION) && s->s3->tmp.cert_request)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST);
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ goto f_err;
+ }
+ s->s3->tmp.reuse_message=1;
+ return(1);
+ }
+
+ if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_WRONG_MESSAGE_TYPE);
+ goto f_err;
+ }
+ p=d=(unsigned char *)s->init_msg;
+
+ if ((sk=sk_X509_new_null()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ n2l3(p,llen);
+ if (llen+3 != n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ for (nc=0; nc<llen; )
+ {
+ n2l3(p,l);
+ if ((l+nc+3) > llen)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
+ goto f_err;
+ }
+
+ q=p;
+ x=d2i_X509(NULL,&p,l);
+ if (x == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_ASN1_LIB);
+ goto err;
+ }
+ if (p != (q+l))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if (!sk_X509_push(sk,x))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ x=NULL;
+ nc+=l+3;
+ }
+
+ if (sk_X509_num(sk) <= 0)
+ {
+ /* TLS does not mind 0 certs returned */
+ if (s->version == SSL3_VERSION)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATES_RETURNED);
+ goto f_err;
+ }
+ /* Fail for TLS only if we required a certificate */
+ else if ((s->verify_mode & SSL_VERIFY_PEER) &&
+ (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ goto f_err;
+ }
+ /* No client certificate so digest cached records */
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+ else
+ {
+ i=ssl_verify_cert_chain(s,sk);
+ if (i <= 0)
+ {
+ al=ssl_verify_alarm_type(s->verify_result);
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATE_RETURNED);
+ goto f_err;
+ }
+ }
+
+ if (s->session->peer != NULL) /* This should not be needed */
+ X509_free(s->session->peer);
+ s->session->peer=sk_X509_shift(sk);
+ s->session->verify_result = s->verify_result;
+
+ /* With the current implementation, sess_cert will always be NULL
+ * when we arrive here. */
+ if (s->session->sess_cert == NULL)
+ {
+ s->session->sess_cert = ssl_sess_cert_new();
+ if (s->session->sess_cert == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ if (s->session->sess_cert->cert_chain != NULL)
+ sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free);
+ s->session->sess_cert->cert_chain=sk;
+ /* Inconsistency alert: cert_chain does *not* include the
+ * peer's own certificate, while we do include it in s3_clnt.c */
+
+ sk=NULL;
+
+ ret=1;
+ if (0)
+ {
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ }
+err:
+ if (x != NULL) X509_free(x);
+ if (sk != NULL) sk_X509_pop_free(sk,X509_free);
+ return(ret);
+ }
+
+int ssl3_send_server_certificate(SSL *s)
+ {
+ unsigned long l;
+ X509 *x;
+
+ if (s->state == SSL3_ST_SW_CERT_A)
+ {
+ x=ssl_get_server_send_cert(s);
+ if (x == NULL)
+ {
+ /* VRS: allow null cert if auth == KRB5 */
+ if ((s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5) ||
+ (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR);
+ return(0);
+ }
+ }
+
+ l=ssl3_output_cert_chain(s,x);
+ s->state=SSL3_ST_SW_CERT_B;
+ s->init_num=(int)l;
+ s->init_off=0;
+ }
+
+ /* SSL3_ST_SW_CERT_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+#ifndef OPENSSL_NO_TLSEXT
+/* send a new session ticket (not necessarily for a new session) */
+int ssl3_send_newsession_ticket(SSL *s)
+ {
+ if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
+ {
+ unsigned char *p, *senc, *macstart;
+ const unsigned char *const_p;
+ int len, slen_full, slen;
+ SSL_SESSION *sess;
+ unsigned int hlen;
+ EVP_CIPHER_CTX ctx;
+ HMAC_CTX hctx;
+ SSL_CTX *tctx = s->initial_ctx;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char key_name[16];
+
+ /* get session encoding length */
+ slen_full = i2d_SSL_SESSION(s->session, NULL);
+ /* Some length values are 16 bits, so forget it if session is
+ * too long
+ */
+ if (slen_full > 0xFF00)
+ return -1;
+ senc = OPENSSL_malloc(slen_full);
+ if (!senc)
+ return -1;
+ p = senc;
+ i2d_SSL_SESSION(s->session, &p);
+
+ /* create a fresh copy (not shared with other threads) to clean up */
+ const_p = senc;
+ sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
+ if (sess == NULL)
+ {
+ OPENSSL_free(senc);
+ return -1;
+ }
+ sess->session_id_length = 0; /* ID is irrelevant for the ticket */
+
+ slen = i2d_SSL_SESSION(sess, NULL);
+ if (slen > slen_full) /* shouldn't ever happen */
+ {
+ OPENSSL_free(senc);
+ return -1;
+ }
+ p = senc;
+ i2d_SSL_SESSION(sess, &p);
+ SSL_SESSION_free(sess);
+
+ /* Grow buffer if need be: the length calculation is as
+ * follows 1 (size of message name) + 3 (message length
+ * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) +
+ * 16 (key name) + max_iv_len (iv length) +
+ * session_length + max_enc_block_size (max encrypted session
+ * length) + max_md_size (HMAC).
+ */
+ if (!BUF_MEM_grow(s->init_buf,
+ 26 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH +
+ EVP_MAX_MD_SIZE + slen))
+ return -1;
+
+ p=(unsigned char *)s->init_buf->data;
+ /* do the header */
+ *(p++)=SSL3_MT_NEWSESSION_TICKET;
+ /* Skip message length for now */
+ p += 3;
+ EVP_CIPHER_CTX_init(&ctx);
+ HMAC_CTX_init(&hctx);
+ /* Initialize HMAC and cipher contexts. If callback present
+ * it does all the work otherwise use generated values
+ * from parent ctx.
+ */
+ if (tctx->tlsext_ticket_key_cb)
+ {
+ if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
+ &hctx, 1) < 0)
+ {
+ OPENSSL_free(senc);
+ return -1;
+ }
+ }
+ else
+ {
+ RAND_pseudo_bytes(iv, 16);
+ EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ tctx->tlsext_tick_aes_key, iv);
+ HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+ tlsext_tick_md(), NULL);
+ memcpy(key_name, tctx->tlsext_tick_key_name, 16);
+ }
+
+ /* Ticket lifetime hint (advisory only):
+ * We leave this unspecified for resumed session (for simplicity),
+ * and guess that tickets for new sessions will live as long
+ * as their sessions. */
+ l2n(s->hit ? 0 : s->session->timeout, p);
+
+ /* Skip ticket length for now */
+ p += 2;
+ /* Output key name */
+ macstart = p;
+ memcpy(p, key_name, 16);
+ p += 16;
+ /* output IV */
+ memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
+ p += EVP_CIPHER_CTX_iv_length(&ctx);
+ /* Encrypt session data */
+ EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
+ p += len;
+ EVP_EncryptFinal(&ctx, p, &len);
+ p += len;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ HMAC_Update(&hctx, macstart, p - macstart);
+ HMAC_Final(&hctx, p, &hlen);
+ HMAC_CTX_cleanup(&hctx);
+
+ p += hlen;
+ /* Now write out lengths: p points to end of data written */
+ /* Total length */
+ len = p - (unsigned char *)s->init_buf->data;
+ p=(unsigned char *)s->init_buf->data + 1;
+ l2n3(len - 4, p); /* Message length */
+ p += 4;
+ s2n(len - 10, p); /* Ticket length */
+
+ /* number of bytes to write */
+ s->init_num= len;
+ s->state=SSL3_ST_SW_SESSION_TICKET_B;
+ s->init_off=0;
+ OPENSSL_free(senc);
+ }
+
+ /* SSL3_ST_SW_SESSION_TICKET_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int ssl3_send_cert_status(SSL *s)
+ {
+ if (s->state == SSL3_ST_SW_CERT_STATUS_A)
+ {
+ unsigned char *p;
+ /* Grow buffer if need be: the length calculation is as
+ * follows 1 (message type) + 3 (message length) +
+ * 1 (ocsp response type) + 3 (ocsp response length)
+ * + (ocsp response)
+ */
+ if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen))
+ return -1;
+
+ p=(unsigned char *)s->init_buf->data;
+
+ /* do the header */
+ *(p++)=SSL3_MT_CERTIFICATE_STATUS;
+ /* message length */
+ l2n3(s->tlsext_ocsp_resplen + 4, p);
+ /* status type */
+ *(p++)= s->tlsext_status_type;
+ /* length of OCSP response */
+ l2n3(s->tlsext_ocsp_resplen, p);
+ /* actual response */
+ memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
+ /* number of bytes to write */
+ s->init_num = 8 + s->tlsext_ocsp_resplen;
+ s->state=SSL3_ST_SW_CERT_STATUS_B;
+ s->init_off = 0;
+ }
+
+ /* SSL3_ST_SW_CERT_STATUS_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
+ * sets the next_proto member in s if found */
+int ssl3_get_next_proto(SSL *s)
+ {
+ int ok;
+ int proto_len, padding_len;
+ long n;
+ const unsigned char *p;
+
+ /* Clients cannot send a NextProtocol message if we didn't see the
+ * extension in their ClientHello */
+ if (!s->s3->next_proto_neg_seen)
+ {
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
+ return -1;
+ }
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_SR_NEXT_PROTO_A,
+ SSL3_ST_SR_NEXT_PROTO_B,
+ SSL3_MT_NEXT_PROTO,
+ 514, /* See the payload format below */
+ &ok);
+
+ if (!ok)
+ return((int)n);
+
+ /* s->state doesn't reflect whether ChangeCipherSpec has been received
+ * in this handshake, but s->s3->change_cipher_spec does (will be reset
+ * by ssl3_get_finished). */
+ if (!s->s3->change_cipher_spec)
+ {
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
+ return -1;
+ }
+
+ if (n < 2)
+ return 0; /* The body must be > 1 bytes long */
+
+ p=(unsigned char *)s->init_msg;
+
+ /* The payload looks like:
+ * uint8 proto_len;
+ * uint8 proto[proto_len];
+ * uint8 padding_len;
+ * uint8 padding[padding_len];
+ */
+ proto_len = p[0];
+ if (proto_len + 2 > s->init_num)
+ return 0;
+ padding_len = p[proto_len + 1];
+ if (proto_len + padding_len + 2 != s->init_num)
+ return 0;
+
+ s->next_proto_negotiated = OPENSSL_malloc(proto_len);
+ if (!s->next_proto_negotiated)
+ {
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(s->next_proto_negotiated, p + 1, proto_len);
+ s->next_proto_negotiated_len = proto_len;
+
+ return 1;
+ }
+# endif
+#endif
diff --git a/drivers/builtin_openssl2/ssl/ssl-lib.com b/drivers/builtin_openssl2/ssl/ssl-lib.com
new file mode 100644
index 0000000000..05bda755b5
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/ssl-lib.com
@@ -0,0 +1,1226 @@
+$!
+$! SSL-LIB.COM
+$! Written By: Robert Byer
+$! Vice-President
+$! A-Com Computing, Inc.
+$! byer@mail.all-net.net
+$!
+$! Changes by Richard Levitte <richard@levitte.org>
+$!
+$! This command file compiles and creates the "[.xxx.EXE.SSL]LIBSSL.OLB"
+$! library for OpenSSL. The "xxx" denotes the machine architecture of
+$! ALPHA, IA64 or VAX.
+$!
+$! It is written to detect what type of machine you are compiling on
+$! (i.e. ALPHA or VAX) and which "C" compiler you have (i.e. VAXC, DECC
+$! or GNU C) or you can specify which compiler to use.
+$!
+$! Specify the following as P1 to build just that part or ALL to just
+$! build everything.
+$!
+$! LIBRARY To just compile the [.xxx.EXE.SSL]LIBSSL.OLB Library.
+$! SSL_TASK To just compile the [.xxx.EXE.SSL]SSL_TASK.EXE
+$!
+$! Specify DEBUG or NODEBUG as P2 to compile with or without debugger
+$! information.
+$!
+$! Specify which compiler at P3 to try to compile under.
+$!
+$! VAXC For VAX C.
+$! DECC For DEC C.
+$! GNUC For GNU C.
+$!
+$! If you don't specify a compiler, it will try to determine which
+$! "C" compiler to use.
+$!
+$! P4, if defined, sets a TCP/IP library to use, through one of the following
+$! keywords:
+$!
+$! UCX for UCX
+$! TCPIP for TCPIP (post UCX)
+$! SOCKETSHR for SOCKETSHR+NETLIB
+$!
+$! P5, if defined, sets a compiler thread NOT needed on OpenVMS 7.1 (and up)
+$!
+$! P6, if defined, specifies the C pointer size. Ignored on VAX.
+$! ("64=ARGV" gives more efficient code with HP C V7.3 or newer.)
+$! Supported values are:
+$!
+$! "" Compile with default (/NOPOINTER_SIZE)
+$! 32 Compile with /POINTER_SIZE=32 (SHORT)
+$! 64 Compile with /POINTER_SIZE=64[=ARGV] (LONG[=ARGV])
+$! (Automatically select ARGV if compiler supports it.)
+$! 64= Compile with /POINTER_SIZE=64 (LONG).
+$! 64=ARGV Compile with /POINTER_SIZE=64=ARGV (LONG=ARGV).
+$!
+$! P7, if defined, specifies a directory where ZLIB files (zlib.h,
+$! libz.olb) may be found. Optionally, a non-default object library
+$! name may be included ("dev:[dir]libz_64.olb", for example).
+$!
+$!
+$! Announce/identify.
+$!
+$ proc = f$environment( "procedure")
+$ write sys$output "@@@ "+ -
+ f$parse( proc, , , "name")+ f$parse( proc, , , "type")
+$!
+$! Define A TCP/IP Library That We Will Need To Link To.
+$! (That Is, If We Need To Link To One.)
+$!
+$ TCPIP_LIB = ""
+$ ZLIB_LIB = ""
+$!
+$! Check What Architecture We Are Using.
+$!
+$ IF (F$GETSYI("CPU").LT.128)
+$ THEN
+$!
+$! The Architecture Is VAX.
+$!
+$ ARCH = "VAX"
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! The Architecture Is Alpha, IA64 or whatever comes in the future.
+$!
+$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE")
+$ IF (ARCH .EQS. "") THEN ARCH = "UNK"
+$!
+$! End The Architecture Check.
+$!
+$ ENDIF
+$!
+$ ARCHD = ARCH
+$ LIB32 = "32"
+$ OPT_FILE = ""
+$ POINTER_SIZE = ""
+$!
+$! Check To Make Sure We Have Valid Command Line Parameters.
+$!
+$ GOSUB CHECK_OPTIONS
+$!
+$! Define The OBJ and EXE Directories.
+$!
+$ OBJ_DIR := SYS$DISK:[-.'ARCHD'.OBJ.SSL]
+$ EXE_DIR := SYS$DISK:[-.'ARCHD'.EXE.SSL]
+$!
+$! Specify the destination directory in any /MAP option.
+$!
+$ if (LINKMAP .eqs. "MAP")
+$ then
+$ LINKMAP = LINKMAP+ "=''EXE_DIR'"
+$ endif
+$!
+$! Add the location prefix to the linker options file name.
+$!
+$ if (OPT_FILE .nes. "")
+$ then
+$ OPT_FILE = EXE_DIR+ OPT_FILE
+$ endif
+$!
+$! Initialise logical names and such
+$!
+$ GOSUB INITIALISE
+$!
+$! Tell The User What Kind of Machine We Run On.
+$!
+$ WRITE SYS$OUTPUT "Host system architecture: ''ARCHD'"
+$!
+$! Check To See If The Architecture Specific OBJ Directory Exists.
+$!
+$ IF (F$PARSE(OBJ_DIR).EQS."")
+$ THEN
+$!
+$! It Dosen't Exist, So Create It.
+$!
+$ CREATE/DIR 'OBJ_DIR'
+$!
+$! End The Architecture Specific OBJ Directory Check.
+$!
+$ ENDIF
+$!
+$! Check To See If The Architecture Specific Directory Exists.
+$!
+$ IF (F$PARSE(EXE_DIR).EQS."")
+$ THEN
+$!
+$! It Dosen't Exist, So Create It.
+$!
+$ CREATE/DIR 'EXE_DIR'
+$!
+$! End The Architecture Specific Directory Check.
+$!
+$ ENDIF
+$!
+$! Define The Library Name.
+$!
+$ SSL_LIB := 'EXE_DIR'SSL_LIBSSL'LIB32'.OLB
+$!
+$! Define The CRYPTO-LIB We Are To Use.
+$!
+$ CRYPTO_LIB := SYS$DISK:[-.'ARCHD'.EXE.CRYPTO]SSL_LIBCRYPTO'LIB32'.OLB
+$!
+$! Set up exceptional compilations.
+$!
+$ CC5_SHOWN = 0
+$!
+$! Check To See What We Are To Do.
+$!
+$ IF (BUILDALL.EQS."TRUE")
+$ THEN
+$!
+$! Since Nothing Special Was Specified, Do Everything.
+$!
+$ GOSUB LIBRARY
+$ GOSUB SSL_TASK
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Build Just What The User Wants Us To Build.
+$!
+$ GOSUB 'BUILDALL'
+$!
+$! End The BUILDALL Check.
+$!
+$ ENDIF
+$!
+$! Time To EXIT.
+$!
+$ EXIT:
+$ GOSUB CLEANUP
+$ EXIT
+$!
+$! Compile The Library.
+$!
+$ LIBRARY:
+$!
+$! Check To See If We Already Have A "[.xxx.EXE.SSL]SSL_LIBSSL''LIB32'.OLB" Library...
+$!
+$ IF (F$SEARCH(SSL_LIB).EQS."")
+$ THEN
+$!
+$! Guess Not, Create The Library.
+$!
+$ LIBRARY/CREATE/OBJECT 'SSL_LIB'
+$!
+$! End The Library Exist Check.
+$!
+$ ENDIF
+$!
+$! Define The Different SSL "library" Files.
+$!
+$ LIB_SSL = "s2_meth,s2_srvr,s2_clnt,s2_lib,s2_enc,s2_pkt,"+ -
+ "s3_meth,s3_srvr,s3_clnt,s3_lib,s3_enc,s3_pkt,s3_both,s3_cbc,"+ -
+ "s23_meth,s23_srvr,s23_clnt,s23_lib,s23_pkt,"+ -
+ "t1_meth,t1_srvr,t1_clnt,t1_lib,t1_enc,"+ -
+ "d1_meth,d1_srvr,d1_clnt,d1_lib,d1_pkt,"+ -
+ "d1_both,d1_enc,d1_srtp,"+ -
+ "ssl_lib,ssl_err2,ssl_cert,ssl_sess,"+ -
+ "ssl_ciph,ssl_stat,ssl_rsa,"+ -
+ "ssl_asn1,ssl_txt,ssl_algs,"+ -
+ "bio_ssl,ssl_err,kssl,tls_srp,t1_reneg"
+$!
+$ COMPILEWITH_CC5 = ""
+$!
+$! Tell The User That We Are Compiling The Library.
+$!
+$ WRITE SYS$OUTPUT "Building The ",SSL_LIB," Library."
+$!
+$! Define A File Counter And Set It To "0"
+$!
+$ FILE_COUNTER = 0
+$!
+$! Top Of The File Loop.
+$!
+$ NEXT_FILE:
+$!
+$! O.K, Extract The File Name From The File List.
+$!
+$ FILE_NAME = F$ELEMENT(FILE_COUNTER,",",LIB_SSL)
+$!
+$! Check To See If We Are At The End Of The File List.
+$!
+$ IF (FILE_NAME.EQS.",") THEN GOTO FILE_DONE
+$!
+$! Increment The Counter.
+$!
+$ FILE_COUNTER = FILE_COUNTER + 1
+$!
+$! Create The Source File Name.
+$!
+$ SOURCE_FILE = "SYS$DISK:[]" + FILE_NAME + ".C"
+$!
+$! Create The Object File Name.
+$!
+$ OBJECT_FILE = OBJ_DIR + FILE_NAME + ".OBJ"
+$ ON WARNING THEN GOTO NEXT_FILE
+$!
+$! Check To See If The File We Want To Compile Is Actually There.
+$!
+$ IF (F$SEARCH(SOURCE_FILE).EQS."")
+$ THEN
+$!
+$! Tell The User That The File Dosen't Exist.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The File ",SOURCE_FILE," Dosen't Exist."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Exit The Build.
+$!
+$ EXIT
+$!
+$! End The File Exists Check.
+$!
+$ ENDIF
+$!
+$! Tell The User What File We Are Compiling.
+$!
+$ WRITE SYS$OUTPUT " ",FILE_NAME,".c"
+$!
+$! Compile The File.
+$!
+$ ON ERROR THEN GOTO NEXT_FILE
+$ CC/OBJECT='OBJECT_FILE' 'SOURCE_FILE'
+$!
+$! Add It To The Library.
+$!
+$ LIBRARY/REPLACE/OBJECT 'SSL_LIB' 'OBJECT_FILE'
+$!
+$! Time To Clean Up The Object File.
+$!
+$ DELETE 'OBJECT_FILE';*
+$!
+$! Go Back And Get The Next File Name.
+$!
+$ GOTO NEXT_FILE
+$!
+$! All Done With This Library.
+$!
+$ FILE_DONE:
+$!
+$! Tell The User That We Are All Done.
+$!
+$ WRITE SYS$OUTPUT "Library ",SSL_LIB," Compiled."
+$!
+$! Time To RETURN.
+$!
+$ RETURN
+$ SSL_TASK:
+$!
+$! Check To See If We Have The Proper Libraries.
+$!
+$ GOSUB LIB_CHECK
+$!
+$! Check To See If We Have A Linker Option File.
+$!
+$ GOSUB CHECK_OPT_FILE
+$!
+$! Check To See If The File We Want To Compile Is Actually There.
+$!
+$ IF (F$SEARCH("SYS$DISK:[]SSL_TASK.C").EQS."")
+$ THEN
+$!
+$! Tell The User That The File Dosen't Exist.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The File SSL_TASK.C Dosen't Exist."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Exit The Build.
+$!
+$ EXIT
+$!
+$! End The SSL_TASK.C File Check.
+$!
+$ ENDIF
+$!
+$ COMPILEWITH_CC5 = "" !!! ",ssl_task,"
+$!
+$! Tell The User We Are Creating The SSL_TASK.
+$!
+$! Tell The User We Are Creating The SSL_TASK.
+$!
+$ WRITE SYS$OUTPUT "Creating SSL_TASK OSU HTTP SSL Engine."
+$!
+$! Tell The User What File We Are Compiling.
+$!
+$ FILE_NAME = "ssl_task"
+$ WRITE SYS$OUTPUT " ",FILE_NAME,".c"
+$!
+$! Compile The File.
+$!
+$ ON ERROR THEN GOTO SSL_TASK_END
+$!
+$ FILE_NAME0 = ","+ F$ELEMENT(0,".",FILE_NAME)+ ","
+$ IF COMPILEWITH_CC5 - FILE_NAME0 .NES. COMPILEWITH_CC5
+$ THEN
+$ if (.not. CC5_SHOWN)
+$ then
+$ CC5_SHOWN = 1
+$ write sys$output " \Using special rule (5)"
+$ x = " "+ CC5
+$ write /symbol sys$output x
+$ endif
+$ CC5 /OBJECT='OBJ_DIR''FILE_NAME'.OBJ SYS$DISK:[]'FILE_NAME'.C
+$ ELSE
+$ CC /OBJECT='OBJ_DIR''FILE_NAME'.OBJ SYS$DISK:[]'FILE_NAME'.C
+$ ENDIF
+$!
+$! Link The Program.
+$!
+$ LINK /'DEBUGGER' /'LINKMAP' /'TRACEBACK' /EXE='EXE_DIR'SSL_TASK.EXE -
+ 'OBJ_DIR'SSL_TASK.OBJ, -
+ 'SSL_LIB'/LIBRARY, -
+ 'CRYPTO_LIB'/LIBRARY -
+ 'TCPIP_LIB' -
+ 'ZLIB_LIB' -
+ ,'OPT_FILE' /OPTIONS
+$!
+$! Time To Return.
+$!
+$SSL_TASK_END:
+$ RETURN
+$!
+$! Check For The Link Option FIle.
+$!
+$ CHECK_OPT_FILE:
+$!
+$! Check To See If We Need To Make A VAX C Option File.
+$!
+$ IF (COMPILER.EQS."VAXC")
+$ THEN
+$!
+$! Check To See If We Already Have A VAX C Linker Option File.
+$!
+$ IF (F$SEARCH(OPT_FILE).EQS."")
+$ THEN
+$!
+$! We Need A VAX C Linker Option File.
+$!
+$ CREATE 'OPT_FILE'
+$DECK
+!
+! Default System Options File To Link Against
+! The Sharable VAX C Runtime Library.
+!
+SYS$SHARE:VAXCRTL.EXE/SHARE
+$EOD
+$!
+$! End The Option File Check.
+$!
+$ ENDIF
+$!
+$! End The VAXC Check.
+$!
+$ ENDIF
+$!
+$! Check To See If We Need A GNU C Option File.
+$!
+$ IF (COMPILER.EQS."GNUC")
+$ THEN
+$!
+$! Check To See If We Already Have A GNU C Linker Option File.
+$!
+$ IF (F$SEARCH(OPT_FILE).EQS."")
+$ THEN
+$!
+$! We Need A GNU C Linker Option File.
+$!
+$ CREATE 'OPT_FILE'
+$DECK
+!
+! Default System Options File To Link Against
+! The Sharable C Runtime Library.
+!
+GNU_CC:[000000]GCCLIB/LIBRARY
+SYS$SHARE:VAXCRTL/SHARE
+$EOD
+$!
+$! End The Option File Check.
+$!
+$ ENDIF
+$!
+$! End The GNU C Check.
+$!
+$ ENDIF
+$!
+$! Check To See If We Need A DEC C Option File.
+$!
+$ IF (COMPILER.EQS."DECC")
+$ THEN
+$!
+$! Check To See If We Already Have A DEC C Linker Option File.
+$!
+$ IF (F$SEARCH(OPT_FILE).EQS."")
+$ THEN
+$!
+$! Figure Out If We Need A non-VAX Or A VAX Linker Option File.
+$!
+$ IF (ARCH.EQS."VAX")
+$ THEN
+$!
+$! We Need A DEC C Linker Option File For VAX.
+$!
+$ CREATE 'OPT_FILE'
+$DECK
+!
+! Default System Options File To Link Against
+! The Sharable DEC C Runtime Library.
+!
+SYS$SHARE:DECC$SHR.EXE/SHARE
+$EOD
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Create The non-VAX Linker Option File.
+$!
+$ CREATE 'OPT_FILE'
+$DECK
+!
+! Default System Options File For non-VAX To Link Against
+! The Sharable C Runtime Library.
+!
+SYS$SHARE:CMA$OPEN_LIB_SHR/SHARE
+SYS$SHARE:CMA$OPEN_RTL/SHARE
+$EOD
+$!
+$! End The DEC C Option File Check.
+$!
+$ ENDIF
+$!
+$! End The Option File Search.
+$!
+$ ENDIF
+$!
+$! End The DEC C Check.
+$!
+$ ENDIF
+$!
+$! Tell The User What Linker Option File We Are Using.
+$!
+$ WRITE SYS$OUTPUT "Using Linker Option File ",OPT_FILE,"."
+$!
+$! Time To RETURN.
+$!
+$ RETURN
+$ LIB_CHECK:
+$!
+$! Look For The VAX Library LIBSSL.OLB.
+$!
+$ IF (F$SEARCH(SSL_LIB).EQS."")
+$ THEN
+$!
+$! Tell The User We Can't Find The LIBSSL.OLB Library.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "Can't Find The Library ",SSL_LIB,"."
+$ WRITE SYS$OUTPUT "We Can't Link Without It."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Since We Can't Link Without It, Exit.
+$!
+$ EXIT
+$!
+$! End The LIBSSL.OLB Library Check.
+$!
+$ ENDIF
+$!
+$! Look For The Library LIBCRYPTO.OLB.
+$!
+$ IF (F$SEARCH(CRYPTO_LIB).EQS."")
+$ THEN
+$!
+$! Tell The User We Can't Find The LIBCRYPTO.OLB Library.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "Can't Find The Library ",CRYPTO_LIB,"."
+$ WRITE SYS$OUTPUT "We Can't Link Without It."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Since We Can't Link Without It, Exit.
+$!
+$ EXIT
+$!
+$! End The LIBCRYPTO.OLB Library Check.
+$!
+$ ENDIF
+$!
+$! Time To Return.
+$!
+$ RETURN
+$!
+$! Check The User's Options.
+$!
+$ CHECK_OPTIONS:
+$!
+$! Check To See If P1 Is Blank.
+$!
+$ IF (P1.EQS."ALL")
+$ THEN
+$!
+$! P1 Is Blank, So Build Everything.
+$!
+$ BUILDALL = "TRUE"
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Else, Check To See If P1 Has A Valid Argument.
+$!
+$ IF (P1.EQS."LIBRARY").OR.(P1.EQS."SSL_TASK")
+$ THEN
+$!
+$! A Valid Argument.
+$!
+$ BUILDALL = P1
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Tell The User We Don't Know What They Want.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P1," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " ALL : Just Build Everything."
+$ WRITE SYS$OUTPUT " LIBRARY : To Compile Just The [.xxx.EXE.SSL]LIBSSL.OLB Library."
+$ WRITE SYS$OUTPUT " SSL_TASK : To Compile Just The [.xxx.EXE.SSL]SSL_TASK.EXE Program."
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " Where 'xxx' Stands For:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " ALPHA[64]: Alpha Architecture."
+$ WRITE SYS$OUTPUT " IA64[64] : IA64 Architecture."
+$ WRITE SYS$OUTPUT " VAX : VAX Architecture."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$!
+$! End The Valid Argument Check.
+$!
+$ ENDIF
+$!
+$! End The P1 Check.
+$!
+$ ENDIF
+$!
+$! Check To See If P2 Is Blank.
+$!
+$ IF (P2.EQS."NODEBUG")
+$ THEN
+$!
+$! P2 Is NODEBUG, So Compile Without Debugger Information.
+$!
+$ DEBUGGER = "NODEBUG"
+$ LINKMAP = "NOMAP"
+$ TRACEBACK = "NOTRACEBACK"
+$ GCC_OPTIMIZE = "OPTIMIZE"
+$ CC_OPTIMIZE = "OPTIMIZE"
+$ WRITE SYS$OUTPUT "No Debugger Information Will Be Produced During Compile."
+$ WRITE SYS$OUTPUT "Compiling With Compiler Optimization."
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Check To See If We Are To Compile With Debugger Information.
+$!
+$ IF (P2.EQS."DEBUG")
+$ THEN
+$!
+$! Compile With Debugger Information.
+$!
+$ DEBUGGER = "DEBUG"
+$ LINKMAP = "MAP"
+$ TRACEBACK = "TRACEBACK"
+$ GCC_OPTIMIZE = "NOOPTIMIZE"
+$ CC_OPTIMIZE = "NOOPTIMIZE"
+$ WRITE SYS$OUTPUT "Debugger Information Will Be Produced During Compile."
+$ WRITE SYS$OUTPUT "Compiling Without Compiler Optimization."
+$ ELSE
+$!
+$! Tell The User Entered An Invalid Option.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P2," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " DEBUG : Compile With The Debugger Information."
+$ WRITE SYS$OUTPUT " NODEBUG : Compile Without The Debugger Information."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$!
+$! End The Valid Argument Check.
+$!
+$ ENDIF
+$!
+$! End The P2 Check.
+$!
+$ ENDIF
+$!
+$! Special Threads For OpenVMS v7.1 Or Later
+$!
+$! Written By: Richard Levitte
+$! richard@levitte.org
+$!
+$!
+$! Check To See If We Have A Option For P5.
+$!
+$ IF (P5.EQS."")
+$ THEN
+$!
+$! Get The Version Of VMS We Are Using.
+$!
+$ ISSEVEN :=
+$ TMP = F$ELEMENT(0,"-",F$EXTRACT(1,4,F$GETSYI("VERSION")))
+$ TMP = F$INTEGER(F$ELEMENT(0,".",TMP)+F$ELEMENT(1,".",TMP))
+$!
+$! Check To See If The VMS Version Is v7.1 Or Later.
+$!
+$ IF (TMP.GE.71)
+$ THEN
+$!
+$! We Have OpenVMS v7.1 Or Later, So Use The Special Threads.
+$!
+$ ISSEVEN := ,PTHREAD_USE_D4
+$!
+$! End The VMS Version Check.
+$!
+$ ENDIF
+$!
+$! End The P5 Check.
+$!
+$ ENDIF
+$!
+$! Check P6 (POINTER_SIZE).
+$!
+$ IF (P6 .NES. "") .AND. (ARCH .NES. "VAX")
+$ THEN
+$!
+$ IF (P6 .EQS. "32")
+$ THEN
+$ POINTER_SIZE = " /POINTER_SIZE=32"
+$ ELSE
+$ POINTER_SIZE = F$EDIT( P6, "COLLAPSE, UPCASE")
+$ IF ((POINTER_SIZE .EQS. "64") .OR. -
+ (POINTER_SIZE .EQS. "64=") .OR. -
+ (POINTER_SIZE .EQS. "64=ARGV"))
+$ THEN
+$ ARCHD = ARCH+ "_64"
+$ LIB32 = ""
+$ POINTER_SIZE = " /POINTER_SIZE=64"
+$ ELSE
+$!
+$! Tell The User Entered An Invalid Option.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ", P6, -
+ " Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT -
+ " """" : Compile with default (short) pointers."
+$ WRITE SYS$OUTPUT -
+ " 32 : Compile with 32-bit (short) pointers."
+$ WRITE SYS$OUTPUT -
+ " 64 : Compile with 64-bit (long) pointers (auto ARGV)."
+$ WRITE SYS$OUTPUT -
+ " 64= : Compile with 64-bit (long) pointers (no ARGV)."
+$ WRITE SYS$OUTPUT -
+ " 64=ARGV : Compile with 64-bit (long) pointers (ARGV)."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$!
+$ ENDIF
+$!
+$ ENDIF
+$!
+$! End The P6 (POINTER_SIZE) Check.
+$!
+$ ENDIF
+$!
+$! Set basic C compiler /INCLUDE directories.
+$!
+$ CC_INCLUDES = "SYS$DISK:[-.CRYPTO],SYS$DISK:[-]"
+$!
+$! Check To See If P3 Is Blank.
+$!
+$ IF (P3.EQS."")
+$ THEN
+$!
+$! O.K., The User Didn't Specify A Compiler, Let's Try To
+$! Find Out Which One To Use.
+$!
+$! Check To See If We Have GNU C.
+$!
+$ IF (F$TRNLNM("GNU_CC").NES."")
+$ THEN
+$!
+$! Looks Like GNUC, Set To Use GNUC.
+$!
+$ P3 = "GNUC"
+$!
+$! End The GNU C Compiler Check.
+$!
+$ ELSE
+$!
+$! Check To See If We Have VAXC Or DECC.
+$!
+$ IF (ARCH.NES."VAX").OR.(F$TRNLNM("DECC$CC_DEFAULT").NES."")
+$ THEN
+$!
+$! Looks Like DECC, Set To Use DECC.
+$!
+$ P3 = "DECC"
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Looks Like VAXC, Set To Use VAXC.
+$!
+$ P3 = "VAXC"
+$!
+$! End The VAXC Compiler Check.
+$!
+$ ENDIF
+$!
+$! End The DECC & VAXC Compiler Check.
+$!
+$ ENDIF
+$!
+$! End The Compiler Check.
+$!
+$ ENDIF
+$!
+$! Check To See If We Have A Option For P4.
+$!
+$ IF (P4.EQS."")
+$ THEN
+$!
+$! Find out what socket library we have available
+$!
+$ IF F$PARSE("SOCKETSHR:") .NES. ""
+$ THEN
+$!
+$! We have SOCKETSHR, and it is my opinion that it's the best to use.
+$!
+$ P4 = "SOCKETSHR"
+$!
+$! Tell the user
+$!
+$ WRITE SYS$OUTPUT "Using SOCKETSHR for TCP/IP"
+$!
+$! Else, let's look for something else
+$!
+$ ELSE
+$!
+$! Like UCX (the reason to do this before Multinet is that the UCX
+$! emulation is easier to use...)
+$!
+$ IF F$TRNLNM("UCX$IPC_SHR") .NES. "" -
+ .OR. F$PARSE("SYS$SHARE:UCX$IPC_SHR.EXE") .NES. "" -
+ .OR. F$PARSE("SYS$LIBRARY:UCX$IPC.OLB") .NES. ""
+$ THEN
+$!
+$! Last resort: a UCX or UCX-compatible library
+$!
+$ P4 = "UCX"
+$!
+$! Tell the user
+$!
+$ WRITE SYS$OUTPUT "Using UCX or an emulation thereof for TCP/IP"
+$!
+$! That was all...
+$!
+$ ENDIF
+$ ENDIF
+$ ENDIF
+$!
+$! Set Up Initial CC Definitions, Possibly With User Ones
+$!
+$ CCDEFS = "TCPIP_TYPE_''P4'"
+$ IF F$TYPE(USER_CCDEFS) .NES. "" THEN CCDEFS = CCDEFS + "," + USER_CCDEFS
+$ CCEXTRAFLAGS = ""
+$ IF F$TYPE(USER_CCFLAGS) .NES. "" THEN CCEXTRAFLAGS = USER_CCFLAGS
+$ CCDISABLEWARNINGS = "" !!! "MAYLOSEDATA3" !!! "LONGLONGTYPE,LONGLONGSUFX,FOUNDCR"
+$ IF F$TYPE(USER_CCDISABLEWARNINGS) .NES. "" THEN -
+ CCDISABLEWARNINGS = CCDISABLEWARNINGS + "," + USER_CCDISABLEWARNINGS
+$!
+$! Check To See If We Have A ZLIB Option.
+$!
+$ ZLIB = P7
+$ IF (ZLIB .NES. "")
+$ THEN
+$!
+$! Check for expected ZLIB files.
+$!
+$ err = 0
+$ file1 = f$parse( "zlib.h", ZLIB, , , "SYNTAX_ONLY")
+$ if (f$search( file1) .eqs. "")
+$ then
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ", ZLIB, " Is Invalid."
+$ WRITE SYS$OUTPUT " Can't find header: ''file1'"
+$ err = 1
+$ endif
+$ file1 = f$parse( "A.;", ZLIB)- "A.;"
+$!
+$ file2 = f$parse( ZLIB, "libz.olb", , , "SYNTAX_ONLY")
+$ if (f$search( file2) .eqs. "")
+$ then
+$ if (err .eq. 0)
+$ then
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ", ZLIB, " Is Invalid."
+$ endif
+$ WRITE SYS$OUTPUT " Can't find library: ''file2'"
+$ WRITE SYS$OUTPUT ""
+$ err = err+ 2
+$ endif
+$ if (err .eq. 1)
+$ then
+$ WRITE SYS$OUTPUT ""
+$ endif
+$!
+$ if (err .ne. 0)
+$ then
+$ EXIT
+$ endif
+$!
+$ CCDEFS = """ZLIB=1"", "+ CCDEFS
+$ CC_INCLUDES = CC_INCLUDES+ ", "+ file1
+$ ZLIB_LIB = ", ''file2' /library"
+$!
+$! Print info
+$!
+$ WRITE SYS$OUTPUT "ZLIB library spec: ", file2
+$!
+$! End The ZLIB Check.
+$!
+$ ENDIF
+$!
+$! Check To See If The User Entered A Valid Parameter.
+$!
+$ IF (P3.EQS."VAXC").OR.(P3.EQS."DECC").OR.(P3.EQS."GNUC")
+$ THEN
+$!
+$! Check To See If The User Wanted DECC.
+$!
+$ IF (P3.EQS."DECC")
+$ THEN
+$!
+$! Looks Like DECC, Set To Use DECC.
+$!
+$ COMPILER = "DECC"
+$!
+$! Tell The User We Are Using DECC.
+$!
+$ WRITE SYS$OUTPUT "Using DECC 'C' Compiler."
+$!
+$! Use DECC...
+$!
+$ CC = "CC"
+$ IF ARCH.EQS."VAX" .AND. F$TRNLNM("DECC$CC_DEFAULT").NES."/DECC" -
+ THEN CC = "CC/DECC"
+$ CC = CC + " /''CC_OPTIMIZE' /''DEBUGGER' /STANDARD=RELAXED"+ -
+ "''POINTER_SIZE' /NOLIST /PREFIX=ALL" + -
+ " /INCLUDE=(''CC_INCLUDES') " + CCEXTRAFLAGS
+$!
+$! Define The Linker Options File Name.
+$!
+$ OPT_FILE = "VAX_DECC_OPTIONS.OPT"
+$!
+$! End DECC Check.
+$!
+$ ENDIF
+$!
+$! Check To See If We Are To Use VAXC.
+$!
+$ IF (P3.EQS."VAXC")
+$ THEN
+$!
+$! Looks Like VAXC, Set To Use VAXC.
+$!
+$ COMPILER = "VAXC"
+$!
+$! Tell The User We Are Using VAX C.
+$!
+$ WRITE SYS$OUTPUT "Using VAXC 'C' Compiler."
+$!
+$! Compile Using VAXC.
+$!
+$ CC = "CC"
+$ IF ARCH.NES."VAX"
+$ THEN
+$ WRITE SYS$OUTPUT "There is no VAX C on ''ARCH'!"
+$ EXIT
+$ ENDIF
+$ IF F$TRNLNM("DECC$CC_DEFAULT").EQS."/DECC" THEN CC = "CC/VAXC"
+$ CC = CC + "/''CC_OPTIMIZE'/''DEBUGGER'/NOLIST" + -
+ "/INCLUDE=(''CC_INCLUDES')" + CCEXTRAFLAGS
+$ CCDEFS = CCDEFS + ",""VAXC"""
+$!
+$! Define <sys> As SYS$COMMON:[SYSLIB]
+$!
+$ DEFINE/NOLOG SYS SYS$COMMON:[SYSLIB]
+$!
+$! Define The Linker Options File Name.
+$!
+$ OPT_FILE = "VAX_VAXC_OPTIONS.OPT"
+$!
+$! End VAXC Check
+$!
+$ ENDIF
+$!
+$! Check To See If We Are To Use GNU C.
+$!
+$ IF (P3.EQS."GNUC")
+$ THEN
+$!
+$! Looks Like GNUC, Set To Use GNUC.
+$!
+$ COMPILER = "GNUC"
+$!
+$! Tell The User We Are Using GNUC.
+$!
+$ WRITE SYS$OUTPUT "Using GNU 'C' Compiler."
+$!
+$! Use GNU C...
+$!
+$ IF F$TYPE(GCC) .EQS. "" THEN GCC := GCC
+$ CC = GCC+"/NOCASE_HACK/''GCC_OPTIMIZE'/''DEBUGGER'/NOLIST" + -
+ "/INCLUDE=(''CC_INCLUDES')" + CCEXTRAFLAGS
+$!
+$! Define The Linker Options File Name.
+$!
+$ OPT_FILE = "VAX_GNUC_OPTIONS.OPT"
+$!
+$! End The GNU C Check.
+$!
+$ ENDIF
+$!
+$! Set up default defines
+$!
+$ CCDEFS = """FLAT_INC=1""," + CCDEFS
+$!
+$! Finish up the definition of CC.
+$!
+$ IF COMPILER .EQS. "DECC"
+$ THEN
+$! Not all compiler versions support MAYLOSEDATA3.
+$ OPT_TEST = "MAYLOSEDATA3"
+$ DEFINE /USER_MODE SYS$ERROR NL:
+$ DEFINE /USER_MODE SYS$OUTPUT NL:
+$ 'CC' /NOCROSS_REFERENCE /NOLIST /NOOBJECT -
+ /WARNINGS = DISABLE = ('OPT_TEST', EMPTYFILE) NL:
+$ IF ($SEVERITY)
+$ THEN
+$ IF CCDISABLEWARNINGS .NES. "" THEN -
+ CCDISABLEWARNINGS = CCDISABLEWARNINGS+ ","
+$ CCDISABLEWARNINGS = CCDISABLEWARNINGS+ OPT_TEST
+$ ENDIF
+$ IF CCDISABLEWARNINGS .EQS. ""
+$ THEN
+$ CC4DISABLEWARNINGS = "DOLLARID"
+$ ELSE
+$ CC4DISABLEWARNINGS = CCDISABLEWARNINGS + ",DOLLARID"
+$ CCDISABLEWARNINGS = " /WARNING=(DISABLE=(" + CCDISABLEWARNINGS + "))"
+$ ENDIF
+$ CC4DISABLEWARNINGS = " /WARNING=(DISABLE=(" + CC4DISABLEWARNINGS + "))"
+$ ELSE
+$ CCDISABLEWARNINGS = ""
+$ CC4DISABLEWARNINGS = ""
+$ ENDIF
+$ CC2 = CC + " /DEFINE=(" + CCDEFS + ",_POSIX_C_SOURCE)" + CCDISABLEWARNINGS
+$ CC3 = CC + " /DEFINE=(" + CCDEFS + ISSEVEN + ")" + CCDISABLEWARNINGS
+$ CC = CC + " /DEFINE=(" + CCDEFS + ")" + CCDISABLEWARNINGS
+$ IF COMPILER .EQS. "DECC"
+$ THEN
+$ CC4 = CC - CCDISABLEWARNINGS + CC4DISABLEWARNINGS
+$ CC5 = CC3 - CCDISABLEWARNINGS + CC4DISABLEWARNINGS
+$ ELSE
+$ CC4 = CC
+$ CC5 = CC3
+$ ENDIF
+$!
+$! Show user the result
+$!
+$ WRITE/SYMBOL SYS$OUTPUT "Main Compiling Command: ",CC
+$!
+$! Else The User Entered An Invalid Argument.
+$!
+$ ELSE
+$!
+$! Tell The User We Don't Know What They Want.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P3," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " VAXC : To Compile With VAX C."
+$ WRITE SYS$OUTPUT " DECC : To Compile With DEC C."
+$ WRITE SYS$OUTPUT " GNUC : To Compile With GNU C."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$ ENDIF
+$!
+$! Time to check the contents, and to make sure we get the correct library.
+$!
+$ IF P4.EQS."SOCKETSHR" .OR. P4.EQS."MULTINET" .OR. P4.EQS."UCX" -
+ .OR. P4.EQS."TCPIP" .OR. P4.EQS."NONE"
+$ THEN
+$!
+$! Check to see if SOCKETSHR was chosen
+$!
+$ IF P4.EQS."SOCKETSHR"
+$ THEN
+$!
+$! Set the library to use SOCKETSHR
+$!
+$ TCPIP_LIB = ",SYS$DISK:[-.VMS]SOCKETSHR_SHR.OPT /OPTIONS"
+$!
+$! Done with SOCKETSHR
+$!
+$ ENDIF
+$!
+$! Check to see if MULTINET was chosen
+$!
+$ IF P4.EQS."MULTINET"
+$ THEN
+$!
+$! Set the library to use UCX emulation.
+$!
+$ P4 = "UCX"
+$!
+$! Done with MULTINET
+$!
+$ ENDIF
+$!
+$! Check to see if UCX was chosen
+$!
+$ IF P4.EQS."UCX"
+$ THEN
+$!
+$! Set the library to use UCX.
+$!
+$ TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_DECC.OPT /OPTIONS"
+$ IF F$TRNLNM("UCX$IPC_SHR") .NES. ""
+$ THEN
+$ TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_DECC_LOG.OPT /OPTIONS"
+$ ELSE
+$ IF COMPILER .NES. "DECC" .AND. ARCH .EQS. "VAX" THEN -
+ TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_VAXC.OPT /OPTIONS"
+$ ENDIF
+$!
+$! Done with UCX
+$!
+$ ENDIF
+$!
+$! Check to see if TCPIP was chosen
+$!
+$ IF P4.EQS."TCPIP"
+$ THEN
+$!
+$! Set the library to use TCPIP (post UCX).
+$!
+$ TCPIP_LIB = ",SYS$DISK:[-.VMS]TCPIP_SHR_DECC.OPT /OPTIONS"
+$!
+$! Done with TCPIP
+$!
+$ ENDIF
+$!
+$! Check to see if NONE was chosen
+$!
+$ IF P4.EQS."NONE"
+$ THEN
+$!
+$! Do not use a TCPIP library.
+$!
+$ TCPIP_LIB = ""
+$!
+$! Done with NONE
+$!
+$ ENDIF
+$!
+$! Print info
+$!
+$ WRITE SYS$OUTPUT "TCP/IP library spec: ", TCPIP_LIB- ","
+$!
+$! Else The User Entered An Invalid Argument.
+$!
+$ ELSE
+$!
+$! Tell The User We Don't Know What They Want.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P4," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " SOCKETSHR : To link with SOCKETSHR TCP/IP library."
+$ WRITE SYS$OUTPUT " UCX : To link with UCX TCP/IP library."
+$ WRITE SYS$OUTPUT " TCPIP : To link with TCPIP (post UCX) TCP/IP library."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$!
+$! Done with TCP/IP libraries
+$!
+$ ENDIF
+$!
+$! Time To RETURN...
+$!
+$ RETURN
+$!
+$ INITIALISE:
+$!
+$! Save old value of the logical name OPENSSL
+$!
+$ __SAVE_OPENSSL = F$TRNLNM("OPENSSL","LNM$PROCESS_TABLE")
+$!
+$! Save directory information
+$!
+$ __HERE = F$PARSE(F$PARSE("A.;",F$ENVIRONMENT("PROCEDURE"))-"A.;","[]A.;") - "A.;"
+$ __HERE = F$EDIT(__HERE,"UPCASE")
+$ __TOP = __HERE - "SSL]"
+$ __INCLUDE = __TOP + "INCLUDE.OPENSSL]"
+$!
+$! Set up the logical name OPENSSL to point at the include directory
+$!
+$ DEFINE OPENSSL/NOLOG '__INCLUDE'
+$!
+$! Done
+$!
+$ RETURN
+$!
+$ CLEANUP:
+$!
+$! Restore the logical name OPENSSL if it had a value
+$!
+$ IF __SAVE_OPENSSL .EQS. ""
+$ THEN
+$ DEASSIGN OPENSSL
+$ ELSE
+$ DEFINE/NOLOG OPENSSL '__SAVE_OPENSSL'
+$ ENDIF
+$!
+$! Done
+$!
+$ RETURN
diff --git a/drivers/builtin_openssl/ssl/ssl_algs.c b/drivers/builtin_openssl2/ssl/ssl_algs.c
index 9c34d19725..9c34d19725 100644
--- a/drivers/builtin_openssl/ssl/ssl_algs.c
+++ b/drivers/builtin_openssl2/ssl/ssl_algs.c
diff --git a/drivers/builtin_openssl2/ssl/ssl_asn1.c b/drivers/builtin_openssl2/ssl/ssl_asn1.c
new file mode 100644
index 0000000000..4775003710
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/ssl_asn1.c
@@ -0,0 +1,646 @@
+/* ssl/ssl_asn1.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ssl_locl.h"
+#include <openssl/asn1_mac.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+
+typedef struct ssl_session_asn1_st
+ {
+ ASN1_INTEGER version;
+ ASN1_INTEGER ssl_version;
+ ASN1_OCTET_STRING cipher;
+ ASN1_OCTET_STRING comp_id;
+ ASN1_OCTET_STRING master_key;
+ ASN1_OCTET_STRING session_id;
+ ASN1_OCTET_STRING session_id_context;
+ ASN1_OCTET_STRING key_arg;
+#ifndef OPENSSL_NO_KRB5
+ ASN1_OCTET_STRING krb5_princ;
+#endif /* OPENSSL_NO_KRB5 */
+ ASN1_INTEGER time;
+ ASN1_INTEGER timeout;
+ ASN1_INTEGER verify_result;
+#ifndef OPENSSL_NO_TLSEXT
+ ASN1_OCTET_STRING tlsext_hostname;
+ ASN1_INTEGER tlsext_tick_lifetime;
+ ASN1_OCTET_STRING tlsext_tick;
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_PSK
+ ASN1_OCTET_STRING psk_identity_hint;
+ ASN1_OCTET_STRING psk_identity;
+#endif /* OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+ ASN1_OCTET_STRING srp_username;
+#endif /* OPENSSL_NO_SRP */
+ } SSL_SESSION_ASN1;
+
+int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
+ {
+#define LSIZE2 (sizeof(long)*2)
+ int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0;
+ unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
+ unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
+#ifndef OPENSSL_NO_TLSEXT
+ int v6=0,v9=0,v10=0;
+ unsigned char ibuf6[LSIZE2];
+#endif
+#ifndef OPENSSL_NO_COMP
+ unsigned char cbuf;
+ int v11=0;
+#endif
+#ifndef OPENSSL_NO_SRP
+ int v12=0;
+#endif
+ long l;
+ SSL_SESSION_ASN1 a;
+ M_ASN1_I2D_vars(in);
+
+ if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0)))
+ return(0);
+
+ /* Note that I cheat in the following 2 assignments. I know
+ * that if the ASN1_INTEGER passed to ASN1_INTEGER_set
+ * is > sizeof(long)+1, the buffer will not be re-OPENSSL_malloc()ed.
+ * This is a bit evil but makes things simple, no dynamic allocation
+ * to clean up :-) */
+ a.version.length=LSIZE2;
+ a.version.type=V_ASN1_INTEGER;
+ a.version.data=ibuf1;
+ ASN1_INTEGER_set(&(a.version),SSL_SESSION_ASN1_VERSION);
+
+ a.ssl_version.length=LSIZE2;
+ a.ssl_version.type=V_ASN1_INTEGER;
+ a.ssl_version.data=ibuf2;
+ ASN1_INTEGER_set(&(a.ssl_version),in->ssl_version);
+
+ a.cipher.type=V_ASN1_OCTET_STRING;
+ a.cipher.data=buf;
+
+ if (in->cipher == NULL)
+ l=in->cipher_id;
+ else
+ l=in->cipher->id;
+ if (in->ssl_version == SSL2_VERSION)
+ {
+ a.cipher.length=3;
+ buf[0]=((unsigned char)(l>>16L))&0xff;
+ buf[1]=((unsigned char)(l>> 8L))&0xff;
+ buf[2]=((unsigned char)(l ))&0xff;
+ }
+ else
+ {
+ a.cipher.length=2;
+ buf[0]=((unsigned char)(l>>8L))&0xff;
+ buf[1]=((unsigned char)(l ))&0xff;
+ }
+
+#ifndef OPENSSL_NO_COMP
+ if (in->compress_meth)
+ {
+ cbuf = (unsigned char)in->compress_meth;
+ a.comp_id.length = 1;
+ a.comp_id.type = V_ASN1_OCTET_STRING;
+ a.comp_id.data = &cbuf;
+ }
+#endif
+
+ a.master_key.length=in->master_key_length;
+ a.master_key.type=V_ASN1_OCTET_STRING;
+ a.master_key.data=in->master_key;
+
+ a.session_id.length=in->session_id_length;
+ a.session_id.type=V_ASN1_OCTET_STRING;
+ a.session_id.data=in->session_id;
+
+ a.session_id_context.length=in->sid_ctx_length;
+ a.session_id_context.type=V_ASN1_OCTET_STRING;
+ a.session_id_context.data=in->sid_ctx;
+
+ a.key_arg.length=in->key_arg_length;
+ a.key_arg.type=V_ASN1_OCTET_STRING;
+ a.key_arg.data=in->key_arg;
+
+#ifndef OPENSSL_NO_KRB5
+ if (in->krb5_client_princ_len)
+ {
+ a.krb5_princ.length=in->krb5_client_princ_len;
+ a.krb5_princ.type=V_ASN1_OCTET_STRING;
+ a.krb5_princ.data=in->krb5_client_princ;
+ }
+#endif /* OPENSSL_NO_KRB5 */
+
+ if (in->time != 0L)
+ {
+ a.time.length=LSIZE2;
+ a.time.type=V_ASN1_INTEGER;
+ a.time.data=ibuf3;
+ ASN1_INTEGER_set(&(a.time),in->time);
+ }
+
+ if (in->timeout != 0L)
+ {
+ a.timeout.length=LSIZE2;
+ a.timeout.type=V_ASN1_INTEGER;
+ a.timeout.data=ibuf4;
+ ASN1_INTEGER_set(&(a.timeout),in->timeout);
+ }
+
+ if (in->verify_result != X509_V_OK)
+ {
+ a.verify_result.length=LSIZE2;
+ a.verify_result.type=V_ASN1_INTEGER;
+ a.verify_result.data=ibuf5;
+ ASN1_INTEGER_set(&a.verify_result,in->verify_result);
+ }
+
+#ifndef OPENSSL_NO_TLSEXT
+ if (in->tlsext_hostname)
+ {
+ a.tlsext_hostname.length=strlen(in->tlsext_hostname);
+ a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
+ a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname;
+ }
+ if (in->tlsext_tick)
+ {
+ a.tlsext_tick.length= in->tlsext_ticklen;
+ a.tlsext_tick.type=V_ASN1_OCTET_STRING;
+ a.tlsext_tick.data=(unsigned char *)in->tlsext_tick;
+ }
+ if (in->tlsext_tick_lifetime_hint > 0)
+ {
+ a.tlsext_tick_lifetime.length=LSIZE2;
+ a.tlsext_tick_lifetime.type=V_ASN1_INTEGER;
+ a.tlsext_tick_lifetime.data=ibuf6;
+ ASN1_INTEGER_set(&a.tlsext_tick_lifetime,in->tlsext_tick_lifetime_hint);
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_PSK
+ if (in->psk_identity_hint)
+ {
+ a.psk_identity_hint.length=strlen(in->psk_identity_hint);
+ a.psk_identity_hint.type=V_ASN1_OCTET_STRING;
+ a.psk_identity_hint.data=(unsigned char *)(in->psk_identity_hint);
+ }
+ if (in->psk_identity)
+ {
+ a.psk_identity.length=strlen(in->psk_identity);
+ a.psk_identity.type=V_ASN1_OCTET_STRING;
+ a.psk_identity.data=(unsigned char *)(in->psk_identity);
+ }
+#endif /* OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+ if (in->srp_username)
+ {
+ a.srp_username.length=strlen(in->srp_username);
+ a.srp_username.type=V_ASN1_OCTET_STRING;
+ a.srp_username.data=(unsigned char *)(in->srp_username);
+ }
+#endif /* OPENSSL_NO_SRP */
+
+ M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER);
+ M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER);
+ M_ASN1_I2D_len(&(a.cipher), i2d_ASN1_OCTET_STRING);
+ M_ASN1_I2D_len(&(a.session_id), i2d_ASN1_OCTET_STRING);
+ M_ASN1_I2D_len(&(a.master_key), i2d_ASN1_OCTET_STRING);
+#ifndef OPENSSL_NO_KRB5
+ if (in->krb5_client_princ_len)
+ M_ASN1_I2D_len(&(a.krb5_princ), i2d_ASN1_OCTET_STRING);
+#endif /* OPENSSL_NO_KRB5 */
+ if (in->key_arg_length > 0)
+ M_ASN1_I2D_len_IMP_opt(&(a.key_arg),i2d_ASN1_OCTET_STRING);
+ if (in->time != 0L)
+ M_ASN1_I2D_len_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
+ if (in->timeout != 0L)
+ M_ASN1_I2D_len_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
+ if (in->peer != NULL)
+ M_ASN1_I2D_len_EXP_opt(in->peer,i2d_X509,3,v3);
+ M_ASN1_I2D_len_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,v4);
+ if (in->verify_result != X509_V_OK)
+ M_ASN1_I2D_len_EXP_opt(&(a.verify_result),i2d_ASN1_INTEGER,5,v5);
+
+#ifndef OPENSSL_NO_TLSEXT
+ if (in->tlsext_tick_lifetime_hint > 0)
+ M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
+ if (in->tlsext_tick)
+ M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
+ if (in->tlsext_hostname)
+ M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#ifndef OPENSSL_NO_COMP
+ if (in->compress_meth)
+ M_ASN1_I2D_len_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING,11,v11);
+#endif
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_PSK
+ if (in->psk_identity_hint)
+ M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
+ if (in->psk_identity)
+ M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
+#endif /* OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+ if (in->srp_username)
+ M_ASN1_I2D_len_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING,12,v12);
+#endif /* OPENSSL_NO_SRP */
+
+ M_ASN1_I2D_seq_total();
+
+ M_ASN1_I2D_put(&(a.version), i2d_ASN1_INTEGER);
+ M_ASN1_I2D_put(&(a.ssl_version), i2d_ASN1_INTEGER);
+ M_ASN1_I2D_put(&(a.cipher), i2d_ASN1_OCTET_STRING);
+ M_ASN1_I2D_put(&(a.session_id), i2d_ASN1_OCTET_STRING);
+ M_ASN1_I2D_put(&(a.master_key), i2d_ASN1_OCTET_STRING);
+#ifndef OPENSSL_NO_KRB5
+ if (in->krb5_client_princ_len)
+ M_ASN1_I2D_put(&(a.krb5_princ), i2d_ASN1_OCTET_STRING);
+#endif /* OPENSSL_NO_KRB5 */
+ if (in->key_arg_length > 0)
+ M_ASN1_I2D_put_IMP_opt(&(a.key_arg),i2d_ASN1_OCTET_STRING,0);
+ if (in->time != 0L)
+ M_ASN1_I2D_put_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
+ if (in->timeout != 0L)
+ M_ASN1_I2D_put_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
+ if (in->peer != NULL)
+ M_ASN1_I2D_put_EXP_opt(in->peer,i2d_X509,3,v3);
+ M_ASN1_I2D_put_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,
+ v4);
+ if (in->verify_result != X509_V_OK)
+ M_ASN1_I2D_put_EXP_opt(&a.verify_result,i2d_ASN1_INTEGER,5,v5);
+#ifndef OPENSSL_NO_TLSEXT
+ if (in->tlsext_hostname)
+ M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_PSK
+ if (in->psk_identity_hint)
+ M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
+ if (in->psk_identity)
+ M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
+#endif /* OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_TLSEXT
+ if (in->tlsext_tick_lifetime_hint > 0)
+ M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
+ if (in->tlsext_tick)
+ M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_COMP
+ if (in->compress_meth)
+ M_ASN1_I2D_put_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING,11,v11);
+#endif
+#ifndef OPENSSL_NO_SRP
+ if (in->srp_username)
+ M_ASN1_I2D_put_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING,12,v12);
+#endif /* OPENSSL_NO_SRP */
+ M_ASN1_I2D_finish();
+ }
+
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
+ long length)
+ {
+ int ssl_version=0,i;
+ long id;
+ ASN1_INTEGER ai,*aip;
+ ASN1_OCTET_STRING os,*osp;
+ M_ASN1_D2I_vars(a,SSL_SESSION *,SSL_SESSION_new);
+
+ aip= &ai;
+ osp= &os;
+
+ M_ASN1_D2I_Init();
+ M_ASN1_D2I_start_sequence();
+
+ ai.data=NULL; ai.length=0;
+ M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
+ if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
+
+ /* we don't care about the version right now :-) */
+ M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
+ ssl_version=(int)ASN1_INTEGER_get(aip);
+ ret->ssl_version=ssl_version;
+ if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
+
+ os.data=NULL; os.length=0;
+ M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
+ if (ssl_version == SSL2_VERSION)
+ {
+ if (os.length != 3)
+ {
+ c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
+ c.line=__LINE__;
+ goto err;
+ }
+ id=0x02000000L|
+ ((unsigned long)os.data[0]<<16L)|
+ ((unsigned long)os.data[1]<< 8L)|
+ (unsigned long)os.data[2];
+ }
+ else if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
+ {
+ if (os.length != 2)
+ {
+ c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
+ c.line=__LINE__;
+ goto err;
+ }
+ id=0x03000000L|
+ ((unsigned long)os.data[0]<<8L)|
+ (unsigned long)os.data[1];
+ }
+ else
+ {
+ c.error=SSL_R_UNKNOWN_SSL_VERSION;
+ c.line=__LINE__;
+ goto err;
+ }
+
+ ret->cipher=NULL;
+ ret->cipher_id=id;
+
+ M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
+ if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
+ i=SSL3_MAX_SSL_SESSION_ID_LENGTH;
+ else /* if (ssl_version>>8 == SSL2_VERSION_MAJOR) */
+ i=SSL2_MAX_SSL_SESSION_ID_LENGTH;
+
+ if (os.length > i)
+ os.length = i;
+ if (os.length > (int)sizeof(ret->session_id)) /* can't happen */
+ os.length = sizeof(ret->session_id);
+
+ ret->session_id_length=os.length;
+ OPENSSL_assert(os.length <= (int)sizeof(ret->session_id));
+ memcpy(ret->session_id,os.data,os.length);
+
+ M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
+ if (os.length > SSL_MAX_MASTER_KEY_LENGTH)
+ ret->master_key_length=SSL_MAX_MASTER_KEY_LENGTH;
+ else
+ ret->master_key_length=os.length;
+ memcpy(ret->master_key,os.data,ret->master_key_length);
+
+ os.length=0;
+
+#ifndef OPENSSL_NO_KRB5
+ os.length=0;
+ M_ASN1_D2I_get_opt(osp,d2i_ASN1_OCTET_STRING,V_ASN1_OCTET_STRING);
+ if (os.data)
+ {
+ if (os.length > SSL_MAX_KRB5_PRINCIPAL_LENGTH)
+ ret->krb5_client_princ_len=0;
+ else
+ ret->krb5_client_princ_len=os.length;
+ memcpy(ret->krb5_client_princ,os.data,ret->krb5_client_princ_len);
+ OPENSSL_free(os.data);
+ os.data = NULL;
+ os.length = 0;
+ }
+ else
+ ret->krb5_client_princ_len=0;
+#endif /* OPENSSL_NO_KRB5 */
+
+ M_ASN1_D2I_get_IMP_opt(osp,d2i_ASN1_OCTET_STRING,0,V_ASN1_OCTET_STRING);
+ if (os.length > SSL_MAX_KEY_ARG_LENGTH)
+ ret->key_arg_length=SSL_MAX_KEY_ARG_LENGTH;
+ else
+ ret->key_arg_length=os.length;
+ memcpy(ret->key_arg,os.data,ret->key_arg_length);
+ if (os.data != NULL) OPENSSL_free(os.data);
+
+ ai.length=0;
+ M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,1);
+ if (ai.data != NULL)
+ {
+ ret->time=ASN1_INTEGER_get(aip);
+ OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+ }
+ else
+ ret->time=(unsigned long)time(NULL);
+
+ ai.length=0;
+ M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,2);
+ if (ai.data != NULL)
+ {
+ ret->timeout=ASN1_INTEGER_get(aip);
+ OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+ }
+ else
+ ret->timeout=3;
+
+ if (ret->peer != NULL)
+ {
+ X509_free(ret->peer);
+ ret->peer=NULL;
+ }
+ M_ASN1_D2I_get_EXP_opt(ret->peer,d2i_X509,3);
+
+ os.length=0;
+ os.data=NULL;
+ M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,4);
+
+ if(os.data != NULL)
+ {
+ if (os.length > SSL_MAX_SID_CTX_LENGTH)
+ {
+ c.error=SSL_R_BAD_LENGTH;
+ c.line=__LINE__;
+ goto err;
+ }
+ else
+ {
+ ret->sid_ctx_length=os.length;
+ memcpy(ret->sid_ctx,os.data,os.length);
+ }
+ OPENSSL_free(os.data); os.data=NULL; os.length=0;
+ }
+ else
+ ret->sid_ctx_length=0;
+
+ ai.length=0;
+ M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,5);
+ if (ai.data != NULL)
+ {
+ ret->verify_result=ASN1_INTEGER_get(aip);
+ OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+ }
+ else
+ ret->verify_result=X509_V_OK;
+
+#ifndef OPENSSL_NO_TLSEXT
+ os.length=0;
+ os.data=NULL;
+ M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
+ if (os.data)
+ {
+ ret->tlsext_hostname = BUF_strndup((char *)os.data, os.length);
+ OPENSSL_free(os.data);
+ os.data = NULL;
+ os.length = 0;
+ }
+ else
+ ret->tlsext_hostname=NULL;
+#endif /* OPENSSL_NO_TLSEXT */
+
+#ifndef OPENSSL_NO_PSK
+ os.length=0;
+ os.data=NULL;
+ M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
+ if (os.data)
+ {
+ ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length);
+ OPENSSL_free(os.data);
+ os.data = NULL;
+ os.length = 0;
+ }
+ else
+ ret->psk_identity_hint=NULL;
+
+ os.length=0;
+ os.data=NULL;
+ M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
+ if (os.data)
+ {
+ ret->psk_identity = BUF_strndup((char *)os.data, os.length);
+ OPENSSL_free(os.data);
+ os.data = NULL;
+ os.length = 0;
+ }
+ else
+ ret->psk_identity=NULL;
+#endif /* OPENSSL_NO_PSK */
+
+#ifndef OPENSSL_NO_TLSEXT
+ ai.length=0;
+ M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,9);
+ if (ai.data != NULL)
+ {
+ ret->tlsext_tick_lifetime_hint=ASN1_INTEGER_get(aip);
+ OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+ }
+ else if (ret->tlsext_ticklen && ret->session_id_length)
+ ret->tlsext_tick_lifetime_hint = -1;
+ else
+ ret->tlsext_tick_lifetime_hint=0;
+ os.length=0;
+ os.data=NULL;
+ M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10);
+ if (os.data)
+ {
+ ret->tlsext_tick = os.data;
+ ret->tlsext_ticklen = os.length;
+ os.data = NULL;
+ os.length = 0;
+ }
+ else
+ ret->tlsext_tick=NULL;
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_COMP
+ os.length=0;
+ os.data=NULL;
+ M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,11);
+ if (os.data)
+ {
+ ret->compress_meth = os.data[0];
+ OPENSSL_free(os.data);
+ os.data = NULL;
+ }
+#endif
+
+#ifndef OPENSSL_NO_SRP
+ os.length=0;
+ os.data=NULL;
+ M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,12);
+ if (os.data)
+ {
+ ret->srp_username = BUF_strndup((char *)os.data, os.length);
+ OPENSSL_free(os.data);
+ os.data = NULL;
+ os.length = 0;
+ }
+ else
+ ret->srp_username=NULL;
+#endif /* OPENSSL_NO_SRP */
+
+ M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
+ }
diff --git a/drivers/builtin_openssl2/ssl/ssl_cert.c b/drivers/builtin_openssl2/ssl/ssl_cert.c
new file mode 100644
index 0000000000..5123a89182
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/ssl_cert.c
@@ -0,0 +1,853 @@
+/*! \file ssl/ssl_cert.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#include <stdio.h>
+
+#include "e_os.h"
+#ifndef NO_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include "o_dir.h"
+#include <openssl/objects.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#include <openssl/bn.h>
+#include "ssl_locl.h"
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void)
+ {
+ static volatile int ssl_x509_store_ctx_idx= -1;
+ int got_write_lock = 0;
+
+ CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
+
+ if (ssl_x509_store_ctx_idx < 0)
+ {
+ CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+ got_write_lock = 1;
+
+ if (ssl_x509_store_ctx_idx < 0)
+ {
+ ssl_x509_store_ctx_idx=X509_STORE_CTX_get_ex_new_index(
+ 0,"SSL for verify callback",NULL,NULL,NULL);
+ }
+ }
+
+ if (got_write_lock)
+ CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+ else
+ CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+
+ return ssl_x509_store_ctx_idx;
+ }
+
+static void ssl_cert_set_default_md(CERT *cert)
+ {
+ /* Set digest values to defaults */
+#ifndef OPENSSL_NO_DSA
+ cert->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_RSA
+ cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+ cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ cert->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
+#endif
+ }
+
+CERT *ssl_cert_new(void)
+ {
+ CERT *ret;
+
+ ret=(CERT *)OPENSSL_malloc(sizeof(CERT));
+ if (ret == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_NEW,ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ memset(ret,0,sizeof(CERT));
+
+ ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]);
+ ret->references=1;
+ ssl_cert_set_default_md(ret);
+ return(ret);
+ }
+
+CERT *ssl_cert_dup(CERT *cert)
+ {
+ CERT *ret;
+ int i;
+
+ ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+ if (ret == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+
+ memset(ret, 0, sizeof(CERT));
+
+ ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]];
+ /* or ret->key = ret->pkeys + (cert->key - cert->pkeys),
+ * if you find that more readable */
+
+ ret->valid = cert->valid;
+ ret->mask_k = cert->mask_k;
+ ret->mask_a = cert->mask_a;
+ ret->export_mask_k = cert->export_mask_k;
+ ret->export_mask_a = cert->export_mask_a;
+
+#ifndef OPENSSL_NO_RSA
+ if (cert->rsa_tmp != NULL)
+ {
+ RSA_up_ref(cert->rsa_tmp);
+ ret->rsa_tmp = cert->rsa_tmp;
+ }
+ ret->rsa_tmp_cb = cert->rsa_tmp_cb;
+#endif
+
+#ifndef OPENSSL_NO_DH
+ if (cert->dh_tmp != NULL)
+ {
+ ret->dh_tmp = DHparams_dup(cert->dh_tmp);
+ if (ret->dh_tmp == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_DH_LIB);
+ goto err;
+ }
+ if (cert->dh_tmp->priv_key)
+ {
+ BIGNUM *b = BN_dup(cert->dh_tmp->priv_key);
+ if (!b)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB);
+ goto err;
+ }
+ ret->dh_tmp->priv_key = b;
+ }
+ if (cert->dh_tmp->pub_key)
+ {
+ BIGNUM *b = BN_dup(cert->dh_tmp->pub_key);
+ if (!b)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB);
+ goto err;
+ }
+ ret->dh_tmp->pub_key = b;
+ }
+ }
+ ret->dh_tmp_cb = cert->dh_tmp_cb;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+ if (cert->ecdh_tmp)
+ {
+ ret->ecdh_tmp = EC_KEY_dup(cert->ecdh_tmp);
+ if (ret->ecdh_tmp == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_EC_LIB);
+ goto err;
+ }
+ }
+ ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
+#endif
+
+ for (i = 0; i < SSL_PKEY_NUM; i++)
+ {
+ if (cert->pkeys[i].x509 != NULL)
+ {
+ ret->pkeys[i].x509 = cert->pkeys[i].x509;
+ CRYPTO_add(&ret->pkeys[i].x509->references, 1,
+ CRYPTO_LOCK_X509);
+ }
+
+ if (cert->pkeys[i].privatekey != NULL)
+ {
+ ret->pkeys[i].privatekey = cert->pkeys[i].privatekey;
+ CRYPTO_add(&ret->pkeys[i].privatekey->references, 1,
+ CRYPTO_LOCK_EVP_PKEY);
+
+ switch(i)
+ {
+ /* If there was anything special to do for
+ * certain types of keys, we'd do it here.
+ * (Nothing at the moment, I think.) */
+
+ case SSL_PKEY_RSA_ENC:
+ case SSL_PKEY_RSA_SIGN:
+ /* We have an RSA key. */
+ break;
+
+ case SSL_PKEY_DSA_SIGN:
+ /* We have a DSA key. */
+ break;
+
+ case SSL_PKEY_DH_RSA:
+ case SSL_PKEY_DH_DSA:
+ /* We have a DH key. */
+ break;
+
+ case SSL_PKEY_ECC:
+ /* We have an ECC key */
+ break;
+
+ default:
+ /* Can't happen. */
+ SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG);
+ }
+ }
+ }
+
+ /* ret->extra_certs *should* exist, but currently the own certificate
+ * chain is held inside SSL_CTX */
+
+ ret->references=1;
+ /* Set digests to defaults. NB: we don't copy existing values as they
+ * will be set during handshake.
+ */
+ ssl_cert_set_default_md(ret);
+
+ return(ret);
+
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH)
+err:
+#endif
+#ifndef OPENSSL_NO_RSA
+ if (ret->rsa_tmp != NULL)
+ RSA_free(ret->rsa_tmp);
+#endif
+#ifndef OPENSSL_NO_DH
+ if (ret->dh_tmp != NULL)
+ DH_free(ret->dh_tmp);
+#endif
+#ifndef OPENSSL_NO_ECDH
+ if (ret->ecdh_tmp != NULL)
+ EC_KEY_free(ret->ecdh_tmp);
+#endif
+
+ for (i = 0; i < SSL_PKEY_NUM; i++)
+ {
+ if (ret->pkeys[i].x509 != NULL)
+ X509_free(ret->pkeys[i].x509);
+ if (ret->pkeys[i].privatekey != NULL)
+ EVP_PKEY_free(ret->pkeys[i].privatekey);
+ }
+
+ return NULL;
+ }
+
+
+void ssl_cert_free(CERT *c)
+ {
+ int i;
+
+ if(c == NULL)
+ return;
+
+ i=CRYPTO_add(&c->references,-1,CRYPTO_LOCK_SSL_CERT);
+#ifdef REF_PRINT
+ REF_PRINT("CERT",c);
+#endif
+ if (i > 0) return;
+#ifdef REF_CHECK
+ if (i < 0)
+ {
+ fprintf(stderr,"ssl_cert_free, bad reference count\n");
+ abort(); /* ok */
+ }
+#endif
+
+#ifndef OPENSSL_NO_RSA
+ if (c->rsa_tmp) RSA_free(c->rsa_tmp);
+#endif
+#ifndef OPENSSL_NO_DH
+ if (c->dh_tmp) DH_free(c->dh_tmp);
+#endif
+#ifndef OPENSSL_NO_ECDH
+ if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp);
+#endif
+
+ for (i=0; i<SSL_PKEY_NUM; i++)
+ {
+ if (c->pkeys[i].x509 != NULL)
+ X509_free(c->pkeys[i].x509);
+ if (c->pkeys[i].privatekey != NULL)
+ EVP_PKEY_free(c->pkeys[i].privatekey);
+#if 0
+ if (c->pkeys[i].publickey != NULL)
+ EVP_PKEY_free(c->pkeys[i].publickey);
+#endif
+ }
+ OPENSSL_free(c);
+ }
+
+int ssl_cert_inst(CERT **o)
+ {
+ /* Create a CERT if there isn't already one
+ * (which cannot really happen, as it is initially created in
+ * SSL_CTX_new; but the earlier code usually allows for that one
+ * being non-existant, so we follow that behaviour, as it might
+ * turn out that there actually is a reason for it -- but I'm
+ * not sure that *all* of the existing code could cope with
+ * s->cert being NULL, otherwise we could do without the
+ * initialization in SSL_CTX_new).
+ */
+
+ if (o == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_INST, ERR_R_PASSED_NULL_PARAMETER);
+ return(0);
+ }
+ if (*o == NULL)
+ {
+ if ((*o = ssl_cert_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_INST, ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+ }
+ return(1);
+ }
+
+
+SESS_CERT *ssl_sess_cert_new(void)
+ {
+ SESS_CERT *ret;
+
+ ret = OPENSSL_malloc(sizeof *ret);
+ if (ret == NULL)
+ {
+ SSLerr(SSL_F_SSL_SESS_CERT_NEW, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ memset(ret, 0 ,sizeof *ret);
+ ret->peer_key = &(ret->peer_pkeys[SSL_PKEY_RSA_ENC]);
+ ret->references = 1;
+
+ return ret;
+ }
+
+void ssl_sess_cert_free(SESS_CERT *sc)
+ {
+ int i;
+
+ if (sc == NULL)
+ return;
+
+ i = CRYPTO_add(&sc->references, -1, CRYPTO_LOCK_SSL_SESS_CERT);
+#ifdef REF_PRINT
+ REF_PRINT("SESS_CERT", sc);
+#endif
+ if (i > 0)
+ return;
+#ifdef REF_CHECK
+ if (i < 0)
+ {
+ fprintf(stderr,"ssl_sess_cert_free, bad reference count\n");
+ abort(); /* ok */
+ }
+#endif
+
+ /* i == 0 */
+ if (sc->cert_chain != NULL)
+ sk_X509_pop_free(sc->cert_chain, X509_free);
+ for (i = 0; i < SSL_PKEY_NUM; i++)
+ {
+ if (sc->peer_pkeys[i].x509 != NULL)
+ X509_free(sc->peer_pkeys[i].x509);
+#if 0 /* We don't have the peer's private key. These lines are just
+ * here as a reminder that we're still using a not-quite-appropriate
+ * data structure. */
+ if (sc->peer_pkeys[i].privatekey != NULL)
+ EVP_PKEY_free(sc->peer_pkeys[i].privatekey);
+#endif
+ }
+
+#ifndef OPENSSL_NO_RSA
+ if (sc->peer_rsa_tmp != NULL)
+ RSA_free(sc->peer_rsa_tmp);
+#endif
+#ifndef OPENSSL_NO_DH
+ if (sc->peer_dh_tmp != NULL)
+ DH_free(sc->peer_dh_tmp);
+#endif
+#ifndef OPENSSL_NO_ECDH
+ if (sc->peer_ecdh_tmp != NULL)
+ EC_KEY_free(sc->peer_ecdh_tmp);
+#endif
+
+ OPENSSL_free(sc);
+ }
+
+int ssl_set_peer_cert_type(SESS_CERT *sc,int type)
+ {
+ sc->peer_cert_type = type;
+ return(1);
+ }
+
+int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
+ {
+ X509 *x;
+ int i;
+ X509_STORE_CTX ctx;
+
+ if ((sk == NULL) || (sk_X509_num(sk) == 0))
+ return(0);
+
+ x=sk_X509_value(sk,0);
+ if(!X509_STORE_CTX_init(&ctx,s->ctx->cert_store,x,sk))
+ {
+ SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB);
+ return(0);
+ }
+#if 0
+ if (SSL_get_verify_depth(s) >= 0)
+ X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s));
+#endif
+ X509_STORE_CTX_set_ex_data(&ctx,SSL_get_ex_data_X509_STORE_CTX_idx(),s);
+
+ /* We need to inherit the verify parameters. These can be determined by
+ * the context: if its a server it will verify SSL client certificates
+ * or vice versa.
+ */
+
+ X509_STORE_CTX_set_default(&ctx,
+ s->server ? "ssl_client" : "ssl_server");
+ /* Anything non-default in "param" should overwrite anything in the
+ * ctx.
+ */
+ X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param);
+
+ if (s->verify_callback)
+ X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback);
+
+ if (s->ctx->app_verify_callback != NULL)
+#if 1 /* new with OpenSSL 0.9.7 */
+ i=s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg);
+#else
+ i=s->ctx->app_verify_callback(&ctx); /* should pass app_verify_arg */
+#endif
+ else
+ {
+#ifndef OPENSSL_NO_X509_VERIFY
+ i=X509_verify_cert(&ctx);
+#else
+ i=0;
+ ctx.error=X509_V_ERR_APPLICATION_VERIFICATION;
+ SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,SSL_R_NO_VERIFY_CALLBACK);
+#endif
+ }
+
+ s->verify_result=ctx.error;
+ X509_STORE_CTX_cleanup(&ctx);
+
+ return(i);
+ }
+
+static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,STACK_OF(X509_NAME) *name_list)
+ {
+ if (*ca_list != NULL)
+ sk_X509_NAME_pop_free(*ca_list,X509_NAME_free);
+
+ *ca_list=name_list;
+ }
+
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk)
+ {
+ int i;
+ STACK_OF(X509_NAME) *ret;
+ X509_NAME *name;
+
+ ret=sk_X509_NAME_new_null();
+ for (i=0; i<sk_X509_NAME_num(sk); i++)
+ {
+ name=X509_NAME_dup(sk_X509_NAME_value(sk,i));
+ if ((name == NULL) || !sk_X509_NAME_push(ret,name))
+ {
+ sk_X509_NAME_pop_free(ret,X509_NAME_free);
+ return(NULL);
+ }
+ }
+ return(ret);
+ }
+
+void SSL_set_client_CA_list(SSL *s,STACK_OF(X509_NAME) *name_list)
+ {
+ set_client_CA_list(&(s->client_CA),name_list);
+ }
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx,STACK_OF(X509_NAME) *name_list)
+ {
+ set_client_CA_list(&(ctx->client_CA),name_list);
+ }
+
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx)
+ {
+ return(ctx->client_CA);
+ }
+
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s)
+ {
+ if (s->type == SSL_ST_CONNECT)
+ { /* we are in the client */
+ if (((s->version>>8) == SSL3_VERSION_MAJOR) &&
+ (s->s3 != NULL))
+ return(s->s3->tmp.ca_names);
+ else
+ return(NULL);
+ }
+ else
+ {
+ if (s->client_CA != NULL)
+ return(s->client_CA);
+ else
+ return(s->ctx->client_CA);
+ }
+ }
+
+static int add_client_CA(STACK_OF(X509_NAME) **sk,X509 *x)
+ {
+ X509_NAME *name;
+
+ if (x == NULL) return(0);
+ if ((*sk == NULL) && ((*sk=sk_X509_NAME_new_null()) == NULL))
+ return(0);
+
+ if ((name=X509_NAME_dup(X509_get_subject_name(x))) == NULL)
+ return(0);
+
+ if (!sk_X509_NAME_push(*sk,name))
+ {
+ X509_NAME_free(name);
+ return(0);
+ }
+ return(1);
+ }
+
+int SSL_add_client_CA(SSL *ssl,X509 *x)
+ {
+ return(add_client_CA(&(ssl->client_CA),x));
+ }
+
+int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x)
+ {
+ return(add_client_CA(&(ctx->client_CA),x));
+ }
+
+static int xname_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
+ {
+ return(X509_NAME_cmp(*a,*b));
+ }
+
+#ifndef OPENSSL_NO_STDIO
+/*!
+ * Load CA certs from a file into a ::STACK. Note that it is somewhat misnamed;
+ * it doesn't really have anything to do with clients (except that a common use
+ * for a stack of CAs is to send it to the client). Actually, it doesn't have
+ * much to do with CAs, either, since it will load any old cert.
+ * \param file the file containing one or more certs.
+ * \return a ::STACK containing the certs.
+ */
+STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file)
+ {
+ BIO *in;
+ X509 *x=NULL;
+ X509_NAME *xn=NULL;
+ STACK_OF(X509_NAME) *ret = NULL,*sk;
+
+ sk=sk_X509_NAME_new(xname_cmp);
+
+ in=BIO_new(BIO_s_file_internal());
+
+ if ((sk == NULL) || (in == NULL))
+ {
+ SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BIO_read_filename(in,file))
+ goto err;
+
+ for (;;)
+ {
+ if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL)
+ break;
+ if (ret == NULL)
+ {
+ ret = sk_X509_NAME_new_null();
+ if (ret == NULL)
+ {
+ SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ if ((xn=X509_get_subject_name(x)) == NULL) goto err;
+ /* check for duplicates */
+ xn=X509_NAME_dup(xn);
+ if (xn == NULL) goto err;
+ if (sk_X509_NAME_find(sk,xn) >= 0)
+ X509_NAME_free(xn);
+ else
+ {
+ sk_X509_NAME_push(sk,xn);
+ sk_X509_NAME_push(ret,xn);
+ }
+ }
+
+ if (0)
+ {
+err:
+ if (ret != NULL) sk_X509_NAME_pop_free(ret,X509_NAME_free);
+ ret=NULL;
+ }
+ if (sk != NULL) sk_X509_NAME_free(sk);
+ if (in != NULL) BIO_free(in);
+ if (x != NULL) X509_free(x);
+ if (ret != NULL)
+ ERR_clear_error();
+ return(ret);
+ }
+#endif
+
+/*!
+ * Add a file of certs to a stack.
+ * \param stack the stack to add to.
+ * \param file the file to add from. All certs in this file that are not
+ * already in the stack will be added.
+ * \return 1 for success, 0 for failure. Note that in the case of failure some
+ * certs may have been added to \c stack.
+ */
+
+int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ const char *file)
+ {
+ BIO *in;
+ X509 *x=NULL;
+ X509_NAME *xn=NULL;
+ int ret=1;
+ int (*oldcmp)(const X509_NAME * const *a, const X509_NAME * const *b);
+
+ oldcmp=sk_X509_NAME_set_cmp_func(stack,xname_cmp);
+
+ in=BIO_new(BIO_s_file_internal());
+
+ if (in == NULL)
+ {
+ SSLerr(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BIO_read_filename(in,file))
+ goto err;
+
+ for (;;)
+ {
+ if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL)
+ break;
+ if ((xn=X509_get_subject_name(x)) == NULL) goto err;
+ xn=X509_NAME_dup(xn);
+ if (xn == NULL) goto err;
+ if (sk_X509_NAME_find(stack,xn) >= 0)
+ X509_NAME_free(xn);
+ else
+ sk_X509_NAME_push(stack,xn);
+ }
+
+ ERR_clear_error();
+
+ if (0)
+ {
+err:
+ ret=0;
+ }
+ if(in != NULL)
+ BIO_free(in);
+ if(x != NULL)
+ X509_free(x);
+
+ (void)sk_X509_NAME_set_cmp_func(stack,oldcmp);
+
+ return ret;
+ }
+
+/*!
+ * Add a directory of certs to a stack.
+ * \param stack the stack to append to.
+ * \param dir the directory to append from. All files in this directory will be
+ * examined as potential certs. Any that are acceptable to
+ * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will be
+ * included.
+ * \return 1 for success, 0 for failure. Note that in the case of failure some
+ * certs may have been added to \c stack.
+ */
+
+int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ const char *dir)
+ {
+ OPENSSL_DIR_CTX *d = NULL;
+ const char *filename;
+ int ret = 0;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_READDIR);
+
+ /* Note that a side effect is that the CAs will be sorted by name */
+
+ while((filename = OPENSSL_DIR_read(&d, dir)))
+ {
+ char buf[1024];
+ int r;
+
+ if(strlen(dir)+strlen(filename)+2 > sizeof buf)
+ {
+ SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK,SSL_R_PATH_TOO_LONG);
+ goto err;
+ }
+
+#ifdef OPENSSL_SYS_VMS
+ r = BIO_snprintf(buf,sizeof buf,"%s%s",dir,filename);
+#else
+ r = BIO_snprintf(buf,sizeof buf,"%s/%s",dir,filename);
+#endif
+ if (r <= 0 || r >= (int)sizeof(buf))
+ goto err;
+ if(!SSL_add_file_cert_subjects_to_stack(stack,buf))
+ goto err;
+ }
+
+ if (errno)
+ {
+ SYSerr(SYS_F_OPENDIR, get_last_sys_error());
+ ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')");
+ SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB);
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ if (d) OPENSSL_DIR_end(&d);
+ CRYPTO_w_unlock(CRYPTO_LOCK_READDIR);
+ return ret;
+ }
+
diff --git a/drivers/builtin_openssl/ssl/ssl_ciph.c b/drivers/builtin_openssl2/ssl/ssl_ciph.c
index 0aba8e048c..0aba8e048c 100644
--- a/drivers/builtin_openssl/ssl/ssl_ciph.c
+++ b/drivers/builtin_openssl2/ssl/ssl_ciph.c
diff --git a/drivers/builtin_openssl2/ssl/ssl_err.c b/drivers/builtin_openssl2/ssl/ssl_err.c
new file mode 100644
index 0000000000..49ab43e0e5
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/ssl_err.c
@@ -0,0 +1,610 @@
+/* ssl/ssl_err.c */
+/* ====================================================================
+ * Copyright (c) 1999-2011 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/* NOTE: this file was auto generated by the mkerr.pl script: any changes
+ * made to it will be overwritten when the script next updates this file,
+ * only reason strings will be preserved.
+ */
+
+#include <stdio.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+/* BEGIN ERROR CODES */
+#ifndef OPENSSL_NO_ERR
+
+#define ERR_FUNC(func) ERR_PACK(ERR_LIB_SSL,func,0)
+#define ERR_REASON(reason) ERR_PACK(ERR_LIB_SSL,0,reason)
+
+static ERR_STRING_DATA SSL_str_functs[]=
+ {
+{ERR_FUNC(SSL_F_CLIENT_CERTIFICATE), "CLIENT_CERTIFICATE"},
+{ERR_FUNC(SSL_F_CLIENT_FINISHED), "CLIENT_FINISHED"},
+{ERR_FUNC(SSL_F_CLIENT_HELLO), "CLIENT_HELLO"},
+{ERR_FUNC(SSL_F_CLIENT_MASTER_KEY), "CLIENT_MASTER_KEY"},
+{ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"},
+{ERR_FUNC(SSL_F_DO_DTLS1_WRITE), "DO_DTLS1_WRITE"},
+{ERR_FUNC(SSL_F_DO_SSL3_WRITE), "DO_SSL3_WRITE"},
+{ERR_FUNC(SSL_F_DTLS1_ACCEPT), "DTLS1_ACCEPT"},
+{ERR_FUNC(SSL_F_DTLS1_ADD_CERT_TO_BUF), "DTLS1_ADD_CERT_TO_BUF"},
+{ERR_FUNC(SSL_F_DTLS1_BUFFER_RECORD), "DTLS1_BUFFER_RECORD"},
+{ERR_FUNC(SSL_F_DTLS1_CHECK_TIMEOUT_NUM), "DTLS1_CHECK_TIMEOUT_NUM"},
+{ERR_FUNC(SSL_F_DTLS1_CLIENT_HELLO), "DTLS1_CLIENT_HELLO"},
+{ERR_FUNC(SSL_F_DTLS1_CONNECT), "DTLS1_CONNECT"},
+{ERR_FUNC(SSL_F_DTLS1_ENC), "DTLS1_ENC"},
+{ERR_FUNC(SSL_F_DTLS1_GET_HELLO_VERIFY), "DTLS1_GET_HELLO_VERIFY"},
+{ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE), "DTLS1_GET_MESSAGE"},
+{ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT), "DTLS1_GET_MESSAGE_FRAGMENT"},
+{ERR_FUNC(SSL_F_DTLS1_GET_RECORD), "DTLS1_GET_RECORD"},
+{ERR_FUNC(SSL_F_DTLS1_HANDLE_TIMEOUT), "DTLS1_HANDLE_TIMEOUT"},
+{ERR_FUNC(SSL_F_DTLS1_HEARTBEAT), "DTLS1_HEARTBEAT"},
+{ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN), "DTLS1_OUTPUT_CERT_CHAIN"},
+{ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT), "DTLS1_PREPROCESS_FRAGMENT"},
+{ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE), "DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"},
+{ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD), "DTLS1_PROCESS_RECORD"},
+{ERR_FUNC(SSL_F_DTLS1_READ_BYTES), "DTLS1_READ_BYTES"},
+{ERR_FUNC(SSL_F_DTLS1_READ_FAILED), "DTLS1_READ_FAILED"},
+{ERR_FUNC(SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST), "DTLS1_SEND_CERTIFICATE_REQUEST"},
+{ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE), "DTLS1_SEND_CLIENT_CERTIFICATE"},
+{ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE), "DTLS1_SEND_CLIENT_KEY_EXCHANGE"},
+{ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_VERIFY), "DTLS1_SEND_CLIENT_VERIFY"},
+{ERR_FUNC(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST), "DTLS1_SEND_HELLO_VERIFY_REQUEST"},
+{ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_CERTIFICATE), "DTLS1_SEND_SERVER_CERTIFICATE"},
+{ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_HELLO), "DTLS1_SEND_SERVER_HELLO"},
+{ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE), "DTLS1_SEND_SERVER_KEY_EXCHANGE"},
+{ERR_FUNC(SSL_F_DTLS1_WRITE_APP_DATA_BYTES), "DTLS1_WRITE_APP_DATA_BYTES"},
+{ERR_FUNC(SSL_F_GET_CLIENT_FINISHED), "GET_CLIENT_FINISHED"},
+{ERR_FUNC(SSL_F_GET_CLIENT_HELLO), "GET_CLIENT_HELLO"},
+{ERR_FUNC(SSL_F_GET_CLIENT_MASTER_KEY), "GET_CLIENT_MASTER_KEY"},
+{ERR_FUNC(SSL_F_GET_SERVER_FINISHED), "GET_SERVER_FINISHED"},
+{ERR_FUNC(SSL_F_GET_SERVER_HELLO), "GET_SERVER_HELLO"},
+{ERR_FUNC(SSL_F_GET_SERVER_VERIFY), "GET_SERVER_VERIFY"},
+{ERR_FUNC(SSL_F_I2D_SSL_SESSION), "i2d_SSL_SESSION"},
+{ERR_FUNC(SSL_F_READ_N), "READ_N"},
+{ERR_FUNC(SSL_F_REQUEST_CERTIFICATE), "REQUEST_CERTIFICATE"},
+{ERR_FUNC(SSL_F_SERVER_FINISH), "SERVER_FINISH"},
+{ERR_FUNC(SSL_F_SERVER_HELLO), "SERVER_HELLO"},
+{ERR_FUNC(SSL_F_SERVER_VERIFY), "SERVER_VERIFY"},
+{ERR_FUNC(SSL_F_SSL23_ACCEPT), "SSL23_ACCEPT"},
+{ERR_FUNC(SSL_F_SSL23_CLIENT_HELLO), "SSL23_CLIENT_HELLO"},
+{ERR_FUNC(SSL_F_SSL23_CONNECT), "SSL23_CONNECT"},
+{ERR_FUNC(SSL_F_SSL23_GET_CLIENT_HELLO), "SSL23_GET_CLIENT_HELLO"},
+{ERR_FUNC(SSL_F_SSL23_GET_SERVER_HELLO), "SSL23_GET_SERVER_HELLO"},
+{ERR_FUNC(SSL_F_SSL23_PEEK), "SSL23_PEEK"},
+{ERR_FUNC(SSL_F_SSL23_READ), "SSL23_READ"},
+{ERR_FUNC(SSL_F_SSL23_WRITE), "SSL23_WRITE"},
+{ERR_FUNC(SSL_F_SSL2_ACCEPT), "SSL2_ACCEPT"},
+{ERR_FUNC(SSL_F_SSL2_CONNECT), "SSL2_CONNECT"},
+{ERR_FUNC(SSL_F_SSL2_ENC_INIT), "SSL2_ENC_INIT"},
+{ERR_FUNC(SSL_F_SSL2_GENERATE_KEY_MATERIAL), "SSL2_GENERATE_KEY_MATERIAL"},
+{ERR_FUNC(SSL_F_SSL2_PEEK), "SSL2_PEEK"},
+{ERR_FUNC(SSL_F_SSL2_READ), "SSL2_READ"},
+{ERR_FUNC(SSL_F_SSL2_READ_INTERNAL), "SSL2_READ_INTERNAL"},
+{ERR_FUNC(SSL_F_SSL2_SET_CERTIFICATE), "SSL2_SET_CERTIFICATE"},
+{ERR_FUNC(SSL_F_SSL2_WRITE), "SSL2_WRITE"},
+{ERR_FUNC(SSL_F_SSL3_ACCEPT), "SSL3_ACCEPT"},
+{ERR_FUNC(SSL_F_SSL3_ADD_CERT_TO_BUF), "SSL3_ADD_CERT_TO_BUF"},
+{ERR_FUNC(SSL_F_SSL3_CALLBACK_CTRL), "SSL3_CALLBACK_CTRL"},
+{ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "SSL3_CHANGE_CIPHER_STATE"},
+{ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM), "SSL3_CHECK_CERT_AND_ALGORITHM"},
+{ERR_FUNC(SSL_F_SSL3_CHECK_CLIENT_HELLO), "SSL3_CHECK_CLIENT_HELLO"},
+{ERR_FUNC(SSL_F_SSL3_CLIENT_HELLO), "SSL3_CLIENT_HELLO"},
+{ERR_FUNC(SSL_F_SSL3_CONNECT), "SSL3_CONNECT"},
+{ERR_FUNC(SSL_F_SSL3_CTRL), "SSL3_CTRL"},
+{ERR_FUNC(SSL_F_SSL3_CTX_CTRL), "SSL3_CTX_CTRL"},
+{ERR_FUNC(SSL_F_SSL3_DIGEST_CACHED_RECORDS), "SSL3_DIGEST_CACHED_RECORDS"},
+{ERR_FUNC(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC), "SSL3_DO_CHANGE_CIPHER_SPEC"},
+{ERR_FUNC(SSL_F_SSL3_ENC), "SSL3_ENC"},
+{ERR_FUNC(SSL_F_SSL3_GENERATE_KEY_BLOCK), "SSL3_GENERATE_KEY_BLOCK"},
+{ERR_FUNC(SSL_F_SSL3_GET_CERTIFICATE_REQUEST), "SSL3_GET_CERTIFICATE_REQUEST"},
+{ERR_FUNC(SSL_F_SSL3_GET_CERT_STATUS), "SSL3_GET_CERT_STATUS"},
+{ERR_FUNC(SSL_F_SSL3_GET_CERT_VERIFY), "SSL3_GET_CERT_VERIFY"},
+{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_CERTIFICATE), "SSL3_GET_CLIENT_CERTIFICATE"},
+{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_HELLO), "SSL3_GET_CLIENT_HELLO"},
+{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE), "SSL3_GET_CLIENT_KEY_EXCHANGE"},
+{ERR_FUNC(SSL_F_SSL3_GET_FINISHED), "SSL3_GET_FINISHED"},
+{ERR_FUNC(SSL_F_SSL3_GET_KEY_EXCHANGE), "SSL3_GET_KEY_EXCHANGE"},
+{ERR_FUNC(SSL_F_SSL3_GET_MESSAGE), "SSL3_GET_MESSAGE"},
+{ERR_FUNC(SSL_F_SSL3_GET_NEW_SESSION_TICKET), "SSL3_GET_NEW_SESSION_TICKET"},
+{ERR_FUNC(SSL_F_SSL3_GET_NEXT_PROTO), "SSL3_GET_NEXT_PROTO"},
+{ERR_FUNC(SSL_F_SSL3_GET_RECORD), "SSL3_GET_RECORD"},
+{ERR_FUNC(SSL_F_SSL3_GET_SERVER_CERTIFICATE), "SSL3_GET_SERVER_CERTIFICATE"},
+{ERR_FUNC(SSL_F_SSL3_GET_SERVER_DONE), "SSL3_GET_SERVER_DONE"},
+{ERR_FUNC(SSL_F_SSL3_GET_SERVER_HELLO), "SSL3_GET_SERVER_HELLO"},
+{ERR_FUNC(SSL_F_SSL3_HANDSHAKE_MAC), "ssl3_handshake_mac"},
+{ERR_FUNC(SSL_F_SSL3_NEW_SESSION_TICKET), "SSL3_NEW_SESSION_TICKET"},
+{ERR_FUNC(SSL_F_SSL3_OUTPUT_CERT_CHAIN), "SSL3_OUTPUT_CERT_CHAIN"},
+{ERR_FUNC(SSL_F_SSL3_PEEK), "SSL3_PEEK"},
+{ERR_FUNC(SSL_F_SSL3_READ_BYTES), "SSL3_READ_BYTES"},
+{ERR_FUNC(SSL_F_SSL3_READ_N), "SSL3_READ_N"},
+{ERR_FUNC(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST), "SSL3_SEND_CERTIFICATE_REQUEST"},
+{ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE), "SSL3_SEND_CLIENT_CERTIFICATE"},
+{ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE), "SSL3_SEND_CLIENT_KEY_EXCHANGE"},
+{ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_VERIFY), "SSL3_SEND_CLIENT_VERIFY"},
+{ERR_FUNC(SSL_F_SSL3_SEND_SERVER_CERTIFICATE), "SSL3_SEND_SERVER_CERTIFICATE"},
+{ERR_FUNC(SSL_F_SSL3_SEND_SERVER_HELLO), "SSL3_SEND_SERVER_HELLO"},
+{ERR_FUNC(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE), "SSL3_SEND_SERVER_KEY_EXCHANGE"},
+{ERR_FUNC(SSL_F_SSL3_SETUP_KEY_BLOCK), "SSL3_SETUP_KEY_BLOCK"},
+{ERR_FUNC(SSL_F_SSL3_SETUP_READ_BUFFER), "SSL3_SETUP_READ_BUFFER"},
+{ERR_FUNC(SSL_F_SSL3_SETUP_WRITE_BUFFER), "SSL3_SETUP_WRITE_BUFFER"},
+{ERR_FUNC(SSL_F_SSL3_WRITE_BYTES), "SSL3_WRITE_BYTES"},
+{ERR_FUNC(SSL_F_SSL3_WRITE_PENDING), "SSL3_WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT"},
+{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT), "SSL_ADD_CLIENTHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT), "SSL_ADD_CLIENTHELLO_USE_SRTP_EXT"},
+{ERR_FUNC(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK), "SSL_add_dir_cert_subjects_to_stack"},
+{ERR_FUNC(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK), "SSL_add_file_cert_subjects_to_stack"},
+{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT), "SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT"},
+{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT), "SSL_ADD_SERVERHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT), "SSL_ADD_SERVERHELLO_USE_SRTP_EXT"},
+{ERR_FUNC(SSL_F_SSL_BAD_METHOD), "SSL_BAD_METHOD"},
+{ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST), "SSL_BYTES_TO_CIPHER_LIST"},
+{ERR_FUNC(SSL_F_SSL_CERT_DUP), "SSL_CERT_DUP"},
+{ERR_FUNC(SSL_F_SSL_CERT_INST), "SSL_CERT_INST"},
+{ERR_FUNC(SSL_F_SSL_CERT_INSTANTIATE), "SSL_CERT_INSTANTIATE"},
+{ERR_FUNC(SSL_F_SSL_CERT_NEW), "SSL_CERT_NEW"},
+{ERR_FUNC(SSL_F_SSL_CHECK_PRIVATE_KEY), "SSL_check_private_key"},
+{ERR_FUNC(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT), "SSL_CHECK_SERVERHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG), "SSL_CHECK_SRVR_ECC_CERT_AND_ALG"},
+{ERR_FUNC(SSL_F_SSL_CIPHER_PROCESS_RULESTR), "SSL_CIPHER_PROCESS_RULESTR"},
+{ERR_FUNC(SSL_F_SSL_CIPHER_STRENGTH_SORT), "SSL_CIPHER_STRENGTH_SORT"},
+{ERR_FUNC(SSL_F_SSL_CLEAR), "SSL_clear"},
+{ERR_FUNC(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD), "SSL_COMP_add_compression_method"},
+{ERR_FUNC(SSL_F_SSL_CREATE_CIPHER_LIST), "SSL_CREATE_CIPHER_LIST"},
+{ERR_FUNC(SSL_F_SSL_CTRL), "SSL_ctrl"},
+{ERR_FUNC(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY), "SSL_CTX_check_private_key"},
+{ERR_FUNC(SSL_F_SSL_CTX_MAKE_PROFILES), "SSL_CTX_MAKE_PROFILES"},
+{ERR_FUNC(SSL_F_SSL_CTX_NEW), "SSL_CTX_new"},
+{ERR_FUNC(SSL_F_SSL_CTX_SET_CIPHER_LIST), "SSL_CTX_set_cipher_list"},
+{ERR_FUNC(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE), "SSL_CTX_set_client_cert_engine"},
+{ERR_FUNC(SSL_F_SSL_CTX_SET_PURPOSE), "SSL_CTX_set_purpose"},
+{ERR_FUNC(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT), "SSL_CTX_set_session_id_context"},
+{ERR_FUNC(SSL_F_SSL_CTX_SET_SSL_VERSION), "SSL_CTX_set_ssl_version"},
+{ERR_FUNC(SSL_F_SSL_CTX_SET_TRUST), "SSL_CTX_set_trust"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE), "SSL_CTX_use_certificate"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1), "SSL_CTX_use_certificate_ASN1"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE), "SSL_CTX_use_certificate_chain_file"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE), "SSL_CTX_use_certificate_file"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY), "SSL_CTX_use_PrivateKey"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1), "SSL_CTX_use_PrivateKey_ASN1"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE), "SSL_CTX_use_PrivateKey_file"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT), "SSL_CTX_use_psk_identity_hint"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY), "SSL_CTX_use_RSAPrivateKey"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1), "SSL_CTX_use_RSAPrivateKey_ASN1"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE), "SSL_CTX_use_RSAPrivateKey_file"},
+{ERR_FUNC(SSL_F_SSL_DO_HANDSHAKE), "SSL_do_handshake"},
+{ERR_FUNC(SSL_F_SSL_GET_NEW_SESSION), "SSL_GET_NEW_SESSION"},
+{ERR_FUNC(SSL_F_SSL_GET_PREV_SESSION), "SSL_GET_PREV_SESSION"},
+{ERR_FUNC(SSL_F_SSL_GET_SERVER_SEND_CERT), "SSL_GET_SERVER_SEND_CERT"},
+{ERR_FUNC(SSL_F_SSL_GET_SERVER_SEND_PKEY), "SSL_GET_SERVER_SEND_PKEY"},
+{ERR_FUNC(SSL_F_SSL_GET_SIGN_PKEY), "SSL_GET_SIGN_PKEY"},
+{ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "SSL_INIT_WBIO_BUFFER"},
+{ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE), "SSL_load_client_CA_file"},
+{ERR_FUNC(SSL_F_SSL_NEW), "SSL_new"},
+{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT"},
+{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT), "SSL_PARSE_CLIENTHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT), "SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT"},
+{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT), "SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT"},
+{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT), "SSL_PARSE_SERVERHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT), "SSL_PARSE_SERVERHELLO_USE_SRTP_EXT"},
+{ERR_FUNC(SSL_F_SSL_PEEK), "SSL_peek"},
+{ERR_FUNC(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT), "SSL_PREPARE_CLIENTHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT), "SSL_PREPARE_SERVERHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_READ), "SSL_read"},
+{ERR_FUNC(SSL_F_SSL_RSA_PRIVATE_DECRYPT), "SSL_RSA_PRIVATE_DECRYPT"},
+{ERR_FUNC(SSL_F_SSL_RSA_PUBLIC_ENCRYPT), "SSL_RSA_PUBLIC_ENCRYPT"},
+{ERR_FUNC(SSL_F_SSL_SESSION_NEW), "SSL_SESSION_new"},
+{ERR_FUNC(SSL_F_SSL_SESSION_PRINT_FP), "SSL_SESSION_print_fp"},
+{ERR_FUNC(SSL_F_SSL_SESSION_SET1_ID_CONTEXT), "SSL_SESSION_set1_id_context"},
+{ERR_FUNC(SSL_F_SSL_SESS_CERT_NEW), "SSL_SESS_CERT_NEW"},
+{ERR_FUNC(SSL_F_SSL_SET_CERT), "SSL_SET_CERT"},
+{ERR_FUNC(SSL_F_SSL_SET_CIPHER_LIST), "SSL_set_cipher_list"},
+{ERR_FUNC(SSL_F_SSL_SET_FD), "SSL_set_fd"},
+{ERR_FUNC(SSL_F_SSL_SET_PKEY), "SSL_SET_PKEY"},
+{ERR_FUNC(SSL_F_SSL_SET_PURPOSE), "SSL_set_purpose"},
+{ERR_FUNC(SSL_F_SSL_SET_RFD), "SSL_set_rfd"},
+{ERR_FUNC(SSL_F_SSL_SET_SESSION), "SSL_set_session"},
+{ERR_FUNC(SSL_F_SSL_SET_SESSION_ID_CONTEXT), "SSL_set_session_id_context"},
+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
+{ERR_FUNC(SSL_F_SSL_SET_TRUST), "SSL_set_trust"},
+{ERR_FUNC(SSL_F_SSL_SET_WFD), "SSL_set_wfd"},
+{ERR_FUNC(SSL_F_SSL_SHUTDOWN), "SSL_shutdown"},
+{ERR_FUNC(SSL_F_SSL_SRP_CTX_INIT), "SSL_SRP_CTX_init"},
+{ERR_FUNC(SSL_F_SSL_UNDEFINED_CONST_FUNCTION), "SSL_UNDEFINED_CONST_FUNCTION"},
+{ERR_FUNC(SSL_F_SSL_UNDEFINED_FUNCTION), "SSL_UNDEFINED_FUNCTION"},
+{ERR_FUNC(SSL_F_SSL_UNDEFINED_VOID_FUNCTION), "SSL_UNDEFINED_VOID_FUNCTION"},
+{ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE), "SSL_use_certificate"},
+{ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_ASN1), "SSL_use_certificate_ASN1"},
+{ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_FILE), "SSL_use_certificate_file"},
+{ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY), "SSL_use_PrivateKey"},
+{ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY_ASN1), "SSL_use_PrivateKey_ASN1"},
+{ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY_FILE), "SSL_use_PrivateKey_file"},
+{ERR_FUNC(SSL_F_SSL_USE_PSK_IDENTITY_HINT), "SSL_use_psk_identity_hint"},
+{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY), "SSL_use_RSAPrivateKey"},
+{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1), "SSL_use_RSAPrivateKey_ASN1"},
+{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), "SSL_use_RSAPrivateKey_file"},
+{ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "SSL_VERIFY_CERT_CHAIN"},
+{ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"},
+{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"},
+{ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "TLS1_CHANGE_CIPHER_STATE"},
+{ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
+{ERR_FUNC(SSL_F_TLS1_EXPORT_KEYING_MATERIAL), "TLS1_EXPORT_KEYING_MATERIAL"},
+{ERR_FUNC(SSL_F_TLS1_HEARTBEAT), "SSL_F_TLS1_HEARTBEAT"},
+{ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), "TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), "TLS1_PREPARE_SERVERHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
+{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
+{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{0,NULL}
+ };
+
+static ERR_STRING_DATA SSL_str_reasons[]=
+ {
+{ERR_REASON(SSL_R_APP_DATA_IN_HANDSHAKE) ,"app data in handshake"},
+{ERR_REASON(SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT),"attempt to reuse session in different context"},
+{ERR_REASON(SSL_R_BAD_ALERT_RECORD) ,"bad alert record"},
+{ERR_REASON(SSL_R_BAD_AUTHENTICATION_TYPE),"bad authentication type"},
+{ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC),"bad change cipher spec"},
+{ERR_REASON(SSL_R_BAD_CHECKSUM) ,"bad checksum"},
+{ERR_REASON(SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),"bad data returned by callback"},
+{ERR_REASON(SSL_R_BAD_DECOMPRESSION) ,"bad decompression"},
+{ERR_REASON(SSL_R_BAD_DH_G_LENGTH) ,"bad dh g length"},
+{ERR_REASON(SSL_R_BAD_DH_PUB_KEY_LENGTH) ,"bad dh pub key length"},
+{ERR_REASON(SSL_R_BAD_DH_P_LENGTH) ,"bad dh p length"},
+{ERR_REASON(SSL_R_BAD_DIGEST_LENGTH) ,"bad digest length"},
+{ERR_REASON(SSL_R_BAD_DSA_SIGNATURE) ,"bad dsa signature"},
+{ERR_REASON(SSL_R_BAD_ECC_CERT) ,"bad ecc cert"},
+{ERR_REASON(SSL_R_BAD_ECDSA_SIGNATURE) ,"bad ecdsa signature"},
+{ERR_REASON(SSL_R_BAD_ECPOINT) ,"bad ecpoint"},
+{ERR_REASON(SSL_R_BAD_HANDSHAKE_LENGTH) ,"bad handshake length"},
+{ERR_REASON(SSL_R_BAD_HELLO_REQUEST) ,"bad hello request"},
+{ERR_REASON(SSL_R_BAD_LENGTH) ,"bad length"},
+{ERR_REASON(SSL_R_BAD_MAC_DECODE) ,"bad mac decode"},
+{ERR_REASON(SSL_R_BAD_MAC_LENGTH) ,"bad mac length"},
+{ERR_REASON(SSL_R_BAD_MESSAGE_TYPE) ,"bad message type"},
+{ERR_REASON(SSL_R_BAD_PACKET_LENGTH) ,"bad packet length"},
+{ERR_REASON(SSL_R_BAD_PROTOCOL_VERSION_NUMBER),"bad protocol version number"},
+{ERR_REASON(SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH),"bad psk identity hint length"},
+{ERR_REASON(SSL_R_BAD_RESPONSE_ARGUMENT) ,"bad response argument"},
+{ERR_REASON(SSL_R_BAD_RSA_DECRYPT) ,"bad rsa decrypt"},
+{ERR_REASON(SSL_R_BAD_RSA_ENCRYPT) ,"bad rsa encrypt"},
+{ERR_REASON(SSL_R_BAD_RSA_E_LENGTH) ,"bad rsa e length"},
+{ERR_REASON(SSL_R_BAD_RSA_MODULUS_LENGTH),"bad rsa modulus length"},
+{ERR_REASON(SSL_R_BAD_RSA_SIGNATURE) ,"bad rsa signature"},
+{ERR_REASON(SSL_R_BAD_SIGNATURE) ,"bad signature"},
+{ERR_REASON(SSL_R_BAD_SRP_A_LENGTH) ,"bad srp a length"},
+{ERR_REASON(SSL_R_BAD_SRP_B_LENGTH) ,"bad srp b length"},
+{ERR_REASON(SSL_R_BAD_SRP_G_LENGTH) ,"bad srp g length"},
+{ERR_REASON(SSL_R_BAD_SRP_N_LENGTH) ,"bad srp n length"},
+{ERR_REASON(SSL_R_BAD_SRP_S_LENGTH) ,"bad srp s length"},
+{ERR_REASON(SSL_R_BAD_SRTP_MKI_VALUE) ,"bad srtp mki value"},
+{ERR_REASON(SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST),"bad srtp protection profile list"},
+{ERR_REASON(SSL_R_BAD_SSL_FILETYPE) ,"bad ssl filetype"},
+{ERR_REASON(SSL_R_BAD_SSL_SESSION_ID_LENGTH),"bad ssl session id length"},
+{ERR_REASON(SSL_R_BAD_STATE) ,"bad state"},
+{ERR_REASON(SSL_R_BAD_WRITE_RETRY) ,"bad write retry"},
+{ERR_REASON(SSL_R_BIO_NOT_SET) ,"bio not set"},
+{ERR_REASON(SSL_R_BLOCK_CIPHER_PAD_IS_WRONG),"block cipher pad is wrong"},
+{ERR_REASON(SSL_R_BN_LIB) ,"bn lib"},
+{ERR_REASON(SSL_R_CA_DN_LENGTH_MISMATCH) ,"ca dn length mismatch"},
+{ERR_REASON(SSL_R_CA_DN_TOO_LONG) ,"ca dn too long"},
+{ERR_REASON(SSL_R_CCS_RECEIVED_EARLY) ,"ccs received early"},
+{ERR_REASON(SSL_R_CERTIFICATE_VERIFY_FAILED),"certificate verify failed"},
+{ERR_REASON(SSL_R_CERT_LENGTH_MISMATCH) ,"cert length mismatch"},
+{ERR_REASON(SSL_R_CHALLENGE_IS_DIFFERENT),"challenge is different"},
+{ERR_REASON(SSL_R_CIPHER_CODE_WRONG_LENGTH),"cipher code wrong length"},
+{ERR_REASON(SSL_R_CIPHER_OR_HASH_UNAVAILABLE),"cipher or hash unavailable"},
+{ERR_REASON(SSL_R_CIPHER_TABLE_SRC_ERROR),"cipher table src error"},
+{ERR_REASON(SSL_R_CLIENTHELLO_TLSEXT) ,"clienthello tlsext"},
+{ERR_REASON(SSL_R_COMPRESSED_LENGTH_TOO_LONG),"compressed length too long"},
+{ERR_REASON(SSL_R_COMPRESSION_DISABLED) ,"compression disabled"},
+{ERR_REASON(SSL_R_COMPRESSION_FAILURE) ,"compression failure"},
+{ERR_REASON(SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE),"compression id not within private range"},
+{ERR_REASON(SSL_R_COMPRESSION_LIBRARY_ERROR),"compression library error"},
+{ERR_REASON(SSL_R_CONNECTION_ID_IS_DIFFERENT),"connection id is different"},
+{ERR_REASON(SSL_R_CONNECTION_TYPE_NOT_SET),"connection type not set"},
+{ERR_REASON(SSL_R_COOKIE_MISMATCH) ,"cookie mismatch"},
+{ERR_REASON(SSL_R_DATA_BETWEEN_CCS_AND_FINISHED),"data between ccs and finished"},
+{ERR_REASON(SSL_R_DATA_LENGTH_TOO_LONG) ,"data length too long"},
+{ERR_REASON(SSL_R_DECRYPTION_FAILED) ,"decryption failed"},
+{ERR_REASON(SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC),"decryption failed or bad record mac"},
+{ERR_REASON(SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG),"dh public value length is wrong"},
+{ERR_REASON(SSL_R_DIGEST_CHECK_FAILED) ,"digest check failed"},
+{ERR_REASON(SSL_R_DTLS_MESSAGE_TOO_BIG) ,"dtls message too big"},
+{ERR_REASON(SSL_R_DUPLICATE_COMPRESSION_ID),"duplicate compression id"},
+{ERR_REASON(SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT),"ecc cert not for key agreement"},
+{ERR_REASON(SSL_R_ECC_CERT_NOT_FOR_SIGNING),"ecc cert not for signing"},
+{ERR_REASON(SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE),"ecc cert should have rsa signature"},
+{ERR_REASON(SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE),"ecc cert should have sha1 signature"},
+{ERR_REASON(SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER),"ecgroup too large for cipher"},
+{ERR_REASON(SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST),"empty srtp protection profile list"},
+{ERR_REASON(SSL_R_ENCRYPTED_LENGTH_TOO_LONG),"encrypted length too long"},
+{ERR_REASON(SSL_R_ERROR_GENERATING_TMP_RSA_KEY),"error generating tmp rsa key"},
+{ERR_REASON(SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST),"error in received cipher list"},
+{ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE),"excessive message size"},
+{ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE) ,"extra data in message"},
+{ERR_REASON(SSL_R_GOT_A_FIN_BEFORE_A_CCS),"got a fin before a ccs"},
+{ERR_REASON(SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS),"got next proto before a ccs"},
+{ERR_REASON(SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION),"got next proto without seeing extension"},
+{ERR_REASON(SSL_R_HTTPS_PROXY_REQUEST) ,"https proxy request"},
+{ERR_REASON(SSL_R_HTTP_REQUEST) ,"http request"},
+{ERR_REASON(SSL_R_ILLEGAL_PADDING) ,"illegal padding"},
+{ERR_REASON(SSL_R_INCONSISTENT_COMPRESSION),"inconsistent compression"},
+{ERR_REASON(SSL_R_INVALID_CHALLENGE_LENGTH),"invalid challenge length"},
+{ERR_REASON(SSL_R_INVALID_COMMAND) ,"invalid command"},
+{ERR_REASON(SSL_R_INVALID_COMPRESSION_ALGORITHM),"invalid compression algorithm"},
+{ERR_REASON(SSL_R_INVALID_PURPOSE) ,"invalid purpose"},
+{ERR_REASON(SSL_R_INVALID_SRP_USERNAME) ,"invalid srp username"},
+{ERR_REASON(SSL_R_INVALID_STATUS_RESPONSE),"invalid status response"},
+{ERR_REASON(SSL_R_INVALID_TICKET_KEYS_LENGTH),"invalid ticket keys length"},
+{ERR_REASON(SSL_R_INVALID_TRUST) ,"invalid trust"},
+{ERR_REASON(SSL_R_KEY_ARG_TOO_LONG) ,"key arg too long"},
+{ERR_REASON(SSL_R_KRB5) ,"krb5"},
+{ERR_REASON(SSL_R_KRB5_C_CC_PRINC) ,"krb5 client cc principal (no tkt?)"},
+{ERR_REASON(SSL_R_KRB5_C_GET_CRED) ,"krb5 client get cred"},
+{ERR_REASON(SSL_R_KRB5_C_INIT) ,"krb5 client init"},
+{ERR_REASON(SSL_R_KRB5_C_MK_REQ) ,"krb5 client mk_req (expired tkt?)"},
+{ERR_REASON(SSL_R_KRB5_S_BAD_TICKET) ,"krb5 server bad ticket"},
+{ERR_REASON(SSL_R_KRB5_S_INIT) ,"krb5 server init"},
+{ERR_REASON(SSL_R_KRB5_S_RD_REQ) ,"krb5 server rd_req (keytab perms?)"},
+{ERR_REASON(SSL_R_KRB5_S_TKT_EXPIRED) ,"krb5 server tkt expired"},
+{ERR_REASON(SSL_R_KRB5_S_TKT_NYV) ,"krb5 server tkt not yet valid"},
+{ERR_REASON(SSL_R_KRB5_S_TKT_SKEW) ,"krb5 server tkt skew"},
+{ERR_REASON(SSL_R_LENGTH_MISMATCH) ,"length mismatch"},
+{ERR_REASON(SSL_R_LENGTH_TOO_SHORT) ,"length too short"},
+{ERR_REASON(SSL_R_LIBRARY_BUG) ,"library bug"},
+{ERR_REASON(SSL_R_LIBRARY_HAS_NO_CIPHERS),"library has no ciphers"},
+{ERR_REASON(SSL_R_MESSAGE_TOO_LONG) ,"message too long"},
+{ERR_REASON(SSL_R_MISSING_DH_DSA_CERT) ,"missing dh dsa cert"},
+{ERR_REASON(SSL_R_MISSING_DH_KEY) ,"missing dh key"},
+{ERR_REASON(SSL_R_MISSING_DH_RSA_CERT) ,"missing dh rsa cert"},
+{ERR_REASON(SSL_R_MISSING_DSA_SIGNING_CERT),"missing dsa signing cert"},
+{ERR_REASON(SSL_R_MISSING_EXPORT_TMP_DH_KEY),"missing export tmp dh key"},
+{ERR_REASON(SSL_R_MISSING_EXPORT_TMP_RSA_KEY),"missing export tmp rsa key"},
+{ERR_REASON(SSL_R_MISSING_RSA_CERTIFICATE),"missing rsa certificate"},
+{ERR_REASON(SSL_R_MISSING_RSA_ENCRYPTING_CERT),"missing rsa encrypting cert"},
+{ERR_REASON(SSL_R_MISSING_RSA_SIGNING_CERT),"missing rsa signing cert"},
+{ERR_REASON(SSL_R_MISSING_SRP_PARAM) ,"can't find SRP server param"},
+{ERR_REASON(SSL_R_MISSING_TMP_DH_KEY) ,"missing tmp dh key"},
+{ERR_REASON(SSL_R_MISSING_TMP_ECDH_KEY) ,"missing tmp ecdh key"},
+{ERR_REASON(SSL_R_MISSING_TMP_RSA_KEY) ,"missing tmp rsa key"},
+{ERR_REASON(SSL_R_MISSING_TMP_RSA_PKEY) ,"missing tmp rsa pkey"},
+{ERR_REASON(SSL_R_MISSING_VERIFY_MESSAGE),"missing verify message"},
+{ERR_REASON(SSL_R_MULTIPLE_SGC_RESTARTS) ,"multiple sgc restarts"},
+{ERR_REASON(SSL_R_NON_SSLV2_INITIAL_PACKET),"non sslv2 initial packet"},
+{ERR_REASON(SSL_R_NO_CERTIFICATES_RETURNED),"no certificates returned"},
+{ERR_REASON(SSL_R_NO_CERTIFICATE_ASSIGNED),"no certificate assigned"},
+{ERR_REASON(SSL_R_NO_CERTIFICATE_RETURNED),"no certificate returned"},
+{ERR_REASON(SSL_R_NO_CERTIFICATE_SET) ,"no certificate set"},
+{ERR_REASON(SSL_R_NO_CERTIFICATE_SPECIFIED),"no certificate specified"},
+{ERR_REASON(SSL_R_NO_CIPHERS_AVAILABLE) ,"no ciphers available"},
+{ERR_REASON(SSL_R_NO_CIPHERS_PASSED) ,"no ciphers passed"},
+{ERR_REASON(SSL_R_NO_CIPHERS_SPECIFIED) ,"no ciphers specified"},
+{ERR_REASON(SSL_R_NO_CIPHER_LIST) ,"no cipher list"},
+{ERR_REASON(SSL_R_NO_CIPHER_MATCH) ,"no cipher match"},
+{ERR_REASON(SSL_R_NO_CLIENT_CERT_METHOD) ,"no client cert method"},
+{ERR_REASON(SSL_R_NO_CLIENT_CERT_RECEIVED),"no client cert received"},
+{ERR_REASON(SSL_R_NO_COMPRESSION_SPECIFIED),"no compression specified"},
+{ERR_REASON(SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER),"Peer haven't sent GOST certificate, required for selected ciphersuite"},
+{ERR_REASON(SSL_R_NO_METHOD_SPECIFIED) ,"no method specified"},
+{ERR_REASON(SSL_R_NO_PRIVATEKEY) ,"no privatekey"},
+{ERR_REASON(SSL_R_NO_PRIVATE_KEY_ASSIGNED),"no private key assigned"},
+{ERR_REASON(SSL_R_NO_PROTOCOLS_AVAILABLE),"no protocols available"},
+{ERR_REASON(SSL_R_NO_PUBLICKEY) ,"no publickey"},
+{ERR_REASON(SSL_R_NO_RENEGOTIATION) ,"no renegotiation"},
+{ERR_REASON(SSL_R_NO_REQUIRED_DIGEST) ,"digest requred for handshake isn't computed"},
+{ERR_REASON(SSL_R_NO_SHARED_CIPHER) ,"no shared cipher"},
+{ERR_REASON(SSL_R_NO_SRTP_PROFILES) ,"no srtp profiles"},
+{ERR_REASON(SSL_R_NO_VERIFY_CALLBACK) ,"no verify callback"},
+{ERR_REASON(SSL_R_NULL_SSL_CTX) ,"null ssl ctx"},
+{ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED),"null ssl method passed"},
+{ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
+{ERR_REASON(SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED),"old session compression algorithm not returned"},
+{ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
+{ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG),"opaque PRF input too long"},
+{ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
+{ERR_REASON(SSL_R_PARSE_TLSEXT) ,"parse tlsext"},
+{ERR_REASON(SSL_R_PATH_TOO_LONG) ,"path too long"},
+{ERR_REASON(SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE),"peer did not return a certificate"},
+{ERR_REASON(SSL_R_PEER_ERROR) ,"peer error"},
+{ERR_REASON(SSL_R_PEER_ERROR_CERTIFICATE),"peer error certificate"},
+{ERR_REASON(SSL_R_PEER_ERROR_NO_CERTIFICATE),"peer error no certificate"},
+{ERR_REASON(SSL_R_PEER_ERROR_NO_CIPHER) ,"peer error no cipher"},
+{ERR_REASON(SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE),"peer error unsupported certificate type"},
+{ERR_REASON(SSL_R_PRE_MAC_LENGTH_TOO_LONG),"pre mac length too long"},
+{ERR_REASON(SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS),"problems mapping cipher functions"},
+{ERR_REASON(SSL_R_PROTOCOL_IS_SHUTDOWN) ,"protocol is shutdown"},
+{ERR_REASON(SSL_R_PSK_IDENTITY_NOT_FOUND),"psk identity not found"},
+{ERR_REASON(SSL_R_PSK_NO_CLIENT_CB) ,"psk no client cb"},
+{ERR_REASON(SSL_R_PSK_NO_SERVER_CB) ,"psk no server cb"},
+{ERR_REASON(SSL_R_PUBLIC_KEY_ENCRYPT_ERROR),"public key encrypt error"},
+{ERR_REASON(SSL_R_PUBLIC_KEY_IS_NOT_RSA) ,"public key is not rsa"},
+{ERR_REASON(SSL_R_PUBLIC_KEY_NOT_RSA) ,"public key not rsa"},
+{ERR_REASON(SSL_R_READ_BIO_NOT_SET) ,"read bio not set"},
+{ERR_REASON(SSL_R_READ_TIMEOUT_EXPIRED) ,"read timeout expired"},
+{ERR_REASON(SSL_R_READ_WRONG_PACKET_TYPE),"read wrong packet type"},
+{ERR_REASON(SSL_R_RECORD_LENGTH_MISMATCH),"record length mismatch"},
+{ERR_REASON(SSL_R_RECORD_TOO_LARGE) ,"record too large"},
+{ERR_REASON(SSL_R_RECORD_TOO_SMALL) ,"record too small"},
+{ERR_REASON(SSL_R_RENEGOTIATE_EXT_TOO_LONG),"renegotiate ext too long"},
+{ERR_REASON(SSL_R_RENEGOTIATION_ENCODING_ERR),"renegotiation encoding err"},
+{ERR_REASON(SSL_R_RENEGOTIATION_MISMATCH),"renegotiation mismatch"},
+{ERR_REASON(SSL_R_REQUIRED_CIPHER_MISSING),"required cipher missing"},
+{ERR_REASON(SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING),"required compresssion algorithm missing"},
+{ERR_REASON(SSL_R_REUSE_CERT_LENGTH_NOT_ZERO),"reuse cert length not zero"},
+{ERR_REASON(SSL_R_REUSE_CERT_TYPE_NOT_ZERO),"reuse cert type not zero"},
+{ERR_REASON(SSL_R_REUSE_CIPHER_LIST_NOT_ZERO),"reuse cipher list not zero"},
+{ERR_REASON(SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING),"scsv received when renegotiating"},
+{ERR_REASON(SSL_R_SERVERHELLO_TLSEXT) ,"serverhello tlsext"},
+{ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),"session id context uninitialized"},
+{ERR_REASON(SSL_R_SHORT_READ) ,"short read"},
+{ERR_REASON(SSL_R_SIGNATURE_ALGORITHMS_ERROR),"signature algorithms error"},
+{ERR_REASON(SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),"signature for non signing certificate"},
+{ERR_REASON(SSL_R_SRP_A_CALC) ,"error with the srp params"},
+{ERR_REASON(SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES),"srtp could not allocate profiles"},
+{ERR_REASON(SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG),"srtp protection profile list too long"},
+{ERR_REASON(SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE),"srtp unknown protection profile"},
+{ERR_REASON(SSL_R_SSL23_DOING_SESSION_ID_REUSE),"ssl23 doing session id reuse"},
+{ERR_REASON(SSL_R_SSL2_CONNECTION_ID_TOO_LONG),"ssl2 connection id too long"},
+{ERR_REASON(SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT),"ssl3 ext invalid ecpointformat"},
+{ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME),"ssl3 ext invalid servername"},
+{ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE),"ssl3 ext invalid servername type"},
+{ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_LONG),"ssl3 session id too long"},
+{ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_SHORT),"ssl3 session id too short"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_BAD_CERTIFICATE),"sslv3 alert bad certificate"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_BAD_RECORD_MAC),"sslv3 alert bad record mac"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED),"sslv3 alert certificate expired"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED),"sslv3 alert certificate revoked"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN),"sslv3 alert certificate unknown"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE),"sslv3 alert decompression failure"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE),"sslv3 alert handshake failure"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER),"sslv3 alert illegal parameter"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_NO_CERTIFICATE),"sslv3 alert no certificate"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE),"sslv3 alert unexpected message"},
+{ERR_REASON(SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE),"sslv3 alert unsupported certificate"},
+{ERR_REASON(SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION),"ssl ctx has no default ssl version"},
+{ERR_REASON(SSL_R_SSL_HANDSHAKE_FAILURE) ,"ssl handshake failure"},
+{ERR_REASON(SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS),"ssl library has no ciphers"},
+{ERR_REASON(SSL_R_SSL_SESSION_ID_CALLBACK_FAILED),"ssl session id callback failed"},
+{ERR_REASON(SSL_R_SSL_SESSION_ID_CONFLICT),"ssl session id conflict"},
+{ERR_REASON(SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG),"ssl session id context too long"},
+{ERR_REASON(SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH),"ssl session id has bad length"},
+{ERR_REASON(SSL_R_SSL_SESSION_ID_IS_DIFFERENT),"ssl session id is different"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_ACCESS_DENIED),"tlsv1 alert access denied"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_DECODE_ERROR),"tlsv1 alert decode error"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_DECRYPTION_FAILED),"tlsv1 alert decryption failed"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_DECRYPT_ERROR),"tlsv1 alert decrypt error"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION),"tlsv1 alert export restriction"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY),"tlsv1 alert insufficient security"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_INTERNAL_ERROR),"tlsv1 alert internal error"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION),"tlsv1 alert no renegotiation"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_PROTOCOL_VERSION),"tlsv1 alert protocol version"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_RECORD_OVERFLOW),"tlsv1 alert record overflow"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_UNKNOWN_CA),"tlsv1 alert unknown ca"},
+{ERR_REASON(SSL_R_TLSV1_ALERT_USER_CANCELLED),"tlsv1 alert user cancelled"},
+{ERR_REASON(SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE),"tlsv1 bad certificate hash value"},
+{ERR_REASON(SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE),"tlsv1 bad certificate status response"},
+{ERR_REASON(SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE),"tlsv1 certificate unobtainable"},
+{ERR_REASON(SSL_R_TLSV1_UNRECOGNIZED_NAME),"tlsv1 unrecognized name"},
+{ERR_REASON(SSL_R_TLSV1_UNSUPPORTED_EXTENSION),"tlsv1 unsupported extension"},
+{ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),"tls client cert req with anon cipher"},
+{ERR_REASON(SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT),"peer does not accept heartbeats"},
+{ERR_REASON(SSL_R_TLS_HEARTBEAT_PENDING) ,"heartbeat request already pending"},
+{ERR_REASON(SSL_R_TLS_ILLEGAL_EXPORTER_LABEL),"tls illegal exporter label"},
+{ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),"tls invalid ecpointformat list"},
+{ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST),"tls peer did not respond with certificate list"},
+{ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG),"tls rsa encrypted value length is wrong"},
+{ERR_REASON(SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER),"tried to use unsupported cipher"},
+{ERR_REASON(SSL_R_UNABLE_TO_DECODE_DH_CERTS),"unable to decode dh certs"},
+{ERR_REASON(SSL_R_UNABLE_TO_DECODE_ECDH_CERTS),"unable to decode ecdh certs"},
+{ERR_REASON(SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY),"unable to extract public key"},
+{ERR_REASON(SSL_R_UNABLE_TO_FIND_DH_PARAMETERS),"unable to find dh parameters"},
+{ERR_REASON(SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS),"unable to find ecdh parameters"},
+{ERR_REASON(SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS),"unable to find public key parameters"},
+{ERR_REASON(SSL_R_UNABLE_TO_FIND_SSL_METHOD),"unable to find ssl method"},
+{ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES),"unable to load ssl2 md5 routines"},
+{ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES),"unable to load ssl3 md5 routines"},
+{ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES),"unable to load ssl3 sha1 routines"},
+{ERR_REASON(SSL_R_UNEXPECTED_MESSAGE) ,"unexpected message"},
+{ERR_REASON(SSL_R_UNEXPECTED_RECORD) ,"unexpected record"},
+{ERR_REASON(SSL_R_UNINITIALIZED) ,"uninitialized"},
+{ERR_REASON(SSL_R_UNKNOWN_ALERT_TYPE) ,"unknown alert type"},
+{ERR_REASON(SSL_R_UNKNOWN_CERTIFICATE_TYPE),"unknown certificate type"},
+{ERR_REASON(SSL_R_UNKNOWN_CIPHER_RETURNED),"unknown cipher returned"},
+{ERR_REASON(SSL_R_UNKNOWN_CIPHER_TYPE) ,"unknown cipher type"},
+{ERR_REASON(SSL_R_UNKNOWN_DIGEST) ,"unknown digest"},
+{ERR_REASON(SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE),"unknown key exchange type"},
+{ERR_REASON(SSL_R_UNKNOWN_PKEY_TYPE) ,"unknown pkey type"},
+{ERR_REASON(SSL_R_UNKNOWN_PROTOCOL) ,"unknown protocol"},
+{ERR_REASON(SSL_R_UNKNOWN_REMOTE_ERROR_TYPE),"unknown remote error type"},
+{ERR_REASON(SSL_R_UNKNOWN_SSL_VERSION) ,"unknown ssl version"},
+{ERR_REASON(SSL_R_UNKNOWN_STATE) ,"unknown state"},
+{ERR_REASON(SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),"unsafe legacy renegotiation disabled"},
+{ERR_REASON(SSL_R_UNSUPPORTED_CIPHER) ,"unsupported cipher"},
+{ERR_REASON(SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"},
+{ERR_REASON(SSL_R_UNSUPPORTED_DIGEST_TYPE),"unsupported digest type"},
+{ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),"unsupported elliptic curve"},
+{ERR_REASON(SSL_R_UNSUPPORTED_PROTOCOL) ,"unsupported protocol"},
+{ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION),"unsupported ssl version"},
+{ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE),"unsupported status type"},
+{ERR_REASON(SSL_R_USE_SRTP_NOT_NEGOTIATED),"use srtp not negotiated"},
+{ERR_REASON(SSL_R_WRITE_BIO_NOT_SET) ,"write bio not set"},
+{ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED) ,"wrong cipher returned"},
+{ERR_REASON(SSL_R_WRONG_MESSAGE_TYPE) ,"wrong message type"},
+{ERR_REASON(SSL_R_WRONG_NUMBER_OF_KEY_BITS),"wrong number of key bits"},
+{ERR_REASON(SSL_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"},
+{ERR_REASON(SSL_R_WRONG_SIGNATURE_SIZE) ,"wrong signature size"},
+{ERR_REASON(SSL_R_WRONG_SIGNATURE_TYPE) ,"wrong signature type"},
+{ERR_REASON(SSL_R_WRONG_SSL_VERSION) ,"wrong ssl version"},
+{ERR_REASON(SSL_R_WRONG_VERSION_NUMBER) ,"wrong version number"},
+{ERR_REASON(SSL_R_X509_LIB) ,"x509 lib"},
+{ERR_REASON(SSL_R_X509_VERIFICATION_SETUP_PROBLEMS),"x509 verification setup problems"},
+{0,NULL}
+ };
+
+#endif
+
+void ERR_load_SSL_strings(void)
+ {
+#ifndef OPENSSL_NO_ERR
+
+ if (ERR_func_error_string(SSL_str_functs[0].error) == NULL)
+ {
+ ERR_load_strings(0,SSL_str_functs);
+ ERR_load_strings(0,SSL_str_reasons);
+ }
+#endif
+ }
diff --git a/drivers/builtin_openssl/ssl/ssl_err2.c b/drivers/builtin_openssl2/ssl/ssl_err2.c
index ea95a5f983..ea95a5f983 100644
--- a/drivers/builtin_openssl/ssl/ssl_err2.c
+++ b/drivers/builtin_openssl2/ssl/ssl_err2.c
diff --git a/drivers/builtin_openssl2/ssl/ssl_lib.c b/drivers/builtin_openssl2/ssl/ssl_lib.c
new file mode 100644
index 0000000000..ef6258ca9f
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/ssl_lib.c
@@ -0,0 +1,3269 @@
+/*! \file ssl/ssl_lib.c
+ * \brief Version independent SSL functions.
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#ifdef REF_CHECK
+# include <assert.h>
+#endif
+#include <stdio.h>
+#include "ssl_locl.h"
+#include "kssl_lcl.h"
+#include <openssl/objects.h>
+#include <openssl/lhash.h>
+#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/ocsp.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
+
+const char *SSL_version_str=OPENSSL_VERSION_TEXT;
+
+SSL3_ENC_METHOD ssl3_undef_enc_method={
+ /* evil casts, but these functions are only called if there's a library bug */
+ (int (*)(SSL *,int))ssl_undefined_function,
+ (int (*)(SSL *, unsigned char *, int))ssl_undefined_function,
+ ssl_undefined_function,
+ (int (*)(SSL *, unsigned char *, unsigned char *, int))ssl_undefined_function,
+ (int (*)(SSL*, int))ssl_undefined_function,
+ (int (*)(SSL *, const char*, int, unsigned char *))ssl_undefined_function,
+ 0, /* finish_mac_length */
+ (int (*)(SSL *, int, unsigned char *))ssl_undefined_function,
+ NULL, /* client_finished_label */
+ 0, /* client_finished_label_len */
+ NULL, /* server_finished_label */
+ 0, /* server_finished_label_len */
+ (int (*)(int))ssl_undefined_function,
+ (int (*)(SSL *, unsigned char *, size_t, const char *,
+ size_t, const unsigned char *, size_t,
+ int use_context)) ssl_undefined_function,
+ };
+
+int SSL_clear(SSL *s)
+ {
+
+ if (s->method == NULL)
+ {
+ SSLerr(SSL_F_SSL_CLEAR,SSL_R_NO_METHOD_SPECIFIED);
+ return(0);
+ }
+
+ if (ssl_clear_bad_session(s))
+ {
+ SSL_SESSION_free(s->session);
+ s->session=NULL;
+ }
+
+ s->error=0;
+ s->hit=0;
+ s->shutdown=0;
+
+#if 0 /* Disabled since version 1.10 of this file (early return not
+ * needed because SSL_clear is not called when doing renegotiation) */
+ /* This is set if we are doing dynamic renegotiation so keep
+ * the old cipher. It is sort of a SSL_clear_lite :-) */
+ if (s->renegotiate) return(1);
+#else
+ if (s->renegotiate)
+ {
+ SSLerr(SSL_F_SSL_CLEAR,ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+#endif
+
+ s->type=0;
+
+ s->state=SSL_ST_BEFORE|((s->server)?SSL_ST_ACCEPT:SSL_ST_CONNECT);
+
+ s->version=s->method->version;
+ s->client_version=s->version;
+ s->rwstate=SSL_NOTHING;
+ s->rstate=SSL_ST_READ_HEADER;
+#if 0
+ s->read_ahead=s->ctx->read_ahead;
+#endif
+
+ if (s->init_buf != NULL)
+ {
+ BUF_MEM_free(s->init_buf);
+ s->init_buf=NULL;
+ }
+
+ ssl_clear_cipher_ctx(s);
+ ssl_clear_hash_ctx(&s->read_hash);
+ ssl_clear_hash_ctx(&s->write_hash);
+
+ s->first_packet=0;
+
+#if 1
+ /* Check to see if we were changed into a different method, if
+ * so, revert back if we are not doing session-id reuse. */
+ if (!s->in_handshake && (s->session == NULL) && (s->method != s->ctx->method))
+ {
+ s->method->ssl_free(s);
+ s->method=s->ctx->method;
+ if (!s->method->ssl_new(s))
+ return(0);
+ }
+ else
+#endif
+ s->method->ssl_clear(s);
+ return(1);
+ }
+
+/** Used to change an SSL_CTXs default SSL method type */
+int SSL_CTX_set_ssl_version(SSL_CTX *ctx,const SSL_METHOD *meth)
+ {
+ STACK_OF(SSL_CIPHER) *sk;
+
+ ctx->method=meth;
+
+ sk=ssl_create_cipher_list(ctx->method,&(ctx->cipher_list),
+ &(ctx->cipher_list_by_id),
+ meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST);
+ if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0))
+ {
+ SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION,SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
+ return(0);
+ }
+ return(1);
+ }
+
+SSL *SSL_new(SSL_CTX *ctx)
+ {
+ SSL *s;
+
+ if (ctx == NULL)
+ {
+ SSLerr(SSL_F_SSL_NEW,SSL_R_NULL_SSL_CTX);
+ return(NULL);
+ }
+ if (ctx->method == NULL)
+ {
+ SSLerr(SSL_F_SSL_NEW,SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
+ return(NULL);
+ }
+
+ s=(SSL *)OPENSSL_malloc(sizeof(SSL));
+ if (s == NULL) goto err;
+ memset(s,0,sizeof(SSL));
+
+#ifndef OPENSSL_NO_KRB5
+ s->kssl_ctx = kssl_ctx_new();
+#endif /* OPENSSL_NO_KRB5 */
+
+ s->options=ctx->options;
+ s->mode=ctx->mode;
+ s->max_cert_list=ctx->max_cert_list;
+
+ if (ctx->cert != NULL)
+ {
+ /* Earlier library versions used to copy the pointer to
+ * the CERT, not its contents; only when setting new
+ * parameters for the per-SSL copy, ssl_cert_new would be
+ * called (and the direct reference to the per-SSL_CTX
+ * settings would be lost, but those still were indirectly
+ * accessed for various purposes, and for that reason they
+ * used to be known as s->ctx->default_cert).
+ * Now we don't look at the SSL_CTX's CERT after having
+ * duplicated it once. */
+
+ s->cert = ssl_cert_dup(ctx->cert);
+ if (s->cert == NULL)
+ goto err;
+ }
+ else
+ s->cert=NULL; /* Cannot really happen (see SSL_CTX_new) */
+
+ s->read_ahead=ctx->read_ahead;
+ s->msg_callback=ctx->msg_callback;
+ s->msg_callback_arg=ctx->msg_callback_arg;
+ s->verify_mode=ctx->verify_mode;
+#if 0
+ s->verify_depth=ctx->verify_depth;
+#endif
+ s->sid_ctx_length=ctx->sid_ctx_length;
+ OPENSSL_assert(s->sid_ctx_length <= sizeof s->sid_ctx);
+ memcpy(&s->sid_ctx,&ctx->sid_ctx,sizeof(s->sid_ctx));
+ s->verify_callback=ctx->default_verify_callback;
+ s->generate_session_id=ctx->generate_session_id;
+
+ s->param = X509_VERIFY_PARAM_new();
+ if (!s->param)
+ goto err;
+ X509_VERIFY_PARAM_inherit(s->param, ctx->param);
+#if 0
+ s->purpose = ctx->purpose;
+ s->trust = ctx->trust;
+#endif
+ s->quiet_shutdown=ctx->quiet_shutdown;
+ s->max_send_fragment = ctx->max_send_fragment;
+
+ CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+ s->ctx=ctx;
+#ifndef OPENSSL_NO_TLSEXT
+ s->tlsext_debug_cb = 0;
+ s->tlsext_debug_arg = NULL;
+ s->tlsext_ticket_expected = 0;
+ s->tlsext_status_type = -1;
+ s->tlsext_status_expected = 0;
+ s->tlsext_ocsp_ids = NULL;
+ s->tlsext_ocsp_exts = NULL;
+ s->tlsext_ocsp_resp = NULL;
+ s->tlsext_ocsp_resplen = -1;
+ CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+ s->initial_ctx=ctx;
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ s->next_proto_negotiated = NULL;
+# endif
+#endif
+
+ s->verify_result=X509_V_OK;
+
+ s->method=ctx->method;
+
+ if (!s->method->ssl_new(s))
+ goto err;
+
+ s->references=1;
+ s->server=(ctx->method->ssl_accept == ssl_undefined_function)?0:1;
+
+ SSL_clear(s);
+
+ CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
+
+#ifndef OPENSSL_NO_PSK
+ s->psk_client_callback=ctx->psk_client_callback;
+ s->psk_server_callback=ctx->psk_server_callback;
+#endif
+
+ return(s);
+err:
+ if (s != NULL)
+ {
+ if (s->cert != NULL)
+ ssl_cert_free(s->cert);
+ if (s->ctx != NULL)
+ SSL_CTX_free(s->ctx); /* decrement reference count */
+ OPENSSL_free(s);
+ }
+ SSLerr(SSL_F_SSL_NEW,ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
+ unsigned int sid_ctx_len)
+ {
+ if(sid_ctx_len > sizeof ctx->sid_ctx)
+ {
+ SSLerr(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+ return 0;
+ }
+ ctx->sid_ctx_length=sid_ctx_len;
+ memcpy(ctx->sid_ctx,sid_ctx,sid_ctx_len);
+
+ return 1;
+ }
+
+int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
+ unsigned int sid_ctx_len)
+ {
+ if(sid_ctx_len > SSL_MAX_SID_CTX_LENGTH)
+ {
+ SSLerr(SSL_F_SSL_SET_SESSION_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+ return 0;
+ }
+ ssl->sid_ctx_length=sid_ctx_len;
+ memcpy(ssl->sid_ctx,sid_ctx,sid_ctx_len);
+
+ return 1;
+ }
+
+int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb)
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+ ctx->generate_session_id = cb;
+ CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+ return 1;
+ }
+
+int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb)
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+ ssl->generate_session_id = cb;
+ CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+ return 1;
+ }
+
+int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
+ unsigned int id_len)
+ {
+ /* A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how
+ * we can "construct" a session to give us the desired check - ie. to
+ * find if there's a session in the hash table that would conflict with
+ * any new session built out of this id/id_len and the ssl_version in
+ * use by this SSL. */
+ SSL_SESSION r, *p;
+
+ if(id_len > sizeof r.session_id)
+ return 0;
+
+ r.ssl_version = ssl->version;
+ r.session_id_length = id_len;
+ memcpy(r.session_id, id, id_len);
+ /* NB: SSLv2 always uses a fixed 16-byte session ID, so even if a
+ * callback is calling us to check the uniqueness of a shorter ID, it
+ * must be compared as a padded-out ID because that is what it will be
+ * converted to when the callback has finished choosing it. */
+ if((r.ssl_version == SSL2_VERSION) &&
+ (id_len < SSL2_SSL_SESSION_ID_LENGTH))
+ {
+ memset(r.session_id + id_len, 0,
+ SSL2_SSL_SESSION_ID_LENGTH - id_len);
+ r.session_id_length = SSL2_SSL_SESSION_ID_LENGTH;
+ }
+
+ CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
+ p = lh_SSL_SESSION_retrieve(ssl->ctx->sessions, &r);
+ CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+ return (p != NULL);
+ }
+
+int SSL_CTX_set_purpose(SSL_CTX *s, int purpose)
+ {
+ return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+ }
+
+int SSL_set_purpose(SSL *s, int purpose)
+ {
+ return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+ }
+
+int SSL_CTX_set_trust(SSL_CTX *s, int trust)
+ {
+ return X509_VERIFY_PARAM_set_trust(s->param, trust);
+ }
+
+int SSL_set_trust(SSL *s, int trust)
+ {
+ return X509_VERIFY_PARAM_set_trust(s->param, trust);
+ }
+
+int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm)
+ {
+ return X509_VERIFY_PARAM_set1(ctx->param, vpm);
+ }
+
+int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm)
+ {
+ return X509_VERIFY_PARAM_set1(ssl->param, vpm);
+ }
+
+void SSL_free(SSL *s)
+ {
+ int i;
+
+ if(s == NULL)
+ return;
+
+ i=CRYPTO_add(&s->references,-1,CRYPTO_LOCK_SSL);
+#ifdef REF_PRINT
+ REF_PRINT("SSL",s);
+#endif
+ if (i > 0) return;
+#ifdef REF_CHECK
+ if (i < 0)
+ {
+ fprintf(stderr,"SSL_free, bad reference count\n");
+ abort(); /* ok */
+ }
+#endif
+
+ if (s->param)
+ X509_VERIFY_PARAM_free(s->param);
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
+
+ if (s->bbio != NULL)
+ {
+ /* If the buffering BIO is in place, pop it off */
+ if (s->bbio == s->wbio)
+ {
+ s->wbio=BIO_pop(s->wbio);
+ }
+ BIO_free(s->bbio);
+ s->bbio=NULL;
+ }
+ if (s->rbio != NULL)
+ BIO_free_all(s->rbio);
+ if ((s->wbio != NULL) && (s->wbio != s->rbio))
+ BIO_free_all(s->wbio);
+
+ if (s->init_buf != NULL) BUF_MEM_free(s->init_buf);
+
+ /* add extra stuff */
+ if (s->cipher_list != NULL) sk_SSL_CIPHER_free(s->cipher_list);
+ if (s->cipher_list_by_id != NULL) sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ /* Make the next call work :-) */
+ if (s->session != NULL)
+ {
+ ssl_clear_bad_session(s);
+ SSL_SESSION_free(s->session);
+ }
+
+ ssl_clear_cipher_ctx(s);
+ ssl_clear_hash_ctx(&s->read_hash);
+ ssl_clear_hash_ctx(&s->write_hash);
+
+ if (s->cert != NULL) ssl_cert_free(s->cert);
+ /* Free up if allocated */
+
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_hostname)
+ OPENSSL_free(s->tlsext_hostname);
+ if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
+#ifndef OPENSSL_NO_EC
+ if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist);
+ if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist);
+#endif /* OPENSSL_NO_EC */
+ if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input);
+ if (s->tlsext_ocsp_exts)
+ sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+ X509_EXTENSION_free);
+ if (s->tlsext_ocsp_ids)
+ sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
+ if (s->tlsext_ocsp_resp)
+ OPENSSL_free(s->tlsext_ocsp_resp);
+#endif
+
+ if (s->client_CA != NULL)
+ sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
+
+ if (s->method != NULL) s->method->ssl_free(s);
+
+ if (s->ctx) SSL_CTX_free(s->ctx);
+
+#ifndef OPENSSL_NO_KRB5
+ if (s->kssl_ctx != NULL)
+ kssl_ctx_free(s->kssl_ctx);
+#endif /* OPENSSL_NO_KRB5 */
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ if (s->next_proto_negotiated)
+ OPENSSL_free(s->next_proto_negotiated);
+#endif
+
+#ifndef OPENSSL_NO_SRTP
+ if (s->srtp_profiles)
+ sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
+#endif
+
+ OPENSSL_free(s);
+ }
+
+void SSL_set_bio(SSL *s,BIO *rbio,BIO *wbio)
+ {
+ /* If the output buffering BIO is still in place, remove it
+ */
+ if (s->bbio != NULL)
+ {
+ if (s->wbio == s->bbio)
+ {
+ s->wbio=s->wbio->next_bio;
+ s->bbio->next_bio=NULL;
+ }
+ }
+ if ((s->rbio != NULL) && (s->rbio != rbio))
+ BIO_free_all(s->rbio);
+ if ((s->wbio != NULL) && (s->wbio != wbio) && (s->rbio != s->wbio))
+ BIO_free_all(s->wbio);
+ s->rbio=rbio;
+ s->wbio=wbio;
+ }
+
+BIO *SSL_get_rbio(const SSL *s)
+ { return(s->rbio); }
+
+BIO *SSL_get_wbio(const SSL *s)
+ { return(s->wbio); }
+
+int SSL_get_fd(const SSL *s)
+ {
+ return(SSL_get_rfd(s));
+ }
+
+int SSL_get_rfd(const SSL *s)
+ {
+ int ret= -1;
+ BIO *b,*r;
+
+ b=SSL_get_rbio(s);
+ r=BIO_find_type(b,BIO_TYPE_DESCRIPTOR);
+ if (r != NULL)
+ BIO_get_fd(r,&ret);
+ return(ret);
+ }
+
+int SSL_get_wfd(const SSL *s)
+ {
+ int ret= -1;
+ BIO *b,*r;
+
+ b=SSL_get_wbio(s);
+ r=BIO_find_type(b,BIO_TYPE_DESCRIPTOR);
+ if (r != NULL)
+ BIO_get_fd(r,&ret);
+ return(ret);
+ }
+
+#ifndef OPENSSL_NO_SOCK
+int SSL_set_fd(SSL *s,int fd)
+ {
+ int ret=0;
+ BIO *bio=NULL;
+
+ bio=BIO_new(BIO_s_socket());
+
+ if (bio == NULL)
+ {
+ SSLerr(SSL_F_SSL_SET_FD,ERR_R_BUF_LIB);
+ goto err;
+ }
+ BIO_set_fd(bio,fd,BIO_NOCLOSE);
+ SSL_set_bio(s,bio,bio);
+ ret=1;
+err:
+ return(ret);
+ }
+
+int SSL_set_wfd(SSL *s,int fd)
+ {
+ int ret=0;
+ BIO *bio=NULL;
+
+ if ((s->rbio == NULL) || (BIO_method_type(s->rbio) != BIO_TYPE_SOCKET)
+ || ((int)BIO_get_fd(s->rbio,NULL) != fd))
+ {
+ bio=BIO_new(BIO_s_socket());
+
+ if (bio == NULL)
+ { SSLerr(SSL_F_SSL_SET_WFD,ERR_R_BUF_LIB); goto err; }
+ BIO_set_fd(bio,fd,BIO_NOCLOSE);
+ SSL_set_bio(s,SSL_get_rbio(s),bio);
+ }
+ else
+ SSL_set_bio(s,SSL_get_rbio(s),SSL_get_rbio(s));
+ ret=1;
+err:
+ return(ret);
+ }
+
+int SSL_set_rfd(SSL *s,int fd)
+ {
+ int ret=0;
+ BIO *bio=NULL;
+
+ if ((s->wbio == NULL) || (BIO_method_type(s->wbio) != BIO_TYPE_SOCKET)
+ || ((int)BIO_get_fd(s->wbio,NULL) != fd))
+ {
+ bio=BIO_new(BIO_s_socket());
+
+ if (bio == NULL)
+ {
+ SSLerr(SSL_F_SSL_SET_RFD,ERR_R_BUF_LIB);
+ goto err;
+ }
+ BIO_set_fd(bio,fd,BIO_NOCLOSE);
+ SSL_set_bio(s,bio,SSL_get_wbio(s));
+ }
+ else
+ SSL_set_bio(s,SSL_get_wbio(s),SSL_get_wbio(s));
+ ret=1;
+err:
+ return(ret);
+ }
+#endif
+
+
+/* return length of latest Finished message we sent, copy to 'buf' */
+size_t SSL_get_finished(const SSL *s, void *buf, size_t count)
+ {
+ size_t ret = 0;
+
+ if (s->s3 != NULL)
+ {
+ ret = s->s3->tmp.finish_md_len;
+ if (count > ret)
+ count = ret;
+ memcpy(buf, s->s3->tmp.finish_md, count);
+ }
+ return ret;
+ }
+
+/* return length of latest Finished message we expected, copy to 'buf' */
+size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count)
+ {
+ size_t ret = 0;
+
+ if (s->s3 != NULL)
+ {
+ ret = s->s3->tmp.peer_finish_md_len;
+ if (count > ret)
+ count = ret;
+ memcpy(buf, s->s3->tmp.peer_finish_md, count);
+ }
+ return ret;
+ }
+
+
+int SSL_get_verify_mode(const SSL *s)
+ {
+ return(s->verify_mode);
+ }
+
+int SSL_get_verify_depth(const SSL *s)
+ {
+ return X509_VERIFY_PARAM_get_depth(s->param);
+ }
+
+int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *)
+ {
+ return(s->verify_callback);
+ }
+
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx)
+ {
+ return(ctx->verify_mode);
+ }
+
+int SSL_CTX_get_verify_depth(const SSL_CTX *ctx)
+ {
+ return X509_VERIFY_PARAM_get_depth(ctx->param);
+ }
+
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *)
+ {
+ return(ctx->default_verify_callback);
+ }
+
+void SSL_set_verify(SSL *s,int mode,
+ int (*callback)(int ok,X509_STORE_CTX *ctx))
+ {
+ s->verify_mode=mode;
+ if (callback != NULL)
+ s->verify_callback=callback;
+ }
+
+void SSL_set_verify_depth(SSL *s,int depth)
+ {
+ X509_VERIFY_PARAM_set_depth(s->param, depth);
+ }
+
+void SSL_set_read_ahead(SSL *s,int yes)
+ {
+ s->read_ahead=yes;
+ }
+
+int SSL_get_read_ahead(const SSL *s)
+ {
+ return(s->read_ahead);
+ }
+
+int SSL_pending(const SSL *s)
+ {
+ /* SSL_pending cannot work properly if read-ahead is enabled
+ * (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)),
+ * and it is impossible to fix since SSL_pending cannot report
+ * errors that may be observed while scanning the new data.
+ * (Note that SSL_pending() is often used as a boolean value,
+ * so we'd better not return -1.)
+ */
+ return(s->method->ssl_pending(s));
+ }
+
+X509 *SSL_get_peer_certificate(const SSL *s)
+ {
+ X509 *r;
+
+ if ((s == NULL) || (s->session == NULL))
+ r=NULL;
+ else
+ r=s->session->peer;
+
+ if (r == NULL) return(r);
+
+ CRYPTO_add(&r->references,1,CRYPTO_LOCK_X509);
+
+ return(r);
+ }
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
+ {
+ STACK_OF(X509) *r;
+
+ if ((s == NULL) || (s->session == NULL) || (s->session->sess_cert == NULL))
+ r=NULL;
+ else
+ r=s->session->sess_cert->cert_chain;
+
+ /* If we are a client, cert_chain includes the peer's own
+ * certificate; if we are a server, it does not. */
+
+ return(r);
+ }
+
+/* Now in theory, since the calling process own 't' it should be safe to
+ * modify. We need to be able to read f without being hassled */
+void SSL_copy_session_id(SSL *t,const SSL *f)
+ {
+ CERT *tmp;
+
+ /* Do we need to to SSL locking? */
+ SSL_set_session(t,SSL_get_session(f));
+
+ /* what if we are setup as SSLv2 but want to talk SSLv3 or
+ * vice-versa */
+ if (t->method != f->method)
+ {
+ t->method->ssl_free(t); /* cleanup current */
+ t->method=f->method; /* change method */
+ t->method->ssl_new(t); /* setup new */
+ }
+
+ tmp=t->cert;
+ if (f->cert != NULL)
+ {
+ CRYPTO_add(&f->cert->references,1,CRYPTO_LOCK_SSL_CERT);
+ t->cert=f->cert;
+ }
+ else
+ t->cert=NULL;
+ if (tmp != NULL) ssl_cert_free(tmp);
+ SSL_set_session_id_context(t,f->sid_ctx,f->sid_ctx_length);
+ }
+
+/* Fix this so it checks all the valid key/cert options */
+int SSL_CTX_check_private_key(const SSL_CTX *ctx)
+ {
+ if ( (ctx == NULL) ||
+ (ctx->cert == NULL) ||
+ (ctx->cert->key->x509 == NULL))
+ {
+ SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
+ return(0);
+ }
+ if (ctx->cert->key->privatekey == NULL)
+ {
+ SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY,SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+ return(0);
+ }
+ return(X509_check_private_key(ctx->cert->key->x509, ctx->cert->key->privatekey));
+ }
+
+/* Fix this function so that it takes an optional type parameter */
+int SSL_check_private_key(const SSL *ssl)
+ {
+ if (ssl == NULL)
+ {
+ SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,ERR_R_PASSED_NULL_PARAMETER);
+ return(0);
+ }
+ if (ssl->cert == NULL)
+ {
+ SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
+ return 0;
+ }
+ if (ssl->cert->key->x509 == NULL)
+ {
+ SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
+ return(0);
+ }
+ if (ssl->cert->key->privatekey == NULL)
+ {
+ SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+ return(0);
+ }
+ return(X509_check_private_key(ssl->cert->key->x509,
+ ssl->cert->key->privatekey));
+ }
+
+int SSL_accept(SSL *s)
+ {
+ if (s->handshake_func == 0)
+ /* Not properly initialized yet */
+ SSL_set_accept_state(s);
+
+ return(s->method->ssl_accept(s));
+ }
+
+int SSL_connect(SSL *s)
+ {
+ if (s->handshake_func == 0)
+ /* Not properly initialized yet */
+ SSL_set_connect_state(s);
+
+ return(s->method->ssl_connect(s));
+ }
+
+long SSL_get_default_timeout(const SSL *s)
+ {
+ return(s->method->get_timeout());
+ }
+
+int SSL_read(SSL *s,void *buf,int num)
+ {
+ if (s->handshake_func == 0)
+ {
+ SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+ {
+ s->rwstate=SSL_NOTHING;
+ return(0);
+ }
+ return(s->method->ssl_read(s,buf,num));
+ }
+
+int SSL_peek(SSL *s,void *buf,int num)
+ {
+ if (s->handshake_func == 0)
+ {
+ SSLerr(SSL_F_SSL_PEEK, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+ {
+ return(0);
+ }
+ return(s->method->ssl_peek(s,buf,num));
+ }
+
+int SSL_write(SSL *s,const void *buf,int num)
+ {
+ if (s->handshake_func == 0)
+ {
+ SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (s->shutdown & SSL_SENT_SHUTDOWN)
+ {
+ s->rwstate=SSL_NOTHING;
+ SSLerr(SSL_F_SSL_WRITE,SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return(-1);
+ }
+ return(s->method->ssl_write(s,buf,num));
+ }
+
+int SSL_shutdown(SSL *s)
+ {
+ /* Note that this function behaves differently from what one might
+ * expect. Return values are 0 for no success (yet),
+ * 1 for success; but calling it once is usually not enough,
+ * even if blocking I/O is used (see ssl3_shutdown).
+ */
+
+ if (s->handshake_func == 0)
+ {
+ SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if ((s != NULL) && !SSL_in_init(s))
+ return(s->method->ssl_shutdown(s));
+ else
+ return(1);
+ }
+
+int SSL_renegotiate(SSL *s)
+ {
+ if (s->renegotiate == 0)
+ s->renegotiate=1;
+
+ s->new_session=1;
+
+ return(s->method->ssl_renegotiate(s));
+ }
+
+int SSL_renegotiate_abbreviated(SSL *s)
+ {
+ if (s->renegotiate == 0)
+ s->renegotiate=1;
+
+ s->new_session=0;
+
+ return(s->method->ssl_renegotiate(s));
+ }
+
+int SSL_renegotiate_pending(SSL *s)
+ {
+ /* becomes true when negotiation is requested;
+ * false again once a handshake has finished */
+ return (s->renegotiate != 0);
+ }
+
+long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
+ {
+ long l;
+
+ switch (cmd)
+ {
+ case SSL_CTRL_GET_READ_AHEAD:
+ return(s->read_ahead);
+ case SSL_CTRL_SET_READ_AHEAD:
+ l=s->read_ahead;
+ s->read_ahead=larg;
+ return(l);
+
+ case SSL_CTRL_SET_MSG_CALLBACK_ARG:
+ s->msg_callback_arg = parg;
+ return 1;
+
+ case SSL_CTRL_OPTIONS:
+ return(s->options|=larg);
+ case SSL_CTRL_CLEAR_OPTIONS:
+ return(s->options&=~larg);
+ case SSL_CTRL_MODE:
+ return(s->mode|=larg);
+ case SSL_CTRL_CLEAR_MODE:
+ return(s->mode &=~larg);
+ case SSL_CTRL_GET_MAX_CERT_LIST:
+ return(s->max_cert_list);
+ case SSL_CTRL_SET_MAX_CERT_LIST:
+ l=s->max_cert_list;
+ s->max_cert_list=larg;
+ return(l);
+ case SSL_CTRL_SET_MTU:
+#ifndef OPENSSL_NO_DTLS1
+ if (larg < (long)dtls1_min_mtu())
+ return 0;
+#endif
+
+ if (SSL_version(s) == DTLS1_VERSION ||
+ SSL_version(s) == DTLS1_BAD_VER)
+ {
+ s->d1->mtu = larg;
+ return larg;
+ }
+ return 0;
+ case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+ if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+ return 0;
+ s->max_send_fragment = larg;
+ return 1;
+ case SSL_CTRL_GET_RI_SUPPORT:
+ if (s->s3)
+ return s->s3->send_connection_binding;
+ else return 0;
+ default:
+ return(s->method->ssl_ctrl(s,cmd,larg,parg));
+ }
+ }
+
+long SSL_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
+ {
+ switch(cmd)
+ {
+ case SSL_CTRL_SET_MSG_CALLBACK:
+ s->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
+ return 1;
+
+ default:
+ return(s->method->ssl_callback_ctrl(s,cmd,fp));
+ }
+ }
+
+LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx)
+ {
+ return ctx->sessions;
+ }
+
+long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,void *parg)
+ {
+ long l;
+
+ switch (cmd)
+ {
+ case SSL_CTRL_GET_READ_AHEAD:
+ return(ctx->read_ahead);
+ case SSL_CTRL_SET_READ_AHEAD:
+ l=ctx->read_ahead;
+ ctx->read_ahead=larg;
+ return(l);
+
+ case SSL_CTRL_SET_MSG_CALLBACK_ARG:
+ ctx->msg_callback_arg = parg;
+ return 1;
+
+ case SSL_CTRL_GET_MAX_CERT_LIST:
+ return(ctx->max_cert_list);
+ case SSL_CTRL_SET_MAX_CERT_LIST:
+ l=ctx->max_cert_list;
+ ctx->max_cert_list=larg;
+ return(l);
+
+ case SSL_CTRL_SET_SESS_CACHE_SIZE:
+ l=ctx->session_cache_size;
+ ctx->session_cache_size=larg;
+ return(l);
+ case SSL_CTRL_GET_SESS_CACHE_SIZE:
+ return(ctx->session_cache_size);
+ case SSL_CTRL_SET_SESS_CACHE_MODE:
+ l=ctx->session_cache_mode;
+ ctx->session_cache_mode=larg;
+ return(l);
+ case SSL_CTRL_GET_SESS_CACHE_MODE:
+ return(ctx->session_cache_mode);
+
+ case SSL_CTRL_SESS_NUMBER:
+ return(lh_SSL_SESSION_num_items(ctx->sessions));
+ case SSL_CTRL_SESS_CONNECT:
+ return(ctx->stats.sess_connect);
+ case SSL_CTRL_SESS_CONNECT_GOOD:
+ return(ctx->stats.sess_connect_good);
+ case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
+ return(ctx->stats.sess_connect_renegotiate);
+ case SSL_CTRL_SESS_ACCEPT:
+ return(ctx->stats.sess_accept);
+ case SSL_CTRL_SESS_ACCEPT_GOOD:
+ return(ctx->stats.sess_accept_good);
+ case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
+ return(ctx->stats.sess_accept_renegotiate);
+ case SSL_CTRL_SESS_HIT:
+ return(ctx->stats.sess_hit);
+ case SSL_CTRL_SESS_CB_HIT:
+ return(ctx->stats.sess_cb_hit);
+ case SSL_CTRL_SESS_MISSES:
+ return(ctx->stats.sess_miss);
+ case SSL_CTRL_SESS_TIMEOUTS:
+ return(ctx->stats.sess_timeout);
+ case SSL_CTRL_SESS_CACHE_FULL:
+ return(ctx->stats.sess_cache_full);
+ case SSL_CTRL_OPTIONS:
+ return(ctx->options|=larg);
+ case SSL_CTRL_CLEAR_OPTIONS:
+ return(ctx->options&=~larg);
+ case SSL_CTRL_MODE:
+ return(ctx->mode|=larg);
+ case SSL_CTRL_CLEAR_MODE:
+ return(ctx->mode&=~larg);
+ case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+ if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+ return 0;
+ ctx->max_send_fragment = larg;
+ return 1;
+ default:
+ return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg));
+ }
+ }
+
+long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
+ {
+ switch(cmd)
+ {
+ case SSL_CTRL_SET_MSG_CALLBACK:
+ ctx->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
+ return 1;
+
+ default:
+ return(ctx->method->ssl_ctx_callback_ctrl(ctx,cmd,fp));
+ }
+ }
+
+int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b)
+ {
+ long l;
+
+ l=a->id-b->id;
+ if (l == 0L)
+ return(0);
+ else
+ return((l > 0)?1:-1);
+ }
+
+int ssl_cipher_ptr_id_cmp(const SSL_CIPHER * const *ap,
+ const SSL_CIPHER * const *bp)
+ {
+ long l;
+
+ l=(*ap)->id-(*bp)->id;
+ if (l == 0L)
+ return(0);
+ else
+ return((l > 0)?1:-1);
+ }
+
+/** return a STACK of the ciphers available for the SSL and in order of
+ * preference */
+STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
+ {
+ if (s != NULL)
+ {
+ if (s->cipher_list != NULL)
+ {
+ return(s->cipher_list);
+ }
+ else if ((s->ctx != NULL) &&
+ (s->ctx->cipher_list != NULL))
+ {
+ return(s->ctx->cipher_list);
+ }
+ }
+ return(NULL);
+ }
+
+/** return a STACK of the ciphers available for the SSL and in order of
+ * algorithm id */
+STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s)
+ {
+ if (s != NULL)
+ {
+ if (s->cipher_list_by_id != NULL)
+ {
+ return(s->cipher_list_by_id);
+ }
+ else if ((s->ctx != NULL) &&
+ (s->ctx->cipher_list_by_id != NULL))
+ {
+ return(s->ctx->cipher_list_by_id);
+ }
+ }
+ return(NULL);
+ }
+
+/** The old interface to get the same thing as SSL_get_ciphers() */
+const char *SSL_get_cipher_list(const SSL *s,int n)
+ {
+ SSL_CIPHER *c;
+ STACK_OF(SSL_CIPHER) *sk;
+
+ if (s == NULL) return(NULL);
+ sk=SSL_get_ciphers(s);
+ if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= n))
+ return(NULL);
+ c=sk_SSL_CIPHER_value(sk,n);
+ if (c == NULL) return(NULL);
+ return(c->name);
+ }
+
+/** specify the ciphers to be used by default by the SSL_CTX */
+int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
+ {
+ STACK_OF(SSL_CIPHER) *sk;
+
+ sk=ssl_create_cipher_list(ctx->method,&ctx->cipher_list,
+ &ctx->cipher_list_by_id,str);
+ /* ssl_create_cipher_list may return an empty stack if it
+ * was unable to find a cipher matching the given rule string
+ * (for example if the rule string specifies a cipher which
+ * has been disabled). This is not an error as far as
+ * ssl_create_cipher_list is concerned, and hence
+ * ctx->cipher_list and ctx->cipher_list_by_id has been
+ * updated. */
+ if (sk == NULL)
+ return 0;
+ else if (sk_SSL_CIPHER_num(sk) == 0)
+ {
+ SSLerr(SSL_F_SSL_CTX_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
+ return 0;
+ }
+ return 1;
+ }
+
+/** specify the ciphers to be used by the SSL */
+int SSL_set_cipher_list(SSL *s,const char *str)
+ {
+ STACK_OF(SSL_CIPHER) *sk;
+
+ sk=ssl_create_cipher_list(s->ctx->method,&s->cipher_list,
+ &s->cipher_list_by_id,str);
+ /* see comment in SSL_CTX_set_cipher_list */
+ if (sk == NULL)
+ return 0;
+ else if (sk_SSL_CIPHER_num(sk) == 0)
+ {
+ SSLerr(SSL_F_SSL_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
+ return 0;
+ }
+ return 1;
+ }
+
+/* works well for SSLv2, not so good for SSLv3 */
+char *SSL_get_shared_ciphers(const SSL *s,char *buf,int len)
+ {
+ char *p;
+ STACK_OF(SSL_CIPHER) *sk;
+ SSL_CIPHER *c;
+ int i;
+
+ if ((s->session == NULL) || (s->session->ciphers == NULL) ||
+ (len < 2))
+ return(NULL);
+
+ p=buf;
+ sk=s->session->ciphers;
+
+ if (sk_SSL_CIPHER_num(sk) == 0)
+ return NULL;
+
+ for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+ {
+ int n;
+
+ c=sk_SSL_CIPHER_value(sk,i);
+ n=strlen(c->name);
+ if (n+1 > len)
+ {
+ if (p != buf)
+ --p;
+ *p='\0';
+ return buf;
+ }
+ strcpy(p,c->name);
+ p+=n;
+ *(p++)=':';
+ len-=n+1;
+ }
+ p[-1]='\0';
+ return(buf);
+ }
+
+int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
+ int (*put_cb)(const SSL_CIPHER *, unsigned char *))
+ {
+ int i,j=0;
+ SSL_CIPHER *c;
+ unsigned char *q;
+#ifndef OPENSSL_NO_KRB5
+ int nokrb5 = !kssl_tgt_is_available(s->kssl_ctx);
+#endif /* OPENSSL_NO_KRB5 */
+
+ if (sk == NULL) return(0);
+ q=p;
+
+ for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+ {
+ c=sk_SSL_CIPHER_value(sk,i);
+ /* Skip TLS v1.2 only ciphersuites if lower than v1.2 */
+ if ((c->algorithm_ssl & SSL_TLSV1_2) &&
+ (TLS1_get_client_version(s) < TLS1_2_VERSION))
+ continue;
+#ifndef OPENSSL_NO_KRB5
+ if (((c->algorithm_mkey & SSL_kKRB5) || (c->algorithm_auth & SSL_aKRB5)) &&
+ nokrb5)
+ continue;
+#endif /* OPENSSL_NO_KRB5 */
+#ifndef OPENSSL_NO_PSK
+ /* with PSK there must be client callback set */
+ if (((c->algorithm_mkey & SSL_kPSK) || (c->algorithm_auth & SSL_aPSK)) &&
+ s->psk_client_callback == NULL)
+ continue;
+#endif /* OPENSSL_NO_PSK */
+ j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p);
+ p+=j;
+ }
+ /* If p == q, no ciphers and caller indicates an error. Otherwise
+ * add SCSV if not renegotiating.
+ */
+ if (p != q && !s->renegotiate)
+ {
+ static SSL_CIPHER scsv =
+ {
+ 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ j = put_cb ? put_cb(&scsv,p) : ssl_put_cipher_by_char(s,&scsv,p);
+ p+=j;
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "SCSV sent by client\n");
+#endif
+ }
+
+ return(p-q);
+ }
+
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
+ STACK_OF(SSL_CIPHER) **skp)
+ {
+ const SSL_CIPHER *c;
+ STACK_OF(SSL_CIPHER) *sk;
+ int i,n;
+ if (s->s3)
+ s->s3->send_connection_binding = 0;
+
+ n=ssl_put_cipher_by_char(s,NULL,NULL);
+ if ((num%n) != 0)
+ {
+ SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+ return(NULL);
+ }
+ if ((skp == NULL) || (*skp == NULL))
+ sk=sk_SSL_CIPHER_new_null(); /* change perhaps later */
+ else
+ {
+ sk= *skp;
+ sk_SSL_CIPHER_zero(sk);
+ }
+
+ for (i=0; i<num; i+=n)
+ {
+ /* Check for SCSV */
+ if (s->s3 && (n != 3 || !p[0]) &&
+ (p[n-2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
+ (p[n-1] == (SSL3_CK_SCSV & 0xff)))
+ {
+ /* SCSV fatal if renegotiating */
+ if (s->renegotiate)
+ {
+ SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
+ }
+ s->s3->send_connection_binding = 1;
+ p += n;
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "SCSV received by server\n");
+#endif
+ continue;
+ }
+
+ c=ssl_get_cipher_by_char(s,p);
+ p+=n;
+ if (c != NULL)
+ {
+ if (!sk_SSL_CIPHER_push(sk,c))
+ {
+ SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ }
+
+ if (skp != NULL)
+ *skp=sk;
+ return(sk);
+err:
+ if ((skp == NULL) || (*skp == NULL))
+ sk_SSL_CIPHER_free(sk);
+ return(NULL);
+ }
+
+
+#ifndef OPENSSL_NO_TLSEXT
+/** return a servername extension value if provided in Client Hello, or NULL.
+ * So far, only host_name types are defined (RFC 3546).
+ */
+
+const char *SSL_get_servername(const SSL *s, const int type)
+ {
+ if (type != TLSEXT_NAMETYPE_host_name)
+ return NULL;
+
+ return s->session && !s->tlsext_hostname ?
+ s->session->tlsext_hostname :
+ s->tlsext_hostname;
+ }
+
+int SSL_get_servername_type(const SSL *s)
+ {
+ if (s->session && (!s->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname))
+ return TLSEXT_NAMETYPE_host_name;
+ return -1;
+ }
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+/* SSL_select_next_proto implements the standard protocol selection. It is
+ * expected that this function is called from the callback set by
+ * SSL_CTX_set_next_proto_select_cb.
+ *
+ * The protocol data is assumed to be a vector of 8-bit, length prefixed byte
+ * strings. The length byte itself is not included in the length. A byte
+ * string of length 0 is invalid. No byte string may be truncated.
+ *
+ * The current, but experimental algorithm for selecting the protocol is:
+ *
+ * 1) If the server doesn't support NPN then this is indicated to the
+ * callback. In this case, the client application has to abort the connection
+ * or have a default application level protocol.
+ *
+ * 2) If the server supports NPN, but advertises an empty list then the
+ * client selects the first protcol in its list, but indicates via the
+ * API that this fallback case was enacted.
+ *
+ * 3) Otherwise, the client finds the first protocol in the server's list
+ * that it supports and selects this protocol. This is because it's
+ * assumed that the server has better information about which protocol
+ * a client should use.
+ *
+ * 4) If the client doesn't support any of the server's advertised
+ * protocols, then this is treated the same as case 2.
+ *
+ * It returns either
+ * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or
+ * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached.
+ */
+int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, const unsigned char *client, unsigned int client_len)
+ {
+ unsigned int i, j;
+ const unsigned char *result;
+ int status = OPENSSL_NPN_UNSUPPORTED;
+
+ /* For each protocol in server preference order, see if we support it. */
+ for (i = 0; i < server_len; )
+ {
+ for (j = 0; j < client_len; )
+ {
+ if (server[i] == client[j] &&
+ memcmp(&server[i+1], &client[j+1], server[i]) == 0)
+ {
+ /* We found a match */
+ result = &server[i];
+ status = OPENSSL_NPN_NEGOTIATED;
+ goto found;
+ }
+ j += client[j];
+ j++;
+ }
+ i += server[i];
+ i++;
+ }
+
+ /* There's no overlap between our protocols and the server's list. */
+ result = client;
+ status = OPENSSL_NPN_NO_OVERLAP;
+
+ found:
+ *out = (unsigned char *) result + 1;
+ *outlen = result[0];
+ return status;
+ }
+
+/* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's
+ * requested protocol for this connection and returns 0. If the client didn't
+ * request any protocol, then *data is set to NULL.
+ *
+ * Note that the client can request any protocol it chooses. The value returned
+ * from this function need not be a member of the list of supported protocols
+ * provided by the callback.
+ */
+void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, unsigned *len)
+ {
+ *data = s->next_proto_negotiated;
+ if (!*data) {
+ *len = 0;
+ } else {
+ *len = s->next_proto_negotiated_len;
+ }
+}
+
+/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a
+ * TLS server needs a list of supported protocols for Next Protocol
+ * Negotiation. The returned list must be in wire format. The list is returned
+ * by setting |out| to point to it and |outlen| to its length. This memory will
+ * not be modified, but one should assume that the SSL* keeps a reference to
+ * it.
+ *
+ * The callback should return SSL_TLSEXT_ERR_OK if it wishes to advertise. Otherwise, no
+ * such extension will be included in the ServerHello. */
+void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *ctx, int (*cb) (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg), void *arg)
+ {
+ ctx->next_protos_advertised_cb = cb;
+ ctx->next_protos_advertised_cb_arg = arg;
+ }
+
+/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a
+ * client needs to select a protocol from the server's provided list. |out|
+ * must be set to point to the selected protocol (which may be within |in|).
+ * The length of the protocol name must be written into |outlen|. The server's
+ * advertised protocols are provided in |in| and |inlen|. The callback can
+ * assume that |in| is syntactically valid.
+ *
+ * The client must select a protocol. It is fatal to the connection if this
+ * callback returns a value other than SSL_TLSEXT_ERR_OK.
+ */
+void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg), void *arg)
+ {
+ ctx->next_proto_select_cb = cb;
+ ctx->next_proto_select_cb_arg = arg;
+ }
+# endif
+#endif
+
+int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+ const char *label, size_t llen, const unsigned char *p, size_t plen,
+ int use_context)
+ {
+ if (s->version < TLS1_VERSION)
+ return -1;
+
+ return s->method->ssl3_enc->export_keying_material(s, out, olen, label,
+ llen, p, plen,
+ use_context);
+ }
+
+static unsigned long ssl_session_hash(const SSL_SESSION *a)
+ {
+ unsigned long l;
+
+ l=(unsigned long)
+ ((unsigned int) a->session_id[0] )|
+ ((unsigned int) a->session_id[1]<< 8L)|
+ ((unsigned long)a->session_id[2]<<16L)|
+ ((unsigned long)a->session_id[3]<<24L);
+ return(l);
+ }
+
+/* NB: If this function (or indeed the hash function which uses a sort of
+ * coarser function than this one) is changed, ensure
+ * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being
+ * able to construct an SSL_SESSION that will collide with any existing session
+ * with a matching session ID. */
+static int ssl_session_cmp(const SSL_SESSION *a,const SSL_SESSION *b)
+ {
+ if (a->ssl_version != b->ssl_version)
+ return(1);
+ if (a->session_id_length != b->session_id_length)
+ return(1);
+ return(memcmp(a->session_id,b->session_id,a->session_id_length));
+ }
+
+/* These wrapper functions should remain rather than redeclaring
+ * SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each
+ * variable. The reason is that the functions aren't static, they're exposed via
+ * ssl.h. */
+static IMPLEMENT_LHASH_HASH_FN(ssl_session, SSL_SESSION)
+static IMPLEMENT_LHASH_COMP_FN(ssl_session, SSL_SESSION)
+
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
+ {
+ SSL_CTX *ret=NULL;
+
+ if (meth == NULL)
+ {
+ SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_NULL_SSL_METHOD_PASSED);
+ return(NULL);
+ }
+
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode() && (meth->version < TLS1_VERSION))
+ {
+ SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+ return NULL;
+ }
+#endif
+
+ if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0)
+ {
+ SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
+ goto err;
+ }
+ ret=(SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
+ if (ret == NULL)
+ goto err;
+
+ memset(ret,0,sizeof(SSL_CTX));
+
+ ret->method=meth;
+
+ ret->cert_store=NULL;
+ ret->session_cache_mode=SSL_SESS_CACHE_SERVER;
+ ret->session_cache_size=SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
+ ret->session_cache_head=NULL;
+ ret->session_cache_tail=NULL;
+
+ /* We take the system default */
+ ret->session_timeout=meth->get_timeout();
+
+ ret->new_session_cb=0;
+ ret->remove_session_cb=0;
+ ret->get_session_cb=0;
+ ret->generate_session_id=0;
+
+ memset((char *)&ret->stats,0,sizeof(ret->stats));
+
+ ret->references=1;
+ ret->quiet_shutdown=0;
+
+/* ret->cipher=NULL;*/
+/* ret->s2->challenge=NULL;
+ ret->master_key=NULL;
+ ret->key_arg=NULL;
+ ret->s2->conn_id=NULL; */
+
+ ret->info_callback=NULL;
+
+ ret->app_verify_callback=0;
+ ret->app_verify_arg=NULL;
+
+ ret->max_cert_list=SSL_MAX_CERT_LIST_DEFAULT;
+ ret->read_ahead=0;
+ ret->msg_callback=0;
+ ret->msg_callback_arg=NULL;
+ ret->verify_mode=SSL_VERIFY_NONE;
+#if 0
+ ret->verify_depth=-1; /* Don't impose a limit (but x509_lu.c does) */
+#endif
+ ret->sid_ctx_length=0;
+ ret->default_verify_callback=NULL;
+ if ((ret->cert=ssl_cert_new()) == NULL)
+ goto err;
+
+ ret->default_passwd_callback=0;
+ ret->default_passwd_callback_userdata=NULL;
+ ret->client_cert_cb=0;
+ ret->app_gen_cookie_cb=0;
+ ret->app_verify_cookie_cb=0;
+
+ ret->sessions=lh_SSL_SESSION_new();
+ if (ret->sessions == NULL) goto err;
+ ret->cert_store=X509_STORE_new();
+ if (ret->cert_store == NULL) goto err;
+
+ ssl_create_cipher_list(ret->method,
+ &ret->cipher_list,&ret->cipher_list_by_id,
+ meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST);
+ if (ret->cipher_list == NULL
+ || sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
+ {
+ SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_LIBRARY_HAS_NO_CIPHERS);
+ goto err2;
+ }
+
+ ret->param = X509_VERIFY_PARAM_new();
+ if (!ret->param)
+ goto err;
+
+ if ((ret->rsa_md5=EVP_get_digestbyname("ssl2-md5")) == NULL)
+ {
+ SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES);
+ goto err2;
+ }
+ if ((ret->md5=EVP_get_digestbyname("ssl3-md5")) == NULL)
+ {
+ SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES);
+ goto err2;
+ }
+ if ((ret->sha1=EVP_get_digestbyname("ssl3-sha1")) == NULL)
+ {
+ SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES);
+ goto err2;
+ }
+
+ if ((ret->client_CA=sk_X509_NAME_new_null()) == NULL)
+ goto err;
+
+ CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data);
+
+ ret->extra_certs=NULL;
+ /* No compression for DTLS */
+ if (meth->version != DTLS1_VERSION)
+ ret->comp_methods=SSL_COMP_get_compression_methods();
+
+ ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+
+#ifndef OPENSSL_NO_TLSEXT
+ ret->tlsext_servername_callback = 0;
+ ret->tlsext_servername_arg = NULL;
+ /* Setup RFC4507 ticket keys */
+ if ((RAND_pseudo_bytes(ret->tlsext_tick_key_name, 16) <= 0)
+ || (RAND_bytes(ret->tlsext_tick_hmac_key, 16) <= 0)
+ || (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
+ ret->options |= SSL_OP_NO_TICKET;
+
+ ret->tlsext_status_cb = 0;
+ ret->tlsext_status_arg = NULL;
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ ret->next_protos_advertised_cb = 0;
+ ret->next_proto_select_cb = 0;
+# endif
+#endif
+#ifndef OPENSSL_NO_PSK
+ ret->psk_identity_hint=NULL;
+ ret->psk_client_callback=NULL;
+ ret->psk_server_callback=NULL;
+#endif
+#ifndef OPENSSL_NO_SRP
+ SSL_CTX_SRP_CTX_init(ret);
+#endif
+#ifndef OPENSSL_NO_BUF_FREELISTS
+ ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT;
+ ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
+ if (!ret->rbuf_freelist)
+ goto err;
+ ret->rbuf_freelist->chunklen = 0;
+ ret->rbuf_freelist->len = 0;
+ ret->rbuf_freelist->head = NULL;
+ ret->wbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
+ if (!ret->wbuf_freelist)
+ {
+ OPENSSL_free(ret->rbuf_freelist);
+ goto err;
+ }
+ ret->wbuf_freelist->chunklen = 0;
+ ret->wbuf_freelist->len = 0;
+ ret->wbuf_freelist->head = NULL;
+#endif
+#ifndef OPENSSL_NO_ENGINE
+ ret->client_cert_engine = NULL;
+#ifdef OPENSSL_SSL_CLIENT_ENGINE_AUTO
+#define eng_strx(x) #x
+#define eng_str(x) eng_strx(x)
+ /* Use specific client engine automatically... ignore errors */
+ {
+ ENGINE *eng;
+ eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
+ if (!eng)
+ {
+ ERR_clear_error();
+ ENGINE_load_builtin_engines();
+ eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
+ }
+ if (!eng || !SSL_CTX_set_client_cert_engine(ret, eng))
+ ERR_clear_error();
+ }
+#endif
+#endif
+ /* Default is to connect to non-RI servers. When RI is more widely
+ * deployed might change this.
+ */
+ ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
+
+ return(ret);
+err:
+ SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);
+err2:
+ if (ret != NULL) SSL_CTX_free(ret);
+ return(NULL);
+ }
+
+#if 0
+static void SSL_COMP_free(SSL_COMP *comp)
+ { OPENSSL_free(comp); }
+#endif
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+static void
+ssl_buf_freelist_free(SSL3_BUF_FREELIST *list)
+ {
+ SSL3_BUF_FREELIST_ENTRY *ent, *next;
+ for (ent = list->head; ent; ent = next)
+ {
+ next = ent->next;
+ OPENSSL_free(ent);
+ }
+ OPENSSL_free(list);
+ }
+#endif
+
+void SSL_CTX_free(SSL_CTX *a)
+ {
+ int i;
+
+ if (a == NULL) return;
+
+ i=CRYPTO_add(&a->references,-1,CRYPTO_LOCK_SSL_CTX);
+#ifdef REF_PRINT
+ REF_PRINT("SSL_CTX",a);
+#endif
+ if (i > 0) return;
+#ifdef REF_CHECK
+ if (i < 0)
+ {
+ fprintf(stderr,"SSL_CTX_free, bad reference count\n");
+ abort(); /* ok */
+ }
+#endif
+
+ if (a->param)
+ X509_VERIFY_PARAM_free(a->param);
+
+ /*
+ * Free internal session cache. However: the remove_cb() may reference
+ * the ex_data of SSL_CTX, thus the ex_data store can only be removed
+ * after the sessions were flushed.
+ * As the ex_data handling routines might also touch the session cache,
+ * the most secure solution seems to be: empty (flush) the cache, then
+ * free ex_data, then finally free the cache.
+ * (See ticket [openssl.org #212].)
+ */
+ if (a->sessions != NULL)
+ SSL_CTX_flush_sessions(a,0);
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
+
+ if (a->sessions != NULL)
+ lh_SSL_SESSION_free(a->sessions);
+
+ if (a->cert_store != NULL)
+ X509_STORE_free(a->cert_store);
+ if (a->cipher_list != NULL)
+ sk_SSL_CIPHER_free(a->cipher_list);
+ if (a->cipher_list_by_id != NULL)
+ sk_SSL_CIPHER_free(a->cipher_list_by_id);
+ if (a->cert != NULL)
+ ssl_cert_free(a->cert);
+ if (a->client_CA != NULL)
+ sk_X509_NAME_pop_free(a->client_CA,X509_NAME_free);
+ if (a->extra_certs != NULL)
+ sk_X509_pop_free(a->extra_certs,X509_free);
+#if 0 /* This should never be done, since it removes a global database */
+ if (a->comp_methods != NULL)
+ sk_SSL_COMP_pop_free(a->comp_methods,SSL_COMP_free);
+#else
+ a->comp_methods = NULL;
+#endif
+
+#ifndef OPENSSL_NO_SRTP
+ if (a->srtp_profiles)
+ sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles);
+#endif
+
+#ifndef OPENSSL_NO_PSK
+ if (a->psk_identity_hint)
+ OPENSSL_free(a->psk_identity_hint);
+#endif
+#ifndef OPENSSL_NO_SRP
+ SSL_CTX_SRP_CTX_free(a);
+#endif
+#ifndef OPENSSL_NO_ENGINE
+ if (a->client_cert_engine)
+ ENGINE_finish(a->client_cert_engine);
+#endif
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+ if (a->wbuf_freelist)
+ ssl_buf_freelist_free(a->wbuf_freelist);
+ if (a->rbuf_freelist)
+ ssl_buf_freelist_free(a->rbuf_freelist);
+#endif
+
+ OPENSSL_free(a);
+ }
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb)
+ {
+ ctx->default_passwd_callback=cb;
+ }
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx,void *u)
+ {
+ ctx->default_passwd_callback_userdata=u;
+ }
+
+void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg)
+ {
+ ctx->app_verify_callback=cb;
+ ctx->app_verify_arg=arg;
+ }
+
+void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int (*cb)(int, X509_STORE_CTX *))
+ {
+ ctx->verify_mode=mode;
+ ctx->default_verify_callback=cb;
+ }
+
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth)
+ {
+ X509_VERIFY_PARAM_set_depth(ctx->param, depth);
+ }
+
+void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
+ {
+ CERT_PKEY *cpk;
+ int rsa_enc,rsa_tmp,rsa_sign,dh_tmp,dh_rsa,dh_dsa,dsa_sign;
+ int rsa_enc_export,dh_rsa_export,dh_dsa_export;
+ int rsa_tmp_export,dh_tmp_export,kl;
+ unsigned long mask_k,mask_a,emask_k,emask_a;
+ int have_ecc_cert, ecdh_ok, ecdsa_ok, ecc_pkey_size;
+#ifndef OPENSSL_NO_ECDH
+ int have_ecdh_tmp;
+#endif
+ X509 *x = NULL;
+ EVP_PKEY *ecc_pkey = NULL;
+ int signature_nid = 0, pk_nid = 0, md_nid = 0;
+
+ if (c == NULL) return;
+
+ kl=SSL_C_EXPORT_PKEYLENGTH(cipher);
+
+#ifndef OPENSSL_NO_RSA
+ rsa_tmp=(c->rsa_tmp != NULL || c->rsa_tmp_cb != NULL);
+ rsa_tmp_export=(c->rsa_tmp_cb != NULL ||
+ (rsa_tmp && RSA_size(c->rsa_tmp)*8 <= kl));
+#else
+ rsa_tmp=rsa_tmp_export=0;
+#endif
+#ifndef OPENSSL_NO_DH
+ dh_tmp=(c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
+ dh_tmp_export=(c->dh_tmp_cb != NULL ||
+ (dh_tmp && DH_size(c->dh_tmp)*8 <= kl));
+#else
+ dh_tmp=dh_tmp_export=0;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+ have_ecdh_tmp=(c->ecdh_tmp != NULL || c->ecdh_tmp_cb != NULL);
+#endif
+ cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
+ rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL);
+ rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+ cpk= &(c->pkeys[SSL_PKEY_RSA_SIGN]);
+ rsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL);
+ cpk= &(c->pkeys[SSL_PKEY_DSA_SIGN]);
+ dsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL);
+ cpk= &(c->pkeys[SSL_PKEY_DH_RSA]);
+ dh_rsa= (cpk->x509 != NULL && cpk->privatekey != NULL);
+ dh_rsa_export=(dh_rsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+ cpk= &(c->pkeys[SSL_PKEY_DH_DSA]);
+/* FIX THIS EAY EAY EAY */
+ dh_dsa= (cpk->x509 != NULL && cpk->privatekey != NULL);
+ dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+ cpk= &(c->pkeys[SSL_PKEY_ECC]);
+ have_ecc_cert= (cpk->x509 != NULL && cpk->privatekey != NULL);
+ mask_k=0;
+ mask_a=0;
+ emask_k=0;
+ emask_a=0;
+
+
+
+#ifdef CIPHER_DEBUG
+ printf("rt=%d rte=%d dht=%d ecdht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n",
+ rsa_tmp,rsa_tmp_export,dh_tmp,have_ecdh_tmp,
+ rsa_enc,rsa_enc_export,rsa_sign,dsa_sign,dh_rsa,dh_dsa);
+#endif
+
+ cpk = &(c->pkeys[SSL_PKEY_GOST01]);
+ if (cpk->x509 != NULL && cpk->privatekey !=NULL) {
+ mask_k |= SSL_kGOST;
+ mask_a |= SSL_aGOST01;
+ }
+ cpk = &(c->pkeys[SSL_PKEY_GOST94]);
+ if (cpk->x509 != NULL && cpk->privatekey !=NULL) {
+ mask_k |= SSL_kGOST;
+ mask_a |= SSL_aGOST94;
+ }
+
+ if (rsa_enc || (rsa_tmp && rsa_sign))
+ mask_k|=SSL_kRSA;
+ if (rsa_enc_export || (rsa_tmp_export && (rsa_sign || rsa_enc)))
+ emask_k|=SSL_kRSA;
+
+#if 0
+ /* The match needs to be both kEDH and aRSA or aDSA, so don't worry */
+ if ( (dh_tmp || dh_rsa || dh_dsa) &&
+ (rsa_enc || rsa_sign || dsa_sign))
+ mask_k|=SSL_kEDH;
+ if ((dh_tmp_export || dh_rsa_export || dh_dsa_export) &&
+ (rsa_enc || rsa_sign || dsa_sign))
+ emask_k|=SSL_kEDH;
+#endif
+
+ if (dh_tmp_export)
+ emask_k|=SSL_kEDH;
+
+ if (dh_tmp)
+ mask_k|=SSL_kEDH;
+
+ if (dh_rsa) mask_k|=SSL_kDHr;
+ if (dh_rsa_export) emask_k|=SSL_kDHr;
+
+ if (dh_dsa) mask_k|=SSL_kDHd;
+ if (dh_dsa_export) emask_k|=SSL_kDHd;
+
+ if (rsa_enc || rsa_sign)
+ {
+ mask_a|=SSL_aRSA;
+ emask_a|=SSL_aRSA;
+ }
+
+ if (dsa_sign)
+ {
+ mask_a|=SSL_aDSS;
+ emask_a|=SSL_aDSS;
+ }
+
+ mask_a|=SSL_aNULL;
+ emask_a|=SSL_aNULL;
+
+#ifndef OPENSSL_NO_KRB5
+ mask_k|=SSL_kKRB5;
+ mask_a|=SSL_aKRB5;
+ emask_k|=SSL_kKRB5;
+ emask_a|=SSL_aKRB5;
+#endif
+
+ /* An ECC certificate may be usable for ECDH and/or
+ * ECDSA cipher suites depending on the key usage extension.
+ */
+ if (have_ecc_cert)
+ {
+ /* This call populates extension flags (ex_flags) */
+ x = (c->pkeys[SSL_PKEY_ECC]).x509;
+ X509_check_purpose(x, -1, 0);
+ ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
+ (x->ex_kusage & X509v3_KU_KEY_AGREEMENT) : 1;
+ ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
+ (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1;
+ ecc_pkey = X509_get_pubkey(x);
+ ecc_pkey_size = (ecc_pkey != NULL) ?
+ EVP_PKEY_bits(ecc_pkey) : 0;
+ EVP_PKEY_free(ecc_pkey);
+ if ((x->sig_alg) && (x->sig_alg->algorithm))
+ {
+ signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+ OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
+ }
+#ifndef OPENSSL_NO_ECDH
+ if (ecdh_ok)
+ {
+
+ if (pk_nid == NID_rsaEncryption || pk_nid == NID_rsa)
+ {
+ mask_k|=SSL_kECDHr;
+ mask_a|=SSL_aECDH;
+ if (ecc_pkey_size <= 163)
+ {
+ emask_k|=SSL_kECDHr;
+ emask_a|=SSL_aECDH;
+ }
+ }
+
+ if (pk_nid == NID_X9_62_id_ecPublicKey)
+ {
+ mask_k|=SSL_kECDHe;
+ mask_a|=SSL_aECDH;
+ if (ecc_pkey_size <= 163)
+ {
+ emask_k|=SSL_kECDHe;
+ emask_a|=SSL_aECDH;
+ }
+ }
+ }
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (ecdsa_ok)
+ {
+ mask_a|=SSL_aECDSA;
+ emask_a|=SSL_aECDSA;
+ }
+#endif
+ }
+
+#ifndef OPENSSL_NO_ECDH
+ if (have_ecdh_tmp)
+ {
+ mask_k|=SSL_kEECDH;
+ emask_k|=SSL_kEECDH;
+ }
+#endif
+
+#ifndef OPENSSL_NO_PSK
+ mask_k |= SSL_kPSK;
+ mask_a |= SSL_aPSK;
+ emask_k |= SSL_kPSK;
+ emask_a |= SSL_aPSK;
+#endif
+
+ c->mask_k=mask_k;
+ c->mask_a=mask_a;
+ c->export_mask_k=emask_k;
+ c->export_mask_a=emask_a;
+ c->valid=1;
+ }
+
+/* This handy macro borrowed from crypto/x509v3/v3_purp.c */
+#define ku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
+
+#ifndef OPENSSL_NO_EC
+
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
+ {
+ unsigned long alg_k, alg_a;
+ EVP_PKEY *pkey = NULL;
+ int keysize = 0;
+ int signature_nid = 0, md_nid = 0, pk_nid = 0;
+ const SSL_CIPHER *cs = s->s3->tmp.new_cipher;
+
+ alg_k = cs->algorithm_mkey;
+ alg_a = cs->algorithm_auth;
+
+ if (SSL_C_IS_EXPORT(cs))
+ {
+ /* ECDH key length in export ciphers must be <= 163 bits */
+ pkey = X509_get_pubkey(x);
+ if (pkey == NULL) return 0;
+ keysize = EVP_PKEY_bits(pkey);
+ EVP_PKEY_free(pkey);
+ if (keysize > 163) return 0;
+ }
+
+ /* This call populates the ex_flags field correctly */
+ X509_check_purpose(x, -1, 0);
+ if ((x->sig_alg) && (x->sig_alg->algorithm))
+ {
+ signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+ OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
+ }
+ if (alg_k & SSL_kECDHe || alg_k & SSL_kECDHr)
+ {
+ /* key usage, if present, must allow key agreement */
+ if (ku_reject(x, X509v3_KU_KEY_AGREEMENT))
+ {
+ SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT);
+ return 0;
+ }
+ if ((alg_k & SSL_kECDHe) && TLS1_get_version(s) < TLS1_2_VERSION)
+ {
+ /* signature alg must be ECDSA */
+ if (pk_nid != NID_X9_62_id_ecPublicKey)
+ {
+ SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE);
+ return 0;
+ }
+ }
+ if ((alg_k & SSL_kECDHr) && TLS1_get_version(s) < TLS1_2_VERSION)
+ {
+ /* signature alg must be RSA */
+
+ if (pk_nid != NID_rsaEncryption && pk_nid != NID_rsa)
+ {
+ SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE);
+ return 0;
+ }
+ }
+ }
+ if (alg_a & SSL_aECDSA)
+ {
+ /* key usage, if present, must allow signing */
+ if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
+ {
+ SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+ return 0;
+ }
+ }
+
+ return 1; /* all checks are ok */
+ }
+
+#endif
+
+/* THIS NEEDS CLEANING UP */
+CERT_PKEY *ssl_get_server_send_pkey(const SSL *s)
+ {
+ unsigned long alg_k,alg_a;
+ CERT *c;
+ int i;
+
+ c=s->cert;
+ ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
+
+ alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+
+ if (alg_k & (SSL_kECDHr|SSL_kECDHe))
+ {
+ /* we don't need to look at SSL_kEECDH
+ * since no certificate is needed for
+ * anon ECDH and for authenticated
+ * EECDH, the check for the auth
+ * algorithm will set i correctly
+ * NOTE: For ECDH-RSA, we need an ECC
+ * not an RSA cert but for EECDH-RSA
+ * we need an RSA cert. Placing the
+ * checks for SSL_kECDH before RSA
+ * checks ensures the correct cert is chosen.
+ */
+ i=SSL_PKEY_ECC;
+ }
+ else if (alg_a & SSL_aECDSA)
+ {
+ i=SSL_PKEY_ECC;
+ }
+ else if (alg_k & SSL_kDHr)
+ i=SSL_PKEY_DH_RSA;
+ else if (alg_k & SSL_kDHd)
+ i=SSL_PKEY_DH_DSA;
+ else if (alg_a & SSL_aDSS)
+ i=SSL_PKEY_DSA_SIGN;
+ else if (alg_a & SSL_aRSA)
+ {
+ if (c->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL)
+ i=SSL_PKEY_RSA_SIGN;
+ else
+ i=SSL_PKEY_RSA_ENC;
+ }
+ else if (alg_a & SSL_aKRB5)
+ {
+ /* VRS something else here? */
+ return(NULL);
+ }
+ else if (alg_a & SSL_aGOST94)
+ i=SSL_PKEY_GOST94;
+ else if (alg_a & SSL_aGOST01)
+ i=SSL_PKEY_GOST01;
+ else /* if (alg_a & SSL_aNULL) */
+ {
+ SSLerr(SSL_F_SSL_GET_SERVER_SEND_PKEY,ERR_R_INTERNAL_ERROR);
+ return(NULL);
+ }
+
+ return c->pkeys + i;
+ }
+
+X509 *ssl_get_server_send_cert(const SSL *s)
+ {
+ CERT_PKEY *cpk;
+ cpk = ssl_get_server_send_pkey(s);
+ if (!cpk)
+ return NULL;
+ return cpk->x509;
+ }
+
+EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
+ {
+ unsigned long alg_a;
+ CERT *c;
+ int idx = -1;
+
+ alg_a = cipher->algorithm_auth;
+ c=s->cert;
+
+ if ((alg_a & SSL_aDSS) &&
+ (c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL))
+ idx = SSL_PKEY_DSA_SIGN;
+ else if (alg_a & SSL_aRSA)
+ {
+ if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL)
+ idx = SSL_PKEY_RSA_SIGN;
+ else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL)
+ idx = SSL_PKEY_RSA_ENC;
+ }
+ else if ((alg_a & SSL_aECDSA) &&
+ (c->pkeys[SSL_PKEY_ECC].privatekey != NULL))
+ idx = SSL_PKEY_ECC;
+ if (idx == -1)
+ {
+ SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR);
+ return(NULL);
+ }
+ if (pmd)
+ *pmd = c->pkeys[idx].digest;
+ return c->pkeys[idx].privatekey;
+ }
+
+void ssl_update_cache(SSL *s,int mode)
+ {
+ int i;
+
+ /* If the session_id_length is 0, we are not supposed to cache it,
+ * and it would be rather hard to do anyway :-) */
+ if (s->session->session_id_length == 0) return;
+
+ i=s->session_ctx->session_cache_mode;
+ if ((i & mode) && (!s->hit)
+ && ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
+ || SSL_CTX_add_session(s->session_ctx,s->session))
+ && (s->session_ctx->new_session_cb != NULL))
+ {
+ CRYPTO_add(&s->session->references,1,CRYPTO_LOCK_SSL_SESSION);
+ if (!s->session_ctx->new_session_cb(s,s->session))
+ SSL_SESSION_free(s->session);
+ }
+
+ /* auto flush every 255 connections */
+ if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) &&
+ ((i & mode) == mode))
+ {
+ if ( (((mode & SSL_SESS_CACHE_CLIENT)
+ ?s->session_ctx->stats.sess_connect_good
+ :s->session_ctx->stats.sess_accept_good) & 0xff) == 0xff)
+ {
+ SSL_CTX_flush_sessions(s->session_ctx,(unsigned long)time(NULL));
+ }
+ }
+ }
+
+const SSL_METHOD *SSL_get_ssl_method(SSL *s)
+ {
+ return(s->method);
+ }
+
+int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth)
+ {
+ int conn= -1;
+ int ret=1;
+
+ if (s->method != meth)
+ {
+ if (s->handshake_func != NULL)
+ conn=(s->handshake_func == s->method->ssl_connect);
+
+ if (s->method->version == meth->version)
+ s->method=meth;
+ else
+ {
+ s->method->ssl_free(s);
+ s->method=meth;
+ ret=s->method->ssl_new(s);
+ }
+
+ if (conn == 1)
+ s->handshake_func=meth->ssl_connect;
+ else if (conn == 0)
+ s->handshake_func=meth->ssl_accept;
+ }
+ return(ret);
+ }
+
+int SSL_get_error(const SSL *s,int i)
+ {
+ int reason;
+ unsigned long l;
+ BIO *bio;
+
+ if (i > 0) return(SSL_ERROR_NONE);
+
+ /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake
+ * etc, where we do encode the error */
+ if ((l=ERR_peek_error()) != 0)
+ {
+ if (ERR_GET_LIB(l) == ERR_LIB_SYS)
+ return(SSL_ERROR_SYSCALL);
+ else
+ return(SSL_ERROR_SSL);
+ }
+
+ if ((i < 0) && SSL_want_read(s))
+ {
+ bio=SSL_get_rbio(s);
+ if (BIO_should_read(bio))
+ return(SSL_ERROR_WANT_READ);
+ else if (BIO_should_write(bio))
+ /* This one doesn't make too much sense ... We never try
+ * to write to the rbio, and an application program where
+ * rbio and wbio are separate couldn't even know what it
+ * should wait for.
+ * However if we ever set s->rwstate incorrectly
+ * (so that we have SSL_want_read(s) instead of
+ * SSL_want_write(s)) and rbio and wbio *are* the same,
+ * this test works around that bug; so it might be safer
+ * to keep it. */
+ return(SSL_ERROR_WANT_WRITE);
+ else if (BIO_should_io_special(bio))
+ {
+ reason=BIO_get_retry_reason(bio);
+ if (reason == BIO_RR_CONNECT)
+ return(SSL_ERROR_WANT_CONNECT);
+ else if (reason == BIO_RR_ACCEPT)
+ return(SSL_ERROR_WANT_ACCEPT);
+ else
+ return(SSL_ERROR_SYSCALL); /* unknown */
+ }
+ }
+
+ if ((i < 0) && SSL_want_write(s))
+ {
+ bio=SSL_get_wbio(s);
+ if (BIO_should_write(bio))
+ return(SSL_ERROR_WANT_WRITE);
+ else if (BIO_should_read(bio))
+ /* See above (SSL_want_read(s) with BIO_should_write(bio)) */
+ return(SSL_ERROR_WANT_READ);
+ else if (BIO_should_io_special(bio))
+ {
+ reason=BIO_get_retry_reason(bio);
+ if (reason == BIO_RR_CONNECT)
+ return(SSL_ERROR_WANT_CONNECT);
+ else if (reason == BIO_RR_ACCEPT)
+ return(SSL_ERROR_WANT_ACCEPT);
+ else
+ return(SSL_ERROR_SYSCALL);
+ }
+ }
+ if ((i < 0) && SSL_want_x509_lookup(s))
+ {
+ return(SSL_ERROR_WANT_X509_LOOKUP);
+ }
+
+ if (i == 0)
+ {
+ if (s->version == SSL2_VERSION)
+ {
+ /* assume it is the socket being closed */
+ return(SSL_ERROR_ZERO_RETURN);
+ }
+ else
+ {
+ if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) &&
+ (s->s3->warn_alert == SSL_AD_CLOSE_NOTIFY))
+ return(SSL_ERROR_ZERO_RETURN);
+ }
+ }
+ return(SSL_ERROR_SYSCALL);
+ }
+
+int SSL_do_handshake(SSL *s)
+ {
+ int ret=1;
+
+ if (s->handshake_func == NULL)
+ {
+ SSLerr(SSL_F_SSL_DO_HANDSHAKE,SSL_R_CONNECTION_TYPE_NOT_SET);
+ return(-1);
+ }
+
+ s->method->ssl_renegotiate_check(s);
+
+ if (SSL_in_init(s) || SSL_in_before(s))
+ {
+ ret=s->handshake_func(s);
+ }
+ return(ret);
+ }
+
+/* For the next 2 functions, SSL_clear() sets shutdown and so
+ * one of these calls will reset it */
+void SSL_set_accept_state(SSL *s)
+ {
+ s->server=1;
+ s->shutdown=0;
+ s->state=SSL_ST_ACCEPT|SSL_ST_BEFORE;
+ s->handshake_func=s->method->ssl_accept;
+ /* clear the current cipher */
+ ssl_clear_cipher_ctx(s);
+ ssl_clear_hash_ctx(&s->read_hash);
+ ssl_clear_hash_ctx(&s->write_hash);
+ }
+
+void SSL_set_connect_state(SSL *s)
+ {
+ s->server=0;
+ s->shutdown=0;
+ s->state=SSL_ST_CONNECT|SSL_ST_BEFORE;
+ s->handshake_func=s->method->ssl_connect;
+ /* clear the current cipher */
+ ssl_clear_cipher_ctx(s);
+ ssl_clear_hash_ctx(&s->read_hash);
+ ssl_clear_hash_ctx(&s->write_hash);
+ }
+
+int ssl_undefined_function(SSL *s)
+ {
+ SSLerr(SSL_F_SSL_UNDEFINED_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return(0);
+ }
+
+int ssl_undefined_void_function(void)
+ {
+ SSLerr(SSL_F_SSL_UNDEFINED_VOID_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return(0);
+ }
+
+int ssl_undefined_const_function(const SSL *s)
+ {
+ SSLerr(SSL_F_SSL_UNDEFINED_CONST_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return(0);
+ }
+
+SSL_METHOD *ssl_bad_method(int ver)
+ {
+ SSLerr(SSL_F_SSL_BAD_METHOD,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return(NULL);
+ }
+
+const char *SSL_get_version(const SSL *s)
+ {
+ if (s->version == TLS1_2_VERSION)
+ return("TLSv1.2");
+ else if (s->version == TLS1_1_VERSION)
+ return("TLSv1.1");
+ else if (s->version == TLS1_VERSION)
+ return("TLSv1");
+ else if (s->version == SSL3_VERSION)
+ return("SSLv3");
+ else if (s->version == SSL2_VERSION)
+ return("SSLv2");
+ else
+ return("unknown");
+ }
+
+SSL *SSL_dup(SSL *s)
+ {
+ STACK_OF(X509_NAME) *sk;
+ X509_NAME *xn;
+ SSL *ret;
+ int i;
+
+ if ((ret=SSL_new(SSL_get_SSL_CTX(s))) == NULL)
+ return(NULL);
+
+ ret->version = s->version;
+ ret->type = s->type;
+ ret->method = s->method;
+
+ if (s->session != NULL)
+ {
+ /* This copies session-id, SSL_METHOD, sid_ctx, and 'cert' */
+ SSL_copy_session_id(ret,s);
+ }
+ else
+ {
+ /* No session has been established yet, so we have to expect
+ * that s->cert or ret->cert will be changed later --
+ * they should not both point to the same object,
+ * and thus we can't use SSL_copy_session_id. */
+
+ ret->method->ssl_free(ret);
+ ret->method = s->method;
+ ret->method->ssl_new(ret);
+
+ if (s->cert != NULL)
+ {
+ if (ret->cert != NULL)
+ {
+ ssl_cert_free(ret->cert);
+ }
+ ret->cert = ssl_cert_dup(s->cert);
+ if (ret->cert == NULL)
+ goto err;
+ }
+
+ SSL_set_session_id_context(ret,
+ s->sid_ctx, s->sid_ctx_length);
+ }
+
+ ret->options=s->options;
+ ret->mode=s->mode;
+ SSL_set_max_cert_list(ret,SSL_get_max_cert_list(s));
+ SSL_set_read_ahead(ret,SSL_get_read_ahead(s));
+ ret->msg_callback = s->msg_callback;
+ ret->msg_callback_arg = s->msg_callback_arg;
+ SSL_set_verify(ret,SSL_get_verify_mode(s),
+ SSL_get_verify_callback(s));
+ SSL_set_verify_depth(ret,SSL_get_verify_depth(s));
+ ret->generate_session_id = s->generate_session_id;
+
+ SSL_set_info_callback(ret,SSL_get_info_callback(s));
+
+ ret->debug=s->debug;
+
+ /* copy app data, a little dangerous perhaps */
+ if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL, &ret->ex_data, &s->ex_data))
+ goto err;
+
+ /* setup rbio, and wbio */
+ if (s->rbio != NULL)
+ {
+ if (!BIO_dup_state(s->rbio,(char *)&ret->rbio))
+ goto err;
+ }
+ if (s->wbio != NULL)
+ {
+ if (s->wbio != s->rbio)
+ {
+ if (!BIO_dup_state(s->wbio,(char *)&ret->wbio))
+ goto err;
+ }
+ else
+ ret->wbio=ret->rbio;
+ }
+ ret->rwstate = s->rwstate;
+ ret->in_handshake = s->in_handshake;
+ ret->handshake_func = s->handshake_func;
+ ret->server = s->server;
+ ret->renegotiate = s->renegotiate;
+ ret->new_session = s->new_session;
+ ret->quiet_shutdown = s->quiet_shutdown;
+ ret->shutdown=s->shutdown;
+ ret->state=s->state; /* SSL_dup does not really work at any state, though */
+ ret->rstate=s->rstate;
+ ret->init_num = 0; /* would have to copy ret->init_buf, ret->init_msg, ret->init_num, ret->init_off */
+ ret->hit=s->hit;
+
+ X509_VERIFY_PARAM_inherit(ret->param, s->param);
+
+ /* dup the cipher_list and cipher_list_by_id stacks */
+ if (s->cipher_list != NULL)
+ {
+ if ((ret->cipher_list=sk_SSL_CIPHER_dup(s->cipher_list)) == NULL)
+ goto err;
+ }
+ if (s->cipher_list_by_id != NULL)
+ if ((ret->cipher_list_by_id=sk_SSL_CIPHER_dup(s->cipher_list_by_id))
+ == NULL)
+ goto err;
+
+ /* Dup the client_CA list */
+ if (s->client_CA != NULL)
+ {
+ if ((sk=sk_X509_NAME_dup(s->client_CA)) == NULL) goto err;
+ ret->client_CA=sk;
+ for (i=0; i<sk_X509_NAME_num(sk); i++)
+ {
+ xn=sk_X509_NAME_value(sk,i);
+ if (sk_X509_NAME_set(sk,i,X509_NAME_dup(xn)) == NULL)
+ {
+ X509_NAME_free(xn);
+ goto err;
+ }
+ }
+ }
+
+ if (0)
+ {
+err:
+ if (ret != NULL) SSL_free(ret);
+ ret=NULL;
+ }
+ return(ret);
+ }
+
+void ssl_clear_cipher_ctx(SSL *s)
+ {
+ if (s->enc_read_ctx != NULL)
+ {
+ EVP_CIPHER_CTX_cleanup(s->enc_read_ctx);
+ OPENSSL_free(s->enc_read_ctx);
+ s->enc_read_ctx=NULL;
+ }
+ if (s->enc_write_ctx != NULL)
+ {
+ EVP_CIPHER_CTX_cleanup(s->enc_write_ctx);
+ OPENSSL_free(s->enc_write_ctx);
+ s->enc_write_ctx=NULL;
+ }
+#ifndef OPENSSL_NO_COMP
+ if (s->expand != NULL)
+ {
+ COMP_CTX_free(s->expand);
+ s->expand=NULL;
+ }
+ if (s->compress != NULL)
+ {
+ COMP_CTX_free(s->compress);
+ s->compress=NULL;
+ }
+#endif
+ }
+
+/* Fix this function so that it takes an optional type parameter */
+X509 *SSL_get_certificate(const SSL *s)
+ {
+ if (s->cert != NULL)
+ return(s->cert->key->x509);
+ else
+ return(NULL);
+ }
+
+/* Fix this function so that it takes an optional type parameter */
+EVP_PKEY *SSL_get_privatekey(SSL *s)
+ {
+ if (s->cert != NULL)
+ return(s->cert->key->privatekey);
+ else
+ return(NULL);
+ }
+
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
+ {
+ if ((s->session != NULL) && (s->session->cipher != NULL))
+ return(s->session->cipher);
+ return(NULL);
+ }
+#ifdef OPENSSL_NO_COMP
+const void *SSL_get_current_compression(SSL *s)
+ {
+ return NULL;
+ }
+const void *SSL_get_current_expansion(SSL *s)
+ {
+ return NULL;
+ }
+#else
+
+const COMP_METHOD *SSL_get_current_compression(SSL *s)
+ {
+ if (s->compress != NULL)
+ return(s->compress->meth);
+ return(NULL);
+ }
+
+const COMP_METHOD *SSL_get_current_expansion(SSL *s)
+ {
+ if (s->expand != NULL)
+ return(s->expand->meth);
+ return(NULL);
+ }
+#endif
+
+int ssl_init_wbio_buffer(SSL *s,int push)
+ {
+ BIO *bbio;
+
+ if (s->bbio == NULL)
+ {
+ bbio=BIO_new(BIO_f_buffer());
+ if (bbio == NULL) return(0);
+ s->bbio=bbio;
+ }
+ else
+ {
+ bbio=s->bbio;
+ if (s->bbio == s->wbio)
+ s->wbio=BIO_pop(s->wbio);
+ }
+ (void)BIO_reset(bbio);
+/* if (!BIO_set_write_buffer_size(bbio,16*1024)) */
+ if (!BIO_set_read_buffer_size(bbio,1))
+ {
+ SSLerr(SSL_F_SSL_INIT_WBIO_BUFFER,ERR_R_BUF_LIB);
+ return(0);
+ }
+ if (push)
+ {
+ if (s->wbio != bbio)
+ s->wbio=BIO_push(bbio,s->wbio);
+ }
+ else
+ {
+ if (s->wbio == bbio)
+ s->wbio=BIO_pop(bbio);
+ }
+ return(1);
+ }
+
+void ssl_free_wbio_buffer(SSL *s)
+ {
+ if (s->bbio == NULL) return;
+
+ if (s->bbio == s->wbio)
+ {
+ /* remove buffering */
+ s->wbio=BIO_pop(s->wbio);
+#ifdef REF_CHECK /* not the usual REF_CHECK, but this avoids adding one more preprocessor symbol */
+ assert(s->wbio != NULL);
+#endif
+ }
+ BIO_free(s->bbio);
+ s->bbio=NULL;
+ }
+
+void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode)
+ {
+ ctx->quiet_shutdown=mode;
+ }
+
+int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx)
+ {
+ return(ctx->quiet_shutdown);
+ }
+
+void SSL_set_quiet_shutdown(SSL *s,int mode)
+ {
+ s->quiet_shutdown=mode;
+ }
+
+int SSL_get_quiet_shutdown(const SSL *s)
+ {
+ return(s->quiet_shutdown);
+ }
+
+void SSL_set_shutdown(SSL *s,int mode)
+ {
+ s->shutdown=mode;
+ }
+
+int SSL_get_shutdown(const SSL *s)
+ {
+ return(s->shutdown);
+ }
+
+int SSL_version(const SSL *s)
+ {
+ return(s->version);
+ }
+
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
+ {
+ return(ssl->ctx);
+ }
+
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
+ {
+ if (ssl->ctx == ctx)
+ return ssl->ctx;
+#ifndef OPENSSL_NO_TLSEXT
+ if (ctx == NULL)
+ ctx = ssl->initial_ctx;
+#endif
+ if (ssl->cert != NULL)
+ ssl_cert_free(ssl->cert);
+ ssl->cert = ssl_cert_dup(ctx->cert);
+ CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+ if (ssl->ctx != NULL)
+ SSL_CTX_free(ssl->ctx); /* decrement reference count */
+ ssl->ctx = ctx;
+ return(ssl->ctx);
+ }
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
+ {
+ return(X509_STORE_set_default_paths(ctx->cert_store));
+ }
+
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+ const char *CApath)
+ {
+ return(X509_STORE_load_locations(ctx->cert_store,CAfile,CApath));
+ }
+#endif
+
+void SSL_set_info_callback(SSL *ssl,
+ void (*cb)(const SSL *ssl,int type,int val))
+ {
+ ssl->info_callback=cb;
+ }
+
+/* One compiler (Diab DCC) doesn't like argument names in returned
+ function pointer. */
+void (*SSL_get_info_callback(const SSL *ssl))(const SSL * /*ssl*/,int /*type*/,int /*val*/)
+ {
+ return ssl->info_callback;
+ }
+
+int SSL_state(const SSL *ssl)
+ {
+ return(ssl->state);
+ }
+
+void SSL_set_state(SSL *ssl, int state)
+ {
+ ssl->state = state;
+ }
+
+void SSL_set_verify_result(SSL *ssl,long arg)
+ {
+ ssl->verify_result=arg;
+ }
+
+long SSL_get_verify_result(const SSL *ssl)
+ {
+ return(ssl->verify_result);
+ }
+
+int SSL_get_ex_new_index(long argl,void *argp,CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func,CRYPTO_EX_free *free_func)
+ {
+ return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, argl, argp,
+ new_func, dup_func, free_func);
+ }
+
+int SSL_set_ex_data(SSL *s,int idx,void *arg)
+ {
+ return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
+ }
+
+void *SSL_get_ex_data(const SSL *s,int idx)
+ {
+ return(CRYPTO_get_ex_data(&s->ex_data,idx));
+ }
+
+int SSL_CTX_get_ex_new_index(long argl,void *argp,CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func,CRYPTO_EX_free *free_func)
+ {
+ return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, argl, argp,
+ new_func, dup_func, free_func);
+ }
+
+int SSL_CTX_set_ex_data(SSL_CTX *s,int idx,void *arg)
+ {
+ return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
+ }
+
+void *SSL_CTX_get_ex_data(const SSL_CTX *s,int idx)
+ {
+ return(CRYPTO_get_ex_data(&s->ex_data,idx));
+ }
+
+int ssl_ok(SSL *s)
+ {
+ return(1);
+ }
+
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx)
+ {
+ return(ctx->cert_store);
+ }
+
+void SSL_CTX_set_cert_store(SSL_CTX *ctx,X509_STORE *store)
+ {
+ if (ctx->cert_store != NULL)
+ X509_STORE_free(ctx->cert_store);
+ ctx->cert_store=store;
+ }
+
+int SSL_want(const SSL *s)
+ {
+ return(s->rwstate);
+ }
+
+/*!
+ * \brief Set the callback for generating temporary RSA keys.
+ * \param ctx the SSL context.
+ * \param cb the callback
+ */
+
+#ifndef OPENSSL_NO_RSA
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,RSA *(*cb)(SSL *ssl,
+ int is_export,
+ int keylength))
+ {
+ SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,(void (*)(void))cb);
+ }
+
+void SSL_set_tmp_rsa_callback(SSL *ssl,RSA *(*cb)(SSL *ssl,
+ int is_export,
+ int keylength))
+ {
+ SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_RSA_CB,(void (*)(void))cb);
+ }
+#endif
+
+#ifdef DOXYGEN
+/*!
+ * \brief The RSA temporary key callback function.
+ * \param ssl the SSL session.
+ * \param is_export \c TRUE if the temp RSA key is for an export ciphersuite.
+ * \param keylength if \c is_export is \c TRUE, then \c keylength is the size
+ * of the required key in bits.
+ * \return the temporary RSA key.
+ * \sa SSL_CTX_set_tmp_rsa_callback, SSL_set_tmp_rsa_callback
+ */
+
+RSA *cb(SSL *ssl,int is_export,int keylength)
+ {}
+#endif
+
+/*!
+ * \brief Set the callback for generating temporary DH keys.
+ * \param ctx the SSL context.
+ * \param dh the callback
+ */
+
+#ifndef OPENSSL_NO_DH
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int is_export,
+ int keylength))
+ {
+ SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
+ }
+
+void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export,
+ int keylength))
+ {
+ SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
+ }
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+ int keylength))
+ {
+ SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
+ }
+
+void SSL_set_tmp_ecdh_callback(SSL *ssl,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+ int keylength))
+ {
+ SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
+ }
+#endif
+
+#ifndef OPENSSL_NO_PSK
+int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
+ {
+ if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN)
+ {
+ SSLerr(SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
+ return 0;
+ }
+ if (ctx->psk_identity_hint != NULL)
+ OPENSSL_free(ctx->psk_identity_hint);
+ if (identity_hint != NULL)
+ {
+ ctx->psk_identity_hint = BUF_strdup(identity_hint);
+ if (ctx->psk_identity_hint == NULL)
+ return 0;
+ }
+ else
+ ctx->psk_identity_hint = NULL;
+ return 1;
+ }
+
+int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint)
+ {
+ if (s == NULL)
+ return 0;
+
+ if (s->session == NULL)
+ return 1; /* session not created yet, ignored */
+
+ if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN)
+ {
+ SSLerr(SSL_F_SSL_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
+ return 0;
+ }
+ if (s->session->psk_identity_hint != NULL)
+ OPENSSL_free(s->session->psk_identity_hint);
+ if (identity_hint != NULL)
+ {
+ s->session->psk_identity_hint = BUF_strdup(identity_hint);
+ if (s->session->psk_identity_hint == NULL)
+ return 0;
+ }
+ else
+ s->session->psk_identity_hint = NULL;
+ return 1;
+ }
+
+const char *SSL_get_psk_identity_hint(const SSL *s)
+ {
+ if (s == NULL || s->session == NULL)
+ return NULL;
+ return(s->session->psk_identity_hint);
+ }
+
+const char *SSL_get_psk_identity(const SSL *s)
+ {
+ if (s == NULL || s->session == NULL)
+ return NULL;
+ return(s->session->psk_identity);
+ }
+
+void SSL_set_psk_client_callback(SSL *s,
+ unsigned int (*cb)(SSL *ssl, const char *hint,
+ char *identity, unsigned int max_identity_len, unsigned char *psk,
+ unsigned int max_psk_len))
+ {
+ s->psk_client_callback = cb;
+ }
+
+void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx,
+ unsigned int (*cb)(SSL *ssl, const char *hint,
+ char *identity, unsigned int max_identity_len, unsigned char *psk,
+ unsigned int max_psk_len))
+ {
+ ctx->psk_client_callback = cb;
+ }
+
+void SSL_set_psk_server_callback(SSL *s,
+ unsigned int (*cb)(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len))
+ {
+ s->psk_server_callback = cb;
+ }
+
+void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx,
+ unsigned int (*cb)(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len))
+ {
+ ctx->psk_server_callback = cb;
+ }
+#endif
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
+ {
+ SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+ }
+void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
+ {
+ SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+ }
+
+/* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
+ * vairable, freeing EVP_MD_CTX previously stored in that variable, if
+ * any. If EVP_MD pointer is passed, initializes ctx with this md
+ * Returns newly allocated ctx;
+ */
+
+EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md)
+{
+ ssl_clear_hash_ctx(hash);
+ *hash = EVP_MD_CTX_create();
+ if (md) EVP_DigestInit_ex(*hash,md,NULL);
+ return *hash;
+}
+void ssl_clear_hash_ctx(EVP_MD_CTX **hash)
+{
+
+ if (*hash) EVP_MD_CTX_destroy(*hash);
+ *hash=NULL;
+}
+
+void SSL_set_debug(SSL *s, int debug)
+ {
+ s->debug = debug;
+ }
+
+int SSL_cache_hit(SSL *s)
+ {
+ return s->hit;
+ }
+
+#if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
+#include "../crypto/bio/bss_file.c"
+#endif
+
+IMPLEMENT_STACK_OF(SSL_CIPHER)
+IMPLEMENT_STACK_OF(SSL_COMP)
+IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER,
+ ssl_cipher_id);
diff --git a/drivers/builtin_openssl/ssl/ssl_locl.h b/drivers/builtin_openssl2/ssl/ssl_locl.h
index e485907748..e485907748 100644
--- a/drivers/builtin_openssl/ssl/ssl_locl.h
+++ b/drivers/builtin_openssl2/ssl/ssl_locl.h
diff --git a/drivers/builtin_openssl/ssl/ssl_rsa.c b/drivers/builtin_openssl2/ssl/ssl_rsa.c
index 60e7b66859..60e7b66859 100644
--- a/drivers/builtin_openssl/ssl/ssl_rsa.c
+++ b/drivers/builtin_openssl2/ssl/ssl_rsa.c
diff --git a/drivers/builtin_openssl/ssl/ssl_sess.c b/drivers/builtin_openssl2/ssl/ssl_sess.c
index ad40fadd02..ad40fadd02 100644
--- a/drivers/builtin_openssl/ssl/ssl_sess.c
+++ b/drivers/builtin_openssl2/ssl/ssl_sess.c
diff --git a/drivers/builtin_openssl/ssl/ssl_stat.c b/drivers/builtin_openssl2/ssl/ssl_stat.c
index 144b81e55f..144b81e55f 100644
--- a/drivers/builtin_openssl/ssl/ssl_stat.c
+++ b/drivers/builtin_openssl2/ssl/ssl_stat.c
diff --git a/drivers/builtin_openssl/ssl/ssl_task.c b/drivers/builtin_openssl2/ssl/ssl_task.c
index b5ce44b47c..b5ce44b47c 100644
--- a/drivers/builtin_openssl/ssl/ssl_task.c
+++ b/drivers/builtin_openssl2/ssl/ssl_task.c
diff --git a/drivers/builtin_openssl/ssl/ssl_txt.c b/drivers/builtin_openssl2/ssl/ssl_txt.c
index 6479d52c0c..6479d52c0c 100644
--- a/drivers/builtin_openssl/ssl/ssl_txt.c
+++ b/drivers/builtin_openssl2/ssl/ssl_txt.c
diff --git a/drivers/builtin_openssl/ssl/ssltest.c b/drivers/builtin_openssl2/ssl/ssltest.c
index 4f80be8ee4..4f80be8ee4 100644
--- a/drivers/builtin_openssl/ssl/ssltest.c
+++ b/drivers/builtin_openssl2/ssl/ssltest.c
diff --git a/drivers/builtin_openssl/ssl/t1_clnt.c b/drivers/builtin_openssl2/ssl/t1_clnt.c
index 578617ed84..578617ed84 100644
--- a/drivers/builtin_openssl/ssl/t1_clnt.c
+++ b/drivers/builtin_openssl2/ssl/t1_clnt.c
diff --git a/drivers/builtin_openssl2/ssl/t1_enc.c b/drivers/builtin_openssl2/ssl/t1_enc.c
new file mode 100644
index 0000000000..ac8c153996
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/t1_enc.c
@@ -0,0 +1,1250 @@
+/* ssl/t1_enc.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#ifndef OPENSSL_NO_COMP
+#include <openssl/comp.h>
+#endif
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#include <openssl/rand.h>
+#ifdef KSSL_DEBUG
+#include <openssl/des.h>
+#endif
+
+/* seed1 through seed5 are virtually concatenated */
+static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
+ int sec_len,
+ const void *seed1, int seed1_len,
+ const void *seed2, int seed2_len,
+ const void *seed3, int seed3_len,
+ const void *seed4, int seed4_len,
+ const void *seed5, int seed5_len,
+ unsigned char *out, int olen)
+ {
+ int chunk;
+ size_t j;
+ EVP_MD_CTX ctx, ctx_tmp;
+ EVP_PKEY *mac_key;
+ unsigned char A1[EVP_MAX_MD_SIZE];
+ size_t A1_len;
+ int ret = 0;
+
+ chunk=EVP_MD_size(md);
+ OPENSSL_assert(chunk >= 0);
+
+ EVP_MD_CTX_init(&ctx);
+ EVP_MD_CTX_init(&ctx_tmp);
+ EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ EVP_MD_CTX_set_flags(&ctx_tmp, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len);
+ if (!mac_key)
+ goto err;
+ if (!EVP_DigestSignInit(&ctx,NULL,md, NULL, mac_key))
+ goto err;
+ if (!EVP_DigestSignInit(&ctx_tmp,NULL,md, NULL, mac_key))
+ goto err;
+ if (seed1 && !EVP_DigestSignUpdate(&ctx,seed1,seed1_len))
+ goto err;
+ if (seed2 && !EVP_DigestSignUpdate(&ctx,seed2,seed2_len))
+ goto err;
+ if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
+ goto err;
+ if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
+ goto err;
+ if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
+ goto err;
+ if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
+ goto err;
+
+ for (;;)
+ {
+ /* Reinit mac contexts */
+ if (!EVP_DigestSignInit(&ctx,NULL,md, NULL, mac_key))
+ goto err;
+ if (!EVP_DigestSignInit(&ctx_tmp,NULL,md, NULL, mac_key))
+ goto err;
+ if (!EVP_DigestSignUpdate(&ctx,A1,A1_len))
+ goto err;
+ if (!EVP_DigestSignUpdate(&ctx_tmp,A1,A1_len))
+ goto err;
+ if (seed1 && !EVP_DigestSignUpdate(&ctx,seed1,seed1_len))
+ goto err;
+ if (seed2 && !EVP_DigestSignUpdate(&ctx,seed2,seed2_len))
+ goto err;
+ if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
+ goto err;
+ if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
+ goto err;
+ if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
+ goto err;
+
+ if (olen > chunk)
+ {
+ if (!EVP_DigestSignFinal(&ctx,out,&j))
+ goto err;
+ out+=j;
+ olen-=j;
+ /* calc the next A1 value */
+ if (!EVP_DigestSignFinal(&ctx_tmp,A1,&A1_len))
+ goto err;
+ }
+ else /* last one */
+ {
+ if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
+ goto err;
+ memcpy(out,A1,olen);
+ break;
+ }
+ }
+ ret = 1;
+err:
+ EVP_PKEY_free(mac_key);
+ EVP_MD_CTX_cleanup(&ctx);
+ EVP_MD_CTX_cleanup(&ctx_tmp);
+ OPENSSL_cleanse(A1,sizeof(A1));
+ return ret;
+ }
+
+/* seed1 through seed5 are virtually concatenated */
+static int tls1_PRF(long digest_mask,
+ const void *seed1, int seed1_len,
+ const void *seed2, int seed2_len,
+ const void *seed3, int seed3_len,
+ const void *seed4, int seed4_len,
+ const void *seed5, int seed5_len,
+ const unsigned char *sec, int slen,
+ unsigned char *out1,
+ unsigned char *out2, int olen)
+ {
+ int len,i,idx,count;
+ const unsigned char *S1;
+ long m;
+ const EVP_MD *md;
+ int ret = 0;
+
+ /* Count number of digests and partition sec evenly */
+ count=0;
+ for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
+ if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) count++;
+ }
+ len=slen/count;
+ if (count == 1)
+ slen = 0;
+ S1=sec;
+ memset(out1,0,olen);
+ for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
+ if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) {
+ if (!md) {
+ SSLerr(SSL_F_TLS1_PRF,
+ SSL_R_UNSUPPORTED_DIGEST_TYPE);
+ goto err;
+ }
+ if (!tls1_P_hash(md ,S1,len+(slen&1),
+ seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
+ out2,olen))
+ goto err;
+ S1+=len;
+ for (i=0; i<olen; i++)
+ {
+ out1[i]^=out2[i];
+ }
+ }
+ }
+ ret = 1;
+err:
+ return ret;
+}
+static int tls1_generate_key_block(SSL *s, unsigned char *km,
+ unsigned char *tmp, int num)
+ {
+ int ret;
+ ret = tls1_PRF(ssl_get_algorithm2(s),
+ TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
+ s->s3->server_random,SSL3_RANDOM_SIZE,
+ s->s3->client_random,SSL3_RANDOM_SIZE,
+ NULL,0,NULL,0,
+ s->session->master_key,s->session->master_key_length,
+ km,tmp,num);
+#ifdef KSSL_DEBUG
+ printf("tls1_generate_key_block() ==> %d byte master_key =\n\t",
+ s->session->master_key_length);
+ {
+ int i;
+ for (i=0; i < s->session->master_key_length; i++)
+ {
+ printf("%02X", s->session->master_key[i]);
+ }
+ printf("\n"); }
+#endif /* KSSL_DEBUG */
+ return ret;
+ }
+
+int tls1_change_cipher_state(SSL *s, int which)
+ {
+ static const unsigned char empty[]="";
+ unsigned char *p,*mac_secret;
+ unsigned char *exp_label;
+ unsigned char tmp1[EVP_MAX_KEY_LENGTH];
+ unsigned char tmp2[EVP_MAX_KEY_LENGTH];
+ unsigned char iv1[EVP_MAX_IV_LENGTH*2];
+ unsigned char iv2[EVP_MAX_IV_LENGTH*2];
+ unsigned char *ms,*key,*iv;
+ int client_write;
+ EVP_CIPHER_CTX *dd;
+ const EVP_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
+ const SSL_COMP *comp;
+#endif
+ const EVP_MD *m;
+ int mac_type;
+ int *mac_secret_size;
+ EVP_MD_CTX *mac_ctx;
+ EVP_PKEY *mac_key;
+ int is_export,n,i,j,k,exp_label_len,cl;
+ int reuse_dd = 0;
+
+ is_export=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
+ c=s->s3->tmp.new_sym_enc;
+ m=s->s3->tmp.new_hash;
+ mac_type = s->s3->tmp.new_mac_pkey_type;
+#ifndef OPENSSL_NO_COMP
+ comp=s->s3->tmp.new_compression;
+#endif
+
+#ifdef KSSL_DEBUG
+ printf("tls1_change_cipher_state(which= %d) w/\n", which);
+ printf("\talg= %ld/%ld, comp= %p\n",
+ s->s3->tmp.new_cipher->algorithm_mkey,
+ s->s3->tmp.new_cipher->algorithm_auth,
+ comp);
+ printf("\tevp_cipher == %p ==? &d_cbc_ede_cipher3\n", c);
+ printf("\tevp_cipher: nid, blksz= %d, %d, keylen=%d, ivlen=%d\n",
+ c->nid,c->block_size,c->key_len,c->iv_len);
+ printf("\tkey_block: len= %d, data= ", s->s3->tmp.key_block_length);
+ {
+ int i;
+ for (i=0; i<s->s3->tmp.key_block_length; i++)
+ printf("%02x", s->s3->tmp.key_block[i]); printf("\n");
+ }
+#endif /* KSSL_DEBUG */
+
+ if (which & SSL3_CC_READ)
+ {
+ if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
+ s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM;
+ else
+ s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM;
+
+ if (s->enc_read_ctx != NULL)
+ reuse_dd = 1;
+ else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
+ goto err;
+ else
+ /* make sure it's intialized in case we exit later with an error */
+ EVP_CIPHER_CTX_init(s->enc_read_ctx);
+ dd= s->enc_read_ctx;
+ mac_ctx=ssl_replace_hash(&s->read_hash,NULL);
+#ifndef OPENSSL_NO_COMP
+ if (s->expand != NULL)
+ {
+ COMP_CTX_free(s->expand);
+ s->expand=NULL;
+ }
+ if (comp != NULL)
+ {
+ s->expand=COMP_CTX_new(comp->method);
+ if (s->expand == NULL)
+ {
+ SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR);
+ goto err2;
+ }
+ if (s->s3->rrec.comp == NULL)
+ s->s3->rrec.comp=(unsigned char *)
+ OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH);
+ if (s->s3->rrec.comp == NULL)
+ goto err;
+ }
+#endif
+ /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
+ if (s->version != DTLS1_VERSION)
+ memset(&(s->s3->read_sequence[0]),0,8);
+ mac_secret= &(s->s3->read_mac_secret[0]);
+ mac_secret_size=&(s->s3->read_mac_secret_size);
+ }
+ else
+ {
+ if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
+ s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
+ else
+ s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM;
+ if (s->enc_write_ctx != NULL && !SSL_IS_DTLS(s))
+ reuse_dd = 1;
+ else if ((s->enc_write_ctx=EVP_CIPHER_CTX_new()) == NULL)
+ goto err;
+ dd= s->enc_write_ctx;
+ if (SSL_IS_DTLS(s))
+ {
+ mac_ctx = EVP_MD_CTX_create();
+ if (!mac_ctx)
+ goto err;
+ s->write_hash = mac_ctx;
+ }
+ else
+ mac_ctx = ssl_replace_hash(&s->write_hash,NULL);
+#ifndef OPENSSL_NO_COMP
+ if (s->compress != NULL)
+ {
+ COMP_CTX_free(s->compress);
+ s->compress=NULL;
+ }
+ if (comp != NULL)
+ {
+ s->compress=COMP_CTX_new(comp->method);
+ if (s->compress == NULL)
+ {
+ SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR);
+ goto err2;
+ }
+ }
+#endif
+ /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
+ if (s->version != DTLS1_VERSION)
+ memset(&(s->s3->write_sequence[0]),0,8);
+ mac_secret= &(s->s3->write_mac_secret[0]);
+ mac_secret_size = &(s->s3->write_mac_secret_size);
+ }
+
+ if (reuse_dd)
+ EVP_CIPHER_CTX_cleanup(dd);
+
+ p=s->s3->tmp.key_block;
+ i=*mac_secret_size=s->s3->tmp.new_mac_secret_size;
+
+ cl=EVP_CIPHER_key_length(c);
+ j=is_export ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
+ cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
+ /* Was j=(exp)?5:EVP_CIPHER_key_length(c); */
+ /* If GCM mode only part of IV comes from PRF */
+ if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
+ k = EVP_GCM_TLS_FIXED_IV_LEN;
+ else
+ k=EVP_CIPHER_iv_length(c);
+ if ( (which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
+ (which == SSL3_CHANGE_CIPHER_SERVER_READ))
+ {
+ ms= &(p[ 0]); n=i+i;
+ key= &(p[ n]); n+=j+j;
+ iv= &(p[ n]); n+=k+k;
+ exp_label=(unsigned char *)TLS_MD_CLIENT_WRITE_KEY_CONST;
+ exp_label_len=TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE;
+ client_write=1;
+ }
+ else
+ {
+ n=i;
+ ms= &(p[ n]); n+=i+j;
+ key= &(p[ n]); n+=j+k;
+ iv= &(p[ n]); n+=k;
+ exp_label=(unsigned char *)TLS_MD_SERVER_WRITE_KEY_CONST;
+ exp_label_len=TLS_MD_SERVER_WRITE_KEY_CONST_SIZE;
+ client_write=0;
+ }
+
+ if (n > s->s3->tmp.key_block_length)
+ {
+ SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,ERR_R_INTERNAL_ERROR);
+ goto err2;
+ }
+
+ memcpy(mac_secret,ms,i);
+
+ if (!(EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER))
+ {
+ mac_key = EVP_PKEY_new_mac_key(mac_type, NULL,
+ mac_secret,*mac_secret_size);
+ EVP_DigestSignInit(mac_ctx,NULL,m,NULL,mac_key);
+ EVP_PKEY_free(mac_key);
+ }
+#ifdef TLS_DEBUG
+printf("which = %04X\nmac key=",which);
+{ int z; for (z=0; z<i; z++) printf("%02X%c",ms[z],((z+1)%16)?' ':'\n'); }
+#endif
+ if (is_export)
+ {
+ /* In here I set both the read and write key/iv to the
+ * same value since only the correct one will be used :-).
+ */
+ if (!tls1_PRF(ssl_get_algorithm2(s),
+ exp_label,exp_label_len,
+ s->s3->client_random,SSL3_RANDOM_SIZE,
+ s->s3->server_random,SSL3_RANDOM_SIZE,
+ NULL,0,NULL,0,
+ key,j,tmp1,tmp2,EVP_CIPHER_key_length(c)))
+ goto err2;
+ key=tmp1;
+
+ if (k > 0)
+ {
+ if (!tls1_PRF(ssl_get_algorithm2(s),
+ TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE,
+ s->s3->client_random,SSL3_RANDOM_SIZE,
+ s->s3->server_random,SSL3_RANDOM_SIZE,
+ NULL,0,NULL,0,
+ empty,0,iv1,iv2,k*2))
+ goto err2;
+ if (client_write)
+ iv=iv1;
+ else
+ iv= &(iv1[k]);
+ }
+ }
+
+ s->session->key_arg_length=0;
+#ifdef KSSL_DEBUG
+ {
+ int i;
+ printf("EVP_CipherInit_ex(dd,c,key=,iv=,which)\n");
+ printf("\tkey= "); for (i=0; i<c->key_len; i++) printf("%02x", key[i]);
+ printf("\n");
+ printf("\t iv= "); for (i=0; i<c->iv_len; i++) printf("%02x", iv[i]);
+ printf("\n");
+ }
+#endif /* KSSL_DEBUG */
+
+ if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
+ {
+ EVP_CipherInit_ex(dd,c,NULL,key,NULL,(which & SSL3_CC_WRITE));
+ EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GCM_SET_IV_FIXED, k, iv);
+ }
+ else
+ EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE));
+
+ /* Needed for "composite" AEADs, such as RC4-HMAC-MD5 */
+ if ((EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER) && *mac_secret_size)
+ EVP_CIPHER_CTX_ctrl(dd,EVP_CTRL_AEAD_SET_MAC_KEY,
+ *mac_secret_size,mac_secret);
+
+#ifdef TLS_DEBUG
+printf("which = %04X\nkey=",which);
+{ int z; for (z=0; z<EVP_CIPHER_key_length(c); z++) printf("%02X%c",key[z],((z+1)%16)?' ':'\n'); }
+printf("\niv=");
+{ int z; for (z=0; z<k; z++) printf("%02X%c",iv[z],((z+1)%16)?' ':'\n'); }
+printf("\n");
+#endif
+
+ OPENSSL_cleanse(tmp1,sizeof(tmp1));
+ OPENSSL_cleanse(tmp2,sizeof(tmp1));
+ OPENSSL_cleanse(iv1,sizeof(iv1));
+ OPENSSL_cleanse(iv2,sizeof(iv2));
+ return(1);
+err:
+ SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,ERR_R_MALLOC_FAILURE);
+err2:
+ return(0);
+ }
+
+int tls1_setup_key_block(SSL *s)
+ {
+ unsigned char *p1,*p2=NULL;
+ const EVP_CIPHER *c;
+ const EVP_MD *hash;
+ int num;
+ SSL_COMP *comp;
+ int mac_type= NID_undef,mac_secret_size=0;
+ int ret=0;
+
+#ifdef KSSL_DEBUG
+ printf ("tls1_setup_key_block()\n");
+#endif /* KSSL_DEBUG */
+
+ if (s->s3->tmp.key_block_length != 0)
+ return(1);
+
+ if (!ssl_cipher_get_evp(s->session,&c,&hash,&mac_type,&mac_secret_size,&comp))
+ {
+ SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+ return(0);
+ }
+
+ s->s3->tmp.new_sym_enc=c;
+ s->s3->tmp.new_hash=hash;
+ s->s3->tmp.new_mac_pkey_type = mac_type;
+ s->s3->tmp.new_mac_secret_size = mac_secret_size;
+ num=EVP_CIPHER_key_length(c)+mac_secret_size+EVP_CIPHER_iv_length(c);
+ num*=2;
+
+ ssl3_cleanup_key_block(s);
+
+ if ((p1=(unsigned char *)OPENSSL_malloc(num)) == NULL)
+ {
+ SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ s->s3->tmp.key_block_length=num;
+ s->s3->tmp.key_block=p1;
+
+ if ((p2=(unsigned char *)OPENSSL_malloc(num)) == NULL)
+ {
+ SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+#ifdef TLS_DEBUG
+printf("client random\n");
+{ int z; for (z=0; z<SSL3_RANDOM_SIZE; z++) printf("%02X%c",s->s3->client_random[z],((z+1)%16)?' ':'\n'); }
+printf("server random\n");
+{ int z; for (z=0; z<SSL3_RANDOM_SIZE; z++) printf("%02X%c",s->s3->server_random[z],((z+1)%16)?' ':'\n'); }
+printf("pre-master\n");
+{ int z; for (z=0; z<s->session->master_key_length; z++) printf("%02X%c",s->session->master_key[z],((z+1)%16)?' ':'\n'); }
+#endif
+ if (!tls1_generate_key_block(s,p1,p2,num))
+ goto err;
+#ifdef TLS_DEBUG
+printf("\nkey block\n");
+{ int z; for (z=0; z<num; z++) printf("%02X%c",p1[z],((z+1)%16)?' ':'\n'); }
+#endif
+
+ if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
+ && s->method->version <= TLS1_VERSION)
+ {
+ /* enable vulnerability countermeasure for CBC ciphers with
+ * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt)
+ */
+ s->s3->need_empty_fragments = 1;
+
+ if (s->session->cipher != NULL)
+ {
+ if (s->session->cipher->algorithm_enc == SSL_eNULL)
+ s->s3->need_empty_fragments = 0;
+
+#ifndef OPENSSL_NO_RC4
+ if (s->session->cipher->algorithm_enc == SSL_RC4)
+ s->s3->need_empty_fragments = 0;
+#endif
+ }
+ }
+
+ ret = 1;
+err:
+ if (p2)
+ {
+ OPENSSL_cleanse(p2,num);
+ OPENSSL_free(p2);
+ }
+ return(ret);
+ }
+
+/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
+ *
+ * Returns:
+ * 0: (in non-constant time) if the record is publically invalid (i.e. too
+ * short etc).
+ * 1: if the record's padding is valid / the encryption was successful.
+ * -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
+ * an internal error occured.
+ */
+int tls1_enc(SSL *s, int send)
+ {
+ SSL3_RECORD *rec;
+ EVP_CIPHER_CTX *ds;
+ unsigned long l;
+ int bs,i,j,k,pad=0,ret,mac_size=0;
+ const EVP_CIPHER *enc;
+
+ if (send)
+ {
+ if (EVP_MD_CTX_md(s->write_hash))
+ {
+ int n=EVP_MD_CTX_size(s->write_hash);
+ OPENSSL_assert(n >= 0);
+ }
+ ds=s->enc_write_ctx;
+ rec= &(s->s3->wrec);
+ if (s->enc_write_ctx == NULL)
+ enc=NULL;
+ else
+ {
+ int ivlen;
+ enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
+ /* For TLSv1.1 and later explicit IV */
+ if (s->version >= TLS1_1_VERSION
+ && EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE)
+ ivlen = EVP_CIPHER_iv_length(enc);
+ else
+ ivlen = 0;
+ if (ivlen > 1)
+ {
+ if ( rec->data != rec->input)
+ /* we can't write into the input stream:
+ * Can this ever happen?? (steve)
+ */
+ fprintf(stderr,
+ "%s:%d: rec->data != rec->input\n",
+ __FILE__, __LINE__);
+ else if (RAND_bytes(rec->input, ivlen) <= 0)
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ if (EVP_MD_CTX_md(s->read_hash))
+ {
+ int n=EVP_MD_CTX_size(s->read_hash);
+ OPENSSL_assert(n >= 0);
+ }
+ ds=s->enc_read_ctx;
+ rec= &(s->s3->rrec);
+ if (s->enc_read_ctx == NULL)
+ enc=NULL;
+ else
+ enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
+ }
+
+#ifdef KSSL_DEBUG
+ printf("tls1_enc(%d)\n", send);
+#endif /* KSSL_DEBUG */
+
+ if ((s->session == NULL) || (ds == NULL) || (enc == NULL))
+ {
+ memmove(rec->data,rec->input,rec->length);
+ rec->input=rec->data;
+ ret = 1;
+ }
+ else
+ {
+ l=rec->length;
+ bs=EVP_CIPHER_block_size(ds->cipher);
+
+ if (EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_AEAD_CIPHER)
+ {
+ unsigned char buf[13],*seq;
+
+ seq = send?s->s3->write_sequence:s->s3->read_sequence;
+
+ if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+ {
+ unsigned char dtlsseq[9],*p=dtlsseq;
+
+ s2n(send?s->d1->w_epoch:s->d1->r_epoch,p);
+ memcpy(p,&seq[2],6);
+ memcpy(buf,dtlsseq,8);
+ }
+ else
+ {
+ memcpy(buf,seq,8);
+ for (i=7; i>=0; i--) /* increment */
+ {
+ ++seq[i];
+ if (seq[i] != 0) break;
+ }
+ }
+
+ buf[8]=rec->type;
+ buf[9]=(unsigned char)(s->version>>8);
+ buf[10]=(unsigned char)(s->version);
+ buf[11]=rec->length>>8;
+ buf[12]=rec->length&0xff;
+ pad=EVP_CIPHER_CTX_ctrl(ds,EVP_CTRL_AEAD_TLS1_AAD,13,buf);
+ if (send)
+ {
+ l+=pad;
+ rec->length+=pad;
+ }
+ }
+ else if ((bs != 1) && send)
+ {
+ i=bs-((int)l%bs);
+
+ /* Add weird padding of upto 256 bytes */
+
+ /* we need to add 'i' padding bytes of value j */
+ j=i-1;
+ if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
+ {
+ if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
+ j++;
+ }
+ for (k=(int)l; k<(int)(l+i); k++)
+ rec->input[k]=j;
+ l+=i;
+ rec->length+=i;
+ }
+
+#ifdef KSSL_DEBUG
+ {
+ unsigned long ui;
+ printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
+ ds,rec->data,rec->input,l);
+ printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
+ ds->buf_len, ds->cipher->key_len,
+ DES_KEY_SZ, DES_SCHEDULE_SZ,
+ ds->cipher->iv_len);
+ printf("\t\tIV: ");
+ for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
+ printf("\n");
+ printf("\trec->input=");
+ for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]);
+ printf("\n");
+ }
+#endif /* KSSL_DEBUG */
+
+ if (!send)
+ {
+ if (l == 0 || l%bs != 0)
+ return 0;
+ }
+
+ i = EVP_Cipher(ds,rec->data,rec->input,l);
+ if ((EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_CUSTOM_CIPHER)
+ ?(i<0)
+ :(i==0))
+ return -1; /* AEAD can fail to verify MAC */
+ if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE && !send)
+ {
+ rec->data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ rec->input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ rec->length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ }
+
+#ifdef KSSL_DEBUG
+ {
+ unsigned long i;
+ printf("\trec->data=");
+ for (i=0; i<l; i++)
+ printf(" %02x", rec->data[i]); printf("\n");
+ }
+#endif /* KSSL_DEBUG */
+
+ ret = 1;
+ if (EVP_MD_CTX_md(s->read_hash) != NULL)
+ mac_size = EVP_MD_CTX_size(s->read_hash);
+ if ((bs != 1) && !send)
+ ret = tls1_cbc_remove_padding(s, rec, bs, mac_size);
+ if (pad && !send)
+ rec->length -= pad;
+ }
+ return ret;
+ }
+
+int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out)
+ {
+ unsigned int ret;
+ EVP_MD_CTX ctx, *d=NULL;
+ int i;
+
+ if (s->s3->handshake_buffer)
+ if (!ssl3_digest_cached_records(s))
+ return 0;
+
+ for (i=0;i<SSL_MAX_DIGEST;i++)
+ {
+ if (s->s3->handshake_dgst[i]&&EVP_MD_CTX_type(s->s3->handshake_dgst[i])==md_nid)
+ {
+ d=s->s3->handshake_dgst[i];
+ break;
+ }
+ }
+ if (!d) {
+ SSLerr(SSL_F_TLS1_CERT_VERIFY_MAC,SSL_R_NO_REQUIRED_DIGEST);
+ return 0;
+ }
+
+ EVP_MD_CTX_init(&ctx);
+ EVP_MD_CTX_copy_ex(&ctx,d);
+ EVP_DigestFinal_ex(&ctx,out,&ret);
+ EVP_MD_CTX_cleanup(&ctx);
+ return((int)ret);
+ }
+
+int tls1_final_finish_mac(SSL *s,
+ const char *str, int slen, unsigned char *out)
+ {
+ unsigned int i;
+ EVP_MD_CTX ctx;
+ unsigned char buf[2*EVP_MAX_MD_SIZE];
+ unsigned char *q,buf2[12];
+ int idx;
+ long mask;
+ int err=0;
+ const EVP_MD *md;
+
+ q=buf;
+
+ if (s->s3->handshake_buffer)
+ if (!ssl3_digest_cached_records(s))
+ return 0;
+
+ EVP_MD_CTX_init(&ctx);
+
+ for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++)
+ {
+ if (mask & ssl_get_algorithm2(s))
+ {
+ int hashsize = EVP_MD_size(md);
+ EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx];
+ if (!hdgst || hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf)))
+ {
+ /* internal error: 'buf' is too small for this cipersuite! */
+ err = 1;
+ }
+ else
+ {
+ if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) ||
+ !EVP_DigestFinal_ex(&ctx,q,&i) ||
+ (i != (unsigned int)hashsize))
+ err = 1;
+ q+=hashsize;
+ }
+ }
+ }
+
+ if (!tls1_PRF(ssl_get_algorithm2(s),
+ str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0,
+ s->session->master_key,s->session->master_key_length,
+ out,buf2,sizeof buf2))
+ err = 1;
+ EVP_MD_CTX_cleanup(&ctx);
+
+ if (err)
+ return 0;
+ else
+ return sizeof buf2;
+ }
+
+int tls1_mac(SSL *ssl, unsigned char *md, int send)
+ {
+ SSL3_RECORD *rec;
+ unsigned char *seq;
+ EVP_MD_CTX *hash;
+ size_t md_size, orig_len;
+ int i;
+ EVP_MD_CTX hmac, *mac_ctx;
+ unsigned char header[13];
+ int stream_mac = (send?(ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM):(ssl->mac_flags&SSL_MAC_FLAG_READ_MAC_STREAM));
+ int t;
+
+ if (send)
+ {
+ rec= &(ssl->s3->wrec);
+ seq= &(ssl->s3->write_sequence[0]);
+ hash=ssl->write_hash;
+ }
+ else
+ {
+ rec= &(ssl->s3->rrec);
+ seq= &(ssl->s3->read_sequence[0]);
+ hash=ssl->read_hash;
+ }
+
+ t=EVP_MD_CTX_size(hash);
+ OPENSSL_assert(t >= 0);
+ md_size=t;
+
+ /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
+ if (stream_mac)
+ {
+ mac_ctx = hash;
+ }
+ else
+ {
+ if (!EVP_MD_CTX_copy(&hmac,hash))
+ return -1;
+ mac_ctx = &hmac;
+ }
+
+ if (ssl->version == DTLS1_VERSION || ssl->version == DTLS1_BAD_VER)
+ {
+ unsigned char dtlsseq[8],*p=dtlsseq;
+
+ s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p);
+ memcpy (p,&seq[2],6);
+
+ memcpy(header, dtlsseq, 8);
+ }
+ else
+ memcpy(header, seq, 8);
+
+ /* kludge: tls1_cbc_remove_padding passes padding length in rec->type */
+ orig_len = rec->length+md_size+((unsigned int)rec->type>>8);
+ rec->type &= 0xff;
+
+ header[8]=rec->type;
+ header[9]=(unsigned char)(ssl->version>>8);
+ header[10]=(unsigned char)(ssl->version);
+ header[11]=(rec->length)>>8;
+ header[12]=(rec->length)&0xff;
+
+ if (!send &&
+ EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+ ssl3_cbc_record_digest_supported(mac_ctx))
+ {
+ /* This is a CBC-encrypted record. We must avoid leaking any
+ * timing-side channel information about how many blocks of
+ * data we are hashing because that gives an attacker a
+ * timing-oracle. */
+ ssl3_cbc_digest_record(
+ mac_ctx,
+ md, &md_size,
+ header, rec->input,
+ rec->length + md_size, orig_len,
+ ssl->s3->read_mac_secret,
+ ssl->s3->read_mac_secret_size,
+ 0 /* not SSLv3 */);
+ }
+ else
+ {
+ EVP_DigestSignUpdate(mac_ctx,header,sizeof(header));
+ EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length);
+ t=EVP_DigestSignFinal(mac_ctx,md,&md_size);
+ OPENSSL_assert(t > 0);
+#ifdef OPENSSL_FIPS
+ if (!send && FIPS_mode())
+ tls_fips_digest_extra(
+ ssl->enc_read_ctx,
+ mac_ctx, rec->input,
+ rec->length, orig_len);
+#endif
+ }
+
+ if (!stream_mac)
+ EVP_MD_CTX_cleanup(&hmac);
+#ifdef TLS_DEBUG
+printf("seq=");
+{int z; for (z=0; z<8; z++) printf("%02X ",seq[z]); printf("\n"); }
+printf("rec=");
+{unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",rec->data[z]); printf("\n"); }
+#endif
+
+ if (ssl->version != DTLS1_VERSION && ssl->version != DTLS1_BAD_VER)
+ {
+ for (i=7; i>=0; i--)
+ {
+ ++seq[i];
+ if (seq[i] != 0) break;
+ }
+ }
+
+#ifdef TLS_DEBUG
+{unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",md[z]); printf("\n"); }
+#endif
+ return(md_size);
+ }
+
+int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
+ int len)
+ {
+ unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
+ const void *co = NULL, *so = NULL;
+ int col = 0, sol = 0;
+
+
+#ifdef KSSL_DEBUG
+ printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
+#endif /* KSSL_DEBUG */
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->client_opaque_prf_input != NULL && s->s3->server_opaque_prf_input != NULL &&
+ s->s3->client_opaque_prf_input_len > 0 &&
+ s->s3->client_opaque_prf_input_len == s->s3->server_opaque_prf_input_len)
+ {
+ co = s->s3->client_opaque_prf_input;
+ col = s->s3->server_opaque_prf_input_len;
+ so = s->s3->server_opaque_prf_input;
+ sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */
+ }
+#endif
+
+ tls1_PRF(ssl_get_algorithm2(s),
+ TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
+ s->s3->client_random,SSL3_RANDOM_SIZE,
+ co, col,
+ s->s3->server_random,SSL3_RANDOM_SIZE,
+ so, sol,
+ p,len,
+ s->session->master_key,buff,sizeof buff);
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Premaster Secret:\n");
+ BIO_dump_fp(stderr, (char *)p, len);
+ fprintf(stderr, "Client Random:\n");
+ BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE);
+ fprintf(stderr, "Server Random:\n");
+ BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE);
+ fprintf(stderr, "Master Secret:\n");
+ BIO_dump_fp(stderr, (char *)s->session->master_key, SSL3_MASTER_SECRET_SIZE);
+#endif
+
+#ifdef KSSL_DEBUG
+ printf ("tls1_generate_master_secret() complete\n");
+#endif /* KSSL_DEBUG */
+ return(SSL3_MASTER_SECRET_SIZE);
+ }
+
+int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+ const char *label, size_t llen, const unsigned char *context,
+ size_t contextlen, int use_context)
+ {
+ unsigned char *buff;
+ unsigned char *val = NULL;
+ size_t vallen, currentvalpos;
+ int rv;
+
+#ifdef KSSL_DEBUG
+ printf ("tls1_export_keying_material(%p,%p,%d,%s,%d,%p,%d)\n", s, out, olen, label, llen, p, plen);
+#endif /* KSSL_DEBUG */
+
+ buff = OPENSSL_malloc(olen);
+ if (buff == NULL) goto err2;
+
+ /* construct PRF arguments
+ * we construct the PRF argument ourself rather than passing separate
+ * values into the TLS PRF to ensure that the concatenation of values
+ * does not create a prohibited label.
+ */
+ vallen = llen + SSL3_RANDOM_SIZE * 2;
+ if (use_context)
+ {
+ vallen += 2 + contextlen;
+ }
+
+ val = OPENSSL_malloc(vallen);
+ if (val == NULL) goto err2;
+ currentvalpos = 0;
+ memcpy(val + currentvalpos, (unsigned char *) label, llen);
+ currentvalpos += llen;
+ memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE);
+ currentvalpos += SSL3_RANDOM_SIZE;
+ memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE);
+ currentvalpos += SSL3_RANDOM_SIZE;
+
+ if (use_context)
+ {
+ val[currentvalpos] = (contextlen >> 8) & 0xff;
+ currentvalpos++;
+ val[currentvalpos] = contextlen & 0xff;
+ currentvalpos++;
+ if ((contextlen > 0) || (context != NULL))
+ {
+ memcpy(val + currentvalpos, context, contextlen);
+ }
+ }
+
+ /* disallow prohibited labels
+ * note that SSL3_RANDOM_SIZE > max(prohibited label len) =
+ * 15, so size of val > max(prohibited label len) = 15 and the
+ * comparisons won't have buffer overflow
+ */
+ if (memcmp(val, TLS_MD_CLIENT_FINISH_CONST,
+ TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0) goto err1;
+ if (memcmp(val, TLS_MD_SERVER_FINISH_CONST,
+ TLS_MD_SERVER_FINISH_CONST_SIZE) == 0) goto err1;
+ if (memcmp(val, TLS_MD_MASTER_SECRET_CONST,
+ TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) goto err1;
+ if (memcmp(val, TLS_MD_KEY_EXPANSION_CONST,
+ TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0) goto err1;
+
+ rv = tls1_PRF(ssl_get_algorithm2(s),
+ val, vallen,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ s->session->master_key,s->session->master_key_length,
+ out,buff,olen);
+
+#ifdef KSSL_DEBUG
+ printf ("tls1_export_keying_material() complete\n");
+#endif /* KSSL_DEBUG */
+ goto ret;
+err1:
+ SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL);
+ rv = 0;
+ goto ret;
+err2:
+ SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, ERR_R_MALLOC_FAILURE);
+ rv = 0;
+ret:
+ if (buff != NULL) OPENSSL_free(buff);
+ if (val != NULL) OPENSSL_free(val);
+ return(rv);
+ }
+
+int tls1_alert_code(int code)
+ {
+ switch (code)
+ {
+ case SSL_AD_CLOSE_NOTIFY: return(SSL3_AD_CLOSE_NOTIFY);
+ case SSL_AD_UNEXPECTED_MESSAGE: return(SSL3_AD_UNEXPECTED_MESSAGE);
+ case SSL_AD_BAD_RECORD_MAC: return(SSL3_AD_BAD_RECORD_MAC);
+ case SSL_AD_DECRYPTION_FAILED: return(TLS1_AD_DECRYPTION_FAILED);
+ case SSL_AD_RECORD_OVERFLOW: return(TLS1_AD_RECORD_OVERFLOW);
+ case SSL_AD_DECOMPRESSION_FAILURE:return(SSL3_AD_DECOMPRESSION_FAILURE);
+ case SSL_AD_HANDSHAKE_FAILURE: return(SSL3_AD_HANDSHAKE_FAILURE);
+ case SSL_AD_NO_CERTIFICATE: return(-1);
+ case SSL_AD_BAD_CERTIFICATE: return(SSL3_AD_BAD_CERTIFICATE);
+ case SSL_AD_UNSUPPORTED_CERTIFICATE:return(SSL3_AD_UNSUPPORTED_CERTIFICATE);
+ case SSL_AD_CERTIFICATE_REVOKED:return(SSL3_AD_CERTIFICATE_REVOKED);
+ case SSL_AD_CERTIFICATE_EXPIRED:return(SSL3_AD_CERTIFICATE_EXPIRED);
+ case SSL_AD_CERTIFICATE_UNKNOWN:return(SSL3_AD_CERTIFICATE_UNKNOWN);
+ case SSL_AD_ILLEGAL_PARAMETER: return(SSL3_AD_ILLEGAL_PARAMETER);
+ case SSL_AD_UNKNOWN_CA: return(TLS1_AD_UNKNOWN_CA);
+ case SSL_AD_ACCESS_DENIED: return(TLS1_AD_ACCESS_DENIED);
+ case SSL_AD_DECODE_ERROR: return(TLS1_AD_DECODE_ERROR);
+ case SSL_AD_DECRYPT_ERROR: return(TLS1_AD_DECRYPT_ERROR);
+ case SSL_AD_EXPORT_RESTRICTION: return(TLS1_AD_EXPORT_RESTRICTION);
+ case SSL_AD_PROTOCOL_VERSION: return(TLS1_AD_PROTOCOL_VERSION);
+ case SSL_AD_INSUFFICIENT_SECURITY:return(TLS1_AD_INSUFFICIENT_SECURITY);
+ case SSL_AD_INTERNAL_ERROR: return(TLS1_AD_INTERNAL_ERROR);
+ case SSL_AD_USER_CANCELLED: return(TLS1_AD_USER_CANCELLED);
+ case SSL_AD_NO_RENEGOTIATION: return(TLS1_AD_NO_RENEGOTIATION);
+ case SSL_AD_UNSUPPORTED_EXTENSION: return(TLS1_AD_UNSUPPORTED_EXTENSION);
+ case SSL_AD_CERTIFICATE_UNOBTAINABLE: return(TLS1_AD_CERTIFICATE_UNOBTAINABLE);
+ case SSL_AD_UNRECOGNIZED_NAME: return(TLS1_AD_UNRECOGNIZED_NAME);
+ case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE);
+ case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE);
+ case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY);
+#if 0 /* not appropriate for TLS, not used for DTLS */
+ case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return
+ (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+#endif
+ default: return(-1);
+ }
+ }
diff --git a/drivers/builtin_openssl2/ssl/t1_lib.c b/drivers/builtin_openssl2/ssl/t1_lib.c
new file mode 100644
index 0000000000..3b8d5153eb
--- /dev/null
+++ b/drivers/builtin_openssl2/ssl/t1_lib.c
@@ -0,0 +1,2732 @@
+/* ssl/t1_lib.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL 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:
+ *
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/ocsp.h>
+#include <openssl/rand.h>
+#include "ssl_locl.h"
+
+const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
+
+#ifndef OPENSSL_NO_TLSEXT
+static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
+ const unsigned char *sess_id, int sesslen,
+ SSL_SESSION **psess);
+#endif
+
+SSL3_ENC_METHOD TLSv1_enc_data={
+ tls1_enc,
+ tls1_mac,
+ tls1_setup_key_block,
+ tls1_generate_master_secret,
+ tls1_change_cipher_state,
+ tls1_final_finish_mac,
+ TLS1_FINISH_MAC_LENGTH,
+ tls1_cert_verify_mac,
+ TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+ TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+ tls1_alert_code,
+ tls1_export_keying_material,
+ };
+
+long tls1_default_timeout(void)
+ {
+ /* 2 hours, the 24 hours mentioned in the TLSv1 spec
+ * is way too long for http, the cache would over fill */
+ return(60*60*2);
+ }
+
+int tls1_new(SSL *s)
+ {
+ if (!ssl3_new(s)) return(0);
+ s->method->ssl_clear(s);
+ return(1);
+ }
+
+void tls1_free(SSL *s)
+ {
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+ ssl3_free(s);
+ }
+
+void tls1_clear(SSL *s)
+ {
+ ssl3_clear(s);
+ s->version = s->method->version;
+ }
+
+#ifndef OPENSSL_NO_EC
+
+static int nid_list[] =
+ {
+ NID_sect163k1, /* sect163k1 (1) */
+ NID_sect163r1, /* sect163r1 (2) */
+ NID_sect163r2, /* sect163r2 (3) */
+ NID_sect193r1, /* sect193r1 (4) */
+ NID_sect193r2, /* sect193r2 (5) */
+ NID_sect233k1, /* sect233k1 (6) */
+ NID_sect233r1, /* sect233r1 (7) */
+ NID_sect239k1, /* sect239k1 (8) */
+ NID_sect283k1, /* sect283k1 (9) */
+ NID_sect283r1, /* sect283r1 (10) */
+ NID_sect409k1, /* sect409k1 (11) */
+ NID_sect409r1, /* sect409r1 (12) */
+ NID_sect571k1, /* sect571k1 (13) */
+ NID_sect571r1, /* sect571r1 (14) */
+ NID_secp160k1, /* secp160k1 (15) */
+ NID_secp160r1, /* secp160r1 (16) */
+ NID_secp160r2, /* secp160r2 (17) */
+ NID_secp192k1, /* secp192k1 (18) */
+ NID_X9_62_prime192v1, /* secp192r1 (19) */
+ NID_secp224k1, /* secp224k1 (20) */
+ NID_secp224r1, /* secp224r1 (21) */
+ NID_secp256k1, /* secp256k1 (22) */
+ NID_X9_62_prime256v1, /* secp256r1 (23) */
+ NID_secp384r1, /* secp384r1 (24) */
+ NID_secp521r1 /* secp521r1 (25) */
+ };
+
+static int pref_list[] =
+ {
+ NID_sect571r1, /* sect571r1 (14) */
+ NID_sect571k1, /* sect571k1 (13) */
+ NID_secp521r1, /* secp521r1 (25) */
+ NID_sect409k1, /* sect409k1 (11) */
+ NID_sect409r1, /* sect409r1 (12) */
+ NID_secp384r1, /* secp384r1 (24) */
+ NID_sect283k1, /* sect283k1 (9) */
+ NID_sect283r1, /* sect283r1 (10) */
+ NID_secp256k1, /* secp256k1 (22) */
+ NID_X9_62_prime256v1, /* secp256r1 (23) */
+ NID_sect239k1, /* sect239k1 (8) */
+ NID_sect233k1, /* sect233k1 (6) */
+ NID_sect233r1, /* sect233r1 (7) */
+ NID_secp224k1, /* secp224k1 (20) */
+ NID_secp224r1, /* secp224r1 (21) */
+ NID_sect193r1, /* sect193r1 (4) */
+ NID_sect193r2, /* sect193r2 (5) */
+ NID_secp192k1, /* secp192k1 (18) */
+ NID_X9_62_prime192v1, /* secp192r1 (19) */
+ NID_sect163k1, /* sect163k1 (1) */
+ NID_sect163r1, /* sect163r1 (2) */
+ NID_sect163r2, /* sect163r2 (3) */
+ NID_secp160k1, /* secp160k1 (15) */
+ NID_secp160r1, /* secp160r1 (16) */
+ NID_secp160r2, /* secp160r2 (17) */
+ };
+
+int tls1_ec_curve_id2nid(int curve_id)
+ {
+ /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+ if ((curve_id < 1) || ((unsigned int)curve_id >
+ sizeof(nid_list)/sizeof(nid_list[0])))
+ return 0;
+ return nid_list[curve_id-1];
+ }
+
+int tls1_ec_nid2curve_id(int nid)
+ {
+ /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+ switch (nid)
+ {
+ case NID_sect163k1: /* sect163k1 (1) */
+ return 1;
+ case NID_sect163r1: /* sect163r1 (2) */
+ return 2;
+ case NID_sect163r2: /* sect163r2 (3) */
+ return 3;
+ case NID_sect193r1: /* sect193r1 (4) */
+ return 4;
+ case NID_sect193r2: /* sect193r2 (5) */
+ return 5;
+ case NID_sect233k1: /* sect233k1 (6) */
+ return 6;
+ case NID_sect233r1: /* sect233r1 (7) */
+ return 7;
+ case NID_sect239k1: /* sect239k1 (8) */
+ return 8;
+ case NID_sect283k1: /* sect283k1 (9) */
+ return 9;
+ case NID_sect283r1: /* sect283r1 (10) */
+ return 10;
+ case NID_sect409k1: /* sect409k1 (11) */
+ return 11;
+ case NID_sect409r1: /* sect409r1 (12) */
+ return 12;
+ case NID_sect571k1: /* sect571k1 (13) */
+ return 13;
+ case NID_sect571r1: /* sect571r1 (14) */
+ return 14;
+ case NID_secp160k1: /* secp160k1 (15) */
+ return 15;
+ case NID_secp160r1: /* secp160r1 (16) */
+ return 16;
+ case NID_secp160r2: /* secp160r2 (17) */
+ return 17;
+ case NID_secp192k1: /* secp192k1 (18) */
+ return 18;
+ case NID_X9_62_prime192v1: /* secp192r1 (19) */
+ return 19;
+ case NID_secp224k1: /* secp224k1 (20) */
+ return 20;
+ case NID_secp224r1: /* secp224r1 (21) */
+ return 21;
+ case NID_secp256k1: /* secp256k1 (22) */
+ return 22;
+ case NID_X9_62_prime256v1: /* secp256r1 (23) */
+ return 23;
+ case NID_secp384r1: /* secp384r1 (24) */
+ return 24;
+ case NID_secp521r1: /* secp521r1 (25) */
+ return 25;
+ default:
+ return 0;
+ }
+ }
+#endif /* OPENSSL_NO_EC */
+
+#ifndef OPENSSL_NO_TLSEXT
+
+/* List of supported signature algorithms and hashes. Should make this
+ * customisable at some point, for now include everything we support.
+ */
+
+#ifdef OPENSSL_NO_RSA
+#define tlsext_sigalg_rsa(md) /* */
+#else
+#define tlsext_sigalg_rsa(md) md, TLSEXT_signature_rsa,
+#endif
+
+#ifdef OPENSSL_NO_DSA
+#define tlsext_sigalg_dsa(md) /* */
+#else
+#define tlsext_sigalg_dsa(md) md, TLSEXT_signature_dsa,
+#endif
+
+#ifdef OPENSSL_NO_ECDSA
+#define tlsext_sigalg_ecdsa(md) /* */
+#else
+#define tlsext_sigalg_ecdsa(md) md, TLSEXT_signature_ecdsa,
+#endif
+
+#define tlsext_sigalg(md) \
+ tlsext_sigalg_rsa(md) \
+ tlsext_sigalg_dsa(md) \
+ tlsext_sigalg_ecdsa(md)
+
+static unsigned char tls12_sigalgs[] = {
+#ifndef OPENSSL_NO_SHA512
+ tlsext_sigalg(TLSEXT_hash_sha512)
+ tlsext_sigalg(TLSEXT_hash_sha384)
+#endif
+#ifndef OPENSSL_NO_SHA256
+ tlsext_sigalg(TLSEXT_hash_sha256)
+ tlsext_sigalg(TLSEXT_hash_sha224)
+#endif
+#ifndef OPENSSL_NO_SHA
+ tlsext_sigalg(TLSEXT_hash_sha1)
+#endif
+};
+
+int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
+ {
+ size_t slen = sizeof(tls12_sigalgs);
+ if (p)
+ memcpy(p, tls12_sigalgs, slen);
+ return (int)slen;
+ }
+
+unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+ {
+ int extdatalen=0;
+ unsigned char *ret = p;
+
+ /* don't add extensions for SSLv3 unless doing secure renegotiation */
+ if (s->client_version == SSL3_VERSION
+ && !s->s3->send_connection_binding)
+ return p;
+
+ ret+=2;
+
+ if (ret>=limit) return NULL; /* this really never occurs, but ... */
+
+ if (s->tlsext_hostname != NULL)
+ {
+ /* Add TLS extension servername to the Client Hello message */
+ unsigned long size_str;
+ long lenmax;
+
+ /* check for enough space.
+ 4 for the servername type and entension length
+ 2 for servernamelist length
+ 1 for the hostname type
+ 2 for hostname length
+ + hostname length
+ */
+
+ if ((lenmax = limit - ret - 9) < 0
+ || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
+ return NULL;
+
+ /* extension type and length */
+ s2n(TLSEXT_TYPE_server_name,ret);
+ s2n(size_str+5,ret);
+
+ /* length of servername list */
+ s2n(size_str+3,ret);
+
+ /* hostname type, length and hostname */
+ *(ret++) = (unsigned char) TLSEXT_NAMETYPE_host_name;
+ s2n(size_str,ret);
+ memcpy(ret, s->tlsext_hostname, size_str);
+ ret+=size_str;
+ }
+
+ /* Add RI if renegotiating */
+ if (s->renegotiate)
+ {
+ int el;
+
+ if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ if((limit - p - 4 - el) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_renegotiate,ret);
+ s2n(el,ret);
+
+ if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el))
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ ret += el;
+ }
+
+#ifndef OPENSSL_NO_SRP
+ /* Add SRP username if there is one */
+ if (s->srp_ctx.login != NULL)
+ { /* Add TLS extension SRP username to the Client Hello message */
+
+ int login_len = strlen(s->srp_ctx.login);
+ if (login_len > 255 || login_len == 0)
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ /* check for enough space.
+ 4 for the srp type type and entension length
+ 1 for the srp user identity
+ + srp user identity length
+ */
+ if ((limit - ret - 5 - login_len) < 0) return NULL;
+
+ /* fill in the extension */
+ s2n(TLSEXT_TYPE_srp,ret);
+ s2n(login_len+1,ret);
+ (*ret++) = (unsigned char) login_len;
+ memcpy(ret, s->srp_ctx.login, login_len);
+ ret+=login_len;
+ }
+#endif
+
+#ifndef OPENSSL_NO_EC
+ if (s->tlsext_ecpointformatlist != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ /* Add TLS extension ECPointFormats to the ClientHello message */
+ long lenmax;
+
+ if ((lenmax = limit - ret - 5) < 0) return NULL;
+ if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
+ if (s->tlsext_ecpointformatlist_length > 255)
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ s2n(TLSEXT_TYPE_ec_point_formats,ret);
+ s2n(s->tlsext_ecpointformatlist_length + 1,ret);
+ *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
+ memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+ ret+=s->tlsext_ecpointformatlist_length;
+ }
+ if (s->tlsext_ellipticcurvelist != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ /* Add TLS extension EllipticCurves to the ClientHello message */
+ long lenmax;
+
+ if ((lenmax = limit - ret - 6) < 0) return NULL;
+ if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
+ if (s->tlsext_ellipticcurvelist_length > 65532)
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ s2n(TLSEXT_TYPE_elliptic_curves,ret);
+ s2n(s->tlsext_ellipticcurvelist_length + 2, ret);
+
+ /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
+ * elliptic_curve_list, but the examples use two bytes.
+ * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
+ * resolves this to two bytes.
+ */
+ s2n(s->tlsext_ellipticcurvelist_length, ret);
+ memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
+ ret+=s->tlsext_ellipticcurvelist_length;
+ }
+#endif /* OPENSSL_NO_EC */
+
+ if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
+ {
+ int ticklen;
+ if (!s->new_session && s->session && s->session->tlsext_tick)
+ ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data)
+ {
+ ticklen = s->tlsext_session_ticket->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick,
+ s->tlsext_session_ticket->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ }
+ else
+ ticklen = 0;
+ if (ticklen == 0 && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data == NULL)
+ goto skip_ext;
+ /* Check for enough room 2 for extension type, 2 for len
+ * rest for ticket
+ */
+ if ((long)(limit - ret - 4 - ticklen) < 0) return NULL;
+ s2n(TLSEXT_TYPE_session_ticket,ret);
+ s2n(ticklen,ret);
+ if (ticklen)
+ {
+ memcpy(ret, s->session->tlsext_tick, ticklen);
+ ret += ticklen;
+ }
+ }
+ skip_ext:
+
+ if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
+ {
+ if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6)
+ return NULL;
+ s2n(TLSEXT_TYPE_signature_algorithms,ret);
+ s2n(sizeof(tls12_sigalgs) + 2, ret);
+ s2n(sizeof(tls12_sigalgs), ret);
+ memcpy(ret, tls12_sigalgs, sizeof(tls12_sigalgs));
+ ret += sizeof(tls12_sigalgs);
+ }
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->client_opaque_prf_input != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ size_t col = s->s3->client_opaque_prf_input_len;
+
+ if ((long)(limit - ret - 6 - col < 0))
+ return NULL;
+ if (col > 0xFFFD) /* can't happen */
+ return NULL;
+
+ s2n(TLSEXT_TYPE_opaque_prf_input, ret);
+ s2n(col + 2, ret);
+ s2n(col, ret);
+ memcpy(ret, s->s3->client_opaque_prf_input, col);
+ ret += col;
+ }
+#endif
+
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+ s->version != DTLS1_VERSION)
+ {
+ int i;
+ long extlen, idlen, itmp;
+ OCSP_RESPID *id;
+
+ idlen = 0;
+ for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+ {
+ id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+ itmp = i2d_OCSP_RESPID(id, NULL);
+ if (itmp <= 0)
+ return NULL;
+ idlen += itmp + 2;
+ }
+
+ if (s->tlsext_ocsp_exts)
+ {
+ extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
+ if (extlen < 0)
+ return NULL;
+ }
+ else
+ extlen = 0;
+
+ if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL;
+ s2n(TLSEXT_TYPE_status_request, ret);
+ if (extlen + idlen > 0xFFF0)
+ return NULL;
+ s2n(extlen + idlen + 5, ret);
+ *(ret++) = TLSEXT_STATUSTYPE_ocsp;
+ s2n(idlen, ret);
+ for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+ {
+ /* save position of id len */
+ unsigned char *q = ret;
+ id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+ /* skip over id len */
+ ret += 2;
+ itmp = i2d_OCSP_RESPID(id, &ret);
+ /* write id len */
+ s2n(itmp, q);
+ }
+ s2n(extlen, ret);
+ if (extlen > 0)
+ i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
+ }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* Add Heartbeat extension */
+ if ((limit - ret - 4 - 1) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_heartbeat,ret);
+ s2n(1,ret);
+ /* Set mode:
+ * 1: peer may send requests
+ * 2: peer not allowed to send requests
+ */
+ if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
+ *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+ else
+ *(ret++) = SSL_TLSEXT_HB_ENABLED;
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
+ {
+ /* The client advertises an emtpy extension to indicate its
+ * support for Next Protocol Negotiation */
+ if (limit - ret - 4 < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_next_proto_neg,ret);
+ s2n(0,ret);
+ }
+#endif
+
+#ifndef OPENSSL_NO_SRTP
+ if(SSL_get_srtp_profiles(s))
+ {
+ int el;
+
+ ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
+
+ if((limit - p - 4 - el) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_use_srtp,ret);
+ s2n(el,ret);
+
+ if(ssl_add_clienthello_use_srtp_ext(s, ret, &el, el))
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+ ret += el;
+ }
+#endif
+ /* Add padding to workaround bugs in F5 terminators.
+ * See https://tools.ietf.org/html/draft-agl-tls-padding-03
+ *
+ * NB: because this code works out the length of all existing
+ * extensions it MUST always appear last.
+ */
+ if (s->options & SSL_OP_TLSEXT_PADDING)
+ {
+ int hlen = ret - (unsigned char *)s->init_buf->data;
+ /* The code in s23_clnt.c to build ClientHello messages
+ * includes the 5-byte record header in the buffer, while
+ * the code in s3_clnt.c does not.
+ */
+ if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
+ hlen -= 5;
+ if (hlen > 0xff && hlen < 0x200)
+ {
+ hlen = 0x200 - hlen;
+ if (hlen >= 4)
+ hlen -= 4;
+ else
+ hlen = 0;
+
+ s2n(TLSEXT_TYPE_padding, ret);
+ s2n(hlen, ret);
+ memset(ret, 0, hlen);
+ ret += hlen;
+ }
+ }
+
+ if ((extdatalen = ret-p-2)== 0)
+ return p;
+
+ s2n(extdatalen,p);
+ return ret;
+ }
+
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+ {
+ int extdatalen=0;
+ unsigned char *ret = p;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ int next_proto_neg_seen;
+#endif
+
+ /* don't add extensions for SSLv3, unless doing secure renegotiation */
+ if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
+ return p;
+
+ ret+=2;
+ if (ret>=limit) return NULL; /* this really never occurs, but ... */
+
+ if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
+ {
+ if ((long)(limit - ret - 4) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_server_name,ret);
+ s2n(0,ret);
+ }
+
+ if(s->s3->send_connection_binding)
+ {
+ int el;
+
+ if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0))
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ if((limit - p - 4 - el) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_renegotiate,ret);
+ s2n(el,ret);
+
+ if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el))
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ ret += el;
+ }
+
+#ifndef OPENSSL_NO_EC
+ if (s->tlsext_ecpointformatlist != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ /* Add TLS extension ECPointFormats to the ServerHello message */
+ long lenmax;
+
+ if ((lenmax = limit - ret - 5) < 0) return NULL;
+ if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
+ if (s->tlsext_ecpointformatlist_length > 255)
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ s2n(TLSEXT_TYPE_ec_point_formats,ret);
+ s2n(s->tlsext_ecpointformatlist_length + 1,ret);
+ *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
+ memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+ ret+=s->tlsext_ecpointformatlist_length;
+
+ }
+ /* Currently the server should not respond with a SupportedCurves extension */
+#endif /* OPENSSL_NO_EC */
+
+ if (s->tlsext_ticket_expected
+ && !(SSL_get_options(s) & SSL_OP_NO_TICKET))
+ {
+ if ((long)(limit - ret - 4) < 0) return NULL;
+ s2n(TLSEXT_TYPE_session_ticket,ret);
+ s2n(0,ret);
+ }
+
+ if (s->tlsext_status_expected)
+ {
+ if ((long)(limit - ret - 4) < 0) return NULL;
+ s2n(TLSEXT_TYPE_status_request,ret);
+ s2n(0,ret);
+ }
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->server_opaque_prf_input != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ size_t sol = s->s3->server_opaque_prf_input_len;
+
+ if ((long)(limit - ret - 6 - sol) < 0)
+ return NULL;
+ if (sol > 0xFFFD) /* can't happen */
+ return NULL;
+
+ s2n(TLSEXT_TYPE_opaque_prf_input, ret);
+ s2n(sol + 2, ret);
+ s2n(sol, ret);
+ memcpy(ret, s->s3->server_opaque_prf_input, sol);
+ ret += sol;
+ }
+#endif
+
+#ifndef OPENSSL_NO_SRTP
+ if(s->srtp_profile)
+ {
+ int el;
+
+ ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
+
+ if((limit - p - 4 - el) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_use_srtp,ret);
+ s2n(el,ret);
+
+ if(ssl_add_serverhello_use_srtp_ext(s, ret, &el, el))
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+ ret+=el;
+ }
+#endif
+
+ if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81)
+ && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG))
+ { const unsigned char cryptopro_ext[36] = {
+ 0xfd, 0xe8, /*65000*/
+ 0x00, 0x20, /*32 bytes length*/
+ 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
+ 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
+ 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
+ 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17};
+ if (limit-ret<36) return NULL;
+ memcpy(ret,cryptopro_ext,36);
+ ret+=36;
+
+ }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* Add Heartbeat extension if we've received one */
+ if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED)
+ {
+ if ((limit - ret - 4 - 1) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_heartbeat,ret);
+ s2n(1,ret);
+ /* Set mode:
+ * 1: peer may send requests
+ * 2: peer not allowed to send requests
+ */
+ if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
+ *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+ else
+ *(ret++) = SSL_TLSEXT_HB_ENABLED;
+
+ }
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ next_proto_neg_seen = s->s3->next_proto_neg_seen;
+ s->s3->next_proto_neg_seen = 0;
+ if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb)
+ {
+ const unsigned char *npa;
+ unsigned int npalen;
+ int r;
+
+ r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg);
+ if (r == SSL_TLSEXT_ERR_OK)
+ {
+ if ((long)(limit - ret - 4 - npalen) < 0) return NULL;
+ s2n(TLSEXT_TYPE_next_proto_neg,ret);
+ s2n(npalen,ret);
+ memcpy(ret, npa, npalen);
+ ret += npalen;
+ s->s3->next_proto_neg_seen = 1;
+ }
+ }
+#endif
+
+ if ((extdatalen = ret-p-2)== 0)
+ return p;
+
+ s2n(extdatalen,p);
+ return ret;
+ }
+
+#ifndef OPENSSL_NO_EC
+/* ssl_check_for_safari attempts to fingerprint Safari using OS X
+ * SecureTransport using the TLS extension block in |d|, of length |n|.
+ * Safari, since 10.6, sends exactly these extensions, in this order:
+ * SNI,
+ * elliptic_curves
+ * ec_point_formats
+ *
+ * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
+ * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
+ * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
+ * 10.8..10.8.3 (which don't work).
+ */
+static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsigned char *d, int n) {
+ unsigned short type, size;
+ static const unsigned char kSafariExtensionsBlock[] = {
+ 0x00, 0x0a, /* elliptic_curves extension */
+ 0x00, 0x08, /* 8 bytes */
+ 0x00, 0x06, /* 6 bytes of curve ids */
+ 0x00, 0x17, /* P-256 */
+ 0x00, 0x18, /* P-384 */
+ 0x00, 0x19, /* P-521 */
+
+ 0x00, 0x0b, /* ec_point_formats */
+ 0x00, 0x02, /* 2 bytes */
+ 0x01, /* 1 point format */
+ 0x00, /* uncompressed */
+ };
+
+ /* The following is only present in TLS 1.2 */
+ static const unsigned char kSafariTLS12ExtensionsBlock[] = {
+ 0x00, 0x0d, /* signature_algorithms */
+ 0x00, 0x0c, /* 12 bytes */
+ 0x00, 0x0a, /* 10 bytes */
+ 0x05, 0x01, /* SHA-384/RSA */
+ 0x04, 0x01, /* SHA-256/RSA */
+ 0x02, 0x01, /* SHA-1/RSA */
+ 0x04, 0x03, /* SHA-256/ECDSA */
+ 0x02, 0x03, /* SHA-1/ECDSA */
+ };
+
+ if (data >= (d+n-2))
+ return;
+ data += 2;
+
+ if (data > (d+n-4))
+ return;
+ n2s(data,type);
+ n2s(data,size);
+
+ if (type != TLSEXT_TYPE_server_name)
+ return;
+
+ if (data+size > d+n)
+ return;
+ data += size;
+
+ if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
+ {
+ const size_t len1 = sizeof(kSafariExtensionsBlock);
+ const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
+
+ if (data + len1 + len2 != d+n)
+ return;
+ if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
+ return;
+ if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
+ return;
+ }
+ else
+ {
+ const size_t len = sizeof(kSafariExtensionsBlock);
+
+ if (data + len != d+n)
+ return;
+ if (memcmp(data, kSafariExtensionsBlock, len) != 0)
+ return;
+ }
+
+ s->s3->is_probably_safari = 1;
+}
+#endif /* !OPENSSL_NO_EC */
+
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+ {
+ unsigned short type;
+ unsigned short size;
+ unsigned short len;
+ unsigned char *data = *p;
+ int renegotiate_seen = 0;
+ int sigalg_seen = 0;
+
+ s->servername_done = 0;
+ s->tlsext_status_type = -1;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ s->s3->next_proto_neg_seen = 0;
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+ SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+#endif
+
+#ifndef OPENSSL_NO_EC
+ if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+ ssl_check_for_safari(s, data, d, n);
+#endif /* !OPENSSL_NO_EC */
+
+ if (data >= (d+n-2))
+ goto ri_check;
+ n2s(data,len);
+
+ if (data > (d+n-len))
+ goto ri_check;
+
+ while (data <= (d+n-4))
+ {
+ n2s(data,type);
+ n2s(data,size);
+
+ if (data+size > (d+n))
+ goto ri_check;
+#if 0
+ fprintf(stderr,"Received extension type %d size %d\n",type,size);
+#endif
+ if (s->tlsext_debug_cb)
+ s->tlsext_debug_cb(s, 0, type, data, size,
+ s->tlsext_debug_arg);
+/* The servername extension is treated as follows:
+
+ - Only the hostname type is supported with a maximum length of 255.
+ - The servername is rejected if too long or if it contains zeros,
+ in which case an fatal alert is generated.
+ - The servername field is maintained together with the session cache.
+ - When a session is resumed, the servername call back invoked in order
+ to allow the application to position itself to the right context.
+ - The servername is acknowledged if it is new for a session or when
+ it is identical to a previously used for the same session.
+ Applications can control the behaviour. They can at any time
+ set a 'desirable' servername for a new SSL object. This can be the
+ case for example with HTTPS when a Host: header field is received and
+ a renegotiation is requested. In this case, a possible servername
+ presented in the new client hello is only acknowledged if it matches
+ the value of the Host: field.
+ - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ if they provide for changing an explicit servername context for the session,
+ i.e. when the session has been established with a servername extension.
+ - On session reconnect, the servername extension may be absent.
+
+*/
+
+ if (type == TLSEXT_TYPE_server_name)
+ {
+ unsigned char *sdata;
+ int servname_type;
+ int dsize;
+
+ if (size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize > size )
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ sdata = data;
+ while (dsize > 3)
+ {
+ servname_type = *(sdata++);
+ n2s(sdata,len);
+ dsize -= 3;
+
+ if (len > dsize)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (s->servername_done == 0)
+ switch (servname_type)
+ {
+ case TLSEXT_NAMETYPE_host_name:
+ if (!s->hit)
+ {
+ if(s->session->tlsext_hostname)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (len > TLSEXT_MAXLEN_host_name)
+ {
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ memcpy(s->session->tlsext_hostname, sdata, len);
+ s->session->tlsext_hostname[len]='\0';
+ if (strlen(s->session->tlsext_hostname) != len) {
+ OPENSSL_free(s->session->tlsext_hostname);
+ s->session->tlsext_hostname = NULL;
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ s->servername_done = 1;
+
+ }
+ else
+ s->servername_done = s->session->tlsext_hostname
+ && strlen(s->session->tlsext_hostname) == len
+ && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
+
+ break;
+
+ default:
+ break;
+ }
+
+ dsize -= len;
+ }
+ if (dsize != 0)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ }
+#ifndef OPENSSL_NO_SRP
+ else if (type == TLSEXT_TYPE_srp)
+ {
+ if (size <= 0 || ((len = data[0])) != (size -1))
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (s->srp_ctx.login != NULL)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if ((s->srp_ctx.login = OPENSSL_malloc(len+1)) == NULL)
+ return -1;
+ memcpy(s->srp_ctx.login, &data[1], len);
+ s->srp_ctx.login[len]='\0';
+
+ if (strlen(s->srp_ctx.login) != len)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+#endif
+
+#ifndef OPENSSL_NO_EC
+ else if (type == TLSEXT_TYPE_ec_point_formats &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+ int ecpointformatlist_length = *(sdata++);
+
+ if (ecpointformatlist_length != size - 1)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->hit)
+ {
+ if(s->session->tlsext_ecpointformatlist)
+ {
+ OPENSSL_free(s->session->tlsext_ecpointformatlist);
+ s->session->tlsext_ecpointformatlist = NULL;
+ }
+ s->session->tlsext_ecpointformatlist_length = 0;
+ if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+ memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+ }
+#if 0
+ fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
+ sdata = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ fprintf(stderr,"%i ",*(sdata++));
+ fprintf(stderr,"\n");
+#endif
+ }
+ else if (type == TLSEXT_TYPE_elliptic_curves &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+ int ellipticcurvelist_length = (*(sdata++) << 8);
+ ellipticcurvelist_length += (*(sdata++));
+
+ if (ellipticcurvelist_length != size - 2 ||
+ ellipticcurvelist_length < 1)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->hit)
+ {
+ if(s->session->tlsext_ellipticcurvelist)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ellipticcurvelist_length = 0;
+ if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
+ memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
+ }
+#if 0
+ fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length);
+ sdata = s->session->tlsext_ellipticcurvelist;
+ for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
+ fprintf(stderr,"%i ",*(sdata++));
+ fprintf(stderr,"\n");
+#endif
+ }
+#endif /* OPENSSL_NO_EC */
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ else if (type == TLSEXT_TYPE_opaque_prf_input &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+
+ if (size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(sdata, s->s3->client_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input_len != size - 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->client_opaque_prf_input);
+ if (s->s3->client_opaque_prf_input_len == 0)
+ s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+#endif
+ else if (type == TLSEXT_TYPE_session_ticket)
+ {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+ else if (type == TLSEXT_TYPE_renegotiate)
+ {
+ if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
+ }
+ else if (type == TLSEXT_TYPE_signature_algorithms)
+ {
+ int dsize;
+ if (sigalg_seen || size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sigalg_seen = 1;
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize != size || dsize & 1)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!tls1_process_sigalgs(s, data, dsize))
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION)
+ {
+
+ if (size < 5)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ s->tlsext_status_type = *data++;
+ size--;
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ {
+ const unsigned char *sdata;
+ int dsize;
+ /* Read in responder_id_list */
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize > size )
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ while (dsize > 0)
+ {
+ OCSP_RESPID *id;
+ int idsize;
+ if (dsize < 4)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data, idsize);
+ dsize -= 2 + idsize;
+ size -= 2 + idsize;
+ if (dsize < 0)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sdata = data;
+ data += idsize;
+ id = d2i_OCSP_RESPID(NULL,
+ &sdata, idsize);
+ if (!id)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (data != sdata)
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->tlsext_ocsp_ids
+ && !(s->tlsext_ocsp_ids =
+ sk_OCSP_RESPID_new_null()))
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ if (!sk_OCSP_RESPID_push(
+ s->tlsext_ocsp_ids, id))
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+
+ /* Read in request_extensions */
+ if (size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize != size)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sdata = data;
+ if (dsize > 0)
+ {
+ if (s->tlsext_ocsp_exts)
+ {
+ sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+ X509_EXTENSION_free);
+ }
+
+ s->tlsext_ocsp_exts =
+ d2i_X509_EXTENSIONS(NULL,
+ &sdata, dsize);
+ if (!s->tlsext_ocsp_exts
+ || (data + dsize != sdata))
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ }
+ /* We don't know what to do with any other type
+ * so ignore it.
+ */
+ else
+ s->tlsext_status_type = -1;
+ }
+#ifndef OPENSSL_NO_HEARTBEATS
+ else if (type == TLSEXT_TYPE_heartbeat)
+ {
+ switch(data[0])
+ {
+ case 0x01: /* Client allows us to send HB requests */
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+ break;
+ case 0x02: /* Client doesn't accept HB requests */
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+ break;
+ default: *al = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+ }
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ else if (type == TLSEXT_TYPE_next_proto_neg &&
+ s->s3->tmp.finish_md_len == 0)
+ {
+ /* We shouldn't accept this extension on a
+ * renegotiation.
+ *
+ * s->new_session will be set on renegotiation, but we
+ * probably shouldn't rely that it couldn't be set on
+ * the initial renegotation too in certain cases (when
+ * there's some other reason to disallow resuming an
+ * earlier session -- the current code won't be doing
+ * anything like that, but this might change).
+
+ * A valid sign that there's been a previous handshake
+ * in this connection is if s->s3->tmp.finish_md_len >
+ * 0. (We are talking about a check that will happen
+ * in the Hello protocol round, well before a new
+ * Finished message could have been computed.) */
+ s->s3->next_proto_neg_seen = 1;
+ }
+#endif
+
+ /* session ticket processed earlier */
+#ifndef OPENSSL_NO_SRTP
+ else if (type == TLSEXT_TYPE_use_srtp)
+ {
+ if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
+ al))
+ return 0;
+ }
+#endif
+
+ data+=size;
+ }
+
+ *p = data;
+
+ ri_check:
+
+ /* Need RI if renegotiating */
+
+ if (!renegotiate_seen && s->renegotiate &&
+ !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+ {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
+ return 1;
+ }
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
+ * elements of zero length are allowed and the set of elements must exactly fill
+ * the length of the block. */
+static char ssl_next_proto_validate(unsigned char *d, unsigned len)
+ {
+ unsigned int off = 0;
+
+ while (off < len)
+ {
+ if (d[off] == 0)
+ return 0;
+ off += d[off];
+ off++;
+ }
+
+ return off == len;
+ }
+#endif
+
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+ {
+ unsigned short length;
+ unsigned short type;
+ unsigned short size;
+ unsigned char *data = *p;
+ int tlsext_servername = 0;
+ int renegotiate_seen = 0;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ s->s3->next_proto_neg_seen = 0;
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+ SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+#endif
+
+ if (data >= (d+n-2))
+ goto ri_check;
+
+ n2s(data,length);
+ if (data+length != d+n)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ while(data <= (d+n-4))
+ {
+ n2s(data,type);
+ n2s(data,size);
+
+ if (data+size > (d+n))
+ goto ri_check;
+
+ if (s->tlsext_debug_cb)
+ s->tlsext_debug_cb(s, 1, type, data, size,
+ s->tlsext_debug_arg);
+
+ if (type == TLSEXT_TYPE_server_name)
+ {
+ if (s->tlsext_hostname == NULL || size > 0)
+ {
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ tlsext_servername = 1;
+ }
+
+#ifndef OPENSSL_NO_EC
+ else if (type == TLSEXT_TYPE_ec_point_formats &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+ int ecpointformatlist_length = *(sdata++);
+
+ if (ecpointformatlist_length != size - 1 ||
+ ecpointformatlist_length < 1)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ecpointformatlist_length = 0;
+ if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
+ if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+ memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+#if 0
+ fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
+ sdata = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ fprintf(stderr,"%i ",*(sdata++));
+ fprintf(stderr,"\n");
+#endif
+ }
+#endif /* OPENSSL_NO_EC */
+
+ else if (type == TLSEXT_TYPE_session_ticket)
+ {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ || (size > 0))
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ s->tlsext_ticket_expected = 1;
+ }
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ else if (type == TLSEXT_TYPE_opaque_prf_input &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+
+ if (size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(sdata, s->s3->server_opaque_prf_input_len);
+ if (s->s3->server_opaque_prf_input_len != size - 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->server_opaque_prf_input);
+ if (s->s3->server_opaque_prf_input_len == 0)
+ s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len);
+
+ if (s->s3->server_opaque_prf_input == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+#endif
+ else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION)
+ {
+ /* MUST be empty and only sent if we've requested
+ * a status request message.
+ */
+ if ((s->tlsext_status_type == -1) || (size > 0))
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ /* Set flag to expect CertificateStatus message */
+ s->tlsext_status_expected = 1;
+ }
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ else if (type == TLSEXT_TYPE_next_proto_neg &&
+ s->s3->tmp.finish_md_len == 0)
+ {
+ unsigned char *selected;
+ unsigned char selected_len;
+
+ /* We must have requested it. */
+ if (s->ctx->next_proto_select_cb == NULL)
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ /* The data must be valid */
+ if (!ssl_next_proto_validate(data, size))
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (s->ctx->next_proto_select_cb(s, &selected, &selected_len, data, size, s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->next_proto_negotiated = OPENSSL_malloc(selected_len);
+ if (!s->next_proto_negotiated)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ memcpy(s->next_proto_negotiated, selected, selected_len);
+ s->next_proto_negotiated_len = selected_len;
+ s->s3->next_proto_neg_seen = 1;
+ }
+#endif
+ else if (type == TLSEXT_TYPE_renegotiate)
+ {
+ if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
+ }
+#ifndef OPENSSL_NO_HEARTBEATS
+ else if (type == TLSEXT_TYPE_heartbeat)
+ {
+ switch(data[0])
+ {
+ case 0x01: /* Server allows us to send HB requests */
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+ break;
+ case 0x02: /* Server doesn't accept HB requests */
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+ break;
+ default: *al = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+ }
+#endif
+#ifndef OPENSSL_NO_SRTP
+ else if (type == TLSEXT_TYPE_use_srtp)
+ {
+ if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
+ al))
+ return 0;
+ }
+#endif
+
+ data+=size;
+ }
+
+ if (data != d+n)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (!s->hit && tlsext_servername == 1)
+ {
+ if (s->tlsext_hostname)
+ {
+ if (s->session->tlsext_hostname == NULL)
+ {
+ s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
+ if (!s->session->tlsext_hostname)
+ {
+ *al = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ }
+ else
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ }
+
+ *p = data;
+
+ ri_check:
+
+ /* Determine if we need to see RI. Strictly speaking if we want to
+ * avoid an attack we should *always* see RI even on initial server
+ * hello because the client doesn't see any renegotiation during an
+ * attack. However this would mean we could not connect to any server
+ * which doesn't support RI so for the immediate future tolerate RI
+ * absence on initial connect only.
+ */
+ if (!renegotiate_seen
+ && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
+ && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+ {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
+ return 1;
+ }
+
+
+int ssl_prepare_clienthello_tlsext(SSL *s)
+ {
+#ifndef OPENSSL_NO_EC
+ /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats
+ * and elliptic curves we support.
+ */
+ int using_ecc = 0;
+ int i;
+ unsigned char *j;
+ unsigned long alg_k, alg_a;
+ STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
+
+ for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
+ {
+ SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
+
+ alg_k = c->algorithm_mkey;
+ alg_a = c->algorithm_auth;
+ if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe) || (alg_a & SSL_aECDSA)))
+ {
+ using_ecc = 1;
+ break;
+ }
+ }
+ using_ecc = using_ecc && (s->version >= TLS1_VERSION);
+ if (using_ecc)
+ {
+ if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
+ if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
+ {
+ SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->tlsext_ecpointformatlist_length = 3;
+ s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
+ s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+ s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+
+ /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */
+ if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist);
+ s->tlsext_ellipticcurvelist_length = sizeof(pref_list)/sizeof(pref_list[0]) * 2;
+ if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL)
+ {
+ s->tlsext_ellipticcurvelist_length = 0;
+ SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ for (i = 0, j = s->tlsext_ellipticcurvelist; (unsigned int)i <
+ sizeof(pref_list)/sizeof(pref_list[0]); i++)
+ {
+ int id = tls1_ec_nid2curve_id(pref_list[i]);
+ s2n(id,j);
+ }
+ }
+#endif /* OPENSSL_NO_EC */
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ {
+ int r = 1;
+
+ if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+ {
+ r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+ if (!r)
+ return -1;
+ }
+
+ if (s->tlsext_opaque_prf_input != NULL)
+ {
+ if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->client_opaque_prf_input);
+
+ if (s->tlsext_opaque_prf_input_len == 0)
+ s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input == NULL)
+ {
+ SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+
+ if (r == 2)
+ /* at callback's request, insist on receiving an appropriate server opaque PRF input */
+ s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+#endif
+
+ return 1;
+ }
+
+int ssl_prepare_serverhello_tlsext(SSL *s)
+ {
+#ifndef OPENSSL_NO_EC
+ /* If we are server and using an ECC cipher suite, send the point formats we support
+ * if the client sent us an ECPointsFormat extension. Note that the server is not
+ * supposed to send an EllipticCurves extension.
+ */
+
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
+ using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
+
+ if (using_ecc)
+ {
+ if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
+ if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
+ {
+ SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->tlsext_ecpointformatlist_length = 3;
+ s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
+ s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+ s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+ }
+#endif /* OPENSSL_NO_EC */
+
+ return 1;
+ }
+
+int ssl_check_clienthello_tlsext_early(SSL *s)
+ {
+ int ret=SSL_TLSEXT_ERR_NOACK;
+ int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+ /* The handling of the ECPointFormats extension is done elsewhere, namely in
+ * ssl3_choose_cipher in s3_lib.c.
+ */
+ /* The handling of the EllipticCurves extension is done elsewhere, namely in
+ * ssl3_choose_cipher in s3_lib.c.
+ */
+#endif
+
+ if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
+ ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+ else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
+ ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ {
+ /* This sort of belongs into ssl_prepare_serverhello_tlsext(),
+ * but we might be sending an alert in response to the client hello,
+ * so this has to happen here in
+ * ssl_check_clienthello_tlsext_early(). */
+
+ int r = 1;
+
+ if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+ {
+ r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+ if (!r)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+
+ if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->server_opaque_prf_input);
+ s->s3->server_opaque_prf_input = NULL;
+
+ if (s->tlsext_opaque_prf_input != NULL)
+ {
+ if (s->s3->client_opaque_prf_input != NULL &&
+ s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len)
+ {
+ /* can only use this extension if we have a server opaque PRF input
+ * of the same length as the client opaque PRF input! */
+
+ if (s->tlsext_opaque_prf_input_len == 0)
+ s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+ if (s->s3->server_opaque_prf_input == NULL)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+ }
+
+ if (r == 2 && s->s3->server_opaque_prf_input == NULL)
+ {
+ /* The callback wants to enforce use of the extension,
+ * but we can't do that with the client opaque PRF input;
+ * abort the handshake.
+ */
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ }
+ }
+
+ err:
+#endif
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ case SSL_TLSEXT_ERR_NOACK:
+ s->servername_done=0;
+ default:
+ return 1;
+ }
+ }
+
+int ssl_check_clienthello_tlsext_late(SSL *s)
+ {
+ int ret = SSL_TLSEXT_ERR_OK;
+ int al;
+
+ /* If status request then ask callback what to do.
+ * Note: this must be called after servername callbacks in case
+ * the certificate has changed, and must be called after the cipher
+ * has been chosen because this may influence which certificate is sent
+ */
+ if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ CERT_PKEY *certpkey;
+ certpkey = ssl_get_server_send_pkey(s);
+ /* If no certificate can't return certificate status */
+ if (certpkey == NULL)
+ {
+ s->tlsext_status_expected = 0;
+ return 1;
+ }
+ /* Set current certificate to one we will use so
+ * SSL_get_certificate et al can pick it up.
+ */
+ s->cert->key = certpkey;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (r)
+ {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
+ s->tlsext_status_expected = 0;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ else
+ s->tlsext_status_expected = 0;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+ else
+ s->tlsext_status_expected = 0;
+
+ err:
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ default:
+ return 1;
+ }
+ }
+
+int ssl_check_serverhello_tlsext(SSL *s)
+ {
+ int ret=SSL_TLSEXT_ERR_NOACK;
+ int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+ /* If we are client and using an elliptic curve cryptography cipher
+ * suite, then if server returns an EC point formats lists extension
+ * it must contain uncompressed.
+ */
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) &&
+ (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) &&
+ ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA)))
+ {
+ /* we are using an ECC cipher */
+ size_t i;
+ unsigned char *list;
+ int found_uncompressed = 0;
+ list = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ {
+ if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed)
+ {
+ found_uncompressed = 1;
+ break;
+ }
+ }
+ if (!found_uncompressed)
+ {
+ SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+ return -1;
+ }
+ }
+ ret = SSL_TLSEXT_ERR_OK;
+#endif /* OPENSSL_NO_EC */
+
+ if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
+ ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+ else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
+ ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->server_opaque_prf_input_len > 0)
+ {
+ /* This case may indicate that we, as a client, want to insist on using opaque PRF inputs.
+ * So first verify that we really have a value from the server too. */
+
+ if (s->s3->server_opaque_prf_input == NULL)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ }
+
+ /* Anytime the server *has* sent an opaque PRF input, we need to check
+ * that we have a client opaque PRF input of the same size. */
+ if (s->s3->client_opaque_prf_input == NULL ||
+ s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ }
+ }
+#endif
+
+ /* If we've requested certificate status and we wont get one
+ * tell the callback
+ */
+ if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
+ && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ /* Set resp to NULL, resplen to -1 so callback knows
+ * there is no response.
+ */
+ if (s->tlsext_ocsp_resp)
+ {
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = NULL;
+ }
+ s->tlsext_ocsp_resplen = -1;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ if (r == 0)
+ {
+ al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ if (r < 0)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ }
+
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ case SSL_TLSEXT_ERR_NOACK:
+ s->servername_done=0;
+ default:
+ return 1;
+ }
+ }
+
+/* Since the server cache lookup is done early on in the processing of the
+ * ClientHello, and other operations depend on the result, we need to handle
+ * any TLS session ticket extension at the same time.
+ *
+ * session_id: points at the session ID in the ClientHello. This code will
+ * read past the end of this in order to parse out the session ticket
+ * extension, if any.
+ * len: the length of the session ID.
+ * limit: a pointer to the first byte after the ClientHello.
+ * ret: (output) on return, if a ticket was decrypted, then this is set to
+ * point to the resulting session.
+ *
+ * If s->tls_session_secret_cb is set then we are expecting a pre-shared key
+ * ciphersuite, in which case we have no use for session tickets and one will
+ * never be decrypted, nor will s->tlsext_ticket_expected be set to 1.
+ *
+ * Returns:
+ * -1: fatal error, either from parsing or decrypting the ticket.
+ * 0: no ticket was found (or was ignored, based on settings).
+ * 1: a zero length extension was found, indicating that the client supports
+ * session tickets but doesn't currently have one to offer.
+ * 2: either s->tls_session_secret_cb was set, or a ticket was offered but
+ * couldn't be decrypted because of a non-fatal error.
+ * 3: a ticket was successfully decrypted and *ret was set.
+ *
+ * Side effects:
+ * Sets s->tlsext_ticket_expected to 1 if the server will have to issue
+ * a new session ticket to the client because the client indicated support
+ * (and s->tls_session_secret_cb is NULL) but the client either doesn't have
+ * a session ticket or we couldn't use the one it gave us, or if
+ * s->ctx->tlsext_ticket_key_cb asked to renew the client's ticket.
+ * Otherwise, s->tlsext_ticket_expected is set to 0.
+ */
+int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
+ const unsigned char *limit, SSL_SESSION **ret)
+ {
+ /* Point after session ID in client hello */
+ const unsigned char *p = session_id + len;
+ unsigned short i;
+
+ *ret = NULL;
+ s->tlsext_ticket_expected = 0;
+
+ /* If tickets disabled behave as if no ticket present
+ * to permit stateful resumption.
+ */
+ if (SSL_get_options(s) & SSL_OP_NO_TICKET)
+ return 0;
+ if ((s->version <= SSL3_VERSION) || !limit)
+ return 0;
+ if (p >= limit)
+ return -1;
+ /* Skip past DTLS cookie */
+ if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+ {
+ i = *(p++);
+ p+= i;
+ if (p >= limit)
+ return -1;
+ }
+ /* Skip past cipher list */
+ n2s(p, i);
+ p+= i;
+ if (p >= limit)
+ return -1;
+ /* Skip past compression algorithm list */
+ i = *(p++);
+ p += i;
+ if (p > limit)
+ return -1;
+ /* Now at start of extensions */
+ if ((p + 2) >= limit)
+ return 0;
+ n2s(p, i);
+ while ((p + 4) <= limit)
+ {
+ unsigned short type, size;
+ n2s(p, type);
+ n2s(p, size);
+ if (p + size > limit)
+ return 0;
+ if (type == TLSEXT_TYPE_session_ticket)
+ {
+ int r;
+ if (size == 0)
+ {
+ /* The client will accept a ticket but doesn't
+ * currently have one. */
+ s->tlsext_ticket_expected = 1;
+ return 1;
+ }
+ if (s->tls_session_secret_cb)
+ {
+ /* Indicate that the ticket couldn't be
+ * decrypted rather than generating the session
+ * from ticket now, trigger abbreviated
+ * handshake based on external mechanism to
+ * calculate the master secret later. */
+ return 2;
+ }
+ r = tls_decrypt_ticket(s, p, size, session_id, len, ret);
+ switch (r)
+ {
+ case 2: /* ticket couldn't be decrypted */
+ s->tlsext_ticket_expected = 1;
+ return 2;
+ case 3: /* ticket was decrypted */
+ return r;
+ case 4: /* ticket decrypted but need to renew */
+ s->tlsext_ticket_expected = 1;
+ return 3;
+ default: /* fatal error */
+ return -1;
+ }
+ }
+ p += size;
+ }
+ return 0;
+ }
+
+/* tls_decrypt_ticket attempts to decrypt a session ticket.
+ *
+ * etick: points to the body of the session ticket extension.
+ * eticklen: the length of the session tickets extenion.
+ * sess_id: points at the session ID.
+ * sesslen: the length of the session ID.
+ * psess: (output) on return, if a ticket was decrypted, then this is set to
+ * point to the resulting session.
+ *
+ * Returns:
+ * -1: fatal error, either from parsing or decrypting the ticket.
+ * 2: the ticket couldn't be decrypted.
+ * 3: a ticket was successfully decrypted and *psess was set.
+ * 4: same as 3, but the ticket needs to be renewed.
+ */
+static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
+ const unsigned char *sess_id, int sesslen,
+ SSL_SESSION **psess)
+ {
+ SSL_SESSION *sess;
+ unsigned char *sdec;
+ const unsigned char *p;
+ int slen, mlen, renew_ticket = 0;
+ unsigned char tick_hmac[EVP_MAX_MD_SIZE];
+ HMAC_CTX hctx;
+ EVP_CIPHER_CTX ctx;
+ SSL_CTX *tctx = s->initial_ctx;
+ /* Need at least keyname + iv + some encrypted data */
+ if (eticklen < 48)
+ return 2;
+ /* Initialize session ticket encryption and HMAC contexts */
+ HMAC_CTX_init(&hctx);
+ EVP_CIPHER_CTX_init(&ctx);
+ if (tctx->tlsext_ticket_key_cb)
+ {
+ unsigned char *nctick = (unsigned char *)etick;
+ int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
+ &ctx, &hctx, 0);
+ if (rv < 0)
+ return -1;
+ if (rv == 0)
+ return 2;
+ if (rv == 2)
+ renew_ticket = 1;
+ }
+ else
+ {
+ /* Check key name matches */
+ if (memcmp(etick, tctx->tlsext_tick_key_name, 16))
+ return 2;
+ HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+ tlsext_tick_md(), NULL);
+ EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ tctx->tlsext_tick_aes_key, etick + 16);
+ }
+ /* Attempt to process session ticket, first conduct sanity and
+ * integrity checks on ticket.
+ */
+ mlen = HMAC_size(&hctx);
+ if (mlen < 0)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return -1;
+ }
+ eticklen -= mlen;
+ /* Check HMAC of encrypted ticket */
+ HMAC_Update(&hctx, etick, eticklen);
+ HMAC_Final(&hctx, tick_hmac, NULL);
+ HMAC_CTX_cleanup(&hctx);
+ if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
+ return 2;
+ /* Attempt to decrypt session data */
+ /* Move p after IV to start of encrypted ticket, update length */
+ p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+ eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+ sdec = OPENSSL_malloc(eticklen);
+ if (!sdec)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return -1;
+ }
+ EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
+ if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
+ return 2;
+ slen += mlen;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ p = sdec;
+
+ sess = d2i_SSL_SESSION(NULL, &p, slen);
+ OPENSSL_free(sdec);
+ if (sess)
+ {
+ /* The session ID, if non-empty, is used by some clients to
+ * detect that the ticket has been accepted. So we copy it to
+ * the session structure. If it is empty set length to zero
+ * as required by standard.
+ */
+ if (sesslen)
+ memcpy(sess->session_id, sess_id, sesslen);
+ sess->session_id_length = sesslen;
+ *psess = sess;
+ if (renew_ticket)
+ return 4;
+ else
+ return 3;
+ }
+ ERR_clear_error();
+ /* For session parse failure, indicate that we need to send a new
+ * ticket. */
+ return 2;
+ }
+
+/* Tables to translate from NIDs to TLS v1.2 ids */
+
+typedef struct
+ {
+ int nid;
+ int id;
+ } tls12_lookup;
+
+static tls12_lookup tls12_md[] = {
+#ifndef OPENSSL_NO_MD5
+ {NID_md5, TLSEXT_hash_md5},
+#endif
+#ifndef OPENSSL_NO_SHA
+ {NID_sha1, TLSEXT_hash_sha1},
+#endif
+#ifndef OPENSSL_NO_SHA256
+ {NID_sha224, TLSEXT_hash_sha224},
+ {NID_sha256, TLSEXT_hash_sha256},
+#endif
+#ifndef OPENSSL_NO_SHA512
+ {NID_sha384, TLSEXT_hash_sha384},
+ {NID_sha512, TLSEXT_hash_sha512}
+#endif
+};
+
+static tls12_lookup tls12_sig[] = {
+#ifndef OPENSSL_NO_RSA
+ {EVP_PKEY_RSA, TLSEXT_signature_rsa},
+#endif
+#ifndef OPENSSL_NO_DSA
+ {EVP_PKEY_DSA, TLSEXT_signature_dsa},
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ {EVP_PKEY_EC, TLSEXT_signature_ecdsa}
+#endif
+};
+
+static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
+ {
+ size_t i;
+ for (i = 0; i < tlen; i++)
+ {
+ if (table[i].nid == nid)
+ return table[i].id;
+ }
+ return -1;
+ }
+#if 0
+static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
+ {
+ size_t i;
+ for (i = 0; i < tlen; i++)
+ {
+ if (table[i].id == id)
+ return table[i].nid;
+ }
+ return -1;
+ }
+#endif
+
+int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md)
+ {
+ int sig_id, md_id;
+ if (!md)
+ return 0;
+ md_id = tls12_find_id(EVP_MD_type(md), tls12_md,
+ sizeof(tls12_md)/sizeof(tls12_lookup));
+ if (md_id == -1)
+ return 0;
+ sig_id = tls12_get_sigid(pk);
+ if (sig_id == -1)
+ return 0;
+ p[0] = (unsigned char)md_id;
+ p[1] = (unsigned char)sig_id;
+ return 1;
+ }
+
+int tls12_get_sigid(const EVP_PKEY *pk)
+ {
+ return tls12_find_id(pk->type, tls12_sig,
+ sizeof(tls12_sig)/sizeof(tls12_lookup));
+ }
+
+const EVP_MD *tls12_get_hash(unsigned char hash_alg)
+ {
+ switch(hash_alg)
+ {
+#ifndef OPENSSL_NO_SHA
+ case TLSEXT_hash_sha1:
+ return EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_SHA256
+ case TLSEXT_hash_sha224:
+ return EVP_sha224();
+
+ case TLSEXT_hash_sha256:
+ return EVP_sha256();
+#endif
+#ifndef OPENSSL_NO_SHA512
+ case TLSEXT_hash_sha384:
+ return EVP_sha384();
+
+ case TLSEXT_hash_sha512:
+ return EVP_sha512();
+#endif
+ default:
+ return NULL;
+
+ }
+ }
+
+/* Set preferred digest for each key type */
+
+int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
+ {
+ int i, idx;
+ const EVP_MD *md;
+ CERT *c = s->cert;
+ /* Extension ignored for TLS versions below 1.2 */
+ if (TLS1_get_version(s) < TLS1_2_VERSION)
+ return 1;
+ /* Should never happen */
+ if (!c)
+ return 0;
+
+ c->pkeys[SSL_PKEY_DSA_SIGN].digest = NULL;
+ c->pkeys[SSL_PKEY_RSA_SIGN].digest = NULL;
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL;
+ c->pkeys[SSL_PKEY_ECC].digest = NULL;
+
+ for (i = 0; i < dsize; i += 2)
+ {
+ unsigned char hash_alg = data[i], sig_alg = data[i+1];
+
+ switch(sig_alg)
+ {
+#ifndef OPENSSL_NO_RSA
+ case TLSEXT_signature_rsa:
+ idx = SSL_PKEY_RSA_SIGN;
+ break;
+#endif
+#ifndef OPENSSL_NO_DSA
+ case TLSEXT_signature_dsa:
+ idx = SSL_PKEY_DSA_SIGN;
+ break;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ case TLSEXT_signature_ecdsa:
+ idx = SSL_PKEY_ECC;
+ break;
+#endif
+ default:
+ continue;
+ }
+
+ if (c->pkeys[idx].digest == NULL)
+ {
+ md = tls12_get_hash(hash_alg);
+ if (md)
+ {
+ c->pkeys[idx].digest = md;
+ if (idx == SSL_PKEY_RSA_SIGN)
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+ }
+ }
+
+ }
+
+
+ /* Set any remaining keys to default values. NOTE: if alg is not
+ * supported it stays as NULL.
+ */
+#ifndef OPENSSL_NO_DSA
+ if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
+ c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_RSA
+ if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
+ {
+ c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+ }
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (!c->pkeys[SSL_PKEY_ECC].digest)
+ c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
+#endif
+ return 1;
+ }
+
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int
+tls1_process_heartbeat(SSL *s)
+ {
+ unsigned char *p = &s->s3->rrec.data[0], *pl;
+ unsigned short hbtype;
+ unsigned int payload;
+ unsigned int padding = 16; /* Use minimum padding */
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+ &s->s3->rrec.data[0], s->s3->rrec.length,
+ s, s->msg_callback_arg);
+
+ /* Read type and payload length first */
+ if (1 + 2 + 16 > s->s3->rrec.length)
+ return 0; /* silently discard */
+ hbtype = *p++;
+ n2s(p, payload);
+ if (1 + 2 + payload + 16 > s->s3->rrec.length)
+ return 0; /* silently discard per RFC 6520 sec. 4 */
+ pl = p;
+
+ if (hbtype == TLS1_HB_REQUEST)
+ {
+ unsigned char *buffer, *bp;
+ int r;
+
+ /* Allocate memory for the response, size is 1 bytes
+ * message type, plus 2 bytes payload length, plus
+ * payload, plus padding
+ */
+ buffer = OPENSSL_malloc(1 + 2 + payload + padding);
+ bp = buffer;
+
+ /* Enter response type, length and copy payload */
+ *bp++ = TLS1_HB_RESPONSE;
+ s2n(payload, bp);
+ memcpy(bp, pl, payload);
+ bp += payload;
+ /* Random padding */
+ RAND_pseudo_bytes(bp, padding);
+
+ r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
+
+ if (r >= 0 && s->msg_callback)
+ s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buffer, 3 + payload + padding,
+ s, s->msg_callback_arg);
+
+ OPENSSL_free(buffer);
+
+ if (r < 0)
+ return r;
+ }
+ else if (hbtype == TLS1_HB_RESPONSE)
+ {
+ unsigned int seq;
+
+ /* We only send sequence numbers (2 bytes unsigned int),
+ * and 16 random bytes, so we just try to read the
+ * sequence number */
+ n2s(pl, seq);
+
+ if (payload == 18 && seq == s->tlsext_hb_seq)
+ {
+ s->tlsext_hb_seq++;
+ s->tlsext_hb_pending = 0;
+ }
+ }
+
+ return 0;
+ }
+
+int
+tls1_heartbeat(SSL *s)
+ {
+ unsigned char *buf, *p;
+ int ret;
+ unsigned int payload = 18; /* Sequence number + random bytes */
+ unsigned int padding = 16; /* Use minimum padding */
+
+ /* Only send if peer supports and accepts HB requests... */
+ if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
+ s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS)
+ {
+ SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+ return -1;
+ }
+
+ /* ...and there is none in flight yet... */
+ if (s->tlsext_hb_pending)
+ {
+ SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING);
+ return -1;
+ }
+
+ /* ...and no handshake in progress. */
+ if (SSL_in_init(s) || s->in_handshake)
+ {
+ SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ /* Check if padding is too long, payload and padding
+ * must not exceed 2^14 - 3 = 16381 bytes in total.
+ */
+ OPENSSL_assert(payload + padding <= 16381);
+
+ /* Create HeartBeat message, we just use a sequence number
+ * as payload to distuingish different messages and add
+ * some random stuff.
+ * - Message Type, 1 byte
+ * - Payload Length, 2 bytes (unsigned int)
+ * - Payload, the sequence number (2 bytes uint)
+ * - Payload, random bytes (16 bytes uint)
+ * - Padding
+ */
+ buf = OPENSSL_malloc(1 + 2 + payload + padding);
+ p = buf;
+ /* Message Type */
+ *p++ = TLS1_HB_REQUEST;
+ /* Payload length (18 bytes here) */
+ s2n(payload, p);
+ /* Sequence number */
+ s2n(s->tlsext_hb_seq, p);
+ /* 16 random bytes */
+ RAND_pseudo_bytes(p, 16);
+ p += 16;
+ /* Random padding */
+ RAND_pseudo_bytes(p, padding);
+
+ ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+ if (ret >= 0)
+ {
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buf, 3 + payload + padding,
+ s, s->msg_callback_arg);
+
+ s->tlsext_hb_pending = 1;
+ }
+
+ OPENSSL_free(buf);
+
+ return ret;
+ }
+#endif
diff --git a/drivers/builtin_openssl/ssl/t1_meth.c b/drivers/builtin_openssl2/ssl/t1_meth.c
index 53c807de28..53c807de28 100644
--- a/drivers/builtin_openssl/ssl/t1_meth.c
+++ b/drivers/builtin_openssl2/ssl/t1_meth.c
diff --git a/drivers/builtin_openssl/ssl/t1_reneg.c b/drivers/builtin_openssl2/ssl/t1_reneg.c
index 9c2cc3c712..9c2cc3c712 100644
--- a/drivers/builtin_openssl/ssl/t1_reneg.c
+++ b/drivers/builtin_openssl2/ssl/t1_reneg.c
diff --git a/drivers/builtin_openssl/ssl/t1_srvr.c b/drivers/builtin_openssl2/ssl/t1_srvr.c
index f1d1565769..f1d1565769 100644
--- a/drivers/builtin_openssl/ssl/t1_srvr.c
+++ b/drivers/builtin_openssl2/ssl/t1_srvr.c
diff --git a/drivers/builtin_openssl/ssl/tls_srp.c b/drivers/builtin_openssl2/ssl/tls_srp.c
index 2315a7c0a2..2315a7c0a2 100644
--- a/drivers/builtin_openssl/ssl/tls_srp.c
+++ b/drivers/builtin_openssl2/ssl/tls_srp.c
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 070c74d130..9cd754ed47 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_envelope.cpp b/drivers/chibi/cp_envelope.cpp
index 8eb3bd5ba0..6ed42a1167 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_envelope.h b/drivers/chibi/cp_envelope.h
index 67df8384c2..e01605ada3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_file_access_wrapper.cpp b/drivers/chibi/cp_file_access_wrapper.cpp
index 66212b2b23..d7c6c6d0b6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_file_access_wrapper.h b/drivers/chibi/cp_file_access_wrapper.h
index 57f3d53e75..c54ce5868d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_instrument.cpp b/drivers/chibi/cp_instrument.cpp
index 9a96da2481..2e5af70565 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_instrument.h b/drivers/chibi/cp_instrument.h
index 863b31c80a..8b434402c5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader.h b/drivers/chibi/cp_loader.h
index 243b8145ae..7763c395b9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_it.cpp b/drivers/chibi/cp_loader_it.cpp
index dae6b26d97..74dd228437 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_it.h b/drivers/chibi/cp_loader_it.h
index 6a192386e2..6ba605bf04 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_it_info.cpp b/drivers/chibi/cp_loader_it_info.cpp
index fc230a3342..0cfd73f1e3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_it_instruments.cpp b/drivers/chibi/cp_loader_it_instruments.cpp
index f315b9b5c8..6293be162c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_it_patterns.cpp b/drivers/chibi/cp_loader_it_patterns.cpp
index 30d87dbebf..c79dffc180 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_it_samples.cpp b/drivers/chibi/cp_loader_it_samples.cpp
index 040f9d4dd7..24d3a12781 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_mod.cpp b/drivers/chibi/cp_loader_mod.cpp
index 1ea3a93e9c..98174ff9b1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_mod.h b/drivers/chibi/cp_loader_mod.h
index cf16635ef0..77245349b7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_s3m.cpp b/drivers/chibi/cp_loader_s3m.cpp
index c5f0830ae6..c21f7bdd38 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -162,7 +162,7 @@ CPLoader::Error CPLoader_S3M::load_sample(CPSample *p_sample) {
p_sample->set_default_volume(def_volume);
p_sample->set_name(name);
- char scrs[4];
+ char scrs[5];
file->get_byte_array((uint8_t*)scrs,4);
scrs[4]=0;
diff --git a/drivers/chibi/cp_loader_s3m.h b/drivers/chibi/cp_loader_s3m.h
index 9fccef0886..6fe9f0ca44 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_xm.cpp b/drivers/chibi/cp_loader_xm.cpp
index 228567afd6..8bde6b673e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_loader_xm.h b/drivers/chibi/cp_loader_xm.h
index 230dff6be7..0a2465475f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_mixer.h b/drivers/chibi/cp_mixer.h
index 28fc11459c..bac2087edf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_note.h b/drivers/chibi/cp_note.h
index 17de7e72ee..5d2c01844a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_order.h b/drivers/chibi/cp_order.h
index ca3684d154..a20e202bde 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_pattern.cpp b/drivers/chibi/cp_pattern.cpp
index b880071cca..cc65833d68 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_pattern.h b/drivers/chibi/cp_pattern.h
index b8d1e0a18d..22611eabab 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_player_data.cpp b/drivers/chibi/cp_player_data.cpp
index 324c3f7c36..76d8f280d2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -125,7 +125,7 @@ int64_t CPPlayer::get_channel_last_note_time_usec(int p_channel) const {
void CPPlayer::set_channel_global_volume(int p_channel,int p_volume) {
CP_FAIL_INDEX(p_channel,64);
- control.channel[p_channel].channel_global_volume=p_volume;
+ control.channel[p_channel].channel_global_volume=CLAMP(p_volume,0,255);
}
diff --git a/drivers/chibi/cp_player_data.h b/drivers/chibi/cp_player_data.h
index d62cef17a1..36a27942cb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_player_data_control.cpp b/drivers/chibi/cp_player_data_control.cpp
index 96ffae667b..d5ca648fff 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -233,7 +233,7 @@ int CPPlayer::get_channel_voice(int p_channel) {
const char* CPPlayer::get_voice_sample_name(int p_voice) {
- const char *name;
+ const char *name = NULL;
@@ -302,7 +302,7 @@ const char * CPPlayer::get_voice_instrument_name(int p_voice) {
- const char *name;
+ const char *name = NULL;
diff --git a/drivers/chibi/cp_player_data_effects.cpp b/drivers/chibi/cp_player_data_effects.cpp
index e116b3b473..eb62b8d962 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_player_data_envelopes.cpp b/drivers/chibi/cp_player_data_envelopes.cpp
index 12456ab082..94378b8bf4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_player_data_events.cpp b/drivers/chibi/cp_player_data_events.cpp
index 6f2815211c..7a7cfdf5bb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -146,6 +146,7 @@ void CPPlayer::Voice_Control::reset() {
void CPPlayer::Channel_Control::reset() {
+ int prev_gv =channel_global_volume;
cp_memzero(this,sizeof(*this));
slave_voice=NULL;
@@ -162,6 +163,7 @@ void CPPlayer::Channel_Control::reset() {
reserved=false;
carry.maybe=false;
last_event_usecs=-1;
+ channel_global_volume=prev_gv;
}
void CPPlayer::Voice_Control::update_info_from_master_channel() {
@@ -316,6 +318,15 @@ void CPPlayer::update_mixer() {
}
+ /*printf("fadeout %i\n",(int)v.fadeout_volume);
+ printf("channel %i\n",(int)v.channel_volume);
+ printf("output %i\n",(int)v.output_volume);
+ printf("env %i\n",(int)tmp_volenv_value);
+ printf("cgb %i\n",(int)v.master_channel->channel_global_volume);
+*/
+
+
+ int cv=v.master_channel->channel_global_volume;
tmpvol=(uint64_t)v.fadeout_volume; /* max 1024 - 10 bits */
tmpvol*=(uint64_t)v.channel_volume; /* * max 64 - 6 bits */
@@ -341,6 +352,7 @@ void CPPlayer::update_mixer() {
v.total_volume=tmpvol;
+
if ((v.master_channel!=NULL) && song->is_channel_mute( v.master_channel_index ) && !v.master_channel->reserved) {
mixer->set_voice_volume(i,0);
@@ -518,7 +530,7 @@ void CPPlayer::update_mixer() {
}
}
-
+
switch(song->get_reverb_mode()) {
case CPSong::REVERB_MODE_ROOM: {
@@ -569,6 +581,8 @@ void CPPlayer::update_mixer() {
}
mixer->set_chorus_params(song->get_chorus_delay_ms(),song->get_chorus_separation_ms(),song->get_chorus_depth_ms10(),song->get_chorus_speed_hz10() );
+
+
}
diff --git a/drivers/chibi/cp_player_data_filter.cpp b/drivers/chibi/cp_player_data_filter.cpp
index 75e8bc961a..fd87e4ae7a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_player_data_nna.cpp b/drivers/chibi/cp_player_data_nna.cpp
index f87045c309..3960234f5e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_player_data_notes.cpp b/drivers/chibi/cp_player_data_notes.cpp
index d61ac0e30f..ea3ba42e86 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_player_data_reserved.cpp b/drivers/chibi/cp_player_data_reserved.cpp
index 43e913a54e..8d9439158b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_player_data_utils.cpp b/drivers/chibi/cp_player_data_utils.cpp
index 543d525f3f..5294fc8139 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_sample.cpp b/drivers/chibi/cp_sample.cpp
index 667d045d7c..bff24d4c4c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_sample.h b/drivers/chibi/cp_sample.h
index 2017ab0659..71b57aaa81 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_sample_defs.h b/drivers/chibi/cp_sample_defs.h
index c17b6fac51..32817efc7d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_sample_manager.cpp b/drivers/chibi/cp_sample_manager.cpp
index 0a18d7b0ab..601db07acf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_sample_manager.h b/drivers/chibi/cp_sample_manager.h
index 35ecb59c7a..2891034482 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_song.cpp b/drivers/chibi/cp_song.cpp
index 3751d76c25..956e2ee6d4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_song.h b/drivers/chibi/cp_song.h
index fb6e7f7f29..6c35b43c76 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_tables.cpp b/drivers/chibi/cp_tables.cpp
index f30aeca543..9f1ae30c9a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/cp_tables.h b/drivers/chibi/cp_tables.h
index 4f4a8c07bd..6c3c9271b0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/chibi/event_stream_chibi.cpp b/drivers/chibi/event_stream_chibi.cpp
index a9106d6d78..ecb5c3f22b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -372,6 +372,7 @@ void CPMixerImpl::set_voice_panning(int p_voice_index,int p_pan) {
void CPMixerImpl::set_voice_volume(int p_voice_index,int p_vol) {
+
Voice &v=voices[p_voice_index];
ERR_FAIL_COND(v.channel==AudioMixer::INVALID_CHANNEL);
float vol = p_vol/512.0;
@@ -488,8 +489,9 @@ void CPMixerImpl::process_usecs(int p_usec,float p_volume,float p_pitch_scale,fl
p_usec-=callback_timeout;
callback_timeout=0;
- if (callback)
+ if (callback) {
callback(userdata);
+ }
callback_timeout=callback_interval*(1.0/p_tempo_scale);
} else {
@@ -704,6 +706,9 @@ float EventStreamPlaybackChibi::get_tempo_scale() const{
void EventStreamPlaybackChibi::set_channel_volume(int p_channel,float p_volume) {
+
+ if (p_channel>=64)
+ return;
player->set_channel_global_volume(p_channel,p_volume*256);
}
@@ -774,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;
@@ -784,28 +791,42 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina
Ref<EventStreamChibi> esc( memnew( EventStreamChibi ) );
CPLoader_IT loader(&f);
- loader.load_song(p_path.utf8().get_data(),&esc->song,false);
+ 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=="xm") {
Ref<EventStreamChibi> esc( memnew( EventStreamChibi ) );
CPLoader_XM loader(&f);
- loader.load_song(p_path.utf8().get_data(),&esc->song,false);
+ 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") {
Ref<EventStreamChibi> esc( memnew( EventStreamChibi ) );
CPLoader_S3M loader(&f);
- loader.load_song(p_path.utf8().get_data(),&esc->song,false);
+ 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") {
Ref<EventStreamChibi> esc( memnew( EventStreamChibi ) );
CPLoader_MOD loader(&f);
- loader.load_song(p_path.utf8().get_data(),&esc->song,false);
+ 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 3f322f7a65..b564c16018 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 49a3e74c2a..775f2adfe2 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
@@ -970,6 +970,7 @@ int32 DecomposeConvex(b2Polygon* p, b2Polygon* results, int32 maxPolys) {
}
if (nTri < 1) {
//Still no luck? Oh well...
+ delete[] triangulated;
return -1;
}
int32 nPolys = PolygonizeTriangles(triangulated, nTri, results, maxPolys);
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 152dc3f4d0..4ce921ad9f 100644
--- a/drivers/etc1/SCsub
+++ b/drivers/etc1/SCsub
@@ -6,9 +6,9 @@ etc_sources = [
"etc1/rg_etc1.cpp"
]
-env.drivers_sources+=etc_sources
+if (env["etc1"] != "no"):
+ env.drivers_sources+=etc_sources
#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 cad9af8830..47dcb57e6b 100644
--- a/drivers/etc1/rg_etc1.cpp
+++ b/drivers/etc1/rg_etc1.cpp
@@ -1,2451 +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 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 = intabs(v - 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 77a94f9333..82195cc6f6 100644
--- a/drivers/gl_context/context_gl.cpp
+++ b/drivers/gl_context/context_gl.cpp
@@ -12,7 +12,7 @@
#include "context_gl.h"
-#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) || defined(GLES2_ENABLED) || defined(GLES1_ENABLED)
+#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED)
diff --git a/drivers/gl_context/context_gl.h b/drivers/gl_context/context_gl.h
index 4c3d863e87..6b06ccdc37 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,7 +29,7 @@
#ifndef CONTEXT_GL_H
#define CONTEXT_GL_H
-#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) || defined(GLES2_ENABLED) || defined(GLES1_ENABLED)
+#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED)
#include "typedefs.h"
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/gles1/SCsub b/drivers/gles1/SCsub
deleted file mode 100644
index 6a3e474eae..0000000000
--- a/drivers/gles1/SCsub
+++ /dev/null
@@ -1,5 +0,0 @@
-Import('env')
-Export('env');
-
-env.add_source_files(env.drivers_sources,"*.cpp")
-
diff --git a/drivers/gles1/rasterizer_gles1.cpp b/drivers/gles1/rasterizer_gles1.cpp
deleted file mode 100644
index ad0c8e3c7f..0000000000
--- a/drivers/gles1/rasterizer_gles1.cpp
+++ /dev/null
@@ -1,5957 +0,0 @@
-/*************************************************************************/
-/* rasterizer_gles1.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifdef GLES1_ENABLED
-
-#include "rasterizer_gles1.h"
-#include "os/os.h"
-#include "globals.h"
-#include <stdio.h>
-#include "drivers/gl_context/context_gl.h"
-#include "servers/visual/shader_language.h"
-#include "servers/visual/particle_system_sw.h"
-#include "gl_context/context_gl.h"
-#include <string.h>
-
-_FORCE_INLINE_ static void _gl_load_transform(const Transform& tr) {
-
- GLfloat matrix[16]={ /* build a 16x16 matrix */
- tr.basis.elements[0][0],
- tr.basis.elements[1][0],
- tr.basis.elements[2][0],
- 0,
- tr.basis.elements[0][1],
- tr.basis.elements[1][1],
- tr.basis.elements[2][1],
- 0,
- tr.basis.elements[0][2],
- tr.basis.elements[1][2],
- tr.basis.elements[2][2],
- 0,
- tr.origin.x,
- tr.origin.y,
- tr.origin.z,
- 1
- };
-
- glLoadMatrixf(matrix);
-};
-
-
-_FORCE_INLINE_ static void _gl_mult_transform(const Transform& tr) {
-
- GLfloat matrix[16]={ /* build a 16x16 matrix */
- tr.basis.elements[0][0],
- tr.basis.elements[1][0],
- tr.basis.elements[2][0],
- 0,
- tr.basis.elements[0][1],
- tr.basis.elements[1][1],
- tr.basis.elements[2][1],
- 0,
- tr.basis.elements[0][2],
- tr.basis.elements[1][2],
- tr.basis.elements[2][2],
- 0,
- tr.origin.x,
- tr.origin.y,
- tr.origin.z,
- 1
- };
-
- glMultMatrixf(matrix);
-};
-
-_FORCE_INLINE_ static void _gl_mult_transform(const Matrix32& tr) {
-
- GLfloat matrix[16]={ /* build a 16x16 matrix */
- tr.elements[0][0],
- tr.elements[0][1],
- 0,
- 0,
- tr.elements[1][0],
- tr.elements[1][1],
- 0,
- 0,
- 0,
- 0,
- 1,
- 0,
- tr.elements[2][0],
- tr.elements[2][1],
- 0,
- 1
- };
-
- glMultMatrixf(matrix);
-};
-
-
-RasterizerGLES1::FX::FX() {
-
- bgcolor_active=false;
- bgcolor=Color(0,1,0,1);
-
- skybox_active=false;
-
- glow_active=false;
- glow_passes=4;
- glow_attenuation=0.7;
- glow_bloom=0.0;
-
- antialias_active=true;
- antialias_tolerance=15;
-
- ssao_active=true;
- ssao_attenuation=0.7;
- ssao_radius=0.18;
- ssao_max_distance=1.0;
- ssao_range_min=0.25;
- ssao_range_max=0.48;
- ssao_only=false;
-
-
- fog_active=false;
- fog_near=5;
- fog_far=100;
- fog_attenuation=1.0;
- fog_color_near=Color(1,1,1,1);
- fog_color_far=Color(1,1,1,1);
- fog_bg=false;
-
- toon_active=false;
- toon_treshold=0.4;
- toon_soft=0.001;
-
- edge_active=false;
- edge_color=Color(0,0,0,1);
- edge_size=1.0;
-
-}
-
-static const GLenum prim_type[]={GL_POINTS,GL_LINES,GL_TRIANGLES,GL_TRIANGLE_FAN};
-
-static void _draw_primitive(int p_points, const Vector3 *p_vertices, const Vector3 *p_normals, const Color* p_colors, const Vector3 *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1) {
-
- ERR_FAIL_COND(!p_vertices);
- ERR_FAIL_COND(p_points <1 || p_points>4);
-
- GLenum type = prim_type[p_points - 1];
-
-
- //if (!p_colors) {
- // glColor4f(1, 1, 1, 1);
- //};
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)p_vertices);
-
- if (p_normals) {
-
- glEnableClientState(GL_NORMAL_ARRAY);
- glNormalPointer(GL_FLOAT, 0, (GLvoid*)p_normals);
- };
-
- if (p_colors) {
- glEnableClientState(GL_COLOR_ARRAY);
- glColorPointer(4,GL_FLOAT, 0, p_colors);
- };
-
- if (p_uvs) {
-
- glClientActiveTexture(GL_TEXTURE0);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(3, GL_FLOAT, 0, p_uvs);
- };
-
- glDrawArrays( type, 0, p_points);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-};
-
-/* TEXTURE API */
-#define _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
-#define _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
-#define _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
-#define _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
-#define _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
-#define _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
-#define _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
-#define _EXT_COMPRESSED_RED_RGTC1_EXT 0x8DBB
-#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB
-#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
-#define _EXT_COMPRESSED_RG_RGTC2 0x8DBD
-#define _EXT_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
-#define _EXT_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC
-#define _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
-#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
-#define _EXT_ETC1_RGB8_OES 0x8D64
-
-/* TEXTURE API */
-
-Image RasterizerGLES1::_get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed) {
-
- r_has_alpha_cache=false;
- r_compressed=false;
- Image image=p_image;
-
- switch(p_format) {
-
- case Image::FORMAT_GRAYSCALE: {
- r_gl_components=1;
- r_gl_format=GL_LUMINANCE;
-
- } break;
- case Image::FORMAT_INTENSITY: {
-
- if (!image.empty())
- image.convert(Image::FORMAT_RGBA);
- r_gl_components=4;
- r_gl_format=GL_RGBA;
- r_has_alpha_cache=true;
- } break;
- case Image::FORMAT_GRAYSCALE_ALPHA: {
-
- //image.convert(Image::FORMAT_RGBA);
- r_gl_components=2;
- r_gl_format=GL_LUMINANCE_ALPHA;
- r_has_alpha_cache=true;
- } break;
-
- case Image::FORMAT_INDEXED: {
-
- if (!image.empty())
- image.convert(Image::FORMAT_RGB);
- r_gl_components=3;
- r_gl_format=GL_RGB;
-
- } break;
-
- case Image::FORMAT_INDEXED_ALPHA: {
-
- if (!image.empty())
- image.convert(Image::FORMAT_RGBA);
- r_gl_components=4;
- r_gl_format=GL_RGBA;
- r_has_alpha_cache=true;
-
- } break;
- case Image::FORMAT_RGB: {
-
- r_gl_components=3;
- r_gl_format=GL_RGB;
- } break;
- case Image::FORMAT_RGBA: {
-
- r_gl_components=4;
- r_gl_format=GL_RGBA;
- r_has_alpha_cache=true;
- } break;
- case Image::FORMAT_BC1: {
-
- r_gl_components=1; //doesn't matter much
- r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- r_compressed=true;
-
- } break;
- case Image::FORMAT_BC2: {
- r_gl_components=1; //doesn't matter much
- r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- r_has_alpha_cache=true;
- r_compressed=true;
-
- } break;
- case Image::FORMAT_BC3: {
-
- r_gl_components=1; //doesn't matter much
- r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- r_has_alpha_cache=true;
- r_compressed=true;
-
- } break;
- case Image::FORMAT_BC4: {
-
- r_gl_format=_EXT_COMPRESSED_RED_RGTC1;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
-
- } break;
- case Image::FORMAT_BC5: {
-
- r_gl_format=_EXT_COMPRESSED_RG_RGTC2;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
- } break;
- case Image::FORMAT_PVRTC2: {
-
- if (!pvr_supported) {
-
- if (!image.empty())
- image.decompress();
- r_gl_components=4;
- r_gl_format=GL_RGBA;
- r_has_alpha_cache=true;
- print_line("Load Compat PVRTC2");
-
- } else {
-
- r_gl_format=_EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
- print_line("Load Normal PVRTC2");
- }
-
- } break;
- case Image::FORMAT_PVRTC2_ALPHA: {
-
- if (!pvr_supported) {
-
- if (!image.empty())
- image.decompress();
- r_gl_components=4;
- r_gl_format=GL_RGBA;
- r_has_alpha_cache=true;
- print_line("Load Compat PVRTC2A");
-
- } else {
-
- r_gl_format=_EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
- print_line("Load Normal PVRTC2A");
- }
-
- } break;
- case Image::FORMAT_PVRTC4: {
-
- if (!pvr_supported) {
-
- if (!image.empty())
- image.decompress();
- r_gl_components=4;
- r_gl_format=GL_RGBA;
- r_has_alpha_cache=true;
- print_line("Load Compat PVRTC4");
- } else {
-
- r_gl_format=_EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
- print_line("Load Normal PVRTC4");
- }
-
- } break;
- case Image::FORMAT_PVRTC4_ALPHA: {
-
- if (!pvr_supported) {
-
- if (!image.empty())
- image.decompress();
- r_gl_components=4;
- r_gl_format=GL_RGBA;
- r_has_alpha_cache=true;
- print_line("Load Compat PVRTC4A");
-
- } else {
-
- r_gl_format=_EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
- print_line("Load Normal PVRTC4A");
- }
-
- } break;
- case Image::FORMAT_ETC: {
-
- if (!pvr_supported) {
-
- if (!image.empty())
- image.decompress();
- } else {
-
- r_gl_format=_EXT_ETC1_RGB8_OES;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
- }
-
- } break;
- case Image::FORMAT_YUV_422:
- case Image::FORMAT_YUV_444: {
-
- if (!image.empty())
- image.convert(Image::FORMAT_RGB);
- r_gl_format=GL_RGB;
- r_gl_components=3;
-
- } break;
-
- default: {
-
- ERR_FAIL_V(Image());
- }
- }
-
- return image;
-}
-
-
-RID RasterizerGLES1::texture_create() {
-
- Texture *texture = memnew(Texture);
- ERR_FAIL_COND_V(!texture,RID());
- glGenTextures(1, &texture->tex_id);
- texture->active=false;
- texture->total_data_size=0;
-
- return texture_owner.make_rid( texture );
-
-}
-
-void RasterizerGLES1::texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags) {
-
- bool has_alpha_cache;
- int components;
- GLenum format;
- bool compressed;
-
- int po2_width = nearest_power_of_2(p_width);
- int po2_height = nearest_power_of_2(p_height);
-
- Texture *texture = texture_owner.get( p_texture );
- ERR_FAIL_COND(!texture);
- texture->width=p_width;
- texture->height=p_height;
- texture->format=p_format;
- texture->flags=p_flags;
- texture->target = /*(p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP :*/ GL_TEXTURE_2D;
-
- bool scale_textures = (!npo2_textures_available || p_format&VS::TEXTURE_FLAG_MIPMAPS);
-
-
- if (scale_textures) {
- texture->alloc_width = po2_width;
- texture->alloc_height = po2_height;
- } else {
-
- texture->alloc_width = texture->width;
- texture->alloc_height = texture->height;
- };
-
- _get_gl_image_and_format(Image(),texture->format,texture->flags,format,components,has_alpha_cache,compressed);
-
- texture->gl_components_cache=components;
- texture->gl_format_cache=format;
- texture->format_has_alpha=has_alpha_cache;
- texture->compressed=compressed;
- texture->data_size=0;
-
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(texture->target, texture->tex_id);
-
-
-
-
- if (compressed) {
-
- glTexParameteri( texture->target, GL_GENERATE_MIPMAP, GL_FALSE );
- } else {
- if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS) {
- glTexParameteri( texture->target, GL_GENERATE_MIPMAP, GL_TRUE );
- } else {
- glTexParameteri( texture->target, GL_GENERATE_MIPMAP, GL_FALSE );
- }
-
- }
-
-
- if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS)
- glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
- else
- glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
-
- if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
-
- glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
-
- } else {
-
- glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // raw Filtering
-
- }
- bool force_clamp_to_edge = !(p_flags&VS::TEXTURE_FLAG_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) {
-
- 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 );
- glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- }
-
- texture->active=true;
-}
-
-void RasterizerGLES1::texture_set_data(RID p_texture,const Image& p_image,VS::CubeMapSide p_cube_side) {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND(!texture);
- ERR_FAIL_COND(!texture->active);
- ERR_FAIL_COND(texture->format != p_image.get_format() );
-
- int components;
- GLenum format;
- bool alpha;
- bool compressed;
-
- if (keep_copies && !(texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && !(use_reload_hooks && texture->reloader)) {
- texture->image[p_cube_side]=p_image;
- }
-
-
- Image img = _get_gl_image_and_format(p_image, p_image.get_format(),texture->flags,format,components,alpha,compressed);
- if (texture->alloc_width != img.get_width() || texture->alloc_height != img.get_height()) {
-
- img.resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR);
- };
-
-
- GLenum blit_target = /*(texture->target == GL_TEXTURE_CUBE_MAP)?_cube_side_enum[p_cube_side]:*/GL_TEXTURE_2D;
-
- texture->data_size=img.get_data().size();
- DVector<uint8_t>::Read read = img.get_data().read();
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(texture->target, texture->tex_id);
-
- int mipmaps=(texture->flags&VS::TEXTURE_FLAG_MIPMAPS && img.get_mipmaps()>0) ? img.get_mipmaps() +1 : 1;
-
- int w=img.get_width();
- int h=img.get_height();
-
- int tsize=0;
- for(int i=0;i<mipmaps;i++) {
-
- int size,ofs;
- img.get_mipmap_offset_and_size(i,ofs,size);
-
- if (texture->compressed) {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glCompressedTexImage2D( blit_target, i, format,w,h,0,size,&read[ofs] );
-
- } else {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-// glTexImage2D(blit_target, i, format==GL_RGB?GL_RGB8:format, w, h, 0, format, GL_UNSIGNED_BYTE,&read[ofs]);
- glTexImage2D(blit_target, i, format, w, h, 0, format, GL_UNSIGNED_BYTE,&read[ofs]);
- //glTexSubImage2D( blit_target, i, 0,0,w,h,format,GL_UNSIGNED_BYTE,&read[ofs] );
- }
- tsize+=size;
-
- w = MAX(1,w>>1);
- h = MAX(1,h>>1);
-
- }
-
- _rinfo.texture_mem-=texture->total_data_size;
- texture->total_data_size=tsize;
- _rinfo.texture_mem+=texture->total_data_size;
-
- printf("texture: %i x %i - size: %i - total: %i\n",texture->width,texture->height,tsize,_rinfo.texture_mem);
-
-
- if (mipmaps==1 && texture->flags&VS::TEXTURE_FLAG_MIPMAPS) {
- glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
-
- } else {
- glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE );
-
- }
-
- if (mipmaps>1) {
-
- //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmaps-1 ); - assumed to have all, always
- }
-
- //texture_set_flags(p_texture,texture->flags);
-
-
-}
-
-Image RasterizerGLES1::texture_get_data(RID p_texture,VS::CubeMapSide p_cube_side) const {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND_V(!texture,Image());
- ERR_FAIL_COND_V(!texture->active,Image());
-
- return texture->image[p_cube_side];
-#if 0
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND_V(!texture,Image());
- ERR_FAIL_COND_V(!texture->active,Image());
- ERR_FAIL_COND_V(texture->data_size==0,Image());
-
- DVector<uint8_t> data;
- GLenum format,type=GL_UNSIGNED_BYTE;
- Image::Format fmt;
- int pixelsize=0;
- int pixelshift=0;
- int minw=1,minh=1;
- bool compressed=false;
-
- fmt=texture->format;
-
- switch(texture->format) {
-
- case Image::FORMAT_GRAYSCALE: {
-
- format=GL_LUMINANCE;
- type=GL_UNSIGNED_BYTE;
- data.resize(texture->alloc_width*texture->alloc_height);
- pixelsize=1;
-
- } break;
- case Image::FORMAT_INTENSITY: {
- return Image();
- } break;
- case Image::FORMAT_GRAYSCALE_ALPHA: {
-
- format=GL_LUMINANCE_ALPHA;
- type=GL_UNSIGNED_BYTE;
- pixelsize=2;
-
- } break;
- case Image::FORMAT_RGB: {
- format=GL_RGB;
- type=GL_UNSIGNED_BYTE;
- pixelsize=3;
- } break;
- case Image::FORMAT_RGBA: {
-
- format=GL_RGBA;
- type=GL_UNSIGNED_BYTE;
- pixelsize=4;
- } break;
- case Image::FORMAT_INDEXED: {
-
- format=GL_RGB;
- type=GL_UNSIGNED_BYTE;
- fmt=Image::FORMAT_RGB;
- pixelsize=3;
- } break;
- case Image::FORMAT_INDEXED_ALPHA: {
-
- format=GL_RGBA;
- type=GL_UNSIGNED_BYTE;
- fmt=Image::FORMAT_RGBA;
- pixelsize=4;
-
- } break;
- case Image::FORMAT_BC1: {
-
- pixelsize=1; //doesn't matter much
- format=GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- compressed=true;
- pixelshift=1;
- minw=minh=4;
-
- } break;
- case Image::FORMAT_BC2: {
- pixelsize=1; //doesn't matter much
- format=GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- compressed=true;
- minw=minh=4;
-
- } break;
- case Image::FORMAT_BC3: {
-
- pixelsize=1; //doesn't matter much
- format=GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- compressed=true;
- minw=minh=4;
-
- } break;
- case Image::FORMAT_BC4: {
-
- format=GL_COMPRESSED_RED_RGTC1;
- pixelsize=1; //doesn't matter much
- compressed=true;
- pixelshift=1;
- minw=minh=4;
-
- } break;
- case Image::FORMAT_BC5: {
-
- format=GL_COMPRESSED_RG_RGTC2;
- pixelsize=1; //doesn't matter much
- compressed=true;
- minw=minh=4;
-
- } break;
-
- default:{}
- }
-
- data.resize(texture->data_size);
- DVector<uint8_t>::Write wb = data.write();
-
- glActiveTexture(GL_TEXTURE0);
- int ofs=0;
- glBindTexture(texture->target,texture->tex_id);
-
- int w=texture->alloc_width;
- int h=texture->alloc_height;
- for(int i=0;i<texture->mipmaps+1;i++) {
-
- if (compressed) {
-
- glPixelStorei(GL_PACK_ALIGNMENT, 4);
- glGetCompressedTexImage(texture->target,i,&wb[ofs]);
-
- } else {
- glPixelStorei(GL_PACK_ALIGNMENT, 1);
- glGetTexImage(texture->target,i,format,type,&wb[ofs]);
- }
-
- int size = (w*h*pixelsize)>>pixelshift;
- ofs+=size;
-
- w=MAX(minw,w>>1);
- h=MAX(minh,h>>1);
-
- }
-
-
- wb=DVector<uint8_t>::Write();
-
- Image img(texture->alloc_width,texture->alloc_height,texture->mipmaps,fmt,data);
-
- if (texture->format<Image::FORMAT_INDEXED && (texture->alloc_width!=texture->width || texture->alloc_height!=texture->height))
- img.resize(texture->width,texture->height);
-
- return img;
-#endif
-}
-
-void RasterizerGLES1::texture_set_flags(RID p_texture,uint32_t p_flags) {
-
- Texture *texture = texture_owner.get( p_texture );
- ERR_FAIL_COND(!texture);
-
- 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) && (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) {
-
- 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 );
- glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
-
- }
-
-
- if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
-
- glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
- if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS)
- glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
- else
- glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
-
- } else {
-
- glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // nearest
- }
-}
-uint32_t RasterizerGLES1::texture_get_flags(RID p_texture) const {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND_V(!texture,0);
-
- return texture->flags;
-
-}
-Image::Format RasterizerGLES1::texture_get_format(RID p_texture) const {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND_V(!texture,Image::FORMAT_GRAYSCALE);
-
- return texture->format;
-}
-uint32_t RasterizerGLES1::texture_get_width(RID p_texture) const {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND_V(!texture,0);
-
- return texture->width;
-}
-uint32_t RasterizerGLES1::texture_get_height(RID p_texture) const {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND_V(!texture,0);
-
- return texture->height;
-}
-
-bool RasterizerGLES1::texture_has_alpha(RID p_texture) const {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND_V(!texture,0);
-
- return false;
-
-}
-
-void RasterizerGLES1::texture_set_size_override(RID p_texture,int p_width, int p_height) {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND(!texture);
-
- ERR_FAIL_COND(p_width<=0 || p_width>4096);
- ERR_FAIL_COND(p_height<=0 || p_height>4096);
- //real texture size is in alloc width and height
- texture->width=p_width;
- texture->height=p_height;
-
-}
-
-void RasterizerGLES1::texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const {
-
- Texture * texture = texture_owner.get(p_texture);
-
- ERR_FAIL_COND(!texture);
-
- texture->reloader=p_owner;
- texture->reloader_func=p_function;
- if (use_reload_hooks && p_owner && keep_copies) {
-
- for(int i=0;i<6;i++)
- texture->image[i]=Image();
- }
-
-
-}
-
-/* SHADER API */
-
-/* SHADER API */
-
-RID RasterizerGLES1::shader_create(VS::ShaderMode p_mode) {
-
- Shader *shader = memnew( Shader );
- shader->mode=p_mode;
- shader->valid=false;
- shader->has_alpha=false;
- shader->fragment_line=0;
- shader->vertex_line=0;
- shader->light_line=0;
- RID rid = shader_owner.make_rid(shader);
- shader_set_mode(rid,p_mode);
-// _shader_make_dirty(shader);
-
- return rid;
-
-}
-
-
-
-void RasterizerGLES1::shader_set_mode(RID p_shader,VS::ShaderMode p_mode) {
-
- ERR_FAIL_INDEX(p_mode,3);
- Shader *shader=shader_owner.get(p_shader);
- ERR_FAIL_COND(!shader);
-// if (shader->custom_code_id && p_mode==shader->mode)
-// return;
-
- shader->mode=p_mode;
-
-}
-VS::ShaderMode RasterizerGLES1::shader_get_mode(RID p_shader) const {
-
- Shader *shader=shader_owner.get(p_shader);
- ERR_FAIL_COND_V(!shader,VS::SHADER_MATERIAL);
- return shader->mode;
-}
-
-
-
-void RasterizerGLES1::shader_set_code(RID p_shader, const String& p_vertex, const String& p_fragment,const String& p_light,int p_vertex_ofs,int p_fragment_ofs,int p_light_ofs) {
-
-
- Shader *shader=shader_owner.get(p_shader);
- ERR_FAIL_COND(!shader);
-
-#ifdef DEBUG_ENABLED
- if (shader->vertex_code==p_vertex && shader->fragment_code==p_fragment && shader->light_code==p_light)
- return;
-#endif
- shader->fragment_code=p_fragment;
- shader->vertex_code=p_vertex;
- shader->light_code=p_light;
- shader->fragment_line=p_fragment_ofs;
- shader->vertex_line=p_vertex_ofs;
- shader->light_line=p_light_ofs;
-
-}
-
-String RasterizerGLES1::shader_get_vertex_code(RID p_shader) const {
-
- Shader *shader=shader_owner.get(p_shader);
- ERR_FAIL_COND_V(!shader,String());
- return shader->vertex_code;
-
-}
-
-String RasterizerGLES1::shader_get_fragment_code(RID p_shader) const {
-
- Shader *shader=shader_owner.get(p_shader);
- ERR_FAIL_COND_V(!shader,String());
- return shader->fragment_code;
-
-}
-
-String RasterizerGLES1::shader_get_light_code(RID p_shader) const {
-
- Shader *shader=shader_owner.get(p_shader);
- ERR_FAIL_COND_V(!shader,String());
- return shader->light_code;
-
-}
-
-void RasterizerGLES1::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
-
- Shader *shader=shader_owner.get(p_shader);
- ERR_FAIL_COND(!shader);
-#if 0
-
- if (shader->dirty_list.in_list())
- _update_shader(shader); // ok should be not anymore dirty
-
-
- Map<int,StringName> order;
-
-
- for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
-
-
- order[E->get().order]=E->key();
- }
-
-
- for(Map<int,StringName>::Element *E=order.front();E;E=E->next()) {
-
- PropertyInfo pi;
- ShaderLanguage::Uniform &u=shader->uniforms[E->get()];
- pi.name=E->get();
- switch(u.type) {
-
- case ShaderLanguage::TYPE_VOID:
- case ShaderLanguage::TYPE_BOOL:
- case ShaderLanguage::TYPE_FLOAT:
- case ShaderLanguage::TYPE_VEC2:
- case ShaderLanguage::TYPE_VEC3:
- case ShaderLanguage::TYPE_MAT3:
- case ShaderLanguage::TYPE_MAT4:
- case ShaderLanguage::TYPE_VEC4:
- pi.type=u.default_value.get_type();
- break;
- case ShaderLanguage::TYPE_TEXTURE:
- pi.type=Variant::_RID;
- pi.hint=PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string="Texture";
- break;
- case ShaderLanguage::TYPE_CUBEMAP:
- pi.type=Variant::_RID;
- pi.hint=PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string="Texture";
- break;
- };
-
- p_param_list->push_back(pi);
-
- }
-#endif
-
-}
-
-/* COMMON MATERIAL API */
-
-
-RID RasterizerGLES1::material_create() {
-
- return material_owner.make_rid( memnew( Material ) );
-}
-
-void RasterizerGLES1::material_set_shader(RID p_material, RID p_shader) {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND(!material);
- material->shader=p_shader;
-
-}
-
-RID RasterizerGLES1::material_get_shader(RID p_material) const {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND_V(!material,RID());
- return material->shader;
-}
-
-#if 0
-
-void RasterizerGLES1::_material_check_alpha(Material *p_material) {
-
- p_material->has_alpha=false;
- Color diffuse=p_material->parameters[VS::FIXED_MATERIAL_PARAM_DIFFUSE];
- if (diffuse.a<0.98) {
-
- p_material->has_alpha=true;
- return;
- }
-
- if (p_material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE].is_valid()) {
-
- Texture *tex = texture_owner.get(p_material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE]);
- if (!tex)
- return;
- if (tex->has_alpha) {
-
- p_material->has_alpha=true;
- return;
- }
- }
-}
-
-#endif
-void RasterizerGLES1::material_set_param(RID p_material, const StringName& p_param, const Variant& p_value) {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND(!material);
-
- if (p_value.get_type()==Variant::NIL)
- material->shader_params.erase(p_param);
- else
- material->shader_params[p_param]=p_value;
-}
-Variant RasterizerGLES1::material_get_param(RID p_material, const StringName& p_param) const {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND_V(!material,Variant());
-
- if (material->shader_params.has(p_param))
- return material->shader_params[p_param];
- else
- return Variant();
-}
-
-
-void RasterizerGLES1::material_set_flag(RID p_material, VS::MaterialFlag p_flag,bool p_enabled) {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND(!material);
- ERR_FAIL_INDEX(p_flag,VS::MATERIAL_FLAG_MAX);
- material->flags[p_flag]=p_enabled;
-
-}
-bool RasterizerGLES1::material_get_flag(RID p_material,VS::MaterialFlag p_flag) const {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND_V(!material,false);
- ERR_FAIL_INDEX_V(p_flag,VS::MATERIAL_FLAG_MAX,false);
- return material->flags[p_flag];
-
-
-}
-
-void RasterizerGLES1::material_set_depth_draw_mode(RID p_material, VS::MaterialDepthDrawMode p_mode) {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND(!material);
- material->depth_draw_mode=p_mode;
-}
-
-VS::MaterialDepthDrawMode RasterizerGLES1::material_get_depth_draw_mode(RID p_material) const{
-
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND_V(!material,VS::MATERIAL_DEPTH_DRAW_ALWAYS);
- return material->depth_draw_mode;
-}
-
-
-void RasterizerGLES1::material_set_blend_mode(RID p_material,VS::MaterialBlendMode p_mode) {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND(!material);
- material->blend_mode=p_mode;
-
-}
-VS::MaterialBlendMode RasterizerGLES1::material_get_blend_mode(RID p_material) const {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND_V(!material,VS::MATERIAL_BLEND_MODE_ADD);
- return material->blend_mode;
-}
-
-void RasterizerGLES1::material_set_line_width(RID p_material,float p_line_width) {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND(!material);
- material->line_width=p_line_width;
-
-}
-float RasterizerGLES1::material_get_line_width(RID p_material) const {
-
- Material *material = material_owner.get(p_material);
- ERR_FAIL_COND_V(!material,0);
-
- return material->line_width;
-}
-
-/* FIXED MATERIAL */
-
-
-RID RasterizerGLES1::fixed_material_create() {
-
- return material_create();
-}
-
-void RasterizerGLES1::fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags p_flag, bool p_enabled) {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND(!m);
- ERR_FAIL_INDEX(p_flag, 3);
- m->fixed_flags[p_flag]=p_enabled;
-}
-
-bool RasterizerGLES1::fixed_material_get_flag(RID p_material, VS::FixedMaterialFlags p_flag) const {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND_V(!m,false);
- ERR_FAIL_INDEX_V(p_flag,VS::FIXED_MATERIAL_FLAG_MAX, false);
- return m->fixed_flags[p_flag];
-}
-
-void RasterizerGLES1::fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value) {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND(!m);
- ERR_FAIL_INDEX(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX);
-
- m->parameters[p_parameter] = p_value;
-
-}
-
-Variant RasterizerGLES1::fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND_V(!m, Variant());
- ERR_FAIL_INDEX_V(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX, Variant());
-
- return m->parameters[p_parameter];
-}
-
-void RasterizerGLES1::fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture) {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND(!m);
- ERR_FAIL_INDEX(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX);
-
- m->textures[p_parameter] = p_texture;
-
-}
-RID RasterizerGLES1::fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND_V(!m, RID());
- ERR_FAIL_INDEX_V(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX, Variant());
-
- return m->textures[p_parameter];
-}
-
-
-void RasterizerGLES1::fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode) {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND(!m);
- ERR_FAIL_INDEX(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX);
- ERR_FAIL_INDEX(p_mode,4);
-
- m->texcoord_mode[p_parameter] = p_mode;
-}
-
-VS::FixedMaterialTexCoordMode RasterizerGLES1::fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND_V(!m, VS::FIXED_MATERIAL_TEXCOORD_UV);
- ERR_FAIL_INDEX_V(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX, VS::FIXED_MATERIAL_TEXCOORD_UV);
-
- return m->texcoord_mode[p_parameter]; // for now
-}
-
-void RasterizerGLES1::fixed_material_set_uv_transform(RID p_material,const Transform& p_transform) {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND(!m);
-
- m->uv_transform = p_transform;
-}
-
-Transform RasterizerGLES1::fixed_material_get_uv_transform(RID p_material) const {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND_V(!m, Transform());
-
- return m->uv_transform;
-}
-
-void RasterizerGLES1::fixed_material_set_point_size(RID p_material,float p_size) {
-
- Material *m=material_owner.get( p_material );
- ERR_FAIL_COND(!m);
- m->point_size=p_size;
-
-}
-float RasterizerGLES1::fixed_material_get_point_size(RID p_material) const {
-
- const Material *m=material_owner.get( p_material );
- ERR_FAIL_COND_V(!m, 0);
- return m->point_size;
-}
-
-
-/* MESH API */
-
-
-RID RasterizerGLES1::mesh_create() {
-
-
- return mesh_owner.make_rid( memnew( Mesh ) );
-}
-
-
-
-void RasterizerGLES1::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,bool p_alpha_sort) {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND(!mesh);
-
- ERR_FAIL_INDEX( p_primitive, VS::PRIMITIVE_MAX );
- ERR_FAIL_COND(p_arrays.size()!=VS::ARRAY_MAX);
-
- uint32_t format=0;
-
- // validation
- int index_array_len=0;
- int array_len=0;
-
- for(int i=0;i<p_arrays.size();i++) {
-
- if (p_arrays[i].get_type()==Variant::NIL)
- continue;
-
- format|=(1<<i);
-
- if (i==VS::ARRAY_VERTEX) {
-
- array_len=Vector3Array(p_arrays[i]).size();
- ERR_FAIL_COND(array_len==0);
- } else if (i==VS::ARRAY_INDEX) {
-
- index_array_len=IntArray(p_arrays[i]).size();
- }
- }
-
- ERR_FAIL_COND((format&VS::ARRAY_FORMAT_VERTEX)==0); // mandatory
-
-
- Surface *surface = memnew( Surface );
- ERR_FAIL_COND( !surface );
-
- bool use_VBO=true; //glGenBuffersARB!=NULL; // TODO detect if it's in there
- if (format&VS::ARRAY_FORMAT_WEIGHTS || mesh->morph_target_count>0) {
-
- use_VBO=false;
- }
-
- surface->packed=pack_arrays && use_VBO;
-
- int total_elem_size=0;
-
- for (int i=0;i<VS::ARRAY_MAX;i++) {
-
-
- Surface::ArrayData&ad=surface->array[i];
- ad.size=0;
- ad.ofs=0;
- int elem_size=0;
- int elem_count=0;
- bool valid_local=true;
- GLenum datatype;
- bool normalize=false;
- bool bind=false;
-
- if (!(format&(1<<i))) // no array
- continue;
-
-
- switch(i) {
-
- case VS::ARRAY_VERTEX: {
-
- if (surface->packed) {
- elem_size=3*sizeof(int16_t); // vertex
- datatype=GL_SHORT;
- normalize=true;
-
- } else {
- elem_size=3*sizeof(GLfloat); // vertex
- datatype=GL_FLOAT;
- }
- bind=true;
- elem_count=3;
-
- } break;
- case VS::ARRAY_NORMAL: {
-
- if (surface->packed) {
- elem_size=3*sizeof(int8_t); // vertex
- datatype=GL_BYTE;
- normalize=true;
- } else {
- elem_size=3*sizeof(GLfloat); // vertex
- datatype=GL_FLOAT;
- }
- bind=true;
- elem_count=3;
- } break;
- case VS::ARRAY_TANGENT: {
- if (surface->packed) {
- elem_size=4*sizeof(int8_t); // vertex
- datatype=GL_BYTE;
- normalize=true;
- } else {
- elem_size=4*sizeof(GLfloat); // vertex
- datatype=GL_FLOAT;
- }
- bind=true;
- elem_count=4;
-
- } break;
- case VS::ARRAY_COLOR: {
-
- elem_size=4*sizeof(uint8_t); /* RGBA */
- datatype=GL_UNSIGNED_BYTE;
- elem_count=4;
- bind=true;
- normalize=true;
- } break;
- case VS::ARRAY_TEX_UV:
- case VS::ARRAY_TEX_UV2: {
- if (surface->packed) {
- elem_size=2*sizeof(int16_t); // vertex
- datatype=GL_SHORT;
- normalize=true;
- } else {
- elem_size=2*sizeof(GLfloat); // vertex
- datatype=GL_FLOAT;
- }
- bind=true;
- elem_count=2;
-
- } break;
- case VS::ARRAY_WEIGHTS: {
-
- elem_size=VS::ARRAY_WEIGHTS_SIZE*sizeof(GLfloat);
- elem_count=VS::ARRAY_WEIGHTS_SIZE;
- valid_local=false;
- datatype=GL_FLOAT;
-
- } break;
- case VS::ARRAY_BONES: {
-
- elem_size=VS::ARRAY_WEIGHTS_SIZE*sizeof(GLuint);
- elem_count=VS::ARRAY_WEIGHTS_SIZE;
- valid_local=false;
- datatype=GL_FLOAT;
-
-
- } break;
- case VS::ARRAY_INDEX: {
-
- if (index_array_len<=0) {
- ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
- break;
- }
- /* determine wether using 16 or 32 bits indices */
- elem_size=2;
- datatype=GL_UNSIGNED_SHORT;
-
-/*
- if (use_VBO) {
-
- glGenBuffers(1,&surface->index_id);
- ERR_FAIL_COND(surface->index_id==0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER,index_array_len*elem_size,NULL,GL_STATIC_DRAW);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
- } else {
- surface->index_array_local = (uint8_t*)memalloc(index_array_len*elem_size);
- };
-*/
- surface->index_array_len=index_array_len; // only way it can exist
- ad.ofs=0;
- ad.size=elem_size;
-
-
- continue;
- } break;
- default: {
- ERR_FAIL( );
- }
- }
-
- ad.ofs=total_elem_size;
- ad.size=elem_size;
- ad.datatype=datatype;
- ad.normalize=normalize;
- ad.bind=bind;
- ad.count=elem_count;
- total_elem_size+=elem_size;
- if (valid_local) {
- surface->local_stride+=elem_size;
- surface->morph_format|=(1<<i);
- }
-
-
- }
-
- surface->stride=total_elem_size;
- surface->array_len=array_len;
- surface->format=format;
- surface->primitive=p_primitive;
- surface->configured_format=0;
- if (keep_copies) {
- surface->data=p_arrays;
- surface->morph_data=p_blend_shapes;
- }
-
- uint8_t *array_ptr=NULL;
- uint8_t *index_array_ptr=NULL;
- DVector<uint8_t> array_pre_vbo;
- DVector<uint8_t>::Write vaw;
- DVector<uint8_t> index_array_pre_vbo;
- DVector<uint8_t>::Write iaw;
-
- /* create pointers */
- if (use_VBO) {
-
- array_pre_vbo.resize(surface->array_len*surface->stride);
- vaw = array_pre_vbo.write();
- array_ptr=vaw.ptr();
-
- if (surface->index_array_len) {
-
- index_array_pre_vbo.resize(surface->index_array_len*surface->array[VS::ARRAY_INDEX].size);
- iaw = index_array_pre_vbo.write();
- index_array_ptr=iaw.ptr();
- }
- } else {
-
- surface->array_local = (uint8_t*)memalloc(surface->array_len*surface->stride);
- array_ptr=(uint8_t*)surface->array_local;
- if (surface->index_array_len) {
- surface->index_array_local = (uint8_t*)memalloc(index_array_len*surface->array[VS::ARRAY_INDEX].size);
- index_array_ptr=(uint8_t*)surface->index_array_local;
- }
- }
-
-
-
- _surface_set_arrays(surface,array_ptr,index_array_ptr,p_arrays,true);
-
-
- /* create buffers!! */
- if (use_VBO) {
- glGenBuffers(1,&surface->vertex_id);
- ERR_FAIL_COND(surface->vertex_id==0);
- glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
- glBufferData(GL_ARRAY_BUFFER,surface->array_len*surface->stride,array_ptr,GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
- if (surface->index_array_len) {
-
- glGenBuffers(1,&surface->index_id);
- ERR_FAIL_COND(surface->index_id==0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER,index_array_len*surface->array[VS::ARRAY_INDEX].size,index_array_ptr,GL_STATIC_DRAW);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
-
- }
- }
-
- mesh->surfaces.push_back(surface);
-
-}
-
-Error RasterizerGLES1::_surface_set_arrays(Surface *p_surface, uint8_t *p_mem,uint8_t *p_index_mem,const Array& p_arrays,bool p_main) {
-
- uint32_t stride = p_main ? p_surface->stride : p_surface->local_stride;
-
- for(int ai=0;ai<VS::ARRAY_MAX;ai++) {
- if (ai>=p_arrays.size())
- break;
- if (p_arrays[ai].get_type()==Variant::NIL)
- continue;
- Surface::ArrayData &a=p_surface->array[ai];
-
- switch(ai) {
-
-
- case VS::ARRAY_VERTEX: {
-
- ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY, ERR_INVALID_PARAMETER );
-
- DVector<Vector3> array = p_arrays[ai];
- ERR_FAIL_COND_V( array.size() != p_surface->array_len, ERR_INVALID_PARAMETER );
-
-
- DVector<Vector3>::Read read = array.read();
- const Vector3* src=read.ptr();
-
- // setting vertices means regenerating the AABB
- AABB aabb;
-
- float scale=1;
- float max=0;
-
-
- for (int i=0;i<p_surface->array_len;i++) {
-
-
- GLfloat vector[3]={ src[i].x, src[i].y, src[i].z };
-
- copymem(&p_mem[a.ofs+i*stride], vector, a.size);
-
- if (i==0) {
-
- aabb=AABB(src[i],Vector3());
- } else {
-
- aabb.expand_to( src[i] );
- }
- }
-
- if (p_main) {
- p_surface->aabb=aabb;
- p_surface->vertex_scale=scale;
- }
-
-
- } break;
- case VS::ARRAY_NORMAL: {
-
- ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY, ERR_INVALID_PARAMETER );
-
- DVector<Vector3> array = p_arrays[ai];
- ERR_FAIL_COND_V( array.size() != p_surface->array_len, ERR_INVALID_PARAMETER );
-
-
- DVector<Vector3>::Read read = array.read();
- const Vector3* src=read.ptr();
-
- // setting vertices means regenerating the AABB
-
- for (int i=0;i<p_surface->array_len;i++) {
-
-
- GLfloat vector[3]={ src[i].x, src[i].y, src[i].z };
- copymem(&p_mem[a.ofs+i*stride], vector, a.size);
-
- }
-
-
- } break;
- case VS::ARRAY_TANGENT: {
-
- ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
-
- DVector<real_t> array = p_arrays[ai];
-
- ERR_FAIL_COND_V( array.size() != p_surface->array_len*4, ERR_INVALID_PARAMETER );
-
-
- DVector<real_t>::Read read = array.read();
- const real_t* src = read.ptr();
-
- for (int i=0;i<p_surface->array_len;i++) {
-
- GLfloat xyzw[4]={
- src[i*4+0],
- src[i*4+1],
- src[i*4+2],
- src[i*4+3]
- };
-
- copymem(&p_mem[a.ofs+i*stride], xyzw, a.size);
-
- }
-
- } break;
- case VS::ARRAY_COLOR: {
-
- ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::COLOR_ARRAY, ERR_INVALID_PARAMETER );
-
-
- DVector<Color> array = p_arrays[ai];
-
- ERR_FAIL_COND_V( array.size() != p_surface->array_len, ERR_INVALID_PARAMETER );
-
-
- DVector<Color>::Read read = array.read();
- const Color* src = read.ptr();
- bool alpha=false;
-
- for (int i=0;i<p_surface->array_len;i++) {
-
- if (src[i].a<0.98) // tolerate alpha a bit, for crappy exporters
- alpha=true;
-
- uint8_t colors[4];
-
- for(int j=0;j<4;j++) {
-
- colors[j]=CLAMP( int((src[i][j])*255.0), 0,255 );
- }
-
- copymem(&p_mem[a.ofs+i*stride], colors, a.size);
-
- }
-
- if (p_main)
- p_surface->has_alpha=alpha;
-
- } break;
- case VS::ARRAY_TEX_UV:
- case VS::ARRAY_TEX_UV2: {
-
- ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::VECTOR2_ARRAY, ERR_INVALID_PARAMETER );
-
- DVector<Vector2> array = p_arrays[ai];
-
- ERR_FAIL_COND_V( array.size() != p_surface->array_len , ERR_INVALID_PARAMETER);
-
- DVector<Vector2>::Read read = array.read();
-
- const Vector2 * src=read.ptr();
- float scale=1.0;
-
-
- for (int i=0;i<p_surface->array_len;i++) {
-
- GLfloat uv[2]={ src[i].x , src[i].y };
-
- copymem(&p_mem[a.ofs+i*stride], uv, a.size);
-
- }
-
- if (p_main) {
-
- if (ai==VS::ARRAY_TEX_UV) {
-
- p_surface->uv_scale=scale;
- }
- if (ai==VS::ARRAY_TEX_UV2) {
-
- p_surface->uv2_scale=scale;
- }
- }
-
- } break;
- case VS::ARRAY_BONES:
- case VS::ARRAY_WEIGHTS: {
-
-
- ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
-
- DVector<real_t> array = p_arrays[ai];
-
- ERR_FAIL_COND_V( array.size() != p_surface->array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER );
-
-
- DVector<real_t>::Read read = array.read();
-
- const real_t * src = read.ptr();
-
- p_surface->max_bone=0;
-
- for (int i=0;i<p_surface->array_len;i++) {
-
- GLfloat data[VS::ARRAY_WEIGHTS_SIZE];
- for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
- data[j]=src[i*VS::ARRAY_WEIGHTS_SIZE+j];
- if (ai==VS::ARRAY_BONES) {
-
- p_surface->max_bone=MAX(data[j],p_surface->max_bone);
- }
- }
-
- copymem(&p_mem[a.ofs+i*stride], data, a.size);
-
-
- }
-
- } break;
- case VS::ARRAY_INDEX: {
-
- ERR_FAIL_COND_V( p_surface->index_array_len<=0, ERR_INVALID_DATA );
- ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::INT_ARRAY, ERR_INVALID_PARAMETER );
-
- DVector<int> indices = p_arrays[ai];
- ERR_FAIL_COND_V( indices.size() == 0, ERR_INVALID_PARAMETER );
- ERR_FAIL_COND_V( indices.size() != p_surface->index_array_len, ERR_INVALID_PARAMETER );
-
- /* determine wether using 16 or 32 bits indices */
-
- DVector<int>::Read read = indices.read();
- const int *src=read.ptr();
-
- for (int i=0;i<p_surface->index_array_len;i++) {
-
-
- if (a.size==2) {
- uint16_t v=src[i];
-
- copymem(&p_index_mem[i*a.size], &v, a.size);
- } else {
- uint32_t v=src[i];
-
- copymem(&p_index_mem[i*a.size], &v, a.size);
- }
- }
-
-
- } break;
-
-
- default: { ERR_FAIL_V(ERR_INVALID_PARAMETER);}
- }
-
- p_surface->configured_format|=(1<<ai);
- }
-
- return OK;
-}
-
-
-
-void RasterizerGLES1::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) {
-
- ERR_EXPLAIN("OpenGL Rasterizer does not support custom surfaces. Running on wrong platform?");
- ERR_FAIL_V();
-}
-
-Array RasterizerGLES1::mesh_get_surface_arrays(RID p_mesh,int p_surface) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,Array());
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Array() );
- Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND_V( !surface, Array() );
-
- return surface->data;
-
-
-}
-Array RasterizerGLES1::mesh_get_surface_morph_arrays(RID p_mesh,int p_surface) const{
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,Array());
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Array() );
- Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND_V( !surface, Array() );
-
- return surface->morph_data;
-
-}
-
-
-void RasterizerGLES1::mesh_set_morph_target_count(RID p_mesh,int p_amount) {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND(!mesh);
- ERR_FAIL_COND( mesh->surfaces.size()!=0 );
-
- mesh->morph_target_count=p_amount;
-
-}
-
-int RasterizerGLES1::mesh_get_morph_target_count(RID p_mesh) const{
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,-1);
-
- return mesh->morph_target_count;
-
-}
-
-void RasterizerGLES1::mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode) {
-
- ERR_FAIL_INDEX(p_mode,2);
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND(!mesh);
-
- mesh->morph_target_mode=p_mode;
-
-}
-
-VS::MorphTargetMode RasterizerGLES1::mesh_get_morph_target_mode(RID p_mesh) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,VS::MORPH_MODE_NORMALIZED);
-
- return mesh->morph_target_mode;
-
-}
-
-
-
-void RasterizerGLES1::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material,bool p_owned) {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND(!mesh);
- ERR_FAIL_INDEX(p_surface, mesh->surfaces.size() );
- Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND( !surface);
-
- if (surface->material_owned && surface->material.is_valid())
- free(surface->material);
-
- surface->material_owned=p_owned;
-
- surface->material=p_material;
-}
-
-RID RasterizerGLES1::mesh_surface_get_material(RID p_mesh, int p_surface) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,RID());
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RID() );
- Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND_V( !surface, RID() );
-
- return surface->material;
-}
-
-int RasterizerGLES1::mesh_surface_get_array_len(RID p_mesh, int p_surface) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,-1);
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 );
- Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND_V( !surface, -1 );
-
- return surface->array_len;
-}
-int RasterizerGLES1::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,-1);
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 );
- Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND_V( !surface, -1 );
-
- return surface->index_array_len;
-}
-uint32_t RasterizerGLES1::mesh_surface_get_format(RID p_mesh, int p_surface) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,0);
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0 );
- Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND_V( !surface, 0 );
-
- return surface->format;
-}
-VS::PrimitiveType RasterizerGLES1::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,VS::PRIMITIVE_POINTS);
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), VS::PRIMITIVE_POINTS );
- Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND_V( !surface, VS::PRIMITIVE_POINTS );
-
- return surface->primitive;
-}
-
-void RasterizerGLES1::mesh_remove_surface(RID p_mesh,int p_index) {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND(!mesh);
- ERR_FAIL_INDEX(p_index, mesh->surfaces.size() );
- Surface *surface = mesh->surfaces[p_index];
- ERR_FAIL_COND( !surface);
-
- if (mesh->morph_target_count) {
- for(int i=0;i<mesh->morph_target_count;i++)
- memfree(surface->morph_targets_local[i].array);
- memfree( surface->morph_targets_local );
- }
-
- memdelete( mesh->surfaces[p_index] );
- mesh->surfaces.remove(p_index);
-
-}
-int RasterizerGLES1::mesh_get_surface_count(RID p_mesh) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,-1);
-
- return mesh->surfaces.size();
-}
-
-AABB RasterizerGLES1::mesh_get_aabb(RID p_mesh) const {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,AABB());
-
- if (mesh->custom_aabb!=AABB())
- return mesh->custom_aabb;
-
- AABB aabb;
-
- for (int i=0;i<mesh->surfaces.size();i++) {
-
- if (i==0)
- aabb=mesh->surfaces[i]->aabb;
- else
- aabb.merge_with(mesh->surfaces[i]->aabb);
- }
-
- return aabb;
-}
-
-void RasterizerGLES1::mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb) {
-
- Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND(!mesh);
-
- mesh->custom_aabb=p_aabb;
-
-}
-
-AABB RasterizerGLES1::mesh_get_custom_aabb(RID p_mesh) const {
-
- const Mesh *mesh = mesh_owner.get( p_mesh );
- ERR_FAIL_COND_V(!mesh,AABB());
-
- return mesh->custom_aabb;
-}
-
-
-/* MULTIMESH API */
-
-RID RasterizerGLES1::multimesh_create() {
-
- return multimesh_owner.make_rid( memnew( MultiMesh ));
-}
-
-void RasterizerGLES1::multimesh_set_instance_count(RID p_multimesh,int p_count) {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND(!multimesh);
-
- multimesh->elements.clear(); // make sure to delete everything, so it "fails" in all implementations
- multimesh->elements.resize(p_count);
-
-}
-int RasterizerGLES1::multimesh_get_instance_count(RID p_multimesh) const {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND_V(!multimesh,-1);
-
- return multimesh->elements.size();
-}
-
-void RasterizerGLES1::multimesh_set_mesh(RID p_multimesh,RID p_mesh) {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND(!multimesh);
-
- multimesh->mesh=p_mesh;
-
-}
-void RasterizerGLES1::multimesh_set_aabb(RID p_multimesh,const AABB& p_aabb) {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- multimesh->aabb=p_aabb;
-}
-void RasterizerGLES1::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform) {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- ERR_FAIL_INDEX(p_index,multimesh->elements.size());
- MultiMesh::Element &e=multimesh->elements[p_index];
-
- e.matrix[0]=p_transform.basis.elements[0][0];
- e.matrix[1]=p_transform.basis.elements[1][0];
- e.matrix[2]=p_transform.basis.elements[2][0];
- e.matrix[3]=0;
- e.matrix[4]=p_transform.basis.elements[0][1];
- e.matrix[5]=p_transform.basis.elements[1][1];
- e.matrix[6]=p_transform.basis.elements[2][1];
- e.matrix[7]=0;
- e.matrix[8]=p_transform.basis.elements[0][2];
- e.matrix[9]=p_transform.basis.elements[1][2];
- e.matrix[10]=p_transform.basis.elements[2][2];
- e.matrix[11]=0;
- e.matrix[12]=p_transform.origin.x;
- e.matrix[13]=p_transform.origin.y;
- e.matrix[14]=p_transform.origin.z;
- e.matrix[15]=1;
-
-}
-void RasterizerGLES1::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color) {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND(!multimesh)
- ERR_FAIL_INDEX(p_index,multimesh->elements.size());
- MultiMesh::Element &e=multimesh->elements[p_index];
- e.color[0]=CLAMP(p_color.r*255,0,255);
- e.color[1]=CLAMP(p_color.g*255,0,255);
- e.color[2]=CLAMP(p_color.b*255,0,255);
- e.color[3]=CLAMP(p_color.a*255,0,255);
-
-
-}
-
-RID RasterizerGLES1::multimesh_get_mesh(RID p_multimesh) const {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND_V(!multimesh,RID());
-
- return multimesh->mesh;
-}
-AABB RasterizerGLES1::multimesh_get_aabb(RID p_multimesh) const {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND_V(!multimesh,AABB());
-
- return multimesh->aabb;
-}
-
-Transform RasterizerGLES1::multimesh_instance_get_transform(RID p_multimesh,int p_index) const {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND_V(!multimesh,Transform());
-
- ERR_FAIL_INDEX_V(p_index,multimesh->elements.size(),Transform());
- MultiMesh::Element &e=multimesh->elements[p_index];
-
- Transform tr;
-
- tr.basis.elements[0][0]=e.matrix[0];
- tr.basis.elements[1][0]=e.matrix[1];
- tr.basis.elements[2][0]=e.matrix[2];
- tr.basis.elements[0][1]=e.matrix[4];
- tr.basis.elements[1][1]=e.matrix[5];
- tr.basis.elements[2][1]=e.matrix[6];
- tr.basis.elements[0][2]=e.matrix[8];
- tr.basis.elements[1][2]=e.matrix[9];
- tr.basis.elements[2][2]=e.matrix[10];
- tr.origin.x=e.matrix[12];
- tr.origin.y=e.matrix[13];
- tr.origin.z=e.matrix[14];
-
- return tr;
-}
-Color RasterizerGLES1::multimesh_instance_get_color(RID p_multimesh,int p_index) const {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND_V(!multimesh,Color());
- ERR_FAIL_INDEX_V(p_index,multimesh->elements.size(),Color());
- MultiMesh::Element &e=multimesh->elements[p_index];
- Color c;
- c.r=e.color[0]/255.0;
- c.g=e.color[1]/255.0;
- c.b=e.color[2]/255.0;
- c.a=e.color[3]/255.0;
-
- return c;
-
-}
-
-void RasterizerGLES1::multimesh_set_visible_instances(RID p_multimesh,int p_visible) {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- multimesh->visible=p_visible;
-
-}
-
-int RasterizerGLES1::multimesh_get_visible_instances(RID p_multimesh) const {
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND_V(!multimesh,-1);
- return multimesh->visible;
-
-}
-
-/* IMMEDIATE API */
-
-
-RID RasterizerGLES1::immediate_create() {
-
- Immediate *im = memnew( Immediate );
- return immediate_owner.make_rid(im);
-
-}
-
-void RasterizerGLES1::immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture){
-
-
-}
-void RasterizerGLES1::immediate_vertex(RID p_immediate,const Vector3& p_vertex){
-
-
-}
-void RasterizerGLES1::immediate_normal(RID p_immediate,const Vector3& p_normal){
-
-
-}
-void RasterizerGLES1::immediate_tangent(RID p_immediate,const Plane& p_tangent){
-
-
-}
-void RasterizerGLES1::immediate_color(RID p_immediate,const Color& p_color){
-
-
-}
-void RasterizerGLES1::immediate_uv(RID p_immediate,const Vector2& tex_uv){
-
-
-}
-void RasterizerGLES1::immediate_uv2(RID p_immediate,const Vector2& tex_uv){
-
-
-}
-
-void RasterizerGLES1::immediate_end(RID p_immediate){
-
-
-}
-void RasterizerGLES1::immediate_clear(RID p_immediate) {
-
-
-}
-
-AABB RasterizerGLES1::immediate_get_aabb(RID p_immediate) const {
-
- return AABB(Vector3(-1,-1,-1),Vector3(2,2,2));
-}
-
-void RasterizerGLES1::immediate_set_material(RID p_immediate,RID p_material) {
-
- Immediate *im = immediate_owner.get(p_immediate);
- ERR_FAIL_COND(!im);
- im->material=p_material;
-}
-
-RID RasterizerGLES1::immediate_get_material(RID p_immediate) const {
-
- const Immediate *im = immediate_owner.get(p_immediate);
- ERR_FAIL_COND_V(!im,RID());
- return im->material;
-
-}
-
-
-/* PARTICLES API */
-
-RID RasterizerGLES1::particles_create() {
-
- Particles *particles = memnew( Particles );
- ERR_FAIL_COND_V(!particles,RID());
- return particles_owner.make_rid(particles);
-}
-
-void RasterizerGLES1::particles_set_amount(RID p_particles, int p_amount) {
-
- ERR_FAIL_COND(p_amount<1);
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.amount=p_amount;
-
-}
-
-int RasterizerGLES1::particles_get_amount(RID p_particles) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,-1);
- return particles->data.amount;
-
-}
-
-void RasterizerGLES1::particles_set_emitting(RID p_particles, bool p_emitting) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.emitting=p_emitting;;
-
-}
-bool RasterizerGLES1::particles_is_emitting(RID p_particles) const {
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,false);
- return particles->data.emitting;
-
-}
-
-void RasterizerGLES1::particles_set_visibility_aabb(RID p_particles, const AABB& p_visibility) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.visibility_aabb=p_visibility;
-
-}
-
-void RasterizerGLES1::particles_set_emission_half_extents(RID p_particles, const Vector3& p_half_extents) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
-
- particles->data.emission_half_extents=p_half_extents;
-}
-Vector3 RasterizerGLES1::particles_get_emission_half_extents(RID p_particles) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,Vector3());
-
- return particles->data.emission_half_extents;
-}
-
-void RasterizerGLES1::particles_set_emission_base_velocity(RID p_particles, const Vector3& p_base_velocity) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
-
- particles->data.emission_base_velocity=p_base_velocity;
-}
-
-Vector3 RasterizerGLES1::particles_get_emission_base_velocity(RID p_particles) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,Vector3());
-
- return particles->data.emission_base_velocity;
-}
-
-
-void RasterizerGLES1::particles_set_emission_points(RID p_particles, const DVector<Vector3>& p_points) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
-
- particles->data.emission_points=p_points;
-}
-
-DVector<Vector3> RasterizerGLES1::particles_get_emission_points(RID p_particles) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,DVector<Vector3>());
-
- return particles->data.emission_points;
-
-}
-
-void RasterizerGLES1::particles_set_gravity_normal(RID p_particles, const Vector3& p_normal) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
-
- particles->data.gravity_normal=p_normal;
-
-}
-Vector3 RasterizerGLES1::particles_get_gravity_normal(RID p_particles) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,Vector3());
-
- return particles->data.gravity_normal;
-}
-
-
-AABB RasterizerGLES1::particles_get_visibility_aabb(RID p_particles) const {
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,AABB());
- return particles->data.visibility_aabb;
-
-}
-
-void RasterizerGLES1::particles_set_variable(RID p_particles, VS::ParticleVariable p_variable,float p_value) {
-
- ERR_FAIL_INDEX(p_variable,VS::PARTICLE_VAR_MAX);
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.particle_vars[p_variable]=p_value;
-
-}
-float RasterizerGLES1::particles_get_variable(RID p_particles, VS::ParticleVariable p_variable) const {
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,-1);
- return particles->data.particle_vars[p_variable];
-}
-
-void RasterizerGLES1::particles_set_randomness(RID p_particles, VS::ParticleVariable p_variable,float p_randomness) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.particle_randomness[p_variable]=p_randomness;
-
-}
-float RasterizerGLES1::particles_get_randomness(RID p_particles, VS::ParticleVariable p_variable) const {
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,-1);
- return particles->data.particle_randomness[p_variable];
-
-}
-
-void RasterizerGLES1::particles_set_color_phases(RID p_particles, int p_phases) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- ERR_FAIL_COND( p_phases<0 || p_phases>VS::MAX_PARTICLE_COLOR_PHASES );
- particles->data.color_phase_count=p_phases;
-
-}
-int RasterizerGLES1::particles_get_color_phases(RID p_particles) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,-1);
- return particles->data.color_phase_count;
-}
-
-
-void RasterizerGLES1::particles_set_color_phase_pos(RID p_particles, int p_phase, float p_pos) {
-
- ERR_FAIL_INDEX(p_phase, VS::MAX_PARTICLE_COLOR_PHASES);
- if (p_pos<0.0)
- p_pos=0.0;
- if (p_pos>1.0)
- p_pos=1.0;
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.color_phases[p_phase].pos=p_pos;
-
-}
-float RasterizerGLES1::particles_get_color_phase_pos(RID p_particles, int p_phase) const {
-
- ERR_FAIL_INDEX_V(p_phase, VS::MAX_PARTICLE_COLOR_PHASES, -1.0);
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,-1);
- return particles->data.color_phases[p_phase].pos;
-
-}
-
-void RasterizerGLES1::particles_set_color_phase_color(RID p_particles, int p_phase, const Color& p_color) {
-
- ERR_FAIL_INDEX(p_phase, VS::MAX_PARTICLE_COLOR_PHASES);
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.color_phases[p_phase].color=p_color;
-
- //update alpha
- particles->has_alpha=false;
- for(int i=0;i<VS::MAX_PARTICLE_COLOR_PHASES;i++) {
- if (particles->data.color_phases[i].color.a<0.99)
- particles->has_alpha=true;
- }
-
-}
-
-Color RasterizerGLES1::particles_get_color_phase_color(RID p_particles, int p_phase) const {
-
- ERR_FAIL_INDEX_V(p_phase, VS::MAX_PARTICLE_COLOR_PHASES, Color());
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,Color());
- return particles->data.color_phases[p_phase].color;
-
-}
-
-void RasterizerGLES1::particles_set_attractors(RID p_particles, int p_attractors) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- ERR_FAIL_COND( p_attractors<0 || p_attractors>VisualServer::MAX_PARTICLE_ATTRACTORS );
- particles->data.attractor_count=p_attractors;
-
-}
-int RasterizerGLES1::particles_get_attractors(RID p_particles) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,-1);
- return particles->data.attractor_count;
-}
-
-void RasterizerGLES1::particles_set_attractor_pos(RID p_particles, int p_attractor, const Vector3& p_pos) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- ERR_FAIL_INDEX(p_attractor,particles->data.attractor_count);
- particles->data.attractors[p_attractor].pos=p_pos;;
-}
-Vector3 RasterizerGLES1::particles_get_attractor_pos(RID p_particles,int p_attractor) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,Vector3());
- ERR_FAIL_INDEX_V(p_attractor,particles->data.attractor_count,Vector3());
- return particles->data.attractors[p_attractor].pos;
-}
-
-void RasterizerGLES1::particles_set_attractor_strength(RID p_particles, int p_attractor, float p_force) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- ERR_FAIL_INDEX(p_attractor,particles->data.attractor_count);
- particles->data.attractors[p_attractor].force=p_force;
-}
-
-float RasterizerGLES1::particles_get_attractor_strength(RID p_particles,int p_attractor) const {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,0);
- ERR_FAIL_INDEX_V(p_attractor,particles->data.attractor_count,0);
- return particles->data.attractors[p_attractor].force;
-}
-
-void RasterizerGLES1::particles_set_material(RID p_particles, RID p_material,bool p_owned) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- if (particles->material_owned && particles->material.is_valid())
- free(particles->material);
-
- particles->material_owned=p_owned;
-
- particles->material=p_material;
-
-}
-RID RasterizerGLES1::particles_get_material(RID p_particles) const {
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,RID());
- return particles->material;
-
-}
-
-void RasterizerGLES1::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.local_coordinates=p_enable;
-
-}
-
-bool RasterizerGLES1::particles_is_using_local_coordinates(RID p_particles) const {
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,false);
- return particles->data.local_coordinates;
-}
-bool RasterizerGLES1::particles_has_height_from_velocity(RID p_particles) const {
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,false);
- return particles->data.height_from_velocity;
-}
-
-void RasterizerGLES1::particles_set_height_from_velocity(RID p_particles, bool p_enable) {
-
- Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND(!particles);
- particles->data.height_from_velocity=p_enable;
-
-}
-
-AABB RasterizerGLES1::particles_get_aabb(RID p_particles) const {
-
- const Particles* particles = particles_owner.get( p_particles );
- ERR_FAIL_COND_V(!particles,AABB());
- return particles->data.visibility_aabb;
-}
-
-/* SKELETON API */
-
-RID RasterizerGLES1::skeleton_create() {
-
- Skeleton *skeleton = memnew( Skeleton );
- ERR_FAIL_COND_V(!skeleton,RID());
- return skeleton_owner.make_rid( skeleton );
-}
-void RasterizerGLES1::skeleton_resize(RID p_skeleton,int p_bones) {
-
- Skeleton *skeleton = skeleton_owner.get( p_skeleton );
- ERR_FAIL_COND(!skeleton);
- if (p_bones == skeleton->bones.size()) {
- return;
- };
-
- skeleton->bones.resize(p_bones);
-
-}
-int RasterizerGLES1::skeleton_get_bone_count(RID p_skeleton) const {
-
- Skeleton *skeleton = skeleton_owner.get( p_skeleton );
- ERR_FAIL_COND_V(!skeleton, -1);
- return skeleton->bones.size();
-}
-void RasterizerGLES1::skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform) {
-
- Skeleton *skeleton = skeleton_owner.get( p_skeleton );
- ERR_FAIL_COND(!skeleton);
- ERR_FAIL_INDEX( p_bone, skeleton->bones.size() );
-
- skeleton->bones[p_bone] = p_transform;
-}
-
-Transform RasterizerGLES1::skeleton_bone_get_transform(RID p_skeleton,int p_bone) {
-
- Skeleton *skeleton = skeleton_owner.get( p_skeleton );
- ERR_FAIL_COND_V(!skeleton, Transform());
- ERR_FAIL_INDEX_V( p_bone, skeleton->bones.size(), Transform() );
-
- // something
- return skeleton->bones[p_bone];
-}
-
-
-/* LIGHT API */
-
-RID RasterizerGLES1::light_create(VS::LightType p_type) {
-
- Light *light = memnew( Light );
- light->type=p_type;
- return light_owner.make_rid(light);
-}
-
-VS::LightType RasterizerGLES1::light_get_type(RID p_light) const {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI);
- return light->type;
-}
-
-void RasterizerGLES1::light_set_color(RID p_light,VS::LightColor p_type, const Color& p_color) {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND(!light);
- ERR_FAIL_INDEX( p_type, 3 );
- light->colors[p_type]=p_color;
-}
-Color RasterizerGLES1::light_get_color(RID p_light,VS::LightColor p_type) const {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND_V(!light, Color());
- ERR_FAIL_INDEX_V( p_type, 3, Color() );
- return light->colors[p_type];
-}
-
-void RasterizerGLES1::light_set_shadow(RID p_light,bool p_enabled) {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND(!light);
- light->shadow_enabled=p_enabled;
-}
-
-bool RasterizerGLES1::light_has_shadow(RID p_light) const {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND_V(!light,false);
- return light->shadow_enabled;
-}
-
-void RasterizerGLES1::light_set_volumetric(RID p_light,bool p_enabled) {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND(!light);
- light->volumetric_enabled=p_enabled;
-
-}
-bool RasterizerGLES1::light_is_volumetric(RID p_light) const {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND_V(!light,false);
- return light->volumetric_enabled;
-}
-
-void RasterizerGLES1::light_set_projector(RID p_light,RID p_texture) {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND(!light);
- light->projector=p_texture;
-}
-RID RasterizerGLES1::light_get_projector(RID p_light) const {
-
- Light *light = light_owner.get(p_light);
- ERR_FAIL_COND_V(!light,RID());
- return light->projector;
-}
-
-void RasterizerGLES1::light_set_var(RID p_light, VS::LightParam p_var, float p_value) {
-
- Light * light = light_owner.get( p_light );
- ERR_FAIL_COND(!light);
- ERR_FAIL_INDEX( p_var, VS::LIGHT_PARAM_MAX );
-
- light->vars[p_var]=p_value;
-}
-float RasterizerGLES1::light_get_var(RID p_light, VS::LightParam p_var) const {
-
- Light * light = light_owner.get( p_light );
- ERR_FAIL_COND_V(!light,0);
-
- ERR_FAIL_INDEX_V( p_var, VS::LIGHT_PARAM_MAX,0 );
-
- return light->vars[p_var];
-}
-
-void RasterizerGLES1::light_set_operator(RID p_light,VS::LightOp p_op) {
-
- Light * light = light_owner.get( p_light );
- ERR_FAIL_COND(!light);
-
-
-};
-
-VS::LightOp RasterizerGLES1::light_get_operator(RID p_light) const {
-
- return VS::LightOp(0);
-};
-
-void RasterizerGLES1::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) {
-
-
-}
-
-VS::LightOmniShadowMode RasterizerGLES1::light_omni_get_shadow_mode(RID p_light) const{
-
- return VS::LightOmniShadowMode(0);
-}
-
-void RasterizerGLES1::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode) {
-
-
-}
-
-VS::LightDirectionalShadowMode RasterizerGLES1::light_directional_get_shadow_mode(RID p_light) const {
-
- return VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
-}
-
-void RasterizerGLES1::light_directional_set_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param, float p_value) {
-
-
-}
-
-float RasterizerGLES1::light_directional_get_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param) const {
-
- return 0;
-}
-
-
-AABB RasterizerGLES1::light_get_aabb(RID p_light) const {
-
- Light *light = light_owner.get( p_light );
- ERR_FAIL_COND_V(!light,AABB());
-
- switch( light->type ) {
-
- case VS::LIGHT_SPOT: {
-
- float len=light->vars[VS::LIGHT_PARAM_RADIUS];
- float size=Math::tan(Math::deg2rad(light->vars[VS::LIGHT_PARAM_SPOT_ANGLE]))*len;
- return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) );
- } break;
- case VS::LIGHT_OMNI: {
-
- float r = light->vars[VS::LIGHT_PARAM_RADIUS];
- return AABB( -Vector3(r,r,r), Vector3(r,r,r)*2 );
- } break;
- case VS::LIGHT_DIRECTIONAL: {
-
- return AABB();
- } break;
- default: {}
- }
-
- ERR_FAIL_V( AABB() );
-}
-
-
-RID RasterizerGLES1::light_instance_create(RID p_light) {
-
- Light *light = light_owner.get( p_light );
- ERR_FAIL_COND_V(!light, RID());
-
- LightInstance *light_instance = memnew( LightInstance );
-
- light_instance->light=p_light;
- light_instance->base=light;
- light_instance->last_pass=0;
-
- return light_instance_owner.make_rid( light_instance );
-}
-void RasterizerGLES1::light_instance_set_transform(RID p_light_instance,const Transform& p_transform) {
-
- LightInstance *lighti = light_instance_owner.get( p_light_instance );
- ERR_FAIL_COND(!lighti);
- lighti->transform=p_transform;
-
-}
-
-bool RasterizerGLES1::light_instance_has_shadow(RID p_light_instance) const {
-
- return false;
-
- /*
- LightInstance *lighti = light_instance_owner.get( p_light_instance );
- ERR_FAIL_COND_V(!lighti, false);
-
- if (!lighti->base->shadow_enabled)
- return false;
-
- if (lighti->base->type==VS::LIGHT_DIRECTIONAL) {
- if (lighti->shadow_pass!=scene_pass)
- return false;
-
- } else {
- if (lighti->shadow_pass!=frame)
- return false;
- }*/
-
-
-
- //return !lighti->shadow_buffers.empty();
-
-}
-
-
-bool RasterizerGLES1::light_instance_assign_shadow(RID p_light_instance) {
-
- return false;
-
-}
-
-
-Rasterizer::ShadowType RasterizerGLES1::light_instance_get_shadow_type(RID p_light_instance) const {
-
- LightInstance *lighti = light_instance_owner.get( p_light_instance );
- ERR_FAIL_COND_V(!lighti,Rasterizer::SHADOW_NONE);
-
- switch(lighti->base->type) {
-
- case VS::LIGHT_DIRECTIONAL: return SHADOW_PSM; break;
- case VS::LIGHT_OMNI: return SHADOW_DUAL_PARABOLOID; break;
- case VS::LIGHT_SPOT: return SHADOW_SIMPLE; break;
- }
-
- return Rasterizer::SHADOW_NONE;
-}
-
-Rasterizer::ShadowType RasterizerGLES1::light_instance_get_shadow_type(RID p_light_instance,bool p_far) const {
-
- return SHADOW_NONE;
-}
-void RasterizerGLES1::light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) {
-
-
-}
-
-int RasterizerGLES1::light_instance_get_shadow_passes(RID p_light_instance) const {
-
- return 0;
-}
-
-bool RasterizerGLES1::light_instance_get_pssm_shadow_overlap(RID p_light_instance) const {
-
- return false;
-}
-
-void RasterizerGLES1::light_instance_set_custom_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) {
-
- LightInstance *lighti = light_instance_owner.get( p_light_instance );
- ERR_FAIL_COND(!lighti);
-
- ERR_FAIL_COND(lighti->base->type!=VS::LIGHT_DIRECTIONAL);
- ERR_FAIL_INDEX(p_index,1);
-
- lighti->custom_projection=p_camera;
- lighti->custom_transform=p_transform;
-
-}
-void RasterizerGLES1::shadow_clear_near() {
-
-
-}
-
-bool RasterizerGLES1::shadow_allocate_near(RID p_light) {
-
- return false;
-}
-
-bool RasterizerGLES1::shadow_allocate_far(RID p_light) {
-
- return false;
-}
-
-/* PARTICLES INSTANCE */
-
-RID RasterizerGLES1::particles_instance_create(RID p_particles) {
-
- ERR_FAIL_COND_V(!particles_owner.owns(p_particles),RID());
- ParticlesInstance *particles_instance = memnew( ParticlesInstance );
- ERR_FAIL_COND_V(!particles_instance, RID() );
- particles_instance->particles=p_particles;
- return particles_instance_owner.make_rid(particles_instance);
-}
-
-void RasterizerGLES1::particles_instance_set_transform(RID p_particles_instance,const Transform& p_transform) {
-
- ParticlesInstance *particles_instance=particles_instance_owner.get(p_particles_instance);
- ERR_FAIL_COND(!particles_instance);
- particles_instance->transform=p_transform;
-}
-
-
-/* RENDER API */
-/* all calls (inside begin/end shadow) are always warranted to be in the following order: */
-
-
-RID RasterizerGLES1::viewport_data_create() {
-
- return RID();
-}
-
-RID RasterizerGLES1::render_target_create(){
-
- return RID();
-
-}
-void RasterizerGLES1::render_target_set_size(RID p_render_target, int p_width, int p_height){
-
-
-}
-RID RasterizerGLES1::render_target_get_texture(RID p_render_target) const{
-
- return RID();
-
-}
-bool RasterizerGLES1::render_target_renedered_in_frame(RID p_render_target){
-
- return false;
-}
-
-
-void RasterizerGLES1::begin_frame() {
-
-
- window_size = Size2( OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height );
- //print_line("begin frame - winsize: "+window_size);
-
- double time = (OS::get_singleton()->get_ticks_usec()/1000); // get msec
- time/=1000.0; // make secs
- time_delta=time-last_time;
- last_time=time;
- frame++;
- clear_viewport(Color(1,0,0.5));
-
- _rinfo.vertex_count=0;
- _rinfo.object_count=0;
- _rinfo.mat_change_count=0;
- _rinfo.shader_change_count=0;
-
-
-// material_shader.set_uniform_default(MaterialShaderGLES1::SCREENZ_SCALE, Math::fmod(time, 3600.0));
- /* nehe ?*/
-
-// glClearColor(0,0,1,1);
-// glClear(GL_COLOR_BUFFER_BIT); //should not clear if anything else cleared..
-}
-
-void RasterizerGLES1::capture_viewport(Image* r_capture) {
-
-
-}
-
-
-void RasterizerGLES1::clear_viewport(const Color& p_color) {
-
- glScissor( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height );
- glEnable(GL_SCISSOR_TEST);
- glClearColor(p_color.r,p_color.g,p_color.b,p_color.a);
- glClear(GL_COLOR_BUFFER_BIT); //should not clear if anything else cleared..
- glDisable(GL_SCISSOR_TEST);
-
-};
-
-void RasterizerGLES1::set_viewport(const VS::ViewportRect& p_viewport) {
-
-
-
- viewport=p_viewport;
- //print_line("viewport: "+itos(p_viewport.x)+","+itos(p_viewport.y)+","+itos(p_viewport.width)+","+itos(p_viewport.height));
-
- glViewport( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height );
-}
-
-void RasterizerGLES1::set_render_target(RID p_render_target, bool p_transparent_bg, bool p_vflip) {
-
-
-}
-
-
-void RasterizerGLES1::begin_scene(RID p_viewport_data,RID p_env,VS::ScenarioDebugMode p_debug) {
-
-
- opaque_render_list.clear();
- alpha_render_list.clear();
- light_instance_count=0;
- scene_fx = NULL; // p_env.is_valid() ? fx_owner.get(p_env) : NULL;
- scene_pass++;
- last_light_id=0;
- directional_light_count=0;
-
-
- //set state
-
- glCullFace(GL_FRONT);
- cull_front=true;
-};
-
-void RasterizerGLES1::begin_shadow_map( RID p_light_instance, int p_shadow_pass ) {
-
-}
-
-void RasterizerGLES1::set_camera(const Transform& p_world,const CameraMatrix& p_projection) {
-
- camera_transform=p_world;
- camera_transform_inverse=camera_transform.inverse();
- camera_projection=p_projection;
- camera_plane = Plane( camera_transform.origin, camera_transform.basis.get_axis(2) );
- camera_z_near=camera_projection.get_z_near();
- camera_z_far=camera_projection.get_z_far();
- camera_projection.get_viewport_size(camera_vp_size.x,camera_vp_size.y);
-}
-
-void RasterizerGLES1::add_light( RID p_light_instance ) {
-
-#define LIGHT_FADE_TRESHOLD 0.05
-
- ERR_FAIL_COND( light_instance_count >= MAX_SCENE_LIGHTS );
-
- LightInstance *li = light_instance_owner.get(p_light_instance);
- ERR_FAIL_COND(!li);
-
-
- /* make light hash */
-
- // actually, not really a hash, but helps to sort the lights
- // and avoid recompiling redudant shader versions
-
-
- li->last_pass=scene_pass;
- li->sort_key=light_instance_count;
-
- switch(li->base->type) {
-
- case VisualServer::LIGHT_DIRECTIONAL: {
-
- li->light_vector = camera_transform_inverse.basis.xform(li->transform.basis.get_axis(2)).normalized();
- if (directional_light_count<MAX_HW_LIGHTS) {
-
- directional_lights[directional_light_count++]=li;
- }
-
- } break;
- case VisualServer::LIGHT_OMNI: {
-
- float radius = li->base->vars[VisualServer::LIGHT_PARAM_RADIUS];
- if (radius==0)
- radius=0.0001;
- li->linear_att=(1/LIGHT_FADE_TRESHOLD)/radius;
- li->light_vector = camera_transform_inverse.xform(li->transform.origin);
-
- } break;
- case VisualServer::LIGHT_SPOT: {
-
- float radius = li->base->vars[VisualServer::LIGHT_PARAM_RADIUS];
- if (radius==0)
- radius=0.0001;
- li->linear_att=(1/LIGHT_FADE_TRESHOLD)/radius;
- li->light_vector = camera_transform_inverse.xform(li->transform.origin);
- li->spot_vector = -camera_transform_inverse.basis.xform(li->transform.basis.get_axis(2)).normalized();
- //li->sort_key|=LIGHT_SPOT_BIT; // this way, omnis go first, spots go last and less shader versions are generated
-
- /*
- if (li->base->projector.is_valid()) {
-
- float far = li->base->vars[ VS::LIGHT_VAR_RADIUS ];
- ERR_FAIL_COND( far<=0 );
- float near= far/200.0;
- if (near<0.05)
- near=0.05;
-
- float angle = li->base->vars[ VS::LIGHT_VAR_SPOT_ANGLE ];
-
- //CameraMatrix proj;
- //proj.set_perspective( angle*2.0, 1.0, near, far );
-
- //Transform modelview=Transform(camera_transform_inverse * li->transform).inverse();
- //li->projector_mtx= proj * modelview;
-
- }*/
- } break;
- }
-
- light_instances[light_instance_count++]=li;
-
-}
-
-void RasterizerGLES1::_add_geometry( const Geometry* p_geometry, const InstanceData *p_instance, const Geometry *p_geometry_cmp, const GeometryOwner *p_owner) {
-
- Material *m=NULL;
- RID m_src=p_instance->material_override.is_valid() ? p_instance->material_override : p_geometry->material;
-
- if (m_src)
- m=material_owner.get( m_src );
-
- if (!m) {
- m=material_owner.get( default_material );
- }
-
- ERR_FAIL_COND(!m);
-
-
- if (m->last_pass!=frame) {
-
- m->last_pass=frame;
- }
-
-
- LightInstance *lights[RenderList::MAX_LIGHTS];
- int light_count=0;
-
- RenderList *render_list=&opaque_render_list;
- if (m->fixed_flags[VS::FIXED_MATERIAL_FLAG_USE_ALPHA] || m->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX) {
- render_list = &alpha_render_list;
- };
-
- if (!m->flags[VS::MATERIAL_FLAG_UNSHADED]) {
-
- int lis = p_instance->light_instances.size();
-
- for(int i=0;i<lis;i++) {
- if (light_count>=RenderList::MAX_LIGHTS)
- break;
-
- LightInstance *li=light_instance_owner.get( p_instance->light_instances[i] );
-
- if (!li || li->last_pass!=scene_pass) //lit by light not in visible scene
- continue;
- lights[light_count++]=li;
- }
- }
-
- RenderList::Element *e = render_list->add_element();
-
- e->geometry=p_geometry;
-// e->geometry_cmp=p_geometry_cmp;
- e->material=m;
- e->instance=p_instance;
- //e->depth=camera_plane.distance_to(p_world->origin);
- e->depth=camera_transform.origin.distance_to(p_instance->transform.origin);
- e->owner=p_owner;
- if (p_instance->skeleton.is_valid())
- e->skeleton=skeleton_owner.get(p_instance->skeleton);
- else
- e->skeleton=NULL;
- e->mirror=p_instance->mirror;
- if (m->flags[VS::MATERIAL_FLAG_INVERT_FACES])
- e->mirror=!e->mirror;
-
- e->light_key=0;
- e->light_count=0;
-
-
- if (!shadow) {
-
-
- if (m->flags[VS::MATERIAL_FLAG_UNSHADED]) {
-
-
- e->light_key--; //special key for all the shadeless people
- } else if (light_count) {
-
- for(int i=0;i<light_count;i++) {
-
- e->lights[i]=lights[i]->sort_key;
- }
-
- e->light_count=light_count;
- int poslight_count=light_count;
- if (poslight_count>1) {
- SortArray<uint16_t> light_sort;
- light_sort.sort(&e->lights[0],poslight_count); //generate an equal sort key
- }
- }
-
- }
-
-}
-
-
-void RasterizerGLES1::add_mesh( const RID& p_mesh, const InstanceData *p_data) {
-
- Mesh *mesh = mesh_owner.get(p_mesh);
- ERR_FAIL_COND(!mesh);
-
- int ssize = mesh->surfaces.size();
-
- for (int i=0;i<ssize;i++) {
-
- Surface *s = mesh->surfaces[i];
- _add_geometry(s,p_data,s,NULL);
- }
-
- mesh->last_pass=frame;
-
-}
-
-void RasterizerGLES1::add_multimesh( const RID& p_multimesh, const InstanceData *p_data){
-
- MultiMesh *multimesh = multimesh_owner.get(p_multimesh);
- ERR_FAIL_COND(!multimesh);
-
- if (!multimesh->mesh.is_valid())
- return;
- if (multimesh->elements.empty())
- return;
-
- Mesh *mesh = mesh_owner.get(multimesh->mesh);
- ERR_FAIL_COND(!mesh);
-
- int surf_count = mesh->surfaces.size();
- if (multimesh->last_pass!=scene_pass) {
-
- multimesh->cache_surfaces.resize(surf_count);
- for(int i=0;i<surf_count;i++) {
-
- multimesh->cache_surfaces[i].material=mesh->surfaces[i]->material;
- multimesh->cache_surfaces[i].has_alpha=mesh->surfaces[i]->has_alpha;
- multimesh->cache_surfaces[i].surface=mesh->surfaces[i];
- }
-
- multimesh->last_pass=scene_pass;
- }
-
- for(int i=0;i<surf_count;i++) {
-
- _add_geometry(&multimesh->cache_surfaces[i],p_data,multimesh->cache_surfaces[i].surface,multimesh);
- }
-
-
-}
-
-void RasterizerGLES1::add_particles( const RID& p_particle_instance, const InstanceData *p_data){
-
- //print_line("adding particles");
- ParticlesInstance *particles_instance = particles_instance_owner.get(p_particle_instance);
- ERR_FAIL_COND(!particles_instance);
- Particles *p=particles_owner.get( particles_instance->particles );
- ERR_FAIL_COND(!p);
-
- _add_geometry(p,p_data,p,particles_instance);
-
-}
-
-
-void RasterizerGLES1::_set_cull(bool p_front,bool p_reverse_cull) {
-
- bool front = p_front;
- if (p_reverse_cull)
- front=!front;
-
- if (front!=cull_front) {
-
- glCullFace(front?GL_FRONT:GL_BACK);
- cull_front=front;
- }
-}
-
-
-void RasterizerGLES1::_setup_fixed_material(const Geometry *p_geometry,const Material *p_material) {
-
- if (!shadow) {
-
- ///ambient @TODO offer global ambient group option
-
- //GLenum side = use_shaders?GL_FRONT:GL_FRONT_AND_BACK;
- GLenum side = GL_FRONT_AND_BACK;
-
-
- ///diffuse
- Color diffuse_color=p_material->parameters[VS::FIXED_MATERIAL_PARAM_DIFFUSE];
- float diffuse_rgba[4]={
- diffuse_color.r,
- diffuse_color.g,
- diffuse_color.b,
- diffuse_color.a
- };
-
- //color array overrides this
- glColor4f( diffuse_rgba[0],diffuse_rgba[1],diffuse_rgba[2],diffuse_rgba[3]);
- last_color=diffuse_color;
- glMaterialfv(side,GL_AMBIENT,diffuse_rgba);
- glMaterialfv(side,GL_DIFFUSE,diffuse_rgba);
- //specular
-
- const Color specular_color=p_material->parameters[VS::FIXED_MATERIAL_PARAM_SPECULAR];
- float specular_rgba[4]={
- specular_color.r,
- specular_color.g,
- specular_color.b,
- 1.0
- };
-
- glMaterialfv(side,GL_SPECULAR,specular_rgba);
-
- const Color emission=p_material->parameters[VS::FIXED_MATERIAL_PARAM_EMISSION];
-
-
- float emission_rgba[4]={
- emission.r,
- emission.g,
- emission.b,
- 1.0 //p_material->parameters[VS::FIXED_MATERIAL_PARAM_DETAIL_MIX]
- };
-
- glMaterialfv(side,GL_EMISSION,emission_rgba);
-
- glMaterialf(side,GL_SHININESS,p_material->parameters[VS::FIXED_MATERIAL_PARAM_SPECULAR_EXP]);
-
- Plane sparams=p_material->parameters[VS::FIXED_MATERIAL_PARAM_SHADE_PARAM];
- //depth test?
-
-
- }
-
-
- if (p_material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE].is_valid()) {
-
- Texture *texture = texture_owner.get( p_material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE] );
- ERR_FAIL_COND(!texture);
- glEnable(GL_TEXTURE_2D);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture( GL_TEXTURE_2D,texture->tex_id );
- } else {
-
- glDisable(GL_TEXTURE_2D);
- }
-
-}
-
-void RasterizerGLES1::_setup_material(const Geometry *p_geometry,const Material *p_material) {
-
- if (p_material->flags[VS::MATERIAL_FLAG_DOUBLE_SIDED])
- glDisable(GL_CULL_FACE);
- else {
- glEnable(GL_CULL_FACE);
- }
-
-/* if (p_material->flags[VS::MATERIAL_FLAG_WIREFRAME])
- glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
- else
- glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);*/
-
- if (p_material->line_width > 0)
- glLineWidth(p_material->line_width);
-
- if (!shadow) {
-
-
- if (blend_mode!=p_material->blend_mode) {
- switch(p_material->blend_mode) {
-
-
- case VS::MATERIAL_BLEND_MODE_MIX: {
- //glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-
- } break;
- case VS::MATERIAL_BLEND_MODE_ADD: {
-
- //glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE);
-
- } break;
- case VS::MATERIAL_BLEND_MODE_SUB: {
-
- //glBlendEquation(GL_FUNC_SUBTRACT);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE);
- } break;
- case VS::MATERIAL_BLEND_MODE_MUL: {
- //glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-
- } break;
-
- }
- blend_mode=p_material->blend_mode;
- }
-
- if (lighting!=!p_material->flags[VS::MATERIAL_FLAG_UNSHADED]) {
- if (p_material->flags[VS::MATERIAL_FLAG_UNSHADED]) {
- glDisable(GL_LIGHTING);
- } else {
- glEnable(GL_LIGHTING);
- }
- lighting=!p_material->flags[VS::MATERIAL_FLAG_UNSHADED];
- }
-
- }
-
- bool current_depth_write=p_material->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_ALWAYS; //broken
- bool current_depth_test=!p_material->flags[VS::MATERIAL_FLAG_ONTOP];
-
-
- _setup_fixed_material(p_geometry,p_material);
-
- if (current_depth_write!=depth_write) {
-
- depth_write=current_depth_write;
- glDepthMask(depth_write);
- }
-
- if (current_depth_test!=depth_test) {
-
- depth_test=current_depth_test;
- if (depth_test)
- glEnable(GL_DEPTH_TEST);
- else
- glDisable(GL_DEPTH_TEST);
- }
-}
-/*
-static const MaterialShaderGLES1::Conditionals _gl_light_version[4][3]={
- {MaterialShaderGLES1::LIGHT_0_DIRECTIONAL,MaterialShaderGLES1::LIGHT_0_OMNI,MaterialShaderGLES1::LIGHT_0_SPOT},
- {MaterialShaderGLES1::LIGHT_1_DIRECTIONAL,MaterialShaderGLES1::LIGHT_1_OMNI,MaterialShaderGLES1::LIGHT_1_SPOT},
- {MaterialShaderGLES1::LIGHT_2_DIRECTIONAL,MaterialShaderGLES1::LIGHT_2_OMNI,MaterialShaderGLES1::LIGHT_2_SPOT},
- {MaterialShaderGLES1::LIGHT_3_DIRECTIONAL,MaterialShaderGLES1::LIGHT_3_OMNI,MaterialShaderGLES1::LIGHT_3_SPOT}
-};
-
-static const MaterialShaderGLES1::Conditionals _gl_light_shadow[4]={
- MaterialShaderGLES1::LIGHT_0_SHADOW,
- MaterialShaderGLES1::LIGHT_1_SHADOW,
- MaterialShaderGLES1::LIGHT_2_SHADOW,
- MaterialShaderGLES1::LIGHT_3_SHADOW
-};
-*/
-
-
-void RasterizerGLES1::_setup_light(LightInstance* p_instance, int p_idx) {
-
- Light* ld = p_instance->base;
-
-// material_shader.set_conditional(MaterialShaderGLES1::LIGHT_0_DIRECTIONAL, true);
-
- //material_shader.set_uniform_default(MaterialShaderGLES1::LIGHT_0_DIFFUSE, ld->colors[VS::LIGHT_COLOR_DIFFUSE]);
- //material_shader.set_uniform_default(MaterialShaderGLES1::LIGHT_0_SPECULAR, ld->colors[VS::LIGHT_COLOR_SPECULAR]);
- //material_shader.set_uniform_default(MaterialShaderGLES1::LIGHT_0_AMBIENT, ld->colors[VS::LIGHT_COLOR_AMBIENT]);
-
- GLenum glid = GL_LIGHT0+p_idx;
-
- Color diff_color = ld->colors[VS::LIGHT_COLOR_DIFFUSE];
- float emult = ld->vars[VS::LIGHT_PARAM_ENERGY];
-
- if (ld->type!=VS::LIGHT_DIRECTIONAL)
- emult*=4.0;
-
- GLfloat diffuse_sdark[4]={
- diff_color.r*emult,
- diff_color.g*emult,
- diff_color.b*emult,
- 1.0
- };
-
- glLightfv(glid , GL_DIFFUSE, diffuse_sdark);
-
- Color amb_color = Color(0,0,0);
- GLfloat amb_stexsize[4]={
- amb_color.r,
- amb_color.g,
- amb_color.b,
- 1.0
- };
-
- glLightfv(glid , GL_AMBIENT, amb_stexsize );
-
- Color spec_color = ld->colors[VS::LIGHT_COLOR_SPECULAR];
- GLfloat spec_op[4]={
- spec_color.r,
- spec_color.g,
- spec_color.b,
- 1.0
- };
-
- glLightfv(glid , GL_SPECULAR, spec_op );
-
- switch(ld->type) {
-
- case VS::LIGHT_DIRECTIONAL: {
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- glLightf(glid,GL_CONSTANT_ATTENUATION, 1);
- glLightf(glid,GL_LINEAR_ATTENUATION, 0);
- glLightf(glid,GL_QUADRATIC_ATTENUATION,0); // energy
-
- float lightdir[4]={
- p_instance->light_vector.x,
- p_instance->light_vector.y,
- p_instance->light_vector.z,
- 0.0
- };
-
- glLightfv(glid,GL_POSITION,lightdir); //at modelview
- glLightf(glid,GL_SPOT_CUTOFF,180.0);
- glLightf(glid,GL_SPOT_EXPONENT, 0);
-
- float sdir[4]={
- 0,
- 0,
- -1,
- 0
- };
-
- glLightfv(glid,GL_SPOT_DIRECTION,sdir); //at modelview
-
-// material_shader.set_uniform_default(MaterialShaderGLES1::LIGHT_0_DIRECTION, p_instance->light_vector);
- glPopMatrix();
-
- } break;
-
- case VS::LIGHT_OMNI: {
-
-
- glLightf(glid,GL_SPOT_CUTOFF,180.0);
- glLightf(glid,GL_SPOT_EXPONENT, 0);
-
-
- glLightf(glid,GL_CONSTANT_ATTENUATION, 0);
- glLightf(glid,GL_LINEAR_ATTENUATION, p_instance->linear_att);
- glLightf(glid,GL_QUADRATIC_ATTENUATION, 0); // wut?
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- float lightpos[4]={
- p_instance->light_vector.x,
- p_instance->light_vector.y,
- p_instance->light_vector.z,
- 1.0
- };
-
- glLightfv(glid,GL_POSITION,lightpos); //at modelview
-
- glPopMatrix();
-
-
- } break;
- case VS::LIGHT_SPOT: {
-
- glLightf(glid,GL_SPOT_CUTOFF, ld->vars[VS::LIGHT_PARAM_SPOT_ANGLE]);
- glLightf(glid,GL_SPOT_EXPONENT, ld->vars[VS::LIGHT_PARAM_SPOT_ATTENUATION]);
-
-
- glLightf(glid,GL_CONSTANT_ATTENUATION, 0);
- glLightf(glid,GL_LINEAR_ATTENUATION, p_instance->linear_att);
- glLightf(glid,GL_QUADRATIC_ATTENUATION, 0); // wut?
-
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- float lightpos[4]={
- p_instance->light_vector.x,
- p_instance->light_vector.y,
- p_instance->light_vector.z,
- 1.0
- };
-
- glLightfv(glid,GL_POSITION,lightpos); //at modelview
-
- float lightdir[4]={
- p_instance->spot_vector.x,
- p_instance->spot_vector.y,
- p_instance->spot_vector.z,
- 1.0
- };
-
- glLightfv(glid,GL_SPOT_DIRECTION,lightdir); //at modelview
-
- glPopMatrix();
-
-
-
- } break;
-
- default: break;
- }
-};
-
-
-
-
-
-void RasterizerGLES1::_setup_lights(const uint16_t * p_lights,int p_light_count) {
-
- if (shadow)
- return;
-
-
-
- for (int i=directional_light_count; i<MAX_HW_LIGHTS; i++) {
-
- if (i<(directional_light_count+p_light_count)) {
-
-
- glEnable(GL_LIGHT0 + i);
- _setup_light(light_instances[p_lights[i]], i);
-
- } else {
- glDisable(GL_LIGHT0 + i);
-
- }
- }
-
-}
-
-
-
-static const GLenum gl_client_states[] = {
-
- GL_VERTEX_ARRAY,
- GL_NORMAL_ARRAY,
- 0, // ARRAY_TANGENT
- 0,//GL_COLOR_ARRAY,
- GL_TEXTURE_COORD_ARRAY, // ARRAY_TEX_UV
- 0,//GL_TEXTURE_COORD_ARRAY, // ARRAY_TEX_UV2
- 0, // ARRAY_BONES
- 0, // ARRAY_WEIGHTS
-};
-
-static const int gl_texcoord_index[VS::ARRAY_MAX-1] = {
-
- -1,
- -1,
- -1, // ARRAY_TANGENT
- -1,
- 0, // ARRAY_TEX_UV
- -1,//1, // ARRAY_TEX_UV2
- -1, // ARRAY_BONES
- -1, // ARRAY_WEIGHTS
-};
-
-
-Error RasterizerGLES1::_setup_geometry(const Geometry *p_geometry, const Material* p_material, const Skeleton *p_skeleton,const float *p_morphs) {
-
-
- switch(p_geometry->type) {
-
- case Geometry::GEOMETRY_MULTISURFACE:
- case Geometry::GEOMETRY_SURFACE: {
-
-
-
- const Surface *surf=NULL;
- if (p_geometry->type==Geometry::GEOMETRY_SURFACE)
- surf=static_cast<const Surface*>(p_geometry);
- else if (p_geometry->type==Geometry::GEOMETRY_MULTISURFACE)
- surf=static_cast<const MultiMeshSurface*>(p_geometry)->surface;
-
-
- if (surf->format != surf->configured_format) {
- if (OS::get_singleton()->is_stdout_verbose()) {
-
- print_line("has format: "+itos(surf->format));
- print_line("configured format: "+itos(surf->configured_format));
- }
- ERR_EXPLAIN("Missing arrays (not set) in surface");
- }
- ERR_FAIL_COND_V( surf->format != surf->configured_format, ERR_UNCONFIGURED );
- uint8_t *base=0;
- int stride=surf->stride;
- bool use_VBO = (surf->array_local==0);
- _setup_geometry_vinfo=surf->array_len;
-
- bool skeleton_valid = p_skeleton && (surf->format&VS::ARRAY_FORMAT_BONES) && (surf->format&VS::ARRAY_FORMAT_WEIGHTS) && !p_skeleton->bones.empty() && p_skeleton->bones.size() > surf->max_bone;
-
-
-
- if (!use_VBO) {
-
- base = surf->array_local;
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- bool can_copy_to_local=surf->local_stride * surf->array_len <= skinned_buffer_size;
- if (!can_copy_to_local)
- skeleton_valid=false;
-
- /* compute morphs */
-
- if (p_morphs && surf->morph_target_count && can_copy_to_local) {
-
- base = skinned_buffer;
- stride=surf->local_stride;
-
- //copy all first
- float coef=1.0;
-
- for(int i=0;i<surf->morph_target_count;i++) {
- if (surf->mesh->morph_target_mode==VS::MORPH_MODE_NORMALIZED)
- coef-=p_morphs[i];
- ERR_FAIL_COND_V( surf->morph_format != surf->morph_targets_local[i].configured_format, ERR_INVALID_DATA );
-
- }
-
-
- for(int i=0;i<VS::ARRAY_MAX-1;i++) {
-
- const Surface::ArrayData& ad=surf->array[i];
- if (ad.size==0)
- continue;
-
- int ofs = ad.ofs;
- int src_stride=surf->stride;
- int dst_stride=surf->local_stride;
- int count = surf->array_len;
-
- switch(i) {
-
- case VS::ARRAY_VERTEX:
- case VS::ARRAY_NORMAL:
- case VS::ARRAY_TANGENT:
- {
-
- for(int k=0;k<count;k++) {
-
- const float *src = (const float*)&surf->array_local[ofs+k*src_stride];
- float *dst = (float*)&base[ofs+k*dst_stride];
-
- dst[0]= src[0]*coef;
- dst[1]= src[1]*coef;
- dst[2]= src[2]*coef;
- } break;
-
- } break;
- case VS::ARRAY_TEX_UV:
- case VS::ARRAY_TEX_UV2: {
-
- for(int k=0;k<count;k++) {
-
- const float *src = (const float*)&surf->array_local[ofs+k*src_stride];
- float *dst = (float*)&base[ofs+k*dst_stride];
-
- dst[0]= src[0]*coef;
- dst[1]= src[1]*coef;
- } break;
-
- } break;
- }
- }
-
-
- for(int j=0;j<surf->morph_target_count;j++) {
-
- for(int i=0;i<VS::ARRAY_MAX-1;i++) {
-
- const Surface::ArrayData& ad=surf->array[i];
- if (ad.size==0)
- continue;
-
-
- int ofs = ad.ofs;
- int dst_stride=surf->local_stride;
- int count = surf->array_len;
- const uint8_t *morph=surf->morph_targets_local[j].array;
- float w = p_morphs[j];
-
- switch(i) {
-
- case VS::ARRAY_VERTEX:
- case VS::ARRAY_NORMAL:
- case VS::ARRAY_TANGENT:
- {
-
- for(int k=0;k<count;k++) {
-
- const float *src_morph = (const float*)&morph[ofs+k*dst_stride];
- float *dst = (float*)&base[ofs+k*dst_stride];
-
- dst[0]+= src_morph[0]*w;
- dst[1]+= src_morph[1]*w;
- dst[2]+= src_morph[2]*w;
- } break;
-
- } break;
- case VS::ARRAY_TEX_UV:
- case VS::ARRAY_TEX_UV2: {
-
- for(int k=0;k<count;k++) {
-
- const float *src_morph = (const float*)&morph[ofs+k*dst_stride];
- float *dst = (float*)&base[ofs+k*dst_stride];
-
- dst[0]+= src_morph[0]*w;
- dst[1]+= src_morph[1]*w;
- } break;
-
- } break;
- }
- }
- }
-
- } else if (skeleton_valid) {
-
- base = skinned_buffer;
- //copy stuff and get it ready for the skeleton
-
- int len = surf->array_len;
- int src_stride = surf->stride;
- int dst_stride = surf->stride - ( surf->array[VS::ARRAY_BONES].size + surf->array[VS::ARRAY_WEIGHTS].size );
-
- for(int i=0;i<len;i++) {
- const uint8_t *src = &surf->array_local[i*src_stride];
- uint8_t *dst = &base[i*dst_stride];
- memcpy(dst,src,dst_stride);
- }
-
-
- stride=dst_stride;
- }
-
-
- if (skeleton_valid) {
- //transform stuff
-
- const uint8_t *src_weights=&surf->array_local[surf->array[VS::ARRAY_WEIGHTS].ofs];
- const uint8_t *src_bones=&surf->array_local[surf->array[VS::ARRAY_BONES].ofs];
- int src_stride = surf->stride;
- int count = surf->array_len;
- const Transform *skeleton = &p_skeleton->bones[0];
-
- for(int i=0;i<VS::ARRAY_MAX-1;i++) {
-
- const Surface::ArrayData& ad=surf->array[i];
- if (ad.size==0)
- continue;
-
- int ofs = ad.ofs;
-
-
- switch(i) {
-
- case VS::ARRAY_VERTEX: {
- for(int k=0;k<count;k++) {
-
- float *ptr= (float*)&base[ofs+k*stride];
- const GLfloat* weights = reinterpret_cast<const GLfloat*>(&src_weights[k*src_stride]);
- const GLfloat *bones = reinterpret_cast<const GLfloat*>(&src_bones[k*src_stride]);
-
- Vector3 src( ptr[0], ptr[1], ptr[2] );
- Vector3 dst;
- for(int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
-
- float w = weights[j];
- if (w==0)
- break;
-
- //print_line("accum "+itos(i)+" += "+rtos(Math::ftoi(bones[j]))+" * "+skeleton[ Math::ftoi(bones[j]) ]+" * "+rtos(w));
- dst+=skeleton[ Math::fast_ftoi(bones[j]) ].xform(src) * w;
- }
-
- ptr[0]=dst.x;
- ptr[1]=dst.y;
- ptr[2]=dst.z;
-
- } break;
-
- } break;
- case VS::ARRAY_NORMAL:
- case VS::ARRAY_TANGENT: {
- for(int k=0;k<count;k++) {
-
- float *ptr= (float*)&base[ofs+k*stride];
- const GLfloat* weights = reinterpret_cast<const GLfloat*>(&src_weights[k*src_stride]);
- const GLfloat *bones = reinterpret_cast<const GLfloat*>(&src_bones[k*src_stride]);
-
- Vector3 src( ptr[0], ptr[1], ptr[2] );
- Vector3 dst;
- for(int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
-
- float w = weights[j];
- if (w==0)
- break;
-
- //print_line("accum "+itos(i)+" += "+rtos(Math::ftoi(bones[j]))+" * "+skeleton[ Math::ftoi(bones[j]) ]+" * "+rtos(w));
- dst+=skeleton[ Math::fast_ftoi(bones[j]) ].basis.xform(src) * w;
- }
-
- ptr[0]=dst.x;
- ptr[1]=dst.y;
- ptr[2]=dst.z;
-
- } break;
-
- } break;
- }
- }
-
- }
-
- } else {
-
- glBindBuffer(GL_ARRAY_BUFFER, surf->vertex_id);
- };
-
-
- for (int i=0;i<(VS::ARRAY_MAX-1);i++) {
-
- const Surface::ArrayData& ad=surf->array[i];
-
-// if (!gl_texcoord_shader[i])
-// continue;
-
- if (ad.size==0 || i==VS::ARRAY_BONES || i==VS::ARRAY_WEIGHTS || gl_client_states[i]==0 ) {
-
- if (gl_texcoord_index[i] != -1) {
- glClientActiveTexture(GL_TEXTURE0+gl_texcoord_index[i]);
- }
-
- if (gl_client_states[i] != 0)
- glDisableClientState(gl_client_states[i]);
-
- if (i == VS::ARRAY_COLOR) {
- glColor4f(last_color.r,last_color.g,last_color.b,last_color.a);
- };
- continue; // this one is disabled.
- }
-
- if (gl_texcoord_index[i] != -1) {
- glClientActiveTexture(GL_TEXTURE0+gl_texcoord_index[i]);
- }
-
- glEnableClientState(gl_client_states[i]);
-
- switch (i) {
-
- case VS::ARRAY_VERTEX: {
-
- glVertexPointer(3,ad.datatype,stride,&base[ad.ofs]);
-
- } break; /* fallthrough to normal */
- case VS::ARRAY_NORMAL: {
-
- glNormalPointer(ad.datatype,stride,&base[ad.ofs]);
- } break;
- case VS::ARRAY_COLOR: {
- glColorPointer(4,ad.datatype,stride,&base[ad.ofs]);
- } break;
- case VS::ARRAY_TEX_UV:
- case VS::ARRAY_TEX_UV2: {
-
- glTexCoordPointer(2,ad.datatype,stride,&base[ad.ofs]);
- } break;
- case VS::ARRAY_TANGENT: {
-
- //glVertexAttribPointer(i, 4, use_VBO?GL_BYTE:GL_FLOAT, use_VBO?GL_TRUE:GL_FALSE, stride, &base[ad.ofs]);
-
- } break;
- case VS::ARRAY_BONES:
- case VS::ARRAY_WEIGHTS: {
-
- //do none
- //glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, surf->stride, &base[ad.ofs]);
-
- } break;
- case VS::ARRAY_INDEX:
- ERR_PRINT("Bug");
- break;
- };
- }
-
-
- } break;
-
- default: break;
-
- };
-
- return OK;
-};
-
-static const GLenum gl_primitive[]={
- GL_POINTS,
- GL_LINES,
- GL_LINE_STRIP,
- GL_LINE_LOOP,
- GL_TRIANGLES,
- GL_TRIANGLE_STRIP,
- GL_TRIANGLE_FAN
-};
-
-static const GLenum gl_poly_primitive[4]={
- GL_POINTS,
- GL_LINES,
- GL_TRIANGLES,
- //GL_QUADS
-
-};
-
-
-void RasterizerGLES1::_render(const Geometry *p_geometry,const Material *p_material, const Skeleton* p_skeleton, const GeometryOwner *p_owner) {
-
-
- _rinfo.object_count++;
-
- switch(p_geometry->type) {
-
- case Geometry::GEOMETRY_SURFACE: {
-
- Surface *s = (Surface*)p_geometry;
-
- _rinfo.vertex_count+=s->array_len;
-
- if (s->packed && s->array_local==0) {
-
- float sc = (1.0/32767.0)*s->vertex_scale;
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glScalef(sc,sc,sc);
- if (s->format&VS::ARRAY_FORMAT_TEX_UV) {
- float uvs=(1.0/32767.0)*s->uv_scale;
- //glActiveTexture(GL_TEXTURE0);
- glClientActiveTexture(GL_TEXTURE0);
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glScalef(uvs,uvs,uvs);
- }
-
-
- }
-
-
- if (s->index_array_len>0) {
-
- if (s->index_array_local) {
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
- glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len>(1<<16))?GL_UNSIGNED_SHORT:GL_UNSIGNED_SHORT, s->index_array_local);
-
- } else {
- // print_line("indices: "+itos(s->index_array_local) );
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,s->index_id);
- glDrawElements(gl_primitive[s->primitive],s->index_array_len, (s->array_len>(1<<16))?GL_UNSIGNED_SHORT:GL_UNSIGNED_SHORT,0);
- }
-
-
- } else {
-
- glDrawArrays(gl_primitive[s->primitive],0,s->array_len);
-
- };
-
- if (s->packed && s->array_local==0) {
- if (s->format&VS::ARRAY_FORMAT_TEX_UV) {
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- }
- glPopMatrix();
- };
- } break;
-
- case Geometry::GEOMETRY_MULTISURFACE: {
-
- Surface *s = static_cast<const MultiMeshSurface*>(p_geometry)->surface;
- const MultiMesh *mm = static_cast<const MultiMesh*>(p_owner);
- int element_count=mm->elements.size();
-
- if (element_count==0)
- return;
-
- const MultiMesh::Element *elements=&mm->elements[0];
-
- _rinfo.vertex_count+=s->array_len*element_count;
-
-
- if (s->index_array_len>0) {
-
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,s->index_id);
- for(int i=0;i<element_count;i++) {
- //glUniformMatrix4fv(material_shader.get_uniform_location(MaterialShaderGLES1::INSTANCE_TRANSFORM), 1, false, elements[i].matrix);
- glDrawElements(gl_primitive[s->primitive],s->index_array_len, (s->array_len>(1<<16))?GL_UNSIGNED_SHORT:GL_UNSIGNED_SHORT,0);
- }
-
-
- } else {
-
- for(int i=0;i<element_count;i++) {
-// glUniformMatrix4fv(material_shader.get_uniform_location(MaterialShaderGLES1::INSTANCE_TRANSFORM), 1, false, elements[i].matrix);
- glDrawArrays(gl_primitive[s->primitive],0,s->array_len);
- }
-
-
- };
- } break;
- case Geometry::GEOMETRY_PARTICLES: {
-
-
- //print_line("particulinas");
- const Particles *particles = static_cast<const Particles*>( p_geometry );
- ERR_FAIL_COND(!p_owner);
- ParticlesInstance *particles_instance = (ParticlesInstance*)p_owner;
-
- ParticleSystemProcessSW &pp = particles_instance->particles_process;
- float td = time_delta; //MIN(time_delta,1.0/10.0);
- pp.process(&particles->data,particles_instance->transform,td);
- ERR_EXPLAIN("A parameter in the particle system is not correct.");
- ERR_FAIL_COND(!pp.valid);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
- glBindBuffer(GL_ARRAY_BUFFER,0);
-
-
- Transform camera;
- if (shadow)
- camera=shadow->transform;
- else
- camera=camera_transform;
-
- particle_draw_info.prepare(&particles->data,&pp,particles_instance->transform,camera);
-
- _rinfo.vertex_count+=4*particles->data.amount;
-
- {
- static const Vector3 points[4]={
- Vector3(-1.0,1.0,0),
- Vector3(1.0,1.0,0),
- Vector3(1.0,-1.0,0),
- Vector3(-1.0,-1.0,0)
- };
- static const Vector3 uvs[4]={
- Vector3(0.0,0.0,0.0),
- Vector3(1.0,0.0,0.0),
- Vector3(1.0,1.0,0.0),
- Vector3(0,1.0,0.0)
- };
- static const Vector3 normals[4]={
- Vector3(0,0,1),
- Vector3(0,0,1),
- Vector3(0,0,1),
- Vector3(0,0,1)
- };
-
- static const Plane tangents[4]={
- Plane(Vector3(1,0,0),0),
- Plane(Vector3(1,0,0),0),
- Plane(Vector3(1,0,0),0),
- Plane(Vector3(1,0,0),0)
- };
-
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- _gl_load_transform(camera_transform_inverse);
- for(int i=0;i<particles->data.amount;i++) {
-
- ParticleSystemDrawInfoSW::ParticleDrawInfo &pinfo=*particle_draw_info.draw_info_order[i];
- if (!pinfo.data->active)
- continue;
- glPushMatrix();
- _gl_mult_transform(pinfo.transform);
-
- glColor4f(pinfo.color.r*last_color.r,pinfo.color.g*last_color.g,pinfo.color.b*last_color.b,pinfo.color.a*last_color.a);
- _draw_primitive(4,points,normals,NULL,uvs,tangents);
- glPopMatrix();
-
- }
- glPopMatrix();
-
- }
-
- } break;
- default: break;
- };
-
-};
-
-void RasterizerGLES1::_setup_shader_params(const Material *p_material) {
-#if 0
- int idx=0;
- int tex_idx=0;
-
- for(Map<StringName,Variant>::Element *E=p_material->shader_cache->params.front();E;E=E->next(),idx++) {
-
- Variant v; //
- v = E->get();
- const Map<StringName,Variant>::Element *F=p_material->shader_params.find(E->key());
- if (F)
- v=F->get();
-
- switch(v.get_type() ) {
- case Variant::OBJECT:
- case Variant::_RID: {
-
- RID tex=v;
- if (!tex.is_valid())
- break;
-
- Texture *texture = texture_owner.get(tex);
- if (!texture)
- break;
- glUniform1i( material_shader.get_custom_uniform_location(idx), tex_idx);
- glActiveTexture(tex_idx);
- glBindTexture(texture->target,texture->tex_id);
-
- } break;
- case Variant::COLOR: {
-
- Color c=v;
- material_shader.set_custom_uniform(idx,Vector3(c.r,c.g,c.b));
- } break;
- default: {
-
- material_shader.set_custom_uniform(idx,v);
- } break;
- }
-
- }
-#endif
-
-}
-
-void RasterizerGLES1::_render_list_forward(RenderList *p_render_list,bool p_reverse_cull) {
-
- const Material *prev_material=NULL;
- uint64_t prev_light_key=0;
- const Skeleton *prev_skeleton=NULL;
- const Geometry *prev_geometry=NULL;
-
- Geometry::Type prev_geometry_type=Geometry::GEOMETRY_INVALID;
-
- for (int i=0;i<p_render_list->element_count;i++) {
-
- RenderList::Element *e = p_render_list->elements[i];
- const Material *material = e->material;
- uint64_t light_key = e->light_key;
- const Skeleton *skeleton = e->skeleton;
- const Geometry *geometry = e->geometry;
-
- if (material!=prev_material || geometry->type!=prev_geometry_type) {
- _setup_material(e->geometry,material);
- _rinfo.mat_change_count++;
- //_setup_material_overrides(e->material,NULL,material_overrides);
- //_setup_material_skeleton(material,skeleton);
- } else {
-
- if (prev_skeleton!=skeleton) {
- //_setup_material_skeleton(material,skeleton);
- };
- }
-
-
- if (geometry!=prev_geometry || geometry->type!=prev_geometry_type || prev_skeleton!=skeleton) {
-
- _setup_geometry(geometry, material,e->skeleton,e->instance->morph_values.ptr());
- };
-
- if (i==0 || light_key!=prev_light_key)
- _setup_lights(e->lights,e->light_count);
-
- _set_cull(e->mirror,p_reverse_cull);
-
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- glPushMatrix();
-
-
- if (e->instance->billboard || e->instance->depth_scale) {
-
- Transform xf=e->instance->transform;
- if (e->instance->depth_scale) {
-
- if (camera_projection.matrix[3][3]) {
- //orthogonal matrix, try to do about the same
- //with viewport size
- //real_t w = Math::abs( 1.0/(2.0*(p_projection.matrix[0][0])) );
- real_t h = Math::abs( 1.0/(2.0*camera_projection.matrix[1][1]) );
- float sc = (h*2.0); //consistent with Y-fov
- xf.basis.scale( Vector3(sc,sc,sc));
- } else {
- //just scale by depth
- real_t sc = -camera_plane.distance_to(xf.origin);
- xf.basis.scale( Vector3(sc,sc,sc));
- }
- }
-
- if (e->instance->billboard) {
-
- Vector3 scale = xf.basis.get_scale();
- xf.set_look_at(xf.origin,xf.origin+camera_transform.get_basis().get_axis(2),camera_transform.get_basis().get_axis(1));
- xf.basis.scale(scale);
- }
- _gl_mult_transform(xf); // for fixed pipeline
-
- } else {
- _gl_mult_transform(e->instance->transform); // for fixed pipeline
- }
-
-
-
- //bool changed_shader = material_shader.bind();
- //if ( changed_shader && material->shader_cache && !material->shader_cache->params.empty())
- // _setup_shader_params(material);
-
- _render(geometry, material, skeleton,e->owner);
-
-
-
- prev_material=material;
- prev_skeleton=skeleton;
- prev_geometry=geometry;
- prev_light_key=e->light_key;
- prev_geometry_type=geometry->type;
- }
-
-
-
-};
-
-
-
-void RasterizerGLES1::end_scene() {
-
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- depth_write=true;
- depth_test=true;
-
- if (scene_fx && scene_fx->skybox_active) {
-
- //skybox
- } else if (scene_fx && scene_fx->bgcolor_active) {
-
- glClearColor(scene_fx->bgcolor.r,scene_fx->bgcolor.g,scene_fx->bgcolor.b,1.0);
-
- } else {
-
- glClearColor(0.3,0.3,0.3,1.0);
- }
-#ifdef GLES_OVER_GL
- //glClearDepth(1.0);
-#else
- //glClearDepthf(1.0);
-#endif
-
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-
- if (scene_fx && scene_fx->fog_active) {
-
- /*
- glEnable(GL_FOG);
- glFogf(GL_FOG_MODE,GL_LINEAR);
- glFogf(GL_FOG_DENSITY,scene_fx->fog_attenuation);
- glFogf(GL_FOG_START,scene_fx->fog_near);
- glFogf(GL_FOG_END,scene_fx->fog_far);
- glFogfv(GL_FOG_COLOR,scene_fx->fog_color_far.components);
- glLightfv(GL_LIGHT5,GL_DIFFUSE,scene_fx->fog_color_near.components);
-
- material_shader.set_conditional( MaterialShaderGLES1::USE_FOG,true);
- */
- }
-
-
-
- for(int i=0;i<directional_light_count;i++) {
-
- glEnable(GL_LIGHT0+i);
- _setup_light(directional_lights[i],i);
- }
-
- opaque_render_list.sort_mat_light();
-
- //material_shader.set_uniform_camera(MaterialShaderGLES1::PROJECTION_MATRIX, camera_projection);
-
- /*
- printf("setting projection to ");
- for (int i=0; i<16; i++) {
- printf("%f, ", ((float*)camera_projection.matrix)[i]);
- };
- printf("\n");
-
- print_line(String("setting camera to ")+camera_transform_inverse);
- */
-// material_shader.set_uniform_default(MaterialShaderGLES1::CAMERA_INVERSE, camera_transform_inverse);
-
- //projection
- //glEnable(GL_RESCALE_NORMAL);
- glEnable(GL_NORMALIZE);
-
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(&camera_projection.matrix[0][0]);
- //modelview (fixedpipie)
- glMatrixMode(GL_MODELVIEW);
- _gl_load_transform(camera_transform_inverse);
- glPushMatrix();
-
- glDisable(GL_BLEND);
-
- blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
- lighting=true;
- glEnable(GL_LIGHTING);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-
- _render_list_forward(&opaque_render_list);
-
-
- alpha_render_list.sort_z();
- glEnable(GL_BLEND);
-
- _render_list_forward(&alpha_render_list);
-
- glPopMatrix();
-
-
-// material_shader.set_conditional( MaterialShaderGLES1::USE_FOG,false);
-
- _debug_shadows();
-}
-void RasterizerGLES1::end_shadow_map() {
-#if 0
- ERR_FAIL_COND(!shadow);
- ERR_FAIL_INDEX(shadow_pass,shadow->shadow_buffers.size());
-
- glDisable(GL_BLEND);
- glDisable(GL_SCISSOR_TEST);
- glEnable(GL_DEPTH_TEST);
- glDepthMask(true);
-
-
- ShadowBuffer *sb = shadow->shadow_buffers[shadow_pass];
-
- ERR_FAIL_COND(!sb);
-
- glBindFramebuffer(GL_FRAMEBUFFER, sb->fbo);
- glViewport(0, 0, sb->size, sb->size);
-
- glColorMask(0, 0, 0, 0);
-
- glEnable(GL_POLYGON_OFFSET_FILL);
- //glPolygonOffset(4,8);
- glPolygonOffset( 4.0f, 4096.0f);
- glPolygonOffset( 8.0f, 16.0f);
-
- glClearDepth(1.0f);
- glClear(GL_DEPTH_BUFFER_BIT);
- CameraMatrix cm;
- float z_near,z_far;
- Transform light_transform;
-
- float dp_direction=0.0;
- bool flip_facing=false;
-
- switch(shadow->base->type) {
-
- case VS::LIGHT_DIRECTIONAL: {
-
- cm = shadow->custom_projection;
- light_transform=shadow->custom_transform;
- z_near=cm.get_z_near();
- z_far=cm.get_z_far();
-
- } break;
- case VS::LIGHT_OMNI: {
-
- material_shader.set_conditional(MaterialShaderGLES1::USE_DUAL_PARABOLOID,true);
- dp_direction = shadow_pass?1.0:0.0;
- flip_facing = (shadow_pass == 1);
- light_transform=shadow->transform;
- z_near=0;
- z_far=shadow->base->vars[ VS::LIGHT_VAR_RADIUS ];
- } break;
- case VS::LIGHT_SPOT: {
-
- float far = shadow->base->vars[ VS::LIGHT_VAR_RADIUS ];
- ERR_FAIL_COND( far<=0 );
- float near= far/200.0;
- if (near<0.05)
- near=0.05;
-
- float angle = shadow->base->vars[ VS::LIGHT_VAR_SPOT_ANGLE ];
-
- cm.set_perspective( angle*2.0, 1.0, near, far );
- shadow->projection=cm; // cache
- light_transform=shadow->transform;
- z_near=cm.get_z_near();
- z_far=cm.get_z_far();
-
- } break;
- }
-
- Transform light_transform_inverse = light_transform.inverse();
-
- opaque_render_list.sort_mat();
-
- glLightf(GL_LIGHT5,GL_LINEAR_ATTENUATION,z_near);
- glLightf(GL_LIGHT5,GL_QUADRATIC_ATTENUATION,z_far);
- glLightf(GL_LIGHT5,GL_CONSTANT_ATTENUATION,dp_direction);
-
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(&cm.matrix[0][0]);
- glMatrixMode(GL_MODELVIEW);
- _gl_load_transform(light_transform_inverse);
- glPushMatrix();
-
- for(int i=0;i<4;i++) {
- for(int j=0;j<3;j++) {
-
- material_shader.set_conditional(_gl_light_version[i][j],false); //start false by default
- }
- material_shader.set_conditional(_gl_light_shadow[i],false);
- }
-
- _render_list_forward(&opaque_render_list,flip_facing);
-
- material_shader.set_conditional(MaterialShaderGLES1::USE_DUAL_PARABOLOID,false);
- glViewport( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height );
- if (framebuffer.active)
- glBindFramebufferEXT(GL_FRAMEBUFFER,framebuffer.fbo);
- else
- glBindFramebufferEXT(GL_FRAMEBUFFER,0);
-
- glDisable(GL_POLYGON_OFFSET_FILL);
-
- glColorMask(1, 1, 1, 1);
- shadow=NULL;
-#endif
-}
-
-void RasterizerGLES1::_debug_draw_shadow(ShadowBuffer *p_buffer, const Rect2& p_rect) {
-
-/*
-
- Transform modelview;
- modelview.translate(-(viewport.width / 2.0f), -(viewport.height / 2.0f), 0.0f);
- modelview.scale( Vector3( 2.0f / viewport.width, -2.0f / viewport.height, 1.0f ) );
- modelview.translate(p_rect.pos.x, p_rect.pos.y, 0);
- material_shader.set_uniform_default(MaterialShaderGLES1::MODELVIEW_TRANSFORM, *e->transform);
- glBindTexture(GL_TEXTURE_2D,p_buffer->depth);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
-
- Vector3 coords[4]= {
- Vector3(p_rect.pos.x, p_rect.pos.y, 0 ),
- Vector3(p_rect.pos.x+p_rect.size.width,
- p_rect.pos.y, 0 ),
- Vector3(p_rect.pos.x+p_rect.size.width,
- p_rect.pos.y+p_rect.size.height, 0 ),
- Vector3(p_rect.pos.x,
- p_rect.pos.y+p_rect.size.height, 0 )
- };
-
- Vector3 texcoords[4]={
- Vector3( 0.0f,0.0f, 0),
- Vector3( 1.0f,0.0f, 0),
- Vector3( 1.0f, 1.0f, 0),
- Vector3( 0.0f, 1.0f, 0),
- };
-
- _draw_primitive(4,coords,0,0,texcoords);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
-*/
-}
-
-void RasterizerGLES1::_debug_draw_shadows_type(Vector<ShadowBuffer>& p_shadows,Point2& ofs) {
-
-
-// Size2 debug_size(128,128);
- Size2 debug_size(512,512);
-
- for (int i=0;i<p_shadows.size();i++) {
-
- ShadowBuffer *sb=&p_shadows[i];
-
- if (!sb->owner)
- continue;
-
- if (sb->owner->base->type==VS::LIGHT_DIRECTIONAL) {
-
- if (sb->owner->shadow_pass!=scene_pass-1)
- continue;
- } else {
-
- if (sb->owner->shadow_pass!=frame)
- continue;
- }
- _debug_draw_shadow(sb, Rect2( ofs, debug_size ));
- ofs.x+=debug_size.x;
- if ( (ofs.x+debug_size.x) > viewport.width ) {
-
- ofs.x=0;
- ofs.y+=debug_size.y;
- }
- }
-
-}
-
-
-void RasterizerGLES1::_debug_shadows() {
-
- return;
-#if 0
- canvas_begin();
- glUseProgram(0);
- glDisable(GL_BLEND);
- Size2 ofs;
-
- /*
- for(int i=0;i<16;i++) {
- glActiveTexture(GL_TEXTURE0+i);
- //glDisable(GL_TEXTURE_2D);
- }
- glActiveTexture(GL_TEXTURE0);
- //glEnable(GL_TEXTURE_2D);
- */
-
-
- _debug_draw_shadows_type(near_shadow_buffers,ofs);
- _debug_draw_shadows_type(far_shadow_buffers,ofs);
-#endif
-}
-
-void RasterizerGLES1::end_frame() {
-
- /*
- if (framebuffer.active) {
-
- canvas_begin(); //resets stuff and goes back to fixedpipe
- glBindFramebuffer(GL_FRAMEBUFFER,0);
-
- //copy to main bufferz
- glEnable(GL_TEXTURE_2D);
-
- glBindTexture(GL_TEXTURE_2D,framebuffer.color);
- glBegin(GL_QUADS);
- glTexCoord2f(0,0);
- glVertex2f(-1,-1);
- glTexCoord2f(0,1);
- glVertex2f(-1,+1);
- glTexCoord2f(1,1);
- glVertex2f(+1,+1);
- glTexCoord2f(1,0);
- glVertex2f(+1,-1);
- glEnd();
-
-
- }
- */
-
- //print_line("VTX: "+itos(_rinfo.vertex_count)+" OBJ: "+itos(_rinfo.object_count)+" MAT: "+itos(_rinfo.mat_change_count)+" SHD: "+itos(_rinfo.shader_change_count));
-
- OS::get_singleton()->swap_buffers();
-}
-
-/* CANVAS API */
-
-
-void RasterizerGLES1::reset_state() {
-
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
- glBindBuffer(GL_ARRAY_BUFFER,0);
-
- glActiveTexture(GL_TEXTURE0);
- glClientActiveTexture(GL_TEXTURE0);
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glColor4f(1,1,1,1);
-
- glDisable(GL_CULL_FACE);
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
-// glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-// glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
- canvas_blend=VS::MATERIAL_BLEND_MODE_MIX;
- glLineWidth(1.0);
- glDisable(GL_LIGHTING);
-
-}
-
-_FORCE_INLINE_ static void _set_glcoloro(const Color& p_color,const float p_opac) {
-
- glColor4f(p_color.r, p_color.g, p_color.b, p_color.a*p_opac);
-}
-
-
-void RasterizerGLES1::canvas_begin() {
-
-
- reset_state();
- canvas_opacity=1.0;
- glEnable(GL_BLEND);
-
-
-}
-
-void RasterizerGLES1::canvas_disable_blending() {
-
- glDisable(GL_BLEND);
-}
-
-void RasterizerGLES1::canvas_set_opacity(float p_opacity) {
-
- canvas_opacity = p_opacity;
-}
-
-void RasterizerGLES1::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) {
-
- switch(p_mode) {
-
- case VS::MATERIAL_BLEND_MODE_MIX: {
- //glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-
- } break;
- case VS::MATERIAL_BLEND_MODE_ADD: {
-
- //glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE);
-
- } break;
- case VS::MATERIAL_BLEND_MODE_SUB: {
-
- //glBlendEquation(GL_FUNC_SUBTRACT);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE);
- } break;
- case VS::MATERIAL_BLEND_MODE_MUL: {
- //glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-
- } break;
-
- }
-
-}
-
-
-void RasterizerGLES1::canvas_begin_rect(const Matrix32& p_transform) {
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glScalef(2.0 / viewport.width, -2.0 / viewport.height, 0);
- glTranslatef((-(viewport.width / 2.0)), (-(viewport.height / 2.0)), 0);
- _gl_mult_transform(p_transform);
-
- glPushMatrix();
-
-}
-
-void RasterizerGLES1::canvas_set_clip(bool p_clip, const Rect2& p_rect) {
-
- if (p_clip) {
-
- glEnable(GL_SCISSOR_TEST);
- // glScissor(viewport.x+p_rect.pos.x,viewport.y+ (viewport.height-(p_rect.pos.y+p_rect.size.height)),
- //p_rect.size.width,p_rect.size.height);
- //glScissor(p_rect.pos.x,(viewport.height-(p_rect.pos.y+p_rect.size.height)),p_rect.size.width,p_rect.size.height);
- glScissor(viewport.x+p_rect.pos.x,viewport.y+ (window_size.y-(p_rect.pos.y+p_rect.size.height)),
- p_rect.size.width,p_rect.size.height);
- } else {
-
- glDisable(GL_SCISSOR_TEST);
- }
-
-
-}
-
-void RasterizerGLES1::canvas_end_rect() {
-
- glPopMatrix();
-}
-
-void RasterizerGLES1::canvas_draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width) {
-
- glDisable(GL_TEXTURE_2D);
- _set_glcoloro( p_color,canvas_opacity );
-
- Vector3 verts[2]={
- Vector3(p_from.x,p_from.y,0),
- Vector3(p_to.x,p_to.y,0)
- };
- Color colors[2]={
- p_color,
- p_color
- };
- colors[0].a*=canvas_opacity;
- colors[1].a*=canvas_opacity;
- glLineWidth(p_width);
- _draw_primitive(2,verts,0,colors,0);
-
-}
-
-static void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_flip_h=false,bool p_flip_v=false ) {
-
-
- Vector3 texcoords[4]= {
- Vector3( p_src_region.pos.x/p_tex_size.width,
- p_src_region.pos.y/p_tex_size.height, 0),
-
- Vector3((p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width,
- p_src_region.pos.y/p_tex_size.height, 0),
-
- Vector3( (p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width,
- (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0),
-
- Vector3( p_src_region.pos.x/p_tex_size.width,
- (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height, 0)
- };
-
-
- if (p_flip_h) {
- SWAP( texcoords[0], texcoords[1] );
- SWAP( texcoords[2], texcoords[3] );
- }
- if (p_flip_v) {
- SWAP( texcoords[1], texcoords[2] );
- SWAP( texcoords[0], texcoords[3] );
- }
-
- Vector3 coords[4]= {
- Vector3( p_rect.pos.x, p_rect.pos.y, 0 ),
- Vector3( p_rect.pos.x+p_rect.size.width, p_rect.pos.y, 0 ),
- Vector3( p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height, 0 ),
- Vector3( p_rect.pos.x,p_rect.pos.y+p_rect.size.height, 0 )
- };
-
- _draw_primitive(4,coords,0,0,texcoords);
-}
-
-static void _draw_quad(const Rect2& p_rect) {
-
- Vector3 coords[4]= {
- Vector3( p_rect.pos.x,p_rect.pos.y, 0 ),
- Vector3( p_rect.pos.x+p_rect.size.width,p_rect.pos.y, 0 ),
- Vector3( p_rect.pos.x+p_rect.size.width,p_rect.pos.y+p_rect.size.height, 0 ),
- Vector3( p_rect.pos.x,p_rect.pos.y+p_rect.size.height, 0 )
- };
-
- _draw_primitive(4,coords,0,0,0);
-
-}
-
-
-void RasterizerGLES1::canvas_draw_rect(const Rect2& p_rect, int p_flags, const Rect2& p_source,RID p_texture,const Color& p_modulate) {
-
- _set_glcoloro( p_modulate,canvas_opacity );
-
- if ( p_texture.is_valid() ) {
-
- glEnable(GL_TEXTURE_2D);
- Texture *texture = texture_owner.get( p_texture );
- ERR_FAIL_COND(!texture);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture( GL_TEXTURE_2D,texture->tex_id );
-
- if (!(p_flags&CANVAS_RECT_REGION)) {
-
- Rect2 region = Rect2(0,0,texture->width,texture->height);
- _draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V);
-
- } else {
-
-
- _draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V );
-
- }
- } else {
-
- glDisable(GL_TEXTURE_2D);
- _draw_quad( p_rect );
-
- }
-
-
-}
-void RasterizerGLES1::canvas_draw_style_box(const Rect2& p_rect, RID p_texture,const float *p_margin, bool p_draw_center,const Color& p_modulate) {
-
- _set_glcoloro( p_modulate,canvas_opacity );
-
-
- Texture *texture = texture_owner.get( p_texture );
- ERR_FAIL_COND(!texture);
-
- glEnable(GL_TEXTURE_2D);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture( GL_TEXTURE_2D,texture->tex_id );
-
-
- /* CORNERS */
-
- _draw_textured_quad( // top left
- Rect2( p_rect.pos, Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_TOP])),
- Rect2( Point2(), Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_TOP])),
- Size2( texture->width, texture->height ) );
-
- _draw_textured_quad( // top right
- Rect2( Point2( p_rect.pos.x + p_rect.size.width - p_margin[MARGIN_RIGHT], p_rect.pos.y), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_TOP])),
- Rect2( Point2(texture->width-p_margin[MARGIN_RIGHT],0), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_TOP])),
- Size2( texture->width, texture->height ) );
-
-
- _draw_textured_quad( // bottom left
- Rect2( Point2(p_rect.pos.x,p_rect.pos.y + p_rect.size.height - p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_BOTTOM])),
- Rect2( Point2(0,texture->height-p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_BOTTOM])),
- Size2( texture->width, texture->height ) );
-
- _draw_textured_quad( // bottom right
- Rect2( Point2( p_rect.pos.x + p_rect.size.width - p_margin[MARGIN_RIGHT], p_rect.pos.y + p_rect.size.height - p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_BOTTOM])),
- Rect2( Point2(texture->width-p_margin[MARGIN_RIGHT],texture->height-p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_BOTTOM])),
- Size2( texture->width, texture->height ) );
-
- Rect2 rect_center( p_rect.pos+Point2( p_margin[MARGIN_LEFT], p_margin[MARGIN_TOP]), Size2( p_rect.size.width - p_margin[MARGIN_LEFT] - p_margin[MARGIN_RIGHT], p_rect.size.height - p_margin[MARGIN_TOP] - p_margin[MARGIN_BOTTOM] ));
-
- Rect2 src_center( Point2( p_margin[MARGIN_LEFT], p_margin[MARGIN_TOP]), Size2( texture->width - p_margin[MARGIN_LEFT] - p_margin[MARGIN_RIGHT], texture->height - p_margin[MARGIN_TOP] - p_margin[MARGIN_BOTTOM] ));
-
-
- _draw_textured_quad( // top
- Rect2( Point2(rect_center.pos.x,p_rect.pos.y),Size2(rect_center.size.width,p_margin[MARGIN_TOP])),
- Rect2( Point2(p_margin[MARGIN_LEFT],0), Size2(src_center.size.width,p_margin[MARGIN_TOP])),
- Size2( texture->width, texture->height ) );
-
- _draw_textured_quad( // bottom
- Rect2( Point2(rect_center.pos.x,rect_center.pos.y+rect_center.size.height),Size2(rect_center.size.width,p_margin[MARGIN_BOTTOM])),
- Rect2( Point2(p_margin[MARGIN_LEFT],src_center.pos.y+src_center.size.height), Size2(src_center.size.width,p_margin[MARGIN_BOTTOM])),
- Size2( texture->width, texture->height ) );
-
- _draw_textured_quad( // left
- Rect2( Point2(p_rect.pos.x,rect_center.pos.y),Size2(p_margin[MARGIN_LEFT],rect_center.size.height)),
- Rect2( Point2(0,p_margin[MARGIN_TOP]), Size2(p_margin[MARGIN_LEFT],src_center.size.height)),
- Size2( texture->width, texture->height ) );
-
- _draw_textured_quad( // right
- Rect2( Point2(rect_center.pos.x+rect_center.size.width,rect_center.pos.y),Size2(p_margin[MARGIN_RIGHT],rect_center.size.height)),
- Rect2( Point2(src_center.pos.x+src_center.size.width,p_margin[MARGIN_TOP]), Size2(p_margin[MARGIN_RIGHT],src_center.size.height)),
- Size2( texture->width, texture->height ) );
-
- if (p_draw_center) {
-
- _draw_textured_quad(
- rect_center,
- src_center,
- Size2( texture->width, texture->height ));
- }
-
-}
-void RasterizerGLES1::canvas_draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width) {
-
- ERR_FAIL_COND(p_points.size()<1);
- Vector3 verts[4];
- Vector3 uvs[4];
-
- _set_glcoloro( Color(1,1,1),canvas_opacity );
-
- for(int i=0;i<p_points.size();i++) {
-
- verts[i]=Vector3(p_points[i].x,p_points[i].y,0);
- }
-
- for(int i=0;i<p_uvs.size();i++) {
-
- uvs[i]=Vector3(p_uvs[i].x,p_uvs[i].y,0);
- }
-
- if (p_texture.is_valid()) {
- glEnable(GL_TEXTURE_2D);
- Texture *texture = texture_owner.get( p_texture );
- if (texture) {
- glActiveTexture(GL_TEXTURE0);
- glBindTexture( GL_TEXTURE_2D,texture->tex_id );
- }
- }
-
- glLineWidth(p_width);
- _draw_primitive(p_points.size(),&verts[0],NULL,p_colors.size()?&p_colors[0]:NULL,p_uvs.size()?uvs:NULL);
-
-}
-
-static const int _max_draw_poly_indices = 8*1024;
-static uint16_t _draw_poly_indices[_max_draw_poly_indices];
-static float _verts3[_max_draw_poly_indices];
-
-void RasterizerGLES1::canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor) {
-
- bool do_colors=false;
-
- //reset_state();
- if (p_singlecolor) {
- Color m = *p_colors;
- m.a*=canvas_opacity;
- glColor4f(m.r, m.g, m.b, m.a);
- } else if (!p_colors) {
- glColor4f(1, 1, 1, canvas_opacity);
- } else
- do_colors=true;
-
- glColor4f(1, 1, 1, 1);
-
- Texture* texture = NULL;
- if (p_texture.is_valid()) {
- glEnable(GL_TEXTURE_2D);
- texture = texture_owner.get( p_texture );
- if (texture) {
- glActiveTexture(GL_TEXTURE0);
- glBindTexture( GL_TEXTURE_2D,texture->tex_id );
- }
- }
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, (GLvoid*)p_vertices);
- if (do_colors) {
-
- glEnableClientState(GL_COLOR_ARRAY);
- glColorPointer(4,GL_FLOAT, 0, p_colors);
-
- } else {
- glDisableClientState(GL_COLOR_ARRAY);
- }
-
- if (texture && p_uvs) {
-
- glClientActiveTexture(GL_TEXTURE0);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, 0, p_uvs);
-
- } else {
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
-
- if (p_indices) {
-
- for (int i=0; i<p_vertex_count; i++) {
- _draw_poly_indices[i] = p_indices[i];
- };
- glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_SHORT, _draw_poly_indices );
- } else {
-
- glDrawArrays(GL_TRIANGLES,0,p_vertex_count);
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-}
-
-void RasterizerGLES1::canvas_set_transform(const Matrix32& p_transform) {
-
- //restore
- glPopMatrix();
- glPushMatrix();
- //set
- _gl_mult_transform(p_transform);
-}
-
-/* FX */
-
-RID RasterizerGLES1::fx_create() {
-
- FX *fx = memnew( FX );
- ERR_FAIL_COND_V(!fx,RID());
- return fx_owner.make_rid(fx);
-
-}
-void RasterizerGLES1::fx_get_effects(RID p_fx,List<String> *p_effects) const {
-
- FX *fx = fx_owner.get(p_fx);
- ERR_FAIL_COND(!fx);
-
- p_effects->clear();
- p_effects->push_back("bgcolor");
- p_effects->push_back("skybox");
- p_effects->push_back("antialias");
- //p_effects->push_back("hdr");
- p_effects->push_back("glow"); // glow has a bloom parameter, too
- p_effects->push_back("ssao");
- p_effects->push_back("fog");
- p_effects->push_back("dof_blur");
- p_effects->push_back("toon");
- p_effects->push_back("edge");
-
-}
-void RasterizerGLES1::fx_set_active(RID p_fx,const String& p_effect, bool p_active) {
-
- FX *fx = fx_owner.get(p_fx);
- ERR_FAIL_COND(!fx);
-
- if (p_effect=="bgcolor")
- fx->bgcolor_active=p_active;
- else if (p_effect=="skybox")
- fx->skybox_active=p_active;
- else if (p_effect=="antialias")
- fx->antialias_active=p_active;
- else if (p_effect=="glow")
- fx->glow_active=p_active;
- else if (p_effect=="ssao")
- fx->ssao_active=p_active;
- else if (p_effect=="fog")
- fx->fog_active=p_active;
-// else if (p_effect=="dof_blur")
-// fx->dof_blur_active=p_active;
- else if (p_effect=="toon")
- fx->toon_active=p_active;
- else if (p_effect=="edge")
- fx->edge_active=p_active;
-}
-bool RasterizerGLES1::fx_is_active(RID p_fx,const String& p_effect) const {
-
- FX *fx = fx_owner.get(p_fx);
- ERR_FAIL_COND_V(!fx,false);
-
- if (p_effect=="bgcolor")
- return fx->bgcolor_active;
- else if (p_effect=="skybox")
- return fx->skybox_active;
- else if (p_effect=="antialias")
- return fx->antialias_active;
- else if (p_effect=="glow")
- return fx->glow_active;
- else if (p_effect=="ssao")
- return fx->ssao_active;
- else if (p_effect=="fog")
- return fx->fog_active;
- //else if (p_effect=="dof_blur")
- // return fx->dof_blur_active;
- else if (p_effect=="toon")
- return fx->toon_active;
- else if (p_effect=="edge")
- return fx->edge_active;
-
- return false;
-}
-void RasterizerGLES1::fx_get_effect_params(RID p_fx,const String& p_effect,List<PropertyInfo> *p_params) const {
-
- FX *fx = fx_owner.get(p_fx);
- ERR_FAIL_COND(!fx);
-
-
- if (p_effect=="bgcolor") {
-
- p_params->push_back( PropertyInfo( Variant::COLOR, "color" ) );
- } else if (p_effect=="skybox") {
- p_params->push_back( PropertyInfo( Variant::_RID, "cubemap" ) );
- } else if (p_effect=="antialias") {
-
- p_params->push_back( PropertyInfo( Variant::REAL, "tolerance", PROPERTY_HINT_RANGE,"1,128,1" ) );
-
- } else if (p_effect=="glow") {
-
- p_params->push_back( PropertyInfo( Variant::INT, "passes", PROPERTY_HINT_RANGE,"1,4,1" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "attenuation", PROPERTY_HINT_RANGE,"0.01,8.0,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "bloom", PROPERTY_HINT_RANGE,"-1.0,1.0,0.01" ) );
-
- } else if (p_effect=="ssao") {
-
- p_params->push_back( PropertyInfo( Variant::REAL, "radius", PROPERTY_HINT_RANGE,"0.0,16.0,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "max_distance", PROPERTY_HINT_RANGE,"0.0,256.0,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "range_max", PROPERTY_HINT_RANGE,"0.0,1.0,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "range_min", PROPERTY_HINT_RANGE,"0.0,1.0,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "attenuation", PROPERTY_HINT_RANGE,"0.0,8.0,0.01" ) );
-
- } else if (p_effect=="fog") {
-
- p_params->push_back( PropertyInfo( Variant::REAL, "begin", PROPERTY_HINT_RANGE,"0.0,8192,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "end", PROPERTY_HINT_RANGE,"0.0,8192,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "attenuation", PROPERTY_HINT_RANGE,"0.0,8.0,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::COLOR, "color_begin" ) );
- p_params->push_back( PropertyInfo( Variant::COLOR, "color_end" ) );
- p_params->push_back( PropertyInfo( Variant::BOOL, "fog_bg" ) );
-
-// } else if (p_effect=="dof_blur") {
-// return fx->dof_blur_active;
- } else if (p_effect=="toon") {
- p_params->push_back( PropertyInfo( Variant::REAL, "treshold", PROPERTY_HINT_RANGE,"0.0,1.0,0.01" ) );
- p_params->push_back( PropertyInfo( Variant::REAL, "soft", PROPERTY_HINT_RANGE,"0.001,1.0,0.001" ) );
- } else if (p_effect=="edge") {
-
- }
-}
-Variant RasterizerGLES1::fx_get_effect_param(RID p_fx,const String& p_effect,const String& p_param) const {
-
- FX *fx = fx_owner.get(p_fx);
- ERR_FAIL_COND_V(!fx,Variant());
-
- if (p_effect=="bgcolor") {
-
- if (p_param=="color")
- return fx->bgcolor;
- } else if (p_effect=="skybox") {
- if (p_param=="cubemap")
- return fx->skybox_cubemap;
- } else if (p_effect=="antialias") {
-
- if (p_param=="tolerance")
- return fx->antialias_tolerance;
-
- } else if (p_effect=="glow") {
-
- if (p_param=="passes")
- return fx->glow_passes;
- if (p_param=="attenuation")
- return fx->glow_attenuation;
- if (p_param=="bloom")
- return fx->glow_bloom;
-
- } else if (p_effect=="ssao") {
-
- if (p_param=="attenuation")
- return fx->ssao_attenuation;
- if (p_param=="max_distance")
- return fx->ssao_max_distance;
- if (p_param=="range_max")
- return fx->ssao_range_max;
- if (p_param=="range_min")
- return fx->ssao_range_min;
- if (p_param=="radius")
- return fx->ssao_radius;
-
- } else if (p_effect=="fog") {
-
- if (p_param=="begin")
- return fx->fog_near;
- if (p_param=="end")
- return fx->fog_far;
- if (p_param=="attenuation")
- return fx->fog_attenuation;
- if (p_param=="color_begin")
- return fx->fog_color_near;
- if (p_param=="color_end")
- return fx->fog_color_far;
- if (p_param=="fog_bg")
- return fx->fog_bg;
-// } else if (p_effect=="dof_blur") {
-// return fx->dof_blur_active;
- } else if (p_effect=="toon") {
- if (p_param=="treshold")
- return fx->toon_treshold;
- if (p_param=="soft")
- return fx->toon_soft;
-
- } else if (p_effect=="edge") {
-
- }
- return Variant();
-}
-void RasterizerGLES1::fx_set_effect_param(RID p_fx,const String& p_effect, const String& p_param, const Variant& p_value) {
-
- FX *fx = fx_owner.get(p_fx);
- ERR_FAIL_COND(!fx);
-
- if (p_effect=="bgcolor") {
-
- if (p_param=="color")
- fx->bgcolor=p_value;
- } else if (p_effect=="skybox") {
- if (p_param=="cubemap")
- fx->skybox_cubemap=p_value;
-
- } else if (p_effect=="antialias") {
-
- if (p_param=="tolerance")
- fx->antialias_tolerance=p_value;
-
- } else if (p_effect=="glow") {
-
- if (p_param=="passes")
- fx->glow_passes=p_value;
- if (p_param=="attenuation")
- fx->glow_attenuation=p_value;
- if (p_param=="bloom")
- fx->glow_bloom=p_value;
-
- } else if (p_effect=="ssao") {
-
- if (p_param=="attenuation")
- fx->ssao_attenuation=p_value;
- if (p_param=="radius")
- fx->ssao_radius=p_value;
- if (p_param=="max_distance")
- fx->ssao_max_distance=p_value;
- if (p_param=="range_max")
- fx->ssao_range_max=p_value;
- if (p_param=="range_min")
- fx->ssao_range_min=p_value;
-
- } else if (p_effect=="fog") {
-
- if (p_param=="begin")
- fx->fog_near=p_value;
- if (p_param=="end")
- fx->fog_far=p_value;
- if (p_param=="attenuation")
- fx->fog_attenuation=p_value;
- if (p_param=="color_begin")
- fx->fog_color_near=p_value;
- if (p_param=="color_end")
- fx->fog_color_far=p_value;
- if (p_param=="fog_bg")
- fx->fog_bg=p_value;
-// } else if (p_effect=="dof_blur") {
-// fx->dof_blur_active=p_value;
- } else if (p_effect=="toon") {
-
- if (p_param=="treshold")
- fx->toon_treshold=p_value;
- if (p_param=="soft")
- fx->toon_soft=p_value;
-
- } else if (p_effect=="edge") {
-
- }
-
-}
-
-/* ENVIRONMENT */
-
-RID RasterizerGLES1::environment_create() {
-
- Environment * env = memnew( Environment );
- return environment_owner.make_rid(env);
-}
-
-void RasterizerGLES1::environment_set_background(RID p_env,VS::EnvironmentBG p_bg) {
-
- ERR_FAIL_INDEX(p_bg,VS::ENV_BG_MAX);
- Environment * env = environment_owner.get(p_env);
- ERR_FAIL_COND(!env);
- env->bg_mode=p_bg;
-}
-
-VS::EnvironmentBG RasterizerGLES1::environment_get_background(RID p_env) const{
-
- const Environment * env = environment_owner.get(p_env);
- ERR_FAIL_COND_V(!env,VS::ENV_BG_MAX);
- return env->bg_mode;
-}
-
-void RasterizerGLES1::environment_set_background_param(RID p_env,VS::EnvironmentBGParam p_param, const Variant& p_value){
-
- ERR_FAIL_INDEX(p_param,VS::ENV_BG_PARAM_MAX);
- Environment * env = environment_owner.get(p_env);
- ERR_FAIL_COND(!env);
- env->bg_param[p_param]=p_value;
-
-}
-Variant RasterizerGLES1::environment_get_background_param(RID p_env,VS::EnvironmentBGParam p_param) const{
-
- ERR_FAIL_INDEX_V(p_param,VS::ENV_BG_PARAM_MAX,Variant());
- const Environment * env = environment_owner.get(p_env);
- ERR_FAIL_COND_V(!env,Variant());
- return env->bg_param[p_param];
-
-}
-
-void RasterizerGLES1::environment_set_enable_fx(RID p_env,VS::EnvironmentFx p_effect,bool p_enabled){
-
- ERR_FAIL_INDEX(p_effect,VS::ENV_FX_MAX);
- Environment * env = environment_owner.get(p_env);
- ERR_FAIL_COND(!env);
- env->fx_enabled[p_effect]=p_enabled;
-}
-bool RasterizerGLES1::environment_is_fx_enabled(RID p_env,VS::EnvironmentFx p_effect) const{
-
- ERR_FAIL_INDEX_V(p_effect,VS::ENV_FX_MAX,false);
- const Environment * env = environment_owner.get(p_env);
- ERR_FAIL_COND_V(!env,false);
- return env->fx_enabled[p_effect];
-
-}
-
-void RasterizerGLES1::environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value){
-
- ERR_FAIL_INDEX(p_param,VS::ENV_FX_PARAM_MAX);
- Environment * env = environment_owner.get(p_env);
- ERR_FAIL_COND(!env);
- env->fx_param[p_param]=p_value;
-}
-Variant RasterizerGLES1::environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const{
-
- ERR_FAIL_INDEX_V(p_param,VS::ENV_FX_PARAM_MAX,Variant());
- const Environment * env = environment_owner.get(p_env);
- ERR_FAIL_COND_V(!env,Variant());
- return env->fx_param[p_param];
-
-}
-
-/*MISC*/
-
-bool RasterizerGLES1::is_texture(const RID& p_rid) const {
-
- return texture_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_material(const RID& p_rid) const {
-
- return material_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_mesh(const RID& p_rid) const {
-
- return mesh_owner.owns(p_rid);
-}
-
-bool RasterizerGLES1::is_immediate(const RID& p_rid) const {
-
- return immediate_owner.owns(p_rid);
-}
-
-bool RasterizerGLES1::is_multimesh(const RID& p_rid) const {
-
- return multimesh_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_particles(const RID &p_beam) const {
-
- return particles_owner.owns(p_beam);
-}
-
-bool RasterizerGLES1::is_light(const RID& p_rid) const {
-
- return light_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_light_instance(const RID& p_rid) const {
-
- return light_instance_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_particles_instance(const RID& p_rid) const {
-
- return particles_instance_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_skeleton(const RID& p_rid) const {
-
- return skeleton_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_environment(const RID& p_rid) const {
-
- return environment_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_fx(const RID& p_rid) const {
-
- return fx_owner.owns(p_rid);
-}
-bool RasterizerGLES1::is_shader(const RID& p_rid) const {
-
- return false;
-}
-
-void RasterizerGLES1::free(const RID& p_rid) {
-
- if (texture_owner.owns(p_rid)) {
-
- // delete the texture
- Texture *texture = texture_owner.get(p_rid);
-
- glDeleteTextures( 1,&texture->tex_id );
- _rinfo.texture_mem-=texture->total_data_size;
- texture_owner.free(p_rid);
- memdelete(texture);
-
- } else if (shader_owner.owns(p_rid)) {
-
- // delete the texture
- Shader *shader = shader_owner.get(p_rid);
-
-
-
- shader_owner.free(p_rid);
- memdelete(shader);
-
- } else if (material_owner.owns(p_rid)) {
-
- Material *material = material_owner.get( p_rid );
- ERR_FAIL_COND(!material);
-
- material_owner.free(p_rid);
- memdelete(material);
-
- } else if (mesh_owner.owns(p_rid)) {
-
- Mesh *mesh = mesh_owner.get(p_rid);
- ERR_FAIL_COND(!mesh);
- for (int i=0;i<mesh->surfaces.size();i++) {
-
- Surface *surface = mesh->surfaces[i];
- if (surface->array_local != 0) {
- memfree(surface->array_local);
- };
- if (surface->index_array_local != 0) {
- memfree(surface->index_array_local);
- };
-
- if (mesh->morph_target_count>0) {
-
- for(int i=0;i<mesh->morph_target_count;i++) {
-
- memfree(surface->morph_targets_local[i].array);
- }
- memfree(surface->morph_targets_local);
- surface->morph_targets_local=NULL;
- }
-
- if (surface->vertex_id)
- glDeleteBuffers(1,&surface->vertex_id);
- if (surface->index_id)
- glDeleteBuffers(1,&surface->index_id);
-
- memdelete( surface );
- };
-
- mesh->surfaces.clear();
-
- mesh_owner.free(p_rid);
- memdelete(mesh);
-
- } else if (multimesh_owner.owns(p_rid)) {
-
- MultiMesh *multimesh = multimesh_owner.get(p_rid);
- ERR_FAIL_COND(!multimesh);
-
- multimesh_owner.free(p_rid);
- memdelete(multimesh);
-
- } else if (particles_owner.owns(p_rid)) {
-
- Particles *particles = particles_owner.get(p_rid);
- ERR_FAIL_COND(!particles);
-
- particles_owner.free(p_rid);
- memdelete(particles);
- } else if (immediate_owner.owns(p_rid)) {
-
- Immediate *immediate = immediate_owner.get(p_rid);
- ERR_FAIL_COND(!immediate);
-
- immediate_owner.free(p_rid);
- memdelete(immediate);
- } else if (particles_instance_owner.owns(p_rid)) {
-
- ParticlesInstance *particles_isntance = particles_instance_owner.get(p_rid);
- ERR_FAIL_COND(!particles_isntance);
-
- particles_instance_owner.free(p_rid);
- memdelete(particles_isntance);
-
- } else if (skeleton_owner.owns(p_rid)) {
-
- Skeleton *skeleton = skeleton_owner.get( p_rid );
- ERR_FAIL_COND(!skeleton)
-
- skeleton_owner.free(p_rid);
- memdelete(skeleton);
-
- } else if (light_owner.owns(p_rid)) {
-
- Light *light = light_owner.get( p_rid );
- ERR_FAIL_COND(!light)
-
- light_owner.free(p_rid);
- memdelete(light);
-
- } else if (light_instance_owner.owns(p_rid)) {
-
- LightInstance *light_instance = light_instance_owner.get( p_rid );
- ERR_FAIL_COND(!light_instance);
- light_instance->clear_shadow_buffers();
- light_instance_owner.free(p_rid);
- memdelete( light_instance );
-
- } else if (fx_owner.owns(p_rid)) {
-
- FX *fx = fx_owner.get( p_rid );
- ERR_FAIL_COND(!fx);
-
- fx_owner.free(p_rid);
- memdelete( fx );
-
- } else if (environment_owner.owns(p_rid)) {
-
- Environment *env = environment_owner.get( p_rid );
- ERR_FAIL_COND(!env);
-
- environment_owner.free(p_rid);
- memdelete( env );
- };
-}
-
-
-void RasterizerGLES1::custom_shade_model_set_shader(int p_model, RID p_shader) {
-
-
-};
-
-RID RasterizerGLES1::custom_shade_model_get_shader(int p_model) const {
-
- return RID();
-};
-
-void RasterizerGLES1::custom_shade_model_set_name(int p_model, const String& p_name) {
-
-};
-
-String RasterizerGLES1::custom_shade_model_get_name(int p_model) const {
-
- return String();
-};
-
-void RasterizerGLES1::custom_shade_model_set_param_info(int p_model, const List<PropertyInfo>& p_info) {
-
-};
-
-void RasterizerGLES1::custom_shade_model_get_param_info(int p_model, List<PropertyInfo>* p_info) const {
-
-};
-
-
-void RasterizerGLES1::ShadowBuffer::init(int p_size) {
-
-
-#if 0
- size=p_size;
-
- glActiveTexture(GL_TEXTURE0);
- glGenTextures(1, &depth);
- ERR_FAIL_COND(depth==0);
-
- /* Setup Depth Texture */
- glBindTexture(GL_TEXTURE_2D, depth);
- glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, p_size, p_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
- float border_color[]={1.0f, 1.0f, 1.0f, 1.0f};
- glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
-
- /* Create FBO */
- glGenFramebuffers(1, &fbo);
-
- ERR_FAIL_COND( fbo==0 );
-
- glBindFramebuffer(GL_FRAMEBUFFER, fbo);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
- glDrawBuffer(GL_FALSE);
- glReadBuffer(GL_FALSE);
-
- /* Check FBO creation */
- GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
-
- ERR_FAIL_COND( status==GL_FRAMEBUFFER_UNSUPPORTED );
-
- glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
-#endif
-
-}
-
-void RasterizerGLES1::_init_shadow_buffers() {
-
- int near_shadow_size=GLOBAL_DEF("rasterizer/near_shadow_size",512);
- int far_shadow_size=GLOBAL_DEF("rasterizer/far_shadow_size",64);
-
- near_shadow_buffers.resize( GLOBAL_DEF("rasterizer/near_shadow_count",4) );
- far_shadow_buffers.resize( GLOBAL_DEF("rasterizer/far_shadow_count",16) );
-
- shadow_near_far_split_size_ratio = GLOBAL_DEF("rasterizer/shadow_near_far_split_size_ratio",0.3);
-
- for (int i=0;i<near_shadow_buffers.size();i++) {
-
- near_shadow_buffers[i].init(near_shadow_size );
- }
-
- for (int i=0;i<far_shadow_buffers.size();i++) {
-
- far_shadow_buffers[i].init(far_shadow_size);
- }
-
-}
-
-
-void RasterizerGLES1::_update_framebuffer() {
-
- return;
-
-#if 0
- bool want_16 = GLOBAL_DEF("rasterizer/support_hdr",true);
- int blur_buffer_div=GLOBAL_DEF("rasterizer/blur_buffer_div",4);
- bool use_fbo = GLOBAL_DEF("rasterizer/use_fbo",true);
-
-
- if (blur_buffer_div<1)
- blur_buffer_div=2;
-
-
- if (use_fbo==framebuffer.active && framebuffer.width==window_size.width && framebuffer.height==window_size.height && framebuffer.buff16==want_16)
- return; //nuthin to change
-
- if (framebuffer.fbo!=0) {
-
- WARN_PRINT("Resizing the screen multiple times while using to FBOs may decrease performance on some hardware.");
- //free the framebuffarz
- glDeleteRenderbuffers(1,&framebuffer.fbo);
- glDeleteTextures(1,&framebuffer.depth);
- glDeleteTextures(1,&framebuffer.color);
- for(int i=0;i<2;i++) {
- glDeleteRenderbuffers(1,&framebuffer.blur[i].fbo);
- glDeleteTextures(1,&framebuffer.blur[i].color);
-
- }
-
- framebuffer.fbo=0;
- }
-
- framebuffer.active=use_fbo;
- framebuffer.width=window_size.width;
- framebuffer.height=window_size.height;
- framebuffer.buff16=want_16;
-
-
- if (!use_fbo)
- return;
-
-
- glGenFramebuffers(1, &framebuffer.fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.fbo);
-
- print_line("generating fbo, id: "+itos(framebuffer.fbo));
- //depth
- glGenTextures(1, &framebuffer.depth);
-
- glBindTexture(GL_TEXTURE_2D, framebuffer.depth);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, framebuffer.width, framebuffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 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_COMPARE_MODE, GL_NONE );
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, framebuffer.depth, 0);
- //color
- glGenTextures(1, &framebuffer.color);
- glBindTexture(GL_TEXTURE_2D, framebuffer.color);
- glTexImage2D(GL_TEXTURE_2D, 0, want_16?GL_RGB16F:GL_RGBA8, framebuffer.width, framebuffer.height, 0, GL_RGBA, want_16?GL_HALF_FLOAT:GL_UNSIGNED_BYTE, NULL);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebuffer.color, 0);
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE );
-
- for(int i=0;i<2;i++) {
-
- glGenFramebuffers(1, &framebuffer.blur[i].fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.blur[i].fbo);
-
- glGenTextures(1, &framebuffer.blur[i].color);
- glBindTexture(GL_TEXTURE_2D, framebuffer.blur[i].color);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, framebuffer.width/blur_buffer_div, framebuffer.height/blur_buffer_div, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebuffer.blur[i].color, 0);
-
- status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE );
- }
-
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
-#endif
-}
-
-void RasterizerGLES1::init() {
-
-#ifdef GLES_OVER_GL
- glewInit();
-#endif
-
-
-
-
- scene_pass=1;
- if (ContextGL::get_singleton())
- ContextGL::get_singleton()->make_current();
-
-
-
- Set<String> extensions;
- Vector<String> strings = String((const char*)glGetString( GL_EXTENSIONS )).split(" ",false);
- for(int i=0;i<strings.size();i++) {
-
- extensions.insert(strings[i]);
-// print_line(strings[i]);
- }
-
-
-
- GLint tmp = 0;
-// glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &tmp);
-// print_line("GL_MAX_VERTEX_ATTRIBS "+itos(tmp));
-
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LEQUAL);
- glFrontFace(GL_CW);
- //glEnable(GL_TEXTURE_2D);
-
- default_material=create_default_material();
-
- _init_shadow_buffers();
-
- shadow=NULL;
- shadow_pass=0;
-
- framebuffer.fbo=0;
- framebuffer.width=0;
- framebuffer.height=0;
- framebuffer.buff16=false;
- framebuffer.blur[0].fbo=false;
- framebuffer.blur[1].fbo=false;
- framebuffer.active=false;
-
- //do a single initial clear
- glClearColor(0,0,0,1);
- //glClearDepth(1.0);
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-
- skinned_buffer_size = GLOBAL_DEF("rasterizer/skinned_buffer_size",DEFAULT_SKINNED_BUFFER_SIZE);
- skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size );
-
- glGenTextures(1, &white_tex);
- unsigned char whitetexdata[8*8*3];
- for(int i=0;i<8*8*3;i++) {
- whitetexdata[i]=255;
- }
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D,white_tex);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE,whitetexdata);
-
- npo2_textures_available=false;
- pvr_supported=extensions.has("GL_IMG_texture_compression_pvrtc");
- etc_supported=true;
- s3tc_supported=false;
- _rinfo.texture_mem=0;
-
-
-}
-
-void RasterizerGLES1::finish() {
-
- memdelete(skinned_buffer);
-}
-
-int RasterizerGLES1::get_render_info(VS::RenderInfo p_info) {
-
- switch(p_info) {
-
- case VS::INFO_OBJECTS_IN_FRAME: {
-
- return _rinfo.object_count;
- } break;
- case VS::INFO_VERTICES_IN_FRAME: {
-
- return _rinfo.vertex_count;
- } break;
- case VS::INFO_MATERIAL_CHANGES_IN_FRAME: {
-
- return _rinfo.mat_change_count;
- } break;
- case VS::INFO_SHADER_CHANGES_IN_FRAME: {
-
- return _rinfo.shader_change_count;
- } break;
- case VS::INFO_USAGE_VIDEO_MEM_TOTAL: {
-
- return 0;
- } break;
- case VS::INFO_VIDEO_MEM_USED: {
-
- return get_render_info(VS::INFO_TEXTURE_MEM_USED)+get_render_info(VS::INFO_VERTEX_MEM_USED);
- } break;
- case VS::INFO_TEXTURE_MEM_USED: {
-
- _rinfo.texture_mem;
- } break;
- case VS::INFO_VERTEX_MEM_USED: {
-
- return 0;
- } break;
- }
-
- return false;
-}
-
-bool RasterizerGLES1::needs_to_draw_next_frame() const {
-
- return false;
-}
-
-void RasterizerGLES1::reload_vram() {
-
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LEQUAL);
- glFrontFace(GL_CW);
-
- //do a single initial clear
- glClearColor(0,0,0,1);
- //glClearDepth(1.0);
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-
-/*
- glGenTextures(1, &white_tex);
- unsigned char whitetexdata[8*8*3];
- for(int i=0;i<8*8*3;i++) {
- whitetexdata[i]=255;
- }
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D,white_tex);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE,whitetexdata);
- glGenerateMipmap(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D,0);
-
-*/
- glEnable(GL_TEXTURE_2D);
- glActiveTexture(GL_TEXTURE0);
-
- List<RID> textures;
- texture_owner.get_owned_list(&textures);
- keep_copies=false;
- for(List<RID>::Element *E=textures.front();E;E=E->next()) {
-
- RID tid = E->get();
- Texture *t=texture_owner.get(tid);
- ERR_CONTINUE(!t);
- t->tex_id=0;
- t->data_size=0;
- glGenTextures(1, &t->tex_id);
- t->active=false;
- texture_allocate(tid,t->width,t->height,t->format,t->flags);
- bool had_image=false;
- for(int i=0;i<6;i++) {
- if (!t->image[i].empty()) {
- texture_set_data(tid,t->image[i],VS::CubeMapSide(i));
- had_image=true;
- }
- }
-
- if (!had_image && t->reloader) {
- Object *rl = ObjectDB::get_instance(t->reloader);
- if (rl)
- rl->call(t->reloader_func,tid);
- }
- }
-
- keep_copies=true;
-
-
-}
-
-bool RasterizerGLES1::has_feature(VS::Features p_feature) const {
-
- switch( p_feature) {
- case VS::FEATURE_SHADERS: return false;
- case VS::FEATURE_NEEDS_RELOAD_HOOK: return use_reload_hooks;
- default: return false;
-
- }
-
-}
-
-
-RasterizerGLES1::RasterizerGLES1(bool p_keep_copies,bool p_use_reload_hooks) {
- keep_copies=p_keep_copies;
- pack_arrays=false;
- use_reload_hooks=p_use_reload_hooks;
-
- frame = 0;
-};
-
-RasterizerGLES1::~RasterizerGLES1() {
-
-};
-
-
-#endif
diff --git a/drivers/gles1/rasterizer_gles1.h b/drivers/gles1/rasterizer_gles1.h
deleted file mode 100644
index e7937f43c3..0000000000
--- a/drivers/gles1/rasterizer_gles1.h
+++ /dev/null
@@ -1,1242 +0,0 @@
-/*************************************************************************/
-/* rasterizer_gles1.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef RASTERIZER_GLES1_H
-#define RASTERIZER_GLES1_H
-
-#include "servers/visual/rasterizer.h"
-
-#ifdef GLES1_ENABLED
-
-#include "image.h"
-#include "rid.h"
-#include "servers/visual_server.h"
-#include "list.h"
-#include "map.h"
-#include "camera_matrix.h"
-#include "sort.h"
-
-#include "platform_config.h"
-#ifndef GLES1_INCLUDE_H
-#include <GLES/gl.h>
-#else
-#include GLES1_INCLUDE_H
-#endif
-
-
-
-#include "servers/visual/particle_system_sw.h"
-
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-class RasterizerGLES1 : public Rasterizer {
-
- enum {
-
- MAX_SCENE_LIGHTS=2048,
- LIGHT_SPOT_BIT=0x80,
- DEFAULT_SKINNED_BUFFER_SIZE = 1024 * 1024, // 10k vertices
- MAX_HW_LIGHTS = 1,
- };
-
-
- uint8_t *skinned_buffer;
- int skinned_buffer_size;
- bool pvr_supported;
- bool s3tc_supported;
- bool etc_supported;
- bool npo2_textures_available;
- bool pack_arrays;
- bool use_reload_hooks;
-
- Image _get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed);
-
-
- struct Texture {
-
- uint32_t flags;
- int width,height;
- int alloc_width, alloc_height;
- Image::Format format;
-
- GLenum target;
- GLenum gl_format_cache;
- int gl_components_cache;
- int data_size; //original data size, useful for retrieving back
- bool format_has_alpha;
- bool compressed;
- bool disallow_mipmaps;
- int total_data_size;
-
- Image image[6];
-
- bool active;
- GLuint tex_id;
-
- ObjectID reloader;
- StringName reloader_func;
-
- Texture() {
-
- flags=width=height=0;
- tex_id=0;
- data_size=0;
- format=Image::FORMAT_GRAYSCALE;
- gl_components_cache=0;
- format_has_alpha=false;
- active=false;
- disallow_mipmaps=false;
-// gen_mipmap=true;
- compressed=false;
- total_data_size=0;
- }
-
- ~Texture() {
-
- if (tex_id!=0) {
-
- glDeleteTextures(1,&tex_id);
- }
- }
- };
-
- mutable RID_Owner<Texture> texture_owner;
-
- struct Shader {
-
- String vertex_code;
- String fragment_code;
- String light_code;
- VS::ShaderMode mode;
- Map<StringName,Variant> params;
- int fragment_line;
- int vertex_line;
- int light_line;
- bool valid;
- bool has_alpha;
- bool use_world_transform;
-
- };
-
- mutable RID_Owner<Shader> shader_owner;
-
-
- struct Material {
-
- bool fixed_flags[VS::FIXED_MATERIAL_FLAG_MAX];
- bool flags[VS::MATERIAL_FLAG_MAX];
- Variant parameters[VisualServer::FIXED_MATERIAL_PARAM_MAX];
- RID textures[VisualServer::FIXED_MATERIAL_PARAM_MAX];
-
- VS::MaterialDepthDrawMode depth_draw_mode;
-
- Transform uv_transform;
- VS::FixedMaterialTexCoordMode texcoord_mode[VisualServer::FIXED_MATERIAL_PARAM_MAX];
-
- VS::MaterialBlendMode blend_mode;
-
- float line_width;
- float point_size;
- bool has_alpha;
-
- RID shader; // shader material
- uint64_t last_pass;
-
- Map<StringName,Variant> shader_params;
-
-
- Material() {
-
-
- for(int i=0;i<VS::FIXED_MATERIAL_FLAG_MAX;i++)
- flags[i]=false;
-
- for(int i=0;i<VS::MATERIAL_FLAG_MAX;i++)
- flags[i]=false;
- flags[VS::MATERIAL_FLAG_VISIBLE]=true;
-
- parameters[VS::FIXED_MATERIAL_PARAM_DIFFUSE] = Color(0.8, 0.8, 0.8);
- parameters[VS::FIXED_MATERIAL_PARAM_SPECULAR_EXP] = 12;
-
- for (int i=0; i<VisualServer::FIXED_MATERIAL_PARAM_MAX; i++) {
- texcoord_mode[i] = VS::FIXED_MATERIAL_TEXCOORD_UV;
- };
- depth_draw_mode=VS::MATERIAL_DEPTH_DRAW_OPAQUE_ONLY;
- line_width=1;
- has_alpha=false;
- blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
- last_pass = 0;
- point_size = 1.0;
-
- }
- };
- mutable RID_Owner<Material> material_owner;
-
- void _material_check_alpha(Material *p_material);
-
-
- struct Geometry {
-
- enum Type {
- GEOMETRY_INVALID,
- GEOMETRY_SURFACE,
- GEOMETRY_POLY,
- GEOMETRY_PARTICLES,
- GEOMETRY_MULTISURFACE,
- };
-
- Type type;
- RID material;
- bool has_alpha;
- bool material_owned;
-
- Geometry() { has_alpha=false; material_owned = false; }
- virtual ~Geometry() {};
- };
-
- struct GeometryOwner {
-
- virtual ~GeometryOwner() {}
- };
-
- class Mesh;
-
- struct Surface : public Geometry {
-
- struct ArrayData {
-
- uint32_t ofs,size,datatype,count;
- bool normalize;
- bool bind;
-
- ArrayData() { ofs=0; size=0; count=0; datatype=0; normalize=0; bind=false;}
- };
-
- Mesh *mesh;
-
- Array data;
- Array morph_data;
- ArrayData array[VS::ARRAY_MAX];
- // support for vertex array objects
- GLuint array_object_id;
- // support for vertex buffer object
- GLuint vertex_id; // 0 means, unconfigured
- GLuint index_id; // 0 means, unconfigured
- // no support for the above, array in localmem.
- uint8_t *array_local;
- uint8_t *index_array_local;
-
- bool packed;
-
- struct MorphTarget {
- uint32_t configured_format;
- uint8_t *array;
- };
-
- MorphTarget* morph_targets_local;
- int morph_target_count;
- AABB aabb;
-
- int array_len;
- int index_array_len;
- int max_bone;
-
- float vertex_scale;
- float uv_scale;
- float uv2_scale;
-
- VS::PrimitiveType primitive;
-
- uint32_t format;
- uint32_t configured_format;
-
- int stride;
- int local_stride;
- uint32_t morph_format;
-
- bool active;
-
- Point2 uv_min;
- Point2 uv_max;
-
- Surface() {
-
-
- array_len=0;
- local_stride=0;
- morph_format=0;
- type=GEOMETRY_SURFACE;
- primitive=VS::PRIMITIVE_POINTS;
- index_array_len=0;
- vertex_scale=1.0;
- uv_scale=1.0;
- uv2_scale=1.0;
-
- format=0;
- stride=0;
- morph_targets_local=0;
- morph_target_count=0;
-
- array_local = index_array_local = 0;
- vertex_id = index_id = 0;
-
- active=false;
- packed=false;
- }
-
- ~Surface() {
-
- }
- };
-
-
- struct Mesh {
-
- bool active;
- Vector<Surface*> surfaces;
- int morph_target_count;
- VS::MorphTargetMode morph_target_mode;
- AABB custom_aabb;
-
- mutable uint64_t last_pass;
- Mesh() {
- morph_target_mode=VS::MORPH_MODE_NORMALIZED;
- morph_target_count=0;
- last_pass=0;
- active=false;
- }
- };
- mutable RID_Owner<Mesh> mesh_owner;
-
- Error _surface_set_arrays(Surface *p_surface, uint8_t *p_mem,uint8_t *p_index_mem,const Array& p_arrays,bool p_main);
-
- struct MultiMesh;
-
- struct MultiMeshSurface : public Geometry {
-
- Surface *surface;
- MultiMeshSurface() { type=GEOMETRY_MULTISURFACE; }
- };
-
- struct MultiMesh : public GeometryOwner {
-
- struct Element {
-
- float matrix[16];
- uint8_t color[4];
- };
-
- AABB aabb;
- RID mesh;
- int visible;
-
- //IDirect3DVertexBuffer9* instance_buffer;
- Vector<Element> elements;
- Vector<MultiMeshSurface> cache_surfaces;
- mutable uint64_t last_pass;
-
- MultiMesh() {
-
- last_pass=0;
- visible = -1;
- }
- };
-
- mutable RID_Owner<MultiMesh> multimesh_owner;
-
-
- struct Immediate {
-
- RID material;
- int empty;
- };
-
- mutable RID_Owner<Immediate> immediate_owner;
-
- struct Particles : public Geometry {
-
- ParticleSystemSW data; // software particle system
-
- Particles() {
- type=GEOMETRY_PARTICLES;
-
- }
- };
-
- mutable RID_Owner<Particles> particles_owner;
-
- struct ParticlesInstance : public GeometryOwner {
-
- RID particles;
-
- ParticleSystemProcessSW particles_process;
- Transform transform;
-
- ParticlesInstance() { }
- };
-
- mutable RID_Owner<ParticlesInstance> particles_instance_owner;
- ParticleSystemDrawInfoSW particle_draw_info;
-
- struct Skeleton {
-
- Vector<Transform> bones;
-
- };
-
- mutable RID_Owner<Skeleton> skeleton_owner;
-
-
- struct Light {
-
- VS::LightType type;
- float vars[VS::LIGHT_PARAM_MAX];
- Color colors[3];
- bool shadow_enabled;
- RID projector;
- bool volumetric_enabled;
- Color volumetric_color;
-
-
- Light() {
-
- vars[VS::LIGHT_PARAM_SPOT_ATTENUATION]=1;
- vars[VS::LIGHT_PARAM_SPOT_ANGLE]=45;
- vars[VS::LIGHT_PARAM_ATTENUATION]=1.0;
- vars[VS::LIGHT_PARAM_ENERGY]=1.0;
- vars[VS::LIGHT_PARAM_RADIUS]=1.0;
- vars[VS::LIGHT_PARAM_SHADOW_Z_OFFSET]=0.05;
-
- colors[VS::LIGHT_COLOR_DIFFUSE]=Color(1,1,1);
- colors[VS::LIGHT_COLOR_SPECULAR]=Color(1,1,1);
- shadow_enabled=false;
- volumetric_enabled=false;
- }
- };
-
-
- struct Environment {
-
-
- VS::EnvironmentBG bg_mode;
- Variant bg_param[VS::ENV_BG_PARAM_MAX];
- bool fx_enabled[VS::ENV_FX_MAX];
- Variant fx_param[VS::ENV_FX_PARAM_MAX];
-
- Environment() {
-
- bg_mode=VS::ENV_BG_DEFAULT_COLOR;
- bg_param[VS::ENV_BG_PARAM_COLOR]=Color(0,0,0);
- bg_param[VS::ENV_BG_PARAM_TEXTURE]=RID();
- bg_param[VS::ENV_BG_PARAM_CUBEMAP]=RID();
- bg_param[VS::ENV_BG_PARAM_ENERGY]=1.0;
-
- for(int i=0;i<VS::ENV_FX_MAX;i++)
- fx_enabled[i]=false;
-
- fx_param[VS::ENV_FX_PARAM_GLOW_BLUR_PASSES]=1;
- fx_param[VS::ENV_FX_PARAM_GLOW_BLOOM]=0.0;
- fx_param[VS::ENV_FX_PARAM_GLOW_BLOOM_TRESHOLD]=0.5;
- fx_param[VS::ENV_FX_PARAM_DOF_BLUR_PASSES]=1;
- fx_param[VS::ENV_FX_PARAM_DOF_BLUR_BEGIN]=100.0;
- fx_param[VS::ENV_FX_PARAM_DOF_BLUR_RANGE]=10.0;
- fx_param[VS::ENV_FX_PARAM_HDR_EXPOSURE]=0.4;
- fx_param[VS::ENV_FX_PARAM_HDR_WHITE]=1.0;
- fx_param[VS::ENV_FX_PARAM_HDR_GLOW_TRESHOLD]=0.95;
- fx_param[VS::ENV_FX_PARAM_HDR_GLOW_SCALE]=0.2;
- fx_param[VS::ENV_FX_PARAM_HDR_MIN_LUMINANCE]=0.4;
- fx_param[VS::ENV_FX_PARAM_HDR_MAX_LUMINANCE]=8.0;
- fx_param[VS::ENV_FX_PARAM_HDR_EXPOSURE_ADJUST_SPEED]=0.5;
- fx_param[VS::ENV_FX_PARAM_FOG_BEGIN]=100.0;
- fx_param[VS::ENV_FX_PARAM_FOG_ATTENUATION]=1.0;
- fx_param[VS::ENV_FX_PARAM_FOG_BEGIN_COLOR]=Color(0,0,0);
- fx_param[VS::ENV_FX_PARAM_FOG_END_COLOR]=Color(0,0,0);
- fx_param[VS::ENV_FX_PARAM_FOG_BG]=true;
- fx_param[VS::ENV_FX_PARAM_BCS_BRIGHTNESS]=1.0;
- fx_param[VS::ENV_FX_PARAM_BCS_CONTRAST]=1.0;
- fx_param[VS::ENV_FX_PARAM_BCS_SATURATION]=1.0;
-
- }
-
- };
-
- mutable RID_Owner<Environment> environment_owner;
-
- struct ShadowBuffer;
-
- struct LightInstance {
-
- struct SplitInfo {
-
- CameraMatrix camera;
- Transform transform;
- float near;
- float far;
- };
-
- RID light;
- Light *base;
- Transform transform;
- CameraMatrix projection;
-
- Transform custom_transform;
- CameraMatrix custom_projection;
-
- Vector3 light_vector;
- Vector3 spot_vector;
- float linear_att;
-
- uint64_t shadow_pass;
- uint64_t last_pass;
- uint16_t sort_key;
-
- Vector<ShadowBuffer*> shadow_buffers;
-
- void clear_shadow_buffers() {
-
- for (int i=0;i<shadow_buffers.size();i++) {
-
- ShadowBuffer *sb=shadow_buffers[i];
- ERR_CONTINUE( sb->owner != this );
-
- sb->owner=NULL;
- }
-
- shadow_buffers.clear();
- }
-
- LightInstance() { shadow_pass=0; last_pass=0; sort_key=0; }
-
- };
- mutable RID_Owner<Light> light_owner;
- mutable RID_Owner<LightInstance> light_instance_owner;
-
- LightInstance *light_instances[MAX_SCENE_LIGHTS];
- LightInstance *directional_lights[4];
-// LightInstance *directional_light_instances[MAX_SCENE_LIGHTS];
- int light_instance_count;
- int directional_light_count;
- int last_light_id;
-
-
- struct RenderList {
-
- enum {
- MAX_ELEMENTS=4096,
- MAX_LIGHTS=4
- };
-
- struct Element {
-
-
- float depth;
- const InstanceData *instance;
- const Skeleton *skeleton;
- union {
- uint16_t lights[MAX_HW_LIGHTS];
- uint64_t light_key;
- };
-
- const Geometry *geometry;
- const Material *material;
- const GeometryOwner *owner;
- uint16_t light_count;
- bool mirror;
-
-
- };
-
-
- Element _elements[MAX_ELEMENTS];
- Element *elements[MAX_ELEMENTS];
- int element_count;
-
- void clear() {
-
- element_count=0;
- }
-
- struct SortZ {
-
- _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const {
-
- return A->depth > B->depth;
- }
- };
-
- void sort_z() {
-
- SortArray<Element*,SortZ> sorter;
- sorter.sort(elements,element_count);
- }
-
-
- struct SortMat {
-
- _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const {
- // TODO move to a single uint64 (one comparison)
- if (A->material == B->material) {
-
- return A->light_key < B->light_key;
- } else {
-
- return (A->material < B->material);
- }
- }
- };
-
- void sort_mat() {
-
- SortArray<Element*,SortMat> sorter;
- sorter.sort(elements,element_count);
- }
-
- struct SortMatLight {
-
- _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const {
-
- if (A->material->flags[VS::MATERIAL_FLAG_UNSHADED] == B->material->flags[VS::MATERIAL_FLAG_UNSHADED]) {
-
- if (A->material == B->material) {
-
- if (A->geometry == B->geometry) {
-
- return A->light_key<B->light_key;
- } else
- return (A->geometry < B->geometry);
- } else {
-
- return (A->material < B->material);
- }
- } else {
-
- return (int(A->material->flags[VS::MATERIAL_FLAG_UNSHADED]) < int(B->material->flags[VS::MATERIAL_FLAG_UNSHADED]));
- }
- }
- };
-
- void sort_mat_light() {
-
- SortArray<Element*,SortMatLight> sorter;
- sorter.sort(elements,element_count);
- }
-
- _FORCE_INLINE_ Element* add_element() {
-
- if (element_count>MAX_ELEMENTS)
- return NULL;
- elements[element_count]=&_elements[element_count];
- return elements[element_count++];
- }
-
- RenderList() {
-
- element_count = 0;
- for (int i=0;i<MAX_ELEMENTS;i++)
- elements[i]=&_elements[i]; // assign elements
- }
- };
-
- RenderList opaque_render_list;
- RenderList alpha_render_list;
-
- RID default_material;
-
- struct FX {
-
- bool bgcolor_active;
- Color bgcolor;
-
- bool skybox_active;
- RID skybox_cubemap;
-
- bool antialias_active;
- float antialias_tolerance;
-
- bool glow_active;
- int glow_passes;
- float glow_attenuation;
- float glow_bloom;
-
- bool ssao_active;
- float ssao_attenuation;
- float ssao_radius;
- float ssao_max_distance;
- float ssao_range_max;
- float ssao_range_min;
- bool ssao_only;
-
- bool fog_active;
- float fog_near;
- float fog_far;
- float fog_attenuation;
- Color fog_color_near;
- Color fog_color_far;
- bool fog_bg;
-
- bool toon_active;
- float toon_treshold;
- float toon_soft;
-
- bool edge_active;
- Color edge_color;
- float edge_size;
-
- FX();
-
- };
- mutable RID_Owner<FX> fx_owner;
-
-
- FX *scene_fx;
- CameraMatrix camera_projection;
- Transform camera_transform;
- Transform camera_transform_inverse;
- float camera_z_near;
- float camera_z_far;
- Size2 camera_vp_size;
- Color last_color;
-
- Plane camera_plane;
-
- bool keep_copies;
-
- bool depth_write;
- bool depth_test;
- int blend_mode;
- bool lighting;
-
- _FORCE_INLINE_ void _add_geometry( const Geometry* p_geometry, const InstanceData *p_instance, const Geometry *p_geometry_cmp, const GeometryOwner *p_owner);
-
- void _render_list_forward(RenderList *p_render_list,bool p_reverse_cull=false);
-
- void _setup_light(LightInstance* p_instance, int p_idx);
- void _setup_lights(const uint16_t * p_lights,int p_light_count);
-
- _FORCE_INLINE_ void _setup_shader_params(const Material *p_material);
- void _setup_fixed_material(const Geometry *p_geometry,const Material *p_material);
- void _setup_material(const Geometry *p_geometry,const Material *p_material);
-
- Error _setup_geometry(const Geometry *p_geometry, const Material* p_material,const Skeleton *p_skeleton, const float *p_morphs);
- void _render(const Geometry *p_geometry,const Material *p_material, const Skeleton* p_skeleton, const GeometryOwner *p_owner);
-
-
- /***********/
- /* SHADOWS */
- /***********/
-
- struct ShadowBuffer {
-
- int size;
- GLuint fbo;
- GLuint depth;
- LightInstance *owner;
- void init(int p_size);
- ShadowBuffer() { size=0; depth=0; owner=NULL; }
- };
-
- Vector<ShadowBuffer> near_shadow_buffers;
- Vector<ShadowBuffer> far_shadow_buffers;
-
- LightInstance *shadow;
- int shadow_pass;
- void _init_shadow_buffers();
-
- float shadow_near_far_split_size_ratio;
- bool _allocate_shadow_buffers(LightInstance *p_instance, Vector<ShadowBuffer>& p_buffers);
- void _debug_draw_shadow(ShadowBuffer *p_buffer, const Rect2& p_rect);
- void _debug_draw_shadows_type(Vector<ShadowBuffer>& p_shadows,Point2& ofs);
- void _debug_shadows();
- void reset_state();
-
- /***********/
- /* FBOs */
- /***********/
-
-
- struct FrameBuffer {
-
- GLuint fbo;
- GLuint color;
- GLuint depth;
- int width,height;
- bool buff16;
- bool active;
-
- struct Blur {
-
- GLuint fbo;
- GLuint color;
- } blur[2];
-
- } framebuffer;
-
- void _update_framebuffer();
- void _process_glow_and_bloom();
-
- /*********/
- /* FRAME */
- /*********/
-
- struct _Rinfo {
-
- int texture_mem;
- int vertex_count;
- int object_count;
- int mat_change_count;
- int shader_change_count;
-
- } _rinfo;
-
- GLuint white_tex;
- RID canvas_tex;
- float canvas_opacity;
- VS::MaterialBlendMode canvas_blend;
- _FORCE_INLINE_ Texture* _bind_canvas_texture(const RID& p_texture);
-
-
- int _setup_geometry_vinfo;
-
- bool cull_front;
- _FORCE_INLINE_ void _set_cull(bool p_front,bool p_reverse_cull=false);
-
- Size2 window_size;
- VS::ViewportRect viewport;
- double last_time;
- double time_delta;
- uint64_t frame;
- uint64_t scene_pass;
-
- //void _draw_primitive(int p_points, const Vector3 *p_vertices, const Vector3 *p_normals, const Color* p_colors, const Vector3 *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1);
- //void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false );
- //void _draw_quad(const Rect2& p_rect);
-
-public:
-
- /* TEXTURE API */
-
- virtual RID texture_create();
- virtual void texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags=VS::TEXTURE_FLAGS_DEFAULT);
- virtual void texture_set_data(RID p_texture,const Image& p_image,VS::CubeMapSide p_cube_side=VS::CUBEMAP_LEFT);
- virtual Image texture_get_data(RID p_texture,VS::CubeMapSide p_cube_side=VS::CUBEMAP_LEFT) const;
- virtual void texture_set_flags(RID p_texture,uint32_t p_flags);
- virtual uint32_t texture_get_flags(RID p_texture) const;
- virtual Image::Format texture_get_format(RID p_texture) const;
- virtual uint32_t texture_get_width(RID p_texture) const;
- virtual uint32_t texture_get_height(RID p_texture) const;
- virtual bool texture_has_alpha(RID p_texture) const;
- 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;
-
- /* SHADER API */
-
- virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_MATERIAL);
-
- virtual void shader_set_mode(RID p_shader,VS::ShaderMode p_mode);
- virtual VS::ShaderMode shader_get_mode(RID p_shader) const;
-
- virtual void shader_set_code(RID p_shader, const String& p_vertex, const String& p_fragment,const String& p_light,int p_vertex_ofs=0,int p_fragment_ofs=0,int p_light_ofs=0);
- virtual String shader_get_fragment_code(RID p_shader) const;
- virtual String shader_get_vertex_code(RID p_shader) const;
- virtual String shader_get_light_code(RID p_shader) const;
-
- virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
-
- /* COMMON MATERIAL API */
-
- virtual RID material_create();
-
- virtual void material_set_shader(RID p_shader_material, RID p_shader);
- virtual RID material_get_shader(RID p_shader_material) const;
-
- virtual void material_set_param(RID p_material, const StringName& p_param, const Variant& p_value);
- virtual Variant material_get_param(RID p_material, const StringName& p_param) const;
-
- virtual void material_set_flag(RID p_material, VS::MaterialFlag p_flag,bool p_enabled);
- virtual bool material_get_flag(RID p_material,VS::MaterialFlag p_flag) const;
-
- virtual void material_set_depth_draw_mode(RID p_material, VS::MaterialDepthDrawMode p_mode);
- virtual VS::MaterialDepthDrawMode material_get_depth_draw_mode(RID p_material) const;
-
- virtual void material_set_blend_mode(RID p_material,VS::MaterialBlendMode p_mode);
- virtual VS::MaterialBlendMode material_get_blend_mode(RID p_material) const;
-
- virtual void material_set_line_width(RID p_material,float p_line_width);
- virtual float material_get_line_width(RID p_material) const;
-
- /* FIXED MATERIAL */
-
- virtual RID fixed_material_create();
-
- virtual void fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags p_flag, bool p_enabled);
- virtual bool fixed_material_get_flag(RID p_material, VS::FixedMaterialFlags p_flag) const;
-
- virtual void fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value);
- virtual Variant fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const;
-
- virtual void fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture);
- virtual RID fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const;
-
- virtual void fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode);
- virtual VS::FixedMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const;
-
- virtual void fixed_material_set_uv_transform(RID p_material,const Transform& p_transform);
- virtual Transform fixed_material_get_uv_transform(RID p_material) const;
-
- virtual void fixed_material_set_point_size(RID p_material,float p_size);
- virtual float fixed_material_get_point_size(RID p_material) const;
-
- /* MESH API */
-
-
- virtual RID mesh_create();
-
- virtual void mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array(),bool p_alpha_sort=false);
- virtual Array mesh_get_surface_arrays(RID p_mesh,int p_surface) const;
- virtual Array mesh_get_surface_morph_arrays(RID p_mesh,int p_surface) const;
- virtual void mesh_add_custom_surface(RID p_mesh,const Variant& p_dat);
-
- virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount);
- virtual int mesh_get_morph_target_count(RID p_mesh) const;
-
- virtual void mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode);
- virtual VS::MorphTargetMode mesh_get_morph_target_mode(RID p_mesh) const;
-
- virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material,bool p_owned=false);
- virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const;
-
- virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const;
- virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const;
- virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const;
- virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const;
-
- virtual void mesh_remove_surface(RID p_mesh,int p_index);
- virtual int mesh_get_surface_count(RID p_mesh) const;
-
- virtual AABB mesh_get_aabb(RID p_mesh) const;
-
- virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb);
- virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
-
- /* MULTIMESH API */
-
- virtual RID multimesh_create();
-
- virtual void multimesh_set_instance_count(RID p_multimesh,int p_count);
- virtual int multimesh_get_instance_count(RID p_multimesh) const;
-
- virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh);
- virtual void multimesh_set_aabb(RID p_multimesh,const AABB& p_aabb);
- virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform);
- virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color);
-
- virtual RID multimesh_get_mesh(RID p_multimesh) const;
- virtual AABB multimesh_get_aabb(RID p_multimesh) const;;
-
- virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const;
- virtual Color multimesh_instance_get_color(RID p_multimesh,int p_index) const;
-
- virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible);
- virtual int multimesh_get_visible_instances(RID p_multimesh) const;
-
- /* IMMEDIATE API */
-
- virtual RID immediate_create();
- virtual void immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture=RID());
- virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex);
- virtual void immediate_normal(RID p_immediate,const Vector3& p_normal);
- virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent);
- virtual void immediate_color(RID p_immediate,const Color& p_color);
- virtual void immediate_uv(RID p_immediate,const Vector2& tex_uv);
- virtual void immediate_uv2(RID p_immediate,const Vector2& tex_uv);
- virtual void immediate_end(RID p_immediate);
- virtual void immediate_clear(RID p_immediate);
- virtual AABB immediate_get_aabb(RID p_immediate) const;
- virtual void immediate_set_material(RID p_immediate,RID p_material);
- virtual RID immediate_get_material(RID p_immediate) const;
-
-
- /* PARTICLES API */
-
- virtual RID particles_create();
-
- virtual void particles_set_amount(RID p_particles, int p_amount);
- virtual int particles_get_amount(RID p_particles) const;
-
- virtual void particles_set_emitting(RID p_particles, bool p_emitting);
- virtual bool particles_is_emitting(RID p_particles) const;
-
- virtual void particles_set_visibility_aabb(RID p_particles, const AABB& p_visibility);
- virtual AABB particles_get_visibility_aabb(RID p_particles) const;
-
- virtual void particles_set_emission_half_extents(RID p_particles, const Vector3& p_half_extents);
- virtual Vector3 particles_get_emission_half_extents(RID p_particles) const;
-
- virtual void particles_set_emission_base_velocity(RID p_particles, const Vector3& p_base_velocity);
- virtual Vector3 particles_get_emission_base_velocity(RID p_particles) const;
-
- virtual void particles_set_emission_points(RID p_particles, const DVector<Vector3>& p_points);
- virtual DVector<Vector3> particles_get_emission_points(RID p_particles) const;
-
- virtual void particles_set_gravity_normal(RID p_particles, const Vector3& p_normal);
- virtual Vector3 particles_get_gravity_normal(RID p_particles) const;
-
- virtual void particles_set_variable(RID p_particles, VS::ParticleVariable p_variable,float p_value);
- virtual float particles_get_variable(RID p_particles, VS::ParticleVariable p_variable) const;
-
- virtual void particles_set_randomness(RID p_particles, VS::ParticleVariable p_variable,float p_randomness);
- virtual float particles_get_randomness(RID p_particles, VS::ParticleVariable p_variable) const;
-
- virtual void particles_set_color_phase_pos(RID p_particles, int p_phase, float p_pos);
- virtual float particles_get_color_phase_pos(RID p_particles, int p_phase) const;
-
- virtual void particles_set_color_phases(RID p_particles, int p_phases);
- virtual int particles_get_color_phases(RID p_particles) const;
-
- virtual void particles_set_color_phase_color(RID p_particles, int p_phase, const Color& p_color);
- virtual Color particles_get_color_phase_color(RID p_particles, int p_phase) const;
-
- virtual void particles_set_attractors(RID p_particles, int p_attractors);
- virtual int particles_get_attractors(RID p_particles) const;
-
- virtual void particles_set_attractor_pos(RID p_particles, int p_attractor, const Vector3& p_pos);
- virtual Vector3 particles_get_attractor_pos(RID p_particles,int p_attractor) const;
-
- virtual void particles_set_attractor_strength(RID p_particles, int p_attractor, float p_force);
- virtual float particles_get_attractor_strength(RID p_particles,int p_attractor) const;
-
- virtual void particles_set_material(RID p_particles, RID p_material,bool p_owned=false);
- virtual RID particles_get_material(RID p_particles) const;
-
- virtual AABB particles_get_aabb(RID p_particles) const;
-
- virtual void particles_set_height_from_velocity(RID p_particles, bool p_enable);
- virtual bool particles_has_height_from_velocity(RID p_particles) const;
-
- virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
- virtual bool particles_is_using_local_coordinates(RID p_particles) const;
-
- /* SKELETON API */
-
- virtual RID skeleton_create();
- virtual void skeleton_resize(RID p_skeleton,int p_bones);
- virtual int skeleton_get_bone_count(RID p_skeleton) const;
- virtual void skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform);
- virtual Transform skeleton_bone_get_transform(RID p_skeleton,int p_bone);
-
-
- /* LIGHT API */
-
- virtual RID light_create(VS::LightType p_type);
- virtual VS::LightType light_get_type(RID p_light) const;
-
- virtual void light_set_color(RID p_light,VS::LightColor p_type, const Color& p_color);
- virtual Color light_get_color(RID p_light,VS::LightColor p_type) const;
-
- virtual void light_set_shadow(RID p_light,bool p_enabled);
- virtual bool light_has_shadow(RID p_light) const;
-
- virtual void light_set_volumetric(RID p_light,bool p_enabled);
- virtual bool light_is_volumetric(RID p_light) const;
-
- virtual void light_set_projector(RID p_light,RID p_texture);
- virtual RID light_get_projector(RID p_light) const;
-
- virtual void light_set_var(RID p_light, VS::LightParam p_var, float p_value);
- virtual float light_get_var(RID p_light, VS::LightParam p_var) const;
-
- virtual void light_set_operator(RID p_light,VS::LightOp p_op);
- virtual VS::LightOp light_get_operator(RID p_light) const;
-
- virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode);
- virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) const;
-
-
- virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode);
- virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) const;
- virtual void light_directional_set_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param, float p_value);
- virtual float light_directional_get_shadow_param(RID p_light,VS::LightDirectionalShadowParam p_param) const;
-
- virtual AABB light_get_aabb(RID p_poly) const;
-
-
- virtual RID light_instance_create(RID p_light);
- virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform);
-
- virtual bool light_instance_has_shadow(RID p_light_instance) const;
- virtual bool light_instance_assign_shadow(RID p_light_instance);
- virtual ShadowType light_instance_get_shadow_type(RID p_light_instance) const;
- virtual int light_instance_get_shadow_passes(RID p_light_instance) const;
- virtual bool light_instance_get_pssm_shadow_overlap(RID p_light_instance) const;
- virtual void light_instance_set_custom_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near=0,float p_split_far=0);
- virtual int light_instance_get_shadow_size(RID p_light_instance, int p_index=0) const { return 1; }
-
- virtual ShadowType light_instance_get_shadow_type(RID p_light_instance,bool p_far=false) const;
- virtual void light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near=0,float p_split_far=0);
-
- virtual void shadow_clear_near();
- virtual bool shadow_allocate_near(RID p_light);
- virtual bool shadow_allocate_far(RID p_light);
-
-
- /* PARTICLES INSTANCE */
-
- virtual RID particles_instance_create(RID p_particles);
- virtual void particles_instance_set_transform(RID p_particles_instance,const Transform& p_transform);
-
- /* VIEWPORT */
-
- virtual RID viewport_data_create();
-
- virtual RID render_target_create();
- virtual void render_target_set_size(RID p_render_target, int p_width, int p_height);
- virtual RID render_target_get_texture(RID p_render_target) const;
- virtual bool render_target_renedered_in_frame(RID p_render_target);
-
- /* RENDER API */
- /* all calls (inside begin/end shadow) are always warranted to be in the following order: */
-
- virtual void begin_frame();
-
- virtual void set_viewport(const VS::ViewportRect& p_viewport);
- virtual void set_render_target(RID p_render_target,bool p_transparent_bg=false,bool p_vflip=false);
- virtual void clear_viewport(const Color& p_color);
- virtual void capture_viewport(Image* r_capture);
-
-
- virtual void begin_scene(RID p_viewport_data,RID p_env,VS::ScenarioDebugMode p_debug);
- virtual void begin_shadow_map( RID p_light_instance, int p_shadow_pass );
-
- virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection);
-
- virtual void add_light( RID p_light_instance ); ///< all "add_light" calls happen before add_geometry calls
-
-
- virtual void add_mesh( const RID& p_mesh, const InstanceData *p_data);
- virtual void add_multimesh( const RID& p_multimesh, const InstanceData *p_data);
- virtual void add_immediate( const RID& p_immediate, const InstanceData *p_data) {}
- virtual void add_particles( const RID& p_particle_instance, const InstanceData *p_data);
-
- virtual void end_scene();
- virtual void end_shadow_map();
-
- virtual void end_frame();
-
- /* CANVAS API */
-
- virtual void canvas_begin();
- virtual void canvas_disable_blending();
- virtual void canvas_set_opacity(float p_opacity);
- virtual void canvas_set_blend_mode(VS::MaterialBlendMode p_mode);
- virtual void canvas_begin_rect(const Matrix32& p_transform);
- virtual void canvas_set_clip(bool p_clip, const Rect2& p_rect);
- virtual void canvas_end_rect();
- virtual void canvas_draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width);
- virtual void canvas_draw_rect(const Rect2& p_rect, int p_flags, const Rect2& p_source,RID p_texture,const Color& p_modulate);
- virtual void canvas_draw_style_box(const Rect2& p_rect, RID p_texture,const float *p_margins, bool p_draw_center=true,const Color& p_modulate=Color(1,1,1));
- virtual void canvas_draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width);
- virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor);
- virtual void canvas_set_transform(const Matrix32& p_transform);
-
- /* FX */
-
- virtual RID fx_create();
- virtual void fx_get_effects(RID p_fx,List<String> *p_effects) const;
- virtual void fx_set_active(RID p_fx,const String& p_effect, bool p_active);
- virtual bool fx_is_active(RID p_fx,const String& p_effect) const;
- virtual void fx_get_effect_params(RID p_fx,const String& p_effect,List<PropertyInfo> *p_params) const;
- virtual Variant fx_get_effect_param(RID p_fx,const String& p_effect,const String& p_param) const;
- virtual void fx_set_effect_param(RID p_fx,const String& p_effect, const String& p_param, const Variant& p_pvalue);
-
- /* ENVIRONMENT */
-
- virtual RID environment_create();
-
- virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg);
- virtual VS::EnvironmentBG environment_get_background(RID p_env) const;
-
- virtual void environment_set_background_param(RID p_env,VS::EnvironmentBGParam p_param, const Variant& p_value);
- virtual Variant environment_get_background_param(RID p_env,VS::EnvironmentBGParam p_param) const;
-
- virtual void environment_set_enable_fx(RID p_env,VS::EnvironmentFx p_effect,bool p_enabled);
- virtual bool environment_is_fx_enabled(RID p_env,VS::EnvironmentFx p_effect) const;
-
- virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value);
- virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const;
-
-
- /*MISC*/
-
- virtual bool is_texture(const RID& p_rid) const;
- virtual bool is_material(const RID& p_rid) const;
- virtual bool is_mesh(const RID& p_rid) const;
- virtual bool is_multimesh(const RID& p_rid) const;
- virtual bool is_immediate(const RID& p_rid) const;
- virtual bool is_particles(const RID &p_beam) const;
-
- virtual bool is_light(const RID& p_rid) const;
- virtual bool is_light_instance(const RID& p_rid) const;
- virtual bool is_particles_instance(const RID& p_rid) const;
- virtual bool is_skeleton(const RID& p_rid) const;
- virtual bool is_environment(const RID& p_rid) const;
- virtual bool is_fx(const RID& p_rid) const;
- virtual bool is_shader(const RID& p_rid) const;
-
- virtual void free(const RID& p_rid);
-
- virtual void custom_shade_model_set_shader(int p_model, RID p_shader);
- virtual RID custom_shade_model_get_shader(int p_model) const;
- virtual void custom_shade_model_set_name(int p_model, const String& p_name);
- virtual String custom_shade_model_get_name(int p_model) const;
- virtual void custom_shade_model_set_param_info(int p_model, const List<PropertyInfo>& p_info);
- virtual void custom_shade_model_get_param_info(int p_model, List<PropertyInfo>* p_info) const;
-
-
- virtual void init();
- virtual void finish();
-
- virtual int get_render_info(VS::RenderInfo p_info);
-
- void reload_vram();
-
- virtual bool needs_to_draw_next_frame() const;
-
- virtual bool has_feature(VS::Features p_feature) const;
-
-
-#ifdef TOOLS_ENABLED
- RasterizerGLES1(bool p_keep_copies=true,bool p_use_reload_hooks=false);
-#else
- RasterizerGLES1(bool p_keep_copies=false,bool p_use_reload_hooks=false);
-#endif
- virtual ~RasterizerGLES1();
-};
-
-#endif
-#endif
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index dd690435ec..83b71fd5ff 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -63,6 +63,13 @@
#define _glClearDepth glClearDepthf
#endif
+
+#define _GL_SRGB_EXT 0x8C40
+#define _GL_SRGB_ALPHA_EXT 0x8C42
+
+#define _GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+
//#define DEBUG_OPENGL
#ifdef DEBUG_OPENGL
@@ -82,6 +89,12 @@
#endif
+static RasterizerGLES2* _singleton = NULL;
+
+#ifdef GLES_NO_CLIENT_ARRAYS
+static float GlobalVertexBuffer[MAX_POLYGON_VERTICES * 8] = {0};
+#endif
+
static const GLenum prim_type[]={GL_POINTS,GL_LINES,GL_TRIANGLES,GL_TRIANGLE_FAN};
_FORCE_INLINE_ static void _set_color_attrib(const Color& p_color) {
@@ -130,11 +143,13 @@ static _FORCE_INLINE_ uint16_t make_half_float(float f) {
else if (exp <= 0x38000000)
{
- // store a denorm half-float value or zero
+ /*// store a denorm half-float value or zero
exp = (0x38000000 - exp) >> 23;
mantissa >>= (14 + exp);
hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa);
+ */
+ hf=0; //denormals do not work for 3D, convert to zero
}
else
{
@@ -301,9 +316,23 @@ void RasterizerGLES2::_draw_primitive(int p_points, const Vector3 *p_vertices, c
#define _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
#define _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
#define _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+
+#define _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54
+#define _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55
+#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56
+#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57
+
+
#define _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#define _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#define _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+
+#define _EXT_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70
+#define _EXT_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71
+#define _EXT_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72
+#define _EXT_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73
+
+
#define _EXT_COMPRESSED_RED_RGTC1_EXT 0x8DBB
#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB
#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
@@ -314,6 +343,22 @@ void RasterizerGLES2::_draw_primitive(int p_points, const Vector3 *p_vertices, c
#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
#define _EXT_ETC1_RGB8_OES 0x8D64
+
+
+#define _EXT_SLUMINANCE_NV 0x8C46
+#define _EXT_SLUMINANCE_ALPHA_NV 0x8C44
+#define _EXT_SRGB8_NV 0x8C41
+#define _EXT_SLUMINANCE8_NV 0x8C47
+#define _EXT_SLUMINANCE8_ALPHA8_NV 0x8C45
+
+
+#define _EXT_COMPRESSED_SRGB_S3TC_DXT1_NV 0x8C4C
+#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV 0x8C4D
+#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV 0x8C4E
+#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV 0x8C4F
+
+
+
#define _EXT_ATC_RGB_AMD 0x8C92
#define _EXT_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
#define _EXT_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
@@ -321,10 +366,11 @@ void RasterizerGLES2::_draw_primitive(int p_points, const Vector3 *p_vertices, c
/* TEXTURE API */
-Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed) {
+Image RasterizerGLES2::_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) {
r_has_alpha_cache=false;
r_compressed=false;
+ r_gl_format=0;
Image image=p_image;
switch(p_format) {
@@ -332,6 +378,7 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
case Image::FORMAT_GRAYSCALE: {
r_gl_components=1;
r_gl_format=GL_LUMINANCE;
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_SLUMINANCE_NV:GL_LUMINANCE;
} break;
case Image::FORMAT_INTENSITY: {
@@ -340,6 +387,7 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
image.convert(Image::FORMAT_RGBA);
r_gl_components=4;
r_gl_format=GL_RGBA;
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_GL_SRGB_ALPHA_EXT:GL_RGBA;
r_has_alpha_cache=true;
} break;
case Image::FORMAT_GRAYSCALE_ALPHA: {
@@ -347,6 +395,7 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
//image.convert(Image::FORMAT_RGBA);
r_gl_components=2;
r_gl_format=GL_LUMINANCE_ALPHA;
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_SLUMINANCE_ALPHA_NV:GL_LUMINANCE_ALPHA;
r_has_alpha_cache=true;
} break;
@@ -356,6 +405,7 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
image.convert(Image::FORMAT_RGB);
r_gl_components=3;
r_gl_format=GL_RGB;
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_GL_SRGB_EXT:GL_RGB;
} break;
@@ -364,72 +414,242 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
if (!image.empty())
image.convert(Image::FORMAT_RGBA);
r_gl_components=4;
- r_gl_format=GL_RGBA;
+
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
r_has_alpha_cache=true;
} break;
case Image::FORMAT_RGB: {
r_gl_components=3;
- r_gl_format=GL_RGB;
+
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_internal_format=_GL_SRGB_EXT;
+ r_gl_format=GL_RGB;
+ } else {
+ r_gl_internal_format=GL_RGB;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGB;
+ }
} break;
case Image::FORMAT_RGBA: {
r_gl_components=4;
- r_gl_format=GL_RGBA;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ r_gl_format=GL_RGBA;
+ //r_gl_internal_format=GL_RGBA;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
+
r_has_alpha_cache=true;
} break;
case Image::FORMAT_BC1: {
- r_gl_components=1; //doesn't matter much
- r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- r_compressed=true;
+ if (!s3tc_supported || (!s3tc_srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) {
+
+ if (!image.empty()) {
+ image.decompress();
+ }
+ r_gl_components=4;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
+ r_has_alpha_cache=true;
+
+ } else {
+
+ r_gl_components=1; //doesn't matter much
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV:_EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ r_compressed=true;
+ };
} break;
case Image::FORMAT_BC2: {
- r_gl_components=1; //doesn't matter much
- r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- r_has_alpha_cache=true;
- r_compressed=true;
+
+ if (!s3tc_supported || (!s3tc_srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) {
+
+ if (!image.empty()) {
+ image.decompress();
+ }
+ r_gl_components=4;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
+ r_has_alpha_cache=true;
+
+ } else {
+ r_gl_components=1; //doesn't matter much
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV:_EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+
+ r_has_alpha_cache=true;
+ r_compressed=true;
+ };
} break;
case Image::FORMAT_BC3: {
- r_gl_components=1; //doesn't matter much
- r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- r_has_alpha_cache=true;
- r_compressed=true;
+ if (!s3tc_supported || (!s3tc_srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) {
+
+ if (!image.empty()) {
+ image.decompress();
+ }
+ r_gl_components=4;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
+ r_has_alpha_cache=true;
+
+ } else {
+ r_gl_components=1; //doesn't matter much
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV:_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ r_has_alpha_cache=true;
+ r_compressed=true;
+ };
} break;
case Image::FORMAT_BC4: {
- r_gl_format=_EXT_COMPRESSED_RED_RGTC1;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
+ if (!latc_supported) {
+
+ if (!image.empty()) {
+ image.decompress();
+ }
+ r_gl_components=4;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
+ r_has_alpha_cache=true;
+
+ } else {
+
+ r_gl_internal_format=_EXT_COMPRESSED_LUMINANCE_LATC1_EXT;
+ r_gl_components=1; //doesn't matter much
+ r_compressed=true;
+ };
} break;
case Image::FORMAT_BC5: {
+ if (!latc_supported ) {
+
+ if (!image.empty()) {
+ image.decompress();
+ }
+ r_gl_components=4;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
+ r_has_alpha_cache=true;
- r_gl_format=_EXT_COMPRESSED_RG_RGTC2;
- r_gl_components=1; //doesn't matter much
- r_compressed=true;
+ } else {
+ r_gl_internal_format=_EXT_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
+ r_gl_components=1; //doesn't matter much
+ r_compressed=true;
+ };
} break;
case Image::FORMAT_PVRTC2: {
- if (!pvr_supported) {
+ if (!pvr_supported || (!pvr_srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) {
if (!image.empty()) {
image.decompress();
}
r_gl_components=4;
- r_gl_format=GL_RGBA;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
r_has_alpha_cache=true;
} else {
- r_gl_format=_EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT:_EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
r_gl_components=1; //doesn't matter much
r_compressed=true;
@@ -438,18 +658,31 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
} break;
case Image::FORMAT_PVRTC2_ALPHA: {
- if (!pvr_supported) {
+ if (!pvr_supported || (!pvr_srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) {
if (!image.empty())
image.decompress();
r_gl_components=4;
- r_gl_format=GL_RGBA;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
r_has_alpha_cache=true;
} else {
- r_gl_format=_EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+ r_gl_internal_format=_EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT:_EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
r_gl_components=1; //doesn't matter much
r_compressed=true;
@@ -458,16 +691,28 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
} break;
case Image::FORMAT_PVRTC4: {
- if (!pvr_supported) {
+ if (!pvr_supported || (!pvr_srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) {
if (!image.empty())
image.decompress();
r_gl_components=4;
- r_gl_format=GL_RGBA;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
r_has_alpha_cache=true;
} else {
- r_gl_format=_EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT:_EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
r_gl_components=1; //doesn't matter much
r_compressed=true;
}
@@ -475,16 +720,28 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
} break;
case Image::FORMAT_PVRTC4_ALPHA: {
- if (!pvr_supported) {
+ if (!pvr_supported || (!pvr_srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) {
if (!image.empty())
image.decompress();
r_gl_components=4;
- r_gl_format=GL_RGBA;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGBA;
+ r_gl_internal_format=_GL_SRGB_ALPHA_EXT;
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGBA;
+ }
r_has_alpha_cache=true;
} else {
- r_gl_format=_EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+ r_gl_internal_format=(srgb_supported && p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT:_EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
r_gl_components=1; //doesn't matter much
r_compressed=true;
}
@@ -492,18 +749,31 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
} break;
case Image::FORMAT_ETC: {
- if (!etc_supported) {
+ if (!etc_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
if (!image.empty()) {
image.decompress();
}
r_gl_components=3;
- r_gl_format=GL_RGB;
+ if (p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
+
+ if (srgb_supported) {
+ r_gl_format=GL_RGB;
+ r_gl_internal_format=_GL_SRGB_EXT;
+ } else {
+ r_gl_internal_format=GL_RGB;
+ if (!image.empty())
+ image.srgb_to_linear();
+ }
+ } else {
+ r_gl_internal_format=GL_RGB;
+ }
+ r_gl_internal_format=GL_RGB;
} else {
- r_gl_format=_EXT_ETC1_RGB8_OES;
+ r_gl_internal_format=_EXT_ETC1_RGB8_OES;
r_gl_components=1; //doesn't matter much
r_compressed=true;
}
@@ -517,12 +787,12 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
image.decompress();
}
r_gl_components=3;
- r_gl_format=GL_RGB;
+ r_gl_internal_format=GL_RGB;
} else {
- r_gl_format=_EXT_ATC_RGB_AMD;
+ r_gl_internal_format=_EXT_ATC_RGB_AMD;
r_gl_components=1; //doesn't matter much
r_compressed=true;
}
@@ -536,12 +806,12 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
image.decompress();
}
r_gl_components=4;
- r_gl_format=GL_RGBA;
+ r_gl_internal_format=GL_RGBA;
} else {
- r_gl_format=_EXT_ATC_RGBA_EXPLICIT_ALPHA_AMD;
+ r_gl_internal_format=_EXT_ATC_RGBA_EXPLICIT_ALPHA_AMD;
r_gl_components=1; //doesn't matter much
r_compressed=true;
}
@@ -555,12 +825,12 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
image.decompress();
}
r_gl_components=4;
- r_gl_format=GL_RGBA;
+ r_gl_internal_format=GL_RGBA;
} else {
- r_gl_format=_EXT_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
+ r_gl_internal_format=_EXT_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
r_gl_components=1; //doesn't matter much
r_compressed=true;
}
@@ -571,7 +841,7 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
if (!image.empty())
image.convert(Image::FORMAT_RGB);
- r_gl_format=GL_RGB;
+ r_gl_internal_format=GL_RGB;
r_gl_components=3;
} break;
@@ -582,6 +852,10 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
}
}
+ if (r_gl_format==0) {
+ r_gl_format=r_gl_internal_format;
+ }
+
return image;
}
@@ -613,6 +887,7 @@ void RasterizerGLES2::texture_allocate(RID p_texture,int p_width, int p_height,I
bool has_alpha_cache;
int components;
GLenum format;
+ GLenum internal_format;
bool compressed;
int po2_width = nearest_power_of_2(p_width);
@@ -631,7 +906,7 @@ void RasterizerGLES2::texture_allocate(RID p_texture,int p_width, int p_height,I
texture->flags=p_flags;
texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
- _get_gl_image_and_format(Image(),texture->format,texture->flags,format,components,has_alpha_cache,compressed);
+ _get_gl_image_and_format(Image(),texture->format,texture->flags,format,internal_format,components,has_alpha_cache,compressed);
bool scale_textures = !compressed && !(p_flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && (!npo2_textures_available || p_flags&VS::TEXTURE_FLAG_MIPMAPS);
@@ -649,6 +924,7 @@ void RasterizerGLES2::texture_allocate(RID p_texture,int p_width, int p_height,I
texture->gl_components_cache=components;
texture->gl_format_cache=format;
+ texture->gl_internal_format_cache=internal_format;
texture->format_has_alpha=has_alpha_cache;
texture->compressed=compressed;
texture->has_alpha=false; //by default it doesn't have alpha unless something with alpha is blitteds
@@ -663,7 +939,7 @@ void RasterizerGLES2::texture_allocate(RID p_texture,int p_width, int p_height,I
if (p_flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) {
//prealloc if video
- glTexImage2D(texture->target, 0, format, p_width, p_height, 0, format, GL_UNSIGNED_BYTE,NULL);
+ glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, GL_UNSIGNED_BYTE,NULL);
}
texture->active=true;
@@ -681,6 +957,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
int components;
GLenum format;
+ GLenum internal_format;
bool alpha;
bool compressed;
@@ -688,7 +965,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
texture->image[p_cube_side]=p_image;
}
- Image img = _get_gl_image_and_format(p_image, p_image.get_format(),texture->flags,format,components,alpha,compressed);
+ Image img = _get_gl_image_and_format(p_image, p_image.get_format(),texture->flags,format,internal_format,components,alpha,compressed);
if (texture->alloc_width != img.get_width() || texture->alloc_height != img.get_height()) {
@@ -698,7 +975,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
- if (img.detect_alpha()==Image::ALPHA_BLEND) {
+ if (!(texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) {
texture->has_alpha=true;
}
@@ -716,8 +993,14 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps)
glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR);
- else
- glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ else {
+ if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
+ glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ } else {
+ glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+
+ }
+ }
if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
@@ -730,10 +1013,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 );
@@ -741,6 +1030,16 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
}
+ if (use_anisotropic_filter) {
+
+ if (texture->flags&VS::TEXTURE_FLAG_ANISOTROPIC_FILTER) {
+
+ glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropic_level);
+ } else {
+ glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
+ }
+ }
+
int mipmaps= (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && img.get_mipmaps()>0) ? img.get_mipmaps() +1 : 1;
@@ -753,6 +1052,8 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
int size,ofs;
img.get_mipmap_offset_and_size(i,ofs,size);
+ //print_line("mipmap: "+itos(i)+" size: "+itos(size)+" w: "+itos(mm_w)+", h: "+itos(mm_h));
+
if (texture->compressed) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glCompressedTexImage2D( blit_target, i, format,w,h,0,size,&read[ofs] );
@@ -760,9 +1061,9 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
} else {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) {
- glTexSubImage2D( blit_target, i, 0,0,w,h,format,GL_UNSIGNED_BYTE,&read[ofs] );
+ glTexSubImage2D( blit_target, i, 0,0,w, h,format,GL_UNSIGNED_BYTE,&read[ofs] );
} else {
- glTexImage2D(blit_target, i, format, w, h, 0, format, GL_UNSIGNED_BYTE,&read[ofs]);
+ glTexImage2D(blit_target, i, internal_format, w, h, 0, format, GL_UNSIGNED_BYTE,&read[ofs]);
}
}
@@ -968,7 +1269,6 @@ void RasterizerGLES2::texture_set_flags(RID p_texture,uint32_t p_flags) {
p_flags&=VS::TEXTURE_FLAG_FILTER;//can change only filter
}
-
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP;
@@ -976,10 +1276,16 @@ void RasterizerGLES2::texture_set_flags(RID p_texture,uint32_t p_flags) {
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 );
@@ -988,10 +1294,26 @@ void RasterizerGLES2::texture_set_flags(RID p_texture,uint32_t p_flags) {
}
+ if (use_anisotropic_filter) {
+
+ if (texture->flags&VS::TEXTURE_FLAG_ANISOTROPIC_FILTER) {
+
+ glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropic_level);
+ } else {
+ glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
+ }
+ }
+
if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps)
glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR);
- else
- glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ else{
+ if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
+ glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ } else {
+ glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+
+ }
+ }
if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
@@ -1078,6 +1400,49 @@ void RasterizerGLES2::texture_set_reload_hook(RID p_texture,ObjectID p_owner,con
}
+GLuint RasterizerGLES2::_texture_get_name(RID p_tex) {
+
+ Texture * texture = texture_owner.get(p_tex);
+ ERR_FAIL_COND_V(!texture, 0);
+
+ 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 */
RID RasterizerGLES2::shader_create(VS::ShaderMode p_mode) {
@@ -1109,6 +1474,9 @@ void RasterizerGLES2::shader_set_mode(RID p_shader,VS::ShaderMode p_mode) {
case VS::SHADER_MATERIAL: {
material_shader.free_custom_shader(shader->custom_code_id);
} break;
+ case VS::SHADER_CANVAS_ITEM: {
+ canvas_shader.free_custom_shader(shader->custom_code_id);
+ } break;
}
shader->custom_code_id=0;
@@ -1120,6 +1488,9 @@ void RasterizerGLES2::shader_set_mode(RID p_shader,VS::ShaderMode p_mode) {
case VS::SHADER_MATERIAL: {
shader->custom_code_id=material_shader.create_custom_shader();
} break;
+ case VS::SHADER_CANVAS_ITEM: {
+ shader->custom_code_id=canvas_shader.create_custom_shader();
+ } break;
}
_shader_make_dirty(shader);
@@ -1239,13 +1610,56 @@ void RasterizerGLES2::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_
}
+void RasterizerGLES2::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture) {
+
+ Shader *shader=shader_owner.get(p_shader);
+ ERR_FAIL_COND(!shader);
+ ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture));
+
+ if (p_texture.is_valid())
+ shader->default_textures[p_name]=p_texture;
+ else
+ shader->default_textures.erase(p_name);
+
+ _shader_make_dirty(shader);
+
+}
+
+RID RasterizerGLES2::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const{
+ const Shader *shader=shader_owner.get(p_shader);
+ ERR_FAIL_COND_V(!shader,RID());
+
+ const Map<StringName,RID>::Element *E=shader->default_textures.find(p_name);
+ if (!E)
+ return RID();
+ return E->get();
+}
+
+Variant RasterizerGLES2::shader_get_default_param(RID p_shader, const StringName& p_name) {
+
+ Shader *shader=shader_owner.get(p_shader);
+ ERR_FAIL_COND_V(!shader,Variant());
+
+ //update shader params if necesary
+ //make sure the shader is compiled and everything
+ //so the actual parameters can be properly retrieved!
+ if (shader->dirty_list.in_list()) {
+ _update_shader(shader);
+ }
+ if (shader->valid && shader->uniforms.has(p_name))
+ return shader->uniforms[p_name].default_value;
+
+ return Variant();
+}
+
/* COMMON MATERIAL API */
RID RasterizerGLES2::material_create() {
- return material_owner.make_rid( memnew( Material ) );
+ RID material = material_owner.make_rid( memnew( Material ) );
+ return material;
}
void RasterizerGLES2::material_set_shader(RID p_material, RID p_shader) {
@@ -1281,13 +1695,18 @@ void RasterizerGLES2::material_set_param(RID p_material, const StringName& p_par
material->shader_version=0; //get default!
} else {
E->get().value=p_value;
+ E->get().inuse=true;
}
} else {
+ if (p_value.get_type()==Variant::NIL)
+ return;
+
Material::UniformData ud;
ud.index=-1;
ud.value=p_value;
ud.istexture=p_value.get_type()==Variant::_RID; /// cache it being texture
+ ud.inuse=true;
material->shader_params[p_param]=ud; //may be got at some point, or erased
}
@@ -1319,7 +1738,7 @@ Variant RasterizerGLES2::material_get_param(RID p_material, const StringName& p_
}
- if (material->shader_params.has(p_param))
+ if (material->shader_params.has(p_param) && material->shader_params[p_param].inuse)
return material->shader_params[p_param].value;
else
return Variant();
@@ -1331,6 +1750,7 @@ void RasterizerGLES2::material_set_flag(RID p_material, VS::MaterialFlag p_flag,
Material *material = material_owner.get(p_material);
ERR_FAIL_COND(!material);
ERR_FAIL_INDEX(p_flag,VS::MATERIAL_FLAG_MAX);
+
material->flags[p_flag]=p_enabled;
}
@@ -1436,6 +1856,23 @@ void RasterizerGLES2::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,
ERR_FAIL_COND((format&VS::ARRAY_FORMAT_VERTEX)==0); // mandatory
+ ERR_FAIL_COND( mesh->morph_target_count!=p_blend_shapes.size() );
+ if (mesh->morph_target_count) {
+ //validate format for morphs
+ for(int i=0;i<p_blend_shapes.size();i++) {
+
+ uint32_t bsformat=0;
+ Array arr = p_blend_shapes[i];
+ for(int j=0;j<arr.size();j++) {
+
+
+ if (arr[j].get_type()!=Variant::NIL)
+ bsformat|=(1<<j);
+ }
+
+ ERR_FAIL_COND( (bsformat)!=(format&(VS::ARRAY_FORMAT_BONES-1)));
+ }
+ }
Surface *surface = memnew( Surface );
ERR_FAIL_COND( !surface );
@@ -1633,7 +2070,9 @@ void RasterizerGLES2::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,
surface->array_len=array_len;
surface->format=format;
surface->primitive=p_primitive;
+ surface->morph_target_count=mesh->morph_target_count;
surface->configured_format=0;
+ surface->mesh=mesh;
if (keep_copies) {
surface->data=p_arrays;
surface->morph_data=p_blend_shapes;
@@ -1659,6 +2098,9 @@ void RasterizerGLES2::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,
iaw = index_array_pre_vbo.write();
index_array_ptr=iaw.ptr();
}
+
+ _surface_set_arrays(surface,array_ptr,index_array_ptr,p_arrays,true);
+
} else {
surface->array_local = (uint8_t*)memalloc(surface->array_len*surface->stride);
@@ -1667,11 +2109,23 @@ void RasterizerGLES2::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,
surface->index_array_local = (uint8_t*)memalloc(index_array_len*surface->array[VS::ARRAY_INDEX].size);
index_array_ptr=(uint8_t*)surface->index_array_local;
}
+
+ _surface_set_arrays(surface,array_ptr,index_array_ptr,p_arrays,true);
+
+ if (mesh->morph_target_count) {
+
+ surface->morph_targets_local = memnew_arr(Surface::MorphTarget,mesh->morph_target_count);
+ for(int i=0;i<mesh->morph_target_count;i++) {
+
+ surface->morph_targets_local[i].array=memnew_arr(uint8_t,surface->local_stride*surface->array_len);
+ surface->morph_targets_local[i].configured_format=surface->morph_format;
+ _surface_set_arrays(surface,surface->morph_targets_local[i].array,NULL,p_blend_shapes[i],false);
+ }
+ }
}
- _surface_set_arrays(surface,array_ptr,index_array_ptr,p_arrays,true);
/* create buffers!! */
@@ -2069,6 +2523,67 @@ Error RasterizerGLES2::_surface_set_arrays(Surface *p_surface, uint8_t *p_mem,ui
p_surface->configured_format|=(1<<ai);
}
+ if (p_surface->format&VS::ARRAY_FORMAT_BONES) {
+ //create AABBs for each detected bone
+ int total_bones = p_surface->max_bone+1;
+ if (p_main) {
+ p_surface->skeleton_bone_aabb.resize(total_bones);
+ p_surface->skeleton_bone_used.resize(total_bones);
+ for(int i=0;i<total_bones;i++)
+ p_surface->skeleton_bone_used[i]=false;
+ }
+ DVector<Vector3> vertices = p_arrays[VS::ARRAY_VERTEX];
+ DVector<int> bones = p_arrays[VS::ARRAY_BONES];
+ DVector<float> weights = p_arrays[VS::ARRAY_WEIGHTS];
+
+ bool any_valid=false;
+
+ if (vertices.size() && bones.size()==vertices.size()*4 && weights.size()==bones.size()) {
+ //print_line("MAKING SKELETHONG");
+ int vs = vertices.size();
+ DVector<Vector3>::Read rv =vertices.read();
+ DVector<int>::Read rb=bones.read();
+ DVector<float>::Read rw=weights.read();
+
+ Vector<bool> first;
+ first.resize(total_bones);
+ for(int i=0;i<total_bones;i++) {
+ first[i]=p_main;
+ }
+ AABB *bptr = p_surface->skeleton_bone_aabb.ptr();
+ bool *fptr=first.ptr();
+ bool *usedptr=p_surface->skeleton_bone_used.ptr();
+
+ for(int i=0;i<vs;i++) {
+
+ Vector3 v = rv[i];
+ for(int j=0;j<4;j++) {
+
+ int idx = rb[i*4+j];
+ float w = rw[i*4+j];
+ if (w==0)
+ continue;//break;
+ ERR_FAIL_INDEX_V(idx,total_bones,ERR_INVALID_DATA);
+
+ if (fptr[idx]) {
+ bptr[idx].pos=v;
+ fptr[idx]=false;
+ any_valid=true;
+ } else {
+ bptr[idx].expand_to(v);
+ }
+ usedptr[idx]=true;
+ }
+ }
+ }
+
+ if (p_main && !any_valid) {
+
+ p_surface->skeleton_bone_aabb.clear();
+ p_surface->skeleton_bone_used.clear();
+ }
+ }
+
return OK;
}
@@ -2077,7 +2592,7 @@ Error RasterizerGLES2::_surface_set_arrays(Surface *p_surface, uint8_t *p_mem,ui
void RasterizerGLES2::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) {
ERR_EXPLAIN("OpenGL Rasterizer does not support custom surfaces. Running on wrong platform?");
- ERR_FAIL_V();
+ ERR_FAIL();
}
Array RasterizerGLES2::mesh_get_surface_arrays(RID p_mesh,int p_surface) const {
@@ -2245,7 +2760,7 @@ int RasterizerGLES2::mesh_get_surface_count(RID p_mesh) const {
return mesh->surfaces.size();
}
-AABB RasterizerGLES2::mesh_get_aabb(RID p_mesh) const {
+AABB RasterizerGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const {
Mesh *mesh = mesh_owner.get( p_mesh );
ERR_FAIL_COND_V(!mesh,AABB());
@@ -2253,14 +2768,62 @@ AABB RasterizerGLES2::mesh_get_aabb(RID p_mesh) const {
if (mesh->custom_aabb!=AABB())
return mesh->custom_aabb;
+ Skeleton *sk=NULL;
+ if (p_skeleton.is_valid())
+ sk=skeleton_owner.get(p_skeleton);
+
AABB aabb;
+ if (sk && sk->bones.size()!=0) {
- for (int i=0;i<mesh->surfaces.size();i++) {
- if (i==0)
- aabb=mesh->surfaces[i]->aabb;
- else
- aabb.merge_with(mesh->surfaces[i]->aabb);
+ for (int i=0;i<mesh->surfaces.size();i++) {
+
+ AABB laabb;
+ if (mesh->surfaces[i]->format&VS::ARRAY_FORMAT_BONES && mesh->surfaces[i]->skeleton_bone_aabb.size()) {
+
+
+ int bs = mesh->surfaces[i]->skeleton_bone_aabb.size();
+ const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr();
+ const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr();
+
+ int sbs = sk->bones.size();
+ ERR_CONTINUE(bs>sbs);
+ Skeleton::Bone *skb = sk->bones.ptr();
+
+ bool first=true;
+ for(int j=0;j<bs;j++) {
+
+ if (!skused[j])
+ continue;
+ AABB baabb = skb[ j ].transform_aabb ( skbones[j] );
+ if (first) {
+ laabb=baabb;
+ first=false;
+ } else {
+ laabb.merge_with(baabb);
+ }
+ }
+
+ } else {
+
+ laabb=mesh->surfaces[i]->aabb;
+ }
+
+ if (i==0)
+ aabb=laabb;
+ else
+ aabb.merge_with(laabb);
+ }
+ } else {
+
+ for (int i=0;i<mesh->surfaces.size();i++) {
+
+ if (i==0)
+ aabb=mesh->surfaces[i]->aabb;
+ else
+ aabb.merge_with(mesh->surfaces[i]->aabb);
+ }
+
}
return aabb;
@@ -3512,6 +4075,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;
@@ -3531,19 +4096,29 @@ 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);
glBindTexture(GL_TEXTURE_2D, rt->color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ if (rt->texture_ptr->flags&VS::TEXTURE_FLAG_FILTER) {
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
@@ -3608,10 +4183,14 @@ 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
+ canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF5,shadow_filter==SHADOW_FILTER_PCF5);
+ canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF13,shadow_filter==SHADOW_FILTER_PCF13);
+ canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_ESM,shadow_filter==SHADOW_FILTER_ESM);
+
window_size = Size2( OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height );
double time = (OS::get_singleton()->get_ticks_usec()/1000); // get msec
@@ -3619,7 +4198,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;
@@ -3729,6 +4307,9 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) {
pixels.resize(viewport.width*viewport.height*4);
DVector<uint8_t>::Write w = pixels.write();
glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+// uint64_t time = OS::get_singleton()->get_ticks_usec();
+
if (current_rt) {
#ifdef GLEW_ENABLED
glReadBuffer(GL_COLOR_ATTACHMENT0);
@@ -3738,10 +4319,28 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) {
// back?
glReadPixels( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height,GL_RGBA,GL_UNSIGNED_BYTE,w.ptr());
}
- w=DVector<uint8_t>::Write();
+ bool flip = current_rt==NULL;
+
+ if (flip) {
+ uint32_t *imgptr = (uint32_t*)w.ptr();
+ for(int y=0;y<(viewport.height/2);y++) {
+
+ uint32_t *ptr1 = &imgptr[y*viewport.width];
+ uint32_t *ptr2 = &imgptr[(viewport.height-y-1)*viewport.width];
+
+ for(int x=0;x<viewport.width;x++) {
+
+ uint32_t tmp = ptr1[x];
+ ptr1[x]=ptr2[x];
+ ptr2[x]=tmp;
+ }
+ }
+ }
+
+ w=DVector<uint8_t>::Write();
r_capture->create(viewport.width,viewport.height,0,Image::FORMAT_RGBA,pixels);
- r_capture->flip_y();
+ //r_capture->flip_y();
#endif
@@ -3751,7 +4350,7 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) {
void RasterizerGLES2::clear_viewport(const Color& p_color) {
- if (current_rt) {
+ if (current_rt || using_canvas_bg) {
glScissor( 0, 0, viewport.width, viewport.height );
} else {
@@ -3759,7 +4358,7 @@ void RasterizerGLES2::clear_viewport(const Color& p_color) {
}
glEnable(GL_SCISSOR_TEST);
- glClearColor(p_color.r,p_color.g,p_color.b,1.0);
+ glClearColor(p_color.r,p_color.g,p_color.b,p_color.a);
glClear(GL_COLOR_BUFFER_BIT); //should not clear if anything else cleared..
glDisable(GL_SCISSOR_TEST);
};
@@ -3844,7 +4443,7 @@ void RasterizerGLES2::begin_shadow_map( RID p_light_instance, int p_shadow_pass
}
-void RasterizerGLES2::set_camera(const Transform& p_world,const CameraMatrix& p_projection) {
+void RasterizerGLES2::set_camera(const Transform& p_world,const CameraMatrix& p_projection,bool p_ortho_hint) {
camera_transform=p_world;
if (current_rt && current_rt_vflip) {
@@ -3852,10 +4451,11 @@ void RasterizerGLES2::set_camera(const Transform& p_world,const CameraMatrix& p_
}
camera_transform_inverse=camera_transform.inverse();
camera_projection=p_projection;
- camera_plane = Plane( camera_transform.origin, camera_transform.basis.get_axis(2) );
+ camera_plane = Plane( camera_transform.origin, -camera_transform.basis.get_axis(2) );
camera_z_near=camera_projection.get_z_near();
camera_z_far=camera_projection.get_z_far();
camera_projection.get_viewport_size(camera_vp_size.x,camera_vp_size.y);
+ camera_ortho=p_ortho_hint;
}
void RasterizerGLES2::add_light( RID p_light_instance ) {
@@ -3944,6 +4544,13 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
if (err) {
return; //invalid
}
+ } else if (p_shader->mode==VS::SHADER_CANVAS_ITEM) {
+
+ Error err = shader_precompiler.compile(p_shader->vertex_code,ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX,vertex_code,vertex_globals,vertex_flags,&p_shader->uniforms);
+ if (err) {
+ return; //invalid
+ }
+
}
//print_line("compiled vertex: "+vertex_code);
@@ -3953,9 +4560,16 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
String fragment_code;
String fragment_globals;
- Error err = shader_precompiler.compile(p_shader->fragment_code,(p_shader->mode==VS::SHADER_MATERIAL?ShaderLanguage::SHADER_MATERIAL_FRAGMENT:ShaderLanguage::SHADER_POST_PROCESS),fragment_code,fragment_globals,fragment_flags,&p_shader->uniforms);
- if (err) {
- return; //invalid
+ if (p_shader->mode==VS::SHADER_MATERIAL) {
+ Error err = shader_precompiler.compile(p_shader->fragment_code,ShaderLanguage::SHADER_MATERIAL_FRAGMENT,fragment_code,fragment_globals,fragment_flags,&p_shader->uniforms);
+ if (err) {
+ return; //invalid
+ }
+ } else if (p_shader->mode==VS::SHADER_CANVAS_ITEM) {
+ Error err = shader_precompiler.compile(p_shader->fragment_code,ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT,fragment_code,fragment_globals,fragment_flags,&p_shader->uniforms);
+ if (err) {
+ return; //invalid
+ }
}
@@ -3968,6 +4582,11 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
if (err) {
return; //invalid
}
+ } else if (p_shader->mode==VS::SHADER_CANVAS_ITEM) {
+ Error err = shader_precompiler.compile(p_shader->light_code,(ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT),light_code,light_globals,light_flags,&p_shader->uniforms);
+ if (err) {
+ return; //invalid
+ }
}
fragment_globals+=light_globals; //both fragment anyway
@@ -3990,20 +4609,22 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
}
}
+ bool uses_time=false;
+
if (p_shader->mode==VS::SHADER_MATERIAL) {
//print_line("setting code to id.. "+itos(p_shader->custom_code_id));
Vector<const char*> enablers;
- if (fragment_flags.use_color_interp)
+ if (fragment_flags.use_color_interp || vertex_flags.use_color_interp)
enablers.push_back("#define ENABLE_COLOR_INTERP\n");
- if (fragment_flags.use_uv_interp)
+ if (fragment_flags.use_uv_interp || vertex_flags.use_uv_interp)
enablers.push_back("#define ENABLE_UV_INTERP\n");
- if (fragment_flags.use_uv2_interp)
+ if (fragment_flags.use_uv2_interp || vertex_flags.use_uv2_interp)
enablers.push_back("#define ENABLE_UV2_INTERP\n");
- if (fragment_flags.use_tangent_interp)
+ if (fragment_flags.use_tangent_interp || vertex_flags.use_tangent_interp || fragment_flags.uses_normalmap)
enablers.push_back("#define ENABLE_TANGENT_INTERP\n");
- if (fragment_flags.use_var1_interp)
+ if (fragment_flags.use_var1_interp || vertex_flags.use_var1_interp)
enablers.push_back("#define ENABLE_VAR1_INTERP\n");
- if (fragment_flags.use_var2_interp)
+ if (fragment_flags.use_var2_interp || vertex_flags.use_var2_interp)
enablers.push_back("#define ENABLE_VAR2_INTERP\n");
if (fragment_flags.uses_texscreen) {
enablers.push_back("#define ENABLE_TEXSCREEN\n");
@@ -4014,12 +4635,64 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
if (fragment_flags.uses_discard) {
enablers.push_back("#define ENABLE_DISCARD\n");
}
+ if (fragment_flags.uses_normalmap) {
+ enablers.push_back("#define ENABLE_NORMALMAP\n");
+ }
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 {
+ } else if (p_shader->mode==VS::SHADER_CANVAS_ITEM) {
+
+ Vector<const char*> enablers;
+
+ if (light_flags.uses_time || fragment_flags.uses_time || vertex_flags.uses_time) {
+ enablers.push_back("#define USE_TIME\n");
+ uses_time=true;
+ }
+ if (fragment_flags.uses_normal) {
+ enablers.push_back("#define NORMAL_USED\n");
+ }
+ if (fragment_flags.uses_normalmap) {
+ enablers.push_back("#define USE_NORMALMAP\n");
+ }
+
+ if (light_flags.uses_light) {
+ enablers.push_back("#define USE_LIGHT_SHADER_CODE\n");
+ }
+ if (fragment_flags.use_var1_interp || vertex_flags.use_var1_interp)
+ enablers.push_back("#define ENABLE_VAR1_INTERP\n");
+ if (fragment_flags.use_var2_interp || vertex_flags.use_var2_interp)
+ enablers.push_back("#define ENABLE_VAR2_INTERP\n");
+ if (fragment_flags.uses_texscreen) {
+ enablers.push_back("#define ENABLE_TEXSCREEN\n");
+ }
+ if (fragment_flags.uses_screen_uv) {
+ enablers.push_back("#define ENABLE_SCREEN_UV\n");
+ }
+ if (fragment_flags.uses_texpixel_size) {
+ enablers.push_back("#define USE_TEXPIXEL_SIZE\n");
+ }
+ if (light_flags.uses_shadow_color) {
+ enablers.push_back("#define USE_LIGHT_SHADOW_COLOR\n");
+ }
+
+ if (vertex_flags.uses_worldvec) {
+ enablers.push_back("#define USE_WORLD_VEC\n");
+ }
+ canvas_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, light_code, fragment_globals,uniform_names,enablers);
+
//postprocess_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, fragment_globals,uniform_names);
}
@@ -4030,6 +4703,9 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
p_shader->has_texscreen=fragment_flags.uses_texscreen;
p_shader->has_screen_uv=fragment_flags.uses_screen_uv;
p_shader->can_zpass=!fragment_flags.uses_discard && !vertex_flags.vertex_code_writes_vertex;
+ p_shader->uses_normal=fragment_flags.uses_normal || light_flags.uses_normal;
+ p_shader->uses_time=uses_time;
+ p_shader->uses_texpixel_size=fragment_flags.uses_texpixel_size;
p_shader->version++;
}
@@ -4148,8 +4824,11 @@ void RasterizerGLES2::_add_geometry( const Geometry* p_geometry, const InstanceD
e->geometry_cmp=p_geometry_cmp;
e->material=m;
e->instance=p_instance;
- //e->depth=camera_plane.distance_to(p_world->origin);
- e->depth=camera_transform.origin.distance_to(p_instance->transform.origin);
+ if (camera_ortho) {
+ e->depth=camera_plane.distance_to(p_instance->transform.origin);
+ } else {
+ e->depth=camera_transform.origin.distance_to(p_instance->transform.origin);
+ }
e->owner=p_owner;
e->light_type=0;
e->additive=false;
@@ -4176,7 +4855,8 @@ void RasterizerGLES2::_add_geometry( const Geometry* p_geometry, const InstanceD
if (m->flags[VS::MATERIAL_FLAG_INVERT_FACES])
e->mirror=!e->mirror;
- e->light_type=0xFF; // no lights!
+ //e->light_type=0xFF; // no lights!
+ e->light_type=3; //light type 3 is no light?
e->light=0xFFFF;
if (!shadow && !has_blend_alpha && has_alpha && m->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA) {
@@ -4191,7 +4871,7 @@ void RasterizerGLES2::_add_geometry( const Geometry* p_geometry, const InstanceD
oe->additive_ptr=&oe->additive;
}
- if (shadow || m->flags[VS::MATERIAL_FLAG_UNSHADED]) {
+ if (shadow || m->flags[VS::MATERIAL_FLAG_UNSHADED] || current_debug==VS::SCENARIO_DEBUG_SHADELESS) {
e->light_type=0x7F; //unshaded is zero
} else {
@@ -4379,31 +5059,58 @@ _FORCE_INLINE_ void RasterizerGLES2::_update_material_shader_params(Material *p_
Material::UniformData ud;
- bool keep=true;
+ bool keep=true; //keep material value
+
+ Map<StringName,Material::UniformData>::Element *OLD=old_mparams.find(E->key());
+ bool has_old = OLD;
+ bool old_inuse=has_old && old_mparams[E->key()].inuse;
- if (!old_mparams.has(E->key()))
+ ud.istexture=(E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP);
+
+ if (!has_old || !old_inuse) {
keep=false;
- else if (old_mparams[E->key()].value.get_type()!=E->value().default_value.get_type()) {
+ }
+ else if (OLD->get().value.get_type()!=E->value().default_value.get_type()) {
- if (old_mparams[E->key()].value.get_type()==Variant::OBJECT) {
+ if (OLD->get().value.get_type()==Variant::INT && E->get().type==ShaderLanguage::TYPE_FLOAT) {
+ //handle common mistake using shaders (feeding ints instead of float)
+ OLD->get().value=float(OLD->get().value);
+ keep=true;
+ } else if (!ud.istexture && E->value().default_value.get_type()!=Variant::NIL) {
+
+ keep=false;
+ }
+ //type changed between old and new
+ /* if (old_mparams[E->key()].value.get_type()==Variant::OBJECT) {
if (E->value().default_value.get_type()!=Variant::_RID) //hackfor textures
keep=false;
} else if (!old_mparams[E->key()].value.is_num() || !E->value().default_value.get_type())
- keep=false;
+ keep=false;*/
+
+ //value is invalid because type differs and default is not null
+ ;
}
+
if (keep) {
ud.value=old_mparams[E->key()].value;
+
//print_line("KEEP: "+String(E->key()));
} else {
- ud.value=E->value().default_value;
+ if (ud.istexture && p_material->shader_cache->default_textures.has(E->key()))
+ ud.value=p_material->shader_cache->default_textures[E->key()];
+ else
+ ud.value=E->value().default_value;
+ old_inuse=false; //if reverted to default, obviously did not work
+
//print_line("NEW: "+String(E->key())+" because: hasold-"+itos(old_mparams.has(E->key())));
//if (old_mparams.has(E->key()))
// print_line(" told "+Variant::get_type_name(old_mparams[E->key()].value.get_type())+" tnew "+Variant::get_type_name(E->value().default_value.get_type()));
}
- ud.istexture=(E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP);
+
ud.index=idx++;
+ ud.inuse=old_inuse;
mparams[E->key()]=ud;
}
@@ -4437,6 +5144,8 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF,shadow_filter==SHADOW_FILTER_PCF5 || shadow_filter==SHADOW_FILTER_PCF13);
material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF_HQ,shadow_filter==SHADOW_FILTER_PCF13);
material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_ESM,shadow_filter==SHADOW_FILTER_ESM);
+ material_shader.set_conditional(MaterialShaderGLES2::USE_LIGHTMAP_ON_UV2,p_material->flags[VS::MATERIAL_FLAG_LIGHTMAP_ON_UV2]);
+ material_shader.set_conditional(MaterialShaderGLES2::USE_COLOR_ATTRIB_SRGB_TO_LINEAR,p_material->flags[VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB] && current_env && current_env->fx_enabled[VS::ENV_FX_SRGB]);
if (p_opaque_pass && p_material->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA && p_material->shader_cache && p_material->shader_cache->has_alpha) {
@@ -4505,8 +5214,10 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
int texcoord=0;
for (Map<StringName,Material::UniformData>::Element *E=p_material->shader_params.front();E;E=E->next()) {
+
if (E->get().index<0)
continue;
+// print_line(String(E->key())+": "+E->get().value);
if (E->get().istexture) {
//clearly a texture..
RID rid = E->get().value;
@@ -4516,12 +5227,14 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
Texture *t=NULL;
if (rid.is_valid()) {
+
t=texture_owner.get(rid);
- if (!t)
+ if (!t) {
E->get().value=RID(); //nullify, invalid texture
+ rid=RID();
+ }
}
-
glActiveTexture(GL_TEXTURE0+texcoord);
glUniform1i(loc,texcoord); //TODO - this could happen automatically on compile...
if (t) {
@@ -4545,8 +5258,10 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
}
+
if (p_material->shader_cache->has_texscreen && framebuffer.active) {
material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height));
+ material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(0,0,float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height));
material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_TEX,texcoord);
glActiveTexture(GL_TEXTURE0+texcoord);
glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
@@ -4557,6 +5272,13 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
}
DEBUG_TEST_ERROR("Material arameters");
+ if (p_material->shader_cache->uses_time) {
+ material_shader.set_uniform(MaterialShaderGLES2::TIME,Math::fmod(last_time,shader_time_rollback));
+ draw_next_frame=true;
+ }
+ //if uses TIME - draw_next_frame=true
+
+
} else {
material_shader.set_custom_shader(0);
@@ -4600,6 +5322,7 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
}
+
//material_shader.set_uniform(MaterialShaderGLES2::TIME,Math::fmod(last_time,300.0));
//if uses TIME - draw_next_frame=true
@@ -4670,7 +5393,7 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) {
if (li->near_shadow_buffer) {
- glActiveTexture(GL_TEXTURE7);
+ glActiveTexture(GL_TEXTURE0+max_texture_units-1);
//if (read_depth_supported) {
glBindTexture(GL_TEXTURE_2D,li->near_shadow_buffer->depth);
@@ -4681,7 +5404,7 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) {
material_shader.set_uniform(MaterialShaderGLES2::SHADOW_MATRIX,li->shadow_projection[0]);
material_shader.set_uniform(MaterialShaderGLES2::SHADOW_TEXEL_SIZE,Vector2(1.0,1.0)/li->near_shadow_buffer->size);
- material_shader.set_uniform(MaterialShaderGLES2::SHADOW_TEXTURE,7);
+ material_shader.set_uniform(MaterialShaderGLES2::SHADOW_TEXTURE,max_texture_units-1);
if (shadow_filter==SHADOW_FILTER_ESM)
material_shader.set_uniform(MaterialShaderGLES2::ESM_MULTIPLIER,float(li->base->vars[VS::LIGHT_PARAM_SHADOW_ESM_MULTIPLIER]));
@@ -4701,7 +5424,8 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) {
}
//print_line("shadow split: "+rtos(li->shadow_split));
- } else
+ }
+
material_shader.set_uniform(MaterialShaderGLES2::SHADOW_DARKENING,li->base->vars[VS::LIGHT_PARAM_SHADOW_DARKENING]);
//matrix
@@ -4724,7 +5448,7 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) {
}
-template<bool USE_NORMAL, bool USE_TANGENT>
+template<bool USE_NORMAL, bool USE_TANGENT,bool INPLACE>
void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_stride, uint8_t * p_dst_array, int p_dst_stride, int p_elements,const uint8_t *p_src_bones, const uint8_t *p_src_weights, const Skeleton::Bone *p_bone_xforms) {
uint32_t basesize = 3;
@@ -4734,6 +5458,8 @@ void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_str
basesize+=4;
uint32_t extra=(p_dst_stride-basesize*4);
+ const int dstvec_size=3+(USE_NORMAL?3:0)+(USE_TANGENT?4:0);
+ float dstcopy[dstvec_size];
for(int i=0;i<p_elements;i++) {
@@ -4742,7 +5468,11 @@ void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_str
const uint16_t *bi = (const uint16_t*)&p_src_bones[ss];
const float *bw = (const float *)&p_src_weights[ss];
const float *src_vec=(const float *)&p_src_array[ss];
- float *dst_vec=(float*)&p_dst_array[ds];
+ float *dst_vec;
+ if (INPLACE)
+ dst_vec=dstcopy;
+ else
+ dst_vec=(float*)&p_dst_array[ds];
dst_vec[0]=0.0;
dst_vec[1]=0.0;
@@ -4795,16 +5525,28 @@ void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_str
end:
- //copy extra stuff
- const uint8_t *esp =(const uint8_t*) &src_vec[basesize];
- uint8_t *edp =(uint8_t*) &dst_vec[basesize];
+ if (INPLACE) {
+ const uint8_t *esp =(const uint8_t*) dstcopy;
+ uint8_t *edp =(uint8_t*)&p_dst_array[ds];
- for(uint32_t j=0;j<extra;j++) {
- edp[j]=esp[j];
- }
+ for(uint32_t j=0;j<dstvec_size*4;j++) {
+
+ edp[j]=esp[j];
+ }
+
+ } else {
+ //copy extra stuff
+ const uint8_t *esp =(const uint8_t*) &src_vec[basesize];
+ uint8_t *edp =(uint8_t*) &dst_vec[basesize];
+
+
+ for(uint32_t j=0;j<extra;j++) {
+ edp[j]=esp[j];
+ }
+ }
}
}
@@ -4855,14 +5597,19 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
base = surf->array_local;
glBindBuffer(GL_ARRAY_BUFFER, 0);
bool can_copy_to_local=surf->local_stride * surf->array_len <= skinned_buffer_size;
+ if (p_morphs && surf->stride * surf->array_len > skinned_buffer_size)
+ can_copy_to_local=false;
+
+
if (!can_copy_to_local)
skeleton_valid=false;
-
/* compute morphs */
if (p_morphs && surf->morph_target_count && can_copy_to_local) {
+
+
base = skinned_buffer;
stride=surf->local_stride;
@@ -4876,6 +5623,8 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
}
+ int16_t coeffp = CLAMP(coef*255,0,255);
+
for(int i=0;i<VS::ARRAY_MAX-1;i++) {
@@ -4885,9 +5634,13 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
int ofs = ad.ofs;
int src_stride=surf->stride;
- int dst_stride=surf->local_stride;
+ int dst_stride=skeleton_valid?surf->stride:surf->local_stride;
int count = surf->array_len;
+ if (!skeleton_valid && i>=VS::ARRAY_MAX-3)
+ break;
+
+
switch(i) {
case VS::ARRAY_VERTEX:
@@ -4903,7 +5656,21 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
dst[0]= src[0]*coef;
dst[1]= src[1]*coef;
dst[2]= src[2]*coef;
- } break;
+ };
+
+ } break;
+ case VS::ARRAY_COLOR: {
+
+ for(int k=0;k<count;k++) {
+
+ const uint8_t *src = (const uint8_t*)&surf->array_local[ofs+k*src_stride];
+ uint8_t *dst = (uint8_t*)&base[ofs+k*dst_stride];
+
+ dst[0]= (src[0]*coeffp)>>8;
+ dst[1]= (src[1]*coeffp)>>8;
+ dst[2]= (src[2]*coeffp)>>8;
+ dst[3]= (src[3]*coeffp)>>8;
+ }
} break;
case VS::ARRAY_TEX_UV:
@@ -4916,16 +5683,32 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
dst[0]= src[0]*coef;
dst[1]= src[1]*coef;
- } break;
+ }
+
+ } break;
+ case VS::ARRAY_BONES:
+ case VS::ARRAY_WEIGHTS: {
+
+ for(int k=0;k<count;k++) {
+
+ const float *src = (const float*)&surf->array_local[ofs+k*src_stride];
+ float *dst = (float*)&base[ofs+k*dst_stride];
+
+ dst[0]= src[0];
+ dst[1]= src[1];
+ dst[2]= src[2];
+ dst[3]= src[3];
+ }
} break;
+
}
}
for(int j=0;j<surf->morph_target_count;j++) {
- for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+ for(int i=0;i<VS::ARRAY_MAX-3;i++) {
const Surface::ArrayData& ad=surf->array[i];
if (ad.size==0)
@@ -4933,10 +5716,12 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
int ofs = ad.ofs;
- int dst_stride=surf->local_stride;
+ int src_stride=surf->local_stride;
+ int dst_stride=skeleton_valid?surf->stride:surf->local_stride;
int count = surf->array_len;
const uint8_t *morph=surf->morph_targets_local[j].array;
float w = p_morphs[j];
+ int16_t wfp = CLAMP(w*255,0,255);
switch(i) {
@@ -4947,13 +5732,26 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
for(int k=0;k<count;k++) {
- const float *src_morph = (const float*)&morph[ofs+k*dst_stride];
+ const float *src_morph = (const float*)&morph[ofs+k*src_stride];
float *dst = (float*)&base[ofs+k*dst_stride];
dst[0]+= src_morph[0]*w;
dst[1]+= src_morph[1]*w;
dst[2]+= src_morph[2]*w;
- } break;
+ }
+
+ } break;
+ case VS::ARRAY_COLOR: {
+ for(int k=0;k<count;k++) {
+
+ const uint8_t *src = (const uint8_t*)&morph[ofs+k*src_stride];
+ uint8_t *dst = (uint8_t*)&base[ofs+k*dst_stride];
+
+ dst[0]= (src[0]*wfp)>>8;
+ dst[1]= (src[1]*wfp)>>8;
+ dst[2]= (src[2]*wfp)>>8;
+ dst[3]= (src[3]*wfp)>>8;
+ }
} break;
case VS::ARRAY_TEX_UV:
@@ -4961,18 +5759,43 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
for(int k=0;k<count;k++) {
- const float *src_morph = (const float*)&morph[ofs+k*dst_stride];
+ const float *src_morph = (const float*)&morph[ofs+k*src_stride];
float *dst = (float*)&base[ofs+k*dst_stride];
dst[0]+= src_morph[0]*w;
dst[1]+= src_morph[1]*w;
- } break;
+ }
} break;
}
}
}
+
+
+ if (skeleton_valid) {
+
+
+
+ const uint8_t *src_weights=&surf->array_local[surf->array[VS::ARRAY_WEIGHTS].ofs];
+ const uint8_t *src_bones=&surf->array_local[surf->array[VS::ARRAY_BONES].ofs];
+ const Skeleton::Bone *skeleton = &p_skeleton->bones[0];
+
+
+ if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT)
+ _skeleton_xform<true,true,true>(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton);
+ else if (surf->format&(VS::ARRAY_FORMAT_NORMAL))
+ _skeleton_xform<true,false,true>(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton);
+ else if (surf->format&(VS::ARRAY_FORMAT_TANGENT))
+ _skeleton_xform<false,true,true>(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton);
+ else
+ _skeleton_xform<false,false,true>(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton);
+
+ }
+
+ stride=skeleton_valid?surf->stride:surf->local_stride;
+
+
#if 0
{
//in-place skeleton tansformation, only used for morphs, slow.
@@ -5066,14 +5889,14 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
const uint8_t *src_bones=&surf->array_local[surf->array[VS::ARRAY_BONES].ofs];
const Skeleton::Bone *skeleton = &p_skeleton->bones[0];
- if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT)
- _skeleton_xform<true,true>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
+ if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT)
+ _skeleton_xform<true,true,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
else if (surf->format&(VS::ARRAY_FORMAT_NORMAL))
- _skeleton_xform<true,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
+ _skeleton_xform<true,false,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
else if (surf->format&(VS::ARRAY_FORMAT_TANGENT))
- _skeleton_xform<false,true>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
+ _skeleton_xform<false,true,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
else
- _skeleton_xform<false,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
+ _skeleton_xform<false,false,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
stride=dst_stride;
@@ -5190,6 +6013,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;
@@ -5203,9 +6030,10 @@ void RasterizerGLES2::_render(const Geometry *p_geometry,const Material *p_mater
float twd=(1.0/mm->tw)*4.0;
float thd=1.0/mm->th;
float parm[3]={0.0,01.0,(1.0f/mm->tw)};
- glActiveTexture(GL_TEXTURE6);
+ glActiveTexture(GL_TEXTURE0+max_texture_units-2);
glDisableVertexAttribArray(6);
glBindTexture(GL_TEXTURE_2D,mm->tex_id);
+ material_shader.set_uniform(MaterialShaderGLES2::INSTANCE_MATRICES,GL_TEXTURE0+max_texture_units-2);
if (s->index_array_len>0) {
@@ -5506,7 +6334,7 @@ void RasterizerGLES2::_setup_skeleton(const Skeleton *p_skeleton) {
material_shader.set_conditional(MaterialShaderGLES2::USE_SKELETON,p_skeleton!=NULL);
if (p_skeleton && p_skeleton->tex_id) {
- glActiveTexture(GL_TEXTURE6);
+ glActiveTexture(GL_TEXTURE0+max_texture_units-2);
glBindTexture(GL_TEXTURE_2D,p_skeleton->tex_id);
}
@@ -5517,7 +6345,7 @@ void RasterizerGLES2::_setup_skeleton(const Skeleton *p_skeleton) {
void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Transform& p_view_transform, const Transform& p_view_transform_inverse,const CameraMatrix& p_projection,bool p_reverse_cull,bool p_fragment_light,bool p_alpha_pass) {
if (current_rt && current_rt_vflip) {
- p_reverse_cull=!p_reverse_cull;
+ //p_reverse_cull=!p_reverse_cull;
glFrontFace(GL_CCW);
}
@@ -5530,6 +6358,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
const Skeleton *prev_skeleton =NULL;
uint8_t prev_sort_flags=0xFF;
const BakedLightData *prev_baked_light=NULL;
+ RID prev_baked_light_texture;
Geometry::Type prev_geometry_type=Geometry::GEOMETRY_INVALID;
@@ -5546,6 +6375,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false);
material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,false);
material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false);
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
// material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,false);
}
@@ -5553,7 +6383,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
bool stores_glow = !shadow && (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) && !p_alpha_pass;
-
+ float sampled_light_dp_multiplier=1.0;
bool prev_blend=false;
glDisable(GL_BLEND);
@@ -5570,7 +6400,9 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
bool rebind=false;
bool bind_baked_light_octree=false;
+ bool bind_baked_lightmap=false;
bool additive=false;
+ bool bind_dp_sampler=false;
if (!shadow) {
@@ -5597,7 +6429,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
if (light_type!=prev_light_type) {
- if (material->flags[VS::MATERIAL_FLAG_UNSHADED]) {
+ if (material->flags[VS::MATERIAL_FLAG_UNSHADED] || current_debug==VS::SCENARIO_DEBUG_SHADELESS) {
material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_DIRECTIONAL,false);
material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_OMNI,false);
material_shader.set_conditional(MaterialShaderGLES2::LIGHT_TYPE_SPOT,false);
@@ -5647,10 +6479,12 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
if (desired_blend) {
glEnable(GL_BLEND);
- glColorMask(1,1,1,0);
+ if (!current_rt || !current_rt_transparent)
+ glColorMask(1,1,1,0);
} else {
glDisable(GL_BLEND);
glColorMask(1,1,1,1);
+
}
prev_blend=desired_blend;
@@ -5658,12 +6492,17 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
if (desired_blend && desired_blend_mode!=current_blend_mode) {
- switch(desired_blend_mode) {
+ switch(desired_blend_mode) {
case VS::MATERIAL_BLEND_MODE_MIX: {
glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
} break;
case VS::MATERIAL_BLEND_MODE_ADD: {
@@ -5674,12 +6513,17 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
} break;
case VS::MATERIAL_BLEND_MODE_SUB: {
- glBlendEquation(GL_FUNC_SUBTRACT);
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
} break;
case VS::MATERIAL_BLEND_MODE_MUL: {
glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
} break;
@@ -5689,30 +6533,87 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
}
material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false);
-// material_shader.set_conditional(MaterialShaderGLES2::USE_AMBIENT_TEXTURE,false);
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,false);
- if (!additive && baked_light) {
+ if (material->flags[VS::MATERIAL_FLAG_UNSHADED] == false && current_debug != VS::SCENARIO_DEBUG_SHADELESS) {
- 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 (e->instance->sampled_light.is_valid()) {
- glActiveTexture(GL_TEXTURE5);
- glBindTexture(tex->target,tex->tex_id); //bind the texture
- }
+ 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;
+ }
+ }
+
+
+ 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) {
+
+ 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;
+
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP, false);
+ bind_baked_lightmap = false;
+
+
+ if (baked_light->lightmaps.has(lightmap_idx)) {
+
+
+ RID texid = baked_light->lightmaps[lightmap_idx];
+
+ if (prev_baked_light != baked_light || texid != prev_baked_light_texture) {
- //material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,true);
+
+ Texture *tex = texture_owner.get(texid);
+ if (tex) {
+
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 3);
+ glBindTexture(tex->target, tex->tex_id); //bind the texture
+ }
+
+ prev_baked_light_texture = texid;
+ }
+
+ 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;
+ }
}
}
@@ -5771,13 +6672,34 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_SIZE, baked_light->octree_lattice_size);
material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_DIVIDE, baked_light->octree_lattice_divide);
material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_STEPS, baked_light->octree_steps);
- material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_TEX,5);
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_TEX,max_texture_units-3);
+ if (baked_light->light_texture.is_valid()) {
+
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_TEX,max_texture_units-4);
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_PIX_SIZE,baked_light->light_tex_pixel_size);
+ } else {
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_TEX,max_texture_units-3);
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_PIX_SIZE,baked_light->octree_tex_pixel_size);
+ }
material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_MULTIPLIER,baked_light->texture_multiplier);
material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_PIX_SIZE,baked_light->octree_tex_pixel_size);
}
+ if (bind_baked_lightmap && (baked_light!=prev_baked_light || rebind)) {
+
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP, max_texture_units-3);
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP_MULTIPLIER, baked_light->lightmap_multiplier);
+
+ }
+
+ if (bind_dp_sampler) {
+
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_DP_SAMPLER_MULTIPLIER,sampled_light_dp_multiplier);
+ material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_DP_SAMPLER,max_texture_units-3);
+ }
+
_set_cull(e->mirror,p_reverse_cull);
@@ -5785,13 +6707,13 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
material_shader.set_uniform(MaterialShaderGLES2::CAMERA_INVERSE_TRANSFORM, p_view_transform_inverse);
material_shader.set_uniform(MaterialShaderGLES2::PROJECTION_TRANSFORM, p_projection);
if (skeleton && use_hw_skeleton_xform) {
- //material_shader.set_uniform(MaterialShaderGLES2::SKELETON_MATRICES,6);
+ material_shader.set_uniform(MaterialShaderGLES2::SKELETON_MATRICES,GL_TEXTURE0+max_texture_units-2);
material_shader.set_uniform(MaterialShaderGLES2::SKELTEX_PIXEL_SIZE,skeleton->pixel_size);
}
if (!shadow) {
if (!additive && current_env && current_env->fx_enabled[VS::ENV_FX_AMBIENT_LIGHT]) {
- Color ambcolor = current_env->fx_param[VS::ENV_FX_PARAM_AMBIENT_LIGHT_COLOR];
+ Color ambcolor = _convert_color(current_env->fx_param[VS::ENV_FX_PARAM_AMBIENT_LIGHT_COLOR]);
float ambnrg = current_env->fx_param[VS::ENV_FX_PARAM_AMBIENT_LIGHT_ENERGY];
material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHT,Vector3(ambcolor.r*ambnrg,ambcolor.g*ambnrg,ambcolor.b*ambnrg));
} else {
@@ -5872,7 +6794,12 @@ void RasterizerGLES2::_copy_to_texscreen() {
#endif
glDisable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
//glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
@@ -6104,7 +7031,7 @@ void RasterizerGLES2::_draw_tex_bg() {
RID texture;
- if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
+ if (current_env->bg_mode==VS::ENV_BG_TEXTURE) {
texture=current_env->bg_param[VS::ENV_BG_PARAM_TEXTURE];
} else {
texture=current_env->bg_param[VS::ENV_BG_PARAM_CUBEMAP];
@@ -6121,25 +7048,20 @@ void RasterizerGLES2::_draw_tex_bg() {
copy_shader.set_conditional(CopyShaderGLES2::USE_ENERGY,true);
- if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
+ if (current_env->bg_mode==VS::ENV_BG_TEXTURE) {
copy_shader.set_conditional(CopyShaderGLES2::USE_CUBEMAP,false);
} else {
copy_shader.set_conditional(CopyShaderGLES2::USE_CUBEMAP,true);
}
- if (current_env->bg_mode==VS::ENV_BG_CUBEMAP_RGBE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
- copy_shader.set_conditional(CopyShaderGLES2::USE_RGBE,true);
- } else {
- copy_shader.set_conditional(CopyShaderGLES2::USE_RGBE,false);
- }
copy_shader.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA,true);
copy_shader.bind();
- if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
+ if (current_env->bg_mode==VS::ENV_BG_TEXTURE) {
glUniform1i( copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0);
} else {
glUniform1i( copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE_CUBE),0);
@@ -6166,7 +7088,7 @@ void RasterizerGLES2::_draw_tex_bg() {
Vector3( 0, 0, 0)
};
- if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
+ if (current_env->bg_mode==VS::ENV_BG_TEXTURE) {
//regular texture
//adjust aspect
@@ -6236,7 +7158,7 @@ void RasterizerGLES2::end_scene() {
if (framebuffer.active) {
//detect when to use the framebuffer object
- if (texscreen_used || framebuffer.scale!=1) {
+ if (using_canvas_bg || texscreen_used || framebuffer.scale!=1) {
use_fb=true;
} else if (current_env) {
use_fb=false;
@@ -6288,6 +7210,7 @@ void RasterizerGLES2::end_scene() {
switch(current_env->bg_mode) {
+ case VS::ENV_BG_CANVAS:
case VS::ENV_BG_KEEP: {
//copy from framebuffer if framebuffer
glClear(GL_DEPTH_BUFFER_BIT);
@@ -6300,7 +7223,7 @@ void RasterizerGLES2::end_scene() {
bgcolor = current_env->bg_param[VS::ENV_BG_PARAM_COLOR];
else
bgcolor = Globals::get_singleton()->get("render/default_clear_color");
- bgcolor = _convert_color(bgcolor);
+ bgcolor = _convert_color(bgcolor);
float a = use_fb ? float(current_env->bg_param[VS::ENV_BG_PARAM_GLOW]) : 1.0;
glClearColor(bgcolor.r,bgcolor.g,bgcolor.b,a);
_glClearDepth(1.0);
@@ -6308,9 +7231,7 @@ void RasterizerGLES2::end_scene() {
} break;
case VS::ENV_BG_TEXTURE:
- case VS::ENV_BG_CUBEMAP:
- case VS::ENV_BG_TEXTURE_RGBE:
- case VS::ENV_BG_CUBEMAP_RGBE: {
+ case VS::ENV_BG_CUBEMAP: {
glClear(GL_DEPTH_BUFFER_BIT);
@@ -6346,7 +7267,12 @@ void RasterizerGLES2::end_scene() {
current_depth_mask=true;
texscreen_copied=false;
glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
glDisable(GL_BLEND);
current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
@@ -6363,7 +7289,12 @@ void RasterizerGLES2::end_scene() {
}
glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
glDisable(GL_BLEND);
current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
material_shader.set_conditional(MaterialShaderGLES2::USE_GLOW,false);
@@ -6519,7 +7450,12 @@ void RasterizerGLES2::end_scene() {
_debug_shadows();
}
// _debug_luminances();
+// _debug_samplers();
+ if (using_canvas_bg) {
+ using_canvas_bg=false;
+ glColorMask(1,1,1,1); //don't touch alpha
+ }
}
void RasterizerGLES2::end_shadow_map() {
@@ -6919,6 +7855,38 @@ void RasterizerGLES2::_debug_luminances() {
}
+void RasterizerGLES2::_debug_samplers() {
+ canvas_shader.set_conditional(CanvasShaderGLES2::DEBUG_ENCODED_32,false);
+ canvas_begin();
+ glDisable(GL_BLEND);
+ _set_color_attrib(Color(1,1,1,1));
+ canvas_shader.bind();
+
+
+ List<RID> samplers;
+ sampled_light_owner.get_owned_list(&samplers);
+
+ Size2 debug_size(128,128);
+ Size2 ofs;
+
+
+ for (List<RID>::Element *E=samplers.front();E;E=E->next()) {
+
+ SampledLight *sl=sampled_light_owner.get(E->get());
+
+ _debug_draw_shadow(sl->texture, Rect2( ofs, debug_size ));
+
+ ofs.x+=debug_size.x/2;
+ if ( (ofs.x+debug_size.x) > viewport.width ) {
+
+ ofs.x=0;
+ ofs.y+=debug_size.y;
+ }
+ }
+
+
+
+}
void RasterizerGLES2::_debug_shadows() {
canvas_begin();
@@ -6956,8 +7924,26 @@ void RasterizerGLES2::flush_frame() {
/* CANVAS API */
+void RasterizerGLES2::begin_canvas_bg() {
+
+ if (framebuffer.active) {
+ using_canvas_bg=true;
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.fbo);
+ glViewport( 0,0,viewport.width , viewport.height );
+ } else {
+ using_canvas_bg=false;
+ }
+
+}
+
void RasterizerGLES2::canvas_begin() {
+
+ if (using_canvas_bg) {
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.fbo);
+ glColorMask(1,1,1,0); //don't touch alpha
+ }
+
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
@@ -6967,7 +7953,12 @@ void RasterizerGLES2::canvas_begin() {
#endif
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
//glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glLineWidth(1.0);
glBindBuffer(GL_ARRAY_BUFFER,0);
@@ -6981,10 +7972,13 @@ void RasterizerGLES2::canvas_begin() {
canvas_tex=RID();
//material_shader.unbind();
canvas_shader.unbind();
+ canvas_shader.set_custom_shader(0);
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false);
canvas_shader.bind();
canvas_shader.set_uniform(CanvasShaderGLES2::TEXTURE, 0);
+ canvas_use_modulate=false;
_set_color_attrib(Color(1,1,1));
- Transform canvas_transform;
+ canvas_transform=Transform();
canvas_transform.translate(-(viewport.width / 2.0f), -(viewport.height / 2.0f), 0.0f);
float csy = 1.0;
if (current_rt && current_rt_vflip)
@@ -6997,7 +7991,10 @@ void RasterizerGLES2::canvas_begin() {
canvas_opacity=1.0;
canvas_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
+ canvas_texscreen_used=false;
+ uses_texpixel_size=false;
+ canvas_last_material=NULL;
}
@@ -7019,7 +8016,12 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) {
case VS::MATERIAL_BLEND_MODE_MIX: {
glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
} break;
case VS::MATERIAL_BLEND_MODE_ADD: {
@@ -7030,12 +8032,12 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) {
} break;
case VS::MATERIAL_BLEND_MODE_SUB: {
- glBlendEquation(GL_FUNC_SUBTRACT);
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
} break;
case VS::MATERIAL_BLEND_MODE_MUL: {
glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFunc(GL_DST_COLOR,GL_ZERO);
} break;
case VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA: {
glBlendEquation(GL_FUNC_ADD);
@@ -7062,8 +8064,16 @@ void RasterizerGLES2::canvas_set_clip(bool p_clip, const Rect2& p_rect) {
if (p_clip) {
glEnable(GL_SCISSOR_TEST);
- glScissor(viewport.x+p_rect.pos.x,viewport.y+ (viewport.height-(p_rect.pos.y+p_rect.size.height)),
- p_rect.size.width,p_rect.size.height);
+ //glScissor(viewport.x+p_rect.pos.x,viewport.y+ (viewport.height-(p_rect.pos.y+p_rect.size.height)),
+
+ int x = p_rect.pos.x;
+ int y = window_size.height-(p_rect.pos.y+p_rect.size.y);
+ int w = p_rect.size.x;
+ int h = p_rect.size.y;
+
+ glScissor(x,y,w,h);
+
+
} else {
glDisable(GL_SCISSOR_TEST);
@@ -7080,7 +8090,7 @@ void RasterizerGLES2::canvas_end_rect() {
RasterizerGLES2::Texture* RasterizerGLES2::_bind_canvas_texture(const RID& p_texture) {
- if (p_texture==canvas_tex) {
+ if (p_texture==canvas_tex && !rebind_texpixel_size) {
if (canvas_tex.is_valid()) {
Texture*texture=texture_owner.get(p_texture);
return texture;
@@ -7088,14 +8098,16 @@ RasterizerGLES2::Texture* RasterizerGLES2::_bind_canvas_texture(const RID& p_tex
return NULL;
}
-
+ rebind_texpixel_size=false;
if (p_texture.is_valid()) {
+
Texture*texture=texture_owner.get(p_texture);
if (!texture) {
canvas_tex=RID();
glBindTexture(GL_TEXTURE_2D,white_tex);
+
return NULL;
}
@@ -7104,6 +8116,9 @@ RasterizerGLES2::Texture* RasterizerGLES2::_bind_canvas_texture(const RID& p_tex
glBindTexture(GL_TEXTURE_2D,texture->tex_id);
canvas_tex=p_texture;
+ if (uses_texpixel_size) {
+ canvas_shader.set_uniform(CanvasShaderGLES2::TEXPIXEL_SIZE,Size2(1.0/texture->width,1.0/texture->height));
+ }
return texture;
@@ -7252,7 +8267,7 @@ void RasterizerGLES2::_draw_gui_primitive2(int p_points, const Vector2 *p_vertic
_rinfo.ci_draw_commands++;
}
-void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip ) {
+void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip, bool p_transpose ) {
Vector2 texcoords[4]= {
Vector2( p_src_region.pos.x/p_tex_size.width,
@@ -7268,6 +8283,9 @@ void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_sr
(p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height)
};
+ if (p_transpose) {
+ SWAP( texcoords[1], texcoords[3] );
+ }
if (p_h_flip) {
SWAP( texcoords[0], texcoords[1] );
SWAP( texcoords[2], texcoords[3] );
@@ -7315,11 +8333,11 @@ void RasterizerGLES2::canvas_draw_rect(const Rect2& p_rect, int p_flags, const R
if (!(p_flags&CANVAS_RECT_REGION)) {
Rect2 region = Rect2(0,0,texture->width,texture->height);
- _draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V);
+ _draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V,p_flags&CANVAS_RECT_TRANSPOSE);
} else {
- _draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V );
+ _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);
}
} else {
@@ -7414,20 +8432,22 @@ void RasterizerGLES2::canvas_draw_primitive(const Vector<Point2>& p_points, cons
void RasterizerGLES2::canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor) {
- bool do_colors=false;
+ bool do_colors=false;
+ Color m;
+ if (p_singlecolor) {
+ m = *p_colors;
+ m.a*=canvas_opacity;
+ _set_color_attrib(m);
+ } else if (!p_colors) {
+ m = Color(1, 1, 1, canvas_opacity);
+ _set_color_attrib(m);
+ } else
+ do_colors=true;
- if (p_singlecolor) {
- Color m = *p_colors;
- m.a*=canvas_opacity;
- _set_color_attrib(m);
- } else if (!p_colors) {
- _set_color_attrib( Color(1,1,1,canvas_opacity));
- } else
- do_colors=true;
-
- Texture *texture = _bind_canvas_texture(p_texture);
+ Texture *texture = _bind_canvas_texture(p_texture);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+#ifndef GLES_NO_CLIENT_ARRAYS
+ glEnableVertexAttribArray(VS::ARRAY_VERTEX);
glVertexAttribPointer( VS::ARRAY_VERTEX, 2 ,GL_FLOAT, false, sizeof(Vector2), p_vertices );
if (do_colors) {
@@ -7446,12 +8466,89 @@ void RasterizerGLES2::canvas_draw_polygon(int p_vertex_count, const int* p_indic
}
if (p_indices) {
-
+#ifdef GLEW_ENABLED
glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_INT, p_indices );
+#else
+ static const int _max_draw_poly_indices = 16*1024; // change this size if needed!!!
+ ERR_FAIL_COND(p_vertex_count > _max_draw_poly_indices);
+ static uint16_t _draw_poly_indices[_max_draw_poly_indices];
+ for (int i=0; i<p_vertex_count; i++) {
+ _draw_poly_indices[i] = p_indices[i];
+ };
+ glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_SHORT, _draw_poly_indices );
+#endif
} else {
glDrawArrays(GL_TRIANGLES,0,p_vertex_count);
}
+
+#else //WebGL specific impl.
+ glBindBuffer(GL_ARRAY_BUFFER, gui_quad_buffer);
+ float *b = GlobalVertexBuffer;
+ int ofs = 0;
+ if(p_vertex_count > MAX_POLYGON_VERTICES){
+ print_line("Too many vertices to render");
+ return;
+ }
+ glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+ glVertexAttribPointer( VS::ARRAY_VERTEX, 2 ,GL_FLOAT, false, sizeof(float)*2, ((float*)0)+ofs );
+ for(int i=0;i<p_vertex_count;i++) {
+ b[ofs++]=p_vertices[i].x;
+ b[ofs++]=p_vertices[i].y;
+ }
+
+ if (p_colors && do_colors) {
+
+ glEnableVertexAttribArray(VS::ARRAY_COLOR);
+ glVertexAttribPointer( VS::ARRAY_COLOR, 4 ,GL_FLOAT, false, sizeof(float)*4, ((float*)0)+ofs );
+ for(int i=0;i<p_vertex_count;i++) {
+ b[ofs++]=p_colors[i].r;
+ b[ofs++]=p_colors[i].g;
+ b[ofs++]=p_colors[i].b;
+ b[ofs++]=p_colors[i].a;
+ }
+
+ } else {
+ glDisableVertexAttribArray(VS::ARRAY_COLOR);
+ }
+
+
+ if (p_uvs) {
+
+ glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glVertexAttribPointer( VS::ARRAY_TEX_UV, 2 ,GL_FLOAT, false, sizeof(float)*2, ((float*)0)+ofs );
+ for(int i=0;i<p_vertex_count;i++) {
+ b[ofs++]=p_uvs[i].x;
+ b[ofs++]=p_uvs[i].y;
+ }
+
+ } else {
+ glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ }
+
+ glBufferSubData(GL_ARRAY_BUFFER,0,ofs*4,&b[0]);
+
+ //bind the indices buffer.
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer);
+
+ static const int _max_draw_poly_indices = 16*1024; // change this size if needed!!!
+ ERR_FAIL_COND(p_vertex_count > _max_draw_poly_indices);
+ static uint16_t _draw_poly_indices[_max_draw_poly_indices];
+ for (int i=0; i<p_vertex_count; i++) {
+ _draw_poly_indices[i] = p_indices[i];
+ //OS::get_singleton()->print("ind: %d ", p_indices[i]);
+ };
+
+ //copy the data to GPU.
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, p_vertex_count * sizeof(uint16_t), &_draw_poly_indices[0]);
+
+ //draw the triangles.
+ glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_SHORT, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+#endif
+
_rinfo.ci_draw_commands++;
};
@@ -7464,6 +8561,1174 @@ void RasterizerGLES2::canvas_set_transform(const Matrix32& p_transform) {
//canvas_transform = Variant(p_transform);
}
+RID RasterizerGLES2::canvas_light_occluder_create() {
+
+ CanvasOccluder *co = memnew( CanvasOccluder );
+ co->index_id=0;
+ co->vertex_id=0;
+ co->len=0;
+
+ return canvas_occluder_owner.make_rid(co);
+}
+
+void RasterizerGLES2::canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines) {
+
+ CanvasOccluder *co = canvas_occluder_owner.get(p_occluder);
+ ERR_FAIL_COND(!co);
+
+ co->lines=p_lines;
+
+ if (p_lines.size()!=co->len) {
+
+ if (co->index_id)
+ glDeleteBuffers(1,&co->index_id);
+ if (co->vertex_id)
+ glDeleteBuffers(1,&co->vertex_id);
+
+ co->index_id=0;
+ co->vertex_id=0;
+ co->len=0;
+
+ }
+
+ if (p_lines.size()) {
+
+
+
+ DVector<float> geometry;
+ DVector<uint16_t> indices;
+ int lc = p_lines.size();
+
+ geometry.resize(lc*6);
+ indices.resize(lc*3);
+
+ DVector<float>::Write vw=geometry.write();
+ DVector<uint16_t>::Write iw=indices.write();
+
+
+ DVector<Vector2>::Read lr=p_lines.read();
+
+ const int POLY_HEIGHT = 16384;
+
+ for(int i=0;i<lc/2;i++) {
+
+ vw[i*12+0]=lr[i*2+0].x;
+ vw[i*12+1]=lr[i*2+0].y;
+ vw[i*12+2]=POLY_HEIGHT;
+
+ vw[i*12+3]=lr[i*2+1].x;
+ vw[i*12+4]=lr[i*2+1].y;
+ vw[i*12+5]=POLY_HEIGHT;
+
+ vw[i*12+6]=lr[i*2+1].x;
+ vw[i*12+7]=lr[i*2+1].y;
+ vw[i*12+8]=-POLY_HEIGHT;
+
+ vw[i*12+9]=lr[i*2+0].x;
+ vw[i*12+10]=lr[i*2+0].y;
+ vw[i*12+11]=-POLY_HEIGHT;
+
+ iw[i*6+0]=i*4+0;
+ iw[i*6+1]=i*4+1;
+ iw[i*6+2]=i*4+2;
+
+ iw[i*6+3]=i*4+2;
+ iw[i*6+4]=i*4+3;
+ iw[i*6+5]=i*4+0;
+
+ }
+
+ //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
+
+
+ if (!co->vertex_id) {
+ glGenBuffers(1,&co->vertex_id);
+ glBindBuffer(GL_ARRAY_BUFFER,co->vertex_id);
+ glBufferData(GL_ARRAY_BUFFER,lc*6*sizeof(real_t),vw.ptr(),GL_STATIC_DRAW);
+ } else {
+
+ glBindBuffer(GL_ARRAY_BUFFER,co->vertex_id);
+ glBufferSubData(GL_ARRAY_BUFFER,0,lc*6*sizeof(real_t),vw.ptr());
+
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+ if (!co->index_id) {
+
+ glGenBuffers(1,&co->index_id);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,co->index_id);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER,lc*3*sizeof(uint16_t),iw.ptr(),GL_STATIC_DRAW);
+ } else {
+
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,co->index_id);
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,lc*3*sizeof(uint16_t),iw.ptr());
+ }
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
+
+ co->len=lc;
+
+ }
+
+
+
+}
+
+RID RasterizerGLES2::canvas_light_shadow_buffer_create(int p_width) {
+
+ CanvasLightShadow *cls = memnew( CanvasLightShadow );
+ if (p_width>max_texture_size)
+ p_width=max_texture_size;
+
+ cls->size=p_width;
+ glActiveTexture(GL_TEXTURE0);
+
+ glGenFramebuffers(1, &cls->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
+
+ // Create a render buffer
+ glGenRenderbuffers(1, &cls->rbo);
+ glBindRenderbuffer(GL_RENDERBUFFER, cls->rbo);
+
+ // Create a texture for storing the depth
+ glGenTextures(1, &cls->depth);
+ glBindTexture(GL_TEXTURE_2D, cls->depth);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ // Remove artifact on the edges of the shadowmap
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ cls->height=16;
+
+ //print_line("ERROR? "+itos(glGetError()));
+ if ( read_depth_supported ) {
+
+ // We'll use a depth texture to store the depths in the shadow map
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, cls->size, cls->height, 0,
+ GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+
+#ifdef GLEW_ENABLED
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#endif
+
+ // Attach the depth texture to FBO depth attachment point
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_TEXTURE_2D, cls->depth, 0);
+
+#ifdef GLEW_ENABLED
+ glDrawBuffer(GL_NONE);
+#endif
+
+ } else {
+ // We'll use a RGBA texture into which we pack the depth info
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ // Attach the RGBA texture to FBO color attachment point
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, cls->depth, 0);
+ cls->rgba=cls->depth;
+
+ // Allocate 16-bit depth buffer
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height);
+
+ // Attach the render buffer as depth buffer - will be ignored
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, cls->rbo);
+
+
+ }
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ //printf("errnum: %x\n",status);
+#ifdef GLEW_ENABLED
+ if (read_depth_supported) {
+ //glDrawBuffer(GL_BACK);
+ }
+#endif
+ glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer);
+ DEBUG_TEST_ERROR("2D Shadow Buffer Init");
+ ERR_FAIL_COND_V( status != GL_FRAMEBUFFER_COMPLETE, RID() );
+
+#ifdef GLEW_ENABLED
+ if (read_depth_supported) {
+ //glDrawBuffer(GL_BACK);
+ }
+#endif
+
+ return canvas_light_shadow_owner.make_rid(cls);
+}
+
+void RasterizerGLES2::canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache) {
+
+ CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_buffer);
+ ERR_FAIL_COND(!cls);
+
+
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_DITHER);
+ glDisable(GL_CULL_FACE);
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(true);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
+
+ if (!use_rgba_shadowmaps)
+ glColorMask(0, 0, 0, 0);
+
+ glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+ canvas_shadow_shader.bind();
+
+ const int vp_height = 10;
+
+ glViewport(0, 0, cls->size,cls->height);
+ _glClearDepth(1.0f);
+ glClearColor(1,1,1,1);
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+
+ VS::CanvasOccluderPolygonCullMode cull=VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+
+
+ for(int i=0;i<4;i++) {
+
+ //make sure it remains orthogonal, makes easy to read angle later
+
+ Transform light;
+ light.origin[0]=p_light_xform[2][0];
+ light.origin[1]=p_light_xform[2][1];
+ light.basis[0][0]=p_light_xform[0][0];
+ light.basis[0][1]=p_light_xform[1][0];
+ light.basis[1][0]=p_light_xform[0][1];
+ light.basis[1][1]=p_light_xform[1][1];
+
+ //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
+
+ /// p_near=1;
+ CameraMatrix projection;
+ {
+ real_t fov = 90;
+ real_t near = p_near;
+ real_t far = p_far;
+ real_t aspect = 1.0;
+
+ real_t ymax = near * Math::tan( Math::deg2rad( fov * 0.5 ) );
+ real_t ymin = - ymax;
+ real_t xmin = ymin * aspect;
+ real_t xmax = ymax * aspect;
+
+ projection.set_frustum( xmin, xmax, ymin, ymax, near, far );
+ }
+
+ Vector3 cam_target=Matrix3(Vector3(0,0,Math_PI*2*(i/4.0))).xform(Vector3(0,1,0));
+ projection = projection * CameraMatrix(Transform().looking_at(cam_target,Vector3(0,0,-1)).affine_inverse());
+
+ //print_line("near: "+rtos(p_near));
+ //print_line("far: "+rtos(p_far));
+ //projection.set_perspective(60,size/float(vp_height),p_near,p_far);
+
+ // CameraMatrix light_mat = projection * CameraMatrix(camera);
+
+ canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::PROJECTION_MATRIX,projection);
+ canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::LIGHT_MATRIX,light);
+
+ if (i==0)
+ *p_xform_cache=projection;
+
+ glViewport(0, (cls->height/4)*i, cls->size,cls->height/4);
+
+ CanvasLightOccluderInstance *instance=p_occluders;
+
+ while(instance) {
+
+ CanvasOccluder *cc = canvas_occluder_owner.get(instance->polygon_buffer);
+ if (!cc || cc->len==0 || !(p_light_mask&instance->light_mask)) {
+
+ instance=instance->next;
+ continue;
+ }
+
+ canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::WORLD_MATRIX,instance->xform_cache);
+ if (cull!=instance->cull_cache) {
+
+ cull=instance->cull_cache;
+ switch(cull) {
+ case VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: {
+
+ glDisable(GL_CULL_FACE);
+
+ } break;
+ case VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: {
+
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_FRONT);
+ } break;
+ case VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: {
+
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+
+ } break;
+ }
+ }
+/*
+ if (i==0) {
+ for(int i=0;i<cc->lines.size();i++) {
+ Vector2 p = instance->xform_cache.xform(cc->lines.get(i));
+ Plane pp(Vector3(p.x,p.y,0),1);
+ pp.normal = light.xform(pp.normal);
+ pp = projection.xform4(pp);
+ print_line(itos(i)+": "+pp.normal/pp.d);
+ //pp=light_mat.xform4(pp);
+ //print_line(itos(i)+": "+pp.normal/pp.d);
+ }
+ }
+*/
+ glBindBuffer(GL_ARRAY_BUFFER,cc->vertex_id);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,cc->index_id);
+ glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0);
+ glDrawElements(GL_TRIANGLES,cc->len*3,GL_UNSIGNED_SHORT,0);
+
+
+ instance=instance->next;
+ }
+
+
+ }
+
+ glDisableVertexAttribArray(VS::ARRAY_VERTEX);
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
+
+ if (shadow_filter==SHADOW_FILTER_ESM) {
+ //blur the buffer
+#if 0
+ //this is ignord, it did not make any difference..
+ if (read_depth_supported) {
+ glDepthFunc(GL_ALWAYS);
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(false);
+ }
+ glDisable(GL_CULL_FACE);
+ glViewport(0, 0, cls->size,cls->height);
+
+ int passes=1;
+ CanvasLightShadow *blur = canvas_light_shadow_owner.get(canvas_shadow_blur);
+
+ copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,true);
+ copy_shader.bind();
+ copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SCALE,1);
+ copy_shader.set_uniform(CopyShaderGLES2::BLUR_MAGNITUDE,1);
+ glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0);
+
+ for(int i=0;i<passes;i++) {
+
+ glBindFramebuffer(GL_FRAMEBUFFER, blur->fbo);
+ glActiveTexture(GL_TEXTURE0);
+
+ if (read_depth_supported)
+ glBindTexture(GL_TEXTURE_2D,cls->depth);
+ else
+ glBindTexture(GL_TEXTURE_2D,cls->rgba);
+
+
+ {
+ Vector2 src_sb_uv[4]={
+ Vector2( 0, 1),
+ Vector2( 1, 1),
+ Vector2( 1, 0),
+ Vector2( 0, 0)
+ };
+ static const Vector2 dst_pos[4]={
+ Vector2(-1, 1),
+ Vector2( 1, 1),
+ Vector2( 1,-1),
+ Vector2(-1,-1)
+ };
+
+
+
+ copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Vector2(1.0,1.0)/cls->size);
+ _draw_gui_primitive(4,dst_pos,NULL,src_sb_uv);
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ if (read_depth_supported)
+ glBindTexture(GL_TEXTURE_2D,blur->depth);
+ else
+ glBindTexture(GL_TEXTURE_2D,blur->rgba);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
+
+ {
+ float hlimit = float(cls->size) / blur->size;
+ //hlimit*=2.0;
+ Vector2 src_sb_uv[4]={
+ Vector2( 0, 1),
+ Vector2( hlimit, 1),
+ Vector2( hlimit, 0),
+ Vector2( 0, 0)
+ };
+ static const Vector2 dst_pos[4]={
+ Vector2(-1, 1),
+ Vector2( 1, 1),
+ Vector2( 1,-1),
+ Vector2(-1,-1)
+ };
+
+
+ copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Vector2(1.0,1.0)/blur->size);
+ _draw_gui_primitive(4,dst_pos,NULL,src_sb_uv);
+ }
+
+ }
+ copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,false);
+ glDepthFunc(GL_LEQUAL);
+#endif
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer);
+ glColorMask(1, 1, 1, 1);
+
+
+
+}
+
+
+void RasterizerGLES2::canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow) {
+
+ CanvasLight* light=p_lights_with_shadow;
+
+ canvas_begin(); //reset
+
+ int h = 10;
+ int w = viewport.width;
+ int ofs = h;
+
+ //print_line(" debug lights ");
+ while(light) {
+
+ // print_line("debug light");
+ if (light->shadow_buffer.is_valid()) {
+
+ // print_line("sb is valid");
+ CanvasLightShadow * sb = canvas_light_shadow_owner.get(light->shadow_buffer);
+ if (sb) {
+ glActiveTexture(GL_TEXTURE0);
+ if (read_depth_supported)
+ glBindTexture(GL_TEXTURE_2D,sb->depth);
+ else
+ glBindTexture(GL_TEXTURE_2D,sb->rgba);
+ _draw_textured_quad(Rect2(h,ofs,w-h*2,h),Rect2(0,0,sb->size,10),Size2(sb->size,10),false,false);
+ ofs+=h*2;
+
+ }
+ }
+
+ light=light->shadows_next_ptr;
+ }
+
+}
+
+void RasterizerGLES2::_canvas_normal_set_flip(const Vector2& p_flip) {
+
+ if (p_flip==normal_flip)
+ return;
+ normal_flip=p_flip;
+ canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,normal_flip);
+}
+
+
+template<bool use_normalmap>
+void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip) {
+
+ int cc=p_item->commands.size();
+ CanvasItem::Command **commands = p_item->commands.ptr();
+
+
+ for(int i=0;i<cc;i++) {
+
+ CanvasItem::Command *c=commands[i];
+
+ switch(c->type) {
+ case CanvasItem::Command::TYPE_LINE: {
+
+ CanvasItem::CommandLine* line = static_cast<CanvasItem::CommandLine*>(c);
+ canvas_draw_line(line->from,line->to,line->color,line->width);
+ } break;
+ case CanvasItem::Command::TYPE_RECT: {
+
+ CanvasItem::CommandRect* rect = static_cast<CanvasItem::CommandRect*>(c);
+// canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate);
+#if 0
+ int flags=0;
+
+ if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) {
+ flags|=Rasterizer::CANVAS_RECT_REGION;
+ }
+ if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) {
+ flags|=Rasterizer::CANVAS_RECT_TILE;
+ }
+ if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) {
+
+ flags|=Rasterizer::CANVAS_RECT_FLIP_H;
+ }
+ if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) {
+
+ flags|=Rasterizer::CANVAS_RECT_FLIP_V;
+ }
+#else
+
+ int flags=rect->flags;
+#endif
+ if (use_normalmap)
+ _canvas_normal_set_flip(Vector2((flags&CANVAS_RECT_FLIP_H)?-1:1,(flags&CANVAS_RECT_FLIP_V)?-1:1));
+ canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate);
+
+ } break;
+ case CanvasItem::Command::TYPE_STYLE: {
+
+ CanvasItem::CommandStyle* style = static_cast<CanvasItem::CommandStyle*>(c);
+ if (use_normalmap)
+ _canvas_normal_set_flip(Vector2(1,1));
+ canvas_draw_style_box(style->rect,style->texture,style->margin,style->draw_center,style->color);
+
+ } break;
+ case CanvasItem::Command::TYPE_PRIMITIVE: {
+
+ if (use_normalmap)
+ _canvas_normal_set_flip(Vector2(1,1));
+ CanvasItem::CommandPrimitive* primitive = static_cast<CanvasItem::CommandPrimitive*>(c);
+ canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width);
+ } break;
+ case CanvasItem::Command::TYPE_POLYGON: {
+
+ if (use_normalmap)
+ _canvas_normal_set_flip(Vector2(1,1));
+ CanvasItem::CommandPolygon* polygon = static_cast<CanvasItem::CommandPolygon*>(c);
+ canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1);
+
+ } break;
+
+ case CanvasItem::Command::TYPE_POLYGON_PTR: {
+
+ if (use_normalmap)
+ _canvas_normal_set_flip(Vector2(1,1));
+ CanvasItem::CommandPolygonPtr* polygon = static_cast<CanvasItem::CommandPolygonPtr*>(c);
+ canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false);
+ } break;
+ case CanvasItem::Command::TYPE_CIRCLE: {
+
+ CanvasItem::CommandCircle* circle = static_cast<CanvasItem::CommandCircle*>(c);
+ static const int numpoints=32;
+ Vector2 points[numpoints+1];
+ points[numpoints]=circle->pos;
+ int indices[numpoints*3];
+
+ for(int i=0;i<numpoints;i++) {
+
+ points[i]=circle->pos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius;
+ indices[i*3+0]=i;
+ indices[i*3+1]=(i+1)%numpoints;
+ indices[i*3+2]=numpoints;
+ }
+ canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true);
+ //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1);
+ } break;
+ case CanvasItem::Command::TYPE_TRANSFORM: {
+
+ CanvasItem::CommandTransform* transform = static_cast<CanvasItem::CommandTransform*>(c);
+ canvas_set_transform(transform->xform);
+ } break;
+ case CanvasItem::Command::TYPE_BLEND_MODE: {
+
+ CanvasItem::CommandBlendMode* bm = static_cast<CanvasItem::CommandBlendMode*>(c);
+ canvas_set_blend_mode(bm->blend_mode);
+
+ } break;
+ case CanvasItem::Command::TYPE_CLIP_IGNORE: {
+
+ CanvasItem::CommandClipIgnore* ci = static_cast<CanvasItem::CommandClipIgnore*>(c);
+ if (current_clip) {
+
+ if (ci->ignore!=reclip) {
+ if (ci->ignore) {
+
+ glDisable(GL_SCISSOR_TEST);
+ reclip=true;
+ } else {
+
+ glEnable(GL_SCISSOR_TEST);
+ //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;
+ 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);
+
+
+ reclip=false;
+ }
+ }
+ }
+
+
+
+ } break;
+ }
+ }
+
+}
+
+void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* shader) {
+
+ if (canvas_shader.bind())
+ rebind_texpixel_size=true;
+
+ if (material->shader_version!=shader->version) {
+ //todo optimize uniforms
+ material->shader_version=shader->version;
+ }
+
+ if (shader->has_texscreen && framebuffer.active) {
+
+ int x = viewport.x;
+ int y = window_size.height-(viewport.height+viewport.y);
+
+ canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height));
+ canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height));
+ canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,max_texture_units-1);
+ glActiveTexture(GL_TEXTURE0+max_texture_units-1);
+ glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
+ if (framebuffer.scale==1 && !canvas_texscreen_used) {
+#ifdef GLEW_ENABLED
+ 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) {
+// // print_line(" a clip ");
+// }
+
+ canvas_texscreen_used=true;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+
+ }
+
+ if (shader->has_screen_uv) {
+ canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height));
+ }
+
+
+ uses_texpixel_size=shader->uses_texpixel_size;
+
+}
+
+void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* shader) {
+
+ //this can be optimized..
+ int tex_id=1;
+ int idx=0;
+ for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
+
+ Map<StringName,Variant>::Element *F=material->shader_param.find(E->key());
+
+ if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) {
+
+ RID rid;
+ if (F) {
+ rid=F->get();
+ }
+
+ if (!rid.is_valid()) {
+
+ Map<StringName,RID>::Element *DT=shader->default_textures.find(E->key());
+ if (DT) {
+ rid=DT->get();
+ }
+ }
+
+ if (rid.is_valid()) {
+
+ int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic..
+
+ glActiveTexture(GL_TEXTURE0+tex_id);
+ Texture *t=texture_owner.get(rid);
+ if (!t)
+ glBindTexture(GL_TEXTURE_2D,white_tex);
+ else
+ glBindTexture(t->target,t->tex_id);
+
+ glUniform1i(loc,tex_id);
+ tex_id++;
+ }
+ } else {
+ Variant &v=F?F->get():E->get().default_value;
+ canvas_shader.set_custom_uniform(idx,v);
+ }
+
+ idx++;
+ }
+
+ if (tex_id>1) {
+ glActiveTexture(GL_TEXTURE0);
+ }
+
+ if (shader->uses_time) {
+ canvas_shader.set_uniform(CanvasShaderGLES2::TIME,Math::fmod(last_time,shader_time_rollback));
+ draw_next_frame=true;
+ }
+ //if uses TIME - draw_next_frame=true
+
+
+}
+
+void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light) {
+
+
+ CanvasItem *current_clip=NULL;
+ Shader *shader_cache=NULL;
+
+ bool rebind_shader=true;
+
+ canvas_opacity=1.0;
+ canvas_use_modulate=p_modulate!=Color(1,1,1,1);
+ canvas_modulate=p_modulate;
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD,false);
+
+
+ bool reset_modulate=false;
+ bool prev_distance_field=false;
+
+ while(p_item_list) {
+
+ CanvasItem *ci=p_item_list;
+
+ if (ci->vp_render) {
+ if (draw_viewport_func) {
+ draw_viewport_func(ci->vp_render->owner,ci->vp_render->udata,ci->vp_render->rect);
+ }
+ memdelete(ci->vp_render);
+ ci->vp_render=NULL;
+ canvas_last_material=NULL;
+ canvas_use_modulate=p_modulate!=Color(1,1,1,1);
+ canvas_modulate=p_modulate;
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD,false);
+ prev_distance_field=false;
+ rebind_shader=true;
+ reset_modulate=true;
+
+
+ }
+
+ if (prev_distance_field!=ci->distance_field) {
+
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD,ci->distance_field);
+ prev_distance_field=ci->distance_field;
+ rebind_shader=true;
+ }
+
+
+ if (current_clip!=ci->final_clip_owner) {
+
+ current_clip=ci->final_clip_owner;
+
+ //setup clip
+ if (current_clip) {
+
+ glEnable(GL_SCISSOR_TEST);
+ //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 = viewport.x+current_clip->final_clip_rect.pos.x;
+ int y = window_size.height-(viewport.y+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);
+
+ } else {
+
+ glDisable(GL_SCISSOR_TEST);
+ }
+ }
+
+ if (ci->copy_back_buffer && framebuffer.active && framebuffer.scale==1) {
+
+ Rect2 rect;
+ int x,y,w,h;
+
+ if (ci->copy_back_buffer->full) {
+
+ x = viewport.x;
+ y = window_size.height-(viewport.height+viewport.y);
+ w = viewport.width;
+ h = viewport.height;
+ } else {
+ x = viewport.x+ci->copy_back_buffer->screen_rect.pos.x;
+ y = window_size.height-(viewport.y+ci->copy_back_buffer->screen_rect.pos.y+ci->copy_back_buffer->screen_rect.size.y);
+ w = ci->copy_back_buffer->screen_rect.size.x;
+ h = ci->copy_back_buffer->screen_rect.size.y;
+ }
+ glActiveTexture(GL_TEXTURE0+max_texture_units-1);
+ glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
+
+#ifdef GLEW_ENABLED
+ 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) {
+// // print_line(" a clip ");
+// }
+
+ canvas_texscreen_used=true;
+ glActiveTexture(GL_TEXTURE0);
+ }
+
+
+
+
+ //begin rect
+ CanvasItem *material_owner = ci->material_owner?ci->material_owner:ci;
+ CanvasItemMaterial *material = material_owner->material;
+
+ if (material!=canvas_last_material || rebind_shader) {
+
+ Shader *shader = NULL;
+ if (material && material->shader.is_valid()) {
+ shader = shader_owner.get(material->shader);
+ if (shader && !shader->valid) {
+ shader=NULL;
+ }
+ }
+
+ shader_cache=shader;
+
+ if (shader) {
+ canvas_shader.set_custom_shader(shader->custom_code_id);
+ _canvas_item_setup_shader_params(material,shader);
+ } else {
+ shader_cache=NULL;
+ canvas_shader.set_custom_shader(0);
+ canvas_shader.bind();
+ uses_texpixel_size=false;
+
+ }
+
+
+ canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform);
+ if (canvas_use_modulate)
+ reset_modulate=true;
+ canvas_last_material=material;
+ rebind_shader=false;
+ }
+
+ if (material && shader_cache) {
+
+ _canvas_item_setup_shader_uniforms(material,shader_cache);
+ }
+
+ bool unshaded = (material && material->shading_mode==VS::CANVAS_ITEM_SHADING_UNSHADED) || ci->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX;
+
+ if (unshaded) {
+ canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,Color(1,1,1,1));
+ reset_modulate=true;
+ } else if (reset_modulate) {
+ canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
+ reset_modulate=false;
+ }
+
+
+
+ canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
+ canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32());
+
+
+ bool reclip=false;
+
+ if (ci==p_item_list || ci->blend_mode!=canvas_blend_mode) {
+
+ switch(ci->blend_mode) {
+
+ case VS::MATERIAL_BLEND_MODE_MIX: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ } break;
+ case VS::MATERIAL_BLEND_MODE_ADD: {
+
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+
+ } break;
+ case VS::MATERIAL_BLEND_MODE_SUB: {
+
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+ } break;
+ case VS::MATERIAL_BLEND_MODE_MUL: {
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_DST_COLOR,GL_ZERO);
+ } break;
+ case VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA: {
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
+ } break;
+
+ }
+
+ canvas_blend_mode=ci->blend_mode;
+ }
+
+ canvas_opacity = ci->final_opacity;
+
+
+ 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) {
+
+ CanvasLight *light = p_light;
+ bool light_used=false;
+ VS::CanvasLightMode mode=VS::CANVAS_LIGHT_MODE_ADD;
+
+
+ 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)) {
+
+ //intersects this light
+
+ if (!light_used || mode!=light->mode) {
+
+ mode=light->mode;
+
+ switch(mode) {
+
+ case VS::CANVAS_LIGHT_MODE_ADD: {
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+
+ } break;
+ case VS::CANVAS_LIGHT_MODE_SUB: {
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+ } break;
+ 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);
+
+ } break;
+ }
+
+ }
+
+ if (!light_used) {
+
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,true);
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false);
+ light_used=true;
+ normal_flip=Vector2(1,1);
+
+ }
+
+
+ bool has_shadow = light->shadow_buffer.is_valid() && ci->light_mask&light->item_shadow_mask;
+
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,has_shadow);
+
+ bool light_rebind = canvas_shader.bind();
+
+ if (light_rebind) {
+
+ if (material && shader_cache) {
+ _canvas_item_setup_shader_params(material,shader_cache);
+ _canvas_item_setup_shader_uniforms(material,shader_cache);
+ }
+
+ canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
+ canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32());
+ canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform);
+ if (canvas_use_modulate)
+ canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
+ canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,Vector2(1,1));
+ canvas_shader.set_uniform(CanvasShaderGLES2::SHADOWPIXEL_SIZE,1.0/light->shadow_buffer_size);
+
+
+ }
+
+ canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX,light->light_shader_xform);
+ canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS,light->light_shader_pos);
+ 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) {
+
+ CanvasLightShadow *cls = canvas_light_shadow_owner.get(light->shadow_buffer);
+ glActiveTexture(GL_TEXTURE0+max_texture_units-3);
+ if (read_depth_supported)
+ glBindTexture(GL_TEXTURE_2D,cls->depth);
+ else
+ glBindTexture(GL_TEXTURE_2D,cls->rgba);
+
+ 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);
+
+ }
+
+
+ glActiveTexture(GL_TEXTURE0+max_texture_units-2);
+ canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_TEXTURE,max_texture_units-2);
+ Texture *t = texture_owner.get(light->texture);
+ if (!t) {
+ glBindTexture(GL_TEXTURE_2D,white_tex);
+ } else {
+
+ glBindTexture(t->target,t->tex_id);
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ _canvas_item_render_commands<true>(ci,current_clip,reclip); //redraw using light
+
+ }
+
+ light=light->next_ptr;
+ }
+
+ if (light_used) {
+
+
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,false);
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,false);
+
+ canvas_shader.bind();
+
+ if (material && shader_cache) {
+ _canvas_item_setup_shader_params(material,shader_cache);
+ _canvas_item_setup_shader_uniforms(material,shader_cache);
+ }
+
+ canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
+ canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32());
+ if (canvas_use_modulate)
+ canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
+
+ glBlendEquation(GL_FUNC_ADD);
+ if (current_rt && current_rt_transparent) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ }
+
+
+ }
+
+ if (reclip) {
+
+ glEnable(GL_SCISSOR_TEST);
+ //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;
+ 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);
+
+
+ }
+
+
+
+ p_item_list=p_item_list->next;
+ }
+
+ if (current_clip) {
+ glDisable(GL_SCISSOR_TEST);
+ }
+
+}
+
/* ENVIRONMENT */
RID RasterizerGLES2::environment_create() {
@@ -7536,6 +9801,78 @@ Variant RasterizerGLES2::environment_fx_get_param(RID p_env,VS::EnvironmentFxPar
}
+
+
+RID RasterizerGLES2::sampled_light_dp_create(int p_width,int p_height) {
+
+ SampledLight *slight = memnew(SampledLight);
+ slight->w=p_width;
+ slight->h=p_height;
+ slight->multiplier=1.0;
+ slight->is_float=float_linear_supported;
+
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1,&slight->texture);
+ glBindTexture(GL_TEXTURE_2D, slight->texture);
+// for debug, but glitchy
+// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ // Remove artifact on the edges of the shadowmap
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+
+ if (slight->is_float) {
+#ifdef GLEW_ENABLED
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_width, p_height, 0, GL_RGBA, GL_FLOAT,NULL);
+#else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_width, p_height, 0, GL_RGBA, GL_FLOAT,NULL);
+#endif
+ } else {
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_width, p_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ }
+
+ return sampled_light_owner.make_rid(slight);
+}
+
+void RasterizerGLES2::sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier) {
+
+ SampledLight *slight = sampled_light_owner.get(p_sampled_light);
+ ERR_FAIL_COND(!slight);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, slight->texture);
+
+ if (slight->is_float) {
+
+#ifdef GLEW_ENABLED
+ glTexSubImage2D(GL_TEXTURE_2D, 0,0,0,slight->w, slight->h, GL_RGBA, GL_FLOAT,p_data);
+#else
+ glTexSubImage2D(GL_TEXTURE_2D, 0,0,0,slight->w, slight->h, GL_RGBA, GL_FLOAT,p_data);
+#endif
+
+ } else {
+ //convert to bytes
+ uint8_t *tex8 = (uint8_t*)alloca(slight->w*slight->h*4);
+ const float* src=(const float*)p_data;
+
+ for(int i=0;i<slight->w*slight->h*4;i++) {
+
+ tex8[i]=Math::fast_ftoi(CLAMP(src[i]*255.0,0.0,255.0));
+ }
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0,0,0,slight->w, slight->h, GL_RGBA, GL_UNSIGNED_BYTE,p_data);
+ }
+
+ slight->multiplier=p_multiplier;
+
+}
+
/*MISC*/
bool RasterizerGLES2::is_texture(const RID& p_rid) const {
@@ -7585,6 +9922,11 @@ bool RasterizerGLES2::is_environment(const RID& p_rid) const {
}
bool RasterizerGLES2::is_shader(const RID& p_rid) const {
+ return shader_owner.owns(p_rid);
+}
+
+bool RasterizerGLES2::is_canvas_light_occluder(const RID& p_rid) const {
+
return false;
}
@@ -7647,9 +9989,9 @@ void RasterizerGLES2::free(const RID& p_rid) {
for(int i=0;i<mesh->morph_target_count;i++) {
- memfree(surface->morph_targets_local[i].array);
+ memdelete_arr(surface->morph_targets_local[i].array);
}
- memfree(surface->morph_targets_local);
+ memdelete_arr(surface->morph_targets_local);
surface->morph_targets_local=NULL;
}
@@ -7755,7 +10097,37 @@ void RasterizerGLES2::free(const RID& p_rid) {
memdelete(render_target->texture_ptr);
render_target_owner.free(p_rid);
memdelete( render_target );
+ } else if (sampled_light_owner.owns(p_rid)) {
+
+ SampledLight *sampled_light = sampled_light_owner.get( p_rid );
+ ERR_FAIL_COND(!sampled_light);
+ glDeleteTextures(1,&sampled_light->texture);
+ sampled_light_owner.free(p_rid);
+ memdelete( sampled_light );
+ } else if (canvas_occluder_owner.owns(p_rid)) {
+
+ CanvasOccluder *co = canvas_occluder_owner.get(p_rid);
+ if (co->index_id)
+ glDeleteBuffers(1,&co->index_id);
+ if (co->vertex_id)
+ glDeleteBuffers(1,&co->vertex_id);
+
+ canvas_occluder_owner.free(p_rid);
+ memdelete(co);
+
+ } else if (canvas_light_shadow_owner.owns(p_rid)) {
+
+ CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid);
+ glDeleteFramebuffers(1,&cls->fbo);
+ glDeleteRenderbuffers(1,&cls->rbo);
+ glDeleteTextures(1,&cls->depth);
+ //if (!read_depth_supported) {
+ // glDeleteTextures(1,&cls->rgba);
+ //}
+
+ canvas_light_shadow_owner.free(p_rid);
+ memdelete(cls);
};
}
@@ -7871,7 +10243,7 @@ bool RasterizerGLES2::ShadowBuffer::init(int p_size,bool p_use_depth) {
//printf("errnum: %x\n",status);
#ifdef GLEW_ENABLED
if (p_use_depth) {
- glDrawBuffer(GL_BACK);
+ //glDrawBuffer(GL_BACK);
}
#endif
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -7880,7 +10252,7 @@ bool RasterizerGLES2::ShadowBuffer::init(int p_size,bool p_use_depth) {
#ifdef GLEW_ENABLED
if (p_use_depth) {
- glDrawBuffer(GL_BACK);
+ //glDrawBuffer(GL_BACK);
}
#endif
@@ -7976,7 +10348,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;
@@ -8018,6 +10394,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;*/
@@ -8031,7 +10414,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);
@@ -8056,7 +10439,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
@@ -8065,7 +10448,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);
@@ -8125,7 +10508,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);
@@ -8197,9 +10580,13 @@ void RasterizerGLES2::_update_framebuffer() {
}
-void RasterizerGLES2::set_base_framebuffer(GLuint p_id) {
+void RasterizerGLES2::set_base_framebuffer(GLuint p_id, Vector2 p_size) {
base_framebuffer=p_id;
+
+ if (p_size.x != 0) {
+ window_size = p_size;
+ };
}
#if 0
@@ -8254,6 +10641,62 @@ void RasterizerGLES2::_update_blur_buffer() {
}
#endif
+
+
+bool RasterizerGLES2::_test_depth_shadow_buffer() {
+
+
+ int size=16;
+
+ GLuint fbo;
+ GLuint rbo;
+ GLuint depth;
+
+ glActiveTexture(GL_TEXTURE0);
+
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ // Create a render buffer
+ glGenRenderbuffers(1, &rbo);
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo);
+
+ // Create a texture for storing the depth
+ glGenTextures(1, &depth);
+ glBindTexture(GL_TEXTURE_2D, depth);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ // Remove artifact on the edges of the shadowmap
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+
+
+ // We'll use a depth texture to store the depths in the shadow map
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size, size, 0,
+ GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+
+#ifdef GLEW_ENABLED
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#endif
+
+ // Attach the depth texture to FBO depth attachment point
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_TEXTURE_2D, depth, 0);
+
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ glDeleteFramebuffers(1,&fbo);
+ glDeleteRenderbuffers(1,&rbo);
+ glDeleteTextures(1,&depth);
+
+ return status == GL_FRAMEBUFFER_COMPLETE;
+
+}
+
void RasterizerGLES2::init() {
#ifdef GLEW_ENABLED
@@ -8286,10 +10729,12 @@ void RasterizerGLES2::init() {
material_shader.init();
canvas_shader.init();
copy_shader.init();
+ canvas_shadow_shader.init();
#ifdef GLEW_ENABLED
material_shader.set_conditional(MaterialShaderGLES2::USE_GLES_OVER_GL,true);
canvas_shader.set_conditional(CanvasShaderGLES2::USE_GLES_OVER_GL,true);
+ canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_GLES_OVER_GL,true);
copy_shader.set_conditional(CopyShaderGLES2::USE_GLES_OVER_GL,true);
#endif
@@ -8311,9 +10756,6 @@ void RasterizerGLES2::init() {
//glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
- skinned_buffer_size = GLOBAL_DEF("rasterizer/skinned_buffer_size",DEFAULT_SKINNED_BUFFER_SIZE);
- skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size );
-
glGenTextures(1, &white_tex);
unsigned char whitetexdata[8*8*3];
for(int i=0;i<8*8*3;i++) {
@@ -8327,7 +10769,7 @@ void RasterizerGLES2::init() {
#ifdef GLEW_ENABLED
- read_depth_supported=true;
+
pvr_supported=false;
etc_supported=false;
use_depth24 =true;
@@ -8339,6 +10781,19 @@ void RasterizerGLES2::init() {
use_texture_instancing=false;
use_attribute_instancing=true;
full_float_fb_supported=true;
+ srgb_supported=true;
+ latc_supported=true;
+ s3tc_srgb_supported=true;
+ use_anisotropic_filter=true;
+ float_linear_supported=true;
+ float_supported=true;
+
+ read_depth_supported=_test_depth_shadow_buffer();
+ use_rgba_shadowmaps=!read_depth_supported;
+ //print_line("read depth support? "+itos(read_depth_supported));
+
+ glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&anisotropic_level);
+ anisotropic_level=MIN(anisotropic_level,float(GLOBAL_DEF("rasterizer/anisotropic_filter_level",4.0)));
#ifdef OSX_ENABLED
use_rgba_shadowmaps=true;
use_fp16_fb=false;
@@ -8358,17 +10813,33 @@ void RasterizerGLES2::init() {
use_rgba_shadowmaps=true; //no other way, go back to rgba
}
pvr_supported=extensions.has("GL_IMG_texture_compression_pvrtc");
+ pvr_srgb_supported=extensions.has("GL_EXT_pvrtc_sRGB");
etc_supported=extensions.has("GL_OES_compressed_ETC1_RGB8_texture");
use_depth24 = extensions.has("GL_OES_depth24");
s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc");
use_half_float = extensions.has("GL_OES_vertex_half_float");
atitc_supported=extensions.has("GL_AMD_compressed_ATC_texture");
+
+ srgb_supported=extensions.has("GL_EXT_sRGB");
+ s3tc_srgb_supported = s3tc_supported && extensions.has("GL_EXT_texture_compression_s3tc");
+ latc_supported = extensions.has("GL_EXT_texture_compression_latc");
+ anisotropic_level=1.0;
+ use_anisotropic_filter=extensions.has("GL_EXT_texture_filter_anisotropic");
+ if (use_anisotropic_filter) {
+ glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&anisotropic_level);
+ anisotropic_level=MIN(anisotropic_level,float(GLOBAL_DEF("rasterizer/anisotropic_filter_level",4.0)));
+ }
+
+
print_line("S3TC: "+itos(s3tc_supported)+" ATITC: "+itos(atitc_supported));
GLint vtf;
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,&vtf);
- use_hw_skeleton_xform=vtf>0 && extensions.has("GL_OES_texture_float");
+ float_supported = extensions.has("GL_OES_texture_float");
+ use_hw_skeleton_xform=vtf>0 && float_supported;
+ float_linear_supported = extensions.has("GL_OES_texture_float_linear");
+
//if (extensions.has("GL_QCOM_tiled_rendering"))
// use_hw_skeleton_xform=false;
GLint mva;
@@ -8406,9 +10877,12 @@ void RasterizerGLES2::init() {
-
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max_texture_size);
//read_depth_supported=false;
+ canvas_shadow_blur = canvas_light_shadow_buffer_create(max_texture_size);
+
{
//shadowmaps
OS::VideoMode vm=OS::get_singleton()->get_video_mode();
@@ -8430,6 +10904,7 @@ void RasterizerGLES2::init() {
//material_shader
material_shader.set_conditional(MaterialShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps);
+ canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps);
}
@@ -8438,8 +10913,9 @@ void RasterizerGLES2::init() {
shadow_mat_ptr = material_owner.get(shadow_material);
overdraw_material = create_overdraw_debug_material();
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;
@@ -8448,22 +10924,38 @@ void RasterizerGLES2::init() {
current_rt=NULL;
current_vd=NULL;
current_debug=VS::SCENARIO_DEBUG_DISABLED;
+ camera_ortho=false;
glGenBuffers(1,&gui_quad_buffer);
glBindBuffer(GL_ARRAY_BUFFER,gui_quad_buffer);
- glBufferData(GL_ARRAY_BUFFER,128,NULL,GL_DYNAMIC_DRAW);
+#ifdef GLES_NO_CLIENT_ARRAYS //WebGL specific implementation.
+ glBufferData(GL_ARRAY_BUFFER, 8 * MAX_POLYGON_VERTICES,NULL,GL_DYNAMIC_DRAW);
+#else
+ glBufferData(GL_ARRAY_BUFFER,128,NULL,GL_DYNAMIC_DRAW);
+#endif
glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+#ifdef GLES_NO_CLIENT_ARRAYS //webgl indices buffer
+ glGenBuffers(1, &indices_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, 16*1024, NULL, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);// unbind
+#endif
+
+ shader_time_rollback = GLOBAL_DEF("rasterizer/shader_time_rollback",300);
+ using_canvas_bg=false;
_update_framebuffer();
DEBUG_TEST_ERROR("Initializing");
}
void RasterizerGLES2::finish() {
-
- memdelete_arr(skinned_buffer);
+ free(default_material);
+ free(shadow_material);
+ free(canvas_shadow_blur);
+ free( overdraw_material );
}
int RasterizerGLES2::get_render_info(VS::RenderInfo p_info) {
@@ -8738,8 +11230,39 @@ void RasterizerGLES2::set_use_framebuffers(bool p_use) {
use_framebuffers=p_use;
}
+RasterizerGLES2* RasterizerGLES2::get_singleton() {
+
+ return _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;
+
+ RenderList::max_elements=GLOBAL_DEF("rasterizer/max_render_elements",(int)RenderList::DEFAULT_MAX_ELEMENTS);
+ if (RenderList::max_elements>64000)
+ RenderList::max_elements=64000;
+ if (RenderList::max_elements<1024)
+ RenderList::max_elements=1024;
+
+ opaque_render_list.init();
+ alpha_render_list.init();
+
+ skinned_buffer_size = GLOBAL_DEF("rasterizer/skeleton_buffer_size_kb",DEFAULT_SKINNED_BUFFER_SIZE);
+ if (skinned_buffer_size<256)
+ skinned_buffer_size=256;
+ if (skinned_buffer_size>16384)
+ skinned_buffer_size=16384;
+ skinned_buffer_size*=1024;
+ skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size );
+
keep_copies=p_keep_ram_copy;
use_reload_hooks=p_use_reload_hooks;
pack_arrays=p_compress_arrays;
@@ -8751,6 +11274,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++) {
@@ -8779,10 +11303,18 @@ 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 83365f2feb..e203a56c24 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,6 +31,8 @@
#include "servers/visual/rasterizer.h"
+#define MAX_POLYGON_VERTICES 4096 //used for WebGL canvas_draw_polygon call.
+
#ifdef GLES2_ENABLED
#include "image.h"
@@ -51,6 +53,7 @@
#include "drivers/gles2/shaders/material.glsl.h"
#include "drivers/gles2/shaders/canvas.glsl.h"
+#include "drivers/gles2/shaders/canvas_shadow.glsl.h"
#include "drivers/gles2/shaders/blur.glsl.h"
#include "drivers/gles2/shaders/copy.glsl.h"
#include "drivers/gles2/shader_compiler_gles2.h"
@@ -65,7 +68,7 @@ class RasterizerGLES2 : public Rasterizer {
MAX_SCENE_LIGHTS=2048,
LIGHT_SPOT_BIT=0x80,
- DEFAULT_SKINNED_BUFFER_SIZE = 2048 * 1024, // 10k vertices
+ DEFAULT_SKINNED_BUFFER_SIZE = 2048, // 10k vertices
MAX_HW_LIGHTS = 1,
};
@@ -73,7 +76,10 @@ class RasterizerGLES2 : public Rasterizer {
uint8_t *skinned_buffer;
int skinned_buffer_size;
bool pvr_supported;
+ bool pvr_srgb_supported;
bool s3tc_supported;
+ bool s3tc_srgb_supported;
+ bool latc_supported;
bool etc_supported;
bool atitc_supported;
bool npo2_textures_available;
@@ -82,6 +88,11 @@ class RasterizerGLES2 : public Rasterizer {
bool full_float_fb_supported;
bool use_shadow_mapping;
bool use_fp16_fb;
+ bool srgb_supported;
+ bool float_supported;
+ bool float_linear_supported;
+ bool use_16bits_fbo;
+
ShadowFilterTechnique shadow_filter;
bool use_shadow_esm;
@@ -91,18 +102,21 @@ class RasterizerGLES2 : public Rasterizer {
bool use_texture_instancing;
bool use_attribute_instancing;
bool use_rgba_shadowmaps;
+ bool use_anisotropic_filter;
+ 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,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed);
+ 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;
@@ -110,6 +124,7 @@ class RasterizerGLES2 : public Rasterizer {
GLenum target;
GLenum gl_format_cache;
+ GLenum gl_internal_format_cache;
int gl_components_cache;
int data_size; //original data size, useful for retrieving back
bool has_alpha;
@@ -180,10 +195,14 @@ class RasterizerGLES2 : public Rasterizer {
bool has_screen_uv;
bool writes_vertex;
bool uses_discard;
+ bool uses_time;
+ bool uses_normal;
+ bool uses_texpixel_size;
Map<StringName,ShaderLanguage::Uniform> uniforms;
StringName first_texture;
+ Map<StringName,RID> default_textures;
SelfList<Shader> dirty_list;
@@ -201,6 +220,8 @@ class RasterizerGLES2 : public Rasterizer {
has_screen_uv=false;
writes_vertex=false;
uses_discard=false;
+ uses_time=false;
+ uses_normal=false;
}
@@ -228,8 +249,9 @@ class RasterizerGLES2 : public Rasterizer {
struct UniformData {
+ bool inuse;
bool istexture;
- Variant value;
+ Variant value;
int index;
};
@@ -284,7 +306,7 @@ class RasterizerGLES2 : public Rasterizer {
virtual ~GeometryOwner() {}
};
- class Mesh;
+ struct Mesh;
struct Surface : public Geometry {
@@ -310,6 +332,8 @@ class RasterizerGLES2 : public Rasterizer {
// no support for the above, array in localmem.
uint8_t *array_local;
uint8_t *index_array_local;
+ Vector<AABB> skeleton_bone_aabb;
+ Vector<bool> skeleton_bone_used;
//bool packed;
@@ -545,6 +569,42 @@ class RasterizerGLES2 : public Rasterizer {
r_dst[1]+=((mtx[0][1]*p_src[0] ) + ( mtx[1][1]*p_src[1] ) + ( mtx[2][1]*p_src[2] ) )*p_weight;
r_dst[2]+=((mtx[0][2]*p_src[0] ) + ( mtx[1][2]*p_src[1] ) + ( mtx[2][2]*p_src[2] ) )*p_weight;
}
+
+ _ALWAYS_INLINE_ AABB transform_aabb(const AABB& p_aabb) const {
+
+ float vertices[8][3]={
+ {p_aabb.pos.x+p_aabb.size.x, p_aabb.pos.y+p_aabb.size.y, p_aabb.pos.z+p_aabb.size.z},
+ {p_aabb.pos.x+p_aabb.size.x, p_aabb.pos.y+p_aabb.size.y, p_aabb.pos.z},
+ {p_aabb.pos.x+p_aabb.size.x, p_aabb.pos.y, p_aabb.pos.z+p_aabb.size.z},
+ {p_aabb.pos.x+p_aabb.size.x, p_aabb.pos.y, p_aabb.pos.z},
+ {p_aabb.pos.x, p_aabb.pos.y+p_aabb.size.y, p_aabb.pos.z+p_aabb.size.z},
+ {p_aabb.pos.x, p_aabb.pos.y+p_aabb.size.y, p_aabb.pos.z},
+ {p_aabb.pos.x, p_aabb.pos.y, p_aabb.pos.z+p_aabb.size.z},
+ {p_aabb.pos.x, p_aabb.pos.y, p_aabb.pos.z}
+ };
+
+
+ AABB ret;
+
+
+
+ for (int i=0;i<8;i++) {
+
+ Vector3 xv(
+
+ ((mtx[0][0]*vertices[i][0] ) + ( mtx[1][0]*vertices[i][1] ) + ( mtx[2][0]*vertices[i][2] ) + mtx[3][0] ),
+ ((mtx[0][1]*vertices[i][0] ) + ( mtx[1][1]*vertices[i][1] ) + ( mtx[2][1]*vertices[i][2] ) + mtx[3][1] ),
+ ((mtx[0][2]*vertices[i][0] ) + ( mtx[1][2]*vertices[i][1] ) + ( mtx[2][2]*vertices[i][2] ) + mtx[3][2] )
+ );
+
+ if (i==0)
+ ret.pos=xv;
+ else
+ ret.expand_to(xv);
+ }
+
+ return ret;
+ }
};
GLuint tex_id;
@@ -561,7 +621,7 @@ class RasterizerGLES2 : public Rasterizer {
mutable SelfList<Skeleton>::List _skeleton_dirty_list;
- template<bool USE_NORMAL, bool USE_TANGENT>
+ template<bool USE_NORMAL, bool USE_TANGENT,bool INPLACE>
void _skeleton_xform(const uint8_t * p_src_array, int p_src_stride, uint8_t * p_dst_array, int p_dst_stride, int p_elements,const uint8_t *p_src_bones, const uint8_t *p_src_weights, const Skeleton::Bone *p_bone_xforms);
struct Light {
@@ -621,6 +681,7 @@ class RasterizerGLES2 : public Rasterizer {
bg_param[VS::ENV_BG_PARAM_ENERGY]=1.0;
bg_param[VS::ENV_BG_PARAM_SCALE]=1.0;
bg_param[VS::ENV_BG_PARAM_GLOW]=0.0;
+ bg_param[VS::ENV_BG_PARAM_CANVAS_MAX_LAYER]=0;
for(int i=0;i<VS::ENV_FX_MAX;i++)
fx_enabled[i]=false;
@@ -657,6 +718,18 @@ class RasterizerGLES2 : public Rasterizer {
mutable RID_Owner<Environment> environment_owner;
+
+ struct SampledLight {
+
+ int w,h;
+ GLuint texture;
+ float multiplier;
+ bool is_float;
+ };
+
+ mutable RID_Owner<SampledLight> sampled_light_owner;
+
+
struct ViewportData {
//1x1 fbo+texture for storing previous HDR value
@@ -749,25 +822,31 @@ class RasterizerGLES2 : public Rasterizer {
bool current_depth_mask;
VS::MaterialBlendMode current_blend_mode;
bool use_fast_texture_filter;
+ int max_texture_size;
bool fragment_lighting;
RID shadow_material;
Material *shadow_mat_ptr;
+ int max_texture_units;
GLuint base_framebuffer;
GLuint gui_quad_buffer;
+ GLuint indices_buffer;
+
struct RenderList {
enum {
- MAX_ELEMENTS=4096,
+ DEFAULT_MAX_ELEMENTS=4096,
MAX_LIGHTS=4,
SORT_FLAG_SKELETON=1,
SORT_FLAG_INSTANCING=2,
};
+ static int max_elements;
+
struct Element {
@@ -800,8 +879,8 @@ class RasterizerGLES2 : public Rasterizer {
};
- Element _elements[MAX_ELEMENTS];
- Element *elements[MAX_ELEMENTS];
+ Element *_elements;
+ Element **elements;
int element_count;
void clear() {
@@ -838,7 +917,7 @@ class RasterizerGLES2 : public Rasterizer {
}
} else {
- return B->material->shader_cache < B->material->shader_cache;
+ return A->material->shader_cache < B->material->shader_cache;
}
}
};
@@ -936,17 +1015,28 @@ class RasterizerGLES2 : public Rasterizer {
}
_FORCE_INLINE_ Element* add_element() {
- if (element_count>MAX_ELEMENTS)
+ if (element_count>=max_elements)
return NULL;
elements[element_count]=&_elements[element_count];
return elements[element_count++];
}
- RenderList() {
+ void init() {
element_count = 0;
- for (int i=0;i<MAX_ELEMENTS;i++)
+ elements=memnew_arr(Element*,max_elements);
+ _elements=memnew_arr(Element,max_elements);
+ for (int i=0;i<max_elements;i++)
elements[i]=&_elements[i]; // assign elements
+
+ }
+
+ RenderList() {
+
+ }
+ ~RenderList() {
+ memdelete_arr(elements);
+ memdelete_arr(_elements);
}
};
@@ -964,6 +1054,7 @@ class RasterizerGLES2 : public Rasterizer {
float camera_z_near;
float camera_z_far;
Size2 camera_vp_size;
+ bool camera_ortho;
Set<String> extensions;
bool texscreen_copied;
bool texscreen_used;
@@ -1024,6 +1115,8 @@ class RasterizerGLES2 : public Rasterizer {
void _debug_draw_shadows_type(Vector<ShadowBuffer>& p_shadows,Point2& ofs);
void _debug_shadows();
void _debug_luminances();
+ void _debug_samplers();
+
/***********/
@@ -1043,6 +1136,7 @@ class RasterizerGLES2 : public Rasterizer {
bool active;
int blur_size;
+
struct Blur {
GLuint fbo;
@@ -1075,6 +1169,7 @@ class RasterizerGLES2 : public Rasterizer {
void _process_glow_and_bloom();
//void _update_blur_buffer();
+
/*********/
/* FRAME */
/*********/
@@ -1093,6 +1188,45 @@ class RasterizerGLES2 : public Rasterizer {
} _rinfo;
+ /*******************/
+ /* CANVAS OCCLUDER */
+ /*******************/
+
+
+ struct CanvasOccluder {
+
+ GLuint vertex_id; // 0 means, unconfigured
+ GLuint index_id; // 0 means, unconfigured
+ DVector<Vector2> lines;
+ int len;
+ };
+
+ RID_Owner<CanvasOccluder> canvas_occluder_owner;
+
+ /***********************/
+ /* CANVAS LIGHT SHADOW */
+ /***********************/
+
+
+ struct CanvasLightShadow {
+
+ int size;
+ int height;
+ GLuint fbo;
+ GLuint rbo;
+ GLuint depth;
+ GLuint rgba; //for older devices
+
+ GLuint blur;
+
+ };
+
+ RID_Owner<CanvasLightShadow> canvas_light_shadow_owner;
+
+ RID canvas_shadow_blur;
+
+ /* ETC */
+
RenderTarget *current_rt;
bool current_rt_transparent;
bool current_rt_vflip;
@@ -1102,6 +1236,17 @@ class RasterizerGLES2 : public Rasterizer {
GLuint white_tex;
RID canvas_tex;
float canvas_opacity;
+ Color canvas_modulate;
+ bool canvas_use_modulate;
+ bool uses_texpixel_size;
+ bool rebind_texpixel_size;
+ Transform canvas_transform;
+ CanvasItemMaterial *canvas_last_material;
+ bool canvas_texscreen_used;
+ Vector2 normal_flip;
+ _FORCE_INLINE_ void _canvas_normal_set_flip(const Vector2& p_flip);
+
+
_FORCE_INLINE_ Texture* _bind_canvas_texture(const RID& p_texture);
VS::MaterialBlendMode canvas_blend_mode;
@@ -1120,6 +1265,7 @@ class RasterizerGLES2 : public Rasterizer {
void _process_hdr();
void _draw_tex_bg();
+ bool using_canvas_bg;
Size2 window_size;
VS::ViewportRect viewport;
double last_time;
@@ -1130,22 +1276,26 @@ class RasterizerGLES2 : public Rasterizer {
Environment *current_env;
VS::ScenarioDebugMode current_debug;
RID overdraw_material;
+ float shader_time_rollback;
+
mutable MaterialShaderGLES2 material_shader;
- CanvasShaderGLES2 canvas_shader;
+ mutable CanvasShaderGLES2 canvas_shader;
BlurShaderGLES2 blur_shader;
CopyShaderGLES2 copy_shader;
+ mutable CanvasShadowShaderGLES2 canvas_shadow_shader;
mutable ShaderCompilerGLES2 shader_precompiler;
void _draw_primitive(int p_points, const Vector3 *p_vertices, const Vector3 *p_normals, const Color* p_colors, const Vector3 *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1);
_FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs);
_FORCE_INLINE_ void _draw_gui_primitive2(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs, const Vector2 *p_uvs2);
- void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false );
+ void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false, bool p_transpose=false );
void _draw_quad(const Rect2& p_rect);
void _copy_screen_quad();
void _copy_to_texscreen();
+ bool _test_depth_shadow_buffer();
Vector3 chunk_vertex;
Vector3 chunk_normal;
@@ -1156,6 +1306,10 @@ class RasterizerGLES2 : public Rasterizer {
GLuint tc0_id_cache;
GLuint tc0_idx;
+ template<bool use_normalmap>
+ _FORCE_INLINE_ void _canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip);
+ _FORCE_INLINE_ void _canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* p_shader);
+ _FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* p_shader);
public:
/* TEXTURE API */
@@ -1173,6 +1327,12 @@ 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 */
virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_MATERIAL);
@@ -1188,6 +1348,10 @@ public:
virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture);
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const;
+
+ virtual Variant shader_get_default_param(RID p_shader, const StringName& p_name);
/* COMMON MATERIAL API */
@@ -1238,7 +1402,7 @@ public:
virtual void mesh_remove_surface(RID p_mesh,int p_index);
virtual int mesh_get_surface_count(RID p_mesh) const;
- virtual AABB mesh_get_aabb(RID p_mesh) const;
+ virtual AABB mesh_get_aabb(RID p_mesh,RID p_skeleton=RID()) const;
virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb);
virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
@@ -1432,7 +1596,7 @@ public:
virtual void begin_shadow_map( RID p_light_instance, int p_shadow_pass );
- virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection);
+ virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection,bool p_ortho_hint);
virtual void add_light( RID p_light_instance ); ///< all "add_light" calls happen before add_geometry calls
@@ -1450,6 +1614,8 @@ public:
/* CANVAS API */
+ virtual void begin_canvas_bg();
+
virtual void canvas_begin();
virtual void canvas_disable_blending();
@@ -1465,6 +1631,19 @@ public:
virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor);
virtual void canvas_set_transform(const Matrix32& p_transform);
+ virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light);
+ virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow);
+
+ /* CANVAS LIGHT SHADOW */
+
+ //buffer
+ virtual RID canvas_light_shadow_buffer_create(int p_width);
+ virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache);
+
+ //occluder
+ virtual RID canvas_light_occluder_create();
+ virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines);
+
/* ENVIRONMENT */
@@ -1482,6 +1661,9 @@ public:
virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value);
virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const;
+ /* SAMPLED LIGHT */
+ virtual RID sampled_light_dp_create(int p_width,int p_height);
+ virtual void sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier);
/*MISC*/
@@ -1499,6 +1681,8 @@ public:
virtual bool is_environment(const RID& p_rid) const;
virtual bool is_shader(const RID& p_rid) const;
+ virtual bool is_canvas_light_occluder(const RID& p_rid) const;
+
virtual void free(const RID& p_rid);
virtual void init();
@@ -1506,7 +1690,7 @@ public:
virtual int get_render_info(VS::RenderInfo p_info);
- void set_base_framebuffer(GLuint p_id);
+ void set_base_framebuffer(GLuint p_id, Vector2 p_size = Vector2(0, 0));
virtual void flush_frame(); //not necesary in most cases
void set_extensions(const char *p_strings);
@@ -1517,7 +1701,12 @@ 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 eec9431f36..a8d478c6e0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/gles2/rasterizer_instance_gles2.h b/drivers/gles2/rasterizer_instance_gles2.h
index 97dcb7bc73..f5ac5f1fe2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index dfab3ea3d1..f981529ee3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -61,6 +61,7 @@ static String _typestr(SL::DataType p_type) {
case SL::TYPE_VEC2: return "vec2";
case SL::TYPE_VEC3: return "vec3";
case SL::TYPE_VEC4: return "vec4";
+ case SL::TYPE_MAT2: return "mat2";
case SL::TYPE_MAT3: return "mat3";
case SL::TYPE_MAT4: return "mat4";
case SL::TYPE_TEXTURE: return "sampler2D";
@@ -131,31 +132,63 @@ 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;
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;
} break;
case SL::Node::TYPE_VARIABLE: {
SL::VariableNode *vnode=(SL::VariableNode*)p_node;
+
if (type==ShaderLanguage::SHADER_MATERIAL_VERTEX) {
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;
+ }
+ if (vnode->name==vname_uv_interp) {
+ flags->use_uv_interp=true;
+ }
+ if (vnode->name==vname_uv2_interp) {
+ flags->use_uv2_interp=true;
+ }
+ if (vnode->name==vname_var1_interp) {
+ flags->use_var1_interp=true;
+ }
+ if (vnode->name==vname_var2_interp) {
+ flags->use_var2_interp=true;
+ }
+ if (vnode->name==vname_tangent_interp || vnode->name==vname_binormal_interp) {
+ flags->use_tangent_interp=true;
+ }
+
+
}
+
+
+
if (type==ShaderLanguage::SHADER_MATERIAL_FRAGMENT) {
if (vnode->name==vname_discard) {
uses_discard=true;
}
+ if (vnode->name==vname_normalmap) {
+ uses_normalmap=true;
+ }
if (vnode->name==vname_screen_uv) {
uses_screen_uv=true;
}
@@ -188,8 +221,71 @@ 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) {
+
+ if (vnode->name==vname_var1_interp) {
+ flags->use_var1_interp=true;
+ }
+ if (vnode->name==vname_var2_interp) {
+ flags->use_var2_interp=true;
+ }
+ if (vnode->name==vname_world_vec) {
+ uses_worldvec=true;
+ }
+
+ }
+
+
+ if (type==ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT) {
+
+
+ if (vnode->name==vname_texpixel_size) {
+ uses_texpixel_size=true;
+ }
+ if (vnode->name==vname_normal) {
+ uses_normal=true;
+ }
+ if (vnode->name==vname_normalmap || vnode->name==vname_normalmap_depth) {
+ uses_normalmap=true;
+ uses_normal=true;
+ }
+
+ if (vnode->name==vname_screen_uv) {
+ uses_screen_uv=true;
+ }
+
+ if (vnode->name==vname_var1_interp) {
+ flags->use_var1_interp=true;
+ }
+ if (vnode->name==vname_var2_interp) {
+ flags->use_var2_interp=true;
+ }
+ }
+
+ if (type==ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT) {
+
+ if (vnode->name==vname_light) {
+ uses_light=true;
+ }
+
+ if (vnode->name==vname_normal) {
+ uses_normal=true;
+ }
+
+ if (vnode->name==vname_shadow) {
+ uses_shadow_color=true;
+ }
+
}
+ if (vnode->name==vname_time) {
+ uses_time=true;
+ }
code=replace_string(vnode->name);
} break;
@@ -203,6 +299,7 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
case SL::TYPE_VEC2: { Vector2 v = cnode->value; code="vec2("+_mknum(v.x)+", "+_mknum(v.y)+")"; } break;
case SL::TYPE_VEC3: { Vector3 v = cnode->value; code="vec3("+_mknum(v.x)+", "+_mknum(v.y)+", "+_mknum(v.z)+")"; } break;
case SL::TYPE_VEC4: { Plane v = cnode->value; code="vec4("+_mknum(v.normal.x)+", "+_mknum(v.normal.y)+", "+_mknum(v.normal.z)+", "+_mknum(v.d)+")"; } break;
+ case SL::TYPE_MAT2: { Matrix32 x = cnode->value; code="mat2( vec2("+_mknum(x[0][0])+", "+_mknum(x[0][1])+"), vec2("+_mknum(x[1][0])+", "+_mknum(x[1][1])+"))"; } break;
case SL::TYPE_MAT3: { Matrix3 x = cnode->value; code="mat3( vec3("+_mknum(x.get_axis(0).x)+", "+_mknum(x.get_axis(0).y)+", "+_mknum(x.get_axis(0).z)+"), vec3("+_mknum(x.get_axis(1).x)+", "+_mknum(x.get_axis(1).y)+", "+_mknum(x.get_axis(1).z)+"), vec3("+_mknum(x.get_axis(2).x)+", "+_mknum(x.get_axis(2).y)+", "+_mknum(x.get_axis(2).z)+"))"; } break;
case SL::TYPE_MAT4: { Transform x = cnode->value; code="mat4( vec4("+_mknum(x.basis.get_axis(0).x)+", "+_mknum(x.basis.get_axis(0).y)+", "+_mknum(x.basis.get_axis(0).z)+",0.0), vec4("+_mknum(x.basis.get_axis(1).x)+", "+_mknum(x.basis.get_axis(1).y)+", "+_mknum(x.basis.get_axis(1).z)+",0.0), vec4("+_mknum(x.basis.get_axis(2).x)+", "+_mknum(x.basis.get_axis(2).y)+", "+_mknum(x.basis.get_axis(2).z)+",0.0), vec4("+_mknum(x.origin.x)+", "+_mknum(x.origin.y)+", "+_mknum(x.origin.z)+",1.0))"; } break;
default: code="<error: "+Variant::get_type_name(cnode->value.get_type())+" ("+itos(cnode->datatype)+">";
@@ -234,13 +331,13 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
String mul_l=dump_node_code(onode->arguments[0],p_level,true);
String mul_r=dump_node_code(onode->arguments[1],p_level);
- code=mul_l+"=(vec4("+mul_l+",1.0,1.0)*("+mul_r+")).xy";
+ code=mul_l+"=(vec4("+mul_l+",0.0,1.0)*("+mul_r+")).xy";
break;
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT4 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) {
String mul_l=dump_node_code(onode->arguments[0],p_level,true);
String mul_r=dump_node_code(onode->arguments[1],p_level);
- code=mul_l+"=(("+mul_l+")*vec4("+mul_r+",1.0,1.0)).xy";
+ code=mul_l+"=(("+mul_l+")*vec4("+mul_r+",0.0,1.0)).xy";
break;
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_VEC2 && onode->arguments[1]->get_datatype()==SL::TYPE_MAT3) {
String mul_l=dump_node_code(onode->arguments[0],p_level,true);
@@ -270,11 +367,11 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
break;
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT4 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) {
- code="("+dump_node_code(onode->arguments[0],p_level)+"*vec4("+dump_node_code(onode->arguments[1],p_level)+",1.0,1.0)).xyz";
+ code="("+dump_node_code(onode->arguments[0],p_level)+"*vec4("+dump_node_code(onode->arguments[1],p_level)+",0.0,1.0)).xy";
break;
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_VEC2 && onode->arguments[1]->get_datatype()==SL::TYPE_MAT4) {
- code="(vec4("+dump_node_code(onode->arguments[0],p_level)+",1.0,1.0)*"+dump_node_code(onode->arguments[1],p_level)+").xyz";
+ code="(vec4("+dump_node_code(onode->arguments[0],p_level)+",0.0,1.0)*"+dump_node_code(onode->arguments[1],p_level)+").xy";
break;
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT3 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) {
@@ -331,7 +428,7 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
} else if (callfunc=="texscreen") {
//create the call to sample the screen, and clamp it
uses_texscreen=true;
- code="(texture2D( texscreen_tex, min(("+dump_node_code(onode->arguments[1],p_level)+").xy*texscreen_screen_mult,texscreen_screen_mult))).rgb";
+ code="(texture2D( texscreen_tex, clamp(("+dump_node_code(onode->arguments[1],p_level)+").xy*texscreen_screen_mult,texscreen_screen_clamp.xy,texscreen_screen_clamp.zw))).rgb";
//code="(texture2D( screen_texture, ("+dump_node_code(onode->arguments[1],p_level)+").xy).rgb";
break;
} else if (callfunc=="texpos") {
@@ -341,6 +438,42 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
// code="get_texpos(gl_ProjectionMatrixInverse * texture2D( depth_texture, clamp(("+dump_node_code(onode->arguments[1],p_level)+").xy,vec2(0.0),vec2(1.0))*gl_LightSource[5].specular.zw+gl_LightSource[5].specular.xy)";
//code="(texture2D( screen_texture, ("+dump_node_code(onode->arguments[1],p_level)+").xy).rgb";
break;
+ } else if (custom_h && callfunc=="cosh_custom") {
+
+ if (!cosh_used) {
+ global_code= "float cosh_custom(float val)\n"\
+ "{\n"\
+ " float tmp = exp(val);\n"\
+ " float cosH = (tmp + 1.0 / tmp) / 2.0;\n"\
+ " return cosH;\n"\
+ "}\n"+global_code;
+ cosh_used=true;
+ }
+ code="cosh_custom("+dump_node_code(onode->arguments[1],p_level)+"";
+ } else if (custom_h && callfunc=="sinh_custom") {
+
+ if (!sinh_used) {
+ global_code= "float sinh_custom(float val)\n"\
+ "{\n"\
+ " float tmp = exp(val);\n"\
+ " float sinH = (tmp - 1.0 / tmp) / 2.0;\n"\
+ " return sinH;\n"\
+ "}\n"+global_code;
+ sinh_used=true;
+ }
+ code="sinh_custom("+dump_node_code(onode->arguments[1],p_level)+"";
+ } else if (custom_h && callfunc=="tanh_custom") {
+
+ if (!tanh_used) {
+ global_code= "float tanh_custom(float val)\n"\
+ "{\n"\
+ " float tmp = exp(val);\n"\
+ " float tanH = (tmp - 1.0 / tmp) / (tmp + 1.0 / tmp);\n"\
+ " return tanH;\n"\
+ "}\n"+global_code;
+ tanh_used=true;
+ }
+ code="tanh_custom("+dump_node_code(onode->arguments[1],p_level)+"";
} else {
@@ -363,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) {
@@ -395,6 +528,11 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
m="[2]";
else if (mnode->name=="w")
m="[3]";
+ } else if (mnode->basetype==SL::TYPE_MAT2) {
+ if (mnode->name=="x")
+ m="[0]";
+ else if (mnode->name=="y")
+ m="[1]";
} else if (mnode->basetype==SL::TYPE_MAT3) {
if (mnode->name=="x")
@@ -429,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) {
@@ -462,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;
}
@@ -474,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);
@@ -522,7 +660,14 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
uses_discard=false;
uses_screen_uv=false;
uses_light=false;
+ uses_time=false;
+ uses_normalmap=false;
+ uses_normal=false;
+ 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;
r_flags.use_color_interp=false;
@@ -531,6 +676,11 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
r_flags.use_tangent_interp=false;
r_flags.use_var1_interp=false;
r_flags.use_var2_interp=false;
+ r_flags.uses_normalmap=false;
+ r_flags.uses_normal=false;
+ sinh_used=false;
+ tanh_used=false;
+ cosh_used=false;
String error;
int errline,errcol;
@@ -548,9 +698,16 @@ 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;
+ r_flags.uses_time=uses_time;
+ r_flags.uses_normalmap=uses_normalmap;
+ r_flags.uses_normal=uses_normal;
+ r_flags.uses_texpixel_size=uses_texpixel_size;
+ r_flags.uses_worldvec=uses_worldvec;
+ r_flags.uses_shadow_color=uses_shadow_color;
r_code_line=code;
r_globals_line=global_code;
return OK;
@@ -558,11 +715,19 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
ShaderCompilerGLES2::ShaderCompilerGLES2() {
+#ifdef GLEW_ENABLED
+ //use custom functions because they are not supported in GLSL120
+ custom_h=true;
+#else
+ custom_h=false;
+#endif
+
replace_table["bool"]= "bool";
replace_table["float" ]= "float";
replace_table["vec2" ]= "vec2";
replace_table["vec3" ]= "vec3";
replace_table["vec4" ]= "vec4";
+ replace_table["mat2" ]= "mat2";
replace_table["mat3" ]= "mat3";
replace_table["mat4" ]= "mat4";
replace_table["texture" ]= "sampler2D";
@@ -575,9 +740,17 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
replace_table["acos" ]= "acos";
replace_table["atan" ]= "atan";
replace_table["atan2"]= "atan";
- replace_table["sinh" ]= "sinh";
- replace_table["cosh" ]= "cosh";
- replace_table["tanh" ]= "tanh";
+
+ if (custom_h) {
+ replace_table["sinh" ]= "sinh_custom";
+ replace_table["cosh" ]= "cosh_custom";
+ replace_table["tanh" ]= "tanh_custom";
+ } else {
+ replace_table["sinh" ]= "sinh";
+ replace_table["cosh" ]= "cosh";
+ replace_table["tanh" ]= "tanh";
+ }
+
replace_table["pow" ]= "pow";
replace_table["exp" ]= "exp";
replace_table["log" ]= "log";
@@ -586,7 +759,11 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
replace_table["sign"]= "sign";
replace_table["floor"]= "floor";
replace_table["trunc"]= "trunc";
+#ifdef GLEW_ENABLED
+ replace_table["round"]= "roundfix";
+#else
replace_table["round"]= "round";
+#endif
replace_table["ceil" ]= "ceil";
replace_table["fract"]= "fract";
replace_table["mod" ]= "mod";
@@ -602,6 +779,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
replace_table["cross" ]="cross";
replace_table["normalize"]= "normalize";
replace_table["reflect"]= "reflect";
+ replace_table["refract"]= "refract";
replace_table["tex"]= "tex";
replace_table["texa"]= "texa";
replace_table["tex2"]= "tex2";
@@ -609,70 +787,131 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
replace_table["texscreen"]= "texscreen";
replace_table["texpos"]= "texpos";
- 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]["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]["BINORMAL"]="binormal";
- 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[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";
+
+
//mode_replace_table[2]["SCREEN_POS"]="SCREEN_POS";
//mode_replace_table[2]["SCREEN_TEXEL_SIZE"]="SCREEN_TEXEL_SIZE";
@@ -691,6 +930,14 @@ 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";
+ vname_normalmap_depth="NORMALMAP_DEPTH";
+ vname_normal="NORMAL";
+ vname_texpixel_size="TEXTURE_PIXEL_SIZE";
+ vname_world_vec="WORLD_VERTEX";
+ vname_shadow="SHADOW";
}
diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h
index d63915a2b6..46ef2e035f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,7 +34,7 @@ class ShaderCompilerGLES2 {
class Uniform;
public:
- class Flags;
+ struct Flags;
private:
ShaderLanguage::ProgramNode *program_node;
@@ -48,8 +48,22 @@ private:
bool uses_texpos;
bool uses_alpha;
bool uses_discard;
+ bool uses_time;
bool uses_screen_uv;
+ bool uses_normalmap;
+ bool uses_normal;
+ bool uses_texpixel_size;
+ bool uses_worldvec;
bool vertex_code_writes_vertex;
+ bool vertex_code_writes_position;
+ bool uses_shadow_color;
+
+ bool sinh_used;
+ bool tanh_used;
+ bool cosh_used;
+
+ bool custom_h;
+
Flags *flags;
StringName vname_discard;
@@ -63,7 +77,15 @@ private:
StringName vname_var1_interp;
StringName vname_var2_interp;
StringName vname_vertex;
+ StringName vname_position;
StringName vname_light;
+ StringName vname_time;
+ StringName vname_normalmap;
+ StringName vname_normalmap_depth;
+ StringName vname_normal;
+ StringName vname_texpixel_size;
+ StringName vname_world_vec;
+ StringName vname_shadow;
Map<StringName,ShaderLanguage::Uniform> *uniforms;
@@ -75,7 +97,7 @@ private:
String replace_string(const StringName& p_string);
- Map<StringName,StringName> mode_replace_table[3];
+ Map<StringName,StringName> mode_replace_table[9];
Map<StringName,StringName> replace_table;
public:
@@ -85,7 +107,9 @@ public:
bool uses_alpha;
bool uses_texscreen;
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;
@@ -95,6 +119,11 @@ public:
bool use_var1_interp;
bool use_var2_interp;
bool uses_light;
+ bool uses_time;
+ bool uses_normal;
+ bool uses_texpixel_size;
+ bool uses_worldvec;
+ bool uses_shadow_color;
};
Error compile(const String& p_code, ShaderLanguage::ShaderType p_type, String& r_code_line, String& r_globals_line, Flags& r_flags, Map<StringName,ShaderLanguage::Uniform> *r_uniforms=NULL);
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index dc68ee489a..e94930fffb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -267,7 +267,9 @@ ShaderGLES2::Version* ShaderGLES2::get_current_version() {
/* SETUP CONDITIONALS */
Vector<const char*> strings;
- //strings.push_back("#version 120\n"); //ATI requieres this before anything
+#ifdef GLEW_ENABLED
+ strings.push_back("#version 120\n"); //ATI requieres this before anything
+#endif
int define_line_ofs=1;
for(int j=0;j<conditional_count;j++) {
diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h
index 9cd6142eb0..4604fd5501 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub
index c665cf9036..38177d725f 100644
--- a/drivers/gles2/shaders/SCsub
+++ b/drivers/gles2/shaders/SCsub
@@ -3,7 +3,6 @@ Import('env')
if env['BUILDERS'].has_key('GLSL120GLES'):
env.GLSL120GLES('material.glsl');
env.GLSL120GLES('canvas.glsl');
+ 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 f36741d586..259e82d704 100644
--- a/drivers/gles2/shaders/canvas.glsl
+++ b/drivers/gles2/shaders/canvas.glsl
@@ -18,20 +18,81 @@ attribute highp vec2 uv_attrib; // attrib:4
varying vec2 uv_interp;
varying vec4 color_interp;
+#if defined(USE_TIME)
+uniform float time;
+#endif
+
+
+#ifdef USE_LIGHTING
+
+uniform highp mat4 light_matrix;
+uniform highp mat4 light_local_matrix;
+uniform vec2 light_pos;
+varying vec4 light_uv_interp;
+
+#if defined(NORMAL_USED)
+varying vec4 local_rot;
+uniform vec2 normal_flip;
+#endif
+
+#ifdef USE_SHADOWS
+varying highp vec2 pos;
+#endif
+
+#endif
+
+#if defined(ENABLE_VAR1_INTERP)
+varying vec4 var1_interp;
+#endif
+
+#if defined(ENABLE_VAR2_INTERP)
+varying vec4 var2_interp;
+#endif
+
//uniform bool snap_pixels;
+VERTEX_SHADER_GLOBALS
+
void main() {
color_interp = color_attrib;
uv_interp = uv_attrib;
- highp vec4 outvec = vec4(vertex, 1.0);
- outvec = extra_matrix * outvec;
- outvec = modelview_matrix * outvec;
+ highp vec4 outvec = vec4(vertex, 1.0);
+{
+ vec2 src_vtx=outvec.xy;
+VERTEX_SHADER_CODE
+
+}
+#if !defined(USE_WORLD_VEC)
+ outvec = extra_matrix * outvec;
+ outvec = modelview_matrix * outvec;
+#endif
+
+
+
#ifdef USE_PIXEL_SNAP
- outvec.xy=floor(outvec.xy+0.5);
+ outvec.xy=floor(outvec.xy+0.5);
#endif
+
+
gl_Position = projection_matrix * outvec;
+
+#ifdef USE_LIGHTING
+
+ light_uv_interp.xy = (light_matrix * outvec).xy;
+ light_uv_interp.zw =(light_local_matrix * outvec).xy;
+#ifdef USE_SHADOWS
+ pos=outvec.xy;
+#endif
+
+#if defined(NORMAL_USED)
+ local_rot.xy=normalize( (modelview_matrix * ( extra_matrix * vec4(1.0,0.0,0.0,0.0) )).xy )*normal_flip.x;
+ local_rot.zw=normalize( (modelview_matrix * ( extra_matrix * vec4(0.0,1.0,0.0,0.0) )).xy )*normal_flip.y;
+#endif
+
+#endif
+
}
[fragment]
@@ -54,17 +115,283 @@ varying vec4 color_interp;
#endif
+#if defined(ENABLE_SCREEN_UV)
+
+uniform vec2 screen_uv_mult;
+
+#endif
+
+#if defined(ENABLE_TEXSCREEN)
+
+uniform vec2 texscreen_screen_mult;
+uniform vec4 texscreen_screen_clamp;
+uniform sampler2D texscreen_tex;
+
+#endif
+
+
+#if defined(ENABLE_VAR1_INTERP)
+varying vec4 var1_interp;
+#endif
+
+#if defined(ENABLE_VAR2_INTERP)
+varying vec4 var2_interp;
+#endif
+
+#if defined(USE_TIME)
+uniform float time;
+#endif
+
+#ifdef USE_MODULATE
+
+uniform vec4 modulate;
+
+#endif
+
+#ifdef USE_LIGHTING
+
+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;
+#endif
+
+#ifdef USE_SHADOWS
+
+uniform highp sampler2D shadow_texture;
+uniform float shadow_attenuation;
+
+uniform highp mat4 shadow_matrix;
+varying highp vec2 pos;
+uniform float shadowpixel_size;
+
+#ifdef SHADOW_ESM
+uniform float shadow_esm_multiplier;
+#endif
+
+#endif
+
+#endif
+
+#if defined(USE_TEXPIXEL_SIZE)
+uniform vec2 texpixel_size;
+#endif
+
+
+FRAGMENT_SHADER_GLOBALS
+
+
void main() {
vec4 color = color_interp;
-
+#if defined(NORMAL_USED)
+ vec3 normal = vec3(0.0,0.0,1.0);
+#endif
+
+#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);
+#else
color *= texture2D( texture, uv_interp );
+#endif
+
+
+#if defined(ENABLE_SCREEN_UV)
+ vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult;
+#endif
+
+
+{
+#if defined(USE_NORMALMAP)
+ vec3 normal_map=vec3(0.0,0.0,1.0);
+ float normal_depth=1.0;
+#endif
+
+FRAGMENT_SHADER_CODE
+
+#if defined(USE_NORMALMAP)
+ normal = mix(vec3(0.0,0.0,1.0), normal_map * vec3(2.0,-2.0,1.0) - vec3( 1.0, -1.0, 0.0 ), normal_depth );
+#endif
+
+}
#ifdef DEBUG_ENCODED_32
highp float enc32 = dot( color,highp vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) );
color = vec4(vec3(enc32),1.0);
#endif
+#ifdef USE_MODULATE
+
+ color*=modulate;
+#endif
+
+
+#ifdef USE_LIGHTING
+
+ vec2 light_vec = light_uv_interp.zw;; //for shadow and normal mapping
+
+#if defined(NORMAL_USED)
+ normal.xy = mat2(local_rot.xy,local_rot.zw) * normal.xy;
+#endif
+
+ float att=1.0;
+
+ vec2 light_uv = light_uv_interp.xy;
+ vec4 light = texture2D(light_texture,light_uv) * light_color;
+#if defined(USE_LIGHT_SHADOW_COLOR)
+ 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;
+LIGHT_SHADER_CODE
+ 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);
+#endif
+
+ color*=light;
+/*
+#ifdef USE_NORMAL
+ color.xy=local_rot.xy;//normal.xy;
+ color.zw=vec2(0.0,1.0);
+#endif
+*/
+
+//light shader code
+#endif
+
+
+#ifdef USE_SHADOWS
+
+ float angle_to_light = -atan(light_vec.x,light_vec.y);
+ float PI = 3.14159265358979323846264;
+ /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays
+ float ang*/
+
+ float su,sz;
+
+ float abs_angle = abs(angle_to_light);
+ vec2 point;
+ float sh;
+ if (abs_angle<45.0*PI/180.0) {
+ point = light_vec;
+ sh=0.0+(1.0/8.0);
+ } else if (abs_angle>135.0*PI/180.0) {
+ point = -light_vec;
+ sh = 0.5+(1.0/8.0);
+ } else if (angle_to_light>0.0) {
+
+ point = vec2(light_vec.y,-light_vec.x);
+ sh = 0.25+(1.0/8.0);
+ } else {
+
+ point = vec2(-light_vec.y,light_vec.x);
+ sh = 0.75+(1.0/8.0);
+
+ }
+
+
+ highp vec4 s = shadow_matrix * vec4(point,0.0,1.0);
+ s.xyz/=s.w;
+ su=s.x*0.5+0.5;
+ sz=s.z*0.5+0.5;
+
+ highp float shadow_attenuation=0.0;
+
+#ifdef USE_DEPTH_SHADOWS
+
+#define SHADOW_DEPTH(m_tex,m_uv) (texture2D((m_tex),(m_uv)).z)
+
+#else
+
+//#define SHADOW_DEPTH(m_tex,m_uv) dot(texture2D((m_tex),(m_uv)),highp vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) )
+#define SHADOW_DEPTH(m_tex,m_uv) dot(texture2D((m_tex),(m_uv)),vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) )
+
+#endif
+
+
+
+#ifdef SHADOW_PCF5
+
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size*2.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su-shadowpixel_size,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su-shadowpixel_size*2.0,sh))<sz?0.0:1.0;
+ shadow_attenuation/=5.0;
+
+#endif
+
+#ifdef SHADOW_PCF13
+
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size*2.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size*3.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size*4.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size*5.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size*6.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su-shadowpixel_size*2.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su-shadowpixel_size*3.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su-shadowpixel_size*4.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su-shadowpixel_size*5.0,sh))<sz?0.0:1.0;
+ shadow_attenuation += SHADOW_DEPTH(shadow_texture,vec2(su-shadowpixel_size*6.0,sh))<sz?0.0:1.0;
+ shadow_attenuation/=13.0;
+
+#endif
+
+#ifdef SHADOW_ESM
+
+
+ {
+ float unnormalized = su/shadowpixel_size;
+ float fractional = fract(unnormalized);
+ unnormalized = floor(unnormalized);
+ float zc = SHADOW_DEPTH(shadow_texture,vec2((unnormalized-0.5)*shadowpixel_size,sh));
+ float zn = SHADOW_DEPTH(shadow_texture,vec2((unnormalized+0.5)*shadowpixel_size,sh));
+ float z = mix(zc,zn,fractional);
+ shadow_attenuation=clamp(exp(shadow_esm_multiplier* ( z - sz )),0.0,1.0);
+ }
+
+#endif
+
+#if !defined(SHADOW_PCF5) && !defined(SHADOW_PCF13) && !defined(SHADOW_ESM)
+
+ shadow_attenuation = SHADOW_DEPTH(shadow_texture,vec2(su+shadowpixel_size,sh))<sz?0.0:1.0;
+
+#endif
+
+#if defined(USE_LIGHT_SHADOW_COLOR)
+ color=mix(shadow_color,color,shadow_attenuation);
+#else
+ //color*=shadow_attenuation;
+ color=mix(light_shadow_color,color,shadow_attenuation);
+#endif
+//use shadows
+#endif
+ }
+
+//use lighting
+#endif
// color.rgb*=color.a;
gl_FragColor = color;
diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl
new file mode 100644
index 0000000000..40cf321dce
--- /dev/null
+++ b/drivers/gles2/shaders/canvas_shadow.glsl
@@ -0,0 +1,62 @@
+[vertex]
+
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
+#endif
+
+uniform highp mat4 projection_matrix;
+uniform highp mat4 light_matrix;
+uniform highp mat4 world_matrix;
+
+attribute highp vec3 vertex; // attrib:0
+
+#ifndef USE_DEPTH_SHADOWS
+
+varying vec4 position_interp;
+
+#endif
+
+
+void main() {
+
+ gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0)));
+
+#ifndef USE_DEPTH_SHADOWS
+ position_interp = gl_Position;
+#endif
+
+}
+
+[fragment]
+
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
+#endif
+
+#ifndef USE_DEPTH_SHADOWS
+
+varying vec4 position_interp;
+
+#endif
+
+void main() {
+
+#ifdef USE_DEPTH_SHADOWS
+
+#else
+ highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias;
+ highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
+ comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
+ gl_FragColor = comp;
+#endif
+
+}
+
diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl
index d8fb03f3a3..ae7185a1d6 100644
--- a/drivers/gles2/shaders/copy.glsl
+++ b/drivers/gles2/shaders/copy.glsl
@@ -46,6 +46,15 @@ precision mediump int;
#endif
+
+float sRGB_gamma_correct(float c){
+ float a = 0.055;
+ if(c < 0.0031308)
+ return 12.92*c;
+ else
+ return (1.0+a)*pow(c, 1.0/2.4) - a;
+}
+
#define LUM_RANGE 4.0
@@ -407,15 +416,26 @@ void main() {
#ifdef USE_SRGB
+#if 0
+ //this was fast, but was commented out because it looked kind of shitty, might it be fixable?
+
{ //i have my doubts about how fast this is
+
color.rgb = min(color.rgb,vec3(1.0)); //clamp just in case
vec3 S1 = sqrt(color.rgb);
vec3 S2 = sqrt(S1);
vec3 S3 = sqrt(S2);
color.rgb = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.225411470 * color.rgb;
}
+#else
+
+ color.r=sRGB_gamma_correct(color.r);
+ color.g=sRGB_gamma_correct(color.g);
+ color.b=sRGB_gamma_correct(color.b);
+
#endif
+#endif
#ifdef USE_HDR_COPY
diff --git a/drivers/gles2/shaders/material.glsl b/drivers/gles2/shaders/material.glsl
index 17365ea264..ccd80bf2f0 100644
--- a/drivers/gles2/shaders/material.glsl
+++ b/drivers/gles2/shaders/material.glsl
@@ -4,10 +4,14 @@
#ifdef USE_GLES_OVER_GL
#define mediump
#define highp
+#define roundfix( m_val ) floor( (m_val) + 0.5 )
#else
precision mediump float;
precision mediump int;
#endif
+
+
+
/*
from VisualServer:
@@ -22,6 +26,26 @@ ARRAY_WEIGHTS=7,
ARRAY_INDEX=8,
*/
+//hack to use uv if no uv present so it works with lightmap
+#ifdef ENABLE_AMBIENT_LIGHTMAP
+
+#ifdef USE_LIGHTMAP_ON_UV2
+
+#ifndef ENABLE_UV2_INTERP
+#define ENABLE_UV2_INTERP
+#endif
+
+#else
+
+#ifndef ENABLE_UV_INTERP
+#define ENABLE_UV_INTERP
+#endif
+
+#endif
+
+#endif
+
+
/* INPUT ATTRIBS */
attribute highp vec4 vertex_attrib; // attrib:0
@@ -36,7 +60,7 @@ uniform float normal_mult;
#ifdef USE_SKELETON
attribute vec4 bone_indices; // attrib:6
attribute vec4 bone_weights; // attrib:7
-uniform highp sampler2D skeleton_matrices; // texunit:6
+uniform highp sampler2D skeleton_matrices;
uniform highp float skeltex_pixel_size;
#endif
@@ -52,7 +76,7 @@ attribute highp vec4 instance_row3; // attrib:11
#ifdef USE_TEXTURE_INSTANCING
attribute highp vec3 instance_uv; // attrib:6
-uniform highp sampler2D instance_matrices; // texunit:6
+uniform highp sampler2D instance_matrices;
#endif
@@ -238,6 +262,7 @@ void main() {
#if defined(ENABLE_TANGENT_INTERP)
vec3 tangent_in = tangent_attrib.xyz;
tangent_in*=normal_mult;
+ float binormalf = tangent_attrib.a;
#endif
#ifdef USE_SKELETON
@@ -267,12 +292,22 @@ void main() {
normal_interp = normalize((modelview * vec4(normal_in,0.0)).xyz);
#if defined(ENABLE_COLOR_INTERP)
+#ifdef USE_COLOR_ATTRIB_SRGB_TO_LINEAR
+
+ color_interp = vec4(
+ color_attrib.r<0.04045 ? color_attrib.r * (1.0 / 12.92) : pow((color_attrib.r + 0.055) * (1.0 / (1 + 0.055)), 2.4),
+ color_attrib.g<0.04045 ? color_attrib.g * (1.0 / 12.92) : pow((color_attrib.g + 0.055) * (1.0 / (1 + 0.055)), 2.4),
+ color_attrib.b<0.04045 ? color_attrib.b * (1.0 / 12.92) : pow((color_attrib.b + 0.055) * (1.0 / (1 + 0.055)), 2.4),
+ color_attrib.a
+ );
+#else
color_interp = color_attrib;
#endif
+#endif
#if defined(ENABLE_TANGENT_INTERP)
- tangent_interp=normalize(tangent_in);
- binormal_interp = normalize( cross(normal_interp,tangent_interp) * tangent_attrib.a );
+ tangent_interp=normalize((modelview * vec4(tangent_in,0.0)).xyz);
+ binormal_interp = normalize( cross(normal_interp,tangent_interp) * binormalf );
#endif
#if defined(ENABLE_UV_INTERP)
@@ -446,6 +481,7 @@ VERTEX_SHADER_CODE
#ifdef USE_GLES_OVER_GL
#define mediump
#define highp
+#define roundfix( m_val ) floor( (m_val) + 0.5 )
#else
precision mediump float;
@@ -453,6 +489,27 @@ precision mediump int;
#endif
+
+//hack to use uv if no uv present so it works with lightmap
+#ifdef ENABLE_AMBIENT_LIGHTMAP
+
+#ifdef USE_LIGHTMAP_ON_UV2
+
+#ifndef ENABLE_UV2_INTERP
+#define ENABLE_UV2_INTERP
+#endif
+
+#else
+
+#ifndef ENABLE_UV_INTERP
+#define ENABLE_UV_INTERP
+#endif
+
+#endif
+
+#endif
+
+
/* Varyings */
#if defined(ENABLE_COLOR_INTERP)
@@ -538,13 +595,28 @@ uniform float time;
varying highp vec3 ambient_octree_coords;
uniform highp float ambient_octree_lattice_size;
uniform highp vec2 ambient_octree_pix_size;
+uniform highp vec2 ambient_octree_light_pix_size;
uniform highp float ambient_octree_lattice_divide;
uniform highp sampler2D ambient_octree_tex;
+uniform highp sampler2D ambient_octree_light_tex;
uniform float ambient_octree_multiplier;
uniform int ambient_octree_steps;
#endif
+#ifdef ENABLE_AMBIENT_LIGHTMAP
+
+uniform highp sampler2D ambient_lightmap;
+uniform float ambient_lightmap_multiplier;
+
+#endif
+
+#ifdef ENABLE_AMBIENT_DP_SAMPLER
+
+uniform highp sampler2D ambient_dp_sampler;
+uniform float ambient_dp_sampler_multiplier;
+
+#endif
FRAGMENT_SHADER_GLOBALS
@@ -707,6 +779,7 @@ uniform highp mat4 camera_inverse_transform;
#if defined(ENABLE_TEXSCREEN)
uniform vec2 texscreen_screen_mult;
+uniform vec4 texscreen_screen_clamp;
uniform sampler2D texscreen_tex;
#endif
@@ -755,6 +828,12 @@ void main() {
vec4 color = color_interp;
#endif
+#if defined(ENABLE_NORMALMAP)
+
+ vec3 normalmap = vec3(0.0);
+#endif
+
+ float normaldepth=1.0;
@@ -769,6 +848,12 @@ FRAGMENT_SHADER_CODE
}
+#if defined(ENABLE_NORMALMAP)
+
+ normal = normalize( mix(normal_interp,tangent_interp * normalmap.x + binormal_interp * normalmap.y + normal_interp * normalmap.z,normaldepth) ) * side;
+
+#endif
+
#if defined(ENABLE_DISCARD)
if (discard_) {
//easy to eliminate dead code
@@ -783,6 +868,34 @@ FRAGMENT_SHADER_CODE
}
#endif
+ float shadow_attenuation = 1.0;
+
+#ifdef ENABLE_AMBIENT_LIGHTMAP
+
+ vec3 ambientmap_color = vec3(0.0,0.0,0.0);
+ vec2 ambientmap_uv = vec2(0.0,0.0);
+
+#ifdef USE_LIGHTMAP_ON_UV2
+
+ ambientmap_uv = uv2_interp;
+
+#else
+
+ ambientmap_uv = uv_interp;
+
+#endif
+
+ vec4 amcol = texture2D(ambient_lightmap,ambientmap_uv);
+ shadow_attenuation=amcol.a;
+ ambientmap_color = amcol.rgb;
+ ambientmap_color*=ambient_lightmap_multiplier;
+ ambientmap_color*=diffuse.rgb;
+
+
+
+#endif
+
+
#ifdef ENABLE_AMBIENT_OCTREE
vec3 ambientmap_color = vec3(0.0,0.0,0.0);
@@ -814,12 +927,12 @@ FRAGMENT_SHADER_CODE
}
//sample color
- octant_uv=(octant_uv+0.5)*ambient_octree_pix_size;
+ octant_uv=(octant_uv+0.5)*ambient_octree_light_pix_size;
highp vec3 sub=(mod(ambient_octree_coords,ld)/ld);
- octant_uv.xy+=sub.xy*ambient_octree_pix_size.xy;
- vec3 col_up=texture2D(ambient_octree_tex,octant_uv).rgb;
- octant_uv.y+=ambient_octree_pix_size.y*2.0;
- vec3 col_down=texture2D(ambient_octree_tex,octant_uv).rgb;
+ octant_uv.xy+=sub.xy*ambient_octree_light_pix_size.xy;
+ vec3 col_up=texture2D(ambient_octree_light_tex,octant_uv).rgb;
+ octant_uv.y+=ambient_octree_light_pix_size.y*2.0;
+ vec3 col_down=texture2D(ambient_octree_light_tex,octant_uv).rgb;
ambientmap_color=mix(col_up,col_down,sub.z)*ambient_octree_multiplier;
ambientmap_color*=diffuse.rgb;
@@ -828,9 +941,29 @@ FRAGMENT_SHADER_CODE
#endif
- float shadow_attenuation = 1.0;
+#ifdef ENABLE_AMBIENT_DP_SAMPLER
+
+ vec3 ambientmap_color = vec3(0.0,0.0,0.0);
+
+ {
+
+ vec3 dp_normal = normalize((vec4(normal,0) * camera_inverse_transform).xyz);
+ vec2 ambient_uv = (dp_normal.xy / (1.0+abs(dp_normal.z)))*0.5+0.5; //dual paraboloid
+ ambient_uv.y*=0.5;
+ if (dp_normal.z<0) {
+
+ ambient_uv.y=(0.5-ambient_uv.y)+0.5;
+
+ }
+
+ ambientmap_color = texture2D(ambient_dp_sampler,ambient_uv ).rgb * ambient_dp_sampler_multiplier;
+ ambientmap_color*=diffuse.rgb;
+ }
+
+#endif
+
@@ -1042,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
{
@@ -1062,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);
@@ -1082,7 +1223,7 @@ LIGHT_SHADER_CODE
# if !defined(LIGHT_TYPE_DIRECTIONAL) && !defined(LIGHT_TYPE_OMNI) && !defined (LIGHT_TYPE_SPOT)
//none
#ifndef SHADELESS
- diffuse.rgb=vec3(0.0,0.0,0.0);
+ diffuse.rgb=ambient_light *diffuse.rgb;
#endif
# endif
@@ -1098,7 +1239,7 @@ LIGHT_SHADER_CODE
vec3 ambient = const_light_mult*ambient_light*diffuse.rgb;
# if defined(LIGHT_TYPE_OMNI) || defined (LIGHT_TYPE_SPOT)
- ambient*=diffuse_interp.a; //attenuation affects ambient too
+// ambient*=diffuse_interp.a; //attenuation affects ambient too
# endif
@@ -1120,7 +1261,7 @@ LIGHT_SHADER_CODE
#endif
-#ifdef ENABLE_AMBIENT_OCTREE
+#if defined(ENABLE_AMBIENT_OCTREE) || defined(ENABLE_AMBIENT_LIGHTMAP) || defined(ENABLE_AMBIENT_DP_SAMPLER)
diffuse.rgb+=ambientmap_color;
#endif
diff --git a/drivers/jpg/SCsub b/drivers/jpg/SCsub
index e1fcc5ea89..df91b10a02 100644
--- a/drivers/jpg/SCsub
+++ b/drivers/jpg/SCsub
@@ -10,4 +10,3 @@ jpg_sources = [
env.drivers_sources+=jpg_sources
#env.add_source_files(env.drivers_sources, jpg_sources)
-
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 e1f9aacf5f..fe6aa05d00 100644
--- a/drivers/mpc/audio_stream_mpc.cpp
+++ b/drivers/mpc/audio_stream_mpc.cpp
@@ -1,13 +1,14 @@
#include "audio_stream_mpc.h"
-Error AudioStreamMPC::_open_file() {
+Error AudioStreamPlaybackMPC::_open_file() {
if (f) {
memdelete(f);
f=NULL;
}
Error err;
+ //printf("mpc open file %ls\n", file.c_str());
f=FileAccess::open(file,FileAccess::READ,&err);
if (err) {
@@ -16,9 +17,10 @@ Error AudioStreamMPC::_open_file() {
return err;
}
- f->seek_end(0);
- streamlen=f->get_pos();
- f->seek(0);
+ //printf("file size is %i\n", f->get_len());
+ //f->seek_end(0);
+ streamlen=f->get_len();
+ //f->seek(0);
if (streamlen<=0) {
memdelete(f);
f=NULL;
@@ -39,7 +41,7 @@ Error AudioStreamMPC::_open_file() {
return OK;
}
-void AudioStreamMPC::_close_file() {
+void AudioStreamPlaybackMPC::_close_file() {
if (f) {
memdelete(f);
@@ -50,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);
@@ -66,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;
@@ -81,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();
@@ -91,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;
@@ -105,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) {
@@ -160,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
@@ -183,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 {
@@ -211,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);
@@ -222,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();
@@ -260,9 +268,9 @@ void AudioStreamMPC::play() {
}
-void AudioStreamMPC::stop() {
+void AudioStreamPlaybackMPC::stop() {
+
- _THREAD_SAFE_METHOD_
if (!active)
return;
if (demux) {
@@ -273,70 +281,58 @@ void AudioStreamMPC::stop() {
active=false;
}
-bool AudioStreamMPC::is_playing() const {
+bool AudioStreamPlaybackMPC::is_playing() const {
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;
@@ -354,7 +350,7 @@ AudioStreamMPC::AudioStreamMPC() {
}
-AudioStreamMPC::~AudioStreamMPC() {
+AudioStreamPlaybackMPC::~AudioStreamPlaybackMPC() {
stop();
@@ -364,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/mpc/mpc_reader.c b/drivers/mpc/mpc_reader.c
index e1d151fe50..550c5ecb54 100644
--- a/drivers/mpc/mpc_reader.c
+++ b/drivers/mpc/mpc_reader.c
@@ -36,6 +36,7 @@
#include <mpc/reader.h>
#include "internal.h"
#include <stdio.h>
+#include <string.h> // memset()
#define STDIO_MAGIC 0xF34B963C ///< Just a random safe-check value...
typedef struct mpc_reader_stdio_t {
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/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..e8578221a9
--- /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-2010 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..76aab2aea6
--- /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-2010 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 5cdc3ea1c0..3ee1bb6408 100644
--- a/drivers/ogg/SCsub
+++ b/drivers/ogg/SCsub
@@ -7,4 +7,3 @@ 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/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..eb9c81e152
--- /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-2015 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..2f173cc270
--- /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-2015 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..9ee066cbb2 100644
--- a/drivers/png/SCsub
+++ b/drivers/png/SCsub
@@ -27,7 +27,10 @@ if ("neon_enabled" in env and env["neon_enabled"]):
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"))
+ import os
+ # Currently .ASM filter_neon.S does not compile on NT.
+ if (os.name!="nt"):
+ png_sources.append(env_neon.Object("#drivers/png/filter_neon.S"))
env.drivers_sources+=png_sources
@@ -35,4 +38,3 @@ env.drivers_sources+=png_sources
#env.add_source_files(env.drivers_sources, png_sources)
Export('env')
-
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 316397ed80..2a4720b07b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,6 +31,8 @@
#include "print_string.h"
#include "os/os.h"
+
+
void ImageLoaderPNG::_read_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length) {
FileAccess *f = (FileAccess*)png_get_io_ptr(png_ptr);
@@ -102,6 +104,9 @@ Error ImageLoaderPNG::_load_image(void *rf_up,png_rw_ptr p_func,Image *p_image)
png_read_info(png, info);
png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
+ png_textp t;
+ //https://svn.gov.pt/projects/ccidadao/repository/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImage/PluginPNG.cpp
+ //png_get_text(png,info,)
/*
printf("Image width:%i\n", width);
printf("Image Height:%i\n", height);
@@ -250,6 +255,7 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const
struct PNGReadStatus {
int offset;
+ int size;
const unsigned char *image;
};
@@ -258,17 +264,26 @@ static void user_read_data(png_structp png_ptr,png_bytep data, png_size_t p_leng
PNGReadStatus *rstatus;
rstatus=(PNGReadStatus*)png_get_io_ptr(png_ptr);
- memcpy(data,&rstatus->image[rstatus->offset],p_length);
- rstatus->offset+=p_length;
+ int to_read=p_length;
+ if (rstatus->size>=0) {
+ to_read = MIN( p_length, rstatus->size - rstatus->offset);
+ }
+ memcpy(data,&rstatus->image[rstatus->offset],to_read);
+ rstatus->offset+=to_read;
+
+ if (to_read<p_length) {
+ memset(&data[to_read],0,p_length-to_read);
+ }
}
-static Image _load_mem_png(const uint8_t* p_png) {
+static Image _load_mem_png(const uint8_t* p_png,int p_size) {
PNGReadStatus prs;
prs.image=p_png;
prs.offset=0;
+ prs.size=p_size;
Image img;
Error err = ImageLoaderPNG::_load_image(&prs,user_read_data,&img);
@@ -280,9 +295,10 @@ static Image _load_mem_png(const uint8_t* p_png) {
static Image _lossless_unpack_png(const DVector<uint8_t>& p_data) {
+ int len = p_data.size();
DVector<uint8_t>::Read r = p_data.read();
ERR_FAIL_COND_V(r[0]!='P' || r[1]!='N' || r[2]!='G' || r[3]!=' ',Image());
- return _load_mem_png(&r[4]);
+ return _load_mem_png(&r[4],len-4);
}
@@ -421,6 +437,7 @@ static DVector<uint8_t> _lossless_pack_png(const Image& p_image) {
ImageLoaderPNG::ImageLoaderPNG() {
+
Image::_png_mem_loader_func=_load_mem_png;
Image::lossless_unpacker=_lossless_unpack_png;
Image::lossless_packer=_lossless_pack_png;
diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h
index 77f575339c..8413a7eae1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,7 +40,10 @@ class ImageLoaderPNG : public ImageFormatLoader {
static void _read_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length);
+
public:
+
+
static Error _load_image(void *rf_up,png_rw_ptr p_func,Image *p_image);
virtual Error load_image(Image *p_image,FileAccess *f);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
diff --git a/drivers/png/pngpriv.h b/drivers/png/pngpriv.h
index 67e486c577..56532f4eeb 100644
--- a/drivers/png/pngpriv.h
+++ b/drivers/png/pngpriv.h
@@ -341,7 +341,11 @@ 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)
-# define png_strlen lstrlenA
+# ifdef WINRT_ENABLED
+# define png_strlen strlen
+# else
+# define png_strlen lstrlenA
+# endif
# define png_memcmp memcmp
# define png_memcpy CopyMemory
# define png_memset memset
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index a898f6e618..581efb5adc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,6 +30,8 @@
#include "scene/resources/texture.h"
#include "drivers/png/png.h"
#include "os/file_access.h"
+#include "globals.h"
+#include "core/image.h"
static void _write_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length) {
@@ -45,12 +47,59 @@ Error ResourceSaverPNG::save(const String &p_path,const RES& p_resource,uint32_t
ERR_EXPLAIN("Can't save empty texture as PNG");
ERR_FAIL_COND_V(!texture->get_width() || !texture->get_height(),ERR_INVALID_PARAMETER);
+
Image img = texture->get_data();
- if (img.get_format() > Image::FORMAT_INDEXED_ALPHA)
- img.decompress();
+ Error err = save_image(p_path, img);
+
+ if (err == OK) {
+
+ bool global_filter = Globals::get_singleton()->get("image_loader/filter");
+ bool global_mipmaps = Globals::get_singleton()->get("image_loader/gen_mipmaps");
+ bool global_repeat = Globals::get_singleton()->get("image_loader/repeat");
+
+ String text;
+
+ if (global_filter!=bool(texture->get_flags()&Texture::FLAG_FILTER)) {
+ text+=bool(texture->get_flags()&Texture::FLAG_FILTER)?"filter=true\n":"filter=false\n";
+ }
+ if (global_mipmaps!=bool(texture->get_flags()&Texture::FLAG_MIPMAPS)) {
+ text+=bool(texture->get_flags()&Texture::FLAG_MIPMAPS)?"gen_mipmaps=true\n":"gen_mipmaps=false\n";
+ }
+ if (global_repeat!=bool(texture->get_flags()&Texture::FLAG_REPEAT)) {
+ text+=bool(texture->get_flags()&Texture::FLAG_REPEAT)?"repeat=true\n":"repeat=false\n";
+ }
+ if (bool(texture->get_flags()&Texture::FLAG_ANISOTROPIC_FILTER)) {
+ text+="anisotropic=true\n";
+ }
+ 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")) {
- ERR_FAIL_COND_V(img.get_format() > Image::FORMAT_INDEXED_ALPHA, ERR_INVALID_PARAMETER);
+ FileAccess* f = FileAccess::open(p_path+".flags",FileAccess::WRITE);
+ if (f) {
+
+ f->store_string(text);
+ memdelete(f);
+ }
+ }
+ }
+
+
+ return err;
+};
+
+Error ResourceSaverPNG::save_image(const String &p_path, Image &p_img) {
+
+ if (p_img.get_format() > Image::FORMAT_INDEXED_ALPHA)
+ p_img.decompress();
+
+ ERR_FAIL_COND_V(p_img.get_format() > Image::FORMAT_INDEXED_ALPHA, ERR_INVALID_PARAMETER);
png_structp png_ptr;
png_infop info_ptr;
@@ -88,7 +137,7 @@ Error ResourceSaverPNG::save(const String &p_path,const RES& p_resource,uint32_t
int cs=0;
- switch(img.get_format()) {
+ switch(p_img.get_format()) {
case Image::FORMAT_GRAYSCALE: {
@@ -112,14 +161,14 @@ Error ResourceSaverPNG::save(const String &p_path,const RES& p_resource,uint32_t
} break;
default: {
- if (img.detect_alpha()) {
+ if (p_img.detect_alpha()) {
- img.convert(Image::FORMAT_RGBA);
+ p_img.convert(Image::FORMAT_RGBA);
pngf=PNG_COLOR_TYPE_RGB_ALPHA;
cs=4;
} else {
- img.convert(Image::FORMAT_RGB);
+ p_img.convert(Image::FORMAT_RGB);
pngf=PNG_COLOR_TYPE_RGB;
cs=3;
}
@@ -127,8 +176,8 @@ Error ResourceSaverPNG::save(const String &p_path,const RES& p_resource,uint32_t
}
}
- int w = img.get_width();
- int h = img.get_height();
+ int w = p_img.get_width();
+ int h = p_img.get_height();
png_set_IHDR(png_ptr, info_ptr, w,h,
8, pngf, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
@@ -143,7 +192,7 @@ Error ResourceSaverPNG::save(const String &p_path,const RES& p_resource,uint32_t
}
- DVector<uint8_t>::Read r = img.get_data().read();
+ DVector<uint8_t>::Read r = p_img.get_data().read();
row_pointers = (png_bytep*)memalloc(sizeof(png_bytep)*h);
for(int i=0;i<h;i++) {
@@ -164,8 +213,8 @@ Error ResourceSaverPNG::save(const String &p_path,const RES& p_resource,uint32_t
png_write_end(png_ptr, NULL);
memdelete(f);
-
/* cleanup heap allocation */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
return OK;
}
@@ -181,3 +230,8 @@ void ResourceSaverPNG::get_recognized_extensions(const RES& p_resource,List<Stri
}
}
+
+ResourceSaverPNG::ResourceSaverPNG() {
+
+ Image::save_png_func = &save_image;
+};
diff --git a/drivers/png/resource_saver_png.h b/drivers/png/resource_saver_png.h
index 7da50150e2..116d425d24 100644
--- a/drivers/png/resource_saver_png.h
+++ b/drivers/png/resource_saver_png.h
@@ -6,9 +6,13 @@
class ResourceSaverPNG : public ResourceFormatSaver {
public:
+ static Error save_image(const String &p_path, Image& p_img);
+
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;
+
+ ResourceSaverPNG();
};
diff --git a/drivers/pulseaudio/SCsub b/drivers/pulseaudio/SCsub
new file mode 100644
index 0000000000..9fbb467baa
--- /dev/null
+++ b/drivers/pulseaudio/SCsub
@@ -0,0 +1,5 @@
+Import('env')
+
+env.add_source_files(env.drivers_sources,"*.cpp")
+
+Export('env')
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
new file mode 100644
index 0000000000..4cda141f92
--- /dev/null
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -0,0 +1,207 @@
+/*************************************************************************/
+/* audio_driver_alsa.cpp */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#include "audio_driver_pulseaudio.h"
+
+#ifdef PULSEAUDIO_ENABLED
+
+#include <pulse/error.h>
+
+#include "globals.h"
+
+Error AudioDriverPulseAudio::init() {
+
+ active = false;
+ thread_exited = false;
+ exit_thread = false;
+ pcm_open = false;
+ samples_in = NULL;
+ samples_out = NULL;
+
+ mix_rate = 44100;
+ output_format = OUTPUT_STEREO;
+ channels = 2;
+
+ pa_sample_spec spec;
+ spec.format = PA_SAMPLE_S16LE;
+ spec.channels = channels;
+ spec.rate = mix_rate;
+
+ int error_code;
+ pulse = pa_simple_new(NULL, // default server
+ "Godot", // application name
+ PA_STREAM_PLAYBACK,
+ NULL, // default device
+ "Sound", // stream description
+ &spec,
+ NULL, // use default channel map
+ NULL, // use default buffering attributes
+ &error_code
+ );
+
+ if (pulse == NULL) {
+
+ fprintf(stderr, "PulseAudio ERR: %s\n", pa_strerror(error_code));\
+ ERR_FAIL_COND_V(pulse == NULL, ERR_CANT_OPEN);
+ }
+
+ 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);
+ samples_out = memnew_arr(int16_t, buffer_size * channels);
+
+ mutex = Mutex::create();
+ thread = Thread::create(AudioDriverPulseAudio::thread_func, this);
+
+ 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;
+
+ while (!ad->exit_thread) {
+
+ if (!ad->active) {
+
+ for (unsigned int i=0; i < ad->buffer_size * ad->channels; i++) {
+
+ ad->samples_out[i] = 0;
+ }
+
+ } else {
+
+ ad->lock();
+
+ ad->audio_server_process(ad->buffer_size, ad->samples_in);
+
+ ad->unlock();
+
+ for (unsigned int i=0; i < ad->buffer_size * ad->channels;i ++) {
+
+ ad->samples_out[i] = ad->samples_in[i] >> 16;
+ }
+ }
+
+ // pa_simple_write always consumes the entire buffer
+
+ int error_code;
+ int byte_size = ad->buffer_size * sizeof(int16_t) * ad->channels;
+ if (pa_simple_write(ad->pulse, ad->samples_out, byte_size, &error_code) < 0) {
+
+ // can't recover here
+ fprintf(stderr, "PulseAudio failed and can't recover: %s\n", pa_strerror(error_code));
+ ad->active = false;
+ ad->exit_thread = true;
+ break;
+ }
+
+ }
+
+ ad->thread_exited = true;
+}
+
+void AudioDriverPulseAudio::start() {
+
+ active = true;
+}
+
+int AudioDriverPulseAudio::get_mix_rate() const {
+
+ return mix_rate;
+}
+
+AudioDriverSW::OutputFormat AudioDriverPulseAudio::get_output_format() const {
+
+ return output_format;
+}
+
+void AudioDriverPulseAudio::lock() {
+
+ if (!thread || !mutex)
+ return;
+ mutex->lock();
+}
+
+void AudioDriverPulseAudio::unlock() {
+
+ if (!thread || !mutex)
+ return;
+ mutex->unlock();
+}
+
+void AudioDriverPulseAudio::finish() {
+
+ if (!thread)
+ return;
+
+ exit_thread = true;
+ Thread::wait_to_finish(thread);
+
+ if (pulse)
+ pa_simple_free(pulse);
+
+ if (samples_in) {
+ memdelete_arr(samples_in);
+ memdelete_arr(samples_out);
+ };
+
+ memdelete(thread);
+ if (mutex) {
+ memdelete(mutex);
+ mutex = NULL;
+ }
+
+ thread = NULL;
+}
+
+AudioDriverPulseAudio::AudioDriverPulseAudio() {
+
+ mutex = NULL;
+ thread = NULL;
+ pulse = NULL;
+ latency=0;
+}
+
+AudioDriverPulseAudio::~AudioDriverPulseAudio() {
+
+}
+
+#endif
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
new file mode 100644
index 0000000000..e7c8bcce36
--- /dev/null
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* audio_driver_pulseaudio.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#include "servers/audio/audio_server_sw.h"
+
+#ifdef PULSEAUDIO_ENABLED
+
+#include "core/os/thread.h"
+#include "core/os/mutex.h"
+
+#include <pulse/simple.h>
+
+class AudioDriverPulseAudio : public AudioDriverSW {
+
+ Thread* thread;
+ Mutex* mutex;
+
+ pa_simple* pulse;
+
+ int32_t* samples_in;
+ int16_t* samples_out;
+
+ static void thread_func(void* p_udata);
+
+ unsigned int mix_rate;
+ OutputFormat output_format;
+
+ unsigned int buffer_size;
+ int channels;
+
+ bool active;
+ bool thread_exited;
+ mutable bool exit_thread;
+ bool pcm_open;
+
+ float latency;
+
+public:
+
+ const char* get_name() const {
+ return "PulseAudio";
+ };
+
+ 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();
+
+ virtual float get_latency();
+
+
+ AudioDriverPulseAudio();
+ ~AudioDriverPulseAudio();
+};
+
+#endif
diff --git a/drivers/pvr/AlphaBitmap.h b/drivers/pvr/AlphaBitmap.h
new file mode 100644
index 0000000000..57c6b026ea
--- /dev/null
+++ b/drivers/pvr/AlphaBitmap.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "Bitmap.h"
+
+namespace Javelin {
+
+class AlphaBitmap : public Bitmap {
+public:
+ AlphaBitmap(int w, int h)
+ : Bitmap(w, h, 1) {
+ }
+
+ const unsigned char *GetData() const { return data; }
+
+ unsigned char *GetData() { return data; }
+};
+
+}
diff --git a/drivers/pvr/BitScale.cpp b/drivers/pvr/BitScale.cpp
new file mode 100644
index 0000000000..97b3f0aa25
--- /dev/null
+++ b/drivers/pvr/BitScale.cpp
@@ -0,0 +1,184 @@
+#include "BitScale.h"
+
+
+const uint8_t Javelin::Data::BITSCALE_5_TO_8[32] = {
+ 0, 8, 16, 24, 32, 41, 49, 57, 65, 74,
+ 82, 90, 98, 106, 115, 123, 131, 139, 148, 156,
+ 164, 172, 180, 189, 197, 205, 213, 222, 230, 238,
+ 246, 255};
+
+const uint8_t Javelin::Data::BITSCALE_4_TO_8[16] = {
+ 0, 17, 34, 51, 68, 85, 102, 119, 136, 153,
+ 170, 187, 204, 221, 238, 255};
+
+const uint8_t Javelin::Data::BITSCALE_3_TO_8[8] = {
+ 0, 36, 72, 109, 145, 182, 218, 255};
+
+const uint8_t Javelin::Data::BITSCALE_8_TO_5_FLOOR[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
+ 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 10, 10, 10, 10, 10, 10, 10,
+ 10, 11, 11, 11, 11, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 12, 12, 12, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 14, 14, 14, 14,
+ 14, 14, 14, 14, 15, 15, 15, 15, 15, 15,
+ 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 18,
+ 18, 18, 18, 18, 18, 18, 18, 19, 19, 19,
+ 19, 19, 19, 19, 19, 20, 20, 20, 20, 20,
+ 20, 20, 20, 21, 21, 21, 21, 21, 21, 21,
+ 21, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 23, 23, 23, 23, 24, 24,
+ 24, 24, 24, 24, 24, 24, 25, 25, 25, 25,
+ 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 27, 27, 27, 27, 27, 27, 27,
+ 27, 28, 28, 28, 28, 28, 28, 28, 28, 29,
+ 29, 29, 29, 29, 29, 29, 29, 30, 30, 30,
+ 30, 30, 30, 30, 30, 31};
+
+const uint8_t Javelin::Data::BITSCALE_8_TO_4_FLOOR[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 15};
+
+const uint8_t Javelin::Data::BITSCALE_8_TO_3_FLOOR[256] = {
+ 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, 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, 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, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 7};
+
+const uint8_t Javelin::Data::BITSCALE_8_TO_5_CEIL[256] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
+ 10, 10, 10, 11, 11, 11, 11, 11, 11, 11,
+ 11, 12, 12, 12, 12, 12, 12, 12, 12, 13,
+ 13, 13, 13, 13, 13, 13, 13, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 15, 15, 15, 16, 16, 16, 16, 16, 16,
+ 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
+ 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
+ 20, 20, 20, 20, 20, 21, 21, 21, 21, 21,
+ 21, 21, 21, 22, 22, 22, 22, 22, 22, 22,
+ 22, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 24, 24, 24, 24, 24, 24, 24, 24, 25, 25,
+ 25, 25, 25, 25, 25, 25, 26, 26, 26, 26,
+ 26, 26, 26, 26, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 28, 28, 28, 28, 28, 28, 28,
+ 28, 29, 29, 29, 29, 29, 29, 29, 29, 30,
+ 30, 30, 30, 30, 30, 30, 30, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31};
+
+const uint8_t Javelin::Data::BITSCALE_8_TO_4_CEIL[256] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15};
+
+const uint8_t Javelin::Data::BITSCALE_8_TO_3_CEIL[256] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 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, 2,
+ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7};
+
diff --git a/drivers/pvr/BitScale.h b/drivers/pvr/BitScale.h
new file mode 100644
index 0000000000..36613aeeee
--- /dev/null
+++ b/drivers/pvr/BitScale.h
@@ -0,0 +1,28 @@
+//============================================================================
+
+#pragma once
+
+#include "typedefs.h"
+
+//============================================================================
+
+namespace Javelin
+{
+ namespace Data
+ {
+//============================================================================
+
+ extern const uint8_t BITSCALE_5_TO_8[32];
+ extern const uint8_t BITSCALE_4_TO_8[16];
+ extern const uint8_t BITSCALE_3_TO_8[8];
+ extern const uint8_t BITSCALE_8_TO_5_FLOOR[256];
+ extern const uint8_t BITSCALE_8_TO_4_FLOOR[256];
+ extern const uint8_t BITSCALE_8_TO_3_FLOOR[256];
+ extern const uint8_t BITSCALE_8_TO_5_CEIL[256];
+ extern const uint8_t BITSCALE_8_TO_4_CEIL[256];
+ extern const uint8_t BITSCALE_8_TO_3_CEIL[256];
+
+//============================================================================
+ } // namespace Data
+} // namespace Javelin
+//============================================================================
diff --git a/drivers/pvr/BitUtility.h b/drivers/pvr/BitUtility.h
new file mode 100644
index 0000000000..588ff3e892
--- /dev/null
+++ b/drivers/pvr/BitUtility.h
@@ -0,0 +1,19 @@
+#pragma once
+
+namespace Javelin {
+
+class BitUtility {
+public:
+ static bool IsPowerOf2(unsigned int x) {
+ return (x & (x - 1)) == 0;
+ }
+
+ static unsigned int RotateRight(unsigned int value, unsigned int shift) {
+ if ((shift &= sizeof(value) * 8 - 1) == 0) {
+ return value;
+ }
+ return (value >> shift) | (value << (sizeof(value) * 8 - shift));
+ }
+};
+
+}
diff --git a/drivers/pvr/Bitmap.h b/drivers/pvr/Bitmap.h
new file mode 100644
index 0000000000..508ed8cb75
--- /dev/null
+++ b/drivers/pvr/Bitmap.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "Point2.h"
+
+namespace Javelin {
+
+class Bitmap {
+public:
+ int width;
+ int height;
+ unsigned char *data;
+
+ Bitmap(int w, int h, int bytesPerPixel)
+ : width(w)
+ , height(h)
+ , data(new unsigned char[width * height * bytesPerPixel]) {
+ }
+
+ virtual ~Bitmap() {
+ delete [] data;
+ }
+
+ Point2<int> GetSize() const { return Point2<int>(width, height); }
+
+ int GetArea() const { return width * height; }
+
+ int GetBitmapWidth() const { return width; }
+
+ int GetBitmapHeight() const { return height; }
+
+ const unsigned char *GetRawData() const { return data; }
+};
+
+}
diff --git a/drivers/pvr/ColorRgba.h b/drivers/pvr/ColorRgba.h
new file mode 100644
index 0000000000..0701420566
--- /dev/null
+++ b/drivers/pvr/ColorRgba.h
@@ -0,0 +1,152 @@
+#pragma once
+
+namespace Javelin {
+
+template<typename T>
+class ColorRgb {
+public:
+ T b;
+ T g;
+ T r;
+
+
+ ColorRgb()
+ : b(0)
+ , g(0)
+ , r(0) {
+ }
+
+ ColorRgb(T red, T green, T blue)
+ : b(blue)
+ , g(green)
+ , r(red) {
+ }
+
+ ColorRgb(const ColorRgb<T> &x)
+ : b(x.b)
+ , g(x.g)
+ , r(x.r) {
+ }
+
+ ColorRgb<int> operator *(int x) {
+ return ColorRgb<int>(r * x, g * x, b * x);
+ }
+
+ ColorRgb<int> operator +(const ColorRgb<T> &x) const {
+ return ColorRgb<int>(r + (int)x.r, g + (int)x.g, b + (int)x.b);
+ }
+
+ ColorRgb<int> operator -(const ColorRgb<T> &x) const {
+ return ColorRgb<int>(r - (int)x.r, g - (int)x.g, b - (int)x.b);
+ }
+
+ int operator %(const ColorRgb<T> &x) const {
+ return r * (int)x.r + g * (int)x.g + b * (int)x.b;
+ }
+
+ bool operator ==(const ColorRgb<T> &x) const {
+ return r == x.r && g == x.g && b == x.b;
+ }
+
+ bool operator !=(const ColorRgb<T> &x) const {
+ return r != x.r || g != x.g || b != x.b;
+ }
+
+ void SetMin(const ColorRgb<T> &x) {
+ if (x.r < r) {
+ r = x.r;
+ }
+ if (x.g < g) {
+ g = x.g;
+ }
+ if (x.b < b) {
+ b = x.b;
+ }
+ }
+
+ void SetMax(const ColorRgb<T> &x) {
+ if (x.r > r) {
+ r = x.r;
+ }
+ if (x.g > g) {
+ g = x.g;
+ }
+ if (x.b > b) {
+ b = x.b;
+ }
+ }
+};
+
+template<typename T>
+class ColorRgba : public ColorRgb<T> {
+public:
+ T a;
+
+ ColorRgba() :
+ a(0) {
+ }
+
+ ColorRgba(T red, T green, T blue, T alpha)
+ : ColorRgb<T>(red, green, blue)
+ , a(alpha) {
+ }
+
+ ColorRgba(const ColorRgba<T> &x)
+ : ColorRgb<T>(x.r, x.g, x.b)
+ , a(x.a) {
+ }
+
+ ColorRgba<int> operator *(int x) {
+ return ColorRgba<T>(ColorRgb<T>::r * x,
+ ColorRgb<T>::g * x,
+ ColorRgb<T>::b * x,
+ a * x);
+ }
+
+ ColorRgba<int> operator +(const ColorRgba<T> &x) {
+ return ColorRgba<T>(ColorRgb<T>::r + (int)x.r,
+ ColorRgb<T>::g + (int)x.g,
+ ColorRgb<T>::b + (int)x.b,
+ a + (int)x.a);
+ }
+
+ ColorRgba<int> operator -(const ColorRgba<T> &x) {
+ return ColorRgba<T>(ColorRgb<T>::r - (int)x.r,
+ ColorRgb<T>::g - (int)x.g,
+ ColorRgb<T>::b - (int)x.b,
+ a - (int)x.a);
+ }
+
+ int operator %(const ColorRgba<T> &x) {
+ return ColorRgb<T>::r * (int)x.r +
+ ColorRgb<T>::g * (int)x.g +
+ ColorRgb<T>::b * (int)x.b +
+ a * (int)x.a;
+ }
+
+ bool operator ==(const ColorRgba<T> &x) {
+ return ColorRgb<T>::r == x.r && ColorRgb<T>::g == x.g &&
+ ColorRgb<T>::b == x.b && a == x.a;
+ }
+
+ bool operator !=(const ColorRgba<T> &x) {
+ return ColorRgb<T>::r != x.r || ColorRgb<T>::g != x.g ||
+ ColorRgb<T>::b != x.b || a != x.a;
+ }
+
+ void SetMin(const ColorRgba<T> &x) {
+ ColorRgb<T>::SetMin(x);
+ if (x.a < a) {
+ a = x.a;
+ }
+ }
+
+ void SetMax(const ColorRgba<T> &x) {
+ ColorRgb<T>::SetMax(x);
+ if (x.a > a) {
+ a = x.a;
+ }
+ }
+};
+
+}
diff --git a/drivers/pvr/Interval.h b/drivers/pvr/Interval.h
new file mode 100644
index 0000000000..a7252e8375
--- /dev/null
+++ b/drivers/pvr/Interval.h
@@ -0,0 +1,21 @@
+#pragma once
+
+namespace Javelin {
+
+template<typename T>
+class Interval {
+public:
+ T min;
+ T max;
+
+ Interval() {
+ }
+
+ Interval<T> &operator|=(const T &x) {
+ min.SetMin(x);
+ max.SetMax(x);
+ return *this;
+ }
+};
+
+}
diff --git a/drivers/pvr/MortonTable.cpp b/drivers/pvr/MortonTable.cpp
new file mode 100644
index 0000000000..29a5af67f6
--- /dev/null
+++ b/drivers/pvr/MortonTable.cpp
@@ -0,0 +1,43 @@
+//============================================================================
+
+#include "MortonTable.h"
+
+//============================================================================
+
+const unsigned short Javelin::Data::MORTON_TABLE[256] =
+{
+ 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+ 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+ 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+ 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+ 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+ 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+ 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+ 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+ 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+ 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+ 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+ 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+ 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+ 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+ 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+ 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+ 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+ 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+ 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+ 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+ 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+ 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+ 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+ 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+ 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+ 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+ 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+ 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+ 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+ 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+ 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+ 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+};
+
+//============================================================================
diff --git a/drivers/pvr/MortonTable.h b/drivers/pvr/MortonTable.h
new file mode 100644
index 0000000000..7a27e59544
--- /dev/null
+++ b/drivers/pvr/MortonTable.h
@@ -0,0 +1,18 @@
+//============================================================================
+
+#pragma once
+
+//============================================================================
+
+namespace Javelin
+{
+ namespace Data
+ {
+//============================================================================
+
+ extern const unsigned short MORTON_TABLE[256];
+
+//============================================================================
+ } // namespace Data
+} // namespace Javelin
+//============================================================================
diff --git a/drivers/pvr/Point2.h b/drivers/pvr/Point2.h
new file mode 100644
index 0000000000..89fa4b6322
--- /dev/null
+++ b/drivers/pvr/Point2.h
@@ -0,0 +1,17 @@
+#pragma once
+
+namespace Javelin {
+
+template<typename T>
+class Point2 {
+public:
+ T x;
+ T y;
+
+ Point2(int a, int b)
+ : x(a)
+ , y(b) {
+ }
+};
+
+}
diff --git a/drivers/pvr/PvrTcDecoder.cpp b/drivers/pvr/PvrTcDecoder.cpp
new file mode 100644
index 0000000000..d8a36b342c
--- /dev/null
+++ b/drivers/pvr/PvrTcDecoder.cpp
@@ -0,0 +1,144 @@
+//============================================================================
+
+#include "PvrTcDecoder.h"
+#include "PvrTcPacket.h"
+
+#include "MortonTable.h"
+#include <assert.h>
+
+//============================================================================
+
+using namespace Javelin;
+using Data::MORTON_TABLE;
+
+//============================================================================
+
+inline unsigned PvrTcDecoder::GetMortonNumber(int x, int y)
+{
+ return MORTON_TABLE[x >> 8] << 17 | MORTON_TABLE[y >> 8] << 16 | MORTON_TABLE[x & 0xFF] << 1 | MORTON_TABLE[y & 0xFF];
+}
+
+//============================================================================
+
+void PvrTcDecoder::DecodeRgb4Bpp(ColorRgb<unsigned char>* result, const Point2<int>& size, const void* data)
+{
+ assert(size.x == size.y);
+
+ const int blocks = size.x / 4;
+ const int blockMask = blocks-1;
+ const PvrTcPacket* packets = static_cast<const PvrTcPacket*>(data);
+
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ const PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+
+ unsigned mod = packet->modulationData;
+ const unsigned char (*weights)[4] = PvrTcPacket::WEIGHTS + 4*packet->usePunchthroughAlpha;
+ const unsigned char (*factor)[4] = PvrTcPacket::BILINEAR_FACTORS;
+
+ for(int py = 0; py < 4; ++py)
+ {
+ const int yOffset = (py < 2) ? -1 : 0;
+ const int y0 = (y + yOffset) & blockMask;
+ const int y1 = (y0+1) & blockMask;
+
+ for(int px = 0; px < 4; ++px)
+ {
+ const int xOffset = (px < 2) ? -1 : 0;
+ const int x0 = (x + xOffset) & blockMask;
+ const int x1 = (x0+1) & blockMask;
+
+ const PvrTcPacket* p0 = packets + GetMortonNumber(x0, y0);
+ const PvrTcPacket* p1 = packets + GetMortonNumber(x1, y0);
+ const PvrTcPacket* p2 = packets + GetMortonNumber(x0, y1);
+ const PvrTcPacket* p3 = packets + GetMortonNumber(x1, y1);
+
+ ColorRgb<int> ca = p0->GetColorRgbA() * (*factor)[0] +
+ p1->GetColorRgbA() * (*factor)[1] +
+ p2->GetColorRgbA() * (*factor)[2] +
+ p3->GetColorRgbA() * (*factor)[3];
+
+ ColorRgb<int> cb = p0->GetColorRgbB() * (*factor)[0] +
+ p1->GetColorRgbB() * (*factor)[1] +
+ p2->GetColorRgbB() * (*factor)[2] +
+ p3->GetColorRgbB() * (*factor)[3];
+
+ const unsigned char* w = weights[mod&3];
+ ColorRgb<unsigned char> c;
+ c.r = (ca.r * w[0] + cb.r * w[1]) >> 7;
+ c.g = (ca.g * w[0] + cb.g * w[1]) >> 7;
+ c.b = (ca.b * w[0] + cb.b * w[1]) >> 7;
+
+ result[(py+y*4)*size.x + (px+x*4)] = c;
+ mod >>= 2;
+ factor++;
+ }
+ }
+ }
+ }
+}
+
+void PvrTcDecoder::DecodeRgba4Bpp(ColorRgba<unsigned char>* result, const Point2<int>& size, const void* data)
+{
+ assert(size.x == size.y);
+
+ const int blocks = size.x / 4;
+ const int blockMask = blocks-1;
+ const PvrTcPacket* packets = static_cast<const PvrTcPacket*>(data);
+
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ const PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+
+ unsigned mod = packet->modulationData;
+ const unsigned char (*weights)[4] = PvrTcPacket::WEIGHTS + 4*packet->usePunchthroughAlpha;
+ const unsigned char (*factor)[4] = PvrTcPacket::BILINEAR_FACTORS;
+
+ for(int py = 0; py < 4; ++py)
+ {
+ const int yOffset = (py < 2) ? -1 : 0;
+ const int y0 = (y + yOffset) & blockMask;
+ const int y1 = (y0+1) & blockMask;
+
+ for(int px = 0; px < 4; ++px)
+ {
+ const int xOffset = (px < 2) ? -1 : 0;
+ const int x0 = (x + xOffset) & blockMask;
+ const int x1 = (x0+1) & blockMask;
+
+ const PvrTcPacket* p0 = packets + GetMortonNumber(x0, y0);
+ const PvrTcPacket* p1 = packets + GetMortonNumber(x1, y0);
+ const PvrTcPacket* p2 = packets + GetMortonNumber(x0, y1);
+ const PvrTcPacket* p3 = packets + GetMortonNumber(x1, y1);
+
+ ColorRgba<int> ca = p0->GetColorRgbaA() * (*factor)[0] +
+ p1->GetColorRgbaA() * (*factor)[1] +
+ p2->GetColorRgbaA() * (*factor)[2] +
+ p3->GetColorRgbaA() * (*factor)[3];
+
+ ColorRgba<int> cb = p0->GetColorRgbaB() * (*factor)[0] +
+ p1->GetColorRgbaB() * (*factor)[1] +
+ p2->GetColorRgbaB() * (*factor)[2] +
+ p3->GetColorRgbaB() * (*factor)[3];
+
+ const unsigned char* w = weights[mod&3];
+ ColorRgba<unsigned char> c;
+ c.r = (ca.r * w[0] + cb.r * w[1]) >> 7;
+ c.g = (ca.g * w[0] + cb.g * w[1]) >> 7;
+ c.b = (ca.b * w[0] + cb.b * w[1]) >> 7;
+ c.a = (ca.a * w[2] + cb.a * w[3]) >> 7;
+
+ result[(py+y*4)*size.x + (px+x*4)] = c;
+ mod >>= 2;
+ factor++;
+ }
+ }
+ }
+ }
+}
+
+//============================================================================
diff --git a/drivers/pvr/PvrTcDecoder.h b/drivers/pvr/PvrTcDecoder.h
new file mode 100644
index 0000000000..1b6fcf964c
--- /dev/null
+++ b/drivers/pvr/PvrTcDecoder.h
@@ -0,0 +1,25 @@
+//============================================================================
+
+#pragma once
+#include "Point2.h"
+#include "ColorRgba.h"
+
+//============================================================================
+
+namespace Javelin
+{
+//============================================================================
+
+ class PvrTcDecoder
+ {
+ public:
+ static void DecodeRgb4Bpp(ColorRgb<unsigned char>* result, const Point2<int>& size, const void* data);
+ static void DecodeRgba4Bpp(ColorRgba<unsigned char>* result, const Point2<int>& size, const void* data);
+
+ private:
+ static unsigned GetMortonNumber(int x, int y);
+ };
+
+//============================================================================
+}
+//============================================================================
diff --git a/drivers/pvr/PvrTcEncoder.cpp b/drivers/pvr/PvrTcEncoder.cpp
new file mode 100644
index 0000000000..587b1320f1
--- /dev/null
+++ b/drivers/pvr/PvrTcEncoder.cpp
@@ -0,0 +1,474 @@
+//============================================================================
+
+#include "PvrTcEncoder.h"
+#include "AlphaBitmap.h"
+#include "PvrTcPacket.h"
+#include "RgbBitmap.h"
+#include "RgbaBitmap.h"
+#include "MortonTable.h"
+#include "BitUtility.h"
+#include "Interval.h"
+#include <assert.h>
+#include <math.h>
+#include <stdint.h>
+
+//============================================================================
+
+using namespace Javelin;
+using Data::MORTON_TABLE;
+
+//============================================================================
+
+static const unsigned char MODULATION_LUT[16] =
+{
+ 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3
+};
+
+//============================================================================
+
+inline unsigned PvrTcEncoder::GetMortonNumber(int x, int y)
+{
+ return MORTON_TABLE[x >> 8] << 17 | MORTON_TABLE[y >> 8] << 16 | MORTON_TABLE[x & 0xFF] << 1 | MORTON_TABLE[y & 0xFF];
+}
+
+//============================================================================
+
+void PvrTcEncoder::EncodeAlpha2Bpp(void* result, const AlphaBitmap& bitmap)
+{
+ int size = bitmap.GetBitmapWidth();
+ assert(size == bitmap.GetBitmapHeight());
+ assert(BitUtility::IsPowerOf2(size));
+
+ // Blocks in each dimension.
+ int xBlocks = size/8;
+ int yBlocks = size/4;
+
+ const unsigned char* bitmapData = bitmap.GetRawData();
+
+ PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
+ for(int y = 0; y < yBlocks; ++y)
+ {
+ for(int x = 0; x < xBlocks; ++x)
+ {
+ PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+ packet->usePunchthroughAlpha = 0;
+ packet->colorAIsOpaque = 0;
+ packet->colorA = 0x7ff; // White, with 0 alpha
+ packet->colorBIsOpaque = 1;
+ packet->colorB = 0x7fff; // White with full alpha
+
+ const unsigned char* blockBitmapData = &bitmapData[y*4*size + x*8];
+
+ uint32_t modulationData = 0;
+ for(int py = 0; py < 4; ++py)
+ {
+ const unsigned char* rowBitmapData = blockBitmapData;
+ for(int px = 0; px < 8; ++px)
+ {
+ unsigned char pixel = *rowBitmapData++;
+ modulationData = BitUtility::RotateRight(modulationData | (pixel >> 7), 1);
+ }
+ blockBitmapData += size;
+ }
+ packet->modulationData = modulationData;
+ }
+ }
+}
+
+void PvrTcEncoder::EncodeAlpha4Bpp(void* result, const AlphaBitmap& bitmap)
+{
+ int size = bitmap.GetBitmapWidth();
+ assert(size == bitmap.GetBitmapHeight());
+ assert(BitUtility::IsPowerOf2(size));
+
+ // Blocks in each dimension.
+ int blocks = size/4;
+
+ const unsigned char* bitmapData = bitmap.GetRawData();
+
+ PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+ packet->usePunchthroughAlpha = 0;
+ packet->colorAIsOpaque = 0;
+ packet->colorA = 0x7ff; // White, with 0 alpha
+ packet->colorBIsOpaque = 1;
+ packet->colorB = 0x7fff; // White with full alpha
+
+ const unsigned char* blockBitmapData = &bitmapData[(y*size + x)*4];
+
+ uint32_t modulationData = 0;
+ for(int py = 0; py < 4; ++py)
+ {
+ const unsigned char* rowBitmapData = blockBitmapData;
+ for(int px = 0; px < 4; ++px)
+ {
+ unsigned char pixel = *rowBitmapData++;
+ modulationData = BitUtility::RotateRight(modulationData | MODULATION_LUT[pixel>>4], 2);
+ }
+ blockBitmapData += size;
+ }
+ packet->modulationData = modulationData;
+ }
+ }
+}
+
+//============================================================================
+
+typedef Interval<ColorRgb<unsigned char> > ColorRgbBoundingBox;
+
+static void CalculateBoundingBox(ColorRgbBoundingBox& cbb, const RgbBitmap& bitmap, int blockX, int blockY)
+{
+ int size = bitmap.GetBitmapWidth();
+ const ColorRgb<unsigned char>* data = bitmap.GetData() + blockY * 4 * size + blockX * 4;
+
+ cbb.min = data[0];
+ cbb.max = data[0];
+ cbb |= data[1];
+ cbb |= data[2];
+ cbb |= data[3];
+
+ cbb |= data[size];
+ cbb |= data[size+1];
+ cbb |= data[size+2];
+ cbb |= data[size+3];
+
+ cbb |= data[2*size];
+ cbb |= data[2*size+1];
+ cbb |= data[2*size+2];
+ cbb |= data[2*size+3];
+
+ cbb |= data[3*size];
+ cbb |= data[3*size+1];
+ cbb |= data[3*size+2];
+ cbb |= data[3*size+3];
+}
+
+void PvrTcEncoder::EncodeRgb4Bpp(void* result, const RgbBitmap& bitmap)
+{
+ assert(bitmap.GetBitmapWidth() == bitmap.GetBitmapHeight());
+ assert(BitUtility::IsPowerOf2(bitmap.GetBitmapWidth()));
+ const int size = bitmap.GetBitmapWidth();
+ const int blocks = size / 4;
+ const int blockMask = blocks-1;
+
+ PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
+
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ ColorRgbBoundingBox cbb;
+ CalculateBoundingBox(cbb, bitmap, x, y);
+ PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+ packet->usePunchthroughAlpha = 0;
+ packet->SetColorA(cbb.min);
+ packet->SetColorB(cbb.max);
+ }
+ }
+
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ const unsigned char (*factor)[4] = PvrTcPacket::BILINEAR_FACTORS;
+ const ColorRgb<unsigned char>* data = bitmap.GetData() + y * 4 * size + x * 4;
+
+ uint32_t modulationData = 0;
+
+ for(int py = 0; py < 4; ++py)
+ {
+ const int yOffset = (py < 2) ? -1 : 0;
+ const int y0 = (y + yOffset) & blockMask;
+ const int y1 = (y0+1) & blockMask;
+
+ for(int px = 0; px < 4; ++px)
+ {
+ const int xOffset = (px < 2) ? -1 : 0;
+ const int x0 = (x + xOffset) & blockMask;
+ const int x1 = (x0+1) & blockMask;
+
+ const PvrTcPacket* p0 = packets + GetMortonNumber(x0, y0);
+ const PvrTcPacket* p1 = packets + GetMortonNumber(x1, y0);
+ const PvrTcPacket* p2 = packets + GetMortonNumber(x0, y1);
+ const PvrTcPacket* p3 = packets + GetMortonNumber(x1, y1);
+
+ ColorRgb<int> ca = p0->GetColorRgbA() * (*factor)[0] +
+ p1->GetColorRgbA() * (*factor)[1] +
+ p2->GetColorRgbA() * (*factor)[2] +
+ p3->GetColorRgbA() * (*factor)[3];
+
+ ColorRgb<int> cb = p0->GetColorRgbB() * (*factor)[0] +
+ p1->GetColorRgbB() * (*factor)[1] +
+ p2->GetColorRgbB() * (*factor)[2] +
+ p3->GetColorRgbB() * (*factor)[3];
+
+ const ColorRgb<unsigned char>& pixel = data[py*size + px];
+ ColorRgb<int> d = cb - ca;
+ ColorRgb<int> p;
+ p.r=pixel.r*16;
+ p.g=pixel.g*16;
+ p.b=pixel.b*16;
+ ColorRgb<int> v = p - ca;
+
+ // PVRTC uses weightings of 0, 3/8, 5/8 and 1
+ // The boundaries for these are 3/16, 1/2 (=8/16), 13/16
+ int projection = (v % d) * 16;
+ int lengthSquared = d % d;
+ if(projection > 3*lengthSquared) modulationData++;
+ if(projection > 8*lengthSquared) modulationData++;
+ if(projection > 13*lengthSquared) modulationData++;
+
+ modulationData = BitUtility::RotateRight(modulationData, 2);
+
+ factor++;
+ }
+ }
+
+ PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+ packet->modulationData = modulationData;
+ }
+ }
+}
+
+//============================================================================
+
+static void CalculateBoundingBox(ColorRgbBoundingBox& cbb, const RgbaBitmap& bitmap, int blockX, int blockY)
+{
+ int size = bitmap.GetBitmapWidth();
+ const ColorRgba<unsigned char>* data = bitmap.GetData() + blockY * 4 * size + blockX * 4;
+
+ cbb.min = data[0];
+ cbb.max = data[0];
+
+ cbb |= data[1];
+ cbb |= data[2];
+ cbb |= data[3];
+
+ cbb |= data[size];
+ cbb |= data[size+1];
+ cbb |= data[size+2];
+ cbb |= data[size+3];
+
+ cbb |= data[2*size];
+ cbb |= data[2*size+1];
+ cbb |= data[2*size+2];
+ cbb |= data[2*size+3];
+
+ cbb |= data[3*size];
+ cbb |= data[3*size+1];
+ cbb |= data[3*size+2];
+ cbb |= data[3*size+3];
+}
+
+void PvrTcEncoder::EncodeRgb4Bpp(void* result, const RgbaBitmap& bitmap)
+{
+ assert(bitmap.GetBitmapWidth() == bitmap.GetBitmapHeight());
+ assert(BitUtility::IsPowerOf2(bitmap.GetBitmapWidth()));
+ const int size = bitmap.GetBitmapWidth();
+ const int blocks = size / 4;
+ const int blockMask = blocks-1;
+
+ PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
+
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ ColorRgbBoundingBox cbb;
+ CalculateBoundingBox(cbb, bitmap, x, y);
+ PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+ packet->usePunchthroughAlpha = 0;
+ packet->SetColorA(cbb.min);
+ packet->SetColorB(cbb.max);
+ }
+ }
+
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ const unsigned char (*factor)[4] = PvrTcPacket::BILINEAR_FACTORS;
+ const ColorRgba<unsigned char>* data = bitmap.GetData() + y * 4 * size + x * 4;
+
+ uint32_t modulationData = 0;
+
+ for(int py = 0; py < 4; ++py)
+ {
+ const int yOffset = (py < 2) ? -1 : 0;
+ const int y0 = (y + yOffset) & blockMask;
+ const int y1 = (y0+1) & blockMask;
+
+ for(int px = 0; px < 4; ++px)
+ {
+ const int xOffset = (px < 2) ? -1 : 0;
+ const int x0 = (x + xOffset) & blockMask;
+ const int x1 = (x0+1) & blockMask;
+
+ const PvrTcPacket* p0 = packets + GetMortonNumber(x0, y0);
+ const PvrTcPacket* p1 = packets + GetMortonNumber(x1, y0);
+ const PvrTcPacket* p2 = packets + GetMortonNumber(x0, y1);
+ const PvrTcPacket* p3 = packets + GetMortonNumber(x1, y1);
+
+ ColorRgb<int> ca = p0->GetColorRgbA() * (*factor)[0] +
+ p1->GetColorRgbA() * (*factor)[1] +
+ p2->GetColorRgbA() * (*factor)[2] +
+ p3->GetColorRgbA() * (*factor)[3];
+
+ ColorRgb<int> cb = p0->GetColorRgbB() * (*factor)[0] +
+ p1->GetColorRgbB() * (*factor)[1] +
+ p2->GetColorRgbB() * (*factor)[2] +
+ p3->GetColorRgbB() * (*factor)[3];
+
+ const ColorRgb<unsigned char>& pixel = data[py*size + px];
+ ColorRgb<int> d = cb - ca;
+ ColorRgb<int> p;
+ p.r=pixel.r*16;
+ p.g=pixel.g*16;
+ p.b=pixel.b*16;
+ ColorRgb<int> v = p - ca;
+
+ // PVRTC uses weightings of 0, 3/8, 5/8 and 1
+ // The boundaries for these are 3/16, 1/2 (=8/16), 13/16
+ int projection = (v % d) * 16;
+ int lengthSquared = d % d;
+ if(projection > 3*lengthSquared) modulationData++;
+ if(projection > 8*lengthSquared) modulationData++;
+ if(projection > 13*lengthSquared) modulationData++;
+
+ modulationData = BitUtility::RotateRight(modulationData, 2);
+
+ factor++;
+ }
+ }
+
+ PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+ packet->modulationData = modulationData;
+ }
+ }
+}
+
+//============================================================================
+
+typedef Interval<ColorRgba<unsigned char> > ColorRgbaBoundingBox;
+
+static void CalculateBoundingBox(ColorRgbaBoundingBox& cbb, const RgbaBitmap& bitmap, int blockX, int blockY)
+{
+ int size = bitmap.GetBitmapWidth();
+ const ColorRgba<unsigned char>* data = bitmap.GetData() + blockY * 4 * size + blockX * 4;
+
+ cbb.min = data[0];
+ cbb.max = data[0];
+
+ cbb |= data[1];
+ cbb |= data[2];
+ cbb |= data[3];
+
+ cbb |= data[size];
+ cbb |= data[size+1];
+ cbb |= data[size+2];
+ cbb |= data[size+3];
+
+ cbb |= data[2*size];
+ cbb |= data[2*size+1];
+ cbb |= data[2*size+2];
+ cbb |= data[2*size+3];
+
+ cbb |= data[3*size];
+ cbb |= data[3*size+1];
+ cbb |= data[3*size+2];
+ cbb |= data[3*size+3];
+}
+
+void PvrTcEncoder::EncodeRgba4Bpp(void* result, const RgbaBitmap& bitmap)
+{
+ assert(bitmap.GetBitmapWidth() == bitmap.GetBitmapHeight());
+ assert(BitUtility::IsPowerOf2(bitmap.GetBitmapWidth()));
+ const int size = bitmap.GetBitmapWidth();
+ const int blocks = size / 4;
+ const int blockMask = blocks-1;
+
+ PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
+
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ ColorRgbaBoundingBox cbb;
+ CalculateBoundingBox(cbb, bitmap, x, y);
+ PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+ packet->usePunchthroughAlpha = 0;
+ packet->SetColorA(cbb.min);
+ packet->SetColorB(cbb.max);
+ }
+ }
+
+ for(int y = 0; y < blocks; ++y)
+ {
+ for(int x = 0; x < blocks; ++x)
+ {
+ const unsigned char (*factor)[4] = PvrTcPacket::BILINEAR_FACTORS;
+ const ColorRgba<unsigned char>* data = bitmap.GetData() + y * 4 * size + x * 4;
+
+ uint32_t modulationData = 0;
+
+ for(int py = 0; py < 4; ++py)
+ {
+ const int yOffset = (py < 2) ? -1 : 0;
+ const int y0 = (y + yOffset) & blockMask;
+ const int y1 = (y0+1) & blockMask;
+
+ for(int px = 0; px < 4; ++px)
+ {
+ const int xOffset = (px < 2) ? -1 : 0;
+ const int x0 = (x + xOffset) & blockMask;
+ const int x1 = (x0+1) & blockMask;
+
+ const PvrTcPacket* p0 = packets + GetMortonNumber(x0, y0);
+ const PvrTcPacket* p1 = packets + GetMortonNumber(x1, y0);
+ const PvrTcPacket* p2 = packets + GetMortonNumber(x0, y1);
+ const PvrTcPacket* p3 = packets + GetMortonNumber(x1, y1);
+
+ ColorRgba<int> ca = p0->GetColorRgbaA() * (*factor)[0] +
+ p1->GetColorRgbaA() * (*factor)[1] +
+ p2->GetColorRgbaA() * (*factor)[2] +
+ p3->GetColorRgbaA() * (*factor)[3];
+
+ ColorRgba<int> cb = p0->GetColorRgbaB() * (*factor)[0] +
+ p1->GetColorRgbaB() * (*factor)[1] +
+ p2->GetColorRgbaB() * (*factor)[2] +
+ p3->GetColorRgbaB() * (*factor)[3];
+
+ const ColorRgba<unsigned char>& pixel = data[py*size + px];
+ ColorRgba<int> d = cb - ca;
+ ColorRgba<int> p;
+ p.r=pixel.r*16;
+ p.g=pixel.g*16;
+ p.b=pixel.b*16;
+ p.a=pixel.a*16;
+ ColorRgba<int> v = p - ca;
+
+ // PVRTC uses weightings of 0, 3/8, 5/8 and 1
+ // The boundaries for these are 3/16, 1/2 (=8/16), 13/16
+ int projection = (v % d) * 16;
+ int lengthSquared = d % d;
+ if(projection > 3*lengthSquared) modulationData++;
+ if(projection > 8*lengthSquared) modulationData++;
+ if(projection > 13*lengthSquared) modulationData++;
+
+ modulationData = BitUtility::RotateRight(modulationData, 2);
+
+ factor++;
+ }
+ }
+
+ PvrTcPacket* packet = packets + GetMortonNumber(x, y);
+ packet->modulationData = modulationData;
+ }
+ }
+}
+
+//============================================================================
diff --git a/drivers/pvr/PvrTcEncoder.h b/drivers/pvr/PvrTcEncoder.h
new file mode 100644
index 0000000000..b9344367d9
--- /dev/null
+++ b/drivers/pvr/PvrTcEncoder.h
@@ -0,0 +1,40 @@
+//============================================================================
+
+#pragma once
+#include "ColorRgba.h"
+
+//============================================================================
+
+namespace Javelin
+{
+//============================================================================
+
+ class AlphaBitmap;
+ class RgbBitmap;
+ class RgbaBitmap;
+
+ class PvrTcEncoder
+ {
+ public:
+ // Result must be large enough for bitmap.GetArea()/4 bytes
+ static void EncodeAlpha2Bpp(void* result, const AlphaBitmap& bitmap);
+
+ // Result must be large enough for bitmap.GetArea()/2 bytes
+ static void EncodeAlpha4Bpp(void* result, const AlphaBitmap& bitmap);
+
+ // Result must be large enough for bitmap.GetArea()/2 bytes
+ static void EncodeRgb4Bpp(void* result, const RgbBitmap& bitmap);
+
+ // Result must be large enough for bitmap.GetArea()/2 bytes
+ static void EncodeRgb4Bpp(void* result, const RgbaBitmap& bitmap);
+
+ // Result must be large enough for bitmap.GetArea()/2 bytes
+ static void EncodeRgba4Bpp(void* result, const RgbaBitmap& bitmap);
+
+ private:
+ static unsigned GetMortonNumber(int x, int y);
+ };
+
+//============================================================================
+}
+//============================================================================
diff --git a/drivers/pvr/PvrTcPacket.cpp b/drivers/pvr/PvrTcPacket.cpp
new file mode 100644
index 0000000000..2e40d371e8
--- /dev/null
+++ b/drivers/pvr/PvrTcPacket.cpp
@@ -0,0 +1,209 @@
+//============================================================================
+
+#include "PvrTcPacket.h"
+#include "BitScale.h"
+
+//============================================================================
+
+using namespace Javelin;
+
+//============================================================================
+
+const unsigned char PvrTcPacket::BILINEAR_FACTORS[16][4] =
+{
+ { 4, 4, 4, 4 },
+ { 2, 6, 2, 6 },
+ { 8, 0, 8, 0 },
+ { 6, 2, 6, 2 },
+
+ { 2, 2, 6, 6 },
+ { 1, 3, 3, 9 },
+ { 4, 0, 12, 0 },
+ { 3, 1, 9, 3 },
+
+ { 8, 8, 0, 0 },
+ { 4, 12, 0, 0 },
+ { 16, 0, 0, 0 },
+ { 12, 4, 0, 0 },
+
+ { 6, 6, 2, 2 },
+ { 3, 9, 1, 3 },
+ { 12, 0, 4, 0 },
+ { 9, 3, 3, 1 },
+};
+
+// Weights are { colorA, colorB, alphaA, alphaB }
+const unsigned char PvrTcPacket::WEIGHTS[8][4] =
+{
+ // Weights for Mode=0
+ { 8, 0, 8, 0 },
+ { 5, 3, 5, 3 },
+ { 3, 5, 3, 5 },
+ { 0, 8, 0, 8 },
+
+ // Weights for Mode=1
+ { 8, 0, 8, 0 },
+ { 4, 4, 4, 4 },
+ { 4, 4, 0, 0 },
+ { 0, 8, 0, 8 },
+};
+
+//============================================================================
+
+ColorRgb<int> PvrTcPacket::GetColorRgbA() const
+{
+ if(colorAIsOpaque)
+ {
+ unsigned char r = colorA >> 9;
+ unsigned char g = colorA >> 4 & 0x1f;
+ unsigned char b = colorA & 0xf;
+ return ColorRgb<int>(Data::BITSCALE_5_TO_8[r],
+ Data::BITSCALE_5_TO_8[g],
+ Data::BITSCALE_4_TO_8[b]);
+ }
+ else
+ {
+ unsigned char r = (colorA >> 7) & 0xf;
+ unsigned char g = (colorA >> 3) & 0xf;
+ unsigned char b = colorA & 7;
+ return ColorRgb<int>(Data::BITSCALE_4_TO_8[r],
+ Data::BITSCALE_4_TO_8[g],
+ Data::BITSCALE_3_TO_8[b]);
+ }
+}
+
+ColorRgb<int> PvrTcPacket::GetColorRgbB() const
+{
+ if(colorBIsOpaque)
+ {
+ unsigned char r = colorB >> 10;
+ unsigned char g = colorB >> 5 & 0x1f;
+ unsigned char b = colorB & 0x1f;
+ return ColorRgb<int>(Data::BITSCALE_5_TO_8[r],
+ Data::BITSCALE_5_TO_8[g],
+ Data::BITSCALE_5_TO_8[b]);
+ }
+ else
+ {
+ unsigned char r = colorB >> 8 & 0xf;
+ unsigned char g = colorB >> 4 & 0xf;
+ unsigned char b = colorB & 0xf;
+ return ColorRgb<int>(Data::BITSCALE_4_TO_8[r],
+ Data::BITSCALE_4_TO_8[g],
+ Data::BITSCALE_4_TO_8[b]);
+ }
+}
+
+ColorRgba<int> PvrTcPacket::GetColorRgbaA() const
+{
+ if(colorAIsOpaque)
+ {
+ unsigned char r = colorA >> 9;
+ unsigned char g = colorA >> 4 & 0x1f;
+ unsigned char b = colorA & 0xf;
+ return ColorRgba<int>(Data::BITSCALE_5_TO_8[r],
+ Data::BITSCALE_5_TO_8[g],
+ Data::BITSCALE_4_TO_8[b],
+ 255);
+ }
+ else
+ {
+ unsigned char a = colorA >> 11 & 7;
+ unsigned char r = colorA >> 7 & 0xf;
+ unsigned char g = colorA >> 3 & 0xf;
+ unsigned char b = colorA & 7;
+ return ColorRgba<int>(Data::BITSCALE_4_TO_8[r],
+ Data::BITSCALE_4_TO_8[g],
+ Data::BITSCALE_3_TO_8[b],
+ Data::BITSCALE_3_TO_8[a]);
+ }
+}
+
+ColorRgba<int> PvrTcPacket::GetColorRgbaB() const
+{
+ if(colorBIsOpaque)
+ {
+ unsigned char r = colorB >> 10;
+ unsigned char g = colorB >> 5 & 0x1f;
+ unsigned char b = colorB & 0x1f;
+ return ColorRgba<int>(Data::BITSCALE_5_TO_8[r],
+ Data::BITSCALE_5_TO_8[g],
+ Data::BITSCALE_5_TO_8[b],
+ 255);
+ }
+ else
+ {
+ unsigned char a = colorB >> 12 & 7;
+ unsigned char r = colorB >> 8 & 0xf;
+ unsigned char g = colorB >> 4 & 0xf;
+ unsigned char b = colorB & 0xf;
+ return ColorRgba<int>(Data::BITSCALE_4_TO_8[r],
+ Data::BITSCALE_4_TO_8[g],
+ Data::BITSCALE_4_TO_8[b],
+ Data::BITSCALE_3_TO_8[a]);
+ }
+}
+
+//============================================================================
+
+void PvrTcPacket::SetColorA(const ColorRgb<unsigned char>& c)
+{
+ int r = Data::BITSCALE_8_TO_5_FLOOR[c.r];
+ int g = Data::BITSCALE_8_TO_5_FLOOR[c.g];
+ int b = Data::BITSCALE_8_TO_4_FLOOR[c.b];
+ colorA = r<<9 | g<<4 | b;
+ colorAIsOpaque = true;
+}
+
+void PvrTcPacket::SetColorB(const ColorRgb<unsigned char>& c)
+{
+ int r = Data::BITSCALE_8_TO_5_CEIL[c.r];
+ int g = Data::BITSCALE_8_TO_5_CEIL[c.g];
+ int b = Data::BITSCALE_8_TO_5_CEIL[c.b];
+ colorB = r<<10 | g<<5 | b;
+ colorBIsOpaque = true;
+}
+
+void PvrTcPacket::SetColorA(const ColorRgba<unsigned char>& c)
+{
+ int a = Data::BITSCALE_8_TO_3_FLOOR[c.a];
+ if(a == 7)
+ {
+ int r = Data::BITSCALE_8_TO_5_FLOOR[c.r];
+ int g = Data::BITSCALE_8_TO_5_FLOOR[c.g];
+ int b = Data::BITSCALE_8_TO_4_FLOOR[c.b];
+ colorA = r<<9 | g<<4 | b;
+ colorAIsOpaque = true;
+ }
+ else
+ {
+ int r = Data::BITSCALE_8_TO_4_FLOOR[c.r];
+ int g = Data::BITSCALE_8_TO_4_FLOOR[c.g];
+ int b = Data::BITSCALE_8_TO_3_FLOOR[c.b];
+ colorA = a<<11 | r<<7 | g<<3 | b;
+ colorAIsOpaque = false;
+ }
+}
+
+void PvrTcPacket::SetColorB(const ColorRgba<unsigned char>& c)
+{
+ int a = Data::BITSCALE_8_TO_3_CEIL[c.a];
+ if(a == 7)
+ {
+ int r = Data::BITSCALE_8_TO_5_CEIL[c.r];
+ int g = Data::BITSCALE_8_TO_5_CEIL[c.g];
+ int b = Data::BITSCALE_8_TO_5_CEIL[c.b];
+ colorB = r<<10 | g<<5 | b;
+ colorBIsOpaque = true;
+ }
+ else
+ {
+ int r = Data::BITSCALE_8_TO_4_CEIL[c.r];
+ int g = Data::BITSCALE_8_TO_4_CEIL[c.g];
+ int b = Data::BITSCALE_8_TO_4_CEIL[c.b];
+ colorB = a<<12 | r<<8 | g<<4 | b;
+ colorBIsOpaque = false;
+ }
+}
+
+//============================================================================
diff --git a/drivers/pvr/PvrTcPacket.h b/drivers/pvr/PvrTcPacket.h
new file mode 100644
index 0000000000..ac3b6a4dd1
--- /dev/null
+++ b/drivers/pvr/PvrTcPacket.h
@@ -0,0 +1,65 @@
+//============================================================================
+//
+// Modulation data specifies weightings of colorA to colorB for each pixel
+//
+// For mode = 0
+// 00: 0/8
+// 01: 3/8
+// 10: 5/8
+// 11: 8/8
+//
+// For mode = 1
+// 00: 0/8
+// 01: 4/8
+// 10: 4/8 with alpha punchthrough
+// 11: 8/8
+//
+// For colorIsOpaque=0
+// 3 bits A
+// 4 bits R
+// 4 bits G
+// 3/4 bits B
+//
+// For colorIsOpaque=1
+// 5 bits R
+// 5 bits G
+// 4/5 bits B
+//
+//============================================================================
+
+#pragma once
+#include "ColorRgba.h"
+
+//============================================================================
+
+namespace Javelin
+{
+//============================================================================
+
+ struct PvrTcPacket
+ {
+ unsigned int modulationData;
+ unsigned usePunchthroughAlpha : 1;
+ unsigned colorA : 14;
+ unsigned colorAIsOpaque : 1;
+ unsigned colorB : 15;
+ unsigned colorBIsOpaque : 1;
+
+ ColorRgb<int> GetColorRgbA() const;
+ ColorRgb<int> GetColorRgbB() const;
+ ColorRgba<int> GetColorRgbaA() const;
+ ColorRgba<int> GetColorRgbaB() const;
+
+ void SetColorA(const ColorRgb<unsigned char>& c);
+ void SetColorB(const ColorRgb<unsigned char>& c);
+
+ void SetColorA(const ColorRgba<unsigned char>& c);
+ void SetColorB(const ColorRgba<unsigned char>& c);
+
+ static const unsigned char BILINEAR_FACTORS[16][4];
+ static const unsigned char WEIGHTS[8][4];
+ };
+
+//============================================================================
+} // namespace Javelin
+//============================================================================
diff --git a/drivers/pvr/RgbBitmap.h b/drivers/pvr/RgbBitmap.h
new file mode 100644
index 0000000000..cf1d78667d
--- /dev/null
+++ b/drivers/pvr/RgbBitmap.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "Bitmap.h"
+#include "ColorRgba.h"
+
+namespace Javelin {
+
+class RgbBitmap : public Bitmap {
+public:
+ RgbBitmap(int w, int h)
+ : Bitmap(w, h, 3) {
+ }
+
+ const ColorRgb<unsigned char> *GetData() const {
+ return reinterpret_cast<ColorRgb<unsigned char> *>(data);
+ }
+
+ ColorRgb<unsigned char> *GetData() {
+ return reinterpret_cast<ColorRgb<unsigned char> *>(data);
+ }
+};
+
+}
diff --git a/drivers/pvr/RgbaBitmap.h b/drivers/pvr/RgbaBitmap.h
new file mode 100644
index 0000000000..66b5542c1a
--- /dev/null
+++ b/drivers/pvr/RgbaBitmap.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "ColorRgba.h"
+#include "Bitmap.h"
+
+namespace Javelin {
+
+class RgbaBitmap : public Bitmap {
+public:
+ RgbaBitmap(int w, int h)
+ : Bitmap(w, h, 4) {
+ }
+
+ const ColorRgba<unsigned char> *GetData() const {
+ return reinterpret_cast<ColorRgba<unsigned char> *>(data);
+ }
+
+ ColorRgba<unsigned char> *GetData() {
+ return reinterpret_cast<ColorRgba<unsigned char> *>(data);
+ }
+};
+
+}
diff --git a/drivers/pvr/SCsub b/drivers/pvr/SCsub
index bd4c6f3f88..44b8c3d6bb 100644
--- a/drivers/pvr/SCsub
+++ b/drivers/pvr/SCsub
@@ -2,10 +2,14 @@ Import('env')
pvr_sources = [
+ "pvr/BitScale.cpp",
+ "pvr/MortonTable.cpp",
+ "pvr/PvrTcDecoder.cpp",
+ "pvr/PvrTcEncoder.cpp",
+ "pvr/PvrTcPacket.cpp",
"pvr/texture_loader_pvr.cpp"
]
env.drivers_sources+=pvr_sources
#env.add_source_files(env.drivers_sources, pvr_sources)
-
diff --git a/drivers/pvr/texture_loader_pvr.cpp b/drivers/pvr/texture_loader_pvr.cpp
index b12e0c28b8..eb67dad8cf 100644
--- a/drivers/pvr/texture_loader_pvr.cpp
+++ b/drivers/pvr/texture_loader_pvr.cpp
@@ -1,6 +1,8 @@
#include "texture_loader_pvr.h"
#include "os/file_access.h"
#include <string.h>
+#include "PvrTcEncoder.h"
+#include "RgbaBitmap.h"
static void _pvrtc_decompress(Image* p_img);
@@ -20,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);
@@ -32,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();
@@ -133,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;
}
@@ -154,10 +163,59 @@ String ResourceFormatPVR::get_resource_type(const String &p_path) const {
}
+
+static void _compress_pvrtc4(Image * p_img) {
+
+ Image img = *p_img;
+
+ bool make_mipmaps=false;
+ if (img.get_width()%8 || img.get_height()%8) {
+ make_mipmaps=img.get_mipmaps()>0;
+ img.resize(img.get_width()+(8-(img.get_width()%8)),img.get_height()+(8-(img.get_height()%8)));
+ }
+ img.convert(Image::FORMAT_RGBA);
+ if (img.get_mipmaps()==0 && make_mipmaps)
+ img.generate_mipmaps();
+
+ bool use_alpha=img.detect_alpha();
+
+ Image new_img;
+ new_img.create(img.get_width(),img.get_height(),true,use_alpha?Image::FORMAT_PVRTC4_ALPHA:Image::FORMAT_PVRTC4);
+ DVector<uint8_t> data=new_img.get_data();
+ {
+ DVector<uint8_t>::Write wr=data.write();
+ DVector<uint8_t>::Read r=img.get_data().read();
+
+
+ for(int i=0;i<=new_img.get_mipmaps();i++) {
+
+ int ofs,size,w,h;
+ img.get_mipmap_offset_size_and_dimensions(i,ofs,size,w,h);
+ Javelin::RgbaBitmap bm(w,h);
+ copymem(bm.GetData(),&r[ofs],size);
+ {
+ Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
+ for(int j=0;j<size/4;j++) {
+ SWAP(dp[j].r,dp[j].b);
+ }
+ }
+
+ new_img.get_mipmap_offset_size_and_dimensions(i,ofs,size,w,h);
+ Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs],bm);
+ }
+
+ }
+
+ *p_img = Image(new_img.get_width(),new_img.get_height(),new_img.get_mipmaps(),new_img.get_format(),data);
+
+}
+
ResourceFormatPVR::ResourceFormatPVR() {
Image::_image_decompress_pvrtc=_pvrtc_decompress;
+ Image::_image_compress_pvrtc4_func=_compress_pvrtc4;
+ Image::_image_compress_pvrtc2_func=_compress_pvrtc4;
}
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 e2af1e5336..11c4e7dd29 100644
--- a/drivers/register_driver_types.cpp
+++ b/drivers/register_driver_types.cpp
@@ -29,6 +29,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,6 +42,9 @@
#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"
@@ -46,7 +54,8 @@
#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"
@@ -83,6 +92,10 @@ 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
@@ -166,6 +179,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 );
@@ -207,6 +225,7 @@ void register_driver_types() {
ObjectTypeDB::register_type<VideoStreamTheora>();
#endif
+
#ifdef TOOLS_ENABLED
#ifdef SQUISH_ENABLED
@@ -215,7 +234,10 @@ void register_driver_types() {
#endif
#endif
+#ifdef ETC1_ENABLED
_register_etc1_compress_func();
+#endif
+
initialize_chibi();
}
@@ -229,15 +251,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);
#endif
+
#ifdef MUSEPACK_ENABLED
memdelete (mpc_stream_loader);
diff --git a/drivers/rtaudio/RtAudio.cpp b/drivers/rtaudio/RtAudio.cpp
index 883c3a82d1..72ca836907 100644
--- a/drivers/rtaudio/RtAudio.cpp
+++ b/drivers/rtaudio/RtAudio.cpp
@@ -6,12 +6,12 @@
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 and ASIO) operating systems.
+ (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-2009 Gary P. Scavone
+ 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
@@ -39,13 +39,14 @@
*/
/************************************************************************/
-// RtAudio: Version 4.0.6
+// RtAudio: Version 4.1.1
#include "RtAudio.h"
#include <iostream>
#include <cstdlib>
#include <cstring>
-#include <limits.h>
+#include <climits>
+#include <algorithm>
// Static variable definitions.
const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
@@ -54,12 +55,32 @@ const unsigned int RtApi::SAMPLE_RATES[] = {
32000, 44100, 48000, 88200, 96000, 176400, 192000
};
-#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
+#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)
-#elif defined(__LINUX_ALSA__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
+
+ #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)
@@ -76,6 +97,11 @@ const unsigned int RtApi::SAMPLE_RATES[] = {
//
// *************************************************** //
+std::string RtAudio :: getVersion( void ) throw()
+{
+ return RTAUDIO_VERSION;
+}
+
void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()
{
apis.clear();
@@ -88,12 +114,18 @@ void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()
#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
@@ -107,6 +139,10 @@ void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()
void RtAudio :: openRtApi( RtAudio::Api api )
{
+ if ( rtapi_ )
+ delete rtapi_;
+ rtapi_ = 0;
+
#if defined(__UNIX_JACK__)
if ( api == UNIX_JACK )
rtapi_ = new RtApiJack();
@@ -115,6 +151,10 @@ void RtAudio :: openRtApi( RtAudio::Api api )
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();
@@ -123,6 +163,10 @@ void RtAudio :: openRtApi( RtAudio::Api api )
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();
@@ -137,7 +181,7 @@ void RtAudio :: openRtApi( RtAudio::Api api )
#endif
}
-RtAudio :: RtAudio( RtAudio::Api api ) throw()
+RtAudio :: RtAudio( RtAudio::Api api )
{
rtapi_ = 0;
@@ -157,7 +201,7 @@ RtAudio :: RtAudio( RtAudio::Api api ) throw()
getCompiledApi( apis );
for ( unsigned int i=0; i<apis.size(); i++ ) {
openRtApi( apis[i] );
- if ( rtapi_->getDeviceCount() ) break;
+ if ( rtapi_ && rtapi_->getDeviceCount() ) break;
}
if ( rtapi_ ) return;
@@ -165,13 +209,15 @@ RtAudio :: RtAudio( RtAudio::Api api ) throw()
// 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 print out an error message.
- std::cerr << "\nRtAudio: no compiled API support found ... critical error!!\n\n";
+ // 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_;
+ if ( rtapi_ )
+ delete rtapi_;
}
void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
@@ -179,11 +225,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames,
RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options )
+ RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback )
{
return rtapi_->openStream( outputParameters, inputParameters, format,
sampleRate, bufferFrames, callback,
- userData, options );
+ userData, options, errorCallback );
}
// *************************************************** //
@@ -202,6 +249,7 @@ RtApi :: RtApi()
stream_.userBuffer[1] = 0;
MUTEX_INITIALIZE( &stream_.mutex );
showWarnings_ = true;
+ firstErrorOccurred_ = false;
}
RtApi :: ~RtApi()
@@ -214,31 +262,40 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames,
RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options )
+ RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback )
{
if ( stream_.state != STREAM_CLOSED ) {
errorText_ = "RtApi::openStream: a stream is already open!";
- error( RtError::INVALID_USE );
+ 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( RtError::INVALID_USE );
+ 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( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return;
}
if ( oParams == NULL && iParams == NULL ) {
errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return;
}
if ( formatBytes(format) == 0 ) {
errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return;
}
unsigned int nDevices = getDeviceCount();
@@ -247,7 +304,8 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
oChannels = oParams->nChannels;
if ( oParams->deviceId >= nDevices ) {
errorText_ = "RtApi::openStream: output device parameter value is invalid.";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return;
}
}
@@ -256,18 +314,21 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
iChannels = iParams->nChannels;
if ( iParams->deviceId >= nDevices ) {
errorText_ = "RtApi::openStream: input device parameter value is invalid.";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return;
}
}
- clearStreamInfo();
bool result;
if ( oChannels > 0 ) {
result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,
sampleRate, format, bufferFrames, options );
- if ( result == false ) error( RtError::SYSTEM_ERROR );
+ if ( result == false ) {
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
}
if ( iChannels > 0 ) {
@@ -276,12 +337,14 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
sampleRate, format, bufferFrames, options );
if ( result == false ) {
if ( oChannels > 0 ) closeStream();
- error( RtError::SYSTEM_ERROR );
+ 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;
@@ -305,10 +368,10 @@ void RtApi :: closeStream( void )
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 )
+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;
@@ -363,6 +426,14 @@ double RtApi :: getStreamTime( void )
#endif
}
+void RtApi :: setStreamTime( double time )
+{
+ verifyStream();
+
+ if ( time >= 0.0 )
+ stream_.streamTime = time;
+}
+
unsigned int RtApi :: getStreamSampleRate( void )
{
verifyStream();
@@ -393,12 +464,6 @@ unsigned int RtApi :: getStreamSampleRate( void )
// 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.
-//
-// The mechanism for querying and setting system parameters was
-// updated (and perhaps simplified) in OS-X version 10.4. However,
-// since 10.4 support is not necessarily available to all users, I've
-// decided not to update the respective code at this time. Perhaps
-// this will happen when Apple makes 10.4 free for everyone. :-)
// A structure to hold various information related to the CoreAudio API
// implementation.
@@ -419,9 +484,23 @@ struct 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()
+RtApiCore:: RtApiCore()
{
- // Nothing to do here.
+#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()
@@ -436,10 +515,11 @@ unsigned int RtApiCore :: getDeviceCount( void )
{
// Find out how many audio devices there are, if any.
UInt32 dataSize;
- OSStatus result = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &dataSize, NULL );
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
@@ -453,21 +533,21 @@ unsigned int RtApiCore :: getDefaultInputDevice( void )
AudioDeviceID id;
UInt32 dataSize = sizeof( AudioDeviceID );
- OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice,
- &dataSize, &id );
-
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
dataSize *= nDevices;
AudioDeviceID deviceList[ nDevices ];
- result = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &dataSize, (void *) &deviceList );
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
@@ -475,7 +555,7 @@ unsigned int RtApiCore :: getDefaultInputDevice( void )
if ( id == deviceList[i] ) return i;
errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
@@ -486,21 +566,21 @@ unsigned int RtApiCore :: getDefaultOutputDevice( void )
AudioDeviceID id;
UInt32 dataSize = sizeof( AudioDeviceID );
- OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
- &dataSize, &id );
-
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
- dataSize *= nDevices;
+ dataSize = sizeof( AudioDeviceID ) * nDevices;
AudioDeviceID deviceList[ nDevices ];
- result = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &dataSize, (void *) &deviceList );
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
@@ -508,7 +588,7 @@ unsigned int RtApiCore :: getDefaultOutputDevice( void )
if ( id == deviceList[i] ) return i;
errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
@@ -521,20 +601,26 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
unsigned int nDevices = getDeviceCount();
if ( nDevices == 0 ) {
errorText_ = "RtApiCore::getDeviceInfo: no devices found!";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return info;
}
AudioDeviceID deviceList[ nDevices ];
UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;
- OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &dataSize, (void *) &deviceList );
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -542,42 +628,62 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
// Get the device name.
info.name.erase();
- char name[256];
- dataSize = 256;
- result = AudioDeviceGetProperty( id, 0, false,
- kAudioDevicePropertyDeviceManufacturer,
- &dataSize, name );
-
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
- info.name.append( (const char *)name, strlen(name) );
+
+ //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);
- dataSize = 256;
- result = AudioDeviceGetProperty( id, 0, false,
- kAudioDevicePropertyDeviceName,
- &dataSize, name );
+ 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( RtError::WARNING );
+ 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;
- result = AudioDeviceGetPropertyInfo( id, 0, false,
- kAudioDevicePropertyStreamConfiguration,
- &dataSize, NULL );
- if (result != noErr || dataSize == 0) {
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -585,18 +691,16 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
bufferList = (AudioBufferList *) malloc( dataSize );
if ( bufferList == NULL ) {
errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
- result = AudioDeviceGetProperty( id, 0, false,
- kAudioDevicePropertyStreamConfiguration,
- &dataSize, bufferList );
- if ( result != noErr ) {
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -607,13 +711,12 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
free( bufferList );
// Get the input stream "configuration".
- result = AudioDeviceGetPropertyInfo( id, 0, true,
- kAudioDevicePropertyStreamConfiguration,
- &dataSize, NULL );
- if (result != noErr || dataSize == 0) {
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -621,18 +724,16 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
bufferList = (AudioBufferList *) malloc( dataSize );
if ( bufferList == NULL ) {
errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
- result = AudioDeviceGetProperty( id, 0, true,
- kAudioDevicePropertyStreamConfiguration,
- &dataSize, bufferList );
- if ( result != noErr ) {
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -651,46 +752,70 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
if ( info.outputChannels == 0 ) isInput = true;
// Determine the supported sample rates.
- result = AudioDeviceGetPropertyInfo( id, 0, isInput,
- kAudioDevicePropertyAvailableNominalSampleRates,
- &dataSize, NULL );
-
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
UInt32 nRanges = dataSize / sizeof( AudioValueRange );
AudioValueRange rangeList[ nRanges ];
- result = AudioDeviceGetProperty( id, 0, isInput,
- kAudioDevicePropertyAvailableNominalSampleRates,
- &dataSize, &rangeList );
-
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
- Float64 minimumRate = 100000000.0, maximumRate = 0.0;
+ // 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 < minimumRate ) minimumRate = rangeList[i].mMinimum;
- if ( rangeList[i].mMaximum > maximumRate ) maximumRate = rangeList[i].mMaximum;
+ 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;
+ }
}
- info.sampleRates.clear();
- 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 ( 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -699,22 +824,22 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
// no interest to the client.
info.nativeFormats = RTAUDIO_FLOAT32;
- if ( getDefaultOutputDevice() == device )
- info.isDefaultOutput = true;
- if ( getDefaultInputDevice() == device )
- info.isDefaultInput = true;
+ 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;
}
-OSStatus callbackHandler( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* infoPointer )
+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;
@@ -725,27 +850,36 @@ OSStatus callbackHandler( AudioDeviceID inDevice,
return kAudioHardwareNoError;
}
-OSStatus deviceListener( AudioDeviceID inDevice,
- UInt32 channel,
- Boolean isInput,
- AudioDevicePropertyID propertyID,
- void* handlePointer )
+static OSStatus xrunListener( AudioObjectID /*inDevice*/,
+ UInt32 nAddresses,
+ const AudioObjectPropertyAddress properties[],
+ void* handlePointer )
{
CoreHandle *handle = (CoreHandle *) handlePointer;
- if ( propertyID == kAudioDeviceProcessorOverload ) {
- if ( isInput )
- handle->xrun[1] = true;
- else
- handle->xrun[0] = true;
+ 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 bool hasProperty( AudioDeviceID id, UInt32 channel, bool isInput, AudioDevicePropertyID property )
+static OSStatus rateListener( AudioObjectID inDevice,
+ UInt32 /*nAddresses*/,
+ const AudioObjectPropertyAddress /*properties*/[],
+ void* ratePointer )
{
- OSStatus result = AudioDeviceGetPropertyInfo( id, channel, isInput, property, NULL, NULL );
- return result == 0;
+ 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,
@@ -769,7 +903,11 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
AudioDeviceID deviceList[ nDevices ];
UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;
- OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &dataSize, (void *) &deviceList );
+ 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;
@@ -779,25 +917,19 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// Setup for stream mode.
bool isInput = false;
- if ( mode == INPUT ) isInput = true;
-
- // Set or disable "hog" mode.
- dataSize = sizeof( UInt32 );
- UInt32 doHog = 0;
- if ( options && options->flags & RTAUDIO_HOG_DEVICE ) doHog = 1;
- result = AudioHardwareSetProperty( kAudioHardwarePropertyHogModeIsAllowed, dataSize, &doHog );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting 'hog' state!";
- errorText_ = errorStream_.str();
- return FAILURE;
+ if ( mode == INPUT ) {
+ isInput = true;
+ property.mScope = kAudioDevicePropertyScopeInput;
}
+ else
+ property.mScope = kAudioDevicePropertyScopeOutput;
// Get the stream "configuration".
- AudioBufferList *bufferList;
- result = AudioDeviceGetPropertyInfo( id, 0, isInput,
- kAudioDevicePropertyStreamConfiguration,
- &dataSize, NULL );
- if (result != noErr || dataSize == 0) {
+ 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;
@@ -810,10 +942,8 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
return FAILURE;
}
- result = AudioDeviceGetProperty( id, 0, isInput,
- kAudioDevicePropertyStreamConfiguration,
- &dataSize, bufferList );
- if ( result != noErr ) {
+ 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();
@@ -889,9 +1019,9 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// Determine the buffer size.
AudioValueRange bufferRange;
dataSize = sizeof( AudioValueRange );
- result = AudioDeviceGetProperty( id, 0, isInput,
- kAudioDevicePropertyBufferFrameSizeRange,
- &dataSize, &bufferRange );
+ 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();
@@ -906,9 +1036,8 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// need to make this setting for the master channel.
UInt32 theSize = (UInt32) *bufferSize;
dataSize = sizeof( UInt32 );
- result = AudioDeviceSetProperty( id, NULL, 0, isInput,
- kAudioDevicePropertyBufferFrameSize,
- dataSize, &theSize );
+ 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 << ").";
@@ -928,144 +1057,194 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.bufferSize = *bufferSize;
stream_.nBuffers = 1;
- // Get the stream ID(s) so we can set the stream format. We'll have
- // to do this for each stream.
- AudioStreamID streamIDs[ nStreams ];
- dataSize = nStreams * sizeof( AudioStreamID );
- result = AudioDeviceGetProperty( id, 0, isInput,
- kAudioDevicePropertyStreams,
- &dataSize, &streamIDs );
+ // 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 stream ID(s) for device (" << device << ").";
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";
errorText_ = errorStream_.str();
return FAILURE;
}
- // Now set the stream format. Also, check the physical format of the
- // device and change that if necessary.
- AudioStreamBasicDescription description;
- dataSize = sizeof( AudioStreamBasicDescription );
-
- bool updateFormat;
- for ( UInt32 i=0; i<streamCount; i++ ) {
-
- result = AudioStreamGetProperty( streamIDs[firstStream+i], 0,
- kAudioStreamPropertyVirtualFormat,
- &dataSize, &description );
+ // 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 ) << ") getting stream format for device (" << device << ").";
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener 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.
- updateFormat = false;
- if ( fabs( description.mSampleRate - (double)sampleRate ) > 1.0 ) {
- description.mSampleRate = (double) sampleRate;
- updateFormat = true;
+ 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;
}
- if ( description.mFormatID != kAudioFormatLinearPCM ) {
- description.mFormatID = kAudioFormatLinearPCM;
- updateFormat = true;
+ // 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 );
}
- if ( updateFormat ) {
- result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0,
- kAudioStreamPropertyVirtualFormat,
- 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;
- }
- }
+ // Remove the property listener.
+ AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
- // Now check the physical format.
- result = AudioStreamGetProperty( streamIDs[firstStream+i], 0,
- kAudioStreamPropertyPhysicalFormat,
- &dataSize, &description );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ").";
+ if ( microCounter > 5000000 ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ").";
errorText_ = errorStream_.str();
return FAILURE;
}
+ }
- if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 24 ) {
- description.mFormatID = kAudioFormatLinearPCM;
- AudioStreamBasicDescription testDescription = description;
- unsigned long formatFlags;
+ // 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;
+ }
- // We'll try higher bit rates first and then work our way down.
- testDescription.mBitsPerChannel = 32;
- formatFlags = description.mFormatFlags | kLinearPCMFormatFlagIsFloat & ~kLinearPCMFormatFlagIsSignedInteger;
- testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
- if ( result == noErr ) continue;
+ // 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;
+ }
- testDescription = description;
- testDescription.mBitsPerChannel = 32;
- formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger) & ~kLinearPCMFormatFlagIsFloat;
- testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
- if ( result == noErr ) continue;
+ if ( description.mFormatID != kAudioFormatLinearPCM ) {
+ description.mFormatID = kAudioFormatLinearPCM;
+ updateFormat = true;
+ }
- testDescription = description;
- testDescription.mBitsPerChannel = 24;
- testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
- if ( result == noErr ) continue;
+ 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;
+ }
+ }
- testDescription = description;
- testDescription.mBitsPerChannel = 16;
- testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
- if ( result == noErr ) continue;
+ // 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 = 8;
- testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
+ 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;
}
}
- }
- // Get the stream latency. There can be latency in both the device
- // and the stream. First, attempt to get the device latency on the
- // master channel or the first open channel. Errors that might
- // occur here are not deemed critical.
+ 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.
- // ***** CHECK THIS ***** //
- UInt32 latency, channel = 0;
+ // Get the stream / device latency.
+ UInt32 latency;
dataSize = sizeof( UInt32 );
- AudioDevicePropertyID property = kAudioDevicePropertyLatency;
- if ( hasProperty( id, channel, isInput, property ) == true ) {
- result = AudioDeviceGetProperty( id, channel, isInput, property, &dataSize, &latency );
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
}
}
- // Now try to get the stream latency. For multiple streams, I assume the
- // latency is equal for each.
- result = AudioStreamGetProperty( streamIDs[firstStream], 0, property, &dataSize, &latency );
- if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] += latency;
- else {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream latency for device (" << device << ").";
- errorText_ = errorStream_.str();
- error( RtError::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.
@@ -1127,7 +1306,9 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// 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 *) 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;
@@ -1191,9 +1372,9 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
// Setup the device property listener for over/underload.
- result = AudioDeviceAddPropertyListener( id, 0, isInput,
- kAudioDeviceProcessorOverload,
- deviceListener, (void *) handle );
+ property.mSelector = kAudioDeviceProcessorOverload;
+ property.mScope = kAudioObjectPropertyScopeGlobal;
+ result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );
return SUCCESS;
@@ -1216,6 +1397,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -1223,12 +1405,24 @@ void RtApiCore :: closeStream( void )
{
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiCore::closeStream(): no open stream to close!";
- error( RtError::WARNING );
+ 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 )
@@ -1240,6 +1434,18 @@ void RtApiCore :: closeStream( void )
}
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 )
@@ -1276,12 +1482,10 @@ void RtApiCore :: startStream( void )
verifyStream();
if ( stream_.state == STREAM_RUNNING ) {
errorText_ = "RtApiCore::startStream(): the stream is already running!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
- MUTEX_LOCK( &stream_.mutex );
-
OSStatus result = noErr;
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
@@ -1310,10 +1514,8 @@ void RtApiCore :: startStream( void )
stream_.state = STREAM_RUNNING;
unlock:
- MUTEX_UNLOCK( &stream_.mutex );
-
if ( result == noErr ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiCore :: stopStream( void )
@@ -1321,14 +1523,7 @@ void RtApiCore :: stopStream( void )
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";
- error( RtError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::WARNING );
return;
}
@@ -1337,7 +1532,7 @@ void RtApiCore :: stopStream( void )
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
if ( handle->drainCounter == 0 ) {
- handle->drainCounter = 1;
+ handle->drainCounter = 2;
pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
}
@@ -1362,10 +1557,8 @@ void RtApiCore :: stopStream( void )
stream_.state = STREAM_STOPPED;
unlock:
- MUTEX_UNLOCK( &stream_.mutex );
-
if ( result == noErr ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiCore :: abortStream( void )
@@ -1373,24 +1566,38 @@ void RtApiCore :: abortStream( void )
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
- handle->drainCounter = 1;
+ 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 ) return SUCCESS;
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return FAILURE;
}
@@ -1399,18 +1606,13 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
// Check if we were draining the stream and signal is finished.
if ( handle->drainCounter > 3 ) {
- if ( handle->internalDrain == false )
- pthread_cond_signal( &handle->condition );
- else
- stopStream();
- return SUCCESS;
- }
-
- MUTEX_LOCK( &stream_.mutex );
+ ThreadHandle threadId;
- // The state might change while waiting on a mutex.
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
+ 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;
}
@@ -1431,15 +1633,19 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
status |= RTAUDIO_INPUT_OVERFLOW;
handle->xrun[1] = false;
}
- handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, info->userData );
- if ( handle->drainCounter == 2 ) {
- MUTEX_UNLOCK( &stream_.mutex );
+
+ 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 ( handle->drainCounter == 1 )
+ else if ( cbReturnValue == 1 ) {
+ handle->drainCounter = 1;
handle->internalDrain = true;
+ }
}
if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) {
@@ -1539,11 +1745,12 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
}
}
}
+ }
- if ( handle->drainCounter ) {
- handle->drainCounter++;
- goto unlock;
- }
+ // Don't bother draining input
+ if ( handle->drainCounter ) {
+ handle->drainCounter++;
+ goto unlock;
}
AudioDeviceID inputDevice;
@@ -1637,7 +1844,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
}
unlock:
- MUTEX_UNLOCK( &stream_.mutex );
+ //MUTEX_UNLOCK( &stream_.mutex );
RtApi::tickStreamTime();
return SUCCESS;
@@ -1721,6 +1928,7 @@ const char* RtApiCore :: getErrorCode( OSStatus code )
#include <jack/jack.h>
#include <unistd.h>
+#include <cstdio>
// A structure to hold various information related to the Jack API
// implementation.
@@ -1737,7 +1945,7 @@ struct JackHandle {
:client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }
};
-void jackSilentError( const char * ) {};
+static void jackSilentError( const char * ) {};
RtApiJack :: RtApiJack()
{
@@ -1756,7 +1964,7 @@ RtApiJack :: ~RtApiJack()
unsigned int RtApiJack :: getDeviceCount( void )
{
// See if we can become a jack client.
- jack_options_t options = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption;
+ 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;
@@ -1791,12 +1999,12 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
RtAudio::DeviceInfo info;
info.probed = false;
- jack_options_t options = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -1823,13 +2031,17 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
}
if ( device >= nDevices ) {
+ jack_client_close( client );
errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return info;
}
// Get the current jack server sample rate.
info.sampleRates.clear();
- info.sampleRates.push_back( jack_get_sample_rate( client ) );
+
+ 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.
@@ -1853,7 +2065,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
if ( info.outputChannels == 0 && info.inputChannels == 0 ) {
jack_client_close(client);
errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -1875,7 +2087,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
return info;
}
-int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
+static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;
@@ -1885,7 +2097,20 @@ int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
return 0;
}
-void jackShutdown( void *infoPointer )
+// 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;
@@ -1897,11 +2122,12 @@ void jackShutdown( void *infoPointer )
// other problem occurred and we should close the stream.
if ( object->isStreamRunning() == false ) return;
- object->closeStream();
+ 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;
}
-int jackXrun( void *infoPointer )
+static int jackXrun( void *infoPointer )
{
JackHandle *handle = (JackHandle *) infoPointer;
@@ -1921,7 +2147,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// 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 | JackUseExactName ); //JackNullOption;
+ 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 );
@@ -1929,7 +2155,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
client = jack_client_open( "RtApiJack", jackoptions, status );
if ( client == 0 ) {
errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return FAILURE;
}
}
@@ -1995,8 +2221,17 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// Get the latency of the JACK port.
ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
- if ( ports[ firstChannel ] )
- stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );
+ 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.
@@ -2157,7 +2392,7 @@ void RtApiJack :: closeStream( void )
{
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiJack::closeStream(): no open stream to close!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -2199,12 +2434,10 @@ void RtApiJack :: startStream( void )
verifyStream();
if ( stream_.state == STREAM_RUNNING ) {
errorText_ = "RtApiJack::startStream(): the stream is already running!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
- MUTEX_LOCK(&stream_.mutex);
-
JackHandle *handle = (JackHandle *) stream_.apiHandle;
int result = jack_activate( handle->client );
if ( result ) {
@@ -2266,10 +2499,8 @@ void RtApiJack :: startStream( void )
stream_.state = STREAM_RUNNING;
unlock:
- MUTEX_UNLOCK(&stream_.mutex);
-
if ( result == 0 ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiJack :: stopStream( void )
@@ -2277,14 +2508,7 @@ void RtApiJack :: stopStream( void )
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";
- error( RtError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::WARNING );
return;
}
@@ -2292,15 +2516,13 @@ void RtApiJack :: stopStream( void )
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
if ( handle->drainCounter == 0 ) {
- handle->drainCounter = 1;
+ handle->drainCounter = 2;
pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
}
}
jack_deactivate( handle->client );
stream_.state = STREAM_STOPPED;
-
- MUTEX_UNLOCK( &stream_.mutex );
}
void RtApiJack :: abortStream( void )
@@ -2308,12 +2530,12 @@ void RtApiJack :: abortStream( void )
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
JackHandle *handle = (JackHandle *) stream_.apiHandle;
- handle->drainCounter = 1;
+ handle->drainCounter = 2;
stopStream();
}
@@ -2323,27 +2545,26 @@ void RtApiJack :: abortStream( void )
// aborted. It is necessary to handle it this way because the
// callbackEvent() function must return before the jack_deactivate()
// function will return.
-extern "C" void *jackStopStream( void *ptr )
+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 ) return SUCCESS;
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return FAILURE;
}
if ( stream_.bufferSize != nframes ) {
errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return FAILURE;
}
@@ -2352,23 +2573,16 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
// Check if we were draining the stream and signal is finished.
if ( handle->drainCounter > 3 ) {
- if ( handle->internalDrain == true ) {
- ThreadHandle id;
- pthread_create( &id, NULL, jackStopStream, info );
- }
+ ThreadHandle threadId;
+
+ stream_.state = STREAM_STOPPING;
+ if ( handle->internalDrain == true )
+ pthread_create( &threadId, NULL, jackStopStream, info );
else
pthread_cond_signal( &handle->condition );
return SUCCESS;
}
- MUTEX_LOCK( &stream_.mutex );
-
- // The state might change while waiting on a mutex.
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return SUCCESS;
- }
-
// Invoke user callback first, to get fresh output data.
if ( handle->drainCounter == 0 ) {
RtAudioCallback callback = (RtAudioCallback) info->callback;
@@ -2382,23 +2596,26 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
status |= RTAUDIO_INPUT_OVERFLOW;
handle->xrun[1] = false;
}
- handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, info->userData );
- if ( handle->drainCounter == 2 ) {
- MUTEX_UNLOCK( &stream_.mutex );
+ 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 ( handle->drainCounter == 1 )
+ 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 > 0 ) { // write zeros to the output stream
+ 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 );
@@ -2421,11 +2638,12 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes );
}
}
+ }
- if ( handle->drainCounter ) {
- handle->drainCounter++;
- goto unlock;
- }
+ // Don't bother draining input
+ if ( handle->drainCounter ) {
+ handle->drainCounter++;
+ goto unlock;
}
if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
@@ -2446,8 +2664,6 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
}
unlock:
- MUTEX_UNLOCK(&stream_.mutex);
-
RtApi::tickStreamTime();
return SUCCESS;
}
@@ -2478,11 +2694,11 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
#include "asiodrivers.h"
#include <cmath>
-AsioDrivers drivers;
-ASIOCallbacks asioCallbacks;
-ASIODriverInfo driverInfo;
-CallbackInfo *asioCallbackInfo;
-bool asioXRun;
+static AsioDrivers drivers;
+static ASIOCallbacks asioCallbacks;
+static ASIODriverInfo driverInfo;
+static CallbackInfo *asioCallbackInfo;
+static bool asioXRun;
struct AsioHandle {
int drainCounter; // Tracks callback counts when draining
@@ -2496,8 +2712,8 @@ struct AsioHandle {
// Function declarations (definitions at end of section)
static const char* getAsioErrorString( ASIOError result );
-void sampleRateChanged( ASIOSampleRate sRate );
-long asioMessages( long selector, long value, void* message, double* opt );
+static void sampleRateChanged( ASIOSampleRate sRate );
+static long asioMessages( long selector, long value, void* message, double* opt );
RtApiAsio :: RtApiAsio()
{
@@ -2508,7 +2724,7 @@ RtApiAsio :: RtApiAsio()
HRESULT hr = CoInitialize( NULL );
if ( FAILED(hr) ) {
errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
}
coInitialized_ = true;
@@ -2539,19 +2755,21 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
unsigned int nDevices = getDeviceCount();
if ( nDevices == 0 ) {
errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";
- error( RtError::INVALID_USE );
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
return devices_[ device ];
@@ -2562,7 +2780,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
if ( result != ASE_OK ) {
errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ").";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -2571,7 +2789,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
if ( !drivers.loadDriver( driverName ) ) {
errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ").";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -2579,7 +2797,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
if ( result != ASE_OK ) {
errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -2590,7 +2808,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -2603,8 +2821,12 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
info.sampleRates.clear();
for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
- if ( result == ASE_OK )
+ 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.
@@ -2617,7 +2839,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting driver channel info (" << driverName << ").";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -2630,18 +2852,20 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
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 ( getDefaultOutputDevice() == device )
- info.isDefaultOutput = true;
- if ( getDefaultInputDevice() == device )
- info.isDefaultInput = true;
+ 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;
}
-void bufferSwitch( long index, ASIOBool processNow )
+static void bufferSwitch( long index, ASIOBool /*processNow*/ )
{
RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;
object->callbackEvent( index );
@@ -2661,9 +2885,12 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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 ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) {
+ if ( isDuplexInput && stream_.device[0] != device ) {
errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";
return FAILURE;
}
@@ -2676,14 +2903,14 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
return FAILURE;
}
- // 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();
-
// Only load the driver once for duplex stream.
- if ( mode != INPUT || stream_.mode != OUTPUT ) {
+ 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();
@@ -2698,22 +2925,26 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
}
+ // 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 ) {
- drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
errorText_ = errorStream_.str();
- return FAILURE;
+ goto error;
}
if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||
( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {
- drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";
errorText_ = errorStream_.str();
- return FAILURE;
+ goto error;
}
stream_.nDeviceChannels[mode] = channels;
stream_.nUserChannels[mode] = channels;
@@ -2722,30 +2953,27 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// Verify the sample rate is supported.
result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
if ( result != ASE_OK ) {
- drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";
errorText_ = errorStream_.str();
- return FAILURE;
+ goto error;
}
// Get the current sample rate
ASIOSampleRate currentRate;
result = ASIOGetSampleRate( &currentRate );
if ( result != ASE_OK ) {
- drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";
errorText_ = errorStream_.str();
- return FAILURE;
+ goto error;
}
// Set the sample rate only if necessary
if ( currentRate != sampleRate ) {
result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
if ( result != ASE_OK ) {
- drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";
errorText_ = errorStream_.str();
- return FAILURE;
+ goto error;
}
}
@@ -2756,10 +2984,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
else channelInfo.isInput = true;
result = ASIOGetChannelInfo( &channelInfo );
if ( result != ASE_OK ) {
- drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";
errorText_ = errorStream_.str();
- return FAILURE;
+ goto error;
}
// Assuming WINDOWS host is always little-endian.
@@ -2782,12 +3009,15 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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 ) {
- drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";
errorText_ = errorStream_.str();
- return FAILURE;
+ goto error;
}
// Set the buffer size. For a duplex stream, this will end up
@@ -2796,49 +3026,63 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
long minSize, maxSize, preferSize, granularity;
result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
if ( result != ASE_OK ) {
- drivers.removeCurrentDriver();
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";
errorText_ = errorStream_.str();
- return FAILURE;
+ goto error;
}
- 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;
+ 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.
- 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;
- }
+ *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;
+ 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;
+ 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;
+ *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;
+ }
}
- if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) {
- drivers.removeCurrentDriver();
+ /*
+ // 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!";
- return FAILURE;
+ goto error;
}
+ */
stream_.bufferSize = *bufferSize;
stream_.nBuffers = 2;
@@ -2850,16 +3094,13 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.deviceInterleaved[mode] = false;
// Allocate, if necessary, our AsioHandle structure for the stream.
- AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
if ( handle == 0 ) {
try {
handle = new AsioHandle;
}
catch ( std::bad_alloc& ) {
- //if ( handle == NULL ) {
- drivers.removeCurrentDriver();
errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";
- return FAILURE;
+ goto error;
}
handle->bufferInfos = 0;
@@ -2874,15 +3115,14 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// 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.
- long inputLatency, outputLatency;
if ( mode == INPUT && stream_.mode == OUTPUT ) {
ASIODisposeBuffers();
if ( handle->bufferInfos ) free( handle->bufferInfos );
}
// Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
- bool buffersAllocated = false;
- unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
+ 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 << ").";
@@ -2903,6 +3143,15 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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;
@@ -2910,11 +3159,21 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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;
+ buffersAllocated = true;
+ stream_.state = STREAM_STOPPED;
// Set flags for buffer conversion.
stream_.doConvertBuffer[mode] = false;
@@ -2937,11 +3196,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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 ( isDuplexInput && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ if ( bufferBytes <= bytesOut ) makeBuffer = false;
}
if ( makeBuffer ) {
@@ -2955,23 +3212,13 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
}
- stream_.sampleRate = sampleRate;
- stream_.device[mode] = device;
- stream_.state = STREAM_STOPPED;
- asioCallbackInfo = &stream_.callbackInfo;
- stream_.callbackInfo.object = (void *) this;
- if ( stream_.mode == OUTPUT && mode == INPUT )
- // We had already set up an output stream.
- stream_.mode = DUPLEX;
- else
- stream_.mode = mode;
-
// 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( RtError::WARNING); // warn but don't fail
+ error( RtAudioError::WARNING); // warn but don't fail
}
else {
stream_.latency[0] = outputLatency;
@@ -2986,38 +3233,44 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
return SUCCESS;
error:
- if ( buffersAllocated )
- ASIODisposeBuffers();
- drivers.removeCurrentDriver();
+ if ( !isDuplexInput ) {
+ // the cleanup for error in the duplex input, is done by RtApi::openStream
+ // So we clean up for single channel only
- if ( handle ) {
- CloseHandle( handle->condition );
- if ( handle->bufferInfos )
- free( handle->bufferInfos );
- delete handle;
- stream_.apiHandle = 0;
- }
+ if ( buffersAllocated )
+ ASIODisposeBuffers();
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
+ drivers.removeCurrentDriver();
+
+ if ( handle ) {
+ CloseHandle( handle->condition );
+ if ( handle->bufferInfos )
+ free( handle->bufferInfos );
+
+ delete handle;
+ stream_.apiHandle = 0;
}
- }
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -3053,17 +3306,17 @@ void RtApiAsio :: closeStream()
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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
- MUTEX_LOCK( &stream_.mutex );
-
AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
ASIOError result = ASIOStart();
if ( result != ASE_OK ) {
@@ -3074,14 +3327,15 @@ void RtApiAsio :: startStream()
handle->drainCounter = 0;
handle->internalDrain = false;
+ ResetEvent( handle->condition );
stream_.state = STREAM_RUNNING;
asioXRun = false;
unlock:
- MUTEX_UNLOCK( &stream_.mutex );
+ stopThreadCalled = false;
if ( result == ASE_OK ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiAsio :: stopStream()
@@ -3089,39 +3343,28 @@ void RtApiAsio :: stopStream()
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!";
- error( RtError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::WARNING );
return;
}
AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
if ( handle->drainCounter == 0 ) {
- handle->drainCounter = 1;
- MUTEX_UNLOCK( &stream_.mutex );
- WaitForMultipleObjects( 1, &handle->condition, FALSE, INFINITE ); // block until signaled
- ResetEvent( handle->condition );
- MUTEX_LOCK( &stream_.mutex );
+ 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();
}
- stream_.state = STREAM_STOPPED;
- MUTEX_UNLOCK( &stream_.mutex );
-
if ( result == ASE_OK ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiAsio :: abortStream()
@@ -3129,7 +3372,7 @@ void RtApiAsio :: abortStream()
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -3138,36 +3381,51 @@ void RtApiAsio :: abortStream()
// 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 = 1;
+ // 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 ) return SUCCESS;
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return FAILURE;
}
CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
- // Check if we were draining the stream and signal is finished.
+ // 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
- stopStream();
+ else { // spawn a thread to stop the stream
+ unsigned threadId;
+ stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,
+ &stream_.callbackInfo, 0, &threadId );
+ }
return SUCCESS;
}
- MUTEX_LOCK( &stream_.mutex );
-
- // The state might change while waiting on a mutex.
- if ( stream_.state == STREAM_STOPPED ) goto unlock;
-
// Invoke user callback to get fresh output data UNLESS we are
// draining stream.
if ( handle->drainCounter == 0 ) {
@@ -3182,15 +3440,20 @@ bool RtApiAsio :: callbackEvent( long bufferIndex )
status |= RTAUDIO_INPUT_OVERFLOW;
asioXRun = false;
}
- handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1],
+ int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
stream_.bufferSize, streamTime, status, info->userData );
- if ( handle->drainCounter == 2 ) {
- MUTEX_UNLOCK( &stream_.mutex );
- abortStream();
+ 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 ( handle->drainCounter == 1 )
+ else if ( cbReturnValue == 1 ) {
+ handle->drainCounter = 1;
handle->internalDrain = true;
+ }
}
unsigned int nChannels, bufferBytes, i, j;
@@ -3236,11 +3499,12 @@ bool RtApiAsio :: callbackEvent( long bufferIndex )
}
}
+ }
- if ( handle->drainCounter ) {
- handle->drainCounter++;
- goto unlock;
- }
+ // Don't bother draining input
+ if ( handle->drainCounter ) {
+ handle->drainCounter++;
+ goto unlock;
}
if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
@@ -3286,13 +3550,11 @@ bool RtApiAsio :: callbackEvent( long bufferIndex )
// drivers apparently do not function correctly without it.
ASIOOutputReady();
- MUTEX_UNLOCK( &stream_.mutex );
-
RtApi::tickStreamTime();
return SUCCESS;
}
-void sampleRateChanged( ASIOSampleRate sRate )
+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,
@@ -3304,7 +3566,7 @@ void sampleRateChanged( ASIOSampleRate sRate )
try {
object->stopStream();
}
- catch ( RtError &exception ) {
+ catch ( RtAudioError &exception ) {
std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl;
return;
}
@@ -3312,7 +3574,7 @@ void sampleRateChanged( ASIOSampleRate sRate )
std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;
}
-long asioMessages( long selector, long value, void* message, double* opt )
+static long asioMessages( long selector, long value, void* /*message*/, double* /*opt*/ )
{
long ret = 0;
@@ -3390,7 +3652,7 @@ static const char* getAsioErrorString( ASIOError result )
const char*message;
};
- static Messages m[] =
+ static const Messages m[] =
{
{ ASE_NotPresent, "Hardware input or output is not present or available." },
{ ASE_HWMalfunction, "Hardware is malfunctioning." },
@@ -3406,21 +3668,1541 @@ static const char* getAsioErrorString( ASIOError result )
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.
-// - Backdoor RtDsStatistics hook provides DirectX performance information.
// - 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
@@ -3436,14 +5218,6 @@ static const char* getAsioErrorString( ASIOError result )
#pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually.
#endif
-static inline DWORD dsPointerDifference( DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )
-{
- if ( laterPointer > earlierPointer )
- return laterPointer - earlierPointer;
- else
- return laterPointer - earlierPointer + bufferSize;
-}
-
static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )
{
if ( pointer > bufferSize ) pointer -= bufferSize;
@@ -3469,25 +5243,6 @@ struct 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; }
};
-/*
-RtApiDs::RtDsStatistics RtApiDs::statistics;
-
-// Provides a backdoor hook to monitor for DirectSound read overruns and write underruns.
-RtApiDs::RtDsStatistics RtApiDs::getDsStatistics()
-{
- RtDsStatistics s = statistics;
-
- // update the calculated fields.
- if ( s.inputFrameSize != 0 )
- s.latency += s.readDeviceSafeLeadBytes * 1.0 / s.inputFrameSize / s.sampleRate;
-
- if ( s.outputFrameSize != 0 )
- s.latency += (s.writeDeviceSafeLeadBytes + s.writeDeviceBufferLeadBytes) * 1.0 / s.outputFrameSize / s.sampleRate;
-
- return s;
-}
-*/
-
// Declarations for utility functions, callbacks, and structures
// specific to the DirectSound implementation.
static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
@@ -3495,21 +5250,23 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
LPCTSTR module,
LPVOID lpContext );
-static char* getErrorString( int code );
+static const char* getErrorString( int code );
-extern "C" unsigned __stdcall callbackHandler( void *ptr );
+static unsigned __stdcall callbackHandler( void *ptr );
-struct EnumInfo {
- bool isInput;
- bool getDefault;
- bool findIndex;
- unsigned int counter;
- unsigned int index;
- LPGUID id;
+struct DsDevice {
+ LPGUID id[2];
+ bool validId[2];
+ bool found;
std::string name;
- EnumInfo()
- : isInput(false), getDefault(false), findIndex(false), counter(0), index(0) {}
+ DsDevice()
+ : found(false) { validId[0] = false; validId[1] = false; }
+};
+
+struct DsProbeData {
+ bool isInput;
+ std::vector<struct DsDevice>* dsDevices;
};
RtApiDs :: RtApiDs()
@@ -3527,105 +5284,87 @@ RtApiDs :: ~RtApiDs()
if ( stream_.state != STREAM_CLOSED ) closeStream();
}
-unsigned int RtApiDs :: getDefaultInputDevice( void )
+// The DirectSound default output is always the first device.
+unsigned int RtApiDs :: getDefaultOutputDevice( void )
{
- // Count output devices.
- EnumInfo info;
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDefaultOutputDevice: error (" << getErrorString( result ) << ") counting output devices!";
- errorText_ = errorStream_.str();
- error( RtError::WARNING );
- return 0;
- }
-
- // Now enumerate input devices until we find the id = NULL.
- info.isInput = true;
- info.getDefault = true;
- result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDefaultInputDevice: error (" << getErrorString( result ) << ") enumerating input devices!";
- errorText_ = errorStream_.str();
- error( RtError::WARNING );
- return 0;
- }
-
- if ( info.counter > 0 ) return info.counter - 1;
return 0;
}
-unsigned int RtApiDs :: getDefaultOutputDevice( void )
+// The DirectSound default input is always the first input device,
+// which is the first capture device enumerated.
+unsigned int RtApiDs :: getDefaultInputDevice( void )
{
- // Enumerate output devices until we find the id = NULL.
- EnumInfo info;
- info.getDefault = true;
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDefaultOutputDevice: error (" << getErrorString( result ) << ") enumerating output devices!";
- errorText_ = errorStream_.str();
- error( RtError::WARNING );
- return 0;
- }
-
- if ( info.counter > 0 ) return info.counter - 1;
return 0;
}
unsigned int RtApiDs :: getDeviceCount( void )
{
- // Count DirectSound devices.
- EnumInfo info;
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
+ // 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
}
- // Count DirectSoundCapture devices.
- info.isInput = true;
- result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
+ // 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( RtError::WARNING );
+ 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 info.counter;
+ return static_cast<unsigned int>(dsDevices.size());
}
RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
{
- // Because DirectSound always enumerates input and output devices
- // separately (and because we don't attempt to combine devices
- // internally), none of our "devices" will ever be duplex.
-
RtAudio::DeviceInfo info;
info.probed = false;
- // Enumerate through devices to find the id (if it exists). Note
- // that we have to do the output enumeration first, even if this is
- // an input device, in order for the device counter to be correct.
- EnumInfo dsinfo;
- dsinfo.findIndex = true;
- dsinfo.index = device;
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &dsinfo );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") enumerating output devices!";
- errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ 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;
}
- if ( dsinfo.name.empty() ) goto probeInput;
+ HRESULT result;
+ if ( dsDevices[ device ].validId[0] == false ) goto probeInput;
LPDIRECTSOUND output;
DSCAPS outCaps;
- result = DirectSoundCreate( dsinfo.id, &output, NULL );
+ result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
- return info;
+ error( RtAudioError::WARNING );
+ goto probeInput;
}
outCaps.dwSize = sizeof( outCaps );
@@ -3634,8 +5373,8 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
output->Release();
errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
- return info;
+ error( RtAudioError::WARNING );
+ goto probeInput;
}
// Get output channel information.
@@ -3645,8 +5384,12 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
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 )
+ 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.
@@ -3658,30 +5401,20 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
if ( getDefaultOutputDevice() == device )
info.isDefaultOutput = true;
- // Copy name and return.
- info.name = dsinfo.name;
-
- info.probed = true;
- return info;
-
- probeInput:
-
- dsinfo.isInput = true;
- result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &dsinfo );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") enumerating input devices!";
- errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ if ( dsDevices[ device ].validId[1] == false ) {
+ info.name = dsDevices[ device ].name;
+ info.probed = true;
+ return info;
}
- if ( dsinfo.name.empty() ) return info;
+ probeInput:
LPDIRECTSOUNDCAPTURE input;
- result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL );
+ result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -3690,9 +5423,9 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
result = input->GetCaps( &inCaps );
if ( FAILED( result ) ) {
input->Release();
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -3700,7 +5433,8 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
info.inputChannels = inCaps.dwChannels;
// Get sample rate and format information.
- if ( inCaps.dwChannels == 2 ) {
+ 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;
@@ -3711,16 +5445,16 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8;
if ( info.nativeFormats & RTAUDIO_SINT16 ) {
- if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.sampleRates.push_back( 11025 );
- if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.sampleRates.push_back( 22050 );
- if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.sampleRates.push_back( 44100 );
- if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.sampleRates.push_back( 96000 );
+ 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 ) info.sampleRates.push_back( 11025 );
- if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.sampleRates.push_back( 22050 );
- if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.sampleRates.push_back( 44100 );
- if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.sampleRates.push_back( 44100 );
+ 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 ) {
@@ -3734,16 +5468,16 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8;
if ( info.nativeFormats & RTAUDIO_SINT16 ) {
- if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.sampleRates.push_back( 11025 );
- if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.sampleRates.push_back( 22050 );
- if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.sampleRates.push_back( 44100 );
- if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.sampleRates.push_back( 96000 );
+ 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 ) info.sampleRates.push_back( 11025 );
- if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.sampleRates.push_back( 22050 );
- if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.sampleRates.push_back( 44100 );
- if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.sampleRates.push_back( 96000 );
+ 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
@@ -3752,11 +5486,28 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
if ( info.inputChannels == 0 ) return info;
- if ( getDefaultInputDevice() == device )
- info.isDefaultInput = true;
+ // 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 = dsinfo.name;
+ info.name = dsDevices[ device ].name;
info.probed = true;
return info;
}
@@ -3771,35 +5522,28 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
return FAILURE;
}
- // Enumerate through devices to find the id (if it exists). Note
- // that we have to do the output enumeration first, even if this is
- // an input device, in order for the device counter to be correct.
- EnumInfo dsinfo;
- dsinfo.findIndex = true;
- dsinfo.index = device;
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &dsinfo );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") enumerating output devices!";
- errorText_ = errorStream_.str();
+ 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 ( dsinfo.name.empty() ) {
+ if ( dsDevices[ device ].validId[0] == false ) {
errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!";
errorText_ = errorStream_.str();
return FAILURE;
}
}
else { // mode == INPUT
- dsinfo.isInput = true;
- HRESULT result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &dsinfo );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") enumerating input devices!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- if ( dsinfo.name.empty() ) {
+ if ( dsDevices[ device ].validId[1] == false ) {
errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!";
errorText_ = errorStream_.str();
return FAILURE;
@@ -3810,9 +5554,11 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
// 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. However, for console
- // applications, no sound was produced when using GetDesktopWindow().
- HWND hWnd = GetForegroundWindow();
+ // 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
@@ -3822,6 +5568,10 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
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;
@@ -3830,19 +5580,20 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
waveFormat.nChannels = channels + firstChannel;
waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
- // Determine the device buffer size. By default, 32k, but we will
- // grow it to make allowances for very large software buffer sizes.
- DWORD dsBufferSize = 0;
+ // 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;
- long bufferBytes = MINIMUM_DEVICE_BUFFER_SIZE; // sound cards will always *knock wood* support this
void *ohandle = 0, *bhandle = 0;
+ HRESULT result;
if ( mode == OUTPUT ) {
LPDIRECTSOUND output;
- result = DirectSoundCreate( dsinfo.id, &output, NULL );
+ result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -3852,14 +5603,14 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
result = output->GetCaps( &outCaps );
if ( FAILED( result ) ) {
output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsinfo.name << ")!";
+ 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 (" << dsinfo.name << ") does not support stereo playback.";
+ errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback.";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -3883,8 +5634,8 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
// If the user wants an even bigger buffer, increase the device buffer size accordingly.
- while ( dsPointerLeadTime * 2U > (DWORD) bufferBytes )
- bufferBytes *= 2;
+ while ( dsPointerLeadTime * 2U > dsBufferSize )
+ dsBufferSize *= 2;
// Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.
// result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
@@ -3892,7 +5643,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );
if ( FAILED( result ) ) {
output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -3911,7 +5662,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
if ( FAILED( result ) ) {
output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -3920,20 +5671,19 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
result = buffer->SetFormat( &waveFormat );
if ( FAILED( result ) ) {
output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
// Setup the secondary DS buffer description.
- dsBufferSize = (DWORD) bufferBytes;
ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
bufferDescription.dwSize = sizeof( DSBUFFERDESC );
bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
DSBCAPS_GLOBALFOCUS |
DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_LOCHARDWARE ); // Force hardware mixing
- bufferDescription.dwBufferBytes = bufferBytes;
+ bufferDescription.dwBufferBytes = dsBufferSize;
bufferDescription.lpwfxFormat = &waveFormat;
// Try to create the secondary DS buffer. If that doesn't work,
@@ -3947,7 +5697,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
if ( FAILED( result ) ) {
output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -3960,21 +5710,21 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
if ( FAILED( result ) ) {
output->Release();
buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
- bufferBytes = dsbcaps.dwBufferBytes;
+ dsBufferSize = dsbcaps.dwBufferBytes;
// Lock the DS buffer
LPVOID audioPtr;
DWORD dataLen;
- result = buffer->Lock( 0, bufferBytes, &audioPtr, &dataLen, NULL, NULL, 0 );
+ 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 (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -3987,12 +5737,11 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
if ( FAILED( result ) ) {
output->Release();
buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
- dsBufferSize = bufferBytes;
ohandle = (void *) output;
bhandle = (void *) buffer;
}
@@ -4000,9 +5749,9 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
if ( mode == INPUT ) {
LPDIRECTSOUNDCAPTURE input;
- result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL );
+ result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -4012,7 +5761,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
result = input->GetCaps( &inCaps );
if ( FAILED( result ) ) {
input->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -4056,17 +5805,16 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
// If the user wants an even bigger buffer, increase the device buffer size accordingly.
- while ( dsPointerLeadTime * 2U > (DWORD) bufferBytes )
- bufferBytes *= 2;
+ while ( dsPointerLeadTime * 2U > dsBufferSize )
+ dsBufferSize *= 2;
// Setup the secondary DS buffer description.
- dsBufferSize = bufferBytes;
DSCBUFFERDESC bufferDescription;
ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) );
bufferDescription.dwSize = sizeof( DSCBUFFERDESC );
bufferDescription.dwFlags = 0;
bufferDescription.dwReserved = 0;
- bufferDescription.dwBufferBytes = bufferBytes;
+ bufferDescription.dwBufferBytes = dsBufferSize;
bufferDescription.lpwfxFormat = &waveFormat;
// Create the capture buffer.
@@ -4074,7 +5822,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL );
if ( FAILED( result ) ) {
input->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -4086,21 +5834,26 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
if ( FAILED( result ) ) {
input->Release();
buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
- bufferBytes = dscbcaps.dwBufferBytes;
+ 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, bufferBytes, &audioPtr, &dataLen, NULL, NULL, 0 );
+ 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 (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
@@ -4113,12 +5866,11 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
if ( FAILED( result ) ) {
input->Release();
buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsinfo.name << ")!";
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!";
errorText_ = errorStream_.str();
return FAILURE;
}
- dsBufferSize = bufferBytes;
ohandle = (void *) input;
bhandle = (void *) buffer;
}
@@ -4144,7 +5896,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
stream_.doConvertBuffer[mode] = true;
// Allocate necessary internal buffers
- bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ 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.";
@@ -4211,18 +5963,20 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
// Setup the callback thread.
- unsigned threadId;
- stream_.callbackInfo.object = (void *) this;
- stream_.callbackInfo.isRunning = true;
- 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;
- }
+ 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 );
+ // Boost DS thread priority
+ SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST );
+ }
return SUCCESS;
error:
@@ -4256,6 +6010,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -4263,7 +6018,7 @@ void RtApiDs :: closeStream()
{
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiDs::closeStream(): no open stream to close!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -4318,26 +6073,17 @@ void RtApiDs :: startStream()
verifyStream();
if ( stream_.state == STREAM_RUNNING ) {
errorText_ = "RtApiDs::startStream(): the stream is already running!";
- error( RtError::WARNING );
+ 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.
-
- MUTEX_LOCK( &stream_.mutex );
-
- DsHandle *handle = (DsHandle *) stream_.apiHandle;
-
timeBeginPeriod( 1 );
- /*
- memset( &statistics, 0, sizeof( statistics ) );
- statistics.sampleRate = stream_.sampleRate;
- statistics.writeDeviceBufferLeadBytes = handle->dsPointerLeadTime[0];
- */
-
buffersRolling = false;
duplexPrerollBytes = 0;
@@ -4348,7 +6094,6 @@ void RtApiDs :: startStream()
HRESULT result = 0;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- //statistics.outputFrameSize = formatBytes( stream_.deviceFormat[0] ) * stream_.nDeviceChannels[0];
LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
result = buffer->Play( 0, 0, DSBPLAY_LOOPING );
@@ -4360,7 +6105,6 @@ void RtApiDs :: startStream()
}
if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
- //statistics.inputFrameSize = formatBytes( stream_.deviceFormat[1]) * stream_.nDeviceChannels[1];
LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
result = buffer->Start( DSCBSTART_LOOPING );
@@ -4373,12 +6117,11 @@ void RtApiDs :: startStream()
handle->drainCounter = 0;
handle->internalDrain = false;
+ ResetEvent( handle->condition );
stream_.state = STREAM_RUNNING;
unlock:
- MUTEX_UNLOCK( &stream_.mutex );
-
- if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR );
+ if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
}
void RtApiDs :: stopStream()
@@ -4386,14 +6129,7 @@ void RtApiDs :: stopStream()
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";
- error( RtError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::WARNING );
return;
}
@@ -4403,13 +6139,14 @@ void RtApiDs :: stopStream()
DsHandle *handle = (DsHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
if ( handle->drainCounter == 0 ) {
- handle->drainCounter = 1;
- MUTEX_UNLOCK( &stream_.mutex );
- WaitForMultipleObjects( 1, &handle->condition, FALSE, INFINITE ); // block until signaled
- ResetEvent( handle->condition );
- MUTEX_LOCK( &stream_.mutex );
+ 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();
@@ -4448,6 +6185,11 @@ void RtApiDs :: stopStream()
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!";
@@ -4481,10 +6223,9 @@ void RtApiDs :: stopStream()
unlock:
timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.
- stream_.state = STREAM_STOPPED;
MUTEX_UNLOCK( &stream_.mutex );
- if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR );
+ if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
}
void RtApiDs :: abortStream()
@@ -4492,26 +6233,26 @@ void RtApiDs :: abortStream()
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
DsHandle *handle = (DsHandle *) stream_.apiHandle;
- handle->drainCounter = 1;
+ handle->drainCounter = 2;
stopStream();
}
void RtApiDs :: callbackEvent()
{
- if ( stream_.state == STREAM_STOPPED ) {
- Sleep(50); // sleep 50 milliseconds
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -4520,6 +6261,8 @@ void RtApiDs :: callbackEvent()
// 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
@@ -4527,14 +6270,6 @@ void RtApiDs :: callbackEvent()
return;
}
- MUTEX_LOCK( &stream_.mutex );
-
- // The state might change while waiting on a mutex.
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
-
// Invoke user callback to get fresh output data UNLESS we are
// draining stream.
if ( handle->drainCounter == 0 ) {
@@ -4549,26 +6284,24 @@ void RtApiDs :: callbackEvent()
status |= RTAUDIO_INPUT_OVERFLOW;
handle->xrun[1] = false;
}
- handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, info->userData );
- if ( handle->drainCounter == 2 ) {
- MUTEX_UNLOCK( &stream_.mutex );
+ 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 ( handle->drainCounter == 1 )
+ else if ( cbReturnValue == 1 ) {
+ handle->drainCounter = 1;
handle->internalDrain = true;
+ }
}
HRESULT result;
- DWORD currentWritePos, safeWritePos;
- DWORD currentReadPos, safeReadPos;
- DWORD leadPos;
- UINT nextWritePos;
-
-#ifdef GENERATE_DEBUG_LOG
- DWORD writeTime, readTime;
-#endif
+ DWORD currentWritePointer, safeWritePointer;
+ DWORD currentReadPointer, safeReadPointer;
+ UINT nextWritePointer;
LPVOID buffer1 = NULL;
LPVOID buffer2 = NULL;
@@ -4578,63 +6311,95 @@ void RtApiDs :: callbackEvent()
char *buffer;
long bufferBytes;
- if ( stream_.mode == DUPLEX && !buffersRolling ) {
- //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
- // 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.
+ if ( buffersRolling == false ) {
+ if ( stream_.mode == DUPLEX ) {
+ //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
- // 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.
+ // 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.
- LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
- LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
+ // 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.
- DWORD initialWritePos, initialSafeWritePos;
- DWORD initialReadPos, initialSafeReadPos;
+ LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
+ LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
- result = dsWriteBuffer->GetCurrentPosition( &initialWritePos, &initialSafeWritePos );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
- errorText_ = errorStream_.str();
- error( RtError::SYSTEM_ERROR );
- }
- result = dsCaptureBuffer->GetCurrentPosition( &initialReadPos, &initialSafeReadPos );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
- errorText_ = errorStream_.str();
- error( RtError::SYSTEM_ERROR );
- }
- while ( true ) {
- result = dsWriteBuffer->GetCurrentPosition( &currentWritePos, &safeWritePos );
+ DWORD startSafeWritePointer, startSafeReadPointer;
+
+ result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
- error( RtError::SYSTEM_ERROR );
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
}
- result = dsCaptureBuffer->GetCurrentPosition( &currentReadPos, &safeReadPos );
+ result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
- error( RtError::SYSTEM_ERROR );
+ 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 );
}
- if ( safeWritePos != initialSafeWritePos && safeReadPos != initialSafeReadPos ) 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 ) {
- //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
+ // 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;
- handle->bufferPointer[0] = ( safeWritePos + handle->dsPointerLeadTime[0] );
- handle->bufferPointer[1] = safeReadPos;
}
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
@@ -4669,67 +6434,59 @@ void RtApiDs :: callbackEvent()
for ( int i=0; i<bufferBytes; i++ ) buffer[i] = (unsigned char) ( buffer[i] + 128 );
DWORD dsBufferSize = handle->dsBufferSize[0];
- nextWritePos = handle->bufferPointer[0];
+ nextWritePointer = handle->bufferPointer[0];
- DWORD endWrite;
+ DWORD endWrite, leadPointer;
while ( true ) {
// Find out where the read and "safe write" pointers are.
- result = dsBuffer->GetCurrentPosition( &currentWritePos, &safeWritePos );
+ result = dsBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
}
- leadPos = safeWritePos + handle->dsPointerLeadTime[0];
- if ( leadPos > dsBufferSize ) leadPos -= dsBufferSize;
- if ( leadPos < nextWritePos ) leadPos += dsBufferSize; // unwrap offset
- endWrite = nextWritePos + bufferBytes;
+ // 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 ( leadPos >= endWrite ) break;
-
- // If we are here, then we must wait until the play pointer gets
- // beyond the write region. The approach here is to use the
- // Sleep() function to suspend operation until safePos catches
- // up. Calculate number of milliseconds to wait as:
- // time = distance * (milliseconds/second) * fudgefactor /
- // ((bytes/sample) * (samples/second))
- // A "fudgefactor" less than 1 is used because it was found
- // that sleeping too long was MUCH worse than sleeping for
- // several shorter periods.
- double millis = ( endWrite - leadPos ) * 900.0;
+ 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;
- if ( millis > 50.0 ) {
- static int nOverruns = 0;
- ++nOverruns;
- }
Sleep( (DWORD) millis );
}
- //if ( statistics.writeDeviceSafeLeadBytes < dsPointerDifference( safeWritePos, currentWritePos, handle->dsBufferSize[0] ) ) {
- // statistics.writeDeviceSafeLeadBytes = dsPointerDifference( safeWritePos, currentWritePos, handle->dsBufferSize[0] );
- //}
-
- if ( dsPointerBetween( nextWritePos, safeWritePos, currentWritePos, dsBufferSize )
- || dsPointerBetween( endWrite, safeWritePos, currentWritePos, dsBufferSize ) ) {
+ if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )
+ || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) {
// We've strayed into the forbidden zone ... resync the read pointer.
- //++statistics.numberOfWriteUnderruns;
handle->xrun[0] = true;
- nextWritePos = safeWritePos + handle->dsPointerLeadTime[0] - bufferBytes + dsBufferSize;
- while ( nextWritePos >= dsBufferSize ) nextWritePos -= dsBufferSize;
- handle->bufferPointer[0] = nextWritePos;
- endWrite = nextWritePos + bufferBytes;
+ 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( nextWritePos, bufferBytes, &buffer1,
+ 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();
- error( RtError::SYSTEM_ERROR );
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
}
// Copy our buffer into the DS buffer
@@ -4741,15 +6498,18 @@ void RtApiDs :: callbackEvent()
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
errorText_ = errorStream_.str();
- error( RtError::SYSTEM_ERROR );
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
}
- nextWritePos = ( nextWritePos + bufferSize1 + bufferSize2 ) % dsBufferSize;
- handle->bufferPointer[0] = nextWritePos;
+ nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
+ handle->bufferPointer[0] = nextWritePointer;
+ }
- if ( handle->drainCounter ) {
- handle->drainCounter++;
- goto unlock;
- }
+ // Don't bother draining input
+ if ( handle->drainCounter ) {
+ handle->drainCounter++;
+ goto unlock;
}
if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
@@ -4767,19 +6527,21 @@ void RtApiDs :: callbackEvent()
}
LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
- long nextReadPos = handle->bufferPointer[1];
+ long nextReadPointer = handle->bufferPointer[1];
DWORD dsBufferSize = handle->dsBufferSize[1];
// Find out where the write and "safe read" pointers are.
- result = dsBuffer->GetCurrentPosition( &currentReadPos, &safeReadPos );
+ result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
- error( RtError::SYSTEM_ERROR );
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
}
- if ( safeReadPos < (DWORD)nextReadPos ) safeReadPos += dsBufferSize; // unwrap offset
- DWORD endRead = nextReadPos + bufferBytes;
+ 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,
@@ -4796,65 +6558,63 @@ void RtApiDs :: callbackEvent()
// zeros from the read buffer while the pointers sync up.
if ( stream_.mode == DUPLEX ) {
- if ( safeReadPos < endRead ) {
+ if ( safeReadPointer < endRead ) {
if ( duplexPrerollBytes <= 0 ) {
// Pre-roll time over. Be more agressive.
- int adjustment = endRead-safeReadPos;
+ int adjustment = endRead-safeReadPointer;
handle->xrun[1] = true;
- //++statistics.numberOfReadOverruns;
// 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 )
- nextReadPos = safeReadPos-2*bufferBytes;
+ nextReadPointer = safeReadPointer-2*bufferBytes;
else
- nextReadPos = safeReadPos-bufferBytes-adjustment;
+ nextReadPointer = safeReadPointer-bufferBytes-adjustment;
- //statistics.readDeviceSafeLeadBytes = currentReadPos-nextReadPos;
- //if ( statistics.readDeviceSafeLeadBytes < 0) statistics.readDeviceSafeLeadBytes += dsBufferSize;
- if ( nextReadPos < 0 ) nextReadPos += dsBufferSize;
+ if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
}
else {
// In pre=roll time. Just do it.
- nextReadPos = safeReadPos-bufferBytes;
- while ( nextReadPos < 0 ) nextReadPos += dsBufferSize;
+ nextReadPointer = safeReadPointer - bufferBytes;
+ while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
}
- endRead = nextReadPos + bufferBytes;
+ endRead = nextReadPointer + bufferBytes;
}
}
else { // mode == INPUT
- while ( safeReadPos < endRead ) {
+ while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) {
// See comments for playback.
- double millis = (endRead - safeReadPos) * 900.0;
+ 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, find out where we are now
- result = dsBuffer->GetCurrentPosition( &currentReadPos, &safeReadPos );
+ // 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();
- error( RtError::SYSTEM_ERROR );
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
}
- if ( safeReadPos < (DWORD)nextReadPos ) safeReadPos += dsBufferSize; // unwrap offset
+ if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
}
}
- //if (statistics.readDeviceSafeLeadBytes < dsPointerDifference( currentReadPos, nextReadPos, dsBufferSize ) )
- // statistics.readDeviceSafeLeadBytes = dsPointerDifference( currentReadPos, nextReadPos, dsBufferSize );
-
// Lock free space in the buffer
- result = dsBuffer->Lock( nextReadPos, bufferBytes, &buffer1,
+ 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();
- error( RtError::SYSTEM_ERROR );
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
}
if ( duplexPrerollBytes <= 0 ) {
@@ -4869,14 +6629,16 @@ void RtApiDs :: callbackEvent()
}
// Update our buffer offset and unlock sound buffer
- nextReadPos = ( nextReadPos + bufferSize1 + bufferSize2 ) % dsBufferSize;
+ 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();
- error( RtError::SYSTEM_ERROR );
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
}
- handle->bufferPointer[1] = nextReadPos;
+ handle->bufferPointer[1] = nextReadPointer;
// No byte swapping necessary in DirectSound implementation.
@@ -4888,31 +6650,16 @@ void RtApiDs :: callbackEvent()
if ( stream_.doConvertBuffer[1] )
convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
}
-#ifdef GENERATE_DEBUG_LOG
- if ( currentDebugLogEntry < debugLog.size() )
- {
- TTickRecord &r = debugLog[currentDebugLogEntry++];
- r.currentReadPointer = currentReadPos;
- r.safeReadPointer = safeReadPos;
- r.currentWritePointer = currentWritePos;
- r.safeWritePointer = safeWritePos;
- r.readTime = readTime;
- r.writeTime = writeTime;
- r.nextReadPointer = handles[1].bufferPointer;
- r.nextWritePointer = handles[0].bufferPointer;
- }
-#endif
unlock:
MUTEX_UNLOCK( &stream_.mutex );
-
RtApi::tickStreamTime();
}
// Definitions for utility functions and callbacks
// specific to the DirectSound implementation.
-extern "C" unsigned __stdcall callbackHandler( void *ptr )
+static unsigned __stdcall callbackHandler( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiDs *object = (RtApiDs *) info->object;
@@ -4926,34 +6673,17 @@ extern "C" unsigned __stdcall callbackHandler( void *ptr )
return 0;
}
-#include "tchar.h"
-
-std::string convertTChar( LPCTSTR name )
-{
- std::string s;
-
-#if defined( UNICODE ) || defined( _UNICODE )
- // Yes, this conversion doesn't make sense for two-byte characters
- // but RtAudio is currently written to return an std::string of
- // one-byte chars for the device name.
- for ( unsigned int i=0; i<wcslen( name ); i++ )
- s.push_back( name[i] );
-#else
- s.append( std::string( name ) );
-#endif
-
- return s;
-}
-
static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
LPCTSTR description,
- LPCTSTR module,
+ LPCTSTR /*module*/,
LPVOID lpContext )
{
- EnumInfo *info = (EnumInfo *) lpContext;
+ struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;
+ std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;
HRESULT hr;
- if ( info->isInput == true ) {
+ bool validDevice = false;
+ if ( probeInfo.isInput == true ) {
DSCCAPS caps;
LPDIRECTSOUNDCAPTURE object;
@@ -4964,7 +6694,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
hr = object->GetCaps( &caps );
if ( hr == DS_OK ) {
if ( caps.dwChannels > 0 && caps.dwFormats > 0 )
- info->counter++;
+ validDevice = true;
}
object->Release();
}
@@ -4978,23 +6708,50 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
hr = object->GetCaps( &caps );
if ( hr == DS_OK ) {
if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
- info->counter++;
+ validDevice = true;
}
object->Release();
}
- if ( info->getDefault && lpguid == NULL ) return FALSE;
+ // 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;
+ }
+ }
- if ( info->findIndex && info->counter > info->index ) {
- info->id = lpguid;
- info->name = convertTChar( description );
- return FALSE;
+ 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 char* getErrorString( int code )
+static const char* getErrorString( int code )
{
switch ( code ) {
@@ -5062,13 +6819,14 @@ struct AlsaHandle {
snd_pcm_t *handles[2];
bool synchronized;
bool xrun[2];
- pthread_cond_t runnable;
+ pthread_cond_t runnable_cv;
+ bool runnable;
AlsaHandle()
- :synchronized(false) { xrun[0] = false; xrun[1] = false; }
+ :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }
};
-extern "C" void *alsaCallbackHandler( void * ptr );
+static void *alsaCallbackHandler( void * ptr );
RtApiAlsa :: RtApiAlsa()
{
@@ -5096,7 +6854,7 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
if ( result < 0 ) {
errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
goto nextcard;
}
subdevice = -1;
@@ -5105,7 +6863,7 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
if ( result < 0 ) {
errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
break;
}
if ( subdevice < 0 )
@@ -5117,6 +6875,12 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
snd_card_next( &card );
}
+ result = snd_ctl_open( &handle, "default", 0 );
+ if (result == 0) {
+ nDevices++;
+ snd_ctl_close( handle );
+ }
+
return nDevices;
}
@@ -5132,6 +6896,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
// Count cards and devices
card = -1;
+ subdevice = -1;
snd_card_next( &card );
while ( card >= 0 ) {
sprintf( name, "hw:%d", card );
@@ -5139,7 +6904,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
if ( result < 0 ) {
errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
goto nextcard;
}
subdevice = -1;
@@ -5148,7 +6913,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
if ( result < 0 ) {
errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
break;
}
if ( subdevice < 0 ) break;
@@ -5163,14 +6928,25 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
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( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return info;
}
foundDevice:
@@ -5179,9 +6955,10 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
// 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
return devices_[ device ];
@@ -5195,23 +6972,25 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca( &params );
- // First try for playback
+ // First try for playback unless default device (which has subdev -1)
stream = SND_PCM_STREAM_PLAYBACK;
- snd_pcm_info_set_device( pcminfo, subdevice );
- snd_pcm_info_set_subdevice( pcminfo, 0 );
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_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( RtError::WARNING );
+ error( RtAudioError::WARNING );
goto captureProbe;
}
@@ -5221,7 +7000,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
snd_pcm_close( phandle );
errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
goto captureProbe;
}
@@ -5232,30 +7011,34 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
snd_pcm_close( phandle );
errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
goto captureProbe;
}
info.outputChannels = value;
snd_pcm_close( phandle );
captureProbe:
- // Now try for capture
stream = SND_PCM_STREAM_CAPTURE;
snd_pcm_info_set_stream( pcminfo, stream );
- 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;
+ // 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
if ( info.outputChannels == 0 ) return info;
goto probeParameters;
}
@@ -5266,7 +7049,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
snd_pcm_close( phandle );
errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
if ( info.outputChannels == 0 ) return info;
goto probeParameters;
}
@@ -5276,7 +7059,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
snd_pcm_close( phandle );
errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
if ( info.outputChannels == 0 ) return info;
goto probeParameters;
}
@@ -5310,7 +7093,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
if ( result < 0 ) {
errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -5320,21 +7103,25 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
snd_pcm_close( phandle );
errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ 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 )
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -5362,17 +7149,20 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
// 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
// Get the device name
char *cardname;
result = snd_card_get_name( card, &cardname );
- if ( result >= 0 )
+ if ( result >= 0 ) {
sprintf( name, "hw:%s,%d", cardname, subdevice );
+ free( cardname );
+ }
info.name = name;
// That's all ... close the device and return
@@ -5409,43 +7199,56 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
char name[64];
snd_ctl_t *chandle;
- // 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;
+ 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 );
}
- subdevice = -1;
- while( 1 ) {
- result = snd_ctl_pcm_next_device( chandle, &subdevice );
- if ( result < 0 ) break;
- if ( subdevice < 0 ) break;
+
+ result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
+ if ( result == 0 ) {
if ( nDevices == device ) {
- sprintf( name, "hw:%d,%d", card, subdevice );
- snd_ctl_close( chandle );
+ strcpy( name, "default" );
goto foundDevice;
}
nDevices++;
}
- snd_ctl_close( chandle );
- snd_card_next( &card );
- }
- 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 ( 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;
+ 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:
@@ -5579,6 +7382,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
// 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;
@@ -5648,13 +7452,8 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
return FAILURE;
}
- // Set the buffer number, which in ALSA is referred to as the "period".
- int totalSize, dir = 0;
- unsigned int periods = 0;
- if ( options ) periods = options->numberOfBuffers;
- totalSize = *bufferSize * periods;
-
// 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 ) {
@@ -5665,10 +7464,11 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
*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;
- else periods = totalSize / *bufferSize;
- // Even though the hardware might allow 1 buffer, it won't work reliably.
- if ( periods < 2 ) 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 );
@@ -5680,6 +7480,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// 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;
@@ -5753,7 +7554,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
goto error;
}
- if ( pthread_cond_init( &apiInfo->runnable, NULL ) ) {
+ if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) {
errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";
goto error;
}
@@ -5766,6 +7567,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
apiInfo = (AlsaHandle *) stream_.apiHandle;
}
apiInfo->handles[mode] = phandle;
+ phandle = 0;
// Allocate necessary internal buffers.
unsigned long bufferBytes;
@@ -5816,7 +7618,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
apiInfo->synchronized = true;
else {
errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
}
}
else {
@@ -5834,22 +7636,21 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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;
+ // 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;
- param.sched_priority = priority;
- pthread_attr_setschedparam( &attr, &param );
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ stream_.callbackInfo.priority = priority;
}
- else
- pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
-#else
- pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#endif
stream_.callbackInfo.isRunning = true;
@@ -5866,13 +7667,15 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
error:
if ( apiInfo ) {
- pthread_cond_destroy( &apiInfo->runnable );
+ 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] );
@@ -5885,6 +7688,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -5892,15 +7696,17 @@ void RtApiAlsa :: closeStream()
{
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiAlsa::closeStream(): no open stream to close!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
stream_.callbackInfo.isRunning = false;
MUTEX_LOCK( &stream_.mutex );
- if ( stream_.state == STREAM_STOPPED )
- pthread_cond_signal( &apiInfo->runnable );
+ if ( stream_.state == STREAM_STOPPED ) {
+ apiInfo->runnable = true;
+ pthread_cond_signal( &apiInfo->runnable_cv );
+ }
MUTEX_UNLOCK( &stream_.mutex );
pthread_join( stream_.callbackInfo.thread, NULL );
@@ -5913,7 +7719,7 @@ void RtApiAlsa :: closeStream()
}
if ( apiInfo ) {
- pthread_cond_destroy( &apiInfo->runnable );
+ 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;
@@ -5943,7 +7749,7 @@ void RtApiAlsa :: startStream()
verifyStream();
if ( stream_.state == STREAM_RUNNING ) {
errorText_ = "RtApiAlsa::startStream(): the stream is already running!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -5966,6 +7772,7 @@ void RtApiAlsa :: startStream()
}
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] );
@@ -5980,12 +7787,12 @@ void RtApiAlsa :: startStream()
stream_.state = STREAM_RUNNING;
unlock:
+ apiInfo->runnable = true;
+ pthread_cond_signal( &apiInfo->runnable_cv );
MUTEX_UNLOCK( &stream_.mutex );
- pthread_cond_signal( &apiInfo->runnable );
-
if ( result >= 0 ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiAlsa :: stopStream()
@@ -5993,17 +7800,13 @@ void RtApiAlsa :: stopStream()
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
+ stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
-
int result = 0;
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
@@ -6029,11 +7832,11 @@ void RtApiAlsa :: stopStream()
}
unlock:
- stream_.state = STREAM_STOPPED;
+ apiInfo->runnable = false; // fixes high CPU usage when stopped
MUTEX_UNLOCK( &stream_.mutex );
if ( result >= 0 ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiAlsa :: abortStream()
@@ -6041,17 +7844,13 @@ void RtApiAlsa :: abortStream()
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
+ stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
-
int result = 0;
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
@@ -6074,11 +7873,11 @@ void RtApiAlsa :: abortStream()
}
unlock:
- stream_.state = STREAM_STOPPED;
+ apiInfo->runnable = false; // fixes high CPU usage when stopped
MUTEX_UNLOCK( &stream_.mutex );
if ( result >= 0 ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiAlsa :: callbackEvent()
@@ -6086,7 +7885,9 @@ void RtApiAlsa :: callbackEvent()
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_STOPPED ) {
MUTEX_LOCK( &stream_.mutex );
- pthread_cond_wait( &apiInfo->runnable, &stream_.mutex );
+ while ( !apiInfo->runnable )
+ pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex );
+
if ( stream_.state != STREAM_RUNNING ) {
MUTEX_UNLOCK( &stream_.mutex );
return;
@@ -6096,7 +7897,7 @@ void RtApiAlsa :: callbackEvent()
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -6179,7 +7980,7 @@ void RtApiAlsa :: callbackEvent()
errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
}
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
goto tryOutput;
}
@@ -6239,6 +8040,8 @@ void RtApiAlsa :: callbackEvent()
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 ) << ".";
@@ -6249,7 +8052,7 @@ void RtApiAlsa :: callbackEvent()
errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
}
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
goto unlock;
}
@@ -6265,12 +8068,20 @@ void RtApiAlsa :: callbackEvent()
if ( doStopStream == 1 ) this->stopStream();
}
-extern "C" void *alsaCallbackHandler( void *ptr )
+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();
@@ -6282,6 +8093,493 @@ extern "C" void *alsaCallbackHandler( void *ptr )
//******************** 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__)
@@ -6289,11 +8587,11 @@ extern "C" void *alsaCallbackHandler( void *ptr )
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
-#include "soundcard.h"
+#include <sys/soundcard.h>
#include <errno.h>
#include <math.h>
-extern "C" void *ossCallbackHandler(void * ptr);
+static void *ossCallbackHandler(void * ptr);
// A structure to hold various information related to the OSS API
// implementation.
@@ -6322,7 +8620,7 @@ unsigned int RtApiOss :: getDeviceCount( void )
int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
if ( mixerfd == -1 ) {
errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
@@ -6330,7 +8628,7 @@ unsigned int RtApiOss :: getDeviceCount( void )
if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) {
close( mixerfd );
errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
@@ -6346,7 +8644,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
if ( mixerfd == -1 ) {
errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -6355,7 +8653,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
if ( result == -1 ) {
close( mixerfd );
errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -6363,13 +8661,15 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
if ( nDevices == 0 ) {
close( mixerfd );
errorText_ = "RtApiOss::getDeviceInfo: no devices found!";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
close( mixerfd );
errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";
- error( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
+ return info;
}
oss_audioinfo ainfo;
@@ -6379,7 +8679,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
if ( result == -1 ) {
errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -6408,7 +8708,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
if ( info.nativeFormats == 0 ) {
errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio.";
errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return info;
}
@@ -6419,6 +8719,10 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
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;
}
}
@@ -6427,15 +8731,19 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
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] )
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
}
else {
info.probed = true;
@@ -6884,7 +9192,7 @@ void RtApiOss :: closeStream()
{
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiOss::closeStream(): no open stream to close!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -6933,7 +9241,7 @@ void RtApiOss :: startStream()
verifyStream();
if ( stream_.state == STREAM_RUNNING ) {
errorText_ = "RtApiOss::startStream(): the stream is already running!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -6955,7 +9263,7 @@ void RtApiOss :: stopStream()
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiOss::stopStream(): the stream is already stopped!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -6992,7 +9300,7 @@ void RtApiOss :: stopStream()
result = write( handle->id[0], buffer, samples * formatBytes(format) );
if ( result == -1 ) {
errorText_ = "RtApiOss::stopStream: audio write error.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
}
}
@@ -7019,7 +9327,7 @@ void RtApiOss :: stopStream()
MUTEX_UNLOCK( &stream_.mutex );
if ( result != -1 ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiOss :: abortStream()
@@ -7027,7 +9335,7 @@ void RtApiOss :: abortStream()
verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
errorText_ = "RtApiOss::abortStream(): the stream is already stopped!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -7065,7 +9373,7 @@ void RtApiOss :: abortStream()
MUTEX_UNLOCK( &stream_.mutex );
if ( result != -1 ) return;
- error( RtError::SYSTEM_ERROR );
+ error( RtAudioError::SYSTEM_ERROR );
}
void RtApiOss :: callbackEvent()
@@ -7083,7 +9391,7 @@ void RtApiOss :: callbackEvent()
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
return;
}
@@ -7153,7 +9461,7 @@ void RtApiOss :: callbackEvent()
// specific means for determining that.
handle->xrun[0] = true;
errorText_ = "RtApiOss::callbackEvent: audio write error.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
// Continue on to input section.
}
}
@@ -7180,7 +9488,7 @@ void RtApiOss :: callbackEvent()
// specific means for determining that.
handle->xrun[1] = true;
errorText_ = "RtApiOss::callbackEvent: audio read error.";
- error( RtError::WARNING );
+ error( RtAudioError::WARNING );
goto unlock;
}
@@ -7200,7 +9508,7 @@ void RtApiOss :: callbackEvent()
if ( doStopStream == 1 ) this->stopStream();
}
-extern "C" void *ossCallbackHandler( void *ptr )
+static void *ossCallbackHandler( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiOss *object = (RtApiOss *) info->object;
@@ -7226,20 +9534,41 @@ extern "C" void *ossCallbackHandler( void *ptr )
// This method can be modified to control the behavior of error
// message printing.
-void RtApi :: error( RtError::Type type )
+void RtApi :: error( RtAudioError::Type type )
{
errorStream_.str(""); // clear the ostringstream
- if ( type == RtError::WARNING && showWarnings_ == true )
+
+ 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
- throw( RtError( errorText_, type ) );
+ 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( RtError::INVALID_USE );
+ error( RtAudioError::INVALID_USE );
}
}
@@ -7258,6 +9587,7 @@ void RtApi :: clearStreamInfo()
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;
@@ -7283,16 +9613,17 @@ unsigned int RtApi :: formatBytes( RtAudioFormat format )
{
if ( format == RTAUDIO_SINT16 )
return 2;
- else if ( format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
- format == RTAUDIO_FLOAT32 )
+ 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( RtError::WARNING );
+ error( RtAudioError::WARNING );
return 0;
}
@@ -7381,7 +9712,7 @@ 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 upper three bytes of a 32-bit integer.
+ // 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 &&
@@ -7420,11 +9751,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ 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]] & 0x00ffffff);
+ out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]].asInt());
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
@@ -7498,11 +9829,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ 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]] & 0x00ffffff);
+ out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]].asInt());
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
@@ -7570,10 +9901,10 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ 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]];
+ out[info.outOffset[j]] = (Int32) in[info.inOffset[j]].asInt();
out[info.outOffset[j]] <<= 8;
}
in += info.inJump;
@@ -7613,13 +9944,13 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}
else if (info.outFormat == RTAUDIO_SINT24) {
- Int32 *out = (Int32 *)outBuffer;
+ 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]];
- out[info.outOffset[j]] <<= 16;
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 16);
+ //out[info.outOffset[j]] <<= 16;
}
in += info.inJump;
out += info.outJump;
@@ -7629,8 +9960,8 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
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]] <<= 8;
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 8);
+ //out[info.outOffset[j]] <<= 8;
}
in += info.inJump;
out += info.outJump;
@@ -7638,7 +9969,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT24) {
// Channel compensation and/or (de)interleaving only.
- Int32 *in = (Int32 *)inBuffer;
+ 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]];
@@ -7651,8 +9982,8 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
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]];
- out[info.outOffset[j]] >>= 8;
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] >> 8);
+ //out[info.outOffset[j]] >>= 8;
}
in += info.inJump;
out += info.outJump;
@@ -7704,10 +10035,10 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ 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]] >> 8) & 0x0000ffff);
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]].asInt() >> 8);
}
in += info.inJump;
out += info.outJump;
@@ -7768,10 +10099,10 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ 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]] >> 16) & 0x000000ff);
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]].asInt() >> 16);
}
in += info.inJump;
out += info.outJump;
@@ -7810,9 +10141,9 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}
- //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)); }
+//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 )
{
@@ -7831,8 +10162,7 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat
ptr += 2;
}
}
- else if ( format == RTAUDIO_SINT24 ||
- format == RTAUDIO_SINT32 ||
+ else if ( format == RTAUDIO_SINT32 ||
format == RTAUDIO_FLOAT32 ) {
for ( unsigned int i=0; i<samples; i++ ) {
// Swap 1st and 4th bytes.
@@ -7850,6 +10180,17 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat
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
diff --git a/drivers/rtaudio/RtAudio.h b/drivers/rtaudio/RtAudio.h
index 03924450b9..7d45d36529 100644
--- a/drivers/rtaudio/RtAudio.h
+++ b/drivers/rtaudio/RtAudio.h
@@ -10,10 +10,17 @@
#elif defined(WINDOWS_ENABLED)
+#if defined(WINRT_ENABLED)
+
+#define __RTAUDIO_DUMMY__
+
+#else
+
#define __WINDOWS_DS__
#endif
+#endif
/************************************************************************/
/*! \class RtAudio
@@ -22,12 +29,12 @@
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 and ASIO) operating systems.
+ (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-2009 Gary P. Scavone
+ 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
@@ -59,14 +66,15 @@
\file RtAudio.h
*/
-// RtAudio: Version 4.0.6
-
#ifndef __RTAUDIO_H
#define __RTAUDIO_H
+#define RTAUDIO_VERSION "4.1.1"
+
#include <string>
#include <vector>
-#include "RtError.h"
+#include <exception>
+#include <iostream>
/*! \typedef typedef unsigned long RtAudioFormat;
\brief RtAudio data format type.
@@ -79,7 +87,7 @@
- \e RTAUDIO_SINT8: 8-bit signed integer.
- \e RTAUDIO_SINT16: 16-bit signed integer.
- - \e RTAUDIO_SINT24: Upper 3 bytes of 32-bit signed integer.
+ - \e RTAUDIO_SINT24: 24-bit signed integer.
- \e RTAUDIO_SINT32: 32-bit signed integer.
- \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0.
- \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0.
@@ -87,7 +95,7 @@
typedef unsigned long RtAudioFormat;
static const RtAudioFormat RTAUDIO_SINT8 = 0x1; // 8-bit signed integer.
static const RtAudioFormat RTAUDIO_SINT16 = 0x2; // 16-bit signed integer.
-static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // Lower 3 bytes of 32-bit signed integer.
+static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // 24-bit signed integer.
static const RtAudioFormat RTAUDIO_SINT32 = 0x8; // 32-bit signed integer.
static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0.
static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0.
@@ -101,6 +109,7 @@ static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/mi
- \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved).
- \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency.
- \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use.
+ - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only).
By default, RtAudio streams pass and receive audio data from the
client in an interleaved format. By passing the
@@ -128,12 +137,17 @@ static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/mi
If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt
to select realtime scheduling (round-robin) for the callback thread.
+
+ If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to
+ open the "default" PCM device when using the ALSA API. Note that this
+ will override any specified input or output device id.
*/
typedef unsigned int RtAudioStreamFlags;
static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1; // Use non-interleaved buffers (default = interleaved).
static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2; // Attempt to set stream parameters for lowest possible latency.
static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4; // Attempt grab device and prevent use by others.
static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread.
+static const RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT = 0x10; // Use the "default" PCM device (ALSA only).
/*! \typedef typedef unsigned long RtAudioStreamStatus;
\brief RtAudio stream status (over- or underflow) flags.
@@ -195,6 +209,63 @@ typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer,
RtAudioStreamStatus status,
void *userData );
+/************************************************************************/
+/*! \class RtAudioError
+ \brief Exception handling class for RtAudio.
+
+ The RtAudioError class is quite simple but it does allow errors to be
+ "caught" by RtAudioError::Type. See the RtAudio documentation to know
+ which methods can throw an RtAudioError.
+*/
+/************************************************************************/
+
+class RtAudioError : public std::exception
+{
+ public:
+ //! Defined RtAudioError types.
+ enum Type {
+ WARNING, /*!< A non-critical error. */
+ DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */
+ UNSPECIFIED, /*!< The default, unspecified error type. */
+ NO_DEVICES_FOUND, /*!< No devices found on system. */
+ INVALID_DEVICE, /*!< An invalid device ID was specified. */
+ MEMORY_ERROR, /*!< An error occured during memory allocation. */
+ INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
+ INVALID_USE, /*!< The function was called incorrectly. */
+ DRIVER_ERROR, /*!< A system driver error occured. */
+ SYSTEM_ERROR, /*!< A system error occured. */
+ THREAD_ERROR /*!< A thread error occured. */
+ };
+
+ //! The constructor.
+ RtAudioError( const std::string& message, Type type = RtAudioError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
+
+ //! The destructor.
+ virtual ~RtAudioError( void ) throw() {}
+
+ //! Prints thrown error message to stderr.
+ virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
+
+ //! Returns the thrown error message type.
+ virtual const Type& getType(void) const throw() { return type_; }
+
+ //! Returns the thrown error message string.
+ virtual const std::string& getMessage(void) const throw() { return message_; }
+
+ //! Returns the thrown error message as a c-style string.
+ virtual const char* what( void ) const throw() { return message_.c_str(); }
+
+ protected:
+ std::string message_;
+ Type type_;
+};
+
+//! RtAudio error callback function prototype.
+/*!
+ \param type Type of error.
+ \param errorText Error description.
+ */
+typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string &errorText );
// **************************************************************** //
//
@@ -219,9 +290,11 @@ class RtAudio
enum Api {
UNSPECIFIED, /*!< Search for a working compiled API. */
LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */
+ LINUX_PULSE, /*!< The Linux PulseAudio API. */
LINUX_OSS, /*!< The Linux Open Sound System API. */
UNIX_JACK, /*!< The Jack Low-Latency Audio Server API. */
MACOSX_CORE, /*!< Macintosh OS-X Core Audio API. */
+ WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */
WINDOWS_ASIO, /*!< The Steinberg Audio Stream I/O API. */
WINDOWS_DS, /*!< The Microsoft Direct Sound API. */
RTAUDIO_DUMMY /*!< A compilable but non-functional API. */
@@ -237,12 +310,13 @@ class RtAudio
bool isDefaultOutput; /*!< true if this is the default output device. */
bool isDefaultInput; /*!< true if this is the default input device. */
std::vector<unsigned int> sampleRates; /*!< Supported sample rates (queried from list of standard rates). */
+ unsigned int preferredSampleRate; /*!< Preferred sample rate, eg. for WASAPI the system sample rate. */
RtAudioFormat nativeFormats; /*!< Bit mask of supported data formats. */
// Default constructor.
DeviceInfo()
:probed(false), outputChannels(0), inputChannels(0), duplexChannels(0),
- isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {}
+ isDefaultOutput(false), isDefaultInput(false), preferredSampleRate(0), nativeFormats(0) {}
};
//! The structure for specifying input or ouput stream parameters.
@@ -265,6 +339,7 @@ class RtAudio
- \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency.
- \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use.
- \e RTAUDIO_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread.
+ - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only).
By default, RtAudio streams pass and receive audio data from the
client in an interleaved format. By passing the
@@ -293,7 +368,11 @@ class RtAudio
If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt
to select realtime scheduling (round-robin) for the callback thread.
The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME
- flag is set. It defines the thread's realtime priority.
+ flag is set. It defines the thread's realtime priority.
+
+ If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to
+ open the "default" PCM device when using the ALSA API. Note that this
+ will override any specified input or output device id.
The \c numberOfBuffers parameter can be used to control stream
latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs
@@ -309,7 +388,7 @@ class RtAudio
RtAudio with Jack, each instance must have a unique client name.
*/
struct StreamOptions {
- RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). */
+ RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_ALSA_USE_DEFAULT). */
unsigned int numberOfBuffers; /*!< Number of stream buffers. */
std::string streamName; /*!< A stream name (currently used only in Jack). */
int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */
@@ -319,6 +398,9 @@ class RtAudio
: flags(0), numberOfBuffers(0), priority(0) {}
};
+ //! A static function to determine the current RtAudio version.
+ static std::string getVersion( void ) throw();
+
//! A static function to determine the available compiled audio APIs.
/*!
The values returned in the std::vector can be compared against
@@ -329,14 +411,14 @@ class RtAudio
//! The class constructor.
/*!
- The constructor performs minor initialization tasks. No exceptions
- can be thrown.
+ The constructor performs minor initialization tasks. An exception
+ can be thrown if no API support is compiled.
If no API argument is specified and multiple API support has been
compiled, the default order of use is JACK, ALSA, OSS (Linux
systems) and ASIO, DS (Windows systems).
*/
- RtAudio( RtAudio::Api api=UNSPECIFIED ) throw();
+ RtAudio( RtAudio::Api api=UNSPECIFIED );
//! The destructor.
/*!
@@ -360,7 +442,7 @@ class RtAudio
/*!
Any device integer between 0 and getDeviceCount() - 1 is valid.
- If an invalid argument is provided, an RtError (type = INVALID_USE)
+ If an invalid argument is provided, an RtAudioError (type = INVALID_USE)
will be thrown. If a device is busy or otherwise unavailable, the
structure member "probed" will have a value of "false" and all
other members are undefined. If the specified device is the
@@ -391,9 +473,9 @@ class RtAudio
//! A public function for opening a stream with the specified parameters.
/*!
- An RtError (type = SYSTEM_ERROR) is thrown if a stream cannot be
+ An RtAudioError (type = SYSTEM_ERROR) is thrown if a stream cannot be
opened with the specified parameters or an error occurs during
- processing. An RtError (type = INVALID_USE) is thrown if any
+ processing. An RtAudioError (type = INVALID_USE) is thrown if any
invalid device ID or channel number parameters are specified.
\param outputParameters Specifies output stream parameters to use
@@ -426,12 +508,14 @@ class RtAudio
chosen. If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the
lowest allowable value is used. The actual value used is
returned via the structure argument. The parameter is API dependent.
+ \param errorCallback A client-defined function that will be invoked
+ when an error has occured.
*/
void openStream( RtAudio::StreamParameters *outputParameters,
RtAudio::StreamParameters *inputParameters,
RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames, RtAudioCallback callback,
- void *userData = NULL, RtAudio::StreamOptions *options = NULL );
+ void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL );
//! A function that closes a stream and frees any associated stream memory.
/*!
@@ -442,8 +526,8 @@ class RtAudio
//! A function that starts a stream.
/*!
- An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
- during processing. An RtError (type = INVALID_USE) is thrown if a
+ An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
+ during processing. An RtAudioError (type = INVALID_USE) is thrown if a
stream is not open. A warning is issued if the stream is already
running.
*/
@@ -451,8 +535,8 @@ class RtAudio
//! Stop a stream, allowing any samples remaining in the output queue to be played.
/*!
- An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
- during processing. An RtError (type = INVALID_USE) is thrown if a
+ An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
+ during processing. An RtAudioError (type = INVALID_USE) is thrown if a
stream is not open. A warning is issued if the stream is already
stopped.
*/
@@ -460,8 +544,8 @@ class RtAudio
//! Stop a stream, discarding any samples remaining in the input/output queue.
/*!
- An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
- during processing. An RtError (type = INVALID_USE) is thrown if a
+ An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
+ during processing. An RtAudioError (type = INVALID_USE) is thrown if a
stream is not open. A warning is issued if the stream is already
stopped.
*/
@@ -475,17 +559,23 @@ class RtAudio
//! Returns the number of elapsed seconds since the stream was started.
/*!
- If a stream is not open, an RtError (type = INVALID_USE) will be thrown.
+ If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown.
*/
double getStreamTime( void );
+ //! Set the stream time to a time in seconds greater than or equal to 0.0.
+ /*!
+ If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown.
+ */
+ void setStreamTime( double time );
+
//! Returns the internal stream latency in sample frames.
/*!
The stream latency refers to delay in audio input and/or output
caused by internal buffering by the audio system and/or hardware.
For duplex streams, the returned value will represent the sum of
the input and output latencies. If a stream is not open, an
- RtError (type = INVALID_USE) will be thrown. If the API does not
+ RtAudioError (type = INVALID_USE) will be thrown. If the API does not
report latency, the return value will be zero.
*/
long getStreamLatency( void );
@@ -494,7 +584,7 @@ class RtAudio
/*!
On some systems, the sample rate used may be slightly different
than that specified in the stream parameters. If a stream is not
- open, an RtError (type = INVALID_USE) will be thrown.
+ open, an RtAudioError (type = INVALID_USE) will be thrown.
*/
unsigned int getStreamSampleRate( void );
@@ -508,14 +598,18 @@ class RtAudio
};
// Operating system dependent thread functionality.
-#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
+#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__)
+
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
#include <windows.h>
#include <process.h>
- typedef unsigned long ThreadHandle;
+ typedef uintptr_t ThreadHandle;
typedef CRITICAL_SECTION StreamMutex;
-#elif defined(__LINUX_ALSA__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
+#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
// Using pthread library for various flavors of unix.
#include <pthread.h>
@@ -538,12 +632,15 @@ struct CallbackInfo {
ThreadHandle thread;
void *callback;
void *userData;
+ void *errorCallback;
void *apiInfo; // void pointer for API specific callback information
bool isRunning;
+ bool doRealtime;
+ int priority;
// Default constructor.
CallbackInfo()
- :object(0), callback(0), userData(0), apiInfo(0), isRunning(false) {}
+ :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false) {}
};
// **************************************************************** //
@@ -556,10 +653,40 @@ struct CallbackInfo {
// Note that RtApi is an abstract base class and cannot be
// explicitly instantiated. The class RtAudio will create an
// instance of an RtApi subclass (RtApiOss, RtApiAlsa,
-// RtApiJack, RtApiCore, RtApiAl, RtApiDs, or RtApiAsio).
+// RtApiJack, RtApiCore, RtApiDs, or RtApiAsio).
//
// **************************************************************** //
+#pragma pack(push, 1)
+class S24 {
+
+ protected:
+ unsigned char c3[3];
+
+ public:
+ S24() {}
+
+ S24& operator = ( const int& i ) {
+ c3[0] = (i & 0x000000ff);
+ c3[1] = (i & 0x0000ff00) >> 8;
+ c3[2] = (i & 0x00ff0000) >> 16;
+ return *this;
+ }
+
+ S24( const S24& v ) { *this = v; }
+ S24( const double& d ) { *this = (int) d; }
+ S24( const float& f ) { *this = (int) f; }
+ S24( const signed short& s ) { *this = (int) s; }
+ S24( const char& c ) { *this = (int) c; }
+
+ int asInt() {
+ int i = c3[0] | (c3[1] << 8) | (c3[2] << 16);
+ if (i & 0x800000) i |= ~0xffffff;
+ return i;
+ }
+};
+#pragma pack(pop)
+
#if defined( HAVE_GETTIMEOFDAY )
#include <sys/time.h>
#endif
@@ -581,7 +708,8 @@ public:
RtAudio::StreamParameters *inputParameters,
RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames, RtAudioCallback callback,
- void *userData, RtAudio::StreamOptions *options );
+ void *userData, RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback );
virtual void closeStream( void );
virtual void startStream( void ) = 0;
virtual void stopStream( void ) = 0;
@@ -589,9 +717,10 @@ public:
long getStreamLatency( void );
unsigned int getStreamSampleRate( void );
virtual double getStreamTime( void );
- bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; };
- bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; };
- void showWarnings( bool value ) { showWarnings_ = value; };
+ virtual void setStreamTime( double time );
+ bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; }
+ bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; }
+ void showWarnings( bool value ) { showWarnings_ = value; }
protected:
@@ -603,6 +732,7 @@ protected:
enum StreamState {
STREAM_STOPPED,
+ STREAM_STOPPING,
STREAM_RUNNING,
STREAM_CLOSED = -50
};
@@ -657,6 +787,7 @@ protected:
:apiHandle(0), deviceBuffer(0) { device[0] = 11111; device[1] = 11111; }
};
+ typedef S24 Int24;
typedef signed short Int16;
typedef signed int Int32;
typedef float Float32;
@@ -666,6 +797,7 @@ protected:
std::string errorText_;
bool showWarnings_;
RtApiStream stream_;
+ bool firstErrorOccurred_;
/*!
Protected, api-specific method that attempts to open a device
@@ -686,13 +818,13 @@ protected:
void clearStreamInfo();
/*!
- Protected common method that throws an RtError (type =
+ Protected common method that throws an RtAudioError (type =
INVALID_USE) if a stream is not open.
*/
void verifyStream( void );
//! Protected common error method to allow global control over error handling.
- void error( RtError::Type type );
+ void error( RtAudioError::Type type );
/*!
Protected method used to perform format, channel number, and/or interleaving
@@ -728,8 +860,9 @@ inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); }
inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); }
inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
-inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); };
+inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); }
inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
+inline void RtAudio :: setStreamTime( double time ) { return rtapi_->setStreamTime( time ); }
inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); }
// RtApi Subclass prototypes.
@@ -744,7 +877,7 @@ public:
RtApiCore();
~RtApiCore();
- RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; };
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
unsigned int getDefaultOutputDevice( void );
@@ -782,7 +915,7 @@ public:
RtApiJack();
~RtApiJack();
- RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; };
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -815,7 +948,7 @@ public:
RtApiAsio();
~RtApiAsio();
- RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; };
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -851,7 +984,7 @@ public:
RtApiDs();
~RtApiDs();
- RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; };
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; }
unsigned int getDeviceCount( void );
unsigned int getDefaultOutputDevice( void );
unsigned int getDefaultInputDevice( void );
@@ -873,6 +1006,7 @@ public:
bool coInitialized_;
bool buffersRolling;
long duplexPrerollBytes;
+ std::vector<struct DsDevice> dsDevices;
bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
@@ -881,6 +1015,43 @@ public:
#endif
+#if defined(__WINDOWS_WASAPI__)
+
+struct IMMDeviceEnumerator;
+
+class RtApiWasapi : public RtApi
+{
+public:
+ RtApiWasapi();
+ ~RtApiWasapi();
+
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_WASAPI; }
+ unsigned int getDeviceCount( void );
+ RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+ unsigned int getDefaultOutputDevice( void );
+ unsigned int getDefaultInputDevice( void );
+ void closeStream( void );
+ void startStream( void );
+ void stopStream( void );
+ void abortStream( void );
+
+private:
+ bool coInitialized_;
+ IMMDeviceEnumerator* deviceEnumerator_;
+
+ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int* bufferSize,
+ RtAudio::StreamOptions* options );
+
+ static DWORD WINAPI runWasapiThread( void* wasapiPtr );
+ static DWORD WINAPI stopWasapiThread( void* wasapiPtr );
+ static DWORD WINAPI abortWasapiThread( void* wasapiPtr );
+ void wasapiThread();
+};
+
+#endif
+
#if defined(__LINUX_ALSA__)
class RtApiAlsa: public RtApi
@@ -889,7 +1060,7 @@ public:
RtApiAlsa();
~RtApiAlsa();
- RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; };
+ RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -915,6 +1086,38 @@ public:
#endif
+#if defined(__LINUX_PULSE__)
+
+class RtApiPulse: public RtApi
+{
+public:
+ ~RtApiPulse();
+ RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }
+ unsigned int getDeviceCount( void );
+ RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+ void closeStream( void );
+ void startStream( void );
+ void stopStream( void );
+ void abortStream( void );
+
+ // This function is intended for internal use only. It must be
+ // public because it is called by the internal callback handler,
+ // which is not a member of RtAudio. External use of this function
+ // will most likely produce highly undesireable results!
+ void callbackEvent( void );
+
+ private:
+
+ std::vector<RtAudio::DeviceInfo> devices_;
+ void saveDeviceInfo( void );
+ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int *bufferSize,
+ RtAudio::StreamOptions *options );
+};
+
+#endif
+
#if defined(__LINUX_OSS__)
class RtApiOss: public RtApi
@@ -923,7 +1126,7 @@ public:
RtApiOss();
~RtApiOss();
- RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; };
+ RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -953,21 +1156,21 @@ class RtApiDummy: public RtApi
{
public:
- RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtError::WARNING ); };
- RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; };
- unsigned int getDeviceCount( void ) { return 0; };
- RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; return info; };
- void closeStream( void ) {};
- void startStream( void ) {};
- void stopStream( void ) {};
- void abortStream( void ) {};
+ RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtAudioError::WARNING ); }
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; }
+ unsigned int getDeviceCount( void ) { return 0; }
+ RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; }
+ void closeStream( void ) {}
+ void startStream( void ) {}
+ void stopStream( void ) {}
+ void abortStream( void ) {}
private:
- bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options ) { return false; };
+ bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
+ unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
+ RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
+ RtAudio::StreamOptions * /*options*/ ) { return false; }
};
#endif
@@ -982,4 +1185,5 @@ public:
// 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 ac8f502178..7bee495869 100644
--- a/drivers/rtaudio/audio_driver_rtaudio.cpp
+++ b/drivers/rtaudio/audio_driver_rtaudio.cpp
@@ -115,7 +115,7 @@ Error AudioDriverRtAudio::init() {
active=true;
break;
- } catch ( RtError& e ) {
+ } catch ( RtAudioError& e ) {
// try with less channels
ERR_PRINT("Unable to open audio, retrying with fewer channels..");
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/squish/image_compress_squish.cpp b/drivers/squish/image_compress_squish.cpp
index 1d71f51db4..2c520bd1e9 100644
--- a/drivers/squish/image_compress_squish.cpp
+++ b/drivers/squish/image_compress_squish.cpp
@@ -18,18 +18,19 @@ void image_compress_squish(Image *p_image) {
if (p_image->get_format()>=Image::FORMAT_BC1)
return; //do not compress, already compressed
-
- Image::AlphaMode alpha = p_image->detect_alpha();
- Image::Format target_format;
int shift=0;
int squish_comp=squish::kColourRangeFit;
- switch(alpha) {
+ Image::Format target_format;
- case Image::ALPHA_NONE: target_format = Image::FORMAT_BC1; shift=1; squish_comp|=squish::kDxt1; break;
- case Image::ALPHA_BIT: target_format = Image::FORMAT_BC2; squish_comp|=squish::kDxt3; break;
- case Image::ALPHA_BLEND: target_format = Image::FORMAT_BC3; squish_comp|=squish::kDxt5; break;
- }
+ if (p_image->get_format()==Image::FORMAT_GRAYSCALE_ALPHA) {
+ //compressed normalmap
+ target_format = Image::FORMAT_BC3; squish_comp|=squish::kDxt5;;
+ } else if (p_image->detect_alpha()!=Image::ALPHA_NONE) {
+ target_format = Image::FORMAT_BC2; squish_comp|=squish::kDxt3;;
+ } else {
+ target_format = Image::FORMAT_BC1; shift=1; squish_comp|=squish::kDxt1;;
+ }
p_image->convert(Image::FORMAT_RGBA); //always expects rgba
diff --git a/drivers/theora/SCsub b/drivers/theora/SCsub
index d3e5838276..fa85b49804 100644
--- a/drivers/theora/SCsub
+++ b/drivers/theora/SCsub
@@ -1,4 +1,3 @@
-
Import('env')
sources = [
@@ -32,6 +31,37 @@ sources = [
"theora/video_stream_theora.cpp",
]
+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/codec.h b/drivers/theora/codec.h
index 5c2669630c..9b816e5cfd 100644
--- a/drivers/theora/codec.h
+++ b/drivers/theora/codec.h
@@ -15,7 +15,7 @@
********************************************************************/
-/**\mainpage
+/**\file
*
* \section intro Introduction
*
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 be0807afd2..fe248bc911 100644
--- a/drivers/theora/video_stream_theora.cpp
+++ b/drivers/theora/video_stream_theora.cpp
@@ -3,48 +3,47 @@
#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;
-}
+ 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);
+ }
-Image VideoStreamTheora::peek_frame() const {
+ } while(read==0);
- if (frames_pending == 0)
- return Image();
- return Image(size.x, size.y, 0, format, frame_data);
-};
+ return read;
-Image VideoStreamTheora::pop_frame() {
+#else
- Image ret = peek_frame();
- frames_pending = 0;
+ int bytes=file->get_buffer((uint8_t*)buffer, 4096);
+ ogg_sync_wrote(&oy,bytes);
+ return(bytes);
- return ret;
-};
-
-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;
+ }
+
+ Image img(size.x,size.y,0,Image::FORMAT_RGBA,frame_data); //zero copy image creation
- format = Image::FORMAT_RGBA;
+ 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,364 @@ 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;
+}
+
+void VideoStreamPlaybackTheora::update(float p_delta) {
if (!playing) {
//printf("not playing\n");
return;
};
- double ctime =AudioServer::get_singleton()->get_mix_time();
+#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 (last_update_time) {
- double delta = (ctime-last_update_time);
- time+=delta;
- //print_line("delta: "+rtos(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;
+ while (vorbis_p) {
+ int ret;
+ float **pcm;
- } else {
+ bool buffer_full=false;
+
+ /* if there's pending, decoded audio, grab it */
+ if ((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0) {
+
+
+
+ const int AUXBUF_LEN=4096;
+ int to_read = ret;
+ int16_t aux_buffer[AUXBUF_LEN];
+
+ while(to_read) {
- /* 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);
+ 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
+ }
+
+
+ }
+
+
+ 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));
}
- } else { /* we need more data; break out to suck in another page */
- //printf("need moar data\n");
+
+ //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");
+ 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 {
+
+ break;
}
+ }
+#ifdef THEORA_USE_THREAD_STREAMING
+ if (file && thread_eof && ring_buffer.data_left()==0) {
+#else
+ if (file && /*!videobuf_ready && */ 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;
};
-bool VideoStreamTheora::is_paused(bool p_paused) const {
+bool VideoStreamPlaybackTheora::is_paused(bool p_paused) const {
return playing;
};
-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 +823,52 @@ VideoStreamTheora::VideoStreamTheora() {
playing = false;
frames_pending = 0;
videobuf_time = 0;
- last_update_time =0;
+
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,15 +878,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
+
diff --git a/drivers/theora/video_stream_theora.h b/drivers/theora/video_stream_theora.h
index b408f9db13..c15ef31cfc 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,37 @@ 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;
- 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 +118,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/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 e63a248e9e..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 452d791d96..0c0867e030 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -87,7 +87,7 @@ bool DirAccessUnix::dir_exists(String p_dir) {
if (p_dir.is_rel_path())
- p_dir=current_dir+"/"+p_dir;
+ p_dir=get_current_dir().plus_file(p_dir);
else
p_dir=fix_path(p_dir);
@@ -161,6 +161,7 @@ String DirAccessUnix::get_next() {
}
+ _cishidden=(fname!="." && fname!=".." && fname.begins_with("."));
@@ -173,6 +174,11 @@ bool DirAccessUnix::current_is_dir() const {
return _cisdir;
}
+bool DirAccessUnix::current_is_hidden() const {
+
+ return _cishidden;
+}
+
void DirAccessUnix::list_dir_end() {
@@ -272,9 +278,16 @@ String DirAccessUnix::get_current_dir() {
Error DirAccessUnix::rename(String p_path,String p_new_path) {
- p_path=fix_path(p_path);
- p_new_path=fix_path(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 DirAccessUnix::remove(String p_path) {
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index 119cb5c3f4..3091e01511 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -50,12 +50,14 @@ class DirAccessUnix : public DirAccess {
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(); ///<
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 239e41be4c..8e70ecc932 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -63,8 +63,8 @@ Error FileAccessUnix::_open(const String& p_path, int p_mode_flags) {
fclose(f);
f=NULL;
- String path=fix_path(p_path);
- //printf("opening %ls\n", path.c_str());
+ 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);
const char* mode_string;
@@ -74,7 +74,7 @@ Error FileAccessUnix::_open(const String& p_path, int p_mode_flags) {
else if (p_mode_flags==WRITE)
mode_string="wb";
else if (p_mode_flags==READ_WRITE)
- mode_string="wb+";
+ mode_string="rb+";
else
return ERR_INVALID_PARAMETER;
@@ -114,6 +114,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 +243,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 0dedfce6ac..6c41a51ec5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 24b18a14f7..989aba52bb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,27 +28,40 @@
/*************************************************************************/
#include "ip_unix.h"
-#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
+#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) && !defined(WINRT_ENABLED)
#ifdef WINDOWS_ENABLED
-#define WINVER 0x0600
-#include <ws2tcpip.h>
-#include <winsock2.h>
-#include <windows.h>
-#include <stdio.h>
-#include <iphlpapi.h>
+ #ifdef WINRT_ENABLED
+ #include <ws2tcpip.h>
+ #include <winsock2.h>
+ #include <windows.h>
+ #include <stdio.h>
+ #else
+ #define WINVER 0x0600
+ #include <ws2tcpip.h>
+ #include <winsock2.h>
+ #include <windows.h>
+ #include <stdio.h>
+ #include <iphlpapi.h>
+ #endif
#else
-#include <netdb.h>
-#ifdef ANDROID_ENABLED
-#include "platform/android/ifaddrs_android.h"
-#else
-#include <ifaddrs.h>
+ #include <netdb.h>
+ #ifdef ANDROID_ENABLED
+ #include "platform/android/ifaddrs_android.h"
+ #else
+ #ifdef __FreeBSD__
+ #include <sys/types.h>
+ #endif
+ #include <ifaddrs.h>
+ #endif
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+ #ifdef __FreeBSD__
+ #include <netinet/in.h>
+ #endif
#endif
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#endif
IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) {
struct hostent *he;
@@ -66,6 +79,14 @@ IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) {
#if defined(WINDOWS_ENABLED)
+#if defined(WINRT_ENABLED)
+
+void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
+
+
+};
+#else
+
void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
ULONG buf_size = 1024;
@@ -119,6 +140,7 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
memfree(addrs);
};
+#endif
#else
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index 2fd5cf964b..5798ac8137 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/memory_pool_static_malloc.cpp b/drivers/unix/memory_pool_static_malloc.cpp
index fa1266b2df..e0bab27a63 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,10 +40,9 @@
* so BE CAREFUL!
*/
-
void* MemoryPoolStaticMalloc::alloc(size_t p_bytes,const char *p_description) {
- #if DFAULT_ALIGNMENT == 1
+ #if DEFAULT_ALIGNMENT == 1
return _alloc(p_bytes, p_description);
@@ -123,7 +122,7 @@ void* MemoryPoolStaticMalloc::_alloc(size_t p_bytes,const char *p_description) {
void* MemoryPoolStaticMalloc::realloc(void *p_memory,size_t p_bytes) {
- #if DFAULT_ALIGNMENT == 1
+ #if DEFAULT_ALIGNMENT == 1
return _realloc(p_memory,p_bytes);
#else
@@ -154,7 +153,7 @@ void* MemoryPoolStaticMalloc::_realloc(void *p_memory,size_t p_bytes) {
return alloc( p_bytes );
}
- if (p_bytes<=0) {
+ if (p_bytes==0) {
this->free(p_memory);
ERR_FAIL_COND_V( p_bytes < 0 , NULL );
@@ -172,7 +171,6 @@ void* MemoryPoolStaticMalloc::_realloc(void *p_memory,size_t p_bytes) {
bool single_element = (ringptr->next == ringptr) && (ringptr->prev == ringptr);
bool is_list = ( ringlist == ringptr );
-
RingPtr *new_ringptr=(RingPtr*)::realloc(ringptr, p_bytes+sizeof(RingPtr));
ERR_FAIL_COND_V( new_ringptr == 0, NULL ); /// reallocation failed
@@ -213,7 +211,7 @@ void MemoryPoolStaticMalloc::free(void *p_ptr) {
ERR_FAIL_COND( !MemoryPoolStatic::get_singleton());
- #if DFAULT_ALIGNMENT == 1
+ #if DEFAULT_ALIGNMENT == 1
_free(p_ptr);
#else
diff --git a/drivers/unix/memory_pool_static_malloc.h b/drivers/unix/memory_pool_static_malloc.h
index 626fec826e..a96259556d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/mutex_posix.cpp b/drivers/unix/mutex_posix.cpp
index 166dfa4b19..73563ea538 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/mutex_posix.h b/drivers/unix/mutex_posix.h
index 3496473688..9b50d7963e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 1af37e2a60..94a7b03f45 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -42,8 +42,11 @@
#include "dir_access_unix.h"
#include "tcp_server_posix.h"
#include "stream_peer_tcp_posix.h"
+#include "packet_peer_udp_posix.h"
-
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#endif
#include <stdarg.h>
#include <sys/time.h>
#include <sys/wait.h>
@@ -54,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]) {
- 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);
+extern bool _print_error_enabled;
- } 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);
+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 (!_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;
}
}
@@ -115,6 +134,7 @@ void OS_Unix::initialize_core() {
#ifndef NO_NETWORK
TCPServerPosix::make_default();
StreamPeerTCPPosix::make_default();
+ PacketPeerUDPPosix::make_default();
IP_Unix::make_default();
#endif
mempool_static = new MemoryPoolStaticMalloc;
@@ -213,31 +233,74 @@ uint64_t OS_Unix::get_unix_time() const {
return time(NULL);
};
+uint64_t OS_Unix::get_system_time_msec() const {
+ struct timeval tv_now;
+ gettimeofday(&tv_now, NULL);
+ //localtime(&tv_now.tv_usec);
+ //localtime((const long *)&tv_now.tv_usec);
+ uint64_t msec = uint64_t(tv_now.tv_sec)*1000+tv_now.tv_usec/1000;
+ return msec;
+}
+
-OS::Date OS_Unix::get_date() const {
+OS::Date OS_Unix::get_date(bool utc) const {
time_t t=time(NULL);
- struct tm *lt=localtime(&t);
+ struct tm *lt;
+ if (utc)
+ lt=gmtime(&t);
+ else
+ 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;
return ret;
}
-OS::Time OS_Unix::get_time() const {
-
+OS::Time OS_Unix::get_time(bool utc) const {
time_t t=time(NULL);
- struct tm *lt=localtime(&t);
+ struct tm *lt;
+ if (utc)
+ lt=gmtime(&t);
+ else
+ lt=localtime(&t);
Time ret;
ret.hour=lt->tm_hour;
ret.min=lt->tm_min;
ret.sec=lt->tm_sec;
+ get_time_zone_info();
return ret;
}
-
+
+OS::TimeZoneInfo OS_Unix::get_time_zone_info() const {
+ time_t t = time(NULL);
+ struct tm *lt = localtime(&t);
+ char name[16];
+ strftime(name, 16, "%Z", lt);
+ name[15] = 0;
+ TimeZoneInfo ret;
+ ret.name = name;
+
+ char bias_buf[16];
+ strftime(bias_buf, 16, "%z", lt);
+ int bias;
+ bias_buf[15] = 0;
+ sscanf(bias_buf, "%d", &bias);
+
+ // convert from ISO 8601 (1 minute=1, 1 hour=100) to minutes
+ int hour = (int)bias / 100;
+ int minutes = bias % 100;
+ if (bias < 0)
+ ret.bias = hour * 60 - minutes;
+ else
+ ret.bias = hour * 60 + minutes;
+
+ return ret;
+}
+
void OS_Unix::delay_usec(uint32_t p_usec) const {
usleep(p_usec);
@@ -303,7 +366,17 @@ Error OS_Unix::execute(const String& p_path, const List<String>& p_arguments,boo
args.push_back((char*)cs[i].get_data());// shitty C cast
args.push_back(0);
+#ifdef __FreeBSD__
+ if(p_path.find("/")) {
+ // exec name contains path so use it
+ execv(p_path.utf8().get_data(),&args[0]);
+ }else{
+ // use program name and search through PATH to find it
+ execvp(getprogname(),&args[0]);
+ }
+#else
execv(p_path.utf8().get_data(),&args[0]);
+#endif
// still alive? something failed..
fprintf(stderr,"**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n",p_path.utf8().get_data());
abort();
@@ -330,6 +403,12 @@ Error OS_Unix::execute(const String& p_path, const List<String>& p_arguments,boo
Error OS_Unix::kill(const ProcessID& p_pid) {
int ret = ::kill(p_pid,SIGKILL);
+ if (!ret) {
+ //avoid zombie process
+ int st;
+ ::waitpid(p_pid,&st,0);
+
+ }
return ret?ERR_INVALID_PARAMETER:OK;
}
@@ -382,9 +461,15 @@ String OS_Unix::get_data_dir() const {
String an = Globals::get_singleton()->get("application/name");
if (an!="") {
+
+
if (has_environment("HOME")) {
- return get_environment("HOME")+"/."+an;
+ bool use_godot = Globals::get_singleton()->get("application/use_shared_user_dir");
+ if (use_godot)
+ return get_environment("HOME")+"/.godot/app_userdata/"+an;
+ else
+ return get_environment("HOME")+"/."+an;
}
}
@@ -392,6 +477,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__
@@ -407,6 +500,12 @@ String OS_Unix::get_executable_path() const {
return OS::get_executable_path();
}
return b;
+#elif defined(__FreeBSD__)
+ char resolved_path[MAXPATHLEN];
+
+ realpath(OS::get_executable_path().utf8().get_data(), resolved_path);
+
+ return String(resolved_path);
#else
ERR_PRINT("Warning, don't know how to obtain executable path on this OS! Please override this function properly.");
return OS::get_executable_path();
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 1dcf0bd2fd..9ac18c9055 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -64,6 +64,8 @@ protected:
String stdin_buf;
+ String get_global_settings_path() const;
+
public:
@@ -88,10 +90,12 @@ public:
virtual String get_name();
- virtual Date get_date() const;
- virtual Time get_time() const;
+ virtual Date get_date(bool utc) const;
+ 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_msec() const;
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
@@ -109,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
new file mode 100644
index 0000000000..2111619080
--- /dev/null
+++ b/drivers/unix/packet_peer_udp_posix.cpp
@@ -0,0 +1,200 @@
+#include "packet_peer_udp_posix.h"
+
+#ifdef UNIX_ENABLED
+
+
+#include <errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <stdio.h>
+
+#ifndef NO_FCNTL
+ #ifdef __HAIKU__
+ #include <fcntl.h>
+ #else
+ #include <sys/fcntl.h>
+ #endif
+#else
+#include <sys/ioctl.h>
+#endif
+
+#ifdef JAVASCRIPT_ENABLED
+#include <arpa/inet.h>
+#endif
+
+
+int PacketPeerUDPPosix::get_available_packet_count() const {
+
+ Error err = const_cast<PacketPeerUDPPosix*>(this)->_poll(false);
+ if (err!=OK)
+ return 0;
+
+ return queue_count;
+}
+
+Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer,int &r_buffer_size) const{
+
+ Error err = const_cast<PacketPeerUDPPosix*>(this)->_poll(false);
+ if (err!=OK)
+ return err;
+ if (queue_count==0)
+ return ERR_UNAVAILABLE;
+
+ uint32_t size;
+ rb.read((uint8_t*)&packet_ip.host,4,true);
+ rb.read((uint8_t*)&packet_port,4,true);
+ rb.read((uint8_t*)&size,4,true);
+ rb.read(packet_buffer,size,true);
+ --queue_count;
+ *r_buffer=packet_buffer;
+ r_buffer_size=size;
+ return OK;
+
+}
+Error PacketPeerUDPPosix::put_packet(const uint8_t *p_buffer,int p_buffer_size){
+
+ int sock = _get_socket();
+ ERR_FAIL_COND_V( sock == -1, FAILED );
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(peer_port);
+ addr.sin_addr = *((struct in_addr*)&peer_addr.host);
+
+ errno = 0;
+ int err;
+
+ while ( (err = sendto(sock, p_buffer, p_buffer_size, 0, (struct sockaddr*)&addr, sizeof(addr))) != p_buffer_size) {
+
+ if (errno != EAGAIN) {
+ return FAILED;
+ }
+ }
+
+ return OK;
+}
+
+int PacketPeerUDPPosix::get_max_packet_size() const{
+
+ return 512; // uhm maybe not
+}
+
+Error PacketPeerUDPPosix::listen(int p_port, int p_recv_buffer_size){
+
+ close();
+ int sock = _get_socket();
+ if (sock == -1 )
+ return ERR_CANT_CREATE;
+ sockaddr_in addr = {0};
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(p_port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) {
+ close();
+ return ERR_UNAVAILABLE;
+ }
+ printf("UDP Connection listening on port %i bufsize %i \n", p_port,p_recv_buffer_size);
+ rb.resize(nearest_shift(p_recv_buffer_size));
+ return OK;
+}
+
+void PacketPeerUDPPosix::close(){
+
+ if (sockfd != -1)
+ ::close(sockfd);
+ sockfd=-1;
+ rb.resize(8);
+ queue_count=0;
+}
+
+
+Error PacketPeerUDPPosix::wait() {
+
+ return _poll(true);
+}
+
+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((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);
+ rb.write((uint8_t*)&ret, 4);
+ rb.write(recv_buffer, ret);
+ len = sizeof(struct sockaddr_in);
+ ++queue_count;
+ };
+
+
+ // TODO: Should ECONNRESET be handled here?
+ if (ret == 0 || (ret == -1 && errno != EAGAIN) ) {
+ close();
+ return FAILED;
+ };
+
+ return OK;
+}
+bool PacketPeerUDPPosix::is_listening() const{
+
+ return sockfd!=-1;
+}
+
+IP_Address PacketPeerUDPPosix::get_packet_address() const {
+
+ return packet_ip;
+}
+
+int PacketPeerUDPPosix::get_packet_port() const{
+
+ return packet_port;
+}
+
+int PacketPeerUDPPosix::_get_socket() {
+
+ if (sockfd != -1)
+ return sockfd;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ ERR_FAIL_COND_V( sockfd == -1, -1 );
+ //fcntl(sockfd, F_SETFL, O_NONBLOCK);
+
+ return sockfd;
+}
+
+
+void PacketPeerUDPPosix::set_send_address(const IP_Address& p_address,int p_port) {
+
+ peer_addr=p_address;
+ peer_port=p_port;
+}
+
+PacketPeerUDP* PacketPeerUDPPosix::_create() {
+
+ return memnew(PacketPeerUDPPosix);
+};
+
+void PacketPeerUDPPosix::make_default() {
+
+ PacketPeerUDP::_create = PacketPeerUDPPosix::_create;
+};
+
+
+PacketPeerUDPPosix::PacketPeerUDPPosix() {
+
+ sockfd=-1;
+ packet_port=0;
+ queue_count=0;
+ peer_port=0;
+}
+
+PacketPeerUDPPosix::~PacketPeerUDPPosix() {
+
+ close();
+}
+#endif
diff --git a/drivers/unix/packet_peer_udp_posix.h b/drivers/unix/packet_peer_udp_posix.h
new file mode 100644
index 0000000000..b14568eb5f
--- /dev/null
+++ b/drivers/unix/packet_peer_udp_posix.h
@@ -0,0 +1,57 @@
+#ifndef PACKET_PEER_UDP_POSIX_H
+#define PACKET_PEER_UDP_POSIX_H
+
+#ifdef UNIX_ENABLED
+
+#include "io/packet_peer_udp.h"
+#include "ring_buffer.h"
+
+class PacketPeerUDPPosix : public PacketPeerUDP {
+
+
+ enum {
+ PACKET_BUFFER_SIZE=65536
+ };
+
+ mutable RingBuffer<uint8_t> rb;
+ uint8_t recv_buffer[PACKET_BUFFER_SIZE];
+ mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE];
+ IP_Address packet_ip;
+ int packet_port;
+ mutable int queue_count;
+ int sockfd;
+
+ IP_Address peer_addr;
+ int peer_port;
+
+ _FORCE_INLINE_ int _get_socket();
+
+ static PacketPeerUDP* _create();
+ virtual Error _poll(bool p_block);
+
+public:
+
+ virtual int get_available_packet_count() const;
+ virtual Error get_packet(const uint8_t **r_buffer,int &r_buffer_size) const;
+ virtual Error put_packet(const uint8_t *p_buffer,int p_buffer_size);
+
+ virtual int get_max_packet_size() const;
+
+ virtual Error listen(int p_port,int p_recv_buffer_size=65536);
+ virtual void close();
+ virtual Error wait();
+ virtual bool is_listening() const;
+
+ virtual IP_Address get_packet_address() const;
+ virtual int get_packet_port() const;
+
+ virtual void set_send_address(const IP_Address& p_address,int p_port);
+
+ static void make_default();
+
+ PacketPeerUDPPosix();
+ ~PacketPeerUDPPosix();
+};
+
+#endif // PACKET_PEER_UDP_POSIX_H
+#endif
diff --git a/drivers/unix/semaphore_posix.cpp b/drivers/unix/semaphore_posix.cpp
index 6f1b8931f9..fba4cd3641 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/semaphore_posix.h b/drivers/unix/semaphore_posix.h
index de563c28c4..6f938455b3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp
index 8d937d9ca8..5aa3915893 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,7 +39,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/stream_peer_tcp_posix.h b/drivers/unix/stream_peer_tcp_posix.h
index 1259b46ff2..9b1716ac42 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp
index dfcf479fc0..aaca0fe0d8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 053aba0d10..17a9fd1d98 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp
index e5d6a02579..03963a9756 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h
index a088f1d5de..4f76f3d7b3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/vorbis/SCsub b/drivers/vorbis/SCsub
index 1c7cccc427..87805cc2d8 100644
--- a/drivers/vorbis/SCsub
+++ b/drivers/vorbis/SCsub
@@ -1,8 +1,10 @@
-
Import('env')
sources = [
"vorbis/audio_stream_ogg_vorbis.cpp",
+]
+
+sources_lib = [
"vorbis/analysis.c",
#"vorbis/barkmel.c",
"vorbis/bitrate.c",
@@ -31,4 +33,4 @@ sources = [
]
env.drivers_sources += sources
-
+env.drivers_sources += sources_lib
diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.cpp b/drivers/vorbis/audio_stream_ogg_vorbis.cpp
index d9b7b1d161..9a60098526 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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();
+ //_clear();
}
-AudioStreamOGGVorbis::UpdateMode AudioStreamOGGVorbis::get_update_mode() const {
-
- return UPDATE_THREAD;
-}
-bool AudioStreamOGGVorbis::is_playing() const {
-
-
- return playing;
-}
-
-float AudioStreamOGGVorbis::get_pos() const {
+float AudioStreamPlaybackOGGVorbis::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 dd84fd1601..5dbada962a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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/vorbis/codebook.c b/drivers/vorbis/codebook.c
index 759d7b4254..8a928cebb9 100644
--- a/drivers/vorbis/codebook.c
+++ b/drivers/vorbis/codebook.c
@@ -248,7 +248,7 @@ static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){
}
/* quantized values */
- if((quantvals*s->q_quant+7>>3)>opb->storage-oggpack_bytes(opb))
+ if(((quantvals*s->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb))
goto _eofout;
s->quantlist=_ogg_malloc(sizeof(*s->quantlist)*quantvals);
for(i=0;i<quantvals;i++)
diff --git a/drivers/vorbis/floor1.c b/drivers/vorbis/floor1.c
index 9f3154a6a3..ae3dcedb1f 100644
--- a/drivers/vorbis/floor1.c
+++ b/drivers/vorbis/floor1.c
@@ -1035,7 +1035,7 @@ static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){
}
}
- fit_value[i]=val+predicted&0x7fff;
+ fit_value[i]=(val+predicted)&0x7fff;
fit_value[look->loneighbor[i-2]]&=0x7fff;
fit_value[look->hineighbor[i-2]]&=0x7fff;
diff --git a/drivers/vorbis/os.h b/drivers/vorbis/os.h
index 276b4decc7..3df1d194e9 100644
--- a/drivers/vorbis/os.h
+++ b/drivers/vorbis/os.h
@@ -120,7 +120,7 @@ static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise,
/* MSVC inline assembly. 32 bit only; inline ASM isn't implemented in the
* 64 bit compiler */
-#if defined(_MSC_VER) && !defined(_WIN64) && !defined(_WIN32_WCE)
+#if defined(_MSC_VER) && !defined(_WIN64) && !defined(_WIN32_WCE) && !defined(WINDOWSPHONE_ENABLED)
# define VORBIS_FPU_CONTROL
typedef ogg_int16_t vorbis_fpu_control;
diff --git a/drivers/vorbis/psy.c b/drivers/vorbis/psy.c
index 9a86151cec..29d2824372 100644
--- a/drivers/vorbis/psy.c
+++ b/drivers/vorbis/psy.c
@@ -1160,7 +1160,7 @@ void _vp_couple_quantize_normalize(int blobno,
However, this is a temporary patch.
by Aoyumi @ 2004/04/18
*/
- /*float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit)));
+ /*float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit))); */
/* elliptical
if(reM[j]+reA[j]<0){
reM[j] = - (qeM[j] = (fabs(reM[j])+fabs(reA[j]))*derate*derate);
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 6e65de9030..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 "../webp/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 ee29eb5faf..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 "../webp/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 042c98aad2..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 "../webp/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(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 992516fcdf..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 "../webp/types.h"
-#include "../webp/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 0e519b6c66..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 "../webp/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 91c03361ed..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 "../webp/types.h"
-#include "../webp/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 1a26113554..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 "../webp/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 ec573c5c85..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 "../webp/format_constants.h"
-#include "../webp/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 7c8c7b1a84..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 "../webp/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 a77778c0d8..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 "../webp/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 9c202f8d36..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 "../webp/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 eae90dd61f..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 "../webp/encode.h"
-#include "../webp/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/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..5081d5cd4d 100644
--- a/drivers/webp/utils/bit_reader.c
+++ b/drivers/webp/utils/bit_reader.c
@@ -1,36 +1,54 @@
// 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"
//------------------------------------------------------------------------------
// 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);
+ VP8LoadNewBytes(br);
+}
+
+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 +63,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 +117,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.
-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
+#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[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 +165,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 36fc13e2da..7e09653ebc 100644
--- a/drivers/webp/utils/bit_reader.h
+++ b/drivers/webp/utils/bit_reader.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.
// -----------------------------------------------------------------------------
//
// Boolean decoder
@@ -17,44 +19,75 @@
#ifdef _MSC_VER
#include <stdlib.h> // _byteswap_ulong
#endif
-#include <string.h> // For memcpy
-#include "../webp/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.
+
+#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
+
+//------------------------------------------------------------------------------
+// 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);
@@ -65,100 +98,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
- }
-}
-
-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;
-}
+// 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 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,
@@ -169,28 +133,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)));
+}
+
+// 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));
}
-// Advances the Read buffer by 4 bytes to make room for reading next 32 bits.
-void VP8LFillBitWindow(VP8LBitReader* const br);
+// 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 f7ca08497f..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 "../webp/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 13be629f36..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 "../webp/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 c5cdbd6deb..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 "../webp/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 41529cc9da..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 "../webp/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 70220a67fb..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 "../webp/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 8ccd291d22..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 "../webp/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 cc3b38d330..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 "../webp/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 89ccafe40d..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 "../webp/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 ef93d465f0..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 "../webp/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 a034762556..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 "../webp/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..9d8a616556
--- /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-2010 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..8fc188cc9c
--- /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-2010 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 aacd02ca24..7c81e8e051 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,7 +26,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED)
#include "dir_access_windows.h"
@@ -36,6 +36,13 @@
#include <wchar.h>
#include <stdio.h>
#include "print_string.h"
+
+#ifdef WINRT_ENABLED
+#include <Synchapi.h>
+#include <collection.h>
+#include <ppltasks.h>
+#endif
+
/*
[03:57] <reduz> yessopie, so i dont havemak to rely on unicows
@@ -56,26 +63,18 @@ struct DirAccessWindowsPrivate {
WIN32_FIND_DATAW fu; //unicode version
};
+// CreateFolderAsync
bool DirAccessWindows::list_dir_begin() {
_cisdir=false;
+ _cishidden=false;
- if (unicode) {
- list_dir_end();
- p->h = FindFirstFileW((current_dir+"\\*").c_str(), &p->fu);
-
- return (p->h==INVALID_HANDLE_VALUE);
- } else {
-
- list_dir_end();
- p->h = FindFirstFileA((current_dir+"\\*").ascii().get_data(), &p->f);
-
- return (p->h==INVALID_HANDLE_VALUE);
+ list_dir_end();
+ p->h = FindFirstFileExW((current_dir+"\\*").c_str(), FindExInfoStandard, &p->fu, FindExSearchNameMatch, NULL, 0);
- }
+ return (p->h==INVALID_HANDLE_VALUE);
- return false;
}
@@ -84,33 +83,20 @@ String DirAccessWindows::get_next() {
if (p->h==INVALID_HANDLE_VALUE)
return "";
- if (unicode) {
- _cisdir=(p->fu.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
- String name=p->fu.cFileName;
-
- if (FindNextFileW(p->h, &p->fu) == 0) {
-
- FindClose(p->h);
- p->h=INVALID_HANDLE_VALUE;
- }
-
- return name;
- } else {
+ _cisdir=(p->fu.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+ _cishidden=(p->fu.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN);
- _cisdir=(p->fu.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+ String name=p->fu.cFileName;
- String name=p->f.cFileName;
+ if (FindNextFileW(p->h, &p->fu) == 0) {
- if (FindNextFileA(p->h, &p->f) == 0) {
-
- FindClose(p->h);
- p->h=INVALID_HANDLE_VALUE;
- }
+ FindClose(p->h);
+ p->h=INVALID_HANDLE_VALUE;
+ }
- return name;
+ return name;
- }
}
bool DirAccessWindows::current_is_dir() const {
@@ -118,6 +104,11 @@ bool DirAccessWindows::current_is_dir() const {
return _cisdir;
}
+bool DirAccessWindows::current_is_hidden() const {
+
+ return _cishidden;
+}
+
void DirAccessWindows::list_dir_end() {
if (p->h!=INVALID_HANDLE_VALUE) {
@@ -144,110 +135,90 @@ Error DirAccessWindows::change_dir(String p_dir) {
GLOBAL_LOCK_FUNCTION
- p_dir=fix_path(p_dir);
-
- if (unicode) {
+#ifdef WINRT_ENABLED
- wchar_t real_current_dir_name[2048];
- GetCurrentDirectoryW(2048,real_current_dir_name);
- String prev_dir=real_current_dir_name;
-
- SetCurrentDirectoryW(current_dir.c_str());
- bool worked=(SetCurrentDirectoryW(p_dir.c_str())!=0);
-
- String base = _get_root_path();
- if (base!="") {
-
- GetCurrentDirectoryW(2048,real_current_dir_name);
- String new_dir;
- new_dir = String(real_current_dir_name).replace("\\","/");
- if (!new_dir.begins_with(base)) {
- worked=false;
- }
- }
-
- if (worked) {
+ p_dir = fix_path(p_dir);
+ current_dir = normalize_path(p_dir);
- GetCurrentDirectoryW(2048,real_current_dir_name);
- current_dir=real_current_dir_name; // TODO, utf8 parser
- current_dir=current_dir.replace("\\","/");
-
- }
+ return OK;
+#else
- SetCurrentDirectoryW(prev_dir.c_str());
- return worked?OK:ERR_INVALID_PARAMETER;
- } else {
+ p_dir=fix_path(p_dir);
- char real_current_dir_name[2048];
- GetCurrentDirectoryA(2048,real_current_dir_name);
- String prev_dir=real_current_dir_name;
- SetCurrentDirectoryA(current_dir.ascii().get_data());
- bool worked=(SetCurrentDirectory(p_dir.ascii().get_data())!=0);
+ wchar_t real_current_dir_name[2048];
+ GetCurrentDirectoryW(2048,real_current_dir_name);
+ String prev_dir=real_current_dir_name;
- if (worked) {
+ SetCurrentDirectoryW(current_dir.c_str());
+ bool worked=(SetCurrentDirectoryW(p_dir.c_str())!=0);
- GetCurrentDirectoryA(2048,real_current_dir_name);
- current_dir=real_current_dir_name; // TODO, utf8 parser
- current_dir=current_dir.replace("\\","/");
+ String base = _get_root_path();
+ if (base!="") {
+ GetCurrentDirectoryW(2048,real_current_dir_name);
+ String new_dir;
+ new_dir = String(real_current_dir_name).replace("\\","/");
+ if (!new_dir.begins_with(base)) {
+ worked=false;
}
+ }
- SetCurrentDirectoryA(prev_dir.ascii().get_data());
+ if (worked) {
- return worked?OK:ERR_INVALID_PARAMETER;
- }
+ GetCurrentDirectoryW(2048,real_current_dir_name);
+ current_dir=real_current_dir_name; // TODO, utf8 parser
+ current_dir=current_dir.replace("\\","/");
- return OK;
+ } //else {
+ SetCurrentDirectoryW(prev_dir.c_str());
+ //}
+
+ return worked?OK:ERR_INVALID_PARAMETER;
+#endif
}
Error DirAccessWindows::make_dir(String p_dir) {
GLOBAL_LOCK_FUNCTION
+#ifdef WINRT_ENABLED
+
+ return ERR_CANT_CREATE;
+
+#else
+
p_dir=fix_path(p_dir);
- p_dir.replace("/","\\");
+ //p_dir.replace("/","\\");
bool success;
int err;
- if (unicode) {
- wchar_t real_current_dir_name[2048];
- GetCurrentDirectoryW(2048,real_current_dir_name);
-
- SetCurrentDirectoryW(current_dir.c_str());
-
- success=CreateDirectoryW(p_dir.c_str(), NULL);
- err = GetLastError();
-
- SetCurrentDirectoryW(real_current_dir_name);
-
- } else {
-
- char real_current_dir_name[2048];
- GetCurrentDirectoryA(2048,real_current_dir_name);
+ wchar_t real_current_dir_name[2048];
+ GetCurrentDirectoryW(2048,real_current_dir_name);
- SetCurrentDirectoryA(current_dir.ascii().get_data());
+ SetCurrentDirectoryW(current_dir.c_str());
- success=CreateDirectoryA(p_dir.ascii().get_data(), NULL);
- err = GetLastError();
+ success=CreateDirectoryW(p_dir.c_str(), NULL);
+ err = GetLastError();
- SetCurrentDirectoryA(real_current_dir_name);
- }
+ SetCurrentDirectoryW(real_current_dir_name);
if (success) {
return OK;
};
- if (err == ERROR_ALREADY_EXISTS) {
+ if (err == ERROR_ALREADY_EXISTS || err == ERROR_ACCESS_DENIED) {
return ERR_ALREADY_EXISTS;
};
return ERR_CANT_CREATE;
+
+#endif
}
@@ -274,73 +245,60 @@ bool DirAccessWindows::file_exists(String p_file) {
GLOBAL_LOCK_FUNCTION
- if (!p_file.is_abs_path())
- p_file=get_current_dir()+"/"+p_file;
+ if (!p_file.is_abs_path())
+ p_file=get_current_dir().plus_file(p_file);
+
p_file=fix_path(p_file);
- p_file.replace("/","\\");
+ //p_file.replace("/","\\");
- if (unicode) {
+ //WIN32_FILE_ATTRIBUTE_DATA fileInfo;
- DWORD fileAttr;
+ DWORD fileAttr;
- fileAttr = GetFileAttributesW(p_file.c_str());
- if (0xFFFFFFFF == fileAttr)
- return false;
+ fileAttr = GetFileAttributesW(p_file.c_str());
+ if (INVALID_FILE_ATTRIBUTES == fileAttr)
+ return false;
- return !(fileAttr&FILE_ATTRIBUTE_DIRECTORY);
-
- } else {
- DWORD fileAttr;
-
- fileAttr = GetFileAttributesA(p_file.ascii().get_data());
- if (0xFFFFFFFF == fileAttr)
- return false;
- return !(fileAttr&FILE_ATTRIBUTE_DIRECTORY);
-
- }
+ return !(fileAttr&FILE_ATTRIBUTE_DIRECTORY);
- return false;
}
bool DirAccessWindows::dir_exists(String p_dir) {
GLOBAL_LOCK_FUNCTION
- if (!p_dir.is_abs_path())
- p_dir=get_current_dir()+"/"+p_dir;
- p_dir=fix_path(p_dir);
-
- p_dir.replace("/","\\");
-
- if (unicode) {
+ if (p_dir.is_rel_path())
+ p_dir=get_current_dir().plus_file(p_dir);
+ else
+ p_dir=fix_path(p_dir);
- DWORD fileAttr;
+ //p_dir.replace("/","\\");
- fileAttr = GetFileAttributesW(p_dir.c_str());
- if (0xFFFFFFFF == fileAttr)
- return false;
+ //WIN32_FILE_ATTRIBUTE_DATA fileInfo;
- return (fileAttr&FILE_ATTRIBUTE_DIRECTORY);
- } else {
- DWORD fileAttr;
+ DWORD fileAttr;
- fileAttr = GetFileAttributesA(p_dir.ascii().get_data());
- if (0xFFFFFFFF == fileAttr)
- return false;
- return (fileAttr&FILE_ATTRIBUTE_DIRECTORY);
+ fileAttr = GetFileAttributesW(p_dir.c_str());
+ if (INVALID_FILE_ATTRIBUTES == fileAttr)
+ return false;
+ return (fileAttr&FILE_ATTRIBUTE_DIRECTORY);
- }
-
- return false;
}
Error DirAccessWindows::rename(String p_path,String p_new_path) {
- p_path=fix_path(p_path);
- p_new_path=fix_path(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);
+
if (file_exists(p_new_path)) {
if (remove(p_new_path) != OK) {
return FAILED;
@@ -355,11 +313,15 @@ Error DirAccessWindows::remove(String p_path) {
p_path=fix_path(p_path);
printf("erasing %s\n",p_path.utf8().get_data());
- DWORD fileAttr = GetFileAttributesW(p_path.c_str());
- if (fileAttr == INVALID_FILE_ATTRIBUTES)
- return FAILED;
+ //WIN32_FILE_ATTRIBUTE_DATA fileInfo;
+ //DWORD fileAttr = GetFileAttributesExW(p_path.c_str(), GetFileExInfoStandard, &fileInfo);
+
+ DWORD fileAttr;
- if (fileAttr & FILE_ATTRIBUTE_DIRECTORY)
+ fileAttr = GetFileAttributesW(p_path.c_str());
+ if (INVALID_FILE_ATTRIBUTES == fileAttr)
+ return FAILED;
+ if ((fileAttr&FILE_ATTRIBUTE_DIRECTORY))
return ::_wrmdir(p_path.c_str())==0?OK:FAILED;
else
return ::_wunlink(p_path.c_str())==0?OK:FAILED;
@@ -378,7 +340,8 @@ FileType DirAccessWindows::get_file_type(const String& p_file) const {
DWORD attr;
if (worked) {
- attr = GetFileAttributesW(p_file.c_str());
+ WIN32_FILE_ATTRIBUTE_DATA fileInfo;
+ attr = GetFileAttributesExW(p_file.c_str(), GetFileExInfoStandard, &fileInfo);
}
@@ -399,9 +362,18 @@ size_t DirAccessWindows::get_space_left() {
DirAccessWindows::DirAccessWindows() {
p = memnew( DirAccessWindowsPrivate );
+ p->h=INVALID_HANDLE_VALUE;
current_dir=".";
drive_count=0;
+
+#ifdef WINRT_ENABLED
+ Windows::Storage::StorageFolder ^install_folder = Windows::ApplicationModel::Package::Current->InstalledLocation;
+ change_dir(install_folder->Path->Data());
+
+#else
+
+
DWORD mask=GetLogicalDrives();
for (int i=0;i<MAX_DRIVES;i++) {
@@ -413,14 +385,8 @@ DirAccessWindows::DirAccessWindows() {
}
}
- unicode=true;
-
- /* We are running Windows 95/98/ME, so no unicode allowed */
- if ( SetCurrentDirectoryW ( L"." ) == FALSE && GetLastError () == ERROR_CALL_NOT_IMPLEMENTED )
- unicode=false;
-
- p->h=INVALID_HANDLE_VALUE;
change_dir(".");
+#endif
}
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index 36530ba9b3..384bc8327d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,14 +56,16 @@ class DirAccessWindows : public DirAccess {
String current_dir;
- bool unicode;
+
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();
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 3cd065841f..90903f2cbd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,14 +28,20 @@
/*************************************************************************/
#ifdef WINDOWS_ENABLED
+#define WINVER 0x0500
+
+#include <windows.h>
+#include "shlwapi.h"
#include "file_access_windows.h"
+
#include <sys/types.h>
#include <sys/stat.h>
#include <wchar.h>
#include <tchar.h>
#include "print_string.h"
+
#ifdef _MSC_VER
#define S_ISREG(m) ((m)&_S_IFREG)
#endif
@@ -54,7 +60,6 @@ void FileAccessWindows::check_errors() const {
Error FileAccessWindows::_open(const String& p_filename, int p_mode_flags) {
String filename=fix_path(p_filename);
-
if (f)
close();
@@ -66,7 +71,7 @@ Error FileAccessWindows::_open(const String& p_filename, int p_mode_flags) {
else if (p_mode_flags==WRITE)
mode_string=L"wb";
else if (p_mode_flags==READ_WRITE)
- mode_string=L"wb+";
+ mode_string=L"rb+";
else
return ERR_INVALID_PARAMETER;
@@ -112,10 +117,20 @@ void FileAccessWindows::close() {
//unlink(save_path.utf8().get_data());
//print_line("renaming..");
- _wunlink(save_path.c_str()); //unlink if exists
- int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str());
+ //_wunlink(save_path.c_str()); //unlink if exists
+ //int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str());
+
+
+ bool rename_error;
+ if (!PathFileExistsW(save_path.c_str())) {
+ //creating new file
+ rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str())!=0;
+ } else {
+ //atomic replace for existing file
+ rename_error = !ReplaceFileW(save_path.c_str(), (save_path+".tmp").c_str(), NULL, 2|4, NULL, NULL);
+ }
save_path="";
- ERR_FAIL_COND( rename_error != 0);
+ ERR_FAIL_COND( rename_error );
}
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 8f16d66fe1..a2598bfeec 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/windows/mutex_windows.cpp b/drivers/windows/mutex_windows.cpp
index d42c45fd13..09f8590510 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -81,7 +81,11 @@ MutexWindows::MutexWindows() {
#ifdef WINDOWS_USE_MUTEX
mutex = CreateMutex( NULL, FALSE, NULL );
#else
- InitializeCriticalSection( &mutex );
+ #ifdef WINRT_ENABLED
+ InitializeCriticalSectionEx( &mutex, 0, 0 );
+ #else
+ InitializeCriticalSection( &mutex );
+ #endif
#endif
}
diff --git a/drivers/windows/mutex_windows.h b/drivers/windows/mutex_windows.h
index 9a3875f053..9447f17a1c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/windows/semaphore_windows.cpp b/drivers/windows/semaphore_windows.cpp
index 28a04f4acf..50cdf7cce5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,13 +28,13 @@
/*************************************************************************/
#include "semaphore_windows.h"
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED) && !defined(WINRT_ENABLED)
#include "os/memory.h"
Error SemaphoreWindows::wait() {
- WaitForSingleObject(semaphore,INFINITE);
+ WaitForSingleObjectEx(semaphore,INFINITE, false);
return OK;
}
Error SemaphoreWindows::post() {
@@ -44,7 +44,7 @@ Error SemaphoreWindows::post() {
}
int SemaphoreWindows::get() const {
long previous;
- switch (WaitForSingleObject(semaphore, 0)) {
+ switch (WaitForSingleObjectEx(semaphore, 0, false)) {
case WAIT_OBJECT_0: {
ERR_FAIL_COND_V(!ReleaseSemaphore(semaphore, 1, &previous),-1);
return previous + 1;
@@ -71,12 +71,21 @@ void SemaphoreWindows::make_default() {
SemaphoreWindows::SemaphoreWindows() {
+#ifdef WINRT_ENABLED
+ semaphore=CreateSemaphoreEx(
+ NULL,
+ 0,
+ 0xFFFFFFF, //wathever
+ NULL,
+ 0,
+ SEMAPHORE_ALL_ACCESS);
+#else
semaphore=CreateSemaphore(
- NULL,
- 0,
- 0xFFFFFFF, //wathever
- NULL);
-
+ NULL,
+ 0,
+ 0xFFFFFFF, //wathever
+ NULL);
+#endif
}
diff --git a/drivers/windows/semaphore_windows.h b/drivers/windows/semaphore_windows.h
index f87b868a68..43f6c0b560 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/windows/shell_windows.cpp b/drivers/windows/shell_windows.cpp
index 2e5f663b96..670f4e483d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,6 +27,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef WINDOWS_ENABLED
+
+#ifdef WINRT_ENABLED
+
+// Use Launcher class on windows 8
+
+#else
+
//
// C++ Implementation: shell_windows
//
@@ -59,3 +66,5 @@ ShellWindows::~ShellWindows()
}
#endif
+
+#endif
diff --git a/drivers/windows/shell_windows.h b/drivers/windows/shell_windows.h
index 8bbf51514c..98eae81175 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/drivers/windows/thread_windows.cpp b/drivers/windows/thread_windows.cpp
index 748e9661fa..6a9e97ba01 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,7 +28,7 @@
/*************************************************************************/
#include "thread_windows.h"
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED) && !defined(WINRT_ENABLED)
#include "os/memory.h"
diff --git a/drivers/windows/thread_windows.h b/drivers/windows/thread_windows.h
index d15e77d065..3c8f92ce57 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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/godot_logo.svg b/godot_logo.svg
new file mode 100644
index 0000000000..98dcddfd2b
--- /dev/null
+++ b/godot_logo.svg
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<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"
+ viewBox="0 0 236.27499 84.6875"
+ height="84.6875"
+ width="236.27499"
+ xml:space="preserve"
+ version="1.1"
+ id="svg3336"><metadata
+ id="metadata3342"><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></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs3340"><clipPath
+ id="clipPath3350"
+ clipPathUnits="userSpaceOnUse"><path
+ id="path3352"
+ d="m 0,67.75 189.02,0 L 189.02,0 0,0 0,67.75 Z" /></clipPath></defs><g
+ transform="matrix(1.25,0,0,-1.25,0,84.6875)"
+ id="g3344"><g
+ id="g3346"><g
+ clip-path="url(#clipPath3350)"
+ id="g3348"><g
+ transform="translate(112.7847,43.5176)"
+ id="g3354"><path
+ id="path3356"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c -1.082,0 -1.989,-0.497 -2.724,-1.488 -0.732,-0.992 -1.099,-2.385 -1.099,-4.177 0,-1.796 0.349,-3.171 1.05,-4.129 0.699,-0.961 1.617,-1.439 2.756,-1.439 1.139,0 2.064,0.484 2.775,1.457 0.71,0.968 1.066,2.355 1.066,4.161 0,1.803 -0.367,3.192 -1.1,4.162 C 1.992,-0.484 1.083,0 0,0 m -0.017,-17.828 c -3.168,0 -5.752,1.037 -7.749,3.11 -1.994,2.075 -2.991,5.104 -2.991,9.084 0,3.984 1.008,6.999 3.027,9.053 2.018,2.051 4.624,3.077 7.815,3.077 3.191,0 5.769,-1.008 7.73,-3.029 1.964,-2.018 2.945,-5.076 2.945,-9.167 0,-4.094 -1.004,-7.139 -3.012,-9.137 -2.008,-1.994 -4.595,-2.991 -7.765,-2.991" /></g><g
+ transform="translate(133.0269,43.2832)"
+ id="g3358"><path
+ id="path3360"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 0,-10.119 c 0,-0.473 0.035,-0.771 0.103,-0.896 0.066,-0.124 0.27,-0.186 0.607,-0.186 1.242,0 2.183,0.464 2.826,1.388 0.645,0.924 0.964,2.462 0.964,4.617 0,2.155 -0.334,3.559 -0.997,4.212 C 2.837,-0.33 1.782,0 0.338,0 L 0,0 Z m -6.495,-15.7 0,20.298 c 0,0.564 0.14,1.009 0.423,1.34 0.281,0.325 0.648,0.49 1.1,0.49 l 5.65,0 c 3.586,0 6.309,-0.905 8.168,-2.709 1.862,-1.804 2.794,-4.645 2.794,-8.525 0,-8.3 -3.543,-12.45 -10.625,-12.45 l -5.785,0 c -1.149,0 -1.725,0.518 -1.725,1.556" /></g><g
+ transform="translate(157.6558,43.5176)"
+ id="g3362"><path
+ id="path3364"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c -1.083,0 -1.991,-0.497 -2.726,-1.488 -0.731,-0.992 -1.097,-2.385 -1.097,-4.177 0,-1.796 0.35,-3.171 1.049,-4.129 0.698,-0.961 1.617,-1.439 2.756,-1.439 1.14,0 2.065,0.484 2.775,1.457 0.711,0.968 1.067,2.355 1.067,4.161 0,1.803 -0.367,3.192 -1.1,4.162 C 1.99,-0.484 1.083,0 0,0 m -0.018,-17.828 c -3.169,0 -5.751,1.037 -7.746,3.11 -1.997,2.075 -2.995,5.104 -2.995,9.084 0,3.984 1.009,6.999 3.027,9.053 2.02,2.051 4.624,3.077 7.817,3.077 3.192,0 5.768,-1.008 7.73,-3.029 1.963,-2.018 2.944,-5.076 2.944,-9.167 0,-4.094 -1.004,-7.139 -3.012,-9.137 -2.007,-1.994 -4.596,-2.991 -7.765,-2.991" /></g><g
+ transform="translate(181.0239,26.5664)"
+ id="g3366"><path
+ id="path3368"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c 0,-0.448 -1.115,-0.676 -3.349,-0.676 -2.232,0 -3.35,0.228 -3.35,0.676 l 0,16.985 -4.059,0 c -0.384,0 -0.655,0.518 -0.812,1.558 -0.068,0.495 -0.1,1.002 -0.1,1.521 0,0.517 0.032,1.026 0.1,1.522 0.157,1.037 0.428,1.559 0.812,1.559 l 14.717,0 c 0.383,0 0.653,-0.522 0.812,-1.559 0.067,-0.496 0.101,-1.005 0.101,-1.522 0,-0.519 -0.034,-1.026 -0.101,-1.521 C 4.612,17.503 4.342,16.985 3.959,16.985 L 0,16.985 0,0 Z" /></g><g
+ transform="translate(96.0444,38.5889)"
+ id="g3370"><path
+ id="path3372"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c -1.821,0.028 -3.906,-0.352 -3.906,-0.352 l 0,-3.554 2.096,0 -0.023,-1.585 c 0,-0.587 -0.582,-0.882 -1.743,-0.882 -1.162,0 -2.188,0.492 -3.078,1.474 -0.893,0.982 -1.337,2.419 -1.337,4.311 0,1.897 0.434,3.295 1.303,4.197 0.866,0.902 2.002,1.354 3.399,1.354 0.587,0 1.195,-0.095 1.827,-0.288 0.632,-0.192 1.055,-0.371 1.27,-0.539 0.214,-0.173 0.417,-0.255 0.609,-0.255 0.191,0 0.501,0.223 0.929,0.676 0.429,0.451 0.813,1.134 1.152,2.046 0.337,0.916 0.506,1.618 0.506,2.116 0,0.494 -0.01,0.835 -0.032,1.014 -0.474,0.519 -1.348,0.93 -2.624,1.236 -1.273,0.304 -2.7,0.456 -4.279,0.456 -3.474,0 -6.191,-1.094 -8.153,-3.281 -1.963,-2.189 -2.943,-5.03 -2.943,-8.527 0,-4.105 1.003,-7.218 3.008,-9.338 2.01,-2.12 4.648,-3.178 7.919,-3.178 1.759,0 3.321,0.151 4.684,0.456 1.366,0.303 2.274,0.615 2.726,0.93 L 3.445,-0.926 C 3.445,-0.311 1.821,-0.031 0,0" /></g><g
+ transform="translate(88.9126,11.8398)"
+ id="g3374"><path
+ id="path3376"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c -0.187,-0.384 -0.531,-0.735 -1.034,-1.054 -0.502,-0.32 -1.14,-0.479 -1.915,-0.479 -1.022,0 -1.844,0.322 -2.469,0.973 -0.622,0.647 -0.934,1.579 -0.934,2.794 l 0,3.032 c 0,1.189 0.294,2.101 0.883,2.738 0.588,0.632 1.376,0.952 2.359,0.952 0.962,0 1.707,-0.253 2.234,-0.753 C -0.35,7.701 -0.074,7 -0.05,6.104 l -0.013,-0.04 -0.785,0 C -0.876,6.751 -1.075,7.28 -1.45,7.654 -1.823,8.025 -2.377,8.213 -3.11,8.213 -3.851,8.213 -4.438,7.962 -4.868,7.459 -5.296,6.957 -5.51,6.229 -5.51,5.273 l 0,-3.048 c 0,-0.992 0.231,-1.747 0.693,-2.268 0.461,-0.517 1.083,-0.775 1.868,-0.775 0.574,0 1.034,0.101 1.379,0.309 0.346,0.205 0.587,0.455 0.722,0.752 l 0,2.655 -2.115,0 0,0.739 L 0,3.637 0,0 Z" /></g><g
+ transform="translate(92.7988,11.0645)"
+ id="g3378"><path
+ id="path3380"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c 0.465,0 0.88,0.132 1.242,0.4 0.362,0.27 0.616,0.611 0.767,1.026 l 0,1.638 -1.346,0 C 0.091,3.064 -0.368,2.902 -0.711,2.578 -1.055,2.256 -1.225,1.854 -1.225,1.375 -1.225,0.971 -1.119,0.639 -0.903,0.383 -0.688,0.126 -0.387,0 0,0 M 2.135,-0.611 C 2.093,-0.349 2.06,-0.136 2.04,0.031 2.02,0.201 2.009,0.37 2.009,0.542 1.779,0.166 1.483,-0.146 1.116,-0.39 0.75,-0.636 0.343,-0.758 -0.105,-0.758 c -0.627,0 -1.109,0.195 -1.45,0.583 -0.34,0.391 -0.511,0.917 -0.511,1.581 0,0.702 0.247,1.266 0.741,1.684 0.494,0.418 1.166,0.627 2.011,0.627 l 1.323,0 0,0.93 C 2.009,5.183 1.873,5.604 1.604,5.909 1.331,6.21 0.954,6.362 0.468,6.362 0.017,6.362 -0.356,6.219 -0.649,5.928 -0.94,5.639 -1.085,5.285 -1.085,4.864 l -0.786,0.007 -0.014,0.041 c -0.022,0.571 0.194,1.076 0.65,1.524 0.454,0.446 1.036,0.668 1.745,0.668 0.701,0 1.265,-0.213 1.696,-0.638 0.428,-0.429 0.643,-1.04 0.643,-1.835 l 0,-3.715 c 0,-0.27 0.012,-0.533 0.036,-0.784 0.024,-0.254 0.063,-0.499 0.125,-0.743 l -0.875,0 z" /></g><g
+ transform="translate(98.2871,18.0273)"
+ id="g3382"><path
+ id="path3384"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 0.072,-1.176 c 0.199,0.421 0.466,0.745 0.796,0.976 0.332,0.227 0.722,0.341 1.171,0.341 0.457,0 0.843,-0.133 1.154,-0.403 0.311,-0.268 0.541,-0.675 0.687,-1.22 0.186,0.503 0.451,0.902 0.794,1.19 0.343,0.289 0.759,0.433 1.242,0.433 0.664,0 1.179,-0.269 1.544,-0.807 0.367,-0.539 0.55,-1.366 0.55,-2.483 l 0,-4.425 -0.846,0 0,4.439 c 0,0.929 -0.128,1.583 -0.378,1.959 -0.252,0.377 -0.612,0.567 -1.078,0.567 -0.491,0 -0.874,-0.207 -1.149,-0.628 C 4.285,-1.658 4.116,-2.185 4.054,-2.82 l 0,-0.197 0,-4.557 -0.842,0 0,4.434 c 0,0.908 -0.127,1.557 -0.387,1.945 -0.259,0.387 -0.619,0.58 -1.081,0.58 -0.442,0 -0.8,-0.135 -1.068,-0.403 C 0.407,-1.286 0.215,-1.654 0.099,-2.121 l 0,-5.453 -0.841,0 0,7.574 L 0,0 Z" /></g><g
+ transform="translate(110.499,17.4268)"
+ id="g3386"><path
+ id="path3388"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c -0.527,0 -0.959,-0.24 -1.299,-0.72 -0.339,-0.481 -0.514,-1.074 -0.529,-1.781 l 3.495,0 0,0.324 c 0,0.625 -0.147,1.146 -0.441,1.559 C 0.931,-0.205 0.523,0 0,0 m 0.119,-7.12 c -0.817,0 -1.485,0.307 -2.003,0.921 -0.517,0.612 -0.777,1.395 -0.777,2.349 l 0,1.258 c 0,0.956 0.26,1.753 0.78,2.387 0.521,0.631 1.147,0.946 1.881,0.946 0.793,0 1.408,-0.281 1.847,-0.845 0.44,-0.566 0.66,-1.326 0.66,-2.279 l 0,-0.831 -4.335,0 0,-0.63 c 0,-0.733 0.176,-1.344 0.525,-1.831 0.35,-0.488 0.826,-0.73 1.422,-0.73 0.414,0 0.775,0.073 1.075,0.217 0.301,0.147 0.558,0.353 0.773,0.624 L 2.311,-6.16 C 2.083,-6.45 1.786,-6.685 1.424,-6.858 1.063,-7.031 0.627,-7.12 0.119,-7.12" /></g><g
+ transform="translate(119.8403,17.4268)"
+ id="g3390"><path
+ id="path3392"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c -0.528,0 -0.962,-0.24 -1.301,-0.72 -0.337,-0.481 -0.513,-1.074 -0.528,-1.781 l 3.495,0 0,0.324 c 0,0.625 -0.146,1.146 -0.442,1.559 C 0.93,-0.205 0.522,0 0,0 m 0.118,-7.12 c -0.817,0 -1.484,0.307 -2.001,0.921 -0.52,0.612 -0.78,1.395 -0.78,2.349 l 0,1.258 c 0,0.956 0.262,1.753 0.78,2.387 C -1.36,0.426 -0.734,0.741 0,0.741 0.792,0.741 1.409,0.46 1.847,-0.104 2.286,-0.67 2.505,-1.43 2.505,-2.383 l 0,-0.831 -4.334,0 0,-0.63 c 0,-0.733 0.176,-1.344 0.527,-1.831 0.348,-0.488 0.822,-0.73 1.42,-0.73 0.416,0 0.775,0.073 1.074,0.217 0.302,0.147 0.559,0.353 0.776,0.624 L 2.31,-6.16 C 2.081,-6.45 1.786,-6.685 1.423,-6.858 1.063,-7.031 0.627,-7.12 0.118,-7.12" /></g><g
+ transform="translate(124.5659,18.0273)"
+ id="g3394"><path
+ id="path3396"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 0.069,-1.252 c 0.202,0.444 0.469,0.789 0.804,1.029 0.332,0.242 0.723,0.364 1.172,0.364 0.677,0 1.196,-0.25 1.556,-0.753 0.363,-0.502 0.544,-1.283 0.544,-2.341 l 0,-4.621 -0.847,0 0,4.613 c 0,0.865 -0.127,1.47 -0.379,1.82 -0.251,0.351 -0.619,0.526 -1.098,0.526 -0.43,0 -0.791,-0.14 -1.08,-0.424 C 0.451,-1.32 0.234,-1.695 0.09,-2.168 l 0,-5.406 -0.84,0 L -0.75,0 0,0 Z" /></g><g
+ transform="translate(131.1768,13.5771)"
+ id="g3398"><path
+ id="path3400"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c 0,-0.769 0.146,-1.38 0.441,-1.835 0.292,-0.459 0.736,-0.686 1.33,-0.686 0.406,0 0.748,0.109 1.029,0.331 0.28,0.221 0.501,0.53 0.664,0.921 l 0,3.752 C 3.307,2.887 3.091,3.213 2.818,3.464 2.545,3.711 2.2,3.835 1.785,3.835 1.193,3.835 0.746,3.577 0.448,3.06 0.149,2.541 0,1.865 0,1.035 L 0,0 Z m -0.849,1.035 c 0,1.073 0.217,1.936 0.652,2.585 0.432,0.647 1.033,0.971 1.8,0.971 0.425,0 0.798,-0.104 1.117,-0.312 C 3.039,4.075 3.303,3.776 3.515,3.396 l 0.082,1.054 0.714,0 0,-7.581 c 0,-0.971 -0.226,-1.723 -0.678,-2.255 -0.452,-0.53 -1.095,-0.799 -1.926,-0.799 -0.298,0 -0.619,0.047 -0.962,0.138 -0.344,0.091 -0.648,0.21 -0.915,0.359 l 0.233,0.739 c 0.227,-0.148 0.481,-0.262 0.763,-0.342 0.279,-0.083 0.568,-0.123 0.867,-0.123 0.602,0 1.049,0.193 1.337,0.579 0.289,0.391 0.434,0.956 0.434,1.704 l 0,0.916 C 3.25,-2.556 2.986,-2.817 2.673,-2.998 2.362,-3.18 1.998,-3.271 1.588,-3.271 c -0.761,0 -1.358,0.298 -1.789,0.894 -0.431,0.595 -0.648,1.388 -0.648,2.377 l 0,1.035 z" /></g><path
+ id="path3402"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 138.318,10.453 -0.848,0 0,7.574 0.848,0 0,-7.574 z m 0,9.731 -0.848,0 0,1.193 0.848,0 0,-1.193 z" /><g
+ transform="translate(141.0552,18.0273)"
+ id="g3404"><path
+ id="path3406"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 0.069,-1.252 c 0.202,0.444 0.468,0.789 0.803,1.029 0.334,0.242 0.725,0.364 1.173,0.364 0.677,0 1.197,-0.25 1.558,-0.753 0.363,-0.502 0.542,-1.283 0.542,-2.341 l 0,-4.621 -0.847,0 0,4.613 c 0,0.865 -0.127,1.47 -0.378,1.82 -0.253,0.351 -0.618,0.526 -1.099,0.526 -0.43,0 -0.79,-0.14 -1.079,-0.424 C 0.453,-1.32 0.235,-1.695 0.092,-2.168 l 0,-5.406 -0.842,0 L -0.75,0 0,0 Z" /></g><g
+ transform="translate(149.4155,17.4268)"
+ id="g3408"><path
+ id="path3410"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 c -0.528,0 -0.961,-0.24 -1.299,-0.72 -0.338,-0.481 -0.514,-1.074 -0.53,-1.781 l 3.495,0 0,0.324 c 0,0.625 -0.145,1.146 -0.44,1.559 C 0.932,-0.205 0.523,0 0,0 m 0.12,-7.12 c -0.819,0 -1.486,0.307 -2.002,0.921 -0.518,0.612 -0.778,1.395 -0.778,2.349 l 0,1.258 c 0,0.956 0.26,1.753 0.78,2.387 0.521,0.631 1.148,0.946 1.88,0.946 0.793,0 1.41,-0.281 1.85,-0.845 0.438,-0.566 0.657,-1.326 0.657,-2.279 l 0,-0.831 -4.336,0 0,-0.63 c 0,-0.733 0.177,-1.344 0.527,-1.831 0.349,-0.488 0.823,-0.73 1.422,-0.73 0.414,0 0.773,0.073 1.072,0.217 0.304,0.147 0.56,0.353 0.777,0.624 L 2.313,-6.16 C 2.082,-6.45 1.787,-6.685 1.425,-6.858 1.064,-7.031 0.628,-7.12 0.12,-7.12" /></g><g
+ transform="translate(64.312,21.7949)"
+ id="g3412"><path
+ id="path3414"
+ style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ 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" /></g><g
+ transform="translate(5.9634,40.0615)"
+ id="g3416"><path
+ id="path3418"
+ style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ 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" /></g><g
+ transform="translate(26.8428,32.3604)"
+ id="g3420"><path
+ id="path3422"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ 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" /></g><g
+ transform="translate(25.27,31.9727)"
+ id="g3424"><path
+ id="path3426"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ 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" /></g><g
+ transform="translate(35.6816,25.2285)"
+ id="g3428"><path
+ id="path3430"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ 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" /></g><g
+ transform="translate(44.5215,32.3604)"
+ id="g3432"><path
+ id="path3434"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ 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" /></g><g
+ transform="translate(46.0947,31.9727)"
+ id="g3436"><path
+ id="path3438"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ 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" /></g></g></g></g></svg> \ No newline at end of file
diff --git a/logo_small.png b/logo_small.png
new file mode 100644
index 0000000000..61e4cc95d6
--- /dev/null
+++ b/logo_small.png
Binary files differ
diff --git a/main/SCsub b/main/SCsub
index 7b51b06187..fa60ffc3e8 100644
--- a/main/SCsub
+++ b/main/SCsub
@@ -5,8 +5,6 @@ env.add_source_files(env.main_sources,"*.cpp")
Export('env')
-lib = env.Library("main",env.main_sources, LIBSUFFIX=env['platform_libsuffix'])
+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..878d21c302
--- /dev/null
+++ b/main/input_default.cpp
@@ -0,0 +1,343 @@
+#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];
+};
+
+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);
+
+ 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);
+ }
+
+ }
+}
+
+InputDefault::InputDefault() {
+
+ mouse_button_mask=0;
+ emulate_touch=false;
+ main_loop=NULL;
+}
diff --git a/main/input_default.h b/main/input_default.h
new file mode 100644
index 0000000000..2ef4f727c6
--- /dev/null
+++ b/main/input_default.h
@@ -0,0 +1,83 @@
+#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;
+ Map<int, String> joy_names;
+ 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();
+ };
+
+ SpeedTrack mouse_speed_track;
+
+ RES custom_cursor;
+
+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);
+
+ 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);
+
+ InputDefault();
+
+};
+
+#endif // INPUT_DEFAULT_H
diff --git a/main/main.cpp b/main/main.cpp
index f5b5953ff4..a060dbd232 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -43,7 +43,7 @@
#include "io/resource_loader.h"
#include "scene/main/scene_main_loop.h"
-#include "scene/io/scene_loader.h"
+
#include "script_language.h"
#include "io/resource_loader.h"
@@ -57,6 +57,7 @@
#include "tools/editor/editor_node.h"
#include "tools/editor/project_manager.h"
#include "tools/editor/console.h"
+#include "tools/pck/pck_packer.h"
#endif
#include "io/file_access_network.h"
@@ -74,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;
@@ -86,14 +87,26 @@ static MessageQueue *message_queue=NULL;
static Performance *performance = NULL;
static PathRemap *path_remap;
static PackedData *packed_data=NULL;
+#ifdef MINIZIP_ENABLED
+static ZipArchive *zip_packed_data=NULL;
+#endif
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_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 int init_screen=-1;
+
static String unescape_cmdline(const String& p_str) {
return p_str.replace("%20"," ");
@@ -110,7 +123,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-2010 Juan Linietsky, Ariel Manzur.\n");
+ OS::get_singleton()->print(VERSION_FULL_NAME" (c) 2008-2015 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");
@@ -129,8 +142,10 @@ 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-vd DRIVER\t : Video Driver (");
for (int i=0;i<OS::get_singleton()->get_video_driver_count();i++) {
@@ -146,12 +161,14 @@ void Main::print_help(const char* p_binary) {
OS::get_singleton()->print(", ");
OS::get_singleton()->print("%s",OS::get_singleton()->get_audio_driver_name(i));
}
+ OS::get_singleton()->print(")\n");
OS::get_singleton()->print("\t-rthread <mode>\t : Render Thread Mode ('unsafe', 'safe', 'separate).");
OS::get_singleton()->print(")\n");
OS::get_singleton()->print("\t-s,-script [script] : Run a script.\n");
OS::get_singleton()->print("\t-d,-debug : Debug (local stdout debugger).\n");
OS::get_singleton()->print("\t-rdebug ADDRESS : Remote debug (<ip>:<port> host address).\n");
OS::get_singleton()->print("\t-fdelay [msec]: Simulate high CPU load (delay each frame by [msec]).\n");
+ OS::get_singleton()->print("\t-timescale [msec]: Simulate high CPU load (delay each frame by [msec]).\n");
OS::get_singleton()->print("\t-bp : breakpoint list as source::line comma separated pairs, no spaces (%%20,%%2C,etc instead).\n");
OS::get_singleton()->print("\t-v : Verbose stdout mode\n");
OS::get_singleton()->print("\t-lang [locale]: Use a specific locale\n");
@@ -225,6 +242,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
String debug_mode;
String debug_host;
String main_pack;
+ bool quiet_stdout=false;
int rtm=-1;
String remotefs;
@@ -244,7 +262,15 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
packed_data = memnew(PackedData);
#ifdef MINIZIP_ENABLED
- packed_data->add_pack_source(ZipArchive::get_singleton());
+
+ //XXX: always get_singleton() == 0x0
+ zip_packed_data = ZipArchive::get_singleton();
+ //TODO: remove this temporary fix
+ if (!zip_packed_data) {
+ zip_packed_data = memnew(ZipArchive);
+ }
+
+ packed_data->add_pack_source(zip_packed_data);
#endif
bool editor=false;
@@ -269,6 +295,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;
@@ -279,6 +306,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;
}
@@ -289,11 +317,43 @@ 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()=="-vd") { // video driver
if (I->next()) {
@@ -301,6 +361,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;
}
@@ -311,6 +372,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;
}
@@ -365,14 +427,17 @@ 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;
-
} else if (I->get()=="-nowindow") { // fullscreen
OS::get_singleton()->set_no_window_mode(true);
+ } else if (I->get()=="-quiet") { // fullscreen
+
+ quiet_stdout=true;
} else if (I->get()=="-v") { // fullscreen
OS::get_singleton()->_verbose_stdout=true;
} else if (I->get()=="-path") { // resolution
@@ -385,7 +450,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;
@@ -415,6 +479,17 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
}
+ } else if (I->get()=="-timescale") { // resolution
+
+ if (I->next()) {
+
+ OS::get_singleton()->set_time_scale(I->next()->get().to_double());
+ N=I->next()->next();
+ } else {
+ goto error;
+
+ }
+
} else if (I->get() == "-pack") {
@@ -440,6 +515,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()) {
@@ -455,8 +534,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;
@@ -486,14 +567,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);
@@ -514,8 +595,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;
}
@@ -567,9 +648,20 @@ 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;
+
OS::get_singleton()->set_cmdline(execpath, main_args);
#ifdef TOOLS_ENABLED
@@ -593,14 +685,28 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (use_custom_res && globals->has("display/resizable"))
video_mode.resizable=globals->get("display/resizable");
+ if (!force_res && use_custom_res && globals->has("display/test_width") && globals->has("display/test_height")) {
+ int tw = globals->get("display/test_width");
+ int th = globals->get("display/test_height");
+ if (tw>0 && th>0) {
+ video_mode.width=tw;
+ video_mode.height=th;
+ }
+ }
GLOBAL_DEF("display/width",video_mode.width);
GLOBAL_DEF("display/height",video_mode.height);
GLOBAL_DEF("display/fullscreen",video_mode.fullscreen);
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);
if (rtm==-1) {
rtm=GLOBAL_DEF("render/thread_model",OS::RENDER_THREAD_SAFE);
+ if (rtm>=1) //hack for now
+ rtm=1;
+
}
if (rtm>=0 && rtm<3)
@@ -677,6 +783,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (p_second_phase)
return setup2();
+
return OK;
error:
@@ -689,7 +796,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);
@@ -705,6 +811,17 @@ 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.
+//#ifdef MINIZIP_ENABLED
+// if (zip_packed_data)
+// memdelete( zip_packed_data );
+//#endif
+
+ unregister_core_driver_types();
unregister_core_types();
OS::get_singleton()->_cmdline.clear();
@@ -721,6 +838,14 @@ 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);
+ }
+ if (init_maximized) {
+ OS::get_singleton()->set_window_maximized(true);
+ } else if (init_fullscreen) {
+ OS::get_singleton()->set_window_fullscreen(true);
+ }
register_core_singletons();
@@ -731,29 +856,51 @@ Error Main::setup2() {
show_logo=false;
#endif
+ if (init_screen!=-1) {
+ OS::get_singleton()->set_current_screen(init_screen);
+ }
+ if (init_maximized) {
+ OS::get_singleton()->set_window_maximized(true);
+ }
+ MAIN_PRINT("Main: Load Remaps");
+
+ path_remap->load_remaps();
+
if (show_logo) { //boot logo!
- Image boot_logo=GLOBAL_DEF("application/boot_logo",Image());
+ 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;
+
+ 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()) {
+ OS::get_singleton()->_msec_splash=OS::get_singleton()->get_ticks_msec();
Color clear = GLOBAL_DEF("render/default_clear_color",Color(0.3,0.3,0.3));
VisualServer::get_singleton()->set_default_clear_color(clear);
Color boot_bg = GLOBAL_DEF("application/boot_bg_color", clear);
- VisualServer::get_singleton()->set_boot_image(boot_logo, boot_bg);
+ 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");
VisualServer::get_singleton()->set_default_clear_color(boot_splash_bg_color);
MAIN_PRINT("Main: Image");
- VisualServer::get_singleton()->set_boot_image(splash, boot_splash_bg_color);
+ VisualServer::get_singleton()->set_boot_image(splash, boot_splash_bg_color,false);
#endif
MAIN_PRINT("Main: DCC");
VisualServer::get_singleton()->set_default_clear_color(GLOBAL_DEF("render/default_clear_color",Color(0.3,0.3,0.3)));
@@ -766,17 +913,41 @@ 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
#endif
MAIN_PRINT("Main: Load Scripts, Modules, Drivers");
@@ -784,6 +955,8 @@ Error Main::setup2() {
register_module_types();
register_driver_types();
+ ScriptServer::init_languages();
+
MAIN_PRINT("Main: Load Translations");
translation_server->setup(); //register translations, load them, etc.
@@ -828,63 +1001,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)
@@ -919,14 +1086,25 @@ 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","");
}
MainLoop *main_loop=NULL;
if (editor) {
- main_loop = memnew(SceneMainLoop);
+ main_loop = memnew(SceneTree);
};
if (test!="") {
@@ -944,7 +1122,7 @@ bool Main::start() {
ERR_EXPLAIN("Can't load script: "+script);
ERR_FAIL_COND_V(script_res.is_null(),false);
- if( script_res->can_instance() /*&& script_res->inherits_from("SceneMainLoopScripted")*/) {
+ if( script_res->can_instance() /*&& script_res->inherits_from("SceneTreeScripted")*/) {
StringName instance_type=script_res->get_instance_base_type();
@@ -970,7 +1148,7 @@ bool Main::start() {
}
if (!main_loop && main_loop_type=="")
- main_loop_type="SceneMainLoop";
+ main_loop_type="SceneTree";
if (!main_loop) {
if (!ObjectTypeDB::type_exists(main_loop_type)) {
@@ -995,12 +1173,19 @@ bool Main::start() {
}
}
- if (main_loop->is_type("SceneMainLoop")) {
+ if (main_loop->is_type("SceneTree")) {
- SceneMainLoop *sml = main_loop->cast_to<SceneMainLoop>();
+ 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) {
@@ -1025,19 +1210,19 @@ bool Main::start() {
String stretch_aspect = GLOBAL_DEF("display/stretch_aspect","ignore");
Size2i stretch_size = Size2(GLOBAL_DEF("display/width",0),GLOBAL_DEF("display/height",0));
- SceneMainLoop::StretchMode sml_sm=SceneMainLoop::STRETCH_MODE_DISABLED;
+ SceneTree::StretchMode sml_sm=SceneTree::STRETCH_MODE_DISABLED;
if (stretch_mode=="2d")
- sml_sm=SceneMainLoop::STRETCH_MODE_2D;
+ sml_sm=SceneTree::STRETCH_MODE_2D;
else if (stretch_mode=="viewport")
- sml_sm=SceneMainLoop::STRETCH_MODE_VIEWPORT;
+ sml_sm=SceneTree::STRETCH_MODE_VIEWPORT;
- SceneMainLoop::StretchAspect sml_aspect=SceneMainLoop::STRETCH_ASPECT_IGNORE;
+ SceneTree::StretchAspect sml_aspect=SceneTree::STRETCH_ASPECT_IGNORE;
if (stretch_aspect=="keep")
- sml_aspect=SceneMainLoop::STRETCH_ASPECT_KEEP;
+ sml_aspect=SceneTree::STRETCH_ASPECT_KEEP;
else if (stretch_aspect=="keep_width")
- sml_aspect=SceneMainLoop::STRETCH_ASPECT_KEEP_WIDTH;
+ sml_aspect=SceneTree::STRETCH_ASPECT_KEEP_WIDTH;
else if (stretch_aspect=="keep_height")
- sml_aspect=SceneMainLoop::STRETCH_ASPECT_KEEP_HEIGHT;
+ sml_aspect=SceneTree::STRETCH_ASPECT_KEEP_HEIGHT;
sml->set_screen_stretch(sml_sm,sml_aspect,stretch_size);
@@ -1096,10 +1281,6 @@ bool Main::start() {
#ifdef TOOLS_ENABLED
if (editor) {
-#ifdef OLD_SCENE_FORMAT_ENABLED
- if (convert_old)
- editor_node->set_convert_old_scene(true);
-#endif
if (_import!="") {
@@ -1142,7 +1323,7 @@ bool Main::start() {
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);
RES res = ResourceLoader::load(path);
ERR_EXPLAIN("Can't autoload: "+path);
@@ -1179,17 +1360,10 @@ bool Main::start() {
if (scenedata.is_valid())
scene=scenedata->instance();
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
- if (!scene) {
- scene = SceneLoader::load(local_game_path,true);
- }
-
-#endif
-
ERR_EXPLAIN("Failed loading scene: "+local_game_path);
ERR_FAIL_COND_V(!scene,false)
- sml->get_root()->add_child(scene);
+ //sml->get_root()->add_child(scene);
+ sml->add_current_scene(scene);
String iconpath = GLOBAL_DEF("application/icon","Variant()""");
if (iconpath!="") {
@@ -1257,20 +1431,24 @@ bool Main::iteration() {
uint64_t ticks=OS::get_singleton()->get_ticks_usec();
uint64_t ticks_elapsed=ticks-last_ticks;
+ double step=(double)ticks_elapsed / 1000000.0;
+ float frame_slice=1.0/OS::get_singleton()->get_iterations_per_second();
+
+// if (time_accum+step < frame_slice)
+// return false;
+
frame+=ticks_elapsed;
last_ticks=ticks;
- double step=(double)ticks_elapsed / 1000000.0;
-
- float frame_slice=1.0/OS::get_singleton()->get_iterations_per_second();
if (step>frame_slice*8)
step=frame_slice*8;
time_accum+=step;
- bool exit=false;
+ float time_scale = OS::get_singleton()->get_time_scale();
+ bool exit=false;
int iters = 0;
@@ -1284,15 +1462,17 @@ bool Main::iteration() {
Physics2DServer::get_singleton()->sync();
Physics2DServer::get_singleton()->flush_queries();
- if (OS::get_singleton()->get_main_loop()->iteration( frame_slice )) {
+ if (OS::get_singleton()->get_main_loop()->iteration( frame_slice*time_scale )) {
exit=true;
break;
}
message_queue->flush();
- PhysicsServer::get_singleton()->step(frame_slice);
- Physics2DServer::get_singleton()->step(frame_slice);
+ PhysicsServer::get_singleton()->step(frame_slice*time_scale);
+
+ Physics2DServer::get_singleton()->end_sync();
+ Physics2DServer::get_singleton()->step(frame_slice*time_scale);
time_accum-=frame_slice;
message_queue->flush();
@@ -1305,14 +1485,16 @@ bool Main::iteration() {
uint64_t idle_begin = OS::get_singleton()->get_ticks_usec();
- OS::get_singleton()->get_main_loop()->idle( step );
+ OS::get_singleton()->get_main_loop()->idle( step*time_scale );
message_queue->flush();
if (SpatialSoundServer::get_singleton())
- SpatialSoundServer::get_singleton()->update( step );
+ SpatialSoundServer::get_singleton()->update( step*time_scale );
if (SpatialSound2DServer::get_singleton())
- SpatialSound2DServer::get_singleton()->update( step );
+ SpatialSound2DServer::get_singleton()->update( step*time_scale );
+
+ VisualServer::get_singleton()->sync(); //sync if still drawing from previous frames.
if (OS::get_singleton()->can_draw()) {
@@ -1326,8 +1508,6 @@ bool Main::iteration() {
OS::get_singleton()->frames_drawn++;
force_redraw_requested = false;
}
- } else {
- VisualServer::get_singleton()->flush(); // flush visual commands
}
if (AudioServer::get_singleton())
@@ -1375,9 +1555,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 0aa1c99108..12b4411d56 100644
--- a/main/main.h
+++ b/main/main.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/main/performance.cpp b/main/performance.cpp
index 81db7ae1fa..f8c5df42d1 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,6 +29,8 @@
#include "performance.h"
#include "os/os.h"
#include "servers/visual_server.h"
+#include "servers/physics_2d_server.h"
+#include "servers/physics_server.h"
#include "message_queue.h"
#include "scene/main/scene_main_loop.h"
Performance *Performance::singleton=NULL;
@@ -61,6 +63,13 @@ void Performance::_bind_methods() {
BIND_CONSTANT( RENDER_VIDEO_MEM_USED );
BIND_CONSTANT( RENDER_TEXTURE_MEM_USED );
BIND_CONSTANT( RENDER_VERTEX_MEM_USED );
+ BIND_CONSTANT( PHYSICS_2D_ACTIVE_OBJECTS );
+ BIND_CONSTANT( PHYSICS_2D_COLLISION_PAIRS );
+ BIND_CONSTANT( PHYSICS_2D_ISLAND_COUNT );
+ BIND_CONSTANT( PHYSICS_3D_ACTIVE_OBJECTS );
+ BIND_CONSTANT( PHYSICS_3D_COLLISION_PAIRS );
+ BIND_CONSTANT( PHYSICS_3D_ISLAND_COUNT );
+
BIND_CONSTANT( MONITOR_MAX );
}
@@ -90,7 +99,14 @@ String Performance::get_monitor_name(Monitor p_monitor) const {
"video/video_mem",
"video/texure_mem",
"video/vertex_mem",
- "render/mem_max"
+ "video/video_mem_max",
+ "physics_2d/active_objects",
+ "physics_2d/collision_pairs",
+ "physics_2d/islands",
+ "physics_3d/active_objects",
+ "physics_3d/collision_pairs",
+ "physics_3d/islands",
+
};
return names[p_monitor];
@@ -117,7 +133,7 @@ float Performance::get_monitor(Monitor p_monitor) const {
MainLoop *ml = OS::get_singleton()->get_main_loop();
if (!ml)
return 0;
- SceneMainLoop *sml = ml->cast_to<SceneMainLoop>();
+ SceneTree *sml = ml->cast_to<SceneTree>();
if (!sml)
return 0;
return sml->get_node_count();
@@ -133,6 +149,13 @@ float Performance::get_monitor(Monitor p_monitor) const {
case RENDER_TEXTURE_MEM_USED: return VS::get_singleton()->get_render_info(VS::INFO_TEXTURE_MEM_USED);
case RENDER_VERTEX_MEM_USED: return VS::get_singleton()->get_render_info(VS::INFO_VERTEX_MEM_USED);
case RENDER_USAGE_VIDEO_MEM_TOTAL: return VS::get_singleton()->get_render_info(VS::INFO_USAGE_VIDEO_MEM_TOTAL);
+ case PHYSICS_2D_ACTIVE_OBJECTS: return Physics2DServer::get_singleton()->get_process_info(Physics2DServer::INFO_ACTIVE_OBJECTS);
+ case PHYSICS_2D_COLLISION_PAIRS: return Physics2DServer::get_singleton()->get_process_info(Physics2DServer::INFO_COLLISION_PAIRS);
+ case PHYSICS_2D_ISLAND_COUNT: return Physics2DServer::get_singleton()->get_process_info(Physics2DServer::INFO_ISLAND_COUNT);
+ case PHYSICS_3D_ACTIVE_OBJECTS: return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_ACTIVE_OBJECTS);
+ case PHYSICS_3D_COLLISION_PAIRS: return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_COLLISION_PAIRS);
+ case PHYSICS_3D_ISLAND_COUNT: return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_ISLAND_COUNT);
+
default: {}
}
diff --git a/main/performance.h b/main/performance.h
index db453d0156..f0cd217b2b 100644
--- a/main/performance.h
+++ b/main/performance.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -69,6 +69,12 @@ public:
RENDER_TEXTURE_MEM_USED,
RENDER_VERTEX_MEM_USED,
RENDER_USAGE_VIDEO_MEM_TOTAL,
+ PHYSICS_2D_ACTIVE_OBJECTS,
+ PHYSICS_2D_COLLISION_PAIRS,
+ PHYSICS_2D_ISLAND_COUNT,
+ PHYSICS_3D_ACTIVE_OBJECTS,
+ PHYSICS_3D_COLLISION_PAIRS,
+ PHYSICS_3D_ISLAND_COUNT,
//physics
MONITOR_MAX
};
diff --git a/main/splash.h b/main/splash.h
index e9c7846d0c..f69383cf00 100644
--- a/main/splash.h
+++ b/main/splash.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,16 +26,16 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BOOT_SPLASH_H
-#define BOOT_SPLASH_H
-
-static const unsigned char boot_splash_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xef,0x0,0x0,0x1,0x3,0x8,0x6,0x0,0x0,0x0,0xdd,0x81,0x53,0xf4,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0x32,0xdf,0x0,0x0,0x32,0xdf,0x1,0x17,0xbe,0xe4,0xb,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x1,0x19,0x13,0x8,0x19,0x46,0x43,0xd9,0xbb,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,0x9d,0x79,0x78,0x54,0xd5,0xf9,0xc7,0x3f,0xef,0x9d,0x49,0xc2,0xe,0xb2,0xb9,0xaf,0xb8,0x2f,0x3f,0xb5,0xa8,0xb4,0xa2,0x66,0x66,0x2,0x4,0xea,0x5a,0xad,0x5a,0x6d,0xb5,0x2e,0xad,0x56,0x24,0x1b,0x4,0xb5,0x5a,0x2b,0xb6,0x6a,0x55,0x2,0x9,0x9,0xae,0x5d,0xd4,0x5a,0x6b,0x15,0xad,0x15,0x15,0x48,0x48,0x66,0x26,0x50,0x10,0x17,0xa,0x2a,0x56,0x51,0x11,0xd7,0x8a,0xec,0x90,0x0,0x59,0x66,0xee,0xfb,0xfb,0x63,0x82,0x4,0x32,0x9,0x99,0x9b,0x99,0x64,0x92,0x9c,0xcf,0xf3,0xcc,0x43,0xb8,0x33,0xf7,0xdc,0x73,0xde,0x73,0xbe,0xe7,0xbc,0xe7,0xdc,0xb3,0x80,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x86,0x16,0x19,0x53,0xe0,0xdf,0xaf,0xbd,0x9e,0x95,0x71,0x5f,0x79,0x2f,0x63,0xf1,0xce,0x87,0x18,0x13,0x24,0x81,0x50,0xa7,0x96,0xa,0x92,0x76,0xb4,0xc0,0x39,0xa0,0xe7,0x0,0xe7,0x0,0x43,0x4a,0xf3,0xbd,0x9,0x17,0x55,0x66,0x81,0xdf,0x7,0x52,0xe,0x2c,0x5,0x16,0x0,0xb,0xdc,0x96,0x1d,0x7c,0x6d,0x62,0xc6,0x16,0x93,0x33,0x46,0xbc,0x86,0x28,0x8c,0x9b,0x56,0xe9,0xb2,0x35,0xec,0x1,0xb9,0x0,0x38,0xf,0x38,0xa2,0x69,0xee,0xc8,0x43,0xa5,0x93,0x3c,0x13,0x12,0x2b,0xde,0x40,0x15,0xd0,0x27,0xca,0x57,0xb,0x15,0x5e,0x1,0x99,0x5d,0x96,0xef,0x59,0x69,0x72,0xcc,0x88,0xb7,0x5b,0xf3,0xc3,0x82,0xa,0xcb,0xc6,0xf2,0x2a,0xfc,0x1c,0xb8,0x8,0xe8,0xbb,0x97,0x5b,0xea,0x43,0x75,0xe1,0xfe,0x15,0xb7,0x8f,0xda,0x91,0x10,0xe1,0x4e,0xd,0xdc,0x88,0xf0,0x68,0x2b,0x7e,0xfa,0x11,0xf0,0xac,0xad,0xfa,0xd4,0xfc,0xc9,0xbe,0xd5,0x26,0x27,0x8d,0x78,0xbb,0xd,0x63,0xb,0x2,0x47,0x2a,0x5c,0xb,0x5c,0x5,0x1c,0x1c,0xe3,0xed,0xf3,0x4b,0xf3,0xbd,0x63,0x12,0xd4,0xea,0xd6,0x3,0xee,0x18,0x6f,0x5b,0x8,0x3c,0x95,0x52,0x5f,0xfb,0xb7,0x57,0x7f,0x3d,0xb6,0xd6,0xe4,0xae,0x11,0x6f,0x97,0xe3,0xfc,0x29,0xaf,0x48,0x5d,0xdf,0x3e,0x67,0xa1,0xe4,0x3,0x17,0xb4,0x21,0xa8,0xb0,0x25,0x1c,0x32,0x77,0x92,0xf7,0x7f,0x71,0x16,0x6e,0x9,0xd0,0x16,0x97,0x7c,0x1b,0x50,0x62,0xa1,0xd3,0xe7,0xe6,0xfb,0xd6,0x99,0x1c,0x37,0xe2,0xed,0x12,0x8c,0x29,0x8,0x64,0xa,0xdc,0xd,0x8c,0x88,0x53,0x90,0x1f,0x96,0xe6,0x7b,0x8f,0x8b,0x5b,0x7f,0xbb,0x78,0x4e,0x9a,0x5d,0xd7,0x73,0x3b,0x60,0xc5,0x21,0x38,0x1b,0xf8,0x6b,0x8a,0x86,0xb2,0x5e,0x9d,0x3c,0xba,0xda,0xe4,0x7e,0xfb,0x61,0x19,0x13,0x24,0xa4,0x46,0x1c,0x1f,0x47,0xe1,0x2,0x1c,0x93,0x39,0x3d,0x70,0x54,0xbc,0x2,0xb3,0xeb,0x7a,0x3e,0x17,0xc7,0xbc,0xb7,0x80,0x6b,0xea,0xc5,0x3d,0xc0,0xe4,0xbc,0x11,0x6f,0x57,0x60,0x6d,0xdc,0xeb,0x3,0x9b,0x57,0xe3,0xd4,0xea,0xba,0x80,0xf3,0x13,0x90,0xe6,0xb0,0xc9,0x76,0x23,0x5e,0x23,0xde,0xe8,0x1c,0x39,0x66,0xaa,0xff,0x80,0x38,0xb4,0xba,0x7f,0x4a,0x50,0xbe,0x1b,0xf1,0x1a,0xf1,0x1a,0xf1,0x36,0x97,0x57,0x22,0xf2,0x4a,0x1c,0xc2,0xb9,0x3a,0x41,0x9d,0x5,0x23,0x5e,0x23,0xde,0x2e,0x80,0x26,0x44,0xbc,0x0,0xa7,0x8c,0x2a,0x2c,0x77,0xdc,0xb7,0xcc,0x2c,0x8,0x4c,0x4b,0x54,0x9e,0x4b,0x64,0xe0,0xca,0xd0,0x8e,0xb8,0x8d,0x9,0x12,0x52,0x92,0x13,0x25,0x5e,0xcb,0x15,0x76,0xbd,0x4,0x78,0x77,0x5e,0x18,0x53,0x10,0x18,0xec,0xb2,0xb4,0x4f,0xd8,0x96,0x5e,0x88,0xf4,0x6,0x3b,0x84,0x6d,0x6d,0x3,0x7b,0x5b,0x38,0xc5,0xde,0x52,0x91,0x3b,0xaa,0xf1,0x8,0x70,0x6e,0xe2,0xea,0x2b,0x35,0x2d,0xaf,0x11,0x6f,0x57,0x68,0x78,0x59,0x9b,0xc0,0x77,0x70,0xe7,0x64,0x16,0x4,0xca,0x80,0x43,0x81,0x43,0x80,0x1e,0xb6,0x2d,0x91,0x77,0x7e,0xaa,0x91,0x36,0x50,0x22,0xff,0xba,0x43,0x2e,0x32,0xb,0x2,0x1b,0x80,0xcf,0x81,0x4d,0x9,0xf6,0xb4,0x8c,0x78,0x8d,0x78,0xbb,0x42,0xc3,0x4b,0x55,0x82,0xbb,0x3a,0xa3,0x63,0xf8,0xfd,0xa0,0x86,0x4f,0xa2,0xab,0xac,0x7a,0x93,0xf3,0xa6,0xcf,0xdb,0xf9,0xc5,0x2b,0x52,0xd3,0xcd,0x92,0x1c,0xaa,0x75,0x89,0x11,0xaf,0x11,0x6f,0x17,0x70,0x9b,0x95,0xee,0x36,0xe7,0xf7,0x83,0x60,0x9e,0x57,0x4d,0xce,0x1b,0xf1,0x76,0x5,0xf5,0x76,0x37,0xf1,0xbe,0x63,0x32,0xdd,0x88,0xb7,0x4b,0x60,0x63,0xd5,0x18,0xf1,0x1a,0x8c,0x78,0x3b,0x21,0xf3,0x27,0xa7,0xdb,0x44,0x46,0x78,0xbb,0x49,0x27,0x5f,0x97,0x9b,0x5c,0x37,0xe2,0xed,0x4a,0xac,0xe8,0x36,0xda,0xb5,0xd5,0xec,0xb4,0xd1,0x11,0x76,0x37,0x26,0x88,0x2f,0x63,0xa7,0xf9,0x53,0x54,0xe5,0x76,0xe0,0x4e,0xc0,0xd5,0x4d,0x92,0xbd,0x5a,0x85,0x5f,0x95,0x4d,0xf2,0x96,0x99,0x12,0x60,0xc4,0xdb,0x29,0xc9,0x2c,0x8,0x8c,0x6,0x1e,0x1,0x86,0x75,0x53,0x13,0x3c,0x6f,0x5b,0xf6,0xcd,0xf3,0x27,0x66,0xac,0x37,0xa5,0xc1,0x88,0x37,0x21,0x8c,0x7b,0x20,0xe0,0xb2,0x5d,0x72,0xbf,0xaa,0xce,0x2e,0x9b,0xec,0x5d,0xd8,0xd6,0xf0,0x46,0x15,0x2f,0xe8,0xe9,0xaa,0xf,0x17,0xa3,0xfc,0xc2,0x14,0x29,0x6a,0x54,0xf9,0xa5,0x1d,0xe,0x3d,0x53,0x7e,0xdb,0xe8,0x36,0xbd,0x3e,0x1a,0xfe,0xd8,0xdb,0xd6,0xe0,0xad,0x55,0x13,0x10,0xde,0x2f,0xcd,0xf7,0x56,0x18,0xd3,0x1a,0xf1,0x92,0x59,0x10,0xb8,0x1b,0xf8,0x2d,0xa0,0xc0,0x6c,0x41,0x7f,0x3d,0x2f,0xdf,0xf7,0x81,0xa3,0xb0,0xa6,0xfa,0x47,0x22,0xf2,0x2c,0xb1,0xef,0x4d,0xd5,0xd5,0x79,0xc1,0x25,0xae,0xeb,0xe7,0x4c,0x3a,0x67,0xab,0xb3,0x3c,0xa,0x5e,0xe,0xfa,0x0,0x91,0x69,0xa0,0x21,0x41,0x4f,0x99,0x97,0xef,0x7b,0xdf,0x98,0xb5,0x1b,0x8b,0x37,0xb3,0x20,0x70,0x25,0xf0,0xcc,0x1e,0x97,0x43,0xc0,0x13,0x2,0x77,0xce,0xcb,0xf7,0x7e,0xdb,0x9a,0x70,0xc6,0x14,0x4,0x5c,0x12,0xe9,0xd7,0xde,0x65,0x8a,0x51,0xb3,0x6c,0x14,0xe4,0xfc,0x79,0xf9,0x9e,0xc5,0xad,0xbd,0x61,0xcc,0xb4,0x80,0x4f,0x94,0x7,0x81,0xe1,0x7b,0x7c,0xb5,0x49,0x2c,0xfb,0xb8,0x79,0x13,0x33,0xbe,0x35,0x66,0xed,0x86,0xe2,0xcd,0x2c,0xf0,0xff,0x0,0x64,0x51,0xb,0xe9,0xde,0x1,0x4c,0x4d,0xad,0xae,0xfe,0xfd,0x2b,0x53,0xce,0xf,0x35,0x17,0xce,0xe8,0xe9,0xc1,0xfe,0x96,0xad,0xcf,0x1,0x99,0xa6,0x8,0xb5,0x8a,0x5b,0xc2,0xa1,0xd0,0xb4,0xf2,0xdb,0x46,0xdb,0x2d,0x78,0x30,0xc3,0x10,0x29,0x6,0xc6,0xb5,0x90,0x3f,0x1f,0x28,0x32,0xa2,0x2c,0xdf,0x53,0x65,0x4c,0xda,0x8d,0xc4,0x3b,0xf6,0x41,0xff,0xe1,0x6a,0xc9,0x7b,0x40,0xef,0x56,0xfc,0xfc,0x33,0x81,0x5f,0xcd,0xcb,0xf7,0x96,0x36,0x9,0xa7,0x20,0x78,0x82,0xa2,0x15,0xc0,0xbe,0xa6,0xf8,0xc4,0xc4,0x4b,0x82,0x5e,0x39,0x2f,0xdf,0x57,0xb3,0x67,0xbf,0x76,0x50,0x55,0xd5,0x6f,0x4,0xee,0x0,0x52,0x5b,0x11,0xce,0x5c,0x4b,0xac,0x8b,0xe6,0x4e,0x4a,0xaf,0x33,0xe2,0xed,0x6,0x8c,0x9b,0xea,0x1f,0x68,0x8b,0x2c,0x23,0xb2,0x84,0xae,0xb5,0x28,0xf0,0xf,0x45,0xb3,0xcb,0xf2,0x7d,0xeb,0x1b,0x5c,0xee,0x4c,0xe0,0x15,0x20,0xc5,0x68,0xd1,0x11,0xff,0xc1,0xd2,0x8c,0xd2,0x89,0xbe,0xcd,0xd,0xfd,0xda,0xc,0xd0,0xc7,0x89,0x76,0x5a,0x44,0xcb,0x14,0xd7,0xf6,0x24,0x37,0x78,0x73,0xf7,0x9e,0x4f,0xdd,0xe5,0xc5,0x9b,0x39,0x35,0xd0,0x13,0x61,0x3e,0x30,0xd2,0x61,0x10,0xd5,0xa,0xb7,0xa2,0x84,0xa5,0x75,0xa7,0xb,0x18,0x5a,0xe6,0x7f,0xaa,0x7a,0xae,0x88,0x4c,0x4,0x7e,0x8a,0xc3,0x89,0x42,0x2,0x37,0xcf,0xcb,0xf7,0x3e,0x6c,0xc4,0xdb,0x45,0x19,0x33,0xb5,0x54,0x44,0x52,0x9f,0x24,0x61,0xfb,0x36,0x19,0x3a,0xb8,0xf0,0x7a,0xe7,0xe5,0x7b,0x83,0xdd,0x35,0xfd,0x5d,0x7a,0x7a,0xa4,0x48,0xea,0xe5,0x46,0xb8,0x5d,0x17,0x85,0x57,0x32,0xb,0x82,0x43,0x4d,0xcb,0xdb,0xf5,0xdc,0xe5,0xc3,0x11,0x56,0x9a,0xfe,0x69,0x97,0xa7,0x52,0x61,0x74,0x59,0xbe,0xb7,0xdb,0x6d,0x6,0xd0,0x25,0x5b,0xde,0xb1,0xd3,0xfc,0x3d,0x11,0x66,0x1b,0xe1,0x76,0xb,0xd2,0x45,0xc8,0x32,0x6e,0x73,0x57,0x71,0xa7,0x54,0xee,0x4,0x4e,0x34,0xe5,0xba,0xdb,0xf8,0xcf,0xd3,0x32,0xa7,0x6,0x4e,0x30,0x6e,0x73,0x67,0x77,0x97,0xb,0xfc,0x27,0x81,0xbc,0x6b,0x4a,0x74,0xb7,0xe3,0x43,0x81,0x53,0xe7,0xe5,0x7b,0xbb,0xcd,0x46,0x8,0x5d,0xaa,0xe5,0x1d,0x53,0xe0,0x4f,0x3,0xf9,0x87,0x29,0xc7,0xdd,0x92,0x63,0x51,0x7e,0x69,0xdc,0xe6,0xce,0xea,0x46,0xa8,0xdc,0x0,0x1c,0x6f,0xca,0x71,0x37,0xf5,0x9e,0x85,0xa2,0x31,0x85,0xc1,0x43,0x8d,0x78,0x3b,0x9b,0xbb,0x3c,0xbd,0xb2,0x7,0xc2,0xfd,0xa6,0x8,0x77,0x6b,0x2c,0x9,0xeb,0x8d,0x46,0xbc,0x9d,0x8c,0xd2,0x89,0xe9,0x35,0xc0,0x4d,0xa6,0xfc,0x76,0x6b,0x6a,0x41,0x4b,0x8c,0x78,0x3b,0x21,0x29,0x96,0xfd,0x77,0x60,0xa1,0x29,0xc3,0xdd,0x96,0x6b,0x4b,0xf3,0x7d,0xdf,0x18,0xf1,0x76,0x42,0x5e,0x9d,0x98,0x11,0x2,0xae,0x22,0xb2,0x3e,0xd7,0xd0,0xbd,0xa8,0xb4,0xc2,0xcc,0xea,0x56,0x7d,0x84,0xae,0x96,0xa0,0xd2,0x7c,0xef,0xe7,0xc0,0x4,0x53,0x96,0xbb,0x15,0x21,0xb5,0xf8,0xd9,0xdc,0x5b,0xbd,0x21,0x23,0xde,0x4e,0x8e,0xc2,0x13,0xc0,0x52,0x53,0xa6,0xbb,0x9,0xca,0x8d,0x65,0x13,0xbd,0x5f,0x75,0xb7,0x64,0x77,0x49,0xf1,0x96,0xe5,0x7b,0xeb,0x54,0xb9,0xcc,0xb8,0xcf,0xdd,0x82,0x85,0x61,0xb7,0xf5,0x74,0x77,0x4c,0x78,0x97,0x5d,0x55,0x54,0x36,0xd9,0xfb,0xa9,0x98,0x15,0x45,0x5d,0x9d,0x6a,0x55,0x7e,0x5c,0x9e,0x97,0x5e,0x6f,0xc4,0xdb,0xc5,0xb0,0xb5,0xee,0x1f,0x34,0xdd,0x6c,0xce,0xd0,0x45,0x10,0x95,0xb,0xca,0x26,0x7b,0xd7,0x76,0xdb,0xf4,0x77,0xf5,0x4,0x8e,0x29,0x8,0xf6,0x13,0x74,0x5,0x66,0x6b,0xd6,0xae,0xc6,0x83,0xa5,0xf9,0xde,0x5b,0xbb,0xb3,0x1,0xba,0xfc,0x59,0x45,0x65,0xf9,0x9e,0xad,0xaa,0x7a,0x2e,0x91,0x3d,0xa9,0xc,0x5d,0x83,0x77,0xb1,0xcc,0x96,0xbb,0xdd,0xe2,0xa0,0xb1,0xb2,0xc9,0xbe,0xf7,0x80,0x9b,0x4d,0x99,0xef,0x12,0xd4,0xdb,0x22,0xe7,0x96,0x4e,0xf4,0xd6,0x18,0xf1,0x76,0x1f,0xca,0x4d,0xb9,0xef,0x12,0x6c,0x98,0x3f,0xc9,0xf3,0x95,0x31,0x83,0x39,0xe2,0xd3,0x60,0xe8,0xb4,0xb8,0x8d,0x9,0xda,0x8e,0x0,0x47,0xc,0xed,0xc3,0xf,0x8e,0x1c,0xcc,0x89,0x7,0xf6,0x67,0x50,0x9f,0x34,0x6,0xf6,0x4e,0x65,0x7b,0x5d,0x98,0xd,0xd5,0xb5,0x7c,0xb5,0x69,0x7,0x4b,0x3e,0x59,0xcf,0x5b,0xab,0x37,0x50,0x1b,0xb2,0x3b,0x7f,0x7a,0x5,0x4e,0x39,0x64,0x1f,0x7e,0x30,0x6c,0x30,0xc3,0x86,0xf6,0x61,0x50,0x9f,0x34,0xfa,0xf7,0x4a,0x61,0xf3,0xb6,0x3a,0xd6,0x57,0xd7,0xf2,0xc9,0xb7,0xd5,0xbc,0xbe,0x6a,0x3d,0x2b,0xbe,0xda,0x82,0xad,0x66,0xa8,0xc1,0x88,0x37,0x49,0x45,0x7b,0xea,0x61,0xfb,0x70,0xfd,0xd9,0xc3,0x18,0x36,0xb4,0x4f,0x93,0xef,0x7b,0xa7,0xb9,0x19,0xd2,0x37,0x8d,0x63,0xf7,0xef,0xc7,0xa8,0xe3,0xf7,0x25,0x14,0xb6,0x99,0xf5,0xd6,0x97,0xfc,0xfd,0x8d,0xcf,0xa9,0xef,0xa4,0x22,0x3e,0xef,0xe4,0x3,0xf8,0xf9,0x59,0x47,0xd0,0xb7,0x47,0xd3,0xa2,0xd3,0x73,0x40,0x4f,0xf6,0x1f,0xd0,0x93,0x93,0xe,0x1a,0xc0,0x8f,0x86,0x1f,0xc4,0x86,0xea,0x3a,0x9e,0xfa,0xf7,0xa7,0x94,0xff,0xf7,0x5b,0x23,0xe2,0x4,0x95,0xbf,0x6e,0x41,0x66,0x41,0xe0,0x28,0xe0,0xa3,0x78,0x85,0x97,0xe6,0xb6,0xb8,0xf5,0xdc,0xe3,0x38,0xf3,0xc8,0x21,0x31,0xdf,0x5b,0x5d,0x1b,0xe2,0x77,0x2f,0xaf,0xe0,0xdd,0x2f,0x37,0x77,0x1a,0xfb,0xd,0xe9,0x9b,0xc6,0x3,0x97,0x9d,0xc2,0x1,0x3,0x7a,0xc6,0x7c,0xef,0xaa,0xb5,0xd5,0xdc,0xf1,0xe2,0xbb,0x6c,0xde,0x1e,0x97,0x13,0x4a,0xd6,0x94,0xe6,0x7b,0xf7,0x37,0xd2,0x35,0x7d,0x5e,0x47,0xf4,0xef,0x95,0x4a,0xc9,0xcf,0x4e,0x73,0x24,0x5c,0x80,0x3e,0x69,0x6e,0xfe,0xf0,0xe3,0x93,0x39,0xff,0x94,0x3,0x3a,0x45,0x7a,0xff,0xef,0xe0,0x1,0xfc,0xf9,0xba,0x11,0x8e,0x84,0xb,0x30,0x6c,0x68,0x1f,0xfe,0x7c,0xfd,0x19,0x51,0xbd,0x13,0x83,0x11,0x6f,0xbb,0xd1,0x23,0xc5,0x45,0xd1,0x15,0xa7,0x72,0xc8,0xa0,0x5e,0x6d,0xa,0xc7,0x65,0x9,0x37,0xf9,0x8e,0xe2,0xfb,0xc3,0x6,0x25,0x75,0x7a,0x87,0xf6,0xeb,0xc1,0x7d,0x97,0x9c,0x4c,0xaa,0xbb,0x6d,0x45,0xa5,0x77,0xaa,0x9b,0xa2,0x2b,0xbf,0xc7,0xa0,0x3e,0x69,0xa6,0x10,0x99,0x3e,0x6f,0x7,0xd4,0x74,0x22,0xfc,0xfa,0xbc,0xe3,0xd9,0xbf,0x85,0x16,0x68,0xe5,0xca,0x95,0x94,0x97,0x57,0xf0,0xce,0x3b,0xef,0xb0,0x61,0xfd,0x6,0x5c,0x2e,0x17,0x43,0x86,0xc,0x61,0xf8,0xf0,0xef,0x31,0x6a,0xf4,0x28,0xe,0x39,0xe4,0x90,0xdd,0xc2,0xbb,0xe3,0xfc,0x13,0xb8,0xe6,0x4f,0x6f,0xb0,0xa1,0xba,0x36,0x29,0xd3,0xfc,0xd0,0x55,0xc3,0x71,0xbb,0x76,0xef,0x5d,0x55,0x55,0x55,0x31,0xe7,0xb5,0x39,0x2c,0x59,0xb2,0x84,0x35,0x6b,0xbe,0x65,0xc7,0x8e,0x1d,0xc,0x1a,0x34,0x90,0xe3,0x8e,0x3b,0x8e,0xb3,0xcf,0x3e,0x9b,0x33,0x46,0x9c,0x81,0x48,0xd3,0x1e,0x59,0x8a,0xcb,0xa2,0xf0,0x8a,0x53,0xf9,0xe5,0x13,0x6f,0x76,0x89,0x81,0x3b,0xd3,0xe7,0xed,0x44,0x7d,0xde,0x63,0xf7,0xef,0x47,0xd1,0x95,0xdf,0x8b,0xfa,0x5d,0x4d,0x4d,0xd,0xf,0xdc,0xff,0x20,0x95,0x95,0x95,0xcd,0x8b,0xdf,0xb2,0x38,0xff,0xfc,0xf3,0xc8,0xc9,0xcd,0xd9,0xed,0xfa,0xea,0x75,0xd5,0xdc,0xf4,0xd7,0xb7,0x93,0xce,0x66,0x37,0x67,0x1c,0xc5,0xf9,0xa7,0x1c,0xb8,0xdb,0xb5,0x67,0x9f,0xfd,0x7,0x4f,0x3e,0xf1,0x24,0xf5,0xf5,0xcd,0xaf,0x5,0x38,0xf1,0xc4,0x13,0xb9,0xf3,0xb7,0xbf,0x61,0xc8,0x90,0xe8,0xdd,0x8a,0x87,0xfd,0x1f,0x33,0x7b,0xd9,0xd7,0xa6,0xcf,0x6b,0xdc,0xe6,0x76,0x72,0x51,0x2c,0xe1,0xf6,0xf3,0xa2,0x6f,0x4c,0xb9,0x65,0xcb,0x16,0xae,0xbb,0xf6,0xfa,0x16,0x85,0xb,0x60,0xdb,0x36,0x2f,0xbf,0x3c,0x9b,0x1b,0x6f,0xf8,0x15,0xb6,0xbd,0xab,0xe5,0x39,0x6c,0x70,0x1f,0xe,0x1f,0xd2,0xbb,0x4d,0xf1,0x73,0x59,0x42,0xfa,0x31,0x43,0xb9,0xe6,0xac,0xc3,0x19,0x7d,0xc2,0x7e,0x51,0x47,0x83,0x63,0x4d,0xef,0xb8,0xff,0xdb,0xbd,0x4f,0x7e,0xef,0x3d,0xf7,0xf2,0xc7,0xc7,0xff,0xd8,0xa2,0x70,0x1,0x56,0xac,0x58,0xc1,0xd5,0x57,0xfd,0x9c,0xcf,0x56,0x7f,0x16,0xf5,0xfb,0x5f,0x79,0x8f,0xa4,0x4f,0x9a,0x71,0xfa,0x8c,0x78,0xdb,0x89,0x21,0xfd,0x7a,0x30,0xb4,0x5f,0x8f,0x26,0xd7,0x6b,0x6b,0x6b,0xc9,0xce,0xca,0x61,0xcd,0x9a,0x35,0xad,0xe,0xeb,0xe3,0x8f,0x3f,0x66,0x72,0xfe,0xe4,0x5d,0xee,0x8f,0x40,0xce,0xe8,0x63,0x1c,0xc7,0xed,0xc8,0xa1,0x7d,0x78,0xf6,0x57,0x67,0xf2,0xeb,0xf3,0x8e,0xe7,0x27,0x23,0xe,0x65,0xd2,0xd8,0x63,0xf9,0xc7,0x4d,0x23,0x19,0x7b,0x92,0xf3,0x6,0xea,0x82,0xef,0x1d,0x84,0xdb,0xda,0xe5,0x98,0x3d,0xf6,0xe8,0x63,0x54,0x54,0xf8,0x5b,0x7d,0x7f,0x6d,0x6d,0x2d,0xe3,0xc7,0xdf,0x4c,0x55,0x55,0x55,0xd4,0xee,0xc7,0xf1,0x7,0xf4,0x37,0x85,0xca,0x88,0xb7,0x7d,0x38,0xfb,0xe8,0xe8,0x2e,0x60,0x69,0x69,0x29,0x5f,0x7e,0xf9,0x65,0xcc,0xe1,0x2d,0x5f,0xfe,0xe,0xff,0xf9,0xcf,0xb2,0x46,0xad,0xaf,0xb3,0x96,0xd7,0x65,0x9,0x45,0x3f,0x1d,0x4e,0xbf,0x9e,0x29,0x4d,0xae,0xe7,0x8e,0x39,0x86,0x81,0xbd,0x53,0x1d,0x85,0x7b,0xe9,0x69,0x7,0x37,0xea,0xe3,0x56,0xf3,0xc2,0xb,0x2f,0xc6,0x1c,0x46,0x4d,0x4d,0xd,0xf,0x3e,0x30,0x35,0xea,0x77,0x3f,0x3b,0xf3,0x30,0x53,0xa8,0x8c,0x78,0xdb,0xa9,0xcf,0x7c,0xe2,0xfe,0x51,0x5b,0x97,0x92,0xe2,0x99,0x8e,0xc2,0x53,0x55,0xee,0xbb,0xf7,0xbe,0xef,0xfe,0x9f,0x96,0xe2,0xc2,0x65,0xc5,0x3e,0x4,0x71,0xf8,0xe0,0x3e,0xbb,0xb5,0x90,0x7b,0xf2,0x93,0x11,0xce,0xf6,0x20,0xef,0xd3,0xc8,0xed,0xbe,0xe7,0x9e,0x7b,0x8,0x87,0xc3,0x8e,0xc2,0x59,0xb4,0x68,0x11,0x9b,0x37,0x37,0x7d,0x9f,0x7d,0xf4,0x7e,0x7d,0x49,0x73,0x9b,0xe2,0x67,0xc4,0x9b,0x68,0x23,0x9,0xec,0x3f,0xa0,0xa9,0xcb,0xbc,0x61,0xfd,0x6,0xc7,0x85,0x1a,0x60,0xeb,0xd6,0xad,0xbb,0x5c,0x67,0xe0,0xe0,0x81,0xb1,0xbf,0x7e,0x3a,0xed,0xf0,0x81,0x2d,0x7e,0x3f,0xc2,0xe1,0xab,0x28,0xab,0xd1,0x68,0xf1,0x7b,0xef,0xbe,0xd7,0x26,0xfb,0xad,0x58,0xb1,0x22,0xea,0xf5,0x54,0xb7,0xcb,0x14,0x2e,0x23,0xde,0xc4,0x92,0xea,0x76,0xed,0x56,0x98,0x77,0xf2,0x85,0x3,0x77,0xb9,0x31,0xa1,0x50,0x88,0xf5,0xeb,0xd7,0xef,0x72,0x9d,0x7,0xf5,0x76,0x54,0xb1,0xb4,0x84,0xd3,0xd7,0x9,0x8d,0xbd,0x80,0x50,0xa8,0x6d,0x5b,0x81,0xbd,0xf5,0x56,0xf4,0x91,0xf4,0x14,0xb7,0x98,0xc2,0x65,0xc4,0x9b,0x58,0x42,0x76,0xf4,0x77,0x92,0x6b,0xbf,0x6d,0xfb,0xe,0x2c,0xdf,0x7c,0xb3,0x6b,0xa0,0x6b,0xc3,0xb6,0xba,0xa4,0x49,0x73,0xe3,0xb9,0xc8,0xb6,0xdd,0xb6,0x77,0xb2,0xdf,0xae,0xf9,0x36,0xea,0xf5,0xb0,0x6d,0xe6,0x3b,0x1b,0xf1,0x26,0x5a,0xbc,0x61,0xa5,0x6a,0x47,0xd3,0xd7,0x23,0x7,0x1c,0xd8,0xf6,0xd7,0x8d,0x7,0x1d,0xb4,0xeb,0x3d,0xea,0xa7,0xeb,0xaa,0x93,0x48,0xbc,0x8d,0xa,0x89,0xd5,0xb6,0x62,0x72,0xe0,0x81,0xd1,0xa7,0x81,0xd6,0x99,0x89,0x1a,0x46,0xbc,0xed,0xc1,0xf2,0x28,0x8b,0x8,0xe,0x3c,0xf0,0xc0,0x36,0x85,0x99,0x92,0x92,0xc2,0x3e,0xfb,0xec,0xf3,0x5d,0x5,0xb1,0xad,0x36,0x79,0x76,0xaa,0xd,0x85,0xed,0xdd,0xe2,0xd9,0x16,0xce,0x18,0x71,0x46,0x93,0x6b,0xdb,0x6a,0x43,0xd4,0xd6,0x1b,0xf1,0x1a,0xf1,0xb6,0x3,0x2f,0x2d,0x6d,0xba,0x79,0xc3,0xe0,0xc1,0x83,0x49,0x4d,0x4d,0x75,0x1c,0xe6,0x4e,0xe1,0x2,0x54,0xd5,0x24,0xd7,0xee,0xa5,0xcb,0x3e,0xdf,0xf4,0xdd,0xdf,0xa7,0x9f,0x7e,0x7a,0x9b,0xc2,0x3a,0xee,0xd8,0xe3,0x9a,0x5c,0xfb,0xe7,0xd2,0x2f,0xcd,0x32,0x41,0x23,0xde,0xf6,0xe1,0x8b,0xd,0xdb,0xa2,0xb6,0x9c,0xb7,0xdc,0x32,0xd9,0x51,0x78,0x22,0xc2,0xdd,0xbf,0x9b,0xf2,0xdd,0xff,0x5f,0x78,0xfb,0xcb,0xa4,0x4a,0xef,0xe3,0xc1,0x4f,0xbe,0xdb,0xb1,0xef,0xd7,0xb7,0xdf,0x86,0xdb,0xed,0x6c,0x46,0xd4,0xd8,0x71,0x63,0xe9,0xd7,0xbf,0x5f,0x93,0xeb,0xe5,0xef,0x7f,0x6b,0xa,0x95,0x11,0x6f,0xfb,0x50,0x5d,0x1b,0xe2,0xc9,0x7f,0xaf,0x6e,0x72,0xfd,0xec,0x73,0xce,0xe6,0xb8,0xe3,0x8e,0x8b,0x39,0xbc,0xb3,0xcf,0x3e,0x9b,0x63,0x8e,0x89,0xcc,0xaa,0xaa,0xa9,0xf,0xf3,0x62,0x92,0x89,0xf7,0x9b,0x2d,0x35,0xac,0xd9,0xbc,0x3,0x80,0xb4,0xb4,0x34,0xae,0xbf,0xfe,0xba,0xa8,0x8b,0xd,0x5a,0xa2,0x7f,0xff,0xfe,0x64,0x65,0x35,0x3d,0x36,0x6a,0xc5,0x57,0x9b,0x59,0x5b,0x55,0x63,0xa,0x95,0x11,0x6f,0xfb,0x31,0x7b,0xd9,0x57,0x4d,0xfa,0x69,0x29,0x29,0x29,0x4c,0x2d,0x78,0x90,0x61,0xc3,0x86,0xb5,0x3a,0x9c,0xe1,0xc3,0x87,0x33,0xe5,0xee,0x5d,0x3b,0x97,0x3e,0xe2,0xff,0x24,0x29,0xd3,0xfb,0xeb,0x17,0xde,0xf9,0xce,0xb5,0xbd,0xfc,0x27,0x97,0x73,0xd1,0x8f,0x2e,0x6a,0xb5,0x80,0xfb,0xf5,0xeb,0xc7,0xa3,0x8f,0x3d,0x42,0xcf,0x9e,0x4d,0x57,0x60,0x3d,0x38,0xf7,0x43,0x8c,0xc7,0x6c,0xc4,0xdb,0xae,0x6c,0xaf,0xb,0x73,0xcb,0xf3,0xcb,0x9a,0x5c,0xef,0xd5,0xab,0x17,0xf,0x3d,0x3c,0x93,0xb,0x2e,0xbc,0xa0,0xc5,0xfb,0x53,0x52,0x52,0xb8,0xfa,0xea,0xab,0x98,0x5a,0xf0,0xe0,0x77,0xd7,0xde,0xfc,0x74,0x3,0xa5,0x2b,0x92,0xf3,0x48,0xd9,0x35,0x5b,0x6a,0x78,0x7a,0xf1,0x67,0xdf,0xfd,0x3f,0x2b,0x6b,0x2,0x93,0xf2,0x27,0xd1,0xb7,0x6f,0xdf,0x16,0xef,0x3b,0xeb,0xac,0x91,0x3c,0xfd,0xb7,0xbf,0xb2,0xef,0xbe,0xfb,0x36,0xf9,0x6e,0xc6,0xfc,0x95,0xac,0xdd,0x6a,0x5a,0xdd,0x78,0x60,0x96,0x76,0xc4,0xc8,0xca,0x35,0x55,0x14,0xcc,0xfd,0x90,0xfc,0x71,0xc7,0xee,0x76,0x3d,0x35,0x35,0x95,0xdc,0xdc,0x1c,0xae,0xb8,0xe2,0xa,0x2a,0xca,0xcb,0x59,0xb6,0x7c,0x79,0xa3,0xf5,0xbc,0x83,0x39,0xed,0xf4,0xd3,0xc9,0xc8,0xf0,0xd1,0xbf,0xff,0xae,0x9,0xf9,0xab,0xd7,0x55,0xf3,0xdb,0x97,0xde,0x4b,0xea,0xf4,0x3e,0xbb,0xe4,0x73,0xe,0x1d,0xd4,0xb,0xcf,0xb1,0x11,0x21,0xfe,0xf0,0x87,0xe3,0x18,0x33,0x66,0x34,0xfe,0xa,0x3f,0x8b,0x17,0x2f,0xde,0x6d,0x3d,0xef,0xf1,0xc7,0x1f,0xcf,0x39,0xe9,0xe7,0x70,0xf4,0xd1,0x47,0x47,0xd,0xeb,0x95,0x65,0x5f,0x33,0xef,0xbd,0x6f,0x4c,0x21,0x32,0xe2,0xed,0x38,0xca,0xff,0xbb,0x86,0xaa,0x9a,0x7a,0xee,0xbc,0xf0,0x4,0xdc,0x7b,0xbc,0x3,0xdd,0x77,0xdf,0xa1,0x5c,0xf9,0xd3,0x2b,0xb9,0xf2,0xa7,0x57,0xb6,0x18,0xc6,0x82,0x95,0x6b,0xf9,0xc3,0x6b,0xff,0x6d,0x73,0x5c,0xf6,0x36,0xcf,0x21,0x1e,0xee,0xe9,0xfd,0xaf,0x7d,0xc0,0xd7,0x9b,0x76,0x70,0xe5,0xf7,0xf,0x43,0x4,0xdc,0x6e,0x37,0x63,0x32,0xc7,0x30,0x26,0x73,0x4c,0xab,0xc3,0xf8,0x53,0xe5,0x2a,0x5e,0x5c,0xfa,0xa5,0x71,0x97,0x8d,0xdb,0xdc,0xf1,0xbc,0xf1,0xe9,0x6,0x7e,0xf1,0x97,0x37,0x59,0xb2,0x6a,0x7d,0x4c,0xf7,0x6d,0xd9,0x51,0x4f,0x51,0xd9,0x4a,0xee,0x7b,0xf5,0xbf,0x71,0x29,0xc8,0x6f,0xad,0xde,0xd8,0xe2,0xf7,0x4b,0x3e,0xdd,0x10,0x97,0xf4,0x3e,0xbd,0xf8,0x33,0x7e,0xfb,0xd2,0xbb,0x7c,0x1e,0x65,0xd4,0xbd,0x25,0x3e,0x5a,0x53,0xc5,0xe4,0xe7,0x96,0xf3,0xc2,0xdb,0x46,0xb8,0xa6,0xe5,0x4d,0xb2,0x3e,0xe1,0x94,0x7f,0xad,0xe0,0x84,0x3,0xfb,0x33,0xfa,0x84,0xfd,0xf8,0xfe,0xb0,0x41,0xc,0xe8,0x95,0x1a,0xa5,0x75,0x54,0x56,0x7c,0xb5,0x85,0x45,0x9f,0xac,0xe7,0xd5,0xe5,0x5f,0xc7,0x75,0x5a,0xe0,0x67,0xeb,0xab,0x9,0xd9,0xda,0xec,0xca,0xa2,0xe7,0xde,0xf8,0x3c,0x6e,0xcf,0x7a,0x6b,0xf5,0x46,0xde,0x5a,0xbd,0x11,0xdf,0x71,0xfb,0x72,0xf6,0xd1,0x43,0x38,0xfd,0xf0,0x81,0xb8,0x5d,0x4d,0xeb,0xff,0xda,0x50,0x98,0xb7,0x3e,0xdd,0x48,0xe5,0xca,0xb5,0xfc,0xfb,0xe3,0x75,0x46,0xb4,0x46,0xbc,0xc9,0xcb,0xfb,0x5f,0x6f,0xe1,0xfd,0xaf,0xb7,0x20,0x22,0x1c,0xb4,0x4f,0x4f,0x6,0xf7,0x49,0x63,0x60,0x9f,0x5d,0x9b,0xae,0xff,0x6f,0xd3,0xe,0xaa,0x13,0x34,0x7b,0x2a,0x6c,0x2b,0xb9,0xcf,0x2c,0xe5,0xbe,0x1f,0x9f,0xbc,0xdb,0x9a,0xde,0xb0,0xad,0x94,0x94,0x7f,0xc4,0xc6,0x4,0xcc,0x97,0xf6,0x7f,0xf0,0x2d,0xfe,0xf,0xbe,0xc5,0xed,0x12,0xe,0x19,0xd8,0x9b,0x41,0x7d,0xd2,0x18,0xd0,0x2b,0x85,0x4d,0xdb,0xeb,0xd8,0x50,0x5d,0xcb,0x17,0x1b,0xb6,0x9b,0x79,0xcb,0x46,0xbc,0x9d,0xb,0x55,0xe5,0xcb,0x8d,0xdb,0xf9,0x72,0xe3,0xf6,0x76,0x7d,0xee,0x27,0x6b,0xab,0xb9,0xe2,0xd1,0xc5,0x8c,0x3c,0x6a,0x8,0x87,0xe,0xea,0xc5,0x37,0x5b,0x6a,0x78,0x63,0xd5,0x7a,0xaa,0x6a,0x12,0x3b,0xdd,0x32,0x14,0x56,0x3e,0x5d,0x57,0x9d,0x54,0x73,0xb2,0x8d,0x78,0xd,0x9d,0x8e,0xb0,0xad,0x2c,0x58,0xb9,0xd6,0x18,0xa2,0x1b,0xd1,0x9d,0x6,0xac,0xc2,0x26,0xbb,0xd,0x46,0xbc,0x9d,0x90,0xd2,0x7c,0xef,0xa7,0x88,0x1e,0x2,0x92,0xf,0xbc,0x69,0xb2,0xbe,0x53,0xb2,0x4,0xf8,0x9d,0x31,0x43,0x84,0x2e,0xb9,0x95,0xc1,0x98,0x82,0xc0,0x71,0x67,0x56,0x57,0x7e,0x38,0x65,0xca,0x94,0x66,0x47,0x4d,0x32,0xa7,0xf9,0xf,0x43,0xe5,0x77,0xc0,0x55,0xa6,0x18,0x24,0x3d,0x4f,0x22,0x3a,0xa5,0x74,0x92,0xef,0x73,0x63,0x8a,0x2e,0x2c,0xde,0xe1,0x8f,0xbd,0x2d,0x83,0xab,0xaa,0xd6,0x3,0x75,0xc0,0xf3,0x82,0xce,0x9a,0x97,0xef,0xfb,0x77,0xb4,0xdf,0xfe,0xb0,0xa0,0x22,0x2d,0x8c,0xb5,0x9,0xe8,0x69,0x8a,0x42,0xd2,0xb2,0xdd,0x85,0xbd,0xcf,0x9c,0xfc,0x8c,0xa8,0xc3,0xe6,0x63,0xb,0xfc,0x67,0x2b,0x72,0x19,0xb0,0xb0,0x34,0xdf,0xfb,0xbc,0x11,0x6f,0x27,0x66,0x6c,0x41,0x60,0x90,0xc2,0x9e,0x33,0x27,0xbe,0x6,0x66,0x21,0x3c,0x5f,0x3a,0xc9,0xfb,0xfa,0x6e,0x2d,0x70,0x41,0xe0,0x7d,0xe0,0xf8,0xbd,0x4,0xbb,0xe,0xf8,0x17,0x70,0x0,0x70,0x6a,0xc3,0xbf,0x6,0x67,0x7c,0xd,0x2c,0x3,0xbe,0x1,0x2e,0x6,0xf6,0xb6,0x43,0xde,0x8a,0xd2,0x7c,0xef,0x49,0xbb,0x7b,0x4d,0x81,0x33,0x51,0x2e,0x3,0x2e,0x3,0x76,0x6e,0x67,0x32,0xa3,0x34,0xdf,0x9b,0xdb,0x9d,0xc,0xd9,0xf5,0x46,0x9b,0x95,0x81,0x51,0xaa,0xa4,0x3,0x81,0x5c,0x94,0xdc,0xcc,0x82,0xc0,0x82,0xd2,0x7c,0x6f,0x7a,0x2c,0x35,0x3f,0xb6,0x7d,0x7c,0xe9,0x2d,0x19,0xeb,0x1b,0x15,0x9e,0xa1,0xa8,0x9c,0xa,0x7a,0x2a,0x70,0x72,0x83,0xa0,0x8f,0x31,0xba,0x6c,0xc2,0xca,0x6,0xa1,0x2e,0x7,0x59,0x86,0xe8,0xf2,0xd2,0x49,0xde,0xb5,0xbb,0x2a,0xda,0xe0,0x6f,0x14,0xfd,0x1c,0xe8,0xd1,0xda,0x0,0x33,0xb,0x2,0x8b,0x51,0x7e,0x10,0xe5,0xab,0xe3,0xba,0x9b,0x71,0xbb,0x9c,0x78,0x55,0xf6,0x5a,0x10,0xf6,0x89,0x31,0xc8,0xf5,0x8d,0x85,0xb,0xd0,0x50,0x0,0x4b,0x1b,0x3e,0x0,0x9c,0xfb,0xc0,0x82,0x5e,0xf5,0x2e,0xfb,0x14,0x89,0x8,0xfa,0x94,0x6,0x41,0x9f,0x4,0xa4,0x76,0x83,0x72,0x54,0x7,0xbc,0x1b,0x11,0x29,0xcb,0x14,0x59,0x9e,0x12,0xb6,0x96,0xbf,0x76,0xeb,0x39,0x2d,0xbe,0xf0,0x9e,0x97,0xef,0x59,0x9b,0x59,0x10,0xd8,0x18,0xa3,0x27,0x33,0xa0,0x99,0xeb,0x46,0xbc,0x5d,0x80,0x78,0x8b,0xa5,0x55,0x53,0x85,0x1a,0xa,0xea,0xe2,0x86,0xf,0x0,0x23,0xff,0xf8,0xa6,0xab,0xef,0xd6,0xed,0x27,0xa8,0xad,0xa7,0x21,0xdc,0xe,0xc,0xeb,0x42,0x76,0xfe,0x4,0xe5,0x5e,0xb1,0x64,0xe9,0xe6,0x81,0x7d,0xde,0x5f,0x72,0xed,0x69,0x76,0x22,0xed,0xdb,0xa,0xe,0x3a,0x7f,0xca,0x6c,0x79,0x65,0xca,0x5,0x6a,0xc4,0xdb,0x79,0xdb,0xde,0xed,0x89,0xec,0xca,0x67,0x16,0x4,0xc6,0x3,0x35,0x8,0xcb,0xd4,0xae,0x5b,0x51,0x36,0x39,0xb3,0xd9,0xcd,0xa7,0x16,0xfd,0xf2,0x8c,0x70,0x43,0x8b,0xf4,0x6e,0x66,0x41,0xe0,0x65,0x9a,0xf6,0xc5,0x5b,0x5b,0xb8,0x3f,0x4,0xb6,0x37,0x8c,0x51,0x48,0xa3,0xf1,0x8a,0x3d,0xff,0x96,0x3d,0x4,0xa1,0x7b,0xf9,0xbb,0x57,0x1b,0x5a,0xac,0xd3,0x4a,0x27,0x7b,0xb7,0xb4,0xe6,0x87,0x63,0xa6,0x96,0xa6,0x88,0x95,0x7a,0x12,0xca,0x29,0x40,0x5a,0x69,0xbe,0xf7,0x91,0x4,0x64,0xcd,0x86,0xee,0x24,0xdc,0x2e,0xda,0xe7,0x95,0xaa,0x84,0xe,0xc3,0x9,0x3f,0x46,0xf1,0xa2,0x20,0x92,0x1a,0xca,0x2c,0x8,0xac,0x68,0xdc,0xaf,0x73,0x11,0x5e,0x3e,0x27,0x3f,0xa3,0xc9,0xe9,0x5a,0x6a,0x6b,0x95,0xc4,0x7e,0x9c,0x89,0xa2,0x7a,0x59,0xe9,0x64,0xdf,0xb,0x89,0xab,0x8c,0x82,0x57,0x80,0x3e,0x43,0x8c,0x35,0x9e,0xda,0x1a,0xd5,0x25,0xfe,0x61,0x41,0x45,0xbf,0x30,0xae,0x93,0x1b,0xc6,0x3,0x76,0x7e,0x4e,0x40,0x1b,0xca,0x9a,0x50,0x1,0x24,0x42,0xbc,0x9f,0x19,0xb7,0xb9,0xb3,0x23,0x5a,0xdd,0x8e,0x83,0xe8,0xee,0x86,0xfe,0xed,0x29,0x3b,0xb5,0x16,0xc6,0xd2,0xcc,0x82,0xc0,0xaa,0x6,0x41,0xcf,0x29,0xcd,0xf7,0x3e,0x19,0xf9,0x46,0x9c,0xc4,0xaa,0x36,0x91,0xc2,0x5,0x28,0xcd,0xf7,0x3c,0x9b,0x59,0x10,0x78,0xa,0x48,0x89,0xad,0x56,0x91,0xc6,0xde,0xc8,0x75,0xc0,0x38,0xe0,0xd4,0x30,0x1c,0x1,0xda,0x11,0x6f,0x31,0x56,0x1b,0xf1,0x76,0x72,0xc2,0xa1,0xf0,0x56,0x97,0x3b,0x65,0x3,0x68,0x6b,0xf,0xe9,0x29,0x7,0xe,0x6b,0x70,0x21,0xe3,0xd3,0x36,0xc3,0x91,0xd,0x9f,0xfd,0x80,0x27,0x13,0xdd,0xdf,0x4e,0x2,0x6e,0x0,0x46,0x24,0x20,0xdc,0x6d,0xd,0xf9,0xd3,0x1a,0x8f,0xeb,0xd,0x23,0xde,0x4e,0x4e,0xf9,0x6d,0xa3,0xed,0xcc,0x82,0xc0,0xdf,0x80,0x9c,0xd6,0xb5,0x3c,0xde,0x9c,0xd1,0x33,0x17,0xde,0xe2,0xda,0x11,0x1a,0xab,0xc2,0xc5,0xc0,0x5,0x34,0x3f,0xa2,0xd9,0xa1,0x64,0x16,0x4,0xb2,0x81,0xf3,0x1a,0xf5,0x59,0x9b,0xfb,0x58,0x2d,0xf4,0x89,0x5,0x98,0x5d,0x9a,0xef,0x9d,0x99,0xa4,0x59,0xb8,0x19,0x78,0x59,0x94,0x7f,0x86,0x7a,0xb9,0xe7,0x95,0xdf,0x7c,0x76,0x5d,0x94,0xca,0x31,0x9a,0xc7,0x55,0x6e,0xc4,0xdb,0x25,0xfa,0xbd,0xbc,0x84,0x34,0x2b,0xde,0x3,0x2f,0x9d,0xbe,0xd8,0x35,0x6b,0xe2,0x99,0xdf,0x2d,0x54,0x98,0x3f,0xe1,0xec,0x5a,0xe0,0x65,0xe0,0xe5,0x71,0x5,0xe5,0x6e,0x5b,0xdc,0x19,0xa8,0x5e,0x2,0x5c,0x98,0x64,0x29,0x3b,0x16,0x18,0x1d,0x87,0x70,0x56,0x26,0x59,0xba,0xd6,0x2,0x2f,0x21,0xf2,0x4f,0x4b,0x43,0xfe,0xb9,0xf9,0xa3,0xa2,0xae,0x65,0xbc,0x74,0xfa,0x62,0xf7,0x56,0xbb,0x76,0xdf,0x66,0xfc,0x9d,0x4f,0x8d,0x78,0xbb,0x42,0xb7,0xd7,0xe2,0xc3,0x16,0x76,0x6f,0x18,0xb8,0xd5,0xae,0x7d,0x27,0xb3,0x20,0x70,0x57,0xc8,0x1d,0x9e,0x53,0x91,0x3b,0x6a,0x47,0xe3,0x2f,0x1b,0xa,0x4e,0x29,0x50,0x3a,0x66,0x5a,0xe5,0x4d,0xa2,0xf6,0x29,0x18,0x12,0xc9,0x85,0x2a,0xd6,0xf2,0xb2,0x49,0xe9,0xcd,0xae,0xfa,0xca,0x2c,0x5c,0xd0,0x8b,0x70,0xf8,0xdc,0xad,0x76,0xed,0xef,0x88,0xfe,0x9e,0x3e,0x50,0x3a,0xc9,0x5b,0x65,0xc4,0xdb,0x5,0x98,0x37,0xc9,0xfb,0xed,0x98,0xa9,0x81,0x7f,0x88,0xf0,0x93,0x66,0x7e,0x72,0x2,0xf0,0x82,0x3b,0xe4,0xaa,0xc9,0x2c,0x8,0xcc,0x5,0xfe,0x69,0xdb,0xd6,0xec,0xf9,0xb7,0xa4,0x6f,0x6d,0xfc,0xa3,0x86,0x2,0xb5,0xd4,0xe8,0x2b,0x71,0x94,0xe6,0x7b,0xa3,0xda,0x77,0xec,0x3,0xfe,0x1,0xea,0x92,0xb,0x80,0x8b,0x9,0x87,0xc7,0x2,0x69,0xcd,0xd7,0xd6,0x72,0x57,0x77,0xb4,0x5d,0xd7,0x5d,0x8c,0x6f,0x71,0x2f,0xda,0xac,0x78,0x77,0xd2,0x3,0xf8,0x11,0xf0,0x23,0xcb,0xb2,0xeb,0x33,0xb,0x2,0x15,0xc0,0x3f,0x71,0xd9,0xff,0x2a,0xcd,0xcb,0x58,0xd7,0x8c,0x4b,0x6e,0x4e,0x84,0x6e,0x5b,0x97,0xa6,0xd9,0x32,0x37,0x66,0xaa,0x7f,0x5f,0x11,0xb9,0x10,0xb8,0x44,0xc1,0xd7,0xca,0xf2,0xf9,0xd,0xe1,0xf0,0x1b,0x46,0xbc,0x5d,0x88,0xba,0x2a,0xde,0x4f,0xeb,0xcd,0x9b,0x8,0x67,0xb4,0xf2,0x96,0x14,0x60,0x2c,0x30,0x96,0xb0,0xf5,0x48,0x66,0x41,0x60,0xa1,0x20,0xff,0xc,0xdb,0xe1,0x7f,0xcd,0xbf,0x25,0xe3,0x4b,0x80,0x31,0xd3,0x2,0xbd,0x51,0x67,0xa3,0xaa,0x16,0xe1,0x30,0xb8,0x4a,0x80,0x23,0x88,0xcc,0xb4,0x1a,0x46,0x8c,0xaf,0x67,0x3a,0xda,0xa4,0xc0,0xa7,0xc0,0x2a,0x60,0x55,0x24,0x3d,0x8e,0x18,0x31,0x66,0x5a,0xa0,0x67,0xd9,0x24,0xef,0xe,0x80,0xb1,0x5,0xfe,0x43,0xc0,0xba,0x48,0xd1,0x4b,0x80,0x91,0x10,0x73,0xe5,0x98,0x53,0x7a,0x4b,0x46,0x9d,0x11,0x6f,0x17,0x22,0x38,0xc5,0xab,0x63,0xb,0x2,0x13,0xd4,0xd9,0xc2,0x7b,0x17,0xe0,0x51,0xd4,0x63,0x59,0x56,0x51,0x66,0x41,0xe0,0x2d,0xe0,0x6d,0x94,0x73,0x5a,0x74,0xdf,0x5a,0x72,0xf,0x6f,0x19,0x15,0x6,0xb2,0x77,0xb5,0x32,0xa5,0x62,0x91,0x76,0x30,0xe8,0x91,0x2a,0xdf,0x89,0x79,0xa7,0xb0,0x8f,0x4,0xfa,0x75,0x80,0xd9,0xb6,0xec,0x14,0xe7,0xce,0x8f,0x28,0xab,0x40,0x56,0xd9,0xd4,0x7e,0x59,0x36,0x39,0x33,0x1e,0xaf,0xae,0x7a,0x88,0xf2,0x7a,0x66,0x41,0xe0,0xdf,0xc0,0xe9,0xa,0xa7,0xb7,0xe1,0xbd,0xf0,0xd7,0x22,0xcc,0xe9,0xae,0x4e,0x4c,0x97,0xde,0xc3,0x6a,0x5e,0xbe,0xf7,0xad,0xcc,0x82,0xc0,0x43,0xc0,0xcd,0x6d,0x72,0xc0,0x23,0xef,0x30,0x9d,0xb4,0xb8,0x87,0x35,0xf7,0x45,0x83,0x10,0xbe,0x68,0xf8,0xf8,0xf7,0xfc,0x7e,0xdc,0xb4,0x8a,0xc1,0xb6,0x6d,0x1d,0xde,0x4e,0xae,0xec,0x48,0x97,0x15,0x5e,0x3d,0x67,0xd2,0xa8,0xf5,0xe,0x43,0x38,0x34,0xc6,0xdf,0x9f,0xdc,0xf0,0x69,0x13,0x2,0x3f,0x9a,0x37,0xc9,0xbb,0xcd,0x88,0xb7,0xab,0x22,0xfa,0x1b,0x54,0x2e,0x7,0x6,0x77,0xc0,0xd3,0xf,0xcc,0x2c,0x8,0x3c,0x24,0xe8,0x5f,0xc4,0xd6,0x55,0x73,0x6f,0xc9,0xd8,0xdc,0xda,0x1b,0xe7,0x4e,0xca,0x58,0x8f,0xb3,0xb9,0xd0,0xb1,0x7b,0x5,0x93,0xbd,0x6f,0xc5,0x7a,0xcf,0xb8,0x7,0x2b,0x6,0xa8,0x25,0xc3,0x14,0xf9,0x25,0x30,0xb4,0xdd,0xb3,0x15,0x1e,0x9a,0x97,0x1f,0x7b,0xbc,0x8d,0x78,0x3b,0x11,0xa5,0x93,0x7c,0x9b,0xc7,0x16,0x4,0x2f,0x51,0xb4,0xb2,0x3,0x1e,0x6f,0x1,0xe3,0x15,0x19,0xaf,0x96,0x90,0x59,0x10,0xd8,0xb0,0xbb,0x5b,0x2a,0x9f,0xaa,0xe8,0x2a,0xcb,0x96,0x55,0xf3,0x26,0x7b,0xbe,0x6e,0x45,0x78,0x7,0xc5,0x29,0x5e,0x7,0xb7,0xe6,0x47,0x63,0xa7,0x6,0xf,0xb4,0x2d,0x1d,0x26,0x2a,0xc3,0x40,0x77,0x73,0xed,0xed,0xbd,0x2f,0xa2,0x4f,0x24,0x5f,0x28,0x7a,0x3b,0xdd,0x1c,0xe9,0x2e,0x9,0xcd,0x2c,0x8,0x4c,0x0,0x4a,0x92,0x38,0x8a,0x35,0x7b,0xf4,0x37,0x3f,0x5,0x56,0x89,0xe8,0x2a,0xf7,0xb6,0x1d,0x9f,0xd5,0xf7,0xea,0x95,0x9,0xcc,0x8e,0xe3,0xf3,0xce,0x4d,0xd9,0xb6,0xad,0x3c,0xd4,0xa7,0xd7,0x61,0xaa,0xb2,0x53,0x98,0x7b,0xf6,0xbd,0x7b,0x24,0xa1,0x9d,0xb6,0xab,0x70,0x7c,0xd9,0x24,0x6f,0xb7,0xdf,0xcf,0xaa,0xdb,0xec,0xdb,0xac,0x5a,0xf7,0x90,0x48,0xea,0xb1,0x6d,0xec,0xff,0x26,0x92,0x1e,0x44,0xde,0x3f,0x9f,0xb0,0x7b,0xbc,0x85,0xfa,0x5e,0xbd,0x12,0xf1,0xbc,0xd7,0xea,0x7b,0xf7,0xee,0x3c,0xb3,0xa7,0x77,0x91,0x61,0x84,0xbb,0xcb,0xad,0xeb,0x16,0x94,0x4d,0xce,0x54,0x4b,0xac,0x89,0xc0,0xab,0x26,0xdb,0x3b,0x6d,0x15,0x7c,0x65,0x69,0xbe,0x77,0x89,0xb1,0x43,0x37,0x13,0x2f,0xc0,0xdc,0x49,0xe9,0x75,0xaa,0xfa,0x63,0xe0,0x19,0x93,0xf5,0x9d,0x4b,0xb5,0xa2,0x72,0x69,0x69,0xbe,0xef,0x59,0x63,0x8a,0x6e,0xd8,0xe7,0x6d,0xcc,0xd8,0xc2,0x80,0x5b,0xc3,0x14,0x2,0x13,0x4c,0x11,0x48,0x7a,0xea,0x5,0xcd,0x9c,0x97,0xef,0xb,0x18,0x53,0x74,0xe3,0x96,0x77,0x27,0xf3,0xf2,0xbc,0xa1,0x70,0x28,0x94,0x83,0x70,0xa7,0x29,0x2,0x49,0xcd,0x7a,0x90,0x11,0x46,0xb8,0xa6,0xe5,0x8d,0x4a,0x66,0x41,0xc0,0xb,0xcc,0xa2,0x63,0x5f,0x7d,0x18,0x9a,0x52,0x66,0x69,0xf8,0x27,0x73,0x27,0x8f,0xda,0x64,0x4c,0x61,0x5a,0xde,0xa8,0x94,0xe6,0x7b,0x3,0x60,0x1f,0xb,0x54,0x98,0xe2,0x90,0x34,0xfc,0xd6,0xb2,0xed,0x1f,0x1a,0xe1,0x9a,0x96,0xb7,0x75,0x2d,0xf0,0xf4,0x80,0x1b,0x25,0x7,0xe5,0x5e,0x1c,0xce,0x5f,0x36,0xb4,0x99,0xf7,0x11,0xb9,0xa1,0x74,0x92,0x67,0xb1,0x31,0x85,0x11,0x6f,0xcc,0x8c,0x79,0xb0,0x62,0x3f,0xb1,0xac,0x87,0x89,0x2c,0x15,0x34,0xb4,0xf,0xf5,0xc0,0x9d,0xaa,0x3a,0xbd,0x6c,0xb2,0xaf,0xde,0x98,0xc3,0x88,0xd7,0x31,0xc3,0x1f,0x7b,0x5b,0x6,0x55,0x55,0x9d,0x2b,0x50,0x44,0xd7,0xda,0x28,0x3d,0x19,0xf9,0x97,0x4b,0xf4,0xe6,0x39,0x93,0x7c,0xff,0x33,0xa6,0x30,0xe2,0x8d,0x5f,0x2b,0x3c,0x35,0xe0,0x16,0xf8,0x39,0xc2,0x6f,0x68,0x61,0x85,0x90,0xc1,0x11,0x73,0x10,0xbd,0xab,0x74,0x92,0xef,0x6d,0x63,0xa,0x23,0xde,0xc4,0xf5,0x87,0x1f,0xac,0x48,0xc1,0xb2,0xae,0x5,0x7e,0x43,0x2b,0x27,0xf5,0x1b,0x9a,0xa5,0x14,0xd5,0xbb,0x4a,0x27,0xfb,0xde,0x30,0xa6,0x30,0xe2,0x6d,0x37,0x7e,0x38,0xbd,0xd2,0x1d,0xb6,0xed,0x1f,0x1,0xe3,0x1,0x8f,0xb1,0x48,0xab,0xa9,0x5,0x9e,0x12,0xe1,0xe1,0x79,0x93,0xbc,0xef,0x18,0x73,0x18,0xf1,0x76,0x6c,0x6b,0x5c,0x10,0x3c,0x1e,0x74,0x3c,0x70,0x2d,0xf1,0xdb,0xb0,0xbd,0xab,0xf1,0x1,0x22,0x8f,0xa6,0xaa,0xfc,0xf9,0x95,0xfc,0xf4,0x6d,0xc6,0x1c,0x46,0xbc,0x49,0xc5,0xa8,0xfb,0x2b,0xd2,0xac,0x14,0xeb,0x2,0x89,0x1c,0xf6,0x7c,0x3e,0xe6,0x35,0xd3,0x17,0xc0,0x2c,0x54,0x9e,0xaf,0x75,0xeb,0x5b,0xc1,0x3c,0xaf,0x9a,0x52,0x62,0xc4,0x9b,0xf4,0x9c,0xfb,0x40,0x69,0x8f,0x90,0x2b,0xe5,0x42,0x90,0xcb,0x80,0x31,0x40,0x9f,0x6e,0x92,0xf4,0x55,0xc0,0x6c,0x11,0x66,0xa5,0x28,0x4b,0x5e,0xc9,0x37,0x82,0x35,0xe2,0xed,0xc4,0x8c,0x29,0x8,0xb8,0x40,0xbe,0x2f,0xe8,0x28,0x22,0xa7,0x1c,0x9c,0xd9,0x85,0xec,0xbd,0x99,0xc8,0x8c,0xb4,0xf9,0x8a,0x5d,0x5e,0x96,0x9f,0xb1,0xca,0xe4,0xb8,0x11,0x6f,0xd7,0x15,0xf3,0x3,0x15,0x7d,0x2c,0x97,0x9c,0xa3,0x30,0x1c,0xe4,0x34,0xe0,0x34,0x62,0x3b,0x11,0xbe,0xa3,0x50,0x60,0x5,0xb0,0x54,0xe1,0x6d,0xd0,0x37,0x51,0xd7,0xd2,0xb2,0xc9,0xe9,0xb6,0xc9,0x55,0x23,0xde,0x6e,0xcb,0xb8,0x69,0x95,0xfb,0x87,0x55,0x4f,0x13,0xf4,0x24,0x22,0xdb,0xbd,0x1e,0xdd,0xf0,0xef,0xbe,0x1d,0x10,0x1d,0x9b,0xc8,0xd6,0x3b,0x1f,0x3,0x1f,0xa3,0x7c,0xac,0x22,0xff,0x9,0xa5,0xda,0xff,0xf1,0x67,0xfb,0x6a,0x4c,0x6e,0x19,0xf1,0x1a,0x5a,0x41,0xe6,0xf4,0xca,0x7e,0x12,0xb6,0x8f,0x52,0xe4,0x10,0x2c,0x86,0xa2,0x3a,0x14,0x18,0x42,0x64,0x97,0xc6,0xa1,0x44,0x56,0x40,0xf5,0x88,0xf2,0x49,0x6d,0x68,0x29,0x6b,0xa2,0x7c,0xb6,0x1,0xeb,0x88,0x1c,0xea,0xb5,0x16,0x64,0x1d,0xe8,0x5a,0x15,0x59,0x6b,0x61,0xaf,0xaa,0xdb,0x6e,0xad,0xf2,0xdf,0xe9,0x9,0x1b,0xeb,0x1b,0xc,0x1d,0xc0,0x8f,0x9f,0x9f,0x65,0x19,0x2b,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x43,0xdb,0xe9,0x90,0x9d,0x34,0x32,0x32,0x32,0xd2,0x34,0xac,0x67,0xa8,0x70,0x0,0x36,0x43,0x91,0xef,0x76,0x89,0xe8,0xd,0x54,0x3,0x55,0x91,0x8f,0x6c,0x11,0xf4,0x23,0x1b,0x79,0x3f,0x18,0xac,0xf8,0xb2,0x3d,0xe3,0xe8,0xf5,0x78,0xf,0x4,0x4e,0x7,0x6b,0x28,0xe8,0xce,0xf8,0xd,0x24,0xb2,0xf9,0xda,0x5a,0x60,0x1d,0xe8,0x5a,0x84,0x77,0x3,0x81,0xc0,0x27,0x89,0x8a,0x87,0xc7,0xe3,0x11,0xa0,0x7f,0xc,0xb7,0xd4,0x4,0x83,0xc1,0xa4,0xde,0xb6,0xc6,0xe3,0xf1,0xec,0x23,0xc8,0xf,0xc0,0xda,0xf,0xbe,0xdb,0x25,0x64,0x8,0x91,0xdd,0x3e,0x1a,0xdb,0x76,0xa5,0xcb,0xe5,0x7a,0xaf,0xbc,0xbc,0x3c,0x2e,0xfb,0x65,0xa5,0xa7,0xa7,0xf7,0x17,0x91,0x76,0x2b,0xf3,0x22,0x12,0xa,0x4,0x2,0xd5,0x9d,0x5e,0xbc,0xe9,0xe9,0x19,0x47,0x59,0x62,0x8f,0x5,0xc9,0x4,0xbc,0xc4,0xbe,0x51,0xf9,0x56,0x60,0x39,0xf0,0x32,0xa2,0x2f,0x4,0x2,0x81,0x2f,0xe2,0x19,0xbf,0x73,0xce,0x19,0xe3,0x72,0x5b,0x21,0xaf,0x42,0x26,0x30,0x16,0x38,0x31,0x86,0xdb,0x57,0x1,0x65,0x8,0xa5,0x5b,0xb7,0x6e,0x79,0x65,0xe9,0xd2,0xa5,0x6d,0x2e,0x6c,0x5e,0xaf,0xd7,0x85,0xca,0x3,0xc0,0xd,0x40,0xdf,0x18,0x6f,0xdf,0x1,0x6c,0x6a,0xf4,0xf9,0x0,0x58,0x8c,0xe8,0xa2,0x40,0x20,0xf0,0x71,0x47,0x8,0xd6,0xe7,0xf1,0x9d,0xae,0x30,0xae,0xc1,0xb6,0x23,0x68,0xfd,0xd9,0xd0,0xdf,0x2,0xf3,0x11,0xca,0x6c,0x3b,0xfc,0x52,0x65,0x65,0xa5,0x23,0x31,0x78,0x3d,0xbe,0xd7,0x80,0x1f,0xb6,0x73,0xb2,0x15,0xc8,0x9,0x4,0xfd,0x25,0x9d,0x52,0xbc,0x5e,0x4f,0xc6,0xb1,0xa0,0x7f,0x0,0x2e,0x8a,0x63,0xb0,0x36,0xb0,0x48,0x21,0x2b,0x18,0xf4,0xb7,0xe9,0xf8,0x8c,0xb3,0xce,0x3a,0xcb,0x4a,0x49,0x49,0xbb,0x8,0xd5,0xbb,0x63,0x14,0x6c,0x73,0xfc,0xf,0xb8,0x2b,0x10,0xf4,0xff,0xa9,0x6d,0xe2,0xcd,0xb8,0x1c,0xd5,0x7f,0x24,0x20,0x4b,0xd6,0x1,0x73,0x14,0x99,0x1e,0xc,0x56,0xbc,0x9b,0xf0,0xfc,0xf7,0x66,0x8c,0x44,0xf5,0xf7,0x44,0x8e,0x87,0x69,0x6b,0x79,0xab,0x2,0x1e,0xb4,0x35,0x3c,0xbd,0xb2,0xb2,0x72,0x7b,0x6b,0x6f,0x1a,0x35,0x6a,0x54,0xef,0x70,0xc8,0xde,0x48,0x64,0x8f,0xaf,0xf6,0xe6,0xb3,0x40,0xd0,0x7f,0x78,0xa7,0x12,0xaf,0xcf,0xeb,0x3b,0x40,0x95,0xbb,0x81,0xeb,0x62,0xa8,0x65,0x63,0xa5,0x6,0xc8,0xb,0x4,0xfd,0x8f,0x3a,0x73,0xdf,0x32,0x3c,0x82,0x4e,0x25,0xb2,0xd,0x6b,0xbc,0x59,0xad,0x70,0x5b,0x30,0xe8,0x7f,0xde,0x61,0x4b,0xb1,0x5,0xe8,0x97,0xe0,0x82,0x35,0x1f,0x91,0x69,0x81,0x40,0x45,0x69,0xfc,0x5d,0xe3,0x8c,0x63,0x5,0x9d,0x46,0xa4,0xb5,0x8d,0x77,0x39,0xdb,0xa8,0x70,0x4f,0x38,0x5c,0x5f,0xbc,0x70,0xe1,0xc2,0x70,0x2b,0x6c,0x79,0x1d,0xf0,0xe7,0x8e,0xea,0x26,0x28,0x7a,0x54,0x30,0x18,0xff,0xae,0x55,0x42,0x44,0xe5,0xf3,0x64,0x9c,0xae,0xca,0x3b,0xc0,0x2f,0x12,0x28,0x5c,0x88,0xec,0x98,0xf8,0xe3,0x58,0x6f,0x1a,0x39,0x72,0xa4,0xe5,0xf5,0xf8,0x26,0x9,0x1a,0x48,0x90,0x70,0x1,0xe,0x17,0x78,0xd6,0xeb,0xf1,0xdd,0x13,0x7b,0x6b,0x35,0xca,0xdd,0xe,0xc2,0x5,0x18,0x8d,0xea,0x3c,0xaf,0xc7,0xf7,0xd7,0x11,0x23,0xbe,0xef,0x8a,0x63,0x6b,0x7b,0x91,0xa0,0xcb,0x1a,0xdc,0xd4,0x44,0x34,0x10,0x3,0x5,0xa6,0xbb,0x5d,0x29,0x7f,0xf7,0xa5,0xfb,0x5a,0xd3,0xfd,0x3a,0xbb,0x43,0x7,0x96,0x54,0x12,0xd2,0xf2,0x5a,0xf1,0x17,0xae,0xef,0x3c,0x45,0x2b,0x81,0xc1,0xed,0x64,0x1b,0x57,0x6c,0x5,0xcb,0xdb,0x23,0x35,0x25,0xed,0xcf,0x40,0x41,0x3b,0xc4,0xcd,0x2,0xee,0xf0,0x7a,0x7c,0x2f,0xc,0x1f,0x3e,0xbc,0xd5,0xb6,0x56,0x6d,0xf7,0x81,0xc4,0xab,0x7a,0xf5,0xec,0xb5,0xd2,0xeb,0xf5,0x1e,0xd6,0xf6,0x6e,0x92,0xef,0x76,0x54,0x5f,0x68,0xa8,0x58,0x13,0xcd,0x65,0x2a,0x2c,0xf0,0xf9,0x32,0x86,0xee,0xe5,0x77,0xfb,0xd2,0xa1,0xea,0x4d,0x4c,0x45,0x1c,0x57,0xf1,0x7a,0x3d,0xbe,0x6b,0x15,0x5e,0x6,0x7a,0xb6,0xa3,0x69,0xbe,0x89,0x41,0xb8,0xbd,0x50,0x29,0x3,0xae,0x69,0xe7,0xec,0xbb,0xa4,0x5f,0xdf,0xfe,0xc9,0x7e,0x88,0xf4,0x30,0x54,0x56,0xf9,0x7c,0x19,0x87,0x3a,0xce,0xff,0x74,0xdf,0x13,0xc0,0xbd,0xb1,0x56,0xa8,0x6d,0x64,0xb8,0xda,0xfa,0xae,0x37,0xdd,0xd7,0x92,0x40,0x3b,0xfa,0xcc,0xa8,0xbe,0x49,0x2d,0x5e,0xaf,0xc7,0x77,0x6,0xf0,0xc7,0x4,0xbb,0xc9,0xd1,0x8,0xb6,0xca,0x23,0xf0,0xf9,0xdc,0xa8,0x3c,0xd1,0x81,0x2e,0xd4,0xa9,0x5e,0x8f,0xef,0xe5,0x24,0x17,0xb0,0xa5,0xb6,0x2e,0x1f,0x37,0x6e,0x5c,0x9a,0x83,0xfc,0x9f,0x82,0xf0,0xf3,0xe,0x8a,0xf7,0xbe,0x8,0xf3,0xbd,0x5e,0x6f,0x73,0x22,0xed,0xe8,0xa3,0x59,0xc2,0x49,0x2b,0x5e,0xaf,0xd7,0xbb,0xf,0xf0,0x7c,0x3b,0xd7,0xb8,0x0,0xb5,0x62,0xf1,0x4c,0x6b,0x7e,0x68,0xdb,0xfc,0x1c,0xb8,0xac,0x83,0x33,0xf1,0x7c,0xaf,0xc7,0x77,0x75,0x92,0xb,0x78,0x40,0xcd,0x8e,0xda,0xa,0xaf,0xd7,0xdb,0xea,0xb2,0x91,0x9e,0xee,0xfb,0x1e,0x70,0x7,0x1d,0x7b,0x2,0xc7,0x49,0xa8,0x34,0x37,0xbe,0x50,0xd5,0xc1,0x36,0xad,0x4a,0x5a,0xf1,0xa2,0xf2,0x8,0x70,0x68,0x7,0x18,0xe5,0x3d,0xbf,0xdf,0xbf,0xd7,0x43,0x9b,0xbd,0x1e,0xdf,0xc1,0x2,0x8f,0x25,0x81,0x30,0x4,0x78,0x64,0xdc,0xb8,0x71,0xae,0x24,0x17,0xf0,0x48,0x51,0x69,0xf5,0x40,0xa0,0x25,0x94,0x2,0xee,0x24,0x88,0x77,0x8e,0xcf,0x9b,0x71,0x72,0xd3,0xf2,0xc9,0xff,0x3a,0x38,0xd3,0xb7,0x26,0xa5,0x78,0xbd,0x5e,0xef,0x58,0xe0,0xf2,0x8e,0x30,0x8a,0xb6,0x7e,0xd0,0x69,0x72,0x7,0x78,0x5,0xcd,0xd1,0xab,0x66,0x47,0xed,0x1f,0x92,0x5c,0xbc,0x28,0x3c,0x99,0x9e,0xee,0xdb,0xab,0x20,0xbd,0x1e,0xdf,0x35,0xb4,0xdf,0xe0,0xe4,0xde,0xe3,0xad,0xfa,0x60,0x13,0xf1,0x8,0x73,0x3a,0x34,0x4e,0x22,0x1f,0x24,0x67,0xcb,0xab,0x72,0x5b,0x7,0xd9,0xe4,0xb3,0x60,0xd0,0xff,0x5c,0x2b,0xfa,0xba,0xfb,0x2,0x13,0x92,0x4c,0x1b,0x37,0x92,0xfc,0xf4,0x14,0xd1,0x53,0x5b,0xf1,0xbb,0x82,0x24,0x8b,0xf7,0x18,0xaf,0xc7,0x77,0x44,0xe3,0xb,0xbd,0xfb,0xf6,0x7e,0xd,0xd8,0xde,0x41,0xf1,0x79,0x27,0x10,0xa8,0xf8,0x26,0xe9,0xc4,0xeb,0xf5,0x64,0x9c,0xe,0xa4,0xc7,0x31,0x3e,0xdb,0x81,0xaf,0x5b,0x61,0x68,0x5b,0x91,0x89,0xad,0xab,0x89,0xf9,0x69,0x1c,0xfb,0x62,0xf1,0x2a,0x0,0xfd,0xbc,0x1e,0xef,0x65,0xc9,0xae,0x5e,0x41,0x5e,0xf4,0x78,0x3c,0x56,0xf3,0x5e,0x57,0xc6,0x59,0x44,0xe6,0x7b,0x27,0x93,0x6d,0x41,0xb8,0xa9,0xf1,0x7f,0x5f,0x79,0xe5,0x95,0x10,0xf0,0x10,0xf0,0x19,0xf0,0x79,0xb,0x1f,0x75,0xf0,0xb4,0x2f,0x5a,0x8,0xef,0x13,0xe0,0xce,0x44,0xf6,0xc1,0xda,0x20,0x5e,0xdf,0xb3,0xc0,0x4f,0xda,0xe6,0x9d,0x31,0x1b,0x78,0xc6,0x85,0xe5,0x2f,0xf,0x96,0x6f,0x68,0xe4,0x8e,0xf,0x5,0x19,0x89,0x72,0x71,0x83,0x5b,0x9e,0xd2,0xe8,0xbe,0x47,0x3,0x41,0xff,0x4d,0x7b,0xb,0xdc,0xe3,0xf1,0xf4,0x11,0xac,0x6f,0x89,0x7d,0x1e,0x75,0xe3,0xf8,0xbd,0x2a,0xf0,0x90,0xe5,0xb6,0x16,0x95,0x97,0x97,0x57,0xa7,0x9f,0x33,0x7a,0xb0,0x25,0xf6,0x68,0x44,0xb3,0x81,0xef,0xb7,0x21,0xed,0x6b,0x2,0x41,0xff,0xfe,0xd1,0xe3,0x3d,0x2a,0x45,0xb0,0xeb,0x62,0xc,0xaf,0x16,0x98,0x48,0x64,0x72,0xc7,0x60,0x22,0xf3,0x87,0xcf,0x8a,0x83,0xff,0xdc,0x27,0x50,0x19,0x7d,0x5c,0xc1,0xeb,0xf1,0x7d,0xa,0xb4,0x65,0x2,0xc2,0x1b,0x2,0x45,0xe2,0xb2,0xca,0x2a,0x2a,0xca,0x37,0x7a,0x3c,0x9e,0xbe,0x82,0x8c,0x4,0xf9,0x15,0x70,0x41,0x1b,0xca,0x67,0x58,0x60,0xb0,0x3f,0xe8,0xdf,0x1c,0x63,0x79,0xae,0x1,0xd2,0x62,0x33,0x8f,0xdd,0x2b,0x18,0xc,0xee,0xe8,0x88,0xca,0xd5,0xf1,0x20,0x83,0xc7,0xe3,0xe9,0x7,0x5c,0xda,0x86,0x67,0x7f,0x81,0xf0,0x93,0x40,0xc0,0xff,0x7a,0xb4,0x2f,0x3,0x81,0xc0,0x5a,0xe0,0x25,0xe0,0x25,0x5f,0xba,0x6f,0xa2,0xa,0x37,0x12,0x79,0x3f,0xfb,0x62,0x20,0xe8,0xbf,0xb5,0x75,0x35,0x93,0x6b,0x18,0xa8,0x53,0xe1,0xd6,0x1,0x37,0x6,0x82,0xfe,0x27,0x1b,0x5f,0xac,0x5c,0x30,0x7f,0x3d,0xf0,0xac,0xcf,0xe7,0x9b,0xa5,0x36,0x77,0x3,0xb7,0x3b,0xc,0x7f,0x9f,0x38,0xe7,0x65,0x7d,0x20,0xe8,0x7f,0xb8,0xf1,0x85,0x8c,0x8c,0x8c,0x21,0x76,0x48,0x6f,0x45,0x98,0xd4,0x6,0xdf,0xec,0x10,0x22,0xb,0x1b,0xa2,0xb1,0x7f,0x1b,0xe2,0x7b,0x2f,0xa2,0x53,0xfc,0x81,0x40,0x68,0xe7,0x85,0x60,0x30,0x58,0x5,0xcc,0x3,0xe6,0xf9,0xbc,0xbe,0xab,0x55,0xf9,0x23,0xce,0xe6,0x23,0xbb,0x80,0x23,0x80,0xff,0xd0,0x85,0x71,0xec,0x36,0xb,0xd6,0xe9,0x6d,0x18,0x4,0xfa,0x40,0x2c,0x4e,0x6b,0x4e,0xb8,0x7b,0xe2,0xaf,0xf4,0xaf,0xb,0x4,0xfd,0xf7,0x4,0x82,0xfe,0x23,0x5b,0x2b,0xdc,0x86,0x7a,0xd1,0xe9,0xd4,0x47,0x5b,0x84,0xac,0x3d,0x85,0xbb,0x5b,0x9c,0xfc,0xfe,0x90,0x62,0xdf,0x9,0x14,0x3a,0x7c,0x46,0x9a,0xd7,0xeb,0x3d,0x3e,0x91,0x99,0x5b,0x51,0x51,0xb1,0x2e,0x50,0xe9,0xcf,0x47,0x9d,0xf,0x28,0x8a,0x72,0x43,0x33,0x63,0x9,0x47,0xe3,0x70,0x16,0x95,0x40,0xb1,0x62,0xff,0x36,0xd0,0x48,0xb8,0x4d,0xec,0x1b,0xf0,0xff,0x15,0xe5,0x26,0x1c,0xbe,0xa3,0x55,0x18,0x4e,0x17,0xa7,0x2d,0x7d,0xde,0x91,0xe,0xef,0xab,0x16,0xb8,0xc4,0xef,0xf7,0xaf,0x6b,0x87,0xf4,0x39,0x2d,0xb4,0x8b,0xfc,0x1,0xff,0xe3,0x7b,0xfb,0x51,0x30,0x18,0xb4,0x2d,0xe4,0x76,0x22,0x2b,0x75,0x9c,0x94,0xb0,0x5f,0xb6,0x47,0x26,0x7,0x2a,0xfd,0xcf,0x3,0x6f,0x3b,0x14,0xc1,0x35,0x19,0x19,0x19,0x4d,0xdc,0x57,0xb5,0xd5,0xe9,0x20,0xe0,0x7a,0x11,0xb9,0x35,0x18,0xc,0xda,0xad,0x88,0xf7,0x5f,0x80,0x5,0xe,0x9f,0x73,0x89,0x11,0x6f,0xf3,0x8c,0x71,0x78,0xdf,0x53,0xfe,0xa0,0xff,0x83,0x44,0x27,0xcc,0xe3,0xf1,0xf4,0x0,0x7c,0x4e,0xdc,0x65,0xc5,0x6a,0xf5,0x60,0x52,0x45,0xb0,0xa2,0x6,0x7,0x8b,0x23,0x1a,0xda,0xa0,0x8b,0xdb,0x2b,0xa3,0x15,0xf9,0xa9,0xc3,0x5b,0x7,0xd8,0x21,0x8d,0xe2,0xba,0xca,0x25,0x4e,0xd3,0x5c,0x11,0xa8,0xa8,0x69,0x7d,0xbc,0xed,0xcb,0x80,0x7a,0x7,0xf,0xf2,0x65,0x64,0x64,0xa4,0x1a,0xf1,0xee,0x41,0x46,0x46,0x46,0x4a,0xc3,0x80,0x48,0xcc,0xfd,0x32,0xb1,0x68,0xa7,0x77,0x9c,0xd6,0x81,0xe,0xdd,0xfa,0x55,0xc1,0x60,0xf9,0x9a,0x18,0xa5,0xb1,0x14,0x67,0x23,0x95,0x3,0xda,0x2b,0xa3,0x83,0xc1,0x8a,0x8f,0x1c,0xbb,0xa0,0x12,0xd5,0x8e,0xfd,0x1c,0x5,0x25,0xba,0x34,0xb6,0x78,0x7,0xd7,0xa1,0xac,0x72,0xf0,0xac,0x14,0xdb,0x6e,0x53,0x9f,0xbc,0x6b,0x8a,0x57,0xc3,0x3a,0x0,0x67,0x83,0x5d,0x1f,0xf8,0xfd,0xfe,0xaf,0xdb,0x23,0x61,0x82,0x38,0x9d,0x8c,0xfe,0x5c,0xac,0x37,0x4,0x82,0x81,0x6d,0x40,0x99,0x83,0x67,0xb5,0xf7,0xac,0x24,0x75,0x66,0xcb,0xa8,0xe2,0x75,0x12,0xf7,0x97,0xfd,0x1,0xff,0x76,0x7,0x11,0x70,0x36,0x27,0x5c,0xb5,0xb7,0x11,0x6f,0xfc,0x5a,0x8c,0xff,0xb6,0x57,0xc2,0x4,0x75,0xb6,0xb2,0x49,0xe4,0x55,0x87,0xf,0xfc,0xa7,0x83,0xbb,0xda,0x7b,0xd6,0xd7,0x57,0xe,0xc5,0x6b,0xc5,0x25,0xee,0x22,0x2f,0x39,0xb3,0xad,0xbe,0xe2,0x30,0xbd,0x3d,0x8c,0x78,0x9b,0x54,0x68,0x8e,0xc5,0xfb,0x51,0x3b,0x36,0x31,0x4e,0xc4,0x1b,0x1a,0x3c,0x78,0xe0,0x7f,0x9c,0x95,0x2f,0x58,0x74,0x8b,0x17,0x0,0x0,0x13,0xdf,0x49,0x44,0x41,0x54,0x59,0x98,0xf4,0x2d,0xaf,0xf2,0x99,0x43,0x5b,0xc6,0xa5,0xe5,0x15,0x78,0xdd,0x91,0x2,0x7b,0xf4,0x58,0xe2,0xc8,0xe5,0xd7,0x76,0x5d,0x9a,0xda,0xee,0x38,0x2d,0x3c,0xe,0xc5,0xab,0x1b,0xf6,0xf6,0xb,0x8f,0xc7,0xe3,0xb2,0xb0,0xe,0xb5,0x91,0xa1,0x16,0xba,0x8f,0x2a,0x3,0x44,0xd8,0x47,0x23,0xcf,0xc,0xa3,0x6c,0x41,0x74,0xa3,0xa8,0x7c,0x64,0xa5,0x58,0x1f,0x95,0x97,0x97,0x37,0xe7,0x86,0x39,0x79,0x8f,0x5a,0x33,0x6b,0xd6,0x2c,0x75,0x56,0xc0,0xb5,0xd6,0x49,0xcb,0x7b,0xe9,0xa5,0x97,0xba,0x66,0xcd,0x9a,0x15,0x6e,0x8f,0xcc,0x16,0x61,0x9d,0x3a,0xcb,0xb7,0x7e,0xc0,0xc6,0x9d,0xff,0xf3,0xf9,0x7c,0x3,0xd4,0x8e,0x7d,0x2,0x85,0xda,0x8e,0x6c,0xc4,0xdc,0xb9,0x73,0xc3,0x5e,0x8f,0xaf,0x2e,0xd6,0x96,0x54,0x2c,0xe9,0x65,0xc4,0xdb,0xb4,0x10,0xf4,0x70,0x56,0x8,0xd8,0xd4,0xd2,0x97,0x5e,0x8f,0xef,0xaf,0xc0,0xe5,0xa,0xa9,0x82,0x46,0x3a,0x68,0xb2,0x47,0x47,0x4d,0x1a,0x9c,0x62,0x81,0x70,0xc8,0xae,0xf3,0x7a,0x7c,0xaf,0x20,0x3a,0xb1,0xc9,0x6e,0x92,0xc2,0x7e,0xe,0x7a,0x78,0x75,0x4e,0xd,0xa9,0x10,0x72,0x32,0x1d,0x68,0xc3,0x86,0xd,0xfb,0x3b,0x75,0x67,0x1d,0x78,0x4c,0x9b,0x9c,0xcd,0x59,0x92,0x3d,0x67,0x10,0x1d,0xec,0xb0,0xf6,0x8,0xb5,0x21,0xfa,0xf5,0xb1,0x8a,0x57,0x55,0x87,0x1a,0xf1,0xee,0x81,0xd,0x5b,0xc5,0x51,0x1,0xdf,0xdb,0x20,0x92,0x1e,0x0,0x12,0xcb,0xf0,0x7e,0x2a,0x70,0x9,0x2a,0x5b,0x80,0xeb,0xe3,0x25,0x44,0x67,0xfd,0x42,0x11,0x27,0xe3,0x41,0xed,0xb8,0x8d,0x30,0x88,0xf4,0x73,0x38,0x66,0x55,0x17,0x1f,0xdb,0xda,0xd2,0x26,0x13,0x1b,0xda,0xde,0xe7,0x15,0xc4,0xd1,0xfa,0x44,0x51,0x6,0x25,0xa8,0x2f,0x27,0x51,0xae,0xad,0x71,0x10,0x92,0xf3,0xf7,0x82,0xaa,0x4e,0x2a,0x42,0xdd,0xbc,0x79,0x73,0x3b,0xae,0x35,0xb5,0x9d,0xda,0xdf,0xde,0xa3,0xc2,0x71,0xb6,0x67,0xb6,0x4a,0x5b,0xfa,0xf8,0x31,0xe7,0x8d,0x88,0xac,0x35,0xe2,0x6d,0x22,0x42,0xdd,0xe2,0xb0,0xee,0x3c,0x24,0x41,0xcd,0x5e,0xb4,0x97,0xf8,0x4e,0x76,0x2f,0xe8,0x71,0xe9,0xa5,0x97,0x3a,0x1b,0x81,0x17,0x75,0xd2,0xc7,0xe,0xc7,0x63,0x83,0xf6,0x18,0x22,0x79,0xb0,0x33,0xf3,0xee,0x2e,0xde,0x8a,0x8a,0x8a,0x1d,0x38,0x18,0x40,0x12,0x4b,0x1c,0xd,0x20,0x79,0x3c,0x9e,0xbe,0xec,0xbe,0x30,0xa5,0xb5,0x7d,0xec,0xed,0x46,0xbc,0x4d,0x9c,0x1f,0xdb,0xe9,0xce,0x0,0x27,0x26,0x28,0x1d,0xa1,0x28,0x2d,0xaf,0x93,0x8c,0x73,0xaf,0x5f,0xbf,0xfe,0x74,0x87,0x71,0x18,0xe7,0x44,0xbc,0xed,0x9c,0xdf,0xc3,0x1c,0x3a,0x36,0xe1,0x56,0xd9,0x7c,0xef,0x7d,0xd0,0x73,0x1c,0x7a,0x7a,0x19,0x8e,0xdc,0x66,0x61,0x87,0x11,0xef,0x9e,0x37,0x59,0xd6,0x16,0x9c,0x75,0x9e,0x4e,0xc8,0xc8,0xc8,0x48,0x8b,0x7b,0x2a,0xb4,0x69,0xcb,0x2b,0x4e,0x33,0x4e,0x2d,0x87,0x27,0x3b,0x88,0x93,0xf5,0xb9,0xa1,0xce,0x90,0xdf,0x88,0x86,0xe3,0x54,0xf1,0x38,0x9d,0x52,0xf9,0x23,0x87,0xe9,0xad,0x31,0xe2,0xdd,0x3,0xbf,0xdf,0x5f,0xf,0x7c,0xe8,0xe0,0xd6,0x7e,0x76,0x48,0xe3,0xbf,0x8b,0x44,0x14,0xb7,0xd9,0x76,0xbc,0x6f,0x90,0xc6,0x3c,0xdf,0xd8,0xeb,0xf1,0xd,0x74,0xe8,0x55,0xb4,0x9b,0x78,0x1b,0xe6,0x7a,0x3b,0x19,0xf4,0xd9,0xa6,0x1a,0x75,0x6d,0xb1,0x93,0xf9,0xc6,0x63,0x3c,0x9e,0xc,0x27,0xdb,0xa0,0x7a,0x9d,0x95,0xb,0xd9,0x66,0xc4,0x1b,0x9d,0xa0,0x43,0xa1,0x4d,0xc8,0xcc,0xcc,0x4c,0x6d,0xa6,0x4f,0x74,0xb1,0x62,0xf,0xd9,0xf9,0x21,0xb2,0x9e,0xd7,0x91,0x8,0xc2,0xe1,0xfa,0xaf,0x89,0x9c,0x38,0x18,0x2b,0x87,0xfb,0xd2,0x7d,0x87,0xc5,0x56,0x46,0xb8,0xd0,0xa1,0xd,0xd7,0xb7,0x5b,0x6f,0x57,0xac,0x89,0x8e,0xc4,0xab,0xbc,0x14,0xc,0x6,0xa3,0x79,0x59,0x6b,0x1c,0x15,0x38,0xd5,0x98,0xb6,0xde,0xcd,0xf0,0x66,0x8c,0x0,0xe,0x74,0xf0,0xa8,0xda,0x50,0x48,0xbf,0x31,0xe2,0x8d,0x9e,0xa9,0x8b,0x1d,0xde,0x79,0x54,0x5d,0x6d,0x7d,0x71,0x33,0x2d,0xfa,0xd6,0x60,0x30,0xb8,0x7e,0xe7,0x7,0x55,0x6d,0x65,0x5c,0x9a,0xb4,0x2,0xb,0x17,0x2e,0xc,0xb,0x38,0x99,0x56,0x97,0xa2,0x42,0xab,0xcf,0x17,0xf2,0x79,0x7d,0x3,0x54,0x79,0xdc,0xa1,0xa4,0x9e,0x69,0xb7,0x9c,0x56,0xa6,0x38,0x2b,0x21,0xfa,0xb7,0xe8,0x75,0x30,0x4f,0x3a,0x8a,0x86,0xf0,0x9c,0xcf,0xe3,0x6b,0xf5,0x9c,0x63,0x5b,0xf5,0x19,0x67,0xe5,0x54,0xca,0x16,0x2e,0xf4,0xd7,0x19,0xf1,0x46,0xbf,0xb3,0x2d,0xbb,0x14,0xdc,0xe0,0xf5,0xf8,0xf6,0xba,0x3,0x85,0x48,0xeb,0x5e,0x2d,0x88,0x44,0x77,0x3f,0x15,0x79,0xd1,0x61,0xfc,0x4e,0xf3,0x7a,0x7c,0xbf,0xdf,0xab,0x70,0xd3,0x7d,0x3d,0x54,0x79,0xd,0xa7,0x93,0x5d,0x2c,0xfd,0x63,0xfb,0xb8,0xcc,0xbe,0xbb,0x71,0x30,0x5a,0xdb,0xa0,0xb6,0x25,0xd1,0x2f,0xa7,0xfc,0xc9,0xe1,0xb8,0x47,0x1f,0x85,0xbf,0x79,0xbd,0xde,0xd6,0xec,0x4c,0xf9,0x17,0x1c,0xe,0xb2,0x21,0xbc,0x40,0x17,0xc7,0xb1,0x78,0x55,0xed,0x95,0x44,0xe,0x9a,0x76,0x66,0x5a,0xb8,0xd7,0xeb,0xf1,0x3d,0xe1,0xf3,0xf9,0xa2,0x6e,0x60,0x36,0x7c,0xf8,0x70,0x51,0x38,0xa6,0x75,0x8d,0x8a,0x34,0xd3,0xff,0xb2,0xff,0xdb,0x86,0xf8,0xdd,0xee,0xf5,0xf8,0x8a,0x7e,0xf0,0x83,0x1f,0x44,0x2d,0x64,0x19,0xbe,0x51,0x7,0x6a,0x64,0xbf,0xe2,0x33,0x1d,0x3e,0x63,0x87,0xdf,0xef,0x8f,0xe7,0xcc,0xaa,0xb4,0x66,0x3c,0x83,0x6b,0x4,0x7e,0xdb,0x6,0x7f,0x3b,0xea,0xc0,0x5f,0x20,0x50,0xba,0xe,0x1c,0x8f,0xe6,0x5e,0x84,0xca,0xb,0xe9,0xe9,0x9e,0xa8,0xd3,0x6c,0x47,0x8f,0x1e,0xdd,0xcb,0xeb,0xf1,0x3d,0x4d,0x5b,0x8e,0xa5,0x51,0x96,0x77,0x75,0xf1,0x3a,0x7e,0x69,0x1e,0xc,0x6,0xc3,0x5e,0x8f,0xef,0x51,0xa0,0x2d,0x5b,0xbf,0x5e,0xa3,0x36,0x17,0x79,0x3d,0xbe,0xbf,0x23,0xcc,0x51,0x8d,0x4c,0x13,0x14,0xd5,0x83,0x10,0xb9,0x92,0x56,0x8a,0x17,0xd1,0xa8,0xe2,0xd,0xdb,0xae,0x55,0x2e,0xcb,0xfe,0x6,0x67,0x7b,0x2d,0x59,0x40,0x4e,0x8f,0xb4,0x9e,0x57,0x78,0x3d,0xbe,0xbf,0xa3,0x2c,0x53,0x61,0xbd,0x20,0x7,0x83,0x7a,0x6d,0xdb,0xbe,0xd8,0x71,0x6b,0x16,0x21,0xde,0x93,0x33,0xac,0x5d,0x2d,0xad,0xc7,0x2d,0xea,0x1a,0x8d,0xe8,0x8d,0xaa,0x8e,0xfb,0xe3,0x80,0xfc,0x25,0x10,0xa8,0x68,0xc9,0xf5,0x5c,0x1,0x9c,0xe1,0x30,0xf0,0xb,0x2d,0xb1,0xbe,0xf2,0x7a,0x7c,0xcf,0xa3,0x2c,0x52,0xe1,0x7f,0x82,0xec,0x7,0x3a,0x22,0x54,0x1f,0xbe,0x92,0xb6,0x9d,0xef,0x53,0xa3,0xf0,0xa9,0x11,0x6f,0xcb,0xcd,0xef,0xe3,0x88,0xdc,0x42,0xdb,0x6,0xbe,0x6,0x0,0xe3,0x51,0xc6,0x4b,0x23,0x3f,0x38,0xa6,0x22,0xa6,0xd1,0x47,0x3e,0x17,0x2c,0x28,0xaf,0xf3,0xa4,0xfb,0x26,0x89,0xf0,0xf7,0x36,0xc4,0x6f,0x28,0x90,0x8b,0xec,0x1c,0xed,0xd1,0x78,0xd8,0x5d,0x41,0xaf,0x8d,0x73,0x5e,0xba,0xbc,0x1e,0xdf,0x56,0x22,0xaf,0x47,0x86,0x20,0x6d,0x8f,0xa7,0xad,0xe1,0x5b,0x5b,0xfe,0x9e,0x9f,0x58,0xc2,0x27,0x6d,0xc8,0xff,0xde,0xc0,0xb5,0x8,0xd7,0xc6,0xd1,0xb6,0x0,0x53,0x82,0xc1,0x8a,0xea,0xae,0x2e,0xde,0x36,0xed,0xdb,0x1c,0xa8,0xc,0xac,0x6,0x5e,0xec,0xe8,0x44,0x68,0x4b,0xaf,0x2d,0x84,0xd7,0x48,0xbe,0xf7,0x7d,0x1b,0x3,0xc1,0xc0,0xc2,0x4,0x84,0xdb,0x17,0x18,0x12,0xa7,0xb0,0x36,0x58,0x96,0x6c,0x6c,0xe9,0x7,0x95,0x95,0xfe,0xd5,0xc0,0x97,0x49,0x57,0xaa,0x85,0xbf,0xd2,0xd,0x88,0xc7,0x59,0x45,0x33,0x92,0x20,0xb3,0x42,0xcd,0xbb,0xf7,0xfe,0xad,0xa,0x77,0x27,0x57,0xd9,0x4a,0xdc,0x46,0xdc,0x71,0x8b,0xa3,0xc8,0xd5,0x81,0x40,0x60,0xaf,0x53,0x20,0x15,0xbd,0x2e,0xc9,0xa2,0xfe,0xc7,0x40,0xc0,0xff,0x8d,0x11,0x6f,0x6b,0x5a,0xdf,0xa0,0x7f,0x11,0xb4,0xfe,0xd5,0x4a,0x82,0x9a,0xde,0xfa,0x96,0xdd,0x6a,0x7d,0x1c,0xf8,0x36,0x49,0x6c,0xbe,0xd9,0x1f,0xf4,0x3f,0x92,0xe4,0xe5,0xe2,0x4d,0x5b,0x65,0x5e,0xeb,0xc6,0x3e,0x2,0x7e,0xe0,0x9d,0x24,0x89,0xb7,0x2a,0xfc,0x81,0x6e,0x42,0x7c,0x4e,0x9,0xb4,0x35,0x1b,0xd8,0xd0,0x51,0x89,0x90,0xbd,0xcc,0xf6,0x9,0x54,0x6,0x36,0x22,0x8e,0xe6,0x1e,0xc7,0x9b,0xb0,0xa2,0xe7,0x27,0x79,0x99,0x50,0xdb,0xe,0x67,0x4,0x83,0xe5,0xad,0x5e,0x78,0x20,0x16,0x67,0xe1,0x6c,0x42,0x4c,0xbc,0xc9,0x9,0x6,0xfd,0xab,0x8d,0x78,0x63,0x69,0x7d,0x17,0x4,0xbe,0x15,0xb8,0x10,0x67,0x53,0xe6,0xda,0x5e,0xda,0x5a,0xb1,0xc8,0x3b,0x10,0xf0,0x2f,0x93,0x8e,0x3f,0x70,0xac,0x20,0x18,0xc,0xfc,0x3b,0xb9,0xa5,0xab,0x97,0x55,0x2e,0xa8,0x8c,0x49,0x88,0x7e,0xbf,0xbf,0x5a,0x22,0xb,0x33,0x42,0x1d,0x18,0xf3,0x97,0xc3,0xb6,0xf5,0x28,0xdd,0x88,0xb8,0x9d,0x62,0xef,0xf,0xfa,0x17,0x21,0x5c,0x49,0x3b,0x2f,0x82,0x6f,0x28,0x70,0xad,0xaa,0x34,0xea,0xc3,0xf5,0x8f,0xa2,0x3c,0xdd,0x41,0xb6,0x7e,0x3a,0x10,0xf4,0xdf,0x96,0xe4,0xe5,0x21,0xd7,0x72,0x5b,0x2f,0x3a,0xcc,0xff,0x7f,0xa3,0xdc,0x45,0xc7,0x9c,0x42,0xbf,0x58,0x91,0x9f,0x2e,0x58,0x50,0x5e,0x6f,0xc4,0xeb,0xb4,0x5,0xe,0xf8,0x5f,0x0,0xf1,0xd0,0x8e,0x73,0x76,0x63,0x11,0xef,0xc2,0x85,0xb,0xc3,0x2a,0xf6,0x35,0x88,0xc3,0xa9,0x82,0xe,0x5d,0x65,0xe0,0x8e,0x40,0xd0,0x7f,0x75,0x72,0xb7,0xb8,0x5c,0x11,0x8,0xfa,0x67,0x54,0x54,0x54,0x38,0x7e,0x5f,0x13,0xa8,0xf4,0xdf,0x27,0xc2,0x55,0xed,0x5c,0x81,0x3f,0x81,0x68,0x46,0x30,0x58,0xb1,0x8d,0x6e,0x86,0x15,0xef,0x0,0x3,0xc1,0x8a,0xd7,0x11,0xce,0xa0,0x1d,0xb7,0x79,0xc5,0x6a,0xfd,0xde,0x48,0xc1,0x60,0xd0,0xe,0x4,0xfc,0x77,0x6b,0xe4,0x74,0xc3,0x44,0xaf,0xa7,0xdd,0x1,0x72,0x51,0x20,0xe8,0xbf,0x2f,0xc6,0x3e,0x7c,0x7b,0xf2,0x99,0x82,0x2f,0x50,0xe9,0xff,0x47,0x5c,0x3c,0xb0,0x80,0xff,0xef,0xa,0x67,0x3,0x5b,0xda,0x21,0xee,0xb9,0x29,0xa9,0xee,0xeb,0x3,0x81,0x40,0xd,0xdd,0x10,0x2b,0x11,0x81,0x6,0x2,0xfe,0xd5,0x96,0xca,0x8,0x22,0xd3,0xf2,0xaa,0x12,0x9c,0x6,0x55,0x8d,0x7d,0xf9,0x5f,0x30,0xe8,0x7f,0x4e,0x84,0x13,0x71,0xb6,0x78,0x61,0x6f,0xd8,0xc0,0x73,0x88,0x1e,0x1f,0x8,0x56,0xc4,0xbc,0xf,0x74,0xd8,0xb6,0x42,0xed,0xd0,0x7a,0x6d,0x4,0xc6,0x5b,0x2a,0x47,0x4,0x83,0xfe,0x40,0x3c,0x3,0xe,0x6,0xfd,0x6f,0x5a,0x2e,0x39,0x12,0x78,0x3c,0x41,0x15,0x64,0x25,0xe8,0xf7,0x3,0x41,0xff,0x8c,0xb2,0xb2,0x32,0xa5,0x9b,0x92,0xf0,0x4a,0xde,0xe7,0x1b,0x35,0x58,0x6d,0xfb,0xe,0x60,0x3c,0x6d,0xd9,0x23,0xaa,0x29,0x5b,0x81,0xd9,0xa,0xd3,0x83,0x41,0xff,0xb2,0xb6,0x4,0xe4,0xf1,0x64,0x8c,0x14,0xf4,0xf,0x44,0x5a,0x8c,0xb6,0x8a,0xf6,0x25,0x81,0xbb,0xfd,0x41,0xff,0x7b,0x6d,0x9,0xc8,0x9b,0xee,0xcb,0x46,0xe2,0xfe,0xe,0xbd,0x1a,0x28,0x7,0xe6,0x2b,0xf6,0x63,0xc1,0x60,0x30,0xe1,0x3b,0x79,0x78,0x3c,0x19,0x47,0xb,0x7a,0xf,0x91,0x85,0xf8,0x6d,0x6d,0x2c,0x16,0x83,0xde,0x35,0x78,0xc8,0xe0,0xa,0xa7,0x5b,0xf4,0xb6,0x68,0x73,0x8f,0x6f,0x3b,0xb1,0xed,0xf7,0x6d,0x37,0x9c,0xcf,0x5b,0xdb,0x25,0xc5,0xbb,0x93,0x8c,0x8c,0x8c,0xfe,0xe1,0xb0,0x8e,0x16,0x18,0x4b,0xe4,0x73,0x60,0x8c,0xa2,0xf8,0x1c,0x58,0x9,0xbc,0x89,0x48,0x69,0x8f,0x1e,0xa9,0x4b,0xe6,0xce,0x9d,0x1b,0xb7,0xc1,0x91,0x71,0xe3,0xc6,0x49,0xed,0xf6,0xda,0xe3,0x10,0xc6,0x69,0x24,0x7e,0xe9,0xb4,0x6e,0xee,0x72,0x15,0x30,0x1f,0xa5,0x4c,0x45,0xca,0x82,0xc1,0x8a,0xb8,0xbc,0xaa,0xc8,0x48,0xcf,0xb0,0x6c,0xf4,0x46,0x84,0x4b,0x80,0x43,0x62,0x28,0xf8,0x4a,0x64,0xc1,0xc8,0x7a,0x22,0xaf,0xef,0xd6,0x3,0x6b,0x11,0x9,0x4,0x2,0x15,0xaf,0xd3,0x41,0x64,0xa4,0x67,0x1c,0xa2,0xa2,0x63,0x15,0x32,0x89,0x1c,0x52,0xd7,0x9a,0xe3,0x68,0xea,0x80,0x4a,0x81,0x32,0x15,0x2d,0xab,0xa9,0xa9,0x79,0xef,0xf5,0xd7,0x5f,0x4f,0x58,0x4b,0xeb,0xf5,0xf8,0xae,0x5,0xae,0x6,0xe,0x22,0xb2,0xef,0xf7,0x0,0x76,0xdf,0x70,0x3e,0xd4,0x60,0xdb,0x4d,0xd,0xe5,0xf1,0xf1,0x40,0xd0,0x3f,0xab,0xcb,0xb6,0xbc,0xd1,0x18,0x3e,0x7c,0xb8,0xf4,0xed,0xbb,0xcf,0x30,0xb,0x7b,0x3f,0x15,0x86,0x60,0x33,0x4,0x61,0x8,0x8a,0x85,0x50,0xd,0xb2,0xd,0xa8,0x46,0xa9,0x12,0xf4,0x73,0x57,0xaa,0xeb,0xe3,0xf9,0xf3,0xe7,0xb7,0xeb,0x7e,0x44,0xe9,0x67,0xa5,0xf7,0x10,0xb7,0xfb,0x58,0xd0,0xa1,0xc0,0x10,0x41,0x87,0x82,0xf4,0x3,0x36,0x28,0xac,0xb3,0x60,0x9d,0x8a,0xae,0x1d,0x3c,0x78,0xf0,0xfb,0x89,0x68,0x5,0xba,0x32,0xc3,0x87,0xf,0xb7,0xfa,0xf6,0x1d,0x70,0x1c,0xe8,0xbe,0x8d,0x6c,0x3b,0x10,0xd8,0xd2,0xc8,0xb6,0xeb,0x52,0xac,0x94,0xff,0x96,0x55,0x94,0xd5,0x76,0x54,0x3c,0x2f,0xbd,0xf4,0x52,0x59,0xbf,0x7e,0x7d,0x3f,0x94,0x3e,0x2e,0xb7,0xab,0x6a,0xd3,0xa6,0x4d,0x55,0x4b,0x97,0x2e,0x35,0x79,0x6d,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0xe8,0x68,0x5c,0xc6,0x4,0x86,0xf6,0x60,0x42,0x6e,0xee,0x61,0xc3,0x87,0x8f,0xb4,0xdf,0x7e,0xeb,0xf5,0x5a,0x63,0x8d,0xf8,0x60,0x19,0x13,0x18,0xda,0x3,0xb1,0x65,0x55,0x8a,0xcb,0xbe,0xde,0x58,0x22,0x7e,0xb8,0xbb,0x42,0x22,0xc6,0x8f,0x1f,0x6f,0xb9,0x5c,0x69,0x17,0x21,0x5c,0xb,0x9c,0x6,0xf4,0x3,0x3e,0x3,0x3e,0x2,0xfe,0x52,0x52,0x5c,0xf8,0x8a,0xc9,0x6a,0x83,0x69,0x79,0x93,0x8c,0x9c,0x9c,0x49,0x3d,0x5d,0xee,0xb4,0x7f,0x20,0xbc,0x48,0xe4,0xb0,0xaf,0x32,0xe0,0x7e,0xe0,0xdf,0xc0,0x11,0xc0,0xec,0xac,0xec,0xbc,0x97,0x4c,0x56,0x77,0x30,0x2a,0xc3,0x6d,0xdb,0xfa,0x9b,0x31,0x44,0x1c,0xbd,0x99,0xce,0x9e,0x80,0xac,0xec,0xbc,0x62,0x22,0xdb,0xdb,0x94,0xd4,0xd6,0x6c,0x9b,0xf4,0xf8,0xe3,0x8f,0x87,0x76,0x9,0x3b,0xc7,0x6d,0xab,0x35,0x11,0x78,0x0,0xb8,0xaf,0xa4,0xb8,0xf0,0xe,0x93,0xe5,0x6,0x23,0xde,0xe4,0x10,0xee,0x91,0xc0,0xc7,0xc0,0xe2,0x92,0xe2,0xc2,0x91,0x51,0x7f,0x93,0x95,0x65,0x21,0xee,0x57,0x81,0x33,0x4b,0x8a,0xb,0x7,0x98,0x2c,0x37,0x18,0xb7,0x39,0x39,0x6a,0x9e,0xb3,0x0,0x6c,0x25,0xab,0xb9,0xdf,0x94,0x94,0x94,0xd8,0xc0,0x54,0xa0,0x7f,0x76,0x76,0xde,0xe1,0x26,0xcb,0xd,0x5d,0x85,0x4e,0x3d,0x60,0xa5,0x30,0x1c,0xa8,0x7a,0xa8,0xa4,0x70,0x2f,0x27,0x16,0xca,0x47,0xa0,0x4f,0x1,0xfb,0x1,0xab,0x9b,0xb6,0xe0,0x13,0x8f,0x1,0xbd,0x1d,0x38,0xa1,0xc1,0x26,0xef,0xa1,0x94,0x94,0x94,0x14,0xbe,0x19,0xa5,0xb5,0xbf,0xb,0xe8,0x59,0x52,0x5c,0x78,0x5b,0x56,0xf6,0x44,0xf,0xe8,0x2d,0xc0,0x91,0xc0,0x1a,0x84,0xc7,0x4a,0x66,0x14,0x3e,0x3,0x30,0x61,0x42,0x6e,0x8a,0x58,0x92,0x43,0x64,0x11,0x7a,0x1f,0x60,0x91,0xcb,0xd2,0xdb,0x8b,0x8a,0x8a,0xa2,0x9e,0x42,0x30,0x7e,0xe2,0x44,0xb1,0x42,0x7a,0x83,0xc0,0x68,0xe0,0x64,0xe0,0x3d,0x60,0x41,0x49,0x71,0x61,0x51,0xcc,0x1e,0x49,0xce,0xc4,0x4b,0x50,0xbd,0x8,0xf8,0x7e,0x83,0x67,0xf2,0xb6,0xa,0x77,0xcd,0x9c,0x51,0xa8,0x7b,0xa4,0xe5,0xf,0xc0,0xfe,0x25,0xc5,0x85,0xd7,0x64,0x65,0xe5,0x9e,0x8c,0xc8,0x94,0x6,0x1b,0x7c,0x1,0x1a,0xb0,0x2d,0xfe,0xf0,0x50,0x51,0x51,0xd4,0x35,0xd3,0x13,0xb2,0x27,0xa6,0xb,0x3a,0x19,0x38,0xe,0xd8,0xa4,0xf0,0x12,0x22,0xf,0x12,0x96,0x11,0x62,0xd9,0xbf,0x50,0xdb,0xfa,0xd5,0xcc,0x99,0xd3,0x6a,0x1a,0x3d,0xeb,0x2f,0x28,0xcf,0x95,0x94,0x14,0x96,0xee,0x8a,0x67,0xde,0x9d,0x28,0x47,0x94,0x14,0x17,0x5e,0x9b,0x95,0x93,0x77,0x22,0xca,0x6f,0x80,0x53,0x88,0x9c,0xe3,0xe4,0x77,0x59,0x7a,0x7f,0x51,0x51,0x51,0xd4,0x2d,0x8e,0x72,0x73,0x73,0x7,0x84,0x6d,0xb9,0x85,0x48,0x5,0xde,0x1b,0xf8,0x8f,0xa,0x33,0x67,0xce,0x28,0x7c,0xa7,0xbb,0x88,0xb7,0xb3,0xf,0x58,0x9d,0x46,0x2b,0xf6,0x8b,0x2e,0x29,0x9e,0xfe,0x75,0x49,0x71,0xe1,0x35,0xc5,0xc5,0x85,0xaf,0x37,0x15,0x63,0xee,0x15,0xa0,0xff,0x25,0xb2,0x48,0x7c,0x45,0x83,0x68,0x46,0x21,0x2c,0x9a,0x90,0x9d,0x97,0x1d,0x25,0xb8,0xf3,0x80,0xcb,0xb2,0xb2,0xf3,0x2e,0x6,0x9d,0x43,0x64,0x77,0x8a,0xa5,0xc0,0x49,0x28,0x4f,0x67,0x65,0xe7,0xdd,0x9c,0x9d,0x3d,0xd1,0x2d,0x96,0xcc,0x2,0x26,0x3,0xab,0x80,0xaf,0x80,0x1b,0xc3,0xb6,0x7c,0x38,0x61,0x42,0x7e,0xff,0xa6,0xae,0xfd,0x44,0xb7,0x2b,0xa4,0x4f,0xa,0x3c,0x42,0x64,0x93,0x82,0x52,0x22,0x87,0xa3,0x15,0x66,0x65,0xe7,0xc5,0xb4,0x9b,0x63,0x56,0x76,0xde,0x3d,0xa8,0xbe,0x0,0x9c,0xd4,0x10,0x4e,0xf,0xe0,0x4e,0x51,0x96,0x5e,0x77,0xfd,0x2f,0xf6,0x7c,0xaf,0x7f,0x31,0xf0,0xf3,0x9,0xd9,0x79,0x23,0x10,0x59,0x4a,0x64,0x17,0x89,0xca,0x48,0x1c,0xe4,0x1e,0xcb,0x96,0xe7,0x73,0x73,0x73,0x25,0xca,0x33,0x2e,0x15,0xb4,0x2,0xc8,0x20,0x32,0xa2,0xff,0x5f,0x81,0x5c,0x51,0xd,0x88,0xa5,0x63,0x81,0x9f,0x8b,0xe8,0x9e,0xd,0xc3,0xcf,0x45,0x38,0x7e,0x8f,0x6b,0xe7,0x2,0xd7,0x64,0x65,0xe5,0x7d,0x1f,0xe5,0xd,0x60,0x30,0x91,0x81,0xc6,0xfd,0x80,0xdf,0x87,0x6d,0x79,0x71,0xfc,0xc4,0x89,0x4d,0xe6,0x22,0x64,0x67,0xe7,0x9e,0x14,0xb6,0xe5,0xfd,0x86,0xb1,0x8e,0xd,0xc0,0x7,0xc0,0x5,0xa2,0x2c,0x9d,0x90,0x9d,0x77,0x85,0x69,0x79,0x3b,0x7,0x87,0x3,0x6b,0x9d,0xde,0x3c,0x21,0x3b,0xef,0x10,0xe0,0x6f,0xc0,0x12,0xb7,0xb,0x5f,0x61,0x61,0x61,0x6d,0x64,0xa0,0x2b,0xaf,0xaf,0xad,0x2c,0x16,0xb8,0x27,0x37,0x37,0xf7,0x89,0xa2,0xa2,0xa2,0x3d,0xf7,0xe1,0x1a,0x2,0x14,0x5b,0x62,0x1f,0x3e,0x63,0xc6,0x8c,0x6f,0x23,0x2d,0x6d,0xce,0xfe,0x62,0x59,0x1f,0x3,0xf7,0x80,0xae,0x2,0x4e,0xac,0xaf,0x73,0x1d,0xfe,0xe8,0xa3,0x5,0xdb,0x1b,0x4,0x3a,0xe,0xd1,0x39,0x62,0x85,0x67,0x2,0x57,0xed,0x5e,0x85,0xea,0xaf,0x51,0x7e,0x6,0x72,0x73,0x49,0xf1,0xf4,0x47,0x22,0x71,0xc8,0x11,0x1b,0x6b,0x22,0x4a,0xc1,0x84,0x9c,0xbc,0xab,0x66,0xce,0x28,0xdc,0xeb,0x96,0xb5,0x59,0x59,0xb9,0x63,0x80,0x3b,0x80,0xa9,0x25,0xc5,0x85,0xb7,0x7c,0x97,0xce,0xac,0xbc,0x8b,0x45,0x78,0xa1,0x77,0xef,0xbe,0x7f,0x4,0xae,0x8b,0xd2,0xfd,0xf0,0x23,0x72,0x56,0xc9,0x8c,0xe9,0x4b,0x1a,0x9,0xb4,0x3c,0xe2,0x35,0xb8,0x6,0xd1,0x74,0x37,0xd0,0x27,0x80,0x1d,0xb6,0x25,0xc7,0x3c,0x54,0x34,0xfd,0x7f,0x0,0xf9,0xf9,0xf9,0x29,0xb5,0x75,0xe1,0x72,0xd0,0xd8,0xdf,0xe5,0xa,0x2f,0xab,0x70,0xfe,0xcc,0x19,0x85,0xfe,0x46,0xcf,0x9f,0xd,0x5c,0x60,0xd5,0x73,0x74,0x83,0x38,0x1b,0x79,0x5c,0x32,0x7,0xb0,0x55,0xe5,0xc4,0x99,0x25,0xd3,0xbf,0x68,0x68,0x89,0xfb,0x84,0x6d,0xa9,0x14,0x78,0x3a,0x2b,0x2b,0xaf,0xbc,0xa4,0xa4,0x70,0x9d,0x69,0x79,0xbb,0xf0,0x80,0x9b,0x8,0x67,0x3,0x8a,0xca,0x5,0x3b,0x85,0xb,0x30,0x63,0x46,0x61,0x15,0x2a,0xd7,0x2,0x7d,0xc3,0xb6,0x5c,0x10,0xe5,0xd6,0xde,0x2,0x97,0xef,0x14,0x2e,0xc0,0xcc,0x99,0x33,0xbe,0x1,0xfd,0x35,0x30,0x40,0xe1,0x39,0x4b,0xb8,0x60,0xa7,0x70,0x1,0xdc,0x6e,0x2d,0x6d,0x70,0x7,0x77,0x3b,0x31,0xe1,0xa6,0x9b,0xb3,0xfa,0xa2,0xfc,0xe,0x58,0xb4,0x53,0xb8,0x91,0x38,0xcc,0x50,0x6c,0x2d,0x2,0xd6,0x8a,0xf2,0xc8,0xde,0x85,0x9b,0x67,0x21,0xf2,0xa,0xb0,0xbe,0xb1,0x70,0x1,0x66,0x96,0x14,0xfe,0x13,0x58,0x4,0x5c,0x9b,0x95,0x9d,0x17,0x6d,0x56,0xdd,0x84,0xc6,0xc2,0x5,0x8,0xbb,0xb8,0x14,0xb0,0x43,0xb6,0xbd,0xdb,0x21,0xe8,0xd9,0x39,0xb9,0x57,0x37,0xa4,0x7f,0xcc,0x4e,0xe1,0x2,0x14,0x14,0x14,0xd4,0xf,0x1a,0xd8,0xdf,0x47,0xeb,0xb6,0xb7,0xd9,0x23,0x13,0xe5,0xf7,0x8d,0x85,0xb,0xe0,0xb2,0xf4,0x5a,0xa0,0x4e,0x44,0xb3,0xf7,0x68,0xf5,0x27,0x3,0x7,0x81,0x5e,0xbc,0x53,0xb8,0x0,0x45,0x45,0x45,0xd5,0x2,0x97,0x47,0x7a,0x53,0x72,0x8d,0x71,0x9b,0xbb,0x38,0xaa,0xf2,0x25,0x68,0x4e,0x49,0xc9,0xf4,0xd,0x4d,0x85,0xad,0x5f,0x37,0xfc,0x95,0x1e,0xe5,0xd6,0x4d,0xc5,0xc5,0x85,0x8b,0xa2,0x14,0xc3,0x7f,0x35,0xfc,0xb1,0x63,0xc6,0x8c,0xc2,0xdd,0xb6,0xbe,0x2d,0x2c,0x2c,0xb4,0x89,0xb8,0xc5,0xbd,0x1a,0x5f,0x4f,0x71,0xb9,0x7d,0x80,0x6d,0x89,0x7d,0x49,0xd3,0xc1,0xb6,0xa2,0x30,0xca,0x7d,0xd,0xae,0x6f,0xcb,0x2,0xb0,0xb4,0x1f,0x90,0xaa,0xc8,0xc5,0x51,0x33,0x5a,0xec,0x5f,0x0,0xa4,0xb8,0x5d,0x3d,0xa3,0x18,0xe2,0x99,0x3d,0x2f,0x3d,0x5c,0x58,0xb8,0x9,0xa8,0xdd,0x39,0x28,0xd8,0xc8,0x66,0xf,0x44,0x5a,0x3f,0x6d,0xb2,0xe9,0xdf,0x94,0x29,0x53,0xc2,0xc0,0x27,0xe,0x72,0xa2,0xc9,0x59,0x57,0x45,0x45,0x45,0x1b,0x1a,0x5c,0xe2,0xef,0xed,0xf1,0xd5,0xf5,0xc0,0x1a,0xb7,0x4b,0x9a,0x8c,0x73,0x14,0x17,0x17,0x7e,0x2,0x7c,0x8e,0xe8,0x85,0xdd,0xa1,0xfc,0xba,0xbb,0x62,0xa2,0xb2,0xb2,0x26,0x1e,0x81,0xe8,0x83,0x51,0x46,0xb8,0x5e,0x2b,0x29,0x29,0x7c,0xe2,0xbb,0x16,0xa9,0x78,0xfa,0x2,0x60,0x41,0x33,0xc2,0xae,0x8f,0x9c,0x71,0xab,0x7,0x44,0xf9,0x3a,0xd4,0x4c,0x13,0x52,0xdb,0x70,0xc4,0xec,0x9a,0x66,0xdc,0x84,0x8f,0x14,0xdc,0xe3,0xc7,0x8f,0x4f,0x79,0xf8,0xe1,0x87,0xeb,0x23,0xcf,0x61,0x14,0x42,0xdd,0x8c,0x19,0x33,0xa2,0xbb,0x79,0x2e,0x16,0x60,0xe3,0xca,0xca,0xca,0xea,0x55,0x52,0x52,0xb2,0xbd,0xd9,0xe2,0x6f,0x93,0x81,0xa0,0x33,0x8b,0xa7,0x47,0x3d,0x3a,0x74,0xc6,0x8c,0x19,0x2b,0xb3,0xb2,0xf3,0xa8,0xaf,0xf,0x9f,0xe,0xec,0xb1,0xd5,0xab,0xd5,0xdc,0x46,0x7e,0x61,0x22,0x13,0x5f,0x1a,0xd3,0x3,0xd8,0x56,0x52,0x5c,0x54,0xd3,0xc2,0x3d,0xb1,0xd2,0xdc,0x7c,0xe7,0x1a,0xe0,0xe8,0x3d,0xae,0xed,0x3,0x4,0xb,0xb,0xb,0x9b,0x7b,0xce,0x16,0xe0,0x94,0x29,0x53,0xa6,0xc8,0x94,0x29,0x53,0xd4,0x88,0xb7,0xf3,0x39,0xd3,0xee,0x86,0xc1,0x8f,0xc6,0x5,0x6e,0x4,0xc2,0x57,0xcd,0xdd,0x32,0x7e,0xfc,0xc4,0xfe,0x6e,0xb7,0x1e,0x9,0x1c,0xaa,0xaa,0x16,0xd8,0x7d,0x63,0xf5,0xca,0x55,0xa9,0x6f,0xb8,0x23,0xea,0x89,0x84,0x8a,0x7c,0xe,0x2a,0xae,0xd4,0xd4,0xc3,0x88,0x8c,0x2,0x43,0xc4,0x75,0x77,0x65,0x65,0xe7,0xfd,0x29,0x6a,0xa0,0x36,0xbd,0x1,0x5c,0x2e,0xd7,0x11,0xd,0x3,0x6a,0xcd,0xf9,0x50,0x19,0x28,0x34,0x1b,0xce,0x2e,0xdb,0x1c,0xd7,0x54,0xbc,0xcd,0x62,0x3,0x7d,0x26,0x4c,0x98,0x68,0xcd,0x9c,0x39,0x7d,0xa7,0xc0,0x53,0x1a,0x6,0xf5,0xda,0x83,0x7a,0x60,0xc0,0xd,0x37,0xdc,0x6a,0x3d,0xfe,0xf8,0x3,0x3b,0x9f,0x3f,0x0,0x38,0xaa,0x85,0x74,0x1e,0xc,0xf4,0xde,0xbc,0x79,0x73,0x1a,0xc9,0x77,0x2e,0xb3,0x11,0xef,0xde,0x28,0x29,0x9e,0xfe,0x11,0xe0,0xf9,0xae,0x25,0xce,0xc9,0x1b,0x86,0x46,0x77,0xe7,0xb2,0xb2,0x73,0xf,0x1,0xb9,0x1f,0xf4,0x8a,0x86,0x6a,0x7a,0x2b,0x22,0xea,0xa4,0x3f,0x2d,0x2a,0xb4,0x74,0x22,0xbd,0xda,0x12,0x12,0x4b,0x71,0xed,0xbe,0x7f,0x75,0x9f,0x86,0xee,0xcb,0xb1,0x2d,0x4,0xbd,0x8,0xd8,0xb1,0x97,0x2e,0x40,0x1f,0x89,0xc4,0x79,0x2f,0xe1,0xe8,0x9a,0x58,0xd3,0x65,0xdb,0xae,0xdd,0x7d,0x1,0xd5,0x76,0x3d,0x2e,0xb5,0xae,0xae,0xe7,0xee,0xcf,0x8f,0xb4,0xbe,0xcd,0xa5,0xf3,0x23,0xe0,0x23,0xdb,0x76,0xd9,0x74,0x71,0x3a,0xbb,0x78,0xab,0x89,0x6d,0x93,0xec,0x3d,0x84,0x3b,0x71,0x10,0xe8,0xf2,0x6,0xf1,0xfc,0x42,0x8,0xbf,0x54,0x5c,0x5c,0xbc,0xb1,0xc1,0xf5,0x1e,0x8c,0x68,0x7b,0x8d,0x58,0x56,0x97,0x14,0x17,0x9e,0x15,0x87,0x70,0xec,0x38,0x85,0x93,0xdc,0x63,0x15,0xa2,0x8f,0xcd,0x9c,0x51,0x74,0x3f,0xdd,0x9c,0xce,0x2e,0xde,0x2f,0x88,0x4c,0x68,0x70,0x5a,0xc,0xee,0x7,0xfa,0xa0,0xe2,0x2d,0x29,0x99,0xbe,0xa8,0x83,0xd2,0xf0,0x29,0x91,0xf7,0x9a,0x6d,0xc2,0x82,0x8f,0xb5,0x7d,0xa6,0xbb,0x86,0x11,0xd9,0xbf,0x3,0xf3,0x7c,0x87,0x68,0x87,0x3e,0x3f,0x69,0xe8,0xec,0xa3,0xcd,0x7e,0x60,0xc0,0x84,0x9,0xb9,0x43,0x62,0xbd,0xf1,0x86,0x1b,0x6e,0x10,0x22,0xb3,0x9f,0x3e,0xeb,0x40,0xe1,0x2,0x32,0x9f,0x38,0x1c,0x3,0x23,0x22,0xaf,0x1,0x72,0xf3,0xcd,0x37,0xf7,0x4c,0x70,0x84,0xeb,0x81,0xff,0xeb,0xc0,0x3c,0xdf,0x8,0xfa,0x3d,0x23,0xdd,0x4e,0x2e,0x5e,0x55,0x9d,0x3,0x88,0x58,0xf2,0xf0,0x5e,0xfa,0x83,0x4d,0x5a,0xa4,0xb4,0xbe,0x7d,0xdd,0xd,0x83,0x1f,0xcd,0x1d,0xd,0x79,0x50,0xbb,0xa4,0xc1,0xb6,0xe7,0x2,0x29,0x59,0xd9,0x79,0xbf,0x68,0x93,0xbf,0xac,0xfa,0x2e,0x80,0xe5,0x4a,0x7d,0x2c,0xc1,0x51,0xfe,0x16,0xe8,0x91,0x95,0x95,0xd7,0xdc,0xfb,0xdc,0xbe,0x89,0xf7,0xb6,0xe4,0xcc,0xac,0xac,0xbc,0xc1,0x46,0xbc,0x9d,0x98,0x1e,0x69,0xee,0x65,0x40,0x5,0x70,0xc1,0x84,0xec,0xbc,0xb,0xa2,0xb7,0xb0,0xb7,0x5a,0x82,0xde,0x4,0x20,0xe8,0xdb,0x3b,0xaf,0x97,0x4c,0x9b,0x56,0x4f,0xe4,0xec,0xa3,0x83,0xae,0xb9,0x66,0xca,0x6e,0x23,0x32,0x39,0x39,0x13,0x7,0x22,0xfa,0x42,0xa4,0x49,0xdb,0xfb,0x3b,0xd6,0x36,0x89,0xd7,0x65,0x7d,0xd8,0xe0,0xfe,0x4f,0xcf,0xc9,0xc9,0xe9,0xbd,0xe7,0xf7,0x39,0x39,0xb9,0x43,0xb3,0x9b,0x49,0x5b,0x63,0x4a,0x8a,0xb,0x43,0xd,0xb6,0xf8,0x59,0x76,0xf6,0xa4,0x26,0x6e,0x65,0x7e,0x7e,0x7e,0x4a,0x56,0xf6,0xc4,0xfc,0x36,0xb7,0xf0,0xe8,0x15,0x80,0x22,0xe4,0xe6,0xe7,0xe7,0xef,0x56,0x29,0x66,0x67,0xe7,0x9d,0x45,0x64,0xd,0x75,0xc2,0xb0,0xe1,0x5a,0x20,0x84,0x70,0xdb,0xd,0x37,0xdc,0x6a,0x35,0x1d,0xc7,0xc8,0xfb,0x59,0x76,0xf6,0xc4,0x81,0xa6,0xcf,0x9b,0xe4,0x14,0x14,0x14,0xd8,0x59,0x59,0xb9,0x57,0x22,0xb2,0x40,0xe0,0xa5,0xac,0xec,0xbc,0x3f,0x82,0xcc,0x42,0x59,0x1,0xea,0xc6,0xe2,0x4,0xb4,0x6e,0x2,0x91,0x59,0x4d,0x7f,0x2e,0x2e,0x2e,0xda,0x73,0x31,0xf8,0x6d,0xc0,0xbf,0xfa,0xf6,0xdb,0x32,0x77,0x42,0x4e,0xde,0x9d,0x62,0xb3,0x5d,0x84,0x33,0x6d,0xd5,0x3b,0x14,0x9e,0x12,0xf8,0xd,0x4a,0x42,0xb,0xc2,0x43,0x33,0xa6,0x87,0x26,0xe4,0xe4,0x8e,0x11,0x95,0x15,0xb6,0x5a,0x1f,0x67,0xe5,0xe4,0xde,0xe8,0x12,0x96,0x84,0x6c,0x39,0x58,0xe0,0xc,0x5b,0x99,0xe,0x7c,0xd,0xcc,0xde,0x5b,0x58,0x29,0x6e,0xeb,0xbc,0xfa,0x90,0xbd,0x56,0xb1,0x57,0x67,0x67,0xe7,0x5d,0xad,0xca,0x22,0xb5,0xa4,0xbf,0xa0,0xa7,0xd5,0xd6,0x85,0x1f,0x0,0x6,0x4c,0xc8,0xc9,0x9b,0x3e,0x73,0x46,0xa1,0xe3,0x91,0xd8,0xe2,0xe2,0xa2,0x65,0x59,0xd9,0x79,0x2b,0x80,0xdf,0xd7,0xd6,0x85,0x7b,0x66,0x67,0xe7,0xbe,0xa,0xb2,0x45,0x61,0x9c,0xc2,0xbd,0x44,0xa6,0x52,0xee,0x97,0x30,0x7b,0x15,0x17,0x7e,0xd2,0xf0,0x9a,0x68,0x52,0x5a,0xcf,0xba,0xfe,0xd9,0xd9,0x79,0x7f,0xb2,0x2d,0xfd,0x4c,0xc2,0x72,0xa,0xc2,0x45,0xc0,0xd,0x36,0xf6,0xb9,0xc0,0x3c,0xd3,0xf2,0x26,0x39,0x25,0x25,0x45,0x6b,0x11,0x19,0x1,0x3c,0x4,0x5c,0xd,0x5a,0x8e,0xe8,0x1a,0x84,0xaf,0x50,0x4a,0x81,0xa3,0x80,0xeb,0x4a,0x8a,0xb,0x9b,0xb8,0xa5,0x76,0x58,0x5e,0x3,0xa,0x80,0xd1,0xa2,0x2c,0x41,0x78,0x57,0xe1,0x41,0x85,0x3f,0x84,0xea,0xec,0x29,0x44,0x26,0x63,0xf4,0x4f,0x74,0x1a,0x66,0xce,0x28,0x5a,0xa9,0xa2,0x47,0x3,0x55,0xa8,0xcc,0xe,0xdb,0xb2,0x56,0x22,0x8b,0x1d,0x1e,0x6,0x5e,0x45,0x43,0xad,0x1a,0x94,0x9b,0x3e,0x7d,0x5a,0x4d,0x7d,0x9d,0xeb,0x0,0xe0,0x6d,0x85,0xe7,0x10,0xbe,0x12,0xd5,0xf7,0x51,0x9e,0x2,0x3e,0x42,0x65,0x58,0x5b,0x84,0xbb,0xcb,0x5d,0x8,0x9d,0xa,0xcc,0x5,0x6e,0x57,0x64,0xb1,0xc2,0xfb,0x44,0x2a,0xba,0x4b,0x1a,0x2a,0x9a,0xc4,0xe6,0x79,0x71,0xe1,0xcd,0xc0,0xcd,0x28,0x57,0x2a,0x2c,0x11,0x5b,0xd6,0x20,0xcc,0x23,0x32,0x3d,0x32,0xc7,0xe,0xd5,0x95,0x99,0x96,0xb7,0xb3,0x8,0x78,0xc6,0xf4,0x2d,0x40,0x76,0x56,0xd6,0xc4,0xc9,0x58,0x7a,0x86,0x28,0xfb,0x2,0x55,0xaa,0xfa,0x79,0x49,0x49,0xd1,0x87,0xcd,0xd6,0xe2,0xf,0x4d,0xf,0x1,0x93,0xb3,0xb3,0x73,0x66,0x28,0xd6,0xff,0x9,0xd4,0x86,0x42,0xee,0xc5,0xf,0x3f,0x3c,0x75,0x47,0xc4,0xd,0xcc,0x1e,0x24,0xe2,0xda,0x43,0xf0,0x2e,0x5f,0x4a,0x4a,0xa8,0x99,0x4a,0xaf,0x7e,0xb3,0xcb,0x72,0xed,0x23,0x22,0x51,0x67,0x60,0xd5,0xd6,0x6e,0x5d,0xde,0xbb,0x77,0xef,0x7d,0x6,0xc,0x18,0x50,0x15,0x45,0xc0,0xab,0x81,0x63,0x26,0x4c,0xc8,0x3b,0x8,0x8b,0xd3,0x44,0x74,0xbb,0xa8,0xbd,0xac,0xb8,0xb8,0x38,0xa6,0xd7,0x55,0x8f,0x3e,0x5a,0x50,0xd,0x9c,0x95,0x9b,0x9b,0x3b,0x24,0x6c,0x5b,0xa7,0x3,0x58,0x12,0x7e,0x7f,0xc6,0x8c,0x19,0x9f,0x47,0x11,0xe1,0xe9,0x2e,0x97,0xcb,0x2a,0x2a,0x2a,0x8c,0x1a,0x5f,0x97,0xa5,0x87,0x0,0x52,0xf2,0xf0,0x54,0x7b,0xf7,0xa,0xb3,0x24,0xc,0xfc,0x70,0xc2,0x84,0xbc,0xfd,0xc4,0x92,0x11,0x2,0xd5,0xd5,0xd5,0xd5,0x95,0x7f,0xf9,0xcb,0xe3,0xa1,0xac,0xec,0xbc,0x22,0x0,0x15,0x3b,0xbc,0x47,0x58,0x83,0x5c,0x2e,0xd7,0x8e,0xdd,0x5b,0xe,0x7b,0x94,0x58,0xe2,0x76,0xbb,0xdd,0x51,0xf,0x47,0xb7,0x84,0xd3,0x45,0xd4,0x7a,0xf2,0xc9,0x29,0x76,0x14,0x1,0x3f,0x7c,0xcd,0x35,0x53,0x1e,0xeb,0xd3,0x6f,0xcb,0xff,0x89,0xc8,0x11,0xa2,0xf6,0x37,0x21,0x97,0xbc,0xf5,0x70,0x61,0x61,0x7d,0x77,0xe9,0xf3,0xa,0x6,0x43,0x1c,0xc9,0xca,0xce,0xfb,0x1f,0x30,0x30,0x54,0x9f,0xd6,0xf3,0x91,0x47,0xee,0x37,0xc7,0x61,0x1a,0xb7,0xd9,0xd0,0x19,0xb8,0xe9,0xa6,0xdb,0x7a,0x10,0x99,0xfd,0xe4,0x37,0xc2,0x35,0xe2,0x35,0x24,0x21,0x37,0xe7,0xe5,0xd,0xce,0xc9,0xc9,0xdd,0x6d,0x20,0x6f,0xca,0x94,0x29,0xe2,0x4e,0xa9,0x7d,0xe,0xe8,0x21,0xc2,0x4d,0xc6,0x4a,0xa6,0xcf,0x6b,0x48,0xc6,0x1a,0xdf,0xe6,0x5e,0x5b,0xe5,0xfa,0xac,0xec,0xbc,0xb9,0x44,0x16,0x58,0xf4,0xdd,0xb0,0x71,0x4b,0x3a,0x70,0x14,0x22,0xc5,0xa1,0xfa,0x9a,0x2f,0x8c,0x95,0x8c,0x78,0xd,0x49,0x88,0x86,0xf5,0x5e,0xb1,0x64,0xd,0x30,0x8e,0xc8,0x7a,0xdf,0xed,0xc0,0xbb,0x82,0xe4,0x17,0xcf,0x98,0x3e,0xdb,0x58,0xa8,0x7d,0xf8,0x7f,0x49,0xf1,0x1a,0x6f,0x4b,0xd5,0x18,0xc6,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
-};
-
-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
-};
-
-static const Color boot_splash_bg_color = Color(224/255.0,224/255.0,224/255.0);
-#endif // SPLASH_H
+#ifndef BOOT_SPLASH_H
+#define BOOT_SPLASH_H
+
+static const unsigned char boot_splash_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xef,0x0,0x0,0x1,0x3,0x8,0x6,0x0,0x0,0x0,0xdd,0x81,0x53,0xf4,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0x32,0xdf,0x0,0x0,0x32,0xdf,0x1,0x17,0xbe,0xe4,0xb,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x1,0x19,0x13,0x8,0x19,0x46,0x43,0xd9,0xbb,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,0x9d,0x79,0x78,0x54,0xd5,0xf9,0xc7,0x3f,0xef,0x9d,0x49,0xc2,0xe,0xb2,0xb9,0xaf,0xb8,0x2f,0x3f,0xb5,0xa8,0xb4,0xa2,0x66,0x66,0x2,0x4,0xea,0x5a,0xad,0x5a,0x6d,0xb5,0x2e,0xad,0x56,0x24,0x1b,0x4,0xb5,0x5a,0x2b,0xb6,0x6a,0x55,0x2,0x9,0x9,0xae,0x5d,0xd4,0x5a,0x6b,0x15,0xad,0x15,0x15,0x48,0x48,0x66,0x26,0x50,0x10,0x17,0xa,0x2a,0x56,0x51,0x11,0xd7,0x8a,0xec,0x90,0x0,0x59,0x66,0xee,0xfb,0xfb,0x63,0x82,0x4,0x32,0x9,0x99,0x9b,0x99,0x64,0x92,0x9c,0xcf,0xf3,0xcc,0x43,0xb8,0x33,0xf7,0xdc,0x73,0xde,0x73,0xbe,0xe7,0xbc,0xe7,0xdc,0xb3,0x80,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x86,0x16,0x19,0x53,0xe0,0xdf,0xaf,0xbd,0x9e,0x95,0x71,0x5f,0x79,0x2f,0x63,0xf1,0xce,0x87,0x18,0x13,0x24,0x81,0x50,0xa7,0x96,0xa,0x92,0x76,0xb4,0xc0,0x39,0xa0,0xe7,0x0,0xe7,0x0,0x43,0x4a,0xf3,0xbd,0x9,0x17,0x55,0x66,0x81,0xdf,0x7,0x52,0xe,0x2c,0x5,0x16,0x0,0xb,0xdc,0x96,0x1d,0x7c,0x6d,0x62,0xc6,0x16,0x93,0x33,0x46,0xbc,0x86,0x28,0x8c,0x9b,0x56,0xe9,0xb2,0x35,0xec,0x1,0xb9,0x0,0x38,0xf,0x38,0xa2,0x69,0xee,0xc8,0x43,0xa5,0x93,0x3c,0x13,0x12,0x2b,0xde,0x40,0x15,0xd0,0x27,0xca,0x57,0xb,0x15,0x5e,0x1,0x99,0x5d,0x96,0xef,0x59,0x69,0x72,0xcc,0x88,0xb7,0x5b,0xf3,0xc3,0x82,0xa,0xcb,0xc6,0xf2,0x2a,0xfc,0x1c,0xb8,0x8,0xe8,0xbb,0x97,0x5b,0xea,0x43,0x75,0xe1,0xfe,0x15,0xb7,0x8f,0xda,0x91,0x10,0xe1,0x4e,0xd,0xdc,0x88,0xf0,0x68,0x2b,0x7e,0xfa,0x11,0xf0,0xac,0xad,0xfa,0xd4,0xfc,0xc9,0xbe,0xd5,0x26,0x27,0x8d,0x78,0xbb,0xd,0x63,0xb,0x2,0x47,0x2a,0x5c,0xb,0x5c,0x5,0x1c,0x1c,0xe3,0xed,0xf3,0x4b,0xf3,0xbd,0x63,0x12,0xd4,0xea,0xd6,0x3,0xee,0x18,0x6f,0x5b,0x8,0x3c,0x95,0x52,0x5f,0xfb,0xb7,0x57,0x7f,0x3d,0xb6,0xd6,0xe4,0xae,0x11,0x6f,0x97,0xe3,0xfc,0x29,0xaf,0x48,0x5d,0xdf,0x3e,0x67,0xa1,0xe4,0x3,0x17,0xb4,0x21,0xa8,0xb0,0x25,0x1c,0x32,0x77,0x92,0xf7,0x7f,0x71,0x16,0x6e,0x9,0xd0,0x16,0x97,0x7c,0x1b,0x50,0x62,0xa1,0xd3,0xe7,0xe6,0xfb,0xd6,0x99,0x1c,0x37,0xe2,0xed,0x12,0x8c,0x29,0x8,0x64,0xa,0xdc,0xd,0x8c,0x88,0x53,0x90,0x1f,0x96,0xe6,0x7b,0x8f,0x8b,0x5b,0x7f,0xbb,0x78,0x4e,0x9a,0x5d,0xd7,0x73,0x3b,0x60,0xc5,0x21,0x38,0x1b,0xf8,0x6b,0x8a,0x86,0xb2,0x5e,0x9d,0x3c,0xba,0xda,0xe4,0x7e,0xfb,0x61,0x19,0x13,0x24,0xa4,0x46,0x1c,0x1f,0x47,0xe1,0x2,0x1c,0x93,0x39,0x3d,0x70,0x54,0xbc,0x2,0xb3,0xeb,0x7a,0x3e,0x17,0xc7,0xbc,0xb7,0x80,0x6b,0xea,0xc5,0x3d,0xc0,0xe4,0xbc,0x11,0x6f,0x57,0x60,0x6d,0xdc,0xeb,0x3,0x9b,0x57,0xe3,0xd4,0xea,0xba,0x80,0xf3,0x13,0x90,0xe6,0xb0,0xc9,0x76,0x23,0x5e,0x23,0xde,0xe8,0x1c,0x39,0x66,0xaa,0xff,0x80,0x38,0xb4,0xba,0x7f,0x4a,0x50,0xbe,0x1b,0xf1,0x1a,0xf1,0x1a,0xf1,0x36,0x97,0x57,0x22,0xf2,0x4a,0x1c,0xc2,0xb9,0x3a,0x41,0x9d,0x5,0x23,0x5e,0x23,0xde,0x2e,0x80,0x26,0x44,0xbc,0x0,0xa7,0x8c,0x2a,0x2c,0x77,0xdc,0xb7,0xcc,0x2c,0x8,0x4c,0x4b,0x54,0x9e,0x4b,0x64,0xe0,0xca,0xd0,0x8e,0xb8,0x8d,0x9,0x12,0x52,0x92,0x13,0x25,0x5e,0xcb,0x15,0x76,0xbd,0x4,0x78,0x77,0x5e,0x18,0x53,0x10,0x18,0xec,0xb2,0xb4,0x4f,0xd8,0x96,0x5e,0x88,0xf4,0x6,0x3b,0x84,0x6d,0x6d,0x3,0x7b,0x5b,0x38,0xc5,0xde,0x52,0x91,0x3b,0xaa,0xf1,0x8,0x70,0x6e,0xe2,0xea,0x2b,0x35,0x2d,0xaf,0x11,0x6f,0x57,0x68,0x78,0x59,0x9b,0xc0,0x77,0x70,0xe7,0x64,0x16,0x4,0xca,0x80,0x43,0x81,0x43,0x80,0x1e,0xb6,0x2d,0x91,0x77,0x7e,0xaa,0x91,0x36,0x50,0x22,0xff,0xba,0x43,0x2e,0x32,0xb,0x2,0x1b,0x80,0xcf,0x81,0x4d,0x9,0xf6,0xb4,0x8c,0x78,0x8d,0x78,0xbb,0x42,0xc3,0x4b,0x55,0x82,0xbb,0x3a,0xa3,0x63,0xf8,0xfd,0xa0,0x86,0x4f,0xa2,0xab,0xac,0x7a,0x93,0xf3,0xa6,0xcf,0xdb,0xf9,0xc5,0x2b,0x52,0xd3,0xcd,0x92,0x1c,0xaa,0x75,0x89,0x11,0xaf,0x11,0x6f,0x17,0x70,0x9b,0x95,0xee,0x36,0xe7,0xf7,0x83,0x60,0x9e,0x57,0x4d,0xce,0x1b,0xf1,0x76,0x5,0xf5,0x76,0x37,0xf1,0xbe,0x63,0x32,0xdd,0x88,0xb7,0x4b,0x60,0x63,0xd5,0x18,0xf1,0x1a,0x8c,0x78,0x3b,0x21,0xf3,0x27,0xa7,0xdb,0x44,0x46,0x78,0xbb,0x49,0x27,0x5f,0x97,0x9b,0x5c,0x37,0xe2,0xed,0x4a,0xac,0xe8,0x36,0xda,0xb5,0xd5,0xec,0xb4,0xd1,0x11,0x76,0x37,0x26,0x88,0x2f,0x63,0xa7,0xf9,0x53,0x54,0xe5,0x76,0xe0,0x4e,0xc0,0xd5,0x4d,0x92,0xbd,0x5a,0x85,0x5f,0x95,0x4d,0xf2,0x96,0x99,0x12,0x60,0xc4,0xdb,0x29,0xc9,0x2c,0x8,0x8c,0x6,0x1e,0x1,0x86,0x75,0x53,0x13,0x3c,0x6f,0x5b,0xf6,0xcd,0xf3,0x27,0x66,0xac,0x37,0xa5,0xc1,0x88,0x37,0x21,0x8c,0x7b,0x20,0xe0,0xb2,0x5d,0x72,0xbf,0xaa,0xce,0x2e,0x9b,0xec,0x5d,0xd8,0xd6,0xf0,0x46,0x15,0x2f,0xe8,0xe9,0xaa,0xf,0x17,0xa3,0xfc,0xc2,0x14,0x29,0x6a,0x54,0xf9,0xa5,0x1d,0xe,0x3d,0x53,0x7e,0xdb,0xe8,0x36,0xbd,0x3e,0x1a,0xfe,0xd8,0xdb,0xd6,0xe0,0xad,0x55,0x13,0x10,0xde,0x2f,0xcd,0xf7,0x56,0x18,0xd3,0x1a,0xf1,0x92,0x59,0x10,0xb8,0x1b,0xf8,0x2d,0xa0,0xc0,0x6c,0x41,0x7f,0x3d,0x2f,0xdf,0xf7,0x81,0xa3,0xb0,0xa6,0xfa,0x47,0x22,0xf2,0x2c,0xb1,0xef,0x4d,0xd5,0xd5,0x79,0xc1,0x25,0xae,0xeb,0xe7,0x4c,0x3a,0x67,0xab,0xb3,0x3c,0xa,0x5e,0xe,0xfa,0x0,0x91,0x69,0xa0,0x21,0x41,0x4f,0x99,0x97,0xef,0x7b,0xdf,0x98,0xb5,0x1b,0x8b,0x37,0xb3,0x20,0x70,0x25,0xf0,0xcc,0x1e,0x97,0x43,0xc0,0x13,0x2,0x77,0xce,0xcb,0xf7,0x7e,0xdb,0x9a,0x70,0xc6,0x14,0x4,0x5c,0x12,0xe9,0xd7,0xde,0x65,0x8a,0x51,0xb3,0x6c,0x14,0xe4,0xfc,0x79,0xf9,0x9e,0xc5,0xad,0xbd,0x61,0xcc,0xb4,0x80,0x4f,0x94,0x7,0x81,0xe1,0x7b,0x7c,0xb5,0x49,0x2c,0xfb,0xb8,0x79,0x13,0x33,0xbe,0x35,0x66,0xed,0x86,0xe2,0xcd,0x2c,0xf0,0xff,0x0,0x64,0x51,0xb,0xe9,0xde,0x1,0x4c,0x4d,0xad,0xae,0xfe,0xfd,0x2b,0x53,0xce,0xf,0x35,0x17,0xce,0xe8,0xe9,0xc1,0xfe,0x96,0xad,0xcf,0x1,0x99,0xa6,0x8,0xb5,0x8a,0x5b,0xc2,0xa1,0xd0,0xb4,0xf2,0xdb,0x46,0xdb,0x2d,0x78,0x30,0xc3,0x10,0x29,0x6,0xc6,0xb5,0x90,0x3f,0x1f,0x28,0x32,0xa2,0x2c,0xdf,0x53,0x65,0x4c,0xda,0x8d,0xc4,0x3b,0xf6,0x41,0xff,0xe1,0x6a,0xc9,0x7b,0x40,0xef,0x56,0xfc,0xfc,0x33,0x81,0x5f,0xcd,0xcb,0xf7,0x96,0x36,0x9,0xa7,0x20,0x78,0x82,0xa2,0x15,0xc0,0xbe,0xa6,0xf8,0xc4,0xc4,0x4b,0x82,0x5e,0x39,0x2f,0xdf,0x57,0xb3,0x67,0xbf,0x76,0x50,0x55,0xd5,0x6f,0x4,0xee,0x0,0x52,0x5b,0x11,0xce,0x5c,0x4b,0xac,0x8b,0xe6,0x4e,0x4a,0xaf,0x33,0xe2,0xed,0x6,0x8c,0x9b,0xea,0x1f,0x68,0x8b,0x2c,0x23,0xb2,0x84,0xae,0xb5,0x28,0xf0,0xf,0x45,0xb3,0xcb,0xf2,0x7d,0xeb,0x1b,0x5c,0xee,0x4c,0xe0,0x15,0x20,0xc5,0x68,0xd1,0x11,0xff,0xc1,0xd2,0x8c,0xd2,0x89,0xbe,0xcd,0xd,0xfd,0xda,0xc,0xd0,0xc7,0x89,0x76,0x5a,0x44,0xcb,0x14,0xd7,0xf6,0x24,0x37,0x78,0x73,0xf7,0x9e,0x4f,0xdd,0xe5,0xc5,0x9b,0x39,0x35,0xd0,0x13,0x61,0x3e,0x30,0xd2,0x61,0x10,0xd5,0xa,0xb7,0xa2,0x84,0xa5,0x75,0xa7,0xb,0x18,0x5a,0xe6,0x7f,0xaa,0x7a,0xae,0x88,0x4c,0x4,0x7e,0x8a,0xc3,0x89,0x42,0x2,0x37,0xcf,0xcb,0xf7,0x3e,0x6c,0xc4,0xdb,0x45,0x19,0x33,0xb5,0x54,0x44,0x52,0x9f,0x24,0x61,0xfb,0x36,0x19,0x3a,0xb8,0xf0,0x7a,0xe7,0xe5,0x7b,0x83,0xdd,0x35,0xfd,0x5d,0x7a,0x7a,0xa4,0x48,0xea,0xe5,0x46,0xb8,0x5d,0x17,0x85,0x57,0x32,0xb,0x82,0x43,0x4d,0xcb,0xdb,0xf5,0xdc,0xe5,0xc3,0x11,0x56,0x9a,0xfe,0x69,0x97,0xa7,0x52,0x61,0x74,0x59,0xbe,0xb7,0xdb,0x6d,0x6,0xd0,0x25,0x5b,0xde,0xb1,0xd3,0xfc,0x3d,0x11,0x66,0x1b,0xe1,0x76,0xb,0xd2,0x45,0xc8,0x32,0x6e,0x73,0x57,0x71,0xa7,0x54,0xee,0x4,0x4e,0x34,0xe5,0xba,0xdb,0xf8,0xcf,0xd3,0x32,0xa7,0x6,0x4e,0x30,0x6e,0x73,0x67,0x77,0x97,0xb,0xfc,0x27,0x81,0xbc,0x6b,0x4a,0x74,0xb7,0xe3,0x43,0x81,0x53,0xe7,0xe5,0x7b,0xbb,0xcd,0x46,0x8,0x5d,0xaa,0xe5,0x1d,0x53,0xe0,0x4f,0x3,0xf9,0x87,0x29,0xc7,0xdd,0x92,0x63,0x51,0x7e,0x69,0xdc,0xe6,0xce,0xea,0x46,0xa8,0xdc,0x0,0x1c,0x6f,0xca,0x71,0x37,0xf5,0x9e,0x85,0xa2,0x31,0x85,0xc1,0x43,0x8d,0x78,0x3b,0x9b,0xbb,0x3c,0xbd,0xb2,0x7,0xc2,0xfd,0xa6,0x8,0x77,0x6b,0x2c,0x9,0xeb,0x8d,0x46,0xbc,0x9d,0x8c,0xd2,0x89,0xe9,0x35,0xc0,0x4d,0xa6,0xfc,0x76,0x6b,0x6a,0x41,0x4b,0x8c,0x78,0x3b,0x21,0x29,0x96,0xfd,0x77,0x60,0xa1,0x29,0xc3,0xdd,0x96,0x6b,0x4b,0xf3,0x7d,0xdf,0x18,0xf1,0x76,0x42,0x5e,0x9d,0x98,0x11,0x2,0xae,0x22,0xb2,0x3e,0xd7,0xd0,0xbd,0xa8,0xb4,0xc2,0xcc,0xea,0x56,0x7d,0x84,0xae,0x96,0xa0,0xd2,0x7c,0xef,0xe7,0xc0,0x4,0x53,0x96,0xbb,0x15,0x21,0xb5,0xf8,0xd9,0xdc,0x5b,0xbd,0x21,0x23,0xde,0x4e,0x8e,0xc2,0x13,0xc0,0x52,0x53,0xa6,0xbb,0x9,0xca,0x8d,0x65,0x13,0xbd,0x5f,0x75,0xb7,0x64,0x77,0x49,0xf1,0x96,0xe5,0x7b,0xeb,0x54,0xb9,0xcc,0xb8,0xcf,0xdd,0x82,0x85,0x61,0xb7,0xf5,0x74,0x77,0x4c,0x78,0x97,0x5d,0x55,0x54,0x36,0xd9,0xfb,0xa9,0x98,0x15,0x45,0x5d,0x9d,0x6a,0x55,0x7e,0x5c,0x9e,0x97,0x5e,0x6f,0xc4,0xdb,0xc5,0xb0,0xb5,0xee,0x1f,0x34,0xdd,0x6c,0xce,0xd0,0x45,0x10,0x95,0xb,0xca,0x26,0x7b,0xd7,0x76,0xdb,0xf4,0x77,0xf5,0x4,0x8e,0x29,0x8,0xf6,0x13,0x74,0x5,0x66,0x6b,0xd6,0xae,0xc6,0x83,0xa5,0xf9,0xde,0x5b,0xbb,0xb3,0x1,0xba,0xfc,0x59,0x45,0x65,0xf9,0x9e,0xad,0xaa,0x7a,0x2e,0x91,0x3d,0xa9,0xc,0x5d,0x83,0x77,0xb1,0xcc,0x96,0xbb,0xdd,0xe2,0xa0,0xb1,0xb2,0xc9,0xbe,0xf7,0x80,0x9b,0x4d,0x99,0xef,0x12,0xd4,0xdb,0x22,0xe7,0x96,0x4e,0xf4,0xd6,0x18,0xf1,0x76,0x1f,0xca,0x4d,0xb9,0xef,0x12,0x6c,0x98,0x3f,0xc9,0xf3,0x95,0x31,0x83,0x39,0xe2,0xd3,0x60,0xe8,0xb4,0xb8,0x8d,0x9,0xda,0x8e,0x0,0x47,0xc,0xed,0xc3,0xf,0x8e,0x1c,0xcc,0x89,0x7,0xf6,0x67,0x50,0x9f,0x34,0x6,0xf6,0x4e,0x65,0x7b,0x5d,0x98,0xd,0xd5,0xb5,0x7c,0xb5,0x69,0x7,0x4b,0x3e,0x59,0xcf,0x5b,0xab,0x37,0x50,0x1b,0xb2,0x3b,0x7f,0x7a,0x5,0x4e,0x39,0x64,0x1f,0x7e,0x30,0x6c,0x30,0xc3,0x86,0xf6,0x61,0x50,0x9f,0x34,0xfa,0xf7,0x4a,0x61,0xf3,0xb6,0x3a,0xd6,0x57,0xd7,0xf2,0xc9,0xb7,0xd5,0xbc,0xbe,0x6a,0x3d,0x2b,0xbe,0xda,0x82,0xad,0x66,0xa8,0xc1,0x88,0x37,0x49,0x45,0x7b,0xea,0x61,0xfb,0x70,0xfd,0xd9,0xc3,0x18,0x36,0xb4,0x4f,0x93,0xef,0x7b,0xa7,0xb9,0x19,0xd2,0x37,0x8d,0x63,0xf7,0xef,0xc7,0xa8,0xe3,0xf7,0x25,0x14,0xb6,0x99,0xf5,0xd6,0x97,0xfc,0xfd,0x8d,0xcf,0xa9,0xef,0xa4,0x22,0x3e,0xef,0xe4,0x3,0xf8,0xf9,0x59,0x47,0xd0,0xb7,0x47,0xd3,0xa2,0xd3,0x73,0x40,0x4f,0xf6,0x1f,0xd0,0x93,0x93,0xe,0x1a,0xc0,0x8f,0x86,0x1f,0xc4,0x86,0xea,0x3a,0x9e,0xfa,0xf7,0xa7,0x94,0xff,0xf7,0x5b,0x23,0xe2,0x4,0x95,0xbf,0x6e,0x41,0x66,0x41,0xe0,0x28,0xe0,0xa3,0x78,0x85,0x97,0xe6,0xb6,0xb8,0xf5,0xdc,0xe3,0x38,0xf3,0xc8,0x21,0x31,0xdf,0x5b,0x5d,0x1b,0xe2,0x77,0x2f,0xaf,0xe0,0xdd,0x2f,0x37,0x77,0x1a,0xfb,0xd,0xe9,0x9b,0xc6,0x3,0x97,0x9d,0xc2,0x1,0x3,0x7a,0xc6,0x7c,0xef,0xaa,0xb5,0xd5,0xdc,0xf1,0xe2,0xbb,0x6c,0xde,0x1e,0x97,0x13,0x4a,0xd6,0x94,0xe6,0x7b,0xf7,0x37,0xd2,0x35,0x7d,0x5e,0x47,0xf4,0xef,0x95,0x4a,0xc9,0xcf,0x4e,0x73,0x24,0x5c,0x80,0x3e,0x69,0x6e,0xfe,0xf0,0xe3,0x93,0x39,0xff,0x94,0x3,0x3a,0x45,0x7a,0xff,0xef,0xe0,0x1,0xfc,0xf9,0xba,0x11,0x8e,0x84,0xb,0x30,0x6c,0x68,0x1f,0xfe,0x7c,0xfd,0x19,0x51,0xbd,0x13,0x83,0x11,0x6f,0xbb,0xd1,0x23,0xc5,0x45,0xd1,0x15,0xa7,0x72,0xc8,0xa0,0x5e,0x6d,0xa,0xc7,0x65,0x9,0x37,0xf9,0x8e,0xe2,0xfb,0xc3,0x6,0x25,0x75,0x7a,0x87,0xf6,0xeb,0xc1,0x7d,0x97,0x9c,0x4c,0xaa,0xbb,0x6d,0x45,0xa5,0x77,0xaa,0x9b,0xa2,0x2b,0xbf,0xc7,0xa0,0x3e,0x69,0xa6,0x10,0x99,0x3e,0x6f,0x7,0xd4,0x74,0x22,0xfc,0xfa,0xbc,0xe3,0xd9,0xbf,0x85,0x16,0x68,0xe5,0xca,0x95,0x94,0x97,0x57,0xf0,0xce,0x3b,0xef,0xb0,0x61,0xfd,0x6,0x5c,0x2e,0x17,0x43,0x86,0xc,0x61,0xf8,0xf0,0xef,0x31,0x6a,0xf4,0x28,0xe,0x39,0xe4,0x90,0xdd,0xc2,0xbb,0xe3,0xfc,0x13,0xb8,0xe6,0x4f,0x6f,0xb0,0xa1,0xba,0x36,0x29,0xd3,0xfc,0xd0,0x55,0xc3,0x71,0xbb,0x76,0xef,0x5d,0x55,0x55,0x55,0x31,0xe7,0xb5,0x39,0x2c,0x59,0xb2,0x84,0x35,0x6b,0xbe,0x65,0xc7,0x8e,0x1d,0xc,0x1a,0x34,0x90,0xe3,0x8e,0x3b,0x8e,0xb3,0xcf,0x3e,0x9b,0x33,0x46,0x9c,0x81,0x48,0xd3,0x1e,0x59,0x8a,0xcb,0xa2,0xf0,0x8a,0x53,0xf9,0xe5,0x13,0x6f,0x76,0x89,0x81,0x3b,0xd3,0xe7,0xed,0x44,0x7d,0xde,0x63,0xf7,0xef,0x47,0xd1,0x95,0xdf,0x8b,0xfa,0x5d,0x4d,0x4d,0xd,0xf,0xdc,0xff,0x20,0x95,0x95,0x95,0xcd,0x8b,0xdf,0xb2,0x38,0xff,0xfc,0xf3,0xc8,0xc9,0xcd,0xd9,0xed,0xfa,0xea,0x75,0xd5,0xdc,0xf4,0xd7,0xb7,0x93,0xce,0x66,0x37,0x67,0x1c,0xc5,0xf9,0xa7,0x1c,0xb8,0xdb,0xb5,0x67,0x9f,0xfd,0x7,0x4f,0x3e,0xf1,0x24,0xf5,0xf5,0xcd,0xaf,0x5,0x38,0xf1,0xc4,0x13,0xb9,0xf3,0xb7,0xbf,0x61,0xc8,0x90,0xe8,0xdd,0x8a,0x87,0xfd,0x1f,0x33,0x7b,0xd9,0xd7,0xa6,0xcf,0x6b,0xdc,0xe6,0x76,0x72,0x51,0x2c,0xe1,0xf6,0xf3,0xa2,0x6f,0x4c,0xb9,0x65,0xcb,0x16,0xae,0xbb,0xf6,0xfa,0x16,0x85,0xb,0x60,0xdb,0x36,0x2f,0xbf,0x3c,0x9b,0x1b,0x6f,0xf8,0x15,0xb6,0xbd,0xab,0xe5,0x39,0x6c,0x70,0x1f,0xe,0x1f,0xd2,0xbb,0x4d,0xf1,0x73,0x59,0x42,0xfa,0x31,0x43,0xb9,0xe6,0xac,0xc3,0x19,0x7d,0xc2,0x7e,0x51,0x47,0x83,0x63,0x4d,0xef,0xb8,0xff,0xdb,0xbd,0x4f,0x7e,0xef,0x3d,0xf7,0xf2,0xc7,0xc7,0xff,0xd8,0xa2,0x70,0x1,0x56,0xac,0x58,0xc1,0xd5,0x57,0xfd,0x9c,0xcf,0x56,0x7f,0x16,0xf5,0xfb,0x5f,0x79,0x8f,0xa4,0x4f,0x9a,0x71,0xfa,0x8c,0x78,0xdb,0x89,0x21,0xfd,0x7a,0x30,0xb4,0x5f,0x8f,0x26,0xd7,0x6b,0x6b,0x6b,0xc9,0xce,0xca,0x61,0xcd,0x9a,0x35,0xad,0xe,0xeb,0xe3,0x8f,0x3f,0x66,0x72,0xfe,0xe4,0x5d,0xee,0x8f,0x40,0xce,0xe8,0x63,0x1c,0xc7,0xed,0xc8,0xa1,0x7d,0x78,0xf6,0x57,0x67,0xf2,0xeb,0xf3,0x8e,0xe7,0x27,0x23,0xe,0x65,0xd2,0xd8,0x63,0xf9,0xc7,0x4d,0x23,0x19,0x7b,0x92,0xf3,0x6,0xea,0x82,0xef,0x1d,0x84,0xdb,0xda,0xe5,0x98,0x3d,0xf6,0xe8,0x63,0x54,0x54,0xf8,0x5b,0x7d,0x7f,0x6d,0x6d,0x2d,0xe3,0xc7,0xdf,0x4c,0x55,0x55,0x55,0xd4,0xee,0xc7,0xf1,0x7,0xf4,0x37,0x85,0xca,0x88,0xb7,0x7d,0x38,0xfb,0xe8,0xe8,0x2e,0x60,0x69,0x69,0x29,0x5f,0x7e,0xf9,0x65,0xcc,0xe1,0x2d,0x5f,0xfe,0xe,0xff,0xf9,0xcf,0xb2,0x46,0xad,0xaf,0xb3,0x96,0xd7,0x65,0x9,0x45,0x3f,0x1d,0x4e,0xbf,0x9e,0x29,0x4d,0xae,0xe7,0x8e,0x39,0x86,0x81,0xbd,0x53,0x1d,0x85,0x7b,0xe9,0x69,0x7,0x37,0xea,0xe3,0x56,0xf3,0xc2,0xb,0x2f,0xc6,0x1c,0x46,0x4d,0x4d,0xd,0xf,0x3e,0x30,0x35,0xea,0x77,0x3f,0x3b,0xf3,0x30,0x53,0xa8,0x8c,0x78,0xdb,0xa9,0xcf,0x7c,0xe2,0xfe,0x51,0x5b,0x97,0x92,0xe2,0x99,0x8e,0xc2,0x53,0x55,0xee,0xbb,0xf7,0xbe,0xef,0xfe,0x9f,0x96,0xe2,0xc2,0x65,0xc5,0x3e,0x4,0x71,0xf8,0xe0,0x3e,0xbb,0xb5,0x90,0x7b,0xf2,0x93,0x11,0xce,0xf6,0x20,0xef,0xd3,0xc8,0xed,0xbe,0xe7,0x9e,0x7b,0x8,0x87,0xc3,0x8e,0xc2,0x59,0xb4,0x68,0x11,0x9b,0x37,0x37,0x7d,0x9f,0x7d,0xf4,0x7e,0x7d,0x49,0x73,0x9b,0xe2,0x67,0xc4,0x9b,0x68,0x23,0x9,0xec,0x3f,0xa0,0xa9,0xcb,0xbc,0x61,0xfd,0x6,0xc7,0x85,0x1a,0x60,0xeb,0xd6,0xad,0xbb,0x5c,0x67,0xe0,0xe0,0x81,0xb1,0xbf,0x7e,0x3a,0xed,0xf0,0x81,0x2d,0x7e,0x3f,0xc2,0xe1,0xab,0x28,0xab,0xd1,0x68,0xf1,0x7b,0xef,0xbe,0xd7,0x26,0xfb,0xad,0x58,0xb1,0x22,0xea,0xf5,0x54,0xb7,0xcb,0x14,0x2e,0x23,0xde,0xc4,0x92,0xea,0x76,0xed,0x56,0x98,0x77,0xf2,0x85,0x3,0x77,0xb9,0x31,0xa1,0x50,0x88,0xf5,0xeb,0xd7,0xef,0x72,0x9d,0x7,0xf5,0x76,0x54,0xb1,0xb4,0x84,0xd3,0xd7,0x9,0x8d,0xbd,0x80,0x50,0xa8,0x6d,0x5b,0x81,0xbd,0xf5,0x56,0xf4,0x91,0xf4,0x14,0xb7,0x98,0xc2,0x65,0xc4,0x9b,0x58,0x42,0x76,0xf4,0x77,0x92,0x6b,0xbf,0x6d,0xfb,0xe,0x2c,0xdf,0x7c,0xb3,0x6b,0xa0,0x6b,0xc3,0xb6,0xba,0xa4,0x49,0x73,0xe3,0xb9,0xc8,0xb6,0xdd,0xb6,0x77,0xb2,0xdf,0xae,0xf9,0x36,0xea,0xf5,0xb0,0x6d,0xe6,0x3b,0x1b,0xf1,0x26,0x5a,0xbc,0x61,0xa5,0x6a,0x47,0xd3,0xd7,0x23,0x7,0x1c,0xd8,0xf6,0xd7,0x8d,0x7,0x1d,0xb4,0xeb,0x3d,0xea,0xa7,0xeb,0xaa,0x93,0x48,0xbc,0x8d,0xa,0x89,0xd5,0xb6,0x62,0x72,0xe0,0x81,0xd1,0xa7,0x81,0xd6,0x99,0x89,0x1a,0x46,0xbc,0xed,0xc1,0xf2,0x28,0x8b,0x8,0xe,0x3c,0xf0,0xc0,0x36,0x85,0x99,0x92,0x92,0xc2,0x3e,0xfb,0xec,0xf3,0x5d,0x5,0xb1,0xad,0x36,0x79,0x76,0xaa,0xd,0x85,0xed,0xdd,0xe2,0xd9,0x16,0xce,0x18,0x71,0x46,0x93,0x6b,0xdb,0x6a,0x43,0xd4,0xd6,0x1b,0xf1,0x1a,0xf1,0xb6,0x3,0x2f,0x2d,0x6d,0xba,0x79,0xc3,0xe0,0xc1,0x83,0x49,0x4d,0x4d,0x75,0x1c,0xe6,0x4e,0xe1,0x2,0x54,0xd5,0x24,0xd7,0xee,0xa5,0xcb,0x3e,0xdf,0xf4,0xdd,0xdf,0xa7,0x9f,0x7e,0x7a,0x9b,0xc2,0x3a,0xee,0xd8,0xe3,0x9a,0x5c,0xfb,0xe7,0xd2,0x2f,0xcd,0x32,0x41,0x23,0xde,0xf6,0xe1,0x8b,0xd,0xdb,0xa2,0xb6,0x9c,0xb7,0xdc,0x32,0xd9,0x51,0x78,0x22,0xc2,0xdd,0xbf,0x9b,0xf2,0xdd,0xff,0x5f,0x78,0xfb,0xcb,0xa4,0x4a,0xef,0xe3,0xc1,0x4f,0xbe,0xdb,0xb1,0xef,0xd7,0xb7,0xdf,0x86,0xdb,0xed,0x6c,0x46,0xd4,0xd8,0x71,0x63,0xe9,0xd7,0xbf,0x5f,0x93,0xeb,0xe5,0xef,0x7f,0x6b,0xa,0x95,0x11,0x6f,0xfb,0x50,0x5d,0x1b,0xe2,0xc9,0x7f,0xaf,0x6e,0x72,0xfd,0xec,0x73,0xce,0xe6,0xb8,0xe3,0x8e,0x8b,0x39,0xbc,0xb3,0xcf,0x3e,0x9b,0x63,0x8e,0x89,0xcc,0xaa,0xaa,0xa9,0xf,0xf3,0x62,0x92,0x89,0xf7,0x9b,0x2d,0x35,0xac,0xd9,0xbc,0x3,0x80,0xb4,0xb4,0x34,0xae,0xbf,0xfe,0xba,0xa8,0x8b,0xd,0x5a,0xa2,0x7f,0xff,0xfe,0x64,0x65,0x35,0x3d,0x36,0x6a,0xc5,0x57,0x9b,0x59,0x5b,0x55,0x63,0xa,0x95,0x11,0x6f,0xfb,0x31,0x7b,0xd9,0x57,0x4d,0xfa,0x69,0x29,0x29,0x29,0x4c,0x2d,0x78,0x90,0x61,0xc3,0x86,0xb5,0x3a,0x9c,0xe1,0xc3,0x87,0x33,0xe5,0xee,0x5d,0x3b,0x97,0x3e,0xe2,0xff,0x24,0x29,0xd3,0xfb,0xeb,0x17,0xde,0xf9,0xce,0xb5,0xbd,0xfc,0x27,0x97,0x73,0xd1,0x8f,0x2e,0x6a,0xb5,0x80,0xfb,0xf5,0xeb,0xc7,0xa3,0x8f,0x3d,0x42,0xcf,0x9e,0x4d,0x57,0x60,0x3d,0x38,0xf7,0x43,0x8c,0xc7,0x6c,0xc4,0xdb,0xae,0x6c,0xaf,0xb,0x73,0xcb,0xf3,0xcb,0x9a,0x5c,0xef,0xd5,0xab,0x17,0xf,0x3d,0x3c,0x93,0xb,0x2e,0xbc,0xa0,0xc5,0xfb,0x53,0x52,0x52,0xb8,0xfa,0xea,0xab,0x98,0x5a,0xf0,0xe0,0x77,0xd7,0xde,0xfc,0x74,0x3,0xa5,0x2b,0x92,0xf3,0x48,0xd9,0x35,0x5b,0x6a,0x78,0x7a,0xf1,0x67,0xdf,0xfd,0x3f,0x2b,0x6b,0x2,0x93,0xf2,0x27,0xd1,0xb7,0x6f,0xdf,0x16,0xef,0x3b,0xeb,0xac,0x91,0x3c,0xfd,0xb7,0xbf,0xb2,0xef,0xbe,0xfb,0x36,0xf9,0x6e,0xc6,0xfc,0x95,0xac,0xdd,0x6a,0x5a,0xdd,0x78,0x60,0x96,0x76,0xc4,0xc8,0xca,0x35,0x55,0x14,0xcc,0xfd,0x90,0xfc,0x71,0xc7,0xee,0x76,0x3d,0x35,0x35,0x95,0xdc,0xdc,0x1c,0xae,0xb8,0xe2,0xa,0x2a,0xca,0xcb,0x59,0xb6,0x7c,0x79,0xa3,0xf5,0xbc,0x83,0x39,0xed,0xf4,0xd3,0xc9,0xc8,0xf0,0xd1,0xbf,0xff,0xae,0x9,0xf9,0xab,0xd7,0x55,0xf3,0xdb,0x97,0xde,0x4b,0xea,0xf4,0x3e,0xbb,0xe4,0x73,0xe,0x1d,0xd4,0xb,0xcf,0xb1,0x11,0x21,0xfe,0xf0,0x87,0xe3,0x18,0x33,0x66,0x34,0xfe,0xa,0x3f,0x8b,0x17,0x2f,0xde,0x6d,0x3d,0xef,0xf1,0xc7,0x1f,0xcf,0x39,0xe9,0xe7,0x70,0xf4,0xd1,0x47,0x47,0xd,0xeb,0x95,0x65,0x5f,0x33,0xef,0xbd,0x6f,0x4c,0x21,0x32,0xe2,0xed,0x38,0xca,0xff,0xbb,0x86,0xaa,0x9a,0x7a,0xee,0xbc,0xf0,0x4,0xdc,0x7b,0xbc,0x3,0xdd,0x77,0xdf,0xa1,0x5c,0xf9,0xd3,0x2b,0xb9,0xf2,0xa7,0x57,0xb6,0x18,0xc6,0x82,0x95,0x6b,0xf9,0xc3,0x6b,0xff,0x6d,0x73,0x5c,0xf6,0x36,0xcf,0x21,0x1e,0xee,0xe9,0xfd,0xaf,0x7d,0xc0,0xd7,0x9b,0x76,0x70,0xe5,0xf7,0xf,0x43,0x4,0xdc,0x6e,0x37,0x63,0x32,0xc7,0x30,0x26,0x73,0x4c,0xab,0xc3,0xf8,0x53,0xe5,0x2a,0x5e,0x5c,0xfa,0xa5,0x71,0x97,0x8d,0xdb,0xdc,0xf1,0xbc,0xf1,0xe9,0x6,0x7e,0xf1,0x97,0x37,0x59,0xb2,0x6a,0x7d,0x4c,0xf7,0x6d,0xd9,0x51,0x4f,0x51,0xd9,0x4a,0xee,0x7b,0xf5,0xbf,0x71,0x29,0xc8,0x6f,0xad,0xde,0xd8,0xe2,0xf7,0x4b,0x3e,0xdd,0x10,0x97,0xf4,0x3e,0xbd,0xf8,0x33,0x7e,0xfb,0xd2,0xbb,0x7c,0x1e,0x65,0xd4,0xbd,0x25,0x3e,0x5a,0x53,0xc5,0xe4,0xe7,0x96,0xf3,0xc2,0xdb,0x46,0xb8,0xa6,0xe5,0x4d,0xb2,0x3e,0xe1,0x94,0x7f,0xad,0xe0,0x84,0x3,0xfb,0x33,0xfa,0x84,0xfd,0xf8,0xfe,0xb0,0x41,0xc,0xe8,0x95,0x1a,0xa5,0x75,0x54,0x56,0x7c,0xb5,0x85,0x45,0x9f,0xac,0xe7,0xd5,0xe5,0x5f,0xc7,0x75,0x5a,0xe0,0x67,0xeb,0xab,0x9,0xd9,0xda,0xec,0xca,0xa2,0xe7,0xde,0xf8,0x3c,0x6e,0xcf,0x7a,0x6b,0xf5,0x46,0xde,0x5a,0xbd,0x11,0xdf,0x71,0xfb,0x72,0xf6,0xd1,0x43,0x38,0xfd,0xf0,0x81,0xb8,0x5d,0x4d,0xeb,0xff,0xda,0x50,0x98,0xb7,0x3e,0xdd,0x48,0xe5,0xca,0xb5,0xfc,0xfb,0xe3,0x75,0x46,0xb4,0x46,0xbc,0xc9,0xcb,0xfb,0x5f,0x6f,0xe1,0xfd,0xaf,0xb7,0x20,0x22,0x1c,0xb4,0x4f,0x4f,0x6,0xf7,0x49,0x63,0x60,0x9f,0x5d,0x9b,0xae,0xff,0x6f,0xd3,0xe,0xaa,0x13,0x34,0x7b,0x2a,0x6c,0x2b,0xb9,0xcf,0x2c,0xe5,0xbe,0x1f,0x9f,0xbc,0xdb,0x9a,0xde,0xb0,0xad,0x94,0x94,0x7f,0xc4,0xc6,0x4,0xcc,0x97,0xf6,0x7f,0xf0,0x2d,0xfe,0xf,0xbe,0xc5,0xed,0x12,0xe,0x19,0xd8,0x9b,0x41,0x7d,0xd2,0x18,0xd0,0x2b,0x85,0x4d,0xdb,0xeb,0xd8,0x50,0x5d,0xcb,0x17,0x1b,0xb6,0x9b,0x79,0xcb,0x46,0xbc,0x9d,0xb,0x55,0xe5,0xcb,0x8d,0xdb,0xf9,0x72,0xe3,0xf6,0x76,0x7d,0xee,0x27,0x6b,0xab,0xb9,0xe2,0xd1,0xc5,0x8c,0x3c,0x6a,0x8,0x87,0xe,0xea,0xc5,0x37,0x5b,0x6a,0x78,0x63,0xd5,0x7a,0xaa,0x6a,0x12,0x3b,0xdd,0x32,0x14,0x56,0x3e,0x5d,0x57,0x9d,0x54,0x73,0xb2,0x8d,0x78,0xd,0x9d,0x8e,0xb0,0xad,0x2c,0x58,0xb9,0xd6,0x18,0xa2,0x1b,0xd1,0x9d,0x6,0xac,0xc2,0x26,0xbb,0xd,0x46,0xbc,0x9d,0x90,0xd2,0x7c,0xef,0xa7,0x88,0x1e,0x2,0x92,0xf,0xbc,0x69,0xb2,0xbe,0x53,0xb2,0x4,0xf8,0x9d,0x31,0x43,0x84,0x2e,0xb9,0x95,0xc1,0x98,0x82,0xc0,0x71,0x67,0x56,0x57,0x7e,0x38,0x65,0xca,0x94,0x66,0x47,0x4d,0x32,0xa7,0xf9,0xf,0x43,0xe5,0x77,0xc0,0x55,0xa6,0x18,0x24,0x3d,0x4f,0x22,0x3a,0xa5,0x74,0x92,0xef,0x73,0x63,0x8a,0x2e,0x2c,0xde,0xe1,0x8f,0xbd,0x2d,0x83,0xab,0xaa,0xd6,0x3,0x75,0xc0,0xf3,0x82,0xce,0x9a,0x97,0xef,0xfb,0x77,0xb4,0xdf,0xfe,0xb0,0xa0,0x22,0x2d,0x8c,0xb5,0x9,0xe8,0x69,0x8a,0x42,0xd2,0xb2,0xdd,0x85,0xbd,0xcf,0x9c,0xfc,0x8c,0xa8,0xc3,0xe6,0x63,0xb,0xfc,0x67,0x2b,0x72,0x19,0xb0,0xb0,0x34,0xdf,0xfb,0xbc,0x11,0x6f,0x27,0x66,0x6c,0x41,0x60,0x90,0xc2,0x9e,0x33,0x27,0xbe,0x6,0x66,0x21,0x3c,0x5f,0x3a,0xc9,0xfb,0xfa,0x6e,0x2d,0x70,0x41,0xe0,0x7d,0xe0,0xf8,0xbd,0x4,0xbb,0xe,0xf8,0x17,0x70,0x0,0x70,0x6a,0xc3,0xbf,0x6,0x67,0x7c,0xd,0x2c,0x3,0xbe,0x1,0x2e,0x6,0xf6,0xb6,0x43,0xde,0x8a,0xd2,0x7c,0xef,0x49,0xbb,0x7b,0x4d,0x81,0x33,0x51,0x2e,0x3,0x2e,0x3,0x76,0x6e,0x67,0x32,0xa3,0x34,0xdf,0x9b,0xdb,0x9d,0xc,0xd9,0xf5,0x46,0x9b,0x95,0x81,0x51,0xaa,0xa4,0x3,0x81,0x5c,0x94,0xdc,0xcc,0x82,0xc0,0x82,0xd2,0x7c,0x6f,0x7a,0x2c,0x35,0x3f,0xb6,0x7d,0x7c,0xe9,0x2d,0x19,0xeb,0x1b,0x15,0x9e,0xa1,0xa8,0x9c,0xa,0x7a,0x2a,0x70,0x72,0x83,0xa0,0x8f,0x31,0xba,0x6c,0xc2,0xca,0x6,0xa1,0x2e,0x7,0x59,0x86,0xe8,0xf2,0xd2,0x49,0xde,0xb5,0xbb,0x2a,0xda,0xe0,0x6f,0x14,0xfd,0x1c,0xe8,0xd1,0xda,0x0,0x33,0xb,0x2,0x8b,0x51,0x7e,0x10,0xe5,0xab,0xe3,0xba,0x9b,0x71,0xbb,0x9c,0x78,0x55,0xf6,0x5a,0x10,0xf6,0x89,0x31,0xc8,0xf5,0x8d,0x85,0xb,0xd0,0x50,0x0,0x4b,0x1b,0x3e,0x0,0x9c,0xfb,0xc0,0x82,0x5e,0xf5,0x2e,0xfb,0x14,0x89,0x8,0xfa,0x94,0x6,0x41,0x9f,0x4,0xa4,0x76,0x83,0x72,0x54,0x7,0xbc,0x1b,0x11,0x29,0xcb,0x14,0x59,0x9e,0x12,0xb6,0x96,0xbf,0x76,0xeb,0x39,0x2d,0xbe,0xf0,0x9e,0x97,0xef,0x59,0x9b,0x59,0x10,0xd8,0x18,0xa3,0x27,0x33,0xa0,0x99,0xeb,0x46,0xbc,0x5d,0x80,0x78,0x8b,0xa5,0x55,0x53,0x85,0x1a,0xa,0xea,0xe2,0x86,0xf,0x0,0x23,0xff,0xf8,0xa6,0xab,0xef,0xd6,0xed,0x27,0xa8,0xad,0xa7,0x21,0xdc,0xe,0xc,0xeb,0x42,0x76,0xfe,0x4,0xe5,0x5e,0xb1,0x64,0xe9,0xe6,0x81,0x7d,0xde,0x5f,0x72,0xed,0x69,0x76,0x22,0xed,0xdb,0xa,0xe,0x3a,0x7f,0xca,0x6c,0x79,0x65,0xca,0x5,0x6a,0xc4,0xdb,0x79,0xdb,0xde,0xed,0x89,0xec,0xca,0x67,0x16,0x4,0xc6,0x3,0x35,0x8,0xcb,0xd4,0xae,0x5b,0x51,0x36,0x39,0xb3,0xd9,0xcd,0xa7,0x16,0xfd,0xf2,0x8c,0x70,0x43,0x8b,0xf4,0x6e,0x66,0x41,0xe0,0x65,0x9a,0xf6,0xc5,0x5b,0x5b,0xb8,0x3f,0x4,0xb6,0x37,0x8c,0x51,0x48,0xa3,0xf1,0x8a,0x3d,0xff,0x96,0x3d,0x4,0xa1,0x7b,0xf9,0xbb,0x57,0x1b,0x5a,0xac,0xd3,0x4a,0x27,0x7b,0xb7,0xb4,0xe6,0x87,0x63,0xa6,0x96,0xa6,0x88,0x95,0x7a,0x12,0xca,0x29,0x40,0x5a,0x69,0xbe,0xf7,0x91,0x4,0x64,0xcd,0x86,0xee,0x24,0xdc,0x2e,0xda,0xe7,0x95,0xaa,0x84,0xe,0xc3,0x9,0x3f,0x46,0xf1,0xa2,0x20,0x92,0x1a,0xca,0x2c,0x8,0xac,0x68,0xdc,0xaf,0x73,0x11,0x5e,0x3e,0x27,0x3f,0xa3,0xc9,0xe9,0x5a,0x6a,0x6b,0x95,0xc4,0x7e,0x9c,0x89,0xa2,0x7a,0x59,0xe9,0x64,0xdf,0xb,0x89,0xab,0x8c,0x82,0x57,0x80,0x3e,0x43,0x8c,0x35,0x9e,0xda,0x1a,0xd5,0x25,0xfe,0x61,0x41,0x45,0xbf,0x30,0xae,0x93,0x1b,0xc6,0x3,0x76,0x7e,0x4e,0x40,0x1b,0xca,0x9a,0x50,0x1,0x24,0x42,0xbc,0x9f,0x19,0xb7,0xb9,0xb3,0x23,0x5a,0xdd,0x8e,0x83,0xe8,0xee,0x86,0xfe,0xed,0x29,0x3b,0xb5,0x16,0xc6,0xd2,0xcc,0x82,0xc0,0xaa,0x6,0x41,0xcf,0x29,0xcd,0xf7,0x3e,0x19,0xf9,0x46,0x9c,0xc4,0xaa,0x36,0x91,0xc2,0x5,0x28,0xcd,0xf7,0x3c,0x9b,0x59,0x10,0x78,0xa,0x48,0x89,0xad,0x56,0x91,0xc6,0xde,0xc8,0x75,0xc0,0x38,0xe0,0xd4,0x30,0x1c,0x1,0xda,0x11,0x6f,0x31,0x56,0x1b,0xf1,0x76,0x72,0xc2,0xa1,0xf0,0x56,0x97,0x3b,0x65,0x3,0x68,0x6b,0xf,0xe9,0x29,0x7,0xe,0x6b,0x70,0x21,0xe3,0xd3,0x36,0xc3,0x91,0xd,0x9f,0xfd,0x80,0x27,0x13,0xdd,0xdf,0x4e,0x2,0x6e,0x0,0x46,0x24,0x20,0xdc,0x6d,0xd,0xf9,0xd3,0x1a,0x8f,0xeb,0xd,0x23,0xde,0x4e,0x4e,0xf9,0x6d,0xa3,0xed,0xcc,0x82,0xc0,0xdf,0x80,0x9c,0xd6,0xb5,0x3c,0xde,0x9c,0xd1,0x33,0x17,0xde,0xe2,0xda,0x11,0x1a,0xab,0xc2,0xc5,0xc0,0x5,0x34,0x3f,0xa2,0xd9,0xa1,0x64,0x16,0x4,0xb2,0x81,0xf3,0x1a,0xf5,0x59,0x9b,0xfb,0x58,0x2d,0xf4,0x89,0x5,0x98,0x5d,0x9a,0xef,0x9d,0x99,0xa4,0x59,0xb8,0x19,0x78,0x59,0x94,0x7f,0x86,0x7a,0xb9,0xe7,0x95,0xdf,0x7c,0x76,0x5d,0x94,0xca,0x31,0x9a,0xc7,0x55,0x6e,0xc4,0xdb,0x25,0xfa,0xbd,0xbc,0x84,0x34,0x2b,0xde,0x3,0x2f,0x9d,0xbe,0xd8,0x35,0x6b,0xe2,0x99,0xdf,0x2d,0x54,0x98,0x3f,0xe1,0xec,0x5a,0xe0,0x65,0xe0,0xe5,0x71,0x5,0xe5,0x6e,0x5b,0xdc,0x19,0xa8,0x5e,0x2,0x5c,0x98,0x64,0x29,0x3b,0x16,0x18,0x1d,0x87,0x70,0x56,0x26,0x59,0xba,0xd6,0x2,0x2f,0x21,0xf2,0x4f,0x4b,0x43,0xfe,0xb9,0xf9,0xa3,0xa2,0xae,0x65,0xbc,0x74,0xfa,0x62,0xf7,0x56,0xbb,0x76,0xdf,0x66,0xfc,0x9d,0x4f,0x8d,0x78,0xbb,0x42,0xb7,0xd7,0xe2,0xc3,0x16,0x76,0x6f,0x18,0xb8,0xd5,0xae,0x7d,0x27,0xb3,0x20,0x70,0x57,0xc8,0x1d,0x9e,0x53,0x91,0x3b,0x6a,0x47,0xe3,0x2f,0x1b,0xa,0x4e,0x29,0x50,0x3a,0x66,0x5a,0xe5,0x4d,0xa2,0xf6,0x29,0x18,0x12,0xc9,0x85,0x2a,0xd6,0xf2,0xb2,0x49,0xe9,0xcd,0xae,0xfa,0xca,0x2c,0x5c,0xd0,0x8b,0x70,0xf8,0xdc,0xad,0x76,0xed,0xef,0x88,0xfe,0x9e,0x3e,0x50,0x3a,0xc9,0x5b,0x65,0xc4,0xdb,0x5,0x98,0x37,0xc9,0xfb,0xed,0x98,0xa9,0x81,0x7f,0x88,0xf0,0x93,0x66,0x7e,0x72,0x2,0xf0,0x82,0x3b,0xe4,0xaa,0xc9,0x2c,0x8,0xcc,0x5,0xfe,0x69,0xdb,0xd6,0xec,0xf9,0xb7,0xa4,0x6f,0x6d,0xfc,0xa3,0x86,0x2,0xb5,0xd4,0xe8,0x2b,0x71,0x94,0xe6,0x7b,0xa3,0xda,0x77,0xec,0x3,0xfe,0x1,0xea,0x92,0xb,0x80,0x8b,0x9,0x87,0xc7,0x2,0x69,0xcd,0xd7,0xd6,0x72,0x57,0x77,0xb4,0x5d,0xd7,0x5d,0x8c,0x6f,0x71,0x2f,0xda,0xac,0x78,0x77,0xd2,0x3,0xf8,0x11,0xf0,0x23,0xcb,0xb2,0xeb,0x33,0xb,0x2,0x15,0xc0,0x3f,0x71,0xd9,0xff,0x2a,0xcd,0xcb,0x58,0xd7,0x8c,0x4b,0x6e,0x4e,0x84,0x6e,0x5b,0x97,0xa6,0xd9,0x32,0x37,0x66,0xaa,0x7f,0x5f,0x11,0xb9,0x10,0xb8,0x44,0xc1,0xd7,0xca,0xf2,0xf9,0xd,0xe1,0xf0,0x1b,0x46,0xbc,0x5d,0x88,0xba,0x2a,0xde,0x4f,0xeb,0xcd,0x9b,0x8,0x67,0xb4,0xf2,0x96,0x14,0x60,0x2c,0x30,0x96,0xb0,0xf5,0x48,0x66,0x41,0x60,0xa1,0x20,0xff,0xc,0xdb,0xe1,0x7f,0xcd,0xbf,0x25,0xe3,0x4b,0x80,0x31,0xd3,0x2,0xbd,0x51,0x67,0xa3,0xaa,0x16,0xe1,0x30,0xb8,0x4a,0x80,0x23,0x88,0xcc,0xb4,0x1a,0x46,0x8c,0xaf,0x67,0x3a,0xda,0xa4,0xc0,0xa7,0xc0,0x2a,0x60,0x55,0x24,0x3d,0x8e,0x18,0x31,0x66,0x5a,0xa0,0x67,0xd9,0x24,0xef,0xe,0x80,0xb1,0x5,0xfe,0x43,0xc0,0xba,0x48,0xd1,0x4b,0x80,0x91,0x10,0x73,0xe5,0x98,0x53,0x7a,0x4b,0x46,0x9d,0x11,0x6f,0x17,0x22,0x38,0xc5,0xab,0x63,0xb,0x2,0x13,0xd4,0xd9,0xc2,0x7b,0x17,0xe0,0x51,0xd4,0x63,0x59,0x56,0x51,0x66,0x41,0xe0,0x2d,0xe0,0x6d,0x94,0x73,0x5a,0x74,0xdf,0x5a,0x72,0xf,0x6f,0x19,0x15,0x6,0xb2,0x77,0xb5,0x32,0xa5,0x62,0x91,0x76,0x30,0xe8,0x91,0x2a,0xdf,0x89,0x79,0xa7,0xb0,0x8f,0x4,0xfa,0x75,0x80,0xd9,0xb6,0xec,0x14,0xe7,0xce,0x8f,0x28,0xab,0x40,0x56,0xd9,0xd4,0x7e,0x59,0x36,0x39,0x33,0x1e,0xaf,0xae,0x7a,0x88,0xf2,0x7a,0x66,0x41,0xe0,0xdf,0xc0,0xe9,0xa,0xa7,0xb7,0xe1,0xbd,0xf0,0xd7,0x22,0xcc,0xe9,0xae,0x4e,0x4c,0x97,0xde,0xc3,0x6a,0x5e,0xbe,0xf7,0xad,0xcc,0x82,0xc0,0x43,0xc0,0xcd,0x6d,0x72,0xc0,0x23,0xef,0x30,0x9d,0xb4,0xb8,0x87,0x35,0xf7,0x45,0x83,0x10,0xbe,0x68,0xf8,0xf8,0xf7,0xfc,0x7e,0xdc,0xb4,0x8a,0xc1,0xb6,0x6d,0x1d,0xde,0x4e,0xae,0xec,0x48,0x97,0x15,0x5e,0x3d,0x67,0xd2,0xa8,0xf5,0xe,0x43,0x38,0x34,0xc6,0xdf,0x9f,0xdc,0xf0,0x69,0x13,0x2,0x3f,0x9a,0x37,0xc9,0xbb,0xcd,0x88,0xb7,0xab,0x22,0xfa,0x1b,0x54,0x2e,0x7,0x6,0x77,0xc0,0xd3,0xf,0xcc,0x2c,0x8,0x3c,0x24,0xe8,0x5f,0xc4,0xd6,0x55,0x73,0x6f,0xc9,0xd8,0xdc,0xda,0x1b,0xe7,0x4e,0xca,0x58,0x8f,0xb3,0xb9,0xd0,0xb1,0x7b,0x5,0x93,0xbd,0x6f,0xc5,0x7a,0xcf,0xb8,0x7,0x2b,0x6,0xa8,0x25,0xc3,0x14,0xf9,0x25,0x30,0xb4,0xdd,0xb3,0x15,0x1e,0x9a,0x97,0x1f,0x7b,0xbc,0x8d,0x78,0x3b,0x11,0xa5,0x93,0x7c,0x9b,0xc7,0x16,0x4,0x2f,0x51,0xb4,0xb2,0x3,0x1e,0x6f,0x1,0xe3,0x15,0x19,0xaf,0x96,0x90,0x59,0x10,0xd8,0xb0,0xbb,0x5b,0x2a,0x9f,0xaa,0xe8,0x2a,0xcb,0x96,0x55,0xf3,0x26,0x7b,0xbe,0x6e,0x45,0x78,0x7,0xc5,0x29,0x5e,0x7,0xb7,0xe6,0x47,0x63,0xa7,0x6,0xf,0xb4,0x2d,0x1d,0x26,0x2a,0xc3,0x40,0x77,0x73,0xed,0xed,0xbd,0x2f,0xa2,0x4f,0x24,0x5f,0x28,0x7a,0x3b,0xdd,0x1c,0xe9,0x2e,0x9,0xcd,0x2c,0x8,0x4c,0x0,0x4a,0x92,0x38,0x8a,0x35,0x7b,0xf4,0x37,0x3f,0x5,0x56,0x89,0xe8,0x2a,0xf7,0xb6,0x1d,0x9f,0xd5,0xf7,0xea,0x95,0x9,0xcc,0x8e,0xe3,0xf3,0xce,0x4d,0xd9,0xb6,0xad,0x3c,0xd4,0xa7,0xd7,0x61,0xaa,0xb2,0x53,0x98,0x7b,0xf6,0xbd,0x7b,0x24,0xa1,0x9d,0xb6,0xab,0x70,0x7c,0xd9,0x24,0x6f,0xb7,0xdf,0xcf,0xaa,0xdb,0xec,0xdb,0xac,0x5a,0xf7,0x90,0x48,0xea,0xb1,0x6d,0xec,0xff,0x26,0x92,0x1e,0x44,0xde,0x3f,0x9f,0xb0,0x7b,0xbc,0x85,0xfa,0x5e,0xbd,0x12,0xf1,0xbc,0xd7,0xea,0x7b,0xf7,0xee,0x3c,0xb3,0xa7,0x77,0x91,0x61,0x84,0xbb,0xcb,0xad,0xeb,0x16,0x94,0x4d,0xce,0x54,0x4b,0xac,0x89,0xc0,0xab,0x26,0xdb,0x3b,0x6d,0x15,0x7c,0x65,0x69,0xbe,0x77,0x89,0xb1,0x43,0x37,0x13,0x2f,0xc0,0xdc,0x49,0xe9,0x75,0xaa,0xfa,0x63,0xe0,0x19,0x93,0xf5,0x9d,0x4b,0xb5,0xa2,0x72,0x69,0x69,0xbe,0xef,0x59,0x63,0x8a,0x6e,0xd8,0xe7,0x6d,0xcc,0xd8,0xc2,0x80,0x5b,0xc3,0x14,0x2,0x13,0x4c,0x11,0x48,0x7a,0xea,0x5,0xcd,0x9c,0x97,0xef,0xb,0x18,0x53,0x74,0xe3,0x96,0x77,0x27,0xf3,0xf2,0xbc,0xa1,0x70,0x28,0x94,0x83,0x70,0xa7,0x29,0x2,0x49,0xcd,0x7a,0x90,0x11,0x46,0xb8,0xa6,0xe5,0x8d,0x4a,0x66,0x41,0xc0,0xb,0xcc,0xa2,0x63,0x5f,0x7d,0x18,0x9a,0x52,0x66,0x69,0xf8,0x27,0x73,0x27,0x8f,0xda,0x64,0x4c,0x61,0x5a,0xde,0xa8,0x94,0xe6,0x7b,0x3,0x60,0x1f,0xb,0x54,0x98,0xe2,0x90,0x34,0xfc,0xd6,0xb2,0xed,0x1f,0x1a,0xe1,0x9a,0x96,0xb7,0x75,0x2d,0xf0,0xf4,0x80,0x1b,0x25,0x7,0xe5,0x5e,0x1c,0xce,0x5f,0x36,0xb4,0x99,0xf7,0x11,0xb9,0xa1,0x74,0x92,0x67,0xb1,0x31,0x85,0x11,0x6f,0xcc,0x8c,0x79,0xb0,0x62,0x3f,0xb1,0xac,0x87,0x89,0x2c,0x15,0x34,0xb4,0xf,0xf5,0xc0,0x9d,0xaa,0x3a,0xbd,0x6c,0xb2,0xaf,0xde,0x98,0xc3,0x88,0xd7,0x31,0xc3,0x1f,0x7b,0x5b,0x6,0x55,0x55,0x9d,0x2b,0x50,0x44,0xd7,0xda,0x28,0x3d,0x19,0xf9,0x97,0x4b,0xf4,0xe6,0x39,0x93,0x7c,0xff,0x33,0xa6,0x30,0xe2,0x8d,0x5f,0x2b,0x3c,0x35,0xe0,0x16,0xf8,0x39,0xc2,0x6f,0x68,0x61,0x85,0x90,0xc1,0x11,0x73,0x10,0xbd,0xab,0x74,0x92,0xef,0x6d,0x63,0xa,0x23,0xde,0xc4,0xf5,0x87,0x1f,0xac,0x48,0xc1,0xb2,0xae,0x5,0x7e,0x43,0x2b,0x27,0xf5,0x1b,0x9a,0xa5,0x14,0xd5,0xbb,0x4a,0x27,0xfb,0xde,0x30,0xa6,0x30,0xe2,0x6d,0x37,0x7e,0x38,0xbd,0xd2,0x1d,0xb6,0xed,0x1f,0x1,0xe3,0x1,0x8f,0xb1,0x48,0xab,0xa9,0x5,0x9e,0x12,0xe1,0xe1,0x79,0x93,0xbc,0xef,0x18,0x73,0x18,0xf1,0x76,0x6c,0x6b,0x5c,0x10,0x3c,0x1e,0x74,0x3c,0x70,0x2d,0xf1,0xdb,0xb0,0xbd,0xab,0xf1,0x1,0x22,0x8f,0xa6,0xaa,0xfc,0xf9,0x95,0xfc,0xf4,0x6d,0xc6,0x1c,0x46,0xbc,0x49,0xc5,0xa8,0xfb,0x2b,0xd2,0xac,0x14,0xeb,0x2,0x89,0x1c,0xf6,0x7c,0x3e,0xe6,0x35,0xd3,0x17,0xc0,0x2c,0x54,0x9e,0xaf,0x75,0xeb,0x5b,0xc1,0x3c,0xaf,0x9a,0x52,0x62,0xc4,0x9b,0xf4,0x9c,0xfb,0x40,0x69,0x8f,0x90,0x2b,0xe5,0x42,0x90,0xcb,0x80,0x31,0x40,0x9f,0x6e,0x92,0xf4,0x55,0xc0,0x6c,0x11,0x66,0xa5,0x28,0x4b,0x5e,0xc9,0x37,0x82,0x35,0xe2,0xed,0xc4,0x8c,0x29,0x8,0xb8,0x40,0xbe,0x2f,0xe8,0x28,0x22,0xa7,0x1c,0x9c,0xd9,0x85,0xec,0xbd,0x99,0xc8,0x8c,0xb4,0xf9,0x8a,0x5d,0x5e,0x96,0x9f,0xb1,0xca,0xe4,0xb8,0x11,0x6f,0xd7,0x15,0xf3,0x3,0x15,0x7d,0x2c,0x97,0x9c,0xa3,0x30,0x1c,0xe4,0x34,0xe0,0x34,0x62,0x3b,0x11,0xbe,0xa3,0x50,0x60,0x5,0xb0,0x54,0xe1,0x6d,0xd0,0x37,0x51,0xd7,0xd2,0xb2,0xc9,0xe9,0xb6,0xc9,0x55,0x23,0xde,0x6e,0xcb,0xb8,0x69,0x95,0xfb,0x87,0x55,0x4f,0x13,0xf4,0x24,0x22,0xdb,0xbd,0x1e,0xdd,0xf0,0xef,0xbe,0x1d,0x10,0x1d,0x9b,0xc8,0xd6,0x3b,0x1f,0x3,0x1f,0xa3,0x7c,0xac,0x22,0xff,0x9,0xa5,0xda,0xff,0xf1,0x67,0xfb,0x6a,0x4c,0x6e,0x19,0xf1,0x1a,0x5a,0x41,0xe6,0xf4,0xca,0x7e,0x12,0xb6,0x8f,0x52,0xe4,0x10,0x2c,0x86,0xa2,0x3a,0x14,0x18,0x42,0x64,0x97,0xc6,0xa1,0x44,0x56,0x40,0xf5,0x88,0xf2,0x49,0x6d,0x68,0x29,0x6b,0xa2,0x7c,0xb6,0x1,0xeb,0x88,0x1c,0xea,0xb5,0x16,0x64,0x1d,0xe8,0x5a,0x15,0x59,0x6b,0x61,0xaf,0xaa,0xdb,0x6e,0xad,0xf2,0xdf,0xe9,0x9,0x1b,0xeb,0x1b,0xc,0x1d,0xc0,0x8f,0x9f,0x9f,0x65,0x19,0x2b,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x43,0xdb,0xe9,0x90,0x9d,0x34,0x32,0x32,0x32,0xd2,0x34,0xac,0x67,0xa8,0x70,0x0,0x36,0x43,0x91,0xef,0x76,0x89,0xe8,0xd,0x54,0x3,0x55,0x91,0x8f,0x6c,0x11,0xf4,0x23,0x1b,0x79,0x3f,0x18,0xac,0xf8,0xb2,0x3d,0xe3,0xe8,0xf5,0x78,0xf,0x4,0x4e,0x7,0x6b,0x28,0xe8,0xce,0xf8,0xd,0x24,0xb2,0xf9,0xda,0x5a,0x60,0x1d,0xe8,0x5a,0x84,0x77,0x3,0x81,0xc0,0x27,0x89,0x8a,0x87,0xc7,0xe3,0x11,0xa0,0x7f,0xc,0xb7,0xd4,0x4,0x83,0xc1,0xa4,0xde,0xb6,0xc6,0xe3,0xf1,0xec,0x23,0xc8,0xf,0xc0,0xda,0xf,0xbe,0xdb,0x25,0x64,0x8,0x91,0xdd,0x3e,0x1a,0xdb,0x76,0xa5,0xcb,0xe5,0x7a,0xaf,0xbc,0xbc,0x3c,0x2e,0xfb,0x65,0xa5,0xa7,0xa7,0xf7,0x17,0x91,0x76,0x2b,0xf3,0x22,0x12,0xa,0x4,0x2,0xd5,0x9d,0x5e,0xbc,0xe9,0xe9,0x19,0x47,0x59,0x62,0x8f,0x5,0xc9,0x4,0xbc,0xc4,0xbe,0x51,0xf9,0x56,0x60,0x39,0xf0,0x32,0xa2,0x2f,0x4,0x2,0x81,0x2f,0xe2,0x19,0xbf,0x73,0xce,0x19,0xe3,0x72,0x5b,0x21,0xaf,0x42,0x26,0x30,0x16,0x38,0x31,0x86,0xdb,0x57,0x1,0x65,0x8,0xa5,0x5b,0xb7,0x6e,0x79,0x65,0xe9,0xd2,0xa5,0x6d,0x2e,0x6c,0x5e,0xaf,0xd7,0x85,0xca,0x3,0xc0,0xd,0x40,0xdf,0x18,0x6f,0xdf,0x1,0x6c,0x6a,0xf4,0xf9,0x0,0x58,0x8c,0xe8,0xa2,0x40,0x20,0xf0,0x71,0x47,0x8,0xd6,0xe7,0xf1,0x9d,0xae,0x30,0xae,0xc1,0xb6,0x23,0x68,0xfd,0xd9,0xd0,0xdf,0x2,0xf3,0x11,0xca,0x6c,0x3b,0xfc,0x52,0x65,0x65,0xa5,0x23,0x31,0x78,0x3d,0xbe,0xd7,0x80,0x1f,0xb6,0x73,0xb2,0x15,0xc8,0x9,0x4,0xfd,0x25,0x9d,0x52,0xbc,0x5e,0x4f,0xc6,0xb1,0xa0,0x7f,0x0,0x2e,0x8a,0x63,0xb0,0x36,0xb0,0x48,0x21,0x2b,0x18,0xf4,0xb7,0xe9,0xf8,0x8c,0xb3,0xce,0x3a,0xcb,0x4a,0x49,0x49,0xbb,0x8,0xd5,0xbb,0x63,0x14,0x6c,0x73,0xfc,0xf,0xb8,0x2b,0x10,0xf4,0xff,0xa9,0x6d,0xe2,0xcd,0xb8,0x1c,0xd5,0x7f,0x24,0x20,0x4b,0xd6,0x1,0x73,0x14,0x99,0x1e,0xc,0x56,0xbc,0x9b,0xf0,0xfc,0xf7,0x66,0x8c,0x44,0xf5,0xf7,0x44,0x8e,0x87,0x69,0x6b,0x79,0xab,0x2,0x1e,0xb4,0x35,0x3c,0xbd,0xb2,0xb2,0x72,0x7b,0x6b,0x6f,0x1a,0x35,0x6a,0x54,0xef,0x70,0xc8,0xde,0x48,0x64,0x8f,0xaf,0xf6,0xe6,0xb3,0x40,0xd0,0x7f,0x78,0xa7,0x12,0xaf,0xcf,0xeb,0x3b,0x40,0x95,0xbb,0x81,0xeb,0x62,0xa8,0x65,0x63,0xa5,0x6,0xc8,0xb,0x4,0xfd,0x8f,0x3a,0x73,0xdf,0x32,0x3c,0x82,0x4e,0x25,0xb2,0xd,0x6b,0xbc,0x59,0xad,0x70,0x5b,0x30,0xe8,0x7f,0xde,0x61,0x4b,0xb1,0x5,0xe8,0x97,0xe0,0x82,0x35,0x1f,0x91,0x69,0x81,0x40,0x45,0x69,0xfc,0x5d,0xe3,0x8c,0x63,0x5,0x9d,0x46,0xa4,0xb5,0x8d,0x77,0x39,0xdb,0xa8,0x70,0x4f,0x38,0x5c,0x5f,0xbc,0x70,0xe1,0xc2,0x70,0x2b,0x6c,0x79,0x1d,0xf0,0xe7,0x8e,0xea,0x26,0x28,0x7a,0x54,0x30,0x18,0xff,0xae,0x55,0x42,0x44,0xe5,0xf3,0x64,0x9c,0xae,0xca,0x3b,0xc0,0x2f,0x12,0x28,0x5c,0x88,0xec,0x98,0xf8,0xe3,0x58,0x6f,0x1a,0x39,0x72,0xa4,0xe5,0xf5,0xf8,0x26,0x9,0x1a,0x48,0x90,0x70,0x1,0xe,0x17,0x78,0xd6,0xeb,0xf1,0xdd,0x13,0x7b,0x6b,0x35,0xca,0xdd,0xe,0xc2,0x5,0x18,0x8d,0xea,0x3c,0xaf,0xc7,0xf7,0xd7,0x11,0x23,0xbe,0xef,0x8a,0x63,0x6b,0x7b,0x91,0xa0,0xcb,0x1a,0xdc,0xd4,0x44,0x34,0x10,0x3,0x5,0xa6,0xbb,0x5d,0x29,0x7f,0xf7,0xa5,0xfb,0x5a,0xd3,0xfd,0x3a,0xbb,0x43,0x7,0x96,0x54,0x12,0xd2,0xf2,0x5a,0xf1,0x17,0xae,0xef,0x3c,0x45,0x2b,0x81,0xc1,0xed,0x64,0x1b,0x57,0x6c,0x5,0xcb,0xdb,0x23,0x35,0x25,0xed,0xcf,0x40,0x41,0x3b,0xc4,0xcd,0x2,0xee,0xf0,0x7a,0x7c,0x2f,0xc,0x1f,0x3e,0xbc,0xd5,0xb6,0x56,0x6d,0xf7,0x81,0xc4,0xab,0x7a,0xf5,0xec,0xb5,0xd2,0xeb,0xf5,0x1e,0xd6,0xf6,0x6e,0x92,0xef,0x76,0x54,0x5f,0x68,0xa8,0x58,0x13,0xcd,0x65,0x2a,0x2c,0xf0,0xf9,0x32,0x86,0xee,0xe5,0x77,0xfb,0xd2,0xa1,0xea,0x4d,0x4c,0x45,0x1c,0x57,0xf1,0x7a,0x3d,0xbe,0x6b,0x15,0x5e,0x6,0x7a,0xb6,0xa3,0x69,0xbe,0x89,0x41,0xb8,0xbd,0x50,0x29,0x3,0xae,0x69,0xe7,0xec,0xbb,0xa4,0x5f,0xdf,0xfe,0xc9,0x7e,0x88,0xf4,0x30,0x54,0x56,0xf9,0x7c,0x19,0x87,0x3a,0xce,0xff,0x74,0xdf,0x13,0xc0,0xbd,0xb1,0x56,0xa8,0x6d,0x64,0xb8,0xda,0xfa,0xae,0x37,0xdd,0xd7,0x92,0x40,0x3b,0xfa,0xcc,0xa8,0xbe,0x49,0x2d,0x5e,0xaf,0xc7,0x77,0x6,0xf0,0xc7,0x4,0xbb,0xc9,0xd1,0x8,0xb6,0xca,0x23,0xf0,0xf9,0xdc,0xa8,0x3c,0xd1,0x81,0x2e,0xd4,0xa9,0x5e,0x8f,0xef,0xe5,0x24,0x17,0xb0,0xa5,0xb6,0x2e,0x1f,0x37,0x6e,0x5c,0x9a,0x83,0xfc,0x9f,0x82,0xf0,0xf3,0xe,0x8a,0xf7,0xbe,0x8,0xf3,0xbd,0x5e,0x6f,0x73,0x22,0xed,0xe8,0xa3,0x59,0xc2,0x49,0x2b,0x5e,0xaf,0xd7,0xbb,0xf,0xf0,0x7c,0x3b,0xd7,0xb8,0x0,0xb5,0x62,0xf1,0x4c,0x6b,0x7e,0x68,0xdb,0xfc,0x1c,0xb8,0xac,0x83,0x33,0xf1,0x7c,0xaf,0xc7,0x77,0x75,0x92,0xb,0x78,0x40,0xcd,0x8e,0xda,0xa,0xaf,0xd7,0xdb,0xea,0xb2,0x91,0x9e,0xee,0xfb,0x1e,0x70,0x7,0x1d,0x7b,0x2,0xc7,0x49,0xa8,0x34,0x37,0xbe,0x50,0xd5,0xc1,0x36,0xad,0x4a,0x5a,0xf1,0xa2,0xf2,0x8,0x70,0x68,0x7,0x18,0xe5,0x3d,0xbf,0xdf,0xbf,0xd7,0x43,0x9b,0xbd,0x1e,0xdf,0xc1,0x2,0x8f,0x25,0x81,0x30,0x4,0x78,0x64,0xdc,0xb8,0x71,0xae,0x24,0x17,0xf0,0x48,0x51,0x69,0xf5,0x40,0xa0,0x25,0x94,0x2,0xee,0x24,0x88,0x77,0x8e,0xcf,0x9b,0x71,0x72,0xd3,0xf2,0xc9,0xff,0x3a,0x38,0xd3,0xb7,0x26,0xa5,0x78,0xbd,0x5e,0xef,0x58,0xe0,0xf2,0x8e,0x30,0x8a,0xb6,0x7e,0xd0,0x69,0x72,0x7,0x78,0x5,0xcd,0xd1,0xab,0x66,0x47,0xed,0x1f,0x92,0x5c,0xbc,0x28,0x3c,0x99,0x9e,0xee,0xdb,0xab,0x20,0xbd,0x1e,0xdf,0x35,0xb4,0xdf,0xe0,0xe4,0xde,0xe3,0xad,0xfa,0x60,0x13,0xf1,0x8,0x73,0x3a,0x34,0x4e,0x22,0x1f,0x24,0x67,0xcb,0xab,0x72,0x5b,0x7,0xd9,0xe4,0xb3,0x60,0xd0,0xff,0x5c,0x2b,0xfa,0xba,0xfb,0x2,0x13,0x92,0x4c,0x1b,0x37,0x92,0xfc,0xf4,0x14,0xd1,0x53,0x5b,0xf1,0xbb,0x82,0x24,0x8b,0xf7,0x18,0xaf,0xc7,0x77,0x44,0xe3,0xb,0xbd,0xfb,0xf6,0x7e,0xd,0xd8,0xde,0x41,0xf1,0x79,0x27,0x10,0xa8,0xf8,0x26,0xe9,0xc4,0xeb,0xf5,0x64,0x9c,0xe,0xa4,0xc7,0x31,0x3e,0xdb,0x81,0xaf,0x5b,0x61,0x68,0x5b,0x91,0x89,0xad,0xab,0x89,0xf9,0x69,0x1c,0xfb,0x62,0xf1,0x2a,0x0,0xfd,0xbc,0x1e,0xef,0x65,0xc9,0xae,0x5e,0x41,0x5e,0xf4,0x78,0x3c,0x56,0xf3,0x5e,0x57,0xc6,0x59,0x44,0xe6,0x7b,0x27,0x93,0x6d,0x41,0xb8,0xa9,0xf1,0x7f,0x5f,0x79,0xe5,0x95,0x10,0xf0,0x10,0xf0,0x19,0xf0,0x79,0xb,0x1f,0x75,0xf0,0xb4,0x2f,0x5a,0x8,0xef,0x13,0xe0,0xce,0x44,0xf6,0xc1,0xda,0x20,0x5e,0xdf,0xb3,0xc0,0x4f,0xda,0xe6,0x9d,0x31,0x1b,0x78,0xc6,0x85,0xe5,0x2f,0xf,0x96,0x6f,0x68,0xe4,0x8e,0xf,0x5,0x19,0x89,0x72,0x71,0x83,0x5b,0x9e,0xd2,0xe8,0xbe,0x47,0x3,0x41,0xff,0x4d,0x7b,0xb,0xdc,0xe3,0xf1,0xf4,0x11,0xac,0x6f,0x89,0x7d,0x1e,0x75,0xe3,0xf8,0xbd,0x2a,0xf0,0x90,0xe5,0xb6,0x16,0x95,0x97,0x97,0x57,0xa7,0x9f,0x33,0x7a,0xb0,0x25,0xf6,0x68,0x44,0xb3,0x81,0xef,0xb7,0x21,0xed,0x6b,0x2,0x41,0xff,0xfe,0xd1,0xe3,0x3d,0x2a,0x45,0xb0,0xeb,0x62,0xc,0xaf,0x16,0x98,0x48,0x64,0x72,0xc7,0x60,0x22,0xf3,0x87,0xcf,0x8a,0x83,0xff,0xdc,0x27,0x50,0x19,0x7d,0x5c,0xc1,0xeb,0xf1,0x7d,0xa,0xb4,0x65,0x2,0xc2,0x1b,0x2,0x45,0xe2,0xb2,0xca,0x2a,0x2a,0xca,0x37,0x7a,0x3c,0x9e,0xbe,0x82,0x8c,0x4,0xf9,0x15,0x70,0x41,0x1b,0xca,0x67,0x58,0x60,0xb0,0x3f,0xe8,0xdf,0x1c,0x63,0x79,0xae,0x1,0xd2,0x62,0x33,0x8f,0xdd,0x2b,0x18,0xc,0xee,0xe8,0x88,0xca,0xd5,0xf1,0x20,0x83,0xc7,0xe3,0xe9,0x7,0x5c,0xda,0x86,0x67,0x7f,0x81,0xf0,0x93,0x40,0xc0,0xff,0x7a,0xb4,0x2f,0x3,0x81,0xc0,0x5a,0xe0,0x25,0xe0,0x25,0x5f,0xba,0x6f,0xa2,0xa,0x37,0x12,0x79,0x3f,0xfb,0x62,0x20,0xe8,0xbf,0xb5,0x75,0x35,0x93,0x6b,0x18,0xa8,0x53,0xe1,0xd6,0x1,0x37,0x6,0x82,0xfe,0x27,0x1b,0x5f,0xac,0x5c,0x30,0x7f,0x3d,0xf0,0xac,0xcf,0xe7,0x9b,0xa5,0x36,0x77,0x3,0xb7,0x3b,0xc,0x7f,0x9f,0x38,0xe7,0x65,0x7d,0x20,0xe8,0x7f,0xb8,0xf1,0x85,0x8c,0x8c,0x8c,0x21,0x76,0x48,0x6f,0x45,0x98,0xd4,0x6,0xdf,0xec,0x10,0x22,0xb,0x1b,0xa2,0xb1,0x7f,0x1b,0xe2,0x7b,0x2f,0xa2,0x53,0xfc,0x81,0x40,0x68,0xe7,0x85,0x60,0x30,0x58,0x5,0xcc,0x3,0xe6,0xf9,0xbc,0xbe,0xab,0x55,0xf9,0x23,0xce,0xe6,0x23,0xbb,0x80,0x23,0x80,0xff,0xd0,0x85,0x71,0xec,0x36,0xb,0xd6,0xe9,0x6d,0x18,0x4,0xfa,0x40,0x2c,0x4e,0x6b,0x4e,0xb8,0x7b,0xe2,0xaf,0xf4,0xaf,0xb,0x4,0xfd,0xf7,0x4,0x82,0xfe,0x23,0x5b,0x2b,0xdc,0x86,0x7a,0xd1,0xe9,0xd4,0x47,0x5b,0x84,0xac,0x3d,0x85,0xbb,0x5b,0x9c,0xfc,0xfe,0x90,0x62,0xdf,0x9,0x14,0x3a,0x7c,0x46,0x9a,0xd7,0xeb,0x3d,0x3e,0x91,0x99,0x5b,0x51,0x51,0xb1,0x2e,0x50,0xe9,0xcf,0x47,0x9d,0xf,0x28,0x8a,0x72,0x43,0x33,0x63,0x9,0x47,0xe3,0x70,0x16,0x95,0x40,0xb1,0x62,0xff,0x36,0xd0,0x48,0xb8,0x4d,0xec,0x1b,0xf0,0xff,0x15,0xe5,0x26,0x1c,0xbe,0xa3,0x55,0x18,0x4e,0x17,0xa7,0x2d,0x7d,0xde,0x91,0xe,0xef,0xab,0x16,0xb8,0xc4,0xef,0xf7,0xaf,0x6b,0x87,0xf4,0x39,0x2d,0xb4,0x8b,0xfc,0x1,0xff,0xe3,0x7b,0xfb,0x51,0x30,0x18,0xb4,0x2d,0xe4,0x76,0x22,0x2b,0x75,0x9c,0x94,0xb0,0x5f,0xb6,0x47,0x26,0x7,0x2a,0xfd,0xcf,0x3,0x6f,0x3b,0x14,0xc1,0x35,0x19,0x19,0x19,0x4d,0xdc,0x57,0xb5,0xd5,0xe9,0x20,0xe0,0x7a,0x11,0xb9,0x35,0x18,0xc,0xda,0xad,0x88,0xf7,0x5f,0x80,0x5,0xe,0x9f,0x73,0x89,0x11,0x6f,0xf3,0x8c,0x71,0x78,0xdf,0x53,0xfe,0xa0,0xff,0x83,0x44,0x27,0xcc,0xe3,0xf1,0xf4,0x0,0x7c,0x4e,0xdc,0x65,0xc5,0x6a,0xf5,0x60,0x52,0x45,0xb0,0xa2,0x6,0x7,0x8b,0x23,0x1a,0xda,0xa0,0x8b,0xdb,0x2b,0xa3,0x15,0xf9,0xa9,0xc3,0x5b,0x7,0xd8,0x21,0x8d,0xe2,0xba,0xca,0x25,0x4e,0xd3,0x5c,0x11,0xa8,0xa8,0x69,0x7d,0xbc,0xed,0xcb,0x80,0x7a,0x7,0xf,0xf2,0x65,0x64,0x64,0xa4,0x1a,0xf1,0xee,0x41,0x46,0x46,0x46,0x4a,0xc3,0x80,0x48,0xcc,0xfd,0x32,0xb1,0x68,0xa7,0x77,0x9c,0xd6,0x81,0xe,0xdd,0xfa,0x55,0xc1,0x60,0xf9,0x9a,0x18,0xa5,0xb1,0x14,0x67,0x23,0x95,0x3,0xda,0x2b,0xa3,0x83,0xc1,0x8a,0x8f,0x1c,0xbb,0xa0,0x12,0xd5,0x8e,0xfd,0x1c,0x5,0x25,0xba,0x34,0xb6,0x78,0x7,0xd7,0xa1,0xac,0x72,0xf0,0xac,0x14,0xdb,0x6e,0x53,0x9f,0xbc,0x6b,0x8a,0x57,0xc3,0x3a,0x0,0x67,0x83,0x5d,0x1f,0xf8,0xfd,0xfe,0xaf,0xdb,0x23,0x61,0x82,0x38,0x9d,0x8c,0xfe,0x5c,0xac,0x37,0x4,0x82,0x81,0x6d,0x40,0x99,0x83,0x67,0xb5,0xf7,0xac,0x24,0x75,0x66,0xcb,0xa8,0xe2,0x75,0x12,0xf7,0x97,0xfd,0x1,0xff,0x76,0x7,0x11,0x70,0x36,0x27,0x5c,0xb5,0xb7,0x11,0x6f,0xfc,0x5a,0x8c,0xff,0xb6,0x57,0xc2,0x4,0x75,0xb6,0xb2,0x49,0xe4,0x55,0x87,0xf,0xfc,0xa7,0x83,0xbb,0xda,0x7b,0xd6,0xd7,0x57,0xe,0xc5,0x6b,0xc5,0x25,0xee,0x22,0x2f,0x39,0xb3,0xad,0xbe,0xe2,0x30,0xbd,0x3d,0x8c,0x78,0x9b,0x54,0x68,0x8e,0xc5,0xfb,0x51,0x3b,0x36,0x31,0x4e,0xc4,0x1b,0x1a,0x3c,0x78,0xe0,0x7f,0x9c,0x95,0x2f,0x58,0x74,0x8b,0x17,0x0,0x0,0x13,0xdf,0x49,0x44,0x41,0x54,0x59,0x98,0xf4,0x2d,0xaf,0xf2,0x99,0x43,0x5b,0xc6,0xa5,0xe5,0x15,0x78,0xdd,0x91,0x2,0x7b,0xf4,0x58,0xe2,0xc8,0xe5,0xd7,0x76,0x5d,0x9a,0xda,0xee,0x38,0x2d,0x3c,0xe,0xc5,0xab,0x1b,0xf6,0xf6,0xb,0x8f,0xc7,0xe3,0xb2,0xb0,0xe,0xb5,0x91,0xa1,0x16,0xba,0x8f,0x2a,0x3,0x44,0xd8,0x47,0x23,0xcf,0xc,0xa3,0x6c,0x41,0x74,0xa3,0xa8,0x7c,0x64,0xa5,0x58,0x1f,0x95,0x97,0x97,0x37,0xe7,0x86,0x39,0x79,0x8f,0x5a,0x33,0x6b,0xd6,0x2c,0x75,0x56,0xc0,0xb5,0xd6,0x49,0xcb,0x7b,0xe9,0xa5,0x97,0xba,0x66,0xcd,0x9a,0x15,0x6e,0x8f,0xcc,0x16,0x61,0x9d,0x3a,0xcb,0xb7,0x7e,0xc0,0xc6,0x9d,0xff,0xf3,0xf9,0x7c,0x3,0xd4,0x8e,0x7d,0x2,0x85,0xda,0x8e,0x6c,0xc4,0xdc,0xb9,0x73,0xc3,0x5e,0x8f,0xaf,0x2e,0xd6,0x96,0x54,0x2c,0xe9,0x65,0xc4,0xdb,0xb4,0x10,0xf4,0x70,0x56,0x8,0xd8,0xd4,0xd2,0x97,0x5e,0x8f,0xef,0xaf,0xc0,0xe5,0xa,0xa9,0x82,0x46,0x3a,0x68,0xb2,0x47,0x47,0x4d,0x1a,0x9c,0x62,0x81,0x70,0xc8,0xae,0xf3,0x7a,0x7c,0xaf,0x20,0x3a,0xb1,0xc9,0x6e,0x92,0xc2,0x7e,0xe,0x7a,0x78,0x75,0x4e,0xd,0xa9,0x10,0x72,0x32,0x1d,0x68,0xc3,0x86,0xd,0xfb,0x3b,0x75,0x67,0x1d,0x78,0x4c,0x9b,0x9c,0xcd,0x59,0x92,0x3d,0x67,0x10,0x1d,0xec,0xb0,0xf6,0x8,0xb5,0x21,0xfa,0xf5,0xb1,0x8a,0x57,0x55,0x87,0x1a,0xf1,0xee,0x81,0xd,0x5b,0xc5,0x51,0x1,0xdf,0xdb,0x20,0x92,0x1e,0x0,0x12,0xcb,0xf0,0x7e,0x2a,0x70,0x9,0x2a,0x5b,0x80,0xeb,0xe3,0x25,0x44,0x67,0xfd,0x42,0x11,0x27,0xe3,0x41,0xed,0xb8,0x8d,0x30,0x88,0xf4,0x73,0x38,0x66,0x55,0x17,0x1f,0xdb,0xda,0xd2,0x26,0x13,0x1b,0xda,0xde,0xe7,0x15,0xc4,0xd1,0xfa,0x44,0x51,0x6,0x25,0xa8,0x2f,0x27,0x51,0xae,0xad,0x71,0x10,0x92,0xf3,0xf7,0x82,0xaa,0x4e,0x2a,0x42,0xdd,0xbc,0x79,0x73,0x3b,0xae,0x35,0xb5,0x9d,0xda,0xdf,0xde,0xa3,0xc2,0x71,0xb6,0x67,0xb6,0x4a,0x5b,0xfa,0xf8,0x31,0xe7,0x8d,0x88,0xac,0x35,0xe2,0x6d,0x22,0x42,0xdd,0xe2,0xb0,0xee,0x3c,0x24,0x41,0xcd,0x5e,0xb4,0x97,0xf8,0x4e,0x76,0x2f,0xe8,0x71,0xe9,0xa5,0x97,0x3a,0x1b,0x81,0x17,0x75,0xd2,0xc7,0xe,0xc7,0x63,0x83,0xf6,0x18,0x22,0x79,0xb0,0x33,0xf3,0xee,0x2e,0xde,0x8a,0x8a,0x8a,0x1d,0x38,0x18,0x40,0x12,0x4b,0x1c,0xd,0x20,0x79,0x3c,0x9e,0xbe,0xec,0xbe,0x30,0xa5,0xb5,0x7d,0xec,0xed,0x46,0xbc,0x4d,0x9c,0x1f,0xdb,0xe9,0xce,0x0,0x27,0x26,0x28,0x1d,0xa1,0x28,0x2d,0xaf,0x93,0x8c,0x73,0xaf,0x5f,0xbf,0xfe,0x74,0x87,0x71,0x18,0xe7,0x44,0xbc,0xed,0x9c,0xdf,0xc3,0x1c,0x3a,0x36,0xe1,0x56,0xd9,0x7c,0xef,0x7d,0xd0,0x73,0x1c,0x7a,0x7a,0x19,0x8e,0xdc,0x66,0x61,0x87,0x11,0xef,0x9e,0x37,0x59,0xd6,0x16,0x9c,0x75,0x9e,0x4e,0xc8,0xc8,0xc8,0x48,0x8b,0x7b,0x2a,0xb4,0x69,0xcb,0x2b,0x4e,0x33,0x4e,0x2d,0x87,0x27,0x3b,0x88,0x93,0xf5,0xb9,0xa1,0xce,0x90,0xdf,0x88,0x86,0xe3,0x54,0xf1,0x38,0x9d,0x52,0xf9,0x23,0x87,0xe9,0xad,0x31,0xe2,0xdd,0x3,0xbf,0xdf,0x5f,0xf,0x7c,0xe8,0xe0,0xd6,0x7e,0x76,0x48,0xe3,0xbf,0x8b,0x44,0x14,0xb7,0xd9,0x76,0xbc,0x6f,0x90,0xc6,0x3c,0xdf,0xd8,0xeb,0xf1,0xd,0x74,0xe8,0x55,0xb4,0x9b,0x78,0x1b,0xe6,0x7a,0x3b,0x19,0xf4,0xd9,0xa6,0x1a,0x75,0x6d,0xb1,0x93,0xf9,0xc6,0x63,0x3c,0x9e,0xc,0x27,0xdb,0xa0,0x7a,0x9d,0x95,0xb,0xd9,0x66,0xc4,0x1b,0x9d,0xa0,0x43,0xa1,0x4d,0xc8,0xcc,0xcc,0x4c,0x6d,0xa6,0x4f,0x74,0xb1,0x62,0xf,0xd9,0xf9,0x21,0xb2,0x9e,0xd7,0x91,0x8,0xc2,0xe1,0xfa,0xaf,0x89,0x9c,0x38,0x18,0x2b,0x87,0xfb,0xd2,0x7d,0x87,0xc5,0x56,0x46,0xb8,0xd0,0xa1,0xd,0xd7,0xb7,0x5b,0x6f,0x57,0xac,0x89,0x8e,0xc4,0xab,0xbc,0x14,0xc,0x6,0xa3,0x79,0x59,0x6b,0x1c,0x15,0x38,0xd5,0x98,0xb6,0xde,0xcd,0xf0,0x66,0x8c,0x0,0xe,0x74,0xf0,0xa8,0xda,0x50,0x48,0xbf,0x31,0xe2,0x8d,0x9e,0xa9,0x8b,0x1d,0xde,0x79,0x54,0x5d,0x6d,0x7d,0x71,0x33,0x2d,0xfa,0xd6,0x60,0x30,0xb8,0x7e,0xe7,0x7,0x55,0x6d,0x65,0x5c,0x9a,0xb4,0x2,0xb,0x17,0x2e,0xc,0xb,0x38,0x99,0x56,0x97,0xa2,0x42,0xab,0xcf,0x17,0xf2,0x79,0x7d,0x3,0x54,0x79,0xdc,0xa1,0xa4,0x9e,0x69,0xb7,0x9c,0x56,0xa6,0x38,0x2b,0x21,0xfa,0xb7,0xe8,0x75,0x30,0x4f,0x3a,0x8a,0x86,0xf0,0x9c,0xcf,0xe3,0x6b,0xf5,0x9c,0x63,0x5b,0xf5,0x19,0x67,0xe5,0x54,0xca,0x16,0x2e,0xf4,0xd7,0x19,0xf1,0x46,0xbf,0xb3,0x2d,0xbb,0x14,0xdc,0xe0,0xf5,0xf8,0xf6,0xba,0x3,0x85,0x48,0xeb,0x5e,0x2d,0x88,0x44,0x77,0x3f,0x15,0x79,0xd1,0x61,0xfc,0x4e,0xf3,0x7a,0x7c,0xbf,0xdf,0xab,0x70,0xd3,0x7d,0x3d,0x54,0x79,0xd,0xa7,0x93,0x5d,0x2c,0xfd,0x63,0xfb,0xb8,0xcc,0xbe,0xbb,0x71,0x30,0x5a,0xdb,0xa0,0xb6,0x25,0xd1,0x2f,0xa7,0xfc,0xc9,0xe1,0xb8,0x47,0x1f,0x85,0xbf,0x79,0xbd,0xde,0xd6,0xec,0x4c,0xf9,0x17,0x1c,0xe,0xb2,0x21,0xbc,0x40,0x17,0xc7,0xb1,0x78,0x55,0xed,0x95,0x44,0xe,0x9a,0x76,0x66,0x5a,0xb8,0xd7,0xeb,0xf1,0x3d,0xe1,0xf3,0xf9,0xa2,0x6e,0x60,0x36,0x7c,0xf8,0x70,0x51,0x38,0xa6,0x75,0x8d,0x8a,0x34,0xd3,0xff,0xb2,0xff,0xdb,0x86,0xf8,0xdd,0xee,0xf5,0xf8,0x8a,0x7e,0xf0,0x83,0x1f,0x44,0x2d,0x64,0x19,0xbe,0x51,0x7,0x6a,0x64,0xbf,0xe2,0x33,0x1d,0x3e,0x63,0x87,0xdf,0xef,0x8f,0xe7,0xcc,0xaa,0xb4,0x66,0x3c,0x83,0x6b,0x4,0x7e,0xdb,0x6,0x7f,0x3b,0xea,0xc0,0x5f,0x20,0x50,0xba,0xe,0x1c,0x8f,0xe6,0x5e,0x84,0xca,0xb,0xe9,0xe9,0x9e,0xa8,0xd3,0x6c,0x47,0x8f,0x1e,0xdd,0xcb,0xeb,0xf1,0x3d,0x4d,0x5b,0x8e,0xa5,0x51,0x96,0x77,0x75,0xf1,0x3a,0x7e,0x69,0x1e,0xc,0x6,0xc3,0x5e,0x8f,0xef,0x51,0xa0,0x2d,0x5b,0xbf,0x5e,0xa3,0x36,0x17,0x79,0x3d,0xbe,0xbf,0x23,0xcc,0x51,0x8d,0x4c,0x13,0x14,0xd5,0x83,0x10,0xb9,0x92,0x56,0x8a,0x17,0xd1,0xa8,0xe2,0xd,0xdb,0xae,0x55,0x2e,0xcb,0xfe,0x6,0x67,0x7b,0x2d,0x59,0x40,0x4e,0x8f,0xb4,0x9e,0x57,0x78,0x3d,0xbe,0xbf,0xa3,0x2c,0x53,0x61,0xbd,0x20,0x7,0x83,0x7a,0x6d,0xdb,0xbe,0xd8,0x71,0x6b,0x16,0x21,0xde,0x93,0x33,0xac,0x5d,0x2d,0xad,0xc7,0x2d,0xea,0x1a,0x8d,0xe8,0x8d,0xaa,0x8e,0xfb,0xe3,0x80,0xfc,0x25,0x10,0xa8,0x68,0xc9,0xf5,0x5c,0x1,0x9c,0xe1,0x30,0xf0,0xb,0x2d,0xb1,0xbe,0xf2,0x7a,0x7c,0xcf,0xa3,0x2c,0x52,0xe1,0x7f,0x82,0xec,0x7,0x3a,0x22,0x54,0x1f,0xbe,0x92,0xb6,0x9d,0xef,0x53,0xa3,0xf0,0xa9,0x11,0x6f,0xcb,0xcd,0xef,0xe3,0x88,0xdc,0x42,0xdb,0x6,0xbe,0x6,0x0,0xe3,0x51,0xc6,0x4b,0x23,0x3f,0x38,0xa6,0x22,0xa6,0xd1,0x47,0x3e,0x17,0x2c,0x28,0xaf,0xf3,0xa4,0xfb,0x26,0x89,0xf0,0xf7,0x36,0xc4,0x6f,0x28,0x90,0x8b,0xec,0x1c,0xed,0xd1,0x78,0xd8,0x5d,0x41,0xaf,0x8d,0x73,0x5e,0xba,0xbc,0x1e,0xdf,0x56,0x22,0xaf,0x47,0x86,0x20,0x6d,0x8f,0xa7,0xad,0xe1,0x5b,0x5b,0xfe,0x9e,0x9f,0x58,0xc2,0x27,0x6d,0xc8,0xff,0xde,0xc0,0xb5,0x8,0xd7,0xc6,0xd1,0xb6,0x0,0x53,0x82,0xc1,0x8a,0xea,0xae,0x2e,0xde,0x36,0xed,0xdb,0x1c,0xa8,0xc,0xac,0x6,0x5e,0xec,0xe8,0x44,0x68,0x4b,0xaf,0x2d,0x84,0xd7,0x48,0xbe,0xf7,0x7d,0x1b,0x3,0xc1,0xc0,0xc2,0x4,0x84,0xdb,0x17,0x18,0x12,0xa7,0xb0,0x36,0x58,0x96,0x6c,0x6c,0xe9,0x7,0x95,0x95,0xfe,0xd5,0xc0,0x97,0x49,0x57,0xaa,0x85,0xbf,0xd2,0xd,0x88,0xc7,0x59,0x45,0x33,0x92,0x20,0xb3,0x42,0xcd,0xbb,0xf7,0xfe,0xad,0xa,0x77,0x27,0x57,0xd9,0x4a,0xdc,0x46,0xdc,0x71,0x8b,0xa3,0xc8,0xd5,0x81,0x40,0x60,0xaf,0x53,0x20,0x15,0xbd,0x2e,0xc9,0xa2,0xfe,0xc7,0x40,0xc0,0xff,0x8d,0x11,0x6f,0x6b,0x5a,0xdf,0xa0,0x7f,0x11,0xb4,0xfe,0xd5,0x4a,0x82,0x9a,0xde,0xfa,0x96,0xdd,0x6a,0x7d,0x1c,0xf8,0x36,0x49,0x6c,0xbe,0xd9,0x1f,0xf4,0x3f,0x92,0xe4,0xe5,0xe2,0x4d,0x5b,0x65,0x5e,0xeb,0xc6,0x3e,0x2,0x7e,0xe0,0x9d,0x24,0x89,0xb7,0x2a,0xfc,0x81,0x6e,0x42,0x7c,0x4e,0x9,0xb4,0x35,0x1b,0xd8,0xd0,0x51,0x89,0x90,0xbd,0xcc,0xf6,0x9,0x54,0x6,0x36,0x22,0x8e,0xe6,0x1e,0xc7,0x9b,0xb0,0xa2,0xe7,0x27,0x79,0x99,0x50,0xdb,0xe,0x67,0x4,0x83,0xe5,0xad,0x5e,0x78,0x20,0x16,0x67,0xe1,0x6c,0x42,0x4c,0xbc,0xc9,0x9,0x6,0xfd,0xab,0x8d,0x78,0x63,0x69,0x7d,0x17,0x4,0xbe,0x15,0xb8,0x10,0x67,0x53,0xe6,0xda,0x5e,0xda,0x5a,0xb1,0xc8,0x3b,0x10,0xf0,0x2f,0x93,0x8e,0x3f,0x70,0xac,0x20,0x18,0xc,0xfc,0x3b,0xb9,0xa5,0xab,0x97,0x55,0x2e,0xa8,0x8c,0x49,0x88,0x7e,0xbf,0xbf,0x5a,0x22,0xb,0x33,0x42,0x1d,0x18,0xf3,0x97,0xc3,0xb6,0xf5,0x28,0xdd,0x88,0xb8,0x9d,0x62,0xef,0xf,0xfa,0x17,0x21,0x5c,0x49,0x3b,0x2f,0x82,0x6f,0x28,0x70,0xad,0xaa,0x34,0xea,0xc3,0xf5,0x8f,0xa2,0x3c,0xdd,0x41,0xb6,0x7e,0x3a,0x10,0xf4,0xdf,0x96,0xe4,0xe5,0x21,0xd7,0x72,0x5b,0x2f,0x3a,0xcc,0xff,0x7f,0xa3,0xdc,0x45,0xc7,0x9c,0x42,0xbf,0x58,0x91,0x9f,0x2e,0x58,0x50,0x5e,0x6f,0xc4,0xeb,0xb4,0x5,0xe,0xf8,0x5f,0x0,0xf1,0xd0,0x8e,0x73,0x76,0x63,0x11,0xef,0xc2,0x85,0xb,0xc3,0x2a,0xf6,0x35,0x88,0xc3,0xa9,0x82,0xe,0x5d,0x65,0xe0,0x8e,0x40,0xd0,0x7f,0x75,0x72,0xb7,0xb8,0x5c,0x11,0x8,0xfa,0x67,0x54,0x54,0x54,0x38,0x7e,0x5f,0x13,0xa8,0xf4,0xdf,0x27,0xc2,0x55,0xed,0x5c,0x81,0x3f,0x81,0x68,0x46,0x30,0x58,0xb1,0x8d,0x6e,0x86,0x15,0xef,0x0,0x3,0xc1,0x8a,0xd7,0x11,0xce,0xa0,0x1d,0xb7,0x79,0xc5,0x6a,0xfd,0xde,0x48,0xc1,0x60,0xd0,0xe,0x4,0xfc,0x77,0x6b,0xe4,0x74,0xc3,0x44,0xaf,0xa7,0xdd,0x1,0x72,0x51,0x20,0xe8,0xbf,0x2f,0xc6,0x3e,0x7c,0x7b,0xf2,0x99,0x82,0x2f,0x50,0xe9,0xff,0x47,0x5c,0x3c,0xb0,0x80,0xff,0xef,0xa,0x67,0x3,0x5b,0xda,0x21,0xee,0xb9,0x29,0xa9,0xee,0xeb,0x3,0x81,0x40,0xd,0xdd,0x10,0x2b,0x11,0x81,0x6,0x2,0xfe,0xd5,0x96,0xca,0x8,0x22,0xd3,0xf2,0xaa,0x12,0x9c,0x6,0x55,0x8d,0x7d,0xf9,0x5f,0x30,0xe8,0x7f,0x4e,0x84,0x13,0x71,0xb6,0x78,0x61,0x6f,0xd8,0xc0,0x73,0x88,0x1e,0x1f,0x8,0x56,0xc4,0xbc,0xf,0x74,0xd8,0xb6,0x42,0xed,0xd0,0x7a,0x6d,0x4,0xc6,0x5b,0x2a,0x47,0x4,0x83,0xfe,0x40,0x3c,0x3,0xe,0x6,0xfd,0x6f,0x5a,0x2e,0x39,0x12,0x78,0x3c,0x41,0x15,0x64,0x25,0xe8,0xf7,0x3,0x41,0xff,0x8c,0xb2,0xb2,0x32,0xa5,0x9b,0x92,0xf0,0x4a,0xde,0xe7,0x1b,0x35,0x58,0x6d,0xfb,0xe,0x60,0x3c,0x6d,0xd9,0x23,0xaa,0x29,0x5b,0x81,0xd9,0xa,0xd3,0x83,0x41,0xff,0xb2,0xb6,0x4,0xe4,0xf1,0x64,0x8c,0x14,0xf4,0xf,0x44,0x5a,0x8c,0xb6,0x8a,0xf6,0x25,0x81,0xbb,0xfd,0x41,0xff,0x7b,0x6d,0x9,0xc8,0x9b,0xee,0xcb,0x46,0xe2,0xfe,0xe,0xbd,0x1a,0x28,0x7,0xe6,0x2b,0xf6,0x63,0xc1,0x60,0x30,0xe1,0x3b,0x79,0x78,0x3c,0x19,0x47,0xb,0x7a,0xf,0x91,0x85,0xf8,0x6d,0x6d,0x2c,0x16,0x83,0xde,0x35,0x78,0xc8,0xe0,0xa,0xa7,0x5b,0xf4,0xb6,0x68,0x73,0x8f,0x6f,0x3b,0xb1,0xed,0xf7,0x6d,0x37,0x9c,0xcf,0x5b,0xdb,0x25,0xc5,0xbb,0x93,0x8c,0x8c,0x8c,0xfe,0xe1,0xb0,0x8e,0x16,0x18,0x4b,0xe4,0x73,0x60,0x8c,0xa2,0xf8,0x1c,0x58,0x9,0xbc,0x89,0x48,0x69,0x8f,0x1e,0xa9,0x4b,0xe6,0xce,0x9d,0x1b,0xb7,0xc1,0x91,0x71,0xe3,0xc6,0x49,0xed,0xf6,0xda,0xe3,0x10,0xc6,0x69,0x24,0x7e,0xe9,0xb4,0x6e,0xee,0x72,0x15,0x30,0x1f,0xa5,0x4c,0x45,0xca,0x82,0xc1,0x8a,0xb8,0xbc,0xaa,0xc8,0x48,0xcf,0xb0,0x6c,0xf4,0x46,0x84,0x4b,0x80,0x43,0x62,0x28,0xf8,0x4a,0x64,0xc1,0xc8,0x7a,0x22,0xaf,0xef,0xd6,0x3,0x6b,0x11,0x9,0x4,0x2,0x15,0xaf,0xd3,0x41,0x64,0xa4,0x67,0x1c,0xa2,0xa2,0x63,0x15,0x32,0x89,0x1c,0x52,0xd7,0x9a,0xe3,0x68,0xea,0x80,0x4a,0x81,0x32,0x15,0x2d,0xab,0xa9,0xa9,0x79,0xef,0xf5,0xd7,0x5f,0x4f,0x58,0x4b,0xeb,0xf5,0xf8,0xae,0x5,0xae,0x6,0xe,0x22,0xb2,0xef,0xf7,0x0,0x76,0xdf,0x70,0x3e,0xd4,0x60,0xdb,0x4d,0xd,0xe5,0xf1,0xf1,0x40,0xd0,0x3f,0xab,0xcb,0xb6,0xbc,0xd1,0x18,0x3e,0x7c,0xb8,0xf4,0xed,0xbb,0xcf,0x30,0xb,0x7b,0x3f,0x15,0x86,0x60,0x33,0x4,0x61,0x8,0x8a,0x85,0x50,0xd,0xb2,0xd,0xa8,0x46,0xa9,0x12,0xf4,0x73,0x57,0xaa,0xeb,0xe3,0xf9,0xf3,0xe7,0xb7,0xeb,0x7e,0x44,0xe9,0x67,0xa5,0xf7,0x10,0xb7,0xfb,0x58,0xd0,0xa1,0xc0,0x10,0x41,0x87,0x82,0xf4,0x3,0x36,0x28,0xac,0xb3,0x60,0x9d,0x8a,0xae,0x1d,0x3c,0x78,0xf0,0xfb,0x89,0x68,0x5,0xba,0x32,0xc3,0x87,0xf,0xb7,0xfa,0xf6,0x1d,0x70,0x1c,0xe8,0xbe,0x8d,0x6c,0x3b,0x10,0xd8,0xd2,0xc8,0xb6,0xeb,0x52,0xac,0x94,0xff,0x96,0x55,0x94,0xd5,0x76,0x54,0x3c,0x2f,0xbd,0xf4,0x52,0x59,0xbf,0x7e,0x7d,0x3f,0x94,0x3e,0x2e,0xb7,0xab,0x6a,0xd3,0xa6,0x4d,0x55,0x4b,0x97,0x2e,0x35,0x79,0x6d,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0x30,0x18,0xc,0x6,0x83,0xc1,0x60,0xe8,0x68,0x5c,0xc6,0x4,0x86,0xf6,0x60,0x42,0x6e,0xee,0x61,0xc3,0x87,0x8f,0xb4,0xdf,0x7e,0xeb,0xf5,0x5a,0x63,0x8d,0xf8,0x60,0x19,0x13,0x18,0xda,0x3,0xb1,0x65,0x55,0x8a,0xcb,0xbe,0xde,0x58,0x22,0x7e,0xb8,0xbb,0x42,0x22,0xc6,0x8f,0x1f,0x6f,0xb9,0x5c,0x69,0x17,0x21,0x5c,0xb,0x9c,0x6,0xf4,0x3,0x3e,0x3,0x3e,0x2,0xfe,0x52,0x52,0x5c,0xf8,0x8a,0xc9,0x6a,0x83,0x69,0x79,0x93,0x8c,0x9c,0x9c,0x49,0x3d,0x5d,0xee,0xb4,0x7f,0x20,0xbc,0x48,0xe4,0xb0,0xaf,0x32,0xe0,0x7e,0xe0,0xdf,0xc0,0x11,0xc0,0xec,0xac,0xec,0xbc,0x97,0x4c,0x56,0x77,0x30,0x2a,0xc3,0x6d,0xdb,0xfa,0x9b,0x31,0x44,0x1c,0xbd,0x99,0xce,0x9e,0x80,0xac,0xec,0xbc,0x62,0x22,0xdb,0xdb,0x94,0xd4,0xd6,0x6c,0x9b,0xf4,0xf8,0xe3,0x8f,0x87,0x76,0x9,0x3b,0xc7,0x6d,0xab,0x35,0x11,0x78,0x0,0xb8,0xaf,0xa4,0xb8,0xf0,0xe,0x93,0xe5,0x6,0x23,0xde,0xe4,0x10,0xee,0x91,0xc0,0xc7,0xc0,0xe2,0x92,0xe2,0xc2,0x91,0x51,0x7f,0x93,0x95,0x65,0x21,0xee,0x57,0x81,0x33,0x4b,0x8a,0xb,0x7,0x98,0x2c,0x37,0x18,0xb7,0x39,0x39,0x6a,0x9e,0xb3,0x0,0x6c,0x25,0xab,0xb9,0xdf,0x94,0x94,0x94,0xd8,0xc0,0x54,0xa0,0x7f,0x76,0x76,0xde,0xe1,0x26,0xcb,0xd,0x5d,0x85,0x4e,0x3d,0x60,0xa5,0x30,0x1c,0xa8,0x7a,0xa8,0xa4,0x70,0x2f,0x27,0x16,0xca,0x47,0xa0,0x4f,0x1,0xfb,0x1,0xab,0x9b,0xb6,0xe0,0x13,0x8f,0x1,0xbd,0x1d,0x38,0xa1,0xc1,0x26,0xef,0xa1,0x94,0x94,0x94,0x14,0xbe,0x19,0xa5,0xb5,0xbf,0xb,0xe8,0x59,0x52,0x5c,0x78,0x5b,0x56,0xf6,0x44,0xf,0xe8,0x2d,0xc0,0x91,0xc0,0x1a,0x84,0xc7,0x4a,0x66,0x14,0x3e,0x3,0x30,0x61,0x42,0x6e,0x8a,0x58,0x92,0x43,0x64,0x11,0x7a,0x1f,0x60,0x91,0xcb,0xd2,0xdb,0x8b,0x8a,0x8a,0xa2,0x9e,0x42,0x30,0x7e,0xe2,0x44,0xb1,0x42,0x7a,0x83,0xc0,0x68,0xe0,0x64,0xe0,0x3d,0x60,0x41,0x49,0x71,0x61,0x51,0xcc,0x1e,0x49,0xce,0xc4,0x4b,0x50,0xbd,0x8,0xf8,0x7e,0x83,0x67,0xf2,0xb6,0xa,0x77,0xcd,0x9c,0x51,0xa8,0x7b,0xa4,0xe5,0xf,0xc0,0xfe,0x25,0xc5,0x85,0xd7,0x64,0x65,0xe5,0x9e,0x8c,0xc8,0x94,0x6,0x1b,0x7c,0x1,0x1a,0xb0,0x2d,0xfe,0xf0,0x50,0x51,0x51,0xd4,0x35,0xd3,0x13,0xb2,0x27,0xa6,0xb,0x3a,0x19,0x38,0xe,0xd8,0xa4,0xf0,0x12,0x22,0xf,0x12,0x96,0x11,0x62,0xd9,0xbf,0x50,0xdb,0xfa,0xd5,0xcc,0x99,0xd3,0x6a,0x1a,0x3d,0xeb,0x2f,0x28,0xcf,0x95,0x94,0x14,0x96,0xee,0x8a,0x67,0xde,0x9d,0x28,0x47,0x94,0x14,0x17,0x5e,0x9b,0x95,0x93,0x77,0x22,0xca,0x6f,0x80,0x53,0x88,0x9c,0xe3,0xe4,0x77,0x59,0x7a,0x7f,0x51,0x51,0x51,0xd4,0x2d,0x8e,0x72,0x73,0x73,0x7,0x84,0x6d,0xb9,0x85,0x48,0x5,0xde,0x1b,0xf8,0x8f,0xa,0x33,0x67,0xce,0x28,0x7c,0xa7,0xbb,0x88,0xb7,0xb3,0xf,0x58,0x9d,0x46,0x2b,0xf6,0x8b,0x2e,0x29,0x9e,0xfe,0x75,0x49,0x71,0xe1,0x35,0xc5,0xc5,0x85,0xaf,0x37,0x15,0x63,0xee,0x15,0xa0,0xff,0x25,0xb2,0x48,0x7c,0x45,0x83,0x68,0x46,0x21,0x2c,0x9a,0x90,0x9d,0x97,0x1d,0x25,0xb8,0xf3,0x80,0xcb,0xb2,0xb2,0xf3,0x2e,0x6,0x9d,0x43,0x64,0x77,0x8a,0xa5,0xc0,0x49,0x28,0x4f,0x67,0x65,0xe7,0xdd,0x9c,0x9d,0x3d,0xd1,0x2d,0x96,0xcc,0x2,0x26,0x3,0xab,0x80,0xaf,0x80,0x1b,0xc3,0xb6,0x7c,0x38,0x61,0x42,0x7e,0xff,0xa6,0xae,0xfd,0x44,0xb7,0x2b,0xa4,0x4f,0xa,0x3c,0x42,0x64,0x93,0x82,0x52,0x22,0x87,0xa3,0x15,0x66,0x65,0xe7,0xc5,0xb4,0x9b,0x63,0x56,0x76,0xde,0x3d,0xa8,0xbe,0x0,0x9c,0xd4,0x10,0x4e,0xf,0xe0,0x4e,0x51,0x96,0x5e,0x77,0xfd,0x2f,0xf6,0x7c,0xaf,0x7f,0x31,0xf0,0xf3,0x9,0xd9,0x79,0x23,0x10,0x59,0x4a,0x64,0x17,0x89,0xca,0x48,0x1c,0xe4,0x1e,0xcb,0x96,0xe7,0x73,0x73,0x73,0x25,0xca,0x33,0x2e,0x15,0xb4,0x2,0xc8,0x20,0x32,0xa2,0xff,0x5f,0x81,0x5c,0x51,0xd,0x88,0xa5,0x63,0x81,0x9f,0x8b,0xe8,0x9e,0xd,0xc3,0xcf,0x45,0x38,0x7e,0x8f,0x6b,0xe7,0x2,0xd7,0x64,0x65,0xe5,0x7d,0x1f,0xe5,0xd,0x60,0x30,0x91,0x81,0xc6,0xfd,0x80,0xdf,0x87,0x6d,0x79,0x71,0xfc,0xc4,0x89,0x4d,0xe6,0x22,0x64,0x67,0xe7,0x9e,0x14,0xb6,0xe5,0xfd,0x86,0xb1,0x8e,0xd,0xc0,0x7,0xc0,0x5,0xa2,0x2c,0x9d,0x90,0x9d,0x77,0x85,0x69,0x79,0x3b,0x7,0x87,0x3,0x6b,0x9d,0xde,0x3c,0x21,0x3b,0xef,0x10,0xe0,0x6f,0xc0,0x12,0xb7,0xb,0x5f,0x61,0x61,0x61,0x6d,0x64,0xa0,0x2b,0xaf,0xaf,0xad,0x2c,0x16,0xb8,0x27,0x37,0x37,0xf7,0x89,0xa2,0xa2,0xa2,0x3d,0xf7,0xe1,0x1a,0x2,0x14,0x5b,0x62,0x1f,0x3e,0x63,0xc6,0x8c,0x6f,0x23,0x2d,0x6d,0xce,0xfe,0x62,0x59,0x1f,0x3,0xf7,0x80,0xae,0x2,0x4e,0xac,0xaf,0x73,0x1d,0xfe,0xe8,0xa3,0x5,0xdb,0x1b,0x4,0x3a,0xe,0xd1,0x39,0x62,0x85,0x67,0x2,0x57,0xed,0x5e,0x85,0xea,0xaf,0x51,0x7e,0x6,0x72,0x73,0x49,0xf1,0xf4,0x47,0x22,0x71,0xc8,0x11,0x1b,0x6b,0x22,0x4a,0xc1,0x84,0x9c,0xbc,0xab,0x66,0xce,0x28,0xdc,0xeb,0x96,0xb5,0x59,0x59,0xb9,0x63,0x80,0x3b,0x80,0xa9,0x25,0xc5,0x85,0xb7,0x7c,0x97,0xce,0xac,0xbc,0x8b,0x45,0x78,0xa1,0x77,0xef,0xbe,0x7f,0x4,0xae,0x8b,0xd2,0xfd,0xf0,0x23,0x72,0x56,0xc9,0x8c,0xe9,0x4b,0x1a,0x9,0xb4,0x3c,0xe2,0x35,0xb8,0x6,0xd1,0x74,0x37,0xd0,0x27,0x80,0x1d,0xb6,0x25,0xc7,0x3c,0x54,0x34,0xfd,0x7f,0x0,0xf9,0xf9,0xf9,0x29,0xb5,0x75,0xe1,0x72,0xd0,0xd8,0xdf,0xe5,0xa,0x2f,0xab,0x70,0xfe,0xcc,0x19,0x85,0xfe,0x46,0xcf,0x9f,0xd,0x5c,0x60,0xd5,0x73,0x74,0x83,0x38,0x1b,0x79,0x5c,0x32,0x7,0xb0,0x55,0xe5,0xc4,0x99,0x25,0xd3,0xbf,0x68,0x68,0x89,0xfb,0x84,0x6d,0xa9,0x14,0x78,0x3a,0x2b,0x2b,0xaf,0xbc,0xa4,0xa4,0x70,0x9d,0x69,0x79,0xbb,0xf0,0x80,0x9b,0x8,0x67,0x3,0x8a,0xca,0x5,0x3b,0x85,0xb,0x30,0x63,0x46,0x61,0x15,0x2a,0xd7,0x2,0x7d,0xc3,0xb6,0x5c,0x10,0xe5,0xd6,0xde,0x2,0x97,0xef,0x14,0x2e,0xc0,0xcc,0x99,0x33,0xbe,0x1,0xfd,0x35,0x30,0x40,0xe1,0x39,0x4b,0xb8,0x60,0xa7,0x70,0x1,0xdc,0x6e,0x2d,0x6d,0x70,0x7,0x77,0x3b,0x31,0xe1,0xa6,0x9b,0xb3,0xfa,0xa2,0xfc,0xe,0x58,0xb4,0x53,0xb8,0x91,0x38,0xcc,0x50,0x6c,0x2d,0x2,0xd6,0x8a,0xf2,0xc8,0xde,0x85,0x9b,0x67,0x21,0xf2,0xa,0xb0,0xbe,0xb1,0x70,0x1,0x66,0x96,0x14,0xfe,0x13,0x58,0x4,0x5c,0x9b,0x95,0x9d,0x17,0x6d,0x56,0xdd,0x84,0xc6,0xc2,0x5,0x8,0xbb,0xb8,0x14,0xb0,0x43,0xb6,0xbd,0xdb,0x21,0xe8,0xd9,0x39,0xb9,0x57,0x37,0xa4,0x7f,0xcc,0x4e,0xe1,0x2,0x14,0x14,0x14,0xd4,0xf,0x1a,0xd8,0xdf,0x47,0xeb,0xb6,0xb7,0xd9,0x23,0x13,0xe5,0xf7,0x8d,0x85,0xb,0xe0,0xb2,0xf4,0x5a,0xa0,0x4e,0x44,0xb3,0xf7,0x68,0xf5,0x27,0x3,0x7,0x81,0x5e,0xbc,0x53,0xb8,0x0,0x45,0x45,0x45,0xd5,0x2,0x97,0x47,0x7a,0x53,0x72,0x8d,0x71,0x9b,0xbb,0x38,0xaa,0xf2,0x25,0x68,0x4e,0x49,0xc9,0xf4,0xd,0x4d,0x85,0xad,0x5f,0x37,0xfc,0x95,0x1e,0xe5,0xd6,0x4d,0xc5,0xc5,0x85,0x8b,0xa2,0x14,0xc3,0x7f,0x35,0xfc,0xb1,0x63,0xc6,0x8c,0xc2,0xdd,0xb6,0xbe,0x2d,0x2c,0x2c,0xb4,0x89,0xb8,0xc5,0xbd,0x1a,0x5f,0x4f,0x71,0xb9,0x7d,0x80,0x6d,0x89,0x7d,0x49,0xd3,0xc1,0xb6,0xa2,0x30,0xca,0x7d,0xd,0xae,0x6f,0xcb,0x2,0xb0,0xb4,0x1f,0x90,0xaa,0xc8,0xc5,0x51,0x33,0x5a,0xec,0x5f,0x0,0xa4,0xb8,0x5d,0x3d,0xa3,0x18,0xe2,0x99,0x3d,0x2f,0x3d,0x5c,0x58,0xb8,0x9,0xa8,0xdd,0x39,0x28,0xd8,0xc8,0x66,0xf,0x44,0x5a,0x3f,0x6d,0xb2,0xe9,0xdf,0x94,0x29,0x53,0xc2,0xc0,0x27,0xe,0x72,0xa2,0xc9,0x59,0x57,0x45,0x45,0x45,0x1b,0x1a,0x5c,0xe2,0xef,0xed,0xf1,0xd5,0xf5,0xc0,0x1a,0xb7,0x4b,0x9a,0x8c,0x73,0x14,0x17,0x17,0x7e,0x2,0x7c,0x8e,0xe8,0x85,0xdd,0xa1,0xfc,0xba,0xbb,0x62,0xa2,0xb2,0xb2,0x26,0x1e,0x81,0xe8,0x83,0x51,0x46,0xb8,0x5e,0x2b,0x29,0x29,0x7c,0xe2,0xbb,0x16,0xa9,0x78,0xfa,0x2,0x60,0x41,0x33,0xc2,0xae,0x8f,0x9c,0x71,0xab,0x7,0x44,0xf9,0x3a,0xd4,0x4c,0x13,0x52,0xdb,0x70,0xc4,0xec,0x9a,0x66,0xdc,0x84,0x8f,0x14,0xdc,0xe3,0xc7,0x8f,0x4f,0x79,0xf8,0xe1,0x87,0xeb,0x23,0xcf,0x61,0x14,0x42,0xdd,0x8c,0x19,0x33,0xa2,0xbb,0x79,0x2e,0x16,0x60,0xe3,0xca,0xca,0xca,0xea,0x55,0x52,0x52,0xb2,0xbd,0xd9,0xe2,0x6f,0x93,0x81,0xa0,0x33,0x8b,0xa7,0x47,0x3d,0x3a,0x74,0xc6,0x8c,0x19,0x2b,0xb3,0xb2,0xf3,0xa8,0xaf,0xf,0x9f,0xe,0xec,0xb1,0xd5,0xab,0xd5,0xdc,0x46,0x7e,0x61,0x22,0x13,0x5f,0x1a,0xd3,0x3,0xd8,0x56,0x52,0x5c,0x54,0xd3,0xc2,0x3d,0xb1,0xd2,0xdc,0x7c,0xe7,0x1a,0xe0,0xe8,0x3d,0xae,0xed,0x3,0x4,0xb,0xb,0xb,0x9b,0x7b,0xce,0x16,0xe0,0x94,0x29,0x53,0xa6,0xc8,0x94,0x29,0x53,0xd4,0x88,0xb7,0xf3,0x39,0xd3,0xee,0x86,0xc1,0x8f,0xc6,0x5,0x6e,0x4,0xc2,0x57,0xcd,0xdd,0x32,0x7e,0xfc,0xc4,0xfe,0x6e,0xb7,0x1e,0x9,0x1c,0xaa,0xaa,0x16,0xd8,0x7d,0x63,0xf5,0xca,0x55,0xa9,0x6f,0xb8,0x23,0xea,0x89,0x84,0x8a,0x7c,0xe,0x2a,0xae,0xd4,0xd4,0xc3,0x88,0x8c,0x2,0x43,0xc4,0x75,0x77,0x65,0x65,0xe7,0xfd,0x29,0x6a,0xa0,0x36,0xbd,0x1,0x5c,0x2e,0xd7,0x11,0xd,0x3,0x6a,0xcd,0xf9,0x50,0x19,0x28,0x34,0x1b,0xce,0x2e,0xdb,0x1c,0xd7,0x54,0xbc,0xcd,0x62,0x3,0x7d,0x26,0x4c,0x98,0x68,0xcd,0x9c,0x39,0x7d,0xa7,0xc0,0x53,0x1a,0x6,0xf5,0xda,0x83,0x7a,0x60,0xc0,0xd,0x37,0xdc,0x6a,0x3d,0xfe,0xf8,0x3,0x3b,0x9f,0x3f,0x0,0x38,0xaa,0x85,0x74,0x1e,0xc,0xf4,0xde,0xbc,0x79,0x73,0x1a,0xc9,0x77,0x2e,0xb3,0x11,0xef,0xde,0x28,0x29,0x9e,0xfe,0x11,0xe0,0xf9,0xae,0x25,0xce,0xc9,0x1b,0x86,0x46,0x77,0xe7,0xb2,0xb2,0x73,0xf,0x1,0xb9,0x1f,0xf4,0x8a,0x86,0x6a,0x7a,0x2b,0x22,0xea,0xa4,0x3f,0x2d,0x2a,0xb4,0x74,0x22,0xbd,0xda,0x12,0x12,0x4b,0x71,0xed,0xbe,0x7f,0x75,0x9f,0x86,0xee,0xcb,0xb1,0x2d,0x4,0xbd,0x8,0xd8,0xb1,0x97,0x2e,0x40,0x1f,0x89,0xc4,0x79,0x2f,0xe1,0xe8,0x9a,0x58,0xd3,0x65,0xdb,0xae,0xdd,0x7d,0x1,0xd5,0x76,0x3d,0x2e,0xb5,0xae,0xae,0xe7,0xee,0xcf,0x8f,0xb4,0xbe,0xcd,0xa5,0xf3,0x23,0xe0,0x23,0xdb,0x76,0xd9,0x74,0x71,0x3a,0xbb,0x78,0xab,0x89,0x6d,0x93,0xec,0x3d,0x84,0x3b,0x71,0x10,0xe8,0xf2,0x6,0xf1,0xfc,0x42,0x8,0xbf,0x54,0x5c,0x5c,0xbc,0xb1,0xc1,0xf5,0x1e,0x8c,0x68,0x7b,0x8d,0x58,0x56,0x97,0x14,0x17,0x9e,0x15,0x87,0x70,0xec,0x38,0x85,0x93,0xdc,0x63,0x15,0xa2,0x8f,0xcd,0x9c,0x51,0x74,0x3f,0xdd,0x9c,0xce,0x2e,0xde,0x2f,0x88,0x4c,0x68,0x70,0x5a,0xc,0xee,0x7,0xfa,0xa0,0xe2,0x2d,0x29,0x99,0xbe,0xa8,0x83,0xd2,0xf0,0x29,0x91,0xf7,0x9a,0x6d,0xc2,0x82,0x8f,0xb5,0x7d,0xa6,0xbb,0x86,0x11,0xd9,0xbf,0x3,0xf3,0x7c,0x87,0x68,0x87,0x3e,0x3f,0x69,0xe8,0xec,0xa3,0xcd,0x7e,0x60,0xc0,0x84,0x9,0xb9,0x43,0x62,0xbd,0xf1,0x86,0x1b,0x6e,0x10,0x22,0xb3,0x9f,0x3e,0xeb,0x40,0xe1,0x2,0x32,0x9f,0x38,0x1c,0x3,0x23,0x22,0xaf,0x1,0x72,0xf3,0xcd,0x37,0xf7,0x4c,0x70,0x84,0xeb,0x81,0xff,0xeb,0xc0,0x3c,0xdf,0x8,0xfa,0x3d,0x23,0xdd,0x4e,0x2e,0x5e,0x55,0x9d,0x3,0x88,0x58,0xf2,0xf0,0x5e,0xfa,0x83,0x4d,0x5a,0xa4,0xb4,0xbe,0x7d,0xdd,0xd,0x83,0x1f,0xcd,0x1d,0xd,0x79,0x50,0xbb,0xa4,0xc1,0xb6,0xe7,0x2,0x29,0x59,0xd9,0x79,0xbf,0x68,0x93,0xbf,0xac,0xfa,0x2e,0x80,0xe5,0x4a,0x7d,0x2c,0xc1,0x51,0xfe,0x16,0xe8,0x91,0x95,0x95,0xd7,0xdc,0xfb,0xdc,0xbe,0x89,0xf7,0xb6,0xe4,0xcc,0xac,0xac,0xbc,0xc1,0x46,0xbc,0x9d,0x98,0x1e,0x69,0xee,0x65,0x40,0x5,0x70,0xc1,0x84,0xec,0xbc,0xb,0xa2,0xb7,0xb0,0xb7,0x5a,0x82,0xde,0x4,0x20,0xe8,0xdb,0x3b,0xaf,0x97,0x4c,0x9b,0x56,0x4f,0xe4,0xec,0xa3,0x83,0xae,0xb9,0x66,0xca,0x6e,0x23,0x32,0x39,0x39,0x13,0x7,0x22,0xfa,0x42,0xa4,0x49,0xdb,0xfb,0x3b,0xd6,0x36,0x89,0xd7,0x65,0x7d,0xd8,0xe0,0xfe,0x4f,0xcf,0xc9,0xc9,0xe9,0xbd,0xe7,0xf7,0x39,0x39,0xb9,0x43,0xb3,0x9b,0x49,0x5b,0x63,0x4a,0x8a,0xb,0x43,0xd,0xb6,0xf8,0x59,0x76,0xf6,0xa4,0x26,0x6e,0x65,0x7e,0x7e,0x7e,0x4a,0x56,0xf6,0xc4,0xfc,0x36,0xb7,0xf0,0xe8,0x15,0x80,0x22,0xe4,0xe6,0xe7,0xe7,0xef,0x56,0x29,0x66,0x67,0xe7,0x9d,0x45,0x64,0xd,0x75,0xc2,0xb0,0xe1,0x5a,0x20,0x84,0x70,0xdb,0xd,0x37,0xdc,0x6a,0x35,0x1d,0xc7,0xc8,0xfb,0x59,0x76,0xf6,0xc4,0x81,0xa6,0xcf,0x9b,0xe4,0x14,0x14,0x14,0xd8,0x59,0x59,0xb9,0x57,0x22,0xb2,0x40,0xe0,0xa5,0xac,0xec,0xbc,0x3f,0x82,0xcc,0x42,0x59,0x1,0xea,0xc6,0xe2,0x4,0xb4,0x6e,0x2,0x91,0x59,0x4d,0x7f,0x2e,0x2e,0x2e,0xda,0x73,0x31,0xf8,0x6d,0xc0,0xbf,0xfa,0xf6,0xdb,0x32,0x77,0x42,0x4e,0xde,0x9d,0x62,0xb3,0x5d,0x84,0x33,0x6d,0xd5,0x3b,0x14,0x9e,0x12,0xf8,0xd,0x4a,0x42,0xb,0xc2,0x43,0x33,0xa6,0x87,0x26,0xe4,0xe4,0x8e,0x11,0x95,0x15,0xb6,0x5a,0x1f,0x67,0xe5,0xe4,0xde,0xe8,0x12,0x96,0x84,0x6c,0x39,0x58,0xe0,0xc,0x5b,0x99,0xe,0x7c,0xd,0xcc,0xde,0x5b,0x58,0x29,0x6e,0xeb,0xbc,0xfa,0x90,0xbd,0x56,0xb1,0x57,0x67,0x67,0xe7,0x5d,0xad,0xca,0x22,0xb5,0xa4,0xbf,0xa0,0xa7,0xd5,0xd6,0x85,0x1f,0x0,0x6,0x4c,0xc8,0xc9,0x9b,0x3e,0x73,0x46,0xa1,0xe3,0x91,0xd8,0xe2,0xe2,0xa2,0x65,0x59,0xd9,0x79,0x2b,0x80,0xdf,0xd7,0xd6,0x85,0x7b,0x66,0x67,0xe7,0xbe,0xa,0xb2,0x45,0x61,0x9c,0xc2,0xbd,0x44,0xa6,0x52,0xee,0x97,0x30,0x7b,0x15,0x17,0x7e,0xd2,0xf0,0x9a,0x68,0x52,0x5a,0xcf,0xba,0xfe,0xd9,0xd9,0x79,0x7f,0xb2,0x2d,0xfd,0x4c,0xc2,0x72,0xa,0xc2,0x45,0xc0,0xd,0x36,0xf6,0xb9,0xc0,0x3c,0xd3,0xf2,0x26,0x39,0x25,0x25,0x45,0x6b,0x11,0x19,0x1,0x3c,0x4,0x5c,0xd,0x5a,0x8e,0xe8,0x1a,0x84,0xaf,0x50,0x4a,0x81,0xa3,0x80,0xeb,0x4a,0x8a,0xb,0x9b,0xb8,0xa5,0x76,0x58,0x5e,0x3,0xa,0x80,0xd1,0xa2,0x2c,0x41,0x78,0x57,0xe1,0x41,0x85,0x3f,0x84,0xea,0xec,0x29,0x44,0x26,0x63,0xf4,0x4f,0x74,0x1a,0x66,0xce,0x28,0x5a,0xa9,0xa2,0x47,0x3,0x55,0xa8,0xcc,0xe,0xdb,0xb2,0x56,0x22,0x8b,0x1d,0x1e,0x6,0x5e,0x45,0x43,0xad,0x1a,0x94,0x9b,0x3e,0x7d,0x5a,0x4d,0x7d,0x9d,0xeb,0x0,0xe0,0x6d,0x85,0xe7,0x10,0xbe,0x12,0xd5,0xf7,0x51,0x9e,0x2,0x3e,0x42,0x65,0x58,0x5b,0x84,0xbb,0xcb,0x5d,0x8,0x9d,0xa,0xcc,0x5,0x6e,0x57,0x64,0xb1,0xc2,0xfb,0x44,0x2a,0xba,0x4b,0x1a,0x2a,0x9a,0xc4,0xe6,0x79,0x71,0xe1,0xcd,0xc0,0xcd,0x28,0x57,0x2a,0x2c,0x11,0x5b,0xd6,0x20,0xcc,0x23,0x32,0x3d,0x32,0xc7,0xe,0xd5,0x95,0x99,0x96,0xb7,0xb3,0x8,0x78,0xc6,0xf4,0x2d,0x40,0x76,0x56,0xd6,0xc4,0xc9,0x58,0x7a,0x86,0x28,0xfb,0x2,0x55,0xaa,0xfa,0x79,0x49,0x49,0xd1,0x87,0xcd,0xd6,0xe2,0xf,0x4d,0xf,0x1,0x93,0xb3,0xb3,0x73,0x66,0x28,0xd6,0xff,0x9,0xd4,0x86,0x42,0xee,0xc5,0xf,0x3f,0x3c,0x75,0x47,0xc4,0xd,0xcc,0x1e,0x24,0xe2,0xda,0x43,0xf0,0x2e,0x5f,0x4a,0x4a,0xa8,0x99,0x4a,0xaf,0x7e,0xb3,0xcb,0x72,0xed,0x23,0x22,0x51,0x67,0x60,0xd5,0xd6,0x6e,0x5d,0xde,0xbb,0x77,0xef,0x7d,0x6,0xc,0x18,0x50,0x15,0x45,0xc0,0xab,0x81,0x63,0x26,0x4c,0xc8,0x3b,0x8,0x8b,0xd3,0x44,0x74,0xbb,0xa8,0xbd,0xac,0xb8,0xb8,0x38,0xa6,0xd7,0x55,0x8f,0x3e,0x5a,0x50,0xd,0x9c,0x95,0x9b,0x9b,0x3b,0x24,0x6c,0x5b,0xa7,0x3,0x58,0x12,0x7e,0x7f,0xc6,0x8c,0x19,0x9f,0x47,0x11,0xe1,0xe9,0x2e,0x97,0xcb,0x2a,0x2a,0x2a,0x8c,0x1a,0x5f,0x97,0xa5,0x87,0x0,0x52,0xf2,0xf0,0x54,0x7b,0xf7,0xa,0xb3,0x24,0xc,0xfc,0x70,0xc2,0x84,0xbc,0xfd,0xc4,0x92,0x11,0x2,0xd5,0xd5,0xd5,0xd5,0x95,0x7f,0xf9,0xcb,0xe3,0xa1,0xac,0xec,0xbc,0x22,0x0,0x15,0x3b,0xbc,0x47,0x58,0x83,0x5c,0x2e,0xd7,0x8e,0xdd,0x5b,0xe,0x7b,0x94,0x58,0xe2,0x76,0xbb,0xdd,0x51,0xf,0x47,0xb7,0x84,0xd3,0x45,0xd4,0x7a,0xf2,0xc9,0x29,0x76,0x14,0x1,0x3f,0x7c,0xcd,0x35,0x53,0x1e,0xeb,0xd3,0x6f,0xcb,0xff,0x89,0xc8,0x11,0xa2,0xf6,0x37,0x21,0x97,0xbc,0xf5,0x70,0x61,0x61,0x7d,0x77,0xe9,0xf3,0xa,0x6,0x43,0x1c,0xc9,0xca,0xce,0xfb,0x1f,0x30,0x30,0x54,0x9f,0xd6,0xf3,0x91,0x47,0xee,0x37,0xc7,0x61,0x1a,0xb7,0xd9,0xd0,0x19,0xb8,0xe9,0xa6,0xdb,0x7a,0x10,0x99,0xfd,0xe4,0x37,0xc2,0x35,0xe2,0x35,0x24,0x21,0x37,0xe7,0xe5,0xd,0xce,0xc9,0xc9,0xdd,0x6d,0x20,0x6f,0xca,0x94,0x29,0xe2,0x4e,0xa9,0x7d,0xe,0xe8,0x21,0xc2,0x4d,0xc6,0x4a,0xa6,0xcf,0x6b,0x48,0xc6,0x1a,0xdf,0xe6,0x5e,0x5b,0xe5,0xfa,0xac,0xec,0xbc,0xb9,0x44,0x16,0x58,0xf4,0xdd,0xb0,0x71,0x4b,0x3a,0x70,0x14,0x22,0xc5,0xa1,0xfa,0x9a,0x2f,0x8c,0x95,0x8c,0x78,0xd,0x49,0x88,0x86,0xf5,0x5e,0xb1,0x64,0xd,0x30,0x8e,0xc8,0x7a,0xdf,0xed,0xc0,0xbb,0x82,0xe4,0x17,0xcf,0x98,0x3e,0xdb,0x58,0xa8,0x7d,0xf8,0x7f,0x49,0xf1,0x1a,0x6f,0x4b,0xd5,0x18,0xc6,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+static const unsigned char app_icon_png[]={
+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);
+#endif // SPLASH_H
diff --git a/makefile b/makefile
deleted file mode 100644
index d24bd0cd32..0000000000
--- a/makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-#*************************************************************************/
-#* This file is part of: */
-#* GODOT ENGINE */
-#* http://www.godotengine.org */
-#*************************************************************************/
-# Simple makefile to give support for external C/C++ IDEs */
-#*************************************************************************/
-
-# Default build
-all: debug
-
-# Release Build
-release:
- scons target="release" bin/godot
-
-# Profile Build
-profile:
- scons target="profile" bin/godot
-
-# Debug Build
-debug:
- # Debug information (code size gets severely affected):
- # g: Default (same as g2)
- # g0: no debug info
- # g1: minimal info
- # g3: maximal info
- scons target="debug" CCFLAGS="-g" bin/godot
-
-clean:
- scons -c bin/godot
diff --git a/makerel.bat b/makerel.bat
new file mode 100644
index 0000000000..7db76e1dd7
--- /dev/null
+++ b/makerel.bat
@@ -0,0 +1 @@
+"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 58cc41f70a..21c2293bf0 100755
--- a/methods.py
+++ b/methods.py
@@ -205,7 +205,7 @@ def build_glsl_header( filename ):
out_file_base = out_file
out_file_base = out_file_base[ out_file_base.rfind("/")+1: ]
out_file_base = out_file_base[ out_file_base.rfind("\\")+1: ]
- print("out file "+out_file+" base " +out_file_base)
+# print("out file "+out_file+" base " +out_file_base)
out_file_ifdef = out_file_base.replace(".","_").upper()
fd.write("#ifndef "+out_file_ifdef+"\n")
fd.write("#define "+out_file_ifdef+"\n")
@@ -504,7 +504,7 @@ def build_hlsl_dx9_header( filename ):
out_file_base = out_file
out_file_base = out_file_base[ out_file_base.rfind("/")+1: ]
out_file_base = out_file_base[ out_file_base.rfind("\\")+1: ]
- print("out file "+out_file+" base " +out_file_base)
+# print("out file "+out_file+" base " +out_file_base)
out_file_ifdef = out_file_base.replace(".","_").upper()
fd.write("#ifndef "+out_file_ifdef+"\n")
fd.write("#define "+out_file_ifdef+"\n")
@@ -714,7 +714,7 @@ def build_legacygl_header( filename, include, class_suffix, output_attribs ):
enumbase = ifdefline[:ifdefline.find("_EN_")];
ifdefline = ifdefline.replace("_EN_","_")
line = line.replace("_EN_","_")
- print(enumbase+":"+ifdefline);
+# print(enumbase+":"+ifdefline);
if (enumbase not in enums):
enums[enumbase]=[]
if (ifdefline not in enums[enumbase]):
@@ -805,7 +805,7 @@ def build_legacygl_header( filename, include, class_suffix, output_attribs ):
out_file_base = out_file
out_file_base = out_file_base[ out_file_base.rfind("/")+1: ]
out_file_base = out_file_base[ out_file_base.rfind("\\")+1: ]
- print("out file "+out_file+" base " +out_file_base)
+# print("out file "+out_file+" base " +out_file_base)
out_file_ifdef = out_file_base.replace(".","_").upper()
fd.write("#ifndef "+out_file_ifdef+class_suffix+"_120\n")
fd.write("#define "+out_file_ifdef+class_suffix+"_120\n")
@@ -952,10 +952,10 @@ def build_legacygl_header( filename, include, class_suffix, output_attribs ):
x=enums[xv]
bits=1
amt = len(x);
- print(x)
+# print(x)
while(2**bits < amt):
bits+=1
- print("amount: "+str(amt)+" bits "+str(bits));
+# print("amount: "+str(amt)+" bits "+str(bits));
strs="{"
for i in range(amt):
strs+="\"#define "+x[i]+"\\n\","
@@ -1083,44 +1083,13 @@ def build_gles2_headers( target, source, env ):
def update_version():
- rev = 0
+ rev = "custom_build"
- try:
- f = open("custom_version.txt","rb")
- rev = int( f.readline().strip() )
- except:
- pass
-
- if (rev==0):
- try:
- f = open(".svn/entries")
- line = f.readline();
- next_rev = False
- while line != "":
- line = line.rstrip('\r\n')
- if next_rev:
- rev = line
- break
- if line == "dir":
- next_rev = True
- line = f.readline();
-
- if rev != 0:
- f = open("version.py")
- ver = f.read()
- import re
- ver = re.sub(r'\$Rev: \d* \$', '$Rev: '+str(rev)+' $', ver)
- f = open("version.py", "wb")
- f.write(ver)
- f.close()
-
- except:
- pass
-
+ if (os.getenv("BUILD_REVISION")!=None):
+ rev=os.getenv("BUILD_REVISION")
+ print("Using custom revision: "+rev)
import version
-
- rev=version.revision
- rev=rev[5:-1].strip()
+
f=open("core/version.h","wb")
f.write("#define VERSION_SHORT_NAME "+str(version.short_name)+"\n")
@@ -1129,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):
@@ -1322,6 +1293,14 @@ def android_module_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):
+ 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):
+ base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file
+ f = open(base_path,"rb")
+ self.android_appattributes_chunk+=f.read()
def disable_module(self):
self.disabled_modules.append(self.current_module)
@@ -1330,7 +1309,7 @@ def save_active_platforms(apnames,ap):
for x in ap:
pth = x+"/logo.png"
- print("open path: "+pth)
+# print("open path: "+pth)
pngf=open(pth,"rb");
b=pngf.read(1);
str=" /* AUTOGENERATED FILE, DO NOT EDIT */ \n"
@@ -1347,3 +1326,39 @@ def save_active_platforms(apnames,ap):
logow = open(wf,"wb")
logow.write(str)
+
+def colored(sys,env):
+
+ #If the output is not a terminal, do nothing
+ if not sys.stdout.isatty():
+ return
+
+ colors = {}
+ colors['cyan'] = '\033[96m'
+ colors['purple'] = '\033[95m'
+ colors['blue'] = '\033[94m'
+ colors['green'] = '\033[92m'
+ colors['yellow'] = '\033[93m'
+ colors['red'] = '\033[91m'
+ colors['end'] = '\033[0m'
+
+ compile_source_message = '%sCompiling %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
+ java_compile_source_message = '%sCompiling %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
+ compile_shared_source_message = '%sCompiling shared %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
+ link_program_message = '%sLinking Program %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+ link_library_message = '%sLinking Static Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+ ranlib_library_message = '%sRanlib Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+ link_shared_library_message = '%sLinking Shared Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+ java_library_message = '%sCreating Java Archive %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+
+ env.Append( CXXCOMSTR=[compile_source_message] )
+ env.Append( CCCOMSTR=[compile_source_message] )
+ env.Append( SHCCCOMSTR=[compile_shared_source_message] )
+ env.Append( SHCXXCOMSTR=[compile_shared_source_message] )
+ env.Append( ARCOMSTR=[link_library_message] )
+ env.Append( RANLIBCOMSTR=[ranlib_library_message] )
+ env.Append( SHLINKCOMSTR=[link_shared_library_message] )
+ env.Append( LINKCOMSTR=[link_program_message] )
+ env.Append( JARCOMSTR=[java_library_message] )
+ env.Append( JAVACCOMSTR=[java_compile_source_message] )
+
diff --git a/modules/SCsub b/modules/SCsub
index 9b42a14e31..9215bfd48f 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -16,8 +16,6 @@ for x in env.module_list:
env_modules.Append(CPPFLAGS=["-DMODULE_"+x.upper()+"_ENABLED"])
SConscript(x+"/SCsub")
-lib = env_modules.Library("modules",env.modules_sources, LIBSUFFIX=env['platform_libsuffix'])
+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 9cbbaf2fcf..a62225f663 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,15 +28,6 @@
/*************************************************************************/
#include "gd_compiler.h"
#include "gd_script.h"
-/* TODO:
-
- *AND and OR need early abort
- -Inheritance properly process (done?)
- *create built in initializer and constructor
- *assign operators
- *build arrays and dictionaries
- *call parent constructor
- */
void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) {
@@ -45,8 +36,13 @@ void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node)
return;
error=p_error;
- err_line=p_node->line;
- err_column=p_node->column;
+ if (p_node) {
+ err_line=p_node->line;
+ err_column=p_node->column;
+ } else {
+ err_line=0;
+ err_column=0;
+ }
}
bool GDCompiler::_create_unary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level) {
@@ -60,22 +56,23 @@ bool GDCompiler::_create_unary_operator(CodeGen& codegen,const GDParser::Operato
codegen.opcodes.push_back(GDFunction::OPCODE_OPERATOR); // perform operator
codegen.opcodes.push_back(op); //which operator
codegen.opcodes.push_back(src_address_a); // argument 1
- codegen.opcodes.push_back(GDFunction::ADDR_TYPE_NIL); // argument 2 (unary only takes one parameter)
+ codegen.opcodes.push_back(src_address_a); // argument 2 (repeated)
+ //codegen.opcodes.push_back(GDFunction::ADDR_TYPE_NIL); // argument 2 (unary only takes one parameter)
return true;
}
-bool GDCompiler::_create_binary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level) {
+bool GDCompiler::_create_binary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level,bool p_initializer) {
ERR_FAIL_COND_V(on->arguments.size()!=2,false);
- int src_address_a = _parse_expression(codegen,on->arguments[0],p_stack_level);
+ int src_address_a = _parse_expression(codegen,on->arguments[0],p_stack_level,false,p_initializer);
if (src_address_a<0)
return false;
if (src_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)
p_stack_level++; //uses stack for return, increase stack
- int src_address_b = _parse_expression(codegen,on->arguments[1],p_stack_level);
+ int src_address_b = _parse_expression(codegen,on->arguments[1],p_stack_level,false,p_initializer);
if (src_address_b<0)
return false;
@@ -110,6 +107,7 @@ int GDCompiler::_parse_assign_right_expression(CodeGen& codegen,const GDParser::
Variant::Operator var_op=Variant::OP_MAX;
+
switch(p_expression->op) {
case GDParser::OperatorNode::OP_ASSIGN_ADD: var_op=Variant::OP_ADD; break;
@@ -122,6 +120,7 @@ int GDCompiler::_parse_assign_right_expression(CodeGen& codegen,const GDParser::
case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: var_op=Variant::OP_BIT_AND; break;
case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: var_op=Variant::OP_BIT_OR; break;
case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: var_op=Variant::OP_BIT_XOR; break;
+ case GDParser::OperatorNode::OP_INIT_ASSIGN:
case GDParser::OperatorNode::OP_ASSIGN: {
//none
@@ -132,12 +131,14 @@ int GDCompiler::_parse_assign_right_expression(CodeGen& codegen,const GDParser::
}
}
+ bool initializer = p_expression->op==GDParser::OperatorNode::OP_INIT_ASSIGN;
+
if (var_op==Variant::OP_MAX) {
- return _parse_expression(codegen,p_expression->arguments[1],p_stack_level);
+ return _parse_expression(codegen,p_expression->arguments[1],p_stack_level,false,initializer);
}
- if (!_create_binary_operator(codegen,p_expression,var_op,p_stack_level))
+ if (!_create_binary_operator(codegen,p_expression,var_op,p_stack_level,initializer))
return -1;
int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS);
@@ -147,7 +148,7 @@ int GDCompiler::_parse_assign_right_expression(CodeGen& codegen,const GDParser::
}
-int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expression, int p_stack_level,bool p_root) {
+int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expression, int p_stack_level,bool p_root,bool p_initializer) {
switch(p_expression->type) {
@@ -164,21 +165,20 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
StringName identifier = in->name;
// TRY STACK!
- if (codegen.stack_identifiers.has(identifier)) {
+ if (!p_initializer && codegen.stack_identifiers.has(identifier)) {
int pos = codegen.stack_identifiers[identifier];
return pos|(GDFunction::ADDR_TYPE_STACK_VARIABLE<<GDFunction::ADDR_BITS);
}
- //TRY ARGUMENTS!
+ //TRY MEMBERS!
if (!codegen.function_node || !codegen.function_node->_static) {
// TRY MEMBER VARIABLES!
-
//static function
if (codegen.script->member_indices.has(identifier)) {
- int idx = codegen.script->member_indices[identifier];
+ int idx = codegen.script->member_indices[identifier].index;
return idx|(GDFunction::ADDR_TYPE_MEMBER<<GDFunction::ADDR_BITS); //argument (stack root)
}
}
@@ -507,6 +507,34 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
codegen.opcodes.push_back(arguments[i]);
}
} break;
+ case GDParser::OperatorNode::OP_YIELD: {
+
+
+ ERR_FAIL_COND_V(on->arguments.size() && on->arguments.size()!=2,-1);
+
+ Vector<int> arguments;
+ int slevel = p_stack_level;
+ for(int i=0;i<on->arguments.size();i++) {
+
+ int ret = _parse_expression(codegen,on->arguments[i],slevel);
+ if (ret<0)
+ return ret;
+ if (ret&(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)) {
+ slevel++;
+ codegen.alloc_stack(slevel);
+ }
+ arguments.push_back(ret);
+ }
+
+ //push call bytecode
+ codegen.opcodes.push_back(arguments.size()==0?GDFunction::OPCODE_YIELD:GDFunction::OPCODE_YIELD_SIGNAL); // basic type constructor
+ for(int i=0;i<arguments.size();i++)
+ codegen.opcodes.push_back(arguments[i]); //arguments
+ codegen.opcodes.push_back(GDFunction::OPCODE_YIELD_RESUME);
+ //next will be where to place the result :)
+
+ } break;
+
//indexing operator
case GDParser::OperatorNode::OP_INDEX:
case GDParser::OperatorNode::OP_INDEX_NAMED: {
@@ -522,7 +550,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
int index;
if (named) {
+#ifdef DEBUG_ENABLED
+ if (on->arguments[0]->type==GDParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) {
+ const Map<StringName,GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name);
+ if (MI && MI->get().getter==codegen.function_node->name) {
+ String n = static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name;
+ _set_error("Must use '"+n+"' instead of 'self."+n+"' in getter.",on);
+ return -1;
+ }
+ }
+#endif
index=codegen.get_name_map_pos(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name);
} else {
@@ -644,8 +682,8 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
case GDParser::OperatorNode::OP_BIT_OR: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_OR,p_stack_level)) return -1;} break;
case GDParser::OperatorNode::OP_BIT_XOR: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_XOR,p_stack_level)) return -1;} break;
//shift
- case GDParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break;
- case GDParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break;
+ case GDParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break;
+ case GDParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break;
//assignment operators
case GDParser::OperatorNode::OP_ASSIGN_ADD:
case GDParser::OperatorNode::OP_ASSIGN_SUB:
@@ -657,6 +695,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
case GDParser::OperatorNode::OP_ASSIGN_BIT_AND:
case GDParser::OperatorNode::OP_ASSIGN_BIT_OR:
case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR:
+ case GDParser::OperatorNode::OP_INIT_ASSIGN:
case GDParser::OperatorNode::OP_ASSIGN: {
ERR_FAIL_COND_V(on->arguments.size()!=2,-1);
@@ -665,6 +704,25 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
if (on->arguments[0]->type==GDParser::Node::TYPE_OPERATOR && (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX || static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED)) {
//SET (chained) MODE!!
+
+#ifdef DEBUG_ENABLED
+ if (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED) {
+ const GDParser::OperatorNode* inon = static_cast<GDParser::OperatorNode*>(on->arguments[0]);
+
+
+ if (inon->arguments[0]->type==GDParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) {
+
+ const Map<StringName,GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDParser::IdentifierNode*>(inon->arguments[1])->name);
+ if (MI && MI->get().setter==codegen.function_node->name) {
+ String n = static_cast<GDParser::IdentifierNode*>(inon->arguments[1])->name;
+ _set_error("Must use '"+n+"' instead of 'self."+n+"' in setter.",inon);
+ return -1;
+ }
+ }
+ }
+#endif
+
+
int slevel=p_stack_level;
GDParser::OperatorNode* op = static_cast<GDParser::OperatorNode*>(on->arguments[0]);
@@ -695,6 +753,8 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
return prev_pos;
int retval=prev_pos;
+ //print_line("retval: "+itos(retval));
+
if (retval&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) {
slevel++;
codegen.alloc_stack(slevel);
@@ -703,6 +763,8 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
Vector<int> setchain;
+ int prev_key_idx=-1;
+
for(List<GDParser::OperatorNode*>::Element *E=chain.back();E;E=E->prev()) {
@@ -714,16 +776,23 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
if (named) {
- key_idx = codegen.get_name_map_pos(static_cast<const GDParser::IdentifierNode*>(E->get()->arguments[1])->name);
+ key_idx = codegen.get_name_map_pos(static_cast<const GDParser::IdentifierNode*>(E->get()->arguments[1])->name);
+ //printf("named key %x\n",key_idx);
+
} else {
- GDParser::Node *key = E->get()->arguments[1];
- key_idx = _parse_expression(codegen,key,slevel);
- if (retval&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) {
+ if (prev_pos&(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)) {
slevel++;
codegen.alloc_stack(slevel);
}
+ GDParser::Node *key = E->get()->arguments[1];
+ key_idx = _parse_expression(codegen,key,slevel);
+ //printf("expr key %x\n",key_idx);
+
+
+ //stack was raised here if retval was stack but..
+
}
if (key_idx<0)
@@ -735,6 +804,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
slevel++;
codegen.alloc_stack(slevel);
int dst_pos = (GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)|slevel;
+
codegen.opcodes.push_back(dst_pos);
//add in reverse order, since it will be reverted
@@ -744,6 +814,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
setchain.push_back(named ? GDFunction::OPCODE_SET_NAMED : GDFunction::OPCODE_SET);
prev_pos=dst_pos;
+ prev_key_idx=key_idx;
}
@@ -801,7 +872,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
int slevel = p_stack_level;
- int dst_address_a = _parse_expression(codegen,on->arguments[0],slevel);
+ int dst_address_a = _parse_expression(codegen,on->arguments[0],slevel,false,on->op==GDParser::OperatorNode::OP_INIT_ASSIGN);
if (dst_address_a<0)
return -1;
@@ -1122,6 +1193,7 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
codegen.current_line=0;
codegen.call_max=0;
codegen.debug_stack=ScriptDebugger::get_singleton()!=NULL;
+ Vector<StringName> argnames;
int stack_level=0;
@@ -1129,6 +1201,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
for(int i=0;i<p_func->arguments.size();i++) {
int idx = i;
codegen.add_stack_identifier(p_func->arguments[i],i);
+#ifdef TOOLS_ENABLED
+ argnames.push_back(p_func->arguments[i]);
+#endif
}
stack_level=p_func->arguments.size();
}
@@ -1203,6 +1278,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
if (p_func)
gdfunc->_static=p_func->_static;
+#ifdef TOOLS_ENABLED
+ gdfunc->arg_names=argnames;
+#endif
//constants
if (codegen.constant_map.size()) {
gdfunc->_constant_count=codegen.constant_map.size();
@@ -1310,13 +1388,14 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
int index_from=0;
+ Ref<GDNativeClass> native;
if (p_class->extends_used) {
//do inheritance
String path = p_class->extends_file;
Ref<GDScript> script;
- Ref<GDNativeClass> native;
+
if (path!="") {
//path (and optionally subclasses)
@@ -1328,7 +1407,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
_set_error("Could not resolve relative path for parent class: "+path,p_class);
return ERR_FILE_NOT_FOUND;
}
- path=base.get_base_dir().plus_file(path);
+ path=base.get_base_dir().plus_file(path).simplify_path();
}
script = ResourceLoader::load(path);
if (script.is_null()) {
@@ -1443,7 +1522,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
}
- print_line("Script: "+p_script->get_path()+" indices: "+itos(p_script->member_indices.size()));
+ //print_line("Script: "+p_script->get_path()+" indices: "+itos(p_script->member_indices.size()));
for(int i=0;i<p_class->variables.size();i++) {
@@ -1465,8 +1544,12 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
#endif
}
- int new_idx = p_script->member_indices.size();
- p_script->member_indices[name]=new_idx;
+ //int new_idx = p_script->member_indices.size();
+ GDScript::MemberInfo minfo;
+ minfo.index = p_script->member_indices.size();
+ minfo.setter = p_class->variables[i].setter;
+ minfo.getter = p_class->variables[i].getter;
+ p_script->member_indices[name]=minfo;
p_script->members.insert(name);
}
@@ -1482,7 +1565,35 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
//p_script->constants[constant->value].make_const();
}
+ for(int i=0;i<p_class->_signals.size();i++) {
+
+ StringName name = p_class->_signals[i].name;
+
+ GDScript *c = p_script;
+
+ while(c) {
+ if (c->_signals.has(name)) {
+ _set_error("Signal '"+name+"' redefined (in current or parent class)",p_class);
+ return ERR_ALREADY_EXISTS;
+ }
+
+ if (c->base.is_valid()) {
+ c=c->base.ptr();
+ } else {
+ c=NULL;
+ }
+ }
+
+ if (native.is_valid()) {
+ if (ObjectTypeDB::has_signal(native->get_name(),name)) {
+ _set_error("Signal '"+name+"' redefined (original in native class '"+String(native->get_name())+"')",p_class);
+ return ERR_ALREADY_EXISTS;
+ }
+ }
+
+ p_script->_signals[name]=p_class->_signals[i].arguments;
+ }
//parse sub-classes
for(int i=0;i<p_class->subclasses.size();i++) {
@@ -1529,6 +1640,48 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
return err;
}
+#ifdef DEBUG_ENABLED
+ //validate setters/getters if debug is enabled
+ for(int i=0;i<p_class->variables.size();i++) {
+
+ if (p_class->variables[i].setter) {
+ const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().find(p_class->variables[i].setter);
+ if (!E) {
+ _set_error("Setter function '"+String(p_class->variables[i].setter)+"' not found in class.",NULL);
+ err_line=p_class->variables[i].line;
+ err_column=0;
+ return ERR_PARSE_ERROR;
+ }
+
+ if (E->get().is_static()) {
+
+ _set_error("Setter function '"+String(p_class->variables[i].setter)+"' is static.",NULL);
+ err_line=p_class->variables[i].line;
+ err_column=0;
+ return ERR_PARSE_ERROR;
+ }
+
+ }
+ if (p_class->variables[i].getter) {
+ const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().find(p_class->variables[i].getter);
+ if (!E) {
+ _set_error("Getter function '"+String(p_class->variables[i].getter)+"' not found in class.",NULL);
+ err_line=p_class->variables[i].line;
+ err_column=0;
+ return ERR_PARSE_ERROR;
+ }
+
+ if (E->get().is_static()) {
+
+ _set_error("Getter function '"+String(p_class->variables[i].getter)+"' is static.",NULL);
+ err_line=p_class->variables[i].line;
+ err_column=0;
+ return ERR_PARSE_ERROR;
+ }
+
+ }
+ }
+#endif
return OK;
}
diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h
index cda221dab0..bdf4e9816a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -37,77 +37,65 @@ class GDCompiler {
const GDParser *parser;
struct CodeGen {
-
-
GDScript *script;
const GDParser::ClassNode *class_node;
const GDParser::FunctionNode *function_node;
-
-
- bool debug_stack;
-
-
- List< Map<StringName,int> > stack_id_stack;
- Map<StringName,int> stack_identifiers;
-
- List<GDFunction::StackDebug> stack_debug;
- List< Map<StringName,int> > block_identifier_stack;
- Map<StringName,int> block_identifiers;
-
-
- void add_stack_identifier(const StringName& p_id,int p_stackpos) {
-
- stack_identifiers[p_id]=p_stackpos;
- if (debug_stack) {
-
- block_identifiers[p_id]=p_stackpos;
- GDFunction::StackDebug sd;
- sd.added=true;
- sd.line=current_line;
- sd.identifier=p_id;
- sd.pos=p_stackpos;
- stack_debug.push_back(sd);
- }
- }
-
- void push_stack_identifiers() {
-
- stack_id_stack.push_back( stack_identifiers );
- if (debug_stack) {
-
- block_identifier_stack.push_back(block_identifiers);
- block_identifiers.clear();
- }
- }
-
- void pop_stack_identifiers() {
-
- stack_identifiers = stack_id_stack.back()->get();
- stack_id_stack.pop_back();
-
- if (debug_stack) {
- for (Map<StringName,int>::Element *E=block_identifiers.front();E;E=E->next()) {
-
- GDFunction::StackDebug sd;
- sd.added=false;
- sd.identifier=E->key();
- sd.line=current_line;
- sd.pos=E->get();
- stack_debug.push_back(sd);
- }
- block_identifiers=block_identifier_stack.back()->get();
- block_identifier_stack.pop_back();
- }
-
- }
-
-
- // int get_identifier_pos(const StringName& p_dentifier) const;
+ bool debug_stack;
+
+ List< Map<StringName,int> > stack_id_stack;
+ Map<StringName,int> stack_identifiers;
+
+ List<GDFunction::StackDebug> stack_debug;
+ List< Map<StringName,int> > block_identifier_stack;
+ Map<StringName,int> block_identifiers;
+
+ void add_stack_identifier(const StringName& p_id,int p_stackpos) {
+ stack_identifiers[p_id]=p_stackpos;
+ if (debug_stack) {
+ block_identifiers[p_id]=p_stackpos;
+ GDFunction::StackDebug sd;
+ sd.added=true;
+ sd.line=current_line;
+ sd.identifier=p_id;
+ sd.pos=p_stackpos;
+ stack_debug.push_back(sd);
+ }
+ }
+
+ void push_stack_identifiers() {
+ stack_id_stack.push_back( stack_identifiers );
+ if (debug_stack) {
+
+ block_identifier_stack.push_back(block_identifiers);
+ block_identifiers.clear();
+ }
+ }
+
+ void pop_stack_identifiers() {
+ stack_identifiers = stack_id_stack.back()->get();
+ stack_id_stack.pop_back();
+
+ if (debug_stack) {
+ for (Map<StringName,int>::Element *E=block_identifiers.front();E;E=E->next()) {
+
+ GDFunction::StackDebug sd;
+ sd.added=false;
+ sd.identifier=E->key();
+ sd.line=current_line;
+ sd.pos=E->get();
+ stack_debug.push_back(sd);
+ }
+ block_identifiers=block_identifier_stack.back()->get();
+ block_identifier_stack.pop_back();
+ }
+ }
+
+
+ //int get_identifier_pos(const StringName& p_dentifier) const;
HashMap<Variant,int,VariantHasher> constant_map;
Map<StringName,int> name_map;
int get_name_map_pos(const StringName& p_identifier) {
-
int ret;
if (!name_map.has(p_identifier)) {
ret=name_map.size();
@@ -118,11 +106,7 @@ class GDCompiler {
return ret;
}
-
-
int get_constant_pos(const Variant& p_constant) {
-
-
if (constant_map.has(p_constant))
return constant_map[p_constant];
int pos = constant_map.size();
@@ -134,7 +118,7 @@ class GDCompiler {
void alloc_stack(int p_level) { if (p_level >= stack_max) stack_max=p_level+1; }
void alloc_call(int p_params) { if (p_params >= call_max) call_max=p_params; }
- int current_line;
+ int current_line;
int stack_max;
int call_max;
};
@@ -153,11 +137,11 @@ class GDCompiler {
void _set_error(const String& p_error,const GDParser::Node *p_node);
bool _create_unary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level);
- bool _create_binary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level);
+ bool _create_binary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level,bool p_initializer=false);
//int _parse_subexpression(CodeGen& codegen,const GDParser::BlockNode *p_block,const GDParser::Node *p_expression);
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);
+ 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_class(GDScript *p_script,GDScript *p_owner,const GDParser::ClassNode *p_class);
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index a98b07ab92..381edcba50 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,11 +28,13 @@
/*************************************************************************/
#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 {
p_delimiters->push_back("#");
+ p_delimiters->push_back("\"\"\" \"\"\"");
}
void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
@@ -50,7 +52,7 @@ String GDScriptLanguage::get_template(const String& p_class_name, const String&
"# var a=2\n"+
"# var b=\"textvar\"\n\n"+
"func _ready():\n"+
- "\t# Initalization here\n"+
+ "\t# Initialization here\n"+
"\tpass\n"+
"\n"+
"\n";
@@ -65,7 +67,7 @@ bool GDScriptLanguage::validate(const String& p_script, int &r_line_error,int &r
GDParser parser;
- Error err = parser.parse(p_script,p_path.get_base_dir(),true);
+ Error err = parser.parse(p_script,p_path.get_base_dir(),true,p_path);
if (err) {
r_line_error=parser.get_error_line();
r_col_error=parser.get_error_column();
@@ -114,6 +116,7 @@ int GDScriptLanguage::find_function(const String& p_function,const String& p_cod
if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE) {
indent=tokenizer.get_token_line_indent();
}
+ //print_line("TOKEN: "+String(GDTokenizer::get_token_name(tokenizer.get_token())));
if (indent==0 && tokenizer.get_token()==GDTokenizer::TK_PR_FUNCTION && tokenizer.get_token(1)==GDTokenizer::TK_IDENTIFIER) {
String identifier = tokenizer.get_token_identifier(1);
@@ -122,6 +125,8 @@ int GDScriptLanguage::find_function(const String& p_function,const String& p_cod
}
}
tokenizer.advance();
+ //print_line("NEXT: "+String(GDTokenizer::get_token_name(tokenizer.get_token())));
+
}
return -1;
}
@@ -234,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,int>& mi = script->debug_get_member_indices();
+ const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices();
- for(const Map<StringName,int>::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()));
- }
+ 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) {
@@ -308,485 +313,2052 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam
}
-static void _parse_native_symbols(const StringName& p_native,bool p_static,List<String>* r_options) {
+#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
- if (!p_static) {
- List<MethodInfo> methods;
- ObjectTypeDB::get_method_list(p_native,&methods);
- for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
- if (!E->get().name.begins_with("_")) {
- r_options->push_back(E->get().name);
- }
+struct GDCompletionIdentifier {
+
+ StringName obj_type;
+ Ref<GDScript> script;
+ Variant::Type type;
+ Variant value; //im case there is a value, also return it
+};
+
+
+
+static GDCompletionIdentifier _get_type_from_variant(const Variant& p_variant) {
+
+ GDCompletionIdentifier t;
+ t.type=p_variant.get_type();
+ t.value=p_variant;
+ if (p_variant.get_type()==Variant::OBJECT) {
+ Object *obj = p_variant;
+ if (obj) {
+ //if (obj->cast_to<GDNativeClass>()) {
+ // t.obj_type=obj->cast_to<GDNativeClass>()->get_name();
+ // t.value=Variant();
+ //} else {
+ t.obj_type=obj->get_type();
+ //}
}
}
+ return t;
+}
- List<String> constants;
- ObjectTypeDB::get_integer_constant_list(p_native,&constants);
+static GDCompletionIdentifier _get_type_from_pinfo(const PropertyInfo& p_info) {
- for(List<String>::Element *E=constants.front();E;E=E->next()) {
- r_options->push_back(E->get());
+ GDCompletionIdentifier t;
+ t.type=p_info.type;
+ if (p_info.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+ t.obj_type=p_info.hint_string;
}
-
+ return t;
}
+struct GDCompletionContext {
-static bool _parse_script_symbols(const Ref<GDScript>& p_script,bool p_static,List<String>* r_options,List<String>::Element *p_indices);
+ const GDParser::ClassNode *_class;
+ const GDParser::FunctionNode *function;
+ const GDParser::BlockNode *block;
+ Object* base;
+ String base_path;
+};
-static bool _parse_completion_variant(const Variant& p_var,List<String>* r_options,List<String>::Element *p_indices) {
- if (p_indices) {
+static Ref<Reference> _get_parent_class(GDCompletionContext& context) {
- bool ok;
- Variant si = p_var.get(p_indices->get(),&ok);
- if (!ok)
- return false;
- return _parse_completion_variant(si,r_options,p_indices->next());
- } else {
- switch(p_var.get_type()) {
+ if (context._class->extends_used) {
+ //do inheritance
+ String path = context._class->extends_file;
+
+ Ref<GDScript> script;
+ Ref<GDNativeClass> native;
+
+ if (path!="") {
+ //path (and optionally subclasses)
+
+ if (path.is_rel_path()) {
- case Variant::DICTIONARY: {
+ path=context.base_path.plus_file(path);
+ }
- Dictionary d=p_var;
- List<Variant> vl;
- d.get_key_list(&vl);
- for (List<Variant>::Element *E=vl.front();E;E=E->next()) {
+ if (ScriptCodeCompletionCache::get_sigleton())
+ script = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path);
+ else
+ script = ResourceLoader::load(path);
- if (E->get().get_type()==Variant::STRING)
- r_options->push_back(E->get());
- }
+ if (script.is_null()) {
+ return REF();
+ }
+ if (script->is_valid()) {
+
+ return REF();
+ }
+ //print_line("EXTENDS PATH: "+path+" script is "+itos(script.is_valid())+" indices is "+itos(script->member_indices.size())+" valid? "+itos(script->valid));
+
+ if (context._class->extends_class.size()) {
+ for(int i=0;i<context._class->extends_class.size();i++) {
- List<MethodInfo> ml;
- p_var.get_method_list(&ml);
- for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
- r_options->push_back(E->get().name);
+ String sub = context._class->extends_class[i];
+ if (script->get_subclasses().has(sub)) {
+
+ script=script->get_subclasses()[sub];
+ } else {
+
+ return REF();
+ }
}
+ }
+
+ if (script.is_valid())
+ return script;
+
+ } else {
+
+ if (context._class->extends_class.size()==0) {
+ ERR_PRINT("BUG");
+ return REF();
+ }
+
+ String base=context._class->extends_class[0];
+ const GDParser::ClassNode *p = context._class->owner;
+ Ref<GDScript> base_class;
+#if 0
+ while(p) {
- } break;
- case Variant::OBJECT: {
+ if (p->subclasses.has(base)) {
+ base_class=p->subclasses[base];
+ break;
+ }
+ p=p->_owner;
+ }
+#endif
+ if (base_class.is_valid()) {
+#if 0
+ for(int i=1;i<context._class->extends_class.size();i++) {
- Object *o=p_var;
- if (o) {
- print_line("OBJECT: "+o->get_type());
- if (p_var.is_ref() && o->cast_to<GDScript>()) {
+ String subclass=context._class->extends_class[i];
- Ref<GDScript> gds = p_var;
- _parse_script_symbols(gds,true,r_options,NULL);
- } else if (o->is_type("GDNativeClass")){
+ if (base_class->subclasses.has(subclass)) {
- GDNativeClass *gnc = o->cast_to<GDNativeClass>();
- _parse_native_symbols(gnc->get_name(),false,r_options);
+ base_class=base_class->subclasses[subclass];
} else {
- print_line("REGULAR BLEND");
- _parse_native_symbols(o->get_type(),false,r_options);
+ //print_line("Could not find subclass: "+subclass);
+ return _get_type_from_class(context); //fail please
}
}
- } break;
- default: {
+ script=base_class;
+#endif
+
+ } else {
+
+ if (context._class->extends_class.size()>1) {
+
+ return REF();
+
- List<PropertyInfo> pi;
- p_var.get_property_list(&pi);
- for(List<PropertyInfo>::Element *E=pi.front();E;E=E->next()) {
- r_options->push_back(E->get().name);
}
- List<StringName> cl;
+ //if not found, try engine classes
+ if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
- p_var.get_numeric_constants_for_type(p_var.get_type(),&cl);
- for(List<StringName>::Element *E=cl.front();E;E=E->next()) {
- r_options->push_back(E->get());
+ return REF();
}
- List<MethodInfo> ml;
- p_var.get_method_list(&ml);
- for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
- r_options->push_back(E->get().name);
+ int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base];
+ native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx];
+ if (!native.is_valid()) {
+
+ print_line("Global not a class: '"+base+"'");
+
}
+ return native;
+ }
+
- } break;
}
- return true;
}
+ return Ref<Reference>();
+}
+
+
+static GDCompletionIdentifier _get_native_class(GDCompletionContext& context) {
+
+ //eeh...
+ GDCompletionIdentifier id;
+ id.type=Variant::NIL;
+
+ REF pc = _get_parent_class(context);
+ if (!pc.is_valid()) {
+ return id;
+ }
+ Ref<GDNativeClass> nc = pc;
+ Ref<GDScript> s = pc;
+
+ if (s.is_null() && nc.is_null()) {
+ return id;
+ }
+ while(!s.is_null()) {
+ nc=s->get_native();
+ s=s->get_base();
+ }
+ if (nc.is_null()) {
+ return id;
+ }
+
+
+ id.type=Variant::OBJECT;
+ if (context.base)
+ id.value=context.base;
+ id.obj_type=nc->get_name();
+ return id;
}
+static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type);
-static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_options,List<String>::Element *p_indices) {
+static bool _guess_expression_type(GDCompletionContext& context,const GDParser::Node* p_node,int p_line,GDCompletionIdentifier &r_type) {
if (p_node->type==GDParser::Node::TYPE_CONSTANT) {
const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(p_node);
- _parse_completion_variant(cn->value,r_options,p_indices?p_indices->next():NULL);
+
+ r_type=_get_type_from_variant(cn->value);
+
+ return true;
} else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) {
- const GDParser::DictionaryNode *dn=static_cast<const GDParser::DictionaryNode*>(p_node);
- for(int i=0;i<dn->elements.size();i++) {
+ r_type.type=Variant::DICTIONARY;
- if (dn->elements[i].key->type==GDParser::Node::TYPE_CONSTANT) {
- const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(dn->elements[i].key);
- if (cn->value.get_type()==Variant::STRING) {
+ //what the heck, fill it anyway
+ const GDParser::DictionaryNode *an = static_cast<const GDParser::DictionaryNode *>(p_node);
+ Dictionary d;
+ for(int i=0;i<an->elements.size();i++) {
+ GDCompletionIdentifier k;
+ if (_guess_expression_type(context,an->elements[i].key,p_line,k) && k.value.get_type()!=Variant::NIL) {
+ GDCompletionIdentifier v;
+ if (_guess_expression_type(context,an->elements[i].value,p_line,v)) {
+ d[k.value]=v.value;
+ }
- String str=cn->value;
- if (p_indices) {
+ }
+ }
+ r_type.value=d;
+ return true;
+ } else if (p_node->type==GDParser::Node::TYPE_ARRAY) {
+
+ r_type.type=Variant::ARRAY;
+ //what the heck, fill it anyway
+ const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode *>(p_node);
+ Array arr;
+ arr.resize(an->elements.size());
+ for(int i=0;i<an->elements.size();i++) {
+ GDCompletionIdentifier ci;
+ if (_guess_expression_type(context,an->elements[i],p_line,ci)) {
+ arr[i]=ci.value;
+ }
+ }
+ r_type.value=arr;
+ return true;
- if (str==p_indices->get()) {
- _parse_expression_node(dn->elements[i].value,r_options,p_indices->next());
- return;
+ } else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+
+ MethodInfo mi = GDFunctions::get_info(static_cast<const GDParser::BuiltInFunctionNode*>(p_node)->function);
+ r_type=_get_type_from_pinfo(mi.return_val);
+
+ return true;
+ } else if (p_node->type==GDParser::Node::TYPE_IDENTIFIER) {
+
+ return _guess_identifier_type(context,p_line-1,static_cast<const GDParser::IdentifierNode *>(p_node)->name,r_type);
+ } else if (p_node->type==GDParser::Node::TYPE_SELF) {
+ //eeh...
+
+ r_type=_get_native_class(context);
+ return r_type.type!=Variant::NIL;
+
+ } else if (p_node->type==GDParser::Node::TYPE_OPERATOR) {
+
+
+ const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_node);
+ if (op->op==GDParser::OperatorNode::OP_CALL) {
+ if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
+
+ const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode *>(op->arguments[0]);
+ r_type.type=tn->vtype;
+ return true;
+ } else if (op->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+
+
+ const GDParser::BuiltInFunctionNode *bin = static_cast<const GDParser::BuiltInFunctionNode *>(op->arguments[0]);
+ return _guess_expression_type(context,bin,p_line,r_type);
+
+ } else if (op->arguments.size()>1 && op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {
+
+
+ GDCompletionIdentifier base;
+ if (!_guess_expression_type(context,op->arguments[0],p_line,base))
+ return false;
+
+ StringName id = static_cast<const GDParser::IdentifierNode *>(op->arguments[1])->name;
+
+ if (base.type==Variant::OBJECT) {
+
+ if (id.operator String()=="new" && base.value.get_type()==Variant::OBJECT) {
+ Object *obj = base.value;
+ if (obj && obj->cast_to<GDNativeClass>()) {
+ GDNativeClass *gdnc = obj->cast_to<GDNativeClass>();
+ r_type.type=Variant::OBJECT;
+ r_type.value=Variant();
+ r_type.obj_type=gdnc->get_name();
+ return true;
}
+ }
+
+ if (ObjectTypeDB::has_method(base.obj_type,id)) {
+
+#ifdef TOOLS_ENABLED
+ MethodBind *mb = ObjectTypeDB::get_method(base.obj_type,id);
+ PropertyInfo pi = mb->get_argument_info(-1);
+
+ //try calling the function if constant and all args are constant, should not crash..
+ Object *baseptr = base.value;
+
+
+ if (mb->is_const() && pi.type==Variant::OBJECT) {
+
+ bool all_valid=true;
+ Vector<Variant> args;
+ for(int i=2;i<op->arguments.size();i++) {
+ GDCompletionIdentifier arg;
+
+ if (_guess_expression_type(context,op->arguments[i],p_line,arg)) {
+ if (arg.value.get_type()!=Variant::NIL && arg.value.get_type()!=Variant::OBJECT) { // calling with object seems dangerous, i don' t know
+ args.push_back(arg.value);
+ } else {
+ all_valid=false;
+ break;
+ }
+ } else {
+ all_valid=false;
+ }
+ }
+
+ 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)) {
+
+ //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;
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ 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;
+ }
+ }
+
+ }
+ }
+ }
+
+ r_type.type=pi.type;
+ if (pi.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+ r_type.obj_type=pi.hint_string;
+ }
+
+
+
+ return true;
+#else
+ return false;
+#endif
} else {
- r_options->push_back(str);
+ return false;
+ }
+ } else {
+ //method for some variant..
+ Variant::CallError ce;
+ Variant v = Variant::construct(base.type,NULL,0,ce);
+ List<MethodInfo> mi;
+ v.get_method_list(&mi);
+ for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+
+ if (!E->get().name.begins_with("_") && E->get().name==id.operator String()) {
+
+
+ MethodInfo mi = E->get();
+ r_type.type=mi.return_val.type;
+ if (mi.return_val.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+ r_type.obj_type=mi.return_val.hint_string;
+ }
+ return true;
+ }
}
+
}
+
+
}
- }
- }
-}
+ } else if (op->op==GDParser::OperatorNode::OP_INDEX || op->op==GDParser::OperatorNode::OP_INDEX_NAMED) {
-static bool _parse_completion_block(const GDParser::BlockNode *p_block,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
+ GDCompletionIdentifier p1;
+ GDCompletionIdentifier p2;
- for(int i=0;i<p_block->sub_blocks.size();i++) {
- //parse inner first
- if (p_line>=p_block->sub_blocks[i]->line && (p_line<=p_block->sub_blocks[i]->end_line || p_block->sub_blocks[i]->end_line==-1)) {
- if (_parse_completion_block(p_block->sub_blocks[i],p_line,r_options,p_indices))
- return true;
- }
- }
- if (p_indices) {
- //parse indices in expressions :|
- for (int i=0;i<p_block->statements.size();i++) {
+ if (op->op==GDParser::OperatorNode::OP_INDEX_NAMED) {
- if (p_block->statements[i]->line>p_line)
- break;
+ if (op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {
+ String id = static_cast<const GDParser::IdentifierNode*>(op->arguments[1])->name;
+ p2.type=Variant::STRING;
+ p2.value=id;
+ }
+
+ } else {
+ if (op->arguments[1]) {
+ if (!_guess_expression_type(context,op->arguments[1],p_line,p2)) {
+
+ return false;
+ }
+ }
+ }
- if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
+ if (op->arguments[0]->type==GDParser::Node::TYPE_ARRAY) {
- const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]);
- if (lv->assign && String(lv->name)==p_indices->get()) {
+ const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode *>(op->arguments[0]);
+ if (p2.value.is_num()) {
+ int index = p2.value;
+ if (index<0 || index>=an->elements.size())
+ return false;
+ return _guess_expression_type(context,an->elements[index],p_line,r_type);
+ }
- _parse_expression_node(lv->assign,r_options,p_indices->next());
- return true;
+ } else if (op->arguments[0]->type==GDParser::Node::TYPE_DICTIONARY) {
+
+ const GDParser::DictionaryNode *dn = static_cast<const GDParser::DictionaryNode *>(op->arguments[0]);
+
+ if (p2.value.get_type()==Variant::NIL)
+ return false;
+
+ for(int i=0;i<dn->elements.size();i++) {
+
+ GDCompletionIdentifier k;
+
+ if (!_guess_expression_type(context,dn->elements[i].key,p_line,k)) {
+
+ return false;
+ }
+
+ if (k.value.get_type()==Variant::NIL)
+ return false;
+
+ if (k.value==p2.value) {
+
+ return _guess_expression_type(context,dn->elements[i].value,p_line,r_type);
+ }
+ }
+
+ } else {
+
+ if (op->arguments[0]) {
+ if (!_guess_expression_type(context,op->arguments[0],p_line,p1)) {
+
+ return false;
+ }
+
+ }
+
+ if (p1.value.get_type()==Variant::OBJECT) {
+ //??
+ } else if (p1.value.get_type()!=Variant::NIL) {
+
+ bool valid;
+ Variant ret = p1.value.get(p2.value,&valid);
+ if (valid) {
+ r_type=_get_type_from_variant(ret);
+ return true;
+ }
+
+ } else {
+ if (p1.type!=Variant::NIL) {
+ Variant::CallError ce;
+ Variant base = Variant::construct(p1.type,NULL,0,ce);
+ bool valid;
+ Variant ret = base.get(p2.value,&valid);
+ if (valid) {
+ r_type=_get_type_from_variant(ret);
+ return true;
+ }
+ }
}
}
- }
- } else {
- for(int i=0;i<p_block->variables.size();i++) {
- //parse variables second
- if (p_line>=p_block->variable_lines[i]) {
- r_options->push_back(p_block->variables[i]);
+ } else {
+
+
+ Variant::Operator vop = Variant::OP_MAX;
+ switch(op->op) {
+ case GDParser::OperatorNode::OP_ADD: vop=Variant::OP_ADD; break;
+ case GDParser::OperatorNode::OP_SUB: vop=Variant::OP_SUBSTRACT; break;
+ case GDParser::OperatorNode::OP_MUL: vop=Variant::OP_MULTIPLY; break;
+ case GDParser::OperatorNode::OP_DIV: vop=Variant::OP_DIVIDE; break;
+ case GDParser::OperatorNode::OP_MOD: vop=Variant::OP_MODULE; break;
+ case GDParser::OperatorNode::OP_SHIFT_LEFT: vop=Variant::OP_SHIFT_LEFT; break;
+ case GDParser::OperatorNode::OP_SHIFT_RIGHT: vop=Variant::OP_SHIFT_RIGHT; break;
+ case GDParser::OperatorNode::OP_BIT_AND: vop=Variant::OP_BIT_AND; break;
+ case GDParser::OperatorNode::OP_BIT_OR: vop=Variant::OP_BIT_OR; break;
+ case GDParser::OperatorNode::OP_BIT_XOR: vop=Variant::OP_BIT_XOR; break;
+ default:{}
+
+ }
+
+
+
+ if (vop==Variant::OP_MAX)
+ return false;
+
+
+
+ GDCompletionIdentifier p1;
+ GDCompletionIdentifier p2;
+
+ if (op->arguments[0]) {
+ if (!_guess_expression_type(context,op->arguments[0],p_line,p1)) {
+
+ return false;
+ }
+
+ }
+
+ if (op->arguments.size()>1) {
+ if (!_guess_expression_type(context,op->arguments[1],p_line,p2)) {
+
+ return false;
+ }
+ }
+
+ Variant::CallError ce;
+ bool v1_use_value = p1.value.get_type()!=Variant::NIL && p1.value.get_type()!=Variant::OBJECT;
+ Variant v1 = (v1_use_value)?p1.value:Variant::construct(p1.type,NULL,0,ce);
+ bool v2_use_value = p2.value.get_type()!=Variant::NIL && p2.value.get_type()!=Variant::OBJECT;
+ Variant v2 = (v2_use_value)?p2.value:Variant::construct(p2.type,NULL,0,ce);
+ // avoid potential invalid ops
+ if ((vop==Variant::OP_DIVIDE || vop==Variant::OP_MODULE) && v2.get_type()==Variant::INT) {
+ v2=1;
+ v2_use_value=false;
}
- else break;
+ if (vop==Variant::OP_DIVIDE && v2.get_type()==Variant::REAL) {
+ v2=1.0;
+ v2_use_value=false;
+ }
+
+ Variant r;
+ bool valid;
+ Variant::evaluate(vop,v1,v2,r,valid);
+ if (!valid)
+ return false;
+ r_type.type=r.get_type();
+ if (v1_use_value && v2_use_value)
+ r_type.value=r;
+
+ return true;
}
+
}
return false;
}
+static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
-static bool _parse_script_symbols(const Ref<GDScript>& p_script,bool p_static,List<String>* r_options,List<String>::Element *p_indices) {
- //for (Map<StringName,Ref<GDScript> >::Element ?
- if (!p_static && !p_indices) {
- for(const Set<StringName>::Element *E=p_script->get_members().front();E;E=E->next()) {
+ const GDParser::Node *last_assign=NULL;
+ int last_assign_line=-1;
- r_options->push_back(E->get());
- }
- }
+ for (int i=0;i<context.block->statements.size();i++) {
- for (const Map<StringName,Variant >::Element *E=p_script->get_constants().front();E;E=E->next()) {
+ if (context.block->statements[i]->line>p_line)
+ continue;
- if( p_indices) {
- if (p_indices->get()==String(E->get())) {
- _parse_completion_variant(E->get(),r_options,p_indices->next());
- return true;
+
+ if (context.block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
+
+ const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(context.block->statements[i]);
+
+ if (lv->assign && lv->name==p_identifier) {
+
+ last_assign=lv->assign;
+ last_assign_line=context.block->statements[i]->line;
}
- } else {
- r_options->push_back(E->key());
}
- }
- if (!p_indices){
- for (const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().front();E;E=E->next()) {
+ if (context.block->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) {
+ const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(context.block->statements[i]);
+ if (op->op==GDParser::OperatorNode::OP_ASSIGN) {
+
+ if (op->arguments.size() && op->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) {
- if (E->get().is_static() || !p_static)
- r_options->push_back(E->key());
+ const GDParser::IdentifierNode *id = static_cast<const GDParser::IdentifierNode *>(op->arguments[0]);
+
+ if (id->name==p_identifier) {
+
+ last_assign=op->arguments[1];
+ last_assign_line=context.block->statements[i]->line;
+ }
+ }
+ }
}
}
- if (p_script->get_base().is_valid()){
- if (_parse_script_symbols(p_script->get_base(),p_static,r_options,p_indices))
- return true;
- } else if (p_script->get_native().is_valid() && !p_indices) {
- _parse_native_symbols(p_script->get_native()->get_name(),p_static,r_options);
+ //use the last assignment, (then backwards?)
+ if (last_assign) {
+
+ return _guess_expression_type(context,last_assign,last_assign_line,r_type);
}
+
return false;
}
-static bool _parse_completion_class(const String& p_base_path,const GDParser::ClassNode *p_class,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
+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++) {
- static const char*_type_names[Variant::VARIANT_MAX]={
- "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform",
- "Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
- "Vector2Array","Vector3Array","ColorArray"};
- if (p_indices && !p_indices->next()) {
- for(int i=0;i<Variant::VARIANT_MAX;i++) {
- if (p_indices->get()==_type_names[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) {
- List<StringName> ic;
+ if (op->arguments.size() && op->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) {
- Variant::get_numeric_constants_for_type(Variant::Type(i),&ic);
- for(List<StringName>::Element *E=ic.front();E;E=E->next()) {
- r_options->push_back(E->get());
+ 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 true;
}
}
}
+ return false;
+}
+
+static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
+ //go to block first
- for(int i=0;i<p_class->subclasses.size();i++) {
- if (p_line>=p_class->subclasses[i]->line && (p_line<=p_class->subclasses[i]->end_line || p_class->subclasses[i]->end_line==-1)) {
+ const GDParser::BlockNode *block=context.block;
- if (_parse_completion_class(p_base_path,p_class->subclasses[i],p_line,r_options,p_indices))
- return true;
+ while(block) {
+
+ GDCompletionContext c = context;
+ c.block=block;
+
+ if (_guess_identifier_type_in_block(c,p_line,p_identifier,r_type)) {
+ return true;
}
+
+ block=block->parent_block;
}
- bool in_static_func=false;
+ //guess from argument if virtual
+ if (context.function && context.function->name!=StringName()) {
- for(int i=0;i<p_class->functions.size();i++) {
+ int argindex = -1;
- const GDParser::FunctionNode *fu = p_class->functions[i];
+ for(int i=0;i<context.function->arguments.size();i++) {
- if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) {
- //if in function, first block stuff from outer to inner
- if (_parse_completion_block(fu->body,p_line,r_options,p_indices))
- return true;
- //then function arguments
- if (!p_indices) {
- for(int j=0;j<fu->arguments.size();j++) {
+ if (context.function->arguments[i]==p_identifier) {
+ argindex=i;
+ break;
+ }
+
+ }
+
+ if (argindex!=-1) {
+ GDCompletionIdentifier id =_get_native_class(context);
+ if (id.type==Variant::OBJECT && id.obj_type!=StringName()) {
+ //this kinda sucks but meh
+
+ List<MethodInfo> vmethods;
+ ObjectTypeDB::get_virtual_methods(id.obj_type,&vmethods);
+ for (List<MethodInfo>::Element *E=vmethods.front();E;E=E->next()) {
+
+
+ if (E->get().name==context.function->name && argindex<E->get().arguments.size()) {
+
+ PropertyInfo arg=E->get().arguments[argindex];
- r_options->push_back(fu->arguments[j]);
+ int scp = arg.name.find(":");
+ if (scp!=-1) {
+
+
+ r_type.type=Variant::OBJECT;
+ r_type.obj_type=arg.name.substr(scp+1,arg.name.length());
+ return true;
+
+ } else {
+
+ r_type.type=arg.type;
+ if (arg.hint==PROPERTY_HINT_RESOURCE_TYPE)
+ r_type.obj_type=arg.hint_string;
+ return true;
+ }
+ }
}
}
}
+ }
+
+ //guess type in constant
+ for(int i=0;i<context._class->constant_expressions.size();i++) {
+
+ if (context._class->constant_expressions[i].identifier==p_identifier) {
+
+ ERR_FAIL_COND_V( context._class->constant_expressions[i].expression->type!=GDParser::Node::TYPE_CONSTANT, false );
+ r_type=_get_type_from_variant(static_cast<const GDParser::ConstantNode*>(context._class->constant_expressions[i].expression)->value );
+ return true;
+ }
}
- for(int i=0;i<p_class->static_functions.size();i++) {
+ if (!(context.function && context.function->_static)) {
- const GDParser::FunctionNode *fu = p_class->static_functions[i];
+ for(int i=0;i<context._class->variables.size();i++) {
- if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) {
+ if (context._class->variables[i].identifier==p_identifier) {
- //if in function, first block stuff from outer to inne
- if (_parse_completion_block(fu->body,p_line,r_options,p_indices))
- return true;
- //then function arguments
- if (!p_indices) {
- for(int j=0;j<fu->arguments.size();j++) {
+ if (context._class->variables[i]._export.type!=Variant::NIL) {
- r_options->push_back(fu->arguments[j]);
+ r_type=_get_type_from_pinfo(context._class->variables[i]._export);
+ return true;
+ } else if (context._class->variables[i].expression) {
+
+ 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;
}
+ }
+ }
+
+
- in_static_func=true;
+ for(Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) {
+ if (E->key()==p_identifier) {
+
+ r_type=_get_type_from_variant(GDScriptLanguage::get_singleton()->get_global_array()[E->get()]);
+ return true;
}
}
+ return false;
+}
+
+static void _find_identifiers_in_block(GDCompletionContext& context,int p_line,bool p_only_functions,Set<String>& result) {
- //add all local names
- if (!p_indices) {
+ if (p_only_functions)
+ return;
- if (!in_static_func) {
+ for (int i=0;i<context.block->statements.size();i++) {
- for(int i=0;i<p_class->variables.size();i++) {
+ if (context.block->statements[i]->line>p_line)
+ continue;
- r_options->push_back(p_class->variables[i].identifier);
- }
+
+ if (context.block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
+
+ const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(context.block->statements[i]);
+ result.insert(lv->name.operator String());
}
+ }
+}
- for(int i=0;i<p_class->constant_expressions.size();i++) {
+static void _find_identifiers_in_class(GDCompletionContext& context,bool p_static,bool p_only_functions,Set<String>& result) {
- r_options->push_back(p_class->constant_expressions[i].identifier);
+ if (!p_static && !p_only_functions) {
+
+ for(int i=0;i<context._class->variables.size();i++) {
+ result.insert(context._class->variables[i].identifier);
}
+ }
+ if (!p_only_functions) {
- if (!in_static_func) {
- for(int i=0;i<p_class->functions.size();i++) {
+ for(int i=0;i<context._class->constant_expressions.size();i++) {
+ result.insert(context._class->constant_expressions[i].identifier);
+ }
- r_options->push_back(p_class->functions[i]->name);
- }
+ for(int i=0;i<context._class->subclasses.size();i++) {
+ result.insert(context._class->subclasses[i]->name);
}
- for(int i=0;i<p_class->static_functions.size();i++) {
+ }
+
+ for(int i=0;i<context._class->static_functions.size();i++) {
+ if (context._class->static_functions[i]->arguments.size())
+ result.insert(context._class->static_functions[i]->name.operator String()+"(");
+ else
+ result.insert(context._class->static_functions[i]->name.operator String()+"()");
+ }
- r_options->push_back(p_class->static_functions[i]->name);
+ if (!p_static) {
+
+ for(int i=0;i<context._class->functions.size();i++) {
+ if (context._class->functions[i]->arguments.size())
+ result.insert(context._class->functions[i]->name.operator String()+"(");
+ else
+ result.insert(context._class->functions[i]->name.operator String()+"()");
}
}
+ //globals
- if (p_class->extends_used) {
- //do inheritance
- String path = p_class->extends_file;
+ Ref<Reference> base = _get_parent_class(context);
- Ref<GDScript> script;
- Ref<GDNativeClass> native;
+ while(true) {
- if (path!="") {
- //path (and optionally subclasses)
+ Ref<GDScript> script = base;
+ Ref<GDNativeClass> nc = base;
+ if (script.is_valid()) {
- script = ResourceLoader::load(path);
- if (script.is_null()) {
- return false;
+ if (!p_static && !p_only_functions) {
+ for (const Set<StringName>::Element *E=script->get_members().front();E;E=E->next()) {
+ result.insert(E->get().operator String());
+ }
}
- if (p_class->extends_class.size()) {
+ if (!p_only_functions) {
+ for (const Map<StringName,Variant>::Element *E=script->get_constants().front();E;E=E->next()) {
+ result.insert(E->key().operator String());
+ }
+ }
- for(int i=0;i<p_class->extends_class.size();i++) {
+ for (const Map<StringName,GDFunction>::Element *E=script->get_member_functions().front();E;E=E->next()) {
+ if (!p_static || E->get().is_static()) {
+ if (E->get().get_argument_count())
+ result.insert(E->key().operator String()+"(");
+ else
+ result.insert(E->key().operator String()+"()");
+ }
+ }
- String sub = p_class->extends_class[i];
- if (script->get_subclasses().has(sub)) {
+ if (!p_only_functions) {
+ for (const Map<StringName,Ref<GDScript> >::Element *E=script->get_subclasses().front();E;E=E->next()) {
+ result.insert(E->key().operator String());
+ }
+ }
- script=script->get_subclasses()[sub];
+ base=script->get_base();
+ if (base.is_null())
+ base=script->get_native();
+ } else if (nc.is_valid()) {
+
+ if (!p_only_functions) {
+
+ StringName type = nc->get_name();
+ List<String> constants;
+ ObjectTypeDB::get_integer_constant_list(type,&constants);
+ for(List<String>::Element *E=constants.front();E;E=E->next()) {
+ result.insert(E->get());
+ }
+
+ List<MethodInfo> methods;
+ ObjectTypeDB::get_method_list(type,&methods);
+ for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+ if (E->get().name.begins_with("_"))
+ continue;
+ if (E->get().arguments.size())
+ result.insert(E->get().name+"(");
+ else
+ result.insert(E->get().name+"()");
+ }
+ }
+ break;
+ } else
+ break;
+
+ }
+
+}
+
+static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_only_functions,Set<String>& result) {
+
+ 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;
+ c.block=block;
+
+ _find_identifiers_in_block(c,p_line,p_only_functions,result);
+ block=block->parent_block;
+ }
+
+ const GDParser::ClassNode *clss=context._class;
+
+ bool _static=context.function && context.function->_static;
+
+ while(clss) {
+ GDCompletionContext c = context;
+ c._class=clss;
+ c.block=NULL;
+ c.function=NULL;
+ _find_identifiers_in_class(c,_static,p_only_functions,result);
+ clss=clss->owner;
+ }
+
+ for(int i=0;i<GDFunctions::FUNC_MAX;i++) {
+
+ result.insert(GDFunctions::get_func_name(GDFunctions::Function(i)));
+ }
+
+ static const char*_type_names[Variant::VARIANT_MAX]={
+ "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Transform",
+ "Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
+ "Vector2Array","Vector3Array","ColorArray"};
+
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ result.insert(_type_names[i]);
+ }
+
+ for(const Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) {
+ result.insert(E->key().operator String());
+ }
+}
+
+
+static String _get_visual_datatype(const PropertyInfo& p_info,bool p_isarg=true) {
+
+ String n = p_info.name;
+ int idx = n.find(":");
+ if (idx!=-1) {
+ return n.substr(idx+1,n.length());
+ }
+
+ if (p_info.type==Variant::OBJECT && p_info.hint==PROPERTY_HINT_RESOURCE_TYPE)
+ return p_info.hint_string;
+ if (p_info.type==Variant::NIL) {
+ if (p_isarg)
+ return "var";
+ else
+ return "void";
+ }
+
+ return Variant::get_type_name(p_info.type);
+}
+
+static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argidx,String& arghint) {
+
+ arghint="func "+p_func->name+"(";
+ for (int i=0;i<p_func->arguments.size();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ arghint+=p_func->arguments[i].operator String();
+ int deffrom = p_func->arguments.size()-p_func->default_values.size();
+
+ if (i>=deffrom) {
+ int defidx = deffrom-i;
+
+ if (defidx>=0 && defidx<p_func->default_values.size()) {
+
+ if (p_func->default_values[defidx]->type==GDParser::Node::TYPE_OPERATOR) {
+
+ const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_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();
+
+ }
+ } else {
+
+ }
+ }
+ }
+
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ }
+ if (p_func->arguments.size()>0)
+ arghint+=" ";
+ arghint+=")";
+}
+
+
+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;
+ Globals::get_singleton()->get_property_list(&pinfo);
+
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ const PropertyInfo &pi=E->get();
+
+ if (!pi.name.begins_with("input/"))
+ continue;
+
+ String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
+ result.insert("\""+name+"\"");
+ }
+
+
+ } else if (id.type==Variant::OBJECT && id.obj_type!=StringName()) {
+
+
+ MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method);
+ 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 (scr->get_base().is_valid())
+ scr=scr->get_base().ptr();
+ else
+ scr=NULL;
+ }
} else {
+ on_script=obj->get_script();
+ }
+ }
+ }
- return false;
+ //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++) {
+
+ //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;
}
}
}
+
} else {
+ //regular method
- ERR_FAIL_COND_V(p_class->extends_class.size()==0,false);
- //look around for the subclasses
+ if (p_method.operator String()=="connect") {
- String base=p_class->extends_class[0];
- Ref<GDScript> base_class;
-#if 0
- while(p) {
- if (p->subclasses.has(base)) {
+ 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) {
- base_class=p->subclasses[base];
- break;
+ 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 {
+
+ if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) {
+
+ 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;
+ // print_line("found "+s);
+ String name = s.get_slice("/",1);
+ result.insert("\"/root/"+name+"\"");
+ }
}
- p=p->_owner;
+
+ 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()) {
+
+ result.insert(E->get());
+ }
+ }
+
}
- if (base_class.is_valid()) {
+ arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("(");
- for(int i=1;i<p_class->extends_class.size();i++) {
+ for(int i=0;i<m->get_argument_count();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
- String subclass=p_class->extends_class[i];
+ 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();
- if (base_class->subclasses.has(subclass)) {
- base_class=base_class->subclasses[subclass];
- } else {
+ if (i>=deffrom) {
+ int defidx = i-deffrom;
- _set_error("Could not find subclass: "+subclass,p_class);
- return ERR_FILE_NOT_FOUND;
+ 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);
+ }
- } else {
-#endif
- if (p_class->extends_class.size()>1) {
+ }
+ if (m->get_argument_count()>0)
+ arghint+=" ";
- return false;
+ arghint+=")";
+ }
+
+ }
+}
+
+
+static void _find_call_arguments(GDCompletionContext& context,const GDParser::Node* p_node, int p_line,int p_argidx, Set<String>& result, String& arghint) {
+
+
+
+ if (!p_node || p_node->type!=GDParser::Node::TYPE_OPERATOR) {
+
+ return;
+ }
+
+ const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_node);
+
+ if (op->op!=GDParser::OperatorNode::OP_CALL) {
+
+ return;
+ }
+
+ if (op->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+ //complete built-in function
+ const GDParser::BuiltInFunctionNode *fn = static_cast<const GDParser::BuiltInFunctionNode*>(op->arguments[0]);
+ MethodInfo mi = GDFunctions::get_info(fn->function);
+
+ arghint = _get_visual_datatype(mi.return_val,false)+" "+GDFunctions::get_func_name(fn->function)+String("(");
+ for(int i=0;i<mi.arguments.size();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ arghint+=_get_visual_datatype(mi.arguments[i])+" "+mi.arguments[i].name;
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+
+ }
+ if (mi.arguments.size()>0)
+ arghint+=" ";
+ arghint+=")";
+
+ } else if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
+ //complete constructor
+ const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode*>(op->arguments[0]);
+
+ List<MethodInfo> mil;
+ Variant::get_constructor_list(tn->vtype,&mil);
+
+ for(List<MethodInfo>::Element *E=mil.front();E;E=E->next()) {
+
+ MethodInfo mi = E->get();
+ if (mi.arguments.size()==0)
+ continue;
+ if (E->prev())
+ arghint+="\n";
+ arghint += Variant::get_type_name(tn->vtype)+" "+Variant::get_type_name(tn->vtype)+String("(");
+ for(int i=0;i<mi.arguments.size();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
}
- //if not found, try engine classes
- if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
- return false;
+ arghint+=_get_visual_datatype(mi.arguments[i])+" "+mi.arguments[i].name;
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
}
- int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base];
- native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx];
- if (!native.is_valid()) {
- return false;
+ }
+ if (mi.arguments.size()>0)
+ arghint+=" ";
+ arghint+=")";
+ }
+
+ } else if (op->arguments.size()>=2 && op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {
+ //make sure identifier exists...
+
+ const GDParser::IdentifierNode *id=static_cast<const GDParser::IdentifierNode *>(op->arguments[1]);
+
+ if (op->arguments[0]->type==GDParser::Node::TYPE_SELF) {
+ //self, look up
+
+ for(int i=0;i<context._class->static_functions.size();i++) {
+ if (context._class->static_functions[i]->name==id->name) {
+ _make_function_hint(context._class->static_functions[i],p_argidx,arghint);
+ return;
}
-#if 0
}
-#endif
+
+ if (context.function && !context.function->_static) {
+
+ for(int i=0;i<context._class->functions.size();i++) {
+ if (context._class->functions[i]->name==id->name) {
+ _make_function_hint(context._class->functions[i],p_argidx,arghint);
+ return;
+ }
+ }
+ }
+
+ Ref<Reference> base = _get_parent_class(context);
+
+ while(true) {
+
+ Ref<GDScript> script = base;
+ Ref<GDNativeClass> nc = base;
+ if (script.is_valid()) {
+
+
+ for (const Map<StringName,GDFunction>::Element *E=script->get_member_functions().front();E;E=E->next()) {
+
+ if (E->key()==id->name) {
+
+ if (context.function && context.function->_static && !E->get().is_static())
+ continue;
+
+
+ arghint = "func "+id->name.operator String()+String("(");
+ 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+=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);
+ }
+
+ }
+ if (E->get().get_argument_count()>0)
+ arghint+=" ";
+ arghint+=")";
+ return;
+ }
+ }
+
+ base=script->get_base();
+ if (base.is_null())
+ base=script->get_native();
+ } else if (nc.is_valid()) {
+
+ if (context.function && !context.function->_static) {
+
+ GDCompletionIdentifier ci;
+ ci.type=Variant::OBJECT;
+ ci.obj_type=nc->get_name();
+ if (!context._class->owner)
+ ci.value=context.base;
+
+ _find_type_arguments(p_node,p_line,id->name,ci,p_argidx,result,arghint);
+ //guess type..
+ /*
+ List<MethodInfo> methods;
+ ObjectTypeDB::get_method_list(type,&methods);
+ for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+ //if (E->get().arguments.size())
+ // result.insert(E->get().name+"(");
+ //else
+ // result.insert(E->get().name+"()");
+ }*/
+ }
+ break;
+ } else
+ break;
+
+ }
+ } else {
+ //indexed lookup
+
+ GDCompletionIdentifier ci;
+ if (_guess_expression_type(context,op->arguments[0],p_line,ci)) {
+
+ _find_type_arguments(p_node,p_line,id->name,ci,p_argidx,result,arghint);
+ return;
+ }
}
- if (script.is_valid()) {
- if (_parse_script_symbols(script,in_static_func,r_options,p_indices))
- return true;
+ }
+#if 0
+ bool _static=context.function->_static;
+
- } else if (native.is_valid() && !p_indices) {
- _parse_native_symbols(native->get_name(),in_static_func,r_options);
+
+ for(int i=0;i<context._class->static_functions.size();i++) {
+ if (context._class->static_functions[i]->arguments.size())
+ result.insert(context._class->static_functions[i]->name.operator String()+"(");
+ else
+ result.insert(context._class->static_functions[i]->name.operator String()+"()");
+ }
+
+ if (!p_static) {
+
+ for(int i=0;i<context._class->functions.size();i++) {
+ if (context._class->functions[i]->arguments.size())
+ result.insert(context._class->functions[i]->name.operator String()+"(");
+ else
+ result.insert(context._class->functions[i]->name.operator String()+"()");
}
}
- return false;
+ Ref<Reference> base = _get_parent_class(context);
-}
+ while(true) {
+
+ Ref<GDScript> script = base;
+ Ref<GDNativeClass> nc = base;
+ if (script.is_valid()) {
+ if (!p_static && !p_only_functions) {
+ for (const Set<StringName>::Element *E=script->get_members().front();E;E=E->next()) {
+ result.insert(E->get().operator String());
+ }
+ }
-Error GDScriptLanguage::complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_base, List<String>* r_options) {
+ if (!p_only_functions) {
+ for (const Map<StringName,Variant>::Element *E=script->get_constants().front();E;E=E->next()) {
+ result.insert(E->key().operator String());
+ }
+ }
- GDParser p;
- Error err = p.parse(p_code,p_base_path);
- // don't care much about error I guess
- const GDParser::Node* root = p.get_parse_tree();
- ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_INVALID_DATA);
+ for (const Map<StringName,GDFunction>::Element *E=script->get_member_functions().front();E;E=E->next()) {
+ if (!p_static || E->get().is_static()) {
+ if (E->get().get_argument_count())
+ result.insert(E->key().operator String()+"(");
+ else
+ result.insert(E->key().operator String()+"()");
+ }
+ }
+
+ if (!p_only_functions) {
+ for (const Map<StringName,Ref<GDScript> >::Element *E=script->get_subclasses().front();E;E=E->next()) {
+ result.insert(E->key().operator String());
+ }
+ }
- const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
+ base=script->get_base();
+ if (base.is_null())
+ base=script->get_native();
+ } else if (nc.is_valid()) {
- List<String> indices;
- Vector<String> spl = p_base.split(".");
+ if (!p_only_functions) {
- for(int i=0;i<spl.size()-1;i++) {
- indices.push_back(spl[i]);
+ StringName type = nc->get_name();
+ List<String> constants;
+ ObjectTypeDB::get_integer_constant_list(type,&constants);
+ for(List<String>::Element *E=constants.front();E;E=E->next()) {
+ result.insert(E->get());
+ }
+
+ List<MethodInfo> methods;
+ ObjectTypeDB::get_method_list(type,&methods);
+ for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+ if (E->get().arguments.size())
+ result.insert(E->get().name+"(");
+ else
+ result.insert(E->get().name+"()");
+ }
+ }
+ break;
+ } else
+ break;
+
+ }
+
+ for(int i=0;i<GDFunctions::FUNC_MAX;i++) {
+
+ result.insert(GDFunctions::get_func_name(GDFunctions::Function(i)));
}
- if (_parse_completion_class(p_base,cl,p_line,r_options,indices.front()))
- return OK;
- //and the globals x_x?
- for(Map<StringName,int>::Element *E=globals.front();E;E=E->next()) {
- if (!indices.empty()) {
- if (String(E->key())==indices.front()->get()) {
+#endif
+
+}
- _parse_completion_variant(global_array[E->get()],r_options,indices.front()->next());
+Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base_path, Object*p_owner, List<String>* r_options, String &r_call_hint) {
+ //print_line( p_code.replace(String::chr(0xFFFF),"<cursor>"));
- return OK;
+ 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(p_code,p_base_path,false,"",true);
+ bool isfunction=false;
+ Set<String> options;
+
+ GDCompletionContext context;
+ context._class=p.get_completion_class();
+ context.block=p.get_completion_block();
+ context.function=p.get_completion_function();
+ context.base=p_owner;
+ context.base_path=p_base_path;
+
+ switch(p.get_completion_type()) {
+
+ case GDParser::COMPLETION_NONE: {
+ print_line("No completion");
+ } break;
+ case GDParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
+ print_line("Built in type constant");
+ List<StringName> constants;
+ Variant::get_numeric_constants_for_type(p.get_completion_built_in_constant(),&constants);
+ for(List<StringName>::Element *E=constants.front();E;E=E->next()) {
+ options.insert(E->get().operator String());
}
- } else {
- r_options->push_back(E->key());
- }
+
+
+ } break;
+ case GDParser::COMPLETION_FUNCTION:
+ isfunction=true;
+ case GDParser::COMPLETION_IDENTIFIER: {
+
+ _find_identifiers(context,p.get_completion_line(),isfunction,options);
+ } break;
+ case GDParser::COMPLETION_PARENT_FUNCTION: {
+ print_line("parent function");
+
+ } break;
+ case GDParser::COMPLETION_METHOD:
+ isfunction=true;
+ case GDParser::COMPLETION_INDEX: {
+
+ const GDParser::Node *node = p.get_completion_node();
+ if (node->type!=GDParser::Node::TYPE_OPERATOR)
+ break;
+
+
+
+
+ GDCompletionIdentifier t;
+ if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) {
+
+ 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) {
+
+ 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
+ }
+
+ }
+
+ 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())
+ scr=scr->get_base().ptr();
+ else
+ scr=NULL;
+ }
+ }
+ }
+
+
+
+
+
+
+ if (!isfunction) {
+ ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options);
+ }
+ List<MethodInfo> mi;
+ ObjectTypeDB::get_method_list(t.obj_type,&mi);
+ for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+
+ if (E->get().name.begins_with("_"))
+ continue;
+
+ if (E->get().arguments.size())
+ options.insert(E->get().name+"(");
+ else
+ options.insert(E->get().name+"()");
+
+ }
+ } else {
+
+
+ if (t.type==Variant::INPUT_EVENT) {
+
+ //this is hardcoded otherwise it's not obvious
+ Set<String> exclude;
+
+ for(int i=0;i<InputEvent::TYPE_MAX;i++) {
+
+ InputEvent ie;
+ ie.type=InputEvent::Type(i);
+ static const char*evnames[]={
+ "# Common",
+ "# Key",
+ "# MouseMotion",
+ "# MouseButton",
+ "# JoyMotion",
+ "# JoyButton",
+ "# ScreenTouch",
+ "# ScreenDrag",
+ "# Action"
+ };
+
+ r_options->push_back(evnames[i]);
+
+ Variant v = ie;
+
+ if (i==0) {
+ List<MethodInfo> mi;
+ v.get_method_list(&mi);
+ for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+ r_options->push_back(E->get().name+"(");
+
+ }
+
+ }
+
+ List<PropertyInfo> pi;
+ v.get_property_list(&pi);
+
+ for (List<PropertyInfo>::Element *E=pi.front();E;E=E->next()) {
+
+ if (i==0)
+ exclude.insert(E->get().name);
+ else if (exclude.has(E->get().name))
+ continue;
+
+ r_options->push_back(E->get().name);
+ }
+ }
+ return OK;
+ } else {
+ if (t.value.get_type()==Variant::NIL) {
+ Variant::CallError ce;
+ t.value=Variant::construct(t.type,NULL,0,ce);
+ }
+
+
+ if (!isfunction) {
+ List<PropertyInfo> pl;
+ t.value.get_property_list(&pl);
+ for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
+
+ if (E->get().name.find("/")==-1)
+ options.insert(E->get().name);
+ }
+ }
+
+ List<MethodInfo> mi;
+ t.value.get_method_list(&mi);
+ for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+ if (E->get().arguments.size())
+ options.insert(E->get().name+"(");
+ else
+ options.insert(E->get().name+"()");
+
+ }
+ }
+ }
+ }
+
+
+ } break;
+ case GDParser::COMPLETION_CALL_ARGUMENTS: {
+
+ _find_call_arguments(context,p.get_completion_node(),p.get_completion_line(),p.get_completion_argument_index(),options,r_call_hint);
+ } break;
+ case GDParser::COMPLETION_VIRTUAL_FUNC: {
+
+ GDCompletionIdentifier cid = _get_native_class(context);
+
+ if (cid.obj_type!=StringName()) {
+ List<MethodInfo> vm;
+ ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm);
+ for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) {
+
+ MethodInfo &mi=E->get();
+ String m = mi.name;
+ if (m.find(":")!=-1)
+ m=m.substr(0,m.find(":"));
+ m+="(";
+
+ if (mi.arguments.size()) {
+ for(int i=0;i<mi.arguments.size();i++) {
+ if (i>0)
+ m+=", ";
+ String n =mi.arguments[i].name;
+ if (n.find(":")!=-1)
+ n=n.substr(0,n.find(":"));
+ m+=n;
+ }
+ }
+ m+="):";
+
+ options.insert(m);
+ }
+ }
+ } break;
+
+
}
+
+ for(Set<String>::Element *E=options.front();E;E=E->next()) {
+ r_options->push_back(E->get());
+ }
+
+ return OK;
+}
+
+#else
+
+Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base_path, Object*p_owner, List<String>* r_options, String &r_call_hint) {
return OK;
}
+#endif
+
+
void GDScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_line) const {
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index 0d11734bbd..6f51ac5312 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -71,6 +71,7 @@ const char *GDFunctions::get_func_name(Function p_func) {
"randi",
"randf",
"rand_range",
+ "seed",
"rand_seed",
"deg2rad",
"rad2deg",
@@ -87,14 +88,18 @@ const char *GDFunctions::get_func_name(Function p_func) {
"str",
"print",
"printt",
+ "prints",
"printerr",
"printraw",
+ "var2str",
+ "str2var",
"range",
"load",
"inst2dict",
"dict2inst",
"hash",
"print_stack",
+ "instance_from_id",
};
return _names[p_func];
@@ -326,6 +331,13 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
VALIDATE_ARG_NUM(1);
r_ret=Math::random(*p_args[0],*p_args[1]);
} break;
+ case MATH_SEED: {
+ VALIDATE_ARG_COUNT(1);
+ VALIDATE_ARG_NUM(0);
+ uint32_t seed=*p_args[0];
+ Math::seed(seed);
+ r_ret=Variant();
+ } break;
case MATH_RANDSEED: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
@@ -551,6 +563,22 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
} break;
+ case TEXT_PRINT_SPACED: {
+
+ String str;
+ for(int i=0;i<p_arg_count;i++) {
+
+ if (i)
+ str+=" ";
+ str+=p_args[i]->operator String();
+ }
+
+ //str+="\n";
+ print_line(str);
+ r_ret=Variant();
+
+
+ } break;
case TEXT_PRINTERR: {
@@ -573,14 +601,27 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
}
//str+="\n";
- OS::get_singleton()->print("%s\n",str.utf8().get_data());
+ OS::get_singleton()->print("%s",str.utf8().get_data());
r_ret=Variant();
} break;
+ case VAR_TO_STR: {
+ VALIDATE_ARG_COUNT(1);
+ r_ret=p_args[0]->get_construct_string();
+ } break;
+ case STR_TO_VAR: {
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::STRING;
+ r_ret=Variant();
+ return;
+ }
+ Variant::construct_from_string(*p_args[0],r_ret);
+ } break;
case GEN_RANGE: {
-
-
switch(p_arg_count) {
case 0: {
@@ -861,9 +902,17 @@ 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: {
@@ -881,6 +930,20 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
};
} break;
+ case INSTANCE_FROM_ID: {
+
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type()!=Variant::INT && p_args[0]->get_type()!=Variant::REAL) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_ret=Variant();
+ break;
+ }
+
+ uint32_t id=*p_args[0];
+ r_ret=ObjectDB::get_instance(id);
+
+ } break;
case FUNC_MAX: {
ERR_FAIL_V();
@@ -1087,7 +1150,7 @@ MethodInfo GDFunctions::get_info(Function p_func) {
return mi;
} break;
case MATH_LERP: {
- MethodInfo mi("lerp",PropertyInfo(Variant::REAL,"a"),PropertyInfo(Variant::REAL,"b"), PropertyInfo(Variant::REAL,"c"));
+ MethodInfo mi("lerp",PropertyInfo(Variant::REAL,"from"),PropertyInfo(Variant::REAL,"to"), PropertyInfo(Variant::REAL,"weight"));
mi.return_val.type=Variant::REAL;
return mi;
} break;
@@ -1116,6 +1179,11 @@ MethodInfo GDFunctions::get_info(Function p_func) {
mi.return_val.type=Variant::REAL;
return mi;
} break;
+ case MATH_SEED: {
+ MethodInfo mi("seed",PropertyInfo(Variant::REAL,"seed"));
+ mi.return_val.type=Variant::NIL;
+ return mi;
+ } break;
case MATH_RANDSEED: {
MethodInfo mi("rand_seed",PropertyInfo(Variant::REAL,"seed"));
mi.return_val.type=Variant::ARRAY;
@@ -1166,6 +1234,8 @@ MethodInfo GDFunctions::get_info(Function p_func) {
MethodInfo mi("weakref",PropertyInfo(Variant::OBJECT,"obj"));
mi.return_val.type=Variant::OBJECT;
+ mi.return_val.name="WeakRef";
+
return mi;
} break;
@@ -1173,6 +1243,7 @@ MethodInfo GDFunctions::get_info(Function p_func) {
MethodInfo mi("funcref",PropertyInfo(Variant::OBJECT,"instance"),PropertyInfo(Variant::STRING,"funcname"));
mi.return_val.type=Variant::OBJECT;
+ mi.return_val.name="FuncRef";
return mi;
} break;
@@ -1207,6 +1278,13 @@ MethodInfo GDFunctions::get_info(Function p_func) {
return mi;
} break;
+ case TEXT_PRINT_SPACED: {
+
+ MethodInfo mi("prints",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"..."));
+ mi.return_val.type=Variant::NIL;
+ return mi;
+
+ } break;
case TEXT_PRINTERR: {
MethodInfo mi("printerr",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"..."));
@@ -1221,6 +1299,18 @@ MethodInfo GDFunctions::get_info(Function p_func) {
return mi;
} break;
+ case VAR_TO_STR: {
+ MethodInfo mi("var2str",PropertyInfo(Variant::NIL,"var"));
+ mi.return_val.type=Variant::STRING;
+ return mi;
+
+ } break;
+ case STR_TO_VAR: {
+
+ MethodInfo mi("str2var:var",PropertyInfo(Variant::STRING,"string"));
+ mi.return_val.type=Variant::NIL;
+ return mi;
+ } break;
case GEN_RANGE: {
MethodInfo mi("range",PropertyInfo(Variant::NIL,"..."));
@@ -1231,6 +1321,7 @@ MethodInfo GDFunctions::get_info(Function p_func) {
MethodInfo mi("load",PropertyInfo(Variant::STRING,"path"));
mi.return_val.type=Variant::OBJECT;
+ mi.return_val.name="Resource";
return mi;
} break;
case INST2DICT: {
@@ -1258,6 +1349,12 @@ MethodInfo GDFunctions::get_info(Function p_func) {
return mi;
} break;
+ case INSTANCE_FROM_ID: {
+ MethodInfo mi("instance_from_id",PropertyInfo(Variant::INT,"instance_id"));
+ mi.return_val.type=Variant::OBJECT;
+ return mi;
+ } break;
+
case FUNC_MAX: {
ERR_FAIL_V(MethodInfo());
diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h
index 340763fb8c..ad35a628d5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -67,6 +67,7 @@ public:
MATH_RAND,
MATH_RANDF,
MATH_RANDOM,
+ MATH_SEED,
MATH_RANDSEED,
MATH_DEG2RAD,
MATH_RAD2DEG,
@@ -83,14 +84,18 @@ public:
TEXT_STR,
TEXT_PRINT,
TEXT_PRINT_TABBED,
+ TEXT_PRINT_SPACED,
TEXT_PRINTERR,
TEXT_PRINTRAW,
+ VAR_TO_STR,
+ STR_TO_VAR,
GEN_RANGE,
RESOURCE_LOAD,
INST2DICT,
DICT2INST,
HASH,
PRINT_STACK,
+ INSTANCE_FROM_ID,
FUNC_MAX
};
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 40c262c503..c55bfee591 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,19 +30,7 @@
#include "print_string.h"
#include "io/resource_loader.h"
#include "os/file_access.h"
-/* TODO:
-
- *Property reduce constant expressions
- *Implement missing operators in variant?
- *constructor
- */
-
-/*
- todo:
- fix post ++,--
- make sure ++,-- don't work on constant expressions
- seems passing parent node as param is not needed
- */
+#include "script_language.h"
template<class T>
T* GDParser::alloc_node() {
@@ -77,8 +65,10 @@ 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();
@@ -116,14 +106,28 @@ bool GDParser::_enter_indent_block(BlockNode* p_block) {
}
}
-bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static) {
+bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static,bool p_can_codecomplete) {
if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
tokenizer->advance();
} else {
+ int argidx=0;
+
while(true) {
+ 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);
if (!arg)
@@ -144,6 +148,7 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
}
tokenizer->advance();
+ argidx++;
} else {
// something is broken
_set_error("Expected ',' or ')'");
@@ -158,6 +163,50 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
}
+void GDParser::_make_completable_call(int p_arg) {
+
+ completion_cursor=StringName();
+ completion_type=COMPLETION_CALL_ARGUMENTS;
+ completion_class=current_class;
+ completion_function=current_function;
+ completion_line=tokenizer->get_token_line();
+ completion_argument=p_arg;
+ completion_block=current_block;
+ completion_found=true;
+ tokenizer->advance();
+
+}
+
+
+bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& identifier) {
+
+ identifier=StringName();
+ if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
+ identifier=tokenizer->get_token_identifier();
+ tokenizer->advance();
+ }
+ if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+
+ completion_cursor=identifier;
+ completion_type=p_type;
+ completion_class=current_class;
+ 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) {
+ identifier=identifier.operator String() + tokenizer->get_token_identifier().operator String();
+ tokenizer->advance();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_allow_assign) {
@@ -199,6 +248,9 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
tokenizer->advance();
expr=subexpr;
+ } else if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+ tokenizer->advance();
+ continue; //no point in cursor in the middle of expression
} else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) {
@@ -225,13 +277,24 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
String path = tokenizer->get_token_constant();
if (!path.is_abs_path() && base_path!="")
path=base_path+"/"+path;
- path = path.replace("///","//");
+ path = path.replace("///","//").simplify_path();
+ if (path==self_path) {
+
+ _set_error("Can't preload itself (use 'get_script()').");
+ return NULL;
+
+ }
+
Ref<Resource> res;
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;
@@ -256,6 +319,55 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
tokenizer->advance();
expr=constant;
+ } else if (tokenizer->get_token()==GDTokenizer::TK_PR_YIELD) {
+
+ //constant defined by tokenizer
+
+ tokenizer->advance();
+ if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after 'yield'");
+ return NULL;
+ }
+
+ tokenizer->advance();
+
+ OperatorNode *yield = alloc_node<OperatorNode>();
+ yield->op=OperatorNode::OP_YIELD;
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ expr=yield;
+ tokenizer->advance();
+ } else {
+
+ Node *object = _parse_and_reduce_expression(p_parent,p_static);
+ if (!object)
+ return NULL;
+ yield->arguments.push_back(object);
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) {
+
+ _set_error("Expected ',' after first argument of 'yield'");
+ return NULL;
+ }
+
+ tokenizer->advance();
+
+ Node *signal = _parse_and_reduce_expression(p_parent,p_static);
+ if (!signal)
+ return NULL;
+ yield->arguments.push_back(signal);
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
+
+ _set_error("Expected ')' after second argument of 'yield'");
+ return NULL;
+ }
+
+ tokenizer->advance();
+
+ expr=yield;
+ }
+
} else if (tokenizer->get_token()==GDTokenizer::TK_SELF) {
@@ -271,12 +383,19 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
Variant::Type bi_type = tokenizer->get_token_type();
tokenizer->advance(2);
- if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+
+ StringName identifier;
+
+ if (_get_completable_identifier(COMPLETION_BUILT_IN_TYPE_CONSTANT,identifier)) {
+
+ completion_built_in_constant=bi_type;
+ }
+
+ if (identifier==StringName()) {
_set_error("Built-in type constant expected after '.'");
return NULL;
}
- StringName identifier = tokenizer->get_token_identifier();
if (!Variant::has_numeric_constant(bi_type,identifier)) {
_set_error("Static constant '"+identifier.operator String()+"' not present in built-in type "+Variant::get_type_name(bi_type)+".");
@@ -286,7 +405,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
ConstantNode *cn = alloc_node<ConstantNode>();
cn->value=Variant::get_numeric_constant_value(bi_type,identifier);
expr=cn;
- tokenizer->advance();
+
} else if (tokenizer->get_token(1)==GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC)) {
//function or constructor
@@ -299,23 +418,35 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
TypeNode *tn = alloc_node<TypeNode>();
tn->vtype=tokenizer->get_token_type();
op->arguments.push_back(tn);
+ tokenizer->advance(2);
} else if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC) {
BuiltInFunctionNode *bn = alloc_node<BuiltInFunctionNode>();
bn->function=tokenizer->get_token_built_in_func();
op->arguments.push_back(bn);
+ tokenizer->advance(2);
} else {
SelfNode *self = alloc_node<SelfNode>();
op->arguments.push_back(self);
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_FUNCTION,identifier)) {
+
+ }
+
IdentifierNode* id = alloc_node<IdentifierNode>();
- id->name=tokenizer->get_token_identifier();
+ id->name=identifier;
op->arguments.push_back(id);
+ tokenizer->advance(1);
}
- tokenizer->advance(2);
- if (!_parse_arguments(op,op->arguments,p_static))
+ if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+ _make_completable_call(0);
+ completion_node=op;
+
+ }
+ if (!_parse_arguments(op,op->arguments,p_static,true))
return NULL;
expr=op;
@@ -323,10 +454,28 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
} else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
//identifier (reference)
- IdentifierNode *id = alloc_node<IdentifierNode>();
- id->name=tokenizer->get_token_identifier();
- tokenizer->advance();
- expr=id;
+ const ClassNode* cln = static_cast<const ClassNode*>(get_parse_tree());
+ bool bfn = false;
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_IDENTIFIER,identifier)) {
+
+ }
+
+ for( int i=0; i<cln->constant_expressions.size(); ++i ) {
+
+ if( cln->constant_expressions[i].identifier == identifier ) {
+
+ expr = cln->constant_expressions[i].expression;
+ bfn = true;
+ break;
+ }
+ }
+
+ if ( !bfn ) {
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name = identifier;
+ expr = id;
+ }
} else if (/*tokenizer->get_token()==GDTokenizer::TK_OP_ADD ||*/ tokenizer->get_token()==GDTokenizer::TK_OP_SUB || tokenizer->get_token()==GDTokenizer::TK_OP_NOT || tokenizer->get_token()==GDTokenizer::TK_OP_BIT_INVERT) {
@@ -528,7 +677,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
expr=dict;
- } else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
+ } else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && (tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
// parent call
tokenizer->advance(); //goto identifier
@@ -539,12 +688,16 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
/*SelfNode *self = alloc_node<SelfNode>();
op->arguments.push_back(self);
forbidden for now */
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_PARENT_FUNCTION,identifier)) {
+ //indexing stuff
+ }
- IdentifierNode* id = alloc_node<IdentifierNode>();
- id->name=tokenizer->get_token_identifier();
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name=identifier;
op->arguments.push_back(id);
- tokenizer->advance(2);
+ tokenizer->advance(1);
if (!_parse_arguments(op,op->arguments,p_static))
return NULL;
@@ -579,7 +732,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
//indexing using "."
- if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) {
+ if (tokenizer->get_token(1)!=GDTokenizer::TK_CURSOR && tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) {
_set_error("Expected identifier as member");
return NULL;
} else if (tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
@@ -587,37 +740,67 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
OperatorNode * op = alloc_node<OperatorNode>();
op->op=OperatorNode::OP_CALL;
+ tokenizer->advance();
+
IdentifierNode * id = alloc_node<IdentifierNode>();
- if (tokenizer->get_token(1)==GDTokenizer::TK_BUILT_IN_FUNC ) {
+ if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC ) {
//small hack so built in funcs don't obfuscate methods
- id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func(1));
+ id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func());
+ tokenizer->advance();
+
} else {
- id->name=tokenizer->get_token_identifier(1);
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_METHOD,identifier)) {
+ completion_node=op;
+ //indexing stuff
+ }
+
+ id->name=identifier;
}
op->arguments.push_back(expr); // call what
op->arguments.push_back(id); // call func
//get arguments
- tokenizer->advance(3);
- if (!_parse_arguments(op,op->arguments,p_static))
+ tokenizer->advance(1);
+ if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+ _make_completable_call(0);
+ completion_node=op;
+
+ }
+ if (!_parse_arguments(op,op->arguments,p_static,true))
return NULL;
expr=op;
} else {
//simple indexing!
+
+
OperatorNode * op = alloc_node<OperatorNode>();
op->op=OperatorNode::OP_INDEX_NAMED;
+ tokenizer->advance();
+
+
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_INDEX,identifier)) {
+
+ if (identifier==StringName()) {
+ identifier="@temp"; //so it parses allright
+ }
+ completion_node=op;
+
+ //indexing stuff
+ }
IdentifierNode * id = alloc_node<IdentifierNode>();
- id->name=tokenizer->get_token_identifier(1);
+ id->name=identifier;
op->arguments.push_back(expr);
op->arguments.push_back(id);
expr=op;
- tokenizer->advance(2);
+
}
} else if (tokenizer->get_token()==GDTokenizer::TK_BRACKET_OPEN) {
@@ -909,6 +1092,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
ConstantNode *cn = alloc_node<ConstantNode>();
Array arr(!p_to_const);
+ //print_line("mk array "+itos(!p_to_const));
arr.resize(an->elements.size());
for(int i=0;i<an->elements.size();i++) {
ConstantNode *acn = static_cast<ConstantNode*>(an->elements[i]);
@@ -1067,6 +1251,10 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
}
return op; //don't reduce yet
+
+ } else if (op->op==OperatorNode::OP_YIELD) {
+ return op;
+
} else if (op->op==OperatorNode::OP_INDEX) {
//can reduce indices into constant arrays or dictionaries
@@ -1089,7 +1277,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
cn->value=v;
return cn;
- } else if (op->arguments[0]->type==Node::TYPE_CONSTANT && op->arguments[1]->type==Node::TYPE_IDENTIFIER) {
+ } /*else if (op->arguments[0]->type==Node::TYPE_CONSTANT && op->arguments[1]->type==Node::TYPE_IDENTIFIER) {
ConstantNode *ca = static_cast<ConstantNode*>(op->arguments[0]);
IdentifierNode *ib = static_cast<IdentifierNode*>(op->arguments[1]);
@@ -1104,10 +1292,31 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
ConstantNode *cn = alloc_node<ConstantNode>();
cn->value=v;
return cn;
+ }*/
+
+ return op;
+
+ } else if (op->op==OperatorNode::OP_INDEX_NAMED) {
+
+ if (op->arguments[0]->type==Node::TYPE_CONSTANT && op->arguments[1]->type==Node::TYPE_IDENTIFIER) {
+
+ ConstantNode *ca = static_cast<ConstantNode*>(op->arguments[0]);
+ IdentifierNode *ib = static_cast<IdentifierNode*>(op->arguments[1]);
+
+ bool valid;
+ Variant v = ca->value.get_named(ib->name,&valid);
+ if (!valid) {
+ _set_error("invalid index '"+String(ib->name)+"' in constant expression");
+ return op;
+ }
+ ConstantNode *cn = alloc_node<ConstantNode>();
+ cn->value=v;
+ return cn;
}
return op;
+
}
//validate assignment (don't assign to cosntant expression
@@ -1126,7 +1335,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
case OperatorNode::OP_ASSIGN_BIT_XOR: {
if (op->arguments[0]->type==Node::TYPE_CONSTANT) {
- _set_error("Can't assign to constant");
+ _set_error("Can't assign to constant",tokenizer->get_token_line()-1);
return op;
}
@@ -1209,6 +1418,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();
@@ -1270,7 +1497,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
} break;
case GDTokenizer::TK_CF_PASS: {
- if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE ) {
+ if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE && tokenizer->get_token(1)!=GDTokenizer::TK_EOF) {
_set_error("Expected ';' or <NewLine>.");
return;
@@ -1306,8 +1533,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;
@@ -1328,16 +1561,22 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
op->arguments.push_back(assigned);
p_block->statements.push_back(op);
- _end_statement();
-
+ if (!_end_statement()) {
+ _set_error("Expected end of statement (var)");
+ return;
+ }
} break;
case GDTokenizer::TK_CF_IF: {
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>();
@@ -1345,6 +1584,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
cf_if->arguments.push_back(condition);
cf_if->body = alloc_node<BlockNode>();
+ cf_if->body->parent_block=p_block;
p_block->sub_blocks.push_back(cf_if->body);
if (!_enter_indent_block(cf_if->body)) {
@@ -1352,7 +1592,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ current_block=cf_if->body;
_parse_block(cf_if->body,p_static);
+ current_block=p_block;
+
if (error_set)
return;
p_block->statements.push_back(cf_if);
@@ -1379,6 +1622,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
tokenizer->advance();
cf_if->body_else=alloc_node<BlockNode>();
+ cf_if->body_else->parent_block=p_block;
p_block->sub_blocks.push_back(cf_if->body_else);
ControlFlowNode *cf_else = alloc_node<ControlFlowNode>();
@@ -1386,14 +1630,19 @@ 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;
cf_if->body_else->statements.push_back(cf_else);
cf_if=cf_else;
cf_if->body=alloc_node<BlockNode>();
+ cf_if->body->parent_block=p_block;
p_block->sub_blocks.push_back(cf_if->body);
@@ -1402,7 +1651,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ current_block=cf_else->body;
_parse_block(cf_else->body,p_static);
+ current_block=p_block;
if (error_set)
return;
@@ -1418,13 +1669,16 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
tokenizer->advance();
cf_if->body_else=alloc_node<BlockNode>();
+ cf_if->body_else->parent_block=p_block;
p_block->sub_blocks.push_back(cf_if->body_else);
if (!_enter_indent_block(cf_if->body_else)) {
p_block->end_line=tokenizer->get_token_line();
return;
}
+ current_block=cf_if->body_else;
_parse_block(cf_if->body_else,p_static);
+ current_block=p_block;
if (error_set)
return;
@@ -1442,8 +1696,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>();
@@ -1451,6 +1709,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
cf_while->arguments.push_back(condition);
cf_while->body = alloc_node<BlockNode>();
+ cf_while->body->parent_block=p_block;
p_block->sub_blocks.push_back(cf_while->body);
if (!_enter_indent_block(cf_while->body)) {
@@ -1458,7 +1717,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ current_block=cf_while->body;
_parse_block(cf_while->body,p_static);
+ current_block=p_block;
if (error_set)
return;
p_block->statements.push_back(cf_while);
@@ -1485,8 +1746,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>();
@@ -1495,6 +1760,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
cf_for->arguments.push_back(container);
cf_for->body = alloc_node<BlockNode>();
+ cf_for->body->parent_block=p_block;
p_block->sub_blocks.push_back(cf_for->body);
if (!_enter_indent_block(cf_for->body)) {
@@ -1502,7 +1768,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ current_block=cf_for->body;
_parse_block(cf_for->body,p_static);
+ current_block=p_block;
+
if (error_set)
return;
p_block->statements.push_back(cf_for);
@@ -1546,8 +1815,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()) {
@@ -1562,8 +1835,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);
@@ -1576,8 +1853,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
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.");
@@ -1661,9 +1942,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();
@@ -1736,8 +2023,10 @@ void GDParser::_parse_class(ClassNode *p_class) {
_parse_extends(p_class);
if (error_set)
return;
- _end_statement();
-
+ if (!_end_statement()) {
+ _set_error("Expected end of statement after extends");
+ return;
+ }
} break;
case GDTokenizer::TK_PR_TOOL: {
@@ -1768,7 +2057,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
ClassNode *newclass = alloc_node<ClassNode>();
newclass->initializer = alloc_node<BlockNode>();
+ newclass->initializer->parent_class=newclass;
newclass->name=name;
+ newclass->owner=p_class;
p_class->subclasses.push_back(newclass);
@@ -1785,7 +2076,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
_set_error("Indented block expected.");
return;
}
+ current_class=newclass;
_parse_class(newclass);
+ current_class=p_class;
} break;
/* this is for functions....
@@ -1814,14 +2107,20 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
- if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER) {
+ tokenizer->advance();
+ StringName name;
+
+ if (_get_completable_identifier(COMPLETION_VIRTUAL_FUNC,name)) {
+
+ }
+
+
+ if (name==StringName()) {
_set_error("Expected identifier after 'func' (syntax: 'func <identifier>([arguments]):' ).");
return;
}
- StringName name = tokenizer->get_token_identifier(1);
-
for(int i=0;i<p_class->functions.size();i++) {
if (p_class->functions[i]->name==name) {
_set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->functions[i]->line)+").");
@@ -1832,7 +2131,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
_set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->static_functions[i]->line)+").");
}
}
- tokenizer->advance(2);
+
if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) {
@@ -1923,6 +2222,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
tokenizer->advance();
BlockNode *block = alloc_node<BlockNode>();
+ block->parent_class=p_class;
if (name=="_init") {
@@ -1998,10 +2298,61 @@ void GDParser::_parse_class(ClassNode *p_class) {
p_class->functions.push_back(function);
- _parse_block(block,_static);
+ current_function=function;
function->body=block;
+ current_block=block;
+ _parse_block(block,_static);
+ current_block=NULL;
+
//arguments
} break;
+ case GDTokenizer::TK_PR_SIGNAL: {
+ tokenizer->advance();
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+ _set_error("Expected identifier after 'signal'.");
+ return;
+ }
+
+ ClassNode::Signal sig;
+ sig.name = tokenizer->get_token_identifier();
+ tokenizer->advance();
+
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) {
+ tokenizer->advance();
+ while(true) {
+
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ tokenizer->advance();
+ break;
+ }
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+ _set_error("Expected identifier in signal argument.");
+ return;
+ }
+
+ sig.arguments.push_back(tokenizer->get_token_identifier());
+ tokenizer->advance();
+
+ if (tokenizer->get_token()==GDTokenizer::TK_COMMA) {
+ tokenizer->advance();
+ } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ',' or ')' after signal parameter identifier.");
+ return;
+ }
+ }
+ }
+
+ p_class->_signals.push_back(sig);
+
+ if (!_end_statement()) {
+ _set_error("Expected end of statement (signal)");
+ return;
+ }
+ } break;
case GDTokenizer::TK_PR_EXPORT: {
tokenizer->advance();
@@ -2026,6 +2377,17 @@ 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) {
+ _set_error("Expected ')' in hint.");
+ return;
+ }
+ break;
+ }
+
if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING) {
//enumeration
current_export.hint=PROPERTY_HINT_ENUM;
@@ -2036,6 +2398,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
current_export=PropertyInfo();
_set_error("Expected a string constant in enumeration hint.");
+ return;
}
String c = tokenizer->get_token_constant();
@@ -2053,6 +2416,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) {
current_export=PropertyInfo();
_set_error("Expected ')' or ',' in enumeration hint.");
+ return;
}
tokenizer->advance();
@@ -2062,19 +2426,36 @@ void GDParser::_parse_class(ClassNode *p_class) {
break;
}
- };
+ }; //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;
+ }
+
+ float sign=1.0;
+
+ if (tokenizer->get_token()==GDTokenizer::TK_OP_SUB) {
+ sign=-1;
+ tokenizer->advance();
+ }
if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) {
current_export=PropertyInfo();
_set_error("Expected a range in numeric hint.");
+ return;
}
//enumeration
current_export.hint=PROPERTY_HINT_RANGE;
- current_export.hint_string=tokenizer->get_token_constant().operator String();
+ current_export.hint_string=rtos(sign*double(tokenizer->get_token_constant()));
tokenizer->advance();
if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
@@ -2086,17 +2467,25 @@ void GDParser::_parse_class(ClassNode *p_class) {
current_export=PropertyInfo();
_set_error("Expected ',' or ')' in numeric range hint.");
+ return;
}
tokenizer->advance();
+ sign=1.0;
+ if (tokenizer->get_token()==GDTokenizer::TK_OP_SUB) {
+ sign=-1;
+ tokenizer->advance();
+ }
+
if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) {
current_export=PropertyInfo();
_set_error("Expected a number as upper bound in numeric range hint.");
+ return;
}
- current_export.hint_string+=","+tokenizer->get_token_constant().operator String();
+ current_export.hint_string+=","+rtos(sign*double(tokenizer->get_token_constant()));
tokenizer->advance();
if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE)
@@ -2106,17 +2495,24 @@ void GDParser::_parse_class(ClassNode *p_class) {
current_export=PropertyInfo();
_set_error("Expected ',' or ')' in numeric range hint.");
+ return;
}
tokenizer->advance();
+ sign=1.0;
+ if (tokenizer->get_token()==GDTokenizer::TK_OP_SUB) {
+ sign=-1;
+ tokenizer->advance();
+ }
if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) {
current_export=PropertyInfo();
_set_error("Expected a number as step in numeric range hint.");
+ return;
}
- current_export.hint_string+=","+tokenizer->get_token_constant().operator String();
+ current_export.hint_string+=","+rtos(sign*double(tokenizer->get_token_constant()));
tokenizer->advance();
} break;
@@ -2132,6 +2528,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
current_export=PropertyInfo();
_set_error("Expected a string constant in enumeration hint.");
+ return;
}
String c = tokenizer->get_token_constant();
@@ -2192,6 +2589,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: {
@@ -2279,86 +2687,129 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
member.identifier=tokenizer->get_token_identifier();
+ member.expression=NULL;
member._export.name=member.identifier;
+ member.line=tokenizer->get_token_line();
tokenizer->advance();
- p_class->variables.push_back(member);
+ if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) {
- if (tokenizer->get_token()!=GDTokenizer::TK_OP_ASSIGN) {
+#ifdef DEBUG_ENABLED
+ int line = tokenizer->get_token_line();
+#endif
+ tokenizer->advance();
- if (autoexport) {
+ Node *subexpr=NULL;
- _set_error("Type-less export needs a constant expression assigned to infer type.");
+ subexpr = _parse_and_reduce_expression(p_class,false,autoexport);
+ if (!subexpr) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
}
- break;
- }
-#ifdef DEBUG_ENABLED
- int line = tokenizer->get_token_line();
-#endif
- tokenizer->advance();
- Node *subexpr=NULL;
+ member.expression=subexpr;
- subexpr = _parse_and_reduce_expression(p_class,false);
- if (!subexpr)
- return;
+ if (autoexport) {
+ if (1)/*(subexpr->type==Node::TYPE_ARRAY) {
- if (autoexport) {
- if (subexpr->type==Node::TYPE_ARRAY) {
+ member._export.type=Variant::ARRAY;
- p_class->variables[p_class->variables.size()-1]._export.type=Variant::ARRAY;
+ } else if (subexpr->type==Node::TYPE_DICTIONARY) {
- } else if (subexpr->type==Node::TYPE_DICTIONARY) {
+ member._export.type=Variant::DICTIONARY;
- p_class->variables[p_class->variables.size()-1]._export.type=Variant::DICTIONARY;
+ } else*/ {
- } else {
+ if (subexpr->type!=Node::TYPE_CONSTANT) {
- if (subexpr->type!=Node::TYPE_CONSTANT) {
+ _set_error("Type-less export needs a constant expression assigned to infer type.");
+ return;
+ }
- _set_error("Type-less export needs a constant expression assigned to infer type.");
- return;
+ ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
+ if (cn->value.get_type()==Variant::NIL) {
+
+ _set_error("Can't accept a null constant expression for infering export type.");
+ return;
+ }
+ member._export.type=cn->value.get_type();
}
+ }
+#ifdef TOOLS_ENABLED
+ if (subexpr->type==Node::TYPE_CONSTANT && member._export.type!=Variant::NIL) {
ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
- if (cn->value.get_type()==Variant::NIL) {
-
- _set_error("Can't accept a null constant expression for infering export type.");
- return;
+ if (cn->value.get_type()!=Variant::NIL) {
+ member.default_value=cn->value;
}
- p_class->variables[p_class->variables.size()-1]._export.type=cn->value.get_type();
}
- }
-#ifdef TOOLS_ENABLED
- if (subexpr->type==Node::TYPE_CONSTANT && p_class->variables[p_class->variables.size()-1]._export.type!=Variant::NIL) {
+#endif
+
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name=member.identifier;
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op=OperatorNode::OP_INIT_ASSIGN;
+ 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);
+#endif
+ p_class->initializer->statements.push_back(op);
+
+
+
+ } else {
+
+ if (autoexport) {
- ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
- if (cn->value.get_type()!=Variant::NIL) {
- p_class->variables[p_class->variables.size()-1].default_value=cn->value;
+ _set_error("Type-less export needs a constant expression assigned to infer type.");
+ return;
}
+
}
-#endif
+ if (tokenizer->get_token()==GDTokenizer::TK_PR_SETGET) {
- IdentifierNode *id = alloc_node<IdentifierNode>();
- id->name=member.identifier;
+ tokenizer->advance();
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op=OperatorNode::OP_ASSIGN;
- op->arguments.push_back(id);
- op->arguments.push_back(subexpr);
+ if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) {
+ //just comma means using only getter
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+ _set_error("Expected identifier for setter function after 'notify'.");
+ }
-#ifdef DEBUG_ENABLED
- NewLineNode *nl = alloc_node<NewLineNode>();
- nl->line=line;
- p_class->initializer->statements.push_back(nl);
-#endif
- p_class->initializer->statements.push_back(op);
+ member.setter=tokenizer->get_token_identifier();
+
+ tokenizer->advance();
+ }
+
+ if (tokenizer->get_token()==GDTokenizer::TK_COMMA) {
+ //there is a getter
+ tokenizer->advance();
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+ _set_error("Expected identifier for getter function after ','.");
+ }
+
+ member.getter=tokenizer->get_token_identifier();
+ tokenizer->advance();
- _end_statement();
+ }
+ }
+ p_class->variables.push_back(member);
+
+ if (!_end_statement()) {
+ _set_error("Expected end of statement (continue)");
+ return;
+ }
} break;
case GDTokenizer::TK_PR_CONST: {
//variale declaration and (eventual) initialization
@@ -2385,8 +2836,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");
@@ -2395,8 +2850,10 @@ void GDParser::_parse_class(ClassNode *p_class) {
p_class->constant_expressions.push_back(constant);
- _end_statement();
-
+ if (!_end_statement()) {
+ _set_error("Expected end of statement (constant)");
+ return;
+ }
} break;
@@ -2453,6 +2910,8 @@ Error GDParser::_parse(const String& p_base_path) {
//assume class
ClassNode *main_class = alloc_node<ClassNode>();
main_class->initializer = alloc_node<BlockNode>();
+ main_class->initializer->parent_class=main_class;
+ current_class=main_class;
_parse_class(main_class);
@@ -2468,8 +2927,21 @@ Error GDParser::_parse(const String& p_base_path) {
return OK;
}
-Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,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;
+
+ self_path=p_self_path;
GDTokenizerBuffer *tb = memnew( GDTokenizerBuffer );
tb->set_code_buffer(p_bytecode);
tokenizer=tb;
@@ -2480,13 +2952,25 @@ 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) {
+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;
+ current_function=NULL;
+ self_path=p_self_path;
GDTokenizerText *tt = memnew( GDTokenizerText );
tt->set_code(p_code);
validating=p_just_validate;
+ for_completion=p_for_completion;
tokenizer=tt;
Error ret = _parse(p_base_path);
memdelete(tt);
@@ -2511,7 +2995,20 @@ void GDParser::clear() {
head=NULL;
list=NULL;
+ completion_type=COMPLETION_NONE;
+ completion_node=NULL;
+ completion_class=NULL;
+ completion_function=NULL;
+ completion_block=NULL;
+ 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);
@@ -2524,6 +3021,52 @@ void GDParser::clear() {
}
+
+GDParser::CompletionType GDParser::get_completion_type() {
+
+ return completion_type;
+}
+
+StringName GDParser::get_completion_cursor() {
+
+ return completion_cursor;
+}
+
+int GDParser::get_completion_line() {
+
+ return completion_line;
+}
+
+Variant::Type GDParser::get_completion_built_in_constant(){
+
+ return completion_built_in_constant;
+}
+
+GDParser::Node *GDParser::get_completion_node(){
+
+ return completion_node;
+}
+
+GDParser::BlockNode *GDParser::get_completion_block() {
+
+ return completion_block;
+}
+
+GDParser::ClassNode *GDParser::get_completion_class(){
+
+ return completion_class;
+}
+
+GDParser::FunctionNode *GDParser::get_completion_function(){
+
+ return completion_function;
+}
+
+int GDParser::get_completion_argument_index() {
+
+ return completion_argument;
+}
+
GDParser::GDParser() {
head=NULL;
diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h
index ae43a26f5a..04f3dff3de 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -76,28 +76,40 @@ public:
StringName extends_file;
Vector<StringName> extends_class;
+
struct Member {
PropertyInfo _export;
#ifdef TOOLS_ENABLED
Variant default_value;
#endif
StringName identifier;
+ StringName setter;
+ StringName getter;
+ int line;
+ Node *expression;
};
struct Constant {
StringName identifier;
Node *expression;
};
+ struct Signal {
+ StringName name;
+ Vector<StringName> arguments;
+ };
+
Vector<ClassNode*> subclasses;
Vector<Member> variables;
Vector<Constant> constant_expressions;
Vector<FunctionNode*> functions;
Vector<FunctionNode*> static_functions;
+ Vector<Signal> _signals;
BlockNode *initializer;
+ ClassNode *owner;
//Vector<Node*> initializers;
int end_line;
- ClassNode() { tool=false; type=TYPE_CLASS; extends_used=false; end_line=-1;}
+ ClassNode() { tool=false; type=TYPE_CLASS; extends_used=false; end_line=-1; owner=NULL;}
};
@@ -116,6 +128,8 @@ public:
struct BlockNode : public Node {
+ ClassNode *parent_class;
+ BlockNode *parent_block;
Map<StringName,int> locals;
List<Node*> statements;
Vector<StringName> variables;
@@ -124,7 +138,7 @@ public:
//the following is useful for code completion
List<BlockNode*> sub_blocks;
int end_line;
- BlockNode() { type=TYPE_BLOCK; end_line=-1;}
+ BlockNode() { type=TYPE_BLOCK; end_line=-1; parent_block=NULL; parent_class=NULL; }
};
struct TypeNode : public Node {
@@ -183,6 +197,7 @@ public:
//call/constructor operator
OP_CALL,
OP_PARENT_CALL,
+ OP_YIELD,
OP_EXTENDS,
//indexing operator
OP_INDEX,
@@ -212,6 +227,7 @@ public:
OP_MOD,
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
+ OP_INIT_ASSIGN,
OP_ASSIGN,
OP_ASSIGN_ADD,
OP_ASSIGN_SUB,
@@ -225,7 +241,7 @@ public:
OP_ASSIGN_BIT_XOR,
OP_BIT_AND,
OP_BIT_OR,
- OP_BIT_XOR
+ OP_BIT_XOR,
};
Operator op;
@@ -258,8 +274,8 @@ public:
Node* condition;
AssertNode() { type=TYPE_ASSERT; }
};
+
struct NewLineNode : public Node {
- int line;
NewLineNode() { type=TYPE_NEWLINE; }
};
@@ -344,6 +360,19 @@ public:
};
*/
+ enum CompletionType {
+ COMPLETION_NONE,
+ COMPLETION_BUILT_IN_TYPE_CONSTANT,
+ COMPLETION_FUNCTION,
+ COMPLETION_IDENTIFIER,
+ COMPLETION_PARENT_FUNCTION,
+ COMPLETION_METHOD,
+ COMPLETION_CALL_ARGUMENTS,
+ COMPLETION_INDEX,
+ COMPLETION_VIRTUAL_FUNC
+ };
+
+
private:
@@ -357,6 +386,7 @@ private:
T* alloc_node();
bool validating;
+ bool for_completion;
int parenthesis;
bool error_set;
String error;
@@ -368,13 +398,35 @@ private:
List<int> tab_level;
String base_path;
+ String self_path;
+
+
+ ClassNode *current_class;
+ FunctionNode *current_function;
+ BlockNode *current_block;
+
+ bool _get_completable_identifier(CompletionType p_type,StringName& identifier);
+ void _make_completable_call(int p_arg);
+
+ CompletionType completion_type;
+ StringName completion_cursor;
+ bool completion_static;
+ Variant::Type completion_built_in_constant;
+ Node *completion_node;
+ ClassNode *completion_class;
+ FunctionNode *completion_function;
+ 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 _parse_arguments(Node* p_parent, Vector<Node*>& p_args, bool p_static, bool p_can_codecomplete=false);
bool _enter_indent_block(BlockNode *p_block=NULL);
bool _parse_newline();
Node* _parse_expression(Node *p_parent,bool p_static,bool p_allow_assign=false);
@@ -393,11 +445,24 @@ 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);
- Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_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;
+ //completion info
+
+ CompletionType get_completion_type();
+ StringName get_completion_cursor();
+ int get_completion_line();
+ Variant::Type get_completion_built_in_constant();
+ Node *get_completion_node();
+ ClassNode *get_completion_class();
+ BlockNode *get_completion_block();
+ FunctionNode *get_completion_function();
+ int get_completion_argument_index();
+
+
void clear();
GDParser();
~GDParser();
diff --git a/modules/gdscript/gd_pretty_print.cpp b/modules/gdscript/gd_pretty_print.cpp
index a5a993bb3a..9c290eac4a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/modules/gdscript/gd_pretty_print.h b/modules/gdscript/gd_pretty_print.h
index fbf002295b..998fdc53ab 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index cc7aa70234..c3cc779bce 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -140,7 +140,7 @@ String GDFunction::_get_call_error(const Variant::CallError& p_err, const String
} else if (p_err.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
err_text="Invalid call to "+p_where+". Expected "+itos(p_err.argument)+" arguments.";
} else if (p_err.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) {
- err_text="Invalid call. Unexisting "+p_where+".";
+ err_text="Invalid call. Nonexistent "+p_where+".";
} else if (p_err.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
err_text="Attempt to call "+p_where+" on a null instance.";
} else {
@@ -183,7 +183,7 @@ static String _get_var_type(const Variant* p_type) {
}
-Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err) {
+Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError& r_err, CallState *p_state) {
if (!_code_ptr) {
@@ -205,77 +205,91 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
#endif
- if (p_argcount!=_argument_count) {
+ uint32_t alloca_size=0;
+ GDScript *_class;
+ int ip=0;
+ int line=_initial_line;
- if (p_argcount>_argument_count) {
+ if (p_state) {
+ //use existing (supplied) state (yielded)
+ stack=(Variant*)p_state->stack.ptr();
+ call_args=(Variant**)&p_state->stack[sizeof(Variant)*p_state->stack_size];
+ line=p_state->line;
+ ip=p_state->ip;
+ alloca_size=p_state->stack.size();
+ _class=p_state->_class;
+ p_instance=p_state->instance;
+ defarg=p_state->defarg;
+ self=p_state->self;
+ //stack[p_state->result_pos]=p_state->result; //assign stack with result
- r_err.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_err.argument=_argument_count;
+ } else {
- return Variant();
- } else if (p_argcount < _argument_count - _default_arg_count) {
+ if (p_argcount!=_argument_count) {
- r_err.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_err.argument=_argument_count - _default_arg_count;
- return Variant();
- } else {
+ if (p_argcount>_argument_count) {
- defarg=_argument_count-p_argcount;
- }
- }
+ r_err.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_err.argument=_argument_count;
- uint32_t alloca_size = sizeof(Variant*)*_call_size + sizeof(Variant)*_stack_size;
+ return Variant();
+ } else if (p_argcount < _argument_count - _default_arg_count) {
- if (alloca_size) {
+ r_err.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_err.argument=_argument_count - _default_arg_count;
+ return Variant();
+ } else {
- uint8_t *aptr = (uint8_t*)alloca(alloca_size);
+ defarg=_argument_count-p_argcount;
+ }
+ }
- if (_stack_size) {
+ alloca_size = sizeof(Variant*)*_call_size + sizeof(Variant)*_stack_size;
- stack=(Variant*)aptr;
- for(int i=0;i<p_argcount;i++)
- memnew_placement(&stack[i],Variant(*p_args[i]));
- for(int i=p_argcount;i<_stack_size;i++)
- memnew_placement(&stack[i],Variant);
- } else {
- stack=NULL;
- }
+ if (alloca_size) {
- if (_call_size) {
+ uint8_t *aptr = (uint8_t*)alloca(alloca_size);
- call_args = (Variant**)&aptr[sizeof(Variant)*_stack_size];
- } else {
+ if (_stack_size) {
- call_args=NULL;
- }
+ stack=(Variant*)aptr;
+ for(int i=0;i<p_argcount;i++)
+ memnew_placement(&stack[i],Variant(*p_args[i]));
+ for(int i=p_argcount;i<_stack_size;i++)
+ memnew_placement(&stack[i],Variant);
+ } else {
+ stack=NULL;
+ }
+ if (_call_size) {
- } else {
- stack=NULL;
- call_args=NULL;
- }
+ call_args = (Variant**)&aptr[sizeof(Variant)*_stack_size];
+ } else {
+ call_args=NULL;
+ }
- GDScript *_class;
- if (p_instance) {
- if (p_instance->base_ref && static_cast<Reference*>(p_instance->owner)->is_referenced()) {
+ } else {
+ stack=NULL;
+ call_args=NULL;
+ }
- self=REF(static_cast<Reference*>(p_instance->owner));
+ if (p_instance) {
+ if (p_instance->base_ref && static_cast<Reference*>(p_instance->owner)->is_referenced()) {
+
+ self=REF(static_cast<Reference*>(p_instance->owner));
+ } else {
+ self=p_instance->owner;
+ }
+ _class=p_instance->script.ptr();
} else {
- self=p_instance->owner;
+ _class=_script;
}
- _class=p_instance->script.ptr();
- } else {
- _class=_script;
}
- int ip=0;
- int line=_initial_line;
String err_text;
-
-
#ifdef DEBUG_ENABLED
if (ScriptDebugger::get_singleton())
@@ -321,16 +335,30 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
GET_VARIANT_PTR(b,3);
GET_VARIANT_PTR(dst,4);
+#ifdef DEBUG_ENABLED
+ Variant ret;
+ Variant::evaluate(op,*a,*b,ret,valid);
+#else
Variant::evaluate(op,*a,*b,*dst,valid);
+#endif
+
if (!valid) {
- if (false && dst->get_type()==Variant::STRING) {
+#ifdef DEBUG_ENABLED
+
+ if (ret.get_type()==Variant::STRING) {
//return a string when invalid with the error
- err_text=*dst;
+ err_text=ret;
+ err_text += " in operator '"+Variant::get_operator_name(op)+"'.";
} else {
err_text="Invalid operands '"+Variant::get_type_name(a->get_type())+"' and '"+Variant::get_type_name(b->get_type())+"' in operator '"+Variant::get_operator_name(op)+"'.";
}
+#endif
break;
+
}
+#ifdef DEBUG_ENABLED
+ *dst=ret;
+#endif
ip+=5;
@@ -442,8 +470,13 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
GET_VARIANT_PTR(dst,3);
bool valid;
+#ifdef DEBUG_ENABLED
+//allow better error message in cases where src and dst are the same stack position
+ Variant ret = src->get(*index,&valid);
+#else
*dst = src->get(*index,&valid);
+#endif
if (!valid) {
String v = index->operator String();
if (v!="") {
@@ -454,6 +487,9 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
err_text="Invalid get index "+v+" (on base: '"+_get_var_type(src)+"').";
break;
}
+#ifdef DEBUG_ENABLED
+ *dst=ret;
+#endif
ip+=4;
} continue;
case OPCODE_SET_NAMED: {
@@ -493,13 +529,25 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
const StringName *index = &_global_names_ptr[indexname];
bool valid;
+#ifdef DEBUG_ENABLED
+//allow better error message in cases where src and dst are the same stack position
+ Variant ret = src->get_named(*index,&valid);
+
+#else
*dst = src->get_named(*index,&valid);
+#endif
if (!valid) {
- err_text="Invalid get index '"+index->operator String()+"' (on base: '"+_get_var_type(src)+"').";
+ if (src->has_method(*index)) {
+ err_text="Invalid get index '"+index->operator String()+"' (on base: '"+_get_var_type(src)+"'). Did you mean '."+index->operator String()+"()' ?";
+ } else {
+ err_text="Invalid get index '"+index->operator String()+"' (on base: '"+_get_var_type(src)+"').";
+ }
break;
}
-
+#ifdef DEBUG_ENABLED
+ *dst=ret;
+#endif
ip+=4;
} continue;
case OPCODE_ASSIGN: {
@@ -784,6 +832,97 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
ip+=4+argc;
} continue;
+ case OPCODE_YIELD:
+ case OPCODE_YIELD_SIGNAL: {
+
+ int ipofs=1;
+ if (_code_ptr[ip]==OPCODE_YIELD_SIGNAL) {
+ CHECK_SPACE(4);
+ ipofs+=2;
+ } else {
+ CHECK_SPACE(2);
+
+ }
+
+ Ref<GDFunctionState> gdfs = memnew( GDFunctionState );
+ gdfs->function=this;
+
+ gdfs->state.stack.resize(alloca_size);
+ //copy variant stack
+ for(int i=0;i<_stack_size;i++) {
+ memnew_placement(&gdfs->state.stack[sizeof(Variant)*i],Variant(stack[i]));
+ }
+ gdfs->state.stack_size=_stack_size;
+ gdfs->state.self=self;
+ gdfs->state.alloca_size=alloca_size;
+ gdfs->state._class=_class;
+ gdfs->state.ip=ip+ipofs;
+ gdfs->state.line=line;
+ //gdfs->state.result_pos=ip+ipofs-1;
+ gdfs->state.defarg=defarg;
+ gdfs->state.instance=p_instance;
+ gdfs->function=this;
+
+ retvalue=gdfs;
+
+ if (_code_ptr[ip]==OPCODE_YIELD_SIGNAL) {
+ GET_VARIANT_PTR(argobj,1);
+ GET_VARIANT_PTR(argname,2);
+ //do the oneshot connect
+
+ if (argobj->get_type()!=Variant::OBJECT) {
+ err_text="First argument of yield() not of type object.";
+ break;
+ }
+ if (argname->get_type()!=Variant::STRING) {
+ err_text="Second argument of yield() not a string (for signal name).";
+ break;
+ }
+ Object *obj=argobj->operator Object *();
+ String signal = argname->operator String();
+#ifdef DEBUG_ENABLED
+
+ if (!obj) {
+ err_text="First argument of yield() is null.";
+ break;
+ }
+ if (ScriptDebugger::get_singleton()) {
+ if (!ObjectDB::instance_validate(obj)) {
+ err_text="First argument of yield() is a previously freed instance.";
+ break;
+ }
+ }
+ if (signal.length()==0) {
+
+ err_text="Second argument of yield() is an empty string (for signal name).";
+ break;
+ }
+
+#endif
+ Error err = obj->connect(signal,gdfs.ptr(),"_signal_callback",varray(gdfs),Object::CONNECT_ONESHOT);
+ if (err!=OK) {
+ err_text="Error connecting to signal: "+signal+" during yield().";
+ break;
+ }
+
+
+ }
+
+ exit_ok=true;
+
+ } break;
+ case OPCODE_YIELD_RESUME: {
+
+ CHECK_SPACE(2);
+ if (!p_state) {
+ err_text=("Invalid Resume (bug?)");
+ break;
+ }
+ GET_VARIANT_PTR(result,1);
+ *result=p_state->result;
+ ip+=2;
+
+ } continue;
case OPCODE_JUMP: {
CHECK_SPACE(2);
@@ -1168,6 +1307,93 @@ GDFunction::GDFunction() {
}
+/////////////////////
+
+
+Variant GDFunctionState::_signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+
+ Variant arg;
+ r_error.error=Variant::CallError::CALL_OK;
+
+ ERR_FAIL_COND_V(!function,Variant());
+
+ if (p_argcount==0) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=1;
+ return Variant();
+ } else if (p_argcount==1) {
+ //noooneee
+ } else if (p_argcount==2) {
+ arg=*p_args[0];
+ } else {
+ Array extra_args;
+ for(int i=0;i<p_argcount-1;i++) {
+ extra_args.push_back(*p_args[i]);
+ }
+ arg=extra_args;
+ }
+
+ Ref<GDFunctionState> self = *p_args[p_argcount-1];
+
+ if (self.is_null()) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=p_argcount-1;
+ r_error.expected=Variant::OBJECT;
+ return Variant();
+ }
+
+ state.result=arg;
+ Variant ret = function->call(NULL,NULL,0,r_error,&state);
+ function=NULL; //cleaned up;
+ state.result=Variant();
+ return ret;
+}
+
+
+bool GDFunctionState::is_valid() const {
+
+ return function!=NULL;
+}
+
+Variant GDFunctionState::resume(const Variant& p_arg) {
+
+ ERR_FAIL_COND_V(!function,Variant());
+
+ state.result=p_arg;
+ Variant::CallError err;
+ Variant ret = function->call(NULL,NULL,0,err,&state);
+ function=NULL; //cleaned up;
+ state.result=Variant();
+ return ret;
+}
+
+
+void GDFunctionState::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("resume:var","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"));
+
+}
+
+GDFunctionState::GDFunctionState() {
+
+ function=NULL;
+}
+
+GDFunctionState::~GDFunctionState() {
+
+ if (function!=NULL) {
+ //never called, deinitialize stack
+ for(int i=0;i<state.stack_size;i++) {
+ Variant *v=(Variant*)&state.stack[sizeof(Variant)*i];
+ v->~Variant();
+ }
+ }
+}
+
+///////////////////////////
+
GDNativeClass::GDNativeClass(const StringName& p_name) {
name=p_name;
@@ -1223,7 +1449,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 */
@@ -1239,14 +1465,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);
- memdelete(instance);
- 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
@@ -1279,7 +1504,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
@@ -1296,7 +1521,9 @@ Variant GDScript::_new(const Variant** p_args,int p_argcount,Variant::CallError&
bool GDScript::can_instance() const {
- return valid; //any script in GDscript can instance
+ //return valid; //any script in GDscript can instance
+ return valid || (!tool && !ScriptServer::is_scripting_enabled());
+
}
StringName GDScript::get_instance_base_type() const {
@@ -1325,6 +1552,7 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
placeholders.erase(p_placeholder);
}
+/*
void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
@@ -1339,7 +1567,7 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
_GDScriptMemberSort ms;
ERR_CONTINUE(!scr->member_indices.has(E->key()));
- ms.index=scr->member_indices[E->key()];
+ ms.index=scr->member_indices[E->key()].index;
ms.name=E->key();
msort.push_back(ms);
@@ -1365,12 +1593,14 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
p_placeholder->update(plist,default_values);
-}
+}*/
#endif
ScriptInstance* GDScript::instance_create(Object *p_this) {
+
if (!tool && !ScriptServer::is_scripting_enabled()) {
+
#ifdef TOOLS_ENABLED
//instance a fake script for editing the values
@@ -1382,7 +1612,8 @@ ScriptInstance* GDScript::instance_create(Object *p_this) {
}*/
PlaceHolderScriptInstance *si = memnew( PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(),Ref<Script>(this),p_this) );
placeholders.insert(si);
- _update_placeholder(si);
+ //_update_placeholder(si);
+ _update_exports();
return si;
#else
return NULL;
@@ -1405,7 +1636,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 {
@@ -1423,8 +1655,166 @@ String GDScript::get_source_code() const {
}
void GDScript::set_source_code(const String& p_code) {
+ if (source==p_code)
+ return;
source=p_code;
+#ifdef TOOLS_ENABLED
+ source_changed_cache=true;
+ //print_line("SC CHANGED "+get_path());
+#endif
+
+}
+
+#ifdef TOOLS_ENABLED
+void GDScript::_update_exports_values(Map<StringName,Variant>& values, List<PropertyInfo> &propnames) {
+
+ if (base_cache.is_valid()) {
+ base_cache->_update_exports_values(values,propnames);
+ }
+
+ for(Map<StringName,Variant>::Element *E=member_default_values_cache.front();E;E=E->next()) {
+ values[E->key()]=E->get();
+ }
+
+ for (List<PropertyInfo>::Element *E=members_cache.front();E;E=E->next()) {
+ propnames.push_back(E->get());
+ }
+
+}
+#endif
+
+bool GDScript::_update_exports() {
+
+#ifdef TOOLS_ENABLED
+
+ bool changed=false;
+
+ if (source_changed_cache) {
+ //print_line("updating source for "+get_path());
+ source_changed_cache=false;
+ changed=true;
+
+ String basedir=path;
+
+ if (basedir=="")
+ basedir=get_path();
+
+ if (basedir!="")
+ basedir=basedir.get_base_dir();
+
+ GDParser parser;
+ Error err = parser.parse(source,basedir,true,path);
+
+ if (err==OK) {
+
+ const GDParser::Node* root = parser.get_parse_tree();
+ ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,false);
+
+ const GDParser::ClassNode *c = static_cast<const GDParser::ClassNode*>(root);
+
+ if (base_cache.is_valid()) {
+ base_cache->inheriters_cache.erase(get_instance_ID());
+ base_cache=Ref<GDScript>();
+ }
+
+
+ if (c->extends_used && String(c->extends_file)!="" && String(c->extends_file) != get_path()) {
+
+ String path = c->extends_file;
+ if (path.is_rel_path()) {
+
+ String base = get_path();
+ if (base=="" || base.is_rel_path()) {
+
+ ERR_PRINT(("Could not resolve relative path for parent class: "+path).utf8().get_data());
+ } else {
+ path=base.get_base_dir().plus_file(path);
+ }
+ }
+
+ Ref<GDScript> bf = ResourceLoader::load(path);
+
+ if (bf.is_valid()) {
+
+ //print_line("parent is: "+bf->get_path());
+ base_cache=bf;
+ bf->inheriters_cache.insert(get_instance_ID());
+
+ //bf->_update_exports(p_instances,true,false);
+
+ }
+ }
+
+ members_cache.clear();;
+ member_default_values_cache.clear();
+
+ for(int i=0;i<c->variables.size();i++) {
+ if (c->variables[i]._export.type==Variant::NIL)
+ continue;
+
+ members_cache.push_back(c->variables[i]._export);
+ //print_line("found "+c->variables[i]._export.name);
+ member_default_values_cache[c->variables[i].identifier]=c->variables[i].default_value;
+ }
+
+ _signals.clear();
+
+ for(int i=0;i<c->_signals.size();i++) {
+ _signals[c->_signals[i].name]=c->_signals[i].arguments;
+ }
+ }
+ } else {
+ //print_line("unchaged is "+get_path());
+
+ }
+
+ if (base_cache.is_valid()) {
+ if (base_cache->_update_exports()) {
+ changed = true;
+ }
+ }
+
+ if (/*changed &&*/ placeholders.size()) { //hm :(
+
+ //print_line("updating placeholders for "+get_path());
+
+ //update placeholders if any
+ Map<StringName,Variant> values;
+ List<PropertyInfo> propnames;
+ _update_exports_values(values,propnames);
+
+ for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
+
+ E->get()->update(propnames,values);
+ }
+ }
+
+ return changed;
+
+#endif
+ return false;
+}
+
+void GDScript::update_exports() {
+
+#ifdef TOOLS_ENABLED
+
+ _update_exports();
+
+ Set<ObjectID> copy=inheriters_cache; //might get modified
+ //print_line("update exports for "+get_path()+" ic: "+itos(copy.size()));
+ for(Set<ObjectID>::Element *E=copy.front();E;E=E->next()) {
+ Object *id=ObjectDB::get_instance(E->get());
+ if (!id)
+ continue;
+ GDScript *s=id->cast_to<GDScript>();
+ if (!s)
+ continue;
+ s->update_exports();
+ }
+
+#endif
}
void GDScript::_set_subclass_path(Ref<GDScript>& p_sc,const String& p_path) {
@@ -1454,7 +1844,7 @@ Error GDScript::reload() {
valid=false;
GDParser parser;
- Error err = parser.parse(source,basedir);
+ Error err = parser.parse(source,basedir,false,path);
if (err) {
if (ScriptDebugger::get_singleton()) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),parser.get_error_line(),"Parser Error: "+parser.get_error());
@@ -1482,10 +1872,10 @@ Error GDScript::reload() {
}
#ifdef TOOLS_ENABLED
- for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
+ /*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
_update_placeholder(E->get());
- }
+ }*/
#endif
return OK;
}
@@ -1587,9 +1977,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) {
@@ -1628,7 +2026,7 @@ Error GDScript::load_byte_code(const String& p_path) {
valid=false;
GDParser parser;
- Error err = parser.parse_bytecode(bytecode,basedir);
+ Error err = parser.parse_bytecode(bytecode,basedir,get_path());
if (err) {
_err_print_error("GDScript::load_byte_code",path.empty()?"built-in":(const char*)path.utf8().get_data(),parser.get_error_line(),("Parse Error: "+parser.get_error()).utf8().get_data());
ERR_FAIL_V(ERR_PARSE_ERROR);
@@ -1681,6 +2079,10 @@ Error GDScript::load_source_code(const String& p_path) {
}
source=s;
+#ifdef TOOLS_ENABLED
+ source_changed_cache=true;
+#endif
+ //print_line("LSC :"+get_path());
path=p_path;
return OK;
@@ -1697,9 +2099,9 @@ const Map<StringName,GDFunction>& GDScript::debug_get_member_functions() const {
StringName GDScript::debug_get_member_by_index(int p_idx) const {
- for(const Map<StringName,int>::Element *E=member_indices.front();E;E=E->next()) {
+ for(const Map<StringName,MemberInfo>::Element *E=member_indices.front();E;E=E->next()) {
- if (E->get()==p_idx)
+ if (E->get().index==p_idx)
return E->key();
}
@@ -1712,6 +2114,47 @@ Ref<GDScript> GDScript::get_base() const {
return base;
}
+bool GDScript::has_script_signal(const StringName& p_signal) const {
+ if (_signals.has(p_signal))
+ return true;
+ if (base.is_valid()) {
+ return base->has_script_signal(p_signal);
+ }
+#ifdef TOOLS_ENABLED
+ else if (base_cache.is_valid()){
+ return base_cache->has_script_signal(p_signal);
+ }
+
+#endif
+ return false;
+}
+void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+
+ for(const Map<StringName,Vector<StringName> >::Element *E=_signals.front();E;E=E->next()) {
+
+ MethodInfo mi;
+ mi.name=E->key();
+ for(int i=0;i<E->get().size();i++) {
+ PropertyInfo arg;
+ arg.name=E->get()[i];
+ mi.arguments.push_back(arg);
+ }
+ r_signals->push_back(mi);
+ }
+
+ if (base.is_valid()) {
+ base->get_script_signal_list(r_signals);
+ }
+#ifdef TOOLS_ENABLED
+ else if (base_cache.is_valid()){
+ base_cache->get_script_signal_list(r_signals);
+ }
+
+#endif
+
+}
+
+
GDScript::GDScript() {
@@ -1722,6 +2165,9 @@ GDScript::GDScript() {
_base=NULL;
_owner=NULL;
tool=false;
+#ifdef TOOLS_ENABLED
+ source_changed_cache=false;
+#endif
}
@@ -1738,11 +2184,19 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) {
//member
{
- const Map<StringName,int>::Element *E = script->member_indices.find(p_name);
+ const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
if (E) {
- members[E->get()]=p_value;
+ if (E->get().setter) {
+ const Variant *val=&p_value;
+ Variant::CallError err;
+ call(E->get().setter,&val,1,err);
+ if (err.error==Variant::CallError::CALL_OK) {
+ return true; //function exists, call was successful
+ }
+ }
+ else
+ members[E->get().index] = p_value;
return true;
-
}
}
@@ -1775,9 +2229,16 @@ bool GDInstance::get(const StringName& p_name, Variant &r_ret) const {
while(sptr) {
{
- const Map<StringName,int>::Element *E = script->member_indices.find(p_name);
+ const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
if (E) {
- r_ret=members[E->get()];
+ if (E->get().getter) {
+ Variant::CallError err;
+ r_ret=const_cast<GDInstance*>(this)->call(E->get().getter,NULL,0,err);
+ if (err.error==Variant::CallError::CALL_OK) {
+ return true;
+ }
+ }
+ r_ret=members[E->get().index];
return true; //index found
}
@@ -1813,6 +2274,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!
@@ -1867,7 +2348,7 @@ void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const {
_GDScriptMemberSort ms;
ERR_CONTINUE(!sptr->member_indices.has(E->key()));
- ms.index=sptr->member_indices[E->key()];
+ ms.index=sptr->member_indices[E->key()].index;
ms.name=E->key();
msort.push_back(ms);
@@ -2103,9 +2584,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);
@@ -2169,8 +2650,8 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"func" ,
"if" ,
"in" ,
- "varl",
"null" ,
+ "not" ,
"return" ,
"self" ,
"while" ,
@@ -2178,11 +2659,17 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"false" ,
"tool",
"var",
+ "setget",
"pass",
"and",
"or",
"export",
"assert",
+ "yield",
+ "static",
+ "float",
+ "int",
+ "signal",
0};
@@ -2243,7 +2730,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 );
@@ -2275,6 +2765,8 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig
script->reload();
}
+ if (r_error)
+ *r_error=OK;
return scriptres;
}
@@ -2316,7 +2808,10 @@ Error ResourceFormatSaverGDScript::save(const String &p_path,const RES& p_resour
}
file->store_string(source);
-
+ if (file->get_error()!=OK && file->get_error()!=ERR_FILE_EOF) {
+ memdelete(file);
+ return ERR_CANT_CREATE;
+ }
file->close();
memdelete(file);
return OK;
diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h
index 3300ee77c8..3d16b59065 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -37,6 +37,8 @@
class GDInstance;
class GDScript;
+
+
class GDFunction {
public:
@@ -58,6 +60,9 @@ public:
OPCODE_CALL_BUILT_IN,
OPCODE_CALL_SELF,
OPCODE_CALL_SELF_BASE,
+ OPCODE_YIELD,
+ OPCODE_YIELD_SIGNAL,
+ OPCODE_YIELD_RESUME,
OPCODE_JUMP,
OPCODE_JUMP_IF,
OPCODE_JUMP_IF_NOT,
@@ -124,6 +129,10 @@ friend class GDCompiler;
const char*_func_cname;
#endif
+#ifdef TOOLS_ENABLED
+ Vector<StringName> arg_names;
+#endif
+
List<StackDebug> stack_debug;
_FORCE_INLINE_ Variant *_get_variant(int p_address,GDInstance *p_instance,GDScript *p_script,Variant &self,Variant *p_stack,String& r_error) const;
@@ -132,6 +141,20 @@ friend class GDCompiler;
public:
+ struct CallState {
+
+ GDInstance *instance;
+ Vector<uint8_t> stack;
+ int stack_size;
+ Variant self;
+ uint32_t alloca_size;
+ GDScript *_class;
+ int ip;
+ int line;
+ int defarg;
+ Variant result;
+
+ };
_FORCE_INLINE_ bool is_static() const { return _static; }
@@ -150,12 +173,43 @@ public:
_FORCE_INLINE_ bool is_empty() const { return _code_size==0; }
int get_argument_count() const { return _argument_count; }
- Variant call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err);
+ StringName get_argument_name(int p_idx) const {
+#ifdef TOOLS_ENABLED
+ ERR_FAIL_INDEX_V(p_idx,arg_names.size(),StringName());
+ return arg_names[p_idx];
+#endif
+ return StringName();
+
+ }
+ Variant get_default_argument(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx,default_arguments.size(),Variant());
+ return default_arguments[p_idx];
+ }
+
+ Variant call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err,CallState *p_state=NULL);
GDFunction();
};
+class GDFunctionState : public Reference {
+
+ OBJ_TYPE(GDFunctionState,Reference);
+friend class GDFunction;
+ GDFunction *function;
+ GDFunction::CallState state;
+ Variant _signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
+protected:
+ static void _bind_methods();
+public:
+
+ bool is_valid() const;
+ Variant resume(const Variant& p_arg=Variant());
+ GDFunctionState();
+ ~GDFunctionState();
+};
+
+
class GDNativeClass : public Reference {
OBJ_TYPE(GDNativeClass,Reference);
@@ -183,11 +237,18 @@ class GDScript : public Script {
bool valid;
+ struct MemberInfo {
+ int index;
+ StringName setter;
+ StringName getter;
+ };
friend class GDInstance;
friend class GDFunction;
friend class GDCompiler;
friend class GDFunctions;
+friend class GDScriptLanguage;
+
Variant _static_ref; //used for static call
Ref<GDNativeClass> native;
Ref<GDScript> base;
@@ -197,11 +258,21 @@ friend class GDFunctions;
Set<StringName> members; //members are just indices to the instanced script.
Map<StringName,Variant> constants;
Map<StringName,GDFunction> member_functions;
- Map<StringName,int> member_indices; //members are just indices to the instanced script.
+ Map<StringName,MemberInfo> member_indices; //members are just indices to the instanced script.
Map<StringName,Ref<GDScript> > subclasses;
+ Map<StringName,Vector<StringName> > _signals;
#ifdef TOOLS_ENABLED
+
Map<StringName,Variant> member_default_values;
+
+ List<PropertyInfo> members_cache;
+ Map<StringName,Variant> member_default_values_cache;
+ Ref<GDScript> base_cache;
+ Set<ObjectID> inheriters_cache;
+ bool source_changed_cache;
+ void _update_exports_values(Map<StringName,Variant>& values, List<PropertyInfo> &propnames);
+
#endif
Map<StringName,PropertyInfo> member_info;
@@ -215,17 +286,20 @@ friend class GDFunctions;
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);
#ifdef TOOLS_ENABLED
Set<PlaceHolderScriptInstance*> placeholders;
- void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
+ //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
#endif
+
+ bool _update_exports();
+
protected:
bool _get(const StringName& p_name,Variant &r_ret) const;
bool _set(const StringName& p_name, const Variant& p_value);
@@ -237,6 +311,7 @@ protected:
static void _bind_methods();
public:
+ bool is_valid() const { return valid; }
const Map<StringName,Ref<GDScript> >& get_subclasses() const { return subclasses; }
const Map<StringName,Variant >& get_constants() const { return constants; }
@@ -244,11 +319,14 @@ public:
const Map<StringName,GDFunction>& get_member_functions() const { return member_functions; }
const Ref<GDNativeClass>& get_native() const { return native; }
+ virtual bool has_script_signal(const StringName& p_signal) const;
+ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const;
+
bool is_tool() const { return tool; }
Ref<GDScript> get_base() const;
- const Map<StringName,int>& debug_get_member_indices() const { return member_indices; }
+ const Map<StringName,MemberInfo>& debug_get_member_indices() const { return member_indices; }
const Map<StringName,GDFunction>& debug_get_member_functions() const; //this is debug only
StringName debug_get_member_by_index(int p_idx) const;
@@ -262,6 +340,8 @@ public:
virtual bool has_source_code() const;
virtual String get_source_code() const;
virtual void set_source_code(const String& p_code);
+ virtual void update_exports();
+
virtual Error reload();
virtual String get_node_type() const;
@@ -269,6 +349,8 @@ 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;
+
virtual ScriptLanguage *get_language() const;
GDScript();
@@ -291,6 +373,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;
@@ -393,6 +477,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;
@@ -430,7 +527,7 @@ public:
virtual bool has_named_classes() const;
virtual int find_function(const String& p_function,const String& p_code) const;
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const;
- virtual Error complete_keyword(const String& p_code, int p_line, const String& p_base_path,const String& p_keyword, List<String>* r_options);
+ 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;
/* DEBUGGER FUNCTIONS */
@@ -462,7 +559,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 a92e2f22ea..e445701669 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -91,10 +91,13 @@ const char* GDTokenizer::token_names[TK_MAX]={
"tool",
"static",
"export",
+"setget",
"const",
"var",
"preload",
"assert",
+"yield",
+"signal",
"'['",
"']'",
"'{'",
@@ -108,7 +111,8 @@ const char* GDTokenizer::token_names[TK_MAX]={
"':'",
"'\\n'",
"Error",
-"EOF"};
+"EOF",
+"Cursor"};
const char *GDTokenizer::get_token_name(Token p_token) {
@@ -236,7 +240,8 @@ void GDTokenizerText::_advance() {
while (true) {
- bool is_node_path=false;
+ bool is_node_path = false;
+ StringMode string_mode=STRING_DOUBLE_QUOTE;
switch(GETCHAR(0)) {
case 0:
@@ -283,7 +288,8 @@ void GDTokenizerText::_advance() {
while(GETCHAR(0)!='\n') {
code_pos++;
if (GETCHAR(0)==0) { //end of file
- _make_error("Unterminated Comment");
+ //_make_error("Unterminated Comment");
+ _make_token(TK_EOF);
return;
}
}
@@ -525,24 +531,49 @@ void GDTokenizerText::_advance() {
}
} break;
case '@':
- if (CharType(GETCHAR(1))!='"') {
+ if( CharType(GETCHAR(1))!='"' && CharType(GETCHAR(1))!='\'' ) {
_make_error("Unexpected '@'");
return;
}
INCPOS(1);
is_node_path=true;
+
+ case '\'':
case '"': {
-
+
+ if (GETCHAR(0)=='\'')
+ string_mode=STRING_SINGLE_QUOTE;
+
+
int i=1;
+ if (string_mode==STRING_DOUBLE_QUOTE && GETCHAR(i)=='"' && GETCHAR(i+1)=='"') {
+ i+=2;
+ string_mode=STRING_MULTILINE;
+
+ }
+
+
String str;
while(true) {
- if (CharType(GETCHAR(i)==0)) {
+ if (CharType(GETCHAR(i))==0) {
_make_error("Unterminated String");
return;
- } else if (CharType(GETCHAR(i)=='"')) {
+ } else if( string_mode==STRING_DOUBLE_QUOTE && CharType(GETCHAR(i))=='"' ) {
break;
- } else if (CharType(GETCHAR(i)=='\\')) {
+ } else if( string_mode==STRING_SINGLE_QUOTE && CharType(GETCHAR(i))=='\'' ) {
+ break;
+ } else if( string_mode==STRING_MULTILINE && CharType(GETCHAR(i))=='\"' && CharType(GETCHAR(i+1))=='\"' && CharType(GETCHAR(i+2))=='\"') {
+ i+=2;
+ break;
+ } 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++;
CharType next = GETCHAR(i);
@@ -564,22 +595,21 @@ void GDTokenizerText::_advance() {
case '\'': res='\''; break;
case '\"': res='\"'; break;
case '\\': res='\\'; break;
- case 'x': {
- //hexnumbarh - oct is deprecated
+ case '/': res='/'; break; //wtf
- int read=0;
+ case 'u': {
+ //hexnumbarh - oct is deprecated
+ i+=1;
for(int j=0;j<4;j++) {
CharType c = GETCHAR(i+j);
if (c==0) {
_make_error("Unterminated String");
return;
}
- if (!_is_hex(c)) {
- if (j==0 || !(j&1)) {
- _make_error("Malformed hex constant in string");
- return;
- } else
- break;
+ if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {
+
+ _make_error("Malformed hex constant in string");
+ return;
}
CharType v;
if (c>='0' && c<='9') {
@@ -598,10 +628,9 @@ void GDTokenizerText::_advance() {
res<<=4;
res|=v;
- read++;
- }
- i+=read-1;
+ }
+ i+=3;
} break;
default: {
@@ -614,6 +643,11 @@ void GDTokenizerText::_advance() {
str+=res;
} else {
+ if (CharType(GETCHAR(i))=='\n') {
+ line++;
+ column=0;
+ }
+
str+=CharType(GETCHAR(i));
}
i++;
@@ -627,6 +661,9 @@ void GDTokenizerText::_advance() {
}
} break;
+ case 0xFFFF: {
+ _make_token(TK_CURSOR);
+ } break;
default: {
if (_is_number(GETCHAR(0)) || (GETCHAR(0)=='.' && _is_number(GETCHAR(1)))) {
@@ -642,19 +679,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;
@@ -664,7 +701,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;
@@ -675,20 +712,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);
@@ -737,20 +774,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"},
@@ -758,7 +790,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"},
@@ -797,7 +828,7 @@ void GDTokenizerText::_advance() {
_make_built_in_func(GDFunctions::Function(i));
found=true;
- break;
+ break;
}
}
@@ -823,9 +854,12 @@ void GDTokenizerText::_advance() {
{TK_PR_TOOL,"tool"},
{TK_PR_STATIC,"static"},
{TK_PR_EXPORT,"export"},
+ {TK_PR_SETGET,"setget"},
{TK_PR_VAR,"var"},
{TK_PR_PRELOAD,"preload"},
{TK_PR_ASSERT,"assert"},
+ {TK_PR_YIELD,"yield"},
+ {TK_PR_SIGNAL,"signal"},
{TK_PR_CONST,"const"},
//controlflow
{TK_CF_IF,"if"},
@@ -1006,7 +1040,7 @@ void GDTokenizerText::advance(int p_amount) {
//////////////////////////////////////////////////////////////////////////////////////////////////////
-#define BYTECODE_VERSION 1
+#define BYTECODE_VERSION 5
Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
@@ -1016,8 +1050,8 @@ Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
ERR_FAIL_COND_V( p_buffer.size()<24 || p_buffer[0]!='G' || p_buffer[1]!='D' || p_buffer[2]!='S' || p_buffer[3]!='C',ERR_INVALID_DATA);
int version = decode_uint32(&buf[4]);
- if (version>1) {
- ERR_EXPLAIN("Bytecode is too New!");
+ if (version>BYTECODE_VERSION) {
+ ERR_EXPLAIN("Bytecode is too New! Please use a newer engine version.");
ERR_FAIL_COND_V(version>BYTECODE_VERSION,ERR_INVALID_DATA);
}
int identifier_count = decode_uint32(&buf[8]);
diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h
index c517e07b89..d6bd63c5b8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -98,10 +98,13 @@ public:
TK_PR_TOOL,
TK_PR_STATIC,
TK_PR_EXPORT,
+ TK_PR_SETGET,
TK_PR_CONST,
TK_PR_VAR,
TK_PR_PRELOAD,
TK_PR_ASSERT,
+ TK_PR_YIELD,
+ TK_PR_SIGNAL,
TK_BRACKET_OPEN,
TK_BRACKET_CLOSE,
TK_CURLY_BRACKET_OPEN,
@@ -116,10 +119,18 @@ public:
TK_NEWLINE,
TK_ERROR,
TK_EOF,
+ TK_CURSOR, //used for code completion
TK_MAX
};
protected:
+
+ enum StringMode {
+ STRING_SINGLE_QUOTE,
+ STRING_DOUBLE_QUOTE,
+ STRING_MULTILINE
+ };
+
static const char* token_names[TK_MAX];
public:
static const char *get_token_name(Token p_token);
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index abb3d5a946..4470b7ca0c 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -121,11 +121,12 @@ static void register_editor_plugin() {
void register_gdscript_types() {
+ ObjectTypeDB::register_type<GDScript>();
+ ObjectTypeDB::register_virtual_type<GDFunctionState>();
script_language_gd=memnew( GDScriptLanguage );
- script_language_gd->init();
+ //script_language_gd->init();
ScriptServer::register_language(script_language_gd);
- ObjectTypeDB::register_type<GDScript>();
resource_loader_gd=memnew( ResourceFormatLoaderGDScript );
ResourceLoader::add_resource_format_loader(resource_loader_gd);
resource_saver_gd=memnew( ResourceFormatSaverGDScript );
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index ff7c2734df..9eb5d1846b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 d258e26a0e..ad7c392cd0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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) {
@@ -122,7 +122,7 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
Octant &g = *octant_map[ok];
g.baked=b;
- g.bake_instance=VS::get_singleton()->instance_create();;
+ g.bake_instance=VS::get_singleton()->instance_create();;
VS::get_singleton()->instance_set_base(g.bake_instance,g.baked->get_rid());
VS::get_singleton()->instance_geometry_set_baked_light(g.bake_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID());
}
@@ -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 {
@@ -418,9 +422,24 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){
Octant *g = memnew( Octant );
g->dirty=true;
g->static_body = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC);
+ PhysicsServer::get_singleton()->body_attach_object_instance_ID(g->static_body,get_instance_ID());
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;
}
@@ -511,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();
@@ -544,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();
@@ -571,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();
@@ -608,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);
@@ -623,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++;
@@ -635,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;
}
@@ -655,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());
@@ -677,7 +738,7 @@ void GridMap::_octant_clear_baked(const OctantKey &p_key) {
g.bake_instance=RID();
g.baked=Ref<Mesh>();
- if (is_inside_scene())
+ if (is_inside_tree())
_octant_enter_world(p_key);
g.dirty=true;
_queue_dirty_map();
@@ -958,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());
@@ -1041,7 +1107,7 @@ void GridMap::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_clip","enabled","clipabove","floor","axis"),&GridMap::set_clip,DEFVAL(true),DEFVAL(0),DEFVAL(Vector3::AXIS_X));
- ObjectTypeDB::bind_method(_MD("crate_area","id","area"),&GridMap::create_area);
+ ObjectTypeDB::bind_method(_MD("create_area","id","area"),&GridMap::create_area);
ObjectTypeDB::bind_method(_MD("area_get_bounds","area","bounds"),&GridMap::area_get_bounds);
ObjectTypeDB::bind_method(_MD("area_set_exterior_portal","area","enable"),&GridMap::area_set_exterior_portal);
ObjectTypeDB::bind_method(_MD("area_set_name","area","name"),&GridMap::area_set_name);
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index df805d99fa..9d3b1dcf95 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 09e279305c..e4559ca100 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -61,7 +61,7 @@ void GridMapEditor::_menu_option(int p_option) {
case MENU_OPTION_CONFIGURE: {
-
+
} break;
case MENU_OPTION_LOCK_VIEW: {
@@ -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;
@@ -522,7 +524,9 @@ void GridMapEditor::_duplicate_paste() {
}
bool GridMapEditor::forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) {
-
+ if (!node) {
+ return false;
+ }
if (edit_mode->get_selected()==0) { // regular click
switch (p_event.type) {
@@ -706,9 +710,40 @@ struct _CGMEItemSort {
};
+void GridMapEditor::_set_display_mode(int p_mode) {
+ if (display_mode==p_mode) {
+ return;
+ }
+
+ if (p_mode == DISPLAY_LIST) {
+ mode_list->set_pressed(true);
+ mode_thumbnail->set_pressed(false);
+ } else if (p_mode == DISPLAY_THUMBNAIL) {
+ mode_list->set_pressed(false);
+ mode_thumbnail->set_pressed(true);
+ }
+
+ display_mode=p_mode;
+
+ update_pallete();
+}
+
void GridMapEditor::update_pallete() {
+ int selected = theme_pallete->get_current();
theme_pallete->clear();
+ if (display_mode == DISPLAY_THUMBNAIL) {
+ theme_pallete->set_max_columns(0);
+ theme_pallete->set_icon_mode(ItemList::ICON_MODE_TOP);
+ } else if (display_mode == DISPLAY_LIST){
+ theme_pallete->set_max_columns(1);
+ theme_pallete->set_icon_mode(ItemList::ICON_MODE_LEFT);
+ }
+
+ float min_size = EDITOR_DEF("grid_map/preview_size",64);
+ theme_pallete->set_min_icon_size(Size2(min_size, min_size));
+ theme_pallete->set_fixed_column_width(min_size*3/2);
+ theme_pallete->set_max_text_lines(2);
Ref<MeshLibrary> theme = node->get_theme();
@@ -720,10 +755,6 @@ void GridMapEditor::update_pallete() {
Vector<int> ids;
ids = theme->get_item_list();
- TreeItem *root = theme_pallete->create_item(NULL);
- theme_pallete->set_hide_root(true);
- TreeItem *selected=NULL;
-
List<_CGMEItemSort> il;
for(int i=0;i<ids.size();i++) {
@@ -734,45 +765,31 @@ void GridMapEditor::update_pallete() {
}
il.sort();
- int col=0;
- TreeItem *ti=NULL;
- int selected_col=0;
+ int item = 0;
for(List<_CGMEItemSort>::Element *E=il.front();E;E=E->next()) {
-
int id = E->get().id;
- if (col==0) {
- ti = theme_pallete->create_item(root);
- }
+ theme_pallete->add_item("");
String name=theme->get_item_name(id);
Ref<Texture> preview = theme->get_item_preview(id);
if (!preview.is_null()) {
-
- ti->set_cell_mode(col,TreeItem::CELL_MODE_ICON);
- ti->set_icon(col,preview);
- ti->set_tooltip(col,name);
- } else {
-
- ti->set_text(col,name);
+ theme_pallete->set_item_icon(item, preview);
+ theme_pallete->set_item_tooltip(item, name);
}
- ti->set_metadata(col,id);
-
- if (selected_pallete==id) {
- selected=ti;
- selected_col=col;
+ if (name!="") {
+ theme_pallete->set_item_text(item,name);
}
+ theme_pallete->set_item_metadata(item, id);
- col++;
- if (col==theme_pallete->get_columns())
- col=0;
-
+ item++;
}
- if (selected)
- selected->select(selected_col);
+ if (selected!=-1) {
+ theme_pallete->select(selected);
+ }
last_theme=theme.operator->();
}
@@ -842,6 +859,9 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,false);
}
+
+ VisualServer::get_singleton()->instance_geometry_set_flag(cursor_instance, VS::INSTANCE_FLAG_VISIBLE,false);
+
_clear_areas();
return;
@@ -868,7 +888,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
{
//update grids
- RID indicator_mat = VisualServer::get_singleton()->fixed_material_create();
+ indicator_mat = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_UNSHADED, true );
VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_ONTOP, false );
@@ -922,7 +942,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
d[VS::ARRAY_VERTEX]=grid_points[i];
d[VS::ARRAY_COLOR]=grid_colors[i];
VisualServer::get_singleton()->mesh_add_surface(grid[i],VisualServer::PRIMITIVE_LINES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat);
}
@@ -951,7 +971,7 @@ void GridMapEditor::update_grid() {
grid_xform.origin.x-=1; //force update in hackish way.. what do i care
- VS *vs = VS::get_singleton();
+ //VS *vs = VS::get_singleton();
grid_ofs[edit_axis]=edit_floor[edit_axis]*node->get_cell_size();
@@ -974,25 +994,25 @@ void GridMapEditor::update_grid() {
void GridMapEditor::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
- theme_pallete->connect("cell_selected", this,"_item_selected_cbk");
+ theme_pallete->connect("item_selected", this,"_item_selected_cbk");
edit_mode->connect("item_selected", this,"_edit_mode_changed");
area_list->connect("item_edited", this,"_area_renamed");
area_list->connect("item_selected", this,"_area_selected");
for(int i=0;i<3;i++) {
grid[i]=VS::get_singleton()->mesh_create();
- grid_instance[i]=VS::get_singleton()->instance_create2(grid[i],get_scene()->get_root()->get_world()->get_scenario());
+ grid_instance[i]=VS::get_singleton()->instance_create2(grid[i],get_tree()->get_root()->get_world()->get_scenario());
}
- selection_instance = VisualServer::get_singleton()->instance_create2(selection_mesh,get_scene()->get_root()->get_world()->get_scenario());
- duplicate_instance = VisualServer::get_singleton()->instance_create2(duplicate_mesh,get_scene()->get_root()->get_world()->get_scenario());
+ selection_instance = VisualServer::get_singleton()->instance_create2(selection_mesh,get_tree()->get_root()->get_world()->get_scenario());
+ duplicate_instance = VisualServer::get_singleton()->instance_create2(duplicate_mesh,get_tree()->get_root()->get_world()->get_scenario());
_update_selection_transform();
_update_duplicate_indicator();
- } else if (p_what==NOTIFICATION_EXIT_SCENE) {
+ } else if (p_what==NOTIFICATION_EXIT_TREE) {
for(int i=0;i<3;i++) {
@@ -1014,7 +1034,7 @@ void GridMapEditor::_notification(int p_what) {
if (xf!=grid_xform) {
for(int i=0;i<3;i++) {
-
+
VS::get_singleton()->instance_set_transform(grid_instance[i],xf * edit_grid_xform);
}
grid_xform=xf;
@@ -1025,7 +1045,7 @@ void GridMapEditor::_notification(int p_what) {
if (lock_view) {
- EditorNode*editor = get_scene()->get_root()->get_child(0)->cast_to<EditorNode>();
+ EditorNode*editor = get_tree()->get_root()->get_child(0)->cast_to<EditorNode>();
Plane p;
p.normal[edit_axis]=1.0;
@@ -1043,7 +1063,9 @@ void GridMapEditor::_notification(int p_what) {
}
void GridMapEditor::_update_cursor_instance() {
-
+ if (!node) {
+ return;
+ }
if (cursor_instance.is_valid())
VisualServer::get_singleton()->free(cursor_instance);
@@ -1055,7 +1077,7 @@ void GridMapEditor::_update_cursor_instance() {
Ref<Mesh> mesh = node->get_theme()->get_item_mesh(selected_pallete);
if (!mesh.is_null() && mesh->get_rid().is_valid()) {
- cursor_instance=VisualServer::get_singleton()->instance_create2(mesh->get_rid(),get_scene()->get_root()->get_world()->get_scenario());
+ cursor_instance=VisualServer::get_singleton()->instance_create2(mesh->get_rid(),get_tree()->get_root()->get_world()->get_scenario());
VisualServer::get_singleton()->instance_set_transform(cursor_instance,cursor_transform);
}
}
@@ -1063,18 +1085,8 @@ void GridMapEditor::_update_cursor_instance() {
}
-void GridMapEditor::_item_selected_cbk() {
-
- TreeItem *it = theme_pallete->get_selected();
- if (it) {
-
- selected_pallete=it->get_metadata(theme_pallete->get_selected_column());
-
- } else {
-
- selected_pallete=-1;
-
- }
+void GridMapEditor::_item_selected_cbk(int idx) {
+ selected_pallete=theme_pallete->get_item_metadata(idx);
_update_cursor_instance();
@@ -1092,7 +1104,9 @@ void GridMapEditor::_clear_areas() {
}
void GridMapEditor::_update_areas_display() {
-
+ if (!node) {
+ return;
+ }
_clear_areas();
List<int> areas;
@@ -1179,7 +1193,7 @@ void GridMapEditor::_bind_methods() {
ObjectTypeDB::bind_method("_area_selected",&GridMapEditor::_area_selected);
ObjectTypeDB::bind_method("_floor_changed",&GridMapEditor::_floor_changed);
-
+ ObjectTypeDB::bind_method(_MD("_set_display_mode","mode"), &GridMapEditor::_set_display_mode);
}
@@ -1192,8 +1206,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
undo_redo=p_editor->get_undo_redo();
int mw = EDITOR_DEF("grid_map/palette_min_width",230);
- EmptyControl *ec = memnew( EmptyControl);
- ec->set_minsize(Size2(mw,0));
+ Control *ec = memnew( Control);
+ ec->set_custom_minimum_size(Size2(mw,0));
add_child(ec);
@@ -1222,9 +1236,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
options->get_popup()->add_item("Cursor Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_A);
options->get_popup()->add_item("Cursor Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_S);
options->get_popup()->add_item("Cursor Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_D);
- options->get_popup()->add_item("Cursor Back Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_ALT+KEY_A);
- options->get_popup()->add_item("Cursor Back Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_ALT+KEY_S);
- options->get_popup()->add_item("Cursor Back Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_ALT+KEY_D);
+ options->get_popup()->add_item("Cursor Back Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_MASK_SHIFT+KEY_A);
+ options->get_popup()->add_item("Cursor Back Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_MASK_SHIFT+KEY_S);
+ options->get_popup()->add_item("Cursor Back Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_MASK_SHIFT+KEY_D);
options->get_popup()->add_item("Cursor Clear Rotation",MENU_OPTION_CURSOR_CLEAR_ROTATION,KEY_W);
options->get_popup()->add_separator();
options->get_popup()->add_check_item("Duplicate Selects",MENU_OPTION_DUPLICATE_SELECTS);
@@ -1237,9 +1251,30 @@ 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");
+ HBoxContainer *hb = memnew( HBoxContainer );
+ add_child(hb);
+ hb->set_h_size_flags(SIZE_EXPAND_FILL);
edit_mode = memnew(OptionButton);
edit_mode->set_area_as_parent_rect();
@@ -1247,13 +1282,27 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
edit_mode->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,14);;
edit_mode->add_item("Tiles");
edit_mode->add_item("Areas");
- add_child(edit_mode);
-
+ hb->add_child(edit_mode);
+ edit_mode->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ mode_thumbnail = memnew( ToolButton );
+ mode_thumbnail->set_toggle_mode(true);
+ mode_thumbnail->set_pressed(true);
+ mode_thumbnail->set_icon(p_editor->get_gui_base()->get_icon("FileThumbnail","EditorIcons"));
+ hb->add_child(mode_thumbnail);
+ mode_thumbnail->connect("pressed", this, "_set_display_mode", varray(DISPLAY_THUMBNAIL));
+
+ mode_list = memnew( ToolButton );
+ mode_list->set_toggle_mode(true);
+ mode_list->set_pressed(false);
+ mode_list->set_icon(p_editor->get_gui_base()->get_icon("FileList", "EditorIcons"));
+ hb->add_child(mode_list);
+ mode_list->connect("pressed", this, "_set_display_mode", varray(DISPLAY_LIST));
+
+ display_mode = DISPLAY_THUMBNAIL;
selected_area=-1;
-
- theme_pallete = memnew( Tree );
- theme_pallete->set_columns(3);
+ theme_pallete = memnew( ItemList );
add_child(theme_pallete);
theme_pallete->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -1340,7 +1389,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
Array d;
d.resize(VS::ARRAY_MAX);
- RID inner_mat = VisualServer::get_singleton()->fixed_material_create();
+ inner_mat = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->fixed_material_set_param(inner_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.3));
VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_ONTOP,true);
VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_UNSHADED,true);
@@ -1349,9 +1398,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
d[VS::ARRAY_VERTEX]=triangles;
VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_TRIANGLES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat);
- RID outer_mat = VisualServer::get_singleton()->fixed_material_create();
+ outer_mat = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->fixed_material_set_param(outer_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.8));
VisualServer::get_singleton()->material_set_line_width(outer_mat,3.0);
VisualServer::get_singleton()->material_set_flag(outer_mat,VS::MATERIAL_FLAG_ONTOP,true);
@@ -1361,10 +1410,10 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
d[VS::ARRAY_VERTEX]=lines;
VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_LINES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat);
- RID inner_mat_dup = VisualServer::get_singleton()->fixed_material_create();
+ inner_mat_dup = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->fixed_material_set_param(inner_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.3));
VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_ONTOP,true);
VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_UNSHADED,true);
@@ -1373,9 +1422,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
d[VS::ARRAY_VERTEX]=triangles;
VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_TRIANGLES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup);
- RID outer_mat_dup = VisualServer::get_singleton()->fixed_material_create();
+ outer_mat_dup = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->fixed_material_set_param(outer_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.8));
VisualServer::get_singleton()->material_set_line_width(outer_mat_dup,3.0);
VisualServer::get_singleton()->material_set_flag(outer_mat_dup,VS::MATERIAL_FLAG_ONTOP,true);
@@ -1385,7 +1434,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
d[VS::ARRAY_VERTEX]=lines;
VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_LINES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup);
}
@@ -1409,6 +1458,11 @@ GridMapEditor::~GridMapEditor() {
VisualServer::get_singleton()->free(cursor_instance);
}
+ VisualServer::get_singleton()->free(inner_mat);
+ VisualServer::get_singleton()->free(outer_mat);
+ VisualServer::get_singleton()->free(inner_mat_dup);
+ VisualServer::get_singleton()->free(outer_mat_dup);
+
VisualServer::get_singleton()->free(selection_mesh);
if (selection_instance.is_valid())
VisualServer::get_singleton()->free(selection_instance);
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 1240d78426..03b2d4226e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,10 +40,8 @@
class SpatialEditorPlugin;
class GridMapEditor : public VBoxContainer {
-
OBJ_TYPE(GridMapEditor, VBoxContainer );
-
enum {
GRID_CURSOR_SIZE=50
@@ -66,6 +64,10 @@ class GridMapEditor : public VBoxContainer {
CLIP_BELOW
};
+ enum DisplayMode {
+ DISPLAY_THUMBNAIL,
+ DISPLAY_LIST
+ };
UndoRedo *undo_redo;
InputAction input_action;
@@ -73,7 +75,12 @@ class GridMapEditor : public VBoxContainer {
MenuButton * options;
SpinBox *floor;
OptionButton *edit_mode;
+ ToolButton *mode_thumbnail;
+ ToolButton *mode_list;
HBoxContainer *spatial_editor_hb;
+ ConfirmationDialog *settings_dialog;
+ VBoxContainer *settings_vbc;
+ SpinBox *settings_pick_distance;
struct SetItem {
@@ -105,6 +112,13 @@ class GridMapEditor : public VBoxContainer {
RID duplicate_mesh;
RID duplicate_instance;
+ RID indicator_mat;
+
+ RID inner_mat;
+ RID outer_mat;
+ RID inner_mat_dup;
+ RID outer_mat_dup;
+
bool updating;
@@ -125,6 +139,7 @@ class GridMapEditor : public VBoxContainer {
Vector3 cursor_origin;
Vector3 last_mouseover;
+ int display_mode;
int selected_pallete;
int selected_area;
int cursor_rot;
@@ -153,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
};
@@ -176,9 +191,10 @@ class GridMapEditor : public VBoxContainer {
void _configure();
void _menu_option(int);
void update_pallete();
- Tree *theme_pallete;
+ void _set_display_mode(int p_mode);
+ ItemList *theme_pallete;
Tree *area_list;
- void _item_selected_cbk();
+ void _item_selected_cbk(int idx);
void _update_cursor_transform();
void _update_cursor_instance();
void _update_clip();
diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp
index 3c3c8aa98f..2bc440759d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,16 +27,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_types.h"
+#ifndef _3D_DISABLED
#include "object_type_db.h"
#include "grid_map.h"
#include "grid_map_editor_plugin.h"
+#endif
void register_gridmap_types() {
+#ifndef _3D_DISABLED
ObjectTypeDB::register_type<GridMap>();
#ifdef TOOLS_ENABLED
EditorPlugins::add_by_type<GridMapEditorPlugin>();
#endif
+#endif
}
diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h
index 5cddb96b70..326d7acf24 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template
index e723b693d8..c95c86c060 100644
--- a/platform/android/AndroidManifest.xml.template
+++ b/platform/android/AndroidManifest.xml.template
@@ -7,10 +7,10 @@
>
<supports-screens android:smallScreens="true"
android:normalScreens="true"
- android:largeScreens="true"
+ android:largeScreens="false"
android:xlargeScreens="true"/>
- <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon">
+ <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"
android:label="@string/godot_project_name_string"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@@ -23,6 +23,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <service android:name="com.android.godot.GodotDownloaderService" />
@@ -32,6 +33,7 @@ $$ADD_APPLICATION_CHUNKS$$
</application>
<uses-feature android:glEsVersion="0x00020000"/>
+$$ADD_PERMISSION_CHUNKS$$
<uses-permission android:name="godot.ACCESS_CHECKIN_PROPERTIES"/>
<uses-permission android:name="godot.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="godot.ACCESS_FINE_LOCATION"/>
@@ -198,6 +200,6 @@ $$ADD_APPLICATION_CHUNKS$$
<uses-permission android:name="godot.custom.18"/>
<uses-permission android:name="godot.custom.19"/>
-<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="15"/>
+<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19"/>
</manifest>
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 8e61b7d8e0..834ee58adc 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -15,7 +15,9 @@ android_files = [
'audio_driver_jandroid.cpp',
'ifaddrs_android.cpp',
'android_native_app_glue.c',
- 'java_glue.cpp'
+ 'java_glue.cpp',
+ 'cpu-features.c',
+ 'java_class_wrapper.cpp'
]
#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
@@ -54,16 +56,18 @@ pp_basein = open(abspath+"/AndroidManifest.xml.template","rb")
pp_baseout = open(abspath+"/java/AndroidManifest.xml","wb")
manifest = pp_basein.read()
manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$",env.android_manifest_chunk)
+manifest = manifest.replace("$$ADD_PERMISSION_CHUNKS$$",env.android_permission_chunk)
+manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$",env.android_appattributes_chunk)
pp_baseout.write( manifest )
for x in env.android_source_files:
- shutil.copy(x,abspath+"/java/src/com/android/godot")
+ shutil.copy(x,abspath+"/java/src/com/android/godot")
for x in env.android_module_libraries:
- shutil.copy(x,abspath+"/java/libs")
+ shutil.copy(x,abspath+"/java/libs")
-env_android.SharedLibrary("#platform/android/libgodot_android.so",[android_objects])
+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'))
+#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 fe8684b5d2..f5ba27ae66 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,7 +26,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
- * Copyright (C) 2010 The Android Open Source Project
+/* 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.
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
index 6e3f6f9505..1a3a1cb563 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h
index f102acf154..bf8584051d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index 857d1a4a54..761bef27aa 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -396,6 +395,14 @@ void AudioDriverOpenSL::finish(){
void AudioDriverOpenSL::set_pause(bool p_pause) {
pause=p_pause;
+
+ if (active) {
+ if (pause) {
+ (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED);
+ } else {
+ (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
+ }
+ }
}
diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h
index d852928ab8..e9d7c7a7ea 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/android/cpu-features.c b/platform/android/cpu-features.c
new file mode 100644
index 0000000000..9cdadd5407
--- /dev/null
+++ b/platform/android/cpu-features.c
@@ -0,0 +1,1089 @@
+/*
+ * 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 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, 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_getCpuFeatures(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__)
diff --git a/platform/android/cpu-features.h b/platform/android/cpu-features.h
new file mode 100644
index 0000000000..01b7fe207c
--- /dev/null
+++ b/platform/android/cpu-features.h
@@ -0,0 +1,214 @@
+/*
+ * 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_ARM64,
+ ANDROID_CPU_FAMILY_X86_64,
+ ANDROID_CPU_FAMILY_MIPS64,
+
+ 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),
+};
+
+extern uint64_t android_getCpuFeatures(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/platform/android/detect.py b/platform/android/detect.py
index c9b21626c3..66097a5149 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -20,21 +20,19 @@ 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','compile for 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():
return [
- ('lua', 'no'),
('tools', 'no'),
('nedmalloc', 'no'),
('builtin_zlib', 'no'),
@@ -53,33 +51,83 @@ 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/apk_expansion")
env.android_source_modules.append("../libs/google_play_services")
- ndk_platform=""
-
- ndk_platform="android-15"
+ env.android_source_modules.append("../libs/downloader_library")
+ env.android_source_modules.append("../libs/play_licensing")
- 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['OBJSUFFIX'] = ".android.ox"
- env['LIBSUFFIX'] = ".android.ax"
- else:
- env['OBJSUFFIX'] = ".android.o"
- env['LIBSUFFIX'] = ".android.a"
- env['PROGSUFFIX'] = ".android"
- env['SHLIBSUFFIX'] = ".so"
-
+ 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
@@ -92,12 +140,12 @@ def configure(env):
gcc_path=gcc_path+"/darwin-x86_64/bin" #this may be wrong
env['SHLINKFLAGS'][1] = '-shared'
elif (os.name=="nt"):
- gcc_path=gcc_path+"/windows/bin" #this may be wrong
+ gcc_path=gcc_path+"/windows-x86_64/bin" #this may be wrong
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"
@@ -110,7 +158,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,19 +171,24 @@ def configure(env):
ld_path=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/"+env['ARCH']+"/usr/lib"
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 ')
- print("********* armv6", env['armv6'])
- if env['x86']=='yes':
- env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__GLIBC__ -Wno-psabi -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
- elif env["armv6"]!="no":
- env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -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 -DGLES1_ENABLED')
- else:
- env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -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 -DGLES1_ENABLED')
+
+ 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["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')
+ 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 ")
@@ -144,38 +197,37 @@ def configure(env):
if (env["target"]=="release"):
env.Append(CCFLAGS=['-O2', '-ffast-math','-fomit-frame-pointer'])
- env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
elif (env["target"]=="release_debug"):
env.Append(CCFLAGS=['-O2', '-ffast-math','-DDEBUG_ENABLED'])
- env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
-
- elif (env["target"]=="profile"):
-
- env.Append(CCFLAGS=['-O2', '-ffast-math','-fomit-frame-pointer', '-g1'])
- env.Append(LIBPATH=['#platform/android/armeabi'])
- env.Append(LIBS=['andprof'])
- env['OBJSUFFIX'] = "_prof"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_prof"+env['LIBSUFFIX']
- env['SHLIBSUFFIX'] = "_prof"+env['SHLIBSUFFIX']
elif (env["target"]=="debug"):
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"])
@@ -186,10 +238,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 60bde61fc4..ca1e58da3f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -79,6 +79,9 @@ bool DirAccessAndroid::current_is_dir() const{
return false;
}
+bool DirAccessAndroid::current_is_hidden() const{
+ return current!="." && current!=".." && current.begins_with(".");
+}
void DirAccessAndroid::list_dir_end(){
if (aad==NULL)
diff --git a/platform/android/dir_access_android.h b/platform/android/dir_access_android.h
index a6aead6eb3..cbbcdb71bb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -52,6 +52,7 @@ 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();
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index f32e16e7d8..2b5fc6a50a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,11 +31,15 @@
#include "dir_access_jandroid.h"
#include "file_access_jandroid.h"
#include "thread_jandroid.h"
+#include "print_string.h"
+
+
jobject DirAccessJAndroid::io=NULL;
jclass DirAccessJAndroid::cls=NULL;
jmethodID DirAccessJAndroid::_dir_open=NULL;
jmethodID DirAccessJAndroid::_dir_next=NULL;
jmethodID DirAccessJAndroid::_dir_close=NULL;
+jmethodID DirAccessJAndroid::_dir_is_dir=NULL;
DirAccess *DirAccessJAndroid::create_fs() {
@@ -67,44 +71,25 @@ String DirAccessJAndroid::get_next(){
if (!str)
return "";
- int sl = env->GetStringLength(str);
- if (sl==0) {
- env->DeleteLocalRef((jobject)str);
- return "";
- }
-
- CharString cs;
- cs.resize(sl+1);
- env->GetStringRegion(str,0,sl,(jchar*)&cs[0]);
- cs[sl]=0;
-
- String ret;
- ret.parse_utf8(&cs[0]);
+ String ret = String::utf8(env->GetStringUTFChars( (jstring)str, NULL ));
env->DeleteLocalRef((jobject)str);
-
return ret;
}
bool DirAccessJAndroid::current_is_dir() const{
- JNIEnv *env = ThreadAndroid::get_env();
- String sd;
- if (current_dir=="")
- sd=current;
- else
- sd=current_dir+"/"+current;
- jstring js = env->NewStringUTF(sd.utf8().get_data());
+ JNIEnv *env = ThreadAndroid::get_env();
- int res = env->CallIntMethod(io,_dir_open,js);
- if (res<=0)
- return false;
+ return env->CallBooleanMethod(io,_dir_is_dir,id);
- env->CallObjectMethod(io,_dir_close,res);
+}
+bool DirAccessJAndroid::current_is_hidden() const {
- return true;
+ return current!="." && current!=".." && current.begins_with(".");
}
+
void DirAccessJAndroid::list_dir_end(){
if (id==0)
@@ -136,24 +121,31 @@ Error DirAccessJAndroid::change_dir(String p_dir){
String new_dir;
+ if (p_dir!="res://" && p_dir.length()>1 && p_dir.ends_with("/"))
+ p_dir=p_dir.substr(0,p_dir.length()-1);
+
if (p_dir.begins_with("/"))
new_dir=p_dir.substr(1,p_dir.length());
else if (p_dir.begins_with("res://"))
new_dir=p_dir.substr(6,p_dir.length());
- else //relative
- new_dir=new_dir+"/"+p_dir;
+ else if (current_dir=="")
+ new_dir=p_dir;
+ else
+ new_dir=current_dir.plus_file(p_dir);
+ //print_line("new dir is: "+new_dir);
//test if newdir exists
new_dir=new_dir.simplify_path();
jstring js = env->NewStringUTF(new_dir.utf8().get_data());
int res = env->CallIntMethod(io,_dir_open,js);
+ env->DeleteLocalRef(js);
if (res<=0)
return ERR_INVALID_PARAMETER;
env->CallObjectMethod(io,_dir_close,res);
-
+ current_dir=new_dir;
return OK;
}
@@ -170,7 +162,7 @@ bool DirAccessJAndroid::file_exists(String p_file){
if (current_dir=="")
sd=p_file;
else
- sd=current_dir+"/"+p_file;
+ sd=current_dir.plus_file(p_file);
FileAccessJAndroid *f = memnew(FileAccessJAndroid);
bool exists = f->file_exists(sd);
@@ -184,12 +176,19 @@ bool DirAccessJAndroid::dir_exists(String p_dir) {
JNIEnv *env = ThreadAndroid::get_env();
String sd;
+
+
if (current_dir=="")
sd=p_dir;
- else
- sd=current_dir+"/"+p_dir;
+ else {
+ if (p_dir.is_rel_path())
+ sd=current_dir.plus_file(p_dir);
+ else
+ sd=fix_path(p_dir);
+ }
+
+ String path=sd.simplify_path();
- String path=fix_path(sd).simplify_path();
if (path.begins_with("/"))
path=path.substr(1,path.length());
else if (path.begins_with("res://"))
@@ -197,6 +196,7 @@ bool DirAccessJAndroid::dir_exists(String p_dir) {
jstring js = env->NewStringUTF(path.utf8().get_data());
int res = env->CallIntMethod(io,_dir_open,js);
+ env->DeleteLocalRef(js);
if (res<=0)
return false;
@@ -250,6 +250,10 @@ void DirAccessJAndroid::setup( jobject p_io) {
if(_dir_close != 0) {
__android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_close ok!!");
}
+ _dir_is_dir = env->GetMethodID(cls, "dir_is_dir", "(I)Z");
+ if(_dir_is_dir != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_is_dir ok!!");
+ }
// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
}
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index 958ea34891..7b6242ca32 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,6 +47,7 @@ class DirAccessJAndroid : public DirAccess {
static jmethodID _dir_open;
static jmethodID _dir_next;
static jmethodID _dir_close;
+ static jmethodID _dir_is_dir;
int id;
@@ -60,6 +61,7 @@ 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();
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index f47ff4ed50..7d550f4fa0 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -184,6 +184,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String cmdline;
bool _signed;
bool apk_expansion;
+ bool remove_prev;
+ bool use_32_fb;
+ bool immersive;
+ bool export_arm;
+ bool export_x86;
String apk_expansion_salt;
String apk_expansion_pkey;
int orientation;
@@ -220,8 +225,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
static void _device_poll_thread(void *ud);
+ 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);
@@ -242,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;
@@ -258,7 +265,9 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
String n=p_name;
- if (n=="custom_package/debug")
+ if (n=="one_click_deploy/clear_previous_install")
+ remove_prev=p_value;
+ else if (n=="custom_package/debug")
custom_debug_package=p_value;
else if (n=="custom_package/release")
custom_release_package=p_value;
@@ -276,6 +285,14 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
icon=p_value;
else if (n=="package/signed")
_signed=p_value;
+ else if (n=="architecture/arm")
+ export_arm=p_value;
+ else if (n=="architecture/x86")
+ export_x86=p_value;
+ else if (n=="screen/use_32_bits_view")
+ use_32_fb=p_value;
+ else if (n=="screen/immersive_mode")
+ immersive=p_value;
else if (n=="screen/orientation")
orientation=p_value;
else if (n=="screen/support_small")
@@ -300,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);
@@ -308,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;
@@ -321,7 +338,9 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret) const{
String n=p_name;
- if (n=="custom_package/debug")
+ if (n=="one_click_deploy/clear_previous_install")
+ r_ret=remove_prev;
+ else if (n=="custom_package/debug")
r_ret=custom_debug_package;
else if (n=="custom_package/release")
r_ret=custom_release_package;
@@ -339,6 +358,14 @@ bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret)
r_ret=icon;
else if (n=="package/signed")
r_ret=_signed;
+ else if (n=="architecture/arm")
+ r_ret=export_arm;
+ else if (n=="architecture/x86")
+ r_ret=export_x86;
+ else if (n=="screen/use_32_bits_view")
+ r_ret=use_32_fb;
+ else if (n=="screen/immersive_mode")
+ r_ret=immersive;
else if (n=="screen/orientation")
r_ret=orientation;
else if (n=="screen/support_small")
@@ -363,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
@@ -378,8 +405,9 @@ bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret)
void EditorExportPlatformAndroid::_get_property_list( List<PropertyInfo> *p_list) const{
- p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_FILE,"apk"));
- p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_FILE,"apk"));
+ p_list->push_back( PropertyInfo( Variant::BOOL, "one_click_deploy/clear_previous_install"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE,"apk"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE,"apk"));
p_list->push_back( PropertyInfo( Variant::STRING, "command_line/extra_args"));
p_list->push_back( PropertyInfo( Variant::INT, "version/code", PROPERTY_HINT_RANGE,"1,65535,1"));
p_list->push_back( PropertyInfo( Variant::STRING, "version/name") );
@@ -387,13 +415,18 @@ void EditorExportPlatformAndroid::_get_property_list( List<PropertyInfo> *p_list
p_list->push_back( PropertyInfo( Variant::STRING, "package/name") );
p_list->push_back( PropertyInfo( Variant::STRING, "package/icon",PROPERTY_HINT_FILE,"png") );
p_list->push_back( PropertyInfo( Variant::BOOL, "package/signed") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "architecture/arm") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "architecture/x86") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "screen/use_32_bits_view") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "screen/immersive_mode") );
p_list->push_back( PropertyInfo( Variant::INT, "screen/orientation",PROPERTY_HINT_ENUM,"Landscape,Portrait") );
p_list->push_back( PropertyInfo( Variant::BOOL, "screen/support_small") );
p_list->push_back( PropertyInfo( Variant::BOOL, "screen/support_normal") );
p_list->push_back( PropertyInfo( Variant::BOOL, "screen/support_large") );
p_list->push_back( PropertyInfo( Variant::BOOL, "screen/support_xlarge") );
- p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release",PROPERTY_HINT_FILE,"keystore") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release",PROPERTY_HINT_GLOBAL_FILE,"keystore") );
p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release_user" ) );
+ p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release_password" ) );
p_list->push_back( PropertyInfo( Variant::BOOL, "apk_expansion/enable" ) );
p_list->push_back( PropertyInfo( Variant::STRING, "apk_expansion/SALT" ) );
p_list->push_back( PropertyInfo( Variant::STRING, "apk_expansion/public_key",PROPERTY_HINT_MULTILINE_TEXT ) );
@@ -426,7 +459,7 @@ static String _parse_string(const uint8_t *p_bytes,bool p_utf8) {
}
offset+=2;
- printf("len %i, unicode: %i\n",len,int(p_utf8));
+ //printf("len %i, unicode: %i\n",len,int(p_utf8));
if (p_utf8) {
@@ -575,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;
@@ -622,11 +655,11 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
int iofs=ofs+8;
- uint32_t string_count=decode_uint32(&p_manifest[iofs]);
- uint32_t styles_count=decode_uint32(&p_manifest[iofs+4]);
+ string_count=decode_uint32(&p_manifest[iofs]);
+ styles_count=decode_uint32(&p_manifest[iofs+4]);
uint32_t string_flags=decode_uint32(&p_manifest[iofs+8]);
- uint32_t string_data_offset=decode_uint32(&p_manifest[iofs+12]);
- uint32_t styles_offset=decode_uint32(&p_manifest[iofs+16]);
+ string_data_offset=decode_uint32(&p_manifest[iofs+12]);
+ styles_offset=decode_uint32(&p_manifest[iofs+16]);
/*
printf("string count: %i\n",string_count);
printf("flags: %i\n",string_flags);
@@ -725,7 +758,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
if (tname=="manifest" && attrname=="package") {
print_line("FOUND PACKAGE");
- string_table[attr_value]=package;
+ string_table[attr_value]=get_package_name();
}
//print_line("tname: "+tname);
@@ -749,19 +782,21 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
if (tname=="activity" && /*nspace=="android" &&*/ attrname=="screenOrientation") {
+ encode_uint32(orientation==0?0:1,&p_manifest[iofs+16]);
+ /*
print_line("FOUND screen orientation");
if (attr_value==0xFFFFFFFF) {
WARN_PRINT("Version name in a resource, should be plaintext")
} else {
string_table[attr_value]=(orientation==0?"landscape":"portrait");
- }
+ }*/
}
if (tname=="application" && /*nspace=="android" &&*/ attrname=="label") {
print_line("FOUND application");
if (attr_value==0xFFFFFFFF) {
- WARN_PRINT("Application name in a resource, should be plaintext.")
+ WARN_PRINT("Application name in a resource, should be plaintext (but you can ignore this).")
} else {
String aname = get_project_name();
@@ -772,7 +807,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
print_line("FOUND activity name");
if (attr_value==0xFFFFFFFF) {
- WARN_PRINT("Activity name in a resource, should be plaintext")
+ WARN_PRINT("Activity name in a resource, should be plaintext (but you can ignore this)")
} else {
String aname;
if (this->name!="") {
@@ -803,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;
}
@@ -816,23 +854,19 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
WARN_PRINT("Screen res name in a resource, should be plaintext")
} else if (attrname=="smallScreens") {
- print_line("SMALLSCREEN");
- string_table[attr_value]=screen_support[SCREEN_SMALL]?"true":"false";
+ encode_uint32(screen_support[SCREEN_SMALL]?0xFFFFFFFF:0,&p_manifest[iofs+16]);
} else if (attrname=="mediumScreens") {
- print_line("MEDSCREEN");
- string_table[attr_value]=screen_support[SCREEN_NORMAL]?"true":"false";
+ encode_uint32(screen_support[SCREEN_NORMAL]?0xFFFFFFFF:0,&p_manifest[iofs+16]);
} else if (attrname=="largeScreens") {
- print_line("LARGECREEN");
- string_table[attr_value]=screen_support[SCREEN_LARGE]?"true":"false";
+ encode_uint32(screen_support[SCREEN_LARGE]?0xFFFFFFFF:0,&p_manifest[iofs+16]);
} else if (attrname=="xlargeScreens") {
- print_line("XLARGECREEN");
- string_table[attr_value]=screen_support[SCREEN_XLARGE]?"true":"false";
+ encode_uint32(screen_support[SCREEN_XLARGE]?0xFFFFFFFF:0,&p_manifest[iofs+16]);
}
}
@@ -980,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);
@@ -1028,6 +1068,8 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
char fname[16384];
ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
+ bool skip=false;
+
String file=fname;
Vector<uint8_t> data;
@@ -1042,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") {
@@ -1080,20 +1122,35 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
}
}
+ if (file=="lib/x86/libgodot_android.so" && !export_x86) {
+ skip=true;
+ }
+
+ if (file=="lib/armeabi/libgodot_android.so" && !export_arm) {
+ skip=true;
+ }
+
+ if (file.begins_with("META-INF") && _signed) {
+ skip=true;
+ }
+
print_line("ADDING: "+file);
- zipOpenNewFileInZip(apk,
- file.utf8().get_data(),
- NULL,
- NULL,
- 0,
- NULL,
- 0,
- NULL,
- Z_DEFLATED,
- Z_DEFAULT_COMPRESSION);
- zipWriteInFileInZip(apk,data.ptr(),data.size());
- zipCloseFileInZip(apk);
+ if (!skip) {
+ zipOpenNewFileInZip(apk,
+ file.utf8().get_data(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+ zipWriteInFileInZip(apk,data.ptr(),data.size());
+ zipCloseFileInZip(apk);
+ }
ret = unzGoToNextFile(pkg);
}
@@ -1109,9 +1166,11 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
}
}
- if (p_dumb) {
+ gen_export_flags(cl,p_flags);
+
+ if (p_flags) {
- String host = EditorSettings::get_singleton()->get("file_server/host");
+ /*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");
@@ -1119,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 {
@@ -1127,7 +1186,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
if (apk_expansion) {
- String apkfname="main."+itos(version_code)+"."+package+".obb";
+ String apkfname="main."+itos(version_code)+"."+get_package_name()+".obb";
String fullpath=p_path.get_base_dir().plus_file(apkfname);
FileAccess *pf = FileAccess::open(fullpath,FileAccess::WRITE);
if (!pf) {
@@ -1151,8 +1210,16 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
err = export_project_files(save_apk_file,&ed,false);
}
+
+
}
+ if (use_32_fb)
+ cl.push_back("-use_depth_32");
+
+ if (immersive)
+ cl.push_back("-use_immersive");
+
if (cl.size()) {
//add comandline
Vector<uint8_t> clf;
@@ -1222,7 +1289,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
}
if (!FileAccess::exists(keystore)) {
- EditorNode::add_io_error("Could not find keytore, unable to export.");
+ EditorNode::add_io_error("Could not find keystore, unable to export.");
return ERR_FILE_CANT_OPEN;
}
@@ -1231,6 +1298,11 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
args.push_back("SHA1");
args.push_back("-sigalg");
args.push_back("MD5withRSA");
+ String tsa_url=EditorSettings::get_singleton()->get("android/timestamping_authority_url");
+ if (tsa_url != "") {
+ args.push_back("-tsa");
+ args.push_back(tsa_url);
+ }
args.push_back("-verbose");
args.push_back("-keystore");
args.push_back(keystore);
@@ -1423,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();
@@ -1442,22 +1514,26 @@ 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;
}
- ep.step("Uninstalling..",1);
-
- print_line("Uninstalling previous version: "+devices[p_device].name);
List<String> args;
- args.push_back("-s");
- args.push_back(devices[p_device].id);
- args.push_back("uninstall");
- args.push_back(package);
int rv;
- err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+
+ if (remove_prev) {
+ ep.step("Uninstalling..",1);
+
+ print_line("Uninstalling previous version: "+devices[p_device].name);
+
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("uninstall");
+ args.push_back(get_package_name());
+
+ err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
#if 0
if (err || rv!=0) {
EditorNode::add_io_error("Could not install to device.");
@@ -1465,6 +1541,8 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
return ERR_CANT_CREATE;
}
#endif
+ }
+
print_line("Installing into device (please wait..): "+devices[p_device].name);
ep.step("Installing to Device (please wait..)..",2);
@@ -1473,7 +1551,7 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
args.push_back(devices[p_device].id);
args.push_back("install");
args.push_back(export_to);
- rv;
+
err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
if (err || rv!=0) {
EditorNode::add_io_error("Could not install to device.");
@@ -1491,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(package+"/com.android.godot.Godot");
+ args.push_back(get_package_name()+"/com.android.godot.Godot");
err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
if (err || rv!=0) {
@@ -1503,18 +1581,50 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
return OK;
}
+String EditorExportPlatformAndroid::get_package_name() {
+
+ String pname = package;
+ String basename = Globals::get_singleton()->get("application/name");
+ basename=basename.to_lower();
+
+ String name;
+ bool first=true;
+ for(int i=0;i<basename.length();i++) {
+ CharType c = basename[i];
+ if (c>='0' && c<='9' && first) {
+ continue;
+ }
+ if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')) {
+ name+=String::chr(c);
+ first=false;
+ }
+ }
+ if (name=="")
+ name="noname";
+
+ pname=pname.replace("$genname",name);
+ return pname;
+
+}
EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
version_code=1;
version_name="1.0";
- package="com.android.noname";
+ package="org.godotengine.$genname";
name="";
_signed=true;
apk_expansion=false;
device_lock = Mutex::create();
quit_request=false;
orientation=0;
+ remove_prev=true;
+ use_32_fb=true;
+ immersive=true;
+
+ export_arm=true;
+ export_x86=false;
+
device_thread=Thread::create(_device_poll_thread,this);
devices_changed=true;
@@ -1555,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";
}
@@ -1594,8 +1701,11 @@ bool EditorExportPlatformAndroid::can_export(String *r_error) const {
EditorExportPlatformAndroid::~EditorExportPlatformAndroid() {
+
quit_request=true;
Thread::wait_to_finish(device_thread);
+ memdelete(device_lock);
+ memdelete(device_thread);
}
@@ -1613,6 +1723,7 @@ void register_android_exporter() {
//EDITOR_DEF("android/release_keystore","");
//EDITOR_DEF("android/release_username","");
//EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/release_keystore",PROPERTY_HINT_GLOBAL_FILE,"*.keystore"));
+ EDITOR_DEF("android/timestamping_authority_url","");
Ref<EditorExportPlatformAndroid> exporter = Ref<EditorExportPlatformAndroid>( memnew(EditorExportPlatformAndroid) );
EditorImportExport::get_singleton()->add_export_platform(exporter);
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index f1a2bf5882..ff70d5ae76 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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)
@@ -184,4 +183,4 @@ FileAccessAndroid::~FileAccessAndroid()
{
close();
}
-#endif
+
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index 080ab1a6ce..506c2c023f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 e1dec4f601..be38d806b2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -62,14 +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 3cbeab5ffc..13ac4e17b8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/android/globals/global_defaults.cpp b/platform/android/globals/global_defaults.cpp
index 84a586d22d..824a4e3606 100644
--- a/platform/android/globals/global_defaults.cpp
+++ b/platform/android/globals/global_defaults.cpp
@@ -10,5 +10,5 @@ void register_android_global_defaults() {
GLOBAL_DEF("display.Android/driver","GLES2");
// GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false);
- Globals::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2"));
+ Globals::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES2"));
}
diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp
index 673ff91641..388ff06c10 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/android/java/res/drawable/icon.png b/platform/android/java/res/drawable/icon.png
index 050a1cf930..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/java/res/layout/downloading_expansion.xml b/platform/android/java/res/layout/downloading_expansion.xml
new file mode 100644
index 0000000000..553155dcd3
--- /dev/null
+++ b/platform/android/java/res/layout/downloading_expansion.xml
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/statusText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:layout_marginLeft="5dp"
+ android:layout_marginTop="10dp"
+ android:textStyle="bold" />
+
+ <LinearLayout
+ android:id="@+id/downloaderDashboard"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/statusText"
+ android:orientation="vertical" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/progressAsFraction"
+ style="@android:style/TextAppearance.Small"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="5dp"
+ android:text="0MB / 0MB" >
+ </TextView>
+
+ <TextView
+ android:id="@+id/progressAsPercentage"
+ style="@android:style/TextAppearance.Small"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignRight="@+id/progressBar"
+ android:text="0%" />
+
+ <ProgressBar
+ android:id="@+id/progressBar"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/progressAsFraction"
+ android:layout_marginBottom="10dp"
+ android:layout_marginLeft="10dp"
+ android:layout_marginRight="10dp"
+ android:layout_marginTop="10dp"
+ android:layout_weight="1" />
+
+ <TextView
+ android:id="@+id/progressAverageSpeed"
+ style="@android:style/TextAppearance.Small"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@+id/progressBar"
+ android:layout_marginLeft="5dp" />
+
+ <TextView
+ android:id="@+id/progressTimeRemaining"
+ style="@android:style/TextAppearance.Small"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignRight="@+id/progressBar"
+ android:layout_below="@+id/progressBar" />
+ </RelativeLayout>
+
+ <LinearLayout
+ android:id="@+id/downloaderDashboard"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/pauseButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="10dp"
+ android:layout_marginLeft="10dp"
+ android:layout_marginRight="5dp"
+ android:layout_marginTop="10dp"
+ android:layout_weight="0"
+ android:minHeight="40dp"
+ android:minWidth="94dp"
+ android:text="@string/text_button_pause" />
+
+ <Button
+ android:id="@+id/cancelButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="10dp"
+ android:layout_marginLeft="5dp"
+ android:layout_marginRight="5dp"
+ android:layout_marginTop="10dp"
+ android:layout_weight="0"
+ android:minHeight="40dp"
+ android:minWidth="94dp"
+ android:text="@string/text_button_cancel"
+ android:visibility="gone" />
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/approveCellular"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:visibility="gone" >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:id="@+id/textPausedParagraph1"
+ android:text="@string/text_paused_cellular" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:id="@+id/textPausedParagraph2"
+ android:text="@string/text_paused_cellular_2" />
+
+ <LinearLayout
+ android:id="@+id/buttonRow"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/resumeOverCellular"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_margin="10dp"
+ android:text="@string/text_button_resume_cellular" />
+
+ <Button
+ android:id="@+id/wifiSettingsButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_margin="10dp"
+ android:text="@string/text_button_wifi_settings" />
+ </LinearLayout>
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
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/java/res/values/strings.xml b/platform/android/java/res/values/strings.xml
index 3a38d40599..49ebcc06f9 100644
--- a/platform/android/java/res/values/strings.xml
+++ b/platform/android/java/res/values/strings.xml
@@ -3,5 +3,15 @@
<string name="godot_project_name_string">godot-project-name</string>
<string name="testuf8">元気です</string>
<string name="testuf2">元気です元気です元気です</string>
-
+ <string name="text_paused_cellular">Would you like to enable downloading over cellular connections? Depending on your data plan, this may cost you money.</string>
+ <string name="text_paused_cellular_2">If you choose not to enable downloading over cellular connections, the download will automatically resume when wi-fi is available.</string>
+ <string name="text_button_resume_cellular">Resume download</string>
+ <string name="text_button_wifi_settings">Wi-Fi settings</string>
+ <string name="text_verifying_download">Verifying Download</string>
+ <string name="text_validation_complete">XAPK File Validation Complete. Select OK to exit.</string>
+ <string name="text_validation_failed">XAPK File Validation Failed.</string>
+ <string name="text_button_pause">Pause Download</string>
+ <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>
diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java
index 658c272321..4c5a313576 100644
--- a/platform/android/java/src/com/android/godot/Godot.java
+++ b/platform/android/java/src/com/android/godot/Godot.java
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,16 +28,20 @@
/*************************************************************************/
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.*;
@@ -48,33 +52,84 @@ 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 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;
-public class Godot extends Activity implements SensorEventListener
+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);
@@ -83,20 +138,20 @@ public class Godot extends Activity implements SensorEventListener
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
boolean found=false;
- System.out.printf("METHOD: %s\n",method.getName());
+ Log.d("XXX","METHOD: %s\n" + method.getName());
for (String s : p_methods) {
- System.out.printf("METHOD CMP WITH: %s\n",s);
+ Log.d("XXX", "METHOD CMP WITH: %s\n" + s);
if (s.equals(method.getName())) {
found=true;
- System.out.printf("METHOD CMP VALID");
+ Log.d("XXX","METHOD CMP VALID");
break;
}
}
if (!found)
continue;
- System.out.printf("METHOD FOUND: %s\n",method.getName());
+ Log.d("XXX","METHOD FOUND: %s\n" + method.getName());
List<String> ptr = new ArrayList<String>();
@@ -202,7 +257,7 @@ public class Godot extends Activity implements SensorEventListener
// ...add to FrameLayout
layout.addView(edittext);
- mView = new GodotView(getApplication(),io,use_gl2, this);
+ 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);
@@ -230,7 +285,7 @@ public class Godot extends Activity implements SensorEventListener
byte[] len = new byte[4];
int r = is.read(len);
if (r<4) {
- System.out.printf("**ERROR** Wrong cmdline length.\n");
+ Log.d("XXX","**ERROR** Wrong cmdline length.\n");
Log.d("GODOT", "**ERROR** Wrong cmdline length.\n");
return new String[0];
}
@@ -258,7 +313,6 @@ public class Godot extends Activity implements SensorEventListener
return cmdline;
} catch (Exception e) {
e.printStackTrace();
- System.out.printf("**ERROR** No commandline.\n");
Log.d("GODOT", "**ERROR** Exception " + e.getClass().getName() + ":" + e.getMessage());
return new String[0];
}
@@ -277,12 +331,14 @@ public class Godot extends Activity implements SensorEventListener
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 ];
}
@@ -294,10 +350,17 @@ public class Godot extends Activity implements SensorEventListener
io = new GodotIO(this);
io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
GodotLib.io=io;
- GodotLib.initialize(this,io.needsReloadHooks(),command_line);
+ 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_NORMAL);
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
result_callback = null;
@@ -306,10 +369,18 @@ public class Godot extends Activity implements SensorEventListener
}
+ @Override
+ public void onServiceConnected(Messenger m) {
+ mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
+ mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
+ }
- @Override protected void onCreate(Bundle icicle) {
- System.out.printf("** GODOT ACTIVITY CREATED HERE ***\n");
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+
+ Log.d("GODOT", "** GODOT ACTIVITY CREATED HERE ***\n");
super.onCreate(icicle);
_self = this;
@@ -319,7 +390,8 @@ public class Godot extends Activity implements SensorEventListener
//check for apk expansion API
- if (!true) {
+ if (true) {
+ boolean md5mismatch = false;
command_line = getCommandLine();
boolean use_apk_expansion=false;
String main_pack_md5=null;
@@ -331,24 +403,45 @@ public class Godot extends Activity implements SensorEventListener
for(int i=0;i<command_line.length;i++) {
boolean has_extra = i< command_line.length -1;
- if (command_line[i].equals("-use_apk_expansion")) {
+ 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())
+ if (new_args.isEmpty()){
command_line=null;
- else
- command_line = new_args.toArray(new String[new_args.size()]);
+ }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 )) {
@@ -374,49 +467,62 @@ public class Godot extends Activity implements SensorEventListener
pack_valid=false;
Log.d("GODOT","**PACK** - File does not exist");
- } else {
- try {
-
- InputStream fis = new FileInputStream(expansion_pack_path);
-
- // 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++)
- hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
- String md5str = hexString.toString();
-
- Log.d("GODOT","**PACK** - My MD5: "+hexString+" - APK md5: "+main_pack_md5);
- if (!hexString.equals(main_pack_md5)) {
- pack_valid=false;
- }
- } catch (Exception e) {
- e.printStackTrace();
- Log.d("GODOT","**PACK FAIL**");
- pack_valid=false;
+ } 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());
+ }
}
@@ -431,6 +537,7 @@ public class Godot extends Activity implements SensorEventListener
}
+
@Override protected void onDestroy(){
if(mPaymentsManager != null ) mPaymentsManager.destroy();
@@ -442,8 +549,12 @@ public class Godot extends Activity implements SensorEventListener
@Override protected void onPause() {
super.onPause();
- if (!godot_initialized)
+ if (!godot_initialized){
+ if (null != mDownloaderClientStub) {
+ mDownloaderClientStub.disconnect(this);
+ }
return;
+ }
mView.onPause();
mSensorManager.unregisterListener(this);
GodotLib.focusout();
@@ -455,24 +566,73 @@ public class Godot extends Activity implements SensorEventListener
@Override protected void onResume() {
super.onResume();
- if (!godot_initialized)
+ 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) {
- float x = event.values[0];
- float y = event.values[1];
- float z = event.values[2];
+ 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);
}
@@ -508,6 +668,54 @@ public class Godot extends Activity implements SensorEventListener
}
+
+ 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) {
@@ -539,7 +747,8 @@ public class Godot extends Activity implements SensorEventListener
//}
} break;
case MotionEvent.ACTION_POINTER_UP: {
- int pointer_idx = event.getActionIndex();
+ 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;
@@ -602,5 +811,115 @@ public class Godot extends Activity implements SensorEventListener
// 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
index d945a8b192..e82c3eb0fe 100644
--- a/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java
+++ b/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java
@@ -6,6 +6,7 @@ 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
@@ -18,10 +19,12 @@ 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
index e0fe95ad96..2657edc1d2 100644
--- a/platform/android/java/src/com/android/godot/GodotDownloaderService.java
+++ b/platform/android/java/src/com/android/godot/GodotDownloaderService.java
@@ -1,5 +1,9 @@
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;
/**
@@ -21,7 +25,11 @@ public class GodotDownloaderService extends DownloaderService {
*/
@Override
public String getPublicKey() {
- return BASE64_PUBLIC_KEY;
+ 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;
}
/**
@@ -41,7 +49,8 @@ public class GodotDownloaderService extends DownloaderService {
*/
@Override
public String getAlarmReceiverClassName() {
- return GodotDownloaderAlarmReceiver.class.getName();
+ 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
index fad489721c..a7dc0c2f75 100644
--- a/platform/android/java/src/com/android/godot/GodotIO.java
+++ b/platform/android/java/src/com/android/godot/GodotIO.java
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -94,6 +94,7 @@ public class GodotIO {
//System.out.printf("file_open: Attempt to Open %s\n",path);
+ //Log.v("MyApp", "TRYING TO OPEN FILE: " + path);
if (write)
return -1;
@@ -105,7 +106,7 @@ public class GodotIO {
} catch (Exception e) {
- //System.out.printf("Exception on file_open: %s\n",e);
+ //System.out.printf("Exception on file_open: %s\n",path);
return -1;
}
@@ -113,7 +114,7 @@ public class GodotIO {
ad.len=ad.is.available();
} catch (Exception e) {
- System.out.printf("Exception availabling on file_open: %s\n",e);
+ System.out.printf("Exception availabling on file_open: %s\n",path);
return -1;
}
@@ -271,6 +272,7 @@ public class GodotIO {
public String[] files;
public int current;
+ public String path;
}
public int last_dir_id=1;
@@ -281,6 +283,7 @@ public class GodotIO {
AssetDir ad = new AssetDir();
ad.current=0;
+ ad.path=path;
try {
ad.files = am.list(path);
@@ -290,6 +293,7 @@ public class GodotIO {
return -1;
}
+ //System.out.printf("Opened dir: %s\n",path);
++last_dir_id;
dirs.put(last_dir_id,ad);
@@ -297,6 +301,32 @@ public class GodotIO {
}
+ 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)) {
@@ -305,8 +335,12 @@ public class GodotIO {
}
AssetDir ad = dirs.get(id);
- if (ad.current>=ad.files.length)
+ //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;
@@ -438,8 +472,26 @@ public class GodotIO {
try {
Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri);
- Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(p_uri));
- activity.startActivity(myIntent);
+ 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) {
@@ -557,6 +609,58 @@ public class GodotIO {
}
}
+
+ 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";
diff --git a/platform/android/java/src/com/android/godot/GodotLib.java b/platform/android/java/src/com/android/godot/GodotLib.java
index 6e2462b4f1..3d870b3b1f 100644
--- a/platform/android/java/src/com/android/godot/GodotLib.java
+++ b/platform/android/java/src/com/android/godot/GodotLib.java
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -44,9 +44,9 @@ public class GodotLib {
* @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 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();
+ 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);
diff --git a/platform/android/java/src/com/android/godot/GodotPaymentV3.java b/platform/android/java/src/com/android/godot/GodotPaymentV3.java
index dba4a9a774..0799e1e83d 100644
--- a/platform/android/java/src/com/android/godot/GodotPaymentV3.java
+++ b/platform/android/java/src/com/android/godot/GodotPaymentV3.java
@@ -1,8 +1,6 @@
package com.android.godot;
-
-import org.json.JSONObject;
-
+import com.android.godot.Dictionary;
import android.app.Activity;
import android.util.Log;
@@ -29,7 +27,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
activity.getPaymentsManager().requestPurchase(sku, transactionId);
}
});
- };
+ }
/* public string requestPurchasedTicket(){
activity.getPaymentsManager()
@@ -44,10 +42,19 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
public GodotPaymentV3(Activity p_activity) {
- registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature"});
+ 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(){
@@ -55,15 +62,26 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
}
- public void callbackSuccess(String ticket, String signature){
- Log.d(this.getClass().getName(), "PRE-Send callback to purchase success");
- GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature});
- Log.d(this.getClass().getName(), "POST-Send callback to purchase success");
+ 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[]{});
+ GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{});
+// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
}
public void callbackCancel(){
@@ -71,6 +89,10 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
// 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;
}
@@ -79,8 +101,6 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
this.purchaseCallbackId = purchaseCallbackId;
}
-
-
public String getPurchaseValidationUrlPrefix(){
return this.purchaseValidationUrlPrefix ;
}
@@ -89,12 +109,10 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
this.purchaseValidationUrlPrefix = url;
}
-
public String getAccessToken() {
return accessToken;
}
-
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
@@ -107,4 +125,30 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
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/com/android/godot/GodotView.java b/platform/android/java/src/com/android/godot/GodotView.java
index f62431b94b..bc249d46c6 100644
--- a/platform/android/java/src/com/android/godot/GodotView.java
+++ b/platform/android/java/src/com/android/godot/GodotView.java
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -71,14 +71,16 @@ public class GodotView extends GLSurfaceView {
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, Godot p_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;
@@ -366,9 +368,17 @@ public class GodotView extends GLSurfaceView {
* custom config chooser. See ConfigChooser class definition
* below.
*/
- setEGLConfigChooser( translucent ?
- new ConfigChooser(8, 8, 8, 8, depth, stencil) :
- new ConfigChooser(5, 6, 5, 0, depth, stencil) );
+
+ 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());
@@ -400,6 +410,26 @@ public class GodotView extends GLSurfaceView {
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 {
@@ -625,7 +655,7 @@ public class GodotView extends GLSurfaceView {
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- GodotLib.newcontext();
+ GodotLib.newcontext(use_32);
}
}
}
diff --git a/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java b/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java
new file mode 100644
index 0000000000..d68f029246
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java
@@ -0,0 +1,53 @@
+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
index a810ac40ae..4c31704cc8 100644
--- a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java
+++ b/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java
@@ -28,19 +28,19 @@ abstract public class HandlePurchaseTask {
public void handlePurchaseRequest(int resultCode, Intent data){
- Log.d("XXX", "Handling purchase response");
+// 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);
+// Log.d("XXX", "Purchase data:" + purchaseData);
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
- Log.d("XXX", "Purchase signature:" + dataSignature);
+ //Log.d("XXX", "Purchase signature:" + dataSignature);
if (resultCode == Activity.RESULT_OK) {
try {
- Log.d("SARLANGA", purchaseData);
+// Log.d("SARLANGA", purchaseData);
JSONObject jo = new JSONObject(purchaseData);
@@ -58,13 +58,13 @@ abstract public class HandlePurchaseTask {
error("Untrusted callback");
return;
}
- Log.d("XXX", "Este es el product ID:" + productId);
+// 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);
+ success(productId, dataSignature, purchaseData);
return;
} catch (JSONException e) {
error(e.getMessage());
@@ -74,7 +74,7 @@ abstract public class HandlePurchaseTask {
}
}
- abstract protected void success(String ticket, String signature);
+ 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
index 7337acc0b8..1de772bf28 100644
--- a/platform/android/java/src/com/android/godot/payments/PaymentsCache.java
+++ b/platform/android/java/src/com/android/godot/payments/PaymentsCache.java
@@ -31,14 +31,14 @@ public class PaymentsCache {
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);
+// 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);
+// 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
index d85a8ea8ea..189f7108c1 100644
--- a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java
+++ b/platform/android/java/src/com/android/godot/payments/PaymentsManager.java
@@ -1,5 +1,9 @@
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;
@@ -7,7 +11,13 @@ 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;
@@ -15,15 +25,12 @@ 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;
}
@@ -38,8 +45,10 @@ public class PaymentsManager {
}
public PaymentsManager initService(){
+ Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
+ intent.setPackage("com.android.vending");
activity.bindService(
- new Intent("com.android.vending.billing.InAppBillingService.BIND"),
+ intent,
mServiceConn,
Context.BIND_AUTO_CREATE);
return this;
@@ -58,13 +67,12 @@ public class PaymentsManager {
}
@Override
- public void onServiceConnected(ComponentName name,
- IBinder service) {
- mService = IInAppBillingService.Stub.asInterface(service);
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mService = IInAppBillingService.Stub.asInterface(service);
}
};
- public void requestPurchase(String sku, String transactionId){
+ public void requestPurchase(final String sku, String transactionId){
new PurchaseTask(mService, Godot.getInstance()) {
@Override
@@ -77,33 +85,116 @@ public class PaymentsManager {
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) {
- new ConsumeTask(mService, activity) {
+ 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("");
- Log.d("XXX", "calling success:" + signature);
- godotPaymentV3.callbackSuccess(ticket, signature);
- }
+ @Override
+ protected void success(String ticket) {
+// godotPaymentV3.callbackSuccess("");
+ }
- @Override
- protected void error(String message) {
- godotPaymentV3.callbackFail();
+ @Override
+ protected void error(String message) {
+ godotPaymentV3.callbackFail();
- }
- }.consume(sku);
-
-
+ }
+ }.consume(sku);
+ }
+// godotPaymentV3.callbackSuccess(new PaymentsCache(activity).getConsumableValue("ticket", sku),signature);
// godotPaymentV3.callbackSuccess(ticket);
//validatePurchase(purchaseToken, sku);
}
@@ -119,7 +210,7 @@ public class PaymentsManager {
godotPaymentV3.callbackCancel();
}
- }.handlePurchaseRequest(resultCode, data);
+ }.handlePurchaseRequest(resultCode, data);
}
public void validatePurchase(String purchaseToken, final String sku){
@@ -133,7 +224,7 @@ public class PaymentsManager {
@Override
protected void success(String ticket) {
- godotPaymentV3.callbackSuccess(ticket, null);
+ godotPaymentV3.callbackSuccess(ticket, null, sku);
}
@@ -160,11 +251,32 @@ public class PaymentsManager {
}.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/com/android/godot/payments/PurchaseTask.java b/platform/android/java/src/com/android/godot/payments/PurchaseTask.java
index 0856b4e900..c1f9d164a1 100644
--- a/platform/android/java/src/com/android/godot/payments/PurchaseTask.java
+++ b/platform/android/java/src/com/android/godot/payments/PurchaseTask.java
@@ -62,33 +62,13 @@ abstract public class PurchaseTask {
// Log.d("XXX", "Buy intent response code: " + responseCode);
if(responseCode == 1 || responseCode == 3 || responseCode == 4){
canceled();
- return ;
+ return;
}
if(responseCode == 7){
- new ConsumeTask(mService, context) {
-
- @Override
- protected void success(String ticket) {
-// Log.d("XXX", "Product was erroniously purchased!");
- if(isLooping){
-// Log.d("XXX", "It is looping");
- error("Error while purchasing product");
- return;
- }
- isLooping=true;
- PurchaseTask.this.purchase(sku, transactionId);
-
- }
-
- @Override
- protected void error(String message) {
- PurchaseTask.this.error(message);
-
- }
- }.consume(sku);
+ alreadyOwned();
return;
}
-
+
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
pc.setConsumableValue("validation_hash", sku, hash);
@@ -116,6 +96,6 @@ abstract public class PurchaseTask {
abstract protected void error(String message);
abstract protected void canceled();
-
+ abstract protected void alreadyOwned();
}
diff --git a/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java
new file mode 100644
index 0000000000..c1a9c5d421
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java
@@ -0,0 +1,87 @@
+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_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
new file mode 100644
index 0000000000..d4cf848484
--- /dev/null
+++ b/platform/android/java_class_wrapper.cpp
@@ -0,0 +1,1332 @@
+#include "java_class_wrapper.h"
+#include "thread_jandroid.h"
+
+
+bool JavaClass::_call_method(JavaObject* p_instance,const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error,Variant& ret) {
+
+ Map<StringName,List<MethodInfo> >::Element *M=methods.find(p_method);
+ if (!M)
+ return false;
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ MethodInfo *method=NULL;
+ for (List<MethodInfo>::Element *E=M->get().front();E;E=E->next()) {
+
+ if (!p_instance && !E->get()._static) {
+ r_error.error=Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ continue;
+ }
+
+ int pc = E->get().param_types.size();
+ if (pc>p_argcount) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=pc;
+ continue;
+ }
+ if (pc<p_argcount) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument=pc;
+ continue;
+ }
+ uint32_t *ptypes=E->get().param_types.ptr();
+ bool valid=true;
+
+ for(int i=0;i<pc;i++) {
+
+ Variant::Type arg_expected=Variant::NIL;
+ switch(ptypes[i]) {
+
+ case ARG_TYPE_VOID: {
+ //bug?
+ } break;
+ case ARG_TYPE_BOOLEAN: {
+ if (p_args[i]->get_type()!=Variant::BOOL)
+ arg_expected=Variant::BOOL;
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BYTE:
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_CHAR:
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_SHORT:
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_INT:
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_LONG:
+ case ARG_TYPE_BYTE:
+ case ARG_TYPE_CHAR:
+ case ARG_TYPE_SHORT:
+ case ARG_TYPE_INT:
+ case ARG_TYPE_LONG: {
+
+ if (!p_args[i]->is_num())
+ arg_expected=Variant::INT;
+
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_FLOAT:
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_DOUBLE:
+ case ARG_TYPE_FLOAT:
+ case ARG_TYPE_DOUBLE: {
+
+ if (!p_args[i]->is_num())
+ arg_expected=Variant::REAL;
+
+ } break;
+ case ARG_TYPE_STRING: {
+
+ if (p_args[i]->get_type()!=Variant::STRING)
+ arg_expected=Variant::STRING;
+
+ } break;
+ case ARG_TYPE_CLASS: {
+
+ if (p_args[i]->get_type()!=Variant::OBJECT)
+ arg_expected=Variant::OBJECT;
+ else {
+
+ Ref<Reference> ref = *p_args[i];
+ if (!ref.is_null()) {
+ if (ref->cast_to<JavaObject>() ) {
+
+ Ref<JavaObject> jo=ref;
+ //could be faster
+ jclass c = env->FindClass(E->get().param_sigs[i].operator String().utf8().get_data());
+ if (!c || !env->IsInstanceOf(jo->instance,c)) {
+
+ arg_expected=Variant::OBJECT;
+ } else {
+ //ok
+ }
+ } else {
+ arg_expected=Variant::OBJECT;
+ }
+
+ }
+ }
+
+ } break;
+ default: {
+
+ if (p_args[i]->get_type()!=Variant::ARRAY)
+ arg_expected=Variant::ARRAY;
+
+ } break;
+
+ }
+
+ if (arg_expected!=Variant::NIL) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=i;
+ r_error.expected=arg_expected;
+ valid=false;
+ break;
+
+ }
+
+ }
+ if (!valid)
+ continue;
+
+
+ method=&E->get();
+ break;
+
+ }
+
+ if (!method)
+ return true; //no version convinces
+
+
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ jvalue *argv=NULL;
+
+ if (method->param_types.size()) {
+
+ argv=(jvalue*)alloca( sizeof(jvalue)*method->param_types.size() );
+ }
+
+ List<jobject> to_free;
+ for(int i=0;i<method->param_types.size();i++) {
+
+ switch(method->param_types[i]) {
+ case ARG_TYPE_VOID: {
+ //can't happen
+ argv[i].l=NULL; //I hope this works
+ } break;
+
+ case ARG_TYPE_BOOLEAN: {
+ argv[i].z=*p_args[i];
+ } break;
+ case ARG_TYPE_BYTE: {
+ argv[i].b=*p_args[i];
+ } break;
+ case ARG_TYPE_CHAR: {
+ argv[i].c=*p_args[i];
+ } break;
+ case ARG_TYPE_SHORT: {
+ argv[i].s=*p_args[i];
+ } break;
+ case ARG_TYPE_INT: {
+ argv[i].i=*p_args[i];
+ } break;
+ case ARG_TYPE_LONG: {
+ argv[i].j=*p_args[i];
+ } break;
+ case ARG_TYPE_FLOAT: {
+ argv[i].f=*p_args[i];
+ } break;
+ case ARG_TYPE_DOUBLE: {
+ argv[i].d=*p_args[i];
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BOOLEAN: {
+ jclass bclass = env->FindClass("java/lang/Boolean");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
+ jvalue val;
+ val.z = (bool)(*p_args[i]);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ argv[i].l = obj;
+ to_free.push_back(obj);
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BYTE: {
+ jclass bclass = env->FindClass("java/lang/Byte");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(B)V");
+ jvalue val;
+ val.b = (int)(*p_args[i]);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ argv[i].l = obj;
+ to_free.push_back(obj);
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_CHAR: {
+ jclass bclass = env->FindClass("java/lang/Character");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(C)V");
+ jvalue val;
+ val.c = (int)(*p_args[i]);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ argv[i].l = obj;
+ to_free.push_back(obj);
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_SHORT: {
+ jclass bclass = env->FindClass("java/lang/Short");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(S)V");
+ jvalue val;
+ val.s = (int)(*p_args[i]);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ argv[i].l = obj;
+ to_free.push_back(obj);
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_INT: {
+ jclass bclass = env->FindClass("java/lang/Integer");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
+ jvalue val;
+ val.i = (int)(*p_args[i]);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ argv[i].l = obj;
+ to_free.push_back(obj);
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_LONG: {
+ jclass bclass = env->FindClass("java/lang/Long");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(J)V");
+ jvalue val;
+ val.j = (int64_t)(*p_args[i]);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ argv[i].l = obj;
+ to_free.push_back(obj);
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_FLOAT: {
+ jclass bclass = env->FindClass("java/lang/Float");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(F)V");
+ jvalue val;
+ val.f = (float)(*p_args[i]);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ argv[i].l = obj;
+ to_free.push_back(obj);
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_TYPE_DOUBLE: {
+ jclass bclass = env->FindClass("java/lang/Double");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
+ jvalue val;
+ val.d = (double)(*p_args[i]);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ argv[i].l = obj;
+ to_free.push_back(obj);
+ } break;
+ case ARG_TYPE_STRING: {
+ String s = *p_args[i];
+ jstring jStr = env->NewStringUTF(s.utf8().get_data());
+ argv[i].l=jStr;
+ to_free.push_back(jStr);
+ } break;
+ case ARG_TYPE_CLASS: {
+
+ Ref<JavaObject> jo=*p_args[i];
+ if (jo.is_valid()) {
+
+ argv[i].l=jo->instance;
+ } else {
+ argv[i].l=NULL; //I hope this works
+ }
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_BOOLEAN: {
+
+ Array arr = *p_args[i];
+ jbooleanArray a = env->NewBooleanArray(arr.size());
+ for(int j=0;j<arr.size();j++) {
+ jboolean val = arr[j];
+ env->SetBooleanArrayRegion(a,j,1,&val);
+ }
+ argv[i].l=a;
+ to_free.push_back(a);
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_BYTE: {
+
+ Array arr = *p_args[i];
+ jbyteArray a = env->NewByteArray(arr.size());
+ for(int j=0;j<arr.size();j++) {
+ jbyte val = arr[j];
+ env->SetByteArrayRegion(a,j,1,&val);
+ }
+ argv[i].l=a;
+ to_free.push_back(a);
+
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_CHAR: {
+
+ Array arr = *p_args[i];
+ jcharArray a = env->NewCharArray(arr.size());
+ for(int j=0;j<arr.size();j++) {
+ jchar val = arr[j];
+ env->SetCharArrayRegion(a,j,1,&val);
+ }
+ argv[i].l=a;
+ to_free.push_back(a);
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_SHORT: {
+
+ Array arr = *p_args[i];
+ jshortArray a = env->NewShortArray(arr.size());
+ for(int j=0;j<arr.size();j++) {
+ jshort val = arr[j];
+ env->SetShortArrayRegion(a,j,1,&val);
+ }
+ argv[i].l=a;
+ to_free.push_back(a);
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_INT: {
+
+ Array arr = *p_args[i];
+ jintArray a = env->NewIntArray(arr.size());
+ for(int j=0;j<arr.size();j++) {
+ jint val = arr[j];
+ env->SetIntArrayRegion(a,j,1,&val);
+ }
+ argv[i].l=a;
+ to_free.push_back(a);
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_LONG: {
+ Array arr = *p_args[i];
+ jlongArray a = env->NewLongArray(arr.size());
+ for(int j=0;j<arr.size();j++) {
+ jlong val = arr[j];
+ env->SetLongArrayRegion(a,j,1,&val);
+ }
+ argv[i].l=a;
+ to_free.push_back(a);
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_FLOAT: {
+
+ Array arr = *p_args[i];
+ jfloatArray a = env->NewFloatArray(arr.size());
+ for(int j=0;j<arr.size();j++) {
+ jfloat val = arr[j];
+ env->SetFloatArrayRegion(a,j,1,&val);
+ }
+ argv[i].l=a;
+ to_free.push_back(a);
+
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_DOUBLE: {
+
+ Array arr = *p_args[i];
+ jdoubleArray a = env->NewDoubleArray(arr.size());
+ for(int j=0;j<arr.size();j++) {
+ jdouble val = arr[j];
+ env->SetDoubleArrayRegion(a,j,1,&val);
+ }
+ argv[i].l=a;
+ to_free.push_back(a);
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_STRING: {
+
+ Array arr = *p_args[i];
+ jobjectArray a = env->NewObjectArray(arr.size(),env->FindClass("java/lang/String"),NULL);
+ for(int j=0;j<arr.size();j++) {
+
+ String s = arr[j];
+ jstring jStr = env->NewStringUTF(s.utf8().get_data());
+ env->SetObjectArrayElement(a,j,jStr);
+ to_free.push_back(jStr);
+ }
+
+ argv[i].l=a;
+ to_free.push_back(a);
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_CLASS: {
+
+ argv[i].l=NULL;
+ } break;
+ }
+ }
+
+ r_error.error=Variant::CallError::CALL_OK;
+ bool success=true;
+
+ switch(method->return_type) {
+
+
+ case ARG_TYPE_VOID: {
+ if (method->_static) {
+ env->CallStaticVoidMethodA(_class,method->method,argv);
+ } else {
+ env->CallVoidMethodA(p_instance->instance,method->method,argv);
+ }
+ ret=Variant();
+
+ } break;
+ case ARG_TYPE_BOOLEAN: {
+ if (method->_static) {
+ ret=env->CallStaticBooleanMethodA(_class,method->method,argv);
+ } else {
+ ret=env->CallBooleanMethodA(p_instance->instance,method->method,argv);
+ }
+ } break;
+ case ARG_TYPE_BYTE: {
+ if (method->_static) {
+ ret=env->CallStaticByteMethodA(_class,method->method,argv);
+ } else {
+ ret=env->CallByteMethodA(p_instance->instance,method->method,argv);
+ }
+ } break;
+ case ARG_TYPE_CHAR: {
+
+ if (method->_static) {
+ ret=env->CallStaticCharMethodA(_class,method->method,argv);
+ } else {
+ ret=env->CallCharMethodA(p_instance->instance,method->method,argv);
+ }
+ } break;
+ case ARG_TYPE_SHORT: {
+
+ if (method->_static) {
+ ret=env->CallStaticShortMethodA(_class,method->method,argv);
+ } else {
+ ret=env->CallShortMethodA(p_instance->instance,method->method,argv);
+ }
+
+ } break;
+ case ARG_TYPE_INT: {
+
+ if (method->_static) {
+ ret=env->CallStaticIntMethodA(_class,method->method,argv);
+ } else {
+ ret=env->CallIntMethodA(p_instance->instance,method->method,argv);
+ }
+
+ } break;
+ case ARG_TYPE_LONG: {
+
+ if (method->_static) {
+ ret=env->CallStaticLongMethodA(_class,method->method,argv);
+ } else {
+ ret=env->CallLongMethodA(p_instance->instance,method->method,argv);
+ }
+
+ } break;
+ case ARG_TYPE_FLOAT: {
+
+ if (method->_static) {
+ ret=env->CallStaticFloatMethodA(_class,method->method,argv);
+ } else {
+ ret=env->CallFloatMethodA(p_instance->instance,method->method,argv);
+ }
+
+ } break;
+ case ARG_TYPE_DOUBLE: {
+
+ if (method->_static) {
+ ret=env->CallStaticDoubleMethodA(_class,method->method,argv);
+ } else {
+ ret=env->CallDoubleMethodA(p_instance->instance,method->method,argv);
+ }
+
+ } break;
+ default: {
+
+ jobject obj;
+ if (method->_static) {
+ obj=env->CallStaticObjectMethodA(_class,method->method,argv);
+ } else {
+ obj=env->CallObjectMethodA(p_instance->instance,method->method,argv);
+ }
+
+ if (!obj) {
+ ret=Variant();
+ } else {
+
+ if (!_convert_object_to_variant(env, obj, ret,method->return_type)) {
+ ret=Variant();
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ success=false;
+ }
+ env->DeleteLocalRef(obj);
+ }
+
+ } break;
+
+ }
+
+ for(List<jobject>::Element *E=to_free.front();E;E=E->next()) {
+ env->DeleteLocalRef(E->get());
+ }
+
+ return success;
+}
+
+Variant JavaClass::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
+
+ Variant ret;
+ bool found = _call_method(NULL,p_method,p_args,p_argcount,r_error,ret);
+ if (found) {
+ return ret;
+ }
+
+ return Reference::call(p_method,p_args,p_argcount,r_error);
+}
+
+JavaClass::JavaClass() {
+
+
+}
+
+/////////////////////
+
+Variant JavaObject::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error){
+
+
+ return Variant();
+}
+
+JavaObject::JavaObject(const Ref<JavaClass>& p_base,jobject *p_instance) {
+
+
+}
+
+JavaObject::~JavaObject(){
+
+
+}
+
+
+////////////////////
+
+void JavaClassWrapper::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("wrap:JavaClass","name"),&JavaClassWrapper::wrap);
+}
+
+
+bool JavaClassWrapper::_get_type_sig(JNIEnv *env,jobject obj,uint32_t& sig,String&strsig) {
+
+ jstring name2 = (jstring)env->CallObjectMethod(obj, Class_getName);
+ String str_type = env->GetStringUTFChars( name2, NULL );
+ print_line("name: "+str_type);
+ env->DeleteLocalRef(name2);
+ uint32_t t=0;
+
+ if (str_type.begins_with("[")) {
+
+ t=JavaClass::ARG_ARRAY_BIT;
+ strsig="[";
+ str_type=str_type.substr(1,str_type.length()-1);
+ if (str_type.begins_with("[")) {
+ print_line("Nested arrays not supported for type: "+str_type);
+ return false;
+ }
+ if (str_type.begins_with("L")) {
+ str_type=str_type.substr(1,str_type.length()-2); //ok it's a class
+ }
+ }
+
+ if (str_type=="void" || str_type=="V") {
+ t|=JavaClass::ARG_TYPE_VOID;
+ strsig+="V";
+ } else if (str_type=="boolean" || str_type=="Z") {
+ t|=JavaClass::ARG_TYPE_BOOLEAN;
+ strsig+="Z";
+ } else if (str_type=="byte" || str_type=="B") {
+ t|=JavaClass::ARG_TYPE_BYTE;
+ strsig+="B";
+ } else if (str_type=="char" || str_type=="C") {
+ t|=JavaClass::ARG_TYPE_CHAR;
+ strsig+="C";
+ } else if (str_type=="short" || str_type=="S") {
+ t|=JavaClass::ARG_TYPE_SHORT;
+ strsig+="S";
+ } else if (str_type=="int" || str_type=="I") {
+ t|=JavaClass::ARG_TYPE_INT;
+ strsig+="I";
+ } else if (str_type=="long" || str_type=="J") {
+ t|=JavaClass::ARG_TYPE_LONG;
+ strsig+="J";
+ } else if (str_type=="float" || str_type=="F") {
+ t|=JavaClass::ARG_TYPE_FLOAT;
+ strsig+="F";
+ } else if (str_type=="double" || str_type=="D") {
+ t|=JavaClass::ARG_TYPE_DOUBLE;
+ strsig+="D";
+ } else if (str_type=="java.lang.String") {
+ t|=JavaClass::ARG_TYPE_STRING;
+ strsig+="Ljava/lang/String;";
+ } else if (str_type=="java.lang.Boolean") {
+ t|=JavaClass::ARG_TYPE_BOOLEAN|JavaClass::ARG_NUMBER_CLASS_BIT;
+ strsig+="Ljava/lang/Boolean;";
+ } else if (str_type=="java.lang.Byte") {
+ t|=JavaClass::ARG_TYPE_BYTE|JavaClass::ARG_NUMBER_CLASS_BIT;
+ strsig+="Ljava/lang/Byte;";
+ } else if (str_type=="java.lang.Character") {
+ t|=JavaClass::ARG_TYPE_CHAR|JavaClass::ARG_NUMBER_CLASS_BIT;
+ strsig+="Ljava/lang/Character;";
+ } else if (str_type=="java.lang.Short") {
+ t|=JavaClass::ARG_TYPE_SHORT|JavaClass::ARG_NUMBER_CLASS_BIT;
+ strsig+="Ljava/lang/Short;";
+ } else if (str_type=="java.lang.Integer") {
+ t|=JavaClass::ARG_TYPE_INT|JavaClass::ARG_NUMBER_CLASS_BIT;
+ strsig+="Ljava/lang/Integer;";
+ } else if (str_type=="java.lang.Long") {
+ t|=JavaClass::ARG_TYPE_LONG|JavaClass::ARG_NUMBER_CLASS_BIT;
+ strsig+="Ljava/lang/Long;";
+ } else if (str_type=="java.lang.Float") {
+ t|=JavaClass::ARG_TYPE_FLOAT|JavaClass::ARG_NUMBER_CLASS_BIT;
+ strsig+="Ljava/lang/Float;";
+ } else if (str_type=="java.lang.Double") {
+ t|=JavaClass::ARG_TYPE_DOUBLE|JavaClass::ARG_NUMBER_CLASS_BIT;
+ strsig+="Ljava/lang/Double;";
+ } else {
+ //a class likely
+ strsig+="L"+str_type.replace(".","/")+";";
+ t|=JavaClass::ARG_TYPE_CLASS;
+ }
+
+ sig=t;
+
+
+ return true;
+
+}
+
+bool JavaClass::_convert_object_to_variant(JNIEnv * env, jobject obj, Variant& var,uint32_t p_sig) {
+
+ if (!obj) {
+ var=Variant(); //seems null is just null...
+ return true;
+ }
+
+
+ switch(p_sig) {
+
+ case ARG_TYPE_VOID: {
+
+ return Variant();
+ } break;
+ case ARG_TYPE_BOOLEAN|ARG_NUMBER_CLASS_BIT: {
+
+ var = env->CallBooleanMethod(obj, JavaClassWrapper::singleton->Boolean_booleanValue);
+ return true;
+ } break;
+ case ARG_TYPE_BYTE|ARG_NUMBER_CLASS_BIT: {
+
+ var = env->CallByteMethod(obj, JavaClassWrapper::singleton->Byte_byteValue);
+ return true;
+
+ } break;
+ case ARG_TYPE_CHAR|ARG_NUMBER_CLASS_BIT: {
+
+ var = env->CallCharMethod(obj, JavaClassWrapper::singleton->Character_characterValue);
+ return true;
+
+ } break;
+ case ARG_TYPE_SHORT|ARG_NUMBER_CLASS_BIT: {
+
+ var = env->CallShortMethod(obj, JavaClassWrapper::singleton->Short_shortValue);
+ return true;
+
+ } break;
+ case ARG_TYPE_INT|ARG_NUMBER_CLASS_BIT: {
+
+ var = env->CallIntMethod(obj, JavaClassWrapper::singleton->Integer_integerValue);
+ return true;
+
+ } break;
+ case ARG_TYPE_LONG|ARG_NUMBER_CLASS_BIT: {
+
+ var = env->CallLongMethod(obj, JavaClassWrapper::singleton->Long_longValue);
+ return true;
+
+ } break;
+ case ARG_TYPE_FLOAT|ARG_NUMBER_CLASS_BIT: {
+
+ var = env->CallFloatMethod(obj, JavaClassWrapper::singleton->Float_floatValue);
+ return true;
+
+ } break;
+ case ARG_TYPE_DOUBLE|ARG_NUMBER_CLASS_BIT: {
+
+ var = env->CallDoubleMethod(obj, JavaClassWrapper::singleton->Double_doubleValue);
+ return true;
+ } break;
+ case ARG_TYPE_STRING: {
+
+ var = String::utf8(env->GetStringUTFChars( (jstring)obj, NULL ));
+ return true;
+ } break;
+ case ARG_TYPE_CLASS: {
+
+ return false;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_VOID: {
+
+ var = Array(); // ?
+ return true;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_BOOLEAN: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jboolean val;
+ env->GetBooleanArrayRegion((jbooleanArray)arr,0,1,&val);
+ ret.push_back(val);
+ }
+
+ var=ret;
+ return true;
+
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_BYTE: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jbyte val;
+ env->GetByteArrayRegion((jbyteArray)arr,0,1,&val);
+ ret.push_back(val);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_CHAR: {
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jchar val;
+ env->GetCharArrayRegion((jcharArray)arr,0,1,&val);
+ ret.push_back(val);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_SHORT: {
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jshort val;
+ env->GetShortArrayRegion((jshortArray)arr,0,1,&val);
+ ret.push_back(val);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_INT: {
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jint val;
+ env->GetIntArrayRegion((jintArray)arr,0,1,&val);
+ ret.push_back(val);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_LONG: {
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jlong val;
+ env->GetLongArrayRegion((jlongArray)arr,0,1,&val);
+ ret.push_back(val);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_FLOAT: {
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jfloat val;
+ env->GetFloatArrayRegion((jfloatArray)arr,0,1,&val);
+ ret.push_back(val);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_DOUBLE: {
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jdouble val;
+ env->GetDoubleArrayRegion((jdoubleArray)arr,0,1,&val);
+ ret.push_back(val);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_ARRAY_BIT|ARG_TYPE_BOOLEAN: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ bool val = env->CallBooleanMethod(o, JavaClassWrapper::singleton->Boolean_booleanValue);
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_ARRAY_BIT|ARG_TYPE_BYTE: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ int val = env->CallByteMethod(o, JavaClassWrapper::singleton->Byte_byteValue);
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_ARRAY_BIT|ARG_TYPE_CHAR: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ int val = env->CallCharMethod(o, JavaClassWrapper::singleton->Character_characterValue);
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_ARRAY_BIT|ARG_TYPE_SHORT: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ int val = env->CallShortMethod(o, JavaClassWrapper::singleton->Short_shortValue);
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_ARRAY_BIT|ARG_TYPE_INT: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ int val = env->CallIntMethod(o, JavaClassWrapper::singleton->Integer_integerValue);
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_ARRAY_BIT|ARG_TYPE_LONG: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ int64_t val = env->CallLongMethod(o, JavaClassWrapper::singleton->Long_longValue);
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_ARRAY_BIT|ARG_TYPE_FLOAT: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ float val = env->CallFloatMethod(o, JavaClassWrapper::singleton->Float_floatValue);
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_NUMBER_CLASS_BIT|ARG_ARRAY_BIT|ARG_TYPE_DOUBLE: {
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ double val = env->CallDoubleMethod(o, JavaClassWrapper::singleton->Double_doubleValue);
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+ } break;
+
+ case ARG_ARRAY_BIT|ARG_TYPE_STRING: {
+
+ Array ret;
+ jobjectArray arr = (jobjectArray)obj;
+
+ int count = env->GetArrayLength(arr);
+
+ for (int i=0; i<count; i++) {
+
+ jobject o = env->GetObjectArrayElement(arr, i);
+ if (!o)
+ ret.push_back(Variant());
+ else {
+ String val = String::utf8(env->GetStringUTFChars( (jstring)o, NULL ));
+ ret.push_back(val);
+
+ }
+ env->DeleteLocalRef(o);
+ }
+
+ var=ret;
+ return true;
+ } break;
+ case ARG_ARRAY_BIT|ARG_TYPE_CLASS: {
+
+ } break;
+ }
+
+ return false;
+
+}
+
+
+Ref<JavaClass> JavaClassWrapper::wrap(const String& p_class) {
+
+ if (class_cache.has(p_class))
+ return class_cache[p_class];
+
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jclass bclass = env->FindClass(p_class.utf8().get_data());
+ ERR_FAIL_COND_V(!bclass,Ref<JavaClass>());
+
+ //jmethodID getDeclaredMethods = env->GetMethodID(bclass,"getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
+
+ //ERR_FAIL_COND_V(!getDeclaredMethods,Ref<JavaClass>());
+
+ jobjectArray methods = (jobjectArray)env->CallObjectMethod(bclass, getDeclaredMethods);
+
+ ERR_FAIL_COND_V(!methods,Ref<JavaClass>());
+
+
+ Ref<JavaClass> java_class = memnew( JavaClass );
+
+ int count = env->GetArrayLength(methods);
+
+ for (int i=0; i<count; i++) {
+
+ jobject obj = env->GetObjectArrayElement(methods, i);
+ ERR_CONTINUE(!obj);
+
+
+ jstring name = (jstring)env->CallObjectMethod(obj, getName);
+ String str_method = env->GetStringUTFChars( name, NULL );
+ env->DeleteLocalRef(name);
+
+ Vector<String> params;
+
+ jint mods = env->CallIntMethod(obj,getModifiers);
+
+ if (!(mods&0x0001)) {
+ env->DeleteLocalRef(obj);
+ continue; //not public bye
+ }
+
+
+
+ jobjectArray param_types = (jobjectArray)env->CallObjectMethod(obj, getParameterTypes);
+ int count2=env->GetArrayLength(param_types);
+
+ if (!java_class->methods.has(str_method)) {
+ java_class->methods[str_method]=List<JavaClass::MethodInfo>();
+ }
+
+ JavaClass::MethodInfo mi;
+ mi._static = (mods&0x8)!=0;
+ bool valid=true;
+ String signature="(";
+
+ for(int j=0;j<count2;j++) {
+
+ jobject obj2 = env->GetObjectArrayElement(param_types, j);
+ String strsig;
+ uint32_t sig=0;
+ if (!_get_type_sig(env,obj2,sig,strsig)) {
+ valid=false;
+ env->DeleteLocalRef(obj2);
+ break;
+ }
+ signature+=strsig;
+ mi.param_types.push_back(sig);
+ mi.param_sigs.push_back(strsig);
+ env->DeleteLocalRef(obj2);
+
+ }
+
+ if (!valid) {
+ print_line("Method Can't be bound (unsupported arguments): "+p_class+"::"+str_method);
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(param_types);
+ continue;
+ }
+
+ signature+=")";
+
+ jobject return_type = (jobject)env->CallObjectMethod(obj, getReturnType);
+
+
+ String strsig;
+ uint32_t sig=0;
+ if (!_get_type_sig(env,return_type,sig,strsig)) {
+ print_line("Method Can't be bound (unsupported return type): "+p_class+"::"+str_method);
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(param_types);
+ env->DeleteLocalRef(return_type);
+ continue;
+ }
+
+ signature+=strsig;
+ mi.return_type=sig;
+
+ print_line("METHOD: "+str_method+" SIG: "+signature+" static: "+itos(mi._static));
+
+ bool discard=false;
+
+ for(List<JavaClass::MethodInfo>::Element *E=java_class->methods[str_method].front();E;E=E->next()) {
+
+ float new_likeliness=0;
+ float existing_likeliness=0;
+
+ if (E->get().param_types.size()!=mi.param_types.size())
+ continue;
+ bool valid=true;
+ for(int j=0;j<E->get().param_types.size();j++) {
+
+ Variant::Type _new;
+ float new_l;
+ Variant::Type existing;
+ float existing_l;
+ JavaClass::_convert_to_variant_type(E->get().param_types[j],existing,existing_l);
+ JavaClass::_convert_to_variant_type(mi.param_types[j],_new,new_l);
+ if (_new!=existing) {
+ valid=false;
+ break;
+ }
+ new_likeliness+=new_l;
+ existing_likeliness=existing_l;
+
+ }
+
+ if (!valid)
+ continue;
+
+ if (new_likeliness>existing_likeliness) {
+ java_class->methods[str_method].erase(E);
+ print_line("replace old");
+ break;
+ } else {
+ discard=true;
+ print_line("old is better");
+ }
+
+
+ }
+
+ if (!discard) {
+ if (mi._static)
+ mi.method = env->GetStaticMethodID(bclass, str_method.utf8().get_data(), signature.utf8().get_data());
+ else
+ mi.method = env->GetMethodID(bclass, str_method.utf8().get_data(), signature.utf8().get_data());
+
+ ERR_CONTINUE(!mi.method);
+
+ java_class->methods[str_method].push_back(mi);
+ }
+
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(param_types);
+ env->DeleteLocalRef(return_type);
+
+
+
+
+ //args[i] = _jobject_to_variant(env, obj);
+// print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type()));
+
+ };
+
+ env->DeleteLocalRef(methods);
+
+ jobjectArray fields = (jobjectArray)env->CallObjectMethod(bclass, getFields);
+
+ count = env->GetArrayLength(fields);
+
+ for (int i=0; i<count; i++) {
+
+ jobject obj = env->GetObjectArrayElement(fields, i);
+ ERR_CONTINUE(!obj);
+
+ jstring name = (jstring)env->CallObjectMethod(obj, Field_getName);
+ String str_field = env->GetStringUTFChars( name, NULL );
+ env->DeleteLocalRef(name);
+ print_line("FIELD: "+str_field);
+ int mods = env->CallIntMethod(obj,Field_getModifiers);
+ if ((mods&0x8) && (mods&0x10) && (mods&0x1)) { //static final public!
+
+ jobject objc = env->CallObjectMethod(obj, Field_get,NULL);
+ if (objc) {
+
+
+ uint32_t sig;
+ String strsig;
+ jclass cl = env->GetObjectClass(objc);
+ if (JavaClassWrapper::_get_type_sig(env,cl,sig,strsig)) {
+
+ if ((sig&JavaClass::ARG_TYPE_MASK)<=JavaClass::ARG_TYPE_STRING) {
+
+ Variant value;
+ if (JavaClass::_convert_object_to_variant(env,objc,value,sig)) {
+
+ java_class->constant_map[str_field]=value;
+ }
+ }
+ }
+
+ env->DeleteLocalRef(cl);
+ }
+
+
+ env->DeleteLocalRef(objc);
+
+ }
+ env->DeleteLocalRef(obj);
+ }
+
+ env->DeleteLocalRef(fields);
+
+
+ return Ref<JavaClass>();
+}
+
+JavaClassWrapper *JavaClassWrapper::singleton=NULL;
+
+JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
+
+ singleton=this;
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jclass activityClass = env->FindClass("com/android/godot/Godot");
+ jmethodID getClassLoader = env->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");
+ classLoader = env->CallObjectMethod(p_activity, getClassLoader);
+ classLoader=(jclass)env->NewGlobalRef(classLoader);
+ jclass classLoaderClass = env->FindClass("java/lang/ClassLoader");
+ findClass = env->GetMethodID(classLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
+ jclass bclass = env->FindClass("java/lang/Class");
+ getDeclaredMethods = env->GetMethodID(bclass,"getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
+ getFields = env->GetMethodID(bclass,"getFields", "()[Ljava/lang/reflect/Field;");
+ Class_getName = env->GetMethodID(bclass,"getName", "()Ljava/lang/String;");
+ //
+ bclass = env->FindClass("java/lang/reflect/Method");
+ getParameterTypes = env->GetMethodID(bclass,"getParameterTypes", "()[Ljava/lang/Class;");
+ getReturnType = env->GetMethodID(bclass,"getReturnType", "()Ljava/lang/Class;");
+ getName = env->GetMethodID(bclass,"getName", "()Ljava/lang/String;");
+ getModifiers = env->GetMethodID(bclass,"getModifiers", "()I");
+ ///
+ bclass = env->FindClass("java/lang/reflect/Field");
+ Field_getName = env->GetMethodID(bclass,"getName", "()Ljava/lang/String;");
+ Field_getModifiers = env->GetMethodID(bclass,"getModifiers", "()I");
+ Field_get = env->GetMethodID(bclass,"get", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ // each
+ bclass = env->FindClass("java/lang/Boolean");
+ Boolean_booleanValue = env->GetMethodID(bclass, "booleanValue", "()Z");
+
+ bclass = env->FindClass("java/lang/Byte");
+ Byte_byteValue = env->GetMethodID(bclass, "byteValue", "()B");
+
+ bclass = env->FindClass("java/lang/Character");
+ Character_characterValue = env->GetMethodID(bclass, "charValue", "()C");
+
+ bclass = env->FindClass("java/lang/Short");
+ Short_shortValue = env->GetMethodID(bclass, "shortValue", "()S");
+
+ bclass = env->FindClass("java/lang/Integer");
+ Integer_integerValue = env->GetMethodID(bclass, "intValue", "()I");
+
+ bclass = env->FindClass("java/lang/Long");
+ Long_longValue = env->GetMethodID(bclass, "longValue", "()J");
+
+ bclass = env->FindClass("java/lang/Float");
+ Float_floatValue = env->GetMethodID(bclass, "floatValue", "()F");
+
+ bclass = env->FindClass("java/lang/Double");
+ Double_doubleValue = env->GetMethodID(bclass, "doubleValue", "()D");
+
+
+}
diff --git a/platform/android/java_class_wrapper.h b/platform/android/java_class_wrapper.h
new file mode 100644
index 0000000000..d5d8bd5be8
--- /dev/null
+++ b/platform/android/java_class_wrapper.h
@@ -0,0 +1,168 @@
+#ifndef JAVA_CLASS_WRAPPER_H
+#define JAVA_CLASS_WRAPPER_H
+
+#include "reference.h"
+#include <jni.h>
+#include <android/log.h>
+
+class JavaObject;
+
+class JavaClass : public Reference {
+
+ OBJ_TYPE(JavaClass,Reference);
+
+ enum ArgumentType {
+
+ ARG_TYPE_VOID,
+ ARG_TYPE_BOOLEAN,
+ ARG_TYPE_BYTE,
+ ARG_TYPE_CHAR,
+ ARG_TYPE_SHORT,
+ ARG_TYPE_INT,
+ ARG_TYPE_LONG,
+ ARG_TYPE_FLOAT,
+ ARG_TYPE_DOUBLE,
+ ARG_TYPE_STRING, //special case
+ ARG_TYPE_CLASS,
+ ARG_ARRAY_BIT=1<<16,
+ ARG_NUMBER_CLASS_BIT=1<<17,
+ ARG_TYPE_MASK=(1<<16)-1
+ };
+
+
+ Map<StringName,Variant> constant_map;
+
+ struct MethodInfo {
+
+ bool _static;
+ Vector<uint32_t> param_types;
+ Vector<StringName> param_sigs;
+ uint32_t return_type;
+ jmethodID method;
+
+ };
+
+ _FORCE_INLINE_ static void _convert_to_variant_type(int p_sig, Variant::Type& r_type, float& likelyhood) {
+
+ likelyhood=1.0;
+ r_type=Variant::NIL;
+
+ switch(p_sig) {
+
+ case ARG_TYPE_VOID: r_type=Variant::NIL; break;
+ case ARG_TYPE_BOOLEAN|ARG_NUMBER_CLASS_BIT:
+ case ARG_TYPE_BOOLEAN: r_type=Variant::BOOL; break;
+ case ARG_TYPE_BYTE|ARG_NUMBER_CLASS_BIT:
+ case ARG_TYPE_BYTE: r_type=Variant::INT; likelyhood=0.1; break;
+ case ARG_TYPE_CHAR|ARG_NUMBER_CLASS_BIT:
+ case ARG_TYPE_CHAR: r_type=Variant::INT; likelyhood=0.2; break;
+ case ARG_TYPE_SHORT|ARG_NUMBER_CLASS_BIT:
+ case ARG_TYPE_SHORT: r_type=Variant::INT; likelyhood=0.3; break;
+ case ARG_TYPE_INT|ARG_NUMBER_CLASS_BIT:
+ case ARG_TYPE_INT: r_type=Variant::INT; likelyhood=1.0; break;
+ case ARG_TYPE_LONG|ARG_NUMBER_CLASS_BIT:
+ case ARG_TYPE_LONG: r_type=Variant::INT; likelyhood=0.5; break;
+ case ARG_TYPE_FLOAT|ARG_NUMBER_CLASS_BIT:
+ case ARG_TYPE_FLOAT: r_type=Variant::REAL; likelyhood=1.0; break;
+ case ARG_TYPE_DOUBLE|ARG_NUMBER_CLASS_BIT:
+ case ARG_TYPE_DOUBLE: r_type=Variant::REAL; likelyhood=0.5; break;
+ case ARG_TYPE_STRING: r_type=Variant::STRING; break;
+ case ARG_TYPE_CLASS: r_type=Variant::OBJECT; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_VOID: r_type=Variant::NIL; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_BOOLEAN: r_type=Variant::ARRAY; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_BYTE: r_type=Variant::RAW_ARRAY; likelyhood=1.0; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_CHAR: r_type=Variant::RAW_ARRAY; likelyhood=0.5; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_SHORT: r_type=Variant::INT_ARRAY; likelyhood=0.3; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_INT: r_type=Variant::INT_ARRAY; likelyhood=1.0; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_LONG: r_type=Variant::INT_ARRAY; likelyhood=0.5; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_FLOAT: r_type=Variant::REAL_ARRAY; likelyhood=1.0; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_DOUBLE: r_type=Variant::REAL_ARRAY; likelyhood=0.5; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_STRING: r_type=Variant::STRING_ARRAY; break;
+ case ARG_ARRAY_BIT|ARG_TYPE_CLASS: r_type=Variant::ARRAY; break;
+ }
+ }
+
+ _FORCE_INLINE_ static bool _convert_object_to_variant(JNIEnv * env, jobject obj, Variant& var,uint32_t p_sig);
+
+
+
+ bool _call_method(JavaObject* p_instance,const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error,Variant& ret);
+
+friend class JavaClassWrapper;
+ Map<StringName,List<MethodInfo> > methods;
+ jclass _class;
+
+public:
+
+ virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error);
+
+ JavaClass();
+
+};
+
+
+class JavaObject : public Reference {
+
+ OBJ_TYPE(JavaObject,Reference);
+
+ Ref<JavaClass> base_class;
+friend class JavaClass;
+
+ jobject instance;
+
+public:
+
+ virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error);
+
+ JavaObject(const Ref<JavaClass>& p_base,jobject *p_instance);
+ ~JavaObject();
+
+};
+
+
+class JavaClassWrapper : public Object {
+
+ OBJ_TYPE(JavaClassWrapper,Object);
+
+
+ Map<String,Ref<JavaClass> > class_cache;
+friend class JavaClass;
+ jclass activityClass;
+ jmethodID findClass;
+ jmethodID getDeclaredMethods;
+ jmethodID getFields;
+ jmethodID getParameterTypes;
+ jmethodID getReturnType;
+ jmethodID getModifiers;
+ jmethodID getName;
+ jmethodID Class_getName;
+ jmethodID Field_getName;
+ jmethodID Field_getModifiers;
+ jmethodID Field_get;
+ jmethodID Boolean_booleanValue;
+ jmethodID Byte_byteValue;
+ jmethodID Character_characterValue;
+ jmethodID Short_shortValue;
+ jmethodID Integer_integerValue;
+ jmethodID Long_longValue;
+ jmethodID Float_floatValue;
+ jmethodID Double_doubleValue;
+ jobject classLoader;
+
+ bool _get_type_sig(JNIEnv *env, jobject obj, uint32_t& sig, String&strsig);
+
+ static JavaClassWrapper *singleton;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ static JavaClassWrapper *get_singleton() { return singleton; }
+
+ Ref<JavaClass> wrap(const String& p_class);
+
+ JavaClassWrapper(jobject p_activity=NULL);
+};
+
+#endif // JAVA_CLASS_WRAPPER_H
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index e67388b6f5..2cc74c3bb0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,18 +33,31 @@
#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;
-jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_arg, bool force_jobject = false) {
+struct jvalret {
- jvalue v;
+ jobject obj;
+ jvalue val;
+ jvalret() { obj=NULL; }
+
+
+};
+
+jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_arg, bool force_jobject = false) {
+
+ jvalret v;
switch(p_type) {
@@ -56,9 +69,12 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
jvalue val;
val.z = (bool)(*p_arg);
jobject obj = env->NewObjectA(bclass, ctor, &val);
- v.l = obj;
+ v.val.l = obj;
+ v.obj=obj;
+ env->DeleteLocalRef(bclass);
} else {
- v.z=*p_arg;
+ v.val.z=*p_arg;
+
};
} break;
case Variant::INT: {
@@ -70,10 +86,13 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
jvalue val;
val.i = (int)(*p_arg);
jobject obj = env->NewObjectA(bclass, ctor, &val);
- v.l = obj;
+ v.val.l = obj;
+ v.obj=obj;
+ env->DeleteLocalRef(bclass);
} else {
- v.i=*p_arg;
+ v.val.i=*p_arg;
+
};
} break;
case Variant::REAL: {
@@ -85,17 +104,20 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
jvalue val;
val.d = (double)(*p_arg);
jobject obj = env->NewObjectA(bclass, ctor, &val);
- v.l = obj;
+ v.val.l = obj;
+ v.obj=obj;
+ env->DeleteLocalRef(bclass);
} else {
- v.f=*p_arg;
+ v.val.f=*p_arg;
};
} break;
case Variant::STRING: {
String s = *p_arg;
jstring jStr = env->NewStringUTF(s.utf8().get_data());
- v.l=jStr;
+ v.val.l=jStr;
+ v.obj=jStr;
} break;
case Variant::STRING_ARRAY: {
@@ -104,9 +126,12 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
for(int j=0;j<sarray.size();j++) {
- env->SetObjectArrayElement(arr,j,env->NewStringUTF( sarray[j].utf8().get_data() ));
+ jstring str = env->NewStringUTF( sarray[j].utf8().get_data() );
+ env->SetObjectArrayElement(arr,j,str);
+ env->DeleteLocalRef(str);
}
- v.l=arr;
+ v.val.l=arr;
+ v.obj=arr;
} break;
@@ -121,27 +146,36 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
jobjectArray jkeys = env->NewObjectArray(keys.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
for (int j=0; j<keys.size(); j++) {
- env->SetObjectArrayElement(jkeys, j, env->NewStringUTF(String(keys[j]).utf8().get_data()));
+ jstring str = env->NewStringUTF(String(keys[j]).utf8().get_data());
+ env->SetObjectArrayElement(jkeys, j, str);
+ env->DeleteLocalRef(str);
};
jmethodID set_keys = env->GetMethodID(dclass, "set_keys", "([Ljava/lang/String;)V");
jvalue val;
val.l = jkeys;
env->CallVoidMethodA(jdict, set_keys, &val);
+ env->DeleteLocalRef(jkeys);
jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), NULL);
for (int j=0; j<keys.size(); j++) {
Variant var = dict[keys[j]];
- val = _variant_to_jvalue(env, var.get_type(), &var, true);
- env->SetObjectArrayElement(jvalues, j, val.l);
+ jvalret v = _variant_to_jvalue(env, var.get_type(), &var, true);
+ env->SetObjectArrayElement(jvalues, j, v.val.l);
+ if (v.obj) {
+ env->DeleteLocalRef(v.obj);
+ }
};
jmethodID set_values = env->GetMethodID(dclass, "set_values", "([Ljava/lang/Object;)V");
val.l = jvalues;
env->CallVoidMethodA(jdict, set_values, &val);
+ env->DeleteLocalRef(jvalues);
+ env->DeleteLocalRef(dclass);
- v.l = jdict;
+ v.val.l = jdict;
+ v.obj=jdict;
} break;
case Variant::INT_ARRAY: {
@@ -150,7 +184,8 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
jintArray arr = env->NewIntArray(array.size());
DVector<int>::Read r = array.read();
env->SetIntArrayRegion(arr,0,array.size(),r.ptr());
- v.l=arr;
+ v.val.l=arr;
+ v.obj=arr;
} break;
case Variant::RAW_ARRAY: {
@@ -158,7 +193,8 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
jbyteArray arr = env->NewByteArray(array.size());
DVector<uint8_t>::Read r = array.read();
env->SetByteArrayRegion(arr,0,array.size(),reinterpret_cast<const signed char*>(r.ptr()));
- v.l=arr;
+ v.val.l=arr;
+ v.obj=arr;
} break;
case Variant::REAL_ARRAY: {
@@ -167,12 +203,13 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
jfloatArray arr = env->NewFloatArray(array.size());
DVector<float>::Read r = array.read();
env->SetFloatArrayRegion(arr,0,array.size(),r.ptr());
- v.l=arr;
+ v.val.l=arr;
+ v.obj=arr;
} break;
default: {
- v.i = 0;
+ v.val.i = 0;
} break;
}
@@ -190,8 +227,11 @@ String _get_class_name(JNIEnv * env, jclass cls, bool* array) {
jboolean isarr = env->CallBooleanMethod(cls, isArray);
(*array) = isarr ? true : false;
}
+ String name = env->GetStringUTFChars( clsName, NULL );
+ env->DeleteLocalRef(clsName);
+
+ return name;
- return env->GetStringUTFChars( clsName, NULL );
};
@@ -202,6 +242,7 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
String name = _get_class_name(env, c, &array);
//print_line("name is " + name + ", array "+Variant(array));
+ print_line("ARGNAME: "+name);
if (name == "java.lang.String") {
return String::utf8(env->GetStringUTFChars( (jstring)obj, NULL ));
@@ -219,6 +260,8 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
jstring string = (jstring) env->GetObjectArrayElement(arr, i);
const char *rawString = env->GetStringUTFChars(string, 0);
sarr.push_back(String(rawString));
+ env->DeleteLocalRef(string);
+
}
return sarr;
@@ -317,30 +360,34 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
jobjectArray arr = (jobjectArray)obj;
int objCount = env->GetArrayLength(arr);
- Array varr;
+ Array varr(true);
for (int i=0; i<objCount; i++) {
jobject jobj = env->GetObjectArrayElement(arr, i);
Variant v = _jobject_to_variant(env, jobj);
varr.push_back(v);
+ env->DeleteLocalRef(jobj);
+
}
return varr;
};
- if (name == "com.android.godot.Dictionary") {
+ if (name == "java.util.HashMap" || name == "com.android.godot.Dictionary") {
- Dictionary ret;
+ Dictionary ret(true);
jclass oclass = c;
jmethodID get_keys = env->GetMethodID(oclass, "get_keys", "()[Ljava/lang/String;");
jobjectArray arr = (jobjectArray)env->CallObjectMethod(obj, get_keys);
StringArray keys = _jobject_to_variant(env, arr);
+ env->DeleteLocalRef(arr);
jmethodID get_values = env->GetMethodID(oclass, "get_values", "()[Ljava/lang/Object;");
arr = (jobjectArray)env->CallObjectMethod(obj, get_values);
Array vals = _jobject_to_variant(env, arr);
+ env->DeleteLocalRef(arr);
//print_line("adding " + String::num(keys.size()) + " to Dictionary!");
for (int i=0; i<keys.size(); i++) {
@@ -348,9 +395,12 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
ret[keys[i]] = vals[i];
};
+
return ret;
};
+ env->DeleteLocalRef(c);
+
return Variant();
};
@@ -388,6 +438,7 @@ public:
}
+
int ac = E->get().argtypes.size();
if (ac<p_argcount) {
@@ -406,7 +457,6 @@ public:
}
-
for(int i=0;i<p_argcount;i++) {
if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) {
@@ -427,10 +477,18 @@ public:
JNIEnv *env = ThreadAndroid::get_env();
+ int res = env->PushLocalFrame(16);
+
+ ERR_FAIL_COND_V(res!=0,Variant());
+
//print_line("argcount "+String::num(p_argcount));
+ List<jobject> to_erase;
for(int i=0;i<p_argcount;i++) {
- v[i] = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+ jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+ v[i] = vr.val;
+ if (vr.obj)
+ to_erase.push_back(vr.obj);
}
//print_line("calling method!!");
@@ -464,6 +522,7 @@ public:
jobject o = env->CallObjectMethodA(instance,E->get().method,v);
String str = env->GetStringUTFChars((jstring)o, NULL );
ret=str;
+ env->DeleteLocalRef(o);
} break;
case Variant::STRING_ARRAY: {
@@ -471,6 +530,7 @@ public:
ret = _jobject_to_variant(env, arr);
+ env->DeleteLocalRef(arr);
} break;
case Variant::INT_ARRAY: {
@@ -484,6 +544,7 @@ public:
env->GetIntArrayRegion(arr,0,fCount,w.ptr());
w = DVector<int>::Write();
ret=sarr;
+ env->DeleteLocalRef(arr);
} break;
case Variant::REAL_ARRAY: {
@@ -497,6 +558,7 @@ public:
env->GetFloatArrayRegion(arr,0,fCount,w.ptr());
w = DVector<float>::Write();
ret=sarr;
+ env->DeleteLocalRef(arr);
} break;
case Variant::DICTIONARY: {
@@ -504,16 +566,24 @@ public:
//print_line("call dictionary");
jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
ret = _jobject_to_variant(env, obj);
+ env->DeleteLocalRef(obj);
} break;
default: {
print_line("failure..");
+ env->PopLocalFrame(NULL);
ERR_FAIL_V(Variant());
} break;
}
+ while (to_erase.size()) {
+ env->DeleteLocalRef(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+ env->PopLocalFrame(NULL);
//print_line("success");
return ret;
@@ -596,7 +666,7 @@ static jmethodID _showKeyboard=0;
static jmethodID _hideKeyboard=0;
static jmethodID _setScreenOrientation=0;
static jmethodID _getUniqueID=0;
-
+static jmethodID _getSystemDir=0;
static jmethodID _playVideo=0;
static jmethodID _isVideoPlaying=0;
static jmethodID _pauseVideo=0;
@@ -656,6 +726,14 @@ static void _set_screen_orient(int p_orient) {
env->CallVoidMethod(godot_io, _setScreenOrientation, p_orient );
};
+static String _get_system_dir(int p_dir) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getSystemDir,p_dir);
+ return String(env->GetStringUTFChars( s, NULL ));
+};
+
+
static void _hide_vk() {
JNIEnv* env = ThreadAndroid::get_env();
@@ -687,7 +765,7 @@ 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) {
+JNIEXPORT void JNICALL Java_com_android_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);
@@ -735,7 +813,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
_showKeyboard = env->GetMethodID(c,"showKeyboard","(Ljava/lang/String;)V");
_hideKeyboard = env->GetMethodID(c,"hideKeyboard","()V");
_setScreenOrientation = env->GetMethodID(c,"setScreenOrientation","(I)V");
-
+ _getSystemDir = env->GetMethodID(c,"getSystemDir","(I)Ljava/lang/String;");
_playVideo = env->GetMethodID(c,"playVideo","(Ljava/lang/String;)V");
_isVideoPlaying = env->GetMethodID(c,"isVideoPlaying","()Z");
_pauseVideo = env->GetMethodID(c,"pauseVideo","()V");
@@ -743,7 +821,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);
}
@@ -753,7 +838,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
int cmdlen=0;
bool use_apk_expansion=false;
if (p_cmdline) {
- int cmdlen = env->GetArrayLength(p_cmdline);
+ cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
cmdline = (const char**)malloc((env->GetArrayLength(p_cmdline)+1)*sizeof(const char*));
cmdline[cmdlen]=NULL;
@@ -776,7 +861,9 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
}
}
- 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, _play_video, _is_video_playing, _pause_video, _stop_video,use_apk_expansion);
+ __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->set_need_reload_hooks(p_need_reload_hook);
char wd[500];
@@ -808,10 +895,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
String vd = Globals::get_singleton()->get("display/driver");
- if (vd.to_upper()=="GLES1")
- env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean)false);
- else
- env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean)true);
+ env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean)true);
__android_log_print(ANDROID_LOG_INFO,"godot","**START");
@@ -836,14 +920,20 @@ 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_com_android_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();
}
+
}
@@ -861,6 +951,7 @@ static void _initialize_java_modules() {
String modules = Globals::get_singleton()->get("android/modules");
Vector<String> mods = modules.split(",",false);
+ print_line("ANDROID MODULES : " + modules);
__android_log_print(ANDROID_LOG_INFO,"godot","mod count: %i",mods.size());
if (mods.size()) {
@@ -932,6 +1023,8 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobjec
// ugly hack to initialize the rest of the engine
// because of the way android forces you to do everything with threads
+ java_class_wrapper = memnew( JavaClassWrapper(_godot_instance ));
+ Globals::get_singleton()->add_singleton(Globals::Singleton("JavaClassWrapper",java_class_wrapper));
_initialize_java_modules();
Main::setup2();
@@ -1541,45 +1634,63 @@ 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) {
- String str_method = env->GetStringUTFChars( method, NULL );
-
Object* obj = ObjectDB::get_instance(ID);
ERR_FAIL_COND(!obj);
+ int res = env->PushLocalFrame(16);
+ ERR_FAIL_COND(res!=0);
+
+ String str_method = env->GetStringUTFChars( method, NULL );
+
+
int count = env->GetArrayLength(params);
Variant* vlist = (Variant*)alloca(sizeof(Variant) * count);
Variant** vptr = (Variant**)alloca(sizeof(Variant*) * count);
for (int i=0; i<count; i++) {
jobject obj = env->GetObjectArrayElement(params, i);
- Variant v = _jobject_to_variant(env, obj);
+ Variant v;
+ if (obj)
+ v=_jobject_to_variant(env, obj);
memnew_placement(&vlist[i], Variant);
vlist[i] = v;
vptr[i] = &vlist[i];
+ env->DeleteLocalRef(obj);
+
};
Variant::CallError err;
obj->call(str_method, (const Variant**)vptr, count, err);
// something
+
+ env->PopLocalFrame(NULL);
+
};
JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
- String str_method = env->GetStringUTFChars( method, NULL );
Object* obj = ObjectDB::get_instance(ID);
ERR_FAIL_COND(!obj);
+ int res = env->PushLocalFrame(16);
+ ERR_FAIL_COND(res!=0);
+
+ String str_method = env->GetStringUTFChars( method, NULL );
+
int count = env->GetArrayLength(params);
Variant args[VARIANT_ARG_MAX];
- print_line("Java->GD call: "+obj->get_type()+"::"+str_method+" argc "+itos(count));
+ //print_line("Java->GD call: "+obj->get_type()+"::"+str_method+" argc "+itos(count));
for (int i=0; i<MIN(count,VARIANT_ARG_MAX); i++) {
jobject obj = env->GetObjectArrayElement(params, i);
- args[i] = _jobject_to_variant(env, obj);
- print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type()));
+ if (obj)
+ args[i] = _jobject_to_variant(env, obj);
+ env->DeleteLocalRef(obj);
+
+// print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type()));
};
@@ -1587,6 +1698,8 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env
obj->call_deferred(str_method, args[0],args[1],args[2],args[3],args[4]);
// something
+ env->PopLocalFrame(NULL);
+
};
//Main::cleanup();
diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h
index 379718a23e..e22b6775d8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,9 +36,9 @@
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_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline,jobject p_asset_manager);
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_newcontext(JNIEnv * env, jobject obj, bool p_32_bits);
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);
diff --git a/platform/android/libs/downloader_library/.classpath b/platform/android/libs/downloader_library/.classpath
new file mode 100644
index 0000000000..7bc01d9a9c
--- /dev/null
+++ b/platform/android/libs/downloader_library/.classpath
@@ -0,0 +1,9 @@
+<?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
new file mode 100644
index 0000000000..b080d2ddc8
--- /dev/null
+++ b/platform/android/libs/downloader_library/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,4 @@
+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
new file mode 100644
index 0000000000..20b74a2988
--- /dev/null
+++ b/platform/android/libs/downloader_library/AndroidManifest.xml
@@ -0,0 +1,9 @@
+<?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
new file mode 100644
index 0000000000..d65c145148
--- /dev/null
+++ b/platform/android/libs/downloader_library/build.xml
@@ -0,0 +1,92 @@
+<?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/proguard-project.txt b/platform/android/libs/downloader_library/proguard-project.txt
new file mode 100644
index 0000000000..f2fe1559a2
--- /dev/null
+++ b/platform/android/libs/downloader_library/proguard-project.txt
@@ -0,0 +1,20 @@
+# 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
new file mode 100644
index 0000000000..eda83430bf
--- /dev/null
+++ b/platform/android/libs/downloader_library/project.properties
@@ -0,0 +1,13 @@
+# 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
new file mode 100644
index 0000000000..f5b762ecf3
--- /dev/null
+++ b/platform/android/libs/downloader_library/res/drawable-hdpi/notify_panel_notification_icon_bg.png
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
new file mode 100644
index 0000000000..9ecb8af06c
--- /dev/null
+++ b/platform/android/libs/downloader_library/res/drawable-mdpi/notify_panel_notification_icon_bg.png
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
new file mode 100644
index 0000000000..23bac02294
--- /dev/null
+++ b/platform/android/libs/downloader_library/res/layout/status_bar_ongoing_event_progress_bar.xml
@@ -0,0 +1,104 @@
+<?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
new file mode 100644
index 0000000000..f2013bc0bf
--- /dev/null
+++ b/platform/android/libs/downloader_library/res/values-v11/styles.xml
@@ -0,0 +1,6 @@
+<?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
new file mode 100644
index 0000000000..736e77a5d6
--- /dev/null
+++ b/platform/android/libs/downloader_library/res/values-v9/styles.xml
@@ -0,0 +1,5 @@
+<?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
new file mode 100644
index 0000000000..b84749faf2
--- /dev/null
+++ b/platform/android/libs/downloader_library/res/values/strings.xml
@@ -0,0 +1,41 @@
+<?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
new file mode 100644
index 0000000000..a442f61e7e
--- /dev/null
+++ b/platform/android/libs/downloader_library/res/values/styles.xml
@@ -0,0 +1,25 @@
+<?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
new file mode 100644
index 0000000000..ff2c6f535a
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Constants.java
@@ -0,0 +1,236 @@
+/*
+ * 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
new file mode 100644
index 0000000000..9cb294d721
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java
@@ -0,0 +1,80 @@
+/*
+ * 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
new file mode 100644
index 0000000000..2201751254
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
@@ -0,0 +1,277 @@
+/*
+ * 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
new file mode 100644
index 0000000000..054eaa9895
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
@@ -0,0 +1,181 @@
+/*
+ * 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
new file mode 100644
index 0000000000..1e84e54a0f
--- /dev/null
+++ b/platform/android/libs/downloader_library/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.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
new file mode 100644
index 0000000000..b8511a62a0
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java
@@ -0,0 +1,126 @@
+/*
+ * 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
new file mode 100644
index 0000000000..4789afe19c
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderService.java
@@ -0,0 +1,83 @@
+/*
+ * 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
new file mode 100644
index 0000000000..d5bc3a843e
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IStub.java
@@ -0,0 +1,41 @@
+/*
+ * 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
new file mode 100644
index 0000000000..12edd97ab2
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/SystemFacade.java
@@ -0,0 +1,123 @@
+/*
+ * 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
new file mode 100644
index 0000000000..4667acce67
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java
@@ -0,0 +1,536 @@
+/*
+ * 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
new file mode 100755
index 0000000000..b77af7e085
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java
@@ -0,0 +1,112 @@
+/*
+ * 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
new file mode 100644
index 0000000000..9a0ca02122
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java
@@ -0,0 +1,30 @@
+/*
+ * 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
new file mode 100644
index 0000000000..45111b16a3
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java
@@ -0,0 +1,92 @@
+/*
+ * 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
new file mode 100644
index 0000000000..eef205d7b7
--- /dev/null
+++ b/platform/android/libs/downloader_library/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.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
new file mode 100644
index 0000000000..056d1eca0b
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
@@ -0,0 +1,963 @@
+/*
+ * 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
new file mode 100644
index 0000000000..627bf3eedd
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
@@ -0,0 +1,1341 @@
+/*
+ * 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
new file mode 100755
index 0000000000..250299c400
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java
@@ -0,0 +1,510 @@
+/*
+ * 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
new file mode 100644
index 0000000000..3f440e9893
--- /dev/null
+++ b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java
@@ -0,0 +1,200 @@
+/*
+ * 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
new file mode 100644
index 0000000000..e736603e2a
--- /dev/null
+++ b/platform/android/libs/downloader_library/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.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
new file mode 100644
index 0000000000..e3666e05b9
--- /dev/null
+++ b/platform/android/libs/downloader_library/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.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
index 6aed2ebfbe..7bc01d9a9c 100644
--- a/platform/android/libs/google_play_services/.classpath
+++ b/platform/android/libs/google_play_services/.classpath
@@ -4,5 +4,6 @@
<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/play_licensing/src/com/google/android/vending/licensing/LicenseChecker.java b/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseChecker.java
index 0b1c4b6cca..8b53545e61 100644
--- 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
@@ -63,7 +63,7 @@ public class LicenseChecker implements ServiceConnection {
private static final int TIMEOUT_MS = 10 * 1000;
private static final SecureRandom RANDOM = new SecureRandom();
- private static final boolean DEBUG_LICENSE_ERROR = false;
+ private static final boolean DEBUG_LICENSE_ERROR = true;
private ILicensingService mService;
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 5fad4386fa..e5d11bef69 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,7 +28,7 @@
/*************************************************************************/
#include "os_android.h"
#include "drivers/gles2/rasterizer_gles2.h"
-#include "drivers/gles1/rasterizer_gles1.h"
+
#include "core/io/file_access_buffered_fa.h"
#include "drivers/unix/file_access_unix.h"
#include "drivers/unix/dir_access_unix.h"
@@ -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
@@ -49,11 +51,11 @@
int OS_Android::get_video_driver_count() const {
- return 2;
+ return 1;
}
const char * OS_Android::get_video_driver_name(int p_driver) const {
- return p_driver==0?"GLES2":"GLES1";
+ return "GLES2";
}
OS::VideoMode OS_Android::get_default_video_mode() const {
@@ -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();
@@ -123,16 +131,18 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_
AudioDriverManagerSW::add_driver(&audio_driver_android);
- if (use_gl2) {
+ if (true) {
RasterizerGLES2 *rasterizer_gles22=memnew( RasterizerGLES2(false,use_reload_hooks,false,use_reload_hooks ) );
if (gl_extensions)
rasterizer_gles22->set_extensions(gl_extensions);
rasterizer = rasterizer_gles22;
} else {
- rasterizer = memnew( RasterizerGLES1(use_reload_hooks, use_reload_hooks) );
+ //rasterizer = memnew( RasterizerGLES1(use_reload_hooks, use_reload_hooks) );
}
+ rasterizer->set_force_16_bits_fbo(use_16bits_fbo);
+
visual_server = memnew( VisualServerRaster(rasterizer) );
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
@@ -151,7 +161,7 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_
sample_manager = memnew( SampleManagerMallocSW );
audio_server = memnew( AudioServerSW(sample_manager) );
- audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,true);
audio_server->init();
spatial_sound_server = memnew( SpatialSoundServerSW );
@@ -163,7 +173,8 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_
//
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ //physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
input = memnew( InputDefault );
@@ -291,6 +302,11 @@ void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen)
p_list->push_back(default_videomode);
}
+Size2 OS_Android::get_window_size() const {
+
+ return Vector2(default_videomode.width,default_videomode.height);
+}
+
String OS_Android::get_name() {
return "Android";
@@ -699,12 +715,26 @@ void OS_Android::native_video_pause() {
video_pause_func();
}
+String OS_Android::get_system_dir(SystemDir p_dir) const {
+
+ if (get_system_dir_func)
+ return get_system_dir_func(p_dir);
+ return String(".");
+}
+
void OS_Android::native_video_stop() {
if (video_stop_func)
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, 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,bool p_use_apk_expansion) {
use_apk_expansion=p_use_apk_expansion;
@@ -726,6 +756,7 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFu
get_locale_func=p_get_locale_func;
get_model_func=p_get_model_func;
get_unique_id_func=p_get_unique_id;
+ get_system_dir_func=p_get_sdir_func;
video_play_func = p_video_play_func;
video_is_playing_func = p_video_is_playing_func;
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index bc52a43002..94c6250ae8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -37,7 +37,11 @@
#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 "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
@@ -63,6 +67,7 @@ typedef String (*GetUniqueIDFunc)();
typedef void (*ShowVirtualKeyboardFunc)(const String&);
typedef void (*HideVirtualKeyboardFunc)();
typedef void (*SetScreenOrientationFunc)(int);
+typedef String (*GetSystemDirFunc)(int);
typedef void (*VideoPlayFunc)(const String&);
typedef bool (*VideoIsPlayingFunc)();
@@ -90,6 +95,8 @@ private:
bool use_reload_hooks;
bool use_apk_expansion;
+ bool use_16bits_fbo;
+
Rasterizer *rasterizer;
VisualServer *visual_server;
AudioServerSW *audio_server;
@@ -98,6 +105,7 @@ private:
SpatialSound2DServerSW *spatial_sound_2d_server;
PhysicsServer *physics_server;
Physics2DServer *physics_2d_server;
+
#if 0
AudioDriverAndroid audio_driver_android;
#else
@@ -118,6 +126,7 @@ private:
HideVirtualKeyboardFunc hide_virtual_keyboard_func;
SetScreenOrientationFunc set_screen_orientation_func;
GetUniqueIDFunc get_unique_id_func;
+ GetSystemDirFunc get_system_dir_func;
VideoPlayFunc video_play_func;
VideoIsPlayingFunc video_is_playing_func;
@@ -167,6 +176,8 @@ public:
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 Size2 get_window_size() const;
+
virtual String get_name();
virtual MainLoop *get_main_loop() const;
@@ -191,6 +202,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);
@@ -203,6 +215,8 @@ public:
virtual String get_unique_ID() const;
+ virtual String get_system_dir(SystemDir p_dir) const;
+
void process_accelerometer(const Vector3& p_accelerometer);
void process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points);
@@ -210,11 +224,11 @@ public:
void init_video_mode(int p_video_width,int p_video_height);
virtual Error native_video_play(String p_path, float p_volume);
- virtual bool native_video_is_playing();
- virtual void native_video_pause();
- virtual void native_video_stop();
+ virtual bool native_video_is_playing();
+ 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, 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,bool p_use_apk_expansion);
~OS_Android();
};
diff --git a/platform/android/platform_config.h b/platform/android/platform_config.h
index 38fc934ae4..1e7d066bb9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/android/project.properties.template b/platform/android/project.properties.template
index d81b72b525..00cacd72bc 100644
--- a/platform/android/project.properties.template
+++ b/platform/android/project.properties.template
@@ -12,4 +12,4 @@
# Project target.
#android.library=true
-target=android-15
+target=android-19
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
index ec6bef89a0..9314a1c013 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/android/thread_jandroid.h b/platform/android/thread_jandroid.h
index 38b4be01ec..051f4e2c3d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/bb10/SCsub b/platform/bb10/SCsub
index 2e8ef47005..81f6e726e4 100644
--- a/platform/bb10/SCsub
+++ b/platform/bb10/SCsub
@@ -18,13 +18,4 @@ if env['bb10_lgles_override'] == "yes":
prog = None
-if env["target"]=="release":
- prog = env_bps.Program('#platform/bb10/godot_bb10_opt', bb10_lib)
-else:
- prog = env_bps.Program('#platform/bb10/godot_bb10', bb10_lib)
-
-import os
-fname = os.path.basename(str(prog[0]))
-
-env.Command('#bin/'+fname, prog, Copy('bin/'+fname, prog[0]))
-
+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 ac6a008a00..f12625d3b8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 98b99107d4..82774bc533 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/bb10/bar/bar-descriptor.xml b/platform/bb10/bar/bar-descriptor.xml
index df5d34e077..0ba70b7180 100644
--- a/platform/bb10/bar/bar-descriptor.xml
+++ b/platform/bb10/bar/bar-descriptor.xml
@@ -1,65 +1,53 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<?xml version='1.0' encoding='utf-8' standalone='no'?>
<qnx xmlns="http://www.qnx.com/schemas/application/1.0">
-
-<!-- BlackBerry® 10 application descriptor file.
+ <!-- BlackBerry® 10 application descriptor file.
Specifies parameters for identifying, installing, and launching native applications on BlackBerry® 10 OS.
-->
-
<!-- A universally unique application identifier. Must be unique across all BlackBerry applications.
Using a reverse DNS-style name as the id is recommended. (Eg. com.example.ExampleApplication.) Required. -->
<id>com.godot.game</id>
-
<!-- The name that is displayed in the BlackBerry application installer.
May have multiple values for each language. See samples or xsd schema file. Optional. -->
<name>Godot Game</name>
-
<!-- A string value of the format <0-999>.<0-999>.<0-999> that represents application version which can be used to check for application upgrade.
Values can also be 1-part or 2-part. It is not necessary to have a 3-part value.
An updated version of application must have a versionNumber value higher than the previous version. Required. -->
<versionNumber>0.0.1</versionNumber>
-
<!-- Fourth digit segment of the package version. First three segments are taken from the
<versionNumber> element. Must be an integer from 0 to 2^16-1 -->
<buildId>0</buildId>
-
<!-- Description, displayed in the BlackBerry application installer.
May have multiple values for each language. See samples or xsd schema file. Optional. -->
<description>Game made with Godot Engine</description>
-
<!-- Name of author which is used for signing. Must match the developer name of your development certificate. -->
<author>You Name or Company</author>
<authorId>authorIDherePlease</authorId>
-
<!-- Unique author ID assigned by signing authority. Required if using debug tokens. -->
<!-- <authorId>ABC1234YjsnUk235h</authorId> -->
-
<initialWindow>
<aspectRatio>landscape</aspectRatio>
<autoOrients>false</autoOrients>
<systemChrome>none</systemChrome>
<transparent>false</transparent>
</initialWindow>
-
<!-- The category where the application appears. Either core.games or core.media. -->
<category>core.games</category>
<permission>read_device_identifying_information</permission>
<permission>access_internet</permission>
- <asset path="assets">assets</asset>
+ <asset path="data.pck">data.pck</asset>
<configuration name="Device-Debug">
- <platformArchitecture>armle-v7</platformArchitecture>
- <asset path="godot_bb10.qnx.armle" entry="true" type="Qnx/Elf">godot_bb10.qnx.armle</asset>
+ <platformArchitecture>armle-v7</platformArchitecture>
+ <asset type="Qnx/Elf" path="godot.bb10.debug.qnx.armle" entry="true">godot.bb10.debug.qnx.armle</asset>
</configuration>
<configuration name="Device-Release">
- <platformArchitecture>armle-v7</platformArchitecture>
- <asset path="godot_bb10_opt.qnx.armle" entry="true" type="Qnx/Elf">godot_bb10_opt.qnx.armle</asset>
+ <platformArchitecture>armle-v7</platformArchitecture>
+ <asset type="Qnx/Elf" path="godot.bb10.opt.qnx.armle" entry="true">godot.bb10.opt.qnx.armle</asset>
</configuration>
<!-- The icon for the application. -->
<icon>
- <image>icon.png</image>
+ <image>icon.png</image>
</icon>
-
<!-- Ensure that shared libraries in the package are found at run-time. -->
- <env var="LD_LIBRARY_PATH" value="app/native/lib:/usr/lib/qt4/lib"/>
-
+ <env value="app/native/lib:/usr/lib/qt4/lib" var="LD_LIBRARY_PATH"/>
</qnx>
diff --git a/platform/bb10/detect.py b/platform/bb10/detect.py
index 22940c0f2d..f134a9df19 100644
--- a/platform/bb10/detect.py
+++ b/platform/bb10/detect.py
@@ -35,6 +35,8 @@ def get_flags():
('lua', 'no'),
('tools', 'no'),
('nedmalloc', 'no'),
+ ('theora', 'no'),
+
]
def configure(env):
@@ -79,8 +81,6 @@ def configure(env):
if (env["target"]=="release"):
env.Append(CCFLAGS=['-O3','-DRELEASE_BUILD'])
- env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
elif (env["target"]=="debug"):
diff --git a/platform/bb10/export/export.cpp b/platform/bb10/export/export.cpp
index 5edcf39396..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;
@@ -147,7 +147,7 @@ void EditorExportPlatformBB10::_get_property_list( List<PropertyInfo> *p_list) c
p_list->push_back( PropertyInfo( Variant::STRING, "package/name") );
p_list->push_back( PropertyInfo( Variant::STRING, "package/description",PROPERTY_HINT_MULTILINE_TEXT) );
p_list->push_back( PropertyInfo( Variant::STRING, "package/icon",PROPERTY_HINT_FILE,"png") );
- p_list->push_back( PropertyInfo( Variant::STRING, "package/custom_template", PROPERTY_HINT_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/custom_template", PROPERTY_HINT_GLOBAL_FILE,"zip"));
p_list->push_back( PropertyInfo( Variant::STRING, "release/author") );
p_list->push_back( PropertyInfo( Variant::STRING, "release/author_id") );
@@ -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);
@@ -321,12 +327,29 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
//BE SUPER CAREFUL WITH THIS PLEASE!!!
//BLACKBERRY THIS IS YOUR FAULT FOR NOT MAKING A BETTER WAY!!
- if (bar_dir.ends_with("bb10_export")) {
- Error err = da->erase_contents_recursive();
- if (err!=OK) {
+ bool berr = bar_dir.ends_with("bb10_export");
+ if (berr) {
+ if (da->list_dir_begin()) {
EditorNode::add_io_error("Can't ensure that dir is empty:\n"+bar_dir);
- ERR_FAIL_COND_V(err!=OK,err);
- }
+ ERR_FAIL_COND_V(berr,FAILED);
+ };
+
+ String f = da->get_next();
+ while (f != "") {
+
+ if (f == "." || f == "..") {
+ f = da->get_next();
+ continue;
+ };
+ Error err = da->remove(bar_dir + "/" + f);
+ if (err != OK) {
+ EditorNode::add_io_error("Can't ensure that dir is empty:\n"+bar_dir);
+ ERR_FAIL_COND_V(err!=OK,err);
+ };
+ f = da->get_next();
+ };
+
+ da->list_dir_end();
} else {
print_line("ARE YOU CRAZY??? THIS IS A SERIOUS BUG HERE!!!");
@@ -405,52 +428,23 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
ret = unzGoToNextFile(pkg);
}
- ep.step("Finding Files..",1);
-
- Vector<StringName> files=get_dependencies(false);
-
ep.step("Adding Files..",2);
- da->change_dir(bar_dir);
- da->make_dir("assets");
- Error err = da->change_dir("assets");
- ERR_FAIL_COND_V(err,err);
-
- String asset_dir=da->get_current_dir();
- if (!asset_dir.ends_with("/"))
- asset_dir+="/";
-
- for(int i=0;i<files.size();i++) {
-
- String fname=files[i];
- Vector<uint8_t> data = get_exported_file(fname);
- /*
- FileAccess *f=FileAccess::open(files[i],FileAccess::READ);
- if (!f) {
- EditorNode::add_io_error("Couldn't read: "+String(files[i]));
- }
- ERR_CONTINUE(!f);
- data.resize(f->get_len());
- f->get_buffer(data.ptr(),data.size());
-*/
- String dst_path=fname;
- dst_path=dst_path.replace_first("res://",asset_dir);
-
- da->make_dir_recursive(dst_path.get_base_dir());
-
- ep.step("Adding File: "+String(files[i]).get_file(),3+i*100/files.size());
-
- FileAccessRef fr = FileAccess::open(dst_path,FileAccess::WRITE);
- fr->store_buffer(data.ptr(),data.size());
+ FileAccess* dst = FileAccess::open(bar_dir+"/data.pck", FileAccess::WRITE);
+ if (!dst) {
+ EditorNode::add_io_error("Can't copy executable file to:\n "+p_path);
+ return ERR_FILE_CANT_WRITE;
}
-
+ save_pack(dst, false, 1024);
+ dst->close();
+ memdelete(dst);
ep.step("Creating BAR Package..",104);
String bb_packager=EditorSettings::get_singleton()->get("blackberry/host_tools");
bb_packager=bb_packager.plus_file("blackberry-nativepackager");
if (OS::get_singleton()->get_name()=="Windows")
- bb_packager+=".exe";
+ bb_packager+=".bat";
if (!FileAccess::exists(bb_packager)) {
@@ -482,7 +476,7 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
int ec;
- err = OS::get_singleton()->execute(bb_packager,args,true,NULL,NULL,&ec);
+ Error err = OS::get_singleton()->execute(bb_packager,args,true,NULL,NULL,&ec);
if (err!=OK)
return err;
@@ -493,7 +487,6 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
}
-
bool EditorExportPlatformBB10::poll_devices() {
bool dc=devices_changed;
@@ -537,7 +530,7 @@ void EditorExportPlatformBB10::_device_poll_thread(void *ud) {
bb_deploy=bb_deploy.plus_file("blackberry-deploy");
bool windows = OS::get_singleton()->get_name()=="Windows";
if (windows)
- bb_deploy+=".exe";
+ bb_deploy+=".bat";
if (!FileAccess::exists(bb_deploy)) {
OS::get_singleton()->delay_usec(3000000);
@@ -632,14 +625,14 @@ 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);
String bb_deploy=EditorSettings::get_singleton()->get("blackberry/host_tools");
bb_deploy=bb_deploy.plus_file("blackberry-deploy");
if (OS::get_singleton()->get_name()=="Windows")
- bb_deploy+=".exe";
+ bb_deploy+=".bat";
if (!FileAccess::exists(bb_deploy)) {
EditorNode::add_io_error("Blackberry Deploy not found:\n"+bb_deploy);
@@ -656,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;
@@ -746,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";
}
@@ -777,6 +768,8 @@ EditorExportPlatformBB10::~EditorExportPlatformBB10() {
quit_request=true;
Thread::wait_to_finish(device_thread);
+ memdelete(device_lock);
+ memdelete(device_thread);
}
diff --git a/platform/bb10/os_bb10.cpp b/platform/bb10/os_bb10.cpp
index ff43a68b1d..c8e7ae561e 100644
--- a/platform/bb10/os_bb10.cpp
+++ b/platform/bb10/os_bb10.cpp
@@ -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);
@@ -619,7 +620,7 @@ OSBB10::OSBB10() {
printf("godot bb10!\n");
getcwd(launch_dir, sizeof(launch_dir));
printf("launch dir %s\n", launch_dir);
- chdir("app/native/assets");
+ chdir("app/native");
launch_dir_ptr = launch_dir;
}
diff --git a/platform/bb10/payment_service.cpp b/platform/bb10/payment_service.cpp
index f6ffffd831..f01230796f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/bb10/payment_service.h b/platform/bb10/payment_service.h
index 09eda11d2e..5036ca6660 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/flash/SCsub b/platform/flash/SCsub
index 0dea7bf011..4e5f26d52a 100644
--- a/platform/flash/SCsub
+++ b/platform/flash/SCsub
@@ -8,7 +8,6 @@ common_flash=[\
#"dir_access_flash.cpp",
]
-print("** path is ", env['ENV']['PATH'])
abc = env.Command('#platform/flash/Console.abc', '#platform/flash/Console.as',
"""
@@ -37,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 56d2516ab5..f079f21fdd 100644
--- a/platform/flash/detect.py
+++ b/platform/flash/detect.py
@@ -11,7 +11,6 @@ def get_name():
def can_build():
#import os
- print(os.environ)
if (not os.environ.has_key("FLASCC_ROOT")):
return False
return True
@@ -90,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/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.h b/platform/flash/rasterizer_flash.h
index af231f7954..1a2c540faa 100644
--- a/platform/flash/rasterizer_flash.h
+++ b/platform/flash/rasterizer_flash.h
@@ -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..859095fa5a
--- /dev/null
+++ b/platform/haiku/SCsub
@@ -0,0 +1,16 @@
+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'
+]
+
+env.Program(
+ '#bin/godot',
+ ['godot_haiku.cpp'] + common_haiku
+)
diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp
new file mode 100644
index 0000000000..3fabe4f96f
--- /dev/null
+++ b/platform/haiku/audio_driver_media_kit.cpp
@@ -0,0 +1,143 @@
+/*************************************************************************/
+/* audio_driver_media_kit.cpp */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#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() {
+ if (player)
+ 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..a23ec447f1
--- /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-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. */
+/*************************************************************************/
+#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..b5fd550442
--- /dev/null
+++ b/platform/haiku/detect.py
@@ -0,0 +1,61 @@
+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 = ['-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_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..ea20d73729
--- /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..3914ee272a
--- /dev/null
+++ b/platform/haiku/haiku_direct_window.cpp
@@ -0,0 +1,344 @@
+#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() {
+ if (update_runner) {
+ 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 d11b2f7793..f0bf2c01d5 100644
--- a/platform/iphone/Appirater.h
+++ b/platform/iphone/Appirater.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
index 0113f75697..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',
]
@@ -25,8 +26,6 @@ env_ios = env.Clone();
if env['ios_gles22_override'] == "yes":
env_ios.Append(CPPFLAGS=['-DGLES2_OVERRIDE'])
-if env['ios_GLES1_override'] == "yes":
- env_ios.Append(CPPFLAGS=['-DGLES1_OVERRIDE'])
if env['ios_appirater'] == "yes":
env_ios.Append(CPPFLAGS=['-DAPPIRATER_ENABLED'])
@@ -35,11 +34,6 @@ if env['ios_appirater'] == "yes":
obj = env_ios.Object('godot_iphone.cpp')
prog = None
-if env["target"]=="release":
- prog = env_ios.Program('#bin/godot_opt', [obj] + iphone_lib)
- #action = "dsymutil "+File(prog)[0].path+" -o ../build/script_exec/build/Debug-iphoneos/script_exec.app.dSYM"
- #env.AddPostAction(prog, action)
-else:
- prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
- action = "dsymutil "+File(prog)[0].path+" -o bin/godot.iphone.dSYM"
- env.AddPostAction(prog, action)
+prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
+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 db641b1f78..0d20f886cc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,12 +31,14 @@
#import "view_controller.h"
@interface AppDelegate : NSObject <UIApplicationDelegate, UIAccelerometerDelegate, GLViewDelegate> {
- UIWindow *window;
+ //@property (strong, nonatomic) UIWindow *window;
ViewController* view_controller;
UIAccelerationValue accel[3];
UIAccelerationValue last_accel[3];
};
+@property (strong, nonatomic) UIWindow *window;
+
+ (ViewController*)getViewController;
@end
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
index 9ba95ff0c5..e5bd7a96b4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,8 @@
#import "Appirater.h"
#endif
+Error _shell_open(String);
+
Error _shell_open(String p_uri) {
NSString* url = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()];
@@ -65,6 +72,8 @@ Error _shell_open(String p_uri) {
@implementation AppDelegate
+@synthesize window;
+
extern int gargc;
extern char** gargv;
extern int iphone_main(int, int, int, char**);
@@ -82,13 +91,11 @@ static int frame_count = 0;
switch (frame_count) {
case 0: {
-
- int backingWidth;
- int backingHeight;
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
-
- iphone_main(backingWidth, backingHeight, gargc, gargv);
+ int backingWidth;
+ int backingHeight;
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
+
OS::VideoMode vm;
vm.fullscreen = true;
@@ -127,7 +134,7 @@ static int frame_count = 0;
OSIPhone::get_singleton()->set_unique_ID(String::utf8([uuid UTF8String]));
- }; // break;
+ }; break;
/*
case 1: {
++frame_count;
@@ -138,6 +145,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: {
@@ -154,7 +185,7 @@ static int frame_count = 0;
[Appirater appLaunched:YES app_id:aid];
#endif
- }; // break; fallthrough
+ }; break; // no fallthrough
default: {
@@ -196,10 +227,19 @@ static int frame_count = 0;
//glView.autoresizesSubviews = YES;
//[glView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
+ int backingWidth;
+ int backingHeight;
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
+
+ iphone_main(backingWidth, backingHeight, gargc, gargv);
+
view_controller = [[ViewController alloc] init];
view_controller.view = glView;
window.rootViewController = view_controller;
+ glView.useCADisplayLink = bool(GLOBAL_DEF("display.iOS/use_cadisplaylink",true)) ? YES : NO;
+ printf("cadisaplylink: %d", glView.useCADisplayLink);
glView.animationInterval = 1.0 / kRenderingFrequency;
[glView startAnimation];
@@ -257,18 +297,25 @@ static int frame_count = 0;
- (void)applicationDidEnterBackground:(UIApplication *)application
{
printf("********************* did enter background\n");
+ if (OS::get_singleton()->get_main_loop())
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
[view_controller.view stopAnimation];
+ if (OS::get_singleton()->native_video_is_playing()) {
+ OSIPhone::get_singleton()->native_video_focus_out();
+ };
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
printf("********************* did enter foreground\n");
+ //OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
[view_controller.view startAnimation];
}
- (void) applicationWillResignActive:(UIApplication *)application
{
printf("********************* will resign active\n");
+ //OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
[view_controller.view stopAnimation]; // FIXME: pause seems to be recommended elsewhere
}
@@ -279,7 +326,12 @@ static int frame_count = 0;
printf("********************* mobile app tracker found\n");
[MobileAppTracker measureSession];
#endif
+ if (OS::get_singleton()->get_main_loop())
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
[view_controller.view startAnimation]; // FIXME: resume seems to be recommended elsewhere
+ if (OSIPhone::get_singleton()->native_video_is_playing()) {
+ OSIPhone::get_singleton()->native_video_unpause();
+ };
}
- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration {
@@ -299,6 +351,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
@@ -306,6 +367,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 d39b8f3c4d..a95cb436a7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -99,7 +99,16 @@ OSStatus AudioDriverIphone::output_callback(void *inRefCon,
AudioBuffer *abuf;
AudioDriverIphone* ad = (AudioDriverIphone*)inRefCon;
- if (!ad->active) {
+ bool mix = true;
+
+ if (!ad->active)
+ mix = false;
+ else if (ad->mutex) {
+ mix = ad->mutex->try_lock() == OK;
+ };
+
+
+ if (!mix) {
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
abuf = &ioData->mBuffers[i];
zeromem(abuf->mData, abuf->mDataByteSize);
@@ -118,9 +127,9 @@ OSStatus AudioDriverIphone::output_callback(void *inRefCon,
while (frames_left) {
int frames = MIN(frames_left, ad->buffer_frames);
- ad->lock();
+ //ad->lock();
ad->audio_server_process(frames, ad->samples_in);
- ad->unlock();
+ //ad->unlock();
for(int i = 0; i < frames * ad->channels; i++) {
@@ -132,6 +141,9 @@ OSStatus AudioDriverIphone::output_callback(void *inRefCon,
};
};
+ if (ad->mutex)
+ ad->mutex->unlock();
+
return 0;
};
@@ -147,11 +159,28 @@ AudioDriverSW::OutputFormat AudioDriverIphone::get_output_format() const {
return OUTPUT_STEREO;
};
-void AudioDriverIphone::lock() {};
-void AudioDriverIphone::unlock() {};
+void AudioDriverIphone::lock() {
+
+ if (active && mutex)
+ mutex->lock();
+};
+
+void AudioDriverIphone::unlock() {
+ if (active && mutex)
+ mutex->unlock();
+};
void AudioDriverIphone::finish() {
memdelete_arr(samples_in);
};
+
+AudioDriverIphone::AudioDriverIphone() {
+
+ mutex=Mutex::create();//NULL;
+};
+
+AudioDriverIphone::~AudioDriverIphone() {
+
+};
diff --git a/platform/iphone/audio_driver_iphone.h b/platform/iphone/audio_driver_iphone.h
index eec54d9ee3..5d406940a3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,6 +34,7 @@ class AudioDriverIphone : public AudioDriverSW {
AudioComponentInstance audio_unit;
bool active;
+ Mutex *mutex;
int channels;
int32_t* samples_in;
@@ -59,5 +60,8 @@ public:
virtual void lock();
virtual void unlock();
virtual void finish();
+
+ AudioDriverIphone();
+ ~AudioDriverIphone();
};
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index ec6e4c98f1..137fcc56f5 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
@@ -21,22 +22,21 @@ def get_opts():
return [
('IPHONEPLATFORM', 'name of the iphone platform', 'iPhoneOS'),
('IPHONEPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'),
- ('IOS_SDK_VERSION', 'The SDK version', 'iPhoneOS7.0'),
+ ('IOS_SDK_VERSION', 'The SDK version', 'iPhoneOS'),
('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_GLES1_override', 'Force legacy GLES (1.1) on iOS', 'no'),
('ios_appirater', 'Enable Appirater', 'no'),
- ('ios_exceptions', 'Use exceptions when compiling on playbook', 'no'),
+ ('ios_exceptions', 'Use exceptions when compiling on playbook', 'yes'),
+ ('ios_triple', 'Triple for ios toolchain', ''),
]
def get_flags():
return [
- ('lua', 'no'),
- ('tools', 'yes'),
- ('nedmalloc', 'no'),
+ ('tools', 'no'),
('webp', 'yes'),
('openssl','builtin'), #use builtin openssl
]
@@ -47,33 +47,45 @@ def configure(env):
env.Append(CPPPATH=['#platform/iphone', '#platform/iphone/include'])
- env['OBJSUFFIX'] = ".iphone.o"
- env['LIBSUFFIX'] = ".iphone.a"
- env['PROGSUFFIX'] = ".iphone"
-
env['ENV']['PATH'] = env['IPHONEPATH']+"/Developer/usr/bin/:"+env['ENV']['PATH']
# 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
- #env['CCFLAGS'] = string.split('-arch armv7 -Wall -fno-strict-aliasing -fno-common -D__IPHONE_OS_VERSION_MIN_REQUIRED=20000 -isysroot $IPHONESDK -fvisibility=hidden -mmacosx-version-min=10.5 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\" -DNO_THUMB')
- 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')
-
-
-#/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ fno-objc-arc -arch armv7 -fmessage-length=0 -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 -v -Os -ffast-math -DSTOREKIT_ENABLED -DIPHONE_ENABLED -DUNIX_ENABLED -DGLES2_ENABLED -DNO_THREADS -DMODULE_GRIDMAP_ENABLED -DMUSEPACK_ENABLED -DOLD_SCENE_FORMAT_ENABLED -DSQUIRREL_ENABLED -DVORBIS_ENABLED -DTHEORA_ENABLED -DPNG_ENABLED -DDDS_ENABLED -DPVR_ENABLED -DJPG_ENABLED -DSPEEX_ENABLED -DTOOLS_ENABLED -DGDSCRIPT_ENABLED -DMINIZIP_ENABLED -DXML_ENABLED -Icore -Icore/math -Itools -Idrivers -I. -Iplatform/iphone -Iplatform/iphone/include -Iplatform/iphone/scoreloop/SDKs -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework/Headers -Iscript/squirrel/src -Iscript/vorbis script/gdscript/gd_script.cpp
-#/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -x objective-c -arch armv7 -fmessage-length=0 -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings -Os -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 -iquote /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-generated-files.hmap -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-own-target-headers.hmap -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-all-target-headers.hmap -iquote /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-project-headers.hmap -I/Users/red/test2/build/Release-iphoneos/include -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/DerivedSources/armv7 -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/DerivedSources -F/Users/red/test2/build/Release-iphoneos -DNS_BLOCK_ASSERTIONS=1 -include /var/folders/LX/LXYXHTeSHSqbkhuPJRIsuE+++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/test2-Prefix-dvdhnltoisfpmyalexovdrmfyeky/test2-Prefix.pch -MMD -MT dependencies -MF /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/Objects-normal/armv7/main.d -c /Users/red/test2/test2/main.m -o /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/Objects-normal/armv7/main.o
-
-
-
-
+ 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.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=5.1.1 -MMD -MT dependencies -isysroot $IPHONESDK')
- env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=4.3',
+ if (env["bits"]=="64"):
+ env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1',
+ '-isysroot', '$IPHONESDK',
+ #'-stdlib=libc++',
+ '-framework', 'Foundation',
+ '-framework', 'UIKit',
+ '-framework', 'CoreGraphics',
+ '-framework', 'OpenGLES',
+ '-framework', 'QuartzCore',
+ '-framework', 'CoreAudio',
+ '-framework', 'AudioToolbox',
+ '-framework', 'SystemConfiguration',
+ '-framework', 'Security',
+ #'-framework', 'AdSupport',
+ '-framework', 'MediaPlayer',
+ '-framework', 'AVFoundation',
+ '-framework', 'CoreMedia',
+ ])
+ else:
+ env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1',
'-isysroot', '$IPHONESDK',
- #'-mmacosx-version-min=10.5',
'-framework', 'Foundation',
'-framework', 'UIKit',
'-framework', 'CoreGraphics',
@@ -85,6 +97,8 @@ def configure(env):
'-framework', 'Security',
#'-framework', 'AdSupport',
'-framework', 'MediaPlayer',
+ '-framework', 'AVFoundation',
+ '-framework', 'CoreMedia',
])
if env['game_center'] == 'yes':
@@ -94,20 +108,26 @@ 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=['-Os', '-ffast-math', '-DNS_BLOCK_ASSERTIONS=1','-Wall'])
+ env.Append(CCFLAGS=['-O3', '-ffast-math', '-DNS_BLOCK_ASSERTIONS=1','-Wall'])
+ env.Append(LINKFLAGS=['-O3', '-ffast-math'])
+
+ 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['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ENABLED'])
elif (env["target"]=="debug"):
env.Append(CCFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-Wall', '-O0', '-DDEBUG_ENABLED'])
- env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ENABLED'])
elif (env["target"]=="profile"):
@@ -116,16 +136,25 @@ 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', '-DGLES1_ENABLED', '-DMPC_FIXED_POINT'])
+ 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:
env.Append(CPPFLAGS=['-fno-exceptions'])
#env['neon_enabled']=True
env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc'
-
- if env['lua'] == "yes":
- env.Append(CCFLAGS=['-DLUA_USE_FLOAT'])
+
+ 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') } )
-# /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c-header -arch armv7s -fmessage-length=0 -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings -Os -Wno-missing-field-initializers -Wno-missing-prototypes -Wreturn-type -Wno-implicit-atomic-properties -Wno-receiver-is-weak -Wduplicate-method-match -Wformat -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-shorten-64-to-32 -Wpointer-sign -Wno-newline-eof -Wno-selector -Wno-strict-selector-match -Wno-undeclared-selector -Wno-deprecated-implementations -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk -Wprotocol -Wdeprecated-declarations -g -fvisibility=hidden -Wno-sign-conversion "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -iquote /Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-generated-files.hmap -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-own-target-headers.hmap -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-all-target-headers.hmap -iquote /Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-project-headers.hmap -I/Users/lucasgondolo/test/build/Release-iphoneos/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/DerivedSources/armv7s -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/DerivedSources -F/Users/lucasgondolo/test/build/Release-iphoneos -DNS_BLOCK_ASSERTIONS=1 --serialize-diagnostics /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.dia -c /Users/lucasgondolo/test/test/test-Prefix.pch -o /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.pth -MMD -MT dependencies -MF /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.d
diff --git a/platform/iphone/game_center.h b/platform/iphone/game_center.h
index df1d980c04..8f180d1638 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -51,6 +51,12 @@ public:
Error post_score(Variant p_score);
Error award_achievement(Variant p_params);
+ void reset_achievements();
+ void request_achievements();
+ void request_achievement_descriptions();
+ Error show_game_center(Variant p_params);
+
+ void game_center_closed();
int get_pending_event_count();
Variant pop_pending_event();
diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm
index d517ddd105..4cb7a20a7f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,8 +30,19 @@
#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"
};
GameCenter* GameCenter::instance = NULL;
@@ -42,6 +53,10 @@ void GameCenter::_bind_methods() {
ObjectTypeDB::bind_method(_MD("post_score"),&GameCenter::post_score);
ObjectTypeDB::bind_method(_MD("award_achievement"),&GameCenter::award_achievement);
+ ObjectTypeDB::bind_method(_MD("reset_achievements"),&GameCenter::reset_achievements);
+ ObjectTypeDB::bind_method(_MD("request_achievements"),&GameCenter::request_achievements);
+ ObjectTypeDB::bind_method(_MD("request_achievement_descriptions"),&GameCenter::request_achievement_descriptions);
+ ObjectTypeDB::bind_method(_MD("show_game_center"),&GameCenter::show_game_center);
ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&GameCenter::get_pending_event_count);
ObjectTypeDB::bind_method(_MD("pop_pending_event"),&GameCenter::pop_pending_event);
@@ -50,23 +65,41 @@ void GameCenter::_bind_methods() {
Error GameCenter::connect() {
- GKLocalPlayer* player = [GKLocalPlayer localPlayer];
- [player authenticateWithCompletionHandler:^(NSError* error) {
+ //if this class isn't available, game center isn't implemented
+ if ((NSClassFromString(@"GKLocalPlayer")) == nil) {
+ GameCenter::get_singleton()->connected = false;
+ return ERR_UNAVAILABLE;
+ }
- Dictionary ret;
- ret["type"] = "authentication";
- if (player.isAuthenticated) {
- ret["result"] = "ok";
- GameCenter::get_singleton()->connected = true;
- } else {
- ret["result"] = "error";
- ret["error_code"] = error.code;
- ret["error_description"] = [error.localizedDescription UTF8String];
- GameCenter::get_singleton()->connected = false;
- };
+ GKLocalPlayer* player = [GKLocalPlayer localPlayer];
+ ERR_FAIL_COND_V(![player respondsToSelector:@selector(authenticateHandler)], ERR_UNAVAILABLE);
+
+ ViewController *root_controller=(ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;
+ ERR_FAIL_COND_V(!root_controller, FAILED);
+
+ //this handler is called serveral times. first when the view needs to be shown, then again after the view is cancelled or the user logs in. or if the user's already logged in, it's called just once to confirm they're authenticated. This is why no result needs to be specified in the presentViewController phase. in this case, more calls to this function will follow.
+ player.authenticateHandler = (^(UIViewController *controller, NSError *error) {
+ if (controller) {
+ [root_controller presentViewController:controller animated:YES completion:nil];
+ }
+ else {
+ Dictionary ret;
+ ret["type"] = "authentication";
+ if (player.isAuthenticated) {
+ ret["result"] = "ok";
+ GameCenter::get_singleton()->connected = true;
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ ret["error_description"] = [error.localizedDescription UTF8String];
+ GameCenter::get_singleton()->connected = false;
+ };
+
+ pending_events.push_back(ret);
+ };
+
+ });
- pending_events.push_back(ret);
- }];
return OK;
};
@@ -85,7 +118,9 @@ Error GameCenter::post_score(Variant p_score) {
GKScore* reporter = [[[GKScore alloc] initWithCategory:cat_str] autorelease];
reporter.value = score;
- [reporter reportScoreWithCompletionHandler:^(NSError* error) {
+ ERR_FAIL_COND_V([GKScore respondsToSelector:@selector(reportScores)], ERR_UNAVAILABLE);
+
+ [GKScore reportScores:@[reporter] withCompletionHandler:^(NSError* error) {
Dictionary ret;
ret["type"] = "post_score";
@@ -114,8 +149,15 @@ Error GameCenter::award_achievement(Variant p_params) {
GKAchievement* achievement = [[[GKAchievement alloc] initWithIdentifier: name_str] autorelease];
ERR_FAIL_COND_V(!achievement, FAILED);
+ ERR_FAIL_COND_V([GKAchievement respondsToSelector:@selector(reportAchievements)], ERR_UNAVAILABLE);
+
achievement.percentComplete = progress;
- [achievement reportAchievementWithCompletionHandler:^(NSError* error) {
+ achievement.showsCompletionBanner = NO;
+ if (params.has("show_completion_banner")) {
+ achievement.showsCompletionBanner = params["show_completion_banner"] ? YES : NO;
+ }
+
+ [GKAchievement reportAchievements:@[achievement] withCompletionHandler:^(NSError *error) {
Dictionary ret;
ret["type"] = "award_achievement";
@@ -132,6 +174,168 @@ Error GameCenter::award_achievement(Variant p_params) {
return OK;
};
+void GameCenter::request_achievement_descriptions() {
+
+ [GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:^(NSArray *descriptions, NSError *error) {
+
+ Dictionary ret;
+ ret["type"] = "achievement_descriptions";
+ if (error == nil) {
+ ret["result"] = "ok";
+ StringArray names;
+ StringArray titles;
+ StringArray unachieved_descriptions;
+ StringArray achieved_descriptions;
+ IntArray maximum_points;
+ Array hidden;
+ Array replayable;
+
+ for (int i=0; i<[descriptions count]; i++) {
+
+ GKAchievementDescription* description = [descriptions objectAtIndex:i];
+
+ const char* str = [description.identifier UTF8String];
+ names.push_back(String::utf8(str != NULL ? str : ""));
+
+ str = [description.title UTF8String];
+ titles.push_back(String::utf8(str != NULL ? str : ""));
+
+ str = [description.unachievedDescription UTF8String];
+ unachieved_descriptions.push_back(String::utf8(str != NULL ? str : ""));
+
+ str = [description.achievedDescription UTF8String];
+ achieved_descriptions.push_back(String::utf8(str != NULL ? str : ""));
+
+ maximum_points.push_back(description.maximumPoints);
+
+ hidden.push_back(description.hidden == YES);
+
+ replayable.push_back(description.replayable == YES);
+ }
+
+ ret["names"] = names;
+ ret["titles"] = titles;
+ ret["unachieved_descriptions"] = unachieved_descriptions;
+ ret["achieved_descriptions"] = achieved_descriptions;
+ ret["maximum_points"] = maximum_points;
+ ret["hidden"] = hidden;
+ ret["replayable"] = replayable;
+
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ };
+
+ pending_events.push_back(ret);
+ }];
+};
+
+
+void GameCenter::request_achievements() {
+
+ [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
+
+ Dictionary ret;
+ ret["type"] = "achievements";
+ if (error == nil) {
+ ret["result"] = "ok";
+ StringArray names;
+ RealArray percentages;
+
+ for (int i=0; i<[achievements count]; i++) {
+
+ GKAchievement* achievement = [achievements objectAtIndex:i];
+ const char* str = [achievement.identifier UTF8String];
+ names.push_back(String::utf8(str != NULL ? str : ""));
+
+ percentages.push_back(achievement.percentComplete);
+ }
+
+ ret["names"] = names;
+ ret["progress"] = percentages;
+
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ };
+
+ pending_events.push_back(ret);
+ }];
+};
+
+void GameCenter::reset_achievements() {
+
+ [GKAchievement resetAchievementsWithCompletionHandler:^(NSError *error)
+ {
+ Dictionary ret;
+ ret["type"] = "reset_achievements";
+ if (error == nil) {
+ ret["result"] = "ok";
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ };
+
+ pending_events.push_back(ret);
+ }];
+};
+
+Error GameCenter::show_game_center(Variant p_params) {
+
+ ERR_FAIL_COND_V(!NSProtocolFromString(@"GKGameCenterControllerDelegate"), FAILED);
+
+ Dictionary params = p_params;
+
+ GKGameCenterViewControllerState view_state = GKGameCenterViewControllerStateDefault;
+ if (params.has("view")) {
+ String view_name = params["view"];
+ if (view_name == "default") {
+ view_state = GKGameCenterViewControllerStateDefault;
+ }
+ else if (view_name == "leaderboards") {
+ view_state = GKGameCenterViewControllerStateLeaderboards;
+ }
+ else if (view_name == "achievements") {
+ view_state = GKGameCenterViewControllerStateAchievements;
+ }
+ else if (view_name == "challenges") {
+ view_state = GKGameCenterViewControllerStateChallenges;
+ }
+ else {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ GKGameCenterViewController *controller = [[GKGameCenterViewController alloc] init];
+ ERR_FAIL_COND_V(!controller, FAILED);
+
+ ViewController *root_controller=(ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;
+ ERR_FAIL_COND_V(!root_controller, FAILED);
+
+ controller.gameCenterDelegate = root_controller;
+ controller.viewState = view_state;
+ if (view_state == GKGameCenterViewControllerStateLeaderboards) {
+ controller.leaderboardIdentifier = nil;
+ if (params.has("leaderboard_name")) {
+ String name = params["leaderboard_name"];
+ NSString* name_str = [[[NSString alloc] initWithUTF8String:name.utf8().get_data()] autorelease];
+ controller.leaderboardIdentifier = name_str;
+ }
+ }
+
+ [root_controller presentViewController: controller animated: YES completion:nil];
+
+ return OK;
+};
+
+void GameCenter::game_center_closed() {
+
+ Dictionary ret;
+ ret["type"] = "show_game_center";
+ ret["result"] = "ok";
+ pending_events.push_back(ret);
+}
+
int GameCenter::get_pending_event_count() {
return pending_events.size();
diff --git a/platform/iphone/gl_view.h b/platform/iphone/gl_view.h
index 3e6181ab90..ca2d1d25ae 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,6 +32,7 @@
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#import <MediaPlayer/MediaPlayer.h>
+#import <AVFoundation/AVFoundation.h>
@protocol GLViewDelegate;
@@ -50,8 +51,14 @@
// OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist)
GLuint depthRenderbuffer;
+ 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;
+
// An animation timer that, when animation is started, will periodically call -drawView at the given rate.
+ // Only used if CADisplayLink is not
NSTimer *animationTimer;
+
NSTimeInterval animationInterval;
// Delegate to do our drawing, called by -drawView, which can be called manually or via the animation timer.
@@ -66,6 +73,13 @@
@property(nonatomic, assign) id<GLViewDelegate> delegate;
+// AVPlayer-related properties
+@property(strong, nonatomic) AVAsset *avAsset;
+@property(strong, nonatomic) AVPlayerItem *avPlayerItem;
+@property(strong, nonatomic) AVPlayer *avPlayer;
+@property(strong, nonatomic) AVPlayerLayer *avPlayerLayer;
+
+// Old videoplayer properties
@property(strong, nonatomic) MPMoviePlayerController *moviePlayerController;
@property(strong, nonatomic) UIWindow *backgroundWindow;
@@ -85,7 +99,10 @@
- (BOOL)createFramebuffer;
- (void)destroyFramebuffer;
+- (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 500c7c7174..f19e16f3f6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -52,6 +52,15 @@ static GLView* _instance = NULL;
static bool video_found_error = false;
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;
@@ -65,12 +74,13 @@ void _hide_keyboard() {
keyboard_text = "";
};
+/*
bool _play_video(String p_path, float p_volume) {
float player_volume = p_volume * AudioServer::get_singleton()->get_singleton()->get_stream_global_volume_scale();
video_previous_volume = [[MPMusicPlayerController applicationMusicPlayer] volume];
- [[MPMusicPlayerController applicationMusicPlayer] setVolume: player_volume];
+ //[[MPMusicPlayerController applicationMusicPlayer] setVolume: player_volume];
p_path = Globals::get_singleton()->globalize_path(p_path);
@@ -96,24 +106,116 @@ bool _play_video(String p_path, float p_volume) {
return true;
}
+*/
+
+bool _play_video(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
+ p_path = Globals::get_singleton()->globalize_path(p_path);
+
+ NSString* file_path = [[[NSString alloc] initWithUTF8String:p_path.utf8().get_data()] autorelease];
+ //NSURL *file_url = [NSURL fileURLWithPath:file_path];
+
+ _instance.avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:file_path]];
+ _instance.avPlayerItem =[[AVPlayerItem alloc]initWithAsset:_instance.avAsset];
+ [_instance.avPlayerItem addObserver:_instance forKeyPath:@"status" options:0 context:nil];
+
+ _instance.avPlayer = [[AVPlayer alloc]initWithPlayerItem:_instance.avPlayerItem];
+ _instance.avPlayerLayer =[AVPlayerLayer playerLayerWithPlayer:_instance.avPlayer];
+
+ [_instance.avPlayer addObserver:_instance forKeyPath:@"status" options:0 context:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:_instance
+ selector:@selector(playerItemDidReachEnd:)
+ name:AVPlayerItemDidPlayToEndTimeNotification
+ object:[_instance.avPlayer currentItem]];
+
+ [_instance.avPlayer addObserver:_instance forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:0];
+
+ [_instance.avPlayerLayer setFrame:_instance.bounds];
+ [_instance.layer addSublayer:_instance.avPlayerLayer];
+ [_instance.avPlayer play];
+
+ AVMediaSelectionGroup *audioGroup = [_instance.avAsset mediaSelectionGroupForMediaCharacteristic: AVMediaCharacteristicAudible];
+
+ NSMutableArray *allAudioParams = [NSMutableArray array];
+ for (id track in audioGroup.options)
+ {
+ NSString* language = [[track locale] localeIdentifier];
+ NSLog(@"subtitle lang: %@", language);
+
+ if ([language isEqualToString:[NSString stringWithUTF8String:p_audio_track.utf8()]])
+ {
+ AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
+ [audioInputParams setVolume:p_volume atTime:kCMTimeZero];
+ [audioInputParams setTrackID:[track trackID]];
+ [allAudioParams addObject:audioInputParams];
+
+ AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
+ [audioMix setInputParameters:allAudioParams];
+
+ [_instance.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup: audioGroup];
+ [_instance.avPlayer.currentItem setAudioMix:audioMix];
+
+ break;
+ }
+ }
+
+ AVMediaSelectionGroup *subtitlesGroup = [_instance.avAsset mediaSelectionGroupForMediaCharacteristic: AVMediaCharacteristicLegible];
+ NSArray *useableTracks = [AVMediaSelectionGroup mediaSelectionOptionsFromArray:subtitlesGroup.options withoutMediaCharacteristics:[NSArray arrayWithObject:AVMediaCharacteristicContainsOnlyForcedSubtitles]];
+
+ for (id track in useableTracks)
+ {
+ NSString* language = [[track locale] localeIdentifier];
+ NSLog(@"subtitle lang: %@", language);
+
+ if ([language isEqualToString:[NSString stringWithUTF8String:p_subtitle_track.utf8()]])
+ {
+ [_instance.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup: subtitlesGroup];
+ break;
+ }
+ }
+
+ video_playing = true;
+
+ return true;
+}
bool _is_video_playing() {
//NSInteger playback_state = _instance.moviePlayerController.playbackState;
- return video_playing || _instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying;
+ //return video_playing || _instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying;
//if (video_found_error)
// return false;
//return (_instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying);
+
+ return video_playing || (_instance.avPlayer.rate > 0 && !_instance.avPlayer.error);
}
void _pause_video() {
- [_instance.moviePlayerController pause];
+ //[_instance.moviePlayerController pause];
+ video_current_time = _instance.avPlayer.currentTime;
+ [_instance.avPlayer pause];
video_playing = false;
}
+void _focus_out_video() {
+ printf("focus out pausing video\n");
+ [_instance.avPlayer pause];
+};
+
+void _unpause_video() {
+
+ [_instance.avPlayer play];
+ video_playing = true;
+
+ //video_current_time = kCMTimeZero;
+};
+
void _stop_video() {
- [_instance.moviePlayerController stop];
- [_instance.moviePlayerController.view removeFromSuperview];
- [[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
+ //[_instance.moviePlayerController stop];
+ //[_instance.moviePlayerController.view removeFromSuperview];
+ //[[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
+
+ [_instance.avPlayer pause];
+ [_instance.avPlayerLayer removeFromSuperlayer];
+ _instance.avPlayer = nil;
video_playing = false;
}
@@ -215,11 +317,7 @@ static void clear_touches() {
nil];
// Create our EAGLContext, and if successful make it current and create our framebuffer.
-#ifdef GLES1_OVERRIDE
- context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
-#else
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
-#endif
if(!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer])
{
@@ -244,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
@@ -262,8 +364,9 @@ static void clear_touches() {
// Generate IDs for a framebuffer object and a color renderbuffer
UIScreen* mainscr = [UIScreen mainScreen];
printf("******** screen size %i, %i\n", (int)mainscr.currentMode.size.width, (int)mainscr.currentMode.size.height);
- if (mainscr.currentMode.size.width == 640 || mainscr.currentMode.size.width == 960) // modern iphone, can go to 640x960
- self.contentScaleFactor = 2.0;
+ float minPointSize = MIN(mainscr.bounds.size.width, mainscr.bounds.size.height);
+ float minScreenSize = MIN(mainscr.currentMode.size.width, mainscr.currentMode.size.height);
+ self.contentScaleFactor = minScreenSize / minPointSize;
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);
@@ -325,7 +428,26 @@ static void clear_touches() {
return;
active = TRUE;
printf("start animation!\n");
- animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
+ 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)
+ {
+ _unpause_video();
+ }
}
- (void)stopAnimation
@@ -334,17 +456,28 @@ static void clear_touches() {
return;
active = FALSE;
printf("******** stop animation!\n");
- [animationTimer invalidate];
- animationTimer = nil;
+
+ if (useCADisplayLink) {
+ [displayLink invalidate];
+ displayLink = nil;
+ }
+ else {
+ [animationTimer invalidate];
+ animationTimer = nil;
+ }
+
clear_touches();
+
+ if (video_playing)
+ {
+ // save position
+ }
}
- (void)setAnimationInterval:(NSTimeInterval)interval
{
animationInterval = interval;
-
- if(animationTimer)
- {
+ if ( (useCADisplayLink && displayLink) || ( !useCADisplayLink && animationTimer ) ) {
[self stopAnimation];
[self startAnimation];
}
@@ -353,6 +486,17 @@ static void clear_touches() {
// Updates the OpenGL view when the timer fires
- (void)drawView
{
+ if (useCADisplayLink) {
+ // Pause the CADisplayLink to avoid recursion
+ [displayLink setPaused: YES];
+
+ // Process all input events
+ while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
+
+ // We are good to go, resume the CADisplayLink
+ [displayLink setPaused: NO];
+ }
+
if (!active) {
printf("draw view not active!\n");
return;
@@ -375,9 +519,11 @@ static void clear_touches() {
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
+#ifdef DEBUG_ENABLED
GLenum err = glGetError();
if(err)
NSLog(@"%x error", err);
+#endif
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
@@ -478,6 +624,39 @@ static void clear_touches() {
printf("inserting text with character %i\n", character[0]);
};
+- (void)audioRouteChangeListenerCallback:(NSNotification*)notification
+{
+ printf("*********** route changed!\n");
+ NSDictionary *interuptionDict = notification.userInfo;
+
+ NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
+
+ switch (routeChangeReason) {
+
+ case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
+ NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable");
+ NSLog(@"Headphone/Line plugged in");
+ break;
+
+ case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
+ NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable");
+ NSLog(@"Headphone/Line was pulled. Resuming video play....");
+ 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
+ NSLog(@"resumed play");
+ });
+ };
+ break;
+
+ case AVAudioSessionRouteChangeReasonCategoryChange:
+ // called at start - also when other audio wants to play
+ NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
+ break;
+ }
+}
+
// When created via code however, we get initWithFrame
-(id)initWithFrame:(CGRect)frame
@@ -493,6 +672,11 @@ static void clear_touches() {
init_touches();
self. multipleTouchEnabled = YES;
+ printf("******** adding observer for sound routing changes\n");
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:)
+ name:AVAudioSessionRouteChangeNotification
+ object:nil];
+
//self.autoresizesSubviews = YES;
//[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
@@ -523,6 +707,44 @@ static void clear_touches() {
[super dealloc];
}
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
+ change:(NSDictionary *)change context:(void *)context {
+
+ if (object == _instance.avPlayerItem && [keyPath isEqualToString:@"status"]) {
+ if (_instance.avPlayerItem.status == AVPlayerStatusFailed || _instance.avPlayer.status == AVPlayerStatusFailed) {
+ _stop_video();
+ video_found_error = true;
+ }
+
+ if(_instance.avPlayer.status == AVPlayerStatusReadyToPlay &&
+ _instance.avPlayerItem.status == AVPlayerItemStatusReadyToPlay &&
+ CMTIME_COMPARE_INLINE(video_current_time, ==, kCMTimeZero)) {
+
+ //NSLog(@"time: %@", video_current_time);
+
+ [_instance.avPlayer seekToTime:video_current_time];
+ video_current_time = kCMTimeZero;
+ }
+ }
+
+ if (object == _instance.avPlayer && [keyPath isEqualToString:@"rate"]) {
+ NSLog(@"Player playback rate changed: %.5f", _instance.avPlayer.rate);
+ if (_is_video_playing() && _instance.avPlayer.rate == 0.0 && !_instance.avPlayer.error) {
+ 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
+ NSLog(@"resumed play");
+ });
+
+ NSLog(@" . . . PAUSED (or just started)");
+ }
+ }
+}
+
+- (void)playerItemDidReachEnd:(NSNotification *)notification {
+ _stop_video();
+}
+
+/*
- (void)moviePlayBackDidFinish:(NSNotification*)notification {
@@ -554,8 +776,9 @@ static void clear_touches() {
[_instance.moviePlayerController stop];
[_instance.moviePlayerController.view removeFromSuperview];
- [[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
+ //[[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
video_playing = false;
}
+*/
@end
diff --git a/platform/iphone/globals/global_defaults.cpp b/platform/iphone/globals/global_defaults.cpp
index 63463ab366..18a51a5b4e 100644..100755
--- a/platform/iphone/globals/global_defaults.cpp
+++ b/platform/iphone/globals/global_defaults.cpp
@@ -6,6 +6,8 @@
void register_iphone_global_defaults() {
GLOBAL_DEF("rasterizer.iOS/use_fragment_lighting",false);
+ 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 b86af007f8..f0cb929429 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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..ca21f62ba1
--- /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-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. */
+/*************************************************************************/
+#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..518385992d
--- /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-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. */
+/*************************************************************************/
+#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 dba1a1a5a1..585cd19538 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,6 +49,8 @@ public:
int get_pending_event_count();
Variant pop_pending_event();
+ void finish_transaction(String product_id);
+ void set_auto_finish_transaction(bool b);
void _post_event(Variant p_event);
void _record_purchase(String product_id);
diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm
index 9b932d147b..f689123c81 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,12 +28,20 @@
/*************************************************************************/
#ifdef STOREKIT_ENABLED
+#ifdef MODULE_FUSEBOXX_ENABLED
+#import "modules/fuseboxx/ios/FuseSDK.h"
+#endif
+
#include "in_app_store.h"
extern "C" {
#import <StoreKit/StoreKit.h>
+#import <Foundation/Foundation.h>
};
+bool auto_finish_transactions = true;
+NSMutableDictionary* pending_transactions = [NSMutableDictionary dictionary];
+
@interface SKProduct (LocalizedPrice)
@property (nonatomic, readonly) NSString *localizedPrice;
@end
@@ -63,6 +71,8 @@ void InAppStore::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&InAppStore::get_pending_event_count);
ObjectTypeDB::bind_method(_MD("pop_pending_event"),&InAppStore::pop_pending_event);
+ ObjectTypeDB::bind_method(_MD("finish_transaction"),&InAppStore::finish_transaction);
+ ObjectTypeDB::bind_method(_MD("set_auto_finish_transaction"),&InAppStore::set_auto_finish_transaction);
};
@interface ProductsDelegate : NSObject<SKProductsRequestDelegate> {
@@ -162,11 +172,13 @@ Error InAppStore::request_product_info(Variant p_params) {
case SKPaymentTransactionStatePurchased: {
printf("status purchased!\n");
String pid = String::utf8([transaction.payment.productIdentifier UTF8String]);
+ String transactionId = String::utf8([transaction.transactionIdentifier UTF8String]);
InAppStore::get_singleton()->_record_purchase(pid);
Dictionary ret;
ret["type"] = "purchase";
ret["result"] = "ok";
ret["product_id"] = pid;
+ ret["transaction_id"] = transactionId;
NSData* receipt = nil;
int sdk_version = 6;
@@ -202,12 +214,23 @@ Error InAppStore::request_product_info(Variant p_params) {
receipt_to_send = [receipt description];
}
Dictionary receipt_ret;
- receipt_ret["receipt"] = String::utf8([receipt_to_send UTF8String]);
+ receipt_ret["receipt"] = String::utf8(receipt_to_send != nil ? [receipt_to_send UTF8String] : "");
receipt_ret["sdk"] = sdk_version;
ret["receipt"] = receipt_ret;
InAppStore::get_singleton()->_post_event(ret);
- [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
+
+ if (auto_finish_transactions){
+ [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
+ }
+ 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");
@@ -290,11 +313,26 @@ InAppStore* InAppStore::get_singleton() {
InAppStore::InAppStore() {
ERR_FAIL_COND(instance != NULL);
instance = this;
+ auto_finish_transactions = false;
TransObserver* observer = [[TransObserver alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
+ //pending_transactions = [NSMutableDictionary dictionary];
+};
+
+void InAppStore::finish_transaction(String product_id){
+ NSString* prod_id = [NSString stringWithCString:product_id.utf8().get_data() encoding:NSUTF8StringEncoding];
+
+ if ([pending_transactions objectForKey:prod_id]){
+ [[SKPaymentQueue defaultQueue] finishTransaction:[pending_transactions objectForKey:prod_id]];
+ [pending_transactions removeObjectForKey:prod_id];
+ }
};
+void InAppStore::set_auto_finish_transaction(bool b){
+ auto_finish_transactions = b;
+}
+
InAppStore::~InAppStore() {
};
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index ba93df994b..3db5e1d215 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,7 @@
#include "os_iphone.h"
#include "drivers/gles2/rasterizer_gles2.h"
-#include "drivers/gles1/rasterizer_gles1.h"
+
#include "servers/visual/visual_server_raster.h"
#include "servers/visual/visual_server_wrap_mt.h"
@@ -40,6 +40,7 @@
#include "audio_driver_iphone.h"
#include "core/os/dir_access.h"
+#include "core/os/file_access.h"
#include "core/globals.h"
#include "sem_iphone.h"
@@ -51,7 +52,7 @@ int OSIPhone::get_video_driver_count() const {
const char * OSIPhone::get_video_driver_name(int p_driver) const {
- return "openglES";
+ return "GLES2";
};
OSIPhone* OSIPhone::get_singleton() {
@@ -77,7 +78,7 @@ void OSIPhone::set_data_dir(String p_dir) {
DirAccess* da = DirAccess::open(p_dir);
data_dir = da->get_current_dir();
-
+ printf("setting data dir to %ls from %ls\n", data_dir.c_str(), p_dir.c_str());
memdelete(da);
};
@@ -105,13 +106,9 @@ void OSIPhone::initialize(const VideoMode& p_desired,int p_video_driver,int p_au
supported_orientations |= ((GLOBAL_DEF("video_mode/allow_vertical", false)?1:0) << PortraitDown);
supported_orientations |= ((GLOBAL_DEF("video_mode/allow_vertical_flipped", false)?1:0) << PortraitUp);
-#ifdef GLES1_OVERRIDE
- rasterizer = memnew( RasterizerGLES1 );
-#else
rasterizer_gles22 = memnew( RasterizerGLES2(false, false, false) );
rasterizer = rasterizer_gles22;
rasterizer_gles22->set_base_framebuffer(gl_view_base_fb);
-#endif
visual_server = memnew( VisualServerRaster(rasterizer) );
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
@@ -139,7 +136,8 @@ void OSIPhone::initialize(const VideoMode& p_desired,int p_video_driver,int p_au
//
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ //physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
input = memnew( InputDefault );
@@ -162,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 {
@@ -211,14 +215,16 @@ void OSIPhone::key(uint32_t p_key, bool p_pressed) {
void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse) {
- InputEvent ev;
- ev.type = InputEvent::SCREEN_TOUCH;
- ev.ID = ++last_event_id;
- ev.screen_touch.index=p_idx;
- ev.screen_touch.pressed=p_pressed;
- ev.screen_touch.x=p_x;
- ev.screen_touch.y=p_y;
- queue_event(ev);
+ if (!GLOBAL_DEF("debug/disable_touch", false)) {
+ InputEvent ev;
+ ev.type = InputEvent::SCREEN_TOUCH;
+ ev.ID = ++last_event_id;
+ ev.screen_touch.index=p_idx;
+ ev.screen_touch.pressed=p_pressed;
+ ev.screen_touch.x=p_x;
+ ev.screen_touch.y=p_y;
+ queue_event(ev);
+ };
mouse_list.pressed[p_idx] = p_pressed;
@@ -236,6 +242,7 @@ 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;
+ 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;
@@ -246,15 +253,18 @@ void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_
void OSIPhone::mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse) {
- InputEvent ev;
- ev.type=InputEvent::SCREEN_DRAG;
- ev.ID = ++last_event_id;
- ev.screen_drag.index=p_idx;
- ev.screen_drag.x=p_x;
- ev.screen_drag.y=p_y;
- ev.screen_drag.relative_x = p_x - p_prev_x;
- ev.screen_drag.relative_y = p_y - p_prev_y;
- queue_event(ev);
+ if (!GLOBAL_DEF("debug/disable_touch", false)) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_DRAG;
+ ev.ID = ++last_event_id;
+ ev.screen_drag.index=p_idx;
+ ev.screen_drag.x=p_x;
+ ev.screen_drag.y=p_y;
+ ev.screen_drag.relative_x = p_x - p_prev_x;
+ ev.screen_drag.relative_y = p_y - p_prev_y;
+ queue_event(ev);
+ };
if (p_use_as_mouse) {
InputEvent ev;
@@ -471,6 +481,11 @@ String OSIPhone::get_name() {
return "iOS";
};
+Size2 OSIPhone::get_window_size() const {
+
+ return Vector2(video_mode.width, video_mode.height);
+}
+
bool OSIPhone::has_touchscreen_ui_hint() const {
return true;
@@ -485,13 +500,22 @@ String OSIPhone::get_locale() const {
return locale_code;
}
-extern bool _play_video(String p_path, float p_volume);
+extern bool _play_video(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
extern bool _is_video_playing();
extern void _pause_video();
+extern void _unpause_video();
extern void _stop_video();
-
-Error OSIPhone::native_video_play(String p_path, float p_volume) {
- if ( _play_video(p_path, p_volume) )
+extern void _focus_out_video();
+
+Error OSIPhone::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
+ FileAccess* f = FileAccess::open(p_path, FileAccess::READ);
+ bool exists = f && f->is_open();
+ printf("file exists for %ls, %i, %p\n", p_path.c_str(), (int)exists, f);
+ if (f)
+ memdelete(f);
+ if (!exists)
+ return FAILED;
+ if ( _play_video(p_path, p_volume, p_audio_track, p_subtitle_track) )
return OK;
return FAILED;
}
@@ -505,6 +529,14 @@ void OSIPhone::native_video_pause() {
_pause_video();
}
+void OSIPhone::native_video_unpause() {
+ _unpause_video();
+};
+
+void OSIPhone::native_video_focus_out() {
+ _focus_out_video();
+};
+
void OSIPhone::native_video_stop() {
if (native_video_is_playing())
_stop_video();
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 14b46816e9..06a67b0cfd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,12 +38,16 @@
#include "servers/visual/rasterizer.h"
#include "servers/physics/physics_server_sw.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_wrap_mt.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 "game_center.h"
#include "in_app_store.h"
+#include "icloud.h"
+
class AudioDriverIphone;
class RasterizerGLES2;
@@ -87,6 +91,9 @@ private:
#ifdef STOREKIT_ENABLED
InAppStore* store_kit;
#endif
+#ifdef ICLOUD_ENABLED
+ ICloud* icloud;
+#endif
MainLoop *main_loop;
@@ -167,6 +174,8 @@ public:
virtual void hide_virtual_keyboard();
virtual void set_cursor_shape(CursorShape p_shape);
+
+ virtual Size2 get_window_size() const;
virtual bool has_touchscreen_ui_hint() const;
@@ -184,9 +193,11 @@ public:
void set_unique_ID(String p_ID);
String get_unique_ID() const;
- virtual Error native_video_play(String p_path, float p_volume);
+ virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
virtual bool native_video_is_playing() const;
virtual void native_video_pause();
+ virtual void native_video_unpause();
+ virtual void native_video_focus_out();
virtual void native_video_stop();
OSIPhone(int width, int height);
diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h
index df50d30f40..3cc74099c0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,5 +28,6 @@
/*************************************************************************/
#include <alloca.h>
#define GLES2_INCLUDE_H <ES2/gl.h>
-#define GLES1_INCLUDE_H <ES1/gl.h>
+
+#define PLATFORM_REFCOUNT
diff --git a/platform/iphone/platform_refcount.h b/platform/iphone/platform_refcount.h
new file mode 100644
index 0000000000..45391e651a
--- /dev/null
+++ b/platform/iphone/platform_refcount.h
@@ -0,0 +1,18 @@
+#include "safe_refcount.h"
+
+#ifdef IPHONE_ENABLED
+
+#define REFCOUNT_T int
+#define REFCOUNT_GET_T int const volatile&
+
+#include <libkern/OSAtomic.h>
+
+inline int atomic_conditional_increment(volatile int* v) {
+ return (*v==0)? 0 : OSAtomicIncrement32(v);
+}
+
+inline int atomic_decrement(volatile int* v) {
+ return OSAtomicDecrement32(v);
+}
+
+#endif
diff --git a/platform/iphone/rasterizer_iphone.cpp b/platform/iphone/rasterizer_iphone.cpp
index 4674a5143c..d2a0777af8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/iphone/rasterizer_iphone.h b/platform/iphone/rasterizer_iphone.h
index 41dbbdaa5a..2a630e597a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/iphone/sem_iphone.cpp b/platform/iphone/sem_iphone.cpp
index 5afaa7b308..36baa40427 100644
--- a/platform/iphone/sem_iphone.cpp
+++ b/platform/iphone/sem_iphone.cpp
@@ -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/view_controller.h b/platform/iphone/view_controller.h
index 7c4a107bb8..0cee2f6fbf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,8 +27,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#import <UIKit/UIKit.h>
+#import <GameKit/GameKit.h>
-@interface ViewController : UIViewController {
+@interface ViewController : UIViewController <GKGameCenterControllerDelegate> {
};
diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm
index eb331a61de..f98fb7c355 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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"];
@@ -124,10 +127,17 @@ int add_cmdline(int p_argc, char** p_args) {
}
};
-
- (BOOL)prefersStatusBarHidden
{
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/SCsub b/platform/isim/SCsub
index e7de935b2e..2bd65cb49b 100644
--- a/platform/isim/SCsub
+++ b/platform/isim/SCsub
@@ -25,8 +25,6 @@ env_ios = env.Clone();
if env['ios_gles22_override'] == "yes":
env_ios.Append(CPPFLAGS=['-DGLES2_OVERRIDE'])
-if env['ios_GLES1_override'] == "yes":
- env_ios.Append(CPPFLAGS=['-DGLES1_OVERRIDE'])
if env['ios_appirater'] == "yes":
env_ios.Append(CPPFLAGS=['-DAPPIRATER_ENABLED'])
@@ -34,11 +32,4 @@ if env['ios_appirater'] == "yes":
obj = env_ios.Object('#platform/iphone/godot_iphone.cpp')
prog = None
-if env["target"]=="release":
- prog = env_ios.Program('#bin/godot_opt', [obj] + iphone_lib)
- #action = "dsymutil "+File(prog)[0].path+" -o ../build/script_exec/build/Debug-iphoneos/script_exec.app.dSYM"
- #env.AddPostAction(prog, action)
-else:
- prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
- #action = "dsymutil "+File(prog)[0].path+" -o ../build/script_exec/build/Debug-iphoneos/script_exec.app.dSYM"
- #env.AddPostAction(prog, action)
+prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
diff --git a/platform/isim/detect.py b/platform/isim/detect.py
index c89ca81167..bd0fd2fea3 100644
--- a/platform/isim/detect.py
+++ b/platform/isim/detect.py
@@ -22,7 +22,7 @@ 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}7.0.sdk'),
+ ('ISIMSDK', 'path to the iphone SDK', '$ISIMPATH/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'),
@@ -34,9 +34,7 @@ def get_opts():
def get_flags():
return [
- ('lua', 'no'),
('tools', 'yes'),
- ('nedmalloc', 'no'),
('webp', 'yes'),
]
@@ -46,10 +44,6 @@ def configure(env):
env.Append(CPPPATH=['#platform/iphone'])
- env['OBJSUFFIX'] = ".isim.o"
- env['LIBSUFFIX'] = ".isim.a"
- env['PROGSUFFIX'] = ".isim"
-
env['ENV']['PATH'] = env['ISIMPATH']+"/Developer/usr/bin/:"+env['ENV']['PATH']
env['CC'] = '$ISIMPATH/Developer/usr/bin/gcc'
@@ -66,14 +60,18 @@ def configure(env):
'-Xlinker',
'-objc_abi_version',
'-Xlinker', '2',
+ '-framework', 'AudioToolbox',
+ '-framework', 'AVFoundation',
+ '-framework', 'CoreAudio',
+ '-framework', 'CoreGraphics',
+ '-framework', 'CoreMedia',
'-framework', 'Foundation',
+ '-framework', 'Security',
'-framework', 'UIKit',
- '-framework', 'IOKit',
- '-framework', 'CoreGraphics',
+ '-framework', 'MediaPlayer',
'-framework', 'OpenGLES',
'-framework', 'QuartzCore',
- '-framework', 'AudioToolbox',
- '-framework', 'MediaPlayer',
+ '-framework', 'SystemConfiguration',
'-F$ISIMSDK',
])
@@ -83,8 +81,6 @@ def configure(env):
env.Append(CCFLAGS=['-O3', '-ffast-math'])
env.Append(LINKFLAGS=['-O3', '-ffast-math'])
- env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
elif (env["target"]=="debug"):
@@ -99,8 +95,6 @@ def configure(env):
env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate'
- env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-fno-exceptions'])
+ env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-fexceptions'])
- if env['lua'] == "yes":
- env.Append(CCFLAGS=['-DLUA_USE_FLOAT'])
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index fd1bb39e90..cd96cf4f31 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -3,11 +3,10 @@ Import('env')
javascript_files = [
"os_javascript.cpp",
"audio_driver_javascript.cpp",
- "javascript_main.cpp"
+ "javascript_main.cpp",
+ "audio_server_javascript.cpp"
]
-#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
-
#obj = env.SharedObject('godot_javascript.cpp')
env_javascript = env.Clone()
@@ -18,8 +17,10 @@ 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])
-env.Program('#bin/godot.html', javascript_objects)
+env.Program('#bin/godot',javascript_objects,PROGSUFFIX=env["PROGSUFFIX"]+".html")
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index 2a77806fb3..cc053cf136 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index 9fe93c56ac..0356ca87f9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/javascript/audio_server_javascript.cpp b/platform/javascript/audio_server_javascript.cpp
new file mode 100644
index 0000000000..a2c6740eaf
--- /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 String& p_description) 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..450237d324
--- /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 String& p_description) 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 e4cdaad313..ec21bf6ee4 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -10,9 +10,9 @@ def get_name():
def can_build():
- import os
- if (not os.environ.has_key("EMSCRIPTEN_ROOT")):
- return False
+ import os
+ if (not os.environ.has_key("EMSCRIPTEN_ROOT")):
+ return False
return True
def get_opts():
@@ -30,12 +30,12 @@ def get_flags():
('theora', 'no'),
('tools', 'no'),
('nedmalloc', 'no'),
- ('vorbis', 'no'),
('musepack', 'no'),
('squirrel', 'no'),
('squish', 'no'),
('speex', 'no'),
('old_scenes', 'no'),
+ ('etc1', 'no'),
# ('default_gui_theme', 'no'),
#('builtin_zlib', 'no'),
@@ -44,44 +44,41 @@ def get_flags():
def configure(env):
+ env.Append(CPPPATH=['#platform/javascript'])
-
- env.Append(CPPPATH=['#platform/android'])
-
- env['OBJSUFFIX'] = ".js.o"
- env['LIBSUFFIX'] = ".js.a"
- env['PROGSUFFIX'] = ".html"
-
em_path=os.environ["EMSCRIPTEN_ROOT"]
-
+
env['ENV']['PATH'] = em_path+":"+env['ENV']['PATH']
env['CC'] = em_path+'/emcc'
env['CXX'] = em_path+'/emcc'
- env['AR'] = em_path+"/emar"
- env['RANLIB'] = em_path+"/emranlib"
+ #env['AR'] = em_path+"/emar"
+ env['AR'] = em_path+"/emcc"
+ env['ARFLAGS'] = "-o"
+
+# env['RANLIB'] = em_path+"/emranlib"
+ env['RANLIB'] = em_path + "/emcc"
+ env['OBJSUFFIX'] = '.bc'
+ env['LIBSUFFIX'] = '.bc'
+ env['CCCOM'] = "$CC -o $TARGET $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES"
+ env['CXXCOM'] = "$CC -o $TARGET $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES"
# env.Append(LIBS=['c','m','stdc++','log','GLESv1_CM','GLESv2'])
# env["LINKFLAGS"]= string.split(" -g --sysroot="+ld_sysroot+" -Wl,--no-undefined -Wl,-z,noexecstack ")
if (env["target"]=="release"):
-
env.Append(CCFLAGS=['-O2'])
- env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
-
elif (env["target"]=="release_debug"):
-
env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED'])
- env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
-
elif (env["target"]=="debug"):
-
env.Append(CCFLAGS=['-D_DEBUG', '-Wall', '-O2', '-DDEBUG_ENABLED'])
+ #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=['-DGLES2_ENABLED'])
@@ -93,10 +90,11 @@ def configure(env):
lzma_binpath = em_path+"/third_party/lzma.js/lzma-native"
lzma_decoder = em_path+"/third_party/lzma.js/lzma-decoder.js"
lzma_dec = "LZMA.decompress"
-
env.Append(LINKFLAGS=['--compression',lzma_binpath+","+lzma_decoder+","+lzma_dec])
env.Append(LINKFLAGS=['-s','ASM_JS=1'])
env.Append(LINKFLAGS=['-O2'])
-
-
+ #env.Append(LINKFLAGS=['-g4'])
+
+ #print "CCCOM is:", env.subst('$CCCOM')
+ #print "P: ", env['p'], " Platofrm: ", env['platform']
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 928d128799..acbcbb4652 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -126,8 +126,8 @@ bool EditorExportPlatformJavaScript::_get(const StringName& p_name,Variant &r_re
}
void EditorExportPlatformJavaScript::_get_property_list( List<PropertyInfo> *p_list) const{
- p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_FILE,"zip"));
- p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE,"zip"));
p_list->push_back( PropertyInfo( Variant::INT, "options/memory_size",PROPERTY_HINT_ENUM,"32mb,64mb,128mb,256mb,512mb,1024mb"));
p_list->push_back( PropertyInfo( Variant::BOOL, "browser/enable_run"));
@@ -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 2b575c9149..a126675983 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index 81485bab8e..fb87dc848e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 581df84925..ae97bf990b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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");
@@ -230,6 +231,12 @@ OS::VideoMode OS_JavaScript::get_video_mode(int p_screen) const {
return default_videomode;
}
+
+Size2 OS_JavaScript::get_window_size() const {
+
+ return Vector2(default_videomode.width,default_videomode.height);
+}
+
void OS_JavaScript::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
p_list->push_back(default_videomode);
@@ -264,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();
}
@@ -556,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) {
@@ -583,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 dfc93d3ff0..1e925fb8df 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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, ... );
@@ -127,6 +133,7 @@ public:
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 Size2 get_window_size() const;
virtual String get_name();
virtual MainLoop *get_main_loop() const;
diff --git a/platform/javascript/platform_config.h b/platform/javascript/platform_config.h
index 38fc934ae4..1e7d066bb9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/audio_driver_nacl.cpp b/platform/nacl/audio_driver_nacl.cpp
index 8f1861eee3..27197ad2b2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/audio_driver_nacl.h b/platform/nacl/audio_driver_nacl.h
index 4a45d0bb4b..be5a4cba67 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/context_gl_nacl.cpp b/platform/nacl/context_gl_nacl.cpp
index 70cf01a16e..8ba3fe49d2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/context_gl_nacl.h b/platform/nacl/context_gl_nacl.h
index a5cf7a728c..18da070e35 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/geturl_handler.cpp b/platform/nacl/geturl_handler.cpp
index 4873d691ce..40583891a9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/geturl_handler.h b/platform/nacl/geturl_handler.h
index 44086ae7c1..901210febd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/godot_module.cpp b/platform/nacl/godot_module.cpp
index b5a049d9bf..490edf62cd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/godot_nacl.cpp b/platform/nacl/godot_nacl.cpp
index 753f4124f8..7302a0b5d5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 1cbf379078..b8ff5874cf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/opengl_context.cpp b/platform/nacl/opengl_context.cpp
index 8dafe959a3..285e8df9ce 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/opengl_context.h b/platform/nacl/opengl_context.h
index b0431f29bf..6c73873f4b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/os_nacl.cpp b/platform/nacl/os_nacl.cpp
index d97195c50d..b282209d72 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -64,7 +64,7 @@ int OSNacl::get_video_driver_count() const {
};
const char * OSNacl::get_video_driver_name(int p_driver) const {
- return "gles2";
+ return "GLES2";
};
OS::VideoMode OSNacl::get_default_video_mode() const {
@@ -240,10 +240,14 @@ MainLoop *OSNacl::get_main_loop() const {
return main_loop;
};
-OS::Date OSNacl::get_date() const {
+OS::Date OSNacl::get_date(bool utc) const {
time_t t=time(NULL);
- struct tm *lt=localtime(&t);
+ struct tm *lt;
+ if (utc)
+ lt=gmtime(&t);
+ else
+ lt=localtime(&t);
Date ret;
ret.year=lt->tm_year;
ret.month=(Month)lt->tm_mon;
@@ -254,10 +258,14 @@ OS::Date OSNacl::get_date() const {
return ret;
};
-OS::Time OSNacl::get_time() const {
+OS::Time OSNacl::get_time(bool utc) const {
time_t t=time(NULL);
- struct tm *lt=localtime(&t);
+ struct tm *lt;
+ if (utc)
+ lt=gmtime(&t);
+ else
+ lt=localtime(&t);
Time ret;
ret.hour=lt->tm_hour;
ret.min=lt->tm_min;
@@ -265,6 +273,32 @@ OS::Time OSNacl::get_time() const {
return ret;
};
+OS::TimeZoneInfo OS_Unix::get_time_zone_info() const {
+ time_t t = time(NULL);
+ struct tm *lt = localtime(&t);
+ char name[16];
+ strftime(name, 16, "%Z", lt);
+ name[15] = 0;
+ TimeZoneInfo ret;
+ ret.name = name;
+
+ char bias_buf[16];
+ strftime(bias_buf, 16, "%z", lt);
+ int bias;
+ bias_buf[15] = 0;
+ sscanf(bias_buf, "%d", &bias);
+
+ // convert from ISO 8601 (1 minute=1, 1 hour=100) to minutes
+ int hour = (int)bias / 100;
+ int minutes = bias % 100;
+ if (bias < 0)
+ ret.bias = hour * 60 - minutes;
+ else
+ ret.bias = hour * 60 + minutes;
+
+ return ret;
+};
+
void OSNacl::delay_usec(uint32_t p_usec) const {
//usleep(p_usec);
diff --git a/platform/nacl/os_nacl.h b/platform/nacl/os_nacl.h
index b8173ef61c..e033abb68d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -137,8 +137,8 @@ public:
virtual MainLoop *get_main_loop() const;
- virtual Date get_date() const;
- virtual Time get_time() const;
+ virtual Date get_date(bool utc) const;
+ virtual Time get_time(bool utc) const;
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
diff --git a/platform/nacl/pepper_main.cpp b/platform/nacl/pepper_main.cpp
index 6a1f4acbe7..406d84419b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/nacl/platform_config.h b/platform/nacl/platform_config.h
index 38fc934ae4..1e7d066bb9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index d7839d7d65..4904636afd 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -8,4 +8,4 @@ files = [
# 'context_gl_osx.cpp',
]
-env.Program('#bin/godot_osx',files)
+env.Program('#bin/godot',files)
diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp
index 8f28e8ff63..6904b7a398 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -101,7 +101,16 @@ OSStatus AudioDriverOSX::output_callback(void *inRefCon,
AudioBuffer *abuf;
AudioDriverOSX* ad = (AudioDriverOSX*)inRefCon;
- if (!ad->active) {
+ bool mix = true;
+
+ if (!ad->active)
+ mix = false;
+ else if (ad->mutex) {
+ mix = ad->mutex->try_lock() == OK;
+ };
+
+
+ if (!mix) {
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
abuf = &ioData->mBuffers[i];
zeromem(abuf->mData, abuf->mDataByteSize);
@@ -120,9 +129,9 @@ OSStatus AudioDriverOSX::output_callback(void *inRefCon,
while (frames_left) {
int frames = MIN(frames_left, ad->buffer_frames);
- ad->lock();
+ //ad->lock();
ad->audio_server_process(frames, ad->samples_in);
- ad->unlock();
+ //ad->unlock();
for(int i = 0; i < frames * ad->channels; i++) {
@@ -134,6 +143,9 @@ OSStatus AudioDriverOSX::output_callback(void *inRefCon,
};
};
+ if (ad->mutex)
+ ad->mutex->unlock();
+
return 0;
};
@@ -149,12 +161,27 @@ AudioDriverSW::OutputFormat AudioDriverOSX::get_output_format() const {
return OUTPUT_STEREO;
};
-void AudioDriverOSX::lock() {};
-void AudioDriverOSX::unlock() {};
+void AudioDriverOSX::lock() {
+ if (active && mutex)
+ mutex->lock();
+};
+void AudioDriverOSX::unlock() {
+ if (active && mutex)
+ mutex->unlock();
+};
void AudioDriverOSX::finish() {
memdelete_arr(samples_in);
};
+AudioDriverOSX::AudioDriverOSX() {
+
+ mutex=Mutex::create();//NULL;
+};
+
+AudioDriverOSX::~AudioDriverOSX() {
+
+};
+
#endif
diff --git a/platform/osx/audio_driver_osx.h b/platform/osx/audio_driver_osx.h
index daa388fb86..bcf6b23864 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,6 +39,7 @@ class AudioDriverOSX : public AudioDriverSW {
AudioComponentInstance audio_unit;
bool active;
+ Mutex *mutex;
int channels;
int32_t* samples_in;
@@ -64,6 +65,9 @@ public:
virtual void lock();
virtual void unlock();
virtual void finish();
+
+ AudioDriverOSX();
+ ~AudioDriverOSX();
};
#endif
diff --git a/platform/osx/context_gl_osx.cpp b/platform/osx/context_gl_osx.cpp
index 9c2cd16b49..f856e1e4a8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/osx/context_gl_osx.h b/platform/osx/context_gl_osx.h
index 54da42b331..770ec74737 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 5337416074..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'),
]
@@ -38,45 +40,52 @@ def configure(env):
env.Append(CPPPATH=['#platform/osx'])
- if (env["tools"]=="no"):
- #no tools suffix
- env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+ if (env["bits"]=="default"):
+ env["bits"]="32"
if (env["target"]=="release"):
env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer','-ftree-vectorize','-msse2'])
- env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
elif (env["target"]=="release_debug"):
env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED'])
- env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
elif (env["target"]=="debug"):
env.Append(CCFLAGS=['-g3', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
- elif (env["target"]=="profile"):
- env.Append(CCFLAGS=['-g','-pg'])
- env.Append(LINKFLAGS=['-pg'])
-
if (env["freetype"]!="no"):
env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
env.Append(CPPPATH=['#tools/freetype'])
env.Append(CPPPATH=['#tools/freetype/freetype/include'])
- if (env["force_64_bits"]!="no"):
- env.Append(CCFLAGS=['-arch', 'x86_64'])
- env.Append(LINKFLAGS=['-arch', 'x86_64'])
- env['OBJSUFFIX'] = ".64"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".64"+env['LIBSUFFIX']
+
+
+ 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'])
@@ -90,12 +99,15 @@ def configure(env):
env.Append(LIBS=['pthread'])
#env.Append(CPPFLAGS=['-F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-mmacosx-version-min=10.4'])
#env.Append(LINKFLAGS=['-mmacosx-version-min=10.4', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk'])
- env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit','-lz'])
+ env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit','-lz'])
if (env["CXX"]=="clang++"):
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
env["CC"]="clang"
env["LD"]="clang++"
+ if (env["colored"]=="yes"):
+ if sys.stdout.isatty():
+ env.Append(CPPFLAGS=["-fcolor-diagnostics"])
import methods
@@ -104,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/export/export.cpp b/platform/osx/export/export.cpp
index 087a648700..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;
@@ -138,8 +138,8 @@ bool EditorExportPlatformOSX::_get(const StringName& p_name,Variant &r_ret) cons
}
void EditorExportPlatformOSX::_get_property_list( List<PropertyInfo> *p_list) const{
- p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_FILE,"zip"));
- p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE,"zip"));
p_list->push_back( PropertyInfo( Variant::STRING, "application/name") );
p_list->push_back( PropertyInfo( Variant::STRING, "application/info") );
@@ -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 3546c1e71a..92fa6ddbc2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/osx/godot_osx.h b/platform/osx/godot_osx.h
index ebac475089..270ba9966f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/osx/godot_osx.mm b/platform/osx/godot_osx.mm
index fb3c5808c7..39119393ff 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 5b203f1560..e8277688ac 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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"
@@ -44,6 +44,7 @@
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include "platform/osx/audio_driver_osx.h"
#include <ApplicationServices/ApplicationServices.h>
@@ -99,6 +100,13 @@ public:
CursorShape cursor_shape;
MouseMode mouse_mode;
+
+ bool minimized;
+ bool maximized;
+ bool zoomed;
+ Vector<Rect2> screens;
+ int current_screen;
+ Rect2 restore_rect;
protected:
virtual int get_video_driver_count() const;
@@ -112,16 +120,13 @@ protected:
virtual void set_main_loop( MainLoop * p_main_loop );
virtual void delete_main_loop();
-
public:
-
-
-
-
static OS_OSX* singleton;
+ void wm_minimized(bool p_minimized);
+
virtual String get_name();
virtual void set_cursor_shape(CursorShape p_shape);
@@ -129,9 +134,12 @@ public:
virtual void set_mouse_show(bool p_show);
virtual void set_mouse_grab(bool p_grab);
virtual bool is_mouse_grab_enabled() const;
+ virtual void warp_mouse_pos(const Point2& p_to);
virtual Point2 get_mouse_pos() const;
virtual int get_mouse_button_state() const;
virtual void set_window_title(const String& p_title);
+
+ virtual Size2 get_window_size() const;
virtual void set_icon(const Image& p_icon);
@@ -149,14 +157,36 @@ 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;
virtual String get_executable_path() const;
+ virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
virtual void move_window_to_foreground();
+ 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 Point2 get_window_position() const;
+ virtual void set_window_position(const Point2& p_position);
+ virtual void set_window_size(const Size2 p_size);
+ 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;
+ Size2 get_screen_size(int p_screen);
+
+
void run();
void set_mouse_mode(MouseMode p_mode);
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 12f98cebe2..4990d04ab6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,6 +27,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#import <Cocoa/Cocoa.h>
+
+#include <Carbon/Carbon.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDLib.h>
@@ -225,19 +227,6 @@ static int button_mask=0;
// centerCursor(window);
}
-- (void)windowDidMiniaturize:(NSNotification *)notification
-{
- // _GodotInputWindowIconify(window, GL_TRUE);
-}
-
-- (void)windowDidDeminiaturize:(NSNotification *)notification
-{
- //if (window->monitor)
-// enterFullscreenMode(window);
-
- // _GodotInputWindowIconify(window, GL_FALSE);
-}
-
- (void)windowDidBecomeKey:(NSNotification *)notification
{
// _GodotInputWindowFocus(window, GL_TRUE);
@@ -254,6 +243,21 @@ static int button_mask=0;
OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
}
+- (void)windowDidMiniaturize:(NSNotification*)notification
+{
+ OS_OSX::singleton->wm_minimized(true);
+ if (OS_OSX::singleton->get_main_loop())
+ OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+};
+
+- (void)windowDidDeminiaturize:(NSNotification*)notification
+{
+
+ OS_OSX::singleton->wm_minimized(false);
+ if (OS_OSX::singleton->get_main_loop())
+ OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+};
+
@end
@interface GodotContentView : NSView
@@ -508,12 +512,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
@@ -694,7 +712,7 @@ static int translateKey(unsigned int key)
ev.type=InputEvent::KEY;
ev.key.pressed=true;
ev.key.mod=translateFlags([event modifierFlags]);
- ev.key.scancode = translateKey([event keyCode]);
+ ev.key.scancode = latin_keyboard_keycode_convert(translateKey([event keyCode]));
ev.key.echo = [event isARepeat];
NSString* characters = [event characters];
@@ -740,7 +758,7 @@ static int translateKey(unsigned int key)
ev.type=InputEvent::KEY;
ev.key.pressed=false;
ev.key.mod=translateFlags([event modifierFlags]);
- ev.key.scancode = translateKey([event keyCode]);
+ ev.key.scancode = latin_keyboard_keycode_convert(translateKey([event keyCode]));
OS_OSX::singleton->push_input(ev);
@@ -835,11 +853,24 @@ void OS_OSX::initialize_core() {
}
+static bool keyboard_layout_dirty = true;
+static void keyboardLayoutChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
+ keyboard_layout_dirty = true;
+}
+
void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
/*** OSX INITIALIZATION ***/
/*** OSX INITIALIZATION ***/
/*** OSX INITIALIZATION ***/
+
+ keyboard_layout_dirty = true;
+
+ // Register to be notified on keyboard layout changes
+ CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
+ NULL, keyboardLayoutChanged,
+ kTISNotifySelectedKeyboardInputSourceChanged, NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
window_delegate = [[GodotWindowDelegate alloc] init];
@@ -888,7 +919,7 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
unsigned int attributeCount = 0;
// OS X needs non-zero color size, so set resonable values
- int colorBits = 24;
+ int colorBits = 32;
// Fail if a robustness strategy was requested
@@ -949,8 +980,10 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
[NSApp activateIgnoringOtherApps:YES];
- [window_object makeKeyAndOrderFront:nil];
+ [window_object makeKeyAndOrderFront:nil];
+ if (p_desired.fullscreen)
+ zoomed = true;
/*** END OSX INITIALIZATION ***/
/*** END OSX INITIALIZATION ***/
@@ -996,17 +1029,28 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
//
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ //physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
input = memnew( InputDefault );
_ensure_data_dir();
+ NSArray *screenArray = [NSScreen screens];
+ printf("nscreen count %i\n", (int)[screenArray count]);
+ for (int i=0; i<[screenArray count]; i++) {
+ NSRect nsrect = [[screenArray objectAtIndex: i] visibleFrame];
+ screens.push_back(Rect2(nsrect.origin.x, nsrect.origin.y, nsrect.size.width, nsrect.size.height));
+ printf("added screen %i\n", screens.size());
+ };
+ restore_rect = Rect2(get_window_position(), get_window_size());
}
void OS_OSX::finalize() {
+ CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
+
}
void OS_OSX::set_main_loop( MainLoop * p_main_loop ) {
@@ -1067,6 +1111,38 @@ bool OS_OSX::is_mouse_grab_enabled() const {
return mouse_grab;
}
+
+void OS_OSX::warp_mouse_pos(const Point2& p_to) {
+
+ //copied from windows impl with osx native calls
+ if (mouse_mode == MOUSE_MODE_CAPTURED){
+ mouse_x = p_to.x;
+ mouse_y = p_to.y;
+ }
+ else{ //set OS position
+
+ /* this code has not been tested, please be a kind soul and fix it if it fails! */
+
+ //local point in window coords
+ NSPoint localPoint = { p_to.x, p_to.y };
+
+ NSPoint pointInWindow = [window_view convertPoint:localPoint toView:nil];
+ NSRect pointInWindowRect;
+ pointInWindowRect.origin = pointInWindow;
+ NSPoint pointOnScreen = [[window_view window] convertRectToScreen:pointInWindowRect].origin;
+
+ //point in scren coords
+ CGPoint lMouseWarpPos = { pointOnScreen.x, pointOnScreen.y};
+
+ //do the warping
+ CGEventSourceRef lEventRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
+ CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0);
+ CGAssociateMouseAndMouseCursorPosition(false);
+ CGWarpMouseCursorPosition(lMouseWarpPos);
+ CGAssociateMouseAndMouseCursorPosition(true);
+ }
+}
+
Point2 OS_OSX::get_mouse_pos() const {
return Vector2(mouse_x,mouse_y);
@@ -1178,13 +1254,21 @@ 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];
}
+void OS_OSX::wm_minimized(bool p_minimized) {
+ minimized = p_minimized;
+};
void OS_OSX::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
@@ -1198,6 +1282,127 @@ void OS_OSX::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) cons
}
+
+int OS_OSX::get_screen_count() const {
+
+ return screens.size();
+};
+
+int OS_OSX::get_current_screen() const {
+
+ return current_screen;
+};
+
+void OS_OSX::set_current_screen(int p_screen) {
+
+ current_screen = 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;
+};
+
+Size2 OS_OSX::get_screen_size(int p_screen) {
+
+ ERR_FAIL_INDEX_V(p_screen, screens.size(), Point2());
+ return screens[p_screen].size;
+};
+
+Point2 OS_OSX::get_window_position() const {
+
+ return Size2([window_object frame].origin.x, [window_object frame].origin.y);
+};
+
+
+void OS_OSX::set_window_position(const Point2& p_position) {
+
+ [window_object setFrame:NSMakeRect(p_position.x, p_position.y, [window_object frame].size.width, [window_object frame].size.height) display:YES];
+};
+
+Size2 OS_OSX::get_window_size() const {
+
+ return Size2([window_object frame].size.width, [window_object frame].size.height);
+};
+
+void OS_OSX::set_window_size(const Size2 p_size) {
+
+ NSRect frame = [window_object frame];
+ [window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, p_size.x, p_size.y) display:YES];
+};
+
+void OS_OSX::set_window_fullscreen(bool p_enabled) {
+
+ if (zoomed != p_enabled) {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+ [window_object toggleFullScreen:nil];
+#else
+ [window_object performZoom:nil];
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+ }
+ zoomed = p_enabled;
+};
+
+bool OS_OSX::is_window_fullscreen() const {
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
+ if ( [window_object respondsToSelector:@selector(isZoomed)] )
+ return [window_object isZoomed];
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+
+ return zoomed;
+};
+
+void OS_OSX::set_window_resizable(bool p_enabled) {
+
+ if (p_enabled)
+ [window_object setStyleMask:[window_object styleMask] | NSResizableWindowMask ];
+ else
+ [window_object setStyleMask:[window_object styleMask] & ~NSResizableWindowMask ];
+};
+
+bool OS_OSX::is_window_resizable() const {
+
+ return [window_object styleMask] & NSResizableWindowMask;
+};
+
+void OS_OSX::set_window_minimized(bool p_enabled) {
+
+ if (p_enabled)
+ [window_object performMiniaturize:nil];
+ else
+ [window_object deminiaturize:nil];
+};
+
+bool OS_OSX::is_window_minimized() const {
+
+ if ( [window_object respondsToSelector:@selector(isMiniaturized)])
+ return [window_object isMiniaturized];
+
+ return minimized;
+};
+
+
+void OS_OSX::set_window_maximized(bool p_enabled) {
+
+ if (p_enabled) {
+ restore_rect = Rect2(get_window_position(), get_window_size());
+ [window_object setFrame:[[[NSScreen screens] objectAtIndex:current_screen] visibleFrame] display:YES];
+ } else {
+ set_window_size(restore_rect.size);
+ set_window_position(restore_rect.pos);
+ };
+ maximized = p_enabled;
+};
+
+bool OS_OSX::is_window_maximized() const {
+
+ // don't know
+ return maximized;
+};
+
+
void OS_OSX::move_window_to_foreground() {
[window_object orderFrontRegardless];
@@ -1222,6 +1427,83 @@ String OS_OSX::get_executable_path() const {
}
+// Returns string representation of keys, if they are printable.
+//
+static NSString *createStringForKeys(const CGKeyCode *keyCode, int length) {
+
+ TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
+ if (!currentKeyboard)
+ return nil;
+
+ CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
+ if (!layoutData)
+ return nil;
+
+ const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
+
+ OSStatus err;
+ CFMutableStringRef output = CFStringCreateMutable(NULL, 0);
+
+ for (int i=0; i<length; ++i) {
+
+ UInt32 keysDown = 0;
+ UniChar chars[4];
+ UniCharCount realLength;
+
+ err = UCKeyTranslate(keyboardLayout,
+ keyCode[i],
+ kUCKeyActionDisplay,
+ 0,
+ LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysBit,
+ &keysDown,
+ sizeof(chars) / sizeof(chars[0]),
+ &realLength,
+ chars);
+
+ if (err != noErr) {
+ CFRelease(output);
+ return nil;
+ }
+
+ CFStringAppendCharacters(output, chars, 1);
+ }
+
+ //CFStringUppercase(output, NULL);
+
+ return (NSString *)output;
+}
+OS::LatinKeyboardVariant OS_OSX::get_latin_keyboard_variant() const {
+
+ static LatinKeyboardVariant layout = LATIN_KEYBOARD_QWERTY;
+
+ if (keyboard_layout_dirty) {
+
+ layout = LATIN_KEYBOARD_QWERTY;
+
+ CGKeyCode keys[] = {kVK_ANSI_Q, kVK_ANSI_W, kVK_ANSI_E, kVK_ANSI_R, kVK_ANSI_T, kVK_ANSI_Y};
+ NSString *test = createStringForKeys(keys, 6);
+
+ if ([test isEqualToString:@"qwertz"]) {
+ layout = LATIN_KEYBOARD_QWERTZ;
+ } else if ([test isEqualToString:@"azerty"]) {
+ layout = LATIN_KEYBOARD_AZERTY;
+ } else if ([test isEqualToString:@"qzerty"]) {
+ layout = LATIN_KEYBOARD_QZERTY;
+ } else if ([test isEqualToString:@"',.pyf"]) {
+ layout = LATIN_KEYBOARD_DVORAK;
+ } else if ([test isEqualToString:@"xvlcwk"]) {
+ layout = LATIN_KEYBOARD_NEO;
+ }
+
+ [test release];
+
+ keyboard_layout_dirty = false;
+ return layout;
+ }
+
+ return layout;
+}
void OS_OSX::process_events() {
@@ -1259,6 +1541,11 @@ void OS_OSX::run() {
main_loop->init();
+ if (zoomed) {
+ zoomed = false;
+ set_window_fullscreen(true);
+ }
+
// uint64_t last_ticks=get_ticks_usec();
// int frames=0;
@@ -1349,5 +1636,9 @@ OS_OSX::OS_OSX() {
last_id=1;
cursor_shape=CURSOR_ARROW;
+ current_screen = 0;
+ maximized = false;
+ minimized = false;
+ zoomed = false;
}
diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h
index da4265f3cf..285d8d0c02 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/server/detect.py b/platform/server/detect.py
index 1ce8c23229..e2d64c6545 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -28,6 +28,7 @@ def get_flags():
return [
('builtin_zlib', 'no'),
+ ('theora','no'), #use builtin openssl
]
@@ -39,51 +40,40 @@ def configure(env):
env["CC"]="clang"
env["CXX"]="clang++"
env["LD"]="clang++"
+ if (env["colored"]=="yes"):
+ if sys.stdout.isatty():
+ env.Append(CXXFLAGS=["-fcolor-diagnostics"])
- env['OBJSUFFIX'] = ".srv"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".srv"+env['LIBSUFFIX']
+ is64=sys.maxsize > 2**32
- if (env["force_32_bits"]!="no"):
- env['OBJSUFFIX'] = ".32"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".32"+env['LIBSUFFIX']
+ if (env["bits"]=="default"):
+ if (is64):
+ env["bits"]="64"
+ else:
+ env["bits"]="32"
- if (env["tools"]=="no"):
- #no tools suffix
- env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+ #if (env["tools"]=="no"):
+ # #no tools suffix
+ # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
+ # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
if (env["target"]=="release"):
-
+
env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer'])
- env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
elif (env["target"]=="release_debug"):
env.Append(CCFLAGS=['-O2','-ffast-math','-DDEBUG_ENABLED'])
- env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
-
elif (env["target"]=="debug"):
-
- env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
- elif (env["target"]=="profile"):
-
- env.Append(CCFLAGS=['-g','-pg'])
- env.Append(LINKFLAGS=['-pg'])
+ env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
-
env.Append(CPPFLAGS=['-DSERVER_ENABLED','-DUNIX_ENABLED'])
env.Append(LIBS=['pthread','z']) #TODO detect linux/BSD!
- if (env["force_32_bits"]=="yes"):
- env.Append(CPPFLAGS=['-m32'])
- env.Append(LINKFLAGS=['-m32','-L/usr/lib/i386-linux-gnu'])
-
if (env["CXX"]=="clang++"):
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
env["CC"]="clang"
diff --git a/platform/server/godot_server.cpp b/platform/server/godot_server.cpp
index 3f817c7237..41e48302c4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index 7bc8f61744..8b831140d6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,7 +56,6 @@ void OS_Server::initialize(const VideoMode& p_desired,int p_video_driver,int p_a
args=OS::get_singleton()->get_cmdline_args();
current_videomode=p_desired;
main_loop=NULL;
-
rasterizer = memnew( RasterizerDummy );
@@ -108,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);
@@ -163,6 +163,12 @@ OS::VideoMode OS_Server::get_video_mode(int p_screen) const {
return current_videomode;
}
+
+Size2 OS_Server::get_window_size() const {
+
+ return Vector2(current_videomode.width,current_videomode.height) ;
+}
+
void OS_Server::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index fcf96253ad..b3410f7955 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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"
@@ -109,6 +109,8 @@ public:
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 Size2 get_window_size() const;
+
virtual void move_window_to_foreground();
void run();
diff --git a/platform/server/platform_config.h b/platform/server/platform_config.h
index 1bb5afb002..43dda9e64e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 1d454e40c2..f98c1b01ff 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -7,7 +7,20 @@ common_win=[
"ctxgl_procaddr.cpp",
"key_mapping_win.cpp",
"tcp_server_winsock.cpp",
+ "packet_peer_udp_winsock.cpp",
"stream_peer_winsock.cpp",
]
-env.Program('#bin/godot.exe',['godot_win.cpp']+common_win)
+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
+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]
diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
index a8f74fde2c..5a9c8edc63 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/windows/context_gl_win.h b/platform/windows/context_gl_win.h
index 6e8d99a5f0..5397676c8e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/windows/ctxgl_procaddr.cpp b/platform/windows/ctxgl_procaddr.cpp
index 9715784c32..6e5f53eb96 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,161 +26,161 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef OPENGL_ENABLED
-#include "ctxgl_procaddr.h"
-#include <GL/gl.h>
-#include <stdio.h>
-
-static PROC _gl_procs[]={
- (PROC)glCullFace,
- (PROC)glFrontFace,
- (PROC)glHint,
- (PROC)glLineWidth,
- (PROC)glPointSize,
- (PROC)glPolygonMode,
- (PROC)glScissor,
- (PROC)glTexParameterf,
- (PROC)glTexParameterfv,
- (PROC)glTexParameteri,
- (PROC)glTexParameteriv,
- (PROC)glTexImage1D,
- (PROC)glTexImage2D,
- (PROC)glDrawBuffer,
- (PROC)glClear,
- (PROC)glClearColor,
- (PROC)glClearStencil,
- (PROC)glClearDepth,
- (PROC)glStencilMask,
- (PROC)glColorMask,
- (PROC)glDepthMask,
- (PROC)glDisable,
- (PROC)glEnable,
- (PROC)glFinish,
- (PROC)glFlush,
- (PROC)glBlendFunc,
- (PROC)glLogicOp,
- (PROC)glStencilFunc,
- (PROC)glStencilOp,
- (PROC)glDepthFunc,
- (PROC)glPixelStoref,
- (PROC)glPixelStorei,
- (PROC)glReadBuffer,
- (PROC)glReadPixels,
- (PROC)glGetBooleanv,
- (PROC)glGetDoublev,
- (PROC)glGetError,
- (PROC)glGetFloatv,
- (PROC)glGetIntegerv,
- (PROC)glGetString,
- (PROC)glGetTexImage,
- (PROC)glGetTexParameterfv,
- (PROC)glGetTexParameteriv,
- (PROC)glGetTexLevelParameterfv,
- (PROC)glGetTexLevelParameteriv,
- (PROC)glIsEnabled,
- (PROC)glDepthRange,
- (PROC)glViewport,
- /* not detected in ATI */
- (PROC)glDrawArrays,
- (PROC)glDrawElements,
- (PROC)glGetPointerv,
- (PROC)glPolygonOffset,
- (PROC)glCopyTexImage1D,
- (PROC)glCopyTexImage2D,
- (PROC)glCopyTexSubImage1D,
- (PROC)glCopyTexSubImage2D,
- (PROC)glTexSubImage1D,
- (PROC)glTexSubImage2D,
- (PROC)glBindTexture,
- (PROC)glDeleteTextures,
- (PROC)glGenTextures,
- (PROC)glIsTexture,
-
- 0
-};
-
-static const char* _gl_proc_names[]={
- "glCullFace",
- "glFrontFace",
- "glHint",
- "glLineWidth",
- "glPointSize",
- "glPolygonMode",
- "glScissor",
- "glTexParameterf",
- "glTexParameterfv",
- "glTexParameteri",
- "glTexParameteriv",
- "glTexImage1D",
- "glTexImage2D",
- "glDrawBuffer",
- "glClear",
- "glClearColor",
- "glClearStencil",
- "glClearDepth",
- "glStencilMask",
- "glColorMask",
- "glDepthMask",
- "glDisable",
- "glEnable",
- "glFinish",
- "glFlush",
- "glBlendFunc",
- "glLogicOp",
- "glStencilFunc",
- "glStencilOp",
- "glDepthFunc",
- "glPixelStoref",
- "glPixelStorei",
- "glReadBuffer",
- "glReadPixels",
- "glGetBooleanv",
- "glGetDoublev",
- "glGetError",
- "glGetFloatv",
- "glGetIntegerv",
- "glGetString",
- "glGetTexImage",
- "glGetTexParameterfv",
- "glGetTexParameteriv",
- "glGetTexLevelParameterfv",
- "glGetTexLevelParameteriv",
- "glIsEnabled",
- "glDepthRange",
- "glViewport",
- /* not detected in ati */
- "glDrawArrays",
- "glDrawElements",
- "glGetPointerv",
- "glPolygonOffset",
- "glCopyTexImage1D",
- "glCopyTexImage2D",
- "glCopyTexSubImage1D",
- "glCopyTexSubImage2D",
- "glTexSubImage1D",
- "glTexSubImage2D",
- "glBindTexture",
- "glDeleteTextures",
- "glGenTextures",
- "glIsTexture",
-
- 0
-};
-
-PROC get_gl_proc_address(const char* p_address) {
-
- PROC proc = wglGetProcAddress((const CHAR*)p_address);
- if (!proc) {
-
- int i=0;
- while(_gl_procs[i]) {
-
- if (strcmp(p_address,_gl_proc_names[i])==0) {
- return _gl_procs[i];
- }
- i++;
- }
- }
- return proc;
-}
-#endif
+#ifdef OPENGL_ENABLED
+#include "ctxgl_procaddr.h"
+#include <GL/gl.h>
+#include <stdio.h>
+
+static PROC _gl_procs[]={
+ (PROC)glCullFace,
+ (PROC)glFrontFace,
+ (PROC)glHint,
+ (PROC)glLineWidth,
+ (PROC)glPointSize,
+ (PROC)glPolygonMode,
+ (PROC)glScissor,
+ (PROC)glTexParameterf,
+ (PROC)glTexParameterfv,
+ (PROC)glTexParameteri,
+ (PROC)glTexParameteriv,
+ (PROC)glTexImage1D,
+ (PROC)glTexImage2D,
+ (PROC)glDrawBuffer,
+ (PROC)glClear,
+ (PROC)glClearColor,
+ (PROC)glClearStencil,
+ (PROC)glClearDepth,
+ (PROC)glStencilMask,
+ (PROC)glColorMask,
+ (PROC)glDepthMask,
+ (PROC)glDisable,
+ (PROC)glEnable,
+ (PROC)glFinish,
+ (PROC)glFlush,
+ (PROC)glBlendFunc,
+ (PROC)glLogicOp,
+ (PROC)glStencilFunc,
+ (PROC)glStencilOp,
+ (PROC)glDepthFunc,
+ (PROC)glPixelStoref,
+ (PROC)glPixelStorei,
+ (PROC)glReadBuffer,
+ (PROC)glReadPixels,
+ (PROC)glGetBooleanv,
+ (PROC)glGetDoublev,
+ (PROC)glGetError,
+ (PROC)glGetFloatv,
+ (PROC)glGetIntegerv,
+ (PROC)glGetString,
+ (PROC)glGetTexImage,
+ (PROC)glGetTexParameterfv,
+ (PROC)glGetTexParameteriv,
+ (PROC)glGetTexLevelParameterfv,
+ (PROC)glGetTexLevelParameteriv,
+ (PROC)glIsEnabled,
+ (PROC)glDepthRange,
+ (PROC)glViewport,
+ /* not detected in ATI */
+ (PROC)glDrawArrays,
+ (PROC)glDrawElements,
+ (PROC)glGetPointerv,
+ (PROC)glPolygonOffset,
+ (PROC)glCopyTexImage1D,
+ (PROC)glCopyTexImage2D,
+ (PROC)glCopyTexSubImage1D,
+ (PROC)glCopyTexSubImage2D,
+ (PROC)glTexSubImage1D,
+ (PROC)glTexSubImage2D,
+ (PROC)glBindTexture,
+ (PROC)glDeleteTextures,
+ (PROC)glGenTextures,
+ (PROC)glIsTexture,
+
+ 0
+};
+
+static const char* _gl_proc_names[]={
+ "glCullFace",
+ "glFrontFace",
+ "glHint",
+ "glLineWidth",
+ "glPointSize",
+ "glPolygonMode",
+ "glScissor",
+ "glTexParameterf",
+ "glTexParameterfv",
+ "glTexParameteri",
+ "glTexParameteriv",
+ "glTexImage1D",
+ "glTexImage2D",
+ "glDrawBuffer",
+ "glClear",
+ "glClearColor",
+ "glClearStencil",
+ "glClearDepth",
+ "glStencilMask",
+ "glColorMask",
+ "glDepthMask",
+ "glDisable",
+ "glEnable",
+ "glFinish",
+ "glFlush",
+ "glBlendFunc",
+ "glLogicOp",
+ "glStencilFunc",
+ "glStencilOp",
+ "glDepthFunc",
+ "glPixelStoref",
+ "glPixelStorei",
+ "glReadBuffer",
+ "glReadPixels",
+ "glGetBooleanv",
+ "glGetDoublev",
+ "glGetError",
+ "glGetFloatv",
+ "glGetIntegerv",
+ "glGetString",
+ "glGetTexImage",
+ "glGetTexParameterfv",
+ "glGetTexParameteriv",
+ "glGetTexLevelParameterfv",
+ "glGetTexLevelParameteriv",
+ "glIsEnabled",
+ "glDepthRange",
+ "glViewport",
+ /* not detected in ati */
+ "glDrawArrays",
+ "glDrawElements",
+ "glGetPointerv",
+ "glPolygonOffset",
+ "glCopyTexImage1D",
+ "glCopyTexImage2D",
+ "glCopyTexSubImage1D",
+ "glCopyTexSubImage2D",
+ "glTexSubImage1D",
+ "glTexSubImage2D",
+ "glBindTexture",
+ "glDeleteTextures",
+ "glGenTextures",
+ "glIsTexture",
+
+ 0
+};
+
+PROC get_gl_proc_address(const char* p_address) {
+
+ PROC proc = wglGetProcAddress((const CHAR*)p_address);
+ if (!proc) {
+
+ int i=0;
+ while(_gl_procs[i]) {
+
+ if (strcmp(p_address,_gl_proc_names[i])==0) {
+ return _gl_procs[i];
+ }
+ i++;
+ }
+ }
+ return proc;
+}
+#endif
diff --git a/platform/windows/ctxgl_procaddr.h b/platform/windows/ctxgl_procaddr.h
index d3ab20e82d..916b480639 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,13 +26,13 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CTXGL_PROCADDR_H
-#define CTXGL_PROCADDR_H
-
-#ifdef OPENGL_ENABLED
-#include <windows.h>
-
-
-PROC get_gl_proc_address(const char* p_address);
-#endif
-#endif // CTXGL_PROCADDR_H
+#ifndef CTXGL_PROCADDR_H
+#define CTXGL_PROCADDR_H
+
+#ifdef OPENGL_ENABLED
+#include <windows.h>
+
+
+PROC get_gl_proc_address(const char* p_address);
+#endif
+#endif // CTXGL_PROCADDR_H
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 0e21540e13..3193a2acbb 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,213 +1,397 @@
-
-
-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("MSVC Not detected, attempting mingw.")
- return True
-
-
-
- if (os.name=="posix"):
-
- if os.system("i586-mingw32msvc-gcc --version") == 0:
- return True
-
-
- return False
-
-def get_opts():
-
- mwp=""
- mwp64=""
- if (os.name!="nt"):
- mwp="i586-mingw32msvc-"
- mwp64="x86_64-w64-mingw32-"
-
- return [
- ('force_64_bits','Force 64 bits binary','no'),
- ('force_32_bits','Force 32 bits binary','no'),
- ('mingw_prefix','Mingw Prefix',mwp),
- ('mingw_prefix_64','Mingw Prefix 64 bits',mwp64),
- ]
-
-def get_flags():
-
- return [
- ('freetype','builtin'), #use builtin freetype
- ('openssl','builtin'), #use builtin openssl
- ]
-
-
-
-def configure(env):
-
- if os.name == "posix":
- env['OBJSUFFIX'] = ".win"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".win"+env['LIBSUFFIX']
-
- env.Append(CPPPATH=['#platform/windows'])
-
- if (env["tools"]=="no"):
- #no tools suffix
- env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
- #env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
- env['platform_libsuffix'] = ".nt"+env['LIBSUFFIX']
-
-
-
- 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"]=="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','/O1'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- env.Append(LINKFLAGS=['/DEBUG'])
-
- elif (env["target"]=="profile"):
-
- env.Append(CCFLAGS=['-g','-pg'])
- env.Append(LINKFLAGS=['-pg'])
-
- 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=['/DGLES1_ENABLED'])
- env.Append(CCFLAGS=['/DGLEW_ENABLED'])
- env.Append(LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI', 'wsock32', 'shell32','advapi32'])
-
- 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:
- #build using mingw
- if (os.name=="nt"):
- env['ENV']['TMP'] = os.environ['TMP'] #way to go scons, you can be so stupid sometimes
-
- mingw_prefix=""
-
- if (env["force_32_bits"]!="no"):
- env['OBJSUFFIX'] = ".32"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".32"+env['LIBSUFFIX']
- env.Append(CCFLAGS=['-m32'])
- env.Append(LINKFLAGS=['-m32'])
- env.Append(LINKFLAGS=['-static-libgcc'])
- env.Append(LINKFLAGS=['-static-libstdc++'])
-
-
-
-
- if (env["force_64_bits"]!="no"):
- mingw_prefix=env["mingw_prefix_64"];
- env['OBJSUFFIX'] = ".64"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".64"+env['LIBSUFFIX']
- env.Append(LINKFLAGS=['-static'])
- else:
- mingw_prefix=env["mingw_prefix"];
-
- if (env["target"]=="release"):
-
- env.Append(CCFLAGS=['-O3','-ffast-math','-fomit-frame-pointer','-msse2'])
- env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
- elif (env["target"]=="release_debug"):
-
- env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED'])
- env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
-
- elif (env["target"]=="debug"):
-
- env.Append(CCFLAGS=['-g', '-Wall','-DDEBUG_ENABLED'])
- elif (env["target"]=="release_tools"):
-
- env.Append(CCFLAGS=['-O2','-Wall','-DDEBUG_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','-DGLES1_ENABLED','-DGLEW_ENABLED'])
- env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','wsock32','kernel32'])
- #'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','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;
+ env["x86_opt_vc"]=True
+ 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["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'])
+
+ # 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..9cfd475091 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-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 "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..f77182f909
--- /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
+PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,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 \ No newline at end of file
diff --git a/platform/windows/godot_win.cpp b/platform/windows/godot_win.cpp
index fa573b9421..fe39051670 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -115,32 +115,32 @@ PCHAR*
return argv;
}
-char* mb_to_utf8(const char* mbs) {
-
- int wlen = MultiByteToWideChar(CP_ACP,0,mbs,-1,NULL,0); // returns 0 if failed
- wchar_t *wbuf = new wchar_t[wlen + 1];
- MultiByteToWideChar(CP_ACP,0,mbs,-1,wbuf,wlen);
- wbuf[wlen]=0;
-
- int ulen = WideCharToMultiByte(CP_UTF8,0,wbuf,-1,NULL,0,NULL,NULL);
+char* wc_to_utf8(const wchar_t* wc) {
+ int ulen = WideCharToMultiByte(CP_UTF8,0,wc,-1,NULL,0,NULL,NULL);
char * ubuf = new char[ulen + 1];
- WideCharToMultiByte(CP_UTF8,0,wbuf,-1,ubuf,ulen,NULL,NULL);
+ WideCharToMultiByte(CP_UTF8,0,wc,-1,ubuf,ulen,NULL,NULL);
ubuf[ulen] = 0;
return ubuf;
}
-int main(int argc, char** argv) {
+int widechar_main(int argc, wchar_t** argv) {
OS_Windows os(NULL);
setlocale(LC_CTYPE, "");
char ** argv_utf8 = new char*[argc];
+
for(int i=0; i<argc; ++i) {
- argv_utf8[i] = mb_to_utf8(argv[i]);
+ argv_utf8[i] = wc_to_utf8(argv[i]);
}
- Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]);
+ Error err = Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]);
+
+ if (err!=OK)
+ return 255;
+
+
if (Main::start())
os.run();
Main::cleanup();
@@ -154,82 +154,30 @@ int main(int argc, char** argv) {
return os.get_exit_code();
};
-HINSTANCE godot_hinstance = NULL;
-
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
-
- int argc;
- char** argv;
-
- char* arg;
- int index;
- int result;
+int main(int _argc, char** _argv) {
+ // _argc and _argv are ignored
+ // we are going to use the WideChar version of them instead
- // count the arguments
+ LPWSTR *wc_argv;
+ int argc;
+ int result;
- argc = 1;
- arg = lpCmdLine;
-
- while (arg[0] != 0) {
-
- while (arg[0] != 0 && arg[0] == ' ') {
- arg++;
- }
-
- if (arg[0] != 0) {
-
- argc++;
-
- while (arg[0] != 0 && arg[0] != ' ') {
- arg++;
- }
-
- }
-
- }
+ wc_argv = CommandLineToArgvW(GetCommandLineW(), &argc);
- // tokenize the arguments
-
- argv = (char**)malloc(argc * sizeof(char*));
-
- arg = lpCmdLine;
- index = 1;
-
- while (arg[0] != 0) {
-
- while (arg[0] != 0 && arg[0] == ' ') {
- arg++;
- }
-
- if (arg[0] != 0) {
-
- argv[index] = arg;
- index++;
-
- while (arg[0] != 0 && arg[0] != ' ') {
- arg++;
- }
-
- if (arg[0] != 0) {
- arg[0] = 0;
- arg++;
- }
-
- }
-
- }
-
- // put the program name into argv[0]
-
- char filename[_MAX_PATH];
+ if( NULL == wc_argv ) {
+ wprintf(L"CommandLineToArgvW failed\n");
+ return 0;
+ }
- GetModuleFileName(NULL, filename, _MAX_PATH);
- argv[0] = filename;
+ result = widechar_main(argc, wc_argv);
- // call the user specified main function
+ LocalFree(wc_argv);
+ return result;
+}
- result = main(argc, argv);
+HINSTANCE godot_hinstance = NULL;
- free(argv);
- return result;
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
+ godot_hinstance = hInstance;
+ return main(0,NULL);
}
diff --git a/platform/windows/key_mapping_win.cpp b/platform/windows/key_mapping_win.cpp
index bdf3b2a92f..f07b7c6eaa 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/windows/key_mapping_win.h b/platform/windows/key_mapping_win.h
index 3e351675b0..288fcdd8de 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,26 +26,26 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef KEY_MAPPING_WINDOWS_H
-#define KEY_MAPPING_WINDOWS_H
-
-
-#include "os/keyboard.h"
-
-#include <windows.h>
-
-#include <winuser.h>
-
-
-class KeyMappingWindows {
-
- KeyMappingWindows() {};
-public:
-
- static unsigned int get_keysym(unsigned int p_code);
-
-};
-
-
-
-#endif
+#ifndef KEY_MAPPING_WINDOWS_H
+#define KEY_MAPPING_WINDOWS_H
+
+
+#include "os/keyboard.h"
+
+#include <windows.h>
+
+#include <winuser.h>
+
+
+class KeyMappingWindows {
+
+ KeyMappingWindows() {};
+public:
+
+ static unsigned int get_keysym(unsigned int p_code);
+
+};
+
+
+
+#endif
diff --git a/platform/windows/lang_table.h b/platform/windows/lang_table.h
index 83f3fb52fd..bfdf2b6ebe 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 64219d6c17..1fb8e6dbd0 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "drivers/gles2/rasterizer_gles2.h"
-#include "drivers/gles1/rasterizer_gles1.h"
+
#include "os_windows.h"
#include "drivers/nedmalloc/memory_pool_static_nedmalloc.h"
#include "drivers/unix/memory_pool_static_malloc.h"
@@ -45,14 +45,27 @@
#include "servers/visual/visual_server_wrap_mt.h"
#include "tcp_server_winsock.h"
+#include "packet_peer_udp_winsock.h"
#include "stream_peer_winsock.h"
#include "os/pc_joystick_map.h"
#include "lang_table.h"
#include "os/memory_pool_dynamic_prealloc.h"
#include "globals.h"
#include "io/marshalls.h"
+
+#include "shlobj.h"
+#include <regstr.h>
+
static const WORD MAX_CONSOLE_LINES = 1500;
+extern "C" {
+#ifdef _MSC_VER
+ _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
+#else
+ __attribute__((visibility("default"))) DWORD NvOptimusEnablement = 0x00000001;
+#endif
+}
+
//#define STDOUT_FILE
extern HINSTANCE godot_hinstance;
@@ -126,11 +139,11 @@ void RedirectIOToConsole() {
int OS_Windows::get_video_driver_count() const {
- return 2;
+ return 1;
}
const char * OS_Windows::get_video_driver_name(int p_driver) const {
- return p_driver==0?"GLES2":"GLES1";
+ return "GLES2";
}
OS::VideoMode OS_Windows::get_default_video_mode() const {
@@ -158,6 +171,8 @@ void OS_Windows::initialize_core() {
last_button_state=0;
//RedirectIOToConsole();
+ maximized=false;
+ minimized=false;
ThreadWindows::make_default();
SemaphoreWindows::make_default();
@@ -173,6 +188,7 @@ void OS_Windows::initialize_core() {
TCPServerWinsock::make_default();
StreamPeerWinsock::make_default();
+ PacketPeerUDPWinsock::make_default();
mempool_static = new MemoryPoolStaticMalloc;
#if 1
@@ -206,6 +222,41 @@ bool OS_Windows::can_draw() const {
return !minimized;
};
+#define MI_WP_SIGNATURE 0xFF515700
+#define SIGNATURE_MASK 0xFFFFFF00
+#define IsPenEvent(dw) (((dw) & SIGNATURE_MASK) == MI_WP_SIGNATURE)
+
+
+void OS_Windows::_touch_event(bool p_pressed, int p_x, int p_y, int idx) {
+
+ InputEvent event;
+ event.type = InputEvent::SCREEN_TOUCH;
+ event.ID=++last_id;
+ event.screen_touch.index = idx;
+
+ event.screen_touch.pressed = p_pressed;
+
+ event.screen_touch.x=p_x;
+ event.screen_touch.y=p_y;
+
+ if (main_loop) {
+ input->parse_input_event(event);
+ }
+};
+
+void OS_Windows::_drag_event(int p_x, int p_y, int idx) {
+
+ InputEvent event;
+ event.type = InputEvent::SCREEN_DRAG;
+ event.ID=++last_id;
+ event.screen_drag.index = idx;
+
+ event.screen_drag.x=p_x;
+ event.screen_drag.y=p_y;
+
+ if (main_loop)
+ input->parse_input_event(event);
+};
LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
@@ -270,28 +321,53 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
}
case WM_MOUSELEAVE: {
- old_invalid=true;
- outside=true;
+ 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) {
+ 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;
+ set_cursor_shape(c);
+ outside=false;
+
+ //Once-Off notification, must call again....
+ TRACKMOUSEEVENT tme;
+ tme.cbSize=sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags=TME_LEAVE;
+ tme.hwndTrack=hWnd;
+ tme.dwHoverTime=HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+
+ }
+
+ /*
+ LPARAM extra = GetMessageExtraInfo();
+ if (IsPenEvent(extra)) {
- CursorShape c=cursor_shape;
- cursor_shape=CURSOR_MAX;
- set_cursor_shape(c);
- outside=false;
+ int idx = extra & 0x7f;
+ _drag_event(idx, uMsg, wParam, lParam);
+ if (idx != 0) {
+ return 0;
+ };
+ // fallthrough for mouse event
+ };
+ */
- //Once-Off notification, must call again....
- TRACKMOUSEEVENT tme;
- tme.cbSize=sizeof(TRACKMOUSEEVENT);
- tme.dwFlags=TME_LEAVE;
- tme.hwndTrack=hWnd;
- tme.dwHoverTime=HOVER_DEFAULT;
- TrackMouseEvent(&tme);
- }
InputEvent event;
event.type=InputEvent::MOUSE_MOTION;
event.ID=++last_id;
@@ -357,9 +433,23 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
case WM_RBUTTONUP:
case WM_MOUSEWHEEL:
case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
/*case WM_XBUTTONDOWN:
case WM_XBUTTONUP: */{
+ /*
+ LPARAM extra = GetMessageExtraInfo();
+ if (IsPenEvent(extra)) {
+
+ int idx = extra & 0x7f;
+ _touch_event(idx, uMsg, wParam, lParam);
+ if (idx != 0) {
+ return 0;
+ };
+ // fallthrough for mouse event
+ };
+ */
+
InputEvent event;
event.type=InputEvent::MOUSE_BUTTON;
event.ID=++last_id;
@@ -397,6 +487,12 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
mb.button_index=1;
mb.doubleclick = true;
} break;
+ case WM_RBUTTONDBLCLK: {
+
+ mb.pressed=true;
+ mb.button_index=2;
+ mb.doubleclick = true;
+ } break;
case WM_MOUSEWHEEL: {
mb.pressed=true;
@@ -518,10 +614,11 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
+ // Make sure we don't include modifiers for the modifier key itself.
KeyEvent ke;
- ke.mod_state.shift=shift_mem;
- ke.mod_state.alt=alt_mem;
- ke.mod_state.control=control_mem;
+ ke.mod_state.shift= (wParam != VK_SHIFT) ? shift_mem : false;
+ ke.mod_state.alt= (! (wParam == VK_MENU && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN))) ? alt_mem : false;
+ ke.mod_state.control= (wParam != VK_CONTROL) ? control_mem : false;
ke.mod_state.meta=meta_mem;
ke.uMsg=uMsg;
@@ -549,6 +646,43 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
print_line("input lang change");
} break;
+
+ #if WINVER >= 0x0700 // for windows 7
+ case WM_TOUCH: {
+
+ BOOL bHandled = FALSE;
+ UINT cInputs = LOWORD(wParam);
+ PTOUCHINPUT pInputs = memnew_arr(TOUCHINPUT, cInputs);
+ if (pInputs){
+ if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT))){
+ for (UINT i=0; i < cInputs; i++){
+ TOUCHINPUT ti = pInputs[i];
+ //do something with each touch input entry
+ if (ti.dwFlags & TOUCHEVENTF_MOVE) {
+
+ _drag_event(ti.x / 100, ti.y / 100, ti.dwID);
+ } else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) {
+
+ _touch_event(ti.dwFlags & TOUCHEVENTF_DOWN != 0, ti.x / 100, ti.y / 100, ti.dwID);
+ };
+ }
+ bHandled = TRUE;
+ }else{
+ /* handle the error here */
+ }
+ memdelete_arr(pInputs);
+ }else{
+ /* handle the error here, probably out of memory */
+ }
+ if (bHandled) {
+ CloseTouchInputHandle((HTOUCHINPUT)lParam);
+ return 0;
+ };
+
+ } break;
+
+ #endif
+
default: {
if (user_proc) {
@@ -572,8 +706,57 @@ 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;
@@ -582,21 +765,46 @@ void OS_Windows::probe_joysticks() {
for (int i=0; i<JOYSTICKS_MAX; i++) {
- joysticks[i].attached = (device_count > 0) && (joyGetPosEx(JOYSTICKID1 + i, &jinfo) == JOYERR_NOERROR);
-
- if (!joysticks[i].attached) {
+ 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;
};
- joysticks[i].last_buttons = jinfo.dwButtons;
+ // 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;
+
+
+ };
+ };
- joysticks[i].last_axis[0] = jinfo.dwXpos;
- joysticks[i].last_axis[1] = jinfo.dwYpos;
- joysticks[i].last_axis[2] = jinfo.dwZpos;
- joysticks[i].last_axis[3] = jinfo.dwRpos;
- joysticks[i].last_axis[4] = jinfo.dwUpos;
- joysticks[i].last_axis[5] = jinfo.dwVpos;
+ joystick_change_queue.push_back(joy);
};
};
@@ -807,7 +1015,7 @@ void OS_Windows::process_joysticks() {
if ( (joysticks[i].last_buttons & (1<<j)) != (jinfo.dwButtons & (1<<j)) ) {
- ievent.joy_button.button_index = _pc_joystick_get_native_button(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);
@@ -818,6 +1026,23 @@ void OS_Windows::process_joysticks() {
};
};
+
+BOOL CALLBACK OS_Windows::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+ OS_Windows *self=(OS_Windows*)OS::get_singleton();
+ MonitorInfo minfo;
+ minfo.hMonitor=hMonitor;
+ minfo.hdcMonitor=hdcMonitor;
+ minfo.rect.pos.x=lprcMonitor->left;
+ minfo.rect.pos.y=lprcMonitor->top;
+ minfo.rect.size.x=lprcMonitor->right - lprcMonitor->left;
+ minfo.rect.size.y=lprcMonitor->bottom - lprcMonitor->top;
+
+ self->monitor_info.push_back(minfo);
+
+ return TRUE;
+}
+
+
void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
@@ -856,13 +1081,20 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
}
+ EnumDisplayMonitors(NULL,NULL,MonitorEnumProc,0);
+
+ print_line("DETECTED MONITORS: "+itos(monitor_info.size()));
+ pre_fs_valid=true;
if (video_mode.fullscreen) {
DEVMODE current;
memset(&current,0,sizeof(current));
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &current);
+
+ WindowRect.right = current.dmPelsWidth;
+ WindowRect.bottom = current.dmPelsHeight;
- DEVMODE dmScreenSettings;
+/* DEVMODE dmScreenSettings;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = video_mode.width;
@@ -874,7 +1106,8 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
if (err!=DISP_CHANGE_SUCCESSFUL) {
video_mode.fullscreen=false;
- }
+ }*/
+ pre_fs_valid=false;
}
DWORD dwExStyle;
@@ -954,7 +1187,7 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
if (!is_no_window_mode_enabled()) {
@@ -998,7 +1231,13 @@ 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();
+ 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);
@@ -1007,6 +1246,7 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
tme.dwHoverTime=HOVER_DEFAULT;
TrackMouseEvent(&tme);
+ //RegisterTouchWindow(hWnd, 0); // Windows 7
_ensure_data_dir();
@@ -1110,7 +1350,9 @@ void OS_Windows::finalize() {
memdelete(main_loop);
main_loop=NULL;
-
+
+ memdelete(input);
+
visual_server->finish();
memdelete(visual_server);
#ifdef OPENGL_ENABLED
@@ -1133,11 +1375,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);
@@ -1145,6 +1386,9 @@ void OS_Windows::finalize() {
physics_2d_server->finish();
memdelete(physics_2d_server);
+ joystick_change_queue.clear();
+ monitor_info.clear();
+
}
void OS_Windows::finalize_core() {
@@ -1224,11 +1468,29 @@ void OS_Windows::set_mouse_mode(MouseMode p_mode) {
OS_Windows::MouseMode OS_Windows::get_mouse_mode() const{
+
return mouse_mode;
}
+void OS_Windows::warp_mouse_pos(const Point2& p_to) {
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+
+ old_x=p_to.x;
+ old_y=p_to.y;
+ } else {
+
+ POINT p;
+ p.x=p_to.x;
+ p.y=p_to.y;
+ ClientToScreen(hWnd,&p);
+
+ SetCursorPos(p.x,p.y);
+ }
+}
+
Point2 OS_Windows::get_mouse_pos() const {
return Point2(old_x, old_y);
@@ -1246,8 +1508,9 @@ void OS_Windows::set_window_title(const String& p_title) {
void OS_Windows::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
-
+
}
+
OS::VideoMode OS_Windows::get_video_mode(int p_screen) const {
return video_mode;
@@ -1257,73 +1520,341 @@ void OS_Windows::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen)
}
-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) {
+int OS_Windows::get_screen_count() const {
+
+ return monitor_info.size();
+}
+int OS_Windows::get_current_screen() const{
+
+ HMONITOR monitor = MonitorFromWindow(hWnd,MONITOR_DEFAULTTONEAREST);
+ for(int i=0;i<monitor_info.size();i++) {
+ if (monitor_info[i].hMonitor==monitor)
+ return i;
+ }
+
+ return 0;
+}
+void OS_Windows::set_current_screen(int p_screen){
+
+ ERR_FAIL_INDEX(p_screen,monitor_info.size());
+
+ Vector2 ofs = get_window_position() - get_screen_position(get_current_screen());
+ set_window_position(ofs+get_screen_position(p_screen));
+
+}
+
+Point2 OS_Windows::get_screen_position(int p_screen) const{
+
+ ERR_FAIL_INDEX_V(p_screen,monitor_info.size(),Point2());
+ return Vector2( monitor_info[p_screen].rect.pos );
+
+}
+Size2 OS_Windows::get_screen_size(int p_screen) const{
+
+ ERR_FAIL_INDEX_V(p_screen,monitor_info.size(),Point2());
+ return Vector2( monitor_info[p_screen].rect.size );
+
+}
+Point2 OS_Windows::get_window_position() const{
+
+ RECT r;
+ GetWindowRect(hWnd,&r);
+ return Point2(r.left,r.top);
+}
+void OS_Windows::set_window_position(const Point2& p_position){
+
+ RECT r;
+ GetWindowRect(hWnd,&r);
+ MoveWindow(hWnd,p_position.x,p_position.y,r.right-r.left,r.bottom-r.top,TRUE);
+
+}
+Size2 OS_Windows::get_window_size() const{
+
+ RECT r;
+ GetClientRect(hWnd,&r);
+ return Vector2(r.right-r.left,r.bottom-r.top);
+
+}
+void OS_Windows::set_window_size(const Size2 p_size){
+
+ video_mode.width=p_size.width;
+ video_mode.height=p_size.height;
+
+ if (video_mode.fullscreen) {
+ return;
+ }
+
+
+ RECT crect;
+ GetClientRect(hWnd,&crect);
+
+ RECT rect;
+ GetWindowRect(hWnd,&rect);
+ int dx = (rect.right-rect.left)-(crect.right-crect.left);
+ int dy = (rect.bottom-rect.top)-(crect.bottom-crect.top);
+
+ rect.right=rect.left+p_size.width+dx;
+ rect.bottom=rect.top+p_size.height+dy;
+
+
+ //print_line("PRE: "+itos(rect.left)+","+itos(rect.top)+","+itos(rect.right-rect.left)+","+itos(rect.bottom-rect.top));
+
+ /*if (video_mode.resizable) {
+ AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
+ } else {
+ AdjustWindowRect(&rect, WS_CAPTION | WS_POPUPWINDOW, FALSE);
+ }*/
+
+ //print_line("POST: "+itos(rect.left)+","+itos(rect.top)+","+itos(rect.right-rect.left)+","+itos(rect.bottom-rect.top));
+
+ MoveWindow(hWnd,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top,TRUE);
+
+}
+void OS_Windows::set_window_fullscreen(bool p_enabled){
+
+ if (video_mode.fullscreen==p_enabled)
+ return;
+
+
+
+ if (p_enabled) {
+
+
+ if (pre_fs_valid) {
+ GetWindowRect(hWnd,&pre_fs_rect);
+ //print_line("A: "+itos(pre_fs_rect.left)+","+itos(pre_fs_rect.top)+","+itos(pre_fs_rect.right-pre_fs_rect.left)+","+itos(pre_fs_rect.bottom-pre_fs_rect.top));
+ //MapWindowPoints(hWnd, GetParent(hWnd), (LPPOINT) &pre_fs_rect, 2);
+ //print_line("B: "+itos(pre_fs_rect.left)+","+itos(pre_fs_rect.top)+","+itos(pre_fs_rect.right-pre_fs_rect.left)+","+itos(pre_fs_rect.bottom-pre_fs_rect.top));
+ }
+
+
+ int cs = get_current_screen();
+ Point2 pos = get_screen_position(cs);
+ Size2 size = get_screen_size(cs);
+
+ /* r.left = pos.x;
+ r.top = pos.y;
+ r.bottom = pos.y+size.y;
+ r.right = pos.x+size.x;
+*/
+ SetWindowLongPtr(hWnd, GWL_STYLE,
+ WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
+ MoveWindow(hWnd, pos.x, pos.y, size.width, size.height, TRUE);
+
+ video_mode.fullscreen=true;
+
+
+ } else {
+
+ RECT rect;
+
+ if (pre_fs_valid) {
+ rect=pre_fs_rect;
+ } else {
+ rect.left=0;
+ rect.right=video_mode.width;
+ rect.top=0;
+ rect.bottom=video_mode.height;
+ }
- HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
- if (!hCon || hCon==INVALID_HANDLE_VALUE) {
- 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);
+ if (video_mode.resizable) {
+
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
+ //AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
+ MoveWindow(hWnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
} 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);
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE);
+ //AdjustWindowRect(&rect, WS_CAPTION | WS_POPUPWINDOW, FALSE);
+ MoveWindow(hWnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
}
+
+ video_mode.fullscreen=false;
+ pre_fs_valid=true;
+/*
+ DWORD dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+ DWORD dwStyle=WS_OVERLAPPEDWINDOW;
+ if (!video_mode.resizable) {
+ dwStyle &= ~WS_THICKFRAME;
+ dwStyle &= ~WS_MAXIMIZEBOX;
+ }
+ AdjustWindowRectEx(&pre_fs_rect, dwStyle, FALSE, dwExStyle);
+ video_mode.fullscreen=false;
+ video_mode.width=pre_fs_rect.right-pre_fs_rect.left;
+ video_mode.height=pre_fs_rect.bottom-pre_fs_rect.top;
+*/
+ }
+
+// MoveWindow(hWnd,r.left,r.top,p_size.x,p_size.y,TRUE);
+
+
+}
+bool OS_Windows::is_window_fullscreen() const{
+
+ return video_mode.fullscreen;
+}
+void OS_Windows::set_window_resizable(bool p_enabled){
+
+ if (video_mode.resizable==p_enabled)
+ return;
+/*
+ GetWindowRect(hWnd,&pre_fs_rect);
+ DWORD dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+ DWORD dwStyle=WS_OVERLAPPEDWINDOW;
+ if (!p_enabled) {
+ dwStyle &= ~WS_THICKFRAME;
+ dwStyle &= ~WS_MAXIMIZEBOX;
+ }
+ AdjustWindowRectEx(&pre_fs_rect, dwStyle, FALSE, dwExStyle);
+ */
+
+ if (!video_mode.fullscreen) {
+ if (p_enabled) {
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
+ } else {
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE);
+
+ }
+
+ RECT rect;
+ GetWindowRect(hWnd,&rect);
+ MoveWindow(hWnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
+ }
+
+ video_mode.resizable=p_enabled;
+
+}
+bool OS_Windows::is_window_resizable() const{
+
+ return video_mode.resizable;
+}
+void OS_Windows::set_window_minimized(bool p_enabled){
+
+ if (p_enabled) {
+ maximized=false;
+ minimized=true;
+ ShowWindow(hWnd,SW_MINIMIZE);
} else {
+ ShowWindow(hWnd,SW_RESTORE);
+ maximized=false;
+ minimized=false;
+ }
+}
+bool OS_Windows::is_window_minimized() const{
- CONSOLE_SCREEN_BUFFER_INFO sbi; //original
- GetConsoleScreenBufferInfo(hCon,&sbi);
+ return minimized;
- SetConsoleTextAttribute(hCon,sbi.wAttributes);
+}
+void OS_Windows::set_window_maximized(bool p_enabled){
+ if (p_enabled) {
+ maximized=true;
+ minimized=false;
+ ShowWindow(hWnd,SW_MAXIMIZE);
+ } else {
+ ShowWindow(hWnd,SW_RESTORE);
+ maximized=false;
+ minimized=false;
+ }
+}
+bool OS_Windows::is_window_maximized() const{
+ return maximized;
+}
+
+
+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) {
+
+ const char* err_details;
+ if (p_rationale && p_rationale[0])
+ err_details = p_rationale;
+ else
+ err_details = p_code;
- 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_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;
}
- if (p_rationale && p_rationale[0]) {
+ } else {
- SetConsoleTextAttribute(hCon,basecol|FOREGROUND_INTENSITY);
+ CONSOLE_SCREEN_BUFFER_INFO sbi; //original
+ 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;
+ switch(p_type) {
+ case ERR_ERROR: basecol = FOREGROUND_RED; break;
+ case ERR_WARNING: basecol = FOREGROUND_RED | FOREGROUND_GREEN; break;
+ case ERR_SCRIPT: basecol = FOREGROUND_RED | FOREGROUND_BLUE; break;
+ }
+
+ 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);
}
-
}
@@ -1332,10 +1863,14 @@ String OS_Windows::get_name() {
return "Windows";
}
-OS::Date OS_Windows::get_date() const {
+OS::Date OS_Windows::get_date(bool utc) const {
SYSTEMTIME systemtime;
- GetSystemTime(&systemtime);
+ if (utc)
+ GetSystemTime(&systemtime);
+ else
+ GetLocalTime(&systemtime);
+
Date date;
date.day=systemtime.wDay;
date.month=Month(systemtime.wMonth);
@@ -1344,10 +1879,13 @@ OS::Date OS_Windows::get_date() const {
date.dst=false;
return date;
}
-OS::Time OS_Windows::get_time() const {
+OS::Time OS_Windows::get_time(bool utc) const {
SYSTEMTIME systemtime;
- GetSystemTime(&systemtime);
+ if (utc)
+ GetSystemTime(&systemtime);
+ else
+ GetLocalTime(&systemtime);
Time time;
time.hour=systemtime.wHour;
@@ -1356,6 +1894,23 @@ OS::Time OS_Windows::get_time() const {
return time;
}
+OS::TimeZoneInfo OS_Windows::get_time_zone_info() const {
+ TIME_ZONE_INFORMATION info;
+ bool daylight = false;
+ if (GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT)
+ daylight = true;
+
+ TimeZoneInfo ret;
+ if (daylight) {
+ ret.name = info.DaylightName;
+ } else {
+ ret.name = info.StandardName;
+ }
+
+ ret.bias = info.Bias;
+ return ret;
+}
+
uint64_t OS_Windows::get_unix_time() const {
FILETIME ft;
@@ -1378,6 +1933,12 @@ uint64_t OS_Windows::get_unix_time() const {
return (*(uint64_t*)&ft - *(uint64_t*)&fep) / 10000000;
};
+uint64_t OS_Windows::get_system_time_msec() const {
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ return st.wMilliseconds;
+}
+
void OS_Windows::delay_usec(uint32_t p_usec) const {
if (p_usec < 1000)
@@ -1558,7 +2119,7 @@ String OS_Windows::get_executable_path() const {
wchar_t bufname[4096];
GetModuleFileNameW(NULL,bufname,4096);
String s= bufname;
- print_line("EXEC PATHPó: "+s);
+ print_line("EXEC PATHP??: "+s);
return s;
}
@@ -1623,12 +2184,13 @@ bool OS_Windows::has_environment(const String& p_var) const {
String OS_Windows::get_environment(const String& p_var) const {
- char* val = getenv(p_var.utf8().get_data());
- if (val)
- return val;
-
+ wchar_t wval[0x7Fff]; // MSDN says 32767 char is the maximum
+ int wlen = GetEnvironmentVariableW(p_var.c_str(),wval,0x7Fff);
+ if ( wlen > 0 ) {
+ return wval;
+ }
return "";
-};
+}
String OS_Windows::get_stdin_string(bool p_block) {
@@ -1644,6 +2206,7 @@ String OS_Windows::get_stdin_string(bool p_block) {
void OS_Windows::move_window_to_foreground() {
SetForegroundWindow(hWnd);
+ BringWindowToTop(hWnd);
}
@@ -1728,7 +2291,46 @@ MainLoop *OS_Windows::get_main_loop() const {
return main_loop;
}
+String OS_Windows::get_system_dir(SystemDir p_dir) const {
+
+ int id;
+
+
+
+ switch(p_dir) {
+ case SYSTEM_DIR_DESKTOP: {
+ id=CSIDL_DESKTOPDIRECTORY;
+ } break;
+ case SYSTEM_DIR_DCIM: {
+ id=CSIDL_MYPICTURES;
+ } break;
+ case SYSTEM_DIR_DOCUMENTS: {
+ id=0x000C;
+ } break;
+ case SYSTEM_DIR_DOWNLOADS: {
+ id=0x000C ;
+ } break;
+ case SYSTEM_DIR_MOVIES: {
+ id=CSIDL_MYVIDEO;
+ } break;
+ case SYSTEM_DIR_MUSIC: {
+ id=CSIDL_MYMUSIC;
+ } break;
+ case SYSTEM_DIR_PICTURES: {
+ id=CSIDL_MYPICTURES;
+ } break;
+ case SYSTEM_DIR_RINGTONES: {
+ id=CSIDL_MYMUSIC;
+ } break;
+ }
+
+ WCHAR szPath[MAX_PATH];
+ HRESULT res = SHGetFolderPathW(NULL,id,NULL,0,szPath);
+ ERR_FAIL_COND_V(res!=S_OK,String());
+ return String(szPath);
+
+}
String OS_Windows::get_data_dir() const {
String an = Globals::get_singleton()->get("application/name");
@@ -1736,7 +2338,11 @@ String OS_Windows::get_data_dir() const {
if (has_environment("APPDATA")) {
- return OS::get_singleton()->get_environment("APPDATA")+"\\"+an;
+ bool use_godot = Globals::get_singleton()->get("application/use_shared_user_dir");
+ if (!use_godot)
+ return (OS::get_singleton()->get_environment("APPDATA")+"/"+an).replace("\\","/");
+ else
+ return (OS::get_singleton()->get_environment("APPDATA")+"/Godot/app_userdata/"+an).replace("\\","/");
}
}
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 365808d175..026b50c33d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -45,7 +45,9 @@
#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
#include "drivers/unix/ip_unix.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 <windows.h>
@@ -86,7 +88,7 @@ class OS_Windows : public OS {
uint64_t ticks_start;
uint64_t ticks_per_second;
- bool minimized;
+
bool old_invalid;
bool outside;
int old_x,old_y;
@@ -106,13 +108,16 @@ class OS_Windows : public OS {
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++) {
@@ -123,9 +128,11 @@ class OS_Windows : public OS {
};
};
+ List<Joystick> joystick_change_queue;
int joystick_count;
Joystick joysticks[JOYSTICKS_MAX];
+ Size2 window_rect;
VideoMode video_mode;
MainLoop *main_loop;
@@ -156,6 +163,9 @@ class OS_Windows : public OS {
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);
+
// functions used by main to initialize/deintialize the OS
protected:
virtual int get_video_driver_count() const;
@@ -180,6 +190,7 @@ protected:
void probe_joysticks();
void process_joysticks();
void process_key_events();
+ String get_joystick_name( int id, JOYCAPS jcaps);
struct ProcessInfo {
@@ -188,6 +199,23 @@ protected:
};
Map<ProcessID, ProcessInfo>* process_map;
+ struct MonitorInfo {
+ HMONITOR hMonitor;
+ HDC hdcMonitor;
+ Rect2 rect;
+
+
+ };
+
+ bool pre_fs_valid;
+ RECT pre_fs_rect;
+ Vector<MonitorInfo> monitor_info;
+ bool maximized;
+ bool minimized;
+
+ static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
+
+
public:
LRESULT WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam);
@@ -201,6 +229,7 @@ public:
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
+ virtual void warp_mouse_pos(const Point2& p_to);
virtual Point2 get_mouse_pos() const;
virtual int get_mouse_button_state() const;
virtual void set_window_title(const String& p_title);
@@ -209,13 +238,33 @@ public:
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 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 Point2 get_window_position() const;
+ virtual void set_window_position(const Point2& p_position);
+ virtual Size2 get_window_size() const;
+ virtual void set_window_size(const Size2 p_size);
+ 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 MainLoop *get_main_loop() const;
virtual String get_name();
- virtual Date get_date() const;
- virtual Time get_time() const;
+ virtual Date get_date(bool utc) const;
+ 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_msec() const;
virtual bool can_draw() const;
virtual Error set_cwd(const String& p_cwd);
@@ -225,7 +274,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;
@@ -241,6 +290,8 @@ public:
virtual void move_window_to_foreground();
virtual String get_data_dir() const;
+ virtual String get_system_dir(SystemDir p_dir) const;
+
virtual void release_rendering_thread();
virtual void make_rendering_thread();
diff --git a/platform/windows/packet_peer_udp_winsock.cpp b/platform/windows/packet_peer_udp_winsock.cpp
new file mode 100644
index 0000000000..0ca2d358af
--- /dev/null
+++ b/platform/windows/packet_peer_udp_winsock.cpp
@@ -0,0 +1,219 @@
+#include "packet_peer_udp_winsock.h"
+
+#include <winsock2.h>
+
+int PacketPeerUDPWinsock::get_available_packet_count() const {
+
+ Error err = const_cast<PacketPeerUDPWinsock*>(this)->_poll(false);
+ if (err!=OK)
+ return 0;
+
+ return queue_count;
+}
+
+Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer,int &r_buffer_size) const{
+
+ Error err = const_cast<PacketPeerUDPWinsock*>(this)->_poll(false);
+ if (err!=OK)
+ return err;
+ if (queue_count==0)
+ return ERR_UNAVAILABLE;
+
+ uint32_t size;
+ rb.read((uint8_t*)&packet_ip.host,4,true);
+ rb.read((uint8_t*)&packet_port,4,true);
+ rb.read((uint8_t*)&size,4,true);
+ rb.read(packet_buffer,size,true);
+ --queue_count;
+ *r_buffer=packet_buffer;
+ r_buffer_size=size;
+ return OK;
+
+}
+Error PacketPeerUDPWinsock::put_packet(const uint8_t *p_buffer,int p_buffer_size){
+
+ int sock = _get_socket();
+ ERR_FAIL_COND_V( sock == -1, FAILED );
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(peer_port);
+ addr.sin_addr = *((struct in_addr*)&peer_addr.host);
+
+
+ _set_blocking(true);
+
+ errno = 0;
+ int err;
+ while ( (err = sendto(sock, (const char*)p_buffer, p_buffer_size, 0, (struct sockaddr*)&addr, sizeof(addr))) != p_buffer_size) {
+
+ if (WSAGetLastError() != WSAEWOULDBLOCK) {
+ return FAILED;
+ };
+ }
+
+ return OK;
+}
+
+int PacketPeerUDPWinsock::get_max_packet_size() const{
+
+ return 512; // uhm maybe not
+}
+
+
+void PacketPeerUDPWinsock::_set_blocking(bool p_blocking) {
+ //am no windows expert
+ //hope this is the right thing
+
+ if (blocking==p_blocking)
+ return;
+
+ blocking=p_blocking;
+ unsigned long par = blocking?0:1;
+ if (ioctlsocket(sockfd, FIONBIO, &par)) {
+ perror("setting non-block mode");
+ //close();
+ //return -1;
+ };
+}
+
+Error PacketPeerUDPWinsock::listen(int p_port, int p_recv_buffer_size){
+
+ close();
+ int sock = _get_socket();
+ if (sock == -1 )
+ return ERR_CANT_CREATE;
+ sockaddr_in addr = {0};
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(p_port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) {
+ close();
+ return ERR_UNAVAILABLE;
+ }
+
+ blocking=true;
+
+ printf("UDP Connection listening on port %i\n", p_port);
+ rb.resize(nearest_shift(p_recv_buffer_size));
+ return OK;
+}
+
+void PacketPeerUDPWinsock::close(){
+
+ if (sockfd != -1)
+ ::closesocket(sockfd);
+ sockfd=-1;
+ rb.resize(8);
+ queue_count=0;
+}
+
+
+Error PacketPeerUDPWinsock::wait() {
+
+ return _poll(true);
+}
+Error PacketPeerUDPWinsock::_poll(bool p_wait) {
+
+
+ _set_blocking(p_wait);
+
+
+ struct sockaddr_in from = {0};
+ int len = sizeof(struct sockaddr_in);
+ int ret;
+ 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);
+ rb.write((uint8_t*)&ret, 4);
+ rb.write(recv_buffer, ret);
+
+ len = sizeof(struct sockaddr_in);
+ ++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) {
+ close();
+ return FAILED;
+ };
+
+
+ return OK;
+}
+
+bool PacketPeerUDPWinsock::is_listening() const{
+
+ return sockfd!=-1;
+}
+
+IP_Address PacketPeerUDPWinsock::get_packet_address() const {
+
+ return packet_ip;
+}
+
+int PacketPeerUDPWinsock::get_packet_port() const{
+
+ return packet_port;
+}
+
+int PacketPeerUDPWinsock::_get_socket() {
+
+ if (sockfd != -1)
+ return sockfd;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ ERR_FAIL_COND_V( sockfd == -1, -1 );
+ //fcntl(sockfd, F_SETFL, O_NONBLOCK);
+
+ return sockfd;
+}
+
+
+void PacketPeerUDPWinsock::set_send_address(const IP_Address& p_address,int p_port) {
+
+ peer_addr=p_address;
+ peer_port=p_port;
+}
+
+void PacketPeerUDPWinsock::make_default() {
+
+ PacketPeerUDP::_create = PacketPeerUDPWinsock::_create;
+};
+
+
+PacketPeerUDP* PacketPeerUDPWinsock::_create() {
+
+ return memnew(PacketPeerUDPWinsock);
+};
+
+
+PacketPeerUDPWinsock::PacketPeerUDPWinsock() {
+
+ sockfd=-1;
+ packet_port=0;
+ queue_count=0;
+ peer_port=0;
+}
+
+PacketPeerUDPWinsock::~PacketPeerUDPWinsock() {
+
+ close();
+}
diff --git a/platform/windows/packet_peer_udp_winsock.h b/platform/windows/packet_peer_udp_winsock.h
new file mode 100644
index 0000000000..34dbcbee91
--- /dev/null
+++ b/platform/windows/packet_peer_udp_winsock.h
@@ -0,0 +1,56 @@
+#ifndef PACKET_PEER_UDP_WINSOCK_H
+#define PACKET_PEER_UDP_WINSOCK_H
+
+#include "io/packet_peer_udp.h"
+#include "ring_buffer.h"
+
+class PacketPeerUDPWinsock : public PacketPeerUDP {
+
+
+ enum {
+ PACKET_BUFFER_SIZE=65536
+ };
+
+ mutable RingBuffer<uint8_t> rb;
+ uint8_t recv_buffer[PACKET_BUFFER_SIZE];
+ mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE];
+ IP_Address packet_ip;
+ int packet_port;
+ mutable int queue_count;
+ int sockfd;
+
+ IP_Address peer_addr;
+ int peer_port;
+
+ _FORCE_INLINE_ int _get_socket();
+
+ static PacketPeerUDP* _create();
+
+ bool blocking;
+ void _set_blocking(bool p_blocking);
+
+ Error _poll(bool p_wait);
+
+public:
+
+ virtual int get_available_packet_count() const;
+ virtual Error get_packet(const uint8_t **r_buffer,int &r_buffer_size) const;
+ virtual Error put_packet(const uint8_t *p_buffer,int p_buffer_size);
+
+ virtual int get_max_packet_size() const;
+
+ virtual Error listen(int p_port,int p_recv_buffer_size=65536);
+ virtual void close();
+ virtual Error wait();
+ virtual bool is_listening() const;
+
+ virtual IP_Address get_packet_address() const;
+ virtual int get_packet_port() const;
+
+ virtual void set_send_address(const IP_Address& p_address,int p_port);
+
+ static void make_default();
+ PacketPeerUDPWinsock();
+ ~PacketPeerUDPWinsock();
+};
+#endif // PACKET_PEER_UDP_WINSOCK_H
diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h
index 7bc3e42833..e6b561552e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,5 +31,5 @@
//#include <alloca.h>
//#endif
#define GLES2_INCLUDE_H "gl_context/glew.h"
-#define GLES1_INCLUDE_H "gl_context/glew.h"
+
diff --git a/platform/windows/stream_peer_winsock.cpp b/platform/windows/stream_peer_winsock.cpp
index eabfb30599..e8245c92e5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/windows/stream_peer_winsock.h b/platform/windows/stream_peer_winsock.h
index 14dd5f0bb1..373b502d2c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/windows/tcp_server_winsock.cpp b/platform/windows/tcp_server_winsock.cpp
index e77ca6feaa..cc689d9dcf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,144 +26,151 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "tcp_server_winsock.h"
-
-#include "stream_peer_winsock.h"
-
-#include <winsock2.h>
-
-extern int winsock_refcount;
-
-TCP_Server* TCPServerWinsock::_create() {
-
- return memnew(TCPServerWinsock);
-};
-
-void TCPServerWinsock::make_default() {
-
- TCP_Server::_create = TCPServerWinsock::_create;
-
- if (winsock_refcount == 0) {
- WSADATA data;
- WSAStartup(MAKEWORD(2,2), &data);
- };
- ++winsock_refcount;
-};
-
-void TCPServerWinsock::cleanup() {
-
- --winsock_refcount;
- if (winsock_refcount == 0) {
-
- WSACleanup();
- };
-};
-
-
-Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_hosts) {
-
- int sockfd;
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- ERR_FAIL_COND_V(sockfd == INVALID_SOCKET, FAILED);
-
- unsigned long par = 1;
- if (ioctlsocket(sockfd, FIONBIO, &par)) {
- perror("setting non-block mode");
- stop();
- return FAILED;
- };
-
- struct sockaddr_in my_addr;
- my_addr.sin_family = AF_INET; // host byte order
- my_addr.sin_port = htons(p_port); // short, network byte order
- 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);
-
- if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) != SOCKET_ERROR) {
-
- if (::listen(sockfd, SOMAXCONN) == SOCKET_ERROR) {
-
- closesocket(sockfd);
- ERR_FAIL_V(FAILED);
- };
- }
- else {
- return ERR_ALREADY_IN_USE;
- };
-
- if (listen_sockfd != INVALID_SOCKET) {
-
- stop();
- };
-
- listen_sockfd = sockfd;
-
- return OK;
-};
-
-bool TCPServerWinsock::is_connection_available() const {
-
- if (listen_sockfd == -1) {
- return false;
- };
-
- timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
-
- fd_set pfd;
- FD_ZERO(&pfd);
- FD_SET(listen_sockfd, &pfd);
-
- int ret = select(listen_sockfd + 1, &pfd, NULL, NULL, &timeout);
- ERR_FAIL_COND_V(ret < 0, 0);
-
- if (ret && (FD_ISSET(listen_sockfd, &pfd))) {
-
- return true;
- };
-
- return false;
-};
-
-
-Ref<StreamPeerTCP> TCPServerWinsock::take_connection() {
-
- if (!is_connection_available()) {
- return NULL;
- };
-
- struct sockaddr_in their_addr;
- int sin_size = sizeof(their_addr);
- int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size);
- ERR_FAIL_COND_V(fd == INVALID_SOCKET, NULL);
-
- Ref<StreamPeerWinsock> conn = memnew(StreamPeerWinsock);
- IP_Address ip;
- ip.host = (uint32_t)their_addr.sin_addr.s_addr;
-
- conn->set_socket(fd, ip, ntohs(their_addr.sin_port));
-
- return conn;
-};
-
-void TCPServerWinsock::stop() {
-
- if (listen_sockfd != INVALID_SOCKET) {
- closesocket(listen_sockfd);
- };
-
- listen_sockfd = -1;
-};
-
-
-TCPServerWinsock::TCPServerWinsock() {
-
- listen_sockfd = INVALID_SOCKET;
-};
-
-TCPServerWinsock::~TCPServerWinsock() {
-
- stop();
-};
-
+#include "tcp_server_winsock.h"
+
+#include "stream_peer_winsock.h"
+
+#include <winsock2.h>
+
+extern int winsock_refcount;
+
+TCP_Server* TCPServerWinsock::_create() {
+
+ return memnew(TCPServerWinsock);
+};
+
+void TCPServerWinsock::make_default() {
+
+ TCP_Server::_create = TCPServerWinsock::_create;
+
+ if (winsock_refcount == 0) {
+ WSADATA data;
+ WSAStartup(MAKEWORD(2,2), &data);
+ };
+ ++winsock_refcount;
+};
+
+void TCPServerWinsock::cleanup() {
+
+ --winsock_refcount;
+ if (winsock_refcount == 0) {
+
+ WSACleanup();
+ };
+};
+
+
+Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_hosts) {
+
+ int sockfd;
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ ERR_FAIL_COND_V(sockfd == INVALID_SOCKET, FAILED);
+
+ unsigned long par = 1;
+ if (ioctlsocket(sockfd, FIONBIO, &par)) {
+ perror("setting non-block mode");
+ stop();
+ return FAILED;
+ };
+
+ struct sockaddr_in my_addr;
+ my_addr.sin_family = AF_INET; // host byte order
+ my_addr.sin_port = htons(p_port); // short, network byte order
+ 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) {
+
+ closesocket(sockfd);
+ ERR_FAIL_V(FAILED);
+ };
+ }
+ else {
+ return ERR_ALREADY_IN_USE;
+ };
+
+ if (listen_sockfd != INVALID_SOCKET) {
+
+ stop();
+ };
+
+ listen_sockfd = sockfd;
+
+ return OK;
+};
+
+bool TCPServerWinsock::is_connection_available() const {
+
+ if (listen_sockfd == -1) {
+ return false;
+ };
+
+ timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ fd_set pfd;
+ FD_ZERO(&pfd);
+ FD_SET(listen_sockfd, &pfd);
+
+ int ret = select(listen_sockfd + 1, &pfd, NULL, NULL, &timeout);
+ ERR_FAIL_COND_V(ret < 0, 0);
+
+ if (ret && (FD_ISSET(listen_sockfd, &pfd))) {
+
+ return true;
+ };
+
+ return false;
+};
+
+
+Ref<StreamPeerTCP> TCPServerWinsock::take_connection() {
+
+ if (!is_connection_available()) {
+ return NULL;
+ };
+
+ struct sockaddr_in their_addr;
+ int sin_size = sizeof(their_addr);
+ int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size);
+ ERR_FAIL_COND_V(fd == INVALID_SOCKET, NULL);
+
+ Ref<StreamPeerWinsock> conn = memnew(StreamPeerWinsock);
+ IP_Address ip;
+ ip.host = (uint32_t)their_addr.sin_addr.s_addr;
+
+ conn->set_socket(fd, ip, ntohs(their_addr.sin_port));
+
+ return conn;
+};
+
+void TCPServerWinsock::stop() {
+
+ if (listen_sockfd != INVALID_SOCKET) {
+ closesocket(listen_sockfd);
+ };
+
+ listen_sockfd = -1;
+};
+
+
+TCPServerWinsock::TCPServerWinsock() {
+
+ listen_sockfd = INVALID_SOCKET;
+};
+
+TCPServerWinsock::~TCPServerWinsock() {
+
+ stop();
+};
+
diff --git a/platform/windows/tcp_server_winsock.h b/platform/windows/tcp_server_winsock.h
index 2d54b6ce40..2516123908 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,30 +26,30 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TCP_SERVER_WINSOCK_H
-#define TCP_SERVER_WINSOCK_H
-
-#include "core/io/tcp_server.h"
-
-class TCPServerWinsock : public TCP_Server {
-
- int listen_sockfd;
-
- static TCP_Server* _create();
-
-public:
-
- virtual Error listen(uint16_t p_port,const List<String> *p_accepted_hosts=NULL);
- virtual bool is_connection_available() const;
- virtual Ref<StreamPeerTCP> take_connection();
-
- virtual void stop(); //stop listening
-
- static void make_default();
- static void cleanup();
-
- TCPServerWinsock();
- ~TCPServerWinsock();
-};
-
-#endif
+#ifndef TCP_SERVER_WINSOCK_H
+#define TCP_SERVER_WINSOCK_H
+
+#include "core/io/tcp_server.h"
+
+class TCPServerWinsock : public TCP_Server {
+
+ int listen_sockfd;
+
+ static TCP_Server* _create();
+
+public:
+
+ virtual Error listen(uint16_t p_port,const List<String> *p_accepted_hosts=NULL);
+ virtual bool is_connection_available() const;
+ virtual Ref<StreamPeerTCP> take_connection();
+
+ virtual void stop(); //stop listening
+
+ static void make_default();
+ static void cleanup();
+
+ TCPServerWinsock();
+ ~TCPServerWinsock();
+};
+
+#endif
diff --git a/platform/winrt/SCsub b/platform/winrt/SCsub
new file mode 100644
index 0000000000..2ea8cbd0de
--- /dev/null
+++ b/platform/winrt/SCsub
@@ -0,0 +1,11 @@
+Import('env')
+
+files = [
+ 'thread_winrt.cpp',
+# '#platform/windows/stream_peer_winsock.cpp',
+ 'gl_context_egl.cpp',
+ 'app.cpp',
+ 'os_winrt.cpp',
+]
+
+env.Program('#bin/godot', files)
diff --git a/platform/winrt/app.cpp b/platform/winrt/app.cpp
new file mode 100644
index 0000000000..263cd684c4
--- /dev/null
+++ b/platform/winrt/app.cpp
@@ -0,0 +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);
+}
diff --git a/platform/winrt/app.h b/platform/winrt/app.h
new file mode 100644
index 0000000000..9ce2fe560f
--- /dev/null
+++ b/platform/winrt/app.h
@@ -0,0 +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];
+ };
+
+}
diff --git a/platform/winrt/detect.py b/platform/winrt/detect.py
new file mode 100644
index 0000000000..7439f0cd55
--- /dev/null
+++ b/platform/winrt/detect.py
@@ -0,0 +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
diff --git a/platform/winrt/gl_context_egl.cpp b/platform/winrt/gl_context_egl.cpp
new file mode 100644
index 0000000000..fd9fbe406f
--- /dev/null
+++ b/platform/winrt/gl_context_egl.cpp
@@ -0,0 +1,177 @@
+#include "gl_context_egl.h"
+
+#include "EGL/eglext.h"
+
+using namespace Platform;
+
+void ContextEGL::release_current() {
+
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEglContext);
+};
+
+void ContextEGL::make_current() {
+
+ eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
+};
+
+int ContextEGL::get_window_width() {
+
+ return width;
+};
+
+int ContextEGL::get_window_height() {
+
+ return height;
+};
+
+void ContextEGL::reset() {
+
+ cleanup();
+
+ window = CoreWindow::GetForCurrentThread();
+ initialize();
+};
+
+void ContextEGL::swap_buffers() {
+
+ if (eglSwapBuffers(mEglDisplay, mEglSurface) != EGL_TRUE)
+ {
+ cleanup();
+
+ window = CoreWindow::GetForCurrentThread();
+ initialize();
+
+ // tell rasterizer to reload textures and stuff?
+ }
+};
+
+Error ContextEGL::initialize() {
+
+ EGLint configAttribList[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 8,
+ EGL_STENCIL_SIZE, 8,
+ EGL_SAMPLE_BUFFERS, 0,
+ EGL_NONE
+ };
+
+ EGLint surfaceAttribList[] = {
+ EGL_NONE, EGL_NONE
+ };
+
+ EGLint numConfigs = 0;
+ EGLint majorVersion = 1;
+ EGLint minorVersion = 0;
+ EGLDisplay display = EGL_NO_DISPLAY;
+ EGLContext context = EGL_NO_CONTEXT;
+ EGLSurface surface = EGL_NO_SURFACE;
+ EGLConfig config = nullptr;
+ EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
+
+ try {
+
+ const EGLint displayAttributes[] =
+ {
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
+ EGL_NONE,
+ };
+
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
+
+ if (!eglGetPlatformDisplayEXT)
+ {
+ throw Exception::CreateException(E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT");
+ }
+
+ display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes);
+
+ if (display == EGL_NO_DISPLAY)
+ {
+ throw Exception::CreateException(E_FAIL, L"Failed to get default EGL display");
+ }
+
+ if (eglInitialize(display, &majorVersion, &minorVersion) == EGL_FALSE)
+ {
+ throw Exception::CreateException(E_FAIL, L"Failed to initialize EGL");
+ }
+
+ if (eglGetConfigs(display, NULL, 0, &numConfigs) == EGL_FALSE)
+ {
+ throw Exception::CreateException(E_FAIL, L"Failed to get EGLConfig count");
+ }
+
+ if (eglChooseConfig(display, configAttribList, &config, 1, &numConfigs) == EGL_FALSE)
+ {
+ throw Exception::CreateException(E_FAIL, L"Failed to choose first EGLConfig count");
+ }
+
+ surface = eglCreateWindowSurface(display, config, reinterpret_cast<IInspectable*>(window), surfaceAttribList);
+ if (surface == EGL_NO_SURFACE)
+ {
+ throw Exception::CreateException(E_FAIL, L"Failed to create EGL fullscreen surface");
+ }
+
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+ if (context == EGL_NO_CONTEXT)
+ {
+ throw Exception::CreateException(E_FAIL, L"Failed to create EGL context");
+ }
+
+ if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
+ {
+ throw Exception::CreateException(E_FAIL, L"Failed to make fullscreen EGLSurface current");
+ }
+ } catch (...) {
+ return FAILED;
+ };
+
+ mEglDisplay = display;
+ mEglSurface = surface;
+ mEglContext = context;
+
+ eglQuerySurface(display,surface,EGL_WIDTH,&width);
+ eglQuerySurface(display,surface,EGL_HEIGHT,&height);
+
+ return OK;
+};
+
+void ContextEGL::cleanup() {
+
+ if (mEglDisplay != EGL_NO_DISPLAY && mEglSurface != EGL_NO_SURFACE)
+ {
+ eglDestroySurface(mEglDisplay, mEglSurface);
+ mEglSurface = EGL_NO_SURFACE;
+ }
+
+ if (mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT)
+ {
+ eglDestroyContext(mEglDisplay, mEglContext);
+ mEglContext = EGL_NO_CONTEXT;
+ }
+
+ if (mEglDisplay != EGL_NO_DISPLAY)
+ {
+ eglTerminate(mEglDisplay);
+ mEglDisplay = EGL_NO_DISPLAY;
+ }
+};
+
+ContextEGL::ContextEGL(CoreWindow^ p_window) :
+ mEglDisplay(EGL_NO_DISPLAY),
+ mEglContext(EGL_NO_CONTEXT),
+ mEglSurface(EGL_NO_SURFACE)
+ {
+
+ window = p_window;
+};
+
+ContextEGL::~ContextEGL() {
+
+ cleanup();
+};
+
diff --git a/platform/winrt/gl_context_egl.h b/platform/winrt/gl_context_egl.h
new file mode 100644
index 0000000000..ca3760e723
--- /dev/null
+++ b/platform/winrt/gl_context_egl.h
@@ -0,0 +1,45 @@
+#ifndef CONTEXT_EGL_H
+#define CONTEXT_EGL_H
+
+#include <wrl.h>
+
+#include "os/os.h"
+#include "EGL/egl.h"
+#include "error_list.h"
+#include "drivers/gl_context/context_gl.h"
+
+using namespace Windows::UI::Core;
+
+class ContextEGL : public ContextGL {
+
+ CoreWindow^ window;
+
+ EGLDisplay mEglDisplay;
+ EGLContext mEglContext;
+ EGLSurface mEglSurface;
+
+ EGLint width;
+ EGLint height;
+
+public:
+
+ virtual void release_current();
+
+ virtual void make_current();
+
+ virtual int get_window_width();
+ virtual int get_window_height();
+ virtual void swap_buffers();
+
+ virtual Error initialize();
+ void reset();
+
+ void cleanup();
+
+ ContextEGL(CoreWindow^ p_window);
+ ~ContextEGL();
+
+};
+
+#endif
+
diff --git a/platform/winrt/include/EGL/egl.h b/platform/winrt/include/EGL/egl.h
new file mode 100644
index 0000000000..12590a0e20
--- /dev/null
+++ b/platform/winrt/include/EGL/egl.h
@@ -0,0 +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
diff --git a/platform/winrt/include/EGL/eglext.h b/platform/winrt/include/EGL/eglext.h
new file mode 100644
index 0000000000..05b2555f31
--- /dev/null
+++ b/platform/winrt/include/EGL/eglext.h
@@ -0,0 +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
diff --git a/platform/winrt/include/EGL/eglplatform.h b/platform/winrt/include/EGL/eglplatform.h
new file mode 100644
index 0000000000..71dadc79d5
--- /dev/null
+++ b/platform/winrt/include/EGL/eglplatform.h
@@ -0,0 +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 */
diff --git a/platform/winrt/include/FunctionDiscoveryKeys_devpkey.h b/platform/winrt/include/FunctionDiscoveryKeys_devpkey.h
new file mode 100644
index 0000000000..303e70b029
--- /dev/null
+++ b/platform/winrt/include/FunctionDiscoveryKeys_devpkey.h
@@ -0,0 +1,213 @@
+#pragma once
+#if 0
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ devpkey.h
+
+Abstract:
+
+ Defines property keys for the Plug and Play Device Property API.
+
+Author:
+
+ Jim Cavalaris (jamesca) 10-14-2003
+
+Environment:
+
+ User-mode only.
+
+Revision History:
+
+ 14-October-2003 jamesca
+
+ Creation and initial implementation.
+
+ 20-June-2006 dougb
+
+ Copied Jim's version replaced "DEFINE_DEVPROPKEY(DEVPKEY_" with "DEFINE_PROPERTYKEY(PKEY_"
+
+--*/
+
+//#include <devpropdef.h>
+
+//
+// _NAME
+//
+
+DEFINE_PROPERTYKEY(PKEY_NAME, 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10); // DEVPROP_TYPE_STRING
+
+//
+// Device properties
+// These PKEYs correspond to the old setupapi SPDRP_XXX properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_CompatibleIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Service, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 6); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Class, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 9); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ClassGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 10); // DEVPROP_TYPE_GUID
+DEFINE_PROPERTYKEY(PKEY_Device_Driver, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 11); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ConfigFlags, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 12); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_LocationInfo, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_PDOName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 16); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Capabilities, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 17); // DEVPROP_TYPE_UNINT32
+DEFINE_PROPERTYKEY(PKEY_Device_UINumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 18); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_UpperFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 19); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_LowerFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 20); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BusTypeGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 21); // DEVPROP_TYPE_GUID
+DEFINE_PROPERTYKEY(PKEY_Device_LegacyBusType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 22); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_BusNumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_EnumeratorName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 24); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Security, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR
+DEFINE_PROPERTYKEY(PKEY_Device_SecuritySDS, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DevType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 27); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Exclusive, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 28); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Characteristics, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 29); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Address, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 30); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_UINumberDescFormat, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 31); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_PowerData, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 32); // DEVPROP_TYPE_BINARY
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicy, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 33); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyDefault, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 34); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyOverride, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 35); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_InstallState, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 36); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_LocationPaths, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 37); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BaseContainerId, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 38); // DEVPROP_TYPE_GUID
+
+//
+// Device properties
+// These PKEYs correspond to a device's status and problem code
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DevNodeStatus, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 2); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_ProblemCode, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 3); // DEVPROP_TYPE_UINT32
+
+//
+// Device properties
+// These PKEYs correspond to device relations
+//
+DEFINE_PROPERTYKEY(PKEY_Device_EjectionRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 4); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 5); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_PowerRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 6); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BusRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 7); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Children, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 9); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Siblings, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 10); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_TransportRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 11); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Other Device properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_Reported, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 2); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_Legacy, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 3); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256); // DEVPROP_TYPE_STRING
+
+DEFINE_PROPERTYKEY(PKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID
+
+DEFINE_PROPERTYKEY(PKEY_Device_ModelId, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 2); // DEVPROP_TYPE_GUID
+
+DEFINE_PROPERTYKEY(PKEY_Device_FriendlyNameAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 3); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_ManufacturerAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 4); // DEVPROP_TYPE_UINT32
+
+DEFINE_PROPERTYKEY(PKEY_Device_PresenceNotForDevice, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 5); // DEVPROP_TYPE_BOOLEAN
+
+
+DEFINE_PROPERTYKEY(PKEY_Numa_Proximity_Domain, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 1); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_DHP_Rebalance_Policy, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 2); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Numa_Node, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
+
+DEFINE_PROPERTYKEY(PKEY_Device_InstallInProgress, 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 9); // DEVPROP_TYPE_BOOLEAN
+
+//
+// Device driver properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2); // DEVPROP_TYPE_FILETIME
+DEFINE_PROPERTYKEY(PKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverDesc, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 4); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfPath, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 5); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSection, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 6); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSectionExt, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 7); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_MatchingDeviceId, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 8); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 9); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverPropPageProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 10); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverCoInstallers, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 11); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerTags, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 12); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerExceptions, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 13); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverRank, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 14); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_DriverLogoLevel, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 15); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_NoConnectSound, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 17); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_GenericDriverInstalled, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 18); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_AdditionalSoftwareRequested, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 19);// DEVPROP_TYPE_BOOLEAN
+
+//
+// Device safe-removal properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequired, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 2); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequiredOverride, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 3);// DEVPROP_TYPE_BOOLEAN
+
+
+//
+// Device properties that were set by the driver package that was installed
+// on the device.
+//
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_Model, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_VendorWebSite, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 3); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_DetailedDescription, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 4); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_DocumentationLink, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 5); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_Icon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 6); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_BrandingIcon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 7); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Device setup class properties
+// These PKEYs correspond to the old setupapi SPCRP_XXX properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_UpperFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 19); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_LowerFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 20); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Security, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_SecuritySDS, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_DevType, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 27); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Exclusive, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 28); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Characteristics, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 29); // DEVPROP_TYPE_UINT32
+
+//
+// Device setup class properties
+// These PKEYs correspond to registry values under the device class GUID key
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Name, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassName, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 3); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Icon, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 4); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassInstaller, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 5); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_PropPageProvider, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 6); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoInstallClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 7); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoDisplayClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 8); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_SilentInstall, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 9); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoUseClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 10); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_DefaultService, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 11); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_IconPath, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 12); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Other Device setup class properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassCoInstallers, 0x713d1703, 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c, 2); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Device interface properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Enabled, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 3); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_ClassGuid, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 4); // DEVPROP_TYPE_GUID
+
+//
+// Device interface class properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceInterfaceClass_DefaultInterface, 0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 2); // DEVPROP_TYPE_STRING
+
+
+
+
+#endif
diff --git a/platform/winrt/include/GLES2/gl2.h b/platform/winrt/include/GLES2/gl2.h
new file mode 100644
index 0000000000..c2d8357268
--- /dev/null
+++ b/platform/winrt/include/GLES2/gl2.h
@@ -0,0 +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_ */
diff --git a/platform/winrt/include/GLES2/gl2ext.h b/platform/winrt/include/GLES2/gl2ext.h
new file mode 100644
index 0000000000..d77fdbaebc
--- /dev/null
+++ b/platform/winrt/include/GLES2/gl2ext.h
@@ -0,0 +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_ */
diff --git a/platform/winrt/include/GLES2/gl2platform.h b/platform/winrt/include/GLES2/gl2platform.h
new file mode 100644
index 0000000000..c9fa3c4d64
--- /dev/null
+++ b/platform/winrt/include/GLES2/gl2platform.h
@@ -0,0 +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_ */
diff --git a/platform/winrt/include/GLES3/gl3.h b/platform/winrt/include/GLES3/gl3.h
new file mode 100644
index 0000000000..9c79862c0d
--- /dev/null
+++ b/platform/winrt/include/GLES3/gl3.h
@@ -0,0 +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
diff --git a/platform/winrt/include/GLES3/gl3ext.h b/platform/winrt/include/GLES3/gl3ext.h
new file mode 100644
index 0000000000..4d4ea96c4d
--- /dev/null
+++ b/platform/winrt/include/GLES3/gl3ext.h
@@ -0,0 +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_ */
+
diff --git a/platform/winrt/include/GLES3/gl3platform.h b/platform/winrt/include/GLES3/gl3platform.h
new file mode 100644
index 0000000000..1bd1a850fa
--- /dev/null
+++ b/platform/winrt/include/GLES3/gl3platform.h
@@ -0,0 +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_ */
diff --git a/platform/winrt/include/GLSLANG/ShaderLang.h b/platform/winrt/include/GLSLANG/ShaderLang.h
new file mode 100644
index 0000000000..647fed6a02
--- /dev/null
+++ b/platform/winrt/include/GLSLANG/ShaderLang.h
@@ -0,0 +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_
diff --git a/platform/winrt/include/GLSLANG/ShaderVars.h b/platform/winrt/include/GLSLANG/ShaderVars.h
new file mode 100644
index 0000000000..da21c3e76e
--- /dev/null
+++ b/platform/winrt/include/GLSLANG/ShaderVars.h
@@ -0,0 +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_
diff --git a/platform/winrt/include/KHR/khrplatform.h b/platform/winrt/include/KHR/khrplatform.h
new file mode 100644
index 0000000000..c9e6f17d34
--- /dev/null
+++ b/platform/winrt/include/KHR/khrplatform.h
@@ -0,0 +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_ */
diff --git a/platform/winrt/include/angle_gl.h b/platform/winrt/include/angle_gl.h
new file mode 100644
index 0000000000..d093f75ee2
--- /dev/null
+++ b/platform/winrt/include/angle_gl.h
@@ -0,0 +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_
diff --git a/platform/winrt/include/angle_windowsstore.h b/platform/winrt/include/angle_windowsstore.h
new file mode 100644
index 0000000000..53ec93e037
--- /dev/null
+++ b/platform/winrt/include/angle_windowsstore.h
@@ -0,0 +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_
diff --git a/platform/winrt/logo.png b/platform/winrt/logo.png
new file mode 100644
index 0000000000..a27e14dde8
--- /dev/null
+++ b/platform/winrt/logo.png
Binary files differ
diff --git a/platform/winrt/os_winrt.cpp b/platform/winrt/os_winrt.cpp
new file mode 100644
index 0000000000..24be2f47e7
--- /dev/null
+++ b/platform/winrt/os_winrt.cpp
@@ -0,0 +1,706 @@
+/*************************************************************************/
+/* os_winrt.cpp */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "os_winrt.h"
+#include "drivers/nedmalloc/memory_pool_static_nedmalloc.h"
+#include "drivers/unix/memory_pool_static_malloc.h"
+#include "os/memory_pool_dynamic_static.h"
+#include "thread_winrt.h"
+//#include "drivers/windows/semaphore_windows.h"
+#include "drivers/windows/mutex_windows.h"
+#include "main/main.h"
+#include "drivers/windows/file_access_windows.h"
+#include "drivers/windows/dir_access_windows.h"
+
+
+#include "servers/visual/visual_server_raster.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+
+#include "os/pc_joystick_map.h"
+#include "os/memory_pool_dynamic_prealloc.h"
+#include "globals.h"
+#include "io/marshalls.h"
+
+#include <wrl.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;
+
+
+int OSWinrt::get_video_driver_count() const {
+
+ return 1;
+}
+const char * OSWinrt::get_video_driver_name(int p_driver) const {
+
+ return "GLES2";
+}
+
+OS::VideoMode OSWinrt::get_default_video_mode() const {
+
+ return video_mode;
+}
+
+int OSWinrt::get_audio_driver_count() const {
+
+ return AudioDriverManagerSW::get_driver_count();
+}
+const char * OSWinrt::get_audio_driver_name(int p_driver) const {
+
+ AudioDriverSW* driver = AudioDriverManagerSW::get_driver(p_driver);
+ ERR_FAIL_COND_V( !driver, "" );
+ return AudioDriverManagerSW::get_driver(p_driver)->get_name();
+}
+
+static MemoryPoolStatic *mempool_static=NULL;
+static MemoryPoolDynamic *mempool_dynamic=NULL;
+
+void OSWinrt::initialize_core() {
+
+
+ last_button_state=0;
+
+ //RedirectIOToConsole();
+
+ ThreadWinrt::make_default();
+ //SemaphoreWindows::make_default();
+ MutexWindows::make_default();
+
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA);
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM);
+ //FileAccessBufferedFA<FileAccessWindows>::make_default();
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM);
+
+ //TCPServerWinsock::make_default();
+ //StreamPeerWinsock::make_default();
+
+ mempool_static = new MemoryPoolStaticMalloc;
+#if 1
+ mempool_dynamic = memnew( MemoryPoolDynamicStatic );
+#else
+#define DYNPOOL_SIZE 4*1024*1024
+ void * buffer = malloc( DYNPOOL_SIZE );
+ mempool_dynamic = memnew( MemoryPoolDynamicPrealloc(buffer,DYNPOOL_SIZE) );
+
+#endif
+
+ // We need to know how often the clock is updated
+ if( !QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second) )
+ ticks_per_second = 1000;
+ // If timeAtGameStart is 0 then we get the time since
+ // the start of the computer when we call GetGameTime()
+ ticks_start = 0;
+ ticks_start = get_ticks_usec();
+
+ cursor_shape=CURSOR_ARROW;
+}
+
+bool OSWinrt::can_draw() const {
+
+ return !minimized;
+};
+
+
+void OSWinrt::set_gl_context(ContextEGL* p_context) {
+
+ gl_context = p_context;
+};
+
+void OSWinrt::screen_size_changed() {
+
+ gl_context->reset();
+};
+
+void OSWinrt::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ main_loop=NULL;
+ outside=true;
+
+ gl_context->initialize();
+ VideoMode vm;
+ vm.width = gl_context->get_window_width();
+ vm.height = gl_context->get_window_height();
+ vm.fullscreen = true;
+ vm.resizable = false;
+
+ set_video_mode(vm);
+
+ gl_context->make_current();
+ rasterizer = memnew( RasterizerGLES2 );
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ if (get_render_thread_mode()!=RENDER_THREAD_UNSAFE) {
+
+ visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD));
+ }
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ visual_server->init();
+
+ input = memnew( InputDefault );
+
+ 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();
+
+
+ _ensure_data_dir();
+}
+
+void OSWinrt::set_clipboard(const String& p_text) {
+
+ /*
+ if (!OpenClipboard(hWnd)) {
+ ERR_EXPLAIN("Unable to open clipboard.");
+ ERR_FAIL();
+ };
+ EmptyClipboard();
+
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (p_text.length() + 1) * sizeof(CharType));
+ if (mem == NULL) {
+ ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
+ ERR_FAIL();
+ };
+ LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
+ memcpy(lptstrCopy, p_text.c_str(), (p_text.length() + 1) * sizeof(CharType));
+ //memset((lptstrCopy + p_text.length()), 0, sizeof(CharType));
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_UNICODETEXT, mem);
+
+ // set the CF_TEXT version (not needed?)
+ CharString utf8 = p_text.utf8();
+ mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
+ if (mem == NULL) {
+ ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
+ ERR_FAIL();
+ };
+ LPTSTR ptr = (LPTSTR)GlobalLock(mem);
+ memcpy(ptr, utf8.get_data(), utf8.length());
+ ptr[utf8.length()] = 0;
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_TEXT, mem);
+
+ CloseClipboard();
+ */
+};
+
+String OSWinrt::get_clipboard() const {
+
+ /*
+ String ret;
+ if (!OpenClipboard(hWnd)) {
+ ERR_EXPLAIN("Unable to open clipboard.");
+ ERR_FAIL_V("");
+ };
+
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem != NULL) {
+
+ LPWSTR ptr = (LPWSTR)GlobalLock(mem);
+ if (ptr != NULL) {
+
+ ret = String((CharType*)ptr);
+ GlobalUnlock(mem);
+ };
+ };
+
+ } else if (IsClipboardFormatAvailable(CF_TEXT)) {
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem != NULL) {
+
+ LPTSTR ptr = (LPTSTR)GlobalLock(mem);
+ if (ptr != NULL) {
+
+ ret.parse_utf8((const char*)ptr);
+ GlobalUnlock(mem);
+ };
+ };
+ };
+
+ CloseClipboard();
+
+ return ret;
+ */
+ return "";
+};
+
+
+void OSWinrt::input_event(InputEvent &p_event) {
+ p_event.ID = ++last_id;
+ input->parse_input_event(p_event);
+};
+
+void OSWinrt::delete_main_loop() {
+
+ if (main_loop)
+ memdelete(main_loop);
+ main_loop=NULL;
+}
+
+void OSWinrt::set_main_loop( MainLoop * p_main_loop ) {
+
+ input->set_main_loop(p_main_loop);
+ main_loop=p_main_loop;
+}
+
+void OSWinrt::finalize() {
+
+ if(main_loop)
+ memdelete(main_loop);
+
+ main_loop=NULL;
+
+ visual_server->finish();
+ memdelete(visual_server);
+#ifdef OPENGL_ENABLED
+ if (gl_context)
+ memdelete(gl_context);
+#endif
+ if (rasterizer)
+ memdelete(rasterizer);
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+ //if (debugger_connection_console) {
+// memdelete(debugger_connection_console);
+//}
+
+ memdelete(sample_manager);
+
+ audio_server->finish();
+ memdelete(audio_server);
+
+ memdelete(input);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+}
+void OSWinrt::finalize_core() {
+
+ if (mempool_dynamic)
+ memdelete( mempool_dynamic );
+ if (mempool_static)
+ delete mempool_static;
+
+}
+
+void OSWinrt::vprint(const char* p_format, va_list p_list, bool p_stderr) {
+
+ char buf[16384+1];
+ int len = vsnprintf(buf,16384,p_format,p_list);
+ if (len<=0)
+ return;
+ buf[len]=0;
+
+
+ int wlen = MultiByteToWideChar(CP_UTF8,0,buf,len,NULL,0);
+ if (wlen<0)
+ return;
+
+ wchar_t *wbuf = (wchar_t*)malloc((len+1)*sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8,0,buf,len,wbuf,wlen);
+ wbuf[wlen]=0;
+
+ if (p_stderr)
+ fwprintf(stderr,L"%s",wbuf);
+ else
+ wprintf(L"%s",wbuf);
+
+#ifdef STDOUT_FILE
+ //vwfprintf(stdo,p_format,p_list);
+#endif
+ free(wbuf);
+
+ fflush(stdout);
+};
+
+void OSWinrt::alert(const String& p_alert,const String& p_title) {
+
+ print_line("ALERT: "+p_alert);
+}
+
+void OSWinrt::set_mouse_mode(MouseMode p_mode) {
+
+}
+
+OSWinrt::MouseMode OSWinrt::get_mouse_mode() const{
+
+ return mouse_mode;
+}
+
+
+
+Point2 OSWinrt::get_mouse_pos() const {
+
+ return Point2(old_x, old_y);
+}
+
+int OSWinrt::get_mouse_button_state() const {
+
+ return last_button_state;
+}
+
+void OSWinrt::set_window_title(const String& p_title) {
+
+}
+
+void OSWinrt::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+ video_mode = p_video_mode;
+}
+OS::VideoMode OSWinrt::get_video_mode(int p_screen) const {
+
+ return video_mode;
+}
+void OSWinrt::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+
+}
+
+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) {
+
+ 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;
+ }
+}
+
+
+String OSWinrt::get_name() {
+
+ return "WinRT";
+}
+
+OS::Date OSWinrt::get_date(bool utc) const {
+
+ SYSTEMTIME systemtime;
+ if (utc)
+ GetSystemTime(&systemtime);
+ else
+ GetLocalTime(&systemtime);
+
+ Date date;
+ date.day=systemtime.wDay;
+ date.month=Month(systemtime.wMonth);
+ date.weekday=Weekday(systemtime.wDayOfWeek);
+ date.year=systemtime.wYear;
+ date.dst=false;
+ return date;
+}
+OS::Time OSWinrt::get_time(bool utc) const {
+
+ SYSTEMTIME systemtime;
+ if (utc)
+ GetSystemTime(&systemtime);
+ else
+ GetLocalTime(&systemtime);
+
+ Time time;
+ time.hour=systemtime.wHour;
+ time.min=systemtime.wMinute;
+ time.sec=systemtime.wSecond;
+ return time;
+}
+
+OS::TimeZoneInfo OS_Windows::get_time_zone_info() const {
+ TIME_ZONE_INFORMATION info;
+ bool daylight = false;
+ if (GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT)
+ daylight = true;
+
+ TimeZoneInfo ret;
+ if (daylight) {
+ ret.name = info.DaylightName;
+ } else {
+ ret.name = info.StandardName;
+ }
+
+ ret.bias = info.Bias;
+ return ret;
+}
+
+uint64_t OSWinrt::get_unix_time() const {
+
+ FILETIME ft;
+ SYSTEMTIME st;
+ GetSystemTime(&systemtime);
+ SystemTimeToFileTime(&st, &ft);
+
+ SYSTEMTIME ep;
+ ep.wYear = 1970;
+ ep.wMonth = 1;
+ ep.wDayOfWeek = 4;
+ ep.wDay = 1;
+ ep.wHour = 0;
+ ep.wMinute = 0;
+ ep.wSecond = 0;
+ ep.wMilliseconds = 0;
+ FILETIME fep;
+ SystemTimeToFileTime(&ep, &fep);
+
+ return (*(uint64_t*)&ft - *(uint64_t*)&fep) / 10000000;
+};
+
+void OSWinrt::delay_usec(uint32_t p_usec) const {
+
+ int msec = p_usec < 1000 ? 1 : p_usec / 1000;
+
+ // no Sleep()
+ WaitForSingleObjectEx(GetCurrentThread(), msec, false);
+
+}
+uint64_t OSWinrt::get_ticks_usec() const {
+
+ uint64_t ticks;
+ uint64_t time;
+ // This is the number of clock ticks since start
+ QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
+ // Divide by frequency to get the time in seconds
+ time = ticks * 1000000L / ticks_per_second;
+ // Subtract the time at game start to get
+ // the time since the game started
+ time -= ticks_start;
+ return time;
+}
+
+
+void OSWinrt::process_events() {
+
+}
+
+void OSWinrt::set_cursor_shape(CursorShape p_shape) {
+
+}
+
+Error OSWinrt::execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id,String* r_pipe,int *r_exitcode) {
+
+ return FAILED;
+};
+
+Error OSWinrt::kill(const ProcessID& p_pid) {
+
+ return FAILED;
+};
+
+Error OSWinrt::set_cwd(const String& p_cwd) {
+
+ return FAILED;
+}
+
+String OSWinrt::get_executable_path() const {
+
+ return "";
+}
+
+void OSWinrt::set_icon(const Image& p_icon) {
+
+}
+
+
+bool OSWinrt::has_environment(const String& p_var) const {
+
+ return false;
+};
+
+String OSWinrt::get_environment(const String& p_var) const {
+
+ return "";
+};
+
+String OSWinrt::get_stdin_string(bool p_block) {
+
+ return String();
+}
+
+
+void OSWinrt::move_window_to_foreground() {
+
+}
+
+Error OSWinrt::shell_open(String p_uri) {
+
+ return FAILED;
+}
+
+
+String OSWinrt::get_locale() const {
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // this should work on phone 8.1, but it doesn't
+ return "en";
+#else
+ Platform::String ^language = Windows::Globalization::Language::CurrentInputMethodLanguageTag;
+ return language->Data();
+#endif
+}
+
+void OSWinrt::release_rendering_thread() {
+
+ gl_context->release_current();
+}
+
+void OSWinrt::make_rendering_thread() {
+
+ gl_context->make_current();
+}
+
+void OSWinrt::swap_buffers() {
+
+ gl_context->swap_buffers();
+}
+
+
+void OSWinrt::run() {
+
+ if (!main_loop)
+ return;
+
+ main_loop->init();
+
+ uint64_t last_ticks=get_ticks_usec();
+
+ int frames=0;
+ uint64_t frame=0;
+
+ while (!force_quit) {
+
+ CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
+ process_events(); // get rid of pending events
+ if (Main::iteration()==true)
+ break;
+ };
+
+ main_loop->finish();
+
+}
+
+
+
+MainLoop *OSWinrt::get_main_loop() const {
+
+ return main_loop;
+}
+
+
+String OSWinrt::get_data_dir() const {
+
+ Windows::Storage::StorageFolder ^data_folder = Windows::Storage::ApplicationData::Current->LocalFolder;
+
+ return data_folder->Path->Data();
+}
+
+
+OSWinrt::OSWinrt() {
+
+ key_event_pos=0;
+ force_quit=false;
+ alt_mem=false;
+ gr_mem=false;
+ shift_mem=false;
+ control_mem=false;
+ meta_mem=false;
+ minimized = false;
+
+ pressrc=0;
+ old_invalid=true;
+ last_id=0;
+ mouse_mode=MOUSE_MODE_VISIBLE;
+#ifdef STDOUT_FILE
+ stdo=fopen("stdout.txt","wb");
+#endif
+
+ gl_context = NULL;
+
+ AudioDriverManagerSW::add_driver(&audio_driver);
+}
+
+
+OSWinrt::~OSWinrt()
+{
+#ifdef STDOUT_FILE
+ fclose(stdo);
+#endif
+}
+
+
diff --git a/platform/winrt/os_winrt.h b/platform/winrt/os_winrt.h
new file mode 100644
index 0000000000..5719426f9f
--- /dev/null
+++ b/platform/winrt/os_winrt.h
@@ -0,0 +1,255 @@
+/*************************************************************************/
+/* OSWinrt.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef OSWinrt_H
+#define OSWinrt_H
+
+#include "os/input.h"
+#include "os/os.h"
+#include "servers/visual_server.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/physics/physics_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 "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/audio/audio_driver_dummy.h"
+
+#include "gl_context_egl.h"
+
+#include <windows.h>
+
+#include <io.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include "main/input_default.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class OSWinrt : public OS {
+
+ enum {
+ JOYSTICKS_MAX = 8,
+ JOY_AXIS_COUNT = 6,
+ MAX_JOY_AXIS = 32768, // I've no idea
+ KEY_EVENT_BUFFER_SIZE=512
+ };
+
+ FILE *stdo;
+
+
+ struct KeyEvent {
+
+ InputModifierState mod_state;
+ UINT uMsg;
+ WPARAM wParam;
+ LPARAM lParam;
+
+ };
+
+ KeyEvent key_event_buffer[KEY_EVENT_BUFFER_SIZE];
+ int key_event_pos;
+
+
+ uint64_t ticks_start;
+ uint64_t ticks_per_second;
+
+ bool minimized;
+ bool old_invalid;
+ bool outside;
+ int old_x,old_y;
+ Point2i center;
+ unsigned int last_id;
+ VisualServer *visual_server;
+ Rasterizer *rasterizer;
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+ int pressrc;
+
+ ContextEGL* gl_context;
+
+ 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];
+
+ VideoMode video_mode;
+
+ MainLoop *main_loop;
+
+ AudioDriverDummy audio_driver;
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+
+ MouseMode mouse_mode;
+ bool alt_mem;
+ bool gr_mem;
+ bool shift_mem;
+ bool control_mem;
+ bool meta_mem;
+ bool force_quit;
+ uint32_t last_button_state;
+
+ CursorShape cursor_shape;
+
+ InputDefault *input;
+
+ void _post_dpad(DWORD p_dpad, int p_device, bool p_pressed);
+
+ void _drag_event(int idx,UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void _touch_event(int idx, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+
+ // functions used by main to initialize/deintialize the OS
+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 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();
+ virtual void finalize_core();
+
+ void process_events();
+
+ void probe_joysticks();
+ void process_joysticks();
+ void process_key_events();
+
+public:
+
+ void print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type);
+
+ virtual void vprint(const char *p_format, va_list p_list, bool p_stderr=false);
+ virtual void alert(const String& p_alert,const String& p_title="ALERT!");
+ String get_stdin_string(bool p_block);
+
+ void set_mouse_mode(MouseMode p_mode);
+ MouseMode get_mouse_mode() 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_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 MainLoop *get_main_loop() const;
+
+ virtual String get_name();
+
+ virtual Date get_date(bool utc) const;
+ virtual Time get_time(bool utc) const;
+ virtual TimeZoneInfo get_time_zone_info() const;
+ virtual uint64_t get_unix_time() const;
+
+ virtual bool can_draw() const;
+ virtual Error set_cwd(const String& p_cwd);
+
+ virtual void delay_usec(uint32_t p_usec) const;
+ virtual uint64_t get_ticks_usec() 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);
+ 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;
+
+ virtual void set_clipboard(const String& p_text);
+ virtual String get_clipboard() const;
+
+ void set_cursor_shape(CursorShape p_shape);
+ void set_icon(const Image& p_icon);
+
+ virtual String get_executable_path() const;
+
+ virtual String get_locale() const;
+
+ virtual void move_window_to_foreground();
+ virtual String get_data_dir() const;
+
+ void set_gl_context(ContextEGL* p_context);
+ void screen_size_changed();
+
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+ virtual bool has_touchscreen_ui_hint() const { return true; };
+
+ virtual Error shell_open(String p_uri);
+
+ void run();
+
+ virtual bool get_swap_ok_cancel() { return true; }
+
+ void input_event(InputEvent &p_event);
+
+ OSWinrt();
+ ~OSWinrt();
+
+};
+
+#endif
diff --git a/platform/winrt/platform_config.h b/platform/winrt/platform_config.h
new file mode 100644
index 0000000000..91669ad489
--- /dev/null
+++ b/platform/winrt/platform_config.h
@@ -0,0 +1,2 @@
+#include <malloc.h>
+
diff --git a/platform/winrt/thread_winrt.cpp b/platform/winrt/thread_winrt.cpp
new file mode 100644
index 0000000000..3217292bee
--- /dev/null
+++ b/platform/winrt/thread_winrt.cpp
@@ -0,0 +1,42 @@
+#include "thread_winrt.h"
+
+#include "os/memory.h"
+
+Thread* ThreadWinrt::create_func_winrt(ThreadCreateCallback p_callback,void *p_user,const Settings&) {
+
+ ThreadWinrt* thread = memnew(ThreadWinrt);
+ std::thread new_thread(p_callback, p_user);
+ std::swap(thread->thread, new_thread);
+
+ return thread;
+};
+
+Thread::ID ThreadWinrt::get_thread_ID_func_winrt() {
+
+ return std::hash<std::thread::id>()(std::this_thread::get_id());
+};
+
+void ThreadWinrt::wait_to_finish_func_winrt(Thread* p_thread) {
+
+ ThreadWinrt *tp=static_cast<ThreadWinrt*>(p_thread);
+ tp->thread.join();
+};
+
+
+Thread::ID ThreadWinrt::get_ID() const {
+
+ return std::hash<std::thread::id>()(thread.get_id());
+};
+
+void ThreadWinrt::make_default() {
+
+};
+
+ThreadWinrt::ThreadWinrt() {
+
+};
+
+ThreadWinrt::~ThreadWinrt() {
+
+};
+
diff --git a/platform/winrt/thread_winrt.h b/platform/winrt/thread_winrt.h
new file mode 100644
index 0000000000..6140c9c506
--- /dev/null
+++ b/platform/winrt/thread_winrt.h
@@ -0,0 +1,35 @@
+#ifndef THREAD_WINRT_H
+#define THREAD_WINRT_H
+
+#ifdef WINRT_ENABLED
+
+#include "os/thread.h"
+
+#include <thread>
+
+class ThreadWinrt : public Thread {
+
+ std::thread thread;
+
+ static Thread* create_func_winrt(ThreadCreateCallback p_callback,void *,const Settings&);
+ static ID get_thread_ID_func_winrt();
+ static void wait_to_finish_func_winrt(Thread* p_thread);
+
+ ThreadWinrt();
+public:
+
+
+ virtual ID get_ID() const;
+
+ static void make_default();
+
+
+ ~ThreadWinrt();
+
+};
+
+
+#endif
+
+#endif
+
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
index 1a552cbaac..7a6f02daa5 100644
--- a/platform/x11/SCsub
+++ b/platform/x11/SCsub
@@ -8,5 +8,3 @@ common_x11=[\
]
env.Program('#bin/godot',['godot_x11.cpp']+common_x11)
-if env['target'] == "release":
- env.Command('#bin/godot_rel', '#bin/godot', Copy('bin/godot_rel', 'bin/godot'))
diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp
index b56b54822e..3db1f6da25 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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) {
@@ -129,17 +130,6 @@ Error ContextGL_X11::initialize() {
}
//};
- if (!OS::get_singleton()->get_video_mode().resizable) {
- XSizeHints *xsh;
- xsh = XAllocSizeHints();
- xsh->flags = PMinSize | PMaxSize;
- xsh->min_width = OS::get_singleton()->get_video_mode().width;
- xsh->max_width = OS::get_singleton()->get_video_mode().width;
- xsh->min_height = OS::get_singleton()->get_video_mode().height;
- xsh->max_height = OS::get_singleton()->get_video_mode().height;
- XSetWMNormalHints(x11_display, x11_window, xsh);
- }
-
if (!opengl_3_context) {
//oldstyle context:
@@ -165,6 +155,9 @@ Error ContextGL_X11::initialize() {
*/
//glXMakeCurrent(x11_display, None, NULL);
+ XFree( vi );
+ XFree( fbc );
+
return OK;
}
@@ -175,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;
-
}
@@ -200,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 20a858bcdd..8b81db9160 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index cff7ea86b6..0f6e640b03 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -1,6 +1,7 @@
import os
import sys
+import platform
def is_active():
@@ -38,6 +39,11 @@ def can_build():
if (x11_error):
print("xcursor not found.. x11 disabled.")
return False
+
+ x11_error=os.system("pkg-config xinerama --modversion > /dev/null ")
+ if (x11_error):
+ print("xinerama not found.. x11 disabled.")
+ return False
return True # X11 enabled
@@ -47,106 +53,126 @@ def get_opts():
return [
('use_llvm','Use llvm compiler','no'),
('use_sanitizer','Use llvm compiler sanitize address','no'),
- ('force_32_bits','Force 32 bits binary','no')
+ ('use_leak_sanitizer','Use llvm compiler sanitize memory leaks','no'),
+ ('pulseaudio','Detect & Use pulseaudio','yes'),
+ ('new_wm_api', 'Use experimental window management API','no'),
+ ('debug_release', 'Add debug symbols to release version','no'),
]
def get_flags():
return [
- ('opengl', 'no'),
- ('legacygl', 'yes'),
('builtin_zlib', 'no'),
("openssl", "yes"),
+ #("theora","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/x11'])
if (env["use_llvm"]=="yes"):
- env["CC"]="clang"
- env["CXX"]="clang++"
- env["LD"]="clang++"
- if (env["use_sanitizer"]=="yes"):
- env.Append(CXXFLAGS=['-fsanitize=address','-fno-omit-frame-pointer'])
- env.Append(LINKFLAGS=['-fsanitize=address'])
+ if 'clang++' not in env['CXX']:
+ env["CC"]="clang"
+ env["CXX"]="clang++"
+ env["LD"]="clang++"
+ env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
+ env.extra_suffix=".llvm"
+ if (env["colored"]=="yes"):
+ if sys.stdout.isatty():
+ env.Append(CXXFLAGS=["-fcolor-diagnostics"])
+ if (env["use_sanitizer"]=="yes"):
+ env.Append(CXXFLAGS=['-fsanitize=address','-fno-omit-frame-pointer'])
+ env.Append(LINKFLAGS=['-fsanitize=address'])
+ env.extra_suffix+="s"
- if (env["tools"]=="no"):
- #no tools suffix
- env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+ if (env["use_leak_sanitizer"]=="yes"):
+ env.Append(CXXFLAGS=['-fsanitize=address','-fno-omit-frame-pointer'])
+ env.Append(LINKFLAGS=['-fsanitize=address'])
+ env.extra_suffix+="s"
+
+
+ #if (env["tools"]=="no"):
+ # #no tools suffix
+ # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
+ # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
if (env["target"]=="release"):
-
- env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer'])
- env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ 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'])
- env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
-
-
-# env.Append(CCFLAGS=['-Os','-ffast-math','-fomit-frame-pointer'])
-#does not seem to have much effect
-# env.Append(CCFLAGS=['-fno-default-inline'])
-#recommended by wxwidgets
-# env.Append(CCFLAGS=['-ffunction-sections','-fdata-sections'])
-# env.Append(LINKFLAGS=['-Wl','--gc-sections'])
+ if (env["debug_release"]=="yes"):
+ env.Append(CCFLAGS=['-g2'])
elif (env["target"]=="debug"):
-
+
env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
-#does not seem to have much effect
-# env.Append(CCFLAGS=['-fno-default-inline'])
-#recommended by wxwidgets
-# env.Append(CCFLAGS=['-ffunction-sections','-fdata-sections'])
-# env.Append(LINKFLAGS=['-Wl','--gc-sections'])
- elif (env["target"]=="debug_light"):
+ env.ParseConfig('pkg-config x11 --cflags --libs')
+ env.ParseConfig('pkg-config xinerama --cflags --libs')
+ env.ParseConfig('pkg-config xcursor --cflags --libs')
- env.Append(CCFLAGS=['-g1', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
+ if (env["openssl"]=="yes"):
+ env.ParseConfig('pkg-config openssl --cflags --libs')
- elif (env["target"]=="profile"):
-
- env.Append(CCFLAGS=['-g','-pg'])
- env.Append(LINKFLAGS=['-pg'])
+ if (env["freetype"]=="yes"):
+ env.ParseConfig('pkg-config freetype2 --cflags --libs')
- env.ParseConfig('pkg-config x11 --cflags --libs')
- env.ParseConfig('pkg-config xcursor --cflags --libs')
- env.ParseConfig('pkg-config openssl --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'])
- if env['opengl'] == 'yes':
- env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
- #env.Append(CPPFLAGS=["-DRTAUDIO_ENABLED"])
- env.Append(CPPFLAGS=["-DALSA_ENABLED"])
- env.Append(CPPFLAGS=['-DX11_ENABLED','-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLES1_ENABLED','-DGLES_OVER_GL'])
-# 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(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
+ if platform.system() == 'Linux':
+ env.Append(CPPFLAGS=["-DALSA_ENABLED"])
+ env.Append(LIBS=['asound'])
+
+ if (env["pulseaudio"]=="yes"):
+ if not os.system("pkg-config --exists libpulse-simple"):
+ print("Enabling PulseAudio")
+ env.Append(CPPFLAGS=["-DPULSEAUDIO_ENABLED"])
+ env.ParseConfig('pkg-config --cflags --libs libpulse-simple')
+ else:
+ 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', 'z'])
#env.Append(CPPFLAGS=['-DMPC_FIXED_POINT'])
- if (env["force_32_bits"]=="yes"):
+
+#host compiler is default..
+
+ if (is64 and env["bits"]=="32"):
env.Append(CPPFLAGS=['-m32'])
env.Append(LINKFLAGS=['-m32','-L/usr/lib/i386-linux-gnu'])
- env['OBJSUFFIX'] = ".32"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".32"+env['LIBSUFFIX']
-
+ elif (not is64 and env["bits"]=="64"):
+ env.Append(CPPFLAGS=['-m64'])
+ env.Append(LINKFLAGS=['-m64','-L/usr/lib/i686-linux-gnu'])
- if (env["CXX"]=="clang++"):
- env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
- env["CC"]="clang"
- env["LD"]="clang++"
import methods
@@ -155,3 +181,9 @@ 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') } )
+ if(env["new_wm_api"]=="yes"):
+ env.Append(CPPFLAGS=['-DNEW_WM_API'])
+ env.ParseConfig('pkg-config xinerama --cflags --libs')
+
+ env["x86_opt_gcc"]=True
+
diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp
index b17b92bccf..bed57fbe9f 100644
--- a/platform/x11/export/export.cpp
+++ b/platform/x11/export/export.cpp
@@ -11,7 +11,7 @@ void register_x11_exporter() {
{
Ref<EditorExportPlatformPC> exporter = Ref<EditorExportPlatformPC>( memnew(EditorExportPlatformPC) );
- exporter->set_binary_extension("bin");
+ exporter->set_binary_extension("");
exporter->set_release_binary32("linux_x11_32_release");
exporter->set_debug_binary32("linux_x11_32_debug");
exporter->set_release_binary64("linux_x11_64_release");
diff --git a/platform/x11/godot_x11.cpp b/platform/x11/godot_x11.cpp
index 3b50e8e515..f90d40fa5c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/x11/key_mapping_x11.cpp b/platform/x11/key_mapping_x11.cpp
index 2f109355b8..9c68ac1a2c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/x11/key_mapping_x11.h b/platform/x11/key_mapping_x11.h
index 97393d92f3..7ab883878f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index e7d9a4d691..4f1b475d06 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,15 +28,27 @@
/*************************************************************************/
#include "servers/visual/visual_server_raster.h"
#include "drivers/gles2/rasterizer_gles2.h"
-#include "drivers/gles1/rasterizer_gles1.h"
#include "os_x11.h"
#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"
+
+#include "X11/Xatom.h"
+#include "X11/extensions/Xinerama.h"
+// ICCCM
+#define WM_NormalState 1L // window normal state
+#define WM_IconicState 3L // window minimized
+// EWMH
+#define _NET_WM_STATE_REMOVE 0L // remove/unset property
+#define _NET_WM_STATE_ADD 1L // add/set property
+#define _NET_WM_STATE_TOGGLE 2L // toggle property
+
#include "main/main.h"
@@ -57,23 +69,33 @@
#include <X11/Xatom.h>
-#include "os/pc_joystick_map.h"
+//#include "os/pc_joystick_map.h"
#undef CursorShape
int OS_X11::get_video_driver_count() const {
-
- return 2;
+ return 1;
}
-const char * OS_X11::get_video_driver_name(int p_driver) const {
- return p_driver==0?"GLES2":"GLES1";
+const char * OS_X11::get_video_driver_name(int p_driver) const {
+ return "GLES2";
}
-OS::VideoMode OS_X11::get_default_video_mode() const {
+OS::VideoMode OS_X11::get_default_video_mode() const {
return OS::VideoMode(800,600,false);
}
+int OS_X11::get_audio_driver_count() const {
+ return AudioDriverManagerSW::get_driver_count();
+}
+
+const char *OS_X11::get_audio_driver_name(int p_driver) const {
+
+ AudioDriverSW* driver = AudioDriverManagerSW::get_driver(p_driver);
+ ERR_FAIL_COND_V( !driver, "" );
+ return AudioDriverManagerSW::get_driver(p_driver)->get_name();
+}
+
void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
last_button_state=0;
@@ -106,10 +128,10 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
if (xim == NULL) {
WARN_PRINT("XOpenIM failed");
- xim_style=NULL;
+ xim_style=0L;
} else {
::XIMStyles *xim_styles=NULL;
- xim_style=0;
+ xim_style=0L;
char *imvalret=NULL;
imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
if (imvalret != NULL || xim_styles == NULL) {
@@ -117,7 +139,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
}
if (xim_styles) {
- xim_style = 0;
+ xim_style = 0L;
for (int i=0;i<xim_styles->count_styles;i++) {
if (xim_styles->supported_styles[i] ==
@@ -130,6 +152,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
XFree (xim_styles);
}
+ XFree( imvalret );
}
/*
@@ -151,14 +174,11 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
// maybe contextgl wants to be in charge of creating the window
//print_line("def videomode "+itos(current_videomode.width)+","+itos(current_videomode.height));
#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+
context_gl = memnew( ContextGL_X11( x11_display, x11_window,current_videomode, false ) );
context_gl->initialize();
- if (p_video_driver == 0) {
- rasterizer = memnew( RasterizerGLES2 );
- } else {
- rasterizer = memnew( RasterizerGLES1 );
- };
+ rasterizer = memnew( RasterizerGLES2 );
#endif
visual_server = memnew( VisualServerRaster(rasterizer) );
@@ -168,11 +188,97 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD));
}
+#if 1
+ // NEW_WM_API
+ // borderless fullscreen window mode
+ if (current_videomode.fullscreen) {
+ // needed for lxde/openbox, possibly others
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = 0;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+ XMapRaised(x11_display, x11_window);
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display, DefaultRootWindow(x11_display), &xwa);
+ XMoveResizeWindow(x11_display, x11_window, 0, 0, xwa.width, xwa.height);
+
+ // code for netwm-compliants
+ XEvent xev;
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = 1;
+ xev.xclient.data.l[1] = fullscreen;
+ xev.xclient.data.l[2] = 0;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureNotifyMask, &xev);
+ }
+
+ // disable resizable window
+ if (!current_videomode.resizable) {
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+ xsh->flags = PMinSize | PMaxSize;
+ XWindowAttributes xwa;
+ if (current_videomode.fullscreen) {
+ XGetWindowAttributes(x11_display,DefaultRootWindow(x11_display),&xwa);
+ } else {
+ XGetWindowAttributes(x11_display,x11_window,&xwa);
+ }
+ xsh->min_width = xwa.width;
+ xsh->max_width = xwa.width;
+ xsh->min_height = xwa.height;
+ xsh->max_height = xwa.height;
+ XSetWMNormalHints(x11_display, x11_window, xsh);
+ XFree(xsh);
+ }
+#else
+ capture_idle = 0;
+ minimized = false;
+ maximized = false;
+
+ if (current_videomode.fullscreen) {
+ //set_wm_border(false);
+ set_wm_fullscreen(true);
+ }
+ if (!current_videomode.resizable) {
+ int screen = get_current_screen();
+ Size2i screen_size = get_screen_size(screen);
+ set_window_size(screen_size);
+ set_window_resizable(false);
+ }
+#endif
+
AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+ audio_driver_index=p_audio_driver;
if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
- ERR_PRINT("Initializing audio failed.");
+ bool success=false;
+ audio_driver_index=-1;
+ 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()));
+ print_line("Using alternate audio driver: "+String(AudioDriverManagerSW::get_driver(i)->get_name()));
+ audio_driver_index=i;
+ break;
+ }
+ }
+ if (!success) {
+ ERR_PRINT("Initializing audio failed.");
+ }
+
}
sample_manager = memnew( SampleManagerMallocSW );
@@ -204,19 +310,19 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
XChangeWindowAttributes(x11_display, x11_window,CWEventMask,&new_attr);
- XClassHint* classHint;
+ XClassHint* classHint;
- /* set the titlebar name */
- XStoreName(x11_display, x11_window, "Godot");
+ /* set the titlebar name */
+ XStoreName(x11_display, x11_window, "Godot");
- /* set the name and class hints for the window manager to use */
- classHint = XAllocClassHint();
- if (classHint) {
- classHint->res_name = "Godot";
- classHint->res_class = "Godot";
- }
- XSetClassHint(x11_display, x11_window, classHint);
- XFree(classHint);
+ /* set the name and class hints for the window manager to use */
+ classHint = XAllocClassHint();
+ if (classHint) {
+ classHint->res_name = (char *)"Godot";
+ classHint->res_class = (char *)"Godot";
+ }
+ XSetClassHint(x11_display, x11_window, classHint);
+ XFree(classHint);
wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true);
XSetWMProtocols(x11_display, x11_window, &wm_delete, 1);
@@ -244,6 +350,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;
@@ -272,16 +379,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]));
}
}
-
}
@@ -292,9 +398,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;
@@ -321,7 +427,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
//
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ //physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
input = memnew( InputDefault );
@@ -329,13 +436,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
probe_joystick();
_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)
@@ -351,9 +453,10 @@ void OS_X11::finalize() {
// memdelete(debugger_connection_console);
//}
+ memdelete(sample_manager);
+
audio_server->finish();
memdelete(audio_server);
- memdelete(sample_manager);
visual_server->finish();
memdelete(visual_server);
@@ -367,14 +470,26 @@ void OS_X11::finalize() {
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();
}
@@ -382,7 +497,6 @@ void OS_X11::finalize() {
void OS_X11::set_mouse_mode(MouseMode p_mode) {
- print_line("WUTF "+itos(p_mode)+" old "+itos(mouse_mode));
if (p_mode==mouse_mode)
return;
@@ -397,6 +511,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,
@@ -409,43 +540,404 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
center.y = current_videomode.height/2;
XWarpPointer(x11_display, None, x11_window,
0,0,0,0, (int)center.x, (int)center.y);
+
+ input->set_mouse_pos(center);
+ } else {
+ do_mouse_warp=false;
+ }
+}
+
+void OS_X11::warp_mouse_pos(const Point2& p_to) {
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+
+ last_mouse_pos=p_to;
+ } else {
+
+ /*XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display, x11_window, &xwa);
+ printf("%d %d\n", xwa.x, xwa.y); needed? */
+
+ XWarpPointer(x11_display, None, x11_window,
+ 0,0,0,0, (int)p_to.x , (int)p_to.y);
}
}
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 {
+}
+
+//#ifdef NEW_WM_API
+#if 0
+// Just now not needed. Can be used for a possible OS.set_border(bool) method
+void OS_X11::set_wm_border(bool p_enabled) {
+ // needed for lxde/openbox, possibly others
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = p_enabled ? 1L : 0L;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+ XMapRaised(x11_display, x11_window);
+ //XMoveResizeWindow(x11_display, x11_window, 0, 0, 800, 800);
+}
+#endif
+
+void OS_X11::set_wm_fullscreen(bool p_enabled) {
+ // Using EWMH -- Extened Window Manager Hints
+ XEvent xev;
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = wm_fullscreen;
+ xev.xclient.data.l[2] = 0;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+}
+
+int OS_X11::get_screen_count() const {
+ // Using Xinerama Extension
+ int event_base, error_base;
+ const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
+ if( !ext_okay ) return 0;
+
+ int count;
+ XineramaScreenInfo* xsi = XineramaQueryScreens(x11_display, &count);
+ XFree(xsi);
+ return count;
+}
+
+int OS_X11::get_current_screen() const {
+ int x,y;
+ Window child;
+ XTranslateCoordinates( x11_display, x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+
+ int count = get_screen_count();
+ for(int i=0; i<count; i++) {
+ Point2i pos = get_screen_position(i);
+ Size2i size = get_screen_size(i);
+ if( (x >= pos.x && x <pos.x + size.width) && (y >= pos.y && y < pos.y + size.height) )
+ return i;
+ }
+ return 0;
+}
+
+void OS_X11::set_current_screen(int p_screen) {
+ int count = get_screen_count();
+ if(p_screen >= count) return;
+
+ if( current_videomode.fullscreen ) {
+ Point2i position = get_screen_position(p_screen);
+ Size2i size = get_screen_size(p_screen);
+
+ XMoveResizeWindow(x11_display, x11_window, position.x, position.y, size.x, size.y);
+ }
+ else {
+ if( p_screen != get_current_screen() ) {
+ Point2i position = get_screen_position(p_screen);
+ XMoveWindow(x11_display, x11_window, position.x, position.y);
+ }
+ }
+}
+
+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);
+ }
+
+ int count;
+ XineramaScreenInfo* xsi = XineramaQueryScreens(x11_display, &count);
+ 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;
+}
+
+Size2 OS_X11::get_screen_size(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 Size2i(0,0);
+
+ int count;
+ XineramaScreenInfo* xsi = XineramaQueryScreens(x11_display, &count);
+ if( p_screen >= count ) return Size2i(0,0);
+
+ Size2i size = Point2i(xsi[p_screen].width, xsi[p_screen].height);
+ XFree(xsi);
+ return size;
+}
+
+Point2 OS_X11::get_window_position() const {
+ int x,y;
+ Window child;
+ XTranslateCoordinates( x11_display, x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+
+ int screen = get_current_screen();
+ Point2i screen_position = get_screen_position(screen);
+
+ return Point2i(x-screen_position.x, y-screen_position.y);
+}
+
+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;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = NULL;
+ int result;
+
+ result = XGetWindowProperty(
+ x11_display,
+ x11_window,
+ property,
+ 0,
+ 32,
+ False,
+ AnyPropertyType,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data
+ );
+
+ long left = 0L;
+ long top = 0L;
+
+ if( result == Success ) {
+ long *extends = (long *) data;
+
+ left = extends[0];
+ top = extends[2];
+
+ XFree(data);
+ }
+ int screen = get_current_screen();
+ Point2i screen_position = get_screen_position(screen);
+ left -= screen_position.x;
+ 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 {
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display, x11_window, &xwa);
+ return Size2i(xwa.width, xwa.height);
+}
+
+void OS_X11::set_window_size(const Size2 p_size) {
+ XResizeWindow(x11_display, x11_window, p_size.x, p_size.y);
+}
+
+void OS_X11::set_window_fullscreen(bool p_enabled) {
+ set_wm_fullscreen(p_enabled);
+ current_videomode.fullscreen = p_enabled;
+}
+
+bool OS_X11::is_window_fullscreen() const {
+ return current_videomode.fullscreen;
+}
+
+void OS_X11::set_window_resizable(bool p_enabled) {
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+ xsh->flags = p_enabled ? 0L : PMinSize | PMaxSize;
+ if(!p_enabled) {
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display,x11_window,&xwa);
+ xsh->min_width = xwa.width;
+ xsh->max_width = xwa.width;
+ xsh->min_height = xwa.height;
+ xsh->max_height = xwa.height;
+ }
+ XSetWMNormalHints(x11_display, x11_window, xsh);
+ XFree(xsh);
+ current_videomode.resizable = p_enabled;
+}
+
+bool OS_X11::is_window_resizable() const {
+ return current_videomode.resizable;
+}
+
+void OS_X11::set_window_minimized(bool p_enabled) {
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ XEvent xev;
+ Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = x11_window;
+ xev.xclient.message_type = wm_change;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ //XEvent xev;
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+ xev.xclient.data.l[1] = wm_hidden;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+}
+
+bool OS_X11::is_window_minimized() const {
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ Atom property = XInternAtom(x11_display,"WM_STATE", True);
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = NULL;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ x11_window,
+ property,
+ 0,
+ 32,
+ False,
+ AnyPropertyType,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data
+ );
+
+ if( result == Success ) {
+ long *state = (long *) data;
+ if( state[0] == WM_IconicState )
+ return true;
+ }
+ return false;
+}
+
+void OS_X11::set_window_maximized(bool p_enabled) {
+ // Using EWMH -- Extended Window Manager Hints
+ XEvent xev;
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = wm_max_horz;
+ 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;
+*/
+ maximized = p_enabled;
+}
+
+bool OS_X11::is_window_maximized() const {
+ // Using EWMH -- Extended Window Manager Hints
+ Atom property = XInternAtom(x11_display,"_NET_WM_STATE",False );
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = NULL;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ x11_window,
+ property,
+ 0,
+ 1024,
+ False,
+ XA_ATOM,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data
+ );
+
+ if(result == Success) {
+ Atom *atoms = (Atom*) data;
+ Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+ bool found_wm_max_horz = false;
+ bool found_wm_max_vert = false;
+
+ for( unsigned int i=0; i < len; i++ ) {
+ if( atoms[i] == wm_max_horz )
+ found_wm_max_horz = true;
+ if( atoms[i] == wm_max_vert )
+ found_wm_max_vert = true;
+
+ if( found_wm_max_horz && found_wm_max_vert )
+ return true;
+ }
+ XFree(atoms);
+ }
+
+ return false;
}
@@ -495,7 +987,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;
@@ -522,11 +1013,9 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
KeySym keysym_keycode=0; // keysym used to find a keycode
KeySym keysym_unicode=0; // keysym used to find unicode
- int nbytes=0; // bytes the string takes
-
// XLookupString returns keysyms usable as nice scancodes/
char str[256+1];
- nbytes=XLookupString(xkeyevent, str, 256, &keysym_keycode, NULL);
+ XLookupString(xkeyevent, str, 256, &keysym_keycode, NULL);
// Meanwhile, XLookupString returns keysyms useful for unicode.
@@ -623,7 +1112,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
::Time tresh=ABS(peek_event.xkey.time-xkeyevent->time);
if (peek_event.type == KeyPress && tresh<5 ) {
KeySym rk;
- nbytes=XLookupString((XKeyEvent*)&peek_event, str, 256, &rk, NULL);
+ XLookupString((XKeyEvent*)&peek_event, str, 256, &rk, NULL);
if (rk==keysym_keycode) {
XEvent event;
XNextEvent(x11_display, &event); //erase next event
@@ -663,15 +1152,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;
@@ -687,13 +1174,31 @@ void OS_X11::process_xevents() {
break;
case VisibilityNotify: {
-
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: {
+ 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);
+ }
+#endif
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
if (mouse_mode==MOUSE_MODE_CAPTURED) {
XGrabPointer(x11_display, x11_window, True,
@@ -704,6 +1209,12 @@ void OS_X11::process_xevents() {
break;
case FocusOut:
+#ifdef NEW_WM_API
+ if(current_videomode.fullscreen) {
+ set_wm_fullscreen(false);
+ set_window_minimized(true);
+ }
+#endif
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
if (mouse_mode==MOUSE_MODE_CAPTURED) {
//dear X11, I try, I really try, but you never work, you do whathever you want.
@@ -730,7 +1241,7 @@ void OS_X11::process_xevents() {
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;
@@ -765,26 +1276,55 @@ void OS_X11::process_xevents() {
last_click_ms+=diff;
last_click_pos = Point2(event.xbutton.x,event.xbutton.y);
}
- }
+ }
input->parse_input_event( mouse_event);
} 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.
// A little hack is in order
// to be able to send relative motion events.
-
Point2i pos( event.xmotion.x, event.xmotion.y );
if (mouse_mode==MOUSE_MODE_CAPTURED) {
#if 1
- Vector2 c = Point2i(current_videomode.width/2,current_videomode.height/2);
+ //Vector2 c = Point2i(current_videomode.width/2,current_videomode.height/2);
if (pos==Point2i(current_videomode.width/2,current_videomode.height/2)) {
//this sucks, it's a hack, etc and is a little inaccurate, etc.
//but nothing I can do, X11 sucks.
@@ -793,9 +1333,9 @@ void OS_X11::process_xevents() {
break;
}
- Point2i ncenter = pos;
- pos = last_mouse_pos + ( pos-center );
- center=ncenter;
+ Point2i new_center = pos;
+ pos = last_mouse_pos + ( pos - center );
+ center=new_center;
do_mouse_warp=true;
#else
//Dear X11, thanks for making my life miserable
@@ -808,9 +1348,7 @@ void OS_X11::process_xevents() {
XWarpPointer(x11_display, None, x11_window,
0,0,0,0, (int)center.x, (int)center.y);
#endif
-
}
-
if (!last_mouse_pos_valid) {
@@ -819,7 +1357,14 @@ void OS_X11::process_xevents() {
}
Point2i rel = pos - last_mouse_pos;
-
+
+#ifdef NEW_WM_API
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ pos.x = current_videomode.width / 2;
+ pos.y = current_videomode.height / 2;
+ }
+#endif
+
InputEvent motion_event;
motion_event.ID=++event_id;
motion_event.type=InputEvent::MOUSE_MOTION;
@@ -839,6 +1384,8 @@ void OS_X11::process_xevents() {
motion_event.mouse_motion.relative_y=rel.y;
last_mouse_pos=pos;
+
+ // printf("rel: %d,%d\n", rel.x, rel.y );
input->parse_input_event( motion_event);
@@ -913,8 +1460,18 @@ void OS_X11::process_xevents() {
if (do_mouse_warp) {
XWarpPointer(x11_display, None, x11_window,
- 0,0,0,0, (int)current_videomode.width/2, (int)current_videomode.height/2);
-
+ 0,0,0,0, (int)current_videomode.width/2, (int)current_videomode.height/2);
+
+ /*
+ Window root, child;
+ int root_x, root_y;
+ int win_x, win_y;
+ unsigned int mask;
+ XQueryPointer( x11_display, x11_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask );
+
+ printf("Root: %d,%d\n", root_x, root_y);
+ printf("Win: %d,%d\n", win_x, win_y);
+ */
}
}
@@ -1027,7 +1584,73 @@ String OS_X11::get_name() {
Error OS_X11::shell_open(String p_uri) {
- return ERR_UNAVAILABLE;
+ Error ok;
+ List<String> args;
+ args.push_back(p_uri);
+ ok = execute("/usr/bin/xdg-open",args,false);
+ if (ok==OK)
+ return OK;
+ ok = execute("gnome-open",args,false);
+ if (ok==OK)
+ return OK;
+ ok = execute("kde-open",args,false);
+ return ok;
+}
+
+String OS_X11::get_system_dir(SystemDir p_dir) const {
+
+
+ String xdgparam;
+
+ switch(p_dir) {
+ case SYSTEM_DIR_DESKTOP: {
+
+ xdgparam="DESKTOP";
+ } break;
+ case SYSTEM_DIR_DCIM: {
+
+ xdgparam="PICTURES";
+
+ } break;
+ case SYSTEM_DIR_DOCUMENTS: {
+
+ xdgparam="DOCUMENTS";
+
+ } break;
+ case SYSTEM_DIR_DOWNLOADS: {
+
+ xdgparam="DOWNLOAD";
+
+ } break;
+ case SYSTEM_DIR_MOVIES: {
+
+ xdgparam="VIDEOS";
+
+ } break;
+ case SYSTEM_DIR_MUSIC: {
+
+ xdgparam="MUSIC";
+
+ } break;
+ case SYSTEM_DIR_PICTURES: {
+
+ xdgparam="PICTURES";
+
+ } break;
+ case SYSTEM_DIR_RINGTONES: {
+
+ xdgparam="MUSIC";
+
+ } break;
+ }
+
+ String pipe;
+ List<String> arg;
+ arg.push_back(xdgparam);
+ Error err = const_cast<OS_X11*>(this)->execute("/usr/bin/xdg-user-dir",arg,true,NULL,&pipe);
+ if (err!=OK)
+ return ".";
+ return pipe.strip_edges();
}
@@ -1046,10 +1669,12 @@ void OS_X11::close_joystick(int p_id) {
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 !defined(__FreeBSD__) && !defined(__OpenBSD__)
+
if (p_id == -1) {
for (int i=0; i<JOYSTICKS_MAX; i++) {
@@ -1059,7 +1684,8 @@ void OS_X11::probe_joystick(int p_id) {
return;
};
- close_joystick(p_id);
+ if (joysticks[p_id].fd != -1)
+ close_joystick(p_id);
const char *joy_names[] = {
"/dev/input/js%d",
@@ -1072,12 +1698,22 @@ void OS_X11::probe_joystick(int p_id) {
char fname[64];
sprintf(fname, joy_names[i], p_id);
- int fd = open(fname, O_RDONLY);
+ int fd = open(fname, O_RDONLY|O_NONBLOCK);
if (fd != -1) {
- fcntl( fd, F_SETFL, O_NONBLOCK );
+ //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
};
@@ -1092,14 +1728,17 @@ void OS_X11::move_window_to_foreground() {
}
void OS_X11::process_joysticks() {
- #ifndef __FreeBSD__
+ #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
int bytes;
js_event events[32];
InputEvent ievent;
for (int i=0; i<JOYSTICKS_MAX; i++) {
- if (joysticks[i].fd == -1)
- continue;
+ 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) {
@@ -1117,8 +1756,9 @@ void OS_X11::process_joysticks() {
case JS_EVENT_AXIS:
- if (joysticks[i].last_axis[event.number] != event.value) {
+ //if (joysticks[i].last_axis[event.number] != event.value) {
+ /*
if (event.number==5 || event.number==6) {
int axis=event.number-5;
@@ -1165,17 +1805,19 @@ void OS_X11::process_joysticks() {
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;
+ //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 = _pc_joystick_get_native_axis(event.number);
+ 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;
- joysticks[i].last_axis[event.number] = event.value;
+ if (event.number < JOY_AXIS_MAX)
+ joysticks[i].last_axis[event.number] = event.value;
input->parse_input_event( ievent );
- };
+ //};
break;
case JS_EVENT_BUTTON:
@@ -1183,17 +1825,21 @@ void OS_X11::process_joysticks() {
ievent.type = InputEvent::JOYSTICK_BUTTON;
ievent.ID = ++event_id;
- ievent.joy_button.button_index = _pc_joystick_get_native_button(event.number);
+ 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);
@@ -1207,7 +1853,6 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) {
XDefineCursor(x11_display,x11_window,cursors[CURSOR_ARROW]);
}
-
current_cursor=p_shape;
}
@@ -1228,8 +1873,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);
@@ -1262,7 +1919,6 @@ void OS_X11::set_icon(const Image& p_icon) {
XDeleteProperty(x11_display, x11_window, net_wm_icon);
}
XFlush(x11_display);
-
}
@@ -1297,13 +1953,15 @@ OS_X11::OS_X11() {
AudioDriverManagerSW::add_driver(&driver_rtaudio);
#endif
+#ifdef PULSEAUDIO_ENABLED
+ AudioDriverManagerSW::add_driver(&driver_pulseaudio);
+#endif
+
#ifdef ALSA_ENABLED
AudioDriverManagerSW::add_driver(&driver_alsa);
#endif
minimized = false;
- xim_style=NULL;
+ xim_style=0L;
mouse_mode=MOUSE_MODE_VISIBLE;
-
-
};
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 77ef37f6f4..ed61df8f0e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -43,13 +43,24 @@
#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/alsa/audio_driver_alsa.h"
+#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 <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xcursor/Xcursor.h>
-//bitch
+// Hints for X11 fullscreen
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+} Hints;
+
#undef CursorShape
/**
@author Juan Linietsky <reduzio@gmail.com>
@@ -104,9 +115,11 @@ class OS_X11 : public OS_Unix {
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;
@@ -121,6 +134,10 @@ class OS_X11 : public OS_Unix {
AudioDriverALSA driver_alsa;
#endif
+#ifdef PULSEAUDIO_ENABLED
+ AudioDriverPulseAudio driver_pulseaudio;
+#endif
+
enum {
JOYSTICKS_MAX = 8,
MAX_JOY_AXIS = 32768, // I've no idea
@@ -139,20 +156,25 @@ class OS_X11 : public OS_Unix {
};
};
};
-
- Atom net_wm_icon;
-
-
int joystick_count;
Joystick joysticks[JOYSTICKS_MAX];
+ int audio_driver_index;
+ unsigned int capture_idle;
+ bool maximized;
+ //void set_wm_border(bool p_enabled);
+ void set_wm_fullscreen(bool p_enabled);
+
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 int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
virtual void finalize();
@@ -162,6 +184,7 @@ protected:
void process_joysticks();
void close_joystick(int p_id = -1);
+
public:
virtual String get_name();
@@ -171,6 +194,7 @@ public:
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
+ virtual void warp_mouse_pos(const Point2& p_to);
virtual Point2 get_mouse_pos() const;
virtual int get_mouse_button_state() const;
virtual void set_window_title(const String& p_title);
@@ -188,14 +212,35 @@ public:
virtual void make_rendering_thread();
virtual void swap_buffers();
+ virtual String get_system_dir(SystemDir p_dir) const;
+
virtual Error shell_open(String p_uri);
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 move_window_to_foreground();
+ 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 Point2 get_window_position() const;
+ virtual void set_window_position(const Point2& p_position);
+ virtual Size2 get_window_size() const;
+ virtual void set_window_size(const Size2 p_size);
+ 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 move_window_to_foreground();
+ virtual void alert(const String& p_alert,const String& p_title="ALERT!");
void run();
OS_X11();
diff --git a/platform/x11/platform_config.h b/platform/x11/platform_config.h
index 21703969cc..1556b56058 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,10 +29,10 @@
#ifdef __linux__
#include <alloca.h>
#endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <stdlib.h>
#endif
#define GLES2_INCLUDE_H "gl_context/glew.h"
-#define GLES1_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 316dffb3f9..458246671c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,6 +27,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "animated_sprite.h"
+#include "scene/scene_string_names.h"
+#include "os/os.h"
void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) {
@@ -149,18 +151,22 @@ void AnimatedSprite::_notification(int p_what) {
Size2i s;
s = texture->get_size();
- Point2i ofs=offset;
+ Point2 ofs=offset;
if (centered)
ofs-=s/2;
- Rect2i dst_rect(ofs,s);
+ if (OS::get_singleton()->get_use_pixel_snap()) {
+ ofs=ofs.floor();
+ }
+ Rect2 dst_rect(ofs,s);
if (hflip)
dst_rect.size.x=-dst_rect.size.x;
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;
@@ -207,7 +213,7 @@ void AnimatedSprite::set_frame(int p_frame) {
frame=p_frame;
update();
_change_notify("frame");
-
+ emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
int AnimatedSprite::get_frame() const {
@@ -233,6 +239,7 @@ void AnimatedSprite::set_offset(const Point2& p_offset) {
offset=p_offset;
update();
item_rect_changed();
+ _change_notify("offset");
}
Point2 AnimatedSprite::get_offset() const {
@@ -283,7 +290,7 @@ Rect2 AnimatedSprite::get_item_rect() const {
return Node2D::get_item_rect();
Size2i s = t->get_size();
- Point2i ofs=offset;
+ Point2 ofs=offset;
if (centered)
ofs-=s/2;
@@ -325,13 +332,15 @@ void AnimatedSprite::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_res_changed"),&AnimatedSprite::_res_changed);
+ ADD_SIGNAL(MethodInfo("frame_changed"));
+
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"), _SCS("set_frame"),_SCS("get_frame"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
+ 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 78d738240f..425f516b14 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index ad228662e4..c44b46adbf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -52,6 +52,17 @@ bool Area2D::is_gravity_a_point() const{
return gravity_is_point;
}
+void Area2D::set_gravity_distance_scale(real_t p_scale){
+
+ gravity_distance_scale=p_scale;
+ Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE,p_scale);
+
+}
+
+real_t Area2D::get_gravity_distance_scale() const{
+ return gravity_distance_scale;
+}
+
void Area2D::set_gravity_vector(const Vector2& p_vec){
gravity_vec=p_vec;
@@ -73,14 +84,25 @@ real_t Area2D::get_gravity() const{
return gravity;
}
-void Area2D::set_density(real_t p_density){
+void Area2D::set_linear_damp(real_t p_linear_damp){
- density=p_density;
- Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_DENSITY,p_density);
+ linear_damp=p_linear_damp;
+ Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_LINEAR_DAMP,p_linear_damp);
}
-real_t Area2D::get_density() const{
+real_t Area2D::get_linear_damp() const{
+
+ return linear_damp;
+}
+
+void Area2D::set_angular_damp(real_t p_angular_damp){
+
+ angular_damp=p_angular_damp;
+ Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_ANGULAR_DAMP,p_angular_damp);
+}
+
+real_t Area2D::get_angular_damp() const{
- return density;
+ return angular_damp;
}
void Area2D::set_priority(real_t p_priority){
@@ -94,7 +116,7 @@ real_t Area2D::get_priority() const{
}
-void Area2D::_body_enter_scene(ObjectID p_id) {
+void Area2D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = obj ? obj->cast_to<Node>() : NULL;
@@ -102,9 +124,9 @@ void Area2D::_body_enter_scene(ObjectID p_id) {
Map<ObjectID,BodyState>::Element *E=body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_scene);
+ ERR_FAIL_COND(E->get().in_tree);
- E->get().in_scene=true;
+ E->get().in_tree=true;
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
for(int i=0;i<E->get().shapes.size();i++) {
@@ -113,15 +135,15 @@ void Area2D::_body_enter_scene(ObjectID p_id) {
}
-void Area2D::_body_exit_scene(ObjectID p_id) {
+void Area2D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = obj ? obj->cast_to<Node>() : NULL;
ERR_FAIL_COND(!node);
Map<ObjectID,BodyState>::Element *E=body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_scene);
- E->get().in_scene=false;
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree=false;
emit_signal(SceneStringNames::get_singleton()->body_exit,node);
for(int i=0;i<E->get().shapes.size();i++) {
@@ -142,16 +164,18 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b
ERR_FAIL_COND(!body_in && !E);
+ locked=true;
+
if (body_in) {
if (!E) {
E = body_map.insert(objid,BodyState());
E->get().rc=0;
- E->get().in_scene=node && node->is_inside_scene();
+ E->get().in_tree=node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid));
- if (E->get().in_scene) {
+ node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree,make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree,make_binds(objid));
+ if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
}
}
@@ -162,7 +186,7 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b
E->get().shapes.insert(ShapePair(p_body_shape,p_area_shape));
- if (E->get().in_scene) {
+ if (!node || E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_area_shape);
}
@@ -178,9 +202,9 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b
if (E->get().rc==0) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene);
- node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene);
- if (E->get().in_scene)
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
+ if (E->get().in_tree)
emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
}
@@ -188,7 +212,7 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b
eraseit=true;
}
- if (node && E->get().in_scene) {
+ if (!node || E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_area_shape);
}
@@ -197,33 +221,182 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b
}
+ locked=false;
+
+
+}
+
+
+
+void Area2D::_area_enter_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_FAIL_COND(!node);
+
+ Map<ObjectID,AreaState>::Element *E=area_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(E->get().in_tree);
+
+ E->get().in_tree=true;
+ emit_signal(SceneStringNames::get_singleton()->area_enter,node);
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_enter_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+ }
+
+}
+
+void Area2D::_area_exit_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_FAIL_COND(!node);
+ Map<ObjectID,AreaState>::Element *E=area_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree=false;
+ emit_signal(SceneStringNames::get_singleton()->area_exit,node);
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+ }
+
+}
+
+void Area2D::_area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape) {
+
+ bool area_in = p_status==Physics2DServer::AREA_BODY_ADDED;
+ ObjectID objid=p_instance;
+
+ Object *obj = ObjectDB::get_instance(objid);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+
+ Map<ObjectID,AreaState>::Element *E=area_map.find(objid);
+
+ ERR_FAIL_COND(!area_in && !E);
+
+ locked=true;
+
+ if (area_in) {
+ if (!E) {
+
+ E = area_map.insert(objid,AreaState());
+ E->get().rc=0;
+ E->get().in_tree=node && node->is_inside_tree();
+ if (node) {
+ node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree,make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree,make_binds(objid));
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_enter,node);
+ }
+ }
+
+ }
+ E->get().rc++;
+ if (node)
+ E->get().shapes.insert(AreaShapePair(p_area_shape,p_self_shape));
+
+
+ if (!node || E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_enter_shape,objid,node,p_area_shape,p_self_shape);
+ }
+
+ } else {
+
+ E->get().rc--;
+
+ if (node)
+ E->get().shapes.erase(AreaShapePair(p_area_shape,p_self_shape));
+
+ bool eraseit=false;
+
+ if (E->get().rc==0) {
+
+ if (node) {
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree);
+ if (E->get().in_tree)
+ emit_signal(SceneStringNames::get_singleton()->area_exit,obj);
+
+ }
+
+ eraseit=true;
+
+ }
+ if (!node || E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,objid,obj,p_area_shape,p_self_shape);
+ }
+
+ if (eraseit)
+ area_map.erase(E);
+
+ }
+
+ locked=false;
+
+
}
+
void Area2D::_clear_monitoring() {
+ if (locked) {
+ ERR_EXPLAIN("This function can't be used during the in/out signal.");
+ }
+ ERR_FAIL_COND(locked);
- Map<ObjectID,BodyState> bmcopy = body_map;
- body_map.clear();
- //disconnect all monitored stuff
+ {
+ Map<ObjectID,BodyState> bmcopy = body_map;
+ body_map.clear();
+ //disconnect all monitored stuff
- for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) {
+ for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
- Node *node = obj ? obj->cast_to<Node>() : NULL;
- ERR_CONTINUE(!node);
- if (!E->get().in_scene)
- continue;
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_CONTINUE(!node);
+ if (!E->get().in_tree)
+ continue;
- for(int i=0;i<E->get().shapes.size();i++) {
+ for(int i=0;i<E->get().shapes.size();i++) {
- emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
+
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
}
- emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
+ }
+
+ {
+
+ Map<ObjectID,AreaState> bmcopy = area_map;
+ area_map.clear();
+ //disconnect all monitored stuff
+
+ for (Map<ObjectID,AreaState>::Element *E=bmcopy.front();E;E=E->next()) {
+
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_CONTINUE(!node);
+ if (!E->get().in_tree)
+ continue;
+
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,E->key(),node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit,obj);
- node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene);
- node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene);
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree);
+ }
}
}
@@ -232,7 +405,7 @@ void Area2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
_clear_monitoring();
} break;
@@ -243,6 +416,11 @@ 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;
@@ -250,9 +428,12 @@ void Area2D::set_enable_monitoring(bool p_enable) {
if (monitoring) {
- Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_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());
_clear_monitoring();
}
@@ -263,11 +444,150 @@ bool Area2D::is_monitoring_enabled() const {
return monitoring;
}
+void Area2D::set_monitorable(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==monitorable)
+ return;
+
+ monitorable=p_enable;
+
+ Physics2DServer::get_singleton()->area_set_monitorable(get_rid(),monitorable);
+}
+
+bool Area2D::is_monitorable() const {
+
+ return monitorable;
+}
+
+Array Area2D::get_overlapping_bodies() const {
+
+ ERR_FAIL_COND_V(!monitoring,Array());
+ Array ret;
+ ret.resize(body_map.size());
+ int idx=0;
+ for (const Map<ObjectID,BodyState>::Element *E=body_map.front();E;E=E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize( ret.size() -1 ); //ops
+ } else {
+ ret[idx++]=obj;
+ }
+
+ }
+
+ return ret;
+}
+
+Array Area2D::get_overlapping_areas() const {
+
+ ERR_FAIL_COND_V(!monitoring,Array());
+ Array ret;
+ ret.resize(area_map.size());
+ int idx=0;
+ for (const Map<ObjectID,AreaState>::Element *E=area_map.front();E;E=E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize( ret.size() -1 ); //ops
+ } else {
+ ret[idx++]=obj;
+ }
+
+ }
+
+ return ret;
+}
+
+bool Area2D::overlaps_area(Node* p_area) const {
+
+ ERR_FAIL_NULL_V(p_area,false);
+ const Map<ObjectID,AreaState>::Element *E=area_map.find(p_area->get_instance_ID());
+ if (!E)
+ return false;
+ return E->get().in_tree;
+
+
+
+}
+
+bool Area2D::overlaps_body(Node* p_body) const{
+
+ ERR_FAIL_NULL_V(p_body,false);
+ const Map<ObjectID,BodyState>::Element *E=body_map.find(p_body->get_instance_ID());
+ if (!E)
+ return false;
+ return E->get().in_tree;
+
+}
+
+void Area2D::set_collision_mask(uint32_t p_mask) {
+
+ collision_mask=p_mask;
+ Physics2DServer::get_singleton()->area_set_collision_mask(get_rid(),p_mask);
+}
+
+uint32_t Area2D::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+
+void Area2D::set_layer_mask(uint32_t p_mask) {
+
+ layer_mask=p_mask;
+ Physics2DServer::get_singleton()->area_set_layer_mask(get_rid(),p_mask);
+}
+
+uint32_t Area2D::get_layer_mask() const {
+
+ return layer_mask;
+}
+
+void Area2D::set_collision_mask_bit(int p_bit, bool p_value) {
+
+ uint32_t mask = get_collision_mask();
+ if (p_value)
+ mask|=1<<p_bit;
+ else
+ mask&=~(1<<p_bit);
+ set_collision_mask(mask);
+
+}
+
+bool Area2D::get_collision_mask_bit(int p_bit) const{
+
+ return get_collision_mask()&(1<<p_bit);
+}
+
+
+void Area2D::set_layer_mask_bit(int p_bit, bool p_value) {
+
+ uint32_t mask = get_layer_mask();
+ if (p_value)
+ mask|=1<<p_bit;
+ else
+ mask&=~(1<<p_bit);
+ set_layer_mask(mask);
+
+}
+
+bool Area2D::get_layer_mask_bit(int p_bit) const{
+
+ return get_layer_mask()&(1<<p_bit);
+}
+
void Area2D::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("_body_enter_scene","id"),&Area2D::_body_enter_scene);
- ObjectTypeDB::bind_method(_MD("_body_exit_scene","id"),&Area2D::_body_exit_scene);
+ ObjectTypeDB::bind_method(_MD("_body_enter_tree","id"),&Area2D::_body_enter_tree);
+ ObjectTypeDB::bind_method(_MD("_body_exit_tree","id"),&Area2D::_body_exit_tree);
+
+ ObjectTypeDB::bind_method(_MD("_area_enter_tree","id"),&Area2D::_area_enter_tree);
+ ObjectTypeDB::bind_method(_MD("_area_exit_tree","id"),&Area2D::_area_exit_tree);
ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area2D::set_space_override_mode);
ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area2D::get_space_override_mode);
@@ -275,36 +595,75 @@ void Area2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_gravity_is_point","enable"),&Area2D::set_gravity_is_point);
ObjectTypeDB::bind_method(_MD("is_gravity_a_point"),&Area2D::is_gravity_a_point);
+ ObjectTypeDB::bind_method(_MD("set_gravity_distance_scale","distance_scale"),&Area2D::set_gravity_distance_scale);
+ ObjectTypeDB::bind_method(_MD("get_gravity_distance_scale"),&Area2D::get_gravity_distance_scale);
+
ObjectTypeDB::bind_method(_MD("set_gravity_vector","vector"),&Area2D::set_gravity_vector);
ObjectTypeDB::bind_method(_MD("get_gravity_vector"),&Area2D::get_gravity_vector);
ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area2D::set_gravity);
ObjectTypeDB::bind_method(_MD("get_gravity"),&Area2D::get_gravity);
- ObjectTypeDB::bind_method(_MD("set_density","density"),&Area2D::set_density);
- ObjectTypeDB::bind_method(_MD("get_density"),&Area2D::get_density);
+ ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&Area2D::set_linear_damp);
+ ObjectTypeDB::bind_method(_MD("get_linear_damp"),&Area2D::get_linear_damp);
+
+ ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&Area2D::set_angular_damp);
+ ObjectTypeDB::bind_method(_MD("get_angular_damp"),&Area2D::get_angular_damp);
ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area2D::set_priority);
ObjectTypeDB::bind_method(_MD("get_priority"),&Area2D::get_priority);
+ ObjectTypeDB::bind_method(_MD("set_collision_mask","collision_mask"),&Area2D::set_collision_mask);
+ ObjectTypeDB::bind_method(_MD("get_collision_mask"),&Area2D::get_collision_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_layer_mask","layer_mask"),&Area2D::set_layer_mask);
+ ObjectTypeDB::bind_method(_MD("get_layer_mask"),&Area2D::get_layer_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_collision_mask_bit","bit","value"),&Area2D::set_collision_mask_bit);
+ ObjectTypeDB::bind_method(_MD("get_collision_mask_bit","bit"),&Area2D::get_collision_mask_bit);
+
+ ObjectTypeDB::bind_method(_MD("set_layer_mask_bit","bit","value"),&Area2D::set_layer_mask_bit);
+ ObjectTypeDB::bind_method(_MD("get_layer_mask_bit","bit"),&Area2D::get_layer_mask_bit);
+
ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area2D::set_enable_monitoring);
ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area2D::is_monitoring_enabled);
+ ObjectTypeDB::bind_method(_MD("set_monitorable","enable"),&Area2D::set_monitorable);
+ ObjectTypeDB::bind_method(_MD("is_monitorable"),&Area2D::is_monitorable);
+
+ ObjectTypeDB::bind_method(_MD("get_overlapping_bodies"),&Area2D::get_overlapping_bodies);
+ ObjectTypeDB::bind_method(_MD("get_overlapping_areas"),&Area2D::get_overlapping_areas);
+
+ ObjectTypeDB::bind_method(_MD("overlaps_body:PhysicsBody2D","body"),&Area2D::overlaps_body);
+ ObjectTypeDB::bind_method(_MD("overlaps_area:Area2D","area"),&Area2D::overlaps_area);
+
ObjectTypeDB::bind_method(_MD("_body_inout"),&Area2D::_body_inout);
+ ObjectTypeDB::bind_method(_MD("_area_inout"),&Area2D::_area_inout);
+
+ ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body",PROPERTY_HINT_RESOURCE_TYPE,"PhysicsBody2D"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body",PROPERTY_HINT_RESOURCE_TYPE,"PhysicsBody2D"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body",PROPERTY_HINT_RESOURCE_TYPE,"PhysicsBody2D")));
+ ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body",PROPERTY_HINT_RESOURCE_TYPE,"PhysicsBody2D")));
+
+ ADD_SIGNAL( MethodInfo("area_enter_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("area_exit_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("area_enter",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D")));
+ ADD_SIGNAL( MethodInfo("area_exit",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D")));
- ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
- ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
- ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body")));
- ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body")));
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_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,"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_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_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"));
}
@@ -314,11 +673,17 @@ Area2D::Area2D() : CollisionObject2D(Physics2DServer::get_singleton()->area_crea
set_gravity(98);;
set_gravity_vector(Vector2(0,1));
gravity_is_point=false;
- density=0.1;
+ gravity_distance_scale=0;
+ linear_damp=0.1;
+ angular_damp=1;
+ locked=false;
priority=0;
monitoring=false;
+ monitorable=false;
+ collision_mask=1;
+ layer_mask=1;
set_enable_monitoring(true);
-
+ set_monitorable(true);
}
Area2D::~Area2D() {
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index b4c8edf138..f5a88390e7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,14 +49,20 @@ private:
Vector2 gravity_vec;
real_t gravity;
bool gravity_is_point;
- real_t density;
+ real_t gravity_distance_scale;
+ real_t linear_damp;
+ real_t angular_damp;
+ uint32_t collision_mask;
+ uint32_t layer_mask;
int priority;
bool monitoring;
+ bool monitorable;
+ bool locked;
void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape);
- void _body_enter_scene(ObjectID p_id);
- void _body_exit_scene(ObjectID p_id);
+ void _body_enter_tree(ObjectID p_id);
+ void _body_exit_tree(ObjectID p_id);
struct ShapePair {
@@ -76,12 +82,42 @@ private:
struct BodyState {
int rc;
- bool in_scene;
+ bool in_tree;
VSet<ShapePair> shapes;
};
Map<ObjectID,BodyState> body_map;
+
+
+ void _area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape);
+
+ void _area_enter_tree(ObjectID p_id);
+ void _area_exit_tree(ObjectID p_id);
+
+ struct AreaShapePair {
+
+ int area_shape;
+ int self_shape;
+ bool operator<(const AreaShapePair& p_sp) const {
+ if (area_shape==p_sp.area_shape)
+ return self_shape < p_sp.self_shape;
+ else
+ return area_shape < p_sp.area_shape;
+ }
+
+ AreaShapePair() {}
+ AreaShapePair(int p_bs, int p_as) { area_shape=p_bs; self_shape=p_as; }
+ };
+
+ struct AreaState {
+
+ int rc;
+ bool in_tree;
+ VSet<AreaShapePair> shapes;
+ };
+
+ Map<ObjectID,AreaState> area_map;
void _clear_monitoring();
@@ -97,14 +133,20 @@ public:
void set_gravity_is_point(bool p_enabled);
bool is_gravity_a_point() const;
+ void set_gravity_distance_scale(real_t p_scale);
+ real_t get_gravity_distance_scale() const;
+
void set_gravity_vector(const Vector2& p_vec);
Vector2 get_gravity_vector() const;
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_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_priority(real_t p_priority);
real_t get_priority() const;
@@ -112,6 +154,26 @@ public:
void set_enable_monitoring(bool p_enable);
bool is_monitoring_enabled() const;
+ void set_monitorable(bool p_enable);
+ bool is_monitorable() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_layer_mask(uint32_t p_mask);
+ uint32_t get_layer_mask() const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
+ void set_layer_mask_bit(int p_bit, bool p_value);
+ bool get_layer_mask_bit(int p_bit) const;
+
+ Array get_overlapping_bodies() const; //function for script
+ Array get_overlapping_areas() const; //function for script
+
+ bool overlaps_area(Node* p_area) const;
+ bool overlaps_body(Node* p_body) const;
Area2D();
~Area2D();
diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp
new file mode 100644
index 0000000000..7a138830db
--- /dev/null
+++ b/scene/2d/back_buffer_copy.cpp
@@ -0,0 +1,75 @@
+#include "back_buffer_copy.h"
+
+void BackBufferCopy::_update_copy_mode() {
+
+ switch(copy_mode) {
+
+ case COPY_MODE_DISABLED: {
+
+ VS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(),false,Rect2());
+ } break;
+ case COPY_MODE_RECT: {
+
+ VS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(),true,rect);
+ } break;
+ case COPY_MODE_VIEWPORT: {
+
+ VS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(),true,Rect2());
+
+ } break;
+
+ }
+}
+
+Rect2 BackBufferCopy::get_item_rect() const {
+
+ return rect;
+}
+
+void BackBufferCopy::set_rect(const Rect2& p_rect) {
+
+ rect=p_rect;
+ _update_copy_mode();
+}
+
+Rect2 BackBufferCopy::get_rect() const{
+ return rect;
+}
+
+void BackBufferCopy::set_copy_mode(CopyMode p_mode){
+
+ copy_mode=p_mode;
+ _update_copy_mode();
+}
+BackBufferCopy::CopyMode BackBufferCopy::get_copy_mode() const{
+
+ return copy_mode;
+}
+
+
+void BackBufferCopy::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_rect","rect"),&BackBufferCopy::set_rect);
+ ObjectTypeDB::bind_method(_MD("get_rect"),&BackBufferCopy::get_rect);
+
+ ObjectTypeDB::bind_method(_MD("set_copy_mode","copy_mode"),&BackBufferCopy::set_copy_mode);
+ ObjectTypeDB::bind_method(_MD("get_copy_mode"),&BackBufferCopy::get_copy_mode);
+
+ 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_DISABLED );
+ BIND_CONSTANT( COPY_MODE_RECT );
+ BIND_CONSTANT( COPY_MODE_VIEWPORT );
+
+}
+
+BackBufferCopy::BackBufferCopy(){
+
+ rect=Rect2(-100,-100,200,200);
+ copy_mode=COPY_MODE_RECT;
+ _update_copy_mode();
+}
+BackBufferCopy::~BackBufferCopy(){
+
+}
diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h
new file mode 100644
index 0000000000..734cad458a
--- /dev/null
+++ b/scene/2d/back_buffer_copy.h
@@ -0,0 +1,41 @@
+#ifndef BACKBUFFERCOPY_H
+#define BACKBUFFERCOPY_H
+
+#include "scene/2d/node_2d.h"
+
+class BackBufferCopy : public Node2D {
+ OBJ_TYPE( BackBufferCopy,Node2D);
+public:
+ enum CopyMode {
+ COPY_MODE_DISABLED,
+ COPY_MODE_RECT,
+ COPY_MODE_VIEWPORT
+ };
+private:
+
+ Rect2 rect;
+ CopyMode copy_mode;
+
+ void _update_copy_mode();
+
+protected:
+
+ static void _bind_methods();
+
+public:
+
+ void set_rect(const Rect2& p_rect);
+ Rect2 get_rect() const;
+
+ void set_copy_mode(CopyMode p_mode);
+ CopyMode get_copy_mode() const;
+
+ Rect2 get_item_rect() const;
+
+ BackBufferCopy();
+ ~BackBufferCopy();
+};
+
+VARIANT_ENUM_CAST(BackBufferCopy::CopyMode);
+
+#endif // BACKBUFFERCOPY_H
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index fe6c9637e0..52ae5d2954 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,11 +33,12 @@
void Camera2D::_update_scroll() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
- if (get_scene()->is_editor_hint()) {
- update(); //will just be drawn
+ if (get_tree()->is_editor_hint()) {
+ // update(); //will just be drawn
+ //??
return;
}
@@ -48,7 +49,7 @@ void Camera2D::_update_scroll() {
if (viewport) {
viewport->set_canvas_transform( xform );
}
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,group_name,"_camera_moved",xform);
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,group_name,"_camera_moved",xform);
};
}
@@ -56,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 {
@@ -67,7 +70,7 @@ Vector2 Camera2D::get_zoom() const {
Matrix32 Camera2D::get_camera_transform() {
- if (!get_scene())
+ if (!get_tree())
return Matrix32();
Size2 screen_size = get_viewport_rect().size;
@@ -80,43 +83,47 @@ Matrix32 Camera2D::get_camera_transform() {
if (!first) {
- if (centered) {
+ if (anchor_mode==ANCHOR_MODE_DRAG_CENTER) {
- if (h_drag_enabled) {
- camera_pos.x = MIN( camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT]));
- camera_pos.x = MAX( camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT]));
- } else {
+ if (h_drag_enabled) {
+ camera_pos.x = MIN( camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT]));
+ camera_pos.x = MAX( camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT]));
+ } else {
- if (h_ofs<0) {
- camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs;
- } else {
- camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs;
- }
- }
+ if (h_ofs<0) {
+ camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs;
+ } else {
+ camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs;
+ }
+ }
- if (v_drag_enabled) {
+ if (v_drag_enabled) {
- camera_pos.y = MIN( camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM]));
- camera_pos.y = MAX( camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP]));
+ camera_pos.y = MIN( camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM]));
+ camera_pos.y = MAX( camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP]));
- } else {
+ } else {
- if (v_ofs<0) {
- camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs;
- } else {
- camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs;
- }
- }
+ if (v_ofs<0) {
+ camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs;
+ } else {
+ camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs;
+ }
+ }
+ } else if (anchor_mode==ANCHOR_MODE_FIXED_TOP_LEFT){
+
+ camera_pos=new_camera_pos;
}
+
if (smoothing>0.0) {
float c = smoothing*get_fixed_process_delta_time();
smoothed_camera_pos = ((new_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;
+ // camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
} else {
ret_camera_pos=smoothed_camera_pos=camera_pos;
@@ -131,8 +138,7 @@ Matrix32 Camera2D::get_camera_transform() {
}
- Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2());;
- screen_offset;
+ Point2 screen_offset = (anchor_mode==ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2());
float angle = get_global_transform().get_rotation();
if(rotating){
@@ -213,7 +219,8 @@ void Camera2D::_notification(int p_what) {
_update_scroll();
} break;
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
+
viewport = NULL;
Node *n=this;
@@ -239,7 +246,7 @@ void Camera2D::_notification(int p_what) {
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (is_current()) {
if (viewport) {
@@ -266,15 +273,15 @@ Vector2 Camera2D::get_offset() const{
return offset;
}
-void Camera2D::set_centered(bool p_centered){
+void Camera2D::set_anchor_mode(AnchorMode p_anchor_mode){
- centered=p_centered;
+ anchor_mode=p_anchor_mode;
_update_scroll();
}
-bool Camera2D::is_centered() const {
+Camera2D::AnchorMode Camera2D::get_anchor_mode() const {
- return centered;
+ return anchor_mode;
}
void Camera2D::set_rotating(bool p_rotating){
@@ -316,13 +323,23 @@ bool Camera2D::is_current() const {
void Camera2D::make_current() {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
current=true;
} else {
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,group_name,"_make_current",this);
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,group_name,"_make_current",this);
}
}
+void Camera2D::clear_current() {
+
+ current=false;
+ if (is_inside_tree()) {
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,group_name,"_make_current",(Object*)(NULL));
+ }
+
+}
+
+
void Camera2D::set_limit(Margin p_margin,int p_limit) {
ERR_FAIL_INDEX(p_margin,4);
@@ -428,13 +445,14 @@ void Camera2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&Camera2D::set_offset);
ObjectTypeDB::bind_method(_MD("get_offset"),&Camera2D::get_offset);
- ObjectTypeDB::bind_method(_MD("set_centered","centered"),&Camera2D::set_centered);
- ObjectTypeDB::bind_method(_MD("is_centered"),&Camera2D::is_centered);
+ ObjectTypeDB::bind_method(_MD("set_anchor_mode","anchor_mode"),&Camera2D::set_anchor_mode);
+ ObjectTypeDB::bind_method(_MD("get_anchor_mode"),&Camera2D::get_anchor_mode);
ObjectTypeDB::bind_method(_MD("set_rotating","rotating"),&Camera2D::set_rotating);
ObjectTypeDB::bind_method(_MD("is_rotating"),&Camera2D::is_rotating);
ObjectTypeDB::bind_method(_MD("make_current"),&Camera2D::make_current);
+ ObjectTypeDB::bind_method(_MD("clear_current"),&Camera2D::clear_current);
ObjectTypeDB::bind_method(_MD("_make_current"),&Camera2D::_make_current);
ObjectTypeDB::bind_method(_MD("_update_scroll"),&Camera2D::_update_scroll);
@@ -475,7 +493,7 @@ void Camera2D::_bind_methods() {
ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_offset"),_SCS("get_offset"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"centered"),_SCS("set_centered"),_SCS("is_centered"));
+ 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") );
@@ -495,6 +513,8 @@ void Camera2D::_bind_methods() {
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/bottom",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_BOTTOM);
+ BIND_CONSTANT( ANCHOR_MODE_DRAG_CENTER );
+ BIND_CONSTANT( ANCHOR_MODE_FIXED_TOP_LEFT );
}
@@ -502,7 +522,7 @@ Camera2D::Camera2D() {
- centered=true;
+ anchor_mode=ANCHOR_MODE_DRAG_CENTER;
rotating=false;
current=false;
limit[MARGIN_LEFT]=-10000000;
@@ -514,6 +534,7 @@ Camera2D::Camera2D() {
drag_margin[MARGIN_RIGHT]=0.2;
drag_margin[MARGIN_BOTTOM]=0.2;
camera_pos=Vector2();
+ first=true;
smoothing=0.0;
zoom = Vector2(1, 1);
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 116169cac1..79d84f48d0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,97 +26,106 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CAMERA_2D_H
-#define CAMERA_2D_H
-
-#include "scene/2d/node_2d.h"
-#include "scene/main/viewport.h"
-
-
-class Camera2D : public Node2D {
-
- OBJ_TYPE( Camera2D, Node2D );
-
-protected:
- Point2 camera_pos;
- Point2 smoothed_camera_pos;
- bool first;
-
- Viewport *viewport;
-
- StringName group_name;
- StringName canvas_group_name;
- RID canvas;
- Vector2 offset;
- Vector2 zoom;
- bool centered;
- bool rotating;
- bool current;
- float smoothing;
- int limit[4];
- float drag_margin[4];
-
- bool h_drag_enabled;
- bool v_drag_enabled;
- float h_ofs;
- float v_ofs;
-
-
- Point2 camera_screen_center;
- void _update_scroll();
-
- void _make_current(Object *p_which);
- void _set_current(bool p_current);
-protected:
-
- virtual Matrix32 get_camera_transform();
- void _notification(int p_what);
- static void _bind_methods();
-public:
-
- void set_offset(const Vector2& p_offset);
- Vector2 get_offset() const;
-
- void set_centered(bool p_centered);
- bool is_centered() const;
-
- void set_rotating(bool p_rotating);
- bool is_rotating() const;
-
- void set_limit(Margin p_margin,int p_limit);
- int get_limit(Margin p_margin) const;
-
-
- void set_h_drag_enabled(bool p_enabled);
- bool is_h_drag_enabled() const;
-
- void set_v_drag_enabled(bool p_enabled);
- bool is_v_drag_enabled() const;
-
- void set_drag_margin(Margin p_margin,float p_drag_margin);
- float get_drag_margin(Margin p_margin) const;
-
- void set_v_offset(float p_offset);
- float get_v_offset() const;
-
- void set_h_offset(float p_offset);
- float get_h_offset() const;
-
- void set_follow_smoothing(float p_speed);
- float get_follow_smoothing() const;
-
- void make_current();
- bool is_current() const;
-
- void set_zoom(const Vector2& p_zoom);
- Vector2 get_zoom() const;
-
- Point2 get_camera_screen_center() const;
-
- Vector2 get_camera_pos() const;
- void force_update_scroll();
-
- Camera2D();
-};
-
-#endif // CAMERA_2D_H
+#ifndef CAMERA_2D_H
+#define CAMERA_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/main/viewport.h"
+
+
+class Camera2D : public Node2D {
+
+ OBJ_TYPE( Camera2D, Node2D );
+public:
+
+ enum AnchorMode {
+ ANCHOR_MODE_FIXED_TOP_LEFT,
+ ANCHOR_MODE_DRAG_CENTER
+ };
+
+protected:
+ Point2 camera_pos;
+ Point2 smoothed_camera_pos;
+ bool first;
+
+ Viewport *viewport;
+
+ StringName group_name;
+ StringName canvas_group_name;
+ RID canvas;
+ Vector2 offset;
+ Vector2 zoom;
+ AnchorMode anchor_mode;
+ bool rotating;
+ bool current;
+ float smoothing;
+ int limit[4];
+ float drag_margin[4];
+
+ bool h_drag_enabled;
+ bool v_drag_enabled;
+ float h_ofs;
+ float v_ofs;
+
+
+ Point2 camera_screen_center;
+ void _update_scroll();
+
+ void _make_current(Object *p_which);
+ void _set_current(bool p_current);
+protected:
+
+ virtual Matrix32 get_camera_transform();
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_offset(const Vector2& p_offset);
+ Vector2 get_offset() const;
+
+ void set_anchor_mode(AnchorMode p_anchor_mode);
+ AnchorMode get_anchor_mode() const;
+
+ void set_rotating(bool p_rotating);
+ bool is_rotating() const;
+
+ void set_limit(Margin p_margin,int p_limit);
+ int get_limit(Margin p_margin) const;
+
+
+ void set_h_drag_enabled(bool p_enabled);
+ bool is_h_drag_enabled() const;
+
+ void set_v_drag_enabled(bool p_enabled);
+ bool is_v_drag_enabled() const;
+
+ void set_drag_margin(Margin p_margin,float p_drag_margin);
+ float get_drag_margin(Margin p_margin) const;
+
+ void set_v_offset(float p_offset);
+ float get_v_offset() const;
+
+ void set_h_offset(float p_offset);
+ float get_h_offset() const;
+
+ void set_follow_smoothing(float p_speed);
+ float get_follow_smoothing() const;
+
+ void make_current();
+ void clear_current();
+ bool is_current() const;
+
+ void set_zoom(const Vector2& p_zoom);
+ Vector2 get_zoom() const;
+
+ Point2 get_camera_screen_center() const;
+
+ Vector2 get_camera_pos() const;
+ void force_update_scroll();
+
+ Camera2D();
+};
+
+VARIANT_ENUM_CAST(Camera2D::AnchorMode);
+
+#endif // CAMERA_2D_H
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index d66f100b3f..295a57d033 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -35,10 +35,200 @@
#include "scene/resources/font.h"
#include "scene/resources/texture.h"
#include "scene/resources/style_box.h"
+#include "os/input.h"
+
+bool CanvasItemMaterial::_set(const StringName& p_name, const Variant& p_value) {
+
+ if (p_name==SceneStringNames::get_singleton()->shader_shader) {
+ set_shader(p_value);
+ return true;
+ } else if (p_name==SceneStringNames::get_singleton()->shading_mode) {
+ set_shading_mode(ShadingMode(p_value.operator int()));
+ return true;
+ } else {
+
+ if (shader.is_valid()) {
+
+
+ StringName pr = shader->remap_param(p_name);
+ if (!pr) {
+ String n = p_name;
+ if (n.find("param/")==0) { //backwards compatibility
+ pr = n.substr(6,n.length());
+ }
+ }
+ if (pr) {
+ VisualServer::get_singleton()->canvas_item_material_set_shader_param(material,pr,p_value);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CanvasItemMaterial::_get(const StringName& p_name,Variant &r_ret) const {
+
+
+ if (p_name==SceneStringNames::get_singleton()->shader_shader) {
+
+ r_ret=get_shader();
+ return true;
+ } else if (p_name==SceneStringNames::get_singleton()->shading_mode) {
+
+
+ r_ret=shading_mode;
+ return true;
+ } else {
+
+ if (shader.is_valid()) {
+
+ StringName pr = shader->remap_param(p_name);
+ if (pr) {
+ r_ret=VisualServer::get_singleton()->canvas_item_material_get_shader_param(material,pr);
+ return true;
+ }
+ }
+
+ }
+
+
+ return false;
+}
+
+
+void CanvasItemMaterial::_get_property_list( List<PropertyInfo> *p_list) const {
+
+ p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"CanvasItemShader,CanvasItemShaderGraph" ) );
+ p_list->push_back( PropertyInfo( Variant::INT, "shader/shading_mode",PROPERTY_HINT_ENUM,"Normal,Unshaded,Light Only") );
+
+ if (!shader.is_null()) {
+
+ shader->get_param_list(p_list);
+ }
+
+}
+
+void CanvasItemMaterial::set_shader(const Ref<Shader>& p_shader) {
+
+ ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM);
+#ifdef TOOLS_ENABLED
+
+ if (shader.is_valid()) {
+ shader->disconnect("changed",this,"_shader_changed");
+ }
+#endif
+ shader=p_shader;
+
+#ifdef TOOLS_ENABLED
+
+ if (shader.is_valid()) {
+ shader->connect("changed",this,"_shader_changed");
+ }
+#endif
+
+ RID rid;
+ if (shader.is_valid())
+ rid=shader->get_rid();
+
+ VS::get_singleton()->canvas_item_material_set_shader(material,rid);
+ _change_notify(); //properties for shader exposed
+ emit_changed();
+}
+
+Ref<Shader> CanvasItemMaterial::get_shader() const{
+
+ return shader;
+}
+
+void CanvasItemMaterial::set_shader_param(const StringName& p_param,const Variant& p_value){
+
+ VS::get_singleton()->canvas_item_material_set_shader_param(material,p_param,p_value);
+}
+
+Variant CanvasItemMaterial::get_shader_param(const StringName& p_param) const{
+
+ return VS::get_singleton()->canvas_item_material_get_shader_param(material,p_param);
+}
+
+void CanvasItemMaterial::_shader_changed() {
+
+
+}
+
+RID CanvasItemMaterial::get_rid() const {
+
+ return material;
+}
+
+void CanvasItemMaterial::set_shading_mode(ShadingMode p_mode) {
+
+ shading_mode=p_mode;
+ VS::get_singleton()->canvas_item_material_set_shading_mode(material,VS::CanvasItemShadingMode(p_mode));
+}
+
+CanvasItemMaterial::ShadingMode CanvasItemMaterial::get_shading_mode() const {
+ return shading_mode;
+}
+
+
+void CanvasItemMaterial::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_shader","shader:Shader"),&CanvasItemMaterial::set_shader);
+ ObjectTypeDB::bind_method(_MD("get_shader:Shader"),&CanvasItemMaterial::get_shader);
+ ObjectTypeDB::bind_method(_MD("set_shader_param","param","value"),&CanvasItemMaterial::set_shader_param);
+ ObjectTypeDB::bind_method(_MD("get_shader_param","param"),&CanvasItemMaterial::get_shader_param);
+ ObjectTypeDB::bind_method(_MD("set_shading_mode","mode"),&CanvasItemMaterial::set_shading_mode);
+ ObjectTypeDB::bind_method(_MD("get_shading_mode"),&CanvasItemMaterial::get_shading_mode);
+
+ BIND_CONSTANT( SHADING_NORMAL );
+ BIND_CONSTANT( SHADING_UNSHADED );
+ BIND_CONSTANT( SHADING_ONLY_LIGHT );
+
+
+}
+
+void CanvasItemMaterial::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+
+ String f = p_function.operator String();
+ if ((f=="get_shader_param" || f=="set_shader_param") && p_idx==0) {
+
+ if (shader.is_valid()) {
+ List<PropertyInfo> pl;
+ shader->get_param_list(&pl);
+ for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
+ r_options->push_back("\""+E->get().name.replace_first("shader_param/","")+"\"");
+ }
+ }
+ }
+ Resource::get_argument_options(p_function,p_idx,r_options);
+}
+
+CanvasItemMaterial::CanvasItemMaterial() {
+
+ material=VS::get_singleton()->canvas_item_material_create();
+ shading_mode=SHADING_NORMAL;
+}
+
+CanvasItemMaterial::~CanvasItemMaterial(){
+
+ VS::get_singleton()->free(material);
+}
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////
+
+
bool CanvasItem::is_visible() const {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return false;
const CanvasItem *p=this;
@@ -75,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);
}
@@ -92,12 +282,13 @@ void CanvasItem::show() {
hidden=false;
VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,true);
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (is_visible()) {
_propagate_visibility_changed(true);
}
+ _change_notify("visibility/visible");
}
@@ -106,15 +297,25 @@ void CanvasItem::hide() {
if (hidden)
return;
- bool propagate=is_inside_scene() && is_visible();
+ bool propagate=is_inside_tree() && is_visible();
hidden=true;
VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,false);
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (propagate)
_propagate_visibility_changed(false);
+ _change_notify("visibility/visible");
+}
+
+void CanvasItem::set_hidden(bool p_hidden) {
+
+ if (hidden == p_hidden) {
+ return;
+ }
+
+ _set_visible_(!p_hidden);
}
@@ -147,12 +348,11 @@ void CanvasItem::_update_callback() {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
pending_update=false;
return;
}
-
VisualServer::get_singleton()->canvas_item_clear(get_canvas_item());
//todo updating = true - only allow drawing here
if (is_visible()) { //todo optimize this!!
@@ -225,7 +425,7 @@ void CanvasItem::_sort_children() {
pending_children_sort=false;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
for(int i=0;i<get_child_count();i++) {
@@ -243,7 +443,7 @@ void CanvasItem::_sort_children() {
void CanvasItem::_raise_self() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
VisualServer::get_singleton()->canvas_item_raise(canvas_item);
@@ -283,7 +483,7 @@ void CanvasItem::_enter_canvas() {
group = "root_canvas"+itos(canvas.get_id());
add_to_group(group);
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_UNIQUE,group,"_raise_self");
+ get_tree()->call_group(SceneTree::GROUP_CALL_UNIQUE,group,"_raise_self");
} else {
@@ -313,7 +513,7 @@ void CanvasItem::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
first_draw=true;
pending_children_sort=false;
@@ -324,14 +524,14 @@ void CanvasItem::_notification(int p_what) {
}
_enter_canvas();
if (!block_transform_notify && !xform_change.in_list()) {
- get_scene()->xform_change_list.add(&xform_change);
+ get_tree()->xform_change_list.add(&xform_change);
}
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
if (group!="") {
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_UNIQUE,group,"_raise_self");
+ get_tree()->call_group(SceneTree::GROUP_CALL_UNIQUE,group,"_raise_self");
} else {
CanvasItem *p = get_parent_item();
ERR_FAIL_COND(!p);
@@ -340,9 +540,9 @@ void CanvasItem::_notification(int p_what) {
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (xform_change.in_list())
- get_scene()->xform_change_list.remove(&xform_change);
+ get_tree()->xform_change_list.remove(&xform_change);
_exit_canvas();
if (C) {
get_parent()->cast_to<CanvasItem>()->children_items.erase(C);
@@ -379,7 +579,7 @@ bool CanvasItem::_is_visible_() const {
void CanvasItem::update() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (pending_update)
return;
@@ -406,7 +606,7 @@ void CanvasItem::set_as_toplevel(bool p_toplevel) {
if (toplevel==p_toplevel)
return;
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
toplevel=p_toplevel;
return;
}
@@ -458,6 +658,16 @@ CanvasItem::BlendMode CanvasItem::get_blend_mode() const {
return blend_mode;
}
+void CanvasItem::set_light_mask(int p_light_mask) {
+
+ light_mask=p_light_mask;
+ VS::get_singleton()->canvas_item_set_light_mask(canvas_item,p_light_mask);
+}
+
+int CanvasItem::get_light_mask() const{
+
+ return light_mask;
+}
void CanvasItem::item_rect_changed() {
@@ -511,7 +721,7 @@ void CanvasItem::draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos)
p_texture->draw(canvas_item,p_pos);
}
-void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_rect, bool p_tile,const Color& 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) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -519,17 +729,17 @@ void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_
}
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw_rect(canvas_item,p_rect,p_tile,p_modulate);
+ p_texture->draw_rect(canvas_item,p_rect,p_tile,p_modulate,p_transpose);
}
-void CanvasItem::draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) {
+void CanvasItem::draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw_rect_region(canvas_item,p_rect,p_src_rect,p_modulate);
+ p_texture->draw_rect_region(canvas_item,p_rect,p_src_rect,p_modulate,p_transpose);
}
void CanvasItem::draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect) {
@@ -630,8 +840,8 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
if (!p_node->xform_change.in_list()) {
if (!p_node->block_transform_notify) {
- if (p_node->is_inside_scene())
- get_scene()->xform_change_list.add(&p_node->xform_change);
+ if (p_node->is_inside_tree())
+ get_tree()->xform_change_list.add(&p_node->xform_change);
}
}
@@ -648,13 +858,13 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
Rect2 CanvasItem::get_viewport_rect() const {
- ERR_FAIL_COND_V(!is_inside_scene(),Rect2());
+ ERR_FAIL_COND_V(!is_inside_tree(),Rect2());
return get_viewport()->get_visible_rect();
}
RID CanvasItem::get_canvas() const {
- ERR_FAIL_COND_V(!is_inside_scene(),RID());
+ ERR_FAIL_COND_V(!is_inside_tree(),RID());
if (canvas_layer)
return canvas_layer->get_world_2d()->get_canvas();
@@ -677,7 +887,7 @@ CanvasItem *CanvasItem::get_toplevel() const {
Ref<World2D> CanvasItem::get_world_2d() const {
- ERR_FAIL_COND_V(!is_inside_scene(),Ref<World2D>());
+ ERR_FAIL_COND_V(!is_inside_tree(),Ref<World2D>());
CanvasItem *tl=get_toplevel();
@@ -693,7 +903,7 @@ Ref<World2D> CanvasItem::get_world_2d() const {
RID CanvasItem::get_viewport_rid() const {
- ERR_FAIL_COND_V(!is_inside_scene(),RID());
+ ERR_FAIL_COND_V(!is_inside_tree(),RID());
return get_viewport()->get_viewport();
}
@@ -720,6 +930,106 @@ bool CanvasItem::is_draw_behind_parent_enabled() const{
return behind;
}
+void CanvasItem::set_material(const Ref<CanvasItemMaterial>& p_material) {
+
+
+ material=p_material;
+ RID rid;
+ if (material.is_valid())
+ rid=material->get_rid();
+ VS::get_singleton()->canvas_item_set_material(canvas_item,rid);
+ _change_notify(); //properties for material exposed
+}
+
+void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
+
+ use_parent_material=p_use_parent_material;
+ VS::get_singleton()->canvas_item_set_use_parent_material(canvas_item,p_use_parent_material);
+}
+
+bool CanvasItem::get_use_parent_material() const{
+
+ return use_parent_material;
+}
+
+Ref<CanvasItemMaterial> CanvasItem::get_material() const{
+
+ return material;
+}
+
+
+InputEvent CanvasItem::make_input_local(const InputEvent& p_event) const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(),p_event);
+
+ InputEvent ev = p_event;
+
+ Matrix32 local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
+
+ switch(ev.type) {
+
+ case InputEvent::MOUSE_BUTTON: {
+
+ Vector2 g = local_matrix.xform(Vector2(ev.mouse_button.global_x,ev.mouse_button.global_y));
+ Vector2 l = local_matrix.xform(Vector2(ev.mouse_button.x,ev.mouse_button.y));
+ ev.mouse_button.x=l.x;
+ ev.mouse_button.y=l.y;
+ ev.mouse_button.global_x=g.x;
+ ev.mouse_button.global_y=g.y;
+
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+ Vector2 g = local_matrix.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y));
+ Vector2 l = local_matrix.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y));
+ Vector2 r = local_matrix.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y));
+ Vector2 s = local_matrix.basis_xform(Vector2(ev.mouse_motion.speed_x,ev.mouse_motion.speed_y));
+ ev.mouse_motion.x=l.x;
+ ev.mouse_motion.y=l.y;
+ ev.mouse_motion.global_x=g.x;
+ ev.mouse_motion.global_y=g.y;
+ ev.mouse_motion.relative_x=r.x;
+ ev.mouse_motion.relative_y=r.y;
+ ev.mouse_motion.speed_x=s.x;
+ ev.mouse_motion.speed_y=s.y;
+
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+
+
+ Vector2 t = local_matrix.xform(Vector2(ev.screen_touch.x,ev.screen_touch.y));
+ ev.screen_touch.x=t.x;
+ ev.screen_touch.y=t.y;
+
+ } break;
+ case InputEvent::SCREEN_DRAG: {
+
+
+ Vector2 t = local_matrix.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y));
+ Vector2 r = local_matrix.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y));
+ Vector2 s = local_matrix.basis_xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y));
+ ev.screen_drag.x=t.x;
+ ev.screen_drag.y=t.y;
+ ev.screen_drag.relative_x=r.x;
+ ev.screen_drag.relative_y=r.y;
+ ev.screen_drag.speed_x=s.x;
+ ev.screen_drag.speed_y=s.y;
+ } break;
+ }
+
+ return ev;
+}
+
+
+Vector2 CanvasItem::get_global_mouse_pos() const {
+
+ return get_viewport_transform().affine_inverse().xform(Input::get_singleton()->get_mouse_pos());
+}
+Vector2 CanvasItem::get_local_mouse_pos() const{
+
+ return (get_viewport_transform() * get_global_transform()).affine_inverse().xform(Input::get_singleton()->get_mouse_pos());
+}
+
void CanvasItem::_bind_methods() {
@@ -742,6 +1052,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);
@@ -751,25 +1062,27 @@ void CanvasItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_blend_mode","blend_mode"),&CanvasItem::set_blend_mode);
ObjectTypeDB::bind_method(_MD("get_blend_mode"),&CanvasItem::get_blend_mode);
+ ObjectTypeDB::bind_method(_MD("set_light_mask","light_mask"),&CanvasItem::set_light_mask);
+ ObjectTypeDB::bind_method(_MD("get_light_mask"),&CanvasItem::get_light_mask);
+
ObjectTypeDB::bind_method(_MD("set_opacity","opacity"),&CanvasItem::set_opacity);
ObjectTypeDB::bind_method(_MD("get_opacity"),&CanvasItem::get_opacity);
ObjectTypeDB::bind_method(_MD("set_self_opacity","self_opacity"),&CanvasItem::set_self_opacity);
ObjectTypeDB::bind_method(_MD("get_self_opacity"),&CanvasItem::get_self_opacity);
- ObjectTypeDB::bind_method(_MD("set_draw_behind_parent","enabe"),&CanvasItem::set_draw_behind_parent);
+ ObjectTypeDB::bind_method(_MD("set_draw_behind_parent","enable"),&CanvasItem::set_draw_behind_parent);
ObjectTypeDB::bind_method(_MD("is_draw_behind_parent_enabled"),&CanvasItem::is_draw_behind_parent_enabled);
ObjectTypeDB::bind_method(_MD("_set_on_top","on_top"),&CanvasItem::_set_on_top);
ObjectTypeDB::bind_method(_MD("_is_on_top"),&CanvasItem::_is_on_top);
-
//ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
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_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>()));
@@ -780,21 +1093,36 @@ void CanvasItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("draw_set_transform","pos","rot","scale"),&CanvasItem::draw_set_transform);
ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
ObjectTypeDB::bind_method(_MD("get_global_transform"),&CanvasItem::get_global_transform);
+ ObjectTypeDB::bind_method(_MD("get_global_transform_with_canvas"),&CanvasItem::get_global_transform_with_canvas);
ObjectTypeDB::bind_method(_MD("get_viewport_transform"),&CanvasItem::get_viewport_transform);
ObjectTypeDB::bind_method(_MD("get_viewport_rect"),&CanvasItem::get_viewport_rect);
+ ObjectTypeDB::bind_method(_MD("get_canvas_transform"),&CanvasItem::get_canvas_transform);
+ ObjectTypeDB::bind_method(_MD("get_local_mouse_pos"),&CanvasItem::get_local_mouse_pos);
+ ObjectTypeDB::bind_method(_MD("get_global_mouse_pos"),&CanvasItem::get_global_mouse_pos);
ObjectTypeDB::bind_method(_MD("get_canvas"),&CanvasItem::get_canvas);
ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d);
//ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport);
+ ObjectTypeDB::bind_method(_MD("set_material","material:CanvasItemMaterial"),&CanvasItem::set_material);
+ ObjectTypeDB::bind_method(_MD("get_material:CanvasItemMaterial"),&CanvasItem::get_material);
+
+ ObjectTypeDB::bind_method(_MD("set_use_parent_material","enable"),&CanvasItem::set_use_parent_material);
+ ObjectTypeDB::bind_method(_MD("get_use_parent_material"),&CanvasItem::get_use_parent_material);
+
+ ObjectTypeDB::bind_method(_MD("make_input_local","event"),&CanvasItem::make_input_local);
+
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_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/behind_parent"), _SCS("set_draw_behind_parent"),_SCS("is_draw_behind_parent_enabled") );
+ 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_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
//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") );
//ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled"));
@@ -824,10 +1152,12 @@ void CanvasItem::_bind_methods() {
Matrix32 CanvasItem::get_canvas_transform() const {
- ERR_FAIL_COND_V(!is_inside_scene(),Matrix32());
+ ERR_FAIL_COND_V(!is_inside_tree(),Matrix32());
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();
@@ -835,7 +1165,7 @@ Matrix32 CanvasItem::get_canvas_transform() const {
Matrix32 CanvasItem::get_viewport_transform() const {
- ERR_FAIL_COND_V(!is_inside_scene(),Matrix32());
+ ERR_FAIL_COND_V(!is_inside_tree(),Matrix32());
if (canvas_layer) {
@@ -854,6 +1184,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) {
@@ -871,7 +1209,10 @@ CanvasItem::CanvasItem() : xform_change(this) {
block_transform_notify=false;
// viewport=NULL;
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 604eef0527..667fedc956 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,6 +32,7 @@
#include "scene/main/node.h"
#include "scene/resources/texture.h"
#include "scene/main/scene_main_loop.h"
+#include "scene/resources/shader.h"
class CanvasLayer;
class Viewport;
@@ -39,6 +40,50 @@ class Font;
class StyleBox;
+class CanvasItemMaterial : public Resource{
+
+ OBJ_TYPE(CanvasItemMaterial,Resource);
+ RID material;
+ Ref<Shader> shader;
+public:
+ enum ShadingMode {
+ SHADING_NORMAL,
+ SHADING_UNSHADED,
+ SHADING_ONLY_LIGHT,
+ };
+
+protected:
+
+ ShadingMode shading_mode;
+
+ 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;
+
+ void _shader_changed();
+ static void _bind_methods();
+
+ void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
+
+public:
+
+ void set_shader(const Ref<Shader>& p_shader);
+ Ref<Shader> get_shader() const;
+
+ void set_shader_param(const StringName& p_param,const Variant& p_value);
+ Variant get_shader_param(const StringName& p_param) const;
+
+ void set_shading_mode(ShadingMode p_mode);
+ ShadingMode get_shading_mode() const;
+
+ virtual RID get_rid() const;
+ CanvasItemMaterial();
+ ~CanvasItemMaterial();
+};
+
+VARIANT_ENUM_CAST( CanvasItemMaterial::ShadingMode );
+
+
class CanvasItem : public Node {
OBJ_TYPE( CanvasItem, Node );
@@ -70,6 +115,7 @@ private:
List<CanvasItem*>::Element *C;
BlendMode blend_mode;
+ int light_mask;
bool first_draw;
bool hidden;
@@ -79,6 +125,10 @@ private:
bool drawing;
bool block_transform_notify;
bool behind;
+ bool use_parent_material;
+ bool notify_local_transform;
+
+ Ref<CanvasItemMaterial> material;
mutable Matrix32 global_transform;
mutable bool global_invalid;
@@ -99,8 +149,6 @@ private:
void _queue_sort_children();
void _sort_children();
-
-
void _notify_transform(CanvasItem *p_node);
void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); }
@@ -108,9 +156,7 @@ private:
protected:
-
-
- _FORCE_INLINE_ void _notify_transform() { if (!is_inside_scene()) 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();
@@ -120,7 +166,7 @@ public:
enum {
- NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED, //unique
+ NOTIFICATION_TRANSFORM_CHANGED=SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique
NOTIFICATION_DRAW=30,
NOTIFICATION_VISIBILITY_CHANGED=31,
NOTIFICATION_ENTER_CANVAS=32,
@@ -144,12 +190,16 @@ 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);
+ int get_light_mask() const;
+
void set_opacity(float p_opacity);
float get_opacity() const;
@@ -162,8 +212,8 @@ public:
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_rect(const Ref<Texture>& p_texture, const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1));
- 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));
+ 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);
void draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture=Ref<Texture>(),float p_width=1);
void draw_polygon(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), Ref<Texture> p_texture=Ref<Texture>());
@@ -204,6 +254,19 @@ public:
RID get_canvas() const;
Ref<World2D> get_world_2d() const;
+ void set_material(const Ref<CanvasItemMaterial>& p_material);
+ Ref<CanvasItemMaterial> get_material() const;
+
+ void set_use_parent_material(bool p_use_parent_material);
+ bool get_use_parent_material() const;
+
+ InputEvent make_input_local(const InputEvent& pevent) const;
+
+ 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();
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
new file mode 100644
index 0000000000..82dd8012a5
--- /dev/null
+++ b/scene/2d/canvas_modulate.cpp
@@ -0,0 +1,46 @@
+#include "canvas_modulate.h"
+
+
+void CanvasModulate::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_CANVAS) {
+
+ 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));
+ }
+}
+
+void CanvasModulate::_bind_methods(){
+
+ ObjectTypeDB::bind_method(_MD("set_color","color"),&CanvasModulate::set_color);
+ ObjectTypeDB::bind_method(_MD("get_color"),&CanvasModulate::get_color);
+
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
+}
+
+
+void CanvasModulate::set_color(const Color& p_color){
+
+ color=p_color;
+ if (is_inside_tree()) {
+ VS::get_singleton()->canvas_set_modulate(get_canvas(),color);
+ }
+}
+Color CanvasModulate::get_color() const {
+
+ return color;
+}
+
+
+CanvasModulate::CanvasModulate()
+{
+ color=Color(1,1,1,1);
+}
+
+CanvasModulate::~CanvasModulate()
+{
+
+}
+
diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h
new file mode 100644
index 0000000000..a6894f29c2
--- /dev/null
+++ b/scene/2d/canvas_modulate.h
@@ -0,0 +1,23 @@
+#ifndef CANVASMODULATE_H
+#define CANVASMODULATE_H
+
+#include "scene/2d/node_2d.h"
+
+class CanvasModulate : public Node2D {
+
+ OBJ_TYPE(CanvasModulate,Node2D);
+
+ Color color;
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_color(const Color& p_color);
+ Color get_color() const;
+
+ CanvasModulate();
+ ~CanvasModulate();
+};
+
+#endif // CANVASMODULATE_H
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index ab8c4551ee..8b8caf13d3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,6 +28,7 @@
/*************************************************************************/
#include "collision_object_2d.h"
#include "servers/physics_2d_server.h"
+#include "scene/scene_string_names.h"
void CollisionObject2D::_update_shapes_from_children() {
@@ -45,8 +46,12 @@ void CollisionObject2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
+ if (area)
+ Physics2DServer::get_singleton()->area_set_transform(rid,get_global_transform());
+ else
+ Physics2DServer::get_singleton()->body_set_state(rid,Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform());
RID space = get_world_2d()->get_space();
if (area) {
@@ -54,9 +59,15 @@ void CollisionObject2D::_notification(int p_what) {
} else
Physics2DServer::get_singleton()->body_set_space(rid,space);
+ _update_pickable();
+
//get space
}
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ _update_pickable();
+ } break;
case NOTIFICATION_TRANSFORM_CHANGED: {
if (area)
@@ -65,7 +76,7 @@ void CollisionObject2D::_notification(int p_what) {
Physics2DServer::get_singleton()->body_set_state(rid,Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform());
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (area) {
Physics2DServer::get_singleton()->area_set_space(rid,RID());
@@ -104,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") {
-
- shapes.resize(p_value);
- _update_shapes();
- _change_notify();
+ if (name.begins_with("shapes/")) {
- } 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);
@@ -132,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")
@@ -152,14 +158,65 @@ 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) );
+ //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)+"/";
- p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D",PROPERTY_USAGE_NOEDITOR) );
- p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) );
- p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) );
+ p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+ p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+ p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+ }
+}
+
+
+void CollisionObject2D::set_pickable(bool p_enabled) {
+
+ if (pickable==p_enabled)
+ return;
+
+ pickable=p_enabled;
+ _update_pickable();
+}
+
+bool CollisionObject2D::is_pickable() const {
+
+ return pickable;
+}
+
+void CollisionObject2D::_input_event(Node *p_viewport, const InputEvent& p_input_event, int p_shape) {
+
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_input_event,p_viewport,p_input_event,p_shape);
+ }
+ emit_signal(SceneStringNames::get_singleton()->input_event,p_viewport,p_input_event,p_shape);
+}
+
+void CollisionObject2D::_mouse_enter() {
+
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter);
+ }
+ emit_signal(SceneStringNames::get_singleton()->mouse_enter);
+}
+
+
+void CollisionObject2D::_mouse_exit() {
+
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit);
}
+ emit_signal(SceneStringNames::get_singleton()->mouse_exit);
+
+}
+
+void CollisionObject2D::_update_pickable() {
+ if (!is_inside_tree())
+ return;
+ bool pickable = this->pickable && is_inside_tree() && is_visible();
+ if (area)
+ Physics2DServer::get_singleton()->area_set_pickable(rid,pickable);
+ else
+ Physics2DServer::get_singleton()->body_set_pickable(rid,pickable);
}
void CollisionObject2D::_bind_methods() {
@@ -176,17 +233,35 @@ void CollisionObject2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("clear_shapes"),&CollisionObject2D::clear_shapes);
ObjectTypeDB::bind_method(_MD("get_rid"),&CollisionObject2D::get_rid);
+ ObjectTypeDB::bind_method(_MD("set_pickable","enabled"),&CollisionObject2D::set_pickable);
+ ObjectTypeDB::bind_method(_MD("is_pickable"),&CollisionObject2D::is_pickable);
+
+ BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::OBJECT,"viewport"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::INT,"shape_idx")));
+
+ ADD_SIGNAL( MethodInfo("input_event",PropertyInfo(Variant::OBJECT,"viewport"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::INT,"shape_idx")));
+ ADD_SIGNAL( MethodInfo("mouse_enter"));
+ ADD_SIGNAL( MethodInfo("mouse_exit"));
+
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"input/pickable"),_SCS("set_pickable"),_SCS("is_pickable"));
+
}
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 {
@@ -197,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) {
@@ -206,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 {
@@ -258,7 +345,9 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
rid=p_rid;
area=p_area;
+ pickable=true;
if (p_area) {
+
Physics2DServer::get_singleton()->area_attach_object_instance_ID(rid,get_instance_ID());
} else {
Physics2DServer::get_singleton()->body_attach_object_instance_ID(rid,get_instance_ID());
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 4a529ce062..473f13d0ff 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,6 +38,7 @@ class CollisionObject2D : public Node2D {
bool area;
RID rid;
+ bool pickable;
struct ShapeData {
Matrix32 xform;
@@ -66,9 +67,17 @@ protected:
bool _get(const StringName& p_name,Variant &r_ret) const;
void _get_property_list( List<PropertyInfo> *p_list) const;
static void _bind_methods();
+
+ void _update_pickable();
+friend class Viewport;
+ void _input_event(Node *p_viewport, const InputEvent& p_input_event, int p_shape);
+ void _mouse_enter();
+ void _mouse_exit();
+
public:
+
void add_shape(const Ref<Shape2D>& p_shape, const Matrix32& p_transform=Matrix32());
int get_shape_count() const;
void set_shape(int p_shape_idx, const Ref<Shape2D>& p_shape);
@@ -80,6 +89,9 @@ public:
void remove_shape(int p_shape_idx);
void clear_shapes();
+ void set_pickable(bool p_enabled);
+ bool is_pickable() const;
+
_FORCE_INLINE_ RID get_rid() const { return rid; }
CollisionObject2D();
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 5ab223a1b8..1479cb7881 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,6 +33,9 @@
void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
+ if (unparenting || !can_update_body)
+ return;
+
CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>();
ERR_FAIL_COND(!co);
@@ -41,18 +44,25 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
bool solids=build_mode==BUILD_SOLIDS;
-
if (solids) {
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon);
+ shape_from=co->get_shape_count();
for(int i=0;i<decomp.size();i++) {
Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D );
convex->set_points(decomp[i]);
co->add_shape(convex,get_transform());
+ if (trigger)
+ 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 {
@@ -71,6 +81,11 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
concave->set_segments(segments);
co->add_shape(concave,get_transform());
+ 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;
}
@@ -80,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;
@@ -93,33 +110,63 @@ void CollisionPolygon2D::_notification(int p_what) {
switch(p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ unparenting=false;
+ can_update_body=get_tree()->is_editor_hint();
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ can_update_body=false;
+ } break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (!is_inside_scene())
+ 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);
}
+//#define DEBUG_DECOMPOSE
+#if defined(TOOLS_ENABLED) && defined (DEBUG_DECOMPOSE)
Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon);
-#define DEBUG_DECOMPOSE
-#ifdef DEBUG_DECOMPOSE
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;
+ _update_parent();
} break;
+
}
}
@@ -127,20 +174,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();
}
@@ -153,6 +202,7 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {
ERR_FAIL_INDEX(p_mode,2);
build_mode=p_mode;
+ _update_parent();
}
CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const{
@@ -165,6 +215,36 @@ Rect2 CollisionPolygon2D::get_item_rect() const {
return aabb;
}
+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{
+
+ return trigger;
+}
+
+
+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);
@@ -174,14 +254,31 @@ void CollisionPolygon2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon2D::set_build_mode);
ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon2D::get_build_mode);
- ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Automatic,Segments,Solids"),_SCS("set_build_mode"),_SCS("get_build_mode"));
+ ObjectTypeDB::bind_method(_MD("set_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() {
aabb=Rect2(-10,-10,20,20);
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 09c2060088..4bc9713c8a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -50,16 +50,29 @@ protected:
Rect2 aabb;
BuildMode build_mode;
Vector<Point2> polygon;
+ bool trigger;
+ bool unparenting;
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);
static void _bind_methods();
public:
+ void set_trigger(bool p_trigger);
+ bool is_trigger() const;
+
void set_build_mode(BuildMode p_mode);
BuildMode get_build_mode() const;
@@ -67,6 +80,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 f7e4c5faf0..85751fc735 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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() {
@@ -72,11 +74,29 @@ void CollisionShape2D::_notification(int p_what) {
switch(p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ unparenting=false;
+ can_update_body=get_tree()->is_editor_hint();
+
+ } break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (!is_inside_scene())
+ 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;
/*
@@ -89,106 +109,22 @@ 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);
- }
-
- 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 (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
+ break;
+ }
- } else if (shape->cast_to<ConvexPolygonShape2D>()) {
+ if (!shape.is_valid()) {
+ break;
+ }
- ConvexPolygonShape2D *s = shape->cast_to<ConvexPolygonShape2D>();
+ rect=Rect2();
- 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;
@@ -206,7 +142,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");
@@ -225,7 +168,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{
@@ -233,6 +183,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);
@@ -242,14 +205,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 a89af49a34..82e1137174 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 0e673ff791..adb2904a0a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@
void Joint2D::_update_joint() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (joint.is_valid()) {
@@ -86,7 +86,7 @@ void Joint2D::_notification(int p_what) {
case NOTIFICATION_READY: {
_update_joint();
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (joint.is_valid()) {
Physics2DServer::get_singleton()->free(joint);
@@ -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,7 +164,7 @@ void PinJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
- if (is_inside_scene() && get_scene()->is_editor_hint()) {
+ 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);
@@ -173,17 +192,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,7 +241,7 @@ void GrooveJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
- if (is_inside_scene() && get_scene()->is_editor_hint()) {
+ 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);
@@ -223,7 +267,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,7 +339,7 @@ void DampedSpringJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
- if (is_inside_scene() && get_scene()->is_editor_hint()) {
+ 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);
@@ -316,7 +364,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 7027e4386a..d468f3a6b5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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
new file mode 100644
index 0000000000..a2112c7d37
--- /dev/null
+++ b/scene/2d/light_2d.cpp
@@ -0,0 +1,382 @@
+#include "light_2d.h"
+#include "servers/visual_server.h"
+
+void Light2D::edit_set_pivot(const Point2& p_pivot) {
+
+ set_texture_offset(p_pivot);
+
+}
+
+Point2 Light2D::edit_get_pivot() const {
+
+ return get_texture_offset();
+}
+bool Light2D::edit_has_pivot() const {
+
+ return true;
+}
+
+Rect2 Light2D::get_item_rect() const {
+
+ if (texture.is_null())
+ return Rect2(0,0,1,1);
+
+ Size2i s;
+
+ s = texture->get_size()*_scale;
+ Point2i ofs=texture_offset;
+ ofs-=s/2;
+
+ if (s==Size2(0,0))
+ s=Size2(1,1);
+
+ return Rect2(ofs,s);
+}
+
+
+void Light2D::set_enabled( bool p_enabled) {
+
+ VS::get_singleton()->canvas_light_set_enabled(canvas_light,p_enabled);
+ enabled=p_enabled;
+}
+
+bool Light2D::is_enabled() const {
+
+ return enabled;
+}
+
+void Light2D::set_texture( const Ref<Texture>& p_texture) {
+
+ texture=p_texture;
+ if (texture.is_valid())
+ VS::get_singleton()->canvas_light_set_texture(canvas_light,texture->get_rid());
+ else
+ VS::get_singleton()->canvas_light_set_texture(canvas_light,RID());
+}
+
+Ref<Texture> Light2D::get_texture() const {
+
+ return texture;
+}
+
+void Light2D::set_texture_offset( const Vector2& p_offset) {
+
+ texture_offset=p_offset;
+ VS::get_singleton()->canvas_light_set_texture_offset(canvas_light,texture_offset);
+ item_rect_changed();
+
+}
+
+Vector2 Light2D::get_texture_offset() const {
+
+ return texture_offset;
+}
+
+void Light2D::set_color( const Color& p_color) {
+
+ color=p_color;
+ VS::get_singleton()->canvas_light_set_color(canvas_light,color);
+
+}
+Color Light2D::get_color() const {
+
+ return color;
+}
+
+void Light2D::set_height( float p_height) {
+
+ height=p_height;
+ VS::get_singleton()->canvas_light_set_height(canvas_light,height);
+
+}
+
+
+float Light2D::get_height() const {
+
+ return height;
+}
+
+void Light2D::set_energy( float p_energy) {
+
+ energy=p_energy;
+ VS::get_singleton()->canvas_light_set_energy(canvas_light,energy);
+
+}
+
+
+float Light2D::get_energy() const {
+
+ return energy;
+}
+
+
+
+void Light2D::set_texture_scale( float p_scale) {
+
+ _scale=p_scale;
+ VS::get_singleton()->canvas_light_set_scale(canvas_light,_scale);
+ item_rect_changed();
+
+}
+
+
+float Light2D::get_texture_scale() const {
+
+ return _scale;
+}
+
+void Light2D::set_z_range_min( int p_min_z) {
+
+ z_min=p_min_z;
+ VS::get_singleton()->canvas_light_set_z_range(canvas_light,z_min,z_max);
+
+}
+int Light2D::get_z_range_min() const {
+
+ return z_min;
+}
+
+void Light2D::set_z_range_max( int p_max_z) {
+
+ z_max=p_max_z;
+ VS::get_singleton()->canvas_light_set_z_range(canvas_light,z_min,z_max);
+
+}
+int Light2D::get_z_range_max() const {
+
+ return z_max;
+}
+
+void Light2D::set_layer_range_min( int p_min_layer) {
+
+ layer_min=p_min_layer;
+ VS::get_singleton()->canvas_light_set_layer_range(canvas_light,layer_min,layer_max);
+
+}
+int Light2D::get_layer_range_min() const {
+
+ return layer_min;
+}
+
+void Light2D::set_layer_range_max( int p_max_layer) {
+
+ layer_max=p_max_layer;
+ VS::get_singleton()->canvas_light_set_layer_range(canvas_light,layer_min,layer_max);
+
+}
+int Light2D::get_layer_range_max() const {
+
+ return layer_max;
+}
+
+void Light2D::set_item_mask( int p_mask) {
+
+ item_mask=p_mask;
+ VS::get_singleton()->canvas_light_set_item_mask(canvas_light,item_mask);
+
+}
+
+int Light2D::get_item_mask() const {
+
+ return item_mask;
+}
+
+void Light2D::set_item_shadow_mask( int p_mask) {
+
+ item_shadow_mask=p_mask;
+ VS::get_singleton()->canvas_light_set_item_shadow_mask(canvas_light,item_shadow_mask);
+
+}
+
+int Light2D::get_item_shadow_mask() const {
+
+ return item_shadow_mask;
+}
+
+void Light2D::set_mode( Mode p_mode ) {
+
+ mode=p_mode;
+ VS::get_singleton()->canvas_light_set_mode(canvas_light,VS::CanvasLightMode(p_mode));
+}
+
+Light2D::Mode Light2D::get_mode() const {
+
+ return mode;
+}
+
+void Light2D::set_shadow_enabled( bool p_enabled) {
+
+ shadow=p_enabled;
+ VS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light,shadow);
+
+}
+bool Light2D::is_shadow_enabled() const {
+
+ return shadow;
+}
+
+void Light2D::set_shadow_buffer_size( int p_size ) {
+
+ shadow_buffer_size=p_size;
+ VS::get_singleton()->canvas_light_set_shadow_buffer_size(canvas_light,shadow_buffer_size);
+}
+
+int Light2D::get_shadow_buffer_size() const {
+
+ return shadow_buffer_size;
+}
+
+void Light2D::set_shadow_esm_multiplier( float p_multiplier) {
+
+ shadow_esm_multiplier=p_multiplier;
+ VS::get_singleton()->canvas_light_set_shadow_esm_multiplier(canvas_light,p_multiplier);
+}
+
+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() );
+ }
+
+ if (p_what==NOTIFICATION_TRANSFORM_CHANGED) {
+
+ VS::get_singleton()->canvas_light_set_transform( canvas_light, get_global_transform());
+ }
+
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+ VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, RID() );
+ }
+
+}
+
+void Light2D::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&Light2D::set_enabled);
+ ObjectTypeDB::bind_method(_MD("is_enabled"),&Light2D::is_enabled);
+
+ ObjectTypeDB::bind_method(_MD("set_texture","texture"),&Light2D::set_texture);
+ ObjectTypeDB::bind_method(_MD("get_texture"),&Light2D::get_texture);
+
+ ObjectTypeDB::bind_method(_MD("set_texture_offset","texture_offset"),&Light2D::set_texture_offset);
+ ObjectTypeDB::bind_method(_MD("get_texture_offset"),&Light2D::get_texture_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_color","color"),&Light2D::set_color);
+ ObjectTypeDB::bind_method(_MD("get_color"),&Light2D::get_color);
+
+ ObjectTypeDB::bind_method(_MD("set_height","height"),&Light2D::set_height);
+ ObjectTypeDB::bind_method(_MD("get_height"),&Light2D::get_height);
+
+ ObjectTypeDB::bind_method(_MD("set_energy","energy"),&Light2D::set_energy);
+ ObjectTypeDB::bind_method(_MD("get_energy"),&Light2D::get_energy);
+
+ ObjectTypeDB::bind_method(_MD("set_texture_scale","texture_scale"),&Light2D::set_texture_scale);
+ ObjectTypeDB::bind_method(_MD("get_texture_scale"),&Light2D::get_texture_scale);
+
+
+ ObjectTypeDB::bind_method(_MD("set_z_range_min","z"),&Light2D::set_z_range_min);
+ ObjectTypeDB::bind_method(_MD("get_z_range_min"),&Light2D::get_z_range_min);
+
+ ObjectTypeDB::bind_method(_MD("set_z_range_max","z"),&Light2D::set_z_range_max);
+ ObjectTypeDB::bind_method(_MD("get_z_range_max"),&Light2D::get_z_range_max);
+
+ ObjectTypeDB::bind_method(_MD("set_layer_range_min","layer"),&Light2D::set_layer_range_min);
+ ObjectTypeDB::bind_method(_MD("get_layer_range_min"),&Light2D::get_layer_range_min);
+
+ ObjectTypeDB::bind_method(_MD("set_layer_range_max","layer"),&Light2D::set_layer_range_max);
+ ObjectTypeDB::bind_method(_MD("get_layer_range_max"),&Light2D::get_layer_range_max);
+
+
+ ObjectTypeDB::bind_method(_MD("set_item_mask","item_mask"),&Light2D::set_item_mask);
+ ObjectTypeDB::bind_method(_MD("get_item_mask"),&Light2D::get_item_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_item_shadow_mask","item_shadow_mask"),&Light2D::set_item_shadow_mask);
+ ObjectTypeDB::bind_method(_MD("get_item_shadow_mask"),&Light2D::get_item_shadow_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_mode","mode"),&Light2D::set_mode);
+ ObjectTypeDB::bind_method(_MD("get_mode"),&Light2D::get_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_shadow_enabled","enabled"),&Light2D::set_shadow_enabled);
+ ObjectTypeDB::bind_method(_MD("is_shadow_enabled"),&Light2D::is_shadow_enabled);
+
+ ObjectTypeDB::bind_method(_MD("set_shadow_buffer_size","size"),&Light2D::set_shadow_buffer_size);
+ ObjectTypeDB::bind_method(_MD("get_shadow_buffer_size"),&Light2D::get_shadow_buffer_size);
+
+ 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,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"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min"));
+ 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"));
+
+ BIND_CONSTANT( MODE_ADD );
+ BIND_CONSTANT( MODE_SUB );
+ BIND_CONSTANT( MODE_MIX );
+ BIND_CONSTANT( MODE_MASK );
+
+
+}
+
+Light2D::Light2D() {
+
+ canvas_light=VisualServer::get_singleton()->canvas_light_create();
+ enabled=true;
+ shadow=false;
+ color=Color(1,1,1);
+ height=0;
+ _scale=1.0;
+ z_min=-1024;
+ z_max=1024;
+ layer_min=0;
+ layer_max=0;
+ item_mask=1;
+ item_shadow_mask=1;
+ mode=MODE_ADD;
+ shadow_buffer_size=2048;
+ shadow_esm_multiplier=80;
+ energy=1.0;
+ shadow_color=Color(0,0,0,0);
+
+}
+
+Light2D::~Light2D() {
+
+ VisualServer::get_singleton()->free(canvas_light);
+}
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
new file mode 100644
index 0000000000..0828d9ac33
--- /dev/null
+++ b/scene/2d/light_2d.h
@@ -0,0 +1,112 @@
+#ifndef LIGHT_2D_H
+#define LIGHT_2D_H
+
+#include "scene/2d/node_2d.h"
+
+class Light2D : public Node2D {
+
+ OBJ_TYPE(Light2D,Node2D);
+public:
+ enum Mode {
+ MODE_ADD,
+ MODE_SUB,
+ MODE_MIX,
+ MODE_MASK,
+ };
+
+private:
+ RID canvas_light;
+ bool enabled;
+ bool shadow;
+ Color color;
+ Color shadow_color;
+ float height;
+ float _scale;
+ float energy;
+ int z_min;
+ int z_max;
+ int layer_min;
+ int layer_max;
+ int item_mask;
+ int item_shadow_mask;
+ int shadow_buffer_size;
+ float shadow_esm_multiplier;
+ Mode mode;
+ Ref<Texture> texture;
+ Vector2 texture_offset;
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+
+ virtual void edit_set_pivot(const Point2& p_pivot);
+ virtual Point2 edit_get_pivot() const;
+ virtual bool edit_has_pivot() const;
+
+ void set_enabled( bool p_enabled);
+ bool is_enabled() const;
+
+ void set_texture( const Ref<Texture>& p_texture);
+ Ref<Texture> get_texture() const;
+
+ void set_texture_offset( const Vector2& p_offset);
+ Vector2 get_texture_offset() const;
+
+ void set_color( const Color& p_color);
+ Color get_color() const;
+
+ void set_height( float p_height);
+ float get_height() const;
+
+ void set_energy( float p_energy);
+ float get_energy() const;
+
+ void set_texture_scale( float p_scale);
+ float get_texture_scale() const;
+
+ void set_z_range_min( int p_min_z);
+ int get_z_range_min() const;
+
+ void set_z_range_max( int p_max_z);
+ int get_z_range_max() const;
+
+ void set_layer_range_min( int p_min_layer);
+ int get_layer_range_min() const;
+
+ void set_layer_range_max( int p_max_layer);
+ int get_layer_range_max() const;
+
+ void set_item_mask( int p_mask);
+ int get_item_mask() const;
+
+ void set_item_shadow_mask( int p_mask);
+ int get_item_shadow_mask() const;
+
+ void set_mode( Mode p_mode );
+ Mode get_mode() const;
+
+ void set_shadow_enabled( bool p_enabled);
+ bool is_shadow_enabled() const;
+
+ void set_shadow_buffer_size( int p_size );
+ int get_shadow_buffer_size() const;
+
+ 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();
+ ~Light2D();
+};
+
+VARIANT_ENUM_CAST(Light2D::Mode);
+
+#endif // LIGHT_2D_H
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
new file mode 100644
index 0000000000..6ebd499f71
--- /dev/null
+++ b/scene/2d/light_occluder_2d.cpp
@@ -0,0 +1,202 @@
+#include "light_occluder_2d.h"
+
+
+void OccluderPolygon2D::set_polygon(const DVector<Vector2>& p_polygon) {
+
+ polygon=p_polygon;
+ VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,p_polygon,closed);
+ emit_changed();
+}
+
+DVector<Vector2> OccluderPolygon2D::get_polygon() const{
+
+ return polygon;
+}
+
+void OccluderPolygon2D::set_closed(bool p_closed) {
+
+ if (closed==p_closed)
+ return;
+ closed=p_closed;
+ if (polygon.size())
+ VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,polygon,closed);
+ emit_changed();
+}
+
+bool OccluderPolygon2D::is_closed() const{
+
+ return closed;
+}
+
+void OccluderPolygon2D::set_cull_mode(CullMode p_mode){
+
+ cull=p_mode;
+ VS::get_singleton()->canvas_occluder_polygon_set_cull_mode(occ_polygon,VS::CanvasOccluderPolygonCullMode(p_mode));
+}
+
+OccluderPolygon2D::CullMode OccluderPolygon2D::get_cull_mode() const{
+
+ return cull;
+}
+
+
+RID OccluderPolygon2D::get_rid() const {
+
+ return occ_polygon;
+}
+
+void OccluderPolygon2D::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method(_MD("set_closed","closed"),&OccluderPolygon2D::set_closed);
+ ObjectTypeDB::bind_method(_MD("is_closed"),&OccluderPolygon2D::is_closed);
+
+ ObjectTypeDB::bind_method(_MD("set_cull_mode","cull_mode"),&OccluderPolygon2D::set_cull_mode);
+ ObjectTypeDB::bind_method(_MD("get_cull_mode"),&OccluderPolygon2D::get_cull_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&OccluderPolygon2D::set_polygon);
+ ObjectTypeDB::bind_method(_MD("get_polygon"),&OccluderPolygon2D::get_polygon);
+
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"closed"),_SCS("set_closed"),_SCS("is_closed"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mode",PROPERTY_HINT_ENUM,"Disabled,ClockWise,CounterClockWise"),_SCS("set_cull_mode"),_SCS("get_cull_mode"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon"));
+
+ BIND_CONSTANT(CULL_DISABLED);
+ BIND_CONSTANT(CULL_CLOCKWISE);
+ BIND_CONSTANT(CULL_COUNTER_CLOCKWISE);
+}
+
+
+OccluderPolygon2D::OccluderPolygon2D() {
+
+ occ_polygon=VS::get_singleton()->canvas_occluder_polygon_create();
+ closed=true;
+ cull=CULL_DISABLED;
+}
+
+OccluderPolygon2D::~OccluderPolygon2D() {
+
+ VS::get_singleton()->free(occ_polygon);
+}
+
+#ifdef DEBUG_ENABLED
+void LightOccluder2D::_poly_changed() {
+
+ update();
+}
+#endif
+
+
+void LightOccluder2D::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_CANVAS) {
+
+ VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,get_canvas());
+ VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform());
+
+ }
+ if (p_what==NOTIFICATION_TRANSFORM_CHANGED) {
+
+ VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform());
+ }
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ if (get_tree()->is_editor_hint()) {
+
+ if (occluder_polygon.is_valid()) {
+
+ DVector<Vector2> poly = occluder_polygon->get_polygon();
+
+ if (poly.size()) {
+ if (occluder_polygon->is_closed()) {
+ Vector<Color> color;
+ color.push_back(Color(0,0,0,0.6));
+ draw_polygon(Variant(poly),color);
+ } else {
+
+ int ps=poly.size();
+ DVector<Vector2>::Read r = poly.read();
+ for(int i=0;i<ps-1;i++) {
+
+ draw_line(r[i],r[i+1],Color(0,0,0,0.6),3);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ if (p_what==NOTIFICATION_EXIT_CANVAS) {
+
+ VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,RID());
+ }
+
+
+}
+
+void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon) {
+
+#ifdef DEBUG_ENABLED
+ if (occluder_polygon.is_valid())
+ occluder_polygon->disconnect("changed",this,"_poly_changed");
+#endif
+ occluder_polygon=p_polygon;
+
+ if (occluder_polygon.is_valid())
+ VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,occluder_polygon->get_rid());
+ else
+ VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,RID());
+
+#ifdef DEBUG_ENABLED
+ if (occluder_polygon.is_valid())
+ occluder_polygon->connect("changed",this,"_poly_changed");
+ update();
+#endif
+
+}
+
+Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const {
+
+ return occluder_polygon;
+}
+
+void LightOccluder2D::set_occluder_light_mask(int p_mask) {
+
+ mask=p_mask;
+ VS::get_singleton()->canvas_light_occluder_set_light_mask(occluder,mask);
+}
+
+int LightOccluder2D::get_occluder_light_mask() const{
+
+ return mask;
+}
+
+void LightOccluder2D::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_occluder_polygon","polygon:OccluderPolygon2D"),&LightOccluder2D::set_occluder_polygon);
+ ObjectTypeDB::bind_method(_MD("get_occluder_polygon:OccluderPolygon2D"),&LightOccluder2D::get_occluder_polygon);
+
+ ObjectTypeDB::bind_method(_MD("set_occluder_light_mask","mask"),&LightOccluder2D::set_occluder_light_mask);
+ ObjectTypeDB::bind_method(_MD("get_occluder_light_mask"),&LightOccluder2D::get_occluder_light_mask);
+
+#ifdef DEBUG_ENABLED
+ ObjectTypeDB::bind_method("_poly_changed",&LightOccluder2D::_poly_changed);
+#endif
+
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"occluder",PROPERTY_HINT_RESOURCE_TYPE,"OccluderPolygon2D"),_SCS("set_occluder_polygon"),_SCS("get_occluder_polygon"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"light_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_occluder_light_mask"),_SCS("get_occluder_light_mask"));
+}
+
+LightOccluder2D::LightOccluder2D() {
+
+ occluder=VS::get_singleton()->canvas_light_occluder_create();
+ mask=1;
+}
+
+LightOccluder2D::~LightOccluder2D() {
+
+ VS::get_singleton()->free(occluder);
+}
+
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
new file mode 100644
index 0000000000..0343e3697e
--- /dev/null
+++ b/scene/2d/light_occluder_2d.h
@@ -0,0 +1,73 @@
+#ifndef LIGHTOCCLUDER2D_H
+#define LIGHTOCCLUDER2D_H
+
+#include "scene/2d/node_2d.h"
+
+class OccluderPolygon2D : public Resource {
+
+ OBJ_TYPE(OccluderPolygon2D,Resource);
+public:
+
+ enum CullMode {
+ CULL_DISABLED,
+ CULL_CLOCKWISE,
+ CULL_COUNTER_CLOCKWISE
+ };
+private:
+
+
+ RID occ_polygon;
+ DVector<Vector2> polygon;
+ bool closed;
+ CullMode cull;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ void set_polygon(const DVector<Vector2>& p_polygon);
+ DVector<Vector2> get_polygon() const;
+
+ void set_closed(bool p_closed);
+ bool is_closed() const;
+
+ void set_cull_mode(CullMode p_mode);
+ CullMode get_cull_mode() const;
+
+ virtual RID get_rid() const;
+ OccluderPolygon2D();
+ ~OccluderPolygon2D();
+
+};
+
+VARIANT_ENUM_CAST(OccluderPolygon2D::CullMode);
+
+class LightOccluder2D : public Node2D {
+ OBJ_TYPE(LightOccluder2D,Node2D);
+
+ RID occluder;
+ bool enabled;
+ int mask;
+ Ref<OccluderPolygon2D> occluder_polygon;
+
+#ifdef DEBUG_ENABLED
+ void _poly_changed();
+#endif
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon);
+ Ref<OccluderPolygon2D> get_occluder_polygon() const;
+
+ void set_occluder_light_mask(int p_mask);
+ int get_occluder_light_mask() const;
+
+ LightOccluder2D();
+ ~LightOccluder2D();
+};
+
+#endif // LIGHTOCCLUDER2D_H
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp
new file mode 100644
index 0000000000..b7d51730a0
--- /dev/null
+++ b/scene/2d/navigation2d.cpp
@@ -0,0 +1,770 @@
+#include "navigation2d.h"
+
+#define USE_ENTRY_POINT
+
+void Navigation2D::_navpoly_link(int p_id) {
+
+ ERR_FAIL_COND(!navpoly_map.has(p_id));
+ NavMesh &nm=navpoly_map[p_id];
+ ERR_FAIL_COND(nm.linked);
+
+ DVector<Vector2> vertices=nm.navpoly->get_vertices();
+ int len = vertices.size();
+ if (len==0)
+ return;
+
+ DVector<Vector2>::Read r=vertices.read();
+
+ for(int i=0;i<nm.navpoly->get_polygon_count();i++) {
+
+ //build
+
+ List<Polygon>::Element *P=nm.polygons.push_back(Polygon());
+ Polygon &p=P->get();
+ p.owner=&nm;
+
+ Vector<int> poly = nm.navpoly->get_polygon(i);
+ int plen=poly.size();
+ const int *indices=poly.ptr();
+ bool valid=true;
+ p.edges.resize(plen);
+
+ Vector2 center;
+ float sum=0;
+
+ for(int j=0;j<plen;j++) {
+
+ int idx = indices[j];
+ if (idx<0 || idx>=len) {
+ valid=false;
+ break;
+ }
+
+ Polygon::Edge e;
+ Vector2 ep=nm.xform.xform(r[idx]);
+ center+=ep;
+ e.point=_get_point(ep);
+ p.edges[j]=e;
+
+ int idxn = indices[(j+1)%plen];
+ if (idxn<0 || idxn>=len) {
+ valid=false;
+ break;
+ }
+
+ Vector2 epn = nm.xform.xform(r[idxn]);
+
+ sum+=(epn.x-ep.x)*(epn.y+ep.y);
+
+
+ }
+
+ p.clockwise=sum>0;
+
+ if (!valid) {
+ nm.polygons.pop_back();
+ ERR_CONTINUE(!valid);
+ continue;
+ }
+
+ p.center=center/plen;
+
+ //connect
+
+ for(int j=0;j<plen;j++) {
+
+ int next = (j+1)%plen;
+ EdgeKey ek(p.edges[j].point,p.edges[next].point);
+
+ Map<EdgeKey,Connection>::Element *C=connections.find(ek);
+ if (!C) {
+
+ Connection c;
+ c.A=&p;
+ c.A_edge=j;
+ c.B=NULL;
+ c.B_edge=-1;
+ connections[ek]=c;
+ } else {
+
+ if (C->get().B!=NULL) {
+ ConnectionPending pending;
+ pending.polygon=&p;
+ pending.edge=j;
+ p.edges[j].P=C->get().pending.push_back(pending);
+ continue;
+ //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
+ }
+
+ C->get().B=&p;
+ C->get().B_edge=j;
+ C->get().A->edges[C->get().A_edge].C=&p;
+ C->get().A->edges[C->get().A_edge].C_edge=j;;
+ p.edges[j].C=C->get().A;
+ p.edges[j].C_edge=C->get().A_edge;
+ //connection successful.
+ }
+ }
+ }
+
+ nm.linked=true;
+
+}
+
+
+void Navigation2D::_navpoly_unlink(int p_id) {
+
+ ERR_FAIL_COND(!navpoly_map.has(p_id));
+ NavMesh &nm=navpoly_map[p_id];
+ ERR_FAIL_COND(!nm.linked);
+
+ //print_line("UNLINK");
+
+ for (List<Polygon>::Element *E=nm.polygons.front();E;E=E->next()) {
+
+
+ Polygon &p=E->get();
+
+ int ec = p.edges.size();
+ Polygon::Edge *edges=p.edges.ptr();
+
+ for(int i=0;i<ec;i++) {
+ int next = (i+1)%ec;
+
+ EdgeKey ek(edges[i].point,edges[next].point);
+ Map<EdgeKey,Connection>::Element *C=connections.find(ek);
+ ERR_CONTINUE(!C);
+
+ if (edges[i].P) {
+ C->get().pending.erase(edges[i].P);
+ edges[i].P=NULL;
+
+ } else if (C->get().B) {
+ //disconnect
+
+ C->get().B->edges[C->get().B_edge].C=NULL;
+ C->get().B->edges[C->get().B_edge].C_edge=-1;
+ C->get().A->edges[C->get().A_edge].C=NULL;
+ C->get().A->edges[C->get().A_edge].C_edge=-1;
+
+ if (C->get().A==&E->get()) {
+
+ C->get().A=C->get().B;
+ C->get().A_edge=C->get().B_edge;
+ }
+ C->get().B=NULL;
+ C->get().B_edge=-1;
+
+ if (C->get().pending.size()) {
+ //reconnect if something is pending
+ ConnectionPending cp = C->get().pending.front()->get();
+ C->get().pending.pop_front();
+
+ C->get().B=cp.polygon;
+ C->get().B_edge=cp.edge;
+ C->get().A->edges[C->get().A_edge].C=cp.polygon;
+ C->get().A->edges[C->get().A_edge].C_edge=cp.edge;
+ cp.polygon->edges[cp.edge].C=C->get().A;
+ cp.polygon->edges[cp.edge].C_edge=C->get().A_edge;
+ cp.polygon->edges[cp.edge].P=NULL;
+ }
+
+ } else {
+ connections.erase(C);
+ //erase
+ }
+ }
+ }
+
+ nm.polygons.clear();
+
+ nm.linked=false;
+
+
+}
+
+
+int Navigation2D::navpoly_create(const Ref<NavigationPolygon>& p_mesh, const Matrix32& p_xform, Object *p_owner) {
+
+ int id = last_id++;
+ NavMesh nm;
+ nm.linked=false;
+ nm.navpoly=p_mesh;
+ nm.xform=p_xform;
+ nm.owner=p_owner;
+ navpoly_map[id]=nm;
+
+ _navpoly_link(id);
+
+ return id;
+}
+
+void Navigation2D::navpoly_set_transform(int p_id, const Matrix32& p_xform){
+
+ ERR_FAIL_COND(!navpoly_map.has(p_id));
+ NavMesh &nm=navpoly_map[p_id];
+ if (nm.xform==p_xform)
+ return; //bleh
+ _navpoly_unlink(p_id);
+ nm.xform=p_xform;
+ _navpoly_link(p_id);
+
+
+
+}
+void Navigation2D::navpoly_remove(int p_id){
+
+ ERR_FAIL_COND(!navpoly_map.has(p_id));
+ _navpoly_unlink(p_id);
+ navpoly_map.erase(p_id);
+
+}
+#if 0
+void Navigation2D::_clip_path(Vector<Vector2>& path, Polygon *from_poly, const Vector2& p_to_point, Polygon* p_to_poly) {
+
+ Vector2 from = path[path.size()-1];
+
+ if (from.distance_to(p_to_point)<CMP_EPSILON)
+ return;
+ Plane cut_plane;
+ cut_plane.normal = (from-p_to_point).cross(up);
+ if (cut_plane.normal==Vector2())
+ return;
+ cut_plane.normal.normalize();
+ cut_plane.d = cut_plane.normal.dot(from);
+
+
+ while(from_poly!=p_to_poly) {
+
+ int pe = from_poly->prev_edge;
+ Vector2 a = _get_vertex(from_poly->edges[pe].point);
+ Vector2 b = _get_vertex(from_poly->edges[(pe+1)%from_poly->edges.size()].point);
+
+ from_poly=from_poly->edges[pe].C;
+ ERR_FAIL_COND(!from_poly);
+
+ if (a.distance_to(b)>CMP_EPSILON) {
+
+ Vector2 inters;
+ if (cut_plane.intersects_segment(a,b,&inters)) {
+ if (inters.distance_to(p_to_point)>CMP_EPSILON && inters.distance_to(path[path.size()-1])>CMP_EPSILON) {
+ path.push_back(inters);
+ }
+ }
+ }
+ }
+}
+#endif
+
+Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vector2& p_end, bool p_optimize) {
+
+
+ Polygon *begin_poly=NULL;
+ Polygon *end_poly=NULL;
+ Vector2 begin_point;
+ Vector2 end_point;
+ float begin_d=1e20;
+ float end_d=1e20;
+
+ //look for point inside triangle
+
+ for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+
+ Polygon &p=F->get();
+ if (begin_d || end_d) {
+ for(int i=2;i<p.edges.size();i++) {
+
+ if (begin_d>0) {
+
+ if (Geometry::is_point_in_triangle(p_start,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) {
+
+ begin_poly=&p;
+ begin_point=p_start;
+ begin_d=0;
+ if (end_d==0)
+ break;
+
+ }
+ }
+
+ if (end_d>0) {
+
+ if (Geometry::is_point_in_triangle(p_end,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) {
+
+ end_poly=&p;
+ end_point=p_end;
+ end_d=0;
+ if (begin_d==0)
+ break;
+ }
+ }
+
+ }
+ }
+
+ p.prev_edge=-1;
+ }
+ }
+
+ //start or end not inside triangle.. look for closest segment :|
+ if (begin_d || end_d) {
+ for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ int es = p.edges.size();
+ for(int i=0;i<es;i++) {
+
+ Vector2 edge[2]={
+ _get_vertex(p.edges[i].point),
+ _get_vertex(p.edges[(i+1)%es].point)
+ };
+
+
+ if (begin_d>0) {
+ Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_start,edge);
+ float d = spoint.distance_to(p_start);
+ if (d<begin_d) {
+ begin_poly=&p;
+ begin_point=spoint;
+ begin_d=d;
+ }
+ }
+
+ if (end_d>0) {
+ Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_end,edge);
+ float d = spoint.distance_to(p_end);
+ if (d<end_d) {
+ end_poly=&p;
+ end_point=spoint;
+ end_d=d;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!begin_poly || !end_poly) {
+
+ return Vector<Vector2>(); //no path
+ }
+
+ if (begin_poly==end_poly) {
+
+ Vector<Vector2> path;
+ path.resize(2);
+ path[0]=begin_point;
+ path[1]=end_point;
+ //print_line("Direct Path");
+ return path;
+ }
+
+
+ bool found_route=false;
+
+ List<Polygon*> open_list;
+
+ begin_poly->entry=p_start;
+
+ for(int i=0;i<begin_poly->edges.size();i++) {
+
+ if (begin_poly->edges[i].C) {
+
+ begin_poly->edges[i].C->prev_edge=begin_poly->edges[i].C_edge;
+#ifdef USE_ENTRY_POINT
+ Vector2 edge[2]={
+ _get_vertex(begin_poly->edges[i].point),
+ _get_vertex(begin_poly->edges[(i+1)%begin_poly->edges.size()].point)
+ };
+
+ Vector2 entry = Geometry::get_closest_point_to_segment_2d(begin_poly->entry,edge);
+ begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry);
+ begin_poly->edges[i].C->entry=entry;
+#else
+ begin_poly->edges[i].C->distance=begin_poly->center.distance_to(begin_poly->edges[i].C->center);
+#endif
+ open_list.push_back(begin_poly->edges[i].C);
+
+ if (begin_poly->edges[i].C==end_poly) {
+ found_route=true;
+ }
+ }
+ }
+
+
+ while(!found_route) {
+
+ if (open_list.size()==0) {
+ // print_line("NOU OPEN LIST");
+ break;
+ }
+ //check open list
+
+ List<Polygon*>::Element *least_cost_poly=NULL;
+ float least_cost=1e30;
+
+ //this could be faster (cache previous results)
+ for (List<Polygon*>::Element *E=open_list.front();E;E=E->next()) {
+
+ Polygon *p=E->get();
+
+
+ float cost=p->distance;
+ cost+=p->center.distance_to(end_point);
+
+ if (cost<least_cost) {
+
+ least_cost_poly=E;
+ least_cost=cost;
+ }
+ }
+
+
+ Polygon *p=least_cost_poly->get();
+ //open the neighbours for search
+ int es = p->edges.size();
+
+ for(int i=0;i<es;i++) {
+
+
+ Polygon::Edge &e=p->edges[i];
+
+ if (!e.C)
+ continue;
+
+#ifdef USE_ENTRY_POINT
+ Vector2 edge[2]={
+ _get_vertex(p->edges[i].point),
+ _get_vertex(p->edges[(i+1)%es].point)
+ };
+
+ Vector2 edge_entry = Geometry::get_closest_point_to_segment_2d(p->entry,edge);
+ float distance = p->entry.distance_to(edge_entry) + p->distance;
+
+#else
+
+ float distance = p->center.distance_to(e.C->center) + p->distance;
+
+#endif
+
+
+ if (e.C->prev_edge!=-1) {
+ //oh this was visited already, can we win the cost?
+
+ if (e.C->distance>distance) {
+
+ e.C->prev_edge=e.C_edge;
+ e.C->distance=distance;
+#ifdef USE_ENTRY_POINT
+ e.C->entry=edge_entry;
+#endif
+ }
+ } else {
+ //add to open neighbours
+
+ e.C->prev_edge=e.C_edge;
+ e.C->distance=distance;
+#ifdef USE_ENTRY_POINT
+ e.C->entry=edge_entry;
+#endif
+
+ open_list.push_back(e.C);
+
+ if (e.C==end_poly) {
+ //oh my reached end! stop algorithm
+ found_route=true;
+ break;
+
+ }
+
+ }
+ }
+
+ if (found_route)
+ break;
+
+ open_list.erase(least_cost_poly);
+ }
+
+ if (found_route) {
+
+ Vector<Vector2> path;
+
+ if (p_optimize) {
+ //string pulling
+
+ Polygon *apex_poly=end_poly;
+ Vector2 apex_point=end_point;
+ Vector2 portal_left=apex_point;
+ Vector2 portal_right=apex_point;
+ Polygon *left_poly=end_poly;
+ Polygon *right_poly=end_poly;
+ Polygon *p=end_poly;
+ path.push_back(end_point);
+
+ while(p) {
+
+ Vector2 left;
+ Vector2 right;
+
+//#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) )
+#define CLOCK_TANGENT(m_a,m_b,m_c) ((((m_a).x - (m_c).x) * ((m_b).y - (m_c).y) - ((m_b).x - (m_c).x) * ((m_a).y - (m_c).y)))
+
+ if (p==begin_poly) {
+ left=begin_point;
+ right=begin_point;
+ } else {
+ int prev = p->prev_edge;
+ int prev_n = (p->prev_edge+1)%p->edges.size();
+ left = _get_vertex(p->edges[prev].point);
+ right = _get_vertex(p->edges[prev_n].point);
+
+ if (p->clockwise) {
+ SWAP(left,right);
+ }
+ /*if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5) < 0){
+ SWAP(left,right);
+ }*/
+ }
+
+ bool skip=false;
+
+ /* 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("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));
+*/
+
+ 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;
+ } else {
+
+ //_clip_path(path,apex_poly,portal_right,right_poly);
+
+ apex_point=portal_right;
+ p=right_poly;
+ left_poly=p;
+ apex_poly=p;
+ portal_left=apex_point;
+ portal_right=apex_point;
+ if (path[path.size()-1].distance_to(apex_point)>CMP_EPSILON)
+ path.push_back(apex_point);
+ skip=true;
+ //print_line("addpoint left");
+ }
+ }
+
+ if (!skip && CLOCK_TANGENT(apex_point,portal_right,right) <= 0){
+ //process
+ if (portal_right.distance_squared_to(apex_point)<CMP_EPSILON || CLOCK_TANGENT(apex_point,right,portal_left) < 0) {
+ right_poly=p;
+ portal_right=right;
+ } else {
+
+ //_clip_path(path,apex_poly,portal_left,left_poly);
+
+ apex_point=portal_left;
+ p=left_poly;
+ right_poly=p;
+ apex_poly=p;
+ portal_right=apex_point;
+ portal_left=apex_point;
+ if (path[path.size()-1].distance_to(apex_point)>CMP_EPSILON)
+ path.push_back(apex_point);
+ //print_line("addpoint right");
+
+ }
+ }
+
+ if (p!=begin_poly)
+ p=p->edges[p->prev_edge].C;
+ else
+ p=NULL;
+
+ }
+
+ if (path[path.size()-1].distance_to(begin_point)>CMP_EPSILON)
+ path.push_back(begin_point);
+
+ path.invert();
+
+
+
+
+ } else {
+ //midpoints
+ Polygon *p=end_poly;
+
+ path.push_back(end_point);
+ 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;
+ path.push_back(point);
+ p = p->edges[prev].C;
+ if (p==begin_poly)
+ break;
+ }
+
+ path.push_back(begin_point);
+
+
+ path.invert();;
+ }
+
+ return path;
+ }
+
+
+ return Vector<Vector2>();
+
+}
+
+
+Vector2 Navigation2D::get_closest_point(const Vector2& p_point) {
+
+ Vector2 closest_point=Vector2();
+ float closest_point_d=1e20;
+
+ for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ if (Geometry::is_point_in_triangle(p_point,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) {
+
+ return p_point; //inside triangle, nothing else to discuss
+ }
+
+ }
+ }
+ }
+
+ for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ int es = p.edges.size();
+ for(int i=0;i<es;i++) {
+
+ Vector2 edge[2]={
+ _get_vertex(p.edges[i].point),
+ _get_vertex(p.edges[(i+1)%es].point)
+ };
+
+
+ Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_point,edge);
+ float d = spoint.distance_squared_to(p_point);
+ if (d<closest_point_d) {
+
+ closest_point=spoint;
+ closest_point_d=d;
+ }
+ }
+ }
+ }
+
+ return closest_point;
+
+}
+
+Object* Navigation2D::get_closest_point_owner(const Vector2& p_point) {
+
+ Object *owner=NULL;
+ Vector2 closest_point=Vector2();
+ float closest_point_d=1e20;
+
+ for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ if (Geometry::is_point_in_triangle(p_point,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) {
+
+ E->get().owner;
+ }
+
+ }
+ }
+ }
+
+ for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ int es = p.edges.size();
+ for(int i=0;i<es;i++) {
+
+ Vector2 edge[2]={
+ _get_vertex(p.edges[i].point),
+ _get_vertex(p.edges[(i+1)%es].point)
+ };
+
+
+ Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_point,edge);
+ float d = spoint.distance_squared_to(p_point);
+ if (d<closest_point_d) {
+
+ closest_point=spoint;
+ closest_point_d=d;
+ owner=E->get().owner;
+ }
+ }
+ }
+ }
+
+ return owner;
+
+}
+
+
+void Navigation2D::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("navpoly_create","mesh:NavigationPolygon","xform","owner"),&Navigation2D::navpoly_create,DEFVAL(Variant()));
+ ObjectTypeDB::bind_method(_MD("navpoly_set_transform","id","xform"),&Navigation2D::navpoly_set_transform);
+ ObjectTypeDB::bind_method(_MD("navpoly_remove","id"),&Navigation2D::navpoly_remove);
+
+ ObjectTypeDB::bind_method(_MD("get_simple_path","start","end","optimize"),&Navigation2D::get_simple_path,DEFVAL(true));
+ ObjectTypeDB::bind_method(_MD("get_closest_point","to_point"),&Navigation2D::get_closest_point);
+ ObjectTypeDB::bind_method(_MD("get_closest_point_owner","to_point"),&Navigation2D::get_closest_point_owner);
+
+}
+
+Navigation2D::Navigation2D() {
+
+ ERR_FAIL_COND( sizeof(Point)!=8 );
+ cell_size=1; // one pixel
+ last_id=1;
+
+}
diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation2d.h
new file mode 100644
index 0000000000..231f1e8c63
--- /dev/null
+++ b/scene/2d/navigation2d.h
@@ -0,0 +1,151 @@
+#ifndef NAVIGATION_2D_H
+#define NAVIGATION_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/2d/navigation_polygon.h"
+
+class Navigation2D : public Node2D {
+
+ OBJ_TYPE( Navigation2D, Node2D);
+
+
+ union Point {
+
+ struct {
+ int64_t x:32;
+ int64_t y:32;
+ };
+
+ uint64_t key;
+ bool operator<(const Point& p_key) const { return key < p_key.key; }
+ };
+
+
+ struct EdgeKey {
+
+ Point a;
+ Point b;
+
+ bool operator<(const EdgeKey& p_key) const {
+ return (a.key==p_key.a.key)?(b.key<p_key.b.key):(a.key<p_key.a.key);
+ };
+
+ EdgeKey(const Point& p_a=Point(),const Point& p_b=Point()) {
+ a=p_a;
+ b=p_b;
+ if (a.key > b.key) {
+ SWAP(a,b);
+ }
+ }
+ };
+
+
+ struct NavMesh;
+ struct Polygon;
+
+ struct ConnectionPending {
+
+ Polygon *polygon;
+ int edge;
+ };
+
+ struct Polygon {
+
+ struct Edge {
+ Point point;
+ Polygon *C; //connection
+ int C_edge;
+ List<ConnectionPending>::Element *P;
+ Edge() { C=NULL; C_edge=-1; P=NULL; }
+ };
+
+ Vector<Edge> edges;
+
+ Vector2 center;
+ Vector2 entry;
+
+ float distance;
+ int prev_edge;
+
+ bool clockwise;
+
+ NavMesh *owner;
+ };
+
+
+ struct Connection {
+
+ Polygon *A;
+ int A_edge;
+ Polygon *B;
+ int B_edge;
+
+ List<ConnectionPending> pending;
+
+ Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;}
+ };
+
+ Map<EdgeKey,Connection> connections;
+
+
+ struct NavMesh {
+
+ Object *owner;
+ Matrix32 xform;
+ bool linked;
+ Ref<NavigationPolygon> navpoly;
+ List<Polygon> polygons;
+
+ };
+
+
+
+ _FORCE_INLINE_ Point _get_point(const Vector2& p_pos) const {
+
+ int x = int(Math::floor(p_pos.x/cell_size));
+ int y = int(Math::floor(p_pos.y/cell_size));
+
+ Point p;
+ p.key=0;
+ p.x=x;
+ p.y=y;
+ return p;
+
+ }
+
+ _FORCE_INLINE_ Vector2 _get_vertex(const Point& p_point) const {
+
+ return Vector2(p_point.x,p_point.y)*cell_size;
+ }
+
+
+
+ void _navpoly_link(int p_id);
+ void _navpoly_unlink(int p_id);
+
+ float cell_size;
+ Map<int,NavMesh> navpoly_map;
+ int last_id;
+#if 0
+ void _clip_path(Vector<Vector2>& path,Polygon *from_poly, const Vector2& p_to_point, Polygon* p_to_poly);
+#endif
+protected:
+
+ static void _bind_methods();
+
+public:
+
+ //API should be as dynamic as possible
+ int navpoly_create(const Ref<NavigationPolygon>& p_mesh,const Matrix32& p_xform,Object* p_owner=NULL);
+ void navpoly_set_transform(int p_id, const Matrix32& p_xform);
+ void navpoly_remove(int p_id);
+
+ Vector<Vector2> get_simple_path(const Vector2& p_start, const Vector2& p_end,bool p_optimize=true);
+ Vector2 get_closest_point(const Vector2& p_point);
+ Object* get_closest_point_owner(const Vector2& p_point);
+
+ Navigation2D();
+};
+
+
+#endif // Navigation2D2D_H
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
new file mode 100644
index 0000000000..792f079ab0
--- /dev/null
+++ b/scene/2d/navigation_polygon.cpp
@@ -0,0 +1,450 @@
+#include "navigation_polygon.h"
+#include "navigation2d.h"
+#include "triangulator.h"
+#include "core_string_names.h"
+
+void NavigationPolygon::set_vertices(const DVector<Vector2>& p_vertices) {
+
+ vertices=p_vertices;
+}
+
+DVector<Vector2> NavigationPolygon::get_vertices() const{
+
+ return vertices;
+}
+
+
+void NavigationPolygon::_set_polygons(const Array& p_array) {
+
+ polygons.resize(p_array.size());
+ for(int i=0;i<p_array.size();i++) {
+ polygons[i].indices=p_array[i];
+ }
+}
+
+Array NavigationPolygon::_get_polygons() const {
+
+ Array ret;
+ ret.resize(polygons.size());
+ for(int i=0;i<ret.size();i++) {
+ ret[i]=polygons[i].indices;
+ }
+
+ return ret;
+}
+
+void NavigationPolygon::_set_outlines(const Array& p_array) {
+
+ outlines.resize(p_array.size());
+ for(int i=0;i<p_array.size();i++) {
+ outlines[i]=p_array[i];
+ }
+}
+
+Array NavigationPolygon::_get_outlines() const {
+
+ Array ret;
+ ret.resize(outlines.size());
+ for(int i=0;i<ret.size();i++) {
+ ret[i]=outlines[i];
+ }
+
+ return ret;
+}
+
+
+void NavigationPolygon::add_polygon(const Vector<int>& p_polygon){
+
+ Polygon polygon;
+ polygon.indices=p_polygon;
+ polygons.push_back(polygon);
+
+}
+
+void NavigationPolygon::add_outline_at_index(const DVector<Vector2>& p_outline,int p_index) {
+
+ outlines.insert(p_index,p_outline);
+}
+
+int NavigationPolygon::get_polygon_count() const{
+
+ return polygons.size();
+}
+Vector<int> NavigationPolygon::get_polygon(int p_idx){
+
+ ERR_FAIL_INDEX_V(p_idx,polygons.size(),Vector<int>());
+ return polygons[p_idx].indices;
+}
+void NavigationPolygon::clear_polygons(){
+
+ polygons.clear();
+}
+
+void NavigationPolygon::add_outline(const DVector<Vector2>& p_outline) {
+
+ outlines.push_back(p_outline);
+}
+
+int NavigationPolygon::get_outline_count() const{
+
+ return outlines.size();
+}
+
+void NavigationPolygon::set_outline(int p_idx,const DVector<Vector2>& p_outline) {
+ ERR_FAIL_INDEX(p_idx,outlines.size());
+ outlines[p_idx]=p_outline;
+}
+
+void NavigationPolygon::remove_outline(int p_idx) {
+
+ ERR_FAIL_INDEX(p_idx,outlines.size());
+ outlines.remove(p_idx);
+
+}
+
+DVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx,outlines.size(),DVector<Vector2>());
+ return outlines[p_idx];
+}
+
+void NavigationPolygon::clear_outlines(){
+
+ outlines.clear();;
+}
+void NavigationPolygon::make_polygons_from_outlines(){
+
+ List<TriangulatorPoly> in_poly,out_poly;
+
+ Vector2 outside_point(-1e10,-1e10);
+
+ for(int i=0;i<outlines.size();i++) {
+
+ DVector<Vector2> ol = outlines[i];
+ int olsize = ol.size();
+ if (olsize<3)
+ continue;
+ DVector<Vector2>::Read r=ol.read();
+ for(int j=0;j<olsize;j++) {
+ outside_point.x = MAX( r[j].x, outside_point.x );
+ outside_point.y = MAX( r[j].y, outside_point.y );
+ }
+
+ }
+
+ outside_point+=Vector2(0.7239784,0.819238); //avoid precision issues
+
+
+
+ for(int i=0;i<outlines.size();i++) {
+
+ DVector<Vector2> ol = outlines[i];
+ int olsize = ol.size();
+ if (olsize<3)
+ continue;
+ DVector<Vector2>::Read r=ol.read();
+
+ int interscount=0;
+ //test if this is an outer outline
+ for(int k=0;k<outlines.size();k++) {
+
+ if (i==k)
+ continue; //no self intersect
+
+ DVector<Vector2> ol2 = outlines[k];
+ int olsize2 = ol2.size();
+ if (olsize2<3)
+ continue;
+ DVector<Vector2>::Read r2=ol2.read();
+
+ for(int l=0;l<olsize2;l++) {
+
+ if (Geometry::segment_intersects_segment_2d(r[0],outside_point,r2[l],r2[(l+1)%olsize2],NULL)) {
+ interscount++;
+ }
+ }
+
+ }
+
+ bool outer = (interscount%2)==0;
+
+ TriangulatorPoly tp;
+ tp.Init(olsize);
+ for(int j=0;j<olsize;j++) {
+ tp[j]=r[j];
+ }
+
+ if (outer)
+ tp.SetOrientation(TRIANGULATOR_CCW);
+ else {
+ tp.SetOrientation(TRIANGULATOR_CW);
+ tp.SetHole(true);
+ }
+
+ in_poly.push_back(tp);
+ }
+
+
+ TriangulatorPartition tpart;
+ if (tpart.ConvexPartition_HM(&in_poly,&out_poly)==0) { //failed!
+ print_line("convex partition failed!");
+ return;
+ }
+
+ polygons.clear();
+ vertices.resize(0);
+
+ Map<Vector2,int> points;
+ for(List<TriangulatorPoly>::Element*I = out_poly.front();I;I=I->next()) {
+
+ TriangulatorPoly& tp = I->get();
+
+ struct Polygon p;
+
+ for(int i=0;i<tp.GetNumPoints();i++) {
+
+ Map<Vector2,int>::Element *E=points.find(tp[i]);
+ if (!E) {
+ E=points.insert(tp[i],vertices.size());
+ vertices.push_back(tp[i]);
+ }
+ p.indices.push_back(E->get());
+ }
+
+ polygons.push_back(p);
+ }
+
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+
+void NavigationPolygon::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_vertices","vertices"),&NavigationPolygon::set_vertices);
+ ObjectTypeDB::bind_method(_MD("get_vertices"),&NavigationPolygon::get_vertices);
+
+ ObjectTypeDB::bind_method(_MD("add_polygon","polygon"),&NavigationPolygon::add_polygon);
+ ObjectTypeDB::bind_method(_MD("get_polygon_count"),&NavigationPolygon::get_polygon_count);
+ ObjectTypeDB::bind_method(_MD("get_polygon","idx"),&NavigationPolygon::get_polygon);
+ ObjectTypeDB::bind_method(_MD("clear_polygons"),&NavigationPolygon::clear_polygons);
+
+ ObjectTypeDB::bind_method(_MD("add_outline","outline"),&NavigationPolygon::add_outline);
+ ObjectTypeDB::bind_method(_MD("add_outline_at_index","outline","index"),&NavigationPolygon::add_outline_at_index);
+ ObjectTypeDB::bind_method(_MD("get_outline_count"),&NavigationPolygon::get_outline_count);
+ ObjectTypeDB::bind_method(_MD("set_outline","idx","outline"),&NavigationPolygon::set_outline);
+ ObjectTypeDB::bind_method(_MD("get_outline","idx"),&NavigationPolygon::get_outline);
+ ObjectTypeDB::bind_method(_MD("remove_outline","idx"),&NavigationPolygon::remove_outline);
+ ObjectTypeDB::bind_method(_MD("clear_outlines"),&NavigationPolygon::clear_outlines);
+ ObjectTypeDB::bind_method(_MD("make_polygons_from_outlines"),&NavigationPolygon::make_polygons_from_outlines);
+
+ ObjectTypeDB::bind_method(_MD("_set_polygons","polygons"),&NavigationPolygon::_set_polygons);
+ ObjectTypeDB::bind_method(_MD("_get_polygons"),&NavigationPolygon::_get_polygons);
+
+ ObjectTypeDB::bind_method(_MD("_set_outlines","outlines"),&NavigationPolygon::_set_outlines);
+ ObjectTypeDB::bind_method(_MD("_get_outlines"),&NavigationPolygon::_get_outlines);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3_ARRAY,"vertices",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_vertices"),_SCS("get_vertices"));
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"polygons",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_polygons"),_SCS("_get_polygons"));
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"outlines",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_outlines"),_SCS("_get_outlines"));
+}
+
+NavigationPolygon::NavigationPolygon() {
+
+
+}
+
+void NavigationPolygonInstance::set_enabled(bool p_enabled) {
+
+ if (enabled==p_enabled)
+ return;
+ enabled=p_enabled;
+
+ if (!is_inside_tree())
+ return;
+
+ if (!enabled) {
+
+ if (nav_id!=-1) {
+ navigation->navpoly_remove(nav_id);
+ nav_id=-1;
+ }
+ } else {
+
+ if (navigation) {
+
+ if (navpoly.is_valid()) {
+
+ nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
+ }
+ }
+
+ }
+
+ if (get_tree()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())
+ update();
+
+// update_gizmo();
+}
+
+bool NavigationPolygonInstance::is_enabled() const {
+
+
+ return enabled;
+}
+
+
+/////////////////////////////
+
+
+void NavigationPolygonInstance::_notification(int p_what) {
+
+
+ switch(p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+
+ Node2D *c=this;
+ while(c) {
+
+ navigation=c->cast_to<Navigation2D>();
+ if (navigation) {
+
+ if (enabled && navpoly.is_valid()) {
+
+ nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
+ }
+ break;
+ }
+
+ c=c->get_parent()->cast_to<Node2D>();
+ }
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ if (navigation && nav_id!=-1) {
+ navigation->navpoly_set_transform(nav_id,get_relative_transform(navigation));
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ if (navigation) {
+
+ if (nav_id!=-1) {
+ navigation->navpoly_remove(nav_id);
+ nav_id=-1;
+ }
+ }
+ navigation=NULL;
+ } break;
+ case NOTIFICATION_DRAW: {
+
+ 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();
+ if (vsize<3)
+ return;
+
+
+ Color color;
+ if (enabled) {
+ color=get_tree()->get_debug_navigation_color();
+ } else {
+ color=get_tree()->get_debug_navigation_disabled_color();
+ }
+ Vector<Color> colors;
+ Vector<Vector2> vertices;
+ vertices.resize(vsize);
+ colors.resize(vsize);
+ {
+ DVector<Vector2>::Read vr = verts.read();
+ for(int i=0;i<vsize;i++) {
+ vertices[i]=vr[i];
+ colors[i]=color;
+ }
+ }
+
+ Vector<int> indices;
+
+
+ for(int i=0;i<navpoly->get_polygon_count();i++) {
+ Vector<int> polygon = navpoly->get_polygon(i);
+
+ for(int j=2;j<polygon.size();j++) {
+
+ int kofs[3]={0,j-1,j};
+ for(int k=0;k<3;k++) {
+
+ int idx = polygon[ kofs[k] ];
+ ERR_FAIL_INDEX(idx,vsize);
+ indices.push_back(idx);
+ }
+ }
+ }
+ VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(),indices,vertices,colors);
+
+ }
+ } break;
+
+ }
+}
+
+
+void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolygon>& p_navpoly) {
+
+ if (p_navpoly==navpoly)
+ return;
+
+ if (navigation && nav_id!=-1) {
+ navigation->navpoly_remove(nav_id);
+ nav_id=-1;
+ }
+ if (navpoly.is_valid()) {
+ navpoly->disconnect(CoreStringNames::get_singleton()->changed,this,"_navpoly_changed");
+ }
+ navpoly=p_navpoly;
+
+ if (navpoly.is_valid()) {
+ navpoly->connect(CoreStringNames::get_singleton()->changed,this,"_navpoly_changed");
+ }
+
+ if (navigation && navpoly.is_valid() && enabled) {
+ nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
+ }
+ //update_gizmo();
+ _change_notify("navpoly");
+
+}
+
+Ref<NavigationPolygon> NavigationPolygonInstance::get_navigation_polygon() const{
+
+ return navpoly;
+}
+
+void NavigationPolygonInstance::_navpoly_changed() {
+
+ if (is_inside_tree() && (get_tree()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()))
+ update();
+}
+
+void NavigationPolygonInstance::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_navigation_polygon","navpoly"),&NavigationPolygonInstance::set_navigation_polygon);
+ ObjectTypeDB::bind_method(_MD("get_navigation_polygon"),&NavigationPolygonInstance::get_navigation_polygon);
+
+ ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&NavigationPolygonInstance::set_enabled);
+ ObjectTypeDB::bind_method(_MD("is_enabled"),&NavigationPolygonInstance::is_enabled);
+
+ ObjectTypeDB::bind_method(_MD("_navpoly_changed"),&NavigationPolygonInstance::_navpoly_changed);
+
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"navpoly",PROPERTY_HINT_RESOURCE_TYPE,"NavigationPolygon"),_SCS("set_navigation_polygon"),_SCS("get_navigation_polygon"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
+}
+
+NavigationPolygonInstance::NavigationPolygonInstance() {
+
+ navigation=NULL;
+ nav_id=-1;
+ enabled=true;
+
+}
diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h
new file mode 100644
index 0000000000..01307a170b
--- /dev/null
+++ b/scene/2d/navigation_polygon.h
@@ -0,0 +1,84 @@
+#ifndef NAVIGATION_POLYGON_H
+#define NAVIGATION_POLYGON_H
+
+#include "scene/2d/node_2d.h"
+
+
+class NavigationPolygon : public Resource {
+
+ OBJ_TYPE( NavigationPolygon, Resource );
+
+ DVector<Vector2> vertices;
+ struct Polygon {
+ Vector<int> indices;
+ };
+ Vector<Polygon> polygons;
+ Vector< DVector<Vector2> > outlines;
+
+protected:
+
+ static void _bind_methods();
+
+ void _set_polygons(const Array& p_array);
+ Array _get_polygons() const;
+
+ void _set_outlines(const Array& p_array);
+ Array _get_outlines() const;
+
+public:
+
+
+
+ void set_vertices(const DVector<Vector2>& p_vertices);
+ DVector<Vector2> get_vertices() const;
+
+ void add_polygon(const Vector<int>& p_polygon);
+ int get_polygon_count() const;
+
+ void add_outline(const DVector<Vector2>& p_outline);
+ void add_outline_at_index(const DVector<Vector2>& p_outline,int p_index);
+ void set_outline(int p_idx,const DVector<Vector2>& p_outline);
+ DVector<Vector2> get_outline(int p_idx) const;
+ void remove_outline(int p_idx);
+ int get_outline_count() const;
+
+ void clear_outlines();
+ void make_polygons_from_outlines();
+
+ Vector<int> get_polygon(int p_idx);
+ void clear_polygons();
+
+ NavigationPolygon();
+};
+
+
+class Navigation2D;
+
+class NavigationPolygonInstance : public Node2D {
+
+ OBJ_TYPE(NavigationPolygonInstance,Node2D);
+
+ bool enabled;
+ int nav_id;
+ Navigation2D *navigation;
+ Ref<NavigationPolygon> navpoly;
+
+ void _navpoly_changed();
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
+ void set_navigation_polygon(const Ref<NavigationPolygon>& p_navpoly);
+ Ref<NavigationPolygon> get_navigation_polygon() const;
+
+ NavigationPolygonInstance();
+};
+
+
+#endif // NAVIGATIONPOLYGON_H
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 9c28212529..52b112f090 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -65,7 +65,7 @@ void Node2D::edit_set_state(const Variant& p_state) {
pos = state[0];
angle = state[1];
- scale = state[2];
+ _scale = state[2];
_update_transform();
_change_notify("transform/rot");
_change_notify("transform/scale");
@@ -93,11 +93,11 @@ void Node2D::edit_set_rect(const Rect2& p_edit_rect) {
Point2 new_pos = p_edit_rect.pos + p_edit_rect.size*zero_offset;//p_edit_rect.pos - r.pos;
Matrix32 postxf;
- postxf.set_rotation_and_scale(angle,scale);
+ postxf.set_rotation_and_scale(angle,_scale);
new_pos = postxf.xform(new_pos);
pos+=new_pos;
- scale*=new_scale;
+ _scale*=new_scale;
_update_transform();
_change_notify("transform/scale");
@@ -118,19 +118,19 @@ void Node2D::_update_xform_values() {
pos=_mat.elements[2];
angle=_mat.get_rotation();
- scale=_mat.get_scale();
+ _scale=_mat.get_scale();
_xform_dirty=false;
}
void Node2D::_update_transform() {
Matrix32 mat(angle,pos);
- _mat.set_rotation_and_scale(angle,scale);
+ _mat.set_rotation_and_scale(angle,_scale);
_mat.elements[2]=pos;
VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),_mat);
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
@@ -161,11 +161,11 @@ void Node2D::set_scale(const Size2& p_scale) {
if (_xform_dirty)
((Node2D*)this)->_update_xform_values();
- scale=p_scale;
- if (scale.x==0)
- scale.x=CMP_EPSILON;
- if (scale.y==0)
- scale.y=CMP_EPSILON;
+ _scale=p_scale;
+ if (_scale.x==0)
+ _scale.x=CMP_EPSILON;
+ if (_scale.y==0)
+ _scale.y=CMP_EPSILON;
_update_transform();
_change_notify("transform/scale");
@@ -187,7 +187,7 @@ Size2 Node2D::get_scale() const {
if (_xform_dirty)
((Node2D*)this)->_update_xform_values();
- return scale;
+ return _scale;
}
void Node2D::_set_rotd(float p_angle) {
@@ -224,11 +224,27 @@ Rect2 Node2D::get_item_rect() const {
return Rect2(Point2(-32,-32),Size2(64,64));
}
-void Node2D::rotate(float p_degrees) {
+void Node2D::rotate(float p_radians) {
- set_rot( get_rot() + p_degrees);
+ set_rot( get_rot() + p_radians);
}
+void Node2D::translate(const Vector2& p_amount) {
+
+ set_pos( get_pos() + p_amount );
+}
+
+void Node2D::global_translate(const Vector2& p_amount) {
+
+ set_global_pos( get_global_pos() + p_amount );
+}
+
+void Node2D::scale(const Vector2& p_amount) {
+
+ set_scale( get_scale() * p_amount );
+}
+
+
void Node2D::move_x(float p_delta,bool p_scaled){
Matrix32 t = get_transform();
@@ -253,6 +269,18 @@ Point2 Node2D::get_global_pos() const {
return get_global_transform().get_origin();
}
+void Node2D::set_global_pos(const Point2& p_pos) {
+
+ Matrix32 inv;
+ CanvasItem *pi = get_parent_item();
+ if (pi) {
+ inv = pi->get_global_transform().affine_inverse();
+ set_pos(inv.xform(p_pos));
+ } else {
+ set_pos(p_pos);
+ }
+}
+
void Node2D::set_transform(const Matrix32& p_transform) {
_mat=p_transform;
@@ -260,7 +288,7 @@ void Node2D::set_transform(const Matrix32& p_transform) {
VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),_mat);
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
_notify_transform();
@@ -277,6 +305,58 @@ void Node2D::set_global_transform(const Matrix32& p_transform) {
}
+void Node2D::set_z(int p_z) {
+
+ ERR_FAIL_COND(p_z<VS::CANVAS_ITEM_Z_MIN);
+ ERR_FAIL_COND(p_z>VS::CANVAS_ITEM_Z_MAX);
+ z=p_z;
+ VS::get_singleton()->canvas_item_set_z(get_canvas_item(),z);
+
+}
+
+void Node2D::set_z_as_relative(bool p_enabled) {
+
+ if (z_relative==p_enabled)
+ return;
+ z_relative=p_enabled;
+ VS::get_singleton()->canvas_item_set_z_as_relative_to_parent(get_canvas_item(),p_enabled);
+}
+
+bool Node2D::is_z_relative() const {
+
+ return z_relative;
+}
+
+
+int Node2D::get_z() const{
+
+ return z;
+}
+
+Matrix32 Node2D::get_relative_transform(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();
+}
+
+
+void Node2D::look_at(const Vector2& p_pos) {
+
+ rotate(get_angle_to(p_pos));
+}
+
+float Node2D::get_angle_to(const Vector2& p_pos) const {
+
+ return (get_global_transform().affine_inverse().xform(p_pos)).angle();
+}
+
void Node2D::_bind_methods() {
@@ -292,21 +372,37 @@ void Node2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_rot"),&Node2D::get_rot);
ObjectTypeDB::bind_method(_MD("get_scale"),&Node2D::get_scale);
- ObjectTypeDB::bind_method(_MD("rotate","degrees"),&Node2D::rotate);
+ ObjectTypeDB::bind_method(_MD("rotate","radians"),&Node2D::rotate);
ObjectTypeDB::bind_method(_MD("move_local_x","delta","scaled"),&Node2D::move_x,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("move_local_y","delta","scaled"),&Node2D::move_y,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("translate","offset"),&Node2D::translate);
+ ObjectTypeDB::bind_method(_MD("global_translate","offset"),&Node2D::global_translate);
+ ObjectTypeDB::bind_method(_MD("scale","ratio"),&Node2D::scale);
+ ObjectTypeDB::bind_method(_MD("set_global_pos","pos"),&Node2D::set_global_pos);
ObjectTypeDB::bind_method(_MD("get_global_pos"),&Node2D::get_global_pos);
ObjectTypeDB::bind_method(_MD("set_transform","xform"),&Node2D::set_transform);
ObjectTypeDB::bind_method(_MD("set_global_transform","xform"),&Node2D::set_global_transform);
+ ObjectTypeDB::bind_method(_MD("look_at","point"),&Node2D::look_at);
+ ObjectTypeDB::bind_method(_MD("get_angle_to","point"),&Node2D::get_angle_to);
+
+ ObjectTypeDB::bind_method(_MD("set_z","z"),&Node2D::set_z);
+ ObjectTypeDB::bind_method(_MD("get_z"),&Node2D::get_z);
+
+ 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);
- 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"));
+ ObjectTypeDB::bind_method(_MD("get_relative_transform"),&Node2D::get_relative_transform);
+ 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"));
}
@@ -316,8 +412,10 @@ Node2D::Node2D() {
angle=0;
- scale=Vector2(1,1);
+ _scale=Vector2(1,1);
_xform_dirty=false;
+ z=0;
+ z_relative=true;
}
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 8e1f22c235..8efce33cda 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -37,7 +37,9 @@ class Node2D : public CanvasItem {
Point2 pos;
float angle;
- Size2 scale;
+ Size2 _scale;
+ int z;
+ bool z_relative;
Matrix32 _mat;
@@ -70,9 +72,12 @@ public:
void set_rot(float p_angle);
void set_scale(const Size2& p_scale);
- void rotate(float p_degrees);
+ void rotate(float p_radians);
void move_x(float p_delta,bool p_scaled=false);
void move_y(float p_delta,bool p_scaled=false);
+ void translate(const Vector2& p_amount);
+ void global_translate(const Vector2& p_amount);
+ void scale(const Vector2& p_amount);
Point2 get_pos() const;
float get_rot() const;
@@ -83,6 +88,19 @@ public:
void set_transform(const Matrix32& p_transform);
void set_global_transform(const Matrix32& p_transform);
+ void set_global_pos(const Point2& p_pos);
+
+ void set_z(int p_z);
+ int get_z() const;
+
+ void look_at(const Vector2& p_pos);
+ float get_angle_to(const Vector2& p_pos) const;
+
+ void set_z_as_relative(bool p_enabled);
+ bool is_z_relative() const;
+
+ Matrix32 get_relative_transform(const Node *p_parent) const;
+
Matrix32 get_transform() const;
diff --git a/scene/2d/node_2d_singleton.cpp b/scene/2d/node_2d_singleton.cpp
index 58e078101d..361edf7587 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/node_2d_singleton.h b/scene/2d/node_2d_singleton.h
index b1d1e65b8b..6a21db2221 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index 55607bd4eb..8bb4eb55ba 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,13 +36,13 @@ void ParallaxBackground::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
group_name = "__cameras_"+itos(get_viewport().get_id());
add_to_group(group_name);
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
remove_from_group(group_name);
} break;
@@ -78,7 +78,7 @@ void ParallaxBackground::set_scroll_offset(const Point2& p_ofs) {
void ParallaxBackground::_update_scroll() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
Vector2 ofs = base_offset+offset*base_scale;
@@ -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"), &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 ed6747f01c..8dede07a16 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 2cda51dccb..70612d7c9a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -74,7 +74,7 @@ void ParallaxLayer::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
orig_offset=get_pos();
orig_scale=get_scale();
@@ -85,9 +85,9 @@ void ParallaxLayer::_notification(int p_what) {
void ParallaxLayer::set_base_offset_and_scale(const Point2& p_offset,float p_scale) {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
- if (get_scene()->is_editor_hint())
+ if (get_tree()->is_editor_hint())
return;
Point2 new_ofs = ((orig_offset+p_offset)*motion_scale)*p_scale;
diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h
index fccd8509b1..8fe2846897 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index 3d7aa58c6d..8f805ceba2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,14 +34,14 @@ void ParticleAttractor2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
_update_owner();
} break;
case NOTIFICATION_DRAW: {
- if (!get_scene()->is_editor_hint())
+ if (!get_tree()->is_editor_hint())
return;
Vector2 pv;
@@ -58,7 +58,7 @@ void ParticleAttractor2D::_notification(int p_what) {
}
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (owner) {
_set_owner(NULL);
}
@@ -76,7 +76,7 @@ void ParticleAttractor2D::_owner_exited() {
void ParticleAttractor2D::_update_owner() {
- if (!is_inside_scene() || !has_node(path)) {
+ if (!is_inside_tree() || !has_node(path)) {
_set_owner(NULL);
return;
}
@@ -98,7 +98,7 @@ void ParticleAttractor2D::_set_owner(Particles2D* p_owner) {
return;
if (owner) {
- owner->disconnect("exit_scene",this,"_owner_exited");
+ owner->disconnect("exit_tree",this,"_owner_exited");
owner->attractors.erase(this);
owner=NULL;
}
@@ -106,7 +106,7 @@ void ParticleAttractor2D::_set_owner(Particles2D* p_owner) {
if (owner) {
- owner->connect("exit_scene",this,"_owner_exited",varray(),CONNECT_ONESHOT);
+ owner->connect("exit_tree",this,"_owner_exited",varray(),CONNECT_ONESHOT);
owner->attractors.insert(this);
}
}
@@ -250,6 +250,7 @@ void Particles2D::_process_particles(float p_delta) {
if (time_to_live < 0) {
emitting = false;
+ _change_notify("config/emitting");
};
};
@@ -352,9 +353,11 @@ void Particles2D::_process_particles(float p_delta) {
p.velocity*=param[PARAM_LINEAR_VELOCITY]+param[PARAM_LINEAR_VELOCITY]*_rand_from_seed(&rand_seed)*randomness[PARAM_LINEAR_VELOCITY];
p.velocity+=initial_velocity;
p.active=true;
- p.rot=0;
+ p.rot=Math::deg2rad(param[PARAM_INITIAL_ANGLE]+param[PARAM_INITIAL_ANGLE]*randomness[PARAM_INITIAL_ANGLE]*_rand_from_seed(&rand_seed));
active_count++;
+ p.frame=Math::fmod(param[PARAM_ANIM_INITIAL_POS]+randomness[PARAM_ANIM_INITIAL_POS]*_rand_from_seed(&rand_seed),1.0);
+
} else {
@@ -426,6 +429,8 @@ void Particles2D::_process_particles(float p_delta) {
p.pos+=p.velocity*frame_time;
p.rot+=Math::lerp(param[PARAM_SPIN_VELOCITY],param[PARAM_SPIN_VELOCITY]*randomness[PARAM_SPIN_VELOCITY]*_rand_from_seed(&rand_seed),randomness[PARAM_SPIN_VELOCITY])*frame_time;
+ float anim_spd=param[PARAM_ANIM_SPEED_SCALE]+param[PARAM_ANIM_SPEED_SCALE]*randomness[PARAM_ANIM_SPEED_SCALE]*_rand_from_seed(&rand_seed);
+ p.frame=Math::fposmod(p.frame+(frame_time/lifetime)*anim_spd,1.0);
active_count++;
@@ -457,7 +462,7 @@ void Particles2D::_notification(int p_what) {
_process_particles( get_process_delta_time() );
} break;
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
float ppt=preprocess;
while(ppt>0) {
@@ -474,9 +479,13 @@ void Particles2D::_notification(int p_what) {
RID ci=get_canvas_item();
Size2 size(1,1);
Point2 center;
+ int total_frames=1;
if (!texture.is_null()) {
size=texture->get_size();
+ size.x/=h_frames;
+ size.y/=v_frames;
+ total_frames=h_frames*v_frames;
}
@@ -484,7 +493,7 @@ void Particles2D::_notification(int p_what) {
Particle *pdata=&particles[0];
int particle_count=particles.size();
- Rect2 r(Point2(),size);
+
RID texrid;
if (texture.is_valid())
@@ -494,20 +503,13 @@ void Particles2D::_notification(int p_what) {
if (!local_space)
invxform=get_global_transform().affine_inverse();
- int col_count=0;
- float last=-1;
- ColorPhase cphase[MAX_COLOR_PHASES];
-
- for(int i=0;i<color_phase_count;i++) {
-
- if (color_phases[i].pos<=last)
- break;
- cphase[i]=color_phases[i];
- col_count++;
- }
-
-
- for(int i=0;i<particle_count;i++) {
+ int start_particle = (int)(time * (float)particle_count / lifetime);
+
+ for (int id=0;id<particle_count;++id) {
+ int i = start_particle + id;
+ if (i >= particle_count) {
+ i -= particle_count;
+ }
Particle &p=pdata[i];
if (!p.active)
@@ -522,32 +524,14 @@ void Particles2D::_notification(int p_what) {
uint32_t rand_seed=p.seed*(i+1);
-
- int cpos=0;
-
- while(cpos<col_count) {
-
- if (cphase[cpos].pos > ptime)
- break;
- cpos++;
- }
-
- cpos--;
-
Color color;
- //could be faster..
- if (cpos==-1)
- color=Color(1,1,1,1);
- else {
- if (cpos==col_count-1)
- color=cphase[cpos].color;
- else {
- float diff = (cphase[cpos+1].pos-cphase[cpos].pos);
- if (diff>0)
- color=cphase[cpos].color.linear_interpolate(cphase[cpos+1].color, (ptime - cphase[cpos].pos) / diff );
- else
- color=cphase[cpos+1].color;
- }
+
+ if(color_ramp.is_valid())
+ {
+ color = color_ramp->get_color_at_offset(ptime);
+ } else
+ {
+ color = default_color;
}
@@ -606,9 +590,20 @@ void Particles2D::_notification(int p_what) {
if (texrid.is_valid()) {
- VisualServer::get_singleton()->canvas_item_add_texture_rect(ci,r,texrid,false,color);
+ Rect2 src_rect;
+ src_rect.size=size;
+
+ if (total_frames>1) {
+ int frame = Math::fast_ftoi(Math::floor(p.frame*total_frames)) % total_frames;
+ src_rect.pos.x = size.x * (frame%h_frames);
+ src_rect.pos.y = size.y * (frame/h_frames);
+ }
+
+
+ texture->draw_rect_region(ci,Rect2(Point2(),size),src_rect,color);
+ //VisualServer::get_singleton()->canvas_item_add_texture_rect(ci,r,texrid,false,color);
} else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci,r,color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2(),size),color);
}
@@ -632,9 +627,12 @@ static const char* _particlesframe_property_names[Particles2D::PARAM_MAX]={
"params/radial_accel",
"params/tangential_accel",
"params/damping",
+ "params/initial_angle",
"params/initial_size",
"params/final_size",
- "params/hue_variation"
+ "params/hue_variation",
+ "params/anim_speed_scale",
+ "params/anim_initial_pos",
};
static const char* _particlesframe_property_rnames[Particles2D::PARAM_MAX]={
@@ -647,10 +645,13 @@ static const char* _particlesframe_property_rnames[Particles2D::PARAM_MAX]={
"randomness/gravity_strength",
"randomness/radial_accel",
"randomness/tangential_accel",
- "randomness/damping",
+ "randomness/damping",
+ "randomness/initial_angle",
"randomness/initial_size",
"randomness/final_size",
- "randomness/hue_variation"
+ "randomness/hue_variation",
+ "randomness/anim_speed_scale",
+ "randomness/anim_initial_pos",
};
static const char* _particlesframe_property_ranges[Particles2D::PARAM_MAX]={
@@ -664,9 +665,12 @@ static const char* _particlesframe_property_ranges[Particles2D::PARAM_MAX]={
"-128,128,0.01",
"-128,128,0.01",
"0,1024,0.001",
+ "0,360,0.01",
"0,1024,0.01",
"0,1024,0.01",
- "0,1,0.01"
+ "0,1,0.01",
+ "0,128,0.01",
+ "0,1,0.01",
};
@@ -683,6 +687,7 @@ void Particles2D::set_emitting(bool p_emitting) {
time_to_live = emit_timeout;
};
emitting=p_emitting;
+ _change_notify("config/emitting");
}
bool Particles2D::is_emitting() const {
@@ -777,6 +782,27 @@ Ref<Texture> Particles2D::get_texture() const {
return texture;
}
+void Particles2D::set_color(const Color& p_color) {
+
+ default_color = p_color;
+}
+
+Color Particles2D::get_color() const {
+
+ return default_color;
+}
+
+
+void Particles2D::set_color_ramp(const Ref<ColorRamp>& p_color_ramp) {
+
+ color_ramp=p_color_ramp;
+}
+
+Ref<ColorRamp> Particles2D::get_color_ramp() const {
+
+ return color_ramp;
+}
+
void Particles2D::set_emissor_offset(const Point2& p_offset) {
emissor_offset=p_offset;
@@ -798,40 +824,76 @@ bool Particles2D::is_using_local_space() const {
return local_space;
}
-
+//Deprecated. Converts color phases to color ramp
void Particles2D::set_color_phases(int p_phases) {
- ERR_FAIL_INDEX(p_phases,MAX_COLOR_PHASES+1);
- color_phase_count=p_phases;
+ //Create color ramp if we have 2 or more phases.
+ //Otherwise first phase phase will be assigned to default color.
+ if(p_phases > 1 && color_ramp.is_null())
+ {
+ color_ramp = Ref<ColorRamp>(memnew (ColorRamp()));
+ }
+ if(color_ramp.is_valid())
+ {
+ color_ramp->get_points().resize(p_phases);
+ }
}
+//Deprecated.
int Particles2D::get_color_phases() const {
- return color_phase_count;
+ if(color_ramp.is_valid())
+ {
+ return color_ramp->get_points_count();
+ }
+ return 0;
}
+//Deprecated. Converts color phases to color ramp
void Particles2D::set_color_phase_color(int p_phase,const Color& p_color) {
ERR_FAIL_INDEX(p_phase,MAX_COLOR_PHASES);
- color_phases[p_phase].color=p_color;
-
+ if(color_ramp.is_valid())
+ {
+ if(color_ramp->get_points_count() > p_phase)
+ color_ramp->set_color(p_phase, p_color);
+ } else
+ {
+ if(p_phase == 0)
+ default_color = p_color;
+ }
}
+
+//Deprecated.
Color Particles2D::get_color_phase_color(int p_phase) const {
ERR_FAIL_INDEX_V(p_phase,MAX_COLOR_PHASES,Color());
- return color_phases[p_phase].color;
+ if(color_ramp.is_valid())
+ {
+ return color_ramp->get_color(p_phase);
+ }
+ return Color(0,0,0,1);
}
+//Deprecated. Converts color phases to color ramp
void Particles2D::set_color_phase_pos(int p_phase,float p_pos) {
ERR_FAIL_INDEX(p_phase,MAX_COLOR_PHASES);
ERR_FAIL_COND(p_pos<0.0 || p_pos>1.0);
- color_phases[p_phase].pos=p_pos;
-
+ if(color_ramp.is_valid() && color_ramp->get_points_count() > p_phase)
+ {
+ return color_ramp->set_offset(p_phase, p_pos);
+ }
}
+
+//Deprecated.
float Particles2D::get_color_phase_pos(int p_phase) const {
ERR_FAIL_INDEX_V(p_phase,MAX_COLOR_PHASES,0);
- return color_phases[p_phase].pos;
+ if(color_ramp.is_valid())
+ {
+ return color_ramp->get_offset(p_phase);
+ }
+ return 0;
}
void Particles2D::set_emission_half_extents(const Vector2& p_extents) {
@@ -899,6 +961,28 @@ bool Particles2D::is_flipped_v() const{
return flip_v;
}
+void Particles2D::set_h_frames(int p_frames) {
+
+ ERR_FAIL_COND(p_frames<1);
+ h_frames=p_frames;
+}
+
+int Particles2D::get_h_frames() const{
+
+ return h_frames;
+}
+
+void Particles2D::set_v_frames(int p_frames){
+
+ ERR_FAIL_COND(p_frames<1);
+ v_frames=p_frames;
+}
+int Particles2D::get_v_frames() const{
+
+ return v_frames;
+}
+
+
void Particles2D::set_emission_points(const DVector<Vector2>& p_points) {
@@ -939,6 +1023,12 @@ void Particles2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_texture:Texture","texture"),&Particles2D::set_texture);
ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&Particles2D::get_texture);
+ ObjectTypeDB::bind_method(_MD("set_color","color"),&Particles2D::set_color);
+ ObjectTypeDB::bind_method(_MD("get_color"),&Particles2D::get_color);
+
+ ObjectTypeDB::bind_method(_MD("set_color_ramp:ColorRamp","color_ramp"),&Particles2D::set_color_ramp);
+ ObjectTypeDB::bind_method(_MD("get_color_ramp:ColorRamp"),&Particles2D::get_color_ramp);
+
ObjectTypeDB::bind_method(_MD("set_emissor_offset","offset"),&Particles2D::set_emissor_offset);
ObjectTypeDB::bind_method(_MD("get_emissor_offset"),&Particles2D::get_emissor_offset);
@@ -948,6 +1038,12 @@ void Particles2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_flip_v","enable"),&Particles2D::set_flip_v);
ObjectTypeDB::bind_method(_MD("is_flipped_v"),&Particles2D::is_flipped_v);
+ ObjectTypeDB::bind_method(_MD("set_h_frames","enable"),&Particles2D::set_h_frames);
+ ObjectTypeDB::bind_method(_MD("get_h_frames"),&Particles2D::get_h_frames);
+
+ ObjectTypeDB::bind_method(_MD("set_v_frames","enable"),&Particles2D::set_v_frames);
+ ObjectTypeDB::bind_method(_MD("get_v_frames"),&Particles2D::get_v_frames);
+
ObjectTypeDB::bind_method(_MD("set_emission_half_extents","extents"),&Particles2D::set_emission_half_extents);
ObjectTypeDB::bind_method(_MD("get_emission_half_extents"),&Particles2D::get_emission_half_extents);
@@ -976,17 +1072,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_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++) {
@@ -994,39 +1092,45 @@ 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"), _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++) {
String phase="phase_"+itos(i)+"/";
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, phase+"pos", PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_color_phase_pos"),_SCS("get_color_phase_pos"),i );
- ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color"),_SCS("set_color_phase_color"),_SCS("get_color_phase_color"),i );
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, phase+"pos", PROPERTY_HINT_RANGE,"0,1,0.01", 0),_SCS("set_color_phase_pos"),_SCS("get_color_phase_pos"),i );
+ ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color", PROPERTY_HINT_NONE, "", 0),_SCS("set_color_phase_color"),_SCS("get_color_phase_color"),i );
}
+ 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 );
BIND_CONSTANT( PARAM_LINEAR_VELOCITY );
BIND_CONSTANT( PARAM_SPIN_VELOCITY );
+ BIND_CONSTANT( PARAM_ORBIT_VELOCITY );
BIND_CONSTANT( PARAM_GRAVITY_DIRECTION );
BIND_CONSTANT( PARAM_GRAVITY_STRENGTH );
BIND_CONSTANT( PARAM_RADIAL_ACCEL );
BIND_CONSTANT( PARAM_TANGENTIAL_ACCEL );
+ BIND_CONSTANT( PARAM_DAMPING );
+ BIND_CONSTANT( PARAM_INITIAL_ANGLE );
BIND_CONSTANT( PARAM_INITIAL_SIZE );
BIND_CONSTANT( PARAM_FINAL_SIZE );
BIND_CONSTANT( PARAM_HUE_VARIATION );
+ BIND_CONSTANT( PARAM_ANIM_SPEED_SCALE );
+ BIND_CONSTANT( PARAM_ANIM_INITIAL_POS );
BIND_CONSTANT( PARAM_MAX );
BIND_CONSTANT( MAX_COLOR_PHASES );
}
-
-
Particles2D::Particles2D() {
for(int i=0;i<PARAM_MAX;i++) {
@@ -1041,9 +1145,12 @@ Particles2D::Particles2D() {
set_param(PARAM_GRAVITY_STRENGTH,9.8);
set_param(PARAM_RADIAL_ACCEL,0);
set_param(PARAM_TANGENTIAL_ACCEL,0);
+ set_param(PARAM_INITIAL_ANGLE,0.0);
set_param(PARAM_INITIAL_SIZE,1.0);
set_param(PARAM_FINAL_SIZE,1.0);
+ set_param(PARAM_ANIM_SPEED_SCALE,1.0);
+ set_color(Color(1,1,1,1));
time=0;
lifetime=2;
@@ -1055,21 +1162,12 @@ Particles2D::Particles2D() {
preprocess=0;
time_scale=1.0;
- color_phase_count=1;
-
- set_color_phase_pos(0,0.0);
- set_color_phase_pos(1,1.0);
- set_color_phase_pos(2,1.0);
- set_color_phase_pos(3,1.0);
-
- set_color_phase_color(0,Color(1,1,1));
- set_color_phase_color(1,Color(0,0,0));
- set_color_phase_color(2,Color(0,0,0));
- set_color_phase_color(3,Color(0,0,0));
flip_h=false;
flip_v=false;
+ v_frames=1;
+ h_frames=1;
emit_timeout = 0;
time_to_live = 0;
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
index f562e826e0..4ee0fcf8da 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,6 +31,7 @@
#include "scene/2d/node_2d.h"
#include "scene/resources/texture.h"
+#include "scene/resources/color_ramp.h"
class Particles2D;
class ParticleAttractor2D : public Node2D {
@@ -87,7 +88,7 @@ public:
enum Parameter {
PARAM_DIRECTION,
PARAM_SPREAD,
- PARAM_LINEAR_VELOCITY,
+ PARAM_LINEAR_VELOCITY,
PARAM_SPIN_VELOCITY,
PARAM_ORBIT_VELOCITY,
PARAM_GRAVITY_DIRECTION,
@@ -95,9 +96,12 @@ public:
PARAM_RADIAL_ACCEL,
PARAM_TANGENTIAL_ACCEL,
PARAM_DAMPING,
+ PARAM_INITIAL_ANGLE,
PARAM_INITIAL_SIZE,
PARAM_FINAL_SIZE,
PARAM_HUE_VARIATION,
+ PARAM_ANIM_SPEED_SCALE,
+ PARAM_ANIM_INITIAL_POS,
PARAM_MAX
};
@@ -116,16 +120,12 @@ private:
Point2 pos;
Vector2 velocity;
float rot;
+ float frame;
uint32_t seed;
- Particle() { active=false; seed=123465789; rot=0;}
+ Particle() { active=false; seed=123465789; rot=0; frame=0;}
};
Vector<Particle> particles;
- int color_phase_count;
- struct ColorPhase {
- Color color;
- float pos;
- } color_phases[MAX_COLOR_PHASES];
struct AttractorCache {
@@ -145,6 +145,8 @@ private:
float time_scale;
bool flip_h;
bool flip_v;
+ int h_frames;
+ int v_frames;
Point2 emissor_offset;
Vector2 initial_velocity;
Vector2 extents;
@@ -155,6 +157,9 @@ private:
Ref<Texture> texture;
+ //If no color ramp is set then default color is used. Created as simple alternative to color_ramp.
+ Color default_color;
+ Ref<ColorRamp> color_ramp;
void testee(int a, int b, int c, int d, int e);
void _process_particles(float p_delta);
@@ -205,6 +210,13 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
+
+ void set_h_frames(int p_frames);
+ int get_h_frames() const;
+
+ void set_v_frames(int p_frames);
+ int get_v_frames() const;
+
void set_color_phases(int p_phases);
int get_color_phases() const;
@@ -217,6 +229,12 @@ public:
void set_texture(const Ref<Texture>& p_texture);
Ref<Texture> get_texture() const;
+ void set_color(const Color& p_color);
+ Color get_color() const;
+
+ void set_color_ramp(const Ref<ColorRamp>& p_texture);
+ Ref<ColorRamp> get_color_ramp() const;
+
void set_emissor_offset(const Point2& p_offset);
Point2 get_emissor_offset() const;
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index febec54124..8f110b3931 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,7 @@
void Path2D::_notification(int p_what) {
- if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_scene() && get_scene()->is_editor_hint()) {
+ if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_tree() && get_tree()->is_editor_hint()) {
//draw the curve!!
for(int i=0;i<curve->get_point_count();i++) {
@@ -52,7 +52,7 @@ void Path2D::_notification(int p_what) {
void Path2D::_curve_changed() {
- if (is_inside_scene() && get_scene()->is_editor_hint())
+ if (is_inside_tree() && get_tree()->is_editor_hint())
update();
}
@@ -118,7 +118,7 @@ void PathFollow2D::_update_transform() {
pos+=n*h_offset;
pos+=t*v_offset;
- set_rot(t.atan2());
+ set_rot(t.angle());
} else {
@@ -135,7 +135,7 @@ void PathFollow2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
Node *parent=get_parent();
if (parent) {
@@ -147,7 +147,7 @@ void PathFollow2D::_notification(int p_what) {
}
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
path=NULL;
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index 90f57c8eac..c9114c5d7d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index ecd147afde..c30921eb69 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -43,11 +43,69 @@ void PhysicsBody2D::_notification(int p_what) {
*/
}
+void PhysicsBody2D::set_one_way_collision_direction(const Vector2& p_dir) {
+
+ one_way_collision_direction=p_dir;
+ Physics2DServer::get_singleton()->body_set_one_way_collision_direction(get_rid(),p_dir);
+}
+
+Vector2 PhysicsBody2D::get_one_way_collision_direction() const{
+
+ return one_way_collision_direction;
+}
+
+
+void PhysicsBody2D::set_one_way_collision_max_depth(float p_depth) {
+
+ one_way_collision_max_depth=p_depth;
+ Physics2DServer::get_singleton()->body_set_one_way_collision_max_depth(get_rid(),p_depth);
+
+}
+
+float PhysicsBody2D::get_one_way_collision_max_depth() const{
+
+ return one_way_collision_max_depth;
+}
+
+
+void PhysicsBody2D::_set_layers(uint32_t p_mask) {
+
+ set_layer_mask(p_mask);
+ set_collision_mask(p_mask);
+}
+
+uint32_t PhysicsBody2D::_get_layers() const{
+
+ return get_layer_mask();
+}
+
void PhysicsBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody2D::set_layer_mask);
ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody2D::get_layer_mask);
- ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
+ ObjectTypeDB::bind_method(_MD("set_collision_mask","mask"),&PhysicsBody2D::set_collision_mask);
+ ObjectTypeDB::bind_method(_MD("get_collision_mask"),&PhysicsBody2D::get_collision_mask);
+
+
+ ObjectTypeDB::bind_method(_MD("set_collision_mask_bit","bit","value"),&PhysicsBody2D::set_collision_mask_bit);
+ ObjectTypeDB::bind_method(_MD("get_collision_mask_bit","bit"),&PhysicsBody2D::get_collision_mask_bit);
+
+ ObjectTypeDB::bind_method(_MD("set_layer_mask_bit","bit","value"),&PhysicsBody2D::set_layer_mask_bit);
+ ObjectTypeDB::bind_method(_MD("get_layer_mask_bit","bit"),&PhysicsBody2D::get_layer_mask_bit);
+
+ ObjectTypeDB::bind_method(_MD("_set_layers","mask"),&PhysicsBody2D::_set_layers);
+ ObjectTypeDB::bind_method(_MD("_get_layers"),&PhysicsBody2D::_get_layers);
+ ObjectTypeDB::bind_method(_MD("set_one_way_collision_direction","dir"),&PhysicsBody2D::set_one_way_collision_direction);
+ ObjectTypeDB::bind_method(_MD("get_one_way_collision_direction"),&PhysicsBody2D::get_one_way_collision_direction);
+ ObjectTypeDB::bind_method(_MD("set_one_way_collision_max_depth","depth"),&PhysicsBody2D::set_one_way_collision_max_depth);
+ ObjectTypeDB::bind_method(_MD("get_one_way_collision_max_depth"),&PhysicsBody2D::get_one_way_collision_max_depth);
+ ObjectTypeDB::bind_method(_MD("add_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::add_collision_exception_with);
+ ObjectTypeDB::bind_method(_MD("remove_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::remove_collision_exception_with);
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS,"",0),_SCS("_set_layers"),_SCS("_get_layers")); //for backwards compat
+ 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_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"one_way_collision/direction"),_SCS("set_one_way_collision_direction"),_SCS("get_one_way_collision_direction"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"one_way_collision/max_depth"),_SCS("set_one_way_collision_max_depth"),_SCS("get_one_way_collision_max_depth"));
}
void PhysicsBody2D::set_layer_mask(uint32_t p_mask) {
@@ -61,12 +119,81 @@ uint32_t PhysicsBody2D::get_layer_mask() const {
return mask;
}
+void PhysicsBody2D::set_collision_mask(uint32_t p_mask) {
+
+ collision_mask=p_mask;
+ Physics2DServer::get_singleton()->body_set_collision_mask(get_rid(),p_mask);
+}
+
+uint32_t PhysicsBody2D::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void PhysicsBody2D::set_collision_mask_bit(int p_bit, bool p_value) {
+
+ uint32_t mask = get_collision_mask();
+ if (p_value)
+ mask|=1<<p_bit;
+ else
+ mask&=~(1<<p_bit);
+ set_collision_mask(mask);
+
+}
+bool PhysicsBody2D::get_collision_mask_bit(int p_bit) const{
+
+ return get_collision_mask()&(1<<p_bit);
+}
+
+
+void PhysicsBody2D::set_layer_mask_bit(int p_bit, bool p_value) {
+
+ uint32_t mask = get_layer_mask();
+ if (p_value)
+ mask|=1<<p_bit;
+ else
+ mask&=~(1<<p_bit);
+ set_layer_mask(mask);
+
+}
+
+bool PhysicsBody2D::get_layer_mask_bit(int p_bit) const{
+
+ return get_layer_mask()&(1<<p_bit);
+}
+
PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject2D( Physics2DServer::get_singleton()->body_create(p_mode), false) {
mask=1;
+ collision_mask=1;
+ set_one_way_collision_max_depth(0);
+ set_pickable(false);
}
+void PhysicsBody2D::add_collision_exception_with(Node* p_node) {
+
+ ERR_FAIL_NULL(p_node);
+ PhysicsBody2D *physics_body = p_node->cast_to<PhysicsBody2D>();
+ if (!physics_body) {
+ ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type");
+ }
+ ERR_FAIL_COND(!physics_body);
+ Physics2DServer::get_singleton()->body_add_collision_exception(get_rid(),physics_body->get_rid());
+
+}
+
+void PhysicsBody2D::remove_collision_exception_with(Node* p_node) {
+
+ ERR_FAIL_NULL(p_node);
+ PhysicsBody2D *physics_body = p_node->cast_to<PhysicsBody2D>();
+ if (!physics_body) {
+ ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type");
+ }
+ ERR_FAIL_COND(!physics_body);
+ Physics2DServer::get_singleton()->body_remove_collision_exception(get_rid(),physics_body->get_rid());
+}
+
void StaticBody2D::set_constant_linear_velocity(const Vector2& p_vel) {
constant_linear_velocity=p_vel;
@@ -173,7 +300,7 @@ StaticBody2D::~StaticBody2D() {
-void RigidBody2D::_body_enter_scene(ObjectID p_id) {
+void RigidBody2D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = obj ? obj->cast_to<Node>() : NULL;
@@ -193,7 +320,7 @@ void RigidBody2D::_body_enter_scene(ObjectID p_id) {
}
-void RigidBody2D::_body_exit_scene(ObjectID p_id) {
+void RigidBody2D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = obj ? obj->cast_to<Node>() : NULL;
@@ -219,24 +346,32 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(objid);
+ /*if (obj) {
+ if (body_in)
+ print_line("in: "+String(obj->call("get_name")));
+ else
+ print_line("out: "+String(obj->call("get_name")));
+ }*/
+
ERR_FAIL_COND(!body_in && !E);
if (body_in) {
if (!E) {
E = contact_monitor->body_map.insert(objid,BodyState());
- E->get().rc=0;
- E->get().in_scene=node && node->is_inside_scene();
+// E->get().rc=0;
+ E->get().in_scene=node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree,make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree,make_binds(objid));
if (E->get().in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
}
}
+ //E->get().rc++;
}
- E->get().rc++;
+
if (node)
E->get().shapes.insert(ShapePair(p_body_shape,p_local_shape));
@@ -247,24 +382,26 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
} else {
- E->get().rc--;
+ //E->get().rc--;
if (node)
E->get().shapes.erase(ShapePair(p_body_shape,p_local_shape));
- if (E->get().rc==0) {
+ bool in_scene = E->get().in_scene;
+
+ if (E->get().shapes.empty()) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene);
- node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene);
- if (E->get().in_scene)
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
+ if (in_scene)
emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
}
contact_monitor->body_map.erase(E);
}
- if (node && E->get().in_scene) {
+ if (node && in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_local_shape);
}
@@ -280,6 +417,16 @@ struct _RigidBody2DInOut {
int local_shape;
};
+
+bool RigidBody2D::_test_motion(const Vector2& p_motion,float p_margin,const Ref<Physics2DTestMotionResult>& p_result) {
+
+ Physics2DServer::MotionResult *r=NULL;
+ if (p_result.is_valid())
+ r=p_result->get_result_ptr();
+ return Physics2DServer::get_singleton()->body_test_motion(get_rid(),p_motion,p_margin,r);
+
+}
+
void RigidBody2D::_direct_state_changed(Object *p_state) {
//eh.. fuck
@@ -315,14 +462,14 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
ObjectID obj = state->get_contact_collider_id(i);
int local_shape = state->get_contact_local_shape(i);
int shape = state->get_contact_collider_shape(i);
- toadd[i].local_shape=local_shape;
- toadd[i].id=obj;
- toadd[i].shape=shape;
// bool found=false;
Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(obj);
if (!E) {
+ toadd[toadd_count].local_shape=local_shape;
+ toadd[toadd_count].id=obj;
+ toadd[toadd_count].shape=shape;
toadd_count++;
continue;
}
@@ -331,6 +478,9 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
int idx = E->get().shapes.find(sp);
if (idx==-1) {
+ toadd[toadd_count].local_shape=local_shape;
+ toadd[toadd_count].id=obj;
+ toadd[toadd_count].shape=shape;
toadd_count++;
continue;
}
@@ -356,6 +506,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
//process remotions
+
for(int i=0;i<toremove_count;i++) {
_body_inout(0,toremove[i].body_id,toremove[i].pair.body_shape,toremove[i].pair.local_shape);
@@ -363,6 +514,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
//process aditions
+
for(int i=0;i<toadd_count;i++) {
_body_inout(1,toadd[i].id,toadd[i].shape,toadd[i].local_shape);
@@ -375,7 +527,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
set_global_transform(state->get_transform());
linear_velocity=state->get_linear_velocity();
angular_velocity=state->get_angular_velocity();
- active=!state->is_sleeping();
+ sleeping=state->is_sleeping();
if (get_script_instance())
get_script_instance()->call("_integrate_forces",state);
set_block_transform_notify(false); // want it back
@@ -466,6 +618,42 @@ real_t RigidBody2D::get_bounce() const{
return bounce;
}
+
+void RigidBody2D::set_gravity_scale(real_t p_gravity_scale){
+
+ gravity_scale=p_gravity_scale;
+ Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_GRAVITY_SCALE,gravity_scale);
+
+}
+real_t RigidBody2D::get_gravity_scale() const{
+
+ return gravity_scale;
+}
+
+void RigidBody2D::set_linear_damp(real_t p_linear_damp){
+
+ ERR_FAIL_COND(p_linear_damp<-1);
+ linear_damp=p_linear_damp;
+ Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_LINEAR_DAMP,linear_damp);
+
+}
+real_t RigidBody2D::get_linear_damp() const{
+
+ return linear_damp;
+}
+
+void RigidBody2D::set_angular_damp(real_t p_angular_damp){
+
+ ERR_FAIL_COND(p_angular_damp<-1);
+ angular_damp=p_angular_damp;
+ Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_ANGULAR_DAMP,angular_damp);
+
+}
+real_t RigidBody2D::get_angular_damp() const{
+
+ return angular_damp;
+}
+
void RigidBody2D::set_axis_velocity(const Vector2& p_axis) {
Vector2 v = state? state->get_linear_velocity() : linear_velocity;
@@ -525,10 +713,10 @@ bool RigidBody2D::is_using_custom_integrator(){
return custom_integrator;
}
-void RigidBody2D::set_active(bool p_active) {
+void RigidBody2D::set_sleeping(bool p_sleeping) {
- active=p_active;
- Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_SLEEPING,!active);
+ sleeping=p_sleeping;
+ Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_SLEEPING,sleeping);
}
@@ -543,9 +731,9 @@ bool RigidBody2D::is_able_to_sleep() const {
return can_sleep;
}
-bool RigidBody2D::is_active() const {
+bool RigidBody2D::is_sleeping() const {
- return active;
+ return sleeping;
}
void RigidBody2D::set_max_contacts_reported(int p_amount) {
@@ -588,6 +776,26 @@ RigidBody2D::CCDMode RigidBody2D::get_continuous_collision_detection_mode() cons
}
+Array RigidBody2D::get_colliding_bodies() const {
+
+ ERR_FAIL_COND_V(!contact_monitor,Array());
+
+ Array ret;
+ ret.resize(contact_monitor->body_map.size());
+ int idx=0;
+ for (const Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize( ret.size() -1 ); //ops
+ } else {
+ ret[idx++]=obj;
+ }
+
+ }
+
+ return ret;
+}
+
void RigidBody2D::set_contact_monitor(bool p_enabled) {
if (p_enabled==is_contact_monitor_enabled())
@@ -633,6 +841,15 @@ void RigidBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&RigidBody2D::set_bounce);
ObjectTypeDB::bind_method(_MD("get_bounce"),&RigidBody2D::get_bounce);
+ ObjectTypeDB::bind_method(_MD("set_gravity_scale","gravity_scale"),&RigidBody2D::set_gravity_scale);
+ ObjectTypeDB::bind_method(_MD("get_gravity_scale"),&RigidBody2D::get_gravity_scale);
+
+ ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&RigidBody2D::set_linear_damp);
+ ObjectTypeDB::bind_method(_MD("get_linear_damp"),&RigidBody2D::get_linear_damp);
+
+ ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&RigidBody2D::set_angular_damp);
+ ObjectTypeDB::bind_method(_MD("get_angular_damp"),&RigidBody2D::get_angular_damp);
+
ObjectTypeDB::bind_method(_MD("set_linear_velocity","linear_velocity"),&RigidBody2D::set_linear_velocity);
ObjectTypeDB::bind_method(_MD("get_linear_velocity"),&RigidBody2D::get_linear_velocity);
@@ -657,15 +874,19 @@ void RigidBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_applied_force","force"),&RigidBody2D::set_applied_force);
ObjectTypeDB::bind_method(_MD("get_applied_force"),&RigidBody2D::get_applied_force);
- ObjectTypeDB::bind_method(_MD("set_active","active"),&RigidBody2D::set_active);
- ObjectTypeDB::bind_method(_MD("is_active"),&RigidBody2D::is_active);
+ ObjectTypeDB::bind_method(_MD("set_sleeping","sleeping"),&RigidBody2D::set_sleeping);
+ ObjectTypeDB::bind_method(_MD("is_sleeping"),&RigidBody2D::is_sleeping);
ObjectTypeDB::bind_method(_MD("set_can_sleep","able_to_sleep"),&RigidBody2D::set_can_sleep);
ObjectTypeDB::bind_method(_MD("is_able_to_sleep"),&RigidBody2D::is_able_to_sleep);
+ ObjectTypeDB::bind_method(_MD("test_motion","motion","margin","result:Physics2DTestMotionResult"),&RigidBody2D::_test_motion,DEFVAL(0.08),DEFVAL(Variant()));
+
ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&RigidBody2D::_direct_state_changed);
- ObjectTypeDB::bind_method(_MD("_body_enter_scene"),&RigidBody2D::_body_enter_scene);
- ObjectTypeDB::bind_method(_MD("_body_exit_scene"),&RigidBody2D::_body_exit_scene);
+ ObjectTypeDB::bind_method(_MD("_body_enter_tree"),&RigidBody2D::_body_enter_tree);
+ ObjectTypeDB::bind_method(_MD("_body_exit_tree"),&RigidBody2D::_body_exit_tree);
+
+ ObjectTypeDB::bind_method(_MD("get_colliding_bodies"),&RigidBody2D::get_colliding_bodies);
BIND_VMETHOD(MethodInfo("_integrate_forces",PropertyInfo(Variant::OBJECT,"state:Physics2DDirectBodyState")));
@@ -674,14 +895,17 @@ void RigidBody2D::_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::INT,"continuous_cd",PROPERTY_HINT_ENUM,"Disabled,Cast Ray,Cast Shape"),_SCS("set_continuous_collision_detection_mode"),_SCS("get_continuous_collision_detection_mode"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"contacts_reported"),_SCS("set_max_contacts_reported"),_SCS("get_max_contacts_reported"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"contact_monitor"),_SCS("set_contact_monitor"),_SCS("is_contact_monitor_enabled"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"active"),_SCS("set_active"),_SCS("is_active"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"sleeping"),_SCS("set_sleeping"),_SCS("is_sleeping"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"can_sleep"),_SCS("set_can_sleep"),_SCS("is_able_to_sleep"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"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")));
@@ -706,11 +930,16 @@ RigidBody2D::RigidBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_RIGID) {
bounce=0;
mass=1;
friction=1;
+
+ gravity_scale=1;
+ linear_damp=-1;
+ angular_damp=-1;
+
max_contacts_reported=0;
state=NULL;
angular_velocity=0;
- active=true;
+ sleeping=false;
ccd_mode=CCD_MODE_DISABLED;
custom_integrator=false;
@@ -749,21 +978,40 @@ Variant KinematicBody2D::_get_collider() const {
return obj;
}
+void KinematicBody2D::revert_motion() {
-bool KinematicBody2D::_ignores_mode(Physics2DServer::BodyMode p_mode) const {
+ Matrix32 gt = get_global_transform();
+ gt.elements[2]-=travel;
+ travel=Vector2();
+ set_global_transform(gt);
- switch(p_mode) {
- case Physics2DServer::BODY_MODE_STATIC: return !collide_static;
- case Physics2DServer::BODY_MODE_KINEMATIC: return !collide_kinematic;
- case Physics2DServer::BODY_MODE_RIGID: return !collide_rigid;
- case Physics2DServer::BODY_MODE_CHARACTER: return !collide_character;
- }
+}
+
+Vector2 KinematicBody2D::get_travel() const {
- return true;
+ return travel;
}
Vector2 KinematicBody2D::move(const Vector2& p_motion) {
+#if 1
+ Physics2DServer::MotionResult result;
+ colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(),p_motion,margin,&result);
+
+ collider_metadata=result.collider_metadata;
+ collider_shape=result.collider_shape;
+ collider_vel=result.collider_velocity;
+ collision=result.collision_point;
+ normal=result.collision_normal;
+ collider=result.collider_id;
+
+ Matrix32 gt = get_global_transform();
+ gt.elements[2]+=result.motion;
+ set_global_transform(gt);
+ travel=result.motion;
+ return result.remainder;
+
+#else
//give me back regular physics engine logic
//this is madness
//and most people using this function will think
@@ -773,7 +1021,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
colliding=false;
- ERR_FAIL_COND_V(!is_inside_scene(),Vector2());
+ ERR_FAIL_COND_V(!is_inside_tree(),Vector2());
Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space());
ERR_FAIL_COND_V(!dss,Vector2());
const int max_shapes=32;
@@ -803,10 +1051,11 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
//print_line("margin: "+rtos(margin));
do {
- //fill exclude list..
+ //motion recover
for(int i=0;i<get_shape_count();i++) {
-
+ if (is_shape_set_as_trigger(i))
+ continue;
if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask))
collided=true;
@@ -826,7 +1075,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
//if (d<margin)
/// continue;
- recover_motion+=(b-a)*0.2;
+ recover_motion+=(b-a)*0.4;
}
if (recover_motion==Vector2()) {
@@ -850,11 +1099,14 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
for(int i=0;i<get_shape_count();i++) {
+ if (is_shape_set_as_trigger(i))
+ continue;
float lsafe,lunsafe;
bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask);
//print_line("shape: "+itos(i)+" travel:"+rtos(ltravel));
if (!valid) {
+
safe=0;
unsafe=0;
best_shape=i; //sadly it's the best
@@ -886,15 +1138,19 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,get_layer_mask(),mask);
if (!c2) {
//should not happen, but floating point precision is so weird..
+
colliding=false;
} else {
+
//print_line("Travel: "+rtos(travel));
colliding=true;
collision=rest_info.point;
normal=rest_info.normal;
collider=rest_info.collider_id;
collider_vel=rest_info.linear_velocity;
+ collider_shape=rest_info.shape;
+ collider_metadata=rest_info.metadata;
}
}
@@ -905,7 +1161,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
set_global_transform(gt);
return p_motion-motion;
-
+#endif
}
Vector2 KinematicBody2D::move_to(const Vector2& p_position) {
@@ -913,58 +1169,22 @@ Vector2 KinematicBody2D::move_to(const Vector2& p_position) {
return move(p_position-get_global_pos());
}
-bool KinematicBody2D::can_move_to(const Vector2& p_position, bool p_discrete) {
-
- ERR_FAIL_COND_V(!is_inside_scene(),false);
- Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space());
- ERR_FAIL_COND_V(!dss,false);
-
- uint32_t mask=0;
- if (collide_static)
- mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY;
- if (collide_kinematic)
- mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY;
- if (collide_rigid)
- mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY;
- if (collide_character)
- mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY;
-
- Vector2 motion = p_position-get_global_pos();
- Matrix32 xform=get_global_transform();
+bool KinematicBody2D::test_move(const Vector2& p_motion) {
- if (p_discrete) {
+ ERR_FAIL_COND_V(!is_inside_tree(),false);
- xform.elements[2]+=motion;
- motion=Vector2();
- }
+ return Physics2DServer::get_singleton()->body_test_motion(get_rid(),p_motion,margin);
- Set<RID> exclude;
- exclude.insert(get_rid());
- //fill exclude list..
- for(int i=0;i<get_shape_count();i++) {
-
-
- bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),motion,0,NULL,0,exclude,get_layer_mask(),mask);
- if (col)
- return false;
- }
-
- return true;
}
-bool KinematicBody2D::is_colliding() const {
-
- ERR_FAIL_COND_V(!is_inside_scene(),false);
-
- return colliding;
-}
Vector2 KinematicBody2D::get_collision_pos() const {
ERR_FAIL_COND_V(!colliding,Vector2());
return collision;
}
+
Vector2 KinematicBody2D::get_collision_normal() const {
ERR_FAIL_COND_V(!colliding,Vector2());
@@ -983,43 +1203,24 @@ ObjectID KinematicBody2D::get_collider() const {
return collider;
}
-void KinematicBody2D::set_collide_with_static_bodies(bool p_enable) {
- collide_static=p_enable;
-}
-bool KinematicBody2D::can_collide_with_static_bodies() const {
-
- return collide_static;
-}
+int KinematicBody2D::get_collider_shape() const {
-void KinematicBody2D::set_collide_with_rigid_bodies(bool p_enable) {
-
- collide_rigid=p_enable;
-
-}
-bool KinematicBody2D::can_collide_with_rigid_bodies() const {
-
-
- return collide_rigid;
+ ERR_FAIL_COND_V(!colliding,0);
+ return collider_shape;
}
-void KinematicBody2D::set_collide_with_kinematic_bodies(bool p_enable) {
+Variant KinematicBody2D::get_collider_metadata() const {
- collide_kinematic=p_enable;
-
-}
-bool KinematicBody2D::can_collide_with_kinematic_bodies() const {
+ ERR_FAIL_COND_V(!colliding,0);
+ return collider_metadata;
- return collide_kinematic;
}
-void KinematicBody2D::set_collide_with_character_bodies(bool p_enable) {
- collide_character=p_enable;
-}
-bool KinematicBody2D::can_collide_with_character_bodies() const {
+bool KinematicBody2D::is_colliding() const{
- return collide_character;
+ return colliding;
}
void KinematicBody2D::set_collision_margin(float p_margin) {
@@ -1038,7 +1239,9 @@ void KinematicBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody2D::move);
ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody2D::move_to);
- ObjectTypeDB::bind_method(_MD("can_move_to","position"),&KinematicBody2D::can_move_to);
+ ObjectTypeDB::bind_method(_MD("test_move","rel_vec"),&KinematicBody2D::test_move);
+ ObjectTypeDB::bind_method(_MD("get_travel"),&KinematicBody2D::get_travel);
+ ObjectTypeDB::bind_method(_MD("revert_motion"),&KinematicBody2D::revert_motion);
ObjectTypeDB::bind_method(_MD("is_colliding"),&KinematicBody2D::is_colliding);
@@ -1046,27 +1249,12 @@ void KinematicBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody2D::get_collision_normal);
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("set_collide_with_static_bodies","enable"),&KinematicBody2D::set_collide_with_static_bodies);
- ObjectTypeDB::bind_method(_MD("can_collide_with_static_bodies"),&KinematicBody2D::can_collide_with_static_bodies);
-
- ObjectTypeDB::bind_method(_MD("set_collide_with_kinematic_bodies","enable"),&KinematicBody2D::set_collide_with_kinematic_bodies);
- ObjectTypeDB::bind_method(_MD("can_collide_with_kinematic_bodies"),&KinematicBody2D::can_collide_with_kinematic_bodies);
-
- ObjectTypeDB::bind_method(_MD("set_collide_with_rigid_bodies","enable"),&KinematicBody2D::set_collide_with_rigid_bodies);
- ObjectTypeDB::bind_method(_MD("can_collide_with_rigid_bodies"),&KinematicBody2D::can_collide_with_rigid_bodies);
-
- ObjectTypeDB::bind_method(_MD("set_collide_with_character_bodies","enable"),&KinematicBody2D::set_collide_with_character_bodies);
- ObjectTypeDB::bind_method(_MD("can_collide_with_character_bodies"),&KinematicBody2D::can_collide_with_character_bodies);
+ 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("set_collision_margin","pixels"),&KinematicBody2D::set_collision_margin);
ObjectTypeDB::bind_method(_MD("get_collision_margin","pixels"),&KinematicBody2D::get_collision_margin);
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/static"),_SCS("set_collide_with_static_bodies"),_SCS("can_collide_with_static_bodies"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/kinematic"),_SCS("set_collide_with_kinematic_bodies"),_SCS("can_collide_with_kinematic_bodies"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/rigid"),_SCS("set_collide_with_rigid_bodies"),_SCS("can_collide_with_rigid_bodies"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/character"),_SCS("set_collide_with_character_bodies"),_SCS("can_collide_with_character_bodies"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/margin",PROPERTY_HINT_RANGE,"0.001,256,0.001"),_SCS("set_collision_margin"),_SCS("get_collision_margin"));
@@ -1074,14 +1262,11 @@ void KinematicBody2D::_bind_methods() {
KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KINEMATIC){
- collide_static=true;
- collide_rigid=true;
- collide_kinematic=true;
- collide_character=true;
-
colliding=false;
collider=0;
+ collider_shape=0;
+
margin=0.08;
}
KinematicBody2D::~KinematicBody2D() {
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 1319d2e4f0..b70fdd59cf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,6 +39,14 @@ class PhysicsBody2D : public CollisionObject2D {
OBJ_TYPE(PhysicsBody2D,CollisionObject2D);
uint32_t mask;
+ uint32_t collision_mask;
+ Vector2 one_way_collision_direction;
+ float one_way_collision_max_depth;
+
+
+ void _set_layers(uint32_t p_mask);
+ uint32_t _get_layers() const;
+
protected:
void _notification(int p_what);
@@ -50,6 +58,25 @@ public:
void set_layer_mask(uint32_t p_mask);
uint32_t get_layer_mask() const;
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
+ void set_layer_mask_bit(int p_bit, bool p_value);
+ bool get_layer_mask_bit(int p_bit) const;
+
+ void add_collision_exception_with(Node* p_node); //must be physicsbody
+ void remove_collision_exception_with(Node* p_node);
+
+ void set_one_way_collision_direction(const Vector2& p_dir);
+ Vector2 get_one_way_collision_direction() const;
+
+ void set_one_way_collision_max_depth(float p_dir);
+ float get_one_way_collision_max_depth() const;
+
PhysicsBody2D();
};
@@ -116,10 +143,13 @@ private:
real_t bounce;
real_t mass;
real_t friction;
+ real_t gravity_scale;
+ real_t linear_damp;
+ real_t angular_damp;
Vector2 linear_velocity;
real_t angular_velocity;
- bool active;
+ bool sleeping;
int max_contacts_reported;
@@ -153,7 +183,7 @@ private:
};
struct BodyState {
- int rc;
+ //int rc;
bool in_scene;
VSet<ShapePair> shapes;
};
@@ -167,13 +197,14 @@ private:
ContactMonitor *contact_monitor;
- void _body_enter_scene(ObjectID p_id);
- void _body_exit_scene(ObjectID p_id);
+ void _body_enter_tree(ObjectID p_id);
+ void _body_exit_tree(ObjectID p_id);
void _body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape);
void _direct_state_changed(Object *p_state);
+ bool _test_motion(const Vector2& p_motion,float p_margin=0.08,const Ref<Physics2DTestMotionResult>& p_result=Ref<Physics2DTestMotionResult>());
protected:
@@ -195,6 +226,15 @@ public:
void set_bounce(real_t p_bounce);
real_t get_bounce() 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_linear_velocity(const Vector2& p_velocity);
Vector2 get_linear_velocity() const;
@@ -206,8 +246,8 @@ public:
void set_use_custom_integrator(bool p_enable);
bool is_using_custom_integrator();
- void set_active(bool p_active);
- bool is_active() const;
+ void set_sleeping(bool p_sleeping);
+ bool is_sleeping() const;
void set_can_sleep(bool p_active);
bool is_able_to_sleep() const;
@@ -226,6 +266,10 @@ public:
void set_applied_force(const Vector2& p_force);
Vector2 get_applied_force() const;
+
+
+ Array get_colliding_bodies() const; //function for script
+
RigidBody2D();
~RigidBody2D();
@@ -241,17 +285,14 @@ class KinematicBody2D : public PhysicsBody2D {
OBJ_TYPE(KinematicBody2D,PhysicsBody2D);
float margin;
- bool collide_static;
- bool collide_rigid;
- bool collide_kinematic;
- bool collide_character;
-
bool colliding;
Vector2 collision;
Vector2 normal;
Vector2 collider_vel;
ObjectID collider;
-
+ int collider_shape;
+ Variant collider_metadata;
+ Vector2 travel;
Variant _get_collider() const;
@@ -264,24 +305,18 @@ public:
Vector2 move(const Vector2& p_motion);
Vector2 move_to(const Vector2& p_position);
- bool can_move_to(const Vector2& p_position,bool p_discrete=false);
+ bool test_move(const Vector2& p_motion);
bool is_colliding() const;
+
+ Vector2 get_travel() const;
+ void revert_motion();
+
Vector2 get_collision_pos() const;
Vector2 get_collision_normal() const;
Vector2 get_collider_velocity() const;
ObjectID get_collider() const;
-
- void set_collide_with_static_bodies(bool p_enable);
- bool can_collide_with_static_bodies() const;
-
- void set_collide_with_rigid_bodies(bool p_enable);
- bool can_collide_with_rigid_bodies() const;
-
- void set_collide_with_kinematic_bodies(bool p_enable);
- bool can_collide_with_kinematic_bodies() const;
-
- void set_collide_with_character_bodies(bool p_enable);
- bool can_collide_with_character_bodies() const;
+ int get_collider_shape() const;
+ Variant get_collider_metadata() const;
void set_collision_margin(float p_margin);
float get_collision_margin() const;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 2b4be734af..fc6986327f 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -192,14 +192,14 @@ void Polygon2D::set_texture(const Ref<Texture>& p_texture){
texture=p_texture;
- if (texture.is_valid()) {
+ /*if (texture.is_valid()) {
uint32_t flags=texture->get_flags();
flags&=~Texture::FLAG_REPEAT;
if (tex_tile)
flags|=Texture::FLAG_REPEAT;
texture->set_flags(flags);
- }
+ }*/
update();
}
Ref<Texture> Polygon2D::get_texture() const{
@@ -228,22 +228,6 @@ float Polygon2D::get_texture_rotation() const{
return tex_rot;
}
-void Polygon2D::set_texture_repeat(bool p_enable){
-
- tex_tile=p_enable;
- if (texture.is_valid()) {
- uint32_t flags=texture->get_flags();
- flags&=~Texture::FLAG_REPEAT;
- if (p_enable)
- flags|=Texture::FLAG_REPEAT;
- texture->set_flags(flags);
- }
- update();
-}
-bool Polygon2D::get_texture_repeat() const{
-
- return tex_tile;
-}
void Polygon2D::_set_texture_rotationd(float p_rot){
@@ -324,8 +308,6 @@ void Polygon2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_texture_scale","texture_scale"),&Polygon2D::set_texture_scale);
ObjectTypeDB::bind_method(_MD("get_texture_scale"),&Polygon2D::get_texture_scale);
- ObjectTypeDB::bind_method(_MD("set_texture_repeat","enable"),&Polygon2D::set_texture_repeat);
- ObjectTypeDB::bind_method(_MD("get_texture_repeat"),&Polygon2D::get_texture_repeat);
ObjectTypeDB::bind_method(_MD("set_invert","invert"),&Polygon2D::set_invert);
ObjectTypeDB::bind_method(_MD("get_invert"),&Polygon2D::get_invert);
@@ -346,7 +328,6 @@ void Polygon2D::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"texture/offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"texture/scale"),_SCS("set_texture_scale"),_SCS("get_texture_scale"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"texture/rotation",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_texture_rotationd"),_SCS("_get_texture_rotationd"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"texture/repeat"),_SCS("set_texture_repeat"),_SCS("get_texture_repeat"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"invert/enable"),_SCS("set_invert"),_SCS("get_invert"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"invert/border",PROPERTY_HINT_RANGE,"0.1,16384,0.1"),_SCS("set_invert_border"),_SCS("get_invert_border"));
@@ -359,5 +340,6 @@ Polygon2D::Polygon2D() {
tex_rot=0;
tex_tile=true;
tex_scale=Vector2(1,1);
+ color=Color(1,1,1);
rect_cache_dirty=true;
}
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index 38fa57b9b4..517b623ccd 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -52,9 +52,6 @@ public:
void set_texture_scale(const Vector2& p_scale);
Vector2 get_texture_scale() const;
- void set_texture_repeat(bool p_rot);
- bool get_texture_repeat() const;
-
void set_invert(bool p_rot);
bool get_invert() const;
diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp
index ca3be9aa8f..f1591b5242 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -45,14 +45,14 @@ void Position2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
update();
} break;
case NOTIFICATION_DRAW: {
- if (!is_inside_scene())
+ if (!is_inside_tree())
break;
- if (get_scene()->is_editor_hint())
+ if (get_tree()->is_editor_hint())
_draw_cross();
} break;
diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h
index caabf98eae..16404e6ce8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 8479338521..4a199e3418 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,7 +33,7 @@
void RayCast2D::set_cast_to(const Vector2& p_point) {
cast_to=p_point;
- if (is_inside_scene() && get_scene()->is_editor_hint())
+ if (is_inside_tree() && get_tree()->is_editor_hint())
update();
}
@@ -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;
@@ -82,7 +92,7 @@ Vector2 RayCast2D::get_collision_normal() const{
void RayCast2D::set_enabled(bool p_enabled) {
enabled=p_enabled;
- if (is_inside_scene() && !get_scene()->is_editor_hint())
+ if (is_inside_tree() && !get_tree()->is_editor_hint())
set_fixed_process(p_enabled);
if (!p_enabled)
collided=false;
@@ -101,31 +111,31 @@ void RayCast2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
- if (enabled && !get_scene()->is_editor_hint())
+ if (enabled && !get_tree()->is_editor_hint())
set_fixed_process(true);
else
set_fixed_process(false);
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (enabled)
set_fixed_process(false);
} break;
-#ifdef TOOLS_ENABLED
+
case NOTIFICATION_DRAW: {
- if (!get_scene()->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 b27fc4bf3d..8c3ce8b3b3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 80d038f6f8..0fbd140cfb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -45,7 +45,7 @@ void RemoteTransform2D::_update_cache() {
void RemoteTransform2D::_update_remote() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (!cache)
@@ -59,7 +59,7 @@ void RemoteTransform2D::_update_remote() {
if (!n)
return;
- if (!n->is_inside_scene())
+ if (!n->is_inside_tree())
return;
//todo make faster
@@ -77,7 +77,7 @@ void RemoteTransform2D::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
- if (!is_inside_scene())
+ if (!is_inside_tree())
break;
if (cache) {
@@ -95,7 +95,7 @@ void RemoteTransform2D::_notification(int p_what) {
void RemoteTransform2D::set_remote_node(const NodePath& p_remote_node) {
remote_node=p_remote_node;
- if (is_inside_scene())
+ if (is_inside_tree())
_update_cache();
}
diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h
index 9561e72255..506bde8cd8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,7 +38,7 @@ class RemoteTransform2D : public Node2D {
void _update_remote();
void _update_cache();
- void _node_exited_scene();
+ //void _node_exited_scene();
protected:
static void _bind_methods();
diff --git a/scene/2d/sample_player_2d.cpp b/scene/2d/sample_player_2d.cpp
index bc1734ec06..ec17ffc55e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -89,7 +89,7 @@ void SamplePlayer2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
SpatialSound2DServer::get_singleton()->source_set_polyphony(get_source_rid(),polyphony);
@@ -102,6 +102,7 @@ void SamplePlayer2D::_notification(int p_what) {
void SamplePlayer2D::set_sample_library(const Ref<SampleLibrary>& p_library) {
library=p_library;
+ _change_notify();
}
Ref<SampleLibrary> SamplePlayer2D::get_sample_library() const {
@@ -213,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 d04abae244..c0f2734ad1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp
index 9d0c9f3d1a..0c3987e6b1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -69,9 +69,9 @@ void TouchScreenButton::_notification(int p_what) {
case NOTIFICATION_DRAW: {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
- if (!get_scene()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY)
+ if (!get_tree()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY)
return;
if (finger_pressed!=-1) {
@@ -87,12 +87,15 @@ void TouchScreenButton::_notification(int p_what) {
}
} break;
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
- if (!get_scene()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY)
+ if (!get_tree()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY)
return;
update();
- set_process_input(true);
+
+ if (!get_tree()->is_editor_hint())
+ set_process_input(true);
+
if (action.operator String()!="" && InputMap::get_singleton()->has_action(action)) {
action_id=InputMap::get_singleton()->get_action_id(action);
} else {
@@ -126,7 +129,10 @@ String TouchScreenButton::get_action() const {
void TouchScreenButton::_input(const InputEvent& p_event) {
- if (!get_scene())
+ if (!get_tree())
+ return;
+
+ if (p_event.device != 0)
return;
if (passby_press) {
@@ -143,7 +149,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=false;
- get_scene()->input_event(ie);
+ get_tree()->input_event(ie);
}
finger_pressed=-1;
@@ -167,7 +173,8 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
}
} else {
- touched=Rect2(Point2(),texture->get_size()).has_point(coord);
+ if (texture.is_valid())
+ touched=Rect2(Point2(),texture->get_size()).has_point(coord);
}
@@ -186,7 +193,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=true;
- get_scene()->input_event(ie);
+ get_tree()->input_event(ie);
}
update();
@@ -206,7 +213,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=false;
- get_scene()->input_event(ie);
+ get_tree()->input_event(ie);
}
finger_pressed=-1;
@@ -261,7 +268,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=true;
- get_scene()->input_event(ie);
+ get_tree()->input_event(ie);
}
update();
@@ -282,7 +289,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=false;
- get_scene()->input_event(ie);
+ get_tree()->input_event(ie);
}
finger_pressed=-1;
update();
diff --git a/scene/2d/screen_button.h b/scene/2d/screen_button.h
index 7305fd29fe..159b829079 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/sound_player_2d.cpp b/scene/2d/sound_player_2d.cpp
index 2fffef4e51..0eb18866af 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,7 +39,7 @@ void SoundPlayer2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
//find the sound space
source_rid = SpatialSound2DServer::get_singleton()->source_create(get_world_2d()->get_sound_space());
@@ -56,7 +56,7 @@ void SoundPlayer2D::_notification(int p_what) {
SpatialSound2DServer::get_singleton()->source_set_transform(source_rid,get_global_transform());
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (source_rid.is_valid())
SpatialSound2DServer::get_singleton()->free(source_rid);
diff --git a/scene/2d/sound_player_2d.h b/scene/2d/sound_player_2d.h
index 9578c6b323..a376cdbed7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index 7d033ed87f..89d9966958 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,10 +30,12 @@
#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) {
set_offset(p_pivot);
+
}
Point2 Sprite::edit_get_pivot() const {
@@ -64,28 +66,31 @@ void Sprite::_notification(int p_what) {
break;
*/
- Size2i s;
- Rect2i src_rect;
+ Size2 s;
+ Rect2 src_rect;
if (region) {
s=region_rect.size;
src_rect=region_rect;
} else {
- s = texture->get_size();
- s=s/Size2i(hframes,vframes);
+ s = Size2(texture->get_size());
+ s=s/Size2(hframes,vframes);
src_rect.size=s;
- src_rect.pos.x+=(frame%hframes)*s.x;
- src_rect.pos.y+=(frame/hframes)*s.y;
+ src_rect.pos.x+=float(frame%hframes)*s.x;
+ src_rect.pos.y+=float(frame/hframes)*s.y;
}
- Point2i ofs=offset;
+ Point2 ofs=offset;
if (centered)
ofs-=s/2;
+ if (OS::get_singleton()->get_use_pixel_snap()) {
+ ofs=ofs.floor();
+ }
- Rect2i dst_rect(ofs,s);
+ Rect2 dst_rect(ofs,s);
if (hflip)
dst_rect.size.x=-dst_rect.size.x;
@@ -102,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();
}
@@ -136,6 +145,7 @@ void Sprite::set_offset(const Point2& p_offset) {
offset=p_offset;
update();
item_rect_changed();
+ _change_notify("offset");
}
Point2 Sprite::get_offset() const {
@@ -183,6 +193,7 @@ void Sprite::set_region_rect(const Rect2& p_region_rect) {
if (region && changed) {
update();
item_rect_changed();
+ _change_notify("region_rect");
}
}
@@ -199,6 +210,8 @@ void Sprite::set_frame(int p_frame) {
item_rect_changed();
frame=p_frame;
+
+ emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
int Sprite::get_frame() const {
@@ -261,7 +274,7 @@ Rect2 Sprite::get_item_rect() const {
s=s/Point2(hframes,vframes);
}
- Point2i ofs=offset;
+ Point2 ofs=offset;
if (centered)
ofs-=s/2;
@@ -307,17 +320,19 @@ void Sprite::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&Sprite::set_modulate);
ObjectTypeDB::bind_method(_MD("get_modulate"),&Sprite::get_modulate);
- 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"), _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_SIGNAL(MethodInfo("frame_changed"));
+
+ 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"));
}
@@ -365,7 +380,7 @@ void ViewportSprite::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
if (!viewport_path.is_empty()) {
@@ -380,7 +395,7 @@ void ViewportSprite::_notification(int p_what) {
item_rect_changed();
}
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (texture.is_valid()) {
@@ -407,11 +422,14 @@ void ViewportSprite::_notification(int p_what) {
src_rect.size=s;
- Point2i ofs=offset;
+ Point2 ofs=offset;
if (centered)
ofs-=s/2;
- Rect2i dst_rect(ofs,s);
+ 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);
} break;
@@ -422,7 +440,7 @@ void ViewportSprite::set_viewport_path(const NodePath& p_viewport) {
viewport_path=p_viewport;
update();
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (texture.is_valid()) {
@@ -499,7 +517,7 @@ Rect2 ViewportSprite::get_item_rect() const {
Size2i s;
s = texture->get_size();
- Point2i ofs=offset;
+ Point2 ofs=offset;
if (centered)
ofs-=s/2;
@@ -524,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 f26852fea6..ad782e746b 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index c4879cf065..167b637bdc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,11 +29,33 @@
#include "tile_map.h"
#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 {
+
+ if (y_sort_mode)
+ return 1;
+ else
+ return quadrant_size;
+}
+
void TileMap::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
+
+ Node2D *c=this;
+ while(c) {
+
+ navigation=c->cast_to<Navigation2D>();
+ if (navigation) {
+ break;
+ }
+
+ c=c->get_parent()->cast_to<Node2D>();
+ }
pending_update=true;
_update_dirty_quadrants();
@@ -43,9 +65,28 @@ void TileMap::_notification(int p_what) {
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
_update_quadrant_space(RID());
+ for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
+
+ Quadrant &q=E->get();
+ if (navigation) {
+ for(Map<PosKey,Quadrant::NavPoly>::Element *E=q.navpoly_ids.front();E;E=E->next()) {
+
+ navigation->navpoly_remove(E->get().id);
+ }
+ q.navpoly_ids.clear();
+ }
+
+ for(Map<PosKey,Quadrant::Occluder>::Element *E=q.occluder_instances.front();E;E=E->next()) {
+ VS::get_singleton()->free(E->get().id);
+ }
+ q.occluder_instances.clear();
+ }
+
+ navigation=NULL;
+
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -62,24 +103,39 @@ void TileMap::_update_quadrant_space(const RID& p_space) {
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
Quadrant &q=E->get();
- Physics2DServer::get_singleton()->body_set_space(q.static_body,p_space);
+ Physics2DServer::get_singleton()->body_set_space(q.body,p_space);
}
}
void TileMap::_update_quadrant_transform() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
Matrix32 global_transform = get_global_transform();
+ Matrix32 nav_rel;
+ if (navigation)
+ nav_rel = get_relative_transform(navigation);
+
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
Quadrant &q=E->get();
Matrix32 xform;
xform.set_origin( q.pos );
xform = global_transform * xform;
- Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
+ Physics2DServer::get_singleton()->body_set_state(q.body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
+
+ if (navigation) {
+ for(Map<PosKey,Quadrant::NavPoly>::Element *E=q.navpoly_ids.front();E;E=E->next()) {
+
+ navigation->navpoly_set_transform(E->get().id,nav_rel * E->get().xform);
+ }
+ }
+
+ for(Map<PosKey,Quadrant::Occluder>::Element *E=q.occluder_instances.front();E;E=E->next()) {
+ VS::get_singleton()->canvas_light_occluder_set_transform(E->get().id,global_transform * E->get().xform);
+ }
}
}
@@ -106,9 +162,9 @@ Ref<TileSet> TileMap::get_tileset() const {
return tile_set;
}
-void TileMap::set_cell_size(int p_size) {
+void TileMap::set_cell_size(Size2 p_size) {
- ERR_FAIL_COND(p_size<1);
+ ERR_FAIL_COND(p_size.x<1 || p_size.y<1);
_clear_quadrants();
cell_size=p_size;
@@ -117,7 +173,7 @@ void TileMap::set_cell_size(int p_size) {
}
-int TileMap::get_cell_size() const {
+Size2 TileMap::get_cell_size() const {
return cell_size;
}
@@ -160,24 +216,89 @@ bool TileMap::get_center_y() const {
return center_y;
}
+void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& p_cell, const Vector2& p_offset, const Size2 &p_sc) {
+
+ Size2 s=p_sc;
+ Vector2 offset = p_offset;
+
+ if (p_cell.transpose) {
+ SWAP(xform.elements[0].x, xform.elements[0].y);
+ SWAP(xform.elements[1].x, xform.elements[1].y);
+ SWAP(offset.x, offset.y);
+ SWAP(s.x, s.y);
+ }
+ if (p_cell.flip_h) {
+ xform.elements[0].x=-xform.elements[0].x;
+ xform.elements[1].x=-xform.elements[1].x;
+ if (tile_origin==TILE_ORIGIN_TOP_LEFT)
+ offset.x=s.x-offset.x;
+ }
+ if (p_cell.flip_v) {
+ xform.elements[0].y=-xform.elements[0].y;
+ xform.elements[1].y=-xform.elements[1].y;
+ if (tile_origin==TILE_ORIGIN_TOP_LEFT)
+ offset.y=s.y-offset.y;
+ }
+ xform.elements[2].x+=offset.x;
+ xform.elements[2].y+=offset.y;
+
+}
+
void TileMap::_update_dirty_quadrants() {
if (!pending_update)
return;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (!tile_set.is_valid())
return;
VisualServer *vs = VisualServer::get_singleton();
Physics2DServer *ps = Physics2DServer::get_singleton();
+ Vector2 tofs = get_cell_draw_offset();
+ Vector2 tcenter = cell_size/2;
+ Matrix32 nav_rel;
+ if (navigation)
+ nav_rel = get_relative_transform(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();
- vs->canvas_item_clear(q.canvas_item);
- ps->body_clear_shapes(q.static_body);
+ for (List<RID>::Element *E=q.canvas_items.front();E;E=E->next()) {
+
+ vs->free(E->get());
+ }
+
+ q.canvas_items.clear();
+
+ ps->body_clear_shapes(q.body);
+ int shape_idx=0;
+
+ if (navigation) {
+ for(Map<PosKey,Quadrant::NavPoly>::Element *E=q.navpoly_ids.front();E;E=E->next()) {
+
+ navigation->navpoly_remove(E->get().id);
+ }
+ q.navpoly_ids.clear();
+ }
+
+ for(Map<PosKey,Quadrant::Occluder>::Element *E=q.occluder_instances.front();E;E=E->next()) {
+ VS::get_singleton()->free(E->get().id);
+ }
+ q.occluder_instances.clear();
+ Ref<CanvasItemMaterial> prev_material;
+ RID prev_canvas_item;
for(int i=0;i<q.cells.size();i++) {
@@ -189,11 +310,35 @@ void TileMap::_update_dirty_quadrants() {
Ref<Texture> tex = tile_set->tile_get_texture(c.id);
Vector2 tile_ofs = tile_set->tile_get_texture_offset(c.id);
- Vector2 offset = Point2( E->key().x, E->key().y )*cell_size - q.pos;
+ Vector2 wofs = _map_to_world(E->key().x, E->key().y);
+ Vector2 offset = wofs - q.pos + tofs;
if (!tex.is_valid())
continue;
+ Ref<CanvasItemMaterial> mat = tile_set->tile_get_material(c.id);
+
+ RID canvas_item;
+
+ if (prev_canvas_item==RID() || prev_material!=mat) {
+
+ canvas_item=vs->canvas_item_create();
+ if (mat.is_valid())
+ vs->canvas_item_set_material(canvas_item,mat->get_rid());
+ vs->canvas_item_set_parent( canvas_item, get_canvas_item() );
+ Matrix32 xform;
+ xform.set_origin( q.pos );
+ vs->canvas_item_set_transform( canvas_item, xform );
+ q.canvas_items.push_back(canvas_item);
+
+ prev_canvas_item=canvas_item;
+ prev_material=mat;
+
+ } else {
+ canvas_item=prev_canvas_item;
+ }
+
+
Rect2 r = tile_set->tile_get_region(c.id);
Size2 s = tex->get_size();
@@ -212,22 +357,40 @@ void TileMap::_update_dirty_quadrants() {
rect.pos=offset.floor();
rect.size=s;
- rect.size.x+=fp_adjust;
- rect.size.y+=fp_adjust;
+ /* rect.size.x+=fp_adjust;
+ rect.size.y+=fp_adjust;*/
if (c.flip_h)
rect.size.x=-rect.size.x;
if (c.flip_v)
rect.size.y=-rect.size.y;
+ Vector2 center_ofs;
- rect.pos+=tile_ofs;
- if (r==Rect2()) {
+ if (tile_origin==TILE_ORIGIN_TOP_LEFT) {
+ rect.pos+=tile_ofs;
+ } else if (tile_origin==TILE_ORIGIN_CENTER) {
+ rect.pos+=tcenter;
+
+ Vector2 center = (s/2) - tile_ofs;
+ center_ofs=tcenter-(s/2);
+
+ if (c.flip_h)
+ rect.pos.x-=s.x-center.x;
+ else
+ rect.pos.x-=center.x;
+
+ if (c.flip_v)
+ rect.pos.y-=s.y-center.y;
+ else
+ rect.pos.y-=center.y;
+ }
- tex->draw_rect(q.canvas_item,rect);
- } else {
- tex->draw_rect_region(q.canvas_item,rect,r);
+ if (r==Rect2()) {
+ tex->draw_rect(canvas_item,rect,false,Color(1,1,1),c.transpose);
+ } else {
+ tex->draw_rect_region(canvas_item,rect,r,Color(1,1,1),c.transpose);
}
Vector< Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id);
@@ -241,25 +404,59 @@ void TileMap::_update_dirty_quadrants() {
Vector2 shape_ofs = tile_set->tile_get_shape_offset(c.id);
Matrix32 xform;
xform.set_origin(offset.floor());
- if (c.flip_h) {
- xform.elements[0]=-xform.elements[0];
- xform.elements[2].x+=s.x-shape_ofs.x;
- } else {
- xform.elements[2].x+=shape_ofs.x;
- }
- if (c.flip_v) {
- xform.elements[1]=-xform.elements[1];
- xform.elements[2].y+=s.y-shape_ofs.y;
- } else {
+ _fix_cell_transform(xform,c,shape_ofs+center_ofs,s);
+
+ if (debug_shapes) {
+ vs->canvas_item_add_set_transform(canvas_item,xform);
+ shape->draw(canvas_item,debug_collision_color);
- xform.elements[2].y+=shape_ofs.y;
}
+ 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));
+
+ }
+ }
+ if (debug_shapes) {
+ vs->canvas_item_add_set_transform(canvas_item,Matrix32());
+ }
+
+ if (navigation) {
+ Ref<NavigationPolygon> navpoly = tile_set->tile_get_navigation_polygon(c.id);
+ if (navpoly.is_valid()) {
+ Vector2 npoly_ofs = tile_set->tile_get_navigation_polygon_offset(c.id);
+ Matrix32 xform;
+ xform.set_origin(offset.floor()+q.pos);
+ _fix_cell_transform(xform,c,npoly_ofs+center_ofs,s);
- ps->body_add_shape(q.static_body,shape->get_rid(),xform);
+ int pid = navigation->navpoly_create(navpoly,nav_rel * xform);
+
+ Quadrant::NavPoly np;
+ np.id=pid;
+ np.xform=xform;
+ q.navpoly_ids[E->key()]=np;
}
}
+
+
+ Ref<OccluderPolygon2D> occluder=tile_set->tile_get_light_occluder(c.id);
+ if (occluder.is_valid()) {
+
+ Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id);
+ Matrix32 xform;
+ xform.set_origin(offset.floor()+q.pos);
+ _fix_cell_transform(xform,c,occluder_ofs+center_ofs,s);
+
+ RID orid = VS::get_singleton()->canvas_light_occluder_create();
+ 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());
+ Quadrant::Occluder oc;
+ oc.xform=xform;
+ oc.id=orid;
+ q.occluder_instances[E->key()]=oc;
+ }
}
dirty_quadrant_list.remove( dirty_quadrant_list.first() );
@@ -269,6 +466,20 @@ void TileMap::_update_dirty_quadrants() {
pending_update=false;
+ if (quadrant_order_dirty) {
+
+ for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
+
+ Quadrant &q=E->get();
+ for (List<RID>::Element *E=q.canvas_items.front();E;E=E->next()) {
+
+ VS::get_singleton()->canvas_item_raise(E->get());
+ }
+ }
+
+ quadrant_order_dirty=false;
+ }
+
_recompute_rect_cache();
}
@@ -285,17 +496,22 @@ void TileMap::_recompute_rect_cache() {
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
- Rect2 r( Point2(E->key().x, E->key().y)*cell_size*quadrant_size, Size2(1,1)*cell_size*quadrant_size );
+ Rect2 r;
+ r.pos=_map_to_world(E->key().x*_get_quadrant_size(), E->key().y*_get_quadrant_size());
+ r.expand_to( _map_to_world(E->key().x*_get_quadrant_size()+_get_quadrant_size(), E->key().y*_get_quadrant_size()) );
+ r.expand_to( _map_to_world(E->key().x*_get_quadrant_size()+_get_quadrant_size(), E->key().y*_get_quadrant_size()+_get_quadrant_size()) );
+ r.expand_to( _map_to_world(E->key().x*_get_quadrant_size(), E->key().y*_get_quadrant_size()+_get_quadrant_size()) );
if (E==quadrant_map.front())
r_total=r;
else
r_total=r_total.merge(r);
}
+
if (r_total==Rect2()) {
rect_cache=Rect2(-10,-10,20,20);
} else {
- rect_cache=r_total;
+ rect_cache=r_total.grow(MAX(cell_size.x,cell_size.y)*_get_quadrant_size());
}
item_rect_changed();
@@ -309,37 +525,60 @@ void TileMap::_recompute_rect_cache() {
Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const PosKey& p_qk) {
Matrix32 xform;
- xform.set_origin(Point2(p_qk.x,p_qk.y)*quadrant_size*cell_size);
+ //xform.set_origin(Point2(p_qk.x,p_qk.y)*cell_size*quadrant_size);
Quadrant q;
- q.canvas_item = VisualServer::get_singleton()->canvas_item_create();
- VisualServer::get_singleton()->canvas_item_set_parent( q.canvas_item, get_canvas_item() );
- VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform );
- q.static_body=Physics2DServer::get_singleton()->body_create(Physics2DServer::BODY_MODE_STATIC);
- Physics2DServer::get_singleton()->body_set_layer_mask(q.static_body,collision_layer);
- Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_FRICTION,friction);
- Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_BOUNCE,bounce);
-
- if (is_inside_scene()) {
+ q.pos = _map_to_world(p_qk.x*_get_quadrant_size(),p_qk.y*_get_quadrant_size());
+ q.pos+=get_cell_draw_offset();
+ if (tile_origin==TILE_ORIGIN_CENTER)
+ q.pos+=cell_size/2;
+
+ xform.set_origin( q.pos );
+// q.canvas_item = VisualServer::get_singleton()->canvas_item_create();
+ q.body=Physics2DServer::get_singleton()->body_create(use_kinematic?Physics2DServer::BODY_MODE_KINEMATIC:Physics2DServer::BODY_MODE_STATIC);
+ Physics2DServer::get_singleton()->body_attach_object_instance_ID(q.body,get_instance_ID());
+ Physics2DServer::get_singleton()->body_set_layer_mask(q.body,collision_layer);
+ Physics2DServer::get_singleton()->body_set_collision_mask(q.body,collision_mask);
+ Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_FRICTION,friction);
+ Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_BOUNCE,bounce);
+
+ if (is_inside_tree()) {
xform = get_global_transform() * xform;
RID space = get_world_2d()->get_space();
- Physics2DServer::get_singleton()->body_set_space(q.static_body,space);
+ Physics2DServer::get_singleton()->body_set_space(q.body,space);
}
- Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
- q.pos=Vector2(p_qk.x,p_qk.y)*quadrant_size*cell_size;
+ Physics2DServer::get_singleton()->body_set_state(q.body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
rect_cache_dirty=true;
+ quadrant_order_dirty=true;
return quadrant_map.insert(p_qk,q);
}
void TileMap::_erase_quadrant(Map<PosKey,Quadrant>::Element *Q) {
Quadrant &q=Q->get();
- Physics2DServer::get_singleton()->free(q.static_body);
- VisualServer::get_singleton()->free(q.canvas_item);
+ Physics2DServer::get_singleton()->free(q.body);
+ for (List<RID>::Element *E=q.canvas_items.front();E;E=E->next()) {
+
+ VisualServer::get_singleton()->free(E->get());
+ }
+ q.canvas_items.clear();
if (q.dirty_list.in_list())
dirty_quadrant_list.remove(&q.dirty_list);
+ if (navigation) {
+ for(Map<PosKey,Quadrant::NavPoly>::Element *E=q.navpoly_ids.front();E;E=E->next()) {
+
+ navigation->navpoly_remove(E->get().id);
+ }
+ q.navpoly_ids.clear();
+ }
+
+ for(Map<PosKey,Quadrant::Occluder>::Element *E=q.occluder_instances.front();E;E=E->next()) {
+ VS::get_singleton()->free(E->get().id);
+ }
+ q.occluder_instances.clear();
+
quadrant_map.erase(Q);
rect_cache_dirty=true;
}
@@ -353,13 +592,17 @@ void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) {
if (pending_update)
return;
pending_update=true;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
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) {
-void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
+ 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) {
PosKey pk(p_x,p_y);
@@ -367,7 +610,7 @@ void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
if (!E && p_tile==INVALID_CELL)
return; //nothing to do
- PosKey qk(p_x/quadrant_size,p_y/quadrant_size);
+ PosKey qk(p_x/_get_quadrant_size(),p_y/_get_quadrant_size());
if (p_tile==INVALID_CELL) {
//erase existing
tile_map.erase(pk);
@@ -387,14 +630,15 @@ void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
if (!E) {
E=tile_map.insert(pk,Cell());
- if (!Q)
+ if (!Q) {
Q=_create_quadrant(qk);
+ }
Quadrant &q=Q->get();
q.cells.insert(pk);
} else {
ERR_FAIL_COND(!Q); // quadrant should exist...
- if (E->get().id==p_tile && E->get().flip_h==p_flip_x && E->get().flip_v==p_flip_y)
+ if (E->get().id==p_tile && E->get().flip_h==p_flip_x && E->get().flip_v==p_flip_y && E->get().transpose==p_transpose)
return; //nothing changed
}
@@ -405,6 +649,7 @@ void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
c.id=p_tile;
c.flip_h=p_flip_x;
c.flip_v=p_flip_y;
+ c.transpose=p_transpose;
_make_quadrant_dirty(Q);
@@ -444,6 +689,17 @@ bool TileMap::is_cell_y_flipped(int p_x,int p_y) const {
return E->get().flip_v;
}
+bool TileMap::is_cell_transposed(int p_x,int p_y) const {
+
+ PosKey pk(p_x,p_y);
+
+ const Map<PosKey,Cell>::Element *E=tile_map.find(pk);
+
+ if (!E)
+ return false;
+
+ return E->get().transpose;
+}
void TileMap::_recreate_quadrants() {
@@ -452,7 +708,7 @@ void TileMap::_recreate_quadrants() {
for (Map<PosKey,Cell>::Element *E=tile_map.front();E;E=E->next()) {
- PosKey qk(E->key().x/quadrant_size,E->key().y/quadrant_size);
+ PosKey qk(E->key().x/_get_quadrant_size(),E->key().y/_get_quadrant_size());
Map<PosKey,Quadrant>::Element *Q=quadrant_map.find(qk);
if (!Q) {
@@ -461,10 +717,14 @@ void TileMap::_recreate_quadrants() {
}
Q->get().cells.insert(E->key());
-
+ _make_quadrant_dirty(Q);
}
+
+
+
}
+
void TileMap::_clear_quadrants() {
while (quadrant_map.size()) {
@@ -505,11 +765,13 @@ void TileMap::_set_tile_data(const DVector<int>& p_data) {
uint32_t v = decode_uint32(&local[4]);
bool flip_h = v&(1<<29);
bool flip_v = v&(1<<30);
+ bool transpose = v&(1<<31);
v&=(1<<29)-1;
// if (x<-20 || y <-20 || x>4000 || y>4000)
// continue;
- set_cell(x,y,v,flip_h,flip_v);
+ set_cell(x,y,v,flip_h,flip_v,transpose);
+
}
}
@@ -531,6 +793,8 @@ DVector<int> TileMap::_get_tile_data() const {
val|=(1<<29);
if (E->get().flip_v)
val|=(1<<30);
+ if (E->get().transpose)
+ val|=(1<<31);
encode_uint32(val,&ptr[4]);
idx+=2;
@@ -549,23 +813,45 @@ Rect2 TileMap::get_item_rect() const {
return rect_cache;
}
-void TileMap::set_collision_layer_mask(uint32_t p_layer) {
+void TileMap::set_collision_layer(uint32_t p_layer) {
collision_layer=p_layer;
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
Quadrant &q=E->get();
- Physics2DServer::get_singleton()->body_set_layer_mask(q.static_body,collision_layer);
+ Physics2DServer::get_singleton()->body_set_layer_mask(q.body,collision_layer);
}
}
+void TileMap::set_collision_mask(uint32_t p_mask) {
+
+ collision_mask=p_mask;
+ for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
+
+ Quadrant &q=E->get();
+ Physics2DServer::get_singleton()->body_set_collision_mask(q.body,collision_mask);
+ }
+}
+
+bool TileMap::get_collision_use_kinematic() const{
+
+ return use_kinematic;
+}
+
+void TileMap::set_collision_use_kinematic(bool p_use_kinematic) {
+
+ _clear_quadrants();
+ use_kinematic=p_use_kinematic;
+ _recreate_quadrants();
+}
+
void TileMap::set_collision_friction(float p_friction) {
friction=p_friction;
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
Quadrant &q=E->get();
- Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_FRICTION,p_friction);
+ Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_FRICTION,p_friction);
}
}
@@ -581,7 +867,7 @@ void TileMap::set_collision_bounce(float p_bounce){
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
Quadrant &q=E->get();
- Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_BOUNCE,p_bounce);
+ Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_BOUNCE,p_bounce);
}
}
@@ -591,11 +877,203 @@ float TileMap::get_collision_bounce() const{
}
-uint32_t TileMap::get_collision_layer_mask() const {
+uint32_t TileMap::get_collision_layer() const {
return collision_layer;
}
+uint32_t TileMap::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void TileMap::set_mode(Mode p_mode) {
+
+ _clear_quadrants();
+ mode=p_mode;
+ _recreate_quadrants();
+ emit_signal("settings_changed");
+}
+
+TileMap::Mode TileMap::get_mode() const {
+ return mode;
+}
+
+void TileMap::set_half_offset(HalfOffset p_half_offset) {
+
+ _clear_quadrants();
+ half_offset=p_half_offset;
+ _recreate_quadrants();
+ emit_signal("settings_changed");
+}
+
+void TileMap::set_tile_origin(TileOrigin p_tile_origin) {
+
+ _clear_quadrants();
+ tile_origin=p_tile_origin;
+ _recreate_quadrants();
+ emit_signal("settings_changed");
+}
+
+TileMap::TileOrigin TileMap::get_tile_origin() const{
+
+ return tile_origin;
+}
+
+
+Vector2 TileMap::get_cell_draw_offset() const {
+
+ switch(mode) {
+
+ case MODE_SQUARE: {
+
+ return Vector2();
+ } break;
+ case MODE_ISOMETRIC: {
+
+ return Vector2(-cell_size.x*0.5,0);
+
+ } break;
+ case MODE_CUSTOM: {
+
+ Vector2 min;
+ min.x = MIN(custom_transform[0].x,min.x);
+ min.y = MIN(custom_transform[0].y,min.y);
+ min.x = MIN(custom_transform[1].x,min.x);
+ min.y = MIN(custom_transform[1].y,min.y);
+ return min;
+ } break;
+ }
+
+ return Vector2();
+
+}
+
+TileMap::HalfOffset TileMap::get_half_offset() const {
+ return half_offset;
+}
+
+Matrix32 TileMap::get_cell_transform() const {
+
+ switch(mode) {
+
+ case MODE_SQUARE: {
+
+ Matrix32 m;
+ m[0]*=cell_size.x;
+ m[1]*=cell_size.y;
+ return m;
+ } break;
+ case MODE_ISOMETRIC: {
+
+ //isometric only makes sense when y is positive in both x and y vectors, otherwise
+ //the drawing of tiles will overlap
+ Matrix32 m;
+ m[0]=Vector2(cell_size.x*0.5,cell_size.y*0.5);
+ m[1]=Vector2(-cell_size.x*0.5,cell_size.y*0.5);
+ return m;
+
+ } break;
+ case MODE_CUSTOM: {
+
+ return custom_transform;
+ } break;
+ }
+
+ return Matrix32();
+}
+
+void TileMap::set_custom_transform(const Matrix32& p_xform) {
+
+ _clear_quadrants();
+ custom_transform=p_xform;
+ _recreate_quadrants();
+ emit_signal("settings_changed");
+
+}
+
+Matrix32 TileMap::get_custom_transform() const{
+
+ return custom_transform;
+}
+
+Vector2 TileMap::_map_to_world(int x,int y,bool p_ignore_ofs) const {
+
+ Vector2 ret = get_cell_transform().xform(Vector2(x,y));
+ if (!p_ignore_ofs) {
+ switch(half_offset) {
+
+ case HALF_OFFSET_X: {
+ if (ABS(y)&1) {
+
+ ret+=get_cell_transform()[0]*0.5;
+ }
+ } break;
+ case HALF_OFFSET_Y: {
+ if (ABS(x)&1) {
+ ret+=get_cell_transform()[1]*0.5;
+ }
+ } break;
+ default: {}
+ }
+ }
+ return ret;
+}
+Vector2 TileMap::map_to_world(const Vector2& p_pos,bool p_ignore_ofs) const {
+
+ return _map_to_world(p_pos.x,p_pos.y,p_ignore_ofs);
+}
+Vector2 TileMap::world_to_map(const Vector2& p_pos) const{
+
+ Vector2 ret = get_cell_transform().affine_inverse().xform(p_pos);
+
+
+ switch(half_offset) {
+
+ case HALF_OFFSET_X: {
+ if ( ret.y > 0 ? int(ret.y)&1 : (int(ret.y)-1)&1 ) {
+ ret.x-=0.5;
+ }
+ } break;
+ case HALF_OFFSET_Y: {
+ if ( ret.x > 0 ? int(ret.x)&1 : (int(ret.x)-1)&1) {
+ ret.y-=0.5;
+ }
+ } break;
+ default: {}
+ }
+
+ return ret.floor();
+}
+
+void TileMap::set_y_sort_mode(bool p_enable) {
+
+ _clear_quadrants();
+ y_sort_mode=p_enable;
+ VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(),y_sort_mode);
+ _recreate_quadrants();
+ emit_signal("settings_changed");
+
+}
+
+bool TileMap::is_y_sort_mode_enabled() const {
+
+ return y_sort_mode;
+}
+
+Array TileMap::get_used_cells() const {
+
+ Array a;
+ a.resize(tile_map.size());
+ int i=0;
+ for (Map<PosKey,Cell>::Element *E=tile_map.front();E;E=E->next()) {
+
+ Vector2 p (E->key().x,E->key().y);
+ a[i++]=p;
+ }
+
+ return a;
+}
void TileMap::_bind_methods() {
@@ -603,21 +1081,44 @@ void TileMap::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_tileset","tileset:TileSet"),&TileMap::set_tileset);
ObjectTypeDB::bind_method(_MD("get_tileset:TileSet"),&TileMap::get_tileset);
+ ObjectTypeDB::bind_method(_MD("set_mode","mode"),&TileMap::set_mode);
+ ObjectTypeDB::bind_method(_MD("get_mode"),&TileMap::get_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_half_offset","half_offset"),&TileMap::set_half_offset);
+ ObjectTypeDB::bind_method(_MD("get_half_offset"),&TileMap::get_half_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_custom_transform","custom_transform"),&TileMap::set_custom_transform);
+ ObjectTypeDB::bind_method(_MD("get_custom_transform"),&TileMap::get_custom_transform);
ObjectTypeDB::bind_method(_MD("set_cell_size","size"),&TileMap::set_cell_size);
ObjectTypeDB::bind_method(_MD("get_cell_size"),&TileMap::get_cell_size);
+ ObjectTypeDB::bind_method(_MD("_set_old_cell_size","size"),&TileMap::_set_old_cell_size);
+ ObjectTypeDB::bind_method(_MD("_get_old_cell_size"),&TileMap::_get_old_cell_size);
+
ObjectTypeDB::bind_method(_MD("set_quadrant_size","size"),&TileMap::set_quadrant_size);
ObjectTypeDB::bind_method(_MD("get_quadrant_size"),&TileMap::get_quadrant_size);
+ ObjectTypeDB::bind_method(_MD("set_tile_origin","origin"),&TileMap::set_tile_origin);
+ ObjectTypeDB::bind_method(_MD("get_tile_origin"),&TileMap::get_tile_origin);
+
ObjectTypeDB::bind_method(_MD("set_center_x","enable"),&TileMap::set_center_x);
ObjectTypeDB::bind_method(_MD("get_center_x"),&TileMap::get_center_x);
ObjectTypeDB::bind_method(_MD("set_center_y","enable"),&TileMap::set_center_y);
ObjectTypeDB::bind_method(_MD("get_center_y"),&TileMap::get_center_y);
- ObjectTypeDB::bind_method(_MD("set_collision_layer_mask","mask"),&TileMap::set_collision_layer_mask);
- ObjectTypeDB::bind_method(_MD("get_collision_layer_mask"),&TileMap::get_collision_layer_mask);
+ ObjectTypeDB::bind_method(_MD("set_y_sort_mode","enable"),&TileMap::set_y_sort_mode);
+ ObjectTypeDB::bind_method(_MD("is_y_sort_mode_enabled"),&TileMap::is_y_sort_mode_enabled);
+
+ ObjectTypeDB::bind_method(_MD("set_collision_use_kinematic","use_kinematic"),&TileMap::set_collision_use_kinematic);
+ ObjectTypeDB::bind_method(_MD("get_collision_use_kinematic"),&TileMap::get_collision_use_kinematic);
+
+ ObjectTypeDB::bind_method(_MD("set_collision_layer","mask"),&TileMap::set_collision_layer);
+ ObjectTypeDB::bind_method(_MD("get_collision_layer"),&TileMap::get_collision_layer);
+
+ ObjectTypeDB::bind_method(_MD("set_collision_mask","mask"),&TileMap::set_collision_mask);
+ ObjectTypeDB::bind_method(_MD("get_collision_mask"),&TileMap::get_collision_mask);
ObjectTypeDB::bind_method(_MD("set_collision_friction","value"),&TileMap::set_collision_friction);
ObjectTypeDB::bind_method(_MD("get_collision_friction"),&TileMap::get_collision_friction);
@@ -625,13 +1126,19 @@ 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_cell","x","y","tile","flip_x","flip_y"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false));
+ 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);
ObjectTypeDB::bind_method(_MD("clear"),&TileMap::clear);
+ ObjectTypeDB::bind_method(_MD("get_used_cells"),&TileMap::get_used_cells);
+
+ ObjectTypeDB::bind_method(_MD("map_to_world","mappos","ignore_half_ofs"),&TileMap::map_to_world,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("world_to_map","worldpos"),&TileMap::world_to_map);
+
ObjectTypeDB::bind_method(_MD("_clear_quadrants"),&TileMap::_clear_quadrants);
ObjectTypeDB::bind_method(_MD("_recreate_quadrants"),&TileMap::_recreate_quadrants);
ObjectTypeDB::bind_method(_MD("_update_dirty_quadrants"),&TileMap::_update_dirty_quadrants);
@@ -639,17 +1146,35 @@ void TileMap::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_set_tile_data"),&TileMap::_set_tile_data);
ObjectTypeDB::bind_method(_MD("_get_tile_data"),&TileMap::_get_tile_data);
- ADD_PROPERTY( PropertyInfo(Variant::INT,"cell_size",PROPERTY_HINT_RANGE,"1,8192,1"),_SCS("set_cell_size"),_SCS("get_cell_size"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Square,Isometric,Custom"),_SCS("set_mode"),_SCS("get_mode"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_set",PROPERTY_HINT_RESOURCE_TYPE,"TileSet"),_SCS("set_tileset"),_SCS("get_tileset"));
- ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"cell_size",PROPERTY_HINT_RANGE,"1,8192,1",0),_SCS("_set_old_cell_size"),_SCS("_get_old_cell_size"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"cell/size",PROPERTY_HINT_RANGE,"1,8192,1"),_SCS("set_cell_size"),_SCS("get_cell_size"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size"));
+ ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"cell/custom_transform"),_SCS("set_custom_transform"),_SCS("get_custom_transform"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/half_offset",PROPERTY_HINT_ENUM,"Offset X,Offset Y,Disabled"),_SCS("set_half_offset"),_SCS("get_half_offset"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/tile_origin",PROPERTY_HINT_ENUM,"Top Left,Center"),_SCS("set_tile_origin"),_SCS("get_tile_origin"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"cell/y_sort"),_SCS("set_y_sort_mode"),_SCS("is_y_sort_mode_enabled"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collision/use_kinematic",PROPERTY_HINT_NONE,""),_SCS("set_collision_use_kinematic"),_SCS("get_collision_use_kinematic"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_friction"),_SCS("get_collision_friction"));
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_mask"),_SCS("get_collision_layer_mask"));
+ 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::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data"));
ADD_SIGNAL(MethodInfo("settings_changed"));
BIND_CONSTANT( INVALID_CELL );
+ BIND_CONSTANT( MODE_SQUARE );
+ BIND_CONSTANT( MODE_ISOMETRIC );
+ BIND_CONSTANT( MODE_CUSTOM );
+ BIND_CONSTANT( HALF_OFFSET_X );
+ BIND_CONSTANT( HALF_OFFSET_Y );
+ BIND_CONSTANT( HALF_OFFSET_DISABLED );
+ BIND_CONSTANT( TILE_ORIGIN_TOP_LEFT );
+ BIND_CONSTANT( TILE_ORIGIN_CENTER );
+
}
TileMap::TileMap() {
@@ -658,16 +1183,23 @@ TileMap::TileMap() {
rect_cache_dirty=true;
pending_update=false;
+ quadrant_order_dirty=false;
quadrant_size=16;
- cell_size=64;
+ cell_size=Size2(64,64);
center_x=false;
center_y=false;
collision_layer=1;
+ collision_mask=1;
friction=1;
bounce=0;
-
- fp_adjust=0.01;
- fp_adjust=0.01;
+ mode=MODE_SQUARE;
+ half_offset=HALF_OFFSET_DISABLED;
+ use_kinematic=false;
+ navigation=NULL;
+ y_sort_mode=false;
+
+ fp_adjust=0.00001;
+ tile_origin=TILE_ORIGIN_TOP_LEFT;
}
TileMap::~TileMap() {
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 4b4d948923..60534cce15 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,6 +30,7 @@
#define TILE_MAP_H
#include "scene/2d/node_2d.h"
+#include "scene/2d/navigation2d.h"
#include "scene/resources/tile_set.h"
#include "self_list.h"
#include "vset.h"
@@ -37,12 +38,38 @@
class TileMap : public Node2D {
OBJ_TYPE( TileMap, Node2D );
+public:
+ enum Mode {
+ MODE_SQUARE,
+ MODE_ISOMETRIC,
+ MODE_CUSTOM
+ };
+
+ enum HalfOffset {
+ HALF_OFFSET_X,
+ HALF_OFFSET_Y,
+ HALF_OFFSET_DISABLED,
+ };
+
+ enum TileOrigin {
+ TILE_ORIGIN_TOP_LEFT,
+ TILE_ORIGIN_CENTER
+ };
+
+
+private:
Ref<TileSet> tile_set;
- int cell_size;
+ Size2i cell_size;
int quadrant_size;
bool center_x,center_y;
+ Mode mode;
+ Matrix32 custom_transform;
+ HalfOffset half_offset;
+ bool use_kinematic;
+ Navigation2D *navigation;
+
union PosKey {
@@ -50,12 +77,13 @@ class TileMap : public Node2D {
int16_t x;
int16_t y;
};
-
uint32_t key;
- bool operator<(const PosKey& pk) const { return key<pk.key; }
+
+ //using a more precise comparison so the regions can be sorted later
+ bool operator<(const PosKey& p_k) const { return (y==p_k.y) ? x < p_k.x : y < p_k.y; }
PosKey(int16_t p_x, int16_t p_y) { x=p_x; y=p_y; }
- PosKey() { key=0; }
+ PosKey() { x=0; y=0; }
};
@@ -66,6 +94,7 @@ class TileMap : public Node2D {
int32_t id:24;
bool flip_h:1;
bool flip_v:1;
+ bool transpose:1;
};
uint32_t _u32t;
@@ -77,15 +106,29 @@ class TileMap : public Node2D {
struct Quadrant {
Vector2 pos;
- RID canvas_item;
- RID static_body;
+ List<RID> canvas_items;
+ RID body;
SelfList<Quadrant> dirty_list;
+ struct NavPoly {
+ int id;
+ Matrix32 xform;
+ };
+
+ struct Occluder {
+ RID id;
+ Matrix32 xform;
+ };
+
+
+ Map<PosKey,NavPoly> navpoly_ids;
+ Map<PosKey,Occluder> occluder_instances;
+
VSet<PosKey> cells;
- void operator=(const Quadrant& q) { pos=q.pos; canvas_item=q.canvas_item; static_body=q.static_body; cells=q.cells; }
- Quadrant(const Quadrant& q) : dirty_list(this) { pos=q.pos; canvas_item=q.canvas_item; static_body=q.static_body; cells=q.cells;}
+ void operator=(const Quadrant& q) { pos=q.pos; canvas_items=q.canvas_items; body=q.body; cells=q.cells; navpoly_ids=q.navpoly_ids; occluder_instances=q.occluder_instances; }
+ Quadrant(const Quadrant& q) : dirty_list(this) { pos=q.pos; canvas_items=q.canvas_items; body=q.body; cells=q.cells; occluder_instances=q.occluder_instances; navpoly_ids=q.navpoly_ids;}
Quadrant() : dirty_list(this) {}
};
@@ -97,11 +140,17 @@ class TileMap : public Node2D {
Rect2 rect_cache;
bool rect_cache_dirty;
+ bool quadrant_order_dirty;
+ bool y_sort_mode;
float fp_adjust;
float friction;
float bounce;
uint32_t collision_layer;
+ uint32_t collision_mask;
+
+ TileOrigin tile_origin;
+ 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);
void _erase_quadrant(Map<PosKey,Quadrant>::Element *Q);
@@ -113,8 +162,19 @@ class TileMap : public Node2D {
void _update_quadrant_transform();
void _recompute_rect_cache();
+ _FORCE_INLINE_ int _get_quadrant_size() const;
+
+
void _set_tile_data(const DVector<int>& p_data);
DVector<int> _get_tile_data() const;
+
+ void _set_old_cell_size(int p_size) { set_cell_size(Size2(p_size,p_size)); }
+ int _get_old_cell_size() const { return cell_size.x; }
+
+ _FORCE_INLINE_ Vector2 _map_to_world(int p_x,int p_y,bool p_ignore_ofs=false) const;
+
+ Array get_used_cells() const;
+
protected:
@@ -130,8 +190,8 @@ public:
void set_tileset(const Ref<TileSet>& p_tileset);
Ref<TileSet> get_tileset() const;
- void set_cell_size(int p_size);
- int get_cell_size() const;
+ void set_cell_size(Size2 p_size);
+ Size2 get_cell_size() const;
void set_quadrant_size(int p_size);
int get_quadrant_size() const;
@@ -141,15 +201,24 @@ public:
void set_center_y(bool p_enable);
bool get_center_y() const;
- void set_cell(int p_x,int p_y,int p_tile,bool p_flip_x=false,bool p_flip_y=false);
+ void set_cell(int p_x,int p_y,int p_tile,bool p_flip_x=false,bool p_flip_y=false,bool p_transpose=false);
int get_cell(int p_x,int p_y) const;
bool is_cell_x_flipped(int p_x,int p_y) const;
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_mask(uint32_t p_layer);
- uint32_t get_collision_layer_mask() const;
+ void set_collision_layer(uint32_t p_layer);
+ uint32_t get_collision_layer() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_use_kinematic(bool p_use_kinematic);
+ bool get_collision_use_kinematic() const;
void set_collision_friction(float p_friction);
float get_collision_friction() const;
@@ -157,10 +226,35 @@ public:
void set_collision_bounce(float p_bounce);
float get_collision_bounce() const;
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ void set_half_offset(HalfOffset p_half_offset);
+ HalfOffset get_half_offset() const;
+
+ void set_tile_origin(TileOrigin p_tile_origin);
+ TileOrigin get_tile_origin() const;
+
+ void set_custom_transform(const Matrix32& p_xform);
+ Matrix32 get_custom_transform() const;
+
+ Matrix32 get_cell_transform() const;
+ Vector2 get_cell_draw_offset() const;
+
+ Vector2 map_to_world(const Vector2& p_pos, bool p_ignore_ofs=false) const;
+ Vector2 world_to_map(const Vector2& p_pos) const;
+
+ void set_y_sort_mode(bool p_enable);
+ bool is_y_sort_mode_enabled() const;
+
void clear();
TileMap();
~TileMap();
};
+VARIANT_ENUM_CAST(TileMap::Mode);
+VARIANT_ENUM_CAST(TileMap::HalfOffset);
+VARIANT_ENUM_CAST(TileMap::TileOrigin);
+
#endif // TILE_MAP_H
diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp
index c76c18a595..dc72c9a267 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,6 +32,7 @@
#include "scene/2d/physics_body_2d.h"
#include "scene/animation/animation_player.h"
#include "scene/scene_string_names.h"
+#include "particles_2d.h"
void VisibilityNotifier2D::_enter_viewport(Viewport* p_viewport) {
@@ -64,8 +65,13 @@ void VisibilityNotifier2D::_exit_viewport(Viewport* p_viewport){
void VisibilityNotifier2D::set_rect(const Rect2& p_rect){
rect=p_rect;
- if (is_inside_scene())
+ if (is_inside_tree()) {
get_world_2d()->_update_notifier(this,get_global_transform().xform(rect));
+ if (get_tree()->is_editor_hint()) {
+ update();
+ item_rect_changed();
+ }
+ }
_change_notify("rect");
}
@@ -85,7 +91,7 @@ void VisibilityNotifier2D::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
//get_world_2d()->
get_world_2d()->_register_notifier(this,get_global_transform().xform(rect));
@@ -97,12 +103,12 @@ void VisibilityNotifier2D::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- if (get_scene()->is_editor_hint()) {
+ if (get_tree()->is_editor_hint()) {
draw_rect(rect,Color(1,0.5,1,0.2));
}
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
get_world_2d()->_remove_notifier(this);
} break;
@@ -149,6 +155,11 @@ void VisibilityEnabler2D::_screen_enter() {
_change_node_state(E->key(),true);
}
+ if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent())
+ get_parent()->set_fixed_process(true);
+ if (enabler[ENABLER_PARENT_PROCESS] && get_parent())
+ get_parent()->set_process(true);
+
visible=true;
}
@@ -159,6 +170,11 @@ void VisibilityEnabler2D::_screen_exit(){
_change_node_state(E->key(),false);
}
+ if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent())
+ get_parent()->set_fixed_process(false);
+ if (enabler[ENABLER_PARENT_PROCESS] && get_parent())
+ get_parent()->set_process(false);
+
visible=false;
}
@@ -188,9 +204,18 @@ void VisibilityEnabler2D::_find_nodes(Node* p_node) {
}
+ if (enabler[ENABLER_PAUSE_PARTICLES]) {
+
+ Particles2D *ps = p_node->cast_to<Particles2D>();
+ if (ps) {
+ add=true;
+ }
+
+ }
+
if (add) {
- p_node->connect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed",varray(p_node),CONNECT_ONESHOT);
+ p_node->connect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed",varray(p_node),CONNECT_ONESHOT);
nodes[p_node]=meta;
_change_node_state(p_node,false);
}
@@ -207,9 +232,9 @@ void VisibilityEnabler2D::_find_nodes(Node* p_node) {
void VisibilityEnabler2D::_notification(int p_what){
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
- if (get_scene()->is_editor_hint())
+ if (get_tree()->is_editor_hint())
return;
@@ -220,11 +245,17 @@ void VisibilityEnabler2D::_notification(int p_what){
_find_nodes(from);
+ if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent())
+ get_parent()->set_fixed_process(false);
+ if (enabler[ENABLER_PARENT_PROCESS] && get_parent())
+ get_parent()->set_process(false);
+
+
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
- if (get_scene()->is_editor_hint())
+ if (get_tree()->is_editor_hint())
return;
@@ -235,7 +266,7 @@ void VisibilityEnabler2D::_notification(int p_what){
if (!visible)
_change_node_state(E->key(),true);
- E->key()->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed");
+ E->key()->disconnect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed");
}
nodes.clear();
@@ -254,10 +285,10 @@ void VisibilityEnabler2D::_change_node_state(Node* p_node,bool p_enabled) {
if (p_enabled) {
RigidBody2D::Mode mode = RigidBody2D::Mode(nodes[p_node].operator int());
//rb->set_mode(mode);
- rb->set_active(true);
+ rb->set_sleeping(false);
} else {
//rb->set_mode(RigidBody2D::MODE_STATIC);
- rb->set_active(false);
+ rb->set_sleeping(true);
}
}
}
@@ -271,6 +302,15 @@ void VisibilityEnabler2D::_change_node_state(Node* p_node,bool p_enabled) {
}
}
+ {
+ Particles2D *ps=p_node->cast_to<Particles2D>();
+
+ if (ps) {
+
+ ps->set_emitting(p_enabled);
+ }
+ }
+
}
@@ -292,9 +332,15 @@ void VisibilityEnabler2D::_bind_methods(){
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_animations"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATIONS );
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/freeze_bodies"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_FREEZE_BODIES);
+ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_particles"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_PARTICLES);
+ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/process_parent"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PARENT_PROCESS);
+ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/fixed_process_parent"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PARENT_FIXED_PROCESS);
BIND_CONSTANT( ENABLER_FREEZE_BODIES );
BIND_CONSTANT( ENABLER_PAUSE_ANIMATIONS );
+ BIND_CONSTANT( ENABLER_PAUSE_PARTICLES );
+ BIND_CONSTANT( ENABLER_PARENT_PROCESS );
+ BIND_CONSTANT( ENABLER_PARENT_FIXED_PROCESS );
BIND_CONSTANT( ENABLER_MAX);
}
@@ -315,8 +361,11 @@ VisibilityEnabler2D::VisibilityEnabler2D() {
for(int i=0;i<ENABLER_MAX;i++)
enabler[i]=true;
+ enabler[ENABLER_PARENT_PROCESS]=false;
+ enabler[ENABLER_PARENT_FIXED_PROCESS]=false;
visible=false;
}
+
diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h
index cdf52ecb27..1f7e4c6d45 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -73,6 +73,9 @@ public:
enum Enabler {
ENABLER_PAUSE_ANIMATIONS,
ENABLER_FREEZE_BODIES,
+ ENABLER_PAUSE_PARTICLES,
+ ENABLER_PARENT_PROCESS,
+ ENABLER_PARENT_FIXED_PROCESS,
ENABLER_MAX
};
diff --git a/scene/2d/y_sort.cpp b/scene/2d/y_sort.cpp
new file mode 100644
index 0000000000..d441abfaf1
--- /dev/null
+++ b/scene/2d/y_sort.cpp
@@ -0,0 +1,29 @@
+#include "y_sort.h"
+
+
+
+void YSort::set_sort_enabled(bool p_enabled) {
+
+ sort_enabled=p_enabled;
+ VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(),sort_enabled);
+}
+
+bool YSort::is_sort_enabled() const {
+
+ return sort_enabled;
+}
+
+void YSort::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_sort_enabled","enabled"),&YSort::set_sort_enabled);
+ ObjectTypeDB::bind_method(_MD("is_sort_enabled"),&YSort::is_sort_enabled);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"sort/enabled"),_SCS("set_sort_enabled"),_SCS("is_sort_enabled"));
+}
+
+
+YSort::YSort() {
+
+ sort_enabled=true;
+ VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(),true);
+}
diff --git a/scene/2d/y_sort.h b/scene/2d/y_sort.h
new file mode 100644
index 0000000000..6d04a67e42
--- /dev/null
+++ b/scene/2d/y_sort.h
@@ -0,0 +1,17 @@
+#ifndef Y_SORT_H
+#define Y_SORT_H
+
+#include "scene/2d/node_2d.h"
+
+class YSort : public Node2D {
+ OBJ_TYPE(YSort,Node2D);
+ bool sort_enabled;
+ static void _bind_methods();
+public:
+
+ void set_sort_enabled(bool p_enabled);
+ bool is_sort_enabled() const;
+ YSort();
+};
+
+#endif // Y_SORT_H
diff --git a/scene/3d/SCsub b/scene/3d/SCsub
index 6789851aab..116e641593 100644
--- a/scene/3d/SCsub
+++ b/scene/3d/SCsub
@@ -1,14 +1,11 @@
Import('env')
-print("V: "+env["disable_3d"])
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 964a086cf6..ff35837bc0 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -52,6 +52,17 @@ bool Area::is_gravity_a_point() const{
return gravity_is_point;
}
+void Area::set_gravity_distance_scale(real_t p_scale){
+
+ gravity_distance_scale=p_scale;
+ PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE,p_scale);
+
+}
+
+real_t Area::get_gravity_distance_scale() const{
+ return gravity_distance_scale;
+}
+
void Area::set_gravity_vector(const Vector3& p_vec){
gravity_vec=p_vec;
@@ -72,15 +83,25 @@ real_t Area::get_gravity() const{
return gravity;
}
+void Area::set_linear_damp(real_t p_linear_damp){
+
+ 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;
+}
-void Area::set_density(real_t p_density){
+void Area::set_angular_damp(real_t p_angular_damp){
- density=p_density;
- PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_DENSITY,p_density);
+ 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){
@@ -94,7 +115,7 @@ real_t Area::get_priority() const{
}
-void Area::_body_enter_scene(ObjectID p_id) {
+void Area::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = obj ? obj->cast_to<Node>() : NULL;
@@ -102,9 +123,9 @@ void Area::_body_enter_scene(ObjectID p_id) {
Map<ObjectID,BodyState>::Element *E=body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_scene);
+ ERR_FAIL_COND(E->get().in_tree);
- E->get().in_scene=true;
+ E->get().in_tree=true;
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
for(int i=0;i<E->get().shapes.size();i++) {
@@ -113,15 +134,16 @@ void Area::_body_enter_scene(ObjectID p_id) {
}
-void Area::_body_exit_scene(ObjectID p_id) {
+void Area::_body_exit_tree(ObjectID p_id) {
+
Object *obj = ObjectDB::get_instance(p_id);
Node *node = obj ? obj->cast_to<Node>() : NULL;
ERR_FAIL_COND(!node);
Map<ObjectID,BodyState>::Element *E=body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_scene);
- E->get().in_scene=false;
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree=false;
emit_signal(SceneStringNames::get_singleton()->body_exit,node);
for(int i=0;i<E->get().shapes.size();i++) {
@@ -132,6 +154,7 @@ void Area::_body_exit_scene(ObjectID p_id) {
void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape) {
+
bool body_in = p_status==PhysicsServer::AREA_BODY_ADDED;
ObjectID objid=p_instance;
@@ -142,16 +165,18 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod
ERR_FAIL_COND(!body_in && !E);
+ locked=true;
+
if (body_in) {
if (!E) {
E = body_map.insert(objid,BodyState());
E->get().rc=0;
- E->get().in_scene=node && node->is_inside_scene();
+ E->get().in_tree=node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid));
- if (E->get().in_scene) {
+ node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree,make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree,make_binds(objid));
+ if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
}
}
@@ -162,7 +187,7 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod
E->get().shapes.insert(ShapePair(p_body_shape,p_area_shape));
- if (E->get().in_scene) {
+ if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_area_shape);
}
@@ -178,9 +203,9 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod
if (E->get().rc==0) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene);
- node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene);
- if (E->get().in_scene)
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
+ if (E->get().in_tree)
emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
}
@@ -188,7 +213,7 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod
eraseit=true;
}
- if (node && E->get().in_scene) {
+ if (node && E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_area_shape);
}
@@ -197,44 +222,86 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod
}
+ locked=false;
+
+
}
void Area::_clear_monitoring() {
- Map<ObjectID,BodyState> bmcopy = body_map;
- body_map.clear();
- //disconnect all monitored stuff
+ if (locked) {
+ ERR_EXPLAIN("This function can't be used during the in/out signal.");
+ }
+ ERR_FAIL_COND(locked);
- for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) {
+ {
+ Map<ObjectID,BodyState> bmcopy = body_map;
+ body_map.clear();
+ //disconnect all monitored stuff
- Object *obj = ObjectDB::get_instance(E->key());
- Node *node = obj ? obj->cast_to<Node>() : NULL;
- ERR_CONTINUE(!node);
- if (!E->get().in_scene)
- continue;
+ for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) {
+
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_CONTINUE(!node);
+ if (!E->get().in_tree)
+ continue;
+
+ for(int i=0;i<E->get().shapes.size();i++) {
- for(int i=0;i<E->get().shapes.size();i++) {
+ emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
- emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape);
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
}
- emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
+ }
+
+ {
+
+ Map<ObjectID,AreaState> bmcopy = area_map;
+ area_map.clear();
+ //disconnect all monitored stuff
+
+ for (Map<ObjectID,AreaState>::Element *E=bmcopy.front();E;E=E->next()) {
+
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_CONTINUE(!node);
+ if (!E->get().in_tree)
+ continue;
+
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,E->key(),node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit,obj);
- node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene);
- node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene);
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree);
+ }
}
}
void Area::_notification(int p_what) {
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
_clear_monitoring();
}
}
void Area::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;
@@ -242,11 +309,128 @@ 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_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());
_clear_monitoring();
+
+ }
+}
+
+
+void Area::_area_enter_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_FAIL_COND(!node);
+
+ Map<ObjectID,AreaState>::Element *E=area_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(E->get().in_tree);
+
+ E->get().in_tree=true;
+ emit_signal(SceneStringNames::get_singleton()->area_enter,node);
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_enter_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+ }
+
+}
+
+void Area::_area_exit_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_FAIL_COND(!node);
+ Map<ObjectID,AreaState>::Element *E=area_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree=false;
+ emit_signal(SceneStringNames::get_singleton()->area_exit,node);
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
}
+
+}
+
+void Area::_area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape) {
+
+
+ bool area_in = p_status==PhysicsServer::AREA_BODY_ADDED;
+ ObjectID objid=p_instance;
+
+ Object *obj = ObjectDB::get_instance(objid);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+
+ Map<ObjectID,AreaState>::Element *E=area_map.find(objid);
+
+ ERR_FAIL_COND(!area_in && !E);
+
+ locked=true;
+
+ if (area_in) {
+ if (!E) {
+
+ E = area_map.insert(objid,AreaState());
+ E->get().rc=0;
+ E->get().in_tree=node && node->is_inside_tree();
+ if (node) {
+ node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree,make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree,make_binds(objid));
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_enter,node);
+
+ }
+ }
+
+ }
+ E->get().rc++;
+ if (node)
+ E->get().shapes.insert(AreaShapePair(p_area_shape,p_self_shape));
+
+
+ if (!node || E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_enter_shape,objid,node,p_area_shape,p_self_shape);
+ }
+
+ } else {
+
+ E->get().rc--;
+
+ if (node)
+ E->get().shapes.erase(AreaShapePair(p_area_shape,p_self_shape));
+
+ bool eraseit=false;
+
+ if (E->get().rc==0) {
+
+ if (node) {
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree);
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_exit,obj);
+ }
+
+ }
+
+ eraseit=true;
+
+ }
+ if (!node || E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,objid,obj,p_area_shape,p_self_shape);
+ }
+
+ if (eraseit)
+ area_map.erase(E);
+
+ }
+
+ locked=false;
+
+
}
bool Area::is_monitoring_enabled() const {
@@ -255,10 +439,94 @@ bool Area::is_monitoring_enabled() const {
}
+Array Area::get_overlapping_bodies() const {
+
+ ERR_FAIL_COND_V(!monitoring,Array());
+ Array ret;
+ ret.resize(body_map.size());
+ int idx=0;
+ for (const Map<ObjectID,BodyState>::Element *E=body_map.front();E;E=E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize( ret.size() -1 ); //ops
+ } else {
+ ret[idx++]=obj;
+ }
+
+ }
+
+ return ret;
+}
+
+void Area::set_monitorable(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==monitorable)
+ return;
+
+ monitorable=p_enable;
+
+ PhysicsServer::get_singleton()->area_set_monitorable(get_rid(),monitorable);
+}
+
+bool Area::is_monitorable() const {
+
+ return monitorable;
+}
+
+
+Array Area::get_overlapping_areas() const {
+
+ ERR_FAIL_COND_V(!monitoring,Array());
+ Array ret;
+ ret.resize(area_map.size());
+ int idx=0;
+ for (const Map<ObjectID,AreaState>::Element *E=area_map.front();E;E=E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize( ret.size() -1 ); //ops
+ } else {
+ ret[idx++]=obj;
+ }
+
+ }
+
+ return ret;
+}
+
+bool Area::overlaps_area(Node* p_area) const {
+
+ ERR_FAIL_NULL_V(p_area,false);
+ const Map<ObjectID,AreaState>::Element *E=area_map.find(p_area->get_instance_ID());
+ if (!E)
+ return false;
+ return E->get().in_tree;
+
+
+
+}
+
+bool Area::overlaps_body(Node* p_body) const{
+
+ ERR_FAIL_NULL_V(p_body,false);
+ const Map<ObjectID,BodyState>::Element *E=body_map.find(p_body->get_instance_ID());
+ if (!E)
+ return false;
+ return E->get().in_tree;
+
+}
+
void Area::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("_body_enter_scene","id"),&Area::_body_enter_scene);
- ObjectTypeDB::bind_method(_MD("_body_exit_scene","id"),&Area::_body_exit_scene);
+ ObjectTypeDB::bind_method(_MD("_body_enter_tree","id"),&Area::_body_enter_tree);
+ ObjectTypeDB::bind_method(_MD("_body_exit_tree","id"),&Area::_body_exit_tree);
+
+ ObjectTypeDB::bind_method(_MD("_area_enter_tree","id"),&Area::_area_enter_tree);
+ ObjectTypeDB::bind_method(_MD("_area_exit_tree","id"),&Area::_area_exit_tree);
ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area::set_space_override_mode);
ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area::get_space_override_mode);
@@ -266,22 +534,39 @@ void Area::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_gravity_is_point","enable"),&Area::set_gravity_is_point);
ObjectTypeDB::bind_method(_MD("is_gravity_a_point"),&Area::is_gravity_a_point);
+ ObjectTypeDB::bind_method(_MD("set_gravity_distance_scale","distance_scale"),&Area::set_gravity_distance_scale);
+ ObjectTypeDB::bind_method(_MD("get_gravity_distance_scale"),&Area::get_gravity_distance_scale);
+
ObjectTypeDB::bind_method(_MD("set_gravity_vector","vector"),&Area::set_gravity_vector);
ObjectTypeDB::bind_method(_MD("get_gravity_vector"),&Area::get_gravity_vector);
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);
+ ObjectTypeDB::bind_method(_MD("set_monitorable","enable"),&Area::set_monitorable);
+ ObjectTypeDB::bind_method(_MD("is_monitorable"),&Area::is_monitorable);
+
+
ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area::set_enable_monitoring);
ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area::is_monitoring_enabled);
+ ObjectTypeDB::bind_method(_MD("get_overlapping_bodies"),&Area::get_overlapping_bodies);
+ ObjectTypeDB::bind_method(_MD("get_overlapping_areas"),&Area::get_overlapping_areas);
+
+ ObjectTypeDB::bind_method(_MD("overlaps_body:PhysicsBody","body"),&Area::overlaps_body);
+ ObjectTypeDB::bind_method(_MD("overlaps_area:Area","area"),&Area::overlaps_area);
+
ObjectTypeDB::bind_method(_MD("_body_inout"),&Area::_body_inout);
+ ObjectTypeDB::bind_method(_MD("_area_inout"),&Area::_area_inout);
ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
@@ -289,13 +574,21 @@ void Area::_bind_methods() {
ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body")));
ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body")));
+ ADD_SIGNAL( MethodInfo("area_enter_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("area_exit_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ 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::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"));
}
@@ -303,11 +596,17 @@ Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),tru
space_override=SPACE_OVERRIDE_DISABLED;
set_gravity(9.8);;
+ locked=false;
set_gravity_vector(Vector3(0,-1,0));
gravity_is_point=false;
- density=0.1;
+ gravity_distance_scale=0;
+ linear_damp=0.1;
+ angular_damp=1;
priority=0;
monitoring=false;
+ set_ray_pickable(false);
+ set_enable_monitoring(true);
+ set_monitorable(true);
}
diff --git a/scene/3d/area.h b/scene/3d/area.h
index 79e98f9dab..f03955d1e7 100644
--- a/scene/3d/area.h
+++ b/scene/3d/area.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,14 +49,19 @@ private:
Vector3 gravity_vec;
real_t gravity;
bool gravity_is_point;
- real_t density;
+ real_t gravity_distance_scale;
+ real_t angular_damp;
+ real_t linear_damp;
int priority;
bool monitoring;
+ bool monitorable;
+ bool locked;
+
void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape);
- void _body_enter_scene(ObjectID p_id);
- void _body_exit_scene(ObjectID p_id);
+ void _body_enter_tree(ObjectID p_id);
+ void _body_exit_tree(ObjectID p_id);
struct ShapePair {
@@ -76,11 +81,41 @@ private:
struct BodyState {
int rc;
- bool in_scene;
+ bool in_tree;
VSet<ShapePair> shapes;
};
Map<ObjectID,BodyState> body_map;
+
+
+ void _area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape);
+
+ void _area_enter_tree(ObjectID p_id);
+ void _area_exit_tree(ObjectID p_id);
+
+ struct AreaShapePair {
+
+ int area_shape;
+ int self_shape;
+ bool operator<(const AreaShapePair& p_sp) const {
+ if (area_shape==p_sp.area_shape)
+ return self_shape < p_sp.self_shape;
+ else
+ return area_shape < p_sp.area_shape;
+ }
+
+ AreaShapePair() {}
+ AreaShapePair(int p_bs, int p_as) { area_shape=p_bs; self_shape=p_as; }
+ };
+
+ struct AreaState {
+
+ int rc;
+ bool in_tree;
+ VSet<AreaShapePair> shapes;
+ };
+
+ Map<ObjectID,AreaState> area_map;
void _clear_monitoring();
@@ -96,14 +131,20 @@ public:
void set_gravity_is_point(bool p_enabled);
bool is_gravity_a_point() const;
+ void set_gravity_distance_scale(real_t p_scale);
+ real_t get_gravity_distance_scale() const;
+
void set_gravity_vector(const Vector3& p_vec);
Vector3 get_gravity_vector() const;
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;
@@ -111,6 +152,15 @@ public:
void set_enable_monitoring(bool p_enable);
bool is_monitoring_enabled() const;
+ void set_monitorable(bool p_enable);
+ bool is_monitorable() const;
+
+ Array get_overlapping_bodies() const;
+ Array get_overlapping_areas() const; //function for script
+
+ bool overlaps_area(Node* p_area) const;
+ bool overlaps_body(Node* p_body) const;
+
Area();
~Area();
diff --git a/scene/3d/baked_light_instance.cpp b/scene/3d/baked_light_instance.cpp
index c1cc1f6b68..1ae7866f0b 100644
--- a/scene/3d/baked_light_instance.cpp
+++ b/scene/3d/baked_light_instance.cpp
@@ -63,3 +63,81 @@ BakedLightInstance::BakedLightInstance() {
}
+/////////////////////////
+
+
+void BakedLightSampler::set_param(Param p_param,float p_value) {
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ params[p_param]=p_value;
+ VS::get_singleton()->baked_light_sampler_set_param(base,VS::BakedLightSamplerParam(p_param),p_value);
+}
+
+float BakedLightSampler::get_param(Param p_param) const{
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return params[p_param];
+
+}
+
+void BakedLightSampler::set_resolution(int p_resolution){
+
+ ERR_FAIL_COND(p_resolution<4 || p_resolution>32);
+ resolution=p_resolution;
+ VS::get_singleton()->baked_light_sampler_set_resolution(base,resolution);
+}
+int BakedLightSampler::get_resolution() const {
+
+ return resolution;
+}
+
+AABB BakedLightSampler::get_aabb() const {
+
+ float r = get_param(PARAM_RADIUS);
+ return AABB( Vector3(-r,-r,-r),Vector3(r*2,r*2,r*2));
+}
+DVector<Face3> BakedLightSampler::get_faces(uint32_t p_usage_flags) const {
+ return DVector<Face3>();
+}
+
+void BakedLightSampler::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_param","param","value"),&BakedLightSampler::set_param);
+ ObjectTypeDB::bind_method(_MD("get_param","param"),&BakedLightSampler::get_param);
+
+ ObjectTypeDB::bind_method(_MD("set_resolution","resolution"),&BakedLightSampler::set_resolution);
+ ObjectTypeDB::bind_method(_MD("get_resolution"),&BakedLightSampler::get_resolution);
+
+
+ BIND_CONSTANT( PARAM_RADIUS );
+ BIND_CONSTANT( PARAM_STRENGTH );
+ BIND_CONSTANT( PARAM_ATTENUATION );
+ BIND_CONSTANT( PARAM_DETAIL_RATIO );
+ BIND_CONSTANT( PARAM_MAX );
+
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/radius",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_RADIUS);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/strength",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_STRENGTH);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/attenuation",PROPERTY_HINT_EXP_EASING),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/detail_ratio",PROPERTY_HINT_RANGE,"0.01,1.0,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_DETAIL_RATIO);
+// ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/detail_ratio",PROPERTY_HINT_RANGE,"0,20,1"),_SCS("set_param"),_SCS("get_param"),PARAM_DETAIL_RATIO);
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"params/resolution",PROPERTY_HINT_RANGE,"4,32,1"),_SCS("set_resolution"),_SCS("get_resolution"));
+
+}
+
+BakedLightSampler::BakedLightSampler() {
+
+ base = VS::get_singleton()->baked_light_sampler_create();
+ set_base(base);
+
+ params[PARAM_RADIUS]=1.0;
+ params[PARAM_STRENGTH]=1.0;
+ params[PARAM_ATTENUATION]=1.0;
+ params[PARAM_DETAIL_RATIO]=0.1;
+ resolution=16;
+
+
+}
+
+BakedLightSampler::~BakedLightSampler(){
+
+ VS::get_singleton()->free(base);
+}
diff --git a/scene/3d/baked_light_instance.h b/scene/3d/baked_light_instance.h
index b904ced9a7..0694c813ce 100644
--- a/scene/3d/baked_light_instance.h
+++ b/scene/3d/baked_light_instance.h
@@ -30,4 +30,46 @@ public:
BakedLightInstance();
};
+
+
+class BakedLightSampler : public VisualInstance {
+ OBJ_TYPE(BakedLightSampler,VisualInstance);
+
+
+public:
+
+ enum Param {
+ PARAM_RADIUS=VS::BAKED_LIGHT_SAMPLER_RADIUS,
+ PARAM_STRENGTH=VS::BAKED_LIGHT_SAMPLER_STRENGTH,
+ PARAM_ATTENUATION=VS::BAKED_LIGHT_SAMPLER_ATTENUATION,
+ PARAM_DETAIL_RATIO=VS::BAKED_LIGHT_SAMPLER_DETAIL_RATIO,
+ PARAM_MAX=VS::BAKED_LIGHT_SAMPLER_MAX
+ };
+
+
+
+protected:
+
+ RID base;
+ float params[PARAM_MAX];
+ int resolution;
+ static void _bind_methods();
+public:
+
+ virtual AABB get_aabb() const;
+ virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ void set_param(Param p_param,float p_value);
+ float get_param(Param p_param) const;
+
+ void set_resolution(int p_resolution);
+ int get_resolution() const;
+
+ BakedLightSampler();
+ ~BakedLightSampler();
+};
+
+VARIANT_ENUM_CAST( BakedLightSampler::Param );
+
+
#endif // BAKED_LIGHT_H
diff --git a/scene/3d/body_shape.cpp b/scene/3d/body_shape.cpp
index b291ce7c72..b54cbfe0f9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -43,8 +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();
@@ -72,7 +74,7 @@ void CollisionShape::make_convex_from_brothers() {
}
}
-
+/*
void CollisionShape::_update_indicator() {
@@ -300,47 +302,80 @@ void CollisionShape::_update_indicator() {
}
-
+*/
void CollisionShape::_add_to_collision_object(Object* p_cshape) {
+ if (unparenting)
+ return;
+
CollisionObject *co=p_cshape->cast_to<CollisionObject>();
ERR_FAIL_COND(!co);
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) {
switch(p_what) {
- case NOTIFICATION_ENTER_WORLD: {
- indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario());
+ 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) {
+ // VisualServer::get_singleton()->instance_set_transform(indicator_instance,get_global_transform());
+ if (can_update_body && updating_body) {
_update_body();
}
} break;
- case NOTIFICATION_EXIT_WORLD: {
- if (indicator_instance.is_valid()) {
+ case NOTIFICATION_EXIT_TREE: {
+ /* if (indicator_instance.is_valid()) {
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: {
- if (updating_body)
+ unparenting=true;
+ 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;
+
}
}
@@ -352,6 +387,18 @@ 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
@@ -363,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"));
}
@@ -378,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 {
@@ -400,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{
@@ -411,15 +475,43 @@ bool CollisionShape::is_trigger() const{
CollisionShape::CollisionShape() {
- indicator = VisualServer::get_singleton()->mesh_create();
+ //indicator = VisualServer::get_singleton()->mesh_create();
updating_body=true;
- trigger=false;
+ unparenting=false;
+ update_shape_index=-1;
+ trigger=false;
+ can_update_body=false;
+ debug_shape=NULL;
}
CollisionShape::~CollisionShape() {
if (!shape.is_null())
shape->unregister_owner(this);
- VisualServer::get_singleton()->free(indicator);
+ //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
diff --git a/scene/3d/body_shape.h b/scene/3d/body_shape.h
index d1cb229f70..6c0b89da56 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -37,23 +37,39 @@ class CollisionShape : public Spatial {
OBJ_TYPE( CollisionShape, Spatial );
OBJ_CATEGORY("3D Physics Nodes");
+ Ref<Shape> shape;
+
+ /*
RID _get_visual_instance_rid() const;
- Ref<Shape> shape;
void _update_indicator();
RID material;
RID indicator;
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);
@@ -69,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 cbc4abb7a9..9cc1719f94 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -102,12 +102,12 @@ void BoneAttachment::_check_unbind() {
void BoneAttachment::set_bone_name(const String& p_name) {
- if (is_inside_scene())
+ if (is_inside_tree())
_check_unbind();
bone_name=p_name;
- if (is_inside_scene())
+ if (is_inside_tree())
_check_bind();
}
@@ -120,11 +120,11 @@ void BoneAttachment::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
_check_bind();
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
_check_unbind();
} break;
diff --git a/scene/3d/bone_attachment.h b/scene/3d/bone_attachment.h
index 5043b40fa8..ca36cc3694 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 56fbf358bc..dce5060a44 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -74,16 +74,22 @@ bool Camera::_set(const StringName& p_name, const Variant& p_value) {
mode=PROJECTION_ORTHOGONAL;
changed_all=true;
- } else if (p_name=="fov")
+ } else if (p_name=="fov" || p_name=="fovy" || p_name=="fovx")
fov=p_value;
- else if (p_name=="size")
+ else if (p_name=="size" || p_name=="sizex" || p_name=="sizey")
size=p_value;
else if (p_name=="near")
near=p_value;
else if (p_name=="far")
far=p_value;
+ else if (p_name=="keep_aspect")
+ set_keep_aspect_mode(KeepAspect(int(p_value)));
else if (p_name=="vaspect")
- set_use_vertical_aspect(p_value);
+ set_keep_aspect_mode(p_value?KEEP_WIDTH:KEEP_HEIGHT);
+ else if (p_name=="h_offset")
+ h_offset=p_value;
+ else if (p_name=="v_offset")
+ v_offset=p_value;
else if (p_name=="current") {
if (p_value.operator bool()) {
make_current();
@@ -107,25 +113,29 @@ bool Camera::_get(const StringName& p_name,Variant &r_ret) const {
if (p_name=="projection") {
r_ret= mode;
- } else if (p_name=="fov")
+ } else if (p_name=="fov" || p_name=="fovy" || p_name=="fovx")
r_ret= fov;
- else if (p_name=="size")
+ else if (p_name=="size" || p_name=="sizex" || p_name=="sizey")
r_ret= size;
else if (p_name=="near")
r_ret= near;
else if (p_name=="far")
r_ret= far;
- else if (p_name=="vaspect")
- r_ret= vaspect;
+ else if (p_name=="keep_aspect")
+ r_ret= int(keep_aspect);
else if (p_name=="current") {
- if (is_inside_scene() && get_scene()->is_editor_hint()) {
+ if (is_inside_tree() && get_tree()->is_editor_hint()) {
r_ret=current;
} else {
r_ret=is_current();
}
} else if (p_name=="visible_layers") {
r_ret=get_visible_layers();
+ } else if (p_name=="h_offset") {
+ r_ret=get_h_offset();
+ } else if (p_name=="v_offset") {
+ r_ret=get_v_offset();
} else if (p_name=="environment") {
r_ret=get_environment();
} else
@@ -142,35 +152,49 @@ void Camera::_get_property_list( List<PropertyInfo> *p_list) const {
case PROJECTION_PERSPECTIVE: {
- p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,89,0.1") );
+ p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_NOEDITOR) );
+ if (keep_aspect==KEEP_WIDTH)
+ p_list->push_back( PropertyInfo( Variant::REAL, "fovx" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_EDITOR) );
+ else
+ p_list->push_back( PropertyInfo( Variant::REAL, "fovy" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_EDITOR) );
+
} break;
case PROJECTION_ORTHOGONAL: {
- p_list->push_back( PropertyInfo( Variant::REAL, "size" , PROPERTY_HINT_RANGE, "1,16384,0.01" ) );
+ p_list->push_back( PropertyInfo( Variant::REAL, "size" , PROPERTY_HINT_RANGE, "1,16384,0.01",PROPERTY_USAGE_NOEDITOR ) );
+ if (keep_aspect==KEEP_WIDTH)
+ p_list->push_back( PropertyInfo( Variant::REAL, "sizex" , PROPERTY_HINT_RANGE, "0.1,16384,0.01",PROPERTY_USAGE_EDITOR) );
+ else
+ p_list->push_back( PropertyInfo( Variant::REAL, "sizey" , PROPERTY_HINT_RANGE, "0.1,16384,0.01",PROPERTY_USAGE_EDITOR) );
+
} break;
}
p_list->push_back( PropertyInfo( Variant::REAL, "near" , PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01") );
p_list->push_back( PropertyInfo( Variant::REAL, "far" , PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01") );
- p_list->push_back( PropertyInfo( Variant::BOOL, "vaspect") );
+ p_list->push_back( PropertyInfo( Variant::INT, "keep_aspect",PROPERTY_HINT_ENUM,"Keep Width,Keep Height") );
p_list->push_back( PropertyInfo( Variant::BOOL, "current" ) );
p_list->push_back( PropertyInfo( Variant::INT, "visible_layers",PROPERTY_HINT_ALL_FLAGS ) );
p_list->push_back( PropertyInfo( Variant::OBJECT, "environment",PROPERTY_HINT_RESOURCE_TYPE,"Environment" ) );
+ p_list->push_back( PropertyInfo( Variant::REAL, "h_offset" ) );
+ p_list->push_back( PropertyInfo( Variant::REAL, "v_offset" ) );
}
void Camera::_update_camera() {
Transform tr = get_camera_transform();
+ tr.origin+=tr.basis.get_axis(1)*v_offset;
+ tr.origin+=tr.basis.get_axis(0)*h_offset;
VisualServer::get_singleton()->camera_set_transform( camera, tr );
// here goes listener stuff
// if (viewport_ptr && is_inside_scene() && is_current())
// viewport_ptr->_camera_transform_changed_notify();
- if (is_inside_scene() && is_current()) {
+ if (is_inside_tree() && is_current()) {
if (viewport_ptr) {
viewport_ptr->_camera_transform_changed_notify();
}
@@ -207,11 +231,14 @@ void Camera::_notification(int p_what) {
}
+ 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)
make_current();
+
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -229,6 +256,8 @@ void Camera::_notification(int p_what) {
if (viewport_ptr)
viewport_ptr->cameras.erase(this);
viewport_ptr=NULL;
+ remove_from_group(camera_group);
+
} break;
case NOTIFICATION_BECAME_CURRENT: {
@@ -250,7 +279,7 @@ void Camera::_notification(int p_what) {
Transform Camera::get_camera_transform() const {
- return get_global_transform();
+ return get_global_transform().orthonormalized();
}
void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
@@ -292,7 +321,7 @@ void Camera::make_current() {
current=true;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (viewport_ptr) {
@@ -302,22 +331,40 @@ void Camera::make_current() {
//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() {
current=false;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (viewport_ptr) {
- if (viewport_ptr->get_camera()==this)
+ 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);
+
+ }
}
}
bool Camera::is_current() const {
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
if (viewport_ptr)
return viewport_ptr->get_camera()==this;
} else
@@ -427,12 +474,20 @@ Vector3 Camera::project_ray_normal(const Point2& p_pos) const {
Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
ERR_EXPLAIN("Camera is not inside scene.");
- ERR_FAIL_COND_V(!is_inside_scene(),Vector3());
+ ERR_FAIL_COND_V(!is_inside_tree(),Vector3());
}
+
+#if 0
Size2 viewport_size = viewport_ptr->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);
+#endif
Vector3 ray;
@@ -441,26 +496,31 @@ Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const {
ray=Vector3(0,0,-1);
} else {
CameraMatrix cm;
- cm.set_perspective(fov,viewport_size.get_aspect(),near,far,vaspect);
+ cm.set_perspective(fov,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
float screen_w,screen_h;
cm.get_viewport_size(screen_w,screen_h);
- ray=Vector3( ((p_pos.x/viewport_size.width)*2.0-1.0)*screen_w, ((1.0-(p_pos.y/viewport_size.height))*2.0-1.0)*screen_h,-near).normalized();
+ ray=Vector3( ((cpos.x/viewport_size.width)*2.0-1.0)*screen_w, ((1.0-(cpos.y/viewport_size.height))*2.0-1.0)*screen_h,-near).normalized();
}
-
return ray;
};
Vector3 Camera::project_ray_origin(const Point2& p_pos) const {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
ERR_EXPLAIN("Camera is not inside scene.");
- ERR_FAIL_COND_V(!is_inside_scene(),Vector3());
+ ERR_FAIL_COND_V(!is_inside_tree(),Vector3());
}
+#if 0
Size2 viewport_size = viewport_ptr->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);
+#endif
ERR_FAIL_COND_V( viewport_size.y == 0, Vector3() );
// float aspect = viewport_size.x / viewport_size.y;
@@ -470,9 +530,9 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const {
return get_camera_transform().origin;
} else {
- Vector2 pos = p_pos / viewport_size;
+ Vector2 pos = cpos / viewport_size;
float vsize,hsize;
- if (vaspect) {
+ if (keep_aspect==KEEP_WIDTH) {
vsize = size/viewport_size.get_aspect();
hsize = size;
} else {
@@ -481,6 +541,8 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const {
}
+
+
Vector3 ray;
ray.x = pos.x * (hsize) - hsize/2;
ray.y = (1.0 - pos.y) * (vsize) - vsize/2;
@@ -490,11 +552,18 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const {
};
};
+bool Camera::is_position_behind(const Vector3& p_pos) const {
+
+ Transform t = get_global_transform();
+ Vector3 eyedir = -get_global_transform().basis.get_axis(2).normalized();
+ return eyedir.dot(p_pos) < (eyedir.dot(t.origin)+near);
+}
+
Point2 Camera::unproject_position(const Vector3& p_pos) const {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
ERR_EXPLAIN("Camera is not inside scene.");
- ERR_FAIL_COND_V(!is_inside_scene(),Vector2());
+ ERR_FAIL_COND_V(!is_inside_tree(),Vector2());
}
Size2 viewport_size = viewport_ptr->get_visible_rect().size;
@@ -503,9 +572,9 @@ Point2 Camera::unproject_position(const Vector3& p_pos) const {
if (mode==PROJECTION_ORTHOGONAL)
- cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,vaspect);
+ cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
else
- cm.set_perspective(fov,viewport_size.get_aspect(),near,far,vaspect);
+ cm.set_perspective(fov,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
Plane p(get_camera_transform().xform_inv(p_pos),1.0);
@@ -523,9 +592,9 @@ Point2 Camera::unproject_position(const Vector3& p_pos) const {
Vector3 Camera::project_position(const Point2& p_point) const {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
ERR_EXPLAIN("Camera is not inside scene.");
- ERR_FAIL_COND_V(!is_inside_scene(),Vector3());
+ ERR_FAIL_COND_V(!is_inside_tree(),Vector3());
}
Size2 viewport_size = viewport_ptr->get_visible_rect().size;
@@ -533,16 +602,16 @@ Vector3 Camera::project_position(const Point2& p_point) const {
CameraMatrix cm;
if (mode==PROJECTION_ORTHOGONAL)
- cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,vaspect);
+ cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
else
- cm.set_perspective(fov,viewport_size.get_aspect(),near,far,vaspect);
+ cm.set_perspective(fov,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
Size2 vp_size;
cm.get_viewport_size(vp_size.x,vp_size.y);
Vector2 point;
point.x = (p_point.x/viewport_size.x) * 2.0 - 1.0;
- point.y = (p_point.y/viewport_size.y) * 2.0 - 1.0;
+ point.y = (1.0-(p_point.y/viewport_size.y)) * 2.0 - 1.0;
point*=vp_size;
Vector3 p(point.x,point.y,-near);
@@ -583,6 +652,20 @@ Ref<Environment> Camera::get_environment() const {
}
+void Camera::set_keep_aspect_mode(KeepAspect p_aspect) {
+
+ keep_aspect=p_aspect;
+ VisualServer::get_singleton()->camera_set_use_vertical_aspect(camera,p_aspect==KEEP_WIDTH);
+
+ _change_notify();
+}
+
+Camera::KeepAspect Camera::get_keep_aspect_mode() const{
+
+ return keep_aspect;
+}
+
+
void Camera::_bind_methods() {
@@ -590,6 +673,7 @@ void Camera::_bind_methods() {
ObjectTypeDB::bind_method( _MD("project_local_ray_normal","screen_point"), &Camera::project_local_ray_normal);
ObjectTypeDB::bind_method( _MD("project_ray_origin","screen_point"), &Camera::project_ray_origin);
ObjectTypeDB::bind_method( _MD("unproject_position","world_point"), &Camera::unproject_position);
+ ObjectTypeDB::bind_method( _MD("is_position_behind","world_point"), &Camera::is_position_behind);
ObjectTypeDB::bind_method( _MD("project_position","screen_point"), &Camera::project_position);
ObjectTypeDB::bind_method( _MD("set_perspective","fov","z_near","z_far"),&Camera::set_perspective );
ObjectTypeDB::bind_method( _MD("set_orthogonal","size","z_near","z_far"),&Camera::set_orthogonal );
@@ -604,16 +688,19 @@ void Camera::_bind_methods() {
ObjectTypeDB::bind_method( _MD("get_projection"),&Camera::get_projection );
ObjectTypeDB::bind_method( _MD("set_visible_layers","mask"),&Camera::set_visible_layers );
ObjectTypeDB::bind_method( _MD("get_visible_layers"),&Camera::get_visible_layers );
- ObjectTypeDB::bind_method( _MD("look_at","target","up"),&Camera::look_at );
- ObjectTypeDB::bind_method( _MD("look_at_from_pos","pos","target","up"),&Camera::look_at_from_pos );
ObjectTypeDB::bind_method(_MD("set_environment","env:Environment"),&Camera::set_environment);
ObjectTypeDB::bind_method(_MD("get_environment:Environment"),&Camera::get_environment);
- ObjectTypeDB::bind_method(_MD("set_use_vertical_aspect","enable"),&Camera::set_use_vertical_aspect);
- ObjectTypeDB::bind_method(_MD("is_using_vertical_aspect"),&Camera::is_using_vertical_aspect);
+ 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 );
BIND_CONSTANT( PROJECTION_ORTHOGONAL );
+
+ BIND_CONSTANT( KEEP_WIDTH );
+ BIND_CONSTANT( KEEP_HEIGHT );
+
}
float Camera::get_fov() const {
@@ -661,42 +748,36 @@ Vector<Plane> Camera::get_frustum() const {
Size2 viewport_size = viewport_ptr->get_visible_rect().size;
CameraMatrix cm;
if (mode==PROJECTION_PERSPECTIVE)
- cm.set_perspective(fov,viewport_size.get_aspect(),near,far,vaspect);
+ cm.set_perspective(fov,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
else
- cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,vaspect);
+ cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
- return cm.get_projection_planes(get_global_transform());
+ return cm.get_projection_planes(get_camera_transform());
}
-void Camera::set_use_vertical_aspect(bool p_enable) {
- vaspect=p_enable;
- VisualServer::get_singleton()->camera_set_use_vertical_aspect(camera,p_enable);
-}
+void Camera::set_v_offset(float p_offset) {
-bool Camera::is_using_vertical_aspect() const{
-
- return vaspect;
+ v_offset=p_offset;
+ _update_camera();;
}
-void Camera::look_at(const Vector3& p_target, const Vector3& p_up_normal) {
+float Camera::get_v_offset() const {
- Transform lookat;
- lookat.origin=get_global_transform().origin;
- lookat=lookat.looking_at(p_target,p_up_normal);
- set_global_transform(lookat);
+ return v_offset;
}
-void Camera::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal) {
+void Camera::set_h_offset(float p_offset) {
+ h_offset=p_offset;
+ _update_camera();
+}
- Transform lookat;
- lookat.origin=p_pos;
- lookat=lookat.looking_at(p_target,p_up_normal);
- set_global_transform(lookat);
+float Camera::get_h_offset() const {
+ return h_offset;
}
@@ -712,8 +793,11 @@ Camera::Camera() {
force_change=false;
mode=PROJECTION_PERSPECTIVE;
set_perspective(60.0,0.1,100.0);
- vaspect=false;
- layers=0xFFFFFFFF;
+ keep_aspect=KEEP_HEIGHT;
+ layers=0xfffff;
+ v_offset=0;
+ h_offset=0;
+ VisualServer::get_singleton()->camera_set_visible_layers(camera,layers);
//active=false;
}
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index a8599497ac..e21f4865ec 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,6 +46,11 @@ public:
PROJECTION_ORTHOGONAL
};
+ enum KeepAspect {
+ KEEP_WIDTH,
+ KEEP_HEIGHT
+ };
+
private:
bool force_change;
@@ -56,11 +61,15 @@ private:
float fov;
float size;
float near,far;
- bool vaspect;
+ float v_offset;
+ float h_offset;
+ KeepAspect keep_aspect;
RID camera;
RID scenario_id;
+ String camera_group;
+
uint32_t layers;
Viewport *viewport_ptr;
@@ -69,6 +78,7 @@ private:
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);
@@ -116,6 +126,7 @@ public:
Vector3 project_ray_origin(const Point2& p_point) const;
Vector3 project_local_ray_normal(const Point2& p_point) const;
Point2 unproject_position(const Vector3& p_pos) const;
+ bool is_position_behind(const Vector3& p_pos) const;
Vector3 project_position(const Point2& p_point) const;
void set_visible_layers(uint32_t p_layers);
@@ -126,11 +137,15 @@ public:
void set_environment(const Ref<Environment>& p_environment);
Ref<Environment> get_environment() const;
- void set_use_vertical_aspect(bool p_enable);
- bool is_using_vertical_aspect() const;
+ void set_keep_aspect_mode(KeepAspect p_aspect);
+ KeepAspect get_keep_aspect_mode() const;
+
+
+ void set_v_offset(float p_offset);
+ float get_v_offset() const;
- 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_h_offset(float p_offset);
+ float get_h_offset() const;
Camera();
@@ -140,5 +155,6 @@ public:
VARIANT_ENUM_CAST( Camera::Projection );
+VARIANT_ENUM_CAST( Camera::KeepAspect );
#endif
diff --git a/scene/3d/car_body.cpp b/scene/3d/car_body.cpp
deleted file mode 100644
index a21598b07c..0000000000
--- a/scene/3d/car_body.cpp
+++ /dev/null
@@ -1,741 +0,0 @@
-/*************************************************************************/
-/* car_body.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "car_body.h"
-
-#define DEG2RADMUL (Math_PI/180.0)
-#define RAD2DEGMUL (180.0/Math_PI)
-
-void CarWheel::_notification(int p_what) {
-
-
- if (p_what==NOTIFICATION_ENTER_SCENE) {
-
- if (!get_parent())
- return;
- CarBody *cb = get_parent()->cast_to<CarBody>();
- if (!cb)
- return;
- body=cb;
- local_xform=get_transform();
- cb->wheels.push_back(this);
- }
- if (p_what==NOTIFICATION_EXIT_SCENE) {
-
- if (!get_parent())
- return;
- CarBody *cb = get_parent()->cast_to<CarBody>();
- if (!cb)
- return;
- cb->wheels.erase(this);
- body=NULL;
- }
-}
-
-void CarWheel::set_side_friction(real_t p_friction) {
-
- side_friction=p_friction;
-}
-void CarWheel::set_forward_friction(real_t p_friction) {
-
- forward_friction=p_friction;
-}
-void CarWheel::set_travel(real_t p_travel) {
-
- travel=p_travel;
- update_gizmo();
-
-}
-void CarWheel::set_radius(real_t p_radius) {
-
- radius=p_radius;
- update_gizmo();
-
-}
-void CarWheel::set_resting_frac(real_t p_frac) {
-
- resting_frac=p_frac;
-}
-void CarWheel::set_damping_frac(real_t p_frac) {
-
- damping_frac=p_frac;
-}
-void CarWheel::set_num_rays(real_t p_rays) {
-
- num_rays=p_rays;
-}
-
-real_t CarWheel::get_side_friction() const{
-
- return side_friction;
-}
-real_t CarWheel::get_forward_friction() const{
-
- return forward_friction;
-}
-real_t CarWheel::get_travel() const{
-
- return travel;
-}
-real_t CarWheel::get_radius() const{
-
- return radius;
-}
-real_t CarWheel::get_resting_frac() const{
-
- return resting_frac;
-}
-real_t CarWheel::get_damping_frac() const{
-
- return damping_frac;
-}
-
-int CarWheel::get_num_rays() const{
-
- return num_rays;
-}
-
-
-void CarWheel::update(real_t dt) {
-
-
- if (dt <= 0.0f)
- return;
-
- float origAngVel = angVel;
-
- if (locked)
- {
- angVel = 0;
- torque = 0;
- }
- else
- {
-
- float wheelMass = 0.03f * body->mass;
- float inertia = 0.5f * (radius * radius) * wheelMass;
-
- angVel += torque * dt / inertia;
- torque = 0;
-
- // prevent friction from reversing dir - todo do this better
- // by limiting the torque
- if (((origAngVel > angVelForGrip) && (angVel < angVelForGrip)) ||
- ((origAngVel < angVelForGrip) && (angVel > angVelForGrip)))
- angVel = angVelForGrip;
-
- angVel += driveTorque * dt / inertia;
- driveTorque = 0;
-
- float maxAngVel = 200;
- print_line("angvel: "+rtos(angVel));
- angVel = CLAMP(angVel, -maxAngVel, maxAngVel);
-
- axisAngle += Math::rad2deg(dt * angVel);
- }
-}
-
-bool CarWheel::add_forces(PhysicsDirectBodyState *s) {
-
-
- Vector3 force;
-
- PhysicsDirectSpaceState *space = s->get_space_state();
-
- Transform world = s->get_transform() * local_xform;
-
- // OpenGl has differnet row/column order for matrixes than XNA has ..
- //Vector3 wheelFwd = world.get_basis().get_axis(Vector3::AXIS_Z);
- //Vector3 wheelFwd = RotationMatrix(mSteerAngle, worldAxis) * carBody.GetOrientation().GetCol(0);
- Vector3 wheelUp = world.get_basis().get_axis(Vector3::AXIS_Y);
- Vector3 wheelFwd = Matrix3(wheelUp,Math::deg2rad(steerAngle)).xform( world.get_basis().get_axis(Vector3::AXIS_Z) );
- Vector3 wheelLeft = -wheelUp.cross(wheelFwd).normalized();
- Vector3 worldPos = world.origin;
- Vector3 worldAxis = wheelUp;
-
- // start of ray
- float rayLen = 2.0f * radius + travel;
- Vector3 wheelRayEnd = worldPos - radius * worldAxis;
- Vector3 wheelRayBegin = wheelRayEnd + rayLen * worldAxis;
- //wheelRayEnd = -rayLen * worldAxis;
-
- //Assert(PhysicsSystem.CurrentPhysicsSystem);
-
-
- ///Assert(collSystem);
- ///
- const int maxNumRays = 32;
-
- int numRaysUse = MIN(num_rays, maxNumRays);
-
- // adjust the start position of the ray - divide the wheel into numRays+2
- // rays, but don't use the first/last.
- float deltaFwd = (2.0f * radius) / (numRaysUse + 1);
- float deltaFwdStart = deltaFwd;
-
- float fracs[maxNumRays];
- Vector3 segmentEnds[maxNumRays];
- Vector3 groundPositions[maxNumRays];
- Vector3 groundNormals[maxNumRays];
-
-
- lastOnFloor = false;
- int bestIRay = 0;
- int iRay;
-
-
- for (iRay = 0; iRay < numRaysUse; ++iRay)
- {
- fracs[iRay] = 1e20;
- // work out the offset relative to the middle ray
- float distFwd = (deltaFwdStart + iRay * deltaFwd) - radius;
- float zOffset = radius * (1.0f - (float)Math::cos( Math::deg2rad( 90.0f * (distFwd / radius))));
-
- segmentEnds[iRay] = wheelRayEnd + distFwd * wheelFwd + zOffset * wheelUp;
-
-
- PhysicsDirectSpaceState::RayResult rr;
-
- bool collided = space->intersect_ray(wheelRayBegin,segmentEnds[iRay],rr,body->exclude);
-
-
- if (collided){
- lastOnFloor = true;
- groundPositions[iRay]=rr.position;
- groundNormals[iRay]=rr.normal;
- fracs[iRay] = ((wheelRayBegin-rr.position).length() / (wheelRayBegin-wheelRayEnd).length());
- if (fracs[iRay] < fracs[bestIRay])
- bestIRay = iRay;
- }
- }
-
-
- if (!lastOnFloor)
- return false;
-
- //Assert(bestIRay < numRays);
-
- // use the best one
- Vector3 groundPos = groundPositions[bestIRay];
- float frac = fracs[bestIRay];
-
- // const Vector3 groundNormal = (worldPos - segments[bestIRay].GetEnd()).NormaliseSafe();
- // const Vector3 groundNormal = groundNormals[bestIRay];
-
-
- Vector3 groundNormal = worldAxis;
-
- if (numRaysUse > 1)
- {
- for (iRay = 0; iRay < numRaysUse; ++iRay)
- {
- if (fracs[iRay] <= 1.0f)
- {
- groundNormal += (1.0f - fracs[iRay]) * (worldPos - segmentEnds[iRay]);
- }
- }
-
- groundNormal.normalize();
-
- }
- else
- {
- groundNormal = groundNormals[bestIRay];
- }
-
-
-
- float spring = (body->mass/body->wheels.size()) * s->get_total_gravity().length() / (resting_frac * travel);
-
- float displacement = rayLen * (1.0f - frac);
- displacement = CLAMP(displacement, 0, travel);
-
-
-
- float displacementForceMag = displacement * spring;
-
- // reduce force when suspension is par to ground
- displacementForceMag *= groundNormals[bestIRay].dot(worldAxis);
-
- // apply damping
- float damping = 2.0f * (float)Math::sqrt(spring * body->mass);
- damping /= body->wheels.size(); // assume wheels act together
- damping *= damping_frac; // a bit bouncy
-
- float upSpeed = (displacement - lastDisplacement) / s->get_step();
-
- float dampingForceMag = upSpeed * damping;
-
- float totalForceMag = displacementForceMag + dampingForceMag;
-
- if (totalForceMag < 0.0f) totalForceMag = 0.0f;
-
- Vector3 extraForce = totalForceMag * worldAxis;
-
-
- force += extraForce;
- // side-slip friction and drive force. Work out wheel- and floor-relative coordinate frame
- Vector3 groundUp = groundNormal;
- Vector3 groundLeft = groundNormal.cross(wheelFwd).normalized();
-
- Vector3 groundFwd = groundLeft.cross(groundUp);
-
- Vector3 wheelPointVel = s->get_linear_velocity() +
- (s->get_angular_velocity()).cross(s->get_transform().basis.xform(local_xform.origin));// * mPos);
-
- Vector3 rimVel = -angVel * wheelLeft.cross(groundPos - worldPos);
- wheelPointVel += rimVel;
-
- // if sitting on another body then adjust for its velocity.
- /*if (worldBody != null)
- {
- Vector3 worldVel = worldBody.Velocity +
- Vector3.Cross(worldBody.AngularVelocity, groundPos - worldBody.Position);
-
- wheelPointVel -= worldVel;
- }*/
-
- // sideways forces
- float noslipVel = 0.2f;
- float slipVel = 0.4f;
- float slipFactor = 0.7f;
-
- float smallVel = 3;
- float friction = side_friction;
-
- float sideVel = wheelPointVel.dot(groundLeft);
-
- if ((sideVel > slipVel) || (sideVel < -slipVel))
- friction *= slipFactor;
- else
- if ((sideVel > noslipVel) || (sideVel < -noslipVel))
- friction *= 1.0f - (1.0f - slipFactor) * (Math::absf(sideVel) - noslipVel) / (slipVel - noslipVel);
-
- if (sideVel < 0.0f)
- friction *= -1.0f;
-
- if (Math::absf(sideVel) < smallVel)
- friction *= Math::absf(sideVel) / smallVel;
-
- float sideForce = -friction * totalForceMag;
-
- extraForce = sideForce * groundLeft;
- force += extraForce;
- // fwd/back forces
- friction = forward_friction;
- float fwdVel = wheelPointVel.dot(groundFwd);
-
- if ((fwdVel > slipVel) || (fwdVel < -slipVel))
- friction *= slipFactor;
- else
- if ((fwdVel > noslipVel) || (fwdVel < -noslipVel))
- friction *= 1.0f - (1.0f - slipFactor) * (Math::absf(fwdVel) - noslipVel) / (slipVel - noslipVel);
-
- if (fwdVel < 0.0f)
- friction *= -1.0f;
-
- if (Math::absf(fwdVel) < smallVel)
- friction *= Math::absf(fwdVel) / smallVel;
-
- float fwdForce = -friction * totalForceMag;
-
- extraForce = fwdForce * groundFwd;
- force += extraForce;
-
-
- //if (!force.IsSensible())
- //{
- // TRACE_FILE_IF(ONCE_1)
- // TRACE("Bad force in car wheel\n");
- // return true;
- //}
-
- // fwd force also spins the wheel
- Vector3 wheelCentreVel = s->get_linear_velocity() +
- (s->get_angular_velocity()).cross(s->get_transform().basis.xform(local_xform.origin));
-
- angVelForGrip = wheelCentreVel.dot(groundFwd) / radius;
- torque += -fwdForce * radius;
-
- // add force to car
-// carBody.AddWorldForce(force, groundPos);
-
- s->add_force(force,(groundPos-s->get_transform().origin));
-
- // add force to the world
- /*
- if (worldBody != null && !worldBody.Immovable)
- {
- // todo get the position in the right place...
- // also limit the velocity that this force can produce by looking at the
- // mass/inertia of the other object
- float maxOtherBodyAcc = 500.0f;
- float maxOtherBodyForce = maxOtherBodyAcc * worldBody.Mass;
-
- if (force.LengthSquared() > (maxOtherBodyForce * maxOtherBodyForce))
- force *= maxOtherBodyForce / force.Length();
-
- worldBody.AddWorldForce(-force, groundPos);
- }*/
-
- Transform wheel_xf = local_xform;
- wheel_xf.origin += wheelUp * displacement;
- wheel_xf.basis = wheel_xf.basis * Matrix3(Vector3(0,1,0),Math::deg2rad(steerAngle));
- //wheel_xf.basis = wheel_xf.basis * Matrix3(wheel_xf.basis[0],-Math::deg2rad(axisAngle));
-
- set_transform(wheel_xf);
- lastDisplacement=displacement;
- return true;
-
-}
-
-void CarWheel::set_type_drive(bool p_enable) {
-
- type_drive=p_enable;
-}
-
-bool CarWheel::is_type_drive() const {
-
- return type_drive;
-}
-
-void CarWheel::set_type_steer(bool p_enable) {
-
- type_steer=p_enable;
-}
-
-bool CarWheel::is_type_steer() const {
-
- return type_steer;
-}
-
-
-void CarWheel::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_side_friction","friction"),&CarWheel::set_side_friction);
- ObjectTypeDB::bind_method(_MD("set_forward_friction","friction"),&CarWheel::set_forward_friction);
- ObjectTypeDB::bind_method(_MD("set_travel","distance"),&CarWheel::set_travel);
- ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CarWheel::set_radius);
- ObjectTypeDB::bind_method(_MD("set_resting_frac","frac"),&CarWheel::set_resting_frac);
- ObjectTypeDB::bind_method(_MD("set_damping_frac","frac"),&CarWheel::set_damping_frac);
- ObjectTypeDB::bind_method(_MD("set_num_rays","amount"),&CarWheel::set_num_rays);
-
- ObjectTypeDB::bind_method(_MD("get_side_friction"),&CarWheel::get_side_friction);
- ObjectTypeDB::bind_method(_MD("get_forward_friction"),&CarWheel::get_forward_friction);
- ObjectTypeDB::bind_method(_MD("get_travel"),&CarWheel::get_travel);
- ObjectTypeDB::bind_method(_MD("get_radius"),&CarWheel::get_radius);
- ObjectTypeDB::bind_method(_MD("get_resting_frac"),&CarWheel::get_resting_frac);
- ObjectTypeDB::bind_method(_MD("get_damping_frac"),&CarWheel::get_damping_frac);
- ObjectTypeDB::bind_method(_MD("get_num_rays"),&CarWheel::get_num_rays);
-
- ObjectTypeDB::bind_method(_MD("set_type_drive","enable"),&CarWheel::set_type_drive);
- ObjectTypeDB::bind_method(_MD("is_type_drive"),&CarWheel::is_type_drive);
-
- ObjectTypeDB::bind_method(_MD("set_type_steer","enable"),&CarWheel::set_type_steer);
- ObjectTypeDB::bind_method(_MD("is_type_steer"),&CarWheel::is_type_steer);
-
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"type/drive"),_SCS("set_type_drive"),_SCS("is_type_drive"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"type/steer"),_SCS("set_type_steer"),_SCS("is_type_steer"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/side_friction",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_side_friction"),_SCS("get_side_friction"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/forward_friction",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_forward_friction"),_SCS("get_forward_friction"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/travel",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_travel"),_SCS("get_travel"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/radius",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_radius"),_SCS("get_radius"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/resting_frac",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_resting_frac"),_SCS("get_resting_frac"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/damping_frac",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_damping_frac"),_SCS("get_damping_frac"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/num_rays",PROPERTY_HINT_RANGE,"1,32,1"),_SCS("set_num_rays"),_SCS("get_num_rays"));
-
-}
-
-CarWheel::CarWheel() {
-
- side_friction=4.7;
- forward_friction=5.0;
- travel=0.2;
- radius=0.4;
- resting_frac=0.45;
- damping_frac=0.3;
- num_rays=1;
-
- angVel = 0.0f;
- steerAngle = 0.0f;
- torque = 0.0f;
- driveTorque = 0.0f;
- axisAngle = 0.0f;
- upSpeed = 0.0f;
- locked = false;
- lastDisplacement = 0.0f;
- lastOnFloor = false;
- angVelForGrip = 0.0f;
- angVelForGrip=0;
-
- type_drive=false;
- type_steer=false;
-
-}
-
-///
-
-
-void CarBody::set_max_steer_angle(real_t p_angle) {
-
- max_steer_angle=p_angle;
-}
-void CarBody::set_steer_rate(real_t p_rate) {
-
- steer_rate=p_rate;
-}
-void CarBody::set_drive_torque(real_t p_torque) {
-
- drive_torque=p_torque;
-}
-
-real_t CarBody::get_max_steer_angle() const{
-
- return max_steer_angle;
-}
-real_t CarBody::get_steer_rate() const{
-
- return steer_rate;
-}
-real_t CarBody::get_drive_torque() const{
-
- return drive_torque;
-}
-
-
-void CarBody::set_target_steering(float p_steering) {
-
- target_steering=p_steering;
-}
-
-void CarBody::set_target_accelerate(float p_accelerate) {
- target_accelerate=p_accelerate;
-}
-
-void CarBody::set_hand_brake(float p_amont) {
-
- hand_brake=p_amont;
-}
-
-real_t CarBody::get_target_steering() const {
-
- return target_steering;
-}
-real_t CarBody::get_target_accelerate() const {
-
- return target_accelerate;
-}
-real_t CarBody::get_hand_brake() const {
-
- return hand_brake;
-}
-
-
-void CarBody::_direct_state_changed(Object *p_state) {
-
- PhysicsDirectBodyState *state=p_state->cast_to<PhysicsDirectBodyState>();
-
- float dt = state->get_step();
- AABB aabb;
- int drive_total=0;
- for(int i=0;i<wheels.size();i++) {
- CarWheel *w=wheels[i];
- if (i==0) {
- aabb.pos=w->local_xform.origin;
- } else {
- aabb.expand_to(w->local_xform.origin);
- }
- if (w->type_drive)
- drive_total++;
-
- }
- // control inputs
- float deltaAccelerate = dt * 4.0f;
-
- float dAccelerate = target_accelerate - accelerate;
- dAccelerate = CLAMP(dAccelerate, -deltaAccelerate, deltaAccelerate);
- accelerate += dAccelerate;
-
- float deltaSteering = dt * steer_rate;
- float dSteering = target_steering - steering;
- dSteering = CLAMP(dSteering, -deltaSteering, deltaSteering);
- steering += dSteering;
-
- // apply these inputs
- float maxTorque = drive_torque;
-
- float torque_div = drive_total/2;
- if (torque_div>0)
- maxTorque/=torque_div;
-
-
- float alpha = ABS(max_steer_angle * steering);
- float angleSgn = steering > 0.0f ? 1.0f : -1.0f;
-
- int wheels_on_floor=0;
-
- for(int i=0;i<wheels.size();i++) {
-
- CarWheel *w=wheels[i];
- if (w->type_drive)
- w->driveTorque+=maxTorque * accelerate;
- w->locked = !w->type_steer && (hand_brake > 0.5f);
-
- if (w->type_steer) {
- //steering
-
- bool inner = (steering > 0 && w->local_xform.origin.x > 0) || (steering < 0 && w->local_xform.origin.x < 0);
-
- if (inner || alpha==0.0) {
-
- w->steerAngle = (angleSgn * alpha);
- } else {
- float dx = aabb.size.z;
- float dy = aabb.size.x;
-
- float beta = Math::atan2(dy, dx + (dy / (float)Math::tan(Math::deg2rad(alpha))));
- beta = Math::rad2deg(beta);
- w->steerAngle = (angleSgn * beta);
-
- }
- }
-
- if (w->add_forces(state))
- wheels_on_floor++;
- w->update(dt);
-
-
- }
-
- print_line("onfloor: "+itos(wheels_on_floor));
-
-
- set_ignore_transform_notification(true);
- set_global_transform(state->get_transform());
- linear_velocity=state->get_linear_velocity();
- angular_velocity=state->get_angular_velocity();
- //active=!state->is_sleeping();
- //if (get_script_instance())
- // get_script_instance()->call("_integrate_forces",state);
- set_ignore_transform_notification(false);
-
-
-}
-
-void CarBody::set_mass(real_t p_mass) {
-
- mass=p_mass;
- PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_MASS,mass);
-}
-
-real_t CarBody::get_mass() const{
-
- return mass;
-}
-
-
-void CarBody::set_friction(real_t p_friction) {
-
- friction=p_friction;
- PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction);
-}
-
-real_t CarBody::get_friction() const{
-
- return friction;
-}
-
-
-void CarBody::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_max_steer_angle","value"),&CarBody::set_max_steer_angle);
- ObjectTypeDB::bind_method(_MD("set_steer_rate","rate"),&CarBody::set_steer_rate);
- ObjectTypeDB::bind_method(_MD("set_drive_torque","value"),&CarBody::set_drive_torque);
-
- ObjectTypeDB::bind_method(_MD("get_max_steer_angle"),&CarBody::get_max_steer_angle);
- ObjectTypeDB::bind_method(_MD("get_steer_rate"),&CarBody::get_steer_rate);
- ObjectTypeDB::bind_method(_MD("get_drive_torque"),&CarBody::get_drive_torque);
-
- ObjectTypeDB::bind_method(_MD("set_target_steering","amount"),&CarBody::set_target_steering);
- ObjectTypeDB::bind_method(_MD("set_target_accelerate","amount"),&CarBody::set_target_accelerate);
- ObjectTypeDB::bind_method(_MD("set_hand_brake","amount"),&CarBody::set_hand_brake);
-
- ObjectTypeDB::bind_method(_MD("get_target_steering"),&CarBody::get_target_steering);
- ObjectTypeDB::bind_method(_MD("get_target_accelerate"),&CarBody::get_target_accelerate);
- ObjectTypeDB::bind_method(_MD("get_hand_brake"),&CarBody::get_hand_brake);
-
- ObjectTypeDB::bind_method(_MD("set_mass","mass"),&CarBody::set_mass);
- ObjectTypeDB::bind_method(_MD("get_mass"),&CarBody::get_mass);
-
- ObjectTypeDB::bind_method(_MD("set_friction","friction"),&CarBody::set_friction);
- ObjectTypeDB::bind_method(_MD("get_friction"),&CarBody::get_friction);
-
- ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&CarBody::_direct_state_changed);
-
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/mass",PROPERTY_HINT_RANGE,"0.01,65536,0.01"),_SCS("set_mass"),_SCS("get_mass"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/friction",PROPERTY_HINT_RANGE,"0.01,1,0.01"),_SCS("set_friction"),_SCS("get_friction"));
-
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/max_steer_angle",PROPERTY_HINT_RANGE,"1,90,1"),_SCS("set_max_steer_angle"),_SCS("get_max_steer_angle"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/drive_torque",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_drive_torque"),_SCS("get_drive_torque"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/steer_rate",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_steer_rate"),_SCS("get_steer_rate"));
-
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/target_steering",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_target_steering"),_SCS("get_target_steering"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/target_accelerate",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_target_accelerate"),_SCS("get_target_accelerate"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/hand_brake",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_hand_brake"),_SCS("get_hand_brake"));
-
-}
-
-CarBody::CarBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) {
-
- forward_drive=true;
- backward_drive=true;
- max_steer_angle=30;
- steer_rate=1;
- drive_torque=520;
-
- target_steering=0;
- target_accelerate=0;
- hand_brake=0;
-
- steering=0;
- accelerate=0;
-
- mass=1;
- friction=1;
-
- ccd=false;
-// can_sleep=true;
-
-
-
-
- exclude.insert(get_rid());
- PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed");
-
-
-}
diff --git a/scene/3d/car_body.h b/scene/3d/car_body.h
deleted file mode 100644
index 87eb047bcf..0000000000
--- a/scene/3d/car_body.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*************************************************************************/
-/* car_body.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef CAR_BODY_H
-#define CAR_BODY_H
-
-#include "scene/3d/physics_body.h"
-
-
-class CarBody;
-
-class CarWheel : public Spatial {
-
- OBJ_TYPE(CarWheel,Spatial);
-
-friend class CarBody;
- real_t side_friction;
- real_t forward_friction;
- real_t travel;
- real_t radius;
- real_t resting_frac;
- real_t damping_frac;
- int num_rays;
- Transform local_xform;
-
- CarBody *body;
-
- float angVel;
- float steerAngle;
- float torque;
- float driveTorque;
- float axisAngle;
- float upSpeed; // speed relative to the car
- bool locked;
- // last frame stuff
- float lastDisplacement;
- float angVelForGrip;
- bool lastOnFloor;
-
- bool type_drive;
- bool type_steer;
-
-
-protected:
- void update(real_t dt);
- bool add_forces(PhysicsDirectBodyState *s);
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
-
- void set_side_friction(real_t p_friction);
- void set_forward_friction(real_t p_friction);
- void set_travel(real_t p_travel);
- void set_radius(real_t p_radius);
- void set_resting_frac(real_t p_frac);
- void set_damping_frac(real_t p_frac);
- void set_num_rays(real_t p_rays);
-
- real_t get_side_friction() const;
- real_t get_forward_friction() const;
- real_t get_travel() const;
- real_t get_radius() const;
- real_t get_resting_frac() const;
- real_t get_damping_frac() const;
- int get_num_rays() const;
-
- void set_type_drive(bool p_enable);
- bool is_type_drive() const;
-
- void set_type_steer(bool p_enable);
- bool is_type_steer() const;
-
- CarWheel();
-
-};
-
-
-
-class CarBody : public PhysicsBody {
-
- OBJ_TYPE(CarBody,PhysicsBody);
-
- real_t mass;
- real_t friction;
-
- Vector3 linear_velocity;
- Vector3 angular_velocity;
- bool ccd;
-
- real_t max_steer_angle;
- real_t steer_rate;
- int wheel_num_rays;
- real_t drive_torque;
-
-// control stuff
- real_t target_steering;
- real_t target_accelerate;
-
- bool forward_drive;
- bool backward_drive;
-
- real_t steering;
- real_t accelerate;
- real_t hand_brake;
- Set<RID> exclude;
-
-
-friend class CarWheel;
- Vector<CarWheel*> wheels;
-
- static void _bind_methods();
-
- void _direct_state_changed(Object *p_state);
-public:
-
-
- void set_mass(real_t p_mass);
- real_t get_mass() const;
-
- void set_friction(real_t p_friction);
- real_t get_friction() const;
-
- void set_max_steer_angle(real_t p_angle);
- void set_steer_rate(real_t p_rate);
- void set_drive_torque(real_t p_torque);
-
- real_t get_max_steer_angle() const;
- real_t get_steer_rate() const;
- real_t get_drive_torque() const;
-
-
- void set_target_steering(float p_steering);
- void set_target_accelerate(float p_accelerate);
- void set_hand_brake(float p_amont);
-
- real_t get_target_steering() const;
- real_t get_target_accelerate() const;
- real_t get_hand_brake() const;
-
-
- CarBody();
-};
-
-#endif // CAR_BODY_H
diff --git a/scene/3d/character_camera.cpp b/scene/3d/character_camera.cpp
index e3c071d42f..19332bd056 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/character_camera.h b/scene/3d/character_camera.h
index f3bdef54a6..99b41c6eda 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index 7ad10d3222..5ecadb48b8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,7 +28,7 @@
/*************************************************************************/
#include "collision_object.h"
#include "servers/physics_server.h"
-
+#include "scene/scene_string_names.h"
void CollisionObject::_update_shapes_from_children() {
shapes.resize(0);
@@ -47,14 +47,20 @@ void CollisionObject::_notification(int p_what) {
case NOTIFICATION_ENTER_WORLD: {
+ if (area)
+ PhysicsServer::get_singleton()->area_set_transform(rid,get_global_transform());
+ else
+ PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform());
+
RID space = get_world()->get_space();
if (area) {
PhysicsServer::get_singleton()->area_set_space(rid,space);
} else
PhysicsServer::get_singleton()->body_set_space(rid,space);
+ _update_pickable();
//get space
- }
+ };
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -64,6 +70,11 @@ void CollisionObject::_notification(int p_what) {
PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform());
} break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ _update_pickable();
+
+ } break;
case NOTIFICATION_EXIT_WORLD: {
if (area) {
@@ -91,11 +102,11 @@ void CollisionObject::_update_shapes() {
continue;
if (area)
PhysicsServer::get_singleton()->area_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform);
- else {
+ else {
PhysicsServer::get_singleton()->body_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform);
- if (shapes[i].trigger)
- PhysicsServer::get_singleton()->body_set_shape_as_trigger(rid,i,shapes[i].trigger);
- }
+ if (shapes[i].trigger)
+ PhysicsServer::get_singleton()->body_set_shape_as_trigger(rid,i,shapes[i].trigger);
+ }
}
}
@@ -111,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")
@@ -137,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")
@@ -154,17 +165,67 @@ bool CollisionObject::_get(const StringName& p_name,Variant &r_ret) const {
void CollisionObject::_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) );
+ 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)+"/";
- p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape",PROPERTY_USAGE_NOEDITOR) );
- p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) );
- p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) );
+ p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+ p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+ p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+
+ }
+}
+
+
+void CollisionObject::_input_event(Node *p_camera, const InputEvent& p_input_event, const Vector3& p_pos, const Vector3& p_normal, int p_shape) {
+
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_input_event,p_camera,p_input_event,p_pos,p_normal,p_shape);
+ }
+ emit_signal(SceneStringNames::get_singleton()->input_event,p_camera,p_input_event,p_pos,p_normal,p_shape);
+}
+
+void CollisionObject::_mouse_enter() {
+
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter);
+ }
+ emit_signal(SceneStringNames::get_singleton()->mouse_enter);
+}
+
+void CollisionObject::_mouse_exit() {
+
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit);
}
+ emit_signal(SceneStringNames::get_singleton()->mouse_exit);
+
+}
+
+void CollisionObject::_update_pickable() {
+ if (!is_inside_tree())
+ return;
+ bool pickable = ray_pickable && is_inside_tree() && is_visible();
+ if (area)
+ PhysicsServer::get_singleton()->area_set_ray_pickable(rid,pickable);
+ else
+ PhysicsServer::get_singleton()->body_set_ray_pickable(rid,pickable);
+}
+
+void CollisionObject::set_ray_pickable(bool p_ray_pickable) {
+
+ ray_pickable=p_ray_pickable;
+ _update_pickable();
+
+}
+
+bool CollisionObject::is_ray_pickable() const {
+
+ return ray_pickable;
}
+
void CollisionObject::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_shape","shape:Shape","transform"),&CollisionObject::add_shape,DEFVAL(Transform()));
@@ -178,8 +239,19 @@ void CollisionObject::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_shape_transform","shape_idx"),&CollisionObject::get_shape_transform);
ObjectTypeDB::bind_method(_MD("remove_shape","shape_idx"),&CollisionObject::remove_shape);
ObjectTypeDB::bind_method(_MD("clear_shapes"),&CollisionObject::clear_shapes);
+ ObjectTypeDB::bind_method(_MD("set_ray_pickable","ray_pickable"),&CollisionObject::set_ray_pickable);
+ ObjectTypeDB::bind_method(_MD("is_ray_pickable"),&CollisionObject::is_ray_pickable);
+ ObjectTypeDB::bind_method(_MD("set_capture_input_on_drag","enable"),&CollisionObject::set_capture_input_on_drag);
+ ObjectTypeDB::bind_method(_MD("get_capture_input_on_drag"),&CollisionObject::get_capture_input_on_drag);
ObjectTypeDB::bind_method(_MD("get_rid"),&CollisionObject::get_rid);
+ BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::OBJECT,"camera"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::VECTOR3,"click_pos"),PropertyInfo(Variant::VECTOR3,"click_normal"),PropertyInfo(Variant::INT,"shape_idx")));
+ ADD_SIGNAL( MethodInfo("input_event",PropertyInfo(Variant::OBJECT,"camera"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::VECTOR3,"click_pos"),PropertyInfo(Variant::VECTOR3,"click_normal"),PropertyInfo(Variant::INT,"shape_idx")));
+ ADD_SIGNAL( MethodInfo("mouse_enter"));
+ ADD_SIGNAL( MethodInfo("mouse_exit"));
+
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"input/ray_pickable"),_SCS("set_ray_pickable"),_SCS("is_ray_pickable"));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"input/capture_on_drag"),_SCS("set_capture_input_on_drag"),_SCS("get_capture_input_on_drag"));
}
@@ -260,6 +332,8 @@ CollisionObject::CollisionObject(RID p_rid, bool p_area) {
rid=p_rid;
area=p_area;
+ capture_input_on_drag=false;
+ ray_pickable=true;
if (p_area) {
PhysicsServer::get_singleton()->area_attach_object_instance_ID(rid,get_instance_ID());
} else {
@@ -269,10 +343,24 @@ CollisionObject::CollisionObject(RID p_rid, bool p_area) {
}
+void CollisionObject::set_capture_input_on_drag(bool p_capture) {
+
+ capture_input_on_drag=p_capture;
+
+}
+
+bool CollisionObject::get_capture_input_on_drag() const {
+
+ return capture_input_on_drag;
+}
+
CollisionObject::CollisionObject() {
+ capture_input_on_drag=false;
+ ray_pickable=true;
+
//owner=
//set_transform_notify(true);
diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h
index 54dc6508ab..548c9fb85b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -50,9 +50,11 @@ class CollisionObject : public Spatial {
};
-
+ bool capture_input_on_drag;
+ bool ray_pickable;
Vector<ShapeData> shapes;
+ void _update_pickable();
void _update_shapes();
friend class CollisionShape;
@@ -67,6 +69,11 @@ protected:
bool _get(const StringName& p_name,Variant &r_ret) const;
void _get_property_list( List<PropertyInfo> *p_list) const;
static void _bind_methods();
+friend class Viewport;
+ virtual void _input_event(Node* p_camera,const InputEvent& p_input_event,const Vector3& p_pos, const Vector3& p_normal, int p_shape);
+ virtual void _mouse_enter();
+ virtual void _mouse_exit();
+
public:
@@ -81,6 +88,13 @@ public:
void set_shape_as_trigger(int p_shape_idx, bool p_trigger);
bool is_shape_set_as_trigger(int p_shape_idx) const;
+ void set_ray_pickable(bool p_ray_pickable);
+ bool is_ray_pickable() const;
+
+ void set_capture_input_on_drag(bool p_capture);
+ bool get_capture_input_on_drag() const;
+
+
_FORCE_INLINE_ RID get_rid() const { return rid; }
CollisionObject();
diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp
new file mode 100644
index 0000000000..bb0a1fca12
--- /dev/null
+++ b/scene/3d/collision_polygon.cpp
@@ -0,0 +1,270 @@
+#include "collision_polygon.h"
+
+#include "collision_object.h"
+#include "scene/resources/concave_polygon_shape.h"
+#include "scene/resources/convex_polygon_shape.h"
+
+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);
+
+ if (polygon.size()==0)
+ return;
+
+ bool solids=build_mode==BUILD_SOLIDS;
+
+ Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon);
+ if (decomp.size()==0)
+ return;
+
+ if (true || solids) {
+
+ //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;
+ int cs = decomp[i].size();
+ cp.resize(cs*2);
+ {
+ DVector<Vector3>::Write w = cp.write();
+ int idx=0;
+ for(int j=0;j<cs;j++) {
+
+ Vector2 d = decomp[i][j];
+ w[idx++]=Vector3(d.x,d.y,depth*0.5);
+ w[idx++]=Vector3(d.x,d.y,-depth*0.5);
+ }
+ }
+
+ convex->set_points(cp);
+ 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
+ Ref<ConcavePolygonShape> concave = memnew( ConcavePolygonShape );
+
+ DVector<Vector2> segments;
+ segments.resize(polygon.size()*2);
+ DVector<Vector2>::Write w=segments.write();
+
+ for(int i=0;i<polygon.size();i++) {
+ w[(i<<1)+0]=polygon[i];
+ w[(i<<1)+1]=polygon[(i+1)%polygon.size()];
+ }
+
+ w=DVector<Vector2>::Write();
+ concave->set_segments(segments);
+
+ co->add_shape(concave,get_transform());
+#endif
+ }
+
+
+ //co->add_shape(shape,get_transform());
+
+}
+
+void CollisionPolygon::_update_parent() {
+
+ if (!can_update_body)
+ return;
+
+ Node *parent = get_parent();
+ if (!parent)
+ return;
+ CollisionObject *co = parent->cast_to<CollisionObject>();
+ if (!co)
+ return;
+ 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;
+ 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
+ case NOTIFICATION_DRAW: {
+ 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);
+ }
+
+ Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon);
+#define DEBUG_DECOMPOSE
+#ifdef DEBUG_DECOMPOSE
+ 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);
+ }
+#endif
+
+ } break;
+#endif
+ }
+}
+
+void CollisionPolygon::set_polygon(const Vector<Point2>& p_polygon) {
+
+ polygon=p_polygon;
+ if (can_update_body) {
+
+ for(int i=0;i<polygon.size();i++) {
+
+ Vector3 p1(polygon[i].x,polygon[i].y,depth*0.5);
+
+ 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);
+
+
+ }
+ 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;
+ }
+ _update_parent();
+ }
+ update_gizmo();
+}
+
+Vector<Point2> CollisionPolygon::get_polygon() const {
+
+ return polygon;
+}
+
+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();
+}
+
+CollisionPolygon::BuildMode CollisionPolygon::get_build_mode() const{
+
+ return build_mode;
+}
+
+AABB CollisionPolygon::get_item_rect() const {
+
+ return aabb;
+}
+
+void CollisionPolygon::set_depth(float p_depth) {
+
+ depth=p_depth;
+ if (!can_update_body)
+ return;
+ _update_parent();
+ update_gizmo();
+}
+
+float CollisionPolygon::get_depth() const {
+
+ return depth;
+}
+
+
+void CollisionPolygon::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon::_add_to_collision_object);
+
+ 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_depth","depth"),&CollisionPolygon::set_depth);
+ ObjectTypeDB::bind_method(_MD("get_depth"),&CollisionPolygon::get_depth);
+
+ 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::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
new file mode 100644
index 0000000000..9b9afea34f
--- /dev/null
+++ b/scene/3d/collision_polygon.h
@@ -0,0 +1,62 @@
+#ifndef COLLISION_POLYGON_H
+#define COLLISION_POLYGON_H
+
+#include "scene/3d/spatial.h"
+#include "scene/resources/shape.h"
+
+
+
+class CollisionPolygon : public Spatial {
+
+ OBJ_TYPE(CollisionPolygon,Spatial);
+public:
+
+ enum BuildMode {
+ BUILD_SOLIDS,
+ BUILD_TRIANGLES,
+ };
+
+protected:
+
+
+ float depth;
+ AABB aabb;
+ 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);
+ static void _bind_methods();
+public:
+
+ void set_build_mode(BuildMode p_mode);
+ BuildMode get_build_mode() const;
+
+ void set_depth(float p_depth);
+ float get_depth() const;
+
+ void set_polygon(const Vector<Point2>& p_polygon);
+ 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();
+};
+
+VARIANT_ENUM_CAST( CollisionPolygon::BuildMode );
+#endif // COLLISION_POLYGON_H
diff --git a/scene/3d/editable_shape.cpp b/scene/3d/editable_shape.cpp
deleted file mode 100644
index ab3f832028..0000000000
--- a/scene/3d/editable_shape.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*************************************************************************/
-/* editable_shape.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "editable_shape.h"
-
-
-void EditableShape::_notification(int p_what) {
-
-
-
-}
-
-
-void EditableShape::set_bsp_tree(const BSP_Tree& p_bsp) {
-
- bsp=p_bsp;
-}
-
-void EditableShape::set_shape(const Ref<Shape>& p_shape) {
-
- shape=p_shape;
-}
-
-
-
-EditableShape::EditableShape()
-{
-}
-
-
-
-/////////////////////////
-
-
-void EditableSphere::set_radius(float p_radius) {
-
- radius=p_radius;
- update_gizmo();
- _change_notify("params/radius");
-}
-
-
-float EditableSphere::get_radius() const{
-
- return radius;
-}
-
-
-void EditableSphere::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_radius","radius"),&EditableSphere::set_radius);
- ObjectTypeDB::bind_method(_MD("get_radius"),&EditableSphere::get_radius);
-
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"params/radius",PROPERTY_HINT_EXP_RANGE,"0.001,16384,0.001"),_SCS("set_radius"),_SCS("get_radius"));
-}
-
-EditableSphere::EditableSphere() {
-
- radius=1.0;
-}
diff --git a/scene/3d/editable_shape.h b/scene/3d/editable_shape.h
deleted file mode 100644
index 9accea575c..0000000000
--- a/scene/3d/editable_shape.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*************************************************************************/
-/* editable_shape.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef EDITABLE_SHAPE_H
-#define EDITABLE_SHAPE_H
-
-#include "scene/3d/spatial.h"
-#include "scene/resources/shape.h"
-
-class EditableShape : public Spatial {
-
- OBJ_TYPE(EditableShape,Spatial);
-
- //can hold either of those
- BSP_Tree bsp;
- Ref<Shape> shape;
-
- void _update_parent();
-protected:
-
- void _notification(int p_what);
-
- void set_bsp_tree(const BSP_Tree& p_bsp);
- void set_shape(const Ref<Shape>& p_shape);
-public:
- EditableShape();
-};
-
-
-class EditableSphere : public EditableShape {
-
- OBJ_TYPE( EditableSphere, EditableShape );
-
-
- float radius;
-protected:
-
- static void _bind_methods();
-public:
-
- void set_radius(float p_radius);
- float get_radius() const;
-
- EditableSphere();
-};
-
-
-#endif // EDITABLE_SHAPE_H
diff --git a/scene/3d/follow_camera.cpp b/scene/3d/follow_camera.cpp
deleted file mode 100644
index e7ced6c2ba..0000000000
--- a/scene/3d/follow_camera.cpp
+++ /dev/null
@@ -1,778 +0,0 @@
-/*************************************************************************/
-/* follow_camera.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "follow_camera.h"
-
-
-#include "physics_body.h"
-#include "scene/resources/surface_tool.h"
-
-void FollowCamera::_set_initial_orbit(const Vector2& p_orbit) {
-
- initial_orbit=p_orbit;
- set_orbit(p_orbit);
-}
-
-
-
-void FollowCamera::_clear_queries() {
-
- if (!queries_active)
- return;
-#if 0
- for(int i=0;i<3;i++)
- PhysicsServer::get_singleton()->query_clear(clip_ray[i].query);
-#endif
- queries_active=false;
-
-}
-
-void FollowCamera::_compute_camera() {
-
- // update the transform with the next proposed transform (camera is 1 logic frame delayed)
-
- /*
- float time = get_root_node()->get_frame_time();
- Vector3 oldp = accepted.get_origin();
- Vector3 newp = proposed.get_origin();
-
- float frame_dist = time *
- if (oldp.distance_to(newp) >
- */
-
- float time = get_process_delta_time();
- bool noblend=false;
-
- if (clip) {
-
- if ((clip_ray[0].clipped==clip_ray[2].clipped || fullclip) && clip_ray[1].clipped) {
- //all have been clipped
- proposed_pos=clip_ray[1].clip_pos-extraclip*(proposed_pos-target_pos).normalized();
- if (clip_ray[0].clipped)
- fullclip=true;
- noblend=true;
-
-
- } else {
-
-
- //Vector3 rel=follow_pos-target_pos;
-
- if (clip_ray[0].clipped && !clip_ray[2].clipped) {
-
- float distance = target_pos.distance_to(clip_ray[0].clip_pos);
- real_t amount = 1.0-(distance/clip_len);
- amount = CLAMP(amount,0,1)*autoturn_speed*time;
- if (clip_ray[1].clipped)
- amount*=2.0;
- //rotate_rel=Matrix3(Vector3(0,1,0),amount).xform(rel);
- rotate_orbit(Vector2(0,amount));
-
- } else if (clip_ray[2].clipped && !clip_ray[0].clipped) {
-
- float distance = target_pos.distance_to(clip_ray[2].clip_pos);
- real_t amount = 1.0-(distance/clip_len);
- amount = CLAMP(amount,0,1)*autoturn_speed*time;
- if (clip_ray[1].clipped)
- amount*=2.0;
- rotate_orbit(Vector2(0,-amount));
- }
-
- fullclip=false;
-
- }
- }
-
-
- Vector3 base_pos = get_global_transform().origin;
- Vector3 pull_from = base_pos;
- pull_from.y+=height; // height compensate
-
-
-
- Vector3 camera_target;
- if (use_lookat_target) {
-
- camera_target = lookat_target;
- } else {
- camera_target = base_pos;
- };
-
- Transform proposed;
- proposed.set_look_at(proposed_pos,camera_target,up_vector);
- proposed = proposed * Transform(Matrix3(Vector3(1,0,0),Math::deg2rad(inclination)),Vector3()); //inclination
-
-
- accepted=proposed;
- if (smooth && !noblend) {
-
-
- Vector3 vec1 = accepted.origin;
- Vector3 vec2 = final.origin;
- final.origin = vec2.linear_interpolate(vec1, MIN(1,smooth_pos_ratio * time));;
-
- Quat q1 = accepted.basis;
- Quat q2 = final.basis;
- final.basis = q2.slerp(q1, MIN(1,smooth_rot_ratio * time));
-
- } else {
- final=accepted;
- }
-
- _update_camera();
-
- // calculate the next proposed transform
-
-
- Vector3 new_pos;
-
- { /*follow code*/
-
-
-
- /* calculate some variables */
-
- Vector3 rel = follow_pos - pull_from;
-
- float l = rel.length();
- Vector3 rel_n = (l > 0) ? (rel/l) : Vector3();
- float ang = Math::acos(rel_n.dot( Vector3(0,1,0) ));
-
- Vector3 tangent = rel_n;
- tangent.y=0; // get rid of y
- if (tangent.length_squared() < CMP_EPSILON2)
- tangent=Vector3(0,0,1); // use Z as tangent if rel is parallel to y
- else
- tangent.normalize();
-
- /* now start applying the rules */
-
- //clip distance
- if (l > max_distance)
- l=max_distance;
- if (l < min_distance)
- l=min_distance;
-
- //fix angle
-
- float ang_min = Math_PI * 0.5 + Math::deg2rad(min_orbit_x);
- float ang_max = Math_PI * 0.5 + Math::deg2rad(max_orbit_x);
-
- if (ang<ang_min)
- ang=ang_min;
- if (ang>ang_max)
- ang=ang_max;
-
- /* finally, rebuild the validated camera position */
-
- new_pos=Vector3(0,Math::cos(ang),0);
- new_pos+=tangent*Math::sin(ang);
- new_pos*=l;
- new_pos+=pull_from;
- follow_pos=new_pos;
-
- }
-
- proposed_pos=new_pos;
-
- Vector3 rel = new_pos-camera_target;
-
-
- if (clip) {
-
- Vector<RID> exclude;
- exclude.push_back(target_body);
-
- for(int i=0;i<3;i++) {
-
- clip_ray[i].clipped=false;
- clip_ray[i].clip_pos=Vector3();
- clip_ray[i].cast_pos=camera_target;
-
- Vector3 cast_to = camera_target+Matrix3(Vector3(0,1,0),Math::deg2rad(autoturn_tolerance*(i-1.0))).xform(rel);
-
-
- if (i!=1) {
-
- Vector3 side = rel.cross(Vector3(0,1,0)).normalized()*(i-1.0);
- clip_ray[i].cast_pos+side*target_width+rel.normalized()*target_width;
-
- Vector3 d = -rel;
- d.rotate(Vector3(0,1,0),Math::deg2rad(get_fov())*(i-1.0));
- Plane p(new_pos,new_pos+d,new_pos+Vector3(0,1,0)); //fov clipping plane, build a face and use it as plane, facing doesn't matter
- Vector3 intersect;
- if (p.intersects_segment(clip_ray[i].cast_pos,cast_to,&intersect))
- cast_to=intersect;
-
- } else {
-
- cast_to+=rel.normalized()*extraclip;
- }
-
- // PhysicsServer::get_singleton()->query_intersection(clip_ray[i].query,get_world()->get_space(),exclude);
- // PhysicsServer::get_singleton()->query_intersection_segment(clip_ray[i].query,clip_ray[i].cast_pos,cast_to);
-
-
-
-
- }
-
- queries_active=true;
- } else {
-
- _clear_queries();
- }
- target_pos=camera_target;
- clip_len=rel.length();
-
-}
-
-void FollowCamera::set_use_lookat_target(bool p_use, const Vector3 &p_lookat) {
-
- use_lookat_target = p_use;
- lookat_target = p_lookat;
-};
-
-
-void FollowCamera::_notification(int p_what) {
-
- switch(p_what) {
-
- case NOTIFICATION_PROCESS: {
-
-
- _compute_camera();
- } break;
-
- case NOTIFICATION_ENTER_WORLD: {
-
- set_orbit(orbit);
- set_distance(distance);
-
- accepted=final=get_global_transform();
- proposed_pos=accepted.origin;
-
- target_body = RID();
-/*
- Node* parent = get_parent();
- while (parent) {
- PhysicsBody* p = parent->cast_to<PhysicsBody>();
- if (p) {
- target_body = p->get_body();
- break;
- };
- parent = parent->get_parent();
- };
-*/
- set_process(true);
-
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
- distance=get_distance();
- orbit=get_orbit();
- _clear_queries();
-
- } break;
- case NOTIFICATION_BECAME_CURRENT: {
-
- set_process(true);
- } break;
- case NOTIFICATION_LOST_CURRENT: {
-
- set_process(false);
- _clear_queries();
-
- } break;
- }
-
-}
-
-
-
-void FollowCamera::set_orbit(const Vector2& p_orbit) {
-
- orbit=p_orbit;
-
- if(is_inside_scene()) {
-
- Vector3 char_pos = get_global_transform().origin;
- char_pos.y+=height;
- float d = char_pos.distance_to(follow_pos);
-
- Matrix3 m;
- m.rotate(Vector3(0,1,0),orbit.y);
- m.rotate(Vector3(1,0,0),orbit.x);
-
- follow_pos=char_pos + m.get_axis(2) * d;
-
- }
-
- update_gizmo();
-
-}
-void FollowCamera::set_orbit_x(float p_x) {
-
- orbit.x=p_x;
- if(is_inside_scene())
- set_orbit(Vector2( p_x, get_orbit().y ));
-}
-void FollowCamera::set_orbit_y(float p_y) {
-
-
- orbit.y=p_y;
- if(is_inside_scene())
- set_orbit(Vector2( get_orbit().x, p_y ));
-
-}
-Vector2 FollowCamera::get_orbit() const {
-
-
- if (is_inside_scene()) {
-
- Vector3 char_pos = get_global_transform().origin;
- char_pos.y+=height;
- Vector3 rel = (follow_pos - char_pos).normalized();
- Vector2 ret_orbit;
- ret_orbit.x = Math::acos( Vector3(0,1,0).dot( rel ) ) - Math_PI * 0.5;
- ret_orbit.y = Math::atan2(rel.x,rel.z);
- return ret_orbit;
- }
- return orbit;
-}
-
-void FollowCamera::rotate_orbit(const Vector2& p_relative) {
-
- if (is_inside_scene()) {
-
- Matrix3 m;
- m.rotate(Vector3(0,1,0),Math::deg2rad(p_relative.y));
- m.rotate(Vector3(1,0,0),Math::deg2rad(p_relative.x));
-
- Vector3 char_pos = get_global_transform().origin;
- char_pos.y+=height;
- Vector3 rel = (follow_pos - char_pos);
- rel = m.xform(rel);
- follow_pos=char_pos+rel;
-
- }
-
- orbit+=p_relative;
- update_gizmo();
-}
-
-void FollowCamera::set_height(float p_height) {
-
-
- height=p_height;
- update_gizmo();
-}
-
-float FollowCamera::get_height() const {
-
- return height;
-
-}
-
-void FollowCamera::set_max_orbit_x(float p_max) {
-
- max_orbit_x=p_max;
- update_gizmo();
-}
-
-float FollowCamera::get_max_orbit_x() const {
-
- return max_orbit_x;
-}
-
-void FollowCamera::set_min_orbit_x(float p_min) {
-
- min_orbit_x=p_min;
- update_gizmo();
-}
-
-float FollowCamera::get_min_orbit_x() const {
-
- return min_orbit_x;
-}
-
-float FollowCamera::get_min_distance() const {
-
- return min_distance;
-}
-float FollowCamera::get_max_distance() const {
-
- return max_distance;
-}
-
-void FollowCamera::set_min_distance(float p_min) {
-
- min_distance=p_min;
- update_gizmo();
-}
-
-void FollowCamera::set_max_distance(float p_max) {
-
- max_distance = p_max;
- update_gizmo();
-}
-
-
-void FollowCamera::set_distance(float p_distance) {
-
- if (is_inside_scene()) {
-
- Vector3 char_pos = get_global_transform().origin;
- char_pos.y+=height;
- Vector3 rel = (follow_pos - char_pos).normalized();
- rel*=p_distance;
- follow_pos=char_pos+rel;
-
- }
-
- distance=p_distance;
-}
-
-float FollowCamera::get_distance() const {
-
- if (is_inside_scene()) {
-
- Vector3 char_pos = get_global_transform().origin;
- char_pos.y+=height;
- return (follow_pos - char_pos).length();
-
- }
-
- return distance;
-}
-
-void FollowCamera::set_clip(bool p_enabled) {
-
-
- clip=p_enabled;
-
- if (!p_enabled)
- _clear_queries();
-}
-
-bool FollowCamera::has_clip() const {
-
- return clip;
-
-}
-
-
-void FollowCamera::set_autoturn(bool p_enabled) {
-
-
- autoturn=p_enabled;
-}
-
-bool FollowCamera::has_autoturn() const {
-
- return autoturn;
-
-}
-
-void FollowCamera::set_autoturn_tolerance(float p_degrees) {
-
-
- autoturn_tolerance=p_degrees;
-}
-float FollowCamera::get_autoturn_tolerance() const {
-
-
- return autoturn_tolerance;
-}
-
-void FollowCamera::set_inclination(float p_degrees) {
-
-
- inclination=p_degrees;
-}
-float FollowCamera::get_inclination() const {
-
-
- return inclination;
-}
-
-
-void FollowCamera::set_autoturn_speed(float p_speed) {
-
-
- autoturn_speed=p_speed;
-}
-
-float FollowCamera::get_autoturn_speed() const {
-
- return autoturn_speed;
-
-}
-
-
-RES FollowCamera::_get_gizmo_geometry() const {
-
- Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
-
- Ref<FixedMaterial> mat( memnew( FixedMaterial ));
-
- mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(1.0,0.5,1.0,0.3) );
- mat->set_line_width(4);
- mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
- mat->set_flag(Material::FLAG_UNSHADED,true);
-// mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
-
- surface_tool->begin(Mesh::PRIMITIVE_LINES);
- surface_tool->set_material(mat);
-
-
- int steps=16;
-
- Vector3 base_up = Matrix3(Vector3(1,0,0),Math::deg2rad(max_orbit_x)).get_axis(2);
- Vector3 base_down = Matrix3(Vector3(1,0,0),Math::deg2rad(min_orbit_x)).get_axis(2);
-
- Vector3 ofs(0,height,0);
-
- for(int i=0;i<steps;i++) {
-
-
- Matrix3 rot(Vector3(0,1,0),Math_PI*2*float(i)/steps);
- Matrix3 rot2(Vector3(0,1,0),Math_PI*2*float(i+1)/steps);
-
- Vector3 up = rot.xform(base_up);
- Vector3 up2 = rot2.xform(base_up);
-
- Vector3 down = rot.xform(base_down);
- Vector3 down2 = rot2.xform(base_down);
-
- surface_tool->add_vertex(ofs+up*min_distance);
- surface_tool->add_vertex(ofs+up*max_distance);
- surface_tool->add_vertex(ofs+up*min_distance);
- surface_tool->add_vertex(ofs+up2*min_distance);
- surface_tool->add_vertex(ofs+up*max_distance);
- surface_tool->add_vertex(ofs+up2*max_distance);
-
- surface_tool->add_vertex(ofs+down*min_distance);
- surface_tool->add_vertex(ofs+down*max_distance);
- surface_tool->add_vertex(ofs+down*min_distance);
- surface_tool->add_vertex(ofs+down2*min_distance);
- surface_tool->add_vertex(ofs+down*max_distance);
- surface_tool->add_vertex(ofs+down2*max_distance);
-
- int substeps = 8;
-
- for(int j=0;j<substeps;j++) {
-
- Vector3 a = up.linear_interpolate(down,float(j)/substeps).normalized()*max_distance;
- Vector3 b = up.linear_interpolate(down,float(j+1)/substeps).normalized()*max_distance;
- Vector3 am = up.linear_interpolate(down,float(j)/substeps).normalized()*min_distance;
- Vector3 bm = up.linear_interpolate(down,float(j+1)/substeps).normalized()*min_distance;
-
- surface_tool->add_vertex(ofs+a);
- surface_tool->add_vertex(ofs+b);
- surface_tool->add_vertex(ofs+am);
- surface_tool->add_vertex(ofs+bm);
-
- }
- }
-
-
- return surface_tool->commit();
-
-
-}
-
-
-void FollowCamera::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("_set_initial_orbit","orbit"),&FollowCamera::_set_initial_orbit);
- ObjectTypeDB::bind_method(_MD("set_orbit","orbit"),&FollowCamera::set_orbit);
- ObjectTypeDB::bind_method(_MD("get_orbit"),&FollowCamera::get_orbit);
- ObjectTypeDB::bind_method(_MD("set_orbit_x","x"),&FollowCamera::set_orbit_x);
- ObjectTypeDB::bind_method(_MD("set_orbit_y","y"),&FollowCamera::set_orbit_y);
- ObjectTypeDB::bind_method(_MD("set_min_orbit_x","x"),&FollowCamera::set_min_orbit_x);
- ObjectTypeDB::bind_method(_MD("get_min_orbit_x"),&FollowCamera::get_min_orbit_x);
- ObjectTypeDB::bind_method(_MD("set_max_orbit_x","x"),&FollowCamera::set_max_orbit_x);
- ObjectTypeDB::bind_method(_MD("get_max_orbit_x"),&FollowCamera::get_max_orbit_x);
- ObjectTypeDB::bind_method(_MD("set_height","height"),&FollowCamera::set_height);
- ObjectTypeDB::bind_method(_MD("get_height"),&FollowCamera::get_height);
- ObjectTypeDB::bind_method(_MD("set_inclination","inclination"),&FollowCamera::set_inclination);
- ObjectTypeDB::bind_method(_MD("get_inclination"),&FollowCamera::get_inclination);
-
- ObjectTypeDB::bind_method(_MD("rotate_orbit"),&FollowCamera::rotate_orbit);
- ObjectTypeDB::bind_method(_MD("set_distance","distance"),&FollowCamera::set_distance);
- ObjectTypeDB::bind_method(_MD("get_distance"),&FollowCamera::get_distance);
- ObjectTypeDB::bind_method(_MD("set_max_distance","max_distance"),&FollowCamera::set_max_distance);
- ObjectTypeDB::bind_method(_MD("get_max_distance"),&FollowCamera::get_max_distance);
- ObjectTypeDB::bind_method(_MD("set_min_distance","min_distance"),&FollowCamera::set_min_distance);
- ObjectTypeDB::bind_method(_MD("get_min_distance"),&FollowCamera::get_min_distance);
- ObjectTypeDB::bind_method(_MD("set_clip","enable"),&FollowCamera::set_clip);
- ObjectTypeDB::bind_method(_MD("has_clip"),&FollowCamera::has_clip);
- ObjectTypeDB::bind_method(_MD("set_autoturn","enable"),&FollowCamera::set_autoturn);
- ObjectTypeDB::bind_method(_MD("has_autoturn"),&FollowCamera::has_autoturn);
- ObjectTypeDB::bind_method(_MD("set_autoturn_tolerance","degrees"),&FollowCamera::set_autoturn_tolerance);
- ObjectTypeDB::bind_method(_MD("get_autoturn_tolerance"),&FollowCamera::get_autoturn_tolerance);
- ObjectTypeDB::bind_method(_MD("set_autoturn_speed","speed"),&FollowCamera::set_autoturn_speed);
- ObjectTypeDB::bind_method(_MD("get_autoturn_speed"),&FollowCamera::get_autoturn_speed);
- ObjectTypeDB::bind_method(_MD("set_smoothing","enable"),&FollowCamera::set_smoothing);
- ObjectTypeDB::bind_method(_MD("has_smoothing"),&FollowCamera::has_smoothing);
- ObjectTypeDB::bind_method(_MD("set_rotation_smoothing","amount"),&FollowCamera::set_rotation_smoothing);
- ObjectTypeDB::bind_method(_MD("get_rotation_smoothing"),&FollowCamera::get_rotation_smoothing);
- ObjectTypeDB::bind_method(_MD("set_translation_smoothing","amount"),&FollowCamera::set_translation_smoothing);
- ObjectTypeDB::bind_method(_MD("get_translation_smoothing"),&FollowCamera::get_translation_smoothing);
- ObjectTypeDB::bind_method(_MD("set_use_lookat_target","use","lookat"),&FollowCamera::set_use_lookat_target, DEFVAL(Vector3()));
- ObjectTypeDB::bind_method(_MD("set_up_vector","vector"),&FollowCamera::set_up_vector);
- ObjectTypeDB::bind_method(_MD("get_up_vector"),&FollowCamera::get_up_vector);
-
- ObjectTypeDB::bind_method(_MD("_ray_collision"),&FollowCamera::_ray_collision);
-
- ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "orbit" ), _SCS("_set_initial_orbit"),_SCS("get_orbit") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "height", PROPERTY_HINT_RANGE,"-1024,1024,0.01" ), _SCS("set_height"), _SCS("get_height") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "inclination", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_inclination"), _SCS("get_inclination") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "max_orbit_x", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_max_orbit_x"), _SCS("get_max_orbit_x") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "min_orbit_x", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_min_orbit_x"), _SCS("get_min_orbit_x") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "min_distance", PROPERTY_HINT_RANGE,"0,100,0.01" ), _SCS("set_min_distance"), _SCS("get_min_distance") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "max_distance", PROPERTY_HINT_RANGE,"0,100,0.01" ), _SCS("set_max_distance"), _SCS("get_max_distance") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "distance", PROPERTY_HINT_RANGE,"0.01,1024,0,01"), _SCS("set_distance"), _SCS("get_distance") );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "clip"), _SCS("set_clip"), _SCS("has_clip") );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "autoturn"), _SCS("set_autoturn"), _SCS("has_autoturn") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "autoturn_tolerance", PROPERTY_HINT_RANGE,"1,90,0.01") , _SCS("set_autoturn_tolerance"), _SCS("get_autoturn_tolerance") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "autoturn_speed", PROPERTY_HINT_RANGE,"1,90,0.01"), _SCS("set_autoturn_speed"), _SCS("get_autoturn_speed") );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "smoothing"), _SCS("set_smoothing"), _SCS("has_smoothing") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "translation_smooth", PROPERTY_HINT_RANGE,"0.01,128,0.01"), _SCS("set_translation_smoothing"), _SCS("get_translation_smoothing") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "rotation_smooth", PROPERTY_HINT_RANGE,"0.01,128,0.01"), _SCS("set_rotation_smoothing"), _SCS("get_rotation_smoothing") );
-
-
-}
-
-void FollowCamera::_ray_collision(Vector3 p_point, Vector3 p_normal, int p_subindex, ObjectID p_against,int p_idx) {
-
- clip_ray[p_idx].clip_pos=p_point;
- clip_ray[p_idx].clipped=true;
-
-};
-
-Transform FollowCamera::get_camera_transform() const {
-
- return final;
-}
-
-void FollowCamera::set_smoothing(bool p_enable) {
-
- smooth=p_enable;
-}
-
-bool FollowCamera::has_smoothing() const {
-
- return smooth;
-}
-
-void FollowCamera::set_translation_smoothing(float p_amount) {
-
- smooth_pos_ratio=p_amount;
-}
-float FollowCamera::get_translation_smoothing() const {
-
- return smooth_pos_ratio;
-}
-
-void FollowCamera::set_rotation_smoothing(float p_amount) {
-
- smooth_rot_ratio=p_amount;
-
-}
-
-void FollowCamera::set_up_vector(const Vector3& p_up) {
-
- up_vector=p_up;
-}
-
-Vector3 FollowCamera::get_up_vector() const{
-
- return up_vector;
-}
-
-float FollowCamera::get_rotation_smoothing() const {
-
- return smooth_pos_ratio;
-
-}
-
-
-FollowCamera::FollowCamera() {
-
-
- height=1;
-
- orbit=Vector2(0,0);
- up_vector=Vector3(0,1,0);
-
- distance=3;
- min_distance=2;
- max_distance=5;
-
- autoturn=true;
- autoturn_tolerance=10;
- autoturn_speed=80;
-
- min_orbit_x=-50;
- max_orbit_x=70;
- inclination=0;
- target_width=0.3;
-
- clip=true;
- use_lookat_target = false;
- extraclip=0.3;
- fullclip=false;
-
- smooth=true;
- smooth_rot_ratio=10;
- smooth_pos_ratio=10;
-
-
- for(int i=0;i<3;i++) {
-// clip_ray[i].query=PhysicsServer::get_singleton()->query_create(this, "_ray_collision", i, true);
- clip_ray[i].clipped=false;
- }
-
- queries_active=false;
-
-
-}
-
-FollowCamera::~FollowCamera() {
-
- for(int i=0;i<3;i++) {
- PhysicsServer::get_singleton()->free(clip_ray[i].query);
- }
-
-
-}
diff --git a/scene/3d/follow_camera.h b/scene/3d/follow_camera.h
deleted file mode 100644
index 10912eb606..0000000000
--- a/scene/3d/follow_camera.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*************************************************************************/
-/* follow_camera.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef FOLLOW_CAMERA_H
-#define FOLLOW_CAMERA_H
-
-#include "scene/3d/camera.h"
-
-class FollowCamera : public Camera {
-
- OBJ_TYPE( FollowCamera, Camera );
-
-private:
-
-
- //used for follow
- Vector3 follow_pos;
- //used for fixed
- Vector2 initial_orbit;
- Vector2 orbit;
- float distance;
-
- float height;
- float target_width;
-
- float min_distance;
- float max_distance;
-
- float max_orbit_x;
- float min_orbit_x;
-
- float inclination;
- float extraclip;
- bool fullclip;
-
- bool clip;
- bool autoturn;
- float autoturn_tolerance;
- float autoturn_speed;
-
- bool smooth;
- float smooth_rot_ratio;
- float smooth_pos_ratio;
-
-
-
- struct ClipRay {
- RID query;
- bool clipped;
- Vector3 cast_pos;
- Vector3 clip_pos;
- };
-
- ClipRay clip_ray[3];
- Vector3 target_pos;
- float clip_len;
-
- Vector3 up_vector;
-
-
- virtual RES _get_gizmo_geometry() const;
-
- Transform ted;
- Vector3 proposed_pos;
- Transform accepted;
- Transform final;
- RID target_body;
-
- bool use_lookat_target;
- Vector3 lookat_target;
-
- void _compute_camera();
-
- bool queries_active;
- void _clear_queries();
-
- void _set_initial_orbit(const Vector2& p_orbit);
-
-protected:
-
- virtual void _request_camera_update() {} //ignore
-
- void _notification(int p_what);
-
- static void _bind_methods();
-
- void _ray_collision(Vector3 p_point, Vector3 p_normal, int p_subindex, ObjectID p_against,int p_idx);
-
-public:
-
-
- void set_orbit(const Vector2& p_orbit);
- void set_orbit_x(float p_x);
- void set_orbit_y(float p_y);
- Vector2 get_orbit() const;
-
- void set_height(float p_height);
- float get_height() const;
-
- void set_inclination(float p_degrees);
- float get_inclination() const;
-
- void set_max_orbit_x(float p_max);
- float get_max_orbit_x() const;
-
- void set_min_orbit_x(float p_min);
- float get_min_orbit_x() const;
-
- void rotate_orbit(const Vector2& p_relative);
-
- void set_distance(float p_distance);
- float get_distance() const;
-
- float get_min_distance() const;
- float get_max_distance() const;
- void set_min_distance(float p_min);
- void set_max_distance(float p_max);
-
- /** FINISH THIS AND CLEAN IT UP */
-
- void set_clip(bool p_enabled);
- bool has_clip() const;
-
- void set_autoturn(bool p_enabled);
- bool has_autoturn() const;
-
- void set_autoturn_tolerance(float p_degrees);
- float get_autoturn_tolerance() const;
-
- void set_autoturn_speed(float p_speed);
- float get_autoturn_speed() const;
-
- void set_smoothing(bool p_enable);
- bool has_smoothing() const;
-
- void set_translation_smoothing(float p_amount);
- float get_translation_smoothing() const;
-
- void set_rotation_smoothing(float p_amount);
- float get_rotation_smoothing() const;
-
- void set_use_lookat_target(bool p_use, const Vector3 &p_lookat = Vector3());
-
- void set_up_vector(const Vector3& p_up);
- Vector3 get_up_vector() const;
-
- virtual Transform get_camera_transform() const;
-
- FollowCamera();
- ~FollowCamera();
-};
-
-
-
-#endif // FOLLOW_CAMERA_H
diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp
index 1459f2c362..651d20ae71 100644
--- a/scene/3d/immediate_geometry.cpp
+++ b/scene/3d/immediate_geometry.cpp
@@ -72,6 +72,53 @@ DVector<Face3> ImmediateGeometry::get_faces(uint32_t p_usage_flags) const {
return DVector<Face3>();
}
+
+
+void ImmediateGeometry::add_sphere(int p_lats,int p_lons,float p_radius) {
+
+ for(int i = 1; i <= p_lats; i++) {
+ double lat0 = Math_PI * (-0.5 + (double) (i - 1) / p_lats);
+ double z0 = Math::sin(lat0);
+ double zr0 = Math::cos(lat0);
+
+ double lat1 = Math_PI * (-0.5 + (double) i / p_lats);
+ double z1 = Math::sin(lat1);
+ double zr1 = Math::cos(lat1);
+
+ for(int j = p_lons; j >= 1; j--) {
+
+ double lng0 = 2 * Math_PI * (double) (j - 1) / p_lons;
+ double x0 = Math::cos(lng0);
+ double y0 = Math::sin(lng0);
+
+ double lng1 = 2 * Math_PI * (double) (j) / p_lons;
+ double x1 = Math::cos(lng1);
+ double y1 = Math::sin(lng1);
+
+
+ Vector3 v[4]={
+ Vector3(x1 * zr0, z0, y1 *zr0),
+ Vector3(x1 * zr1, z1, y1 *zr1),
+ Vector3(x0 * zr1, z1, y0 *zr1),
+ Vector3(x0 * zr0, z0, y0 *zr0)
+ };
+
+#define ADD_POINT(m_idx)\
+ set_normal(v[m_idx]);\
+ add_vertex(v[m_idx]*p_radius);
+
+ ADD_POINT(0);
+ ADD_POINT(1);
+ ADD_POINT(2);
+
+ ADD_POINT(2);
+ ADD_POINT(3);
+ ADD_POINT(0);
+ }
+ }
+
+}
+
void ImmediateGeometry::_bind_methods() {
ObjectTypeDB::bind_method(_MD("begin","primitive","texture:Texture"),&ImmediateGeometry::begin);
@@ -80,12 +127,15 @@ void ImmediateGeometry::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_color","color"),&ImmediateGeometry::set_color);
ObjectTypeDB::bind_method(_MD("set_uv","uv"),&ImmediateGeometry::set_uv);
ObjectTypeDB::bind_method(_MD("set_uv2","uv"),&ImmediateGeometry::set_uv2);
- ObjectTypeDB::bind_method(_MD("add_vertex","color"),&ImmediateGeometry::add_vertex);
+ ObjectTypeDB::bind_method(_MD("add_vertex","pos"),&ImmediateGeometry::add_vertex);
+ ObjectTypeDB::bind_method(_MD("add_sphere","lats","lons","radius"),&ImmediateGeometry::add_sphere);
ObjectTypeDB::bind_method(_MD("end"),&ImmediateGeometry::end);
ObjectTypeDB::bind_method(_MD("clear"),&ImmediateGeometry::clear);
}
+
+
ImmediateGeometry::ImmediateGeometry() {
im = VisualServer::get_singleton()->immediate_create();
diff --git a/scene/3d/immediate_geometry.h b/scene/3d/immediate_geometry.h
index 2db81134c6..beb8ea8214 100644
--- a/scene/3d/immediate_geometry.h
+++ b/scene/3d/immediate_geometry.h
@@ -31,6 +31,11 @@ public:
void end();
void clear();
+
+ void add_sphere(int p_lats,int p_lons,float p_radius);
+
+
+
virtual AABB get_aabb() const;
virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp
index 4d8c9cf7a5..f44713e8a0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,9 +32,9 @@
void InterpolatedCamera::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
- if (get_scene()->is_editor_hint() && enabled)
+ if (get_tree()->is_editor_hint() && enabled)
set_fixed_process(false);
} break;
@@ -50,7 +50,7 @@ void InterpolatedCamera::_notification(int p_what) {
float delta = speed*get_process_delta_time();
Transform target_xform = node->get_global_transform();
- Transform local_transform = get_transform();
+ Transform local_transform = get_global_transform();
local_transform = local_transform.interpolate_with(target_xform,delta);
set_global_transform(local_transform);
@@ -109,7 +109,7 @@ void InterpolatedCamera::set_interpolation_enabled(bool p_enable) {
return;
enabled=p_enable;
if (p_enable) {
- if (is_inside_scene() && get_scene()->is_editor_hint())
+ if (is_inside_tree() && get_tree()->is_editor_hint())
return;
set_process(true);
} else
@@ -136,7 +136,7 @@ void InterpolatedCamera::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_target_path","target_path"),&InterpolatedCamera::set_target_path);
ObjectTypeDB::bind_method(_MD("get_target_path"),&InterpolatedCamera::get_target_path);
- ObjectTypeDB::bind_method(_MD("set_target","target"),&InterpolatedCamera::_set_target);
+ ObjectTypeDB::bind_method(_MD("set_target","target:Camera"),&InterpolatedCamera::_set_target);
ObjectTypeDB::bind_method(_MD("set_speed","speed"),&InterpolatedCamera::set_speed);
ObjectTypeDB::bind_method(_MD("get_speed"),&InterpolatedCamera::get_speed);
diff --git a/scene/3d/interpolated_camera.h b/scene/3d/interpolated_camera.h
index da0e3d562b..a8ed649c42 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,38 +26,38 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef INTERPOLATED_CAMERA_H
-#define INTERPOLATED_CAMERA_H
-
-#include "scene/3d/camera.h"
-
-class InterpolatedCamera : public Camera {
-
- OBJ_TYPE(InterpolatedCamera,Camera);
-
- bool enabled;
- real_t speed;
- NodePath target;
-protected:
-
- void _notification(int p_what);
- static void _bind_methods();
- void _set_target(const Object *p_target);
-
-public:
-
- void set_target(const Spatial *p_target);
- void set_target_path(const NodePath& p_path);
- NodePath get_target_path() const;
-
- void set_speed(real_t p_speed);
- real_t get_speed() const;
-
- void set_interpolation_enabled(bool p_enable);
- bool is_interpolation_enabled() const;
-
-
- InterpolatedCamera();
-};
-
-#endif // INTERPOLATED_CAMERA_H
+#ifndef INTERPOLATED_CAMERA_H
+#define INTERPOLATED_CAMERA_H
+
+#include "scene/3d/camera.h"
+
+class InterpolatedCamera : public Camera {
+
+ OBJ_TYPE(InterpolatedCamera,Camera);
+
+ bool enabled;
+ real_t speed;
+ NodePath target;
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+ void _set_target(const Object *p_target);
+
+public:
+
+ void set_target(const Spatial *p_target);
+ void set_target_path(const NodePath& p_path);
+ NodePath get_target_path() const;
+
+ void set_speed(real_t p_speed);
+ real_t get_speed() const;
+
+ void set_interpolation_enabled(bool p_enable);
+ bool is_interpolation_enabled() const;
+
+
+ InterpolatedCamera();
+};
+
+#endif // INTERPOLATED_CAMERA_H
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 25f3b3d3a5..9f9c87b675 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -415,11 +415,11 @@ void Light::approximate_opengl_attenuation(float p_constant, float p_linear, flo
float energy=1.0;
- if (p_constant>0)
+ /*if (p_constant>0)
energy=1.0/p_constant; //energy is this
else
energy=8.0; // some high number..
-
+*/
if (radius==10000)
radius=100; //bug?
@@ -429,10 +429,42 @@ void Light::approximate_opengl_attenuation(float p_constant, float p_linear, flo
}
+
+void Light::_update_visibility() {
+
+ if (!is_inside_tree())
+ return;
+
+
+bool editor_ok=true;
+
+#ifdef TOOLS_ENABLED
+ if (editor_only) {
+ if (!get_tree()->is_editor_hint()) {
+ editor_ok=false;
+ } else {
+ editor_ok = (get_tree()->get_edited_scene_root() && (this==get_tree()->get_edited_scene_root() || get_owner()==get_tree()->get_edited_scene_root()));
+ }
+ }
+#endif
+
+ VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible() && enabled && editor_ok);
+ _change_notify("geometry/visible");
+
+}
+
+
+void Light::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE || p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+ _update_visibility();
+ }
+}
+
void Light::set_enabled(bool p_enabled) {
enabled=p_enabled;
- VS::get_singleton()->instance_light_set_enabled(get_instance(),enabled);
+ _update_visibility();
}
bool Light::is_enabled() const{
@@ -440,6 +472,17 @@ bool Light::is_enabled() const{
return enabled;
}
+void Light::set_editor_only(bool p_editor_only) {
+
+ editor_only=p_editor_only;
+ _update_visibility();
+}
+
+bool Light::is_editor_only() const{
+
+ return editor_only;
+}
+
void Light::_bind_methods() {
@@ -457,10 +500,13 @@ void Light::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_bake_mode"), &Light::get_bake_mode );
ObjectTypeDB::bind_method(_MD("set_enabled","enabled"), &Light::set_enabled );
ObjectTypeDB::bind_method(_MD("is_enabled"), &Light::is_enabled );
+ ObjectTypeDB::bind_method(_MD("set_editor_only","editor_only"), &Light::set_editor_only );
+ ObjectTypeDB::bind_method(_MD("is_editor_only"), &Light::is_editor_only );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/enabled"), _SCS("set_enabled"), _SCS("is_enabled"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode"));
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Indirect+Shadows,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode"));
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY );
/*
if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) {
@@ -477,7 +523,7 @@ void Light::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/diffuse"), _SCS("set_color"), _SCS("get_color"),COLOR_DIFFUSE);
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/specular"), _SCS("set_color"), _SCS("get_color"),COLOR_SPECULAR);
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/shadow"), _SCS("set_project_shadows"), _SCS("has_project_shadows"));
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING );
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING );
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_offset", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_OFFSET);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_slope_scale", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_SLOPE_SCALE);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/esm_multiplier", PROPERTY_HINT_RANGE, "1.0,512.0,0.1"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_ESM_MULTIPLIER);
@@ -498,6 +544,12 @@ void Light::_bind_methods() {
BIND_CONSTANT( COLOR_DIFFUSE );
BIND_CONSTANT( COLOR_SPECULAR );
+ BIND_CONSTANT( BAKE_MODE_DISABLED );
+ BIND_CONSTANT( BAKE_MODE_INDIRECT );
+ BIND_CONSTANT( BAKE_MODE_INDIRECT_AND_SHADOWS );
+ BIND_CONSTANT( BAKE_MODE_FULL );
+
+
}
@@ -525,6 +577,7 @@ Light::Light(VisualServer::LightType p_type) {
set_project_shadows( false );
set_base(light);
enabled=true;
+ editor_only=false;
bake_mode=BAKE_MODE_DISABLED;
}
@@ -616,7 +669,7 @@ void SpotLight::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ATTENUATION );
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_angle", PROPERTY_HINT_RANGE, "0.01,89.9,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPOT_ANGLE );
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ATTENUATION );
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_attenuation", PROPERTY_HINT_EXP_EASING, "spot_attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPOT_ATTENUATION );
}
diff --git a/scene/3d/light.h b/scene/3d/light.h
index 6b1ea2d455..fb77ac9e64 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,7 +49,7 @@ public:
PARAM_ENERGY=VisualServer::LIGHT_PARAM_ENERGY,
PARAM_ATTENUATION=VisualServer::LIGHT_PARAM_ATTENUATION,
PARAM_SPOT_ANGLE=VisualServer::LIGHT_PARAM_SPOT_ANGLE,
- PARAM_SPOT_ATTENUATION=VisualServer::LIGHT_PARAM_ATTENUATION,
+ PARAM_SPOT_ATTENUATION=VisualServer::LIGHT_PARAM_SPOT_ATTENUATION,
PARAM_SHADOW_DARKENING=VisualServer::LIGHT_PARAM_SHADOW_DARKENING,
PARAM_SHADOW_Z_OFFSET=VisualServer::LIGHT_PARAM_SHADOW_Z_OFFSET,
PARAM_SHADOW_Z_SLOPE_SCALE=VisualServer::LIGHT_PARAM_SHADOW_Z_SLOPE_SCALE,
@@ -69,6 +69,7 @@ public:
BAKE_MODE_DISABLED,
BAKE_MODE_INDIRECT,
+ BAKE_MODE_INDIRECT_AND_SHADOWS,
BAKE_MODE_FULL
};
@@ -91,8 +92,10 @@ private:
VisualServer::LightType type;
bool shadows;
bool enabled;
+ bool editor_only;
Operator op;
-
+
+ void _update_visibility();
// bind helpers
protected:
@@ -103,6 +106,7 @@ protected:
virtual RES _get_gizmo_geometry() const;
static void _bind_methods();
+ void _notification(int p_what);
Light(VisualServer::LightType p_type);
@@ -131,6 +135,9 @@ public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
+ void set_editor_only(bool p_editor_only);
+ bool is_editor_only() const;
+
virtual AABB get_aabb() const;
virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
@@ -196,7 +203,7 @@ protected:
public:
- OmniLight() : Light( VisualServer::LIGHT_OMNI ) {}
+ OmniLight() : Light( VisualServer::LIGHT_OMNI ) { set_parameter(PARAM_SHADOW_Z_OFFSET,0.001);}
};
class SpotLight : public Light {
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 40981d468e..62b32729c3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#include "skeleton.h"
#include "physics_body.h"
-
+#include "body_shape.h"
bool MeshInstance::_set(const StringName& p_name, const Variant& p_value) {
@@ -126,7 +126,7 @@ void MeshInstance::_resolve_skeleton_path(){
void MeshInstance::set_skeleton_path(const NodePath &p_skeleton) {
skeleton_path = p_skeleton;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
_resolve_skeleton_path();
}
@@ -168,7 +168,7 @@ Node* MeshInstance::create_trimesh_collision_node() {
static_body->add_shape( shape );
return static_body;
- return NULL;
+
}
void MeshInstance::create_trimesh_collision() {
@@ -181,6 +181,11 @@ void MeshInstance::create_trimesh_collision() {
add_child(static_body);
if (get_owner())
static_body->set_owner( get_owner() );
+ CollisionShape *cshape = memnew( CollisionShape );
+ cshape->set_shape(static_body->get_shape(0));
+ static_body->add_child(cshape);
+ if (get_owner())
+ cshape->set_owner( get_owner() );
}
@@ -197,7 +202,7 @@ Node* MeshInstance::create_convex_collision_node() {
static_body->add_shape( shape );
return static_body;
- return NULL;
+
}
void MeshInstance::create_convex_collision() {
@@ -210,12 +215,18 @@ void MeshInstance::create_convex_collision() {
add_child(static_body);
if (get_owner())
static_body->set_owner( get_owner() );
+ CollisionShape *cshape = memnew( CollisionShape );
+ cshape->set_shape(static_body->get_shape(0));
+ static_body->add_child(cshape);
+ if (get_owner())
+ cshape->set_owner( get_owner() );
+
}
void MeshInstance::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
_resolve_skeleton_path();
}
}
@@ -229,9 +240,9 @@ void MeshInstance::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_skeleton_path:NodePath"),&MeshInstance::get_skeleton_path);
ObjectTypeDB::bind_method(_MD("get_aabb"),&MeshInstance::get_aabb);
ObjectTypeDB::bind_method(_MD("create_trimesh_collision"),&MeshInstance::create_trimesh_collision);
- ObjectTypeDB::set_method_flags("MeshInstance","create_trimesh_collision",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+ ObjectTypeDB::set_method_flags("MeshInstance","create_trimesh_collision",METHOD_FLAGS_DEFAULT);
ObjectTypeDB::bind_method(_MD("create_convex_collision"),&MeshInstance::create_convex_collision);
- ObjectTypeDB::set_method_flags("MeshInstance","create_convex_collision",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+ ObjectTypeDB::set_method_flags("MeshInstance","create_convex_collision",METHOD_FLAGS_DEFAULT);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "mesh/mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh" ), _SCS("set_mesh"), _SCS("get_mesh"));
ADD_PROPERTY( PropertyInfo (Variant::NODE_PATH, "mesh/skeleton"), _SCS("set_skeleton_path"), _SCS("get_skeleton_path"));
}
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 1b97564b4e..76a0eeea60 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/multimesh_instance.cpp b/scene/3d/multimesh_instance.cpp
index b4e58aca40..cd620ff447 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/multimesh_instance.h b/scene/3d/multimesh_instance.h
index fd50140bae..be6b3677e2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
new file mode 100644
index 0000000000..ce28350be0
--- /dev/null
+++ b/scene/3d/navigation.cpp
@@ -0,0 +1,725 @@
+#include "navigation.h"
+
+void Navigation::_navmesh_link(int p_id) {
+
+ ERR_FAIL_COND(!navmesh_map.has(p_id));
+ NavMesh &nm=navmesh_map[p_id];
+ ERR_FAIL_COND(nm.linked);
+
+ print_line("LINK");
+
+ DVector<Vector3> vertices=nm.navmesh->get_vertices();
+ int len = vertices.size();
+ if (len==0)
+ return;
+
+ DVector<Vector3>::Read r=vertices.read();
+
+ for(int i=0;i<nm.navmesh->get_polygon_count();i++) {
+
+ //build
+
+ List<Polygon>::Element *P=nm.polygons.push_back(Polygon());
+ Polygon &p=P->get();
+ p.owner=&nm;
+
+ Vector<int> poly = nm.navmesh->get_polygon(i);
+ int plen=poly.size();
+ const int *indices=poly.ptr();
+ bool valid=true;
+ p.edges.resize(plen);
+
+ Vector3 center;
+ float sum=0;
+
+ for(int j=0;j<plen;j++) {
+
+ int idx = indices[j];
+ if (idx<0 || idx>=len) {
+ valid=false;
+ break;
+ }
+
+ Polygon::Edge e;
+ Vector3 ep=nm.xform.xform(r[idx]);
+ center+=ep;
+ e.point=_get_point(ep);
+ p.edges[j]=e;
+
+ if (j>=2) {
+ Vector3 epa = nm.xform.xform(r[indices[j-2]]);
+ Vector3 epb = nm.xform.xform(r[indices[j-1]]);
+
+ sum+=up.dot((epb-epa).cross(ep-epa));
+
+ }
+
+ }
+
+ p.clockwise=sum>0;
+
+ if (!valid) {
+ nm.polygons.pop_back();
+ ERR_CONTINUE(!valid);
+ continue;
+ }
+
+ p.center=center/plen;
+
+ //connect
+
+ for(int j=0;j<plen;j++) {
+
+ int next = (j+1)%plen;
+ EdgeKey ek(p.edges[j].point,p.edges[next].point);
+
+ Map<EdgeKey,Connection>::Element *C=connections.find(ek);
+ if (!C) {
+
+ Connection c;
+ c.A=&p;
+ c.A_edge=j;
+ c.B=NULL;
+ c.B_edge=-1;
+ connections[ek]=c;
+ } else {
+
+ if (C->get().B!=NULL) {
+ ConnectionPending pending;
+ pending.polygon=&p;
+ pending.edge=j;
+ p.edges[j].P=C->get().pending.push_back(pending);
+ continue;
+ //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
+ }
+ //ERR_CONTINUE(C->get().B!=NULL); //wut
+
+ C->get().B=&p;
+ C->get().B_edge=j;
+ C->get().A->edges[C->get().A_edge].C=&p;
+ C->get().A->edges[C->get().A_edge].C_edge=j;;
+ p.edges[j].C=C->get().A;
+ p.edges[j].C_edge=C->get().A_edge;
+ //connection successful.
+ }
+ }
+ }
+
+ nm.linked=true;
+
+}
+
+
+void Navigation::_navmesh_unlink(int p_id) {
+
+ ERR_FAIL_COND(!navmesh_map.has(p_id));
+ NavMesh &nm=navmesh_map[p_id];
+ ERR_FAIL_COND(!nm.linked);
+
+ print_line("UNLINK");
+
+ for (List<Polygon>::Element *E=nm.polygons.front();E;E=E->next()) {
+
+
+ Polygon &p=E->get();
+
+ int ec = p.edges.size();
+ Polygon::Edge *edges=p.edges.ptr();
+
+ for(int i=0;i<ec;i++) {
+ int next = (i+1)%ec;
+
+ EdgeKey ek(edges[i].point,edges[next].point);
+ Map<EdgeKey,Connection>::Element *C=connections.find(ek);
+
+ ERR_CONTINUE(!C);
+
+ if (edges[i].P) {
+ C->get().pending.erase(edges[i].P);
+ edges[i].P=NULL;
+ } else if (C->get().B) {
+ //disconnect
+
+ C->get().B->edges[C->get().B_edge].C=NULL;
+ C->get().B->edges[C->get().B_edge].C_edge=-1;
+ C->get().A->edges[C->get().A_edge].C=NULL;
+ C->get().A->edges[C->get().A_edge].C_edge=-1;
+
+ if (C->get().A==&E->get()) {
+
+ C->get().A=C->get().B;
+ C->get().A_edge=C->get().B_edge;
+ }
+ C->get().B=NULL;
+ C->get().B_edge=-1;
+
+ if (C->get().pending.size()) {
+ //reconnect if something is pending
+ ConnectionPending cp = C->get().pending.front()->get();
+ C->get().pending.pop_front();
+
+ C->get().B=cp.polygon;
+ C->get().B_edge=cp.edge;
+ C->get().A->edges[C->get().A_edge].C=cp.polygon;
+ C->get().A->edges[C->get().A_edge].C_edge=cp.edge;
+ cp.polygon->edges[cp.edge].C=C->get().A;
+ cp.polygon->edges[cp.edge].C_edge=C->get().A_edge;
+ cp.polygon->edges[cp.edge].P=NULL;
+ }
+
+ } else {
+ connections.erase(C);
+ //erase
+ }
+ }
+ }
+
+ nm.polygons.clear();
+
+ nm.linked=false;
+
+
+}
+
+
+int Navigation::navmesh_create(const Ref<NavigationMesh>& p_mesh, const Transform& p_xform, Object *p_owner) {
+
+ int id = last_id++;
+ NavMesh nm;
+ nm.linked=false;
+ nm.navmesh=p_mesh;
+ nm.xform=p_xform;
+ nm.owner=p_owner;
+ navmesh_map[id]=nm;
+
+ _navmesh_link(id);
+
+ return id;
+}
+
+void Navigation::navmesh_set_transform(int p_id, const Transform& p_xform){
+
+ ERR_FAIL_COND(!navmesh_map.has(p_id));
+ NavMesh &nm=navmesh_map[p_id];
+ if (nm.xform==p_xform)
+ return; //bleh
+ _navmesh_unlink(p_id);
+ nm.xform=p_xform;
+ _navmesh_link(p_id);
+
+
+
+}
+void Navigation::navmesh_remove(int p_id){
+
+ ERR_FAIL_COND(!navmesh_map.has(p_id));
+ _navmesh_unlink(p_id);
+ navmesh_map.erase(p_id);
+
+}
+
+void Navigation::_clip_path(Vector<Vector3>& path, Polygon *from_poly, const Vector3& p_to_point, Polygon* p_to_poly) {
+
+ Vector3 from = path[path.size()-1];
+
+ if (from.distance_to(p_to_point)<CMP_EPSILON)
+ return;
+ Plane cut_plane;
+ cut_plane.normal = (from-p_to_point).cross(up);
+ if (cut_plane.normal==Vector3())
+ return;
+ cut_plane.normal.normalize();
+ cut_plane.d = cut_plane.normal.dot(from);
+
+
+ while(from_poly!=p_to_poly) {
+
+ int pe = from_poly->prev_edge;
+ Vector3 a = _get_vertex(from_poly->edges[pe].point);
+ Vector3 b = _get_vertex(from_poly->edges[(pe+1)%from_poly->edges.size()].point);
+
+ from_poly=from_poly->edges[pe].C;
+ ERR_FAIL_COND(!from_poly);
+
+ if (a.distance_to(b)>CMP_EPSILON) {
+
+ Vector3 inters;
+ if (cut_plane.intersects_segment(a,b,&inters)) {
+ if (inters.distance_to(p_to_point)>CMP_EPSILON && inters.distance_to(path[path.size()-1])>CMP_EPSILON) {
+ path.push_back(inters);
+ }
+ }
+ }
+ }
+}
+
+Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end, bool p_optimize) {
+
+
+ Polygon *begin_poly=NULL;
+ Polygon *end_poly=NULL;
+ Vector3 begin_point;
+ Vector3 end_point;
+ float begin_d=1e20;
+ float end_d=1e20;
+
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 spoint = f.get_closest_point_to(p_start);
+ float dpoint = spoint.distance_to(p_start);
+ if (dpoint<begin_d) {
+ begin_d=dpoint;
+ begin_poly=&p;
+ begin_point=spoint;
+ }
+
+ spoint = f.get_closest_point_to(p_end);
+ dpoint = spoint.distance_to(p_end);
+ if (dpoint<end_d) {
+ end_d=dpoint;
+ end_poly=&p;
+ end_point=spoint;
+ }
+ }
+
+ p.prev_edge=-1;
+ }
+ }
+
+
+ if (!begin_poly || !end_poly) {
+
+ //print_line("No Path Path");
+ return Vector<Vector3>(); //no path
+ }
+
+
+ if (begin_poly==end_poly) {
+
+ Vector<Vector3> path;
+ path.resize(2);
+ path[0]=begin_point;
+ path[1]=end_point;
+ //print_line("Direct Path");
+ return path;
+ }
+
+
+ bool found_route=false;
+
+ List<Polygon*> open_list;
+
+ for(int i=0;i<begin_poly->edges.size();i++) {
+
+ if (begin_poly->edges[i].C) {
+
+ begin_poly->edges[i].C->prev_edge=begin_poly->edges[i].C_edge;
+ begin_poly->edges[i].C->distance=begin_poly->center.distance_to(begin_poly->edges[i].C->center);
+ open_list.push_back(begin_poly->edges[i].C);
+
+ if (begin_poly->edges[i].C==end_poly) {
+ found_route=true;
+ }
+ }
+ }
+
+
+ while(!found_route) {
+
+ if (open_list.size()==0) {
+ // print_line("NOU OPEN LIST");
+ break;
+ }
+ //check open list
+
+ List<Polygon*>::Element *least_cost_poly=NULL;
+ float least_cost=1e30;
+
+ //this could be faster (cache previous results)
+ for (List<Polygon*>::Element *E=open_list.front();E;E=E->next()) {
+
+ Polygon *p=E->get();
+
+
+ float cost=p->distance;
+ cost+=p->center.distance_to(end_point);
+
+ if (cost<least_cost) {
+
+ least_cost_poly=E;
+ least_cost=cost;
+ }
+ }
+
+
+ Polygon *p=least_cost_poly->get();
+ //open the neighbours for search
+
+ for(int i=0;i<p->edges.size();i++) {
+
+
+ Polygon::Edge &e=p->edges[i];
+
+ if (!e.C)
+ continue;
+
+ float distance = p->center.distance_to(e.C->center) + p->distance;
+
+ if (e.C->prev_edge!=-1) {
+ //oh this was visited already, can we win the cost?
+
+ if (e.C->distance>distance) {
+
+ e.C->prev_edge=e.C_edge;
+ e.C->distance=distance;
+ }
+ } else {
+ //add to open neighbours
+
+ e.C->prev_edge=e.C_edge;
+ e.C->distance=distance;
+ open_list.push_back(e.C);
+
+ if (e.C==end_poly) {
+ //oh my reached end! stop algorithm
+ found_route=true;
+ break;
+
+ }
+
+ }
+ }
+
+ if (found_route)
+ break;
+
+ open_list.erase(least_cost_poly);
+ }
+
+ if (found_route) {
+
+ Vector<Vector3> path;
+
+ if (p_optimize) {
+ //string pulling
+
+ Polygon *apex_poly=end_poly;
+ Vector3 apex_point=end_point;
+ Vector3 portal_left=apex_point;
+ Vector3 portal_right=apex_point;
+ Polygon *left_poly=end_poly;
+ Polygon *right_poly=end_poly;
+ Polygon *p=end_poly;
+ path.push_back(end_point);
+
+ while(p) {
+
+ Vector3 left;
+ Vector3 right;
+
+#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) )
+
+ if (p==begin_poly) {
+ left=begin_point;
+ right=begin_point;
+ } else {
+ int prev = p->prev_edge;
+ int prev_n = (p->prev_edge+1)%p->edges.size();
+ left = _get_vertex(p->edges[prev].point);
+ right = _get_vertex(p->edges[prev_n].point);
+
+ //if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5).dot(up) < 0){
+ if (p->clockwise) {
+ SWAP(left,right);
+ }
+ }
+
+ bool skip=false;
+
+
+ if (CLOCK_TANGENT(apex_point,portal_left,left).dot(up) >= 0){
+ //process
+ if (portal_left==apex_point || CLOCK_TANGENT(apex_point,left,portal_right).dot(up) > 0) {
+ left_poly=p;
+ portal_left=left;
+ } else {
+
+ _clip_path(path,apex_poly,portal_right,right_poly);
+
+ apex_point=portal_right;
+ p=right_poly;
+ left_poly=p;
+ apex_poly=p;
+ portal_left=apex_point;
+ portal_right=apex_point;
+ path.push_back(apex_point);
+ skip=true;
+ }
+ }
+
+ if (!skip && CLOCK_TANGENT(apex_point,portal_right,right).dot(up) <= 0){
+ //process
+ if (portal_right==apex_point || CLOCK_TANGENT(apex_point,right,portal_left).dot(up) < 0) {
+ right_poly=p;
+ portal_right=right;
+ } else {
+
+ _clip_path(path,apex_poly,portal_left,left_poly);
+
+ apex_point=portal_left;
+ p=left_poly;
+ right_poly=p;
+ apex_poly=p;
+ portal_right=apex_point;
+ portal_left=apex_point;
+ path.push_back(apex_point);
+ }
+ }
+
+ if (p!=begin_poly)
+ p=p->edges[p->prev_edge].C;
+ else
+ p=NULL;
+
+ }
+
+ if (path[path.size()-1]!=begin_point)
+ path.push_back(begin_point);
+
+ path.invert();
+
+
+
+
+ } else {
+ //midpoints
+ Polygon *p=end_poly;
+
+ path.push_back(end_point);
+ while(true) {
+ int prev = p->prev_edge;
+ int prev_n = (p->prev_edge+1)%p->edges.size();
+ Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5;
+ path.push_back(point);
+ p = p->edges[prev].C;
+ if (p==begin_poly)
+ break;
+ }
+
+ path.push_back(begin_point);
+
+
+ path.invert();;
+ }
+
+ return path;
+ }
+
+
+ return Vector<Vector3>();
+
+}
+
+Vector3 Navigation::get_closest_point_to_segment(const Vector3& p_from,const Vector3& p_to,const bool& p_use_collision) {
+
+
+ bool use_collision=p_use_collision;
+ Vector3 closest_point;
+ float closest_point_d=1e20;
+ NavMesh *closest_navmesh=NULL;
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 inters;
+ if (f.intersects_segment(p_from,p_to,&inters)) {
+
+ if (!use_collision) {
+ closest_point=inters;
+ use_collision=true;
+ closest_point_d=p_from.distance_to(inters);
+ closest_navmesh=p.owner;
+ } else if (closest_point_d > inters.distance_to(p_from)){
+
+ closest_point=inters;
+ closest_point_d=p_from.distance_to(inters);
+ closest_navmesh=p.owner;
+ }
+ }
+ }
+
+ if (!use_collision) {
+
+ for(int i=0;i<p.edges.size();i++) {
+
+ Vector3 a,b;
+
+ Geometry::get_closest_points_between_segments(p_from,p_to,_get_vertex(p.edges[i].point),_get_vertex(p.edges[(i+1)%p.edges.size()].point),a,b);
+
+ float d = a.distance_to(b);
+ if (d<closest_point_d) {
+
+ closest_point_d=d;
+ closest_point=b;
+ closest_navmesh=p.owner;
+ }
+
+ }
+ }
+ }
+ }
+
+ if (closest_navmesh && closest_navmesh->owner) {
+ //print_line("navmesh is: "+closest_navmesh->owner->cast_to<Node>()->get_name());
+ }
+
+ return closest_point;
+}
+
+Vector3 Navigation::get_closest_point(const Vector3& p_point) {
+
+ Vector3 closest_point;
+ float closest_point_d=1e20;
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 inters = f.get_closest_point_to(p_point);
+ float d = inters.distance_to(p_point);
+ if (d<closest_point_d) {
+ closest_point=inters;
+ closest_point_d=d;
+ }
+ }
+ }
+ }
+
+ return closest_point;
+
+}
+
+Vector3 Navigation::get_closest_point_normal(const Vector3& p_point){
+
+ Vector3 closest_point;
+ Vector3 closest_normal;
+ float closest_point_d=1e20;
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 inters = f.get_closest_point_to(p_point);
+ float d = inters.distance_to(p_point);
+ if (d<closest_point_d) {
+ closest_point=inters;
+ closest_point_d=d;
+ closest_normal=f.get_plane().normal;
+ }
+ }
+ }
+ }
+
+ return closest_normal;
+
+}
+
+
+Object* Navigation::get_closest_point_owner(const Vector3& p_point){
+
+ Vector3 closest_point;
+ Object *owner=NULL;
+ float closest_point_d=1e20;
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 inters = f.get_closest_point_to(p_point);
+ float d = inters.distance_to(p_point);
+ if (d<closest_point_d) {
+ closest_point=inters;
+ closest_point_d=d;
+ owner=E->get().owner;
+ }
+ }
+ }
+ }
+
+ return owner;
+
+}
+
+void Navigation::set_up_vector(const Vector3& p_up) {
+
+
+ up=p_up;
+}
+
+Vector3 Navigation::get_up_vector() const{
+
+ return up;
+}
+
+
+void Navigation::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("navmesh_create","mesh:NavigationMesh","xform","owner"),&Navigation::navmesh_create,DEFVAL(Variant()));
+ ObjectTypeDB::bind_method(_MD("navmesh_set_transform","id","xform"),&Navigation::navmesh_set_transform);
+ ObjectTypeDB::bind_method(_MD("navmesh_remove","id"),&Navigation::navmesh_remove);
+
+ ObjectTypeDB::bind_method(_MD("get_simple_path","start","end","optimize"),&Navigation::get_simple_path,DEFVAL(true));
+ ObjectTypeDB::bind_method(_MD("get_closest_point_to_segment","start","end","use_collision"),&Navigation::get_closest_point_to_segment,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("get_closest_point","to_point"),&Navigation::get_closest_point);
+ ObjectTypeDB::bind_method(_MD("get_closest_point_normal","to_point"),&Navigation::get_closest_point_normal);
+ ObjectTypeDB::bind_method(_MD("get_closest_point_owner","to_point"),&Navigation::get_closest_point_owner);
+
+ ObjectTypeDB::bind_method(_MD("set_up_vector","up"),&Navigation::set_up_vector);
+ ObjectTypeDB::bind_method(_MD("get_up_vector"),&Navigation::get_up_vector);
+
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"up_vector"),_SCS("set_up_vector"),_SCS("get_up_vector"));
+}
+
+Navigation::Navigation() {
+
+ ERR_FAIL_COND( sizeof(Point)!=8 );
+ cell_size=0.01; //one centimeter
+ last_id=1;
+ up=Vector3(0,1,0);
+}
+
+
diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h
new file mode 100644
index 0000000000..f8434aaf72
--- /dev/null
+++ b/scene/3d/navigation.h
@@ -0,0 +1,159 @@
+#ifndef NAVIGATION_H
+#define NAVIGATION_H
+
+#include "scene/3d/spatial.h"
+#include "scene/3d/navigation_mesh.h"
+
+class Navigation : public Spatial {
+
+ OBJ_TYPE( Navigation, Spatial);
+
+
+ union Point {
+
+ struct {
+ int64_t x:21;
+ int64_t y:22;
+ int64_t z:21;
+ };
+
+ uint64_t key;
+ bool operator<(const Point& p_key) const { return key < p_key.key; }
+ };
+
+
+ struct EdgeKey {
+
+ Point a;
+ Point b;
+
+ bool operator<(const EdgeKey& p_key) const {
+ return (a.key==p_key.a.key)?(b.key<p_key.b.key):(a.key<p_key.a.key);
+ };
+
+ EdgeKey(const Point& p_a=Point(),const Point& p_b=Point()) {
+ a=p_a;
+ b=p_b;
+ if (a.key > b.key) {
+ SWAP(a,b);
+ }
+ }
+ };
+
+
+ struct NavMesh;
+ struct Polygon;
+
+ struct ConnectionPending {
+
+ Polygon *polygon;
+ int edge;
+ };
+
+
+ struct Polygon {
+
+ struct Edge {
+ Point point;
+ Polygon *C; //connection
+ int C_edge;
+ List<ConnectionPending>::Element *P;
+ Edge() { C=NULL; C_edge=-1; P=NULL; }
+ };
+
+ Vector<Edge> edges;
+
+ Vector3 center;
+
+ float distance;
+ int prev_edge;
+ bool clockwise;
+
+
+ NavMesh *owner;
+ };
+
+
+ struct Connection {
+
+ Polygon *A;
+ int A_edge;
+ Polygon *B;
+ int B_edge;
+
+ List<ConnectionPending> pending;
+
+ Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;}
+ };
+
+ Map<EdgeKey,Connection> connections;
+
+
+ struct NavMesh {
+
+ Object *owner;
+ Transform xform;
+ bool linked;
+ Ref<NavigationMesh> navmesh;
+ List<Polygon> polygons;
+
+ };
+
+
+
+ _FORCE_INLINE_ Point _get_point(const Vector3& p_pos) const {
+
+ int x = int(Math::floor(p_pos.x/cell_size));
+ int y = int(Math::floor(p_pos.y/cell_size));
+ int z = int(Math::floor(p_pos.z/cell_size));
+
+ Point p;
+ p.key=0;
+ p.x=x;
+ p.y=y;
+ p.z=z;
+ return p;
+
+ }
+
+ _FORCE_INLINE_ Vector3 _get_vertex(const Point& p_point) const {
+
+ return Vector3(p_point.x,p_point.y,p_point.z)*cell_size;
+ }
+
+
+
+ void _navmesh_link(int p_id);
+ void _navmesh_unlink(int p_id);
+
+ float cell_size;
+ Map<int,NavMesh> navmesh_map;
+ int last_id;
+
+ Vector3 up;
+ void _clip_path(Vector<Vector3>& path,Polygon *from_poly, const Vector3& p_to_point, Polygon* p_to_poly);
+
+protected:
+
+ static void _bind_methods();
+
+public:
+
+ void set_up_vector(const Vector3& p_up);
+ Vector3 get_up_vector() const;
+
+ //API should be as dynamic as possible
+ int navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform,Object* p_owner=NULL);
+ void navmesh_set_transform(int p_id, const Transform& p_xform);
+ void navmesh_remove(int p_id);
+
+ Vector<Vector3> get_simple_path(const Vector3& p_start, const Vector3& p_end,bool p_optimize=true);
+ Vector3 get_closest_point_to_segment(const Vector3& p_from,const Vector3& p_to,const bool& p_use_collision=false);
+ Vector3 get_closest_point(const Vector3& p_point);
+ Vector3 get_closest_point_normal(const Vector3& p_point);
+ Object* get_closest_point_owner(const Vector3& p_point);
+
+ Navigation();
+};
+
+#endif // NAVIGATION_H
diff --git a/scene/3d/navigation_agent.cpp b/scene/3d/navigation_agent.cpp
new file mode 100644
index 0000000000..9b304e45ec
--- /dev/null
+++ b/scene/3d/navigation_agent.cpp
@@ -0,0 +1,5 @@
+#include "navigation_agent.h"
+
+NavigationAgent::NavigationAgent()
+{
+}
diff --git a/scene/3d/navigation_agent.h b/scene/3d/navigation_agent.h
new file mode 100644
index 0000000000..baceb693a5
--- /dev/null
+++ b/scene/3d/navigation_agent.h
@@ -0,0 +1,10 @@
+#ifndef NAVIGATION_AGENT_H
+#define NAVIGATION_AGENT_H
+
+class NavigationAgent
+{
+public:
+ NavigationAgent();
+};
+
+#endif // NAVIGATION_AGENT_H
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
new file mode 100644
index 0000000000..a238a8ff22
--- /dev/null
+++ b/scene/3d/navigation_mesh.cpp
@@ -0,0 +1,359 @@
+#include "navigation_mesh.h"
+#include "navigation.h"
+#include "mesh_instance.h"
+
+void NavigationMesh::create_from_mesh(const Ref<Mesh>& p_mesh) {
+
+
+ vertices=DVector<Vector3>();
+ clear_polygons();
+
+ for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+ if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+ continue;
+ Array arr = p_mesh->surface_get_arrays(i);
+ DVector<Vector3> varr = arr[Mesh::ARRAY_VERTEX];
+ DVector<int> iarr = arr[Mesh::ARRAY_INDEX];
+ if (varr.size()==0 || iarr.size()==0)
+ continue;
+
+ int from = vertices.size();
+ vertices.append_array(varr);
+ int rlen = iarr.size();
+ DVector<int>::Read r = iarr.read();
+
+ for(int j=0;j<rlen;j+=3) {
+ Vector<int> vi;
+ vi.resize(3);
+ vi[0]=r[j+0]+from;
+ vi[1]=r[j+1]+from;
+ vi[2]=r[j+2]+from;
+
+ add_polygon(vi);
+ }
+ }
+}
+
+void NavigationMesh::set_vertices(const DVector<Vector3>& p_vertices) {
+
+ vertices=p_vertices;
+}
+
+DVector<Vector3> NavigationMesh::get_vertices() const{
+
+ return vertices;
+}
+
+
+void NavigationMesh::_set_polygons(const Array& p_array) {
+
+ polygons.resize(p_array.size());
+ for(int i=0;i<p_array.size();i++) {
+ polygons[i].indices=p_array[i];
+ }
+}
+
+Array NavigationMesh::_get_polygons() const {
+
+ Array ret;
+ ret.resize(polygons.size());
+ for(int i=0;i<ret.size();i++) {
+ ret[i]=polygons[i].indices;
+ }
+
+ return ret;
+}
+
+
+void NavigationMesh::add_polygon(const Vector<int>& p_polygon){
+
+ Polygon polygon;
+ polygon.indices=p_polygon;
+ polygons.push_back(polygon);
+
+}
+int NavigationMesh::get_polygon_count() const{
+
+ return polygons.size();
+}
+Vector<int> NavigationMesh::get_polygon(int p_idx){
+
+ ERR_FAIL_INDEX_V(p_idx,polygons.size(),Vector<int>());
+ return polygons[p_idx].indices;
+}
+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);
+ ObjectTypeDB::bind_method(_MD("get_vertices"),&NavigationMesh::get_vertices);
+
+ ObjectTypeDB::bind_method(_MD("add_polygon","polygon"),&NavigationMesh::add_polygon);
+ ObjectTypeDB::bind_method(_MD("get_polygon_count"),&NavigationMesh::get_polygon_count);
+ ObjectTypeDB::bind_method(_MD("get_polygon","idx"),&NavigationMesh::get_polygon);
+ ObjectTypeDB::bind_method(_MD("clear_polygons"),&NavigationMesh::clear_polygons);
+
+ ObjectTypeDB::bind_method(_MD("_set_polygons","polygons"),&NavigationMesh::_set_polygons);
+ ObjectTypeDB::bind_method(_MD("_get_polygons"),&NavigationMesh::_get_polygons);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3_ARRAY,"vertices",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_vertices"),_SCS("get_vertices"));
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"polygons",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_polygons"),_SCS("_get_polygons"));
+}
+
+NavigationMesh::NavigationMesh() {
+
+}
+
+void NavigationMeshInstance::set_enabled(bool p_enabled) {
+
+ if (enabled==p_enabled)
+ return;
+ enabled=p_enabled;
+
+ if (!is_inside_tree())
+ return;
+
+ if (!enabled) {
+
+ if (nav_id!=-1) {
+ navigation->navmesh_remove(nav_id);
+ nav_id=-1;
+ }
+ } else {
+
+ if (navigation) {
+
+ if (navmesh.is_valid()) {
+
+ nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation),this);
+ }
+ }
+
+ }
+
+ 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();
+}
+
+bool NavigationMeshInstance::is_enabled() const {
+
+
+ return enabled;
+}
+
+
+/////////////////////////////
+
+
+void NavigationMeshInstance::_notification(int p_what) {
+
+
+ switch(p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+
+ Spatial *c=this;
+ while(c) {
+
+ navigation=c->cast_to<Navigation>();
+ if (navigation) {
+
+ if (enabled && navmesh.is_valid()) {
+
+ nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation),this);
+ }
+ break;
+ }
+
+ 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: {
+
+ if (navigation && nav_id!=-1) {
+ navigation->navmesh_set_transform(nav_id,get_relative_transform(navigation));
+ }
+
+
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ if (navigation) {
+
+ if (nav_id!=-1) {
+ navigation->navmesh_remove(nav_id);
+ nav_id=-1;
+ }
+ }
+
+ if (debug_view) {
+ debug_view->queue_delete();
+ debug_view=NULL;
+ }
+ navigation=NULL;
+ } break;
+ }
+}
+
+
+void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh>& p_navmesh) {
+
+ if (p_navmesh==navmesh)
+ return;
+
+ if (navigation && nav_id!=-1) {
+ navigation->navmesh_remove(nav_id);
+ nav_id=-1;
+ }
+ navmesh=p_navmesh;
+
+ if (navigation && navmesh.is_valid() && enabled) {
+ nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation),this);
+ }
+ update_gizmo();
+
+}
+
+Ref<NavigationMesh> NavigationMeshInstance::get_navigation_mesh() const{
+
+ return navmesh;
+}
+
+void NavigationMeshInstance::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_navigation_mesh","navmesh"),&NavigationMeshInstance::set_navigation_mesh);
+ ObjectTypeDB::bind_method(_MD("get_navigation_mesh"),&NavigationMeshInstance::get_navigation_mesh);
+
+ ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&NavigationMeshInstance::set_enabled);
+ ObjectTypeDB::bind_method(_MD("is_enabled"),&NavigationMeshInstance::is_enabled);
+
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"navmesh",PROPERTY_HINT_RESOURCE_TYPE,"NavigationMesh"),_SCS("set_navigation_mesh"),_SCS("get_navigation_mesh"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
+}
+
+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
new file mode 100644
index 0000000000..1e53b2127a
--- /dev/null
+++ b/scene/3d/navigation_mesh.h
@@ -0,0 +1,85 @@
+#ifndef NAVIGATION_MESH_H
+#define NAVIGATION_MESH_H
+
+#include "scene/3d/spatial.h"
+#include "scene/resources/mesh.h"
+
+class Mesh;
+
+class NavigationMesh : public Resource {
+
+ OBJ_TYPE( NavigationMesh, Resource );
+
+ DVector<Vector3> vertices;
+ struct Polygon {
+ 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:
+
+ static void _bind_methods();
+
+ void _set_polygons(const Array& p_array);
+ Array _get_polygons() const;
+
+public:
+
+ void create_from_mesh(const Ref<Mesh>& p_mesh);
+
+ void set_vertices(const DVector<Vector3>& p_vertices);
+ DVector<Vector3> get_vertices() const;
+
+ void add_polygon(const Vector<int>& p_polygon);
+ int get_polygon_count() const;
+ Vector<int> get_polygon(int p_idx);
+ void clear_polygons();
+
+ Ref<Mesh> get_debug_mesh();
+
+ NavigationMesh();
+};
+
+
+class Navigation;
+
+class NavigationMeshInstance : public Spatial {
+
+ OBJ_TYPE(NavigationMeshInstance,Spatial);
+
+ bool enabled;
+ int nav_id;
+ Navigation *navigation;
+ Ref<NavigationMesh> navmesh;
+
+ Node *debug_view;
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+
+
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
+ void set_navigation_mesh(const Ref<NavigationMesh>& p_navmesh);
+ Ref<NavigationMesh> get_navigation_mesh() const;
+
+ NavigationMeshInstance();
+};
+
+
+#endif // NAVIGATION_MESH_H
diff --git a/scene/3d/optimized_spatial_scene.cpp b/scene/3d/optimized_spatial_scene.cpp
index 12c847f71c..85c1b79a9a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/optimized_spatial_scene.h b/scene/3d/optimized_spatial_scene.h
index 36ae1ec213..a55b5235da 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index b47f1644e3..6868646c48 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/particles.h b/scene/3d/particles.h
index 40d569d7b4..260573fe5f 100644
--- a/scene/3d/particles.h
+++ b/scene/3d/particles.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index bc5cb1c4a2..9cd41b25f6 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,363 +26,363 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "path.h"
-#include "scene/scene_string_names.h"
-
-void Path::_notification(int p_what) {
-#if 0
- if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_scene() && get_scene()->is_editor_hint()) {
- //draw the curve!!
-
- for(int i=0;i<curve->get_point_count();i++) {
-
- Vector2 prev_p=curve->get_point_pos(i);
-
- for(int j=1;j<=8;j++) {
-
- real_t frac = j/8.0;
- Vector2 p = curve->interpolate(i,frac);
- draw_line(prev_p,p,Color(0.5,0.6,1.0,0.7),2);
- prev_p=p;
- }
- }
- }
-#endif
-}
-
-void Path::_curve_changed() {
-
-
- if (is_inside_scene() && get_scene()->is_editor_hint())
- update_gizmo();
-}
-
-
-void Path::set_curve(const Ref<Curve3D>& p_curve) {
-
- if (curve.is_valid()) {
- curve->disconnect("changed",this,"_curve_changed");
- }
-
- curve=p_curve;
-
- if (curve.is_valid()) {
- curve->connect("changed",this,"_curve_changed");
- }
- _curve_changed();
-
-}
-
-Ref<Curve3D> Path::get_curve() const{
-
- return curve;
-}
-
-void Path::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_curve","curve:Curve3D"),&Path::set_curve);
- ObjectTypeDB::bind_method(_MD("get_curve:Curve3D","curve"),&Path::get_curve);
- ObjectTypeDB::bind_method(_MD("_curve_changed"),&Path::_curve_changed);
-
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), _SCS("set_curve"),_SCS("get_curve"));
-}
-
-Path::Path() {
-
- set_curve(Ref<Curve3D>( memnew( Curve3D ))); //create one by default
-}
-
-
-//////////////
-
-
-void PathFollow::_update_transform() {
-
-
- if (!path)
- return;
-
- Ref<Curve3D> c =path->get_curve();
- if (!c.is_valid())
- return;
-
-
- float o = offset;
- if (loop)
- o=Math::fposmod(o,c->get_baked_length());
-
- Vector3 pos = c->interpolate_baked(o,cubic);
- Transform t=get_transform();
-
-
- if (rotation_mode!=ROTATION_NONE) {
-
- Vector3 n = (c->interpolate_baked(o+lookahead,cubic)-pos).normalized();
-
- if (rotation_mode==ROTATION_Y) {
-
- n.y=0;
- n.normalize();
- }
-
- if (n.length()<CMP_EPSILON) {//nothing, use previous
- n=-t.get_basis().get_axis(2).normalized();
- }
-
-
- Vector3 up = Vector3(0,1,0);
-
- if (rotation_mode==ROTATION_XYZ) {
-
- float tilt = c->interpolate_baked_tilt(o);
- if (tilt!=0) {
-
- Matrix3 rot(-n,tilt); //remember.. lookat will be znegative.. znegative!! we abide by opengl clan.
- up=rot.xform(up);
- }
- }
-
- t.set_look_at(pos,pos+n,up);
-
- } else {
-
- t.origin=pos;
- }
-
- t.origin+=t.basis.get_axis(0)*h_offset + t.basis.get_axis(1)*v_offset;
- set_transform(t);
-
-}
-
-void PathFollow::_notification(int p_what) {
-
-
- switch(p_what) {
-
- case NOTIFICATION_ENTER_SCENE: {
-
- Node *parent=get_parent();
- if (parent) {
-
- path=parent->cast_to<Path>();
- if (path) {
- _update_transform();
- }
- }
-
- } break;
- case NOTIFICATION_EXIT_SCENE: {
-
-
- path=NULL;
- } break;
- }
-
-}
-
-void PathFollow::set_cubic_interpolation(bool p_enable) {
-
- cubic=p_enable;
-}
-
-bool PathFollow::get_cubic_interpolation() const {
-
- return cubic;
-}
-
-
-bool PathFollow::_set(const StringName& p_name, const Variant& p_value) {
-
- if (p_name==SceneStringNames::get_singleton()->offset) {
- set_offset(p_value);
- } else if (p_name==SceneStringNames::get_singleton()->unit_offset) {
- set_unit_offset(p_value);
- } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) {
- set_rotation_mode(RotationMode(p_value.operator int()));
- } else if (p_name==SceneStringNames::get_singleton()->v_offset) {
- set_v_offset(p_value);
- } else if (p_name==SceneStringNames::get_singleton()->h_offset) {
- set_h_offset(p_value);
- } else if (String(p_name)=="cubic_interp") {
- set_cubic_interpolation(p_value);
- } else if (String(p_name)=="loop") {
- set_loop(p_value);
- } else if (String(p_name)=="lookahead") {
- set_lookahead(p_value);
- } else
- return false;
-
- return true;
-}
-
-bool PathFollow::_get(const StringName& p_name,Variant &r_ret) const{
-
- if (p_name==SceneStringNames::get_singleton()->offset) {
- r_ret=get_offset();
- } else if (p_name==SceneStringNames::get_singleton()->unit_offset) {
- r_ret=get_unit_offset();
- } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) {
- r_ret=get_rotation_mode();
- } else if (p_name==SceneStringNames::get_singleton()->v_offset) {
- r_ret=get_v_offset();
- } else if (p_name==SceneStringNames::get_singleton()->h_offset) {
- r_ret=get_h_offset();
- } else if (String(p_name)=="cubic_interp") {
- r_ret=cubic;
- } else if (String(p_name)=="loop") {
- r_ret=loop;
- } else if (String(p_name)=="lookahead") {
- r_ret=lookahead;
- } else
- return false;
-
- return true;
-
-}
-void PathFollow::_get_property_list( List<PropertyInfo> *p_list) const{
-
- float max=10000;
- if (path && path->get_curve().is_valid())
- max=path->get_curve()->get_baked_length();
- p_list->push_back( PropertyInfo( Variant::REAL, "offset", PROPERTY_HINT_RANGE,"0,"+rtos(max)+",0.01"));
- p_list->push_back( PropertyInfo( Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE,"0,1,0.0001",PROPERTY_USAGE_EDITOR));
- p_list->push_back( PropertyInfo( Variant::REAL, "h_offset") );
- p_list->push_back( PropertyInfo( Variant::REAL, "v_offset") );
- p_list->push_back( PropertyInfo( Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM,"None,Y,XY,XYZ"));
- p_list->push_back( PropertyInfo( Variant::BOOL, "cubic_interp"));
- p_list->push_back( PropertyInfo( Variant::BOOL, "loop"));
- p_list->push_back( PropertyInfo( Variant::REAL, "lookahead",PROPERTY_HINT_RANGE,"0.001,1024.0,0.001"));
-}
-
-
-void PathFollow::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_offset","offset"),&PathFollow::set_offset);
- ObjectTypeDB::bind_method(_MD("get_offset"),&PathFollow::get_offset);
-
- ObjectTypeDB::bind_method(_MD("set_h_offset","h_offset"),&PathFollow::set_h_offset);
- ObjectTypeDB::bind_method(_MD("get_h_offset"),&PathFollow::get_h_offset);
-
- ObjectTypeDB::bind_method(_MD("set_v_offset","v_offset"),&PathFollow::set_v_offset);
- ObjectTypeDB::bind_method(_MD("get_v_offset"),&PathFollow::get_v_offset);
-
- ObjectTypeDB::bind_method(_MD("set_unit_offset","unit_offset"),&PathFollow::set_unit_offset);
- ObjectTypeDB::bind_method(_MD("get_unit_offset"),&PathFollow::get_unit_offset);
-
- ObjectTypeDB::bind_method(_MD("set_rotation_mode","rotation_mode"),&PathFollow::set_rotation_mode);
- ObjectTypeDB::bind_method(_MD("get_rotation_mode"),&PathFollow::get_rotation_mode);
-
- ObjectTypeDB::bind_method(_MD("set_cubic_interpolation","enable"),&PathFollow::set_cubic_interpolation);
- ObjectTypeDB::bind_method(_MD("get_cubic_interpolation"),&PathFollow::get_cubic_interpolation);
-
- ObjectTypeDB::bind_method(_MD("set_loop","loop"),&PathFollow::set_loop);
- ObjectTypeDB::bind_method(_MD("has_loop"),&PathFollow::has_loop);
-
- BIND_CONSTANT( ROTATION_NONE );
- BIND_CONSTANT( ROTATION_Y );
- BIND_CONSTANT( ROTATION_XY );
- BIND_CONSTANT( ROTATION_XYZ );
-
-}
-
-void PathFollow::set_offset(float p_offset) {
-
- offset=p_offset;
- if (path)
- _update_transform();
- _change_notify("offset");
- _change_notify("unit_offset");
-
-}
-
-void PathFollow::set_h_offset(float p_h_offset) {
-
- h_offset=p_h_offset;
- if (path)
- _update_transform();
-
-}
-
-float PathFollow::get_h_offset() const {
-
- return h_offset;
-}
-
-void PathFollow::set_v_offset(float p_v_offset) {
-
- v_offset=p_v_offset;
- if (path)
- _update_transform();
-
-}
-
-float PathFollow::get_v_offset() const {
-
- return v_offset;
-}
-
-
-float PathFollow::get_offset() const{
-
- return offset;
-}
-
-void PathFollow::set_unit_offset(float p_unit_offset) {
-
- if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
- set_offset(p_unit_offset*path->get_curve()->get_baked_length());
-
-}
-
-float PathFollow::get_unit_offset() const{
-
- if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
- return get_offset()/path->get_curve()->get_baked_length();
- else
- return 0;
-}
-
-void PathFollow::set_lookahead(float p_lookahead) {
-
- lookahead=p_lookahead;
-
-}
-
-float PathFollow::get_lookahead() const{
-
- return lookahead;
-}
-
-void PathFollow::set_rotation_mode(RotationMode p_rotation_mode) {
-
- rotation_mode=p_rotation_mode;
- _update_transform();
-}
-
-PathFollow::RotationMode PathFollow::get_rotation_mode() const {
-
- return rotation_mode;
-}
-
-void PathFollow::set_loop(bool p_loop) {
-
- loop=p_loop;
-}
-
-bool PathFollow::has_loop() const{
-
- return loop;
-}
-
-
-PathFollow::PathFollow() {
-
- offset=0;
- h_offset=0;
- v_offset=0;
- path=NULL;
- rotation_mode=ROTATION_XYZ;
- cubic=true;
- loop=true;
- lookahead=0.1;
-}
+#include "path.h"
+#include "scene/scene_string_names.h"
+
+void Path::_notification(int p_what) {
+#if 0
+ if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_scene() && get_scene()->is_editor_hint()) {
+ //draw the curve!!
+
+ for(int i=0;i<curve->get_point_count();i++) {
+
+ Vector2 prev_p=curve->get_point_pos(i);
+
+ for(int j=1;j<=8;j++) {
+
+ real_t frac = j/8.0;
+ Vector2 p = curve->interpolate(i,frac);
+ draw_line(prev_p,p,Color(0.5,0.6,1.0,0.7),2);
+ prev_p=p;
+ }
+ }
+ }
+#endif
+}
+
+void Path::_curve_changed() {
+
+
+ if (is_inside_tree() && get_tree()->is_editor_hint())
+ update_gizmo();
+}
+
+
+void Path::set_curve(const Ref<Curve3D>& p_curve) {
+
+ if (curve.is_valid()) {
+ curve->disconnect("changed",this,"_curve_changed");
+ }
+
+ curve=p_curve;
+
+ if (curve.is_valid()) {
+ curve->connect("changed",this,"_curve_changed");
+ }
+ _curve_changed();
+
+}
+
+Ref<Curve3D> Path::get_curve() const{
+
+ return curve;
+}
+
+void Path::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_curve","curve:Curve3D"),&Path::set_curve);
+ ObjectTypeDB::bind_method(_MD("get_curve:Curve3D","curve"),&Path::get_curve);
+ ObjectTypeDB::bind_method(_MD("_curve_changed"),&Path::_curve_changed);
+
+ ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), _SCS("set_curve"),_SCS("get_curve"));
+}
+
+Path::Path() {
+
+ set_curve(Ref<Curve3D>( memnew( Curve3D ))); //create one by default
+}
+
+
+//////////////
+
+
+void PathFollow::_update_transform() {
+
+
+ if (!path)
+ return;
+
+ Ref<Curve3D> c =path->get_curve();
+ if (!c.is_valid())
+ return;
+
+
+ float o = offset;
+ if (loop)
+ o=Math::fposmod(o,c->get_baked_length());
+
+ Vector3 pos = c->interpolate_baked(o,cubic);
+ Transform t=get_transform();
+
+
+ if (rotation_mode!=ROTATION_NONE) {
+
+ Vector3 n = (c->interpolate_baked(o+lookahead,cubic)-pos).normalized();
+
+ if (rotation_mode==ROTATION_Y) {
+
+ n.y=0;
+ n.normalize();
+ }
+
+ if (n.length()<CMP_EPSILON) {//nothing, use previous
+ n=-t.get_basis().get_axis(2).normalized();
+ }
+
+
+ Vector3 up = Vector3(0,1,0);
+
+ if (rotation_mode==ROTATION_XYZ) {
+
+ float tilt = c->interpolate_baked_tilt(o);
+ if (tilt!=0) {
+
+ Matrix3 rot(-n,tilt); //remember.. lookat will be znegative.. znegative!! we abide by opengl clan.
+ up=rot.xform(up);
+ }
+ }
+
+ t.set_look_at(pos,pos+n,up);
+
+ } else {
+
+ t.origin=pos;
+ }
+
+ t.origin+=t.basis.get_axis(0)*h_offset + t.basis.get_axis(1)*v_offset;
+ set_transform(t);
+
+}
+
+void PathFollow::_notification(int p_what) {
+
+
+ switch(p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ Node *parent=get_parent();
+ if (parent) {
+
+ path=parent->cast_to<Path>();
+ if (path) {
+ _update_transform();
+ }
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+
+ path=NULL;
+ } break;
+ }
+
+}
+
+void PathFollow::set_cubic_interpolation(bool p_enable) {
+
+ cubic=p_enable;
+}
+
+bool PathFollow::get_cubic_interpolation() const {
+
+ return cubic;
+}
+
+
+bool PathFollow::_set(const StringName& p_name, const Variant& p_value) {
+
+ if (p_name==SceneStringNames::get_singleton()->offset) {
+ set_offset(p_value);
+ } else if (p_name==SceneStringNames::get_singleton()->unit_offset) {
+ set_unit_offset(p_value);
+ } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) {
+ set_rotation_mode(RotationMode(p_value.operator int()));
+ } else if (p_name==SceneStringNames::get_singleton()->v_offset) {
+ set_v_offset(p_value);
+ } else if (p_name==SceneStringNames::get_singleton()->h_offset) {
+ set_h_offset(p_value);
+ } else if (String(p_name)=="cubic_interp") {
+ set_cubic_interpolation(p_value);
+ } else if (String(p_name)=="loop") {
+ set_loop(p_value);
+ } else if (String(p_name)=="lookahead") {
+ set_lookahead(p_value);
+ } else
+ return false;
+
+ return true;
+}
+
+bool PathFollow::_get(const StringName& p_name,Variant &r_ret) const{
+
+ if (p_name==SceneStringNames::get_singleton()->offset) {
+ r_ret=get_offset();
+ } else if (p_name==SceneStringNames::get_singleton()->unit_offset) {
+ r_ret=get_unit_offset();
+ } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) {
+ r_ret=get_rotation_mode();
+ } else if (p_name==SceneStringNames::get_singleton()->v_offset) {
+ r_ret=get_v_offset();
+ } else if (p_name==SceneStringNames::get_singleton()->h_offset) {
+ r_ret=get_h_offset();
+ } else if (String(p_name)=="cubic_interp") {
+ r_ret=cubic;
+ } else if (String(p_name)=="loop") {
+ r_ret=loop;
+ } else if (String(p_name)=="lookahead") {
+ r_ret=lookahead;
+ } else
+ return false;
+
+ return true;
+
+}
+void PathFollow::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ float max=10000;
+ if (path && path->get_curve().is_valid())
+ max=path->get_curve()->get_baked_length();
+ p_list->push_back( PropertyInfo( Variant::REAL, "offset", PROPERTY_HINT_RANGE,"0,"+rtos(max)+",0.01"));
+ p_list->push_back( PropertyInfo( Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE,"0,1,0.0001",PROPERTY_USAGE_EDITOR));
+ p_list->push_back( PropertyInfo( Variant::REAL, "h_offset") );
+ p_list->push_back( PropertyInfo( Variant::REAL, "v_offset") );
+ p_list->push_back( PropertyInfo( Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM,"None,Y,XY,XYZ"));
+ p_list->push_back( PropertyInfo( Variant::BOOL, "cubic_interp"));
+ p_list->push_back( PropertyInfo( Variant::BOOL, "loop"));
+ p_list->push_back( PropertyInfo( Variant::REAL, "lookahead",PROPERTY_HINT_RANGE,"0.001,1024.0,0.001"));
+}
+
+
+void PathFollow::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_offset","offset"),&PathFollow::set_offset);
+ ObjectTypeDB::bind_method(_MD("get_offset"),&PathFollow::get_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_h_offset","h_offset"),&PathFollow::set_h_offset);
+ ObjectTypeDB::bind_method(_MD("get_h_offset"),&PathFollow::get_h_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_v_offset","v_offset"),&PathFollow::set_v_offset);
+ ObjectTypeDB::bind_method(_MD("get_v_offset"),&PathFollow::get_v_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_unit_offset","unit_offset"),&PathFollow::set_unit_offset);
+ ObjectTypeDB::bind_method(_MD("get_unit_offset"),&PathFollow::get_unit_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_rotation_mode","rotation_mode"),&PathFollow::set_rotation_mode);
+ ObjectTypeDB::bind_method(_MD("get_rotation_mode"),&PathFollow::get_rotation_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_cubic_interpolation","enable"),&PathFollow::set_cubic_interpolation);
+ ObjectTypeDB::bind_method(_MD("get_cubic_interpolation"),&PathFollow::get_cubic_interpolation);
+
+ ObjectTypeDB::bind_method(_MD("set_loop","loop"),&PathFollow::set_loop);
+ ObjectTypeDB::bind_method(_MD("has_loop"),&PathFollow::has_loop);
+
+ BIND_CONSTANT( ROTATION_NONE );
+ BIND_CONSTANT( ROTATION_Y );
+ BIND_CONSTANT( ROTATION_XY );
+ BIND_CONSTANT( ROTATION_XYZ );
+
+}
+
+void PathFollow::set_offset(float p_offset) {
+
+ offset=p_offset;
+ if (path)
+ _update_transform();
+ _change_notify("offset");
+ _change_notify("unit_offset");
+
+}
+
+void PathFollow::set_h_offset(float p_h_offset) {
+
+ h_offset=p_h_offset;
+ if (path)
+ _update_transform();
+
+}
+
+float PathFollow::get_h_offset() const {
+
+ return h_offset;
+}
+
+void PathFollow::set_v_offset(float p_v_offset) {
+
+ v_offset=p_v_offset;
+ if (path)
+ _update_transform();
+
+}
+
+float PathFollow::get_v_offset() const {
+
+ return v_offset;
+}
+
+
+float PathFollow::get_offset() const{
+
+ return offset;
+}
+
+void PathFollow::set_unit_offset(float p_unit_offset) {
+
+ if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
+ set_offset(p_unit_offset*path->get_curve()->get_baked_length());
+
+}
+
+float PathFollow::get_unit_offset() const{
+
+ if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
+ return get_offset()/path->get_curve()->get_baked_length();
+ else
+ return 0;
+}
+
+void PathFollow::set_lookahead(float p_lookahead) {
+
+ lookahead=p_lookahead;
+
+}
+
+float PathFollow::get_lookahead() const{
+
+ return lookahead;
+}
+
+void PathFollow::set_rotation_mode(RotationMode p_rotation_mode) {
+
+ rotation_mode=p_rotation_mode;
+ _update_transform();
+}
+
+PathFollow::RotationMode PathFollow::get_rotation_mode() const {
+
+ return rotation_mode;
+}
+
+void PathFollow::set_loop(bool p_loop) {
+
+ loop=p_loop;
+}
+
+bool PathFollow::has_loop() const{
+
+ return loop;
+}
+
+
+PathFollow::PathFollow() {
+
+ offset=0;
+ h_offset=0;
+ v_offset=0;
+ path=NULL;
+ rotation_mode=ROTATION_XYZ;
+ cubic=true;
+ loop=true;
+ lookahead=0.1;
+}
diff --git a/scene/3d/path.h b/scene/3d/path.h
index 6f907265ba..1b40ec413d 100644
--- a/scene/3d/path.h
+++ b/scene/3d/path.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,97 +26,97 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PATH_H
-#define PATH_H
-
-#include "scene/resources/curve.h"
-#include "scene/3d/spatial.h"
-
-class Path : public Spatial {
-
- OBJ_TYPE( Path, Spatial );
-
- Ref<Curve3D> curve;
-
- void _curve_changed();
-
-
-protected:
-
- void _notification(int p_what);
- static void _bind_methods();
-public:
-
- void set_curve(const Ref<Curve3D>& p_curve);
- Ref<Curve3D> get_curve() const;
-
-
- Path();
-};
-
-class PathFollow : public Spatial {
-
- OBJ_TYPE(PathFollow,Spatial);
-public:
-
- enum RotationMode {
-
- ROTATION_NONE,
- ROTATION_Y,
- ROTATION_XY,
- ROTATION_XYZ
- };
-
-private:
- Path *path;
- real_t offset;
- real_t h_offset;
- real_t v_offset;
- real_t lookahead;
- bool cubic;
- bool loop;
- RotationMode rotation_mode;
-
- void _update_transform();
-
-
-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;
-
- void _notification(int p_what);
- static void _bind_methods();
-public:
-
- void set_offset(float p_offset);
- float get_offset() const;
-
- void set_h_offset(float p_h_offset);
- float get_h_offset() const;
-
- void set_v_offset(float p_v_offset);
- float get_v_offset() const;
-
- void set_unit_offset(float p_unit_offset);
- float get_unit_offset() const;
-
- void set_lookahead(float p_lookahead);
- float get_lookahead() const;
-
- void set_loop(bool p_loop);
- bool has_loop() const;
-
- void set_rotation_mode(RotationMode p_rotation_mode);
- RotationMode get_rotation_mode() const;
-
- void set_cubic_interpolation(bool p_enable);
- bool get_cubic_interpolation() const;
-
- PathFollow();
-};
-
-VARIANT_ENUM_CAST(PathFollow::RotationMode);
-
-#endif // PATH_H
+#ifndef PATH_H
+#define PATH_H
+
+#include "scene/resources/curve.h"
+#include "scene/3d/spatial.h"
+
+class Path : public Spatial {
+
+ OBJ_TYPE( Path, Spatial );
+
+ Ref<Curve3D> curve;
+
+ void _curve_changed();
+
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_curve(const Ref<Curve3D>& p_curve);
+ Ref<Curve3D> get_curve() const;
+
+
+ Path();
+};
+
+class PathFollow : public Spatial {
+
+ OBJ_TYPE(PathFollow,Spatial);
+public:
+
+ enum RotationMode {
+
+ ROTATION_NONE,
+ ROTATION_Y,
+ ROTATION_XY,
+ ROTATION_XYZ
+ };
+
+private:
+ Path *path;
+ real_t offset;
+ real_t h_offset;
+ real_t v_offset;
+ real_t lookahead;
+ bool cubic;
+ bool loop;
+ RotationMode rotation_mode;
+
+ void _update_transform();
+
+
+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;
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_offset(float p_offset);
+ float get_offset() const;
+
+ void set_h_offset(float p_h_offset);
+ float get_h_offset() const;
+
+ void set_v_offset(float p_v_offset);
+ float get_v_offset() const;
+
+ void set_unit_offset(float p_unit_offset);
+ float get_unit_offset() const;
+
+ void set_lookahead(float p_lookahead);
+ float get_lookahead() const;
+
+ void set_loop(bool p_loop);
+ bool has_loop() const;
+
+ void set_rotation_mode(RotationMode p_rotation_mode);
+ RotationMode get_rotation_mode() const;
+
+ void set_cubic_interpolation(bool p_enable);
+ bool get_cubic_interpolation() const;
+
+ PathFollow();
+};
+
+VARIANT_ENUM_CAST(PathFollow::RotationMode);
+
+#endif // PATH_H
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 2a1a5972a9..de50484a1e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -43,166 +43,160 @@ void PhysicsBody::_notification(int p_what) {
*/
}
-PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject( PhysicsServer::get_singleton()->body_create(p_mode), false) {
+Vector3 PhysicsBody::get_linear_velocity() const {
+ return Vector3();
+}
+Vector3 PhysicsBody::get_angular_velocity() const {
+ return Vector3();
+}
+float PhysicsBody::get_inverse_mass() const {
+
+ return 0;
}
-void StaticBody::set_constant_linear_velocity(const Vector3& p_vel) {
- constant_linear_velocity=p_vel;
- PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_LINEAR_VELOCITY,constant_linear_velocity);
+void PhysicsBody::set_layer_mask(uint32_t p_mask) {
+ layer_mask=p_mask;
+ PhysicsServer::get_singleton()->body_set_layer_mask(get_rid(),p_mask);
}
-void StaticBody::set_constant_angular_velocity(const Vector3& p_vel) {
+uint32_t PhysicsBody::get_layer_mask() const {
- constant_angular_velocity=p_vel;
- PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_ANGULAR_VELOCITY,constant_angular_velocity);
+ return layer_mask;
}
-Vector3 StaticBody::get_constant_linear_velocity() const {
+void PhysicsBody::add_collision_exception_with(Node* p_node) {
- return constant_linear_velocity;
-}
-Vector3 StaticBody::get_constant_angular_velocity() const {
+ ERR_FAIL_NULL(p_node);
+ PhysicsBody *physics_body = p_node->cast_to<PhysicsBody>();
+ if (!physics_body) {
+ ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type");
+ }
+ ERR_FAIL_COND(!physics_body);
+ PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(),physics_body->get_rid());
- return constant_angular_velocity;
}
+void PhysicsBody::remove_collision_exception_with(Node* p_node) {
-void StaticBody::_state_notify(Object *p_object) {
+ ERR_FAIL_NULL(p_node);
+ PhysicsBody *physics_body = p_node->cast_to<PhysicsBody>();
+ if (!physics_body) {
+ ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type");
+ }
+ ERR_FAIL_COND(!physics_body);
+ PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(),physics_body->get_rid());
+}
- if (!pre_xform)
- return;
- PhysicsDirectBodyState *p2d = (PhysicsDirectBodyState*)p_object;
- setting=true;
+void PhysicsBody::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody::set_layer_mask);
+ ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody::get_layer_mask);
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
+}
- Transform new_xform = p2d->get_transform();
- *pre_xform=new_xform;
- set_ignore_transform_notification(true);
- set_global_transform(new_xform);
- set_ignore_transform_notification(false);
- setting=false;
+PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject( PhysicsServer::get_singleton()->body_create(p_mode), false) {
+ layer_mask=1;
}
-void StaticBody::_update_xform() {
- if (!pre_xform || !pending)
- return;
+void StaticBody::set_friction(real_t p_friction){
- setting=true;
+ ERR_FAIL_COND(p_friction<0 || p_friction>1);
+ friction=p_friction;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction);
- Transform new_xform = get_global_transform(); //obtain the new one
+}
+real_t StaticBody::get_friction() const{
- //set_block_transform_notify(true);
- set_ignore_transform_notification(true);
- PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_TRANSFORM,*pre_xform); //then simulate motion!
- set_global_transform(*pre_xform); //but restore state to previous one in both visual and physics
- set_ignore_transform_notification(false);
+ return friction;
+}
- PhysicsServer::get_singleton()->body_static_simulate_motion(get_rid(),new_xform); //then simulate motion!
+void StaticBody::set_bounce(real_t p_bounce){
- setting=false;
- pending=false;
+ ERR_FAIL_COND(p_bounce<0 || p_bounce>1);
-}
+ bounce=p_bounce;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_BOUNCE,bounce);
-void StaticBody::_notification(int p_what) {
+}
+real_t StaticBody::get_bounce() const{
- switch(p_what) {
+ return bounce;
+}
- case NOTIFICATION_ENTER_SCENE: {
- if (pre_xform)
- *pre_xform = get_global_transform();
- pending=false;
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
- if (simulating_motion && !pending && is_inside_scene() && !setting && !get_scene()->is_editor_hint()) {
+void StaticBody::set_constant_linear_velocity(const Vector3& p_vel) {
- call_deferred(SceneStringNames::get_singleton()->_update_xform);
- pending=true;
- }
+ constant_linear_velocity=p_vel;
+ PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_LINEAR_VELOCITY,constant_linear_velocity);
- } break;
- }
+}
+void StaticBody::set_constant_angular_velocity(const Vector3& p_vel) {
+ constant_angular_velocity=p_vel;
+ PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_ANGULAR_VELOCITY,constant_angular_velocity);
}
-void StaticBody::set_simulate_motion(bool p_enable) {
-
- if (p_enable==simulating_motion)
- return;
- simulating_motion=p_enable;
+Vector3 StaticBody::get_constant_linear_velocity() const {
- if (p_enable) {
- pre_xform = memnew( Transform );
- if (is_inside_scene())
- *pre_xform=get_transform();
-// query = PhysicsServer::get_singleton()->query_create(this,"_state_notify",Variant());
- // PhysicsServer::get_singleton()->query_body_direct_state(query,get_rid());
- PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_state_notify");
+ return constant_linear_velocity;
+}
+Vector3 StaticBody::get_constant_angular_velocity() const {
- } else {
- memdelete( pre_xform );
- pre_xform=NULL;
- PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),NULL,StringName());
- pending=false;
- }
+ return constant_angular_velocity;
}
-bool StaticBody::is_simulating_motion() const {
- return simulating_motion;
-}
void StaticBody::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("set_simulate_motion","enabled"),&StaticBody::set_simulate_motion);
- ObjectTypeDB::bind_method(_MD("is_simulating_motion"),&StaticBody::is_simulating_motion);
- ObjectTypeDB::bind_method(_MD("_update_xform"),&StaticBody::_update_xform);
- ObjectTypeDB::bind_method(_MD("_state_notify"),&StaticBody::_state_notify);
ObjectTypeDB::bind_method(_MD("set_constant_linear_velocity","vel"),&StaticBody::set_constant_linear_velocity);
ObjectTypeDB::bind_method(_MD("set_constant_angular_velocity","vel"),&StaticBody::set_constant_angular_velocity);
ObjectTypeDB::bind_method(_MD("get_constant_linear_velocity"),&StaticBody::get_constant_linear_velocity);
ObjectTypeDB::bind_method(_MD("get_constant_angular_velocity"),&StaticBody::get_constant_angular_velocity);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL,"simulate_motion"),_SCS("set_simulate_motion"),_SCS("is_simulating_motion"));
+ ObjectTypeDB::bind_method(_MD("set_friction","friction"),&StaticBody::set_friction);
+ ObjectTypeDB::bind_method(_MD("get_friction"),&StaticBody::get_friction);
+
+ ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&StaticBody::set_bounce);
+ ObjectTypeDB::bind_method(_MD("get_bounce"),&StaticBody::get_bounce);
+
+ ObjectTypeDB::bind_method(_MD("add_collision_exception_with","body:PhysicsBody"),&PhysicsBody::add_collision_exception_with);
+ ObjectTypeDB::bind_method(_MD("remove_collision_exception_with","body:PhysicsBody"),&PhysicsBody::remove_collision_exception_with);
+
+ 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::VECTOR3,"constant_linear_velocity"),_SCS("set_constant_linear_velocity"),_SCS("get_constant_linear_velocity"));
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"constant_angular_velocity"),_SCS("set_constant_angular_velocity"),_SCS("get_constant_angular_velocity"));
}
StaticBody::StaticBody() : PhysicsBody(PhysicsServer::BODY_MODE_STATIC) {
- simulating_motion=false;
- pre_xform=NULL;
- setting=false;
- pending=false;
- //constant_angular_velocity=0;
-
+ bounce=0;
+ friction=1;
}
StaticBody::~StaticBody() {
- if (pre_xform)
- memdelete(pre_xform);
- //if (query.is_valid())
- // PhysicsServer::get_singleton()->free(query);
+
}
-void RigidBody::_body_enter_scene(ObjectID p_id) {
+void RigidBody::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = obj ? obj->cast_to<Node>() : NULL;
@@ -210,9 +204,9 @@ void RigidBody::_body_enter_scene(ObjectID p_id) {
Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_scene);
+ ERR_FAIL_COND(E->get().in_tree);
- E->get().in_scene=true;
+ E->get().in_tree=true;
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
for(int i=0;i<E->get().shapes.size();i++) {
@@ -222,15 +216,15 @@ void RigidBody::_body_enter_scene(ObjectID p_id) {
}
-void RigidBody::_body_exit_scene(ObjectID p_id) {
+void RigidBody::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = obj ? obj->cast_to<Node>() : NULL;
ERR_FAIL_COND(!node);
Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_scene);
- E->get().in_scene=false;
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree=false;
emit_signal(SceneStringNames::get_singleton()->body_exit,node);
for(int i=0;i<E->get().shapes.size();i++) {
@@ -254,46 +248,48 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,
if (!E) {
E = contact_monitor->body_map.insert(objid,BodyState());
- E->get().rc=0;
- E->get().in_scene=node && node->is_inside_scene();
+ //E->get().rc=0;
+ E->get().in_tree=node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid));
- if (E->get().in_scene) {
+ node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree,make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree,make_binds(objid));
+ if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
}
}
}
- E->get().rc++;
+ //E->get().rc++;
if (node)
E->get().shapes.insert(ShapePair(p_body_shape,p_local_shape));
- if (E->get().in_scene) {
+ if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_local_shape);
}
} else {
- E->get().rc--;
+ //E->get().rc--;
if (node)
E->get().shapes.erase(ShapePair(p_body_shape,p_local_shape));
- if (E->get().rc==0) {
+ bool in_tree = E->get().in_tree;
+
+ if (E->get().shapes.empty()) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene);
- node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene);
- if (E->get().in_scene)
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
+ if (in_tree)
emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
}
contact_monitor->body_map.erase(E);
}
- if (node && E->get().in_scene) {
+ if (node && in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_local_shape);
}
@@ -344,14 +340,14 @@ void RigidBody::_direct_state_changed(Object *p_state) {
ObjectID obj = state->get_contact_collider_id(i);
int local_shape = state->get_contact_local_shape(i);
int shape = state->get_contact_collider_shape(i);
- toadd[i].local_shape=local_shape;
- toadd[i].id=obj;
- toadd[i].shape=shape;
- bool found=false;
+// bool found=false;
Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(obj);
if (!E) {
+ toadd[toadd_count].local_shape=local_shape;
+ toadd[toadd_count].id=obj;
+ toadd[toadd_count].shape=shape;
toadd_count++;
continue;
}
@@ -360,6 +356,9 @@ void RigidBody::_direct_state_changed(Object *p_state) {
int idx = E->get().shapes.find(sp);
if (idx==-1) {
+ toadd[toadd_count].local_shape=local_shape;
+ toadd[toadd_count].id=obj;
+ toadd[toadd_count].shape=shape;
toadd_count++;
continue;
}
@@ -403,7 +402,7 @@ void RigidBody::_direct_state_changed(Object *p_state) {
set_global_transform(state->get_transform());
linear_velocity=state->get_linear_velocity();
angular_velocity=state->get_angular_velocity();
- active=!state->is_sleeping();
+ sleeping=state->is_sleeping();
if (get_script_instance())
get_script_instance()->call("_integrate_forces",state);
set_ignore_transform_notification(false);
@@ -497,6 +496,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;
@@ -554,10 +589,10 @@ bool RigidBody::is_using_custom_integrator(){
return custom_integrator;
}
-void RigidBody::set_active(bool p_active) {
+void RigidBody::set_sleeping(bool p_sleeping) {
- active=p_active;
- PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_SLEEPING,!active);
+ sleeping=p_sleeping;
+ PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_SLEEPING,sleeping);
}
@@ -572,9 +607,9 @@ bool RigidBody::is_able_to_sleep() const {
return can_sleep;
}
-bool RigidBody::is_active() const {
+bool RigidBody::is_sleeping() const {
- return active;
+ return sleeping;
}
void RigidBody::set_max_contacts_reported(int p_amount) {
@@ -644,6 +679,27 @@ RigidBody::AxisLock RigidBody::get_axis_lock() const {
}
+Array RigidBody::get_colliding_bodies() const {
+
+ ERR_FAIL_COND_V(!contact_monitor,Array());
+
+ Array ret;
+ ret.resize(contact_monitor->body_map.size());
+ int idx=0;
+ for (const Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize( ret.size() -1 ); //ops
+ } else {
+ ret[idx++]=obj;
+ }
+
+ }
+
+ return ret;
+}
+
+
void RigidBody::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_mode","mode"),&RigidBody::set_mode);
@@ -667,6 +723,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);
@@ -682,19 +748,21 @@ void RigidBody::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_axis_velocity","axis_velocity"),&RigidBody::set_axis_velocity);
ObjectTypeDB::bind_method(_MD("apply_impulse","pos","impulse"),&RigidBody::apply_impulse);
- ObjectTypeDB::bind_method(_MD("set_active","active"),&RigidBody::set_active);
- ObjectTypeDB::bind_method(_MD("is_active"),&RigidBody::is_active);
+ ObjectTypeDB::bind_method(_MD("set_sleeping","sleeping"),&RigidBody::set_sleeping);
+ ObjectTypeDB::bind_method(_MD("is_sleeping"),&RigidBody::is_sleeping);
ObjectTypeDB::bind_method(_MD("set_can_sleep","able_to_sleep"),&RigidBody::set_can_sleep);
ObjectTypeDB::bind_method(_MD("is_able_to_sleep"),&RigidBody::is_able_to_sleep);
ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&RigidBody::_direct_state_changed);
- ObjectTypeDB::bind_method(_MD("_body_enter_scene"),&RigidBody::_body_enter_scene);
- ObjectTypeDB::bind_method(_MD("_body_exit_scene"),&RigidBody::_body_exit_scene);
+ ObjectTypeDB::bind_method(_MD("_body_enter_tree"),&RigidBody::_body_enter_tree);
+ ObjectTypeDB::bind_method(_MD("_body_exit_tree"),&RigidBody::_body_exit_tree);
ObjectTypeDB::bind_method(_MD("set_axis_lock","axis_lock"),&RigidBody::set_axis_lock);
ObjectTypeDB::bind_method(_MD("get_axis_lock"),&RigidBody::get_axis_lock);
+ ObjectTypeDB::bind_method(_MD("get_colliding_bodies"),&RigidBody::get_colliding_bodies);
+
BIND_VMETHOD(MethodInfo("_integrate_forces",PropertyInfo(Variant::OBJECT,"state:PhysicsDirectBodyState")));
ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Rigid,Static,Character,Kinematic"),_SCS("set_mode"),_SCS("get_mode"));
@@ -702,15 +770,18 @@ 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"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"contact_monitor"),_SCS("set_contact_monitor"),_SCS("is_contact_monitor_enabled"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"active"),_SCS("set_active"),_SCS("is_active"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"sleeping"),_SCS("set_sleeping"),_SCS("is_sleeping"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"can_sleep"),_SCS("set_can_sleep"),_SCS("is_able_to_sleep"));
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")));
@@ -733,8 +804,12 @@ 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;
- active=true;
+ sleeping=false;
ccd=false;
custom_integrator=false;
@@ -754,4 +829,425 @@ RigidBody::~RigidBody() {
}
+//////////////////////////////////////////////////////
+//////////////////////////
+
+
+Variant KinematicBody::_get_collider() const {
+
+ ObjectID oid=get_collider();
+ if (oid==0)
+ return Variant();
+ Object *obj = ObjectDB::get_instance(oid);
+ if (!obj)
+ return Variant();
+
+ Reference *ref = obj->cast_to<Reference>();
+ if (ref) {
+ return Ref<Reference>(ref);
+ }
+
+ return obj;
+}
+
+
+bool KinematicBody::_ignores_mode(PhysicsServer::BodyMode p_mode) const {
+
+ switch(p_mode) {
+ case PhysicsServer::BODY_MODE_STATIC: return !collide_static;
+ case PhysicsServer::BODY_MODE_KINEMATIC: return !collide_kinematic;
+ case PhysicsServer::BODY_MODE_RIGID: return !collide_rigid;
+ case PhysicsServer::BODY_MODE_CHARACTER: return !collide_character;
+ }
+
+ return true;
+}
+
+Vector3 KinematicBody::move(const Vector3& p_motion) {
+
+ //give me back regular physics engine logic
+ //this is madness
+ //and most people using this function will think
+ //what it does is simpler than using physics
+ //this took about a week to get right..
+ //but is it right? who knows at this point..
+
+
+ colliding=false;
+ ERR_FAIL_COND_V(!is_inside_tree(),Vector3());
+ PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(get_world()->get_space());
+ ERR_FAIL_COND_V(!dss,Vector3());
+ const int max_shapes=32;
+ Vector3 sr[max_shapes*2];
+ int res_shapes;
+
+ Set<RID> exclude;
+ exclude.insert(get_rid());
+
+
+ //recover first
+ int recover_attempts=4;
+
+ bool collided=false;
+ uint32_t mask=0;
+ if (collide_static)
+ mask|=PhysicsDirectSpaceState::TYPE_MASK_STATIC_BODY;
+ if (collide_kinematic)
+ mask|=PhysicsDirectSpaceState::TYPE_MASK_KINEMATIC_BODY;
+ if (collide_rigid)
+ mask|=PhysicsDirectSpaceState::TYPE_MASK_RIGID_BODY;
+ if (collide_character)
+ mask|=PhysicsDirectSpaceState::TYPE_MASK_CHARACTER_BODY;
+
+// print_line("motion: "+p_motion+" margin: "+rtos(margin));
+
+ //print_line("margin: "+rtos(margin));
+
+ float m = margin;
+ //m=0.001;
+
+ do {
+
+ //motion recover
+ for(int i=0;i<get_shape_count();i++) {
+
+ if (is_shape_set_as_trigger(i))
+ continue;
+
+ if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),m,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) {
+ collided=true;
+ }
+
+ }
+
+
+
+ if (!collided)
+ break;
+
+ //print_line("have to recover");
+ Vector3 recover_motion;
+ bool all_outside=true;
+ for(int j=0;j<8;j++) {
+ for(int i=0;i<res_shapes;i++) {
+
+ Vector3 a = sr[i*2+0];
+ Vector3 b = sr[i*2+1];
+ //print_line(String()+a+" -> "+b);
+#if 0
+ float d = a.distance_to(b);
+
+ //if (d<margin)
+ /// continue;
+ ///
+ ///
+ recover_motion+=(b-a)*0.2;
+#else
+ float dist = a.distance_to(b);
+ if (dist>CMP_EPSILON) {
+ Vector3 norm = (b-a).normalized();
+ if (dist>margin*0.5)
+ all_outside=false;
+ float adv = norm.dot(recover_motion);
+ //print_line(itos(i)+" dist: "+rtos(dist)+" adv: "+rtos(adv));
+ recover_motion+=norm*MAX(dist-adv,0)*0.4;
+ }
+#endif
+
+ }
+ }
+
+
+ if (recover_motion==Vector3()) {
+ collided=false;
+ break;
+ }
+
+ //print_line("**** RECOVER: "+recover_motion);
+
+ Transform gt = get_global_transform();
+ gt.origin+=recover_motion;
+ set_global_transform(gt);
+
+ recover_attempts--;
+
+ if (all_outside)
+ break;
+
+ } while (recover_attempts);
+
+
+ //move second
+ float safe = 1.0;
+ float unsafe = 1.0;
+ int best_shape=-1;
+
+ PhysicsDirectSpaceState::ShapeRestInfo rest;
+
+ //print_line("pos: "+get_global_transform().origin);
+ //print_line("motion: "+p_motion);
+
+
+ for(int i=0;i<get_shape_count();i++) {
+
+
+ if (is_shape_set_as_trigger(i))
+ continue;
+
+ float lsafe,lunsafe;
+ PhysicsDirectSpaceState::ShapeRestInfo lrest;
+ bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion,0, lsafe,lunsafe,exclude,get_layer_mask(),mask,&lrest);
+ //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel));
+ if (!valid) {
+ safe=0;
+ unsafe=0;
+ best_shape=i; //sadly it's the best
+ //print_line("initial stuck");
+
+ break;
+ }
+ if (lsafe==1.0) {
+ //print_line("initial free");
+ continue;
+ }
+ if (lsafe < safe) {
+
+ //print_line("initial at "+rtos(lsafe));
+ safe=lsafe;
+ safe=MAX(0,lsafe-0.01);
+ unsafe=lunsafe;
+ best_shape=i;
+ rest=lrest;
+ }
+ }
+
+
+ //print_line("best shape: "+itos(best_shape)+" motion "+p_motion);
+
+ if (safe>=1) {
+ //not collided
+ colliding=false;
+ } else {
+
+ colliding=true;
+
+ if (true || (safe==0 && unsafe==0)) { //use it always because it's more precise than GJK
+ //no advance, use rest info from collision
+ Transform ugt = get_global_transform();
+ ugt.origin+=p_motion*unsafe;
+
+ PhysicsDirectSpaceState::ShapeRestInfo rest_info;
+ bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), m,&rest,exclude,get_layer_mask(),mask);
+ if (!c2) {
+ //should not happen, but floating point precision is so weird..
+ colliding=false;
+ }
+
+ // print_line("Rest Travel: "+rest.normal);
+
+ }
+
+ if (colliding) {
+
+ collision=rest.point;
+ normal=rest.normal;
+ collider=rest.collider_id;
+ collider_vel=rest.linear_velocity;
+ collider_shape=rest.shape;
+ }
+ }
+
+ Vector3 motion=p_motion*safe;
+ //if (colliding)
+ // motion+=normal*0.001;
+ Transform gt = get_global_transform();
+ gt.origin+=motion;
+ set_global_transform(gt);
+
+ return p_motion-motion;
+
+}
+
+Vector3 KinematicBody::move_to(const Vector3& p_position) {
+
+ return move(p_position-get_global_transform().origin);
+}
+
+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());
+ ERR_FAIL_COND_V(!dss,false);
+
+ uint32_t mask=0;
+ if (collide_static)
+ mask|=PhysicsDirectSpaceState::TYPE_MASK_STATIC_BODY;
+ if (collide_kinematic)
+ mask|=PhysicsDirectSpaceState::TYPE_MASK_KINEMATIC_BODY;
+ if (collide_rigid)
+ mask|=PhysicsDirectSpaceState::TYPE_MASK_RIGID_BODY;
+ if (collide_character)
+ mask|=PhysicsDirectSpaceState::TYPE_MASK_CHARACTER_BODY;
+
+ Transform xform=get_global_transform();
+ xform.origin=p_position;
+
+ Set<RID> exclude;
+ exclude.insert(get_rid());
+
+ 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,1,exclude,get_layer_mask(),mask);
+ if (col)
+ return false;
+ }
+
+ return true;
+}
+
+bool KinematicBody::is_colliding() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(),false);
+
+ return colliding;
+}
+Vector3 KinematicBody::get_collision_pos() const {
+
+ ERR_FAIL_COND_V(!colliding,Vector3());
+ return collision;
+
+}
+Vector3 KinematicBody::get_collision_normal() const {
+
+ ERR_FAIL_COND_V(!colliding,Vector3());
+ return normal;
+
+}
+
+Vector3 KinematicBody::get_collider_velocity() const {
+
+ return collider_vel;
+}
+
+ObjectID KinematicBody::get_collider() const {
+
+ ERR_FAIL_COND_V(!colliding,0);
+ return collider;
+}
+int KinematicBody::get_collider_shape() const {
+
+ ERR_FAIL_COND_V(!colliding,-1);
+ return collider_shape;
+
+}
+void KinematicBody::set_collide_with_static_bodies(bool p_enable) {
+
+ collide_static=p_enable;
+}
+bool KinematicBody::can_collide_with_static_bodies() const {
+
+ return collide_static;
+}
+
+void KinematicBody::set_collide_with_rigid_bodies(bool p_enable) {
+
+ collide_rigid=p_enable;
+
+}
+bool KinematicBody::can_collide_with_rigid_bodies() const {
+
+
+ return collide_rigid;
+}
+
+void KinematicBody::set_collide_with_kinematic_bodies(bool p_enable) {
+
+ collide_kinematic=p_enable;
+
+}
+bool KinematicBody::can_collide_with_kinematic_bodies() const {
+
+ return collide_kinematic;
+}
+
+void KinematicBody::set_collide_with_character_bodies(bool p_enable) {
+
+ collide_character=p_enable;
+}
+bool KinematicBody::can_collide_with_character_bodies() const {
+
+ return collide_character;
+}
+
+void KinematicBody::set_collision_margin(float p_margin) {
+
+ margin=p_margin;
+}
+
+float KinematicBody::get_collision_margin() const{
+
+ return margin;
+}
+
+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_teleport_to","position"),&KinematicBody::can_teleport_to);
+
+ ObjectTypeDB::bind_method(_MD("is_colliding"),&KinematicBody::is_colliding);
+
+ ObjectTypeDB::bind_method(_MD("get_collision_pos"),&KinematicBody::get_collision_pos);
+ ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody::get_collision_normal);
+ ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody::get_collider_velocity);
+ ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody::_get_collider);
+ ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody::get_collider_shape);
+
+
+ ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody::set_collide_with_static_bodies);
+ ObjectTypeDB::bind_method(_MD("can_collide_with_static_bodies"),&KinematicBody::can_collide_with_static_bodies);
+
+ ObjectTypeDB::bind_method(_MD("set_collide_with_kinematic_bodies","enable"),&KinematicBody::set_collide_with_kinematic_bodies);
+ ObjectTypeDB::bind_method(_MD("can_collide_with_kinematic_bodies"),&KinematicBody::can_collide_with_kinematic_bodies);
+
+ ObjectTypeDB::bind_method(_MD("set_collide_with_rigid_bodies","enable"),&KinematicBody::set_collide_with_rigid_bodies);
+ ObjectTypeDB::bind_method(_MD("can_collide_with_rigid_bodies"),&KinematicBody::can_collide_with_rigid_bodies);
+
+ ObjectTypeDB::bind_method(_MD("set_collide_with_character_bodies","enable"),&KinematicBody::set_collide_with_character_bodies);
+ ObjectTypeDB::bind_method(_MD("can_collide_with_character_bodies"),&KinematicBody::can_collide_with_character_bodies);
+
+ ObjectTypeDB::bind_method(_MD("set_collision_margin","pixels"),&KinematicBody::set_collision_margin);
+ ObjectTypeDB::bind_method(_MD("get_collision_margin","pixels"),&KinematicBody::get_collision_margin);
+
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/static"),_SCS("set_collide_with_static_bodies"),_SCS("can_collide_with_static_bodies"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/kinematic"),_SCS("set_collide_with_kinematic_bodies"),_SCS("can_collide_with_kinematic_bodies"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/rigid"),_SCS("set_collide_with_rigid_bodies"),_SCS("can_collide_with_rigid_bodies"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/character"),_SCS("set_collide_with_character_bodies"),_SCS("can_collide_with_character_bodies"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/margin",PROPERTY_HINT_RANGE,"0.001,256,0.001"),_SCS("set_collision_margin"),_SCS("get_collision_margin"));
+
+
+}
+
+KinematicBody::KinematicBody() : PhysicsBody(PhysicsServer::BODY_MODE_KINEMATIC){
+
+ collide_static=true;
+ collide_rigid=true;
+ collide_kinematic=true;
+ collide_character=true;
+
+ colliding=false;
+ collider=0;
+ margin=0.001;
+ collider_shape=0;
+}
+KinematicBody::~KinematicBody() {
+
+
+}
+
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 6695ee719a..0e63b77118 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,12 +38,26 @@ class PhysicsBody : public CollisionObject {
OBJ_TYPE(PhysicsBody,CollisionObject);
+ uint32_t layer_mask;
protected:
+ static void _bind_methods();
void _notification(int p_what);
PhysicsBody(PhysicsServer::BodyMode p_mode);
public:
+ virtual Vector3 get_linear_velocity() const;
+ virtual Vector3 get_angular_velocity() const;
+ virtual float get_inverse_mass() const;
+
+ void set_layer_mask(uint32_t p_mask);
+ uint32_t get_layer_mask() const;
+
+ void add_collision_exception_with(Node* p_node); //must be physicsbody
+ void remove_collision_exception_with(Node* p_node);
+
+
+
PhysicsBody();
};
@@ -52,25 +66,26 @@ class StaticBody : public PhysicsBody {
OBJ_TYPE(StaticBody,PhysicsBody);
- Transform *pre_xform;
- //RID query;
- bool setting;
- bool pending;
- bool simulating_motion;
Vector3 constant_linear_velocity;
Vector3 constant_angular_velocity;
- void _update_xform();
- void _state_notify(Object *p_object);
+
+ real_t bounce;
+ real_t friction;
+
protected:
- void _notification(int p_what);
static void _bind_methods();
public:
- void set_simulate_motion(bool p_enable);
- bool is_simulating_motion() const;
+
+ void set_friction(real_t p_friction);
+ real_t get_friction() const;
+
+ void set_bounce(real_t p_bounce);
+ real_t get_bounce() const;
+
void set_constant_linear_velocity(const Vector3& p_vel);
void set_constant_angular_velocity(const Vector3& p_vel);
@@ -114,7 +129,11 @@ private:
Vector3 linear_velocity;
Vector3 angular_velocity;
- bool active;
+ real_t gravity_scale;
+ real_t linear_damp;
+ real_t angular_damp;
+
+ bool sleeping;
bool ccd;
AxisLock axis_lock;
@@ -149,8 +168,8 @@ private:
};
struct BodyState {
- int rc;
- bool in_scene;
+ //int rc;
+ bool in_tree;
VSet<ShapePair> shapes;
};
@@ -163,8 +182,8 @@ private:
ContactMonitor *contact_monitor;
- void _body_enter_scene(ObjectID p_id);
- void _body_exit_scene(ObjectID p_id);
+ void _body_enter_tree(ObjectID p_id);
+ void _body_exit_tree(ObjectID p_id);
void _body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape);
@@ -183,6 +202,8 @@ public:
void set_mass(real_t p_mass);
real_t get_mass() const;
+ virtual float get_inverse_mass() const { return 1.0/mass; }
+
void set_weight(real_t p_weight);
real_t get_weight() const;
@@ -200,11 +221,21 @@ 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();
- void set_active(bool p_active);
- bool is_active() const;
+ void set_sleeping(bool p_sleeping);
+ bool is_sleeping() const;
void set_can_sleep(bool p_active);
bool is_able_to_sleep() const;
@@ -221,6 +252,7 @@ public:
void set_axis_lock(AxisLock p_lock);
AxisLock get_axis_lock() const;
+ Array get_colliding_bodies() const;
void apply_impulse(const Vector3& p_pos, const Vector3& p_impulse);
@@ -231,4 +263,73 @@ public:
VARIANT_ENUM_CAST(RigidBody::Mode);
VARIANT_ENUM_CAST(RigidBody::AxisLock);
+
+
+
+
+
+class KinematicBody : public PhysicsBody {
+
+ OBJ_TYPE(KinematicBody,PhysicsBody);
+
+ float margin;
+ bool collide_static;
+ bool collide_rigid;
+ bool collide_kinematic;
+ bool collide_character;
+
+ bool colliding;
+ Vector3 collision;
+ Vector3 normal;
+ Vector3 collider_vel;
+ ObjectID collider;
+ int collider_shape;
+
+
+
+ Variant _get_collider() const;
+
+ _FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const;
+protected:
+
+ static void _bind_methods();
+public:
+
+ enum {
+ SLIDE_FLAG_FLOOR,
+ SLIDE_FLAG_WALL,
+ SLIDE_FLAG_ROOF
+ };
+
+ Vector3 move(const Vector3& p_motion);
+ Vector3 move_to(const Vector3& p_position);
+
+ bool can_teleport_to(const Vector3& p_position);
+ bool is_colliding() const;
+ Vector3 get_collision_pos() const;
+ Vector3 get_collision_normal() const;
+ Vector3 get_collider_velocity() const;
+ ObjectID get_collider() const;
+ int get_collider_shape() const;
+
+ void set_collide_with_static_bodies(bool p_enable);
+ bool can_collide_with_static_bodies() const;
+
+ void set_collide_with_rigid_bodies(bool p_enable);
+ bool can_collide_with_rigid_bodies() const;
+
+ void set_collide_with_kinematic_bodies(bool p_enable);
+ bool can_collide_with_kinematic_bodies() const;
+
+ void set_collide_with_character_bodies(bool p_enable);
+ bool can_collide_with_character_bodies() const;
+
+ void set_collision_margin(float p_margin);
+ float get_collision_margin() const;
+
+ KinematicBody();
+ ~KinematicBody();
+
+};
+
#endif // PHYSICS_BODY__H
diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp
index 961198c8d4..f4facb7c3f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,7 +27,1063 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "physics_joint.h"
-
+
+
+
+void Joint::_update_joint(bool p_only_free) {
+
+
+ if (joint.is_valid()) {
+ 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();
+ bb=RID();
+ }
+
+ if (p_only_free || !is_inside_tree())
+ return;
+
+ Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL;
+ Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL;
+
+ if (!node_a && !node_b)
+ return;
+
+ PhysicsBody *body_a=node_a ? node_a->cast_to<PhysicsBody>() : (PhysicsBody*)NULL;
+ PhysicsBody *body_b=node_b ? node_b->cast_to<PhysicsBody>() : (PhysicsBody*)NULL;
+
+ if (!body_a && !body_b)
+ return;
+
+ if (!body_a) {
+ SWAP(body_a,body_b);
+ } else if (body_b) {
+ //add a collision exception between both
+ PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
+ }
+
+ joint = _configure_joint(body_a,body_b);
+
+ if (joint.is_valid())
+ PhysicsServer::get_singleton()->joint_set_solver_priority(joint,solver_priority);
+
+ if (body_b && joint.is_valid()) {
+
+ ba=body_a->get_rid();
+ bb=body_b->get_rid();
+ PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
+
+ }
+
+}
+
+
+void Joint::set_node_a(const NodePath& p_node_a) {
+
+
+ if (a==p_node_a)
+ return;
+
+ a=p_node_a;
+ _update_joint();
+}
+
+NodePath Joint::get_node_a() const{
+
+ return a;
+}
+
+void Joint::set_node_b(const NodePath& p_node_b){
+
+ if (b==p_node_b)
+ return;
+ b=p_node_b;
+ _update_joint();
+
+}
+NodePath Joint::get_node_b() const{
+
+
+ return b;
+}
+
+
+void Joint::set_solver_priority(int p_priority) {
+
+ solver_priority=p_priority;
+ if (joint.is_valid())
+ PhysicsServer::get_singleton()->joint_set_solver_priority(joint,solver_priority);
+
+}
+
+int Joint::get_solver_priority() const {
+
+ return solver_priority;
+}
+
+
+void Joint::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_READY: {
+ _update_joint();
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (joint.is_valid()) {
+ _update_joint(true);
+ PhysicsServer::get_singleton()->free(joint);
+ joint=RID();
+ }
+ } break;
+
+ }
+
+}
+
+
+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() {
+
+
+ ObjectTypeDB::bind_method( _MD("set_node_a","node"), &Joint::set_node_a );
+ ObjectTypeDB::bind_method( _MD("get_node_a"), &Joint::get_node_a );
+
+ ObjectTypeDB::bind_method( _MD("set_node_b","node"), &Joint::set_node_b );
+ ObjectTypeDB::bind_method( _MD("get_node_b"), &Joint::get_node_b );
+
+ 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") );
+
+
+
+}
+
+
+
+Joint::Joint() {
+
+ exclude_from_collision=true;
+ solver_priority=1;
+}
+
+
+///////////////////////////////////
+
+void PinJoint::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_param","param","value"),&PinJoint::set_param);
+ ObjectTypeDB::bind_method(_MD("get_param","param"),&PinJoint::get_param);
+
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/bias",PROPERTY_HINT_RANGE,"0.01,0.99,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_BIAS );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/damping",PROPERTY_HINT_RANGE,"0.01,8.0,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_DAMPING );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/impulse_clamp",PROPERTY_HINT_RANGE,"0.0,64.0,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_IMPULSE_CLAMP );
+
+ BIND_CONSTANT( PARAM_BIAS );
+ BIND_CONSTANT( PARAM_DAMPING );
+ BIND_CONSTANT( PARAM_IMPULSE_CLAMP );
+}
+
+void PinJoint::set_param(Param p_param,float p_value){
+
+ ERR_FAIL_INDEX(p_param,3);
+ params[p_param]=p_value;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->pin_joint_set_param(get_joint(),PhysicsServer::PinJointParam(p_param),p_value);
+}
+float PinJoint::get_param(Param p_param) const{
+
+ ERR_FAIL_INDEX_V(p_param,3,0);
+ return params[p_param];
+}
+
+
+RID PinJoint::_configure_joint(PhysicsBody *body_a,PhysicsBody *body_b) {
+
+
+ Vector3 pinpos = get_global_transform().origin;
+ Vector3 local_a = body_a->get_global_transform().affine_inverse().xform(pinpos);
+ Vector3 local_b;
+
+ if (body_b)
+ local_b = body_b->get_global_transform().affine_inverse().xform(pinpos);
+ else
+ local_b=pinpos;
+
+ RID j = PhysicsServer::get_singleton()->joint_create_pin(body_a->get_rid(),local_a,body_b?body_b->get_rid():RID(),local_b);
+ for(int i=0;i<3;i++) {
+ PhysicsServer::get_singleton()->pin_joint_set_param(j,PhysicsServer::PinJointParam(i),params[i]);
+ }
+ return j;
+}
+
+
+PinJoint::PinJoint() {
+
+ params[PARAM_BIAS]=0.3;
+ params[PARAM_DAMPING]=1;
+ params[PARAM_IMPULSE_CLAMP]=0;
+
+}
+
+
+
+
+/////////////////////////////////////////////////
+
+
+
+///////////////////////////////////
+
+
+void HingeJoint::_set_upper_limit(float p_limit) {
+
+ set_param(PARAM_LIMIT_UPPER,Math::deg2rad(p_limit));
+}
+
+float HingeJoint::_get_upper_limit() const {
+
+ return Math::rad2deg(get_param(PARAM_LIMIT_UPPER));
+}
+
+void HingeJoint::_set_lower_limit(float p_limit) {
+
+ set_param(PARAM_LIMIT_LOWER,Math::deg2rad(p_limit));
+
+}
+
+float HingeJoint::_get_lower_limit() const {
+
+ return Math::rad2deg(get_param(PARAM_LIMIT_LOWER));
+
+}
+
+
+void HingeJoint::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_param","param","value"),&HingeJoint::set_param);
+ ObjectTypeDB::bind_method(_MD("get_param","param"),&HingeJoint::get_param);
+
+ ObjectTypeDB::bind_method(_MD("set_flag","flag","enabled"),&HingeJoint::set_flag);
+ ObjectTypeDB::bind_method(_MD("get_flag","flag"),&HingeJoint::get_flag);
+
+ ObjectTypeDB::bind_method(_MD("_set_upper_limit","upper_limit"),&HingeJoint::_set_upper_limit);
+ ObjectTypeDB::bind_method(_MD("_get_upper_limit"),&HingeJoint::_get_upper_limit);
+
+ ObjectTypeDB::bind_method(_MD("_set_lower_limit","lower_limit"),&HingeJoint::_set_lower_limit);
+ ObjectTypeDB::bind_method(_MD("_get_lower_limit"),&HingeJoint::_get_lower_limit);
+
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/bias",PROPERTY_HINT_RANGE,"0.01,0.99,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_BIAS );
+
+ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"angular_limit/enable"),_SCS("set_flag"),_SCS("get_flag"), FLAG_USE_LIMIT );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_limit/upper",PROPERTY_HINT_RANGE,"-180,180,0.1"),_SCS("_set_upper_limit"),_SCS("_get_upper_limit") );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_limit/lower",PROPERTY_HINT_RANGE,"-180,180,0.1"),_SCS("_set_lower_limit"),_SCS("_get_lower_limit") );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_limit/bias",PROPERTY_HINT_RANGE,"0.01,0.99,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_LIMIT_BIAS );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_limit/softness",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_LIMIT_SOFTNESS );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_limit/relaxation",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_LIMIT_RELAXATION );
+
+ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"motor/enable"),_SCS("set_flag"),_SCS("get_flag"), FLAG_ENABLE_MOTOR );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"motor/target_velocity",PROPERTY_HINT_RANGE,"0.01,4096,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_MOTOR_TARGET_VELOCITY );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"motor/max_impulse",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_MOTOR_MAX_IMPULSE);
+
+
+ BIND_CONSTANT( PARAM_BIAS );
+ BIND_CONSTANT( PARAM_LIMIT_UPPER );
+ BIND_CONSTANT( PARAM_LIMIT_LOWER );
+ BIND_CONSTANT( PARAM_LIMIT_BIAS );
+ BIND_CONSTANT( PARAM_LIMIT_SOFTNESS );
+ BIND_CONSTANT( PARAM_LIMIT_RELAXATION );
+ BIND_CONSTANT( PARAM_MOTOR_TARGET_VELOCITY );
+ BIND_CONSTANT( PARAM_MOTOR_MAX_IMPULSE );
+ BIND_CONSTANT( PARAM_MAX );
+
+ BIND_CONSTANT( FLAG_USE_LIMIT );
+ BIND_CONSTANT( FLAG_ENABLE_MOTOR );
+ BIND_CONSTANT( FLAG_MAX );
+
+}
+
+void HingeJoint::set_param(Param p_param,float p_value){
+
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ params[p_param]=p_value;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(get_joint(),PhysicsServer::HingeJointParam(p_param),p_value);
+
+ update_gizmo();
+
+}
+float HingeJoint::get_param(Param p_param) const{
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return params[p_param];
+}
+
+
+void HingeJoint::set_flag(Flag p_flag,bool p_value){
+
+ ERR_FAIL_INDEX(p_flag,FLAG_MAX);
+ flags[p_flag]=p_value;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_flag(get_joint(),PhysicsServer::HingeJointFlag(p_flag),p_value);
+
+ update_gizmo();
+}
+bool HingeJoint::get_flag(Flag p_flag) const{
+
+ ERR_FAIL_INDEX_V(p_flag,FLAG_MAX,false);
+ return flags[p_flag];
+}
+
+RID HingeJoint::_configure_joint(PhysicsBody *body_a,PhysicsBody *body_b) {
+
+
+ Transform gt = get_global_transform();
+ Vector3 hingepos = gt.origin;
+ Vector3 hingedir = gt.basis.get_axis(2);
+
+ Transform ainv = body_a->get_global_transform().affine_inverse();
+
+ Transform local_a = ainv * gt;
+ local_a.orthonormalize();
+ Transform local_b = gt;
+
+ if (body_b) {
+ Transform binv = body_b->get_global_transform().affine_inverse();
+ local_b = binv * gt;
+ }
+
+ local_b.orthonormalize();
+
+ RID j = PhysicsServer::get_singleton()->joint_create_hinge(body_a->get_rid(),local_a,body_b?body_b->get_rid():RID(),local_b);
+ for(int i=0;i<PARAM_MAX;i++) {
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j,PhysicsServer::HingeJointParam(i),params[i]);
+ }
+ for(int i=0;i<FLAG_MAX;i++) {
+ set_flag(Flag(i),flags[i]);
+ PhysicsServer::get_singleton()->hinge_joint_set_flag(j,PhysicsServer::HingeJointFlag(i),flags[i]);
+ }
+ return j;
+}
+
+
+HingeJoint::HingeJoint() {
+
+ params[PARAM_BIAS]=0.3;
+ params[PARAM_LIMIT_UPPER]=Math_PI*0.5;
+ params[PARAM_LIMIT_LOWER]=-Math_PI*0.5;
+ params[PARAM_LIMIT_BIAS]=0.3;
+ params[PARAM_LIMIT_SOFTNESS]=0.9;
+ params[PARAM_LIMIT_RELAXATION]=1.0;
+ params[PARAM_MOTOR_TARGET_VELOCITY]=1;
+ params[PARAM_MOTOR_MAX_IMPULSE]=1;
+
+
+ flags[FLAG_USE_LIMIT]=false;
+ flags[FLAG_ENABLE_MOTOR]=false;
+
+}
+
+
+
+
+/////////////////////////////////////////////////
+
+
+//////////////////////////////////
+
+
+
+void SliderJoint::_set_upper_limit_angular(float p_limit_angular) {
+
+ set_param(PARAM_ANGULAR_LIMIT_UPPER,Math::deg2rad(p_limit_angular));
+}
+
+float SliderJoint::_get_upper_limit_angular() const {
+
+ return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_UPPER));
+}
+
+void SliderJoint::_set_lower_limit_angular(float p_limit_angular) {
+
+ set_param(PARAM_ANGULAR_LIMIT_LOWER,Math::deg2rad(p_limit_angular));
+
+}
+
+float SliderJoint::_get_lower_limit_angular() const {
+
+ return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_LOWER));
+
+}
+
+
+void SliderJoint::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_param","param","value"),&SliderJoint::set_param);
+ ObjectTypeDB::bind_method(_MD("get_param","param"),&SliderJoint::get_param);
+
+
+ ObjectTypeDB::bind_method(_MD("_set_upper_limit_angular","upper_limit_angular"),&SliderJoint::_set_upper_limit_angular);
+ ObjectTypeDB::bind_method(_MD("_get_upper_limit_angular"),&SliderJoint::_get_upper_limit_angular);
+
+ ObjectTypeDB::bind_method(_MD("_set_lower_limit_angular","lower_limit_angular"),&SliderJoint::_set_lower_limit_angular);
+ ObjectTypeDB::bind_method(_MD("_get_lower_limit_angular"),&SliderJoint::_get_lower_limit_angular);
+
+
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_limit/upper_distance",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_LIMIT_UPPER);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_limit/lower_distance",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_LIMIT_LOWER);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_limit/softness",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_limit/restitution",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_LIMIT_RESTITUTION);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_limit/damping",PROPERTY_HINT_RANGE,"0,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_LIMIT_DAMPING);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_motion/softness",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_MOTION_SOFTNESS);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_motion/restitution",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_MOTION_RESTITUTION);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_motion/damping",PROPERTY_HINT_RANGE,"0,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_MOTION_DAMPING);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_ortho/softness",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_ORTHOGONAL_SOFTNESS);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_ortho/restitution",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_ORTHOGONAL_RESTITUTION);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"linear_ortho/damping",PROPERTY_HINT_RANGE,"0,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_LINEAR_ORTHOGONAL_DAMPING);
+
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_limit/upper_angle",PROPERTY_HINT_RANGE,"-180,180,0.1"),_SCS("_set_upper_limit_angular"),_SCS("_get_upper_limit_angular") );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_limit/lower_angle",PROPERTY_HINT_RANGE,"-180,180,0.1"),_SCS("_set_lower_limit_angular"),_SCS("_get_lower_limit_angular") );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_limit/softness",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_limit/restitution",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_LIMIT_RESTITUTION);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_limit/damping",PROPERTY_HINT_RANGE,"0,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_LIMIT_DAMPING);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_motion/softness",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_MOTION_SOFTNESS);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_motion/restitution",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_MOTION_RESTITUTION);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_motion/damping",PROPERTY_HINT_RANGE,"0,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_MOTION_DAMPING);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_ortho/softness",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_ORTHOGONAL_SOFTNESS);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_ortho/restitution",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_ORTHOGONAL_RESTITUTION);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"angular_ortho/damping",PROPERTY_HINT_RANGE,"0,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_ANGULAR_ORTHOGONAL_DAMPING);
+
+
+ BIND_CONSTANT( PARAM_LINEAR_LIMIT_UPPER);
+ BIND_CONSTANT( PARAM_LINEAR_LIMIT_LOWER);
+ BIND_CONSTANT( PARAM_LINEAR_LIMIT_SOFTNESS);
+ BIND_CONSTANT( PARAM_LINEAR_LIMIT_RESTITUTION);
+ BIND_CONSTANT( PARAM_LINEAR_LIMIT_DAMPING);
+ BIND_CONSTANT( PARAM_LINEAR_MOTION_SOFTNESS);
+ BIND_CONSTANT( PARAM_LINEAR_MOTION_RESTITUTION);
+ BIND_CONSTANT( PARAM_LINEAR_MOTION_DAMPING);
+ BIND_CONSTANT( PARAM_LINEAR_ORTHOGONAL_SOFTNESS);
+ BIND_CONSTANT( PARAM_LINEAR_ORTHOGONAL_RESTITUTION);
+ BIND_CONSTANT( PARAM_LINEAR_ORTHOGONAL_DAMPING);
+
+ BIND_CONSTANT( PARAM_ANGULAR_LIMIT_UPPER);
+ BIND_CONSTANT( PARAM_ANGULAR_LIMIT_LOWER);
+ BIND_CONSTANT( PARAM_ANGULAR_LIMIT_SOFTNESS);
+ BIND_CONSTANT( PARAM_ANGULAR_LIMIT_RESTITUTION);
+ BIND_CONSTANT( PARAM_ANGULAR_LIMIT_DAMPING);
+ BIND_CONSTANT( PARAM_ANGULAR_MOTION_SOFTNESS);
+ BIND_CONSTANT( PARAM_ANGULAR_MOTION_RESTITUTION);
+ BIND_CONSTANT( PARAM_ANGULAR_MOTION_DAMPING);
+ BIND_CONSTANT( PARAM_ANGULAR_ORTHOGONAL_SOFTNESS);
+ BIND_CONSTANT( PARAM_ANGULAR_ORTHOGONAL_RESTITUTION);
+ BIND_CONSTANT( PARAM_ANGULAR_ORTHOGONAL_DAMPING);
+
+ BIND_CONSTANT( PARAM_MAX);
+}
+
+void SliderJoint::set_param(Param p_param,float p_value){
+
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ params[p_param]=p_value;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(get_joint(),PhysicsServer::SliderJointParam(p_param),p_value);
+ update_gizmo();
+
+}
+float SliderJoint::get_param(Param p_param) const{
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return params[p_param];
+}
+
+
+RID SliderJoint::_configure_joint(PhysicsBody *body_a,PhysicsBody *body_b) {
+
+
+ Transform gt = get_global_transform();
+ Vector3 sliderpos = gt.origin;
+ Vector3 sliderdir = gt.basis.get_axis(2);
+
+ Transform ainv = body_a->get_global_transform().affine_inverse();
+
+ Transform local_a = ainv * gt;
+ local_a.orthonormalize();
+ Transform local_b = gt;
+
+ if (body_b) {
+ Transform binv = body_b->get_global_transform().affine_inverse();
+ local_b = binv * gt;
+ }
+
+ local_b.orthonormalize();
+
+ RID j = PhysicsServer::get_singleton()->joint_create_slider(body_a->get_rid(),local_a,body_b?body_b->get_rid():RID(),local_b);
+ for(int i=0;i<PARAM_MAX;i++) {
+ PhysicsServer::get_singleton()->slider_joint_set_param(j,PhysicsServer::SliderJointParam(i),params[i]);
+ }
+
+ return j;
+}
+
+
+SliderJoint::SliderJoint() {
+
+
+
+ params[ PARAM_LINEAR_LIMIT_UPPER ]=1.0;
+ params[ PARAM_LINEAR_LIMIT_LOWER ]=-1.0;
+ params[ PARAM_LINEAR_LIMIT_SOFTNESS ]=1.0;
+ params[ PARAM_LINEAR_LIMIT_RESTITUTION]=0.7;
+ params[ PARAM_LINEAR_LIMIT_DAMPING]=1.0;
+ params[ PARAM_LINEAR_MOTION_SOFTNESS ]=1.0;
+ params[ PARAM_LINEAR_MOTION_RESTITUTION]=0.7;
+ params[ PARAM_LINEAR_MOTION_DAMPING]=0;//1.0;
+ params[ PARAM_LINEAR_ORTHOGONAL_SOFTNESS ]=1.0;
+ params[ PARAM_LINEAR_ORTHOGONAL_RESTITUTION]=0.7;
+ params[ PARAM_LINEAR_ORTHOGONAL_DAMPING]=1.0;
+
+ params[ PARAM_ANGULAR_LIMIT_UPPER ]=0 ;
+ params[ PARAM_ANGULAR_LIMIT_LOWER ]=0 ;
+ params[ PARAM_ANGULAR_LIMIT_SOFTNESS ]=1.0;
+ params[ PARAM_ANGULAR_LIMIT_RESTITUTION]=0.7;
+ params[ PARAM_ANGULAR_LIMIT_DAMPING]=0;//1.0;
+ params[ PARAM_ANGULAR_MOTION_SOFTNESS ]=1.0;
+ params[ PARAM_ANGULAR_MOTION_RESTITUTION]=0.7;
+ params[ PARAM_ANGULAR_MOTION_DAMPING]=1.0;
+ params[ PARAM_ANGULAR_ORTHOGONAL_SOFTNESS ]=1.0;
+ params[ PARAM_ANGULAR_ORTHOGONAL_RESTITUTION]=0.7;
+ params[ PARAM_ANGULAR_ORTHOGONAL_DAMPING]=1.0;
+}
+
+
+
+//////////////////////////////////
+
+
+
+void ConeTwistJoint::_set_swing_span(float p_limit_angular) {
+
+ set_param(PARAM_SWING_SPAN,Math::deg2rad(p_limit_angular));
+}
+
+float ConeTwistJoint::_get_swing_span() const {
+
+ return Math::rad2deg(get_param(PARAM_SWING_SPAN));
+}
+
+void ConeTwistJoint::_set_twist_span(float p_limit_angular) {
+
+ set_param(PARAM_TWIST_SPAN,Math::deg2rad(p_limit_angular));
+
+}
+
+float ConeTwistJoint::_get_twist_span() const {
+
+ return Math::rad2deg(get_param(PARAM_TWIST_SPAN));
+
+}
+
+
+void ConeTwistJoint::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_param","param","value"),&ConeTwistJoint::set_param);
+ ObjectTypeDB::bind_method(_MD("get_param","param"),&ConeTwistJoint::get_param);
+
+
+ ObjectTypeDB::bind_method(_MD("_set_swing_span","swing_span"),&ConeTwistJoint::_set_swing_span);
+ ObjectTypeDB::bind_method(_MD("_get_swing_span"),&ConeTwistJoint::_get_swing_span);
+
+ ObjectTypeDB::bind_method(_MD("_set_twist_span","twist_span"),&ConeTwistJoint::_set_twist_span);
+ ObjectTypeDB::bind_method(_MD("_get_twist_span"),&ConeTwistJoint::_get_twist_span);
+
+
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"swing_span",PROPERTY_HINT_RANGE,"-180,180,0.1"),_SCS("_set_swing_span"),_SCS("_get_swing_span") );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"twist_span",PROPERTY_HINT_RANGE,"-40000,40000,0.1"),_SCS("_set_twist_span"),_SCS("_get_twist_span") );
+
+
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"bias",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_BIAS );
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"softness",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_SOFTNESS);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"relaxation",PROPERTY_HINT_RANGE,"0.01,16.0,0.01") ,_SCS("set_param"),_SCS("get_param"), PARAM_RELAXATION);
+
+ BIND_CONSTANT( PARAM_SWING_SPAN );
+ BIND_CONSTANT( PARAM_TWIST_SPAN );
+ BIND_CONSTANT( PARAM_BIAS );
+ BIND_CONSTANT( PARAM_SOFTNESS );
+ BIND_CONSTANT( PARAM_RELAXATION );
+ BIND_CONSTANT( PARAM_MAX );
+}
+
+void ConeTwistJoint::set_param(Param p_param,float p_value){
+
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ params[p_param]=p_value;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(get_joint(),PhysicsServer::ConeTwistJointParam(p_param),p_value);
+
+ update_gizmo();
+}
+float ConeTwistJoint::get_param(Param p_param) const{
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return params[p_param];
+}
+
+
+RID ConeTwistJoint::_configure_joint(PhysicsBody *body_a,PhysicsBody *body_b) {
+
+
+ Transform gt = get_global_transform();
+ //Vector3 cone_twistpos = gt.origin;
+ //Vector3 cone_twistdir = gt.basis.get_axis(2);
+
+ Transform ainv = body_a->get_global_transform().affine_inverse();
+
+ Transform local_a = ainv * gt;
+ local_a.orthonormalize();
+ Transform local_b = gt;
+
+ if (body_b) {
+ Transform binv = body_b->get_global_transform().affine_inverse();
+ local_b = binv * gt;
+ }
+
+ local_b.orthonormalize();
+
+ RID j = PhysicsServer::get_singleton()->joint_create_cone_twist(body_a->get_rid(),local_a,body_b?body_b->get_rid():RID(),local_b);
+ for(int i=0;i<PARAM_MAX;i++) {
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j,PhysicsServer::ConeTwistJointParam(i),params[i]);
+ }
+
+ return j;
+}
+
+
+ConeTwistJoint::ConeTwistJoint() {
+
+
+ params[ PARAM_SWING_SPAN ]=Math_PI*0.25;
+ params[ PARAM_TWIST_SPAN ]=Math_PI;
+ params[ PARAM_BIAS ]=0.3;
+ params[ PARAM_SOFTNESS ]=0.8;
+ params[ PARAM_RELAXATION ]=1.0;
+
+}
+
+/////////////////////////////////////////////////////////////////////
+
+
+void Generic6DOFJoint::_set_angular_hi_limit_x(float p_limit_angular) {
+
+ set_param_x(PARAM_ANGULAR_UPPER_LIMIT,Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint::_get_angular_hi_limit_x() const{
+
+ return Math::rad2deg(get_param_x(PARAM_ANGULAR_UPPER_LIMIT));
+
+}
+
+void Generic6DOFJoint::_set_angular_lo_limit_x(float p_limit_angular) {
+
+ set_param_x(PARAM_ANGULAR_LOWER_LIMIT,Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint::_get_angular_lo_limit_x() const{
+
+ return Math::rad2deg(get_param_x(PARAM_ANGULAR_LOWER_LIMIT));
+
+}
+
+
+void Generic6DOFJoint::_set_angular_hi_limit_y(float p_limit_angular) {
+
+ set_param_y(PARAM_ANGULAR_UPPER_LIMIT,Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint::_get_angular_hi_limit_y() const{
+
+ return Math::rad2deg(get_param_y(PARAM_ANGULAR_UPPER_LIMIT));
+
+}
+
+void Generic6DOFJoint::_set_angular_lo_limit_y(float p_limit_angular) {
+
+ set_param_y(PARAM_ANGULAR_LOWER_LIMIT,Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint::_get_angular_lo_limit_y() const{
+
+ return Math::rad2deg(get_param_y(PARAM_ANGULAR_LOWER_LIMIT));
+
+}
+
+
+void Generic6DOFJoint::_set_angular_hi_limit_z(float p_limit_angular) {
+
+ set_param_z(PARAM_ANGULAR_UPPER_LIMIT,Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint::_get_angular_hi_limit_z() const{
+
+ return Math::rad2deg(get_param_z(PARAM_ANGULAR_UPPER_LIMIT));
+
+}
+
+void Generic6DOFJoint::_set_angular_lo_limit_z(float p_limit_angular) {
+
+ set_param_z(PARAM_ANGULAR_LOWER_LIMIT,Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint::_get_angular_lo_limit_z() const{
+
+ return Math::rad2deg(get_param_z(PARAM_ANGULAR_LOWER_LIMIT));
+
+}
+
+
+
+void Generic6DOFJoint::_bind_methods(){
+
+
+ ObjectTypeDB::bind_method(_MD("_set_angular_hi_limit_x","angle"),&Generic6DOFJoint::_set_angular_hi_limit_x);
+ ObjectTypeDB::bind_method(_MD("_get_angular_hi_limit_x"),&Generic6DOFJoint::_get_angular_hi_limit_x);
+
+ ObjectTypeDB::bind_method(_MD("_set_angular_lo_limit_x","angle"),&Generic6DOFJoint::_set_angular_lo_limit_x);
+ ObjectTypeDB::bind_method(_MD("_get_angular_lo_limit_x"),&Generic6DOFJoint::_get_angular_lo_limit_x);
+
+ ObjectTypeDB::bind_method(_MD("_set_angular_hi_limit_y","angle"),&Generic6DOFJoint::_set_angular_hi_limit_y);
+ ObjectTypeDB::bind_method(_MD("_get_angular_hi_limit_y"),&Generic6DOFJoint::_get_angular_hi_limit_y);
+
+ ObjectTypeDB::bind_method(_MD("_set_angular_lo_limit_y","angle"),&Generic6DOFJoint::_set_angular_lo_limit_y);
+ ObjectTypeDB::bind_method(_MD("_get_angular_lo_limit_y"),&Generic6DOFJoint::_get_angular_lo_limit_y);
+
+ ObjectTypeDB::bind_method(_MD("_set_angular_hi_limit_z","angle"),&Generic6DOFJoint::_set_angular_hi_limit_z);
+ ObjectTypeDB::bind_method(_MD("_get_angular_hi_limit_z"),&Generic6DOFJoint::_get_angular_hi_limit_z);
+
+ ObjectTypeDB::bind_method(_MD("_set_angular_lo_limit_z","angle"),&Generic6DOFJoint::_set_angular_lo_limit_z);
+ ObjectTypeDB::bind_method(_MD("_get_angular_lo_limit_z"),&Generic6DOFJoint::_get_angular_lo_limit_z);
+
+ ObjectTypeDB::bind_method(_MD("set_param_x","param","value"),&Generic6DOFJoint::set_param_x);
+ ObjectTypeDB::bind_method(_MD("get_param_x","param"),&Generic6DOFJoint::get_param_x);
+
+ ObjectTypeDB::bind_method(_MD("set_param_y","param","value"),&Generic6DOFJoint::set_param_y);
+ ObjectTypeDB::bind_method(_MD("get_param_y","param"),&Generic6DOFJoint::get_param_y);
+
+ ObjectTypeDB::bind_method(_MD("set_param_z","param","value"),&Generic6DOFJoint::set_param_z);
+ ObjectTypeDB::bind_method(_MD("get_param_z","param"),&Generic6DOFJoint::get_param_z);
+
+ ObjectTypeDB::bind_method(_MD("set_flag_x","flag","value"),&Generic6DOFJoint::set_flag_x);
+ ObjectTypeDB::bind_method(_MD("get_flag_x","flag"),&Generic6DOFJoint::get_flag_x);
+
+ ObjectTypeDB::bind_method(_MD("set_flag_y","flag","value"),&Generic6DOFJoint::set_flag_y);
+ ObjectTypeDB::bind_method(_MD("get_flag_y","flag"),&Generic6DOFJoint::get_flag_y);
+
+ ObjectTypeDB::bind_method(_MD("set_flag_z","flag","value"),&Generic6DOFJoint::set_flag_z);
+ ObjectTypeDB::bind_method(_MD("get_flag_z","flag"),&Generic6DOFJoint::get_flag_z);
+
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"linear_limit_x/enabled"),_SCS("set_flag_x"),_SCS("get_flag_x"),FLAG_ENABLE_LINEAR_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_x/upper_distance"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_LINEAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_x/lower_distance"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_LINEAR_LOWER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_x/softness",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_x/restitution",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_LINEAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_x/damping",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"angular_limit_x/enabled"),_SCS("set_flag_x"),_SCS("get_flag_x"),FLAG_ENABLE_ANGULAR_LIMIT);
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"angular_limit_x/upper_angle",PROPERTY_HINT_RANGE,"-180,180,0.01"),_SCS("_set_angular_hi_limit_x"),_SCS("_get_angular_hi_limit_x"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"angular_limit_x/lower_angle",PROPERTY_HINT_RANGE,"-180,180,0.01"),_SCS("_set_angular_lo_limit_x"),_SCS("_get_angular_lo_limit_x"));
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_x/softness",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_ANGULAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_x/restitution",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_ANGULAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_x/damping",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_ANGULAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_x/force_limit"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_ANGULAR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_x/erp"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_ANGULAR_ERP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"angular_motor_x/enabled"),_SCS("set_flag_x"),_SCS("get_flag_x"),FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_motor_x/target_velocity"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_motor_x/force_limit"),_SCS("set_param_x"),_SCS("get_param_x"),PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"linear_limit_y/enabled"),_SCS("set_flag_y"),_SCS("get_flag_y"),FLAG_ENABLE_LINEAR_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_y/upper_distance"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_LINEAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_y/lower_distance"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_LINEAR_LOWER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_y/softness",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_y/restitution",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_LINEAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_y/damping",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"angular_limit_y/enabled"),_SCS("set_flag_y"),_SCS("get_flag_y"),FLAG_ENABLE_ANGULAR_LIMIT);
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"angular_limit_y/upper_angle",PROPERTY_HINT_RANGE,"-180,180,0.01"),_SCS("_set_angular_hi_limit_y"),_SCS("_get_angular_hi_limit_y"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"angular_limit_y/lower_angle",PROPERTY_HINT_RANGE,"-180,180,0.01"),_SCS("_set_angular_lo_limit_y"),_SCS("_get_angular_lo_limit_y"));
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_y/softness",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_ANGULAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_y/restitution",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_ANGULAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_y/damping",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_ANGULAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_y/force_limit"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_ANGULAR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_y/erp"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_ANGULAR_ERP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"angular_motor_y/enabled"),_SCS("set_flag_y"),_SCS("get_flag_y"),FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_motor_y/target_velocity"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_motor_y/force_limit"),_SCS("set_param_y"),_SCS("get_param_y"),PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"linear_limit_z/enabled"),_SCS("set_flag_z"),_SCS("get_flag_z"),FLAG_ENABLE_LINEAR_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_z/upper_distance"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_LINEAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_z/lower_distance"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_LINEAR_LOWER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_z/softness",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_z/restitution",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_LINEAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"linear_limit_z/damping",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"angular_limit_z/enabled"),_SCS("set_flag_z"),_SCS("get_flag_z"),FLAG_ENABLE_ANGULAR_LIMIT);
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"angular_limit_z/upper_angle",PROPERTY_HINT_RANGE,"-180,180,0.01"),_SCS("_set_angular_hi_limit_z"),_SCS("_get_angular_hi_limit_z"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"angular_limit_z/lower_angle",PROPERTY_HINT_RANGE,"-180,180,0.01"),_SCS("_set_angular_lo_limit_z"),_SCS("_get_angular_lo_limit_z"));
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_z/softness",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_ANGULAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_z/restitution",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_ANGULAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_z/damping",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_ANGULAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_z/force_limit"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_ANGULAR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_limit_z/erp"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_ANGULAR_ERP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"angular_motor_z/enabled"),_SCS("set_flag_z"),_SCS("get_flag_z"),FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_motor_z/target_velocity"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"angular_motor_z/force_limit"),_SCS("set_param_z"),_SCS("get_param_z"),PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+
+
+ BIND_CONSTANT( PARAM_LINEAR_LOWER_LIMIT);
+ BIND_CONSTANT( PARAM_LINEAR_UPPER_LIMIT);
+ BIND_CONSTANT( PARAM_LINEAR_LIMIT_SOFTNESS);
+ BIND_CONSTANT( PARAM_LINEAR_RESTITUTION);
+ BIND_CONSTANT( PARAM_LINEAR_DAMPING);
+ BIND_CONSTANT( PARAM_ANGULAR_LOWER_LIMIT);
+ BIND_CONSTANT( PARAM_ANGULAR_UPPER_LIMIT);
+ BIND_CONSTANT( PARAM_ANGULAR_LIMIT_SOFTNESS);
+ BIND_CONSTANT( PARAM_ANGULAR_DAMPING);
+ BIND_CONSTANT( PARAM_ANGULAR_RESTITUTION);
+ BIND_CONSTANT( PARAM_ANGULAR_FORCE_LIMIT);
+ BIND_CONSTANT( PARAM_ANGULAR_ERP);
+ BIND_CONSTANT( PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ BIND_CONSTANT( PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+ BIND_CONSTANT( PARAM_MAX);
+
+ BIND_CONSTANT( FLAG_ENABLE_LINEAR_LIMIT);
+ BIND_CONSTANT( FLAG_ENABLE_ANGULAR_LIMIT);
+ BIND_CONSTANT( FLAG_ENABLE_MOTOR);
+ BIND_CONSTANT( FLAG_MAX );
+}
+
+
+void Generic6DOFJoint::set_param_x(Param p_param,float p_value){
+
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ params_x[p_param]=p_value;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(get_joint(),Vector3::AXIS_X,PhysicsServer::G6DOFJointAxisParam(p_param),p_value);
+
+ update_gizmo();
+}
+float Generic6DOFJoint::get_param_x(Param p_param) const{
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return params_x[p_param];
+}
+
+void Generic6DOFJoint::set_param_y(Param p_param,float p_value){
+
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ params_y[p_param]=p_value;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(get_joint(),Vector3::AXIS_Y,PhysicsServer::G6DOFJointAxisParam(p_param),p_value);
+ update_gizmo();
+
+}
+float Generic6DOFJoint::get_param_y(Param p_param) const{
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return params_y[p_param];
+}
+
+
+void Generic6DOFJoint::set_param_z(Param p_param,float p_value){
+
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ params_z[p_param]=p_value;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(get_joint(),Vector3::AXIS_Z,PhysicsServer::G6DOFJointAxisParam(p_param),p_value);
+ update_gizmo();
+}
+float Generic6DOFJoint::get_param_z(Param p_param) const{
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return params_z[p_param];
+}
+
+
+void Generic6DOFJoint::set_flag_x(Flag p_flag,bool p_enabled){
+
+ ERR_FAIL_INDEX(p_flag,FLAG_MAX);
+ flags_x[p_flag]=p_enabled;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(get_joint(),Vector3::AXIS_X,PhysicsServer::G6DOFJointAxisFlag(p_flag),p_enabled);
+ update_gizmo();
+
+}
+bool Generic6DOFJoint::get_flag_x(Flag p_flag) const{
+
+ ERR_FAIL_INDEX_V(p_flag,FLAG_MAX,false);
+ return flags_x[p_flag];
+
+}
+
+void Generic6DOFJoint::set_flag_y(Flag p_flag,bool p_enabled){
+
+ ERR_FAIL_INDEX(p_flag,FLAG_MAX);
+ flags_y[p_flag]=p_enabled;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(get_joint(),Vector3::AXIS_Y,PhysicsServer::G6DOFJointAxisFlag(p_flag),p_enabled);
+ update_gizmo();
+}
+bool Generic6DOFJoint::get_flag_y(Flag p_flag) const{
+
+ ERR_FAIL_INDEX_V(p_flag,FLAG_MAX,false);
+ return flags_y[p_flag];
+
+}
+
+void Generic6DOFJoint::set_flag_z(Flag p_flag,bool p_enabled){
+
+ ERR_FAIL_INDEX(p_flag,FLAG_MAX);
+ flags_z[p_flag]=p_enabled;
+ if (get_joint().is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(get_joint(),Vector3::AXIS_Z,PhysicsServer::G6DOFJointAxisFlag(p_flag),p_enabled);
+ update_gizmo();
+}
+bool Generic6DOFJoint::get_flag_z(Flag p_flag) const{
+
+ ERR_FAIL_INDEX_V(p_flag,FLAG_MAX,false);
+ return flags_z[p_flag];
+
+}
+
+RID Generic6DOFJoint::_configure_joint(PhysicsBody *body_a,PhysicsBody *body_b) {
+
+
+ Transform gt = get_global_transform();
+ //Vector3 cone_twistpos = gt.origin;
+ //Vector3 cone_twistdir = gt.basis.get_axis(2);
+
+ Transform ainv = body_a->get_global_transform().affine_inverse();
+
+ Transform local_a = ainv * gt;
+ local_a.orthonormalize();
+ Transform local_b = gt;
+
+ if (body_b) {
+ Transform binv = body_b->get_global_transform().affine_inverse();
+ local_b = binv * gt;
+ }
+
+ local_b.orthonormalize();
+
+ RID j = PhysicsServer::get_singleton()->joint_create_generic_6dof(body_a->get_rid(),local_a,body_b?body_b->get_rid():RID(),local_b);
+ for(int i=0;i<PARAM_MAX;i++) {
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j,Vector3::AXIS_X,PhysicsServer::G6DOFJointAxisParam(i),params_x[i]);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j,Vector3::AXIS_Y,PhysicsServer::G6DOFJointAxisParam(i),params_y[i]);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j,Vector3::AXIS_Z,PhysicsServer::G6DOFJointAxisParam(i),params_z[i]);
+ }
+ for(int i=0;i<FLAG_MAX;i++) {
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j,Vector3::AXIS_X,PhysicsServer::G6DOFJointAxisFlag(i),flags_x[i]);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j,Vector3::AXIS_Y,PhysicsServer::G6DOFJointAxisFlag(i),flags_y[i]);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j,Vector3::AXIS_Z,PhysicsServer::G6DOFJointAxisFlag(i),flags_z[i]);
+ }
+
+ return j;
+}
+
+
+Generic6DOFJoint::Generic6DOFJoint() {
+
+ set_param_x( PARAM_LINEAR_LOWER_LIMIT,0);
+ set_param_x( PARAM_LINEAR_UPPER_LIMIT,0);
+ set_param_x( PARAM_LINEAR_LIMIT_SOFTNESS,0.7);
+ set_param_x( PARAM_LINEAR_RESTITUTION,0.5);
+ set_param_x( PARAM_LINEAR_DAMPING,1.0);
+ set_param_x( PARAM_ANGULAR_LOWER_LIMIT,0);
+ set_param_x( PARAM_ANGULAR_UPPER_LIMIT,0);
+ set_param_x( PARAM_ANGULAR_LIMIT_SOFTNESS,0.5f);
+ set_param_x( PARAM_ANGULAR_DAMPING,1.0f);
+ set_param_x( PARAM_ANGULAR_RESTITUTION,0);
+ set_param_x( PARAM_ANGULAR_FORCE_LIMIT,0);
+ set_param_x( PARAM_ANGULAR_ERP,0.5);
+ set_param_x( PARAM_ANGULAR_MOTOR_TARGET_VELOCITY,0);
+ set_param_x( PARAM_ANGULAR_MOTOR_FORCE_LIMIT,300);
+
+ set_flag_x( FLAG_ENABLE_ANGULAR_LIMIT,true);
+ set_flag_x( FLAG_ENABLE_LINEAR_LIMIT,true);
+ set_flag_x( FLAG_ENABLE_MOTOR,false);
+
+ set_param_y( PARAM_LINEAR_LOWER_LIMIT,0);
+ set_param_y( PARAM_LINEAR_UPPER_LIMIT,0);
+ set_param_y( PARAM_LINEAR_LIMIT_SOFTNESS,0.7);
+ set_param_y( PARAM_LINEAR_RESTITUTION,0.5);
+ set_param_y( PARAM_LINEAR_DAMPING,1.0);
+ set_param_y( PARAM_ANGULAR_LOWER_LIMIT,0);
+ set_param_y( PARAM_ANGULAR_UPPER_LIMIT,0);
+ set_param_y( PARAM_ANGULAR_LIMIT_SOFTNESS,0.5f);
+ set_param_y( PARAM_ANGULAR_DAMPING,1.0f);
+ set_param_y( PARAM_ANGULAR_RESTITUTION,0);
+ set_param_y( PARAM_ANGULAR_FORCE_LIMIT,0);
+ set_param_y( PARAM_ANGULAR_ERP,0.5);
+ set_param_y( PARAM_ANGULAR_MOTOR_TARGET_VELOCITY,0);
+ set_param_y( PARAM_ANGULAR_MOTOR_FORCE_LIMIT,300);
+
+ set_flag_y( FLAG_ENABLE_ANGULAR_LIMIT,true);
+ set_flag_y( FLAG_ENABLE_LINEAR_LIMIT,true);
+ set_flag_y( FLAG_ENABLE_MOTOR,false);
+
+
+ set_param_z( PARAM_LINEAR_LOWER_LIMIT,0);
+ set_param_z( PARAM_LINEAR_UPPER_LIMIT,0);
+ set_param_z( PARAM_LINEAR_LIMIT_SOFTNESS,0.7);
+ set_param_z( PARAM_LINEAR_RESTITUTION,0.5);
+ set_param_z( PARAM_LINEAR_DAMPING,1.0);
+ set_param_z( PARAM_ANGULAR_LOWER_LIMIT,0);
+ set_param_z( PARAM_ANGULAR_UPPER_LIMIT,0);
+ set_param_z( PARAM_ANGULAR_LIMIT_SOFTNESS,0.5f);
+ set_param_z( PARAM_ANGULAR_DAMPING,1.0f);
+ set_param_z( PARAM_ANGULAR_RESTITUTION,0);
+ set_param_z( PARAM_ANGULAR_FORCE_LIMIT,0);
+ set_param_z( PARAM_ANGULAR_ERP,0.5);
+ set_param_z( PARAM_ANGULAR_MOTOR_TARGET_VELOCITY,0);
+ set_param_z( PARAM_ANGULAR_MOTOR_FORCE_LIMIT,300);
+
+ set_flag_z( FLAG_ENABLE_ANGULAR_LIMIT,true);
+ set_flag_z( FLAG_ENABLE_LINEAR_LIMIT,true);
+ set_flag_z( FLAG_ENABLE_MOTOR,false);
+
+}
+
+
+
+
#if 0
void PhysicsJoint::_set(const String& p_name, const Variant& p_value) {
diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h
index 4a0c609e69..3f5a0e91a6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,6 +32,322 @@
#include "scene/3d/spatial.h"
#include "scene/3d/physics_body.h"
+
+class Joint : public Spatial {
+
+ OBJ_TYPE(Joint,Spatial);
+
+ RID ba,bb;
+
+ RID joint;
+
+ NodePath a;
+ NodePath b;
+
+ int solver_priority;
+ bool exclude_from_collision;
+
+
+protected:
+
+ void _update_joint(bool p_only_free=false);
+
+ void _notification(int p_what);
+
+ virtual RID _configure_joint(PhysicsBody *body_a,PhysicsBody *body_b)=0;
+
+ static void _bind_methods();
+public:
+
+ void set_node_a(const NodePath& p_node_a);
+ NodePath get_node_a() const;
+
+ void set_node_b(const NodePath& p_node_b);
+ NodePath get_node_b() const;
+
+ 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();
+
+};
+
+///////////////////////////////////////////
+
+
+class PinJoint : public Joint {
+
+ OBJ_TYPE(PinJoint,Joint);
+public:
+
+ enum Param {
+ PARAM_BIAS=PhysicsServer::PIN_JOINT_BIAS,
+ PARAM_DAMPING=PhysicsServer::PIN_JOINT_DAMPING,
+ PARAM_IMPULSE_CLAMP=PhysicsServer::PIN_JOINT_IMPULSE_CLAMP
+ };
+
+protected:
+
+ float params[3];
+ virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
+ static void _bind_methods();
+public:
+
+ void set_param(Param p_param,float p_value);
+ float get_param(Param p_param) const;
+
+ PinJoint();
+};
+
+VARIANT_ENUM_CAST(PinJoint::Param);
+
+
+class HingeJoint : public Joint {
+
+ OBJ_TYPE(HingeJoint,Joint);
+public:
+
+ enum Param {
+ PARAM_BIAS=PhysicsServer::HINGE_JOINT_BIAS,
+ PARAM_LIMIT_UPPER=PhysicsServer::HINGE_JOINT_LIMIT_UPPER,
+ PARAM_LIMIT_LOWER=PhysicsServer::HINGE_JOINT_LIMIT_LOWER,
+ PARAM_LIMIT_BIAS=PhysicsServer::HINGE_JOINT_LIMIT_BIAS,
+ PARAM_LIMIT_SOFTNESS=PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS,
+ PARAM_LIMIT_RELAXATION=PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION,
+ PARAM_MOTOR_TARGET_VELOCITY=PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY,
+ PARAM_MOTOR_MAX_IMPULSE=PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE,
+ PARAM_MAX=PhysicsServer::HINGE_JOINT_MAX
+ };
+
+ enum Flag {
+ FLAG_USE_LIMIT=PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT,
+ FLAG_ENABLE_MOTOR=PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR,
+ FLAG_MAX=PhysicsServer::HINGE_JOINT_FLAG_MAX
+ };
+
+
+
+protected:
+
+ float params[PARAM_MAX];
+ bool flags[FLAG_MAX];
+ virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
+ static void _bind_methods();
+
+ void _set_upper_limit(float p_limit);
+ float _get_upper_limit() const;
+
+ void _set_lower_limit(float p_limit);
+ float _get_lower_limit() const;
+
+public:
+
+ void set_param(Param p_param,float p_value);
+ float get_param(Param p_param) const;
+
+ void set_flag(Flag p_flag,bool p_value);
+ bool get_flag(Flag p_flag) const;
+
+ HingeJoint();
+};
+
+VARIANT_ENUM_CAST(HingeJoint::Param);
+VARIANT_ENUM_CAST(HingeJoint::Flag);
+
+
+class SliderJoint : public Joint {
+
+ OBJ_TYPE(SliderJoint,Joint);
+public:
+
+ enum Param {
+ PARAM_LINEAR_LIMIT_UPPER=PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER,
+ PARAM_LINEAR_LIMIT_LOWER=PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER,
+ PARAM_LINEAR_LIMIT_SOFTNESS=PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS,
+ PARAM_LINEAR_LIMIT_RESTITUTION=PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION,
+ PARAM_LINEAR_LIMIT_DAMPING=PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING,
+ PARAM_LINEAR_MOTION_SOFTNESS=PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS,
+ PARAM_LINEAR_MOTION_RESTITUTION=PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION,
+ PARAM_LINEAR_MOTION_DAMPING=PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING,
+ PARAM_LINEAR_ORTHOGONAL_SOFTNESS=PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS,
+ PARAM_LINEAR_ORTHOGONAL_RESTITUTION=PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION,
+ PARAM_LINEAR_ORTHOGONAL_DAMPING=PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING,
+
+ PARAM_ANGULAR_LIMIT_UPPER=PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER,
+ PARAM_ANGULAR_LIMIT_LOWER=PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER,
+ PARAM_ANGULAR_LIMIT_SOFTNESS=PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS,
+ PARAM_ANGULAR_LIMIT_RESTITUTION=PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION,
+ PARAM_ANGULAR_LIMIT_DAMPING=PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING,
+ PARAM_ANGULAR_MOTION_SOFTNESS=PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS,
+ PARAM_ANGULAR_MOTION_RESTITUTION=PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION,
+ PARAM_ANGULAR_MOTION_DAMPING=PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING,
+ PARAM_ANGULAR_ORTHOGONAL_SOFTNESS=PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS,
+ PARAM_ANGULAR_ORTHOGONAL_RESTITUTION=PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION,
+ PARAM_ANGULAR_ORTHOGONAL_DAMPING=PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING,
+ PARAM_MAX=PhysicsServer::SLIDER_JOINT_MAX
+
+ };
+
+protected:
+
+
+
+ void _set_upper_limit_angular(float p_limit_angular);
+ float _get_upper_limit_angular() const;
+
+ void _set_lower_limit_angular(float p_limit_angular);
+ float _get_lower_limit_angular() const;
+
+ float params[PARAM_MAX];
+ virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
+ static void _bind_methods();
+public:
+
+ void set_param(Param p_param,float p_value);
+ float get_param(Param p_param) const;
+
+ SliderJoint();
+};
+
+
+VARIANT_ENUM_CAST(SliderJoint::Param);
+
+
+
+
+class ConeTwistJoint : public Joint {
+
+ OBJ_TYPE(ConeTwistJoint,Joint);
+public:
+
+ enum Param {
+
+ PARAM_SWING_SPAN,
+ PARAM_TWIST_SPAN,
+ PARAM_BIAS,
+ PARAM_SOFTNESS,
+ PARAM_RELAXATION,
+ PARAM_MAX
+ };
+
+protected:
+
+
+ void _set_swing_span(float p_limit_angular);
+ float _get_swing_span() const;
+
+ void _set_twist_span(float p_limit_angular);
+ float _get_twist_span() const;
+
+ float params[PARAM_MAX];
+ virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
+ static void _bind_methods();
+public:
+
+ void set_param(Param p_param,float p_value);
+ float get_param(Param p_param) const;
+
+ ConeTwistJoint();
+};
+
+
+VARIANT_ENUM_CAST(ConeTwistJoint::Param);
+
+
+class Generic6DOFJoint : public Joint {
+
+ OBJ_TYPE(Generic6DOFJoint,Joint);
+public:
+
+ enum Param {
+
+ PARAM_LINEAR_LOWER_LIMIT=PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT,
+ PARAM_LINEAR_UPPER_LIMIT=PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT,
+ PARAM_LINEAR_LIMIT_SOFTNESS=PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
+ PARAM_LINEAR_RESTITUTION=PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION,
+ PARAM_LINEAR_DAMPING=PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING,
+ PARAM_ANGULAR_LOWER_LIMIT=PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
+ PARAM_ANGULAR_UPPER_LIMIT=PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
+ PARAM_ANGULAR_LIMIT_SOFTNESS=PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
+ PARAM_ANGULAR_DAMPING=PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING,
+ PARAM_ANGULAR_RESTITUTION=PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION,
+ PARAM_ANGULAR_FORCE_LIMIT=PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT,
+ PARAM_ANGULAR_ERP=PhysicsServer::G6DOF_JOINT_ANGULAR_ERP,
+ PARAM_ANGULAR_MOTOR_TARGET_VELOCITY=PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY,
+ PARAM_ANGULAR_MOTOR_FORCE_LIMIT=PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT,
+ PARAM_MAX=PhysicsServer::G6DOF_JOINT_MAX,
+ };
+
+ enum Flag {
+ FLAG_ENABLE_LINEAR_LIMIT=PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
+ FLAG_ENABLE_ANGULAR_LIMIT=PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
+ FLAG_ENABLE_MOTOR=PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR,
+ FLAG_MAX=PhysicsServer::G6DOF_JOINT_FLAG_MAX
+ };
+
+
+protected:
+
+
+ void _set_angular_hi_limit_x(float p_limit_angular);
+ float _get_angular_hi_limit_x() const;
+
+ void _set_angular_hi_limit_y(float p_limit_angular);
+ float _get_angular_hi_limit_y() const;
+
+ void _set_angular_hi_limit_z(float p_limit_angular);
+ float _get_angular_hi_limit_z() const;
+
+ void _set_angular_lo_limit_x(float p_limit_angular);
+ float _get_angular_lo_limit_x() const;
+
+ void _set_angular_lo_limit_y(float p_limit_angular);
+ float _get_angular_lo_limit_y() const;
+
+ void _set_angular_lo_limit_z(float p_limit_angular);
+ float _get_angular_lo_limit_z() const;
+
+ float params_x[PARAM_MAX];
+ bool flags_x[FLAG_MAX];
+ float params_y[PARAM_MAX];
+ bool flags_y[FLAG_MAX];
+ float params_z[PARAM_MAX];
+ bool flags_z[FLAG_MAX];
+
+ virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
+ static void _bind_methods();
+public:
+
+ void set_param_x(Param p_param,float p_value);
+ float get_param_x(Param p_param) const;
+
+ void set_param_y(Param p_param,float p_value);
+ float get_param_y(Param p_param) const;
+
+ void set_param_z(Param p_param,float p_value);
+ float get_param_z(Param p_param) const;
+
+ void set_flag_x(Flag p_flag,bool p_enabled);
+ bool get_flag_x(Flag p_flag) const;
+
+ void set_flag_y(Flag p_flag,bool p_enabled);
+ bool get_flag_y(Flag p_flag) const;
+
+ void set_flag_z(Flag p_flag,bool p_enabled);
+ bool get_flag_z(Flag p_flag) const;
+
+ Generic6DOFJoint();
+};
+
+
+VARIANT_ENUM_CAST(Generic6DOFJoint::Param);
+VARIANT_ENUM_CAST(Generic6DOFJoint::Flag);
+
+
#if 0
class PhysicsJoint : public Spatial {
diff --git a/scene/3d/portal.cpp b/scene/3d/portal.cpp
index fe627c2cc0..34499578aa 100644
--- a/scene/3d/portal.cpp
+++ b/scene/3d/portal.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/portal.h b/scene/3d/portal.h
index 6905724499..14c1275312 100644
--- a/scene/3d/portal.h
+++ b/scene/3d/portal.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/position_3d.cpp b/scene/3d/position_3d.cpp
index 19bf1c4e1d..d692c0f249 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/position_3d.h b/scene/3d/position_3d.h
index 468b9aafeb..265c0b48c7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp
index b3378c7698..334246b033 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -119,7 +119,7 @@ void ProximityGroup::_notification(int what) {
switch (what) {
- case NOTIFICATION_EXIT_SCENE:
+ case NOTIFICATION_EXIT_TREE:
++group_version;
clear_groups();
break;
@@ -135,7 +135,7 @@ void ProximityGroup::broadcast(String p_name, Variant p_params) {
E = groups.front();
while (E) {
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params);
+ get_tree()->call_group(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params);
E = E->next();
};
diff --git a/scene/3d/proximity_group.h b/scene/3d/proximity_group.h
index c8660c17dd..35e3f3dd98 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/quad.cpp b/scene/3d/quad.cpp
index 78dd56141c..43bde8dc61 100644
--- a/scene/3d/quad.cpp
+++ b/scene/3d/quad.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,7 @@
void Quad::_update() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
Vector3 normal;
@@ -171,14 +171,14 @@ void Quad::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
if (pending_update)
_update();
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
pending_update=true;
diff --git a/scene/3d/quad.h b/scene/3d/quad.h
index 4870b988f2..5ef4af8b81 100644
--- a/scene/3d/quad.h
+++ b/scene/3d/quad.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
index e36e2da14f..5f2c8e0ba3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,7 +33,7 @@
void RayCast::set_cast_to(const Vector3& p_point) {
cast_to=p_point;
- if (is_inside_scene() && get_scene()->is_editor_hint())
+ if (is_inside_tree() && get_tree()->is_editor_hint())
update_gizmo();
}
@@ -72,7 +72,7 @@ Vector3 RayCast::get_collision_normal() const{
void RayCast::set_enabled(bool p_enabled) {
enabled=p_enabled;
- if (is_inside_scene() && !get_scene()->is_editor_hint())
+ if (is_inside_tree() && !get_tree()->is_editor_hint())
set_fixed_process(p_enabled);
if (!p_enabled)
collided=false;
@@ -91,35 +91,22 @@ void RayCast::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
- if (enabled && !get_scene()->is_editor_hint()) {
+ if (enabled && !get_tree()->is_editor_hint()) {
set_fixed_process(true);
- Node *p = get_parent();
- while( p && p->cast_to<Spatial>() ) {
-
- CollisionObject *co = p->cast_to<CollisionObject>();
- if (co) {
-
- exception=co->get_rid();
- exceptions.insert(exception);
- }
-
- p=p->get_parent();
- }
} else
set_fixed_process(false);
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (enabled) {
set_fixed_process(false);
}
- exceptions.erase(exception);
} break;
case NOTIFICATION_FIXED_PROCESS: {
@@ -143,7 +130,7 @@ void RayCast::_notification(int p_what) {
PhysicsDirectSpaceState::RayResult rr;
- if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exceptions)) {
+ if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude)) {
collided=true;
against=rr.collider_id;
@@ -160,6 +147,41 @@ void RayCast::_notification(int p_what) {
}
}
+void RayCast::add_exception_rid(const RID& p_rid) {
+
+ exclude.insert(p_rid);
+}
+
+void RayCast::add_exception(const Object* p_object){
+
+ ERR_FAIL_NULL(p_object);
+ CollisionObject *co=((Object*)p_object)->cast_to<CollisionObject>();
+ if (!co)
+ return;
+ add_exception_rid(co->get_rid());
+}
+
+void RayCast::remove_exception_rid(const RID& p_rid) {
+
+ exclude.erase(p_rid);
+}
+
+void RayCast::remove_exception(const Object* p_object){
+
+ ERR_FAIL_NULL(p_object);
+ CollisionObject *co=((Object*)p_object)->cast_to<CollisionObject>();
+ if (!co)
+ return;
+ remove_exception_rid(co->get_rid());
+}
+
+
+void RayCast::clear_exceptions(){
+
+ exclude.clear();
+}
+
+
void RayCast::_bind_methods() {
@@ -176,6 +198,14 @@ void RayCast::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_collision_point"),&RayCast::get_collision_point);
ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast::get_collision_normal);
+ ObjectTypeDB::bind_method(_MD("add_exception_rid","rid"),&RayCast::add_exception_rid);
+ ObjectTypeDB::bind_method(_MD("add_exception","node"),&RayCast::add_exception);
+
+ ObjectTypeDB::bind_method(_MD("remove_exception_rid","rid"),&RayCast::remove_exception_rid);
+ ObjectTypeDB::bind_method(_MD("remove_exception","node"),&RayCast::remove_exception);
+
+ ObjectTypeDB::bind_method(_MD("clear_exceptions"),&RayCast::clear_exceptions);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
}
diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h
index 96606b1628..06e9e31396 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -45,8 +45,7 @@ class RayCast : public Spatial {
Vector3 cast_to;
- RID exception;
- Set<RID> exceptions;
+ Set<RID> exclude;
protected:
@@ -66,6 +65,12 @@ public:
Vector3 get_collision_point() const;
Vector3 get_collision_normal() const;
+ void add_exception_rid(const RID& p_rid);
+ void add_exception(const Object* p_object);
+ void remove_exception_rid(const RID& p_rid);
+ void remove_exception(const Object* p_object);
+ void clear_exceptions();
+
RayCast();
};
diff --git a/scene/3d/room_instance.cpp b/scene/3d/room_instance.cpp
index fa1d3ecf6b..2ae75b8b68 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -147,7 +147,7 @@ void Room::set_room( const Ref<RoomBounds>& p_room ) {
set_base(RID());
}
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
diff --git a/scene/3d/room_instance.h b/scene/3d/room_instance.h
index 1d11630cef..09fccc5ebc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp
index 05546ee4db..59c8b5e0df 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -35,20 +35,35 @@ void WorldEnvironment::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_WORLD) {
- get_world()->set_environment(environment);
+ if (environment.is_valid()) {
+ if (get_world()->get_environment().is_valid()) {
+ WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding.");
+ }
+ get_world()->set_environment(environment);
+ }
+
} else if (p_what==NOTIFICATION_EXIT_WORLD) {
- get_world()->set_environment(Ref<Environment>());
+ if (environment.is_valid() && get_world()->get_environment()==environment)
+ get_world()->set_environment(Ref<Environment>());
}
}
void WorldEnvironment::set_environment(const Ref<Environment>& p_environment) {
+ if (is_inside_world() && environment.is_valid() && get_world()->get_environment()==environment) {
+ get_world()->set_environment(Ref<Environment>());
+ //clean up
+ }
+
+
environment=p_environment;
- if (is_inside_world()) {
+ if (is_inside_world() && environment.is_valid()) {
+ if (get_world()->get_environment().is_valid()) {
+ WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding.");
+ }
get_world()->set_environment(environment);
}
-
}
Ref<Environment> WorldEnvironment::get_environment() const {
diff --git a/scene/3d/scenario_fx.h b/scene/3d/scenario_fx.h
index b8b06ea983..b877cccc19 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index 323bfa4dc4..cb81228dff 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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) {
- if (b.parent>=0) {
-
- b.pose_global=bonesptr[b.parent].pose_global * (b.rest * pose);
+ b.pose_global=bonesptr[b.parent].pose_global * pose;
+ } else {
+
+ 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);
}
}
@@ -237,6 +266,29 @@ Transform Skeleton::get_bone_transform(int p_bone) const {
return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse;
}
+
+void Skeleton::set_bone_global_pose(int p_bone,const Transform& p_pose) {
+
+ ERR_FAIL_INDEX(p_bone,bones.size());
+ if (bones[p_bone].parent==-1) {
+
+ set_bone_pose(p_bone,bones[p_bone].rest_global_inverse * p_pose); //fast
+ } else {
+
+ set_bone_pose(p_bone, bones[p_bone].rest.affine_inverse() * (get_bone_global_pose(bones[p_bone].parent).affine_inverse() * p_pose)); //slow
+
+ }
+
+}
+
+Transform Skeleton::get_bone_global_pose(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone,bones.size(),Transform());
+ if (dirty)
+ const_cast<Skeleton*>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
+ return bones[p_bone].pose_global;
+}
+
RID Skeleton::get_skeleton() const {
return skeleton;
@@ -292,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 );
@@ -381,7 +464,7 @@ void Skeleton::clear_bones() {
void Skeleton::set_bone_pose(int p_bone, const Transform& p_pose) {
ERR_FAIL_INDEX( p_bone, bones.size() );
- ERR_FAIL_COND( !is_inside_scene() );
+ ERR_FAIL_COND( !is_inside_tree() );
bones[p_bone].pose=p_pose;
@@ -419,7 +502,7 @@ void Skeleton::_make_dirty() {
if (dirty)
return;
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
dirty=true;
return;
}
@@ -499,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);
@@ -511,6 +599,9 @@ void Skeleton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_bone_pose","bone_idx"),&Skeleton::get_bone_pose);
ObjectTypeDB::bind_method(_MD("set_bone_pose","bone_idx","pose"),&Skeleton::set_bone_pose);
+ ObjectTypeDB::bind_method(_MD("set_bone_global_pose","bone_idx","pose"),&Skeleton::set_bone_global_pose);
+ ObjectTypeDB::bind_method(_MD("get_bone_global_pose","bone_idx"),&Skeleton::get_bone_global_pose);
+
ObjectTypeDB::bind_method(_MD("get_bone_custom_pose","bone_idx"),&Skeleton::get_bone_custom_pose);
ObjectTypeDB::bind_method(_MD("set_bone_custom_pose","bone_idx","custom_pose"),&Skeleton::set_bone_custom_pose);
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index c95734fbf1..6678722d12 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,11 +112,19 @@ 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);
Transform get_bone_rest(int p_bone) const;
Transform get_bone_transform(int p_bone) const;
+ Transform get_bone_global_pose(int p_bone) const;
+
+ void set_bone_global_pose(int p_bone,const Transform& p_pose);
void set_bone_enabled(int p_bone, bool p_enabled);
bool is_bone_enabled(int p_bone) const;
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index c52503870f..7d48420a83 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -76,7 +76,7 @@ void Spatial::_notify_dirty() {
if (!data.ignore_notification && !xform_change.in_list()) {
- get_scene()->xform_change_list.add(&xform_change);
+ get_tree()->xform_change_list.add(&xform_change);
}
}
@@ -91,7 +91,7 @@ void Spatial::_update_local_transform() const {
}
void Spatial::_propagate_transform_changed(Spatial *p_origin) {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
return;
}
@@ -110,7 +110,7 @@ void Spatial::_propagate_transform_changed(Spatial *p_origin) {
if (!data.ignore_notification && !xform_change.in_list()) {
- get_scene()->xform_change_list.add(&xform_change);
+ get_tree()->xform_change_list.add(&xform_change);
}
data.dirty|=DIRTY_GLOBAL;
@@ -121,7 +121,7 @@ void Spatial::_propagate_transform_changed(Spatial *p_origin) {
void Spatial::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
Node *p = get_parent();
if (p)
@@ -132,7 +132,7 @@ void Spatial::_notification(int p_what) {
else
data.C=NULL;
- if (data.toplevel && !get_scene()->is_editor_hint()) {
+ if (data.toplevel && !get_tree()->is_editor_hint()) {
if (data.parent) {
data.local_transform = data.parent->get_global_transform() * get_transform();
@@ -147,11 +147,11 @@ void Spatial::_notification(int p_what) {
notification(NOTIFICATION_ENTER_WORLD);
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
notification(NOTIFICATION_EXIT_WORLD,true);
if (xform_change.in_list())
- get_scene()->xform_change_list.remove(&xform_change);
+ get_tree()->xform_change_list.remove(&xform_change);
if (data.C)
data.parent->data.children.erase(data.C);
data.parent=NULL;
@@ -177,10 +177,10 @@ void Spatial::_notification(int p_what) {
get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world,NULL,0);
}
#ifdef TOOLS_ENABLED
- if (get_scene()->is_editor_hint()) {
+ if (get_tree()->is_editor_hint()) {
// get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
- get_scene()->call_group(0,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
+ get_tree()->call_group(0,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
if (!data.gizmo_disabled) {
if (data.gizmo.is_valid())
@@ -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);
+ }
+
+
}
@@ -257,7 +262,7 @@ Transform Spatial::get_transform() const {
}
Transform Spatial::get_global_transform() const {
- ERR_FAIL_COND_V(!is_inside_scene(), Transform());
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform());
if (data.dirty & DIRTY_GLOBAL) {
@@ -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);
+ }
}
@@ -438,8 +452,12 @@ Ref<SpatialGizmo> Spatial::get_gizmo() const {
void Spatial::_update_gizmo() {
data.gizmo_dirty=false;
- if (data.gizmo.is_valid())
- data.gizmo->redraw();
+ if (data.gizmo.is_valid()) {
+ if (is_visible())
+ data.gizmo->redraw();
+ else
+ data.gizmo->clear();
+ }
}
@@ -456,7 +474,7 @@ void Spatial::set_as_toplevel(bool p_enabled) {
if (data.toplevel==p_enabled)
return;
- if (is_inside_scene() && !get_scene()->is_editor_hint()) {
+ if (is_inside_tree() && !get_tree()->is_editor_hint()) {
if (p_enabled)
set_transform(get_global_transform());
@@ -506,6 +524,198 @@ Transform Spatial::get_import_transform() const {
#endif
+void Spatial::_propagate_visibility_changed() {
+
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ _change_notify("visibility/visible");
+#ifdef TOOLS_ENABLED
+ if (data.gizmo.is_valid())
+ _update_gizmo();
+#endif
+
+ for (List<Spatial*>::Element*E=data.children.front();E;E=E->next()) {
+
+ Spatial *c=E->get();
+ if (!c || !c->data.visible)
+ continue;
+ c->_propagate_visibility_changed();
+ }
+}
+
+
+void Spatial::show() {
+
+ if (data.visible)
+ return;
+
+ data.visible=true;
+
+ if (!is_inside_tree())
+ return;
+
+ if (!data.parent || is_visible()) {
+
+ _propagate_visibility_changed();
+ }
+}
+
+void Spatial::hide(){
+
+ if (!data.visible)
+ return;
+
+ bool was_visible = is_visible();
+ data.visible=false;
+
+ if (!data.parent || was_visible) {
+
+ _propagate_visibility_changed();
+ }
+
+}
+bool Spatial::is_visible() const{
+
+ const Spatial *s=this;
+
+ while(s) {
+ if (!s->data.visible) {
+ return false;
+ }
+ s=s->data.parent;
+ }
+
+ return true;
+}
+
+
+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)
+ show();
+ else
+ hide();
+}
+
+bool Spatial::_is_visible_() const {
+
+ return !is_hidden();
+}
+
+void Spatial::rotate(const Vector3& p_normal,float p_radians) {
+
+ Transform t =get_transform();
+ t.basis.rotate(p_normal,p_radians);
+ set_transform(t);
+}
+
+void Spatial::rotate_x(float p_radians) {
+
+ Transform t =get_transform();
+ t.basis.rotate(Vector3(1,0,0),p_radians);
+ set_transform(t);
+
+}
+
+void Spatial::rotate_y(float p_radians){
+
+ Transform t =get_transform();
+ t.basis.rotate(Vector3(0,1,0),p_radians);
+ set_transform(t);
+
+}
+void Spatial::rotate_z(float p_radians){
+
+ Transform t =get_transform();
+ t.basis.rotate(Vector3(0,0,1),p_radians);
+ set_transform(t);
+
+}
+
+void Spatial::translate(const Vector3& p_offset){
+
+ Transform t =get_transform();
+ t.translate(p_offset);
+ set_transform(t);
+
+}
+
+void Spatial::scale(const Vector3& p_ratio){
+
+ Transform t =get_transform();
+ t.basis.scale(p_ratio);
+ set_transform(t);
+
+}
+void Spatial::global_rotate(const Vector3& p_normal,float p_radians){
+
+ Matrix3 rotation(p_normal,p_radians);
+ Transform t = get_global_transform();
+ t.basis= rotation * t.basis;
+ set_global_transform(t);
+
+}
+void Spatial::global_translate(const Vector3& p_offset){
+ Transform t = get_global_transform();
+ t.origin+=p_offset;
+ set_global_transform(t);
+
+}
+
+void Spatial::orthonormalize() {
+
+ Transform t = get_transform();
+ t.orthonormalize();
+ set_transform(t);
+
+}
+
+void Spatial::set_identity() {
+
+ set_transform(Transform());
+
+}
+
+
+void Spatial::look_at(const Vector3& p_target, const Vector3& p_up_normal) {
+
+ Transform lookat;
+ lookat.origin=get_global_transform().origin;
+ lookat=lookat.looking_at(p_target,p_up_normal);
+ set_global_transform(lookat);
+}
+
+void Spatial::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal) {
+
+ Transform lookat;
+ lookat.origin=p_pos;
+ lookat=lookat.looking_at(p_target,p_up_normal);
+ set_global_transform(lookat);
+
+}
+
+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() {
ObjectTypeDB::bind_method(_MD("set_transform","local"), &Spatial::set_transform);
@@ -537,9 +747,44 @@ void Spatial::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_gizmo","gizmo:SpatialGizmo"), &Spatial::set_gizmo);
ObjectTypeDB::bind_method(_MD("get_gizmo:SpatialGizmo"), &Spatial::get_gizmo);
+ ObjectTypeDB::bind_method(_MD("show"), &Spatial::show);
+ 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);
+ void rotate_z(float p_radians);
+ void translate(const Vector3& p_offset);
+ void scale(const Vector3& p_ratio);
+ void global_rotate(const Vector3& p_normal,float p_radians);
+ void global_translate(const Vector3& p_offset);
+
+ ObjectTypeDB::bind_method( _MD("rotate","normal","radians"),&Spatial::rotate );
+ ObjectTypeDB::bind_method( _MD("global_rotate","normal","radians"),&Spatial::global_rotate );
+ ObjectTypeDB::bind_method( _MD("rotate_x","radians"),&Spatial::rotate_x );
+ ObjectTypeDB::bind_method( _MD("rotate_y","radians"),&Spatial::rotate_y );
+ ObjectTypeDB::bind_method( _MD("rotate_z","radians"),&Spatial::rotate_z );
+ ObjectTypeDB::bind_method( _MD("translate","offset"),&Spatial::translate );
+ ObjectTypeDB::bind_method( _MD("global_translate","offset"),&Spatial::global_translate );
+ ObjectTypeDB::bind_method( _MD("orthonormalize"),&Spatial::orthonormalize );
+ ObjectTypeDB::bind_method( _MD("set_identity"),&Spatial::set_identity );
+
+ ObjectTypeDB::bind_method( _MD("look_at","target","up"),&Spatial::look_at );
+ ObjectTypeDB::bind_method( _MD("look_at_from_pos","pos","target","up"),&Spatial::look_at_from_pos );
+
BIND_CONSTANT( NOTIFICATION_TRANSFORM_CHANGED );
BIND_CONSTANT( NOTIFICATION_ENTER_WORLD );
BIND_CONSTANT( NOTIFICATION_EXIT_WORLD );
+ BIND_CONSTANT( NOTIFICATION_VISIBILITY_CHANGED );
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), _SCS("set_global_transform"), _SCS("get_global_transform") );
ADD_PROPERTYNZ( PropertyInfo(Variant::TRANSFORM,"transform/local",PROPERTY_HINT_NONE,""), _SCS("set_transform"), _SCS("get_transform") );
@@ -547,8 +792,11 @@ 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_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" ) );
+
}
@@ -564,10 +812,12 @@ Spatial::Spatial() : xform_change(this)
data.scale=Vector3(1,1,1);
data.viewport=NULL;
data.inside_world=false;
+ data.visible=true;
#ifdef TOOLS_ENABLED
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 e1119be515..b1e3a82868 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -45,6 +45,7 @@ public:
virtual void create()=0;
virtual void transform()=0;
+ virtual void clear()=0;
virtual void redraw()=0;
virtual void free()=0;
@@ -90,6 +91,9 @@ class Spatial : public Node {
List<Spatial*>::Element *C;
bool ignore_notification;
+ bool notify_local_transform;
+
+ bool visible;
#ifdef TOOLS_ENABLED
Ref<SpatialGizmo> gizmo;
@@ -109,6 +113,8 @@ class Spatial : public Node {
void _set_rotation_deg(const Vector3& p_deg);
Vector3 _get_rotation_deg() const;
+ void _propagate_visibility_changed();
+
protected:
@@ -118,14 +124,18 @@ protected:
void _notification(int p_what);
static void _bind_methods();
-
+
+ void _set_visible_(bool p_visible);
+ bool _is_visible_() const;
public:
enum {
- NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED,
+ NOTIFICATION_TRANSFORM_CHANGED=SceneTree::NOTIFICATION_TRANSFORM_CHANGED,
NOTIFICATION_ENTER_WORLD=41,
NOTIFICATION_EXIT_WORLD=42,
+ NOTIFICATION_VISIBILITY_CHANGED=43,
+ NOTIFICATION_LOCAL_TRANSFORM_CHANGED=44,
};
Spatial *get_parent_spatial() const;
@@ -159,6 +169,30 @@ public:
Transform get_relative_transform(const Node *p_parent) const;
+ void rotate(const Vector3& p_normal,float p_radians);
+ void rotate_x(float p_radians);
+ void rotate_y(float p_radians);
+ void rotate_z(float p_radians);
+ void translate(const Vector3& p_offset);
+ void scale(const Vector3& p_ratio);
+ void global_rotate(const Vector3& p_normal,float p_radians);
+ void global_translate(const Vector3& p_offset);
+
+ 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();
+
+ void show();
+ 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) ;
Transform get_import_transform() const;
diff --git a/scene/3d/spatial_indexer.cpp b/scene/3d/spatial_indexer.cpp
index 261c62f51c..2f7aee5c67 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/spatial_indexer.h b/scene/3d/spatial_indexer.h
index d3038a1293..bc19b54d8f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/spatial_player.cpp b/scene/3d/spatial_player.cpp
index 8e3a0d30ea..5948c01ff8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/spatial_player.h b/scene/3d/spatial_player.h
index e11028d2c9..2f54497847 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/spatial_sample_player.cpp b/scene/3d/spatial_sample_player.cpp
index b4a5d3bc1b..28b8fdd01e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -103,6 +103,7 @@ void SpatialSamplePlayer::_notification(int p_what) {
void SpatialSamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) {
library=p_library;
+ _change_notify();
}
Ref<SampleLibrary> SpatialSamplePlayer::get_sample_library() const {
diff --git a/scene/3d/spatial_sample_player.h b/scene/3d/spatial_sample_player.h
index 68a0326c49..1d7bb8e238 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/spatial_stream_player.cpp b/scene/3d/spatial_stream_player.cpp
index 25448498cb..7ed2335fcb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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()) {
+ 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,47 +138,57 @@ Ref<AudioStream> SpatialStreamPlayer::get_stream() const {
}
-void SpatialStreamPlayer::play() {
+void SpatialStreamPlayer::play(float p_from_offset) {
- if (!is_inside_scene())
- return;
- if (stream.is_null())
+ ERR_FAIL_COND(!is_inside_tree());
+ if (playback.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);
}
void SpatialStreamPlayer::stop() {
- if (!is_inside_scene())
+ 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"),&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 6b73a8ad1b..f2775a4982 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 49e593c1f5..c7d1249a07 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -37,7 +37,7 @@ void SpriteBase3D::_propagate_color_changed() {
void SpriteBase3D::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
if (!pending_update)
_im_update();
@@ -52,7 +52,7 @@ void SpriteBase3D::_notification(int p_what) {
}
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
if (parent_sprite) {
@@ -275,6 +275,9 @@ void SpriteBase3D::_bind_methods() {
BIND_CONSTANT( ALPHA_CUT_DISABLED );
BIND_CONSTANT( ALPHA_CUT_DISCARD );
BIND_CONSTANT( ALPHA_CUT_OPAQUE_PREPASS );
+
+
+
}
@@ -289,7 +292,7 @@ SpriteBase3D::SpriteBase3D() {
parent_sprite=NULL;
pI=NULL;
- for(int i=0;i<4;i++)
+ for(int i=0;i<FLAG_MAX;i++)
flags[i]=i==FLAG_TRANSPARENT;
axis=Vector3::AXIS_Z;
@@ -399,6 +402,20 @@ void Sprite3D::_draw() {
int x_axis = ((axis + 1) % 3);
int y_axis = ((axis + 2) % 3);
+ if (axis!=Vector3::AXIS_Z) {
+ SWAP(x_axis,y_axis);
+
+ for(int i=0;i<4;i++) {
+ //uvs[i] = Vector2(1.0,1.0)-uvs[i];
+ //SWAP(vertices[i].x,vertices[i].y);
+ if (axis==Vector3::AXIS_Y) {
+ vertices[i].y = - vertices[i].y;
+ } else if (axis==Vector3::AXIS_X) {
+ vertices[i].x = - vertices[i].x;
+ }
+ }
+ }
+
AABB aabb;
for(int i=0;i<4;i++) {
@@ -407,8 +424,8 @@ void Sprite3D::_draw() {
VS::get_singleton()->immediate_uv(immediate,uvs[i]);
Vector3 vtx;
- vtx[x_axis]=vertices[i][x_axis];
- vtx[y_axis]=vertices[i][y_axis];
+ vtx[x_axis]=vertices[i][0];
+ vtx[y_axis]=vertices[i][1];
VS::get_singleton()->immediate_vertex(immediate,vtx);
if (i==0) {
aabb.pos=vtx;
@@ -480,6 +497,8 @@ void Sprite3D::set_frame(int p_frame) {
frame=p_frame;
_queue_update();
+ emit_signal(SceneStringNames::get_singleton()->frame_changed);
+
}
int Sprite3D::get_frame() const {
@@ -559,12 +578,14 @@ 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, "frame"), _SCS("set_frame"),_SCS("get_frame"));
+ 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"));
+ ADD_SIGNAL(MethodInfo("frame_changed"));
+
}
Sprite3D::Sprite3D() {
@@ -661,6 +682,20 @@ void AnimatedSprite3D::_draw() {
int x_axis = ((axis + 1) % 3);
int y_axis = ((axis + 2) % 3);
+ if (axis!=Vector3::AXIS_Z) {
+ SWAP(x_axis,y_axis);
+
+ for(int i=0;i<4;i++) {
+ //uvs[i] = Vector2(1.0,1.0)-uvs[i];
+ //SWAP(vertices[i].x,vertices[i].y);
+ if (axis==Vector3::AXIS_Y) {
+ vertices[i].y = - vertices[i].y;
+ } else if (axis==Vector3::AXIS_X) {
+ vertices[i].x = - vertices[i].x;
+ }
+ }
+ }
+
AABB aabb;
for(int i=0;i<4;i++) {
@@ -669,8 +704,8 @@ void AnimatedSprite3D::_draw() {
VS::get_singleton()->immediate_uv(immediate,uvs[i]);
Vector3 vtx;
- vtx[x_axis]=vertices[i][x_axis];
- vtx[y_axis]=vertices[i][y_axis];
+ vtx[x_axis]=vertices[i][0];
+ vtx[y_axis]=vertices[i][1];
VS::get_singleton()->immediate_vertex(immediate,vtx);
if (i==0) {
aabb.pos=vtx;
@@ -692,7 +727,9 @@ void AnimatedSprite3D::_bind_methods(){
ObjectTypeDB::bind_method(_MD("get_frame"),&AnimatedSprite3D::get_frame);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
+
+ ADD_SIGNAL(MethodInfo("frame_changed"));
}
@@ -736,6 +773,7 @@ void AnimatedSprite3D::set_frame(int p_frame){
frame=p_frame;
_queue_update();
+ emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
int AnimatedSprite3D::get_frame() const{
diff --git a/scene/3d/test_cube.cpp b/scene/3d/test_cube.cpp
index 265263a760..0acd1b3351 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/test_cube.h b/scene/3d/test_cube.h
index 8a5b566f1f..2dbd7c9856 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
new file mode 100644
index 0000000000..ba30c118f0
--- /dev/null
+++ b/scene/3d/vehicle_body.cpp
@@ -0,0 +1,1045 @@
+#include "vehicle_body.h"
+
+#define ROLLING_INFLUENCE_FIX
+
+class btVehicleJacobianEntry
+{
+public:
+
+ Vector3 m_linearJointAxis;
+ Vector3 m_aJ;
+ Vector3 m_bJ;
+ Vector3 m_0MinvJt;
+ Vector3 m_1MinvJt;
+ //Optimization: can be stored in the w/last component of one of the vectors
+ real_t m_Adiag;
+
+ real_t getDiagonal() const { return m_Adiag; }
+
+ btVehicleJacobianEntry() {};
+ //constraint between two different rigidbodies
+ btVehicleJacobianEntry(
+ const Matrix3& world2A,
+ const Matrix3& world2B,
+ const Vector3& rel_pos1,
+ const Vector3& rel_pos2,
+ const Vector3& jointAxis,
+ const Vector3& inertiaInvA,
+ const real_t massInvA,
+ const Vector3& inertiaInvB,
+ const real_t massInvB)
+ :m_linearJointAxis(jointAxis)
+ {
+ m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
+ m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
+
+ //btAssert(m_Adiag > real_t(0.0));
+ }
+
+ real_t getRelativeVelocity(const Vector3& linvelA,const Vector3& angvelA,const Vector3& linvelB,const Vector3& angvelB)
+ {
+ Vector3 linrel = linvelA - linvelB;
+ Vector3 angvela = angvelA * m_aJ;
+ Vector3 angvelb = angvelB * m_bJ;
+ linrel *= m_linearJointAxis;
+ angvela += angvelb;
+ angvela += linrel;
+ real_t rel_vel2 = angvela[0]+angvela[1]+angvela[2];
+ return rel_vel2 + CMP_EPSILON;
+ }
+
+
+};
+
+void VehicleWheel::_notification(int p_what) {
+
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ if (!get_parent())
+ return;
+ VehicleBody *cb = get_parent()->cast_to<VehicleBody>();
+ if (!cb)
+ return;
+ body=cb;
+ local_xform=get_transform();
+ cb->wheels.push_back(this);
+
+ m_chassisConnectionPointCS = get_transform().origin;
+ m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
+ m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
+
+ }
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+ if (!get_parent())
+ return;
+ VehicleBody *cb = get_parent()->cast_to<VehicleBody>();
+ if (!cb)
+ return;
+ cb->wheels.erase(this);
+ body=NULL;
+ }
+
+}
+
+
+void VehicleWheel::_update(PhysicsDirectBodyState *s) {
+
+
+
+ if (m_raycastInfo.m_isInContact)
+
+ {
+ real_t project= m_raycastInfo.m_contactNormalWS.dot( m_raycastInfo.m_wheelDirectionWS );
+ Vector3 chassis_velocity_at_contactPoint;
+ Vector3 relpos = m_raycastInfo.m_contactPointWS - s->get_transform().origin;
+
+ chassis_velocity_at_contactPoint = s->get_linear_velocity() +
+ (s->get_angular_velocity()).cross(relpos);// * mPos);
+
+ real_t projVel = m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint );
+ if ( project >= real_t(-0.1))
+ {
+ m_suspensionRelativeVelocity = real_t(0.0);
+ m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
+ }
+ else
+ {
+ real_t inv = real_t(-1.) / project;
+ m_suspensionRelativeVelocity = projVel * inv;
+ m_clippedInvContactDotSuspension = inv;
+ }
+
+ }
+
+ else // Not in contact : position wheel in a nice (rest length) position
+ {
+ m_raycastInfo.m_suspensionLength = m_suspensionRestLength;
+ m_suspensionRelativeVelocity = real_t(0.0);
+ m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS;
+ m_clippedInvContactDotSuspension = real_t(1.0);
+ }
+}
+
+void VehicleWheel::set_radius(float p_radius) {
+
+ m_wheelRadius=p_radius;
+ update_gizmo();
+}
+
+float VehicleWheel::get_radius() const{
+
+ return m_wheelRadius;
+}
+
+void VehicleWheel::set_suspension_rest_length(float p_length){
+
+ m_suspensionRestLength=p_length;
+ update_gizmo();
+}
+float VehicleWheel::get_suspension_rest_length() const{
+
+ return m_suspensionRestLength;
+}
+
+void VehicleWheel::set_suspension_travel(float p_length){
+
+ m_maxSuspensionTravelCm=p_length/0.01;
+}
+float VehicleWheel::get_suspension_travel() const{
+
+ return m_maxSuspensionTravelCm*0.01;
+}
+
+void VehicleWheel::set_suspension_stiffness(float p_value){
+
+ m_suspensionStiffness=p_value;
+}
+float VehicleWheel::get_suspension_stiffness() const{
+
+ return m_suspensionStiffness;
+}
+
+void VehicleWheel::set_suspension_max_force(float p_value){
+
+ m_maxSuspensionForce=p_value;
+}
+float VehicleWheel::get_suspension_max_force() const{
+
+ return m_maxSuspensionForce;
+}
+
+void VehicleWheel::set_damping_compression(float p_value){
+
+ m_wheelsDampingCompression=p_value;
+}
+float VehicleWheel::get_damping_compression() const{
+
+ return m_wheelsDampingCompression;
+}
+
+void VehicleWheel::set_damping_relaxation(float p_value){
+
+ m_wheelsDampingRelaxation=p_value;
+}
+float VehicleWheel::get_damping_relaxation() const{
+
+ return m_wheelsDampingRelaxation;
+}
+
+void VehicleWheel::set_friction_slip(float p_value) {
+
+ m_frictionSlip=p_value;
+}
+float VehicleWheel::get_friction_slip() const{
+
+ return m_frictionSlip;
+}
+
+
+void VehicleWheel::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method(_MD("set_radius","length"),&VehicleWheel::set_radius);
+ ObjectTypeDB::bind_method(_MD("get_radius"),&VehicleWheel::get_radius);
+
+ ObjectTypeDB::bind_method(_MD("set_suspension_rest_length","length"),&VehicleWheel::set_suspension_rest_length);
+ ObjectTypeDB::bind_method(_MD("get_suspension_rest_length"),&VehicleWheel::get_suspension_rest_length);
+
+ ObjectTypeDB::bind_method(_MD("set_suspension_travel","length"),&VehicleWheel::set_suspension_travel);
+ ObjectTypeDB::bind_method(_MD("get_suspension_travel"),&VehicleWheel::get_suspension_travel);
+
+ ObjectTypeDB::bind_method(_MD("set_suspension_stiffness","length"),&VehicleWheel::set_suspension_stiffness);
+ ObjectTypeDB::bind_method(_MD("get_suspension_stiffness"),&VehicleWheel::get_suspension_stiffness);
+
+ ObjectTypeDB::bind_method(_MD("set_suspension_max_force","length"),&VehicleWheel::set_suspension_max_force);
+ ObjectTypeDB::bind_method(_MD("get_suspension_max_force"),&VehicleWheel::get_suspension_max_force);
+
+
+ ObjectTypeDB::bind_method(_MD("set_damping_compression","length"),&VehicleWheel::set_damping_compression);
+ ObjectTypeDB::bind_method(_MD("get_damping_compression"),&VehicleWheel::get_damping_compression);
+
+ ObjectTypeDB::bind_method(_MD("set_damping_relaxation","length"),&VehicleWheel::set_damping_relaxation);
+ ObjectTypeDB::bind_method(_MD("get_damping_relaxation"),&VehicleWheel::get_damping_relaxation);
+
+ ObjectTypeDB::bind_method(_MD("set_use_as_traction","enable"),&VehicleWheel::set_use_as_traction);
+ ObjectTypeDB::bind_method(_MD("is_used_as_traction"),&VehicleWheel::is_used_as_traction);
+
+ ObjectTypeDB::bind_method(_MD("set_use_as_steering","enable"),&VehicleWheel::set_use_as_steering);
+ ObjectTypeDB::bind_method(_MD("is_used_as_steering"),&VehicleWheel::is_used_as_steering);
+
+ ObjectTypeDB::bind_method(_MD("set_friction_slip","length"),&VehicleWheel::set_friction_slip);
+ ObjectTypeDB::bind_method(_MD("get_friction_slip"),&VehicleWheel::get_friction_slip);
+
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"type/traction"),_SCS("set_use_as_traction"),_SCS("is_used_as_traction"));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"type/steering"),_SCS("set_use_as_steering"),_SCS("is_used_as_steering"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"wheel/radius"),_SCS("set_radius"),_SCS("get_radius"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"wheel/rest_length"),_SCS("set_suspension_rest_length"),_SCS("get_suspension_rest_length"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"wheel/friction_slip"),_SCS("set_friction_slip"),_SCS("get_friction_slip"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"suspension/travel"),_SCS("set_suspension_travel"),_SCS("get_suspension_travel"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"suspension/stiffness"),_SCS("set_suspension_stiffness"),_SCS("get_suspension_stiffness"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"suspension/max_force"),_SCS("set_suspension_max_force"),_SCS("get_suspension_max_force"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"damping/compression"),_SCS("set_damping_compression"),_SCS("get_damping_compression"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"damping/relaxation"),_SCS("set_damping_relaxation"),_SCS("get_damping_relaxation"));
+
+}
+
+
+void VehicleWheel::set_use_as_traction(bool p_enable) {
+
+ engine_traction=p_enable;
+}
+
+bool VehicleWheel::is_used_as_traction() const{
+
+ return engine_traction;
+}
+
+
+void VehicleWheel::set_use_as_steering(bool p_enabled){
+
+ steers=p_enabled;
+}
+
+bool VehicleWheel::is_used_as_steering() const{
+
+ return steers;
+}
+
+
+VehicleWheel::VehicleWheel() {
+
+
+ steers=false;
+ engine_traction=false;
+
+ m_steering = real_t(0.);
+ //m_engineForce = real_t(0.);
+ m_rotation = real_t(0.);
+ m_deltaRotation = real_t(0.);
+ m_brake = real_t(0.);
+ m_rollInfluence = real_t(0.1);
+
+ m_suspensionRestLength = 0.15;
+ m_wheelRadius = 0.5;//0.28;
+ m_suspensionStiffness = 5.88;
+ m_wheelsDampingCompression = 0.83;
+ m_wheelsDampingRelaxation = 0.88;
+ m_frictionSlip = 10.5;
+ m_bIsFrontWheel = false;
+ m_maxSuspensionTravelCm = 500;
+ m_maxSuspensionForce = 6000;
+
+ m_suspensionRelativeVelocity=0;
+ m_clippedInvContactDotSuspension=1.0;
+ m_raycastInfo.m_isInContact=false;
+
+ body=NULL;
+}
+
+
+void VehicleBody::_update_wheel_transform(VehicleWheel& wheel ,PhysicsDirectBodyState *s) {
+
+ wheel.m_raycastInfo.m_isInContact = false;
+
+ Transform chassisTrans = s->get_transform();
+ //if (interpolatedTransform && (getRigidBody()->getMotionState()))
+ //{
+ // getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
+ //}
+
+ wheel.m_raycastInfo.m_hardPointWS = chassisTrans.xform( wheel.m_chassisConnectionPointCS );
+ //wheel.m_raycastInfo.m_hardPointWS+=s->get_linear_velocity()*s->get_step();
+ wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.get_basis().xform( wheel.m_wheelDirectionCS).normalized();
+ wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.get_basis().xform( wheel.m_wheelAxleCS ).normalized();
+}
+
+void VehicleBody::_update_wheel(int p_idx,PhysicsDirectBodyState *s) {
+
+ VehicleWheel& wheel = *wheels[p_idx];
+ _update_wheel_transform(wheel,s);
+
+ Vector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS;
+ const Vector3& right = wheel.m_raycastInfo.m_wheelAxleWS;
+ Vector3 fwd = up.cross(right);
+ fwd = fwd.normalized();
+// up = right.cross(fwd);
+// up.normalize();
+
+ //rotate around steering over de wheelAxleWS
+ real_t steering = wheel.steers?m_steeringValue:0.0;
+ //print_line(itos(p_idx)+": "+rtos(steering));
+
+ Matrix3 steeringMat(up,steering);
+
+ Matrix3 rotatingMat(right,-wheel.m_rotation);
+
+// if (p_idx==1)
+// print_line("steeringMat " +steeringMat);
+
+ Matrix3 basis2(
+ right[0],up[0],fwd[0],
+ right[1],up[1],fwd[1],
+ right[2],up[2],fwd[2]
+ );
+
+ wheel.m_worldTransform.set_basis(steeringMat * rotatingMat * basis2);
+ //wheel.m_worldTransform.set_basis(basis2 * (steeringMat * rotatingMat));
+ wheel.m_worldTransform.set_origin(
+ wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength
+ );
+
+}
+
+
+real_t VehicleBody::_ray_cast(int p_idx,PhysicsDirectBodyState *s) {
+
+
+ VehicleWheel& wheel = *wheels[p_idx];
+
+ _update_wheel_transform(wheel,s);
+
+
+ real_t depth = -1;
+
+ real_t raylen = wheel.m_suspensionRestLength+wheel.m_wheelRadius;
+
+ Vector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen);
+ Vector3 source = wheel.m_raycastInfo.m_hardPointWS;
+ wheel.m_raycastInfo.m_contactPointWS = source + rayvector;
+ const Vector3& target = wheel.m_raycastInfo.m_contactPointWS;
+ source-=wheel.m_wheelRadius * wheel.m_raycastInfo.m_wheelDirectionWS;
+
+ real_t param = real_t(0.);
+
+
+ PhysicsDirectSpaceState::RayResult rr;
+
+
+ PhysicsDirectSpaceState *ss=s->get_space_state();
+
+ bool col = ss->intersect_ray(source,target,rr,exclude);
+
+
+ wheel.m_raycastInfo.m_groundObject = 0;
+
+ if (col)
+ {
+ //print_line("WHEEL "+itos(p_idx)+" FROM "+source+" TO: "+target);
+ //print_line("WHEEL "+itos(p_idx)+" COLLIDE? "+itos(col));
+ param = source.distance_to(rr.position)/source.distance_to(target);
+ depth = raylen * param;
+ wheel.m_raycastInfo.m_contactNormalWS = rr.normal;
+
+ wheel.m_raycastInfo.m_isInContact = true;
+ if (rr.collider)
+ wheel.m_raycastInfo.m_groundObject=rr.collider->cast_to<PhysicsBody>();
+
+
+ real_t hitDistance = param*raylen;
+ wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelRadius;
+ //clamp on max suspension travel
+
+ real_t minSuspensionLength = wheel.m_suspensionRestLength - wheel.m_maxSuspensionTravelCm*real_t(0.01);
+ real_t maxSuspensionLength = wheel.m_suspensionRestLength+ wheel.m_maxSuspensionTravelCm*real_t(0.01);
+ if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength)
+ {
+ wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength;
+ }
+ if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength)
+ {
+ wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength;
+ }
+
+ wheel.m_raycastInfo.m_contactPointWS = rr.position;
+
+ real_t denominator= wheel.m_raycastInfo.m_contactNormalWS.dot( wheel.m_raycastInfo.m_wheelDirectionWS );
+
+ Vector3 chassis_velocity_at_contactPoint;
+ //Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition();
+
+ //chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos);
+
+ chassis_velocity_at_contactPoint = s->get_linear_velocity() +
+ (s->get_angular_velocity()).cross(wheel.m_raycastInfo.m_contactPointWS-s->get_transform().origin);// * mPos);
+
+
+ real_t projVel = wheel.m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint );
+
+ if ( denominator >= real_t(-0.1))
+ {
+ wheel.m_suspensionRelativeVelocity = real_t(0.0);
+ wheel.m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
+ }
+ else
+ {
+ real_t inv = real_t(-1.) / denominator;
+ wheel.m_suspensionRelativeVelocity = projVel * inv;
+ wheel.m_clippedInvContactDotSuspension = inv;
+ }
+
+ } else
+ {
+ wheel.m_raycastInfo.m_isInContact = false;
+ //put wheel info as in rest position
+ wheel.m_raycastInfo.m_suspensionLength = wheel.m_suspensionRestLength;
+ wheel.m_suspensionRelativeVelocity = real_t(0.0);
+ wheel.m_raycastInfo.m_contactNormalWS = - wheel.m_raycastInfo.m_wheelDirectionWS;
+ wheel.m_clippedInvContactDotSuspension = real_t(1.0);
+ }
+
+ return depth;
+}
+
+
+void VehicleBody::_update_suspension(PhysicsDirectBodyState *s)
+{
+
+ real_t deltaTime = s->get_step();
+ real_t chassisMass = mass;
+
+ for (int w_it=0; w_it<wheels.size(); w_it++)
+ {
+ VehicleWheel& wheel_info = *wheels[w_it];
+
+
+ if ( wheel_info.m_raycastInfo.m_isInContact )
+ {
+ real_t force;
+ // Spring
+ {
+ real_t susp_length = wheel_info.m_suspensionRestLength;
+ real_t current_length = wheel_info.m_raycastInfo.m_suspensionLength;
+
+ real_t length_diff = (susp_length - current_length);
+
+ force = wheel_info.m_suspensionStiffness
+ * length_diff * wheel_info.m_clippedInvContactDotSuspension;
+ }
+
+ // Damper
+ {
+ real_t projected_rel_vel = wheel_info.m_suspensionRelativeVelocity;
+ {
+ real_t susp_damping;
+ if ( projected_rel_vel < real_t(0.0) )
+ {
+ susp_damping = wheel_info.m_wheelsDampingCompression;
+ }
+ else
+ {
+ susp_damping = wheel_info.m_wheelsDampingRelaxation;
+ }
+ force -= susp_damping * projected_rel_vel;
+ }
+ }
+
+ // RESULT
+ wheel_info.m_wheelsSuspensionForce = force * chassisMass;
+ if (wheel_info.m_wheelsSuspensionForce < real_t(0.))
+ {
+ wheel_info.m_wheelsSuspensionForce = real_t(0.);
+ }
+ }
+ else
+ {
+ wheel_info.m_wheelsSuspensionForce = real_t(0.0);
+ }
+ }
+
+}
+
+
+//bilateral constraint between two dynamic objects
+void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3& pos1,
+ PhysicsBody* body2, const Vector3& pos2, const Vector3& normal,real_t& impulse)
+{
+
+ real_t normalLenSqr = normal.length_squared();
+ //ERR_FAIL_COND( normalLenSqr < real_t(1.1));
+
+ if (normalLenSqr > real_t(1.1))
+ {
+ impulse = real_t(0.);
+ return;
+ }
+
+ Vector3 rel_pos1 = pos1 - s->get_transform().origin;
+ Vector3 rel_pos2;
+ if (body2)
+ rel_pos2 = pos2 - body2->get_global_transform().origin;
+ //this jacobian entry could be re-used for all iterations
+
+ Vector3 vel1 = s->get_linear_velocity() + (s->get_angular_velocity()).cross(rel_pos1);// * mPos);
+ Vector3 vel2;
+
+ if (body2)
+ vel2=body2->get_linear_velocity() + body2->get_angular_velocity().cross(rel_pos2);
+
+ Vector3 vel = vel1 - vel2;
+
+ Matrix3 b2trans;
+ float b2invmass=0;
+ Vector3 b2lv;
+ Vector3 b2av;
+ Vector3 b2invinertia; //todo
+
+ if (body2) {
+ b2trans = body2->get_global_transform().basis.transposed();
+ b2invmass = body2->get_inverse_mass();
+ b2lv = body2->get_linear_velocity();
+ b2av = body2->get_angular_velocity();
+ }
+
+
+
+ btVehicleJacobianEntry jac(s->get_transform().basis.transposed(),
+ b2trans,
+ rel_pos1,
+ rel_pos2,
+ normal,
+ s->get_inverse_inertia(),
+ 1.0/mass,
+ b2invinertia,
+ b2invmass);
+
+ real_t jacDiagAB = jac.getDiagonal();
+ real_t jacDiagABInv = real_t(1.) / jacDiagAB;
+
+ real_t rel_vel = jac.getRelativeVelocity(
+ s->get_linear_velocity(),
+ s->get_transform().basis.transposed().xform(s->get_angular_velocity()),
+ b2lv,
+ b2trans.xform(b2av));
+ real_t a;
+ a=jacDiagABInv;
+
+
+ rel_vel = normal.dot(vel);
+
+ //todo: move this into proper structure
+ real_t contactDamping = real_t(0.4);
+#define ONLY_USE_LINEAR_MASS
+#ifdef ONLY_USE_LINEAR_MASS
+ real_t massTerm = real_t(1.) / ((1.0/mass) + b2invmass);
+ impulse = - contactDamping * rel_vel * massTerm;
+#else
+ real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
+ impulse = velocityImpulse;
+#endif
+
+}
+
+
+
+VehicleBody::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDirectBodyState *s,PhysicsBody* body1,const Vector3& frictionPosWorld,const Vector3& frictionDirectionWorld, real_t maxImpulse)
+ :m_s(s),
+ m_body1(body1),
+ m_frictionPositionWorld(frictionPosWorld),
+ m_frictionDirectionWorld(frictionDirectionWorld),
+ m_maxImpulse(maxImpulse)
+{
+ float denom0=0;
+ float denom1=0;
+
+ {
+ Vector3 r0 = frictionPosWorld - s->get_transform().origin;
+ Vector3 c0 = (r0).cross(frictionDirectionWorld);
+ Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
+ denom0= s->get_inverse_mass() + frictionDirectionWorld.dot(vec);
+ }
+
+ if (body1) {
+
+ Vector3 r0 = frictionPosWorld - body1->get_global_transform().origin;
+ Vector3 c0 = (r0).cross(frictionDirectionWorld);
+ Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
+ //denom1= body1->get_inverse_mass() + frictionDirectionWorld.dot(vec);
+ denom1=0;
+
+ }
+
+
+ real_t relaxation = 1.f;
+ m_jacDiagABInv = relaxation/(denom0+denom1);
+}
+
+
+real_t VehicleBody::_calc_rolling_friction(btVehicleWheelContactPoint& contactPoint) {
+
+ real_t j1=0.f;
+
+ const Vector3& contactPosWorld = contactPoint.m_frictionPositionWorld;
+
+ Vector3 rel_pos1 = contactPosWorld - contactPoint.m_s->get_transform().origin;
+ Vector3 rel_pos2;
+ if (contactPoint.m_body1)
+ rel_pos2 = contactPosWorld - contactPoint.m_body1->get_global_transform().origin;
+
+ real_t maxImpulse = contactPoint.m_maxImpulse;
+
+ Vector3 vel1 = contactPoint.m_s->get_linear_velocity() + (contactPoint.m_s->get_angular_velocity()).cross(rel_pos1);// * mPos);
+
+ Vector3 vel2;
+ if (contactPoint.m_body1) {
+ vel2=contactPoint.m_body1->get_linear_velocity() + contactPoint.m_body1->get_angular_velocity().cross(rel_pos2);
+
+ }
+
+ Vector3 vel = vel1 - vel2;
+
+ real_t vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
+
+ // calculate j that moves us to zero relative velocity
+ j1 = -vrel * contactPoint.m_jacDiagABInv;
+
+ return CLAMP(j1,-maxImpulse,maxImpulse);
+}
+
+
+static const real_t sideFrictionStiffness2 = real_t(1.0);
+void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
+
+ //calculate the impulse, so that the wheels don't move sidewards
+ int numWheel = wheels.size();
+ if (!numWheel)
+ return;
+
+ m_forwardWS.resize(numWheel);
+ m_axle.resize(numWheel);
+ m_forwardImpulse.resize(numWheel);
+ m_sideImpulse.resize(numWheel);
+
+ int numWheelsOnGround = 0;
+
+
+ //collapse all those loops into one!
+ for (int i=0;i<wheels.size();i++)
+ {
+ VehicleWheel& wheelInfo = *wheels[i];
+ if (wheelInfo.m_raycastInfo.m_isInContact)
+ numWheelsOnGround++;
+ m_sideImpulse[i] = real_t(0.);
+ m_forwardImpulse[i] = real_t(0.);
+
+ }
+
+ {
+
+ for (int i=0;i<wheels.size();i++)
+ {
+
+ VehicleWheel& wheelInfo = *wheels[i];
+
+
+ if (wheelInfo.m_raycastInfo.m_isInContact)
+ {
+
+ //const btTransform& wheelTrans = getWheelTransformWS( i );
+
+ Matrix3 wheelBasis0 = wheelInfo.m_worldTransform.basis;//get_global_transform().basis;
+
+ m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
+ //m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS;
+
+ const Vector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
+ real_t proj = m_axle[i].dot(surfNormalWS);
+ m_axle[i] -= surfNormalWS * proj;
+ m_axle[i] = m_axle[i].normalized();
+
+ m_forwardWS[i] = surfNormalWS.cross(m_axle[i]);
+ m_forwardWS[i].normalize();
+
+
+ _resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
+ wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
+ m_axle[i],m_sideImpulse[i]);
+
+ m_sideImpulse[i] *= sideFrictionStiffness2;
+
+
+ }
+ }
+ }
+
+ real_t sideFactor = real_t(1.);
+ real_t fwdFactor = 0.5;
+
+ bool sliding = false;
+ {
+ for (int wheel =0;wheel <wheels.size();wheel++)
+ {
+ VehicleWheel& wheelInfo = *wheels[wheel];
+
+
+ //class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject;
+
+ real_t rollingFriction = 0.f;
+
+ if (wheelInfo.m_raycastInfo.m_isInContact)
+ {
+ if (engine_force != 0.f)
+ {
+ rollingFriction = -engine_force* s->get_step();
+ } else
+ {
+ real_t defaultRollingFrictionImpulse = 0.f;
+ float cbrake = MAX(wheelInfo.m_brake,brake);
+ real_t maxImpulse = cbrake ? cbrake : defaultRollingFrictionImpulse;
+ btVehicleWheelContactPoint contactPt(s,wheelInfo.m_raycastInfo.m_groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse);
+ rollingFriction = _calc_rolling_friction(contactPt);
+ }
+ }
+
+ //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
+
+
+
+
+ m_forwardImpulse[wheel] = real_t(0.);
+ wheelInfo.m_skidInfo= real_t(1.);
+
+ if (wheelInfo.m_raycastInfo.m_isInContact)
+ {
+ wheelInfo.m_skidInfo= real_t(1.);
+
+ real_t maximp = wheelInfo.m_wheelsSuspensionForce * s->get_step() * wheelInfo.m_frictionSlip;
+ real_t maximpSide = maximp;
+
+ real_t maximpSquared = maximp * maximpSide;
+
+
+ m_forwardImpulse[wheel] = rollingFriction;//wheelInfo.m_engineForce* timeStep;
+
+ real_t x = (m_forwardImpulse[wheel] ) * fwdFactor;
+ real_t y = (m_sideImpulse[wheel] ) * sideFactor;
+
+ real_t impulseSquared = (x*x + y*y);
+
+ if (impulseSquared > maximpSquared)
+ {
+ sliding = true;
+
+ real_t factor = maximp / Math::sqrt(impulseSquared);
+
+ wheelInfo.m_skidInfo *= factor;
+ }
+ }
+
+ }
+ }
+
+
+
+
+ if (sliding)
+ {
+ for (int wheel = 0;wheel < wheels.size(); wheel++)
+ {
+ if (m_sideImpulse[wheel] != real_t(0.))
+ {
+ if (wheels[wheel]->m_skidInfo< real_t(1.))
+ {
+ m_forwardImpulse[wheel] *= wheels[wheel]->m_skidInfo;
+ m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo;
+ }
+ }
+ }
+ }
+
+ // apply the impulses
+ {
+ for (int wheel = 0;wheel<wheels.size(); wheel++)
+ {
+ VehicleWheel& wheelInfo = *wheels[wheel];
+
+ Vector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS -
+ s->get_transform().origin;
+
+ if (m_forwardImpulse[wheel] != real_t(0.))
+ {
+ s->apply_impulse(rel_pos,m_forwardWS[wheel]*(m_forwardImpulse[wheel]));
+ }
+ if (m_sideImpulse[wheel] != real_t(0.))
+ {
+ PhysicsBody* groundObject = wheelInfo.m_raycastInfo.m_groundObject;
+
+ Vector3 rel_pos2;
+ if (groundObject) {
+ rel_pos2=wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->get_global_transform().origin;
+ }
+
+
+ Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
+
+#if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
+ Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1];//getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
+ rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f-wheelInfo.m_rollInfluence));
+#else
+ rel_pos[1] *= wheelInfo.m_rollInfluence; //?
+#endif
+ s->apply_impulse(rel_pos,sideImp);
+
+ //apply friction impulse on the ground
+ //todo
+ //groundObject->applyImpulse(-sideImp,rel_pos2);
+ }
+ }
+ }
+
+
+}
+
+
+void VehicleBody::_direct_state_changed(Object *p_state) {
+
+
+ PhysicsDirectBodyState *s = p_state->cast_to<PhysicsDirectBodyState>();
+
+ set_ignore_transform_notification(true);
+ set_global_transform(s->get_transform());
+ set_ignore_transform_notification(false);
+
+
+ float step = s->get_step();
+
+ for(int i=0;i<wheels.size();i++) {
+
+ _update_wheel(i,s);
+ }
+
+
+ for(int i=0;i<wheels.size();i++) {
+
+ _ray_cast(i,s);
+ wheels[i]->set_transform(s->get_transform().inverse() * wheels[i]->m_worldTransform);
+ }
+
+ _update_suspension(s);
+
+ for(int i=0;i<wheels.size();i++) {
+
+ //apply suspension force
+ VehicleWheel& wheel = *wheels[i];
+
+ real_t suspensionForce = wheel.m_wheelsSuspensionForce;
+
+ if (suspensionForce > wheel.m_maxSuspensionForce)
+ {
+ suspensionForce = wheel.m_maxSuspensionForce;
+ }
+ Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
+ Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - s->get_transform().origin;
+
+ s->apply_impulse(relpos,impulse);
+ //getRigidBody()->applyImpulse(impulse, relpos);
+
+ }
+
+
+ _update_friction(s);
+
+
+ for (int i=0;i<wheels.size();i++)
+ {
+ VehicleWheel& wheel = *wheels[i];
+ Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - s->get_transform().origin;
+ Vector3 vel = s->get_linear_velocity() + (s->get_angular_velocity()).cross(relpos);// * mPos);
+
+ if (wheel.m_raycastInfo.m_isInContact)
+ {
+ const Transform& chassisWorldTransform = s->get_transform();
+
+ Vector3 fwd (
+ chassisWorldTransform.basis[0][Vector3::AXIS_Z],
+ chassisWorldTransform.basis[1][Vector3::AXIS_Z],
+ chassisWorldTransform.basis[2][Vector3::AXIS_Z]);
+
+ real_t proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
+ fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
+
+ real_t proj2 = fwd.dot(vel);
+
+ wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius);
+ wheel.m_rotation += wheel.m_deltaRotation;
+
+ } else
+ {
+ wheel.m_rotation += wheel.m_deltaRotation;
+ }
+
+ wheel.m_deltaRotation *= real_t(0.99);//damping of rotation when not in contact
+
+ }
+
+}
+
+void VehicleBody::set_mass(real_t p_mass) {
+
+ mass=p_mass;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_MASS,mass);
+}
+
+real_t VehicleBody::get_mass() const{
+
+ return mass;
+}
+
+
+void VehicleBody::set_friction(real_t p_friction) {
+
+ friction=p_friction;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction);
+}
+
+real_t VehicleBody::get_friction() const{
+
+ return friction;
+}
+
+void VehicleBody::set_engine_force(float p_force) {
+
+ engine_force=p_force;
+}
+
+float VehicleBody::get_engine_force() const{
+
+ return engine_force;
+}
+
+void VehicleBody::set_brake(float p_brake){
+
+ brake=p_brake;
+}
+float VehicleBody::get_brake() const{
+
+ return brake;
+}
+
+void VehicleBody::set_steering(float p_steering){
+
+ m_steeringValue=p_steering;
+}
+float VehicleBody::get_steering() const{
+
+ return m_steeringValue;
+}
+
+
+void VehicleBody::_bind_methods(){
+
+ ObjectTypeDB::bind_method(_MD("set_mass","mass"),&VehicleBody::set_mass);
+ ObjectTypeDB::bind_method(_MD("get_mass"),&VehicleBody::get_mass);
+
+ ObjectTypeDB::bind_method(_MD("set_friction","friction"),&VehicleBody::set_friction);
+ ObjectTypeDB::bind_method(_MD("get_friction"),&VehicleBody::get_friction);
+
+ ObjectTypeDB::bind_method(_MD("set_engine_force","engine_force"),&VehicleBody::set_engine_force);
+ ObjectTypeDB::bind_method(_MD("get_engine_force"),&VehicleBody::get_engine_force);
+
+ ObjectTypeDB::bind_method(_MD("set_brake","brake"),&VehicleBody::set_brake);
+ ObjectTypeDB::bind_method(_MD("get_brake"),&VehicleBody::get_brake);
+
+ ObjectTypeDB::bind_method(_MD("set_steering","steering"),&VehicleBody::set_steering);
+ ObjectTypeDB::bind_method(_MD("get_steering"),&VehicleBody::get_steering);
+
+ ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&VehicleBody::_direct_state_changed);
+
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/engine_force",PROPERTY_HINT_RANGE,"0.00,1024.0,0.01"),_SCS("set_engine_force"),_SCS("get_engine_force"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/brake",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_brake"),_SCS("get_brake"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/steering",PROPERTY_HINT_RANGE,"-180,180.0,0.01"),_SCS("set_steering"),_SCS("get_steering"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/mass",PROPERTY_HINT_RANGE,"0.01,65536,0.01"),_SCS("set_mass"),_SCS("get_mass"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/friction",PROPERTY_HINT_RANGE,"0.01,1,0.01"),_SCS("set_friction"),_SCS("get_friction"));
+
+
+}
+
+
+
+VehicleBody::VehicleBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) {
+
+
+ m_pitchControl=0;
+ m_currentVehicleSpeedKmHour = real_t(0.);
+ m_steeringValue = real_t(0.);
+
+ engine_force=0;
+ brake=0;
+
+
+
+ friction=1;
+
+ ccd=false;
+
+ exclude.insert(get_rid());
+ PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed");
+
+ set_mass(40);
+}
+
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
new file mode 100644
index 0000000000..285cca142d
--- /dev/null
+++ b/scene/3d/vehicle_body.h
@@ -0,0 +1,185 @@
+#ifndef VEHICLE_BODY_H
+#define VEHICLE_BODY_H
+
+#include "scene/3d/physics_body.h"
+
+class VehicleBody;
+
+class VehicleWheel : public Spatial {
+
+ OBJ_TYPE(VehicleWheel,Spatial);
+
+friend class VehicleBody;
+
+
+ Transform m_worldTransform;
+ Transform local_xform;
+ bool engine_traction;
+ bool steers;
+
+
+ Vector3 m_chassisConnectionPointCS; //const
+ Vector3 m_wheelDirectionCS;//const
+ Vector3 m_wheelAxleCS; // const or modified by steering
+
+ real_t m_suspensionRestLength;
+ real_t m_maxSuspensionTravelCm;
+ real_t m_wheelRadius;
+
+ real_t m_suspensionStiffness;
+ real_t m_wheelsDampingCompression;
+ real_t m_wheelsDampingRelaxation;
+ real_t m_frictionSlip;
+ real_t m_maxSuspensionForce;
+ bool m_bIsFrontWheel;
+
+ VehicleBody *body;
+
+// btVector3 m_wheelAxleCS; // const or modified by steering ?
+
+ real_t m_steering;
+ real_t m_rotation;
+ real_t m_deltaRotation;
+ real_t m_rollInfluence;
+ //real_t m_engineForce;
+ real_t m_brake;
+
+ real_t m_clippedInvContactDotSuspension;
+ real_t m_suspensionRelativeVelocity;
+ //calculated by suspension
+ real_t m_wheelsSuspensionForce;
+ real_t m_skidInfo;
+
+
+ struct RaycastInfo {
+ //set by raycaster
+ Vector3 m_contactNormalWS;//contactnormal
+ Vector3 m_contactPointWS;//raycast hitpoint
+ real_t m_suspensionLength;
+ Vector3 m_hardPointWS;//raycast starting point
+ Vector3 m_wheelDirectionWS; //direction in worldspace
+ Vector3 m_wheelAxleWS; // axle in worldspace
+ bool m_isInContact;
+ PhysicsBody* m_groundObject; //could be general void* ptr
+ } m_raycastInfo;
+
+ void _update(PhysicsDirectBodyState *s);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+
+ void set_radius(float p_radius);
+ float get_radius() const;
+
+ void set_suspension_rest_length(float p_length);
+ float get_suspension_rest_length() const;
+
+ void set_suspension_travel(float p_length);
+ float get_suspension_travel() const;
+
+ void set_suspension_stiffness(float p_value);
+ float get_suspension_stiffness() const;
+
+ void set_suspension_max_force(float p_value);
+ float get_suspension_max_force() const;
+
+ void set_damping_compression(float p_value);
+ float get_damping_compression() const;
+
+ void set_damping_relaxation(float p_value);
+ float get_damping_relaxation() const;
+
+ void set_friction_slip(float p_value);
+ float get_friction_slip() const;
+
+ void set_use_as_traction(bool p_enable);
+ bool is_used_as_traction() const;
+
+ void set_use_as_steering(bool p_enabled);
+ bool is_used_as_steering() const;
+
+ VehicleWheel();
+
+};
+
+
+class VehicleBody : public PhysicsBody {
+
+ OBJ_TYPE(VehicleBody,PhysicsBody);
+
+ real_t mass;
+ real_t friction;
+
+ float engine_force;
+ float brake;
+
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
+ bool ccd;
+
+ real_t m_pitchControl;
+ real_t m_steeringValue;
+ real_t m_currentVehicleSpeedKmHour;
+
+ Set<RID> exclude;
+
+ Vector<Vector3> m_forwardWS;
+ Vector<Vector3> m_axle;
+ Vector<real_t> m_forwardImpulse;
+ Vector<real_t> m_sideImpulse;
+
+ struct btVehicleWheelContactPoint {
+ PhysicsDirectBodyState *m_s;
+ PhysicsBody* m_body1;
+ Vector3 m_frictionPositionWorld;
+ Vector3 m_frictionDirectionWorld;
+ real_t m_jacDiagABInv;
+ real_t m_maxImpulse;
+
+
+ btVehicleWheelContactPoint(PhysicsDirectBodyState *s,PhysicsBody* body1,const Vector3& frictionPosWorld,const Vector3& frictionDirectionWorld, real_t maxImpulse);
+ };
+
+ void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3& pos1, PhysicsBody* body2, const Vector3& pos2, const Vector3& normal, real_t& impulse);
+ real_t _calc_rolling_friction(btVehicleWheelContactPoint& contactPoint);
+
+ void _update_friction(PhysicsDirectBodyState *s);
+ void _update_suspension(PhysicsDirectBodyState *s);
+ real_t _ray_cast(int p_idx,PhysicsDirectBodyState *s);
+ void _update_wheel_transform(VehicleWheel& wheel ,PhysicsDirectBodyState *s);
+ void _update_wheel(int p_idx,PhysicsDirectBodyState *s);
+
+
+
+friend class VehicleWheel;
+ Vector<VehicleWheel*> wheels;
+
+ static void _bind_methods();
+
+ void _direct_state_changed(Object *p_state);
+public:
+
+
+ void set_mass(real_t p_mass);
+ real_t get_mass() const;
+
+ void set_friction(real_t p_friction);
+ real_t get_friction() const;
+
+ void set_engine_force(float p_engine_force);
+ float get_engine_force() const;
+
+ void set_brake(float p_force);
+ float get_brake() const;
+
+ void set_steering(float p_steering);
+ float get_steering() const;
+
+
+ VehicleBody();
+};
+
+#endif // VEHICLE_BODY_H
diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp
index da01827c49..ad62f6d809 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -183,7 +183,7 @@ void VisibilityEnabler::_find_nodes(Node* p_node) {
if (add) {
- p_node->connect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed",varray(p_node),CONNECT_ONESHOT);
+ p_node->connect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed",varray(p_node),CONNECT_ONESHOT);
nodes[p_node]=meta;
_change_node_state(p_node,false);
}
@@ -200,9 +200,9 @@ void VisibilityEnabler::_find_nodes(Node* p_node) {
void VisibilityEnabler::_notification(int p_what){
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
- if (get_scene()->is_editor_hint())
+ if (get_tree()->is_editor_hint())
return;
@@ -215,9 +215,9 @@ void VisibilityEnabler::_notification(int p_what){
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
- if (get_scene()->is_editor_hint())
+ if (get_tree()->is_editor_hint())
return;
@@ -228,7 +228,7 @@ void VisibilityEnabler::_notification(int p_what){
if (!visible)
_change_node_state(E->key(),true);
- E->key()->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed");
+ E->key()->disconnect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed");
}
nodes.clear();
@@ -247,10 +247,10 @@ void VisibilityEnabler::_change_node_state(Node* p_node,bool p_enabled) {
if (p_enabled) {
RigidBody::Mode mode = RigidBody::Mode(nodes[p_node].operator int());
//rb->set_mode(mode);
- rb->set_active(true);
+ rb->set_sleeping(false);
} else {
//rb->set_mode(RigidBody::MODE_STATIC);
- rb->set_active(false);
+ rb->set_sleeping(true);
}
}
}
@@ -271,7 +271,7 @@ void VisibilityEnabler::_node_removed(Node* p_node) {
if (!visible)
_change_node_state(p_node,true);
- p_node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed");
+ p_node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed");
nodes.erase(p_node);
}
diff --git a/scene/3d/visibility_notifier.h b/scene/3d/visibility_notifier.h
index 52acd0ba2c..85c26bec94 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 625da9b093..41e8b6bf54 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -50,17 +50,24 @@ void VisualInstance::_notification(int p_what) {
// CHECK ROOM
Spatial * parent = get_parent_spatial();
Room *room=NULL;
+ bool is_geom = cast_to<GeometryInstance>();
while(parent) {
room = parent->cast_to<Room>();
if (room)
break;
- else
- parent=parent->get_parent_spatial();
+
+ if (is_geom && parent->cast_to<BakedLightSampler>()) {
+ VS::get_singleton()->instance_geometry_set_baked_light_sampler(get_instance(),parent->cast_to<BakedLightSampler>()->get_instance());
+ break;
+ }
+
+ parent=parent->get_parent_spatial();
}
+
if (room) {
VisualServer::get_singleton()->instance_set_room(instance,room->get_instance());
@@ -85,6 +92,7 @@ void VisualInstance::_notification(int p_what) {
VisualServer::get_singleton()->instance_set_scenario( instance, RID() );
VisualServer::get_singleton()->instance_set_room(instance,RID());
VisualServer::get_singleton()->instance_attach_skeleton( instance, RID() );
+ VS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() );
} break;
@@ -195,6 +203,7 @@ void GeometryInstance::_notification(int p_what) {
_find_baked_light();
}
+ _update_visibility();
} else if (p_what==NOTIFICATION_EXIT_WORLD) {
@@ -207,8 +216,13 @@ void GeometryInstance::_notification(int p_what) {
_baked_light_changed();
}
+
+ } if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ _update_visibility();
}
+
}
void GeometryInstance::_baked_light_changed() {
@@ -241,6 +255,15 @@ void GeometryInstance::_find_baked_light() {
_baked_light_changed();
}
+void GeometryInstance::_update_visibility() {
+
+ if (!is_inside_tree())
+ return;
+
+ _change_notify("geometry/visible");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(),VS::INSTANCE_FLAG_VISIBLE,is_visible() && flags[FLAG_VISIBLE]);
+}
+
void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
ERR_FAIL_INDEX(p_flag,FLAG_MAX);
@@ -250,8 +273,7 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
flags[p_flag]=p_value;
VS::get_singleton()->instance_geometry_set_flag(get_instance(),(VS::InstanceFlags)p_flag,p_value);
if (p_flag==FLAG_VISIBLE) {
- _change_notify("geometry/visible");
- emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ _update_visibility();
}
if (p_flag==FLAG_USE_BAKED_LIGHT) {
@@ -276,6 +298,29 @@ bool GeometryInstance::get_flag(Flags p_flag) const{
}
+void GeometryInstance::set_baked_light_texture_id(int p_id) {
+
+ baked_light_texture_id=p_id;
+ VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),baked_light_texture_id);
+
+}
+
+int GeometryInstance::get_baked_light_texture_id() const{
+
+ return baked_light_texture_id;
+}
+
+void GeometryInstance::set_extra_cull_margin(float p_margin) {
+
+ ERR_FAIL_COND(p_margin<0);
+ extra_cull_margin=p_margin;
+ VS::get_singleton()->instance_set_extra_visibility_margin(get_instance(),extra_cull_margin);
+}
+
+float GeometryInstance::get_extra_cull_margin() const{
+
+ return extra_cull_margin;
+}
void GeometryInstance::_bind_methods() {
@@ -291,6 +336,12 @@ void GeometryInstance::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_draw_range_end","mode"), &GeometryInstance::set_draw_range_end);
ObjectTypeDB::bind_method(_MD("get_draw_range_end"), &GeometryInstance::get_draw_range_end);
+ ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id);
+ ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id);
+
+ ObjectTypeDB::bind_method(_MD("set_extra_cull_margin","margin"), &GeometryInstance::set_extra_cull_margin);
+ ObjectTypeDB::bind_method(_MD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
+
ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE);
@@ -299,13 +350,15 @@ void GeometryInstance::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/receive_shadows"), _SCS("set_flag"), _SCS("get_flag"),FLAG_RECEIVE_SHADOWS);
ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_begin",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_begin"), _SCS("get_draw_range_begin"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_end",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_end"), _SCS("get_draw_range_end"));
+ ADD_PROPERTY( PropertyInfo( Variant::REAL, "geometry/extra_cull_margin",PROPERTY_HINT_RANGE,"0,16384,0"), _SCS("set_extra_cull_margin"), _SCS("get_extra_cull_margin"));
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT);
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/baked_light_tex_id"), _SCS("set_baked_light_texture_id"), _SCS("get_baked_light_texture_id"));
- ADD_SIGNAL( MethodInfo("visibility_changed"));
+// ADD_SIGNAL( MethodInfo("visibility_changed"));
BIND_CONSTANT(FLAG_VISIBLE );
BIND_CONSTANT(FLAG_CAST_SHADOW );
@@ -321,14 +374,17 @@ void GeometryInstance::_bind_methods() {
GeometryInstance::GeometryInstance() {
draw_begin=0;
draw_end=0;
+ for(int i=0;i<FLAG_MAX;i++) {
+ flags[i]=false;
+ }
+
flags[FLAG_VISIBLE]=true;
flags[FLAG_CAST_SHADOW]=true;
flags[FLAG_RECEIVE_SHADOWS]=true;
- flags[FLAG_BILLBOARD]=false;
- flags[FLAG_BILLBOARD_FIX_Y]=false;
- flags[FLAG_DEPH_SCALE]=false;
- flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false;
baked_light_instance=NULL;
+ baked_light_texture_id=0;
+ extra_cull_margin=0;
+ VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
}
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 1cf96d5d9e..3c69f09978 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,6 +47,7 @@ class VisualInstance : public Spatial {
RID _get_visual_instance_rid() const;
+
protected:
@@ -106,8 +107,11 @@ private:
float draw_end;
void _find_baked_light();
BakedLightInstance *baked_light_instance;
+ int baked_light_texture_id;
+ float extra_cull_margin;
void _baked_light_changed();
+ void _update_visibility();
protected:
void _notification(int p_what);
@@ -126,6 +130,12 @@ public:
void set_material_override(const Ref<Material>& p_material);
Ref<Material> get_material_override() const;
+ void set_baked_light_texture_id(int p_id);
+ int get_baked_light_texture_id() const;
+
+ void set_extra_cull_margin(float p_margin);
+ float get_extra_cull_margin() const;
+
GeometryInstance();
};
diff --git a/scene/SCsub b/scene/SCsub
index 28fb358106..6d1dd0044f 100644
--- a/scene/SCsub
+++ b/scene/SCsub
@@ -15,8 +15,6 @@ SConscript('resources/SCsub');
SConscript('io/SCsub');
-lib = env.Library("scene",env.scene_sources, LIBSUFFIX=env['platform_libsuffix'])
+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 38cfe0d8a9..b1d6da7294 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
-void AnimationCache::_node_exit_scene(Node *p_node) {
+void AnimationCache::_node_exit_tree(Node *p_node) {
//it is one shot, so it disconnects upon arrival
@@ -59,7 +59,7 @@ void AnimationCache::_clear_cache() {
while(connected_nodes.size()) {
- connected_nodes.front()->get()->disconnect("exit_scene",this,"_node_exit_scene");
+ connected_nodes.front()->get()->disconnect("exit_tree",this,"_node_exit_tree");
connected_nodes.erase(connected_nodes.front());
}
path_cache.clear();;
@@ -73,7 +73,7 @@ void AnimationCache::_update_cache() {
cache_valid=false;
ERR_FAIL_COND(!root);
- ERR_FAIL_COND(!root->is_inside_scene());
+ ERR_FAIL_COND(!root->is_inside_tree());
ERR_FAIL_COND(animation.is_null());
for(int i=0;i<animation->get_track_count();i++) {
@@ -206,7 +206,7 @@ void AnimationCache::_update_cache() {
if (!connected_nodes.has(path.node)) {
connected_nodes.insert(path.node);
- path.node->connect("exit_scene",this,"_node_exit_scene",Node::make_binds(path.node),CONNECT_ONESHOT);
+ path.node->connect("exit_tree",this,"_node_exit_tree",Node::make_binds(path.node),CONNECT_ONESHOT);
}
@@ -368,7 +368,7 @@ void AnimationCache::set_animation(const Ref<Animation>& p_animation) {
void AnimationCache::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("_node_exit_scene"),&AnimationCache::_node_exit_scene);
+ ObjectTypeDB::bind_method(_MD("_node_exit_tree"),&AnimationCache::_node_exit_tree);
ObjectTypeDB::bind_method(_MD("_animation_changed"),&AnimationCache::_animation_changed);
}
diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h
index 72ee8f1860..e94530d924 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -58,7 +58,7 @@ class AnimationCache : public Object {
bool cache_dirty;
bool cache_valid;
- void _node_exit_scene(Node *p_node);
+ void _node_exit_tree(Node *p_node);
void _clear_cache();
void _update_cache();
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 15d3dccb71..b040e59d16 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
@@ -180,12 +180,16 @@ void AnimationPlayer::_get_property_list( List<PropertyInfo> *p_list) const {
}
+void AnimationPlayer::advance(float p_time) {
+
+ _animation_process( p_time );
+}
void AnimationPlayer::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
if (!processing) {
//make sure that a previous process state was not saved
@@ -198,7 +202,7 @@ void AnimationPlayer::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- if (!get_scene()->is_editor_hint() && animation_set.has(autoplay)) {
+ if (!get_tree()->is_editor_hint() && animation_set.has(autoplay)) {
play(autoplay);
}
} break;
@@ -217,9 +221,9 @@ void AnimationPlayer::_notification(int p_what) {
if (processing)
_animation_process( get_fixed_process_delta_time() );
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
- stop_all();
+ //stop_all();
clear_caches();
} break;
}
@@ -257,13 +261,14 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) {
}
{
- if (!child->is_connected("exit_scene",this,"_node_removed"))
- child->connect("exit_scene",this,"_node_removed",make_binds(child),CONNECT_ONESHOT);
+ if (!child->is_connected("exit_tree",this,"_node_removed"))
+ child->connect("exit_tree",this,"_node_removed",make_binds(child),CONNECT_ONESHOT);
}
TrackNodeCacheKey key;
key.id=id;
key.bone_idx=bone_idx;
+
if (node_cache_map.has(key)) {
@@ -274,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>();
@@ -291,7 +297,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) {
p_anim->node_cache[i]->bone_idx=p_anim->node_cache[i]->skeleton->find_bone(bone_name);
if (p_anim->node_cache[i]->bone_idx<0) {
- // broken track (unexisting bone)
+ // broken track (nonexistent bone)
p_anim->node_cache[i]->skeleton=NULL;
p_anim->node_cache[i]->spatial=NULL;
printf("bone is %ls\n", String(bone_name).c_str());
@@ -316,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)
@@ -344,7 +351,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p
Animation *a=p_anim->animation.operator->();
- bool can_call = is_inside_scene() && !get_scene()->is_editor_hint();
+ bool can_call = is_inside_tree() && !get_tree()->is_editor_hint();
for (int i=0;i<a->get_track_count();i++) {
@@ -370,7 +377,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p
Error err = a->transform_track_interpolate(i,p_time,&loc,&rot,&scale);
- ERR_CONTINUE(err!=OK); //used for testing, should be removed
+ //ERR_CONTINUE(err!=OK); //used for testing, should be removed
if (err!=OK)
@@ -406,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);
@@ -432,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;
}
}
@@ -603,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
@@ -637,14 +716,15 @@ void AnimationPlayer::_animation_process(float p_delta) {
play(queued.front()->get());
String new_name = playback.assigned;
queued.pop_front();
+ end_notify=false;
emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name);
} else {
//stop();
playing = false;
_set_process(false);
+ end_notify=false;
emit_signal(SceneStringNames::get_singleton()->finished);
}
-
}
} else {
@@ -656,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());
@@ -849,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());
@@ -912,16 +1000,17 @@ void AnimationPlayer::play(const StringName& p_name, float p_custom_blend, float
c.current.speed_scale=p_custom_scale;
c.assigned=p_name;
- queued.clear();
+ if (!end_notify)
+ queued.clear();
_set_process(true); // always process when starting an animation
playing = true;
- if (is_inside_scene() && get_scene()->is_editor_hint())
+ if (is_inside_tree() && get_tree()->is_editor_hint())
return; // no next in this case
StringName next=animation_get_next(p_name);
- if (next!=StringName()) {
+ if (next!=StringName() && animation_set.has(next)) {
queue(next);
}
}
@@ -961,14 +1050,16 @@ String AnimationPlayer::get_current_animation() const {
}
-void AnimationPlayer::stop() {
+void AnimationPlayer::stop(bool p_reset) {
Playback &c=playback;
c.blend.clear();
- c.current.from=NULL;
+ if (p_reset) {
+ c.current.from=NULL;
+ }
_set_process(false);
queued.clear();
- playing = false;
+ playing = false;
}
void AnimationPlayer::stop_all() {
@@ -1172,6 +1263,19 @@ NodePath AnimationPlayer::get_root() const {
return root;
}
+void AnimationPlayer::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+
+ String pf = p_function;
+ if (p_function=="play" || p_function=="remove_animation" || p_function=="has_animation" || p_function=="queue") {
+ List<StringName> al;
+ get_animation_list(&al);
+ for (List<StringName>::Element *E=al.front();E;E=E->next()) {
+
+ r_options->push_back("\""+String(E->get())+"\"");
+ }
+ }
+ Node::get_argument_options(p_function,p_idx,r_options);
+}
void AnimationPlayer::_bind_methods() {
@@ -1192,7 +1296,8 @@ 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("stop"),&AnimationPlayer::stop);
+ 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);
ObjectTypeDB::bind_method(_MD("set_current_animation","anim"),&AnimationPlayer::set_current_animation);
@@ -1225,6 +1330,8 @@ void AnimationPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_current_animation_pos"),&AnimationPlayer::get_current_animation_pos);
ObjectTypeDB::bind_method(_MD("get_current_animation_length"),&AnimationPlayer::get_current_animation_length);
+ ObjectTypeDB::bind_method(_MD("advance","delta"),&AnimationPlayer::advance);
+
ADD_PROPERTY( PropertyInfo( Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_animation_process_mode"), _SCS("get_animation_process_mode"));
ADD_PROPERTY( PropertyInfo( Variant::REAL, "playback/default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), _SCS("set_default_blend_time"), _SCS("get_default_blend_time"));
@@ -1248,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 51c000d4d8..18cedee796 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,9 +260,10 @@ 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();
+ void stop(bool p_reset=true);
bool is_playing() const;
String get_current_animation() const;
void set_current_animation(const String& p_anim);
@@ -283,10 +286,15 @@ public:
float get_current_animation_pos() const;
float get_current_animation_length() const;
+ void advance(float p_time);
+
void set_root(const NodePath& p_root);
NodePath get_root() const;
void clear_caches(); ///< must be called by hand if an animation was modified after added
+
+ void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
+
AnimationPlayer();
~AnimationPlayer();
diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp
index bd124746ba..c7e259c3c6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -83,7 +124,8 @@ bool AnimationTreePlayer::_set(const StringName& p_name, const Variant& p_value)
ERR_FAIL_COND_V(nt==NODE_MAX,false);
- add_node(nt,id);
+ if (nt!=NODE_OUTPUT)
+ add_node(nt,id);
node_set_pos(id,pos);
@@ -189,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;
@@ -341,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()) {
@@ -353,7 +413,19 @@ 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;
}
@@ -655,10 +727,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;
@@ -674,7 +743,7 @@ void AnimationTreePlayer::_process_animation() {
_process_node(out_name,&prev, 1.0, 0, 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 );
if (dirty_caches) {
//some animation changed.. ignore this pass
@@ -1046,8 +1115,9 @@ void AnimationTreePlayer::timescale_node_set_scale(const StringName& p_node,floa
void AnimationTreePlayer::timeseek_node_seek(const StringName& p_node,float p_pos) {
-// GET_NODE( NODE_TIMESEEK, TimeSeekNode );
-//hmm
+ GET_NODE( NODE_TIMESEEK, TimeSeekNode );
+ n->seek_pos=p_pos;
+
}
void AnimationTreePlayer::transition_node_set_input_count(const StringName& p_node, int p_inputs) {
@@ -1518,8 +1588,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 {
@@ -1585,7 +1659,7 @@ void AnimationTreePlayer::_update_sources() {
if (master==NodePath())
return;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
Node *m = get_node(master);
@@ -1661,7 +1735,7 @@ void AnimationTreePlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("node_get_type","id"),&AnimationTreePlayer::node_get_type);
ObjectTypeDB::bind_method(_MD("node_get_input_count","id"),&AnimationTreePlayer::node_get_input_count);
- ObjectTypeDB::bind_method(_MD("node_get_input_sourcre","id","idx"),&AnimationTreePlayer::node_get_input_source);
+ ObjectTypeDB::bind_method(_MD("node_get_input_source","id","idx"),&AnimationTreePlayer::node_get_input_source);
ObjectTypeDB::bind_method(_MD("animation_node_set_animation","id","animation:Animation"),&AnimationTreePlayer::animation_node_set_animation);
ObjectTypeDB::bind_method(_MD("animation_node_get_animation:Animation","id"),&AnimationTreePlayer::animation_node_get_animation);
@@ -1736,12 +1810,23 @@ void AnimationTreePlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_base_path","path"),&AnimationTreePlayer::set_base_path);
ObjectTypeDB::bind_method(_MD("get_base_path"),&AnimationTreePlayer::get_base_path);
+ ObjectTypeDB::bind_method(_MD("set_master_player","nodepath"),&AnimationTreePlayer::set_master_player);
+ ObjectTypeDB::bind_method(_MD("get_master_player"),&AnimationTreePlayer::get_master_player);
+
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 );
@@ -1762,6 +1847,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 135e5f414e..9ea5ccf330 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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();
+ 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 990f55f9cb..d210f29db0 100644
--- a/scene/animation/transitioner.cpp
+++ b/scene/animation/transitioner.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/animation/transitioner.h b/scene/animation/transitioner.h
index 3cff5e6d49..dba83cddd8 100644
--- a/scene/animation/transitioner.h
+++ b/scene/animation/transitioner.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
new file mode 100644
index 0000000000..73d93e50ec
--- /dev/null
+++ b/scene/animation/tween.cpp
@@ -0,0 +1,1554 @@
+/*************************************************************************/
+/* tween.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 "tween.h"
+#include "method_bind_ext.inc"
+
+void Tween::_add_pending_command(StringName p_key
+ ,const Variant& p_arg1 ,const Variant& p_arg2 ,const Variant& p_arg3 ,const Variant& p_arg4 ,const Variant& p_arg5
+ ,const Variant& p_arg6 ,const Variant& p_arg7 ,const Variant& p_arg8 ,const Variant& p_arg9 ,const Variant& p_arg10
+) {
+
+ pending_commands.push_back(PendingCommand());
+ PendingCommand& cmd = pending_commands.back()->get();
+
+ cmd.key = p_key;
+ int& count = cmd.args;
+ if(p_arg10.get_type() != Variant::NIL)
+ count = 10;
+ else if(p_arg9.get_type() != Variant::NIL)
+ count = 9;
+ else if(p_arg8.get_type() != Variant::NIL)
+ count = 8;
+ else if(p_arg7.get_type() != Variant::NIL)
+ count = 7;
+ else if(p_arg6.get_type() != Variant::NIL)
+ count = 6;
+ else if(p_arg5.get_type() != Variant::NIL)
+ count = 5;
+ else if(p_arg4.get_type() != Variant::NIL)
+ count = 4;
+ else if(p_arg3.get_type() != Variant::NIL)
+ count = 3;
+ else if(p_arg2.get_type() != Variant::NIL)
+ count = 2;
+ else if(p_arg1.get_type() != Variant::NIL)
+ count = 1;
+ if(count > 0)
+ cmd.arg[0] = p_arg1;
+ if(count > 1)
+ cmd.arg[1] = p_arg2;
+ if(count > 2)
+ cmd.arg[2] = p_arg3;
+ if(count > 3)
+ cmd.arg[3] = p_arg4;
+ if(count > 4)
+ cmd.arg[4] = p_arg5;
+ if(count > 5)
+ cmd.arg[5] = p_arg6;
+ if(count > 6)
+ cmd.arg[6] = p_arg7;
+ if(count > 7)
+ cmd.arg[7] = p_arg8;
+ if(count > 8)
+ cmd.arg[8] = p_arg9;
+ if(count > 9)
+ cmd.arg[9] = p_arg10;
+}
+
+void Tween::_process_pending_commands() {
+
+ for(List<PendingCommand>::Element *E=pending_commands.front();E;E=E->next()) {
+
+ PendingCommand& cmd = E->get();
+ Variant::CallError err;
+ Variant *arg[10] = {
+ &cmd.arg[0],
+ &cmd.arg[1],
+ &cmd.arg[2],
+ &cmd.arg[3],
+ &cmd.arg[4],
+ &cmd.arg[5],
+ &cmd.arg[6],
+ &cmd.arg[7],
+ &cmd.arg[8],
+ &cmd.arg[9],
+ };
+ this->call(cmd.key, (const Variant **) arg, cmd.args, err);
+ }
+ pending_commands.clear();
+}
+
+bool Tween::_set(const StringName& p_name, const Variant& p_value) {
+
+ String name=p_name;
+
+ if (name=="playback/speed" || name=="speed") { //bw compatibility
+ set_speed(p_value);
+
+ } else if (name=="playback/active") {
+ set_active(p_value);
+
+ } else if (name=="playback/repeat") {
+ set_repeat(p_value);
+
+ }
+ return true;
+}
+
+bool Tween::_get(const StringName& p_name,Variant &r_ret) const {
+
+ String name=p_name;
+
+ if (name=="playback/speed") { //bw compatibility
+
+ r_ret=speed_scale;
+ } else if (name=="playback/active") {
+
+ r_ret=is_active();
+ } else if(name=="playback/repeat") {
+
+ r_ret=is_repeat();
+ }
+
+ return true;
+}
+
+void Tween::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ p_list->push_back( PropertyInfo( Variant::BOOL, "playback/active", PROPERTY_HINT_NONE,"" ) );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "playback/repeat", PROPERTY_HINT_NONE,"" ) );
+ p_list->push_back( PropertyInfo( Variant::REAL, "playback/speed", PROPERTY_HINT_RANGE, "-64,64,0.01") );
+}
+
+void Tween::_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: {
+
+ } break;
+ case NOTIFICATION_PROCESS: {
+ if (tween_process_mode==TWEEN_PROCESS_FIXED)
+ break;
+
+ if (processing)
+ _tween_process( get_process_delta_time() );
+ } break;
+ case NOTIFICATION_FIXED_PROCESS: {
+
+ if (tween_process_mode==TWEEN_PROCESS_IDLE)
+ break;
+
+ if (processing)
+ _tween_process( get_fixed_process_delta_time() );
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ stop_all();
+ } break;
+ }
+}
+
+void Tween::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("is_active"),&Tween::is_active );
+ ObjectTypeDB::bind_method(_MD("set_active","active"),&Tween::set_active );
+
+ ObjectTypeDB::bind_method(_MD("is_repeat"),&Tween::is_repeat );
+ ObjectTypeDB::bind_method(_MD("set_repeat","repeat"),&Tween::set_repeat );
+
+ ObjectTypeDB::bind_method(_MD("set_speed","speed"),&Tween::set_speed);
+ ObjectTypeDB::bind_method(_MD("get_speed"),&Tween::get_speed);
+
+ ObjectTypeDB::bind_method(_MD("set_tween_process_mode","mode"),&Tween::set_tween_process_mode);
+ ObjectTypeDB::bind_method(_MD("get_tween_process_mode"),&Tween::get_tween_process_mode);
+
+ ObjectTypeDB::bind_method(_MD("start"),&Tween::start );
+ ObjectTypeDB::bind_method(_MD("reset","object","key"),&Tween::reset );
+ ObjectTypeDB::bind_method(_MD("reset_all"),&Tween::reset_all );
+ ObjectTypeDB::bind_method(_MD("stop","object","key"),&Tween::stop );
+ ObjectTypeDB::bind_method(_MD("stop_all"),&Tween::stop_all );
+ ObjectTypeDB::bind_method(_MD("resume","object","key"),&Tween::resume );
+ ObjectTypeDB::bind_method(_MD("resume_all"),&Tween::resume_all );
+ ObjectTypeDB::bind_method(_MD("remove","object","key"),&Tween::remove );
+ ObjectTypeDB::bind_method(_MD("remove_all"),&Tween::remove_all );
+ ObjectTypeDB::bind_method(_MD("seek","time"),&Tween::seek );
+ ObjectTypeDB::bind_method(_MD("tell"),&Tween::tell );
+ ObjectTypeDB::bind_method(_MD("get_runtime"),&Tween::get_runtime );
+
+ ObjectTypeDB::bind_method(_MD("interpolate_property","object","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) );
+ ObjectTypeDB::bind_method(_MD("interpolate_method","object","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) );
+ ObjectTypeDB::bind_method(_MD("interpolate_callback","object","times_in_sec","callback","arg1", "arg2","arg3","arg4","arg5"),&Tween::interpolate_callback, DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()) );
+ ObjectTypeDB::bind_method(_MD("interpolate_deferred_callback","object","times_in_sec","callback","arg1","arg2","arg3","arg4","arg5"),&Tween::interpolate_deferred_callback, DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()) );
+ ObjectTypeDB::bind_method(_MD("follow_property","object","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) );
+ ObjectTypeDB::bind_method(_MD("follow_method","object","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) );
+ ObjectTypeDB::bind_method(_MD("targeting_property","object","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) );
+ ObjectTypeDB::bind_method(_MD("targeting_method","object","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) );
+
+ ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) );
+ ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) );
+ ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) );
+
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_tween_process_mode"), _SCS("get_tween_process_mode"));
+
+ BIND_CONSTANT(TWEEN_PROCESS_FIXED);
+ BIND_CONSTANT(TWEEN_PROCESS_IDLE);
+
+ BIND_CONSTANT(TRANS_LINEAR);
+ BIND_CONSTANT(TRANS_SINE);
+ BIND_CONSTANT(TRANS_QUINT);
+ BIND_CONSTANT(TRANS_QUART);
+ BIND_CONSTANT(TRANS_QUAD);
+ BIND_CONSTANT(TRANS_EXPO);
+ BIND_CONSTANT(TRANS_ELASTIC);
+ BIND_CONSTANT(TRANS_CUBIC);
+ BIND_CONSTANT(TRANS_CIRC);
+ BIND_CONSTANT(TRANS_BOUNCE);
+ BIND_CONSTANT(TRANS_BACK);
+
+ BIND_CONSTANT(EASE_IN);
+ BIND_CONSTANT(EASE_OUT);
+ BIND_CONSTANT(EASE_IN_OUT);
+ BIND_CONSTANT(EASE_OUT_IN);
+}
+
+Variant& Tween::_get_initial_val(InterpolateData& p_data) {
+
+ switch(p_data.type) {
+ case INTER_PROPERTY:
+ case INTER_METHOD:
+ case FOLLOW_PROPERTY:
+ case FOLLOW_METHOD:
+ return p_data.initial_val;
+
+ case TARGETING_PROPERTY:
+ case TARGETING_METHOD: {
+
+ Object *object = ObjectDB::get_instance(p_data.target_id);
+ ERR_FAIL_COND_V(object == NULL,p_data.initial_val);
+
+ static Variant initial_val;
+ if(p_data.type == TARGETING_PROPERTY) {
+
+ bool valid = false;
+ initial_val = object->get(p_data.target_key, &valid);
+ ERR_FAIL_COND_V(!valid,p_data.initial_val);
+ } else {
+
+ Variant::CallError error;
+ initial_val = object->call(p_data.target_key, NULL, 0, error);
+ ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK,p_data.initial_val);
+ }
+ return initial_val;
+ }
+ break;
+ }
+ return p_data.delta_val;
+}
+
+Variant& Tween::_get_delta_val(InterpolateData& p_data) {
+
+ switch(p_data.type) {
+ case INTER_PROPERTY:
+ case INTER_METHOD:
+ return p_data.delta_val;
+
+ case FOLLOW_PROPERTY:
+ case FOLLOW_METHOD: {
+
+ Object *target = ObjectDB::get_instance(p_data.target_id);
+ ERR_FAIL_COND_V(target == NULL,p_data.initial_val);
+
+ Variant final_val;
+
+ if(p_data.type == FOLLOW_PROPERTY) {
+
+ bool valid = false;
+ final_val = target->get(p_data.target_key, &valid);
+ ERR_FAIL_COND_V(!valid,p_data.initial_val);
+ } else {
+
+ Variant::CallError error;
+ final_val = target->call(p_data.target_key, NULL, 0, error);
+ ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK,p_data.initial_val);
+ }
+
+ // convert INT to REAL is better for interpolaters
+ if(final_val.get_type() == Variant::INT) final_val = final_val.operator real_t();
+ _calc_delta_val(p_data.initial_val, final_val, p_data.delta_val);
+ return p_data.delta_val;
+ }
+ break;
+
+ case TARGETING_PROPERTY:
+ case TARGETING_METHOD: {
+
+ Variant initial_val = _get_initial_val(p_data);
+ // convert INT to REAL is better for interpolaters
+ if(initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t();
+
+ //_calc_delta_val(p_data.initial_val, p_data.final_val, p_data.delta_val);
+ _calc_delta_val(initial_val, p_data.final_val, p_data.delta_val);
+ return p_data.delta_val;
+ }
+ break;
+ }
+ return p_data.initial_val;
+}
+
+Variant Tween::_run_equation(InterpolateData& p_data) {
+
+ Variant& initial_val = _get_initial_val(p_data);
+ Variant& delta_val = _get_delta_val(p_data);
+ Variant result;
+
+#define APPLY_EQUATION(element)\
+ r.element = _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, i.element, d.element, p_data.times_in_sec);
+
+ switch(initial_val.get_type())
+ {
+
+ case Variant::BOOL:
+ result = ( _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, initial_val, delta_val, p_data.times_in_sec)) >= 0.5;
+ break;
+
+ case Variant::INT:
+ result = (int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec);
+ break;
+
+ case Variant::REAL:
+ result = _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (real_t) initial_val, (real_t) delta_val, p_data.times_in_sec);
+ break;
+
+ case Variant::VECTOR2:
+ {
+ Vector2 i = initial_val;
+ Vector2 d = delta_val;
+ Vector2 r;
+
+ APPLY_EQUATION(x);
+ APPLY_EQUATION(y);
+
+ result = r;
+ }
+ break;
+
+ case Variant::VECTOR3:
+ {
+ Vector3 i = initial_val;
+ Vector3 d = delta_val;
+ Vector3 r;
+
+ APPLY_EQUATION(x);
+ APPLY_EQUATION(y);
+ APPLY_EQUATION(z);
+
+ result = r;
+ }
+ break;
+
+ case Variant::MATRIX3:
+ {
+ Matrix3 i = initial_val;
+ Matrix3 d = delta_val;
+ Matrix3 r;
+
+ APPLY_EQUATION(elements[0][0]);
+ APPLY_EQUATION(elements[0][1]);
+ APPLY_EQUATION(elements[0][2]);
+ APPLY_EQUATION(elements[1][0]);
+ APPLY_EQUATION(elements[1][1]);
+ APPLY_EQUATION(elements[1][2]);
+ APPLY_EQUATION(elements[2][0]);
+ APPLY_EQUATION(elements[2][1]);
+ APPLY_EQUATION(elements[2][2]);
+
+ result = r;
+ }
+ break;
+
+ case Variant::MATRIX32:
+ {
+ Matrix3 i = initial_val;
+ Matrix3 d = delta_val;
+ Matrix3 r;
+
+ APPLY_EQUATION(elements[0][0]);
+ APPLY_EQUATION(elements[0][1]);
+ APPLY_EQUATION(elements[1][0]);
+ APPLY_EQUATION(elements[1][1]);
+ APPLY_EQUATION(elements[2][0]);
+ APPLY_EQUATION(elements[2][1]);
+
+ result = r;
+ }
+ break;
+ case Variant::QUAT:
+ {
+ Quat i = initial_val;
+ Quat d = delta_val;
+ Quat r;
+
+ APPLY_EQUATION(x);
+ APPLY_EQUATION(y);
+ APPLY_EQUATION(z);
+ APPLY_EQUATION(w);
+
+ result = r;
+ }
+ break;
+ case Variant::_AABB:
+ {
+ AABB i = initial_val;
+ AABB d = delta_val;
+ AABB r;
+
+ APPLY_EQUATION(pos.x);
+ APPLY_EQUATION(pos.y);
+ APPLY_EQUATION(pos.z);
+ APPLY_EQUATION(size.x);
+ APPLY_EQUATION(size.y);
+ APPLY_EQUATION(size.z);
+
+ result = r;
+ }
+ break;
+ case Variant::TRANSFORM:
+ {
+ Transform i = initial_val;
+ Transform d = delta_val;
+ Transform r;
+
+ APPLY_EQUATION(basis.elements[0][0]);
+ APPLY_EQUATION(basis.elements[0][1]);
+ APPLY_EQUATION(basis.elements[0][2]);
+ APPLY_EQUATION(basis.elements[1][0]);
+ APPLY_EQUATION(basis.elements[1][1]);
+ APPLY_EQUATION(basis.elements[1][2]);
+ APPLY_EQUATION(basis.elements[2][0]);
+ APPLY_EQUATION(basis.elements[2][1]);
+ APPLY_EQUATION(basis.elements[2][2]);
+ APPLY_EQUATION(origin.x);
+ APPLY_EQUATION(origin.y);
+ APPLY_EQUATION(origin.z);
+
+ result = r;
+ }
+ break;
+ case Variant::COLOR:
+ {
+ Color i = initial_val;
+ Color d = delta_val;
+ Color r;
+
+ APPLY_EQUATION(r);
+ APPLY_EQUATION(g);
+ APPLY_EQUATION(b);
+ APPLY_EQUATION(a);
+
+ result = r;
+ }
+ break;
+ };
+#undef APPLY_EQUATION
+
+ return result;
+}
+
+bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) {
+
+ Object *object = ObjectDB::get_instance(p_data.id);
+ ERR_FAIL_COND_V(object == NULL, false);
+
+ switch(p_data.type) {
+
+ case INTER_PROPERTY:
+ case FOLLOW_PROPERTY:
+ case TARGETING_PROPERTY:
+ {
+ bool valid = false;
+ object->set(p_data.key,value, &valid);
+ return valid;
+ }
+
+ case INTER_METHOD:
+ case FOLLOW_METHOD:
+ case TARGETING_METHOD:
+ {
+ Variant::CallError error;
+ if (value.get_type() != Variant::NIL) {
+ Variant *arg[1] = { &value };
+ object->call(p_data.key, (const Variant **) arg, 1, error);
+ } else {
+ object->call(p_data.key, NULL, 0, error);
+ }
+
+ if(error.error == Variant::CallError::CALL_OK)
+ return true;
+ return false;
+ }
+
+ case INTER_CALLBACK:
+ break;
+ };
+ return true;
+}
+
+void Tween::_tween_process(float p_delta) {
+
+ _process_pending_commands();
+
+ if (speed_scale == 0)
+ return;
+ p_delta *= speed_scale;
+
+ pending_update ++;
+ // if repeat and all interpolates was finished then reset all interpolates
+ if(repeat) {
+ bool all_finished = true;
+
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+
+ if(!data.finish) {
+ all_finished = false;
+ break;
+ }
+ }
+
+ if(all_finished)
+ reset_all();
+ }
+
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+ if(!data.active || data.finish)
+ continue;
+
+ Object *object = ObjectDB::get_instance(data.id);
+ if(object == NULL)
+ continue;
+
+ bool prev_delaying = data.elapsed <= data.delay;
+ data.elapsed += p_delta;
+ if(data.elapsed < data.delay)
+ continue;
+ else if(prev_delaying) {
+
+ emit_signal("tween_start",object,data.key);
+ _apply_tween_value(data, data.initial_val);
+ }
+
+ if(data.elapsed > (data.delay + data.times_in_sec)) {
+
+ data.elapsed = data.delay + data.times_in_sec;
+ data.finish = true;
+ }
+
+ switch(data.type)
+ {
+ case INTER_PROPERTY:
+ case INTER_METHOD:
+ break;
+ case INTER_CALLBACK:
+ if(data.finish) {
+
+ Variant::CallError error;
+ if (data.call_deferred) {
+
+ switch (data.args) {
+ case 0:
+ object->call_deferred(data.key); break;
+ case 1:
+ object->call_deferred(data.key, data.arg[0]); break;
+ case 2:
+ object->call_deferred(data.key, data.arg[0], data.arg[1]); break;
+ case 3:
+ object->call_deferred(data.key, data.arg[0], data.arg[1], data.arg[2]); break;
+ case 4:
+ object->call_deferred(data.key, data.arg[0], data.arg[1], data.arg[2], data.arg[3]); break;
+ case 5:
+ object->call_deferred(data.key, data.arg[0], data.arg[1], data.arg[2], data.arg[3], data.arg[4]); break;
+ }
+
+ }
+ else {
+ Variant *arg[5] = {
+ &data.arg[0],
+ &data.arg[1],
+ &data.arg[2],
+ &data.arg[3],
+ &data.arg[4],
+ };
+ object->call(data.key, (const Variant **) arg, data.args, error);
+ }
+ }
+ continue;
+ }
+
+ Variant result = _run_equation(data);
+ emit_signal("tween_step",object,data.key,data.elapsed,result);
+
+ _apply_tween_value(data, result);
+
+ if (data.finish) {
+ emit_signal("tween_complete",object,data.key);
+ // not repeat mode, remove completed action
+ if (!repeat)
+ call_deferred("remove", object, data.key);
+ }
+ }
+ pending_update --;
+}
+
+void Tween::set_tween_process_mode(TweenProcessMode p_mode) {
+
+ if (tween_process_mode==p_mode)
+ return;
+
+ bool pr = processing;
+ if (pr)
+ _set_process(false);
+ tween_process_mode=p_mode;
+ if (pr)
+ _set_process(true);
+}
+
+Tween::TweenProcessMode Tween::get_tween_process_mode() const {
+
+ return tween_process_mode;
+}
+
+void Tween::_set_process(bool p_process,bool p_force) {
+
+ if (processing==p_process && !p_force)
+ return;
+
+ switch(tween_process_mode) {
+
+ case TWEEN_PROCESS_FIXED: set_fixed_process(p_process && active); break;
+ case TWEEN_PROCESS_IDLE: set_process(p_process && active); break;
+ }
+
+ processing=p_process;
+}
+
+bool Tween::is_active() const {
+
+ return active;
+}
+
+void Tween::set_active(bool p_active) {
+
+ if (active==p_active)
+ return;
+
+ active=p_active;
+ _set_process(processing,true);
+}
+
+bool Tween::is_repeat() const {
+
+ return repeat;
+}
+
+void Tween::set_repeat(bool p_repeat) {
+
+ repeat = p_repeat;
+}
+
+void Tween::set_speed(float p_speed) {
+
+ speed_scale=p_speed;
+}
+
+float Tween::get_speed() const {
+
+ return speed_scale;
+}
+
+bool Tween::start() {
+
+ set_active(true);
+ _set_process(true);
+ return true;
+}
+
+bool Tween::reset(Object *p_object, String p_key) {
+
+ pending_update ++;
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+ Object *object = ObjectDB::get_instance(data.id);
+ if(object == NULL)
+ continue;
+
+ if(object == p_object && data.key == p_key) {
+
+ data.elapsed = 0;
+ data.finish = false;
+ if(data.delay == 0)
+ _apply_tween_value(data, data.initial_val);
+ }
+ }
+ pending_update --;
+ return true;
+}
+
+bool Tween::reset_all() {
+
+ pending_update ++;
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+ data.elapsed = 0;
+ data.finish = false;
+ if(data.delay == 0)
+ _apply_tween_value(data, data.initial_val);
+ }
+ pending_update --;
+ return true;
+}
+
+bool Tween::stop(Object *p_object, String p_key) {
+
+ pending_update ++;
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+ Object *object = ObjectDB::get_instance(data.id);
+ if(object == NULL)
+ continue;
+ if(object == p_object && data.key == p_key)
+ data.active = false;
+ }
+ pending_update --;
+ return true;
+}
+
+bool Tween::stop_all() {
+
+ set_active(false);
+ _set_process(false);
+
+ pending_update ++;
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+ data.active = false;
+ }
+ pending_update --;
+ return true;
+}
+
+bool Tween::resume(Object *p_object, String p_key) {
+
+ set_active(true);
+ _set_process(true);
+
+ pending_update ++;
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+ Object *object = ObjectDB::get_instance(data.id);
+ if(object == NULL)
+ continue;
+ if(object == p_object && data.key == p_key)
+ data.active = true;
+ }
+ pending_update --;
+ return true;
+}
+
+bool Tween::resume_all() {
+
+ set_active(true);
+ _set_process(true);
+
+ pending_update ++;
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+ data.active = true;
+ }
+ pending_update --;
+ return true;
+}
+
+bool Tween::remove(Object *p_object, String p_key) {
+
+ if(pending_update != 0) {
+ call_deferred("remove", p_object, p_key);
+ return true;
+ }
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+ Object *object = ObjectDB::get_instance(data.id);
+ if(object == NULL)
+ continue;
+ if(object == p_object && data.key == p_key) {
+ interpolates.erase(E);
+ return true;
+ }
+ }
+ return true;
+}
+
+bool Tween::remove_all() {
+
+ if(pending_update != 0) {
+ call_deferred("remove_all");
+ return true;
+ }
+ set_active(false);
+ _set_process(false);
+ interpolates.clear();
+ return true;
+}
+
+bool Tween::seek(real_t p_time) {
+
+ pending_update ++;
+ for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ InterpolateData& data = E->get();
+
+ data.elapsed = p_time;
+ if(data.elapsed < data.delay) {
+
+ data.finish = false;
+ continue;
+ }
+ else if(data.elapsed >= (data.delay + data.times_in_sec)) {
+
+ data.finish = true;
+ data.elapsed = (data.delay + data.times_in_sec);
+ } else
+ data.finish = false;
+
+ switch(data.type)
+ {
+ case INTER_PROPERTY:
+ case INTER_METHOD:
+ break;
+ case INTER_CALLBACK:
+ continue;
+ }
+
+ Variant result = _run_equation(data);
+
+ _apply_tween_value(data, result);
+ }
+ pending_update --;
+ return true;
+}
+
+real_t Tween::tell() const {
+
+ pending_update ++;
+ real_t pos = 0;
+ for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ const InterpolateData& data = E->get();
+ if(data.elapsed > pos)
+ pos = data.elapsed;
+ }
+ pending_update --;
+ return pos;
+}
+
+real_t Tween::get_runtime() const {
+
+ pending_update ++;
+ real_t runtime = 0;
+ for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
+
+ const InterpolateData& data = E->get();
+ real_t t = data.delay + data.times_in_sec;
+ if(t > runtime)
+ runtime = t;
+ }
+ pending_update --;
+ return runtime;
+}
+
+bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final_val, Variant& p_delta_val) {
+
+ const Variant& initial_val = p_initial_val;
+ const Variant& final_val = p_final_val;
+ Variant& delta_val = p_delta_val;
+
+ switch(initial_val.get_type()) {
+
+ case Variant::BOOL:
+ //delta_val = p_final_val;
+ delta_val = (int) p_final_val - (int) p_initial_val;
+ break;
+
+ case Variant::INT:
+ delta_val = (int) final_val - (int) initial_val;
+ break;
+
+ case Variant::REAL:
+ delta_val = (real_t) final_val - (real_t) initial_val;
+ break;
+
+ case Variant::VECTOR2:
+ delta_val = final_val.operator Vector2() - initial_val.operator Vector2();
+ break;
+
+ case Variant::VECTOR3:
+ delta_val = final_val.operator Vector3() - initial_val.operator Vector3();
+ break;
+
+ case Variant::MATRIX3:
+ {
+ Matrix3 i = initial_val;
+ Matrix3 f = final_val;
+ delta_val = Matrix3(f.elements[0][0] - i.elements[0][0],
+ f.elements[0][1] - i.elements[0][1],
+ f.elements[0][2] - i.elements[0][2],
+ f.elements[1][0] - i.elements[1][0],
+ f.elements[1][1] - i.elements[1][1],
+ f.elements[1][2] - i.elements[1][2],
+ f.elements[2][0] - i.elements[2][0],
+ f.elements[2][1] - i.elements[2][1],
+ f.elements[2][2] - i.elements[2][2]
+ );
+ }
+ break;
+
+ case Variant::MATRIX32:
+ {
+ Matrix32 i = initial_val;
+ Matrix32 f = final_val;
+ Matrix32 d = Matrix32();
+ d[0][0] = f.elements[0][0] - i.elements[0][0];
+ d[0][1] = f.elements[0][1] - i.elements[0][1];
+ d[1][0] = f.elements[1][0] - i.elements[1][0];
+ d[1][1] = f.elements[1][1] - i.elements[1][1];
+ d[2][0] = f.elements[2][0] - i.elements[2][0];
+ d[2][1] = f.elements[2][1] - i.elements[2][1];
+ delta_val = d;
+ }
+ break;
+ case Variant::QUAT:
+ delta_val = final_val.operator Quat() - initial_val.operator Quat();
+ break;
+ case Variant::_AABB:
+ {
+ AABB i = initial_val;
+ AABB f = final_val;
+ delta_val = AABB(f.pos - i.pos, f.size - i.size);
+ }
+ break;
+ case Variant::TRANSFORM:
+ {
+ Transform i = initial_val;
+ Transform f = final_val;
+ Transform d;
+ d.set(f.basis.elements[0][0] - i.basis.elements[0][0],
+ f.basis.elements[0][1] - i.basis.elements[0][1],
+ f.basis.elements[0][2] - i.basis.elements[0][2],
+ f.basis.elements[1][0] - i.basis.elements[1][0],
+ f.basis.elements[1][1] - i.basis.elements[1][1],
+ f.basis.elements[1][2] - i.basis.elements[1][2],
+ f.basis.elements[2][0] - i.basis.elements[2][0],
+ f.basis.elements[2][1] - i.basis.elements[2][1],
+ f.basis.elements[2][2] - i.basis.elements[2][2],
+ f.origin.x - i.origin.x,
+ f.origin.y - i.origin.y,
+ f.origin.z - i.origin.z
+ );
+
+ delta_val = d;
+ }
+ break;
+ case Variant::COLOR:
+ {
+ Color i = initial_val;
+ Color f = final_val;
+ delta_val = Color(f.r - i.r, f.g - i.g, f.b - i.b, f.a - i.a);
+ }
+ break;
+
+ default:
+ ERR_PRINT("Invalid param type, except(int/real/vector2/vector/matrix/matrix32/quat/aabb/transform/color)");
+ return false;
+ };
+ return true;
+}
+
+bool Tween::interpolate_property(Object *p_object
+ , String p_property
+ , Variant p_initial_val
+ , Variant p_final_val
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay
+) {
+ if(pending_update != 0) {
+ _add_pending_command("interpolate_property"
+ , p_object
+ , p_property
+ , p_initial_val
+ , p_final_val
+ , p_times_in_sec
+ , p_trans_type
+ , p_ease_type
+ , p_delay
+ );
+ return true;
+ }
+ // convert INT to REAL is better for interpolaters
+ if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
+ if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
+
+ ERR_FAIL_COND_V(p_object == NULL, false);
+ ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false);
+ ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
+ ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
+ ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
+ ERR_FAIL_COND_V(p_delay < 0, false);
+
+ bool prop_valid = false;
+ p_object->get(p_property,&prop_valid);
+ ERR_FAIL_COND_V(!prop_valid, false);
+
+ InterpolateData data;
+ data.active = true;
+ data.type = INTER_PROPERTY;
+ data.finish = false;
+ data.elapsed = 0;
+
+ data.id = p_object->get_instance_ID();
+ data.key = p_property;
+ data.initial_val = p_initial_val;
+ data.final_val = p_final_val;
+ data.times_in_sec = p_times_in_sec;
+ data.trans_type = p_trans_type;
+ data.ease_type = p_ease_type;
+ data.delay = p_delay;
+
+ if(!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
+ return false;
+
+ interpolates.push_back(data);
+ return true;
+}
+
+bool Tween::interpolate_method(Object *p_object
+ , String p_method
+ , Variant p_initial_val
+ , Variant p_final_val
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay
+) {
+ if(pending_update != 0) {
+ _add_pending_command("interpolate_method"
+ , p_object
+ , p_method
+ , p_initial_val
+ , p_final_val
+ , p_times_in_sec
+ , p_trans_type
+ , p_ease_type
+ , p_delay
+ );
+ return true;
+ }
+ // convert INT to REAL is better for interpolaters
+ if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
+ if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
+
+ ERR_FAIL_COND_V(p_object == NULL, false);
+ ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false);
+ ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
+ ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
+ ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
+ ERR_FAIL_COND_V(p_delay < 0, false);
+
+ ERR_EXPLAIN("Object has no method named: %s" + p_method);
+ ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
+
+ InterpolateData data;
+ data.active = true;
+ data.type = INTER_METHOD;
+ data.finish = false;
+ data.elapsed = 0;
+
+ data.id = p_object->get_instance_ID();
+ data.key = p_method;
+ data.initial_val = p_initial_val;
+ data.final_val = p_final_val;
+ data.times_in_sec = p_times_in_sec;
+ data.trans_type = p_trans_type;
+ data.ease_type = p_ease_type;
+ data.delay = p_delay;
+
+ if(!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
+ return false;
+
+ interpolates.push_back(data);
+ return true;
+}
+
+bool Tween::interpolate_callback(Object *p_object
+ , real_t p_times_in_sec
+ , String p_callback
+ , VARIANT_ARG_DECLARE
+) {
+
+ if(pending_update != 0) {
+ _add_pending_command("interpolate_callback"
+ , p_object
+ , p_times_in_sec
+ , p_callback
+ , p_arg1
+ , p_arg2
+ , p_arg3
+ , p_arg4
+ , p_arg5
+ );
+ return true;
+ }
+ ERR_FAIL_COND_V(p_object == NULL, false);
+ ERR_FAIL_COND_V(p_times_in_sec < 0, false);
+
+ ERR_EXPLAIN("Object has no callback named: %s" + p_callback);
+ ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
+
+ InterpolateData data;
+ data.active = true;
+ data.type = INTER_CALLBACK;
+ data.finish = false;
+ data.call_deferred = false;
+ data.elapsed = 0;
+
+ data.id = p_object->get_instance_ID();
+ data.key = p_callback;
+ data.times_in_sec = p_times_in_sec;
+ data.delay = 0;
+
+ 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;
+
+ data.args = args;
+ data.arg[0] = p_arg1;
+ data.arg[1] = p_arg2;
+ data.arg[2] = p_arg3;
+ data.arg[3] = p_arg4;
+ data.arg[4] = p_arg5;
+
+ pending_update ++;
+ interpolates.push_back(data);
+ pending_update --;
+ return true;
+}
+
+bool Tween::interpolate_deferred_callback(Object *p_object
+ , real_t p_times_in_sec
+ , String p_callback
+ , VARIANT_ARG_DECLARE
+) {
+
+ if(pending_update != 0) {
+ _add_pending_command("interpolate_deferred_callback"
+ , p_object
+ , p_times_in_sec
+ , p_callback
+ , p_arg1
+ , p_arg2
+ , p_arg3
+ , p_arg4
+ , p_arg5
+ );
+ return true;
+ }
+ ERR_FAIL_COND_V(p_object == NULL, false);
+ ERR_FAIL_COND_V(p_times_in_sec < 0, false);
+
+ ERR_EXPLAIN("Object has no callback named: %s" + p_callback);
+ ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
+
+ InterpolateData data;
+ data.active = true;
+ data.type = INTER_CALLBACK;
+ data.finish = false;
+ data.call_deferred = true;
+ data.elapsed = 0;
+
+ data.id = p_object->get_instance_ID();
+ data.key = p_callback;
+ data.times_in_sec = p_times_in_sec;
+ data.delay = 0;
+
+ 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;
+
+ data.args = args;
+ data.arg[0] = p_arg1;
+ data.arg[1] = p_arg2;
+ data.arg[2] = p_arg3;
+ data.arg[3] = p_arg4;
+ data.arg[4] = p_arg5;
+
+ pending_update ++;
+ interpolates.push_back(data);
+ pending_update --;
+ return true;
+}
+
+bool Tween::follow_property(Object *p_object
+ , String p_property
+ , Variant p_initial_val
+ , Object *p_target
+ , String p_target_property
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay
+) {
+ if(pending_update != 0) {
+ _add_pending_command("follow_property"
+ , p_object
+ , p_property
+ , p_initial_val
+ , p_target
+ , p_target_property
+ , p_times_in_sec
+ , p_trans_type
+ , p_ease_type
+ , p_delay
+ );
+ return true;
+ }
+ // convert INT to REAL is better for interpolaters
+ if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
+
+ ERR_FAIL_COND_V(p_object == NULL, false);
+ ERR_FAIL_COND_V(p_target == NULL, false);
+ ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
+ ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
+ ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
+ ERR_FAIL_COND_V(p_delay < 0, false);
+
+ bool prop_valid = false;
+ p_object->get(p_property,&prop_valid);
+ ERR_FAIL_COND_V(!prop_valid, false);
+
+ bool target_prop_valid = false;
+ Variant target_val = p_target->get(p_target_property,&target_prop_valid);
+ ERR_FAIL_COND_V(!target_prop_valid, false);
+
+ // convert INT to REAL is better for interpolaters
+ if(target_val.get_type() == Variant::INT) target_val = target_val.operator real_t();
+ ERR_FAIL_COND_V(target_val.get_type() != p_initial_val.get_type(), false);
+
+ InterpolateData data;
+ data.active = true;
+ data.type = FOLLOW_PROPERTY;
+ data.finish = false;
+ data.elapsed = 0;
+
+ data.id = p_object->get_instance_ID();
+ data.key = p_property;
+ data.initial_val = p_initial_val;
+ data.target_id = p_target->get_instance_ID();
+ data.target_key = p_target_property;
+ data.times_in_sec = p_times_in_sec;
+ data.trans_type = p_trans_type;
+ data.ease_type = p_ease_type;
+ data.delay = p_delay;
+
+ interpolates.push_back(data);
+ return true;
+}
+
+bool Tween::follow_method(Object *p_object
+ , String p_method
+ , Variant p_initial_val
+ , Object *p_target
+ , String p_target_method
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay
+) {
+ if(pending_update != 0) {
+ _add_pending_command("follow_method"
+ , p_object
+ , p_method
+ , p_initial_val
+ , p_target
+ , p_target_method
+ , p_times_in_sec
+ , p_trans_type
+ , p_ease_type
+ , p_delay
+ );
+ return true;
+ }
+ // convert INT to REAL is better for interpolaters
+ if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
+
+ ERR_FAIL_COND_V(p_object == NULL, false);
+ ERR_FAIL_COND_V(p_target == NULL, false);
+ ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
+ ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
+ ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
+ ERR_FAIL_COND_V(p_delay < 0, false);
+
+ ERR_EXPLAIN("Object has no method named: %s" + p_method);
+ ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
+ ERR_EXPLAIN("Target has no method named: %s" + p_target_method);
+ ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false);
+
+ Variant::CallError error;
+ Variant target_val = p_target->call(p_target_method, NULL, 0, error);
+ ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, false);
+
+ // convert INT to REAL is better for interpolaters
+ if(target_val.get_type() == Variant::INT) target_val = target_val.operator real_t();
+ ERR_FAIL_COND_V(target_val.get_type() != p_initial_val.get_type(), false);
+
+ InterpolateData data;
+ data.active = true;
+ data.type = FOLLOW_METHOD;
+ data.finish = false;
+ data.elapsed = 0;
+
+ data.id = p_object->get_instance_ID();
+ data.key = p_method;
+ data.initial_val = p_initial_val;
+ data.target_id = p_target->get_instance_ID();
+ data.target_key = p_target_method;
+ data.times_in_sec = p_times_in_sec;
+ data.trans_type = p_trans_type;
+ data.ease_type = p_ease_type;
+ data.delay = p_delay;
+
+ interpolates.push_back(data);
+ return true;
+}
+
+bool Tween::targeting_property(Object *p_object
+ , String p_property
+ , Object *p_initial
+ , String p_initial_property
+ , Variant p_final_val
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay
+) {
+ if(pending_update != 0) {
+ _add_pending_command("targeting_property"
+ , p_object
+ , p_property
+ , p_initial
+ , p_initial_property
+ , p_final_val
+ , p_times_in_sec
+ , p_trans_type
+ , p_ease_type
+ , p_delay
+ );
+ return true;
+ }
+ // convert INT to REAL is better for interpolaters
+ if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
+
+ ERR_FAIL_COND_V(p_object == NULL, false);
+ ERR_FAIL_COND_V(p_initial == NULL, false);
+ ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
+ ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
+ ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
+ ERR_FAIL_COND_V(p_delay < 0, false);
+
+ bool prop_valid = false;
+ p_object->get(p_property,&prop_valid);
+ ERR_FAIL_COND_V(!prop_valid, false);
+
+ bool initial_prop_valid = false;
+ Variant initial_val = p_initial->get(p_initial_property,&initial_prop_valid);
+ ERR_FAIL_COND_V(!initial_prop_valid, false);
+
+ // convert INT to REAL is better for interpolaters
+ if(initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t();
+ ERR_FAIL_COND_V(initial_val.get_type() != p_final_val.get_type(), false);
+
+ InterpolateData data;
+ data.active = true;
+ data.type = TARGETING_PROPERTY;
+ data.finish = false;
+ data.elapsed = 0;
+
+ data.id = p_object->get_instance_ID();
+ data.key = p_property;
+ data.target_id = p_initial->get_instance_ID();
+ data.target_key = p_initial_property;
+ data.initial_val = initial_val;
+ data.final_val = p_final_val;
+ data.times_in_sec = p_times_in_sec;
+ data.trans_type = p_trans_type;
+ data.ease_type = p_ease_type;
+ data.delay = p_delay;
+
+ if(!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
+ return false;
+
+ interpolates.push_back(data);
+ return true;
+}
+
+
+bool Tween::targeting_method(Object *p_object
+ , String p_method
+ , Object *p_initial
+ , String p_initial_method
+ , Variant p_final_val
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay
+) {
+ if(pending_update != 0) {
+ _add_pending_command("targeting_method"
+ , p_object
+ , p_method
+ , p_initial
+ , p_initial_method
+ , p_final_val
+ , p_times_in_sec
+ , p_trans_type
+ , p_ease_type
+ , p_delay
+ );
+ return true;
+ }
+ // convert INT to REAL is better for interpolaters
+ if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
+
+ ERR_FAIL_COND_V(p_object == NULL, false);
+ ERR_FAIL_COND_V(p_initial == NULL, false);
+ ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
+ ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
+ ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
+ ERR_FAIL_COND_V(p_delay < 0, false);
+
+ ERR_EXPLAIN("Object has no method named: %s" + p_method);
+ ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
+ ERR_EXPLAIN("Initial Object has no method named: %s" + p_initial_method);
+ ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false);
+
+ Variant::CallError error;
+ Variant initial_val = p_initial->call(p_initial_method, NULL, 0, error);
+ ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, false);
+
+ // convert INT to REAL is better for interpolaters
+ if(initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t();
+ ERR_FAIL_COND_V(initial_val.get_type() != p_final_val.get_type(), false);
+
+ InterpolateData data;
+ data.active = true;
+ data.type = TARGETING_METHOD;
+ data.finish = false;
+ data.elapsed = 0;
+
+ data.id = p_object->get_instance_ID();
+ data.key = p_method;
+ data.target_id = p_initial->get_instance_ID();
+ data.target_key = p_initial_method;
+ data.initial_val = initial_val;
+ data.final_val = p_final_val;
+ data.times_in_sec = p_times_in_sec;
+ data.trans_type = p_trans_type;
+ data.ease_type = p_ease_type;
+ data.delay = p_delay;
+
+ if(!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
+ return false;
+
+ interpolates.push_back(data);
+ return true;
+}
+
+Tween::Tween() {
+
+ //String autoplay;
+ tween_process_mode=TWEEN_PROCESS_IDLE;
+ processing=false;
+ active=false;
+ repeat=false;
+ speed_scale=1;
+ pending_update=0;
+}
+
+Tween::~Tween() {
+
+}
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
new file mode 100644
index 0000000000..d504c63d8a
--- /dev/null
+++ b/scene/animation/tween.h
@@ -0,0 +1,269 @@
+/*************************************************************************/
+/* tween.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 TWEEN_H
+#define TWEEN_H
+
+#include "scene/main/node.h"
+
+
+class Tween : public Node {
+
+ OBJ_TYPE( Tween, Node );
+
+public:
+ enum TweenProcessMode {
+ TWEEN_PROCESS_FIXED,
+ TWEEN_PROCESS_IDLE,
+ };
+
+ enum TransitionType {
+ TRANS_LINEAR,
+ TRANS_SINE,
+ TRANS_QUINT,
+ TRANS_QUART,
+ TRANS_QUAD,
+ TRANS_EXPO,
+ TRANS_ELASTIC,
+ TRANS_CUBIC,
+ TRANS_CIRC,
+ TRANS_BOUNCE,
+ TRANS_BACK,
+
+ TRANS_COUNT,
+ };
+
+ enum EaseType {
+ EASE_IN,
+ EASE_OUT,
+ EASE_IN_OUT,
+ EASE_OUT_IN,
+
+ EASE_COUNT,
+ };
+
+private:
+ enum InterpolateType {
+
+ INTER_PROPERTY,
+ INTER_METHOD,
+ FOLLOW_PROPERTY,
+ FOLLOW_METHOD,
+ TARGETING_PROPERTY,
+ TARGETING_METHOD,
+ INTER_CALLBACK,
+ };
+
+ struct InterpolateData {
+ bool active;
+ InterpolateType type;
+ bool finish;
+ bool call_deferred;
+ real_t elapsed;
+ ObjectID id;
+ StringName key;
+ Variant initial_val;
+ Variant delta_val;
+ Variant final_val;
+ ObjectID target_id;
+ StringName target_key;
+ real_t times_in_sec;
+ TransitionType trans_type;
+ EaseType ease_type;
+ real_t delay;
+ int args;
+ Variant arg[5];
+ };
+
+ String autoplay;
+ TweenProcessMode tween_process_mode;
+ bool processing;
+ bool active;
+ bool repeat;
+ float speed_scale;
+ mutable int pending_update;
+
+ List<InterpolateData> interpolates;
+
+ struct PendingCommand {
+ StringName key;
+ int args;
+ Variant arg[10];
+ };
+ List<PendingCommand> pending_commands;
+
+ void _add_pending_command(StringName p_key
+ ,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()
+ ,const Variant& p_arg6=Variant()
+ ,const Variant& p_arg7=Variant()
+ ,const Variant& p_arg8=Variant()
+ ,const Variant& p_arg9=Variant()
+ ,const Variant& p_arg10=Variant()
+ );
+ void _process_pending_commands();
+
+ typedef real_t (*interpolater)(real_t t, real_t b, real_t c, real_t d);
+ static interpolater interpolaters[TRANS_COUNT][EASE_COUNT];
+
+ real_t _run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
+ Variant& _get_delta_val(InterpolateData& p_data);
+ Variant& _get_initial_val(InterpolateData& p_data);
+ Variant _run_equation(InterpolateData& p_data);
+ bool _calc_delta_val(const Variant& p_initial_val, const Variant& p_final_val, Variant& p_delta_val);
+ bool _apply_tween_value(InterpolateData& p_data, Variant& value);
+
+ void _tween_process(float p_delta);
+ void _set_process(bool p_process,bool p_force=false);
+
+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;
+ void _notification(int p_what);
+
+ static void _bind_methods();
+
+public:
+
+ bool is_active() const;
+ void set_active(bool p_active);
+
+ bool is_repeat() const;
+ void set_repeat(bool p_repeat);
+
+ void set_tween_process_mode(TweenProcessMode p_mode);
+ TweenProcessMode get_tween_process_mode() const;
+
+ void set_speed(float p_speed);
+ float get_speed() const;
+
+ bool start();
+ bool reset(Object *p_node, String p_key);
+ bool reset_all();
+ bool stop(Object *p_node, String p_key);
+ bool stop_all();
+ bool resume(Object *p_node, String p_key);
+ bool resume_all();
+ bool remove(Object *p_node, String p_key);
+ bool remove_all();
+
+ bool seek(real_t p_time);
+ real_t tell() const;
+ real_t get_runtime() const;
+
+ bool interpolate_property(Object *p_node
+ , String p_property
+ , Variant p_initial_val
+ , Variant p_final_val
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay = 0
+ );
+
+ bool interpolate_method(Object *p_node
+ , String p_method
+ , Variant p_initial_val
+ , Variant p_final_val
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay = 0
+ );
+
+ bool interpolate_callback(Object *p_object
+ , real_t p_times_in_sec
+ , String p_callback
+ , VARIANT_ARG_DECLARE
+ );
+
+ bool interpolate_deferred_callback(Object *p_object
+ , real_t p_times_in_sec
+ , String p_callback
+ , VARIANT_ARG_DECLARE
+ );
+
+ bool follow_property(Object *p_node
+ , String p_property
+ , Variant p_initial_val
+ , Object *p_target
+ , String p_target_property
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay = 0
+ );
+
+ bool follow_method(Object *p_node
+ , String p_method
+ , Variant p_initial_val
+ , Object *p_target
+ , String p_target_method
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay = 0
+ );
+
+ bool targeting_property(Object *p_node
+ , String p_property
+ , Object *p_initial
+ , String p_initial_property
+ , Variant p_final_val
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay = 0
+ );
+
+ bool targeting_method(Object *p_node
+ , String p_method
+ , Object *p_initial
+ , String p_initial_method
+ , Variant p_final_val
+ , real_t p_times_in_sec
+ , TransitionType p_trans_type
+ , EaseType p_ease_type
+ , real_t p_delay = 0
+ );
+
+ Tween();
+ ~Tween();
+};
+
+VARIANT_ENUM_CAST( Tween::TweenProcessMode );
+VARIANT_ENUM_CAST( Tween::TransitionType );
+VARIANT_ENUM_CAST( Tween::EaseType );
+
+#endif
+
diff --git a/scene/animation/tween_interpolaters.cpp b/scene/animation/tween_interpolaters.cpp
new file mode 100644
index 0000000000..9128d220de
--- /dev/null
+++ b/scene/animation/tween_interpolaters.cpp
@@ -0,0 +1,407 @@
+/*************************************************************************/
+/* tween.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 "tween.h"
+
+const real_t pi = 3.1415926535898;
+
+///////////////////////////////////////////////////////////////////////////
+// linear
+///////////////////////////////////////////////////////////////////////////
+namespace linear {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * t / d + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * t / d + b;
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * t / d + b;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * t / d + b;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// sine
+///////////////////////////////////////////////////////////////////////////
+namespace sine {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return -c * cos(t / d * (pi / 2)) + c + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * sin(t / d * (pi / 2)) + b;
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return -c / 2 * (cos(pi * t / d) - 1) + b;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// quint
+///////////////////////////////////////////////////////////////////////////
+namespace quint {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * pow(t / d, 5) + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * (pow(t / d - 1, 5) + 1) + b;
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ t = t / d * 2;
+ if (t < 1) return c / 2 * pow(t, 5) + b;
+ return c / 2 * (pow(t - 2, 5) + 2) + b;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// quart
+///////////////////////////////////////////////////////////////////////////
+namespace quart {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * pow(t / d, 4) + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return -c * (pow(t / d - 1, 4) - 1) + b;
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ t = t / d * 2;
+ if (t < 1) return c / 2 * pow(t, 4) + b;
+ return -c / 2 * (pow(t - 2, 4) - 2) + b;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// quad
+///////////////////////////////////////////////////////////////////////////
+namespace quad {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * pow(t / d, 2) + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ t = t / d;
+ return -c * t * (t - 2) + b;
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ t = t / d * 2;
+ if (t < 1) return c / 2 * pow(t, 2) + b;
+ return -c / 2 * ((t - 1) * (t - 3) - 1) + b;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// expo
+///////////////////////////////////////////////////////////////////////////
+namespace expo {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ if (t == 0) return b;
+ return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ if (t == d) return b + c;
+ return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b;
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ if (t == 0) return b;
+ if (t == d) return b + c;
+ t = t / d * 2;
+ if (t < 1) return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005;
+ return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// elastic
+///////////////////////////////////////////////////////////////////////////
+namespace elastic {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ if (t == 0) return b;
+ if ((t /= d) == 1) return b + c;
+ float p = d * 0.3f;
+ float a = c;
+ float s = p / 4;
+ float postFix = a * pow(2,10 * (t -= 1)); // this is a fix, again, with post-increment operators
+ return -(postFix * sin((t * d - s) * (2 * pi) / p )) + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ if (t == 0) return b;
+ if ((t /= d) == 1) return b + c;
+ float p = d * 0.3f;
+ float a = c;
+ float s = p / 4;
+ return (a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p ) + c + b);
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ if (t == 0) return b;
+ if ((t /= d / 2) == 2) return b + c;
+ float p = d * (0.3f * 1.5f);
+ float a = c;
+ float s = p / 4;
+
+ if (t < 1) {
+ float postFix = a * pow(2, 10 * (t -= 1)); // postIncrement is evil
+ return -0.5f * (postFix * sin((t * d - s) * (2 * pi) / p)) + b;
+ }
+ float postFix = a * pow(2, -10 * (t -= 1)); // postIncrement is evil
+ return postFix * sin((t * d - s) * (2 * pi) / p ) * 0.5f + c + b;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// cubic
+///////////////////////////////////////////////////////////////////////////
+namespace cubic {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * (t /= d) * t * t + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * ((t = t / d - 1) * t * t + 1) + b;
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
+ return c / 2 * ((t -= 2) * t * t + 2) + b;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// circ
+///////////////////////////////////////////////////////////////////////////
+namespace circ {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return -c * (sqrt(1 - (t /= d) * t) - 1) + b; // TODO: ehrich: operation with t is undefined
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c * sqrt(1 - (t = t / d - 1) * t) + b; // TODO: ehrich: operation with t is undefined
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b;
+ return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; // TODO: ehrich: operation with t is undefined
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// bounce
+///////////////////////////////////////////////////////////////////////////
+namespace bounce {
+ static real_t out(real_t t, real_t b, real_t c, real_t d);
+
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return c - out(d - t, 0, c, d) + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ if ((t /= d) < (1 / 2.75f)) {
+ return c*(7.5625f*t*t) + b;
+ } else if (t < (2/2.75f)) {
+ float postFix = t-=(1.5f/2.75f);
+ return c*(7.5625f*(postFix)*t + .75f) + b;
+ } else if (t < (2.5/2.75)) {
+ float postFix = t-=(2.25f/2.75f);
+ return c*(7.5625f*(postFix)*t + .9375f) + b;
+ } else {
+ float postFix = t-=(2.625f/2.75f);
+ return c*(7.5625f*(postFix)*t + .984375f) + b;
+ }
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? in(t * 2, b, c / 2, d)
+ : out((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+///////////////////////////////////////////////////////////////////////////
+// back
+///////////////////////////////////////////////////////////////////////////
+namespace back {
+ static real_t in(real_t t, real_t b, real_t c, real_t d)
+ {
+ float s = 1.70158f;
+ float postFix = t /= d;
+ return c * (postFix) * t * ((s + 1) * t - s) + b;
+ }
+
+ static real_t out(real_t t, real_t b, real_t c, real_t d)
+ {
+ float s = 1.70158f;
+ return c * ((t = t / d- 1) * t * ((s + 1) * t + s) + 1) + b; // TODO: ehrich: operation with t is undefined
+ }
+
+ static real_t in_out(real_t t, real_t b, real_t c, real_t d)
+ {
+ float s = 1.70158f;
+ if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; // TODO: ehrich: operation with s is undefined
+ float postFix = t -= 2;
+ return c / 2 * ((postFix) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; // TODO: ehrich: operation with s is undefined
+ }
+
+ static real_t out_in(real_t t, real_t b, real_t c, real_t d)
+ {
+ return (t < d / 2)
+ ? out(t * 2, b, c / 2, d)
+ : in((t * 2) - d, b + c / 2, c / 2, d)
+ ;
+ }
+};
+
+Tween::interpolater Tween::interpolaters[Tween::TRANS_COUNT][Tween::EASE_COUNT] = {
+ { &linear::in, &linear::out, &linear::in_out, &linear::out_in },
+ { &sine::in, &sine::out, &sine::in_out, &sine::out_in },
+ { &quint::in, &quint::out, &quint::in_out, &quint::out_in },
+ { &quart::in, &quart::out, &quart::in_out, &quart::out_in },
+ { &quad::in, &quad::out, &quad::in_out, &quad::out_in },
+ { &expo::in, &expo::out, &expo::in_out, &expo::out_in },
+ { &elastic::in, &elastic::out, &elastic::in_out, &elastic::out_in },
+ { &cubic::in, &cubic::out, &cubic::in_out, &cubic::out_in },
+ { &circ::in, &circ::out, &circ::in_out, &circ::out_in },
+ { &bounce::in, &bounce::out, &bounce::in_out, &bounce::out_in },
+ { &back::in, &back::out, &back::in_out, &back::out_in },
+};
+
+real_t Tween::_run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d) {
+
+ interpolater cb = interpolaters[p_trans_type][p_ease_type];
+ ERR_FAIL_COND_V(cb == NULL, b);
+ return cb(t, b, c, d);
+}
+
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 07162e42fd..1bd692431d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,13 +33,13 @@ void EventPlayer::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
//set_idle_process(false); //don't annoy
- if (playback.is_valid() && autoplay && !get_scene()->is_editor_hint())
+ if (playback.is_valid() && autoplay && !get_tree()->is_editor_hint())
play();
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
stop(); //wathever it may be doing, stop
} break;
@@ -75,9 +75,10 @@ Ref<EventStream> EventPlayer::get_stream() const {
void EventPlayer::play() {
- ERR_FAIL_COND(!is_inside_scene());
- if (playback.is_null())
+ ERR_FAIL_COND(!is_inside_tree());
+ if (playback.is_null()) {
return;
+ }
if (playback->is_playing()) {
AudioServer::get_singleton()->lock();
stop();
@@ -92,7 +93,7 @@ void EventPlayer::play() {
void EventPlayer::stop() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (playback.is_null())
return;
@@ -240,7 +241,7 @@ bool EventPlayer::is_paused() const {
void EventPlayer::_set_play(bool p_play) {
_play=p_play;
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
if(_play)
play();
else
@@ -279,8 +280,8 @@ float EventPlayer::get_channel_last_note_time(int p_channel) const {
void EventPlayer::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&EventPlayer::set_stream);
- ObjectTypeDB::bind_method(_MD("get_stream:Stream"),&EventPlayer::get_stream);
+ ObjectTypeDB::bind_method(_MD("set_stream","stream:EventStream"),&EventPlayer::set_stream);
+ ObjectTypeDB::bind_method(_MD("get_stream:EventStream"),&EventPlayer::get_stream);
ObjectTypeDB::bind_method(_MD("play"),&EventPlayer::play);
ObjectTypeDB::bind_method(_MD("stop"),&EventPlayer::stop);
diff --git a/scene/audio/event_player.h b/scene/audio/event_player.h
index 2b3111b36d..05e78040d2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/audio/sample_player.cpp b/scene/audio/sample_player.cpp
index 90994f01b4..7c0a926324 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
}
@@ -498,6 +498,7 @@ bool SamplePlayer::is_active() const {
void SamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) {
library=p_library;
+ _change_notify();
}
Ref<SampleLibrary> SamplePlayer::get_sample_library() const {
@@ -590,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;
}
@@ -605,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 );
@@ -614,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 );
@@ -637,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 );
@@ -646,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 );
@@ -676,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 d0ce1825ee..75a01aff86 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 3e0a64b3f1..8886113e03 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -53,8 +53,8 @@ void SoundRoomParams::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
-#if 0
+ case NOTIFICATION_ENTER_TREE: {
+//#if 0
Node *n=this;
Room *room_instance=NULL;
while(n) {
@@ -74,14 +74,14 @@ void SoundRoomParams::_notification(int p_what) {
if (room_instance) {
room=room_instance->get_sound_room();
} else {
- room=get_scene()->get_default_world()->get_sound_space();
+ room=get_viewport()->find_world()->get_sound_space();
}
_update_sound_room();
-#endif
+//#endif
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
room=RID();
diff --git a/scene/audio/sound_room_params.h b/scene/audio/sound_room_params.h
index 5999046b80..8af2ae8c12 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/audio/stream_player.cpp b/scene/audio/stream_player.cpp
index 5084c1295b..4cfca0492a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,18 +28,79 @@
/*************************************************************************/
#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()) {
+ 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) {
+ 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) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
//set_idle_process(false); //don't annoy
- if (stream.is_valid() && autoplay && !get_scene()->is_editor_hint())
+ if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint())
play();
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
stop(); //wathever it may be doing, stop
} break;
@@ -52,19 +113,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 +136,18 @@ Ref<AudioStream> StreamPlayer::get_stream() const {
}
-void StreamPlayer::play() {
+void StreamPlayer::play(float p_from_offset) {
- ERR_FAIL_COND(!is_inside_scene());
- if (stream.is_null())
+ ERR_FAIL_COND(!is_inside_tree());
+ 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)
@@ -91,30 +157,33 @@ void StreamPlayer::play() {
void StreamPlayer::stop() {
- if (!is_inside_scene())
+ 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();
+ playback->stop();
+ resampler.flush();
+
//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 +203,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 +243,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 +286,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 {
@@ -214,7 +298,7 @@ bool StreamPlayer::is_paused() const {
void StreamPlayer::_set_play(bool p_play) {
_play=p_play;
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
if(_play)
play();
else
@@ -228,13 +312,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"),&StreamPlayer::play,DEFVAL(0));
ObjectTypeDB::bind_method(_MD("stop"),&StreamPlayer::stop);
ObjectTypeDB::bind_method(_MD("is_playing"),&StreamPlayer::is_playing);
@@ -251,6 +346,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 +372,8 @@ 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") );
}
@@ -281,10 +384,17 @@ 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;
+
}
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 945d615d6c..be090f50e1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,17 +31,43 @@
#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;
+
+ AudioRBResampler resampler;
bool _play;
void _set_play(bool p_play);
@@ -55,7 +81,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 +94,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 +110,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 ac2417d539..0c63a3bc74 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#include "os/keyboard.h"
#include "print_string.h"
#include "button_group.h"
-
+#include "scene/scene_string_names.h"
void BaseButton::_input_event(InputEvent p_event) {
@@ -56,13 +56,25 @@ void BaseButton::_input_event(InputEvent p_event) {
if (!toggle_mode) { //mouse press attempt
+ status.press_attempt=true;
+ status.pressing_inside=true;
+
pressed();
+ if (get_script_instance()) {
+ Variant::CallError ce;
+ get_script_instance()->call(SceneStringNames::get_singleton()->_pressed,NULL,0,ce);
+ }
+
emit_signal("pressed");
} else {
status.pressed=!status.pressed;
pressed();
+ if (get_script_instance()) {
+ Variant::CallError ce;
+ get_script_instance()->call(SceneStringNames::get_singleton()->_pressed,NULL,0,ce);
+ }
emit_signal("pressed");
toggled(status.pressed);
@@ -71,8 +83,15 @@ void BaseButton::_input_event(InputEvent p_event) {
}
- }
+ } else {
+ if (status.press_attempt && status.pressing_inside) {
+// released();
+ emit_signal("released");
+ }
+ status.press_attempt=false;
+ }
+ update();
break;
}
@@ -85,14 +104,19 @@ void BaseButton::_input_event(InputEvent p_event) {
if (status.press_attempt &&status.pressing_inside) {
-
+
if (!toggle_mode) { //mouse press attempt
-
+
pressed();
- emit_signal("pressed");
+ if (get_script_instance()) {
+ Variant::CallError ce;
+ get_script_instance()->call(SceneStringNames::get_singleton()->_pressed,NULL,0,ce);
+ }
+
+ emit_signal("pressed");
} else {
-
+
status.pressed=!status.pressed;
pressed();
@@ -100,11 +124,15 @@ void BaseButton::_input_event(InputEvent p_event) {
toggled(status.pressed);
emit_signal("toggled",status.pressed);
-
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_toggled,status.pressed);
+ }
+
+
}
-
+
}
-
+
status.press_attempt=false;
}
@@ -120,6 +148,7 @@ void BaseButton::_input_event(InputEvent p_event) {
update();
}
} break;
+ case InputEvent::ACTION:
case InputEvent::JOYSTICK_BUTTON:
case InputEvent::KEY: {
@@ -167,6 +196,9 @@ void BaseButton::_input_event(InputEvent p_event) {
emit_signal("pressed");
toggled(status.pressed);
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_toggled,status.pressed);
+ }
emit_signal("toggled",status.pressed);
}
}
@@ -201,7 +233,7 @@ void BaseButton::_notification(int p_what) {
}
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
CanvasItem *ci=this;
while(ci) {
@@ -217,12 +249,22 @@ void BaseButton::_notification(int p_what) {
}
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
if (group)
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() {
@@ -248,12 +290,12 @@ void BaseButton::set_disabled(bool p_disabled) {
set_focus_mode(FOCUS_NONE);
else
set_focus_mode(FOCUS_ALL);
-};
+}
bool BaseButton::is_disabled() const {
return status.disabled;
-};
+}
void BaseButton::set_pressed(bool p_pressed) {
@@ -336,6 +378,8 @@ bool BaseButton::get_click_on_press() const {
}
+
+
void BaseButton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_input_event"),&BaseButton::_input_event);
@@ -348,12 +392,24 @@ void BaseButton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_disabled"),&BaseButton::is_disabled);
ObjectTypeDB::bind_method(_MD("set_click_on_press","enable"),&BaseButton::set_click_on_press);
ObjectTypeDB::bind_method(_MD("get_click_on_press"),&BaseButton::get_click_on_press);
+ ObjectTypeDB::bind_method(_MD("get_draw_mode"),&BaseButton::get_draw_mode);
+
+ BIND_VMETHOD(MethodInfo("_pressed"));
+ BIND_VMETHOD(MethodInfo("_toggled",PropertyInfo(Variant::BOOL,"pressed")));
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, "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 );
+ BIND_CONSTANT( DRAW_PRESSED );
+ BIND_CONSTANT( DRAW_HOVER );
+ BIND_CONSTANT( DRAW_DISABLED );
}
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index a2c640b9cf..e187a85eae 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -61,15 +61,8 @@ class BaseButton : public Control {
protected:
- enum DrawMode {
- DRAW_NORMAL,
- DRAW_PRESSED,
- DRAW_HOVER,
- DRAW_DISABLED,
- };
- DrawMode get_draw_mode() const;
virtual void pressed();
virtual void toggled(bool p_pressed);
@@ -78,7 +71,16 @@ protected:
void _notification(int p_what);
public:
-
+
+ enum DrawMode {
+ DRAW_NORMAL,
+ DRAW_PRESSED,
+ DRAW_HOVER,
+ DRAW_DISABLED,
+ };
+
+ DrawMode get_draw_mode() const;
+
/* Signals */
bool is_pressed() const; ///< return wether button is pressed (toggled in)
@@ -101,4 +103,6 @@ public:
};
+VARIANT_ENUM_CAST( BaseButton::DrawMode );
+
#endif
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 216c6d7122..b63b3de530 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -44,7 +44,7 @@ void BoxContainer::_resort() {
Size2i new_size=get_size();;
- int sep=get_constant("separation",vertical?"VBoxContainer":"HBoxContainer");
+ int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer");
bool first=true;
int children_count=0;
@@ -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;
@@ -202,7 +216,7 @@ Size2 BoxContainer::get_minimum_size() const {
/* Calculate MINIMUM SIZE */
Size2i minimum;
- int sep=get_constant("separation",vertical?"VBoxContainer":"HBoxContainer");
+ int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer");
bool first=true;
@@ -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 fb305f0423..c357814baf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 0532ab22da..edeb18bfc1 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -97,6 +97,13 @@ void Button::_notification(int p_what) {
} break;
}
+
+ if (has_focus()) {
+
+ Ref<StyleBox> style = get_stylebox("focus");
+ style->draw(ci,Rect2(Point2(),size));
+ }
+
Ref<StyleBox> style = get_stylebox("normal" );
Ref<Font> font=get_font("font");
Ref<Texture> _icon;
@@ -115,6 +122,8 @@ void Button::_notification(int p_what) {
text_ofs.y+=style->get_offset().y;
} break;
case ALIGN_CENTER: {
+ if (text_ofs.x<0)
+ text_ofs.x=0;
text_ofs+=icon_ofs;
text_ofs+=style->get_offset();
} break;
@@ -132,11 +141,7 @@ void Button::_notification(int p_what) {
_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) );
}
- if (has_focus()) {
- Ref<StyleBox> style = get_stylebox("focus");
- style->draw(ci,Rect2(Point2(),size));
- }
}
}
@@ -220,11 +225,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 cf79e23579..690179b90c 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/button_array.cpp b/scene/gui/button_array.cpp
index e3a2b7b290..b86e32dda7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 f536040039..ea2c1e4968 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,98 +26,98 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BUTTON_ARRAY_H
-#define BUTTON_ARRAY_H
-
-#include "scene/gui/control.h"
-
-class ButtonArray : public Control {
-
- OBJ_TYPE(ButtonArray, Control);
-public:
- enum Align {
- ALIGN_BEGIN,
- ALIGN_CENTER,
- ALIGN_END,
- ALIGN_FILL,
- ALIGN_EXPAND_FILL
- };
-private:
-
- Orientation orientation;
- Align align;
-
- struct Button {
-
- String text;
- Ref<Texture> icon;
- mutable int _ms_cache;
- mutable int _pos_cache;
- mutable int _size_cache;
- };
-
- int selected;
- int hover;
- double min_button_size;
-
- Vector<Button> buttons;
-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;
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
-
- void _input_event(const InputEvent& p_event);
-
-
- void set_align(Align p_align);
- Align get_align() const;
-
- void add_button(const String& p_button);
- void add_icon_button(const Ref<Texture>& p_icon,const String& p_button="");
-
- void set_button_text(int p_button, const String& p_text);
- void set_button_icon(int p_button, const Ref<Texture>& p_icon);
-
-
- String get_button_text(int p_button) const;
- Ref<Texture> get_button_icon(int p_button) const;
-
- int get_selected() const;
- int get_hovered() const;
- void set_selected(int p_selected);
-
- int get_button_count() const;
-
- void erase_button(int p_button);
- void clear();
-
- virtual Size2 get_minimum_size() const;
-
- virtual void get_translatable_strings(List<String> *p_strings) const;
-
-
- ButtonArray(Orientation p_orientation=HORIZONTAL);
-};
-
-class HButtonArray : public ButtonArray {
- OBJ_TYPE(HButtonArray,ButtonArray);
-public:
-
- HButtonArray() : ButtonArray(HORIZONTAL) {};
-};
-
-class VButtonArray : public ButtonArray {
- OBJ_TYPE(VButtonArray,ButtonArray);
-public:
-
- VButtonArray() : ButtonArray(VERTICAL) {};
-};
-
-
-#endif // BUTTON_ARRAY_H
+#ifndef BUTTON_ARRAY_H
+#define BUTTON_ARRAY_H
+
+#include "scene/gui/control.h"
+
+class ButtonArray : public Control {
+
+ OBJ_TYPE(ButtonArray, Control);
+public:
+ enum Align {
+ ALIGN_BEGIN,
+ ALIGN_CENTER,
+ ALIGN_END,
+ ALIGN_FILL,
+ ALIGN_EXPAND_FILL
+ };
+private:
+
+ Orientation orientation;
+ Align align;
+
+ struct Button {
+
+ String text;
+ Ref<Texture> icon;
+ mutable int _ms_cache;
+ mutable int _pos_cache;
+ mutable int _size_cache;
+ };
+
+ int selected;
+ int hover;
+ double min_button_size;
+
+ Vector<Button> buttons;
+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;
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+
+ void _input_event(const InputEvent& p_event);
+
+
+ void set_align(Align p_align);
+ Align get_align() const;
+
+ void add_button(const String& p_button);
+ void add_icon_button(const Ref<Texture>& p_icon,const String& p_button="");
+
+ void set_button_text(int p_button, const String& p_text);
+ void set_button_icon(int p_button, const Ref<Texture>& p_icon);
+
+
+ String get_button_text(int p_button) const;
+ Ref<Texture> get_button_icon(int p_button) const;
+
+ int get_selected() const;
+ int get_hovered() const;
+ void set_selected(int p_selected);
+
+ int get_button_count() const;
+
+ void erase_button(int p_button);
+ void clear();
+
+ virtual Size2 get_minimum_size() const;
+
+ virtual void get_translatable_strings(List<String> *p_strings) const;
+
+
+ ButtonArray(Orientation p_orientation=HORIZONTAL);
+};
+
+class HButtonArray : public ButtonArray {
+ OBJ_TYPE(HButtonArray,ButtonArray);
+public:
+
+ HButtonArray() : ButtonArray(HORIZONTAL) {};
+};
+
+class VButtonArray : public ButtonArray {
+ OBJ_TYPE(VButtonArray,ButtonArray);
+public:
+
+ VButtonArray() : ButtonArray(VERTICAL) {};
+};
+
+
+#endif // BUTTON_ARRAY_H
diff --git a/scene/gui/button_group.cpp b/scene/gui/button_group.cpp
index 65cfd03505..c92d7f2696 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -67,6 +67,9 @@ Array ButtonGroup::_get_button_list() const {
List<BaseButton*> b;
get_button_list(&b);
+
+ b.sort_custom<Node::Comparator>();
+
Array arr;
arr.resize(b.size());
@@ -114,7 +117,7 @@ BaseButton *ButtonGroup::get_focused_button() const{
int ButtonGroup::get_pressed_button_index() const {
//in tree order, this is bizarre
- ERR_FAIL_COND_V(!is_inside_scene(),0);
+ ERR_FAIL_COND_V(!is_inside_tree(),0);
BaseButton *pressed = get_pressed_button();
if (!pressed)
@@ -152,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 e154f609a8..74e847e937 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 9cedf02371..8a22a38980 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,6 +32,8 @@
Size2 CenterContainer::get_minimum_size() const {
+ if (use_top_left)
+ return Size2();
Size2 ms;
for(int i=0;i<get_child_count();i++) {
@@ -53,6 +55,20 @@ Size2 CenterContainer::get_minimum_size() const {
}
+
+void CenterContainer::set_use_top_left(bool p_enable) {
+
+ use_top_left=p_enable;
+ queue_sort();
+
+}
+
+bool CenterContainer::is_using_top_left() const {
+
+ return use_top_left;
+}
+
+
void CenterContainer::_notification(int p_what) {
if (p_what==NOTIFICATION_SORT_CHILDREN) {
@@ -65,14 +81,24 @@ void CenterContainer::_notification(int p_what) {
continue;
if (c->is_set_as_toplevel())
continue;
+
Size2 minsize = c->get_combined_minimum_size();
- Point2 ofs = ((size - minsize)/2.0).floor();
+ Point2 ofs = use_top_left ? (-minsize*0.5).floor() : ((size - minsize)/2.0).floor();
fit_child_in_rect(c,Rect2(ofs,minsize));
}
}
}
-CenterContainer::CenterContainer()
-{
+void CenterContainer::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_use_top_left","enable"),&CenterContainer::set_use_top_left);
+ ObjectTypeDB::bind_method(_MD("is_using_top_left"),&CenterContainer::is_using_top_left);
+
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"use_top_left"),_SCS("set_use_top_left"),_SCS("is_using_top_left"));
+}
+
+CenterContainer::CenterContainer() {
+
+ use_top_left=false;
}
diff --git a/scene/gui/center_container.h b/scene/gui/center_container.h
index 458e2e7251..4d8d06ac8c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,11 +36,16 @@ class CenterContainer : public Container {
OBJ_TYPE( CenterContainer, Container );
+ bool use_top_left;
protected:
void _notification(int p_what);
+ static void _bind_methods();
public:
+ void set_use_top_left(bool p_enable);
+ bool is_using_top_left() const;
+
virtual Size2 get_minimum_size() const;
CenterContainer();
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
new file mode 100644
index 0000000000..2aa82bc5f5
--- /dev/null
+++ b/scene/gui/check_box.cpp
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* check_button.cpp */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#include "check_box.h"
+
+#include "servers/visual_server.h"
+#include "button_group.h"
+
+
+void CheckBox::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ RID ci = get_canvas_item();
+
+ Ref<Texture> on=Control::get_icon(is_radio() ? "radio_checked" : "checked");
+ Ref<Texture> off=Control::get_icon(is_radio() ? "radio_unchecked" : "unchecked");
+
+ Vector2 ofs;
+ ofs.x = 0;
+ ofs.y = int((get_size().height - on->get_height())/2);
+
+ if (is_pressed())
+ on->draw(ci,ofs);
+ else
+ off->draw(ci,ofs);
+
+
+ }
+}
+
+bool CheckBox::is_radio()
+{
+ Node* parent = this;
+ do {
+ parent = parent->get_parent();
+ if (parent->cast_to<ButtonGroup>())
+ break;
+ } while (parent);
+
+ return (parent != 0);
+}
+
+CheckBox::CheckBox(const String &p_text):
+ Button(p_text)
+{
+ set_toggle_mode(true);
+ set_text_align(ALIGN_LEFT);
+
+}
+
+CheckBox::~CheckBox()
+{
+}
diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h
new file mode 100644
index 0000000000..171fd55351
--- /dev/null
+++ b/scene/gui/check_box.h
@@ -0,0 +1,55 @@
+/*************************************************************************/
+/* check_box.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef CHECK_BOX_H
+#define CHECK_BOX_H
+
+
+#include "scene/gui/button.h"
+/**
+@author Mariano Suligoy <marianognu.esyrpg@gmail.com>
+*/
+class CheckBox : public Button {
+
+ OBJ_TYPE( CheckBox, Button );
+
+
+protected:
+ void _notification(int p_what);
+
+ bool is_radio();
+
+
+public:
+
+ CheckBox(const String& p_text=String());
+ ~CheckBox();
+
+};
+
+#endif
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index 10dca67053..d765aefe5e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h
index a4ebe5b8af..b90bb31c2d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 6d1f2324fc..c30d473610 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -52,9 +52,6 @@ void ColorPicker::_notification(int p_what) {
void ColorPicker::_update_controls() {
-
- int cw = get_constant("color_width");
-
if (edit_alpha) {
values[3]->show();
scroll[3]->show();
@@ -65,8 +62,6 @@ void ColorPicker::_update_controls() {
labels[3]->hide();
}
-
-
}
@@ -106,8 +101,8 @@ void ColorPicker::_value_changed(double) {
} break;
case MODE_HSV: {
- color.set_hsv( CLAMP(scroll[0]->get_val()/255,0,0.99), scroll[1]->get_val()/255, scroll[2]->get_val()/255 );
- color.a=scroll[3]->get_val()/255.0;
+ 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: {
@@ -147,29 +142,50 @@ void ColorPicker::_update_color() {
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_step(1);
+ labels[i]->set_text(_lt[i]);
}
- scroll[0]->set_val( color.get_h()*255 );
- scroll[1]->set_val( color.get_s()*255 );
- scroll[2]->set_val( color.get_v()*255 );
- scroll[3]->set_val(color.a*255);
+ scroll[0]->set_max(359);
+ scroll[0]->set_step(0.01);
+ scroll[0]->set_val( color.get_h()*359 );
+
+ scroll[1]->set_max(100);
+ scroll[1]->set_step(0.01);
+ scroll[1]->set_val( color.get_s()*100 );
+
+ scroll[2]->set_max(100);
+ scroll[2]->set_step(0.01);
+ scroll[2]->set_val( color.get_v()*100 );
+
+ scroll[3]->set_max(100);
+ scroll[3]->set_step(0.01);
+ scroll[3]->set_val( color.a*100);
} break;
}
@@ -260,9 +276,6 @@ ColorPicker::ColorPicker() {
HBoxContainer *hbc = memnew( HBoxContainer );
labels[i]=memnew( Label );
- static const char*_lt[4]={"R","G","B","A"};
- labels[i]->set_text(_lt[i]);
-
hbc->add_child(labels[i]);
scroll[i]=memnew( HSlider );
@@ -274,8 +287,6 @@ ColorPicker::ColorPicker() {
scroll[i]->set_min(0);
- scroll[i]->set_max(255);
- scroll[i]->set_step(1);
scroll[i]->set_page(0);
scroll[i]->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -341,6 +352,7 @@ void ColorPickerButton::set_color(const Color& p_color){
picker->set_color(p_color);
+ update();
}
Color ColorPickerButton::get_color() const{
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index e45b4b131e..0756e88cf2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/color_ramp_edit.cpp b/scene/gui/color_ramp_edit.cpp
new file mode 100644
index 0000000000..14a48fe3d3
--- /dev/null
+++ b/scene/gui/color_ramp_edit.cpp
@@ -0,0 +1,422 @@
+#include "color_ramp_edit.h"
+#include "os/keyboard.h"
+
+ColorRampEdit::ColorRampEdit(){
+ grabbed=-1;
+ grabbing=false;
+ set_focus_mode(FOCUS_ALL);
+
+ popup = memnew( PopupPanel );
+ picker = memnew( ColorPicker );
+ popup->add_child(picker);
+ popup->set_child_rect(picker);
+ add_child(popup);
+
+ checker = Ref<ImageTexture>(memnew( ImageTexture ));
+ checker->create_from_image( Image(checker_bg_png),ImageTexture::FLAG_REPEAT );
+}
+
+int ColorRampEdit::_get_point_from_pos(int x) {
+ int result = -1;
+ int total_w = get_size().width-get_size().height-3;
+ for(int i=0;i<points.size();i++) {
+ //Check if we clicked at point
+ if (ABS(x-points[i].offset*total_w+1)<(POINT_WIDTH/2+1)) {
+ result=i;
+ }
+ }
+ return result;
+}
+
+void ColorRampEdit::_show_color_picker() {
+ if (grabbed==-1)
+ return;
+ Size2 ms = Size2(350, picker->get_combined_minimum_size().height+10);
+ picker->set_color(points[grabbed].color);
+ popup->set_pos(get_global_pos()-Vector2(ms.width-get_size().width,ms.height));
+ popup->set_size(ms);
+ popup->popup();
+}
+
+ColorRampEdit::~ColorRampEdit() {
+
+}
+
+void ColorRampEdit::_input_event(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::KEY && p_event.key.pressed && p_event.key.scancode==KEY_DELETE && grabbed!=-1) {
+
+ points.remove(grabbed);
+ grabbed=-1;
+ grabbing=false;
+ update();
+ emit_signal("ramp_changed");
+ accept_event();
+ }
+
+ //Show color picker on double click.
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.doubleclick && p_event.mouse_button.pressed) {
+ grabbed=_get_point_from_pos(p_event.mouse_button.x);
+ _show_color_picker();
+ accept_event();
+ }
+
+ //Delete point on right click
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==2 && p_event.mouse_button.pressed) {
+ grabbed=_get_point_from_pos(p_event.mouse_button.x);
+ if(grabbed != -1)
+ {
+ points.remove(grabbed);
+ grabbed=-1;
+ grabbing=false;
+ update();
+ emit_signal("ramp_changed");
+ accept_event();
+ }
+ }
+
+ //Hold alt key to duplicate selected color
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed && p_event.key.mod.alt ) {
+
+ int x = p_event.mouse_button.x;
+ grabbed=_get_point_from_pos(x);
+
+ if( grabbed != -1 ) {
+ int total_w = get_size().width-get_size().height-3;
+ ColorRamp::Point newPoint = points[grabbed];
+ newPoint.offset=CLAMP(x/float(total_w),0,1);
+
+ points.push_back(newPoint);
+ points.sort();
+ for(int i=0;i<points.size();++i) {
+ if (points[i].offset==newPoint.offset) {
+ grabbed=i;
+ break;
+ }
+ }
+
+ emit_signal("ramp_changed");
+ update();
+ }
+ }
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
+
+ update();
+ int x = p_event.mouse_button.x;
+ int total_w = get_size().width-get_size().height-3;
+
+ //Check if color selector was clicked.
+ if (x>total_w+3) {
+ _show_color_picker();
+ return;
+ }
+
+ grabbing=true;
+
+ grabbed=_get_point_from_pos(x);
+ //grab or select
+ if (grabbed!=-1) {
+ return;
+ }
+
+ //insert
+ ColorRamp::Point newPoint;
+ newPoint.offset=CLAMP(x/float(total_w),0,1);
+
+ ColorRamp::Point prev;
+ ColorRamp::Point next;
+
+ int pos=-1;
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset<newPoint.offset)
+ pos=i;
+ }
+
+ if (pos==-1) {
+
+ prev.color=Color(0,0,0);
+ prev.offset=0;
+ if (points.size()) {
+ next=points[0];
+ } else {
+ next.color=Color(1,1,1);
+ next.offset=1.0;
+ }
+ } else {
+
+ if (pos==points.size()-1) {
+ next.color=Color(1,1,1);
+ next.offset=1.0;
+ } else {
+ next=points[pos+1];
+ }
+ prev=points[pos];
+
+ }
+
+ newPoint.color=prev.color.linear_interpolate(next.color,(newPoint.offset-prev.offset)/(next.offset-prev.offset));
+
+ points.push_back(newPoint);
+ points.sort();
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset==newPoint.offset) {
+ grabbed=i;
+ break;
+ }
+ }
+
+ emit_signal("ramp_changed");
+
+ }
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && !p_event.mouse_button.pressed) {
+
+ if (grabbing) {
+ grabbing=false;
+ emit_signal("ramp_changed");
+ }
+ update();
+ }
+
+ if (p_event.type==InputEvent::MOUSE_MOTION && grabbing) {
+
+ int total_w = get_size().width-get_size().height-3;
+
+ int x = p_event.mouse_motion.x;
+ float newofs = CLAMP(x/float(total_w),0,1);
+
+ //Snap to nearest point if holding shift
+ if (p_event.key.mod.shift) {
+ float snap_treshhold = 0.03;
+ float smallest_ofs = snap_treshhold;
+ bool founded = false;
+ int nearest_point;
+ for(int i=0;i<points.size();++i) {
+ if (i != grabbed) {
+ float temp_ofs = ABS(points[i].offset - newofs);
+ if (temp_ofs < smallest_ofs) {
+ smallest_ofs = temp_ofs;
+ nearest_point = i;
+ if (founded)
+ break;
+ founded = true;
+ }
+ }
+ }
+ if (founded) {
+ if (points[nearest_point].offset < newofs)
+ newofs = points[nearest_point].offset+0.00001;
+ else
+ newofs = points[nearest_point].offset-0.00001;
+ newofs = CLAMP(newofs,0,1);
+ }
+ }
+
+ bool valid=true;
+ for(int i=0;i<points.size();i++) {
+
+ if (points[i].offset==newofs && i!=grabbed) {
+ valid=false;
+ }
+ }
+
+ if (!valid)
+ return;
+
+ points[grabbed].offset=newofs;
+
+ points.sort();
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset==newofs) {
+ grabbed=i;
+ break;
+ }
+ }
+
+ emit_signal("ramp_changed");
+
+ update();
+ }
+}
+
+void ColorRampEdit::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+ picker->connect("color_changed",this,"_color_changed");
+ }
+ if (p_what==NOTIFICATION_DRAW) {
+
+ int w = get_size().x;
+ int h = get_size().y;
+
+ if (w == 0 || h == 0)
+ return; //Safety check. We have division by 'h'. And in any case there is nothing to draw with such size
+
+ int total_w = get_size().width-get_size().height-3;
+
+ //Draw checker pattern for ramp
+ _draw_checker(0,0, total_w, h);
+
+ //Draw color ramp
+ ColorRamp::Point prev;
+ prev.offset=0;
+ if(points.size() == 0)
+ prev.color=Color(0,0,0); //Draw black rectangle if we have no points
+ else
+ prev.color = points[0].color; //Extend color of first point to the beginning.
+
+ for(int i=-1;i<points.size();i++) {
+
+ ColorRamp::Point next;
+ //If there is no next point
+ if (i+1 == points.size()) {
+ if(points.size() == 0)
+ next.color=Color(0,0,0); //Draw black rectangle if we have no points
+ else
+ next.color=points[i].color; //Extend color of last point to the end.
+ next.offset=1;
+ } else {
+ next=points[i+1];
+ }
+
+ if (prev.offset==next.offset) {
+ prev=next;
+ continue;
+ }
+
+ Vector<Vector2> points;
+ Vector<Color> colors;
+ points.push_back(Vector2(prev.offset*total_w,h));
+ points.push_back(Vector2(prev.offset*total_w,0));
+ points.push_back(Vector2(next.offset*total_w,0));
+ points.push_back(Vector2(next.offset*total_w,h));
+ colors.push_back(prev.color);
+ colors.push_back(prev.color);
+ colors.push_back(next.color);
+ colors.push_back(next.color);
+ draw_primitive(points,colors,Vector<Point2>());
+ prev=next;
+ }
+
+ //Draw point markers
+ for(int i=0;i<points.size();i++) {
+
+ Color col = i==grabbed?Color(1,0.0,0.0,0.9):points[i].color.contrasted();
+ col.a = 0.9;
+
+ draw_line(Vector2(points[i].offset*total_w,0),Vector2(points[i].offset*total_w,h/2),col);
+ draw_rect(Rect2(points[i].offset*total_w-POINT_WIDTH/2, h/2, POINT_WIDTH, h/2), Color(0.6, 0.6, 0.6, i==grabbed?0.9:0.4));
+ draw_line(Vector2(points[i].offset*total_w-POINT_WIDTH/2,h/2),Vector2(points[i].offset*total_w-POINT_WIDTH/2,h-1),col);
+ draw_line(Vector2(points[i].offset*total_w+POINT_WIDTH/2,h/2),Vector2(points[i].offset*total_w+POINT_WIDTH/2,h-1),col);
+ draw_line(Vector2(points[i].offset*total_w-POINT_WIDTH/2,h/2),Vector2(points[i].offset*total_w+POINT_WIDTH/2,h/2),col);
+ draw_line(Vector2(points[i].offset*total_w-POINT_WIDTH/2,h-1),Vector2(points[i].offset*total_w+POINT_WIDTH/2,h-1),col);
+
+ }
+
+
+ //Draw "button" for color selector
+ _draw_checker(total_w+3,0, h, h);
+ if (grabbed!=-1) {
+ //Draw with selection color
+ draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color);
+ } else {
+ //if no color selected draw grey color with 'X' on top.
+ draw_rect(Rect2(total_w+3,0,h,h), Color(0.5, 0.5, 0.5, 1));
+ draw_line(Vector2(total_w+3,0),Vector2(total_w+3+h,h),Color(1,1,1,0.6));
+ draw_line(Vector2(total_w+3,h),Vector2(total_w+3+h,0),Color(1,1,1,0.6));
+ }
+
+ //Draw borders around color ramp if in focus
+ if (has_focus()) {
+
+ draw_line(Vector2(-1,-1),Vector2(total_w+1,-1),Color(1,1,1,0.6));
+ draw_line(Vector2(total_w+1,-1),Vector2(total_w+1,h+1),Color(1,1,1,0.6));
+ draw_line(Vector2(total_w+1,h+1),Vector2(-1,h+1),Color(1,1,1,0.6));
+ draw_line(Vector2(-1,-1),Vector2(-1,h+1),Color(1,1,1,0.6));
+ }
+
+ }
+}
+
+void ColorRampEdit::_draw_checker(int x, int y, int w, int h) {
+ //Draw it with polygon to insert UVs for scale
+ Vector<Vector2> backPoints;
+ backPoints.push_back(Vector2(x, y));
+ backPoints.push_back(Vector2(x, y+h));
+ backPoints.push_back(Vector2(x+w, y+h));
+ backPoints.push_back(Vector2(x+w, y));
+ Vector<Color> colorPoints;
+ colorPoints.push_back(Color(1, 1, 1, 1));
+ colorPoints.push_back(Color(1, 1, 1, 1));
+ colorPoints.push_back(Color(1, 1, 1, 1));
+ colorPoints.push_back(Color(1, 1, 1, 1));
+ Vector<Vector2> uvPoints;
+ //Draw checker pattern pixel-perfect and scale it by 2.
+ uvPoints.push_back(Vector2(x, y));
+ uvPoints.push_back(Vector2(x, y+h*.5f/checker->get_height()));
+ uvPoints.push_back(Vector2(x+w*.5f/checker->get_width(), y+h*.5f/checker->get_height()));
+ uvPoints.push_back(Vector2(x+w*.5f/checker->get_width(), y));
+ draw_polygon(backPoints, colorPoints, uvPoints, checker);
+}
+
+Size2 ColorRampEdit::get_minimum_size() const {
+
+ return Vector2(0,16);
+}
+
+void ColorRampEdit::_color_changed(const Color& p_color) {
+
+ if (grabbed==-1)
+ return;
+ points[grabbed].color=p_color;
+ update();
+ emit_signal("ramp_changed");
+
+}
+
+void ColorRampEdit::set_ramp(const Vector<float>& p_offsets,const Vector<Color>& p_colors) {
+
+ ERR_FAIL_COND(p_offsets.size()!=p_colors.size());
+ points.clear();
+ for(int i=0;i<p_offsets.size();i++) {
+ ColorRamp::Point p;
+ p.offset=p_offsets[i];
+ p.color=p_colors[i];
+ points.push_back(p);
+ }
+
+ points.sort();
+ update();
+}
+
+Vector<float> ColorRampEdit::get_offsets() const {
+ Vector<float> ret;
+ for(int i=0;i<points.size();i++)
+ ret.push_back(points[i].offset);
+ return ret;
+}
+
+Vector<Color> ColorRampEdit::get_colors() const {
+ Vector<Color> ret;
+ for(int i=0;i<points.size();i++)
+ ret.push_back(points[i].color);
+ return ret;
+}
+
+void ColorRampEdit::set_points(Vector<ColorRamp::Point>& p_points) {
+ if(points.size() != p_points.size())
+ grabbed = -1;
+ points.clear();
+ points = p_points;
+}
+
+Vector<ColorRamp::Point>& ColorRampEdit::get_points() {
+ return points;
+}
+
+void ColorRampEdit::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("_input_event"),&ColorRampEdit::_input_event);
+ ObjectTypeDB::bind_method(_MD("_color_changed"),&ColorRampEdit::_color_changed);
+ ADD_SIGNAL(MethodInfo("ramp_changed"));
+}
diff --git a/scene/gui/color_ramp_edit.h b/scene/gui/color_ramp_edit.h
new file mode 100644
index 0000000000..91292eed0d
--- /dev/null
+++ b/scene/gui/color_ramp_edit.h
@@ -0,0 +1,52 @@
+#ifndef SCENE_GUI_COLOR_RAMP_EDIT_H_
+#define SCENE_GUI_COLOR_RAMP_EDIT_H_
+
+#include "scene/gui/popup.h"
+#include "scene/gui/color_picker.h"
+#include "scene/resources/color_ramp.h"
+#include "scene/resources/default_theme/theme_data.h"
+
+#define POINT_WIDTH 8
+
+class ColorRampEdit : public Control {
+
+ OBJ_TYPE(ColorRampEdit,Control);
+
+ PopupPanel *popup;
+ ColorPicker *picker;
+
+ Ref<ImageTexture> checker;
+
+ bool grabbing;
+ int grabbed;
+ Vector<ColorRamp::Point> points;
+
+ void _draw_checker(int x, int y, int w, int h);
+ void _color_changed(const Color& p_color);
+ int _get_point_from_pos(int x);
+ void _show_color_picker();
+
+protected:
+ void _input_event(const InputEvent& p_event);
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_ramp(const Vector<float>& p_offsets,const Vector<Color>& p_colors);
+ Vector<float> get_offsets() const;
+ Vector<Color> get_colors() const;
+ void set_points(Vector<ColorRamp::Point>& p_points);
+ Vector<ColorRamp::Point>& get_points();
+ virtual Size2 get_minimum_size() const;
+
+ ColorRampEdit();
+ virtual ~ColorRampEdit();
+};
+
+/*class ColorRampEditPanel : public Panel
+{
+ OBJ_TYPE(ColorRampEditPanel, Panel );
+};*/
+
+
+#endif /* SCENE_GUI_COLOR_RAMP_EDIT_H_ */
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 6543a0388d..8cdf4dd039 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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) {
@@ -67,7 +75,7 @@ void Container::remove_child_notify(Node *p_child) {
void Container::_sort_children() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
notification(NOTIFICATION_SORT_CHILDREN);
@@ -101,7 +109,7 @@ void Container::fit_child_in_rect(Control *p_child,const Rect2& p_rect) {
void Container::queue_sort() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (pending_sort)
@@ -115,7 +123,7 @@ void Container::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
pending_sort=false;
queue_sort();
} break;
diff --git a/scene/gui/container.h b/scene/gui/container.h
index 841244fb9a..04d5d6ab36 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 6878793360..bd6b8078ff 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -136,44 +136,54 @@ 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_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();
} else
return false;
} 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_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
return false;
}
@@ -183,7 +193,7 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) {
void Control::_update_minimum_size() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
data.pending_min_size_update=false;
@@ -207,22 +217,22 @@ 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_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
@@ -341,7 +351,7 @@ void Control::_notification(int p_notification) {
switch(p_notification) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
if (data.window==this) {
@@ -365,7 +375,7 @@ void Control::_notification(int p_notification) {
window->drag_attempted=false;
window->drag_preview=NULL;
- if (get_scene()->is_editor_hint()) {
+ if (get_tree()->is_editor_hint()) {
Node *n = this;
while(n) {
@@ -385,7 +395,7 @@ void Control::_notification(int p_notification) {
_size_changed();
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (data.window) {
@@ -514,13 +524,15 @@ void Control::_notification(int p_notification) {
if (data.MI) {
- data.window->window->modal_stack.erase(data.MI);
+ if (data.window && data.window->window)
+ data.window->window->modal_stack.erase(data.MI);
data.MI=NULL;
}
if (data.SI) {
//erase from subwindows
- data.window->window->subwindows.erase(data.SI);
+ if (data.window && data.window->window)
+ data.window->window->subwindows.erase(data.SI);
data.SI=NULL;
}
@@ -536,15 +548,18 @@ void Control::_notification(int p_notification) {
Control * parent = get_parent()->cast_to<Control>();
//make children reference them theme
- if (parent && data.theme.is_null() && parent->data.theme_owner)
+
+ if (parent && data.theme.is_null() && parent->data.theme_owner) {
_propagate_theme_changed(parent->data.theme_owner);
+ }
} break;
case NOTIFICATION_UNPARENTED: {
//make children unreference the theme
- if (data.theme.is_null() && data.theme_owner)
+ if (data.theme.is_null() && data.theme_owner) {
_propagate_theme_changed(NULL);
+ }
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
@@ -630,7 +645,7 @@ void Control::_notification(int p_notification) {
}
} break;
- case SceneMainLoop::NOTIFICATION_WM_UNFOCUS_REQUEST: {
+ case SceneTree::NOTIFICATION_WM_UNFOCUS_REQUEST: {
if (!window)
return;
@@ -710,7 +725,7 @@ 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_scene());
+ ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND(!data.window);
ERR_FAIL_COND(p_data.get_type()==Variant::NIL);
@@ -728,8 +743,8 @@ 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_scene() || !data.window);
- ERR_FAIL_COND(p_control->is_inside_scene());
+ 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) {
@@ -940,67 +955,67 @@ void Control::_window_input_event(InputEvent p_event) {
case InputEvent::MOUSE_BUTTON: {
- window->key_event_accepted=false;
+ 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) {
+ 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) {
+ Size2 pos = mpos;
+ if (window->mouse_focus && p_event.mouse_button.button_index!=window->mouse_focus_button) {
- //do not steal mouse focus and stuff
+ //do not steal mouse focus and stuff
- } else {
+ } else {
- _window_sort_modal_stack();
- while (!window->modal_stack.empty()) {
+ _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))) {
+ 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_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- get_scene()->set_input_as_handled();
- return; // no one gets the event if exclusive NO ONE
- }
+ 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;
+ top->notification(NOTIFICATION_MODAL_CLOSE);
+ top->_modal_stack_remove();
+ top->hide();
+ } else {
+ break;
+ }
}
- }
- Matrix32 parent_xform;
+ Matrix32 parent_xform;
- if (data.parent_canvas_item)
- parent_xform=data.parent_canvas_item->get_global_transform();
+ 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;
+ 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 (!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();
- }
+ 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;
@@ -1020,8 +1035,8 @@ void Control::_window_input_event(InputEvent p_event) {
/*if (bool(GLOBAL_DEF("debug/print_clicked_control",false))) {
- print_line(String(window->mouse_focus->get_path())+" - "+pos);
- }*/
+ 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) {
@@ -1033,9 +1048,11 @@ void Control::_window_input_event(InputEvent p_event) {
if (window->mouse_focus->can_process()) {
_window_call_input(window->mouse_focus,p_event);
}
-
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- get_scene()->set_input_as_handled();
+
+ 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 {
@@ -1079,8 +1096,8 @@ void Control::_window_input_event(InputEvent p_event) {
}
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- get_scene()->set_input_as_handled();
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ get_tree()->set_input_as_handled();
}
} break;
@@ -1126,6 +1143,7 @@ void Control::_window_input_event(InputEvent p_event) {
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();
@@ -1147,7 +1165,7 @@ void Control::_window_input_event(InputEvent p_event) {
window->mouse_over=over;
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_tooltip");
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_tooltip");
if (window->drag_preview) {
window->drag_preview->set_pos(pos);
@@ -1203,8 +1221,8 @@ void Control::_window_input_event(InputEvent p_event) {
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- get_scene()->set_input_as_handled();
+ 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) {
@@ -1230,7 +1248,7 @@ void Control::_window_input_event(InputEvent p_event) {
if (window->key_event_accepted) {
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
break;
}
}
@@ -1290,7 +1308,7 @@ void Control::_window_input_event(InputEvent p_event) {
if (next) {
next->grab_focus();
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
}
}
@@ -1305,7 +1323,7 @@ Control *Control::get_window() const {
bool Control::is_window() const {
- return (is_inside_scene() && window);
+ return (is_inside_tree() && window);
}
@@ -1325,9 +1343,12 @@ Size2 Control::get_minimum_size() const {
Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type) const {
- const Ref<Texture>* tex = data.icon_override.getptr(p_name);
- if (tex)
- return *tex;
+ if (p_type==StringName()) {
+
+ const Ref<Texture>* tex = data.icon_override.getptr(p_name);
+ if (tex)
+ return *tex;
+ }
StringName type = p_type?p_type:get_type_name();
@@ -1353,12 +1374,11 @@ Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type
Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p_type) const {
-
- const Ref<StyleBox>* style = data.style_override.getptr(p_name);
-
-
- if (style)
- return *style;
+ if (p_type==StringName()) {
+ const Ref<StyleBox>* style = data.style_override.getptr(p_name);
+ if (style)
+ return *style;
+ }
StringName type = p_type?p_type:get_type_name();
@@ -1381,10 +1401,12 @@ Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p
}
Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) const {
-
- const Ref<Font>* font = data.font_override.getptr(p_name);
- if (font)
- return *font;
+
+ if (p_type==StringName()) {
+ const Ref<Font>* font = data.font_override.getptr(p_name);
+ if (font)
+ return *font;
+ }
StringName type = p_type?p_type:get_type_name();
@@ -1410,10 +1432,12 @@ Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) c
}
Color Control::get_color(const StringName& p_name,const StringName& p_type) const {
-
- const Color* color = data.color_override.getptr(p_name);
- if (color)
- return *color;
+
+ if (p_type==StringName()) {
+ const Color* color = data.color_override.getptr(p_name);
+ if (color)
+ return *color;
+ }
StringName type = p_type?p_type:get_type_name();
// try with custom themes
@@ -1437,10 +1461,12 @@ Color Control::get_color(const StringName& p_name,const StringName& p_type) cons
}
int Control::get_constant(const StringName& p_name,const StringName& p_type) const {
-
- const int* constant = data.constant_override.getptr(p_name);
- if (constant)
- return *constant;
+
+ if (p_type==StringName()) {
+ const int* constant = data.constant_override.getptr(p_name);
+ if (constant)
+ return *constant;
+ }
StringName type = p_type?p_type:get_type_name();
// try with custom themes
@@ -1467,9 +1493,11 @@ int Control::get_constant(const StringName& p_name,const StringName& p_type) con
bool Control::has_icon(const StringName& p_name,const StringName& p_type) const {
- const Ref<Texture>* tex = data.icon_override.getptr(p_name);
- if (tex)
- return true;
+ if (p_type==StringName()) {
+ const Ref<Texture>* tex = data.icon_override.getptr(p_name);
+ if (tex)
+ return true;
+ }
StringName type = p_type?p_type:get_type_name();
@@ -1494,11 +1522,12 @@ bool Control::has_icon(const StringName& p_name,const StringName& p_type) const
}
bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) const {
-
- const Ref<StyleBox>* style = data.style_override.getptr(p_name);
-
- if (style)
- return true;
+ if (p_type==StringName()) {
+ const Ref<StyleBox>* style = data.style_override.getptr(p_name);
+
+ if (style)
+ return true;
+ }
StringName type = p_type?p_type:get_type_name();
@@ -1523,9 +1552,11 @@ bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) co
}
bool Control::has_font(const StringName& p_name,const StringName& p_type) const {
- const Ref<Font>* font = data.font_override.getptr(p_name);
- if (font)
- return true;
+ if (p_type==StringName()) {
+ const Ref<Font>* font = data.font_override.getptr(p_name);
+ if (font)
+ return true;
+ }
StringName type = p_type?p_type:get_type_name();
@@ -1551,9 +1582,11 @@ bool Control::has_font(const StringName& p_name,const StringName& p_type) const
}
bool Control::has_color(const StringName& p_name,const StringName& p_type) const {
- const Color* color = data.color_override.getptr(p_name);
- if (color)
- return true;
+ if (p_type==StringName()) {
+ const Color* color = data.color_override.getptr(p_name);
+ if (color)
+ return true;
+ }
StringName type = p_type?p_type:get_type_name();
@@ -1578,10 +1611,13 @@ bool Control::has_color(const StringName& p_name,const StringName& p_type) const
}
bool Control::has_constant(const StringName& p_name,const StringName& p_type) const {
-
- const int* constant = data.constant_override.getptr(p_name);
- if (constant)
- return true;
+
+ if (p_type==StringName()) {
+
+ const int* constant = data.constant_override.getptr(p_name);
+ if (constant)
+ return true;
+ }
StringName type = p_type?p_type:get_type_name();
@@ -1607,7 +1643,7 @@ bool Control::has_constant(const StringName& p_name,const StringName& p_type) co
Size2 Control::get_parent_area_size() const {
- ERR_FAIL_COND_V(!is_inside_scene(),Size2());
+ ERR_FAIL_COND_V(!is_inside_tree(),Size2());
Size2 parent_size;
@@ -1624,7 +1660,7 @@ Size2 Control::get_parent_area_size() const {
void Control::_size_changed() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
Size2 parent_size = get_parent_area_size();
@@ -1677,7 +1713,7 @@ void Control::_size_changed() {
float Control::_get_parent_range(int p_idx) const {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
return 1.0;
@@ -1738,9 +1774,9 @@ float Control::_a2s(float p_val, AnchorType p_anchor,float p_range) const {
case ANCHOR_RATIO: {
return Math::floor(p_range*p_val);
} break;
- case ANCHOR_CENTER: {
- return Math::floor((p_range/2)-p_val);
- } break;
+ case ANCHOR_CENTER: {
+ return Math::floor((p_range/2)-p_val);
+ } break;
}
return 0;
}
@@ -1748,7 +1784,7 @@ float Control::_a2s(float p_val, AnchorType p_anchor,float p_range) const {
void Control::set_anchor(Margin p_margin,AnchorType p_anchor) {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
data.anchor[p_margin]=p_anchor;
} else {
@@ -1980,7 +2016,7 @@ void Control::add_constant_override(const StringName& p_name, int p_constant) {
void Control::set_focus_mode(FocusMode p_focus_mode) {
- if (is_inside_scene() && p_focus_mode == FOCUS_NONE && data.focus_mode!=FOCUS_NONE && has_focus())
+ if (is_inside_tree() && p_focus_mode == FOCUS_NONE && data.focus_mode!=FOCUS_NONE && has_focus())
release_focus();
data.focus_mode=p_focus_mode;
@@ -2178,7 +2214,7 @@ bool Control::has_focus() const {
void Control::grab_focus() {
- ERR_FAIL_COND(!is_inside_scene());
+ ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND(!data.window);
if (data.focus_mode==FOCUS_NONE)
@@ -2188,7 +2224,7 @@ void Control::grab_focus() {
if (data.window->window->key_focus && data.window->window->key_focus==this)
return;
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_window_remove_focus");
+ 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
@@ -2202,13 +2238,13 @@ void Control::grab_focus() {
void Control::release_focus() {
- ERR_FAIL_COND(!is_inside_scene());
+ ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND(!data.window);
if (!has_focus())
return;
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_window_remove_focus");
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_window_remove_focus");
//data.window->window->key_focus=this;
//notification(NOTIFICATION_FOCUS_ENTER);
update();
@@ -2217,12 +2253,12 @@ void Control::release_focus() {
bool Control::is_toplevel_control() const {
- return is_inside_scene() && (!data.parent_canvas_item && !window && is_set_as_toplevel());
+ return is_inside_tree() && (!data.parent_canvas_item && !window && is_set_as_toplevel());
}
void Control::show_modal(bool p_exclusive) {
- ERR_FAIL_COND(!is_inside_scene());
+ ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND(!data.SI && data.window!=this);
ERR_FAIL_COND(!data.window);
@@ -2248,7 +2284,10 @@ 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;
}
@@ -2282,7 +2321,7 @@ void Control::_modal_stack_remove() {
if (!pfoc)
return;
- if (!pfoc->is_inside_scene() || !pfoc->is_visible())
+ if (!pfoc->is_inside_tree() || !pfoc->is_visible())
return;
pfoc->grab_focus();
} else {
@@ -2332,13 +2371,13 @@ void Control::set_theme(const Ref<Theme>& p_theme) {
void Control::_window_accept_event() {
window->key_event_accepted=true;
- if (is_inside_scene())
- get_scene()->set_input_as_handled();
+ if (is_inside_tree())
+ get_tree()->set_input_as_handled();
}
void Control::accept_event() {
- if (is_inside_scene() && get_window())
+ if (is_inside_tree() && get_window())
get_window()->_window_accept_event();
}
@@ -2585,7 +2624,7 @@ float Control::get_stretch_ratio() const {
void Control::grab_click_focus() {
- ERR_FAIL_COND(!is_inside_scene());
+ ERR_FAIL_COND(!is_inside_tree());
if (data.window && data.window->window->mouse_focus) {
@@ -2620,7 +2659,7 @@ void Control::grab_click_focus() {
void Control::minimum_size_changed() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (data.pending_min_size_update)
@@ -2663,9 +2702,30 @@ bool Control::is_stopping_mouse() const {
Control *Control::get_focus_owner() const {
- ERR_FAIL_COND_V(!is_inside_scene(),NULL);
- ERR_FAIL_COND_V(!window,NULL);
- return window->key_focus;
+ ERR_FAIL_COND_V(!is_inside_tree(),NULL);
+ ERR_FAIL_COND_V(!data.window,NULL);
+ return data.window->window->key_focus;
+}
+
+
+void Control::warp_mouse(const Point2& p_to_pos) {
+ ERR_FAIL_COND(!is_inside_tree());
+ 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::_bind_methods() {
@@ -2764,6 +2824,9 @@ void Control::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_drag_preview","control:Control"),&Control::set_drag_preview);
+ ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"),&Control::warp_mouse);
+
+
BIND_VMETHOD(MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"event")));
BIND_VMETHOD(MethodInfo(Variant::VECTOR2,"get_minimum_size"));
BIND_VMETHOD(MethodInfo(Variant::OBJECT,"get_drag_data",PropertyInfo(Variant::VECTOR2,"pos")));
@@ -2784,16 +2847,16 @@ void Control::_bind_methods() {
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::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 );
@@ -2836,7 +2899,7 @@ void Control::_bind_methods() {
BIND_CONSTANT( SIZE_EXPAND_FILL );
ADD_SIGNAL( MethodInfo("resized") );
- ADD_SIGNAL( MethodInfo("input_event") );
+ ADD_SIGNAL( MethodInfo("input_event",PropertyInfo(Variant::INPUT_EVENT,"ev")) );
ADD_SIGNAL( MethodInfo("mouse_enter") );
ADD_SIGNAL( MethodInfo("mouse_exit") );
ADD_SIGNAL( MethodInfo("focus_enter") );
diff --git a/scene/gui/control.h b/scene/gui/control.h
index f9225a1c2b..4311b299c8 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -55,7 +55,7 @@ public:
ANCHOR_BEGIN,
ANCHOR_END,
ANCHOR_RATIO,
- ANCHOR_CENTER,
+ ANCHOR_CENTER,
};
enum FocusMode {
@@ -380,7 +380,9 @@ public:
void grab_click_focus();
+ void warp_mouse(const Point2& p_to_pos);
+ virtual bool is_text_field() const;
Control();
~Control();
diff --git a/scene/gui/custom_button.cpp b/scene/gui/custom_button.cpp
index ed3f01e5fa..53a3bf0914 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/custom_button.h b/scene/gui/custom_button.h
index 1f0f0470ed..49fcf7408f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index ac0ded03ab..efda8a66e1 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -93,7 +93,7 @@ void WindowDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED:
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
close_button->set_normal_texture( get_icon("close","WindowDialog"));
close_button->set_pressed_texture( get_icon("close","WindowDialog"));
@@ -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;
@@ -297,7 +297,7 @@ void AcceptDialog::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_label"),&AcceptDialog::get_label);
ObjectTypeDB::bind_method(_MD("set_hide_on_ok","enabled"),&AcceptDialog::set_hide_on_ok);
ObjectTypeDB::bind_method(_MD("get_hide_on_ok"),&AcceptDialog::get_hide_on_ok);
- ObjectTypeDB::bind_method(_MD("add_button:Button","text","right","action"),&AcceptDialog::add_cancel,DEFVAL(false),DEFVAL(""));
+ ObjectTypeDB::bind_method(_MD("add_button:Button","text","right","action"),&AcceptDialog::add_button,DEFVAL(false),DEFVAL(""));
ObjectTypeDB::bind_method(_MD("add_cancel:Button","name"),&AcceptDialog::add_cancel);
ObjectTypeDB::bind_method(_MD("_builtin_text_entered"),&AcceptDialog::_builtin_text_entered);
ObjectTypeDB::bind_method(_MD("register_text_enter:LineEdit","line_edit"),&AcceptDialog::register_text_enter);
@@ -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") );
+
}
@@ -328,8 +330,8 @@ AcceptDialog::AcceptDialog() {
label->set_anchor(MARGIN_RIGHT,ANCHOR_END);
label->set_anchor(MARGIN_BOTTOM,ANCHOR_END);
label->set_begin( Point2( margin, margin) );
- label->set_end( Point2( margin, button_margin) );
- label->set_autowrap(true);
+ label->set_end( Point2( margin, button_margin+10) );
+ //label->set_autowrap(true);
add_child(label);
hbc = memnew( HBoxContainer );
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index e547d5f2af..67c574a420 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/empty_control.cpp b/scene/gui/empty_control.cpp
deleted file mode 100644
index 1e377b2b73..0000000000
--- a/scene/gui/empty_control.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*************************************************************************/
-/* empty_control.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "empty_control.h"
-
-Size2 EmptyControl::get_minimum_size() const {
-
- return minsize;
-}
-
-void EmptyControl::set_minsize(const Size2& p_size) {
-
- minsize=p_size;
- minimum_size_changed();
-}
-
-Size2 EmptyControl::get_minsize() const {
-
- return minsize;
-}
-
-
-void EmptyControl::_bind_methods() {
-
-
- ObjectTypeDB::bind_method(_MD("set_minsize","minsize"),&EmptyControl::set_minsize);
- ObjectTypeDB::bind_method(_MD("get_minsize"),&EmptyControl::get_minsize);
-
- ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"minsize"), _SCS("set_minsize"),_SCS("get_minsize") );
-}
-
-EmptyControl::EmptyControl()
-{
-}
diff --git a/scene/gui/empty_control.h b/scene/gui/empty_control.h
deleted file mode 100644
index 993af45ac4..0000000000
--- a/scene/gui/empty_control.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*************************************************************************/
-/* empty_control.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef EMPTY_CONTROL_H
-#define EMPTY_CONTROL_H
-
-#include "scene/gui/control.h"
-
-class EmptyControl : public Control {
-
- OBJ_TYPE(EmptyControl,Control);
- Size2 minsize;
-protected:
- static void _bind_methods();
-public:
- virtual Size2 get_minimum_size() const;
- void set_minsize(const Size2& p_size);
- Size2 get_minsize() const;
-
- EmptyControl();
-};
-
-#endif // EMPTY_CONTROL_H
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index a7ff1431bd..22e3a81e52 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,6 +29,8 @@
#include "file_dialog.h"
#include "scene/gui/label.h"
#include "print_string.h"
+#include "os/keyboard.h"
+
FileDialog::GetIconFunc FileDialog::get_icon_func=NULL;
@@ -44,6 +46,11 @@ VBoxContainer *FileDialog::get_vbox() {
}
void FileDialog::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ refresh->set_icon(get_icon("Reload","EditorIcons"));
+ }
if (p_what==NOTIFICATION_DRAW) {
@@ -90,7 +97,6 @@ void FileDialog::_file_entered(const String& p_file) {
}
void FileDialog::_save_confirm_pressed() {
-
String f=dir_access->get_current_dir().plus_file(file->get_text());
emit_signal("file_selected",f);
hide();
@@ -156,7 +162,6 @@ void FileDialog::_action_pressed() {
if (mode==MODE_SAVE_FILE) {
- String ext = f.extension();
bool valid=false;
if (filter->get_selected()==filter->get_item_count()-1) {
@@ -184,7 +189,8 @@ void FileDialog::_action_pressed() {
if (idx>=0 && idx<filters.size()) {
String flt=filters[idx].get_slice(";",0);
- for (int j=0;j<flt.get_slice_count(",");j++) {
+ int filterSliceCount=flt.get_slice_count(",");
+ for (int j=0;j<filterSliceCount;j++) {
String str = (flt.get_slice(",",j).strip_edges());
if (f.match(str)) {
@@ -192,6 +198,13 @@ void FileDialog::_action_pressed() {
break;
}
}
+
+ if (!valid && filterSliceCount>0) {
+ String str = (flt.get_slice(",",0).strip_edges());
+ f+=str.substr(1, str.length()-1);
+ file->set_text(f.get_file());
+ valid=true;
+ }
} else {
valid=true;
}
@@ -271,13 +284,20 @@ void FileDialog::update_file_list() {
List<String> dirs;
bool isdir;
+ bool ishidden;
+ bool show_hidden = show_hidden_files;
String item;
+
while ((item=dir_access->get_next(&isdir))!="") {
-
- if (!isdir)
- files.push_back(item);
- else
- dirs.push_back(item);
+
+ ishidden = dir_access->current_is_hidden();
+
+ if (show_hidden || !ishidden) {
+ if (!isdir)
+ files.push_back(item);
+ else
+ dirs.push_back(item);
+ }
}
dirs.sort_custom<NoCaseComparator>();
@@ -593,22 +613,19 @@ void FileDialog::_update_drives() {
drives->clear();
drives->show();
- int current=-1;
- String abspath = dir_access->get_current_dir();
-
for(int i=0;i<dir_access->get_drive_count();i++) {
- String d = dir_access->get_drive(i);
- if (abspath.begins_with(d))
- current=i;
+ String d = dir_access->get_drive(i);
drives->add_item(dir_access->get_drive(i));
}
- if (current!=-1)
- drives->select(current);
+ drives->select(dir_access->get_current_drive());
}
}
+bool FileDialog::default_show_hidden_files=false;
+
+
void FileDialog::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_tree_selected"),&FileDialog::_tree_selected);
@@ -633,6 +650,8 @@ 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("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);
ObjectTypeDB::bind_method(_MD("_make_dir_confirm"),&FileDialog::_make_dir_confirm);
@@ -657,9 +676,23 @@ void FileDialog::_bind_methods() {
}
+void FileDialog::set_show_hidden_files(bool p_show) {
+ show_hidden_files=p_show;
+ invalidate();
+}
+
+bool FileDialog::is_showing_hidden_files() const {
+ return show_hidden_files;
+}
+
+void FileDialog::set_default_show_hidden_files(bool p_show) {
+ default_show_hidden_files=p_show;
+}
FileDialog::FileDialog() {
-
+
+ show_hidden_files=default_show_hidden_files;
+
VBoxContainer *vbc = memnew( VBoxContainer );
add_child(vbc);
set_child_rect(vbc);
@@ -672,6 +705,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 bda1797696..370088b215 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,9 +87,15 @@ private:
OptionButton *filter;
DirAccess *dir_access;
ConfirmationDialog *confirm_save;
+
+ ToolButton *refresh;
Vector<String> filters;
+
+ static bool default_show_hidden_files;
+ bool show_hidden_files;
+
bool invalidated;
void update_dir();
@@ -141,6 +148,11 @@ public:
void set_access(Access p_access);
Access get_access() const;
+ void set_show_hidden_files(bool p_show);
+ bool is_showing_hidden_files() const;
+
+ static void set_default_show_hidden_files(bool p_show);
+
void invalidate();
FileDialog();
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
new file mode 100644
index 0000000000..deb3151798
--- /dev/null
+++ b/scene/gui/graph_edit.cpp
@@ -0,0 +1,773 @@
+#include "graph_edit.h"
+#include "os/input.h"
+#include "os/keyboard.h"
+bool GraphEditFilter::has_point(const Point2& p_point) const {
+
+ return ge->_filter_input(p_point);
+}
+
+
+GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) {
+
+ ge=p_edit;
+}
+
+
+Error GraphEdit::connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) {
+
+ if (is_node_connected(p_from,p_from_port,p_to,p_to_port))
+ return OK;
+ Connection c;
+ c.from=p_from;
+ c.from_port=p_from_port;
+ c.to=p_to;
+ c.to_port=p_to_port;
+ connections.push_back(c);
+ top_layer->update();
+
+ return OK;
+}
+
+bool GraphEdit::is_node_connected(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)
+ return true;
+ }
+
+ return false;
+
+}
+
+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) {
+
+ connections.erase(E);
+ top_layer->update();
+ return;
+ }
+ }
+}
+
+void GraphEdit::get_connection_list(List<Connection> *r_connections) const {
+
+ *r_connections=connections;
+}
+
+
+void GraphEdit::_scroll_moved(double) {
+
+
+ _update_scroll_offset();
+ top_layer->update();
+}
+
+void GraphEdit::_update_scroll_offset() {
+
+ for(int i=0;i<get_child_count();i++) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ Point2 pos=gn->get_offset();
+ pos-=Point2(h_scroll->get_val(),v_scroll->get_val());
+ gn->set_pos(pos);
+ }
+
+}
+
+void GraphEdit::_update_scroll() {
+
+ if (updating)
+ return;
+
+ updating=true;
+ Rect2 screen;
+ for(int i=0;i<get_child_count();i++) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ Rect2 r;
+ r.pos=gn->get_offset();
+ r.size=gn->get_size();
+ screen = screen.merge(r);
+ }
+
+ screen.pos-=get_size();
+ screen.size+=get_size()*2.0;
+
+
+ h_scroll->set_min(screen.pos.x);
+ h_scroll->set_max(screen.pos.x+screen.size.x);
+ h_scroll->set_page(get_size().x);
+ if (h_scroll->get_max() - h_scroll->get_min() <= h_scroll->get_page())
+ h_scroll->hide();
+ else
+ h_scroll->show();
+
+ v_scroll->set_min(screen.pos.y);
+ v_scroll->set_max(screen.pos.y+screen.size.y);
+ v_scroll->set_page(get_size().y);
+
+ if (v_scroll->get_max() - v_scroll->get_min() <= v_scroll->get_page())
+ v_scroll->hide();
+ else
+ v_scroll->show();
+
+ _update_scroll_offset();
+ updating=false;
+}
+
+
+void GraphEdit::_graph_node_raised(Node* p_gn) {
+
+ GraphNode *gn=p_gn->cast_to<GraphNode>();
+ ERR_FAIL_COND(!gn);
+ gn->raise();
+ top_layer->raise();
+
+}
+
+
+void GraphEdit::_graph_node_moved(Node *p_gn) {
+
+ GraphNode *gn=p_gn->cast_to<GraphNode>();
+ ERR_FAIL_COND(!gn);
+ top_layer->update();
+}
+
+void GraphEdit::add_child_notify(Node *p_child) {
+
+ top_layer->call_deferred("raise"); //top layer always on top!
+ GraphNode *gn = p_child->cast_to<GraphNode>();
+ if (gn) {
+ gn->connect("offset_changed",this,"_graph_node_moved",varray(gn));
+ gn->connect("raise_request",this,"_graph_node_raised",varray(gn));
+ _graph_node_moved(gn);
+ gn->set_stop_mouse(false);
+ }
+}
+
+void GraphEdit::remove_child_notify(Node *p_child) {
+
+ top_layer->call_deferred("raise"); //top layer always on top!
+ GraphNode *gn = p_child->cast_to<GraphNode>();
+ if (gn) {
+ gn->disconnect("offset_changed",this,"_graph_node_moved");
+ gn->disconnect("raise_request",this,"_graph_node_raised");
+ }
+}
+
+void GraphEdit::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_READY) {
+ Size2 hmin = h_scroll->get_combined_minimum_size();
+ Size2 vmin = v_scroll->get_combined_minimum_size();
+
+ v_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,vmin.width);
+ v_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0);
+ v_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,0);
+ v_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0);
+
+ h_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,0);
+ h_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0);
+ h_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,hmin.height);
+ h_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0);
+
+ }
+ if (p_what==NOTIFICATION_DRAW) {
+ VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
+
+ }
+
+ if (p_what==NOTIFICATION_RESIZED) {
+ _update_scroll();
+ top_layer->update();
+ }
+}
+
+bool GraphEdit::_filter_input(const Point2& p_point) {
+
+ Ref<Texture> port =get_icon("port","GraphNode");
+
+ float grab_r=port->get_width()*0.5;
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ for(int j=0;j<gn->get_connection_output_count();j++) {
+
+ Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
+ if (pos.distance_to(p_point)<grab_r)
+ return true;
+
+
+ }
+
+ for(int j=0;j<gn->get_connection_input_count();j++) {
+
+ Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
+ if (pos.distance_to(p_point)<grab_r)
+ return true;
+
+
+ }
+
+ }
+
+ return false;
+}
+
+void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
+
+ if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && p_ev.mouse_button.pressed) {
+
+ Ref<Texture> port =get_icon("port","GraphNode");
+ Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y);
+ float grab_r=port->get_width()*0.5;
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ for(int j=0;j<gn->get_connection_output_count();j++) {
+
+ Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
+ if (pos.distance_to(mpos)<grab_r) {
+
+ connecting=true;
+ connecting_from=gn->get_name();
+ connecting_index=j;
+ connecting_out=true;
+ connecting_type=gn->get_connection_output_type(j);
+ connecting_color=gn->get_connection_output_color(j);
+ connecting_target=false;
+ connecting_to=pos;
+ return;
+ }
+
+
+ }
+
+ for(int j=0;j<gn->get_connection_input_count();j++) {
+
+ Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
+
+ if (pos.distance_to(mpos)<grab_r) {
+
+ if (right_disconnects) {
+ //check disconnect
+ for (List<Connection>::Element*E=connections.front();E;E=E->next()) {
+
+ if (E->get().to==gn->get_name() && E->get().to_port==j) {
+
+ Node*fr = get_node(String(E->get().from));
+ if (fr && fr->cast_to<GraphNode>()) {
+
+ connecting_from=E->get().from;
+ connecting_index=E->get().from_port;
+ connecting_out=true;
+ connecting_type=fr->cast_to<GraphNode>()->get_connection_output_type(E->get().from_port);
+ connecting_color=fr->cast_to<GraphNode>()->get_connection_output_color(E->get().from_port);
+ connecting_target=false;
+ connecting_to=pos;
+
+ emit_signal("disconnection_request",E->get().from,E->get().from_port,E->get().to,E->get().to_port);
+ fr = get_node(String(connecting_from)); //maybe it was erased
+ if (fr && fr->cast_to<GraphNode>()) {
+ connecting=true;
+ }
+ return;
+ }
+
+ }
+ }
+ }
+
+
+ connecting=true;
+ connecting_from=gn->get_name();
+ connecting_index=j;
+ connecting_out=false;
+ connecting_type=gn->get_connection_input_type(j);
+ connecting_color=gn->get_connection_input_color(j);
+ connecting_target=false;
+ connecting_to=pos;
+ return;
+ }
+
+
+ }
+ }
+ }
+
+ if (p_ev.type==InputEvent::MOUSE_MOTION && connecting) {
+
+ connecting_to=Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y);
+ connecting_target=false;
+ top_layer->update();
+
+ Ref<Texture> port =get_icon("port","GraphNode");
+ Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y);
+ float grab_r=port->get_width()*0.5;
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ if (!connecting_out) {
+ for(int j=0;j<gn->get_connection_output_count();j++) {
+
+ Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
+ int type =gn->get_connection_output_type(j);
+ if (type==connecting_type && pos.distance_to(mpos)<grab_r) {
+
+ connecting_target=true;
+ connecting_to=pos;
+ connecting_target_to=gn->get_name();
+ connecting_target_index=j;
+ return;
+ }
+
+
+ }
+ } else {
+
+ for(int j=0;j<gn->get_connection_input_count();j++) {
+
+ Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
+ int type =gn->get_connection_input_type(j);
+ if (type==connecting_type && pos.distance_to(mpos)<grab_r) {
+ connecting_target=true;
+ connecting_to=pos;
+ connecting_target_to=gn->get_name();
+ connecting_target_index=j;
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && !p_ev.mouse_button.pressed) {
+
+ if (connecting && connecting_target) {
+
+ String from = connecting_from;
+ int from_slot = connecting_index;
+ String to =connecting_target_to;
+ int to_slot = connecting_target_index;
+
+ if (!connecting_out) {
+ SWAP(from,to);
+ SWAP(from_slot,to_slot);
+ }
+ emit_signal("connection_request",from,from_slot,to,to_slot);
+
+ }
+ connecting=false;
+ top_layer->update();
+
+ }
+
+
+
+}
+
+void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color) {
+
+ static const int steps = 20;
+
+ Rect2 r;
+ r.pos=p_from;
+ r.expand_to(p_to);
+ Vector2 sign=Vector2((p_from.x < p_to.x) ? 1 : -1,(p_from.y < p_to.y) ? 1 : -1);
+ bool flip = sign.x * sign.y < 0;
+
+ Vector2 prev;
+ for(int i=0;i<=steps;i++) {
+
+ float d = i/float(steps);
+ float c=-Math::cos(d*Math_PI) * 0.5+0.5;
+ if (flip)
+ c=1.0-c;
+ Vector2 p = r.pos+Vector2(d*r.size.width,c*r.size.height);
+
+ if (i>0) {
+
+ top_layer->draw_line(prev,p,p_color,2);
+ }
+
+ prev=p;
+ }
+}
+
+void GraphEdit::_top_layer_draw() {
+
+ _update_scroll();
+
+ if (connecting) {
+
+ Node *fromn = get_node(connecting_from);
+ ERR_FAIL_COND(!fromn);
+ GraphNode *from = fromn->cast_to<GraphNode>();
+ ERR_FAIL_COND(!from);
+ Vector2 pos;
+ if (connecting_out)
+ pos=from->get_connection_output_pos(connecting_index);
+ else
+ pos=from->get_connection_input_pos(connecting_index);
+ pos+=from->get_pos();
+
+ Vector2 topos;
+ topos=connecting_to;
+
+ Color col=connecting_color;
+
+ if (connecting_target) {
+ col.r+=0.4;
+ col.g+=0.4;
+ col.b+=0.4;
+ }
+ _draw_cos_line(pos,topos,col);
+ }
+
+ List<List<Connection>::Element* > to_erase;
+ for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
+
+ NodePath fromnp(E->get().from);
+
+ Node * from = get_node(fromnp);
+ if (!from) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ GraphNode *gfrom = from->cast_to<GraphNode>();
+
+ if (!gfrom) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ NodePath tonp(E->get().to);
+ Node * to = get_node(tonp);
+ if (!to) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ GraphNode *gto = to->cast_to<GraphNode>();
+
+ if (!gto) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos();
+ Color color = gfrom->get_connection_output_color(E->get().from_port);
+ Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos();
+ _draw_cos_line(frompos,topos,color);
+
+ }
+
+ while(to_erase.size()) {
+ connections.erase(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+ 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) {
+
+ if (p_ev.type==InputEvent::MOUSE_MOTION && (p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE || (p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
+ 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() {
+
+ connections.clear();
+ update();
+}
+
+
+void GraphEdit::set_right_disconnects(bool p_enable) {
+
+ right_disconnects=p_enable;
+}
+
+bool GraphEdit::is_right_disconnects_enabled() const{
+
+ return right_disconnects;
+}
+
+Array GraphEdit::_get_connection_list() const {
+
+ List<Connection> conns;
+ get_connection_list(&conns);
+ Array arr;
+ for(List<Connection>::Element *E=conns.front();E;E=E->next()) {
+ Dictionary d;
+ d["from"]=E->get().from;
+ d["from_port"]=E->get().from_port;
+ d["to"]=E->get().to;
+ d["to_port"]=E->get().to_port;
+ arr.push_back(d);
+ }
+ return arr;
+}
+void GraphEdit::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("connect_node:Error","from","from_port","to","to_port"),&GraphEdit::connect_node);
+ 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("set_right_disconnects","enable"),&GraphEdit::set_right_disconnects);
+ ObjectTypeDB::bind_method(_MD("is_right_disconnects_enabled"),&GraphEdit::is_right_disconnects_enabled);
+
+ ObjectTypeDB::bind_method(_MD("_graph_node_moved"),&GraphEdit::_graph_node_moved);
+ ObjectTypeDB::bind_method(_MD("_graph_node_raised"),&GraphEdit::_graph_node_raised);
+
+ ObjectTypeDB::bind_method(_MD("_top_layer_input"),&GraphEdit::_top_layer_input);
+ ObjectTypeDB::bind_method(_MD("_top_layer_draw"),&GraphEdit::_top_layer_draw);
+ ObjectTypeDB::bind_method(_MD("_scroll_moved"),&GraphEdit::_scroll_moved);
+
+ ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event);
+
+ 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);
+ top_layer->set_stop_mouse(false);
+ top_layer->set_area_as_parent_rect();
+ top_layer->connect("draw",this,"_top_layer_draw");
+ top_layer->set_stop_mouse(false);
+ top_layer->connect("input_event",this,"_top_layer_input");
+
+ h_scroll = memnew(HScrollBar);
+ h_scroll->set_name("_h_scroll");
+ top_layer->add_child(h_scroll);
+
+ v_scroll = memnew(VScrollBar);
+ v_scroll->set_name("_v_scroll");
+ top_layer->add_child(v_scroll);
+ updating=false;
+ 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
new file mode 100644
index 0000000000..44f5a369c2
--- /dev/null
+++ b/scene/gui/graph_edit.h
@@ -0,0 +1,109 @@
+#ifndef GRAPH_EDIT_H
+#define GRAPH_EDIT_H
+
+#include "scene/gui/graph_node.h"
+#include "scene/gui/scroll_bar.h"
+
+class GraphEdit;
+
+class GraphEditFilter : public Control {
+
+ OBJ_TYPE(GraphEditFilter,Control);
+
+ friend class GraphEdit;
+ GraphEdit *ge;
+ virtual bool has_point(const Point2& p_point) const;
+
+public:
+
+
+ GraphEditFilter(GraphEdit *p_edit);
+};
+
+class GraphEdit : public Control {
+
+ OBJ_TYPE(GraphEdit,Control);
+public:
+
+ struct Connection {
+ StringName from;
+ StringName to;
+ int from_port;
+ int to_port;
+
+ };
+private:
+
+ HScrollBar* h_scroll;
+ VScrollBar* v_scroll;
+
+
+ bool connecting;
+ String connecting_from;
+ bool connecting_out;
+ int connecting_index;
+ int connecting_type;
+ Color connecting_color;
+ bool connecting_target;
+ Vector2 connecting_to;
+ 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;
+ List<Connection> connections;
+
+ void _draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color);
+
+ void _graph_node_raised(Node* p_gn);
+ void _graph_node_moved(Node *p_gn);
+
+ void _update_scroll();
+ void _scroll_moved(double);
+ void _input_event(const InputEvent& p_ev);
+
+ GraphEditFilter *top_layer;
+ void _top_layer_input(const InputEvent& p_ev);
+ void _top_layer_draw();
+ void _update_scroll_offset();
+
+ Array _get_connection_list() const;
+
+ friend class GraphEditFilter;
+ bool _filter_input(const Point2& p_point);
+protected:
+
+ static void _bind_methods();
+ virtual void add_child_notify(Node *p_child);
+ virtual void remove_child_notify(Node *p_child);
+ void _notification(int p_what);
+
+public:
+
+ Error connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
+ bool is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
+ void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
+ void clear_connections();
+
+ GraphEditFilter *get_top_layer() const { return top_layer; }
+ void get_connection_list(List<Connection> *r_connections) const;
+
+ void set_right_disconnects(bool p_enable);
+ bool is_right_disconnects_enabled() const;
+
+
+ GraphEdit();
+};
+
+#endif // GRAPHEdit_H
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
new file mode 100644
index 0000000000..5efc9757b7
--- /dev/null
+++ b/scene/gui/graph_node.cpp
@@ -0,0 +1,589 @@
+#include "graph_node.h"
+#include "method_bind_ext.inc"
+
+
+bool GraphNode::_set(const StringName& p_name, const Variant& p_value) {
+
+ if (!p_name.operator String().begins_with("slot/"))
+ return false;
+
+ int idx=p_name.operator String().get_slice("/",1).to_int();
+ String what = p_name.operator String().get_slice("/",2);
+
+
+ Slot si;
+ if (slot_info.has(idx))
+ si=slot_info[idx];
+
+
+ if (what=="left_enabled")
+ si.enable_left=p_value;
+ else if (what=="left_type")
+ si.type_left=p_value;
+ else if (what=="left_color")
+ si.color_left=p_value;
+ else if (what=="right_enabled")
+ si.enable_right=p_value;
+ else if (what=="right_type")
+ si.type_right=p_value;
+ else if (what=="right_color")
+ si.color_right=p_value;
+ else
+ return false;
+
+ set_slot(idx,si.enable_left,si.type_left,si.color_left,si.enable_right,si.type_right,si.color_right);
+ update();
+ return true;
+}
+
+bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{
+
+
+
+ if (!p_name.operator String().begins_with("slot/")) {
+ return false;
+ }
+
+ int idx=p_name.operator String().get_slice("/",1).to_int();
+ String what = p_name.operator String().get_slice("/",2);
+
+
+
+ Slot si;
+ if (slot_info.has(idx))
+ si=slot_info[idx];
+
+ if (what=="left_enabled")
+ r_ret=si.enable_left;
+ else if (what=="left_type")
+ r_ret=si.type_left;
+ else if (what=="left_color")
+ r_ret=si.color_left;
+ else if (what=="right_enabled")
+ r_ret=si.enable_right;
+ else if (what=="right_type")
+ r_ret=si.type_right;
+ else if (what=="right_color")
+ r_ret=si.color_right;
+ else
+ return false;
+
+ return true;
+}
+void GraphNode::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ int idx=0;
+ for(int i=0;i<get_child_count();i++) {
+ Control *c=get_child(i)->cast_to<Control>();
+ if (!c || c->is_set_as_toplevel() )
+ continue;
+
+ String base="slot/"+itos(idx)+"/";
+
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"left_enabled"));
+ p_list->push_back(PropertyInfo(Variant::INT,base+"left_type"));
+ p_list->push_back(PropertyInfo(Variant::COLOR,base+"left_color"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"right_enabled"));
+ p_list->push_back(PropertyInfo(Variant::INT,base+"right_type"));
+ p_list->push_back(PropertyInfo(Variant::COLOR,base+"right_color"));
+
+ idx++;
+ }
+}
+
+
+void GraphNode::_resort() {
+
+
+
+ int sep=get_constant("separation");
+ Ref<StyleBox> sb=get_stylebox("frame");
+ bool first=true;
+
+ Size2 minsize;
+
+ 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;
+
+ Size2i size=c->get_combined_minimum_size();
+
+ minsize.y+=size.y;
+ minsize.x=MAX(minsize.x,size.x);
+
+ if (first)
+ first=false;
+ else
+ minsize.y+=sep;
+
+ }
+
+
+ int vofs=0;
+ int w = get_size().x - sb->get_minimum_size().x;
+
+
+ cache_y.clear();
+ 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;
+
+ Size2i size=c->get_combined_minimum_size();
+
+ Rect2 r(sb->get_margin(MARGIN_LEFT),sb->get_margin(MARGIN_TOP)+vofs,w,size.y);
+
+ fit_child_in_rect(c,r);
+ cache_y.push_back(vofs+size.y*0.5);
+
+ if (vofs>0)
+ vofs+=sep;
+ vofs+=size.y;
+
+
+ }
+
+ _change_notify();
+ update();
+ connpos_dirty=true;
+
+
+}
+
+
+void GraphNode::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ 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");
+ Ref<Font> title_font = get_font("title_font");
+ int title_offset = get_constant("title_offset");
+ Color title_color = get_color("title_color");
+ Point2i icofs = -port->get_size()*0.5;
+ int edgeofs=get_constant("port_offset");
+ icofs.y+=sb->get_margin(MARGIN_TOP);
+ draw_style_box(sb,Rect2(Point2(),get_size()));
+
+ int w = get_size().width-sb->get_minimum_size().x;
+
+ if (show_close)
+ w-=close->get_width();
+
+ draw_string(title_font,Point2(sb->get_margin(MARGIN_LEFT),-title_font->get_height()+title_font->get_ascent()+title_offset),title,title_color,w);
+ if (show_close) {
+ Vector2 cpos = Point2(w+sb->get_margin(MARGIN_LEFT),-close->get_height()+close_offset);
+ draw_texture(close,cpos);
+ close_rect.pos=cpos;
+ close_rect.size=close->get_size();
+ } else {
+ close_rect=Rect2();
+ }
+
+ for (Map<int,Slot>::Element *E=slot_info.front();E;E=E->next()) {
+
+ if (E->key() < 0 || E->key()>=cache_y.size())
+ continue;
+ if (!slot_info.has(E->key()))
+ continue;
+ const Slot &s=slot_info[E->key()];
+ //left
+ if (s.enable_left)
+ port->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left);
+ if (s.enable_right)
+ port->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right);
+
+ }
+ }
+
+ if (p_what==NOTIFICATION_SORT_CHILDREN) {
+
+ _resort();
+ }
+
+}
+
+
+void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) {
+
+ ERR_FAIL_COND(p_idx<0);
+
+ if (!p_enable_left && p_type_left==0 && p_color_left==Color(1,1,1,1) && !p_enable_right && p_type_right==0 && p_color_right==Color(1,1,1,1)) {
+ slot_info.erase(p_idx);
+ return;
+ }
+
+ Slot s;
+ s.enable_left=p_enable_left;
+ s.type_left=p_type_left;
+ s.color_left=p_color_left;
+ s.enable_right=p_enable_right;
+ s.type_right=p_type_right;
+ s.color_right=p_color_right;
+ slot_info[p_idx]=s;
+ update();
+ connpos_dirty=true;
+
+}
+
+void GraphNode::clear_slot(int p_idx){
+
+ slot_info.erase(p_idx);
+ update();
+ connpos_dirty=true;
+
+}
+void GraphNode::clear_all_slots(){
+
+ slot_info.clear();
+ update();
+ connpos_dirty=true;
+
+}
+bool GraphNode::is_slot_enabled_left(int p_idx) const{
+
+ if (!slot_info.has(p_idx))
+ return false;
+ return slot_info[p_idx].enable_left;
+
+}
+
+int GraphNode::get_slot_type_left(int p_idx) const{
+
+ if (!slot_info.has(p_idx))
+ return 0;
+ return slot_info[p_idx].type_left;
+
+}
+
+Color GraphNode::get_slot_color_left(int p_idx) const{
+
+ if (!slot_info.has(p_idx))
+ return Color(1,1,1,1);
+ return slot_info[p_idx].color_left;
+
+}
+
+bool GraphNode::is_slot_enabled_right(int p_idx) const{
+
+ if (!slot_info.has(p_idx))
+ return false;
+ return slot_info[p_idx].enable_right;
+
+}
+
+
+
+int GraphNode::get_slot_type_right(int p_idx) const{
+
+ if (!slot_info.has(p_idx))
+ return 0;
+ return slot_info[p_idx].type_right;
+
+}
+
+Color GraphNode::get_slot_color_right(int p_idx) const{
+
+ if (!slot_info.has(p_idx))
+ return Color(1,1,1,1);
+ return slot_info[p_idx].color_right;
+
+}
+
+Size2 GraphNode::get_minimum_size() const {
+
+ Ref<Font> title_font = get_font("title_font");
+
+ int sep=get_constant("separation");
+ Ref<StyleBox> sb=get_stylebox("frame");
+ bool first=true;
+
+ Size2 minsize;
+ minsize.x=title_font->get_string_size(title).x;
+ if (show_close) {
+ Ref<Texture> close =get_icon("close");
+ minsize.x+=sep+close->get_width();
+ }
+
+
+ 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;
+
+ Size2i size=c->get_combined_minimum_size();
+
+ minsize.y+=size.y;
+ minsize.x=MAX(minsize.x,size.x);
+
+ if (first)
+ first=false;
+ else
+ minsize.y+=sep;
+ }
+
+ return minsize+sb->get_minimum_size();
+}
+
+void GraphNode::set_title(const String& p_title) {
+
+ title=p_title;
+ minimum_size_changed();
+ update();
+
+}
+
+String GraphNode::get_title() const{
+
+ return title;
+}
+
+void GraphNode::set_offset(const Vector2& p_offset) {
+
+ offset=p_offset;
+ emit_signal("offset_changed");
+ update();
+}
+
+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){
+
+ show_close=p_enable;
+ update();
+}
+bool GraphNode::is_close_button_visible() const{
+
+ return show_close;
+}
+
+void GraphNode::_connpos_update() {
+
+
+ int edgeofs=get_constant("port_offset");
+ int sep=get_constant("separation");
+
+ Ref<StyleBox> sb=get_stylebox("frame");
+ conn_input_cache.clear();
+ conn_output_cache.clear();
+ int vofs=0;
+
+ int idx=0;
+
+ 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;
+
+ Size2i size=c->get_combined_minimum_size();
+
+ int y = sb->get_margin(MARGIN_TOP)+vofs;
+ int h = size.y;
+
+
+ if (slot_info.has(idx)) {
+
+ if (slot_info[idx].enable_left) {
+ ConnCache cc;
+ cc.pos=Point2i(edgeofs,y+h/2);
+ cc.type=slot_info[idx].type_left;
+ cc.color=slot_info[idx].color_left;
+ conn_input_cache.push_back(cc);
+ }
+ if (slot_info[idx].enable_right) {
+ ConnCache cc;
+ cc.pos=Point2i(get_size().width-edgeofs,y+h/2);
+ cc.type=slot_info[idx].type_right;
+ cc.color=slot_info[idx].color_right;
+ conn_output_cache.push_back(cc);
+ }
+ }
+
+ if (vofs>0)
+ vofs+=sep;
+ vofs+=size.y;
+ idx++;
+
+ }
+
+
+ connpos_dirty=false;
+}
+
+int GraphNode::get_connection_input_count() {
+
+ if (connpos_dirty)
+ _connpos_update();
+
+ return conn_input_cache.size();
+
+}
+int GraphNode::get_connection_output_count() {
+
+ if (connpos_dirty)
+ _connpos_update();
+
+ return conn_output_cache.size();
+
+}
+
+
+Vector2 GraphNode::get_connection_input_pos(int p_idx) {
+
+ if (connpos_dirty)
+ _connpos_update();
+
+ ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Vector2());
+ return conn_input_cache[p_idx].pos;
+}
+
+int GraphNode::get_connection_input_type(int p_idx) {
+
+ if (connpos_dirty)
+ _connpos_update();
+
+ ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),0);
+ return conn_input_cache[p_idx].type;
+}
+
+Color GraphNode::get_connection_input_color(int p_idx) {
+
+ if (connpos_dirty)
+ _connpos_update();
+
+ ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Color());
+ return conn_input_cache[p_idx].color;
+}
+
+Vector2 GraphNode::get_connection_output_pos(int p_idx){
+
+ if (connpos_dirty)
+ _connpos_update();
+
+ ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Vector2());
+ return conn_output_cache[p_idx].pos;
+
+}
+
+int GraphNode::get_connection_output_type(int p_idx) {
+
+ if (connpos_dirty)
+ _connpos_update();
+
+ ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),0);
+ return conn_output_cache[p_idx].type;
+}
+
+Color GraphNode::get_connection_output_color(int p_idx) {
+
+ if (connpos_dirty)
+ _connpos_update();
+
+ ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Color());
+ return conn_output_cache[p_idx].color;
+}
+
+void GraphNode::_input_event(const InputEvent& p_ev) {
+
+ 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;
+ }
+ emit_signal("raise_request");
+ }
+ }
+
+}
+
+
+void GraphNode::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_title","title"),&GraphNode::set_title);
+ ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title);
+ ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event);
+
+ ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right"),&GraphNode::set_slot);
+ ObjectTypeDB::bind_method(_MD("clear_slot","idx"),&GraphNode::clear_slot);
+ ObjectTypeDB::bind_method(_MD("clear_all_slots","idx"),&GraphNode::clear_all_slots);
+ ObjectTypeDB::bind_method(_MD("is_slot_enabled_left","idx"),&GraphNode::is_slot_enabled_left);
+ ObjectTypeDB::bind_method(_MD("get_slot_type_left","idx"),&GraphNode::get_slot_type_left);
+ ObjectTypeDB::bind_method(_MD("get_slot_color_left","idx"),&GraphNode::get_slot_color_left);
+ ObjectTypeDB::bind_method(_MD("is_slot_enabled_right","idx"),&GraphNode::is_slot_enabled_right);
+ ObjectTypeDB::bind_method(_MD("get_slot_type_right","idx"),&GraphNode::get_slot_type_right);
+ ObjectTypeDB::bind_method(_MD("get_slot_color_right","idx"),&GraphNode::get_slot_color_right);
+
+ ObjectTypeDB::bind_method(_MD("set_offset","offset"),&GraphNode::set_offset);
+ ObjectTypeDB::bind_method(_MD("get_offset"),&GraphNode::get_offset);
+
+ ObjectTypeDB::bind_method(_MD("get_connection_output_count"),&GraphNode::get_connection_output_count);
+ ObjectTypeDB::bind_method(_MD("get_connection_input_count"),&GraphNode::get_connection_input_count);
+
+ ObjectTypeDB::bind_method(_MD("get_connection_output_pos","idx"),&GraphNode::get_connection_output_pos);
+ ObjectTypeDB::bind_method(_MD("get_connection_output_type","idx"),&GraphNode::get_connection_output_type);
+ ObjectTypeDB::bind_method(_MD("get_connection_output_color","idx"),&GraphNode::get_connection_output_color);
+ ObjectTypeDB::bind_method(_MD("get_connection_input_pos","idx"),&GraphNode::get_connection_input_pos);
+ ObjectTypeDB::bind_method(_MD("get_connection_input_type","idx"),&GraphNode::get_connection_input_type);
+ ObjectTypeDB::bind_method(_MD("get_connection_input_color","idx"),&GraphNode::get_connection_input_color);
+
+
+ ObjectTypeDB::bind_method(_MD("set_show_close_button","show"),&GraphNode::set_show_close_button);
+ ObjectTypeDB::bind_method(_MD("is_close_button_visible"),&GraphNode::is_close_button_visible);
+
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"show_close"),_SCS("set_show_close_button"),_SCS("is_close_button_visible"));
+
+ ADD_SIGNAL(MethodInfo("offset_changed"));
+ ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to")));
+ ADD_SIGNAL(MethodInfo("raise_request"));
+ ADD_SIGNAL(MethodInfo("close_request"));
+}
+
+GraphNode::GraphNode() {
+ show_close=false;
+ connpos_dirty=true;
+}
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
new file mode 100644
index 0000000000..201529380d
--- /dev/null
+++ b/scene/gui/graph_node.h
@@ -0,0 +1,106 @@
+#ifndef GRAPH_NODE_H
+#define GRAPH_NODE_H
+
+#include "scene/gui/container.h"
+
+class GraphNode : public Container {
+
+ OBJ_TYPE(GraphNode,Container);
+
+
+
+ struct Slot {
+ bool enable_left;
+ int type_left;
+ Color color_left;
+ bool enable_right;
+ int type_right;
+ 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); }
+ };
+
+ String title;
+ bool show_close;
+ Vector2 offset;
+
+ Rect2 close_rect;
+
+ Vector<int> cache_y;
+
+ struct ConnCache {
+ Vector2 pos;
+ int type;
+ Color color;
+ };
+
+ Vector<ConnCache> conn_input_cache;
+ Vector<ConnCache> conn_output_cache;
+
+ Map<int,Slot> slot_info;
+
+ bool connpos_dirty;
+
+ void _connpos_update();
+ void _resort();
+
+ Vector2 drag_from;
+ bool selected;
+protected:
+
+ void _input_event(const InputEvent& p_ev);
+ void _notification(int p_what);
+ 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 set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right);
+ void clear_slot(int p_idx);
+ void clear_all_slots();
+ bool is_slot_enabled_left(int p_idx) const;
+ int get_slot_type_left(int p_idx) const;
+ Color get_slot_color_left(int p_idx) const;
+ bool is_slot_enabled_right(int p_idx) const;
+ int get_slot_type_right(int p_idx) const;
+ Color get_slot_color_right(int p_idx) const;
+
+ void set_title(const String& p_title);
+ String get_title() const;
+
+ 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;
+
+ int get_connection_input_count() ;
+ int get_connection_output_count() ;
+ Vector2 get_connection_input_pos(int p_idx);
+ int get_connection_input_type(int p_idx);
+ Color get_connection_input_color(int p_idx);
+ Vector2 get_connection_output_pos(int p_idx);
+ int get_connection_output_type(int p_idx);
+ Color get_connection_output_color(int p_idx);
+
+
+ virtual Size2 get_minimum_size() const;
+
+ GraphNode();
+};
+
+
+#endif // GRAPH_NODE_H
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index f54345cdb8..105f66f368 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,7 +40,8 @@ void GridContainer::_notification(int p_what) {
Set<int> col_expanded;
Set<int> row_expanded;
- int sep=get_constant("separation");
+ int hsep=get_constant("hseparation");
+ int vsep=get_constant("vseparation");
int idx=0;
int max_row=0;
@@ -69,6 +70,7 @@ void GridContainer::_notification(int p_what) {
else
row_minh[row]=ms.height;
+ // print_line("store row "+itos(row)+" mw "+itos(ms.height));
if (c->get_h_size_flags()&SIZE_EXPAND)
col_expanded.insert(col);
@@ -96,8 +98,8 @@ void GridContainer::_notification(int p_what) {
expand_rows++;
}
- ms.height+=sep*max_row;
- ms.width+=sep*max_col;
+ ms.height+=vsep*max_row;
+ ms.width+=hsep*max_col;
int row_expand = expand_rows?(size.y-ms.y)/expand_rows:0;
int col_expand = expand_cols?(size.x-ms.x)/expand_cols:0;
@@ -118,29 +120,28 @@ void GridContainer::_notification(int p_what) {
if (col==0) {
col_ofs=0;
if (row>0 && row_minh.has(row-1))
- row_ofs+=row_minh[row-1]+sep+(row_expanded.has(row-1)?row_expand:0);
+ row_ofs+=row_minh[row-1]+vsep+(row_expanded.has(row-1)?row_expand:0);
}
- if (c->is_visible()) {
- Size2 s;
- if (col_minw.has(col))
- s.width=col_minw[col];
- if (row_minh.has(row))
- s.height=row_minh[col];
-
- if (row_expanded.has(row))
- s.height+=row_expand;
- if (col_expanded.has(col))
- s.width+=col_expand;
+ Size2 s;
+ if (col_minw.has(col))
+ s.width=col_minw[col];
+ if (row_minh.has(row))
+ s.height=row_minh[row];
- Point2 p(col_ofs,row_ofs);
+ if (row_expanded.has(row))
+ s.height+=row_expand;
+ if (col_expanded.has(col))
+ s.width+=col_expand;
- fit_child_in_rect(c,Rect2(p,s));
+ Point2 p(col_ofs,row_ofs);
- }
+// print_line("col: "+itos(col)+" row: "+itos(row)+" col_ofs: "+itos(col_ofs)+" row_ofs: "+itos(row_ofs));
+ fit_child_in_rect(c,Rect2(p,s));
+ //print_line("col: "+itos(col)+" row: "+itos(row)+" rect: "+Rect2(p,s));
if (col_minw.has(col)) {
- col_ofs+=col_minw[col]+sep+(col_expanded.has(col)?col_expand:0);
+ col_ofs+=col_minw[col]+hsep+(col_expanded.has(col)?col_expand:0);
}
idx++;
@@ -178,7 +179,8 @@ Size2 GridContainer::get_minimum_size() const {
Map<int,int> col_minw;
Map<int,int> row_minh;
- int sep=get_constant("separation");
+ int hsep=get_constant("hseparation");
+ int vsep=get_constant("vseparation");
int idx=0;
int max_row=0;
@@ -216,8 +218,8 @@ Size2 GridContainer::get_minimum_size() const {
ms.height+=E->get();
}
- ms.height+=sep*max_row;
- ms.width+=sep*max_col;
+ ms.height+=vsep*max_row;
+ ms.width+=hsep*max_col;
return ms;
@@ -226,5 +228,6 @@ Size2 GridContainer::get_minimum_size() const {
GridContainer::GridContainer() {
+ set_stop_mouse(false);
columns=1;
}
diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h
index f74ad6c66a..8d8bc27293 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
new file mode 100644
index 0000000000..f035cb7722
--- /dev/null
+++ b/scene/gui/item_list.cpp
@@ -0,0 +1,1148 @@
+#include "item_list.h"
+#include "os/os.h"
+#include "globals.h"
+
+
+void ItemList::add_item(const String& p_item,const Ref<Texture>& p_texture,bool p_selectable) {
+
+ Item item;
+ item.icon=p_texture;
+ item.text=p_item;
+ item.selectable=p_selectable;
+ item.selected=false;
+ item.disabled=false;
+ item.custom_bg=Color(0,0,0,0);
+ items.push_back(item);
+
+ update();
+ shape_changed=true;
+
+}
+
+void ItemList::add_icon_item(const Ref<Texture>& p_item,bool p_selectable){
+
+ Item item;
+ item.icon=p_item;
+ //item.text=p_item;
+ item.selectable=p_selectable;
+ item.selected=false;
+ item.disabled=false;
+ item.custom_bg=Color(0,0,0,0);
+ items.push_back(item);
+
+ update();
+ shape_changed=true;
+
+}
+
+void ItemList::set_item_text(int p_idx,const String& p_text){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].text=p_text;
+ update();
+ shape_changed=true;
+
+}
+
+String ItemList::get_item_text(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),String());
+ return items[p_idx].text;
+
+}
+
+void ItemList::set_item_tooltip(int p_idx,const String& p_tooltip){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].tooltip=p_tooltip;
+ update();
+ shape_changed=true;
+
+}
+
+String ItemList::get_item_tooltip(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),String());
+ return items[p_idx].tooltip;
+
+}
+
+void ItemList::set_item_icon(int p_idx,const Ref<Texture>& p_icon){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].icon=p_icon;
+ update();
+ shape_changed=true;
+
+
+}
+Ref<Texture> ItemList::get_item_icon(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),Ref<Texture>());
+
+ return items[p_idx].icon;
+
+}
+
+void ItemList::set_item_custom_bg_color(int p_idx,const Color& p_custom_bg_color) {
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].custom_bg=p_custom_bg_color;
+
+}
+
+Color ItemList::get_item_custom_bg_color(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),Color());
+
+ return items[p_idx].custom_bg;
+
+}
+
+
+
+void ItemList::set_item_tag_icon(int p_idx,const Ref<Texture>& p_tag_icon){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].tag_icon=p_tag_icon;
+ update();
+ shape_changed=true;
+
+
+}
+Ref<Texture> ItemList::get_item_tag_icon(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),Ref<Texture>());
+
+ return items[p_idx].tag_icon;
+
+}
+
+void ItemList::set_item_selectable(int p_idx,bool p_selectable){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].selectable=p_selectable;
+
+
+}
+
+
+bool ItemList::is_item_selectable(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),false);
+ return items[p_idx].selectable;
+}
+
+void ItemList::set_item_disabled(int p_idx,bool p_disabled){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].disabled=p_disabled;
+
+
+}
+
+
+bool ItemList::is_item_disabled(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),false);
+ return items[p_idx].disabled;
+}
+
+
+void ItemList::set_item_metadata(int p_idx,const Variant& p_metadata){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].metadata=p_metadata;
+ update();
+ shape_changed=true;
+
+}
+
+Variant ItemList::get_item_metadata(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),Variant());
+ return items[p_idx].metadata;
+
+}
+void ItemList::select(int p_idx,bool p_single){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ if (p_single || select_mode==SELECT_SINGLE) {
+
+ if (!items[p_idx].selectable) {
+ return;
+ }
+
+ for(int i=0;i<items.size();i++) {
+ items[i].selected=p_idx==i;
+ }
+
+ current=p_idx;
+ ensure_selected_visible=false;
+ } else {
+
+ if (items[p_idx].selectable) {
+ items[p_idx].selected=true;
+ }
+ }
+ update();
+
+
+}
+void ItemList::unselect(int p_idx){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ if (select_mode!=SELECT_MULTI) {
+ items[p_idx].selected=false;
+ current=-1;
+ } else {
+ items[p_idx].selected=false;
+ }
+ update();
+
+}
+bool ItemList::is_selected(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),false);
+
+ return items[p_idx].selected;
+
+}
+
+void ItemList::set_current(int p_current) {
+ ERR_FAIL_INDEX(p_current,items.size());
+
+ if (select_mode==SELECT_SINGLE)
+ select(p_current,true);
+ else {
+ current=p_current;
+ update();
+ }
+}
+
+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{
+
+ return items.size();
+}
+void ItemList::remove_item(int p_idx){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items.remove(p_idx);
+ update();
+ shape_changed=true;
+
+
+}
+
+void ItemList::clear(){
+
+ items.clear();
+ current=-1;
+ ensure_selected_visible=false;
+ update();
+
+}
+
+void ItemList::set_fixed_column_width(int p_size){
+
+ ERR_FAIL_COND(p_size<0);
+ fixed_column_width=p_size;
+ update();
+ shape_changed=true;
+
+}
+int ItemList::get_fixed_column_width() const{
+
+ return fixed_column_width;
+}
+
+void ItemList::set_max_text_lines(int p_lines){
+
+ ERR_FAIL_COND(p_lines<1);
+ max_text_lines=p_lines;
+ update();
+ shape_changed=true;
+
+}
+int ItemList::get_max_text_lines() const{
+
+ return max_text_lines;
+}
+
+void ItemList::set_max_columns(int p_amount){
+
+ ERR_FAIL_COND(p_amount<0);
+ max_columns=p_amount;
+ update();
+}
+int ItemList::get_max_columns() const{
+
+ return max_columns;
+}
+
+void ItemList::set_select_mode(SelectMode p_mode) {
+
+ select_mode=p_mode;
+ update();
+}
+
+ItemList::SelectMode ItemList::get_select_mode() const {
+
+ return select_mode;
+}
+
+void ItemList::set_icon_mode(IconMode p_mode){
+
+ icon_mode=p_mode;
+ update();
+ shape_changed=true;
+
+}
+ItemList::IconMode ItemList::get_icon_mode() const{
+
+ return icon_mode;
+}
+
+void ItemList::set_min_icon_size(const Size2& p_size) {
+
+ min_icon_size=p_size;
+ update();
+}
+
+Size2 ItemList::get_min_icon_size() const {
+
+ return min_icon_size;
+}
+
+
+
+void ItemList::_input_event(const InputEvent& p_event) {
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_LEFT && p_event.mouse_button.pressed) {
+
+ const InputEventMouseButton &mb = p_event.mouse_button;
+
+ search_string=""; //any mousepress cancels
+ Vector2 pos(mb.x,mb.y);
+ Ref<StyleBox> bg = get_stylebox("bg");
+ pos-=bg->get_offset();
+ pos.y+=scroll_bar->get_val();
+
+ int closest = -1;
+ int closest_dist=0x7FFFFFFF;
+
+ for(int i=0;i<items.size();i++) {
+
+ Rect2 rc = items[i].rect_cache;
+ if (i%current_columns==current_columns-1) {
+ rc.size.width=get_size().width; //not right but works
+ }
+
+ if (rc.has_point(pos)) {
+ closest=i;
+ break;
+ }
+
+ float dist = rc.distance_to(pos);
+ if (dist<closest_dist) {
+ closest=i;
+ closest_dist=dist;
+ }
+ }
+
+ if (closest!=-1) {
+
+ int i = closest;
+
+ if (select_mode==SELECT_MULTI && items[i].selected && mb.mod.command) {
+ unselect(i);
+ emit_signal("multi_selected",i,false);
+ } else if (select_mode==SELECT_MULTI && mb.mod.shift && current>=0 && current<items.size() && current!=i) {
+
+ int from = current;
+ int to = i;
+ if (i<current) {
+ SWAP(from,to);
+ }
+ for(int j=from;j<=to;j++) {
+ bool selected = !items[j].selected;
+ select(j,false);
+ if (selected)
+ emit_signal("multi_selected",i,true);
+ }
+ } else {
+ bool selected = !items[i].selected;
+ select(i,select_mode==SELECT_SINGLE || !mb.mod.command);
+ if (selected) {
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",i);
+ } else
+ emit_signal("multi_selected",i,true);
+ }
+
+ if (/*select_mode==SELECT_SINGLE &&*/ mb.doubleclick) {
+
+ emit_signal("item_activated",i);
+
+ }
+
+
+ }
+
+
+ return;
+ }
+ }
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_WHEEL_UP && p_event.mouse_button.pressed) {
+
+ scroll_bar->set_val( scroll_bar->get_val()-scroll_bar->get_page()/8 );
+
+ }
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_WHEEL_DOWN && p_event.mouse_button.pressed) {
+
+ scroll_bar->set_val( scroll_bar->get_val()+scroll_bar->get_page()/8 );
+
+ }
+
+ if (p_event.is_pressed() && items.size()>0) {
+ if (p_event.is_action("ui_up")) {
+
+ if (search_string!="") {
+
+ uint64_t now = OS::get_singleton()->get_ticks_msec();
+ uint64_t diff = now-search_time_msec;
+
+ if (diff<int(Globals::get_singleton()->get("gui/incr_search_max_interval_msec"))*2) {
+
+ for(int i=current-1;i>=0;i--) {
+
+ if (items[i].text.begins_with(search_string)) {
+
+ set_current(i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+
+
+ break;
+ }
+ }
+ accept_event();
+ return;
+ }
+ }
+
+ if (current>=current_columns) {
+ set_current(current-current_columns);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+ }
+ } else if (p_event.is_action("ui_down")) {
+
+ if (search_string!="") {
+
+ uint64_t now = OS::get_singleton()->get_ticks_msec();
+ uint64_t diff = now-search_time_msec;
+
+ if (diff<int(Globals::get_singleton()->get("gui/incr_search_max_interval_msec"))*2) {
+
+ for(int i=current+1;i<items.size();i++) {
+
+ if (items[i].text.begins_with(search_string)) {
+
+ set_current(i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ break;
+ }
+ }
+ accept_event();
+ return;
+ }
+ }
+
+ if (current<items.size()-current_columns) {
+ set_current(current+current_columns);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+
+ }
+ } else if (p_event.is_action("ui_page_up")) {
+
+ search_string=""; //any mousepress cancels
+
+ for(int i=4;i>0;i--) {
+ if (current-current_columns*i >=0 ) {
+ set_current( current- current_columns*i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+ break;
+ }
+ }
+ } else if (p_event.is_action("ui_page_down")) {
+
+ search_string=""; //any mousepress cancels
+
+ for(int i=4;i>0;i--) {
+ if (current+current_columns*i < items.size() ) {
+ set_current( current+ current_columns*i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+
+ break;
+ }
+ }
+ } else if (p_event.is_action("ui_left")) {
+
+ search_string=""; //any mousepress cancels
+
+ if (current%current_columns!=0) {
+ set_current(current-1);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+
+ }
+ } else if (p_event.is_action("ui_right")) {
+
+ search_string=""; //any mousepress cancels
+
+ if (current%current_columns!=(current_columns-1)) {
+ set_current(current+1);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+
+ }
+ } else if (p_event.is_action("ui_cancel")) {
+ search_string="";
+ } else if (p_event.is_action("ui_select")) {
+
+
+ if (select_mode==SELECT_MULTI && current>=0 && current<items.size()) {
+ if (items[current].selectable && !items[current].selected) {
+ select(current,false);
+ emit_signal("multi_selected",current,true);
+ } else if (items[current].selected) {
+ unselect(current);
+ emit_signal("multi_selected",current,false);
+ }
+ }
+ } else if (p_event.is_action("ui_accept")) {
+ search_string=""; //any mousepress cance
+
+ if (current>=0 && current<items.size()) {
+ emit_signal("item_activated",current);
+ }
+ } else if (p_event.type==InputEvent::KEY) {
+
+ if (p_event.key.unicode) {
+
+ uint64_t now = OS::get_singleton()->get_ticks_msec();
+ uint64_t diff = now-search_time_msec;
+ uint64_t max_interval = uint64_t(GLOBAL_DEF("gui/incr_search_max_interval_msec",2000));
+ search_time_msec = now;
+
+ if (diff>max_interval) {
+ search_string="";
+ }
+
+ search_string+=String::chr(p_event.key.unicode);
+ for(int i=0;i<items.size();i++) {
+ if (items[i].text.begins_with(search_string)) {
+ set_current(i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ break;
+ }
+ }
+
+ }
+
+ }
+ }
+
+
+
+
+}
+
+void ItemList::ensure_current_is_visible() {
+
+ ensure_selected_visible=true;
+ update();
+}
+
+void ItemList::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_RESIZED) {
+ shape_changed=true;
+ update();
+ }
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
+ Ref<StyleBox> bg = get_stylebox("bg");
+
+ int mw = scroll_bar->get_minimum_size().x;
+ scroll_bar->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,mw+bg->get_margin(MARGIN_RIGHT));
+ scroll_bar->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,bg->get_margin(MARGIN_RIGHT));
+ scroll_bar->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,bg->get_margin(MARGIN_TOP));
+ scroll_bar->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,bg->get_margin(MARGIN_BOTTOM));
+
+
+ Size2 size = get_size();
+
+ float page = size.height-bg->get_minimum_size().height;
+ int width = size.width - mw - bg->get_minimum_size().width;
+ scroll_bar->set_page(page);
+
+ draw_style_box(bg,Rect2(Point2(),size));
+
+ int hseparation = get_constant("hseparation");
+ int vseparation = get_constant("vseparation");
+ int icon_margin = get_constant("icon_margin");
+ int line_separation = get_constant("line_separation");
+
+ Ref<StyleBox> sbsel = has_focus()?get_stylebox("selected_focus"):get_stylebox("selected");
+ Ref<StyleBox> cursor = has_focus()?get_stylebox("cursor"):get_stylebox("cursor_unfocused");
+
+ Ref<Font> font = get_font("font");
+ Color guide_color = get_color("guide_color");
+ Color font_color = get_color("font_color");
+ Color font_color_selected = get_color("font_color_selected");
+ int font_height = font->get_height();
+ Vector<int> line_size_cache;
+ Vector<int> line_limit_cache;
+
+ if (max_text_lines) {
+ line_size_cache.resize(max_text_lines);
+ line_limit_cache.resize(max_text_lines);
+ }
+
+ if (has_focus()) {
+ VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(),true);
+ draw_style_box(get_stylebox("bg_focus"),Rect2(Point2(),size));
+ VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(),false);
+ }
+
+ if (shape_changed) {
+
+ //1- compute item minimum sizes
+ for(int i=0;i<items.size();i++) {
+
+ Size2 minsize;
+ if (items[i].icon.is_valid()) {
+ minsize=items[i].icon->get_size();
+ if (min_icon_size.x!=0)
+ minsize.x = MAX(minsize.x,min_icon_size.x);
+ if (min_icon_size.y!=0)
+ minsize.y = MAX(minsize.y,min_icon_size.y);
+
+ if (items[i].text!="") {
+ if (icon_mode==ICON_MODE_TOP) {
+ minsize.y+=icon_margin;
+ } else {
+ minsize.x+=icon_margin;
+ }
+ }
+ }
+
+ if (items[i].text!="") {
+
+ Size2 s = font->get_string_size(items[i].text);
+ //s.width=MIN(s.width,fixed_column_width);
+
+
+
+ if (icon_mode==ICON_MODE_TOP) {
+ minsize.x=MAX(minsize.x,s.width);
+ if (max_text_lines>0) {
+ minsize.y+=(font_height+line_separation)*max_text_lines;
+ } else {
+ minsize.y+=s.height;
+ }
+
+ } else {
+ minsize.y=MAX(minsize.y,s.height);
+ minsize.x+=s.width;
+ }
+ }
+
+
+
+ items[i].rect_cache.size=minsize;
+ if (fixed_column_width>0)
+ items[i].rect_cache.size.x=fixed_column_width;
+
+ }
+
+ int fit_size = size.x - bg->get_minimum_size().width - mw;
+
+ //2-attempt best fit
+ current_columns = 0x7FFFFFFF;
+ if (max_columns>0)
+ current_columns=max_columns;
+
+
+ while(true) {
+ //repeat util all fits
+ //print_line("try with "+itos(current_columns));
+ bool all_fit=true;
+ Vector2 ofs;
+ int col=0;
+ int max_h=0;
+ separators.clear();;
+ for(int i=0;i<items.size();i++) {
+
+ if (current_columns>1 && items[i].rect_cache.size.width+ofs.x > fit_size) {
+ //went past
+ current_columns=MAX(col,1);
+ all_fit=false;
+ break;
+ }
+
+ items[i].rect_cache.pos=ofs;
+ max_h=MAX(max_h,items[i].rect_cache.size.y);
+ ofs.x+=items[i].rect_cache.size.x;
+ //print_line("item "+itos(i)+" ofs "+rtos(items[i].rect_cache.size.x));
+ if (col>0)
+ ofs.x+=hseparation;
+ col++;
+ if (col==current_columns) {
+
+ if (i<items.size()-1)
+ separators.push_back(ofs.y+max_h+vseparation/2);
+ ofs.x=0;
+ ofs.y+=max_h+vseparation;
+ col=0;
+ max_h=0;
+ }
+ }
+
+ if (all_fit) {
+ float max = MAX(page,ofs.y+max_h);
+ scroll_bar->set_max(max);
+ //print_line("max: "+rtos(max)+" page "+rtos(page));
+ if (max<=page) {
+ scroll_bar->set_val(0);
+ scroll_bar->hide();
+ } else {
+ scroll_bar->show();
+ }
+ break;
+ }
+ }
+
+
+ shape_changed=false;
+ }
+
+
+
+ Vector2 base_ofs = bg->get_offset();
+ base_ofs.y-=int(scroll_bar->get_val());
+
+ Rect2 clip(Point2(),size-bg->get_minimum_size()+Vector2(0,scroll_bar->get_val()));
+
+ for(int i=0;i<items.size();i++) {
+
+
+ Rect2 rcache = items[i].rect_cache;
+
+ if (!clip.intersects(rcache))
+ continue;
+
+
+ if (current_columns==1) {
+ rcache.size.width = width-rcache.pos.x;
+ }
+ if (items[i].custom_bg.a>0.001) {
+ Rect2 r=rcache;
+ r.pos+=base_ofs;
+ draw_rect(r,items[i].custom_bg);
+ }
+ if (items[i].selected) {
+ Rect2 r=rcache;
+ r.pos+=base_ofs;
+
+ r.pos.x-=sbsel->get_margin(MARGIN_LEFT);
+ r.size.x+=sbsel->get_margin(MARGIN_LEFT)+sbsel->get_margin(MARGIN_RIGHT);
+ r.pos.y-=sbsel->get_margin(MARGIN_TOP);
+ r.size.y+=sbsel->get_margin(MARGIN_TOP)+sbsel->get_margin(MARGIN_BOTTOM);
+
+ draw_style_box(sbsel,r);
+
+ }
+
+
+ Vector2 text_ofs;
+ if (items[i].icon.is_valid()) {
+
+ Vector2 icon_ofs;
+ if (min_icon_size!=Vector2()) {
+ icon_ofs = (min_icon_size - items[i].icon->get_size())/2;
+ }
+
+ if (icon_mode==ICON_MODE_TOP) {
+ draw_texture(items[i].icon,icon_ofs+items[i].rect_cache.pos+Vector2(items[i].rect_cache.size.width/2-items[i].icon->get_width()/2,0).floor()+base_ofs);
+ text_ofs.y = MAX(items[i].icon->get_height(),min_icon_size.y)+icon_margin;
+ } else {
+ draw_texture(items[i].icon,icon_ofs+items[i].rect_cache.pos+Vector2(0,items[i].rect_cache.size.height/2-items[i].icon->get_height()/2).floor()+base_ofs);
+ text_ofs.x = MAX(items[i].icon->get_width(),min_icon_size.x)+icon_margin;
+ }
+ }
+
+ if (items[i].tag_icon.is_valid()) {
+
+ draw_texture(items[i].tag_icon,items[i].rect_cache.pos+base_ofs);
+ }
+
+ if (items[i].text!="") {
+
+ int max_len=-1;
+
+ Vector2 size = font->get_string_size(items[i].text);
+ if (fixed_column_width)
+ max_len=fixed_column_width;
+ else
+ max_len=size.x;
+
+ if (icon_mode==ICON_MODE_TOP && max_text_lines>0) {
+
+ int ss = items[i].text.length();
+ float ofs=0;
+ int line=0;
+ for(int j=0;j<=ss;j++) {
+
+ int cs = j<ss?font->get_char_size(items[i].text[j],items[i].text[j+1]).x:0;
+ if (ofs+cs>max_len || j==ss) {
+ line_limit_cache[line]=j;
+ line_size_cache[line]=ofs;
+ line++;
+ ofs=0;
+ if (line>=max_text_lines)
+ break;
+ } else {
+ ofs+=cs;
+ }
+
+ }
+
+ line=0;
+ ofs=0;
+
+ text_ofs.y+=font->get_ascent();
+ text_ofs=text_ofs.floor();
+ text_ofs+=base_ofs;
+ text_ofs+=items[i].rect_cache.pos;
+
+ for(int j=0;j<ss;j++) {
+
+ if (j==line_limit_cache[line]) {
+ line++;
+ ofs=0;
+ if (line>=max_text_lines)
+ break;
+ }
+ ofs+=font->draw_char(get_canvas_item(),text_ofs+Vector2(ofs+(max_len-line_size_cache[line])/2,line*(font_height+line_separation)).floor(),items[i].text[j],items[i].text[j+1],items[i].selected?font_color_selected:font_color);
+ }
+
+ //special multiline mode
+ } else {
+
+ if (fixed_column_width>0)
+ size.x=MIN(size.x,fixed_column_width);
+
+ if (icon_mode==ICON_MODE_TOP) {
+ text_ofs.x+=(items[i].rect_cache.size.width-size.x)/2;
+ } else {
+ text_ofs.y+=(items[i].rect_cache.size.height-size.y)/2;
+ }
+
+ text_ofs.y+=font->get_ascent();
+ text_ofs=text_ofs.floor();
+ text_ofs+=base_ofs;
+ text_ofs+=items[i].rect_cache.pos;
+
+ draw_string(font,text_ofs,items[i].text,items[i].selected?font_color_selected:font_color,max_len+1);
+ }
+
+
+ }
+
+ if (select_mode==SELECT_MULTI && i==current) {
+
+ Rect2 r=rcache;
+ r.pos+=base_ofs;
+ draw_style_box(cursor,r);
+
+ }
+ }
+
+ for(int i=0;i<separators.size();i++) {
+ 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;
+
+ }
+}
+
+void ItemList::_scroll_changed(double) {
+ update();
+}
+
+
+String ItemList::get_tooltip(const Point2& p_pos) const {
+
+ Vector2 pos=p_pos;
+ Ref<StyleBox> bg = get_stylebox("bg");
+ pos-=bg->get_offset();
+ pos.y+=scroll_bar->get_val();
+
+ int closest = -1;
+ int closest_dist=0x7FFFFFFF;
+
+ for(int i=0;i<items.size();i++) {
+
+ Rect2 rc = items[i].rect_cache;
+ if (i%current_columns==current_columns-1) {
+ rc.size.width=get_size().width; //not right but works
+ }
+
+ if (rc.has_point(pos)) {
+ closest=i;
+ break;
+ }
+
+ float dist = rc.distance_to(pos);
+ if (dist<closest_dist) {
+ closest=i;
+ closest_dist=dist;
+ }
+ }
+
+ if (closest!=-1) {
+ if (items[closest].tooltip!="") {
+ return items[closest].tooltip;
+ }
+ if (items[closest].text!="") {
+ return items[closest].text;
+ }
+ }
+
+ return Control::get_tooltip(p_pos);
+
+
+}
+
+void ItemList::sort_items_by_text() {
+ items.sort();
+ update();
+ if (select_mode==SELECT_SINGLE) {
+ for(int i=0;i<items.size();i++) {
+ if (items[i].selected) {
+ select(i);
+ return;
+ }
+ }
+ }
+}
+
+int ItemList::find_metadata(const Variant& p_metadata) const {
+
+ for(int i=0;i<items.size();i++) {
+ if (items[i].metadata==p_metadata) {
+ return i;
+ }
+ }
+
+ return -1;
+
+}
+
+void ItemList::_bind_methods(){
+
+ ObjectTypeDB::bind_method(_MD("add_item","text","icon:Texture","selectable"),&ItemList::add_item,DEFVAL(Ref<Texture>()),DEFVAL(true));
+ ObjectTypeDB::bind_method(_MD("add_icon_item","icon:Texture","selectable"),&ItemList::add_icon_item,DEFVAL(true));
+
+ ObjectTypeDB::bind_method(_MD("set_item_text","idx","text"),&ItemList::set_item_text);
+ 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: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);
+
+ ObjectTypeDB::bind_method(_MD("set_item_disabled","idx","disabled"),&ItemList::set_item_disabled);
+ ObjectTypeDB::bind_method(_MD("is_item_disabled","idx"),&ItemList::is_item_disabled);
+
+ ObjectTypeDB::bind_method(_MD("set_item_metadata","idx","metadata"),&ItemList::set_item_metadata);
+ ObjectTypeDB::bind_method(_MD("get_item_metadata","idx"),&ItemList::get_item_metadata);
+
+ ObjectTypeDB::bind_method(_MD("set_item_custom_bg_color","idx","custom_bg_color"),&ItemList::set_item_custom_bg_color);
+ ObjectTypeDB::bind_method(_MD("get_item_custom_bg_color","idx"),&ItemList::get_item_custom_bg_color);
+
+ ObjectTypeDB::bind_method(_MD("set_item_tooltip","idx","tooltip"),&ItemList::set_item_tooltip);
+ ObjectTypeDB::bind_method(_MD("get_item_tooltip","idx"),&ItemList::get_item_tooltip);
+
+ ObjectTypeDB::bind_method(_MD("select","idx","single"),&ItemList::select,DEFVAL(true));
+ ObjectTypeDB::bind_method(_MD("unselect","idx"),&ItemList::unselect);
+ ObjectTypeDB::bind_method(_MD("is_selected","idx"),&ItemList::is_selected);
+
+ ObjectTypeDB::bind_method(_MD("get_item_count"),&ItemList::get_item_count);
+ ObjectTypeDB::bind_method(_MD("remove_item","idx"),&ItemList::remove_item);
+
+ ObjectTypeDB::bind_method(_MD("clear"),&ItemList::clear);
+ ObjectTypeDB::bind_method(_MD("sort_items_by_text"),&ItemList::clear);
+
+ ObjectTypeDB::bind_method(_MD("set_fixed_column_width","width"),&ItemList::set_fixed_column_width);
+ ObjectTypeDB::bind_method(_MD("get_fixed_column_width"),&ItemList::get_fixed_column_width);
+
+ ObjectTypeDB::bind_method(_MD("set_max_text_lines","lines"),&ItemList::set_max_text_lines);
+ ObjectTypeDB::bind_method(_MD("get_max_text_lines"),&ItemList::get_max_text_lines);
+
+ ObjectTypeDB::bind_method(_MD("set_max_columns","amount"),&ItemList::set_max_columns);
+ ObjectTypeDB::bind_method(_MD("get_max_columns"),&ItemList::get_max_columns);
+
+ ObjectTypeDB::bind_method(_MD("set_select_mode","mode"),&ItemList::set_select_mode);
+ ObjectTypeDB::bind_method(_MD("get_select_mode"),&ItemList::get_select_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_icon_mode","mode"),&ItemList::set_icon_mode);
+ ObjectTypeDB::bind_method(_MD("get_icon_mode"),&ItemList::get_icon_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_min_icon_size","size"),&ItemList::set_min_icon_size);
+ ObjectTypeDB::bind_method(_MD("get_min_icon_size"),&ItemList::get_min_icon_size);
+
+ ObjectTypeDB::bind_method(_MD("ensure_current_is_visible"),&ItemList::ensure_current_is_visible);
+
+ ObjectTypeDB::bind_method(_MD("_scroll_changed"),&ItemList::_scroll_changed);
+ ObjectTypeDB::bind_method(_MD("_input_event"),&ItemList::_input_event);
+
+ BIND_CONSTANT( ICON_MODE_TOP );
+ BIND_CONSTANT( ICON_MODE_LEFT );
+ BIND_CONSTANT( SELECT_SINGLE );
+ BIND_CONSTANT( SELECT_MULTI );
+
+ ADD_SIGNAL( MethodInfo("item_selected",PropertyInfo(Variant::INT,"index")));
+ ADD_SIGNAL( MethodInfo("multi_selected",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::BOOL,"selected")));
+ ADD_SIGNAL( MethodInfo("item_activated",PropertyInfo(Variant::INT,"index")));
+}
+
+
+
+ItemList::ItemList() {
+
+ current=-1;
+
+ select_mode=SELECT_SINGLE;
+ icon_mode=ICON_MODE_LEFT;
+
+ fixed_column_width=0;
+ max_text_lines=1;
+ max_columns=1;
+
+ scroll_bar = memnew( VScrollBar );
+ add_child(scroll_bar);
+
+ shape_changed=true;
+ scroll_bar->connect("value_changed",this,"_scroll_changed");
+
+ set_focus_mode(FOCUS_ALL);
+ current_columns=1;
+ search_time_msec=0;
+ ensure_selected_visible=false;
+
+}
+
+ItemList::~ItemList() {
+
+}
+
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
new file mode 100644
index 0000000000..bd3cf6484e
--- /dev/null
+++ b/scene/gui/item_list.h
@@ -0,0 +1,144 @@
+#ifndef ITEMLIST_H
+#define ITEMLIST_H
+
+#include "scene/gui/control.h"
+#include "scene/gui/scroll_bar.h"
+
+class ItemList : public Control {
+
+ OBJ_TYPE( ItemList, Control );
+public:
+
+ enum IconMode {
+ ICON_MODE_TOP,
+ ICON_MODE_LEFT
+ };
+
+ enum SelectMode {
+ SELECT_SINGLE,
+ SELECT_MULTI
+ };
+private:
+ struct Item {
+
+ Ref<Texture> icon;
+ Ref<Texture> tag_icon;
+ String text;
+ bool selectable;
+ bool selected;
+ bool disabled;
+ Variant metadata;
+ String tooltip;
+ Color custom_bg;
+
+
+ Rect2 rect_cache;
+
+ bool operator<(const Item& p_another) const { return text<p_another.text; }
+ };
+
+ int current;
+
+ bool shape_changed;
+
+ bool ensure_selected_visible;
+
+ Vector<Item> items;
+ Vector<int> separators;
+
+ SelectMode select_mode;
+ IconMode icon_mode;
+ VScrollBar *scroll_bar;
+
+ uint64_t search_time_msec;
+ String search_string;
+
+ int current_columns;
+ int fixed_column_width;
+ int max_text_lines;
+ int max_columns;
+ Size2 min_icon_size;
+
+ void _scroll_changed(double);
+ void _input_event(const InputEvent& p_event);
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void add_item(const String& p_item,const Ref<Texture>& p_texture=Ref<Texture>(),bool p_selectable=true);
+ void add_icon_item(const Ref<Texture>& p_item,bool p_selectable=true);
+
+ void set_item_text(int p_idx,const String& p_text);
+ String get_item_text(int p_idx) const;
+
+ void set_item_icon(int p_idx,const Ref<Texture>& p_icon);
+ Ref<Texture> get_item_icon(int p_idx) const;
+
+ void set_item_selectable(int p_idx,bool p_selectable);
+ bool is_item_selectable(int p_idx) const;
+
+ void set_item_disabled(int p_idx,bool p_disabled);
+ bool is_item_disabled(int p_idx) const;
+
+ void set_item_metadata(int p_idx,const Variant& p_metadata);
+ Variant get_item_metadata(int p_idx) const;
+
+ void set_item_tag_icon(int p_idx,const Ref<Texture>& p_tag_icon);
+ Ref<Texture> get_item_tag_icon(int p_idx) const;
+
+ void set_item_tooltip(int p_idx,const String& p_tooltip);
+ String get_item_tooltip(int p_idx) const;
+
+ void set_item_custom_bg_color(int p_idx,const Color& p_custom_bg_color);
+ Color get_item_custom_bg_color(int p_idx) const;
+
+ void select(int p_idx,bool p_single=true);
+ void unselect(int p_idx);
+ bool is_selected(int p_idx) const;
+
+ 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);
+
+ void clear();
+
+ void set_fixed_column_width(int p_size);
+ int get_fixed_column_width() const;
+
+ void set_max_text_lines(int p_amount);
+ int get_max_text_lines() const;
+
+ void set_max_columns(int p_amount);
+ int get_max_columns() const;
+
+ void set_select_mode(SelectMode p_mode);
+ SelectMode get_select_mode() const;
+
+ void set_icon_mode(IconMode p_mode);
+ IconMode get_icon_mode() const;
+
+ void set_min_icon_size(const Size2& p_size);
+ Size2 get_min_icon_size() const;
+
+ void ensure_current_is_visible();
+
+ void sort_items_by_text();
+ int find_metadata(const Variant& p_metadata) const;
+
+ virtual String get_tooltip(const Point2& p_pos) const;
+
+ ItemList();
+ ~ItemList();
+};
+
+VARIANT_ENUM_CAST(ItemList::SelectMode);
+VARIANT_ENUM_CAST(ItemList::IconMode);
+
+
+#endif // ITEMLIST_H
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index b7918994d8..002e49cbcf 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,18 +67,18 @@ int Label::get_line_height() const {
void Label::_notification(int p_what) {
-
+
if (p_what==NOTIFICATION_DRAW) {
-
- if (clip && !autowrap)
+
+ 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();
@@ -87,40 +88,46 @@ void Label::_notification(int p_what) {
bool use_outlinde = get_constant("shadow_as_outline");
Point2 shadow_ofs(get_constant("shadow_offset_x"),get_constant("shadow_offset_y"));
-
+ 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;
}
@@ -128,21 +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)
@@ -150,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) {
- spaces++;
+ 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: {
@@ -197,38 +204,38 @@ 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;
}
- if (from!=wc) {
+ if (from->space_count) {
/* spacing */
- x_ofs+=space_w;
+ x_ofs+=space_w*from->space_count;
if (can_fill && align==ALIGN_FILL && spaces) {
-
+
x_ofs+=int((size.width-(taken+space_w*spaces))/spaces);
}
-
-
+
+
}
-
-
-
+
+
+
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];
@@ -248,10 +255,10 @@ void Label::_notification(int p_what) {
}
}
-
+
}
for (int i=0;i<from->word_len;i++) {
-
+
if (visible_chars < 0 || chars_total<visible_chars) {
CharType c = text[i+pos];
CharType n = text[i+pos+1];
@@ -267,79 +274,79 @@ 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;
}
int Label::get_line_count() const {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return 1;
if (word_cache_dirty)
const_cast<Label*>(this)->regenerate_word_cache();
@@ -348,40 +355,46 @@ 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");
-
+
int current_word_size=0;
int word_pos=0;
int line_width=0;
- int last_width=0;
+ int space_count=0;
+ 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)
current=String::char_uppercase(current);
+ // ranges taken from http://www.unicodemap.org/
+ // if your language is not well supported, consider helping improve
+ // the unicode support in Godot.
+ bool separatable = (current>=0x2E08 && current<=0xFAFF) || (current>=0xFE30 && current<=0xFE4F);
+ //current>=33 && (current < 65||current >90) && (current<97||current>122) && (current<48||current>57);
bool insert_newline=false;
-
+ int char_width;
+
if (current<33) {
-
+
if (current_word_size>0) {
-
WordCache *wc = memnew( WordCache );
if (word_cache) {
last->next=wc;
@@ -389,14 +402,17 @@ void Label::regenerate_word_cache() {
word_cache=wc;
}
last=wc;
-
+
wc->pixel_width=current_word_size;
wc->char_pos=word_pos;
wc->word_len=i-word_pos;
+ wc->space_count = space_count;
current_word_size=0;
-
+ space_count=0;
+
}
-
+
+
if (current=='\n') {
insert_newline=true;
} else {
@@ -405,26 +421,49 @@ void Label::regenerate_word_cache() {
if (i<text.length() && text[i] == ' ') {
total_char_cache--; // do not count spaces
+ if (line_width > 0 || last==NULL || last->char_pos!=WordCache::CHAR_WRAPLINE) {
+ space_count++;
+ line_width+=space_width;
+ }else {
+ space_count=0;
+ }
}
} else {
-
+ // latin characters
if (current_word_size==0) {
- if (line_width>0) // add a space before the new word if a word existed before
- line_width+=font->get_char_size(' ').width;
word_pos=i;
}
-
- int char_width=font->get_char_size(current).width;
+
+ 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_width<width) || insert_newline) {
-
+
+ if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || separatable)) || insert_newline) {
+ if (separatable) {
+ if (current_word_size>0) {
+ WordCache *wc = memnew( WordCache );
+ if (word_cache) {
+ last->next=wc;
+ } else {
+ word_cache=wc;
+ }
+ last=wc;
+
+ wc->pixel_width=current_word_size-char_width;
+ wc->char_pos=word_pos;
+ wc->word_len=i-word_pos;
+ wc->space_count = space_count;
+ current_word_size=char_width;
+ space_count=0;
+ word_pos=i;
+ }
+ }
+
WordCache *wc = memnew( WordCache );
if (word_cache) {
last->next=wc;
@@ -432,39 +471,30 @@ void Label::regenerate_word_cache() {
word_cache=wc;
}
last=wc;
-
+
wc->pixel_width=0;
wc->char_pos=insert_newline?WordCache::CHAR_NEWLINE:WordCache::CHAR_WRAPLINE;
line_width=current_word_size;
line_count++;
+ space_count=0;
-
}
-
- last_width=line_width;
-
+
}
-
- 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) {
@@ -474,7 +504,7 @@ void Label::set_align(Align p_align) {
}
Label::Align Label::get_align() const{
-
+
return align;
}
@@ -491,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();
@@ -520,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{
@@ -544,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 {
@@ -554,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);
@@ -563,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 );
@@ -582,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);
@@ -605,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 131ee3a944..4ea9f5d377 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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
@@ -75,25 +75,28 @@ private:
int char_pos; // if -1, then newline
int word_len;
int pixel_width;
+ int space_count;
WordCache *next;
- WordCache() { char_pos=0; word_len=0; pixel_width=0; next=0; }
- };
-
+ 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);
@@ -104,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;
@@ -112,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);
@@ -120,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 e822cfef13..10ba20a833 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;}
}
@@ -212,7 +231,7 @@ void LineEdit::_input_event(InputEvent p_event) {
emit_signal( "text_entered",text );
// notify to hide soft keyboard
- notification(NOTIFICATION_FOCUS_EXIT);
+ notification(NOTIFICATION_FOCUS_EXIT);
return;
} break;
@@ -272,7 +291,7 @@ void LineEdit::_input_event(InputEvent p_event) {
if (editable) {
selection_delete();
- CharType ucodestr[2]={k.unicode,0};
+ CharType ucodestr[2]={(CharType)k.unicode,0};
append_at_cursor(ucodestr);
emit_signal("text_changed",text);
_change_notify("text");
@@ -303,6 +322,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 +356,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 +404,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 +447,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 +540,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 +602,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 );
@@ -572,7 +655,7 @@ void LineEdit::set_cursor_pos(int p_pos) {
// set_window_pos(cursor_pos-get_window_lengt//h());
// }
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
window_pos=cursor_pos;
return;
@@ -593,13 +676,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 +711,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,7 +770,22 @@ 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);
if (cursor_pos>=text.length()) {
@@ -781,9 +890,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);
@@ -804,15 +919,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 6c18594cda..f28136d66e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 54373b7592..f10ca6353a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h
index 7f0a1f53e3..56f2344ea7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 7353744d07..be7a6b468a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
/*
@@ -84,6 +86,7 @@ void MenuButton::pressed() {
popup->set_parent_rect( Rect2(Point2(gp-popup->get_global_pos()),get_size()));
popup->popup();
popup->call_deferred("grab_click_focus");
+ popup->set_invalidate_click_until_motion();
}
@@ -123,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 52c9a9aea5..47e7382d34 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index fa4a313115..ff94a37be0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -192,7 +192,7 @@ void OptionButton::_select(int p_idx,bool p_emit) {
set_text( popup->get_item_text( current ) );
set_icon( popup->get_item_icon( current ) );
- if (is_inside_scene() && p_emit)
+ if (is_inside_tree() && p_emit)
emit_signal("item_selected",current);
}
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 295127175d..7d850479aa 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp
index fd1d5d2de6..d9ba20810b 100644
--- a/scene/gui/panel.cpp
+++ b/scene/gui/panel.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/panel.h b/scene/gui/panel.h
index 8dab05f1a6..7e6be62923 100644
--- a/scene/gui/panel.h
+++ b/scene/gui/panel.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp
index 91581ecccd..5ee061356e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h
index ac67b52be8..c09479241c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 65ad02723c..5ce7e2e0d3 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -51,11 +51,18 @@ void Popup::_fix_size() {
Control *window = get_window();
ERR_FAIL_COND(!window);
-
+
+#if 0
Point2 pos = get_pos();
Size2 size = get_size();
Point2 window_size = window==this ? get_parent_area_size() :window->get_size();
+#else
+
+ Point2 pos = get_global_pos();
+ Size2 size = get_size();
+ Point2 window_size = get_viewport_rect().size;
+#endif
if (pos.x+size.width > window_size.width)
pos.x=window_size.width-size.width;
if (pos.x<0)
@@ -65,8 +72,56 @@ void Popup::_fix_size() {
pos.y=window_size.height-size.height;
if (pos.y<0)
pos.y=0;
+#if 0
if (pos!=get_pos())
set_pos(pos);
+#else
+ if (pos!=get_pos())
+ set_global_pos(pos);
+
+#endif
+
+}
+
+
+void Popup::set_as_minsize() {
+
+ Size2 total_minsize;
+
+ for(int i=0;i<get_child_count();i++) {
+
+ Control *c=get_child(i)->cast_to<Control>();
+ if (!c)
+ continue;
+ if (c->is_hidden())
+ continue;
+
+ Size2 minsize = c->get_combined_minimum_size();
+
+ for(int j=0;j<2;j++) {
+
+ Margin m_beg = Margin(0+j);
+ Margin m_end = Margin(2+j);
+
+ float margin_begin = c->get_margin(m_beg);
+ float margin_end = c->get_margin(m_end);
+ AnchorType anchor_begin = c->get_anchor(m_beg);
+ AnchorType anchor_end = c->get_anchor(m_end);
+
+ if (anchor_begin == ANCHOR_BEGIN)
+ minsize[j]+=margin_begin;
+ if (anchor_end == ANCHOR_END)
+ minsize[j]+=margin_end;
+
+ }
+
+ print_line(String(c->get_type())+": "+minsize);
+
+ total_minsize.width = MAX( total_minsize.width, minsize.width );
+ total_minsize.height = MAX( total_minsize.height, minsize.height );
+ }
+
+ set_size(total_minsize);
}
@@ -81,6 +136,8 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) {
Control *c=get_child(i)->cast_to<Control>();
if (!c)
continue;
+ if (c->is_hidden())
+ continue;
Size2 minsize = c->get_combined_minimum_size();
@@ -101,6 +158,8 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) {
}
+ print_line(String(c->get_type())+": "+minsize);
+
total_minsize.width = MAX( total_minsize.width, minsize.width );
total_minsize.height = MAX( total_minsize.height, minsize.height );
}
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 072b66c2c7..6c72a3c82b 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -62,6 +62,7 @@ public:
void popup_centered_ratio(float p_screen_ratio=0.75);
void popup_centered(const Size2& p_size=Size2());
void popup_centered_minsize(const Size2& p_minsize=Size2());
+ void set_as_minsize();
virtual void popup();
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index c2dc1318c9..20f28ecf10 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,6 +30,7 @@
#include "print_string.h"
#include "os/keyboard.h"
#include "translation.h"
+#include "os/input.h"
String PopupMenu::_get_accel_text(uint32_t p_accel) const {
@@ -169,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>();
@@ -318,8 +326,17 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
int over=_get_mouse_over(Point2(b.x,b.y));
- if (over<0 || items[over].separator || items[over].disabled)
+ if (invalidated_click) {
+ invalidated_click=false;
+ break;
+ }
+ if (over<0) {
+ hide();
break; //non-activable
+ }
+
+ if (items[over].separator || items[over].disabled)
+ break;
if (items[over].submenu!="") {
@@ -336,6 +353,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
case InputEvent::MOUSE_MOTION: {
+ if (invalidated_click) {
+ moved+=Vector2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y);
+ if (moved.length()>4)
+ invalidated_click=false;
+
+ }
+
const InputEventMouseMotion &m=p_event.mouse_motion;
for(List<Rect2>::Element *E=autohide_areas.front();E;E=E->next()) {
@@ -348,8 +372,11 @@ 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;
- if (id<0)
+ if (id<0) {
+ mouse_over=-1;
+ update();
break;
+ }
if (items[over].submenu!="" && submenu_over!=over) {
submenu_over=over;
@@ -726,10 +753,18 @@ int PopupMenu::find_item_by_accelerator(uint32_t p_accel) const {
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);
+
+ //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();
}
@@ -752,6 +787,7 @@ void PopupMenu::add_separator() {
void PopupMenu::clear() {
items.clear();
+ mouse_over=-1;
update();
idcount=0;
@@ -855,7 +891,7 @@ void PopupMenu::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_item","label","id","accel"),&PopupMenu::add_item,DEFVAL(-1),DEFVAL(0));
ObjectTypeDB::bind_method(_MD("add_icon_check_item","texture","label","id","accel"),&PopupMenu::add_icon_check_item,DEFVAL(-1),DEFVAL(0));
ObjectTypeDB::bind_method(_MD("add_check_item","label","id","accel"),&PopupMenu::add_check_item,DEFVAL(-1),DEFVAL(0));
- ObjectTypeDB::bind_method(_MD("add_submenu_item","label","submenu","id"),&PopupMenu::add_check_item,DEFVAL(-1));
+ ObjectTypeDB::bind_method(_MD("add_submenu_item","label","submenu","id"),&PopupMenu::add_submenu_item,DEFVAL(-1));
ObjectTypeDB::bind_method(_MD("set_item_text","idx","text"),&PopupMenu::set_item_text);
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);
@@ -893,12 +929,17 @@ void PopupMenu::_bind_methods() {
}
+
+void PopupMenu::set_invalidate_click_until_motion() {
+ moved=Vector2();
+ invalidated_click=true;
+}
+
PopupMenu::PopupMenu() {
idcount=0;
mouse_over=-1;
-
set_focus_mode(FOCUS_ALL);
set_as_toplevel(true);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index b150be1008..ed78fe6738 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -70,6 +70,8 @@ class PopupMenu : public Popup {
void _activate_submenu(int over);
void _submenu_timeout();
+ bool invalidated_click;
+ Vector2 moved;
Array _get_items() const;
void _set_items(const Array& p_items);
@@ -88,7 +90,7 @@ public:
void add_icon_check_item(const Ref<Texture>& p_icon,const String& p_label,int p_ID=-1,uint32_t p_accel=0);
void add_check_item(const String& p_label,int p_ID=-1,uint32_t p_accel=0);
void add_submenu_item(const String& p_label,const String& p_submenu, int p_ID=-1);
-
+
void set_item_text(int p_idx,const String& p_text);
void set_item_icon(int p_idx,const Ref<Texture>& p_icon);
void set_item_checked(int p_idx,bool p_checked);
@@ -134,6 +136,8 @@ public:
void add_autohide_area(const Rect2& p_area);
void clear_autohide_areas();
+ void set_invalidate_click_until_motion();
+
PopupMenu();
~PopupMenu();
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index 73fa1fbb98..e7e2c88f4a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h
index fd34c67fae..33b0d5c185 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index bc0fa9675e..7103ee651f 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -42,7 +42,7 @@ void Range::Shared::emit_value_changed() {
for (Set<Range*>::Element *E=owners.front();E;E=E->next()) {
Range *r=E->get();
- if (!r->is_inside_scene())
+ if (!r->is_inside_tree())
continue;
r->_value_changed_notify();
}
@@ -59,7 +59,7 @@ void Range::Shared::emit_changed() {
for (Set<Range*>::Element *E=owners.front();E;E=E->next()) {
Range *r=E->get();
- if (!r->is_inside_scene())
+ if (!r->is_inside_tree())
continue;
r->_changed_notify();
}
@@ -243,7 +243,7 @@ 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, "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") );
}
diff --git a/scene/gui/range.h b/scene/gui/range.h
index e33a71e6ab..48361ddb0e 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/reference_frame.cpp b/scene/gui/reference_frame.cpp
index 679c2cc1e2..b90ea8292d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,9 +32,9 @@ void ReferenceFrame::_notification(int p_what) {
if (p_what==NOTIFICATION_DRAW) {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
- if (get_scene()->is_editor_hint())
+ if (get_tree()->is_editor_hint())
draw_style_box(get_stylebox("border"),Rect2(Point2(),get_size())) ;
}
}
diff --git a/scene/gui/reference_frame.h b/scene/gui/reference_frame.h
index 954b17b5c8..8915b1df0c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 94df42fc8f..5abb6c1d01 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -58,7 +58,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item* p_item) {
}
-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) {
+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) {
RID ci;
if (r_outside)
@@ -78,6 +78,8 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
int margin=_find_margin(it,p_base_font);
Align align=_find_align(it);;
int line=0;
+ int spaces=0;
+
if (p_mode!=PROCESS_CACHE) {
@@ -85,7 +87,14 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
line_ofs = l.offset_caches[line];
}
+ if (p_mode==PROCESS_CACHE) {
+ l.offset_caches.clear();
+ l.height_caches.clear();
+ l.char_count=0;
+ }
+
int wofs=margin;
+ int spaces_size=0;
if (p_mode!=PROCESS_CACHE && align!=ALIGN_FILL)
wofs+=line_ofs;
@@ -101,7 +110,6 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
Variant meta;
-
#define NEW_LINE \
{\
if (p_mode!=PROCESS_CACHE) {\
@@ -117,12 +125,15 @@ 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-wofs); 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);\
}\
y+=line_height+get_constant(SceneStringNames::get_singleton()->line_separation);\
line_height=0;\
+ spaces=0;\
+ spaces_size=0;\
wofs=begin;\
if (p_mode!=PROCESS_CACHE) {\
lh=line<l.height_caches.size()?l.height_caches[line]:1;\
@@ -138,6 +149,10 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
#define ENSURE_WIDTH(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 (r_outside) *r_outside=true; \
*r_click_item=it;\
@@ -203,33 +218,76 @@ if (m_height > line_height) {\
underline=true;
}
+ } else if (p_mode==PROCESS_CACHE) {
+ l.char_count+=text->text.length();
}
rchar=0;
+
while(*c) {
int end=0;
int w=0;
+ int fw=0;
lh=0;
if (p_mode!=PROCESS_CACHE) {
lh=line<l.height_caches.size()?l.height_caches[line]:1;
}
+ bool found_space=false;
while (c[end]!=0 && !(end && c[end-1]==' ' && c[end]!=' ')) {
+
int cw = font->get_char_size(c[end],c[end+1]).width;
+ if (c[end]=='\t') {
+ cw=tab_size*font->get_char_size(' ').width;
+ }
w+=cw;
- end++;
+
+ if (c[end]==' ') {
+
+ if (p_mode==PROCESS_CACHE) {
+ fw+=cw;
+ } else if (align==ALIGN_FILL && line<l.space_caches.size() && l.space_caches[line]>0) {
+ //print_line(String(c,end)+": "+itos(l.offset_caches[line])+"/"+itos(l.space_caches[line]));
+ //sub_space=cw;
+ found_space=true;
+ } else {
+ fw+=cw;
+ }
+ } else {
+ fw+=cw;
+ }
+
+ end++;
}
- ENSURE_WIDTH(w);
+ 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;
+ }
+
+ if (found_space) {
+ int ln = MIN(l.offset_caches.size()-1,line);
+
+ fw+=l.offset_caches[ln]/l.space_caches[ln];
+ }
+
+ }
+
{
int ofs=0;
+
for(int i=0;i<end;i++) {
int pofs=wofs+ofs;
@@ -239,7 +297,11 @@ if (m_height > line_height) {\
if (p_mode==PROCESS_POINTER && r_click_char && p_click_pos.y>=y && p_click_pos.y<=y+lh) {
//int o = (wofs+w)-p_click_pos.x;
+
int cw=font->get_char_size(c[i],c[i+1]).x;
+ if (c[i]=='\t') {
+ cw=tab_size*font->get_char_size(' ').width;
+ }
if (p_click_pos.x-cw/2>pofs) {
@@ -268,22 +330,36 @@ if (m_height > line_height) {\
}
}
- int cw;
+ int cw=0;
+
+ bool visible = visible_characters<0 || p_char_count<visible_characters;
if (selected) {
cw = font->get_char_size(c[i],c[i+1]).x;
draw_rect(Rect2(pofs,y,cw,lh),selection_bg);
- font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg);
+ if (visible)
+ font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg);
} else {
- cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
+ if (visible)
+ cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
}
+ p_char_count++;
+ if (c[i]=='\t') {
+ cw=tab_size*font->get_char_size(' ').width;
+ }
+
+
+ //print_line("draw char: "+String::chr(c[i]));
+
if (underline) {
Color uc=color;
- uc.a*=0.3;
- VS::get_singleton()->canvas_item_add_line(ci,Point2(pofs,y+ascent+2),Point2(pofs+cw,y+ascent+2),uc);
+ 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);
}
ofs+=cw;
}
@@ -292,7 +368,7 @@ if (m_height > line_height) {\
}
- ADVANCE(w);
+ ADVANCE(fw);
CHECK_HEIGHT(fh); //must be done somewhere
c=&c[end];
}
@@ -304,6 +380,8 @@ if (m_height > line_height) {\
lh=0;
if (p_mode!=PROCESS_CACHE)
lh = line<l.height_caches.size()?l.height_caches[line]:1;
+ else
+ l.char_count+=1; //images count as chars too
ItemImage *img = static_cast<ItemImage*>(it);
@@ -316,9 +394,12 @@ if (m_height > line_height) {\
ENSURE_WIDTH( img->image->get_width() );
- if (p_mode==PROCESS_DRAW) {
+ 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()));
}
+ p_char_count++;
ADVANCE( img->image->get_width() );
CHECK_HEIGHT( (img->image->get_height()+font->get_descent()) );
@@ -450,6 +531,23 @@ void RichTextLabel::_notification(int p_what) {
update();
} break;
+ case NOTIFICATION_ENTER_TREE: {
+
+ if (use_bbcode)
+ parse_bbcode(bbcode);
+ first_invalid_line=0; //invalidate ALL
+ update();
+
+ } break;
+ case NOTIFICATION_THEME_CHANGED: {
+
+ if (is_inside_tree() && use_bbcode) {
+ parse_bbcode(bbcode);
+ //first_invalid_line=0; //invalidate ALL
+ //update();
+ }
+
+ } break;
case NOTIFICATION_DRAW: {
_validate_line_caches();
@@ -472,23 +570,26 @@ void RichTextLabel::_notification(int p_what) {
//todo, change to binary search
int from_line = 0;
+ int total_chars = 0;
while (from_line<lines.size()) {
if (lines[from_line].height_accum_cache>=ofs)
break;
from_line++;
+ total_chars+=lines[from_line].char_count;
}
if (from_line>=lines.size())
break; //nothing to draw
int y = (lines[from_line].height_accum_cache - lines[from_line].height_cache) - ofs;
- Ref<Font> base_font=get_font("default_font");
+ Ref<Font> base_font=get_font("normal_font");
Color base_color=get_color("default_color");
while (y<size.height && from_line<lines.size()) {
- _process_line(y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color);
+ _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;
from_line++;
}
}
@@ -521,7 +622,7 @@ void RichTextLabel::_find_click(const Point2i& p_click,Item **r_click_item,int *
int y = (lines[from_line].height_accum_cache - lines[from_line].height_cache) - ofs;
- Ref<Font> base_font=get_font("default_font");
+ Ref<Font> base_font=get_font("normal_font");
Color base_color=get_color("default_color");
@@ -618,7 +719,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: {
@@ -634,12 +735,12 @@ void RichTextLabel::_input_event(InputEvent p_event) {
case KEY_UP: {
if (vscroll->is_visible())
- vscroll->set_val( vscroll->get_val() - get_font("default_font")->get_height() );
+ vscroll->set_val( vscroll->get_val() - get_font("normal_font")->get_height() );
} break;
case KEY_DOWN: {
if (vscroll->is_visible())
- vscroll->set_val( vscroll->get_val() + get_font("default_font")->get_height() );
+ vscroll->set_val( vscroll->get_val() + get_font("normal_font")->get_height() );
} break;
case KEY_HOME: {
@@ -664,6 +765,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
default: handled=false;
}
+
if (handled)
accept_event();
}
@@ -856,13 +958,12 @@ void RichTextLabel::_validate_line_caches() {
//validate invalid lines!s
Size2 size = get_size();
- Ref<Font> base_font=get_font("default_font");
+ Ref<Font> base_font=get_font("normal_font");
for(int i=first_invalid_line;i<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;
@@ -1152,9 +1253,19 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
int pos = 0;
List<String> tag_stack;
- Ref<Font> base_font=get_font("default_font");
+ Ref<Font> normal_font=get_font("normal_font");
+ Ref<Font> bold_font=get_font("bold_font");
+ Ref<Font> italics_font=get_font("italics_font");
+ Ref<Font> bold_italics_font=get_font("bold_italics_font");
+ Ref<Font> mono_font=get_font("mono_font");
+
Color base_color=get_color("default_color");
+ int indent_level=0;
+
+ bool in_bold=false;
+ bool in_italics=false;
+
while(pos < p_bbcode.length()) {
@@ -1182,12 +1293,18 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
String tag = p_bbcode.substr(brk_pos+1,brk_end-brk_pos-1);
- if (tag.begins_with("/")) {
+ if (tag.begins_with("/") && tag_stack.size()) {
bool tag_ok = tag_stack.size() && tag_stack.front()->get()==tag.substr(1,tag.length());
+ if (tag_stack.front()->get()=="b")
+ in_bold=false;
+ if (tag_stack.front()->get()=="i")
+ in_italics=false;
+ if (tag_stack.front()->get()=="indent")
+ indent_level--;
if (!tag_ok) {
@@ -1205,19 +1322,27 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
} else if (tag=="b") {
//use bold font
- push_font(base_font);
+ in_bold=true;
+ if (in_italics)
+ push_font(bold_italics_font);
+ else
+ push_font(bold_font);
pos=brk_end+1;
tag_stack.push_front(tag);
} else if (tag=="i") {
//use italics font
- push_font(base_font);
+ in_italics=true;
+ if (in_bold)
+ push_font(bold_italics_font);
+ else
+ push_font(italics_font);
pos=brk_end+1;
tag_stack.push_front(tag);
} else if (tag=="code") {
//use monospace font
- push_font(base_font);
+ push_font(mono_font);
pos=brk_end+1;
tag_stack.push_front(tag);
} else if (tag=="u") {
@@ -1232,6 +1357,43 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
push_underline();
pos=brk_end+1;
tag_stack.push_front(tag);
+ } else if (tag=="center") {
+
+ //use underline
+ push_align(ALIGN_CENTER);
+ pos=brk_end+1;
+ tag_stack.push_front(tag);
+ } else if (tag=="fill") {
+
+ //use underline
+ push_align(ALIGN_FILL);
+ pos=brk_end+1;
+ tag_stack.push_front(tag);
+ } else if (tag=="right") {
+
+ //use underline
+ push_align(ALIGN_RIGHT);
+ pos=brk_end+1;
+ tag_stack.push_front(tag);
+ } else if (tag=="ul") {
+
+ //use underline
+ push_list(LIST_DOTS);
+ pos=brk_end+1;
+ tag_stack.push_front(tag);
+ } else if (tag=="ol") {
+
+ //use underline
+ push_list(LIST_NUMBERS);
+ pos=brk_end+1;
+ tag_stack.push_front(tag);
+ } else if (tag=="indent") {
+
+ //use underline
+ indent_level++;
+ push_indent(indent_level);
+ pos=brk_end+1;
+ tag_stack.push_front(tag);
} else if (tag=="url") {
@@ -1244,6 +1406,7 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
pos=brk_end+1;
tag_stack.push_front(tag);
+
} else if (tag.begins_with("url=")) {
String url = tag.substr(4,tag.length());
@@ -1321,7 +1484,7 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
if (font.is_valid())
push_font(font);
else
- push_font(base_font);
+ push_font(normal_font);
pos=brk_end+1;
tag_stack.push_front("font");
@@ -1343,8 +1506,7 @@ 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);
-
+ vscroll->set_val(lines[p_line].height_accum_cache-lines[p_line].height_cache);
}
@@ -1407,27 +1569,20 @@ bool RichTextLabel::search(const String& p_string,bool p_from_selection) {
it=_get_next_item(it);
}
- if (!it)
- line=lines.size()-1;
}
- scroll_to_line(line-2);
+ line-=2;
+ scroll_to_line(line<0?0:line);
return true;
}
- } else if (it->type==ITEM_NEWLINE) {
-
- line=static_cast<ItemNewline*>(it)->line;
}
-
it=_get_next_item(it);
charidx=0;
}
-
-
return false;
}
@@ -1467,7 +1622,7 @@ void RichTextLabel::selection_copy() {
if (text!="") {
OS::get_singleton()->set_clipboard(text);
- print_line("COPY: "+text);
+ //print_line("COPY: "+text);
}
}
@@ -1477,7 +1632,29 @@ bool RichTextLabel::is_selection_enabled() const {
return selection.enabled;
}
+void RichTextLabel::set_bbcode(const String& p_bbcode) {
+ bbcode=p_bbcode;
+ if (is_inside_tree() && use_bbcode)
+ parse_bbcode(p_bbcode);
+}
+
+String RichTextLabel::get_bbcode() const {
+ return bbcode;
+}
+
+void RichTextLabel::set_use_bbcode(bool p_enable) {
+ if (use_bbcode==p_enable)
+ return;
+ use_bbcode=p_enable;
+ if (is_inside_tree() && use_bbcode)
+ parse_bbcode(bbcode);
+}
+
+bool RichTextLabel::is_using_bbcode() const {
+
+ return use_bbcode;
+}
void RichTextLabel::_bind_methods() {
@@ -1506,6 +1683,10 @@ void RichTextLabel::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_scroll_follow","follow"),&RichTextLabel::set_scroll_follow);
ObjectTypeDB::bind_method(_MD("is_scroll_following"),&RichTextLabel::is_scroll_following);
+ ObjectTypeDB::bind_method(_MD("get_v_scroll"),&RichTextLabel::get_v_scroll);
+
+ ObjectTypeDB::bind_method(_MD("scroll_to_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);
@@ -1515,6 +1696,20 @@ void RichTextLabel::_bind_methods() {
ObjectTypeDB::bind_method(_MD("parse_bbcode", "bbcode"),&RichTextLabel::parse_bbcode);
ObjectTypeDB::bind_method(_MD("append_bbcode", "bbcode"),&RichTextLabel::append_bbcode);
+ ObjectTypeDB::bind_method(_MD("set_bbcode","text"),&RichTextLabel::set_bbcode);
+ ObjectTypeDB::bind_method(_MD("get_bbcode"),&RichTextLabel::get_bbcode);
+
+ ObjectTypeDB::bind_method(_MD("set_visible_characters","amount"),&RichTextLabel::set_visible_characters);
+ ObjectTypeDB::bind_method(_MD("get_visible_characters"),&RichTextLabel::get_visible_characters);
+
+ ObjectTypeDB::bind_method(_MD("get_total_character_count"),&RichTextLabel::get_total_character_count);
+
+ ObjectTypeDB::bind_method(_MD("set_use_bbcode","enable"),&RichTextLabel::set_use_bbcode);
+ ObjectTypeDB::bind_method(_MD("is_using_bbcode"),&RichTextLabel::is_using_bbcode);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"bbcode/enabled"),_SCS("set_use_bbcode"),_SCS("is_using_bbcode"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"bbcode/bbcode",PROPERTY_HINT_MULTILINE_TEXT),_SCS("set_bbcode"),_SCS("get_bbcode"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"visible_characters",PROPERTY_HINT_RANGE,"-1,128000,1"),_SCS("set_visible_characters"),_SCS("get_visible_characters"));
ADD_SIGNAL( MethodInfo("meta_clicked",PropertyInfo(Variant::NIL,"meta")));
@@ -1541,6 +1736,27 @@ void RichTextLabel::_bind_methods() {
}
+
+void RichTextLabel::set_visible_characters(int p_visible) {
+
+ visible_characters=p_visible;
+ update();
+}
+
+int RichTextLabel::get_visible_characters() const {
+
+ return visible_characters;
+}
+int RichTextLabel::get_total_character_count() const {
+
+ int tc=0;
+ for(int i=0;i<lines.size();i++)
+ tc+=lines[i].char_count;
+
+ return tc;
+}
+
+
RichTextLabel::RichTextLabel() {
@@ -1572,11 +1788,14 @@ RichTextLabel::RichTextLabel() {
vscroll->set_step(1);
vscroll->hide();
current_idx=1;
+ use_bbcode=false;
selection.click=NULL;
selection.active=false;
selection.enabled=false;
+ visible_characters=-1;
+
}
RichTextLabel::~RichTextLabel() {
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 228d607049..eaa8d5d60a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -168,10 +168,12 @@ private:
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; }
+ Line() { from=NULL; char_count=0; }
};
@@ -222,10 +224,10 @@ private:
Selection selection;
+ 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);
+ 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);
@@ -242,6 +244,10 @@ private:
void _input_event(InputEvent p_event);
Item *_get_next_item(Item* p_item);
+ bool use_bbcode;
+ String bbcode;
+
+
protected:
void _notification(int p_what);
@@ -291,9 +297,20 @@ public:
bool is_selection_enabled() const;
void selection_copy();
+
Error parse_bbcode(const String& p_bbcode);
Error append_bbcode(const String& p_bbcode);
+ void set_use_bbcode(bool p_enable);
+ bool is_using_bbcode() const;
+
+ void set_bbcode(const String& p_bbcode);
+ String get_bbcode() const;
+
+ void set_visible_characters(int p_visible);
+ int get_visible_characters() const;
+ int get_total_character_count() const;
+
RichTextLabel();
~RichTextLabel();
};
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index c661a804b3..b1fd914fcd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -51,20 +51,20 @@ void ScrollBar::_input_event(InputEvent p_event) {
if (b.button_index==5 && b.pressed) {
- if (orientation==VERTICAL)
- set_val( get_val() + get_page() / 4.0 );
- else
- set_val( get_val() + get_page() / 4.0 );
+ //if (orientation==VERTICAL)
+ // set_val( get_val() + get_page() / 4.0 );
+ //else
+ set_val( get_val() + get_page() / 4.0 );
accept_event();
}
if (b.button_index==4 && b.pressed) {
- if (orientation==HORIZONTAL)
- set_val( get_val() - get_page() / 4.0 );
- else
- set_val( get_val() - get_page() / 4.0 );
+ //if (orientation==HORIZONTAL)
+ // set_val( get_val() - get_page() / 4.0 );
+ //else
+ set_val( get_val() - get_page() / 4.0 );
accept_event();
}
@@ -293,7 +293,7 @@ void ScrollBar::_notification(int p_what) {
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
if (has_node(drag_slave_path)) {
@@ -303,16 +303,16 @@ void ScrollBar::_notification(int p_what) {
if (drag_slave) {
drag_slave->connect("input_event",this,"_drag_slave_input");
- drag_slave->connect("exit_scene",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT);
+ drag_slave->connect("exit_tree",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT);
}
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
if (drag_slave) {
drag_slave->disconnect("input_event",this,"_drag_slave_input");
- drag_slave->disconnect("exit_scene",this,"_drag_slave_exit");
+ drag_slave->disconnect("exit_tree",this,"_drag_slave_exit");
}
drag_slave=NULL;
@@ -635,18 +635,18 @@ void ScrollBar::_drag_slave_input(const InputEvent& p_input) {
void ScrollBar::set_drag_slave(const NodePath& p_path) {
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
if (drag_slave) {
drag_slave->disconnect("input_event",this,"_drag_slave_input");
- drag_slave->disconnect("exit_scene",this,"_drag_slave_exit");
+ drag_slave->disconnect("exit_tree",this,"_drag_slave_exit");
}
}
drag_slave=NULL;
drag_slave_path=p_path;
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
if (has_node(p_path)) {
Node *n = get_node(p_path);
@@ -655,7 +655,7 @@ void ScrollBar::set_drag_slave(const NodePath& p_path) {
if (drag_slave) {
drag_slave->connect("input_event",this,"_drag_slave_input");
- drag_slave->connect("exit_scene",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT);
+ drag_slave->connect("exit_tree",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT);
}
}
}
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index ad3d1a7f58..367bc3eb53 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index c8f9ed16b5..e5b5d531a0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -169,7 +169,7 @@ void ScrollContainer::_update_scrollbar_pos() {
void ScrollContainer::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_SCENE || p_what == NOTIFICATION_THEME_CHANGED) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
call_deferred("_update_scrollbar_pos");
};
@@ -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 c8b03b3671..b8d37be08c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp
index aac9ac0d03..5e822a10ad 100644
--- a/scene/gui/separator.cpp
+++ b/scene/gui/separator.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/separator.h b/scene/gui/separator.h
index 177e69cffe..17e9c11e34 100644
--- a/scene/gui/separator.h
+++ b/scene/gui/separator.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 68525cf464..b6292c544b 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,7 +49,10 @@ void Slider::_input_event(InputEvent p_event) {
if (mb.pressed) {
grab.pos=orientation==VERTICAL?mb.y:mb.x;
double max = orientation==VERTICAL ? get_size().height : get_size().width ;
- set_val( ( ( (double)grab.pos / max) * ( get_max() - get_min() ) ) + get_min() );
+ if (orientation==VERTICAL)
+ set_val( ( ( -(double)grab.pos / max) * ( get_max() - get_min() ) ) + get_max() );
+ else
+ set_val( ( ( (double)grab.pos / max) * ( get_max() - get_min() ) ) + get_min() );
grab.active=true;
grab.uvalue=get_unit_value();
} else {
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index d9cb7e754b..5850c48ce3 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 59f4386996..051a8dd018 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,11 +192,12 @@ 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) {
//_value_changed(0);
- } else if (p_what==NOTIFICATION_ENTER_SCENE) {
+ } else if (p_what==NOTIFICATION_ENTER_TREE) {
_value_changed(0);
}
@@ -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 70121c9088..1b3bc6d817 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 49a7957d7c..49067bb3a0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -345,6 +345,7 @@ void SplitContainer::_input_event(const InputEvent& p_event) {
expand_ofs=drag_ofs+((vertical?mm.y:mm.x)-drag_from);
queue_sort();
+ emit_signal("dragged",get_split_offset());
}
}
@@ -431,10 +432,12 @@ void SplitContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_dragger_visible","visible"),&SplitContainer::set_dragger_visible);
ObjectTypeDB::bind_method(_MD("is_dragger_visible"),&SplitContainer::is_dragger_visible);
+ 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::BOOL,"split/dragger_visible"),_SCS("set_dragger_visible"),_SCS("is_dragger_visible"));
+
}
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index 4065b7818c..d7f56c6fb4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 3c95b102d7..6fa701340d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -88,7 +88,22 @@ void TabContainer::_input_event(const InputEvent& p_event) {
Ref<Font> font = get_font("font");
Ref<Texture> incr = get_icon("increment");
Ref<Texture> decr = get_icon("decrement");
+ Ref<Texture> menu = get_icon("menu");
+ Ref<Texture> menu_hl = get_icon("menu_hl");
+ if (popup && pos.x>get_size().width-menu->get_width()) {
+
+
+ emit_signal("pre_popup_pressed");
+ Vector2 pp_pos = get_global_pos();
+ pp_pos.x+=get_size().width;
+ pp_pos.x-=popup->get_size().width;
+ pp_pos.y+=menu->get_height();
+
+ popup->set_global_pos( pp_pos );
+ popup->popup();;
+ return;
+ }
pos.x-=tabs_ofs_cache;
int idx=0;
@@ -113,20 +128,20 @@ void TabContainer::_input_event(const InputEvent& p_event) {
break;
}
- String s = c->has_meta("_tab_title")?String(XL_MESSAGE(String(c->get_meta("_tab_title")))):String(c->get_name());
+ String s = c->has_meta("_tab_name")?String(XL_MESSAGE(String(c->get_meta("_tab_name")))):String(c->get_name());
int tab_width=font->get_string_size(s).width;
- if (c->has_meta("_tab_icon")) {
- Ref<Texture> icon = c->get_meta("_tab_icon");
- if (icon.is_valid()) {
- tab_width+=icon->get_width();
- if (s!="")
- tab_width+=get_constant("hseparation");
+ if (c->has_meta("_tab_icon")) {
+ Ref<Texture> icon = c->get_meta("_tab_icon");
+ if (icon.is_valid()) {
+ tab_width+=icon->get_width();
+ if (s!="")
+ tab_width+=get_constant("hseparation");
- }
- }
+ }
+ }
- if (idx==current) {
+ if (idx==current) {
tab_width+=tab_fg->get_minimum_size().width;
} else {
@@ -163,7 +178,7 @@ void TabContainer::_input_event(const InputEvent& p_event) {
if (found!=-1) {
- set_current_tab(found);
+ set_current_tab(found);
}
}
@@ -194,7 +209,9 @@ void TabContainer::_notification(int p_what) {
Ref<Texture> incr = get_icon("increment");
Ref<Texture> incr_hl = get_icon("increment_hilite");
Ref<Texture> decr = get_icon("decrement");
- Ref<Texture> decr_hl = get_icon("decrement_hilite");
+ Ref<Texture> decr_hl = get_icon("decrement_hilite");
+ Ref<Texture> menu = get_icon("menu");
+ Ref<Texture> menu_hl = get_icon("menu_hl");
Ref<Font> font = get_font("font");
Color color_fg = get_color("font_color_fg");
Color color_bg = get_color("font_color_bg");
@@ -209,8 +226,21 @@ void TabContainer::_notification(int p_what) {
Size2 top_size = Size2( size.width, top_margin );
+
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>();
@@ -218,16 +248,29 @@ 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_title")?String(XL_MESSAGE(String(c->get_meta("_tab_title")))):String(c->get_name());
+ 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;
if (c->has_meta("_tab_icon")) {
Ref<Texture> icon = c->get_meta("_tab_icon");
if (icon.is_valid()) {
w+=icon->get_width();
if (s!="")
- w+=get_constant("hseparation");
+ w+=get_constant("hseparation");
}
}
@@ -239,52 +282,47 @@ void TabContainer::_notification(int p_what) {
w+=tab_bg->get_minimum_size().width;
}
+ if (idx<tab_display_ofs) {
+
+ }
+ last_tab_cache=idx;
+
idx++;
}
int ofs;
- int limit=get_size().width;
-
-
- if (w<=get_size().width) {
- switch(align) {
- case ALIGN_LEFT: ofs = side_margin; break;
- case ALIGN_CENTER: ofs = (int(top_size.width) - w)/2; break;
- case ALIGN_RIGHT: ofs = int(top_size.width) - 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;
+ }
}
- String s = c->has_meta("_tab_title")?String(c->get_meta("_tab_title")):String(c->get_name());
+ 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;
if (c->has_meta("_tab_icon")) {
@@ -314,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;
@@ -335,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;
@@ -364,6 +399,15 @@ void TabContainer::_notification(int p_what) {
incr->draw(ci,Point2(limit+incr->get_width(),vofs),Color(1,1,1,notdone?1.0:0.5));
}
+ if (popup) {
+ int from = get_size().width-menu->get_width();
+
+ if (mouse_x_cache > from)
+ menu_hl->draw(get_canvas_item(),Size2(from,0));
+ else
+ menu->draw(get_canvas_item(),Size2(from,0));
+ }
+
panel->draw(ci, Rect2( 0, top_size.height, size.width, size.height-top_size.height));
} break;
@@ -465,6 +509,48 @@ int TabContainer::get_current_tab() const {
return current;
}
+Control* TabContainer::get_tab_control(int p_idx) const {
+
+ int idx=0;
+
+
+ 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;
+ if (idx==p_idx) {
+ return c;
+
+ }
+ idx++;
+ }
+
+ return NULL;
+}
+Control* TabContainer::get_current_tab_control() const {
+
+ int idx=0;
+
+
+ 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;
+ if (idx==current) {
+ return c;
+
+ }
+ idx++;
+ }
+
+ return NULL;
+}
void TabContainer::remove_child_notify(Node *p_child) {
@@ -602,12 +688,58 @@ void TabContainer::get_translatable_strings(List<String> *p_strings) const {
}
+Size2 TabContainer::get_minimum_size() const {
+
+ Size2 ms;
+
+ 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;
+
+ if (!c->has_meta("_tab_name"))
+ continue;
+
+ if (!c->is_visible())
+ continue;
+
+ Size2 cms = c->get_minimum_size();
+ ms.x=MAX(ms.x,cms.x);
+ ms.y=MAX(ms.y,cms.y);
+ }
+
+ Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
+ Ref<Font> font = get_font("font");
+
+ ms.y+=MAX(tab_bg->get_minimum_size().y,tab_fg->get_minimum_size().y);
+ ms.y+=font->get_height();
+
+ return ms;
+}
+
+void TabContainer::set_popup(Node *p_popup) {
+ ERR_FAIL_NULL(p_popup);
+ popup=p_popup->cast_to<Popup>();
+ update();
+}
+
+Popup* TabContainer::get_popup() const {
+ return popup;
+}
+
+
void TabContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_input_event"),&TabContainer::_input_event);
ObjectTypeDB::bind_method(_MD("get_tab_count"),&TabContainer::get_tab_count);
ObjectTypeDB::bind_method(_MD("set_current_tab","tab_idx"),&TabContainer::set_current_tab);
ObjectTypeDB::bind_method(_MD("get_current_tab"),&TabContainer::get_current_tab);
+ ObjectTypeDB::bind_method(_MD("get_current_tab_control:Control"),&TabContainer::get_current_tab_control);
+ ObjectTypeDB::bind_method(_MD("get_tab_control:Control","idx"),&TabContainer::get_tab_control);
ObjectTypeDB::bind_method(_MD("set_tab_align","align"),&TabContainer::set_tab_align);
ObjectTypeDB::bind_method(_MD("get_tab_align"),&TabContainer::get_tab_align);
ObjectTypeDB::bind_method(_MD("set_tabs_visible","visible"),&TabContainer::set_tabs_visible);
@@ -616,10 +748,13 @@ void TabContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_tab_title","tab_idx"),&TabContainer::get_tab_title);
ObjectTypeDB::bind_method(_MD("set_tab_icon","tab_idx","icon:Texture"),&TabContainer::set_tab_icon);
ObjectTypeDB::bind_method(_MD("get_tab_icon:Texture","tab_idx"),&TabContainer::get_tab_icon);
+ ObjectTypeDB::bind_method(_MD("set_popup","popup:Popup"),&TabContainer::set_popup);
+ ObjectTypeDB::bind_method(_MD("get_popup:Popup"),&TabContainer::get_popup);
ObjectTypeDB::bind_method(_MD("_child_renamed_callback"),&TabContainer::_child_renamed_callback);
ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab")));
+ ADD_SIGNAL(MethodInfo("pre_popup_pressed"));
ADD_PROPERTY( PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM,"Left,Center,Right"), _SCS("set_tab_align"), _SCS("get_tab_align") );
ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") );
@@ -636,5 +771,6 @@ TabContainer::TabContainer() {
mouse_x_cache=0;
align=ALIGN_CENTER;
tabs_visible=true;
+ popup=NULL;
}
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index d5b6a2b503..602d248b46 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,7 @@
#include "scene/gui/control.h"
-
+#include "scene/gui/popup.h"
class TabContainer : public Control {
OBJ_TYPE( TabContainer, Control );
@@ -55,6 +55,8 @@ private:
TabAlign align;
Control *_get_tab(int idx) const;
int _get_top_margin() const;
+ Popup *popup;
+
protected:
@@ -85,8 +87,17 @@ public:
void set_current_tab(int p_current);
int get_current_tab() const;
+ Control* get_tab_control(int p_idx) const;
+ Control* get_current_tab_control() const;
+
+ virtual Size2 get_minimum_size() const;
+
virtual void get_translatable_strings(List<String> *p_strings) const;
+ void set_popup(Node *p_popup);
+ Popup* get_popup() const;
+
+
TabContainer();
};
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index b7c857b9c7..47a55e0716 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,7 +56,22 @@ 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 (tabs[i].close_button.is_valid()) {
+ Ref<Texture> cb=tabs[i].close_button;
+ 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);
+ }
}
return ms;
@@ -66,6 +81,81 @@ 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 );
+
+ 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
+ if (cb_displaypolicy == SHOW_HOVER) {
+ 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) {
+ hover=i;
+ }
+ }
+
+
+ // 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) {
@@ -76,9 +166,21 @@ void Tabs::_input_event(const InputEvent& p_event) {
int found=-1;
for(int i=0;i<tabs.size();i++) {
- int ofs=tabs[i].ofs_cache;
+ 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;
+ }
- if (pos.x < ofs) {
+ 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) {
found=i;
break;
@@ -89,6 +191,7 @@ void Tabs::_input_event(const InputEvent& p_event) {
if (found!=-1) {
set_current_tab(found);
+ emit_signal("tab_changed",found);
}
}
@@ -99,7 +202,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();
@@ -117,17 +225,31 @@ void Tabs::_notification(int p_what) {
int w=0;
+ int mw = get_minimum_size().width;
+
+ if (tab_align==ALIGN_CENTER) {
+ w=(get_size().width-mw)/2;
+ } else if (tab_align==ALIGN_RIGHT) {
+ w=get_size().width-mw;
+
+ }
+
+ if (w<0) {
+ w=0;
+ }
+
for(int i=0;i<tabs.size();i++) {
+ 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!="")
@@ -136,6 +258,66 @@ 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);
+
+ }
+
+ // Close button
+ switch (cb_displaypolicy) {
+ case SHOW_ALWAYS: {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> rb=tabs[i].close_button;
+
+ lsize+=get_constant("hseparation");
+ //lsize+=style->get_margin(MARGIN_LEFT);
+ lsize+=rb->get_width();
+ //lsize+=style->get_margin(MARGIN_RIGHT);
+
+ }
+ } break;
+ case SHOW_ACTIVE_ONLY: {
+ if (i==current) {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> rb=tabs[i].close_button;
+
+ lsize+=get_constant("hseparation");
+ //lsize+=style->get_margin(MARGIN_LEFT);
+ lsize+=rb->get_width();
+ //lsize+=style->get_margin(MARGIN_RIGHT);
+
+ }
+ }
+ } break;
+ case SHOW_HOVER: {
+ if (i==current || i==hover) {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> rb=tabs[i].close_button;
+
+ lsize+=get_constant("hseparation");
+ //lsize+=style->get_margin(MARGIN_LEFT);
+ lsize+=rb->get_width();
+ //lsize+=style->get_margin(MARGIN_RIGHT);
+
+ }
+ }
+ } break;
+ case SHOW_NEVER: // by default, never show close button
+ default: {
+ // do nothing
+ } break;
+
+ }
+
Ref<StyleBox> sb;
int va;
@@ -169,9 +351,136 @@ 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;
- tabs[i].ofs_cache=w;
+ 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;
+
+
+ }
+
+
+
+
+ // Close button
+ switch (cb_displaypolicy) {
+ case SHOW_ALWAYS: {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> cb=tabs[i].close_button;
+
+ 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;
+ }
+ } break;
+ case SHOW_ACTIVE_ONLY: {
+ if (current==i) {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> cb=tabs[i].close_button;
+
+ 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;
+ }
+ }
+ } break;
+ case SHOW_HOVER: {
+ if (current==i || hover==i) {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> cb=tabs[i].close_button;
+
+ 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;
+ }
+ }
+ } break;
+ case SHOW_NEVER:
+ default: {
+ // show nothing
+ } break;
+
+ }
+
+ w+=sb->get_margin(MARGIN_RIGHT);
+
+ tabs[i].size_cache=w-tabs[i].ofs_cache;
}
@@ -195,7 +504,7 @@ void Tabs::set_current_tab(int p_current) {
current=p_current;
_change_notify("current_tab");
- emit_signal("tab_changed",current);
+ //emit_signal("tab_changed",current);
update();
}
@@ -237,11 +546,46 @@ 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::set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button) {
+ ERR_FAIL_INDEX(p_tab, tabs.size());
+ tabs[p_tab].close_button=p_close_button;
+ update();
+ minimum_size_changed();
+}
+
+
+Ref<Texture> Tabs::get_tab_close_button(int p_tab) const{
+
+ ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>());
+ return tabs[p_tab].close_button;
+
+}
+
void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) {
Tab t;
t.text=p_str;
t.icon=p_icon;
+
+ t.close_button = get_icon("Close","EditorIcons");
+
tabs.push_back(t);
update();
@@ -249,6 +593,12 @@ void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) {
}
+void Tabs::clear_tabs() {
+ tabs.clear();
+ current=0;
+ update();
+}
+
void Tabs::remove_tab(int p_idx) {
ERR_FAIL_INDEX(p_idx,tabs.size());
@@ -263,10 +613,26 @@ void Tabs::remove_tab(int p_idx) {
if (current>=tabs.size())
current=tabs.size()-1;
- emit_signal("tab_changed",current);
+ //emit_signal("tab_changed",current);
}
+void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy) {
+ cb_displaypolicy = p_cb_displaypolicy;
+}
+
+
+void Tabs::set_tab_align(TabAlign p_align) {
+
+ tab_align=p_align;
+ update();
+}
+
+Tabs::TabAlign Tabs::get_tab_align() const {
+
+ return tab_align;
+}
+
void Tabs::_bind_methods() {
@@ -278,16 +644,37 @@ void Tabs::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_tab_title","tab_idx"),&Tabs::get_tab_title);
ObjectTypeDB::bind_method(_MD("set_tab_icon","tab_idx","icon:Texture"),&Tabs::set_tab_icon);
ObjectTypeDB::bind_method(_MD("get_tab_icon:Texture","tab_idx"),&Tabs::get_tab_icon);
- ObjectTypeDB::bind_method(_MD("remove_tab","tab_idx","icon:Texture"),&Tabs::remove_tab);
+ ObjectTypeDB::bind_method(_MD("remove_tab","tab_idx"),&Tabs::remove_tab);
+ 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);
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( SHOW_ACTIVE_ONLY );
+ BIND_CONSTANT( SHOW_ALWAYS );
+ BIND_CONSTANT( SHOW_HOVER );
+ BIND_CONSTANT( SHOW_NEVER );
}
+
Tabs::Tabs() {
current=0;
+ tab_align=ALIGN_CENTER;
+ rb_hover=-1;
+ rb_pressing=false;
+ cb_hover=-1;
+ cb_pressing=false;
+ cb_displaypolicy = SHOW_NEVER; // Default : no close button
}
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 72c077a8b0..1a8352bc93 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,6 +34,22 @@
class Tabs : public Control {
OBJ_TYPE( Tabs, Control );
+public:
+
+ enum TabAlign {
+
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT
+ };
+
+ enum CloseButtonDisplayPolicy {
+
+ SHOW_ALWAYS,
+ SHOW_ACTIVE_ONLY,
+ SHOW_HOVER,
+ SHOW_NEVER
+ };
private:
@@ -42,12 +58,26 @@ private:
String text;
Ref<Texture> icon;
int ofs_cache;
+ int size_cache;
+ Ref<Texture> right_button;
+ Rect2 rb_rect;
+ Ref<Texture> close_button;
+ Rect2 cb_rect;
};
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
protected:
@@ -65,16 +95,29 @@ 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_close_button(int p_tab, const Ref<Texture>& p_close_button);
+ Ref<Texture> get_tab_close_button(int p_tab) const;
+ void set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy);
+
+ void set_tab_align(TabAlign p_align);
+ TabAlign get_tab_align() const;
+
int get_tab_count() const;
void set_current_tab(int p_current);
int get_current_tab() const;
void remove_tab(int p_idx);
+ void clear_tabs();
+
Size2 get_minimum_size() const;
Tabs();
};
+VARIANT_ENUM_CAST(Tabs::TabAlign);
#endif // TABS_H
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 3566c1bfc4..29969b65e6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,52 +26,43 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
- /*****f********************************************/
-/* text_edit.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 "text_edit.h"
#include "os/keyboard.h"
+#include "os/input.h"
#include "os/os.h"
-
+
#include "globals.h"
#include "message_queue.h"
#define TAB_PIXELS
static bool _is_text_char(CharType c) {
-
+
return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
}
static bool _is_symbol(CharType c) {
-
+
return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t');
}
static bool _is_pair_right_symbol(CharType c) {
return
- c == '"' ||
- c == '\'' ||
- c == ')' ||
- c == ']' ||
- c == '}';
+ c == '"' ||
+ c == '\'' ||
+ c == ')' ||
+ c == ']' ||
+ c == '}';
}
static bool _is_pair_left_symbol(CharType c) {
return
- c == '"' ||
- c == '\'' ||
- c == '(' ||
- c == '[' ||
- c == '{';
+ c == '"' ||
+ c == '\'' ||
+ c == '(' ||
+ c == '[' ||
+ c == '{';
}
static bool _is_pair_symbol(CharType c) {
@@ -93,81 +84,81 @@ static CharType _get_right_pair_symbol(CharType c) {
}
void TextEdit::Text::set_font(const Ref<Font>& p_font) {
-
+
font=p_font;
}
void TextEdit::Text::set_tab_size(int p_tab_size) {
-
+
tab_size=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();
-
+
//update width
-
+
for(int i=0;i<len;i++) {
if (str[i]=='\t') {
-
+
int left = w%tab_w;
if (left==0)
w+=tab_w;
else
w+=tab_w-w%tab_w; // is right...
-
+
} else {
-
+
w+=font->get_char_size(str[i],str[i+1]).width;
}
}
-
-
+
+
text[p_line].width_cache=w;
-
+
//update regions
-
+
text[p_line].region_info.clear();
-
+
for(int i=0;i<len;i++) {
-
+
if (!_is_symbol(str[i]))
continue;
if (str[i]=='\\') {
i++; //skip quoted anything
continue;
}
-
+
int left=len-i;
-
+
for(int j=0;j<color_regions->size();j++) {
-
+
const ColorRegion& cr=color_regions->operator [](j);
-
+
/* BEGIN */
-
+
int lr=cr.begin_key.length();
if (lr==0 || lr>left)
continue;
-
+
const CharType* kc = cr.begin_key.c_str();
-
+
bool match=true;
-
+
for(int k=0;k<lr;k++) {
if (kc[k]!=str[i+k]) {
match=false;
break;
}
}
-
+
if (match) {
-
+
ColorRegionInfo cri;
cri.end=false;
cri.region=j;
@@ -175,26 +166,26 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
i+=lr-1;
break;
}
-
+
/* END */
-
+
lr=cr.end_key.length();
if (lr==0 || lr>left)
continue;
-
+
kc = cr.end_key.c_str();
-
+
match=true;
-
+
for(int k=0;k<lr;k++) {
if (kc[k]!=str[i+k]) {
match=false;
break;
}
}
-
+
if (match) {
-
+
ColorRegionInfo cri;
cri.end=true;
cri.region=j;
@@ -202,72 +193,72 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
i+=lr-1;
break;
}
-
+
}
}
-
-
+
+
}
const Map<int,TextEdit::Text::ColorRegionInfo>& TextEdit::Text::get_color_region_info(int p_line) {
-
+
Map<int,ColorRegionInfo> *cri=NULL;
ERR_FAIL_INDEX_V(p_line,text.size(),*cri); //enjoy your crash
-
+
if (text[p_line].width_cache==-1) {
_update_line_cache(p_line);
}
-
+
return text[p_line].region_info;
}
int TextEdit::Text::get_line_width(int p_line) const {
-
+
ERR_FAIL_INDEX_V(p_line,text.size(),-1);
-
+
if (text[p_line].width_cache==-1) {
_update_line_cache(p_line);
}
-
+
return text[p_line].width_cache;
}
void TextEdit::Text::clear_caches() {
-
+
for(int i=0;i<text.size();i++)
text[i].width_cache=-1;
-
+
}
void TextEdit::Text::clear() {
-
-
+
+
text.clear();;
insert(0,"");
}
int TextEdit::Text::get_max_width() const {
//quite some work.. but should be fast enough.
-
+
int max = 0;
-
+
for(int i=0;i<text.size();i++)
max=MAX(max,get_line_width(i));
return max;
-
+
}
void TextEdit::Text::set(int p_line,const String& p_text) {
-
+
ERR_FAIL_INDEX(p_line,text.size());
-
+
text[p_line].width_cache=-1;
text[p_line].data=p_text;
}
void TextEdit::Text::insert(int p_at,const String& p_text) {
-
+
Line line;
line.marked=false;
line.breakpoint=false;
@@ -276,114 +267,140 @@ void TextEdit::Text::insert(int p_at,const String& p_text) {
text.insert(p_at,line);
}
void TextEdit::Text::remove(int p_at) {
-
+
text.remove(p_at);
}
void TextEdit::_update_scrollbars() {
-
-
+
+
Size2 size = get_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
-
-
-
+
+
+
v_scroll->set_begin( Point2(size.width - vmin.width, cache.style_normal->get_margin(MARGIN_TOP)) );
v_scroll->set_end( Point2(size.width, size.height - cache.style_normal->get_margin(MARGIN_TOP) - cache.style_normal->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) );
-
-
+
+
int hscroll_rows = ((hmin.height-1)/get_row_height())+1;
int visible_rows = get_visible_rows();
- int total_rows = text.size() * cache.line_spacing;
-
+ int total_rows = text.size();
+
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;
-
+
if (total_rows <= visible_rows && total_width <= visible_width) {
//thanks yessopie for this clever bit of logic
use_hscroll=false;
use_vscroll=false;
-
+
} else {
-
+
if (total_rows > visible_rows && total_width <= visible_width - vscroll_pixels) {
//thanks yessopie for this clever bit of logic
use_hscroll=false;
}
-
+
if (total_rows <= visible_rows - hscroll_rows && total_width > visible_width) {
//thanks yessopie for this clever bit of logic
use_vscroll=false;
}
}
-
+
updating_scrolls=true;
-
+
if (use_vscroll) {
-
+
v_scroll->show();
v_scroll->set_max(total_rows);
v_scroll->set_page(visible_rows);
-
v_scroll->set_val(cursor.line_ofs);
-
+
} else {
cursor.line_ofs = 0;
v_scroll->hide();
}
-
+
if (use_hscroll) {
-
+
h_scroll->show();
h_scroll->set_max(total_width);
h_scroll->set_page(visible_width);
h_scroll->set_val(cursor.x_ofs);
+
} else {
-
+
h_scroll->hide();
}
+
+
+
+ updating_scrolls=false;
+}
+void TextEdit::_click_selection_held() {
+ if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode!=Selection::MODE_NONE) {
- updating_scrolls=false;
+ 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) {
-
+
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
-
+ case NOTIFICATION_ENTER_TREE: {
+
_update_caches();
if (cursor_changed_dirty)
MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit");
if (text_changed_dirty)
MessageQueue::get_singleton()->push_call(this,"_text_changed_emit");
-
+
} break;
case NOTIFICATION_RESIZED: {
-
+
cache.size=get_size();
adjust_viewport_to_cursor();
-
-
+
+
} break;
case NOTIFICATION_THEME_CHANGED: {
-
+
_update_caches();
};
case NOTIFICATION_DRAW: {
-
+
int line_number_char_count=0;
-
+
{
int lc=text.size()+1;
cache.line_number_w=0;
@@ -391,20 +408,20 @@ void TextEdit::_notification(int p_what) {
cache.line_number_w+=1;
lc/=10;
};
-
+
if (line_numbers) {
-
+
line_number_char_count=cache.line_number_w;
cache.line_number_w=(cache.line_number_w+1)*cache.font->get_char_size('0').width;
} else {
cache.line_number_w=0;
}
-
-
+
+
}
_update_scrollbars();
-
-
+
+
RID ci = get_canvas_item();
int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w;
int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT);
@@ -412,77 +429,233 @@ void TextEdit::_notification(int p_what) {
cache.style_normal->draw(ci,Rect2(Point2(),cache.size));
if (has_focus())
cache.style_focus->draw(ci,Rect2(Point2(),cache.size));
-
-
+
+
int ascent=cache.font->get_ascent();
-
+
int visible_rows = get_visible_rows();
-
+
int tab_w = cache.font->get_char_size(' ').width*tab_size;
-
+
Color color = cache.font_color;
int in_region=-1;
-
+
if (syntax_coloring) {
-
+
if (custom_bg_color.a>0.01) {
-
+
Point2i ofs = Point2i(cache.style_normal->get_offset())/2.0;
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(ofs, get_size()-cache.style_normal->get_minimum_size()+ofs),custom_bg_color);
}
//compute actual region to start (may be inside say, a comment).
//slow in very large documments :( but ok for source!
-
+
for(int i=0;i<cursor.line_ofs;i++) {
-
+
const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(i);
-
+
if (in_region>=0 && color_regions[in_region].line_only) {
in_region=-1; //reset regions that end at end of line
}
-
+
for( const Map<int,Text::ColorRegionInfo>::Element* E= cri_map.front();E;E=E->next() ) {
-
+
const Text::ColorRegionInfo &cri=E->get();
-
+
if (in_region==-1) {
-
+
if (!cri.end) {
-
+
in_region=cri.region;
}
} else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
-
+
if (cri.end || color_regions[cri.region].eq) {
-
+
in_region=-1;
}
}
}
}
}
-
+
+ int brace_open_match_line=-1;
+ int brace_open_match_column=-1;
+ bool brace_open_matching=false;
+ bool brace_open_mismatch=false;
+ int brace_close_match_line=-1;
+ int brace_close_match_column=-1;
+ bool brace_close_matching=false;
+ bool brace_close_mismatch=false;
+
+
+ if (brace_matching_enabled) {
+
+ if (cursor.column<text[cursor.line].length()) {
+ //check for open
+ CharType c = text[cursor.line][cursor.column];
+ CharType closec=0;
+
+ if (c=='[') {
+ closec=']';
+ } else if (c=='{') {
+ closec='}';
+ } else if (c=='(') {
+ closec=')';
+ }
+
+ if (closec!=0) {
+
+ int stack=1;
+
+
+ for(int i=cursor.line;i<text.size();i++) {
+
+ int from = i==cursor.line?cursor.column+1:0;
+ for(int j=from;j<text[i].length();j++) {
+
+ CharType cc = text[i][j];
+ //ignore any brackets inside a string
+ if (cc== '"' || cc == '\'') {
+ CharType quotation = cc;
+ do {
+ j++;
+ if (!(j<text[i].length())) {
+ break;
+ }
+ cc=text[i][j];
+ //skip over escaped quotation marks inside strings
+ if (cc=='\\') {
+ bool escaped = true;
+ while (j+1<text[i].length() && text[i][j+1]=='\\') {
+ escaped=!escaped;
+ j++;
+ }
+ if (escaped) {
+ j++;
+ continue;
+ }
+ }
+ } while (cc!= quotation);
+ } else if (cc==c)
+ stack++;
+ else if (cc==closec)
+ stack--;
+
+ if (stack==0) {
+ brace_open_match_line=i;
+ brace_open_match_column=j;
+ brace_open_matching=true;
+
+ break;
+ }
+ }
+ if (brace_open_match_line!=-1)
+ break;
+ }
+
+ if (!brace_open_matching)
+ brace_open_mismatch=true;
+
+
+ }
+ }
+
+ if (cursor.column>0) {
+ CharType c = text[cursor.line][cursor.column-1];
+ CharType closec=0;
+
+
+
+ if (c==']') {
+ closec='[';
+ } else if (c=='}') {
+ closec='{';
+ } else if (c==')') {
+ closec='(';
+ }
+
+ if (closec!=0) {
+
+ int stack=1;
+
+
+ for(int i=cursor.line;i>=0;i--) {
+
+ int from = i==cursor.line?cursor.column-2:text[i].length()-1;
+ for(int j=from;j>=0;j--) {
+
+ CharType cc = text[i][j];
+ //ignore any brackets inside a string
+ if (cc== '"' || cc == '\'') {
+ CharType quotation = cc;
+ do {
+ j--;
+ if (!(j>=0)) {
+ break;
+ }
+ cc=text[i][j];
+ //skip over escaped quotation marks inside strings
+ if (cc==quotation) {
+ bool escaped = false;
+ while (j-1>=0 && text[i][j-1]=='\\') {
+ escaped=!escaped;
+ j--;
+ }
+ if (escaped) {
+ j--;
+ cc='\\';
+ continue;
+ }
+ }
+ } while (cc!= quotation);
+ } else if (cc==c)
+ stack++;
+ else if (cc==closec)
+ stack--;
+
+ if (stack==0) {
+ brace_close_match_line=i;
+ brace_close_match_column=j;
+ brace_close_matching=true;
+
+ break;
+ }
+ }
+ if (brace_close_match_line!=-1)
+ break;
+ }
+
+ if (!brace_close_matching)
+ brace_close_mismatch=true;
+
+
+ }
+
+
+ }
+ }
+
+
int deregion=0; //force it to clear inrgion
Point2 cursor_pos;
-
+
for (int i=0;i<visible_rows;i++) {
-
+
int line=i+cursor.line_ofs;
-
+
if (line<0 || line>=(int)text.size())
continue;
-
-
-
+
const String &str=text[line];
-
+
int char_margin=xmargin_beg-cursor.x_ofs;
int char_ofs=0;
int ofs_y=i*get_row_height()+cache.line_spacing/2;
bool prev_is_char=false;
bool in_keyword=false;
Color keyword_color;
-
+
if (cache.line_number_w) {
Color fcol = cache.font_color;
fcol.a*=0.4;
@@ -490,167 +663,191 @@ void TextEdit::_notification(int p_what) {
while (fc.length() < line_number_char_count) {
fc="0"+fc;
}
-
+
cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol);
}
-
+
const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line);
-
-
+
+
if (text.is_marked(line)) {
-
+
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.mark_color);
}
-
+
if (text.is_breakpoint(line)) {
-
+
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color);
}
-
-
+
+
if (line==cursor.line) {
-
+
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color);
-
+
}
for (int j=0;j<str.length();j++) {
-
+
//look for keyword
-
+
if (deregion>0) {
deregion--;
if (deregion==0)
in_region=-1;
}
if (syntax_coloring && deregion==0) {
-
-
+
+
color = cache.font_color; //reset
//find keyword
bool is_char = _is_text_char(str[j]);
bool is_symbol=_is_symbol(str[j]);
-
+
if (j==0 && in_region>=0 && color_regions[in_region].line_only) {
in_region=-1; //reset regions that end at end of line
}
-
+
if (is_symbol && cri_map.has(j)) {
-
-
+
+
const Text::ColorRegionInfo &cri=cri_map[j];
-
+
if (in_region==-1) {
-
+
if (!cri.end) {
-
+
in_region=cri.region;
}
} else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
-
+
if (cri.end || color_regions[cri.region].eq) {
-
+
deregion=color_regions[cri.region].eq?color_regions[cri.region].begin_key.length():color_regions[cri.region].end_key.length();
}
}
}
-
+
if (!is_char)
in_keyword=false;
-
+
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);
StrRange range(&str[j],to-j);
-
+
const Color *col=keywords.custom_getptr(range,hash);
-
+
if (col) {
-
+
in_keyword=true;
keyword_color=*col;
}
}
-
-
+
+
if (in_region>=0)
color=color_regions[in_region].color;
else if (in_keyword)
color=keyword_color;
else if (is_symbol)
color=symbol_color;
-
+
prev_is_char=is_char;
-
+
}
int char_w;
-
+
//handle tabulator
-
-
+
+
if (str[j]=='\t') {
int left = char_ofs%tab_w;
if (left==0)
char_w=tab_w;
else
char_w=tab_w-char_ofs%tab_w; // is right...
-
+
} else {
char_w=cache.font->get_char_size(str[j],str[j+1]).width;
}
-
+
if ( (char_ofs+char_margin)<xmargin_beg) {
char_ofs+=char_w;
continue;
}
-
+
if ( (char_ofs+char_margin+char_w)>=xmargin_end) {
if (syntax_coloring)
continue;
else
break;
}
-
+
bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column));
-
-
+
+
if (in_selection) {
//inside selection!
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color);
}
-
-
-
+
+
+ if (brace_matching_enabled) {
+ if ( (brace_open_match_line==line && brace_open_match_column==j) ||
+ (cursor.column==j && cursor.line==line && (brace_open_matching||brace_open_mismatch))) {
+
+ if (brace_open_mismatch)
+ color=cache.brace_mismatch_color;
+ cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),'_',str[j+1],in_selection?cache.font_selected_color:color);
+
+ }
+
+ if (
+ (brace_close_match_line==line && brace_close_match_column==j) ||
+ (cursor.column==j+1 && cursor.line==line && (brace_close_matching||brace_close_mismatch))) {
+
+
+ if (brace_close_mismatch)
+ color=cache.brace_mismatch_color;
+ cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),'_',str[j+1],in_selection?cache.font_selected_color:color);
+
+ }
+ }
+
+
if (str[j]>=32)
cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color);
+
else if (draw_tabs && str[j]=='\t') {
int yofs= (get_row_height() - cache.tab_icon->get_height())/2;
cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color);
}
-
-
+
+
if (cursor.column==j && cursor.line==line) {
-
+
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);
-
-
+
+
}
char_ofs+=char_w;
-
+
}
-
+
if (cursor.column==str.length() && cursor.line==line) {
-
+
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);
-
+
}
}
-
+
+
if (completion_active) {
// code completion box
Ref<StyleBox> csb = get_stylebox("completion");
@@ -658,17 +855,18 @@ void TextEdit::_notification(int p_what) {
int maxlines = get_constant("completion_lines");
int cmax_width = get_constant("completion_max_width")*cache.font->get_char_size('x').x;
Color existing = get_color("completion_existing");
+ existing.a=0.2;
int scrollw = get_constant("completion_scroll_width");
Color scrollc = get_color("completion_scroll_color");
-
-
-
+
+
+
int lines = MIN(completion_options.size(),maxlines);
int w=0;
int h=lines*get_row_height();
int nofs = cache.font->get_string_size(completion_base).width;
-
-
+
+
if (completion_options.size() < 50) {
for(int i=0;i<completion_options.size();i++) {
int w2=MIN(cache.font->get_string_size(completion_options[i]).x,cmax_width);
@@ -678,67 +876,135 @@ void TextEdit::_notification(int p_what) {
} else {
w=cmax_width;
}
-
+
int th = h + csb->get_minimum_size().y;
if (cursor_pos.y+get_row_height()+th > get_size().height) {
completion_rect.pos.y=cursor_pos.y-th;
} else {
completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y;
+
}
-
+
if (cursor_pos.x-nofs+w+scrollw > get_size().width) {
completion_rect.pos.x=get_size().width-w-scrollw;
} else {
completion_rect.pos.x=cursor_pos.x-nofs;
}
-
- completion_rect.size.width=w;
+
+ completion_rect.size.width=w+2;
completion_rect.size.height=h;
if (completion_options.size()<=maxlines)
scrollw=0;
-
+
draw_style_box(csb,Rect2(completion_rect.pos-csb->get_offset(),completion_rect.size+csb->get_minimum_size()+Size2(scrollw,0)));
-
-
+
+
int line_from = CLAMP(completion_index - lines/2, 0, completion_options.size() - lines);
draw_style_box(csel,Rect2(Point2(completion_rect.pos.x,completion_rect.pos.y+(completion_index-line_from)*get_row_height()),Size2(completion_rect.size.width,get_row_height())));
-
+
draw_rect(Rect2(completion_rect.pos,Size2(nofs,completion_rect.size.height)),existing);
-
+
+
+
+
for(int i=0;i<lines;i++) {
-
+
int l = line_from + i;
ERR_CONTINUE( l < 0 || l>= completion_options.size());
- draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],cache.font_color,completion_rect.size.width);
+ Color text_color = cache.font_color;
+ for(int j=0;j<color_regions.size();j++) {
+ if (completion_options[l].begins_with(color_regions[j].begin_key)) {
+ text_color=color_regions[j].color;
+ }
+ }
+ draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],text_color,completion_rect.size.width);
}
-
+
if (scrollw) {
//draw a small scroll rectangle to show a position in the options
float r = maxlines / (float)completion_options.size();
float o = line_from / (float)completion_options.size();
draw_rect(Rect2(completion_rect.pos.x+completion_rect.size.width,completion_rect.pos.y+o*completion_rect.size.y,scrollw,completion_rect.size.y*r),scrollc);
}
-
+
completion_line_ofs=line_from;
-
+
}
-
-
-
+
+ if (completion_hint!="") {
+
+ Ref<StyleBox> sb = get_stylebox("panel","TooltipPanel");
+ Ref<Font> font = cache.font;
+ Color font_color = get_color("font_color","TooltipLabel");
+
+
+ int max_w=0;
+ int sc = completion_hint.get_slice_count("\n");
+ int offset=0;
+ int spacing=0;
+ for(int i=0;i<sc;i++) {
+
+ String l = completion_hint.get_slice("\n",i);
+ int len = font->get_string_size(l).x;
+ max_w = MAX(len,max_w);
+ if (i==0) {
+ offset = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x;
+ } else {
+ spacing+=cache.line_spacing;
+ }
+
+
+ }
+
+
+
+ Size2 size = Size2(max_w,sc*font->get_height()+spacing);
+ Size2 minsize = size+sb->get_minimum_size();
+
+
+ if (completion_hint_offset==-0xFFFF) {
+ completion_hint_offset=cursor_pos.x-offset;
+ }
+
+
+ Point2 hint_ofs = Vector2(completion_hint_offset,cursor_pos.y-minsize.y);
+ draw_style_box(sb,Rect2(hint_ofs,minsize));
+
+ spacing=0;
+ for(int i=0;i<sc;i++) {
+ int begin=0;
+ int end=0;
+ String l = completion_hint.get_slice("\n",i);
+
+ if (l.find(String::chr(0xFFFF))!=-1) {
+ begin = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x;
+ end = font->get_string_size(l.substr(0,l.rfind(String::chr(0xFFFF)))).x;
+ }
+
+ draw_string(font,hint_ofs+sb->get_offset()+Vector2(0,font->get_ascent()+font->get_height()*i+spacing),l.replace(String::chr(0xFFFF),""),font_color);
+ if (end>0) {
+ Vector2 b = hint_ofs+sb->get_offset()+Vector2(begin,font->get_height()+font->get_height()*i+spacing-1);
+ draw_line(b,b+Vector2(end-begin,0),font_color);
+ }
+ spacing+=cache.line_spacing;
+ }
+ }
+
+
} break;
case NOTIFICATION_FOCUS_ENTER: {
-
+
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->show_virtual_keyboard(get_text(),get_global_rect());
-
+
} break;
case NOTIFICATION_FOCUS_EXIT: {
-
+
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->hide_virtual_keyboard();
-
+
} break;
-
+
}
}
@@ -750,23 +1016,23 @@ void TextEdit::_consume_pair_symbol(CharType ch) {
CharType ch_single_pair[2] = {_get_right_pair_symbol(ch), 0};
CharType ch_pair[3] = {ch, _get_right_pair_symbol(ch), 0};
- if(is_selection_active()) {
+ if(is_selection_active()) {
int new_column,new_line;
_begin_compex_operation();
_insert_text(get_selection_from_line(), get_selection_from_column(),
- ch_single,
- &new_line, &new_column);
+ ch_single,
+ &new_line, &new_column);
int to_col_offset = 0;
- if(get_selection_from_line() == get_selection_to_line())
+ if(get_selection_from_line() == get_selection_to_line())
to_col_offset = 1;
- _insert_text(get_selection_to_line(),
- get_selection_to_column() + to_col_offset,
- ch_single_pair,
- &new_line,&new_column);
+ _insert_text(get_selection_to_line(),
+ get_selection_to_column() + to_col_offset,
+ ch_single_pair,
+ &new_line,&new_column);
_end_compex_operation();
cursor_set_line(get_selection_to_line());
@@ -778,9 +1044,9 @@ void TextEdit::_consume_pair_symbol(CharType ch) {
}
if( (ch == '\'' || ch == '"') &&
- cursor_get_column() > 0 &&
- _is_text_char(text[cursor.line][cursor_get_column() - 1])
- ) {
+ cursor_get_column() > 0 &&
+ _is_text_char(text[cursor.line][cursor_get_column() - 1])
+ ) {
insert_text_at_cursor(ch_single);
cursor_set_column(cursor_position_to_move);
return;
@@ -792,9 +1058,9 @@ void TextEdit::_consume_pair_symbol(CharType ch) {
cursor_set_column(cursor_position_to_move);
return;
}
- if( _is_pair_right_symbol(ch) &&
- text[cursor.line][cursor_get_column()] == ch
- ) {
+ if( _is_pair_right_symbol(ch) &&
+ text[cursor.line][cursor_get_column()] == ch
+ ) {
cursor_set_column(cursor_position_to_move);
return;
}
@@ -830,88 +1096,89 @@ void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column
}
void TextEdit::backspace_at_cursor() {
+ if (readonly)
+ return;
if (cursor.column==0 && cursor.line==0)
return;
-
+
int prev_line = cursor.column?cursor.line:cursor.line-1;
int prev_column = cursor.column?(cursor.column-1):(text[cursor.line-1].length());
- if(auto_brace_completion_enabled &&
- cursor.column > 0 &&
- _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) {
+ if(auto_brace_completion_enabled &&
+ cursor.column > 0 &&
+ _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) {
_consume_backspace_for_pair_symbol(prev_line, prev_column);
} else {
_remove_text(prev_line,prev_column,cursor.line,cursor.column);
}
-
+
cursor_set_line(prev_line);
cursor_set_column(prev_column);
-
+
}
-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();
+void TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const {
+
+ 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>=get_visible_rows())
- return false;
+ if (row<0)
+ row=0;
- row+=cursor.line_ofs;
int col=0;
-
+
if (row>=text.size()) {
-
+
row=text.size()-1;
col=text[row].size();
} else {
-
+
col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w);
col+=cursor.x_ofs;
col=get_char_pos_for( col, get_line(row) );
}
-
+
r_row=row;
r_col=col;
- return true;
}
void TextEdit::_input_event(const InputEvent& p_input_event) {
-
+
switch(p_input_event.type) {
-
+
case InputEvent::MOUSE_BUTTON: {
-
+
const InputEventMouseButton &mb=p_input_event.mouse_button;
-
+
if (completion_active && completion_rect.has_point(Point2(mb.x,mb.y))) {
-
+
if (!mb.pressed)
return;
-
+
if (mb.button_index==BUTTON_WHEEL_UP) {
if (completion_index>0) {
completion_index--;
completion_current=completion_options[completion_index];
update();
}
-
+
}
if (mb.button_index==BUTTON_WHEEL_DOWN) {
-
+
if (completion_index<completion_options.size()-1) {
completion_index++;
completion_current=completion_options[completion_index];
update();
}
}
-
+
if (mb.button_index==BUTTON_LEFT) {
-
+
completion_index=CLAMP(completion_line_ofs+(mb.y-completion_rect.pos.y)/get_row_height(),0,completion_options.size()-1);
-
+
completion_current=completion_options[completion_index];
update();
if (mb.doubleclick)
@@ -920,8 +1187,9 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
return;
} else {
_cancel_completion();
+ _cancel_code_hint();
}
-
+
if (mb.pressed) {
if (mb.button_index==BUTTON_WHEEL_UP) {
v_scroll->set_val( v_scroll->get_val() -3 );
@@ -930,281 +1198,357 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
v_scroll->set_val( v_scroll->get_val() +3 );
}
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;
+
+
+
cursor_set_line( row );
cursor_set_column( col );
+
+ if (mb.mod.shift && (cursor.column!=prev_col || cursor.line!=prev_line)) {
- //if sel active and dblick last time < something
+ if (!selection.active) {
+ selection.active=true;
+ selection.selecting_mode=Selection::MODE_POINTER;
+ selection.from_column=prev_col;
+ selection.from_line=prev_line;
+ 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);
+ selection.shiftclick_left=false;
+ } else {
+ selection.shiftclick_left=true;
+ }
+ selection.selecting_line=prev_line;
+ selection.selecting_column=prev_col;
+ update();
+ } 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.from_column=cursor.column;
+ selection.from_line=cursor.line;
+
+ } 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;
+
+ } else {
+ selection.active=false;
+ }
+
+ update();
+ }
- //else
- selection.active=false;
- selection.selecting_mode=Selection::MODE_POINTER;
- selection.selecting_line=row;
- selection.selecting_column=col;
- if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600) {
+
+
+
+
+ } else {
+
+ //if sel active and dblick last time < something
+
+ //else
+ selection.active=false;
+ selection.selecting_mode=Selection::MODE_POINTER;
+ selection.selecting_line=row;
+ selection.selecting_column=col;
+ }
+
+
+ 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()) {
-
+
//doubleclick select world
String s = text[cursor.line];
int beg=CLAMP(cursor.column,0,s.length());
int end=beg;
-
+
if (s[beg]>32 || beg==s.length()) {
-
+
bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this
-
+
while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) {
beg--;
}
while(end<s.length() && s[end+1]>32 && (symbol==_is_symbol(s[end+1]))) {
end++;
}
-
+
if (end<s.length())
end+=1;
-
+
select(cursor.line,beg,cursor.line,end);
- }
+ selection.selecting_column=beg;
+ }
+
last_dblclk = OS::get_singleton()->get_ticks_msec();
-
+
}
-
+
update();
}
} else {
- selection.selecting_mode=Selection::MODE_NONE;
- // notify to show soft keyboard
- notification(NOTIFICATION_FOCUS_ENTER);
+ if (mb.button_index==BUTTON_LEFT)
+ click_select_held->stop();
+
+ // notify to show soft keyboard
+ notification(NOTIFICATION_FOCUS_ENTER);
}
-
+
} break;
- case InputEvent::MOUSE_MOTION: {
-
- const InputEventMouseMotion &mm=p_input_event.mouse_motion;
-
- 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) {
+ case InputEvent::MOUSE_MOTION: {
+
+ const InputEventMouseMotion &mm=p_input_event.mouse_motion;
+
+ if (mm.button_mask&BUTTON_MASK_LEFT) {
+
+ 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();
- }
-
- }
-
- } break;
-
+ click_select_held->start();
+
+ }
+
+ }
+
+ } break;
+
case InputEvent::KEY: {
-
+
InputEventKey k=p_input_event.key;
-
+
if (!k.pressed)
return;
-
+
if (completion_active) {
+ if (readonly)
+ break;
bool valid=true;
- if (k.mod.command || k.mod.alt || k.mod.meta)
+ if (k.mod.command || k.mod.meta)
valid=false;
-
+
if (valid) {
+
+ if (!k.mod.alt) {
+ if (k.scancode==KEY_UP) {
+
+ if (completion_index>0) {
+ completion_index--;
+ completion_current=completion_options[completion_index];
+ update();
+ }
+ accept_event();
+ return;
+ }
+
+
+ if (k.scancode==KEY_DOWN) {
- if (k.scancode==KEY_UP) {
+ if (completion_index<completion_options.size()-1) {
+ completion_index++;
+ completion_current=completion_options[completion_index];
+ update();
+ }
+ accept_event();
+ return;
+ }
- if (completion_index>0) {
- completion_index--;
+ if (k.scancode==KEY_PAGEUP) {
+
+ completion_index-=get_constant("completion_lines");
+ if (completion_index<0)
+ completion_index=0;
completion_current=completion_options[completion_index];
update();
+ accept_event();
+ return;
}
- accept_event();
- return;
- }
- if (k.scancode==KEY_DOWN) {
+ if (k.scancode==KEY_PAGEDOWN) {
- if (completion_index<completion_options.size()-1) {
- completion_index++;
+ completion_index+=get_constant("completion_lines");
+ if (completion_index>=completion_options.size())
+ completion_index=completion_options.size()-1;
completion_current=completion_options[completion_index];
update();
+ accept_event();
+ return;
}
- accept_event();
- return;
- }
- if (k.scancode==KEY_PAGEUP) {
+ if (k.scancode==KEY_HOME && completion_index>0) {
- completion_index-=get_constant("completion_lines");
- if (completion_index<0)
completion_index=0;
- completion_current=completion_options[completion_index];
- update();
- accept_event();
- return;
- }
-
+ completion_current=completion_options[completion_index];
+ update();
+ accept_event();
+ return;
+ }
- if (k.scancode==KEY_PAGEDOWN) {
+ if (k.scancode==KEY_END && completion_index<completion_options.size()-1) {
- completion_index+=get_constant("completion_lines");
- if (completion_index>=completion_options.size())
completion_index=completion_options.size()-1;
- completion_current=completion_options[completion_index];
- update();
- accept_event();
- return;
- }
-
- if (k.scancode==KEY_HOME) {
-
- completion_index=0;
- completion_current=completion_options[completion_index];
- update();
- accept_event();
- return;
- }
-
- if (k.scancode==KEY_END) {
-
- completion_index=completion_options.size()-1;
- completion_current=completion_options[completion_index];
- update();
- accept_event();
- return;
- }
+ completion_current=completion_options[completion_index];
+ update();
+ accept_event();
+ return;
+ }
- if (k.scancode==KEY_DOWN) {
+ if (k.scancode==KEY_DOWN) {
- if (completion_index<completion_options.size()-1) {
- completion_index++;
- completion_current=completion_options[completion_index];
- update();
+ if (completion_index<completion_options.size()-1) {
+ completion_index++;
+ completion_current=completion_options[completion_index];
+ update();
+ }
+ accept_event();
+ return;
}
- accept_event();
- return;
- }
- if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) {
+ if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) {
- _confirm_completion();
- accept_event();
- return;
- }
+ _confirm_completion();
+ accept_event();
+ return;
+ }
- if (k.scancode==KEY_BACKSPACE) {
+ if (k.scancode==KEY_BACKSPACE) {
- backspace_at_cursor();
- _update_completion_candidates();
- accept_event();
- return;
- }
+ backspace_at_cursor();
+ _update_completion_candidates();
+ accept_event();
+ return;
+ }
- if (k.scancode==KEY_SHIFT) {
- accept_event();
- return;
+ if (k.scancode==KEY_SHIFT) {
+ accept_event();
+ return;
+ }
}
-
+
if (k.unicode>32) {
-
+
if (cursor.column<text[cursor.line].length() && text[cursor.line][cursor.column]==k.unicode) {
//same char, move ahead
cursor_set_column(cursor.column+1);
} else {
//different char, go back
- const CharType chr[2] = {k.unicode, 0};
+ const CharType chr[2] = {(CharType)k.unicode, 0};
if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
_consume_pair_symbol(chr[0]);
} else {
_insert_text_at_cursor(chr);
}
}
-
+
_update_completion_candidates();
accept_event();
-
+
return;
}
}
-
+
_cancel_completion();
+
}
-
+
/* TEST CONTROL FIRST!! */
-
+
// some remaps for duplicate functions..
if (k.mod.command && !k.mod.shift && !k.mod.alt && !k.mod.meta && k.scancode==KEY_INSERT) {
-
+
k.scancode=KEY_C;
}
if (!k.mod.command && k.mod.shift && !k.mod.alt && !k.mod.meta && k.scancode==KEY_INSERT) {
-
+
k.scancode=KEY_V;
k.mod.command=true;
- k.mod.shift=false;
+ k.mod.shift=false;
}
-
+
// stuff to do when selection is active..
-
+
if (selection.active) {
+ if (readonly)
+ break;
+
bool clear=false;
bool unselect=false;
bool dobreak=false;
-
+
switch(k.scancode) {
-
+
case KEY_TAB: {
-
+
String txt = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
String prev_txt=txt;
-
+
if (k.mod.shift) {
-
+
for(int i=0;i<txt.length();i++) {
- if (((i>0 && txt[i-1]=='\n') || (i==0 && selection.from_column==0)) && (txt[i]=='\t' || txt[i]==' ')) {
+ if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/)) && (txt[i]=='\t' || txt[i]==' ')) {
txt.remove(i);
//i--;
}
}
} else {
-
+
for(int i=0;i<txt.length();i++) {
-
- if (((i>0 && txt[i-1]=='\n') || (i==0 && selection.from_column==0))) {
+
+ if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/))) {
txt=txt.insert(i,"\t");
//i--;
}
}
}
-
+
if (txt!=prev_txt) {
-
+
int sel_line=selection.from_line;
int sel_column=selection.from_column;
-
+
cursor_set_line(selection.from_line);
cursor_set_column(selection.from_column);
_begin_compex_operation();
@@ -1218,10 +1562,10 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
selection.to_line=cursor.line;
update();
}
-
+
dobreak=true;
accept_event();
-
+
} break;
case KEY_X:
case KEY_C:
@@ -1232,7 +1576,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
case KEY_BACKSPACE:
accept_event();
clear=true; dobreak=true;
- break;
+ break;
case KEY_LEFT:
case KEY_RIGHT:
case KEY_UP:
@@ -1241,24 +1585,26 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
case KEY_PAGEDOWN:
case KEY_HOME:
case KEY_END:
- if (k.mod.shift) // if selecting ignore
+ // ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys)
+ if (k.mod.command || k.mod.shift || k.mod.alt)
break;
unselect=true;
break;
+
default:
if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta)
clear=true;
if (auto_brace_completion_enabled && _is_pair_left_symbol(k.unicode))
clear=false;
}
-
+
if (unselect) {
selection.active=false;
selection.selecting_mode=Selection::MODE_NONE;
update();
}
if (clear) {
-
+
selection.active=false;
update();
_remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
@@ -1269,20 +1615,23 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (dobreak)
break;
}
-
- selection.selecting_test=false;
-
+
+ selection.selecting_text=false;
+
bool scancode_handled=true;
-
+
// special scancode test...
switch (k.scancode) {
-
+
case KEY_ENTER:
case KEY_RETURN: {
- String ins="\n";
+ if (readonly)
+ break;
+ String ins="\n";
+
//keep indentation
for(int i=0;i<text[cursor.line].length();i++) {
if (text[cursor.line][i]=='\t')
@@ -1290,26 +1639,40 @@ 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();
-
+
+ } break;
+ case KEY_ESCAPE: {
+ if (completion_hint!="") {
+ completion_hint="";
+ update();
+
+ }
} break;
case KEY_TAB: {
-
+
if (readonly)
break;
-
+
if (selection.active) {
-
-
+
+
} else {
if (k.mod.shift) {
-
+
int cc = cursor.column;
if (cc>0 && cc<=text[cursor.line].length() && text[cursor.line][cursor.column-1]=='\t') {
//simple unindent
-
+
backspace_at_cursor();
}
} else {
@@ -1317,45 +1680,100 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
_insert_text_at_cursor("\t");
}
}
-
+
} break;
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_LEFT: {
-
+
if (k.mod.shift)
_pre_shift_selection();
-
+
#ifdef APPLE_STYLE_KEYS
if (k.mod.command) {
cursor_set_column(0);
} else if (k.mod.alt) {
-
+
#else
- if (k.mod.command) {
+ if (k.mod.alt) {
+ scancode_handled=false;
+ break;
+ } else if (k.mod.command) {
#endif
bool prev_char=false;
int cc=cursor.column;
while (cc>0) {
-
+
bool ischar=_is_text_char(text[cursor.line][cc-1]);
-
+
if (prev_char && !ischar)
break;
-
+
prev_char=ischar;
cc--;
-
+
}
-
+
cursor_set_column(cc);
-
+
} else if (cursor.column==0) {
-
+
if (cursor.line>0) {
cursor_set_line(cursor.line-1);
cursor_set_column(text[cursor.line].length());
@@ -1363,39 +1781,42 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
} else {
cursor_set_column(cursor_get_column()-1);
}
-
+
if (k.mod.shift)
_post_shift_selection();
-
+
} break;
case KEY_RIGHT: {
-
+
if (k.mod.shift)
_pre_shift_selection();
-
+
#ifdef APPLE_STYLE_KEYS
if (k.mod.command) {
cursor_set_column(text[cursor.line].length());
} else if (k.mod.alt) {
#else
- if (k.mod.command) {
+ if (k.mod.alt) {
+ scancode_handled=false;
+ break;
+ } else if (k.mod.command) {
#endif
bool prev_char=false;
int cc=cursor.column;
while (cc<text[cursor.line].length()) {
-
+
bool ischar=_is_text_char(text[cursor.line][cc]);
-
+
if (prev_char && !ischar)
break;
prev_char=ischar;
cc++;
}
-
+
cursor_set_column(cc);
-
+
} else if (cursor.column==text[cursor.line].length()) {
-
+
if (cursor.line<text.size()-1) {
cursor_set_line(cursor.line+1);
cursor_set_column(0);
@@ -1403,87 +1824,148 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
} else {
cursor_set_column(cursor_get_column()+1);
}
-
+
if (k.mod.shift)
_post_shift_selection();
-
+
} break;
case KEY_UP: {
-
+
if (k.mod.shift)
_pre_shift_selection();
-
+ if (k.mod.alt) {
+ scancode_handled=false;
+ break;
+ }
#ifdef APPLE_STYLE_KEYS
if (k.mod.command)
cursor_set_line(0);
else
#endif
cursor_set_line(cursor_get_line()-1);
-
+
if (k.mod.shift)
_post_shift_selection();
-
+ _cancel_code_hint();
+
} break;
case KEY_DOWN: {
-
+
if (k.mod.shift)
_pre_shift_selection();
-
+ if (k.mod.alt) {
+ scancode_handled=false;
+ break;
+ }
#ifdef APPLE_STYLE_KEYS
if (k.mod.command)
cursor_set_line(text.size()-1);
else
#endif
cursor_set_line(cursor_get_line()+1);
-
+
if (k.mod.shift)
_post_shift_selection();
-
+ _cancel_code_hint();
+
} break;
-
+
case KEY_DELETE: {
-
+
if (readonly)
break;
int curline_len = text[cursor.line].length();
-
+
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;
- int next_line = cursor.column<curline_len?cursor.line:cursor.line+1;
- int next_column = cursor.column<curline_len?(cursor.column+1):0;
- _remove_text(cursor.line,cursor.column,next_line,next_column);
- update();
- } break;
#ifdef APPLE_STYLE_KEYS
- case KEY_HOME: {
+ 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;
- if (k.mod.shift)
- _pre_shift_selection();
+ bool prev_char=false;
+ bool only_whitespace=true;
- cursor_set_line(0);
+ while (only_whitespace && line < last_line) {
- if (k.mod.shift)
- _post_shift_selection();
+ while (column<text[line].length()) {
+ CharType c=text[line][column];
- } break;
- case KEY_END: {
+ if (c != '\t' && c != ' ') {
+ only_whitespace=false;
+ break;
+ }
- if (k.mod.shift)
- _pre_shift_selection();
+ column++;
+ }
- cursor_set_line(text.size()-1);
+ if (only_whitespace) {
+ line++;
+ column=0;
+ }
+ }
- if (k.mod.shift)
- _post_shift_selection();
+ while (column<text[line].length()) {
- } break;
+ bool ischar=_is_text_char(text[line][column]);
-#else
- case KEY_HOME: {
+ 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;
+#ifdef APPLE_STYLE_KEYS
+ case KEY_HOME: {
+
+
+ if (k.mod.shift)
+ _pre_shift_selection();
+
+ cursor_set_line(0);
+
+ if (k.mod.shift)
+ _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: {
+
+
if (k.mod.shift)
_pre_shift_selection();
@@ -1503,177 +1985,239 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (k.mod.command)
cursor_set_line(0);
-
+
if (k.mod.shift)
_post_shift_selection();
-
+ _cancel_completion();
+ completion_hint="";
+
} break;
case KEY_END: {
-
+
if (k.mod.shift)
_pre_shift_selection();
-
+
if (k.mod.command)
cursor_set_line(text.size()-1);
cursor_set_column(text[cursor.line].length());
-
+
if (k.mod.shift)
_post_shift_selection();
+ _cancel_completion();
+ completion_hint="";
+
} break;
#endif
case KEY_PAGEUP: {
-
+
if (k.mod.shift)
_pre_shift_selection();
-
+
cursor_set_line(cursor_get_line()-get_visible_rows());
-
+
if (k.mod.shift)
_post_shift_selection();
+ _cancel_completion();
+ completion_hint="";
+
+
} break;
case KEY_PAGEDOWN: {
-
+
if (k.mod.shift)
_pre_shift_selection();
-
+
cursor_set_line(cursor_get_line()+get_visible_rows());
-
+
if (k.mod.shift)
_post_shift_selection();
+ _cancel_completion();
+ completion_hint="";
+
+
} break;
case KEY_A: {
-
+
if (!k.mod.command || k.mod.shift || k.mod.alt) {
scancode_handled=false;
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].size();
- selection.selecting_mode=Selection::MODE_NONE;
- update();
-
+
+ select_all();
+
} break;
case KEY_X: {
-
+
if (!k.mod.command || k.mod.shift || k.mod.alt) {
scancode_handled=false;
break;
}
-
- if (!selection.active)
- break;
-
- String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
- OS::get_singleton()->set_clipboard(clipboard);
-
- cursor_set_line(selection.from_line);
- cursor_set_column(selection.from_column);
-
- _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
- selection.active=false;
- selection.selecting_mode=Selection::MODE_NONE;
- update();
-
+
+ if (!selection.active){
+
+ String clipboard = text[cursor.line];
+ OS::get_singleton()->set_clipboard(clipboard);
+ cursor_set_line(cursor.line);
+ cursor_set_column(0);
+ _remove_text(cursor.line,0,cursor.line,text[cursor.line].length());
+
+ backspace_at_cursor();
+ update();
+ cursor_set_line(cursor.line+1);
+ cut_copy_line = true;
+
+ }
+ else
+ {
+
+ String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
+ OS::get_singleton()->set_clipboard(clipboard);
+
+ cursor_set_line(selection.from_line);
+ cursor_set_column(selection.from_column);
+
+ _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
+ selection.active=false;
+ selection.selecting_mode=Selection::MODE_NONE;
+ update();
+ cut_copy_line = false;
+ }
+
} break;
case KEY_C: {
-
+
if (!k.mod.command || k.mod.shift || k.mod.alt) {
- scancode_handled=false;
- break;
- }
-
- if (!selection.active)
+ scancode_handled=false;
break;
-
- String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
- OS::get_singleton()->set_clipboard(clipboard);
+ }
+
+ if (!selection.active){
+ String clipboard = _base_get_text(cursor.line,0,cursor.line,text[cursor.line].length());
+ OS::get_singleton()->set_clipboard(clipboard);
+ cut_copy_line = true;
+ }
+ else{
+ String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
+ OS::get_singleton()->set_clipboard(clipboard);
+ cut_copy_line = false;
+ }
} break;
case KEY_Z: {
-
- if (!k.mod.command) {
- scancode_handled=false;
- break;
- }
-
- if (k.mod.shift)
- redo();
- else
- undo();
+
+ if (!k.mod.command) {
+ scancode_handled=false;
+ break;
+ }
+
+ if (k.mod.shift)
+ redo();
+ else
+ undo();
} break;
case KEY_V: {
-
+
if (!k.mod.command || k.mod.shift || k.mod.alt) {
- scancode_handled=false;
- break;
+ scancode_handled=false;
+ break;
}
-
+
String clipboard = OS::get_singleton()->get_clipboard();
-
+
if (selection.active) {
selection.active=false;
_remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
cursor_set_line(selection.from_line);
cursor_set_column(selection.from_column);
-
+
}
-
+ else if (cut_copy_line)
+ {
+ cursor_set_column(0);
+ String ins="\n";
+ clipboard += ins;
+ }
+
_insert_text_at_cursor(clipboard);
-
+
update();
} break;
case KEY_SPACE: {
+#ifdef OSX_ENABLED
+ if (completion_enabled && k.mod.meta) { //cmd-space is spotlight shortcut in OSX
+#else
if (completion_enabled && k.mod.command) {
-
+#endif
+
query_code_comple();
scancode_handled=true;
} else {
scancode_handled=false;
}
-
+
} break;
-
+
+ case KEY_U:{
+ if (!k.mod.command || k.mod.shift) {
+ scancode_handled=false;
+ break;
+ }
+ else {
+ if (selection.active) {
+ int ini = selection.from_line;
+ int end = selection.to_line;
+ for (int i=ini; i<= end; i++)
+ {
+ if (text[i][0] == '#')
+ _remove_text(i,0,i,1);
+ }
+ }
+ else{
+ if (text[cursor.line][0] == '#')
+ _remove_text(cursor.line,0,cursor.line,1);
+ }
+ update();
+ }
+ break;}
+
default: {
-
+
scancode_handled=false;
} break;
-
+
}
-
+
if (scancode_handled)
accept_event();
-
- if (!scancode_handled && !k.mod.command && !k.mod.alt) {
-
- if (k.unicode>=32) {
-
- if (readonly)
- break;
-
- accept_event();
- } else {
-
- break;
- }
- }
-
- if (!scancode_handled && !k.mod.command && !k.mod.alt) {
+ /*
+ if (!scancode_handled && !k.mod.command && !k.mod.alt) {
+
+ if (k.unicode>=32) {
+
+ if (readonly)
+ break;
+ accept_event();
+ } else {
+
+ break;
+ }
+ }
+*/
+ if (!scancode_handled && !k.mod.command) { //for german kbds
+
if (k.unicode>=32) {
-
+
if (readonly)
break;
- const CharType chr[2] = {k.unicode, 0};
+ 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 {
@@ -1682,177 +2226,168 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
accept_event();
} else {
-
+
break;
}
}
-
- if (!selection.selecting_test) {
-
- selection.selecting_mode=Selection::MODE_NONE;
- }
-
return;
} break;
-
+
}
-
+
}
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() {
-
-
+
+
if (selection.active && selection.selecting_mode==Selection::MODE_SHIFT) {
-
+
select(selection.selecting_line,selection.selecting_column,cursor.line,cursor.column);
update();
}
-
-
- selection.selecting_test=true;
+
+
+ selection.selecting_text=true;
}
/**** TEXT EDIT CORE API ****/
void TextEdit::_base_insert_text(int p_line, int p_char,const String& p_text,int &r_end_line,int &r_end_column) {
-
+
//save for undo...
ERR_FAIL_INDEX(p_line,text.size());
ERR_FAIL_COND(p_char<0);
-
+
/* STEP 1 add spaces if the char is greater than the end of the line */
while(p_char>text[p_line].length()) {
-
+
text.set(p_line,text[p_line]+String::chr(' '));
}
-
+
/* STEP 2 separate dest string in pre and post text */
-
+
String preinsert_text = text[p_line].substr(0,p_char);
String postinsert_text = text[p_line].substr(p_char,text[p_line].size());
-
+
/* STEP 3 remove \r from source text and separate in substrings */
-
+
//buh bye \r and split
Vector<String> substrings = p_text.replace("\r","").split("\n");
-
-
+
+
for(int i=0;i<substrings.size();i++) {
//insert the substrings
-
+
if (i==0) {
-
+
text.set(p_line,preinsert_text+substrings[i]);
} else {
-
+
text.insert(p_line+i,substrings[i]);
}
-
+
if (i==substrings.size()-1){
-
+
text.set(p_line+i,text[p_line+i]+postinsert_text);
}
}
-
+
r_end_line=p_line+substrings.size()-1;
r_end_column=text[r_end_line].length()-postinsert_text.length();
-
+
if (!text_changed_dirty && !setting_text) {
-
- if (is_inside_scene())
+ if (is_inside_tree())
MessageQueue::get_singleton()->push_call(this,"_text_changed_emit");
text_changed_dirty=true;
}
-
+
}
String TextEdit::_base_get_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) const {
-
+
ERR_FAIL_INDEX_V(p_from_line,text.size(),String());
ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,String());
ERR_FAIL_INDEX_V(p_to_line,text.size(),String());
ERR_FAIL_INDEX_V(p_to_column,text[p_to_line].length()+1,String());
ERR_FAIL_COND_V(p_to_line < p_from_line ,String()); // from > to
ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column<p_from_column,String()); // from > to
-
+
String ret;
-
+
for(int i=p_from_line;i<=p_to_line;i++) {
-
+
int begin = (i==p_from_line)?p_from_column:0;
int end = (i==p_to_line)?p_to_column:text[i].length();
-
+
if (i>p_from_line)
ret+="\n";
ret+=text[i].substr(begin,end-begin);
}
-
+
return ret;
}
void TextEdit::_base_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) {
-
+
ERR_FAIL_INDEX(p_from_line,text.size());
ERR_FAIL_INDEX(p_from_column,text[p_from_line].length()+1);
ERR_FAIL_INDEX(p_to_line,text.size());
ERR_FAIL_INDEX(p_to_column,text[p_to_line].length()+1);
ERR_FAIL_COND(p_to_line < p_from_line ); // from > to
ERR_FAIL_COND(p_to_line == p_from_line && p_to_column<p_from_column); // from > to
-
-
+
+
String pre_text = text[p_from_line].substr(0,p_from_column);
String post_text = text[p_to_line].substr(p_to_column,text[p_to_line].length());
-
+
for(int i=p_from_line;i<p_to_line;i++) {
-
+
text.remove(p_from_line+1);
}
-
+
text.set(p_from_line,pre_text+post_text);
-
+
if (!text_changed_dirty && !setting_text) {
-
- if (is_inside_scene())
+ if (is_inside_tree())
MessageQueue::get_singleton()->push_call(this,"_text_changed_emit");
text_changed_dirty=true;
}
}
-
-
void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_end_line,int *r_end_column) {
-
+
if (!setting_text)
idle_detect->start();
-
+
if (undo_enabled) {
_clear_redo();
}
-
+
int retline,retchar;
_base_insert_text(p_line,p_char,p_text,retline,retchar);
if (r_end_line)
*r_end_line=retline;
if (r_end_column)
*r_end_column=retchar;
-
+
if (!undo_enabled)
return;
-
+
/* UNDO!! */
TextOperation op;
op.type=TextOperation::TYPE_INSERT;
@@ -1864,12 +2399,12 @@ void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_e
op.version=++version;
op.chain_forward=false;
op.chain_backward=false;
-
+
//see if it shold just be set as current op
if (current_op.type!=op.type) {
_push_current_op();
current_op=op;
-
+
return; //set as current op, return
}
//see if it can be merged
@@ -1879,30 +2414,30 @@ void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_e
return; //set as current op, return
}
//merge current op
-
+
current_op.text+=p_text;
current_op.to_column=retchar;
current_op.to_line=retline;
current_op.version=op.version;
-
+
}
void TextEdit::_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) {
-
+
if (!setting_text)
idle_detect->start();
-
+
String text;
if (undo_enabled) {
_clear_redo();
text=_base_get_text(p_from_line,p_from_column,p_to_line,p_to_column);
}
-
+
_base_remove_text(p_from_line,p_from_column,p_to_line,p_to_column);
-
+
if (!undo_enabled)
return;
-
+
/* UNDO!! */
TextOperation op;
op.type=TextOperation::TYPE_REMOVE;
@@ -1914,7 +2449,7 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column,int p_to_line,int
op.version=++version;
op.chain_forward=false;
op.chain_backward=false;
-
+
//see if it shold just be set as current op
if (current_op.type!=op.type) {
_push_current_op();
@@ -1930,26 +2465,26 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column,int p_to_line,int
return; //update current op
}
if (current_op.from_line==p_from_line && current_op.from_column==p_from_column) {
-
+
//current_op.text=text+current_op.text;
//current_op.from_line=p_from_line;
//current_op.from_column=p_from_column;
//return; //update current op
}
-
+
_push_current_op();
current_op=op;
-
+
}
void TextEdit::_insert_text_at_cursor(const String& p_text) {
-
+
int new_column,new_line;
_insert_text(cursor.line,cursor.column,p_text,&new_line,&new_column);
cursor_set_line(new_line);
cursor_set_column(new_column);
-
+
update();
}
@@ -1957,145 +2492,144 @@ void TextEdit::_insert_text_at_cursor(const String& p_text) {
int TextEdit::get_char_count() {
-
+
int totalsize=0;
-
+
for (int i=0;i<text.size();i++) {
-
+
if (i>0)
totalsize++; // incliude \n
totalsize+=text[i].length();
}
-
+
return totalsize; // omit last \n
}
Size2 TextEdit::get_minimum_size() {
-
+
return cache.style_normal->get_minimum_size();
}
int TextEdit::get_visible_rows() const {
-
+
int total=cache.size.height;
total-=cache.style_normal->get_minimum_size().height;
total/=get_row_height();
return total;
}
void TextEdit::adjust_viewport_to_cursor() {
-
+
if (cursor.line_ofs>cursor.line)
cursor.line_ofs=cursor.line;
-
+
int visible_width=cache.size.width-cache.style_normal->get_minimum_size().width-cache.line_number_w;
if (v_scroll->is_visible())
visible_width-=v_scroll->get_combined_minimum_size().width;
visible_width-=20; // give it a little more space
-
-
+
+
//printf("rowofs %i, visrows %i, cursor.line %i\n",cursor.line_ofs,get_visible_rows(),cursor.line);
-
+
int visible_rows = get_visible_rows();
if (h_scroll->is_visible())
visible_rows-=((h_scroll->get_combined_minimum_size().height-1)/get_row_height());
-
+
if (cursor.line>=(cursor.line_ofs+visible_rows))
cursor.line_ofs=cursor.line-visible_rows+1;
if (cursor.line<cursor.line_ofs)
cursor.line_ofs=cursor.line;
-
+
int cursor_x = get_column_x_offset( cursor.column, text[cursor.line] );
-
+
if (cursor_x>(cursor.x_ofs+visible_width))
cursor.x_ofs=cursor_x-visible_width+1;
-
+
if (cursor_x < cursor.x_ofs)
cursor.x_ofs=cursor_x;
-
+
update();
-/*
- get_range()->set_max(text.size());
-
- get_range()->set_page(get_visible_rows());
-
- get_range()->set((int)cursor.line_ofs);
+ /*
+ get_range()->set_max(text.size());
+
+ get_range()->set_page(get_visible_rows());
+
+ get_range()->set((int)cursor.line_ofs);
*/
-
-
+
+
}
-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;
-
+
cursor.column=p_col;
if (cursor.column > get_line( cursor.line ).length())
cursor.column=get_line( cursor.line ).length();
-
+
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_scene())
+ if (is_inside_tree())
MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit");
cursor_changed_dirty=true;
}
-
+
}
-void TextEdit::cursor_set_line(int p_row) {
-
+void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport) {
+
if (setting_row)
return;
-
+
setting_row=true;
if (p_row<0)
p_row=0;
-
-
+
+
if (p_row>=(int)text.size())
p_row=(int)text.size()-1;
-
+
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;
-
-
+
+
if (!cursor_changed_dirty) {
-
- if (is_inside_scene())
+ if (is_inside_tree())
MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit");
cursor_changed_dirty=true;
}
-
+
}
int TextEdit::cursor_get_column() const {
-
+
return cursor.column;
}
int TextEdit::cursor_get_line() const {
-
+
return cursor.line;
}
void TextEdit::_scroll_moved(double p_to_val) {
-
+
if (updating_scrolls)
return;
-
+
if (h_scroll->is_visible())
cursor.x_ofs=h_scroll->get_val();
if (v_scroll->is_visible())
@@ -2108,87 +2642,87 @@ void TextEdit::_scroll_moved(double p_to_val) {
int TextEdit::get_row_height() const {
-
+
return cache.font->get_height()+cache.line_spacing;
}
int TextEdit::get_char_pos_for(int p_px,String p_str) const {
-
+
int px=0;
int c=0;
-
+
int tab_w = cache.font->get_char_size(' ').width*tab_size;
-
+
while (c<p_str.length()) {
-
+
int w=0;
-
+
if (p_str[c]=='\t') {
-
+
int left = px%tab_w;
if (left==0)
w=tab_w;
else
w=tab_w-px%tab_w; // is right...
-
+
} else {
-
+
w=cache.font->get_char_size(p_str[c],p_str[c+1]).width;
}
-
+
if (p_px<(px+w/2))
break;
px+=w;
c++;
}
-
+
return c;
}
int TextEdit::get_column_x_offset(int p_char,String p_str) {
-
+
int px=0;
-
+
int tab_w = cache.font->get_char_size(' ').width*tab_size;
-
+
for (int i=0;i<p_char;i++) {
-
+
if (i>=p_str.length())
break;
-
+
if (p_str[i]=='\t') {
-
+
int left = px%tab_w;
if (left==0)
px+=tab_w;
else
px+=tab_w-px%tab_w; // is right...
-
+
} else {
px+=cache.font->get_char_size(p_str[i],p_str[i+1]).width;
}
}
-
+
return px;
-
+
}
void TextEdit::insert_text_at_cursor(const String& p_text) {
-
+
if (selection.active) {
-
+
cursor_set_line(selection.from_line);
cursor_set_column(selection.from_column);
-
+
_remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
selection.active=false;
selection.selecting_mode=Selection::MODE_NONE;
-
+
}
-
+
_insert_text_at_cursor(p_text);
update();
-
+
}
Control::CursorShape TextEdit::get_cursor_shape(const Point2& p_pos) const {
@@ -2200,11 +2734,11 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2& p_pos) const {
void TextEdit::set_text(String p_text){
-
+
setting_text=true;
- _clear();
+ clear();
_insert_text_at_cursor(p_text);
-
+ clear_undo_history();
cursor.column=0;
cursor.line=0;
cursor.x_ofs=0;
@@ -2214,7 +2748,7 @@ void TextEdit::set_text(String p_text){
cursor_set_column(0);
update();
setting_text=false;
-
+
//get_range()->set(0);
};
@@ -2222,29 +2756,53 @@ String TextEdit::get_text() {
String longthing;
int len = text.size();
for (int i=0;i<len;i++) {
-
-
+
+
longthing+=text[i];
if (i!=len-1)
longthing+="\n";
}
-
+
return longthing;
+
+};
+String TextEdit::get_text_for_completion() {
+
+ String longthing;
+ int len = text.size();
+ for (int i=0;i<len;i++) {
+
+ if (i==cursor.line) {
+ longthing+=text[i].substr(0,cursor.column);
+ longthing+=String::chr(0xFFFF); //not unicode, represents the cursor
+ longthing+=text[i].substr(cursor.column,text[i].size());
+ } else {
+
+ longthing+=text[i];
+ }
+
+
+ if (i!=len-1)
+ longthing+="\n";
+ }
+
+ return longthing;
+
};
String TextEdit::get_line(int line) const {
-
+
if (line<0 || line>=text.size())
return "";
-
+
return text[line];
-
+
};
void TextEdit::_clear() {
-
+
clear_undo_history();
text.clear();
cursor.column=0;
@@ -2257,31 +2815,31 @@ void TextEdit::_clear() {
void TextEdit::clear() {
-
+
setting_text=true;
_clear();
setting_text=false;
-
+
};
void TextEdit::set_readonly(bool p_readonly) {
-
-
+
+
readonly=p_readonly;
}
void TextEdit::set_wrap(bool p_wrap) {
-
+
wrap=p_wrap;
}
void TextEdit::set_max_chars(int p_max_chars) {
-
+
max_chars=p_max_chars;
}
void TextEdit::_update_caches() {
-
+
cache.style_normal=get_stylebox("normal");
cache.style_focus=get_stylebox("focus");
cache.font=get_font("font");
@@ -2292,16 +2850,17 @@ void TextEdit::_update_caches() {
cache.mark_color=get_color("mark_color");
cache.current_line_color=get_color("current_line_color");
cache.breakpoint_color=get_color("breakpoint_color");
+ cache.brace_mismatch_color=get_color("brace_mismatch_color");
cache.line_spacing=get_constant("line_spacing");
cache.row_height = cache.font->get_height() + cache.line_spacing;
cache.tab_icon=get_icon("tab");
text.set_font(cache.font);
-
+
}
void TextEdit::clear_colors() {
-
+
keywords.clear();
color_regions.clear();;
text.clear_caches();
@@ -2309,20 +2868,20 @@ void TextEdit::clear_colors() {
}
void TextEdit::set_custom_bg_color(const Color& p_color) {
-
+
custom_bg_color=p_color;
update();
}
void TextEdit::add_keyword_color(const String& p_keyword,const Color& p_color) {
-
+
keywords[p_keyword]=p_color;
update();
-
+
}
void TextEdit::add_color_region(const String& p_begin_key,const String& p_end_key,const Color &p_color,bool p_line_only) {
-
+
color_regions.push_back(ColorRegion(p_begin_key,p_end_key,p_color,p_line_only));
text.clear_caches();
update();
@@ -2330,168 +2889,190 @@ void TextEdit::add_color_region(const String& p_begin_key,const String& p_end_ke
}
void TextEdit::set_symbol_color(const Color& p_color) {
-
+
symbol_color=p_color;
update();
}
void TextEdit::set_syntax_coloring(bool p_enabled) {
-
+
syntax_coloring=p_enabled;
update();
}
bool TextEdit::is_syntax_coloring_enabled() const {
-
+
return syntax_coloring;
}
-void TextEdit::cut() {
+void TextEdit::set_auto_indent(bool p_auto_indent) {
+ auto_indent = p_auto_indent;
+}
+void TextEdit::cut() {
+
if (!selection.active)
return;
-
+
String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
OS::get_singleton()->set_clipboard(clipboard);
-
+
cursor_set_line(selection.from_line);
cursor_set_column(selection.from_column);
-
+
_remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
selection.active=false;
selection.selecting_mode=Selection::MODE_NONE;
update();
-
+
}
void TextEdit::copy() {
-
+
if (!selection.active)
return;
+
+ print_line("from line: "+itos(selection.from_line));
+ print_line("from column: "+itos(selection.from_column));
+ print_line("to line: "+itos(selection.to_line));
+ print_line("to column: "+itos(selection.to_column));
String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
OS::get_singleton()->set_clipboard(clipboard);
-
+
}
void TextEdit::paste() {
-
+
if (selection.active) {
-
+
cursor_set_line(selection.from_line);
cursor_set_column(selection.from_column);
-
+
_remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
selection.active=false;
selection.selecting_mode=Selection::MODE_NONE;
-
+
}
-
+
String clipboard = OS::get_singleton()->get_clipboard();
_insert_text_at_cursor(clipboard);
update();
-
+
}
void TextEdit::select_all() {
-
+
if (text.size()==1 && text[0].length()==0)
return;
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].size();
- selection.selecting_mode=Selection::MODE_NONE;
+ selection.to_column=text[selection.to_line].length();
+ 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();
-
+
}
void TextEdit::deselect() {
-
+
selection.active=false;
update();
}
void TextEdit::select(int p_from_line,int p_from_column,int p_to_line,int p_to_column) {
-
+
if (p_from_line>=text.size())
p_from_line=text.size()-1;
if (p_from_column>=text[p_from_line].length())
p_from_column=text[p_from_line].length();
-
+
if (p_to_line>=text.size())
p_to_line=text.size()-1;
if (p_to_column>=text[p_to_line].length())
p_to_column=text[p_to_line].length();
-
+
selection.from_line=p_from_line;
selection.from_column=p_from_column;
selection.to_line=p_to_line;
selection.to_column=p_to_column;
-
+
selection.active=true;
-
+
if (selection.from_line==selection.to_line) {
-
+
if (selection.from_column==selection.to_column) {
-
+
selection.active=false;
-
+
} 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;
+ }
+
+
update();
}
bool TextEdit::is_selection_active() const {
-
+
return selection.active;
}
int TextEdit::get_selection_from_line() const {
-
+
ERR_FAIL_COND_V(!selection.active,-1);
return selection.from_line;
-
+
}
int TextEdit::get_selection_from_column() const {
-
+
ERR_FAIL_COND_V(!selection.active,-1);
return selection.from_column;
-
+
}
int TextEdit::get_selection_to_line() const {
-
+
ERR_FAIL_COND_V(!selection.active,-1);
return selection.to_line;
-
+
}
int TextEdit::get_selection_to_column() const {
-
+
ERR_FAIL_COND_V(!selection.active,-1);
return selection.to_column;
-
+
}
String TextEdit::get_selection_text() const {
-
+
if (!selection.active)
return "";
-
+
return _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column);
-
+
}
String TextEdit::get_word_under_cursor() const {
-
+
int prev_cc = cursor.column;
while(prev_cc >0) {
bool is_char = _is_text_char(text[cursor.line][prev_cc-1]);
@@ -2499,7 +3080,7 @@ String TextEdit::get_word_under_cursor() const {
break;
--prev_cc;
}
-
+
int next_cc = cursor.column;
while(next_cc<text[cursor.line].length()) {
bool is_char = _is_text_char(text[cursor.line][next_cc]);
@@ -2513,7 +3094,7 @@ String TextEdit::get_word_under_cursor() const {
}
DVector<int> TextEdit::_search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const {
-
+
int col,line;
if (search(p_key,p_search_flags,p_from_line,p_from_column,col,line)) {
DVector<int> result;
@@ -2521,45 +3102,78 @@ DVector<int> TextEdit::_search_bind(const String &p_key,uint32_t p_search_flags,
result.set(0,line);
result.set(1,col);
return result;
-
+
} else {
-
+
return DVector<int>();
}
}
bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_line, int p_from_column,int &r_line,int &r_column) const {
-
+
if (p_key.length()==0)
return false;
ERR_FAIL_INDEX_V(p_from_line,text.size(),false);
ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,false);
-
+
//search through the whole documment, but start by current line
-
+
int line=-1;
int pos=-1;
-
+
+ line=p_from_line;
+
for(int i=0;i<text.size()+1;i++) {
//backwards is broken...
- int idx=(p_search_flags&SEARCH_BACKWARDS)?(text.size()-i):i; //do backwards seearch
- line = (idx+p_from_line)%text.size();
-
+ //int idx=(p_search_flags&SEARCH_BACKWARDS)?(text.size()-i):i; //do backwards seearch
+
+
+ if (line<0) {
+ line=text.size()-1;
+ }
+ if (line==text.size()) {
+ line=0;
+ }
+
String text_line = text[line];
- int from_column=(idx==0)?p_from_column:0;
- if (idx==text.size()) {
- text_line=text_line.substr(0,p_from_column); //wrap around for missing begining.
+ int from_column=0;
+ if (line==p_from_line) {
+
+ if (i==text.size()) {
+ //wrapped
+
+ if (p_search_flags&SEARCH_BACKWARDS) {
+ text_line=text_line.substr(from_column,text_line.length());
+ from_column=text_line.length();
+ } else {
+ text_line=text_line.substr(0,from_column);
+ from_column=0;
+ }
+
+ } else {
+
+ from_column=p_from_column;
+ }
+
+
+ } else {
+ //text_line=text_line.substr(0,p_from_column); //wrap around for missing begining.
+ if (p_search_flags&SEARCH_BACKWARDS)
+ from_column=text_line.length()-1;
+ else
+ from_column=0;
}
-
+
pos=-1;
-
+
if (!(p_search_flags&SEARCH_BACKWARDS)) {
+
pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,from_column):text_line.findn(p_key,from_column);
} else {
-
+
pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.rfind(p_key,from_column):text_line.rfindn(p_key,from_column);
}
-
+
if (pos!=-1 && (p_search_flags&SEARCH_WHOLE_WORDS)) {
//validate for whole words
if (pos>0 && _is_text_char(text_line[pos-1]))
@@ -2567,61 +3181,66 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li
else if (_is_text_char(text_line[pos+p_key.length()]))
pos=-1;
}
-
+
if (pos!=-1)
break;
-
+
+ if (p_search_flags&SEARCH_BACKWARDS)
+ line--;
+ else
+ line++;
+
}
-
+
if (pos==-1) {
r_line=-1;
r_column=-1;
return false;
}
-
+
r_line=line;
r_column=pos;
-
-
+
+
return true;
}
void TextEdit::_cursor_changed_emit() {
-
+
emit_signal("cursor_changed");
cursor_changed_dirty=false;
}
void TextEdit::_text_changed_emit() {
-
+
emit_signal("text_changed");
text_changed_dirty=false;
}
void TextEdit::set_line_as_marked(int p_line,bool p_marked) {
-
+
ERR_FAIL_INDEX(p_line,text.size());
text.set_marked(p_line,p_marked);
update();
}
bool TextEdit::is_line_set_as_breakpoint(int p_line) const {
-
+
ERR_FAIL_INDEX_V(p_line,text.size(),false);
return text.is_breakpoint(p_line);
-
+
}
void TextEdit::set_line_as_breakpoint(int p_line,bool p_breakpoint) {
-
-
+
+
ERR_FAIL_INDEX(p_line,text.size());
text.set_breakpoint(p_line,p_breakpoint);
update();
}
void TextEdit::get_breakpoints(List<int> *p_breakpoints) const {
-
+
for(int i=0;i<text.size();i++) {
if (text.is_breakpoint(i))
p_breakpoints->push_back(i);
@@ -2629,39 +3248,39 @@ void TextEdit::get_breakpoints(List<int> *p_breakpoints) const {
}
int TextEdit::get_line_count() const {
-
+
return text.size();
}
void TextEdit::_do_text_op(const TextOperation& p_op, bool p_reverse) {
-
+
ERR_FAIL_COND(p_op.type==TextOperation::TYPE_NONE);
-
+
bool insert = p_op.type==TextOperation::TYPE_INSERT;
if (p_reverse)
insert=!insert;
-
+
if (insert) {
-
+
int check_line;
int check_column;
_base_insert_text(p_op.from_line,p_op.from_column,p_op.text,check_line,check_column);
ERR_FAIL_COND( check_line != p_op.to_line ); // BUG
ERR_FAIL_COND( check_column != p_op.to_column ); // BUG
} else {
-
+
_base_remove_text(p_op.from_line,p_op.from_column,p_op.to_line,p_op.to_column);
}
-
+
}
void TextEdit::_clear_redo() {
-
+
if (undo_stack_pos==NULL)
return; //nothing to clear
-
+
_push_current_op();
-
+
while (undo_stack_pos) {
List<TextOperation>::Element *elem = undo_stack_pos;
undo_stack_pos=undo_stack_pos->next();
@@ -2673,19 +3292,19 @@ void TextEdit::_clear_redo() {
void TextEdit::undo() {
_push_current_op();
-
+
if (undo_stack_pos==NULL) {
-
+
if (!undo_stack.size())
return; //nothing to undo
-
+
undo_stack_pos=undo_stack.back();
-
+
} else if (undo_stack_pos==undo_stack.front())
return; // at the bottom of the undo stack
else
undo_stack_pos=undo_stack_pos->prev();
-
+
_do_text_op( undo_stack_pos->get(),true);
if(undo_stack_pos->get().chain_backward) {
do {
@@ -2693,19 +3312,19 @@ void TextEdit::undo() {
_do_text_op(undo_stack_pos->get(), true);
} while(!undo_stack_pos->get().chain_forward);
}
-
+
cursor_set_line(undo_stack_pos->get().from_line);
cursor_set_column(undo_stack_pos->get().from_column);
update();
}
void TextEdit::redo() {
-
+
_push_current_op();
-
+
if (undo_stack_pos==NULL)
return; //nothing to do.
-
+
_do_text_op(undo_stack_pos->get(), false);
if(undo_stack_pos->get().chain_forward) {
do {
@@ -2720,12 +3339,12 @@ void TextEdit::redo() {
}
void TextEdit::clear_undo_history() {
-
+
saved_version=0;
current_op.type=TextOperation::TYPE_NONE;
undo_stack_pos=NULL;
undo_stack.clear();
-
+
}
void TextEdit::_begin_compex_operation() {
@@ -2764,12 +3383,12 @@ void TextEdit::_push_current_op() {
}
void TextEdit::set_draw_tabs(bool p_draw) {
-
+
draw_tabs=p_draw;
}
bool TextEdit::is_drawing_tabs() const{
-
+
return draw_tabs;
}
@@ -2777,35 +3396,35 @@ uint32_t TextEdit::get_version() const {
return current_op.version;
}
uint32_t TextEdit::get_saved_version() const {
-
+
return saved_version;
}
void TextEdit::tag_saved_version() {
-
+
saved_version=get_version();
}
int TextEdit::get_v_scroll() const {
-
+
return v_scroll->get_val();
}
void TextEdit::set_v_scroll(int p_scroll) {
-
+
v_scroll->set_val(p_scroll);
cursor.line_ofs=p_scroll;
}
int TextEdit::get_h_scroll() const {
-
+
return h_scroll->get_val();
}
void TextEdit::set_h_scroll(int p_scroll) {
-
+
h_scroll->set_val(p_scroll);
}
void TextEdit::set_completion(bool p_enabled,const Vector<String>& p_prefixes) {
-
+
completion_prefixes.clear();
completion_enabled=p_enabled;
for(int i=0;i<p_prefixes.size();i++)
@@ -2813,7 +3432,7 @@ void TextEdit::set_completion(bool p_enabled,const Vector<String>& p_prefixes) {
}
void TextEdit::_confirm_completion() {
-
+
String remaining=completion_current.substr(completion_base.length(),completion_current.length()-completion_base.length());
String l = text[cursor.line];
bool same=true;
@@ -2825,44 +3444,112 @@ void TextEdit::_confirm_completion() {
break;
}
}
-
+
if (same)
cursor_set_column(cursor.column+remaining.length());
- else
+ else {
insert_text_at_cursor(remaining);
-
+ if (remaining.ends_with("(") && auto_brace_completion_enabled) {
+ insert_text_at_cursor(")");
+ cursor.column--;
+ }
+ }
+
_cancel_completion();
}
-void TextEdit::_cancel_completion() {
+void TextEdit::_cancel_code_hint() {
+ completion_hint="";
+ update();
+}
+
+void TextEdit::_cancel_completion() {
+
if (!completion_active)
return;
-
+
completion_active=false;
update();
+
+}
+static bool _is_completable(CharType c) {
+
+ return !_is_symbol(c) || c=='"' || c=='\'';
}
-void TextEdit::_update_completion_candidates() {
+void TextEdit::_update_completion_candidates() {
+
String l = text[cursor.line];
int cofs = CLAMP(cursor.column,0,l.length());
-
+
+
String s;
- while(cofs>0 && l[cofs-1]>32 && !_is_symbol(l[cofs-1])) {
- s=String::chr(l[cofs-1])+s;
- cofs--;
+
+ //look for keywords first
+
+ 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--;
}
- update();
+ 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]==' ')
+ kofs--;
+
+ while(kofs>=0 && l[kofs]>32 && _is_completable(l[kofs])) {
+ kw=String::chr(l[kofs])+kw;
+ kofs--;
+ }
+
+ pre_keyword=keywords.has(kw);
+ //print_line("KW "+kw+"? "+itos(pre_keyword));
+
+ } else {
+
+
+ while(cofs>0 && l[cofs-1]>32 && _is_completable(l[cofs-1])) {
+ s=String::chr(l[cofs-1])+s;
+ if (l[cofs-1]=='\'' || l[cofs-1]=='"')
+ break;
- if (s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) {
+ cofs--;
+ }
+ }
+
+
+ update();
+
+ if (cancel || (!pre_keyword && s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1]))))) {
//none to complete, cancel
_cancel_completion();
return;
}
-
+
completion_options.clear();
completion_index=0;
completion_base=s;
@@ -2875,7 +3562,7 @@ void TextEdit::_update_completion_candidates() {
if (max<ci_match)
continue;
for(int j=0;j<max;j++) {
-
+
if (j>=completion_strings[i].length())
break;
if (completion_current[j]!=completion_strings[i][j])
@@ -2886,181 +3573,194 @@ void TextEdit::_update_completion_candidates() {
ci_match=m;
completion_index=completion_options.size()-1;
}
-
+
}
}
-
-
-
+
+
+
if (completion_options.size()==0) {
//no options to complete, cancel
_cancel_completion();
return;
-
+
}
-
+
completion_current=completion_options[completion_index];
-
+
#if 0 // even there's only one option, user still get the chance to choose using it or not
if (completion_options.size()==1) {
//one option to complete, just complete it automagically
_confirm_completion();
-// insert_text_at_cursor(completion_options[0].substr(s.length(),completion_options[0].length()-s.length()));
+ // insert_text_at_cursor(completion_options[0].substr(s.length(),completion_options[0].length()-s.length()));
_cancel_completion();
return;
-
+
}
#endif
if (completion_options.size()==1 && s==completion_options[0])
_cancel_completion();
-
+
completion_enabled=true;
+}
-}
-
void TextEdit::query_code_comple() {
-
+
String l = text[cursor.line];
int ofs = CLAMP(cursor.column,0,l.length());
- String cs;
- while(ofs>0 && l[ofs-1]>32) {
-
- if (_is_symbol(l[ofs-1])) {
- String s;
- while(ofs>0 && l[ofs-1]>32 && _is_symbol(l[ofs-1])) {
- s=String::chr(l[ofs-1])+s;
- ofs--;
- }
- if (completion_prefixes.has(s))
- cs=s+cs;
- else
- break;
- } else {
-
- cs=String::chr(l[ofs-1])+cs;
- ofs--;
- }
+
+ bool inquote=false;
+ int c=ofs-1;
+ while(c>=0) {
+ if (l[c]=='"' || l[c]=='\'')
+ inquote=!inquote;
+ c--;
}
- if (cs!="") {
- emit_signal("request_completion",cs,cursor.line);
+ if (ofs>0 && (inquote || _is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1]))))
+ emit_signal("request_completion");
+
+}
- }
+void TextEdit::set_code_hint(const String& p_hint) {
+
+ completion_hint=p_hint;
+ completion_hint_offset=-0xFFFF;
+ update();
}
void TextEdit::code_complete(const Vector<String> &p_strings) {
-
-
+
+
completion_strings=p_strings;
completion_active=true;
completion_current="";
completion_index=0;
_update_completion_candidates();
-//
+ //
}
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);
int beg=CLAMP(col,0,s.length());
int end=beg;
-
-
+
+
if (s[beg]>32 || beg==s.length()) {
-
+
bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this
-
+
while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) {
beg--;
}
while(end<s.length() && s[end+1]>32 && (symbol==_is_symbol(s[end+1]))) {
end++;
}
-
+
if (end<s.length())
end+=1;
-
+
String tt = tooltip_obj->call(tooltip_func,s.substr(beg,end-beg),tooltip_ud);
-
+
return tt;
-
+
}
-
+
return Control::get_tooltip(p_pos);
-
+
}
void TextEdit::set_tooltip_request_func(Object *p_obj, const StringName& p_function,const Variant& p_udata) {
-
+
tooltip_obj=p_obj;
tooltip_func=p_function;
tooltip_ud=p_udata;
}
+void TextEdit::set_line(int line, String new_text)
+{
+ if (line < 0 || line > text.size())
+ return;
+ _remove_text(line, 0, line, text[line].length());
+ _insert_text(line, 0, new_text);
+ if (cursor.line==line) {
+ cursor.column=MIN(cursor.column,new_text.length());
+ }
+}
-void TextEdit::set_show_line_numbers(bool p_show) {
+void TextEdit::insert_at(const String &p_text, int at)
+{
+ cursor_set_column(0);
+ cursor_set_line(at);
+ _insert_text(at, 0, p_text+"\n");
+}
+void TextEdit::set_show_line_numbers(bool p_show) {
+
line_numbers=p_show;
update();
}
+bool TextEdit::is_text_field() const {
+ return true;
+}
void TextEdit::_bind_methods() {
-
-
+
+
ObjectTypeDB::bind_method(_MD("_input_event"),&TextEdit::_input_event);
ObjectTypeDB::bind_method(_MD("_scroll_moved"),&TextEdit::_scroll_moved);
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 );
BIND_CONSTANT( SEARCH_BACKWARDS );
-
-/*
- ObjectTypeDB::bind_method(_MD("delete_char"),&TextEdit::delete_char);
- ObjectTypeDB::bind_method(_MD("delete_line"),&TextEdit::delete_line);
+
+ /*
+ ObjectTypeDB::bind_method(_MD("delete_char"),&TextEdit::delete_char);
+ ObjectTypeDB::bind_method(_MD("delete_line"),&TextEdit::delete_line);
*/
-
+
ObjectTypeDB::bind_method(_MD("set_text","text"),&TextEdit::set_text);
ObjectTypeDB::bind_method(_MD("insert_text_at_cursor","text"),&TextEdit::insert_text_at_cursor);
-
+
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("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_get_column"),&TextEdit::cursor_get_column);
ObjectTypeDB::bind_method(_MD("cursor_get_line"),&TextEdit::cursor_get_line);
-
-
+
+
ObjectTypeDB::bind_method(_MD("set_readonly","enable"),&TextEdit::set_readonly);
ObjectTypeDB::bind_method(_MD("set_wrap","enable"),&TextEdit::set_wrap);
ObjectTypeDB::bind_method(_MD("set_max_chars","amount"),&TextEdit::set_max_chars);
-
+
ObjectTypeDB::bind_method(_MD("cut"),&TextEdit::cut);
ObjectTypeDB::bind_method(_MD("copy"),&TextEdit::copy);
ObjectTypeDB::bind_method(_MD("paste"),&TextEdit::paste);
ObjectTypeDB::bind_method(_MD("select_all"),&TextEdit::select_all);
ObjectTypeDB::bind_method(_MD("select","from_line","from_column","to_line","to_column"),&TextEdit::select);
-
+
ObjectTypeDB::bind_method(_MD("is_selection_active"),&TextEdit::is_selection_active);
ObjectTypeDB::bind_method(_MD("get_selection_from_line"),&TextEdit::get_selection_from_line);
ObjectTypeDB::bind_method(_MD("get_selection_from_column"),&TextEdit::get_selection_from_column);
@@ -3069,30 +3769,30 @@ void TextEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_selection_text"),&TextEdit::get_selection_text);
ObjectTypeDB::bind_method(_MD("get_word_under_cursor"),&TextEdit::get_word_under_cursor);
ObjectTypeDB::bind_method(_MD("search","flags","from_line","from_column","to_line","to_column"),&TextEdit::_search_bind);
-
+
ObjectTypeDB::bind_method(_MD("undo"),&TextEdit::undo);
ObjectTypeDB::bind_method(_MD("redo"),&TextEdit::redo);
ObjectTypeDB::bind_method(_MD("clear_undo_history"),&TextEdit::clear_undo_history);
ObjectTypeDB::bind_method(_MD("set_syntax_coloring","enable"),&TextEdit::set_syntax_coloring);
ObjectTypeDB::bind_method(_MD("is_syntax_coloring_enabled"),&TextEdit::is_syntax_coloring_enabled);
-
+
ObjectTypeDB::bind_method(_MD("add_keyword_color","keyword","color"),&TextEdit::add_keyword_color);
ObjectTypeDB::bind_method(_MD("add_color_region","begin_key","end_key","color","line_only"),&TextEdit::add_color_region,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("set_symbol_color","color"),&TextEdit::set_symbol_color);
ObjectTypeDB::bind_method(_MD("set_custom_bg_color","color"),&TextEdit::set_custom_bg_color);
ObjectTypeDB::bind_method(_MD("clear_colors"),&TextEdit::clear_colors);
-
-
+
+
ADD_SIGNAL(MethodInfo("cursor_changed"));
ADD_SIGNAL(MethodInfo("text_changed"));
- ADD_SIGNAL(MethodInfo("request_completion",PropertyInfo(Variant::STRING,"keyword"),PropertyInfo(Variant::INT,"line")));
-
+ ADD_SIGNAL(MethodInfo("request_completion"));
+
}
TextEdit::TextEdit() {
-
+
readonly=false;
setting_row=false;
draw_tabs=false;
@@ -3102,35 +3802,39 @@ TextEdit::TextEdit() {
set_focus_mode(FOCUS_ALL);
_update_caches();
cache.size=Size2(1,1);
+ cache.row_height=1;
+ cache.line_spacing=1;
+ cache.line_number_w=1;
+
tab_size=4;
text.set_tab_size(tab_size);
text.clear();
-// text.insert(1,"Mongolia..");
-// text.insert(2,"PAIS GENEROSO!!");
+ // text.insert(1,"Mongolia..");
+ // text.insert(2,"PAIS GENEROSO!!");
text.set_color_regions(&color_regions);
-
+
h_scroll = memnew( HScrollBar );
v_scroll = memnew( VScrollBar );
-
+
add_child(h_scroll);
add_child(v_scroll);
-
+
updating_scrolls=false;
selection.active=false;
-
+
h_scroll->connect("value_changed", this,"_scroll_moved");
v_scroll->connect("value_changed", this,"_scroll_moved");
-
+
cursor_changed_dirty=false;
text_changed_dirty=false;
-
+
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;
-
+
custom_bg_color=Color(0,0,0,0);
idle_detect = memnew( Timer );
add_child(idle_detect);
@@ -3138,6 +3842,11 @@ TextEdit::TextEdit() {
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;
keywords["void"]=Color(0.3,0.0,0.1);
@@ -3147,15 +3856,15 @@ TextEdit::TextEdit() {
keywords["extends"]=Color(0.3,0.0,0.1);
keywords["constructor"]=Color(0.3,0.0,0.1);
symbol_color=Color(0.1,0.0,0.3,1.0);
-
+
color_regions.push_back(ColorRegion("/*","*/",Color(0.4,0.6,0,4)));
color_regions.push_back(ColorRegion("//","",Color(0.6,0.6,0.4)));
color_regions.push_back(ColorRegion("\"","\"",Color(0.4,0.7,0.7)));
color_regions.push_back(ColorRegion("'","'",Color(0.4,0.8,0.8)));
color_regions.push_back(ColorRegion("#","",Color(0.2,1.0,0.2)));
-
+
#endif
-
+
current_op.type=TextOperation::TYPE_NONE;
undo_enabled=true;
undo_stack_pos=NULL;
@@ -3164,7 +3873,7 @@ TextEdit::TextEdit() {
current_op.version=0;
version=0;
saved_version=0;
-
+
completion_enabled=false;
completion_active=false;
completion_line_ofs=0;
@@ -3172,9 +3881,10 @@ TextEdit::TextEdit() {
line_numbers=false;
next_operation_is_complex=false;
auto_brace_completion_enabled=false;
+ brace_matching_enabled=false;
+ auto_indent=false;
}
-TextEdit::~TextEdit(){
+TextEdit::~TextEdit()
+{
}
-
-
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 7700bfd4d3..f8e8ef3b9a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -55,7 +55,7 @@ class TextEdit : public Control {
Mode selecting_mode;
int selecting_line,selecting_column;
- bool selecting_test;
+ bool selecting_text;
bool active;
@@ -63,6 +63,7 @@ class TextEdit : public Control {
int from_line,from_column;
int to_line,to_column;
+ bool shiftclick_left;
} selection;
@@ -79,6 +80,7 @@ class TextEdit : public Control {
Color mark_color;
Color breakpoint_color;
Color current_line_color;
+ Color brace_mismatch_color;
int row_height;
int line_spacing;
@@ -138,7 +140,7 @@ class TextEdit : public Control {
int size() const { return text.size(); }
void clear();
void clear_caches();
- _FORCE_INLINE_ const String& operator[](int p_line) const { return text[p_line].data; }
+ _FORCE_INLINE_ const String& operator[](int p_line) const { return text[p_line].data; }
Text() { tab_size=4; }
};
@@ -162,7 +164,7 @@ class TextEdit : public Control {
TextOperation current_op;
List<TextOperation> undo_stack;
- List<TextOperation>::Element *undo_stack_pos;
+ List<TextOperation>::Element *undo_stack_pos;
void _clear_redo();
void _do_text_op(const TextOperation& p_op, bool p_reverse);
@@ -185,6 +187,8 @@ class TextEdit : public Control {
int completion_index;
Rect2i completion_rect;
int completion_line_ofs;
+ String completion_hint;
+ int completion_hint_offset;
bool setting_text;
@@ -208,10 +212,14 @@ class TextEdit : public Control {
bool line_numbers;
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;
@@ -233,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();
@@ -260,10 +269,11 @@ class TextEdit : public Control {
void _clear();
void _cancel_completion();
+ void _cancel_code_hint();
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:
@@ -298,6 +308,7 @@ public:
void set_text(String p_text);
void insert_text_at_cursor(const String& p_text);
+ void insert_at(const String& p_text, int at);
int get_line_count() const;
void set_line_as_marked(int p_line,bool p_marked);
void set_line_as_breakpoint(int p_line,bool p_breakpoint);
@@ -305,14 +316,20 @@ public:
void get_breakpoints(List<int> *p_breakpoints) const;
String get_text();
String get_line(int line) const;
+ void set_line(int line, String new_text);
void backspace_at_cursor();
inline void set_auto_brace_completion(bool p_enabled) {
auto_brace_completion_enabled = p_enabled;
}
-
- void cursor_set_column(int p_col);
- void cursor_set_line(int p_row);
+ inline void set_brace_matching(bool p_enabled) {
+ brace_matching_enabled=p_enabled;
+ update();
+ }
+ void set_auto_indent(bool p_auto_indent);
+
+ 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;
@@ -336,7 +353,7 @@ public:
bool is_selection_active() const;
int get_selection_from_line() const;
- int get_selection_from_column() const;
+ int get_selection_from_column() const;
int get_selection_to_line() const;
int get_selection_to_column() const;
String get_selection_text() const;
@@ -373,10 +390,14 @@ public:
void set_tooltip_request_func(Object *p_obj, const StringName& p_function, const Variant& p_udata);
- void set_completion(bool p_enabled,const Vector<String>& p_prefixes);
+ void set_completion(bool p_enabled,const Vector<String>& p_prefixes);
void code_complete(const Vector<String> &p_strings);
+ void set_code_hint(const String& p_hint);
void query_code_comple();
+ 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 7954ac65df..5b2caecb5b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,28 +31,37 @@
Size2 TextureButton::get_minimum_size() const {
+ Size2 rscale;
if (normal.is_null()) {
if (pressed.is_null()) {
if (hover.is_null())
if (click_mask.is_null())
- return Size2();
+ rscale= Size2();
else
- return click_mask->get_size();
+ rscale= click_mask->get_size();
else
- return hover->get_size();
+ rscale= hover->get_size();
} else
- return pressed->get_size();
+ rscale= pressed->get_size()*scale;
} else
- return normal->get_size();
+ rscale= normal->get_size();
+
+ return rscale*scale;
}
bool TextureButton::has_point(const Point2& p_point) const {
+ if (scale[0] <= 0 || scale[1] <= 0) {
+ return false;
+ }
+
+ Point2 ppos = p_point/scale;
+
if (click_mask.is_valid()) {
- Point2i p =p_point;
+ Point2i p =ppos;
if (p.x<0 || p.x>=click_mask->get_size().width || p.y<0 || p.y>=click_mask->get_size().height)
return false;
@@ -71,46 +80,57 @@ void TextureButton::_notification(int p_what) {
DrawMode draw_mode = get_draw_mode();
// if (normal.is_null())
// break;
+
+ Ref<Texture> texdraw;
+
switch (draw_mode) {
case DRAW_NORMAL: {
if (normal.is_valid())
- normal->draw(canvas_item,Point2());
+ texdraw=normal;
} break;
case DRAW_PRESSED: {
if (pressed.is_null()) {
if (hover.is_null()) {
if (normal.is_valid())
- normal->draw(canvas_item,Point2());
+ texdraw=normal;
} else
- hover->draw(canvas_item,Point2());
+ texdraw=hover;
} else
- pressed->draw(canvas_item,Point2());
+ texdraw=pressed;
} break;
case DRAW_HOVER: {
if (hover.is_null()) {
if (pressed.is_valid() && is_pressed())
- pressed->draw(canvas_item,Point2());
+ texdraw=pressed;
else if (normal.is_valid())
- normal->draw(canvas_item,Point2());
+ texdraw=normal;
} else
- hover->draw(canvas_item,Point2());
+ texdraw=hover;
} break;
case DRAW_DISABLED: {
if (disabled.is_null()) {
if (normal.is_valid())
- normal->draw(canvas_item,Point2());
+ texdraw=normal;
} else
- disabled->draw(canvas_item,Point2());
+ texdraw=disabled;
} break;
}
+
+ if (texdraw.is_valid()) {
+ Rect2 drect(Point2(),texdraw->get_size()*scale);
+ draw_texture_rect(texdraw,drect,false,modulate);
+
+ }
if (has_focus() && focused.is_valid()) {
- focused->draw(canvas_item, Point2());
+ Rect2 drect(Point2(),focused->get_size()*scale);
+ draw_texture_rect(focused,drect,false,modulate);
+
};
} break;
@@ -125,6 +145,8 @@ 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_modulate","color"),&TextureButton::set_modulate);
ObjectTypeDB::bind_method(_MD("get_normal_texture:Texture"),&TextureButton::get_normal_texture);
ObjectTypeDB::bind_method(_MD("get_pressed_texture:Texture"),&TextureButton::get_pressed_texture);
@@ -132,13 +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);
-
- 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")) ;
+ ObjectTypeDB::bind_method(_MD("get_scale"),&TextureButton::get_scale);
+ ObjectTypeDB::bind_method(_MD("get_modulate"),&TextureButton::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_scale"), _SCS("get_scale"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::COLOR,"params/modulate"), _SCS("set_modulate"), _SCS("get_modulate"));
}
@@ -206,6 +232,29 @@ void TextureButton::set_focused_texture(const Ref<Texture>& p_focused) {
focused = p_focused;
};
+void TextureButton::set_scale(Size2 p_scale) {
+
+ scale=p_scale;
+ minimum_size_changed();
+ update();
+}
+
+Size2 TextureButton::get_scale() const{
+
+ return scale;
+}
+
+void TextureButton::set_modulate(const Color& p_modulate) {
+ modulate=p_modulate;
+ update();
+}
+
+Color TextureButton::get_modulate() const {
+ return modulate;
+}
+
TextureButton::TextureButton() {
+ scale=Size2(1.0, 1.0);
+ modulate=Color(1,1,1);
}
diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h
index d186966cb1..01924c1c15 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -41,6 +41,8 @@ class TextureButton : public BaseButton {
Ref<Texture> disabled;
Ref<Texture> focused;
Ref<BitMap> click_mask;
+ Size2 scale;
+ Color modulate;
protected:
@@ -66,6 +68,11 @@ 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_modulate(const Color& p_modulate);
+ Color get_modulate() const;
TextureButton();
};
diff --git a/scene/gui/texture_frame.cpp b/scene/gui/texture_frame.cpp
index 26f4d32965..5a6bc86638 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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") );
}
@@ -88,8 +88,8 @@ void TextureFrame::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
+ //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();
}
diff --git a/scene/gui/texture_frame.h b/scene/gui/texture_frame.h
index 9f75e1c2c0..0ccbf5a591 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index 0ce7df5d20..c8930add6e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 93a0d1046c..7187fd5f07 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 e0ba30a202..d5bcb73476 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/tool_button.h b/scene/gui/tool_button.h
index 9b1664c3fb..648d776b51 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index fb85f0c6b7..ee7c0724e3 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
@@ -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;
@@ -1438,8 +1485,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
if (p_button==BUTTON_LEFT) {
/* process selection */
- if (p_doubleclick && (!c.editable || c.mode==TreeItem::CELL_MODE_CUSTOM || c.mode==TreeItem::CELL_MODE_ICON)) {
-
+ if (p_doubleclick && (!c.editable || c.mode==TreeItem::CELL_MODE_CUSTOM || c.mode==TreeItem::CELL_MODE_ICON || c.mode==TreeItem::CELL_MODE_CHECK)) {
emit_signal("item_activated");
return -1;
@@ -1468,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 );
@@ -1479,8 +1525,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
//}
update();
}
-
-
+
+
}
}
@@ -1491,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;
@@ -1500,20 +1546,20 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
case TreeItem::CELL_MODE_STRING: {
//nothing in particular
- if (select_mode==SELECT_MULTI && (get_scene()->get_last_event_id() == focus_in_id || !already_cursor)) {
+ if (select_mode==SELECT_MULTI && (get_tree()->get_last_event_id() == focus_in_id || !already_cursor)) {
bring_up_editor=false;
}
} 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);
}
@@ -1528,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);
}
@@ -1541,45 +1587,61 @@ 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 ) );
bring_up_value_editor=false;
- if (select_mode==SELECT_MULTI && get_scene()->get_last_event_id() == focus_in_id)
+ if (select_mode==SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id)
bring_up_editor=false;
- }
+ }
}
click_handled=true;
@@ -1590,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;
@@ -1606,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 */
@@ -1694,12 +1739,19 @@ void Tree::text_editor_enter(String p_text) {
case TreeItem::CELL_MODE_RANGE: {
c.val=p_text.to_double();
+ if (c.step>0)
+ c.val=Math::stepify(c.val,c.step);
+ if (c.val<c.min)
+ c.val=c.min;
+ else if (c.val>c.max)
+ c.val=c.max;
+
//popup_edited_item->edited_signal.call( popup_edited_item_col );
} break;
default: { ERR_FAIL(); }
}
- item_edited(popup_edited_item_col,popup_edited_item);
+ item_edited(popup_edited_item_col,popup_edited_item);
update();
}
@@ -1727,19 +1779,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)
@@ -2021,6 +2073,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();
@@ -2028,7 +2082,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) {
@@ -2056,6 +2109,33 @@ 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) {
@@ -2066,18 +2146,45 @@ 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 {
+ text_editor->set_pos(pressing_item_rect.pos);
+ text_editor->set_size(pressing_item_rect.size);
+
+ text_editor->clear();
+ text_editor->set_text( pressing_for_editor_text );
+ text_editor->select_all();
+
+ text_editor->show_modal();
+ text_editor->grab_focus();
+
+ }
+ pressing_for_editor=false;
+
+ }
+
+
+
if (cache.click_type==Cache::CLICK_BUTTON) {
emit_signal("button_pressed",cache.click_item,cache.click_column,cache.click_id);
@@ -2110,7 +2217,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) {
@@ -2139,11 +2246,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) {
@@ -2168,18 +2279,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;
}
-
+
}
@@ -2212,9 +2326,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;
@@ -2228,7 +2345,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);
}
@@ -2277,10 +2394,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;
}
@@ -2299,39 +2416,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();
- }
+ }
}
@@ -2344,7 +2461,7 @@ void Tree::_notification(int p_what) {
if (p_what==NOTIFICATION_FOCUS_ENTER) {
- focus_in_id=get_scene()->get_last_event_id();
+ focus_in_id=get_tree()->get_last_event_id();
}
if (p_what==NOTIFICATION_MOUSE_EXIT) {
@@ -2354,7 +2471,12 @@ void Tree::_notification(int p_what) {
}
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ drag_touching=false;
+ }
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
update_cache();;
}
@@ -2405,16 +2527,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();
@@ -2432,7 +2554,7 @@ void Tree::_notification(int p_what) {
draw_size.y-=tbh;
if (root) {
-
+
draw_item( Point2(),draw_ofs,draw_size,root);
@@ -2443,10 +2565,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) {
@@ -2466,6 +2588,10 @@ void Tree::_notification(int p_what) {
}
}
+ if (p_what==NOTIFICATION_THEME_CHANGED) {
+ update_cache();
+ }
+
}
@@ -2542,7 +2668,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");
@@ -2550,14 +2676,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;
@@ -2573,16 +2699,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() {
@@ -2600,6 +2726,8 @@ void Tree::clear() {
selected_item=NULL;
edited_item=NULL;
popup_edited_item=NULL;
+ selected_item=NULL;
+ pressing_for_editor=false;
update();
};
@@ -2610,15 +2738,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;
@@ -2628,8 +2756,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();
}
@@ -2644,78 +2772,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 {
@@ -2726,30 +2854,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)
@@ -2759,17 +2887,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;
}
@@ -2787,7 +2915,7 @@ int Tree::get_item_offset(TreeItem *p_item) const {
ofs+=compute_item_height(it)+cache.vseparation;
- if (it->childs) {
+ if (it->childs && !it->collapsed) {
it=it->childs;
@@ -2812,7 +2940,7 @@ int Tree::get_item_offset(TreeItem *p_item) const {
void Tree::ensure_cursor_is_visible() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
TreeItem *selected = get_selected();
@@ -3009,20 +3137,23 @@ TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_co
String Tree::get_tooltip(const Point2& p_pos) const {
if (root) {
+
Point2 pos=p_pos;
pos -= cache.bg->get_offset();
pos.y-=_get_title_button_height();
if (pos.y<0)
return Control::get_tooltip(p_pos);
- pos.x+=h_scroll->get_val();
- pos.y+=v_scroll->get_val();
+ if (h_scroll->is_visible())
+ pos.x+=h_scroll->get_val();
+ if (v_scroll->is_visible())
+ pos.y+=v_scroll->get_val();
int col,h;
TreeItem *it = _find_item_at_pos(root,pos,col,h);
- if (it) {
+ if (it) {
String ret;
if (it->get_tooltip(col)=="")
@@ -3046,9 +3177,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,7 +3214,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);
@@ -3087,6 +3229,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"));
@@ -3111,7 +3256,7 @@ Tree::Tree() {
edited_item=NULL;
selected_col=-1;
edited_col=-1;
-
+
hide_root=false;
select_mode=SELECT_SINGLE;
root=0;
@@ -3119,8 +3264,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);
@@ -3136,10 +3281,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");
@@ -3171,6 +3320,10 @@ Tree::Tree() {
drag_speed=0;
drag_touching=false;
drag_touching_deaccel=false;
+ pressing_for_editor=false;
+ range_drag_enabled=false;
+
+ hide_folding=false;
}
@@ -3180,6 +3333,6 @@ Tree::~Tree() {
if (root) {
memdelete( root );
}
-
+
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 3ffbececb2..55ccc16d01 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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();
@@ -454,6 +473,13 @@ public:
void set_cursor_can_exit_tree(bool p_enable);
bool can_cursor_exit_tree() const;
+ 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 e3bb50a9af..d99da5e906 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,15 +27,97 @@
/* 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) {
switch (p_notification) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
//set_idle_process(false); //don't annoy
- if (stream.is_valid() && autoplay && !get_scene()->is_editor_hint())
+ if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint())
play();
} break;
@@ -45,20 +127,25 @@ void VideoPlayer::_notification(int p_notification) {
return;
if (paused)
return;
+ if (!playback->is_playing())
+ return;
- while (stream->get_pending_frame_count()) {
+ 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;
- Image img = stream->pop_frame();
- if (texture->get_width() == 0) {
- texture->create(img.get_width(),img.get_height(),img.get_format(),Texture::FLAG_VIDEO_SURFACE|Texture::FLAG_FILTER);
- update();
- minimum_size_changed();
- } else {
- if (stream->get_pending_frame_count() == 0)
- texture->set_data(img);
- };
- };
+ playback->update(delta);
+
+ /*int prev_width = texture->get_width();
+ stream->pop_frame(texture);
+ if (prev_width == 0) {
+ update();
+ minimum_size_changed();
+ };*/
} break;
@@ -79,6 +166,9 @@ void VideoPlayer::_notification(int p_notification) {
};
+
+
+
Size2 VideoPlayer::get_minimum_size() const {
if (!expand && !texture.is_null())
@@ -104,20 +194,33 @@ void VideoPlayer::set_stream(const Ref<VideoStream> &p_stream) {
stop();
- if (stream_rid.is_valid())
- AudioServer::get_singleton()->free(stream_rid);
- stream_rid=RID();
-
- texture = Ref<ImageTexture>(memnew(ImageTexture));
-
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_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 {
@@ -127,40 +230,44 @@ Ref<VideoStream> VideoPlayer::get_stream() const {
void VideoPlayer::play() {
- ERR_FAIL_COND(!is_inside_scene());
- if (stream.is_null())
+ ERR_FAIL_COND(!is_inside_tree());
+ 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);
- set_process(true);
+ last_audio_time=0;
};
void VideoPlayer::stop() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
- if (stream.is_null())
+ if (playback.is_null())
return;
+ playback->stop();
AudioServer::get_singleton()->stream_set_active(stream_rid,false);
- stream->stop();
+ 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);
};
};
@@ -168,13 +275,31 @@ void VideoPlayer::set_paused(bool p_paused) {
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) {
volume=p_vol;
- if (stream_rid.is_valid())
- AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
};
float VideoPlayer::get_volume() const {
@@ -206,13 +331,14 @@ String VideoPlayer::get_stream_name() const {
return stream->get_name();
};
-float VideoPlayer::get_pos() 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();
};
+
void VideoPlayer::set_autoplay(bool p_enable) {
autoplay=p_enable;
@@ -242,9 +368,12 @@ 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_pos"),&VideoPlayer::get_pos);
+ ObjectTypeDB::bind_method(_MD("get_stream_pos"),&VideoPlayer::get_stream_pos);
ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&VideoPlayer::set_autoplay);
ObjectTypeDB::bind_method(_MD("has_autoplay"),&VideoPlayer::has_autoplay);
@@ -252,8 +381,11 @@ 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);
- ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"), _SCS("get_stream") );
+ 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") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") );
@@ -265,11 +397,21 @@ void VideoPlayer::_bind_methods() {
VideoPlayer::VideoPlayer() {
volume=1;
- loops=false;
- paused=false;
- autoplay=false;
+ loops = false;
+ paused = false;
+ 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 db5f9a58a6..c485e3d6b6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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:
@@ -77,11 +105,17 @@ public:
float get_volume_db() const;
String get_stream_name() const;
- float get_pos() const;
+ float get_stream_pos() const;
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 b0fcf9717b..f67d50b56c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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
@@ -131,14 +137,60 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina
uint32_t flags=0;
- if (bool(GLOBAL_DEF("image_loader/filter",true)))
+
+ FileAccess *f2 = FileAccess::open(p_path+".flags",FileAccess::READ);
+ Map<String,bool> flags_found;
+ if (f2) {
+
+ while(!f2->eof_reached()) {
+ String l2 = f2->get_line();
+ int eqpos = l2.find("=");
+ if (eqpos!=-1) {
+ String flag=l2.substr(0,eqpos).strip_edges();
+ String val=l2.substr(eqpos+1,l2.length()).strip_edges().to_lower();
+ flags_found[flag]=(val=="true" || val=="1")?true:false;
+ }
+ }
+ memdelete(f2);
+ }
+
+
+ if (flags_found.has("filter")) {
+ if (flags_found["filter"])
+ flags|=Texture::FLAG_FILTER;
+ } else if (bool(GLOBAL_DEF("image_loader/filter",true))) {
flags|=Texture::FLAG_FILTER;
- if (bool(GLOBAL_DEF("image_loader/gen_mipmaps",true)))
+ }
+
+
+ if (flags_found.has("gen_mipmaps")) {
+ if (flags_found["gen_mipmaps"])
+ flags|=Texture::FLAG_MIPMAPS;
+ } else if (bool(GLOBAL_DEF("image_loader/gen_mipmaps",true))) {
flags|=Texture::FLAG_MIPMAPS;
- if (bool(GLOBAL_DEF("image_loader/repeat",false)))
+ }
+
+ if (flags_found.has("repeat")) {
+ if (flags_found["repeat"])
+ flags|=Texture::FLAG_REPEAT;
+ } else if (bool(GLOBAL_DEF("image_loader/repeat",true))) {
flags|=Texture::FLAG_REPEAT;
+ }
+ if (flags_found.has("anisotropic")) {
+ if (flags_found["anisotropic"])
+ flags|=Texture::FLAG_ANISOTROPIC_FILTER;
+ }
+ if (flags_found.has("tolinear")) {
+ 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();
@@ -153,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 d9fe45a244..b5ec5a1200 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 74eeb819b8..00b800b28b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -146,18 +151,28 @@ RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_
}
int frames=chunksize;
+
frames/=format_channels;
frames/=(format_bits>>3);
-
+ /*print_line("chunksize: "+itos(chunksize));
+ print_line("channels: "+itos(format_channels));
+ print_line("bits: "+itos(format_bits));
+*/
sample->create(
(format_bits==8) ? Sample::FORMAT_PCM8 : Sample::FORMAT_PCM16,
(format_channels==2)?true:false,
frames );
sample->set_mix_rate( format_freq );
+ int len=frames;
+ if (format_channels==2)
+ len*=2;
+ if (format_bits>8)
+ len*=2;
+
DVector<uint8_t> data;
- data.resize(chunksize);
+ data.resize(len);
DVector<uint8_t>::Write dataw = data.write();
void * data_ptr = dataw.ptr();
@@ -234,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 1011521079..a74da041c1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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/io/scene_format_object.cpp b/scene/io/scene_format_object.cpp
deleted file mode 100644
index 6ffae30282..0000000000
--- a/scene/io/scene_format_object.cpp
+++ /dev/null
@@ -1,851 +0,0 @@
-/*************************************************************************/
-/* scene_format_object.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "scene_format_object.h"
-#include "print_string.h"
-#include "globals.h"
-#include "scene/resources/packed_scene.h"
-#include "io/resource_loader.h"
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-void SceneFormatSaverObject::save_node(const Node* p_root,const Node* p_node,const Node* p_owner,ObjectFormatSaver *p_saver,String p_base_path,uint32_t p_flags,Map<const Node*,uint32_t>& owner_id) const {
-
- if (p_node!=p_root && p_node->get_owner()==NULL)
- return;
-
-
- if (p_flags&SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES || p_node->get_owner() == p_owner || p_node == p_owner ) {
-
- Dictionary d;
- if (p_root!=p_node) {
- d["path"]=p_root->get_path_to(p_node->get_parent());
- }
-
- d["name"]=p_node->get_name();
-
- /* Connections */
-
- List<MethodInfo> signal_list;
-
- p_node->get_signal_list(&signal_list);
-
- int conn_count=0;
-
- Set<Node::Connection> exclude_connections;
-
- if (!(p_flags&SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES)) {
-
- Vector<Node::Connection> ex = p_node->get_instance_connections();
- for(int i=0;i<ex.size();i++) {
- exclude_connections.insert(ex[i]);
- }
- }
-
- for (List<MethodInfo>::Element *S=signal_list.front();S;S=S->next()) {
-
- List<Node::Connection> connections;
- p_node->get_signal_connection_list(S->get().name,&connections);
- for(List<Node::Connection>::Element *E=connections.front();E;E=E->next()) {
-
- Node::Connection &c=E->get();
- if (!(c.flags&Object::CONNECT_PERSIST))
- continue;
- if (exclude_connections.has(c))
- continue;
-
- Node *target = c.target->cast_to<Node>();
- if (!target)
- continue; //connected to something not a node, ignoring
-
- Dictionary cd;
- cd["signal"]=c.signal;
- cd["target"]=p_node->get_path_to(target);
- cd["method"]=c.method;
- cd["realtime"]=!(c.flags&Object::CONNECT_DEFERRED);
- if (c.binds.size())
- cd["binds"]=c.binds;
- d["connection/"+itos(conn_count+1)]=cd;
-
- conn_count++;
- }
- }
-
- d["connection_count"]=conn_count;
- if (owner_id.has(p_node->get_owner())) {
-
- d["owner"]=owner_id[p_node->get_owner()];
- }
-
- /* Groups */
-
- DVector<String> group_array;
- List<Node::GroupInfo> groups;
- p_node->get_groups(&groups);
- Set<StringName> exclude_groups;
-
- if (!(p_flags&SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES)) {
- //generate groups to exclude (came from instance)
- Vector<StringName> eg;
- eg=p_node->get_instance_groups();
- for(int i=0;i<eg.size();i++)
- exclude_groups.insert(eg[i]);
- }
-
- for(List<Node::GroupInfo>::Element*E=groups.front();E;E=E->next()) {
-
- if (E->get().persistent && !exclude_groups.has(E->get().name))
- group_array.push_back(E->get().name);
- }
-
- if (group_array.size())
- d["groups"]=group_array;
-
- /* Save */
-
- if (p_owner!=p_node && p_node->get_filename()!="") {
-
- String instance_path;
- if (p_flags&SceneSaver::FLAG_RELATIVE_PATHS)
- instance_path=p_base_path.path_to_file(Globals::get_singleton()->localize_path(p_node->get_filename()));
- else
- instance_path=p_node->get_filename();
- d["instance"]=instance_path;
-
- if (p_flags&SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES) {
-
- int id = owner_id.size();
- d["owner_id"]=id;
- owner_id[p_node]=id;
-
- p_saver->save(p_node,d);
-
- //owner change!
- for (int i=0;i<p_node->get_child_count();i++) {
-
- save_node(p_root,p_node->get_child(i),p_node,p_saver,p_base_path,p_flags,owner_id);
- }
- return;
-
- } else {
- DVector<String> prop_names;
- Array prop_values;
-
- List<PropertyInfo> properties;
- p_node->get_property_list(&properties);
-
- //instance state makes sure that only changes to instance are saved
- Dictionary instance_state=p_node->get_instance_state();
-
- for(List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) {
-
- if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
- continue;
-
- String name=E->get().name;
- Variant value=p_node->get(E->get().name);
-
- if (!instance_state.has(name))
- continue; // did not change since it was loaded, not save
- if (value==instance_state[name])
- continue;
- prop_names.push_back( name );
- prop_values.push_back( value );
-
- }
-
- d["override_names"]=prop_names;
- d["override_values"]=prop_values;
-
- p_saver->save(NULL,d);
- }
- } else {
-
- p_saver->save(p_node,d);
- }
- }
-
- for (int i=0;i<p_node->get_child_count();i++) {
-
- save_node(p_root,p_node->get_child(i),p_owner,p_saver,p_base_path,p_flags,owner_id);
- }
-}
-
-
-Error SceneFormatSaverObject::save(const String &p_path,const Node* p_scene,uint32_t p_flags,const Ref<OptimizedSaver> &p_optimizer) {
-
- String extension=p_path.extension();
- if (extension=="scn")
- extension="bin";
- if (extension=="xscn")
- extension="xml";
-
- String local_path=Globals::get_singleton()->localize_path(p_path);
- uint32_t saver_flags=0;
- if (p_flags&SceneSaver::FLAG_RELATIVE_PATHS)
- saver_flags|=ObjectSaver::FLAG_RELATIVE_PATHS;
- if (p_flags&SceneSaver::FLAG_BUNDLE_RESOURCES)
- saver_flags|=ObjectSaver::FLAG_BUNDLE_RESOURCES;
- if (p_flags&SceneSaver::FLAG_OMIT_EDITOR_PROPERTIES)
- saver_flags|=ObjectSaver::FLAG_OMIT_EDITOR_PROPERTIES;
- if (p_flags&SceneSaver::FLAG_SAVE_BIG_ENDIAN)
- saver_flags|=ObjectSaver::FLAG_SAVE_BIG_ENDIAN;
-
- ObjectFormatSaver *saver = ObjectSaver::instance_format_saver(local_path,"SCENE",extension,saver_flags,p_optimizer);
-
- ERR_FAIL_COND_V(!saver,ERR_FILE_UNRECOGNIZED);
-
- /* SAVE SCENE */
-
- Map<const Node*,uint32_t> node_id_map;
- save_node(p_scene,p_scene,p_scene,saver,local_path,p_flags,node_id_map);
-
- memdelete(saver);
-
- return OK;
-}
-
-void SceneFormatSaverObject::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("xml");
- p_extensions->push_back("scn");
- p_extensions->push_back("xscn");
-
-// ObjectSaver::get_recognized_extensions(p_extensions);
-}
-
-
-/////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////
-
-void SceneFormatLoaderObject::_apply_meta(Node *node, const Variant&meta, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,Map<uint32_t,Node*>& owner_map) {
-
- r_err = OK;
-
-
- Dictionary d=meta;
-
- if (!d.has("name")) {
-
- r_err=ERR_WTF;
- memdelete(node);
- ERR_FAIL_COND(!d.has("name"));
- }
-
-
- node->set_name(d["name"]);
- int connection_count=d.has("connection_count")?d["connection_count"].operator int():0;
-
-
- for (int i=0;i<connection_count;i++) {
-
- Dictionary cd=d["connection/"+itos(i+1)];
-
- ERR_CONTINUE(!cd.has("target"));
- ERR_CONTINUE(!cd.has("method"));
- ERR_CONTINUE(!cd.has("realtime"));
- ERR_CONTINUE(!cd.has("signal"));
-
- ConnectionItem ci;
-
- ci.node=node;
- ci.target=cd["target"];
- ci.method=cd["method"];
- ci.signal=cd["signal"];
- ci.realtime=cd["realtime"];
- if (cd.has("binds"))
- ci.binds=cd["binds"];
-
- connections.push_back(ci);
-
- }
-
- DVector<String> groups=d.has("groups")?d["groups"].operator DVector<String>():DVector<String>();
- for (int i=0;i<groups.size();i++) {
-
- node->add_to_group(groups[i],true);
- }
-
-}
-
-
-
-Ref<SceneInteractiveLoader> SceneFormatLoaderObject::load_interactive(const String &p_path,bool p_save_root_state) {
-
- SceneInteractiveLoaderObject *sil = memnew( SceneInteractiveLoaderObject(p_path,p_save_root_state) );
-
- if (sil->error!=OK) {
-
- memdelete( sil );
- return Ref<SceneInteractiveLoader>();
- }
-
- return Ref<SceneInteractiveLoader>( sil );
-
-}
-
-
-Node* SceneFormatLoaderObject::load_node(Object *obj, const Variant& meta, Node *p_root, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,bool p_save_instance_state,Map<uint32_t,Node*>& owner_map) {
-
- r_err = OK;
-
- Node *node=obj->cast_to<Node>();
-
- _apply_meta(node,meta,p_loader,connections,r_err,owner_map);
- if (r_err!=OK)
- return NULL;
-
- Dictionary d=meta;
-
- if (p_root) {
- NodePath path=d.has("path")?d["path"].operator NodePath():NodePath(".");
-
- Node *parent=p_root->get_node(path);
- if (!parent) {
- memdelete(node);
- r_err=ERR_FILE_CORRUPT;
- ERR_FAIL_COND_V(!parent,NULL);
- }
-
- parent->add_child(node);
-
- if (d.has("owner_id")) {
- //is owner
- owner_map[d["owner_id"]]=node;
- if (d.has("instance"))
- node->set_filename(d["instance"]);
-
- }
-
- if (d.has("owner")) {
-
- uint32_t owner = d["owner"];
- ERR_FAIL_COND_V(!owner_map.has(owner),NULL);
- node->set_owner(owner_map[owner]);
- } else {
-
- node->set_owner(p_root);
- }
- }
-
- return node;
-}
-
-void SceneFormatLoaderObject::_apply_connections(List<ConnectionItem>& connections) {
-
- int idx=0;
- for (List<ConnectionItem>::Element *E=connections.front();E;E=E->next()) {
-
- ConnectionItem &ci=E->get();
- Node *target = ci.node->get_node(ci.target);
- ERR_CONTINUE(!target);
- ci.node->connect(ci.signal,target,ci.method,ci.binds,(ci.realtime?0:Object::CONNECT_DEFERRED)|Object::CONNECT_PERSIST);
- idx++;
- }
-
-}
-
-Node* SceneFormatLoaderObject::load(const String &p_path,bool p_save_instance_state) {
-
- List<ConnectionItem> connections;
-
- String extension=p_path.extension();
- if (extension=="scn")
- extension="bin";
- if (extension=="xscn")
- extension="xml";
-
- String local_path = Globals::get_singleton()->localize_path(p_path);
-
- ObjectFormatLoader *loader = ObjectLoader::instance_format_loader(local_path,"SCENE",extension);
-
- ERR_EXPLAIN("Couldn't load scene: "+p_path);
- ERR_FAIL_COND_V(!loader,NULL);
-
- Node *root=NULL;
- Map<uint32_t,Node*> owner_map;
-
- while(true) {
-
- Object *obj=NULL;
- Variant metav;
- Error r_err=loader->load(&obj,metav);
-
- if (r_err == ERR_SKIP) {
- continue;
- };
-
- if (r_err==ERR_FILE_EOF) {
- memdelete(loader);
- ERR_FAIL_COND_V(!root,NULL);
- _apply_connections(connections);
- return root;
- }
-
- if (r_err || (!obj && metav.get_type()==Variant::NIL)) {
- memdelete(loader);
- ERR_EXPLAIN("Object Loader Failed for Scene: "+p_path) ;
- ERR_FAIL_COND_V( r_err, NULL);
- ERR_EXPLAIN("Object Loader Failed for Scene: "+p_path) ;
- ERR_FAIL_COND_V( !obj && metav.get_type()==Variant::NIL,NULL);
- }
-
- if (obj) {
- if (obj->cast_to<Node>()) {
-
- Error err;
- Node* node = load_node(obj, metav, root, loader,connections,err,p_save_instance_state,owner_map);
- if (err)
- memdelete(loader);
-
- ERR_FAIL_COND_V( err, NULL );
- if (!root)
- root=node;
- } else {
-
- memdelete(loader);
- ERR_FAIL_V( NULL );
-
- }
- } else {
-
- // check for instance
- Dictionary meta=metav;
- if (meta.has("instance")) {
- if (!root) {
-
- memdelete(loader);
- ERR_FAIL_COND_V(!root,NULL);
- }
-
- String path = meta["instance"];
-
- 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()+"/"+path);
- }
-
-
- Node *scene = SceneLoader::load(path);
-
- if (!scene) {
-
- Ref<PackedScene> sd = ResourceLoader::load(path);
- if (sd.is_valid()) {
-
- scene=sd->instance();
- }
- }
-
-
- if (!scene) {
-
- memdelete(loader);
- ERR_FAIL_COND_V(!scene,NULL);
- }
-
- if (p_save_instance_state)
- scene->generate_instance_state();
-
-
- Error err;
- _apply_meta(scene,metav,loader,connections,err,owner_map);
- if (err!=OK) {
- memdelete(loader);
- ERR_FAIL_COND_V(err!=OK,NULL);
- }
-
- Node *parent=root;
-
- if (meta.has("path"))
- parent=root->get_node(meta["path"]);
-
-
- if (!parent) {
-
- memdelete(loader);
- ERR_FAIL_COND_V(!parent,NULL);
- }
-
-
- if (meta.has("override_names") && meta.has("override_values")) {
-
- DVector<String> override_names=meta["override_names"];
- Array override_values=meta["override_values"];
-
- int len = override_names.size();
- if ( len > 0 && len == override_values.size() ) {
-
- DVector<String>::Read names = override_names.read();
-
- for(int i=0;i<len;i++) {
-
- scene->set(names[i],override_values[i]);
- }
-
- }
-
- }
-
- scene->set_filename(path);
-
- parent->add_child(scene);
- scene->set_owner(root);
- }
- }
- }
-
- return NULL;
-}
-
-void SceneFormatLoaderObject::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("xml");
- p_extensions->push_back("scn");
- p_extensions->push_back("xscn");
-
-// ObjectLoader::get_recognized_extensions(p_extensions);
-
-}
-
-
-
-///////////////////////////////////////////////////
-
-
-void SceneInteractiveLoaderObject::_apply_meta(Node *node, const Variant&meta, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,Map<uint32_t,Node*>& owner_map) {
-
- r_err = OK;
-
-
- Dictionary d=meta;
-
- if (!d.has("name")) {
-
- r_err=ERR_WTF;
- memdelete(node);
- ERR_FAIL_COND(!d.has("name"));
- }
-
-
- node->set_name(d["name"]);
- int connection_count=d.has("connection_count")?d["connection_count"].operator int():0;
-
-
- for (int i=0;i<connection_count;i++) {
-
- Dictionary cd=d["connection/"+itos(i+1)];
-
- ERR_CONTINUE(!cd.has("target"));
- ERR_CONTINUE(!cd.has("method"));
- ERR_CONTINUE(!cd.has("realtime"));
- ERR_CONTINUE(!cd.has("signal"));
-
- ConnectionItem ci;
-
- ci.node=node;
- ci.target=cd["target"];
- ci.method=cd["method"];
- ci.signal=cd["signal"];
- ci.realtime=cd["realtime"];
- if (cd.has("binds"))
- ci.binds=cd["binds"];
-
- connections.push_back(ci);
-
- }
-
- DVector<String> groups=d.has("groups")?d["groups"].operator DVector<String>():DVector<String>();
- for (int i=0;i<groups.size();i++) {
-
- node->add_to_group(groups[i],true);
- }
-
-}
-
-
-
-Node* SceneInteractiveLoaderObject::load_node(Object *obj, const Variant& meta, Node *p_root, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,bool p_save_instance_state,Map<uint32_t,Node*>& owner_map) {
-
- r_err = OK;
-
- Node *node=obj->cast_to<Node>();
-
- _apply_meta(node,meta,p_loader,connections,r_err,owner_map);
- if (r_err!=OK)
- return NULL;
-
- Dictionary d=meta;
-
- if (p_root) {
- NodePath path=d.has("path")?d["path"].operator NodePath():NodePath(".");
-
- Node *parent=p_root->get_node(path);
- if (!parent) {
- memdelete(node);
- r_err=ERR_FILE_CORRUPT;
- ERR_FAIL_COND_V(!parent,NULL);
- }
-
- parent->add_child(node);
-
- if (d.has("owner_id")) {
- //is owner
- owner_map[d["owner_id"]]=node;
- if (d.has("instance"))
- node->set_filename(d["instance"]);
-
- }
-
- if (d.has("owner")) {
-
- uint32_t owner = d["owner"];
- ERR_FAIL_COND_V(!owner_map.has(owner),NULL);
- node->set_owner(owner_map[owner]);
- } else {
-
- node->set_owner(p_root);
- }
- }
-
- return node;
-}
-
-void SceneInteractiveLoaderObject::_apply_connections(List<ConnectionItem>& connections) {
-
- int idx=0;
- for (List<ConnectionItem>::Element *E=connections.front();E;E=E->next()) {
-
- ConnectionItem &ci=E->get();
- Node *target = ci.node->get_node(ci.target);
- ERR_CONTINUE(!target);
- ci.node->connect(ci.signal,target,ci.method,ci.binds,(ci.realtime?0:Object::CONNECT_DEFERRED)|Object::CONNECT_PERSIST);
- idx++;
- }
-
-}
-
-SceneInteractiveLoaderObject::SceneInteractiveLoaderObject(const String &p_path,bool p_save_root_state) {
-
- error=OK;
- path=p_path;
- save_instance_state=p_save_root_state;
- node_path=p_path;
- root=NULL;
- stage_max=1;
- stage=0;
-
-
- String extension=p_path.extension();
- if (extension=="scn")
- extension="bin";
- if (extension=="xscn")
- extension="xml";
-
- local_path = Globals::get_singleton()->localize_path(p_path);
-
- loader = ObjectLoader::instance_format_loader(local_path,"SCENE",extension);
-
- if (!loader) {
-
- error=ERR_CANT_OPEN;
- }
- ERR_EXPLAIN("Couldn't load scene: "+p_path);
- ERR_FAIL_COND(!loader);
-
-}
-
-
-
-void SceneInteractiveLoaderObject::set_local_path(const String& p_local_path) {
-
- node_path=p_local_path;
-}
-
-Node *SceneInteractiveLoaderObject::get_scene() {
-
- if (error==ERR_FILE_EOF)
- return root;
- return NULL;
-}
-Error SceneInteractiveLoaderObject::poll() {
-
- if (error!=OK)
- return error;
-
- Object *obj=NULL;
- Variant metav;
- Error r_err=loader->load(&obj,metav);
-
-
- if (r_err == ERR_SKIP) {
- stage++;
- return OK;
- };
-
- if (r_err==ERR_FILE_EOF) {
- memdelete(loader);
- error=ERR_FILE_CORRUPT;
- ERR_FAIL_COND_V(!root,ERR_FILE_CORRUPT);
- _apply_connections(connections);
- error=ERR_FILE_EOF;
- if (root)
- root->set_filename(node_path);
- return error;
- }
-
- if (r_err || (!obj && metav.get_type()==Variant::NIL)) {
- memdelete(loader);
- error=ERR_FILE_CORRUPT;
- ERR_EXPLAIN("Object Loader Failed for Scene: "+path);
- ERR_FAIL_COND_V( r_err, ERR_FILE_CORRUPT);
- ERR_EXPLAIN("Object Loader Failed for Scene: "+path);
- ERR_FAIL_COND_V( !obj && metav.get_type()==Variant::NIL,ERR_FILE_CORRUPT);
- }
-
- if (obj) {
- if (obj->cast_to<Node>()) {
-
- Error err;
- Node* node = load_node(obj, metav, root, loader,connections,err,save_instance_state,owner_map);
- if (err) {
- error=ERR_FILE_CORRUPT;
- memdelete(loader);
- }
-
- ERR_FAIL_COND_V( err, ERR_FILE_CORRUPT );
- if (!root)
- root=node;
- } else {
-
- error=ERR_FILE_CORRUPT;
- memdelete(loader);
- ERR_EXPLAIN("Loaded something not a node.. (?)");
- ERR_FAIL_V( ERR_FILE_CORRUPT );
-
- }
- } else {
-
- // check for instance
- Dictionary meta=metav;
- if (meta.has("instance")) {
-
- if (!root) {
-
- error=ERR_FILE_CORRUPT;
- memdelete(loader);
- ERR_FAIL_COND_V(!root,ERR_FILE_CORRUPT);
- }
-
- String path = meta["instance"];
-
- 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()+"/"+path);
- }
-
- Node *scene = SceneLoader::load(path);
-
- if (!scene) {
-
- error=ERR_FILE_CORRUPT;
- memdelete(loader);
- ERR_FAIL_COND_V(!scene,ERR_FILE_CORRUPT);
- }
-
- if (save_instance_state)
- scene->generate_instance_state();
-
-
- Error err;
- _apply_meta(scene,metav,loader,connections,err,owner_map);
- if (err!=OK) {
- error=ERR_FILE_CORRUPT;
- memdelete(loader);
- ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT);
- }
-
- Node *parent=root;
-
- if (meta.has("path"))
- parent=root->get_node(meta["path"]);
-
-
- if (!parent) {
-
- error=ERR_FILE_CORRUPT;
- memdelete(loader);
- ERR_FAIL_COND_V(!parent,ERR_FILE_CORRUPT);
- }
-
-
- if (meta.has("override_names") && meta.has("override_values")) {
-
- DVector<String> override_names=meta["override_names"];
- Array override_values=meta["override_values"];
-
- int len = override_names.size();
- if ( len > 0 && len == override_values.size() ) {
-
- DVector<String>::Read names = override_names.read();
-
- for(int i=0;i<len;i++) {
-
- scene->set(names[i],override_values[i]);
- }
-
- }
-
- }
-
- scene->set_filename(path);
-
- parent->add_child(scene);
- scene->set_owner(root);
- }
- }
-
- stage++;
- error=OK;
- return error;
-
-}
-int SceneInteractiveLoaderObject::get_stage() const {
-
- return stage;
-}
-int SceneInteractiveLoaderObject::get_stage_count() const {
-
- return stage_max;
-}
-
-
-#endif
diff --git a/scene/io/scene_format_object.h b/scene/io/scene_format_object.h
deleted file mode 100644
index 3f0bbd4627..0000000000
--- a/scene/io/scene_format_object.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*************************************************************************/
-/* scene_format_object.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef SCENE_FORMAT_OBJECT_H
-#define SCENE_FORMAT_OBJECT_H
-
-
-#include "scene/main/node.h"
-#include "scene/io/scene_saver.h"
-#include "scene/io/scene_loader.h"
-#include "io/object_saver.h"
-#include "io/object_loader.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-class SceneFormatSaverObject : public SceneFormatSaver {
-
- void save_node(const Node* p_root,const Node* p_node,const Node* p_owner,ObjectFormatSaver *p_saver,String p_base_path,uint32_t p_flags,Map<const Node*,uint32_t>& owner_id) const;
-
-public:
-
- virtual Error save(const String &p_path,const Node* p_scenezz,uint32_t p_flags=0,const Ref<OptimizedSaver> &p_optimizer=Ref<OptimizedSaver>());
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual ~SceneFormatSaverObject() {}
-};
-
-
-
-class SceneFormatLoaderObject : public SceneFormatLoader {
-
-
- struct ConnectionItem {
- Node *node;
- NodePath target;
- StringName method;
- StringName signal;
- Vector<Variant> binds;
- bool realtime;
- };
-
- Node* load_node(Object *obj, const Variant& meta, Node *p_root, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,bool p_root_scene_hint,Map<uint32_t,Node*>& owner_map);
- void _apply_connections(List<ConnectionItem>& connections);
- void _apply_meta(Node *node, const Variant& meta, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,Map<uint32_t,Node*>& owner_map);
-
-public:
-
- virtual Ref<SceneInteractiveLoader> load_interactive(const String &p_path,bool p_root_scene_hint=false);
- virtual Node* load(const String &p_path,bool p_save_root_state=false);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
-
-};
-
-
-class SceneInteractiveLoaderObject : public SceneInteractiveLoader {
-
- OBJ_TYPE(SceneInteractiveLoaderObject,SceneInteractiveLoader);
-
- struct ConnectionItem {
- Node *node;
- NodePath target;
- StringName method;
- StringName signal;
- Vector<Variant> binds;
- bool realtime;
- };
- ObjectFormatLoader *loader;
- String path;
- String node_path;
- String local_path;
- Error error;
- bool save_instance_state;
- List<ConnectionItem> connections;
- Map<uint32_t,Node*> owner_map;
- Node *root;
- int stage_max;
- int stage;
-
-
- Node* load_node(Object *obj, const Variant& meta, Node *p_root, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,bool p_root_scene_hint,Map<uint32_t,Node*>& owner_map);
- void _apply_connections(List<ConnectionItem>& connections);
- void _apply_meta(Node *node, const Variant& meta, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,Map<uint32_t,Node*>& owner_map);
-
-friend class SceneFormatLoaderObject;
-public:
-
- virtual void set_local_path(const String& p_local_path);
- virtual Node *get_scene();
- virtual Error poll();
- virtual int get_stage() const;
- virtual int get_stage_count() const;
-
-
- SceneInteractiveLoaderObject(const String &p_path,bool p_save_root_state=false);
-};
-
-
-
-#endif
-#endif
diff --git a/scene/io/scene_format_script.cpp b/scene/io/scene_format_script.cpp
deleted file mode 100644
index a6f1596d2b..0000000000
--- a/scene/io/scene_format_script.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*************************************************************************/
-/* scene_format_script.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "scene_format_script.h"
-#if 0
-Node* SceneFormatLoaderScript::load(const String &p_path,bool p_save_instance_state) {
-
- Ref<Script> script = ResourceLoader::load(p_path);
- ERR_EXPLAIN("Can't load script-based scene: "+p_path);
- ERR_FAIL_COND_V(script.is_null(),NULL);
- ERR_EXPLAIN("Script does not instance in a node: "+p_path);
- ERR_FAIL_COND_V(script->get_node_type()=="",NULL);
- String node_type=script->get_node_type();
- Object *obj = ObjectTypeDB::instance(node_type);
- ERR_EXPLAIN("Unknown node type for instancing '"+node_type+"' in script: "+p_path);
- ERR_FAIL_COND_V(!obj,NULL);
- Node *node = obj->cast_to<Node>();
- if (!node)
- memdelete(obj);
- ERR_EXPLAIN("Node type '"+node_type+"' not of type 'Node'' in script: "+p_path);
- ERR_FAIL_COND_V(!node,NULL);
-
- node->set_script(script.get_ref_ptr());
-
- return node;
-}
-
-void SceneFormatLoaderScript::get_recognized_extensions(List<String> *p_extensions) const {
-
- for (int i=0;i<ScriptServer::get_language_count();i++) {
-
- ScriptServer::get_language(i)->get_recognized_extensions(p_extensions);
- }
-}
-
-
-SceneFormatLoaderScript::SceneFormatLoaderScript()
-{
-}
-#endif
diff --git a/scene/io/scene_format_script.h b/scene/io/scene_format_script.h
deleted file mode 100644
index 9bfcc0b1e3..0000000000
--- a/scene/io/scene_format_script.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************************************/
-/* scene_format_script.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef SCENE_FORMAT_SCRIPT_H
-#define SCENE_FORMAT_SCRIPT_H
-
-#include "scene/io/scene_loader.h"
-#include "io/resource_loader.h"
-#if 0
-
-class SceneFormatLoaderScript : public SceneFormatLoader {
-public:
-
- virtual Node* load(const String &p_path,bool p_save_instance_state=false);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
-
- SceneFormatLoaderScript();
-};
-#endif
-#endif // SCENE_FORMAT_SCRIPT_H
diff --git a/scene/io/scene_loader.cpp b/scene/io/scene_loader.cpp
deleted file mode 100644
index 8615e64ae9..0000000000
--- a/scene/io/scene_loader.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*************************************************************************/
-/* scene_loader.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "scene_loader.h"
-#include "globals.h"
-#include "path_remap.h"
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-SceneFormatLoader *SceneLoader::loader[MAX_LOADERS];
-
-int SceneLoader::loader_count=0;
-
-
-void SceneInteractiveLoader::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("get_scene"),&SceneInteractiveLoader::get_scene);
- ObjectTypeDB::bind_method(_MD("poll"),&SceneInteractiveLoader::poll);
- ObjectTypeDB::bind_method(_MD("get_stage"),&SceneInteractiveLoader::get_stage);
- ObjectTypeDB::bind_method(_MD("get_stage_count"),&SceneInteractiveLoader::get_stage_count);
-}
-
-class SceneInteractiveLoaderDefault : public SceneInteractiveLoader {
-
- OBJ_TYPE( SceneInteractiveLoaderDefault, SceneInteractiveLoader );
-public:
- Node *scene;
-
- virtual void set_local_path(const String& p_local_path) { scene->set_filename(p_local_path); }
- virtual Node *get_scene() { return scene; }
- virtual Error poll() { return ERR_FILE_EOF; }
- virtual int get_stage() const { return 1; }
- virtual int get_stage_count() const { return 1; }
-
- SceneInteractiveLoaderDefault() {}
-};
-
-
-Ref<SceneInteractiveLoader> SceneFormatLoader::load_interactive(const String &p_path,bool p_root_scene_hint) {
-
- Node *scene = load(p_path,p_root_scene_hint);
- if (!scene)
- return Ref<SceneInteractiveLoader>();
- Ref<SceneInteractiveLoaderDefault> sil = Ref<SceneInteractiveLoaderDefault>( memnew( SceneInteractiveLoaderDefault ));
- sil->scene=scene;
- return sil;
-}
-
-
-
-bool SceneFormatLoader::recognize(const String& p_extension) const {
-
-
- List<String> extensions;
- get_recognized_extensions(&extensions);
- for (List<String>::Element *E=extensions.front();E;E=E->next()) {
-
- if (E->get().nocasecmp_to(p_extension.extension())==0)
- return true;
- }
-
- return false;
-}
-
-Ref<SceneInteractiveLoader> SceneLoader::load_interactive(const String &p_path,bool p_save_root_state) {
-
- String 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;
- Ref<SceneInteractiveLoader> il = loader[i]->load_interactive(remapped_path,p_save_root_state);
-
- if (il.is_null() && remapped_path!=local_path)
- il = loader[i]->load_interactive(local_path,p_save_root_state);
-
- ERR_EXPLAIN("Error loading scene: "+local_path);
- ERR_FAIL_COND_V(il.is_null(),Ref<SceneInteractiveLoader>());
- il->set_local_path(local_path);
-
- return il;
- }
-
- ERR_EXPLAIN("No loader found for scene: "+p_path);
- ERR_FAIL_V(Ref<SceneInteractiveLoader>());
- return Ref<SceneInteractiveLoader>();
-}
-
-Node* SceneLoader::load(const String &p_path,bool p_root_scene_hint) {
-
- String 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;
- Node*node = loader[i]->load(remapped_path,p_root_scene_hint);
-
- if (!node && remapped_path!=local_path)
- node = loader[i]->load(local_path,p_root_scene_hint);
-
- ERR_EXPLAIN("Error loading scene: "+local_path);
- ERR_FAIL_COND_V(!node,NULL);
- node->set_filename(local_path);
-
- return node;
- }
-
- ERR_EXPLAIN("No loader found for scene: "+p_path);
- ERR_FAIL_V(NULL);
-}
-
-void SceneLoader::get_recognized_extensions(List<String> *p_extensions) {
-
- for (int i=0;i<loader_count;i++) {
-
- loader[i]->get_recognized_extensions(p_extensions);
- }
-
-}
-
-void SceneLoader::add_scene_format_loader(SceneFormatLoader *p_format_loader) {
-
- ERR_FAIL_COND( loader_count >= MAX_LOADERS );
- loader[loader_count++]=p_format_loader;
-}
-
-
-#endif
diff --git a/scene/io/scene_loader.h b/scene/io/scene_loader.h
deleted file mode 100644
index 2562fc0520..0000000000
--- a/scene/io/scene_loader.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*************************************************************************/
-/* scene_loader.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef SCENE_LOADER_H
-#define SCENE_LOADER_H
-
-#include "scene/main/node.h"
-
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-class SceneInteractiveLoader : public Reference {
-
- OBJ_TYPE(SceneInteractiveLoader,Reference);
-protected:
-
- static void _bind_methods();
-public:
-
- virtual void set_local_path(const String& p_local_path)=0;
- virtual Node *get_scene()=0;
- virtual Error poll()=0;
- virtual int get_stage() const=0;
- virtual int get_stage_count() const=0;
-
-
- SceneInteractiveLoader() {}
-};
-
-class SceneFormatLoader {
-public:
-
- virtual Ref<SceneInteractiveLoader> load_interactive(const String &p_path,bool p_root_scene_hint=false);
- virtual Node* load(const String &p_path,bool p_root_scene_hint=false)=0;
- virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
- bool recognize(const String& p_extension) const;
-
- virtual ~SceneFormatLoader() {}
-};
-
-class SceneLoader {
-
- enum {
- MAX_LOADERS=64
- };
-
- static SceneFormatLoader *loader[MAX_LOADERS];
- static int loader_count;
-
-public:
-
- static Ref<SceneInteractiveLoader> load_interactive(const String &p_path,bool p_save_root_state=false);
- static Node* load(const String &p_path,bool p_save_root_state=false);
- static void add_scene_format_loader(SceneFormatLoader *p_format_loader);
- static void get_recognized_extensions(List<String> *p_extensions);
-
-
-};
-
-#endif
-
-#endif
diff --git a/scene/io/scene_saver.cpp b/scene/io/scene_saver.cpp
deleted file mode 100644
index f1b503ef27..0000000000
--- a/scene/io/scene_saver.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*************************************************************************/
-/* scene_saver.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "scene_saver.h"
-#include "print_string.h"
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-SceneFormatSaver *SceneSaver::saver[MAX_SAVERS];
-
-int SceneSaver::saver_count=0;
-
-bool SceneFormatSaver::recognize(const String& p_extension) const {
-
-
- List<String> extensions;
- get_recognized_extensions(&extensions);
- for (List<String>::Element *E=extensions.front();E;E=E->next()) {
-
-
- if (E->get().nocasecmp_to(p_extension.extension())==0)
- return true;
- }
-
- return false;
-}
-
-Error SceneSaver::save(const String &p_path,const Node* p_scene,uint32_t p_flags,const Ref<OptimizedSaver> &p_optimizer) {
-
- String extension=p_path.extension();
- Error err=ERR_FILE_UNRECOGNIZED;
- bool recognized=false;
-
- for (int i=0;i<saver_count;i++) {
-
- if (!saver[i]->recognize(extension))
- continue;
- recognized=true;
- err = saver[i]->save(p_path,p_scene,p_flags,p_optimizer);
- if (err == OK )
- return OK;
- }
-
- if (err) {
- if (!recognized) {
- ERR_EXPLAIN("No saver format found for scene: "+p_path);
- } else {
- ERR_EXPLAIN("Couldn't save scene: "+p_path);
- }
- ERR_FAIL_V(err);
- }
-
- return err;
-}
-
-void SceneSaver::get_recognized_extensions(List<String> *p_extensions) {
-
- for (int i=0;i<saver_count;i++) {
-
- saver[i]->get_recognized_extensions(p_extensions);
- }
-}
-
-void SceneSaver::add_scene_format_saver(SceneFormatSaver *p_format_saver) {
-
- ERR_FAIL_COND( saver_count >= MAX_SAVERS );
- saver[saver_count++]=p_format_saver;
-}
-
-#endif
diff --git a/scene/io/scene_saver.h b/scene/io/scene_saver.h
deleted file mode 100644
index 3028dce133..0000000000
--- a/scene/io/scene_saver.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*************************************************************************/
-/* scene_saver.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef SCENE_SAVER_H
-#define SCENE_SAVER_H
-
-#include "scene/main/node.h"
-#include "io/object_saver.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-class SceneFormatSaver {
-public:
-
- virtual Error save(const String &p_path,const Node* p_scen,uint32_t p_flags=0,const Ref<OptimizedSaver> &p_optimizer=Ref<OptimizedSaver>())=0;
- virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
- bool recognize(const String& p_extension) const;
- virtual ~SceneFormatSaver() {}
-};
-
-
-
-
-class SceneSaver {
-
- enum {
- MAX_SAVERS=64
- };
-
- static SceneFormatSaver *saver[MAX_SAVERS];
- static int saver_count;
-
-public:
- enum SaverFlags {
-
- FLAG_RELATIVE_PATHS=1,
- FLAG_BUNDLE_RESOURCES=2,
- FLAG_BUNDLE_INSTANCED_SCENES=4,
- FLAG_OMIT_EDITOR_PROPERTIES=8,
- FLAG_SAVE_BIG_ENDIAN=16
- };
-
- static Error save(const String &p_path,const Node* p_scenezz,uint32_t p_flags=0,const Ref<OptimizedSaver> &p_optimizer=Ref<OptimizedSaver>());
- static void add_scene_format_saver(SceneFormatSaver *p_format_saver);
- static void get_recognized_extensions(List<String> *p_extensions);
-};
-
-
-
-#endif
-#endif
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 5006f55daf..ee3d7f5afd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -144,7 +144,7 @@ void CanvasLayer::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
Node *n = this;
vp=NULL;
@@ -169,7 +169,7 @@ void CanvasLayer::_notification(int p_what) {
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
VisualServer::get_singleton()->viewport_remove_canvas(viewport,canvas->get_canvas());
viewport=RID();
@@ -180,7 +180,7 @@ void CanvasLayer::_notification(int p_what) {
Size2 CanvasLayer::get_viewport_size() const {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return Size2(1,1);
Rect2 r = vp->get_visible_rect();
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index 638f3ec579..edd00c1a7a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 761f470c11..108621baa5 100644
--- a/scene/main/misc.cpp
+++ b/scene/main/misc.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/main/misc.h b/scene/main/misc.h
index 34b80a08b4..e7894aa68d 100644
--- a/scene/main/misc.h
+++ b/scene/main/misc.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index b90fd489b3..a832162994 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,7 +28,6 @@
/*************************************************************************/
#include "node.h"
#include "print_string.h"
-#include "scene/io/scene_loader.h"
#include "message_queue.h"
#include "scene/scene_string_names.h"
#include "scene/resources/packed_scene.h"
@@ -65,7 +64,7 @@ void Node::_notification(int p_notification) {
}
} break;
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
if (data.pause_mode==PAUSE_MODE_INHERIT) {
@@ -84,12 +83,12 @@ void Node::_notification(int p_notification) {
if (data.unhandled_key_input)
add_to_group("_vp_unhandled_key_input"+itos(get_viewport()->get_instance_ID()));
- get_scene()->node_count++;
+ get_tree()->node_count++;
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
- get_scene()->node_count--;
+ get_tree()->node_count--;
if (data.input)
remove_from_group("_vp_input"+itos(get_viewport()->get_instance_ID()));
if (data.unhandled_input)
@@ -105,7 +104,7 @@ void Node::_notification(int p_notification) {
Variant::CallError err;
get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready,NULL,0);
}
- //emit_signal(SceneStringNames::get_singleton()->enter_scene);
+ //emit_signal(SceneStringNames::get_singleton()->enter_tree);
} break;
case NOTIFICATION_POSTINITIALIZE: {
@@ -151,11 +150,11 @@ void Node::_propagate_ready() {
}
-void Node::_propagate_enter_scene() {
- // this needs to happen to all childs before any ENTER_SCENE
+void Node::_propagate_enter_tree() {
+ // this needs to happen to all childs before any enter_tree
if (data.parent) {
- data.scene=data.parent->data.scene;
+ data.tree=data.parent->data.tree;
data.depth=data.parent->data.depth+1;
} else {
@@ -166,25 +165,25 @@ void Node::_propagate_enter_scene() {
if (!data.viewport)
data.viewport = data.parent->data.viewport;
- data.inside_scene=true;
+ data.inside_tree=true;
const StringName *K=NULL;
while ((K=data.grouped.next(K))) {
- data.scene->add_to_group(*K,this);
+ data.tree->add_to_group(*K,this);
}
- notification(NOTIFICATION_ENTER_SCENE);
+ notification(NOTIFICATION_ENTER_TREE);
if (get_script_instance()) {
Variant::CallError err;
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_scene,NULL,0);
+ get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree,NULL,0);
}
- emit_signal(SceneStringNames::get_singleton()->enter_scene);
+ emit_signal(SceneStringNames::get_singleton()->enter_tree);
data.blocked++;
@@ -192,25 +191,55 @@ void Node::_propagate_enter_scene() {
for (int i=0;i<data.children.size();i++) {
- if (!data.children[i]->is_inside_scene()) // could have been added in ENTER_SCENE
- data.children[i]->_propagate_enter_scene();
+ if (!data.children[i]->is_inside_tree()) // could have been added in enter_tree
+ data.children[i]->_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
}
-void Node::_propagate_exit_scene() {
+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--) {
- data.children[i]->_propagate_exit_scene();
+ data.children[i]->_propagate_exit_tree();
}
data.blocked--;
@@ -218,29 +247,29 @@ void Node::_propagate_exit_scene() {
if (get_script_instance()) {
Variant::CallError err;
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_scene,NULL,0);
+ get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree,NULL,0);
}
- emit_signal(SceneStringNames::get_singleton()->exit_scene);
+ emit_signal(SceneStringNames::get_singleton()->exit_tree);
- notification(NOTIFICATION_EXIT_SCENE,true);
- if (data.scene)
- data.scene->node_removed(this);
+ notification(NOTIFICATION_EXIT_TREE,true);
+ if (data.tree)
+ data.tree->node_removed(this);
// exit groups
const StringName *K=NULL;
while ((K=data.grouped.next(K))) {
- data.scene->remove_from_group(*K,this);
+ data.tree->remove_from_group(*K,this);
}
data.viewport = NULL;
- if (data.scene)
- data.scene->tree_changed();
+ if (data.tree)
+ data.tree->tree_changed();
- data.inside_scene=false;
- data.scene=NULL;
+ data.inside_tree=false;
+ data.tree=NULL;
data.depth=-1;
}
@@ -261,8 +290,8 @@ void Node::move_child(Node *p_child,int p_pos) {
data.children.remove( p_child->data.pos );
data.children.insert( p_pos, p_child );
- if (data.scene) {
- data.scene->tree_changed();
+ if (data.tree) {
+ data.tree->tree_changed();
}
data.blocked++;
@@ -272,6 +301,7 @@ void Node::move_child(Node *p_child,int p_pos) {
data.children[i]->data.pos=i;
}
// notification second
+ move_child_notify(p_child);
for (int i=0;i<data.children.size();i++) {
data.children[i]->notification( NOTIFICATION_MOVED_IN_PARENT );
@@ -295,7 +325,7 @@ void Node::add_child_notify(Node *p_child) {
// to be used when not wanted
}
-
+/*
void Node::remove_and_delete_child(Node *p_child) {
ERR_FAIL_NULL( p_child );
@@ -305,12 +335,18 @@ void Node::remove_and_delete_child(Node *p_child) {
memdelete(p_child);
}
+*/
void Node::remove_child_notify(Node *p_child) {
// to be used when not wanted
}
+void Node::move_child_notify(Node *p_child) {
+
+ // to be used when not wanted
+}
+
void Node::set_fixed_process(bool p_process) {
if (data.fixed_process==p_process)
@@ -334,7 +370,7 @@ void Node::set_pause_mode(PauseMode p_mode) {
bool prev_inherits=data.pause_mode==PAUSE_MODE_INHERIT;
data.pause_mode=p_mode;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return; //pointless
if ((data.pause_mode==PAUSE_MODE_INHERIT) == prev_inherits)
return; ///nothing changed
@@ -373,10 +409,12 @@ void Node::_propagate_pause_owner(Node*p_owner) {
bool Node::can_process() const {
- ERR_FAIL_COND_V( !is_inside_scene(), false );
+ ERR_FAIL_COND_V( !is_inside_tree(), false );
- if (get_scene()->is_paused()) {
+ if (get_tree()->is_paused()) {
+ if (data.pause_mode==PAUSE_MODE_STOP)
+ return false;
if (data.pause_mode==PAUSE_MODE_PROCESS)
return true;
if (data.pause_mode==PAUSE_MODE_INHERIT) {
@@ -386,6 +424,9 @@ bool Node::can_process() const {
if (data.pause_owner->data.pause_mode==PAUSE_MODE_PROCESS)
return true;
+
+ if (data.pause_owner->data.pause_mode==PAUSE_MODE_STOP)
+ return false;
}
}
@@ -396,8 +437,8 @@ bool Node::can_process() const {
float Node::get_fixed_process_delta_time() const {
- if (data.scene)
- return data.scene->get_fixed_process_time();
+ if (data.tree)
+ return data.tree->get_fixed_process_time();
else
return 0;
}
@@ -420,8 +461,8 @@ void Node::set_process(bool p_idle_process) {
float Node::get_process_delta_time() const {
- if (data.scene)
- return data.scene->get_idle_process_time();
+ if (data.tree)
+ return data.tree->get_idle_process_time();
else
return 0;
}
@@ -443,7 +484,7 @@ void Node::set_process_input(bool p_enable) {
return;
data.input=p_enable;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (p_enable)
@@ -463,7 +504,7 @@ void Node::set_process_unhandled_input(bool p_enable) {
if (p_enable==data.unhandled_input)
return;
data.unhandled_input=p_enable;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (p_enable)
@@ -483,7 +524,7 @@ void Node::set_process_unhandled_key_input(bool p_enable) {
if (p_enable==data.unhandled_key_input)
return;
data.unhandled_key_input=p_enable;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if (p_enable)
@@ -521,10 +562,10 @@ void Node::set_name(const String& p_name) {
data.parent->_validate_child_name(this);
}
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
emit_signal("renamed");
- get_scene()->tree_changed();
+ get_tree()->tree_changed();
}
}
@@ -541,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
@@ -613,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;
}
}
@@ -630,39 +713,42 @@ void Node::_add_child_nocheck(Node* p_child,const StringName& p_name) {
p_child->data.pos=data.children.size();
data.children.push_back( p_child );
p_child->data.parent=this;
+ p_child->notification(NOTIFICATION_PARENTED);
- if (data.scene) {
- p_child->_set_scene(data.scene);
+ if (data.tree) {
+ p_child->_set_tree(data.tree);
}
/* Notify */
//recognize childs created in this node constructor
p_child->data.parent_owned=data.in_constructor;
- p_child->notification(NOTIFICATION_PARENTED);
add_child_notify(p_child);
}
-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) {
@@ -720,7 +806,7 @@ void Node::remove_child(Node *p_child) {
//if (data.scene) { does not matter
- p_child->_set_scene(NULL);
+ p_child->_set_tree(NULL);
//}
remove_child_notify(p_child);
@@ -754,9 +840,23 @@ 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_scene && p_path.is_absolute(), NULL );
+ ERR_FAIL_COND_V( !data.inside_tree && p_path.is_absolute(), NULL );
Node *current=NULL;
Node *root=NULL;
@@ -819,8 +919,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;
}
@@ -829,6 +931,28 @@ bool Node::has_node(const NodePath& p_path) const {
return _get_node(p_path)!=NULL;
}
+
+Node* Node::find_node(const String& p_mask,bool p_recursive,bool p_owned) const {
+
+ Node * const*cptr = data.children.ptr();
+ int ccount = data.children.size();
+ for(int i=0;i<ccount;i++) {
+ if (p_owned && !cptr[i]->data.owner)
+ continue;
+ if (cptr[i]->data.name.operator String().match(p_mask))
+ return cptr[i];
+
+ if (!p_recursive)
+ continue;
+
+ Node* ret = cptr[i]->find_node(p_mask,true,p_owned);
+ if (ret)
+ return ret;
+ }
+ return NULL;
+
+}
+
Node *Node::get_parent() const {
return data.parent;
@@ -852,8 +976,8 @@ bool Node::is_a_parent_of(const Node *p_node) const {
bool Node::is_greater_than(const Node *p_node) const {
ERR_FAIL_NULL_V(p_node,false);
- ERR_FAIL_COND_V( !data.inside_scene, false );
- ERR_FAIL_COND_V( !p_node->data.inside_scene, false );
+ ERR_FAIL_COND_V( !data.inside_tree, false );
+ ERR_FAIL_COND_V( !p_node->data.inside_tree, false );
ERR_FAIL_COND_V( data.depth<0, false);
ERR_FAIL_COND_V( p_node->data.depth<0, false);
@@ -927,6 +1051,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();
@@ -1024,7 +1149,7 @@ NodePath Node::get_path_to(const Node *p_node) const {
NodePath Node::get_path() const {
- ERR_FAIL_COND_V(!is_inside_scene(),NodePath());
+ ERR_FAIL_COND_V(!is_inside_tree(),NodePath());
const Node *n = this;
Vector<StringName> path;
@@ -1053,8 +1178,8 @@ void Node::add_to_group(const StringName& p_identifier,bool p_persistent) {
GroupData gd;
- if (data.scene)
- data.scene->add_to_group(p_identifier,this);
+ if (data.tree)
+ data.tree->add_to_group(p_identifier,this);
gd.persistent=p_persistent;
@@ -1071,8 +1196,8 @@ void Node::remove_from_group(const StringName& p_identifier) {
ERR_FAIL_COND(!g);
- if (data.scene)
- data.scene->remove_from_group(p_identifier,this);
+ if (data.tree)
+ data.tree->remove_from_group(p_identifier,this);
data.grouped.erase(p_identifier);
@@ -1107,7 +1232,7 @@ void Node::get_groups(List<GroupInfo> *p_groups) const {
void Node::_print_tree(const Node *p_node) {
- printf("%ls\n", String(p_node->get_path_to(this)).c_str());
+ print_line(String(p_node->get_path_to(this)));
for (int i=0;i<data.children.size();i++)
data.children[i]->_print_tree(p_node);
}
@@ -1132,7 +1257,7 @@ void Node::_propagate_reverse_notification(int p_notification) {
void Node::_propagate_deferred_notification(int p_notification, bool p_reverse) {
- ERR_FAIL_COND(!is_inside_scene());
+ ERR_FAIL_COND(!is_inside_tree());
data.blocked++;
@@ -1223,7 +1348,29 @@ 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() {
@@ -1235,7 +1382,7 @@ void Node::generate_instance_state() {
for( List<PropertyInfo>::Element *E=properties.front();E;E=E->next() ) {
PropertyInfo &pi=E->get();
- if (!(pi.usage&PROPERTY_USAGE_EDITOR) || !(pi.usage&PROPERTY_USAGE_STORAGE))
+ if ((pi.usage&PROPERTY_USAGE_NO_INSTANCE_STATE) || !(pi.usage&PROPERTY_USAGE_EDITOR) || !(pi.usage&PROPERTY_USAGE_STORAGE))
continue;
data.instance_state[pi.name]=get(pi.name);
@@ -1274,13 +1421,36 @@ Dictionary Node::get_instance_state() const {
return data.instance_state;
}
-Vector<StringName> Node::get_instance_groups() const {
+#endif
- return data.instance_groups;
+void Node::set_scene_instance_state(const Ref<SceneState>& p_state) {
+
+ data.instance_state=p_state;
+}
+
+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;
}
-Vector<Node::Connection> Node::get_instance_connections() const{
- return data.instance_connections;
+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 {
@@ -1290,18 +1460,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
@@ -1327,7 +1510,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);
@@ -1406,6 +1592,41 @@ void Node::_duplicate_and_reown(Node* p_new_parent, const Map<Node*,Node*>& p_re
}
+
+void Node::_duplicate_signals(const Node* p_original,Node* p_copy) const {
+
+ if (this!=p_original && get_owner()!=p_original)
+ return;
+
+ List<Connection> conns;
+ get_all_signal_connections(&conns);
+
+ for (List<Connection>::Element *E=conns.front();E;E=E->next()) {
+
+ if (E->get().flags&CONNECT_PERSIST) {
+ //user connected
+ NodePath p = p_original->get_path_to(this);
+ Node *copy = p_copy->get_node(p);
+
+ Node *target = E->get().target->cast_to<Node>();
+ if (!target)
+ continue;
+ NodePath ptarget = p_original->get_path_to(target);
+ Node *copytarget = p_copy->get_node(ptarget);
+
+ if (copy && copytarget) {
+ copy->connect(E->get().signal,copytarget,E->get().method,E->get().binds,CONNECT_PERSIST);
+ }
+ }
+ }
+
+ for(int i=0;i<get_child_count();i++) {
+ get_child(i)->_duplicate_signals(p_original,p_copy);
+ }
+
+}
+
+
Node *Node::duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const {
@@ -1425,11 +1646,26 @@ Node *Node::duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const {
node->set_name(get_name());
+ List<PropertyInfo> plist;
+
+ get_property_list(&plist);
+
+ for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
+
+ if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
+ continue;
+ String name = E->get().name;
+ node->set( name, get(name) );
+
+ }
+
+
for(int i=0;i<get_child_count();i++) {
get_child(i)->_duplicate_and_reown(node,p_reown_map);
}
+ _duplicate_signals(this,node);
return node;
}
@@ -1611,29 +1847,29 @@ Node *Node::get_node_and_resource(const NodePath& p_path,RES& r_res) const {
return node;
}
-void Node::_set_scene(SceneMainLoop *p_scene) {
+void Node::_set_tree(SceneTree *p_tree) {
- SceneMainLoop *tree_changed_a=NULL;
- SceneMainLoop *tree_changed_b=NULL;
+ SceneTree *tree_changed_a=NULL;
+ SceneTree *tree_changed_b=NULL;
// ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null
- if (data.scene) {
- _propagate_exit_scene();
+ if (data.tree) {
+ _propagate_exit_tree();
- tree_changed_a=data.scene;
+ tree_changed_a=data.tree;
}
- data.scene=p_scene;
+ data.tree=p_tree;
- if (data.scene) {
+ if (data.tree) {
- _propagate_enter_scene();
+ _propagate_enter_tree();
_propagate_ready(); //reverse_notification(NOTIFICATION_READY);
- tree_changed_b=data.scene;
+ tree_changed_b=data.tree;
}
@@ -1651,7 +1887,7 @@ static void _Node_debug_sn(Object *p_obj) {
if (!n)
return;
- if (n->is_inside_scene())
+ if (n->is_inside_tree())
return;
Node *p=n;
@@ -1683,8 +1919,8 @@ void Node::print_stray_nodes() {
void Node::queue_delete() {
- ERR_FAIL_COND( !is_inside_scene() );
- get_scene()->queue_delete(this);
+ ERR_FAIL_COND( !is_inside_tree() );
+ get_tree()->queue_delete(this);
}
Array Node::_get_children() const {
@@ -1712,24 +1948,55 @@ NodePath Node::get_import_path() const {
#endif
+static void _add_nodes_to_options(const Node *p_base,const Node *p_node,List<String>*r_options) {
+
+ if (p_node!=p_base && !p_node->get_owner())
+ return;
+ String n = p_base->get_path_to(p_node);
+ r_options->push_back("\""+n+"\"");
+ for(int i=0;i<p_node->get_child_count();i++) {
+ _add_nodes_to_options(p_base,p_node->get_child(i),r_options);
+ }
+}
+
+void Node::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+
+ String pf=p_function;
+ if ((pf=="has_node" || pf=="get_node") && p_idx==0) {
+
+ _add_nodes_to_options(this,this,r_options);
+ }
+ Object::get_argument_options(p_function,p_idx,r_options);
+}
+
+
+void Node::clear_internal_tree_resource_paths() {
+
+ clear_internal_resource_paths();
+ for(int i=0;i<data.children.size();i++) {
+ data.children[i]->clear_internal_tree_resource_paths();
+ }
+
+}
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("remove_and_delete_child","node:Node"),&Node::remove_and_delete_child);
ObjectTypeDB::bind_method(_MD("get_child_count"),&Node::get_child_count);
ObjectTypeDB::bind_method(_MD("get_children"),&Node::_get_children);
ObjectTypeDB::bind_method(_MD("get_child:Node","idx"),&Node::get_child);
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::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);
- ObjectTypeDB::bind_method(_MD("is_inside_scene"),&Node::is_inside_scene);
+ ObjectTypeDB::bind_method(_MD("is_inside_tree"),&Node::is_inside_tree);
ObjectTypeDB::bind_method(_MD("is_a_parent_of","node:Node"),&Node::is_a_parent_of);
ObjectTypeDB::bind_method(_MD("is_greater_than","node:Node"),&Node::is_greater_than);
ObjectTypeDB::bind_method(_MD("get_path"),&Node::get_path);
@@ -1766,23 +2033,27 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("print_stray_nodes"),&Node::_print_stray_nodes);
ObjectTypeDB::bind_method(_MD("get_position_in_parent"),&Node::get_position_in_parent);
- ObjectTypeDB::bind_method(_MD("get_scene:SceneMainLoop"),&Node::get_scene);
+ 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
- BIND_CONSTANT( NOTIFICATION_ENTER_SCENE );
- BIND_CONSTANT( NOTIFICATION_EXIT_SCENE );
+ BIND_CONSTANT( NOTIFICATION_ENTER_TREE );
+ BIND_CONSTANT( NOTIFICATION_EXIT_TREE );
BIND_CONSTANT( NOTIFICATION_MOVED_IN_PARENT );
//BIND_CONSTANT( NOTIFICATION_PARENT_DECONFIGURED );
BIND_CONSTANT( NOTIFICATION_READY );
@@ -1799,8 +2070,8 @@ void Node::_bind_methods() {
BIND_CONSTANT( PAUSE_MODE_PROCESS );
ADD_SIGNAL( MethodInfo("renamed") );
- ADD_SIGNAL( MethodInfo("enter_scene") );
- ADD_SIGNAL( MethodInfo("exit_scene") );
+ ADD_SIGNAL( MethodInfo("enter_tree") );
+ ADD_SIGNAL( MethodInfo("exit_tree") );
// ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/process" ),_SCS("set_process"),_SCS("is_processing") );
// ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/fixed_process" ), _SCS("set_fixed_process"),_SCS("is_fixed_processing") );
@@ -1810,8 +2081,8 @@ void Node::_bind_methods() {
BIND_VMETHOD( MethodInfo("_process",PropertyInfo(Variant::REAL,"delta")) );
BIND_VMETHOD( MethodInfo("_fixed_process",PropertyInfo(Variant::REAL,"delta")) );
- BIND_VMETHOD( MethodInfo("_enter_scene") );
- BIND_VMETHOD( MethodInfo("_exit_scene") );
+ BIND_VMETHOD( MethodInfo("_enter_tree") );
+ BIND_VMETHOD( MethodInfo("_exit_tree") );
BIND_VMETHOD( MethodInfo("_ready") );
BIND_VMETHOD( MethodInfo("_input",PropertyInfo(Variant::INPUT_EVENT,"event")) );
BIND_VMETHOD( MethodInfo("_unhandled_input",PropertyInfo(Variant::INPUT_EVENT,"event")) );
@@ -1828,10 +2099,10 @@ Node::Node() {
data.depth=-1;
data.blocked=0;
data.parent=NULL;
- data.scene=NULL;
+ data.tree=NULL;
data.fixed_process=false;
data.idle_process=false;
- data.inside_scene=false;
+ data.inside_tree=false;
data.owner=NULL;
data.OW=NULL;
@@ -1843,6 +2114,7 @@ Node::Node() {
data.parent_owned=false;
data.in_constructor=true;
data.viewport=NULL;
+ data.use_placeholder=false;
}
Node::~Node() {
@@ -1859,3 +2131,4 @@ Node::~Node() {
}
+////////////////////////////////
diff --git a/scene/main/node.h b/scene/main/node.h
index f1ecf497e0..196c4a06eb 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -80,8 +82,8 @@ private:
int depth;
int blocked; // safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
StringName name;
- SceneMainLoop *scene;
- bool inside_scene;
+ SceneTree *tree;
+ bool inside_tree;
#ifdef TOOLS_ENABLED
NodePath import_path; //path used when imported, used by scene editors to keep tracking
#endif
@@ -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,27 +118,30 @@ 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);
- void _propagate_enter_scene();
+ void _propagate_enter_tree();
void _propagate_ready();
- void _propagate_exit_scene();
+ void _propagate_exit_tree();
void _propagate_validate_owner();
void _print_stray_nodes();
void _propagate_pause_owner(Node*p_owner);
Array _get_node_and_resource(const NodePath& p_path);
+ void _duplicate_signals(const Node* p_original,Node* p_copy) const;
void _duplicate_and_reown(Node* p_new_parent, const Map<Node*,Node*>& p_reown_map) const;
Array _get_children() const;
Array _get_groups() const;
-friend class SceneMainLoop;
+friend class SceneTree;
- void _set_scene(SceneMainLoop *p_scene);
+ void _set_tree(SceneTree *p_tree);
protected:
void _block() { data.blocked++; }
@@ -142,13 +151,14 @@ protected:
virtual void add_child_notify(Node *p_child);
virtual void remove_child_notify(Node *p_child);
- void remove_and_delete_child(Node *p_child);
+ virtual void move_child_notify(Node *p_child);
+ //void remove_and_delete_child(Node *p_child);
void _propagate_replace_owner(Node *p_owner,Node* p_by_owner);
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);
@@ -158,8 +168,8 @@ public:
enum {
// you can make your own, but don't use the same numbers as other notifications in other nodes
- NOTIFICATION_ENTER_SCENE=10,
- NOTIFICATION_EXIT_SCENE =11,
+ NOTIFICATION_ENTER_TREE=10,
+ NOTIFICATION_EXIT_TREE =11,
NOTIFICATION_MOVED_IN_PARENT =12,
NOTIFICATION_READY=13,
//NOTIFICATION_PARENT_DECONFIGURED =15, - it's confusing, it's going away
@@ -169,6 +179,7 @@ public:
NOTIFICATION_PROCESS = 17,
NOTIFICATION_PARENTED=18,
NOTIFICATION_UNPARENTED=19,
+ NOTIFICATION_INSTANCED=20,
};
/* NODE/TREE */
@@ -176,20 +187,21 @@ 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;
Node *get_child(int p_index) const;
bool has_node(const NodePath& p_path) const;
Node *get_node(const NodePath& p_path) const;
+ Node* find_node(const String& p_mask,bool p_recursive=true,bool p_owned=true) const;
bool has_node_and_resource(const NodePath& p_path) const;
Node *get_node_and_resource(const NodePath& p_path,RES& r_res) const;
Node *get_parent() const;
- _FORCE_INLINE_ SceneMainLoop *get_scene() const { ERR_FAIL_COND_V( !data.scene, NULL ); return data.scene; }
+ _FORCE_INLINE_ SceneTree *get_tree() const { ERR_FAIL_COND_V( !data.tree, NULL ); return data.tree; }
- _FORCE_INLINE_ bool is_inside_scene() const { return data.inside_scene; }
+ _FORCE_INLINE_ bool is_inside_tree() const { return data.inside_tree; }
bool is_a_parent_of(const Node *p_node) const;
bool is_greater_than(const Node *p_node) const;
@@ -203,7 +215,7 @@ public:
struct GroupInfo {
- String name;
+ StringName name;
bool persistent;
};
@@ -224,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);
@@ -250,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);
@@ -270,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
@@ -283,6 +306,9 @@ public:
NodePath get_import_path() const;
#endif
+ void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
+
+ void clear_internal_tree_resource_paths();
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
@@ -296,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 8227046ecb..f49f626e78 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/main/resource_preloader.h b/scene/main/resource_preloader.h
index e1e3beb0b3..b3e7496fb7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp
index 492c7633c1..adf053f5c9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -41,16 +41,21 @@
#include "scene/scene_string_names.h"
#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 SceneMainLoop::tree_changed() {
+void SceneTree::tree_changed() {
tree_version++;
emit_signal(tree_changed_name);
}
-void SceneMainLoop::node_removed(Node *p_node) {
+void SceneTree::node_removed(Node *p_node) {
+ if (current_scene==p_node) {
+ current_scene=NULL;
+ }
emit_signal(node_removed_name,p_node);
if (call_lock>0)
call_skip.insert(p_node);
@@ -59,7 +64,7 @@ void SceneMainLoop::node_removed(Node *p_node) {
}
-void SceneMainLoop::add_to_group(const StringName& p_group, Node *p_node) {
+void SceneTree::add_to_group(const StringName& p_group, Node *p_node) {
Map<StringName,Group>::Element *E=group_map.find(p_group);
if (!E) {
@@ -74,7 +79,7 @@ void SceneMainLoop::add_to_group(const StringName& p_group, Node *p_node) {
E->get().last_tree_version=0;
}
-void SceneMainLoop::remove_from_group(const StringName& p_group, Node *p_node) {
+void SceneTree::remove_from_group(const StringName& p_group, Node *p_node) {
Map<StringName,Group>::Element *E=group_map.find(p_group);
ERR_FAIL_COND(!E);
@@ -85,7 +90,7 @@ void SceneMainLoop::remove_from_group(const StringName& p_group, Node *p_node) {
group_map.erase(E);
}
-void SceneMainLoop::_flush_transform_notifications() {
+void SceneTree::_flush_transform_notifications() {
SelfList<Node>* n = xform_change_list.first();
while(n) {
@@ -98,7 +103,7 @@ void SceneMainLoop::_flush_transform_notifications() {
}
}
-void SceneMainLoop::_flush_ugc() {
+void SceneTree::_flush_ugc() {
ugc_locked=true;
@@ -118,7 +123,7 @@ void SceneMainLoop::_flush_ugc() {
ugc_locked=false;
}
-void SceneMainLoop::_update_group_order(Group& g) {
+void SceneTree::_update_group_order(Group& g) {
if (g.last_tree_version==tree_version)
return;
@@ -134,7 +139,7 @@ void SceneMainLoop::_update_group_order(Group& g) {
}
-void SceneMainLoop::call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,VARIANT_ARG_DECLARE) {
+void SceneTree::call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,VARIANT_ARG_DECLARE) {
Map<StringName,Group>::Element *E=group_map.find(p_group);
if (!E)
@@ -216,7 +221,7 @@ void SceneMainLoop::call_group(uint32_t p_call_flags,const StringName& p_group,c
call_skip.clear();
}
-void SceneMainLoop::notify_group(uint32_t p_call_flags,const StringName& p_group,int p_notification) {
+void SceneTree::notify_group(uint32_t p_call_flags,const StringName& p_group,int p_notification) {
Map<StringName,Group>::Element *E=group_map.find(p_group);
if (!E)
@@ -266,7 +271,7 @@ void SceneMainLoop::notify_group(uint32_t p_call_flags,const StringName& p_group
call_skip.clear();
}
-void SceneMainLoop::set_group(uint32_t p_call_flags,const StringName& p_group,const String& p_name,const Variant& p_value) {
+void SceneTree::set_group(uint32_t p_call_flags,const StringName& p_group,const String& p_name,const Variant& p_value) {
Map<StringName,Group>::Element *E=group_map.find(p_group);
if (!E)
@@ -316,12 +321,12 @@ void SceneMainLoop::set_group(uint32_t p_call_flags,const StringName& p_group,co
call_skip.clear();
}
-void SceneMainLoop::set_input_as_handled() {
+void SceneTree::set_input_as_handled() {
input_handled=true;
}
-void SceneMainLoop::input_text( const String& p_text ) {
+void SceneTree::input_text( const String& p_text ) {
root_lock++;
@@ -330,16 +335,20 @@ void SceneMainLoop::input_text( const String& p_text ) {
}
-void SceneMainLoop::input_event( const InputEvent& p_event ) {
+void SceneTree::input_event( const InputEvent& p_event ) {
+
+ if (is_editor_hint() && (p_event.type==InputEvent::JOYSTICK_MOTION || p_event.type==InputEvent::JOYSTICK_BUTTON))
+ return; //avoid joy input on editor
root_lock++;
- last_id=p_event.ID;
+ //last_id=p_event.ID;
input_handled=false;
InputEvent ev = p_event;
+ ev.ID=++last_id; //this should work better
#if 0
switch(ev.type) {
@@ -393,7 +402,7 @@ void SceneMainLoop::input_event( const InputEvent& p_event ) {
#endif
- MainLoop::input_event(p_event);
+ MainLoop::input_event(ev);
#if 0
_call_input_pause("input","_input",ev);
@@ -415,7 +424,7 @@ void SceneMainLoop::input_event( const InputEvent& p_event ) {
//transform for the rest
#else
- call_group(GROUP_CALL_REALTIME,"_viewports","_vp_input",p_event); //special one for GUI, as controls use their own process check
+ call_group(GROUP_CALL_REALTIME,"_viewports","_vp_input",ev); //special one for GUI, as controls use their own process check
#endif
if (ScriptDebugger::get_singleton() && ScriptDebugger::get_singleton()->is_remote() && ev.type==InputEvent::KEY && ev.key.pressed && !ev.key.echo && ev.key.scancode==KEY_F8) {
@@ -440,7 +449,7 @@ void SceneMainLoop::input_event( const InputEvent& p_event ) {
}
#else
- call_group(GROUP_CALL_REALTIME,"_viewports","_vp_unhandled_input",p_event); //special one for GUI, as controls use their own process check
+ call_group(GROUP_CALL_REALTIME,"_viewports","_vp_unhandled_input",ev); //special one for GUI, as controls use their own process check
#endif
input_handled=true;
@@ -455,7 +464,7 @@ void SceneMainLoop::input_event( const InputEvent& p_event ) {
}
-void SceneMainLoop::init() {
+void SceneTree::init() {
//_quit=false;
accept_quit=true;
@@ -463,15 +472,14 @@ void SceneMainLoop::init() {
input_handled=false;
- editor_hint=false;
pause=false;
- root->_set_scene(this);
+ root->_set_tree(this);
MainLoop::init();
}
-bool SceneMainLoop::iteration(float p_time) {
+bool SceneTree::iteration(float p_time) {
root_lock++;
@@ -481,8 +489,10 @@ bool SceneMainLoop::iteration(float p_time) {
_flush_transform_notifications();
MainLoop::iteration(p_time);
-
fixed_process_time=p_time;
+
+ emit_signal("fixed_frame");
+
_notify_group_pause("fixed_process",Node::NOTIFICATION_FIXED_PROCESS);
_flush_ugc();
_flush_transform_notifications();
@@ -494,7 +504,7 @@ bool SceneMainLoop::iteration(float p_time) {
return _quit;
}
-bool SceneMainLoop::idle(float p_time){
+bool SceneTree::idle(float p_time){
// print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage()));
@@ -507,6 +517,8 @@ bool SceneMainLoop::idle(float p_time){
idle_process_time=p_time;
+ emit_signal("idle_frame");
+
_flush_transform_notifications();
_notify_group_pause("idle_process",Node::NOTIFICATION_PROCESS);
@@ -534,7 +546,7 @@ bool SceneMainLoop::idle(float p_time){
return _quit;
}
-void SceneMainLoop::finish() {
+void SceneTree::finish() {
_flush_delete_queue();
@@ -545,7 +557,7 @@ void SceneMainLoop::finish() {
MainLoop::finish();
if (root) {
- root->_set_scene(NULL);
+ root->_set_tree(NULL);
memdelete(root); //delete root
}
@@ -560,12 +572,12 @@ void SceneMainLoop::finish() {
}
-void SceneMainLoop::quit() {
+void SceneTree::quit() {
_quit=true;
}
-void SceneMainLoop::_notification(int p_notification) {
+void SceneTree::_notification(int p_notification) {
@@ -580,6 +592,7 @@ void SceneMainLoop::_notification(int p_notification) {
break;
}
} break;
+ case NOTIFICATION_OS_MEMORY_WARNING:
case NOTIFICATION_WM_FOCUS_IN:
case NOTIFICATION_WM_FOCUS_OUT: {
@@ -597,22 +610,191 @@ void SceneMainLoop::_notification(int p_notification) {
};
-void SceneMainLoop::set_auto_accept_quit(bool p_enable) {
+void SceneTree::set_auto_accept_quit(bool p_enable) {
accept_quit=p_enable;
}
-void SceneMainLoop::set_editor_hint(bool p_enabled) {
+void SceneTree::set_editor_hint(bool p_enabled) {
editor_hint=p_enabled;
}
-bool SceneMainLoop::is_editor_hint() const {
+bool SceneTree::is_editor_hint() const {
return editor_hint;
}
-void SceneMainLoop::set_pause(bool p_enabled) {
+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)
return;
@@ -623,12 +805,12 @@ void SceneMainLoop::set_pause(bool p_enabled) {
get_root()->propagate_notification(p_enabled ? Node::NOTIFICATION_PAUSED : Node::NOTIFICATION_UNPAUSED);
}
-bool SceneMainLoop::is_paused() const {
+bool SceneTree::is_paused() const {
return pause;
}
-void SceneMainLoop::_call_input_pause(const StringName& p_group,const StringName& p_method,const InputEvent& p_input) {
+void SceneTree::_call_input_pause(const StringName& p_group,const StringName& p_method,const InputEvent& p_input) {
Map<StringName,Group>::Element *E=group_map.find(p_group);
if (!E)
@@ -673,7 +855,7 @@ void SceneMainLoop::_call_input_pause(const StringName& p_group,const StringName
call_skip.clear();
}
-void SceneMainLoop::_notify_group_pause(const StringName& p_group,int p_notification) {
+void SceneTree::_notify_group_pause(const StringName& p_group,int p_notification) {
Map<StringName,Group>::Element *E=group_map.find(p_group);
if (!E)
@@ -723,13 +905,13 @@ void SceneMainLoop::_update_listener_2d() {
}
*/
-uint32_t SceneMainLoop::get_last_event_id() const {
+uint32_t SceneTree::get_last_event_id() const {
return last_id;
}
-Variant SceneMainLoop::_call_group(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+Variant SceneTree::_call_group(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
r_error.error=Variant::CallError::CALL_OK;
@@ -754,13 +936,13 @@ Variant SceneMainLoop::_call_group(const Variant** p_args, int p_argcount, Varia
}
-int64_t SceneMainLoop::get_frame() const {
+int64_t SceneTree::get_frame() const {
return current_frame;
}
-Array SceneMainLoop::_get_nodes_in_group(const StringName& p_group) {
+Array SceneTree::_get_nodes_in_group(const StringName& p_group) {
Array ret;
Map<StringName,Group>::Element *E=group_map.find(p_group);
@@ -783,7 +965,7 @@ Array SceneMainLoop::_get_nodes_in_group(const StringName& p_group) {
return ret;
}
-void SceneMainLoop::get_nodes_in_group(const StringName& p_group,List<Node*> *p_list) {
+void SceneTree::get_nodes_in_group(const StringName& p_group,List<Node*> *p_list) {
Map<StringName,Group>::Element *E=group_map.find(p_group);
@@ -813,9 +995,9 @@ static void _fill_array(Node *p_node, Array& array, int p_level) {
}
}
-void SceneMainLoop::_debugger_request_tree(void *self) {
+void SceneTree::_debugger_request_tree(void *self) {
- SceneMainLoop *sml = (SceneMainLoop *)self;
+ SceneTree *sml = (SceneTree *)self;
Array arr;
_fill_array(sml->root,arr,0);
@@ -823,7 +1005,7 @@ void SceneMainLoop::_debugger_request_tree(void *self) {
}
-void SceneMainLoop::_flush_delete_queue() {
+void SceneTree::_flush_delete_queue() {
_THREAD_SAFE_METHOD_
@@ -837,21 +1019,22 @@ void SceneMainLoop::_flush_delete_queue() {
}
}
-void SceneMainLoop::queue_delete(Object *p_object) {
+void SceneTree::queue_delete(Object *p_object) {
_THREAD_SAFE_METHOD_
ERR_FAIL_NULL(p_object);
+ p_object->_is_queued_for_deletion = true;
delete_queue.push_back(p_object->get_instance_ID());
}
-int SceneMainLoop::get_node_count() const {
+int SceneTree::get_node_count() const {
return node_count;
}
-void SceneMainLoop::_update_root_rect() {
+void SceneTree::_update_root_rect() {
if (stretch_mode==STRETCH_MODE_DISABLED) {
@@ -954,7 +1137,7 @@ void SceneMainLoop::_update_root_rect() {
}
-void SceneMainLoop::set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize) {
+void SceneTree::set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize) {
stretch_mode=p_mode;
stretch_aspect=p_aspect;
@@ -963,35 +1146,478 @@ void SceneMainLoop::set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect
}
-void SceneMainLoop::_bind_methods() {
+#ifdef TOOLS_ENABLED
+void SceneTree::set_edited_scene_root(Node *p_node) {
+ edited_scene_root=p_node;
+}
+
+Node *SceneTree::get_edited_scene_root() const {
+
+ return edited_scene_root;
+}
+#endif
+
+void SceneTree::set_current_scene(Node* p_scene) {
+
+ ERR_FAIL_COND(p_scene && p_scene->get_parent()!=root);
+ current_scene=p_scene;
+}
+
+Node* SceneTree::get_current_scene() const{
+
+ return current_scene;
+}
+
+void SceneTree::_change_scene(Node* p_to) {
+
+ if (current_scene) {
+ memdelete( current_scene );
+ current_scene=NULL;
+ }
+
+ if (p_to) {
+ current_scene=p_to;
+ root->add_child(p_to);
+ }
+}
+
+Error SceneTree::change_scene(const String& p_path){
+
+ Ref<PackedScene> new_scene = ResourceLoader::load(p_path);
+ if (new_scene.is_null())
+ return ERR_CANT_OPEN;
+
+ return change_scene_to(new_scene);
+
+}
+Error SceneTree::change_scene_to(const Ref<PackedScene>& p_scene){
+
+ Node *new_scene=NULL;
+ if (p_scene.is_valid()) {
+ new_scene = p_scene->instance();
+ ERR_FAIL_COND_V(!new_scene,ERR_CANT_CREATE);
+ }
+
+ call_deferred("_change_scene",new_scene);
+ return OK;
+
+}
+Error SceneTree::reload_current_scene() {
+
+ ERR_FAIL_COND_V(!current_scene,ERR_UNCONFIGURED);
+ String fname = current_scene->get_filename();
+ return change_scene(fname);
+}
+
+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() {
//ObjectTypeDB::bind_method(_MD("call_group","call_flags","group","method","arg1","arg2"),&SceneMainLoop::_call_group,DEFVAL(Variant()),DEFVAL(Variant()));
- ObjectTypeDB::bind_method(_MD("notify_group","call_flags","group","notification"),&SceneMainLoop::notify_group);
- ObjectTypeDB::bind_method(_MD("set_group","call_flags","group","property","value"),&SceneMainLoop::set_group);
+ 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"),&SceneMainLoop::_get_nodes_in_group);
+ ObjectTypeDB::bind_method(_MD("get_root:Viewport"),&SceneTree::get_root);
- ObjectTypeDB::bind_method(_MD("get_root:Viewport"),&SceneMainLoop::get_root);
+ ObjectTypeDB::bind_method(_MD("set_auto_accept_quit","enabled"),&SceneTree::set_auto_accept_quit);
- ObjectTypeDB::bind_method(_MD("set_auto_accept_quit","enabled"),&SceneMainLoop::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);
- ObjectTypeDB::bind_method(_MD("set_editor_hint","enable"),&SceneMainLoop::set_editor_hint);
- ObjectTypeDB::bind_method(_MD("is_editor_hint"),&SceneMainLoop::is_editor_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);
+#endif
+
+ ObjectTypeDB::bind_method(_MD("set_pause","enable"),&SceneTree::set_pause);
+ ObjectTypeDB::bind_method(_MD("is_paused"),&SceneTree::is_paused);
+ ObjectTypeDB::bind_method(_MD("set_input_as_handled"),&SceneTree::set_input_as_handled);
- ObjectTypeDB::bind_method(_MD("set_pause","enable"),&SceneMainLoop::set_pause);
- ObjectTypeDB::bind_method(_MD("is_paused"),&SceneMainLoop::is_paused);
- ObjectTypeDB::bind_method(_MD("set_input_as_handled"),&SceneMainLoop::set_input_as_handled);
+ ObjectTypeDB::bind_method(_MD("get_node_count"),&SceneTree::get_node_count);
+ ObjectTypeDB::bind_method(_MD("get_frame"),&SceneTree::get_frame);
+ ObjectTypeDB::bind_method(_MD("quit"),&SceneTree::quit);
- ObjectTypeDB::bind_method(_MD("get_node_count"),&SceneMainLoop::get_node_count);
- ObjectTypeDB::bind_method(_MD("get_frame"),&SceneMainLoop::get_frame);
- ObjectTypeDB::bind_method(_MD("quit"),&SceneMainLoop::quit);
+ ObjectTypeDB::bind_method(_MD("set_screen_stretch","mode","aspect","minsize"),&SceneTree::set_screen_stretch);
- ObjectTypeDB::bind_method(_MD("set_screen_stretch","mode","aspect","minsize"),&SceneMainLoop::set_screen_stretch);
+ ObjectTypeDB::bind_method(_MD("queue_delete","obj"),&SceneTree::queue_delete);
- ObjectTypeDB::bind_method(_MD("queue_delete","obj"),&SceneMainLoop::queue_delete);
MethodInfo mi;
@@ -1005,12 +1631,25 @@ void SceneMainLoop::_bind_methods() {
defargs.push_back(Variant());
}
- ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_group",&SceneMainLoop::_call_group,mi,defargs);
+ ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_group",&SceneTree::_call_group,mi,defargs);
+
+ ObjectTypeDB::bind_method(_MD("set_current_scene","child_node:Node"),&SceneTree::set_current_scene);
+ ObjectTypeDB::bind_method(_MD("get_current_scene:Node"),&SceneTree::get_current_scene);
+
+ ObjectTypeDB::bind_method(_MD("change_scene","path"),&SceneTree::change_scene);
+ ObjectTypeDB::bind_method(_MD("change_scene_to","packed_scene:PackedScene"),&SceneTree::change_scene_to);
+
+ ObjectTypeDB::bind_method(_MD("reload_current_scene"),&SceneTree::reload_current_scene);
+
+ ObjectTypeDB::bind_method(_MD("_change_scene"),&SceneTree::_change_scene);
ADD_SIGNAL( MethodInfo("tree_changed") );
ADD_SIGNAL( MethodInfo("node_removed",PropertyInfo( Variant::OBJECT, "node") ) );
ADD_SIGNAL( MethodInfo("screen_resized") );
+ ADD_SIGNAL( MethodInfo("idle_frame"));
+ ADD_SIGNAL( MethodInfo("fixed_frame"));
+
BIND_CONSTANT( GROUP_CALL_DEFAULT );
BIND_CONSTANT( GROUP_CALL_REVERSE );
BIND_CONSTANT( GROUP_CALL_REALTIME );
@@ -1026,14 +1665,27 @@ void SceneMainLoop::_bind_methods() {
}
-SceneMainLoop::SceneMainLoop() {
+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;
- last_id=0;
+ last_id=1;
root=NULL;
current_frame=0;
tree_changed_name="tree_changed";
@@ -1051,6 +1703,7 @@ SceneMainLoop::SceneMainLoop() {
//root->set_world_2d( Ref<World2D>( memnew( World2D )));
root->set_as_audio_listener(true);
root->set_as_audio_listener_2d(true);
+ current_scene=NULL;
stretch_mode=STRETCH_MODE_DISABLED;
stretch_aspect=STRETCH_ASPECT_IGNORE;
@@ -1062,10 +1715,47 @@ SceneMainLoop::SceneMainLoop() {
ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree,this);
}
+ root->set_physics_object_picking(GLOBAL_DEF("physics/enable_object_picking",true));
+
+#ifdef TOOLS_ENABLED
+ 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
+
+
}
-SceneMainLoop::~SceneMainLoop() {
+SceneTree::~SceneTree() {
}
diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h
index 493644d2bc..8d9021d24e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -41,16 +41,18 @@
*/
-class SceneMainLoop;
-
+class SceneTree;
+class PackedScene;
class Node;
class Viewport;
+class Material;
+class Mesh;
-class SceneMainLoop : public MainLoop {
+class SceneTree : public MainLoop {
_THREAD_SAFE_CLASS_
- OBJ_TYPE( SceneMainLoop, MainLoop );
+ OBJ_TYPE( SceneTree, MainLoop );
public:
@@ -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;
@@ -102,6 +106,9 @@ private:
int64_t current_frame;
int node_count;
+#ifdef TOOLS_ENABLED
+ Node *edited_scene_root;
+#endif
struct UGCall {
StringName group;
@@ -133,9 +140,22 @@ private:
Array _get_nodes_in_group(const StringName& p_group);
+ 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();
@@ -159,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);
@@ -213,6 +285,32 @@ public:
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;
@@ -223,15 +321,34 @@ public:
void set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize);
+ //void change_scene(const String& p_path);
+ //Node *get_loaded_scene();
+
+#ifdef TOOLS_ENABLED
+ void set_edited_scene_root(Node *p_node);
+ Node *get_edited_scene_root() const;
+#endif
+
+ void set_current_scene(Node* p_scene);
+ Node* get_current_scene() const;
+ Error change_scene(const String& p_path);
+ Error change_scene_to(const Ref<PackedScene>& p_scene);
+ Error reload_current_scene();
+
+ //used by Main::start, don't use otherwise
+ void add_current_scene(Node * p_current);
+
+ static SceneTree* get_singleton() { return singleton; }
+
- SceneMainLoop();
- ~SceneMainLoop();
+ SceneTree();
+ ~SceneTree();
};
-VARIANT_ENUM_CAST( SceneMainLoop::StretchMode );
-VARIANT_ENUM_CAST( SceneMainLoop::StretchAspect );
+VARIANT_ENUM_CAST( SceneTree::StretchMode );
+VARIANT_ENUM_CAST( SceneTree::StretchAspect );
diff --git a/scene/main/scene_singleton.cpp b/scene/main/scene_singleton.cpp
index 042164a1f3..69eb6e24d9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/main/scene_singleton.h b/scene/main/scene_singleton.h
index 1e0359fe91..25157a26ac 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index 25d1c8530e..1bd22a9db1 100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,16 +36,23 @@ void Timer::_notification(int p_what) {
case NOTIFICATION_READY: {
- if (autostart)
+ if (autostart) {
+#ifdef TOOLS_ENABLED
+ if (get_tree()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()==this || get_tree()->get_edited_scene_root()->is_a_parent_of(this)))
+ break;
+#endif
start();
+ }
} break;
case NOTIFICATION_PROCESS: {
-
+ if (timer_process_mode == TIMER_PROCESS_FIXED || !is_processing())
+ return;
time_left -= get_process_delta_time();
if (time_left<0) {
if (!one_shot)
- time_left=wait_time+time_left;
+ //time_left=wait_time+time_left;
+ time_left = wait_time;
else
stop();
@@ -53,13 +60,27 @@ void Timer::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_FIXED_PROCESS: {
+ if (timer_process_mode == TIMER_PROCESS_IDLE || !is_fixed_processing())
+ return;
+ time_left -= get_fixed_process_delta_time();
+
+ if (time_left<0) {
+ if (!one_shot)
+ //time_left = wait_time + time_left;
+ time_left = wait_time;
+ else
+ stop();
+ emit_signal("timeout");
+ }
+
+ } break;
}
}
void Timer::set_wait_time(float p_time) {
-
ERR_EXPLAIN("time should be greater than zero.");
ERR_FAIL_COND(p_time<=0);
wait_time=p_time;
@@ -89,14 +110,13 @@ bool Timer::has_autostart() const {
}
void Timer::start() {
-
time_left=wait_time;
- set_process(true);
+ _set_process(true);
}
void Timer::stop() {
time_left=-1;
- set_process(false);
+ _set_process(false);
autostart=false;
}
@@ -105,6 +125,41 @@ float Timer::get_time_left() const {
return time_left >0 ? time_left : 0;
}
+void Timer::set_timer_process_mode(TimerProcessMode p_mode) {
+
+ if (timer_process_mode == p_mode)
+ return;
+
+ switch (timer_process_mode) {
+ case TIMER_PROCESS_FIXED:
+ if (is_fixed_processing()) {
+ set_fixed_process(false);
+ set_process(true);
+ }
+ break;
+ case TIMER_PROCESS_IDLE:
+ if (is_processing()) {
+ set_process(false);
+ set_fixed_process(true);
+ }
+ break;
+ }
+ timer_process_mode = p_mode;
+}
+
+Timer::TimerProcessMode Timer::get_timer_process_mode() const{
+
+ return timer_process_mode;
+}
+
+
+void Timer::_set_process(bool p_process, bool p_force)
+{
+ switch (timer_process_mode) {
+ case TIMER_PROCESS_FIXED: set_fixed_process(p_process); break;
+ case TIMER_PROCESS_IDLE: set_process(p_process); break;
+ }
+}
void Timer::_bind_methods() {
@@ -122,17 +177,23 @@ void Timer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_time_left"),&Timer::get_time_left);
+ ObjectTypeDB::bind_method(_MD("set_timer_process_mode", "mode"), &Timer::set_timer_process_mode);
+ ObjectTypeDB::bind_method(_MD("get_timer_process_mode"), &Timer::get_timer_process_mode);
+
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::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() {
-
-
+ timer_process_mode = TIMER_PROCESS_IDLE;
autostart=false;
wait_time=1;
one_shot=false;
diff --git a/scene/main/timer.h b/scene/main/timer.h
index b89cd10664..4b9cecba84 100644
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,6 +46,11 @@ protected:
static void _bind_methods();
public:
+ enum TimerProcessMode {
+ TIMER_PROCESS_FIXED,
+ TIMER_PROCESS_IDLE,
+ };
+
void set_wait_time(float p_time);
float get_wait_time() const;
@@ -60,7 +65,16 @@ public:
float get_time_left() const;
+ void set_timer_process_mode(TimerProcessMode p_mode);
+ TimerProcessMode get_timer_process_mode() const;
Timer();
+
+private:
+ TimerProcessMode timer_process_mode;
+ void _set_process(bool p_process, bool p_force = false);
+
};
+VARIANT_ENUM_CAST(Timer::TimerProcessMode);
+
#endif // TIMER_H
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index defa7da6ae..d19b5767c2 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,15 +29,19 @@
#include "viewport.h"
#include "os/os.h"
#include "scene/3d/spatial.h"
+#include "os/input.h"
+#include "servers/physics_2d_server.h"
//#include "scene/3d/camera.h"
#include "servers/spatial_sound_server.h"
#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"
int RenderTargetTexture::get_width() const {
@@ -94,13 +98,17 @@ void Viewport::_update_stretch_transform() {
if (size_override_stretch && size_override) {
+ //print_line("sive override size "+size_override_size);
+ //print_line("rect size "+rect.size);
stretch_transform=Matrix32();
Size2 scale = rect.size/(size_override_size+size_override_margin*2);
stretch_transform.scale(scale);
stretch_transform.elements[2]=size_override_margin*scale;
+
} else {
+
stretch_transform=Matrix32();
}
@@ -110,7 +118,7 @@ void Viewport::_update_stretch_transform() {
void Viewport::_update_rect() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
Node *parent = get_parent();
@@ -132,7 +140,9 @@ void Viewport::_update_rect() {
}
vr.width=rect.size.width;
vr.height=rect.size.height;
+
VisualServer::get_singleton()->viewport_set_rect(viewport,vr);
+ last_vp_rect=rect;
if (canvas_item.is_valid()) {
VisualServer::get_singleton()->canvas_item_set_custom_rect(canvas_item,true,rect);
@@ -161,13 +171,16 @@ void Viewport::_parent_visibility_changed() {
Control *c = parent->cast_to<Control>();
VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,c->is_visible());
+
+ _update_listener();
+ _update_listener_2d();
}
}
-void Viewport::_vp_enter_scene() {
+void Viewport::_vp_enter_tree() {
Node *parent = get_parent();
//none?
@@ -192,7 +205,7 @@ void Viewport::_vp_enter_scene() {
}
-void Viewport::_vp_exit_scene() {
+void Viewport::_vp_exit_tree() {
Node *parent = get_parent();
if (parent && parent->cast_to<Control>()) {
@@ -223,14 +236,48 @@ void Viewport::_vp_exit_scene() {
void Viewport::update_worlds() {
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
Rect2 xformed_rect = (global_canvas_transform * canvas_transform).affine_inverse().xform(get_visible_rect());
find_world_2d()->_update_viewport(this,xformed_rect);
find_world_2d()->_update();
- find_world()->_update(get_scene()->get_frame());
+ find_world()->_update(get_tree()->get_frame());
+}
+
+
+void Viewport::_test_new_mouseover(ObjectID new_collider) {
+#ifndef _3D_DISABLED
+ if (new_collider!=physics_object_over) {
+
+ if (physics_object_over) {
+ Object *obj = ObjectDB::get_instance(physics_object_over);
+ if (obj) {
+ CollisionObject *co = obj->cast_to<CollisionObject>();
+ if (co) {
+ co->_mouse_exit();
+ }
+ }
+ }
+
+ if (new_collider) {
+ Object *obj = ObjectDB::get_instance(new_collider);
+ if (obj) {
+ CollisionObject *co = obj->cast_to<CollisionObject>();
+ if (co) {
+ co->_mouse_enter();
+
+ }
+ }
+
+ }
+
+ physics_object_over=new_collider;
+
+ }
+#endif
+
}
void Viewport::_notification(int p_what) {
@@ -238,11 +285,11 @@ void Viewport::_notification(int p_what) {
switch( p_what ) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
if (!render_target)
- _vp_enter_scene();
+ _vp_enter_tree();
this->parent=NULL;
Node *parent=get_parent();
@@ -273,6 +320,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: {
@@ -292,7 +356,7 @@ void Viewport::_notification(int p_what) {
}
#endif
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
@@ -300,14 +364,280 @@ void Viewport::_notification(int p_what) {
world_2d->_remove_viewport(this);
if (!render_target)
- _vp_exit_scene();
+ _vp_exit_tree();
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");
} 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);
+ CollisionObject *last_object;
+ ObjectID last_id=0;
+ PhysicsDirectSpaceState::RayResult result;
+ Physics2DDirectSpaceState *ss2d=Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
+
+ bool motion_tested=false;
+
+ while(physics_picking_events.size()) {
+
+ InputEvent ev = physics_picking_events.front()->get();
+ physics_picking_events.pop_front();
+
+ Vector2 pos;
+ switch(ev.type) {
+ case InputEvent::MOUSE_MOTION: {
+ pos.x=ev.mouse_motion.x;
+ pos.y=ev.mouse_motion.y;
+ motion_tested=true;
+ physics_last_mousepos=pos;
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+ pos.x=ev.mouse_button.x;
+ pos.y=ev.mouse_button.y;
+
+ } break;
+ case InputEvent::SCREEN_DRAG: {
+ pos.x=ev.screen_drag.x;
+ pos.y=ev.screen_drag.y;
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+ pos.x=ev.screen_touch.x;
+ pos.y=ev.screen_touch.y;
+ } break;
+
+ }
+
+ if (ss2d) {
+ //send to 2D
+
+
+ uint64_t frame = get_tree()->get_frame();
+
+ Vector2 point = get_canvas_transform().affine_inverse().xform(pos);
+ Physics2DDirectSpaceState::ShapeResult res[64];
+ int rc = ss2d->intersect_point(point,res,64,Set<RID>(),0xFFFFFFFF,0xFFFFFFFF);
+ for(int i=0;i<rc;i++) {
+
+ if (res[i].collider_id && res[i].collider) {
+ CollisionObject2D *co=res[i].collider->cast_to<CollisionObject2D>();
+ if (co) {
+
+ Map<ObjectID,uint64_t>::Element *E=physics_2d_mouseover.find(res[i].collider_id);
+ if (!E) {
+ E=physics_2d_mouseover.insert(res[i].collider_id,frame);
+ co->_mouse_enter();
+ } else {
+ E->get()=frame;
+ }
+
+ co->_input_event(this,ev,res[i].shape);
+ }
+ }
+ }
+
+ List<Map<ObjectID,uint64_t>::Element*> to_erase;
+
+ for (Map<ObjectID,uint64_t>::Element*E=physics_2d_mouseover.front();E;E=E->next()) {
+ if (E->get()!=frame) {
+ Object *o=ObjectDB::get_instance(E->key());
+ if (o) {
+
+ CollisionObject2D *co=o->cast_to<CollisionObject2D>();
+ if (co) {
+ co->_mouse_exit();
+ }
+ }
+ to_erase.push_back(E);
+ }
+ }
+
+ while(to_erase.size()) {
+ physics_2d_mouseover.erase(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+ }
+
+
+
+#ifndef _3D_DISABLED
+ bool captured=false;
+
+ if (physics_object_capture!=0) {
+
+
+ Object *obj = ObjectDB::get_instance(physics_object_capture);
+ if (obj) {
+ CollisionObject *co = obj->cast_to<CollisionObject>();
+ if (co) {
+ co->_input_event(camera,ev,Vector3(),Vector3(),0);
+ captured=true;
+ if (ev.type==InputEvent::MOUSE_BUTTON && ev.mouse_button.button_index==1 && !ev.mouse_button.pressed) {
+ physics_object_capture=0;
+ }
+
+ } else {
+ physics_object_capture=0;
+ }
+ } else {
+ physics_object_capture=0;
+ }
+ }
+
+
+ if (captured) {
+ //none
+ } else if (pos==last_pos) {
+
+ if (last_id) {
+ if (ObjectDB::get_instance(last_id)) {
+ //good, exists
+ last_object->_input_event(camera,ev,result.position,result.normal,result.shape);
+ if (last_object->get_capture_input_on_drag() && ev.type==InputEvent::MOUSE_BUTTON && ev.mouse_button.button_index==1 && ev.mouse_button.pressed) {
+ physics_object_capture=last_id;
+ }
+
+
+ }
+ }
+ } else {
+
+
+
+
+ if (camera) {
+
+ Vector3 from = camera->project_ray_origin(pos);
+ Vector3 dir = camera->project_ray_normal(pos);
+
+ 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);
+ ObjectID new_collider=0;
+ if (col) {
+
+ if (result.collider) {
+
+ CollisionObject *co = result.collider->cast_to<CollisionObject>();
+ if (co) {
+
+ co->_input_event(camera,ev,result.position,result.normal,result.shape);
+ last_object=co;
+ last_id=result.collider_id;
+ new_collider=last_id;
+ if (co->get_capture_input_on_drag() && ev.type==InputEvent::MOUSE_BUTTON && ev.mouse_button.button_index==1 && ev.mouse_button.pressed) {
+ physics_object_capture=last_id;
+ }
+
+ }
+ }
+ }
+
+ if (ev.type==InputEvent::MOUSE_MOTION) {
+ _test_new_mouseover(new_collider);
+ }
+ }
+
+ last_pos=pos;
+ }
+ }
+ }
+
+ if (!motion_tested && camera && physics_last_mousepos!=Vector2(1e20,1e20)) {
+
+ //test anyway for mouseenter/exit because objects might move
+ Vector3 from = camera->project_ray_origin(physics_last_mousepos);
+ Vector3 dir = camera->project_ray_normal(physics_last_mousepos);
+
+ 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);
+ ObjectID new_collider=0;
+ if (col) {
+ if (result.collider) {
+ CollisionObject *co = result.collider->cast_to<CollisionObject>();
+ if (co) {
+ new_collider=result.collider_id;
+
+ }
+ }
+ }
+
+ _test_new_mouseover(new_collider);
+
+ }
+#endif
+ }
+
+ }
+
+ } break;
}
}
@@ -321,6 +651,7 @@ void Viewport::set_rect(const Rect2& p_rect) {
if (rect==p_rect)
return;
rect=p_rect;
+
_update_rect();
_update_stretch_transform();
@@ -355,7 +686,7 @@ Rect2 Viewport::get_rect() const {
void Viewport::_update_listener() {
- if (is_inside_scene() && audio_listener && camera) {
+ if (is_inside_tree() && audio_listener && camera && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible()))) {
SpatialSoundServer::get_singleton()->listener_set_space(listener,find_world()->get_sound_space());
} else {
SpatialSoundServer::get_singleton()->listener_set_space(listener,RID());
@@ -366,7 +697,7 @@ void Viewport::_update_listener() {
void Viewport::_update_listener_2d() {
- if (is_inside_scene() && audio_listener_2d)
+ if (is_inside_tree() && audio_listener && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible())))
SpatialSound2DServer::get_singleton()->listener_set_space(listener_2d,find_world_2d()->get_sound_space());
else
SpatialSound2DServer::get_singleton()->listener_set_space(listener_2d,RID());
@@ -545,7 +876,7 @@ void Viewport::_propagate_enter_world(Node *p_node) {
if (p_node!=this) {
- if (!p_node->is_inside_scene()) //may not have entered scene yet
+ if (!p_node->is_inside_tree()) //may not have entered scene yet
return;
Spatial *s = p_node->cast_to<Spatial>();
@@ -574,7 +905,7 @@ void Viewport::_propagate_exit_world(Node *p_node) {
if (p_node!=this) {
- if (!p_node->is_inside_scene()) //may have exited scene already
+ if (!p_node->is_inside_tree()) //may have exited scene already
return;
Spatial *s = p_node->cast_to<Spatial>();
@@ -605,7 +936,7 @@ void Viewport::set_world(const Ref<World>& p_world) {
if (world==p_world)
return;
- if (is_inside_scene())
+ if (is_inside_tree())
_propagate_exit_world(this);
#ifndef _3D_DISABLED
@@ -615,7 +946,7 @@ void Viewport::set_world(const Ref<World>& p_world) {
world=p_world;
- if (is_inside_scene())
+ if (is_inside_tree())
_propagate_enter_world(this);
#ifndef _3D_DISABLED
@@ -625,7 +956,7 @@ void Viewport::set_world(const Ref<World>& p_world) {
//propagate exit
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
VisualServer::get_singleton()->viewport_set_scenario(viewport,find_world()->get_scenario());
}
@@ -713,12 +1044,12 @@ void Viewport::set_as_render_target(bool p_enable){
render_target=p_enable;
VS::get_singleton()->viewport_set_as_render_target(viewport,p_enable);
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
if (p_enable)
- _vp_exit_scene();
+ _vp_exit_tree();
else
- _vp_enter_scene();
+ _vp_enter_tree();
}
if (p_enable) {
@@ -774,6 +1105,22 @@ bool Viewport::get_render_target_vflip() const{
return render_target_vflip;
}
+void Viewport::set_render_target_clear_on_new_frame(bool p_enable) {
+
+ render_target_clear_on_new_frame=p_enable;
+ VisualServer::get_singleton()->viewport_set_render_target_clear_on_new_frame(viewport,p_enable);
+}
+
+bool Viewport::get_render_target_clear_on_new_frame() const{
+
+ return render_target_clear_on_new_frame;
+}
+
+void Viewport::render_target_clear() {
+
+ //render_target_clear=true;
+ VisualServer::get_singleton()->viewport_render_target_clear(viewport);
+}
void Viewport::set_render_target_filter(bool p_enable) {
@@ -786,6 +1133,19 @@ bool Viewport::get_render_target_filter() const{
return (render_target_texture->get_flags()&Texture::FLAG_FILTER)!=0;
}
+void Viewport::set_render_target_gen_mipmaps(bool p_enable) {
+
+ //render_target_texture->set_flags(p_enable?int(Texture::FLAG_FILTER):int(0));
+ render_target_gen_mipmaps=p_enable;
+
+}
+
+bool Viewport::get_render_target_gen_mipmaps() const{
+
+ //return (render_target_texture->get_flags()&Texture::FLAG_FILTER)!=0;
+ return render_target_gen_mipmaps;
+}
+
Matrix32 Viewport::_get_input_pre_xform() const {
@@ -794,8 +1154,9 @@ Matrix32 Viewport::_get_input_pre_xform() const {
ERR_FAIL_COND_V(to_screen_rect.size.x==0,pre_xf);
ERR_FAIL_COND_V(to_screen_rect.size.y==0,pre_xf);
- pre_xf.scale(rect.size/to_screen_rect.size);
+
pre_xf.elements[2]=-to_screen_rect.pos;
+ pre_xf.scale(rect.size/to_screen_rect.size);
} else {
pre_xf.elements[2]=-rect.pos;
@@ -824,13 +1185,16 @@ void Viewport::_make_input_local(InputEvent& ev) {
Matrix32 ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
Vector2 g = ai.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y));
Vector2 l = ai.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y));
- Vector2 r = ai.xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y));
+ Vector2 r = ai.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y));
+ Vector2 s = ai.basis_xform(Vector2(ev.mouse_motion.speed_x,ev.mouse_motion.speed_y));
ev.mouse_motion.x=l.x;
ev.mouse_motion.y=l.y;
ev.mouse_motion.global_x=g.x;
ev.mouse_motion.global_y=g.y;
ev.mouse_motion.relative_x=r.x;
ev.mouse_motion.relative_y=r.y;
+ ev.mouse_motion.speed_x=s.x;
+ ev.mouse_motion.speed_y=s.y;
} break;
case InputEvent::SCREEN_TOUCH: {
@@ -845,8 +1209,8 @@ void Viewport::_make_input_local(InputEvent& ev) {
Matrix32 ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
Vector2 t = ai.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y));
- Vector2 r = ai.xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y));
- Vector2 s = ai.xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y));
+ Vector2 r = ai.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y));
+ Vector2 s = ai.basis_xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y));
ev.screen_drag.x=t.x;
ev.screen_drag.y=t.y;
ev.screen_drag.relative_x=r.x;
@@ -856,6 +1220,7 @@ void Viewport::_make_input_local(InputEvent& ev) {
} break;
}
+
}
@@ -875,7 +1240,8 @@ void Viewport::_vp_input(const InputEvent& p_ev) {
void Viewport::_vp_unhandled_input(const InputEvent& p_ev) {
- if (render_target)
+
+ 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
@@ -887,23 +1253,43 @@ void Viewport::_vp_unhandled_input(const InputEvent& p_ev) {
}
+Vector2 Viewport::get_mouse_pos() const {
+
+ return (get_final_transform().affine_inverse() * _get_input_pre_xform()).xform(Input::get_singleton()->get_mouse_pos());
+}
+
+void Viewport::warp_mouse(const Vector2& p_pos) {
+
+ Vector2 gpos = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse().xform(p_pos);
+ Input::get_singleton()->warp_mouse_pos(gpos);
+}
+
void Viewport::input(const InputEvent& p_event) {
- ERR_FAIL_COND(!is_inside_scene());
- get_scene()->_call_input_pause(input_group,"_input",p_event);
- get_scene()->call_group(SceneMainLoop::GROUP_CALL_REVERSE|SceneMainLoop::GROUP_CALL_REALTIME|SceneMainLoop::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check
+ 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
}
void Viewport::unhandled_input(const InputEvent& p_event) {
- ERR_FAIL_COND(!is_inside_scene());
+ ERR_FAIL_COND(!is_inside_tree());
- get_scene()->_call_input_pause(unhandled_input_group,"_unhandled_input",p_event);
+ 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_scene()->input_handled && p_event.type==InputEvent::KEY) {
- get_scene()->_call_input_pause(unhandled_key_input_group,"_unhandled_key_input",p_event);
+ if (!get_tree()->input_handled && p_event.type==InputEvent::KEY) {
+ get_tree()->_call_input_pause(unhandled_key_input_group,"_unhandled_key_input",p_event);
//call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev);
}
+
+
+ if (physics_object_picking && !get_tree()->input_handled) {
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON || p_event.type==InputEvent::MOUSE_MOTION || p_event.type==InputEvent::SCREEN_DRAG || p_event.type==InputEvent::SCREEN_TOUCH) {
+ physics_picking_events.push_back(p_event);
+ }
+ }
+
}
void Viewport::set_use_own_world(bool p_world) {
@@ -912,7 +1298,7 @@ void Viewport::set_use_own_world(bool p_world) {
return;
- if (is_inside_scene())
+ if (is_inside_tree())
_propagate_exit_world(this);
#ifndef _3D_DISABLED
@@ -925,7 +1311,7 @@ void Viewport::set_use_own_world(bool p_world) {
else
own_world=Ref<World>( memnew( World ));
- if (is_inside_scene())
+ if (is_inside_tree())
_propagate_enter_world(this);
#ifndef _3D_DISABLED
@@ -935,7 +1321,7 @@ void Viewport::set_use_own_world(bool p_world) {
//propagate exit
- if (is_inside_scene()) {
+ if (is_inside_tree()) {
VisualServer::get_singleton()->viewport_set_scenario(viewport,find_world()->get_scenario());
}
@@ -960,6 +1346,37 @@ Rect2 Viewport::get_render_target_to_screen_rect() const{
return to_screen_rect;
}
+void Viewport::set_physics_object_picking(bool p_enable) {
+
+ physics_object_picking=p_enable;
+ set_fixed_process(physics_object_picking);
+ if (!physics_object_picking)
+ physics_picking_events.clear();
+
+
+}
+
+
+Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
+
+ Matrix32 xf = get_final_transform();
+ return xf.xform(p_viewport_coords);
+
+
+}
+
+Vector2 Viewport::get_camera_rect_size() const {
+
+ return last_vp_rect.size;
+}
+
+
+bool Viewport::get_physics_object_picking() {
+
+
+ return physics_object_picking;
+}
+
void Viewport::_bind_methods() {
@@ -1003,15 +1420,26 @@ void Viewport::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_render_target_vflip","enable"), &Viewport::set_render_target_vflip);
ObjectTypeDB::bind_method(_MD("get_render_target_vflip"), &Viewport::get_render_target_vflip);
+
+ ObjectTypeDB::bind_method(_MD("set_render_target_clear_on_new_frame","enable"), &Viewport::set_render_target_clear_on_new_frame);
+ ObjectTypeDB::bind_method(_MD("get_render_target_clear_on_new_frame"), &Viewport::get_render_target_clear_on_new_frame);
+
+ ObjectTypeDB::bind_method(_MD("render_target_clear"), &Viewport::render_target_clear);
ObjectTypeDB::bind_method(_MD("set_render_target_filter","enable"), &Viewport::set_render_target_filter);
ObjectTypeDB::bind_method(_MD("get_render_target_filter"), &Viewport::get_render_target_filter);
+ ObjectTypeDB::bind_method(_MD("set_render_target_gen_mipmaps","enable"), &Viewport::set_render_target_gen_mipmaps);
+ ObjectTypeDB::bind_method(_MD("get_render_target_gen_mipmaps"), &Viewport::get_render_target_gen_mipmaps);
+
ObjectTypeDB::bind_method(_MD("set_render_target_update_mode","mode"), &Viewport::set_render_target_update_mode);
ObjectTypeDB::bind_method(_MD("get_render_target_update_mode"), &Viewport::get_render_target_update_mode);
ObjectTypeDB::bind_method(_MD("get_render_target_texture:RenderTargetTexture"), &Viewport::get_render_target_texture);
+ ObjectTypeDB::bind_method(_MD("set_physics_object_picking","enable"), &Viewport::set_physics_object_picking);
+ ObjectTypeDB::bind_method(_MD("get_physics_object_picking"), &Viewport::get_physics_object_picking);
+
ObjectTypeDB::bind_method(_MD("get_viewport"), &Viewport::get_viewport);
ObjectTypeDB::bind_method(_MD("input","local_event"), &Viewport::input);
ObjectTypeDB::bind_method(_MD("unhandled_input","local_event"), &Viewport::unhandled_input);
@@ -1021,6 +1449,7 @@ void Viewport::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_use_own_world","enable"), &Viewport::set_use_own_world);
ObjectTypeDB::bind_method(_MD("is_using_own_world"), &Viewport::is_using_own_world);
+ ObjectTypeDB::bind_method(_MD("get_camera:Camera"), &Viewport::get_camera);
ObjectTypeDB::bind_method(_MD("set_as_audio_listener","enable"), &Viewport::set_as_audio_listener);
ObjectTypeDB::bind_method(_MD("is_audio_listener","enable"), &Viewport::is_audio_listener);
@@ -1029,6 +1458,8 @@ void Viewport::_bind_methods() {
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("get_mouse_pos"), &Viewport::get_mouse_pos);
+ ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"), &Viewport::warp_mouse);
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") );
@@ -1037,10 +1468,13 @@ void Viewport::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transparent_bg"), _SCS("set_transparent_background"), _SCS("has_transparent_background") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/enabled"), _SCS("set_as_render_target"), _SCS("is_set_as_render_target") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/v_flip"), _SCS("set_render_target_vflip"), _SCS("get_render_target_vflip") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/clear_on_new_frame"), _SCS("set_render_target_clear_on_new_frame"), _SCS("get_render_target_clear_on_new_frame") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/filter"), _SCS("set_render_target_filter"), _SCS("get_render_target_filter") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/gen_mipmaps"), _SCS("set_render_target_gen_mipmaps"), _SCS("get_render_target_gen_mipmaps") );
ADD_PROPERTY( PropertyInfo(Variant::INT,"render_target/update_mode",PROPERTY_HINT_ENUM,"Disabled,Once,When Visible,Always"), _SCS("set_render_target_update_mode"), _SCS("get_render_target_update_mode") );
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_SIGNAL(MethodInfo("size_changed"));
@@ -1070,11 +1504,19 @@ Viewport::Viewport() {
size_override=false;
size_override_stretch=false;
size_override_size=Size2(1,1);
+ render_target_gen_mipmaps=false;
render_target=false;
render_target_vflip=false;
+ render_target_clear_on_new_frame=true;
+ //render_target_clear=true;
render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE;
render_target_texture = Ref<RenderTargetTexture>( memnew( RenderTargetTexture(this) ) );
+ physics_object_picking=false;
+ physics_object_capture=0;
+ physics_object_over=0;
+ physics_last_mousepos=Vector2(1e20,1e20);
+
String id=itos(get_instance_ID());
input_group = "_vp_input"+id;
@@ -1083,6 +1525,8 @@ Viewport::Viewport() {
unhandled_key_input_group = "_vp_unhandled_key_input"+id;
+
+
}
@@ -1090,6 +1534,7 @@ Viewport::~Viewport() {
VisualServer::get_singleton()->free( viewport );
SpatialSoundServer::get_singleton()->free(listener);
+ SpatialSound2DServer::get_singleton()->free(listener_2d);
if (render_target_texture.is_valid())
render_target_texture->vp=NULL; //so if used, will crash
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index d54b489843..843a1fd9b7 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -104,16 +104,32 @@ 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;
Size2 size_override_size;
Size2 size_override_margin;
+ Rect2 last_vp_rect;
bool transparent_bg;
bool render_target_vflip;
+ bool render_target_clear_on_new_frame;
bool render_target_filter;
+ bool render_target_gen_mipmaps;
+
+ bool physics_object_picking;
+ List<InputEvent> physics_picking_events;
+ ObjectID physics_object_capture;
+ ObjectID physics_object_over;
+ Vector2 physics_last_mousepos;
+ void _test_new_mouseover(ObjectID new_collider);
+ Map<ObjectID,uint64_t> physics_2d_mouseover;
void _update_rect();
@@ -150,8 +166,8 @@ friend class RenderTargetTexture;
_FORCE_INLINE_ Matrix32 _get_input_pre_xform() const;
- void _vp_enter_scene();
- void _vp_exit_scene();
+ void _vp_enter_tree();
+ void _vp_exit_tree();
void _vp_input(const InputEvent& p_ev);
void _vp_unhandled_input(const InputEvent& p_ev);
@@ -211,13 +227,24 @@ public:
void set_render_target_vflip(bool p_enable);
bool get_render_target_vflip() const;
+ void set_render_target_clear_on_new_frame(bool p_enable);
+ bool get_render_target_clear_on_new_frame() const;
+ void render_target_clear();
+
void set_render_target_filter(bool p_enable);
bool get_render_target_filter() const;
+ void set_render_target_gen_mipmaps(bool p_enable);
+ bool get_render_target_gen_mipmaps() const;
+
void set_render_target_update_mode(RenderTargetUpdateMode p_mode);
RenderTargetUpdateMode get_render_target_update_mode() const;
Ref<RenderTargetTexture> get_render_target_texture() const;
+
+ Vector2 get_camera_coords(const Vector2& p_viewport_coords) const;
+ Vector2 get_camera_rect_size() const;
+
void queue_screen_capture();
Image get_screen_capture() const;
@@ -230,6 +257,12 @@ public:
void set_render_target_to_screen_rect(const Rect2& p_rect);
Rect2 get_render_target_to_screen_rect() const;
+ Vector2 get_mouse_pos() const;
+ void warp_mouse(const Vector2& p_pos);
+
+ void set_physics_object_picking(bool p_enable);
+ bool get_physics_object_picking();
+
Viewport();
~Viewport();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index a468f0a379..b3a9ab922e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,14 +32,14 @@
#include "scene/io/resource_format_image.h"
#include "scene/io/resource_format_wav.h"
-#include "scene/io/scene_format_script.h"
+//#include "scene/io/scene_format_script.h"
#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"
-#include "scene/gui/empty_control.h"
#include "scene/gui/button.h"
#include "scene/gui/button_array.h"
#include "scene/gui/button_group.h"
@@ -53,7 +53,9 @@
#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"
#include "scene/gui/tab_container.h"
#include "scene/gui/panel_container.h"
@@ -66,6 +68,7 @@
#include "scene/gui/file_dialog.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
+#include "scene/gui/item_list.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/texture_button.h"
#include "scene/gui/separator.h"
@@ -75,14 +78,20 @@
#include "scene/gui/split_container.h"
#include "scene/gui/video_player.h"
#include "scene/gui/reference_frame.h"
+#include "scene/gui/graph_node.h"
+#include "scene/gui/graph_edit.h"
+#include "scene/gui/tool_button.h"
#include "scene/resources/video_stream.h"
#include "scene/2d/particles_2d.h"
#include "scene/2d/path_2d.h"
+#include "scene/2d/light_2d.h"
+#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/canvas_item.h"
#include "scene/2d/sprite.h"
#include "scene/2d/animated_sprite.h"
#include "scene/2d/polygon_2d.h"
+#include "scene/2d/back_buffer_copy.h"
#include "scene/2d/visibility_notifier_2d.h"
@@ -100,6 +109,9 @@
#include "scene/2d/sample_player_2d.h"
#include "scene/2d/screen_button.h"
#include "scene/2d/remote_transform_2d.h"
+#include "scene/2d/y_sort.h"
+#include "scene/2d/navigation2d.h"
+#include "scene/2d/canvas_modulate.h"
#include "scene/2d/position_2d.h"
#include "scene/2d/tile_map.h"
@@ -108,6 +120,7 @@
#include "scene/animation/animation_player.h"
#include "scene/animation/animation_tree_player.h"
+#include "scene/animation/tween.h"
#include "scene/main/scene_main_loop.h"
#include "scene/main/resource_preloader.h"
#include "scene/resources/packed_scene.h"
@@ -118,7 +131,7 @@
#include "scene/resources/scene_preloader.h"
#include "scene/main/timer.h"
-#include "scene/io/scene_format_object.h"
+
#include "scene/audio/stream_player.h"
#include "scene/audio/event_player.h"
#include "scene/audio/sound_room_params.h"
@@ -140,7 +153,7 @@
#include "scene/resources/mesh_library.h"
-#include "scene/resources/image_path_finder.h"
+
#include "scene/resources/polygon_path_finder.h"
#include "scene/resources/sample.h"
@@ -150,6 +163,8 @@
#include "scene/resources/mesh.h"
#include "scene/resources/room.h"
+#include "scene/resources/shader_graph.h"
+
#include "scene/resources/world.h"
#include "scene/resources/world_2d.h"
#include "scene/resources/volume.h"
@@ -158,6 +173,7 @@
#include "scene/resources/audio_stream.h"
#include "scene/resources/gibberish_stream.h"
#include "scene/resources/bit_mask.h"
+#include "scene/resources/color_ramp.h"
#include "scene/scene_string_names.h"
@@ -172,9 +188,8 @@
#ifndef _3D_DISABLED
#include "scene/3d/camera.h"
-#include "scene/3d/editable_shape.h"
+
#include "scene/3d/interpolated_camera.h"
-#include "scene/3d/follow_camera.h"
#include "scene/3d/position_3d.h"
#include "scene/3d/test_cube.h"
#include "scene/3d/mesh_instance.h"
@@ -184,7 +199,8 @@
#include "scene/3d/portal.h"
#include "scene/resources/environment.h"
#include "scene/3d/physics_body.h"
-#include "scene/3d/car_body.h"
+
+#include "scene/3d/vehicle_body.h"
#include "scene/3d/body_shape.h"
#include "scene/3d/area.h"
#include "scene/3d/physics_joint.h"
@@ -196,9 +212,12 @@
#include "scene/3d/spatial_sample_player.h"
#include "scene/3d/spatial_stream_player.h"
#include "scene/3d/proximity_group.h"
+#include "scene/3d/navigation_mesh.h"
+#include "scene/3d/navigation.h"
+#include "scene/3d/collision_polygon.h"
#endif
-#include "scene/scene_binds.h"
+#include "scene/resources/scene_format_text.h"
static ResourceFormatLoaderImage *resource_loader_image=NULL;
static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
@@ -210,15 +229,9 @@ static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL;
#endif
static ResourceFormatLoaderTheme *resource_loader_theme=NULL;
static ResourceFormatLoaderShader *resource_loader_shader=NULL;
-#ifdef OLD_SCENE_FORMAT_ENABLED
-static SceneFormatSaverObject *scene_saver_object=NULL;
-static SceneFormatLoaderObject *scene_loader_object=NULL;
-//static SceneFormatLoaderScript *scene_loader_script=NULL;
-#endif
-#ifdef OLD_SCENE_FORMAT_ENABLED
-SceneIO *scene_io=NULL;
-#endif
+static ResourceFormatSaverText *resource_saver_text=NULL;
+static ResourceFormatLoaderText *resource_loader_text=NULL;
//static SceneStringNames *string_names;
@@ -230,13 +243,6 @@ void register_scene_types() {
Node::init_node_hrcr();
-#ifdef OLD_SCENE_FORMAT_ENABLED
- ObjectTypeDB::register_type<SceneIO>();
- ObjectTypeDB::register_virtual_type<SceneInteractiveLoader>();
- scene_io = memnew( SceneIO );
- Globals::get_singleton()->add_singleton(Globals::Singleton("SceneIO",scene_io));
-#endif
-
resource_loader_image = memnew( ResourceFormatLoaderImage );
ResourceLoader::add_resource_format_loader( resource_loader_image );
@@ -257,16 +263,6 @@ void register_scene_types() {
resource_loader_shader = memnew( ResourceFormatLoaderShader );
ResourceLoader::add_resource_format_loader( resource_loader_shader );
-#ifdef OLD_SCENE_FORMAT_ENABLED
- scene_saver_object=memnew( SceneFormatSaverObject );
- SceneSaver::add_scene_format_saver(scene_saver_object);
-
- scene_loader_object=memnew( SceneFormatLoaderObject );
- SceneLoader::add_scene_format_loader(scene_loader_object);
-
-// scene_loader_script=memnew( SceneFormatLoaderScript );
-// SceneLoader::add_scene_format_loader(scene_loader_script);
-#endif
make_default_theme();
@@ -275,11 +271,13 @@ 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>();
ObjectTypeDB::register_type<Timer>();
ObjectTypeDB::register_type<CanvasLayer>();
+ ObjectTypeDB::register_type<CanvasModulate>();
ObjectTypeDB::register_type<ResourcePreloader>();
/* REGISTER GUI */
@@ -289,7 +287,8 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
ObjectTypeDB::register_type<Control>();
- ObjectTypeDB::register_type<EmptyControl>();
+// ObjectTypeDB::register_type<EmptyControl>();
+ ObjectTypeDB::add_compatibility_type("EmptyControl","Control");
ObjectTypeDB::register_type<Button>();
ObjectTypeDB::register_type<Label>();
ObjectTypeDB::register_type<HScrollBar>();
@@ -300,13 +299,16 @@ void register_scene_types() {
ObjectTypeDB::register_type<Popup>();
ObjectTypeDB::register_type<PopupPanel>();
ObjectTypeDB::register_type<MenuButton>();
+ ObjectTypeDB::register_type<CheckBox>();
ObjectTypeDB::register_type<CheckButton>();
+ ObjectTypeDB::register_type<ToolButton>();
ObjectTypeDB::register_type<Panel>();
ObjectTypeDB::register_type<Range>();
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>();
@@ -324,6 +326,8 @@ void register_scene_types() {
ObjectTypeDB::register_virtual_type<SplitContainer>();
ObjectTypeDB::register_type<HSplitContainer>();
ObjectTypeDB::register_type<VSplitContainer>();
+ ObjectTypeDB::register_type<GraphNode>();
+ ObjectTypeDB::register_type<GraphEdit>();
OS::get_singleton()->yield(); //may take time to init
@@ -332,7 +336,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<HButtonArray>();
ObjectTypeDB::register_type<VButtonArray>();
ObjectTypeDB::register_type<TextureProgress>();
-
+ ObjectTypeDB::register_type<ItemList>();
#ifndef ADVANCED_GUI_DISABLED
@@ -340,6 +344,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<LineEdit>();
ObjectTypeDB::register_type<PopupMenu>();
ObjectTypeDB::register_type<Tree>();
+
ObjectTypeDB::register_type<TextEdit>();
ObjectTypeDB::register_virtual_type<TreeItem>();
@@ -365,6 +370,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<Spatial>();
ObjectTypeDB::register_type<Skeleton>();
ObjectTypeDB::register_type<AnimationPlayer>();
+ ObjectTypeDB::register_type<Tween>();
OS::get_singleton()->yield(); //may take time to init
@@ -372,7 +378,6 @@ void register_scene_types() {
ObjectTypeDB::register_type<BoneAttachment>();
ObjectTypeDB::register_virtual_type<VisualInstance>();
ObjectTypeDB::register_type<Camera>();
- ObjectTypeDB::register_type<FollowCamera>();
ObjectTypeDB::register_type<InterpolatedCamera>();
ObjectTypeDB::register_type<TestCube>();
ObjectTypeDB::register_type<MeshInstance>();
@@ -388,20 +393,25 @@ void register_scene_types() {
ObjectTypeDB::register_type<Particles>();
ObjectTypeDB::register_type<Position3D>();
ObjectTypeDB::register_type<Quad>();
+ ObjectTypeDB::register_type<NavigationMeshInstance>();
+ ObjectTypeDB::register_type<NavigationMesh>();
+ ObjectTypeDB::register_type<Navigation>();
OS::get_singleton()->yield(); //may take time to init
ObjectTypeDB::register_virtual_type<CollisionObject>();
ObjectTypeDB::register_type<StaticBody>();
ObjectTypeDB::register_type<RigidBody>();
- ObjectTypeDB::register_type<CarBody>();
- ObjectTypeDB::register_type<CarWheel>();
+ ObjectTypeDB::register_type<KinematicBody>();
+
+
+ ObjectTypeDB::register_type<VehicleBody>();
+ ObjectTypeDB::register_type<VehicleWheel>();
ObjectTypeDB::register_type<Area>();
ObjectTypeDB::register_type<ProximityGroup>();
ObjectTypeDB::register_type<CollisionShape>();
+ ObjectTypeDB::register_type<CollisionPolygon>();
ObjectTypeDB::register_type<RayCast>();
- ObjectTypeDB::register_virtual_type<EditableShape>();
- ObjectTypeDB::register_type<EditableSphere>();
ObjectTypeDB::register_type<MultiMeshInstance>();
ObjectTypeDB::register_type<Room>();
ObjectTypeDB::register_type<Curve3D>();
@@ -410,8 +420,16 @@ void register_scene_types() {
ObjectTypeDB::register_type<VisibilityNotifier>();
ObjectTypeDB::register_type<VisibilityEnabler>();
ObjectTypeDB::register_type<BakedLightInstance>();
+ ObjectTypeDB::register_type<BakedLightSampler>();
ObjectTypeDB::register_type<WorldEnvironment>();
+ ObjectTypeDB::register_virtual_type<Joint>();
+ ObjectTypeDB::register_type<PinJoint>();
+ ObjectTypeDB::register_type<HingeJoint>();
+ ObjectTypeDB::register_type<SliderJoint>();
+ ObjectTypeDB::register_type<ConeTwistJoint>();
+ ObjectTypeDB::register_type<Generic6DOFJoint>();
+
//scenariofx
OS::get_singleton()->yield(); //may take time to init
@@ -420,6 +438,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<SpatialStreamPlayer>();
ObjectTypeDB::register_type<SoundRoomParams>();
+
#endif
ObjectTypeDB::register_type<MeshLibrary>();
AcceptDialog::set_swap_ok_cancel( GLOBAL_DEF("display/swap_ok_cancel",bool(OS::get_singleton()->get_swap_ok_cancel())) );
@@ -434,21 +453,23 @@ void register_scene_types() {
//ObjectTypeDB::register_type<BodyVolumeBox>();
//ObjectTypeDB::register_type<BodyVolumeCylinder>();
//ObjectTypeDB::register_type<BodyVolumeCapsule>();
- //ObjectTypeDB::register_virtual_type<PhysicsJoint>();
//ObjectTypeDB::register_type<PhysicsJointPin>();
+
+
+
ObjectTypeDB::register_type<StreamPlayer>();
ObjectTypeDB::register_type<EventPlayer>();
/* 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);
//ObjectTypeDB::set_type_enabled("BodyVolumeCylinder",false);
//ObjectTypeDB::set_type_enabled("BodyVolumeConvexPolygon",false);
+ ObjectTypeDB::register_type<CanvasItemMaterial>();
ObjectTypeDB::register_virtual_type<CanvasItem>();
ObjectTypeDB::register_type<Node2D>();
ObjectTypeDB::register_type<Particles2D>();
@@ -470,9 +491,17 @@ void register_scene_types() {
ObjectTypeDB::register_type<VisibilityNotifier2D>();
ObjectTypeDB::register_type<VisibilityEnabler2D>();
ObjectTypeDB::register_type<Polygon2D>();
-
- ObjectTypeDB::set_type_enabled("CollisionShape2D",false);
- ObjectTypeDB::set_type_enabled("CollisionPolygon2D",false);
+ ObjectTypeDB::register_type<Light2D>();
+ ObjectTypeDB::register_type<LightOccluder2D>();
+ ObjectTypeDB::register_type<OccluderPolygon2D>();
+ ObjectTypeDB::register_type<YSort>();
+ ObjectTypeDB::register_type<BackBufferCopy>();
+ 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
@@ -494,15 +523,22 @@ void register_scene_types() {
/* REGISTER RESOURCES */
+ ObjectTypeDB::register_virtual_type<Shader>();
+ ObjectTypeDB::register_virtual_type<ShaderGraph>();
+ ObjectTypeDB::register_type<CanvasItemShader>();
+ ObjectTypeDB::register_type<CanvasItemShaderGraph>();
+
#ifndef _3D_DISABLED
ObjectTypeDB::register_type<Mesh>();
ObjectTypeDB::register_virtual_type<Material>();
ObjectTypeDB::register_type<FixedMaterial>();
- ObjectTypeDB::register_type<ParticleSystemMaterial>();
- ObjectTypeDB::register_type<UnshadedMaterial>();
ObjectTypeDB::register_type<ShaderMaterial>();
ObjectTypeDB::register_type<RoomBounds>();
- ObjectTypeDB::register_type<Shader>();
+ ObjectTypeDB::register_type<MaterialShaderGraph>();
+ ObjectTypeDB::register_type<MaterialShader>();
+ ObjectTypeDB::add_compatibility_type("Shader","MaterialShader");
+ ObjectTypeDB::add_compatibility_type("ParticleSystemMaterial","FixedMaterial");
+ ObjectTypeDB::add_compatibility_type("UnshadedMaterial","FixedMaterial");
ObjectTypeDB::register_type<MultiMesh>();
ObjectTypeDB::register_type<MeshLibrary>();
@@ -538,9 +574,10 @@ void register_scene_types() {
ObjectTypeDB::register_type<StyleBoxFlat>();
ObjectTypeDB::register_type<StyleBoxImageMask>();
ObjectTypeDB::register_type<Theme>();
- ObjectTypeDB::register_type<ImagePathFinder>();
+
ObjectTypeDB::register_type<PolygonPathFinder>();
ObjectTypeDB::register_type<BitMap>();
+ ObjectTypeDB::register_type<ColorRamp>();
OS::get_singleton()->yield(); //may take time to init
@@ -548,7 +585,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
@@ -566,19 +604,25 @@ void register_scene_types() {
ObjectTypeDB::register_type<Path2D>();
ObjectTypeDB::register_type<PathFollow2D>();
+ ObjectTypeDB::register_type<Navigation2D>();
+ ObjectTypeDB::register_type<NavigationPolygon>();
+ ObjectTypeDB::register_type<NavigationPolygonInstance>();
+
OS::get_singleton()->yield(); //may take time to init
ObjectTypeDB::register_type<PackedScene>();
-#ifdef OLD_SCENE_FORMAT_ENABLED
- ObjectTypeDB::register_type<ScenePreloader>();
-#endif
-
- ObjectTypeDB::register_type<SceneMainLoop>();
+ ObjectTypeDB::register_type<SceneTree>();
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() {
@@ -596,11 +640,12 @@ void unregister_scene_types() {
memdelete( resource_loader_theme );
memdelete( resource_loader_shader );
-#ifdef OLD_SCENE_FORMAT_ENABLED
- memdelete( scene_saver_object );
- memdelete( scene_loader_object );
-// memdelete( scene_loader_script );
- memdelete( scene_io );
-#endif
+
+ 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 b6d192d27c..7d36dbc101 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/SCsub b/scene/resources/SCsub
index 87bd33e00e..bb9766e1ca 100644
--- a/scene/resources/SCsub
+++ b/scene/resources/SCsub
@@ -1,8 +1,8 @@
Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
+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 7fa606f5da..afd4dc5304 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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") {
@@ -1216,8 +1216,8 @@ T Animation::_interpolate( const Vector< TKey<T> >& p_keys, float p_time, Inter
if (p_ok)
*p_ok=true;
-
- int next;
+
+ int next=0;
float c=0;
// prepare for all cases of interpolation
@@ -1266,7 +1266,7 @@ T Animation::_interpolate( const Vector< TKey<T> >& p_keys, float p_time, Inter
}
} else { // no loop
-
+
if (idx>=0) {
if ((idx+1) < len) {
@@ -1716,188 +1716,235 @@ void Animation::clear() {
}
-void Animation::_transform_track_optimize(int p_idx,float p_allowed_err) {
- ERR_FAIL_INDEX(p_idx,tracks.size());
- ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM);
- TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]);
- 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 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);
- real_t t[3]={-1,-1,-1};
- { //translation
+ real_t c = (t1.time-t0.time)/(t2.time-t0.time);
+ real_t t[3]={-1,-1,-1};
- const Vector3 &v0=t0.value.loc;
- const Vector3 &v1=t1.value.loc;
- const Vector3 &v2=t2.value.loc;
+ { //translation
- if (v0.distance_to(v2)<CMP_EPSILON) {
- //0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1)>CMP_EPSILON) {
- //not close, not optimizable
- continue;
- }
+ const Vector3 &v0=t0.value.loc;
+ const Vector3 &v1=t1.value.loc;
+ const Vector3 &v2=t2.value.loc;
- } else {
+ if (v0.distance_to(v2)<CMP_EPSILON) {
+ //0 and 2 are close, let's see if 1 is close
+ if (v0.distance_to(v1)>CMP_EPSILON) {
+ //not close, not optimizable
+ return false;
+ }
- Vector3 pd = (v2-v0);
- float d0 = pd.dot(v0);
- float d1 = pd.dot(v1);
- float d2 = pd.dot(v2);
- if (d1<d0 || d1>d2) {
- continue; //beyond segment range
- }
+ } else {
- Vector3 s[2]={ v0, v2 };
- real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
+ Vector3 pd = (v2-v0);
+ float d0 = pd.dot(v0);
+ float d1 = pd.dot(v1);
+ float d2 = pd.dot(v2);
+ if (d1<d0 || d1>d2) {
+ return false;
+ }
- if (d>pd.length()*p_allowed_err) {
- continue; //beyond allowed error for colinearity
- }
+ Vector3 s[2]={ v0, v2 };
+ real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
- t[0] = (d1-d0)/(d2-d0);
+ if (d>pd.length()*p_alowed_linear_err) {
+ return false; //beyond allowed error for colinearity
}
- }
- { //rotation
+ if (p_norm!=Vector3() && Math::acos(pd.normalized().dot(p_norm))>p_alowed_angular_err)
+ return false;
+
+ t[0] = (d1-d0)/(d2-d0);
+ }
+ }
- const Quat &q0=t0.value.rot;
- const Quat &q1=t1.value.rot;
- const Quat &q2=t2.value.rot;
+ { //rotation
- //localize both to rotation from q0
+ const Quat &q0=t0.value.rot;
+ const Quat &q1=t1.value.rot;
+ const Quat &q2=t2.value.rot;
- if ((q0-q2).length() < CMP_EPSILON) {
+ //localize both to rotation from q0
- if ((q0-q1).length() > CMP_EPSILON)
- continue;
+ if ((q0-q2).length() < CMP_EPSILON) {
- } else {
+ if ((q0-q1).length() > CMP_EPSILON)
+ return false;
- Quat r02 = (q0.inverse() * q2).normalized();
- Quat r01 = (q0.inverse() * q1).normalized();
+ } else {
- Vector3 v02,v01;
- real_t a02,a01;
- r02.get_axis_and_angle(v02,a02);
- r01.get_axis_and_angle(v01,a01);
+ Quat r02 = (q0.inverse() * q2).normalized();
+ Quat r01 = (q0.inverse() * q1).normalized();
- if (v01.dot(v02)<0) {
- //make sure both rotations go the same way to compare
- v02=-v02;
- a02=-a02;
- }
+ Vector3 v02,v01;
+ real_t a02,a01;
- real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI;
- if (err_01>p_allowed_err) {
- //not rotating in the same axis
- continue;
- }
+ r02.get_axis_and_angle(v02,a02);
+ r01.get_axis_and_angle(v01,a01);
- if (a01*a02 < 0 ) {
- //not rotating in the same direction
- continue;
- }
+ if (Math::abs(a02)>p_max_optimizable_angle)
+ return false;
- real_t tr = a01/a02;
- if (tr<0 || tr>1)
- continue; //rotating too much or too less
+ if (v01.dot(v02)<0) {
+ //make sure both rotations go the same way to compare
+ v02=-v02;
+ a02=-a02;
+ }
- t[1]=tr;
+ real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI;
+ if (err_01>p_alowed_angular_err) {
+ //not rotating in the same axis
+ return false;
+ }
+ if (a01*a02 < 0 ) {
+ //not rotating in the same direction
+ return false;
}
+ real_t tr = a01/a02;
+ if (tr<0 || tr>1)
+ return false; //rotating too much or too less
+
+ t[1]=tr;
+
}
- { //scale
+ }
- const Vector3 &v0=t0.value.scale;
- const Vector3 &v1=t1.value.scale;
- const Vector3 &v2=t2.value.scale;
+ { //scale
- if (v0.distance_to(v2)<CMP_EPSILON) {
- //0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1)>CMP_EPSILON) {
- //not close, not optimizable
- continue;
- }
+ const Vector3 &v0=t0.value.scale;
+ const Vector3 &v1=t1.value.scale;
+ const Vector3 &v2=t2.value.scale;
- } else {
+ if (v0.distance_to(v2)<CMP_EPSILON) {
+ //0 and 2 are close, let's see if 1 is close
+ if (v0.distance_to(v1)>CMP_EPSILON) {
+ //not close, not optimizable
+ return false;
+ }
- Vector3 pd = (v2-v0);
- float d0 = pd.dot(v0);
- float d1 = pd.dot(v1);
- float d2 = pd.dot(v2);
- if (d1<d0 || d1>d2) {
- continue; //beyond segment range
- }
+ } else {
- Vector3 s[2]={ v0, v2 };
- real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
+ Vector3 pd = (v2-v0);
+ float d0 = pd.dot(v0);
+ float d1 = pd.dot(v1);
+ float d2 = pd.dot(v2);
+ if (d1<d0 || d1>d2) {
+ return false; //beyond segment range
+ }
- if (d>pd.length()*p_allowed_err) {
- continue; //beyond allowed error for colinearity
- }
+ Vector3 s[2]={ v0, v2 };
+ real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
- t[2] = (d1-d0)/(d2-d0);
+ if (d>pd.length()*p_alowed_linear_err) {
+ return false; //beyond allowed error for colinearity
}
+
+ t[2] = (d1-d0)/(d2-d0);
}
+ }
- bool erase=false;
- if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
+ bool erase=false;
+ if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
- erase=true;
- } else {
+ erase=true;
+ } else {
- erase=true;
- real_t lt=-1;
- for(int j=0;j<3;j++) {
- //search for t on first, one must be it
- if (t[j]!=-1) {
- lt=t[j]; //official t
- //validate rest
- for(int k=j+1;k<3;k++) {
- if (t[k]==-1)
- continue;
-
- if (Math::abs(lt-t[k])>p_allowed_err) {
- erase=false;
- break;
- }
+ erase=true;
+ real_t lt=-1;
+ for(int j=0;j<3;j++) {
+ //search for t on first, one must be it
+ if (t[j]!=-1) {
+ lt=t[j]; //official t
+ //validate rest
+ for(int k=j+1;k<3;k++) {
+ if (t[k]==-1)
+ continue;
+
+ if (Math::abs(lt-t[k])>p_alowed_linear_err) {
+ erase=false;
+ break;
}
- break;
}
+ break;
}
+ }
- ERR_CONTINUE( lt==-1 );
+ ERR_FAIL_COND_V( lt==-1,false );
- if (erase) {
+ if (erase) {
- if (Math::abs(lt-c)>p_allowed_err) {
- //todo, evaluate changing the transition if this fails?
- //this could be done as a second pass and would be
- //able to optimize more
- erase=false;
- } else {
+ if (Math::abs(lt-c)>p_alowed_linear_err) {
+ //todo, evaluate changing the transition if this fails?
+ //this could be done as a second pass and would be
+ //able to optimize more
+ erase=false;
+ } else {
- //print_line(itos(i)+"because of interp");
- }
+ //print_line(itos(i)+"because of interp");
}
+ }
+
+ }
+
+
+ return erase;
+
+
+}
+
+
+void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
+ ERR_FAIL_INDEX(p_idx,tracks.size());
+ ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM);
+ TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]);
+ 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,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,norm)) {
+ //avoid error to go beyond first erased key
+ erase=false;
+ }
+
+
if (erase) {
+
+ if (!prev_erased) {
+ first_erased=t1;
+ prev_erased=true;
+ }
+
tt->transforms.remove(i);
i--;
+
+ } else {
+ prev_erased=false;
+ norm=Vector3();
}
+
// print_line(itos(i)+" could be eliminated: "+rtos(tr));
//}
}
@@ -1905,7 +1952,7 @@ void Animation::_transform_track_optimize(int p_idx,float p_allowed_err) {
}
-void Animation::optimize(float p_allowed_err) {
+void Animation::optimize(float p_allowed_linear_err,float p_allowed_angular_err,float p_angle_max) {
int total_tt=0;
@@ -1913,7 +1960,7 @@ void Animation::optimize(float p_allowed_err) {
for(int i=0;i<tracks.size();i++) {
if (tracks[i]->type==TYPE_TRANSFORM)
- _transform_track_optimize(i,p_allowed_err);
+ _transform_track_optimize(i,p_allowed_linear_err,p_allowed_angular_err,p_angle_max);
}
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 4366bdaca8..256826a4bb 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -204,7 +204,8 @@ private:
return idxr;
}
- void _transform_track_optimize(int p_idx,float p_allowed_err=0.05);
+ 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:
@@ -271,7 +272,7 @@ public:
void clear();
- void optimize(float p_allowed_err=0.05);
+ void optimize(float p_allowed_linear_err=0.05,float p_allowed_angular_err=0.01,float p_max_optimizable_angle=Math_PI*0.125);
Animation();
~Animation();
diff --git a/scene/resources/audio_stream.cpp b/scene/resources/audio_stream.cpp
index 9ee4593110..569ed8620d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 a4f35b6d1c..b16e62b8c7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 8e694a6110..edbca60bd3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,6 +28,9 @@
/*************************************************************************/
#include "audio_stream_resampled.h"
#include "globals.h"
+
+
+#if 0
int AudioStreamResampled::get_channel_count() const {
if (!rb)
@@ -38,15 +41,18 @@ int AudioStreamResampled::get_channel_count() const {
template<int C>
-void AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) {
+uint32_t AudioStreamResampled::_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(pos>=rb_len);
+ ERR_FAIL_COND_V(pos>=rb_len,0);
#endif
uint32_t pos_next = (pos+1)&rb_mask;
//printf("rb pos %i\n",pos);
@@ -151,7 +157,7 @@ void AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increm
}
- rb_read_pos=offset>>MIX_FRAC_BITS;
+ return read>>MIX_FRAC_BITS;//rb_read_pos=offset>>MIX_FRAC_BITS;
}
@@ -173,10 +179,10 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) {
} else if (rb_read_pos<write_pos_cache) {
- rb_todo=write_pos_cache-rb_read_pos-1;
+ rb_todo=write_pos_cache-rb_read_pos; //-1?
} else {
- rb_todo=(rb_len-rb_read_pos)+write_pos_cache-1;
+ 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 );
@@ -220,13 +226,67 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) {
#endif
{
+ uint32_t read=0;
switch(channels) {
- case 1: _resample<1>(p_dest,todo,increment); break;
- case 2: _resample<2>(p_dest,todo,increment); break;
- case 4: _resample<4>(p_dest,todo,increment); break;
- case 6: _resample<6>(p_dest,todo,increment); break;
+ 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;
@@ -304,6 +364,16 @@ AudioStreamResampled::AudioStreamResampled() {
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;
+ mix_rate=0;
+
}
AudioStreamResampled::~AudioStreamResampled() {
@@ -315,3 +385,4 @@ AudioStreamResampled::~AudioStreamResampled() {
}
+#endif
diff --git a/scene/resources/audio_stream_resampled.h b/scene/resources/audio_stream_resampled.h
index f1e3629ac7..570c311878 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,6 +31,7 @@
#include "scene/resources/audio_stream.h"
+#if 0
class AudioStreamResampled : public AudioStream {
OBJ_TYPE(AudioStreamResampled,AudioStream);
@@ -57,7 +58,7 @@ class AudioStreamResampled : public AudioStream {
template<int C>
- void _resample(int32_t *p_dest,int p_todo,int32_t p_increment);
+ uint32_t _resample(int32_t *p_dest,int p_todo,int32_t p_increment);
protected:
@@ -97,7 +98,7 @@ protected:
_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);
+ ERR_FAIL_COND(p_frames >= rb_len);
switch(channels) {
case 1: {
@@ -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 725ac1c946..31282a0274 100644
--- a/scene/resources/baked_light.cpp
+++ b/scene/resources/baked_light.cpp
@@ -5,6 +5,7 @@ void BakedLight::set_mode(Mode p_mode) {
mode=p_mode;
VS::get_singleton()->baked_light_set_mode(baked_light,(VS::BakedLightMode(p_mode)));
+
}
BakedLight::Mode BakedLight::get_mode() const{
@@ -22,57 +23,101 @@ DVector<uint8_t> BakedLight::get_octree() const {
return VS::get_singleton()->baked_light_get_octree(baked_light);
}
+void BakedLight::set_light(const DVector<uint8_t>& p_light) {
-void BakedLight::_update_lightmaps() {
+ VS::get_singleton()->baked_light_set_light(baked_light,p_light);
+}
- VS::get_singleton()->baked_light_clear_lightmaps(baked_light);
- for(Map<int,Ref<Texture> >::Element *E=lightmaps.front();E;E=E->next()) {
+DVector<uint8_t> BakedLight::get_light() const {
- VS::get_singleton()->baked_light_add_lightmap(baked_light,E->get()->get_rid(),E->key());
- }
+ return VS::get_singleton()->baked_light_get_light(baked_light);
+}
+
+void BakedLight::set_sampler_octree(const DVector<int>& p_sampler_octree) {
+
+ VS::get_singleton()->baked_light_set_sampler_octree(baked_light,p_sampler_octree);
}
-void BakedLight::add_lightmap(const Ref<Texture> p_texture,int p_id) {
+DVector<int> BakedLight::get_sampler_octree() const {
- ERR_FAIL_COND(!p_texture.is_valid());
- ERR_FAIL_COND(p_id<0);
- lightmaps[p_id]=p_texture;
- VS::get_singleton()->baked_light_add_lightmap(baked_light,p_texture->get_rid(),p_id);
+ return VS::get_singleton()->baked_light_get_sampler_octree(baked_light);
}
-void BakedLight::erase_lightmap(int p_id) {
- ERR_FAIL_COND(!lightmaps.has(p_id));
- lightmaps.erase(p_id);
+
+
+
+void BakedLight::add_lightmap(const Ref<Texture> &p_texture,Size2 p_gen_size) {
+
+ LightMap lm;
+ lm.texture=p_texture;
+ lm.gen_size=p_gen_size;
+ lightmaps.push_back(lm);
_update_lightmaps();
+ _change_notify();
}
-void BakedLight::get_lightmaps(List<int> *r_lightmaps) {
+void BakedLight::set_lightmap_gen_size(int p_idx,const Size2& p_size){
- for(Map<int,Ref<Texture> >::Element *E=lightmaps.front();E;E=E->next()) {
+ ERR_FAIL_INDEX(p_idx,lightmaps.size());
+ lightmaps[p_idx].gen_size=p_size;
+ _update_lightmaps();
+}
+Size2 BakedLight::get_lightmap_gen_size(int p_idx) const{
- r_lightmaps->push_back(E->key());
- }
+ ERR_FAIL_INDEX_V(p_idx,lightmaps.size(),Size2());
+ return lightmaps[p_idx].gen_size;
}
+void BakedLight::set_lightmap_texture(int p_idx,const Ref<Texture> &p_texture){
-Ref<Texture> BakedLight::get_lightmap_texture(int p_id) {
+ ERR_FAIL_INDEX(p_idx,lightmaps.size());
+ lightmaps[p_idx].texture=p_texture;
+ _update_lightmaps();
+
+}
+Ref<Texture> BakedLight::get_lightmap_texture(int p_idx) const{
- if (!lightmaps.has(p_id))
- return Ref<Texture>();
+ ERR_FAIL_INDEX_V(p_idx,lightmaps.size(),Ref<Texture>());
+ return lightmaps[p_idx].texture;
- return lightmaps[p_id];
+}
+void BakedLight::erase_lightmap(int p_idx){
+ ERR_FAIL_INDEX(p_idx,lightmaps.size());
+ lightmaps.remove(p_idx);
+ _update_lightmaps();
+ _change_notify();
}
+int BakedLight::get_lightmaps_count() const{
-void BakedLight::clear_lightmaps() {
+ return lightmaps.size();
+}
+void BakedLight::clear_lightmaps(){
lightmaps.clear();
_update_lightmaps();
+ _change_notify();
+}
+
+
+
+void BakedLight::_update_lightmaps() {
+
+ VS::get_singleton()->baked_light_clear_lightmaps(baked_light);
+ for(int i=0;i<lightmaps.size();i++) {
+
+ RID tid;
+ if (lightmaps[i].texture.is_valid())
+ tid=lightmaps[i].texture->get_rid();
+ VS::get_singleton()->baked_light_add_lightmap(baked_light,tid,i);
+ }
}
+
+
RID BakedLight::get_rid() const {
return baked_light;
@@ -84,12 +129,11 @@ Array BakedLight::_get_lightmap_data() const {
ret.resize(lightmaps.size()*2);
int idx=0;
- for(Map<int,Ref<Texture> >::Element *E=lightmaps.front();E;E=E->next()) {
+ for(int i=0;i<lightmaps.size();i++) {
- ret[idx++]=E->key();
- ret[idx++]=E->get();
+ ret[idx++]=Size2(lightmaps[i].gen_size);
+ ret[idx++]=lightmaps[i].texture;
}
-
return ret;
}
@@ -99,11 +143,13 @@ void BakedLight::_set_lightmap_data(Array p_array){
lightmaps.clear();
for(int i=0;i<p_array.size();i+=2) {
- int id = p_array[i];
+ Size2 size = p_array[i];
Ref<Texture> tex = p_array[i+1];
- ERR_CONTINUE(id<0);
- ERR_CONTINUE(tex.is_null());
- lightmaps[id]=tex;
+// ERR_CONTINUE(tex.is_null());
+ LightMap lm;
+ lm.gen_size=size;
+ lm.texture=tex;
+ lightmaps.push_back(lm);
}
_update_lightmaps();
}
@@ -174,6 +220,43 @@ float BakedLight::get_normal_damp() const {
return normal_damp;
}
+void BakedLight::set_tint(float p_margin) {
+ tint=p_margin;
+}
+
+float BakedLight::get_tint() const {
+
+ return tint;
+}
+
+void BakedLight::set_saturation(float p_margin) {
+ saturation=p_margin;
+}
+
+float BakedLight::get_saturation() const {
+
+ return saturation;
+}
+
+void BakedLight::set_ao_radius(float p_ao_radius) {
+ ao_radius=p_ao_radius;
+}
+
+float BakedLight::get_ao_radius() const {
+ return ao_radius;
+}
+
+void BakedLight::set_ao_strength(float p_ao_strength) {
+
+ ao_strength=p_ao_strength;
+}
+
+float BakedLight::get_ao_strength() const {
+
+ return ao_strength;
+}
+
+
void BakedLight::set_energy_multiplier(float p_multiplier){
energy_multiply=p_multiplier;
@@ -204,7 +287,7 @@ bool BakedLight::get_bake_flag(BakeFlags p_flags) const{
void BakedLight::set_format(Format p_format) {
format=p_format;
-
+ VS::get_singleton()->baked_light_set_lightmap_multiplier(baked_light,format==FORMAT_HDR8?8.0:1.0);
}
BakedLight::Format BakedLight::get_format() const{
@@ -212,6 +295,88 @@ BakedLight::Format BakedLight::get_format() const{
return format;
}
+void BakedLight::set_transfer_lightmaps_only_to_uv2(bool p_enable) {
+
+ transfer_only_uv2=p_enable;
+}
+
+bool BakedLight::get_transfer_lightmaps_only_to_uv2() const{
+
+ return transfer_only_uv2;
+}
+
+
+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_slicec('/',1).to_int();
+ ERR_FAIL_COND_V(idx<0,false);
+ ERR_FAIL_COND_V(idx>lightmaps.size(),false);
+
+ String what = n.get_slicec('/',2);
+ Ref<Texture> tex;
+ Size2 gens;
+
+ if (what=="texture")
+ tex=p_value;
+ else if (what=="gen_size")
+ gens=p_value;
+
+ if (idx==lightmaps.size()) {
+ if (tex.is_valid() || gens!=Size2())
+ add_lightmap(tex,gens);
+ } else {
+ if (tex.is_valid())
+ set_lightmap_texture(idx,tex);
+ else if (gens!=Size2())
+ set_lightmap_gen_size(idx,gens);
+ }
+
+
+ return true;
+}
+
+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_slicec('/',1).to_int();
+ ERR_FAIL_COND_V(idx<0,false);
+ ERR_FAIL_COND_V(idx>lightmaps.size(),false);
+
+ String what = n.get_slicec('/',2);
+
+ if (what=="texture") {
+ if (idx==lightmaps.size())
+ r_ret=Ref<Texture>();
+ else
+ r_ret=lightmaps[idx].texture;
+
+ } else if (what=="gen_size") {
+
+ if (idx==lightmaps.size())
+ r_ret=Size2();
+ else
+ r_ret=Size2(lightmaps[idx].gen_size);
+ } else
+ return false;
+
+ return true;
+
+
+}
+void BakedLight::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ for(int i=0;i<=lightmaps.size();i++) {
+
+ p_list->push_back(PropertyInfo(Variant::VECTOR2,"lightmaps/"+itos(i)+"/gen_size",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::OBJECT,"lightmaps/"+itos(i)+"/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture",PROPERTY_USAGE_EDITOR));
+ }
+}
+
void BakedLight::_bind_methods(){
@@ -222,7 +387,14 @@ void BakedLight::_bind_methods(){
ObjectTypeDB::bind_method(_MD("set_octree","octree"),&BakedLight::set_octree);
ObjectTypeDB::bind_method(_MD("get_octree"),&BakedLight::get_octree);
- ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","id"),&BakedLight::add_lightmap);
+ ObjectTypeDB::bind_method(_MD("set_light","light"),&BakedLight::set_light);
+ ObjectTypeDB::bind_method(_MD("get_light"),&BakedLight::get_light);
+
+ ObjectTypeDB::bind_method(_MD("set_sampler_octree","sampler_octree"),&BakedLight::set_sampler_octree);
+ ObjectTypeDB::bind_method(_MD("get_sampler_octree"),&BakedLight::get_sampler_octree);
+
+
+ ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","gen_size"),&BakedLight::add_lightmap);
ObjectTypeDB::bind_method(_MD("erase_lightmap","id"),&BakedLight::erase_lightmap);
ObjectTypeDB::bind_method(_MD("clear_lightmaps"),&BakedLight::clear_lightmaps);
@@ -250,9 +422,26 @@ void BakedLight::_bind_methods(){
ObjectTypeDB::bind_method(_MD("set_normal_damp","normal_damp"),&BakedLight::set_normal_damp);
ObjectTypeDB::bind_method(_MD("get_normal_damp"),&BakedLight::get_normal_damp);
+ ObjectTypeDB::bind_method(_MD("set_tint","tint"),&BakedLight::set_tint);
+ ObjectTypeDB::bind_method(_MD("get_tint"),&BakedLight::get_tint);
+
+ ObjectTypeDB::bind_method(_MD("set_saturation","saturation"),&BakedLight::set_saturation);
+ ObjectTypeDB::bind_method(_MD("get_saturation"),&BakedLight::get_saturation);
+
+ ObjectTypeDB::bind_method(_MD("set_ao_radius","ao_radius"),&BakedLight::set_ao_radius);
+ ObjectTypeDB::bind_method(_MD("get_ao_radius"),&BakedLight::get_ao_radius);
+
+ ObjectTypeDB::bind_method(_MD("set_ao_strength","ao_strength"),&BakedLight::set_ao_strength);
+ ObjectTypeDB::bind_method(_MD("get_ao_strength"),&BakedLight::get_ao_strength);
+
ObjectTypeDB::bind_method(_MD("set_format","format"),&BakedLight::set_format);
ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format);
+ ObjectTypeDB::bind_method(_MD("set_transfer_lightmaps_only_to_uv2","enable"),&BakedLight::set_transfer_lightmaps_only_to_uv2);
+ ObjectTypeDB::bind_method(_MD("get_transfer_lightmaps_only_to_uv2"),&BakedLight::get_transfer_lightmaps_only_to_uv2);
+
+
+
ObjectTypeDB::bind_method(_MD("set_energy_multiplier","energy_multiplier"),&BakedLight::set_energy_multiplier);
ObjectTypeDB::bind_method(_MD("get_energy_multiplier"),&BakedLight::get_energy_multiplier);
@@ -272,16 +461,24 @@ void BakedLight::_bind_methods(){
ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/plot_size",PROPERTY_HINT_RANGE,"1.0,16.0,0.01"),_SCS("set_plot_size"),_SCS("get_plot_size"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/energy_mult",PROPERTY_HINT_RANGE,"0.01,4096.0,0.01"),_SCS("set_energy_multiplier"),_SCS("get_energy_multiplier"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/gamma_adjust",PROPERTY_HINT_EXP_EASING),_SCS("set_gamma_adjust"),_SCS("get_gamma_adjust"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/saturation",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_saturation"),_SCS("get_saturation"));
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/diffuse"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_DIFFUSE);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY);
+ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/linear_color"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_LINEAR_COLOR);
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"lightmap/use_only_uv2"),_SCS("set_transfer_lightmaps_only_to_uv2"),_SCS("get_transfer_lightmaps_only_to_uv2"));
ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree"));
+ ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"light",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_light"),_SCS("get_light"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT_ARRAY,"sampler_octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_sampler_octree"),_SCS("get_sampler_octree"));
ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/cell_margin",PROPERTY_HINT_RANGE,"0.01,0.8,0.01"),_SCS("set_cell_extra_margin"),_SCS("get_cell_extra_margin"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/edge_damp",PROPERTY_HINT_RANGE,"0.0,8.0,0.1"),_SCS("set_edge_damp"),_SCS("get_edge_damp"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/normal_damp",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_normal_damp"),_SCS("get_normal_damp"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/light_tint",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_tint"),_SCS("get_tint"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_radius",PROPERTY_HINT_RANGE,"0.0,16.0,0.01"),_SCS("set_ao_radius"),_SCS("get_ao_radius"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_strength",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_ao_strength"),_SCS("get_ao_strength"));
BIND_CONSTANT( MODE_OCTREE );
BIND_CONSTANT( MODE_LIGHTMAPS );
@@ -302,17 +499,24 @@ BakedLight::BakedLight() {
lattice_subdiv=4;
plot_size=2.5;
bounces=1;
- energy_multiply=1.0;
- gamma_adjust=1.0;
+ energy_multiply=2.0;
+ gamma_adjust=0.7;
cell_extra_margin=0.05;
edge_damp=0.0;
normal_damp=0.0;
+ saturation=1;
+ tint=0.0;
+ ao_radius=2.5;
+ ao_strength=0.7;
format=FORMAT_RGB;
+ transfer_only_uv2=false;
+
flags[BAKE_DIFFUSE]=true;
flags[BAKE_SPECULAR]=false;
flags[BAKE_TRANSLUCENT]=true;
flags[BAKE_CONSERVE_ENERGY]=false;
+ flags[BAKE_LINEAR_COLOR]=false;
mode=MODE_OCTREE;
baked_light=VS::get_singleton()->baked_light_create();
diff --git a/scene/resources/baked_light.h b/scene/resources/baked_light.h
index df86f98c08..41e1e5f9e0 100644
--- a/scene/resources/baked_light.h
+++ b/scene/resources/baked_light.h
@@ -26,6 +26,7 @@ public:
BAKE_SPECULAR,
BAKE_TRANSLUCENT,
BAKE_CONSERVE_ENERGY,
+ BAKE_LINEAR_COLOR,
BAKE_MAX
};
@@ -33,7 +34,13 @@ private:
RID baked_light;
Mode mode;
- Map<int,Ref<Texture> > lightmaps;
+ struct LightMap {
+ Size2i gen_size;
+ Ref<Texture> texture;
+ };
+
+
+ Vector< LightMap> lightmaps;
//bake vars
int cell_subdiv;
@@ -44,7 +51,12 @@ private:
float cell_extra_margin;
float edge_damp;
float normal_damp;
+ float tint;
+ float ao_radius;
+ float ao_strength;
+ float saturation;
int bounces;
+ bool transfer_only_uv2;
Format format;
bool flags[BAKE_MAX];
@@ -54,6 +66,13 @@ private:
Array _get_lightmap_data() const;
void _set_lightmap_data(Array p_array);
+
+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:
@@ -85,22 +104,48 @@ public:
void set_normal_damp(float p_margin);
float get_normal_damp() const;
+ void set_tint(float p_margin);
+ float get_tint() const;
+
+ void set_saturation(float p_saturation);
+ float get_saturation() const;
+
+ void set_ao_radius(float p_ao_radius);
+ float get_ao_radius() const;
+
+ void set_ao_strength(float p_ao_strength);
+ float get_ao_strength() const;
+
void set_bake_flag(BakeFlags p_flags,bool p_enable);
bool get_bake_flag(BakeFlags p_flags) const;
void set_format(Format p_margin);
Format get_format() const;
+ void set_transfer_lightmaps_only_to_uv2(bool p_enable);
+ bool get_transfer_lightmaps_only_to_uv2() const;
+
void set_mode(Mode p_mode);
Mode get_mode() const;
void set_octree(const DVector<uint8_t>& p_octree);
DVector<uint8_t> get_octree() const;
- void add_lightmap(const Ref<Texture> p_texture,int p_id);
- void erase_lightmap(int p_id);
- void get_lightmaps(List<int> *r_lightmaps);
- Ref<Texture> get_lightmap_texture(int p_id);
+ void set_light(const DVector<uint8_t>& p_light);
+ DVector<uint8_t> get_light() const;
+
+ void set_sampler_octree(const DVector<int>& p_sampler_octree);
+ DVector<int> get_sampler_octree() const;
+
+
+
+ void add_lightmap(const Ref<Texture> &p_texture,Size2 p_gen_size=Size2(256,256));
+ void set_lightmap_gen_size(int p_idx,const Size2& p_size);
+ Size2 get_lightmap_gen_size(int p_idx) const;
+ void set_lightmap_texture(int p_idx,const Ref<Texture> &p_texture);
+ Ref<Texture> get_lightmap_texture(int p_idx) const;
+ void erase_lightmap(int p_idx);
+ int get_lightmaps_count() const;
void clear_lightmaps();
virtual RID get_rid() const;
diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp
index bf542b56d0..9a6452797a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -205,7 +205,10 @@ BitMap::BitMap() {
//////////////////////////////////////
-RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderBitMap::load(const String &p_path, const String& p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error=ERR_FILE_CANT_OPEN;
BitMap* ptr = memnew(BitMap);
Ref<BitMap> bitmap( ptr );
@@ -219,6 +222,8 @@ RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_origin
ERR_FAIL_COND_V(err, RES());
bitmap->create_from_image_alpha(image);
+ if (r_error)
+ *r_error=OK;
return bitmap;
diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h
index b06fb1b0aa..a6b29bb919 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -66,7 +66,7 @@ class ResourceFormatLoaderBitMap : 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/bounds.cpp b/scene/resources/bounds.cpp
index 7a9b2505c2..7382d60535 100644
--- a/scene/resources/bounds.cpp
+++ b/scene/resources/bounds.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/bounds.h b/scene/resources/bounds.h
index 720ac082f5..68aca6f6a0 100644
--- a/scene/resources/bounds.h
+++ b/scene/resources/bounds.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/box_shape.cpp b/scene/resources/box_shape.cpp
index 54a588b8eb..ba29a1b601 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 241ac8ae77..9667515657 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 1ded7127ec..51953d9683 100644
--- a/scene/resources/canvas.cpp
+++ b/scene/resources/canvas.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/canvas.h b/scene/resources/canvas.h
index 95bfeca440..71dc080e64 100644
--- a/scene/resources/canvas.h
+++ b/scene/resources/canvas.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/capsule_shape.cpp b/scene/resources/capsule_shape.cpp
index ff92d99177..67ceed6be0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 f804296941..e516d0e3c7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 922511aca0..923a509ad5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 9e7b75e319..dc679966f9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 056be87e72..c77395612c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
@@ -54,9 +54,28 @@ void CircleShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CircleShape2D::set_radius);
ObjectTypeDB::bind_method(_MD("get_radius"),&CircleShape2D::get_radius);
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"radius",PROPERTY_HINT_RANGE,"0.01,16384,0.5"),_SCS("set_radius"),_SCS("get_radius") );
+
+}
+
+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());
+ }
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"radius"),_SCS("set_radius"),_SCS("get_radius") );
+ Vector<Color> col;
+ col.push_back(p_color);
+ VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid,points,col);
}
diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h
index 646108f735..a5902b189c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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
new file mode 100644
index 0000000000..97d3fafd58
--- /dev/null
+++ b/scene/resources/color_ramp.cpp
@@ -0,0 +1,117 @@
+/*
+ * color_ramp.h
+ */
+
+#include "color_ramp.h"
+
+//setter and getter names for property serialization
+#define COLOR_RAMP_GET_OFFSETS "get_offsets"
+#define COLOR_RAMP_GET_COLORS "get_colors"
+#define COLOR_RAMP_SET_OFFSETS "set_offsets"
+#define COLOR_RAMP_SET_COLORS "set_colors"
+
+ColorRamp::ColorRamp() {
+ //Set initial color ramp transition from black to white
+ points.resize(2);
+ points[0].color = Color(0,0,0,1);
+ points[0].offset = 0;
+ points[1].color = Color(1,1,1,1);
+ points[1].offset = 1;
+ is_sorted = true;
+}
+
+ColorRamp::~ColorRamp() {
+
+}
+
+void ColorRamp::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD(COLOR_RAMP_SET_OFFSETS,"offsets"),&ColorRamp::set_offsets);
+ ObjectTypeDB::bind_method(_MD(COLOR_RAMP_GET_OFFSETS),&ColorRamp::get_offsets);
+
+ ObjectTypeDB::bind_method(_MD(COLOR_RAMP_SET_COLORS,"colors"),&ColorRamp::set_colors);
+ ObjectTypeDB::bind_method(_MD(COLOR_RAMP_GET_COLORS),&ColorRamp::get_colors);
+
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"offsets"),_SCS(COLOR_RAMP_SET_OFFSETS),_SCS(COLOR_RAMP_GET_OFFSETS) );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"colors"),_SCS(COLOR_RAMP_SET_COLORS),_SCS(COLOR_RAMP_GET_COLORS) );
+}
+
+Vector<float> ColorRamp::get_offsets() const {
+ Vector<float> offsets;
+ offsets.resize(points.size());
+ for(int i = 0; i < points.size(); i++)
+ {
+ offsets[i] = points[i].offset;
+ }
+ return offsets;
+}
+
+Vector<Color> ColorRamp::get_colors() const {
+ Vector<Color> colors;
+ colors.resize(points.size());
+ for(int i = 0; i < points.size(); i++)
+ {
+ colors[i] = points[i].color;
+ }
+ return colors;
+}
+
+void ColorRamp::set_offsets(const Vector<float>& p_offsets) {
+ points.resize(p_offsets.size());
+ for(int i = 0; i < points.size(); i++)
+ {
+ points[i].offset = p_offsets[i];
+ }
+ is_sorted = false;
+}
+
+void ColorRamp::set_colors(const Vector<Color>& p_colors) {
+ if(points.size()<p_colors.size())
+ is_sorted = false;
+ points.resize(p_colors.size());
+ for(int i = 0; i < points.size(); i++)
+ {
+ points[i].color = p_colors[i];
+ }
+}
+
+Vector<ColorRamp::Point>& ColorRamp::get_points() {
+ return points;
+}
+
+void ColorRamp::set_points(Vector<ColorRamp::Point>& p_points) {
+ points = p_points;
+ is_sorted = false;
+}
+
+void ColorRamp::set_offset(int pos, const float offset) {
+ if(points.size() <= pos)
+ points.resize(pos + 1);
+ points[pos].offset = offset;
+ is_sorted = false;
+}
+
+float ColorRamp::get_offset(int pos) const {
+ if(points.size() > pos)
+ return points[pos].offset;
+ return 0; //TODO: Maybe throw some error instead?
+}
+
+void ColorRamp::set_color(int pos, const Color& color) {
+ if(points.size() <= pos)
+ {
+ points.resize(pos + 1);
+ is_sorted = false;
+ }
+ points[pos].color = color;
+}
+
+Color ColorRamp::get_color(int pos) const {
+ if(points.size() > pos)
+ return points[pos].color;
+ return Color(0,0,0,1); //TODO: Maybe throw some error instead?
+}
+
+int ColorRamp::get_points_count() const {
+ return points.size();
+}
diff --git a/scene/resources/color_ramp.h b/scene/resources/color_ramp.h
new file mode 100644
index 0000000000..8f6ba2c3e5
--- /dev/null
+++ b/scene/resources/color_ramp.h
@@ -0,0 +1,98 @@
+/*
+ * color_ramp.h
+ */
+
+#ifndef SCENE_RESOURCES_COLOR_RAMP_H_
+#define SCENE_RESOURCES_COLOR_RAMP_H_
+
+#include "resource.h"
+
+class ColorRamp: public Resource {
+ OBJ_TYPE( ColorRamp, Resource );
+ OBJ_SAVE_TYPE( ColorRamp );
+
+public:
+ struct Point {
+
+ float offset;
+ Color color;
+ bool operator<(const Point& p_ponit) const {
+ return offset<p_ponit.offset;
+ }
+ };
+
+private:
+ Vector<Point> points;
+ bool is_sorted;
+
+protected:
+ static void _bind_methods();
+
+public:
+ ColorRamp();
+ virtual ~ColorRamp();
+
+ void set_points(Vector<Point>& points);
+ Vector<Point>& get_points();
+
+ void set_offset(int pos, const float offset);
+ float get_offset(int pos) const;
+
+ void set_color(int pos, const Color& color);
+ Color get_color(int pos) const;
+
+ void set_offsets(const Vector<float>& offsets);
+ Vector<float> get_offsets() const;
+
+ void set_colors(const Vector<Color>& colors);
+ Vector<Color> get_colors() const;
+
+ _FORCE_INLINE_ Color get_color_at_offset(float p_offset) {
+
+ if (points.empty())
+ return Color(0,0,0,1);
+
+ if(!is_sorted)
+ {
+ points.sort();
+ is_sorted = true;
+ }
+
+ //binary search
+ int low = 0;
+ int high = points.size() -1;
+ int middle;
+
+ while( low <= high )
+ {
+ middle = ( low + high ) / 2;
+ Point& point = points[middle];
+ if( point.offset > p_offset ) {
+ high = middle - 1; //search low end of array
+ } else if ( point.offset < p_offset) {
+ low = middle + 1; //search high end of array
+ } else {
+ return point.color;
+ }
+ }
+
+ //return interpolated value
+ if (points[middle].offset>p_offset)
+ {
+ middle--;
+ }
+ int first=middle;
+ int second=middle+1;
+ if(second>=points.size())
+ return points[points.size()-1].color;
+ if(first<0)
+ return points[0].color;
+ Point& pointFirst = points[first];
+ Point& pointSecond = points[second];
+ return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset-pointFirst.offset)/(pointSecond.offset - pointFirst.offset));
+ }
+
+ int get_points_count() const;
+};
+
+#endif /* SCENE_RESOURCES_COLOR_RAMP_H_ */
diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp
index e6093ff30b..7aeac04a22 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 bb7b0b49e8..fae98ee046 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 1d60b54eb4..01b7531f14 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 1f6f83eb66..29666c88c1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 eb51fa8f82..6a405c9c94 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 e82924dcf5..48454deb2b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 b8d30998ea..a1137ba614 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,10 +29,11 @@
#include "convex_polygon_shape_2d.h"
#include "servers/physics_2d_server.h"
-
+#include "servers/visual_server.h"
void ConvexPolygonShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(),points);
+ emit_changed();
}
@@ -62,7 +63,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 4c45e4d608..1af7787f67 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 ae2c07ff56..c1a389942f 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -134,7 +134,7 @@ Vector2 Curve2D::interpolate(int p_index, float p_offset) const {
Vector2 Curve2D::interpolatef(real_t p_findex) const {
- if (p_findex>0)
+ if (p_findex<0)
p_findex=0;
else if (p_findex>=points.size())
p_findex=points.size();
@@ -485,7 +485,7 @@ Vector2 Curve2D::interpolate(int p_index, float p_offset) const {
Vector2 Curve2D::interpolatef(real_t p_findex) const {
- if (p_findex>0)
+ if (p_findex<0)
p_findex=0;
else if (p_findex>=points.size())
p_findex=points.size();
@@ -541,19 +541,12 @@ void Curve2D::_bake() const {
Vector2 pos=points[0].pos;
- int point=0;
- float ofs=0;
List<Vector2> pointlist;
for(int i=0;i<points.size()-1;i++) {
- float slen=points[i].pos.distance_to(points[i+1].pos);
- float divs = slen / bake_interval;
- if (divs>1)
- divs=1;
-
- float step = divs*0.1; // 10 substeps ought to be enough?
+ float step = 0.1; // at least 10 substeps ought to be enough?
float p = 0;
while(p<1.0) {
@@ -805,6 +798,7 @@ void Curve2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_baked_length"),&Curve2D::get_baked_length);
ObjectTypeDB::bind_method(_MD("interpolate_baked","offset","cubic"),&Curve2D::interpolate_baked,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_baked_points"),&Curve2D::get_baked_points);
+ ObjectTypeDB::bind_method(_MD("tesselate","max_stages","tolerance_degrees"),&Curve2D::tesselate,DEFVAL(5),DEFVAL(4));
ObjectTypeDB::bind_method(_MD("_get_data"),&Curve2D::_get_data);
ObjectTypeDB::bind_method(_MD("_set_data"),&Curve2D::_set_data);
@@ -956,7 +950,7 @@ Vector3 Curve3D::interpolate(int p_index, float p_offset) const {
Vector3 Curve3D::interpolatef(real_t p_findex) const {
- if (p_findex>0)
+ if (p_findex<0)
p_findex=0;
else if (p_findex>=points.size())
p_findex=points.size();
@@ -1014,19 +1008,12 @@ void Curve3D::_bake() const {
Vector3 pos=points[0].pos;
- int point=0;
- float ofs=0;
List<Plane> pointlist;
pointlist.push_back(Plane(pos,points[0].tilt));
for(int i=0;i<points.size()-1;i++) {
- float slen=points[i].pos.distance_to(points[i+1].pos);
- float divs = slen / bake_interval;
- if (divs>1)
- divs=1;
-
- float step = divs*0.1; // 10 substeps ought to be enough?
+ float step = 0.1; // at least 10 substeps ought to be enough?
float p = 0;
while(p<1.0) {
@@ -1344,6 +1331,7 @@ void Curve3D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("interpolate_baked","offset","cubic"),&Curve3D::interpolate_baked,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_baked_points"),&Curve3D::get_baked_points);
ObjectTypeDB::bind_method(_MD("get_baked_tilts"),&Curve3D::get_baked_tilts);
+ ObjectTypeDB::bind_method(_MD("tesselate","max_stages","tolerance_degrees"),&Curve3D::tesselate,DEFVAL(5),DEFVAL(4));
ObjectTypeDB::bind_method(_MD("_get_data"),&Curve3D::_get_data);
ObjectTypeDB::bind_method(_MD("_set_data"),&Curve3D::_set_data);
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index e361604ce3..4818632dc3 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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/arrow_down.png b/scene/resources/default_theme/arrow_down.png
index 1e5c04cb0e..bb4c9d6831 100644
--- a/scene/resources/default_theme/arrow_down.png
+++ b/scene/resources/default_theme/arrow_down.png
Binary files differ
diff --git a/scene/resources/default_theme/arrow_right.png b/scene/resources/default_theme/arrow_right.png
index 33e0c1965b..e39356dea8 100644
--- a/scene/resources/default_theme/arrow_right.png
+++ b/scene/resources/default_theme/arrow_right.png
Binary files differ
diff --git a/scene/resources/default_theme/button_disabled.png b/scene/resources/default_theme/button_disabled.png
index 8bcfa54cc6..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 aa3035fe4f..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 fbccf22636..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 882b583081..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 171c61b6e5..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/checker_bg.png b/scene/resources/default_theme/checker_bg.png
new file mode 100644
index 0000000000..0674f9da26
--- /dev/null
+++ b/scene/resources/default_theme/checker_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/close_hl.png b/scene/resources/default_theme/close_hl.png
index 835790e9e9..0f3be4a320 100644
--- a/scene/resources/default_theme/close_hl.png
+++ b/scene/resources/default_theme/close_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index d10bb37f60..25407a5b84 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -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,17 +56,27 @@ 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) );
-
+ texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER );
+
return texture;
}
@@ -75,7 +85,7 @@ static Ref<Font> make_font(int p_height,int p_ascent, int p_valign, int p_charco
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 +101,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 +162,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;
}
@@ -168,8 +178,6 @@ void make_default_theme() {
tex_cache = memnew( TexCacheMap );
- uint32_t last=OS::get_singleton()->get_ticks_msec();
-
Ref<Theme> t( memnew( Theme ) );
//Ref<Font> default_font = make_font(_bi_font_normal_height,_bi_font_normal_ascent,_bi_font_normal_valign,_bi_font_normal_charcount,_bi_font_normal_characters,make_icon(font_normal_png));
@@ -177,166 +185,291 @@ void make_default_theme() {
Ref<Font> source_font=make_font2(_builtin_source_font_height,_builtin_source_font_ascent,_builtin_source_font_charcount,&_builtin_source_font_charrects[0][0],_builtin_source_font_kerning_pair_count,&_builtin_source_font_kerning_pairs[0][0],_builtin_source_font_img_width,_builtin_source_font_img_height,_builtin_source_font_img_data);
Ref<Font> large_font=make_font2(_builtin_large_font_height,_builtin_large_font_ascent,_builtin_large_font_charcount,&_builtin_large_font_charrects[0][0],_builtin_large_font_kerning_pair_count,&_builtin_large_font_kerning_pairs[0][0],_builtin_large_font_img_width,_builtin_large_font_img_height,_builtin_large_font_img_data);
+ // 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);
+ Color control_font_color_pressed = Color::html("ffffff");
+ Color font_color_selection = Color::html("7d7d7d");
+
+
+ // Panel
+
t->set_stylebox("panel","Panel", make_stylebox( panel_bg_png,0,0,0,0) );
- Color control_font_color = Color::html("cfc9d5");
- Color control_font_color_low = Color::html("bab4c1");
- Color control_font_color_hover = Color::html("ffffff");
- Color control_font_color_disabled = Color(0.9,0.9,0.9,0.6);
- Color control_font_color_pressed = Color::html("bfb9c5");
- Color font_color_selection = Color::html("715e7d");
- Ref<Texture> empty_icon = memnew( ImageTexture );
- t->set_stylebox("normal","Button", make_stylebox( button_normal_png,5,5,5,5,8,3,8,4) );
- t->set_stylebox("pressed","Button", make_stylebox( button_pressed_png,5,5,5,5,3,3,3,3) );
- t->set_stylebox("hover","Button", make_stylebox( button_hover_png,5,5,5,5,3,0,3,0) );
- t->set_stylebox("disabled","Button", make_stylebox( button_disabled_png,5,5,5,5,3,3,3,3) );
- Ref<StyleBoxTexture> focus = make_stylebox( focus_png,6,6,6,6,3,3,3,3);
+
+ // Focus
+
+ 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);
}
- t->set_stylebox("focus","Button", focus );
+
+
+
+ // Button
+
+ 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 );
+
t->set_color("font_color","Button", control_font_color );
t->set_color("font_color_pressed","Button", control_font_color_pressed );
t->set_color("font_color_hover","Button", control_font_color_hover );
t->set_color("font_color_disabled","Button", control_font_color_disabled );
- t->set_constant("hseparation","Button", 2 );
+ t->set_constant("hseparation","Button", 2);
+
+
+
+ // ColorPickerButton
+
+ 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_stylebox("normal","ColorPickerButton", make_stylebox( button_normal_png,7,7,7,7,8,3,8,3) );
- t->set_stylebox("pressed","ColorPickerButton", make_stylebox( button_pressed_png,5,5,5,5,3,3,3,3) );
- t->set_stylebox("hover","ColorPickerButton", make_stylebox( button_hover_png,4,4,4,4,3,3,3,3) );
- t->set_stylebox("disabled","ColorPickerButton", make_stylebox( button_disabled_png,4,4,4,4,3,3,3,3) );
- t->set_stylebox("focus","ColorPickerButton", make_stylebox( focus_png,5,5,5,5,3,3,3,3) );
t->set_font("font","ColorPickerButton", default_font );
+
t->set_color("font_color","ColorPickerButton", Color(1,1,1,1) );
t->set_color("font_color_pressed","ColorPickerButton", Color(0.8,0.8,0.8,1) );
t->set_color("font_color_hover","ColorPickerButton", Color(1,1,1,1) );
- t->set_color("font_color_disabled","ColorPickerButton", Color(0.9,0.9,0.9,0.6) );
+ t->set_color("font_color_disabled","ColorPickerButton", Color(0.9,0.9,0.9,0.3) );
+
t->set_constant("hseparation","ColorPickerButton", 2 );
- t->set_stylebox("normal","ToolButton", make_empty_stylebox(5,3,5,3) );
- t->set_stylebox("pressed","ToolButton", make_stylebox( button_pressed_png,5,5,5,5,3,3,3,3) );
- t->set_stylebox("hover","ToolButton", make_stylebox( button_normal_png,5,5,5,5,3,3,3,3) );
- //t->set_stylebox("disabled","ToolButton", make_stylebox( button_disabled_png,5,5,5,5,3,3,3,3) );
- t->set_stylebox("disabled","ToolButton", make_empty_stylebox(3,3,3,3) );
- t->set_stylebox("focus","ToolButton", make_stylebox( focus_png,5,5,5,5,3,3,3,3) );
+ // ToolButton
+
+ Ref<StyleBox> tb_empty = memnew( StyleBoxEmpty );
+ tb_empty->set_default_margin(MARGIN_LEFT,8);
+ tb_empty->set_default_margin(MARGIN_RIGHT,8);
+ tb_empty->set_default_margin(MARGIN_TOP,4);
+ tb_empty->set_default_margin(MARGIN_BOTTOM,4);
+
+ t->set_stylebox("normal","ToolButton", tb_empty);
+ t->set_stylebox("pressed","ToolButton", make_stylebox( button_pressed_png,4,4,4,4) );
+ 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 );
t->set_color("font_color_pressed","ToolButton", control_font_color_pressed );
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.6) );
- t->set_constant("hseparation","ToolButton", 2 );
-
- t->set_stylebox("normal","OptionButton", make_stylebox( option_button_normal_png,4,4,20,5,8,3,20,4) );
- t->set_stylebox("pressed","OptionButton", make_stylebox( option_button_pressed_png,4,4,20,5,3,3,3,3) );
- t->set_stylebox("hover","OptionButton", make_stylebox( option_button_hover_png,4,4,20,5,3,3,3,3) );
- t->set_stylebox("disabled","OptionButton", make_stylebox( option_button_disabled_png,4,4,20,5,3,3,3,3) );
- t->set_stylebox("focus","OptionButton", focus );
- t->set_constant("arrow_margin","OptionButton", 1 );
+ t->set_color("font_color_disabled","ToolButton", Color(0.9,0.95,1,0.3) );
+
+ t->set_constant("hseparation","ToolButton", 3 );
+
+
+
+ // OptionButton
+
+ 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 ) );
t->set_font("font","OptionButton", default_font );
+
t->set_color("font_color","OptionButton", control_font_color );
t->set_color("font_color_pressed","OptionButton", control_font_color_pressed );
t->set_color("font_color_hover","OptionButton", control_font_color_hover );
t->set_color("font_color_disabled","OptionButton", control_font_color_disabled );
t->set_constant("hseparation","OptionButton", 2 );
+ t->set_constant("arrow_margin","OptionButton", 2 );
- t->set_stylebox("normal","MenuButton", make_stylebox( button_normal_png,6,6,6,6,3,3,3,3) );
- t->set_stylebox("pressed","MenuButton", make_stylebox( tool_button_pressed_png ,6,6,6,6,3,3,3,3) );
- t->set_stylebox("hover","MenuButton", make_stylebox( button_normal_png,6,6,6,6,3,3,3,3) );
+
+
+ // MenuButton
+
+ 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 );
+
t->set_color("font_color","MenuButton", control_font_color );
t->set_color("font_color_pressed","MenuButton", control_font_color_pressed );
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_stylebox("focus","OptionButton", Ref<StyleBox>( memnew( StyleBoxEmpty )) );
- t->set_constant("hseparation","MenuButton", 2 );
-
+ t->set_constant("hseparation","MenuButton", 3 );
+
+ // ButtonGroup
+
+ t->set_stylebox("panel","ButtonGroup", memnew( StyleBoxEmpty ));
+
+ // 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);
+
+ 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_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_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);
+
t->set_stylebox("normal","CheckButton", cb_empty );
t->set_stylebox("pressed","CheckButton", cb_empty );
t->set_stylebox("disabled","CheckButton", cb_empty );
t->set_stylebox("hover","CheckButton", cb_empty );
- //t->set_stylebox("hover","CheckButton", make_stylebox( button_hover_png,5,5,5,5,3,3,3,3) );
+ t->set_stylebox("focus","CheckButton", focus );
+
+ t->set_icon("on","CheckButton", make_icon(toggle_on_png) );
+ t->set_icon("off","CheckButton", make_icon(toggle_off_png));
+
t->set_font("font","CheckButton", default_font );
+
t->set_color("font_color","CheckButton", control_font_color );
t->set_color("font_color_pressed","CheckButton", control_font_color_pressed );
t->set_color("font_color_hover","CheckButton", control_font_color_hover );
t->set_color("font_color_disabled","CheckButton", control_font_color_disabled );
- t->set_icon("on","CheckButton", make_icon(toggle_on_png) );
- t->set_icon("off","CheckButton", make_icon(toggle_off_png));
- t->set_stylebox("focus","CheckButton", focus );
+
t->set_constant("hseparation","CheckButton",4);
t->set_constant("check_vadjust","CheckButton",0);
-
+
+
+ // Label
+
t->set_font("font","Label", default_font );
+
t->set_color("font_color","Label", Color(1,1,1) );
t->set_color("font_color_shadow","Label", Color(0,0,0,0) );
+
t->set_constant("shadow_offset_x","Label", 1 );
t->set_constant("shadow_offset_y","Label", 1 );
t->set_constant("shadow_as_outline","Label", 0 );
- t->set_stylebox("normal","LineEdit", make_stylebox( line_edit_png,4,4,4,4,3,4,3,4) );
- t->set_stylebox("focus","LineEdit", focus );
- t->set_stylebox("read_only","LineEdit", make_stylebox( line_edit_disabled_png,6,6,6,6,4,4,4,4) );
- Image n(line_edit_png);
- Image nf(line_edit_focus_png);
+ // LineEdit
+
+ t->set_stylebox("normal","LineEdit", make_stylebox( line_edit_png,5,5,5,5) );
+ t->set_stylebox("focus","LineEdit", focus );
+ t->set_stylebox("read_only","LineEdit", make_stylebox( line_edit_disabled_png,6,6,6,6) );
t->set_font("font","LineEdit", default_font );
+
t->set_color("font_color","LineEdit", control_font_color );
t->set_color("font_color_selected","LineEdit", Color(0,0,0) );
t->set_color("cursor_color","LineEdit", control_font_color_hover );
t->set_color("selection_color","LineEdit", font_color_selection );
- t->set_constant("minimum_spaces","LineEdit", 8 );
- t->set_stylebox("bg","ProgressBar", make_stylebox( progress_bar_png,5,5,5,5,0,0,0,0) );
- t->set_stylebox("fg","ProgressBar", make_stylebox( progress_fill_png,5,5,5,5,2,2,2,2) );
+ t->set_constant("minimum_spaces","LineEdit", 12 );
+
+
+
+ // ProgressBar
+
+ t->set_stylebox("bg","ProgressBar", make_stylebox( progress_bar_png,4,4,4,4,0,0,0,0) );
+ t->set_stylebox("fg","ProgressBar", make_stylebox( progress_fill_png,6,6,6,6,2,1,2,1) );
+
t->set_font("font","ProgressBar", default_font );
- t->set_color("font_color","ProgressBar", control_font_color );
+
+ t->set_color("font_color","ProgressBar", control_font_color_hover );
t->set_color("font_color_shadow","ProgressBar", Color(0,0,0) );
- t->set_icon("tab","TextEdit", make_icon( tab_png) );
- t->set_stylebox("normal","TextEdit", make_stylebox( tree_bg_png,12,12,12,12,3,3,3,3) );
- t->set_stylebox("focus","TextEdit", focus );
- t->set_stylebox("completion","TextEdit", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) );
- t->set_constant("completion_lines","TextEdit", 7 );
- t->set_constant("completion_max_width","TextEdit", 50 );
- t->set_constant("completion_scroll_width","TextEdit", 3 );
- t->set_color("completion_scroll_color","TextEdit", control_font_color_pressed );
- t->set_color("completion_existing","TextEdit", control_font_color );
+ // TextEdit
- //t->set_font("font","TextEdit", mono_font );
+ t->set_stylebox("normal","TextEdit", make_stylebox( tree_bg_png,3,3,3,3) );
+ t->set_stylebox("focus","TextEdit", focus );
+ t->set_stylebox("completion","TextEdit", make_stylebox( tree_bg_png,3,3,3,3) );
+
+ t->set_icon("tab","TextEdit", make_icon( tab_png) );
t->set_font("font","TextEdit", default_font );
+
+ t->set_color("completion_scroll_color","TextEdit", control_font_color_pressed );
+ t->set_color("completion_existing","TextEdit", control_font_color );
t->set_color("font_color","TextEdit", control_font_color );
t->set_color("font_color_selected","TextEdit", Color(0,0,0) );
t->set_color("selection_color","TextEdit", font_color_selection );
t->set_color("mark_color","TextEdit", Color(1.0,0.4,0.4,0.4) );
- t->set_color("breakpoint_color","TextEdit", Color(0.8,0.8,0.4,0.4) );
- t->set_color("current_line_color","TextEdit", Color(0.3,0.5,0.8,0.15) );
+ t->set_color("breakpoint_color","TextEdit", Color(0.8,0.8,0.4,0.2) );
+ t->set_color("current_line_color","TextEdit", Color(0.25,0.25,0.26,0.8) );
t->set_color("cursor_color","TextEdit", control_font_color );
t->set_color("symbol_color","TextEdit", control_font_color_hover );
- t->set_constant("line_spacing","TextEdit",1 );
+ t->set_color("brace_mismatch_color","TextEdit", Color(1,0.2,0.2) );
+
+ t->set_constant("completion_lines","TextEdit", 7 );
+ t->set_constant("completion_max_width","TextEdit", 50 );
+ t->set_constant("completion_scroll_width","TextEdit", 3 );
+ t->set_constant("line_spacing","TextEdit",4 );
- t->set_stylebox("scroll","HScrollBar", make_stylebox( hscroll_bg_png,3,3,3,3,0,0,0,0) );
- t->set_stylebox("scroll_focus","HScrollBar", make_stylebox( hscroll_bg_png,3,3,3,3,0,0,0,0) );
- t->set_stylebox("grabber","HScrollBar", make_stylebox( hscroll_grabber_png,3,3,3,3,2,2,2,2) );
- t->set_stylebox("grabber_hilite","HScrollBar", make_stylebox( hscroll_grabber_hl_png,3,3,3,3,2,2,2,2) );
+
+ Ref<Texture> empty_icon = memnew( ImageTexture );
+
+ // HScrollBar
+
+ 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);
@@ -344,247 +477,397 @@ void make_default_theme() {
t->set_icon("decrement_hilite","HScrollBar",empty_icon);
- t->set_stylebox("scroll","VScrollBar", make_stylebox( vscroll_bg_png,3,3,3,3,0,0,0,0) );
- t->set_stylebox("scroll_focus","VScrollBar", make_stylebox( vscroll_bg_png,3,3,3,3,0,0,0,0) );
- t->set_stylebox("grabber","VScrollBar", make_stylebox( vscroll_grabber_png,3,3,3,3,2,2,2,2) );
- t->set_stylebox("grabber_hilite","VScrollBar", make_stylebox( vscroll_grabber_hl_png,3,3,3,3,2,2,2,2) );
+
+ // VScrollBar
+
+ 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);
t->set_icon("decrement","VScrollBar",empty_icon);
t->set_icon("decrement_hilite","VScrollBar",empty_icon);
- t->set_stylebox("slider","HSlider", make_stylebox( hslider_bg_png,5,5,5,5,1,1,1,1) );
- t->set_stylebox("focus","HSlider", make_stylebox( focus_png,3,3,3,3,1,1,1,1) );
- //t->set_stylebox("slider_focus","HSlider", make_stylebox( hslider_bg_focus_png,6,6,6,6,2,2,2,2) );
+
+
+ // HSlider
+
+ t->set_stylebox("slider","HSlider", make_stylebox( hslider_bg_png,4,4,4,4) );
+ t->set_stylebox("grabber_hilite","HSlider", make_stylebox( hslider_grabber_hl_png,6,6,6,6) );
+ t->set_stylebox("focus","HSlider", focus );
+
t->set_icon("grabber","HSlider", make_icon( hslider_grabber_png ) );
t->set_icon("grabber_hilite","HSlider", make_icon( hslider_grabber_hl_png ) );
t->set_icon("tick","HSlider", make_icon( hslider_tick_png ) );
- t->set_stylebox("grabber_hilite","HSlider", make_stylebox( hslider_grabber_hl_png,6,6,6,6,2,2,2,2) );
- t->set_stylebox("slider","VSlider", make_stylebox( vslider_bg_png,5,5,5,5,1,1,1,1) );
- t->set_stylebox("focus","HSlider", make_stylebox( focus_png,3,3,3,3,1,1,1,1) );
- //t->set_stylebox("slider_focus","VSlider", make_stylebox( vslider_bg_focus_png,6,6,6,6,2,2,2,2) );
+
+
+
+ // VSlider
+
+ t->set_stylebox("slider","VSlider", make_stylebox( vslider_bg_png,4,4,4,4) );
+ t->set_stylebox("grabber_hilite","VSlider", make_stylebox( vslider_grabber_hl_png,6,6,6,6) );
+ t->set_stylebox("focus","HSlider", focus );
+
t->set_icon("grabber","VSlider", make_icon( vslider_grabber_png) );
t->set_icon("grabber_hilite","VSlider", make_icon( vslider_grabber_hl_png ) );
t->set_icon("tick","VSlider", make_icon( vslider_tick_png ) );
- t->set_stylebox("grabber_hilite","VSlider", make_stylebox( vslider_grabber_hl_png,6,6,6,6,2,2,2,2) );
+
+
+
+ // SpinBox
t->set_icon("updown","SpinBox",make_icon(spinbox_updown_png));
- Ref<StyleBoxTexture> style_pp_win = make_stylebox( popup_window_png,6,28,6,7,8,8,8,8);
- for(int i=0;i<4;i++)
+
+ // WindowDialog
+
+ 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 );
- t->set_constant("titlebar_height","WindowDialog", 18 );
- t->set_constant("title_height","WindowDialog", 20 );
- t->set_font("title_font","WindowDialog", large_font );
- t->set_color("title_color","WindowDialog", Color(0,0,0) );
+
t->set_icon("close","WindowDialog", make_icon( close_png ) );
t->set_icon("close_hilite","WindowDialog", make_icon( close_hl_png ) );
+
+ t->set_font("title_font","WindowDialog", large_font );
+
+ t->set_color("title_color","WindowDialog", Color(0,0,0) );
+
t->set_constant("close_h_ofs","WindowDialog", 22 );
t->set_constant("close_v_ofs","WindowDialog", 20 );
+ t->set_constant("titlebar_height","WindowDialog", 18 );
+ t->set_constant("title_height","WindowDialog", 20 );
- Ref<StyleBoxTexture> style_pp = make_stylebox( popup_bg_png,6,19,6,7,8,8,8,8);
- style_pp->set_expand_margin_size(MARGIN_LEFT,2);
- style_pp->set_expand_margin_size(MARGIN_TOP,3);
- style_pp->set_expand_margin_size(MARGIN_RIGHT,2);
- style_pp->set_expand_margin_size(MARGIN_BOTTOM,3);
+ // Popup
- t->set_stylebox("panel","PopupMenu", style_pp );
- t->set_stylebox("panel","PopupPanel", style_pp );
+ 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++) {
selected->set_expand_margin_size(Margin(i),2);
}
- t->set_stylebox("panel_disabled","PopupMenu", make_stylebox( popup_bg_disabled_png,5,5,5,5) );
+ t->set_stylebox("panel","PopupPanel", style_pp );
+
+
+
+
+ // PopupMenu
+
+ t->set_stylebox("panel","PopupMenu", make_stylebox( popup_bg_png,4,4,4,4,10,10,10,10) );
+ t->set_stylebox("panel_disabled","PopupMenu", make_stylebox( popup_bg_disabled_png,4,4,4,4) );
t->set_stylebox("hover","PopupMenu", selected );
t->set_stylebox("separator","PopupMenu", make_stylebox( vseparator_png,3,3,3,3) );
- t->set_icon("checked","PopupMenu", make_icon(popup_checked_png) );
- t->set_icon("unchecked","PopupMenu", make_icon(popup_unchecked_png) );
+
+ t->set_icon("checked","PopupMenu", make_icon(checked_png) );
+ t->set_icon("unchecked","PopupMenu", make_icon(unchecked_png) );
t->set_icon("submenu","PopupMenu", make_icon(submenu_png) );
+
t->set_font("font","PopupMenu", default_font );
+
t->set_color("font_color","PopupMenu", control_font_color );
t->set_color("font_color_accel","PopupMenu", Color(0.7,0.7,0.7,0.8) );
t->set_color("font_color_disabled","PopupMenu", Color(0.4,0.4,0.4,0.8) );
t->set_color("font_color_hover","PopupMenu", control_font_color );
- t->set_constant("hseparation","PopupMenu",2);
- t->set_constant("vseparation","PopupMenu",1);
-
- t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) );
+
+ t->set_constant("hseparation","PopupMenu",4);
+ t->set_constant("vseparation","PopupMenu",4);
+
+
+ // GraphNode
+
+ 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 ) );
+ t->set_font("title_font","GraphNode", default_font );
+ t->set_color("title_color","GraphNode", Color(0,0,0,1));
+ t->set_constant("title_offset","GraphNode", 18);
+ t->set_constant("close_offset","GraphNode", 18);
+ t->set_constant("port_offset","GraphNode", 3);
+
+
+ // Tree
+
+ Ref<StyleBoxTexture> tree_selected = make_stylebox( selection_png,4,4,4,4,8,0,8,0);
+ Ref<StyleBoxTexture> tree_selected_oof = make_stylebox( selection_oof_png,4,4,4,4,8,0,8,0);
+
+ t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5) );
t->set_stylebox("bg_focus","Tree", focus );
- Ref<StyleBoxTexture> tree_selected = make_stylebox( selection_png,4,4,4,4);
- Ref<StyleBoxTexture> tree_selected_oof = make_stylebox( selection_oof_png,4,4,4,4);
- for(int i=0;i<4;i++) {
- tree_selected->set_expand_margin_size(Margin(i),2);
- tree_selected_oof->set_expand_margin_size(Margin(i),2);
- }
t->set_stylebox("selected","Tree", tree_selected_oof );
t->set_stylebox("selected_focus","Tree", tree_selected );
- t->set_stylebox("completion_selected","TextEdit", tree_selected );
-
-
t->set_stylebox("cursor","Tree", focus );
t->set_stylebox("cursor_unfocused","Tree", focus );
- t->set_stylebox("button_pressed","Tree",make_stylebox( button_pressed_png,5,5,5,5,3,3,3,3));
+ t->set_stylebox("button_pressed","Tree",make_stylebox( button_pressed_png,4,4,4,4));
+ t->set_stylebox("title_button_normal","Tree", make_stylebox( tree_title_png,4,4,4,4) );
+ t->set_stylebox("title_button_pressed","Tree", make_stylebox( tree_title_pressed_png,4,4,4,4) );
+ t->set_stylebox("title_button_hover","Tree", make_stylebox( tree_title_png,4,4,4,4) );
+
+ t->set_icon("checked","Tree",make_icon(checked_png));
+ t->set_icon("unchecked","Tree",make_icon(unchecked_png));
+ t->set_icon("updown","Tree",make_icon(updown_png));
+ t->set_icon("select_arrow","Tree",make_icon(dropdown_png));
+ t->set_icon("arrow","Tree",make_icon(arrow_down_png));
+ t->set_icon("arrow_collapsed","Tree",make_icon(arrow_right_png));
+
+ t->set_font("title_button_font","Tree", default_font );
t->set_font("font","Tree", default_font );
+
+ t->set_color("title_button_color","Tree", control_font_color );
t->set_color("font_color","Tree", control_font_color_low );
- t->set_color("font_color_selected","Tree", control_font_color );
+ t->set_color("font_color_selected","Tree", control_font_color_pressed );
t->set_color("selection_color","Tree", Color(0.1,0.1,1,0.8) );
t->set_color("cursor_color","Tree", Color(0,0,0) );
t->set_color("guide_color","Tree", Color(0,0,0,0.1) );
- t->set_constant("hseparation","Tree",2);
- t->set_constant("vseparation","Tree",1);
- t->set_constant("guide_width","Tree",1);
+
+ t->set_constant("hseparation","Tree",4);
+ t->set_constant("vseparation","Tree",4);
+ t->set_constant("guide_width","Tree",2);
t->set_constant("item_margin","Tree",12);
- t->set_constant("button_margin","Tree",2);
+ t->set_constant("button_margin","Tree",4);
- t->set_stylebox("title_button_normal","Tree", make_stylebox( tree_title_png,4,4,4,4,3,3,3,3) );
- t->set_stylebox("title_button_pressed","Tree", make_stylebox( tree_title_pressed_png,4,4,4,4,3,3,3,3) );
- t->set_stylebox("title_button_hover","Tree", make_stylebox( tree_title_png,4,4,4,4,3,3,3,3) );
- t->set_color("title_button_color","Tree", control_font_color );
- t->set_font("title_button_font","Tree", default_font );
+ // ItemList
+ Ref<StyleBoxTexture> item_selected = make_stylebox( selection_png,4,4,4,4,8,2,8,2);
+ Ref<StyleBoxTexture> item_selected_oof = make_stylebox( selection_oof_png,4,4,4,4,8,2,8,2);
- t->set_icon("checked","Tree",make_icon(checked_png));
- t->set_icon("unchecked","Tree",make_icon(unchecked_png));
- t->set_icon("updown","Tree",make_icon(updown_png));
- t->set_icon("select_arrow","Tree",make_icon(dropdown_png));
- t->set_icon("arrow","Tree",make_icon(arrow_down_png));
- t->set_icon("arrow_collapsed","Tree",make_icon(arrow_right_png));
+ t->set_stylebox("bg","ItemList", make_stylebox( tree_bg_png,4,4,4,5) );
+ t->set_stylebox("bg_focus","ItemList", focus );
+ t->set_constant("hseparation","ItemList",4);
+ t->set_constant("vseparation","ItemList",2);
+ 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_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 );
+ t->set_stylebox("selected_focus","ItemList", item_selected );
+ t->set_stylebox("cursor","ItemList", focus );
+ t->set_stylebox("cursor_unfocused","ItemList", focus );
- t->set_stylebox("tab_fg","TabContainer", make_stylebox( tab_current_png,5,5,5,5,8,3,8,3) );
- t->set_stylebox("tab_bg","TabContainer", make_stylebox( tab_behind_png,5,5,5,5,8,4,8,3) );
- Ref<StyleBoxTexture> tc_sb = make_stylebox( tab_container_bg_png,6,19,6,7);
- for(int i=0;i<4;i++) {
- tc_sb->set_default_margin(Margin(i),7);
- tc_sb->set_expand_margin_size(Margin(i),2);
- }
- //tc_sb->set_expand_margin_size(MARGIN_TOP,2);
- //tc_sb->set_default_margin(MARGIN_TOP,6);
+
+ // TextEdit
+
+ t->set_stylebox("completion_selected","TextEdit", tree_selected );
+
+
+
+ // TabContainer
+
+ 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", 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));
t->set_icon("increment_hilite","TabContainer",make_icon( scroll_button_right_hl_png));
t->set_icon("decrement","TabContainer",make_icon( scroll_button_left_png));
t->set_icon("decrement_hilite","TabContainer",make_icon( scroll_button_left_hl_png));
+ t->set_icon("menu","TabContainer",make_icon( tab_menu_png));
+ t->set_icon("menu_hilite","TabContainer",make_icon( tab_menu_hl_png));
t->set_font("font","TabContainer", default_font );
+
t->set_color("font_color_fg","TabContainer", control_font_color_hover );
- t->set_color("font_color_bg","TabContainer", control_font_color );
- t->set_constant("side_margin","TabContainer", 5 );
+ t->set_color("font_color_bg","TabContainer", control_font_color_low );
+
+ t->set_constant("side_margin","TabContainer", 8 );
t->set_constant("top_margin","TabContainer", 24);
- t->set_constant("label_valign_fg","TabContainer", 4);
- t->set_constant("label_valign_bg","TabContainer", 5);
- t->set_constant("hseparation","TabContainer", 2);
+ t->set_constant("label_valign_fg","TabContainer", 0);
+ t->set_constant("label_valign_bg","TabContainer", 2);
+ t->set_constant("hseparation","TabContainer", 4);
+
+
+
+ // Tabs
+
+ 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_stylebox("tab_fg","Tabs", make_stylebox( tab_current_png,5,5,5,5,8,3,8,3) );
- t->set_stylebox("tab_bg","Tabs", make_stylebox( tab_behind_png,5,5,5,5,8,4,8,3) );
- t->set_stylebox("panel","Tabs", make_stylebox( tab_container_bg_png,3,3,3,3) );
t->set_font("font","Tabs", default_font );
+
t->set_color("font_color_fg","Tabs", control_font_color_hover );
- t->set_color("font_color_bg","Tabs", control_font_color );
+ t->set_color("font_color_bg","Tabs", control_font_color_low );
+
t->set_constant("top_margin","Tabs", 24);
- t->set_constant("label_valign_fg","Tabs", 4);
- t->set_constant("label_valign_bg","Tabs", 5);
- t->set_constant("hseparation","Tabs", 2);
+ t->set_constant("label_valign_fg","Tabs", 0);
+ t->set_constant("label_valign_bg","Tabs", 2);
+ t->set_constant("hseparation","Tabs", 4);
+
+
+
+ // Separators
t->set_stylebox("separator","HSeparator", make_stylebox( vseparator_png,3,3,3,3) );
- t->set_constant("separation","HSeparator", 7);
t->set_stylebox("separator","VSeparator", make_stylebox( hseparator_png,3,3,3,3) );
- t->set_constant("separation","VSeparator", 7);
t->set_icon("close","Icons", make_icon(icon_close_png));
t->set_font("source","Fonts", source_font);
t->set_font("normal","Fonts", default_font );
t->set_font("large","Fonts", large_font );
+ t->set_constant("separation","HSeparator", 4);
+ t->set_constant("separation","VSeparator", 4);
+
+ // Dialogs
- t->set_constant("margin","Dialogs",10);
+ t->set_constant("margin","Dialogs",8);
t->set_constant("button_margin","Dialogs",32);
-
+
+
+
+ // FileDialog
+
t->set_icon("folder","FileDialog",make_icon(icon_folder_png));
t->set_color("files_disabled","FileDialog",Color(0,0,0,0.7));
+
+
+ // colorPicker
+
t->set_constant("value_height","ColorPicker", 23 );
t->set_constant("value_width","ColorPicker", 50);
t->set_constant("color_width","ColorPicker", 100);
- t->set_constant("label_width","ColorPicker", 15);
+ t->set_constant("label_width","ColorPicker", 20);
t->set_constant("hseparator","ColorPicker", 4);
- Ref<StyleBoxTexture> style_tt = make_stylebox( tooltip_bg_png,9,9,9,9,8,8,8,8);
+
+
+ // TooltipPanel
+
+ Ref<StyleBoxTexture> style_tt = make_stylebox( tooltip_bg_png,4,4,4,4);
for(int i=0;i<4;i++)
style_tt->set_expand_margin_size((Margin)i,4);
+
t->set_stylebox("panel","TooltipPanel", style_tt );
+
t->set_font("font","TooltipLabel", default_font );
+
t->set_color("font_color","TooltipLabel", Color(0,0,0) );
t->set_color("font_color_shadow","TooltipLabel", Color(0,0,0,0.1) );
+
t->set_constant("shadow_offset_x","TooltipLabel", 1 );
t->set_constant("shadow_offset_y","TooltipLabel", 1 );
- t->set_font("default_font","RichTextLabel", default_font );
+
+
+ // RichTextLabel
+
+ t->set_stylebox("focus","RichTextLabel", focus );
+
+ t->set_font("normal_font","RichTextLabel", default_font );
+ t->set_font("bold_font","RichTextLabel", default_font );
+ t->set_font("italics_font","RichTextLabel", default_font );
+ t->set_font("bold_italics_font","RichTextLabel", default_font );
+ t->set_font("mono_font","RichTextLabel", default_font );
+
t->set_color("default_color","RichTextLabel", control_font_color );
t->set_color("font_color_selected","RichTextLabel", font_color_selection );
t->set_color("selection_color","RichTextLabel", Color(0.1,0.1,1,0.8) );
+
t->set_constant("line_separation","RichTextLabel", 1 );
- t->set_stylebox("focus","RichTextLabel", focus );
- t->set_constant("separation","HBoxContainer",4);
- t->set_constant("separation","VBoxContainer",4);
- t->set_constant("margin","MarginContainer",15);
- t->set_constant("separation","GridContainer",4);
+ // Containers
+
+ t->set_stylebox("bg","VSplitContainer", make_stylebox( vsplit_bg_png,1,1,1,1) );
+ t->set_stylebox("bg","HSplitContainer", make_stylebox( hsplit_bg_png,1,1,1,1) );
- t->set_constant("separation","HSplitContainer",8);
- t->set_constant("separation","VSplitContainer",8);
- t->set_constant("autohide","HSplitContainer",1);
- t->set_constant("autohide","VSplitContainer",1);
t->set_icon("grabber","VSplitContainer",make_icon(vsplitter_png));
t->set_icon("grabber","HSplitContainer",make_icon(hsplitter_png));
- t->set_stylebox("bg","VSplitContainer", make_stylebox( vsplit_bg_png,1,1,1,1,1,1,1,1) );
- t->set_stylebox("bg","HSplitContainer", make_stylebox( hsplit_bg_png,1,1,1,1,1,1,1,1) );
+ t->set_constant("separation","HBoxContainer",4);
+ t->set_constant("separation","VBoxContainer",4);
+ t->set_constant("margin","MarginContainer",8);
+ t->set_constant("hseparation","GridContainer",4);
+ t->set_constant("vseparation","GridContainer",4);
+ t->set_constant("separation","HSplitContainer",12);
+ t->set_constant("separation","VSplitContainer",12);
+ t->set_constant("autohide","HSplitContainer",1);
+ t->set_constant("autohide","VSplitContainer",1);
+
+
+
+ // HButtonArray
+
+ t->set_stylebox("normal","HButtonArray", make_stylebox( button_normal_png,4,4,4,4,0,4,22,4) );
+ t->set_stylebox("selected","HButtonArray", make_stylebox( button_pressed_png,4,4,4,4,0,4,22,4) );
+ t->set_stylebox("hover","HButtonArray", make_stylebox( button_hover_png,4,4,4,4) );
- t->set_stylebox("normal","HButtonArray", make_stylebox( button_normal_png,2,2,2,2,3,3,3,3) );
- t->set_stylebox("selected","HButtonArray", make_stylebox( button_pressed_png,5,5,5,5,3,3,3,3) );
- t->set_stylebox("hover","HButtonArray", make_stylebox( button_hover_png,5,5,5,5,3,3,3,3) );
- t->set_stylebox("focus","HButtonArray", make_stylebox( focus_png,5,5,5,5,3,3,3,3) );
t->set_font("font","HButtonArray", default_font);
t->set_font("font_selected","HButtonArray", default_font);
- t->set_color("font_color","HButtonArray", Color(1,1,1,1) );
- t->set_color("font_color_selected","HButtonArray", Color(0.7,0.7,0.7,1) );
- t->set_constant("icon_separator","HButtonArray", 2 );
- t->set_constant("button_separator","HButtonArray", 3 );
-
- t->set_stylebox("normal","VButtonArray", make_stylebox( button_normal_png,2,2,2,2,3,3,3,3) );
- t->set_stylebox("selected","VButtonArray", make_stylebox( button_pressed_png,5,5,5,5,3,3,3,3) );
- t->set_stylebox("hover","VButtonArray", make_stylebox( button_hover_png,5,5,5,5,3,3,3,3) );
- t->set_stylebox("focus","VButtonArray", make_stylebox( focus_png,5,5,5,5,3,3,3,3) );
+
+ t->set_color("font_color","HButtonArray", control_font_color_low );
+ t->set_color("font_color_selected","HButtonArray", control_font_color_hover );
+
+ t->set_constant("icon_separator","HButtonArray", 4 );
+ t->set_constant("button_separator","HButtonArray", 8 );
+
+ t->set_stylebox("focus","HButtonArray", focus );
+
+
+ // VButtonArray
+
+ t->set_stylebox("normal","VButtonArray", make_stylebox( button_normal_png,4,4,4,4,0,4,22,4) );
+ t->set_stylebox("selected","VButtonArray", make_stylebox( button_pressed_png,4,4,4,4,0,4,22,4) );
+ t->set_stylebox("hover","VButtonArray", make_stylebox( button_hover_png,4,4,4,4) );
+
t->set_font("font","VButtonArray", default_font);
t->set_font("font_selected","VButtonArray", default_font);
- t->set_color("font_color","VButtonArray", Color(1,1,1,1) );
- t->set_color("font_color_selected","VButtonArray", Color(0.7,0.7,0.7,1) );
- t->set_constant("icon_separator","VButtonArray", 2 );
- t->set_constant("button_separator","VButtonArray", 3 );
- t->set_stylebox("border","ReferenceFrame", make_stylebox( reference_border_png,5,5,5,5,3,3,3,3) );
+ t->set_color("font_color","VButtonArray", control_font_color_low );
+ t->set_color("font_color_selected","VButtonArray", control_font_color_hover );
+
+ t->set_constant("icon_separator","VButtonArray", 4);
+ t->set_constant("button_separator","VButtonArray", 8);
+
+ t->set_stylebox("focus","VButtonArray", focus );
+
+
+ // ReferenceFrame
Ref<StyleBoxTexture> ttnc = make_stylebox( full_panel_bg_png,8,8,8,8);
ttnc->set_draw_center(false);
+
+ t->set_stylebox("border","ReferenceFrame", make_stylebox( reference_border_png,4,4,4,4) );
t->set_stylebox("panelnc","Panel", ttnc );
t->set_stylebox("panelf","Panel", tc_sb );
-
t->set_stylebox("panel","PanelContainer", tc_sb );
t->set_icon( "logo","Icons", make_icon(logo_png) );
+
+
+ // Theme
+
Theme::set_default( t );
Theme::set_default_icon( make_icon(error_icon_png) );
Theme::set_default_style( make_stylebox( error_icon_png,2,2,2,2) );
@@ -611,8 +894,8 @@ void make_default_theme() {
style->set_texture(texture);
for(int i=0;i<4;i++) {
- style->set_margin_size( Margin(),2);
- style->set_default_margin( Margin(),2);
+ style->set_margin_size( Margin(),8);
+ style->set_default_margin( Margin(),8);
}
Ref<Font> f = make_default_font();
@@ -625,10 +908,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/dropdown.png b/scene/resources/default_theme/dropdown.png
index 5279e72d24..72fc5d73a3 100644
--- a/scene/resources/default_theme/dropdown.png
+++ b/scene/resources/default_theme/dropdown.png
Binary files differ
diff --git a/scene/resources/default_theme/focus.png b/scene/resources/default_theme/focus.png
index 0daf85718f..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/full_panel_bg.png b/scene/resources/default_theme/full_panel_bg.png
index b43469a8aa..771e50e2af 100644
--- a/scene/resources/default_theme/full_panel_bg.png
+++ b/scene/resources/default_theme/full_panel_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node.png b/scene/resources/default_theme/graph_node.png
new file mode 100644
index 0000000000..3adccf2c3b
--- /dev/null
+++ b/scene/resources/default_theme/graph_node.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png
new file mode 100644
index 0000000000..ea5b510418
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_close.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/graph_port.png b/scene/resources/default_theme/graph_port.png
new file mode 100644
index 0000000000..92f425f977
--- /dev/null
+++ b/scene/resources/default_theme/graph_port.png
Binary files differ
diff --git a/scene/resources/default_theme/hscroll_bg.png b/scene/resources/default_theme/hscroll_bg.png
deleted file mode 100644
index 9d6381f0c9..0000000000
--- a/scene/resources/default_theme/hscroll_bg.png
+++ /dev/null
Binary files differ
diff --git a/scene/resources/default_theme/hscroll_bg_focus.png b/scene/resources/default_theme/hscroll_bg_focus.png
deleted file mode 100644
index e81a867b87..0000000000
--- a/scene/resources/default_theme/hscroll_bg_focus.png
+++ /dev/null
Binary files differ
diff --git a/scene/resources/default_theme/hscroll_grabber.png b/scene/resources/default_theme/hscroll_grabber.png
deleted file mode 100644
index 9015038911..0000000000
--- a/scene/resources/default_theme/hscroll_grabber.png
+++ /dev/null
Binary files differ
diff --git a/scene/resources/default_theme/hscroll_grabber_hl.png b/scene/resources/default_theme/hscroll_grabber_hl.png
deleted file mode 100644
index 11c895e9e3..0000000000
--- a/scene/resources/default_theme/hscroll_grabber_hl.png
+++ /dev/null
Binary files differ
diff --git a/scene/resources/default_theme/hslider_bg.png b/scene/resources/default_theme/hslider_bg.png
index 2d6c336e18..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 626709dd32..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 30b06089c5..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/hslider_tick.png b/scene/resources/default_theme/hslider_tick.png
index 3ba740355e..e8e18b5402 100644
--- a/scene/resources/default_theme/hslider_tick.png
+++ b/scene/resources/default_theme/hslider_tick.png
Binary files differ
diff --git a/scene/resources/default_theme/hsplit_bg.png b/scene/resources/default_theme/hsplit_bg.png
index 6147aac10d..34033289d0 100644
--- a/scene/resources/default_theme/hsplit_bg.png
+++ b/scene/resources/default_theme/hsplit_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/hsplitter.png b/scene/resources/default_theme/hsplitter.png
index cfd9ab7d93..4173dc02e7 100644
--- a/scene/resources/default_theme/hsplitter.png
+++ b/scene/resources/default_theme/hsplitter.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_folder.png b/scene/resources/default_theme/icon_folder.png
index 9ec797a8a5..0abf60253a 100644
--- a/scene/resources/default_theme/icon_folder.png
+++ b/scene/resources/default_theme/icon_folder.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_play.png b/scene/resources/default_theme/icon_play.png
index f04a5cd789..40bbce5f0d 100644
--- a/scene/resources/default_theme/icon_play.png
+++ b/scene/resources/default_theme/icon_play.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_stop.png b/scene/resources/default_theme/icon_stop.png
index 5ae2851d57..b0fd5caa83 100644
--- a/scene/resources/default_theme/icon_stop.png
+++ b/scene/resources/default_theme/icon_stop.png
Binary files differ
diff --git a/scene/resources/default_theme/line_edit.png b/scene/resources/default_theme/line_edit.png
index 3d8b748dff..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 4507c36857..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/option_arrow.png b/scene/resources/default_theme/option_arrow.png
index 4c04cbc6ad..b0ab74421a 100644
--- a/scene/resources/default_theme/option_arrow.png
+++ b/scene/resources/default_theme/option_arrow.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_disabled.png b/scene/resources/default_theme/option_button_disabled.png
index 6cb7c6f858..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 da0216e813..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 fb61d0b50f..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 116e6e2a3e..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 255269ee68..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 655b3eadf4..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_checked.png b/scene/resources/default_theme/popup_checked.png
index 7cd2cd45b0..d313db6820 100644
--- a/scene/resources/default_theme/popup_checked.png
+++ b/scene/resources/default_theme/popup_checked.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_window.png b/scene/resources/default_theme/popup_window.png
index de903216d1..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/progress_bar.png b/scene/resources/default_theme/progress_bar.png
index 5d290ce0fb..3016c52216 100644
--- a/scene/resources/default_theme/progress_bar.png
+++ b/scene/resources/default_theme/progress_bar.png
Binary files differ
diff --git a/scene/resources/default_theme/progress_fill.png b/scene/resources/default_theme/progress_fill.png
index d446407f08..ee7c3315e4 100644
--- a/scene/resources/default_theme/progress_fill.png
+++ b/scene/resources/default_theme/progress_fill.png
Binary files differ
diff --git a/scene/resources/default_theme/radio_checked.png b/scene/resources/default_theme/radio_checked.png
new file mode 100644
index 0000000000..ada8dde3c1
--- /dev/null
+++ b/scene/resources/default_theme/radio_checked.png
Binary files differ
diff --git a/scene/resources/default_theme/radio_unchecked.png b/scene/resources/default_theme/radio_unchecked.png
new file mode 100644
index 0000000000..018af99afd
--- /dev/null
+++ b/scene/resources/default_theme/radio_unchecked.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_bg.png b/scene/resources/default_theme/scroll_bg.png
new file mode 100644
index 0000000000..e1e419d663
--- /dev/null
+++ b/scene/resources/default_theme/scroll_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_down.png b/scene/resources/default_theme/scroll_button_down.png
index 87de51d5ef..88b218f581 100644
--- a/scene/resources/default_theme/scroll_button_down.png
+++ b/scene/resources/default_theme/scroll_button_down.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_down_hl.png b/scene/resources/default_theme/scroll_button_down_hl.png
index cfece0d5d0..90b1a48ac8 100644
--- a/scene/resources/default_theme/scroll_button_down_hl.png
+++ b/scene/resources/default_theme/scroll_button_down_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_left.png b/scene/resources/default_theme/scroll_button_left.png
index 57bdb29ea1..8e60a96476 100644
--- a/scene/resources/default_theme/scroll_button_left.png
+++ b/scene/resources/default_theme/scroll_button_left.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_left_hl.png b/scene/resources/default_theme/scroll_button_left_hl.png
index a5f497178a..1114a92381 100644
--- a/scene/resources/default_theme/scroll_button_left_hl.png
+++ b/scene/resources/default_theme/scroll_button_left_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_right.png b/scene/resources/default_theme/scroll_button_right.png
index 7fc0748305..ee79c0aa56 100644
--- a/scene/resources/default_theme/scroll_button_right.png
+++ b/scene/resources/default_theme/scroll_button_right.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_right_hl.png b/scene/resources/default_theme/scroll_button_right_hl.png
index 9e643262b3..b83e24a954 100644
--- a/scene/resources/default_theme/scroll_button_right_hl.png
+++ b/scene/resources/default_theme/scroll_button_right_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_up.png b/scene/resources/default_theme/scroll_button_up.png
index 3487213eba..251106b487 100644
--- a/scene/resources/default_theme/scroll_button_up.png
+++ b/scene/resources/default_theme/scroll_button_up.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_up_hl.png b/scene/resources/default_theme/scroll_button_up_hl.png
index e263754f50..059b4b0f2b 100644
--- a/scene/resources/default_theme/scroll_button_up_hl.png
+++ b/scene/resources/default_theme/scroll_button_up_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_grabber.png b/scene/resources/default_theme/scroll_grabber.png
new file mode 100644
index 0000000000..3a193e5448
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..82c94c03c8
--- /dev/null
+++ b/scene/resources/default_theme/scroll_grabber_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/selection.png b/scene/resources/default_theme/selection.png
index 08e242c28c..3b1c810c40 100644
--- a/scene/resources/default_theme/selection.png
+++ b/scene/resources/default_theme/selection.png
Binary files differ
diff --git a/scene/resources/default_theme/selection_oof.png b/scene/resources/default_theme/selection_oof.png
index c6e5ee285b..e8680128cd 100644
--- a/scene/resources/default_theme/selection_oof.png
+++ b/scene/resources/default_theme/selection_oof.png
Binary files differ
diff --git a/scene/resources/default_theme/submenu.png b/scene/resources/default_theme/submenu.png
index 286300e25b..034912eb7a 100644
--- a/scene/resources/default_theme/submenu.png
+++ b/scene/resources/default_theme/submenu.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_behind.png b/scene/resources/default_theme/tab_behind.png
index 953c76eabb..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_container_bg.png b/scene/resources/default_theme/tab_container_bg.png
index bfe117af39..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 08f4faf829..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/tab_menu.png b/scene/resources/default_theme/tab_menu.png
new file mode 100644
index 0000000000..c5659da11b
--- /dev/null
+++ b/scene/resources/default_theme/tab_menu.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_menu_hl.png b/scene/resources/default_theme/tab_menu_hl.png
new file mode 100644
index 0000000000..6f68502c07
--- /dev/null
+++ b/scene/resources/default_theme/tab_menu_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 9cef0265ee..c338126d3a 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -5,12 +5,12 @@
static const unsigned char arrow_down_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,0x98,0x0,0x74,0x0,0xf2,0x18,0x7e,0x84,0x12,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,0xdd,0x9,0x16,0x10,0x34,0x34,0x9c,0xae,0x6b,0x51,0x0,0x0,0x0,0x91,0x49,0x44,0x41,0x54,0x28,0xcf,0xb5,0x91,0xbd,0x9,0xc3,0x40,0xc,0x85,0xbf,0x5c,0x76,0xf1,0x95,0x1e,0x20,0x99,0xe7,0x46,0x50,0x77,0x95,0xba,0x1b,0x41,0xf3,0x24,0x7b,0x18,0x63,0xbc,0x80,0x21,0xe0,0xca,0x69,0x64,0x38,0x12,0xc7,0x89,0x8b,0x3c,0x10,0xe8,0xe7,0x7b,0xcd,0x13,0xfc,0x5d,0x2a,0x76,0x88,0x3d,0x79,0x73,0x1,0x6e,0x5f,0xf8,0x6b,0x2e,0xe9,0x1e,0x7c,0x58,0x80,0x69,0x7,0x9e,0x9c,0x61,0x35,0x74,0xc0,0x79,0x5d,0xbe,0x68,0xf1,0x5b,0x7,0x10,0x54,0x8c,0x5c,0xd2,0x8,0x44,0x60,0xde,0x30,0xcc,0x40,0xcc,0x25,0x8d,0x2a,0x46,0xc8,0x25,0xe1,0xa6,0x1,0x68,0x81,0xbe,0x82,0x7b,0xa0,0xcd,0x25,0xd,0xce,0xbc,0xa7,0xa5,0x62,0x8d,0x8a,0x3d,0xbc,0x9a,0xdd,0x24,0x2b,0x53,0x54,0xb1,0xf8,0x53,0xec,0x35,0x70,0xe4,0x47,0x1f,0xf5,0x4,0x90,0xda,0x3c,0x12,0x9e,0x52,0xc6,0x4e,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,0xde,0x9,0x1c,0xa,0x30,0xc,0x28,0x58,0xa2,0xa7,0x0,0x0,0x0,0x7c,0x49,0x44,0x41,0x54,0x28,0x91,0xa5,0xd1,0xcb,0xa,0x83,0x30,0x10,0x46,0xe1,0xaf,0x97,0x77,0xe9,0xb2,0x74,0xed,0xda,0xf7,0x5f,0x57,0x8,0x88,0x88,0x2f,0xe0,0xa2,0xb8,0x4a,0x37,0x51,0x52,0x49,0x2b,0xa1,0x3f,0xc,0x84,0x33,0x73,0x86,0x90,0x9c,0x42,0x8,0x6a,0x72,0xae,0x9a,0xfe,0x47,0x68,0x10,0xf,0xaa,0xc9,0x85,0x88,0xf9,0xc7,0xe2,0x39,0xcd,0x6c,0x42,0x8f,0xcb,0xa,0x77,0x89,0xa9,0xd7,0xe7,0xc2,0x84,0x1b,0x96,0x82,0xb0,0xa4,0xde,0x94,0xb,0x30,0xe2,0x8e,0x21,0x63,0x43,0x62,0xe3,0xa,0xf6,0xaf,0xd4,0xa1,0xc5,0x2b,0x55,0x9b,0xd8,0x96,0x6b,0xe1,0xa,0x1d,0x1e,0xd9,0xf9,0x23,0x25,0x1,0x9e,0x5f,0x78,0xfd,0xc7,0xbd,0x1,0x73,0x20,0x21,0xa9,0x4,0x80,0xe0,0x11,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char arrow_right_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,0x98,0x0,0x74,0x0,0xf2,0x18,0x7e,0x84,0x12,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,0xdd,0x9,0x16,0x10,0x35,0x5,0xd4,0x6b,0x5a,0x2a,0x0,0x0,0x0,0xa0,0x49,0x44,0x41,0x54,0x28,0xcf,0x95,0x92,0xbd,0xd,0xc2,0x40,0xc,0x46,0x1f,0x81,0x2,0xa,0x36,0xa0,0x86,0x16,0x6a,0x68,0x59,0xc5,0x23,0xa4,0x73,0x75,0x9d,0x47,0xc8,0x24,0x48,0xb4,0x2c,0x11,0x68,0x10,0x42,0x59,0x80,0x2,0x51,0x1d,0x4d,0x22,0x5,0x73,0x47,0xc4,0xd7,0x59,0xf2,0xf3,0xe7,0x3f,0x68,0x15,0xca,0x8a,0xbe,0x7c,0xdc,0x69,0xe4,0x92,0xb6,0x40,0x4,0xae,0x6a,0xd2,0x84,0xb2,0x42,0x4d,0x3e,0x80,0xc2,0x15,0x38,0x1,0x7,0xe0,0x12,0xca,0x6a,0xa1,0x26,0x5f,0x4e,0x45,0xc2,0x75,0xe,0xcc,0x5a,0x68,0xe9,0xa1,0x2,0xb2,0xad,0x4e,0x81,0xa3,0x87,0xfc,0xc,0x31,0x1,0x3f,0x81,0x8d,0x9a,0xd4,0xbf,0x1c,0xb2,0x1a,0x2,0x6e,0xc0,0x5a,0x4d,0xea,0xae,0xa5,0x49,0x26,0x31,0x2,0x2f,0x60,0xaf,0x26,0xe7,0xfe,0x7a,0x53,0xc0,0x3,0x18,0x3,0x2b,0x35,0xb9,0xfb,0x5b,0x78,0x60,0x37,0x74,0x38,0xfe,0x7d,0x8d,0x37,0xf2,0x54,0x41,0xdd,0x92,0x6e,0x8a,0x2e,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,0xde,0x9,0x1c,0xa,0x2e,0x1a,0x8,0xcd,0x28,0x29,0x0,0x0,0x0,0x7b,0x49,0x44,0x41,0x54,0x28,0x91,0x95,0xd1,0xb1,0xe,0x1,0x51,0x10,0x46,0xe1,0x6f,0x51,0x50,0x78,0x5,0x25,0xad,0x9e,0xd6,0x53,0x6f,0x4b,0xaf,0x45,0x6e,0x22,0x22,0x5e,0x40,0xa5,0x5a,0x8d,0x2b,0x32,0x76,0xb9,0x7b,0xba,0x99,0xc9,0x99,0x4c,0xfe,0xa9,0x52,0x4a,0xfa,0x30,0xa,0xf5,0xa,0xd,0xce,0xb8,0x95,0x8,0x5b,0xdc,0x31,0xc4,0x2,0xd7,0x28,0xc,0x5a,0x96,0x4c,0x31,0xc1,0x9,0xf3,0x12,0x1,0x2a,0x8c,0x51,0x47,0xa9,0x4b,0xc8,0xcc,0xb0,0x7f,0x9d,0x57,0x24,0x7c,0xf1,0x4f,0xb8,0x60,0x89,0x43,0x6e,0xc4,0x94,0x32,0xd,0x1e,0xd8,0xe0,0xf8,0x39,0x68,0x13,0x7e,0xc6,0x1a,0x85,0xb5,0x9e,0x8f,0xdb,0x75,0x9c,0xf8,0xe6,0x9,0x8,0x62,0x16,0x5f,0x9a,0xba,0xfd,0xff,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -25,27 +25,37 @@ 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,0x3e,0x0,0x34,0x0,0x44,0xb5,0x81,0x75,0x5d,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,0xdd,0x9,0x1b,0x15,0xd,0x2e,0x9b,0xe9,0x5,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,0x0,0xec,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0xd0,0xb1,0x6a,0xc2,0x50,0x0,0x85,0xe1,0xff,0x26,0x91,0x28,0x41,0x8a,0xb5,0x6,0xa3,0x90,0x21,0x6b,0x69,0xc1,0xa1,0x5d,0x3a,0xb9,0x38,0x76,0x28,0x94,0x2e,0x3e,0x96,0x8f,0xe0,0x22,0x85,0xe2,0xec,0xe2,0xe4,0x62,0x7,0xa1,0xd0,0xb5,0x43,0x21,0x55,0x4c,0x62,0xb4,0x41,0x6a,0x12,0xaa,0x2e,0xba,0xdf,0xe0,0xd2,0xa1,0xff,0xfe,0x9d,0xe1,0x8,0x0,0xdb,0x72,0x6e,0x81,0x16,0x70,0x8d,0x5c,0x6f,0xc0,0xe0,0x73,0xfa,0x31,0x16,0xb6,0xe5,0xdc,0x5b,0x95,0x7a,0xbb,0x71,0x79,0x43,0xad,0x52,0x97,0xd2,0x5f,0x9e,0xcb,0xe4,0xfd,0x95,0xa9,0xe7,0x76,0x85,0x6d,0x39,0x9d,0x87,0xd6,0x93,0xf9,0x13,0x6f,0x8,0xc2,0x85,0xd4,0x40,0xb9,0x74,0x4e,0x41,0xcf,0xf3,0x32,0xe8,0xcd,0x35,0xc0,0x5c,0x45,0x2b,0xa2,0xf5,0x1a,0xd9,0x82,0x70,0x41,0xd1,0x30,0x0,0x4c,0x5,0xc8,0x84,0x8f,0x1d,0x8d,0xc2,0x89,0xfd,0xf,0xfc,0x95,0x1,0x7f,0x19,0xf9,0x99,0xe1,0xc1,0xf8,0xea,0x59,0xb1,0x94,0x4b,0xd2,0xf8,0x4a,0xd3,0x54,0xa,0xba,0x21,0x85,0xc3,0x6f,0x8f,0x99,0xe7,0x92,0xa4,0x49,0x5f,0x0,0xdc,0x35,0x9a,0x8f,0xf3,0x60,0xd6,0x8c,0xd3,0xf8,0x42,0x66,0x40,0xcf,0xe9,0xbe,0x59,0xae,0xe,0x47,0x93,0xe1,0xb3,0x0,0xd8,0x6d,0x77,0x2a,0x90,0xcf,0xf0,0xc9,0x16,0xd8,0x8,0x45,0xfc,0xee,0x1,0x19,0x87,0x50,0x44,0x2,0xd,0x4,0xc3,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,0x4e,0x0,0x41,0x0,0x56,0xed,0xd0,0x4e,0x61,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,0xdd,0x9,0x1b,0x15,0xb,0x2f,0xba,0xb4,0x92,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,0x1,0x7b,0x49,0x44,0x41,0x54,0x38,0xcb,0x95,0x92,0xbd,0x2f,0x44,0x41,0x14,0xc5,0x7f,0x77,0xbc,0xcd,0x5a,0x1f,0x11,0x11,0x62,0x49,0x56,0x96,0x52,0x45,0xa2,0x53,0x9,0x7a,0x1a,0xbd,0xce,0x1f,0x40,0x2b,0x3a,0xf1,0xf,0xe8,0xf4,0x1a,0x7a,0x12,0x95,0x4e,0x42,0xa5,0x44,0x6c,0xb2,0x88,0x8d,0x42,0x7c,0xbe,0x8f,0x99,0xab,0xd8,0xd9,0xf7,0x56,0x88,0x3c,0x37,0x99,0xc9,0xe4,0xdc,0x73,0xcf,0x9c,0x7b,0x67,0x44,0x55,0x19,0x1b,0x99,0x58,0x2,0xd6,0x80,0x5,0xf2,0xc5,0x31,0xb0,0x7b,0x7b,0x77,0x75,0x28,0x95,0xf2,0xf8,0x7a,0x79,0x70,0x74,0x67,0x6a,0x72,0x86,0x91,0xc1,0xd1,0x5c,0xd5,0x77,0x8d,0x3a,0x17,0x97,0x67,0xdc,0x37,0xea,0x1b,0x52,0x29,0x8f,0x5f,0x2f,0x2f,0xae,0x54,0x3f,0xc2,0x4f,0xde,0x3f,0xde,0x72,0x9,0x74,0x95,0xba,0x29,0x15,0x3b,0x39,0x38,0xda,0xbf,0x9,0x80,0xea,0xf3,0xcb,0x33,0x71,0x12,0x93,0x37,0xde,0xde,0x5f,0x89,0xa2,0x10,0xa0,0x6a,0x80,0x7f,0x15,0xb7,0xa2,0x55,0x13,0x0,0xa8,0x75,0x20,0x3e,0xa3,0xa0,0xfe,0x28,0x1e,0x53,0xf,0x48,0xba,0x91,0x92,0x2,0x0,0xab,0x16,0x54,0x9a,0xa0,0xb4,0x5d,0xa3,0xbf,0x5c,0xed,0x5a,0x1c,0xcd,0x4,0x12,0x67,0x1,0x83,0xc1,0x81,0x1a,0xcf,0xcb,0xce,0x88,0xc3,0x60,0x52,0x5,0xa7,0xc6,0x2b,0x79,0x1,0x67,0x6d,0xab,0xa4,0x99,0x48,0x2d,0xbb,0xd4,0x88,0xa3,0xad,0x4d,0xdc,0x77,0x7,0xd6,0x29,0xa2,0x9e,0x2c,0x20,0x2a,0x80,0x66,0xb3,0xf0,0xbb,0x8a,0x22,0x1e,0x54,0x3f,0xa0,0xa6,0x80,0xb5,0x18,0x1c,0x4e,0xf0,0xb6,0x5d,0x6a,0x38,0x73,0xd0,0x96,0xd3,0x8c,0xd1,0x6c,0xc1,0x25,0xde,0x2c,0xa0,0x69,0x23,0x3f,0x26,0x8e,0x6f,0xa3,0x8d,0x41,0x0,0xd4,0xa2,0x24,0xac,0x4,0xa6,0xf0,0x73,0xe2,0xbf,0xbd,0x82,0xc7,0x12,0x17,0x3,0xd4,0x3a,0xfa,0x7a,0xfb,0x3b,0xa3,0x38,0x9c,0xef,0x2a,0x75,0x63,0x8c,0x78,0xc6,0xdf,0x2b,0xb1,0x31,0xf,0x8d,0x3a,0x51,0x1c,0x6d,0x8b,0xaa,0x32,0x3b,0x3d,0xb7,0xf9,0xf8,0xf4,0xb0,0x1a,0xc6,0x61,0x25,0xcf,0x2f,0x2c,0x16,0x8a,0xb5,0xa1,0x81,0xe1,0xbd,0xd3,0xf3,0x93,0x2d,0x51,0x55,0x50,0xa,0x40,0xf,0xd0,0x91,0xf3,0x27,0x5b,0xe0,0x15,0x21,0xfe,0x2,0x54,0x16,0xb4,0xfe,0xee,0xb0,0x9,0x99,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,0x4e,0x0,0x41,0x0,0x56,0xed,0xd0,0x4e,0x61,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,0xdd,0x9,0x1b,0x15,0xb,0x19,0x75,0xe,0x7,0x2e,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,0x77,0x49,0x44,0x41,0x54,0x38,0xcb,0x95,0x92,0x3d,0x4f,0x54,0x41,0x14,0x86,0x9f,0xb3,0x7b,0x5d,0x2f,0xa8,0xc4,0xaf,0x5,0x51,0x24,0xd9,0x82,0x46,0xb,0x12,0x1a,0xb,0x5a,0xc,0x95,0x5,0x7f,0xc1,0xce,0x1f,0x0,0xad,0xb1,0x33,0xfe,0x1,0x3b,0xff,0x82,0x85,0x95,0xb1,0xb6,0xb0,0x31,0xb1,0x80,0xc6,0x44,0x92,0x35,0x1a,0x40,0x4,0x34,0x7c,0x2c,0xf7,0xce,0xcc,0x4b,0x71,0x67,0x71,0x76,0x85,0xe4,0x72,0x92,0xb9,0x99,0xbc,0x73,0xde,0x8f,0x39,0x77,0x4c,0x12,0x77,0xc7,0xef,0x2f,0x1,0xcf,0x80,0xc7,0xd4,0xab,0xf,0xc0,0xeb,0x9f,0x5b,0xdf,0xdf,0xda,0x64,0x7b,0x6a,0xb9,0x7d,0x63,0xe2,0xd5,0xc3,0x99,0x59,0xee,0xdc,0xba,0x57,0x8b,0xbd,0xf1,0xfb,0x7,0xab,0x5f,0xbf,0xf0,0x6b,0x77,0x73,0xc5,0x26,0xdb,0x53,0xdf,0x16,0xe7,0x9f,0x74,0x7a,0x45,0x8f,0xa3,0xde,0x61,0x2d,0x81,0x91,0x7c,0x94,0xbc,0x95,0xf3,0xfe,0xe3,0xbb,0xf5,0xc,0xe8,0xfc,0x3d,0xf8,0x83,0x73,0x8e,0xba,0x75,0x78,0x74,0x40,0x51,0x1e,0x3,0x74,0x1a,0xc0,0x85,0xc8,0xfd,0xea,0x73,0x32,0x0,0x85,0x0,0x16,0x4f,0x4,0x8a,0x5b,0x8b,0x98,0x22,0x60,0xa7,0x1f,0x4e,0x9b,0x32,0x0,0x2f,0xf,0xb2,0xa,0xb4,0xc4,0x46,0x67,0x58,0x87,0x7e,0x8f,0x12,0x81,0x50,0xa1,0x86,0x2a,0x21,0x40,0xc9,0x1e,0x13,0x96,0x58,0x4b,0x36,0x28,0x10,0x82,0x1f,0xb4,0x4e,0x23,0xa7,0x41,0xd2,0x74,0x83,0x9,0x84,0x29,0x54,0xb0,0x81,0x45,0x7,0xd,0xf0,0xc,0x99,0xb0,0x8,0x2a,0xe,0xa8,0x4a,0xe0,0x3d,0x86,0xaa,0xc4,0x91,0x3c,0x3c,0xa,0x91,0x9c,0xe9,0x5f,0x47,0x25,0x20,0x3f,0xd4,0xc9,0x39,0x77,0x18,0xbe,0x46,0x25,0xd0,0x2d,0x5d,0x31,0xdd,0x6c,0x64,0xff,0x4f,0xfc,0xac,0xbf,0x10,0x31,0x1f,0x1c,0x40,0xb7,0x79,0xed,0xca,0x58,0x5e,0xba,0x62,0x21,0xbf,0x3c,0x82,0x35,0x2c,0x89,0x71,0xfe,0xf2,0xde,0xb1,0xbd,0xbb,0x49,0xe9,0xca,0x97,0x26,0x89,0xb9,0x7,0x8f,0x9e,0xef,0xec,0x6d,0x3f,0x2d,0x5c,0x31,0x5d,0xe7,0x15,0xb6,0xb2,0x56,0xf7,0xe6,0xf5,0xdb,0x6f,0x3e,0xaf,0x7d,0x7a,0x61,0x92,0x50,0xd0,0x25,0xe0,0x2a,0xd0,0xac,0xf9,0x92,0x3d,0xb0,0x6f,0xd,0x2b,0x4f,0x0,0xb1,0x79,0xab,0x16,0x83,0x7a,0xfa,0xf1,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,0x3e,0x0,0x34,0x0,0x44,0xb5,0x81,0x75,0x5d,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,0xdd,0x9,0x1b,0x15,0xd,0xa,0xa7,0xea,0xe1,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,0x53,0x49,0x44,0x41,0x54,0x38,0xcb,0x95,0x93,0x4d,0x4a,0xc4,0x40,0x10,0x85,0xbf,0x72,0x12,0x93,0x19,0xfc,0x43,0x4,0x51,0x41,0x1c,0xf4,0xa,0xae,0xdd,0xe8,0x1,0xbc,0x82,0xbb,0x39,0x80,0x6e,0xc5,0x9d,0x78,0x1,0x77,0x5e,0xc1,0x3,0xcc,0xca,0xb5,0x57,0x10,0x84,0x1,0x11,0x51,0x5c,0x89,0x26,0x23,0xa9,0xe7,0xa2,0x3b,0x71,0x46,0x66,0x11,0x6b,0xd1,0x5d,0xa4,0xaa,0x5e,0xbf,0xf7,0xba,0x63,0x92,0xe8,0x6f,0xed,0x1d,0x3,0x3,0xe0,0x88,0x76,0x31,0x4,0xae,0x1f,0x9f,0x1e,0x6e,0x6d,0x67,0x73,0xf7,0x34,0x9b,0xcf,0xaf,0xba,0x59,0x8f,0x2c,0xcf,0x5a,0x4d,0x97,0x45,0xc9,0x57,0xf9,0x49,0x39,0x2e,0xce,0x12,0x60,0xb0,0xb4,0xb0,0x4c,0x37,0xef,0x61,0x66,0xad,0x0,0xb2,0x34,0x27,0x4d,0x53,0x5e,0xdf,0x8b,0x41,0x2,0xf4,0xbb,0x79,0xf,0x0,0x49,0xb4,0x8d,0x38,0xd3,0x4f,0x66,0xd,0xa,0x30,0x84,0x8,0x8c,0xea,0x7c,0x16,0xbf,0x4,0xa0,0x72,0xf,0x45,0xb,0x60,0x66,0x86,0x4,0x98,0x47,0x66,0x6,0x26,0x3c,0xd6,0x50,0x38,0xa4,0x1,0x70,0x55,0x1,0xc0,0x6b,0x90,0xc8,0x24,0xee,0x56,0xd3,0x2,0x54,0xf7,0x4c,0x2,0xc8,0xbd,0xf9,0xc0,0xa4,0x1a,0x9b,0x6,0x62,0x46,0x4f,0x60,0xe0,0x1e,0x7,0x4,0xb2,0xc6,0x3,0xec,0x17,0xa1,0xf1,0x20,0xf6,0x4c,0x7b,0xd0,0x48,0x30,0x64,0x8e,0x9,0xdc,0xc,0x53,0xf4,0x80,0x90,0xbb,0x81,0x85,0xe5,0x8f,0x4,0x39,0x8a,0xc6,0x58,0x64,0x80,0xbc,0xb9,0x5,0x88,0xb9,0xc0,0x9,0x7,0xd4,0xa5,0x20,0xa1,0xf2,0x46,0x73,0x9b,0x97,0xa0,0x3f,0x1e,0x8c,0x2a,0xaf,0xb6,0xeb,0xeb,0x69,0x1b,0xf1,0xed,0x8c,0x3a,0x2b,0x8b,0xab,0xb9,0x4c,0x87,0x9d,0xb9,0x84,0xff,0x44,0xf9,0x5d,0xe0,0x95,0x5f,0x9a,0x24,0xe,0xf6,0x8f,0xce,0x5f,0xde,0x9e,0x4f,0xca,0x71,0xb1,0xdd,0xea,0x5f,0x98,0xcf,0x47,0xeb,0x6b,0x1b,0x37,0x77,0xf7,0xc3,0xb,0x53,0x70,0x2f,0x5,0x16,0x80,0x4e,0x4b,0x2,0x15,0xf0,0x81,0xf1,0xfd,0x3,0xe7,0x4,0xa3,0xf4,0x4f,0x7,0x6b,0x83,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,0x34,0x0,0x2e,0x0,0x39,0xc0,0x34,0x46,0xdb,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,0xdd,0x9,0x1b,0x12,0x7,0x16,0x4c,0x4b,0x43,0x36,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,0xd0,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0xbf,0x6b,0x53,0x51,0x14,0xc7,0x3f,0xaf,0x7d,0xa4,0x31,0x49,0x93,0x26,0x69,0x5e,0x5e,0x4c,0x8a,0x15,0x41,0x84,0x80,0xb5,0xb5,0x2a,0x82,0xa2,0xa8,0x4b,0xc1,0x45,0xc1,0x5d,0xba,0x94,0xe,0x5,0x11,0x4,0x45,0x94,0x3a,0x29,0xe,0xae,0x1d,0x4,0xd1,0xc1,0x3f,0x40,0x7,0xd1,0x49,0x8c,0x14,0x5c,0x8a,0x38,0x38,0x44,0xc8,0x62,0x69,0x4d,0x43,0xa5,0xc5,0xa,0x49,0xee,0xbb,0x3f,0x1c,0x34,0x8f,0xbc,0xf4,0x5,0x44,0xf,0x1c,0xb8,0xf7,0x7e,0xcf,0xf9,0x9c,0xc3,0xe1,0x1e,0xcb,0x71,0x1c,0xfe,0xc7,0xec,0xde,0x87,0x46,0xa3,0xf1,0xd7,0xc9,0x8e,0xe3,0x4,0x1,0x83,0x26,0x72,0xb5,0x90,0x2b,0xcd,0x3,0xc7,0x7b,0x83,0xc7,0x8b,0x7,0xb8,0xbe,0x70,0xe3,0x47,0x3c,0x11,0xab,0x65,0xf3,0xe9,0x63,0x27,0xce,0x4e,0xaa,0x40,0x7,0x83,0x26,0x72,0xd7,0x1d,0xdd,0x7b,0xef,0xf0,0xc1,0x29,0x32,0xa9,0xdc,0xae,0x6a,0xe7,0x67,0xce,0xa0,0x94,0x4a,0xce,0x5d,0x9b,0x9d,0xf4,0x3c,0xef,0xe,0xb0,0x8,0x30,0xd0,0x15,0x33,0x7f,0xe4,0xd0,0x34,0xcd,0x76,0x93,0xda,0x6a,0x35,0xe0,0x7b,0xa2,0x31,0x32,0xce,0x8,0xf,0x1f,0x3d,0xe0,0xd4,0xd4,0x39,0x2c,0xcb,0x9a,0xb,0x9b,0x81,0xbb,0xbd,0xb3,0x85,0x52,0x6a,0x57,0xf5,0xa3,0x27,0x27,0xa8,0xbc,0xfa,0x80,0x3d,0x60,0xd3,0x6a,0x37,0x1,0xdc,0x8e,0xd6,0xdd,0x1,0x6d,0xd1,0x42,0x2a,0x8f,0x42,0xae,0xc8,0xcc,0x85,0x8b,0xa4,0x93,0x19,0x4a,0xf9,0x7d,0x94,0xf6,0x17,0x78,0x5d,0x79,0x49,0x3c,0x96,0xa0,0x2d,0x5a,0x1,0x78,0x0,0x60,0x8c,0xc1,0x18,0x43,0xed,0xeb,0x17,0x8a,0xe3,0x2e,0x97,0xaf,0x5c,0xa2,0x5c,0x2e,0xf3,0x79,0xa5,0x8a,0xa7,0x3c,0x5f,0xef,0xb,0x90,0x52,0x22,0xa5,0xc4,0xa0,0xb9,0xbd,0x78,0x93,0x74,0x36,0xc5,0xf4,0xe9,0x9,0x2a,0xef,0xdf,0x11,0x1b,0x8a,0xfb,0x7a,0x5f,0x80,0x36,0xa,0x6d,0x7e,0xcf,0x20,0x11,0x1f,0xe6,0xd9,0xe3,0xe7,0x88,0x96,0xe0,0x53,0x75,0xc5,0xd7,0x3a,0x7a,0xe8,0x47,0xd2,0x5a,0xfb,0xe7,0x68,0x24,0xca,0xf2,0xc7,0xb7,0xc,0x3d,0x8d,0x92,0x8c,0xa7,0x2,0x5a,0xbf,0xe,0xd6,0x84,0x14,0x68,0xad,0x7d,0x1f,0x4d,0xe7,0x79,0xb3,0xfc,0xc2,0x87,0x6b,0xad,0x11,0x52,0x0,0xac,0x85,0x1,0x96,0x36,0x36,0xd7,0x11,0x52,0xa0,0xb4,0x46,0xfd,0xa9,0x58,0xc8,0x8d,0xf9,0x77,0x21,0x5,0x1b,0x9b,0xeb,0x0,0x4b,0x9d,0x24,0xab,0x7b,0x99,0xdc,0x91,0xb1,0xfb,0x5b,0x3b,0xdf,0x67,0xa5,0x94,0xa1,0x1b,0x66,0xdb,0x76,0x23,0x3d,0x9c,0x7d,0x52,0xdf,0x5e,0xbd,0x15,0xa,0xa8,0x7f,0xab,0x47,0x80,0x44,0xef,0x70,0xbb,0xc7,0x4,0xfc,0x74,0xb,0xae,0x8,0x5,0xfc,0x8b,0xfd,0x2,0xb8,0xb3,0xcd,0xf1,0xa1,0x77,0xab,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,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
+};
+
+
+static const unsigned char checker_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,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,0xe,0xc4,0x0,0x0,0xe,0xc4,0x1,0x95,0x2b,0xe,0x1b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0xd,0x1c,0x1b,0x52,0x41,0x72,0xa4,0x0,0x0,0x0,0x24,0x49,0x44,0x41,0x54,0x28,0x53,0x63,0xfc,0xf,0x4,0xc,0x48,0xa0,0xa1,0xa1,0x1,0xca,0x82,0x0,0x26,0x28,0x8d,0x13,0x50,0xae,0x80,0xb1,0xbe,0xbe,0x7e,0x60,0xdd,0xc0,0xc0,0x0,0x0,0x78,0x11,0x9,0x87,0x2b,0xa,0xe1,0x69,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -55,7 +65,7 @@ static const unsigned char close_png[]={
static const unsigned char close_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,0x73,0x0,0x29,0x0,0x7c,0x29,0x1e,0x61,0x18,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,0xdd,0x9,0x19,0x1,0x14,0x12,0x9e,0xa0,0x13,0x1f,0x0,0x0,0x1,0xbf,0x49,0x44,0x41,0x54,0x38,0xcb,0xcd,0x52,0x4d,0x8f,0xd2,0x50,0x14,0x3d,0x7d,0xaf,0xad,0xbc,0x9a,0xf6,0xd5,0x21,0x8,0x63,0x13,0x61,0xe1,0x8a,0xb5,0x23,0x6,0x8b,0x2b,0xd8,0xba,0x98,0x59,0xcd,0x2f,0x30,0xf3,0x3,0xf4,0x87,0x68,0x4c,0xf4,0x1f,0xe8,0x4f,0x30,0xb3,0xd3,0x8d,0xbb,0x59,0x98,0x8,0x21,0x10,0x9d,0x90,0x20,0x8f,0x41,0xd3,0x7,0x25,0xd8,0xf,0x5a,0x37,0x25,0x61,0x9a,0xea,0x56,0xcf,0xe6,0xdd,0x77,0xee,0xbd,0x27,0xb9,0xf7,0x5c,0xe0,0x5f,0x43,0x29,0xf8,0xab,0x59,0x1c,0xe5,0x72,0x5a,0xf6,0xc6,0x0,0xd2,0x1d,0x49,0x73,0xcd,0xb7,0xea,0xf5,0xfa,0x31,0x0,0x33,0x8,0x2,0x9,0x20,0xc8,0x78,0x9b,0x73,0x7e,0xbf,0x56,0xab,0xb9,0x52,0xca,0x9,0x80,0x5f,0x45,0x2,0x5a,0xa3,0xd1,0x38,0x69,0xb5,0x5a,0xaf,0x75,0x5d,0x3f,0x16,0x42,0x5c,0x24,0x49,0xf2,0x3,0x0,0xd3,0x34,0xed,0x51,0xaf,0xd7,0x7b,0x47,0x8,0x79,0x42,0x29,0x1d,0x49,0x29,0xbf,0x0,0x48,0xf2,0x2,0x34,0x8a,0xa2,0x1b,0x8a,0xa2,0x9c,0x10,0x42,0x2a,0x9c,0xf3,0xc7,0xcb,0xe5,0xf2,0x9b,0xaa,0xaa,0xf7,0x3a,0x9d,0xce,0xcb,0xf5,0x7a,0x5d,0x59,0xad,0x56,0xde,0x64,0x32,0x79,0x15,0xc7,0xf1,0xf7,0x9d,0x40,0x7e,0x7,0x9c,0x10,0xf2,0xb0,0xd9,0x6c,0xbe,0x31,0xc,0xa3,0xee,0xfb,0xbe,0x60,0x8c,0x29,0x9c,0xf3,0xdb,0xb3,0xd9,0xec,0xb2,0xdf,0xef,0x3f,0x4d,0xd3,0xf4,0x13,0x0,0x59,0x34,0x2,0x0,0x84,0x69,0x9a,0xfe,0xf4,0x3c,0xef,0xab,0x61,0x18,0x6d,0xd3,0x34,0xf,0x9,0x21,0x37,0x85,0x10,0xd3,0xf1,0x78,0xfc,0x3c,0x49,0x92,0x8f,0xfb,0xcd,0x0,0x40,0x8a,0xac,0x21,0x84,0xd0,0x52,0xa9,0x44,0x1,0x20,0x4d,0x53,0x10,0x42,0x88,0xaa,0xaa,0xb4,0xa8,0x36,0x4f,0xda,0xba,0xae,0xbb,0xae,0xeb,0xbe,0x60,0x8c,0xd5,0x16,0x8b,0xc5,0x34,0x8a,0xa2,0x95,0x65,0x59,0x87,0xa6,0x69,0x3e,0x90,0x52,0x7e,0xde,0x6e,0xb7,0xe2,0x8f,0x2e,0xd8,0xb6,0x7d,0xd4,0xed,0x76,0xdf,0xfa,0xbe,0x5f,0x99,0xcf,0xe7,0x97,0xa3,0xd1,0xe8,0x99,0xe7,0x79,0xef,0x2d,0xcb,0x3a,0x32,0xc,0xe3,0x6e,0xb9,0x5c,0xee,0x6d,0x36,0x9b,0xf,0x41,0x10,0x4c,0x77,0x4b,0xbc,0x36,0x82,0xe3,0x38,0xd,0x21,0x84,0x2a,0xa5,0xbc,0x1a,0xe,0x87,0x67,0x71,0x1c,0x9f,0x87,0x61,0x78,0x3e,0x18,0xc,0xce,0xc2,0x30,0xbc,0xa2,0x94,0xea,0x9c,0xf3,0x3b,0x7f,0xbb,0xca,0x3,0xc7,0x71,0x4e,0x19,0x63,0x6d,0x0,0x3c,0xe3,0x14,0x0,0x9c,0x31,0xd6,0xae,0x56,0xab,0xa7,0x0,0xe,0xa,0xdc,0xbb,0x26,0xa2,0xed,0x9d,0xf3,0x3e,0xd4,0x2c,0xa7,0xe0,0xbf,0xc2,0x6f,0x5f,0x7b,0xa6,0x3c,0x3f,0xa9,0x93,0x5b,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,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,0x11,0x4,0x37,0xf7,0xbe,0xdc,0xa,0x0,0x0,0x1,0x29,0x49,0x44,0x41,0x54,0x38,0x8d,0xa5,0xd3,0x4d,0x2b,0x45,0x61,0x10,0x7,0xf0,0xdf,0x71,0xaf,0x2c,0xa4,0x2e,0xd7,0xc2,0x95,0xb0,0xba,0x5b,0x1b,0x59,0x78,0xd9,0x5b,0x58,0xc8,0x57,0xb0,0xb2,0xb5,0xf0,0x41,0x2c,0x90,0x85,0xf2,0x1,0x94,0xb2,0xb2,0x56,0x4a,0x36,0x4a,0x36,0x36,0x3a,0x29,0x25,0xa5,0xbc,0x24,0x6f,0xb9,0x16,0xe6,0xea,0xe9,0x1c,0x56,0x77,0x6a,0x7a,0x3a,0xf3,0xfc,0xff,0xff,0x33,0x33,0xcf,0x4c,0xd6,0x6c,0x36,0x75,0x62,0x5d,0x1d,0xb1,0x51,0x2d,0x7c,0x67,0x49,0xec,0xa3,0x70,0xd7,0x1d,0xe7,0x27,0x5a,0xed,0x60,0xa5,0x5e,0xaf,0xa7,0xe4,0x7e,0x2c,0xa1,0xf,0xf,0x78,0x8b,0x78,0xd,0x93,0x98,0xc5,0x35,0x5e,0xdb,0xa4,0xb4,0x84,0x2a,0x16,0xb0,0x85,0xbd,0x0,0xf,0x84,0xcf,0x62,0x1f,0x1b,0x81,0xa9,0xfe,0x25,0x0,0x97,0x78,0xc6,0x20,0x36,0x31,0x1f,0xbe,0x1d,0xd9,0xbd,0x4,0xe6,0xd7,0xd2,0x12,0xbe,0xf0,0x84,0x53,0xcc,0x61,0x14,0x33,0x21,0x30,0x84,0x1c,0xcb,0x38,0xb,0xa1,0x92,0x0,0xbc,0xe3,0x1e,0x57,0x98,0x46,0x3,0xbd,0xb8,0xc1,0x1a,0x8e,0xa2,0x37,0xbf,0xf6,0xdf,0x33,0x56,0xc2,0x53,0x5c,0xe5,0x4f,0x60,0x21,0x83,0x9a,0x9f,0x86,0xad,0x47,0xda,0x37,0x51,0x56,0x3,0x53,0x38,0xc7,0xad,0x7f,0x5e,0xa1,0x1b,0x13,0xd8,0xd,0x42,0x8e,0xd5,0xf0,0x1c,0x23,0xd8,0x9,0x4c,0x7b,0x26,0x4a,0x83,0x34,0x1e,0xb1,0x3b,0xac,0xe0,0x24,0xe2,0x8f,0x21,0xdc,0x83,0xe1,0x94,0x90,0xa,0x7c,0xe2,0xc0,0x4f,0x23,0x73,0x5c,0x4,0x11,0x8e,0xb1,0x88,0x31,0x1c,0x6,0x16,0x64,0x85,0x65,0x6a,0x8f,0x72,0x2b,0x5,0x25,0x3f,0xcb,0x14,0x46,0xb9,0x58,0x42,0x4b,0x79,0x7,0xd2,0xc,0x4b,0xd6,0xf1,0x36,0x7e,0x3,0x2b,0x36,0x3d,0x6b,0xfa,0xe7,0xaf,0xa6,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -65,7 +75,7 @@ static const unsigned char dosfont_png[]={
static const unsigned char dropdown_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,0x73,0x0,0x29,0x0,0x7c,0x29,0x1e,0x61,0x18,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,0xdd,0x9,0x19,0x1,0x18,0x18,0xd2,0xc0,0xb5,0xd,0x0,0x0,0x0,0x8e,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0x60,0x60,0x60,0xf8,0xf0,0xf6,0x33,0x33,0x3,0x1a,0x80,0x89,0x31,0x7e,0x78,0xfb,0x99,0xf9,0xdf,0xbf,0x7f,0x7a,0x28,0xb2,0xff,0x19,0x98,0x19,0x18,0x18,0x18,0x84,0xc4,0xf8,0xcf,0xb0,0xfc,0xfd,0xfb,0xcf,0xfe,0xcb,0xc7,0x6f,0x7b,0x19,0xb0,0x80,0x57,0xcf,0xde,0x75,0x33,0x31,0x31,0x32,0xde,0x87,0xf2,0xff,0xa0,0x2b,0x60,0x62,0x66,0xba,0xc4,0xc4,0xc8,0xc4,0xf8,0x94,0x4f,0x90,0x5b,0x8a,0x81,0x81,0x81,0x85,0x81,0x81,0xe1,0x2f,0x4c,0x92,0x9b,0x97,0x33,0x4e,0x44,0x5c,0x60,0x9,0x23,0xd4,0x41,0x6c,0xff,0xff,0xff,0x17,0xfe,0xf4,0xfe,0xeb,0x33,0xb8,0xa4,0x84,0xc0,0x62,0x74,0x57,0xb3,0xbd,0x7b,0xfd,0x49,0xee,0xcd,0x8b,0xf,0xa9,0xc,0xb8,0xc0,0x87,0xb7,0x9f,0x99,0xd0,0xc5,0x0,0x9d,0xb3,0x34,0xc7,0x2,0xa0,0x66,0xfc,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,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,0xd,0x1c,0x1b,0x52,0x41,0x72,0xa4,0x0,0x0,0x0,0x8b,0x49,0x44,0x41,0x54,0x18,0x95,0x6d,0x8e,0x31,0xe,0x2,0x21,0x10,0x45,0x3f,0xc3,0x66,0x1b,0x12,0x1a,0xa8,0x2c,0x3c,0x82,0x57,0xf0,0x26,0x76,0x9e,0xc6,0x63,0xec,0x5e,0xc3,0x1b,0x58,0x79,0x1,0x2b,0x2d,0x8,0x21,0x13,0x42,0x29,0x8c,0xcd,0x92,0x6c,0x88,0xd3,0xfd,0xff,0x7e,0x26,0xf,0x0,0xc0,0xcc,0x1a,0xc3,0xf5,0x4e,0x31,0xb3,0x6e,0xad,0x9d,0xf6,0x50,0x44,0x34,0x0,0x38,0xe7,0x1e,0x53,0xad,0xf5,0x5c,0x4a,0xb9,0x8f,0x1f,0x0,0x20,0x84,0x70,0x23,0xa5,0xd4,0x6b,0xcb,0xdf,0x71,0x40,0x44,0x4f,0x22,0xa2,0xb7,0xb5,0xf6,0x0,0x60,0x2,0x50,0x3b,0x34,0xc6,0x5c,0xbc,0xf7,0xab,0xda,0x84,0x66,0x11,0x71,0x39,0xe7,0xcf,0xe,0x2e,0xa3,0xf5,0x9c,0x52,0x3a,0xc6,0x18,0xaf,0xff,0x7c,0xfa,0x88,0xc6,0xee,0x7,0x3f,0xda,0x36,0xc7,0xfa,0xc,0x38,0x2c,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -75,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,0x34,0x0,0x2e,0x0,0x39,0xc0,0x34,0x46,0xdb,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,0xdd,0x9,0x1b,0x12,0x3,0x2b,0x70,0x4f,0xca,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,0x1,0x41,0x49,0x44,0x41,0x54,0x38,0xcb,0xad,0x53,0x3b,0x6e,0xc2,0x50,0x10,0x9c,0xb5,0xcd,0x47,0xf,0x1b,0x9,0x21,0x71,0x1,0xce,0x90,0x1b,0xa4,0xd,0x17,0x40,0xe9,0x42,0x84,0x94,0x2a,0x5d,0x4,0x32,0x2d,0xe9,0xa8,0xd2,0xc4,0xe9,0x72,0x84,0xb4,0xa9,0x28,0x49,0xc5,0x1,0xb8,0x80,0x45,0x1a,0x40,0x18,0x23,0xfb,0x4d,0x9a,0x67,0xc9,0x21,0x18,0x85,0x28,0x23,0x8d,0xb6,0x9a,0x91,0x76,0x77,0x46,0x60,0x40,0x52,0x0,0x58,0x86,0xc8,0xcd,0xc,0x3a,0x37,0xb5,0x88,0x10,0x0,0x24,0x27,0x76,0x0,0x94,0xd,0x9d,0x3,0x33,0x6d,0x98,0x0,0xd8,0x1b,0x26,0x22,0x42,0xc9,0x89,0xab,0x93,0xbb,0xd7,0x60,0xb5,0x59,0x5d,0x26,0xc9,0xbe,0x89,0x23,0x70,0x9c,0xf2,0x67,0xdd,0xad,0xbf,0xdf,0x3f,0x5d,0xf7,0x0,0xec,0x0,0x24,0x20,0x69,0x93,0xac,0x8d,0x7b,0xc1,0xb4,0xdf,0x19,0x30,0x9c,0xf3,0xa8,0x18,0x0,0xc2,0x39,0x9b,0xfd,0xce,0x80,0xe3,0x5e,0x30,0x25,0x59,0x23,0x69,0x83,0x64,0x89,0x64,0xc3,0xef,0x4e,0xa2,0x34,0xa6,0x78,0x2d,0xb4,0x8b,0xc,0xbc,0x16,0xda,0x69,0x4c,0xf1,0xbb,0x93,0x88,0x64,0x83,0x64,0x29,0xdb,0xd3,0x21,0x59,0xb5,0x2b,0xc2,0x75,0x88,0x45,0x91,0xc1,0x3a,0xc4,0xc2,0xae,0x8,0x49,0x56,0xb3,0x3b,0x15,0x5d,0xfc,0x37,0xb0,0x70,0xe2,0x65,0x67,0x1b,0xfc,0x19,0xd6,0x41,0x48,0xce,0x81,0xfe,0x37,0x3,0x6d,0x52,0x15,0x9d,0xca,0x40,0x3e,0xb,0x22,0x12,0x99,0x54,0xea,0xcc,0x60,0xaf,0x94,0x3b,0x1b,0xf9,0xc3,0x65,0x1a,0xd3,0x2b,0x12,0xa7,0x31,0xbd,0x91,0x3f,0x5c,0x2a,0xe5,0xce,0x4c,0x9c,0x75,0x3e,0xca,0xea,0xf1,0xf6,0xe5,0x6d,0xbb,0xdd,0x5c,0x98,0x3f,0xff,0x80,0x88,0xec,0x94,0x72,0x3f,0x1e,0x9e,0x6f,0xae,0x0,0x6c,0x1,0x24,0x59,0x99,0x6c,0xb3,0xce,0x39,0x65,0xd2,0x22,0x92,0x4a,0x41,0x9d,0xad,0x13,0x87,0xfb,0x56,0xe7,0x2f,0x3a,0x44,0xa3,0xad,0xf6,0x7e,0xe,0x1,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
};
@@ -94,28 +104,43 @@ 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,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xdb,0xb,0x4,0x13,0x34,0x38,0xc1,0xd7,0xb6,0x4a,0x0,0x0,0x4,0x58,0x49,0x44,0x41,0x54,0x58,0xc3,0xbd,0x97,0xb1,0x72,0x1d,0x37,0xc,0x45,0xf,0xf6,0xad,0x9e,0xe4,0xc2,0x6d,0x92,0x36,0xfa,0x88,0x64,0x26,0x95,0x93,0x49,0x93,0xaf,0x76,0xe7,0x19,0xfb,0x23,0x5c,0xdb,0x6e,0x5d,0x59,0x4b,0xe2,0xa6,0x0,0x48,0x62,0x9f,0x14,0xa7,0x4a,0x76,0x46,0xab,0x5d,0x3e,0x92,0x0,0x81,0x7b,0x2f,0xb0,0xf6,0xd7,0x1f,0x7f,0x4a,0x12,0xee,0x1e,0x7f,0x12,0x92,0x0,0x40,0x2,0xbb,0x79,0x34,0x40,0xcc,0xf1,0xd3,0xa5,0x17,0xc6,0xc6,0x22,0x81,0x99,0xb1,0x6d,0xc6,0x66,0x1b,0xdb,0xb6,0x61,0x9b,0xb1,0xcb,0x45,0xf7,0x4e,0x6b,0x8d,0xd6,0x3a,0x5d,0x1d,0x77,0x27,0x7c,0xd0,0x79,0xf3,0x97,0x8c,0xbe,0xf4,0x9b,0xaa,0x71,0x40,0x86,0x19,0x6c,0x97,0x8d,0xcb,0x76,0x61,0xbf,0x5c,0xd8,0xf7,0x9d,0xcd,0x2e,0xec,0xbd,0x77,0x8e,0xde,0xf8,0xfa,0xf5,0x2b,0x9f,0xbe,0x7c,0xe6,0xff,0xb8,0x7e,0xfa,0xe1,0x47,0x5e,0xbf,0x7e,0xcd,0x9d,0x60,0xef,0x72,0x8e,0xd6,0xf8,0xf4,0xe5,0x33,0xbf,0xfd,0xf2,0x2b,0x8f,0x8f,0x8f,0xff,0xa9,0xf1,0x8f,0x1f,0x3f,0xf2,0xee,0xc3,0x7b,0x1e,0x5e,0x3d,0x70,0xd9,0x8c,0xdd,0x7b,0xa7,0xf7,0x6,0xc0,0xcf,0x8f,0x3f,0xf3,0xf6,0xed,0x5b,0xee,0xaf,0xd7,0xef,0x46,0x98,0xef,0xa4,0xdf,0xfe,0x21,0x23,0x6,0x7c,0x7b,0x7a,0xe2,0xcd,0xef,0x6f,0x78,0xf7,0xe1,0x3d,0xbd,0x77,0x7a,0x77,0x76,0x97,0xe3,0xde,0x1,0xf0,0xee,0x5c,0xef,0xee,0xf0,0x4,0xa1,0xfd,0xb,0xbe,0xce,0xde,0x9,0x1,0x4a,0x17,0x84,0x2d,0x8,0xe4,0xed,0xee,0xee,0xe,0xef,0xe,0x40,0xf7,0xc0,0xda,0xee,0xe,0x69,0x3f,0x6,0x7,0x3,0x10,0x92,0x4d,0x2f,0x6c,0x6c,0xaa,0x30,0x84,0x19,0x96,0xd6,0x83,0x21,0xc3,0xa8,0xc6,0x28,0x5e,0x9c,0x94,0x9,0x53,0xd8,0x0,0x90,0x83,0xb,0xf6,0xf0,0x56,0x33,0x2,0x41,0xc1,0x3c,0x96,0x7c,0xc6,0x21,0x67,0x84,0x53,0xe3,0x79,0x4,0x5c,0xc2,0xd3,0x57,0xa5,0x83,0x66,0x63,0x5d,0xc6,0xc2,0x85,0xc,0xbc,0xa7,0x3,0x69,0x67,0xa7,0xf0,0xbe,0xf7,0x8e,0x3c,0x23,0x60,0xb1,0x71,0xf2,0x91,0x69,0x37,0x9d,0x33,0x55,0x87,0xe2,0x74,0x9e,0xa7,0xc4,0xc,0xc9,0xc3,0xb7,0x5c,0x6b,0x8,0xdc,0xe8,0xe9,0xc0,0xb0,0xbb,0x3b,0x9a,0xe7,0xeb,0xde,0x11,0xa9,0x1,0x23,0xb7,0x99,0x6,0xf3,0x34,0x6e,0xb9,0x38,0xf3,0x6d,0x16,0xf3,0x57,0xe2,0xc,0xdc,0xb1,0x2,0x20,0x49,0x33,0x4d,0xdd,0x7d,0xc6,0x4f,0x88,0x3d,0x5e,0x98,0x11,0x70,0x1f,0xa7,0x67,0x49,0x60,0x79,0x5d,0x8e,0xc5,0x3c,0xf9,0xad,0xf0,0x45,0xd0,0x49,0xa3,0x6b,0x72,0xdc,0xfb,0x4c,0x41,0xc,0xec,0x2a,0x61,0xee,0xbd,0xcf,0xd0,0x4d,0xf0,0x94,0x3d,0xcc,0x86,0x43,0x76,0x92,0xe7,0xe9,0xd3,0x98,0x43,0x1a,0xb7,0x0,0x72,0x9d,0x33,0x53,0x30,0x22,0x50,0xe9,0xe5,0xdd,0x71,0x39,0x3,0xdf,0xc,0x5c,0x6b,0xa1,0x7a,0x5,0x67,0xcd,0x18,0x83,0x4a,0xcd,0x1f,0x2c,0x40,0xb1,0x4a,0x5,0xc8,0x3d,0x69,0x18,0xf3,0x14,0xb5,0x60,0x80,0xb0,0xf5,0x9e,0x11,0x17,0x15,0xeb,0x83,0xe3,0xb1,0x61,0x8c,0x2e,0x27,0xbd,0xa4,0x48,0x33,0x9,0xb1,0xc3,0x4d,0x7e,0xa4,0x95,0x82,0x8c,0xd2,0xae,0x49,0x9,0xe8,0xbd,0x2d,0xf4,0x9a,0x4d,0xc3,0xf6,0x82,0xfa,0xe8,0xe6,0x79,0xa2,0x1f,0x2f,0x79,0xd7,0x33,0x2d,0x6d,0xa9,0xba,0x52,0xb0,0x7c,0x47,0x3e,0xb7,0xeb,0x7d,0x9,0x91,0xb9,0x46,0x15,0xad,0xc9,0x40,0xaa,0x5a,0xc7,0x0,0x6,0x9e,0x69,0x9a,0x1c,0x37,0x9b,0xd8,0xb2,0xe1,0x98,0xac,0x44,0x20,0x34,0x67,0x57,0x71,0xb4,0xb5,0x96,0xd1,0x48,0x3d,0x73,0x8a,0x13,0x99,0xe7,0xb1,0xaf,0x59,0xee,0xbf,0xc2,0x2c,0x2f,0x98,0xcf,0x9b,0x19,0x79,0xa8,0x10,0xb6,0xa5,0x3,0xa4,0x10,0xd,0xc4,0x4e,0x16,0x14,0x8f,0x54,0xc2,0x37,0xc0,0x5f,0xe9,0xf9,0x42,0x91,0x50,0xa9,0xd,0xc3,0xa9,0x29,0x6c,0x40,0x6f,0xad,0x24,0xcf,0x93,0x86,0x39,0xb9,0xb5,0x50,0x42,0x95,0xda,0x16,0xda,0x5f,0x4a,0xcb,0xd,0x35,0x31,0x61,0xb2,0x53,0x7,0x34,0x22,0x91,0x72,0x70,0x2a,0x4f,0xad,0x15,0x29,0x9e,0x20,0xa4,0xb2,0x20,0x1d,0xb0,0x30,0xee,0xb5,0xec,0xd,0x8a,0xcd,0x32,0xa1,0x41,0x82,0x29,0x14,0xe6,0x2b,0x4d,0x13,0xc6,0xb2,0x94,0xf,0x9f,0xa5,0x5f,0x80,0x5c,0x11,0x81,0x95,0x82,0x86,0xcb,0x73,0x23,0xc7,0xb,0xfe,0xc5,0x59,0x5a,0xcf,0x2c,0xd3,0x39,0x3a,0xe3,0x79,0xe0,0xc9,0x7c,0x92,0xa2,0x95,0x62,0x24,0xc4,0xee,0x65,0xf3,0x0,0x61,0x24,0x4e,0xe7,0x5a,0xf6,0xbc,0x35,0xd1,0xb3,0xc6,0xaf,0x38,0x72,0x2,0x4b,0x46,0x23,0x80,0xdd,0x5a,0x2b,0x3a,0x48,0x54,0x43,0x7c,0x1,0xc4,0x5d,0x98,0x55,0x14,0x9c,0x99,0xbd,0x8,0x39,0xf5,0xf3,0xdc,0xbc,0xc,0x21,0xb3,0x97,0x23,0xd7,0x13,0x3,0x78,0xbc,0x47,0x39,0xce,0x69,0x47,0x6b,0xc1,0xcf,0x1b,0x10,0xa9,0x1e,0xca,0xce,0x32,0xf4,0x2c,0x45,0x5a,0xeb,0x46,0xfd,0x18,0x38,0x33,0xc1,0x51,0x31,0xc0,0x28,0x46,0x79,0x1d,0x29,0x44,0x27,0x2e,0xab,0x80,0xcd,0xc,0x73,0xc5,0xff,0xc5,0xce,0xe7,0x7d,0x60,0xa1,0xef,0xa9,0xbf,0x1,0xda,0x71,0x2c,0x91,0xf,0x16,0xac,0x8,0xf4,0xe3,0x0,0xf7,0x94,0xe1,0x1b,0xe3,0x83,0x92,0x36,0x30,0x62,0x8b,0x1,0x76,0x2b,0xba,0x2a,0x5,0x29,0x5b,0x8a,0x6c,0x99,0x8e,0xa9,0x84,0xe1,0xc4,0x1e,0xb9,0x60,0xea,0x80,0xcf,0x36,0xe6,0x4c,0x37,0x4b,0xb9,0x5d,0xd6,0xb4,0x1a,0x14,0xb7,0xa5,0x90,0x44,0xff,0x17,0xa7,0x5f,0xd5,0x74,0x48,0xb1,0x1f,0x6d,0x9,0x94,0x88,0x8e,0x68,0x84,0xee,0xa9,0x1d,0x93,0x5,0x21,0x28,0xb,0xf1,0xc2,0x66,0x63,0x39,0xde,0xe7,0x9,0xb,0xfa,0x23,0xd7,0xc9,0x51,0xb3,0x73,0x8f,0x69,0xe2,0xa9,0x1d,0x8c,0x12,0xe2,0x12,0x7b,0xad,0x74,0xab,0x1a,0x8e,0x1e,0xc0,0x17,0xb8,0x4c,0x21,0x32,0x83,0xb,0x56,0x2a,0xe5,0xed,0xfc,0xd1,0x94,0xf8,0x60,0x43,0xf4,0x88,0x96,0x54,0xaf,0xd7,0x1e,0xde,0x6c,0x91,0x82,0xa3,0x85,0x14,0x5b,0xa1,0x53,0x65,0xc0,0xc8,0xa7,0x8c,0xa,0x5e,0xcd,0xa2,0xb3,0xe8,0x36,0xfa,0xa0,0xf1,0x8d,0x99,0x81,0x9b,0xe,0x98,0xc5,0x8c,0x9d,0xcd,0xd8,0x2e,0xc6,0xf5,0xfe,0x9e,0xa7,0x6f,0xdf,0x6e,0x44,0xa6,0x56,0xb6,0xf5,0x7c,0xee,0x6,0x9e,0x2d,0x79,0xd6,0x31,0xd4,0xeb,0x68,0x8d,0xeb,0xc3,0x3d,0xdb,0x65,0x83,0xcd,0xd8,0x4d,0xf1,0xb9,0xfc,0xf0,0xea,0x15,0xd7,0xeb,0x15,0x97,0xcf,0x2e,0xb6,0x72,0xac,0x7c,0xa3,0x7c,0xff,0xfb,0xcc,0x5e,0x7e,0x37,0xb,0x35,0xdc,0xb6,0x8d,0xed,0x72,0x61,0x63,0xc3,0x30,0xfe,0x6,0x66,0xdc,0xf6,0xe9,0x76,0x8a,0xde,0xff,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,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
+};
+
+
+static const unsigned char graph_node_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,0xde,0xc,0x14,0x10,0x3,0x2e,0x15,0xb6,0x7,0x4a,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,0x6a,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xbb,0x6e,0x13,0x51,0x10,0x86,0xbf,0xf1,0x2e,0xb1,0x83,0x85,0x63,0x5,0x10,0xe2,0x22,0xa5,0x0,0x1a,0x24,0x90,0x22,0x9e,0x81,0x2,0xd1,0x53,0xf1,0x2,0x20,0xa,0x1a,0xa,0xa0,0x44,0xd0,0xd0,0x20,0x81,0xe0,0x5,0xa8,0xe8,0x11,0x5,0xcf,0x80,0x22,0x81,0x42,0x3,0x14,0x91,0xb8,0x4,0x85,0x58,0x8e,0x21,0x78,0xd7,0xd9,0x73,0x86,0xe2,0x9c,0xdd,0xec,0xae,0xd7,0xce,0x85,0xe,0xed,0x34,0xbb,0x3a,0x3e,0xf3,0xcd,0xcc,0x3f,0x63,0x69,0x47,0xd8,0x36,0x1,0x1a,0x40,0xe0,0x9f,0x42,0xd1,0x14,0xb0,0x80,0xf1,0x4f,0x25,0x77,0xa9,0x1,0x1c,0x4,0xe6,0x81,0xa3,0x40,0x7,0x38,0x50,0x2,0x6c,0x1,0x3,0x60,0xd,0xe8,0x1,0x7f,0x0,0x9b,0x46,0x6d,0x3,0x67,0xe6,0xe,0x75,0xaf,0xb7,0x9a,0xad,0xcb,0x33,0x33,0xcd,0x53,0x54,0xd8,0x68,0x14,0x7f,0x89,0xe2,0xe8,0xf5,0xc6,0xaf,0xfe,0x73,0xe0,0x13,0xb0,0x29,0x3e,0xd2,0xc2,0x7c,0xf7,0xf0,0xe3,0xd3,0xb,0x67,0xaf,0x3c,0xb8,0xfb,0x88,0xd9,0x4e,0xab,0xca,0x9f,0xe1,0x20,0xe2,0xde,0xc3,0xdb,0x7c,0x5e,0xf9,0xf8,0xaa,0xd7,0x5f,0xbf,0x5,0xac,0x8,0xd0,0x2,0x16,0x8f,0x1f,0x3b,0xf9,0xe6,0xc5,0xb3,0x97,0xed,0x24,0xb1,0x24,0xa3,0xa4,0x12,0x10,0xce,0x84,0x84,0x61,0x83,0x6b,0x37,0xae,0x6e,0x7e,0xff,0xf1,0xf5,0x12,0xb0,0x14,0x7a,0x1d,0xda,0x61,0x10,0xb6,0x87,0xbf,0x63,0x10,0x75,0x47,0xa,0x2a,0x79,0x85,0x95,0x51,0xbc,0xc5,0x28,0x86,0x30,0x8,0xdb,0xbe,0x6c,0x49,0x1,0x1,0x80,0x51,0xeb,0xfc,0x9d,0xc0,0x4e,0x6b,0xf,0xd1,0xfc,0xb9,0xb3,0x20,0x5,0x68,0xfa,0x8b,0x5a,0x8b,0xaa,0x80,0x28,0x82,0xa0,0x28,0xa2,0x92,0x73,0xd3,0xb1,0xde,0x86,0x85,0x46,0x5b,0x45,0x51,0x50,0x45,0xc4,0x95,0x61,0x53,0x27,0x71,0x61,0x74,0x1a,0xc0,0xaa,0xcd,0x6e,0xa8,0x64,0x2f,0xee,0x5d,0x29,0x8a,0x32,0x39,0x3,0x5f,0xb6,0x2f,0x4c,0x45,0x73,0x5a,0xd8,0x31,0x48,0x1,0x60,0xac,0x2d,0xf1,0x5,0x51,0x75,0x45,0x68,0x5a,0xbf,0x4e,0xcf,0x60,0xfb,0x82,0x2b,0x5a,0x73,0x4e,0xb6,0xe2,0xf,0x52,0x2,0xd8,0x82,0xe2,0x14,0x50,0x54,0xc4,0x2f,0x8b,0x68,0xad,0x1f,0x99,0x54,0x79,0x41,0xdd,0x0,0xf8,0xb6,0x82,0x88,0x4e,0xeb,0x82,0x66,0x89,0xaa,0x3b,0xc8,0x52,0x48,0x41,0x56,0x76,0xcc,0x60,0x7b,0x74,0x75,0xac,0x1a,0x49,0x47,0x72,0x72,0x6,0xe2,0xe7,0x56,0x45,0xfd,0x5d,0xc9,0x44,0x28,0x40,0x2b,0x45,0x34,0xea,0x7,0xa8,0x14,0xc9,0x92,0x75,0x64,0x7,0x11,0x8d,0x8f,0x98,0x9b,0x87,0xf2,0xf4,0x4d,0xd5,0x40,0xd5,0xc9,0x97,0xf,0xa3,0x5a,0x74,0x9c,0x36,0x89,0xf7,0x9f,0xdc,0x61,0xaf,0x96,0x1,0x92,0x2d,0xc3,0xe2,0xf9,0x8b,0xbb,0x72,0x5a,0x7a,0xff,0xb6,0x3a,0x83,0x8d,0x41,0x7f,0xcf,0x19,0x34,0xf8,0x47,0xab,0x1,0x35,0xa0,0x6,0xd4,0x80,0x1a,0x50,0x3,0x6a,0xc0,0x7f,0x9,0x90,0x8a,0x4f,0xe0,0x3d,0x67,0x60,0xf7,0xe1,0x6b,0x53,0x80,0x5,0x22,0x63,0x4c,0x6c,0x93,0x5d,0x78,0x25,0x60,0x8c,0x89,0x81,0x8,0xb0,0xd,0xbf,0xca,0xae,0x47,0xf1,0x70,0x79,0xad,0xb7,0xca,0x34,0x88,0x4d,0x60,0xad,0xb7,0x4a,0x14,0xf,0x97,0x81,0x75,0xc0,0xa4,0x9b,0xeb,0x1c,0x70,0xa1,0xd3,0xee,0x3e,0x6d,0x35,0x67,0xcf,0x5,0x41,0x50,0x29,0xae,0x31,0xc6,0x46,0xf1,0xf0,0xc3,0x60,0xb3,0x7f,0x13,0x78,0x7,0x6c,0x48,0x6e,0x85,0xeb,0x0,0x27,0x80,0x23,0x40,0x73,0xc2,0xf2,0x1d,0x3,0x3f,0x81,0x6f,0x7e,0x8f,0x36,0x52,0x12,0x34,0x4c,0xf7,0xc1,0x9,0x55,0xa8,0x2f,0x39,0xd9,0xa7,0xf0,0xe3,0xf6,0x17,0x4c,0x97,0x1d,0x24,0x5b,0x8,0x8b,0x95,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
-static const unsigned char hscroll_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x30,0x1c,0x3c,0x99,0xa,0x1c,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,0x53,0x49,0x44,0x41,0x54,0x18,0xd3,0x7d,0x8f,0xc9,0xd,0x80,0x20,0x0,0xc0,0xca,0x21,0xe8,0x5f,0x12,0x89,0x84,0xfd,0x5c,0x48,0x26,0x34,0x3e,0x74,0x2,0xa2,0xe8,0x2,0x40,0xbf,0xed,0xa7,0xc2,0xbb,0xb0,0x3,0x1b,0x75,0x92,0xf0,0x2e,0x7c,0x46,0x9b,0xaa,0xcd,0x4f,0x46,0x3,0x8c,0x76,0xea,0x7,0x4a,0x29,0x5a,0x68,0x0,0x29,0x65,0x3f,0x30,0x83,0xed,0x6,0xe9,0xbc,0x8e,0xf6,0x45,0x79,0xb,0xc0,0x5c,0xb3,0xeb,0x12,0xef,0x1f,0xc6,0x6f,0x12,0x2,0xa,0xbd,0xc9,0x5d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+static const unsigned char graph_node_close_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,0xde,0xc,0x15,0x14,0x15,0x39,0x35,0x48,0xf8,0xe3,0x0,0x0,0x0,0x80,0x49,0x44,0x41,0x54,0x28,0xcf,0xa5,0xd1,0xb1,0xa,0xc2,0x40,0x10,0x84,0xe1,0x4f,0xe5,0x30,0xad,0x9d,0xb5,0x60,0xeb,0x3,0x88,0x2f,0x6d,0xfa,0xb4,0x29,0x83,0xbd,0xb5,0xb5,0x9d,0x68,0x15,0x9b,0x3d,0xb9,0x4,0x11,0xe,0x7,0xb6,0xd9,0xfd,0x67,0xb9,0xb9,0xa5,0x52,0xab,0xa8,0x13,0xb6,0x78,0xe0,0x39,0x63,0x36,0x38,0x60,0x87,0x1b,0x34,0xb8,0x60,0xc4,0x19,0xa9,0x80,0x53,0xf4,0xc6,0x60,0x9a,0x72,0xd0,0xc6,0xa0,0x2b,0xc,0x5d,0xf4,0xda,0xd9,0xa2,0x8f,0x29,0x3,0x43,0x54,0x5e,0x90,0x7e,0xe5,0xca,0x60,0x36,0x4e,0xb4,0xf4,0x87,0xaa,0x9e,0x54,0x15,0xba,0xea,0x5b,0x17,0x71,0xb8,0x23,0x5e,0xb8,0xe2,0xfe,0xe5,0x70,0x7b,0xac,0xd1,0x57,0x7,0x7d,0x3,0x51,0x8f,0x29,0x6b,0x3c,0x49,0x28,0x81,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
-static const unsigned char hscroll_bg_focus_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x30,0x29,0x6a,0x2a,0xce,0x3f,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,0x53,0x49,0x44,0x41,0x54,0x18,0xd3,0x7d,0x8f,0xc9,0xd,0x80,0x20,0x0,0xc0,0xca,0x21,0xe8,0x5f,0x12,0x89,0x84,0xfd,0x5c,0x48,0x26,0x34,0x3e,0x74,0x2,0xa2,0xe8,0x2,0x40,0xbf,0xed,0xa7,0xc2,0xbb,0xb0,0x3,0x1b,0x75,0x92,0xf0,0x2e,0x7c,0x46,0x9b,0xaa,0xcd,0x4f,0x46,0x3,0x8c,0x76,0xea,0x7,0x4a,0x29,0x5a,0x68,0x0,0x29,0x65,0x3f,0x30,0x83,0xed,0x6,0xe9,0xbc,0x8e,0xf6,0x45,0x79,0xb,0xc0,0x5c,0xb3,0xeb,0x12,0xef,0x1f,0xc6,0x6f,0x12,0x2,0xa,0xbd,0xc9,0x5d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+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 hscroll_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x2f,0x24,0xd9,0xc1,0xbc,0x1c,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,0x93,0x49,0x44,0x41,0x54,0x18,0xd3,0x85,0x8f,0xb1,0xa,0x82,0x50,0x18,0x46,0x8f,0xf9,0x73,0xad,0x74,0x68,0xa8,0x20,0x68,0x71,0x72,0x10,0x5a,0x5b,0x7a,0xfc,0x96,0xa6,0xa0,0x47,0x88,0xa0,0x92,0x1b,0x86,0x10,0x79,0xed,0xbf,0xda,0x10,0x4,0x2d,0x79,0x96,0x6f,0x3b,0x1f,0x27,0x58,0xcc,0x96,0x1d,0x7f,0x10,0x11,0x61,0x3a,0x99,0xb3,0x5e,0x6d,0x18,0x45,0x31,0x0,0x4f,0xf7,0x60,0x77,0xd8,0x62,0xef,0x5,0x2,0x90,0xa5,0x39,0xd7,0xdb,0x19,0xef,0x3d,0x0,0x61,0x18,0x92,0xa5,0x39,0x76,0x5f,0x20,0xaa,0x8a,0x6b,0x6a,0x5c,0x53,0x7f,0xb5,0xea,0x5f,0x9f,0x55,0x45,0x8c,0x18,0x4e,0x97,0x23,0x91,0x19,0xfe,0x7c,0xbb,0xa6,0xc0,0x88,0x61,0x10,0x8f,0x13,0xca,0xca,0xe2,0x5b,0xa5,0xa3,0xa5,0xa3,0xc5,0xb7,0x4a,0x59,0x59,0xe2,0x71,0x42,0xd0,0x57,0xd1,0xcb,0x1b,0xea,0x76,0x39,0x31,0xbf,0x4b,0x5d,0xcc,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 hscroll_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x2e,0x38,0xd4,0xdb,0xd1,0x12,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,0x18,0xd3,0x85,0x8f,0x21,0xf,0x82,0x40,0x0,0x85,0x3f,0xe4,0x6e,0x27,0xca,0xa0,0x58,0x1c,0xc5,0x60,0x21,0x11,0x28,0x56,0x83,0xbf,0xda,0x60,0xb0,0xf8,0x23,0x9c,0xc5,0x9d,0xe0,0x70,0x34,0xc7,0xb1,0x3b,0xd0,0x80,0x73,0xb3,0xc8,0xf7,0xc2,0x4b,0xef,0xbd,0x3d,0x6f,0x95,0xac,0x5f,0xfc,0x41,0x48,0x29,0x59,0x2e,0x12,0xb6,0x9b,0x1d,0xc1,0x74,0xe,0x40,0x63,0x9e,0x1c,0x4e,0x7b,0x8a,0x87,0x46,0x0,0x64,0x69,0xce,0xed,0xae,0x71,0x5d,0x37,0xa4,0x7c,0x9f,0x2c,0xcd,0x29,0x8e,0x1a,0x61,0xad,0xc5,0x98,0x6,0xd3,0x36,0xdf,0x5a,0xe7,0x6,0xb7,0xd6,0x22,0x94,0x54,0x5c,0xae,0x67,0x2,0x35,0xfb,0xd9,0x6e,0x5a,0x8d,0x92,0x8a,0x49,0x14,0xc6,0x54,0x75,0x89,0xeb,0x2d,0xfd,0x47,0xae,0xb7,0x54,0x75,0x49,0x14,0xc6,0x78,0x63,0x2f,0x46,0x79,0x3,0x79,0x63,0x38,0x4a,0x58,0xf8,0x57,0x67,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,32 +150,32 @@ 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,0x4b,0x0,0x3f,0x0,0x52,0x7c,0x32,0x40,0x52,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,0xdd,0x9,0x1b,0x16,0x2b,0x22,0x53,0xc7,0x74,0xf1,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,0xd1,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x93,0x31,0x4a,0x4,0x41,0x14,0x44,0xdf,0xff,0xfd,0x77,0x86,0x41,0x57,0x10,0x19,0x99,0xc1,0x89,0xd,0x4d,0x4,0xf,0xe0,0x49,0xc4,0xcc,0x23,0x98,0xb8,0x18,0x9,0x5e,0xc0,0x4c,0x3c,0x8f,0x60,0x62,0x68,0xec,0xb2,0xa2,0x88,0x81,0x8b,0x83,0xd2,0xfd,0xdb,0xc8,0xd8,0xde,0x7c,0xb,0x2a,0xac,0x82,0x57,0x50,0xb0,0x96,0x0,0xf4,0xed,0x70,0x2,0x9c,0x1,0x47,0x85,0xb9,0x7b,0xe0,0x66,0xf1,0xf6,0x7c,0x27,0x7d,0x3b,0x5c,0x84,0x10,0x2e,0x45,0x4,0x45,0x8b,0xd2,0x8e,0x93,0x73,0x26,0xa5,0x34,0x93,0xbe,0x1d,0x16,0x4d,0xdd,0x74,0xaa,0x8a,0x4a,0x28,0x2b,0xc8,0x9,0x77,0x67,0xfc,0x1e,0x5f,0xc,0xe8,0xaa,0x49,0x8d,0xaa,0xae,0x40,0x6e,0x7f,0x5,0x9d,0x1,0x73,0x33,0xdb,0x13,0x74,0xa5,0xf1,0x54,0x1d,0x60,0x1e,0xa6,0x1b,0x5b,0xd,0x39,0x1f,0x57,0x93,0x1a,0x33,0x43,0x55,0xff,0xb5,0xbb,0xf3,0x35,0x2e,0x89,0x29,0x5e,0xb,0xc0,0xc1,0xfe,0xe1,0xd5,0xc7,0xe7,0xfb,0x69,0x8c,0x71,0xb7,0x8,0xc0,0xec,0x75,0x7b,0xba,0x73,0xfb,0xf8,0xf4,0x70,0x2e,0x0,0x9e,0xbc,0x2,0x36,0xa1,0x98,0xc3,0x81,0xa5,0x6,0xfd,0x59,0x3f,0x1,0x7e,0x1,0xa,0xde,0x42,0x4a,0x10,0xf4,0x3a,0xdc,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,0x4b,0x0,0x3f,0x0,0x52,0x7c,0x32,0x40,0x52,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,0xdd,0x9,0x1b,0x16,0x29,0x3a,0x72,0x9d,0x8e,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,0x1,0xd8,0x49,0x44,0x41,0x54,0x38,0xcb,0x7d,0x92,0xb1,0x6b,0x13,0x51,0x1c,0xc7,0x3f,0xaf,0x9,0x69,0xd2,0x33,0x26,0x2d,0x6d,0x48,0x8a,0x2d,0x94,0x82,0x48,0x43,0x3b,0x38,0x64,0xa,0x85,0x4e,0x3a,0x65,0x32,0xbb,0xab,0xb3,0x53,0x17,0x41,0x71,0xe8,0x1f,0x20,0x38,0x9,0xee,0x3a,0x39,0xb9,0xb8,0x9,0x82,0x83,0x83,0x42,0x87,0x82,0x83,0xb6,0x31,0xe1,0x25,0xc6,0xea,0xe5,0x72,0x97,0xcb,0xbd,0xfb,0x39,0x24,0x17,0x72,0xcd,0xe9,0x17,0x1e,0xf7,0xde,0xef,0xf7,0x7d,0x9f,0xdf,0xef,0xdd,0x7b,0x8a,0xa9,0x4a,0xa5,0x12,0x29,0xc9,0xdc,0x7,0x1e,0x0,0x35,0x92,0xf5,0x11,0x78,0x6e,0x94,0xff,0x52,0x6b,0xd,0x40,0x3a,0xca,0xa4,0x24,0xf3,0xa8,0xbc,0xbe,0xf9,0xf8,0xe0,0xe6,0x6d,0xd6,0xa,0x1b,0x89,0xbb,0xfb,0xbf,0xbb,0xb5,0xcf,0x67,0x9f,0x6a,0x9d,0xde,0x8f,0x6d,0xe0,0x9,0x80,0x8a,0x92,0x95,0x8d,0x1b,0xed,0xbb,0xf5,0x46,0xd9,0x71,0x1d,0xbc,0x91,0x9b,0x8,0xc8,0x2e,0xe7,0xb0,0x72,0x16,0x6f,0xdf,0xbf,0xe9,0xb4,0xbb,0x17,0x95,0x58,0x7,0x40,0xf9,0xd2,0xfe,0x85,0x31,0x86,0x7f,0xc9,0x1b,0xb9,0x8c,0x3,0x1f,0xa0,0x1c,0xc5,0xe6,0x1,0xf8,0x63,0x6f,0xae,0x29,0x99,0x7e,0x55,0xc,0x12,0x84,0x41,0x6c,0x1d,0x3,0x84,0x2,0x4a,0x42,0x44,0x81,0x42,0x81,0x80,0x10,0xa2,0x50,0x88,0x92,0x49,0x6c,0x6,0x4e,0x0,0x48,0x28,0x88,0x12,0x8,0x15,0x82,0xcc,0xec,0x82,0xa0,0x44,0x8,0x91,0x85,0x8e,0xe2,0x0,0x9,0xa7,0x5,0x26,0x46,0x99,0xab,0x96,0x34,0x4b,0x0,0xcc,0x27,0x25,0xf1,0x47,0x5e,0x8d,0xc6,0x0,0xbd,0x4b,0xcd,0xda,0xf5,0x75,0xfe,0xa7,0xfe,0x9f,0x5e,0x6c,0xbd,0x14,0x4d,0x1a,0x47,0xcd,0x43,0xdd,0xef,0x30,0x70,0x6d,0x26,0xa7,0x5d,0x1c,0x3,0xd7,0x46,0xf7,0x3b,0x34,0x8e,0x9a,0x87,0x5c,0xbd,0xa3,0xe9,0x53,0xbe,0x97,0x4e,0xa7,0x5f,0x6d,0x57,0x76,0xc8,0xa4,0x33,0xb1,0x4a,0x7e,0xe0,0x73,0xd1,0xfe,0x86,0x1f,0xf8,0x4d,0xa3,0xfc,0xd7,0xd1,0x53,0x4e,0x45,0x6,0xcb,0xb2,0x10,0x65,0x4e,0x9,0x95,0xed,0x8d,0xdc,0x3b,0x56,0x2e,0xcf,0x92,0x9a,0xf0,0x3,0x63,0x68,0xeb,0x73,0x46,0xe3,0xd1,0x43,0xa3,0xfc,0x17,0x0,0x8e,0xe3,0x2c,0x2,0xb4,0xd6,0xac,0x5c,0xcb,0x7e,0x30,0x81,0x64,0xfd,0xb1,0x57,0xcf,0x5b,0x5,0x0,0xda,0xdd,0x73,0x86,0xde,0xf0,0xc4,0x28,0xff,0xa9,0xd6,0x1a,0xcb,0xb2,0x16,0x1,0xd5,0x6a,0x95,0x5b,0x5b,0x7,0xac,0x14,0x96,0x29,0xac,0xe6,0xdf,0xf5,0xba,0xfd,0x6c,0x60,0x82,0xba,0xe3,0xe,0xb0,0x87,0xf6,0xc9,0xd6,0xce,0xe6,0x71,0xb1,0x58,0x9c,0x79,0x5a,0xad,0xd6,0xe2,0x2d,0xcc,0x6b,0x6f,0x77,0xff,0xf8,0xf4,0xeb,0x97,0xef,0x40,0x6a,0x6f,0x77,0xff,0x99,0x1d,0xfe,0x4c,0xf4,0xfd,0x5,0x7b,0xf0,0xd8,0x4,0x34,0x6f,0x3,0xa9,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,0x4b,0x0,0x3f,0x0,0x52,0x7c,0x32,0x40,0x52,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,0xdd,0x9,0x1b,0x16,0x2a,0x25,0xd4,0xb8,0xd0,0x13,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,0xd9,0x49,0x44,0x41,0x54,0x38,0xcb,0x7d,0x92,0x3d,0x6f,0x13,0x41,0x10,0x86,0x9f,0xbd,0xe0,0xf8,0xe3,0x8c,0x7c,0x12,0xc2,0x36,0x10,0x12,0xb9,0x40,0x41,0xb6,0x44,0x41,0xe1,0x2a,0x4a,0x43,0x81,0x52,0xd1,0x80,0xbb,0x48,0xb4,0xd4,0x54,0x69,0x90,0x40,0x14,0xf9,0x1,0x48,0x54,0x48,0xd4,0x40,0xc3,0xf,0x48,0x8d,0x94,0x82,0xd2,0x12,0x5,0x22,0x9,0x3e,0xd9,0x3e,0xc7,0x6,0xfc,0xb5,0xb9,0x3b,0xef,0x2e,0x85,0xed,0x70,0x8e,0x8f,0x8c,0xb4,0x5a,0xcd,0xcc,0xbb,0xcf,0x8c,0x76,0x46,0x30,0xb3,0x7c,0x3e,0xcf,0xaa,0x48,0x3f,0x5,0x9e,0x1,0x55,0xe2,0xed,0x10,0x78,0x1b,0x18,0xf9,0xde,0xf3,0x3c,0x0,0xae,0xcc,0x33,0xab,0x22,0xfd,0xe2,0x56,0x61,0xfd,0xe5,0xfd,0x72,0x95,0x6b,0xce,0xf5,0xd8,0xd7,0xdd,0xdf,0x9d,0xea,0xd7,0xfa,0x61,0xd5,0x6d,0x9f,0xac,0x3,0xaf,0x0,0xc4,0x3c,0xb9,0x56,0xd8,0x68,0x3e,0x7a,0x50,0x2b,0x8e,0xc6,0x43,0xa4,0x2f,0x63,0x1,0xe9,0x64,0x1a,0x3b,0x93,0xe5,0xf3,0xc1,0x87,0x56,0xa3,0x7d,0x7c,0x63,0xa1,0x3,0xa0,0xf8,0xab,0xdf,0x43,0x29,0xc5,0xff,0x4c,0xfa,0x92,0x60,0x12,0x0,0x14,0xe7,0xb1,0x28,0x80,0x20,0x94,0x91,0xa6,0xcc,0xec,0x16,0xb,0x90,0x89,0xe,0x17,0xfc,0x5,0x80,0x36,0x20,0xb4,0xc6,0x58,0x20,0x10,0xa0,0xc1,0xa0,0x11,0x8,0x8c,0x65,0xa6,0xb1,0x73,0x70,0x1c,0x40,0x19,0x10,0x6,0xd4,0x54,0x68,0x1,0x7a,0xd6,0x8d,0xa5,0xc,0xa,0xb3,0xd4,0xd1,0x2,0xc0,0x18,0x3d,0x2b,0x30,0x15,0xaa,0x48,0xb5,0x7f,0x3f,0x63,0x2e,0x3,0x44,0x93,0x26,0xf6,0x23,0x2f,0x46,0xad,0xa8,0xe3,0xf5,0x5a,0x68,0xad,0x2f,0x3d,0x9d,0x5e,0x2b,0x1e,0x50,0xdb,0xd9,0xdd,0x6e,0x9e,0xba,0xc,0xc6,0x7d,0xc,0x3a,0xf6,0xc,0xc6,0x7d,0x9a,0xa7,0x2e,0xb5,0x9d,0xdd,0x6d,0x2e,0xce,0x68,0xb6,0xca,0x8f,0x13,0x89,0xc4,0xc7,0xd2,0xda,0x1d,0x92,0x89,0xd5,0x85,0x4a,0x7e,0x18,0x70,0xdc,0xf8,0x8e,0x1f,0xfa,0x4f,0x2,0x23,0x3f,0xcd,0x57,0x79,0x65,0x2e,0xb0,0x6d,0x1b,0xc5,0xa4,0x2e,0xb4,0x35,0x90,0x67,0xe3,0x87,0xd9,0x4c,0xe,0xcb,0x9a,0xf2,0xc3,0x89,0xa2,0xd1,0x3c,0xe2,0x2c,0x90,0xcf,0x3,0x23,0xdf,0x1,0x8c,0x46,0xa3,0x65,0x80,0xe7,0x79,0xa4,0xec,0xe4,0x17,0xad,0x4c,0xca,0xf,0xe5,0x56,0xce,0x76,0xc0,0xc0,0xcf,0xf6,0x11,0x23,0x39,0xdc,0xf,0x8c,0x7c,0xed,0x79,0x1e,0xb6,0x6d,0x2f,0x3,0x2a,0x95,0xa,0x77,0x6f,0xdf,0x23,0x93,0x4b,0x72,0xd5,0xc9,0x1e,0x74,0x3b,0xbd,0xd4,0x44,0x85,0x5b,0x83,0x71,0x9f,0xfe,0xf0,0xcf,0xfe,0xcd,0x8d,0xc2,0x9e,0xe3,0x38,0xe7,0x1a,0xd7,0x75,0x97,0xc7,0x18,0xb5,0xcd,0x52,0x79,0xef,0xdb,0x8f,0xfa,0x9,0xb0,0xb2,0x59,0x2a,0xbf,0x19,0xe8,0x6e,0xac,0xee,0x2f,0x2,0xc9,0xee,0x56,0x52,0x6e,0x3f,0xf8,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
};
static const unsigned char hslider_tick_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x31,0xb6,0xde,0xf3,0x0,0x0,0x0,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xdb,0xb,0x4,0x17,0x21,0x8,0xd7,0xb2,0xc8,0x2e,0x0,0x0,0x0,0x63,0x49,0x44,0x41,0x54,0x18,0xd3,0xbd,0x8f,0x21,0x12,0x40,0x50,0x14,0x0,0x97,0x4f,0xf2,0x83,0x22,0x71,0x9,0xc7,0x73,0x7,0x4d,0x76,0x3,0x7,0x70,0xb,0xa3,0xf8,0x81,0x88,0x31,0x23,0x31,0x9e,0x4a,0xa1,0x20,0xdb,0xb8,0x69,0x57,0x1,0xe4,0x59,0x96,0xb8,0x58,0x62,0xba,0x76,0xb2,0x1,0x44,0x84,0x9b,0x97,0x50,0x0,0xbe,0xa7,0x5,0x98,0x4d,0xd7,0xae,0xe,0xc0,0xa0,0x83,0x8a,0x5f,0x51,0x0,0x69,0x51,0xb2,0x1e,0x8a,0xbe,0xa9,0xaf,0xd2,0xfd,0x91,0x1e,0x2d,0x63,0x12,0x6e,0x73,0xfc,0xf9,0xf2,0x12,0x27,0xf1,0xc,0x27,0x85,0x5f,0x3c,0x99,0x1e,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,0x4,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x31,0xb6,0xde,0xf3,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,0x34,0x2e,0xcd,0x40,0x50,0x4c,0x0,0x0,0x0,0x65,0x49,0x44,0x41,0x54,0x18,0x95,0xbd,0x8f,0xb1,0x9,0x80,0x30,0x10,0x0,0x8f,0x44,0xb0,0x4a,0x61,0xa3,0x73,0x38,0x5e,0x76,0x70,0x80,0xc,0xe1,0x0,0x6e,0x21,0x36,0xc2,0xf7,0x16,0x62,0xa,0x41,0x78,0xc1,0x4a,0x1b,0xb5,0x50,0xb0,0xf4,0xca,0xab,0xee,0x2c,0x40,0x8,0xc1,0x1b,0x63,0x54,0x44,0x46,0x3,0xa0,0xaa,0x5c,0xbc,0x84,0x5,0x70,0xce,0x29,0x10,0x45,0x64,0x49,0x0,0xa6,0x34,0x6b,0xf9,0x15,0xb,0x50,0xd5,0xd,0xcb,0x6e,0x19,0xfa,0xee,0x2c,0x5d,0x1f,0xe9,0xc5,0x1a,0x7d,0xbe,0xcd,0xe5,0x2d,0x3e,0xe7,0xe,0xef,0x24,0x27,0x89,0xb7,0xa5,0x60,0x2,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char hsplit_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,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x3b,0x0,0x36,0x0,0x38,0x27,0x56,0x13,0x54,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,0xdb,0xc,0x1b,0x3,0x20,0x14,0x7b,0xdd,0x35,0x55,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,0x7d,0x49,0x44,0x41,0x54,0x18,0xd3,0x4d,0x8e,0x41,0xe,0x2,0x31,0xc,0x3,0xc7,0x65,0xbf,0x89,0xb8,0xf0,0x7f,0x9,0xa4,0xdd,0xa5,0xaa,0x53,0x73,0xa0,0x2,0x72,0x4b,0x3c,0xb1,0xad,0xfb,0xf5,0x96,0xc7,0xe3,0x89,0x4,0xae,0x89,0x3d,0xa8,0x2a,0x5c,0x45,0xef,0x2f,0xb6,0xfe,0xea,0xb8,0x4c,0x95,0xb1,0xeb,0x2b,0xce,0x32,0xe7,0xd9,0x69,0x21,0x90,0x40,0xc4,0xff,0x4,0x21,0x42,0x93,0x84,0x24,0x50,0x0,0x21,0x40,0x1f,0x82,0xd6,0x2e,0xb4,0xdf,0x8b,0x90,0x42,0xd6,0xaa,0x45,0x36,0x8,0x4,0x58,0xa2,0xbe,0x11,0xcb,0x5,0xb4,0xae,0x42,0x8b,0xfd,0x6f,0xb2,0xed,0xfb,0xce,0x71,0x9c,0x38,0xa6,0x66,0xc8,0xc,0xd3,0x66,0xd8,0x8c,0x31,0x78,0x3,0x89,0x16,0x57,0xf3,0xfa,0x1c,0xf,0x2c,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,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,0xd,0x13,0x21,0x13,0xd5,0xb7,0xd9,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
};
static const unsigned char hsplitter_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x27,0x4,0x36,0x8a,0x0,0x0,0x0,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xdb,0xc,0x18,0xf,0x2b,0x9,0xe0,0x80,0xd6,0xcd,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,0x3c,0x49,0x44,0x41,0x54,0x48,0xc7,0x63,0x60,0x20,0x6,0x2c,0x9b,0x35,0xe7,0x7f,0x76,0x7c,0xd2,0x7f,0x6c,0x7c,0x26,0x6,0x6,0x6,0x86,0xa3,0x47,0x8f,0x31,0x5c,0xbe,0x79,0x1d,0xae,0x1,0x9d,0x4f,0x5,0x30,0xea,0x86,0x51,0x37,0x8c,0xba,0x61,0xd4,0xd,0xa3,0x6e,0x18,0x75,0xc3,0xa8,0x1b,0x6,0x8b,0x1b,0x0,0x64,0xbb,0x3b,0x50,0x70,0x4,0xe8,0x8b,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,0x40,0x8,0x6,0x0,0x0,0x0,0x27,0x4,0x36,0x8a,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,0x34,0x17,0x92,0x45,0xd8,0x44,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,0x3c,0x49,0x44,0x41,0x54,0x48,0x89,0x63,0x60,0x20,0x6,0x2c,0x58,0xb0,0xe0,0x7f,0x6a,0x6a,0xea,0x7f,0x6c,0x7c,0x26,0x6,0x6,0x6,0x86,0xa3,0x47,0x8f,0x32,0x5c,0xbb,0x76,0xd,0xae,0x1,0x9d,0x4f,0x5,0x30,0xea,0x86,0x51,0x37,0x8c,0xba,0x61,0xd4,0xd,0xa3,0x6e,0x18,0x75,0xc3,0xa8,0x1b,0x6,0x8b,0x1b,0x0,0xa,0x48,0x3b,0xf0,0x67,0x1e,0xb,0x3a,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -160,27 +185,27 @@ static const unsigned char icon_close_png[]={
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,0x73,0x0,0x29,0x0,0x7c,0x29,0x1e,0x61,0x18,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,0xdd,0x9,0x19,0x1,0x11,0x39,0x4f,0x6b,0x1e,0x1a,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,0x3f,0x49,0x44,0x41,0x54,0x38,0xcb,0xc5,0x92,0x4d,0x4e,0x2,0x41,0x10,0x46,0x5f,0x55,0x37,0x3,0xe3,0x8,0x12,0x7e,0xa2,0x2e,0x3c,0xa,0x57,0xd0,0xa5,0x47,0xf0,0x22,0x7a,0xa,0xae,0xe0,0xce,0xa5,0x3b,0x4f,0xa0,0xb,0x3,0x6,0x43,0x42,0x58,0xa0,0x41,0x12,0xe2,0x68,0x10,0x86,0xe9,0x76,0x33,0x90,0xa8,0x18,0x99,0x95,0x95,0xf4,0xa2,0x53,0x5d,0xd5,0xef,0xfb,0xaa,0xe0,0xbf,0x43,0x6,0xbd,0x91,0xdf,0x94,0x8,0x4a,0x85,0xab,0xc3,0xa3,0xc6,0xf1,0x74,0x12,0x7,0x1b,0xd2,0xbe,0x5a,0x2f,0x27,0x0,0x32,0xec,0x3f,0x8f,0x5c,0xea,0xf6,0x1,0x1,0x3c,0xb0,0xcc,0x1e,0x15,0xc2,0xa8,0x78,0x21,0x22,0xb3,0xef,0xc5,0x22,0x32,0x6e,0x1c,0x54,0xdb,0x0,0xd6,0x18,0x1d,0xba,0xd4,0x35,0x1,0x3,0xc8,0xce,0x6e,0xe9,0xdc,0x7b,0x5f,0x0,0x10,0x91,0x79,0xd6,0xf8,0xb,0x35,0xf8,0x35,0x95,0x3c,0xd,0x5f,0x2e,0xe7,0x1f,0xc9,0x9,0xa0,0x51,0x39,0x3c,0x7b,0x8f,0x67,0xed,0xad,0xf5,0x8b,0xbc,0xaa,0x1a,0x1d,0x0,0xe,0x50,0x8f,0x8f,0x72,0xf8,0xe7,0xd4,0xe8,0x48,0x55,0xa5,0xf,0xd8,0x95,0xbe,0x3c,0xd,0xac,0xd5,0xae,0x8a,0xea,0x23,0xa0,0x59,0x79,0x5,0x58,0xe4,0x20,0xe8,0xaa,0x88,0xf4,0x0,0xac,0x35,0x9d,0x65,0x92,0xb6,0x32,0x33,0xb7,0x89,0x40,0x8d,0xde,0x69,0xad,0x59,0xe9,0x3,0xd8,0xc0,0xdc,0x24,0x8b,0xa4,0xb5,0xa6,0xd9,0x22,0x54,0xe5,0xd6,0xae,0x2f,0x46,0xef,0xbd,0x27,0xcc,0xb3,0x85,0xb5,0xe6,0x5e,0xc7,0x66,0xe3,0x78,0xcb,0xf3,0x73,0x66,0xb6,0x63,0xe5,0xbe,0x1a,0x19,0xe3,0xb1,0x40,0x9a,0x9d,0x3f,0xe6,0xcf,0xd2,0x58,0xf3,0x0,0x60,0xa7,0x93,0x58,0x5d,0xea,0x4e,0x45,0xa5,0x1b,0x46,0xc5,0xfa,0x2f,0xdb,0xf7,0x83,0xc0,0x18,0xbd,0x9e,0x4e,0x62,0x11,0x80,0xe9,0x24,0x36,0x19,0x52,0x21,0x87,0x8c,0xb4,0x5a,0x2f,0xa7,0x9f,0xdb,0x2b,0x65,0xf1,0xeb,0xc5,0x60,0x57,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,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
};
static const unsigned char icon_play_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,0x73,0x0,0x29,0x0,0x7c,0x29,0x1e,0x61,0x18,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,0xdd,0x9,0x19,0x3,0x35,0x2,0xc,0xc,0xc2,0xf6,0x0,0x0,0x0,0xb3,0x49,0x44,0x41,0x54,0x38,0xcb,0x63,0x60,0xa0,0x6,0xf8,0xf0,0xf6,0x33,0x33,0x12,0x9b,0x89,0x2c,0x43,0x1e,0xde,0x7e,0xfe,0xff,0xd9,0xc3,0xd7,0xa7,0xde,0xbd,0xfa,0x68,0x46,0x8a,0x41,0x28,0x8a,0x7e,0xff,0xfa,0x63,0xfc,0xf9,0xe3,0xb7,0x93,0xcf,0x1e,0xbe,0x3e,0xf9,0xef,0xef,0x3f,0x13,0x62,0xc,0x62,0xc2,0xc6,0xff,0xfd,0xeb,0x8f,0x9,0xb1,0x6,0x31,0xe1,0x33,0x98,0x18,0x83,0x98,0x88,0xf1,0x22,0x3e,0x83,0x18,0x91,0x3,0x91,0x88,0x30,0xfb,0xc7,0xc0,0xc0,0xc0,0xc4,0xca,0xc6,0x72,0x82,0x9d,0x93,0xad,0x8a,0x99,0x99,0xe9,0x10,0x13,0xa5,0x49,0x80,0x85,0x48,0x75,0x30,0x9b,0xcf,0x70,0x70,0xb2,0xe5,0xa,0x89,0xf1,0x9f,0xfa,0xf0,0xf6,0x33,0x93,0x80,0x30,0xef,0x3f,0x26,0x22,0x34,0x32,0xb0,0xb2,0xb1,0x9c,0xe1,0xe5,0xe7,0x32,0x97,0x92,0x17,0x35,0x67,0x62,0x66,0x3a,0xc3,0xc0,0xc0,0xc0,0x20,0x20,0xcc,0xfb,0xf,0x5f,0x20,0x12,0xd4,0x88,0x2b,0x16,0x88,0xd6,0x48,0xb5,0xa4,0x4c,0xbd,0xcc,0x44,0x2e,0x0,0x0,0x8c,0xcd,0x82,0xb2,0x7b,0xf9,0xcd,0xd,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,0xde,0x9,0xf,0x14,0x33,0x2d,0x1b,0x8,0x97,0x31,0x0,0x0,0x0,0xb4,0x49,0x44,0x41,0x54,0x38,0x8d,0xad,0x93,0xbd,0xe,0xc2,0x20,0x14,0x46,0x3f,0xb9,0x12,0x16,0x6,0x12,0x36,0x5e,0xc3,0xc6,0x3e,0x95,0x2f,0xe0,0xe3,0x39,0xd9,0xa6,0x2f,0xc1,0xc2,0x46,0xc2,0xc0,0xd6,0x94,0xba,0xb4,0x49,0xad,0x69,0x40,0xf4,0x4c,0x24,0x7c,0xf7,0x70,0xf9,0x3,0xfe,0x41,0x8,0x81,0x36,0x63,0x56,0x25,0xb1,0xd6,0xce,0xce,0xb9,0xde,0x7b,0x7f,0xfd,0x46,0xf4,0x16,0x1a,0xc7,0xf1,0x12,0x63,0xec,0x9c,0x73,0xdd,0x34,0x4d,0x4d,0x89,0x68,0x3f,0xc9,0x16,0x51,0x53,0x2a,0x3a,0xb2,0x17,0x8b,0x72,0xfb,0xcc,0x8a,0x4e,0x6b,0xd2,0x5a,0x3b,0x67,0x64,0x0,0x90,0x0,0x30,0xce,0xf9,0x53,0x8,0x71,0x27,0xa2,0x47,0xdd,0x95,0x6d,0x38,0x17,0xe6,0xd6,0x95,0x7,0x21,0xc4,0x4d,0x6b,0xdd,0x87,0x10,0x98,0x52,0x2a,0xe5,0x3a,0x48,0x0,0xc0,0x39,0x1f,0xa4,0x94,0xad,0x31,0xa6,0x25,0xa2,0x1,0x0,0x94,0x52,0x9,0x38,0x3e,0xc4,0x6c,0xe1,0xca,0x5e,0x50,0x5c,0xf8,0x41,0xed,0x53,0xc6,0x12,0xfe,0xfd,0x33,0xd5,0xf2,0x2,0x84,0xae,0x82,0xae,0xa4,0x17,0x47,0xe1,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,0x73,0x0,0x29,0x0,0x7c,0x29,0x1e,0x61,0x18,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,0xdd,0x9,0x19,0x3,0x35,0x39,0xbd,0x7,0x2b,0xd2,0x0,0x0,0x0,0x34,0x49,0x44,0x41,0x54,0x38,0xcb,0x63,0x60,0xa0,0x6,0xf8,0xf0,0xf6,0x33,0x33,0xb9,0x7a,0x18,0x61,0x2,0xf,0x6f,0x3f,0xff,0x4f,0x8a,0x1,0xf2,0xaa,0x92,0x8c,0xc,0xc,0xc,0xc,0x4c,0x94,0xba,0x7e,0xd4,0x80,0x51,0x3,0x6,0x87,0x1,0x14,0x67,0x26,0x8a,0x1,0x0,0x2a,0xbb,0xf,0x64,0x53,0x81,0x8c,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,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,0x3e,0x0,0x34,0x0,0x44,0xb5,0x81,0x75,0x5d,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,0xdd,0x9,0x1b,0x15,0x15,0x14,0xdf,0xfe,0x44,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,0x0,0xc0,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0xd0,0x2d,0x8e,0x2,0x41,0x10,0x86,0xe1,0xb7,0x7f,0x66,0x4,0x20,0xd6,0xb0,0x21,0x60,0x20,0x70,0x1,0x34,0x8a,0x5b,0xac,0x26,0x5c,0x62,0x4f,0xc0,0x11,0x30,0x4,0xcd,0x29,0x40,0xa1,0xb9,0x0,0x9,0x6a,0x12,0x2,0x6,0x1,0x23,0x9a,0xa9,0x2e,0xcc,0x1e,0x60,0x3a,0xeb,0x8,0xaf,0xff,0x9e,0x4a,0xca,0xa8,0x2a,0x83,0xde,0x68,0x5,0xfc,0x0,0x4d,0xea,0xf5,0x0,0x36,0xa7,0xe2,0x38,0x37,0xfd,0xee,0x70,0xeb,0xbc,0x9f,0x7a,0xef,0x48,0xa9,0xaa,0x4,0xa9,0xaa,0x9d,0xe9,0x77,0x87,0xd2,0x68,0x36,0xac,0x73,0xe,0x6b,0xea,0x21,0x51,0x5,0x11,0xa1,0x7c,0x94,0xd1,0x3,0x36,0xf3,0x79,0xd2,0x75,0x6b,0x1c,0xd6,0x3b,0xa0,0xb4,0x96,0x7f,0xf6,0x1,0xde,0x6,0x28,0xa2,0x4a,0xf2,0xf0,0x6f,0x53,0x58,0x60,0x19,0x42,0x20,0x5,0x89,0x2a,0x84,0x10,0x0,0x96,0x46,0x55,0x99,0x8c,0xa7,0x8b,0xeb,0xed,0x3c,0x7b,0x86,0xe7,0x77,0x1d,0x20,0xcb,0xb3,0x4b,0xfb,0xab,0xb3,0xde,0x1f,0x76,0xbf,0x46,0x55,0x41,0xc9,0x81,0x56,0xc2,0x4f,0x22,0x70,0xc7,0x10,0x5e,0xb5,0x47,0x48,0x5e,0x61,0x62,0xef,0xf5,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,0x3e,0x0,0x34,0x0,0x44,0xb5,0x81,0x75,0x5d,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,0xdd,0x9,0x1b,0x15,0x1d,0x13,0x89,0x43,0x5b,0xe7,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,0xc0,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0xce,0x2f,0x4e,0x3,0x41,0x14,0xc7,0xf1,0xef,0x9b,0x37,0xb3,0x5b,0x1c,0x8,0x12,0xb2,0xaa,0xc9,0x1e,0xa0,0xad,0x45,0x91,0xe0,0xb8,0x8,0x47,0xe0,0xc,0x48,0x24,0xc7,0x58,0x83,0x23,0x41,0xd5,0xb6,0x17,0x68,0x52,0xd5,0x34,0x59,0x1,0xaa,0x90,0xd9,0xf9,0x83,0xe1,0x0,0x33,0xc1,0x11,0xbe,0xfe,0xf7,0x79,0x4f,0x0,0xe6,0x5d,0xff,0x0,0xdc,0x2,0x33,0xca,0xfa,0x2,0x5e,0xf7,0x87,0xdd,0xa3,0xcc,0xbb,0xfe,0x49,0xad,0x5d,0x59,0xab,0xd4,0x14,0x42,0x24,0x86,0xb0,0xb1,0xc0,0xa2,0x6d,0x1b,0x54,0x15,0x23,0x65,0x48,0xca,0x11,0xd5,0xc8,0x29,0x84,0x85,0x5,0x8c,0xb3,0x4d,0xd5,0x75,0x23,0x8a,0xb1,0xa,0x9c,0x8c,0xe1,0x97,0xfd,0x3,0x7f,0x6,0x18,0x53,0x8e,0xd5,0xc3,0x9f,0xcd,0x68,0x80,0xc1,0x7b,0x4f,0xd,0x92,0x72,0xc4,0x7b,0xf,0x30,0x8,0xc0,0xf5,0xf2,0xe6,0x7e,0xfc,0x38,0xde,0x4d,0x7e,0xba,0x28,0x1,0x5c,0xe3,0xde,0x2f,0xcf,0xaf,0x5e,0xd6,0xdb,0xb7,0x67,0x1,0xc8,0x29,0x3b,0xe0,0xc,0x90,0xc2,0x27,0x32,0xf0,0x29,0x46,0xa6,0x6f,0xea,0x47,0x3d,0x8f,0x5e,0xa4,0x39,0x87,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
};
@@ -195,12 +220,12 @@ static const unsigned char logo_png[]={
static const unsigned char option_arrow_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,0x89,0x0,0x76,0x0,0x95,0x95,0xac,0x1a,0xb5,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,0xdd,0x9,0x1b,0x15,0x35,0x3,0xc9,0xa9,0xe5,0x29,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,0xcb,0x63,0x60,0x18,0x9e,0xc0,0xdb,0x3e,0x88,0x81,0x87,0x41,0x58,0x82,0x9f,0x47,0xf0,0x3f,0xf,0x83,0xb0,0x84,0xb7,0x7d,0x10,0x69,0x6,0xf0,0x30,0x8,0xb3,0x28,0xcb,0xaa,0xfd,0x5f,0x39,0x6b,0xf3,0x7f,0x65,0x59,0xb5,0xff,0x3c,0xc,0xc2,0x2c,0x24,0x19,0xa0,0x2c,0xab,0xf6,0x7f,0xf9,0xf4,0xd,0xff,0x4f,0x1f,0xba,0xf8,0x7f,0xf9,0xf4,0xd,0xff,0x95,0x65,0xd5,0xfe,0xe3,0x52,0xcb,0x88,0x4d,0x70,0x5e,0xef,0x8a,0xff,0xba,0xa6,0x9a,0x70,0xfe,0xe5,0xd3,0xd7,0x19,0x92,0x8a,0x23,0x18,0x89,0x36,0x80,0x87,0x41,0x98,0x7,0x5d,0xec,0xb,0xc3,0xdb,0x2f,0x44,0x7b,0x41,0x52,0x54,0xe6,0x3f,0x3,0x3,0x3,0x1c,0x43,0xf9,0xc4,0x7b,0x61,0x4e,0xf7,0xb2,0xff,0xfa,0xe6,0xda,0x70,0xfe,0xc5,0x93,0x57,0x19,0x52,0x4a,0xa3,0x18,0x49,0x89,0x5,0x89,0xd,0x8b,0x76,0xfe,0x3f,0x7d,0xe8,0xe2,0xff,0xd,0x8b,0x76,0xfe,0xe7,0x61,0x10,0x96,0xc0,0xa5,0x96,0x9,0x9b,0xe0,0x4f,0x86,0x4f,0x3c,0xaa,0xac,0x6e,0x1c,0xcf,0x1f,0xbf,0x64,0x50,0x65,0x75,0xe3,0xf8,0xc9,0xf0,0x89,0x87,0x61,0x14,0xe0,0x4,0x0,0x59,0x95,0x3d,0x5c,0xd0,0x53,0x81,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,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,0xd,0x1c,0x2e,0x4,0xf2,0xb6,0x87,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,0x61,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0xbc,0x7b,0xf7,0x2e,0x3,0x25,0x80,0x89,0x22,0xdd,0xb4,0x36,0x40,0x82,0x81,0x81,0xe1,0x3f,0x94,0x26,0xd9,0x0,0x16,0x6,0x6,0x86,0xe7,0x50,0xf6,0x73,0x28,0x9f,0x24,0x3,0x7e,0x13,0xe0,0x13,0x34,0x80,0x68,0x80,0xcb,0x69,0xbc,0x94,0x1a,0xf0,0x19,0x8b,0x18,0x23,0x36,0x85,0x34,0x8b,0x46,0x49,0x2,0x7c,0x82,0x6,0xf0,0x30,0x30,0x30,0x70,0x40,0xd9,0x1c,0x50,0x3e,0x56,0x80,0x2b,0xc,0xee,0x40,0x69,0x46,0x34,0x3e,0xd1,0x2e,0x20,0x1a,0xc,0xbc,0x1,0x0,0x1e,0x2d,0xa,0xcc,0x68,0x85,0xc9,0x5b,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
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,0x89,0x0,0x76,0x0,0x95,0x95,0xac,0x1a,0xb5,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,0xdd,0x9,0x1b,0x15,0x32,0xf,0x8f,0x5e,0x3f,0xc5,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,0x9,0x49,0x44,0x41,0x54,0x48,0xc7,0xbd,0x95,0xb1,0x6b,0x14,0x51,0x10,0xc6,0x7f,0xb3,0x2e,0x77,0xb7,0xa7,0xa8,0x88,0x84,0x90,0x2a,0x90,0xbf,0x40,0xb4,0x53,0xc4,0xc2,0xc2,0x26,0x29,0x52,0x58,0xa,0x36,0x16,0xfe,0x49,0x96,0x76,0x76,0x12,0x1b,0x2b,0x2b,0xb,0x11,0x82,0x8d,0x60,0x23,0x28,0x21,0xe6,0xc8,0x9d,0x60,0x23,0x49,0xf6,0xf6,0xbd,0x19,0x8b,0x7d,0xbb,0xf7,0xf6,0x6e,0xf,0xf6,0x2e,0xe0,0xc0,0xb2,0x8f,0xb7,0xf3,0x66,0xbe,0xf9,0xe6,0x9b,0xb7,0x2,0xb0,0xbd,0xb5,0xf3,0x0,0xd8,0x5,0xee,0xd2,0xc1,0xf2,0x22,0xe7,0x92,0x76,0x8,0xbc,0x1b,0x4d,0x8e,0x3f,0xca,0xf6,0xd6,0xce,0xd3,0x7e,0x6f,0xf0,0x22,0xeb,0xf,0xe9,0xf,0xfa,0x9d,0x4e,0x1f,0x9d,0xfc,0xe4,0xf9,0xfe,0xcb,0xb5,0xb3,0x8f,0x26,0xbf,0x38,0xfc,0xfa,0x89,0xc9,0x9f,0xd3,0x57,0x29,0xb0,0x77,0xfd,0xda,0xd,0xb2,0xc1,0x10,0x11,0xe9,0x1c,0x44,0xbd,0xe7,0xc7,0xf1,0xf7,0xb5,0x0,0x64,0xd9,0x55,0xee,0xdf,0x79,0xc4,0xdb,0xf,0x6f,0xf6,0x52,0x60,0x33,0x1b,0xc,0x1,0x30,0xb3,0xce,0x41,0xa,0x5f,0xac,0xe4,0x1f,0xdb,0xd9,0xd9,0x5f,0xf2,0x69,0xe,0xb0,0x99,0xb6,0x25,0x36,0x40,0x30,0x8c,0x92,0x91,0x6a,0x1d,0xf3,0xe3,0xbc,0xbb,0x94,0x8,0xbc,0x2b,0x0,0x48,0x1,0xbc,0x6a,0x19,0x5c,0x4a,0x30,0x22,0x82,0x19,0x20,0x1a,0x98,0x11,0x10,0x43,0x23,0xa0,0xae,0x70,0x78,0x2d,0xbf,0x27,0x32,0x43,0xae,0x61,0x59,0xed,0x69,0x54,0x5b,0x12,0x72,0xd4,0x55,0x56,0x0,0xd4,0x7c,0xb9,0xaf,0x15,0x88,0xe0,0x13,0xde,0x12,0x1d,0xa8,0x2b,0x50,0x87,0x9a,0x5f,0x48,0x52,0x6b,0xa4,0x6d,0xf,0xc0,0x57,0x48,0x6c,0x6,0xc0,0x54,0x67,0xf1,0xe3,0x83,0xd2,0x4,0x12,0x9b,0x73,0xe,0xf5,0xda,0xe6,0x4e,0x9b,0x32,0xe2,0xf6,0x5,0xdc,0x11,0x3,0x81,0x4a,0xc4,0xc0,0xa4,0xd6,0x0,0x32,0x43,0xb0,0xa8,0x81,0x2,0xe7,0xb5,0x99,0x38,0xa1,0xee,0x41,0x2b,0x98,0x64,0x81,0x8f,0xa0,0x81,0xba,0x5,0x82,0x89,0x22,0x6,0x2a,0x82,0x58,0xd0,0x0,0xe5,0x5a,0xa5,0xc9,0x80,0xa9,0x7,0xc,0x1f,0xb1,0x97,0x98,0x34,0xf6,0x92,0x88,0x3,0x35,0x23,0x9,0x88,0x34,0x14,0x17,0xa6,0x40,0x31,0xb,0xea,0xf,0xc,0x60,0x5a,0x4f,0x1,0x84,0xb5,0x35,0xa7,0xc0,0x99,0x6b,0x52,0x6b,0x42,0x7c,0xaa,0x6a,0x79,0xcd,0x44,0xf5,0x5d,0xa9,0xbd,0xca,0x16,0xf8,0x19,0x6f,0x5d,0x27,0xdb,0x7b,0x87,0x7a,0xbf,0x9c,0xef,0x65,0x82,0x98,0xbb,0xeb,0x52,0x60,0xec,0xd5,0x6f,0x88,0xac,0x90,0x1d,0x70,0xae,0xc0,0xd7,0xe3,0xd2,0xe2,0xb0,0x2c,0x96,0x55,0x5,0x14,0x0,0xe3,0x4,0x38,0xc8,0x8b,0xb,0xcc,0xac,0xf3,0x53,0xb6,0xc0,0x7,0x82,0x57,0x7f,0x9c,0x9b,0x72,0x32,0x3e,0x2,0x38,0x10,0x80,0x87,0xf7,0x1e,0x3f,0x3b,0xfd,0x3d,0x7a,0x92,0x4f,0x2f,0x36,0xfe,0xc7,0xdf,0xb0,0x97,0xf6,0xc6,0xb7,0x6e,0xde,0x7e,0xff,0xe5,0xdb,0xe7,0xd7,0xe5,0x1d,0xa3,0x96,0x2,0xd9,0xfc,0xa0,0x2c,0xb3,0x75,0xff,0x1,0x73,0x33,0x78,0x9e,0x5c,0x49,0xdc,0x3f,0x60,0x6c,0x40,0xa3,0x6f,0xcc,0xee,0xbb,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 +235,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,0x89,0x0,0x76,0x0,0x95,0x95,0xac,0x1a,0xb5,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,0xdd,0x9,0x1b,0x15,0x30,0x2f,0x86,0x6,0x7d,0x8f,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,0x3,0x49,0x44,0x41,0x54,0x48,0xc7,0xbd,0x95,0x31,0x68,0x14,0x41,0x14,0x86,0xbf,0x99,0xbb,0xa8,0x18,0x4b,0x89,0x78,0xc1,0xe0,0xa1,0xad,0x55,0x10,0xb,0x8b,0x54,0xa9,0xac,0xc4,0xc2,0xde,0xee,0x5a,0x41,0x4b,0xc5,0xc6,0x42,0x6c,0xc4,0xe2,0xb0,0xd1,0xd2,0x52,0x4,0xbb,0x58,0x59,0xa7,0xb1,0x12,0x11,0x63,0x38,0xf1,0x34,0x41,0x50,0x48,0x24,0xb9,0x9d,0x37,0xef,0x59,0xec,0xec,0xde,0xde,0x65,0x23,0x97,0x13,0x6e,0x61,0x60,0xf9,0xe7,0x9f,0xf9,0xff,0xf7,0xcf,0x1b,0xc6,0x99,0x19,0xed,0xc5,0x8b,0xd7,0x81,0xe,0xb0,0xca,0x6c,0xbe,0x35,0xa0,0xbb,0xd9,0xff,0xfc,0xca,0x9d,0x6f,0x5d,0xb8,0xd3,0x5a,0x38,0xf7,0x68,0xf9,0xd2,0x15,0x5a,0xb,0x8b,0x13,0xad,0x7e,0xf6,0xf2,0x9,0xf7,0x6e,0x3f,0x9c,0x5a,0xfd,0xc7,0x56,0x9f,0x37,0x6b,0xaf,0xe9,0x6f,0x7f,0xbd,0xdb,0x4,0x3a,0x57,0x97,0x57,0xd8,0x1b,0xec,0xf1,0xe9,0xcb,0xc7,0x89,0x37,0xd1,0x18,0xd9,0xd8,0xdc,0x98,0xca,0xc0,0xfc,0xfc,0x49,0x6e,0x5c,0xbb,0xc9,0xd3,0x17,0x8f,0x3b,0x4d,0xa0,0xfd,0x7b,0xe7,0x17,0x12,0xe4,0x48,0x9b,0x84,0x28,0x98,0xda,0x54,0x6,0x76,0x77,0xfe,0xb0,0x3f,0xc8,0x0,0xda,0x1e,0x38,0xb2,0x38,0x80,0x44,0xf9,0xaf,0x26,0x90,0x2c,0x0,0xd0,0x4,0x50,0x8d,0xe0,0xd2,0x8c,0x41,0x51,0x97,0xfb,0x7,0x26,0x99,0x10,0x55,0x1,0xf0,0x15,0x9e,0xa6,0xdf,0x2,0xab,0x86,0xe4,0x61,0x44,0xa7,0x34,0x10,0x2d,0x82,0xb9,0x7c,0xb5,0xaf,0xd8,0xac,0x4b,0xd8,0x8a,0x1e,0x10,0xd4,0xe4,0x80,0x48,0xd9,0x23,0x75,0x18,0x40,0x2c,0x34,0x6c,0x68,0x40,0xa2,0x2,0xe,0x8f,0x41,0x74,0x89,0x6c,0xb9,0xa9,0x6a,0x35,0x15,0x4c,0x44,0xd0,0xa8,0x39,0xa6,0x89,0xe7,0x2b,0xbc,0x84,0xe1,0x2d,0x55,0x3f,0x2c,0x5d,0xa3,0x1b,0x35,0xa0,0x2a,0x80,0x2b,0xe3,0x2b,0xaa,0x2c,0x96,0x88,0xab,0xc1,0x62,0x20,0x84,0x38,0x82,0x45,0xa3,0x3c,0x83,0x52,0x2e,0xa6,0x39,0xc6,0xd2,0x4d,0xc4,0x94,0x80,0xe1,0x2d,0x7,0xd4,0x81,0xb7,0x5c,0xb1,0x34,0x54,0x83,0x49,0x88,0x79,0xef,0x54,0x79,0x76,0x90,0x37,0xd4,0x74,0xa8,0x59,0x11,0x8,0x9a,0x9a,0xa9,0x59,0xdc,0x69,0x43,0xf3,0x74,0xcd,0xa3,0x68,0x59,0x1,0x80,0xd5,0x60,0x41,0x84,0xa0,0x61,0x94,0x87,0x27,0x8e,0xf1,0x74,0x24,0xd4,0x34,0xaf,0x39,0x77,0xec,0x8,0xa,0xa6,0x52,0x31,0x7d,0x28,0x26,0x22,0xa8,0xc4,0xfa,0xbc,0x6b,0xba,0xbd,0x3c,0x8,0x57,0xf9,0x4f,0x6,0x7a,0x59,0x18,0x2c,0x35,0x1a,0x73,0x87,0x76,0x7c,0x1d,0x26,0x92,0x95,0xd7,0x70,0x9a,0x2f,0xc4,0xc,0xa0,0xe7,0x81,0xee,0xb7,0xed,0x1e,0x41,0x32,0x8c,0x38,0xd1,0x0,0x8,0x41,0x50,0xa6,0x1b,0x99,0xc,0x78,0xff,0x61,0x1d,0xa0,0xeb,0xcc,0x8c,0x95,0xcb,0xab,0xf7,0xb7,0x7e,0x7e,0xbf,0x35,0xc8,0xf6,0x97,0x66,0xf1,0x14,0x1e,0x3f,0x76,0xa2,0x77,0xe6,0xf4,0xd9,0xe7,0xef,0xd6,0xdf,0x3e,0x70,0x66,0x86,0x99,0xcd,0x1,0xa7,0x80,0xc6,0x8c,0x9e,0xe3,0x8,0xec,0x7a,0xef,0xc3,0x5f,0x3e,0xcd,0x47,0x5a,0x1d,0xdb,0x7d,0x47,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,0x89,0x0,0x76,0x0,0x95,0x95,0xac,0x1a,0xb5,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,0xdd,0x9,0x1b,0x15,0x2d,0xd,0xac,0xa,0x50,0x77,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,0xfb,0x49,0x44,0x41,0x54,0x48,0xc7,0xbd,0x95,0xbd,0x6b,0x14,0x51,0x14,0xc5,0x7f,0x77,0x76,0x4c,0x11,0x2d,0xfc,0x8a,0xdf,0x6,0x52,0xd8,0xc4,0x42,0x48,0xa1,0xad,0x8d,0x8d,0x8d,0xf8,0x27,0x68,0xb7,0x9d,0x8d,0x82,0x95,0xd8,0xfa,0xf,0x2c,0x58,0x28,0x76,0x76,0x29,0x45,0x4,0x4b,0xb,0x1b,0x2b,0x9,0x4,0x89,0xb0,0x44,0xa2,0x46,0xe2,0x7,0x59,0x48,0xe6,0xdd,0xfb,0xae,0xc5,0xcc,0x6c,0x66,0x77,0x26,0xeb,0x66,0x85,0x1d,0x78,0x30,0x73,0xde,0x79,0xf7,0x9e,0x7b,0xee,0x1d,0x9e,0xb8,0x3b,0xe7,0x4e,0x5d,0xbc,0xd,0xb4,0x81,0x1b,0x4c,0xe7,0x79,0x3,0x74,0x36,0x36,0xd7,0x97,0xe5,0xec,0xdc,0x85,0xfb,0x73,0xc7,0x4e,0x3f,0xb9,0x7c,0xe9,0xa,0x67,0x4e,0x9c,0x1f,0xeb,0xf4,0xcb,0x57,0xcf,0xb9,0x77,0xe7,0xe1,0xc4,0xd9,0x37,0xbe,0x7f,0xe1,0xed,0xbb,0xd7,0x6c,0xfe,0xfc,0xf6,0x20,0x5,0xda,0x4b,0x8b,0x57,0xd9,0xc9,0x76,0x58,0x5b,0x5f,0x1d,0x3b,0x48,0x34,0x63,0xad,0xfb,0x69,0x22,0x1,0xb3,0xb3,0x87,0xb9,0x79,0xfd,0x16,0x2f,0x96,0x9f,0xb6,0x53,0x60,0xe1,0x4f,0xef,0x37,0xaa,0x7a,0xa0,0x20,0xc1,0x2,0xee,0x3e,0x91,0x80,0x5e,0x6f,0x9b,0xdd,0x6c,0x17,0x60,0x21,0x1,0xe,0x9c,0x1c,0x40,0x4d,0xff,0x6b,0x8,0x34,0x4,0x0,0x52,0x0,0x8f,0x11,0xa4,0xd8,0x71,0x28,0xeb,0x92,0x11,0x98,0x6,0xc5,0x62,0x4,0x20,0xa9,0xf0,0x62,0xf1,0x5a,0x62,0xb1,0x62,0x52,0x2,0x3,0x79,0xfa,0x2,0xcc,0xd,0x5c,0x72,0x50,0x2a,0x32,0x9b,0x1c,0x2e,0x30,0x33,0x25,0xba,0xd5,0x92,0xf4,0x67,0xa4,0x9,0x3,0xb0,0x52,0x89,0x57,0x4,0xc4,0x8,0x8,0x82,0xe7,0x42,0x0,0xaf,0xbc,0x97,0x55,0x57,0x31,0x55,0x25,0x5a,0xfc,0x27,0xf,0xc9,0x13,0x49,0xa5,0x74,0x37,0x19,0x14,0x10,0xa3,0xd,0x96,0x5e,0xa8,0x2f,0x91,0x28,0x75,0x4c,0x2d,0xa0,0x6a,0x3,0x98,0x27,0xf4,0x7b,0x20,0x4d,0x26,0x26,0x35,0x3f,0x4a,0x7,0x1c,0xf1,0x1c,0x70,0x1,0x71,0x29,0xeb,0xe8,0x47,0x1b,0xc6,0x54,0xb5,0x10,0xee,0xfd,0xbe,0xe3,0x90,0x14,0xbc,0x58,0xcb,0x29,0x44,0x77,0x12,0x2f,0x8b,0x92,0x8a,0x3,0x66,0x8,0x9e,0xbb,0x56,0x4,0x18,0x18,0x85,0x6,0x4c,0x55,0x51,0xd7,0x1a,0x2f,0xe,0xf1,0xac,0xea,0x44,0xb9,0x1f,0xf7,0xa2,0xe5,0x2,0x8a,0x61,0xc2,0x87,0x3c,0x6b,0xf2,0x51,0xf6,0x7e,0xc3,0x58,0xb4,0x60,0x14,0xaf,0x36,0xc8,0x32,0xf8,0x99,0x2,0xdd,0xa0,0xd9,0x7c,0x2b,0x49,0xf7,0x9d,0xf8,0x26,0x4c,0x35,0x60,0x45,0xdb,0x46,0xf1,0xf6,0x3d,0x6f,0x1,0xa0,0x9b,0x0,0x9d,0xcd,0xad,0xaf,0xa8,0x5,0x9c,0x38,0xd6,0x2a,0x5b,0xe0,0xd8,0x44,0x2b,0x68,0xc6,0xea,0xe7,0x8f,0x0,0x1d,0x71,0x77,0x96,0x16,0xaf,0x3d,0xda,0xfa,0xf5,0xe3,0x6e,0xa6,0xd9,0xfc,0x34,0xae,0xc2,0x99,0x74,0xa6,0x7b,0xfc,0xe8,0xc9,0x67,0x1f,0x56,0xde,0x3f,0x16,0x77,0xc7,0xa3,0x1f,0x2,0x8e,0x0,0xad,0x29,0x5d,0xc7,0x6,0x6c,0x27,0xad,0x24,0xfc,0x5,0xbc,0xa8,0x41,0xe0,0x6f,0x35,0x49,0x88,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,0x89,0x0,0x76,0x0,0x95,0x95,0xac,0x1a,0xb5,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,0xdd,0x9,0x1b,0x15,0x31,0x33,0x8b,0x1c,0x10,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,0x2,0x8,0x49,0x44,0x41,0x54,0x48,0xc7,0xbd,0x95,0xbf,0x8a,0x14,0x41,0x10,0xc6,0x7f,0x35,0x37,0xee,0x3f,0xf,0x15,0x31,0xba,0xe0,0xb8,0xe3,0x9e,0x40,0x30,0x13,0xc4,0x40,0x1f,0x40,0xdf,0x40,0xb3,0x35,0xd7,0x54,0x4c,0x7d,0x81,0xcd,0xcc,0x8d,0x34,0x17,0x8c,0x45,0x10,0x13,0xc1,0x44,0x50,0x86,0xf3,0x96,0xbb,0x15,0x4c,0x8e,0xe3,0x66,0xa7,0xbb,0xca,0x60,0x7a,0x66,0x7b,0x6e,0x67,0x61,0x76,0xf,0x6c,0x68,0xa6,0xe9,0xa9,0xae,0xfa,0xea,0xab,0xaf,0xba,0x5,0x60,0x6f,0xe7,0xe0,0x11,0x30,0x6,0x1e,0xd2,0x61,0xe4,0x45,0xce,0x25,0xc7,0x7,0x60,0x32,0x9d,0x1d,0xbe,0x93,0xbd,0x9d,0x83,0xe7,0xfd,0xde,0xe0,0xf5,0xb0,0x3f,0xa2,0x3f,0xe8,0x77,0x3a,0x9d,0x1d,0xfd,0xe2,0xc9,0xe3,0x67,0x1b,0x47,0x9f,0xce,0x7e,0xf3,0xe5,0xdb,0x27,0x66,0x7f,0x8f,0x5f,0xa4,0xc0,0xf8,0xda,0xf6,0x75,0x86,0x83,0x11,0x22,0xd2,0xd9,0x89,0x7a,0xcf,0xcf,0xc3,0x1f,0x1b,0x1,0x18,0xe,0xaf,0x72,0xf7,0xf6,0x7d,0xde,0x7f,0x7c,0x3b,0x4e,0x81,0xfd,0xe1,0x60,0x4,0x80,0x99,0x75,0x76,0x52,0xf8,0x62,0x2d,0xfb,0x78,0x9c,0x9d,0x9d,0x92,0xcf,0x73,0x80,0xfd,0xb4,0x2d,0xb0,0x1,0x82,0x61,0x94,0x8c,0x54,0xeb,0x98,0x1f,0xe7,0xdd,0xa5,0x44,0xe0,0x5d,0x1,0x40,0xa,0xe0,0x55,0x4b,0xe7,0x52,0x82,0x11,0x11,0xcc,0x0,0xd1,0xc0,0x8c,0x80,0x18,0x1a,0x1,0x75,0x85,0xc3,0x6b,0xf9,0x3f,0x91,0x5,0x72,0xd,0xcb,0x6a,0x4f,0xa3,0xdc,0x92,0x10,0xa3,0xce,0xb2,0x2,0xa0,0xe6,0xcb,0x7d,0xad,0x40,0x4,0x9b,0xf0,0x95,0xe8,0x40,0x9d,0x81,0x3a,0xd4,0xfc,0x52,0x90,0x5a,0x23,0x6d,0x7b,0x0,0xbe,0x42,0x62,0xb,0x0,0xa6,0xba,0xf0,0x1f,0x1f,0x94,0x26,0x90,0x78,0x38,0xe7,0x50,0xaf,0x6d,0xe6,0xb4,0x29,0x23,0x2e,0x5f,0xc0,0x1d,0x31,0x10,0xa8,0x44,0xc,0x4c,0x6a,0xd,0x20,0xb,0x4,0xcb,0x1a,0x28,0x70,0x5e,0x9b,0x81,0x13,0xea,0x1a,0xb4,0x82,0x49,0x96,0xf8,0x8,0x1a,0xa8,0x4b,0x20,0x98,0x28,0x62,0xa0,0x22,0x88,0x5,0xd,0x50,0xae,0x55,0x9a,0xc,0x98,0x7a,0xc0,0xf0,0x11,0x7b,0x89,0x49,0x63,0x2f,0x89,0x38,0x50,0x33,0x92,0x80,0x48,0x43,0x72,0xa1,0xb,0x14,0xb3,0xa0,0xfe,0xc0,0x0,0xa6,0x75,0x17,0x40,0x58,0x5b,0xb3,0xb,0x9c,0xb9,0x26,0xb5,0x26,0xc4,0xa7,0xaa,0x92,0xd7,0x4c,0x54,0xff,0x95,0xda,0xaa,0x2c,0x81,0x5f,0xf0,0xd6,0xb5,0xb3,0xbd,0x77,0xa8,0xf7,0xab,0xf9,0x5e,0x25,0x88,0xb,0x77,0x5d,0xa,0x64,0x5e,0xfd,0xae,0xc8,0x1a,0xd1,0x1,0xe7,0xa,0x7c,0xdd,0x2e,0x2d,0x6,0xab,0x7c,0x59,0x95,0x40,0x1,0x90,0x25,0xc0,0x24,0x2f,0xce,0x31,0xb3,0xce,0xb3,0x2c,0x81,0xf,0x4,0xaf,0x3f,0x9d,0x9b,0x73,0x74,0x92,0x1,0x4c,0x4,0xe0,0xde,0x9d,0x7,0x2f,0x8f,0xff,0x4c,0x9f,0xe6,0xf3,0xf3,0xdd,0xff,0xf1,0x1a,0xf6,0xd2,0x5e,0x76,0xf3,0xc6,0xad,0x37,0x5f,0xbf,0x7f,0x7e,0x55,0xde,0x31,0x6a,0x57,0x80,0x6d,0x60,0xab,0x8b,0x83,0x4d,0xdf,0x80,0xb,0xda,0x3c,0x4d,0xb6,0x92,0xe2,0x1f,0x29,0x56,0x40,0xcc,0x4c,0xed,0x94,0xcb,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,0x41,0x0,0x3c,0x0,0x44,0xc0,0x10,0x53,0xfb,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,0xdd,0x9,0x1b,0x17,0xb,0xf,0x82,0x5e,0x66,0x11,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,0x74,0x77,0xf6,0xff,0xcf,0x80,0x7,0x30,0x31,0x10,0x0,0xc3,0x43,0x1,0x0,0xea,0x61,0x1,0xe8,0x68,0xbf,0x2f,0x36,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,0x20,0x8,0x6,0x0,0x0,0x0,0x1b,0x89,0xf8,0xcc,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x30,0x0,0x27,0x0,0x35,0x33,0xd3,0x97,0xbf,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,0xdd,0x9,0x1b,0x11,0x1c,0x2f,0xb8,0x3e,0xbe,0xfd,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,0xea,0x49,0x44,0x41,0x54,0x48,0xc7,0xed,0x95,0xb1,0x6e,0xd4,0x40,0x10,0x86,0xbf,0xf1,0x39,0x77,0xb9,0x2,0x21,0x90,0x2,0x42,0x40,0x83,0x94,0x74,0x44,0x22,0xaf,0x40,0xcf,0x1b,0xa0,0xbc,0x4,0x75,0x8a,0x20,0xa8,0x78,0xb,0x3a,0xe8,0xe8,0x79,0x6,0xa,0xca,0x48,0x34,0x10,0x25,0x87,0x93,0xb,0xc7,0x9,0x2e,0x17,0xef,0xce,0x50,0x78,0x7d,0x59,0xaf,0x7c,0x76,0x91,0x16,0x4b,0xeb,0xd9,0xb5,0x67,0xfe,0xf9,0x67,0xfe,0xd5,0x2e,0xdc,0xf0,0x91,0xc8,0x66,0xc0,0x20,0x58,0x59,0xe3,0x6f,0x80,0x2,0x3e,0x58,0x93,0xe0,0x3c,0x0,0x36,0x9e,0x3c,0xda,0xfe,0xb4,0x58,0x2e,0x9e,0x77,0x1,0x8c,0x47,0xe3,0xcf,0xdf,0x7e,0x1c,0xbd,0x0,0x4a,0xc0,0xd7,0xc1,0xc3,0x7b,0x77,0x1f,0x1c,0x3e,0xbc,0xff,0xf8,0xd5,0xd3,0xed,0x67,0xdc,0xbe,0x75,0xa7,0x35,0x7a,0x36,0xbf,0xe0,0xeb,0xd1,0x17,0x8e,0x27,0xdf,0xdf,0xfd,0x9c,0x9e,0x1c,0x0,0x57,0x79,0xa0,0xbc,0x91,0x65,0xd9,0xfe,0xee,0xce,0x1e,0xf3,0xbf,0xbf,0x39,0x9f,0x15,0xad,0x0,0xa3,0xe1,0x26,0xbb,0x3b,0x7b,0x9c,0x14,0xc7,0xfb,0xc0,0x6b,0xc0,0xd5,0x0,0xb9,0x88,0x6c,0x4d,0x67,0xe7,0x78,0x75,0x6b,0xb,0xb8,0x5c,0x2e,0x28,0xcb,0x12,0x11,0xd9,0x2,0x72,0x20,0xcb,0xa3,0x1e,0xe0,0xb4,0xac,0xda,0x64,0x49,0x8b,0xed,0x1a,0xc4,0x69,0x59,0x4f,0x7,0x31,0x80,0x0,0x98,0x1a,0x82,0x60,0x71,0x44,0x4,0x20,0x8,0x66,0xd6,0x50,0x30,0x6f,0xfa,0x59,0x78,0x87,0xd4,0x96,0x52,0xd1,0x14,0x3a,0x1,0xb0,0x1a,0xc6,0x56,0x19,0xab,0x2f,0x1a,0x25,0x91,0x2e,0x80,0xc0,0x40,0xd2,0xc0,0x6b,0x46,0x9d,0xc,0x30,0xad,0x32,0x98,0x36,0xb2,0x9,0xf1,0x5a,0x3b,0x18,0x90,0x96,0xd0,0xac,0xbc,0x4d,0xdd,0x6,0x80,0x5a,0xc8,0x69,0x96,0xa8,0x17,0xd6,0x42,0x5f,0x13,0xab,0xdc,0xb2,0x72,0x6b,0xba,0x9b,0xf5,0x30,0xa8,0x6a,0x97,0x88,0xb2,0x44,0xf2,0xb2,0x5a,0xf5,0xc8,0xa8,0x2b,0xd7,0xb4,0x76,0x8b,0xfe,0xad,0x97,0x51,0x5a,0xa8,0x77,0xd4,0x91,0x0,0x68,0xa3,0x3,0x12,0x26,0x26,0xd1,0x6e,0xe8,0x4,0x48,0x1c,0x2c,0x99,0x58,0x9f,0x8c,0xd6,0xd6,0xe6,0x9e,0x27,0xbb,0xe9,0xa1,0xfa,0x1f,0xa0,0x2,0xb0,0x4a,0x0,0x2b,0xbc,0xba,0xde,0x0,0xaf,0xe,0x33,0x2b,0x6a,0x55,0x6b,0x0,0xef,0xbc,0xfb,0x50,0x4c,0x4f,0xe9,0x2,0xf1,0xea,0x28,0xa6,0xa7,0x38,0xe7,0x3e,0xd6,0xb7,0x53,0x1e,0x36,0xbf,0x3b,0xbb,0x98,0xbc,0xc5,0x18,0xce,0xff,0xcc,0x5f,0x66,0x59,0xb6,0xd9,0x6,0xa0,0xaa,0x97,0xde,0xfb,0xf7,0x67,0xbf,0x26,0x6f,0x0,0x7,0xe8,0xea,0x5a,0x3,0xc6,0x61,0x8c,0xc2,0x6,0x93,0xe4,0x60,0xb7,0x10,0xb4,0x4,0x16,0x61,0x94,0xf1,0xdd,0x98,0x3,0xc3,0x60,0x7,0x2d,0x7,0x90,0x5,0xda,0xe,0xb8,0xa,0xd6,0x4b,0x94,0x29,0x8b,0x46,0x7c,0x6b,0xc7,0xfb,0x5b,0x23,0x20,0x5,0xec,0x1f,0x7b,0x45,0xf9,0x5f,0xa9,0x9f,0xe1,0xbb,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
};
@@ -240,7 +265,7 @@ static const unsigned char popup_bg_disabled_png[]={
static const unsigned char popup_checked_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,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,0xe,0x15,0xb4,0x28,0xc,0xa7,0x0,0x0,0x0,0x4a,0x49,0x44,0x41,0x54,0x18,0xd3,0x85,0x8c,0xbb,0xd,0xc0,0x20,0x14,0x3,0xef,0xa1,0xcc,0x91,0x2a,0xb,0xb0,0xff,0xe,0xb0,0x0,0x4d,0xb2,0x88,0xd3,0xe4,0x21,0x44,0xf8,0xd8,0x95,0x7d,0xd2,0x99,0x10,0xab,0x4,0x36,0x39,0x66,0x20,0x97,0x47,0x53,0x83,0xc3,0x78,0x9d,0x16,0x7c,0x8c,0x60,0x35,0xf8,0xd9,0x43,0x0,0x13,0xa2,0xb5,0xb4,0x10,0x0,0x7d,0x4d,0xe5,0x96,0xf8,0xf7,0x5,0x67,0x99,0x30,0x2b,0xcf,0xbf,0xba,0xe0,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,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,0x5,0xf,0x4c,0x8a,0xd4,0x7,0x0,0x0,0x0,0x43,0x49,0x44,0x41,0x54,0x18,0x95,0x7d,0xcc,0xc9,0xd,0x0,0x20,0xc,0x3,0xc1,0xd,0xa2,0x18,0xe8,0xbf,0x98,0xd0,0x8d,0xf9,0x10,0x84,0xb8,0xe2,0x57,0x3c,0x92,0x4d,0x88,0xdf,0xa5,0xaf,0x2,0xf9,0x5,0xcd,0x9b,0x9e,0xb,0x81,0xa5,0x16,0x4b,0xf1,0xdc,0x70,0x2e,0x44,0xb9,0x23,0x80,0x9,0xb1,0xae,0xac,0x8,0x80,0x46,0xdc,0x5d,0xe2,0x4c,0x7,0x5d,0x41,0x30,0x13,0xdf,0x10,0x9e,0xf0,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -255,17 +280,27 @@ 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,0x94,0x0,0x80,0x0,0xa0,0xea,0x26,0x82,0xc7,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,0xdd,0x9,0x1b,0x14,0x21,0x38,0x57,0xce,0xb1,0x6f,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,0x9c,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0x3f,0x6b,0x14,0x51,0x14,0xc5,0x7f,0x77,0x76,0x92,0xac,0xa2,0x1,0x6d,0x8c,0x89,0x89,0x60,0x29,0x58,0x88,0xdf,0xc0,0x4f,0x20,0x76,0x56,0x96,0x36,0xb6,0x5a,0xa8,0xa5,0x5a,0x68,0x15,0xb0,0xb1,0xb4,0xb2,0x13,0x21,0xbd,0xdf,0x40,0x2c,0x4,0x5b,0x31,0x31,0x71,0x25,0x26,0x9a,0x7f,0x24,0x3b,0x7f,0xde,0xb1,0x78,0xef,0xcd,0xce,0x6c,0x26,0x89,0x41,0xc1,0x66,0x7,0x6,0x86,0xd9,0x7b,0xcf,0x3b,0xe7,0xdc,0x33,0x33,0xfb,0xe0,0x7f,0x1f,0x56,0x3b,0x93,0x99,0xa9,0xd9,0x9b,0x66,0x76,0xc7,0xcc,0xae,0xb7,0x15,0x4b,0x7a,0x27,0xe9,0xe5,0x72,0x6f,0xe9,0xd,0xe0,0x0,0x19,0x90,0x0,0x9d,0x99,0xa9,0xd9,0xfb,0xd3,0xe7,0x66,0x1e,0x3f,0x79,0xf0,0x9c,0x13,0x93,0xdd,0xd6,0xd5,0x76,0x37,0xf7,0x78,0xf8,0xf4,0x1e,0x2b,0xdf,0x97,0x1f,0x2d,0xf7,0x96,0x9e,0x1,0xa5,0x1,0x29,0x30,0x71,0xe1,0xfc,0xdc,0xa7,0x57,0x2f,0x5e,0xcf,0x15,0x85,0xa3,0xc8,0x8a,0x56,0x80,0x74,0x3c,0x25,0x4d,0x13,0x6e,0xdf,0xbd,0xb5,0xf8,0xf5,0xdb,0xe2,0x65,0xa0,0x9f,0x2,0x1d,0xa0,0x6b,0x66,0x73,0xbb,0xdb,0x7d,0x30,0x79,0x45,0xa,0xfc,0x2a,0xad,0x22,0xeb,0xe7,0x64,0x7d,0x30,0xb3,0x39,0xa0,0xb,0x14,0x11,0x60,0x1c,0xa0,0x94,0xf3,0xfd,0xc8,0x77,0xb9,0xe0,0xe,0xa0,0xfa,0x7d,0x7f,0x8c,0x3,0x9d,0x34,0x78,0x30,0x6,0x20,0xe7,0x90,0xc,0x4c,0x18,0x86,0x10,0x26,0xab,0xb5,0x89,0x1a,0xa9,0x31,0x20,0x49,0xe3,0x4,0x3c,0x80,0x10,0x2,0x9,0x33,0x2f,0xc3,0xc5,0x26,0xf3,0x4,0x6a,0x1c,0x12,0xc0,0xd2,0x1,0x49,0x70,0x72,0x55,0x85,0xac,0xba,0xf0,0xd7,0xa2,0x69,0x4a,0xb0,0x26,0x6d,0xcc,0xd9,0x9,0x45,0x44,0x85,0x15,0x4d,0x35,0x2f,0x5c,0x1d,0xc4,0x8,0x23,0xac,0x8e,0xd2,0xb9,0x7d,0x39,0x33,0xc9,0x8b,0x50,0xd4,0xaf,0xe6,0x68,0x87,0x19,0xc,0xa,0xbc,0x68,0xd5,0x9a,0x5c,0x5d,0x6f,0x3b,0x80,0x6b,0x38,0x4e,0x3,0x8a,0x96,0xf5,0x87,0x0,0x9c,0x73,0x21,0x32,0xd1,0x79,0x43,0x3e,0x0,0x61,0xac,0x60,0x76,0x88,0x4,0x27,0x55,0x44,0xe5,0x6f,0x54,0x14,0x22,0x90,0xb3,0x23,0x19,0xc,0xa2,0xab,0x7d,0x6a,0x2c,0x46,0xf2,0x60,0x6,0x16,0x72,0x2b,0x53,0xa8,0xb5,0xca,0x84,0x6,0x68,0xab,0x89,0xa5,0x42,0x80,0x86,0x56,0x72,0x54,0x13,0x39,0xc2,0xc4,0x32,0xac,0x58,0xcb,0xc3,0x70,0xfa,0xe,0xf5,0x40,0xf2,0xf6,0xa9,0xf1,0x1a,0x6a,0x36,0xe,0x1,0xe,0x31,0x50,0x1c,0x56,0x20,0x3b,0x48,0x80,0xe4,0x47,0x79,0x44,0x12,0x5d,0x23,0x79,0x98,0x2,0x3,0x6b,0x8c,0xf2,0x60,0x0,0x85,0xc,0x48,0x10,0x1e,0x67,0xa2,0xac,0xe0,0xab,0xd9,0x21,0x12,0xb2,0xac,0xef,0x1f,0xf4,0x8e,0xa1,0xd2,0x50,0x47,0x50,0x8a,0xa4,0xe3,0x9b,0x5c,0xa9,0xd6,0xd7,0xfa,0x24,0x70,0x76,0x76,0xfa,0xe2,0xe7,0xe3,0x7c,0xf,0x96,0x56,0xbe,0x5c,0x2,0xd6,0x2a,0x6,0x45,0x5e,0x72,0xf5,0xca,0xb5,0x3f,0x6a,0xfe,0xf0,0xf1,0x7d,0xbb,0x84,0x8d,0xcd,0x5f,0xc7,0xfe,0x32,0x25,0x7f,0xfb,0x69,0x1b,0x1,0x8c,0x0,0x46,0x0,0x23,0x80,0x11,0xc0,0x8,0x60,0x4,0xf0,0xef,0x0,0x14,0x1,0x14,0xf6,0x84,0x3f,0x5c,0x71,0x74,0x97,0x2b,0x7c,0x6d,0x4,0x89,0xc,0x5c,0x9e,0x67,0xb,0xab,0xeb,0x3d,0xe,0x3,0x71,0x5,0xac,0xae,0xf7,0xc8,0xf3,0x6c,0x21,0xfe,0xfd,0x4c,0x81,0x12,0x28,0xd6,0x36,0x56,0xe7,0x5,0x27,0xb7,0x76,0xb6,0x6e,0x24,0x49,0x32,0xd1,0xa,0xe0,0x5c,0x3f,0x2f,0xf2,0xb7,0xeb,0x1b,0xab,0xf3,0x40,0x11,0x37,0x9e,0x5d,0xe0,0x14,0x70,0x26,0x9c,0xa7,0xc3,0x96,0x6e,0xd8,0x1f,0x7,0x64,0xc0,0x16,0xf0,0x33,0x9c,0xdb,0x91,0xc1,0x5e,0xf8,0x81,0x50,0x34,0x16,0xf6,0x93,0x56,0x33,0xac,0x4,0x72,0x60,0x27,0xd4,0xee,0x45,0x6,0x49,0x90,0x32,0x1e,0xd8,0x4c,0x84,0xe6,0x64,0x8,0xc0,0x5,0x90,0x7e,0x68,0xce,0x80,0xe2,0x37,0x5,0x81,0x51,0xea,0x99,0x8b,0xa0,0x84,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
};
static const unsigned char progress_bar_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,0x30,0x0,0x2d,0x0,0x31,0x39,0x29,0xd6,0x70,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,0xdd,0x9,0x17,0xe,0x26,0xb,0xfc,0x38,0xdf,0xa0,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,0xb2,0x49,0x44,0x41,0x54,0x38,0xcb,0x6d,0x92,0xbd,0x8e,0x13,0x51,0xc,0x85,0x3f,0x7b,0xa6,0x49,0x93,0x49,0xa,0x2a,0x9a,0x28,0x4a,0xc7,0xdf,0x2,0xed,0x2a,0x35,0x25,0x1d,0x88,0xdd,0x17,0x98,0x82,0x7,0x48,0x8f,0xc4,0x23,0xa4,0xdc,0x86,0x20,0xb6,0xa3,0xe4,0x25,0xb2,0x12,0x7f,0x55,0x14,0xa5,0xa2,0xa2,0x1,0x69,0xa5,0x14,0x7b,0x6d,0x53,0xcc,0xdc,0xd9,0x4c,0x58,0x4b,0x6e,0xae,0xcf,0xb1,0x8f,0x8f,0xaf,0x4c,0xa6,0x33,0x72,0xa8,0xf3,0x2,0xa8,0x81,0xe7,0xc0,0x7d,0xfa,0xf1,0xb,0x58,0x3,0xcb,0xed,0x6e,0xf3,0x25,0x3f,0xca,0x64,0x3a,0x43,0x9d,0xa,0x78,0x2f,0x22,0xb5,0x8a,0xa0,0x85,0x40,0x8,0x22,0x2,0x40,0x44,0x80,0x4,0x6e,0x81,0x47,0x10,0x11,0x4b,0x60,0xb1,0xdd,0x6d,0xfe,0x96,0xea,0x0,0xbc,0x53,0x91,0xba,0x28,0xb5,0x21,0x22,0x20,0x74,0xd,0xda,0x59,0xa8,0x6,0x2a,0x81,0x25,0xaf,0x3d,0xc2,0x80,0xb7,0x32,0x9d,0xcc,0x5e,0x89,0xc8,0xa7,0xb2,0x54,0x4,0x6d,0xa0,0x22,0xa8,0x8,0xd1,0x51,0xc9,0x93,0x1b,0x45,0x38,0x29,0x39,0x11,0xf1,0xba,0x4,0x6a,0x2d,0xa4,0x47,0x16,0x11,0x10,0xa1,0x3f,0x9f,0x6e,0x1d,0x41,0xd1,0x22,0xb0,0x14,0x75,0x9,0x9c,0xe8,0x11,0x39,0xa7,0xb6,0x2b,0x78,0x44,0xcf,0xcd,0x88,0x40,0x51,0xc,0x3f,0x29,0x81,0xea,0x98,0x78,0xa8,0xe2,0x70,0xfa,0x1d,0x51,0x95,0xdd,0x9,0xf,0xa5,0xe7,0x6c,0x95,0x21,0xde,0x5b,0x25,0x0,0x6b,0x55,0x95,0x59,0x7a,0x1c,0x37,0x41,0x6f,0xaf,0x10,0xa,0xe2,0x1d,0xd9,0x23,0xba,0x5a,0x79,0xa8,0xc7,0xdb,0xdd,0x44,0x1a,0xa7,0xb3,0xf8,0x68,0xef,0x11,0x21,0x78,0x78,0x6f,0x7,0x5,0xae,0x1b,0x67,0xb3,0x3c,0xef,0xce,0x45,0x34,0x1f,0x2a,0x1b,0x17,0xf8,0x2d,0xae,0xc1,0x5c,0x2b,0xb0,0x8e,0x68,0x7e,0x58,0xbe,0x75,0x97,0x78,0xd7,0x30,0xe7,0x21,0xe,0x58,0x2b,0xb0,0x4c,0x66,0x7d,0x62,0x6,0xb4,0x79,0x57,0x2d,0x99,0x1,0x2c,0xb5,0x1a,0xe,0x2f,0x87,0x55,0x75,0x61,0x77,0x34,0x31,0x77,0xcc,0xfd,0xff,0x77,0x33,0x86,0x55,0x75,0xb1,0xdd,0x6d,0x2e,0x55,0x80,0xf9,0xfc,0x74,0x31,0x1a,0x8f,0x57,0x37,0x29,0x91,0xcc,0x30,0xf7,0xde,0x64,0xda,0x66,0xc9,0x8c,0x9b,0x94,0x18,0x8d,0xc7,0xab,0xf9,0xfc,0x74,0x1,0x20,0x4f,0x1f,0x3f,0x83,0x8,0xae,0xbe,0x5d,0x8d,0xce,0xde,0x9c,0xbf,0xfc,0xf1,0xfd,0xe7,0xd9,0x7e,0xbf,0x7f,0x62,0x66,0xf7,0xe,0xdd,0x2e,0x8a,0xe2,0xf7,0x60,0x30,0xf8,0xfa,0xf0,0xd1,0x83,0xd5,0xea,0xe3,0x87,0xcf,0xc0,0x1f,0x80,0x7f,0x8a,0x82,0x28,0xc9,0xa8,0xf,0x19,0xf1,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,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,0x16,0x1b,0x8f,0x3,0x26,0x8d,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,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
};
static const unsigned char progress_fill_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,0xaf,0x0,0x9a,0x0,0xec,0x52,0xc,0x20,0x4d,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,0xdd,0x9,0x17,0xe,0x28,0x33,0x4a,0xb9,0x4a,0xb0,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,0x9a,0x49,0x44,0x41,0x54,0x38,0xcb,0x75,0x93,0x4b,0x88,0x5c,0x45,0x14,0x86,0xbf,0x53,0x75,0x6b,0xa6,0x67,0x92,0xee,0x76,0x32,0xce,0x18,0x8c,0xc3,0xb4,0x4,0x62,0x30,0xf,0x41,0x41,0x8c,0xae,0x5d,0xb8,0x8,0x98,0x8c,0x90,0x85,0x44,0x70,0x2d,0x66,0xab,0xb,0x97,0x6e,0xdc,0xeb,0x5a,0x48,0x16,0x32,0x90,0xc9,0x80,0x2e,0x7c,0x80,0xd9,0x9,0x1a,0xc8,0x42,0xe3,0xa0,0x84,0x3c,0xe6,0x21,0x61,0x3a,0x9d,0x89,0xf6,0xed,0x3b,0xf7,0xd9,0x55,0xc7,0x45,0xdf,0x91,0x9e,0x80,0x3f,0x14,0x75,0xaa,0xea,0xd4,0x7f,0xfe,0xf3,0x53,0x25,0xaa,0xca,0x1e,0x3a,0xb3,0x67,0x3e,0xd1,0xe1,0xc4,0x7,0x61,0x18,0xcd,0x11,0x22,0xcb,0x38,0xcc,0xd0,0x9b,0x68,0xd8,0x93,0xa8,0xfc,0xa2,0x7b,0xb8,0xf9,0xe9,0xde,0xb6,0x0,0x74,0x9e,0x7e,0x75,0xc1,0x57,0xee,0xdb,0x93,0xc7,0x5f,0x3b,0x71,0xfe,0x9d,0xf3,0x2c,0x2e,0x1e,0xa5,0xd5,0x3a,0x44,0x91,0x7,0x0,0x26,0x1b,0x86,0x38,0x7e,0xcc,0xc6,0xc6,0x5d,0xae,0x5d,0xbd,0xc6,0xef,0x7f,0xfe,0xbc,0x66,0x5d,0xf5,0xd6,0xf6,0x7c,0x7b,0x4b,0x0,0x16,0xda,0x6f,0xfc,0x7a,0x61,0xe9,0xfd,0xd3,0xe7,0xce,0x5d,0xa4,0xbf,0xe3,0x49,0x63,0xc8,0xe3,0xb0,0x4f,0x40,0xa3,0x65,0x98,0x6e,0x41,0x7b,0xd6,0xb2,0xba,0x7a,0x85,0xe5,0x95,0x2f,0x7f,0xd3,0xe2,0xc0,0x4b,0xb6,0x33,0x73,0xe6,0xf3,0x53,0xc7,0x5e,0x3f,0x7b,0xf1,0xbd,0x4b,0x3c,0xdc,0x8,0xf4,0xbb,0x4a,0xdc,0xf3,0x94,0xb9,0xee,0x1b,0x69,0x3f,0x50,0xa6,0x90,0xa5,0xca,0xa9,0x97,0x4f,0x73,0xff,0xf6,0x9d,0x67,0x76,0xe2,0x3b,0x73,0xb6,0xed,0x8e,0x7e,0xf5,0xe1,0xa5,0x8f,0x27,0x7d,0x32,0x43,0xfc,0x48,0x49,0xfe,0xf1,0xa8,0x7,0xef,0x41,0xbd,0x12,0xbc,0xd6,0x31,0x14,0x59,0x40,0xbd,0x40,0x80,0x17,0x4e,0x2e,0x70,0xfd,0xc7,0x1f,0x8e,0x47,0xa1,0x72,0xcd,0xe6,0x81,0x23,0xf4,0x1f,0x4,0xe2,0xee,0x10,0x4,0x74,0xdc,0x20,0xf6,0xaf,0xe3,0x2c,0x60,0x5d,0x44,0xfb,0xd9,0x23,0x84,0xca,0x35,0x23,0x51,0x2b,0x45,0x1a,0x28,0xd3,0x40,0x59,0x84,0x3a,0x5b,0x41,0x64,0x3f,0x81,0xea,0x88,0x42,0xa0,0x4c,0x3,0x45,0x1a,0x10,0xb5,0x12,0x1,0x64,0x3,0x25,0x4f,0x3c,0x55,0x1e,0x46,0x89,0x22,0xf5,0x85,0xb1,0xda,0x2,0x68,0x0,0x11,0xf2,0xc4,0xe3,0x6,0xa3,0xb3,0x48,0x82,0x21,0x1f,0x78,0x8a,0x44,0xa8,0x32,0x5f,0xb,0xd5,0x7a,0xaa,0x9,0x64,0xac,0x2f,0x2,0x45,0x2,0x6e,0xe0,0x91,0x60,0xf8,0x4f,0x41,0xb1,0x5b,0x2b,0x18,0xc3,0x93,0x5e,0xec,0xa1,0xd8,0x5,0xbb,0xa7,0x0,0x51,0xcd,0x13,0x2f,0xc5,0x0,0xca,0x2c,0x8c,0xa,0xcb,0xff,0x98,0xa8,0xa3,0xd8,0x1a,0x30,0xd3,0x1e,0x44,0x35,0xc2,0x56,0xc9,0x76,0x6f,0xb3,0x79,0xb0,0xec,0x10,0xca,0x80,0xd7,0xb1,0x47,0x3a,0xde,0x42,0x4d,0x63,0x5,0xbc,0x13,0xb6,0x7b,0x9b,0x60,0xab,0xc4,0xe0,0x76,0x97,0x6f,0xdc,0x5a,0xc5,0xb6,0x2d,0x38,0x4b,0x28,0x95,0x2a,0xb,0x54,0xd9,0xa8,0xa5,0x2a,0xaf,0xe3,0x2c,0x10,0x4a,0x5,0x67,0xb1,0x6d,0xcb,0x8d,0x5b,0xab,0xe0,0x76,0x97,0x6d,0xbf,0xf8,0xeb,0xba,0x33,0x13,0x17,0xd4,0x4f,0x1e,0x9a,0x9f,0x7f,0x11,0x9,0x82,0x15,0xc1,0x88,0x60,0xc4,0x60,0x8c,0xc1,0x46,0x6,0x37,0x61,0xb1,0x53,0x11,0xd1,0x53,0x8e,0xb5,0xf5,0xaf,0xb9,0xf7,0xe8,0xfb,0xbb,0xeb,0xf1,0x4f,0x6f,0x5b,0x80,0xc5,0xce,0x73,0xbf,0x6c,0x3d,0x58,0x7b,0xf3,0x61,0x77,0xa3,0xdd,0x68,0xce,0x60,0xa7,0xe,0x62,0xa7,0xa6,0x89,0x1a,0x16,0xd3,0xb0,0x68,0x23,0xa2,0xb0,0x29,0x8f,0xcb,0x7b,0xdc,0xfc,0xe3,0x32,0xeb,0x7f,0x7f,0xb7,0xd9,0x3a,0x3c,0x7c,0xb7,0xbb,0xb3,0xb5,0x25,0xb5,0x57,0x53,0x4b,0x4b,0x4b,0xcf,0xdf,0xbe,0xb9,0xf3,0x51,0xdc,0x93,0xb3,0x54,0x93,0x2d,0x42,0x64,0x9e,0xf8,0xce,0x1,0x57,0xc4,0xad,0x39,0xfd,0xe6,0xd8,0x2b,0xb3,0x9f,0xad,0xac,0xac,0xdc,0x7,0xb2,0x7f,0x1,0x90,0xaf,0x58,0x10,0xf8,0xc7,0xe,0xbe,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,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,0x15,0x1e,0x28,0xcd,0x92,0x83,0xf8,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,0x82,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0xd0,0x21,0xe,0xc3,0x30,0xc,0x5,0xd0,0xbf,0xc9,0x2c,0x3f,0xb4,0xbd,0xca,0x60,0x6e,0xd0,0xb3,0xe6,0x6,0x81,0x3b,0x4b,0x59,0x64,0x87,0x39,0xd2,0xc8,0x40,0xe7,0x4a,0x93,0xc6,0x6,0xfa,0xe1,0xb3,0xfd,0x81,0x81,0x2b,0xb7,0x8,0xa5,0x94,0x87,0xaa,0x56,0x33,0x5b,0x8e,0x4e,0x72,0xcf,0x39,0x6f,0xad,0xb5,0xe7,0xd1,0x25,0x16,0xa8,0x6a,0xed,0xbd,0x27,0x77,0xff,0xf0,0x39,0x67,0x2,0x50,0x1,0xac,0x5f,0xb,0xcc,0x6c,0x89,0xc7,0x0,0xe0,0xee,0xc9,0xcc,0x52,0xf4,0xfb,0x69,0xf3,0xc7,0xfc,0x61,0x1,0xc9,0x5d,0x44,0x46,0x74,0x11,0x19,0x24,0xf7,0x93,0x47,0xc8,0x39,0x6f,0x0,0x6a,0x7c,0x18,0xc9,0xf1,0x9e,0x5d,0x9,0x79,0x1,0x2e,0x56,0x2e,0xc3,0x70,0xd9,0xde,0xde,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char radio_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,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,0x3,0x1,0x4,0x19,0x36,0x83,0x13,0x8d,0xb2,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,0x1,0x9d,0x49,0x44,0x41,0x54,0x38,0xcb,0xad,0x93,0x31,0x6b,0xdb,0x50,0x14,0x85,0x3f,0x59,0x8a,0x21,0xbb,0x17,0xd1,0x37,0xa4,0xa4,0xb5,0x10,0xb5,0x3,0xfa,0x7,0x5d,0x3a,0x74,0xf2,0x56,0x39,0x64,0x4d,0x97,0x42,0x9b,0xce,0x6d,0x7e,0x44,0xe3,0x8e,0xf5,0x60,0x4,0xc5,0x22,0x9b,0x27,0x63,0xe8,0xea,0xc5,0x43,0x4d,0x48,0x40,0x7a,0xe9,0xd0,0xe0,0xd4,0x68,0x32,0x18,0x3c,0x8,0x64,0xc3,0xed,0x50,0x59,0x34,0x71,0xa7,0x3a,0x7,0xde,0x72,0xef,0x79,0x87,0x7b,0xde,0x3d,0xf,0xb6,0x84,0x71,0xbf,0xe0,0x38,0xce,0x23,0xe0,0x2d,0xf0,0x12,0xa8,0xe6,0xe5,0x6b,0xa0,0xf,0x7c,0xd6,0x5a,0x4f,0xff,0x29,0x60,0x99,0x16,0xfb,0x4f,0xf6,0x8f,0x81,0x56,0xb3,0x79,0xb4,0x7b,0x78,0xf8,0xa,0xc3,0xf8,0xd3,0x16,0x11,0xba,0xdd,0x73,0xc2,0xf0,0x6b,0xa,0xbc,0x9b,0x4c,0x26,0xed,0x34,0x4d,0xef,0xa,0x38,0x8e,0x73,0xbc,0xb7,0xf7,0xf8,0xcb,0xd9,0xd9,0xa7,0xe2,0xe2,0x7d,0x88,0x8,0x27,0x27,0xef,0xb9,0xb9,0xf9,0xf9,0x5a,0x6b,0xdd,0x2e,0x4,0xf2,0xb1,0x7f,0xf4,0x7a,0xbd,0x5d,0xc3,0x30,0xc8,0xb2,0x8c,0xf1,0x78,0x4c,0x14,0x45,0x0,0xb8,0xae,0x8b,0xe7,0x79,0x94,0xcb,0x65,0x44,0x84,0x46,0xa3,0x91,0x2,0x4f,0xb5,0xd6,0x53,0x13,0xa0,0x52,0xa9,0x7c,0x6c,0x36,0x8f,0x9e,0x1f,0x1c,0xd4,0xc8,0xb2,0x8c,0x4e,0xa7,0x43,0xab,0xd5,0x62,0x30,0x18,0x30,0x1c,0xe,0x19,0x8d,0x46,0xac,0x56,0x2b,0xea,0xf5,0x3a,0x96,0x65,0x21,0x52,0xda,0xb9,0xba,0xba,0x5c,0xce,0x66,0xb3,0x6f,0xeb,0xf1,0x2f,0xe2,0x38,0x16,0xad,0xb5,0x4,0x41,0x20,0x4a,0x29,0x1,0xee,0x1c,0xa5,0x94,0x4,0x41,0x20,0x5a,0x6b,0x89,0xe3,0x58,0x1c,0xc7,0xb9,0x0,0x28,0xe5,0xf6,0xaa,0x6b,0xdf,0x51,0x14,0x91,0x24,0xc9,0x86,0xff,0x24,0x49,0xa,0x4b,0x39,0xb7,0xfa,0xb7,0xc0,0x7f,0x63,0x2d,0x70,0x2d,0x22,0xc5,0x83,0xd9,0xb6,0xbd,0x41,0xb4,0x6d,0x1b,0xd7,0x75,0x8b,0x6d,0xe4,0xd9,0x28,0x4,0xfa,0xdd,0xee,0x39,0x0,0x9e,0xe7,0xe1,0xfb,0x3e,0x4a,0x29,0x4c,0xd3,0xc4,0x34,0x4d,0x94,0x52,0xf8,0xbe,0x8f,0xe7,0x79,0x0,0xe4,0xdc,0xfe,0x83,0xac,0x71,0xeb,0x20,0x99,0xeb,0xe6,0x62,0xb1,0xf8,0x6e,0x18,0x4c,0xc3,0x30,0x7c,0x21,0x52,0xda,0xa9,0xd5,0x9e,0x6d,0x44,0xf9,0xf4,0xf4,0x43,0x3a,0x9f,0xcf,0xdf,0xdc,0xde,0xfe,0x6a,0x2f,0x97,0xcb,0x87,0xf9,0x4c,0x5b,0xe3,0x37,0x57,0xdf,0xd7,0x8,0xe6,0x62,0x7d,0xab,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char radio_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,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,0x3,0x1,0x4,0x1b,0x6,0x97,0xfc,0xdf,0x9c,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,0x1,0x9,0x49,0x44,0x41,0x54,0x38,0xcb,0xad,0x93,0xbd,0x72,0x82,0x40,0x14,0x85,0xf,0x68,0xa,0x9e,0x21,0x8d,0x8e,0x9,0xdb,0xc4,0xc7,0x48,0x41,0x43,0x2b,0xa3,0xad,0x69,0x32,0xc3,0xda,0xc7,0xa7,0x8,0x94,0xa1,0xd,0x68,0x4b,0xc3,0x5b,0xd8,0x5f,0x2d,0xe2,0x60,0xe8,0x99,0xa1,0xd8,0x82,0xc2,0x34,0x17,0x67,0x35,0x19,0x43,0x34,0xa7,0xbc,0x7b,0xee,0x37,0xf7,0x6f,0x81,0x2b,0x65,0x9c,0x6,0x84,0x10,0xb7,0x0,0x7c,0x0,0xe,0x0,0x9b,0xc3,0x6b,0x0,0x19,0x80,0x90,0x88,0x8a,0x1f,0x1,0xdd,0x4e,0x17,0x83,0xbb,0xc1,0x14,0x40,0xe0,0x79,0x13,0x6b,0x3c,0x1e,0x1d,0x81,0xe3,0x78,0x89,0xc5,0xe2,0x5d,0x1,0x90,0x79,0x9e,0x47,0x4a,0xa9,0x63,0x80,0x10,0x62,0xda,0xeb,0xf5,0xdf,0x82,0xe0,0xf5,0x6c,0xc9,0x52,0xce,0xb0,0xdd,0x7e,0x3c,0x11,0x51,0x74,0x0,0x70,0xd9,0x9b,0x34,0x4d,0xad,0x36,0x7d,0xbb,0xae,0xab,0x0,0xdc,0x13,0x51,0x61,0x72,0xcc,0xf7,0xbc,0x89,0xd5,0x76,0x70,0xec,0xf5,0x1,0xa0,0x1,0x38,0xa7,0x3d,0x9f,0x13,0x7b,0x1d,0x1d,0x60,0x5f,0xb0,0x41,0x5b,0x7,0x5c,0x2c,0x53,0xdb,0xf3,0x5f,0xb5,0xd6,0x1,0x59,0x1c,0x2f,0x5b,0x67,0xb2,0x37,0xd3,0x1,0x21,0x1f,0x49,0x2b,0xb1,0x37,0x3c,0x0,0xf8,0x3c,0xa5,0x94,0xb3,0x5f,0x93,0xd9,0x23,0x9b,0x93,0xee,0x34,0xf,0x55,0x55,0xad,0xc,0x3,0x45,0x92,0x24,0x8f,0xfb,0xbd,0x79,0x33,0x1c,0x3e,0x7c,0x2b,0x7b,0x3e,0x7f,0x51,0x65,0x59,0x3e,0xef,0x76,0x9f,0x51,0x5d,0xd7,0xff,0xf3,0x99,0xae,0xd6,0x17,0xf,0x97,0x66,0x8b,0x3d,0xf1,0x64,0x47,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -274,53 +309,68 @@ 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,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
+};
+
+
static const unsigned char scroll_button_down_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,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,0xdb,0xb,0x4,0x11,0x20,0xd,0xba,0x4e,0x71,0x52,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,0x8d,0x49,0x44,0x41,0x54,0x38,0xcb,0x9d,0x93,0xcf,0x4a,0x5b,0x41,0x14,0xc6,0x7f,0x13,0xae,0x12,0x11,0xb,0x66,0x93,0x40,0x56,0xd2,0x7,0x28,0x5d,0x74,0xa3,0x48,0x4b,0x9f,0xc2,0x75,0xa0,0x8f,0x21,0x6e,0x4,0x11,0x5c,0x64,0x2b,0x5,0xd7,0x7d,0x8a,0xd2,0xae,0xbb,0x28,0x7d,0x80,0xe2,0xaa,0xa0,0x88,0x51,0x6a,0xee,0x9c,0x33,0x73,0xe7,0x8f,0x8b,0xa4,0xf7,0xde,0x68,0x5a,0x8b,0x7,0x86,0x19,0x66,0xbe,0xef,0x3b,0x33,0xe7,0x3b,0x63,0x80,0x3c,0xec,0xf,0x78,0x4e,0xfc,0xba,0xbc,0xa0,0x18,0xf6,0x7,0xbc,0xdc,0xda,0xe2,0xfd,0xdb,0x77,0xbc,0xd8,0xd8,0x0,0xc,0xe4,0xc,0xe6,0x1,0x3a,0x3,0xc6,0x0,0x99,0xdf,0x77,0x77,0x7c,0xfe,0xfa,0x5,0x80,0x2,0x60,0x77,0x7b,0x7,0x80,0xeb,0xab,0xeb,0x3f,0xc8,0xd6,0xcc,0xa3,0xbd,0x95,0xee,0x2a,0xbb,0xdb,0x3b,0xfc,0x3c,0x3f,0x9f,0x9,0xf4,0x36,0x37,0xb9,0x99,0x4c,0xf0,0xde,0x35,0xd9,0xf3,0x22,0xbd,0xe1,0x1b,0x4c,0x7,0x7a,0xbd,0x5e,0x73,0x83,0x18,0x13,0x29,0x26,0x52,0x4a,0x2d,0xc6,0x92,0x27,0x0,0xe4,0x4c,0x8a,0x89,0x18,0x53,0x23,0x10,0x42,0x45,0x88,0x91,0x14,0xe3,0x52,0x6e,0x3b,0xc,0x10,0x62,0x24,0x84,0xaa,0x11,0x70,0xea,0xa8,0xbc,0xc7,0x7b,0xcf,0xde,0x87,0xd1,0x3f,0x5,0x3e,0x7d,0x3c,0x3,0x63,0x70,0xea,0x1a,0x1,0x75,0x8a,0x73,0xe,0xef,0xfd,0x93,0xd6,0x39,0xef,0xc9,0x73,0xe,0x40,0x7,0xc0,0x8a,0x45,0x44,0x10,0x11,0x4e,0x4f,0xc6,0x7f,0x25,0x9f,0x9e,0x8c,0x6b,0x9c,0x15,0xdb,0x8,0xc8,0xd4,0x22,0x62,0x51,0x55,0x44,0x85,0xf1,0xe1,0xd1,0x23,0xf2,0xf8,0xf0,0x8,0x51,0x99,0x61,0xc4,0x22,0xd3,0x96,0x80,0x55,0x41,0xd5,0xa1,0x4e,0xeb,0x71,0xbc,0x7f,0x50,0x93,0x8f,0xf7,0xf,0x16,0xce,0x54,0x1d,0x56,0x65,0x56,0xd4,0x61,0x7f,0x90,0xdf,0xbc,0x7a,0x8d,0xaa,0x10,0xaa,0xb0,0x58,0xee,0x65,0x36,0x2,0xc5,0x4a,0x41,0xb7,0xbb,0xc6,0xb7,0x1f,0xdf,0xe7,0x45,0x14,0xc5,0x57,0x9e,0x18,0x22,0xff,0xe3,0x63,0xca,0x9,0xb2,0x69,0x5c,0x10,0xef,0x8,0x55,0xd5,0x34,0xd2,0x13,0xd1,0x49,0x89,0x38,0x4f,0x54,0x0,0x5c,0x5c,0x5d,0xb2,0xde,0x5d,0x23,0xb7,0xd3,0xe7,0x25,0x1d,0x54,0x2f,0xd,0xe5,0xed,0xa4,0x16,0x18,0x4d,0xcb,0xf2,0x6c,0x5a,0x96,0xcf,0xf9,0xd1,0xa3,0x7b,0xce,0xd7,0xea,0xb0,0xa,0xcf,0xbd,0x5b,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,0x59,0x0,0x59,0x0,0x59,0xbd,0x9a,0xea,0xaa,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,0x13,0x19,0x1f,0x9,0x3d,0x3c,0xb0,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,0xa3,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x93,0x31,0xa,0x2,0x31,0x10,0x45,0x7f,0xc2,0x14,0x3,0x6,0xab,0xad,0x32,0x57,0x50,0xbc,0x87,0x88,0x97,0x11,0xf1,0xc,0x22,0x1e,0x33,0x5b,0xa5,0xb1,0x59,0xa7,0x18,0x58,0x5b,0x89,0x9b,0x95,0x88,0xa0,0xbf,0x4c,0xfe,0xfb,0xf9,0x3,0x13,0xb7,0x5e,0x6d,0x58,0xa2,0xc,0x44,0xe4,0xd0,0x20,0x33,0x1b,0x53,0x9f,0x16,0x24,0x51,0xee,0xaa,0xa,0x55,0x6d,0xe1,0xc1,0xcc,0x4e,0xa2,0xc,0x9e,0x88,0x9a,0x61,0x0,0x50,0x55,0x10,0x11,0x7c,0x33,0x59,0xe8,0xf7,0x1,0x54,0x1e,0x5c,0xae,0xe7,0x59,0xe0,0x78,0x38,0x7d,0xb7,0xc1,0x4b,0x40,0xf9,0xc2,0xbb,0xbb,0xc9,0x6,0x53,0xc6,0x5a,0x70,0x75,0x84,0x67,0x60,0xae,0x95,0xdb,0x6d,0xf7,0x63,0xce,0xb9,0x6a,0x98,0x53,0xd7,0x75,0x7f,0xb0,0x7,0xde,0xcc,0xc0,0xcc,0xcd,0x20,0x33,0xc3,0xcc,0x40,0xa9,0x4f,0x4b,0x89,0x72,0xb,0x21,0x7c,0xf2,0x9d,0xe5,0x1,0xd1,0x91,0x38,0x2b,0x1d,0x55,0xcb,0xf6,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char scroll_button_down_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,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xdb,0xb,0x4,0x11,0x1f,0x1f,0x11,0x29,0x2a,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,0x1,0x84,0x49,0x44,0x41,0x54,0x38,0xcb,0x9d,0x93,0xcf,0x4a,0x6b,0x31,0x10,0x87,0xbf,0x94,0xfa,0x7,0xa1,0x82,0xdd,0xea,0xc2,0x9d,0xfa,0x16,0x45,0x10,0x1f,0xc0,0xbd,0xa0,0x2f,0x71,0x71,0x23,0x72,0x17,0x82,0xb8,0x70,0xd1,0xb5,0xa,0xee,0x7d,0x0,0xf1,0x41,0xd4,0x9d,0xe0,0x15,0x17,0x52,0x2f,0x9c,0x43,0x32,0x49,0xce,0x49,0x72,0x17,0xad,0x4d,0x6b,0x7b,0x55,0x1c,0x8,0x9,0x99,0xf9,0x7d,0x33,0xc9,0x24,0xa,0x48,0xab,0xcb,0x2b,0xfc,0xc4,0x1e,0x9f,0xff,0xd0,0x5c,0x5d,0x5e,0x61,0x63,0x6d,0x9d,0xed,0xad,0x2d,0x16,0x5b,0x2d,0x40,0x41,0x4a,0xa0,0x3e,0x44,0x27,0x40,0x29,0x20,0x51,0x94,0x25,0x37,0xb7,0xb7,0x0,0x34,0x1,0x36,0x3b,0x1d,0x0,0x7a,0xaf,0xbd,0xf7,0xc8,0x91,0x99,0x89,0xbd,0x99,0xf9,0x59,0x36,0x3b,0x1d,0xee,0x1e,0xee,0xfb,0x80,0xf6,0xd2,0x12,0x7f,0xdf,0xde,0xf0,0xde,0xe5,0xec,0x69,0x5c,0x9e,0xf5,0xa,0xd5,0x80,0x76,0xbb,0x9d,0x2b,0x8,0x21,0x12,0x43,0x24,0xc6,0x38,0xa2,0x98,0x72,0x4,0x80,0x94,0x88,0x21,0x12,0x42,0xcc,0x80,0xba,0xae,0xa8,0x43,0x20,0x86,0x30,0x55,0x3b,0x6a,0xa,0xa8,0x43,0xa0,0xae,0xab,0xc,0x70,0xd6,0x51,0x79,0x8f,0x77,0x8e,0x9d,0xbd,0xdd,0x4f,0x1,0xd7,0x97,0x57,0xa0,0x14,0xce,0xba,0xc,0xb0,0xce,0xe2,0xac,0xc5,0x7b,0xff,0x65,0xeb,0x9c,0xf7,0x24,0xc0,0xce,0xcf,0x1,0xd0,0x0,0x30,0x62,0x30,0x46,0x30,0xc6,0x70,0x7e,0xd6,0xfd,0xaf,0xf8,0xfc,0xac,0x8b,0x31,0x83,0x58,0x31,0x19,0x20,0xa5,0x46,0x8c,0x46,0xa4,0xef,0xe8,0x1e,0x9f,0x4c,0x88,0xbb,0xc7,0x27,0x18,0x31,0x88,0x48,0x3f,0xb6,0xd4,0x19,0xa0,0xc5,0x20,0x62,0x11,0x2b,0xc3,0x71,0x7a,0x78,0x34,0x14,0x9f,0x1e,0x1e,0x8d,0xf9,0x44,0x2c,0x7a,0x50,0x41,0x13,0x40,0x6b,0x83,0x38,0x4b,0x55,0x55,0x63,0xd7,0xfd,0xfb,0xd7,0xc1,0x64,0x1b,0x81,0x30,0x13,0x41,0x37,0x32,0x40,0xb4,0xe0,0xbc,0x23,0xd4,0x35,0xdf,0xe9,0x63,0x8c,0x11,0x92,0xca,0x0,0xe3,0x2c,0x95,0xf7,0xf9,0x21,0x7d,0x61,0x8d,0x10,0x9,0x83,0x44,0x4d,0x80,0xa7,0x97,0x67,0x5a,0xb,0xb,0xa4,0xd1,0xf4,0x69,0xca,0xb,0x1a,0x2e,0x15,0x65,0xef,0x75,0x8,0xd8,0x2f,0xca,0xe2,0xa2,0x28,0x8b,0x9f,0xfc,0xe8,0xfd,0x7f,0xcd,0x23,0xeb,0x93,0x35,0xff,0xc7,0x89,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,0x59,0x0,0x59,0x0,0x59,0xbd,0x9a,0xea,0xaa,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,0x13,0x1a,0x0,0xaf,0x18,0x62,0x86,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,0x9c,0x49,0x44,0x41,0x54,0x38,0x8d,0xc5,0x93,0x41,0xa,0x2,0x31,0xc,0x45,0x7f,0x87,0x6,0x21,0x5,0xe7,0x6,0x2e,0x9a,0x63,0x88,0x78,0x30,0x11,0x4,0xf1,0x98,0x9d,0x4b,0x48,0xa3,0x90,0x85,0x6e,0xb5,0xce,0x8c,0xad,0xa,0xfe,0x65,0xd2,0xf7,0xf3,0x53,0x88,0xdb,0xac,0xb7,0xb,0x89,0x72,0x21,0x22,0x87,0x6,0x99,0xd9,0x2d,0xd,0x69,0xe9,0x25,0xca,0x55,0x55,0x91,0x55,0x5b,0x78,0x4,0x66,0x27,0x51,0xce,0x1d,0x11,0x35,0xc3,0x0,0x90,0x55,0x41,0x44,0xe8,0x9a,0xc9,0x42,0xff,0x37,0xf0,0x65,0xe1,0x78,0x3a,0xcc,0x2,0xfb,0xdd,0x73,0xff,0xf7,0x2b,0x94,0x13,0xde,0xf5,0x46,0x13,0x8c,0x3d,0x9c,0x32,0x9e,0x5c,0xe1,0x11,0x98,0x4b,0xf5,0xf2,0x89,0x35,0x53,0xab,0x12,0xd4,0xea,0x7b,0x3,0x33,0x43,0x60,0x6e,0x6,0x3,0x33,0xcc,0xc,0x3e,0xd,0x89,0x25,0x4a,0xee,0xfb,0xfe,0x93,0x73,0x5e,0xdd,0x1,0xb6,0x6d,0x35,0xa4,0xf0,0x42,0xdf,0x17,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char scroll_button_left_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,0x30,0x0,0x2d,0x0,0x31,0x39,0x29,0xd6,0x70,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,0xdd,0x9,0x17,0xe,0x16,0x1f,0x39,0xa4,0x3d,0x2e,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,0x47,0x49,0x44,0x41,0x54,0x38,0xcb,0x5d,0x93,0x51,0x4b,0x54,0x51,0x10,0xc7,0x7f,0x77,0x77,0x75,0x33,0xd7,0x5d,0x64,0xa3,0x56,0x83,0x50,0xb1,0xd0,0xd2,0x90,0xa,0xa1,0x97,0x9e,0xfb,0x8,0xe1,0x37,0xd8,0x87,0x90,0x1e,0x12,0xd3,0xd5,0xc2,0x82,0x88,0x5e,0x3,0x3f,0x41,0xdf,0xa1,0xcf,0x10,0x18,0x91,0x41,0x11,0xa2,0x66,0x65,0xab,0xbb,0xa6,0x5e,0x77,0xb5,0xbb,0x7b,0x66,0xa6,0x87,0x7b,0xf7,0xb6,0x3a,0x70,0x38,0x87,0x73,0x66,0xe6,0x3f,0xf3,0x9f,0xf3,0xf7,0x68,0xb3,0xa1,0x81,0xe1,0xfb,0x40,0x11,0xb8,0xd,0x5c,0xe6,0xb4,0xfd,0x2,0x56,0x80,0xe5,0xf5,0xcd,0xb5,0x77,0xad,0x4b,0x2f,0xa,0xcc,0x1,0x2f,0xb,0x85,0xfe,0xe2,0xd8,0xe8,0x38,0xbd,0xb9,0x5e,0x3a,0xd3,0x69,0x54,0xc,0x80,0x44,0xd2,0xa3,0x11,0x4,0xec,0x1f,0xee,0xf3,0xf9,0xcb,0x2a,0xe5,0xf2,0xf6,0x32,0xf0,0x64,0x7d,0x73,0xed,0x30,0x15,0x25,0x7a,0x31,0x71,0xf3,0x56,0x71,0xf0,0xca,0x35,0x2a,0x95,0xa,0x1b,0x7b,0x5b,0x4,0x41,0xf3,0x14,0x7c,0x3a,0xdd,0xc1,0xb9,0xae,0x2e,0xee,0xde,0xb9,0xc7,0xc6,0xd6,0xb7,0xe2,0xc7,0x4f,0x1f,0x4,0x78,0x98,0x1c,0x1a,0x18,0x9e,0xea,0x2b,0xf4,0xbf,0xba,0x3a,0x38,0xc2,0x8f,0xef,0x3f,0x39,0xae,0x1f,0xd3,0x14,0x87,0x61,0x98,0x81,0x99,0x1,0x86,0x6b,0xa,0x27,0x7f,0x4f,0xf0,0xf,0x7c,0xfa,0xfa,0xfa,0xa9,0xd5,0xfd,0xc9,0x8e,0x8e,0xce,0xaf,0x9,0xa0,0x78,0x7d,0x64,0x8c,0xdd,0x72,0x95,0xa0,0x11,0x20,0x26,0xa8,0x2a,0x2a,0x8a,0x9a,0x30,0x53,0x9a,0xe6,0xf1,0xfc,0x74,0x78,0x2f,0x4a,0xd0,0x8,0xd8,0x2d,0x57,0xb9,0x31,0x3a,0xe,0x50,0x4c,0x0,0xe3,0x22,0x42,0xad,0x5e,0x43,0x4d,0x50,0x15,0x54,0x4,0x35,0x65,0xb6,0xf4,0x88,0xa8,0xc,0x44,0x25,0x7a,0x57,0x6a,0xf5,0x23,0x44,0x4,0x60,0x22,0x5,0xe4,0x9c,0x38,0xd4,0x4,0xc2,0x6a,0xc1,0x33,0xe6,0x17,0x67,0xb0,0xe8,0xc,0x1e,0xa6,0x82,0xb5,0x78,0x37,0xc3,0x89,0x3,0xc8,0xa5,0x0,0xc4,0x35,0x11,0x15,0x3c,0xb,0xe3,0x17,0x96,0x66,0x23,0xe7,0x10,0x1d,0x40,0x55,0x63,0x42,0x2d,0x8a,0x1,0x48,0x1,0x34,0x9d,0x43,0x55,0xf0,0xa2,0x47,0x33,0x8b,0xcf,0x21,0x66,0xd8,0x42,0xbb,0x35,0x9d,0xb,0x47,0xc,0xe0,0x9c,0x43,0x4d,0x11,0x15,0x4c,0x95,0x67,0xa5,0xe7,0x58,0xdc,0x8f,0x61,0x18,0xaa,0x82,0xa9,0xc4,0xbb,0x6b,0x4b,0x70,0xe8,0x9c,0x43,0x45,0x30,0x8b,0x88,0x32,0x61,0x71,0x6e,0x9,0x33,0x8b,0x97,0xaa,0x22,0xaa,0xa8,0xa,0xa2,0xda,0x4a,0x50,0x4b,0x0,0xab,0xce,0x35,0x51,0x5c,0xec,0xa0,0x12,0xee,0xb,0x73,0x4f,0x23,0xfc,0xb0,0x82,0xd6,0x14,0x14,0x87,0xb,0x39,0x58,0xf1,0x86,0x6,0x86,0xa7,0x72,0xb9,0xdc,0xdb,0x8b,0xf9,0x4b,0xf8,0xbe,0x8f,0x47,0x22,0xfa,0xe0,0x6d,0x8c,0x79,0x5e,0x4c,0xa6,0xa1,0x64,0xb3,0x59,0x76,0xaa,0x65,0x7c,0xdf,0x7f,0x90,0xdc,0x3f,0xf8,0xb3,0x7a,0xbe,0xab,0xfb,0x42,0x3a,0x9d,0x9e,0xcc,0x74,0x67,0x68,0x48,0x23,0xea,0x33,0x42,0x8e,0x26,0x61,0x9e,0xe0,0x25,0x3d,0x7a,0x32,0x3d,0xd4,0x4f,0xea,0xec,0xed,0x55,0xdf,0xac,0x6f,0xae,0xbd,0x6e,0x69,0xa1,0xf4,0xbb,0xbc,0x9d,0xec,0xc9,0x64,0x8b,0xf9,0x7c,0x1e,0x2f,0x91,0xf8,0xaf,0xb4,0xb6,0x69,0x98,0x2a,0x3b,0x95,0x1d,0x8e,0x6a,0xfe,0x32,0x50,0x6a,0xf7,0x39,0x2b,0xe7,0x49,0xa0,0x70,0x46,0xce,0x65,0xe0,0xfd,0x59,0x39,0xff,0x3,0xf4,0x94,0x88,0x15,0xb6,0xb0,0x66,0x34,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,0x59,0x0,0x59,0x0,0x59,0xbd,0x9a,0xea,0xaa,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,0x13,0x19,0x39,0xdb,0x30,0xb9,0x4d,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,0xbb,0x49,0x44,0x41,0x54,0x38,0x8d,0xad,0x93,0x3d,0xe,0x82,0x40,0x10,0x85,0x1f,0x64,0x8a,0x49,0x24,0x56,0x54,0x3b,0x57,0xd0,0x78,0xf,0x63,0x3c,0x8e,0xbf,0x7,0x50,0x44,0x8e,0x9,0x15,0x8d,0xd,0x4e,0x31,0xc9,0x5a,0x61,0xa1,0x22,0x2c,0xfa,0x92,0xa9,0x36,0xdf,0xb7,0x6f,0x93,0x9d,0x68,0x3e,0x5b,0xb0,0x38,0x69,0x88,0x28,0x42,0x40,0xcc,0xcc,0x97,0x55,0x39,0x21,0x71,0x72,0x57,0x55,0xa8,0x6a,0x8,0xf,0x66,0x8e,0xc4,0x49,0x13,0x13,0x51,0x30,0xc,0x0,0xaa,0xa,0x22,0x42,0x1c,0x4c,0xbe,0xa4,0x57,0x90,0x17,0x19,0xf2,0x22,0xeb,0x3c,0xa7,0x6f,0xf0,0xe5,0x7a,0x86,0xf7,0x7e,0x5c,0x83,0x2c,0x3f,0xf5,0x95,0xeb,0x6e,0xd0,0xc2,0x7d,0xb7,0x77,0xa,0x86,0x80,0x6d,0x3e,0x3e,0x61,0xb7,0x39,0xfc,0x26,0x68,0x25,0xde,0xfb,0xe7,0x4,0xb,0x0,0x60,0xbf,0x3d,0xf6,0xa,0xa2,0xd5,0x72,0xed,0xeb,0xba,0x1e,0xd2,0xf6,0x2d,0x69,0x9a,0xfe,0xe1,0x27,0x9a,0x19,0x98,0x39,0x18,0x64,0x66,0x98,0x19,0xa8,0xac,0xca,0xa9,0x38,0xb9,0x25,0x49,0x32,0x66,0x9d,0xe5,0x1,0x80,0xd0,0x51,0x2e,0x9,0x63,0x6e,0xe0,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char scroll_button_left_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,0x30,0x0,0x2d,0x0,0x31,0x39,0x29,0xd6,0x70,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,0xdd,0x9,0x17,0xe,0x16,0x30,0x92,0x75,0x0,0x77,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,0x5a,0x49,0x44,0x41,0x54,0x38,0xcb,0x5d,0x93,0x5d,0x4b,0x94,0x51,0x10,0xc7,0x7f,0xcf,0xb3,0x5b,0xbe,0x90,0xee,0x9a,0xa1,0xd5,0x96,0x18,0x44,0x96,0xac,0xf8,0x6,0x46,0x75,0x13,0x74,0xd3,0x47,0x8,0xaf,0x25,0xd8,0xc4,0xb,0x8d,0x2e,0xa,0xaf,0xca,0x30,0xa9,0xee,0x2,0x3f,0x41,0xdf,0xa1,0x2f,0x10,0x51,0xa0,0x10,0x8a,0x28,0x44,0xf8,0xd2,0xd2,0xea,0x52,0xeb,0xfa,0xa8,0xed,0xee,0x73,0x66,0xa6,0x8b,0x67,0x5d,0x57,0x7,0xe,0x7,0xe6,0xcc,0xfc,0x67,0xe6,0x3f,0xe7,0xef,0x51,0x67,0xbd,0x3d,0xe9,0x87,0x40,0x6,0x18,0x6,0x52,0x9c,0xb4,0x2c,0xb0,0x0,0xcc,0xaf,0xac,0x2d,0x7f,0x3a,0x72,0x7a,0xd5,0xc4,0x4,0x30,0x7b,0xb5,0xab,0x3b,0x33,0xd4,0x3f,0x44,0x5b,0xa2,0x8d,0xb3,0xd,0xd,0xa8,0x1a,0x0,0xbe,0xef,0x51,0x29,0x97,0x29,0x14,0xb,0x2c,0x7e,0x5f,0x64,0x6b,0x73,0x7d,0x1e,0x78,0xbe,0xb2,0xb6,0x5c,0x8c,0x57,0x81,0x66,0xee,0xdc,0xbe,0x97,0xb9,0x7e,0xed,0x26,0xdb,0xdb,0x79,0xfe,0xee,0x6c,0x50,0x2a,0x85,0x27,0xca,0x37,0x36,0x9e,0xa1,0xa9,0xb9,0x99,0xfb,0x77,0x1f,0xf0,0xe3,0xd2,0x6a,0xe6,0xcb,0xd7,0xcf,0x2,0x4c,0xc4,0x7a,0x7b,0xd2,0xa3,0x5d,0x5d,0xdd,0x73,0xb7,0x6e,0xa4,0xd9,0xf8,0xb9,0xc5,0xc1,0xfe,0x1,0xa1,0xb,0x31,0x14,0x33,0xc3,0xcc,0x0,0xc3,0x85,0x8e,0xc3,0x7f,0x87,0x14,0xb,0x7b,0xa4,0xae,0xa4,0x8,0xf6,0xf7,0x46,0x1a,0xce,0x36,0xac,0xfa,0x40,0x66,0xa0,0x6f,0x90,0x5c,0x36,0x4f,0xa9,0x5c,0x42,0x4c,0x50,0x55,0x54,0x14,0x35,0x61,0x7c,0x6a,0x8c,0x27,0x93,0x63,0x91,0x5f,0x94,0x52,0xb9,0x44,0x2e,0x9b,0x67,0xb0,0x7f,0x18,0x20,0xe3,0x3,0x7d,0x22,0x42,0x10,0x4,0xa8,0xa,0x2a,0x82,0xba,0x8,0x64,0x62,0xea,0x31,0x98,0x81,0x19,0x4e,0xa4,0xfa,0xae,0x4,0xc1,0x1e,0x22,0x2,0x30,0x10,0x7,0x12,0xa1,0x38,0xc4,0x1c,0x44,0xdd,0x82,0x67,0x4c,0x3e,0x1b,0xaf,0xb5,0xf,0x1e,0xa6,0xe,0x39,0xe2,0xdd,0x8c,0x50,0x1c,0x40,0x22,0xe,0x20,0x61,0x5,0x51,0xc1,0xd3,0x28,0xfc,0xe9,0x8b,0x9,0x22,0xfe,0xa3,0xea,0x0,0xaa,0x5a,0x23,0xd4,0xaa,0x39,0x0,0x71,0x80,0x8a,0x73,0x88,0x8,0x3e,0xa0,0x80,0x99,0xe1,0x55,0x3,0xa3,0x9a,0xd1,0x8,0xf5,0x56,0x71,0x2e,0x5a,0x31,0x80,0xb,0x43,0xd4,0x4,0xa7,0xe,0x53,0x61,0x6e,0xe6,0xfd,0xf1,0x6,0xcc,0x50,0x33,0x54,0x1d,0xa6,0xae,0x76,0xbb,0x30,0xac,0x1,0x14,0x43,0xe7,0x50,0x11,0xcc,0x4,0xad,0x9e,0xd9,0x57,0xef,0xa0,0x6e,0x8d,0xaa,0x8a,0xa8,0xa2,0x2a,0x88,0x2a,0x61,0xd4,0xc1,0xbe,0xf,0x2c,0xb9,0xb0,0x82,0x10,0xe2,0x44,0x10,0x71,0x88,0x8b,0xee,0xd7,0x2f,0xdf,0x60,0x44,0x20,0x22,0xe,0xd1,0x68,0x54,0x21,0xc4,0x45,0x1c,0x2c,0x78,0xbd,0x3d,0xe9,0xd1,0xf3,0xed,0xed,0x1f,0x2f,0x77,0xa4,0xd8,0xdd,0x2d,0xe0,0x11,0xab,0x7e,0xf0,0x3a,0xc6,0x3c,0xaf,0x46,0xa6,0x21,0x24,0x93,0x6d,0x64,0x73,0x5b,0x14,0xa,0x85,0x47,0xb1,0xfc,0x9f,0x9d,0xa5,0x73,0xcd,0x2d,0x17,0x1a,0x9b,0x9b,0x46,0x5a,0x5b,0x12,0x94,0x5d,0x29,0x9a,0x53,0xc,0x43,0x11,0x34,0x1a,0xc5,0x13,0xbc,0x98,0x47,0xa2,0x35,0x49,0x70,0x18,0xb0,0xbd,0x9d,0xfb,0xb0,0xb2,0xb6,0xfc,0xf6,0x48,0xb,0xd3,0x9b,0x9b,0xeb,0xb1,0x64,0xa2,0x2d,0xd3,0xd1,0xd9,0x89,0xef,0xfb,0xc7,0x4a,0xab,0xdb,0x86,0xaa,0x92,0xfd,0xfd,0x8b,0xdd,0x62,0x61,0x1e,0x98,0xae,0x8f,0x39,0x2d,0xe7,0x11,0xe0,0xe2,0x29,0x39,0xe7,0x80,0x6f,0xa7,0xe5,0xfc,0x1f,0xa8,0xd,0x8b,0xe8,0xd0,0x6f,0x71,0x8b,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,0x59,0x0,0x59,0x0,0x59,0xbd,0x9a,0xea,0xaa,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,0x13,0x19,0x35,0xd2,0x86,0xf5,0x66,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,0xc3,0x49,0x44,0x41,0x54,0x38,0x8d,0x9d,0x93,0x4d,0xa,0x83,0x30,0x10,0x85,0x5f,0xc4,0xa1,0x10,0xa1,0xde,0xa0,0xb,0x73,0x8c,0x52,0x7a,0x2d,0xa9,0x68,0x5d,0xb4,0xf6,0xef,0x8c,0xf1,0x12,0xc5,0xb4,0x30,0x8b,0xe9,0x4e,0x8a,0x68,0x34,0xbe,0x6d,0x78,0xdf,0xbc,0x99,0x47,0xd4,0x61,0x7f,0xdc,0x98,0xcc,0x7c,0x88,0x48,0x21,0x40,0xcc,0x2c,0xb6,0xb5,0xdb,0xd8,0x64,0xe6,0xeb,0x9c,0x43,0xe7,0x5c,0x88,0x1f,0x89,0xd6,0xca,0x64,0xe6,0x1d,0x11,0x51,0xb0,0x19,0x0,0x3a,0xe7,0x40,0x44,0x88,0x82,0x9d,0x3,0xcd,0x2,0xaa,0xba,0x40,0x55,0x17,0x93,0xef,0xb1,0xcf,0x5c,0x9e,0x4f,0x10,0x11,0xef,0x80,0x49,0x40,0x51,0xe6,0x10,0x11,0x88,0x8,0x94,0x9a,0x2e,0x68,0x14,0x50,0x94,0x39,0x0,0xf4,0x80,0xe0,0x4,0x43,0x93,0xf,0x32,0x7a,0xc4,0xe6,0xf2,0xe8,0xa7,0xcf,0xa5,0x98,0x6c,0xe1,0x76,0x7d,0x2e,0x5a,0xc1,0x5b,0xe3,0xbd,0x79,0x1,0xf0,0xaf,0xe0,0xad,0xf1,0x1f,0xb2,0x2a,0xc1,0x12,0x45,0xcc,0x8c,0x44,0xeb,0x60,0x63,0xa2,0x35,0x98,0x19,0xb1,0x6d,0xad,0x36,0x99,0xe9,0xd2,0x34,0x5d,0xf3,0x9d,0x77,0x3f,0xd3,0x69,0x5f,0xde,0x59,0x55,0x4f,0x95,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char scroll_button_right_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,0x30,0x0,0x2d,0x0,0x31,0x39,0x29,0xd6,0x70,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,0xdd,0x9,0x17,0xe,0x16,0x14,0xae,0x76,0xe4,0xa6,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,0x43,0x49,0x44,0x41,0x54,0x38,0xcb,0x5d,0x93,0xdf,0x4a,0x54,0x51,0x14,0x87,0xbf,0x73,0x46,0x9d,0xcc,0xd1,0x41,0x26,0x6a,0x34,0x8,0x15,0xb,0x2d,0xd,0xa9,0x10,0xba,0xe9,0xba,0x47,0x8,0xdf,0x60,0x2e,0xa2,0x82,0x90,0xb4,0x29,0x85,0x84,0x88,0x6e,0x3,0x9f,0xa0,0x77,0xe8,0x19,0x2,0x23,0x32,0x28,0x42,0xd4,0xac,0x6c,0x74,0xc6,0xd4,0xe3,0x8c,0x36,0x33,0x7b,0xad,0xd5,0xc5,0x3e,0xf3,0x27,0x37,0x1c,0x38,0xac,0xb3,0xd7,0xf7,0xfb,0xad,0xb5,0xce,0xa,0x68,0x3b,0x23,0x43,0xa3,0x77,0x81,0x1c,0x70,0x13,0xb8,0xc8,0xff,0xe7,0x17,0xb0,0x2,0x2c,0xaf,0x6f,0xae,0xbd,0x6b,0x4,0x83,0x38,0x31,0xd,0xbc,0xcc,0x66,0x7,0x73,0x13,0xe3,0x93,0xf4,0xa7,0xfb,0xe9,0x4a,0x26,0x51,0x31,0x0,0xc2,0x44,0x40,0xad,0x5a,0x65,0xff,0x70,0x9f,0xcf,0x5f,0x56,0x29,0x14,0xb6,0x97,0x81,0xb9,0xf5,0xcd,0xb5,0xc3,0x8e,0x18,0xb4,0x34,0x75,0xfd,0x46,0x6e,0xf8,0xd2,0x15,0x8a,0xc5,0x22,0x1b,0x7b,0x5b,0x54,0xab,0xf5,0xff,0xe4,0x93,0xc9,0x4e,0xce,0x74,0x77,0x73,0xfb,0xd6,0x1d,0x36,0xb6,0xbe,0xe5,0x3e,0x7e,0xfa,0x20,0xc0,0xfd,0xc4,0xc8,0xd0,0xe8,0xcc,0x40,0x76,0xf0,0xd5,0xe5,0xe1,0x31,0x7e,0x7c,0xff,0xc9,0x71,0xe5,0x98,0xba,0x38,0xc,0xc3,0xc,0xcc,0xc,0x30,0x5c,0x5d,0x38,0xf9,0x7b,0x42,0x74,0x10,0x31,0x30,0x30,0x48,0xb9,0x12,0x4d,0x77,0x76,0x76,0x7d,0xd,0x81,0xdc,0xd5,0xb1,0x9,0x76,0xb,0x25,0xaa,0xb5,0x2a,0x62,0x82,0xaa,0x32,0xfb,0xf4,0x21,0xb3,0xf9,0x7,0xa8,0x9,0xa2,0xe2,0xe3,0xa2,0x54,0x6b,0x55,0x76,0xb,0x25,0xae,0x8d,0x4f,0x2,0xe4,0x42,0x60,0x52,0x44,0x28,0x57,0xca,0xa8,0x9,0xaa,0x82,0x8a,0x80,0x1,0x66,0x3c,0xc9,0x3f,0x42,0xd5,0x43,0x34,0x86,0x97,0x2b,0x47,0x88,0x8,0xc0,0x54,0x8,0xa4,0x9d,0xb8,0xe6,0x47,0x15,0x45,0x4d,0x30,0x53,0x5f,0x2,0xc6,0xdc,0xf3,0xc7,0x98,0xc6,0xf0,0x58,0xc4,0x89,0x3,0x48,0x87,0x0,0xe2,0xea,0x5e,0x41,0x62,0x25,0x55,0x6f,0x0,0xc3,0xcc,0x3f,0xf3,0xb,0xb3,0x5e,0x40,0x5,0x31,0x45,0x9c,0x6f,0x72,0x7,0x40,0xdd,0x39,0x54,0x85,0x0,0xef,0xbc,0x61,0xdf,0x9a,0xb3,0xf6,0xef,0xa2,0xd2,0x9c,0x4a,0xdd,0xb9,0x16,0xc0,0x39,0x87,0x9a,0x82,0x19,0x41,0x7c,0xbd,0x95,0xee,0x79,0x8b,0xf9,0xa5,0xa6,0x40,0x10,0xe7,0x34,0x0,0x87,0xce,0xb9,0xb4,0x8a,0x10,0x4,0x86,0x35,0x0,0xd6,0x2,0x2c,0xe4,0x5f,0xd0,0xe2,0x79,0x44,0xc,0x28,0x87,0xc0,0xaa,0x73,0x75,0x14,0x87,0xc4,0x35,0xaa,0xa8,0xaf,0x1d,0xe3,0xd9,0xfc,0xa2,0x8f,0xb5,0x4d,0x41,0x71,0x38,0xdf,0x83,0x95,0x60,0x64,0x68,0x74,0x26,0x9d,0x4e,0xbf,0x3d,0x9f,0xb9,0x40,0x14,0x45,0x4,0x84,0xf1,0xf,0xde,0x2e,0x18,0x40,0xec,0xc8,0x50,0xfa,0xfa,0xfa,0xd8,0x29,0x15,0x88,0xa2,0xe8,0x5e,0x62,0xff,0xe0,0xcf,0xea,0xd9,0xee,0x9e,0x73,0xc9,0x64,0x72,0x3a,0xd5,0x93,0xa2,0x26,0x35,0x54,0x5,0x53,0xef,0x40,0x31,0xdf,0xd0,0x40,0x8,0x12,0x1,0xbd,0xa9,0x5e,0x2a,0x27,0x15,0xf6,0xf6,0x4a,0x6f,0xd6,0x37,0xd7,0x5e,0x37,0x76,0x21,0xff,0xbb,0xb0,0x9d,0xe8,0x4d,0xf5,0xe5,0x32,0x99,0xc,0x41,0x18,0xb6,0x36,0x8d,0x56,0xf9,0xa6,0xca,0x4e,0x71,0x87,0xa3,0x72,0xb4,0xc,0xe4,0xdb,0xef,0x9c,0x5e,0xe7,0x69,0x20,0x7b,0x6a,0x9d,0xb,0xc0,0xfb,0xd3,0xeb,0xfc,0xf,0xed,0x2d,0x85,0x24,0xfc,0x1,0xe2,0x46,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,0x59,0x0,0x59,0x0,0x59,0xbd,0x9a,0xea,0xaa,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,0x13,0x19,0x31,0xd5,0xeb,0x31,0x7f,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,0xbb,0x49,0x44,0x41,0x54,0x38,0x8d,0xad,0x93,0x3d,0xe,0x82,0x40,0x10,0x85,0x1f,0x64,0x8a,0x49,0x24,0x56,0x54,0x3b,0x57,0xd0,0x78,0xf,0x63,0x3c,0x8e,0xbf,0x7,0x50,0x44,0x8e,0x9,0x15,0x8d,0xd,0x4e,0x31,0x61,0xad,0xb0,0x30,0x82,0x2c,0xf1,0x25,0x9b,0x6c,0xf1,0xbe,0x97,0x37,0x99,0xdd,0x68,0xb9,0x58,0xb1,0x38,0x69,0x88,0x28,0x42,0x80,0xcc,0xcc,0x97,0x55,0x39,0x23,0x71,0xf2,0x54,0x55,0xa8,0x6a,0x8,0xf,0x66,0x8e,0xc4,0x49,0x13,0x13,0x51,0x30,0xc,0x0,0xaa,0xa,0x22,0x42,0x1c,0x4c,0x7e,0xa8,0x37,0x20,0x2f,0x32,0xe4,0x45,0x36,0x3d,0x0,0x0,0xbc,0xf7,0xb8,0xdd,0xaf,0xd3,0x2,0xda,0xb6,0x7d,0xdf,0x87,0x42,0x7e,0x36,0xe8,0x4e,0x96,0x5f,0xbe,0x7a,0x68,0x8,0x1e,0xa3,0xd1,0x5b,0x38,0xec,0x4e,0xd3,0x1b,0x1c,0xf7,0xe7,0xf0,0x6,0xdd,0xec,0x43,0x30,0x0,0x44,0x9b,0xf5,0xd6,0xd7,0x75,0x3d,0x68,0xea,0x53,0x9a,0xa6,0x7f,0x78,0x89,0x66,0x6,0x66,0xe,0x6,0x99,0x19,0x66,0x6,0x2a,0xab,0x72,0x2e,0x4e,0x1e,0x49,0x92,0x4c,0xf9,0xce,0xf2,0x2,0x3d,0xd2,0x54,0x2c,0x85,0x2c,0xaa,0x56,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char scroll_button_right_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,0x30,0x0,0x2d,0x0,0x31,0x39,0x29,0xd6,0x70,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,0xdd,0x9,0x17,0xe,0x17,0x3,0x34,0xbe,0x50,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,0x2,0x58,0x49,0x44,0x41,0x54,0x38,0xcb,0x5d,0x93,0x5d,0x4b,0x54,0x51,0x14,0x86,0x9f,0x73,0xc6,0x1c,0x1d,0xd2,0xd1,0xc,0xad,0x2c,0x31,0x88,0x2c,0x51,0xfc,0x2,0xa3,0x8f,0x8b,0xa0,0x9b,0x7e,0x42,0x78,0x5d,0xd1,0x20,0x46,0x49,0x4,0x81,0x57,0x91,0x7d,0x49,0x5d,0x5,0xfe,0x82,0xfe,0x43,0x7f,0x20,0xa2,0x40,0x21,0x14,0x51,0x88,0xf0,0xa3,0xa1,0xd1,0xa1,0xc6,0xf1,0xa8,0xcd,0xcc,0xd9,0x6b,0xad,0x2e,0xce,0xcc,0x38,0xba,0x6f,0x36,0xac,0xbd,0xde,0xf7,0x5d,0x6b,0xed,0xf5,0x7a,0xd4,0x9c,0xde,0x9e,0xbe,0xdb,0x40,0xa,0x18,0x1,0x3a,0x39,0x7c,0xd2,0xc0,0x1c,0x30,0xbb,0xb4,0xb2,0xf8,0xa9,0x12,0xf4,0xca,0xc0,0x24,0xf0,0xea,0x5c,0x57,0x77,0x6a,0x78,0x60,0x98,0xd6,0x64,0x2b,0xf5,0xf1,0x38,0xaa,0x6,0x80,0xef,0x7b,0x94,0x8a,0x45,0x72,0xf9,0x1c,0xf3,0xdf,0xe7,0xd9,0x58,0x5f,0x9d,0x5,0x9e,0x2d,0xad,0x2c,0xe6,0xeb,0xca,0x44,0x2f,0xae,0x5e,0xb9,0x9e,0xba,0x70,0xfe,0x12,0x9b,0x9b,0x59,0xfe,0x6e,0xad,0x51,0x28,0x84,0x87,0xe4,0x1b,0x1a,0x8e,0xd1,0x98,0x48,0x70,0xf3,0xda,0x2d,0x7e,0x9c,0x5e,0x4e,0x7d,0xf9,0xfa,0x59,0x80,0x89,0x58,0x6f,0x4f,0xdf,0x58,0x57,0x57,0xf7,0x9b,0xcb,0x17,0xfb,0x58,0xfb,0xb9,0xc1,0xde,0xee,0x1e,0xa1,0xb,0x31,0x14,0x33,0xc3,0xcc,0x0,0xc3,0x85,0x8e,0xfd,0x7f,0xfb,0xe4,0x73,0x3b,0x74,0x9e,0xed,0x24,0xd8,0xdd,0x19,0x8d,0xd7,0xc7,0x97,0x7d,0x20,0x35,0xd8,0x3f,0x44,0x26,0x9d,0xa5,0x50,0x2c,0x20,0x26,0xa8,0x2a,0xe3,0x8f,0xef,0x31,0x3e,0x79,0x17,0x35,0x41,0x54,0xa2,0xb8,0x28,0x85,0x62,0x81,0x4c,0x3a,0xcb,0xd0,0xc0,0x8,0x40,0xca,0x7,0xfa,0x45,0x84,0x20,0x8,0x50,0x15,0x54,0x4,0x75,0x2,0x66,0x60,0xc6,0xc4,0xe4,0x7d,0x54,0x4,0x27,0x52,0x7e,0x57,0x82,0x60,0x7,0x11,0x1,0x18,0xf4,0x81,0x64,0x28,0xe,0x31,0x17,0x29,0x89,0x20,0xe6,0x30,0xab,0xb4,0xa0,0x3c,0x7c,0xf2,0x0,0x53,0x87,0x68,0x25,0xcf,0x11,0x8a,0x3,0x48,0xfa,0x0,0x12,0x96,0x10,0x8d,0x94,0x45,0xa2,0x16,0xa2,0xce,0xad,0x3a,0x87,0x47,0x4f,0xc7,0x51,0x55,0x54,0x5,0x31,0x45,0xc2,0x12,0x0,0x75,0x0,0x25,0xe7,0x10,0x11,0x7c,0x40,0x1,0x4,0x30,0xc3,0xaa,0x7f,0x6d,0x98,0x81,0x8b,0xca,0xa6,0x82,0xa9,0x12,0xb8,0x30,0x44,0x4d,0x50,0x33,0xbc,0x28,0x3d,0x52,0x2e,0x2f,0x8a,0x2,0x6f,0xa7,0xdf,0xe3,0x41,0x35,0xe6,0xc2,0xb0,0x4a,0x90,0xf,0x9d,0x4b,0xaa,0x8,0x9e,0x67,0x58,0xd,0x1,0x65,0xc0,0xeb,0xe9,0x77,0x54,0xcb,0x29,0x53,0x84,0x51,0x5,0xbb,0x75,0xc0,0x82,0xb,0x4b,0x37,0x84,0x10,0xc4,0x8b,0x54,0x8c,0x88,0xc0,0x33,0x5e,0x3e,0x9f,0xa9,0xc5,0x45,0x77,0xcc,0x70,0xd1,0xc,0xe6,0xbc,0xde,0x9e,0xbe,0xb1,0x13,0x6d,0x6d,0x1f,0xcf,0xb4,0x77,0xb2,0xbd,0x9d,0xc3,0x23,0x56,0x5e,0xf0,0x5a,0x41,0x2f,0x62,0x5,0xc,0xa1,0xa5,0xa5,0x95,0x74,0x66,0x83,0x5c,0x2e,0x77,0x27,0x96,0xfd,0xb3,0xb5,0x70,0x3c,0xd1,0x74,0xb2,0x21,0xd1,0x38,0xda,0xdc,0x94,0xa4,0xe8,0xa,0xa8,0x3a,0x4c,0xc,0x43,0x11,0x34,0x1a,0xa8,0x27,0x78,0x31,0x8f,0x64,0x73,0xb,0xc1,0x7e,0xc0,0xe6,0x66,0xe6,0xc3,0xd2,0xca,0xe2,0x4c,0xc5,0xb,0x53,0xeb,0xeb,0xab,0xb1,0x96,0x64,0x6b,0xaa,0xbd,0xa3,0x3,0xdf,0xf7,0xf,0x9c,0xc6,0x41,0xfb,0xaa,0x4a,0xfa,0xf7,0x2f,0xb6,0xf3,0xb9,0x59,0x60,0xaa,0x36,0xe7,0xa8,0x9d,0x47,0x81,0x53,0x47,0xec,0x9c,0x1,0xbe,0x1d,0xb5,0xf3,0x7f,0xe9,0x95,0x7b,0x78,0x8a,0x5f,0xe7,0x67,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,0x59,0x0,0x59,0x0,0x59,0xbd,0x9a,0xea,0xaa,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,0x13,0x19,0x2c,0xb6,0xed,0x5d,0xa6,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,0xa5,0x93,0x4d,0xa,0xc2,0x30,0x10,0x85,0x5f,0xa5,0x83,0x90,0x82,0xbd,0x81,0x8b,0xe4,0x18,0x22,0x5e,0x4b,0xad,0xad,0xdd,0x68,0xfd,0xbb,0x62,0x7a,0x9,0x69,0x14,0x6,0x32,0xae,0x4,0x91,0xb6,0x92,0xf8,0x56,0xb3,0x98,0xef,0xe3,0x2d,0x66,0x92,0xe5,0x62,0x35,0x35,0xda,0x3c,0x88,0x28,0x41,0x40,0x98,0x59,0x6c,0x6b,0x67,0xa9,0xd1,0xe6,0xe9,0x9c,0x43,0xe7,0x5c,0x8,0x8f,0x4c,0xa9,0xc4,0x68,0x73,0x9f,0x10,0x51,0x30,0xc,0x0,0x9d,0x73,0x20,0x22,0x4c,0x82,0xc9,0xaf,0xc,0xa,0xaa,0xba,0x40,0x55,0x17,0xf1,0x2,0x11,0x81,0x88,0xa0,0xdc,0x6f,0xe3,0x4,0xde,0x7b,0x88,0x8,0xbc,0xf7,0xd8,0x55,0x9b,0x70,0xc1,0x67,0xb,0x11,0x41,0x51,0xae,0x7b,0x77,0xd2,0x31,0xb8,0x6f,0x8e,0x12,0x0,0x40,0x73,0xb8,0xc4,0xb,0x4e,0xc7,0x6b,0x7c,0x83,0x73,0x73,0x1b,0x84,0x47,0x5,0xbf,0xc0,0x77,0xfe,0xbf,0x44,0x66,0x46,0xa6,0x54,0x30,0x98,0x29,0x5,0x66,0x46,0x6a,0x5b,0xab,0x8c,0x36,0x5d,0x9e,0xe7,0x31,0xef,0x3c,0x7f,0x1,0x85,0xa9,0x5c,0xe7,0x16,0x3f,0x9a,0xd3,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char scroll_button_up_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,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,0xdb,0xb,0x4,0x11,0x1f,0x28,0xa9,0x94,0x8f,0x29,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,0x86,0x49,0x44,0x41,0x54,0x38,0xcb,0x9d,0x93,0x4d,0x4a,0x9c,0x41,0x10,0x86,0x9f,0xfe,0x66,0x14,0x25,0x28,0x38,0x9b,0x19,0x98,0x95,0xe4,0xe,0x9,0x28,0x62,0xc8,0x15,0xb2,0x71,0x21,0xc,0x82,0xb,0x17,0x5e,0x41,0xb2,0xcd,0x35,0x2,0x6e,0x73,0x85,0x10,0x97,0x1e,0x42,0x5c,0x9,0x8a,0x38,0x9,0x51,0xfb,0xaf,0xba,0xba,0x5d,0x38,0x33,0xfd,0xe9,0x28,0x82,0xb5,0xe9,0xa6,0xba,0xde,0xa7,0xba,0xab,0xaa,0xcd,0xb0,0x3f,0xf8,0x4,0x9c,0xf2,0x3e,0xfb,0x6c,0x86,0xfd,0x41,0xf9,0xb8,0xbe,0xce,0xd7,0xed,0x2f,0xac,0xae,0xac,0x0,0x6,0x4a,0x1,0xf3,0x2c,0xb4,0x0,0xc6,0x0,0x85,0xff,0xb7,0xb7,0xfc,0x3e,0xf9,0xc3,0xd9,0xf9,0x39,0x5d,0x80,0xad,0x8d,0x4d,0x0,0x6e,0xae,0x6f,0xa6,0x91,0xad,0x95,0x39,0xdf,0xc2,0xd2,0x22,0x5b,0x1b,0x9b,0x15,0xd0,0x5b,0x5b,0xe3,0xef,0x78,0x4c,0x8c,0xa1,0x66,0x2f,0x4f,0xe5,0x55,0x6f,0x30,0xd,0xf4,0x7a,0x3d,0x80,0x47,0x80,0x6a,0x26,0x6b,0x26,0xe7,0xdc,0x52,0xbc,0xf0,0x4,0x80,0x52,0xc8,0x9a,0x51,0xcd,0x15,0x90,0x92,0x90,0x54,0xc9,0xaa,0x4f,0xb4,0xdf,0x46,0xbb,0x0,0xfc,0xfa,0x79,0x3c,0xf3,0x19,0x20,0xa9,0x92,0x92,0x0,0xd0,0x0,0x4,0x1f,0x90,0x18,0x89,0x31,0x22,0x22,0x88,0xc8,0x4c,0x3c,0x5,0x4d,0xfd,0x31,0x46,0x24,0x46,0x82,0xf,0x15,0xe0,0x83,0x27,0x84,0x40,0x98,0x1c,0xec,0xec,0xef,0xcd,0xbd,0x60,0x67,0x7f,0x8f,0xe0,0x27,0x31,0x21,0xe0,0x83,0xaf,0x0,0xeb,0x2c,0xce,0x39,0x9c,0x73,0x8c,0xe,0xf,0x5e,0x6d,0xfa,0xe8,0xf0,0x60,0x16,0x67,0x9d,0xad,0x35,0x70,0x77,0x16,0xe7,0x2c,0x22,0xe9,0xcd,0xc9,0xf1,0xde,0xa3,0x9a,0xe8,0x74,0x3a,0x15,0x60,0xbd,0xc3,0xfb,0x80,0x24,0xe1,0xc7,0xd1,0x77,0xda,0x5d,0x7b,0xbe,0x7f,0xec,0xda,0x2,0x4d,0xb7,0xdb,0x2,0x58,0x87,0x8f,0x81,0xd4,0xbe,0x81,0x79,0xa5,0x8d,0x80,0xe6,0xc,0xb6,0xa9,0x0,0xef,0x3c,0x51,0x22,0x9a,0xf4,0xe5,0x19,0x68,0x9b,0x81,0x5c,0x32,0x14,0xd3,0xaa,0x41,0xc,0x24,0x91,0x3a,0x48,0x6f,0x58,0x93,0x33,0x3a,0x49,0xd4,0x5,0xb8,0xbc,0xbe,0xe2,0xc3,0xd2,0x32,0xa5,0x9d,0xbe,0xcc,0x67,0xae,0x5b,0xc3,0xfd,0xbf,0x71,0xad,0xcf,0xb0,0x3f,0x78,0xd7,0x5f,0xbe,0xb8,0xba,0xe4,0x1,0xf0,0xd2,0xea,0x35,0xc0,0x6a,0x26,0xd2,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,0x59,0x0,0x59,0x0,0x59,0xbd,0x9a,0xea,0xaa,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,0x13,0x19,0x26,0x56,0x38,0xb4,0xb8,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,0x9a,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x93,0x31,0xa,0xc3,0x30,0xc,0x45,0xbf,0x83,0x6,0x41,0x4d,0x27,0x4f,0xd6,0x15,0x5a,0x7a,0x8f,0x52,0x7a,0xaf,0x10,0x72,0x4c,0x67,0xf2,0xd2,0x25,0xd5,0x20,0x48,0xd7,0x92,0xba,0xa1,0x76,0x29,0xf4,0xaf,0xe2,0x3d,0x81,0xd0,0x77,0xc7,0xc3,0x89,0x25,0xca,0x4c,0x44,0xe,0x15,0x31,0xb3,0x25,0x4d,0x69,0x47,0x12,0xe5,0xae,0xaa,0x50,0xd5,0x1a,0x1e,0xcc,0xec,0x24,0xca,0xdc,0x11,0x51,0x35,0xc,0x0,0xaa,0xa,0x22,0x42,0x57,0x4d,0xae,0xf2,0x5b,0xc1,0x30,0xf6,0x18,0xc6,0xbe,0x4d,0xf0,0xc,0x6e,0x49,0x8a,0x82,0x12,0xf0,0x4e,0xf2,0x22,0xd8,0xda,0x56,0x9a,0x7d,0x7d,0x44,0x77,0x39,0x5f,0x97,0x9c,0x73,0x13,0x1c,0x42,0xf8,0xf7,0x3f,0xf8,0x48,0x60,0x66,0x60,0xe6,0x6a,0x90,0x99,0x61,0x66,0xa0,0x34,0xa5,0xbd,0x44,0xb9,0x79,0xef,0x5b,0xea,0x2c,0xf,0x4,0x76,0x39,0xf7,0xc5,0x49,0xf5,0x9f,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char scroll_button_up_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,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xdb,0xb,0x4,0x11,0x20,0x2,0x2a,0xf1,0x6c,0xc3,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,0x86,0x49,0x44,0x41,0x54,0x38,0xcb,0x9d,0x93,0xbf,0x4e,0x1b,0x41,0x10,0x87,0xbf,0xbd,0x9c,0x51,0x64,0xc9,0x91,0x70,0x6b,0x17,0xee,0x20,0x2f,0x40,0x5a,0xb,0x9,0xa5,0x4b,0x43,0x81,0x64,0x51,0x50,0x50,0xf0,0x14,0x88,0x3a,0xf,0x82,0x94,0x36,0x1d,0xf2,0x13,0xe4,0x9,0x12,0x3a,0xa4,0x80,0x28,0x90,0x89,0x14,0xeb,0xf6,0xff,0xec,0x52,0x18,0xb3,0x67,0xc,0x42,0x62,0x9a,0x5b,0x8d,0x7e,0xbf,0x6f,0x76,0x76,0xe6,0xd4,0x68,0x30,0xdc,0x1,0x7e,0xf1,0xbe,0xf8,0xa2,0x46,0x83,0x61,0xfe,0xbc,0xb5,0xcd,0xd7,0xbd,0x3d,0x3e,0xf5,0x7a,0x80,0x82,0x9c,0x41,0x3d,0x93,0x66,0x40,0x29,0x20,0xf3,0x7f,0x3e,0xe7,0x62,0x3a,0xe5,0xf7,0xe5,0x1f,0x6a,0x80,0xdd,0xf1,0x18,0x80,0xd9,0xdd,0x6c,0xa9,0x6c,0x7d,0x59,0xcb,0x75,0x3e,0x6e,0xb0,0x3b,0x1e,0x17,0x40,0x7f,0x73,0x93,0x7f,0xf7,0xf7,0x78,0xef,0x4a,0xf5,0xbc,0x6a,0x2f,0x7e,0x85,0xaa,0xa0,0xdf,0xef,0x3,0x2c,0x0,0x22,0x89,0x24,0x89,0x94,0x52,0xcb,0xf1,0x42,0xb,0x0,0x39,0x93,0x24,0x21,0x92,0xa,0x20,0xc6,0x40,0x14,0x21,0x89,0xac,0x78,0xbf,0x4d,0xe,0x0,0xf8,0x79,0xfe,0xe3,0x29,0xa7,0x80,0x28,0x42,0x8c,0x1,0x80,0xa,0xc0,0x59,0x47,0xf0,0x1e,0xef,0x1c,0xc1,0x7,0x82,0xf,0x4f,0xe6,0x25,0x68,0x99,0x5f,0x68,0x3c,0xce,0xba,0x2,0xb0,0xce,0xe2,0xac,0xc5,0x79,0x8f,0xb3,0x96,0xfd,0xa3,0xc3,0xb5,0xe,0xf6,0x8f,0xe,0x57,0x34,0xd6,0xd9,0x2,0xd0,0x46,0xa3,0xb5,0x41,0x6b,0xcd,0xe4,0xe4,0xf8,0xd5,0xa1,0x4f,0x4e,0x8e,0xd1,0xfa,0x51,0x6b,0x74,0x79,0x3,0x33,0x6f,0x30,0xba,0xc1,0x87,0xf0,0xe6,0xe6,0x18,0x63,0x90,0x18,0xa9,0xeb,0xf,0x5,0xd0,0x18,0x8d,0x31,0x16,0x1f,0x3d,0xdf,0x4f,0xcf,0x68,0x4f,0xed,0xf9,0x19,0x40,0xa2,0x50,0x75,0xea,0x16,0xa0,0xd1,0x18,0x67,0x9,0xed,0x1b,0xa8,0x57,0xc6,0x8,0x48,0x27,0x41,0x53,0xb5,0x5a,0x68,0xc,0xce,0x3b,0x24,0xc6,0x97,0x77,0xa0,0x1d,0x8a,0xc5,0xbe,0x64,0x55,0x0,0xda,0x59,0x82,0xf7,0x65,0x91,0xde,0x88,0x4a,0x12,0xf2,0x58,0xa8,0x6,0xf8,0x7b,0x7b,0x43,0xaf,0xdb,0x25,0xb7,0xcb,0xe7,0xf5,0xca,0xe5,0xa8,0x98,0xcf,0xee,0xca,0xfb,0x8c,0x6,0xc3,0x77,0xfd,0xcb,0x57,0x37,0xd7,0x3c,0x0,0xb0,0x7,0xe9,0xba,0xfd,0xb,0xce,0x5b,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,0x59,0x0,0x59,0x0,0x59,0xbd,0x9a,0xea,0xaa,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,0x13,0x19,0x21,0xc8,0x5c,0x21,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,0x9a,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x93,0x51,0xa,0xc2,0x30,0xc,0x86,0xff,0x8d,0x6,0x21,0x5,0x7b,0x3,0x1f,0x9a,0x63,0x88,0x78,0x30,0x11,0x6,0x63,0xc7,0xec,0x2e,0x21,0x8d,0x42,0x1e,0xf4,0x75,0xcc,0x6e,0xd8,0x89,0xe0,0xff,0x98,0xf2,0x7d,0x29,0x21,0x69,0x4e,0xc7,0xf3,0x4e,0xa2,0xdc,0x89,0xa8,0x41,0x45,0xcc,0xec,0x99,0xc6,0xb4,0x77,0x12,0xe5,0xa1,0xaa,0xc8,0xaa,0x35,0x3c,0x3c,0x73,0x23,0x51,0x6e,0x2d,0x11,0x55,0xc3,0x0,0x90,0x55,0x41,0x44,0x68,0xab,0xc9,0x59,0x7e,0x2b,0xe8,0x87,0xe,0xfd,0xd0,0x6d,0x13,0x4c,0xc1,0x35,0x49,0x51,0x50,0x2,0x96,0x24,0x6f,0x82,0xb5,0x6e,0xa5,0xb7,0xaf,0x87,0xe8,0xe6,0x85,0xeb,0x65,0xf9,0x7,0xa5,0xfc,0xf9,0x1e,0x7c,0x24,0x30,0x33,0x78,0xe6,0x6a,0xd0,0x33,0xc3,0xcc,0xe0,0xd2,0x98,0x58,0xa2,0xe4,0x10,0xc2,0x96,0x73,0x3e,0xbc,0x0,0x5f,0x36,0x36,0x12,0x78,0xeb,0xb3,0xc5,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+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,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,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
};
static const unsigned char selection_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,0x4e,0x0,0x41,0x0,0x56,0xed,0xd0,0x4e,0x61,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,0xdd,0x9,0x1b,0x13,0x25,0x36,0xd1,0x55,0x4f,0xe9,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,0x76,0x49,0x44,0x41,0x54,0x38,0xcb,0x95,0x92,0xb1,0x6e,0x13,0x41,0x10,0x86,0xbf,0x59,0xd9,0xb2,0x4c,0x68,0x63,0xc2,0x21,0x39,0xb2,0x29,0xa9,0x52,0xb8,0x4b,0x93,0x2,0xa5,0xe,0xd,0x3d,0x1d,0xf,0x0,0x2d,0xa2,0xe5,0x5,0xdc,0xa5,0x4f,0x3,0x35,0xca,0x23,0xa4,0x48,0x95,0x32,0x41,0x58,0xf2,0x81,0x9d,0x22,0x42,0x22,0x36,0xf6,0xed,0xce,0x50,0x9c,0xef,0x6e,0x2f,0x2e,0x38,0x46,0x5a,0x8d,0x76,0x77,0xfe,0x4f,0xb3,0xff,0xac,0x98,0x19,0xfb,0xcf,0x9e,0x9f,0x0,0x6f,0x81,0x97,0x34,0x8b,0x73,0x60,0xfc,0x7d,0x7a,0xfd,0x45,0xfa,0xc9,0xf0,0xdd,0xd3,0x5e,0xf2,0xe9,0xe0,0xc5,0x88,0x64,0x2f,0x69,0xa4,0x4e,0x7f,0xa6,0x5c,0x5e,0x5d,0xf0,0x63,0x9e,0xbe,0x97,0x7e,0x32,0xbc,0x79,0x75,0xfc,0x7a,0xb0,0x5c,0x2d,0x59,0x2e,0xef,0x1b,0x1,0xba,0xdd,0x1d,0xba,0x9d,0x2e,0x9f,0xbf,0x9e,0x7d,0x6b,0x1,0x83,0x5f,0xf7,0x77,0xf8,0xb5,0xa7,0x69,0x2c,0x16,0xbf,0x59,0xfb,0x3f,0x0,0x3,0x7,0xfc,0x97,0xb8,0x88,0x42,0xd3,0x2,0x50,0x55,0x70,0x80,0x92,0xe7,0x22,0x14,0x10,0x1,0xb1,0xea,0x4e,0xeb,0xa0,0x16,0x40,0x50,0x8f,0x98,0x60,0x0,0x59,0x1d,0x62,0x6a,0x88,0x48,0xbe,0x9,0xd1,0xb9,0x59,0xd4,0x81,0x19,0x98,0x61,0xb6,0x29,0xd6,0xaa,0x48,0x44,0xca,0xe2,0x22,0x97,0xc0,0xb2,0x83,0x50,0xa1,0x63,0xc1,0x43,0x71,0x21,0x54,0xd5,0x6d,0x80,0x38,0x87,0x15,0x17,0xb1,0x1f,0x51,0x16,0x1c,0xe6,0xb4,0xf2,0xa7,0x0,0x18,0x8a,0x7a,0x45,0x1c,0x18,0x20,0x9a,0x67,0x7c,0xdd,0x50,0x71,0x5a,0x3d,0x2f,0x6,0x68,0xc8,0xdb,0xd4,0x0,0x52,0x98,0xf,0x28,0x8a,0xc3,0x95,0xe6,0x59,0x6c,0xa2,0x58,0xfc,0x84,0x8d,0xf5,0xe5,0x98,0x14,0x5c,0x3e,0xa,0xbf,0x51,0x9b,0x2a,0x82,0x43,0x6a,0x33,0xce,0x1,0x93,0x2c,0x64,0x7d,0xe7,0x5a,0xb5,0x31,0x11,0xc2,0xd6,0xe7,0xb1,0xa8,0x40,0xd5,0x3,0x4c,0x1c,0x30,0x4e,0x67,0x53,0x7c,0xc8,0x36,0xd4,0x7f,0x2f,0x1f,0x32,0xd2,0xd9,0x14,0x60,0x2c,0x66,0xc6,0xe1,0xe8,0xe8,0xc3,0xfc,0x76,0xf6,0x66,0x95,0xad,0xfa,0x4d,0xbe,0x71,0xa7,0xdd,0x99,0xf4,0x76,0x9f,0x9c,0x3e,0x6a,0x3f,0xfe,0xf8,0x17,0xda,0x44,0xc8,0x77,0x97,0xc9,0xd6,0x18,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,0x15,0x0,0x15,0x0,0x17,0xc8,0x7d,0x47,0xd1,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,0x6,0x14,0x14,0x31,0x1a,0x5f,0x97,0xc4,0x56,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,0xa3,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x93,0xbd,0xa,0xc2,0x40,0x10,0x84,0xbf,0xbb,0x6c,0x72,0x8,0x1,0x51,0x4b,0xdf,0x23,0xc9,0xfb,0x57,0x12,0x9f,0x43,0xb0,0x10,0x2c,0x14,0xe4,0x92,0xcb,0xc5,0x66,0x3,0x36,0x26,0x7,0x69,0x2c,0x9c,0x6e,0x60,0x67,0xf6,0x87,0x1d,0x3,0x14,0xc0,0x6,0x70,0x80,0x25,0xd,0x11,0xf0,0xc0,0x4b,0x54,0x7c,0x4,0x76,0x40,0x9e,0x68,0xd0,0x3,0x77,0xe0,0x22,0xda,0x79,0x3f,0xf4,0x63,0x4b,0xa0,0x56,0x3e,0x7,0x8f,0x70,0xce,0x72,0x53,0x1,0x37,0xd1,0xb1,0x85,0x40,0xc3,0xc8,0xc3,0x47,0xae,0x73,0x6a,0x67,0x29,0x9,0x34,0xaa,0xb3,0x9f,0x3b,0x17,0x3e,0xf2,0x5c,0x9a,0x5d,0x6b,0x8a,0x89,0xa7,0x1e,0xed,0x2b,0xfe,0x6,0xbf,0x66,0xd0,0x39,0x4b,0xb9,0x24,0xd0,0x9a,0x6e,0xe2,0xa2,0xc1,0x8,0x8,0x2d,0x81,0xda,0x65,0x1c,0x12,0x5e,0xf9,0x4,0x54,0x40,0x34,0xc0,0x76,0x4d,0x98,0xcc,0xda,0x38,0xbf,0x1,0xae,0x5a,0x2a,0xba,0xb8,0xa1,0xb8,0x4f,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char selection_oof_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,0x4e,0x0,0x41,0x0,0x56,0xed,0xd0,0x4e,0x61,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,0xdd,0x9,0x1b,0x13,0x1d,0x6,0xe0,0x13,0xc3,0xbe,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,0x6a,0x49,0x44,0x41,0x54,0x38,0xcb,0x95,0x92,0xcf,0x2e,0x3,0x51,0x14,0xc6,0xbf,0xd3,0x4e,0x6a,0x4a,0x48,0xd1,0x96,0x52,0x4d,0xba,0xb0,0x61,0x21,0xb1,0xb1,0xb0,0x25,0x56,0x16,0x5e,0xc1,0xce,0x3,0xb0,0x15,0x3b,0xf1,0x2,0x76,0x5e,0xc1,0xc2,0x4a,0xac,0x3d,0x80,0x85,0x95,0x84,0xa4,0x42,0x94,0x52,0x24,0xfd,0x63,0xfe,0xdc,0xcf,0xe2,0xce,0x9d,0xce,0xb4,0x8d,0x8c,0x93,0x4c,0x4e,0x72,0xee,0x77,0x7e,0xf7,0x3b,0x67,0xae,0x90,0xc4,0x5c,0x71,0x61,0x7,0xc0,0x1e,0x80,0x4d,0x24,0x8b,0x2b,0x0,0xa7,0xcf,0xaf,0x8f,0xe7,0x52,0x2a,0x94,0xf7,0xb,0x93,0x33,0x27,0xcb,0x8b,0x2b,0x98,0x9d,0x9e,0x4f,0xd4,0xfd,0xf2,0xfe,0x84,0xdb,0xbb,0x1b,0xbc,0x35,0xeb,0x7,0x52,0x2a,0x94,0xef,0xb7,0xd6,0xb7,0xab,0x5d,0xa7,0x8b,0x4e,0xb7,0x9d,0x8,0x90,0xb5,0x47,0x61,0x67,0x6c,0x5c,0x5e,0x5f,0x3c,0x58,0x0,0xaa,0xdf,0xad,0x2f,0x78,0x9e,0x87,0xa4,0xd1,0xee,0xb4,0xe0,0xb8,0x3f,0x0,0x50,0x4d,0x1,0xf8,0x57,0xb3,0x9,0xd3,0x63,0x1,0x80,0x52,0xa,0x10,0x0,0x84,0xce,0x26,0x8,0x5d,0x10,0xf6,0xce,0x18,0x7,0x5,0x0,0x1f,0x22,0xa2,0xcf,0x54,0x1f,0x4,0x4,0x28,0x11,0x60,0x8c,0x1e,0x0,0x48,0x80,0xec,0x59,0x60,0x54,0x14,0xbd,0xd6,0x64,0x19,0x74,0x10,0x86,0x48,0x0,0x33,0x3a,0x3,0x64,0x7c,0x9c,0x38,0x40,0x85,0x8d,0xc,0x18,0xc6,0xb9,0xc4,0x4c,0x98,0x42,0xcf,0x4c,0x30,0x82,0xa,0x67,0x27,0x22,0x3b,0x53,0x3a,0xf,0x82,0xfa,0x1,0x4a,0xe9,0x1a,0xb5,0xc6,0xec,0x51,0x81,0x90,0x80,0xca,0xfe,0x25,0xca,0xc0,0xe,0x44,0x3b,0x8,0x94,0x14,0xad,0x50,0xa6,0x8b,0xda,0x82,0xc,0xf9,0xb,0x35,0xd7,0x77,0x2b,0xe9,0x94,0x15,0xbf,0x81,0x1c,0xf2,0x7c,0x18,0x4a,0x7c,0xe5,0x1,0x40,0x2d,0x3d,0x3e,0x36,0x61,0xbb,0x9e,0xb3,0x61,0x8f,0x64,0x21,0x29,0x33,0xe4,0xdf,0x9f,0xef,0x7b,0x68,0x34,0xeb,0x70,0x3d,0xf7,0x58,0x48,0x62,0x75,0x69,0xed,0xf0,0xe3,0xb3,0xb1,0xeb,0x78,0x4e,0x25,0xc9,0x33,0xce,0x58,0x99,0xda,0x54,0x2e,0x7f,0x96,0xcf,0x15,0x8f,0x7e,0x1,0x52,0xd8,0xb3,0xdb,0x19,0xc1,0x3b,0xf1,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,0x15,0x0,0x15,0x0,0x17,0xc8,0x7d,0x47,0xd1,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,0x6,0x14,0x14,0x32,0x15,0xe4,0x5,0x8a,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,0xa5,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0xd3,0x41,0x6a,0x2,0x51,0x10,0x4,0xd0,0xf7,0xe7,0xff,0xc1,0x30,0x4,0xe2,0x5a,0x18,0x4f,0x10,0x2,0x9e,0x29,0xe7,0xca,0x99,0x4,0xc9,0xda,0xcd,0x5c,0x20,0x8b,0x20,0x8a,0xfe,0x8c,0x9b,0x76,0xeb,0x8,0xb3,0xc9,0xc2,0x82,0xde,0x34,0x55,0xd5,0x34,0x54,0x25,0x74,0x58,0xe2,0x15,0x19,0xc9,0x7d,0x8c,0xa8,0xf8,0xc5,0x4f,0x9,0xf1,0x7,0x7a,0xbc,0x3c,0x68,0x70,0xc4,0x80,0x5d,0x89,0xcb,0x6b,0xef,0xcd,0x57,0xdd,0xd6,0x1e,0xed,0x84,0xc1,0x39,0x6f,0xf2,0xe0,0xfb,0xef,0x13,0xfb,0x82,0x82,0x45,0x88,0xf,0x31,0xf7,0xd0,0xd5,0x6d,0xed,0x73,0x9b,0x16,0x28,0x4d,0x2c,0x53,0x5c,0x9e,0x12,0xb,0x4e,0x7b,0x7b,0xb5,0x31,0x13,0x4f,0x83,0xff,0x64,0x30,0xe2,0x1c,0xbd,0x98,0x42,0x17,0xdc,0x51,0xa4,0xf0,0x82,0x53,0xde,0xe4,0x21,0xd2,0xf8,0xf6,0x50,0x94,0x39,0xe1,0x92,0xb0,0x9a,0x53,0xa6,0x34,0xb7,0xce,0x57,0x8f,0xdf,0x31,0x5b,0x17,0xde,0x59,0x7e,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -330,7 +380,7 @@ static const unsigned char spinbox_updown_png[]={
static const unsigned char submenu_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,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xdb,0x4,0x1b,0x16,0x1b,0x32,0xbf,0xff,0x75,0xca,0x0,0x0,0x0,0x3a,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0x80,0x82,0x73,0x2f,0x5e,0xdd,0x3b,0xf7,0xe2,0xd5,0x3d,0x6,0x34,0xc0,0x84,0x2e,0x80,0xae,0x8,0x43,0x1,0xba,0x22,0xac,0xa,0x90,0x15,0xe1,0x54,0x40,0xd0,0x4,0x23,0x9,0x31,0x25,0x9c,0xa,0x60,0x92,0x58,0x15,0x20,0x4b,0x32,0x30,0x30,0x30,0x0,0x0,0x56,0x5a,0x13,0xb,0xf,0x58,0x99,0x10,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,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,0x12,0x38,0x2b,0x92,0xa,0x47,0xe3,0x0,0x0,0x0,0x3a,0x49,0x44,0x41,0x54,0x18,0x95,0x63,0x60,0x80,0x82,0x3b,0x77,0xee,0xdc,0xbb,0x73,0xe7,0xce,0x3d,0x6,0x34,0xc0,0x84,0x2e,0x80,0xae,0x8,0x43,0x1,0xba,0x22,0xac,0xa,0x90,0x15,0xe1,0x54,0x40,0xd0,0x4,0x15,0x15,0x15,0x25,0x9c,0xa,0x60,0x92,0x58,0x15,0x20,0x4b,0x32,0x30,0x30,0x30,0x0,0x0,0x2c,0x62,0x12,0xf3,0xa8,0xc4,0xd,0xa6,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -340,27 +390,37 @@ 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,0x4f,0x0,0x42,0x0,0x57,0xa5,0xf1,0xe9,0x1e,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,0xdd,0x9,0x1b,0x10,0x25,0x6,0xf5,0xca,0xc1,0x1c,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,0xcb,0xa5,0x90,0x31,0x4e,0xc3,0x40,0x14,0x44,0xdf,0x97,0x82,0x2,0x45,0x64,0xc7,0xc8,0x29,0x28,0x90,0x2c,0x51,0xd0,0xd1,0xd3,0x50,0x71,0x0,0x8e,0xc1,0x1,0xe0,0x10,0x5c,0x80,0x63,0x70,0x0,0x2a,0x1a,0x7a,0x3a,0xa,0x4,0x12,0x5,0x45,0x24,0x14,0x4b,0xa0,0x4,0xb,0xb1,0x43,0xb1,0xbb,0x5e,0x3b,0x69,0x42,0xf8,0xc5,0xea,0xef,0xff,0x3b,0xb3,0x33,0x63,0x92,0xd8,0xcd,0x27,0x6c,0x52,0xef,0xf5,0x14,0x2b,0xb2,0x92,0x7c,0x34,0xe6,0x60,0xff,0x90,0x49,0xbe,0xb7,0x16,0x70,0x5a,0xbf,0xf1,0xf4,0xfa,0x48,0xfd,0x31,0xf3,0x4,0xc0,0x19,0x70,0xe,0x9c,0xae,0xf9,0xf9,0x2d,0x70,0xd,0xdc,0x58,0x91,0x95,0x17,0xf9,0x68,0x7c,0xb5,0xa1,0x82,0x4b,0x2b,0xb2,0xf2,0xf9,0xf8,0xe8,0xa4,0x6a,0xbe,0x1b,0xbe,0x9a,0xc5,0x5a,0x4,0xdb,0xc3,0x1d,0x86,0x5b,0x43,0xee,0x1f,0xee,0x5e,0x6,0x40,0x55,0x7f,0xce,0xfe,0x14,0xde,0xa2,0x99,0xb3,0x68,0xe6,0x0,0xd5,0x0,0x40,0xa,0x87,0x1,0x18,0x26,0x21,0x0,0x33,0x8f,0x90,0x30,0x40,0x66,0x80,0x40,0x69,0x37,0x0,0x70,0xee,0xc7,0x63,0x5,0x58,0x20,0x8c,0xf7,0xe5,0x56,0x2d,0x67,0x22,0x0,0xe1,0xc2,0xd2,0xd4,0xc3,0xf5,0xaa,0xdd,0x59,0x10,0x9b,0x14,0x4,0x64,0x64,0x8e,0x52,0xfb,0x70,0x14,0x6d,0xa,0xa4,0x8e,0x5,0xe1,0xda,0xdf,0xbd,0x5,0xd1,0xa5,0xf0,0xbd,0x9f,0xe1,0x40,0x96,0xbc,0x78,0x5,0xd2,0x8a,0x74,0x61,0xc9,0x6f,0x0,0x28,0xe2,0x14,0x67,0x51,0x81,0x53,0xfb,0xd0,0x5c,0x90,0xb1,0xca,0xe8,0x49,0xcc,0xfc,0xaa,0x1b,0xa2,0x70,0xed,0x40,0xf1,0x8c,0x69,0x75,0x23,0xf,0xbd,0x94,0x56,0x3d,0x5,0xcb,0xd1,0x99,0xd4,0xb1,0xd0,0xc9,0x43,0xe9,0xa1,0x15,0x59,0x29,0xfe,0x51,0xbf,0xb4,0x87,0x9c,0x22,0x50,0x2e,0x97,0xaa,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_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,0x20,0x8,0x6,0x0,0x0,0x0,0x1b,0x89,0xf8,0xcc,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4b,0x0,0x3f,0x0,0x52,0x7c,0x32,0x40,0x52,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,0xdd,0x9,0x1b,0x10,0x1b,0x28,0x68,0xd9,0xd7,0xae,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,0xf3,0x49,0x44,0x41,0x54,0x48,0xc7,0xcd,0x95,0xbf,0x6e,0xd4,0x40,0x10,0xc6,0x7f,0x63,0xfb,0xfe,0x8,0x44,0x4,0x97,0x44,0xd0,0x50,0x20,0xa,0xd2,0x10,0xf2,0x4,0xe4,0x29,0x28,0x52,0xf1,0x24,0x5c,0x3,0x2f,0x42,0x1b,0xde,0x82,0x37,0x40,0x54,0x14,0x88,0x2,0x9,0xe,0x2e,0x98,0x88,0xd3,0x29,0x77,0x67,0xef,0xc,0x45,0x76,0xcd,0xda,0xb1,0x7d,0xa0,0x34,0x8c,0xb4,0xb2,0xc7,0x9e,0xef,0x9b,0x6f,0x67,0xd6,0x1e,0x1,0xc4,0xaf,0x4,0x48,0xfd,0x12,0x2e,0x2d,0x5c,0x2d,0xba,0x3a,0xbf,0x14,0xb0,0xcc,0x7,0xa5,0xc0,0x10,0x18,0x1,0x83,0x88,0x24,0x26,0x8,0xe0,0x2,0x58,0x3,0x1b,0xc0,0x65,0x3e,0xf3,0x10,0xb8,0xf1,0xe0,0xfe,0xc3,0x37,0xab,0xf5,0xfa,0x69,0x4,0x6c,0x9a,0x8d,0x47,0xa3,0xb7,0x9f,0x3e,0x7f,0x7c,0xe6,0xfd,0x75,0x16,0xb2,0xef,0x4f,0xee,0x4d,0x6f,0xef,0x4c,0x8e,0x1f,0x3f,0x7a,0xc2,0xce,0xad,0x3b,0xad,0xe8,0x5f,0x8b,0x9f,0xf2,0xfe,0xc3,0xbb,0xe3,0xfd,0xc9,0x72,0x3a,0xcf,0x67,0x53,0xa0,0xc,0xa,0x6,0x69,0x9a,0x9e,0x1c,0x1e,0x1c,0xb1,0x58,0x2e,0xf8,0x71,0x7e,0xd6,0x4a,0x30,0x1a,0x8e,0x39,0x3c,0x38,0xe2,0xeb,0xf7,0x2f,0x27,0xc0,0x2b,0x60,0x15,0x6a,0x90,0x89,0xc8,0x6e,0x7e,0x9e,0xe3,0xb4,0xa4,0xcb,0x56,0xeb,0xb,0x8a,0xa2,0x40,0x44,0x76,0xbd,0xf2,0x24,0x8b,0x8b,0x55,0xb8,0xa2,0xb6,0x79,0x6b,0xb4,0x22,0xc4,0xc4,0x8f,0x6b,0x4,0x98,0x55,0x20,0x5a,0x88,0x1a,0x26,0x80,0x64,0xb5,0x40,0xf3,0xa1,0x22,0xe1,0x41,0xbb,0x1f,0x59,0x76,0x25,0x93,0x59,0x15,0x28,0x1e,0x68,0xaa,0x51,0x5e,0xe9,0x21,0x8,0xe0,0x0,0x44,0xeb,0x55,0xd8,0xaa,0x40,0x15,0x11,0xf9,0x93,0xb1,0x92,0xae,0x95,0xa2,0x9a,0x9a,0x26,0x41,0x50,0x61,0xe2,0xb7,0xe0,0x13,0x5a,0x75,0x43,0xbf,0x2,0xd,0x12,0xd5,0xea,0xca,0xbd,0x6f,0xb2,0x85,0x20,0x74,0x41,0x9a,0x5d,0xe9,0xf0,0x5b,0xb6,0xa0,0x98,0x49,0x24,0xd9,0x53,0x45,0xbe,0x88,0xf5,0x15,0x11,0x10,0x5,0xd,0x5d,0xa8,0xd7,0x2,0x51,0x4c,0xb7,0xb5,0x51,0x62,0x44,0x4b,0xed,0xac,0x4f,0x1,0x5a,0xaf,0x54,0xe8,0x58,0xd2,0x7d,0xb0,0xdb,0x4f,0x22,0x1d,0x3f,0x34,0xfe,0xb2,0xb,0xff,0x62,0x9,0xd7,0xb4,0xff,0x83,0xc0,0xfa,0xcb,0xd4,0x69,0x6,0xd8,0x75,0x9,0x2a,0x5,0xa5,0x99,0xcd,0x9d,0x73,0x5b,0x51,0xce,0x39,0xcc,0x6c,0xe,0x94,0x80,0x26,0xfe,0xb8,0x14,0x65,0x59,0x9e,0xce,0xf3,0x19,0x7d,0x24,0xce,0x39,0xe6,0xf9,0x8c,0xb2,0x2c,0x4f,0xfd,0x84,0x52,0xf1,0x67,0x61,0x8,0xdc,0xdc,0x9b,0xdc,0x7d,0x99,0x26,0xe9,0xf3,0x24,0x49,0xc6,0x6d,0x4,0xaa,0xba,0x72,0xea,0x5e,0x9f,0xe5,0xdf,0x5e,0x0,0x4b,0x60,0x13,0xf,0xd5,0x81,0x9f,0x8d,0xc3,0x2d,0xb3,0x71,0xe3,0x67,0x63,0x1,0x38,0xe9,0x99,0xce,0x6d,0x23,0x42,0xfd,0xba,0x32,0x9d,0xe3,0xcf,0xc7,0x1a,0x59,0x9b,0x5f,0x83,0xc5,0xef,0x7e,0x3,0xcb,0x7b,0xfd,0x30,0x11,0x50,0x3,0x75,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,0x4f,0x0,0x42,0x0,0x57,0xa5,0xf1,0xe9,0x1e,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,0xdd,0x9,0x1b,0x10,0x28,0x1b,0x23,0x62,0xd3,0x88,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,0x4a,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x92,0x31,0x4a,0x3,0x51,0x14,0x45,0xcf,0x1b,0x82,0x4,0x5b,0x65,0x24,0x24,0x44,0x52,0xd9,0x9,0xae,0xc0,0xca,0xca,0x2a,0xcb,0x70,0x1,0xba,0x8,0x37,0xe0,0x32,0x52,0x59,0x59,0xb9,0x2,0xc1,0xce,0x46,0x11,0x2,0x41,0x31,0x85,0xc5,0x24,0x41,0x98,0x77,0x2d,0xfe,0x9f,0x9f,0x2f,0x93,0x62,0xc0,0xc7,0x14,0x7f,0xe6,0xde,0x77,0xdf,0xbd,0x6f,0xbe,0x49,0x62,0x74,0x74,0x3c,0x5,0xae,0x80,0xb,0xba,0xd5,0x3,0x70,0x37,0xff,0x78,0x9f,0xd9,0xb0,0x1c,0x5f,0x97,0x7,0x83,0xdb,0xd3,0x93,0x33,0x6,0x87,0xa3,0x4e,0xdd,0x8b,0xaf,0x39,0xcf,0x2f,0x4f,0x7c,0x2e,0x17,0x37,0x36,0x2c,0xc7,0xaf,0x97,0xe7,0xd3,0xc9,0xe6,0x67,0xc3,0x6a,0xb3,0xea,0x24,0xb0,0xdf,0xdf,0xa7,0xbf,0xd7,0xe7,0xfe,0x71,0xf6,0xd6,0x3,0x26,0xcb,0xef,0xe5,0xe,0x9a,0x10,0x6,0x80,0x21,0x88,0x67,0x80,0x6a,0x5d,0x51,0xad,0x2b,0x80,0x49,0xf,0xc0,0x25,0x70,0x41,0x11,0xe8,0xe6,0x42,0x10,0xdf,0x41,0x2e,0xc,0xa1,0xc2,0x0,0x81,0x3,0x45,0x10,0xc,0x2,0x75,0x1d,0xf4,0xeb,0x30,0x48,0x8a,0xa3,0xea,0xdc,0xf,0xa1,0x31,0x62,0x8a,0x58,0xaf,0x81,0x3d,0xb2,0x4c,0x89,0xd3,0xaa,0x84,0xd9,0x36,0x50,0x74,0xe0,0x1,0x25,0x24,0xc1,0x2c,0xe6,0xce,0x1d,0x4,0x6b,0x16,0x53,0x48,0x79,0x4,0x3c,0x4d,0xf,0x3c,0x6d,0x6d,0xc7,0xf5,0x35,0x2b,0x95,0x43,0xe8,0x55,0x26,0x20,0x6f,0x59,0xf,0x13,0xe3,0xd9,0x9a,0xbf,0x12,0xfb,0xd4,0x7c,0x8b,0x2,0x72,0x25,0xa2,0x79,0xb4,0xd1,0x56,0xc,0x22,0x66,0x1,0x52,0x2e,0x20,0xc7,0x5,0x96,0x86,0x2a,0x3e,0xf1,0x1e,0x28,0x53,0x92,0x12,0x77,0x1b,0xc1,0x95,0x5d,0x9e,0xb4,0xf3,0xd4,0xe8,0x59,0x66,0x23,0x2c,0xf0,0x8f,0x3,0xc7,0x91,0xda,0x37,0x71,0xd7,0xb1,0x71,0xd1,0x38,0x28,0x12,0x6e,0x74,0x2f,0xcb,0xfe,0xd0,0xb0,0x1c,0x8b,0x7f,0xd4,0x2f,0xdd,0x10,0xa9,0xd4,0xe9,0xbe,0xe5,0x86,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
+};
+
+
+static const unsigned char tab_menu_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,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x6,0xd,0x3,0x2c,0x7,0xf7,0x85,0x69,0x73,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,0x54,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x92,0xb1,0xd,0xc0,0x20,0x10,0x3,0x8f,0xec,0x63,0x65,0xff,0x2d,0x40,0x1e,0xe8,0xd3,0x50,0x24,0xd1,0x83,0x48,0x97,0x2,0xb7,0xb6,0x4f,0xd6,0xeb,0x61,0xeb,0x67,0xb2,0x5d,0xbe,0x66,0x4a,0x12,0x88,0x19,0x40,0xd2,0xa3,0x73,0x24,0x99,0x6,0x64,0x90,0xe8,0x1e,0xd3,0x5,0x7d,0x45,0x3,0x74,0xf3,0x3,0xb0,0xa4,0x73,0x9,0xf0,0x82,0x30,0x2a,0xaf,0x1c,0xb5,0xda,0xae,0xfb,0xbd,0xe6,0xba,0x0,0x22,0x30,0x1e,0x2c,0xd7,0x21,0xa8,0x0,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char tab_menu_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,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,0x6,0xd,0x3,0x2c,0x15,0x4,0x3c,0x18,0x3b,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,0x58,0x49,0x44,0x41,0x54,0x38,0xcb,0x63,0x60,0x18,0x5,0x83,0xc,0xbc,0x7c,0xf9,0x92,0x91,0x54,0x35,0x8c,0x58,0x14,0xfc,0xc7,0x67,0x80,0xb8,0xb8,0x38,0x8a,0x1e,0x26,0x2c,0x6a,0x2e,0x32,0x30,0x30,0x60,0x33,0xe4,0x3f,0x54,0x8e,0x1,0xaf,0xb,0xa0,0xae,0xb8,0xc8,0xc0,0xc0,0xa0,0x8b,0x24,0xff,0x9f,0x81,0x81,0xe1,0xb2,0xb8,0xb8,0xb8,0x3e,0x51,0x6,0xa0,0x19,0xc2,0x80,0x4b,0x33,0x31,0x81,0x7a,0xe1,0xe5,0xcb,0x97,0x17,0x46,0x93,0x17,0x7e,0x0,0x0,0xa,0x9a,0x1f,0x34,0xff,0x99,0xf7,0x75,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
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,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,0xdd,0x9,0x17,0x5,0xb,0x18,0x54,0xf9,0x2b,0x70,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,0x6,0xd4,0x49,0x44,0x41,0x54,0x68,0xde,0xed,0x98,0x5d,0x8c,0x55,0x67,0x15,0x86,0x9f,0xf5,0xed,0xbd,0xcf,0xef,0x9c,0x33,0xce,0x3f,0xc3,0x88,0x14,0xa1,0x88,0x5a,0x63,0x8d,0xe5,0xce,0x26,0x6a,0x1a,0xef,0x1a,0xb5,0xa,0x5c,0x18,0xf4,0xc2,0x68,0x6c,0x2a,0xc4,0xc4,0x14,0xe4,0xaa,0x29,0x51,0xd3,0xb,0xb5,0x4d,0x40,0xaa,0x16,0x2f,0x8c,0x97,0xd4,0x68,0x62,0x62,0xac,0x26,0x46,0x6d,0xc7,0x26,0x25,0x1,0x2b,0x43,0xab,0x29,0xc8,0xcc,0x0,0x33,0x40,0x99,0x99,0xce,0xdf,0x39,0x67,0xe6,0xec,0x6f,0x2d,0x2f,0xf6,0x3e,0x87,0x19,0x60,0x60,0xfe,0xee,0x9c,0x95,0xec,0xe4,0x64,0xef,0x9c,0x6f,0x7f,0xfb,0x5d,0xef,0xfb,0xae,0xb5,0x3e,0xd8,0x88,0x8d,0xd8,0x88,0x8d,0xf8,0x3f,0xe,0x59,0xea,0x41,0x67,0x67,0x57,0x6b,0x47,0x5b,0xd7,0xd1,0x6c,0x36,0xfb,0x94,0x13,0x9,0x40,0xb0,0x35,0xbc,0xc8,0x1,0x5e,0x3d,0xd5,0x5a,0x15,0xef,0x3d,0x22,0xe9,0xab,0xcd,0xd6,0xe9,0x4b,0x24,0x5d,0xce,0x10,0xc0,0x4,0xf,0x5c,0xc0,0x78,0x1e,0xb3,0x5f,0xfd,0x77,0xe8,0x62,0x6d,0xd9,0x0,0x74,0x77,0x76,0xb7,0xf7,0xf4,0x6c,0x7e,0xe3,0xa1,0xf,0x7f,0x7c,0x7b,0xdf,0xa6,0x2d,0x1a,0x4,0x81,0x53,0x5d,0xe3,0xfe,0x9c,0xa0,0xbe,0xce,0xb5,0x9b,0xd7,0x38,0x37,0x70,0x86,0xb8,0x3e,0x7f,0xb,0x84,0x75,0x8,0x4b,0x3f,0x46,0x53,0x40,0xcd,0x14,0x33,0xc3,0xab,0xa2,0x5e,0x7f,0xaf,0x6a,0xfb,0x2e,0xd,0x5f,0xac,0xde,0xfe,0xbf,0xf0,0x6e,0x8b,0xb5,0xb5,0x75,0xbc,0xf0,0x91,0x5d,0x1f,0xdb,0x5e,0x88,0xca,0xb3,0x3,0x3,0x3,0x45,0x1f,0x2b,0x26,0xc6,0x6a,0x29,0x20,0x92,0x24,0x3a,0xc,0x43,0x36,0xf7,0x6e,0x66,0xd7,0xce,0x87,0x18,0x78,0xeb,0x2c,0xe2,0x1c,0xd6,0xdc,0xfa,0x1a,0x69,0x6c,0xa,0x6,0x4e,0x4,0x35,0x43,0x10,0x10,0xd1,0x30,0x90,0x99,0x18,0x1e,0x37,0xf4,0x49,0xe0,0x27,0xcb,0x2,0x20,0x8a,0xb2,0xfb,0x3b,0xca,0x5d,0x7a,0xe1,0x9d,0xb,0xc5,0x42,0xb1,0x8,0xd9,0xf5,0x4b,0xd3,0x95,0x2b,0x57,0xf8,0xe0,0xf6,0x6d,0xb8,0x20,0x24,0x10,0x41,0x4d,0xd7,0x85,0x9,0x66,0x1,0x90,0x80,0x80,0x25,0x74,0x55,0x55,0x67,0x4a,0x29,0x8,0x2,0xf3,0x5e,0xbf,0xbb,0x6c,0x0,0x4c,0xd5,0x2a,0x95,0xaa,0x73,0xa1,0x43,0x53,0x2a,0xb1,0x26,0x7,0x90,0x26,0x13,0x5c,0x20,0xd4,0xaa,0x35,0x7c,0xec,0x9,0x73,0x11,0xe2,0xa5,0x9,0x80,0x99,0x21,0x69,0x6,0x4d,0x93,0xf7,0x3a,0xe7,0x70,0xce,0x61,0x66,0xcd,0x2b,0x11,0x39,0xcd,0xfb,0x89,0x8f,0x24,0x60,0x3a,0xe7,0x70,0x12,0x60,0xd,0x60,0x1d,0x22,0xc9,0xd6,0x7b,0xef,0xb6,0xb3,0xbb,0x3,0x80,0x89,0x6a,0x8c,0xaa,0xa2,0xea,0xd3,0xcd,0xaf,0x3e,0x4b,0x6a,0x1e,0x2c,0x59,0xc3,0xcc,0x50,0xef,0x31,0x8c,0x40,0x1c,0x38,0x43,0x24,0x91,0x42,0x80,0xc3,0x7b,0x4f,0x4b,0xa1,0x40,0xa9,0x54,0x42,0x44,0x98,0x9d,0x9d,0x65,0x6a,0x7a,0x8a,0x28,0x8a,0x28,0x16,0x8a,0x4,0x41,0xd8,0x4,0x6a,0x72,0xf2,0x3d,0xf2,0xf9,0x2,0xb9,0x6c,0x86,0x58,0xd,0x11,0xa8,0x54,0x66,0xa9,0x56,0x6b,0x38,0x9,0x20,0x0,0xf5,0xda,0x10,0x99,0x2c,0x1b,0x80,0x84,0x3e,0xb6,0x8,0x75,0xf5,0xa9,0xf,0xac,0x82,0xf6,0x41,0x10,0x34,0x7f,0xab,0x6a,0x6a,0x54,0x86,0x10,0x20,0x2,0x92,0x28,0x16,0x55,0x25,0x9f,0x2f,0x72,0xe3,0xdd,0x1b,0xfc,0xe3,0x8d,0xd7,0x1,0xe3,0xfd,0xbd,0x5b,0xd8,0xfa,0x81,0xad,0x4c,0x4f,0x4d,0x33,0x3c,0xf4,0x36,0x95,0x6a,0x25,0x65,0x89,0xf2,0xe0,0xf6,0xf,0x31,0x38,0x3c,0xc8,0xf8,0xf8,0x18,0x61,0x18,0x52,0xaf,0x7b,0x7a,0x37,0x6d,0xa2,0xad,0xad,0x8d,0x7a,0xbd,0x9e,0xac,0x9b,0xae,0x7f,0xaf,0xea,0xb4,0x64,0xd6,0x14,0x8f,0x99,0x7,0x31,0xca,0xad,0x65,0x5a,0xcb,0xad,0x2b,0xbe,0xda,0xda,0xde,0x87,0xb,0x4,0xc3,0x63,0x28,0x8a,0x4f,0x19,0x91,0x50,0xdf,0x89,0x43,0x24,0xf9,0x5d,0xc8,0x17,0x18,0xbd,0x36,0xc2,0x93,0xdf,0xfe,0x56,0xd3,0xc5,0x8f,0xbf,0x78,0x8c,0xab,0x23,0x57,0xd9,0xd4,0xbb,0x89,0x53,0xbf,0x3d,0xc5,0x9b,0xe7,0xdf,0xe4,0xf4,0x99,0xd3,0x9c,0x3b,0x7f,0x8e,0x72,0x6b,0x89,0x67,0x9e,0x7d,0x86,0xc1,0xcb,0x83,0xbc,0xda,0xff,0x2a,0x6f,0xfd,0x7b,0x80,0x2f,0x7c,0xf1,0xf3,0xcc,0xcc,0xcc,0x90,0xcd,0x64,0x52,0xf1,0xb9,0x44,0x7b,0x4b,0x30,0x38,0x5c,0xc2,0x51,0x1a,0xe5,0x3,0x1f,0x18,0xaa,0x31,0x97,0xaf,0xe,0xae,0xd8,0x5,0x4,0x41,0x55,0x29,0x16,0x5b,0x88,0xc2,0x8,0xcc,0xa3,0xaa,0xc4,0xea,0x53,0x11,0x3,0xde,0x40,0x84,0x28,0x8a,0x18,0x1a,0x1e,0xe4,0xc0,0x77,0xe,0x70,0xf0,0xe0,0x41,0xbe,0xf4,0xc4,0x1e,0xa6,0xa7,0xa6,0x78,0xe9,0xe4,0x2f,0x78,0xe1,0xd8,0xf3,0x1c,0x39,0x74,0x84,0x47,0x3e,0xf9,0x8,0x47,0x9f,0x3d,0xca,0xc4,0xc4,0x4,0xce,0x39,0xe6,0xe7,0xe6,0xd9,0xdc,0xbb,0x99,0xf3,0xe7,0x6,0xf8,0xf9,0xcf,0x5e,0x22,0x97,0xcf,0x31,0x3e,0x36,0x41,0x14,0x45,0x78,0x6b,0x10,0xdf,0xb8,0x17,0x71,0xc3,0xa5,0x68,0xab,0xaa,0x49,0xc6,0xcc,0x23,0xe,0xba,0xba,0x7a,0x56,0x45,0x7f,0x71,0xc2,0x5c,0xad,0x86,0xf7,0x9a,0x96,0xc3,0x86,0xc1,0xa5,0x89,0x71,0x49,0xf6,0xe7,0xe7,0xe7,0x68,0x29,0xb5,0xb0,0x77,0xef,0x1e,0x8e,0x1f,0xfb,0x29,0xff,0x3a,0xfb,0x4f,0xa,0xc5,0x22,0x87,0x9e,0x3e,0xcc,0x89,0x17,0x8f,0xb3,0x63,0xc7,0xe,0x26,0xa7,0x26,0xc9,0x44,0x11,0xf9,0x7c,0x9e,0xa1,0xa1,0x61,0xe6,0xe6,0xe7,0x10,0xc0,0xb9,0x80,0x28,0xc,0x29,0x95,0x5a,0x78,0xed,0xaf,0xfd,0x74,0x75,0x77,0x50,0xad,0xd5,0x8,0xc4,0x11,0x37,0x4c,0x73,0x25,0x0,0x58,0x43,0x2,0x9a,0x6c,0x56,0x81,0x5a,0xad,0xb2,0xea,0x7a,0xad,0x3e,0xad,0x24,0x22,0xa9,0x7,0xf8,0xe6,0x8b,0x9a,0xd,0x8c,0x2a,0xb9,0x5c,0x8e,0x28,0x13,0x31,0x72,0x75,0x84,0xee,0x9e,0x1e,0x9c,0x73,0x54,0xab,0x35,0xf2,0x85,0x3c,0x85,0x62,0x91,0xd9,0xd9,0xa,0x7b,0xf6,0xed,0x23,0x8e,0x63,0xce,0x9c,0x39,0xc3,0x89,0x63,0x27,0xf0,0xde,0xf3,0xf0,0x27,0x1e,0x66,0xff,0xd7,0xbe,0x4a,0x5f,0x5f,0x1f,0xaf,0xfc,0xe1,0xcf,0x4,0x41,0x98,0x76,0x83,0xd6,0x64,0x80,0xac,0x18,0x0,0x55,0xcc,0x14,0x4d,0xaf,0xd9,0x4a,0x6d,0x55,0xc5,0x4f,0x4d,0xc9,0x65,0xf3,0x38,0xe7,0x10,0x24,0x59,0x53,0xd,0x93,0x85,0x8a,0x33,0x32,0x99,0xc,0xa3,0xa3,0xa3,0x5c,0xb9,0x7c,0x85,0xc7,0x3e,0xf7,0x18,0x27,0x4f,0x9e,0x24,0x74,0x21,0x87,0x8e,0x3c,0xcd,0xf5,0xeb,0x37,0x18,0x1e,0x1e,0xa2,0xbd,0xbd,0x8d,0xaf,0x3c,0x75,0x80,0x9b,0xef,0xde,0x24,0xf6,0x31,0x81,0xb,0x70,0xce,0xf1,0xf2,0xa9,0xdf,0xf0,0xdc,0xf,0x9f,0x23,0x9b,0xc9,0x52,0x2e,0x97,0xa9,0x54,0x2a,0xcd,0x8a,0x73,0xbf,0x8,0x97,0xe2,0xae,0xa9,0xc7,0xab,0xc7,0xa9,0xc3,0x89,0xd0,0xdd,0xd9,0x85,0x89,0xac,0xa0,0x1f,0x48,0xda,0xbf,0x20,0x70,0x4c,0x4f,0x4f,0x13,0xc7,0x1e,0x91,0x64,0x1e,0xb0,0x86,0x7,0xdc,0xe6,0x17,0xad,0xad,0xad,0x7c,0xff,0xe8,0xf,0x78,0xf9,0x77,0xa7,0xf8,0x7b,0xff,0xdf,0x98,0x18,0x1b,0xe7,0x53,0x8f,0x3e,0xca,0x37,0xbe,0xfe,0x4d,0xcc,0x1b,0xed,0xed,0xed,0xe4,0xb2,0x39,0x72,0xb9,0x1c,0xd5,0x6a,0x15,0xe7,0x1c,0x3d,0x3d,0x3d,0x89,0x87,0x64,0x32,0x64,0x32,0xd9,0x66,0xc9,0x36,0x6b,0x34,0x45,0xf7,0xde,0xf3,0x5d,0x99,0xb1,0x6b,0xe7,0x47,0x6d,0xe7,0xb6,0x5d,0xdc,0x18,0xbb,0x41,0x26,0xca,0x60,0x6a,0xcc,0xc5,0xb5,0x55,0xf5,0x42,0x66,0x46,0x36,0xca,0x25,0x5a,0x47,0x98,0xaf,0xcf,0xd3,0xd3,0xd9,0xcd,0x7f,0x2e,0xbd,0x4d,0x6b,0xa9,0x8c,0xda,0xad,0x21,0xc3,0x39,0xa1,0x5e,0x8f,0xe9,0xec,0xec,0x64,0xf7,0xee,0xdd,0xb4,0xb4,0xb4,0xd0,0xdf,0xff,0x1a,0x23,0x23,0xa3,0x44,0x99,0x88,0xbe,0xbe,0x3e,0x46,0x47,0x46,0x51,0x4d,0xe4,0x99,0xc,0x6d,0x1d,0x78,0xaf,0x8c,0xdd,0x1c,0x6f,0x66,0xdd,0x50,0x4c,0xd,0x53,0xf0,0x16,0x83,0x41,0xa5,0x56,0xe5,0xe2,0xa5,0x77,0x64,0xd9,0xc,0x50,0x8b,0x11,0x34,0x69,0x2f,0xc5,0xc8,0x65,0xb2,0xf7,0xac,0xa7,0xf7,0x82,0x58,0x55,0x13,0x56,0x25,0x8e,0x80,0x27,0x4e,0x8d,0xd6,0x50,0xbd,0x55,0xa1,0xbc,0x1a,0x4e,0x2,0xa6,0xa7,0x66,0x78,0xe5,0x8f,0x7f,0x6a,0x4a,0x23,0x70,0x21,0xbe,0xae,0x8c,0x5e,0xbd,0x4e,0x1c,0xfb,0x45,0xd4,0x9e,0x18,0x9f,0x4c,0xd,0x75,0x21,0xe5,0xd,0x4b,0x8b,0xee,0x2d,0x51,0xaf,0x48,0x2,0xe0,0x4d,0xf1,0xb1,0xe1,0x5c,0x82,0xe6,0x7a,0xc,0xdd,0x22,0x92,0x7e,0xb4,0x2d,0xd8,0xd2,0x9d,0xc3,0x50,0xbd,0x5e,0x4f,0x3c,0x43,0x84,0x7a,0xbd,0xbe,0xe0,0xfe,0xfc,0x1d,0x4b,0xc7,0x71,0xdc,0x64,0x5a,0xca,0xf9,0x45,0x13,0xb6,0xe9,0xaa,0x3c,0x0,0x53,0x53,0xf1,0x96,0x78,0x80,0xb1,0x46,0x0,0xec,0x96,0xce,0xbd,0x25,0x8d,0x90,0x60,0x69,0xb3,0xe3,0xb1,0xbb,0x30,0x4b,0xbd,0x5f,0x11,0xbe,0xd6,0x4,0x21,0x61,0x16,0x8d,0x2e,0x56,0x34,0x99,0x15,0x96,0x30,0xc4,0x70,0xc9,0x9,0x56,0x9c,0x9a,0x99,0x5b,0xaf,0xf3,0x8a,0x46,0x96,0x4c,0x9b,0xd,0x40,0x5a,0x61,0x6c,0x71,0x3d,0xbc,0x9d,0x14,0xf7,0x99,0x96,0xc5,0x1a,0x7e,0x2b,0x69,0xa2,0x52,0x6,0x34,0x86,0x38,0xc3,0x2c,0x61,0xdc,0xb5,0x65,0x3,0xe0,0x55,0x7f,0x5d,0xa9,0xcc,0xec,0x2f,0x97,0xca,0xb3,0xd3,0xd3,0x93,0xc5,0xb5,0xce,0xeb,0xb,0xa9,0x50,0x2a,0x95,0x99,0x9d,0x9d,0x21,0x70,0x82,0xf7,0x7e,0xb1,0x44,0xed,0x4e,0xd6,0xdc,0x47,0xc2,0xc9,0xa3,0x14,0x43,0x5d,0x30,0xe,0xa7,0x8c,0x30,0x60,0x26,0xf6,0xbe,0x24,0x22,0x3f,0x5e,0x76,0x15,0xd8,0xb1,0xed,0xc1,0x8e,0x42,0xb1,0x78,0xb6,0xa5,0x50,0xda,0x52,0x2c,0x16,0x54,0xd5,0xdc,0x7a,0x7c,0x7e,0xd2,0xbe,0xce,0x31,0xf6,0xde,0x38,0x4e,0x58,0xdf,0x13,0xa1,0xc6,0x51,0x98,0xa5,0x16,0xa8,0x4a,0xec,0x3d,0xf5,0xf9,0x79,0x4a,0xe5,0xf2,0x5f,0xa2,0x5c,0xee,0xf1,0xd3,0xa7,0x5f,0xaf,0x2c,0xfb,0x4c,0xf0,0xcb,0x4f,0xec,0xed,0x1c,0x19,0x19,0xf9,0xd1,0xd8,0xd8,0xf8,0x7e,0xc0,0x9,0xeb,0x61,0x3,0x86,0xf7,0xbe,0x39,0xce,0xb2,0x8e,0xfa,0xb2,0x5,0x5e,0xd0,0xb0,0x91,0x28,0x8a,0x86,0x1e,0x78,0x60,0xeb,0x2f,0x3f,0xf3,0xd9,0x4f,0x1f,0x3f,0xfc,0xbd,0xc3,0x93,0x1b,0x47,0xc0,0x1b,0xb1,0x11,0x1b,0xb1,0x11,0x1b,0xb1,0x38,0xfe,0x7,0x2f,0xf4,0xda,0xd3,0xbb,0x47,0x75,0xc1,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,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,0xdd,0x9,0x17,0x5,0xb,0x2,0xa9,0x9b,0xd2,0xa,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,0x6,0xd6,0x49,0x44,0x41,0x54,0x68,0xde,0xed,0x98,0x5d,0x8c,0x5d,0x55,0x15,0xc7,0x7f,0x6b,0x9d,0x73,0x3f,0x66,0xe6,0xce,0x74,0x7a,0x67,0x86,0x34,0xb6,0xb5,0x2d,0x23,0x6d,0xd1,0xe8,0x60,0x6a,0xa9,0x50,0x3e,0xd4,0x18,0xe3,0xb,0x49,0x1f,0x68,0xc5,0x7,0xe3,0x77,0x20,0x1,0x63,0x1a,0x51,0xf1,0x85,0xc4,0x68,0x22,0x98,0x9a,0xbe,0x88,0xa,0x8d,0x40,0xf4,0xa1,0x32,0xb5,0x4a,0xa8,0x81,0x4,0xc4,0x92,0x34,0xb1,0x26,0x90,0x48,0xa1,0xcd,0x50,0x4b,0x9,0x76,0xda,0x32,0xd5,0x69,0x99,0x99,0x76,0xee,0xbd,0xe7,0x63,0xef,0xe5,0xc3,0x39,0x77,0xa6,0xa5,0x33,0x30,0x77,0x66,0xde,0x9c,0x95,0xec,0x87,0xc9,0xb9,0xe7,0xcc,0xde,0x6b,0xfd,0xff,0xff,0xf5,0x5f,0x1b,0x96,0x62,0x29,0x96,0x62,0x29,0xfe,0x8f,0x43,0x66,0x7b,0x70,0xed,0x9a,0xfe,0x32,0x22,0x5f,0x45,0xd8,0x9,0x7c,0x44,0x8c,0xc0,0x0,0x91,0xfc,0x15,0xb3,0x45,0xdd,0x81,0x77,0x1e,0xf5,0x55,0xba,0x8b,0xeb,0x50,0x3a,0x0,0xcb,0x1f,0xce,0xff,0xff,0x38,0x6a,0xee,0x52,0xed,0xc2,0x23,0x27,0x46,0x8e,0x3e,0x68,0x9c,0x1b,0x9f,0x73,0x2,0xd6,0x7d,0xb8,0xbf,0x4d,0x55,0x9e,0xd2,0x40,0xef,0x8,0x54,0x11,0x11,0x44,0x14,0x0,0x15,0x99,0xda,0xda,0x62,0x65,0xc0,0xb9,0x94,0x36,0xeb,0xe7,0x2b,0x5f,0x7a,0x80,0x9b,0x6f,0xda,0x4a,0x67,0xe7,0x82,0xce,0xd,0x92,0xd5,0x67,0x72,0x12,0x7f,0xf0,0xd0,0xf3,0xba,0x77,0xf0,0xd7,0x27,0x5f,0x7f,0xeb,0x1f,0x37,0x3a,0x46,0x2e,0xbc,0xf7,0xa7,0xe1,0x8c,0xef,0xab,0xdc,0xa7,0x81,0xde,0x11,0x6,0xc1,0x4,0x48,0x45,0x40,0x9b,0x87,0x47,0x40,0x10,0x24,0x4f,0xc4,0x42,0xa,0x6f,0x1e,0x54,0x8d,0xb4,0xd6,0xcb,0x97,0xef,0xba,0x9f,0x4d,0x9f,0xd8,0xca,0xab,0x87,0xc6,0x68,0xd4,0xd3,0x45,0x41,0x56,0xb1,0xa8,0xfa,0xd9,0x9b,0xbe,0x70,0x9,0xa7,0xfd,0xf5,0xdf,0x4d,0xfc,0xe2,0xf8,0xb9,0x91,0xaf,0xcf,0x29,0x1,0xc0,0xce,0x20,0x8,0xc,0x93,0x4e,0x51,0x11,0x55,0xcd,0x2a,0x9e,0xa3,0x20,0x43,0xc4,0xc2,0x71,0x60,0x18,0x41,0x41,0xa9,0xc8,0x6a,0xb6,0x6c,0xbe,0x9d,0xd7,0xfe,0x3e,0x4a,0xb1,0x58,0xa2,0xa3,0x23,0x5c,0x14,0x6c,0x79,0x6f,0x1c,0x7e,0xe9,0x3f,0x95,0xdb,0x3f,0xf3,0x79,0x3f,0xb8,0xef,0xb7,0x5f,0x3,0xe6,0x9c,0x80,0x15,0x8a,0x8,0x2a,0xf9,0x61,0xa7,0x17,0x48,0x4e,0x3,0x8f,0xf7,0x86,0xf7,0x1e,0x11,0x41,0x73,0xaa,0x98,0x19,0x66,0x36,0xf5,0xfb,0xe6,0x73,0x11,0x99,0x86,0x75,0x33,0x6f,0x2a,0x88,0x82,0x4f,0x3,0x48,0x20,0x8d,0x3c,0x81,0xa,0x8e,0xc5,0xd1,0x17,0x11,0xc1,0x25,0xe0,0x62,0x54,0x5c,0x69,0xc6,0x8f,0x86,0xb3,0xa0,0x47,0xc8,0x37,0xad,0x81,0xa2,0x28,0x48,0x93,0x2,0x92,0xef,0x5d,0xe9,0x5e,0xd6,0x45,0xb9,0xdc,0x86,0x73,0x29,0xef,0x8e,0xbd,0x8b,0xf3,0x9e,0x72,0xb1,0x44,0xa9,0x54,0xe6,0xd2,0xc5,0x8b,0x78,0xef,0x59,0xbe,0x7c,0x39,0x8d,0x7a,0x9d,0x38,0x8d,0x91,0x8c,0x49,0xd3,0x8,0xf0,0x10,0xa8,0x91,0x9a,0x90,0x46,0xe0,0x12,0xc3,0x7,0x1e,0xb0,0x5,0x61,0xcb,0x2e,0x4f,0x40,0x6c,0xa4,0x11,0x98,0x89,0xcc,0x39,0x1,0x57,0xf0,0xdd,0x32,0x5,0x10,0x11,0x44,0x73,0x21,0x54,0x45,0x9,0x78,0xed,0xf5,0xa3,0x5c,0x18,0x1f,0x25,0x20,0x64,0x60,0x60,0x0,0x45,0x19,0x1d,0x3d,0xcf,0xf8,0xf8,0x18,0xab,0x57,0xad,0x21,0xc,0x4b,0x1c,0x3b,0x76,0x94,0xde,0xde,0x6b,0xe8,0x68,0xef,0x98,0xbd,0x9,0x18,0xb8,0x18,0x5c,0x6c,0xb8,0x20,0x43,0x90,0x79,0x9b,0x1f,0xc3,0x2c,0xef,0x54,0x59,0xcd,0xf0,0x89,0xc7,0x45,0xb3,0x77,0x2d,0x9d,0x5,0x3b,0x20,0x82,0xa0,0x48,0x4e,0x83,0xa6,0xe,0xa8,0x4,0x34,0xea,0x11,0xc5,0xb6,0x2,0x7f,0x3d,0xf8,0x3c,0x66,0x46,0x2d,0x9a,0xe4,0xba,0xf5,0xfd,0x24,0x49,0xc2,0xf6,0x1d,0xdb,0x39,0xf0,0xdc,0x1,0x96,0x75,0x77,0x31,0x31,0x3e,0xce,0xfe,0x3f,0xef,0xe7,0x96,0x5b,0xb6,0x92,0xa6,0x29,0x41,0x10,0x5c,0x45,0xa9,0x26,0x6d,0xe2,0x8,0x92,0xd8,0xe7,0xcb,0x8,0xca,0x9,0x41,0x21,0x21,0x28,0xb6,0xb8,0xca,0x9,0x9e,0x94,0xa4,0x6e,0xa4,0xb1,0x91,0x44,0x9e,0x38,0x9a,0xbd,0x6b,0x87,0xef,0xdb,0x9e,0x5,0xb0,0x26,0xec,0xd,0x8,0x48,0x5d,0x4a,0x7b,0x47,0x3b,0x8f,0xee,0xf9,0xd,0x67,0x4f,0x9f,0x65,0xcb,0xa7,0x3e,0xcd,0xad,0xb7,0xdd,0xca,0x1f,0x6,0x9f,0x62,0xeb,0xcd,0x5b,0x11,0x84,0x2d,0x37,0x6e,0x61,0xc7,0x5d,0xdb,0xf9,0xd9,0x4f,0x1f,0xa2,0xda,0x53,0xa5,0xb3,0xb3,0x13,0xc3,0x32,0xd,0xbd,0x5c,0x7,0xac,0xd9,0xb2,0x84,0x24,0x6,0x8b,0x3d,0x5e,0x1c,0x22,0x1,0xa7,0x4f,0x9e,0x41,0x35,0xc4,0xcc,0xb7,0x24,0xfd,0x86,0x51,0x69,0xeb,0xa6,0xbd,0x6d,0x19,0x3e,0x75,0x58,0x6c,0xd9,0xb7,0x69,0x31,0x1,0xe4,0x82,0x97,0x55,0xe9,0x32,0xb0,0x78,0x18,0xf8,0xe4,0x0,0xd5,0x6a,0xf,0xf,0x7c,0xff,0x47,0x44,0x51,0xc4,0x9e,0x47,0xf7,0xf0,0xed,0xbb,0xbf,0xc5,0xdd,0xf7,0xdc,0xc3,0x8b,0x2f,0xbc,0xc8,0xd9,0x77,0xce,0xb2,0x6d,0xdb,0x36,0x9e,0x78,0xfc,0xc9,0x4c,0x28,0xcd,0xa3,0x3a,0x5,0xac,0x2b,0xc5,0x46,0xb3,0xea,0xa4,0x11,0x44,0xb1,0x47,0xd5,0xf0,0x96,0xf0,0xa1,0xbe,0x8f,0xe6,0x87,0x97,0x16,0xd9,0x2f,0xc4,0x71,0x83,0x5a,0x2d,0x22,0x50,0x25,0x8a,0x1d,0x49,0x3,0xcc,0xb,0xad,0x88,0x60,0x5e,0x7c,0x3,0xf1,0x19,0x15,0xb0,0xcc,0xc,0x9,0x74,0xb4,0xb7,0x33,0x31,0x31,0x4e,0xea,0x52,0xfa,0xfa,0xfa,0x38,0x75,0x6a,0x98,0x7a,0x3d,0x62,0x79,0x77,0x37,0x95,0x4a,0x85,0xc3,0x87,0xf,0x23,0xa6,0xdc,0xff,0x83,0xef,0x91,0x24,0x31,0x61,0x18,0x62,0x36,0xbb,0xb4,0x99,0x81,0x6b,0x80,0x8f,0x3c,0x29,0x1e,0x1,0xce,0x25,0xff,0x42,0x9,0xb0,0x16,0x3b,0x82,0x89,0x51,0xf0,0x15,0x42,0xab,0xe0,0xc4,0xe1,0xa2,0x4c,0x3,0x5a,0xa6,0xc0,0xd5,0x66,0x71,0x7a,0xf3,0xc3,0xc3,0xc3,0xf4,0xf5,0xf6,0xb1,0x6a,0xf5,0x4a,0xf6,0xfe,0x7e,0x2f,0xdd,0x3d,0x55,0x36,0x6c,0x5c,0xcf,0x1f,0x7,0xf7,0x51,0x6e,0x2b,0x53,0x2a,0x96,0xf8,0xf1,0x83,0x3f,0xe1,0xe9,0x3,0x7f,0xa2,0x5a,0xad,0x52,0xab,0xd5,0x50,0xd5,0x99,0x77,0x61,0xd9,0x8a,0x1a,0xe0,0x22,0x48,0xbd,0xa1,0x2a,0x44,0xb5,0x2,0x22,0x8a,0xb5,0x64,0xb9,0x33,0x5e,0x59,0x41,0xd0,0x82,0xc7,0x0,0x1f,0x43,0x5c,0xcf,0xa9,0xdc,0x72,0x2,0x2c,0xef,0xdd,0x32,0xbd,0x89,0x20,0x8,0x38,0xfe,0xc6,0x71,0x6,0x7,0xf7,0xf1,0xd8,0x9e,0xc7,0xb8,0x73,0xfb,0x9d,0x6c,0xda,0xb4,0x89,0x93,0x27,0x4e,0xf2,0xcc,0xd3,0xcf,0xf0,0x9d,0xef,0xde,0xcb,0xc6,0x8d,0x1b,0x19,0x1f,0x1f,0x67,0xf7,0xae,0xdd,0xec,0xda,0xbd,0x8b,0x72,0xb9,0x3c,0xe5,0x7,0x66,0x3a,0xbf,0x9a,0x10,0x37,0x20,0x8e,0x3d,0x8a,0x61,0xe6,0xe8,0xad,0xae,0xc1,0xcc,0xb5,0x6c,0xb6,0x4,0xa1,0x51,0xaf,0x51,0xaf,0x37,0x50,0xd,0x89,0x23,0x4f,0xd4,0xb8,0xe2,0x8,0x1f,0x3c,0xb,0xf4,0xaf,0xbb,0xce,0xda,0xcb,0x6d,0x20,0x10,0x48,0x88,0x28,0x59,0x37,0x60,0xda,0xec,0xa8,0xc2,0x86,0x8d,0x1b,0x18,0xb8,0xe1,0x6,0x4e,0xf,0xf,0xf3,0xf2,0xcb,0xaf,0x10,0xc7,0x31,0x5d,0x5d,0x5d,0x94,0xca,0x25,0x46,0xff,0x3b,0x8a,0xf7,0x9e,0xb5,0xeb,0xd6,0x72,0x6e,0xe4,0x1c,0x51,0x14,0x5d,0x7d,0x78,0xf,0x61,0x11,0x26,0x4f,0x5c,0xcf,0xbd,0x3b,0x9e,0xe4,0x8d,0x57,0xde,0x24,0xc,0x4b,0xa8,0x28,0xa3,0xd1,0x71,0x54,0xa,0x2d,0xf,0x5,0x66,0x9e,0xf6,0x42,0x2f,0xed,0x41,0x2f,0x8e,0x94,0xb8,0x51,0xe3,0xe3,0x9b,0xd7,0xf3,0xcb,0xfd,0xdf,0xe0,0xc8,0xf9,0x27,0xa4,0x5,0x4,0x64,0x82,0xe2,0x71,0x28,0x3a,0x95,0xa9,0x69,0x97,0xa7,0xbc,0x79,0xe2,0x2d,0x8e,0x1d,0x1d,0xa2,0x58,0x2c,0xe6,0x4e,0x4f,0x98,0xbc,0x54,0xa3,0x36,0x59,0xcf,0x7c,0xbe,0x4,0xbc,0x73,0x66,0x84,0x24,0x49,0x66,0x46,0xbf,0xcf,0x16,0x40,0x52,0x87,0x38,0xf2,0x39,0x54,0x1d,0xcb,0xf5,0x63,0xf3,0x9b,0x88,0x4,0x7c,0xea,0x88,0x72,0xe3,0x95,0x46,0x46,0xdc,0x98,0xdd,0x7,0x84,0xb3,0x67,0x32,0x37,0x15,0xc1,0xf4,0xdf,0x22,0x99,0x2a,0x9b,0x81,0xf7,0x1e,0x6f,0x9e,0x62,0xb1,0x84,0xf7,0x6e,0x8a,0xab,0xce,0xb9,0xcb,0xbe,0x61,0xc4,0x71,0xfc,0xbe,0x29,0x36,0x33,0xf0,0x99,0x8,0x92,0x1a,0x2a,0xd9,0xfb,0xce,0x26,0x17,0x60,0x81,0x9b,0x25,0xf3,0x58,0xea,0x71,0x8d,0xac,0xd5,0xce,0x3d,0x1,0x66,0x66,0x78,0x41,0x4,0x33,0x9d,0x72,0x65,0x5e,0xb3,0x4e,0x4b,0xd3,0xd7,0x1b,0x24,0xce,0xcd,0x7f,0x26,0xb2,0xbc,0x3,0x18,0x44,0x89,0xc7,0xc5,0x46,0x6c,0x96,0x2b,0xbf,0x2e,0x74,0x14,0x42,0xc8,0xac,0x70,0x23,0x6,0x6f,0x32,0xf7,0x59,0xc0,0x60,0xc4,0xbc,0xad,0x10,0x15,0xc,0x13,0xc3,0x63,0x28,0x6a,0x86,0x21,0x99,0xa0,0x88,0x65,0xad,0x6d,0xa6,0x3b,0x8b,0x19,0xcc,0xce,0x7b,0x9f,0x49,0x3e,0xb3,0x8b,0x1,0x41,0x4c,0x94,0x34,0xc0,0x84,0x24,0xb2,0xcb,0x66,0x86,0xf9,0xd,0x45,0x42,0x66,0x38,0x3c,0x1e,0xf3,0x42,0x9c,0x3a,0x6f,0x12,0xe9,0xdc,0x7d,0x80,0xc8,0xee,0xd4,0xb9,0x9f,0x17,0x54,0x2f,0x9a,0x59,0xc5,0x83,0x88,0x39,0x9c,0x29,0x88,0xe5,0xc3,0x91,0x7d,0xf0,0x1e,0x6d,0xf6,0x73,0x34,0x29,0xe6,0x52,0xf0,0xed,0x67,0x18,0x3a,0x75,0x88,0xb5,0xd7,0xdc,0xc6,0xe8,0x99,0x61,0x92,0x34,0x61,0x41,0xb7,0x2e,0xd9,0xd5,0x15,0x61,0x10,0xb0,0x62,0xd5,0xf5,0xf5,0x63,0xa7,0x9f,0x6d,0xab,0xdb,0xc8,0xde,0x39,0x27,0xa0,0xda,0xd3,0xf3,0x48,0x12,0x45,0x5f,0xbc,0x38,0x31,0xf1,0xb9,0x42,0xb1,0x48,0x18,0x4,0x90,0xcf,0x2,0x59,0x51,0x33,0x78,0x2d,0xc6,0xa5,0x85,0x79,0x8,0x2a,0x17,0x38,0x32,0xf2,0x2b,0x5c,0xb5,0xc8,0xca,0x95,0x9b,0x29,0x51,0xc9,0x4,0x72,0x9e,0x9f,0x55,0xc0,0x14,0x62,0x9b,0xb4,0xa1,0xb1,0x67,0xdb,0x86,0x2e,0x3c,0x7e,0x7e,0x2c,0x19,0xda,0xd9,0xd2,0x9d,0xe0,0xc3,0xf,0x3d,0xbc,0xec,0xe0,0xdf,0x5e,0xba,0xef,0xed,0xb7,0xff,0xfd,0xcd,0x24,0x49,0xd6,0x34,0x49,0x39,0x13,0xaa,0x17,0x9a,0x5,0x13,0x23,0x4d,0x12,0xa8,0xf5,0x50,0x4e,0xae,0x25,0xf0,0x5d,0xb,0xbc,0x13,0x3,0x10,0x73,0xc1,0x24,0x85,0xce,0xb1,0xbf,0x14,0x7a,0x46,0x7e,0xf8,0xcf,0x23,0xaf,0xe,0x2d,0x5d,0x1,0x2f,0xc5,0x52,0x2c,0xc5,0x52,0x2c,0xc5,0x95,0xf1,0x3f,0x3d,0xec,0x5e,0x6b,0xe4,0x4d,0x1e,0xfb,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
};
@@ -370,12 +430,12 @@ static const unsigned char tool_button_pressed_png[]={
static const unsigned char tooltip_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,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xda,0xc,0x3,0x2,0x34,0x35,0x46,0x29,0x34,0xbc,0x0,0x0,0x3,0xda,0x49,0x44,0x41,0x54,0x58,0xc3,0xc5,0x97,0x3d,0x8e,0x65,0x49,0x11,0x85,0xbf,0x73,0x22,0xdf,0xeb,0x1e,0x69,0x24,0xd8,0x5,0x5e,0x2f,0x60,0xc,0xec,0xf1,0x86,0x2d,0x20,0xd8,0x7,0x62,0x1f,0x20,0xb6,0x0,0x1e,0x12,0xe,0x1a,0x1,0xfe,0xb4,0xc7,0xe,0x0,0xb,0x83,0x11,0x53,0xf7,0xde,0x88,0xc0,0xc8,0xbc,0xd5,0xd5,0xa5,0x87,0xd4,0xf,0xaa,0x20,0xa5,0x54,0x4a,0xf7,0x27,0xe3,0xc4,0x89,0x13,0x11,0x99,0x2,0x78,0xf7,0xee,0x9d,0x98,0x43,0x4f,0xe6,0x6b,0x8c,0x7e,0x32,0x79,0xff,0xfe,0x7d,0x6b,0x19,0x17,0x10,0xc0,0x0,0xbc,0xe6,0x6b,0x8c,0x5a,0xf3,0x0,0x12,0xe8,0xb1,0x5e,0x4,0xf0,0x6,0x78,0xbb,0xd6,0xf1,0xa,0x2c,0xf4,0x32,0xfc,0x0,0x7c,0xb7,0xd6,0xe3,0x34,0x34,0x96,0xf1,0xef,0x1,0x9f,0x3,0xd7,0xc5,0x82,0x5e,0xd0,0x78,0x1,0x1b,0xf0,0x8f,0xf5,0x2c,0x81,0x3c,0x1,0x78,0x79,0xfe,0x39,0xf0,0xfd,0x5,0x26,0x5e,0x18,0x40,0x2e,0xcf,0x59,0xeb,0x3f,0x1,0x9d,0x21,0xf0,0x62,0xe1,0xa,0xbc,0xfd,0xe5,0x2f,0x7e,0xfe,0xdb,0xd7,0x10,0xc0,0x4f,0x7e,0xfa,0xb3,0x2f,0x97,0x8d,0x53,0x6b,0x7a,0x1a,0xeb,0x93,0x89,0xd8,0x73,0xe3,0xd7,0xbf,0xf9,0xd5,0x8b,0x1a,0xff,0xd1,0x57,0x3f,0x3e,0xb5,0xf6,0x51,0x68,0xc7,0xb3,0xef,0x4,0x68,0xdf,0x77,0x46,0x4,0x5f,0xfc,0xf0,0x7,0xb7,0x14,0x5c,0x4f,0x53,0x69,0xad,0xcf,0xd3,0xd8,0x4f,0xb3,0xe9,0x4f,0x5f,0xff,0x99,0x7d,0xdf,0xb9,0x95,0xe2,0xe3,0x16,0xda,0xe3,0x38,0x3e,0x4,0xe7,0x83,0x60,0x6e,0x1,0xe8,0xe7,0xe0,0xd7,0x7c,0xfa,0x3e,0x34,0xe6,0x9e,0xb7,0xc6,0x6d,0x0,0xdb,0x3,0x97,0x88,0x99,0x9f,0x41,0x76,0x29,0xe5,0x2e,0x72,0x2,0x68,0xa9,0xb2,0xdd,0x8a,0xec,0xce,0x20,0x40,0x15,0x9,0x39,0xbd,0xb7,0xd4,0xb4,0x3b,0xa1,0x43,0xc5,0x25,0x22,0x8e,0xed,0xe1,0xd3,0x1,0x6c,0xc7,0xe,0x36,0x96,0xaa,0x6b,0x19,0x2d,0x25,0xfa,0xc0,0x42,0xa8,0x9a,0x52,0xa3,0x82,0x99,0x36,0xda,0x3,0xa1,0x6a,0x67,0x74,0xaa,0x3a,0x4e,0x66,0xec,0xd8,0x8e,0xfd,0xe,0x6,0x8e,0x83,0xeb,0x30,0xe5,0xae,0x80,0xea,0x8c,0x52,0x64,0x9d,0x4c,0x24,0xcc,0xe7,0xa5,0xa9,0x81,0xb6,0xb2,0x8a,0xa3,0xed,0xab,0xd4,0xb9,0xd4,0x96,0x2b,0x24,0xd7,0xe1,0xfb,0x42,0xb0,0xef,0x3b,0xb2,0x71,0xa9,0x1a,0x6a,0x44,0xd6,0x51,0x7a,0x64,0xc2,0x50,0xd,0x55,0x76,0x5f,0xaa,0x50,0x24,0x47,0x49,0x57,0x55,0xe7,0xd2,0xc5,0x6e,0xe3,0x2a,0x5,0x48,0xf6,0x29,0xc2,0x4f,0x7,0x70,0x19,0x46,0x76,0x1b,0xba,0xa1,0xc2,0x93,0xfa,0x82,0xca,0x19,0x86,0xbc,0x54,0x35,0x76,0x37,0x28,0x3c,0xc5,0x17,0x55,0x60,0x2b,0x96,0xf7,0x65,0xfb,0x32,0xee,0x4,0x90,0xc7,0x6,0x36,0x40,0x57,0xd0,0x91,0x53,0xd1,0xcb,0xbb,0x7a,0xb,0x49,0x64,0xee,0x44,0x9d,0x5c,0x47,0x10,0x99,0x53,0x82,0x6,0x9,0x9c,0x97,0xee,0x80,0xc6,0x9e,0x7b,0x7e,0xb2,0x6,0x6a,0xe3,0xcd,0xa5,0x59,0x89,0xd0,0xc4,0x4,0x10,0x2b,0xb5,0xa,0x1a,0xa2,0x22,0x96,0x28,0x63,0x16,0x97,0x88,0xc7,0x14,0xa4,0x33,0x1e,0xbf,0x7f,0x73,0x69,0x8e,0xba,0xd,0xe0,0x66,0xdb,0xdd,0xf3,0x1,0x7b,0x10,0xd3,0x28,0x31,0x37,0xc4,0x19,0x6d,0x89,0x96,0xda,0x19,0xf4,0x14,0x68,0xb6,0x54,0xce,0x68,0x66,0xb8,0xa6,0xf1,0x51,0xb3,0x8,0x0,0xf6,0x60,0xcf,0x3b,0xd2,0xb0,0x6b,0xe3,0x12,0xa2,0x25,0x9d,0xf5,0x33,0x46,0x11,0xa0,0x74,0x13,0x20,0x46,0x11,0xc8,0x8c,0x9a,0x8e,0x8c,0xc2,0xcc,0xef,0x19,0x33,0x3d,0x42,0xa2,0x81,0x4b,0x88,0xba,0x87,0x81,0x3c,0x36,0x62,0x18,0x11,0x84,0x5b,0xb8,0x15,0x6e,0x55,0x6,0x51,0x52,0x80,0x2a,0x23,0x2,0x8c,0x7b,0x28,0xc3,0x22,0x22,0x40,0xca,0x50,0xb8,0x11,0xa1,0xc7,0x7f,0xc7,0x9d,0x1a,0xd8,0x8e,0x83,0xcf,0x3e,0xf3,0xf4,0x94,0x10,0x25,0x1d,0x6e,0x29,0x30,0x83,0xae,0x63,0xb4,0x2f,0x8d,0xb0,0x54,0xea,0xbe,0xb4,0x54,0x52,0x11,0x41,0xe0,0xb0,0x5c,0x85,0xaa,0x86,0xc6,0x4a,0xc3,0xed,0x9e,0x3a,0x90,0xc7,0x86,0xe2,0xca,0xe1,0xd6,0x0,0xe1,0xf6,0x80,0x3e,0xa0,0x55,0x26,0xdc,0x1c,0x25,0x3d,0x40,0x47,0x9b,0x41,0x82,0x5b,0x47,0xc9,0x40,0x6c,0x65,0xf,0xf7,0xd9,0x8c,0xa4,0x88,0x3b,0xb3,0x60,0x4f,0x86,0x4d,0x94,0xcc,0xc8,0x6e,0x68,0xca,0x1d,0x23,0x9b,0x32,0x47,0x89,0x31,0xd2,0x71,0x44,0xa3,0x6a,0x5c,0x72,0x19,0xdc,0xa6,0x64,0x4a,0x81,0xdb,0x7,0x38,0xc0,0xc3,0xe6,0xd8,0xf3,0x1e,0x0,0x3b,0xad,0xb,0x65,0x9b,0x72,0x9b,0x9c,0x9d,0xad,0x4c,0x4f,0x4a,0x95,0xe5,0xb6,0x73,0xa6,0x5c,0x99,0x84,0xa9,0xd,0xdb,0x26,0xdd,0x10,0x22,0xc,0xe9,0xd6,0x85,0xe3,0xae,0x4a,0x98,0x3b,0xc3,0x10,0x2e,0x27,0xb4,0x2a,0xc0,0x85,0xd5,0xaa,0x96,0xa2,0x10,0xae,0xf6,0x1,0xbb,0xa3,0xc3,0x53,0xf5,0x13,0x44,0x39,0x91,0x29,0x1b,0x70,0x11,0x1e,0x9e,0x7b,0xde,0x55,0x8a,0xed,0xeb,0x79,0x5c,0xe,0x3c,0x3b,0x5e,0xb5,0x66,0xbf,0x77,0x19,0xe8,0x1a,0xea,0x59,0x8b,0x66,0xd7,0x3b,0xcb,0xef,0xcc,0x8e,0x3a,0x35,0x10,0xf6,0xf5,0x93,0x4b,0x71,0x3,0xbd,0x6d,0x85,0x6d,0xfe,0xf6,0x97,0xc7,0xe2,0x71,0xd6,0xa3,0xff,0x68,0xd8,0x66,0xdb,0x8a,0x1b,0x87,0x18,0xc6,0xb3,0xa3,0x55,0x1,0xb9,0x1d,0x7,0x7f,0xf8,0xe3,0x37,0x2f,0x7b,0x22,0x9d,0xbd,0x25,0x9f,0x9c,0xa8,0x3e,0x62,0xe0,0xbc,0xad,0x6c,0xc0,0x77,0xbf,0xff,0xdd,0x5f,0xbf,0x7c,0xc5,0x63,0xf9,0xb6,0x6c,0xd5,0x79,0x33,0x3a,0x3d,0x7f,0x0,0xbe,0x5d,0x3f,0x5c,0xff,0x1b,0xca,0xff,0xcd,0xc8,0x65,0xfc,0xdb,0x65,0xeb,0x23,0x0,0xc7,0x42,0xf7,0xf7,0xb5,0xbe,0xa4,0xf7,0xcf,0x59,0x38,0xaf,0x66,0xc7,0xd3,0xbb,0xe1,0xf9,0x22,0xd7,0x8d,0xe5,0x7f,0x75,0x39,0x9d,0x5e,0xfe,0x3f,0xaf,0xe7,0xff,0x2,0xd,0x2f,0x3a,0x83,0xce,0x22,0x38,0x16,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,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,0xd,0x2d,0xcd,0xa6,0x10,0x43,0x0,0x0,0x0,0xd2,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0x93,0x3d,0x6a,0xc3,0x40,0x10,0x85,0xbf,0x55,0x6,0x2c,0x9,0x17,0xa9,0x77,0xb1,0x4f,0xe0,0x9f,0x42,0x27,0x12,0x42,0x65,0x8,0x3e,0x49,0xe,0x20,0x8c,0x4f,0xe4,0xc2,0x3f,0x75,0x9a,0xb0,0xaa,0x53,0x84,0x48,0x82,0x31,0x4a,0x11,0xa5,0x5d,0x5,0xd4,0xb8,0xf0,0x2b,0x87,0x79,0xdf,0x30,0xf0,0x9e,0x1,0x52,0xe0,0x19,0x98,0x3,0x4f,0x80,0x21,0xac,0x1e,0xb8,0x1,0x5f,0xc0,0xa7,0xc,0xe6,0xd,0xb0,0x0,0xe2,0x7f,0x2,0x5a,0xe0,0x3,0x38,0xcb,0x70,0x79,0xb9,0x5e,0x6d,0xdf,0x9c,0x75,0x89,0x88,0x4,0x1,0xaa,0xda,0xfb,0xda,0x37,0x97,0xeb,0x69,0x7,0xbc,0xb,0x20,0xc0,0xcc,0x59,0x97,0xb6,0x6d,0xcb,0xfe,0x50,0x1d,0x43,0x80,0x22,0x2f,0x33,0x67,0x5d,0x7a,0xb9,0x9e,0x66,0x80,0x44,0xc3,0xdc,0x88,0xc8,0xa8,0x19,0x60,0x7f,0xa8,0x8e,0x22,0xc2,0xdf,0xab,0x51,0x78,0x7d,0x5c,0xf,0xc0,0x3d,0x1,0x7a,0x55,0xa5,0xc8,0xcb,0x6c,0xcc,0x50,0xe4,0x65,0xa6,0xaa,0xf0,0x1b,0x69,0x4,0x50,0xa0,0xf3,0xb5,0xff,0x76,0xd6,0x25,0xaf,0x2f,0xbb,0x20,0x24,0x8e,0xe3,0xde,0xd7,0xbe,0x1,0x3a,0x40,0xd,0x60,0x99,0x50,0x26,0xc3,0xc4,0x3a,0xff,0x0,0x26,0xe4,0x45,0xbd,0xbe,0xa2,0xc,0xd0,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
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,0x30,0x0,0x27,0x0,0x35,0x33,0xd3,0x97,0xbf,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,0xdd,0x9,0x1b,0x11,0x4,0x30,0xb7,0x2d,0x2b,0x51,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,0xc0,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0xd0,0x2d,0x8e,0x2,0x41,0x10,0x86,0xe1,0xb7,0x7f,0x66,0x4,0x20,0xd6,0xb0,0x21,0x60,0x20,0x70,0x1,0x34,0x8a,0x5b,0xac,0x26,0x5c,0x62,0x4f,0xc0,0x11,0x30,0x4,0xcd,0x29,0x40,0xa1,0xb9,0x0,0x9,0x6a,0x12,0x2,0x6,0x1,0x23,0x9a,0xa9,0x2e,0xcc,0x1e,0x60,0x3a,0xeb,0x8,0xaf,0xff,0x9e,0x4a,0xca,0xa8,0x2a,0x83,0xde,0x68,0x5,0xfc,0x0,0x4d,0xea,0xf5,0x0,0x36,0xa7,0xe2,0x38,0x37,0xfd,0xee,0x70,0xeb,0xbc,0x9f,0x7a,0xef,0x48,0xa9,0xaa,0x4,0xa9,0xaa,0x9d,0xe9,0x77,0x87,0xd2,0x68,0x36,0xac,0x73,0xe,0x6b,0xea,0x21,0x51,0x5,0x11,0xa1,0x7c,0x94,0xd1,0x3,0x36,0xf3,0x79,0xd2,0x75,0x6b,0x1c,0xd6,0x3b,0xa0,0xb4,0x96,0x7f,0xf6,0x1,0xde,0x6,0x28,0xa2,0x4a,0xf2,0xf0,0x6f,0x53,0x58,0x60,0x19,0x42,0x20,0x5,0x89,0x2a,0x84,0x10,0x0,0x96,0x46,0x55,0x99,0x8c,0xa7,0x8b,0xeb,0xed,0x3c,0x7b,0x86,0xe7,0x77,0x1d,0x20,0xcb,0xb3,0x4b,0xfb,0xab,0xb3,0xde,0x1f,0x76,0xbf,0x46,0x55,0x41,0xc9,0x81,0x56,0xc2,0x4f,0x22,0x70,0xc7,0x10,0x5e,0xb5,0x47,0x48,0x5e,0x61,0x62,0xef,0xf5,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
};
@@ -395,42 +455,22 @@ static const unsigned char tree_cursor_unfocus_png[]={
static const unsigned char tree_title_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,0x4e,0x0,0x41,0x0,0x56,0xed,0xd0,0x4e,0x61,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,0xdd,0x9,0x1b,0x12,0x1e,0xf,0xb3,0x20,0x42,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,0x77,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x92,0xbd,0x4e,0xdc,0x50,0x10,0x85,0xbf,0xd9,0xb5,0xb2,0x38,0x80,0x4,0x11,0xb0,0x26,0x74,0x14,0xa4,0x48,0x4,0x1d,0x55,0x2a,0x44,0xc1,0x63,0xa0,0x74,0x79,0x4,0x1a,0xa2,0x54,0x91,0xf2,0x2,0x74,0x11,0x8f,0x41,0x41,0x49,0x95,0x32,0x52,0x9a,0xf4,0x28,0xcb,0xff,0x22,0x7e,0xc,0x6b,0x7b,0x4e,0x8a,0x7b,0xbd,0xe,0xa4,0xc8,0x22,0x46,0xb2,0x8e,0x74,0x75,0xef,0x37,0x73,0xce,0xd8,0x24,0x91,0xcd,0xbd,0xde,0x4,0x3e,0x2,0xab,0x8c,0x56,0xdf,0x81,0x1d,0x59,0xb5,0x6b,0xdd,0xd9,0xf9,0xed,0xee,0x4c,0xf6,0xf9,0xed,0xd2,0x32,0xd3,0x53,0xaf,0x46,0x7a,0x7d,0xd1,0x3f,0xe7,0xe7,0xaf,0x1f,0x1c,0x9d,0xf6,0x3e,0x59,0x77,0x76,0xfe,0xf7,0xfa,0xfb,0x8d,0x2c,0xbf,0xbb,0x25,0xbf,0xcf,0x47,0x2,0xa4,0x9d,0x94,0x74,0xec,0x25,0xfb,0x7,0x7b,0xbd,0x4,0xc8,0xce,0x2f,0xcf,0x78,0x4a,0xe5,0xf7,0x79,0xdd,0x2c,0x4b,0x0,0xe4,0x8e,0x64,0x98,0x9,0xcc,0x40,0x8d,0xd6,0xe7,0x92,0x81,0x9,0x3,0x4,0x58,0x84,0x25,0x0,0x95,0x3b,0x66,0x86,0x5c,0x41,0xd5,0xa8,0x0,0x53,0xbc,0xad,0xf0,0xf8,0x6f,0x40,0x8b,0x67,0x56,0xb0,0x20,0xa1,0x38,0x85,0x2b,0x8c,0x59,0x2b,0x80,0xc7,0x8e,0x8a,0xd6,0x6a,0x1b,0xd,0xc0,0x3d,0x5e,0x74,0x88,0x5e,0x87,0xa,0x98,0x2c,0x8c,0x6e,0xc2,0xdc,0x70,0x1a,0x5f,0x21,0x3,0x55,0xb4,0x68,0x21,0xfd,0xb,0x18,0xfa,0x95,0x5,0x0,0x60,0xb4,0x70,0x79,0x3,0x40,0xc2,0xa9,0x9a,0xf0,0xfc,0xa1,0xba,0xe2,0x24,0x44,0x8b,0x11,0x3c,0x4,0x78,0xb4,0x50,0xe7,0x11,0xba,0x85,0x69,0xdc,0x7c,0x98,0x85,0x22,0xa8,0xde,0x4e,0xd,0x38,0x1c,0x14,0xc5,0x42,0xd2,0x6e,0x3f,0x8c,0xf7,0xd1,0xea,0x1e,0x57,0x59,0x55,0x0,0x87,0xed,0x89,0xf1,0xc9,0xb4,0x28,0x6,0x6b,0x9d,0x4e,0xa,0xf5,0xee,0xff,0xf3,0x95,0x65,0xc9,0xc9,0xd9,0x11,0x45,0x59,0x7c,0x35,0x49,0xbc,0x7b,0xb3,0xf2,0xa5,0x7f,0x75,0xf1,0xa1,0x2c,0xcb,0xb9,0x91,0x76,0x9f,0x24,0xc7,0x53,0x93,0xd3,0xdf,0x4e,0xfa,0xbd,0x2d,0x93,0xc4,0xcd,0xe5,0xcd,0xb,0x60,0xe2,0x9,0x3f,0x96,0x3,0xd7,0x8b,0x4b,0x8b,0x83,0x3f,0xb0,0xb8,0xed,0xb9,0xad,0xea,0xa4,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,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,0x14,0x11,0x9,0x88,0xc3,0x72,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,0x0,0x1d,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x54,0x55,0x56,0xfd,0xcf,0x40,0x1,0x60,0xa2,0x44,0xf3,0xa8,0x1,0xa3,0x6,0x8c,0x1a,0x30,0x98,0xc,0x0,0x0,0x7,0x54,0x1,0x8c,0x3f,0xc3,0xfb,0x99,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char tree_title_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x21,0x14,0x61,0x9b,0xa1,0x3e,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,0x69,0x49,0x44,0x41,0x54,0x38,0xcb,0x95,0x92,0xcd,0x4a,0x5b,0x41,0x14,0xc7,0x7f,0xff,0xb9,0xd7,0xc6,0x5b,0x22,0x69,0x12,0x90,0x6c,0xa,0x2d,0xd,0x85,0xbe,0x80,0xf,0xe0,0x93,0x88,0x3b,0x1f,0xc1,0x8d,0xe2,0x4a,0xf0,0x5,0xdc,0x89,0xcf,0xe3,0x23,0x94,0x2e,0xba,0x91,0xb4,0x62,0x2a,0x25,0x21,0x26,0xf7,0x7a,0x73,0x5c,0xdc,0x99,0xc9,0x88,0x2e,0xae,0x3,0x7,0x66,0xe6,0x7c,0xfc,0x3f,0x38,0x32,0x33,0x6,0x9f,0x86,0x7,0xc0,0x11,0xb0,0x47,0xbb,0x73,0x3,0x5c,0x6e,0x75,0xf2,0x6b,0xf5,0x7b,0x83,0x93,0x7e,0x6f,0x78,0x36,0xec,0xf,0x1,0xb5,0xec,0x37,0xa6,0xf,0x53,0x1e,0xfe,0x4f,0x4f,0xd5,0xef,0xd,0x26,0xe3,0x2f,0xdf,0x47,0xf5,0x7a,0xcd,0x6a,0xb5,0x6c,0xd5,0xde,0xe9,0x6c,0x93,0x39,0xc7,0xaf,0xdf,0x3f,0xff,0xe4,0xc0,0x68,0xf1,0xb8,0xe0,0x3d,0x27,0x1,0x1a,0xe5,0x0,0x92,0x3,0x81,0xcc,0xb0,0x58,0xa6,0x48,0x37,0xbc,0xa5,0xe6,0xd9,0x54,0x35,0xf9,0x66,0x80,0xf3,0xc5,0x12,0xa,0xb9,0xd8,0x27,0x48,0xff,0x1c,0x28,0xf1,0x2a,0x7,0x70,0x3e,0x6b,0xd,0xd,0xdf,0x27,0xcc,0x37,0x85,0x19,0x88,0x58,0xf9,0x92,0x81,0x84,0x21,0x9c,0x4,0x96,0x88,0x10,0x98,0x40,0x26,0xe4,0xdb,0x90,0x7,0x34,0x5e,0x4a,0x50,0xe4,0xa8,0x14,0xaa,0xd1,0x2d,0xef,0x41,0xf4,0x44,0xd1,0xa2,0x8d,0x89,0xe0,0x25,0x24,0xdb,0xf0,0xe6,0x5a,0x28,0x31,0x3a,0xe,0x48,0x10,0xcc,0x83,0x7,0x12,0x9,0x60,0x50,0xe7,0x7c,0x7e,0x63,0xa2,0xdc,0x6,0x2e,0x98,0xe8,0x35,0x28,0x61,0x11,0x80,0x3c,0xd7,0x38,0xec,0xb6,0xaa,0x2a,0x24,0xf9,0x70,0x3e,0xd2,0x7b,0xf6,0xea,0xbf,0xaa,0x2a,0x80,0xdb,0xac,0xd8,0x2e,0x8a,0x55,0xb9,0xdc,0x2f,0x3a,0x5,0x59,0xbe,0x95,0x14,0x85,0xc0,0x87,0xb,0x17,0xca,0x72,0xc9,0xdf,0xfb,0x9,0x4f,0xf5,0xd3,0x85,0xcc,0x8c,0xaf,0x9f,0xbf,0x9d,0xcf,0x17,0xb3,0xc3,0xba,0xae,0x77,0xdb,0xac,0x72,0x96,0x65,0x77,0xdd,0x8f,0x3b,0x57,0x8b,0x72,0x7e,0x2c,0x33,0x63,0xf6,0x6f,0xf6,0x1,0xe8,0x7a,0x49,0x6d,0xce,0x1a,0x98,0x8f,0x7f,0x8c,0xcb,0x67,0x6d,0xca,0x77,0x8d,0xe2,0x85,0x9c,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,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,0x14,0x11,0x5,0x81,0x75,0x3e,0x22,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,0x1d,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x34,0x33,0x31,0xfb,0xcf,0x40,0x1,0x60,0xa2,0x44,0xf3,0xa8,0x1,0xa3,0x6,0x8c,0x1a,0x30,0x98,0xc,0x0,0x0,0xd6,0x1e,0x1,0xbf,0x4c,0xf9,0x63,0xb6,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
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,0x34,0x0,0x2e,0x0,0x39,0xc0,0x34,0x46,0xdb,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,0xdd,0x9,0x1b,0x12,0x7,0x34,0x99,0x2b,0x2,0xd2,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,0x24,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0x3b,0x4e,0x2,0x51,0x14,0x86,0xbf,0x61,0x26,0x23,0x8,0xc6,0xf8,0x62,0x6,0x8c,0x96,0x96,0x16,0x16,0x54,0x2e,0xc0,0xca,0x35,0x10,0x17,0x62,0xa2,0x9,0x6b,0xa0,0x73,0x11,0x56,0x2e,0xc0,0x86,0xc6,0xc2,0xd2,0xce,0x44,0x60,0x50,0x22,0xbe,0xc8,0xcc,0x5c,0xee,0xc3,0x6a,0x12,0x8,0x17,0x8c,0xcc,0x9f,0x9c,0xe6,0x26,0xe7,0xbb,0xe7,0xff,0x73,0x8e,0x63,0x8c,0x1,0x20,0x8,0x2,0x56,0x51,0x81,0x9c,0x9a,0x1,0xb8,0xc6,0x6f,0xba,0xc6,0xef,0xb8,0xc6,0x37,0xb,0xaa,0xe3,0x1a,0xbf,0x39,0xdd,0xe3,0x4d,0x35,0x5f,0x86,0xbb,0xf5,0xab,0xe3,0xa3,0x13,0xb6,0x37,0xf7,0xac,0xbf,0xbd,0x7f,0xbe,0x35,0x1e,0x9f,0x1e,0x1a,0xd1,0xb0,0x77,0xa8,0x1c,0x71,0xd,0xe0,0x64,0x19,0xd4,0xab,0x7,0xfd,0xb3,0xd3,0xf3,0x70,0x1c,0x8f,0x49,0xd2,0xd8,0xa,0x28,0xae,0x95,0x28,0x97,0xca,0xdc,0xdd,0xdf,0x46,0xca,0x11,0xb5,0x99,0x9,0x80,0xf0,0xe3,0x7b,0x84,0x52,0x6a,0xa1,0xdf,0x24,0x8d,0x99,0x48,0x1,0x10,0xce,0x59,0x0,0x48,0x45,0xf2,0x67,0x68,0x52,0x4d,0xb0,0x66,0x0,0x90,0xd9,0xf9,0x8f,0x66,0x0,0x52,0xca,0x7c,0x0,0x6d,0x54,0x4e,0x80,0xd6,0xb9,0x0,0x5d,0x21,0xc5,0xbe,0x57,0xf0,0x96,0x87,0xa8,0x25,0x40,0xd7,0xb6,0x89,0xed,0xc1,0xb0,0x87,0x90,0x2,0xa5,0xb5,0xb5,0x84,0x14,0xc,0x86,0x3d,0x80,0xf6,0xdc,0x4,0xca,0x11,0xad,0xf5,0x62,0x50,0x79,0x19,0x3c,0x5f,0x48,0x29,0xab,0xd6,0x71,0x3d,0xef,0x75,0x6b,0x63,0xe7,0xe6,0x2b,0x19,0xb5,0xb2,0x37,0x67,0xfa,0x1a,0xa3,0x7e,0xe4,0x3,0x95,0x25,0x47,0xa6,0x81,0x9f,0xb0,0x16,0xa,0x2b,0x60,0x15,0xfd,0x2,0x76,0xc9,0x92,0x92,0xf5,0xaf,0x5f,0x3b,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
};
static const unsigned char updown_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x2b,0x8a,0x3e,0x7d,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x73,0x0,0x29,0x0,0x7c,0x29,0x1e,0x61,0x18,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,0xdd,0x9,0x19,0x1,0x16,0x3a,0x99,0x23,0xd9,0x67,0x0,0x0,0x1,0x1,0x49,0x44,0x41,0x54,0x28,0xcf,0x85,0x91,0x3b,0x4e,0xc3,0x40,0x14,0x45,0x8f,0xc7,0x8e,0xad,0x28,0x2,0x45,0x4a,0x8a,0x20,0x50,0x24,0x36,0x40,0x83,0x44,0x8b,0x68,0xd8,0x4,0x9f,0x2e,0x9b,0x61,0x15,0xc8,0xde,0x45,0xa,0xa8,0x91,0xa8,0xd8,0x0,0x22,0x45,0x62,0x25,0x63,0x33,0xf6,0xc8,0x31,0x3f,0xcf,0xd0,0x38,0x28,0x38,0xa,0xdc,0xf2,0x9d,0x5b,0xbc,0xf3,0x1e,0xac,0x45,0x25,0x9a,0x66,0x44,0x3,0xa,0x19,0xab,0xcd,0x42,0xd,0x7d,0x63,0xec,0x1,0x30,0x5a,0x2f,0x79,0x2b,0x68,0xad,0xed,0x69,0x55,0xbc,0x0,0x74,0x76,0xda,0x6f,0x32,0x56,0x51,0x7f,0xd0,0xc5,0x51,0x89,0xf6,0xad,0xb5,0xbd,0xfc,0xb5,0x98,0x2,0x15,0xe0,0xd6,0xa5,0x6b,0x1c,0x22,0x61,0x8d,0xdd,0xaf,0xe1,0x97,0x1f,0xb4,0xee,0x3a,0xbb,0xed,0xb,0x80,0x42,0x97,0x21,0x70,0xe9,0x19,0x6b,0xf,0x1,0xfc,0xa0,0x75,0xbf,0x37,0xec,0x9f,0x3,0xc8,0x58,0xb9,0x85,0x2e,0x43,0x53,0x99,0x23,0x54,0xa2,0xdd,0x74,0x91,0x1d,0x37,0xf5,0xd2,0x79,0x76,0xf2,0x4b,0x73,0x5b,0x44,0x55,0x99,0x53,0xad,0x96,0x8f,0xb3,0x89,0x1c,0xaf,0x86,0x32,0x56,0x57,0x3a,0x5b,0x3e,0xcc,0xa7,0xe9,0x8d,0x27,0x1c,0xe7,0x19,0xe0,0xe3,0xfd,0xf3,0x6c,0x36,0x91,0xe3,0x56,0xe0,0xdd,0x16,0x79,0x19,0x2,0x8,0x57,0x3c,0xfd,0xa9,0xd9,0x1f,0x74,0x23,0xa7,0xbe,0xe4,0x7a,0xe9,0x7,0xd2,0x78,0x94,0x9f,0x2e,0xf2,0xa1,0x8c,0xd5,0x68,0xeb,0xc6,0x2a,0xd1,0xff,0x5a,0x6d,0xe4,0x1b,0x83,0x27,0x93,0x7,0x1d,0x11,0x34,0xe5,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
-};
-
-
-static const unsigned char vscroll_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x24,0x11,0x6c,0x86,0xa1,0xf4,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,0x51,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x94,0x14,0x95,0x99,0xc6,0xc0,0xc0,0x90,0xc9,0x80,0x9,0xa6,0x33,0x30,0x30,0x64,0x31,0x4a,0x8a,0xca,0xfc,0x67,0x63,0x61,0x63,0xe0,0x60,0xe7,0x64,0x60,0x66,0x66,0x66,0x60,0x62,0x62,0x62,0x60,0x63,0x65,0x67,0x78,0xfe,0xfa,0x29,0xc3,0xd3,0x17,0x8f,0x44,0x99,0x18,0x8,0x80,0xc1,0xa0,0x80,0x85,0x81,0x81,0x61,0xfa,0xaf,0x3f,0xbf,0x32,0x7f,0xfd,0xf9,0x85,0xcd,0x9b,0x6f,0x0,0xae,0x38,0x11,0xcb,0x70,0x15,0x64,0xf2,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
-};
-
-
-static const unsigned char vscroll_bg_focus_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x24,0x1e,0xfc,0x39,0xbc,0x65,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,0x51,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x94,0x14,0x95,0x99,0xc6,0xc0,0xc0,0x90,0xc9,0x80,0x9,0xa6,0x33,0x30,0x30,0x64,0x31,0x4a,0x8a,0xca,0xfc,0x67,0x63,0x61,0x63,0xe0,0x60,0xe7,0x64,0x60,0x66,0x66,0x66,0x60,0x62,0x62,0x62,0x60,0x63,0x65,0x67,0x78,0xfe,0xfa,0x29,0xc3,0xd3,0x17,0x8f,0x44,0x99,0x18,0x8,0x80,0xc1,0xa0,0x80,0x85,0x81,0x81,0x61,0xfa,0xaf,0x3f,0xbf,0x32,0x7f,0xfd,0xf9,0x85,0xcd,0x9b,0x6f,0x0,0xae,0x38,0x11,0xcb,0x70,0x15,0x64,0xf2,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
-};
-
-
-static const unsigned char vscroll_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x27,0x14,0x37,0xc1,0x6,0xb8,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,0x9c,0x49,0x44,0x41,0x54,0x18,0xd3,0x7d,0x8f,0x3d,0xb,0x82,0x40,0x0,0x40,0x9f,0xe7,0x75,0x67,0x4,0x41,0x86,0xa1,0x20,0xcd,0x4d,0xd1,0x10,0xb4,0xf4,0xf3,0x5b,0x5a,0x83,0x86,0xa6,0x8,0xa2,0xec,0x73,0xca,0xf2,0x2e,0xb5,0x26,0xf,0x5a,0x7a,0xe3,0xe3,0x2d,0xcf,0x4b,0xa2,0xf4,0xd3,0xeb,0x86,0xe4,0xcf,0x7,0xb6,0xb4,0x48,0x29,0x1,0x28,0xcb,0x12,0xc0,0x93,0x0,0xf6,0x6d,0x18,0xf4,0x13,0xd2,0x78,0x88,0x56,0x1,0x9b,0xed,0x9a,0xec,0x7a,0x60,0x32,0x9a,0x22,0x0,0xa2,0x30,0x46,0xab,0x0,0x63,0xb,0x8c,0x2d,0x98,0x8d,0xe7,0x34,0x8,0x0,0x21,0x84,0x13,0x55,0x55,0xd1,0xd6,0x9d,0xdf,0xe0,0x1f,0x2,0xa0,0xae,0x6b,0x27,0x7c,0xdf,0xe7,0x65,0xf2,0xdf,0xe0,0x72,0xcf,0x30,0xb6,0x40,0xab,0x0,0xad,0x2,0x96,0xab,0x85,0xb,0x24,0x80,0x6a,0x69,0xce,0xb7,0x23,0xfb,0xd3,0xce,0x6d,0x36,0x7c,0x1,0xa3,0x8f,0x31,0x52,0x6,0xb1,0x57,0x8b,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
-};
-
-
-static const unsigned char vscroll_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,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x27,0x25,0x66,0x1f,0x6,0x82,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,0xa2,0x49,0x44,0x41,0x54,0x18,0xd3,0x7d,0x8f,0x3b,0xf,0xc1,0x50,0x0,0x46,0x8f,0xdb,0x56,0xef,0x65,0x32,0x78,0x4,0xd,0x91,0xe,0x46,0x83,0xc1,0x6a,0xf0,0xab,0xd,0x56,0x8b,0xc1,0x24,0x91,0x48,0xbc,0xe2,0x31,0x12,0xf4,0x5e,0x57,0xcb,0xa4,0xd2,0xc5,0x19,0x4f,0xce,0x37,0x7c,0xb9,0x76,0x23,0x7c,0x97,0x4b,0x15,0xae,0xb7,0xb,0xc6,0x1a,0x3c,0xcf,0x3,0xc0,0x5a,0x8b,0x79,0xea,0x9c,0xb,0x60,0x9e,0x9a,0x66,0xad,0x45,0x27,0x8,0x91,0x52,0x31,0x5f,0xcc,0xd8,0x1e,0xd7,0xf4,0xba,0x7d,0x4,0x40,0xbd,0x1a,0xa0,0xfc,0x2,0xda,0x44,0x68,0x1d,0x31,0x1c,0x8c,0xf8,0x22,0x0,0x84,0x70,0x52,0xf1,0x8a,0x63,0x94,0x2c,0x66,0x83,0x7f,0x8,0x80,0x24,0x89,0x53,0xe1,0x3a,0xe,0x91,0xbe,0x67,0x83,0xc3,0x79,0x47,0x64,0x1e,0x48,0x5f,0x21,0xa5,0x62,0x32,0x1d,0xff,0x6,0x0,0x7e,0x5e,0xb2,0x3f,0x6d,0x58,0xed,0x96,0xe9,0xcd,0x2f,0x1f,0x74,0x4f,0x34,0x2d,0xfc,0x9b,0x87,0x78,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,0x10,0x8,0x6,0x0,0x0,0x0,0x2b,0x8a,0x3e,0x7d,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,0x2a,0x25,0x8e,0xd3,0xb6,0x1b,0x0,0x0,0x0,0xfb,0x49,0x44,0x41,0x54,0x28,0x91,0x85,0x8f,0xbd,0x4a,0xc4,0x40,0x14,0x46,0xbf,0x4c,0x26,0xd3,0x4c,0x23,0x6c,0xa,0x83,0xb2,0xe0,0xb,0xd8,0x8,0xb6,0x62,0xe3,0x4b,0xf8,0xd3,0xed,0xcb,0xf8,0x14,0x92,0xbc,0xc5,0x16,0x5a,0xb,0x56,0xbe,0x80,0xd8,0x38,0x4b,0x98,0xc,0x97,0x4c,0x6,0x24,0x64,0x66,0x6c,0xb2,0xb2,0xc9,0xb2,0x7a,0xca,0x7b,0x4e,0x71,0x3f,0x60,0x7,0x6a,0x2c,0xe6,0xb0,0x89,0x4c,0x3d,0xd3,0x1b,0xda,0xf,0x46,0x29,0x42,0x8,0xa7,0xe0,0xc3,0x6a,0x37,0xe2,0x5b,0x19,0x63,0x5c,0x58,0x6b,0x3f,0x1,0x40,0x4a,0xf9,0xad,0x37,0x54,0xe5,0xc7,0x47,0x48,0x88,0x48,0xc4,0x18,0x17,0x6d,0xdb,0x7e,0x1,0xf0,0x0,0xd2,0x31,0x7a,0x80,0xe7,0x15,0xb,0x21,0x9c,0x8c,0x72,0x10,0x42,0x3c,0x4b,0x29,0x6f,0x1,0xc0,0x39,0x57,0x22,0x1d,0xee,0x78,0x8c,0xf1,0xc,0x0,0x84,0x10,0x2f,0x45,0x51,0xdc,0x0,0x80,0xd6,0x3a,0x75,0xce,0x95,0x21,0x84,0x73,0x10,0x51,0x6a,0x8c,0xb9,0x98,0xcf,0x6b,0x9a,0xe6,0x72,0x32,0xf3,0x10,0xcc,0x7b,0x7f,0x65,0xad,0x7d,0x53,0x4a,0xad,0xb7,0x47,0xad,0xf5,0x7d,0xd7,0x75,0xaf,0x75,0x5d,0x3f,0xf2,0x24,0x49,0x3e,0x0,0xa0,0xef,0xfb,0x6b,0xa5,0xd4,0x3a,0xcb,0xb2,0x27,0xe7,0x5c,0x9,0x0,0x8c,0xb1,0xf7,0x3f,0x67,0xe6,0x79,0x5e,0x25,0x0,0x30,0x8b,0x7e,0xe5,0xe4,0x19,0x22,0x12,0xc6,0x98,0xa5,0xd6,0x7a,0x75,0xf0,0x63,0x22,0xfa,0x77,0xd5,0x1e,0x3f,0x3b,0xb0,0x99,0x1,0x70,0x56,0xb8,0xf7,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -440,32 +480,32 @@ 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,0x4b,0x0,0x3f,0x0,0x52,0x7c,0x32,0x40,0x52,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,0xdd,0x9,0x1b,0x16,0x2b,0x31,0xd7,0x79,0x35,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,0xba,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x93,0x31,0x6a,0x2,0x51,0x14,0x45,0xcf,0x7f,0xff,0x39,0xa2,0x19,0x3,0x21,0x28,0xa,0xae,0x23,0xeb,0x9,0x76,0xb3,0x89,0x58,0x9,0xd9,0xc1,0x74,0x71,0x3f,0xb1,0xb1,0x73,0x3,0x8a,0xa0,0x84,0x14,0x13,0x23,0x84,0xef,0xfb,0xe9,0x44,0xe4,0x8b,0x4e,0xef,0x2d,0x2f,0xe7,0x9e,0xee,0x3a,0x12,0x19,0x74,0x87,0x6f,0x40,0x1,0xf4,0x81,0x15,0x50,0xae,0xb7,0xcb,0x49,0x8a,0x75,0x89,0xf1,0xab,0xf7,0x7e,0x9a,0x69,0x46,0xd6,0x68,0xa2,0xaa,0xfc,0xee,0x77,0xe4,0xed,0xc7,0xf7,0xf9,0x62,0x36,0x16,0x2f,0x7f,0xa7,0xbc,0x24,0xa4,0x85,0x73,0xe,0x11,0x41,0x44,0x70,0x8,0xf,0xad,0xe,0xdf,0xd5,0xd7,0x8,0xc8,0xcf,0xe1,0x94,0xe0,0x45,0x10,0xc4,0xf9,0x63,0xa1,0xaa,0x84,0x10,0x7a,0x29,0x3e,0x25,0xa8,0x95,0xbb,0xe0,0x2e,0xb8,0x24,0xf8,0x34,0xc,0x8b,0x87,0x63,0x11,0x42,0x40,0x55,0x37,0x80,0xdd,0x22,0x28,0x63,0x8c,0x98,0x19,0x66,0x46,0xc4,0xd8,0xed,0x2b,0x9e,0x3a,0xcf,0x1f,0xc0,0xcf,0xd5,0x37,0xd6,0xbd,0xf3,0x3f,0xe8,0xbb,0x37,0x1e,0x27,0x3c,0x2c,0x9e,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,0x4b,0x0,0x3f,0x0,0x52,0x7c,0x32,0x40,0x52,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,0xdd,0x9,0x1b,0x16,0x2a,0xf,0xf,0x3,0x19,0xc5,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,0xa7,0x49,0x44,0x41,0x54,0x38,0xcb,0xc5,0x93,0x3d,0x4c,0x14,0x41,0x18,0x86,0x9f,0x6f,0x66,0x5d,0xd8,0x2c,0x97,0x3b,0xee,0x64,0x4e,0x2e,0x78,0x86,0xd8,0x99,0xd8,0x5e,0x6c,0x24,0x26,0x56,0x36,0x26,0x26,0x5a,0x51,0x59,0xda,0x6a,0x3,0xad,0xd,0x34,0x5a,0x99,0xd0,0x58,0xd8,0x9f,0x15,0x8d,0x95,0x21,0xa1,0x32,0x86,0x10,0xa3,0x89,0x31,0x24,0xc4,0xe3,0xef,0xc0,0xe5,0x27,0x22,0x5e,0x56,0xf6,0x6e,0xf9,0x2c,0xe4,0x4e,0x90,0x43,0x4a,0xbe,0x62,0x32,0x33,0xc9,0xfb,0xce,0x3b,0xcf,0x37,0x3,0xe7,0x5d,0x52,0xa9,0x54,0x0,0xa8,0xd5,0x6a,0x9d,0xcd,0x7b,0xb7,0x46,0x6f,0x4e,0xcf,0x54,0x67,0xff,0xa3,0xdb,0x0,0xa6,0x52,0x49,0x9e,0xca,0xed,0x1b,0x77,0x0,0x78,0xfb,0xee,0xd,0xce,0x39,0xac,0xfa,0xf7,0xad,0xb5,0x55,0x97,0xbf,0xc4,0xc5,0x9c,0x43,0x44,0x10,0x31,0x88,0x11,0x8c,0x80,0x7f,0xa1,0x97,0x5c,0xa6,0x9f,0xf,0x5f,0xe6,0xd8,0xd8,0xaa,0x3f,0xb4,0x3,0xa5,0x3c,0x89,0xc6,0x34,0x9b,0x4d,0xac,0xfa,0x8f,0x3d,0xcf,0x7b,0x39,0x54,0xbc,0x42,0xb6,0xaf,0xff,0x50,0x2c,0x88,0x1,0x3,0x88,0x18,0x40,0x50,0x55,0x86,0x8a,0x65,0x16,0x57,0x16,0x4a,0xa6,0x9d,0xc9,0xaa,0x3f,0x11,0xf4,0x4,0xcf,0xca,0x83,0xc3,0x84,0x41,0x78,0x3c,0xb0,0xa,0x2a,0x7f,0x97,0xbf,0xf6,0x63,0xf2,0xd9,0x1,0x80,0x8a,0xc9,0x98,0x2,0x2b,0x5f,0xeb,0x13,0x61,0x10,0x8e,0x95,0x5c,0x19,0xdf,0xf3,0xff,0xc5,0x74,0x38,0xa,0xa0,0x27,0x60,0x78,0x9f,0x17,0x3f,0x3d,0xca,0xf6,0xe5,0xc6,0x8a,0x85,0x41,0x44,0xa4,0xb,0x2f,0xfd,0x23,0xd6,0x8e,0xd7,0xb1,0x32,0x80,0x3d,0xab,0x55,0xa,0xe8,0x29,0xe,0xe6,0xda,0xd5,0xeb,0x2f,0x76,0x7f,0x7e,0x9f,0x5c,0x8b,0x96,0x69,0xa5,0xe9,0xe9,0xfd,0xee,0x76,0x3c,0x60,0xf6,0xe,0xb6,0xb9,0x3c,0x5c,0x1a,0x6f,0xc4,0x8d,0xc9,0x7a,0xb4,0x4c,0xd2,0x4a,0xba,0x88,0x15,0x15,0xed,0x6e,0xd0,0x9e,0xa4,0x92,0x8c,0xc7,0xfb,0xf1,0x93,0xd5,0xf5,0x25,0x1a,0x71,0xe3,0xc4,0x15,0x8e,0x26,0xe8,0xed,0x9,0xd8,0xd9,0xdd,0x4,0x78,0x6f,0x32,0xa6,0x40,0xc6,0x14,0x88,0xa2,0x88,0x54,0x92,0xe7,0x49,0x2b,0x79,0xb0,0xfa,0x6d,0x89,0x9d,0x1f,0x5b,0x47,0x98,0x4b,0x87,0x82,0xb5,0x96,0x30,0x8,0xf9,0xb8,0x30,0xf,0x30,0xe5,0xed,0x1d,0x6c,0x3,0xe0,0x9c,0x6b,0x27,0x79,0x7d,0x77,0x64,0x74,0x64,0x7a,0xa6,0x3a,0xbb,0xbe,0xb9,0x76,0xd6,0x53,0x7e,0x75,0xee,0x9f,0x91,0xdf,0x78,0x37,0x8a,0xe3,0x79,0x7e,0x6,0x97,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,0x4b,0x0,0x3f,0x0,0x52,0x7c,0x32,0x40,0x52,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,0xdd,0x9,0x1b,0x16,0x2b,0x3,0x1f,0xae,0x64,0xaf,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,0xac,0x49,0x44,0x41,0x54,0x38,0xcb,0xc5,0x93,0xb1,0x6f,0xd3,0x40,0x14,0x87,0xbf,0x77,0x8e,0x5d,0x9c,0xc4,0x55,0xe3,0x10,0x43,0x4c,0xa1,0x44,0xa8,0x42,0xe2,0xf,0x88,0xba,0xc0,0x82,0x18,0x60,0x86,0xad,0xb,0x4b,0x25,0x56,0x58,0xda,0x95,0xa5,0x5d,0x60,0x42,0xea,0xc2,0x80,0xd4,0xad,0x65,0xcf,0xd4,0xa5,0x53,0x55,0x21,0x26,0x14,0x89,0x4a,0x55,0x1c,0x28,0x25,0xd,0x4,0x2a,0x92,0xd6,0xc4,0x86,0x1c,0x4b,0x13,0x1a,0x62,0x60,0xec,0x1b,0x9e,0xee,0x7e,0xa7,0xf7,0xf4,0xdd,0xef,0xdd,0xc1,0x69,0x87,0x94,0xcb,0x65,0x0,0x82,0x20,0x18,0x88,0xb3,0x77,0xe6,0xae,0xaf,0x56,0x56,0x36,0xfe,0x51,0xd7,0x0,0x96,0x23,0x1d,0x3e,0x96,0x9b,0x33,0xb7,0x1,0x58,0xdf,0xac,0xe0,0x79,0x1e,0x96,0xd8,0x77,0x8d,0x54,0x6a,0xad,0x78,0xf6,0x2,0x9e,0x7b,0x1e,0x11,0x41,0x44,0xa1,0xc,0x41,0x9,0x58,0xa6,0x4d,0x6e,0xdc,0xe5,0xd5,0x9b,0x4d,0x3e,0xec,0xbf,0xbb,0x6f,0x14,0x7c,0x97,0x48,0x87,0xc4,0x71,0x8c,0x25,0xf6,0x43,0xd3,0x34,0x9f,0x4f,0xf9,0x57,0xc8,0x39,0xee,0x71,0xb1,0x20,0xa,0x94,0x6,0x51,0xa,0x10,0xb4,0xd6,0x5c,0x2a,0x5e,0x66,0x3b,0xa8,0xfa,0xaa,0xcf,0x64,0x89,0xbd,0x98,0x3e,0x93,0x79,0x52,0x9a,0x9c,0x26,0x9b,0xce,0xe,0x3,0x6b,0x41,0xab,0xdf,0xdb,0xb0,0x1b,0x92,0x9f,0x28,0x0,0x94,0x95,0xa3,0xf2,0xec,0xd5,0xf7,0x17,0xb3,0x19,0x67,0xfe,0x62,0xb1,0xc4,0x98,0x69,0xfd,0x69,0xd3,0x71,0x16,0x40,0x8f,0x98,0x91,0x7a,0x5b,0xab,0x3e,0xc8,0x8d,0xbb,0xf3,0x7e,0x61,0x12,0x51,0x92,0xe0,0x97,0x46,0x21,0xd0,0x3,0x8c,0xd1,0x53,0x95,0x2c,0xf,0x47,0xf,0xd0,0xe8,0x1,0xcd,0x50,0x83,0xab,0xa5,0x6b,0xcf,0xbe,0x7e,0xfb,0xb2,0x54,0x6f,0xd4,0x88,0x7f,0xfc,0xfc,0xfb,0xbc,0x91,0x44,0x5d,0xb5,0x7b,0x2d,0xfc,0xa9,0x73,0xb,0x9d,0xc3,0xf6,0xd2,0xfb,0x8f,0x35,0xba,0x71,0x94,0x80,0xa9,0xd1,0x4a,0x27,0x37,0xe8,0x2f,0x22,0x1d,0x2e,0x1c,0x7d,0x3f,0x7c,0x54,0xdf,0xdd,0xa1,0x73,0xd4,0x19,0xb9,0xc2,0x49,0x2,0x7b,0xcc,0xa6,0x75,0xf0,0x9,0x60,0x4b,0x39,0x2a,0x8f,0xa3,0xf2,0x34,0x9b,0x4d,0x22,0x1d,0x3e,0xed,0xc6,0xdd,0x7b,0xc1,0xde,0xe,0x9f,0xf,0x9a,0x27,0x3c,0x97,0x81,0xb,0x86,0x61,0x90,0x49,0x67,0x79,0x5d,0xdd,0x2,0x58,0x4e,0xb5,0x7b,0x2d,0x0,0x3c,0xcf,0xeb,0x93,0xbc,0x9c,0xbd,0x35,0x77,0x63,0xb5,0xb2,0xb2,0xb1,0xdb,0xa8,0xff,0xef,0x29,0xbf,0x38,0xf5,0xcf,0xc8,0x2f,0x96,0x82,0x8d,0xc9,0x9c,0xd1,0x82,0x63,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
};
static const unsigned char vslider_tick_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x4,0x8,0x6,0x0,0x0,0x0,0x87,0xb4,0xbf,0xec,0x0,0x0,0x0,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xdb,0xb,0x4,0x17,0x21,0x6,0x30,0xa,0xe5,0x29,0x0,0x0,0x0,0x46,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0xa0,0x10,0x30,0xb6,0xd7,0xd6,0x56,0x72,0x73,0x73,0x33,0x70,0x73,0x73,0x33,0x3c,0xe1,0x97,0x6a,0xe7,0xe6,0xe2,0x66,0x28,0x9,0xf1,0xc0,0xaa,0xd8,0x22,0x34,0x9e,0x41,0xfa,0xcb,0x6b,0x43,0x13,0x13,0x63,0xf,0x98,0x1e,0x96,0x33,0x67,0xce,0xee,0x80,0x29,0x78,0xca,0x23,0x4a,0x8c,0xa5,0xaf,0x91,0xf5,0x50,0xc,0x0,0x35,0x9a,0x11,0x6d,0xa1,0xf1,0x5c,0x24,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,0x4,0x8,0x6,0x0,0x0,0x0,0x87,0xb4,0xbf,0xec,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,0x28,0x1f,0x7a,0xe9,0xd,0x2b,0x0,0x0,0x0,0x46,0x49,0x44,0x41,0x54,0x18,0x95,0x63,0x60,0xa0,0x10,0x30,0x36,0x35,0x35,0x55,0x72,0x73,0x73,0x33,0x70,0x73,0x73,0x33,0xbc,0xe4,0x12,0x6d,0xe7,0xe6,0xe2,0x66,0x28,0x9,0xf1,0xc0,0xaa,0xd8,0x22,0x34,0x9e,0x41,0xec,0xe7,0x7b,0x43,0x13,0x13,0x13,0xf,0x98,0x1e,0x96,0x33,0x67,0xce,0xec,0x80,0x29,0x78,0xc5,0x2e,0x48,0x8c,0xa5,0xaf,0x91,0xf5,0x50,0xc,0x0,0x36,0xc,0x11,0x6c,0x6d,0xa6,0x47,0xcd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char vsplit_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,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x3b,0x0,0x36,0x0,0x38,0x27,0x56,0x13,0x54,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,0xdb,0xc,0x1b,0x3,0x20,0x0,0x61,0x7,0xe1,0x28,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,0x7b,0x49,0x44,0x41,0x54,0x18,0xd3,0x4d,0x8c,0xc1,0xe,0xc2,0x30,0x14,0xc3,0x1c,0xe8,0x6f,0x22,0x2e,0xfc,0xbf,0x34,0xa4,0x6d,0x54,0xcd,0x6b,0x38,0x6c,0x82,0xf9,0x92,0x83,0x23,0xeb,0xf5,0x78,0xa6,0x7f,0x3a,0x21,0x48,0xe2,0x20,0x80,0x58,0xd7,0x95,0xb6,0x2c,0x6f,0x5c,0x86,0x5c,0xe,0x87,0x67,0xdb,0x76,0x9a,0x4,0x55,0x86,0x8,0x94,0xff,0x22,0x1c,0xd3,0x5c,0x13,0xbb,0xce,0xb4,0x90,0x72,0x4,0x2,0x35,0x43,0xb3,0x7,0x55,0x75,0xea,0x5f,0x9d,0x0,0x99,0xa1,0x55,0x15,0xbe,0x1c,0xae,0x4c,0x9b,0xe6,0x2a,0x66,0x99,0x20,0x8,0xe8,0x18,0x0,0x86,0x4d,0xeb,0xfd,0xc3,0xbe,0x77,0x44,0xb8,0xdd,0xee,0xff,0x3e,0x61,0x8c,0xc1,0x17,0xf5,0xc0,0x57,0xfd,0xb2,0x2f,0x89,0xfc,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,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,0xd,0x13,0x1b,0xd5,0xd9,0x6e,0x6b,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
};
static const unsigned char vsplitter_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0x49,0x62,0xf9,0xdf,0x0,0x0,0x0,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,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,0xdb,0xc,0x18,0xf,0x2c,0x3,0x4f,0x14,0xa9,0x14,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,0x36,0x49,0x44,0x41,0x54,0x48,0xc7,0x63,0x60,0x18,0x5,0xc,0xc,0xcb,0x66,0xcd,0xf9,0x9f,0x1d,0x9f,0xf4,0x7f,0x24,0xf2,0x99,0x18,0x18,0x18,0x18,0x8e,0x1e,0x3d,0xc6,0x70,0xf9,0xe6,0x75,0x78,0x80,0x8c,0x34,0xfe,0x28,0x18,0x2d,0x3,0x46,0xcb,0x80,0xd1,0x32,0x60,0xc4,0x2,0x0,0x41,0x33,0x3b,0x34,0xfe,0xbe,0xf2,0x77,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,0x8,0x8,0x6,0x0,0x0,0x0,0x49,0x62,0xf9,0xdf,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,0x27,0x31,0x21,0xa7,0x1c,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,0x0,0x38,0x49,0x44,0x41,0x54,0x48,0x89,0x63,0x60,0x18,0x5,0xc,0xc,0xb,0x16,0x2c,0xf8,0x9f,0x9a,0x9a,0xfa,0x7f,0x24,0xf2,0x99,0x18,0x18,0x18,0x18,0x8e,0x1e,0x3d,0xca,0x70,0xed,0xda,0x35,0x78,0x80,0x8c,0x34,0xfe,0x28,0x18,0xf1,0x60,0x30,0xe5,0x49,0x7a,0xf3,0x47,0xcb,0x80,0x91,0xe,0x0,0x53,0x40,0x3b,0xd4,0x11,0xa7,0x10,0x39,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
diff --git a/scene/resources/default_theme/toggle_off.png b/scene/resources/default_theme/toggle_off.png
index d5809cd72b..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 692e03b01d..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/tooltip_bg.png b/scene/resources/default_theme/tooltip_bg.png
index c61169f7fc..c5eb502ace 100644
--- a/scene/resources/default_theme/tooltip_bg.png
+++ b/scene/resources/default_theme/tooltip_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_bg.png b/scene/resources/default_theme/tree_bg.png
index e16317d348..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/tree_title.png b/scene/resources/default_theme/tree_title.png
index 7104085467..e7a158b961 100644
--- a/scene/resources/default_theme/tree_title.png
+++ b/scene/resources/default_theme/tree_title.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_title_pressed.png b/scene/resources/default_theme/tree_title_pressed.png
index ffba8e8fb1..82b49cdd2f 100644
--- a/scene/resources/default_theme/tree_title_pressed.png
+++ b/scene/resources/default_theme/tree_title_pressed.png
Binary files differ
diff --git a/scene/resources/default_theme/unchecked.png b/scene/resources/default_theme/unchecked.png
index 65b9ba4d23..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/updown.png b/scene/resources/default_theme/updown.png
index 8d4189cf1c..a5ca1212e0 100644
--- a/scene/resources/default_theme/updown.png
+++ b/scene/resources/default_theme/updown.png
Binary files differ
diff --git a/scene/resources/default_theme/vscroll_bg.png b/scene/resources/default_theme/vscroll_bg.png
deleted file mode 100644
index 18b79553b7..0000000000
--- a/scene/resources/default_theme/vscroll_bg.png
+++ /dev/null
Binary files differ
diff --git a/scene/resources/default_theme/vscroll_bg_focus.png b/scene/resources/default_theme/vscroll_bg_focus.png
deleted file mode 100644
index 30abdd0c98..0000000000
--- a/scene/resources/default_theme/vscroll_bg_focus.png
+++ /dev/null
Binary files differ
diff --git a/scene/resources/default_theme/vscroll_grabber.png b/scene/resources/default_theme/vscroll_grabber.png
deleted file mode 100644
index 81c9c58064..0000000000
--- a/scene/resources/default_theme/vscroll_grabber.png
+++ /dev/null
Binary files differ
diff --git a/scene/resources/default_theme/vscroll_grabber_hl.png b/scene/resources/default_theme/vscroll_grabber_hl.png
deleted file mode 100644
index a0cfa37ae1..0000000000
--- a/scene/resources/default_theme/vscroll_grabber_hl.png
+++ /dev/null
Binary files differ
diff --git a/scene/resources/default_theme/vslider_bg.png b/scene/resources/default_theme/vslider_bg.png
index d184e87aa4..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 dfb9578d5e..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 2c8e414b6f..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/vslider_tick.png b/scene/resources/default_theme/vslider_tick.png
index 17980a858c..76c5870dbc 100644
--- a/scene/resources/default_theme/vslider_tick.png
+++ b/scene/resources/default_theme/vslider_tick.png
Binary files differ
diff --git a/scene/resources/default_theme/vsplit_bg.png b/scene/resources/default_theme/vsplit_bg.png
index 353ff8960c..f4e1715447 100644
--- a/scene/resources/default_theme/vsplit_bg.png
+++ b/scene/resources/default_theme/vsplit_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/vsplitter.png b/scene/resources/default_theme/vsplitter.png
index 255995fdb4..4a9904a3ec 100644
--- a/scene/resources/default_theme/vsplitter.png
+++ b/scene/resources/default_theme/vsplitter.png
Binary files differ
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index df18e4f0f5..ffa02e819c 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -108,13 +108,14 @@ void Environment::_bind_methods() {
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"fxaa/enabled"),_SCS("set_enable_fx"),_SCS("is_fx_enabled"), FX_FXAA);
- ADD_PROPERTY( PropertyInfo(Variant::INT,"background/mode",PROPERTY_HINT_ENUM,"Keep,Default Color,Color,Texture,Cubemap,Texture RGBE,Cubemap RGBE"),_SCS("set_background"),_SCS("get_background"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"background/mode",PROPERTY_HINT_ENUM,"Keep,Default Color,Color,Texture,Cubemap,Canvas"),_SCS("set_background"),_SCS("get_background"));
ADD_PROPERTYI( PropertyInfo(Variant::COLOR,"background/color"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_COLOR);
ADD_PROPERTYI( PropertyInfo(Variant::OBJECT,"background/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_TEXTURE);
- ADD_PROPERTYI( PropertyInfo(Variant::OBJECT,"background/cubemap",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_CUBEMAP);
+ ADD_PROPERTYI( PropertyInfo(Variant::OBJECT,"background/cubemap",PROPERTY_HINT_RESOURCE_TYPE,"CubeMap"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_CUBEMAP);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"background/energy",PROPERTY_HINT_RANGE,"0,128,0.01"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_ENERGY);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"background/scale",PROPERTY_HINT_RANGE,"0.001,16,0.001"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_SCALE);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"background/glow",PROPERTY_HINT_RANGE,"0.00,8,0.01"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_GLOW);
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"background/canvas_max_layer"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_CANVAS_MAX_LAYER);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"glow/enabled"),_SCS("set_enable_fx"),_SCS("is_fx_enabled"), FX_GLOW);
ADD_PROPERTYI( PropertyInfo(Variant::INT,"glow/blur_passes",PROPERTY_HINT_RANGE,"1,4,1"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GLOW_BLUR_PASSES);
@@ -182,10 +183,10 @@ void Environment::_bind_methods() {
BIND_CONSTANT( BG_COLOR );
BIND_CONSTANT( BG_TEXTURE );
BIND_CONSTANT( BG_CUBEMAP );
- BIND_CONSTANT( BG_TEXTURE_RGBE );
- BIND_CONSTANT( BG_CUBEMAP_RGBE );
+ BIND_CONSTANT( BG_CANVAS );
BIND_CONSTANT( BG_MAX );
+ BIND_CONSTANT( BG_PARAM_CANVAS_MAX_LAYER );
BIND_CONSTANT( BG_PARAM_COLOR );
BIND_CONSTANT( BG_PARAM_TEXTURE );
BIND_CONSTANT( BG_PARAM_CUBEMAP );
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index a9e2f422b9..bee45b78cd 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -44,14 +44,14 @@ public:
BG_COLOR=VS::ENV_BG_COLOR,
BG_TEXTURE=VS::ENV_BG_TEXTURE,
BG_CUBEMAP=VS::ENV_BG_CUBEMAP,
- BG_TEXTURE_RGBE=VS::ENV_BG_TEXTURE_RGBE,
- BG_CUBEMAP_RGBE=VS::ENV_BG_CUBEMAP_RGBE,
+ BG_CANVAS=VS::ENV_BG_CANVAS,
BG_MAX=VS::ENV_BG_MAX
};
enum BGParam {
- BG_PARAM_COLOR=VS::ENV_BG_PARAM_COLOR,
+ BG_PARAM_CANVAS_MAX_LAYER=VS::ENV_BG_PARAM_CANVAS_MAX_LAYER,
+ BG_PARAM_COLOR=VS::ENV_BG_PARAM_COLOR,
BG_PARAM_TEXTURE=VS::ENV_BG_PARAM_TEXTURE,
BG_PARAM_CUBEMAP=VS::ENV_BG_PARAM_CUBEMAP,
BG_PARAM_ENERGY=VS::ENV_BG_PARAM_ENERGY,
diff --git a/scene/resources/event_stream.cpp b/scene/resources/event_stream.cpp
index d7ecfe1aba..e8cd08c064 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,10 +32,12 @@
Error EventStreamPlayback::play() {
if (stream.is_valid())
stop();
+
Error err = _play();
if (err)
return err;
+
playing=true;
AudioServer::get_singleton()->stream_set_active(stream,true);
diff --git a/scene/resources/event_stream.h b/scene/resources/event_stream.h
index 0f70adb4af..f9a5e3785a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 49ee3ee017..aad5e7cfdd 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -398,6 +398,17 @@ int Font::get_kerning_pair(CharType p_A,CharType p_B) const {
return 0;
}
+void Font::set_distance_field_hint(bool p_distance_field) {
+
+ distance_field_hint=p_distance_field;
+ emit_changed();
+}
+
+bool Font::is_distance_field_hint() const{
+
+ return distance_field_hint;
+}
+
void Font::clear() {
@@ -406,6 +417,7 @@ void Font::clear() {
char_map.clear();
textures.clear();
kerning_map.clear();
+ distance_field_hint=false;
}
Size2 Font::get_string_size(const String& p_string) const {
@@ -450,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);
}
}
@@ -482,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;
@@ -496,8 +496,19 @@ 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);
ObjectTypeDB::bind_method(_MD("set_height","px"),&Font::set_height);
ObjectTypeDB::bind_method(_MD("get_height"),&Font::get_height);
@@ -511,9 +522,16 @@ void Font::_bind_methods() {
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));
+
+ ObjectTypeDB::bind_method(_MD("get_texture_count"),&Font::get_texture_count);
+ ObjectTypeDB::bind_method(_MD("get_texture:Texture","idx"),&Font::get_texture);
+
ObjectTypeDB::bind_method(_MD("get_char_size","char","next"),&Font::get_char_size,DEFVAL(0));
ObjectTypeDB::bind_method(_MD("get_string_size","string"),&Font::get_string_size);
+ ObjectTypeDB::bind_method(_MD("set_distance_field_hint","enable"),&Font::set_distance_field_hint);
+ ObjectTypeDB::bind_method(_MD("is_distance_field_hint"),&Font::is_distance_field_hint);
+
ObjectTypeDB::bind_method(_MD("clear"),&Font::clear);
ObjectTypeDB::bind_method(_MD("draw","canvas_item","pos","string","modulate","clip_w"),&Font::draw,DEFVAL(Color(1,1,1)),DEFVAL(-1));
@@ -528,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") );
@@ -535,12 +555,15 @@ 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") );
}
Font::Font() {
clear();
+
}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index a64ec1ef7a..27e3045eaa 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -75,6 +75,7 @@ private:
float height;
float ascent;
+ bool distance_field_hint;
void _set_chars(const DVector<int>& p_chars);
DVector<int> _get_chars() const;
@@ -83,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();
@@ -112,10 +114,17 @@ 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);
+ bool is_distance_field_hint() const;
void draw(RID p_canvas_item, const Point2& p_pos, const String& p_text,const Color& p_modulate=Color(1,1,1),int p_clip_w=-1) const;
void draw_halign(RID p_canvas_item, const Point2& p_pos, HAlign p_align,float p_width,const String& p_text,const Color& p_modulate=Color(1,1,1)) const;
@@ -130,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 5dc73fc98a..7af81bd992 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 1e7905d05f..77393db9f4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 bbaa6fc1b6..2c7c5384fa 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/height_map_shape.h b/scene/resources/height_map_shape.h
index 898068888d..46d49dab08 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/image_path_finder.cpp b/scene/resources/image_path_finder.cpp
deleted file mode 100644
index 1a7758789c..0000000000
--- a/scene/resources/image_path_finder.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/*************************************************************************/
-/* image_path_finder.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "image_path_finder.h"
-
-
-void ImagePathFinder::_unlock() {
-
- lock=DVector<Cell>::Write();
- cells=NULL;
-
-}
-
-void ImagePathFinder::_lock() {
-
- lock = cell_data.write();
- cells=lock.ptr();
-
-}
-
-
-bool ImagePathFinder::_can_go_straigth(const Point2& p_from, const Point2& p_to) const {
-
- int x1=p_from.x;
- int y1=p_from.y;
- int x2=p_to.x;
- int y2=p_to.y;
-
-#define _TEST_VALID \
- {\
- uint32_t ofs=drawy*width+drawx;\
- if (cells[ofs].solid) {\
- if (!((drawx>0 && cells[ofs-1].visited) ||\
- (drawx<width-1 && cells[ofs+1].visited) ||\
- (drawy>0 && cells[ofs-width].visited) ||\
- (drawy<height-1 && cells[ofs+width].visited))) {\
- return false;\
- }\
- }\
- }\
-
-
- int n, deltax, deltay, sgndeltax, sgndeltay, deltaxabs, deltayabs, x, y, drawx, drawy;
- deltax = x2 - x1;
- deltay = y2 - y1;
- deltaxabs = ABS(deltax);
- deltayabs = ABS(deltay);
- sgndeltax = SGN(deltax);
- sgndeltay = SGN(deltay);
- x = deltayabs >> 1;
- y = deltaxabs >> 1;
- drawx = x1;
- drawy = y1;
- int pc=0;
-
- _TEST_VALID
-
- if(deltaxabs >= deltayabs) {
- for(n = 0; n < deltaxabs; n++) {
- y += deltayabs;
- if(y >= deltaxabs){
- y -= deltaxabs;
- drawy += sgndeltay;
- }
- drawx += sgndeltax;
- _TEST_VALID
- }
- } else {
- for(n = 0; n < deltayabs; n++) {
- x += deltaxabs;
- if(x >= deltayabs) {
- x -= deltayabs;
- drawx += sgndeltax;
- }
- drawy += sgndeltay;
- _TEST_VALID
- }
- }
- return true;
-
-
-}
-
-bool ImagePathFinder::_is_linear_path(const Point2& p_from, const Point2& p_to) {
-
- int x1=p_from.x;
- int y1=p_from.y;
- int x2=p_to.x;
- int y2=p_to.y;
-
-#define _TEST_CELL \
- if (cells[drawy*width+drawx].solid)\
- return false;
-
-
- int n, deltax, deltay, sgndeltax, sgndeltay, deltaxabs, deltayabs, x, y, drawx, drawy;
- deltax = x2 - x1;
- deltay = y2 - y1;
- deltaxabs = ABS(deltax);
- deltayabs = ABS(deltay);
- sgndeltax = SGN(deltax);
- sgndeltay = SGN(deltay);
- x = deltayabs >> 1;
- y = deltaxabs >> 1;
- drawx = x1;
- drawy = y1;
- int pc=0;
-
- _TEST_CELL
-
- if(deltaxabs >= deltayabs) {
- for(n = 0; n < deltaxabs; n++) {
- y += deltayabs;
- if(y >= deltaxabs){
- y -= deltaxabs;
- drawy += sgndeltay;
- }
- drawx += sgndeltax;
- _TEST_CELL
- }
- } else {
- for(n = 0; n < deltayabs; n++) {
- x += deltaxabs;
- if(x >= deltayabs) {
- x -= deltayabs;
- drawx += sgndeltax;
- }
- drawy += sgndeltay;
- _TEST_CELL
- }
- }
- return true;
-}
-
-
-DVector<Point2> ImagePathFinder::find_path(const Point2& p_from, const Point2& p_to,bool p_optimize) {
-
-
- Point2i from=p_from;
- Point2i to=p_to;
-
- ERR_FAIL_COND_V(from.x < 0,DVector<Point2>());
- ERR_FAIL_COND_V(from.y < 0,DVector<Point2>());
- ERR_FAIL_COND_V(from.x >=width,DVector<Point2>());
- ERR_FAIL_COND_V(from.y >=height,DVector<Point2>());
- ERR_FAIL_COND_V(to.x < 0,DVector<Point2>());
- ERR_FAIL_COND_V(to.y < 0,DVector<Point2>());
- ERR_FAIL_COND_V(to.x >=width,DVector<Point2>());
- ERR_FAIL_COND_V(to.y >=height,DVector<Point2>());
-
- if (from==to) {
- DVector<Point2> p;
- p.push_back(from);
- return p;
- }
-
- _lock();
-
-
- if (p_optimize) { //try a line first
-
- if (_is_linear_path(p_from,p_to)) {
- _unlock();
- DVector<Point2> p;
- p.push_back(from);
- p.push_back(to);
- return p;
- }
- }
-
-
- //clear all
- for(int i=0;i<width*height;i++) {
-
- bool s = cells[i].solid;
- cells[i].data=0;
- cells[i].solid=s;
- }
-
-#define CELL_INDEX(m_p) (m_p.y*width+m_p.x)
-#define CELL_COST(m_p) (cells[CELL_INDEX(m_p)].cost+( ABS(m_p.x-to.x)+ABS(m_p.y-to.y))*10)
-
-
- Set<Point2i> pending;
- pending.insert(from);
-
- //helper constants
- static const Point2i neighbour_rel[8]={
- Point2i(-1,-1), //0
- Point2i(-1, 0), //1
- Point2i(-1,+1), //2
- Point2i( 0,-1), //3
- Point2i( 0,+1), //4
- Point2i(+1,-1), //5
- Point2i(+1, 0), //6
- Point2i(+1,+1) }; //7
-
- static const int neighbour_cost[8]={
- 14,
- 10,
- 14,
- 10,
- 10,
- 14,
- 10,
- 14
- };
-
- static const int neighbour_parent[8]={
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- };
-
- while(true) {
-
- if (pending.size() == 0) {
- _unlock();
- return DVector<Point2>(); // points don't connect
- }
- Point2i current;
- int lc=0x7FFFFFFF;
- { //find the one with the least cost
-
- Set<Point2i>::Element *Efound=NULL;
- for (Set<Point2i>::Element *E=pending.front();E;E=E->next()) {
-
- int cc =CELL_COST(E->get());
- if (cc<lc) {
- lc=cc;
- current=E->get();
- Efound=E;
-
- }
-
- }
- pending.erase(Efound);
- }
-
- Cell &c = cells[CELL_INDEX(current)];
-
- //search around other cells
-
-
- int accum_cost = (from==current) ? 0 : cells[CELL_INDEX((current + neighbour_rel[c.parent]))].cost;
-
- bool done=false;
-
- for(int i=0;i<8;i++) {
-
- Point2i neighbour=current+neighbour_rel[i];
- if (neighbour.x<0 || neighbour.y<0 || neighbour.x>=width || neighbour.y>=height)
- continue;
-
- Cell &n = cells[CELL_INDEX(neighbour)];
- if (n.solid)
- continue; //no good
-
- int cost = neighbour_cost[i]+accum_cost;
-
- if (n.visited && n.cost < cost)
- continue;
-
- n.cost=cost;
- n.parent=neighbour_parent[i];
- n.visited=true;
- pending.insert(neighbour);
- if (neighbour==to)
- done=true;
-
- }
-
- if (done)
- break;
- }
-
-
- // go througuh poins twice, first compute amount, then add them
-
- Point2i current=to;
- int pcount=0;
-
- while(true) {
-
- Cell &c = cells[CELL_INDEX(current)];
- c.visited=true;
- pcount++;
- if (current==from)
- break;
- current+=neighbour_rel[ c.parent ];
- }
-
- //now place them in an array
- DVector<Vector2> result;
- result.resize(pcount);
-
- DVector<Vector2>::Write res=result.write();
-
- current=to;
- int pidx=pcount-1;
-
- while(true) {
-
- Cell &c = cells[CELL_INDEX(current)];
- res[pidx]=current;
- pidx--;
- if (current==from)
- break;
- current+=neighbour_rel[ c.parent ];
- }
-
-
- //simplify..
-
-
- if (p_optimize) {
-
- int p=pcount-1;
- while(p>0) {
-
-
- int limit=p;
- while(limit>0) {
-
- limit--;
- if (!_can_go_straigth(res[p],res[limit]))
- break;
- }
-
-
- if (limit<p-1) {
- int diff = p-limit-1;
- pcount-=diff;
- for(int i=limit+1;i<pcount;i++) {
-
- res[i]=res[i+diff];
- }
- }
- p=limit;
- }
- }
-
- res=DVector<Vector2>::Write();
- result.resize(pcount);
- return result;
-}
-
-Size2 ImagePathFinder::get_size() const {
-
- return Size2(width,height);
-}
-bool ImagePathFinder::is_solid(const Point2& p_pos) {
-
-
- Point2i pos = p_pos;
-
- ERR_FAIL_COND_V(pos.x<0,true);
- ERR_FAIL_COND_V(pos.y<0,true);
- ERR_FAIL_COND_V(pos.x>=width,true);
- ERR_FAIL_COND_V(pos.y>=height,true);
-
- return cell_data[pos.y*width+pos.x].solid;
-}
-
-void ImagePathFinder::create_from_image_alpha(const Image& p_image) {
-
- ERR_FAIL_COND(p_image.get_format() != Image::FORMAT_RGBA);
- width = p_image.get_width();
- height = p_image.get_height();
- DVector<uint8_t> data = p_image.get_data();
- cell_data.resize(width * height);
- DVector<uint8_t>::Read read = data.read();
- DVector<Cell>::Write write = cell_data.write();
- for (int i=0; i<width * height; i++) {
- Cell cell;
- cell.data = 0;
- cell.solid = read[i*4+3] < 128;
- write[i] = cell;
- };
-};
-
-
-void ImagePathFinder::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("find_path","from","to","optimize"),&ImagePathFinder::find_path,DEFVAL(false));
- ObjectTypeDB::bind_method(_MD("get_size"),&ImagePathFinder::get_size);
- ObjectTypeDB::bind_method(_MD("is_solid","pos"),&ImagePathFinder::is_solid);
- ObjectTypeDB::bind_method(_MD("create_from_image_alpha"),&ImagePathFinder::create_from_image_alpha);
-}
-
-ImagePathFinder::ImagePathFinder()
-{
-
- cells=NULL;
- width=0;
- height=0;
-}
diff --git a/scene/resources/image_path_finder.h b/scene/resources/image_path_finder.h
deleted file mode 100644
index e975ea5ed9..0000000000
--- a/scene/resources/image_path_finder.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*************************************************************************/
-/* image_path_finder.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef IMAGE_PATH_FINDER_H
-#define IMAGE_PATH_FINDER_H
-
-#include "resource.h"
-
-class ImagePathFinder : public Resource{
-
-
- OBJ_TYPE(ImagePathFinder,Resource);
- union Cell {
-
- struct {
- bool solid:1;
- bool visited:1;
- bool final:1;
- uint8_t parent:3;
- uint32_t cost:26;
- };
-
- uint32_t data;
- };
-
-
-
-
-
- DVector<Cell>::Write lock;
- DVector<Cell> cell_data;
-
- uint32_t width;
- uint32_t height;
- Cell* cells; //when unlocked
-
- void _unlock();
- void _lock();
-
-
- _FORCE_INLINE_ bool _can_go_straigth(const Point2& p_from, const Point2& p_to) const;
- _FORCE_INLINE_ bool _is_linear_path(const Point2& p_from, const Point2& p_to);
-
-protected:
-
- static void _bind_methods();
-public:
-
- DVector<Point2> find_path(const Point2& p_from, const Point2& p_to,bool p_optimize=false);
- Size2 get_size() const;
- bool is_solid(const Point2& p_pos);
- void create_from_image_alpha(const Image& p_image);
-
-
-
- ImagePathFinder();
-};
-
-#endif // IMAGE_PATH_FINDER_H
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 2314926b2b..55bb4e9073 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,7 +36,8 @@ static const char*_flag_names[Material::FLAG_MAX]={
"invert_faces",
"unshaded",
"on_top",
- "lightmap_on_uv2"
+ "lightmap_on_uv2",
+ "colarray_is_srgb"
};
@@ -46,7 +47,8 @@ static const Material::Flag _flag_indices[Material::FLAG_MAX]={
Material::FLAG_INVERT_FACES,
Material::FLAG_UNSHADED,
Material::FLAG_ONTOP,
- Material::FLAG_LIGHTMAP_ON_UV2
+ Material::FLAG_LIGHTMAP_ON_UV2,
+ Material::FLAG_COLOR_ARRAY_SRGB,
};
@@ -132,6 +134,8 @@ void Material::_bind_methods() {
BIND_CONSTANT( FLAG_INVERT_FACES );
BIND_CONSTANT( FLAG_UNSHADED );
BIND_CONSTANT( FLAG_ONTOP );
+ BIND_CONSTANT( FLAG_LIGHTMAP_ON_UV2 );
+ BIND_CONSTANT( FLAG_COLOR_ARRAY_SRGB );
BIND_CONSTANT( FLAG_MAX );
BIND_CONSTANT( DEPTH_DRAW_ALWAYS );
@@ -156,6 +160,8 @@ Material::Material(const RID& p_material) {
flags[FLAG_INVERT_FACES]=false;
flags[FLAG_UNSHADED]=false;
flags[FLAG_ONTOP]=false;
+ flags[FLAG_LIGHTMAP_ON_UV2]=true;
+ flags[FLAG_COLOR_ARRAY_SRGB]=false;
depth_draw_mode=DEPTH_DRAW_OPAQUE_ONLY;
@@ -316,14 +322,14 @@ Transform FixedMaterial::get_uv_transform() const {
void FixedMaterial::set_fixed_flag(FixedFlag p_flag, bool p_value) {
- ERR_FAIL_INDEX(p_flag,4);
+ ERR_FAIL_INDEX(p_flag,5);
fixed_flags[p_flag]=p_value;
VisualServer::get_singleton()->fixed_material_set_flag(material,(VS::FixedMaterialFlags)p_flag,p_value);
}
bool FixedMaterial::get_fixed_flag(FixedFlag p_flag) const {
- ERR_FAIL_INDEX_V(p_flag,4,false);
+ ERR_FAIL_INDEX_V(p_flag,5,false);
return fixed_flags[p_flag];
}
@@ -371,6 +377,7 @@ void FixedMaterial::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_color_array" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_COLOR_ARRAY);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_point_size" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_POINT_SIZE);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/discard_alpha" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_DISCARD_ALPHA);
+ ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_xy_normalmap" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_XY_NORMALMAP);
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/diffuse" ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_DIFFUSE);
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/specular", PROPERTY_HINT_COLOR_NO_ALPHA ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPECULAR );
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/emission", PROPERTY_HINT_COLOR_NO_ALPHA ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_EMISSION );
@@ -399,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 );
@@ -410,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 );
+
}
@@ -426,11 +437,14 @@ FixedMaterial::FixedMaterial() : Material(VS::get_singleton()->fixed_material_cr
param[PARAM_SHADE_PARAM]=0.5;
param[PARAM_DETAIL]=1.0;
-
+ set_flag(FLAG_COLOR_ARRAY_SRGB,true);
fixed_flags[FLAG_USE_ALPHA]=false;
fixed_flags[FLAG_USE_COLOR_ARRAY]=false;
fixed_flags[FLAG_USE_POINT_SIZE]=false;
+ fixed_flags[FLAG_USE_XY_NORMALMAP]=false;
+ fixed_flags[FLAG_DISCARD_ALPHA]=false;
+
for(int i=0;i<PARAM_MAX;i++) {
@@ -448,6 +462,8 @@ FixedMaterial::~FixedMaterial() {
}
+
+
bool ShaderMaterial::_set(const StringName& p_name, const Variant& p_value) {
if (p_name==SceneStringNames::get_singleton()->shader_shader) {
@@ -455,10 +471,20 @@ bool ShaderMaterial::_set(const StringName& p_name, const Variant& p_value) {
return true;
} else {
- String n = p_name;
- if (n.begins_with("param/")) {
- VisualServer::get_singleton()->material_set_param(material,String(n.ptr()+6),p_value);
- return true;
+ if (shader.is_valid()) {
+
+
+ StringName pr = shader->remap_param(p_name);
+ if (!pr) {
+ String n = p_name;
+ if (n.find("param/")==0) { //backwards compatibility
+ pr = n.substr(6,n.length());
+ }
+ }
+ if (pr) {
+ VisualServer::get_singleton()->material_set_param(material,pr,p_value);
+ return true;
+ }
}
}
@@ -474,10 +500,13 @@ bool ShaderMaterial::_get(const StringName& p_name,Variant &r_ret) const {
return true;
} else {
- String n = p_name;
- if (n.begins_with("param/")) {
- r_ret=VisualServer::get_singleton()->material_get_param(material,String(n.ptr()+6));
- return true;
+ if (shader.is_valid()) {
+
+ StringName pr = shader->remap_param(p_name);
+ if (pr) {
+ r_ret=VisualServer::get_singleton()->material_get_param(material,pr);
+ return true;
+ }
}
}
@@ -489,7 +518,7 @@ bool ShaderMaterial::_get(const StringName& p_name,Variant &r_ret) const {
void ShaderMaterial::_get_property_list( List<PropertyInfo> *p_list) const {
- p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"Shader" ) );
+ p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"MaterialShader,MaterialShaderGraph" ) );
if (!shader.is_null()) {
@@ -509,7 +538,7 @@ void ShaderMaterial::set_shader(const Ref<Shader>& p_shader) {
if (shader.is_valid())
shader->disconnect(SceneStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->_shader_changed);
shader=p_shader;
- VS::get_singleton()->material_set_shader(material,shader->get_rid());
+ VS::get_singleton()->material_set_shader(material,shader.is_valid()?shader->get_rid():RID());
if (shader.is_valid()) {
shader->connect(SceneStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->_shader_changed);
}
@@ -540,124 +569,34 @@ 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("_shader_changed"), &ShaderMaterial::_shader_changed );
-}
-
-
-
-
-ShaderMaterial::ShaderMaterial() :Material(VisualServer::get_singleton()->material_create()){
-
-
-}
-
-
-/////////////////////////////////
-
-void ParticleSystemMaterial::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_texture","texture"),&ParticleSystemMaterial::set_texture);
- ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&ParticleSystemMaterial::get_texture);
-
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture" ), _SCS("set_texture"), _SCS("get_texture"));
-
-}
-
-void ParticleSystemMaterial::set_texture(const Ref<Texture>& p_texture) {
- texture=p_texture;
- RID rid;
- if (texture.is_valid())
- rid=texture->get_rid();
-
- VS::get_singleton()->fixed_material_set_texture(material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,rid);
-}
-
-Ref<Texture> ParticleSystemMaterial::get_texture() const {
-
- return texture;
-}
-
-ParticleSystemMaterial::ParticleSystemMaterial() :Material(VisualServer::get_singleton()->fixed_material_create()){
-
- set_flag(FLAG_DOUBLE_SIDED,true);
- set_flag(FLAG_UNSHADED,true);
- set_depth_draw_mode(DEPTH_DRAW_NEVER);
- VisualServer::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
- VisualServer::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
-}
-
-ParticleSystemMaterial::~ParticleSystemMaterial() {
-
-
-}
-
-//////////////////////////////
-
-
-
-void UnshadedMaterial::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_texture","texture"),&UnshadedMaterial::set_texture);
- ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&UnshadedMaterial::get_texture);
-
- ObjectTypeDB::bind_method(_MD("set_use_alpha","enable"),&UnshadedMaterial::set_use_alpha);
- ObjectTypeDB::bind_method(_MD("is_using_alpha"),&UnshadedMaterial::is_using_alpha);
-
- ObjectTypeDB::bind_method(_MD("set_use_color_array","enable"),&UnshadedMaterial::set_use_color_array);
- ObjectTypeDB::bind_method(_MD("is_using_color_array"),&UnshadedMaterial::is_using_color_array);
-
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture" ), _SCS("set_texture"), _SCS("get_texture"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "alpha" ), _SCS("set_use_alpha"), _SCS("is_using_alpha"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "color_array" ), _SCS("set_use_color_array"), _SCS("is_using_color_array"));
-
-}
-
-void UnshadedMaterial::set_texture(const Ref<Texture>& p_texture) {
- RID rid;
- if (texture.is_valid())
- rid=texture->get_rid();
-
- VS::get_singleton()->fixed_material_set_texture(material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,rid);
-}
-Ref<Texture> UnshadedMaterial::get_texture() const {
-
- return texture;
-}
-
-void UnshadedMaterial::set_use_alpha(bool p_use_alpha) {
-
- alpha=p_use_alpha;
- VS::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_ALPHA,p_use_alpha);
- //set_depth_draw_mode();
- //set_hint(HINT,p_use_alpha);
+ 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("_shader_changed"), &ShaderMaterial::_shader_changed );
}
-bool UnshadedMaterial::is_using_alpha() const{
-
- return alpha;
-}
-void UnshadedMaterial::set_use_color_array(bool p_use_color_array){
+void ShaderMaterial::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
- color_array=p_use_color_array;
- VS::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,p_use_color_array);
+ String f = p_function.operator String();
+ if ((f=="get_shader_param" || f=="set_shader_param") && p_idx==0) {
+ if (shader.is_valid()) {
+ List<PropertyInfo> pl;
+ shader->get_param_list(&pl);
+ for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
+ r_options->push_back("\""+E->get().name.replace_first("shader_param/","")+"\"");
+ }
+ }
+ }
+ Material::get_argument_options(p_function,p_idx,r_options);
}
-bool UnshadedMaterial::is_using_color_array() const{
-
- return color_array;
-}
+ShaderMaterial::ShaderMaterial() :Material(VisualServer::get_singleton()->material_create()){
-UnshadedMaterial::UnshadedMaterial() :Material(VisualServer::get_singleton()->fixed_material_create()){
- set_flag(FLAG_UNSHADED,true);
- set_use_alpha(true);
}
-UnshadedMaterial::~UnshadedMaterial() {
-
-}
+/////////////////////////////////
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 23ecb18fac..7b7bc50567 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -54,6 +54,7 @@ public:
FLAG_UNSHADED = VS::MATERIAL_FLAG_UNSHADED,
FLAG_ONTOP = VS::MATERIAL_FLAG_ONTOP,
FLAG_LIGHTMAP_ON_UV2 = VS::MATERIAL_FLAG_LIGHTMAP_ON_UV2,
+ FLAG_COLOR_ARRAY_SRGB = VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB,
FLAG_MAX = VS::MATERIAL_FLAG_MAX
};
@@ -141,7 +142,9 @@ public:
FLAG_USE_ALPHA=VS::FIXED_MATERIAL_FLAG_USE_ALPHA,
FLAG_USE_COLOR_ARRAY=VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,
FLAG_USE_POINT_SIZE=VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE,
- FLAG_DISCARD_ALPHA=VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA
+ FLAG_DISCARD_ALPHA=VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA,
+ FLAG_USE_XY_NORMALMAP=VS::FIXED_MATERIAL_FLAG_USE_XY_NORMALMAP,
+ FLAG_MAX=VS::FIXED_MATERIAL_FLAG_MAX
};
enum LightShader {
@@ -166,7 +169,7 @@ private:
Ref<Texture> texture_param[PARAM_MAX];
TexCoordMode texture_texcoord[PARAM_MAX];
LightShader light_shader;
- bool fixed_flags[3];
+ bool fixed_flags[FLAG_MAX];
float point_size;
@@ -240,6 +243,7 @@ public:
void set_shader_param(const StringName& p_param,const Variant& p_value);
Variant get_shader_param(const StringName& p_param) const;
+ void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
ShaderMaterial();
};
@@ -249,68 +253,6 @@ public:
-class ParticleSystemMaterial : public Material {
-
- OBJ_TYPE( ParticleSystemMaterial, Material );
- REVERSE_GET_PROPERTY_LIST
-
-private:
-
-
-
- Ref<Texture> texture;
-
-protected:
-
-
- static void _bind_methods();
-
-public:
-
- void set_texture(const Ref<Texture>& p_texture);
- Ref<Texture> get_texture() const;
-
-
- ParticleSystemMaterial();
- ~ParticleSystemMaterial();
-
-};
-
-///////////////////////////////////////////
-
-
-class UnshadedMaterial : public Material {
-
- OBJ_TYPE( UnshadedMaterial, Material );
- REVERSE_GET_PROPERTY_LIST
-
-private:
-
-
- bool alpha;
- bool color_array;
- Ref<Texture> texture;
-
-protected:
-
-
- static void _bind_methods();
-
-public:
-
- void set_texture(const Ref<Texture>& p_texture);
- Ref<Texture> get_texture() const;
-
- void set_use_alpha(bool p_use_alpha);
- bool is_using_alpha() const;
-
- void set_use_color_array(bool p_use_color_array);
- bool is_using_color_array() const;
-
- UnshadedMaterial();
- ~UnshadedMaterial();
-
-};
#endif
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index c6e492fcb3..8cb0904415 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,6 +29,7 @@
#include "mesh.h"
#include "scene/resources/concave_polygon_shape.h"
#include "scene/resources/convex_polygon_shape.h"
+#include "surface_tool.h"
static const char*_array_name[]={
"vertex_array",
@@ -98,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")
@@ -116,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()) {
@@ -179,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")
@@ -194,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;
@@ -648,6 +649,30 @@ void Mesh::center_geometry() {
}
+void Mesh::regen_normalmaps() {
+
+
+ Vector< Ref<SurfaceTool> > surfs;
+ for(int i=0;i<get_surface_count();i++) {
+
+ Ref<SurfaceTool> st = memnew( SurfaceTool );
+ st->create_from(Ref<Mesh>(this),i);
+ surfs.push_back(st);
+ }
+
+ while (get_surface_count()) {
+ surface_remove(0);
+ }
+
+ for(int i=0;i<surfs.size();i++) {
+
+ surfs[i]->generate_tangents();
+ surfs[i]->commit(Ref<Mesh>(this));
+ }
+}
+
+
+
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
if (triangle_mesh.is_valid())
@@ -718,6 +743,225 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
}
+Ref<Mesh> Mesh::create_outline(float p_margin) const {
+
+
+ Array arrays;
+ int index_accum=0;
+ for(int i=0;i<get_surface_count();i++) {
+
+ if (surface_get_primitive_type(i)!=PRIMITIVE_TRIANGLES)
+ continue;
+
+ Array a = surface_get_arrays(i);
+ int vcount=0;
+
+ if (i==0) {
+ arrays=a;
+ DVector<Vector3> v=a[ARRAY_VERTEX];
+ index_accum+=v.size();
+ } else {
+
+ for(int j=0;j<arrays.size();j++) {
+
+ if (arrays[j].get_type()==Variant::NIL || a[j].get_type()==Variant::NIL) {
+ //mismatch, do not use
+ arrays[j]=Variant();
+ continue;
+ }
+
+ switch(j) {
+
+ case ARRAY_VERTEX:
+ case ARRAY_NORMAL: {
+
+ DVector<Vector3> dst = arrays[j];
+ DVector<Vector3> src = a[j];
+ if (j==ARRAY_VERTEX)
+ vcount=src.size();
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+ } break;
+ case ARRAY_TANGENT:
+ case ARRAY_BONES:
+ case ARRAY_WEIGHTS: {
+
+ DVector<real_t> dst = arrays[j];
+ DVector<real_t> src = a[j];
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+
+ } break;
+ case ARRAY_COLOR: {
+ DVector<Color> dst = arrays[j];
+ DVector<Color> src = a[j];
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+
+ } break;
+ case ARRAY_TEX_UV:
+ case ARRAY_TEX_UV2: {
+ DVector<Vector2> dst = arrays[j];
+ DVector<Vector2> src = a[j];
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+
+ } break;
+ case ARRAY_INDEX: {
+ DVector<int> dst = arrays[j];
+ DVector<int> src = a[j];
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ {
+ int ss = src.size();
+ DVector<int>::Write w = src.write();
+ for(int k=0;k<ss;k++) {
+ w[k]+=index_accum;
+ }
+
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+ index_accum+=vcount;
+
+ } break;
+
+ }
+ }
+ }
+ }
+
+ {
+ int tc=0;
+ DVector<int>::Write ir;
+ DVector<int> indices =arrays[ARRAY_INDEX];
+ bool has_indices=false;
+ DVector<Vector3> vertices =arrays[ARRAY_VERTEX];
+ int vc = vertices.size();
+ ERR_FAIL_COND_V(!vc,Ref<Mesh>());
+ DVector<Vector3>::Write r=vertices.write();
+
+
+ if (indices.size()) {
+ vc=indices.size();
+ ir=indices.write();
+ has_indices=true;
+ }
+
+ Map<Vector3,Vector3> normal_accum;
+
+ //fill normals with triangle normals
+ for(int i=0;i<vc;i+=3) {
+
+
+ Vector3 t[3];
+
+ if (has_indices) {
+ t[0]=r[ir[i+0]];
+ t[1]=r[ir[i+1]];
+ t[2]=r[ir[i+2]];
+ } else {
+ t[0]=r[i+0];
+ t[1]=r[i+1];
+ t[2]=r[i+2];
+ }
+
+ Vector3 n = Plane(t[0],t[1],t[2]).normal;
+
+ for(int j=0;j<3;j++) {
+
+ Map<Vector3,Vector3>::Element *E=normal_accum.find(t[j]);
+ if (!E) {
+ normal_accum[t[j]]=n;
+ } else {
+ float d = n.dot(E->get());
+ if (d<1.0)
+ E->get()+=n*(1.0-d);
+ //E->get()+=n;
+ }
+ }
+ }
+
+ //normalize
+
+ for (Map<Vector3,Vector3>::Element *E=normal_accum.front();E;E=E->next()) {
+ E->get().normalize();
+ }
+
+
+ //displace normals
+ int vc2 = vertices.size();
+
+ for(int i=0;i<vc2;i++) {
+
+
+ Vector3 t=r[i];
+
+ Map<Vector3,Vector3>::Element *E=normal_accum.find(t);
+ ERR_CONTINUE(!E);
+
+ t+=E->get()*p_margin;
+ r[i]=t;
+ }
+
+ r = DVector<Vector3>::Write();
+ arrays[ARRAY_VERTEX]=vertices;
+
+ if (!has_indices) {
+
+ DVector<int> new_indices;
+ new_indices.resize(vertices.size());
+ DVector<int>::Write iw = new_indices.write();
+
+ for(int j=0;j<vc2;j+=3) {
+
+ iw[j]=j;
+ iw[j+1]=j+2;
+ iw[j+2]=j+1;
+ }
+
+ iw=DVector<int>::Write();
+ arrays[ARRAY_INDEX]=new_indices;
+
+ } else {
+
+ for(int j=0;j<vc;j+=3) {
+
+ SWAP(ir[j+1],ir[j+2]);
+ }
+ ir=DVector<int>::Write();
+ arrays[ARRAY_INDEX]=indices;
+
+ }
+ }
+
+
+
+
+ Ref<Mesh> newmesh = memnew( Mesh );
+ newmesh->add_surface(PRIMITIVE_TRIANGLES,arrays);
+ return newmesh;
+}
+
+
void Mesh::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_morph_target","name"),&Mesh::add_morph_target);
@@ -740,6 +984,8 @@ void Mesh::_bind_methods() {
ObjectTypeDB::bind_method(_MD("surface_get_name","surf_idx"),&Mesh::surface_get_name);
ObjectTypeDB::bind_method(_MD("center_geometry"),&Mesh::center_geometry);
ObjectTypeDB::set_method_flags(get_type_static(),_SCS("center_geometry"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+ ObjectTypeDB::bind_method(_MD("regen_normalmaps"),&Mesh::regen_normalmaps);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("regen_normalmaps"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
ObjectTypeDB::bind_method(_MD("set_custom_aabb","aabb"),&Mesh::set_custom_aabb);
ObjectTypeDB::bind_method(_MD("get_custom_aabb"),&Mesh::get_custom_aabb);
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 5243163a4d..50463ce80e 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -166,7 +166,10 @@ public:
Ref<Shape> create_trimesh_shape() const;
Ref<Shape> create_convex_shape() const;
+ Ref<Mesh> create_outline(float p_margin) const;
+
void center_geometry();
+ void regen_normalmaps();
DVector<Face3> get_faces() const;
Ref<TriangleMesh> generate_triangle_mesh() const;
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index 7fdc88c3e4..42aaed39e1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h
index 6aed1dae86..e7e7924e98 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index ed75bf6ea1..5ebab9be76 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 59e2bcb3a5..a6a7b71669 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/mikktspace.c b/scene/resources/mikktspace.c
new file mode 100644
index 0000000000..62aa2da251
--- /dev/null
+++ b/scene/resources/mikktspace.c
@@ -0,0 +1,1890 @@
+/** \file mikktspace/mikktspace.c
+ * \ingroup mikktspace
+ */
+/**
+ * Copyright (C) 2011 by Morten S. Mikkelsen
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <float.h>
+#include <stdlib.h>
+
+#include "mikktspace.h"
+
+#define TFALSE 0
+#define TTRUE 1
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795
+#endif
+
+#define INTERNAL_RND_SORT_SEED 39871946
+
+// internal structure
+typedef struct {
+ float x, y, z;
+} SVec3;
+
+static tbool veq( const SVec3 v1, const SVec3 v2 )
+{
+ return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z);
+}
+
+static SVec3 vadd( const SVec3 v1, const SVec3 v2 )
+{
+ SVec3 vRes;
+
+ vRes.x = v1.x + v2.x;
+ vRes.y = v1.y + v2.y;
+ vRes.z = v1.z + v2.z;
+
+ return vRes;
+}
+
+
+static SVec3 vsub( const SVec3 v1, const SVec3 v2 )
+{
+ SVec3 vRes;
+
+ vRes.x = v1.x - v2.x;
+ vRes.y = v1.y - v2.y;
+ vRes.z = v1.z - v2.z;
+
+ return vRes;
+}
+
+static SVec3 vscale(const float fS, const SVec3 v)
+{
+ SVec3 vRes;
+
+ vRes.x = fS * v.x;
+ vRes.y = fS * v.y;
+ vRes.z = fS * v.z;
+
+ return vRes;
+}
+
+static float LengthSquared( const SVec3 v )
+{
+ return v.x*v.x + v.y*v.y + v.z*v.z;
+}
+
+static float Length( const SVec3 v )
+{
+ return sqrtf(LengthSquared(v));
+}
+
+static SVec3 Normalize( const SVec3 v )
+{
+ return vscale(1 / Length(v), v);
+}
+
+static float vdot( const SVec3 v1, const SVec3 v2)
+{
+ return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
+}
+
+
+static tbool NotZero(const float fX)
+{
+ // could possibly use FLT_EPSILON instead
+ return fabsf(fX) > FLT_MIN;
+}
+
+static tbool VNotZero(const SVec3 v)
+{
+ // might change this to an epsilon based test
+ return NotZero(v.x) || NotZero(v.y) || NotZero(v.z);
+}
+
+
+
+typedef struct {
+ int iNrFaces;
+ int * pTriMembers;
+} SSubGroup;
+
+typedef struct {
+ int iNrFaces;
+ int * pFaceIndices;
+ int iVertexRepresentitive;
+ tbool bOrientPreservering;
+} SGroup;
+
+//
+#define MARK_DEGENERATE 1
+#define QUAD_ONE_DEGEN_TRI 2
+#define GROUP_WITH_ANY 4
+#define ORIENT_PRESERVING 8
+
+
+
+typedef struct {
+ int FaceNeighbors[3];
+ SGroup * AssignedGroup[3];
+
+ // normalized first order face derivatives
+ SVec3 vOs, vOt;
+ float fMagS, fMagT; // original magnitudes
+
+ // determines if the current and the next triangle are a quad.
+ int iOrgFaceNumber;
+ int iFlag, iTSpacesOffs;
+ unsigned char vert_num[4];
+} STriInfo;
+
+typedef struct {
+ SVec3 vOs;
+ float fMagS;
+ SVec3 vOt;
+ float fMagT;
+ int iCounter; // this is to average back into quads.
+ tbool bOrient;
+} STSpace;
+
+static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
+static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
+static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
+static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn);
+static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[],
+ const int iNrActiveGroups, const int piTriListIn[], const float fThresCos,
+ const SMikkTSpaceContext * pContext);
+
+static int MakeIndex(const int iFace, const int iVert)
+{
+ assert(iVert>=0 && iVert<4 && iFace>=0);
+ return (iFace<<2) | (iVert&0x3);
+}
+
+static void IndexToData(int * piFace, int * piVert, const int iIndexIn)
+{
+ piVert[0] = iIndexIn&0x3;
+ piFace[0] = iIndexIn>>2;
+}
+
+static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1)
+{
+ STSpace ts_res;
+
+ // this if is important. Due to floating point precision
+ // averaging when ts0==ts1 will cause a slight difference
+ // which results in tangent space splits later on
+ if (pTS0->fMagS==pTS1->fMagS && pTS0->fMagT==pTS1->fMagT &&
+ veq(pTS0->vOs,pTS1->vOs) && veq(pTS0->vOt, pTS1->vOt))
+ {
+ ts_res.fMagS = pTS0->fMagS;
+ ts_res.fMagT = pTS0->fMagT;
+ ts_res.vOs = pTS0->vOs;
+ ts_res.vOt = pTS0->vOt;
+ }
+ else
+ {
+ ts_res.fMagS = 0.5f*(pTS0->fMagS+pTS1->fMagS);
+ ts_res.fMagT = 0.5f*(pTS0->fMagT+pTS1->fMagT);
+ ts_res.vOs = vadd(pTS0->vOs,pTS1->vOs);
+ ts_res.vOt = vadd(pTS0->vOt,pTS1->vOt);
+ if ( VNotZero(ts_res.vOs) ) ts_res.vOs = Normalize(ts_res.vOs);
+ if ( VNotZero(ts_res.vOt) ) ts_res.vOt = Normalize(ts_res.vOt);
+ }
+
+ return ts_res;
+}
+
+
+
+static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index);
+static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index);
+static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index);
+
+
+// degen triangles
+static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris);
+static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris);
+
+
+tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext)
+{
+ return genTangSpace(pContext, 180.0f);
+}
+
+tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold)
+{
+ // count nr_triangles
+ int * piTriListIn = NULL, * piGroupTrianglesBuffer = NULL;
+ STriInfo * pTriInfos = NULL;
+ SGroup * pGroups = NULL;
+ STSpace * psTspace = NULL;
+ int iNrTrianglesIn = 0, f=0, t=0, i=0;
+ int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0;
+ int iNrActiveGroups = 0, index = 0;
+ const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext);
+ tbool bRes = TFALSE;
+ const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f);
+
+ // verify all call-backs have been set
+ if ( pContext->m_pInterface->m_getNumFaces==NULL ||
+ pContext->m_pInterface->m_getNumVerticesOfFace==NULL ||
+ pContext->m_pInterface->m_getPosition==NULL ||
+ pContext->m_pInterface->m_getNormal==NULL ||
+ pContext->m_pInterface->m_getTexCoord==NULL )
+ return TFALSE;
+
+ // count triangles on supported faces
+ for (f=0; f<iNrFaces; f++)
+ {
+ const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
+ if (verts==3) ++iNrTrianglesIn;
+ else if (verts==4) iNrTrianglesIn += 2;
+ }
+ if (iNrTrianglesIn<=0) return TFALSE;
+
+ // allocate memory for an index list
+ piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn);
+ pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn);
+ if (piTriListIn==NULL || pTriInfos==NULL)
+ {
+ if (piTriListIn!=NULL) free(piTriListIn);
+ if (pTriInfos!=NULL) free(pTriInfos);
+ return TFALSE;
+ }
+
+ // make an initial triangle --> face index list
+ iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn);
+
+ // make a welded index list of identical positions and attributes (pos, norm, texc)
+ //printf("gen welded index list begin\n");
+ GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn);
+ //printf("gen welded index list end\n");
+
+ // Mark all degenerate triangles
+ iTotTris = iNrTrianglesIn;
+ iDegenTriangles = 0;
+ for (t=0; t<iTotTris; t++)
+ {
+ const int i0 = piTriListIn[t*3+0];
+ const int i1 = piTriListIn[t*3+1];
+ const int i2 = piTriListIn[t*3+2];
+ const SVec3 p0 = GetPosition(pContext, i0);
+ const SVec3 p1 = GetPosition(pContext, i1);
+ const SVec3 p2 = GetPosition(pContext, i2);
+ if (veq(p0,p1) || veq(p0,p2) || veq(p1,p2)) // degenerate
+ {
+ pTriInfos[t].iFlag |= MARK_DEGENERATE;
+ ++iDegenTriangles;
+ }
+ }
+ iNrTrianglesIn = iTotTris - iDegenTriangles;
+
+ // mark all triangle pairs that belong to a quad with only one
+ // good triangle. These need special treatment in DegenEpilogue().
+ // Additionally, move all good triangles to the start of
+ // pTriInfos[] and piTriListIn[] without changing order and
+ // put the degenerate triangles last.
+ DegenPrologue(pTriInfos, piTriListIn, iNrTrianglesIn, iTotTris);
+
+
+ // evaluate triangle level attributes and neighbor list
+ //printf("gen neighbors list begin\n");
+ InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn);
+ //printf("gen neighbors list end\n");
+
+
+ // based on the 4 rules, identify groups based on connectivity
+ iNrMaxGroups = iNrTrianglesIn*3;
+ pGroups = (SGroup *) malloc(sizeof(SGroup)*iNrMaxGroups);
+ piGroupTrianglesBuffer = (int *) malloc(sizeof(int)*iNrTrianglesIn*3);
+ if (pGroups==NULL || piGroupTrianglesBuffer==NULL)
+ {
+ if (pGroups!=NULL) free(pGroups);
+ if (piGroupTrianglesBuffer!=NULL) free(piGroupTrianglesBuffer);
+ free(piTriListIn);
+ free(pTriInfos);
+ return TFALSE;
+ }
+ //printf("gen 4rule groups begin\n");
+ iNrActiveGroups =
+ Build4RuleGroups(pTriInfos, pGroups, piGroupTrianglesBuffer, piTriListIn, iNrTrianglesIn);
+ //printf("gen 4rule groups end\n");
+
+ //
+
+ psTspace = (STSpace *) malloc(sizeof(STSpace)*iNrTSPaces);
+ if (psTspace==NULL)
+ {
+ free(piTriListIn);
+ free(pTriInfos);
+ free(pGroups);
+ free(piGroupTrianglesBuffer);
+ return TFALSE;
+ }
+ memset(psTspace, 0, sizeof(STSpace)*iNrTSPaces);
+ for (t=0; t<iNrTSPaces; t++)
+ {
+ psTspace[t].vOs.x=1.0f; psTspace[t].vOs.y=0.0f; psTspace[t].vOs.z=0.0f; psTspace[t].fMagS = 1.0f;
+ psTspace[t].vOt.x=0.0f; psTspace[t].vOt.y=1.0f; psTspace[t].vOt.z=0.0f; psTspace[t].fMagT = 1.0f;
+ }
+
+ // make tspaces, each group is split up into subgroups if necessary
+ // based on fAngularThreshold. Finally a tangent space is made for
+ // every resulting subgroup
+ //printf("gen tspaces begin\n");
+ bRes = GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriListIn, fThresCos, pContext);
+ //printf("gen tspaces end\n");
+
+ // clean up
+ free(pGroups);
+ free(piGroupTrianglesBuffer);
+
+ if (!bRes) // if an allocation in GenerateTSpaces() failed
+ {
+ // clean up and return false
+ free(pTriInfos); free(piTriListIn); free(psTspace);
+ return TFALSE;
+ }
+
+
+ // degenerate quads with one good triangle will be fixed by copying a space from
+ // the good triangle to the coinciding vertex.
+ // all other degenerate triangles will just copy a space from any good triangle
+ // with the same welded index in piTriListIn[].
+ DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesIn, iTotTris);
+
+ free(pTriInfos); free(piTriListIn);
+
+ index = 0;
+ for (f=0; f<iNrFaces; f++)
+ {
+ const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
+ if (verts!=3 && verts!=4) continue;
+
+
+ // I've decided to let degenerate triangles and group-with-anythings
+ // vary between left/right hand coordinate systems at the vertices.
+ // All healthy triangles on the other hand are built to always be either or.
+
+ /*// force the coordinate system orientation to be uniform for every face.
+ // (this is already the case for good triangles but not for
+ // degenerate ones and those with bGroupWithAnything==true)
+ bool bOrient = psTspace[index].bOrient;
+ if (psTspace[index].iCounter == 0) // tspace was not derived from a group
+ {
+ // look for a space created in GenerateTSpaces() by iCounter>0
+ bool bNotFound = true;
+ int i=1;
+ while (i<verts && bNotFound)
+ {
+ if (psTspace[index+i].iCounter > 0) bNotFound=false;
+ else ++i;
+ }
+ if (!bNotFound) bOrient = psTspace[index+i].bOrient;
+ }*/
+
+ // set data
+ for (i=0; i<verts; i++)
+ {
+ const STSpace * pTSpace = &psTspace[index];
+ float tang[] = {pTSpace->vOs.x, pTSpace->vOs.y, pTSpace->vOs.z};
+ float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z};
+ if (pContext->m_pInterface->m_setTSpace!=NULL)
+ pContext->m_pInterface->m_setTSpace(pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i);
+ if (pContext->m_pInterface->m_setTSpaceBasic!=NULL)
+ pContext->m_pInterface->m_setTSpaceBasic(pContext, tang, pTSpace->bOrient==TTRUE ? 1.0f : (-1.0f), f, i);
+
+ ++index;
+ }
+ }
+
+ free(psTspace);
+
+
+ return TTRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct {
+ float vert[3];
+ int index;
+} STmpVert;
+
+static const int g_iCells = 2048;
+
+#ifdef _MSC_VER
+ #define NOINLINE __declspec(noinline)
+#else
+ #define NOINLINE __attribute__ ((noinline))
+#endif
+
+// it is IMPORTANT that this function is called to evaluate the hash since
+// inlining could potentially reorder instructions and generate different
+// results for the same effective input value fVal.
+static NOINLINE int FindGridCell(const float fMin, const float fMax, const float fVal)
+{
+ const float fIndex = g_iCells * ((fVal-fMin)/(fMax-fMin));
+ const int iIndex = (int)fIndex;
+ return iIndex < g_iCells ? (iIndex >= 0 ? iIndex : 0) : (g_iCells - 1);
+}
+
+static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in);
+static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries);
+static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
+
+static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn)
+{
+
+ // Generate bounding box
+ int * piHashTable=NULL, * piHashCount=NULL, * piHashOffsets=NULL, * piHashCount2=NULL;
+ STmpVert * pTmpVert = NULL;
+ int i=0, iChannel=0, k=0, e=0;
+ int iMaxCount=0;
+ SVec3 vMin = GetPosition(pContext, 0), vMax = vMin, vDim;
+ float fMin, fMax;
+ for (i=1; i<(iNrTrianglesIn*3); i++)
+ {
+ const int index = piTriList_in_and_out[i];
+
+ const SVec3 vP = GetPosition(pContext, index);
+ if (vMin.x > vP.x) vMin.x = vP.x;
+ else if (vMax.x < vP.x) vMax.x = vP.x;
+ if (vMin.y > vP.y) vMin.y = vP.y;
+ else if (vMax.y < vP.y) vMax.y = vP.y;
+ if (vMin.z > vP.z) vMin.z = vP.z;
+ else if (vMax.z < vP.z) vMax.z = vP.z;
+ }
+
+ vDim = vsub(vMax,vMin);
+ iChannel = 0;
+ fMin = vMin.x; fMax=vMax.x;
+ if (vDim.y>vDim.x && vDim.y>vDim.z)
+ {
+ iChannel=1;
+ fMin = vMin.y, fMax=vMax.y;
+ }
+ else if (vDim.z>vDim.x)
+ {
+ iChannel=2;
+ fMin = vMin.z, fMax=vMax.z;
+ }
+
+ // make allocations
+ piHashTable = (int *) malloc(sizeof(int)*iNrTrianglesIn*3);
+ piHashCount = (int *) malloc(sizeof(int)*g_iCells);
+ piHashOffsets = (int *) malloc(sizeof(int)*g_iCells);
+ piHashCount2 = (int *) malloc(sizeof(int)*g_iCells);
+
+ if (piHashTable==NULL || piHashCount==NULL || piHashOffsets==NULL || piHashCount2==NULL)
+ {
+ if (piHashTable!=NULL) free(piHashTable);
+ if (piHashCount!=NULL) free(piHashCount);
+ if (piHashOffsets!=NULL) free(piHashOffsets);
+ if (piHashCount2!=NULL) free(piHashCount2);
+ GenerateSharedVerticesIndexListSlow(piTriList_in_and_out, pContext, iNrTrianglesIn);
+ return;
+ }
+ memset(piHashCount, 0, sizeof(int)*g_iCells);
+ memset(piHashCount2, 0, sizeof(int)*g_iCells);
+
+ // count amount of elements in each cell unit
+ for (i=0; i<(iNrTrianglesIn*3); i++)
+ {
+ const int index = piTriList_in_and_out[i];
+ const SVec3 vP = GetPosition(pContext, index);
+ const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z);
+ const int iCell = FindGridCell(fMin, fMax, fVal);
+ ++piHashCount[iCell];
+ }
+
+ // evaluate start index of each cell.
+ piHashOffsets[0]=0;
+ for (k=1; k<g_iCells; k++)
+ piHashOffsets[k]=piHashOffsets[k-1]+piHashCount[k-1];
+
+ // insert vertices
+ for (i=0; i<(iNrTrianglesIn*3); i++)
+ {
+ const int index = piTriList_in_and_out[i];
+ const SVec3 vP = GetPosition(pContext, index);
+ const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z);
+ const int iCell = FindGridCell(fMin, fMax, fVal);
+ int * pTable = NULL;
+
+ assert(piHashCount2[iCell]<piHashCount[iCell]);
+ pTable = &piHashTable[piHashOffsets[iCell]];
+ pTable[piHashCount2[iCell]] = i; // vertex i has been inserted.
+ ++piHashCount2[iCell];
+ }
+ for (k=0; k<g_iCells; k++)
+ assert(piHashCount2[k] == piHashCount[k]); // verify the count
+ free(piHashCount2);
+
+ // find maximum amount of entries in any hash entry
+ iMaxCount = piHashCount[0];
+ for (k=1; k<g_iCells; k++)
+ if (iMaxCount<piHashCount[k])
+ iMaxCount=piHashCount[k];
+ pTmpVert = (STmpVert *) malloc(sizeof(STmpVert)*iMaxCount);
+
+
+ // complete the merge
+ for (k=0; k<g_iCells; k++)
+ {
+ // extract table of cell k and amount of entries in it
+ int * pTable = &piHashTable[piHashOffsets[k]];
+ const int iEntries = piHashCount[k];
+ if (iEntries < 2) continue;
+
+ if (pTmpVert!=NULL)
+ {
+ for (e=0; e<iEntries; e++)
+ {
+ int i = pTable[e];
+ const SVec3 vP = GetPosition(pContext, piTriList_in_and_out[i]);
+ pTmpVert[e].vert[0] = vP.x; pTmpVert[e].vert[1] = vP.y;
+ pTmpVert[e].vert[2] = vP.z; pTmpVert[e].index = i;
+ }
+ MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, 0, iEntries-1);
+ }
+ else
+ MergeVertsSlow(piTriList_in_and_out, pContext, pTable, iEntries);
+ }
+
+ if (pTmpVert!=NULL) { free(pTmpVert); }
+ free(piHashTable);
+ free(piHashCount);
+ free(piHashOffsets);
+}
+
+static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in)
+{
+ // make bbox
+ int c=0, l=0, channel=0;
+ float fvMin[3], fvMax[3];
+ float dx=0, dy=0, dz=0, fSep=0;
+ for (c=0; c<3; c++)
+ { fvMin[c]=pTmpVert[iL_in].vert[c]; fvMax[c]=fvMin[c]; }
+ for (l=(iL_in+1); l<=iR_in; l++)
+ for (c=0; c<3; c++)
+ if (fvMin[c]>pTmpVert[l].vert[c]) fvMin[c]=pTmpVert[l].vert[c];
+ else if (fvMax[c]<pTmpVert[l].vert[c]) fvMax[c]=pTmpVert[l].vert[c];
+
+ dx = fvMax[0]-fvMin[0];
+ dy = fvMax[1]-fvMin[1];
+ dz = fvMax[2]-fvMin[2];
+
+ channel = 0;
+ if (dy>dx && dy>dz) channel=1;
+ else if (dz>dx) channel=2;
+
+ fSep = 0.5f*(fvMax[channel]+fvMin[channel]);
+
+ // terminate recursion when the separation/average value
+ // is no longer strictly between fMin and fMax values.
+ if (fSep>=fvMax[channel] || fSep<=fvMin[channel])
+ {
+ // complete the weld
+ for (l=iL_in; l<=iR_in; l++)
+ {
+ int i = pTmpVert[l].index;
+ const int index = piTriList_in_and_out[i];
+ const SVec3 vP = GetPosition(pContext, index);
+ const SVec3 vN = GetNormal(pContext, index);
+ const SVec3 vT = GetTexCoord(pContext, index);
+
+ tbool bNotFound = TTRUE;
+ int l2=iL_in, i2rec=-1;
+ while (l2<l && bNotFound)
+ {
+ const int i2 = pTmpVert[l2].index;
+ const int index2 = piTriList_in_and_out[i2];
+ const SVec3 vP2 = GetPosition(pContext, index2);
+ const SVec3 vN2 = GetNormal(pContext, index2);
+ const SVec3 vT2 = GetTexCoord(pContext, index2);
+ i2rec=i2;
+
+ //if (vP==vP2 && vN==vN2 && vT==vT2)
+ if (vP.x==vP2.x && vP.y==vP2.y && vP.z==vP2.z &&
+ vN.x==vN2.x && vN.y==vN2.y && vN.z==vN2.z &&
+ vT.x==vT2.x && vT.y==vT2.y && vT.z==vT2.z)
+ bNotFound = TFALSE;
+ else
+ ++l2;
+ }
+
+ // merge if previously found
+ if (!bNotFound)
+ piTriList_in_and_out[i] = piTriList_in_and_out[i2rec];
+ }
+ }
+ else
+ {
+ int iL=iL_in, iR=iR_in;
+ assert((iR_in-iL_in)>0); // at least 2 entries
+
+ // separate (by fSep) all points between iL_in and iR_in in pTmpVert[]
+ while (iL < iR)
+ {
+ tbool bReadyLeftSwap = TFALSE, bReadyRightSwap = TFALSE;
+ while ((!bReadyLeftSwap) && iL<iR)
+ {
+ assert(iL>=iL_in && iL<=iR_in);
+ bReadyLeftSwap = !(pTmpVert[iL].vert[channel]<fSep);
+ if (!bReadyLeftSwap) ++iL;
+ }
+ while ((!bReadyRightSwap) && iL<iR)
+ {
+ assert(iR>=iL_in && iR<=iR_in);
+ bReadyRightSwap = pTmpVert[iR].vert[channel]<fSep;
+ if (!bReadyRightSwap) --iR;
+ }
+ assert( (iL<iR) || !(bReadyLeftSwap && bReadyRightSwap) );
+
+ if (bReadyLeftSwap && bReadyRightSwap)
+ {
+ const STmpVert sTmp = pTmpVert[iL];
+ assert(iL<iR);
+ pTmpVert[iL] = pTmpVert[iR];
+ pTmpVert[iR] = sTmp;
+ ++iL; --iR;
+ }
+ }
+
+ assert(iL==(iR+1) || (iL==iR));
+ if (iL==iR)
+ {
+ const tbool bReadyRightSwap = pTmpVert[iR].vert[channel]<fSep;
+ if (bReadyRightSwap) ++iL;
+ else --iR;
+ }
+
+ // only need to weld when there is more than 1 instance of the (x,y,z)
+ if (iL_in < iR)
+ MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR); // weld all left of fSep
+ if (iL < iR_in)
+ MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL, iR_in); // weld all right of (or equal to) fSep
+ }
+}
+
+static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries)
+{
+ // this can be optimized further using a tree structure or more hashing.
+ int e=0;
+ for (e=0; e<iEntries; e++)
+ {
+ int i = pTable[e];
+ const int index = piTriList_in_and_out[i];
+ const SVec3 vP = GetPosition(pContext, index);
+ const SVec3 vN = GetNormal(pContext, index);
+ const SVec3 vT = GetTexCoord(pContext, index);
+
+ tbool bNotFound = TTRUE;
+ int e2=0, i2rec=-1;
+ while (e2<e && bNotFound)
+ {
+ const int i2 = pTable[e2];
+ const int index2 = piTriList_in_and_out[i2];
+ const SVec3 vP2 = GetPosition(pContext, index2);
+ const SVec3 vN2 = GetNormal(pContext, index2);
+ const SVec3 vT2 = GetTexCoord(pContext, index2);
+ i2rec = i2;
+
+ if (veq(vP,vP2) && veq(vN,vN2) && veq(vT,vT2))
+ bNotFound = TFALSE;
+ else
+ ++e2;
+ }
+
+ // merge if previously found
+ if (!bNotFound)
+ piTriList_in_and_out[i] = piTriList_in_and_out[i2rec];
+ }
+}
+
+static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn)
+{
+ int iNumUniqueVerts = 0, t=0, i=0;
+ for (t=0; t<iNrTrianglesIn; t++)
+ {
+ for (i=0; i<3; i++)
+ {
+ const int offs = t*3 + i;
+ const int index = piTriList_in_and_out[offs];
+
+ const SVec3 vP = GetPosition(pContext, index);
+ const SVec3 vN = GetNormal(pContext, index);
+ const SVec3 vT = GetTexCoord(pContext, index);
+
+ tbool bFound = TFALSE;
+ int t2=0, index2rec=-1;
+ while (!bFound && t2<=t)
+ {
+ int j=0;
+ while (!bFound && j<3)
+ {
+ const int index2 = piTriList_in_and_out[t2*3 + j];
+ const SVec3 vP2 = GetPosition(pContext, index2);
+ const SVec3 vN2 = GetNormal(pContext, index2);
+ const SVec3 vT2 = GetTexCoord(pContext, index2);
+
+ if (veq(vP,vP2) && veq(vN,vN2) && veq(vT,vT2))
+ bFound = TTRUE;
+ else
+ ++j;
+ }
+ if (!bFound) ++t2;
+ }
+
+ assert(bFound);
+ // if we found our own
+ if (index2rec == index) { ++iNumUniqueVerts; }
+
+ piTriList_in_and_out[offs] = index2rec;
+ }
+ }
+}
+
+static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn)
+{
+ int iTSpacesOffs = 0, f=0, t=0;
+ int iDstTriIndex = 0;
+ for (f=0; f<pContext->m_pInterface->m_getNumFaces(pContext); f++)
+ {
+ const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
+ if (verts!=3 && verts!=4) continue;
+
+ pTriInfos[iDstTriIndex].iOrgFaceNumber = f;
+ pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs;
+
+ if (verts==3)
+ {
+ unsigned char * pVerts = pTriInfos[iDstTriIndex].vert_num;
+ pVerts[0]=0; pVerts[1]=1; pVerts[2]=2;
+ piTriList_out[iDstTriIndex*3+0] = MakeIndex(f, 0);
+ piTriList_out[iDstTriIndex*3+1] = MakeIndex(f, 1);
+ piTriList_out[iDstTriIndex*3+2] = MakeIndex(f, 2);
+ ++iDstTriIndex; // next
+ }
+ else
+ {
+ {
+ pTriInfos[iDstTriIndex+1].iOrgFaceNumber = f;
+ pTriInfos[iDstTriIndex+1].iTSpacesOffs = iTSpacesOffs;
+ }
+
+ {
+ // need an order independent way to evaluate
+ // tspace on quads. This is done by splitting
+ // along the shortest diagonal.
+ const int i0 = MakeIndex(f, 0);
+ const int i1 = MakeIndex(f, 1);
+ const int i2 = MakeIndex(f, 2);
+ const int i3 = MakeIndex(f, 3);
+ const SVec3 T0 = GetTexCoord(pContext, i0);
+ const SVec3 T1 = GetTexCoord(pContext, i1);
+ const SVec3 T2 = GetTexCoord(pContext, i2);
+ const SVec3 T3 = GetTexCoord(pContext, i3);
+ const float distSQ_02 = LengthSquared(vsub(T2,T0));
+ const float distSQ_13 = LengthSquared(vsub(T3,T1));
+ tbool bQuadDiagIs_02;
+ if (distSQ_02<distSQ_13)
+ bQuadDiagIs_02 = TTRUE;
+ else if (distSQ_13<distSQ_02)
+ bQuadDiagIs_02 = TFALSE;
+ else
+ {
+ const SVec3 P0 = GetPosition(pContext, i0);
+ const SVec3 P1 = GetPosition(pContext, i1);
+ const SVec3 P2 = GetPosition(pContext, i2);
+ const SVec3 P3 = GetPosition(pContext, i3);
+ const float distSQ_02 = LengthSquared(vsub(P2,P0));
+ const float distSQ_13 = LengthSquared(vsub(P3,P1));
+
+ bQuadDiagIs_02 = distSQ_13<distSQ_02 ? TFALSE : TTRUE;
+ }
+
+ if (bQuadDiagIs_02)
+ {
+ {
+ unsigned char * pVerts_A = pTriInfos[iDstTriIndex].vert_num;
+ pVerts_A[0]=0; pVerts_A[1]=1; pVerts_A[2]=2;
+ }
+ piTriList_out[iDstTriIndex*3+0] = i0;
+ piTriList_out[iDstTriIndex*3+1] = i1;
+ piTriList_out[iDstTriIndex*3+2] = i2;
+ ++iDstTriIndex; // next
+ {
+ unsigned char * pVerts_B = pTriInfos[iDstTriIndex].vert_num;
+ pVerts_B[0]=0; pVerts_B[1]=2; pVerts_B[2]=3;
+ }
+ piTriList_out[iDstTriIndex*3+0] = i0;
+ piTriList_out[iDstTriIndex*3+1] = i2;
+ piTriList_out[iDstTriIndex*3+2] = i3;
+ ++iDstTriIndex; // next
+ }
+ else
+ {
+ {
+ unsigned char * pVerts_A = pTriInfos[iDstTriIndex].vert_num;
+ pVerts_A[0]=0; pVerts_A[1]=1; pVerts_A[2]=3;
+ }
+ piTriList_out[iDstTriIndex*3+0] = i0;
+ piTriList_out[iDstTriIndex*3+1] = i1;
+ piTriList_out[iDstTriIndex*3+2] = i3;
+ ++iDstTriIndex; // next
+ {
+ unsigned char * pVerts_B = pTriInfos[iDstTriIndex].vert_num;
+ pVerts_B[0]=1; pVerts_B[1]=2; pVerts_B[2]=3;
+ }
+ piTriList_out[iDstTriIndex*3+0] = i1;
+ piTriList_out[iDstTriIndex*3+1] = i2;
+ piTriList_out[iDstTriIndex*3+2] = i3;
+ ++iDstTriIndex; // next
+ }
+ }
+ }
+
+ iTSpacesOffs += verts;
+ assert(iDstTriIndex<=iNrTrianglesIn);
+ }
+
+ for (t=0; t<iNrTrianglesIn; t++)
+ pTriInfos[t].iFlag = 0;
+
+ // return total amount of tspaces
+ return iTSpacesOffs;
+}
+
+static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index)
+{
+ int iF, iI;
+ SVec3 res; float pos[3];
+ IndexToData(&iF, &iI, index);
+ pContext->m_pInterface->m_getPosition(pContext, pos, iF, iI);
+ res.x=pos[0]; res.y=pos[1]; res.z=pos[2];
+ return res;
+}
+
+static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index)
+{
+ int iF, iI;
+ SVec3 res; float norm[3];
+ IndexToData(&iF, &iI, index);
+ pContext->m_pInterface->m_getNormal(pContext, norm, iF, iI);
+ res.x=norm[0]; res.y=norm[1]; res.z=norm[2];
+ return res;
+}
+
+static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index)
+{
+ int iF, iI;
+ SVec3 res; float texc[2];
+ IndexToData(&iF, &iI, index);
+ pContext->m_pInterface->m_getTexCoord(pContext, texc, iF, iI);
+ res.x=texc[0]; res.y=texc[1]; res.z=1.0f;
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef union {
+ struct
+ {
+ int i0, i1, f;
+ };
+ int array[3];
+} SEdge;
+
+static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn);
+static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn);
+
+// returns the texture area times 2
+static float CalcTexArea(const SMikkTSpaceContext * pContext, const int indices[])
+{
+ const SVec3 t1 = GetTexCoord(pContext, indices[0]);
+ const SVec3 t2 = GetTexCoord(pContext, indices[1]);
+ const SVec3 t3 = GetTexCoord(pContext, indices[2]);
+
+ const float t21x = t2.x-t1.x;
+ const float t21y = t2.y-t1.y;
+ const float t31x = t3.x-t1.x;
+ const float t31y = t3.y-t1.y;
+
+ const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x;
+
+ return fSignedAreaSTx2<0 ? (-fSignedAreaSTx2) : fSignedAreaSTx2;
+}
+
+static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn)
+{
+ int f=0, i=0, t=0;
+ // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function.
+
+ // generate neighbor info list
+ for (f=0; f<iNrTrianglesIn; f++)
+ for (i=0; i<3; i++)
+ {
+ pTriInfos[f].FaceNeighbors[i] = -1;
+ pTriInfos[f].AssignedGroup[i] = NULL;
+
+ pTriInfos[f].vOs.x=0.0f; pTriInfos[f].vOs.y=0.0f; pTriInfos[f].vOs.z=0.0f;
+ pTriInfos[f].vOt.x=0.0f; pTriInfos[f].vOt.y=0.0f; pTriInfos[f].vOt.z=0.0f;
+ pTriInfos[f].fMagS = 0;
+ pTriInfos[f].fMagT = 0;
+
+ // assumed bad
+ pTriInfos[f].iFlag |= GROUP_WITH_ANY;
+ }
+
+ // evaluate first order derivatives
+ for (f=0; f<iNrTrianglesIn; f++)
+ {
+ // initial values
+ const SVec3 v1 = GetPosition(pContext, piTriListIn[f*3+0]);
+ const SVec3 v2 = GetPosition(pContext, piTriListIn[f*3+1]);
+ const SVec3 v3 = GetPosition(pContext, piTriListIn[f*3+2]);
+ const SVec3 t1 = GetTexCoord(pContext, piTriListIn[f*3+0]);
+ const SVec3 t2 = GetTexCoord(pContext, piTriListIn[f*3+1]);
+ const SVec3 t3 = GetTexCoord(pContext, piTriListIn[f*3+2]);
+
+ const float t21x = t2.x-t1.x;
+ const float t21y = t2.y-t1.y;
+ const float t31x = t3.x-t1.x;
+ const float t31y = t3.y-t1.y;
+ const SVec3 d1 = vsub(v2,v1);
+ const SVec3 d2 = vsub(v3,v1);
+
+ const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x;
+ //assert(fSignedAreaSTx2!=0);
+ SVec3 vOs = vsub(vscale(t31y,d1), vscale(t21y,d2)); // eq 18
+ SVec3 vOt = vadd(vscale(-t31x,d1), vscale(t21x,d2)); // eq 19
+
+ pTriInfos[f].iFlag |= (fSignedAreaSTx2>0 ? ORIENT_PRESERVING : 0);
+
+ if ( NotZero(fSignedAreaSTx2) )
+ {
+ const float fAbsArea = fabsf(fSignedAreaSTx2);
+ const float fLenOs = Length(vOs);
+ const float fLenOt = Length(vOt);
+ const float fS = (pTriInfos[f].iFlag&ORIENT_PRESERVING)==0 ? (-1.0f) : 1.0f;
+ if ( NotZero(fLenOs) ) pTriInfos[f].vOs = vscale(fS/fLenOs, vOs);
+ if ( NotZero(fLenOt) ) pTriInfos[f].vOt = vscale(fS/fLenOt, vOt);
+
+ // evaluate magnitudes prior to normalization of vOs and vOt
+ pTriInfos[f].fMagS = fLenOs / fAbsArea;
+ pTriInfos[f].fMagT = fLenOt / fAbsArea;
+
+ // if this is a good triangle
+ if ( NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT))
+ pTriInfos[f].iFlag &= (~GROUP_WITH_ANY);
+ }
+ }
+
+ // force otherwise healthy quads to a fixed orientation
+ while (t<(iNrTrianglesIn-1))
+ {
+ const int iFO_a = pTriInfos[t].iOrgFaceNumber;
+ const int iFO_b = pTriInfos[t+1].iOrgFaceNumber;
+ if (iFO_a==iFO_b) // this is a quad
+ {
+ const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE;
+ const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE;
+
+ // bad triangles should already have been removed by
+ // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false
+ if ((bIsDeg_a||bIsDeg_b)==TFALSE)
+ {
+ const tbool bOrientA = (pTriInfos[t].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ const tbool bOrientB = (pTriInfos[t+1].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ // if this happens the quad has extremely bad mapping!!
+ if (bOrientA!=bOrientB)
+ {
+ //printf("found quad with bad mapping\n");
+ tbool bChooseOrientFirstTri = TFALSE;
+ if ((pTriInfos[t+1].iFlag&GROUP_WITH_ANY)!=0) bChooseOrientFirstTri = TTRUE;
+ else if ( CalcTexArea(pContext, &piTriListIn[t*3+0]) >= CalcTexArea(pContext, &piTriListIn[(t+1)*3+0]) )
+ bChooseOrientFirstTri = TTRUE;
+
+ // force match
+ {
+ const int t0 = bChooseOrientFirstTri ? t : (t+1);
+ const int t1 = bChooseOrientFirstTri ? (t+1) : t;
+ pTriInfos[t1].iFlag &= (~ORIENT_PRESERVING); // clear first
+ pTriInfos[t1].iFlag |= (pTriInfos[t0].iFlag&ORIENT_PRESERVING); // copy bit
+ }
+ }
+ }
+ t += 2;
+ }
+ else
+ ++t;
+ }
+
+ // match up edge pairs
+ {
+ SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge)*iNrTrianglesIn*3);
+ if (pEdges==NULL)
+ BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn);
+ else
+ {
+ BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn);
+
+ free(pEdges);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup);
+static void AddTriToGroup(SGroup * pGroup, const int iTriIndex);
+
+static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn)
+{
+ const int iNrMaxGroups = iNrTrianglesIn*3;
+ int iNrActiveGroups = 0;
+ int iOffset = 0, f=0, i=0;
+ (void)iNrMaxGroups; /* quiet warnings in non debug mode */
+ for (f=0; f<iNrTrianglesIn; f++)
+ {
+ for (i=0; i<3; i++)
+ {
+ // if not assigned to a group
+ if ((pTriInfos[f].iFlag&GROUP_WITH_ANY)==0 && pTriInfos[f].AssignedGroup[i]==NULL)
+ {
+ tbool bOrPre;
+ int neigh_indexL, neigh_indexR;
+ const int vert_index = piTriListIn[f*3+i];
+ assert(iNrActiveGroups<iNrMaxGroups);
+ pTriInfos[f].AssignedGroup[i] = &pGroups[iNrActiveGroups];
+ pTriInfos[f].AssignedGroup[i]->iVertexRepresentitive = vert_index;
+ pTriInfos[f].AssignedGroup[i]->bOrientPreservering = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0;
+ pTriInfos[f].AssignedGroup[i]->iNrFaces = 0;
+ pTriInfos[f].AssignedGroup[i]->pFaceIndices = &piGroupTrianglesBuffer[iOffset];
+ ++iNrActiveGroups;
+
+ AddTriToGroup(pTriInfos[f].AssignedGroup[i], f);
+ bOrPre = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ neigh_indexL = pTriInfos[f].FaceNeighbors[i];
+ neigh_indexR = pTriInfos[f].FaceNeighbors[i>0?(i-1):2];
+ if (neigh_indexL>=0) // neighbor
+ {
+ const tbool bAnswer =
+ AssignRecur(piTriListIn, pTriInfos, neigh_indexL,
+ pTriInfos[f].AssignedGroup[i] );
+
+ const tbool bOrPre2 = (pTriInfos[neigh_indexL].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE;
+ assert(bAnswer || bDiff);
+ (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */
+ }
+ if (neigh_indexR>=0) // neighbor
+ {
+ const tbool bAnswer =
+ AssignRecur(piTriListIn, pTriInfos, neigh_indexR,
+ pTriInfos[f].AssignedGroup[i] );
+
+ const tbool bOrPre2 = (pTriInfos[neigh_indexR].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE;
+ assert(bAnswer || bDiff);
+ (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */
+ }
+
+ // update offset
+ iOffset += pTriInfos[f].AssignedGroup[i]->iNrFaces;
+ // since the groups are disjoint a triangle can never
+ // belong to more than 3 groups. Subsequently something
+ // is completely screwed if this assertion ever hits.
+ assert(iOffset <= iNrMaxGroups);
+ }
+ }
+ }
+
+ return iNrActiveGroups;
+}
+
+static void AddTriToGroup(SGroup * pGroup, const int iTriIndex)
+{
+ pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex;
+ ++pGroup->iNrFaces;
+}
+
+static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[],
+ const int iMyTriIndex, SGroup * pGroup)
+{
+ STriInfo * pMyTriInfo = &psTriInfos[iMyTriIndex];
+
+ // track down vertex
+ const int iVertRep = pGroup->iVertexRepresentitive;
+ const int * pVerts = &piTriListIn[3*iMyTriIndex+0];
+ int i=-1;
+ if (pVerts[0]==iVertRep) i=0;
+ else if (pVerts[1]==iVertRep) i=1;
+ else if (pVerts[2]==iVertRep) i=2;
+ assert(i>=0 && i<3);
+
+ // early out
+ if (pMyTriInfo->AssignedGroup[i] == pGroup) return TTRUE;
+ else if (pMyTriInfo->AssignedGroup[i]!=NULL) return TFALSE;
+ if ((pMyTriInfo->iFlag&GROUP_WITH_ANY)!=0)
+ {
+ // first to group with a group-with-anything triangle
+ // determines it's orientation.
+ // This is the only existing order dependency in the code!!
+ if ( pMyTriInfo->AssignedGroup[0] == NULL &&
+ pMyTriInfo->AssignedGroup[1] == NULL &&
+ pMyTriInfo->AssignedGroup[2] == NULL )
+ {
+ pMyTriInfo->iFlag &= (~ORIENT_PRESERVING);
+ pMyTriInfo->iFlag |= (pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0);
+ }
+ }
+ {
+ const tbool bOrient = (pMyTriInfo->iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ if (bOrient != pGroup->bOrientPreservering) return TFALSE;
+ }
+
+ AddTriToGroup(pGroup, iMyTriIndex);
+ pMyTriInfo->AssignedGroup[i] = pGroup;
+
+ {
+ const int neigh_indexL = pMyTriInfo->FaceNeighbors[i];
+ const int neigh_indexR = pMyTriInfo->FaceNeighbors[i>0?(i-1):2];
+ if (neigh_indexL>=0)
+ AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup);
+ if (neigh_indexR>=0)
+ AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup);
+ }
+
+
+
+ return TTRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2);
+static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed);
+static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive);
+
+static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[],
+ const int iNrActiveGroups, const int piTriListIn[], const float fThresCos,
+ const SMikkTSpaceContext * pContext)
+{
+ STSpace * pSubGroupTspace = NULL;
+ SSubGroup * pUniSubGroups = NULL;
+ int * pTmpMembers = NULL;
+ int iMaxNrFaces=0, iUniqueTspaces=0, g=0, i=0;
+ for (g=0; g<iNrActiveGroups; g++)
+ if (iMaxNrFaces < pGroups[g].iNrFaces)
+ iMaxNrFaces = pGroups[g].iNrFaces;
+
+ if (iMaxNrFaces == 0) return TTRUE;
+
+ // make initial allocations
+ pSubGroupTspace = (STSpace *) malloc(sizeof(STSpace)*iMaxNrFaces);
+ pUniSubGroups = (SSubGroup *) malloc(sizeof(SSubGroup)*iMaxNrFaces);
+ pTmpMembers = (int *) malloc(sizeof(int)*iMaxNrFaces);
+ if (pSubGroupTspace==NULL || pUniSubGroups==NULL || pTmpMembers==NULL)
+ {
+ if (pSubGroupTspace!=NULL) free(pSubGroupTspace);
+ if (pUniSubGroups!=NULL) free(pUniSubGroups);
+ if (pTmpMembers!=NULL) free(pTmpMembers);
+ return TFALSE;
+ }
+
+
+ iUniqueTspaces = 0;
+ for (g=0; g<iNrActiveGroups; g++)
+ {
+ const SGroup * pGroup = &pGroups[g];
+ int iUniqueSubGroups = 0, s=0;
+
+ for (i=0; i<pGroup->iNrFaces; i++) // triangles
+ {
+ const int f = pGroup->pFaceIndices[i]; // triangle number
+ int index=-1, iVertIndex=-1, iOF_1=-1, iMembers=0, j=0, l=0;
+ SSubGroup tmp_group;
+ tbool bFound;
+ SVec3 n, vOs, vOt;
+ if (pTriInfos[f].AssignedGroup[0]==pGroup) index=0;
+ else if (pTriInfos[f].AssignedGroup[1]==pGroup) index=1;
+ else if (pTriInfos[f].AssignedGroup[2]==pGroup) index=2;
+ assert(index>=0 && index<3);
+
+ iVertIndex = piTriListIn[f*3+index];
+ assert(iVertIndex==pGroup->iVertexRepresentitive);
+
+ // is normalized already
+ n = GetNormal(pContext, iVertIndex);
+
+ // project
+ vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n));
+ vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n));
+ if ( VNotZero(vOs) ) vOs = Normalize(vOs);
+ if ( VNotZero(vOt) ) vOt = Normalize(vOt);
+
+ // original face number
+ iOF_1 = pTriInfos[f].iOrgFaceNumber;
+
+ iMembers = 0;
+ for (j=0; j<pGroup->iNrFaces; j++)
+ {
+ const int t = pGroup->pFaceIndices[j]; // triangle number
+ const int iOF_2 = pTriInfos[t].iOrgFaceNumber;
+
+ // project
+ SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n));
+ SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n));
+ if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2);
+ if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2);
+
+ {
+ const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE;
+ // make sure triangles which belong to the same quad are joined.
+ const tbool bSameOrgFace = iOF_1==iOF_2 ? TTRUE : TFALSE;
+
+ const float fCosS = vdot(vOs,vOs2);
+ const float fCosT = vdot(vOt,vOt2);
+
+ assert(f!=t || bSameOrgFace); // sanity check
+ if (bAny || bSameOrgFace || (fCosS>fThresCos && fCosT>fThresCos))
+ pTmpMembers[iMembers++] = t;
+ }
+ }
+
+ // sort pTmpMembers
+ tmp_group.iNrFaces = iMembers;
+ tmp_group.pTriMembers = pTmpMembers;
+ if (iMembers>1)
+ {
+ unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
+ QuickSort(pTmpMembers, 0, iMembers-1, uSeed);
+ }
+
+ // look for an existing match
+ bFound = TFALSE;
+ l=0;
+ while (l<iUniqueSubGroups && !bFound)
+ {
+ bFound = CompareSubGroups(&tmp_group, &pUniSubGroups[l]);
+ if (!bFound) ++l;
+ }
+
+ // assign tangent space index
+ assert(bFound || l==iUniqueSubGroups);
+ //piTempTangIndices[f*3+index] = iUniqueTspaces+l;
+
+ // if no match was found we allocate a new subgroup
+ if (!bFound)
+ {
+ // insert new subgroup
+ int * pIndices = (int *) malloc(sizeof(int)*iMembers);
+ if (pIndices==NULL)
+ {
+ // clean up and return false
+ int s=0;
+ for (s=0; s<iUniqueSubGroups; s++)
+ free(pUniSubGroups[s].pTriMembers);
+ free(pUniSubGroups);
+ free(pTmpMembers);
+ free(pSubGroupTspace);
+ return TFALSE;
+ }
+ pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers;
+ pUniSubGroups[iUniqueSubGroups].pTriMembers = pIndices;
+ memcpy(pIndices, tmp_group.pTriMembers, iMembers*sizeof(int));
+ pSubGroupTspace[iUniqueSubGroups] =
+ EvalTspace(tmp_group.pTriMembers, iMembers, piTriListIn, pTriInfos, pContext, pGroup->iVertexRepresentitive);
+ ++iUniqueSubGroups;
+ }
+
+ // output tspace
+ {
+ const int iOffs = pTriInfos[f].iTSpacesOffs;
+ const int iVert = pTriInfos[f].vert_num[index];
+ STSpace * pTS_out = &psTspace[iOffs+iVert];
+ assert(pTS_out->iCounter<2);
+ assert(((pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0) == pGroup->bOrientPreservering);
+ if (pTS_out->iCounter==1)
+ {
+ *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]);
+ pTS_out->iCounter = 2; // update counter
+ pTS_out->bOrient = pGroup->bOrientPreservering;
+ }
+ else
+ {
+ assert(pTS_out->iCounter==0);
+ *pTS_out = pSubGroupTspace[l];
+ pTS_out->iCounter = 1; // update counter
+ pTS_out->bOrient = pGroup->bOrientPreservering;
+ }
+ }
+ }
+
+ // clean up and offset iUniqueTspaces
+ for (s=0; s<iUniqueSubGroups; s++)
+ free(pUniSubGroups[s].pTriMembers);
+ iUniqueTspaces += iUniqueSubGroups;
+ }
+
+ // clean up
+ free(pUniSubGroups);
+ free(pTmpMembers);
+ free(pSubGroupTspace);
+
+ return TTRUE;
+}
+
+static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[],
+ const SMikkTSpaceContext * pContext, const int iVertexRepresentitive)
+{
+ STSpace res;
+ float fAngleSum = 0;
+ int face=0;
+ res.vOs.x=0.0f; res.vOs.y=0.0f; res.vOs.z=0.0f;
+ res.vOt.x=0.0f; res.vOt.y=0.0f; res.vOt.z=0.0f;
+ res.fMagS = 0; res.fMagT = 0;
+
+ for (face=0; face<iFaces; face++)
+ {
+ const int f = face_indices[face];
+
+ // only valid triangles get to add their contribution
+ if ( (pTriInfos[f].iFlag&GROUP_WITH_ANY)==0 )
+ {
+ SVec3 n, vOs, vOt, p0, p1, p2, v1, v2;
+ float fCos, fAngle, fMagS, fMagT;
+ int i=-1, index=-1, i0=-1, i1=-1, i2=-1;
+ if (piTriListIn[3*f+0]==iVertexRepresentitive) i=0;
+ else if (piTriListIn[3*f+1]==iVertexRepresentitive) i=1;
+ else if (piTriListIn[3*f+2]==iVertexRepresentitive) i=2;
+ assert(i>=0 && i<3);
+
+ // project
+ index = piTriListIn[3*f+i];
+ n = GetNormal(pContext, index);
+ vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n));
+ vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n));
+ if ( VNotZero(vOs) ) vOs = Normalize(vOs);
+ if ( VNotZero(vOt) ) vOt = Normalize(vOt);
+
+ i2 = piTriListIn[3*f + (i<2?(i+1):0)];
+ i1 = piTriListIn[3*f + i];
+ i0 = piTriListIn[3*f + (i>0?(i-1):2)];
+
+ p0 = GetPosition(pContext, i0);
+ p1 = GetPosition(pContext, i1);
+ p2 = GetPosition(pContext, i2);
+ v1 = vsub(p0,p1);
+ v2 = vsub(p2,p1);
+
+ // project
+ v1 = vsub(v1, vscale(vdot(n,v1),n)); if ( VNotZero(v1) ) v1 = Normalize(v1);
+ v2 = vsub(v2, vscale(vdot(n,v2),n)); if ( VNotZero(v2) ) v2 = Normalize(v2);
+
+ // weight contribution by the angle
+ // between the two edge vectors
+ fCos = vdot(v1,v2); fCos=fCos>1?1:(fCos<(-1) ? (-1) : fCos);
+ fAngle = (float) acos(fCos);
+ fMagS = pTriInfos[f].fMagS;
+ fMagT = pTriInfos[f].fMagT;
+
+ res.vOs=vadd(res.vOs, vscale(fAngle,vOs));
+ res.vOt=vadd(res.vOt,vscale(fAngle,vOt));
+ res.fMagS+=(fAngle*fMagS);
+ res.fMagT+=(fAngle*fMagT);
+ fAngleSum += fAngle;
+ }
+ }
+
+ // normalize
+ if ( VNotZero(res.vOs) ) res.vOs = Normalize(res.vOs);
+ if ( VNotZero(res.vOt) ) res.vOt = Normalize(res.vOt);
+ if (fAngleSum>0)
+ {
+ res.fMagS /= fAngleSum;
+ res.fMagT /= fAngleSum;
+ }
+
+ return res;
+}
+
+static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2)
+{
+ tbool bStillSame=TTRUE;
+ int i=0;
+ if (pg1->iNrFaces!=pg2->iNrFaces) return TFALSE;
+ while (i<pg1->iNrFaces && bStillSame)
+ {
+ bStillSame = pg1->pTriMembers[i]==pg2->pTriMembers[i] ? TTRUE : TFALSE;
+ if (bStillSame) ++i;
+ }
+ return bStillSame;
+}
+
+static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed)
+{
+ int iL, iR, n, index, iMid, iTmp;
+
+ // Random
+ unsigned int t=uSeed&31;
+ t=(uSeed<<t)|(uSeed>>(32-t));
+ uSeed=uSeed+t+3;
+ // Random end
+
+ iL=iLeft; iR=iRight;
+ n = (iR-iL)+1;
+ assert(n>=0);
+ index = (int) (uSeed%n);
+
+ iMid=pSortBuffer[index + iL];
+
+
+ do
+ {
+ while (pSortBuffer[iL] < iMid)
+ ++iL;
+ while (pSortBuffer[iR] > iMid)
+ --iR;
+
+ if (iL <= iR)
+ {
+ iTmp = pSortBuffer[iL];
+ pSortBuffer[iL] = pSortBuffer[iR];
+ pSortBuffer[iR] = iTmp;
+ ++iL; --iR;
+ }
+ }
+ while (iL <= iR);
+
+ if (iLeft < iR)
+ QuickSort(pSortBuffer, iLeft, iR, uSeed);
+ if (iL < iRight)
+ QuickSort(pSortBuffer, iL, iRight, uSeed);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed);
+static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in);
+
+static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn)
+{
+ // build array of edges
+ unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
+ int iEntries=0, iCurStartIndex=-1, f=0, i=0;
+ for (f=0; f<iNrTrianglesIn; f++)
+ for (i=0; i<3; i++)
+ {
+ const int i0 = piTriListIn[f*3+i];
+ const int i1 = piTriListIn[f*3+(i<2?(i+1):0)];
+ pEdges[f*3+i].i0 = i0 < i1 ? i0 : i1; // put minimum index in i0
+ pEdges[f*3+i].i1 = !(i0 < i1) ? i0 : i1; // put maximum index in i1
+ pEdges[f*3+i].f = f; // record face number
+ }
+
+ // sort over all edges by i0, this is the pricy one.
+ QuickSortEdges(pEdges, 0, iNrTrianglesIn*3-1, 0, uSeed); // sort channel 0 which is i0
+
+ // sub sort over i1, should be fast.
+ // could replace this with a 64 bit int sort over (i0,i1)
+ // with i0 as msb in the quicksort call above.
+ iEntries = iNrTrianglesIn*3;
+ iCurStartIndex = 0;
+ for (i=1; i<iEntries; i++)
+ {
+ if (pEdges[iCurStartIndex].i0 != pEdges[i].i0)
+ {
+ const int iL = iCurStartIndex;
+ const int iR = i-1;
+ //const int iElems = i-iL;
+ iCurStartIndex = i;
+ QuickSortEdges(pEdges, iL, iR, 1, uSeed); // sort channel 1 which is i1
+ }
+ }
+
+ // sub sort over f, which should be fast.
+ // this step is to remain compliant with BuildNeighborsSlow() when
+ // more than 2 triangles use the same edge (such as a butterfly topology).
+ iCurStartIndex = 0;
+ for (i=1; i<iEntries; i++)
+ {
+ if (pEdges[iCurStartIndex].i0 != pEdges[i].i0 || pEdges[iCurStartIndex].i1 != pEdges[i].i1)
+ {
+ const int iL = iCurStartIndex;
+ const int iR = i-1;
+ //const int iElems = i-iL;
+ iCurStartIndex = i;
+ QuickSortEdges(pEdges, iL, iR, 2, uSeed); // sort channel 2 which is f
+ }
+ }
+
+ // pair up, adjacent triangles
+ for (i=0; i<iEntries; i++)
+ {
+ const int i0=pEdges[i].i0;
+ const int i1=pEdges[i].i1;
+ const int f = pEdges[i].f;
+ tbool bUnassigned_A;
+
+ int i0_A, i1_A;
+ int edgenum_A, edgenum_B=0; // 0,1 or 2
+ GetEdge(&i0_A, &i1_A, &edgenum_A, &piTriListIn[f*3], i0, i1); // resolve index ordering and edge_num
+ bUnassigned_A = pTriInfos[f].FaceNeighbors[edgenum_A] == -1 ? TTRUE : TFALSE;
+
+ if (bUnassigned_A)
+ {
+ // get true index ordering
+ int j=i+1, t;
+ tbool bNotFound = TTRUE;
+ while (j<iEntries && i0==pEdges[j].i0 && i1==pEdges[j].i1 && bNotFound)
+ {
+ tbool bUnassigned_B;
+ int i0_B, i1_B;
+ t = pEdges[j].f;
+ // flip i0_B and i1_B
+ GetEdge(&i1_B, &i0_B, &edgenum_B, &piTriListIn[t*3], pEdges[j].i0, pEdges[j].i1); // resolve index ordering and edge_num
+ //assert(!(i0_A==i1_B && i1_A==i0_B));
+ bUnassigned_B = pTriInfos[t].FaceNeighbors[edgenum_B]==-1 ? TTRUE : TFALSE;
+ if (i0_A==i0_B && i1_A==i1_B && bUnassigned_B)
+ bNotFound = TFALSE;
+ else
+ ++j;
+ }
+
+ if (!bNotFound)
+ {
+ int t = pEdges[j].f;
+ pTriInfos[f].FaceNeighbors[edgenum_A] = t;
+ //assert(pTriInfos[t].FaceNeighbors[edgenum_B]==-1);
+ pTriInfos[t].FaceNeighbors[edgenum_B] = f;
+ }
+ }
+ }
+}
+
+static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn)
+{
+ int f=0, i=0;
+ for (f=0; f<iNrTrianglesIn; f++)
+ {
+ for (i=0; i<3; i++)
+ {
+ // if unassigned
+ if (pTriInfos[f].FaceNeighbors[i] == -1)
+ {
+ const int i0_A = piTriListIn[f*3+i];
+ const int i1_A = piTriListIn[f*3+(i<2?(i+1):0)];
+
+ // search for a neighbor
+ tbool bFound = TFALSE;
+ int t=0, j=0;
+ while (!bFound && t<iNrTrianglesIn)
+ {
+ if (t!=f)
+ {
+ j=0;
+ while (!bFound && j<3)
+ {
+ // in rev order
+ const int i1_B = piTriListIn[t*3+j];
+ const int i0_B = piTriListIn[t*3+(j<2?(j+1):0)];
+ //assert(!(i0_A==i1_B && i1_A==i0_B));
+ if (i0_A==i0_B && i1_A==i1_B)
+ bFound = TTRUE;
+ else
+ ++j;
+ }
+ }
+
+ if (!bFound) ++t;
+ }
+
+ // assign neighbors
+ if (bFound)
+ {
+ pTriInfos[f].FaceNeighbors[i] = t;
+ //assert(pTriInfos[t].FaceNeighbors[j]==-1);
+ pTriInfos[t].FaceNeighbors[j] = f;
+ }
+ }
+ }
+ }
+}
+
+static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed)
+{
+ unsigned int t;
+ int iL, iR, n, index, iMid;
+
+ // early out
+ SEdge sTmp;
+ const int iElems = iRight-iLeft+1;
+ if (iElems<2) return;
+ else if (iElems==2)
+ {
+ if (pSortBuffer[iLeft].array[channel] > pSortBuffer[iRight].array[channel])
+ {
+ sTmp = pSortBuffer[iLeft];
+ pSortBuffer[iLeft] = pSortBuffer[iRight];
+ pSortBuffer[iRight] = sTmp;
+ }
+ return;
+ }
+
+ // Random
+ t=uSeed&31;
+ t=(uSeed<<t)|(uSeed>>(32-t));
+ uSeed=uSeed+t+3;
+ // Random end
+
+ iL=iLeft, iR=iRight;
+ n = (iR-iL)+1;
+ assert(n>=0);
+ index = (int) (uSeed%n);
+
+ iMid=pSortBuffer[index + iL].array[channel];
+
+ do
+ {
+ while (pSortBuffer[iL].array[channel] < iMid)
+ ++iL;
+ while (pSortBuffer[iR].array[channel] > iMid)
+ --iR;
+
+ if (iL <= iR)
+ {
+ sTmp = pSortBuffer[iL];
+ pSortBuffer[iL] = pSortBuffer[iR];
+ pSortBuffer[iR] = sTmp;
+ ++iL; --iR;
+ }
+ }
+ while (iL <= iR);
+
+ if (iLeft < iR)
+ QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed);
+ if (iL < iRight)
+ QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed);
+}
+
+// resolve ordering and edge number
+static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in)
+{
+ *edgenum_out = -1;
+
+ // test if first index is on the edge
+ if (indices[0]==i0_in || indices[0]==i1_in)
+ {
+ // test if second index is on the edge
+ if (indices[1]==i0_in || indices[1]==i1_in)
+ {
+ edgenum_out[0]=0; // first edge
+ i0_out[0]=indices[0];
+ i1_out[0]=indices[1];
+ }
+ else
+ {
+ edgenum_out[0]=2; // third edge
+ i0_out[0]=indices[2];
+ i1_out[0]=indices[0];
+ }
+ }
+ else
+ {
+ // only second and third index is on the edge
+ edgenum_out[0]=1; // second edge
+ i0_out[0]=indices[1];
+ i1_out[0]=indices[2];
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Degenerate triangles ////////////////////////////////////
+
+static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris)
+{
+ int iNextGoodTriangleSearchIndex=-1;
+ tbool bStillFindingGoodOnes;
+
+ // locate quads with only one good triangle
+ int t=0;
+ while (t<(iTotTris-1))
+ {
+ const int iFO_a = pTriInfos[t].iOrgFaceNumber;
+ const int iFO_b = pTriInfos[t+1].iOrgFaceNumber;
+ if (iFO_a==iFO_b) // this is a quad
+ {
+ const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE;
+ const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE;
+ if ((bIsDeg_a^bIsDeg_b)!=0)
+ {
+ pTriInfos[t].iFlag |= QUAD_ONE_DEGEN_TRI;
+ pTriInfos[t+1].iFlag |= QUAD_ONE_DEGEN_TRI;
+ }
+ t += 2;
+ }
+ else
+ ++t;
+ }
+
+ // reorder list so all degen triangles are moved to the back
+ // without reordering the good triangles
+ iNextGoodTriangleSearchIndex = 1;
+ t=0;
+ bStillFindingGoodOnes = TTRUE;
+ while (t<iNrTrianglesIn && bStillFindingGoodOnes)
+ {
+ const tbool bIsGood = (pTriInfos[t].iFlag&MARK_DEGENERATE)==0 ? TTRUE : TFALSE;
+ if (bIsGood)
+ {
+ if (iNextGoodTriangleSearchIndex < (t+2))
+ iNextGoodTriangleSearchIndex = t+2;
+ }
+ else
+ {
+ int t0, t1;
+ // search for the first good triangle.
+ tbool bJustADegenerate = TTRUE;
+ while (bJustADegenerate && iNextGoodTriangleSearchIndex<iTotTris)
+ {
+ const tbool bIsGood = (pTriInfos[iNextGoodTriangleSearchIndex].iFlag&MARK_DEGENERATE)==0 ? TTRUE : TFALSE;
+ if (bIsGood) bJustADegenerate=TFALSE;
+ else ++iNextGoodTriangleSearchIndex;
+ }
+
+ t0 = t;
+ t1 = iNextGoodTriangleSearchIndex;
+ ++iNextGoodTriangleSearchIndex;
+ assert(iNextGoodTriangleSearchIndex > (t+1));
+
+ // swap triangle t0 and t1
+ if (!bJustADegenerate)
+ {
+ int i=0;
+ for (i=0; i<3; i++)
+ {
+ const int index = piTriList_out[t0*3+i];
+ piTriList_out[t0*3+i] = piTriList_out[t1*3+i];
+ piTriList_out[t1*3+i] = index;
+ }
+ {
+ const STriInfo tri_info = pTriInfos[t0];
+ pTriInfos[t0] = pTriInfos[t1];
+ pTriInfos[t1] = tri_info;
+ }
+ }
+ else
+ bStillFindingGoodOnes = TFALSE; // this is not supposed to happen
+ }
+
+ if (bStillFindingGoodOnes) ++t;
+ }
+
+ assert(bStillFindingGoodOnes); // code will still work.
+ assert(iNrTrianglesIn == t);
+}
+
+static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris)
+{
+ int t=0, i=0;
+ // deal with degenerate triangles
+ // punishment for degenerate triangles is O(N^2)
+ for (t=iNrTrianglesIn; t<iTotTris; t++)
+ {
+ // degenerate triangles on a quad with one good triangle are skipped
+ // here but processed in the next loop
+ const tbool bSkip = (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 ? TTRUE : TFALSE;
+
+ if (!bSkip)
+ {
+ for (i=0; i<3; i++)
+ {
+ const int index1 = piTriListIn[t*3+i];
+ // search through the good triangles
+ tbool bNotFound = TTRUE;
+ int j=0;
+ while (bNotFound && j<(3*iNrTrianglesIn))
+ {
+ const int index2 = piTriListIn[j];
+ if (index1==index2) bNotFound=TFALSE;
+ else ++j;
+ }
+
+ if (!bNotFound)
+ {
+ const int iTri = j/3;
+ const int iVert = j%3;
+ const int iSrcVert=pTriInfos[iTri].vert_num[iVert];
+ const int iSrcOffs=pTriInfos[iTri].iTSpacesOffs;
+ const int iDstVert=pTriInfos[t].vert_num[i];
+ const int iDstOffs=pTriInfos[t].iTSpacesOffs;
+
+ // copy tspace
+ psTspace[iDstOffs+iDstVert] = psTspace[iSrcOffs+iSrcVert];
+ }
+ }
+ }
+ }
+
+ // deal with degenerate quads with one good triangle
+ for (t=0; t<iNrTrianglesIn; t++)
+ {
+ // this triangle belongs to a quad where the
+ // other triangle is degenerate
+ if ( (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 )
+ {
+ SVec3 vDstP;
+ int iOrgF=-1, i=0;
+ tbool bNotFound;
+ unsigned char * pV = pTriInfos[t].vert_num;
+ int iFlag = (1<<pV[0]) | (1<<pV[1]) | (1<<pV[2]);
+ int iMissingIndex = 0;
+ if ((iFlag&2)==0) iMissingIndex=1;
+ else if ((iFlag&4)==0) iMissingIndex=2;
+ else if ((iFlag&8)==0) iMissingIndex=3;
+
+ iOrgF = pTriInfos[t].iOrgFaceNumber;
+ vDstP = GetPosition(pContext, MakeIndex(iOrgF, iMissingIndex));
+ bNotFound = TTRUE;
+ i=0;
+ while (bNotFound && i<3)
+ {
+ const int iVert = pV[i];
+ const SVec3 vSrcP = GetPosition(pContext, MakeIndex(iOrgF, iVert));
+ if (veq(vSrcP, vDstP)==TTRUE)
+ {
+ const int iOffs = pTriInfos[t].iTSpacesOffs;
+ psTspace[iOffs+iMissingIndex] = psTspace[iOffs+iVert];
+ bNotFound=TFALSE;
+ }
+ else
+ ++i;
+ }
+ assert(!bNotFound);
+ }
+ }
+}
diff --git a/scene/resources/mikktspace.h b/scene/resources/mikktspace.h
new file mode 100644
index 0000000000..52c44a713c
--- /dev/null
+++ b/scene/resources/mikktspace.h
@@ -0,0 +1,145 @@
+/** \file mikktspace/mikktspace.h
+ * \ingroup mikktspace
+ */
+/**
+ * Copyright (C) 2011 by Morten S. Mikkelsen
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#ifndef __MIKKTSPACE_H__
+#define __MIKKTSPACE_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Author: Morten S. Mikkelsen
+ * Version: 1.0
+ *
+ * The files mikktspace.h and mikktspace.c are designed to be
+ * stand-alone files and it is important that they are kept this way.
+ * Not having dependencies on structures/classes/libraries specific
+ * to the program, in which they are used, allows them to be copied
+ * and used as is into any tool, program or plugin.
+ * The code is designed to consistently generate the same
+ * tangent spaces, for a given mesh, in any tool in which it is used.
+ * This is done by performing an internal welding step and subsequently an order-independent evaluation
+ * of tangent space for meshes consisting of triangles and quads.
+ * This means faces can be received in any order and the same is true for
+ * the order of vertices of each face. The generated result will not be affected
+ * by such reordering. Additionally, whether degenerate (vertices or texture coordinates)
+ * primitives are present or not will not affect the generated results either.
+ * Once tangent space calculation is done the vertices of degenerate primitives will simply
+ * inherit tangent space from neighboring non degenerate primitives.
+ * The analysis behind this implementation can be found in my master's thesis
+ * which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf
+ * Note that though the tangent spaces at the vertices are generated in an order-independent way,
+ * by this implementation, the interpolated tangent space is still affected by which diagonal is
+ * chosen to split each quad. A sensible solution is to have your tools pipeline always
+ * split quads by the shortest diagonal. This choice is order-independent and works with mirroring.
+ * If these have the same length then compare the diagonals defined by the texture coordinates.
+ * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin
+ * and also quad triangulator plugin.
+ */
+
+
+typedef int tbool;
+typedef struct SMikkTSpaceContext SMikkTSpaceContext;
+
+typedef struct {
+ // Returns the number of faces (triangles/quads) on the mesh to be processed.
+ int (*m_getNumFaces)(const SMikkTSpaceContext * pContext);
+
+ // Returns the number of vertices on face number iFace
+ // iFace is a number in the range {0, 1, ..., getNumFaces()-1}
+ int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace);
+
+ // returns the position/normal/texcoord of the referenced face of vertex number iVert.
+ // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
+ void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert);
+ void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert);
+ void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert);
+
+ // either (or both) of the two setTSpace callbacks can be set.
+ // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
+
+ // This function is used to return the tangent and fSign to the application.
+ // fvTangent is a unit length vector.
+ // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
+ // bitangent = fSign * cross(vN, tangent);
+ // Note that the results are returned unindexed. It is possible to generate a new index list
+ // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
+ // DO NOT! use an already existing index list.
+ void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
+
+ // This function is used to return tangent space results to the application.
+ // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their
+ // true magnitudes which can be used for relief mapping effects.
+ // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
+ // However, both are perpendicular to the vertex normal.
+ // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
+ // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
+ // bitangent = fSign * cross(vN, tangent);
+ // Note that the results are returned unindexed. It is possible to generate a new index list
+ // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
+ // DO NOT! use an already existing index list.
+ void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
+ const tbool bIsOrientationPreserving, const int iFace, const int iVert);
+} SMikkTSpaceInterface;
+
+struct SMikkTSpaceContext
+{
+ SMikkTSpaceInterface * m_pInterface; // initialized with callback functions
+ void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call)
+};
+
+// these are both thread safe!
+tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled)
+tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold);
+
+
+// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the
+// normal map sampler must use the exact inverse of the pixel shader transformation.
+// The most efficient transformation we can possibly do in the pixel shader is
+// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
+// pixel shader (fast transform out)
+// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
+// where vNt is the tangent space normal. The normal map sampler must likewise use the
+// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
+// sampler does (exact inverse of pixel shader):
+// float3 row0 = cross(vB, vN);
+// float3 row1 = cross(vN, vT);
+// float3 row2 = cross(vT, vB);
+// float fSign = dot(vT, row0)<0 ? -1 : 1;
+// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
+// where vNout is the sampled normal in some chosen 3D space.
+//
+// Should you choose to reconstruct the bitangent in the pixel shader instead
+// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
+// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
+// quads as your renderer then problems will occur since the interpolated tangent spaces will differ
+// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before
+// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier.
+// However, this must be used both by the sampler and your tools/rendering pipeline.
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index 8c138695c9..0755d101b2 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h
index 09bb7cb61f..c2736e3070 100644
--- a/scene/resources/multimesh.h
+++ b/scene/resources/multimesh.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 3bd7314778..863f2be699 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,13 +29,33 @@
#include "packed_scene.h"
#include "globals.h"
#include "io/resource_loader.h"
+#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);
@@ -50,86 +70,175 @@ 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 ]);
- ERR_FAIL_COND_V(!obj,NULL);
+ if (!obj || !obj->cast_to<Node>()) {
+ if (obj) {
+ memdelete(obj);
+ obj=NULL;
+ }
+ WARN_PRINT(String("Warning node of type "+snames[n.type].operator String()+" does not exist.").ascii().get_data());
+ if (n.parent>=0 && n.parent<nc && ret_nodes[n.parent]) {
+ if (ret_nodes[n.parent]->cast_to<Spatial>()) {
+ obj = memnew( Spatial );
+ } else if (ret_nodes[n.parent]->cast_to<Control>()) {
+ obj = memnew( Control );
+ } else if (ret_nodes[n.parent]->cast_to<Node2D>()) {
+ obj = memnew( Node2D );
+ }
+
+ }
+ if (!obj) {
+ obj = memnew( Node );
+ }
+ }
+
node = obj->cast_to<Node>();
- ERR_FAIL_COND_V(!node,NULL);
}
- //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
+
+ //properties
+ int nprop_count=n.properties.size();
+ if (nprop_count) {
- const NodeData::Property* nprops=&n.properties[0];
+ const NodeData::Property* nprops=&n.properties[0];
- for(int j=0;j<nprop_count;j++) {
+ for(int j=0;j<nprop_count;j++) {
- bool valid;
- ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL );
- ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL );
+ 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);
+ 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 ] );
+ }
- 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) {
+ NODE_FROM_ID(owner,n.owner);
+ if (owner)
+ node->_set_owner_nocheck(owner);
+ }
- if (n.owner>=0) {
- ERR_FAIL_INDEX_V(n.owner,i,NULL);
- node->_set_owner_nocheck(ret_nodes[n.owner]);
}
+
+ ret_nodes[i]=node;
+
+ if (node && gen_node_path_cache && ret_nodes[0]) {
+ NodePath n = ret_nodes[0]->get_path_to(node);
+ node_path_cache[n]=i;
+ }
}
@@ -141,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()) {
@@ -151,15 +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];
+
+ //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);
+ }
+ }
- if (get_path()!="" && get_path().find("::")==-1)
- s->set_filename(get_path());
return ret_nodes[0];
}
@@ -185,63 +310,224 @@ 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) {
+
+
+ // 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!
- 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
+ //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) {
+
+ 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
+ Ref<SceneState> base_scene = p_node->get_scene_inherited_state(); //for inheritance
+ Ref<SceneState> instance_state;
+ int instance_state_node=-1;
- Dictionary instance_state;
- Set<StringName> instance_groups;
+ 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 (p_node!=p_owner && p_node->get_filename()!="") {
- //instanced
+ 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()) {
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
+
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
continue;
+ }
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;
+// }
+
- if (nd.instance>=0) {
- //only save changed properties in instance
- if (!instance_state.has(name))
+ //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 (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 (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;
- if (instance_state[name]==value)
+ }
+
+ 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 && bool(Variant::evaluate(Variant::OP_EQUAL,value,original))) {
+ //exists and did not change
continue;
+ }
+
+ 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;
@@ -252,6 +538,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()) {
@@ -259,27 +548,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;
}
@@ -288,53 +673,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) {
-
- 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
-
- List<MethodInfo> signals;
- p_node->get_signal_list(&signals);
+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) {
- ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG);
- NodeData &nd = nodes[node_map[p_node]];
- Set<Connection> instance_connections;
+ 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;
- if (nd.instance>=0) {
- Vector<Connection> iconns = p_node->get_instance_connections();
- for(int i=0;i<iconns.size();i++) {
+ List<MethodInfo> _signals;
+ p_node->get_signal_list(&_signals);
- 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;
+ }
- if (!node_map.has(n)) {
- WARN_PRINT("Connection to node outside scene??")
+ //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 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;
@@ -349,7 +816,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;
}
@@ -358,7 +825,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 );
@@ -369,14 +836,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()) {
- Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map);
+ 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,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);
@@ -397,19 +877,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"));
@@ -420,6 +1058,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()) {
@@ -497,11 +1144,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());
@@ -562,7 +1232,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;
@@ -571,10 +1259,345 @@ 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;
+}
+
+
+////////////////
+
+
+
+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;
+}
+
+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);
@@ -585,5 +1608,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 2a737335da..f3ec0afb6d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,79 +26,175 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PACKED_SCENE_H
-#define PACKED_SCENE_H
-
-#include "resource.h"
-#include "scene/main/node.h"
-
-class PackedScene : public Resource {
-
- OBJ_TYPE( PackedScene, Resource );
- RES_BASE_EXTENSION("scn");
- Vector<StringName> names;
- Vector<Variant> variants;
-
- //missing - instances
- //missing groups
- //missing - owner
- //missing - override names and values
-
- struct NodeData {
-
- int parent;
- int owner;
- int type;
- int name;
- int instance;
-
- struct Property {
-
- int name;
- int value;
- };
-
- Vector<Property> properties;
- Vector<int> groups;
- };
-
-
- Vector<NodeData> nodes;
-
- struct ConnectionData {
-
- int from;
- int to;
- int signal;
- int method;
- int flags;
- Vector<int> binds;
- };
-
- 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);
-
-
- void _set_bundled_scene(const Dictionary& p_scene);
- Dictionary _get_bundled_scene() const;
-
-protected:
-
-
- static void _bind_methods();
-public:
-
-
- Error pack(Node *p_scene);
-
- void clear();
-
- bool can_instance() const;
- Node *instance(bool p_gen_edit_state=false) const;
-
- PackedScene();
-};
-
-#endif // SCENE_PRELOADER_H
+#ifndef PACKED_SCENE_H
+#define PACKED_SCENE_H
+
+#include "resource.h"
+#include "scene/main/node.h"
+
+
+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;
+
+ enum {
+ FLAG_ID_IS_PATH=(1<<30),
+ FLAG_INSTANCE_IS_PLACEHOLDER=(1<<30),
+ FLAG_MASK=(1<<24)-1,
+ NO_PARENT_SAVED=0x7FFFFFFF,
+ TYPE_INSTANCED=0x7FFFFFFF,
+
+ };
+
+ struct NodeData {
+
+ int parent;
+ int owner;
+ int type;
+ int name;
+ int instance;
+
+ struct Property {
+
+ int name;
+ int value;
+ };
+
+ Vector<Property> properties;
+ Vector<int> groups;
+
+ };
+
+ struct PackState {
+ Ref<SceneState> state;
+ int node;
+ PackState() { node=-1; }
+ };
+
+ Vector<NodeData> nodes;
+
+ struct ConnectionData {
+
+ int from;
+ int to;
+ int signal;
+ int method;
+ int flags;
+ Vector<int> binds;
+ };
+
+ 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,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;
+
+ _FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const;
+
+ static bool disable_placeholders;
+public:
+
+ 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);
+
+
+ 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:
+
+
+ Error pack(Node *p_scene);
+
+ void clear();
+
+ bool can_instance() const;
+ Node *instance(bool p_gen_edit_state=false) const;
+
+ virtual void set_path(const String& p_path,bool p_take_over=false);
+
+ Ref<SceneState> get_state();
+
+ PackedScene();
+
+};
+
+#endif // SCENE_PRELOADER_H
diff --git a/scene/resources/plane_shape.cpp b/scene/resources/plane_shape.cpp
index ab85ec11f4..760a36a91e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 e588413cb1..dd285171c4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index afb0ae1815..e8cdec66df 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -142,6 +142,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector
if (d<closest_dist) {
ignore_from_edge=E->get();
closest_dist=d;
+ closest_point=closest;
}
}
@@ -168,6 +169,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector
if (d<closest_dist) {
ignore_to_edge=E->get();
closest_dist=d;
+ closest_point=closest;
}
}
@@ -523,24 +525,32 @@ bool PolygonPathFinder::is_point_inside(const Vector2& p_point) const {
Vector2 PolygonPathFinder::get_closest_point(const Vector2& p_point) const {
- int closest_idx=-1;
float closest_dist=1e20;
- for(int i=0;i<points.size()-2;i++) {
+ Vector2 closest_point;
+
+ for (Set<Edge>::Element *E=edges.front();E;E=E->next()) {
+
+ const Edge& e=E->get();
+ Vector2 seg[2]={
+ points[e.points[0]].pos,
+ points[e.points[1]].pos
+ };
+
+
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point,seg);
+ float d = p_point.distance_squared_to(closest);
- float d = p_point.distance_squared_to(points[i].pos);
if (d<closest_dist) {
- d=closest_dist;
- closest_idx=i;
+ closest_dist=d;
+ closest_point=closest;
}
-
}
+
+ ERR_FAIL_COND_V(closest_dist==1e20,Vector2());
- ERR_FAIL_COND_V(closest_idx==-1,Vector2());
-
- return points[closest_idx].pos;
+ return closest_point;
}
-
Vector<Vector2> PolygonPathFinder::get_intersections(const Vector2& p_from, const Vector2& p_to) const {
Vector<Vector2> inters;
diff --git a/scene/resources/ray_shape.cpp b/scene/resources/ray_shape.cpp
index 027fc0780c..ee55cc6e37 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 227e3fb405..edb29b83b5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 47b0920176..7903d88736 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 99e434fb25..96de02fb70 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 8fe1d0b616..7e58a19ac3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/rich_text.h b/scene/resources/rich_text.h
index 5d0bffd13e..9dfffbfeb3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/room.cpp b/scene/resources/room.cpp
index a9f9df5ab2..3673b18394 100644
--- a/scene/resources/room.cpp
+++ b/scene/resources/room.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/room.h b/scene/resources/room.h
index 9d785b5baf..f621d8f1bf 100644
--- a/scene/resources/room.h
+++ b/scene/resources/room.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/sample.cpp b/scene/resources/sample.cpp
index e763812670..0a785e7bf6 100644
--- a/scene/resources/sample.cpp
+++ b/scene/resources/sample.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/sample.h b/scene/resources/sample.h
index 65b9616e91..4877e0b841 100644
--- a/scene/resources/sample.h
+++ b/scene/resources/sample.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/sample_library.cpp b/scene/resources/sample_library.cpp
index 348508f3ea..ffcaa1e675 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 dbd543424b..88519e7035 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp
new file mode 100644
index 0000000000..851083aecf
--- /dev/null
+++ b/scene/resources/scene_format_text.cpp
@@ -0,0 +1,1812 @@
+#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());
+
+
+Error ResourceInteractiveLoaderText::parse_property(Variant& r_v, String &r_name) {
+
+ return OK;
+}
+
+
+
+
+///
+
+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();
+ }
+ 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("owner")) {
+ owner=packed_scene->get_state()->add_node_path(next_tag.fields["owner"]);
+ } else {
+ if (parent!=-1)
+ owner=0; //if no owner, owner is root
+ }
+
+
+ if (next_tag.fields.has("type")) {
+ type=packed_scene->get_state()->add_name(next_tag.fields["type"]);
+ }
+
+ 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;
+ }
+ }
+
+ 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;
+ }
+ 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=9;i<binds.size();i++) {
+ bind_ints.push_back( packed_scene->get_state()->add_value( bind_ints[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);
+}
+
+
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+
+
+void ResourceFormatSaverTextInstance::write_property(const String& p_name,const Variant& p_property,bool *r_ok) {
+
+ if (r_ok)
+ *r_ok=false;
+
+ if (p_name!=String()) {
+ f->store_string(p_name+" = ");
+ }
+
+ switch( p_property.get_type() ) {
+
+ case Variant::NIL: {
+ f->store_string("null");
+ } break;
+ case Variant::BOOL: {
+
+ f->store_string(p_property.operator bool() ? "true":"false" );
+ } break;
+ case Variant::INT: {
+
+ f->store_string( itos(p_property.operator int()) );
+ } break;
+ case Variant::REAL: {
+
+ f->store_string( rtoss(p_property.operator real_t()) );
+ } break;
+ case Variant::STRING: {
+
+ String str=p_property;
+
+ str="\""+str.c_escape()+"\"";
+ f->store_string( str );
+ } break;
+ case Variant::VECTOR2: {
+
+ Vector2 v = p_property;
+ f->store_string("Vector2( "+rtoss(v.x) +", "+rtoss(v.y)+" )" );
+ } break;
+ case Variant::RECT2: {
+
+ Rect2 aabb = p_property;
+ f->store_string("Rect2( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y)+" )" );
+
+ } break;
+ case Variant::VECTOR3: {
+
+ Vector3 v = p_property;
+ f->store_string("Vector3( "+rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z)+" )");
+ } break;
+ case Variant::PLANE: {
+
+ Plane p = p_property;
+ f->store_string("Plane( "+rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d)+" )" );
+
+ } break;
+ case Variant::_AABB: {
+
+ AABB aabb = p_property;
+ f->store_string("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_property;
+ f->store_string("Quat( "+rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+" )");
+
+ } break;
+ case Variant::MATRIX32: {
+
+ String s="Matrix32( ";
+ Matrix32 m3 = p_property;
+ 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] );
+ }
+ }
+
+ f->store_string(s+" )");
+
+ } break;
+ case Variant::MATRIX3: {
+
+ String s="Matrix3( ";
+ Matrix3 m3 = p_property;
+ 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] );
+ }
+ }
+
+ f->store_string(s+" )");
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ String s="Transform( ";
+ Transform t = p_property;
+ 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);
+
+ f->store_string(s+" )");
+ } break;
+
+ // misc types
+ case Variant::COLOR: {
+
+ Color c = p_property;
+ f->store_string("Color( "+rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a)+" )");
+
+ } break;
+ case Variant::IMAGE: {
+
+
+ Image img=p_property;
+
+ if (img.empty()) {
+ f->store_string("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+=", ";
+ f->store_string(imgstr);
+ f->store_string(s);
+ f->store_string(" )");
+ } break;
+ case Variant::NODE_PATH: {
+
+ String str=p_property;
+
+ str="NodePath(\""+str.c_escape()+"\")";
+ f->store_string(str);
+
+ } break;
+
+ case Variant::OBJECT: {
+
+ RES res = p_property;
+ if (res.is_null()) {
+ f->store_string("null");
+ if (r_ok)
+ *r_ok=true;
+
+ break; // don't save it
+ }
+
+ if (external_resources.has(res)) {
+
+ f->store_string("ExtResource( "+itos(external_resources[res]+1)+" )");
+ } else {
+
+ if (internal_resources.has(res)) {
+ f->store_string("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();
+ f->store_string("Resource( \""+path+"\" )");
+ } else {
+ f->store_string("null");
+ ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
+ ERR_BREAK(true);
+ //internal resource
+ }
+ }
+
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ f->store_string("InputEvent()"); //will be added later
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary dict = p_property;
+
+ List<Variant> keys;
+ dict.get_key_list(&keys);
+ keys.sort();
+
+ f->store_string("{ ");
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ //if (!_check_type(dict[E->get()]))
+ // continue;
+ bool ok;
+ write_property("",E->get(),&ok);
+ ERR_CONTINUE(!ok);
+
+ f->store_string(":");
+ write_property("",dict[E->get()],&ok);
+ if (!ok)
+ write_property("",Variant()); //at least make the file consistent..
+ if (E->next())
+ f->store_string(", ");
+ }
+
+
+ f->store_string(" }");
+
+
+ } break;
+ case Variant::ARRAY: {
+
+ f->store_string("[ ");
+ Array array = p_property;
+ int len=array.size();
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+ write_property("",array[i]);
+
+
+ }
+ f->store_string(" ]");
+
+ } break;
+
+ case Variant::RAW_ARRAY: {
+
+ f->store_string("ByteArray( ");
+ String s;
+ DVector<uint8_t> data = p_property;
+ 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)
+ f->store_string(", ");
+
+ f->store_string(itos(ptr[i]));
+
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ f->store_string("IntArray( ");
+ DVector<int> data = p_property;
+ 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)
+ f->store_string(", ");
+
+ f->store_string(itos(ptr[i]));
+ }
+
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ f->store_string("FloatArray( ");
+ DVector<real_t> data = p_property;
+ 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)
+ f->store_string(", ");
+ f->store_string(rtoss(ptr[i]));
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ f->store_string("StringArray( ");
+ DVector<String> data = p_property;
+ 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)
+ f->store_string(", ");
+ String str=ptr[i];
+ f->store_string(""+str.c_escape()+"\"");
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::VECTOR2_ARRAY: {
+
+ f->store_string("Vector2Array( ");
+ DVector<Vector2> data = p_property;
+ 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)
+ f->store_string(", ");
+ f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y) );
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ f->store_string("Vector3Array( ");
+ DVector<Vector3> data = p_property;
+ 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)
+ f->store_string(", ");
+ f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y)+", "+rtoss(ptr[i].z) );
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ f->store_string("ColorArray( ");
+
+ DVector<Color> data = p_property;
+ 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)
+ f->store_string(", ");
+
+ f->store_string(rtoss(ptr[i].r)+", "+rtoss(ptr[i].g)+", "+rtoss(ptr[i].b)+", "+rtoss(ptr[i].a) );
+
+ }
+ f->store_string(" )");
+
+ } break;
+ default: {}
+
+ }
+
+ if (r_ok)
+ *r_ok=true;
+
+}
+
+
+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
+ }
+
+
+ for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) {
+
+ String p = E->key()->get_path();
+
+ f->store_string("[ext_resource path=\""+p+"\" type=\""+E->key()->get_save_type()+"\" id="+itos(E->get()+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;
+
+ write_property(name,value);
+ f->store_string("\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()) {
+ f->store_string(" instance=");
+ write_property("",instance);
+ }
+
+ f->store_line("]\n");
+
+ for(int j=0;j<state->get_node_property_count(i);j++) {
+
+ write_property(state->get_node_property_name(i,j),state->get_node_property_value(i,j));
+ f->store_line(String());
+
+ }
+
+ 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()) {
+ f->store_string(" binds=");
+ write_property("",binds);
+ }
+
+ 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..4f18af2b62
--- /dev/null
+++ b/scene/resources/scene_format_text.h
@@ -0,0 +1,140 @@
+#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 parse_property(Variant& r_v, String &r_name);
+ 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);
+ void write_property(const String& p_name,const Variant& p_property,bool *r_ok=NULL);
+
+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 59d8cae970..09001c1a94 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,430 +26,429 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scene_preloader.h"
-#include "scene/io/scene_loader.h"
-#include "globals.h"
-
-bool ScenePreloader::can_instance() const {
-
- return nodes.size()>0;
-}
-
-Node *ScenePreloader::instance() const {
-
- int nc = nodes.size();
- ERR_FAIL_COND_V(nc==0,NULL);
-
- const StringName*snames=NULL;
- int sname_count=names.size();
- if (sname_count)
- snames=&names[0];
-
- const Variant*props=NULL;
- int prop_count=variants.size();
- if (prop_count)
- props=&variants[0];
-
- Vector<Variant> properties;
-
- const NodeData *nd = &nodes[0];
-
- Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );
-
- 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;
- }
-
- Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
- ERR_FAIL_COND_V(!obj,NULL);
- Node *node = obj->cast_to<Node>();
- ERR_FAIL_COND_V(!node,NULL);
-
- int nprop_count=n.properties.size();
- if (nprop_count) {
-
- const NodeData::Property* nprops=&n.properties[0];
-
- for(int j=0;j<nprop_count;j++) {
-
- bool valid;
- node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
- }
-
-
- }
-
- node->set_name( snames[ n.name ] );
- 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(node);
- }
- }
-
-
- //do connections
-
- int cc = connections.size();
- const ConnectionData *cdata = connections.ptr();
-
- 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 );
-
- Vector<Variant> binds;
- if (c.binds.size()) {
- binds.resize(c.binds.size());
- for(int j=0;j<c.binds.size();j++)
- 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 );
- }
-
- return ret_nodes[0];
-
-}
-
-
-static int _nm_get_string(const String& p_string, Map<StringName,int> &name_map) {
-
- if (name_map.has(p_string))
- return name_map[p_string];
-
- int idx = name_map.size();
- name_map[p_string]=idx;
- return idx;
-}
-
-static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,VariantHasher> &variant_map) {
-
- if (variant_map.has(p_variant))
- return variant_map[p_variant];
-
- int idx = variant_map.size();
- variant_map[p_variant]=idx;
- return idx;
-}
-
-void ScenePreloader::_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) {
-
- if (p_node!=p_owner && !p_node->get_owner())
- return;
-
- 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;
-
- List<PropertyInfo> plist;
- p_node->get_property_list(&plist);
- for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
-
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
- continue;
-
- NodeData::Property prop;
- prop.name=_nm_get_string(E->get().name,name_map);
- prop.value=_vm_get_variant( p_node->get( E->get().name ), variant_map);
- nd.properties.push_back(prop);
- }
-
- int idx = nodes.size();
- node_map[p_node]=idx;
- nodes.push_back(nd);
-
- for(int i=0;i<p_node->get_child_count();i++) {
-
- Node *c=p_node->get_child(i);
- _parse_node(p_owner,c,idx,name_map,variant_map,node_map);
- }
-
-
-
-}
-
-void ScenePreloader::_parse_connections(Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,bool p_instance) {
-
-
- List<MethodInfo> signals;
- p_node->get_signal_list(&signals);
-
- 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))
- continue;
- Node *n=c.target->cast_to<Node>();
- if (!n)
- continue;
-
- if (!node_map.has(n))
- continue;
-
- ConnectionData cd;
- cd.from=node_map[p_node];
- cd.to=node_map[n];
- cd.method=_nm_get_string(c.method,name_map);
- cd.signal=_nm_get_string(c.signal,name_map);
- for(int i=0;i<c.binds.size();i++) {
-
- cd.binds.push_back( _vm_get_variant(c.binds[i],variant_map));
- }
- connections.push_back(cd);
- }
- }
-
-}
-
-
-Error ScenePreloader::load_scene(const String& p_path) {
-
- return ERR_CANT_OPEN;
-#if 0
- if (path==p_path)
- return OK;
-
- String p=Globals::get_singleton()->localize_path(p_path);
- clear();
-
- Node *scene = SceneLoader::load(p);
-
- ERR_FAIL_COND_V(!scene,ERR_CANT_OPEN);
-
- path=p;
-
- Map<StringName,int> name_map;
- HashMap<Variant,int,VariantHasher> variant_map;
- Map<Node*,int> node_map;
-
- _parse_node(scene,scene,-1,name_map,variant_map,node_map);
-
-
- names.resize(name_map.size());
-
- for(Map<StringName,int>::Element *E=name_map.front();E;E=E->next()) {
-
- names[E->get()]=E->key();
- }
-
- variants.resize(variant_map.size());
- const Variant *K=NULL;
- while((K=variant_map.next(K))) {
-
- int idx = variant_map[*K];
- variants[idx]=*K;
- }
-
-
- memdelete(scene); // <- me falto esto :(
- return OK;
-#endif
-}
-
-String ScenePreloader::get_scene_path() const {
-
- return path;
-}
-
-void ScenePreloader::clear() {
-
- names.clear();
- variants.clear();
- nodes.clear();
- connections.clear();
-
-}
-
-void ScenePreloader::_set_bundled_scene(const Dictionary& d) {
-
-
- ERR_FAIL_COND( !d.has("names"));
- ERR_FAIL_COND( !d.has("variants"));
- ERR_FAIL_COND( !d.has("node_count"));
- ERR_FAIL_COND( !d.has("nodes"));
- ERR_FAIL_COND( !d.has("conn_count"));
- ERR_FAIL_COND( !d.has("conns"));
- ERR_FAIL_COND( !d.has("path"));
-
- DVector<String> snames = d["names"];
- if (snames.size()) {
-
- int namecount = snames.size();
- names.resize(namecount);
- DVector<String>::Read r =snames.read();
- for(int i=0;i<names.size();i++)
- names[i]=r[i];
- }
-
- Array svariants = d["variants"];
-
- if (svariants.size()) {
- int varcount=svariants.size();
- variants.resize(varcount);
- for(int i=0;i<varcount;i++) {
-
- variants[i]=svariants[i];
- }
-
- } else {
- variants.clear();
- }
-
- nodes.resize(d["node_count"]);
- int nc=nodes.size();
- if (nc) {
- DVector<int> snodes = d["nodes"];
- DVector<int>::Read r = snodes.read();
- int idx=0;
- for(int i=0;i<nc;i++) {
- NodeData &nd = nodes[i];
- nd.parent=r[idx++];
- nd.type=r[idx++];
- nd.name=r[idx++];
- nd.properties.resize(r[idx++]);
- for(int j=0;j<nd.properties.size();j++) {
-
- nd.properties[j].name=r[idx++];
- nd.properties[j].value=r[idx++];
- }
- }
-
- }
-
- connections.resize(d["conn_count"]);
- int cc=connections.size();
-
- if (cc) {
-
- DVector<int> sconns = d["conns"];
- DVector<int>::Read r = sconns.read();
- int idx=0;
- for(int i=0;i<nc;i++) {
- ConnectionData &cd = connections[nc];
- cd.from=r[idx++];
- cd.to=r[idx++];
- cd.signal=r[idx++];
- cd.method=r[idx++];
- cd.binds.resize(r[idx++]);
- for(int j=0;j<cd.binds.size();j++) {
-
- cd.binds[j]=r[idx++];
- }
- }
-
- }
-
-
-
- path=d["path"];
-
-}
-
-Dictionary ScenePreloader::_get_bundled_scene() const {
-
- DVector<String> rnames;
- rnames.resize(names.size());
-
- if (names.size()) {
-
- DVector<String>::Write r=rnames.write();
-
- for(int i=0;i<names.size();i++)
- r[i]=names[i];
- }
-
- Dictionary d;
- d["names"]=rnames;
- d["variants"]=variants;
-
- Vector<int> rnodes;
- d["node_count"]=nodes.size();
-
- for(int i=0;i<nodes.size();i++) {
-
- const NodeData &nd=nodes[i];
- rnodes.push_back(nd.parent);
- rnodes.push_back(nd.type);
- rnodes.push_back(nd.name);
- rnodes.push_back(nd.properties.size());
- for(int j=0;j<nd.properties.size();j++) {
-
- rnodes.push_back(nd.properties[j].name);
- rnodes.push_back(nd.properties[j].value);
- }
- }
-
- d["nodes"]=rnodes;
-
- Vector<int> rconns;
- d["conn_count"]=connections.size();
-
- for(int i=0;i<connections.size();i++) {
-
- const ConnectionData &cd=connections[i];
- rconns.push_back(cd.from);
- rconns.push_back(cd.to);
- rconns.push_back(cd.signal);
- rconns.push_back(cd.method);
- rconns.push_back(cd.binds.size());
- for(int j=0;j<cd.binds.size();i++)
- rconns.push_back(cd.binds[j]);
-
- }
-
- d["conns"]=rconns;
-
- d["path"]=path;
-
- return d;
-
-
-}
-
-void ScenePreloader::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("load_scene","path"),&ScenePreloader::load_scene);
- ObjectTypeDB::bind_method(_MD("get_scene_path"),&ScenePreloader::get_scene_path);
- ObjectTypeDB::bind_method(_MD("instance:Node"),&ScenePreloader::instance);
- ObjectTypeDB::bind_method(_MD("can_instance"),&ScenePreloader::can_instance);
- ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&ScenePreloader::_set_bundled_scene);
- ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&ScenePreloader::_get_bundled_scene);
-
- ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled_scene"),_SCS("_get_bundled_scene"));
-#if 0
- List<String> extensions;
- SceneLoader::get_recognized_extensions(&extensions);
- String exthint;
- for (List<String>::Element*E=extensions.front();E;E=E->next()) {
-
- if (exthint!="")
- exthint+=",";
- exthint+="*."+E->get();
- }
-
- exthint+="; Scenes";
-
- ADD_PROPERTY( PropertyInfo(Variant::STRING,"scene",PROPERTY_HINT_FILE,exthint),_SCS("load_scene"),_SCS("get_scene_path"));
-#endif
-}
-
-ScenePreloader::ScenePreloader() {
-
-
-}
+#include "scene_preloader.h"
+#include "globals.h"
+
+bool ScenePreloader::can_instance() const {
+
+ return nodes.size()>0;
+}
+
+Node *ScenePreloader::instance() const {
+
+ int nc = nodes.size();
+ ERR_FAIL_COND_V(nc==0,NULL);
+
+ const StringName*snames=NULL;
+ int sname_count=names.size();
+ if (sname_count)
+ snames=&names[0];
+
+ const Variant*props=NULL;
+ int prop_count=variants.size();
+ if (prop_count)
+ props=&variants[0];
+
+ Vector<Variant> properties;
+
+ const NodeData *nd = &nodes[0];
+
+ Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );
+
+ 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;
+ }
+
+ Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
+ ERR_FAIL_COND_V(!obj,NULL);
+ Node *node = obj->cast_to<Node>();
+ ERR_FAIL_COND_V(!node,NULL);
+
+ int nprop_count=n.properties.size();
+ if (nprop_count) {
+
+ const NodeData::Property* nprops=&n.properties[0];
+
+ for(int j=0;j<nprop_count;j++) {
+
+ bool valid;
+ node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
+ }
+
+
+ }
+
+ node->set_name( snames[ n.name ] );
+ 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(node);
+ }
+ }
+
+
+ //do connections
+
+ int cc = connections.size();
+ const ConnectionData *cdata = connections.ptr();
+
+ 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 );
+
+ Vector<Variant> binds;
+ if (c.binds.size()) {
+ binds.resize(c.binds.size());
+ for(int j=0;j<c.binds.size();j++)
+ 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 );
+ }
+
+ return ret_nodes[0];
+
+}
+
+
+static int _nm_get_string(const String& p_string, Map<StringName,int> &name_map) {
+
+ if (name_map.has(p_string))
+ return name_map[p_string];
+
+ int idx = name_map.size();
+ name_map[p_string]=idx;
+ return idx;
+}
+
+static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,VariantHasher> &variant_map) {
+
+ if (variant_map.has(p_variant))
+ return variant_map[p_variant];
+
+ int idx = variant_map.size();
+ variant_map[p_variant]=idx;
+ return idx;
+}
+
+void ScenePreloader::_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) {
+
+ if (p_node!=p_owner && !p_node->get_owner())
+ return;
+
+ 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;
+
+ List<PropertyInfo> plist;
+ p_node->get_property_list(&plist);
+ for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
+
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
+ continue;
+
+ NodeData::Property prop;
+ prop.name=_nm_get_string(E->get().name,name_map);
+ prop.value=_vm_get_variant( p_node->get( E->get().name ), variant_map);
+ nd.properties.push_back(prop);
+ }
+
+ int idx = nodes.size();
+ node_map[p_node]=idx;
+ nodes.push_back(nd);
+
+ for(int i=0;i<p_node->get_child_count();i++) {
+
+ Node *c=p_node->get_child(i);
+ _parse_node(p_owner,c,idx,name_map,variant_map,node_map);
+ }
+
+
+
+}
+
+void ScenePreloader::_parse_connections(Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,bool p_instance) {
+
+
+ List<MethodInfo> signals;
+ p_node->get_signal_list(&signals);
+
+ 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))
+ continue;
+ Node *n=c.target->cast_to<Node>();
+ if (!n)
+ continue;
+
+ if (!node_map.has(n))
+ continue;
+
+ ConnectionData cd;
+ cd.from=node_map[p_node];
+ cd.to=node_map[n];
+ cd.method=_nm_get_string(c.method,name_map);
+ cd.signal=_nm_get_string(c.signal,name_map);
+ for(int i=0;i<c.binds.size();i++) {
+
+ cd.binds.push_back( _vm_get_variant(c.binds[i],variant_map));
+ }
+ connections.push_back(cd);
+ }
+ }
+
+}
+
+
+Error ScenePreloader::load_scene(const String& p_path) {
+
+ return ERR_CANT_OPEN;
+#if 0
+ if (path==p_path)
+ return OK;
+
+ String p=Globals::get_singleton()->localize_path(p_path);
+ clear();
+
+ Node *scene = SceneLoader::load(p);
+
+ ERR_FAIL_COND_V(!scene,ERR_CANT_OPEN);
+
+ path=p;
+
+ Map<StringName,int> name_map;
+ HashMap<Variant,int,VariantHasher> variant_map;
+ Map<Node*,int> node_map;
+
+ _parse_node(scene,scene,-1,name_map,variant_map,node_map);
+
+
+ names.resize(name_map.size());
+
+ for(Map<StringName,int>::Element *E=name_map.front();E;E=E->next()) {
+
+ names[E->get()]=E->key();
+ }
+
+ variants.resize(variant_map.size());
+ const Variant *K=NULL;
+ while((K=variant_map.next(K))) {
+
+ int idx = variant_map[*K];
+ variants[idx]=*K;
+ }
+
+
+ memdelete(scene); // <- me falto esto :(
+ return OK;
+#endif
+}
+
+String ScenePreloader::get_scene_path() const {
+
+ return path;
+}
+
+void ScenePreloader::clear() {
+
+ names.clear();
+ variants.clear();
+ nodes.clear();
+ connections.clear();
+
+}
+
+void ScenePreloader::_set_bundled_scene(const Dictionary& d) {
+
+
+ ERR_FAIL_COND( !d.has("names"));
+ ERR_FAIL_COND( !d.has("variants"));
+ ERR_FAIL_COND( !d.has("node_count"));
+ ERR_FAIL_COND( !d.has("nodes"));
+ ERR_FAIL_COND( !d.has("conn_count"));
+ ERR_FAIL_COND( !d.has("conns"));
+ ERR_FAIL_COND( !d.has("path"));
+
+ DVector<String> snames = d["names"];
+ if (snames.size()) {
+
+ int namecount = snames.size();
+ names.resize(namecount);
+ DVector<String>::Read r =snames.read();
+ for(int i=0;i<names.size();i++)
+ names[i]=r[i];
+ }
+
+ Array svariants = d["variants"];
+
+ if (svariants.size()) {
+ int varcount=svariants.size();
+ variants.resize(varcount);
+ for(int i=0;i<varcount;i++) {
+
+ variants[i]=svariants[i];
+ }
+
+ } else {
+ variants.clear();
+ }
+
+ nodes.resize(d["node_count"]);
+ int nc=nodes.size();
+ if (nc) {
+ DVector<int> snodes = d["nodes"];
+ DVector<int>::Read r = snodes.read();
+ int idx=0;
+ for(int i=0;i<nc;i++) {
+ NodeData &nd = nodes[i];
+ nd.parent=r[idx++];
+ nd.type=r[idx++];
+ nd.name=r[idx++];
+ nd.properties.resize(r[idx++]);
+ for(int j=0;j<nd.properties.size();j++) {
+
+ nd.properties[j].name=r[idx++];
+ nd.properties[j].value=r[idx++];
+ }
+ }
+
+ }
+
+ connections.resize(d["conn_count"]);
+ int cc=connections.size();
+
+ if (cc) {
+
+ DVector<int> sconns = d["conns"];
+ DVector<int>::Read r = sconns.read();
+ int idx=0;
+ for(int i=0;i<nc;i++) {
+ ConnectionData &cd = connections[nc];
+ cd.from=r[idx++];
+ cd.to=r[idx++];
+ cd.signal=r[idx++];
+ cd.method=r[idx++];
+ cd.binds.resize(r[idx++]);
+ for(int j=0;j<cd.binds.size();j++) {
+
+ cd.binds[j]=r[idx++];
+ }
+ }
+
+ }
+
+
+
+ path=d["path"];
+
+}
+
+Dictionary ScenePreloader::_get_bundled_scene() const {
+
+ DVector<String> rnames;
+ rnames.resize(names.size());
+
+ if (names.size()) {
+
+ DVector<String>::Write r=rnames.write();
+
+ for(int i=0;i<names.size();i++)
+ r[i]=names[i];
+ }
+
+ Dictionary d;
+ d["names"]=rnames;
+ d["variants"]=variants;
+
+ Vector<int> rnodes;
+ d["node_count"]=nodes.size();
+
+ for(int i=0;i<nodes.size();i++) {
+
+ const NodeData &nd=nodes[i];
+ rnodes.push_back(nd.parent);
+ rnodes.push_back(nd.type);
+ rnodes.push_back(nd.name);
+ rnodes.push_back(nd.properties.size());
+ for(int j=0;j<nd.properties.size();j++) {
+
+ rnodes.push_back(nd.properties[j].name);
+ rnodes.push_back(nd.properties[j].value);
+ }
+ }
+
+ d["nodes"]=rnodes;
+
+ Vector<int> rconns;
+ d["conn_count"]=connections.size();
+
+ for(int i=0;i<connections.size();i++) {
+
+ const ConnectionData &cd=connections[i];
+ rconns.push_back(cd.from);
+ rconns.push_back(cd.to);
+ rconns.push_back(cd.signal);
+ rconns.push_back(cd.method);
+ rconns.push_back(cd.binds.size());
+ for(int j=0;j<cd.binds.size();j++)
+ rconns.push_back(cd.binds[j]);
+
+ }
+
+ d["conns"]=rconns;
+
+ d["path"]=path;
+
+ return d;
+
+
+}
+
+void ScenePreloader::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("load_scene","path"),&ScenePreloader::load_scene);
+ ObjectTypeDB::bind_method(_MD("get_scene_path"),&ScenePreloader::get_scene_path);
+ ObjectTypeDB::bind_method(_MD("instance:Node"),&ScenePreloader::instance);
+ ObjectTypeDB::bind_method(_MD("can_instance"),&ScenePreloader::can_instance);
+ ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&ScenePreloader::_set_bundled_scene);
+ ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&ScenePreloader::_get_bundled_scene);
+
+ ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled_scene"),_SCS("_get_bundled_scene"));
+#if 0
+ List<String> extensions;
+ SceneLoader::get_recognized_extensions(&extensions);
+ String exthint;
+ for (List<String>::Element*E=extensions.front();E;E=E->next()) {
+
+ if (exthint!="")
+ exthint+=",";
+ exthint+="*."+E->get();
+ }
+
+ exthint+="; Scenes";
+
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"scene",PROPERTY_HINT_FILE,exthint),_SCS("load_scene"),_SCS("get_scene_path"));
+#endif
+}
+
+ScenePreloader::ScenePreloader() {
+
+
+}
diff --git a/scene/resources/scene_preloader.h b/scene/resources/scene_preloader.h
index 0e1a54e298..d60d08afd4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,76 +26,76 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCENE_PRELOADER_H
-#define SCENE_PRELOADER_H
-
-#include "resource.h"
-#include "scene/main/node.h"
-
-class ScenePreloader : public Resource {
-
- OBJ_TYPE( ScenePreloader, Resource );
-
- Vector<StringName> names;
- Vector<Variant> variants;
-
- //missing - instances
- //missing groups
- //missing - owner
- //missing - override names and values
-
- struct NodeData {
-
- int parent;
- int type;
- int name;
-
- struct Property {
-
- int name;
- int value;
- };
-
- Vector<Property> properties;
- };
-
-
- Vector<NodeData> nodes;
-
- struct ConnectionData {
-
- int from;
- int to;
- int signal;
- int method;
- Vector<int> binds;
- };
-
- Vector<ConnectionData> connections;
-
- void _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);
- void _parse_connections(Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,bool p_instance);
-
- String path;
-
- void _set_bundled_scene(const Dictionary& p_scene);
- Dictionary _get_bundled_scene() const;
-
-protected:
-
-
- static void _bind_methods();
-public:
-
-
- Error load_scene(const String& p_path);
- String get_scene_path() const;
- void clear();
-
- bool can_instance() const;
- Node *instance() const;
-
- ScenePreloader();
-};
-
-#endif // SCENE_PRELOADER_H
+#ifndef SCENE_PRELOADER_H
+#define SCENE_PRELOADER_H
+
+#include "resource.h"
+#include "scene/main/node.h"
+
+class ScenePreloader : public Resource {
+
+ OBJ_TYPE( ScenePreloader, Resource );
+
+ Vector<StringName> names;
+ Vector<Variant> variants;
+
+ //missing - instances
+ //missing groups
+ //missing - owner
+ //missing - override names and values
+
+ struct NodeData {
+
+ int parent;
+ int type;
+ int name;
+
+ struct Property {
+
+ int name;
+ int value;
+ };
+
+ Vector<Property> properties;
+ };
+
+
+ Vector<NodeData> nodes;
+
+ struct ConnectionData {
+
+ int from;
+ int to;
+ int signal;
+ int method;
+ Vector<int> binds;
+ };
+
+ Vector<ConnectionData> connections;
+
+ void _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);
+ void _parse_connections(Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,bool p_instance);
+
+ String path;
+
+ void _set_bundled_scene(const Dictionary& p_scene);
+ Dictionary _get_bundled_scene() const;
+
+protected:
+
+
+ static void _bind_methods();
+public:
+
+
+ Error load_scene(const String& p_path);
+ String get_scene_path() const;
+ void clear();
+
+ bool can_instance() const;
+ Node *instance() const;
+
+ ScenePreloader();
+};
+
+#endif // SCENE_PRELOADER_H
diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp
index f4b822ae45..88f7adcd9b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 d95ccf0f1f..37c68b6c92 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 6d65da3782..a9376faf62 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,16 +33,10 @@
#include "scene/scene_string_names.h"
-void Shader::set_mode(Mode p_mode) {
-
- ERR_FAIL_INDEX(p_mode,2);
- VisualServer::get_singleton()->shader_set_mode(shader,VisualServer::ShaderMode(p_mode));
- emit_signal(SceneStringNames::get_singleton()->changed);
-}
Shader::Mode Shader::get_mode() const {
- return (Mode)VisualServer::get_singleton()->shader_get_mode(shader);
+ return mode;
}
void Shader::set_code( const String& p_vertex, const String& p_fragment, const String& p_light,int p_fragment_ofs,int p_light_ofs) {
@@ -90,7 +84,7 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const {
for(List<PropertyInfo>::Element *E=local.front();E;E=E->next()) {
PropertyInfo pi=E->get();
- pi.name="param/"+pi.name;
+ pi.name="shader_param/"+pi.name;
params_cache[pi.name]=E->get().name;
if (p_params) {
@@ -120,6 +114,13 @@ Dictionary Shader::_get_code() {
c["vertex_ofs"]=0;
c["light"]=ls;
c["light_ofs"]=0;
+ Array arr;
+ for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) {
+ arr.push_back(E->key());
+ arr.push_back(E->get());
+ }
+ if (arr.size())
+ c["default_tex"]=arr;
return c;
}
@@ -132,11 +133,48 @@ void Shader::_set_code(const Dictionary& p_string) {
light=p_string["light"];
set_code(p_string["vertex"],p_string["fragment"],light);
+ if (p_string.has("default_tex")) {
+ Array arr=p_string["default_tex"];
+ if ((arr.size()&1)==0) {
+ for(int i=0;i<arr.size();i+=2) {
+
+ set_default_texture_param(arr[i],arr[i+1]);
+ }
+ }
+ }
+}
+
+void Shader::set_default_texture_param(const StringName& p_param,const Ref<Texture>& p_texture) {
+
+ if (p_texture.is_valid()) {
+ default_textures[p_param]=p_texture;
+ VS::get_singleton()->shader_set_default_texture_param(shader,p_param,p_texture->get_rid());
+ } else {
+ default_textures.erase(p_param);
+ VS::get_singleton()->shader_set_default_texture_param(shader,p_param,RID());
+ }
}
+Ref<Texture> Shader::get_default_texture_param(const StringName& p_param) const{
+
+ if (default_textures.has(p_param))
+ return default_textures[p_param];
+ else
+ return Ref<Texture>();
+}
+
+void Shader::get_default_texture_param_list(List<StringName>* r_textures) const{
+
+ for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) {
+
+ r_textures->push_back(E->key());
+ }
+
+}
+
+
void Shader::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("set_mode","mode"),&Shader::set_mode);
ObjectTypeDB::bind_method(_MD("get_mode"),&Shader::get_mode);
ObjectTypeDB::bind_method(_MD("set_code","vcode","fcode","lcode","fofs","lofs"),&Shader::set_code,DEFVAL(0),DEFVAL(0));
@@ -144,6 +182,9 @@ void Shader::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_fragment_code"),&Shader::get_fragment_code);
ObjectTypeDB::bind_method(_MD("get_light_code"),&Shader::get_light_code);
+ ObjectTypeDB::bind_method(_MD("set_default_texture_param","param","texture:Texture"),&Shader::set_default_texture_param);
+ ObjectTypeDB::bind_method(_MD("get_default_texture_param:Texture","param"),&Shader::get_default_texture_param);
+
ObjectTypeDB::bind_method(_MD("has_param","name"),&Shader::has_param);
ObjectTypeDB::bind_method(_MD("_set_code","code"),&Shader::_set_code);
@@ -160,9 +201,10 @@ void Shader::_bind_methods() {
}
-Shader::Shader() {
+Shader::Shader(Mode p_mode) {
- shader = VisualServer::get_singleton()->shader_create();
+ mode=p_mode;
+ shader = VisualServer::get_singleton()->shader_create(VS::ShaderMode(p_mode));
params_cache_dirty=true;
}
@@ -177,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;
@@ -193,8 +238,10 @@ 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 ) );
+ Ref<Shader> shader;//( memnew( Shader ) );
int line=0;
@@ -299,7 +346,6 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin
String type = right.substr(0,popenpos);
String param = right.substr(popenpos+1,pclosepos-popenpos-1).strip_edges();
- print_line("type: "+type+" param: "+param);
if (type=="tex") {
@@ -394,6 +440,8 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin
f->close();
memdelete(f);
+ if (r_error)
+ *r_error=OK;
return shader;
}
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index fff6f1d28a..61a369c408 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,14 +31,24 @@
#include "resource.h"
#include "io/resource_loader.h"
-
+#include "scene/resources/texture.h"
class Shader : public Resource {
OBJ_TYPE(Shader,Resource);
OBJ_SAVE_TYPE( Shader );
RES_BASE_EXTENSION("shd");
- RID shader;
+public:
+ enum Mode {
+
+ MODE_MATERIAL,
+ MODE_CANVAS_ITEM,
+ MODE_POST_PROCESS,
+ MODE_MAX
+ };
+private:
+ RID shader;
+ Mode mode;
Dictionary _get_code();
void _set_code(const Dictionary& p_string);
@@ -48,20 +58,19 @@ class Shader : public Resource {
// convertion fast and save memory.
mutable bool params_cache_dirty;
mutable Map<StringName,StringName> params_cache; //map a shader param to a material param..
+ Map<StringName,Ref<Texture> > default_textures;
+
+
protected:
+
static void _bind_methods();
public:
- enum Mode {
- MODE_MATERIAL,
- MODE_CANVAS_ITEM,
- MODE_POST_PROCESS
- };
- void set_mode(Mode p_mode);
+ //void set_mode(Mode p_mode);
Mode get_mode() const;
void set_code( const String& p_vertex, const String& p_fragment, const String& p_light,int p_fragment_ofs=0,int p_light_ofs=0);
@@ -72,20 +81,52 @@ public:
void get_param_list(List<PropertyInfo> *p_params) const;
bool has_param(const StringName& p_param) const;
+ void set_default_texture_param(const StringName& p_param, const Ref<Texture> &p_texture);
+ Ref<Texture> get_default_texture_param(const StringName& p_param) const;
+ void get_default_texture_param_list(List<StringName>* r_textures) const;
+
+ _FORCE_INLINE_ StringName remap_param(const StringName& p_param) const {
+ if (params_cache_dirty)
+ get_param_list(NULL);
+
+ const Map<StringName,StringName>::Element *E=params_cache.find(p_param);
+ if (E)
+ return E->get();
+ return StringName();
+ }
+
virtual RID get_rid() const;
- Shader();
+ Shader(Mode p_mode);
~Shader();
};
VARIANT_ENUM_CAST( Shader::Mode );
+class MaterialShader : public Shader {
+
+ OBJ_TYPE(MaterialShader,Shader);
+
+public:
+
+ MaterialShader() : Shader(MODE_MATERIAL) {};
+};
+
+class CanvasItemShader : public Shader {
+
+ OBJ_TYPE(CanvasItemShader,Shader);
+
+public:
+
+ CanvasItemShader() : Shader(MODE_CANVAS_ITEM) {};
+};
+
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 7267746373..7b67eaeda8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,132 +27,392 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "shader_graph.h"
-#if 0
-
+#include "scene/scene_string_names.h"
+Array ShaderGraph::_get_node_list(ShaderType p_type) const {
-void Shader::_set(const String& p_name, const Variant& p_value) {
+ List<int> nodes;
+ get_node_list(p_type,&nodes);
+ Array arr(true);
+ for (List<int>::Element *E=nodes.front();E;E=E->next())
+ arr.push_back(E->get());
+ return arr;
+}
+Array ShaderGraph::_get_connections(ShaderType p_type) const {
- if (p_name.begins_with("nodes/")) {
- int idx=p_name.get_slice("/",1).to_int();
- Dictionary data=p_value;
+ List<Connection> connections;
+ get_node_connections(p_type,&connections);
+ Array arr(true);
+ for (List<Connection>::Element *E=connections.front();E;E=E->next()) {
- ERR_FAIL_COND(!data.has("type"));
- String type=data["type"];
- VS::ShaderNodeType node_type=VS::NODE_TYPE_MAX;
- for(int i=0;i<NODE_TYPE_MAX;i++) {
+ Dictionary d(true);
+ d["src_id"]=E->get().src_id;
+ d["src_slot"]=E->get().src_slot;
+ d["dst_id"]=E->get().dst_id;
+ d["dst_slot"]=E->get().dst_slot;
+ arr.push_back(d);
- if (type==VisualServer::shader_node_get_type_info((VS::ShaderNodeType)i).name)
- node_type=(VS::ShaderNodeType)i;
- }
+ }
+ return arr;
+}
- ERR_FAIL_COND(node_type==VS::NODE_TYPE_MAX);
+void ShaderGraph::_set_data(const Dictionary &p_data) {
+
+ Dictionary d=p_data;
+ ERR_FAIL_COND(!d.has("shaders"));
+ Array sh=d["shaders"];
+ ERR_FAIL_COND(sh.size()!=3);
+
+ for(int t=0;t<3;t++) {
+ Array data=sh[t];
+ ERR_FAIL_COND((data.size()%6)!=0);
+ shader[t].node_map.clear();
+ for(int i=0;i<data.size();i+=6) {
+
+ Node n;
+ n.id=data[i+0];
+ n.type=NodeType(int(data[i+1]));
+ n.pos=data[i+2];
+ n.param1=data[i+3];
+ n.param2=data[i+4];
+
+ Array conns=data[i+5];
+ ERR_FAIL_COND((conns.size()%3)!=0);
+
+ for(int j=0;j<conns.size();j+=3) {
+ SourceSlot ss;
+ int ls=conns[j+0];
+ 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;
- node_add( (NodeType)node_type, idx );
- if (data.has("param"))
- node_set_param(idx,data["param"]);
- if (data.has("pos"))
- node_set_pos(idx,data["pos"]);
+ }
}
- if (p_name.begins_with("conns/")) {
- Dictionary data=p_value;
- ERR_FAIL_COND( !data.has("src_id") );
- ERR_FAIL_COND( !data.has("src_slot") );
- ERR_FAIL_COND( !data.has("dst_id") );
- ERR_FAIL_COND( !data.has("dst_slot") );
+ _pending_update_shader=true;
+ _update_shader();
+
+}
- connect(data["src_id"],data["src_slot"],data["dst_id"],data["dst_slot"]);
+Dictionary ShaderGraph::_get_data() const {
+
+ Array sh;
+ for(int i=0;i<3;i++) {
+ Array data;
+ int ec = shader[i].node_map.size();
+ data.resize(ec*6);
+ int idx=0;
+ for (Map<int,Node>::Element*E=shader[i].node_map.front();E;E=E->next()) {
+
+ data[idx+0]=E->key();
+ data[idx+1]=E->get().type;
+ data[idx+2]=E->get().pos;
+ data[idx+3]=E->get().param1;
+ data[idx+4]=E->get().param2;
+
+ Array conns;
+ 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()) {
+
+ conns[idx2+0]=F->key();
+ conns[idx2+1]=F->get().id;
+ 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;
+ }
+ sh.push_back(data);
}
+ Dictionary data;
+ data["shaders"]=sh;
+ return data;
}
-Variant Shader::_get(const String& p_name) const {
- if (p_name.begins_with("nodes/")) {
- int idx=p_name.get_slice("/",1).to_int();
- Dictionary data;
- data["type"]=VisualServer::shader_node_get_type_info((VS::ShaderNodeType)node_get_type(idx)).name;
- data["pos"]=node_get_pos(idx);
- data["param"]=node_get_param(idx);
- return data;
- }
- if (p_name.begins_with("conns/")) {
- int idx=p_name.get_slice("/",1).to_int();
- Dictionary data;
- List<Connection> connections;
- get_connections(&connections);
- ERR_FAIL_INDEX_V( idx,connections.size(), Variant() );
- Connection c = connections[idx];
- data["src_id"]=c.src_id;
- data["src_slot"]=c.src_slot;
- data["dst_id"]=c.dst_id;
- data["dst_slot"]=c.dst_slot;
- return data;
- }
+ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
- return Variant();
+ ERR_FAIL_INDEX_V(p_type,3,GRAPH_OK);
+ return shader[p_type].error;
}
-void Shader::_get_property_list( List<PropertyInfo> *p_list) const {
- List<int> nodes;
- get_node_list(&nodes);
+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;
+}
- for(List<int>::Element *E=nodes.front();E;E=E->next()) {
+void ShaderGraph::_bind_methods() {
- int idx=E->get();
- p_list->push_back(PropertyInfo( Variant::DICTIONARY , "nodes/"+itos(idx),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) );
- }
+ ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader);
- List<Connection> connections;
- get_connections(&connections);
- int idx=0;
- for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
- p_list->push_back(PropertyInfo( Variant::DICTIONARY , "conns/"+itos(idx++),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) );
- }
+ ObjectTypeDB::bind_method(_MD("node_add","shader_type","node_type","id"),&ShaderGraph::node_add);
+ ObjectTypeDB::bind_method(_MD("node_remove","shader_type","id"),&ShaderGraph::node_remove);
+ ObjectTypeDB::bind_method(_MD("node_set_pos","shader_type","id","pos"),&ShaderGraph::node_set_pos);
+ ObjectTypeDB::bind_method(_MD("node_get_pos","shader_type","id"),&ShaderGraph::node_get_pos);
-}
+ ObjectTypeDB::bind_method(_MD("node_get_type","shader_type","id"),&ShaderGraph::node_get_type);
-Array Shader::_get_connections_helper() const {
+ ObjectTypeDB::bind_method(_MD("get_node_list","shader_type"),&ShaderGraph::_get_node_list);
- Array connections_ret;
- List<Connection> connections;
- get_connections(&connections);
- connections_ret.resize(connections.size());
+ 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);
- int idx=0;
- for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
+ 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);
- Connection c = E->get();
- Dictionary data;
- data["src_id"]=c.src_id;
- data["src_slot"]=c.src_slot;
- data["dst_id"]=c.dst_id;
- data["dst_slot"]=c.dst_slot;
- connections_ret.set(idx++,data);
- }
+ 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("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("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);
+
+
+// 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_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("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);
+
+ ObjectTypeDB::bind_method(_MD("vec_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_op_node_set_op);
+ ObjectTypeDB::bind_method(_MD("vec_op_node_get_op","shader_type","id"),&ShaderGraph::vec_op_node_get_op);
+
+ ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_scalar_op_node_set_op);
+ ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_get_op","shader_type","id"),&ShaderGraph::vec_scalar_op_node_get_op);
+
+ ObjectTypeDB::bind_method(_MD("rgb_op_node_set_op","shader_type","id","op"),&ShaderGraph::rgb_op_node_set_op);
+ ObjectTypeDB::bind_method(_MD("rgb_op_node_get_op","shader_type","id"),&ShaderGraph::rgb_op_node_get_op);
+
+
+ ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_set_no_translation","shader_type","id","disable"),&ShaderGraph::xform_vec_mult_node_set_no_translation);
+ ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_get_no_translation","shader_type","id"),&ShaderGraph::xform_vec_mult_node_get_no_translation);
+
+ ObjectTypeDB::bind_method(_MD("scalar_func_node_set_function","shader_type","id","func"),&ShaderGraph::scalar_func_node_set_function);
+ ObjectTypeDB::bind_method(_MD("scalar_func_node_get_function","shader_type","id"),&ShaderGraph::scalar_func_node_get_function);
+
+ ObjectTypeDB::bind_method(_MD("vec_func_node_set_function","shader_type","id","func"),&ShaderGraph::vec_func_node_set_function);
+ ObjectTypeDB::bind_method(_MD("vec_func_node_get_function","shader_type","id"),&ShaderGraph::vec_func_node_get_function);
+
+ ObjectTypeDB::bind_method(_MD("input_node_set_name","shader_type","id","name"),&ShaderGraph::input_node_set_name);
+ ObjectTypeDB::bind_method(_MD("input_node_get_name","shader_type","id"),&ShaderGraph::input_node_get_name);
+
+ ObjectTypeDB::bind_method(_MD("scalar_input_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("scalar_input_node_get_value","shader_type","id"),&ShaderGraph::scalar_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("vec_input_node_set_value","shader_type","id","value"),&ShaderGraph::vec_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("vec_input_node_get_value","shader_type","id"),&ShaderGraph::vec_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("rgb_input_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("rgb_input_node_get_value","shader_type","id"),&ShaderGraph::rgb_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("xform_input_node_set_value","shader_type","id","value"),&ShaderGraph::xform_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("xform_input_node_get_value","shader_type","id"),&ShaderGraph::xform_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("texture_input_node_set_value","shader_type","id","value:Texture"),&ShaderGraph::texture_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("texture_input_node_get_value:Texture","shader_type","id"),&ShaderGraph::texture_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("cubemap_input_node_set_value","shader_type","id","value:CubeMap"),&ShaderGraph::cubemap_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("cubemap_input_node_get_value:CubeMap","shader_type","id"),&ShaderGraph::cubemap_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("comment_node_set_text","shader_type","id","text"),&ShaderGraph::comment_node_set_text);
+ ObjectTypeDB::bind_method(_MD("comment_node_get_text","shader_type","id"),&ShaderGraph::comment_node_get_text);
+
+ ObjectTypeDB::bind_method(_MD("color_ramp_node_set_ramp","shader_type","id","colors","offsets"),&ShaderGraph::color_ramp_node_set_ramp);
+ ObjectTypeDB::bind_method(_MD("color_ramp_node_get_colors","shader_type","id"),&ShaderGraph::color_ramp_node_get_colors);
+ ObjectTypeDB::bind_method(_MD("color_ramp_node_get_offsets","shader_type","id"),&ShaderGraph::color_ramp_node_get_offsets);
+
+ ObjectTypeDB::bind_method(_MD("curve_map_node_set_points","shader_type","id","points"),&ShaderGraph::curve_map_node_set_points);
+ ObjectTypeDB::bind_method(_MD("curve_map_node_get_points","shader_type","id"),&ShaderGraph::curve_map_node_get_points);
+
+ ObjectTypeDB::bind_method(_MD("connect_node:Error","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::connect_node);
+ ObjectTypeDB::bind_method(_MD("is_node_connected","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::is_node_connected);
+ ObjectTypeDB::bind_method(_MD("disconnect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::disconnect_node);
+ ObjectTypeDB::bind_method(_MD("get_node_connections","shader_type"),&ShaderGraph::_get_connections);
+
+ 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("_set_data"),&ShaderGraph::_set_data);
+ ObjectTypeDB::bind_method(_MD("_get_data"),&ShaderGraph::_get_data);
+
+ ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"),_SCS("_get_data"));
+
+ //void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
- return connections_ret;
-}
-void Shader::_bind_methods() {
+ BIND_CONSTANT( NODE_INPUT ); // all inputs (shader type dependent)
+ BIND_CONSTANT( NODE_SCALAR_CONST ); //scalar constant
+ BIND_CONSTANT( NODE_VEC_CONST ); //vec3 constant
+ BIND_CONSTANT( NODE_RGB_CONST ); //rgb constant (shows a color picker instead)
+ BIND_CONSTANT( NODE_XFORM_CONST ); // 4x4 matrix constant
+ BIND_CONSTANT( NODE_TIME ); // time in seconds
+ BIND_CONSTANT( NODE_SCREEN_TEX ); // screen texture sampler (takes UV) (only usable in fragment shader)
+ BIND_CONSTANT( NODE_SCALAR_OP ); // scalar vs scalar op (mul ); add ); div ); etc)
+ BIND_CONSTANT( NODE_VEC_OP ); // vec3 vs vec3 op (mul );ad );div );crossprod );etc)
+ BIND_CONSTANT( NODE_VEC_SCALAR_OP ); // vec3 vs scalar op (mul ); add ); div ); etc)
+ BIND_CONSTANT( NODE_RGB_OP ); // vec3 vs vec3 rgb op (with scalar amount) ); like brighten ); darken ); burn ); dodge ); multiply ); etc.
+ BIND_CONSTANT( NODE_XFORM_MULT ); // mat4 x mat4
+ BIND_CONSTANT( NODE_XFORM_VEC_MULT ); // mat4 x vec3 mult (with no-translation option)
+ BIND_CONSTANT( NODE_XFORM_VEC_INV_MULT ); // mat4 x vec3 inverse mult (with no-translation option)
+ BIND_CONSTANT( NODE_SCALAR_FUNC ); // scalar function (sin ); cos ); etc)
+ BIND_CONSTANT( NODE_VEC_FUNC ); // vector function (normalize ); negate ); reciprocal ); rgb2hsv ); hsv2rgb ); etc ); etc)
+ BIND_CONSTANT( NODE_VEC_LEN ); // vec3 length
+ BIND_CONSTANT( NODE_DOT_PROD ); // vec3 . vec3 (dot product -> scalar output)
+ BIND_CONSTANT( NODE_VEC_TO_SCALAR ); // 1 vec3 input ); 3 scalar outputs
+ BIND_CONSTANT( NODE_SCALAR_TO_VEC ); // 3 scalar input ); 1 vec3 output
+ BIND_CONSTANT( NODE_VEC_TO_XFORM ); // 3 vec input ); 1 xform output
+ BIND_CONSTANT( NODE_XFORM_TO_VEC ); // 3 vec input ); 1 xform output
+ BIND_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve)
+ BIND_CONSTANT( NODE_VEC_INTERP ); // vec3 interpolation (with optional curve)
+ BIND_CONSTANT( NODE_COLOR_RAMP );
+ BIND_CONSTANT( NODE_CURVE_MAP );
+ BIND_CONSTANT( NODE_SCALAR_INPUT ); // scalar uniform (assignable in material)
+ BIND_CONSTANT( NODE_VEC_INPUT ); // vec3 uniform (assignable in material)
+ BIND_CONSTANT( NODE_RGB_INPUT ); // color uniform (assignable in material)
+ BIND_CONSTANT( NODE_XFORM_INPUT ); // mat4 uniform (assignable in material)
+ BIND_CONSTANT( NODE_TEXTURE_INPUT ); // texture input (assignable in material)
+ BIND_CONSTANT( NODE_CUBEMAP_INPUT ); // cubemap input (assignable in material)
+ BIND_CONSTANT( NODE_DEFAULT_TEXTURE );
+ BIND_CONSTANT( NODE_OUTPUT ); // output (shader type dependent)
+ BIND_CONSTANT( NODE_COMMENT ); // comment
+ BIND_CONSTANT( NODE_TYPE_MAX );
+
+ BIND_CONSTANT( SLOT_TYPE_SCALAR );
+ BIND_CONSTANT( SLOT_TYPE_VEC );
+ BIND_CONSTANT( SLOT_TYPE_XFORM );
+ BIND_CONSTANT( SLOT_TYPE_TEXTURE );
+ BIND_CONSTANT( SLOT_MAX );
+
+ BIND_CONSTANT( SHADER_TYPE_VERTEX );
+ BIND_CONSTANT( SHADER_TYPE_FRAGMENT );
+ BIND_CONSTANT( SHADER_TYPE_LIGHT );
+ BIND_CONSTANT( SHADER_TYPE_MAX );
+
+
+ BIND_CONSTANT( SLOT_IN );
+ BIND_CONSTANT( SLOT_OUT );
+
+ BIND_CONSTANT( GRAPH_OK );
+ BIND_CONSTANT( GRAPH_ERROR_CYCLIC );
+ BIND_CONSTANT( GRAPH_ERROR_MISSING_CONNECTIONS );
+
+ BIND_CONSTANT( SCALAR_OP_ADD );
+ BIND_CONSTANT( SCALAR_OP_SUB );
+ BIND_CONSTANT( SCALAR_OP_MUL );
+ BIND_CONSTANT( SCALAR_OP_DIV );
+ BIND_CONSTANT( SCALAR_OP_MOD );
+ BIND_CONSTANT( SCALAR_OP_POW );
+ BIND_CONSTANT( SCALAR_OP_MAX );
+ BIND_CONSTANT( SCALAR_OP_MIN );
+ BIND_CONSTANT( SCALAR_OP_ATAN2 );
+ BIND_CONSTANT( SCALAR_MAX_OP );
+
+ BIND_CONSTANT( VEC_OP_ADD );
+ BIND_CONSTANT( VEC_OP_SUB );
+ BIND_CONSTANT( VEC_OP_MUL );
+ BIND_CONSTANT( VEC_OP_DIV );
+ BIND_CONSTANT( VEC_OP_MOD );
+ BIND_CONSTANT( VEC_OP_POW );
+ BIND_CONSTANT( VEC_OP_MAX );
+ BIND_CONSTANT( VEC_OP_MIN );
+ BIND_CONSTANT( VEC_OP_CROSS );
+ BIND_CONSTANT( VEC_MAX_OP );
+
+ BIND_CONSTANT( VEC_SCALAR_OP_MUL );
+ BIND_CONSTANT( VEC_SCALAR_OP_DIV );
+ BIND_CONSTANT( VEC_SCALAR_OP_POW );
+ BIND_CONSTANT( VEC_SCALAR_MAX_OP );
+
+ BIND_CONSTANT( RGB_OP_SCREEN );
+ BIND_CONSTANT( RGB_OP_DIFFERENCE );
+ BIND_CONSTANT( RGB_OP_DARKEN );
+ BIND_CONSTANT( RGB_OP_LIGHTEN );
+ BIND_CONSTANT( RGB_OP_OVERLAY );
+ BIND_CONSTANT( RGB_OP_DODGE );
+ BIND_CONSTANT( RGB_OP_BURN );
+ BIND_CONSTANT( RGB_OP_SOFT_LIGHT );
+ BIND_CONSTANT( RGB_OP_HARD_LIGHT );
+ BIND_CONSTANT( RGB_MAX_OP );
+
+ BIND_CONSTANT( SCALAR_FUNC_SIN );
+ BIND_CONSTANT( SCALAR_FUNC_COS );
+ BIND_CONSTANT( SCALAR_FUNC_TAN );
+ BIND_CONSTANT( SCALAR_FUNC_ASIN );
+ BIND_CONSTANT( SCALAR_FUNC_ACOS );
+ BIND_CONSTANT( SCALAR_FUNC_ATAN );
+ BIND_CONSTANT( SCALAR_FUNC_SINH );
+ BIND_CONSTANT( SCALAR_FUNC_COSH );
+ BIND_CONSTANT( SCALAR_FUNC_TANH );
+ BIND_CONSTANT( SCALAR_FUNC_LOG );
+ BIND_CONSTANT( SCALAR_FUNC_EXP );
+ BIND_CONSTANT( SCALAR_FUNC_SQRT );
+ BIND_CONSTANT( SCALAR_FUNC_ABS );
+ BIND_CONSTANT( SCALAR_FUNC_SIGN );
+ BIND_CONSTANT( SCALAR_FUNC_FLOOR );
+ BIND_CONSTANT( SCALAR_FUNC_ROUND );
+ BIND_CONSTANT( SCALAR_FUNC_CEIL );
+ BIND_CONSTANT( SCALAR_FUNC_FRAC );
+ BIND_CONSTANT( SCALAR_FUNC_SATURATE );
+ BIND_CONSTANT( SCALAR_FUNC_NEGATE );
+ BIND_CONSTANT( SCALAR_MAX_FUNC );
+
+ BIND_CONSTANT( VEC_FUNC_NORMALIZE );
+ BIND_CONSTANT( VEC_FUNC_SATURATE );
+ BIND_CONSTANT( VEC_FUNC_NEGATE );
+ BIND_CONSTANT( VEC_FUNC_RECIPROCAL );
+ BIND_CONSTANT( VEC_FUNC_RGB2HSV );
+ BIND_CONSTANT( VEC_FUNC_HSV2RGB );
+ BIND_CONSTANT( VEC_MAX_FUNC );
+
+ ADD_SIGNAL(MethodInfo("updated"));
- ObjectTypeDB::bind_method(_MD("node_add"),&Shader::node_add );
- ObjectTypeDB::bind_method(_MD("node_remove"),&Shader::node_remove );
- ObjectTypeDB::bind_method(_MD("node_set_param"),&Shader::node_set_param );
- ObjectTypeDB::bind_method(_MD("node_set_pos"),&Shader::node_set_pos );
- ObjectTypeDB::bind_method(_MD("node_get_pos"),&Shader::node_get_pos );
- ObjectTypeDB::bind_method(_MD("node_get_param"),&Shader::node_get_type);
- ObjectTypeDB::bind_method(_MD("node_get_type"),&Shader::node_get_param);
+#if 0
+ ObjectTypeDB::bind_method(_MD("node_add"),&ShaderGraph::node_add );
+ ObjectTypeDB::bind_method(_MD("node_remove"),&ShaderGraph::node_remove );
+ ObjectTypeDB::bind_method(_MD("node_set_param"),&ShaderGraph::node_set_param );
+ ObjectTypeDB::bind_method(_MD("node_set_pos"),&ShaderGraph::node_set_pos );
+
+ ObjectTypeDB::bind_method(_MD("node_get_pos"),&ShaderGraph::node_get_pos );
+ ObjectTypeDB::bind_method(_MD("node_get_param"),&ShaderGraph::node_get_param);
+ ObjectTypeDB::bind_method(_MD("node_get_type"),&ShaderGraph::node_get_type);
- ObjectTypeDB::bind_method(_MD("connect"),&Shader::connect );
- ObjectTypeDB::bind_method(_MD("disconnect"),&Shader::disconnect );
+ ObjectTypeDB::bind_method(_MD("connect"),&ShaderGraph::connect );
+ ObjectTypeDB::bind_method(_MD("disconnect"),&ShaderGraph::disconnect );
- ObjectTypeDB::bind_method(_MD("get_connections"),&Shader::_get_connections_helper );
+ ObjectTypeDB::bind_method(_MD("get_connections"),&ShaderGraph::_get_connections_helper );
- ObjectTypeDB::bind_method(_MD("clear"),&Shader::clear );
+ ObjectTypeDB::bind_method(_MD("clear"),&ShaderGraph::clear );
BIND_CONSTANT( NODE_IN ); ///< param 0: name
BIND_CONSTANT( NODE_OUT ); ///< param 0: name
@@ -208,655 +468,2182 @@ void Shader::_bind_methods() {
BIND_CONSTANT( NODE_TEXTURE_2D_PARAMETER );
BIND_CONSTANT( NODE_TEXTURE_CUBE_PARAMETER );
BIND_CONSTANT( NODE_TYPE_MAX );
+#endif
}
-void Shader::node_add(NodeType p_type,int p_id) {
- VisualServer::get_singleton()->shader_node_add(shader,(VS::ShaderNodeType)p_type,p_id);
-#ifdef TOOLS_ENABLED
- positions[p_id]=Point2();
-#endif
- version++;
+String ShaderGraph::_find_unique_name(const String& p_base) {
+
+
+
+ int idx=1;
+ while(true) {
+ String tocmp=p_base;
+ if (idx>1) {
+ tocmp+="_"+itos(idx);
+ }
+ bool valid=true;
+ for(int i=0;i<3;i++) {
+ if (!valid)
+ break;
+ for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+ if (E->get().type!=NODE_SCALAR_INPUT && E->get().type!=NODE_VEC_INPUT && E->get().type==NODE_RGB_INPUT && E->get().type==NODE_XFORM_INPUT && E->get().type==NODE_TEXTURE_INPUT && E->get().type==NODE_CUBEMAP_INPUT)
+ continue;
+ String name = E->get().param1;
+ if (name==tocmp) {
+ valid=false;
+ break;
+ }
+
+ }
+ }
+
+ if (!valid) {
+ idx++;
+ continue;
+ }
+ return tocmp;
+ }
+ return String();
}
-void Shader::node_remove(int p_id) {
- VisualServer::get_singleton()->shader_node_remove(shader,p_id);
-#ifdef TOOLS_ENABLED
- positions.erase(p_id);
-#endif
+void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(p_id==0);
+ ERR_FAIL_COND(p_node_type==NODE_OUTPUT); //can't create output
+ ERR_FAIL_COND( shader[p_type].node_map.has(p_id ) );
+ ERR_FAIL_INDEX( p_node_type, NODE_TYPE_MAX );
+ Node node;
+
+ if (p_node_type==NODE_INPUT) {
+ //see if it already exists
+ for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+ if (E->get().type==NODE_INPUT) {
+ ERR_EXPLAIN("Only one input node can be added to the graph.");
+ ERR_FAIL_COND(E->get().type==NODE_INPUT);
+ }
+ }
+ }
+ node.type=p_node_type;
+ node.id=p_id;
+
+ switch(p_node_type) {
+ case NODE_INPUT: {} break; // all inputs (shader type dependent)
+ case NODE_SCALAR_CONST: { node.param1=0;} break; //scalar constant
+ case NODE_VEC_CONST: {node.param1=Vector3();} break; //vec3 constant
+ case NODE_RGB_CONST: {node.param1=Color();} break; //rgb constant (shows a color picker instead)
+ case NODE_XFORM_CONST: {node.param1=Transform();} break; // 4x4 matrix constant
+ case NODE_TIME: {} break; // time in seconds
+ case NODE_SCREEN_TEX: {Array arr; arr.push_back(0); arr.push_back(0); node.param2=arr;} break; // screen texture sampler (takes UV) (only usable in fragment shader)
+ case NODE_SCALAR_OP: {node.param1=SCALAR_OP_ADD;} break; // scalar vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
+ case NODE_VEC_OP: {node.param1=VEC_OP_ADD;} break; // vec3 vs vec3 op (mul: {} break;ad: {} break;div: {} break;crossprod: {} break;etc)
+ case NODE_VEC_SCALAR_OP: {node.param1=VEC_SCALAR_OP_MUL;} break; // vec3 vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
+ case NODE_RGB_OP: {node.param1=RGB_OP_SCREEN;} break; // vec3 vs vec3 rgb op (with scalar amount): {} break; like brighten: {} break; darken: {} break; burn: {} break; dodge: {} break; multiply: {} break; etc.
+ case NODE_XFORM_MULT: {} break; // mat4 x mat4
+ case NODE_XFORM_VEC_MULT: {} break; // mat4 x vec3 mult (with no-translation option)
+ case NODE_XFORM_VEC_INV_MULT: {} break; // mat4 x vec3 inverse mult (with no-translation option)
+ case NODE_SCALAR_FUNC: {node.param1=SCALAR_FUNC_SIN;} break; // scalar function (sin: {} break; cos: {} break; etc)
+ case NODE_VEC_FUNC: {node.param1=VEC_FUNC_NORMALIZE;} break; // vector function (normalize: {} break; negate: {} break; reciprocal: {} break; rgb2hsv: {} break; hsv2rgb: {} break; etc: {} break; etc)
+ case NODE_VEC_LEN: {} break; // vec3 length
+ case NODE_DOT_PROD: {} break; // vec3 . vec3 (dot product -> scalar output)
+ case NODE_VEC_TO_SCALAR: {} break; // 1 vec3 input: {} break; 3 scalar outputs
+ case NODE_SCALAR_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
+ case NODE_VEC_TO_XFORM: {} break; // 3 scalar input: {} break; 1 vec3 output
+ case NODE_XFORM_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
+ case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve)
+ case NODE_VEC_INTERP: {} break; // vec3 interpolation (with optional curve)
+ case NODE_COLOR_RAMP: { node.param1=DVector<Color>(); node.param2=DVector<real_t>();} break; // vec3 interpolation (with optional curve)
+ case NODE_CURVE_MAP: { node.param1=DVector<Vector2>();} break; // vec3 interpolation (with optional curve)
+ case NODE_SCALAR_INPUT: {node.param1=_find_unique_name("Scalar"); node.param2=0;} break; // scalar uniform (assignable in material)
+ case NODE_VEC_INPUT: {node.param1=_find_unique_name("Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material)
+ 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_DEFAULT_TEXTURE: {}; break;
+ case NODE_OUTPUT: {} break; // output (shader type dependent)
+ case NODE_COMMENT: {} break; // comment
+ case NODE_TYPE_MAX: {};
+ }
+ shader[p_type].node_map[p_id]=node;
+ _request_update();
}
-void Shader::node_set_param( int p_id, const Variant& p_value) {
- VisualServer::get_singleton()->shader_node_set_param(shader,p_id,p_value);
- version++;
+void ShaderGraph::node_set_pos(ShaderType p_type,int p_id, const Vector2& p_pos) {
+ ERR_FAIL_INDEX(p_type,3);
+
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ shader[p_type].node_map[p_id].pos=p_pos;
+ _request_update();
+
}
+Vector2 ShaderGraph::node_get_pos(ShaderType p_type,int p_id) const {
+ ERR_FAIL_INDEX_V(p_type,3,Vector2());
+
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector2());
+ return shader[p_type].node_map[p_id].pos;
+}
+
+
+void ShaderGraph::node_remove(ShaderType p_type,int p_id) {
+
+ ERR_FAIL_COND(p_id==0);
+ ERR_FAIL_INDEX(p_type,3);
+
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+
+ //erase connections associated with node
+ for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+ if (E->key()==p_id)
+ continue; //no self
-void Shader::get_node_list(List<int> *p_node_list) const {
+ for (Map<int,SourceSlot>::Element *F=E->get().connections.front();F;) {
+ Map<int,SourceSlot>::Element *N=F->next();
+
+ if (F->get().id==p_id) {
+ E->get().connections.erase(F);
+ }
+
+ F=N;
+ }
+ }
+
+ shader[p_type].node_map.erase(p_id);
+
+ _request_update();
- VisualServer::get_singleton()->shader_get_node_list(shader,p_node_list);
}
-Shader::NodeType Shader::node_get_type(int p_id) const {
- return (NodeType)VisualServer::get_singleton()->shader_node_get_type(shader,p_id);
+
+
+void ShaderGraph::get_node_list(ShaderType p_type,List<int> *p_node_list) const {
+
+ ERR_FAIL_INDEX(p_type,3);
+
+ Map<int,Node>::Element *E = shader[p_type].node_map.front();
+
+ while(E) {
+
+ p_node_list->push_back(E->key());
+ E=E->next();
+ }
}
-Variant Shader::node_get_param(int p_id) const {
- return VisualServer::get_singleton()->shader_node_get_param(shader,p_id);
+
+ShaderGraph::NodeType ShaderGraph::node_get_type(ShaderType p_type,int p_id) const {
+
+ ERR_FAIL_INDEX_V(p_type,3,NODE_TYPE_MAX);
+
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),NODE_TYPE_MAX);
+ return shader[p_type].node_map[p_id].type;
}
-void Shader::connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
- VisualServer::get_singleton()->shader_connect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot);
- version++;
+Error ShaderGraph::connect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+ ERR_FAIL_INDEX_V(p_type,3,ERR_INVALID_PARAMETER);
+
+ ERR_FAIL_COND_V(p_src_id==p_dst_id, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_src_id), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_dst_id), ERR_INVALID_PARAMETER);
+ NodeType type_src=shader[p_type].node_map[p_src_id].type;
+ NodeType type_dst=shader[p_type].node_map[p_dst_id].type;
+ ERR_FAIL_INDEX_V( p_src_slot, get_node_output_slot_count(get_mode(),p_type,type_src), ERR_INVALID_PARAMETER );
+ ERR_FAIL_INDEX_V( p_dst_slot, get_node_input_slot_count(get_mode(),p_type,type_dst), ERR_INVALID_PARAMETER );
+ ERR_FAIL_COND_V(get_node_output_slot_type(get_mode(),p_type,type_src,p_src_slot) != get_node_input_slot_type(get_mode(),p_type,type_dst,p_dst_slot), ERR_INVALID_PARAMETER );
+
+
+ SourceSlot ts;
+ ts.id=p_src_id;
+ ts.slot=p_src_slot;
+ shader[p_type].node_map[p_dst_id].connections[p_dst_slot]=ts;
+ _request_update();
+
+ return OK;
}
-void Shader::disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
- VisualServer::get_singleton()->shader_disconnect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot);
- version++;
+bool ShaderGraph::is_node_connected(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const {
+
+ ERR_FAIL_INDEX_V(p_type,3,false);
+
+ SourceSlot ts;
+ ts.id=p_src_id;
+ ts.slot=p_src_slot;
+ return shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
+ shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts;
}
-void Shader::get_connections(List<Connection> *p_connections) const {
+void ShaderGraph::disconnect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+ ERR_FAIL_INDEX(p_type,3);
- List<VS::ShaderConnection> connections;
- VisualServer::get_singleton()->shader_get_connections(shader,&connections);
- for( List<VS::ShaderConnection>::Element *E=connections.front();E;E=E->next()) {
+ SourceSlot ts;
+ ts.id=p_src_id;
+ ts.slot=p_src_slot;
+ if (shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
+ shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts) {
+ shader[p_type].node_map[p_dst_id].connections.erase(p_dst_slot);
- Connection c;
- c.src_id=E->get().src_id;
- c.src_slot=E->get().src_slot;
- c.dst_id=E->get().dst_id;
- c.dst_slot=E->get().dst_slot;
- p_connections->push_back(c);
}
+ _request_update();
+
}
-void Shader::node_set_pos(int p_id,const Point2& p_pos) {
+void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_connections) const {
-#ifdef TOOLS_ENABLED
- ERR_FAIL_COND(!positions.has(p_id));
- positions[p_id]=p_pos;
-#endif
+ ERR_FAIL_INDEX(p_type,3);
+
+ 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()) {
+
+ Connection c;
+ c.dst_id=E->key();
+ c.dst_slot=F->key();
+ c.src_id=F->get().id;
+ c.src_slot=F->get().slot;
+ p_connections->push_back(c);
+ }
+ }
}
-Point2 Shader::node_get_pos(int p_id) const {
-#ifdef TOOLS_ENABLED
- ERR_FAIL_COND_V(!positions.has(p_id),Point2());
- return positions[p_id];
-#endif
+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) {
+
+ ERR_FAIL_INDEX(p_type,3);
+ shader[p_type].node_map.clear();
+ Node out;
+ out.pos=Vector2(300,300);
+ out.type=NODE_OUTPUT;
+ shader[p_type].node_map.insert(0,out);
+
+ _request_update();
+
+}
+
+
+void ShaderGraph::scalar_const_node_set_value(ShaderType p_type,int p_id,float p_value) {
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_CONST);
+ n.param1=p_value;
+ _request_update();
+
+}
+
+float ShaderGraph::scalar_const_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,0);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_CONST,0);
+ return n.param1;
+}
+
+void ShaderGraph::vec_const_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_VEC_CONST);
+ n.param1=p_value;
+ _request_update();
+
+
+}
+Vector3 ShaderGraph::vec_const_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Vector3());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_CONST,Vector3());
+ return n.param1;
+
+}
+
+void ShaderGraph::rgb_const_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_RGB_CONST);
+ n.param1=p_value;
+ _request_update();
+
+}
+Color ShaderGraph::rgb_const_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Color());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_RGB_CONST,Color());
+ return n.param1;
+
}
-void Shader::clear() {
+void ShaderGraph::xform_const_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_XFORM_CONST);
+ n.param1=p_value;
+ _request_update();
- VisualServer::get_singleton()->shader_clear(shader);
- version++;
}
+Transform ShaderGraph::xform_const_node_get_value(ShaderType p_type,int p_id) const{
-Shader::Shader() {
+ ERR_FAIL_INDEX_V(p_type,3,Transform());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_XFORM_CONST,Transform());
+ return n.param1;
- shader = VisualServer::get_singleton()->shader_create();
- version = 1;
}
-Shader::~Shader() {
+void ShaderGraph::texture_node_set_filter_size(ShaderType p_type,int p_id,int p_size){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
+ Array arr = n.param2;
+ arr[0]=p_size;
+ n.param2=arr;
+ _request_update();
- VisualServer::get_singleton()->free(shader);
}
+int ShaderGraph::texture_node_get_filter_size(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,0);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
+ Array arr = n.param2;
+ return arr[0];
+
+}
+
+void ShaderGraph::texture_node_set_filter_strength(ShaderType p_type,float p_id,float p_strength){
-ShaderGraph::ShaderGraph()
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
+ Array arr = n.param2;
+ arr[1]=p_strength;
+ n.param2=arr;
+ _request_update();
+
+}
+float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type,float p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,0);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
+ Array arr = n.param2;
+ 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 VisualServer::shader_get_default_input_nodes(ShaderType p_type,List<PropertyInfo> *p_inputs) {
- switch(p_type) {
+void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp p_op){
- case SHADER_VERTEX: {
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_OP);
+ n.param1=p_op;
+ _request_update();
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- } break;
- case SHADER_FRAGMENT: {
+}
+ShaderGraph::ScalarOp ShaderGraph::scalar_op_node_get_op(ShaderType p_type,float p_id) const{
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"position") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
+ ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_OP);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_OP);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_OP,SCALAR_MAX_OP);
+ int op = n.param1;
+ return ScalarOp(op);
- } break;
- case SHADER_POST_PROCESS: {
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- } break;
+}
+
+
+void ShaderGraph::vec_op_node_set_op(ShaderType p_type,float p_id,VecOp p_op){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_VEC_OP);
+ n.param1=p_op;
+ _request_update();
+
+}
+ShaderGraph::VecOp ShaderGraph::vec_op_node_get_op(ShaderType p_type,float p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_OP);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_OP);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_OP,VEC_MAX_OP);
+ int op = n.param1;
+ return VecOp(op);
+
+}
+
+
+void ShaderGraph::vec_scalar_op_node_set_op(ShaderType p_type,float p_id,VecScalarOp p_op){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_VEC_SCALAR_OP);
+ n.param1=p_op;
+ _request_update();
+
+}
+ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_type,float p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,VEC_SCALAR_MAX_OP);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_SCALAR_MAX_OP);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_SCALAR_OP,VEC_SCALAR_MAX_OP);
+ int op = n.param1;
+ return VecScalarOp(op);
+
+}
+
+void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_RGB_OP);
+ n.param1=p_op;
+
+ _request_update();
+
+}
+ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type,float p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,RGB_MAX_OP);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),RGB_MAX_OP);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_RGB_OP,RGB_MAX_OP);
+ int op = n.param1;
+ return RGBOp(op);
+
+}
+
+
+void ShaderGraph::xform_vec_mult_node_set_no_translation(ShaderType p_type,int p_id,bool p_no_translation){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT);
+ n.param1=p_no_translation;
+ _request_update();
+
+}
+bool ShaderGraph::xform_vec_mult_node_get_no_translation(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,false);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),false);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT,false);
+ return n.param1;
+
+}
+
+void ShaderGraph::scalar_func_node_set_function(ShaderType p_type,int p_id,ScalarFunc p_func){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_FUNC);
+ int func = p_func;
+ ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
+ n.param1=func;
+ _request_update();
+
+}
+ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_FUNC);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_FUNC);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_FUNC,SCALAR_MAX_FUNC);
+ int func = n.param1;
+ 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);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_VEC_FUNC);
+ int func = p_func;
+ ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
+ n.param1=func;
+
+ _request_update();
+
+}
+ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type, int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_FUNC);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_FUNC);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_FUNC,VEC_MAX_FUNC);
+ int func = n.param1;
+ return VecFunc(func);
+}
+
+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();
+
+}
+
+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;
+
+
+}
+
+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;
+
+}
+
+
+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();
+
+}
+
+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;
+
+}
+
+
+
+void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p_name){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ ERR_FAIL_COND(!p_name.is_valid_identifier());
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT);
+
+ n.param1="";
+ n.param1=_find_unique_name(p_name);
+ _request_update();
+
+}
+String ShaderGraph::input_node_get_name(ShaderType p_type,int p_id){
+
+ ERR_FAIL_INDEX_V(p_type,3,String());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT,String());
+ return n.param1;
+}
+
+
+void ShaderGraph::scalar_input_node_set_value(ShaderType p_type,int p_id,float p_value) {
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT);
+ n.param2=p_value;
+ _request_update();
+
+}
+
+float ShaderGraph::scalar_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,0);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT,0);
+
+ return n.param2;
+}
+
+void ShaderGraph::vec_input_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_VEC_INPUT);
+
+ n.param2=p_value;
+ _request_update();
+
+}
+Vector3 ShaderGraph::vec_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Vector3());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_INPUT,Vector3());
+ return n.param2;
+}
+
+void ShaderGraph::rgb_input_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_RGB_INPUT);
+ n.param2=p_value;
+ _request_update();
+
+}
+Color ShaderGraph::rgb_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Color());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_RGB_INPUT,Color());
+ return n.param2;
+}
+
+void ShaderGraph::xform_input_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_XFORM_INPUT);
+ n.param2=p_value;
+ _request_update();
+
+}
+Transform ShaderGraph::xform_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Transform());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_XFORM_INPUT,Transform());
+ return n.param2;
+}
+
+
+void ShaderGraph::texture_input_node_set_value(ShaderType p_type,int p_id,const Ref<Texture>& p_texture) {
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT);
+ n.param2=p_texture;
+ _request_update();
+
+}
+
+Ref<Texture> ShaderGraph::texture_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Ref<Texture>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<Texture>());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT,Ref<Texture>());
+ return n.param2;
+}
+
+void ShaderGraph::cubemap_input_node_set_value(ShaderType p_type,int p_id,const Ref<CubeMap>& p_cubemap){
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_CUBEMAP_INPUT);
+ n.param2=p_cubemap;
+ _request_update();
+
+}
+
+Ref<CubeMap> ShaderGraph::cubemap_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Ref<CubeMap>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<CubeMap>());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_CUBEMAP_INPUT,Ref<CubeMap>());
+ return n.param2;
+
+}
+
+
+void ShaderGraph::comment_node_set_text(ShaderType p_type,int p_id,const String& p_comment) {
+
+ 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];
+ ERR_FAIL_COND(n.type!=NODE_COMMENT);
+ n.param1=p_comment;
+
+}
+
+String ShaderGraph::comment_node_get_text(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,String());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_COMMENT,String());
+ return n.param1;
+
+}
+
+void ShaderGraph::_request_update() {
+
+ if (_pending_update_shader)
+ return;
+
+ _pending_update_shader=true;
+ call_deferred("_update_shader");
+
+}
+
+Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const {
+
+ ERR_FAIL_INDEX_V(p_type,3,Variant());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Variant());
+ const Node& n = shader[p_type].node_map[p_id];
+ Dictionary s;
+ 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;
}
-void VisualServer::shader_get_default_output_nodes(ShaderType p_type,List<PropertyInfo> *p_outputs) {
+void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_state) {
+
+ 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];
+ Dictionary d = p_state;
+ 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]];
+ }
+}
- switch(p_type) {
+ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) {
- case SHADER_VERTEX: {
+ //shader = VisualServer::get_singleton()->shader_create();
+ _pending_update_shader=false;
+ Node out;
+ out.id=0;
+ out.pos=Vector2(250,20);
+ out.type=NODE_OUTPUT;
+ for(int i=0;i<3;i++) {
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- } break;
- case SHADER_FRAGMENT: {
+ shader[i].node_map.insert(0,out);
+ }
+}
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"diffuse") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"specular") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"emission") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"spec_exp") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"glow") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha_discard") );
+ShaderGraph::~ShaderGraph() {
- } break;
- case SHADER_POST_PROCESS: {
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- } break;
+ //VisualServer::get_singleton()->free(shader);
+}
+
+
+const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
+ //material vertex in
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","SRC_VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","SRC_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","SRC_TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"BinormalF","SRC_BINORMALF","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","SRC_COLOR","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","SRC_ALPHA","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","SRC_UV2","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ModelviewMatrix","MODELVIEW_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InstanceID","INSTANCE_ID","",SLOT_TYPE_SCALAR,SLOT_IN},
+
+ //material vertex out
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","UV2",".xy",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"SpecExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ //pixel vertex in
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Position","POSITION.xyz","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","IN_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV2","vec3(UV2,0)","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","vec3(SCREEN_UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ //pixel vertex out
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Diffuse","DIFFUSE_OUT","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"DiffuseAlpha","ALPHA_OUT","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"SpecularExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Emission","EMISSION","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Glow","GLOW","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Discard","DISCARD",">0.5",SLOT_TYPE_SCALAR,SLOT_OUT},
+ //light in
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDir","LIGHT_DIR","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDiffuse","LIGHT_DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightSpecular","LIGHT_SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"EyeVec","EYE_VEC","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Diffuse","DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"SpecExp","SPECULAR_EXP","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {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},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Color","SRC_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Alpha","SRC_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"ExtraMatrix","EXTRA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ //canvas item vertex out
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Vertex","VERTEX",".xy",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ //canvas item fragment in
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Color","SRC_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Alpha","SRC_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"UVScreen","vec3(SCREEN_UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"TexPixelSize","vec3(TEXTURE_PIXEL_SIZE,0)","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
+ //canvas item fragment out
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ //canvas item light in
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightColor","LIGHT_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightAlpha","LIGHT_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightHeight","LIGHT_HEIGHT","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"TexPixelSize","vec3(TEXTURE_PIXEL_SIZE,0)","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
+ //canvas item light out
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightColor","LIGHT.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightAlpha","LIGHT.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ //end
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT},
+
+
+
+};
+
+void ShaderGraph::get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_type==iop->shader_type) {
+
+ SlotInfo si;
+ si.dir=iop->dir;
+ si.name=iop->name;
+ si.type=iop->slot_type;
+ r_slots->push_back(si);
+ }
+ iop++;
+ }
+}
+
+
+const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= {
+
+ {NODE_SCALAR_CONST,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, //scalar constant
+ {NODE_VEC_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, //vec3 constant
+ {NODE_RGB_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, //rgb constant (shows a color picker instead)
+ {NODE_XFORM_CONST,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // 4x4 matrix constant
+ {NODE_TIME,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // time in seconds
+ {NODE_SCREEN_TEX,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // screen texture sampler (takes UV) (only usable in fragment shader)
+ {NODE_SCALAR_OP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_VEC_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_VEC_SCALAR_OP,{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_RGB_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_XFORM_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 x mat4
+ {NODE_XFORM_VEC_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 mult (with no-translation option)
+ {NODE_XFORM_VEC_INV_MULT,{SLOT_TYPE_VEC,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option)
+ {NODE_SCALAR_FUNC,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar function (sin,{SLOT_MAX},{SLOT_MAX}}, cos,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_VEC_FUNC,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vector function (normalize,{SLOT_MAX},{SLOT_MAX}}, negate,{SLOT_MAX},{SLOT_MAX}}, reciprocal,{SLOT_MAX},{SLOT_MAX}}, rgb2hsv,{SLOT_MAX},{SLOT_MAX}}, hsv2rgb,{SLOT_MAX},{SLOT_MAX}}, etc,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_VEC_LEN,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 length
+ {NODE_DOT_PROD,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 . vec3 (dot product -> scalar output)
+ {NODE_VEC_TO_SCALAR,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR}}, // 1 vec3 input,{SLOT_MAX},{SLOT_MAX}}, 3 scalar outputs
+ {NODE_SCALAR_TO_VEC,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // 3 scalar input,{SLOT_MAX},{SLOT_MAX}}, 1 vec3 output
+ {NODE_SCALAR_INTERP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar interpolation (with optional curve)
+ {NODE_VEC_INTERP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 interpolation (with optional curve)
+ {NODE_COLOR_RAMP,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 interpolation (with optional curve)
+ {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_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)
+ {NODE_DEFAULT_TEXTURE,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
+ {NODE_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment
+ {NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}}
+};
+
+int ShaderGraph::get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type) {
+
+ if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int pc=0;
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+ if (iop->dir==SLOT_OUT)
+ pc++;
+ }
+ iop++;
+ }
+ return pc;
+ } else if (p_type==NODE_VEC_TO_XFORM){
+ return 4;
+ } else if (p_type==NODE_XFORM_TO_VEC){
+ return 1;
+ } else {
+
+ const NodeSlotInfo*nsi=&node_slot_info[0];
+ while(nsi->type!=NODE_TYPE_MAX) {
+
+ if (nsi->type==p_type) {
+ int pc=0;
+ for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
+ if (nsi->ins[i]==SLOT_MAX)
+ break;
+ pc++;
+ }
+ return pc;
+ }
+
+ nsi++;
+ }
+
+ return 0;
}
+}
+
+int ShaderGraph::get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type){
+ if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int pc=0;
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+ if (iop->dir==SLOT_IN)
+ pc++;
+ }
+ iop++;
+ }
+ return pc;
+ } else if (p_type==NODE_VEC_TO_XFORM){
+ return 1;
+ } else if (p_type==NODE_XFORM_TO_VEC){
+ return 4;
+ } else {
+
+ const NodeSlotInfo*nsi=&node_slot_info[0];
+ while(nsi->type!=NODE_TYPE_MAX) {
+
+ if (nsi->type==p_type) {
+ int pc=0;
+ for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
+ if (nsi->outs[i]==SLOT_MAX)
+ break;
+ pc++;
+ }
+ return pc;
+ }
+
+ nsi++;
+ }
+
+ return 0;
+
+ }
}
+ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){
+
+ if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int pc=0;
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+ if (iop->dir==SLOT_OUT) {
+ if (pc==p_idx)
+ return iop->slot_type;
+ pc++;
+ }
+ }
+ iop++;
+ }
+ ERR_FAIL_V(SLOT_MAX);
+ } else if (p_type==NODE_VEC_TO_XFORM){
+ return SLOT_TYPE_VEC;
+ } else if (p_type==NODE_XFORM_TO_VEC){
+ return SLOT_TYPE_XFORM;
+ } else {
+
+ const NodeSlotInfo*nsi=&node_slot_info[0];
+ while(nsi->type!=NODE_TYPE_MAX) {
+
+ if (nsi->type==p_type) {
+ for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
+
+ if (nsi->ins[i]==SLOT_MAX)
+ break;
+ if (i==p_idx)
+ return nsi->ins[i];
+ }
+ }
+
+ nsi++;
+ }
+ ERR_FAIL_V(SLOT_MAX);
-PropertyInfo VisualServer::shader_node_get_type_info(ShaderNodeType p_type) {
-
- switch(p_type) {
-
- case NODE_IN: return PropertyInfo(Variant::STRING,"in");
- case NODE_OUT: return PropertyInfo(Variant::STRING,"out");
- case NODE_CONSTANT: return PropertyInfo(Variant::REAL,"const");
- case NODE_PARAMETER: return PropertyInfo(Variant::STRING,"param");
- case NODE_ADD: return PropertyInfo(Variant::NIL,"add");
- case NODE_SUB: return PropertyInfo(Variant::NIL,"sub");
- case NODE_MUL: return PropertyInfo(Variant::NIL,"mul");
- case NODE_DIV: return PropertyInfo(Variant::NIL,"div");
- case NODE_MOD: return PropertyInfo(Variant::NIL,"rem");
- case NODE_SIN: return PropertyInfo(Variant::NIL,"sin");
- case NODE_COS: return PropertyInfo(Variant::NIL,"cos");
- case NODE_TAN: return PropertyInfo(Variant::NIL,"tan");
- case NODE_ARCSIN: return PropertyInfo(Variant::NIL,"arcsin");
- case NODE_ARCCOS: return PropertyInfo(Variant::NIL,"arccos");
- case NODE_ARCTAN: return PropertyInfo(Variant::NIL,"arctan");
- case NODE_POW: return PropertyInfo(Variant::NIL,"pow");
- case NODE_LOG: return PropertyInfo(Variant::NIL,"log");
- case NODE_MAX: return PropertyInfo(Variant::NIL,"max");
- case NODE_MIN: return PropertyInfo(Variant::NIL,"min");
- case NODE_COMPARE: return PropertyInfo(Variant::NIL,"cmp");
- case NODE_TEXTURE: return PropertyInfo(Variant::_RID,"texture1D",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
- case NODE_TIME: return PropertyInfo(Variant::NIL,"time");
- case NODE_NOISE: return PropertyInfo(Variant::NIL,"noise");
- case NODE_PASS: return PropertyInfo(Variant::NIL,"pass");
- case NODE_VEC_IN: return PropertyInfo(Variant::STRING,"vin");
- case NODE_VEC_OUT: return PropertyInfo(Variant::STRING,"vout");
- case NODE_VEC_CONSTANT: return PropertyInfo(Variant::VECTOR3,"vconst");
- case NODE_VEC_PARAMETER: return PropertyInfo(Variant::STRING,"vparam");
- case NODE_VEC_ADD: return PropertyInfo(Variant::NIL,"vadd");
- case NODE_VEC_SUB: return PropertyInfo(Variant::NIL,"vsub");
- case NODE_VEC_MUL: return PropertyInfo(Variant::NIL,"vmul");
- case NODE_VEC_DIV: return PropertyInfo(Variant::NIL,"vdiv");
- case NODE_VEC_MOD: return PropertyInfo(Variant::NIL,"vrem");
- case NODE_VEC_CROSS: return PropertyInfo(Variant::NIL,"cross");
- case NODE_VEC_DOT: return PropertyInfo(Variant::NIL,"dot");
- case NODE_VEC_POW: return PropertyInfo(Variant::NIL,"vpow");
- case NODE_VEC_NORMALIZE: return PropertyInfo(Variant::NIL,"normalize");
- case NODE_VEC_INTERPOLATE: return PropertyInfo(Variant::NIL,"mix");
- case NODE_VEC_SCREEN_TO_UV: return PropertyInfo(Variant::NIL,"scrn2uv");
- case NODE_VEC_TRANSFORM3: return PropertyInfo(Variant::NIL,"xform3");
- case NODE_VEC_TRANSFORM4: return PropertyInfo(Variant::NIL,"xform4");
- case NODE_VEC_COMPARE: return PropertyInfo(Variant::_RID,"vcmp",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
- case NODE_VEC_TEXTURE_2D: return PropertyInfo(Variant::_RID,"texture2D",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
- case NODE_VEC_TEXTURE_CUBE: return PropertyInfo(Variant::NIL,"texcube");
- case NODE_VEC_NOISE: return PropertyInfo(Variant::NIL,"vec_noise");
- case NODE_VEC_0: return PropertyInfo(Variant::NIL,"vec_0");
- case NODE_VEC_1: return PropertyInfo(Variant::NIL,"vec_1");
- case NODE_VEC_2: return PropertyInfo(Variant::NIL,"vec_2");
- case NODE_VEC_BUILD: return PropertyInfo(Variant::NIL,"vbuild");
- case NODE_VEC_PASS: return PropertyInfo(Variant::NIL,"vpass");
- case NODE_COLOR_CONSTANT: return PropertyInfo(Variant::COLOR,"color_const");
- case NODE_COLOR_PARAMETER: return PropertyInfo(Variant::STRING,"color_param");
- case NODE_TEXTURE_PARAMETER: return PropertyInfo(Variant::STRING,"tex1D_param");
- case NODE_TEXTURE_2D_PARAMETER: return PropertyInfo(Variant::STRING,"tex2D_param");
- case NODE_TEXTURE_CUBE_PARAMETER: return PropertyInfo(Variant::STRING,"texcube_param");
- case NODE_TRANSFORM_CONSTANT: return PropertyInfo(Variant::TRANSFORM,"xform_const");
- case NODE_TRANSFORM_PARAMETER: return PropertyInfo(Variant::STRING,"xform_param");
- case NODE_LABEL: return PropertyInfo(Variant::STRING,"label");
-
- default: {}
-
- }
-
- ERR_FAIL_V( PropertyInfo(Variant::NIL,"error") );
-}
-int VisualServer::shader_get_input_count(ShaderNodeType p_type) {
-
- switch(p_type) {
- case NODE_IN: return 0;
- case NODE_OUT: return 1;
- case NODE_CONSTANT: return 0;
- case NODE_PARAMETER: return 0;
- case NODE_ADD: return 2;
- case NODE_SUB: return 2;
- case NODE_MUL: return 2;
- case NODE_DIV: return 2;
- case NODE_MOD: return 2;
- case NODE_SIN: return 1;
- case NODE_COS: return 1;
- case NODE_TAN: return 1;
- case NODE_ARCSIN: return 1;
- case NODE_ARCCOS: return 1;
- case NODE_ARCTAN: return 1;
- case NODE_POW: return 2;
- case NODE_LOG: return 1;
- case NODE_MAX: return 2;
- case NODE_MIN: return 2;
- case NODE_COMPARE: return 4;
- case NODE_TEXTURE: return 1; ///< param 0: texture
- case NODE_TIME: return 1; ///< param 0: interval length
- case NODE_NOISE: return 0;
- case NODE_PASS: return 1;
- case NODE_VEC_IN: return 0; ///< param 0: name
- case NODE_VEC_OUT: return 1; ///< param 0: name
- case NODE_VEC_CONSTANT: return 0; ///< param 0: value
- case NODE_VEC_PARAMETER: return 0; ///< param 0: name
- case NODE_VEC_ADD: return 2;
- case NODE_VEC_SUB: return 2;
- case NODE_VEC_MUL: return 2;
- case NODE_VEC_DIV: return 2;
- case NODE_VEC_MOD: return 2;
- case NODE_VEC_CROSS: return 2;
- case NODE_VEC_DOT: return 2;
- case NODE_VEC_POW: return 2;
- case NODE_VEC_NORMALIZE: return 1;
- case NODE_VEC_INTERPOLATE: return 3;
- case NODE_VEC_SCREEN_TO_UV: return 1;
- case NODE_VEC_TRANSFORM3: return 4;
- case NODE_VEC_TRANSFORM4: return 5;
- case NODE_VEC_COMPARE: return 4;
- case NODE_VEC_TEXTURE_2D: return 1;
- case NODE_VEC_TEXTURE_CUBE: return 1;
- case NODE_VEC_NOISE: return 0;
- case NODE_VEC_0: return 1;
- case NODE_VEC_1: return 1;
- case NODE_VEC_2: return 1;
- case NODE_VEC_BUILD: return 3;
- case NODE_VEC_PASS: return 1;
- case NODE_COLOR_CONSTANT: return 0;
- case NODE_COLOR_PARAMETER: return 0;
- case NODE_TEXTURE_PARAMETER: return 1;
- case NODE_TEXTURE_2D_PARAMETER: return 1;
- case NODE_TEXTURE_CUBE_PARAMETER: return 1;
- case NODE_TRANSFORM_CONSTANT: return 1;
- case NODE_TRANSFORM_PARAMETER: return 1;
- case NODE_LABEL: return 0;
- default: {}
- }
- ERR_FAIL_V( 0 );
-}
-int VisualServer::shader_get_output_count(ShaderNodeType p_type) {
-
- switch(p_type) {
- case NODE_IN: return 1;
- case NODE_OUT: return 0;
- case NODE_CONSTANT: return 1;
- case NODE_PARAMETER: return 1;
- case NODE_ADD: return 1;
- case NODE_SUB: return 1;
- case NODE_MUL: return 1;
- case NODE_DIV: return 1;
- case NODE_MOD: return 1;
- case NODE_SIN: return 1;
- case NODE_COS: return 1;
- case NODE_TAN: return 1;
- case NODE_ARCSIN: return 1;
- case NODE_ARCCOS: return 1;
- case NODE_ARCTAN: return 1;
- case NODE_POW: return 1;
- case NODE_LOG: return 1;
- case NODE_MAX: return 1;
- case NODE_MIN: return 1;
- case NODE_COMPARE: return 2;
- case NODE_TEXTURE: return 3; ///< param 0: texture
- case NODE_TIME: return 1; ///< param 0: interval length
- case NODE_NOISE: return 1;
- case NODE_PASS: return 1;
- case NODE_VEC_IN: return 1; ///< param 0: name
- case NODE_VEC_OUT: return 0; ///< param 0: name
- case NODE_VEC_CONSTANT: return 1; ///< param 0: value
- case NODE_VEC_PARAMETER: return 1; ///< param 0: name
- case NODE_VEC_ADD: return 1;
- case NODE_VEC_SUB: return 1;
- case NODE_VEC_MUL: return 1;
- case NODE_VEC_DIV: return 1;
- case NODE_VEC_MOD: return 1;
- case NODE_VEC_CROSS: return 1;
- case NODE_VEC_DOT: return 1;
- case NODE_VEC_POW: return 1;
- case NODE_VEC_NORMALIZE: return 1;
- case NODE_VEC_INTERPOLATE: return 1;
- case NODE_VEC_SCREEN_TO_UV: return 1;
- case NODE_VEC_TRANSFORM3: return 1;
- case NODE_VEC_TRANSFORM4: return 1;
- case NODE_VEC_COMPARE: return 2;
- case NODE_VEC_TEXTURE_2D: return 3;
- case NODE_VEC_TEXTURE_CUBE: return 3;
- case NODE_VEC_NOISE: return 1;
- case NODE_VEC_0: return 1;
- case NODE_VEC_1: return 1;
- case NODE_VEC_2: return 1;
- case NODE_VEC_BUILD: return 1;
- case NODE_VEC_PASS: return 1;
- case NODE_COLOR_CONSTANT: return 2;
- case NODE_COLOR_PARAMETER: return 2;
- case NODE_TEXTURE_PARAMETER: return 3;
- case NODE_TEXTURE_2D_PARAMETER: return 3;
- case NODE_TEXTURE_CUBE_PARAMETER: return 3;
- case NODE_TRANSFORM_CONSTANT: return 1;
- case NODE_TRANSFORM_PARAMETER: return 1;
- case NODE_LABEL: return 0;
-
- default: {}
- }
- ERR_FAIL_V( 0 );
-
-}
-
-#define RET2(m_a,m_b) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else return "";
-#define RET3(m_a,m_b,m_c) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else return "";
-#define RET4(m_a,m_b,m_c,m_d) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else return "";
-
-#define RET5(m_a,m_b,m_c,m_d,m_e) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else if (p_idx==4) return m_e; else return "";
-
-String VisualServer::shader_get_input_name(ShaderNodeType p_type,int p_idx) {
-
- switch(p_type) {
-
- case NODE_IN: return "";
- case NODE_OUT: return "out";
- case NODE_CONSTANT: return "";
- case NODE_PARAMETER: return "";
- case NODE_ADD: RET2("a","b");
- case NODE_SUB: RET2("a","b");
- case NODE_MUL: RET2("a","b");
- case NODE_DIV: RET2("a","b");
- case NODE_MOD: RET2("a","b");
- case NODE_SIN: return "rad";
- case NODE_COS: return "rad";
- case NODE_TAN: return "rad";
- case NODE_ARCSIN: return "in";
- case NODE_ARCCOS: return "in";
- case NODE_ARCTAN: return "in";
- case NODE_POW: RET2("in","exp");
- case NODE_LOG: return "in";
- case NODE_MAX: return "in";
- case NODE_MIN: return "in";
- case NODE_COMPARE: RET4("a","b","ret1","ret2");
- case NODE_TEXTURE: return "u";
- case NODE_TIME: return "";
- case NODE_NOISE: return "";
- case NODE_PASS: return "in";
- case NODE_VEC_IN: return "";
- case NODE_VEC_OUT: return "out";
- case NODE_VEC_CONSTANT: return "";
- case NODE_VEC_PARAMETER: return "";
- case NODE_VEC_ADD: RET2("a","b");
- case NODE_VEC_SUB: RET2("a","b");
- case NODE_VEC_MUL: RET2("a","b");
- case NODE_VEC_DIV: RET2("a","b");
- case NODE_VEC_MOD: RET2("a","b");
- case NODE_VEC_CROSS: RET2("a","b");
- case NODE_VEC_DOT: RET2("a","b");
- case NODE_VEC_POW: RET2("a","b");
- case NODE_VEC_NORMALIZE: return "vec";
- case NODE_VEC_INTERPOLATE: RET3("a","b","c");
- case NODE_VEC_SCREEN_TO_UV: return "scr";
- case NODE_VEC_TRANSFORM3: RET4("in","col0","col1","col2");
- case NODE_VEC_TRANSFORM4: RET5("in","col0","col1","col2","col3");
- case NODE_VEC_COMPARE: RET4("a","b","ret1","ret2");
- case NODE_VEC_TEXTURE_2D: return "uv";
- case NODE_VEC_TEXTURE_CUBE: return "uvw";
- case NODE_VEC_NOISE: return "";
- case NODE_VEC_0: return "vec";
- case NODE_VEC_1: return "vec";
- case NODE_VEC_2: return "vec";
- case NODE_VEC_BUILD: RET3("x/r","y/g","z/b");
- case NODE_VEC_PASS: return "in";
- case NODE_COLOR_CONSTANT: return "";
- case NODE_COLOR_PARAMETER: return "";
- case NODE_TEXTURE_PARAMETER: return "u";
- case NODE_TEXTURE_2D_PARAMETER: return "uv";
- case NODE_TEXTURE_CUBE_PARAMETER: return "uvw";
- case NODE_TRANSFORM_CONSTANT: return "in";
- case NODE_TRANSFORM_PARAMETER: return "in";
- case NODE_LABEL: return "";
-
- default: {}
- }
-
- ERR_FAIL_V("");
-}
-String VisualServer::shader_get_output_name(ShaderNodeType p_type,int p_idx) {
-
- switch(p_type) {
-
- case NODE_IN: return "in";
- case NODE_OUT: return "";
- case NODE_CONSTANT: return "out";
- case NODE_PARAMETER: return "out";
- case NODE_ADD: return "sum";
- case NODE_SUB: return "dif";
- case NODE_MUL: return "prod";
- case NODE_DIV: return "quot";
- case NODE_MOD: return "rem";
- case NODE_SIN: return "out";
- case NODE_COS: return "out";
- case NODE_TAN: return "out";
- case NODE_ARCSIN: return "rad";
- case NODE_ARCCOS: return "rad";
- case NODE_ARCTAN: return "rad";
- case NODE_POW: RET2("in","exp");
- case NODE_LOG: return "out";
- case NODE_MAX: return "out";
- case NODE_MIN: return "out";
- case NODE_COMPARE: RET2("a/b","a/b");
- case NODE_TEXTURE: RET3("rgb","a","v");
- case NODE_TIME: return "out";
- case NODE_NOISE: return "out";
- case NODE_PASS: return "out";
- case NODE_VEC_IN: return "in";
- case NODE_VEC_OUT: return "";
- case NODE_VEC_CONSTANT: return "out";
- case NODE_VEC_PARAMETER: return "out";
- case NODE_VEC_ADD: return "sum";
- case NODE_VEC_SUB: return "sub";
- case NODE_VEC_MUL: return "mul";
- case NODE_VEC_DIV: return "div";
- case NODE_VEC_MOD: return "rem";
- case NODE_VEC_CROSS: return "crs";
- case NODE_VEC_DOT: return "prod";
- case NODE_VEC_POW: return "out";
- case NODE_VEC_NORMALIZE: return "norm";
- case NODE_VEC_INTERPOLATE: return "out";
- case NODE_VEC_SCREEN_TO_UV: return "uv";
- case NODE_VEC_TRANSFORM3: return "prod";
- case NODE_VEC_TRANSFORM4: return "prod";
- case NODE_VEC_COMPARE: RET2("a/b","a/b");
- case NODE_VEC_TEXTURE_2D: RET3("rgb","a","v");
- case NODE_VEC_TEXTURE_CUBE: RET3("rgb","a","v");
- case NODE_VEC_NOISE: return "out";
- case NODE_VEC_0: return "x/r";
- case NODE_VEC_1: return "y/g";
- case NODE_VEC_2: return "z/b";
- case NODE_VEC_BUILD: return "vec";
- case NODE_VEC_PASS: return "out";
- case NODE_COLOR_CONSTANT: RET2("rgb","a");
- case NODE_COLOR_PARAMETER: RET2("rgb","a");
- case NODE_TEXTURE_PARAMETER: RET3("rgb","a","v");
- case NODE_TEXTURE_2D_PARAMETER: RET3("rgb","a","v");
- case NODE_TEXTURE_CUBE_PARAMETER: RET3("rgb","a","v");
- case NODE_TRANSFORM_CONSTANT: return "out";
- case NODE_TRANSFORM_PARAMETER: return "out";
- case NODE_LABEL: return "";
-
- default: {}
- }
-
- ERR_FAIL_V("");
-}
-bool VisualServer::shader_is_input_vector(ShaderNodeType p_type,int p_input) {
-
- switch(p_type) {
-
- case NODE_IN: return false;
- case NODE_OUT: return false;
- case NODE_CONSTANT: return false;
- case NODE_PARAMETER: return false;
- case NODE_ADD: return false;
- case NODE_SUB: return false;
- case NODE_MUL: return false;
- case NODE_DIV: return false;
- case NODE_MOD: return false;
- case NODE_SIN: return false;
- case NODE_COS: return false;
- case NODE_TAN: return false;
- case NODE_ARCSIN: return false;
- case NODE_ARCCOS: return false;
- case NODE_ARCTAN: return false;
- case NODE_POW: return false;
- case NODE_LOG: return false;
- case NODE_MAX: return false;
- case NODE_MIN: return false;
- case NODE_COMPARE: return false;
- case NODE_TEXTURE: return false;
- case NODE_TIME: return false;
- case NODE_NOISE: return false;
- case NODE_PASS: return false;
- case NODE_VEC_IN: return false;
- case NODE_VEC_OUT: return true;
- case NODE_VEC_CONSTANT: return false;
- case NODE_VEC_PARAMETER: return false;
- case NODE_VEC_ADD: return true;
- case NODE_VEC_SUB: return true;
- case NODE_VEC_MUL: return true;
- case NODE_VEC_DIV: return true;
- case NODE_VEC_MOD: return true;
- case NODE_VEC_CROSS: return true;
- case NODE_VEC_DOT: return true;
- case NODE_VEC_POW: return (p_input==0)?true:false;
- case NODE_VEC_NORMALIZE: return true;
- case NODE_VEC_INTERPOLATE: return (p_input<2)?true:false;
- case NODE_VEC_SCREEN_TO_UV: return true;
- case NODE_VEC_TRANSFORM3: return true;
- case NODE_VEC_TRANSFORM4: return true;
- case NODE_VEC_COMPARE: return (p_input<2)?false:true;
- case NODE_VEC_TEXTURE_2D: return true;
- case NODE_VEC_TEXTURE_CUBE: return true;
- case NODE_VEC_NOISE: return false;
- case NODE_VEC_0: return true;
- case NODE_VEC_1: return true;
- case NODE_VEC_2: return true;
- case NODE_VEC_BUILD: return false;
- case NODE_VEC_PASS: return true;
- case NODE_COLOR_CONSTANT: return false;
- case NODE_COLOR_PARAMETER: return false;
- case NODE_TEXTURE_PARAMETER: return false;
- case NODE_TEXTURE_2D_PARAMETER: return true;
- case NODE_TEXTURE_CUBE_PARAMETER: return true;
- case NODE_TRANSFORM_CONSTANT: return true;
- case NODE_TRANSFORM_PARAMETER: return true;
- case NODE_LABEL: return false;
-
- default: {}
- }
-
- ERR_FAIL_V(false);
-}
-bool VisualServer::shader_is_output_vector(ShaderNodeType p_type,int p_input) {
-
- switch(p_type) {
-
- case NODE_IN: return false;
- case NODE_OUT: return false ;
- case NODE_CONSTANT: return false;
- case NODE_PARAMETER: return false;
- case NODE_ADD: return false;
- case NODE_SUB: return false;
- case NODE_MUL: return false;
- case NODE_DIV: return false;
- case NODE_MOD: return false;
- case NODE_SIN: return false;
- case NODE_COS: return false;
- case NODE_TAN: return false;
- case NODE_ARCSIN: return false;
- case NODE_ARCCOS: return false;
- case NODE_ARCTAN: return false;
- case NODE_POW: return false;
- case NODE_LOG: return false;
- case NODE_MAX: return false;
- case NODE_MIN: return false;
- case NODE_COMPARE: return false;
- case NODE_TEXTURE: return false;
- case NODE_TIME: return false;
- case NODE_NOISE: return false;
- case NODE_PASS: return false;
- case NODE_VEC_IN: return true;
- case NODE_VEC_OUT: return false;
- case NODE_VEC_CONSTANT: return true;
- case NODE_VEC_PARAMETER: return true;
- case NODE_VEC_ADD: return true;
- case NODE_VEC_SUB: return true;
- case NODE_VEC_MUL: return true;
- case NODE_VEC_DIV: return true;
- case NODE_VEC_MOD: return true;
- case NODE_VEC_CROSS: return true;
- case NODE_VEC_DOT: return false;
- case NODE_VEC_POW: return true;
- case NODE_VEC_NORMALIZE: return true;
- case NODE_VEC_INTERPOLATE: return true;
- case NODE_VEC_SCREEN_TO_UV: return true;
- case NODE_VEC_TRANSFORM3: return true;
- case NODE_VEC_TRANSFORM4: return true;
- case NODE_VEC_COMPARE: return true;
- case NODE_VEC_TEXTURE_2D: return (p_input==0)?true:false;
- case NODE_VEC_TEXTURE_CUBE: return (p_input==0)?true:false;
- case NODE_VEC_NOISE: return true;
- case NODE_VEC_0: return false;
- case NODE_VEC_1: return false;
- case NODE_VEC_2: return false;
- case NODE_VEC_BUILD: return true;
- case NODE_VEC_PASS: return true;
- case NODE_COLOR_CONSTANT: return (p_input==0)?true:false;
- case NODE_COLOR_PARAMETER: return (p_input==0)?true:false;
- case NODE_TEXTURE_PARAMETER: return (p_input==0)?true:false;
- case NODE_TEXTURE_2D_PARAMETER: return (p_input==0)?true:false;
- case NODE_TEXTURE_CUBE_PARAMETER: return (p_input==0)?true:false;
- case NODE_TRANSFORM_CONSTANT: return true;
- case NODE_TRANSFORM_PARAMETER: return true;
- case NODE_LABEL: return false;
-
- default: {}
- }
-
- ERR_FAIL_V("");
+ }
}
+ShaderGraph::SlotType ShaderGraph::get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){
+
+ if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int pc=0;
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+ if (iop->dir==SLOT_IN) {
+ if (pc==p_idx)
+ return iop->slot_type;
+ pc++;
+ }
+ }
+ iop++;
+ }
+ ERR_FAIL_V(SLOT_MAX);
+ } else if (p_type==NODE_VEC_TO_XFORM){
+ return SLOT_TYPE_XFORM;
+ } else if (p_type==NODE_XFORM_TO_VEC){
+ return SLOT_TYPE_VEC;
+ } else {
+
+ const NodeSlotInfo*nsi=&node_slot_info[0];
+ while(nsi->type!=NODE_TYPE_MAX) {
+
+ if (nsi->type==p_type) {
+ for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
+ if (nsi->outs[i]==SLOT_MAX)
+ break;
+ if (i==p_idx)
+ return nsi->outs[i];
+ }
+ }
+
+ nsi++;
+ }
+ ERR_FAIL_V(SLOT_MAX);
+ }
+}
-#endif
+
+
+
+
+void ShaderGraph::_update_shader() {
+
+
+ String code[3];
+
+ List<StringName> names;
+ get_default_texture_param_list(&names);
+
+ for (List<StringName>::Element *E=names.front();E;E=E->next()) {
+
+ set_default_texture_param(E->get(),Ref<Texture>());
+ }
+
+
+ for(int i=0;i<3;i++) {
+
+ int idx=0;
+ for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+ E->get().sort_order=idx++;
+ }
+ //simple method for graph solving using bubblesort derived algorithm
+ int iters=0;
+ int iter_max=shader[i].node_map.size()*shader[i].node_map.size();
+
+ while(true) {
+ if (iters>iter_max)
+ break;
+
+ int swaps=0;
+ for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+ for(Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
+
+ //this is kinda slow, could be sped up
+ Map<int,Node>::Element *G = shader[i].node_map.find(F->get().id);
+ ERR_FAIL_COND(!G);
+ if (G->get().sort_order > E->get().sort_order) {
+
+ SWAP(G->get().sort_order,E->get().sort_order);
+ swaps++;
+ }
+ }
+ }
+
+ iters++;
+ if (swaps==0) {
+ iters=0;
+ break;
+ }
+ }
+
+ if (iters>0) {
+
+ shader[i].error=GRAPH_ERROR_CYCLIC;
+ continue;
+ }
+
+ Vector<Node*> order;
+ order.resize(shader[i].node_map.size());
+
+ for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+ order[E->get().sort_order]=&E->get();
+ }
+
+ //generate code for the ordered graph
+ bool failed=false;
+
+ if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+ code[i]+="vec3 DIFFUSE_OUT=vec3(0,0,0);\n";
+ code[i]+="float ALPHA_OUT=0;\n";
+ }
+
+
+ Map<String,String> inputs_xlate;
+ Map<String,String> input_names_xlate;
+ Set<String> inputs_used;
+
+ for(int j=0;j<order.size();j++) {
+
+ Node *n=order[j];
+ if (n->type==NODE_INPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int idx=0;
+ while(iop->name) {
+ if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_IN==iop->dir) {
+
+ const char *typestr[4]={"float","vec3","mat4","texture"};
+
+ String vname=("nd"+itos(n->id)+"sl"+itos(idx));
+ inputs_xlate[vname]=String(typestr[iop->slot_type])+" "+vname+"="+iop->variable+";\n";
+ input_names_xlate[vname]=iop->variable;
+ idx++;
+ }
+ iop++;
+ }
+
+ } else if (n->type==NODE_OUTPUT) {
+
+
+ bool use_alpha=false;
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int idx=0;
+ while(iop->name) {
+ if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_OUT==iop->dir) {
+
+ if (n->connections.has(idx)) {
+ String iname=("nd"+itos(n->connections[idx].id)+"sl"+itos(n->connections[idx].slot));
+ if (node_get_type(ShaderType(i),n->connections[idx].id)==NODE_INPUT)
+ inputs_used.insert(iname);
+ code[i]+=String(iop->variable)+"="+iname+String(iop->postfix)+";\n";
+ if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL && String(iop->name)=="DiffuseAlpha")
+ use_alpha=true;
+ }
+ idx++;
+ }
+ iop++;
+ }
+
+ if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+
+ if (use_alpha) {
+ code[i]+="DIFFUSE_ALPHA=vec4(DIFFUSE_OUT,ALPHA_OUT);\n";
+ } else {
+ code[i]+="DIFFUSE=DIFFUSE_OUT;\n";
+ }
+ }
+
+ } else {
+ 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)) {
+ 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);
+ }
+
+ }
+ inputs.push_back(iname);
+ }
+
+ if (failed)
+ break;
+
+ if (n->type==NODE_TEXTURE_INPUT || n->type==NODE_CUBEMAP_INPUT) {
+
+ set_default_texture_param(n->param1,n->param2);
+
+ }
+ _add_node_code(ShaderType(i),n,inputs,code[i]);
+ }
+
+ }
+
+ if (failed)
+ continue;
+
+
+ for(Set<String>::Element *E=inputs_used.front();E;E=E->next()) {
+
+ ERR_CONTINUE( !inputs_xlate.has(E->get()));
+ code[i]=inputs_xlate[E->get()]+code[i];
+ String name=input_names_xlate[E->get()];
+
+ if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_MATERIAL) {
+ if (name==("SRC_COLOR"))
+ code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
+ if (name==("SRC_ALPHA"))
+ code[i]="float SRC_ALPHA=COLOR.a;\n"+code[i];
+ if (name==("SRC_UV"))
+ code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
+ if (name==("SRC_UV2"))
+ code[i]="float SRC_UV2=vec3(UV2,0);\n"+code[i];
+ } else if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+ if (name==("IN_NORMAL"))
+ code[i]="vec3 IN_NORMAL=NORMAL;\n"+code[i];
+ } else if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_CANVAS_ITEM) {
+ if (name==("SRC_COLOR"))
+ code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
+ if (name==("SRC_UV"))
+ code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
+ }
+
+ }
+
+
+
+ shader[i].error=GRAPH_OK;
+
+ }
+
+ bool all_ok=true;
+ for(int i=0;i<3;i++) {
+ if (shader[i].error!=GRAPH_OK)
+ all_ok=false;
+ }
+
+ /*print_line("VERTEX: \n"+code[0]);
+ print_line("FRAGMENT: \n"+code[1]);
+ print_line("LIGHT: \n"+code[2]);*/
+
+ if (all_ok) {
+ set_code(code[0],code[1],code[2]);
+ }
+ //do shader here
+
+ _pending_update_shader=false;
+ emit_signal(SceneStringNames::get_singleton()->updated);
+}
+
+void ShaderGraph::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d,uint8_t* p_heights,bool *p_useds) {
+
+ float geometry[4][4];
+ float tmp1[4][4];
+ float tmp2[4][4];
+ float deltas[4][4];
+ double x, dx, dx2, dx3;
+ double y, dy, dy2, dy3;
+ double d, d2, d3;
+ int lastx, lasty;
+ int newx, newy;
+ int ntimes;
+ int i,j;
+
+ int xmax=255;
+ int ymax=255;
+
+ /* construct the geometry matrix from the segment */
+ for (i = 0; i < 4; i++) {
+ geometry[i][2] = 0;
+ geometry[i][3] = 0;
+ }
+
+ geometry[0][0] = (p_a[0] * xmax);
+ geometry[1][0] = (p_b[0] * xmax);
+ geometry[2][0] = (p_c[0] * xmax);
+ geometry[3][0] = (p_d[0] * xmax);
+
+ geometry[0][1] = (p_a[1] * ymax);
+ geometry[1][1] = (p_b[1] * ymax);
+ geometry[2][1] = (p_c[1] * ymax);
+ geometry[3][1] = (p_d[1] * ymax);
+
+ /* subdivide the curve ntimes (1000) times */
+ ntimes = 4 * xmax;
+ /* ntimes can be adjusted to give a finer or coarser curve */
+ d = 1.0 / ntimes;
+ d2 = d * d;
+ 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;
+
+ /* 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 },
+ };
+
+ for (i = 0; i < 4; i++)
+ {
+ 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]);
+ }
+ }
+ /* compose the above results to get the deltas matrix */
+
+ for (i = 0; i < 4; i++)
+ {
+ 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]);
+ }
+ }
+
+
+ /* extract the x deltas */
+ x = deltas[0][0];
+ dx = deltas[1][0];
+ dx2 = deltas[2][0];
+ dx3 = deltas[3][0];
+
+ /* extract the y deltas */
+ y = deltas[0][1];
+ dy = deltas[1][1];
+ dy2 = deltas[2][1];
+ dy3 = deltas[3][1];
+
+
+ lastx = CLAMP (x, 0, xmax);
+ lasty = CLAMP (y, 0, ymax);
+
+ p_heights[lastx] = lasty;
+ p_useds[lastx] = true;
+
+ /* loop over the curve */
+ for (i = 0; i < ntimes; i++)
+ {
+ /* increment the x values */
+ x += dx;
+ dx += dx2;
+ dx2 += dx3;
+
+ /* increment the y values */
+ y += dy;
+ dy += dy2;
+ dy2 += dy3;
+
+ newx = CLAMP ((Math::round (x)), 0, xmax);
+ newy = CLAMP ((Math::round (y)), 0, ymax);
+
+ /* if this point is different than the last one...then draw it */
+ if ((lastx != newx) || (lasty != newy))
+ {
+ p_useds[newx]=true;
+ p_heights[newx]=newy;
+ }
+
+ lastx = newx;
+ lasty = newy;
+ }
+}
+
+
+void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) {
+
+
+ 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) {
+
+ case NODE_INPUT: {
+
+
+ }break;
+ case NODE_SCALAR_CONST: {
+
+ double scalar = p_node->param1;
+ code+=OUTNAME(p_node->id,0)+"="+rtos(scalar)+";\n";
+ }break;
+ case NODE_VEC_CONST: {
+ Vector3 vec = p_node->param1;
+ code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(vec.x)+","+rtos(vec.y)+","+rtos(vec.z)+");\n";
+ }break;
+ case NODE_RGB_CONST: {
+ Color col = p_node->param1;
+ code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n";
+ code+=OUTNAME(p_node->id,1)+"="+rtos(col.a)+";\n";
+ }break;
+ case NODE_XFORM_CONST: {
+
+ Transform xf = p_node->param1;
+ code+=OUTNAME(p_node->id,0)+"=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+=");";
+
+ }break;
+ case NODE_TIME: {
+ 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) {
+
+ case SCALAR_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
+ case SCALAR_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
+ case SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+ case SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+ case SCALAR_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case SCALAR_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case SCALAR_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case SCALAR_OP_ATAN2: optxt = "atan2("+p_inputs[0]+","+p_inputs[1]+");"; break;
+
+ }
+ code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";;
+
+ }break;
+ case NODE_VEC_OP: {
+ DEF_VEC(0);
+ DEF_VEC(1);
+ int op = p_node->param1;
+ String optxt;
+ switch(op) {
+ case VEC_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
+ case VEC_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
+ case VEC_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+ case VEC_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+ case VEC_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case VEC_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case VEC_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case VEC_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case VEC_OP_CROSS: optxt = "cross("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ }
+ code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
+
+ }break;
+ case NODE_VEC_SCALAR_OP: {
+ DEF_VEC(0);
+ DEF_SCALAR(1);
+ int op = p_node->param1;
+ String optxt;
+ switch(op) {
+ case VEC_SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+ case VEC_SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+ case VEC_SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ }
+ code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
+
+ }break;
+ case NODE_RGB_OP: {
+ DEF_COLOR(0);
+ DEF_COLOR(1);
+
+ int op = p_node->param1;
+ static const char*axisn[3]={"x","y","z"};
+ switch(op) {
+ case RGB_OP_SCREEN: {
+
+ code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")*(vec3(1.0)-"+p_inputs[1]+");\n";
+ } break;
+ case RGB_OP_DIFFERENCE: {
+
+ code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
+ } break;
+ case RGB_OP_DARKEN: {
+
+ code += OUTNAME(p_node->id,0)+"=min("+p_inputs[0]+","+p_inputs[1]+");\n";
+ } break;
+ case RGB_OP_LIGHTEN: {
+
+ code += OUTNAME(p_node->id,0)+"=max("+p_inputs[0]+","+p_inputs[1]+");\n";
+
+ } break;
+ case RGB_OP_OVERLAY: {
+
+ code += OUTNAME(p_node->id,0)+";\n";
+ for(int i=0;i<3;i++) {
+ code += "{\n";
+ code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+ code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+ code += "\tif (base < 0.5) {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 2.0 * base * blend;\n";
+ code += "\t} else {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n";
+ code += "\t}\n";
+ code += "}\n";
+ }
+
+ } break;
+ case RGB_OP_DODGE: {
+
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+")/(vec3(1.0)-"+p_inputs[1]+");\n";
+
+ } break;
+ case RGB_OP_BURN: {
+
+ code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")/("+p_inputs[1]+");\n";
+ } break;
+ case RGB_OP_SOFT_LIGHT: {
+
+ code += OUTNAME(p_node->id,0)+";\n";
+ for(int i=0;i<3;i++) {
+ code += "{\n";
+ code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+ code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+ code += "\tif (base < 0.5) {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (blend+0.5));\n";
+ code += "\t} else {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-(blend-0.5)));\n";
+ code += "\t}\n";
+ code += "}\n";
+ }
+
+ } break;
+ case RGB_OP_HARD_LIGHT: {
+
+ code += OUTNAME(p_node->id,0)+";\n";
+ for(int i=0;i<3;i++) {
+ code += "{\n";
+ code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+ code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+ code += "\tif (base < 0.5) {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (2*blend));\n";
+ code += "\t} else {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-2*(blend-0.5)));\n";
+ code += "\t}\n";
+ code += "}\n";
+ }
+
+ } break;
+ }
+ }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) {
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",0)).xyz;\n";
+ } else {
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",1)).xyz;\n";
+ }
+
+ }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";
+ } else {
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",1)).xyz;\n";
+ }
+ }break;
+ case NODE_SCALAR_FUNC: {
+ DEF_SCALAR(0);
+ static const char*scalar_func_id[SCALAR_MAX_FUNC]={
+ "sin($)",
+ "cos($)",
+ "tan($)",
+ "asin($)",
+ "acos($)",
+ "atan($)",
+ "sinh($)",
+ "cosh($)",
+ "tanh($)",
+ "log($)",
+ "exp($)",
+ "sqrt($)",
+ "abs($)",
+ "sign($)",
+ "floor($)",
+ "round($)",
+ "ceil($)",
+ "fract($)",
+ "min(max($,0),1)",
+ "-($)",
+ };
+
+ int func = p_node->param1;
+ ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
+ code += OUTNAME(p_node->id,0)+"="+String(scalar_func_id[func]).replace("$",p_inputs[0])+";\n";
+
+ } 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))",
+ "-($)",
+ "1.0/($)",
+ "",
+ "",
+ };
+
+
+ int func = p_node->param1;
+ ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
+ if (func==VEC_FUNC_RGB2HSV) {
+ code += OUTNAME(p_node->id,0)+";\n";
+ code+="{\n";
+ code+="\tvec3 c = "+p_inputs[0]+";\n";
+ code+="\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
+ code+="\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
+ code+="\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
+ code+="\tfloat d = q.x - min(q.w, q.y);\n";
+ code+="\tfloat e = 1.0e-10;\n";
+ code+="\t"+OUTVAR(p_node->id,0)+"=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
+ code+="}\n";
+ } else if (func==VEC_FUNC_HSV2RGB) {
+ code += OUTNAME(p_node->id,0)+";\n";;
+ code+="{\n";
+ code+="\tvec3 c = "+p_inputs[0]+";\n";
+ code+="\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
+ code+="\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
+ code+="\t"+OUTVAR(p_node->id,0)+"=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
+ code+="}\n";
+
+ } else {
+ code += OUTNAME(p_node->id,0)+"="+String(vec_func_id[func]).replace("$",p_inputs[0])+";\n";
+ }
+ }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: {
+ 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: {
+ 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;
+ cramp.resize(color_ramp_len*4);
+ {
+
+ DVector<Color> colors=p_node->param1;
+ DVector<real_t> offsets=p_node->param2;
+ int cc =colors.size();
+ DVector<uint8_t>::Write crw = cramp.write();
+ DVector<Color>::Read cr = colors.read();
+ DVector<real_t>::Read ofr = offsets.read();
+
+ int at=0;
+ Color color_at(0,0,0,1);
+ for(int i=0;i<=cc;i++) {
+
+ int pos;
+ Color to;
+ if (i==cc) {
+ if (at==color_ramp_len)
+ break;
+ pos=color_ramp_len;
+ to=Color(1,1,1,1);
+ } else {
+ to=cr[i];
+ pos= MIN(ofr[i]*color_ramp_len,color_ramp_len);
+ }
+ for(int j=at;j<pos;j++) {
+ float t = (j-at)/float(pos-at);
+ Color c = color_at.linear_interpolate(to,t);
+ crw[j*4+0]=Math::fast_ftoi( CLAMP(c.r*255.0,0,255) );
+ crw[j*4+1]=Math::fast_ftoi( CLAMP(c.g*255.0,0,255) );
+ crw[j*4+2]=Math::fast_ftoi( CLAMP(c.b*255.0,0,255) );
+ crw[j*4+3]=Math::fast_ftoi( CLAMP(c.a*255.0,0,255) );
+ }
+
+ at=pos;
+ color_at=to;
+ }
+ }
+
+ Image gradient(color_ramp_len,1,0,Image::FORMAT_RGBA,cramp);
+ Ref<ImageTexture> it = memnew( ImageTexture );
+ it->create_from_image(gradient,Texture::FLAG_FILTER|Texture::FLAG_MIPMAPS);
+
+ String crampname= "cramp_"+itos(p_node->id);
+ set_default_texture_param(crampname,it);
+
+ code +="uniform texture "+crampname+";\n";
+ code +="vec4 "+crampname+"_r=tex("+crampname+",vec2("+p_inputs[0]+",0));\n";
+ code += OUTNAME(p_node->id,0)+"="+crampname+"_r.rgb;\n";
+ code += OUTNAME(p_node->id,1)+"="+crampname+"_r.a;\n";
+
+ }break;
+ case NODE_CURVE_MAP: {
+ DEF_SCALAR(0);
+ static const int curve_map_len=256;
+ bool mapped[256];
+ zeromem(mapped,sizeof(mapped));
+ DVector<uint8_t> cmap;
+ cmap.resize(curve_map_len);
+ {
+
+ DVector<Point2> points=p_node->param1;
+ int pc =points.size();
+ DVector<uint8_t>::Write cmw = cmap.write();
+ DVector<Point2>::Read pr = points.read();
+
+ Vector2 prev=Vector2(0,0);
+ Vector2 prev2=Vector2(0,0);
+
+ for(int i=-1;i<pc;i++) {
+
+ Vector2 next;
+ Vector2 next2;
+ if (i+1>=pc) {
+ next=Vector2(1,1);
+ } else {
+ next=Vector2(pr[i+1].x,pr[i+1].y);
+ }
+
+ if (i+2>=pc) {
+ next2=Vector2(1,1);
+ } else {
+ next2=Vector2(pr[i+2].x,pr[i+2].y);
+ }
+
+ /*if (i==-1 && prev.offset==next.offset) {
+ prev=next;
+ continue;
+ }*/
+
+ _plot_curve(prev2,prev,next,next2,cmw.ptr(),mapped);
+
+ prev2=prev;
+ prev=next;
+ }
+
+ uint8_t pp=0;
+ for(int i=0;i<curve_map_len;i++) {
+
+ if (!mapped[i]) {
+ cmw[i]=pp;
+ } else {
+ pp=cmw[i];
+ }
+ }
+ }
+
+
+
+ Image gradient(curve_map_len,1,0,Image::FORMAT_GRAYSCALE,cmap);
+ Ref<ImageTexture> it = memnew( ImageTexture );
+ it->create_from_image(gradient,Texture::FLAG_FILTER|Texture::FLAG_MIPMAPS);
+
+ String cmapname= "cmap_"+itos(p_node->id);
+ set_default_texture_param(cmapname,it);
+
+ code +="uniform texture "+cmapname+";\n";
+ code += OUTNAME(p_node->id,0)+"=tex("+cmapname+",vec2("+p_inputs[0]+",0)).r;\n";
+
+ }break;
+ case NODE_SCALAR_INPUT: {
+ String name = p_node->param1;
+ float dv=p_node->param2;
+ code +="uniform float "+name+"="+rtos(dv)+";\n";
+ code += OUTNAME(p_node->id,0)+"="+name+";\n";
+ }break;
+ case NODE_VEC_INPUT: {
+
+ String name = p_node->param1;
+ Vector3 dv=p_node->param2;
+ code +="uniform vec3 "+name+"=vec3("+rtos(dv.x)+","+rtos(dv.y)+","+rtos(dv.z)+");\n";
+ code += OUTNAME(p_node->id,0)+"="+name+";\n";
+ }break;
+ case NODE_RGB_INPUT: {
+
+ 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 += OUTNAME(p_node->id,0)+"="+name+".rgb;\n";
+
+ }break;
+ case NODE_XFORM_INPUT: {
+
+ String name = p_node->param1;
+ Transform dv= p_node->param2;
+
+ code +="uniform mat4 "+name+"=mat4(\n";
+ code+="\tvec4(vec3("+rtos(dv.basis.get_axis(0).x)+","+rtos(dv.basis.get_axis(0).y)+","+rtos(dv.basis.get_axis(0).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(dv.basis.get_axis(1).x)+","+rtos(dv.basis.get_axis(1).y)+","+rtos(dv.basis.get_axis(1).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(dv.basis.get_axis(2).x)+","+rtos(dv.basis.get_axis(2).y)+","+rtos(dv.basis.get_axis(2).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(dv.origin.x)+","+rtos(dv.origin.y)+","+rtos(dv.origin.z)+"),1)\n";
+ code+=");";
+
+ code += OUTNAME(p_node->id,0)+"="+name+";\n";
+
+ }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+";";
+ code +="vec4 "+rname+"=tex("+name+","+p_inputs[0]+".xy);\n";
+ code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
+ code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
+
+ }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);
+ code +="vec4 "+rname+"=texcube("+name+","+p_inputs[0]+".xy);\n";
+ code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
+ 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) {
+
+ String rname="rt_default_tex"+itos(p_node->id);
+ code +="vec4 "+rname+"=tex(TEXTURE,"+p_inputs[0]+".xy);\n";
+ code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
+ code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
+
+ } else {
+ //not supported
+ code += OUTNAME(p_node->id,0)+"=vec3(0,0,0);\n";
+ code += OUTNAME(p_node->id,1)+"=1.0;\n";
+
+ }
+ } break;
+ case NODE_OUTPUT: {
+
+
+ }break;
+ case NODE_COMMENT: {
+
+ }break;
+ case NODE_TYPE_MAX: {
+
+ }
+ }
+#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 57c6ea94f0..f867ae0388 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,104 +30,56 @@
#define SHADER_GRAPH_H
-#include "map.h"
-#if 0
+#include "map.h"
+#include "scene/resources/shader.h"
-class Shader : public Resource {
+class ShaderGraph : public Shader {
- OBJ_TYPE( Shader, Resource );
+ OBJ_TYPE( ShaderGraph, Shader );
RES_BASE_EXTENSION("sgp");
- RID shader;
- Map<int,Point2> positions;
- uint64_t version;
-
-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();
-
- Array _get_connections_helper() const;
public:
enum NodeType {
- NODE_IN, ///< param 0: name
- NODE_OUT, ///< param 0: name
- NODE_CONSTANT, ///< param 0: value
- NODE_PARAMETER, ///< param 0: name
- NODE_ADD,
- NODE_SUB,
- NODE_MUL,
- NODE_DIV,
- NODE_MOD,
- NODE_SIN,
- NODE_COS,
- NODE_TAN,
- NODE_ARCSIN,
- NODE_ARCCOS,
- NODE_ARCTAN,
- NODE_POW,
- NODE_LOG,
- NODE_MAX,
- NODE_MIN,
- NODE_COMPARE,
- NODE_TEXTURE, ///< param 0: texture
- NODE_TIME, ///< param 0: interval length
- NODE_NOISE,
- NODE_PASS,
- NODE_VEC_IN, ///< param 0: name
- NODE_VEC_OUT, ///< param 0: name
- NODE_VEC_CONSTANT, ///< param 0: value
- NODE_VEC_PARAMETER, ///< param 0: name
- NODE_VEC_ADD,
- NODE_VEC_SUB,
- NODE_VEC_MUL,
- NODE_VEC_DIV,
- NODE_VEC_MOD,
- NODE_VEC_CROSS,
- NODE_VEC_DOT,
- NODE_VEC_POW,
- NODE_VEC_NORMALIZE,
- NODE_VEC_INTERPOLATE,
- NODE_VEC_SCREEN_TO_UV,
- NODE_VEC_TRANSFORM3,
- NODE_VEC_TRANSFORM4,
- NODE_VEC_COMPARE,
- NODE_VEC_TEXTURE_2D,
- NODE_VEC_TEXTURE_CUBE,
- NODE_VEC_NOISE,
- NODE_VEC_0,
- NODE_VEC_1,
- NODE_VEC_2,
- NODE_VEC_BUILD,
- NODE_VEC_PASS,
- NODE_COLOR_CONSTANT,
- NODE_COLOR_PARAMETER,
- NODE_TEXTURE_PARAMETER,
- NODE_TEXTURE_2D_PARAMETER,
- NODE_TEXTURE_CUBE_PARAMETER,
- NODE_TRANSFORM_CONSTANT,
- NODE_TRANSFORM_PARAMETER,
- NODE_LABEL,
+ NODE_INPUT, // all inputs (shader type dependent)
+ NODE_SCALAR_CONST, //scalar constant
+ NODE_VEC_CONST, //vec3 constant
+ NODE_RGB_CONST, //rgb constant (shows a color picker instead)
+ NODE_XFORM_CONST, // 4x4 matrix constant
+ NODE_TIME, // time in seconds
+ NODE_SCREEN_TEX, // screen texture sampler (takes UV) (only usable in fragment shader)
+ NODE_SCALAR_OP, // scalar vs scalar op (mul, add, div, etc)
+ NODE_VEC_OP, // vec3 vs vec3 op (mul,ad,div,crossprod,etc)
+ NODE_VEC_SCALAR_OP, // vec3 vs scalar op (mul, add, div, etc)
+ NODE_RGB_OP, // vec3 vs vec3 rgb op (with scalar amount), like brighten, darken, burn, dodge, multiply, etc.
+ NODE_XFORM_MULT, // mat4 x mat4
+ NODE_XFORM_VEC_MULT, // mat4 x vec3 mult (with no-translation option)
+ NODE_XFORM_VEC_INV_MULT, // mat4 x vec3 inverse mult (with no-translation option)
+ NODE_SCALAR_FUNC, // scalar function (sin, cos, etc)
+ NODE_VEC_FUNC, // vector function (normalize, negate, reciprocal, rgb2hsv, hsv2rgb, etc, etc)
+ NODE_VEC_LEN, // vec3 length
+ NODE_DOT_PROD, // vec3 . vec3 (dot product -> scalar output)
+ NODE_VEC_TO_SCALAR, // 1 vec3 input, 3 scalar outputs
+ NODE_SCALAR_TO_VEC, // 3 scalar input, 1 vec3 output
+ NODE_XFORM_TO_VEC, // 3 vec input, 1 xform output
+ NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output
+ NODE_SCALAR_INTERP, // scalar interpolation (with optional curve)
+ 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_VEC_INPUT, // vec3 uniform (assignable in material)
+ NODE_RGB_INPUT, // color uniform (assignable in material)
+ NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
+ NODE_TEXTURE_INPUT, // texture input (assignable in material)
+ NODE_CUBEMAP_INPUT, // cubemap input (assignable in material)
+ NODE_DEFAULT_TEXTURE,
+ NODE_OUTPUT, // output (shader type dependent)
+ NODE_COMMENT, // comment
NODE_TYPE_MAX
};
- void node_add(NodeType p_type,int p_id);
- void node_remove(int p_id);
- void node_set_param( int p_id, const Variant& p_value);
- void node_set_pos(int p_id,const Point2& p_pos);
- Point2 node_get_pos(int p_id) const;
-
- void get_node_list(List<int> *p_node_list) const;
- NodeType node_get_type(int p_id) const;
- Variant node_get_param(int p_id) const;
-
- void connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
- void disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
struct Connection {
@@ -137,40 +89,356 @@ public:
int dst_slot;
};
- void get_connections(List<Connection> *p_connections) const;
+ enum SlotType {
- void clear();
+ SLOT_TYPE_SCALAR,
+ SLOT_TYPE_VEC,
+ SLOT_TYPE_XFORM,
+ SLOT_TYPE_TEXTURE,
+ SLOT_MAX
+ };
- virtual RID get_rid() const { return shader; }
+ enum ShaderType {
+ SHADER_TYPE_VERTEX,
+ SHADER_TYPE_FRAGMENT,
+ SHADER_TYPE_LIGHT,
+ SHADER_TYPE_MAX
+ };
- uint64_t get_version() const { return version; }
+ enum SlotDir {
+ SLOT_IN,
+ SLOT_OUT
+ };
- Shader();
- ~Shader();
-};
+ enum GraphError {
+ GRAPH_OK,
+ GRAPH_ERROR_CYCLIC,
+ GRAPH_ERROR_MISSING_CONNECTIONS
+ };
+
+private:
+
+ String _find_unique_name(const String& p_base);
+
+ enum {SLOT_DEFAULT_VALUE = 0x7FFFFFFF};
+ struct SourceSlot {
+
+ int id;
+ int slot;
+ bool operator==(const SourceSlot& p_slot) const {
+ return id==p_slot.id && slot==p_slot.slot;
+ }
+ };
+
+ struct Node {
+
+ Vector2 pos;
+ NodeType type;
+ Variant param1;
+ Variant param2;
+ Map<int, Variant> defaults;
+ int id;
+ mutable int order; // used for sorting
+ int sort_order;
+ Map<int,SourceSlot> connections;
+
+ };
+
+ struct ShaderData {
+ Map<int,Node> node_map;
+ GraphError error;
+ } shader[3];
+
+
+
+ struct InOutParamInfo {
+ Mode shader_mode;
+ ShaderType shader_type;
+ const char *name;
+ const char *variable;
+ const char *postfix;
+ SlotType slot_type;
+ SlotDir dir;
+ };
-enum ShaderType {
- SHADER_VERTEX,
- SHADER_FRAGMENT,
- SHADER_POST_PROCESS
+ static const InOutParamInfo inout_param_info[];
+
+ struct NodeSlotInfo {
+
+ enum { MAX_INS=3, MAX_OUTS=3 };
+ NodeType type;
+ const SlotType ins[MAX_INS];
+ const SlotType outs[MAX_OUTS];
+ };
+
+ static const NodeSlotInfo node_slot_info[];
+
+ bool _pending_update_shader;
+ void _update_shader();
+ void _request_update();
+
+ void _plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d,uint8_t* p_heights,bool *p_useds);
+ void _add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code);
+
+ Array _get_node_list(ShaderType p_type) const;
+ Array _get_connections(ShaderType p_type) const;
+
+ void _set_data(const Dictionary& p_data);
+ Dictionary _get_data() const;
+protected:
+
+ static void _bind_methods();
+
+public:
+
+
+ void node_add(ShaderType p_type, NodeType p_node_type, int p_id);
+ void node_remove(ShaderType p_which,int p_id);
+ void node_set_pos(ShaderType p_which,int p_id,const Point2& p_pos);
+ Point2 node_get_pos(ShaderType p_which,int p_id) const;
+
+ void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
+ NodeType node_get_type(ShaderType p_which,int p_id) const;
+
+ void scalar_const_node_set_value(ShaderType p_which,int p_id,float p_value);
+ float scalar_const_node_get_value(ShaderType p_which,int p_id) const;
+
+ void vec_const_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
+ Vector3 vec_const_node_get_value(ShaderType p_which,int p_id) const;
+
+ void rgb_const_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
+ Color rgb_const_node_get_value(ShaderType p_which,int p_id) const;
+
+ void xform_const_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
+ Transform xform_const_node_get_value(ShaderType p_which,int p_id) const;
+
+ void texture_node_set_filter_size(ShaderType p_which,int p_id,int p_size);
+ int texture_node_get_filter_size(ShaderType p_which,int p_id) const;
+
+ 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,
+ SCALAR_OP_MUL,
+ SCALAR_OP_DIV,
+ SCALAR_OP_MOD,
+ SCALAR_OP_POW,
+ SCALAR_OP_MAX,
+ SCALAR_OP_MIN,
+ SCALAR_OP_ATAN2,
+ SCALAR_MAX_OP
+ };
+
+ void scalar_op_node_set_op(ShaderType p_which,float p_id,ScalarOp p_op);
+ ScalarOp scalar_op_node_get_op(ShaderType p_which,float p_id) const;
+
+ enum VecOp {
+ VEC_OP_ADD,
+ VEC_OP_SUB,
+ VEC_OP_MUL,
+ VEC_OP_DIV,
+ VEC_OP_MOD,
+ VEC_OP_POW,
+ VEC_OP_MAX,
+ VEC_OP_MIN,
+ VEC_OP_CROSS,
+ VEC_MAX_OP
+ };
+
+ void vec_op_node_set_op(ShaderType p_which,float p_id,VecOp p_op);
+ VecOp vec_op_node_get_op(ShaderType p_which,float p_id) const;
+
+ enum VecScalarOp {
+ VEC_SCALAR_OP_MUL,
+ VEC_SCALAR_OP_DIV,
+ VEC_SCALAR_OP_POW,
+ VEC_SCALAR_MAX_OP
+ };
+
+ void vec_scalar_op_node_set_op(ShaderType p_which,float p_id,VecScalarOp p_op);
+ VecScalarOp vec_scalar_op_node_get_op(ShaderType p_which,float p_id) const;
+
+ enum RGBOp {
+ RGB_OP_SCREEN,
+ RGB_OP_DIFFERENCE,
+ RGB_OP_DARKEN,
+ RGB_OP_LIGHTEN,
+ RGB_OP_OVERLAY,
+ RGB_OP_DODGE,
+ RGB_OP_BURN,
+ RGB_OP_SOFT_LIGHT,
+ RGB_OP_HARD_LIGHT,
+ RGB_MAX_OP
+ };
+
+ void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op);
+ RGBOp rgb_op_node_get_op(ShaderType p_which,float p_id) const;
+
+ void xform_vec_mult_node_set_no_translation(ShaderType p_which,int p_id,bool p_no_translation);
+ bool xform_vec_mult_node_get_no_translation(ShaderType p_which,int p_id) const;
+
+ enum ScalarFunc {
+ SCALAR_FUNC_SIN,
+ SCALAR_FUNC_COS,
+ SCALAR_FUNC_TAN,
+ SCALAR_FUNC_ASIN,
+ SCALAR_FUNC_ACOS,
+ SCALAR_FUNC_ATAN,
+ SCALAR_FUNC_SINH,
+ SCALAR_FUNC_COSH,
+ SCALAR_FUNC_TANH,
+ SCALAR_FUNC_LOG,
+ SCALAR_FUNC_EXP,
+ SCALAR_FUNC_SQRT,
+ SCALAR_FUNC_ABS,
+ SCALAR_FUNC_SIGN,
+ SCALAR_FUNC_FLOOR,
+ SCALAR_FUNC_ROUND,
+ SCALAR_FUNC_CEIL,
+ SCALAR_FUNC_FRAC,
+ SCALAR_FUNC_SATURATE,
+ SCALAR_FUNC_NEGATE,
+ SCALAR_MAX_FUNC
+ };
+
+ void scalar_func_node_set_function(ShaderType p_which,int p_id,ScalarFunc p_func);
+ ScalarFunc scalar_func_node_get_function(ShaderType p_which,int p_id) const;
+
+ enum VecFunc {
+ VEC_FUNC_NORMALIZE,
+ VEC_FUNC_SATURATE,
+ VEC_FUNC_NEGATE,
+ VEC_FUNC_RECIPROCAL,
+ VEC_FUNC_RGB2HSV,
+ VEC_FUNC_HSV2RGB,
+ 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;
+
+ void color_ramp_node_set_ramp(ShaderType p_which,int p_id,const DVector<Color>& p_colors, const DVector<real_t>& p_offsets);
+ DVector<Color> color_ramp_node_get_colors(ShaderType p_which,int p_id) const;
+ DVector<real_t> color_ramp_node_get_offsets(ShaderType p_which,int p_id) const;
+
+ void curve_map_node_set_points(ShaderType p_which, int p_id, const DVector<Vector2>& p_points);
+ DVector<Vector2> curve_map_node_get_points(ShaderType p_which,int p_id) const;
+
+ void input_node_set_name(ShaderType p_which,int p_id,const String& p_name);
+ String input_node_get_name(ShaderType p_which,int p_id);
+
+ void scalar_input_node_set_value(ShaderType p_which,int p_id,float p_value);
+ float scalar_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void vec_input_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
+ Vector3 vec_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void rgb_input_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
+ Color rgb_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void xform_input_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
+ Transform xform_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void texture_input_node_set_value(ShaderType p_which,int p_id,const Ref<Texture>& p_texture);
+ Ref<Texture> texture_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void cubemap_input_node_set_value(ShaderType p_which,int p_id,const Ref<CubeMap>& p_cubemap);
+ Ref<CubeMap> cubemap_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void comment_node_set_text(ShaderType p_which,int p_id,const String& p_comment);
+ String comment_node_get_text(ShaderType p_which,int p_id) const;
+
+ Error connect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+ bool is_node_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const;
+ void disconnect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+
+ 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;
+ void node_set_state(ShaderType p_type, int p_id, const Variant& p_state);
+
+ 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);
+ static SlotType get_type_output_type(NodeType p_type,int p_idx);
+ static bool is_type_valid(Mode p_mode,ShaderType p_type);
+
+
+ struct SlotInfo {
+ String name;
+ SlotType type;
+ SlotDir dir;
+ };
+
+ static void get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots);
+
+ static int get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type);
+ static int get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type);
+ static SlotType get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx);
+ static SlotType get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx);
+
+
+ ShaderGraph(Mode p_mode);
+ ~ShaderGraph();
};
+
//helper functions
-static void shader_get_default_input_nodes(ShaderType p_type,List<PropertyInfo> *p_inputs);
-static void shader_get_default_output_nodes(ShaderType p_type,List<PropertyInfo> *p_outputs);
-static PropertyInfo shader_node_get_type_info(ShaderNodeType p_type);
-static int shader_get_input_count(ShaderNodeType p_type);
-static int shader_get_output_count(ShaderNodeType p_type);
-static String shader_get_input_name(ShaderNodeType p_type,int p_input);
-static String shader_get_output_name(ShaderNodeType p_type,int p_output);
-static bool shader_is_input_vector(ShaderNodeType p_type,int p_input);
-static bool shader_is_output_vector(ShaderNodeType p_type,int p_input);
-VARIANT_ENUM_CAST( Shader::NodeType );
+VARIANT_ENUM_CAST( ShaderGraph::NodeType );
+VARIANT_ENUM_CAST( ShaderGraph::ShaderType );
+VARIANT_ENUM_CAST( ShaderGraph::SlotType );
+VARIANT_ENUM_CAST( ShaderGraph::ScalarOp );
+VARIANT_ENUM_CAST( ShaderGraph::VecOp );
+VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp );
+VARIANT_ENUM_CAST( ShaderGraph::RGBOp );
+VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc );
+VARIANT_ENUM_CAST( ShaderGraph::VecFunc );
+VARIANT_ENUM_CAST( ShaderGraph::GraphError );
+
+
+class MaterialShaderGraph : public ShaderGraph {
+ OBJ_TYPE( MaterialShaderGraph, ShaderGraph );
+
+public:
+
+
+ MaterialShaderGraph() : ShaderGraph(MODE_MATERIAL) {
+
+ }
+};
+
+class CanvasItemShaderGraph : public ShaderGraph {
+
+ OBJ_TYPE( CanvasItemShaderGraph, ShaderGraph );
+
+public:
+
+
+ CanvasItemShaderGraph() : ShaderGraph(MODE_CANVAS_ITEM) {
+
+ }
+};
-#endif
#endif // SHADER_GRAPH_H
diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp
index 6ed877b904..143ef82d51 100644
--- a/scene/resources/shape.cpp
+++ b/scene/resources/shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 6cf2dc0aa3..1992ce51c3 100644
--- a/scene/resources/shape.h
+++ b/scene/resources/shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 ca891920da..31b28ee892 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -109,7 +109,7 @@ void Shape2D::_bind_methods() {
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_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);
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 5f254a1572..1737301d9d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 4cc97da369..97e9985754 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 a82ebe4cad..f32ad7fb7c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 8df70f8031..6dbf7c4a73 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/space_2d.h b/scene/resources/space_2d.h
index 5bdf453fee..eb3e13ee62 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/sphere_shape.cpp b/scene/resources/sphere_shape.cpp
index f9e5a82e20..a7e28eb727 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 4967d002cb..2543d94439 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 316b5e91eb..527fae5946 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -85,6 +85,12 @@ void StyleBox::_bind_methods() {
ObjectTypeDB::bind_method(_MD("draw"),&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 );
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/top", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_TOP);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/bottom", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_BOTTOM );
+
+
}
StyleBox::StyleBox() {
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 0a4a1074fd..337bb54026 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 2856101674..418df97f51 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -105,7 +105,7 @@ void SurfaceTool::add_vertex( const Vector3& p_vertex) {
vtx.weights=last_weights;
vtx.bones=last_bones;
vtx.tangent=last_tangent.normal;
- vtx.binormal=last_tangent.normal.cross(last_normal).normalized() * last_tangent.d;
+ vtx.binormal=last_normal.cross(last_tangent.normal).normalized() * last_tangent.d;
vertex_array.push_back(vtx);
first=false;
format|=Mesh::ARRAY_FORMAT_VERTEX;
@@ -299,7 +299,9 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) {
w[idx+0]=v.tangent.x;
w[idx+1]=v.tangent.y;
w[idx+2]=v.tangent.z;
- float d = v.binormal.dot(v.normal.cross(v.tangent));
+
+ //float d = v.tangent.dot(v.binormal,v.normal);
+ float d = v.binormal.dot( v.normal.cross(v.tangent));
w[idx+3]=d<0 ? -1 : 1;
}
@@ -565,6 +567,7 @@ void SurfaceTool::create_from(const Ref<Mesh>& p_existing, int p_surface) {
clear();
primitive=p_existing->surface_get_primitive_type(p_surface);
_create_list(p_existing,p_surface,&vertex_array,&index_array,format);
+ material=p_existing->surface_get_material(p_surface);
}
@@ -611,165 +614,96 @@ void SurfaceTool::append_from(const Ref<Mesh>& p_existing, int p_surface,const T
}
+//mikktspace callbacks
+int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext * pContext) {
-void SurfaceTool::generate_tangents() {
-
- ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV));
- ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL));
-
-
- if (index_array.size()) {
-
- Vector<List<Vertex>::Element*> vtx;
- vtx.resize(vertex_array.size());
- int idx=0;
- for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
- vtx[idx++]=E;
- E->get().binormal=Vector3();
- E->get().tangent=Vector3();
- }
-
- for (List<int>::Element *E=index_array.front();E;) {
-
- int i[3];
- i[0]=E->get();
- E=E->next();
- ERR_FAIL_COND(!E);
- i[1]=E->get();
- E=E->next();
- ERR_FAIL_COND(!E);
- i[2]=E->get();
- E=E->next();
- ERR_FAIL_COND(!E);
-
-
- Vector3 v1 = vtx[ i[0] ]->get().vertex;
- Vector3 v2 = vtx[ i[1] ]->get().vertex;
- Vector3 v3 = vtx[ i[2] ]->get().vertex;
-
- Vector2 w1 = vtx[ i[0] ]->get().uv;
- Vector2 w2 = vtx[ i[1] ]->get().uv;
- Vector2 w3 = vtx[ i[2] ]->get().uv;
-
-
- float x1 = v2.x - v1.x;
- float x2 = v3.x - v1.x;
- float y1 = v2.y - v1.y;
- float y2 = v3.y - v1.y;
- float z1 = v2.z - v1.z;
- float z2 = v3.z - v1.z;
-
- float s1 = w2.x - w1.x;
- float s2 = w3.x - w1.x;
- float t1 = w2.y - w1.y;
- float t2 = w3.y - w1.y;
-
- float r = (s1 * t2 - s2 * t1);
-
- Vector3 binormal,tangent;
-
- if (r==0) {
- binormal=Vector3(0,0,0);
- tangent=Vector3(0,0,0);
- } else {
- tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
- (t2 * z1 - t1 * z2) * r);
- binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
- (s1 * z2 - s2 * z1) * r);
- }
-
- tangent.normalize();
- binormal.normalize();
- Vector3 normal=Plane( v1, v2, v3 ).normal;
-
- Vector3 tangentp = tangent - normal * normal.dot( tangent );
- Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
-
- tangentp.normalize();
- binormalp.normalize();
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ return varr.size()/3;
+}
+int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace){
+ return 3; //always 3
+}
+void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert){
- for (int j=0;j<3;j++) {
- vtx[ i[j] ]->get().binormal+=binormalp;
- vtx[ i[j] ]->get().tangent+=tangentp;
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ Vector3 v = varr[iFace*3+iVert]->get().vertex;
+ fvPosOut[0]=v.x;
+ fvPosOut[1]=v.y;
+ fvPosOut[2]=v.z;
- }
- }
- for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
- E->get().binormal.normalize();
- E->get().tangent.normalize();
- }
+}
+void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert){
- } else {
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ Vector3 v = varr[iFace*3+iVert]->get().normal;
+ fvNormOut[0]=v.x;
+ fvNormOut[1]=v.y;
+ fvNormOut[2]=v.z;
- for (List<Vertex>::Element *E=vertex_array.front();E;) {
+}
+void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert){
- List< Vertex >::Element *v[3];
- v[0]=E;
- v[1]=v[0]->next();
- ERR_FAIL_COND(!v[1]);
- v[2]=v[1]->next();
- ERR_FAIL_COND(!v[2]);
- E=v[2]->next();
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ Vector2 v = varr[iFace*3+iVert]->get().uv;
+ fvTexcOut[0]=v.x;
+ fvTexcOut[1]=v.y;
+ //fvTexcOut[1]=1.0-v.y;
- Vector3 v1 = v[0]->get().vertex;
- Vector3 v2 = v[1]->get().vertex;
- Vector3 v3 = v[2]->get().vertex;
+}
+void SurfaceTool::mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert){
- Vector2 w1 = v[0]->get().uv;
- Vector2 w2 = v[1]->get().uv;
- Vector2 w3 = v[2]->get().uv;
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ Vertex &vtx = varr[iFace*3+iVert]->get();
+ vtx.tangent = Vector3(fvTangent[0],fvTangent[1],fvTangent[2]);
+ vtx.binormal = vtx.normal.cross(vtx.tangent) * fSign;
+}
- float x1 = v2.x - v1.x;
- float x2 = v3.x - v1.x;
- float y1 = v2.y - v1.y;
- float y2 = v3.y - v1.y;
- float z1 = v2.z - v1.z;
- float z2 = v3.z - v1.z;
- float s1 = w2.x - w1.x;
- float s2 = w3.x - w1.x;
- float t1 = w2.y - w1.y;
- float t2 = w3.y - w1.y;
+void SurfaceTool::generate_tangents() {
- float r = (s1 * t2 - s2 * t1);
+ ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV));
+ ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL));
- Vector3 binormal,tangent;
+ bool indexed = index_array.size()>0;
+ if (indexed)
+ deindex();
- if (r==0) {
- binormal=Vector3(0,0,0);
- tangent=Vector3(0,0,0);
- } else {
- tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
- (t2 * z1 - t1 * z2) * r);
- binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
- (s1 * z2 - s2 * z1) * r);
- }
- tangent.normalize();
- binormal.normalize();
- Vector3 normal=Plane( v1, v2, v3 ).normal;
+ SMikkTSpaceInterface mkif;
+ mkif.m_getNormal=mikktGetNormal;
+ mkif.m_getNumFaces=mikktGetNumFaces;
+ mkif.m_getNumVerticesOfFace=mikktGetNumVerticesOfFace;
+ mkif.m_getPosition=mikktGetPosition;
+ mkif.m_getTexCoord=mikktGetTexCoord;
+ mkif.m_setTSpaceBasic=mikktSetTSpaceBasic;
+ mkif.m_setTSpace=NULL;
- Vector3 tangentp = tangent - normal * normal.dot( tangent );
- Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
+ SMikkTSpaceContext msc;
+ msc.m_pInterface=&mkif;
- tangentp.normalize();
- binormalp.normalize();
+ Vector<List<Vertex>::Element*> vtx;
+ vtx.resize(vertex_array.size());
+ int idx=0;
+ for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
+ vtx[idx++]=E;
+ E->get().binormal=Vector3();
+ E->get().tangent=Vector3();
+ }
+ msc.m_pUserData=&vtx;
+ bool res = genTangSpaceDefault(&msc);
- for (int j=0;j<3;j++) {
- v[j]->get().binormal=binormalp;
- v[j]->get().tangent=tangentp;
+ ERR_FAIL_COND(!res);
+ format|=Mesh::ARRAY_FORMAT_TANGENT;
- }
- }
- }
+ if (indexed)
+ index();
- format|=Mesh::ARRAY_FORMAT_TANGENT;
}
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index fe82d3a4ce..ed91b4df61 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#define SURFACE_TOOL_H
#include "scene/resources/mesh.h"
-
+#include "mikktspace.h"
class SurfaceTool : public Reference {
@@ -82,6 +82,14 @@ private:
void _create_list(const Ref<Mesh>& p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index,int &lformat);
+
+ //mikktspace callbacks
+ static int mikktGetNumFaces(const SMikkTSpaceContext * pContext);
+ static int mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace);
+ static void mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert);
+ static void mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert);
+ static void mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert);
+ static void mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
protected:
static void _bind_methods();
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 5b31ba1f1b..5df3d64d1a 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,19 +38,19 @@ Size2 Texture::get_size() const {
}
-void Texture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const {
+void Texture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, get_size()),get_rid(),false,p_modulate);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, get_size()),get_rid(),false,p_modulate,p_transpose);
}
-void Texture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const {
+void Texture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,get_rid(),p_tile,p_modulate);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,get_rid(),p_tile,p_modulate,p_transpose);
}
-void Texture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const{
+void Texture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,get_rid(),p_src_rect,p_modulate);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,get_rid(),p_src_rect,p_modulate,p_transpose);
}
bool Texture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const {
@@ -70,15 +70,18 @@ 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)));
- ObjectTypeDB::bind_method(_MD("draw_rect","canvas_item","rect","tile","modulate"),&Texture::draw_rect,DEFVAL(Color(1,1,1)));
- ObjectTypeDB::bind_method(_MD("draw_rect_region","canvas_item","rect","src_rect","modulate"),&Texture::draw_rect_region,DEFVAL(Color(1,1,1)));
+ 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));
BIND_CONSTANT( FLAG_MIPMAPS );
BIND_CONSTANT( FLAG_REPEAT );
BIND_CONSTANT( FLAG_FILTER );
BIND_CONSTANT( FLAG_VIDEO_SURFACE );
BIND_CONSTANT( FLAGS_DEFAULT );
+ BIND_CONSTANT( FLAG_ANISOTROPIC_FILTER );
+ BIND_CONSTANT( FLAG_CONVERT_TO_LINEAR );
+ BIND_CONSTANT( FLAG_MIRRORED_REPEAT );
}
@@ -179,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") );
+ 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"));
@@ -319,34 +322,50 @@ void ImageTexture::premultiply_alpha() {
}
}
+void ImageTexture::normal_to_xy() {
+
+ Image img = get_data();
+ img.normalmap_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 );
}
-void ImageTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const {
+void ImageTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
if ((w|h)==0)
return;
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate,p_transpose);
}
-void ImageTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const {
+void ImageTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
if ((w|h)==0)
return;
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate,p_transpose);
}
-void ImageTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const{
+void ImageTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{
if ((w|h)==0)
return;
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate,p_transpose);
}
-
void ImageTexture::set_size_override(const Size2& p_size) {
Size2 s=p_size;
@@ -357,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;
@@ -404,9 +433,14 @@ void ImageTexture::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_lossy_storage_quality"),&ImageTexture::get_lossy_storage_quality);
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);
@@ -544,7 +578,7 @@ void AtlasTexture::_bind_methods() {
-void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const {
+void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
Rect2 rc=region;
@@ -559,10 +593,10 @@ void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_m
rc.size.height=atlas->get_height();
}
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,Rect2(p_pos+margin.pos,rc.size),atlas->get_rid(),rc,p_modulate);
+ VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,Rect2(p_pos+margin.pos,rc.size),atlas->get_rid(),rc,p_modulate,p_transpose);
}
-void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const {
+void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
Rect2 rc=region;
@@ -580,10 +614,10 @@ void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,
Vector2 scale = p_rect.size / (region.size+margin.size);
Rect2 dr( p_rect.pos+margin.pos*scale,rc.size*scale );
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),rc,p_modulate);
+ VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),rc,p_modulate,p_transpose);
}
-void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const {
+void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const {
//this might not necesarily work well if using a rect, needs to be fixed properly
Rect2 rc=region;
@@ -613,7 +647,7 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const
}
Rect2 dr( p_rect.pos+ofs*scale,src_c.size*scale );
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),src_c,p_modulate);
+ VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),src_c,p_modulate,p_transpose);
}
bool AtlasTexture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const {
@@ -799,15 +833,16 @@ void LargeTexture::_bind_methods() {
-void LargeTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const {
+void LargeTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
for(int i=0;i<pieces.size();i++) {
- pieces[i].texture->draw(p_canvas_item,pieces[i].offset+p_pos,p_modulate);
+ // TODO
+ pieces[i].texture->draw(p_canvas_item,pieces[i].offset+p_pos,p_modulate,p_transpose);
}
}
-void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const {
+void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
//tiling not supported for this
if (size.x==0 || size.y==0)
@@ -817,11 +852,11 @@ void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,
for(int i=0;i<pieces.size();i++) {
- pieces[i].texture->draw_rect(p_canvas_item,Rect2(pieces[i].offset*scale+p_rect.pos,pieces[i].texture->get_size()*scale),false,p_modulate);
+ // TODO
+ pieces[i].texture->draw_rect(p_canvas_item,Rect2(pieces[i].offset*scale+p_rect.pos,pieces[i].texture->get_size()*scale),false,p_modulate,p_transpose);
}
-
}
-void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const {
+void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const {
//tiling not supported for this
@@ -832,6 +867,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const
for(int i=0;i<pieces.size();i++) {
+ // TODO
Rect2 rect( pieces[i].offset, pieces[i].texture->get_size());
if (!p_src_rect.intersects(rect))
continue;
@@ -840,7 +876,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const
target.size*=scale;
target.pos=p_rect.pos+(p_src_rect.pos+rect.pos)*scale;
local.pos-=rect.pos;
- pieces[i].texture->draw_rect_region(p_canvas_item,target,local,p_modulate);
+ pieces[i].texture->draw_rect_region(p_canvas_item,target,local,p_modulate,p_transpose);
}
}
@@ -931,23 +967,33 @@ 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")
+ if (p_name=="side/left") {
set_side(SIDE_LEFT,p_value);
- if (p_name=="side/right")
+ } else if (p_name=="side/right") {
set_side(SIDE_RIGHT,p_value);
- if (p_name=="side/bottom")
+ } else if (p_name=="side/bottom") {
set_side(SIDE_BOTTOM,p_value);
- if (p_name=="side/top")
+ } else if (p_name=="side/top") {
set_side(SIDE_TOP,p_value);
- if (p_name=="side/front")
+ } else if (p_name=="side/front") {
set_side(SIDE_FRONT,p_value);
- if (p_name=="side/back")
+ } else if (p_name=="side/back") {
set_side(SIDE_BACK,p_value);
- else if (p_name=="flags")
+ } else if (p_name=="flags") {
set_flags(p_value);
- else if (p_name=="storage") {
+ } else if (p_name=="storage") {
storage=Storage(p_value.operator int());
} else if (p_name=="lossy_quality") {
lossy_storage_quality=p_value;
@@ -960,25 +1006,25 @@ bool CubeMap::_set(const StringName& p_name, const Variant& p_value) {
bool CubeMap::_get(const StringName& p_name,Variant &r_ret) const {
- if (p_name=="side/left")
+ if (p_name=="side/left") {
r_ret=get_side(SIDE_LEFT);
- if (p_name=="side/right")
+ } else if (p_name=="side/right") {
r_ret=get_side(SIDE_RIGHT);
- if (p_name=="side/bottom")
+ } else if (p_name=="side/bottom") {
r_ret=get_side(SIDE_BOTTOM);
- if (p_name=="side/top")
+ } else if (p_name=="side/top") {
r_ret=get_side(SIDE_TOP);
- if (p_name=="side/front")
+ } else if (p_name=="side/front") {
r_ret=get_side(SIDE_FRONT);
- if (p_name=="side/back")
+ } else if (p_name=="side/back") {
r_ret=get_side(SIDE_BACK);
- else if (p_name=="flags")
+ } else if (p_name=="flags") {
r_ret= flags;
- else if (p_name=="storage")
+ } else if (p_name=="storage") {
r_ret= storage;
- else if (p_name=="lossy_quality")
+ } else if (p_name=="lossy_quality") {
r_ret= lossy_storage_quality;
- else
+ } else
return false;
return true;
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 86ff246498..3be13bf815 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -52,8 +52,11 @@ public:
FLAG_MIPMAPS=VisualServer::TEXTURE_FLAG_MIPMAPS,
FLAG_REPEAT=VisualServer::TEXTURE_FLAG_REPEAT,
FLAG_FILTER=VisualServer::TEXTURE_FLAG_FILTER,
+ FLAG_ANISOTROPIC_FILTER=VisualServer::TEXTURE_FLAG_ANISOTROPIC_FILTER,
+ 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
};
@@ -67,9 +70,9 @@ public:
virtual void set_flags(uint32_t p_flags)=0;
virtual uint32_t get_flags() const=0;
- virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const;
- virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const;
- virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const;
+ virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
virtual bool get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const;
@@ -133,10 +136,9 @@ public:
virtual RID get_rid() const;
bool has_alpha() const;
- virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const;
- virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const;
- virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const;
-
+ virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
void set_storage(Storage p_storage);
Storage get_storage() const;
@@ -145,10 +147,14 @@ 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();
@@ -189,9 +195,9 @@ public:
void set_margin(const Rect2& p_margin);
Rect2 get_margin() const ;
- virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const;
- virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const;
- virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const;
+ virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
virtual bool get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const;
@@ -239,9 +245,9 @@ public:
Vector2 get_piece_offset(int p_idx) const;
Ref<Texture> get_piece_texture(int p_idx) const;
- virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const;
- virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const;
- virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const;
+ virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
LargeTexture();
@@ -316,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 f6e0293dd9..651e234b49 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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") {
@@ -105,6 +105,9 @@ bool Theme::_get(const StringName& p_name,Variant &r_ret) const {
void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
+
+ List<PropertyInfo> list;
+
const StringName *key=NULL;
while((key=icon_map.next(key))) {
@@ -113,7 +116,7 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
while((key2=icon_map[*key].next(key2))) {
- p_list->push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/icons/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "Texture" ) );
+ list.push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/icons/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "Texture" ) );
}
}
@@ -125,7 +128,7 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
while((key2=style_map[*key].next(key2))) {
- p_list->push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/styles/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox" ) );
+ list.push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/styles/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox" ) );
}
}
@@ -138,7 +141,7 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
while((key2=font_map[*key].next(key2))) {
- p_list->push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/fonts/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "Font" ) );
+ list.push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/fonts/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "Font" ) );
}
}
@@ -150,7 +153,7 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
while((key2=color_map[*key].next(key2))) {
- p_list->push_back( PropertyInfo( Variant::COLOR, String()+*key+"/colors/"+*key2 ) );
+ list.push_back( PropertyInfo( Variant::COLOR, String()+*key+"/colors/"+*key2 ) );
}
}
@@ -162,9 +165,14 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
while((key2=constant_map[*key].next(key2))) {
- p_list->push_back( PropertyInfo( Variant::INT, String()+*key+"/constants/"+*key2 ) );
+ list.push_back( PropertyInfo( Variant::INT, String()+*key+"/constants/"+*key2 ) );
}
}
+
+ list.sort();
+ for(List<PropertyInfo>::Element *E=list.front();E;E=E->next()) {
+ p_list->push_back(E->get());
+ }
}
@@ -593,7 +601,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);
@@ -603,6 +613,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;
@@ -995,6 +1007,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 b2df917511..cfa0762595 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -124,7 +124,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 208ba5bb66..28e179b34c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,6 +46,8 @@ bool TileSet::_set(const StringName& p_name, const Variant& p_value) {
tile_set_texture(id,p_value);
else if (what=="tex_offset")
tile_set_texture_offset(id,p_value);
+ else if (what=="material")
+ tile_set_material(id,p_value);
else if (what=="shape_offset")
tile_set_shape_offset(id,p_value);
else if (what=="region")
@@ -54,6 +56,14 @@ bool TileSet::_set(const StringName& p_name, const Variant& p_value) {
tile_set_shape(id,p_value);
else if (what=="shapes")
_tile_set_shapes(id,p_value);
+ else if (what=="occluder")
+ tile_set_light_occluder(id,p_value);
+ else if (what=="occluder_offset")
+ tile_set_occluder_offset(id,p_value);
+ else if (what=="navigation")
+ tile_set_navigation_polygon(id,p_value);
+ else if (what=="navigation_offset")
+ tile_set_navigation_polygon_offset(id,p_value);
else
return false;
@@ -79,6 +89,8 @@ bool TileSet::_get(const StringName& p_name,Variant &r_ret) const{
r_ret=tile_get_texture(id);
else if (what=="tex_offset")
r_ret=tile_get_texture_offset(id);
+ else if (what=="material")
+ r_ret=tile_get_material(id);
else if (what=="shape_offset")
r_ret=tile_get_shape_offset(id);
else if (what=="region")
@@ -87,6 +99,14 @@ bool TileSet::_get(const StringName& p_name,Variant &r_ret) const{
r_ret=tile_get_shape(id);
else if (what=="shapes")
r_ret=_tile_get_shapes(id);
+ else if (what=="occluder")
+ r_ret=tile_get_light_occluder(id);
+ else if (what=="occluder_offset")
+ r_ret=tile_get_occluder_offset(id);
+ else if (what=="navigation")
+ r_ret=tile_get_navigation_polygon(id);
+ else if (what=="navigation_offset")
+ r_ret=tile_get_navigation_polygon_offset(id);
else
return false;
@@ -103,8 +123,13 @@ void TileSet::_get_property_list( List<PropertyInfo> *p_list) const{
p_list->push_back(PropertyInfo(Variant::STRING,pre+"name"));
p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"));
p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"tex_offset"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"shape_offset"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"material",PROPERTY_HINT_RESOURCE_TYPE,"CanvasItemMaterial"));
p_list->push_back(PropertyInfo(Variant::RECT2,pre+"region"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"occluder_offset"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"occluder",PROPERTY_HINT_RESOURCE_TYPE,"OccluderPolygon2D"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"navigation_offset"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"navigation",PROPERTY_HINT_RESOURCE_TYPE,"NavigationPolygon"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"shape_offset"));
p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D",PROPERTY_USAGE_EDITOR));
p_list->push_back(PropertyInfo(Variant::ARRAY,pre+"shapes",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
}
@@ -134,6 +159,22 @@ Ref<Texture> TileSet::tile_get_texture(int p_id) const {
}
+
+void TileSet::tile_set_material(int p_id,const Ref<CanvasItemMaterial> &p_material) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ tile_map[p_id].material=p_material;
+ emit_changed();
+
+}
+
+Ref<CanvasItemMaterial> TileSet::tile_get_material(int p_id) const{
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id),Ref<CanvasItemMaterial>());
+ return tile_map[p_id].material;
+}
+
+
void TileSet::tile_set_texture_offset(int p_id,const Vector2 &p_offset) {
ERR_FAIL_COND(!tile_map.has(p_id));
@@ -210,6 +251,58 @@ Ref<Shape2D> TileSet::tile_get_shape(int p_id) const {
}
+void TileSet::tile_set_light_occluder(int p_id,const Ref<OccluderPolygon2D> &p_light_occluder) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ tile_map[p_id].occluder=p_light_occluder;
+
+}
+
+Ref<OccluderPolygon2D> TileSet::tile_get_light_occluder(int p_id) const{
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id),Ref<OccluderPolygon2D>());
+ return tile_map[p_id].occluder;
+
+}
+
+void TileSet::tile_set_navigation_polygon_offset(int p_id,const Vector2& p_offset) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ tile_map[p_id].navigation_polygon_offset=p_offset;
+
+}
+
+Vector2 TileSet::tile_get_navigation_polygon_offset(int p_id) const{
+ ERR_FAIL_COND_V(!tile_map.has(p_id),Vector2());
+ return tile_map[p_id].navigation_polygon_offset;
+}
+
+void TileSet::tile_set_navigation_polygon(int p_id,const Ref<NavigationPolygon> &p_navigation_polygon) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ tile_map[p_id].navigation_polygon=p_navigation_polygon;
+
+}
+
+Ref<NavigationPolygon> TileSet::tile_get_navigation_polygon(int p_id) const {
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id),Ref<NavigationPolygon>());
+ return tile_map[p_id].navigation_polygon;
+
+}
+
+void TileSet::tile_set_occluder_offset(int p_id,const Vector2& p_offset) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ tile_map[p_id].occluder_offset=p_offset;
+
+}
+
+Vector2 TileSet::tile_get_occluder_offset(int p_id) const{
+ ERR_FAIL_COND_V(!tile_map.has(p_id),Vector2());
+ return tile_map[p_id].occluder_offset;
+}
+
void TileSet::tile_set_shapes(int p_id,const Vector<Ref<Shape2D> > &p_shapes) {
ERR_FAIL_COND(!tile_map.has(p_id));
@@ -319,6 +412,8 @@ void TileSet::_bind_methods() {
ObjectTypeDB::bind_method(_MD("tile_get_name","id"),&TileSet::tile_get_name);
ObjectTypeDB::bind_method(_MD("tile_set_texture","id","texture:Texture"),&TileSet::tile_set_texture);
ObjectTypeDB::bind_method(_MD("tile_get_texture:Texture","id"),&TileSet::tile_get_texture);
+ ObjectTypeDB::bind_method(_MD("tile_set_material","id","material:CanvasItemMaterial"),&TileSet::tile_set_material);
+ ObjectTypeDB::bind_method(_MD("tile_get_material:CanvasItemMaterial","id"),&TileSet::tile_get_material);
ObjectTypeDB::bind_method(_MD("tile_set_texture_offset","id","texture_offset"),&TileSet::tile_set_texture_offset);
ObjectTypeDB::bind_method(_MD("tile_get_texture_offset","id"),&TileSet::tile_get_texture_offset);
ObjectTypeDB::bind_method(_MD("tile_set_shape_offset","id","shape_offset"),&TileSet::tile_set_shape_offset);
@@ -329,6 +424,15 @@ void TileSet::_bind_methods() {
ObjectTypeDB::bind_method(_MD("tile_get_shape:Shape2D","id"),&TileSet::tile_get_shape);
ObjectTypeDB::bind_method(_MD("tile_set_shapes","id","shapes"),&TileSet::_tile_set_shapes);
ObjectTypeDB::bind_method(_MD("tile_get_shapes","id"),&TileSet::_tile_get_shapes);
+ ObjectTypeDB::bind_method(_MD("tile_set_navigation_polygon","id","navigation_polygon:NavigationPolygon"),&TileSet::tile_set_navigation_polygon);
+ ObjectTypeDB::bind_method(_MD("tile_get_navigation_polygon:NavigationPolygon","id"),&TileSet::tile_get_navigation_polygon);
+ ObjectTypeDB::bind_method(_MD("tile_set_navigation_polygon_offset","id","navigation_polygon_offset"),&TileSet::tile_set_navigation_polygon_offset);
+ ObjectTypeDB::bind_method(_MD("tile_get_navigation_polygon_offset","id"),&TileSet::tile_get_navigation_polygon_offset);
+ ObjectTypeDB::bind_method(_MD("tile_set_light_occluder","id","light_occluder:OccluderPolygon2D"),&TileSet::tile_set_light_occluder);
+ ObjectTypeDB::bind_method(_MD("tile_get_light_occluder:OccluderPolygon2D","id"),&TileSet::tile_get_light_occluder);
+ ObjectTypeDB::bind_method(_MD("tile_set_occluder_offset","id","occluder_offset"),&TileSet::tile_set_occluder_offset);
+ ObjectTypeDB::bind_method(_MD("tile_get_occluder_offset","id"),&TileSet::tile_get_occluder_offset);
+
ObjectTypeDB::bind_method(_MD("remove_tile","id"),&TileSet::remove_tile);
ObjectTypeDB::bind_method(_MD("clear"),&TileSet::clear);
ObjectTypeDB::bind_method(_MD("get_last_unused_tile_id"),&TileSet::get_last_unused_tile_id);
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index ddbb1b59a6..96048bf06b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,6 +32,8 @@
#include "resource.h"
#include "scene/resources/shape_2d.h"
#include "scene/resources/texture.h"
+#include "scene/2d/light_occluder_2d.h"
+#include "scene/2d/navigation_polygon.h"
class TileSet : public Resource {
@@ -45,6 +47,11 @@ class TileSet : public Resource {
Vector2 shape_offset;
Rect2i region;
Vector<Ref<Shape2D> > shapes;
+ Vector2 occluder_offset;
+ Ref<OccluderPolygon2D> occluder;
+ Vector2 navigation_polygon_offset;
+ Ref<NavigationPolygon> navigation_polygon;
+ Ref<CanvasItemMaterial> material;
};
Map<int,Data> tile_map;
@@ -84,6 +91,21 @@ public:
void tile_set_shape(int p_id,const Ref<Shape2D> &p_shape);
Ref<Shape2D> tile_get_shape(int p_id) const;
+ void tile_set_material(int p_id,const Ref<CanvasItemMaterial> &p_material);
+ Ref<CanvasItemMaterial> tile_get_material(int p_id) const;
+
+ void tile_set_occluder_offset(int p_id,const Vector2& p_offset);
+ Vector2 tile_get_occluder_offset(int p_id) const;
+
+ void tile_set_light_occluder(int p_id,const Ref<OccluderPolygon2D> &p_light_occluder);
+ Ref<OccluderPolygon2D> tile_get_light_occluder(int p_id) const;
+
+ void tile_set_navigation_polygon_offset(int p_id,const Vector2& p_offset);
+ Vector2 tile_get_navigation_polygon_offset(int p_id) const;
+
+ void tile_set_navigation_polygon(int p_id,const Ref<NavigationPolygon> &p_navigation_polygon);
+ Ref<NavigationPolygon> tile_get_navigation_polygon(int p_id) const;
+
void tile_set_shapes(int p_id,const Vector<Ref<Shape2D> > &p_shapes);
Vector<Ref<Shape2D> > tile_get_shapes(int p_id) const;
diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp
index fffe1ad7fa..c957fd4c67 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,15 +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);
};
-VideoStream::VideoStream() {
+VideoStreamPlayback::VideoStreamPlayback() {
};
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index 32bc8670f0..a23ef0c64f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,24 +30,64 @@
#define VIDEO_STREAM_H
#include "audio_stream_resampled.h"
+#include "scene/resources/texture.h"
+class VideoStreamPlayback : public Resource {
-class VideoStream : public AudioStreamResampled {
-
- OBJ_TYPE(VideoStream,AudioStreamResampled);
+ OBJ_TYPE(VideoStreamPlayback,Resource);
protected:
static void _bind_methods();
public:
- virtual int get_pending_frame_count() const=0;
- virtual Image pop_frame()=0;
- virtual Image peek_frame() const=0;
+ typedef int (*AudioMixCallback)(void* p_udata,const int16_t *p_data,int p_frames);
+
+ virtual void stop()=0;
+ virtual void play()=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 float get_pos() const=0;
+ virtual void seek_pos(float p_time)=0;
+
+ virtual void set_audio_track(int p_idx) =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;
+
+ 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();
+ VideoStream() {}
};
+
#endif
diff --git a/scene/resources/volume.cpp b/scene/resources/volume.cpp
index 213d4eba3a..a668a39c4f 100644
--- a/scene/resources/volume.cpp
+++ b/scene/resources/volume.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/volume.h b/scene/resources/volume.h
index 1db6030bfa..f929792b74 100644
--- a/scene/resources/volume.h
+++ b/scene/resources/volume.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/scene/resources/world.cpp b/scene/resources/world.cpp
index 880a3a32e3..fb3469102c 100644
--- a/scene/resources/world.cpp
+++ b/scene/resources/world.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -307,6 +307,11 @@ Ref<Environment> World::get_environment() const {
}
+PhysicsDirectSpaceState *World::get_direct_space_state() {
+
+ return PhysicsServer::get_singleton()->space_get_direct_state(space);
+}
+
void World::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_space"),&World::get_space);
@@ -314,6 +319,7 @@ void World::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_sound_space"),&World::get_sound_space);
ObjectTypeDB::bind_method(_MD("set_environment","env:Environment"),&World::set_environment);
ObjectTypeDB::bind_method(_MD("get_environment:Environment"),&World::get_environment);
+ ObjectTypeDB::bind_method(_MD("get_direct_space_state:PhysicsDirectSpaceState"),&World::get_direct_space_state);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"environment",PROPERTY_HINT_RESOURCE_TYPE,"Environment"),_SCS("set_environment"),_SCS("get_environment"));
}
diff --git a/scene/resources/world.h b/scene/resources/world.h
index 60b3b99ab0..165122124d 100644
--- a/scene/resources/world.h
+++ b/scene/resources/world.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -75,6 +75,8 @@ public:
void set_environment(const Ref<Environment>& p_environment);
Ref<Environment> get_environment() const;
+ PhysicsDirectSpaceState *get_direct_space_state();
+
World();
~World();
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index aee7ddde00..3b1f1d2346 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -352,8 +352,17 @@ void World2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_canvas"),&World2D::get_canvas);
ObjectTypeDB::bind_method(_MD("get_space"),&World2D::get_space);
ObjectTypeDB::bind_method(_MD("get_sound_space"),&World2D::get_sound_space);
+
+ ObjectTypeDB::bind_method(_MD("get_direct_space_state:Physics2DDirectSpaceState"),&World2D::get_direct_space_state);
+
+}
+
+Physics2DDirectSpaceState *World2D::get_direct_space_state() {
+
+ return Physics2DServer::get_singleton()->space_get_direct_state(space);
}
+
World2D::World2D() {
canvas = VisualServer::get_singleton()->canvas_create();
@@ -364,12 +373,12 @@ World2D::World2D() {
Physics2DServer::get_singleton()->space_set_active(space,true);
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_DENSITY,GLOBAL_DEF("physics_2d/default_density",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_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);
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD,2);
- Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,20);
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,0.2);
indexer = memnew( SpatialIndexer2D );
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index 3feb23495d..a3a79dee09 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#define WORLD_2D_H
#include "resource.h"
-
+#include "servers/physics_2d_server.h"
class SpatialIndexer2D;
class VisibilityNotifier2D;
@@ -68,6 +68,8 @@ public:
RID get_space();
RID get_sound_space();
+ Physics2DDirectSpaceState *get_direct_space_state();
+
World2D();
~World2D();
};
diff --git a/scene/scene_binds.cpp b/scene/scene_binds.cpp
deleted file mode 100644
index 5c6a02611f..0000000000
--- a/scene/scene_binds.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*************************************************************************/
-/* scene_binds.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "scene_binds.h"
-
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-void SceneIO::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("load:Node","path"),&SceneIO::load);
- ObjectTypeDB::bind_method(_MD("save","path","scene:Node","flags","optimizer:OptimizedSaver","scene"),&SceneIO::save,DEFVAL(0),DEFVAL(Ref<OptimizedSaver>()));
- ObjectTypeDB::bind_method(_MD("load_interactive:SceneInteractiveLoader","path"),&SceneIO::load_interactive);
-}
-
-Node* SceneIO::load(const String& p_scene) {
-
- return SceneLoader::load(p_scene);
-}
-
-Error SceneIO::save(const String& p_path, Node *p_scene,int p_flags,const Ref<OptimizedSaver> &p_optimizer) {
-
- return SceneSaver::save(p_path,p_scene,p_flags,p_optimizer);
-}
-
-Ref<SceneInteractiveLoader> SceneIO::load_interactive(const String& p_scene) {
-
- return SceneLoader::load_interactive(p_scene);
-}
-
-#endif
diff --git a/scene/scene_binds.h b/scene/scene_binds.h
deleted file mode 100644
index 29e4b9ab60..0000000000
--- a/scene/scene_binds.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*************************************************************************/
-/* scene_binds.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef SCENE_BINDS_H
-#define SCENE_BINDS_H
-
-#include "scene/io/scene_loader.h"
-#include "scene/io/scene_saver.h"
-
-#ifdef OLD_SCENE_FORMAT_ENABLED
-
-class SceneIO : public Object {
-
- OBJ_TYPE( SceneIO, Object );
-protected:
-
- static void _bind_methods();
-public:
-
- enum SaveFlags {
-
- SAVE_FLAG_RELATIVE_PATHS=SceneSaver::FLAG_RELATIVE_PATHS,
- SAVE_FLAG_BUNDLE_RESOURCES=SceneSaver::FLAG_BUNDLE_RESOURCES,
- SAVE_FLAG_BUNDLE_INSTANCED_SCENES=SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES,
- SAVE_FLAG_OMIT_EDITOR_PROPERTIES=SceneSaver::FLAG_OMIT_EDITOR_PROPERTIES,
- SAVE_FLAG_SAVE_BIG_ENDIAN=SceneSaver::FLAG_SAVE_BIG_ENDIAN
- };
-
- Node* load(const String& p_scene);
- Error save(const String& p_path, Node *p_scene,int p_flags=0,const Ref<OptimizedSaver> &p_optimizer=Ref<OptimizedSaver>());
- Ref<SceneInteractiveLoader> load_interactive(const String& p_scene);
-
- SceneIO() {}
-};
-
-#endif
-#endif // SCENE_BINDS_H
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 0576d5a5b1..9509878dc9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -41,8 +41,10 @@ SceneStringNames::SceneStringNames() {
visibility_changed=StaticCString::create("visibility_changed");
input_event=StaticCString::create("input_event");
shader_shader=StaticCString::create("shader/shader");
- enter_scene=StaticCString::create("enter_scene");
- exit_scene=StaticCString::create("exit_scene");
+ shader_unshaded=StaticCString::create("shader/unshaded");
+ shading_mode=StaticCString::create("shader/shading_mode");
+ enter_tree=StaticCString::create("enter_tree");
+ exit_tree=StaticCString::create("exit_tree");
item_rect_changed=StaticCString::create("item_rect_changed");
size_flags_changed=StaticCString::create("size_flags_changed");
minimum_size_changed=StaticCString::create("minimum_size_changed");
@@ -63,10 +65,16 @@ SceneStringNames::SceneStringNames() {
body_exit_shape = StaticCString::create("body_exit_shape");
body_exit = StaticCString::create("body_exit");
+ 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");
update=StaticCString::create("update");
+ updated=StaticCString::create("updated");
_get_gizmo_geometry=StaticCString::create("_get_gizmo_geometry");
_can_gizmo_scale=StaticCString::create("_can_gizmo_scale");
@@ -74,8 +82,8 @@ SceneStringNames::SceneStringNames() {
_fixed_process=StaticCString::create("_fixed_process");
_process=StaticCString::create("_process");
- _enter_scene=StaticCString::create("_enter_scene");
- _exit_scene=StaticCString::create("_exit_scene");
+ _enter_tree=StaticCString::create("_enter_tree");
+ _exit_tree=StaticCString::create("_exit_tree");
_enter_world=StaticCString::create("_enter_world");
_exit_world=StaticCString::create("_exit_world");
_ready=StaticCString::create("_ready");
@@ -98,8 +106,11 @@ SceneStringNames::SceneStringNames() {
enter_camera=StaticCString::create("enter_camera");
exit_camera=StaticCString::create("exit_camera");
- _body_enter_scene = StaticCString::create("_body_enter_scene");
- _body_exit_scene = StaticCString::create("_body_exit_scene");
+ _body_enter_tree = StaticCString::create("_body_enter_tree");
+ _body_exit_tree = StaticCString::create("_body_exit_tree");
+
+ _area_enter_tree = StaticCString::create("_area_enter_tree");
+ _area_exit_tree = StaticCString::create("_area_exit_tree");
_input_event=StaticCString::create("_input_event");
@@ -144,5 +155,19 @@ SceneStringNames::SceneStringNames() {
baked_light_changed = StaticCString::create("baked_light_changed");
_baked_light_changed = StaticCString::create("_baked_light_changed");
+ _mouse_enter=StaticCString::create("_mouse_enter");
+ _mouse_exit=StaticCString::create("_mouse_exit");
+
+ _pressed=StaticCString::create("_pressed");
+ _toggled=StaticCString::create("_toggled");
+
+ 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 d4de0555ed..48f17ed38b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#define SCENE_STRING_NAMES_H
#include "string_db.h"
-
+#include "path_db.h"
class SceneStringNames {
friend void register_scene_types();
@@ -56,13 +56,16 @@ public:
StringName _input_event;
StringName item_rect_changed;
StringName shader_shader;
- StringName enter_scene;
- StringName exit_scene;
+ StringName shader_unshaded;
+ StringName shading_mode;
+ StringName enter_tree;
+ StringName exit_tree;
StringName size_flags_changed;
StringName minimum_size_changed;
StringName idle;
StringName iteration;
StringName update;
+ StringName updated;
StringName line_separation;
@@ -81,6 +84,12 @@ public:
StringName body_exit_shape;
StringName body_exit;
+ StringName area_enter_shape;
+ StringName area_exit_shape;
+
+ StringName _body_inout;
+ StringName _area_inout;
+
StringName _get_gizmo_geometry;
StringName _can_gizmo_scale;
@@ -89,12 +98,15 @@ public:
StringName _process;
StringName _enter_world;
StringName _exit_world;
- StringName _enter_scene;
- StringName _exit_scene;
+ StringName _enter_tree;
+ StringName _exit_tree;
StringName _draw;
StringName _input;
StringName _ready;
+ StringName _pressed;
+ StringName _toggled;
+
StringName _update_scroll;
StringName _update_xform;
@@ -116,8 +128,11 @@ public:
StringName enter_camera;
StringName exit_camera;
- StringName _body_enter_scene;
- StringName _body_exit_scene;
+ StringName _body_enter_tree;
+ StringName _body_exit_tree;
+
+ StringName _area_enter_tree;
+ StringName _area_exit_tree;
StringName changed;
StringName _shader_changed;
@@ -152,6 +167,19 @@ public:
StringName baked_light_changed;
StringName _baked_light_changed;
+ StringName _mouse_enter;
+ StringName _mouse_exit;
+
+ 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 1a858533b7..d861847101 100644
--- a/servers/SCsub
+++ b/servers/SCsub
@@ -12,8 +12,6 @@ SConscript('audio/SCsub');
SConscript('spatial_sound/SCsub');
SConscript('spatial_sound_2d/SCsub');
-lib = env.Library("servers",env.servers_sources, LIBSUFFIX=env['platform_libsuffix'])
+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 14d89cc216..dd5243e467 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h
index 6784edf594..04926b89eb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio/audio_filter_sw.cpp b/servers/audio/audio_filter_sw.cpp
index 5d8750ffdb..032d93b617 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio/audio_filter_sw.h b/servers/audio/audio_filter_sw.h
index 52315af686..e8540adea6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio/audio_mixer_sw.cpp b/servers/audio/audio_mixer_sw.cpp
index 873e19823a..033cd333d5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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];
@@ -369,7 +381,17 @@ void AudioMixerSW::mix_channel(Channel& c) {
AS::SampleLoopFormat loop_format=sample_manager->sample_get_loop_format(c.sample);
AS::SampleFormat format=sample_manager->sample_get_format(c.sample);
- bool use_fx=fx_enabled && (c.mix.old_reverb_vol || c.mix.reverb_vol || c.mix.old_chorus_vol || c.mix.chorus_vol );
+ bool use_fx=false;
+
+ if (fx_enabled) {
+
+ for(int i=0;i<mix_channels;i++) {
+ if (c.mix.old_reverb_vol[i] || c.mix.reverb_vol[i] || c.mix.old_chorus_vol[i] || c.mix.chorus_vol[i] ) {
+ use_fx=true;
+ break;
+ }
+ }
+ }
/* audio data */
@@ -389,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;
}
}
@@ -437,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);
@@ -539,16 +564,18 @@ 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);
}
c.mix.offset+=rstate.pos;
- dst_buff+=target*2;
-
+ dst_buff+=target*mix_channels;
+ rstate.reverb_buffer+=target*mix_channels;
}
c.filter.old_coefs=c.filter.coefs;
@@ -755,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;
@@ -767,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 d3caf03089..d8d9b7bacd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 cb08024851..417a582da6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -332,6 +332,7 @@ void AudioServerSW::driver_process_chunk(int p_frames,int32_t *p_buffer) {
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) {
@@ -454,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);
}
@@ -502,6 +503,7 @@ void AudioServerSW::voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, fl
cmd.voice=p_voice;
cmd.reverb.room=p_room_type;
cmd.reverb.send=p_reverb;
+
voice_rb.push_command(cmd);
}
@@ -794,6 +796,8 @@ void AudioServerSW::init() {
mixer = memnew( AudioMixerSW( sample_manager, latency, AudioDriverSW::get_singleton()->get_mix_rate(),mix_chans,mixer_use_fx,mixer_interp,_mixer_callback,this ) );
mixer_step_usecs=mixer->get_step_usecs();
+ _output_delay=0;
+
stream_volume=0.3;
// start the audio driver
if (AudioDriverSW::get_singleton())
@@ -826,10 +830,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;
}
}
@@ -910,6 +918,11 @@ float AudioServerSW::get_event_voice_global_volume_scale() const {
return event_voice_volume_scale;
}
+double AudioServerSW::get_output_delay() const {
+
+ return _output_delay+AudioDriverSW::get_singleton()->get_latency();
+}
+
double AudioServerSW::get_mix_time() const {
return AudioDriverSW::get_singleton()->get_mix_time();
diff --git a/servers/audio/audio_server_sw.h b/servers/audio/audio_server_sw.h
index d137c15633..c566e129c1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -92,6 +92,8 @@ class AudioServerSW : public AudioServer {
float peak_left,peak_right;
uint32_t max_peak;
+ double _output_delay;
+
VoiceRBSW voice_rb;
bool exit_update_thread;
@@ -144,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 );
@@ -206,6 +208,9 @@ public:
virtual double get_mix_time() const; //useful for video -> audio sync
+ virtual double get_output_delay() const;
+
+
AudioServerSW(SampleManagerSW *p_sample_manager);
~AudioServerSW();
@@ -251,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 6d09be9a3d..b840b9390b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio/reverb_buffers_sw.h b/servers/audio/reverb_buffers_sw.h
index 64a9e4fe7d..817122b65d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio/reverb_sw.cpp b/servers/audio/reverb_sw.cpp
index df36886db8..cc4b4bd778 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio/reverb_sw.h b/servers/audio/reverb_sw.h
index acf22f01b4..937824f907 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio/sample_manager_sw.cpp b/servers/audio/sample_manager_sw.cpp
index 5a5aa1a34c..375aa88cd2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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..
@@ -135,17 +135,50 @@ void SampleManagerMallocSW::sample_set_data(RID p_sample, const DVector<uint8_t>
ERR_EXPLAIN("Sample buffer size does not match sample size.");
+ //print_line("len bytes: "+itos(s->length_bytes)+" bufsize: "+itos(buff_size));
ERR_FAIL_COND(s->length_bytes!=buff_size);
DVector<uint8_t>::Read buffer_r=p_buffer.read();
const uint8_t *src = buffer_r.ptr();
uint8_t *dst = (uint8_t*)s->data;
- print_line("set data: "+itos(s->length_bytes));
+ //print_line("set data: "+itos(s->length_bytes));
for(int i=0;i<s->length_bytes;i++) {
dst[i]=src[i];
}
+ switch(s->format) {
+
+ case AS::SAMPLE_FORMAT_PCM8: {
+
+ if (s->stereo) {
+ dst[s->length]=dst[s->length-2];
+ dst[s->length+1]=dst[s->length-1];
+ } else {
+
+ dst[s->length]=dst[s->length-1];
+ }
+
+ } break;
+ case AS::SAMPLE_FORMAT_PCM16: {
+
+ if (s->stereo) {
+ dst[s->length]=dst[s->length-4];
+ dst[s->length+1]=dst[s->length-3];
+ dst[s->length+2]=dst[s->length-2];
+ dst[s->length+3]=dst[s->length-1];
+ } else {
+
+ dst[s->length]=dst[s->length-2];
+ dst[s->length+1]=dst[s->length-1];
+ }
+
+ } break;
+
+ }
+
+
+
}
const DVector<uint8_t> SampleManagerMallocSW::sample_get_data(RID p_sample) const {
diff --git a/servers/audio/sample_manager_sw.h b/servers/audio/sample_manager_sw.h
index 5de1b40389..94254f99d5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,104 +26,104 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SAMPLE_MANAGER_SW_H
-#define SAMPLE_MANAGER_SW_H
-
-#include "servers/audio_server.h"
-
-class SampleManagerSW {
-public:
-
- /* SAMPLE API */
-
- virtual RID sample_create(AS::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=0;
-
- virtual AS::SampleFormat sample_get_format(RID p_sample) const=0;
- virtual bool sample_is_stereo(RID p_sample) const=0;
- virtual int sample_get_length(RID p_sample) const=0;
-
- virtual void sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer)=0;
- virtual const DVector<uint8_t> sample_get_data(RID p_sample) const=0;
-
- virtual void *sample_get_data_ptr(RID p_sample) const=0;
-
- virtual void sample_set_mix_rate(RID p_sample,int p_rate)=0;
- virtual int sample_get_mix_rate(RID p_sample) const=0;
-
- virtual void sample_set_loop_format(RID p_sample,AS::SampleLoopFormat p_format)=0;
- virtual AS::SampleLoopFormat sample_get_loop_format(RID p_sample) const=0;
-
- virtual void sample_set_loop_begin(RID p_sample,int p_pos)=0;
- virtual int sample_get_loop_begin(RID p_sample) const=0;
-
- virtual void sample_set_loop_end(RID p_sample,int p_pos)=0;
- virtual int sample_get_loop_end(RID p_sample) const=0;
-
- virtual bool is_sample(RID) const=0;
- virtual void free(RID p_sample)=0;
-
-
-
- virtual ~SampleManagerSW();
-};
-
-
-class SampleManagerMallocSW : public SampleManagerSW {
-
-
- struct Sample {
-
- void *data;
- int length;
- int length_bytes;
- AS::SampleFormat format;
- bool stereo;
- AS::SampleLoopFormat loop_format;
- int loop_begin;
- int loop_end;
- int mix_rate;
- String description;
- };
-
- mutable RID_Owner<Sample> sample_owner;
-public:
-
- /* SAMPLE API */
-
- virtual RID sample_create(AS::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 AS::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 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_get_data_ptr(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,AS::SampleLoopFormat p_format);
- virtual AS::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;
-
- virtual bool is_sample(RID) const;
- virtual void free(RID p_sample);
-
- SampleManagerMallocSW();
- virtual ~SampleManagerMallocSW();
-};
-
-#endif // SAMPLE_MANAGER_SW_H
+#ifndef SAMPLE_MANAGER_SW_H
+#define SAMPLE_MANAGER_SW_H
+
+#include "servers/audio_server.h"
+
+class SampleManagerSW {
+public:
+
+ /* SAMPLE API */
+
+ virtual RID sample_create(AS::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=0;
+
+ virtual AS::SampleFormat sample_get_format(RID p_sample) const=0;
+ virtual bool sample_is_stereo(RID p_sample) const=0;
+ virtual int sample_get_length(RID p_sample) const=0;
+
+ virtual void sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer)=0;
+ virtual const DVector<uint8_t> sample_get_data(RID p_sample) const=0;
+
+ virtual void *sample_get_data_ptr(RID p_sample) const=0;
+
+ virtual void sample_set_mix_rate(RID p_sample,int p_rate)=0;
+ virtual int sample_get_mix_rate(RID p_sample) const=0;
+
+ virtual void sample_set_loop_format(RID p_sample,AS::SampleLoopFormat p_format)=0;
+ virtual AS::SampleLoopFormat sample_get_loop_format(RID p_sample) const=0;
+
+ virtual void sample_set_loop_begin(RID p_sample,int p_pos)=0;
+ virtual int sample_get_loop_begin(RID p_sample) const=0;
+
+ virtual void sample_set_loop_end(RID p_sample,int p_pos)=0;
+ virtual int sample_get_loop_end(RID p_sample) const=0;
+
+ virtual bool is_sample(RID) const=0;
+ virtual void free(RID p_sample)=0;
+
+
+
+ virtual ~SampleManagerSW();
+};
+
+
+class SampleManagerMallocSW : public SampleManagerSW {
+
+
+ struct Sample {
+
+ void *data;
+ int length;
+ int length_bytes;
+ AS::SampleFormat format;
+ bool stereo;
+ AS::SampleLoopFormat loop_format;
+ int loop_begin;
+ int loop_end;
+ int mix_rate;
+ String description;
+ };
+
+ mutable RID_Owner<Sample> sample_owner;
+public:
+
+ /* SAMPLE API */
+
+ virtual RID sample_create(AS::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 AS::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 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_get_data_ptr(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,AS::SampleLoopFormat p_format);
+ virtual AS::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;
+
+ virtual bool is_sample(RID) const;
+ virtual void free(RID p_sample);
+
+ SampleManagerMallocSW();
+ virtual ~SampleManagerMallocSW();
+};
+
+#endif // SAMPLE_MANAGER_SW_H
diff --git a/servers/audio/voice_rb_sw.cpp b/servers/audio/voice_rb_sw.cpp
index 93f176b755..a385e15283 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,9 +26,9 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "voice_rb_sw.h"
-/*
-VoiceRBSW::VoiceRBSW()
-{
-}
-*/
+#include "voice_rb_sw.h"
+/*
+VoiceRBSW::VoiceRBSW()
+{
+}
+*/
diff --git a/servers/audio/voice_rb_sw.h b/servers/audio/voice_rb_sw.h
index 7fcdebaa1a..cbebcdb86f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 81dab367c1..6c5a2de97b 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 85289de58a..cd3e920f31 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -274,6 +274,7 @@ public:
static AudioServer *get_singleton();
virtual double get_mix_time() const=0; //useful for video -> audio sync
+ virtual double get_output_delay() const=0;
AudioServer();
virtual ~AudioServer();
diff --git a/servers/physics/SCsub b/servers/physics/SCsub
index 16fe3a59ac..95296eadbe 100644
--- a/servers/physics/SCsub
+++ b/servers/physics/SCsub
@@ -4,4 +4,4 @@ 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 4a303d3fdd..3eb96fb681 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -67,7 +67,6 @@ void AreaPairSW::solve(float p_step) {
AreaPairSW::AreaPairSW(BodySW *p_body,int p_body_shape, AreaSW *p_area,int p_area_shape) {
-
body=p_body;
area=p_area;
body_shape=p_body_shape;
@@ -75,6 +74,8 @@ AreaPairSW::AreaPairSW(BodySW *p_body,int p_body_shape, AreaSW *p_area,int p_are
colliding=false;
body->add_constraint(this,0);
area->add_constraint(this);
+ if (p_body->get_mode()==PhysicsServer::BODY_MODE_KINEMATIC)
+ p_body->set_active(true);
}
@@ -92,3 +93,72 @@ AreaPairSW::~AreaPairSW() {
body->remove_constraint(this);
area->remove_constraint(this);
}
+
+////////////////////////////////////////////////////
+
+
+
+bool Area2PairSW::setup(float p_step) {
+
+// bool result = area_a->test_collision_mask(area_b) && CollisionSolverSW::solve(area_a->get_shape(shape_a),area_a->get_transform() * area_a->get_shape_transform(shape_a),Vector2(),area_b->get_shape(shape_b),area_b->get_transform() * area_b->get_shape_transform(shape_b),Vector2(),NULL,this);
+ bool result = CollisionSolverSW::solve_static(area_a->get_shape(shape_a),area_a->get_transform() * area_a->get_shape_transform(shape_a),area_b->get_shape(shape_b),area_b->get_transform() * area_b->get_shape_transform(shape_b),NULL,this);
+
+ if (result!=colliding) {
+
+ if (result) {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->add_area_to_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->add_area_to_query(area_b,shape_b,shape_a);
+
+ } else {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->remove_area_from_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->remove_area_from_query(area_b,shape_b,shape_a);
+ }
+
+ colliding=result;
+
+ }
+
+ return false; //never do any post solving
+}
+
+void Area2PairSW::solve(float p_step) {
+
+
+}
+
+
+Area2PairSW::Area2PairSW(AreaSW *p_area_a,int p_shape_a, AreaSW *p_area_b,int p_shape_b) {
+
+
+ area_a=p_area_a;
+ area_b=p_area_b;
+ shape_a=p_shape_a;
+ shape_b=p_shape_b;
+ colliding=false;
+ area_a->add_constraint(this);
+ area_b->add_constraint(this);
+
+}
+
+Area2PairSW::~Area2PairSW() {
+
+ if (colliding) {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->remove_area_from_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->remove_area_from_query(area_b,shape_b,shape_a);
+ }
+
+ area_a->remove_constraint(this);
+ area_b->remove_constraint(this);
+}
diff --git a/servers/physics/area_pair_sw.h b/servers/physics/area_pair_sw.h
index e5e2b5cf5e..4f8087280a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,5 +49,23 @@ public:
~AreaPairSW();
};
+
+class Area2PairSW : public ConstraintSW {
+
+ AreaSW *area_a;
+ AreaSW *area_b;
+ int shape_a;
+ int shape_b;
+ bool colliding;
+public:
+
+ bool setup(float p_step);
+ void solve(float p_step);
+
+ Area2PairSW(AreaSW *p_area_a,int p_shape_a, AreaSW *p_area_b,int p_shape_b);
+ ~Area2PairSW();
+};
+
+
#endif // AREA_PAIR__SW_H
diff --git a/servers/physics/area_sw.cpp b/servers/physics/area_sw.cpp
index 33962d993a..e78f0699cb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,6 +31,7 @@
#include "body_sw.h"
AreaSW::BodyKey::BodyKey(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape) { rid=p_body->get_self(); instance_id=p_body->get_instance_id(); body_shape=p_body_shape; area_shape=p_area_shape; }
+AreaSW::BodyKey::BodyKey(AreaSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape) { rid=p_body->get_self(); instance_id=p_body->get_instance_id(); body_shape=p_body_shape; area_shape=p_area_shape; }
void AreaSW::_shapes_changed() {
@@ -43,6 +44,7 @@ void AreaSW::set_transform(const Transform& p_transform) {
get_space()->area_add_to_moved_list(&moved_list);
_set_transform(p_transform);
+ _set_inv_transform(p_transform.affine_inverse());
}
void AreaSW::set_space(SpaceSW *p_space) {
@@ -56,6 +58,7 @@ void AreaSW::set_space(SpaceSW *p_space) {
}
monitored_bodies.clear();
+ monitored_areas.clear();
_set_space(p_space);
}
@@ -75,11 +78,40 @@ void AreaSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) {
monitor_callback_method=p_method;
monitored_bodies.clear();
+ monitored_areas.clear();
+
_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) {
+
+
+ if (p_id==area_monitor_callback_id) {
+ area_monitor_callback_method=p_method;
+ return;
+ }
+
+ _unregister_shapes();
+
+ area_monitor_callback_id=p_id;
+ area_monitor_callback_method=p_method;
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _shape_changed();
+
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+
+
+}
void AreaSW::set_space_override_mode(PhysicsServer::AreaSpaceOverrideMode p_mode) {
@@ -97,8 +129,10 @@ void AreaSW::set_param(PhysicsServer::AreaParameter p_param, const Variant& p_va
case PhysicsServer::AREA_PARAM_GRAVITY: gravity=p_value; ; break;
case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR: gravity_vector=p_value; ; break;
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;
}
@@ -112,8 +146,10 @@ Variant AreaSW::get_param(PhysicsServer::AreaParameter p_param) const {
case PhysicsServer::AREA_PARAM_GRAVITY: return gravity;
case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR: return gravity_vector;
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;
}
@@ -131,6 +167,15 @@ void AreaSW::_queue_monitor_update() {
}
+void AreaSW::set_monitorable(bool p_monitorable) {
+
+ if (monitorable==p_monitorable)
+ return;
+
+ monitorable=p_monitorable;
+ _set_static(!monitorable);
+}
+
void AreaSW::call_queries() {
if (monitor_callback_id && !monitored_bodies.empty()) {
@@ -147,8 +192,6 @@ void AreaSW::call_queries() {
return;
}
-
-
for (Map<BodyKey,BodyState>::Element *E=monitored_bodies.front();E;E=E->next()) {
if (E->get().state==0)
@@ -167,6 +210,41 @@ void AreaSW::call_queries() {
monitored_bodies.clear();
+ if (area_monitor_callback_id && !monitored_areas.empty()) {
+
+
+ Variant res[5];
+ Variant *resptr[5];
+ for(int i=0;i<5;i++)
+ resptr[i]=&res[i];
+
+ Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
+ if (!obj) {
+ monitored_areas.clear();
+ area_monitor_callback_id=0;
+ return;
+ }
+
+
+
+ for (Map<BodyKey,BodyState>::Element *E=monitored_areas.front();E;E=E->next()) {
+
+ if (E->get().state==0)
+ continue; //nothing happened
+
+ res[0]=E->get().state>0 ? PhysicsServer::AREA_BODY_ADDED : PhysicsServer::AREA_BODY_REMOVED;
+ res[1]=E->key().rid;
+ res[2]=E->key().instance_id;
+ res[3]=E->key().body_shape;
+ res[4]=E->key().area_shape;
+
+
+ Variant::CallError ce;
+ obj->call(area_monitor_callback_method,(const Variant**)resptr,5,ce);
+ }
+ }
+
+ monitored_areas.clear();
//get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
}
@@ -178,10 +256,15 @@ AreaSW::AreaSW() : CollisionObjectSW(TYPE_AREA), monitor_query_list(this), move
gravity=9.80665;
gravity_vector=Vector3(0,-1,0);
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;
+ area_monitor_callback_id=0;
+ monitorable=false;
}
diff --git a/servers/physics/area_sw.h b/servers/physics/area_sw.h
index 3e39dc3bb6..40ccdaf370 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -45,13 +45,19 @@ class AreaSW : public CollisionObjectSW{
float gravity;
Vector3 gravity_vector;
bool gravity_is_point;
+ float gravity_distance_scale;
float point_attenuation;
- float density;
+ float linear_damp;
+ float angular_damp;
int priority;
+ bool monitorable;
ObjectID monitor_callback_id;
StringName monitor_callback_method;
+ ObjectID area_monitor_callback_id;
+ StringName area_monitor_callback_method;
+
SelfList<AreaSW> monitor_query_list;
SelfList<AreaSW> moved_list;
@@ -70,7 +76,7 @@ class AreaSW : public CollisionObjectSW{
return area_shape < p_key.area_shape;
} else
- return body_shape < p_key.area_shape;
+ return body_shape < p_key.body_shape;
} else
return rid < p_key.rid;
@@ -78,6 +84,8 @@ class AreaSW : public CollisionObjectSW{
_FORCE_INLINE_ BodyKey() {}
BodyKey(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+ BodyKey(AreaSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+
};
struct BodyState {
@@ -89,6 +97,7 @@ class AreaSW : public CollisionObjectSW{
};
Map<BodyKey,BodyState> monitored_bodies;
+ Map<BodyKey,BodyState> monitored_areas;
//virtual void shape_changed_notify(ShapeSW *p_shape);
//virtual void shape_deleted_notify(ShapeSW *p_shape);
@@ -107,9 +116,15 @@ public:
void set_monitor_callback(ObjectID p_id, const StringName& p_method);
_FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id; }
+ void set_area_monitor_callback(ObjectID p_id, const StringName& p_method);
+ _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id; }
+
_FORCE_INLINE_ void add_body_to_query(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
_FORCE_INLINE_ void remove_body_from_query(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+ _FORCE_INLINE_ void add_area_to_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape);
+ _FORCE_INLINE_ void remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape);
+
void set_param(PhysicsServer::AreaParameter p_param, const Variant& p_value);
Variant get_param(PhysicsServer::AreaParameter p_param) const;
@@ -125,11 +140,17 @@ public:
_FORCE_INLINE_ void set_gravity_as_point(bool p_enable) { gravity_is_point=p_enable; }
_FORCE_INLINE_ bool is_gravity_point() const { return gravity_is_point; }
+ _FORCE_INLINE_ void set_gravity_distance_scale(float scale) { gravity_distance_scale=scale; }
+ _FORCE_INLINE_ float get_gravity_distance_scale() const { return gravity_distance_scale; }
+
_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; }
@@ -138,6 +159,9 @@ public:
_FORCE_INLINE_ void remove_constraint( ConstraintSW* p_constraint) { constraints.erase(p_constraint); }
_FORCE_INLINE_ const Set<ConstraintSW*>& get_constraints() const { return constraints; }
+ void set_monitorable(bool p_monitorable);
+ _FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
+
void set_transform(const Transform& p_transform);
void set_space(SpaceSW *p_space);
@@ -165,6 +189,27 @@ void AreaSW::remove_body_from_query(BodySW *p_body, uint32_t p_body_shape,uint32
}
+void AreaSW::add_area_to_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape) {
+
+
+ BodyKey bk(p_area,p_area_shape,p_self_shape);
+ monitored_areas[bk].inc();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+
+
+}
+void AreaSW::remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape) {
+
+
+ BodyKey bk(p_area,p_area_shape,p_self_shape);
+ 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 094f56a421..7eab9eb86d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,7 +29,7 @@
#include "body_pair_sw.h"
#include "collision_solver_sw.h"
#include "space_sw.h"
-
+#include "os/os.h"
/*
#define NO_ACCUMULATE_IMPULSES
@@ -172,8 +172,59 @@ void BodyPairSW::validate_contacts() {
}
}
+
+bool BodyPairSW::_test_ccd(float p_step,BodySW *p_A, int p_shape_A,const Transform& p_xform_A,BodySW *p_B, int p_shape_B,const Transform& p_xform_B) {
+
+
+
+ Vector3 motion = p_A->get_linear_velocity()*p_step;
+ real_t mlen = motion.length();
+ if (mlen<CMP_EPSILON)
+ return false;
+
+ Vector3 mnormal = motion / mlen;
+
+ real_t min,max;
+ p_A->get_shape(p_shape_A)->project_range(mnormal,p_xform_A,min,max);
+ bool fast_object = mlen > (max-min)*0.3; //going too fast in that direction
+
+ if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
+ return false;
+ }
+
+ //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
+ 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;
+
+ Transform from_inv = p_xform_B.affine_inverse();
+
+ Vector3 local_from = from_inv.xform(from-mnormal*mlen*0.1); //start from a little inside the bounding box
+ Vector3 local_to = from_inv.xform(to);
+
+ Vector3 rpos,rnorm;
+ if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from,local_to,rpos,rnorm)) {
+ return false;
+ }
+
+ //shorten the linear velocity so it does not hit, but gets close enough, next frame will hit softly or soft enough
+ Vector3 hitpos = p_xform_B.xform(rpos);
+
+ float newlen = hitpos.distance_to(from)-(max-min)*0.01;
+ p_A->set_linear_velocity((mnormal*newlen)/p_step);
+
+ return true;
+}
+
+
bool BodyPairSW::setup(float p_step) {
+ //cannot collide
+ if ((A->get_layer_mask()&B->get_layer_mask())==0 || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && A->get_max_contacts_reported()==0 && B->get_max_contacts_reported()==0)) {
+ collided=false;
+ return false;
+ }
offset_B = B->get_transform().get_origin() - A->get_transform().get_origin();
@@ -193,15 +244,24 @@ bool BodyPairSW::setup(float p_step) {
bool collided = CollisionSolverSW::solve_static(shape_A_ptr,xform_A,shape_B_ptr,xform_B,_contact_added_callback,this,&sep_axis);
this->collided=collided;
- if (!collided)
- return false;
+ if (!collided) {
+
+ //test ccd (currently just a raycast)
+
+ if (A->is_continuous_collision_detection_enabled() && A->get_mode()>PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC) {
+ _test_ccd(p_step,A,shape_A,xform_A,B,shape_B,xform_B);
+ }
+
+ if (B->is_continuous_collision_detection_enabled() && B->get_mode()>PhysicsServer::BODY_MODE_KINEMATIC && A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC) {
+ _test_ccd(p_step,B,shape_B,xform_B,A,shape_A,xform_A);
+ }
- //cannot collide
- if (A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC)) {
return false;
}
+
+
real_t max_penetration = space->get_contact_max_allowed_penetration();
float bias = 0.3f;
@@ -217,6 +277,7 @@ bool BodyPairSW::setup(float p_step) {
}
+
real_t inv_dt = 1.0/p_step;
for(int i=0;i<contact_count;i++) {
@@ -227,6 +288,7 @@ bool BodyPairSW::setup(float p_step) {
Vector3 global_A = xform_Au.xform(c.local_A);
Vector3 global_B = xform_Bu.xform(c.local_B);
+
real_t depth = c.normal.dot(global_A - global_B);
if (depth<=0) {
@@ -236,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();
@@ -264,6 +336,14 @@ bool BodyPairSW::setup(float p_step) {
B->add_contact(global_B,c.normal,depth,shape_B,global_A,shape_A,A->get_instance_id(),A->get_self(),crA);
}
+ if (A->is_shape_set_as_trigger(shape_A) || B->is_shape_set_as_trigger(shape_B) || (A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC)) {
+ c.active=false;
+ collided=false;
+ continue;
+
+ }
+
+
c.active=true;
// Precompute normal mass, tangent mass, and bias.
@@ -295,6 +375,17 @@ bool BodyPairSW::setup(float p_step) {
A->apply_bias_impulse( c.rA, -jb_vec );
B->apply_bias_impulse( c.rB, jb_vec );
+ c.bounce = MAX(A->get_bounce(),B->get_bounce());
+ if (c.bounce) {
+
+ Vector3 crA = A->get_angular_velocity().cross( c.rA );
+ Vector3 crB = B->get_angular_velocity().cross( c.rB );
+ Vector3 dv = B->get_linear_velocity() + crB - A->get_linear_velocity() - crA;
+ //normal impule
+ c.bounce = c.bounce * dv.dot(c.normal);
+ }
+
+
}
return true;
@@ -347,8 +438,7 @@ void BodyPairSW::solve(float p_step) {
if (Math::abs(vn)>MIN_VELOCITY) {
- real_t bounce=0;
- real_t jn = (-bounce -vn)*c.mass_normal;
+ real_t jn = -(c.bounce + vn)*c.mass_normal;
real_t jnOld = c.acc_normal_impulse;
c.acc_normal_impulse = MAX(jnOld + jn, 0.0f);
diff --git a/servers/physics/body_pair_sw.h b/servers/physics/body_pair_sw.h
index ad66227b36..8ec7a9ccef 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -61,6 +61,7 @@ class BodyPairSW : public ConstraintSW {
real_t acc_bias_impulse; // accumulated normal impulse for position bias (Pnb)
real_t mass_normal;
real_t bias;
+ real_t bounce;
real_t depth;
bool active;
@@ -81,6 +82,7 @@ class BodyPairSW : public ConstraintSW {
void contact_added_callback(const Vector3& p_point_A,const Vector3& p_point_B);
void validate_contacts();
+ bool _test_ccd(float p_step,BodySW *p_A, int p_shape_A,const Transform& p_xform_A,BodySW *p_B, int p_shape_B,const Transform& p_xform_B);
SpaceSW *space;
diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp
index 52edc0faa7..c66e73b430 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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:{}
}
@@ -185,6 +208,7 @@ float BodySW::get_param(PhysicsServer::BodyParameter p_param) const {
void BodySW::set_mode(PhysicsServer::BodyMode p_mode) {
+ PhysicsServer::BodyMode prev=mode;
mode=p_mode;
switch(p_mode) {
@@ -195,22 +219,25 @@ void BodySW::set_mode(PhysicsServer::BodyMode p_mode) {
_set_inv_transform(get_transform().affine_inverse());
_inv_mass=0;
_set_static(p_mode==PhysicsServer::BODY_MODE_STATIC);
- set_active(p_mode==PhysicsServer::BODY_MODE_KINEMATIC);
+ //set_active(p_mode==PhysicsServer::BODY_MODE_KINEMATIC);
+ set_active(p_mode==PhysicsServer::BODY_MODE_KINEMATIC && contacts.size());
linear_velocity=Vector3();
angular_velocity=Vector3();
+ if (mode==PhysicsServer::BODY_MODE_KINEMATIC && prev!=mode) {
+ first_time_kinematic=true;
+ }
+
} break;
case PhysicsServer::BODY_MODE_RIGID: {
_inv_mass=mass>0?(1.0/mass):0;
_set_static(false);
- simulated_motion=false; //jic
} break;
case PhysicsServer::BODY_MODE_CHARACTER: {
_inv_mass=mass>0?(1.0/mass):0;
_set_static(false);
- simulated_motion=false; //jic
} break;
}
@@ -235,17 +262,31 @@ void BodySW::set_state(PhysicsServer::BodyState p_state, const Variant& p_varian
case PhysicsServer::BODY_STATE_TRANSFORM: {
- if (mode==PhysicsServer::BODY_MODE_STATIC || mode==PhysicsServer::BODY_MODE_KINEMATIC) {
+ if (mode==PhysicsServer::BODY_MODE_KINEMATIC) {
+ new_transform=p_variant;
+ //wakeup_neighbours();
+ set_active(true);
+ if (first_time_kinematic) {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().affine_inverse());
+ first_time_kinematic=false;
+ }
+
+ } else if (mode==PhysicsServer::BODY_MODE_STATIC) {
_set_transform(p_variant);
_set_inv_transform(get_transform().affine_inverse());
wakeup_neighbours();
} else {
Transform t = p_variant;
t.orthonormalize();
+ new_transform=get_transform(); //used as old to compute motion
+ if (new_transform==t)
+ break;
_set_transform(t);
_set_inv_transform(get_transform().inverse());
}
+ wakeup();
} break;
case PhysicsServer::BODY_STATE_LINEAR_VELOCITY: {
@@ -253,11 +294,13 @@ void BodySW::set_state(PhysicsServer::BodyState p_state, const Variant& p_varian
//if (mode==PhysicsServer::BODY_MODE_STATIC)
// break;
linear_velocity=p_variant;
+ wakeup();
} break;
case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY: {
//if (mode!=PhysicsServer::BODY_MODE_RIGID)
// break;
angular_velocity=p_variant;
+ wakeup();
} break;
case PhysicsServer::BODY_STATE_SLEEPING: {
@@ -339,63 +382,120 @@ void BodySW::set_space(SpaceSW *p_space){
}
-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()) {
-
- gravity = (p_area->get_gravity_vector() - get_transform().get_origin()).normalized() * p_area->get_gravity();
-
+ if(p_area->get_gravity_distance_scale() > 0) {
+ Vector3 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
+ gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale()+1, 2) );
+ } else {
+ gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
+ }
} else {
- gravity = p_area->get_gravity_vector() * p_area->get_gravity();
+ 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) {
- if (mode==PhysicsServer::BODY_MODE_STATIC || mode==PhysicsServer::BODY_MODE_KINEMATIC)
+ if (mode==PhysicsServer::BODY_MODE_STATIC)
return;
- AreaSW *current_area = get_space()->get_default_area();
- ERR_FAIL_COND(!current_area);
+ AreaSW *def_area = get_space()->get_default_area();
+ AreaSW *damp_area = def_area;
+
+ ERR_FAIL_COND(!def_area);
- int prio = current_area->get_priority();
int ac = areas.size();
+ bool replace = false;
+ gravity = Vector3(0,0,0);
+ area_linear_damp = 0;
+ area_angular_damp = 0;
if (ac) {
+ areas.sort();
const AreaCMP *aa = &areas[0];
- for(int i=0;i<ac;i++) {
- if (aa[i].area->get_priority() > prio) {
- current_area=aa[i].area;
- prio=current_area->get_priority();
+ damp_area = aa[ac-1].area;
+ for(int i=ac-1;i>=0;i--) {
+ _compute_area_gravity_and_dampenings(aa[i].area);
+ if (aa[i].area->get_space_override_mode() == PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE) {
+ replace = true;
+ break;
}
}
}
- _compute_area_gravity(current_area);
- density=current_area->get_density();
+ if( !replace ) {
+ _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;
- if (!omit_force_integration) {
- //overriden by direct state query
+ if (mode==PhysicsServer::BODY_MODE_KINEMATIC) {
+
+ //compute motion, angular and etc. velocities from prev transform
+ linear_velocity = (new_transform.origin - get_transform().origin)/p_step;
+
+ //compute a FAKE angular velocity, not so easy
+ Matrix3 rot=new_transform.basis.orthonormalized().transposed() * get_transform().basis.orthonormalized();
+ Vector3 axis;
+ float angle;
+
+ rot.get_axis_and_angle(axis,angle);
+ axis.normalize();
+ angular_velocity=axis.normalized() * (angle/p_step);
- Vector3 force=gravity*mass;
- force+=applied_force;
- Vector3 torque=applied_torque;
+ motion = new_transform.origin - get_transform().origin;
+ do_motion=true;
- real_t damp = 1.0 - p_step * density;
+ } else {
+ if (!omit_force_integration) {
+ //overriden by direct state query
+
+ Vector3 force=gravity*mass;
+ force+=applied_force;
+ Vector3 torque=applied_torque;
- if (damp<0) // reached zero in the given time
- damp=0;
+ real_t damp = 1.0 - p_step * area_linear_damp;
- real_t angular_damp = 1.0 - p_step * density * get_space()->get_body_angular_velocity_damp_ratio();
+ if (damp<0) // reached zero in the given time
+ damp=0;
- if (angular_damp<0) // reached zero in the given time
- angular_damp=0;
+ real_t angular_damp = 1.0 - p_step * area_angular_damp;
- linear_velocity*=damp;
- angular_velocity*=angular_damp;
+ if (angular_damp<0) // reached zero in the given time
+ angular_damp=0;
+
+ linear_velocity*=damp;
+ angular_velocity*=angular_damp;
+
+ linear_velocity+=_inv_mass * force * p_step;
+ angular_velocity+=_inv_inertia_tensor.xform(torque)*p_step;
+ }
+
+ if (continuous_cd) {
+ motion=linear_velocity*p_step;
+ do_motion=true;
+ }
- linear_velocity+=_inv_mass * force * p_step;
- angular_velocity+=_inv_inertia_tensor.xform(torque)*p_step;
}
applied_force=Vector3();
@@ -406,10 +506,13 @@ void BodySW::integrate_forces(real_t p_step) {
biased_angular_velocity=Vector3();
biased_linear_velocity=Vector3();
- if (continuous_cd) //shapes temporarily extend for raycast
- _update_shapes_with_motion(linear_velocity*p_step);
- current_area=NULL; // clear the area, so it is set in the next frame
+ if (do_motion) {//shapes temporarily extend for raycast
+ _update_shapes_with_motion(motion);
+ }
+
+
+ def_area=NULL; // clear the area, so it is set in the next frame
contact_count=0;
}
@@ -419,9 +522,16 @@ void BodySW::integrate_velocities(real_t p_step) {
if (mode==PhysicsServer::BODY_MODE_STATIC)
return;
+ if (fi_callback)
+ get_space()->body_add_to_state_query_list(&direct_state_query_list);
+
if (mode==PhysicsServer::BODY_MODE_KINEMATIC) {
- if (fi_callback)
- get_space()->body_add_to_state_query_list(&direct_state_query_list);
+
+ _set_transform(new_transform,false);
+ _set_inv_transform(new_transform.affine_inverse());
+ if (contacts.size()==0 && linear_velocity==Vector3() && angular_velocity==Vector3())
+ set_active(false); //stopped moving, deactivate
+
return;
}
@@ -475,14 +585,13 @@ void BodySW::integrate_velocities(real_t p_step) {
_update_inertia_tensor();
- if (fi_callback) {
-
- get_space()->body_add_to_state_query_list(&direct_state_query_list);
- }
+ //if (fi_callback) {
+ // get_space()->body_add_to_state_query_list(&direct_state_query_list);
+ //
}
-
+/*
void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) {
Transform inv_xform = p_xform.affine_inverse();
@@ -514,6 +623,7 @@ void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) {
}
+*/
void BodySW::wakeup_neighbours() {
@@ -562,12 +672,7 @@ void BodySW::call_queries() {
}
- if (simulated_motion) {
- // linear_velocity=Vector3();
- // angular_velocity=0;
- simulated_motion=false;
- }
}
@@ -631,10 +736,15 @@ BodySW::BodySW() : CollisionObjectSW(TYPE_BODY), active_list(this), inertia_upda
island_step=0;
island_next=NULL;
island_list_next=NULL;
+ first_time_kinematic=false;
_set_static(false);
- density=0;
+
contact_count=0;
- simulated_motion=false;
+ gravity_scale=1.0;
+
+ area_angular_damp=0;
+ area_linear_damp=0;
+
still_time=0;
continuous_cd=false;
can_sleep=false;
diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h
index 8923899278..4c4c7818c5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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;
@@ -71,24 +78,26 @@ class BodySW : public CollisionObjectSW {
VSet<RID> exceptions;
bool omit_force_integration;
bool active;
- bool simulated_motion;
+
bool continuous_cd;
bool can_sleep;
+ bool first_time_kinematic;
void _update_inertia();
virtual void _shapes_changed();
+ Transform new_transform;
Map<ConstraintSW*,int> constraint_map;
struct AreaCMP {
AreaSW *area;
- _FORCE_INLINE_ bool operator<(const AreaCMP& p_cmp) const { return area->get_self() < p_cmp.area->get_self() ; }
+ _FORCE_INLINE_ bool operator==(const AreaCMP& p_cmp) const { return area->get_self() == p_cmp.area->get_self();}
+ _FORCE_INLINE_ bool operator<(const AreaCMP& p_cmp) const { return area->get_priority() < p_cmp.area->get_priority();}
_FORCE_INLINE_ AreaCMP() {}
_FORCE_INLINE_ AreaCMP(AreaSW *p_area) { area=p_area;}
};
-
- VSet<AreaCMP> areas;
+ Vector<AreaCMP> areas;
struct Contact {
@@ -121,7 +130,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();
@@ -132,11 +141,10 @@ public:
void set_force_integration_callback(ObjectID p_id,const StringName& p_method,const Variant& p_udata=Variant());
-
- _FORCE_INLINE_ void add_area(AreaSW *p_area) { areas.insert(AreaCMP(p_area)); }
+ _FORCE_INLINE_ void add_area(AreaSW *p_area) { areas.ordered_insert(AreaCMP(p_area)); }
_FORCE_INLINE_ void remove_area(AreaSW *p_area) { areas.erase(AreaCMP(p_area)); }
- _FORCE_INLINE_ void set_max_contacts_reported(int p_size) { contacts.resize(p_size); contact_count=0; }
+ _FORCE_INLINE_ void set_max_contacts_reported(int p_size) { contacts.resize(p_size); contact_count=0; if (mode==PhysicsServer::BODY_MODE_KINEMATIC && p_size) set_active(true);}
_FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); }
_FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); }
@@ -199,6 +207,12 @@ public:
void set_active(bool p_active);
_FORCE_INLINE_ bool is_active() const { return active; }
+ _FORCE_INLINE_ void wakeup() {
+ if ((!get_space()) || mode==PhysicsServer::BODY_MODE_STATIC || mode==PhysicsServer::BODY_MODE_KINEMATIC)
+ return;
+ set_active(true);
+ }
+
void set_param(PhysicsServer::BodyParameter p_param, float);
float get_param(PhysicsServer::BodyParameter p_param) const;
@@ -226,7 +240,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; }
@@ -235,7 +248,29 @@ public:
void integrate_forces(real_t p_step);
void integrate_velocities(real_t p_step);
- void simulate_motion(const Transform& p_xform,real_t p_step);
+ _FORCE_INLINE_ Vector3 get_velocity_in_local_point(const Vector3& rel_pos) const {
+
+ return linear_velocity + angular_velocity.cross(rel_pos);
+ }
+
+ _FORCE_INLINE_ real_t compute_impulse_denominator(const Vector3& p_pos, const Vector3& p_normal) const {
+
+ Vector3 r0 = p_pos - get_transform().origin;
+
+ Vector3 c0 = (r0).cross(p_normal);
+
+ Vector3 vec = (_inv_inertia_tensor.xform_inv(c0)).cross(r0);
+
+ return _inv_mass + p_normal.dot(vec);
+
+ }
+
+ _FORCE_INLINE_ real_t compute_angular_impulse_denominator(const Vector3& p_axis) const {
+
+ return p_axis.dot( _inv_inertia_tensor.xform_inv(p_axis) );
+ }
+
+ //void simulate_motion(const Transform& p_xform,real_t p_step);
void call_queries();
void wakeup_neighbours();
@@ -306,8 +341,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
@@ -323,6 +359,7 @@ public:
virtual Transform get_transform() const { return body->get_transform(); }
virtual void add_force(const Vector3& p_force, const Vector3& p_pos) { body->add_force(p_force,p_pos); }
+ virtual void apply_impulse(const Vector3& p_pos, const Vector3& p_j) { body->apply_impulse(p_pos,p_j); }
virtual void set_sleep_state(bool p_enable) { body->set_active(!p_enable); }
virtual bool is_sleeping() const { return !body->is_active(); }
diff --git a/servers/physics/broad_phase_basic.cpp b/servers/physics/broad_phase_basic.cpp
index 5db78e669f..c49caed795 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics/broad_phase_basic.h b/servers/physics/broad_phase_basic.h
index 7b77466292..9848c4b16e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics/broad_phase_octree.cpp b/servers/physics/broad_phase_octree.cpp
index edf4aae2b2..874ae29755 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics/broad_phase_octree.h b/servers/physics/broad_phase_octree.h
index d365213966..200878f6df 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics/broad_phase_sw.cpp b/servers/physics/broad_phase_sw.cpp
index 1211db141f..910be4e623 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics/broad_phase_sw.h b/servers/physics/broad_phase_sw.h
index 57301a2af9..2bf9f202e2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp
index 156004d15d..19b3f28a2f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -216,4 +216,6 @@ CollisionObjectSW::CollisionObjectSW(Type p_type) {
type=p_type;
space=NULL;
instance_id=0;
+ layer_mask=1;
+ ray_pickable=true;
}
diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h
index 6d60f2f078..c018ab6224 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,6 +34,11 @@
#include "self_list.h"
#include "broad_phase_sw.h"
+#ifdef DEBUG_ENABLED
+#define MAX_OBJECT_DISTANCE 10000000.0
+#define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE*MAX_OBJECT_DISTANCE)
+#endif
+
class SpaceSW;
class CollisionObjectSW : public ShapeOwnerSW {
@@ -47,6 +52,7 @@ private:
Type type;
RID self;
ObjectID instance_id;
+ uint32_t layer_mask;
struct Shape {
@@ -55,6 +61,9 @@ private:
BroadPhaseSW::ID bpid;
AABB aabb_cache; //for rayqueries
ShapeSW *shape;
+ bool trigger;
+
+ Shape() { trigger=false; }
};
Vector<Shape> shapes;
@@ -71,13 +80,28 @@ protected:
void _update_shapes_with_motion(const Vector3& p_motion);
void _unregister_shapes();
- _FORCE_INLINE_ void _set_transform(const Transform& p_transform) { transform=p_transform; _update_shapes(); }
+ _FORCE_INLINE_ void _set_transform(const Transform& p_transform,bool p_update_shapes=true) {
+
+#ifdef DEBUG_ENABLED
+
+ if (p_transform.origin.length_squared() > MAX_OBJECT_DISTANCE_X2) {
+ ERR_EXPLAIN("Object went too far away (more than "+itos(MAX_OBJECT_DISTANCE)+"mts from origin).");
+ ERR_FAIL();
+ }
+#endif
+
+ transform=p_transform; if (p_update_shapes) _update_shapes();
+
+ }
_FORCE_INLINE_ void _set_inv_transform(const Transform& p_transform) { inv_transform=p_transform; }
void _set_static(bool p_static);
virtual void _shapes_changed()=0;
void _set_space(SpaceSW *space);
+ bool ray_pickable;
+
+
CollisionObjectSW(Type p_type);
public:
@@ -103,7 +127,14 @@ public:
_FORCE_INLINE_ Transform get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ SpaceSW* get_space() const { return space; }
+ _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable=p_enable; }
+ _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; }
+
+ _FORCE_INLINE_ void set_shape_as_trigger(int p_idx,bool p_enable) { shapes[p_idx].trigger=p_enable; }
+ _FORCE_INLINE_ bool is_shape_set_as_trigger(int p_idx) const { return shapes[p_idx].trigger; }
+ _FORCE_INLINE_ void set_layer_mask(uint32_t p_mask) { layer_mask=p_mask; }
+ _FORCE_INLINE_ uint32_t get_layer_mask() const { return layer_mask; }
void remove_shape(ShapeSW *p_shape);
void remove_shape(int p_index);
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
index 1cd40db772..72e61f1456 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -43,7 +43,9 @@ struct _CollectorCallback {
_FORCE_INLINE_ void call(const Vector3& p_point_A, const Vector3& p_point_B) {
//if (normal.dot(p_point_A) >= normal.dot(p_point_B))
- // return;
+ // return;
+// print_line("** A: "+p_point_A+" B: "+p_point_B+" D: "+rtos(p_point_A.distance_to(p_point_B)));
+
if (swap)
callback(p_point_B,p_point_A,userdata);
else
@@ -231,11 +233,14 @@ static void _generate_contacts_face_face(const Vector3 * p_points_A,int p_point_
for (int i=0;i<clipbuf_len;i++) {
float d = plane_B.distance_to(clipbuf_src[i]);
- if (d>CMP_EPSILON)
- continue;
+ //if (d>CMP_EPSILON)
+ // continue;
Vector3 closest_B=clipbuf_src[i] - plane_B.normal*d;
+ if (p_callback->normal.dot(clipbuf_src[i]) >= p_callback->normal.dot(closest_B))
+ continue;
+
p_callback->call(clipbuf_src[i],closest_B);
added++;
@@ -301,7 +306,7 @@ static void _generate_contacts_from_supports(const Vector3 * p_points_A,int p_po
-template<class ShapeA, class ShapeB>
+template<class ShapeA, class ShapeB, bool withMargin=false>
class SeparatorAxisTest {
const ShapeA *shape_A;
@@ -311,7 +316,8 @@ class SeparatorAxisTest {
real_t best_depth;
Vector3 best_axis;
_CollectorCallback *callback;
-
+ real_t margin_A;
+ real_t margin_B;
Vector3 separator_axis;
public:
@@ -340,6 +346,13 @@ public:
shape_A->project_range(axis,*transform_A,min_A,max_A);
shape_B->project_range(axis,*transform_B,min_B,max_B);
+ if (withMargin) {
+ min_A-=margin_A;
+ max_A+=margin_A;
+ min_B-=margin_B;
+ max_B+=margin_B;
+ }
+
min_B -= ( max_A - min_A ) * 0.5;
max_B += ( max_A - min_A ) * 0.5;
@@ -394,6 +407,14 @@ public:
supports_A[i] = transform_A->xform(supports_A[i]);
}
+ if (withMargin) {
+
+ for(int i=0;i<support_count_A;i++) {
+ supports_A[i]+=-best_axis*margin_A;
+ }
+
+ }
+
Vector3 supports_B[max_supports];
int support_count_B;
@@ -401,8 +422,16 @@ public:
for(int i=0;i<support_count_B;i++) {
supports_B[i] = transform_B->xform(supports_B[i]);
}
+
+ if (withMargin) {
+
+ for(int i=0;i<support_count_B;i++) {
+ supports_B[i]+=best_axis*margin_B;
+ }
+ }
/*
print_line("best depth: "+rtos(best_depth));
+ print_line("best axis: "+(best_axis));
for(int i=0;i<support_count_A;i++) {
print_line("A-"+itos(i)+": "+supports_A[i]);
@@ -423,13 +452,16 @@ public:
}
- _FORCE_INLINE_ SeparatorAxisTest(const ShapeA *p_shape_A,const Transform& p_transform_A, const ShapeB *p_shape_B,const Transform& p_transform_B,_CollectorCallback *p_callback) {
+ _FORCE_INLINE_ SeparatorAxisTest(const ShapeA *p_shape_A,const Transform& p_transform_A, const ShapeB *p_shape_B,const Transform& p_transform_B,_CollectorCallback *p_callback,real_t p_margin_A=0,real_t p_margin_B=0) {
best_depth=1e15;
shape_A=p_shape_A;
shape_B=p_shape_B;
transform_A=&p_transform_A;
transform_B=&p_transform_B;
callback=p_callback;
+ margin_A=p_margin_A;
+ margin_B=p_margin_B;
+
}
};
@@ -440,16 +472,17 @@ public:
/****** SAT TESTS *******/
-typedef void (*CollisionFunc)(const ShapeSW*,const Transform&,const ShapeSW*,const Transform&,_CollectorCallback *p_callback);
+typedef void (*CollisionFunc)(const ShapeSW*,const Transform&,const ShapeSW*,const Transform&,_CollectorCallback *p_callback,float,float);
-static void _collision_sphere_sphere(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_sphere_sphere(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW*>(p_a);
const SphereShapeSW *sphere_B = static_cast<const SphereShapeSW*>(p_b);
- SeparatorAxisTest<SphereShapeSW,SphereShapeSW> separator(sphere_A,p_transform_a,sphere_B,p_transform_b,p_collector);
+ SeparatorAxisTest<SphereShapeSW,SphereShapeSW,withMargin> separator(sphere_A,p_transform_a,sphere_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
// previous axis
@@ -462,13 +495,14 @@ static void _collision_sphere_sphere(const ShapeSW *p_a,const Transform &p_trans
separator.generate_contacts();
}
-static void _collision_sphere_box(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_sphere_box(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW*>(p_a);
const BoxShapeSW *box_B = static_cast<const BoxShapeSW*>(p_b);
- SeparatorAxisTest<SphereShapeSW,BoxShapeSW> separator(sphere_A,p_transform_a,box_B,p_transform_b,p_collector);
+ SeparatorAxisTest<SphereShapeSW,BoxShapeSW,withMargin> separator(sphere_A,p_transform_a,box_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
return;
@@ -516,13 +550,13 @@ static void _collision_sphere_box(const ShapeSW *p_a,const Transform &p_transfor
}
-
-static void _collision_sphere_capsule(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_sphere_capsule(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW*>(p_a);
const CapsuleShapeSW *capsule_B = static_cast<const CapsuleShapeSW*>(p_b);
- SeparatorAxisTest<SphereShapeSW,CapsuleShapeSW> separator(sphere_A,p_transform_a,capsule_B,p_transform_b,p_collector);
+ SeparatorAxisTest<SphereShapeSW,CapsuleShapeSW,withMargin> separator(sphere_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
return;
@@ -540,7 +574,7 @@ static void _collision_sphere_capsule(const ShapeSW *p_a,const Transform &p_tran
Vector3 capsule_ball_2 = p_transform_b.origin - capsule_axis;
- if (!separator.test_axis( (capsule_ball_1 - p_transform_a.origin).normalized() ) )
+ if (!separator.test_axis( (capsule_ball_2 - p_transform_a.origin).normalized() ) )
return;
//capsule edge, sphere
@@ -556,13 +590,14 @@ static void _collision_sphere_capsule(const ShapeSW *p_a,const Transform &p_tran
separator.generate_contacts();
}
-static void _collision_sphere_convex_polygon(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_sphere_convex_polygon(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW*>(p_a);
const ConvexPolygonShapeSW *convex_polygon_B = static_cast<const ConvexPolygonShapeSW*>(p_b);
- SeparatorAxisTest<SphereShapeSW,ConvexPolygonShapeSW> separator(sphere_A,p_transform_a,convex_polygon_B,p_transform_b,p_collector);
+ SeparatorAxisTest<SphereShapeSW,ConvexPolygonShapeSW,withMargin> separator(sphere_A,p_transform_a,convex_polygon_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
@@ -626,14 +661,15 @@ static void _collision_sphere_convex_polygon(const ShapeSW *p_a,const Transform
}
-static void _collision_sphere_face(const ShapeSW *p_a,const Transform &p_transform_a, const ShapeSW *p_b,const Transform& p_transform_b, _CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_sphere_face(const ShapeSW *p_a,const Transform &p_transform_a, const ShapeSW *p_b,const Transform& p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW*>(p_a);
const FaceShapeSW *face_B = static_cast<const FaceShapeSW*>(p_b);
- SeparatorAxisTest<SphereShapeSW,FaceShapeSW> separator(sphere_A,p_transform_a,face_B,p_transform_b,p_collector);
+ SeparatorAxisTest<SphereShapeSW,FaceShapeSW,withMargin> separator(sphere_A,p_transform_a,face_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
Vector3 vertex[3]={
@@ -669,16 +705,14 @@ static void _collision_sphere_face(const ShapeSW *p_a,const Transform &p_transfo
}
-
-
-
-static void _collision_box_box(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_box_box(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const BoxShapeSW *box_A = static_cast<const BoxShapeSW*>(p_a);
const BoxShapeSW *box_B = static_cast<const BoxShapeSW*>(p_b);
- SeparatorAxisTest<BoxShapeSW,BoxShapeSW> separator(box_A,p_transform_a,box_B,p_transform_b,p_collector);
+ SeparatorAxisTest<BoxShapeSW,BoxShapeSW,withMargin> separator(box_A,p_transform_a,box_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
return;
@@ -723,18 +757,69 @@ static void _collision_box_box(const ShapeSW *p_a,const Transform &p_transform_a
}
}
+ if (withMargin) {
+ //add endpoint test between closest vertices and edges
+
+ // calculate closest point to sphere
+
+ Vector3 ab_vec = p_transform_b.origin - p_transform_a.origin;
+
+ Vector3 cnormal_a=p_transform_a.basis.xform_inv( ab_vec );
+
+ Vector3 support_a=p_transform_a.xform( Vector3(
+
+ (cnormal_a.x<0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
+ (cnormal_a.y<0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
+ (cnormal_a.z<0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z
+ ) );
+
+
+ Vector3 cnormal_b=p_transform_b.basis.xform_inv( -ab_vec );
+
+ Vector3 support_b=p_transform_b.xform( Vector3(
+
+ (cnormal_b.x<0) ? -box_B->get_half_extents().x : box_B->get_half_extents().x,
+ (cnormal_b.y<0) ? -box_B->get_half_extents().y : box_B->get_half_extents().y,
+ (cnormal_b.z<0) ? -box_B->get_half_extents().z : box_B->get_half_extents().z
+ ) );
+
+ Vector3 axis_ab = (support_a-support_b);
+
+ if (!separator.test_axis( axis_ab.normalized() )) {
+ return;
+ }
+
+ //now try edges, which become cylinders!
+
+ for(int i=0;i<3;i++) {
+
+ //a ->b
+ Vector3 axis_a = p_transform_a.basis.get_axis(i);
+
+ if (!separator.test_axis( axis_ab.cross(axis_a).cross(axis_a).normalized() ))
+ return;
+
+ //b ->a
+ Vector3 axis_b = p_transform_b.basis.get_axis(i);
+
+ if (!separator.test_axis( axis_ab.cross(axis_b).cross(axis_b).normalized() ))
+ return;
+
+ }
+ }
+
separator.generate_contacts();
}
-
-static void _collision_box_capsule(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_box_capsule(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const BoxShapeSW *box_A = static_cast<const BoxShapeSW*>(p_a);
const CapsuleShapeSW *capsule_B = static_cast<const CapsuleShapeSW*>(p_b);
- SeparatorAxisTest<BoxShapeSW,CapsuleShapeSW> separator(box_A,p_transform_a,capsule_B,p_transform_b,p_collector);
+ SeparatorAxisTest<BoxShapeSW,CapsuleShapeSW,withMargin> separator(box_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
return;
@@ -828,15 +913,15 @@ static void _collision_box_capsule(const ShapeSW *p_a,const Transform &p_transfo
separator.generate_contacts();
}
-
-static void _collision_box_convex_polygon(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_box_convex_polygon(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const BoxShapeSW *box_A = static_cast<const BoxShapeSW*>(p_a);
const ConvexPolygonShapeSW *convex_polygon_B = static_cast<const ConvexPolygonShapeSW*>(p_b);
- SeparatorAxisTest<BoxShapeSW,ConvexPolygonShapeSW> separator(box_A,p_transform_a,convex_polygon_B,p_transform_b,p_collector);
+ SeparatorAxisTest<BoxShapeSW,ConvexPolygonShapeSW,withMargin> separator(box_A,p_transform_a,convex_polygon_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
return;
@@ -886,18 +971,84 @@ static void _collision_box_convex_polygon(const ShapeSW *p_a,const Transform &p_
}
}
+ if (withMargin) {
+
+ // calculate closest points between vertices and box edges
+ for(int v=0;v<vertex_count;v++) {
+
+
+ Vector3 vtxb = p_transform_b.xform(vertices[v]);
+ Vector3 ab_vec = vtxb - p_transform_a.origin;
+
+ Vector3 cnormal_a=p_transform_a.basis.xform_inv( ab_vec );
+
+ Vector3 support_a=p_transform_a.xform( Vector3(
+
+ (cnormal_a.x<0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
+ (cnormal_a.y<0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
+ (cnormal_a.z<0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z
+ ) );
+
+
+ Vector3 axis_ab = support_a-vtxb;
+
+ if (!separator.test_axis( axis_ab.normalized() )) {
+ return;
+ }
+
+ //now try edges, which become cylinders!
+
+ for(int i=0;i<3;i++) {
+
+ //a ->b
+ Vector3 axis_a = p_transform_a.basis.get_axis(i);
+
+ if (!separator.test_axis( axis_ab.cross(axis_a).cross(axis_a).normalized() ))
+ return;
+ }
+ }
+
+ //convex edges and box points
+ for (int i=0;i<2;i++) {
+ for (int j=0;j<2;j++) {
+ for (int k=0;k<2;k++) {
+ Vector3 he = box_A->get_half_extents();
+ he.x*=(i*2-1);
+ he.y*=(j*2-1);
+ he.z*=(k*2-1);
+ Vector3 point=p_transform_a.origin;
+ for(int l=0;l<3;l++)
+ point+=p_transform_a.basis.get_axis(l)*he[l];
+
+ for(int e=0;e<edge_count;e++) {
+
+ Vector3 p1=p_transform_b.xform(vertices[edges[e].a]);
+ Vector3 p2=p_transform_b.xform(vertices[edges[e].b]);
+ Vector3 n = (p2-p1);
+
+
+ if (!separator.test_axis( (point-p2).cross(n).cross(n).normalized() ))
+ return;
+ }
+ }
+ }
+ }
+ }
+
separator.generate_contacts();
}
-static void _collision_box_face(const ShapeSW *p_a,const Transform &p_transform_a, const ShapeSW *p_b,const Transform& p_transform_b, _CollectorCallback *p_collector) {
+
+template<bool withMargin>
+static void _collision_box_face(const ShapeSW *p_a,const Transform &p_transform_a, const ShapeSW *p_b,const Transform& p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const BoxShapeSW *box_A = static_cast<const BoxShapeSW*>(p_a);
const FaceShapeSW *face_B = static_cast<const FaceShapeSW*>(p_b);
- SeparatorAxisTest<BoxShapeSW,FaceShapeSW> separator(box_A,p_transform_a,face_B,p_transform_b,p_collector);
+ SeparatorAxisTest<BoxShapeSW,FaceShapeSW,withMargin> separator(box_A,p_transform_a,face_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
Vector3 vertex[3]={
p_transform_b.xform( face_B->vertex[0] ),
@@ -918,13 +1069,14 @@ static void _collision_box_face(const ShapeSW *p_a,const Transform &p_transform_
}
// combined edges
+
for(int i=0;i<3;i++) {
Vector3 e=vertex[i]-vertex[(i+1)%3];
- for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
- Vector3 axis = p_transform_a.basis.get_axis(i);
+ Vector3 axis = p_transform_a.basis.get_axis(j);
if (!separator.test_axis( e.cross(axis).normalized() ))
return;
@@ -932,16 +1084,82 @@ static void _collision_box_face(const ShapeSW *p_a,const Transform &p_transform_
}
+ if (withMargin) {
+
+ // calculate closest points between vertices and box edges
+ for(int v=0;v<3;v++) {
+
+
+ Vector3 ab_vec = vertex[v] - p_transform_a.origin;
+
+ Vector3 cnormal_a=p_transform_a.basis.xform_inv( ab_vec );
+
+ Vector3 support_a=p_transform_a.xform( Vector3(
+
+ (cnormal_a.x<0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
+ (cnormal_a.y<0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
+ (cnormal_a.z<0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z
+ ) );
+
+
+ Vector3 axis_ab = support_a-vertex[v];
+
+ if (!separator.test_axis( axis_ab.normalized() )) {
+ return;
+ }
+
+ //now try edges, which become cylinders!
+
+ for(int i=0;i<3;i++) {
+
+ //a ->b
+ Vector3 axis_a = p_transform_a.basis.get_axis(i);
+
+ if (!separator.test_axis( axis_ab.cross(axis_a).cross(axis_a).normalized() ))
+ return;
+ }
+ }
+
+ //convex edges and box points, there has to be a way to speed up this (get closest point?)
+ for (int i=0;i<2;i++) {
+ for (int j=0;j<2;j++) {
+ for (int k=0;k<2;k++) {
+ Vector3 he = box_A->get_half_extents();
+ he.x*=(i*2-1);
+ he.y*=(j*2-1);
+ he.z*=(k*2-1);
+ Vector3 point=p_transform_a.origin;
+ for(int l=0;l<3;l++)
+ point+=p_transform_a.basis.get_axis(l)*he[l];
+
+ for(int e=0;e<3;e++) {
+
+ Vector3 p1=vertex[e];
+ Vector3 p2=vertex[(e+1)%3];
+
+ Vector3 n = (p2-p1);
+
+ if (!separator.test_axis( (point-p2).cross(n).cross(n).normalized() ))
+ return;
+ }
+ }
+ }
+ }
+
+ }
+
separator.generate_contacts();
}
-static void _collision_capsule_capsule(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+
+template<bool withMargin>
+static void _collision_capsule_capsule(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW*>(p_a);
const CapsuleShapeSW *capsule_B = static_cast<const CapsuleShapeSW*>(p_b);
- SeparatorAxisTest<CapsuleShapeSW,CapsuleShapeSW> separator(capsule_A,p_transform_a,capsule_B,p_transform_b,p_collector);
+ SeparatorAxisTest<CapsuleShapeSW,CapsuleShapeSW,withMargin> separator(capsule_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
return;
@@ -993,13 +1211,14 @@ static void _collision_capsule_capsule(const ShapeSW *p_a,const Transform &p_tra
}
-static void _collision_capsule_convex_polygon(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_capsule_convex_polygon(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW*>(p_a);
const ConvexPolygonShapeSW *convex_polygon_B = static_cast<const ConvexPolygonShapeSW*>(p_b);
- SeparatorAxisTest<CapsuleShapeSW,ConvexPolygonShapeSW> separator(capsule_A,p_transform_a,convex_polygon_B,p_transform_b,p_collector);
+ SeparatorAxisTest<CapsuleShapeSW,ConvexPolygonShapeSW,withMargin> separator(capsule_A,p_transform_a,convex_polygon_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
return;
@@ -1063,12 +1282,14 @@ static void _collision_capsule_convex_polygon(const ShapeSW *p_a,const Transform
}
-static void _collision_capsule_face(const ShapeSW *p_a,const Transform &p_transform_a, const ShapeSW *p_b,const Transform& p_transform_b, _CollectorCallback *p_collector) {
+
+template<bool withMargin>
+static void _collision_capsule_face(const ShapeSW *p_a,const Transform &p_transform_a, const ShapeSW *p_b,const Transform& p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW*>(p_a);
const FaceShapeSW *face_B = static_cast<const FaceShapeSW*>(p_b);
- SeparatorAxisTest<CapsuleShapeSW,FaceShapeSW> separator(capsule_A,p_transform_a,face_B,p_transform_b,p_collector);
+ SeparatorAxisTest<CapsuleShapeSW,FaceShapeSW,withMargin> separator(capsule_A,p_transform_a,face_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
@@ -1125,13 +1346,14 @@ static void _collision_capsule_face(const ShapeSW *p_a,const Transform &p_transf
}
-static void _collision_convex_polygon_convex_polygon(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector) {
+template<bool withMargin>
+static void _collision_convex_polygon_convex_polygon(const ShapeSW *p_a,const Transform &p_transform_a,const ShapeSW *p_b,const Transform &p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const ConvexPolygonShapeSW *convex_polygon_A = static_cast<const ConvexPolygonShapeSW*>(p_a);
const ConvexPolygonShapeSW *convex_polygon_B = static_cast<const ConvexPolygonShapeSW*>(p_b);
- SeparatorAxisTest<ConvexPolygonShapeSW,ConvexPolygonShapeSW> separator(convex_polygon_A,p_transform_a,convex_polygon_B,p_transform_b,p_collector);
+ SeparatorAxisTest<ConvexPolygonShapeSW,ConvexPolygonShapeSW,withMargin> separator(convex_polygon_A,p_transform_a,convex_polygon_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
if (!separator.test_previous_axis())
return;
@@ -1192,17 +1414,70 @@ static void _collision_convex_polygon_convex_polygon(const ShapeSW *p_a,const Tr
}
}
+ if (withMargin) {
+
+ //vertex-vertex
+ for(int i=0;i<vertex_count_A;i++) {
+
+ Vector3 va = p_transform_a.xform(vertices_A[i]);
+
+ for(int j=0;j<vertex_count_B;j++) {
+
+ if (!separator.test_axis( (va-p_transform_b.xform(vertices_B[j])).normalized() ))
+ return;
+
+ }
+ }
+ //edge-vertex( hsell)
+
+ for (int i=0;i<edge_count_A;i++) {
+
+ Vector3 e1=p_transform_a.basis.xform( vertices_A[ edges_A[i].a] );
+ Vector3 e2=p_transform_a.basis.xform( vertices_A[ edges_A[i].b] );
+ Vector3 n = (e2-e1);
+
+ for(int j=0;j<vertex_count_B;j++) {
+
+ Vector3 e3=p_transform_b.xform(vertices_B[j]);
+
+
+ if (!separator.test_axis( (e1-e3).cross(n).cross(n).normalized() ))
+ return;
+ }
+ }
+
+ for (int i=0;i<edge_count_B;i++) {
+
+ Vector3 e1=p_transform_b.basis.xform( vertices_B[ edges_B[i].a] );
+ Vector3 e2=p_transform_b.basis.xform( vertices_B[ edges_B[i].b] );
+ Vector3 n = (e2-e1);
+
+ for(int j=0;j<vertex_count_A;j++) {
+
+ Vector3 e3=p_transform_a.xform(vertices_A[j]);
+
+
+ if (!separator.test_axis( (e1-e3).cross(n).cross(n).normalized() ))
+ return;
+ }
+ }
+
+
+ }
+
separator.generate_contacts();
}
-static void _collision_convex_polygon_face(const ShapeSW *p_a,const Transform &p_transform_a, const ShapeSW *p_b,const Transform& p_transform_b, _CollectorCallback *p_collector) {
+
+template<bool withMargin>
+static void _collision_convex_polygon_face(const ShapeSW *p_a,const Transform &p_transform_a, const ShapeSW *p_b,const Transform& p_transform_b,_CollectorCallback *p_collector,float p_margin_a,float p_margin_b) {
const ConvexPolygonShapeSW *convex_polygon_A = static_cast<const ConvexPolygonShapeSW*>(p_a);
const FaceShapeSW *face_B = static_cast<const FaceShapeSW*>(p_b);
- SeparatorAxisTest<ConvexPolygonShapeSW,FaceShapeSW> separator(convex_polygon_A,p_transform_a,face_B,p_transform_b,p_collector);
+ SeparatorAxisTest<ConvexPolygonShapeSW,FaceShapeSW,withMargin> separator(convex_polygon_A,p_transform_a,face_B,p_transform_b,p_collector,p_margin_a,p_margin_b);
const Geometry::MeshData &mesh = convex_polygon_A->get_mesh();
@@ -1252,12 +1527,62 @@ static void _collision_convex_polygon_face(const ShapeSW *p_a,const Transform &p
}
}
+
+ if (withMargin) {
+
+ //vertex-vertex
+ for(int i=0;i<vertex_count;i++) {
+
+ Vector3 va = p_transform_a.xform(vertices[i]);
+
+ for(int j=0;j<3;j++) {
+
+ if (!separator.test_axis( (va-vertex[j]).normalized() ))
+ return;
+
+ }
+ }
+ //edge-vertex( hsell)
+
+ for (int i=0;i<edge_count;i++) {
+
+ Vector3 e1=p_transform_a.basis.xform( vertices[ edges[i].a] );
+ Vector3 e2=p_transform_a.basis.xform( vertices[ edges[i].b] );
+ Vector3 n = (e2-e1);
+
+ for(int j=0;j<3;j++) {
+
+ Vector3 e3=vertex[j];
+
+
+ if (!separator.test_axis( (e1-e3).cross(n).cross(n).normalized() ))
+ return;
+ }
+ }
+
+ for (int i=0;i<3;i++) {
+
+ Vector3 e1=vertex[i];
+ Vector3 e2=vertex[(i+1)%3];
+ Vector3 n = (e2-e1);
+
+ for(int j=0;j<vertex_count;j++) {
+
+ Vector3 e3=p_transform_a.xform(vertices[j]);
+
+
+ if (!separator.test_axis( (e1-e3).cross(n).cross(n).normalized() ))
+ return;
+ }
+ }
+ }
+
separator.generate_contacts();
}
-bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform& p_transform_A, const ShapeSW *p_shape_B, const Transform& p_transform_B, CollisionSolverSW::CallbackResult p_result_callback,void *p_userdata,bool p_swap,Vector3* r_prev_axis) {
+bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform& p_transform_A, const ShapeSW *p_shape_B, const Transform& p_transform_B, CollisionSolverSW::CallbackResult p_result_callback,void *p_userdata,bool p_swap,Vector3* r_prev_axis,float p_margin_a,float p_margin_b) {
PhysicsServer::ShapeType type_A=p_shape_A->get_type();
@@ -1273,26 +1598,54 @@ bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform& p_tran
static const CollisionFunc collision_table[5][5]={
- {_collision_sphere_sphere,
- _collision_sphere_box,
- _collision_sphere_capsule,
- _collision_sphere_convex_polygon,
- _collision_sphere_face},
+ {_collision_sphere_sphere<false>,
+ _collision_sphere_box<false>,
+ _collision_sphere_capsule<false>,
+ _collision_sphere_convex_polygon<false>,
+ _collision_sphere_face<false>},
+ {0,
+ _collision_box_box<false>,
+ _collision_box_capsule<false>,
+ _collision_box_convex_polygon<false>,
+ _collision_box_face<false>},
+ {0,
+ 0,
+ _collision_capsule_capsule<false>,
+ _collision_capsule_convex_polygon<false>,
+ _collision_capsule_face<false>},
+ {0,
+ 0,
+ 0,
+ _collision_convex_polygon_convex_polygon<false>,
+ _collision_convex_polygon_face<false>},
{0,
- _collision_box_box,
- _collision_box_capsule,
- _collision_box_convex_polygon,
- _collision_box_face},
+ 0,
+ 0,
+ 0,
+ 0},
+ };
+
+ static const CollisionFunc collision_table_margin[5][5]={
+ {_collision_sphere_sphere<true>,
+ _collision_sphere_box<true>,
+ _collision_sphere_capsule<true>,
+ _collision_sphere_convex_polygon<true>,
+ _collision_sphere_face<true>},
+ {0,
+ _collision_box_box<true>,
+ _collision_box_capsule<true>,
+ _collision_box_convex_polygon<true>,
+ _collision_box_face<true>},
{0,
0,
- _collision_capsule_capsule,
- _collision_capsule_convex_polygon,
- _collision_capsule_face},
+ _collision_capsule_capsule<true>,
+ _collision_capsule_convex_polygon<true>,
+ _collision_capsule_face<true>},
{0,
0,
0,
- _collision_convex_polygon_convex_polygon,
- _collision_convex_polygon_face},
+ _collision_convex_polygon_convex_polygon<true>,
+ _collision_convex_polygon_face<true>},
{0,
0,
0,
@@ -1311,20 +1664,30 @@ bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform& p_tran
const ShapeSW *B=p_shape_B;
const Transform *transform_A=&p_transform_A;
const Transform *transform_B=&p_transform_B;
+ float margin_A=p_margin_a;
+ float margin_B=p_margin_b;
if (type_A > type_B) {
SWAP(A,B);
SWAP(transform_A,transform_B);
SWAP(type_A,type_B);
+ SWAP(margin_A,margin_B);
callback.swap = !callback.swap;
}
- CollisionFunc collision_func = collision_table[type_A-2][type_B-2];
+ CollisionFunc collision_func;
+ if (margin_A!=0.0 || margin_B!=0.0) {
+ collision_func = collision_table_margin[type_A-2][type_B-2];
+
+ } else {
+ collision_func = collision_table[type_A-2][type_B-2];
+
+ }
ERR_FAIL_COND_V(!collision_func,false);
- collision_func(A,*transform_A,B,*transform_B,&callback);
+ collision_func(A,*transform_A,B,*transform_B,&callback,margin_A,margin_B);
return callback.collided;
diff --git a/servers/physics/collision_solver_sat.h b/servers/physics/collision_solver_sat.h
index 5023a17810..686b587243 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,6 +32,6 @@
#include "collision_solver_sw.h"
-bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform& p_transform_A, const ShapeSW *p_shape_B, const Transform& p_transform_B, CollisionSolverSW::CallbackResult p_result_callback,void *p_userdata, bool p_swap=false,Vector3* r_prev_axis=NULL);
+bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform& p_transform_A, const ShapeSW *p_shape_B, const Transform& p_transform_B, CollisionSolverSW::CallbackResult p_result_callback,void *p_userdata, bool p_swap=false,Vector3* r_prev_axis=NULL,float p_margin_a=0,float p_margin_b=0);
#endif // COLLISION_SOLVER_SAT_H
diff --git a/servers/physics/collision_solver_sw.cpp b/servers/physics/collision_solver_sw.cpp
index da28a4934f..b5a5c64660 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -114,6 +114,10 @@ struct _ConcaveCollisionInfo {
bool collided;
int aabb_tests;
int collisions;
+ bool tested;
+ float margin_A;
+ float margin_B;
+ Vector3 close_A,close_B;
};
@@ -123,7 +127,7 @@ void CollisionSolverSW::concave_callback(void *p_userdata, ShapeSW *p_convex) {
_ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo*)(p_userdata);
cinfo.aabb_tests++;
- bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, p_convex,*cinfo.transform_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result );
+ bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, p_convex,*cinfo.transform_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result,NULL,cinfo.margin_A,cinfo.margin_B);
if (!collided)
return;
@@ -132,7 +136,7 @@ void CollisionSolverSW::concave_callback(void *p_userdata, ShapeSW *p_convex) {
}
-bool CollisionSolverSW::solve_concave(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result) {
+bool CollisionSolverSW::solve_concave(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result,float p_margin_A,float p_margin_B) {
const ConcaveShapeSW *concave_B=static_cast<const ConcaveShapeSW*>(p_shape_B);
@@ -146,6 +150,8 @@ bool CollisionSolverSW::solve_concave(const ShapeSW *p_shape_A,const Transform&
cinfo.swap_result=p_swap_result;
cinfo.collided=false;
cinfo.collisions=0;
+ cinfo.margin_A=p_margin_A;
+ cinfo.margin_B=p_margin_B;
cinfo.aabb_tests=0;
@@ -163,21 +169,24 @@ bool CollisionSolverSW::solve_concave(const ShapeSW *p_shape_A,const Transform&
float smin,smax;
p_shape_A->project_range(axis,rel_transform,smin,smax);
+ smin-=p_margin_A;
+ smax+=p_margin_A;
smin*=axis_scale;
smax*=axis_scale;
+
local_aabb.pos[i]=smin;
local_aabb.size[i]=smax-smin;
}
concave_B->cull(local_aabb,concave_callback,&cinfo);
-
+ //print_line("COL AABB TESTS: "+itos(cinfo.aabb_tests));
return cinfo.collided;
}
-bool CollisionSolverSW::solve_static(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,Vector3 *r_sep_axis) {
+bool CollisionSolverSW::solve_static(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,Vector3 *r_sep_axis,float p_margin_A,float p_margin_B) {
PhysicsServer::ShapeType type_A=p_shape_A->get_type();
@@ -225,17 +234,170 @@ bool CollisionSolverSW::solve_static(const ShapeSW *p_shape_A,const Transform& p
return false;
if (!swap)
- return solve_concave(p_shape_A,p_transform_A,p_shape_B,p_transform_B,p_result_callback,p_userdata,false);
+ return solve_concave(p_shape_A,p_transform_A,p_shape_B,p_transform_B,p_result_callback,p_userdata,false,p_margin_A,p_margin_B);
else
- return solve_concave(p_shape_B,p_transform_B,p_shape_A,p_transform_A,p_result_callback,p_userdata,true);
+ return solve_concave(p_shape_B,p_transform_B,p_shape_A,p_transform_A,p_result_callback,p_userdata,true,p_margin_A,p_margin_B);
+
+
+
+ } else {
+
+ return collision_solver(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback,p_userdata,false,r_sep_axis,p_margin_A,p_margin_B);
+ }
+
+
+ return false;
+}
+
+
+void CollisionSolverSW::concave_distance_callback(void *p_userdata, ShapeSW *p_convex) {
+
+
+ _ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo*)(p_userdata);
+ cinfo.aabb_tests++;
+ if (cinfo.collided)
+ return;
+
+ Vector3 close_A,close_B;
+ cinfo.collided = !gjk_epa_calculate_distance(cinfo.shape_A,*cinfo.transform_A,p_convex,*cinfo.transform_B,close_A,close_B);
+
+ if (cinfo.collided)
+ return;
+ if (!cinfo.tested || close_A.distance_squared_to(close_B) < cinfo.close_A.distance_squared_to(cinfo.close_B)) {
+
+ cinfo.close_A=close_A;
+ cinfo.close_B=close_B;
+ cinfo.tested=true;
+ }
+
+ cinfo.collisions++;
+
+}
+
+
+
+bool CollisionSolverSW::solve_distance_plane(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,Vector3& r_point_A,Vector3& r_point_B) {
+
+ const PlaneShapeSW *plane = static_cast<const PlaneShapeSW*>(p_shape_A);
+ if (p_shape_B->get_type()==PhysicsServer::SHAPE_PLANE)
+ return false;
+ Plane p = p_transform_A.xform(plane->get_plane());
+
+ static const int max_supports = 16;
+ Vector3 supports[max_supports];
+ int support_count;
+ p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(),max_supports,supports,support_count);
+
+ bool collided=false;
+ Vector3 closest;
+ float closest_d;
+
+
+ for(int i=0;i<support_count;i++) {
+
+ supports[i] = p_transform_B.xform( supports[i] );
+ real_t d = p.distance_to(supports[i]);
+ if (i==0 || d<closest_d) {
+ closest=supports[i];
+ closest_d=d;
+ if (d<=0)
+ collided=true;
+ }
+
+ }
+
+ r_point_A=p.project(closest);
+ r_point_B=closest;
+
+ return collided;
+}
+
+bool CollisionSolverSW::solve_distance(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,Vector3& r_point_A,Vector3& r_point_B,const AABB& p_concave_hint,Vector3 *r_sep_axis) {
+
+ if (p_shape_A->is_concave())
+ return false;
+
+ if (p_shape_B->get_type()==PhysicsServer::SHAPE_PLANE) {
+
+ Vector3 a,b;
+ bool col = solve_distance_plane(p_shape_B,p_transform_B,p_shape_A,p_transform_A,a,b);
+ r_point_A=b;
+ r_point_B=a;
+ return !col;
+
+ } else if (p_shape_B->is_concave()) {
+
+ if (p_shape_A->is_concave())
+ return false;
+
+
+ const ConcaveShapeSW *concave_B=static_cast<const ConcaveShapeSW*>(p_shape_B);
+
+ _ConcaveCollisionInfo cinfo;
+ cinfo.transform_A=&p_transform_A;
+ cinfo.shape_A=p_shape_A;
+ cinfo.transform_B=&p_transform_B;
+ cinfo.result_callback=NULL;
+ cinfo.userdata=NULL;
+ cinfo.swap_result=false;
+ cinfo.collided=false;
+ cinfo.collisions=0;
+ cinfo.aabb_tests=0;
+ cinfo.tested=false;
+
+ Transform rel_transform = p_transform_A;
+ rel_transform.origin-=p_transform_B.origin;
+
+ //quickly compute a local AABB
+
+ bool use_cc_hint=p_concave_hint!=AABB();
+ AABB cc_hint_aabb;
+ if (use_cc_hint) {
+ cc_hint_aabb=p_concave_hint;
+ cc_hint_aabb.pos-=p_transform_B.origin;
+ }
+
+ AABB local_aabb;
+ for(int i=0;i<3;i++) {
+
+ Vector3 axis( p_transform_B.basis.get_axis(i) );
+ float axis_scale = 1.0/axis.length();
+ axis*=axis_scale;
+ float smin,smax;
+ if (use_cc_hint) {
+ cc_hint_aabb.project_range_in_plane(Plane(axis,0),smin,smax);
+ } else {
+ p_shape_A->project_range(axis,rel_transform,smin,smax);
+ }
+
+ smin*=axis_scale;
+ smax*=axis_scale;
+
+ local_aabb.pos[i]=smin;
+ local_aabb.size[i]=smax-smin;
+ }
+
+
+ concave_B->cull(local_aabb,concave_distance_callback,&cinfo);
+ if (!cinfo.collided) {
+// print_line(itos(cinfo.tested));
+ r_point_A=cinfo.close_A;
+ r_point_B=cinfo.close_B;
+
+ }
+
+ //print_line("DIST AABB TESTS: "+itos(cinfo.aabb_tests));
+
+ return !cinfo.collided;
} else {
- return collision_solver(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback,p_userdata,false,r_sep_axis);
+ return gjk_epa_calculate_distance(p_shape_A,p_transform_A,p_shape_B,p_transform_B,r_point_A,r_point_B); //should pass sepaxis..
}
return false;
}
+
diff --git a/servers/physics/collision_solver_sw.h b/servers/physics/collision_solver_sw.h
index e135ab92e0..5ed5260b7d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,12 +40,15 @@ private:
static void concave_callback(void *p_userdata, ShapeSW *p_convex);
static bool solve_static_plane(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result);
static bool solve_ray(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result);
- static bool solve_concave(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result);
+ static bool solve_concave(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result,float p_margin_A=0,float p_margin_B=0);
+ static void concave_distance_callback(void *p_userdata, ShapeSW *p_convex);
+ static bool solve_distance_plane(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,Vector3& r_point_A,Vector3& r_point_B);
public:
- static bool solve_static(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,Vector3 *r_sep_axis=NULL);
+ static bool solve_static(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,Vector3 *r_sep_axis=NULL,float p_margin_A=0,float p_margin_B=0);
+ static bool solve_distance(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,Vector3& r_point_A,Vector3& r_point_B,const AABB& p_concave_hint,Vector3 *r_sep_axis=NULL);
};
diff --git a/servers/physics/constraint_sw.cpp b/servers/physics/constraint_sw.cpp
index f1179bdb5c..fb45485233 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics/constraint_sw.h b/servers/physics/constraint_sw.h
index 1be96422e1..1ec237f9c5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,12 +38,13 @@ class ConstraintSW {
uint64_t island_step;
ConstraintSW *island_next;
ConstraintSW *island_list_next;
+ int priority;
RID self;
protected:
- ConstraintSW(BodySW **p_body_ptr=NULL,int p_body_count=0) { _body_ptr=p_body_ptr; _body_count=p_body_count; island_step=0; }
+ ConstraintSW(BodySW **p_body_ptr=NULL,int p_body_count=0) { _body_ptr=p_body_ptr; _body_count=p_body_count; island_step=0; priority=1; }
public:
_FORCE_INLINE_ void set_self(const RID& p_self) { self=p_self; }
@@ -62,6 +63,9 @@ public:
_FORCE_INLINE_ BodySW **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
+ _FORCE_INLINE_ void set_priority(int p_priority) { priority=p_priority; }
+ _FORCE_INLINE_ int get_priority() const { return priority; }
+
virtual bool setup(float p_step)=0;
virtual void solve(float p_step)=0;
diff --git a/servers/physics/gjk_epa.cpp b/servers/physics/gjk_epa.cpp
index 37edc0d414..9b5b3d4f67 100644
--- a/servers/physics/gjk_epa.cpp
+++ b/servers/physics/gjk_epa.cpp
@@ -1,31 +1,14 @@
-/*************************************************************************/
-/* gjk_epa.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/*************************************************/
+/* gjk_epa.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 "gjk_epa.h"
/*************** Bullet's GJK-EPA2 IMPLEMENTATION *******************/
@@ -798,8 +781,8 @@ bool Distance( const ShapeSW* shape0,
w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
}
- results.witnesses[0] = wtrs0.xform(w0);
- results.witnesses[1] = wtrs0.xform(w1);
+ results.witnesses[0] = w0;
+ results.witnesses[1] = w1;
results.normal = w0-w1;
results.distance = results.normal.length();
results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1;
@@ -881,6 +864,24 @@ bool Penetration( const ShapeSW* shape0,
+
+
+bool gjk_epa_calculate_distance(const ShapeSW *p_shape_A, const Transform& p_transform_A, const ShapeSW *p_shape_B, const Transform& p_transform_B, Vector3& r_result_A, Vector3& r_result_B) {
+
+
+ GjkEpa2::sResults res;
+
+ if (GjkEpa2::Distance(p_shape_A,p_transform_A,p_shape_B,p_transform_B,p_transform_B.origin-p_transform_A.origin,res)) {
+
+ r_result_A=res.witnesses[0];
+ r_result_B=res.witnesses[1];
+ return true;
+ }
+
+ return false;
+
+}
+
bool gjk_epa_calculate_penetration(const ShapeSW *p_shape_A, const Transform& p_transform_A, const ShapeSW *p_shape_B, const Transform& p_transform_B, CollisionSolverSW::CallbackResult p_result_callback,void *p_userdata, bool p_swap ) {
GjkEpa2::sResults res;
diff --git a/servers/physics/gjk_epa.h b/servers/physics/gjk_epa.h
index 0303478f17..08b0a65b15 100644
--- a/servers/physics/gjk_epa.h
+++ b/servers/physics/gjk_epa.h
@@ -1,31 +1,14 @@
-/*************************************************************************/
-/* gjk_epa.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/*************************************************/
+/* gjk_epa.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 GJK_EPA_H
#define GJK_EPA_H
@@ -36,5 +19,6 @@
#include "collision_solver_sw.h"
bool gjk_epa_calculate_penetration(const ShapeSW *p_shape_A, const Transform& p_transform_A, const ShapeSW *p_shape_B, const Transform& p_transform_B, CollisionSolverSW::CallbackResult p_result_callback,void *p_userdata, bool p_swap=false);
+bool gjk_epa_calculate_distance(const ShapeSW *p_shape_A, const Transform& p_transform_A, const ShapeSW *p_shape_B, const Transform& p_transform_B, Vector3& r_result_A, Vector3& r_result_B);
#endif
diff --git a/servers/physics/joints/SCsub b/servers/physics/joints/SCsub
new file mode 100644
index 0000000000..d31af2c1c4
--- /dev/null
+++ b/servers/physics/joints/SCsub
@@ -0,0 +1,5 @@
+Import('env')
+
+env.add_source_files(env.servers_sources,"*.cpp")
+
+Export('env')
diff --git a/servers/physics/joints/cone_twist_joint_sw.cpp b/servers/physics/joints/cone_twist_joint_sw.cpp
new file mode 100644
index 0000000000..d97d8c599f
--- /dev/null
+++ b/servers/physics/joints/cone_twist_joint_sw.cpp
@@ -0,0 +1,340 @@
+#include "cone_twist_joint_sw.h"
+
+static void plane_space(const Vector3& n, Vector3& p, Vector3& q) {
+
+ if (Math::abs(n.z) > 0.707106781186547524400844362) {
+ // choose p in y-z plane
+ real_t a = n[1]*n[1] + n[2]*n[2];
+ real_t k = 1.0/Math::sqrt(a);
+ p=Vector3(0,-n[2]*k,n[1]*k);
+ // set q = n x p
+ q=Vector3(a*k,-n[0]*p[2],n[0]*p[1]);
+ }
+ else {
+ // choose p in x-y plane
+ real_t a = n.x*n.x + n.y*n.y;
+ real_t k = 1.0/Math::sqrt(a);
+ p=Vector3(-n.y*k,n.x*k,0);
+ // set q = n x p
+ q=Vector3(-n.z*p.y,n.z*p.x,a*k);
+ }
+}
+
+
+static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x)
+{
+ real_t coeff_1 = Math_PI / 4.0f;
+ real_t coeff_2 = 3.0f * coeff_1;
+ real_t abs_y = Math::abs(y);
+ real_t angle;
+ if (x >= 0.0f) {
+ real_t r = (x - abs_y) / (x + abs_y);
+ angle = coeff_1 - coeff_1 * r;
+ } else {
+ real_t r = (x + abs_y) / (abs_y - x);
+ angle = coeff_2 - coeff_1 * r;
+ }
+ return (y < 0.0f) ? -angle : angle;
+}
+
+ConeTwistJointSW::ConeTwistJointSW(BodySW* rbA,BodySW* rbB,const Transform& rbAFrame, const Transform& rbBFrame) : JointSW(_arr,2) {
+
+ A=rbA;
+ B=rbB;
+
+
+ m_rbAFrame=rbAFrame;
+ m_rbBFrame=rbBFrame;
+
+ m_swingSpan1 = Math_PI/4.0;
+ m_swingSpan2 = Math_PI/4.0;
+ m_twistSpan = Math_PI*2;
+ m_biasFactor = 0.3f;
+ m_relaxationFactor = 1.0f;
+
+ m_solveTwistLimit = false;
+ m_solveSwingLimit = false;
+
+ A->add_constraint(this,0);
+ B->add_constraint(this,1);
+
+ m_appliedImpulse=0;
+}
+
+
+bool ConeTwistJointSW::setup(float p_step) {
+ m_appliedImpulse = real_t(0.);
+
+ //set bias, sign, clear accumulator
+ m_swingCorrection = real_t(0.);
+ m_twistLimitSign = real_t(0.);
+ m_solveTwistLimit = false;
+ m_solveSwingLimit = false;
+ m_accTwistLimitImpulse = real_t(0.);
+ m_accSwingLimitImpulse = real_t(0.);
+
+ if (!m_angularOnly)
+ {
+ Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
+ Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
+ Vector3 relPos = pivotBInW - pivotAInW;
+
+ Vector3 normal[3];
+ if (relPos.length_squared() > CMP_EPSILON)
+ {
+ normal[0] = relPos.normalized();
+ }
+ else
+ {
+ normal[0]=Vector3(real_t(1.0),0,0);
+ }
+
+ plane_space(normal[0], normal[1], normal[2]);
+
+ for (int i=0;i<3;i++)
+ {
+ memnew_placement(&m_jac[i], JacobianEntrySW(
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ pivotAInW - A->get_transform().origin,
+ pivotBInW - B->get_transform().origin,
+ normal[i],
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()));
+ }
+ }
+
+ Vector3 b1Axis1,b1Axis2,b1Axis3;
+ Vector3 b2Axis1,b2Axis2;
+
+ b1Axis1 = A->get_transform().basis.xform( this->m_rbAFrame.basis.get_axis(0) );
+ b2Axis1 = B->get_transform().basis.xform( this->m_rbBFrame.basis.get_axis(0) );
+
+ real_t swing1=real_t(0.),swing2 = real_t(0.);
+
+ real_t swx=real_t(0.),swy = real_t(0.);
+ real_t thresh = real_t(10.);
+ real_t fact;
+
+ // Get Frame into world space
+ if (m_swingSpan1 >= real_t(0.05f))
+ {
+ b1Axis2 = A->get_transform().basis.xform( this->m_rbAFrame.basis.get_axis(1) );
+// swing1 = btAtan2Fast( b2Axis1.dot(b1Axis2),b2Axis1.dot(b1Axis1) );
+ swx = b2Axis1.dot(b1Axis1);
+ swy = b2Axis1.dot(b1Axis2);
+ swing1 = atan2fast(swy, swx);
+ fact = (swy*swy + swx*swx) * thresh * thresh;
+ fact = fact / (fact + real_t(1.0));
+ swing1 *= fact;
+
+ }
+
+ if (m_swingSpan2 >= real_t(0.05f))
+ {
+ b1Axis3 = A->get_transform().basis.xform( this->m_rbAFrame.basis.get_axis(2) );
+// swing2 = btAtan2Fast( b2Axis1.dot(b1Axis3),b2Axis1.dot(b1Axis1) );
+ swx = b2Axis1.dot(b1Axis1);
+ swy = b2Axis1.dot(b1Axis3);
+ swing2 = atan2fast(swy, swx);
+ fact = (swy*swy + swx*swx) * thresh * thresh;
+ fact = fact / (fact + real_t(1.0));
+ swing2 *= fact;
+ }
+
+ real_t RMaxAngle1Sq = 1.0f / (m_swingSpan1*m_swingSpan1);
+ real_t RMaxAngle2Sq = 1.0f / (m_swingSpan2*m_swingSpan2);
+ real_t EllipseAngle = Math::abs(swing1*swing1)* RMaxAngle1Sq + Math::abs(swing2*swing2) * RMaxAngle2Sq;
+
+ if (EllipseAngle > 1.0f)
+ {
+ m_swingCorrection = EllipseAngle-1.0f;
+ m_solveSwingLimit = true;
+
+ // Calculate necessary axis & factors
+ m_swingAxis = b2Axis1.cross(b1Axis2* b2Axis1.dot(b1Axis2) + b1Axis3* b2Axis1.dot(b1Axis3));
+ m_swingAxis.normalize();
+
+ real_t swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f;
+ m_swingAxis *= swingAxisSign;
+
+ m_kSwing = real_t(1.) / (A->compute_angular_impulse_denominator(m_swingAxis) +
+ B->compute_angular_impulse_denominator(m_swingAxis));
+
+ }
+
+ // Twist limits
+ if (m_twistSpan >= real_t(0.))
+ {
+ Vector3 b2Axis2 = B->get_transform().basis.xform( this->m_rbBFrame.basis.get_axis(1) );
+ Quat rotationArc = Quat(b2Axis1,b1Axis1);
+ Vector3 TwistRef = rotationArc.xform(b2Axis2);
+ real_t twist = atan2fast( TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2) );
+
+ real_t lockedFreeFactor = (m_twistSpan > real_t(0.05f)) ? m_limitSoftness : real_t(0.);
+ if (twist <= -m_twistSpan*lockedFreeFactor)
+ {
+ m_twistCorrection = -(twist + m_twistSpan);
+ m_solveTwistLimit = true;
+
+ m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
+ m_twistAxis.normalize();
+ m_twistAxis *= -1.0f;
+
+ m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) +
+ B->compute_angular_impulse_denominator(m_twistAxis));
+
+ } else
+ if (twist > m_twistSpan*lockedFreeFactor)
+ {
+ m_twistCorrection = (twist - m_twistSpan);
+ m_solveTwistLimit = true;
+
+ m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
+ m_twistAxis.normalize();
+
+ m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) +
+ B->compute_angular_impulse_denominator(m_twistAxis));
+
+ }
+ }
+
+ return true;
+}
+
+void ConeTwistJointSW::solve(real_t timeStep)
+{
+
+ Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
+ Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
+
+ real_t tau = real_t(0.3);
+
+ //linear part
+ if (!m_angularOnly)
+ {
+ Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
+ Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
+
+ Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
+ Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
+ Vector3 vel = vel1 - vel2;
+
+ for (int i=0;i<3;i++)
+ {
+ const Vector3& normal = m_jac[i].m_linearJointAxis;
+ real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
+
+ real_t rel_vel;
+ rel_vel = normal.dot(vel);
+ //positional error (zeroth order error)
+ real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
+ real_t impulse = depth*tau/timeStep * jacDiagABInv - rel_vel * jacDiagABInv;
+ m_appliedImpulse += impulse;
+ Vector3 impulse_vector = normal * impulse;
+ A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
+ B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
+ }
+ }
+
+ {
+ ///solve angular part
+ const Vector3& angVelA = A->get_angular_velocity();
+ const Vector3& angVelB = B->get_angular_velocity();
+
+ // solve swing limit
+ if (m_solveSwingLimit)
+ {
+ real_t amplitude = ((angVelB - angVelA).dot( m_swingAxis )*m_relaxationFactor*m_relaxationFactor + m_swingCorrection*(real_t(1.)/timeStep)*m_biasFactor);
+ real_t impulseMag = amplitude * m_kSwing;
+
+ // Clamp the accumulated impulse
+ real_t temp = m_accSwingLimitImpulse;
+ m_accSwingLimitImpulse = MAX(m_accSwingLimitImpulse + impulseMag, real_t(0.0) );
+ impulseMag = m_accSwingLimitImpulse - temp;
+
+ Vector3 impulse = m_swingAxis * impulseMag;
+
+ A->apply_torque_impulse(impulse);
+ B->apply_torque_impulse(-impulse);
+
+ }
+
+ // solve twist limit
+ if (m_solveTwistLimit)
+ {
+ real_t amplitude = ((angVelB - angVelA).dot( m_twistAxis )*m_relaxationFactor*m_relaxationFactor + m_twistCorrection*(real_t(1.)/timeStep)*m_biasFactor );
+ real_t impulseMag = amplitude * m_kTwist;
+
+ // Clamp the accumulated impulse
+ real_t temp = m_accTwistLimitImpulse;
+ m_accTwistLimitImpulse = MAX(m_accTwistLimitImpulse + impulseMag, real_t(0.0) );
+ impulseMag = m_accTwistLimitImpulse - temp;
+
+ Vector3 impulse = m_twistAxis * impulseMag;
+
+ A->apply_torque_impulse(impulse);
+ B->apply_torque_impulse(-impulse);
+
+ }
+
+ }
+
+}
+
+void ConeTwistJointSW::set_param(PhysicsServer::ConeTwistJointParam p_param, float p_value) {
+
+ switch(p_param) {
+ case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: {
+
+ m_swingSpan1=p_value;
+ m_swingSpan2=p_value;
+ } break;
+ case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN: {
+
+ m_twistSpan=p_value;
+ } break;
+ case PhysicsServer::CONE_TWIST_JOINT_BIAS: {
+
+ m_biasFactor=p_value;
+ } break;
+ case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS: {
+
+ m_limitSoftness=p_value;
+ } break;
+ case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: {
+
+ m_relaxationFactor=p_value;
+ } break;
+ }
+}
+
+float ConeTwistJointSW::get_param(PhysicsServer::ConeTwistJointParam p_param) const{
+
+ switch(p_param) {
+ case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: {
+
+ return m_swingSpan1;
+ } break;
+ case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN: {
+
+ return m_twistSpan;
+ } break;
+ case PhysicsServer::CONE_TWIST_JOINT_BIAS: {
+
+ return m_biasFactor;
+ } break;
+ case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS: {
+
+ return m_limitSoftness;
+ } break;
+ case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: {
+
+ return m_relaxationFactor;
+ } break;
+ }
+
+ return 0;
+}
diff --git a/servers/physics/joints/cone_twist_joint_sw.h b/servers/physics/joints/cone_twist_joint_sw.h
new file mode 100644
index 0000000000..63502d2036
--- /dev/null
+++ b/servers/physics/joints/cone_twist_joint_sw.h
@@ -0,0 +1,125 @@
+#ifndef CONE_TWIST_JOINT_SW_H
+#define CONE_TWIST_JOINT_SW_H
+
+#include "servers/physics/joints_sw.h"
+#include "servers/physics/joints/jacobian_entry_sw.h"
+
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+ConeTwistJointSW is Copyright (c) 2007 Starbreeze Studios
+
+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.
+
+Written by: Marcus Hennix
+*/
+
+
+
+///ConeTwistJointSW can be used to simulate ragdoll joints (upper arm, leg etc)
+class ConeTwistJointSW : public JointSW
+{
+#ifdef IN_PARALLELL_SOLVER
+public:
+#endif
+
+ union {
+ struct {
+ BodySW *A;
+ BodySW *B;
+ };
+
+ BodySW *_arr[2];
+ };
+
+ JacobianEntrySW m_jac[3]; //3 orthogonal linear constraints
+
+
+ real_t m_appliedImpulse;
+ Transform m_rbAFrame;
+ Transform m_rbBFrame;
+
+ real_t m_limitSoftness;
+ real_t m_biasFactor;
+ real_t m_relaxationFactor;
+
+ real_t m_swingSpan1;
+ real_t m_swingSpan2;
+ real_t m_twistSpan;
+
+ Vector3 m_swingAxis;
+ Vector3 m_twistAxis;
+
+ real_t m_kSwing;
+ real_t m_kTwist;
+
+ real_t m_twistLimitSign;
+ real_t m_swingCorrection;
+ real_t m_twistCorrection;
+
+ real_t m_accSwingLimitImpulse;
+ real_t m_accTwistLimitImpulse;
+
+ bool m_angularOnly;
+ bool m_solveTwistLimit;
+ bool m_solveSwingLimit;
+
+
+public:
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_CONE_TWIST; }
+
+ virtual bool setup(float p_step);
+ virtual void solve(float p_step);
+
+ ConeTwistJointSW(BodySW* rbA,BodySW* rbB,const Transform& rbAFrame, const Transform& rbBFrame);
+
+
+ void setAngularOnly(bool angularOnly)
+ {
+ m_angularOnly = angularOnly;
+ }
+
+ void setLimit(real_t _swingSpan1,real_t _swingSpan2,real_t _twistSpan, real_t _softness = 0.8f, real_t _biasFactor = 0.3f, real_t _relaxationFactor = 1.0f)
+ {
+ m_swingSpan1 = _swingSpan1;
+ m_swingSpan2 = _swingSpan2;
+ m_twistSpan = _twistSpan;
+
+ m_limitSoftness = _softness;
+ m_biasFactor = _biasFactor;
+ m_relaxationFactor = _relaxationFactor;
+ }
+
+ inline int getSolveTwistLimit()
+ {
+ return m_solveTwistLimit;
+ }
+
+ inline int getSolveSwingLimit()
+ {
+ return m_solveTwistLimit;
+ }
+
+ inline real_t getTwistLimitSign()
+ {
+ return m_twistLimitSign;
+ }
+
+ void set_param(PhysicsServer::ConeTwistJointParam p_param, float p_value);
+ float get_param(PhysicsServer::ConeTwistJointParam p_param) const;
+
+
+};
+
+
+
+#endif // CONE_TWIST_JOINT_SW_H
diff --git a/servers/physics/joints/generic_6dof_joint_sw.cpp b/servers/physics/joints/generic_6dof_joint_sw.cpp
new file mode 100644
index 0000000000..decc379461
--- /dev/null
+++ b/servers/physics/joints/generic_6dof_joint_sw.cpp
@@ -0,0 +1,691 @@
+#include "generic_6dof_joint_sw.h"
+
+
+
+#define GENERIC_D6_DISABLE_WARMSTARTING 1
+
+real_t btGetMatrixElem(const Matrix3& mat, int index);
+real_t btGetMatrixElem(const Matrix3& mat, int index)
+{
+ int i = index%3;
+ int j = index/3;
+ return mat[i][j];
+}
+
+///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
+bool matrixToEulerXYZ(const Matrix3& mat,Vector3& xyz);
+bool matrixToEulerXYZ(const Matrix3& mat,Vector3& xyz)
+{
+// // rot = cy*cz -cy*sz sy
+// // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
+// // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
+//
+
+ if (btGetMatrixElem(mat,2) < real_t(1.0))
+ {
+ if (btGetMatrixElem(mat,2) > real_t(-1.0))
+ {
+ xyz[0] = Math::atan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
+ xyz[1] = Math::asin(btGetMatrixElem(mat,2));
+ xyz[2] = Math::atan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
+ return true;
+ }
+ else
+ {
+ // WARNING. Not unique. XA - ZA = -atan2(r10,r11)
+ xyz[0] = -Math::atan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
+ xyz[1] = -Math_PI*0.5;
+ xyz[2] = real_t(0.0);
+ return false;
+ }
+ }
+ else
+ {
+ // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
+ xyz[0] = Math::atan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
+ xyz[1] = Math_PI*0.5;
+ xyz[2] = 0.0;
+
+ }
+
+
+ return false;
+}
+
+
+
+//////////////////////////// G6DOFRotationalLimitMotorSW ////////////////////////////////////
+
+
+int G6DOFRotationalLimitMotorSW::testLimitValue(real_t test_value)
+{
+ if(m_loLimit>m_hiLimit)
+ {
+ m_currentLimit = 0;//Free from violation
+ return 0;
+ }
+
+ if (test_value < m_loLimit)
+ {
+ m_currentLimit = 1;//low limit violation
+ m_currentLimitError = test_value - m_loLimit;
+ return 1;
+ }
+ else if (test_value> m_hiLimit)
+ {
+ m_currentLimit = 2;//High limit violation
+ m_currentLimitError = test_value - m_hiLimit;
+ return 2;
+ };
+
+ m_currentLimit = 0;//Free from violation
+ return 0;
+
+}
+
+
+real_t G6DOFRotationalLimitMotorSW::solveAngularLimits(
+ real_t timeStep,Vector3& axis,real_t jacDiagABInv,
+ BodySW * body0, BodySW * body1)
+{
+ if (needApplyTorques()==false) return 0.0f;
+
+ real_t target_velocity = m_targetVelocity;
+ real_t maxMotorForce = m_maxMotorForce;
+
+ //current error correction
+ if (m_currentLimit!=0)
+ {
+ target_velocity = -m_ERP*m_currentLimitError/(timeStep);
+ maxMotorForce = m_maxLimitForce;
+ }
+
+ maxMotorForce *= timeStep;
+
+ // current velocity difference
+ Vector3 vel_diff = body0->get_angular_velocity();
+ if (body1)
+ {
+ vel_diff -= body1->get_angular_velocity();
+ }
+
+
+
+ real_t rel_vel = axis.dot(vel_diff);
+
+ // correction velocity
+ real_t motor_relvel = m_limitSoftness*(target_velocity - m_damping*rel_vel);
+
+
+ if ( motor_relvel < CMP_EPSILON && motor_relvel > -CMP_EPSILON )
+ {
+ return 0.0f;//no need for applying force
+ }
+
+
+ // correction impulse
+ real_t unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv;
+
+ // clip correction impulse
+ real_t clippedMotorImpulse;
+
+ ///@todo: should clip against accumulated impulse
+ if (unclippedMotorImpulse>0.0f)
+ {
+ clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse;
+ }
+ else
+ {
+ clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse;
+ }
+
+
+ // sort with accumulated impulses
+ real_t lo = real_t(-1e30);
+ real_t hi = real_t(1e30);
+
+ real_t oldaccumImpulse = m_accumulatedImpulse;
+ real_t sum = oldaccumImpulse + clippedMotorImpulse;
+ m_accumulatedImpulse = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum;
+
+ clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
+
+
+
+ Vector3 motorImp = clippedMotorImpulse * axis;
+
+
+ body0->apply_torque_impulse(motorImp);
+ if (body1) body1->apply_torque_impulse(-motorImp);
+
+ return clippedMotorImpulse;
+
+
+}
+
+//////////////////////////// End G6DOFRotationalLimitMotorSW ////////////////////////////////////
+
+//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
+real_t G6DOFTranslationalLimitMotorSW::solveLinearAxis(
+ real_t timeStep,
+ real_t jacDiagABInv,
+ BodySW* body1,const Vector3 &pointInA,
+ BodySW* body2,const Vector3 &pointInB,
+ int limit_index,
+ const Vector3 & axis_normal_on_a,
+ const Vector3 & anchorPos)
+{
+
+///find relative velocity
+// Vector3 rel_pos1 = pointInA - body1->get_transform().origin;
+// Vector3 rel_pos2 = pointInB - body2->get_transform().origin;
+ Vector3 rel_pos1 = anchorPos - body1->get_transform().origin;
+ Vector3 rel_pos2 = anchorPos - body2->get_transform().origin;
+
+ Vector3 vel1 = body1->get_velocity_in_local_point(rel_pos1);
+ Vector3 vel2 = body2->get_velocity_in_local_point(rel_pos2);
+ Vector3 vel = vel1 - vel2;
+
+ real_t rel_vel = axis_normal_on_a.dot(vel);
+
+
+
+/// apply displacement correction
+
+//positional error (zeroth order error)
+ real_t depth = -(pointInA - pointInB).dot(axis_normal_on_a);
+ real_t lo = real_t(-1e30);
+ real_t hi = real_t(1e30);
+
+ real_t minLimit = m_lowerLimit[limit_index];
+ real_t maxLimit = m_upperLimit[limit_index];
+
+ //handle the limits
+ if (minLimit < maxLimit)
+ {
+ {
+ if (depth > maxLimit)
+ {
+ depth -= maxLimit;
+ lo = real_t(0.);
+
+ }
+ else
+ {
+ if (depth < minLimit)
+ {
+ depth -= minLimit;
+ hi = real_t(0.);
+ }
+ else
+ {
+ return 0.0f;
+ }
+ }
+ }
+ }
+
+ real_t normalImpulse= m_limitSoftness[limit_index]*(m_restitution[limit_index]*depth/timeStep - m_damping[limit_index]*rel_vel) * jacDiagABInv;
+
+
+
+
+ real_t oldNormalImpulse = m_accumulatedImpulse[limit_index];
+ real_t sum = oldNormalImpulse + normalImpulse;
+ m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum;
+ normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
+
+ Vector3 impulse_vector = axis_normal_on_a * normalImpulse;
+ body1->apply_impulse( rel_pos1, impulse_vector);
+ body2->apply_impulse( rel_pos2, -impulse_vector);
+ return normalImpulse;
+}
+
+//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
+
+
+Generic6DOFJointSW::Generic6DOFJointSW(BodySW* rbA, BodySW* rbB, const Transform& frameInA, const Transform& frameInB, bool useLinearReferenceFrameA)
+ : JointSW(_arr,2)
+ , m_frameInA(frameInA)
+ , m_frameInB(frameInB),
+ m_useLinearReferenceFrameA(useLinearReferenceFrameA)
+{
+ A=rbA;
+ B=rbB;
+ A->add_constraint(this,0);
+ B->add_constraint(this,1);
+}
+
+
+
+
+
+void Generic6DOFJointSW::calculateAngleInfo()
+{
+ Matrix3 relative_frame = m_calculatedTransformA.basis.inverse()*m_calculatedTransformB.basis;
+
+ matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff);
+
+
+
+ // in euler angle mode we do not actually constrain the angular velocity
+ // along the axes axis[0] and axis[2] (although we do use axis[1]) :
+ //
+ // to get constrain w2-w1 along ...not
+ // ------ --------------------- ------
+ // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
+ // d(angle[1])/dt = 0 ax[1]
+ // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
+ //
+ // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
+ // to prove the result for angle[0], write the expression for angle[0] from
+ // GetInfo1 then take the derivative. to prove this for angle[2] it is
+ // easier to take the euler rate expression for d(angle[2])/dt with respect
+ // to the components of w and set that to 0.
+
+ Vector3 axis0 = m_calculatedTransformB.basis.get_axis(0);
+ Vector3 axis2 = m_calculatedTransformA.basis.get_axis(2);
+
+ m_calculatedAxis[1] = axis2.cross(axis0);
+ m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
+ m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
+
+
+// if(m_debugDrawer)
+// {
+//
+// char buff[300];
+// sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ",
+// m_calculatedAxisAngleDiff[0],
+// m_calculatedAxisAngleDiff[1],
+// m_calculatedAxisAngleDiff[2]);
+// m_debugDrawer->reportErrorWarning(buff);
+// }
+
+}
+
+void Generic6DOFJointSW::calculateTransforms()
+{
+ m_calculatedTransformA = A->get_transform() * m_frameInA;
+ m_calculatedTransformB = B->get_transform() * m_frameInB;
+
+ calculateAngleInfo();
+}
+
+
+void Generic6DOFJointSW::buildLinearJacobian(
+ JacobianEntrySW & jacLinear,const Vector3 & normalWorld,
+ const Vector3 & pivotAInW,const Vector3 & pivotBInW)
+{
+ memnew_placement(&jacLinear, JacobianEntrySW(
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ pivotAInW - A->get_transform().origin,
+ pivotBInW - B->get_transform().origin,
+ normalWorld,
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()));
+
+}
+
+void Generic6DOFJointSW::buildAngularJacobian(
+ JacobianEntrySW & jacAngular,const Vector3 & jointAxisW)
+{
+ memnew_placement(&jacAngular, JacobianEntrySW(jointAxisW,
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+
+}
+
+bool Generic6DOFJointSW::testAngularLimitMotor(int axis_index)
+{
+ real_t angle = m_calculatedAxisAngleDiff[axis_index];
+
+ //test limits
+ m_angularLimits[axis_index].testLimitValue(angle);
+ return m_angularLimits[axis_index].needApplyTorques();
+}
+
+bool Generic6DOFJointSW::setup(float p_step) {
+
+ // Clear accumulated impulses for the next simulation step
+ m_linearLimits.m_accumulatedImpulse=Vector3(real_t(0.), real_t(0.), real_t(0.));
+ int i;
+ for(i = 0; i < 3; i++)
+ {
+ m_angularLimits[i].m_accumulatedImpulse = real_t(0.);
+ }
+ //calculates transform
+ calculateTransforms();
+
+// const Vector3& pivotAInW = m_calculatedTransformA.origin;
+// const Vector3& pivotBInW = m_calculatedTransformB.origin;
+ calcAnchorPos();
+ Vector3 pivotAInW = m_AnchorPos;
+ Vector3 pivotBInW = m_AnchorPos;
+
+// not used here
+// Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
+// Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
+
+ Vector3 normalWorld;
+ //linear part
+ for (i=0;i<3;i++)
+ {
+ if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i))
+ {
+ if (m_useLinearReferenceFrameA)
+ normalWorld = m_calculatedTransformA.basis.get_axis(i);
+ else
+ normalWorld = m_calculatedTransformB.basis.get_axis(i);
+
+ buildLinearJacobian(
+ m_jacLinear[i],normalWorld ,
+ pivotAInW,pivotBInW);
+
+ }
+ }
+
+ // angular part
+ for (i=0;i<3;i++)
+ {
+ //calculates error angle
+ if (m_angularLimits[i].m_enableLimit && testAngularLimitMotor(i))
+ {
+ normalWorld = this->getAxis(i);
+ // Create angular atom
+ buildAngularJacobian(m_jacAng[i],normalWorld);
+ }
+ }
+
+ return true;
+}
+
+
+void Generic6DOFJointSW::solve(real_t timeStep)
+{
+ m_timeStep = timeStep;
+
+ //calculateTransforms();
+
+ int i;
+
+ // linear
+
+ Vector3 pointInA = m_calculatedTransformA.origin;
+ Vector3 pointInB = m_calculatedTransformB.origin;
+
+ real_t jacDiagABInv;
+ Vector3 linear_axis;
+ for (i=0;i<3;i++)
+ {
+ if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i))
+ {
+ jacDiagABInv = real_t(1.) / m_jacLinear[i].getDiagonal();
+
+ if (m_useLinearReferenceFrameA)
+ linear_axis = m_calculatedTransformA.basis.get_axis(i);
+ else
+ linear_axis = m_calculatedTransformB.basis.get_axis(i);
+
+ m_linearLimits.solveLinearAxis(
+ m_timeStep,
+ jacDiagABInv,
+ A,pointInA,
+ B,pointInB,
+ i,linear_axis, m_AnchorPos);
+
+ }
+ }
+
+ // angular
+ Vector3 angular_axis;
+ real_t angularJacDiagABInv;
+ for (i=0;i<3;i++)
+ {
+ if (m_angularLimits[i].m_enableLimit && m_angularLimits[i].needApplyTorques())
+ {
+
+ // get axis
+ angular_axis = getAxis(i);
+
+ angularJacDiagABInv = real_t(1.) / m_jacAng[i].getDiagonal();
+
+ m_angularLimits[i].solveAngularLimits(m_timeStep,angular_axis,angularJacDiagABInv, A,B);
+ }
+ }
+}
+
+void Generic6DOFJointSW::updateRHS(real_t timeStep)
+{
+ (void)timeStep;
+
+}
+
+Vector3 Generic6DOFJointSW::getAxis(int axis_index) const
+{
+ return m_calculatedAxis[axis_index];
+}
+
+real_t Generic6DOFJointSW::getAngle(int axis_index) const
+{
+ return m_calculatedAxisAngleDiff[axis_index];
+}
+
+void Generic6DOFJointSW::calcAnchorPos(void)
+{
+ real_t imA = A->get_inv_mass();
+ real_t imB = B->get_inv_mass();
+ real_t weight;
+ if(imB == real_t(0.0))
+ {
+ weight = real_t(1.0);
+ }
+ else
+ {
+ weight = imA / (imA + imB);
+ }
+ const Vector3& pA = m_calculatedTransformA.origin;
+ const Vector3& pB = m_calculatedTransformB.origin;
+ m_AnchorPos = pA * weight + pB * (real_t(1.0) - weight);
+ return;
+} // Generic6DOFJointSW::calcAnchorPos()
+
+
+void Generic6DOFJointSW::set_param(Vector3::Axis p_axis,PhysicsServer::G6DOFJointAxisParam p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_axis,3);
+ switch(p_param) {
+ case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
+
+ m_linearLimits.m_lowerLimit[p_axis]=p_value;
+ } break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
+
+ m_linearLimits.m_upperLimit[p_axis]=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
+
+ m_linearLimits.m_limitSoftness[p_axis]=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: {
+
+ m_linearLimits.m_restitution[p_axis]=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: {
+
+ m_linearLimits.m_damping[p_axis]=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
+
+ m_angularLimits[p_axis].m_loLimit=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
+
+ m_angularLimits[p_axis].m_hiLimit=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
+
+ m_angularLimits[p_axis].m_limitSoftness=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: {
+
+ m_angularLimits[p_axis].m_damping=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: {
+
+ m_angularLimits[p_axis].m_bounce=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
+
+ m_angularLimits[p_axis].m_maxLimitForce=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: {
+
+ m_angularLimits[p_axis].m_ERP=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
+
+ m_angularLimits[p_axis].m_targetVelocity=p_value;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
+
+ m_angularLimits[p_axis].m_maxLimitForce=p_value;
+
+ } break;
+ }
+}
+
+float Generic6DOFJointSW::get_param(Vector3::Axis p_axis,PhysicsServer::G6DOFJointAxisParam p_param) const{
+ ERR_FAIL_INDEX_V(p_axis,3,0);
+ switch(p_param) {
+ case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
+
+ return m_linearLimits.m_lowerLimit[p_axis];
+ } break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
+
+ return m_linearLimits.m_upperLimit[p_axis];
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
+
+ return m_linearLimits.m_limitSoftness[p_axis];
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: {
+
+ return m_linearLimits.m_restitution[p_axis];
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: {
+
+ return m_linearLimits.m_damping[p_axis];
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
+
+ return m_angularLimits[p_axis].m_loLimit;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
+
+ return m_angularLimits[p_axis].m_hiLimit;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
+
+ return m_angularLimits[p_axis].m_limitSoftness;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: {
+
+ return m_angularLimits[p_axis].m_damping;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: {
+
+ return m_angularLimits[p_axis].m_bounce;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
+
+ return m_angularLimits[p_axis].m_maxLimitForce;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: {
+
+ return m_angularLimits[p_axis].m_ERP;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
+
+ return m_angularLimits[p_axis].m_targetVelocity;
+
+ } break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
+
+ return m_angularLimits[p_axis].m_maxLimitForce;
+
+ } break;
+ }
+ return 0;
+}
+
+void Generic6DOFJointSW::set_flag(Vector3::Axis p_axis,PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value){
+
+ ERR_FAIL_INDEX(p_axis,3);
+
+ switch(p_flag) {
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
+
+ m_linearLimits.enable_limit[p_axis]=p_value;
+ } break;
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
+
+ m_angularLimits[p_axis].m_enableLimit=p_value;
+ } break;
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
+
+ m_angularLimits[p_axis].m_enableMotor=p_value;
+ } break;
+ }
+
+
+}
+bool Generic6DOFJointSW::get_flag(Vector3::Axis p_axis,PhysicsServer::G6DOFJointAxisFlag p_flag) const{
+
+ ERR_FAIL_INDEX_V(p_axis,3,0);
+ switch(p_flag) {
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
+
+ return m_linearLimits.enable_limit[p_axis];
+ } break;
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
+
+ return m_angularLimits[p_axis].m_enableLimit;
+ } break;
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
+
+ return m_angularLimits[p_axis].m_enableMotor;
+ } break;
+ }
+
+ return 0;
+}
diff --git a/servers/physics/joints/generic_6dof_joint_sw.h b/servers/physics/joints/generic_6dof_joint_sw.h
new file mode 100644
index 0000000000..7f762e51a2
--- /dev/null
+++ b/servers/physics/joints/generic_6dof_joint_sw.h
@@ -0,0 +1,428 @@
+#ifndef GENERIC_6DOF_JOINT_SW_H
+#define GENERIC_6DOF_JOINT_SW_H
+
+#include "servers/physics/joints_sw.h"
+#include "servers/physics/joints/jacobian_entry_sw.h"
+
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+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.
+*/
+
+
+/*
+2007-09-09
+Generic6DOFJointSW Refactored by Francisco Le?n
+email: projectileman@yahoo.com
+http://gimpact.sf.net
+*/
+
+
+//! Rotation Limit structure for generic joints
+class G6DOFRotationalLimitMotorSW {
+public:
+ //! limit_parameters
+ //!@{
+ real_t m_loLimit;//!< joint limit
+ real_t m_hiLimit;//!< joint limit
+ real_t m_targetVelocity;//!< target motor velocity
+ real_t m_maxMotorForce;//!< max force on motor
+ real_t m_maxLimitForce;//!< max force on limit
+ real_t m_damping;//!< Damping.
+ real_t m_limitSoftness;//! Relaxation factor
+ real_t m_ERP;//!< Error tolerance factor when joint is at limit
+ real_t m_bounce;//!< restitution factor
+ bool m_enableMotor;
+ bool m_enableLimit;
+
+ //!@}
+
+ //! temp_variables
+ //!@{
+ real_t m_currentLimitError;//! How much is violated this limit
+ int m_currentLimit;//!< 0=free, 1=at lo limit, 2=at hi limit
+ real_t m_accumulatedImpulse;
+ //!@}
+
+ G6DOFRotationalLimitMotorSW()
+ {
+ m_accumulatedImpulse = 0.f;
+ m_targetVelocity = 0;
+ m_maxMotorForce = 0.1f;
+ m_maxLimitForce = 300.0f;
+ m_loLimit = -1e30;
+ m_hiLimit = 1e30;
+ m_ERP = 0.5f;
+ m_bounce = 0.0f;
+ m_damping = 1.0f;
+ m_limitSoftness = 0.5f;
+ m_currentLimit = 0;
+ m_currentLimitError = 0;
+ m_enableMotor = false;
+ m_enableLimit=false;
+ }
+
+ G6DOFRotationalLimitMotorSW(const G6DOFRotationalLimitMotorSW & limot)
+ {
+ m_targetVelocity = limot.m_targetVelocity;
+ m_maxMotorForce = limot.m_maxMotorForce;
+ m_limitSoftness = limot.m_limitSoftness;
+ m_loLimit = limot.m_loLimit;
+ m_hiLimit = limot.m_hiLimit;
+ m_ERP = limot.m_ERP;
+ m_bounce = limot.m_bounce;
+ m_currentLimit = limot.m_currentLimit;
+ m_currentLimitError = limot.m_currentLimitError;
+ m_enableMotor = limot.m_enableMotor;
+ }
+
+
+
+ //! Is limited
+ bool isLimited()
+ {
+ if(m_loLimit>=m_hiLimit) return false;
+ return true;
+ }
+
+ //! Need apply correction
+ bool needApplyTorques()
+ {
+ if(m_currentLimit == 0 && m_enableMotor == false) return false;
+ return true;
+ }
+
+ //! calculates error
+ /*!
+ calculates m_currentLimit and m_currentLimitError.
+ */
+ int testLimitValue(real_t test_value);
+
+ //! apply the correction impulses for two bodies
+ real_t solveAngularLimits(real_t timeStep,Vector3& axis, real_t jacDiagABInv,BodySW * body0, BodySW * body1);
+
+
+};
+
+
+
+class G6DOFTranslationalLimitMotorSW
+{
+public:
+ Vector3 m_lowerLimit;//!< the constraint lower limits
+ Vector3 m_upperLimit;//!< the constraint upper limits
+ Vector3 m_accumulatedImpulse;
+ //! Linear_Limit_parameters
+ //!@{
+ Vector3 m_limitSoftness;//!< Softness for linear limit
+ Vector3 m_damping;//!< Damping for linear limit
+ Vector3 m_restitution;//! Bounce parameter for linear limit
+ //!@}
+ bool enable_limit[3];
+
+ G6DOFTranslationalLimitMotorSW()
+ {
+ m_lowerLimit=Vector3(0.f,0.f,0.f);
+ m_upperLimit=Vector3(0.f,0.f,0.f);
+ m_accumulatedImpulse=Vector3(0.f,0.f,0.f);
+
+ m_limitSoftness = Vector3(1,1,1)*0.7f;
+ m_damping = Vector3(1,1,1)*real_t(1.0f);
+ m_restitution = Vector3(1,1,1)*real_t(0.5f);
+
+ enable_limit[0]=true;
+ enable_limit[1]=true;
+ enable_limit[2]=true;
+ }
+
+ G6DOFTranslationalLimitMotorSW(const G6DOFTranslationalLimitMotorSW & other )
+ {
+ m_lowerLimit = other.m_lowerLimit;
+ m_upperLimit = other.m_upperLimit;
+ m_accumulatedImpulse = other.m_accumulatedImpulse;
+
+ m_limitSoftness = other.m_limitSoftness ;
+ m_damping = other.m_damping;
+ m_restitution = other.m_restitution;
+ }
+
+ //! Test limit
+ /*!
+ - free means upper < lower,
+ - locked means upper == lower
+ - limited means upper > lower
+ - limitIndex: first 3 are linear, next 3 are angular
+ */
+ inline bool isLimited(int limitIndex)
+ {
+ return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
+ }
+
+
+ real_t solveLinearAxis(
+ real_t timeStep,
+ real_t jacDiagABInv,
+ BodySW* body1,const Vector3 &pointInA,
+ BodySW* body2,const Vector3 &pointInB,
+ int limit_index,
+ const Vector3 & axis_normal_on_a,
+ const Vector3 & anchorPos);
+
+
+};
+
+
+class Generic6DOFJointSW : public JointSW
+{
+protected:
+
+
+ union {
+ struct {
+ BodySW *A;
+ BodySW *B;
+ };
+
+ BodySW *_arr[2];
+ };
+
+ //! relative_frames
+ //!@{
+ Transform m_frameInA;//!< the constraint space w.r.t body A
+ Transform m_frameInB;//!< the constraint space w.r.t body B
+ //!@}
+
+ //! Jacobians
+ //!@{
+ JacobianEntrySW m_jacLinear[3];//!< 3 orthogonal linear constraints
+ JacobianEntrySW m_jacAng[3];//!< 3 orthogonal angular constraints
+ //!@}
+
+ //! Linear_Limit_parameters
+ //!@{
+ G6DOFTranslationalLimitMotorSW m_linearLimits;
+ //!@}
+
+
+ //! hinge_parameters
+ //!@{
+ G6DOFRotationalLimitMotorSW m_angularLimits[3];
+ //!@}
+
+
+protected:
+ //! temporal variables
+ //!@{
+ real_t m_timeStep;
+ Transform m_calculatedTransformA;
+ Transform m_calculatedTransformB;
+ Vector3 m_calculatedAxisAngleDiff;
+ Vector3 m_calculatedAxis[3];
+
+ Vector3 m_AnchorPos; // point betwen pivots of bodies A and B to solve linear axes
+
+ bool m_useLinearReferenceFrameA;
+
+ //!@}
+
+ Generic6DOFJointSW& operator=(Generic6DOFJointSW& other)
+ {
+ ERR_PRINT("pito");
+ (void) other;
+ return *this;
+ }
+
+
+
+ void buildLinearJacobian(
+ JacobianEntrySW & jacLinear,const Vector3 & normalWorld,
+ const Vector3 & pivotAInW,const Vector3 & pivotBInW);
+
+ void buildAngularJacobian(JacobianEntrySW & jacAngular,const Vector3 & jointAxisW);
+
+
+ //! calcs the euler angles between the two bodies.
+ void calculateAngleInfo();
+
+
+
+public:
+ Generic6DOFJointSW(BodySW* rbA, BodySW* rbB, const Transform& frameInA, const Transform& frameInB ,bool useLinearReferenceFrameA);
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_6DOF; }
+
+ virtual bool setup(float p_step);
+ virtual void solve(float p_step);
+
+
+ //! Calcs global transform of the offsets
+ /*!
+ Calcs the global transform for the joint offset for body A an B, and also calcs the agle differences between the bodies.
+ \sa Generic6DOFJointSW.getCalculatedTransformA , Generic6DOFJointSW.getCalculatedTransformB, Generic6DOFJointSW.calculateAngleInfo
+ */
+ void calculateTransforms();
+
+ //! Gets the global transform of the offset for body A
+ /*!
+ \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo.
+ */
+ const Transform & getCalculatedTransformA() const
+ {
+ return m_calculatedTransformA;
+ }
+
+ //! Gets the global transform of the offset for body B
+ /*!
+ \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo.
+ */
+ const Transform & getCalculatedTransformB() const
+ {
+ return m_calculatedTransformB;
+ }
+
+ const Transform & getFrameOffsetA() const
+ {
+ return m_frameInA;
+ }
+
+ const Transform & getFrameOffsetB() const
+ {
+ return m_frameInB;
+ }
+
+
+ Transform & getFrameOffsetA()
+ {
+ return m_frameInA;
+ }
+
+ Transform & getFrameOffsetB()
+ {
+ return m_frameInB;
+ }
+
+
+ //! performs Jacobian calculation, and also calculates angle differences and axis
+
+
+ void updateRHS(real_t timeStep);
+
+ //! Get the rotation axis in global coordinates
+ /*!
+ \pre Generic6DOFJointSW.buildJacobian must be called previously.
+ */
+ Vector3 getAxis(int axis_index) const;
+
+ //! Get the relative Euler angle
+ /*!
+ \pre Generic6DOFJointSW.buildJacobian must be called previously.
+ */
+ real_t getAngle(int axis_index) const;
+
+ //! Test angular limit.
+ /*!
+ Calculates angular correction and returns true if limit needs to be corrected.
+ \pre Generic6DOFJointSW.buildJacobian must be called previously.
+ */
+ bool testAngularLimitMotor(int axis_index);
+
+ void setLinearLowerLimit(const Vector3& linearLower)
+ {
+ m_linearLimits.m_lowerLimit = linearLower;
+ }
+
+ void setLinearUpperLimit(const Vector3& linearUpper)
+ {
+ m_linearLimits.m_upperLimit = linearUpper;
+ }
+
+ void setAngularLowerLimit(const Vector3& angularLower)
+ {
+ m_angularLimits[0].m_loLimit = angularLower.x;
+ m_angularLimits[1].m_loLimit = angularLower.y;
+ m_angularLimits[2].m_loLimit = angularLower.z;
+ }
+
+ void setAngularUpperLimit(const Vector3& angularUpper)
+ {
+ m_angularLimits[0].m_hiLimit = angularUpper.x;
+ m_angularLimits[1].m_hiLimit = angularUpper.y;
+ m_angularLimits[2].m_hiLimit = angularUpper.z;
+ }
+
+ //! Retrieves the angular limit informacion
+ G6DOFRotationalLimitMotorSW * getRotationalLimitMotor(int index)
+ {
+ return &m_angularLimits[index];
+ }
+
+ //! Retrieves the limit informacion
+ G6DOFTranslationalLimitMotorSW * getTranslationalLimitMotor()
+ {
+ return &m_linearLimits;
+ }
+
+ //first 3 are linear, next 3 are angular
+ void setLimit(int axis, real_t lo, real_t hi)
+ {
+ if(axis<3)
+ {
+ m_linearLimits.m_lowerLimit[axis] = lo;
+ m_linearLimits.m_upperLimit[axis] = hi;
+ }
+ else
+ {
+ m_angularLimits[axis-3].m_loLimit = lo;
+ m_angularLimits[axis-3].m_hiLimit = hi;
+ }
+ }
+
+ //! Test limit
+ /*!
+ - free means upper < lower,
+ - locked means upper == lower
+ - limited means upper > lower
+ - limitIndex: first 3 are linear, next 3 are angular
+ */
+ bool isLimited(int limitIndex)
+ {
+ if(limitIndex<3)
+ {
+ return m_linearLimits.isLimited(limitIndex);
+
+ }
+ return m_angularLimits[limitIndex-3].isLimited();
+ }
+
+ const BodySW* getRigidBodyA() const
+ {
+ return A;
+ }
+ const BodySW* getRigidBodyB() const
+ {
+ return B;
+ }
+
+ virtual void calcAnchorPos(void); // overridable
+
+ void set_param(Vector3::Axis p_axis,PhysicsServer::G6DOFJointAxisParam p_param, float p_value);
+ float get_param(Vector3::Axis p_axis,PhysicsServer::G6DOFJointAxisParam p_param) const;
+
+ void set_flag(Vector3::Axis p_axis,PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value);
+ bool get_flag(Vector3::Axis p_axis,PhysicsServer::G6DOFJointAxisFlag p_flag) const;
+
+};
+
+
+#endif // GENERIC_6DOF_JOINT_SW_H
diff --git a/servers/physics/joints/hinge_joint_sw.cpp b/servers/physics/joints/hinge_joint_sw.cpp
new file mode 100644
index 0000000000..feaf00290d
--- /dev/null
+++ b/servers/physics/joints/hinge_joint_sw.cpp
@@ -0,0 +1,438 @@
+#include "hinge_joint_sw.h"
+
+static void plane_space(const Vector3& n, Vector3& p, Vector3& q) {
+
+ if (Math::abs(n.z) > 0.707106781186547524400844362) {
+ // choose p in y-z plane
+ real_t a = n[1]*n[1] + n[2]*n[2];
+ real_t k = 1.0/Math::sqrt(a);
+ p=Vector3(0,-n[2]*k,n[1]*k);
+ // set q = n x p
+ q=Vector3(a*k,-n[0]*p[2],n[0]*p[1]);
+ }
+ else {
+ // choose p in x-y plane
+ real_t a = n.x*n.x + n.y*n.y;
+ real_t k = 1.0/Math::sqrt(a);
+ p=Vector3(-n.y*k,n.x*k,0);
+ // set q = n x p
+ q=Vector3(-n.z*p.y,n.z*p.x,a*k);
+ }
+}
+
+HingeJointSW::HingeJointSW(BodySW* rbA,BodySW* rbB, const Transform& frameA, const Transform& frameB) : JointSW(_arr,2) {
+
+ A=rbA;
+ B=rbB;
+
+ m_rbAFrame=frameA;
+ m_rbBFrame=frameB;
+ // flip axis
+ m_rbBFrame.basis[0][2] *= real_t(-1.);
+ m_rbBFrame.basis[1][2] *= real_t(-1.);
+ m_rbBFrame.basis[2][2] *= real_t(-1.);
+
+
+ //start with free
+ m_lowerLimit = Math_PI;
+ m_upperLimit = -Math_PI;
+
+
+ m_useLimit = false;
+ m_biasFactor = 0.3f;
+ m_relaxationFactor = 1.0f;
+ m_limitSoftness = 0.9f;
+ m_solveLimit = false;
+
+ tau=0.3;
+
+ m_angularOnly=false;
+ m_enableAngularMotor=false;
+
+ A->add_constraint(this,0);
+ B->add_constraint(this,1);
+
+}
+
+HingeJointSW::HingeJointSW(BodySW* rbA,BodySW* rbB, const Vector3& pivotInA,const Vector3& pivotInB,
+ const Vector3& axisInA,const Vector3& axisInB) : JointSW(_arr,2) {
+
+ A=rbA;
+ B=rbB;
+
+ m_rbAFrame.origin = pivotInA;
+
+ // since no frame is given, assume this to be zero angle and just pick rb transform axis
+ Vector3 rbAxisA1 = rbA->get_transform().basis.get_axis(0);
+
+ Vector3 rbAxisA2;
+ real_t projection = axisInA.dot(rbAxisA1);
+ if (projection >= 1.0f - CMP_EPSILON) {
+ rbAxisA1 = -rbA->get_transform().basis.get_axis(2);
+ rbAxisA2 = rbA->get_transform().basis.get_axis(1);
+ } else if (projection <= -1.0f + CMP_EPSILON) {
+ rbAxisA1 = rbA->get_transform().basis.get_axis(2);
+ rbAxisA2 = rbA->get_transform().basis.get_axis(1);
+ } else {
+ rbAxisA2 = axisInA.cross(rbAxisA1);
+ rbAxisA1 = rbAxisA2.cross(axisInA);
+ }
+
+ m_rbAFrame.basis=Matrix3( rbAxisA1.x,rbAxisA2.x,axisInA.x,
+ rbAxisA1.y,rbAxisA2.y,axisInA.y,
+ rbAxisA1.z,rbAxisA2.z,axisInA.z );
+
+ Quat rotationArc = Quat(axisInA,axisInB);
+ Vector3 rbAxisB1 = rotationArc.xform(rbAxisA1);
+ Vector3 rbAxisB2 = axisInB.cross(rbAxisB1);
+
+ m_rbBFrame.origin = pivotInB;
+ m_rbBFrame.basis=Matrix3( rbAxisB1.x,rbAxisB2.x,-axisInB.x,
+ rbAxisB1.y,rbAxisB2.y,-axisInB.y,
+ rbAxisB1.z,rbAxisB2.z,-axisInB.z );
+
+ //start with free
+ m_lowerLimit = Math_PI;
+ m_upperLimit = -Math_PI;
+
+
+ m_useLimit = false;
+ m_biasFactor = 0.3f;
+ m_relaxationFactor = 1.0f;
+ m_limitSoftness = 0.9f;
+ m_solveLimit = false;
+
+ tau=0.3;
+
+ m_angularOnly=false;
+ m_enableAngularMotor=false;
+
+ A->add_constraint(this,0);
+ B->add_constraint(this,1);
+
+}
+
+
+
+bool HingeJointSW::setup(float p_step) {
+
+ m_appliedImpulse = real_t(0.);
+
+ if (!m_angularOnly)
+ {
+ Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
+ Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
+ Vector3 relPos = pivotBInW - pivotAInW;
+
+ Vector3 normal[3];
+ if (relPos.length_squared() > CMP_EPSILON)
+ {
+ normal[0] = relPos.normalized();
+ }
+ else
+ {
+ normal[0]=Vector3(real_t(1.0),0,0);
+ }
+
+ plane_space(normal[0], normal[1], normal[2]);
+
+ for (int i=0;i<3;i++)
+ {
+ memnew_placement(&m_jac[i], JacobianEntrySW(
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ pivotAInW - A->get_transform().origin,
+ pivotBInW - B->get_transform().origin,
+ normal[i],
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()) );
+ }
+ }
+
+ //calculate two perpendicular jointAxis, orthogonal to hingeAxis
+ //these two jointAxis require equal angular velocities for both bodies
+
+ //this is unused for now, it's a todo
+ Vector3 jointAxis0local;
+ Vector3 jointAxis1local;
+
+ plane_space(m_rbAFrame.basis.get_axis(2),jointAxis0local,jointAxis1local);
+
+ A->get_transform().basis.xform( m_rbAFrame.basis.get_axis(2) );
+ Vector3 jointAxis0 = A->get_transform().basis.xform( jointAxis0local );
+ Vector3 jointAxis1 = A->get_transform().basis.xform( jointAxis1local );
+ Vector3 hingeAxisWorld = A->get_transform().basis.xform( m_rbAFrame.basis.get_axis(2) );
+
+ memnew_placement(&m_jacAng[0], JacobianEntrySW(jointAxis0,
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+
+ memnew_placement(&m_jacAng[1], JacobianEntrySW(jointAxis1,
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+
+ memnew_placement(&m_jacAng[2], JacobianEntrySW(hingeAxisWorld,
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+
+
+ // Compute limit information
+ real_t hingeAngle = get_hinge_angle();
+
+// print_line("angle: "+rtos(hingeAngle));
+ //set bias, sign, clear accumulator
+ m_correction = real_t(0.);
+ m_limitSign = real_t(0.);
+ m_solveLimit = false;
+ m_accLimitImpulse = real_t(0.);
+
+
+
+ /*if (m_useLimit) {
+ print_line("low: "+rtos(m_lowerLimit));
+ print_line("hi: "+rtos(m_upperLimit));
+ }*/
+
+// if (m_lowerLimit < m_upperLimit)
+ if (m_useLimit && m_lowerLimit <= m_upperLimit)
+ {
+// if (hingeAngle <= m_lowerLimit*m_limitSoftness)
+ if (hingeAngle <= m_lowerLimit)
+ {
+ m_correction = (m_lowerLimit - hingeAngle);
+ m_limitSign = 1.0f;
+ m_solveLimit = true;
+ }
+// else if (hingeAngle >= m_upperLimit*m_limitSoftness)
+ else if (hingeAngle >= m_upperLimit)
+ {
+ m_correction = m_upperLimit - hingeAngle;
+ m_limitSign = -1.0f;
+ m_solveLimit = true;
+ }
+ }
+
+ //Compute K = J*W*J' for hinge axis
+ Vector3 axisA = A->get_transform().basis.xform( m_rbAFrame.basis.get_axis(2) );
+ m_kHinge = 1.0f / (A->compute_angular_impulse_denominator(axisA) +
+ B->compute_angular_impulse_denominator(axisA));
+
+ return true;
+}
+
+void HingeJointSW::solve(float p_step) {
+
+ Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
+ Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
+
+ //real_t tau = real_t(0.3);
+
+ //linear part
+ if (!m_angularOnly)
+ {
+ Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
+ Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
+
+ Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
+ Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
+ Vector3 vel = vel1 - vel2;
+
+ for (int i=0;i<3;i++)
+ {
+ const Vector3& normal = m_jac[i].m_linearJointAxis;
+ real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
+
+ real_t rel_vel;
+ rel_vel = normal.dot(vel);
+ //positional error (zeroth order error)
+ real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
+ real_t impulse = depth*tau/p_step * jacDiagABInv - rel_vel * jacDiagABInv;
+ m_appliedImpulse += impulse;
+ Vector3 impulse_vector = normal * impulse;
+ A->apply_impulse(pivotAInW - A->get_transform().origin,impulse_vector);
+ B->apply_impulse(pivotBInW - B->get_transform().origin,-impulse_vector);
+ }
+ }
+
+
+ {
+ ///solve angular part
+
+ // get axes in world space
+ Vector3 axisA = A->get_transform().basis.xform( m_rbAFrame.basis.get_axis(2) );
+ Vector3 axisB = B->get_transform().basis.xform( m_rbBFrame.basis.get_axis(2) );
+
+ const Vector3& angVelA = A->get_angular_velocity();
+ const Vector3& angVelB = B->get_angular_velocity();
+
+ Vector3 angVelAroundHingeAxisA = axisA * axisA.dot(angVelA);
+ Vector3 angVelAroundHingeAxisB = axisB * axisB.dot(angVelB);
+
+ Vector3 angAorthog = angVelA - angVelAroundHingeAxisA;
+ Vector3 angBorthog = angVelB - angVelAroundHingeAxisB;
+ Vector3 velrelOrthog = angAorthog-angBorthog;
+ {
+ //solve orthogonal angular velocity correction
+ real_t relaxation = real_t(1.);
+ real_t len = velrelOrthog.length();
+ if (len > real_t(0.00001))
+ {
+ Vector3 normal = velrelOrthog.normalized();
+ real_t denom = A->compute_angular_impulse_denominator(normal) +
+ B->compute_angular_impulse_denominator(normal);
+ // scale for mass and relaxation
+ velrelOrthog *= (real_t(1.)/denom) * m_relaxationFactor;
+ }
+
+ //solve angular positional correction
+ Vector3 angularError = -axisA.cross(axisB) *(real_t(1.)/p_step);
+ real_t len2 = angularError.length();
+ if (len2>real_t(0.00001))
+ {
+ Vector3 normal2 = angularError.normalized();
+ real_t denom2 = A->compute_angular_impulse_denominator(normal2) +
+ B->compute_angular_impulse_denominator(normal2);
+ angularError *= (real_t(1.)/denom2) * relaxation;
+ }
+
+ A->apply_torque_impulse(-velrelOrthog+angularError);
+ B->apply_torque_impulse(velrelOrthog-angularError);
+
+ // solve limit
+ if (m_solveLimit)
+ {
+ real_t amplitude = ( (angVelB - angVelA).dot( axisA )*m_relaxationFactor + m_correction* (real_t(1.)/p_step)*m_biasFactor ) * m_limitSign;
+
+ real_t impulseMag = amplitude * m_kHinge;
+
+ // Clamp the accumulated impulse
+ real_t temp = m_accLimitImpulse;
+ m_accLimitImpulse = MAX(m_accLimitImpulse + impulseMag, real_t(0) );
+ impulseMag = m_accLimitImpulse - temp;
+
+
+ Vector3 impulse = axisA * impulseMag * m_limitSign;
+ A->apply_torque_impulse(impulse);
+ B->apply_torque_impulse(-impulse);
+ }
+ }
+
+ //apply motor
+ if (m_enableAngularMotor)
+ {
+ //todo: add limits too
+ Vector3 angularLimit(0,0,0);
+
+ Vector3 velrel = angVelAroundHingeAxisA - angVelAroundHingeAxisB;
+ real_t projRelVel = velrel.dot(axisA);
+
+ real_t desiredMotorVel = m_motorTargetVelocity;
+ real_t motor_relvel = desiredMotorVel - projRelVel;
+
+ real_t unclippedMotorImpulse = m_kHinge * motor_relvel;;
+ //todo: should clip against accumulated impulse
+ real_t clippedMotorImpulse = unclippedMotorImpulse > m_maxMotorImpulse ? m_maxMotorImpulse : unclippedMotorImpulse;
+ clippedMotorImpulse = clippedMotorImpulse < -m_maxMotorImpulse ? -m_maxMotorImpulse : clippedMotorImpulse;
+ Vector3 motorImp = clippedMotorImpulse * axisA;
+
+ A->apply_torque_impulse(motorImp+angularLimit);
+ B->apply_torque_impulse(-motorImp-angularLimit);
+
+ }
+ }
+
+}
+/*
+void HingeJointSW::updateRHS(real_t timeStep)
+{
+ (void)timeStep;
+
+}
+*/
+
+static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x)
+{
+ real_t coeff_1 = Math_PI / 4.0f;
+ real_t coeff_2 = 3.0f * coeff_1;
+ real_t abs_y = Math::abs(y);
+ real_t angle;
+ if (x >= 0.0f) {
+ real_t r = (x - abs_y) / (x + abs_y);
+ angle = coeff_1 - coeff_1 * r;
+ } else {
+ real_t r = (x + abs_y) / (abs_y - x);
+ angle = coeff_2 - coeff_1 * r;
+ }
+ return (y < 0.0f) ? -angle : angle;
+}
+
+
+real_t HingeJointSW::get_hinge_angle() {
+ const Vector3 refAxis0 = A->get_transform().basis.xform( m_rbAFrame.basis.get_axis(0) );
+ const Vector3 refAxis1 = A->get_transform().basis.xform( m_rbAFrame.basis.get_axis(1) );
+ const Vector3 swingAxis = B->get_transform().basis.xform( m_rbBFrame.basis.get_axis(1) );
+
+ return atan2fast( swingAxis.dot(refAxis0), swingAxis.dot(refAxis1) );
+}
+
+
+void HingeJointSW::set_param(PhysicsServer::HingeJointParam p_param, float p_value) {
+
+ switch (p_param) {
+
+ case PhysicsServer::HINGE_JOINT_BIAS: tau=p_value; break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_UPPER: m_upperLimit=p_value; break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_LOWER: m_lowerLimit=p_value; break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_BIAS: m_biasFactor=p_value; break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS: m_limitSoftness=p_value; break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION: m_relaxationFactor=p_value; break;
+ case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY: m_motorTargetVelocity=p_value; break;
+ case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: m_maxMotorImpulse=p_value; break;
+
+ }
+}
+
+float HingeJointSW::get_param(PhysicsServer::HingeJointParam p_param) const{
+
+ switch (p_param) {
+
+ case PhysicsServer::HINGE_JOINT_BIAS: return tau;
+ case PhysicsServer::HINGE_JOINT_LIMIT_UPPER: return m_upperLimit;
+ case PhysicsServer::HINGE_JOINT_LIMIT_LOWER: return m_lowerLimit;
+ case PhysicsServer::HINGE_JOINT_LIMIT_BIAS: return m_biasFactor;
+ case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS: return m_limitSoftness;
+ case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION: return m_relaxationFactor;
+ case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY: return m_motorTargetVelocity;
+ case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: return m_maxMotorImpulse;
+
+ }
+
+ return 0;
+}
+
+void HingeJointSW::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value){
+
+ print_line(p_flag+": "+itos(p_value));
+ switch (p_flag) {
+ case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT: m_useLimit=p_value; break;
+ case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: m_enableAngularMotor=p_value; break;
+ }
+
+}
+bool HingeJointSW::get_flag(PhysicsServer::HingeJointFlag p_flag) const{
+
+ switch (p_flag) {
+ case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT: return m_useLimit;
+ case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR:return m_enableAngularMotor;
+ }
+
+ return false;
+}
diff --git a/servers/physics/joints/hinge_joint_sw.h b/servers/physics/joints/hinge_joint_sw.h
new file mode 100644
index 0000000000..4f6cdaf799
--- /dev/null
+++ b/servers/physics/joints/hinge_joint_sw.h
@@ -0,0 +1,89 @@
+#ifndef HINGE_JOINT_SW_H
+#define HINGE_JOINT_SW_H
+
+#include "servers/physics/joints_sw.h"
+#include "servers/physics/joints/jacobian_entry_sw.h"
+
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+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.
+*/
+
+
+
+class HingeJointSW : public JointSW {
+
+ union {
+ struct {
+ BodySW *A;
+ BodySW *B;
+ };
+
+ BodySW *_arr[2];
+ };
+
+ JacobianEntrySW m_jac[3]; //3 orthogonal linear constraints
+ JacobianEntrySW m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor
+
+ Transform m_rbAFrame; // constraint axii. Assumes z is hinge axis.
+ Transform m_rbBFrame;
+
+ real_t m_motorTargetVelocity;
+ real_t m_maxMotorImpulse;
+
+ real_t m_limitSoftness;
+ real_t m_biasFactor;
+ real_t m_relaxationFactor;
+
+ real_t m_lowerLimit;
+ real_t m_upperLimit;
+
+ real_t m_kHinge;
+
+ real_t m_limitSign;
+ real_t m_correction;
+
+ real_t m_accLimitImpulse;
+
+ real_t tau;
+
+ bool m_useLimit;
+ bool m_angularOnly;
+ bool m_enableAngularMotor;
+ bool m_solveLimit;
+
+ real_t m_appliedImpulse;
+
+
+public:
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_HINGE; }
+
+ virtual bool setup(float p_step);
+ virtual void solve(float p_step);
+
+ real_t get_hinge_angle();
+
+ void set_param(PhysicsServer::HingeJointParam p_param, float p_value);
+ float get_param(PhysicsServer::HingeJointParam p_param) const;
+
+ void set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value);
+ bool get_flag(PhysicsServer::HingeJointFlag p_flag) const;
+
+ HingeJointSW(BodySW* rbA,BodySW* rbB, const Transform& frameA, const Transform& frameB);
+ HingeJointSW(BodySW* rbA,BodySW* rbB, const Vector3& pivotInA,const Vector3& pivotInB, const Vector3& axisInA,const Vector3& axisInB);
+
+};
+
+#endif // HINGE_JOINT_SW_H
diff --git a/servers/physics/joints/jacobian_entry_sw.cpp b/servers/physics/joints/jacobian_entry_sw.cpp
new file mode 100644
index 0000000000..faa3cf15c4
--- /dev/null
+++ b/servers/physics/joints/jacobian_entry_sw.cpp
@@ -0,0 +1,2 @@
+#include "jacobian_entry_sw.h"
+
diff --git a/servers/physics/joints/jacobian_entry_sw.h b/servers/physics/joints/jacobian_entry_sw.h
new file mode 100644
index 0000000000..16fa034215
--- /dev/null
+++ b/servers/physics/joints/jacobian_entry_sw.h
@@ -0,0 +1,146 @@
+#ifndef JACOBIAN_ENTRY_SW_H
+#define JACOBIAN_ENTRY_SW_H
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+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 "transform.h"
+
+class JacobianEntrySW {
+public:
+ JacobianEntrySW() {};
+ //constraint between two different rigidbodies
+ JacobianEntrySW(
+ const Matrix3& world2A,
+ const Matrix3& world2B,
+ const Vector3& rel_pos1,const Vector3& rel_pos2,
+ const Vector3& jointAxis,
+ const Vector3& inertiaInvA,
+ const real_t massInvA,
+ const Vector3& inertiaInvB,
+ const real_t massInvB)
+ :m_linearJointAxis(jointAxis)
+ {
+ m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
+ m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
+
+ ERR_FAIL_COND(m_Adiag <= real_t(0.0));
+ }
+
+ //angular constraint between two different rigidbodies
+ JacobianEntrySW(const Vector3& jointAxis,
+ const Matrix3& world2A,
+ const Matrix3& world2B,
+ const Vector3& inertiaInvA,
+ const Vector3& inertiaInvB)
+ :m_linearJointAxis(Vector3(real_t(0.),real_t(0.),real_t(0.)))
+ {
+ m_aJ= world2A.xform(jointAxis);
+ m_bJ = world2B.xform(-jointAxis);
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ);
+
+ ERR_FAIL_COND(m_Adiag <= real_t(0.0));
+ }
+
+ //angular constraint between two different rigidbodies
+ JacobianEntrySW(const Vector3& axisInA,
+ const Vector3& axisInB,
+ const Vector3& inertiaInvA,
+ const Vector3& inertiaInvB)
+ : m_linearJointAxis(Vector3(real_t(0.),real_t(0.),real_t(0.)))
+ , m_aJ(axisInA)
+ , m_bJ(-axisInB)
+ {
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ);
+
+ ERR_FAIL_COND(m_Adiag <= real_t(0.0));
+ }
+
+ //constraint on one rigidbody
+ JacobianEntrySW(
+ const Matrix3& world2A,
+ const Vector3& rel_pos1,const Vector3& rel_pos2,
+ const Vector3& jointAxis,
+ const Vector3& inertiaInvA,
+ const real_t massInvA)
+ :m_linearJointAxis(jointAxis)
+ {
+ m_aJ= world2A.xform(rel_pos1.cross(jointAxis));
+ m_bJ = world2A.xform(rel_pos2.cross(-jointAxis));
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = Vector3(real_t(0.),real_t(0.),real_t(0.));
+ m_Adiag = massInvA + m_0MinvJt.dot(m_aJ);
+
+ ERR_FAIL_COND(m_Adiag <= real_t(0.0));
+ }
+
+ real_t getDiagonal() const { return m_Adiag; }
+
+ // for two constraints on the same rigidbody (for example vehicle friction)
+ real_t getNonDiagonal(const JacobianEntrySW& jacB, const real_t massInvA) const
+ {
+ const JacobianEntrySW& jacA = *this;
+ real_t lin = massInvA * jacA.m_linearJointAxis.dot(jacB.m_linearJointAxis);
+ real_t ang = jacA.m_0MinvJt.dot(jacB.m_aJ);
+ return lin + ang;
+ }
+
+
+
+ // for two constraints on sharing two same rigidbodies (for example two contact points between two rigidbodies)
+ real_t getNonDiagonal(const JacobianEntrySW& jacB,const real_t massInvA,const real_t massInvB) const
+ {
+ const JacobianEntrySW& jacA = *this;
+ Vector3 lin = jacA.m_linearJointAxis * jacB.m_linearJointAxis;
+ Vector3 ang0 = jacA.m_0MinvJt * jacB.m_aJ;
+ Vector3 ang1 = jacA.m_1MinvJt * jacB.m_bJ;
+ Vector3 lin0 = massInvA * lin ;
+ Vector3 lin1 = massInvB * lin;
+ Vector3 sum = ang0+ang1+lin0+lin1;
+ return sum[0]+sum[1]+sum[2];
+ }
+
+ real_t getRelativeVelocity(const Vector3& linvelA,const Vector3& angvelA,const Vector3& linvelB,const Vector3& angvelB)
+ {
+ Vector3 linrel = linvelA - linvelB;
+ Vector3 angvela = angvelA * m_aJ;
+ Vector3 angvelb = angvelB * m_bJ;
+ linrel *= m_linearJointAxis;
+ angvela += angvelb;
+ angvela += linrel;
+ real_t rel_vel2 = angvela[0]+angvela[1]+angvela[2];
+ return rel_vel2 + CMP_EPSILON;
+ }
+//private:
+
+ Vector3 m_linearJointAxis;
+ Vector3 m_aJ;
+ Vector3 m_bJ;
+ Vector3 m_0MinvJt;
+ Vector3 m_1MinvJt;
+ //Optimization: can be stored in the w/last component of one of the vectors
+ real_t m_Adiag;
+
+};
+
+
+#endif // JACOBIAN_ENTRY_SW_H
diff --git a/servers/physics/joints/pin_joint_sw.cpp b/servers/physics/joints/pin_joint_sw.cpp
new file mode 100644
index 0000000000..229863fb7b
--- /dev/null
+++ b/servers/physics/joints/pin_joint_sw.cpp
@@ -0,0 +1,127 @@
+#include "pin_joint_sw.h"
+
+bool PinJointSW::setup(float p_step) {
+
+ m_appliedImpulse = real_t(0.);
+
+ Vector3 normal(0,0,0);
+
+ for (int i=0;i<3;i++)
+ {
+ normal[i] = 1;
+ memnew_placement(&m_jac[i],JacobianEntrySW(
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ A->get_transform().xform(m_pivotInA) - A->get_transform().origin,
+ B->get_transform().xform(m_pivotInB) - B->get_transform().origin,
+ normal,
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()));
+ normal[i] = 0;
+ }
+
+ return true;
+}
+
+void PinJointSW::solve(float p_step){
+
+ Vector3 pivotAInW = A->get_transform().xform(m_pivotInA);
+ Vector3 pivotBInW = B->get_transform().xform(m_pivotInB);
+
+
+ Vector3 normal(0,0,0);
+
+
+// Vector3 angvelA = A->get_transform().origin.getBasis().transpose() * A->getAngularVelocity();
+// Vector3 angvelB = B->get_transform().origin.getBasis().transpose() * B->getAngularVelocity();
+
+ for (int i=0;i<3;i++)
+ {
+ normal[i] = 1;
+ real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
+
+ Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
+ Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
+ //this jacobian entry could be re-used for all iterations
+
+ Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
+ Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
+ Vector3 vel = vel1 - vel2;
+
+ real_t rel_vel;
+ rel_vel = normal.dot(vel);
+
+ /*
+ //velocity error (first order error)
+ real_t rel_vel = m_jac[i].getRelativeVelocity(A->getLinearVelocity(),angvelA,
+ B->getLinearVelocity(),angvelB);
+ */
+
+ //positional error (zeroth order error)
+ real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
+
+ real_t impulse = depth*m_tau/p_step * jacDiagABInv - m_damping * rel_vel * jacDiagABInv;
+
+ real_t impulseClamp = m_impulseClamp;
+ if (impulseClamp > 0)
+ {
+ if (impulse < -impulseClamp)
+ impulse = -impulseClamp;
+ if (impulse > impulseClamp)
+ impulse = impulseClamp;
+ }
+
+ m_appliedImpulse+=impulse;
+ Vector3 impulse_vector = normal * impulse;
+ A->apply_impulse(pivotAInW - A->get_transform().origin,impulse_vector);
+ B->apply_impulse(pivotBInW - B->get_transform().origin,-impulse_vector);
+
+ normal[i] = 0;
+ }
+}
+
+void PinJointSW::set_param(PhysicsServer::PinJointParam p_param,float p_value) {
+
+ switch(p_param) {
+ case PhysicsServer::PIN_JOINT_BIAS: m_tau=p_value; break;
+ case PhysicsServer::PIN_JOINT_DAMPING: m_damping=p_value; break;
+ case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP: m_impulseClamp=p_value; break;
+ }
+}
+
+float PinJointSW::get_param(PhysicsServer::PinJointParam p_param) const{
+
+ switch(p_param) {
+ case PhysicsServer::PIN_JOINT_BIAS: return m_tau;
+ case PhysicsServer::PIN_JOINT_DAMPING: return m_damping;
+ case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP: return m_impulseClamp;
+ }
+
+ return 0;
+}
+
+PinJointSW::PinJointSW(BodySW* p_body_a,const Vector3& p_pos_a,BodySW* p_body_b,const Vector3& p_pos_b) : JointSW(_arr,2) {
+
+ A=p_body_a;
+ B=p_body_b;
+ m_pivotInA=p_pos_a;
+ m_pivotInB=p_pos_b;
+
+ m_tau=0.3;
+ m_damping=1;
+ m_impulseClamp=0;
+ m_appliedImpulse=0;
+
+ A->add_constraint(this,0);
+ B->add_constraint(this,1);
+
+
+}
+
+PinJointSW::~PinJointSW() {
+
+
+
+}
diff --git a/servers/physics/joints/pin_joint_sw.h b/servers/physics/joints/pin_joint_sw.h
new file mode 100644
index 0000000000..dae6e7d5f2
--- /dev/null
+++ b/servers/physics/joints/pin_joint_sw.h
@@ -0,0 +1,67 @@
+#ifndef PIN_JOINT_SW_H
+#define PIN_JOINT_SW_H
+
+#include "servers/physics/joints_sw.h"
+#include "servers/physics/joints/jacobian_entry_sw.h"
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+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.
+*/
+
+
+class PinJointSW : public JointSW {
+
+ union {
+ struct {
+ BodySW *A;
+ BodySW *B;
+ };
+
+ BodySW *_arr[2];
+ };
+
+
+ real_t m_tau; //bias
+ real_t m_damping;
+ real_t m_impulseClamp;
+ real_t m_appliedImpulse;
+
+ JacobianEntrySW m_jac[3]; //3 orthogonal linear constraints
+
+ Vector3 m_pivotInA;
+ Vector3 m_pivotInB;
+
+public:
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_PIN; }
+
+ virtual bool setup(float p_step);
+ virtual void solve(float p_step);
+
+ void set_param(PhysicsServer::PinJointParam p_param,float p_value);
+ float get_param(PhysicsServer::PinJointParam p_param) const;
+
+ void set_pos_A(const Vector3& p_pos) { m_pivotInA=p_pos; }
+ void set_pos_B(const Vector3& p_pos) { m_pivotInB=p_pos; }
+
+ Vector3 get_pos_A() { return m_pivotInB; }
+ Vector3 get_pos_B() { return m_pivotInA; }
+
+ PinJointSW(BodySW* p_body_a,const Vector3& p_pos_a,BodySW* p_body_b,const Vector3& p_pos_b);
+ ~PinJointSW();
+};
+
+
+
+#endif // PIN_JOINT_SW_H
diff --git a/servers/physics/joints/slider_joint_sw.cpp b/servers/physics/joints/slider_joint_sw.cpp
new file mode 100644
index 0000000000..faa6875378
--- /dev/null
+++ b/servers/physics/joints/slider_joint_sw.cpp
@@ -0,0 +1,439 @@
+#include "slider_joint_sw.h"
+
+//-----------------------------------------------------------------------------
+
+static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x)
+{
+ real_t coeff_1 = Math_PI / 4.0f;
+ real_t coeff_2 = 3.0f * coeff_1;
+ real_t abs_y = Math::abs(y);
+ real_t angle;
+ if (x >= 0.0f) {
+ real_t r = (x - abs_y) / (x + abs_y);
+ angle = coeff_1 - coeff_1 * r;
+ } else {
+ real_t r = (x + abs_y) / (abs_y - x);
+ angle = coeff_2 - coeff_1 * r;
+ }
+ return (y < 0.0f) ? -angle : angle;
+}
+
+
+void SliderJointSW::initParams()
+{
+ m_lowerLinLimit = real_t(1.0);
+ m_upperLinLimit = real_t(-1.0);
+ m_lowerAngLimit = real_t(0.);
+ m_upperAngLimit = real_t(0.);
+ m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingDirLin = real_t(0.);
+ m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingDirAng = real_t(0.);
+ m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING;
+ m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING;
+ m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING;
+ m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING;
+
+ m_poweredLinMotor = false;
+ m_targetLinMotorVelocity = real_t(0.);
+ m_maxLinMotorForce = real_t(0.);
+ m_accumulatedLinMotorImpulse = real_t(0.0);
+
+ m_poweredAngMotor = false;
+ m_targetAngMotorVelocity = real_t(0.);
+ m_maxAngMotorForce = real_t(0.);
+ m_accumulatedAngMotorImpulse = real_t(0.0);
+
+} // SliderJointSW::initParams()
+
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+
+SliderJointSW::SliderJointSW(BodySW* rbA, BodySW* rbB, const Transform& frameInA, const Transform& frameInB)
+ : JointSW(_arr,2)
+ , m_frameInA(frameInA)
+ , m_frameInB(frameInB)
+{
+
+ A=rbA;
+ B=rbB;
+
+ A->add_constraint(this,0);
+ B->add_constraint(this,1);
+
+ initParams();
+} // SliderJointSW::SliderJointSW()
+
+//-----------------------------------------------------------------------------
+
+bool SliderJointSW::setup(float p_step)
+{
+
+ //calculate transforms
+ m_calculatedTransformA = A->get_transform() * m_frameInA;
+ m_calculatedTransformB = B->get_transform() * m_frameInB;
+ m_realPivotAInW = m_calculatedTransformA.origin;
+ m_realPivotBInW = m_calculatedTransformB.origin;
+ m_sliderAxis = m_calculatedTransformA.basis.get_axis(0); // along X
+ m_delta = m_realPivotBInW - m_realPivotAInW;
+ m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
+ m_relPosA = m_projPivotInW - A->get_transform().origin;
+ m_relPosB = m_realPivotBInW - B->get_transform().origin;
+ Vector3 normalWorld;
+ int i;
+ //linear part
+ for(i = 0; i < 3; i++)
+ {
+ normalWorld = m_calculatedTransformA.basis.get_axis(i);
+ memnew_placement(&m_jacLin[i], JacobianEntrySW(
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ m_relPosA,
+ m_relPosB,
+ normalWorld,
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()
+ ));
+ m_jacLinDiagABInv[i] = real_t(1.) / m_jacLin[i].getDiagonal();
+ m_depth[i] = m_delta.dot(normalWorld);
+ }
+ testLinLimits();
+ // angular part
+ for(i = 0; i < 3; i++)
+ {
+ normalWorld = m_calculatedTransformA.basis.get_axis(i);
+ memnew_placement(&m_jacAng[i], JacobianEntrySW(
+ normalWorld,
+ A->get_transform().basis.transposed(),
+ B->get_transform().basis.transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()
+ ));
+ }
+ testAngLimits();
+ Vector3 axisA = m_calculatedTransformA.basis.get_axis(0);
+ m_kAngle = real_t(1.0 )/ (A->compute_angular_impulse_denominator(axisA) + B->compute_angular_impulse_denominator(axisA));
+ // clear accumulator for motors
+ m_accumulatedLinMotorImpulse = real_t(0.0);
+ m_accumulatedAngMotorImpulse = real_t(0.0);
+
+ return true;
+} // SliderJointSW::buildJacobianInt()
+
+//-----------------------------------------------------------------------------
+
+void SliderJointSW::solve(real_t p_step) {
+
+ int i;
+ // linear
+ Vector3 velA = A->get_velocity_in_local_point(m_relPosA);
+ Vector3 velB = B->get_velocity_in_local_point(m_relPosB);
+ Vector3 vel = velA - velB;
+ for(i = 0; i < 3; i++)
+ {
+ const Vector3& normal = m_jacLin[i].m_linearJointAxis;
+ real_t rel_vel = normal.dot(vel);
+ // calculate positional error
+ real_t depth = m_depth[i];
+ // get parameters
+ real_t softness = (i) ? m_softnessOrthoLin : (m_solveLinLim ? m_softnessLimLin : m_softnessDirLin);
+ real_t restitution = (i) ? m_restitutionOrthoLin : (m_solveLinLim ? m_restitutionLimLin : m_restitutionDirLin);
+ real_t damping = (i) ? m_dampingOrthoLin : (m_solveLinLim ? m_dampingLimLin : m_dampingDirLin);
+ // calcutate and apply impulse
+ real_t normalImpulse = softness * (restitution * depth / p_step - damping * rel_vel) * m_jacLinDiagABInv[i];
+ Vector3 impulse_vector = normal * normalImpulse;
+ A->apply_impulse( m_relPosA, impulse_vector);
+ B->apply_impulse(m_relPosB,-impulse_vector);
+ if(m_poweredLinMotor && (!i))
+ { // apply linear motor
+ if(m_accumulatedLinMotorImpulse < m_maxLinMotorForce)
+ {
+ real_t desiredMotorVel = m_targetLinMotorVelocity;
+ real_t motor_relvel = desiredMotorVel + rel_vel;
+ normalImpulse = -motor_relvel * m_jacLinDiagABInv[i];
+ // clamp accumulated impulse
+ real_t new_acc = m_accumulatedLinMotorImpulse + Math::abs(normalImpulse);
+ if(new_acc > m_maxLinMotorForce)
+ {
+ new_acc = m_maxLinMotorForce;
+ }
+ real_t del = new_acc - m_accumulatedLinMotorImpulse;
+ if(normalImpulse < real_t(0.0))
+ {
+ normalImpulse = -del;
+ }
+ else
+ {
+ normalImpulse = del;
+ }
+ m_accumulatedLinMotorImpulse = new_acc;
+ // apply clamped impulse
+ impulse_vector = normal * normalImpulse;
+ A->apply_impulse( m_relPosA, impulse_vector);
+ B->apply_impulse( m_relPosB,-impulse_vector);
+ }
+ }
+ }
+ // angular
+ // get axes in world space
+ Vector3 axisA = m_calculatedTransformA.basis.get_axis(0);
+ Vector3 axisB = m_calculatedTransformB.basis.get_axis(0);
+
+ const Vector3& angVelA = A->get_angular_velocity();
+ const Vector3& angVelB = B->get_angular_velocity();
+
+ Vector3 angVelAroundAxisA = axisA * axisA.dot(angVelA);
+ Vector3 angVelAroundAxisB = axisB * axisB.dot(angVelB);
+
+ Vector3 angAorthog = angVelA - angVelAroundAxisA;
+ Vector3 angBorthog = angVelB - angVelAroundAxisB;
+ Vector3 velrelOrthog = angAorthog-angBorthog;
+ //solve orthogonal angular velocity correction
+ real_t len = velrelOrthog.length();
+ if (len > real_t(0.00001))
+ {
+ Vector3 normal = velrelOrthog.normalized();
+ real_t denom = A->compute_angular_impulse_denominator(normal) + B->compute_angular_impulse_denominator(normal);
+ velrelOrthog *= (real_t(1.)/denom) * m_dampingOrthoAng * m_softnessOrthoAng;
+ }
+ //solve angular positional correction
+ Vector3 angularError = axisA.cross(axisB) *(real_t(1.)/p_step);
+ real_t len2 = angularError.length();
+ if (len2>real_t(0.00001))
+ {
+ Vector3 normal2 = angularError.normalized();
+ real_t denom2 = A->compute_angular_impulse_denominator(normal2) + B->compute_angular_impulse_denominator(normal2);
+ angularError *= (real_t(1.)/denom2) * m_restitutionOrthoAng * m_softnessOrthoAng;
+ }
+ // apply impulse
+ A->apply_torque_impulse(-velrelOrthog+angularError);
+ B->apply_torque_impulse(velrelOrthog-angularError);
+ real_t impulseMag;
+ //solve angular limits
+ if(m_solveAngLim)
+ {
+ impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingLimAng + m_angDepth * m_restitutionLimAng / p_step;
+ impulseMag *= m_kAngle * m_softnessLimAng;
+ }
+ else
+ {
+ impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingDirAng + m_angDepth * m_restitutionDirAng / p_step;
+ impulseMag *= m_kAngle * m_softnessDirAng;
+ }
+ Vector3 impulse = axisA * impulseMag;
+ A->apply_torque_impulse(impulse);
+ B->apply_torque_impulse(-impulse);
+ //apply angular motor
+ if(m_poweredAngMotor)
+ {
+ if(m_accumulatedAngMotorImpulse < m_maxAngMotorForce)
+ {
+ Vector3 velrel = angVelAroundAxisA - angVelAroundAxisB;
+ real_t projRelVel = velrel.dot(axisA);
+
+ real_t desiredMotorVel = m_targetAngMotorVelocity;
+ real_t motor_relvel = desiredMotorVel - projRelVel;
+
+ real_t angImpulse = m_kAngle * motor_relvel;
+ // clamp accumulated impulse
+ real_t new_acc = m_accumulatedAngMotorImpulse + Math::abs(angImpulse);
+ if(new_acc > m_maxAngMotorForce)
+ {
+ new_acc = m_maxAngMotorForce;
+ }
+ real_t del = new_acc - m_accumulatedAngMotorImpulse;
+ if(angImpulse < real_t(0.0))
+ {
+ angImpulse = -del;
+ }
+ else
+ {
+ angImpulse = del;
+ }
+ m_accumulatedAngMotorImpulse = new_acc;
+ // apply clamped impulse
+ Vector3 motorImp = angImpulse * axisA;
+ A->apply_torque_impulse(motorImp);
+ B->apply_torque_impulse(-motorImp);
+ }
+ }
+} // SliderJointSW::solveConstraint()
+
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+
+void SliderJointSW::calculateTransforms(void){
+ m_calculatedTransformA = A->get_transform() * m_frameInA ;
+ m_calculatedTransformB = B->get_transform() * m_frameInB;
+ m_realPivotAInW = m_calculatedTransformA.origin;
+ m_realPivotBInW = m_calculatedTransformB.origin;
+ m_sliderAxis = m_calculatedTransformA.basis.get_axis(0); // along X
+ m_delta = m_realPivotBInW - m_realPivotAInW;
+ m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
+ Vector3 normalWorld;
+ int i;
+ //linear part
+ for(i = 0; i < 3; i++)
+ {
+ normalWorld = m_calculatedTransformA.basis.get_axis(i);
+ m_depth[i] = m_delta.dot(normalWorld);
+ }
+} // SliderJointSW::calculateTransforms()
+
+//-----------------------------------------------------------------------------
+
+void SliderJointSW::testLinLimits(void)
+{
+ m_solveLinLim = false;
+ m_linPos = m_depth[0];
+ if(m_lowerLinLimit <= m_upperLinLimit)
+ {
+ if(m_depth[0] > m_upperLinLimit)
+ {
+ m_depth[0] -= m_upperLinLimit;
+ m_solveLinLim = true;
+ }
+ else if(m_depth[0] < m_lowerLinLimit)
+ {
+ m_depth[0] -= m_lowerLinLimit;
+ m_solveLinLim = true;
+ }
+ else
+ {
+ m_depth[0] = real_t(0.);
+ }
+ }
+ else
+ {
+ m_depth[0] = real_t(0.);
+ }
+} // SliderJointSW::testLinLimits()
+
+//-----------------------------------------------------------------------------
+
+
+void SliderJointSW::testAngLimits(void)
+{
+ m_angDepth = real_t(0.);
+ m_solveAngLim = false;
+ if(m_lowerAngLimit <= m_upperAngLimit)
+ {
+ const Vector3 axisA0 = m_calculatedTransformA.basis.get_axis(1);
+ const Vector3 axisA1 = m_calculatedTransformA.basis.get_axis(2);
+ const Vector3 axisB0 = m_calculatedTransformB.basis.get_axis(1);
+ real_t rot = atan2fast(axisB0.dot(axisA1), axisB0.dot(axisA0));
+ if(rot < m_lowerAngLimit)
+ {
+ m_angDepth = rot - m_lowerAngLimit;
+ m_solveAngLim = true;
+ }
+ else if(rot > m_upperAngLimit)
+ {
+ m_angDepth = rot - m_upperAngLimit;
+ m_solveAngLim = true;
+ }
+ }
+} // SliderJointSW::testAngLimits()
+
+
+//-----------------------------------------------------------------------------
+
+
+
+Vector3 SliderJointSW::getAncorInA(void)
+{
+ Vector3 ancorInA;
+ ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * real_t(0.5) * m_sliderAxis;
+ ancorInA = A->get_transform().inverse().xform( ancorInA );
+ return ancorInA;
+} // SliderJointSW::getAncorInA()
+
+//-----------------------------------------------------------------------------
+
+Vector3 SliderJointSW::getAncorInB(void)
+{
+ Vector3 ancorInB;
+ ancorInB = m_frameInB.origin;
+ return ancorInB;
+} // SliderJointSW::getAncorInB();
+
+void SliderJointSW::set_param(PhysicsServer::SliderJointParam p_param, float p_value) {
+
+ switch(p_param) {
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: m_upperLinLimit=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: m_lowerLinLimit=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: m_softnessLimLin=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: m_restitutionLimLin=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: m_dampingLimLin=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: m_softnessDirLin=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: m_restitutionDirLin=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: m_dampingDirLin=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: m_softnessOrthoLin=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: m_restitutionOrthoLin=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: m_dampingOrthoLin=p_value; break;
+
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: m_upperAngLimit=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: m_lowerAngLimit=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: m_softnessLimAng=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: m_restitutionLimAng=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: m_dampingLimAng=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: m_softnessDirAng=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: m_restitutionDirAng=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: m_dampingDirAng=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: m_softnessOrthoAng=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: m_restitutionOrthoAng=p_value; break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: m_dampingOrthoAng=p_value; break;
+
+ }
+
+}
+
+float SliderJointSW::get_param(PhysicsServer::SliderJointParam p_param) const {
+
+ switch(p_param) {
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: return m_upperLinLimit;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: return m_lowerLinLimit;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: return m_softnessLimLin;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: return m_restitutionLimLin;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: return m_dampingLimLin;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: return m_softnessDirLin;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: return m_restitutionDirLin;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: return m_dampingDirLin;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: return m_softnessOrthoLin;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: return m_restitutionOrthoLin;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: return m_dampingOrthoLin;
+
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: return m_upperAngLimit;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: return m_lowerAngLimit;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: return m_softnessLimAng;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: return m_restitutionLimAng;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: return m_dampingLimAng;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: return m_softnessDirAng;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: return m_restitutionDirAng;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: return m_dampingDirAng;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: return m_softnessOrthoAng;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: return m_restitutionOrthoAng;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: return m_dampingOrthoAng;
+
+ }
+
+ return 0;
+
+}
+
+
diff --git a/servers/physics/joints/slider_joint_sw.h b/servers/physics/joints/slider_joint_sw.h
new file mode 100644
index 0000000000..517bb5e6bc
--- /dev/null
+++ b/servers/physics/joints/slider_joint_sw.h
@@ -0,0 +1,218 @@
+#ifndef SLIDER_JOINT_SW_H
+#define SLIDER_JOINT_SW_H
+
+#include "servers/physics/joints_sw.h"
+#include "servers/physics/joints/jacobian_entry_sw.h"
+
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+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.
+*/
+
+/*
+Added by Roman Ponomarev (rponom@gmail.com)
+April 04, 2008
+
+*/
+
+#define SLIDER_CONSTRAINT_DEF_SOFTNESS (real_t(1.0))
+#define SLIDER_CONSTRAINT_DEF_DAMPING (real_t(1.0))
+#define SLIDER_CONSTRAINT_DEF_RESTITUTION (real_t(0.7))
+
+//-----------------------------------------------------------------------------
+
+class SliderJointSW : public JointSW {
+protected:
+
+ union {
+ struct {
+ BodySW *A;
+ BodySW *B;
+ };
+
+ BodySW *_arr[2];
+ };
+
+ Transform m_frameInA;
+ Transform m_frameInB;
+
+ // linear limits
+ real_t m_lowerLinLimit;
+ real_t m_upperLinLimit;
+ // angular limits
+ real_t m_lowerAngLimit;
+ real_t m_upperAngLimit;
+ // softness, restitution and damping for different cases
+ // DirLin - moving inside linear limits
+ // LimLin - hitting linear limit
+ // DirAng - moving inside angular limits
+ // LimAng - hitting angular limit
+ // OrthoLin, OrthoAng - against constraint axis
+ real_t m_softnessDirLin;
+ real_t m_restitutionDirLin;
+ real_t m_dampingDirLin;
+ real_t m_softnessDirAng;
+ real_t m_restitutionDirAng;
+ real_t m_dampingDirAng;
+ real_t m_softnessLimLin;
+ real_t m_restitutionLimLin;
+ real_t m_dampingLimLin;
+ real_t m_softnessLimAng;
+ real_t m_restitutionLimAng;
+ real_t m_dampingLimAng;
+ real_t m_softnessOrthoLin;
+ real_t m_restitutionOrthoLin;
+ real_t m_dampingOrthoLin;
+ real_t m_softnessOrthoAng;
+ real_t m_restitutionOrthoAng;
+ real_t m_dampingOrthoAng;
+
+ // for interlal use
+ bool m_solveLinLim;
+ bool m_solveAngLim;
+
+ JacobianEntrySW m_jacLin[3];
+ real_t m_jacLinDiagABInv[3];
+
+ JacobianEntrySW m_jacAng[3];
+
+ real_t m_timeStep;
+ Transform m_calculatedTransformA;
+ Transform m_calculatedTransformB;
+
+ Vector3 m_sliderAxis;
+ Vector3 m_realPivotAInW;
+ Vector3 m_realPivotBInW;
+ Vector3 m_projPivotInW;
+ Vector3 m_delta;
+ Vector3 m_depth;
+ Vector3 m_relPosA;
+ Vector3 m_relPosB;
+
+ real_t m_linPos;
+
+ real_t m_angDepth;
+ real_t m_kAngle;
+
+ bool m_poweredLinMotor;
+ real_t m_targetLinMotorVelocity;
+ real_t m_maxLinMotorForce;
+ real_t m_accumulatedLinMotorImpulse;
+
+ bool m_poweredAngMotor;
+ real_t m_targetAngMotorVelocity;
+ real_t m_maxAngMotorForce;
+ real_t m_accumulatedAngMotorImpulse;
+
+ //------------------------
+ void initParams();
+public:
+ // constructors
+ SliderJointSW(BodySW* rbA, BodySW* rbB, const Transform& frameInA, const Transform& frameInB);
+ //SliderJointSW();
+ // overrides
+
+ // access
+ const BodySW* getRigidBodyA() const { return A; }
+ const BodySW* getRigidBodyB() const { return B; }
+ const Transform & getCalculatedTransformA() const { return m_calculatedTransformA; }
+ const Transform & getCalculatedTransformB() const { return m_calculatedTransformB; }
+ const Transform & getFrameOffsetA() const { return m_frameInA; }
+ const Transform & getFrameOffsetB() const { return m_frameInB; }
+ Transform & getFrameOffsetA() { return m_frameInA; }
+ Transform & getFrameOffsetB() { return m_frameInB; }
+ real_t getLowerLinLimit() { return m_lowerLinLimit; }
+ void setLowerLinLimit(real_t lowerLimit) { m_lowerLinLimit = lowerLimit; }
+ real_t getUpperLinLimit() { return m_upperLinLimit; }
+ void setUpperLinLimit(real_t upperLimit) { m_upperLinLimit = upperLimit; }
+ real_t getLowerAngLimit() { return m_lowerAngLimit; }
+ void setLowerAngLimit(real_t lowerLimit) { m_lowerAngLimit = lowerLimit; }
+ real_t getUpperAngLimit() { return m_upperAngLimit; }
+ void setUpperAngLimit(real_t upperLimit) { m_upperAngLimit = upperLimit; }
+
+ real_t getSoftnessDirLin() { return m_softnessDirLin; }
+ real_t getRestitutionDirLin() { return m_restitutionDirLin; }
+ real_t getDampingDirLin() { return m_dampingDirLin ; }
+ real_t getSoftnessDirAng() { return m_softnessDirAng; }
+ real_t getRestitutionDirAng() { return m_restitutionDirAng; }
+ real_t getDampingDirAng() { return m_dampingDirAng; }
+ real_t getSoftnessLimLin() { return m_softnessLimLin; }
+ real_t getRestitutionLimLin() { return m_restitutionLimLin; }
+ real_t getDampingLimLin() { return m_dampingLimLin; }
+ real_t getSoftnessLimAng() { return m_softnessLimAng; }
+ real_t getRestitutionLimAng() { return m_restitutionLimAng; }
+ real_t getDampingLimAng() { return m_dampingLimAng; }
+ real_t getSoftnessOrthoLin() { return m_softnessOrthoLin; }
+ real_t getRestitutionOrthoLin() { return m_restitutionOrthoLin; }
+ real_t getDampingOrthoLin() { return m_dampingOrthoLin; }
+ real_t getSoftnessOrthoAng() { return m_softnessOrthoAng; }
+ real_t getRestitutionOrthoAng() { return m_restitutionOrthoAng; }
+ real_t getDampingOrthoAng() { return m_dampingOrthoAng; }
+ void setSoftnessDirLin(real_t softnessDirLin) { m_softnessDirLin = softnessDirLin; }
+ void setRestitutionDirLin(real_t restitutionDirLin) { m_restitutionDirLin = restitutionDirLin; }
+ void setDampingDirLin(real_t dampingDirLin) { m_dampingDirLin = dampingDirLin; }
+ void setSoftnessDirAng(real_t softnessDirAng) { m_softnessDirAng = softnessDirAng; }
+ void setRestitutionDirAng(real_t restitutionDirAng) { m_restitutionDirAng = restitutionDirAng; }
+ void setDampingDirAng(real_t dampingDirAng) { m_dampingDirAng = dampingDirAng; }
+ void setSoftnessLimLin(real_t softnessLimLin) { m_softnessLimLin = softnessLimLin; }
+ void setRestitutionLimLin(real_t restitutionLimLin) { m_restitutionLimLin = restitutionLimLin; }
+ void setDampingLimLin(real_t dampingLimLin) { m_dampingLimLin = dampingLimLin; }
+ void setSoftnessLimAng(real_t softnessLimAng) { m_softnessLimAng = softnessLimAng; }
+ void setRestitutionLimAng(real_t restitutionLimAng) { m_restitutionLimAng = restitutionLimAng; }
+ void setDampingLimAng(real_t dampingLimAng) { m_dampingLimAng = dampingLimAng; }
+ void setSoftnessOrthoLin(real_t softnessOrthoLin) { m_softnessOrthoLin = softnessOrthoLin; }
+ void setRestitutionOrthoLin(real_t restitutionOrthoLin) { m_restitutionOrthoLin = restitutionOrthoLin; }
+ void setDampingOrthoLin(real_t dampingOrthoLin) { m_dampingOrthoLin = dampingOrthoLin; }
+ void setSoftnessOrthoAng(real_t softnessOrthoAng) { m_softnessOrthoAng = softnessOrthoAng; }
+ void setRestitutionOrthoAng(real_t restitutionOrthoAng) { m_restitutionOrthoAng = restitutionOrthoAng; }
+ void setDampingOrthoAng(real_t dampingOrthoAng) { m_dampingOrthoAng = dampingOrthoAng; }
+ void setPoweredLinMotor(bool onOff) { m_poweredLinMotor = onOff; }
+ bool getPoweredLinMotor() { return m_poweredLinMotor; }
+ void setTargetLinMotorVelocity(real_t targetLinMotorVelocity) { m_targetLinMotorVelocity = targetLinMotorVelocity; }
+ real_t getTargetLinMotorVelocity() { return m_targetLinMotorVelocity; }
+ void setMaxLinMotorForce(real_t maxLinMotorForce) { m_maxLinMotorForce = maxLinMotorForce; }
+ real_t getMaxLinMotorForce() { return m_maxLinMotorForce; }
+ void setPoweredAngMotor(bool onOff) { m_poweredAngMotor = onOff; }
+ bool getPoweredAngMotor() { return m_poweredAngMotor; }
+ void setTargetAngMotorVelocity(real_t targetAngMotorVelocity) { m_targetAngMotorVelocity = targetAngMotorVelocity; }
+ real_t getTargetAngMotorVelocity() { return m_targetAngMotorVelocity; }
+ void setMaxAngMotorForce(real_t maxAngMotorForce) { m_maxAngMotorForce = maxAngMotorForce; }
+ real_t getMaxAngMotorForce() { return m_maxAngMotorForce; }
+ real_t getLinearPos() { return m_linPos; }
+
+ // access for ODE solver
+ bool getSolveLinLimit() { return m_solveLinLim; }
+ real_t getLinDepth() { return m_depth[0]; }
+ bool getSolveAngLimit() { return m_solveAngLim; }
+ real_t getAngDepth() { return m_angDepth; }
+ // shared code used by ODE solver
+ void calculateTransforms(void);
+ void testLinLimits(void);
+ void testAngLimits(void);
+ // access for PE Solver
+ Vector3 getAncorInA(void);
+ Vector3 getAncorInB(void);
+
+ void set_param(PhysicsServer::SliderJointParam p_param, float p_value);
+ float get_param(PhysicsServer::SliderJointParam p_param) const;
+
+ bool setup(float p_step);
+ void solve(float p_step);
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_SLIDER; }
+
+};
+
+
+#endif // SLIDER_JOINT_SW_H
diff --git a/servers/physics/joints_sw.cpp b/servers/physics/joints_sw.cpp
index f9e22e1665..aa9d3265d2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics/joints_sw.h b/servers/physics/joints_sw.h
index c10568fb52..d7ba6ef925 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,22 +36,12 @@
class JointSW : public ConstraintSW {
- real_t max_force;
- real_t bias;
- real_t max_bias;
-public:
-
- _FORCE_INLINE_ void set_max_force(real_t p_force) { max_force=p_force; }
- _FORCE_INLINE_ real_t get_max_force() const { return max_force; }
- _FORCE_INLINE_ void set_bias(real_t p_bias) { bias=p_bias; }
- _FORCE_INLINE_ real_t get_bias() const { return bias; }
-
- _FORCE_INLINE_ void set_max_bias(real_t p_bias) { max_bias=p_bias; }
- _FORCE_INLINE_ real_t get_max_bias() const { return max_bias; }
+public:
-// virtual PhysicsServer::JointType get_type() const=0;
- JointSW(BodySW **p_body_ptr=NULL,int p_body_count=0) : ConstraintSW(p_body_ptr,p_body_count) { bias=0; max_force=max_bias=3.40282e+38; };
+ virtual PhysicsServer::JointType get_type() const=0;
+ _FORCE_INLINE_ JointSW(BodySW **p_body_ptr=NULL,int p_body_count=0) : ConstraintSW(p_body_ptr,p_body_count) {
+ }
};
diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp
index aff60b5881..a9a8042c19 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,6 +29,12 @@
#include "physics_server_sw.h"
#include "broad_phase_basic.h"
#include "broad_phase_octree.h"
+#include "joints/pin_joint_sw.h"
+#include "joints/hinge_joint_sw.h"
+#include "joints/slider_joint_sw.h"
+#include "joints/cone_twist_joint_sw.h"
+#include "joints/generic_6dof_joint_sw.h"
+
RID PhysicsServerSW::shape_create(ShapeType p_shape) {
@@ -137,6 +143,10 @@ RID PhysicsServerSW::space_create() {
space->set_default_area(area);
area->set_space(space);
area->set_priority(-1);
+ RID sgb = body_create();
+ body_set_space(sgb,id);
+ body_set_mode(sgb,BODY_MODE_STATIC);
+ space->set_static_global_body(sgb);
return id;
};
@@ -191,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 );
@@ -384,6 +418,14 @@ Transform PhysicsServerSW::area_get_transform(RID p_area) const {
return area->get_transform();
};
+void PhysicsServerSW::area_set_monitorable(RID p_area,bool p_monitorable) {
+
+ AreaSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_monitorable(p_monitorable);
+}
+
void PhysicsServerSW::area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) {
AreaSW *area = area_owner.get(p_area);
@@ -394,6 +436,33 @@ void PhysicsServerSW::area_set_monitor_callback(RID p_area,Object *p_receiver,co
}
+void PhysicsServerSW::area_set_ray_pickable(RID p_area,bool p_enable) {
+
+ AreaSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_ray_pickable(p_enable);
+
+}
+
+bool PhysicsServerSW::area_is_ray_pickable(RID p_area) const{
+
+ AreaSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area,false);
+
+ return area->is_ray_pickable();
+
+}
+
+
+void PhysicsServerSW::area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) {
+
+
+ AreaSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_area_monitor_callback(p_receiver?p_receiver->get_instance_ID():0,p_method);
+}
/* BODY API */
@@ -511,6 +580,8 @@ void PhysicsServerSW::body_set_shape_as_trigger(RID p_body, int p_shape_idx,bool
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
+ ERR_FAIL_INDEX(p_shape_idx,body->get_shape_count());
+ body->set_shape_as_trigger(p_shape_idx,p_enable);
}
@@ -518,10 +589,9 @@ bool PhysicsServerSW::body_is_shape_set_as_trigger(RID p_body, int p_shape_idx)
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body,false);
+ ERR_FAIL_INDEX_V(p_shape_idx,body->get_shape_count(),false);
- // todo ?
-
- return false;
+ return body->is_shape_set_as_trigger(p_shape_idx);
}
@@ -568,6 +638,26 @@ bool PhysicsServerSW::body_is_continuous_collision_detection_enabled(RID p_body)
return body->is_continuous_collision_detection_enabled();
}
+void PhysicsServerSW::body_set_layer_mask(RID p_body, uint32_t p_mask) {
+
+ BodySW *body = body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_layer_mask(p_mask);
+ body->wakeup();
+
+}
+
+uint32_t PhysicsServerSW::body_get_layer_mask(RID p_body, uint32_t p_mask) const{
+
+ const BodySW *body = body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body,0);
+
+ return body->get_layer_mask();
+
+}
+
+
void PhysicsServerSW::body_attach_object_instance_ID(RID p_body,uint32_t p_ID) {
BodySW *body = body_owner.get(p_body);
@@ -618,13 +708,6 @@ float PhysicsServerSW::body_get_param(RID p_body, BodyParameter p_param) const {
};
-void PhysicsServerSW::body_static_simulate_motion(RID p_body,const Transform& p_new_transform) {
-
- BodySW *body = body_owner.get(p_body);
- ERR_FAIL_COND(!body);
- body->simulate_motion(p_new_transform,last_step);
-
-};
void PhysicsServerSW::body_set_state(RID p_body, BodyState p_state, const Variant& p_variant) {
@@ -632,6 +715,7 @@ void PhysicsServerSW::body_set_state(RID p_body, BodyState p_state, const Varian
ERR_FAIL_COND(!body);
body->set_state(p_state,p_variant);
+
};
Variant PhysicsServerSW::body_get_state(RID p_body, BodyState p_state) const {
@@ -649,6 +733,7 @@ void PhysicsServerSW::body_set_applied_force(RID p_body, const Vector3& p_force)
ERR_FAIL_COND(!body);
body->set_applied_force(p_force);
+ body->wakeup();
};
Vector3 PhysicsServerSW::body_get_applied_force(RID p_body) const {
@@ -664,6 +749,7 @@ void PhysicsServerSW::body_set_applied_torque(RID p_body, const Vector3& p_torqu
ERR_FAIL_COND(!body);
body->set_applied_torque(p_torque);
+ body->wakeup();
};
Vector3 PhysicsServerSW::body_get_applied_torque(RID p_body) const {
@@ -680,6 +766,7 @@ void PhysicsServerSW::body_apply_impulse(RID p_body, const Vector3& p_pos, const
ERR_FAIL_COND(!body);
body->apply_impulse(p_pos,p_impulse);
+ body->wakeup();
};
void PhysicsServerSW::body_set_axis_velocity(RID p_body, const Vector3& p_axis_velocity) {
@@ -692,6 +779,7 @@ void PhysicsServerSW::body_set_axis_velocity(RID p_body, const Vector3& p_axis_v
v-=axis*axis.dot(v);
v+=p_axis_velocity;
body->set_linear_velocity(v);
+ body->wakeup();
};
@@ -701,6 +789,7 @@ void PhysicsServerSW::body_set_axis_lock(RID p_body,BodyAxisLock p_lock) {
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_axis_lock(p_lock);
+ body->wakeup();
}
@@ -720,6 +809,7 @@ void PhysicsServerSW::body_add_collision_exception(RID p_body, RID p_body_b) {
ERR_FAIL_COND(!body);
body->add_exception(p_body_b);
+ body->wakeup();
};
@@ -728,7 +818,8 @@ void PhysicsServerSW::body_remove_collision_exception(RID p_body, RID p_body_b)
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
- body->remove_exception(p_body);
+ body->remove_exception(p_body_b);
+ body->wakeup();
};
@@ -795,9 +886,342 @@ void PhysicsServerSW::body_set_force_integration_callback(RID p_body,Object *p_r
}
+void PhysicsServerSW::body_set_ray_pickable(RID p_body,bool p_enable) {
+
+ BodySW *body = body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_ray_pickable(p_enable);
+
+}
+
+bool PhysicsServerSW::body_is_ray_pickable(RID p_body) const{
+
+ BodySW *body = body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body,false);
+ return body->is_ray_pickable();
+
+}
+
/* JOINT API */
+RID PhysicsServerSW::joint_create_pin(RID p_body_A,const Vector3& p_local_A,RID p_body_B,const Vector3& p_local_B) {
+
+ BodySW *body_A = body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A,RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(),RID());
+ p_body_B=body_A->get_space()->get_static_global_body();
+ }
+
+ BodySW *body_B = body_owner.get(p_body_B);
+ ERR_FAIL_COND_V(!body_B,RID());
+
+ ERR_FAIL_COND_V(body_A==body_B,RID());
+
+ JointSW *joint = memnew( PinJointSW(body_A,p_local_A,body_B,p_local_B) );
+ RID rid = joint_owner.make_rid(joint);
+ joint->set_self(rid);
+ return rid;
+}
+
+void PhysicsServerSW::pin_joint_set_param(RID p_joint,PinJointParam p_param, float p_value){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_PIN);
+ PinJointSW *pin_joint = static_cast<PinJointSW*>(joint);
+ pin_joint->set_param(p_param,p_value);
+
+}
+float PhysicsServerSW::pin_joint_get_param(RID p_joint,PinJointParam p_param) const{
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,0);
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_PIN,0);
+ PinJointSW *pin_joint = static_cast<PinJointSW*>(joint);
+ return pin_joint->get_param(p_param);
+
+}
+
+void PhysicsServerSW::pin_joint_set_local_A(RID p_joint, const Vector3& p_A){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_PIN);
+ PinJointSW *pin_joint = static_cast<PinJointSW*>(joint);
+ pin_joint->set_pos_A(p_A);
+
+}
+Vector3 PhysicsServerSW::pin_joint_get_local_A(RID p_joint) const{
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,Vector3());
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_PIN,Vector3());
+ PinJointSW *pin_joint = static_cast<PinJointSW*>(joint);
+ return pin_joint->get_pos_A();
+
+}
+
+void PhysicsServerSW::pin_joint_set_local_B(RID p_joint, const Vector3& p_B){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_PIN);
+ PinJointSW *pin_joint = static_cast<PinJointSW*>(joint);
+ pin_joint->set_pos_B(p_B);
+
+}
+Vector3 PhysicsServerSW::pin_joint_get_local_B(RID p_joint) const{
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,Vector3());
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_PIN,Vector3());
+ PinJointSW *pin_joint = static_cast<PinJointSW*>(joint);
+ return pin_joint->get_pos_B();
+
+}
+
+
+RID PhysicsServerSW::joint_create_hinge(RID p_body_A,const Transform& p_frame_A,RID p_body_B,const Transform& p_frame_B) {
+
+ BodySW *body_A = body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A,RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(),RID());
+ p_body_B=body_A->get_space()->get_static_global_body();
+ }
+
+ BodySW *body_B = body_owner.get(p_body_B);
+ ERR_FAIL_COND_V(!body_B,RID());
+
+ ERR_FAIL_COND_V(body_A==body_B,RID());
+
+ JointSW *joint = memnew( HingeJointSW(body_A,body_B,p_frame_A,p_frame_B) );
+ RID rid = joint_owner.make_rid(joint);
+ joint->set_self(rid);
+ return rid;
+
+}
+
+
+RID PhysicsServerSW::joint_create_hinge_simple(RID p_body_A,const Vector3& p_pivot_A,const Vector3& p_axis_A,RID p_body_B,const Vector3& p_pivot_B,const Vector3& p_axis_B) {
+
+ BodySW *body_A = body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A,RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(),RID());
+ p_body_B=body_A->get_space()->get_static_global_body();
+ }
+
+ BodySW *body_B = body_owner.get(p_body_B);
+ ERR_FAIL_COND_V(!body_B,RID());
+
+ ERR_FAIL_COND_V(body_A==body_B,RID());
+
+ JointSW *joint = memnew( HingeJointSW(body_A,body_B,p_pivot_A,p_pivot_B,p_axis_A,p_axis_B) );
+ RID rid = joint_owner.make_rid(joint);
+ joint->set_self(rid);
+ return rid;
+
+}
+
+void PhysicsServerSW::hinge_joint_set_param(RID p_joint,HingeJointParam p_param, float p_value){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_HINGE);
+ HingeJointSW *hinge_joint = static_cast<HingeJointSW*>(joint);
+ hinge_joint->set_param(p_param,p_value);
+
+}
+float PhysicsServerSW::hinge_joint_get_param(RID p_joint,HingeJointParam p_param) const{
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,0);
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_HINGE,0);
+ HingeJointSW *hinge_joint = static_cast<HingeJointSW*>(joint);
+ return hinge_joint->get_param(p_param);
+
+}
+
+void PhysicsServerSW::hinge_joint_set_flag(RID p_joint,HingeJointFlag p_flag, bool p_value){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_HINGE);
+ HingeJointSW *hinge_joint = static_cast<HingeJointSW*>(joint);
+ hinge_joint->set_flag(p_flag,p_value);
+
+}
+bool PhysicsServerSW::hinge_joint_get_flag(RID p_joint,HingeJointFlag p_flag) const{
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,false);
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_HINGE,false);
+ HingeJointSW *hinge_joint = static_cast<HingeJointSW*>(joint);
+ return hinge_joint->get_flag(p_flag);
+}
+
+void PhysicsServerSW::joint_set_solver_priority(RID p_joint,int p_priority) {
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ joint->set_priority(p_priority);
+}
+
+int PhysicsServerSW::joint_get_solver_priority(RID p_joint) const{
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,0);
+ return joint->get_priority();
+
+}
+
+PhysicsServerSW::JointType PhysicsServerSW::joint_get_type(RID p_joint) const {
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,JOINT_PIN);
+ return joint->get_type();
+}
+
+RID PhysicsServerSW::joint_create_slider(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B) {
+
+ BodySW *body_A = body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A,RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(),RID());
+ p_body_B=body_A->get_space()->get_static_global_body();
+ }
+
+ BodySW *body_B = body_owner.get(p_body_B);
+ ERR_FAIL_COND_V(!body_B,RID());
+
+ ERR_FAIL_COND_V(body_A==body_B,RID());
+
+ JointSW *joint = memnew( SliderJointSW(body_A,body_B,p_local_frame_A,p_local_frame_B) );
+ RID rid = joint_owner.make_rid(joint);
+ joint->set_self(rid);
+ return rid;
+}
+
+void PhysicsServerSW::slider_joint_set_param(RID p_joint,SliderJointParam p_param, float p_value){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_SLIDER);
+ SliderJointSW *slider_joint = static_cast<SliderJointSW*>(joint);
+ slider_joint->set_param(p_param,p_value);
+}
+float PhysicsServerSW::slider_joint_get_param(RID p_joint,SliderJointParam p_param) const{
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,0);
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_CONE_TWIST,0);
+ SliderJointSW *slider_joint = static_cast<SliderJointSW*>(joint);
+ return slider_joint->get_param(p_param);
+}
+
+
+RID PhysicsServerSW::joint_create_cone_twist(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B) {
+
+ BodySW *body_A = body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A,RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(),RID());
+ p_body_B=body_A->get_space()->get_static_global_body();
+ }
+
+ BodySW *body_B = body_owner.get(p_body_B);
+ ERR_FAIL_COND_V(!body_B,RID());
+
+ ERR_FAIL_COND_V(body_A==body_B,RID());
+
+ JointSW *joint = memnew( ConeTwistJointSW(body_A,body_B,p_local_frame_A,p_local_frame_B) );
+ RID rid = joint_owner.make_rid(joint);
+ joint->set_self(rid);
+ return rid;
+}
+
+void PhysicsServerSW::cone_twist_joint_set_param(RID p_joint,ConeTwistJointParam p_param, float p_value) {
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_CONE_TWIST);
+ ConeTwistJointSW *cone_twist_joint = static_cast<ConeTwistJointSW*>(joint);
+ cone_twist_joint->set_param(p_param,p_value);
+}
+float PhysicsServerSW::cone_twist_joint_get_param(RID p_joint,ConeTwistJointParam p_param) const {
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,0);
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_CONE_TWIST,0);
+ ConeTwistJointSW *cone_twist_joint = static_cast<ConeTwistJointSW*>(joint);
+ return cone_twist_joint->get_param(p_param);
+}
+
+
+RID PhysicsServerSW::joint_create_generic_6dof(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B) {
+
+ BodySW *body_A = body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A,RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(),RID());
+ p_body_B=body_A->get_space()->get_static_global_body();
+ }
+
+ BodySW *body_B = body_owner.get(p_body_B);
+ ERR_FAIL_COND_V(!body_B,RID());
+
+ ERR_FAIL_COND_V(body_A==body_B,RID());
+
+ JointSW *joint = memnew( Generic6DOFJointSW(body_A,body_B,p_local_frame_A,p_local_frame_B,true) );
+ RID rid = joint_owner.make_rid(joint);
+ joint->set_self(rid);
+ return rid;
+}
+
+void PhysicsServerSW::generic_6dof_joint_set_param(RID p_joint,Vector3::Axis p_axis,G6DOFJointAxisParam p_param, float p_value){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_6DOF);
+ Generic6DOFJointSW *generic_6dof_joint = static_cast<Generic6DOFJointSW*>(joint);
+ generic_6dof_joint->set_param(p_axis,p_param,p_value);
+}
+float PhysicsServerSW::generic_6dof_joint_get_param(RID p_joint,Vector3::Axis p_axis,G6DOFJointAxisParam p_param){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,0);
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_6DOF,0);
+ Generic6DOFJointSW *generic_6dof_joint = static_cast<Generic6DOFJointSW*>(joint);
+ return generic_6dof_joint->get_param(p_axis,p_param);
+}
+
+void PhysicsServerSW::generic_6dof_joint_set_flag(RID p_joint,Vector3::Axis p_axis,G6DOFJointAxisFlag p_flag, bool p_enable){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type()!=JOINT_6DOF);
+ Generic6DOFJointSW *generic_6dof_joint = static_cast<Generic6DOFJointSW*>(joint);
+ generic_6dof_joint->set_flag(p_axis,p_flag,p_enable);
+}
+bool PhysicsServerSW::generic_6dof_joint_get_flag(RID p_joint,Vector3::Axis p_axis,G6DOFJointAxisFlag p_flag){
+
+ JointSW *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint,false);
+ ERR_FAIL_COND_V(joint->get_type()!=JOINT_6DOF,false);
+ Generic6DOFJointSW *generic_6dof_joint = static_cast<Generic6DOFJointSW*>(joint);
+ return generic_6dof_joint->get_flag(p_axis,p_flag);
+}
+
+
#if 0
void PhysicsServerSW::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) {
@@ -976,12 +1400,18 @@ void PhysicsServerSW::free(RID p_rid) {
active_spaces.erase(space);
free(space->get_default_area()->get_self());
+ free(space->get_static_global_body());
+
space_owner.free(p_rid);
memdelete(space);
} else if (joint_owner.owns(p_rid)) {
JointSW *joint = joint_owner.get(p_rid);
+ for(int i=0;i<joint->get_body_count();i++) {
+
+ joint->get_body_ptr()[i]->remove_constraint(joint);
+ }
joint_owner.free(p_rid);
memdelete(joint);
@@ -1021,11 +1451,18 @@ void PhysicsServerSW::step(float p_step) {
last_step=p_step;
PhysicsDirectBodyStateSW::singleton->step=p_step;
+ island_count=0;
+ active_objects=0;
+ collision_pairs=0;
for( Set<const SpaceSW*>::Element *E=active_spaces.front();E;E=E->next()) {
stepper->step((SpaceSW*)E->get(),p_step,iterations);
+ island_count+=E->get()->get_island_count();
+ active_objects+=E->get()->get_active_objects();
+ collision_pairs+=E->get()->get_collision_pairs();
}
-};
+
+}
void PhysicsServerSW::sync() {
@@ -1054,9 +1491,72 @@ void PhysicsServerSW::finish() {
};
+int PhysicsServerSW::get_process_info(ProcessInfo p_info) {
+
+ switch(p_info) {
+
+ case INFO_ACTIVE_OBJECTS: {
+
+ return active_objects;
+ } break;
+ case INFO_COLLISION_PAIRS: {
+ return collision_pairs;
+ } break;
+ case INFO_ISLAND_COUNT: {
+
+ return island_count;
+ } break;
+
+ }
+
+ return 0;
+}
+
+
+void PhysicsServerSW::_shape_col_cbk(const Vector3& p_point_A,const Vector3& p_point_B,void *p_userdata) {
+
+
+ CollCbkData *cbk=(CollCbkData *)p_userdata;
+
+ if (cbk->max==0)
+ return;
+
+ if (cbk->amount == cbk->max) {
+ //find least deep
+ float min_depth=1e20;
+ int min_depth_idx=0;
+ for(int i=0;i<cbk->amount;i++) {
+
+ float d = cbk->ptr[i*2+0].distance_squared_to(cbk->ptr[i*2+1]);
+ if (d<min_depth) {
+ min_depth=d;
+ min_depth_idx=i;
+ }
+
+ }
+
+ float d = p_point_A.distance_squared_to(p_point_B);
+ if (d<min_depth)
+ return;
+ cbk->ptr[min_depth_idx*2+0]=p_point_A;
+ cbk->ptr[min_depth_idx*2+1]=p_point_B;
+
+
+ } else {
+
+ cbk->ptr[cbk->amount*2+0]=p_point_A;
+ cbk->ptr[cbk->amount*2+1]=p_point_B;
+ cbk->amount++;
+ }
+}
+
+
PhysicsServerSW::PhysicsServerSW() {
BroadPhaseSW::create_func=BroadPhaseOctree::_create;
+ island_count=0;
+ active_objects=0;
+ collision_pairs=0;
active=true;
diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h
index 0822d76936..abbb057616 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,6 +47,10 @@ friend class PhysicsDirectSpaceStateSW;
bool doing_sync;
real_t last_step;
+ int island_count;
+ int active_objects;
+ int collision_pairs;
+
StepSW *stepper;
Set<const SpaceSW*> active_spaces;
@@ -61,6 +65,15 @@ friend class PhysicsDirectSpaceStateSW;
// void _clear_query(QuerySW *p_query);
public:
+ struct CollCbkData {
+
+ int max;
+ int amount;
+ Vector3 *ptr;
+ };
+
+ static void _shape_col_cbk(const Vector3& p_point_A,const Vector3& p_point_B,void *p_userdata);
+
virtual RID shape_create(ShapeType p_shape);
virtual void shape_set_data(RID p_shape, const Variant& p_data);
virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias);
@@ -81,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 */
@@ -112,7 +128,13 @@ public:
virtual Variant area_get_param(RID p_parea,AreaParameter p_param) const;
virtual Transform area_get_transform(RID p_area) const;
+ virtual void area_set_ray_pickable(RID p_area,bool p_enable);
+ virtual bool area_is_ray_pickable(RID p_area) const;
+
+ virtual void area_set_monitorable(RID p_area,bool p_monitorable);
+
virtual void area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method);
+ virtual void area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method);
/* BODY API */
@@ -146,15 +168,15 @@ public:
virtual void body_set_enable_continuous_collision_detection(RID p_body,bool p_enable);
virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const;
+ virtual void body_set_layer_mask(RID p_body, uint32_t p_mask);
+ virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const;
+
virtual void body_set_user_flags(RID p_body, uint32_t p_flags);
virtual uint32_t body_get_user_flags(RID p_body, uint32_t p_flags) const;
virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value);
virtual float body_get_param(RID p_body, BodyParameter p_param) const;
- //advanced simulation
- virtual void body_static_simulate_motion(RID p_body,const Transform& p_new_transform);
-
virtual void body_set_state(RID p_body, BodyState p_state, const Variant& p_variant);
virtual Variant body_get_state(RID p_body, BodyState p_state) const;
@@ -185,7 +207,55 @@ public:
virtual void body_set_force_integration_callback(RID p_body,Object *p_receiver,const StringName& p_method,const Variant& p_udata=Variant());
+ virtual void body_set_ray_pickable(RID p_body,bool p_enable);
+ virtual bool body_is_ray_pickable(RID p_body) const;
+
/* JOINT API */
+
+ virtual RID joint_create_pin(RID p_body_A,const Vector3& p_local_A,RID p_body_B,const Vector3& p_local_B);
+
+ virtual void pin_joint_set_param(RID p_joint,PinJointParam p_param, float p_value);
+ virtual float pin_joint_get_param(RID p_joint,PinJointParam p_param) const;
+
+ virtual void pin_joint_set_local_A(RID p_joint, const Vector3& p_A);
+ virtual Vector3 pin_joint_get_local_A(RID p_joint) const;
+
+ virtual void pin_joint_set_local_B(RID p_joint, const Vector3& p_B);
+ virtual Vector3 pin_joint_get_local_B(RID p_joint) const;
+
+ virtual RID joint_create_hinge(RID p_body_A,const Transform& p_frame_A,RID p_body_B,const Transform& p_frame_B);
+ virtual RID joint_create_hinge_simple(RID p_body_A,const Vector3& p_pivot_A,const Vector3& p_axis_A,RID p_body_B,const Vector3& p_pivot_B,const Vector3& p_axis_B);
+
+ virtual void hinge_joint_set_param(RID p_joint,HingeJointParam p_param, float p_value);
+ virtual float hinge_joint_get_param(RID p_joint,HingeJointParam p_param) const;
+
+ virtual void hinge_joint_set_flag(RID p_joint,HingeJointFlag p_flag, bool p_value);
+ virtual bool hinge_joint_get_flag(RID p_joint,HingeJointFlag p_flag) const;
+
+
+ virtual RID joint_create_slider(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B); //reference frame is A
+
+ virtual void slider_joint_set_param(RID p_joint,SliderJointParam p_param, float p_value);
+ virtual float slider_joint_get_param(RID p_joint,SliderJointParam p_param) const;
+
+ virtual RID joint_create_cone_twist(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B); //reference frame is A
+
+ virtual void cone_twist_joint_set_param(RID p_joint,ConeTwistJointParam p_param, float p_value);
+ virtual float cone_twist_joint_get_param(RID p_joint,ConeTwistJointParam p_param) const;
+
+ virtual RID joint_create_generic_6dof(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B); //reference frame is A
+
+ virtual void generic_6dof_joint_set_param(RID p_joint,Vector3::Axis,G6DOFJointAxisParam p_param, float p_value);
+ virtual float generic_6dof_joint_get_param(RID p_joint,Vector3::Axis,G6DOFJointAxisParam p_param);
+
+ virtual void generic_6dof_joint_set_flag(RID p_joint,Vector3::Axis,G6DOFJointAxisFlag p_flag, bool p_enable);
+ virtual bool generic_6dof_joint_get_flag(RID p_joint,Vector3::Axis,G6DOFJointAxisFlag p_flag);
+
+ virtual JointType joint_get_type(RID p_joint) const;
+
+ virtual void joint_set_solver_priority(RID p_joint,int p_priority);
+ virtual int joint_get_solver_priority(RID p_joint) const;
+
#if 0
virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value);
virtual real_t joint_get_param(RID p_joint,JointParam p_param) const;
@@ -209,6 +279,8 @@ public:
virtual void flush_queries();
virtual void finish();
+ int get_process_info(ProcessInfo p_info);
+
PhysicsServerSW();
~PhysicsServerSW();
diff --git a/servers/physics/shape_sw.cpp b/servers/physics/shape_sw.cpp
index 70e5c00b92..fabfa88ee5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,1639 +26,1658 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "shape_sw.h"
-#include "geometry.h"
-#include "sort.h"
-#include "quick_hull.h"
-#define _POINT_SNAP 0.001953125
-#define _EDGE_IS_VALID_SUPPORT_TRESHOLD 0.0002
-#define _FACE_IS_VALID_SUPPORT_TRESHOLD 0.9998
-
-
-void ShapeSW::configure(const AABB& p_aabb) {
- aabb=p_aabb;
- configured=true;
- for (Map<ShapeOwnerSW*,int>::Element *E=owners.front();E;E=E->next()) {
- ShapeOwnerSW* co=(ShapeOwnerSW*)E->key();
- co->_shape_changed();
- }
-}
-
-
-Vector3 ShapeSW::get_support(const Vector3& p_normal) const {
-
- Vector3 res;
- int amnt;
- get_supports(p_normal,1,&res,amnt);
- return res;
-}
-
-void ShapeSW::add_owner(ShapeOwnerSW *p_owner) {
-
- Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
- if (E) {
- E->get()++;
- } else {
- owners[p_owner]=1;
- }
-}
-
-void ShapeSW::remove_owner(ShapeOwnerSW *p_owner){
-
- Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
- ERR_FAIL_COND(!E);
- E->get()--;
- if (E->get()==0) {
- owners.erase(E);
- }
-
-}
-
-bool ShapeSW::is_owner(ShapeOwnerSW *p_owner) const{
-
- return owners.has(p_owner);
-
-}
-
-const Map<ShapeOwnerSW*,int>& ShapeSW::get_owners() const{
- return owners;
-}
-
-
-ShapeSW::ShapeSW() {
-
- custom_bias=0;
- configured=false;
-}
-
-
-ShapeSW::~ShapeSW() {
-
- ERR_FAIL_COND(owners.size());
-}
-
-
-
-Plane PlaneShapeSW::get_plane() const {
-
- return plane;
-}
-
-void PlaneShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- // gibberish, a plane is infinity
- r_min=-1e7;
- r_max=1e7;
-}
-
-Vector3 PlaneShapeSW::get_support(const Vector3& p_normal) const {
-
- return p_normal*1e15;
-}
-
-
-bool PlaneShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- bool inters=plane.intersects_segment(p_begin,p_end,&r_result);
- if(inters)
- r_normal=plane.normal;
- return inters;
-}
-
-Vector3 PlaneShapeSW::get_moment_of_inertia(float p_mass) const {
-
- return Vector3(); //wtf
-}
-
-void PlaneShapeSW::_setup(const Plane& p_plane) {
-
- plane=p_plane;
- configure(AABB(Vector3(-1e4,-1e4,-1e4),Vector3(1e4*2,1e4*2,1e4*2)));
-}
-
-void PlaneShapeSW::set_data(const Variant& p_data) {
-
- _setup(p_data);
-
-}
-
-Variant PlaneShapeSW::get_data() const {
-
- return plane;
-}
-
-PlaneShapeSW::PlaneShapeSW() {
-
-
-}
-
-//
-
-float RayShapeSW::get_length() const {
-
- return length;
-}
-
-void RayShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- // don't think this will be even used
- r_min=0;
- r_max=1;
-}
-
-Vector3 RayShapeSW::get_support(const Vector3& p_normal) const {
-
- if (p_normal.z>0)
- return Vector3(0,0,length);
- else
- return Vector3(0,0,0);
-}
-
-void RayShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
- r_amount=2;
- r_supports[0]=Vector3(0,0,0);
- r_supports[1]=Vector3(0,0,length);
- } if (p_normal.z>0) {
- r_amount=1;
- *r_supports=Vector3(0,0,length);
- } else {
- r_amount=1;
- *r_supports=Vector3(0,0,0);
- }
-}
-
-
-bool RayShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- return false; //simply not possible
-}
-
-Vector3 RayShapeSW::get_moment_of_inertia(float p_mass) const {
-
- return Vector3();
-}
-
-void RayShapeSW::_setup(float p_length) {
-
- length=p_length;
- configure(AABB(Vector3(0,0,0),Vector3(0.1,0.1,length)));
-}
-
-void RayShapeSW::set_data(const Variant& p_data) {
-
- _setup(p_data);
-
-}
-
-Variant RayShapeSW::get_data() const {
-
- return length;
-}
-
-RayShapeSW::RayShapeSW() {
-
- length=1;
-}
-
-
-
-/********** SPHERE *************/
-
-real_t SphereShapeSW::get_radius() const {
-
- return radius;
-}
-
-void SphereShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- float d = p_normal.dot( p_transform.origin );
-
- // figure out scale at point
- Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
- float scale = local_normal.length();
-
- r_min = d - (radius) * scale;
- r_max = d + (radius) * scale;
-
-}
-
-Vector3 SphereShapeSW::get_support(const Vector3& p_normal) const {
-
- return p_normal*radius;
-}
-
-void SphereShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- *r_supports=p_normal*radius;
- r_amount=1;
-}
-
-bool SphereShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- return Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(),radius,&r_result,&r_normal);
-}
-
-Vector3 SphereShapeSW::get_moment_of_inertia(float p_mass) const {
-
- float s = 0.4 * p_mass * radius * radius;
- return Vector3(s,s,s);
-}
-
-void SphereShapeSW::_setup(real_t p_radius) {
-
-
- radius=p_radius;
- configure(AABB( Vector3(-radius,-radius,-radius), Vector3(radius*2.0,radius*2.0,radius*2.0)));
-
-}
-
-void SphereShapeSW::set_data(const Variant& p_data) {
-
- _setup(p_data);
-}
-
-Variant SphereShapeSW::get_data() const {
-
- return radius;
-}
-
-SphereShapeSW::SphereShapeSW() {
-
- radius=0;
-}
-
-
-/********** BOX *************/
-
-
-void BoxShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- // no matter the angle, the box is mirrored anyway
- Vector3 local_normal=p_transform.basis.xform_inv(p_normal);
-
- float length = local_normal.abs().dot(half_extents);
- float distance = p_normal.dot( p_transform.origin );
-
- r_min = distance - length;
- r_max = distance + length;
-
-
-}
-
-Vector3 BoxShapeSW::get_support(const Vector3& p_normal) const {
-
-
- Vector3 point(
- (p_normal.x<0) ? -half_extents.x : half_extents.x,
- (p_normal.y<0) ? -half_extents.y : half_extents.y,
- (p_normal.z<0) ? -half_extents.z : half_extents.z
- );
-
- return point;
-}
-
-void BoxShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- static const int next[3]={1,2,0};
- static const int next2[3]={2,0,1};
-
- for (int i=0;i<3;i++) {
-
- Vector3 axis;
- axis[i]=1.0;
- float dot = p_normal.dot( axis );
- if ( Math::abs( dot ) > _FACE_IS_VALID_SUPPORT_TRESHOLD ) {
-
- //Vector3 axis_b;
-
- bool neg = dot<0;
- r_amount = 4;
-
- Vector3 point;
- point[i]=half_extents[i];
-
- int i_n=next[i];
- int i_n2=next2[i];
-
- static const float sign[4][2]={
-
- {-1.0, 1.0},
- { 1.0, 1.0},
- { 1.0,-1.0},
- {-1.0,-1.0},
- };
-
- for (int j=0;j<4;j++) {
-
- point[i_n]=sign[j][0]*half_extents[i_n];
- point[i_n2]=sign[j][1]*half_extents[i_n2];
- r_supports[j]=neg?-point:point;
-
- }
-
- if (neg) {
- SWAP( r_supports[1], r_supports[2] );
- SWAP( r_supports[0], r_supports[3] );
- }
-
- return;
- }
-
- r_amount=0;
-
- }
-
- for (int i=0;i<3;i++) {
-
- Vector3 axis;
- axis[i]=1.0;
-
- if (Math::abs(p_normal.dot(axis))<_EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
- r_amount= 2;
-
- int i_n=next[i];
- int i_n2=next2[i];
-
- Vector3 point=half_extents;
-
- if (p_normal[i_n]<0) {
- point[i_n]=-point[i_n];
- }
- if (p_normal[i_n2]<0) {
- point[i_n2]=-point[i_n2];
- }
-
- r_supports[0] = point;
- point[i]=-point[i];
- r_supports[1] = point;
- return;
- }
- }
- /* USE POINT */
-
- Vector3 point(
- (p_normal.x<0) ? -half_extents.x : half_extents.x,
- (p_normal.y<0) ? -half_extents.y : half_extents.y,
- (p_normal.z<0) ? -half_extents.z : half_extents.z
- );
-
- r_amount=1;
- r_supports[0]=point;
-}
-
-bool BoxShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- AABB aabb(-half_extents,half_extents*2.0);
-
- return aabb.intersects_segment(p_begin,p_end,&r_result,&r_normal);
-
-}
-
-Vector3 BoxShapeSW::get_moment_of_inertia(float p_mass) const {
-
- float lx=half_extents.x;
- float ly=half_extents.y;
- float lz=half_extents.z;
-
- return Vector3( (p_mass/3.0) * (ly*ly + lz*lz), (p_mass/3.0) * (lx*lx + lz*lz), (p_mass/3.0) * (lx*lx + ly*ly) );
-
-}
-
-void BoxShapeSW::_setup(const Vector3& p_half_extents) {
-
- half_extents=p_half_extents.abs();
-
- configure(AABB(-half_extents,half_extents*2));
-
-
-}
-
-void BoxShapeSW::set_data(const Variant& p_data) {
-
-
- _setup(p_data);
-}
-
-Variant BoxShapeSW::get_data() const {
-
- return half_extents;
-}
-
-BoxShapeSW::BoxShapeSW() {
-
-
-}
-
-
-/********** CAPSULE *************/
-
-
-void CapsuleShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- Vector3 n=p_transform.basis.xform_inv(p_normal).normalized();
- float h = (n.z > 0) ? height : -height;
-
- n *= radius;
- n.z += h * 0.5;
-
- r_max=p_normal.dot(p_transform.xform(n));
- r_min=p_normal.dot(p_transform.xform(-n));
- return;
-
- n = p_transform.basis.xform(n);
-
- float distance = p_normal.dot( p_transform.origin );
- float length = Math::abs(p_normal.dot(n));
- r_min = distance - length;
- r_max = distance + length;
-
- ERR_FAIL_COND( r_max < r_min );
-
-}
-
-Vector3 CapsuleShapeSW::get_support(const Vector3& p_normal) const {
-
- Vector3 n=p_normal;
-
- float h = (n.z > 0) ? height : -height;
-
- n*=radius;
- n.z += h*0.5;
- return n;
-}
-
-void CapsuleShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
-
- Vector3 n=p_normal;
-
- float d = n.z;
-
- if (Math::abs( d )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) {
-
- // make it flat
- n.z=0.0;
- n.normalize();
- n*=radius;
-
- r_amount=2;
- r_supports[0]=n;
- r_supports[0].z+=height*0.5;
- r_supports[1]=n;
- r_supports[1].z-=height*0.5;
-
- } else {
-
- float h = (d > 0) ? height : -height;
-
- n*=radius;
- n.z += h*0.5;
- r_amount=1;
- *r_supports=n;
-
- }
-
-}
-
-
-bool CapsuleShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- Vector3 norm=(p_end-p_begin).normalized();
- float min_d=1e20;
-
-
- Vector3 res,n;
- bool collision=false;
-
- Vector3 auxres,auxn;
- bool collided;
-
- // test against cylinder and spheres :-|
-
- collided = Geometry::segment_intersects_cylinder(p_begin,p_end,height,radius,&auxres,&auxn);
-
- if (collided) {
- float d=norm.dot(auxres);
- if (d<min_d) {
- min_d=d;
- res=auxres;
- n=auxn;
- collision=true;
- }
- }
-
- collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*0.5),radius,&auxres,&auxn);
-
- if (collided) {
- float d=norm.dot(auxres);
- if (d<min_d) {
- min_d=d;
- res=auxres;
- n=auxn;
- collision=true;
- }
- }
-
- collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*-0.5),radius,&auxres,&auxn);
-
- if (collided) {
- float d=norm.dot(auxres);
-
- if (d<min_d) {
- min_d=d;
- res=auxres;
- n=auxn;
- collision=true;
- }
- }
-
- if (collision) {
-
- r_result=res;
- r_normal=n;
- }
- return collision;
-}
-
-Vector3 CapsuleShapeSW::get_moment_of_inertia(float p_mass) const {
-
- // use crappy AABB approximation
- Vector3 extents=get_aabb().size*0.5;
-
- return Vector3(
- (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
- (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
- (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
- );
-
-}
-
-
-
-
-void CapsuleShapeSW::_setup(real_t p_height,real_t p_radius) {
-
- height=p_height;
- radius=p_radius;
- configure(AABB(Vector3(-radius,-radius,-height*0.5-radius),Vector3(radius*2,radius*2,height+radius*2.0)));
-
-}
-
-void CapsuleShapeSW::set_data(const Variant& p_data) {
-
- Dictionary d = p_data;
- ERR_FAIL_COND(!d.has("radius"));
- ERR_FAIL_COND(!d.has("height"));
- _setup(d["height"],d["radius"]);
-
-}
-
-Variant CapsuleShapeSW::get_data() const {
-
- Dictionary d;
- d["radius"]=radius;
- d["height"]=height;
- return d;
-
-}
-
-
-CapsuleShapeSW::CapsuleShapeSW() {
-
- height=radius=0;
-
-}
-
-/********** CONVEX POLYGON *************/
-
-
-void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-
- int vertex_count=mesh.vertices.size();
- if (vertex_count==0)
- return;
-
- const Vector3 *vrts=&mesh.vertices[0];
-
- for (int i=0;i<vertex_count;i++) {
-
- float d=p_normal.dot( p_transform.xform( vrts[i] ) );
-
- if (i==0 || d > r_max)
- r_max=d;
- if (i==0 || d < r_min)
- r_min=d;
- }
-}
-
-Vector3 ConvexPolygonShapeSW::get_support(const Vector3& p_normal) const {
-
- Vector3 n=p_normal;
-
- int vert_support_idx=-1;
- float support_max;
-
- int vertex_count=mesh.vertices.size();
- if (vertex_count==0)
- return Vector3();
-
- const Vector3 *vrts=&mesh.vertices[0];
-
- for (int i=0;i<vertex_count;i++) {
-
- float d=n.dot(vrts[i]);
-
- if (i==0 || d > support_max) {
- support_max=d;
- vert_support_idx=i;
- }
- }
-
- return vrts[vert_support_idx];
-
-}
-
-
-
-void ConvexPolygonShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int fc = mesh.faces.size();
-
- const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
- int ec = mesh.edges.size();
-
- const Vector3 *vertices = mesh.vertices.ptr();
- int vc = mesh.vertices.size();
-
- //find vertex first
- real_t max;
- int vtx;
-
- for (int i=0;i<vc;i++) {
-
- float d=p_normal.dot(vertices[i]);
-
- if (i==0 || d > max) {
- max=d;
- vtx=i;
- }
- }
-
-
- for(int i=0;i<fc;i++) {
-
- if (faces[i].plane.normal.dot(p_normal)>_FACE_IS_VALID_SUPPORT_TRESHOLD) {
-
- int ic = faces[i].indices.size();
- const int *ind=faces[i].indices.ptr();
-
- bool valid=false;
- for(int j=0;j<ic;j++) {
- if (ind[j]==vtx) {
- valid=true;
- break;
- }
- }
-
- if (!valid)
- continue;
-
- int m = MIN(p_max,ic);
- for(int j=0;j<m;j++) {
-
- r_supports[j]=vertices[ind[j]];
- }
- r_amount=m;
- return;
- }
- }
-
- for(int i=0;i<ec;i++) {
-
-
- float dot=(vertices[edges[i].a]-vertices[edges[i].b]).normalized().dot(p_normal);
- dot=ABS(dot);
- if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD && (edges[i].a==vtx || edges[i].b==vtx)) {
-
- r_amount=2;
- r_supports[0]=vertices[edges[i].a];
- r_supports[1]=vertices[edges[i].b];
- return;
- }
- }
-
-
- r_supports[0]=vertices[vtx];
- r_amount=1;
-}
-
-bool ConvexPolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int fc = mesh.faces.size();
-
- const Vector3 *vertices = mesh.vertices.ptr();
- int vc = mesh.vertices.size();
-
- Vector3 n = p_end-p_begin;
- float min = 1e20;
- bool col=false;
-
- for(int i=0;i<fc;i++) {
-
- if (faces[i].plane.normal.dot(n) > 0)
- continue; //opposing face
-
- int ic = faces[i].indices.size();
- const int *ind=faces[i].indices.ptr();
-
- for(int j=1;j<ic-1;j++) {
-
- Face3 f(vertices[ind[0]],vertices[ind[i]],vertices[ind[i+1]]);
- Vector3 result;
- if (f.intersects_segment(p_begin,p_end,&result)) {
- float d = n.dot(result);
- if (d<min) {
- min=d;
- r_result=result;
- r_normal=faces[i].plane.normal;
- col=true;
- }
-
- break;
- }
-
- }
- }
-
- return col;
-
-}
-
-Vector3 ConvexPolygonShapeSW::get_moment_of_inertia(float p_mass) const {
-
- // use crappy AABB approximation
- Vector3 extents=get_aabb().size*0.5;
-
- return Vector3(
- (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
- (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
- (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
- );
-
-}
-
-void ConvexPolygonShapeSW::_setup(const Vector<Vector3>& p_vertices) {
-
- Error err = QuickHull::build(p_vertices,mesh);
- AABB _aabb;
-
- for(int i=0;i<mesh.vertices.size();i++) {
-
- if (i==0)
- _aabb.pos=mesh.vertices[i];
- else
- _aabb.expand_to(mesh.vertices[i]);
- }
-
- configure(_aabb);
-
-
-}
-
-void ConvexPolygonShapeSW::set_data(const Variant& p_data) {
-
- _setup(p_data);
-
-}
-
-Variant ConvexPolygonShapeSW::get_data() const {
-
- return mesh.vertices;
-}
-
-
-ConvexPolygonShapeSW::ConvexPolygonShapeSW() {
-
-
-}
-
-
-/********** FACE POLYGON *************/
-
-
-void FaceShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- for (int i=0;i<3;i++) {
-
- Vector3 v=p_transform.xform(vertex[i]);
- float d=p_normal.dot(v);
-
- if (i==0 || d > r_max)
- r_max=d;
-
- if (i==0 || d < r_min)
- r_min=d;
- }
-}
-
-Vector3 FaceShapeSW::get_support(const Vector3& p_normal) const {
-
-
- Vector3 n=p_normal;
-
- int vert_support_idx=-1;
- float support_max;
-
- for (int i=0;i<3;i++) {
-
- //float d=n.dot(vertex[i]);
- float d=p_normal.dot(vertex[i]);
-
- if (i==0 || d > support_max) {
- support_max=d;
- vert_support_idx=i;
- }
- }
-
- return vertex[vert_support_idx];
-}
-
-void FaceShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- Vector3 n=p_normal;
-
- /** TEST FACE AS SUPPORT **/
- if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_TRESHOLD) {
-
- r_amount=3;
- for (int i=0;i<3;i++) {
-
- r_supports[i]=vertex[i];
- }
- return;
-
- }
-
- /** FIND SUPPORT VERTEX **/
-
- int vert_support_idx=-1;
- float support_max;
-
- for (int i=0;i<3;i++) {
-
- float d=n.dot(vertex[i]);
-
- if (i==0 || d > support_max) {
- support_max=d;
- vert_support_idx=i;
- }
- }
-
- /** TEST EDGES AS SUPPORT **/
-
- for (int i=0;i<3;i++) {
-
- int nx=(i+1)%3;
- //if (i!=vert_support_idx && nx!=vert_support_idx)
- // continue;
-
- // check if edge is valid as a support
- float dot=(vertex[i]-vertex[nx]).normalized().dot(n);
- dot=ABS(dot);
- if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
- r_amount=2;
- r_supports[0]=vertex[i];
- r_supports[1]=vertex[nx];
- return;
- }
- }
-
- r_amount=1;
- r_supports[0]=vertex[vert_support_idx];
-}
-
-bool FaceShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-
- bool c=Geometry::segment_intersects_triangle(p_begin,p_end,vertex[0],vertex[1],vertex[2],&r_result);
- if (c)
- r_normal=Plane(vertex[0],vertex[1],vertex[2]).normal;
-
- return c;
-}
-
-Vector3 FaceShapeSW::get_moment_of_inertia(float p_mass) const {
-
- return Vector3(); // Sorry, but i don't think anyone cares, FaceShape!
-
-}
-
-FaceShapeSW::FaceShapeSW() {
-
- configure(AABB());
-
-}
-
-
-
-DVector<Vector3> ConcavePolygonShapeSW::get_faces() const {
-
-
- DVector<Vector3> rfaces;
- rfaces.resize(faces.size()*3);
-
- for(int i=0;i<faces.size();i++) {
-
- Face f=faces.get(i);
-
- for(int j=0;j<3;j++) {
-
- rfaces.set(i*3+j, vertices.get( f.indices[j] ) );
- }
- }
-
- return rfaces;
-}
-
-void ConcavePolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- int count=vertices.size();
- DVector<Vector3>::Read r=vertices.read();
- const Vector3 *vptr=r.ptr();
-
- for (int i=0;i<count;i++) {
-
- float d=p_normal.dot( p_transform.xform( vptr[i] ) );
-
- if (i==0 || d > r_max)
- r_max=d;
- if (i==0 || d < r_min)
- r_min=d;
-
- }
-}
-
-Vector3 ConcavePolygonShapeSW::get_support(const Vector3& p_normal) const {
-
-
- int count=vertices.size();
- DVector<Vector3>::Read r=vertices.read();
- const Vector3 *vptr=r.ptr();
-
- Vector3 n=p_normal;
-
- int vert_support_idx=-1;
- float support_max;
-
- for (int i=0;i<count;i++) {
-
- float d=n.dot(vptr[i]);
-
- if (i==0 || d > support_max) {
- support_max=d;
- vert_support_idx=i;
- }
- }
-
-
- return vptr[vert_support_idx];
-
-}
-
-void ConcavePolygonShapeSW::_cull_segment(int p_idx,_SegmentCullParams *p_params) const {
-
- const BVH *bvh=&p_params->bvh[p_idx];
-
-
- //if (p_params->dir.dot(bvh->aabb.get_support(-p_params->dir))>p_params->min_d)
- // return; //test against whole AABB, which isn't very costly
-
-
- //printf("addr: %p\n",bvh);
- if (!bvh->aabb.intersects_segment(p_params->from,p_params->to)) {
-
- return;
- }
-
-
- if (bvh->face_index>=0) {
-
-
- Vector3 res;
- Vector3 vertices[3]={
- p_params->vertices[ p_params->faces[ bvh->face_index ].indices[0] ],
- p_params->vertices[ p_params->faces[ bvh->face_index ].indices[1] ],
- p_params->vertices[ p_params->faces[ bvh->face_index ].indices[2] ]
- };
-
- if (Geometry::segment_intersects_triangle(
- p_params->from,
- p_params->to,
- vertices[0],
- vertices[1],
- vertices[2],
- &res)) {
-
-
- float d=p_params->normal.dot(res) - p_params->normal.dot(p_params->from);
- //TODO, seems segmen/triangle intersection is broken :(
- if (d>0 && d<p_params->min_d) {
-
- p_params->min_d=d;
- p_params->result=res;
- p_params->normal=Plane(vertices[0],vertices[1],vertices[2]).normal;
- p_params->collisions++;
- }
-
- }
-
-
-
- } else {
-
- if (bvh->left>=0)
- _cull_segment(bvh->left,p_params);
- if (bvh->right>=0)
- _cull_segment(bvh->right,p_params);
-
-
- }
-}
-
-bool ConcavePolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- // unlock data
- DVector<Face>::Read fr=faces.read();
- DVector<Vector3>::Read vr=vertices.read();
- DVector<BVH>::Read br=bvh.read();
-
-
- _SegmentCullParams params;
- params.from=p_begin;
- params.to=p_end;
- params.collisions=0;
- params.normal=(p_end-p_begin).normalized();
-
- params.faces=fr.ptr();
- params.vertices=vr.ptr();
- params.bvh=br.ptr();
-
- params.min_d=1e20;
- // cull
- _cull_segment(0,&params);
-
- if (params.collisions>0) {
-
-
- r_result=params.result;
- r_normal=params.normal;
- return true;
- } else {
-
- return false;
- }
-}
-
-void ConcavePolygonShapeSW::_cull(int p_idx,_CullParams *p_params) const {
-
- const BVH* bvh=&p_params->bvh[p_idx];
-
- if (!p_params->aabb.intersects( bvh->aabb ))
- return;
-
- if (bvh->face_index>=0) {
-
- const Face *f=&p_params->faces[ bvh->face_index ];
- FaceShapeSW *face=p_params->face;
- face->normal=f->normal;
- face->vertex[0]=p_params->vertices[f->indices[0]];
- face->vertex[1]=p_params->vertices[f->indices[1]];
- face->vertex[2]=p_params->vertices[f->indices[2]];
- p_params->callback(p_params->userdata,face);
-
- } else {
-
- if (bvh->left>=0) {
-
- _cull(bvh->left,p_params);
-
- }
-
- if (bvh->right>=0) {
-
- _cull(bvh->right,p_params);
- }
-
- }
-}
-
-void ConcavePolygonShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
-
- // make matrix local to concave
-
- AABB local_aabb=p_local_aabb;
-
- // unlock data
- DVector<Face>::Read fr=faces.read();
- DVector<Vector3>::Read vr=vertices.read();
- DVector<BVH>::Read br=bvh.read();
-
- FaceShapeSW face; // use this to send in the callback
-
- _CullParams params;
- params.aabb=local_aabb;
- params.face=&face;
- params.faces=fr.ptr();
- params.vertices=vr.ptr();
- params.bvh=br.ptr();
- params.callback=p_callback;
- params.userdata=p_userdata;
-
- // cull
- _cull(0,&params);
-
-}
-
-Vector3 ConcavePolygonShapeSW::get_moment_of_inertia(float p_mass) const {
-
- // use crappy AABB approximation
- Vector3 extents=get_aabb().size*0.5;
-
- return Vector3(
- (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
- (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
- (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
- );
-}
-
-
-struct _VolumeSW_BVH_Element {
-
- AABB aabb;
- Vector3 center;
- int face_index;
-};
-
-struct _VolumeSW_BVH_CompareX {
-
- _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
-
- return a.center.x<b.center.x;
- }
-};
-
-
-struct _VolumeSW_BVH_CompareY {
-
- _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
-
- return a.center.y<b.center.y;
- }
-};
-
-struct _VolumeSW_BVH_CompareZ {
-
- _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
-
- return a.center.z<b.center.z;
- }
-};
-
-struct _VolumeSW_BVH {
-
- AABB aabb;
- _VolumeSW_BVH *left;
- _VolumeSW_BVH *right;
-
- int face_index;
-};
-
-
-_VolumeSW_BVH* _volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements,int p_size,int &count) {
-
- _VolumeSW_BVH* bvh = memnew( _VolumeSW_BVH );
-
- if (p_size==1) {
- //leaf
- bvh->aabb=p_elements[0].aabb;
- bvh->left=NULL;
- bvh->right=NULL;
- bvh->face_index=p_elements->face_index;
- count++;
- return bvh;
- } else {
-
- bvh->face_index=-1;
- }
-
- AABB aabb;
- for(int i=0;i<p_size;i++) {
-
- if (i==0)
- aabb=p_elements[i].aabb;
- else
- aabb.merge_with(p_elements[i].aabb);
- }
- bvh->aabb=aabb;
- switch(aabb.get_longest_axis_index()) {
-
- case 0: {
-
- SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareX> sort_x;
- sort_x.sort(p_elements,p_size);
-
- } break;
- case 1: {
-
- SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareY> sort_y;
- sort_y.sort(p_elements,p_size);
- } break;
- case 2: {
-
- SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareZ> sort_z;
- sort_z.sort(p_elements,p_size);
- } break;
- }
-
- int split=p_size/2;
- bvh->left=_volume_sw_build_bvh(p_elements,split,count);
- bvh->right=_volume_sw_build_bvh(&p_elements[split],p_size-split,count);
-
-// printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index);
- count++;
- return bvh;
-}
-
-
-void ConcavePolygonShapeSW::_fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array,int& p_idx) {
-
- int idx=p_idx;
-
-
- p_bvh_array[idx].aabb=p_bvh_tree->aabb;
- p_bvh_array[idx].face_index=p_bvh_tree->face_index;
-// printf("%p - %i: %i(%p) -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right);
-
-
- if (p_bvh_tree->left) {
- p_bvh_array[idx].left=++p_idx;
- _fill_bvh(p_bvh_tree->left,p_bvh_array,p_idx);
-
- } else {
-
- p_bvh_array[p_idx].left=-1;
- }
-
- if (p_bvh_tree->right) {
- p_bvh_array[idx].right=++p_idx;
- _fill_bvh(p_bvh_tree->right,p_bvh_array,p_idx);
-
- } else {
-
- p_bvh_array[p_idx].right=-1;
- }
-
- memdelete(p_bvh_tree);
-
-}
-
-void ConcavePolygonShapeSW::_setup(DVector<Vector3> p_faces) {
-
- int src_face_count=p_faces.size();
- ERR_FAIL_COND(src_face_count%3);
- src_face_count/=3;
-
- DVector<Vector3>::Read r = p_faces.read();
- const Vector3 * facesr= r.ptr();
-
-#if 0
- Map<Vector3,int> point_map;
- List<Face> face_list;
-
-
- for(int i=0;i<src_face_count;i++) {
-
- Face3 faceaux;
-
- for(int j=0;j<3;j++) {
-
- faceaux.vertex[j]=facesr[i*3+j].snapped(_POINT_SNAP);
- //faceaux.vertex[j]=facesr[i*3+j];//facesr[i*3+j].snapped(_POINT_SNAP);
- }
-
- ERR_CONTINUE( faceaux.is_degenerate() );
-
- Face face;
-
- for(int j=0;j<3;j++) {
-
-
- Map<Vector3,int>::Element *E=point_map.find(faceaux.vertex[j]);
- if (E) {
-
- face.indices[j]=E->value();
- } else {
-
- face.indices[j]=point_map.size();
- point_map.insert(faceaux.vertex[j],point_map.size());
-
- }
- }
-
- face_list.push_back(face);
- }
-
- vertices.resize( point_map.size() );
-
- DVector<Vector3>::Write vw = vertices.write();
- Vector3 *verticesw=vw.ptr();
-
- AABB _aabb;
-
- for( Map<Vector3,int>::Element *E=point_map.front();E;E=E->next()) {
-
- if (E==point_map.front()) {
- _aabb.pos=E->key();
- } else {
-
- _aabb.expand_to(E->key());
- }
- verticesw[E->value()]=E->key();
- }
-
- point_map.clear(); // not needed anymore
-
- faces.resize(face_list.size());
- DVector<Face>::Write w = faces.write();
- Face *facesw=w.ptr();
-
- int fc=0;
-
- for( List<Face>::Element *E=face_list.front();E;E=E->next()) {
-
- facesw[fc++]=E->get();
- }
-
- face_list.clear();
-
-
- DVector<_VolumeSW_BVH_Element> bvh_array;
- bvh_array.resize( fc );
-
- DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
- _VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
-
-
- for(int i=0;i<fc;i++) {
-
- AABB face_aabb;
- face_aabb.pos=verticesw[facesw[i].indices[0]];
- face_aabb.expand_to( verticesw[facesw[i].indices[1]] );
- face_aabb.expand_to( verticesw[facesw[i].indices[2]] );
-
- bvh_arrayw[i].face_index=i;
- bvh_arrayw[i].aabb=face_aabb;
- bvh_arrayw[i].center=face_aabb.pos+face_aabb.size*0.5;
-
- }
-
- w=DVector<Face>::Write();
- vw=DVector<Vector3>::Write();
-
-
- int count=0;
- _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,fc,count);
-
- ERR_FAIL_COND(count==0);
-
- bvhw=DVector<_VolumeSW_BVH_Element>::Write();
-
- bvh.resize( count+1 );
-
- DVector<BVH>::Write bvhw2 = bvh.write();
- BVH*bvh_arrayw2=bvhw2.ptr();
-
- int idx=0;
- _fill_bvh(bvh_tree,bvh_arrayw2,idx);
-
- set_aabb(_aabb);
-
-#else
- DVector<_VolumeSW_BVH_Element> bvh_array;
- bvh_array.resize( src_face_count );
-
- DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
- _VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
-
- faces.resize(src_face_count);
- DVector<Face>::Write w = faces.write();
- Face *facesw=w.ptr();
-
- vertices.resize( src_face_count*3 );
-
- DVector<Vector3>::Write vw = vertices.write();
- Vector3 *verticesw=vw.ptr();
-
- AABB _aabb;
-
-
- for(int i=0;i<src_face_count;i++) {
-
- Face3 face( facesr[i*3+0], facesr[i*3+1], facesr[i*3+2] );
-
- bvh_arrayw[i].aabb=face.get_aabb();
- bvh_arrayw[i].center = bvh_arrayw[i].aabb.pos + bvh_arrayw[i].aabb.size * 0.5;
- bvh_arrayw[i].face_index=i;
- facesw[i].indices[0]=i*3+0;
- facesw[i].indices[1]=i*3+1;
- facesw[i].indices[2]=i*3+2;
- facesw[i].normal=face.get_plane().normal;
- verticesw[i*3+0]=face.vertex[0];
- verticesw[i*3+1]=face.vertex[1];
- verticesw[i*3+2]=face.vertex[2];
- if (i==0)
- _aabb=bvh_arrayw[i].aabb;
- else
- _aabb.merge_with(bvh_arrayw[i].aabb);
-
- }
-
- w=DVector<Face>::Write();
- vw=DVector<Vector3>::Write();
-
- int count=0;
- _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,src_face_count,count);
-
- bvh.resize( count+1 );
-
- DVector<BVH>::Write bvhw2 = bvh.write();
- BVH*bvh_arrayw2=bvhw2.ptr();
-
- int idx=0;
- _fill_bvh(bvh_tree,bvh_arrayw2,idx);
-
- configure(_aabb); // this type of shape has no margin
-
-
-#endif
-}
-
-
-void ConcavePolygonShapeSW::set_data(const Variant& p_data) {
-
-
- _setup(p_data);
-}
-
-Variant ConcavePolygonShapeSW::get_data() const {
-
- return get_faces();
-}
-
-ConcavePolygonShapeSW::ConcavePolygonShapeSW() {
-
-
-}
-
-
-
-/* HEIGHT MAP SHAPE */
-
-DVector<float> HeightMapShapeSW::get_heights() const {
-
- return heights;
-}
-int HeightMapShapeSW::get_width() const {
-
- return width;
-}
-int HeightMapShapeSW::get_depth() const {
-
- return depth;
-}
-float HeightMapShapeSW::get_cell_size() const {
-
- return cell_size;
-}
-
-
-void HeightMapShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- //not very useful, but not very used either
- p_transform.xform(get_aabb()).project_range_in_plane( Plane(p_normal,0),r_min,r_max );
-
-}
-
-Vector3 HeightMapShapeSW::get_support(const Vector3& p_normal) const {
-
-
- //not very useful, but not very used either
- return get_aabb().get_support(p_normal);
-
-}
-
-bool HeightMapShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const {
-
-
- return false;
-}
-
-
-void HeightMapShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
-
-
-
-}
-
-
-Vector3 HeightMapShapeSW::get_moment_of_inertia(float p_mass) const {
-
-
- // use crappy AABB approximation
- Vector3 extents=get_aabb().size*0.5;
-
- return Vector3(
- (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
- (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
- (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
- );
-}
-
-
-void HeightMapShapeSW::_setup(DVector<real_t> p_heights,int p_width,int p_depth,real_t p_cell_size) {
-
- heights=p_heights;
- width=p_width;
- depth=p_depth;;
- cell_size=p_cell_size;
-
- DVector<real_t>::Read r = heights. read();
-
- AABB aabb;
-
- for(int i=0;i<depth;i++) {
-
- for(int j=0;j<width;j++) {
-
- float h = r[i*width+j];
-
- Vector3 pos( j*cell_size, h, i*cell_size );
- if (i==0 || j==0)
- aabb.pos=pos;
- else
- aabb.expand_to(pos);
-
- }
- }
-
-
- configure(aabb);
-}
-
-void HeightMapShapeSW::set_data(const Variant& p_data) {
-
- ERR_FAIL_COND( p_data.get_type()!=Variant::DICTIONARY );
- Dictionary d=p_data;
- ERR_FAIL_COND( !d.has("width") );
- ERR_FAIL_COND( !d.has("depth") );
- ERR_FAIL_COND( !d.has("cell_size") );
- ERR_FAIL_COND( !d.has("heights") );
-
- int width=d["width"];
- int depth=d["depth"];
- float cell_size=d["cell_size"];
- DVector<float> heights=d["heights"];
-
- ERR_FAIL_COND( width<= 0);
- ERR_FAIL_COND( depth<= 0);
- ERR_FAIL_COND( cell_size<= CMP_EPSILON);
- ERR_FAIL_COND( heights.size() != (width*depth) );
- _setup(heights, width, depth, cell_size );
-
-}
-
-Variant HeightMapShapeSW::get_data() const {
-
- ERR_FAIL_V(Variant());
-
-}
-
-HeightMapShapeSW::HeightMapShapeSW() {
-
- width=0;
- depth=0;
- cell_size=0;
-}
-
-
-
+#include "shape_sw.h"
+#include "geometry.h"
+#include "sort.h"
+#include "quick_hull.h"
+#define _POINT_SNAP 0.001953125
+#define _EDGE_IS_VALID_SUPPORT_TRESHOLD 0.0002
+#define _FACE_IS_VALID_SUPPORT_TRESHOLD 0.9998
+
+
+void ShapeSW::configure(const AABB& p_aabb) {
+ aabb=p_aabb;
+ configured=true;
+ for (Map<ShapeOwnerSW*,int>::Element *E=owners.front();E;E=E->next()) {
+ ShapeOwnerSW* co=(ShapeOwnerSW*)E->key();
+ co->_shape_changed();
+ }
+}
+
+
+Vector3 ShapeSW::get_support(const Vector3& p_normal) const {
+
+ Vector3 res;
+ int amnt;
+ get_supports(p_normal,1,&res,amnt);
+ return res;
+}
+
+void ShapeSW::add_owner(ShapeOwnerSW *p_owner) {
+
+ Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
+ if (E) {
+ E->get()++;
+ } else {
+ owners[p_owner]=1;
+ }
+}
+
+void ShapeSW::remove_owner(ShapeOwnerSW *p_owner){
+
+ Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
+ ERR_FAIL_COND(!E);
+ E->get()--;
+ if (E->get()==0) {
+ owners.erase(E);
+ }
+
+}
+
+bool ShapeSW::is_owner(ShapeOwnerSW *p_owner) const{
+
+ return owners.has(p_owner);
+
+}
+
+const Map<ShapeOwnerSW*,int>& ShapeSW::get_owners() const{
+ return owners;
+}
+
+
+ShapeSW::ShapeSW() {
+
+ custom_bias=0;
+ configured=false;
+}
+
+
+ShapeSW::~ShapeSW() {
+
+ ERR_FAIL_COND(owners.size());
+}
+
+
+
+Plane PlaneShapeSW::get_plane() const {
+
+ return plane;
+}
+
+void PlaneShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ // gibberish, a plane is infinity
+ r_min=-1e7;
+ r_max=1e7;
+}
+
+Vector3 PlaneShapeSW::get_support(const Vector3& p_normal) const {
+
+ return p_normal*1e15;
+}
+
+
+bool PlaneShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+ bool inters=plane.intersects_segment(p_begin,p_end,&r_result);
+ if(inters)
+ r_normal=plane.normal;
+ return inters;
+}
+
+Vector3 PlaneShapeSW::get_moment_of_inertia(float p_mass) const {
+
+ return Vector3(); //wtf
+}
+
+void PlaneShapeSW::_setup(const Plane& p_plane) {
+
+ plane=p_plane;
+ configure(AABB(Vector3(-1e4,-1e4,-1e4),Vector3(1e4*2,1e4*2,1e4*2)));
+}
+
+void PlaneShapeSW::set_data(const Variant& p_data) {
+
+ _setup(p_data);
+
+}
+
+Variant PlaneShapeSW::get_data() const {
+
+ return plane;
+}
+
+PlaneShapeSW::PlaneShapeSW() {
+
+
+}
+
+//
+
+float RayShapeSW::get_length() const {
+
+ return length;
+}
+
+void RayShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ // don't think this will be even used
+ r_min=0;
+ r_max=1;
+}
+
+Vector3 RayShapeSW::get_support(const Vector3& p_normal) const {
+
+ if (p_normal.z>0)
+ return Vector3(0,0,length);
+ else
+ return Vector3(0,0,0);
+}
+
+void RayShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+ if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
+
+ r_amount=2;
+ r_supports[0]=Vector3(0,0,0);
+ r_supports[1]=Vector3(0,0,length);
+ } if (p_normal.z>0) {
+ r_amount=1;
+ *r_supports=Vector3(0,0,length);
+ } else {
+ r_amount=1;
+ *r_supports=Vector3(0,0,0);
+ }
+}
+
+
+bool RayShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+ return false; //simply not possible
+}
+
+Vector3 RayShapeSW::get_moment_of_inertia(float p_mass) const {
+
+ return Vector3();
+}
+
+void RayShapeSW::_setup(float p_length) {
+
+ length=p_length;
+ configure(AABB(Vector3(0,0,0),Vector3(0.1,0.1,length)));
+}
+
+void RayShapeSW::set_data(const Variant& p_data) {
+
+ _setup(p_data);
+
+}
+
+Variant RayShapeSW::get_data() const {
+
+ return length;
+}
+
+RayShapeSW::RayShapeSW() {
+
+ length=1;
+}
+
+
+
+/********** SPHERE *************/
+
+real_t SphereShapeSW::get_radius() const {
+
+ return radius;
+}
+
+void SphereShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ float d = p_normal.dot( p_transform.origin );
+
+ // figure out scale at point
+ Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
+ float scale = local_normal.length();
+
+ r_min = d - (radius) * scale;
+ r_max = d + (radius) * scale;
+
+}
+
+Vector3 SphereShapeSW::get_support(const Vector3& p_normal) const {
+
+ return p_normal*radius;
+}
+
+void SphereShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+ *r_supports=p_normal*radius;
+ r_amount=1;
+}
+
+bool SphereShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+ return Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(),radius,&r_result,&r_normal);
+}
+
+Vector3 SphereShapeSW::get_moment_of_inertia(float p_mass) const {
+
+ float s = 0.4 * p_mass * radius * radius;
+ return Vector3(s,s,s);
+}
+
+void SphereShapeSW::_setup(real_t p_radius) {
+
+
+ radius=p_radius;
+ configure(AABB( Vector3(-radius,-radius,-radius), Vector3(radius*2.0,radius*2.0,radius*2.0)));
+
+}
+
+void SphereShapeSW::set_data(const Variant& p_data) {
+
+ _setup(p_data);
+}
+
+Variant SphereShapeSW::get_data() const {
+
+ return radius;
+}
+
+SphereShapeSW::SphereShapeSW() {
+
+ radius=0;
+}
+
+
+/********** BOX *************/
+
+
+void BoxShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ // no matter the angle, the box is mirrored anyway
+ Vector3 local_normal=p_transform.basis.xform_inv(p_normal);
+
+ float length = local_normal.abs().dot(half_extents);
+ float distance = p_normal.dot( p_transform.origin );
+
+ r_min = distance - length;
+ r_max = distance + length;
+
+
+}
+
+Vector3 BoxShapeSW::get_support(const Vector3& p_normal) const {
+
+
+ Vector3 point(
+ (p_normal.x<0) ? -half_extents.x : half_extents.x,
+ (p_normal.y<0) ? -half_extents.y : half_extents.y,
+ (p_normal.z<0) ? -half_extents.z : half_extents.z
+ );
+
+ return point;
+}
+
+void BoxShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+ static const int next[3]={1,2,0};
+ static const int next2[3]={2,0,1};
+
+ for (int i=0;i<3;i++) {
+
+ Vector3 axis;
+ axis[i]=1.0;
+ float dot = p_normal.dot( axis );
+ if ( Math::abs( dot ) > _FACE_IS_VALID_SUPPORT_TRESHOLD ) {
+
+ //Vector3 axis_b;
+
+ bool neg = dot<0;
+ r_amount = 4;
+
+ Vector3 point;
+ point[i]=half_extents[i];
+
+ int i_n=next[i];
+ int i_n2=next2[i];
+
+ static const float sign[4][2]={
+
+ {-1.0, 1.0},
+ { 1.0, 1.0},
+ { 1.0,-1.0},
+ {-1.0,-1.0},
+ };
+
+ for (int j=0;j<4;j++) {
+
+ point[i_n]=sign[j][0]*half_extents[i_n];
+ point[i_n2]=sign[j][1]*half_extents[i_n2];
+ r_supports[j]=neg?-point:point;
+
+ }
+
+ if (neg) {
+ SWAP( r_supports[1], r_supports[2] );
+ SWAP( r_supports[0], r_supports[3] );
+ }
+
+ return;
+ }
+
+ r_amount=0;
+
+ }
+
+ for (int i=0;i<3;i++) {
+
+ Vector3 axis;
+ axis[i]=1.0;
+
+ if (Math::abs(p_normal.dot(axis))<_EDGE_IS_VALID_SUPPORT_TRESHOLD) {
+
+ r_amount= 2;
+
+ int i_n=next[i];
+ int i_n2=next2[i];
+
+ Vector3 point=half_extents;
+
+ if (p_normal[i_n]<0) {
+ point[i_n]=-point[i_n];
+ }
+ if (p_normal[i_n2]<0) {
+ point[i_n2]=-point[i_n2];
+ }
+
+ r_supports[0] = point;
+ point[i]=-point[i];
+ r_supports[1] = point;
+ return;
+ }
+ }
+ /* USE POINT */
+
+ Vector3 point(
+ (p_normal.x<0) ? -half_extents.x : half_extents.x,
+ (p_normal.y<0) ? -half_extents.y : half_extents.y,
+ (p_normal.z<0) ? -half_extents.z : half_extents.z
+ );
+
+ r_amount=1;
+ r_supports[0]=point;
+}
+
+bool BoxShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+ AABB aabb(-half_extents,half_extents*2.0);
+
+ return aabb.intersects_segment(p_begin,p_end,&r_result,&r_normal);
+
+}
+
+Vector3 BoxShapeSW::get_moment_of_inertia(float p_mass) const {
+
+ float lx=half_extents.x;
+ float ly=half_extents.y;
+ float lz=half_extents.z;
+
+ return Vector3( (p_mass/3.0) * (ly*ly + lz*lz), (p_mass/3.0) * (lx*lx + lz*lz), (p_mass/3.0) * (lx*lx + ly*ly) );
+
+}
+
+void BoxShapeSW::_setup(const Vector3& p_half_extents) {
+
+ half_extents=p_half_extents.abs();
+
+ configure(AABB(-half_extents,half_extents*2));
+
+
+}
+
+void BoxShapeSW::set_data(const Variant& p_data) {
+
+
+ _setup(p_data);
+}
+
+Variant BoxShapeSW::get_data() const {
+
+ return half_extents;
+}
+
+BoxShapeSW::BoxShapeSW() {
+
+
+}
+
+
+/********** CAPSULE *************/
+
+
+void CapsuleShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ Vector3 n=p_transform.basis.xform_inv(p_normal).normalized();
+ float h = (n.z > 0) ? height : -height;
+
+ n *= radius;
+ n.z += h * 0.5;
+
+ r_max=p_normal.dot(p_transform.xform(n));
+ r_min=p_normal.dot(p_transform.xform(-n));
+ return;
+
+ n = p_transform.basis.xform(n);
+
+ float distance = p_normal.dot( p_transform.origin );
+ float length = Math::abs(p_normal.dot(n));
+ r_min = distance - length;
+ r_max = distance + length;
+
+ ERR_FAIL_COND( r_max < r_min );
+
+}
+
+Vector3 CapsuleShapeSW::get_support(const Vector3& p_normal) const {
+
+ Vector3 n=p_normal;
+
+ float h = (n.z > 0) ? height : -height;
+
+ n*=radius;
+ n.z += h*0.5;
+ return n;
+}
+
+void CapsuleShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+
+ Vector3 n=p_normal;
+
+ float d = n.z;
+
+ if (Math::abs( d )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) {
+
+ // make it flat
+ n.z=0.0;
+ n.normalize();
+ n*=radius;
+
+ r_amount=2;
+ r_supports[0]=n;
+ r_supports[0].z+=height*0.5;
+ r_supports[1]=n;
+ r_supports[1].z-=height*0.5;
+
+ } else {
+
+ float h = (d > 0) ? height : -height;
+
+ n*=radius;
+ n.z += h*0.5;
+ r_amount=1;
+ *r_supports=n;
+
+ }
+
+}
+
+
+bool CapsuleShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+ Vector3 norm=(p_end-p_begin).normalized();
+ float min_d=1e20;
+
+
+ Vector3 res,n;
+ bool collision=false;
+
+ Vector3 auxres,auxn;
+ bool collided;
+
+ // test against cylinder and spheres :-|
+
+ collided = Geometry::segment_intersects_cylinder(p_begin,p_end,height,radius,&auxres,&auxn);
+
+ if (collided) {
+ float d=norm.dot(auxres);
+ if (d<min_d) {
+ min_d=d;
+ res=auxres;
+ n=auxn;
+ collision=true;
+ }
+ }
+
+ collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*0.5),radius,&auxres,&auxn);
+
+ if (collided) {
+ float d=norm.dot(auxres);
+ if (d<min_d) {
+ min_d=d;
+ res=auxres;
+ n=auxn;
+ collision=true;
+ }
+ }
+
+ collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*-0.5),radius,&auxres,&auxn);
+
+ if (collided) {
+ float d=norm.dot(auxres);
+
+ if (d<min_d) {
+ min_d=d;
+ res=auxres;
+ n=auxn;
+ collision=true;
+ }
+ }
+
+ if (collision) {
+
+ r_result=res;
+ r_normal=n;
+ }
+ return collision;
+}
+
+Vector3 CapsuleShapeSW::get_moment_of_inertia(float p_mass) const {
+
+ // use crappy AABB approximation
+ Vector3 extents=get_aabb().size*0.5;
+
+ return Vector3(
+ (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
+ (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
+ (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
+ );
+
+}
+
+
+
+
+void CapsuleShapeSW::_setup(real_t p_height,real_t p_radius) {
+
+ height=p_height;
+ radius=p_radius;
+ configure(AABB(Vector3(-radius,-radius,-height*0.5-radius),Vector3(radius*2,radius*2,height+radius*2.0)));
+
+}
+
+void CapsuleShapeSW::set_data(const Variant& p_data) {
+
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("radius"));
+ ERR_FAIL_COND(!d.has("height"));
+ _setup(d["height"],d["radius"]);
+
+}
+
+Variant CapsuleShapeSW::get_data() const {
+
+ Dictionary d;
+ d["radius"]=radius;
+ d["height"]=height;
+ return d;
+
+}
+
+
+CapsuleShapeSW::CapsuleShapeSW() {
+
+ height=radius=0;
+
+}
+
+/********** CONVEX POLYGON *************/
+
+
+void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+
+ int vertex_count=mesh.vertices.size();
+ if (vertex_count==0)
+ return;
+
+ const Vector3 *vrts=&mesh.vertices[0];
+
+ for (int i=0;i<vertex_count;i++) {
+
+ float d=p_normal.dot( p_transform.xform( vrts[i] ) );
+
+ if (i==0 || d > r_max)
+ r_max=d;
+ if (i==0 || d < r_min)
+ r_min=d;
+ }
+}
+
+Vector3 ConvexPolygonShapeSW::get_support(const Vector3& p_normal) const {
+
+ Vector3 n=p_normal;
+
+ int vert_support_idx=-1;
+ float support_max;
+
+ int vertex_count=mesh.vertices.size();
+ if (vertex_count==0)
+ return Vector3();
+
+ const Vector3 *vrts=&mesh.vertices[0];
+
+ for (int i=0;i<vertex_count;i++) {
+
+ float d=n.dot(vrts[i]);
+
+ if (i==0 || d > support_max) {
+ support_max=d;
+ vert_support_idx=i;
+ }
+ }
+
+ return vrts[vert_support_idx];
+
+}
+
+
+
+void ConvexPolygonShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int fc = mesh.faces.size();
+
+ const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
+ int ec = mesh.edges.size();
+
+ const Vector3 *vertices = mesh.vertices.ptr();
+ int vc = mesh.vertices.size();
+
+ //find vertex first
+ real_t max;
+ int vtx;
+
+ for (int i=0;i<vc;i++) {
+
+ float d=p_normal.dot(vertices[i]);
+
+ if (i==0 || d > max) {
+ max=d;
+ vtx=i;
+ }
+ }
+
+
+ for(int i=0;i<fc;i++) {
+
+ if (faces[i].plane.normal.dot(p_normal)>_FACE_IS_VALID_SUPPORT_TRESHOLD) {
+
+ int ic = faces[i].indices.size();
+ const int *ind=faces[i].indices.ptr();
+
+ bool valid=false;
+ for(int j=0;j<ic;j++) {
+ if (ind[j]==vtx) {
+ valid=true;
+ break;
+ }
+ }
+
+ if (!valid)
+ continue;
+
+ int m = MIN(p_max,ic);
+ for(int j=0;j<m;j++) {
+
+ r_supports[j]=vertices[ind[j]];
+ }
+ r_amount=m;
+ return;
+ }
+ }
+
+ for(int i=0;i<ec;i++) {
+
+
+ float dot=(vertices[edges[i].a]-vertices[edges[i].b]).normalized().dot(p_normal);
+ dot=ABS(dot);
+ if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD && (edges[i].a==vtx || edges[i].b==vtx)) {
+
+ r_amount=2;
+ r_supports[0]=vertices[edges[i].a];
+ r_supports[1]=vertices[edges[i].b];
+ return;
+ }
+ }
+
+
+ r_supports[0]=vertices[vtx];
+ r_amount=1;
+}
+
+bool ConvexPolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int fc = mesh.faces.size();
+
+ const Vector3 *vertices = mesh.vertices.ptr();
+ int vc = mesh.vertices.size();
+
+ Vector3 n = p_end-p_begin;
+ float min = 1e20;
+ bool col=false;
+
+ for(int i=0;i<fc;i++) {
+
+ if (faces[i].plane.normal.dot(n) > 0)
+ continue; //opposing face
+
+ int ic = faces[i].indices.size();
+ const int *ind=faces[i].indices.ptr();
+
+ for(int j=1;j<ic-1;j++) {
+
+ Face3 f(vertices[ind[0]],vertices[ind[j]],vertices[ind[j+1]]);
+ Vector3 result;
+ if (f.intersects_segment(p_begin,p_end,&result)) {
+ float d = n.dot(result);
+ if (d<min) {
+ min=d;
+ r_result=result;
+ r_normal=faces[i].plane.normal;
+ col=true;
+ }
+
+ break;
+ }
+
+ }
+ }
+
+ return col;
+
+}
+
+Vector3 ConvexPolygonShapeSW::get_moment_of_inertia(float p_mass) const {
+
+ // use crappy AABB approximation
+ Vector3 extents=get_aabb().size*0.5;
+
+ return Vector3(
+ (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
+ (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
+ (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
+ );
+
+}
+
+void ConvexPolygonShapeSW::_setup(const Vector<Vector3>& p_vertices) {
+
+ Error err = QuickHull::build(p_vertices,mesh);
+ AABB _aabb;
+
+ for(int i=0;i<mesh.vertices.size();i++) {
+
+ if (i==0)
+ _aabb.pos=mesh.vertices[i];
+ else
+ _aabb.expand_to(mesh.vertices[i]);
+ }
+
+ configure(_aabb);
+
+
+}
+
+void ConvexPolygonShapeSW::set_data(const Variant& p_data) {
+
+ _setup(p_data);
+
+}
+
+Variant ConvexPolygonShapeSW::get_data() const {
+
+ return mesh.vertices;
+}
+
+
+ConvexPolygonShapeSW::ConvexPolygonShapeSW() {
+
+
+}
+
+
+/********** FACE POLYGON *************/
+
+
+void FaceShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ for (int i=0;i<3;i++) {
+
+ Vector3 v=p_transform.xform(vertex[i]);
+ float d=p_normal.dot(v);
+
+ if (i==0 || d > r_max)
+ r_max=d;
+
+ if (i==0 || d < r_min)
+ r_min=d;
+ }
+}
+
+Vector3 FaceShapeSW::get_support(const Vector3& p_normal) const {
+
+
+ Vector3 n=p_normal;
+
+ int vert_support_idx=-1;
+ float support_max;
+
+ for (int i=0;i<3;i++) {
+
+ //float d=n.dot(vertex[i]);
+ float d=p_normal.dot(vertex[i]);
+
+ if (i==0 || d > support_max) {
+ support_max=d;
+ vert_support_idx=i;
+ }
+ }
+
+ return vertex[vert_support_idx];
+}
+
+void FaceShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+ Vector3 n=p_normal;
+
+ /** TEST FACE AS SUPPORT **/
+ if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_TRESHOLD) {
+
+ r_amount=3;
+ for (int i=0;i<3;i++) {
+
+ r_supports[i]=vertex[i];
+ }
+ return;
+
+ }
+
+ /** FIND SUPPORT VERTEX **/
+
+ int vert_support_idx=-1;
+ float support_max;
+
+ for (int i=0;i<3;i++) {
+
+ float d=n.dot(vertex[i]);
+
+ if (i==0 || d > support_max) {
+ support_max=d;
+ vert_support_idx=i;
+ }
+ }
+
+ /** TEST EDGES AS SUPPORT **/
+
+ for (int i=0;i<3;i++) {
+
+ int nx=(i+1)%3;
+ if (i!=vert_support_idx && nx!=vert_support_idx)
+ continue;
+
+ // check if edge is valid as a support
+ float dot=(vertex[i]-vertex[nx]).normalized().dot(n);
+ dot=ABS(dot);
+ if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
+
+ r_amount=2;
+ r_supports[0]=vertex[i];
+ r_supports[1]=vertex[nx];
+ return;
+ }
+ }
+
+ r_amount=1;
+ r_supports[0]=vertex[vert_support_idx];
+}
+
+bool FaceShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+
+ bool c=Geometry::segment_intersects_triangle(p_begin,p_end,vertex[0],vertex[1],vertex[2],&r_result);
+ if (c) {
+ r_normal=Plane(vertex[0],vertex[1],vertex[2]).normal;
+ if (r_normal.dot(p_end-p_begin)>0) {
+ r_normal=-r_normal;
+ }
+ }
+
+ return c;
+}
+
+Vector3 FaceShapeSW::get_moment_of_inertia(float p_mass) const {
+
+ return Vector3(); // Sorry, but i don't think anyone cares, FaceShape!
+
+}
+
+FaceShapeSW::FaceShapeSW() {
+
+ configure(AABB());
+
+}
+
+
+
+DVector<Vector3> ConcavePolygonShapeSW::get_faces() const {
+
+
+ DVector<Vector3> rfaces;
+ rfaces.resize(faces.size()*3);
+
+ for(int i=0;i<faces.size();i++) {
+
+ Face f=faces.get(i);
+
+ for(int j=0;j<3;j++) {
+
+ rfaces.set(i*3+j, vertices.get( f.indices[j] ) );
+ }
+ }
+
+ return rfaces;
+}
+
+void ConcavePolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ int count=vertices.size();
+ if (count==0) {
+ r_min=0;
+ r_max=0;
+ return;
+ }
+ DVector<Vector3>::Read r=vertices.read();
+ const Vector3 *vptr=r.ptr();
+
+ for (int i=0;i<count;i++) {
+
+ float d=p_normal.dot( p_transform.xform( vptr[i] ) );
+
+ if (i==0 || d > r_max)
+ r_max=d;
+ if (i==0 || d < r_min)
+ r_min=d;
+
+ }
+}
+
+Vector3 ConcavePolygonShapeSW::get_support(const Vector3& p_normal) const {
+
+
+ int count=vertices.size();
+ if (count==0)
+ return Vector3();
+
+ DVector<Vector3>::Read r=vertices.read();
+ const Vector3 *vptr=r.ptr();
+
+ Vector3 n=p_normal;
+
+ int vert_support_idx=-1;
+ float support_max;
+
+ for (int i=0;i<count;i++) {
+
+ float d=n.dot(vptr[i]);
+
+ if (i==0 || d > support_max) {
+ support_max=d;
+ vert_support_idx=i;
+ }
+ }
+
+
+ return vptr[vert_support_idx];
+
+}
+
+void ConcavePolygonShapeSW::_cull_segment(int p_idx,_SegmentCullParams *p_params) const {
+
+ const BVH *bvh=&p_params->bvh[p_idx];
+
+
+ //if (p_params->dir.dot(bvh->aabb.get_support(-p_params->dir))>p_params->min_d)
+ // return; //test against whole AABB, which isn't very costly
+
+
+ //printf("addr: %p\n",bvh);
+ if (!bvh->aabb.intersects_segment(p_params->from,p_params->to)) {
+
+ return;
+ }
+
+
+ if (bvh->face_index>=0) {
+
+
+ Vector3 res;
+ Vector3 vertices[3]={
+ p_params->vertices[ p_params->faces[ bvh->face_index ].indices[0] ],
+ p_params->vertices[ p_params->faces[ bvh->face_index ].indices[1] ],
+ p_params->vertices[ p_params->faces[ bvh->face_index ].indices[2] ]
+ };
+
+ if (Geometry::segment_intersects_triangle(
+ p_params->from,
+ p_params->to,
+ vertices[0],
+ vertices[1],
+ vertices[2],
+ &res)) {
+
+
+ float d=p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
+ //TODO, seems segmen/triangle intersection is broken :(
+ if (d>0 && d<p_params->min_d) {
+
+ p_params->min_d=d;
+ p_params->result=res;
+ p_params->normal=Plane(vertices[0],vertices[1],vertices[2]).normal;
+ if (p_params->normal.dot(p_params->dir)>0)
+ p_params->normal=-p_params->normal;
+ p_params->collisions++;
+ }
+
+ }
+
+
+
+ } else {
+
+ if (bvh->left>=0)
+ _cull_segment(bvh->left,p_params);
+ if (bvh->right>=0)
+ _cull_segment(bvh->right,p_params);
+
+
+ }
+}
+
+bool ConcavePolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+ if (faces.size()==0)
+ return false;
+
+ // unlock data
+ DVector<Face>::Read fr=faces.read();
+ DVector<Vector3>::Read vr=vertices.read();
+ DVector<BVH>::Read br=bvh.read();
+
+
+ _SegmentCullParams params;
+ params.from=p_begin;
+ params.to=p_end;
+ params.collisions=0;
+ params.dir=(p_end-p_begin).normalized();
+
+ params.faces=fr.ptr();
+ params.vertices=vr.ptr();
+ params.bvh=br.ptr();
+
+ params.min_d=1e20;
+ // cull
+ _cull_segment(0,&params);
+
+ if (params.collisions>0) {
+
+
+ r_result=params.result;
+ r_normal=params.normal;
+ return true;
+ } else {
+
+ return false;
+ }
+}
+
+void ConcavePolygonShapeSW::_cull(int p_idx,_CullParams *p_params) const {
+
+ const BVH* bvh=&p_params->bvh[p_idx];
+
+ if (!p_params->aabb.intersects( bvh->aabb ))
+ return;
+
+ if (bvh->face_index>=0) {
+
+ const Face *f=&p_params->faces[ bvh->face_index ];
+ FaceShapeSW *face=p_params->face;
+ face->normal=f->normal;
+ face->vertex[0]=p_params->vertices[f->indices[0]];
+ face->vertex[1]=p_params->vertices[f->indices[1]];
+ face->vertex[2]=p_params->vertices[f->indices[2]];
+ p_params->callback(p_params->userdata,face);
+
+ } else {
+
+ if (bvh->left>=0) {
+
+ _cull(bvh->left,p_params);
+
+ }
+
+ if (bvh->right>=0) {
+
+ _cull(bvh->right,p_params);
+ }
+
+ }
+}
+
+void ConcavePolygonShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
+
+ // make matrix local to concave
+ if (faces.size()==0)
+ return;
+
+ AABB local_aabb=p_local_aabb;
+
+ // unlock data
+ DVector<Face>::Read fr=faces.read();
+ DVector<Vector3>::Read vr=vertices.read();
+ DVector<BVH>::Read br=bvh.read();
+
+ FaceShapeSW face; // use this to send in the callback
+
+ _CullParams params;
+ params.aabb=local_aabb;
+ params.face=&face;
+ params.faces=fr.ptr();
+ params.vertices=vr.ptr();
+ params.bvh=br.ptr();
+ params.callback=p_callback;
+ params.userdata=p_userdata;
+
+ // cull
+ _cull(0,&params);
+
+}
+
+Vector3 ConcavePolygonShapeSW::get_moment_of_inertia(float p_mass) const {
+
+ // use crappy AABB approximation
+ Vector3 extents=get_aabb().size*0.5;
+
+ return Vector3(
+ (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
+ (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
+ (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
+ );
+}
+
+
+struct _VolumeSW_BVH_Element {
+
+ AABB aabb;
+ Vector3 center;
+ int face_index;
+};
+
+struct _VolumeSW_BVH_CompareX {
+
+ _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
+
+ return a.center.x<b.center.x;
+ }
+};
+
+
+struct _VolumeSW_BVH_CompareY {
+
+ _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
+
+ return a.center.y<b.center.y;
+ }
+};
+
+struct _VolumeSW_BVH_CompareZ {
+
+ _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
+
+ return a.center.z<b.center.z;
+ }
+};
+
+struct _VolumeSW_BVH {
+
+ AABB aabb;
+ _VolumeSW_BVH *left;
+ _VolumeSW_BVH *right;
+
+ int face_index;
+};
+
+
+_VolumeSW_BVH* _volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements,int p_size,int &count) {
+
+ _VolumeSW_BVH* bvh = memnew( _VolumeSW_BVH );
+
+ if (p_size==1) {
+ //leaf
+ bvh->aabb=p_elements[0].aabb;
+ bvh->left=NULL;
+ bvh->right=NULL;
+ bvh->face_index=p_elements->face_index;
+ count++;
+ return bvh;
+ } else {
+
+ bvh->face_index=-1;
+ }
+
+ AABB aabb;
+ for(int i=0;i<p_size;i++) {
+
+ if (i==0)
+ aabb=p_elements[i].aabb;
+ else
+ aabb.merge_with(p_elements[i].aabb);
+ }
+ bvh->aabb=aabb;
+ switch(aabb.get_longest_axis_index()) {
+
+ case 0: {
+
+ SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareX> sort_x;
+ sort_x.sort(p_elements,p_size);
+
+ } break;
+ case 1: {
+
+ SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareY> sort_y;
+ sort_y.sort(p_elements,p_size);
+ } break;
+ case 2: {
+
+ SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareZ> sort_z;
+ sort_z.sort(p_elements,p_size);
+ } break;
+ }
+
+ int split=p_size/2;
+ bvh->left=_volume_sw_build_bvh(p_elements,split,count);
+ bvh->right=_volume_sw_build_bvh(&p_elements[split],p_size-split,count);
+
+// printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index);
+ count++;
+ return bvh;
+}
+
+
+void ConcavePolygonShapeSW::_fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array,int& p_idx) {
+
+ int idx=p_idx;
+
+
+ p_bvh_array[idx].aabb=p_bvh_tree->aabb;
+ p_bvh_array[idx].face_index=p_bvh_tree->face_index;
+// printf("%p - %i: %i(%p) -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right);
+
+
+ if (p_bvh_tree->left) {
+ p_bvh_array[idx].left=++p_idx;
+ _fill_bvh(p_bvh_tree->left,p_bvh_array,p_idx);
+
+ } else {
+
+ p_bvh_array[p_idx].left=-1;
+ }
+
+ if (p_bvh_tree->right) {
+ p_bvh_array[idx].right=++p_idx;
+ _fill_bvh(p_bvh_tree->right,p_bvh_array,p_idx);
+
+ } else {
+
+ p_bvh_array[p_idx].right=-1;
+ }
+
+ memdelete(p_bvh_tree);
+
+}
+
+void ConcavePolygonShapeSW::_setup(DVector<Vector3> p_faces) {
+
+ int src_face_count=p_faces.size();
+ ERR_FAIL_COND(src_face_count%3);
+ src_face_count/=3;
+
+ DVector<Vector3>::Read r = p_faces.read();
+ const Vector3 * facesr= r.ptr();
+
+#if 0
+ Map<Vector3,int> point_map;
+ List<Face> face_list;
+
+
+ for(int i=0;i<src_face_count;i++) {
+
+ Face3 faceaux;
+
+ for(int j=0;j<3;j++) {
+
+ faceaux.vertex[j]=facesr[i*3+j].snapped(_POINT_SNAP);
+ //faceaux.vertex[j]=facesr[i*3+j];//facesr[i*3+j].snapped(_POINT_SNAP);
+ }
+
+ ERR_CONTINUE( faceaux.is_degenerate() );
+
+ Face face;
+
+ for(int j=0;j<3;j++) {
+
+
+ Map<Vector3,int>::Element *E=point_map.find(faceaux.vertex[j]);
+ if (E) {
+
+ face.indices[j]=E->value();
+ } else {
+
+ face.indices[j]=point_map.size();
+ point_map.insert(faceaux.vertex[j],point_map.size());
+
+ }
+ }
+
+ face_list.push_back(face);
+ }
+
+ vertices.resize( point_map.size() );
+
+ DVector<Vector3>::Write vw = vertices.write();
+ Vector3 *verticesw=vw.ptr();
+
+ AABB _aabb;
+
+ for( Map<Vector3,int>::Element *E=point_map.front();E;E=E->next()) {
+
+ if (E==point_map.front()) {
+ _aabb.pos=E->key();
+ } else {
+
+ _aabb.expand_to(E->key());
+ }
+ verticesw[E->value()]=E->key();
+ }
+
+ point_map.clear(); // not needed anymore
+
+ faces.resize(face_list.size());
+ DVector<Face>::Write w = faces.write();
+ Face *facesw=w.ptr();
+
+ int fc=0;
+
+ for( List<Face>::Element *E=face_list.front();E;E=E->next()) {
+
+ facesw[fc++]=E->get();
+ }
+
+ face_list.clear();
+
+
+ DVector<_VolumeSW_BVH_Element> bvh_array;
+ bvh_array.resize( fc );
+
+ DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
+ _VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
+
+
+ for(int i=0;i<fc;i++) {
+
+ AABB face_aabb;
+ face_aabb.pos=verticesw[facesw[i].indices[0]];
+ face_aabb.expand_to( verticesw[facesw[i].indices[1]] );
+ face_aabb.expand_to( verticesw[facesw[i].indices[2]] );
+
+ bvh_arrayw[i].face_index=i;
+ bvh_arrayw[i].aabb=face_aabb;
+ bvh_arrayw[i].center=face_aabb.pos+face_aabb.size*0.5;
+
+ }
+
+ w=DVector<Face>::Write();
+ vw=DVector<Vector3>::Write();
+
+
+ int count=0;
+ _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,fc,count);
+
+ ERR_FAIL_COND(count==0);
+
+ bvhw=DVector<_VolumeSW_BVH_Element>::Write();
+
+ bvh.resize( count+1 );
+
+ DVector<BVH>::Write bvhw2 = bvh.write();
+ BVH*bvh_arrayw2=bvhw2.ptr();
+
+ int idx=0;
+ _fill_bvh(bvh_tree,bvh_arrayw2,idx);
+
+ set_aabb(_aabb);
+
+#else
+ DVector<_VolumeSW_BVH_Element> bvh_array;
+ bvh_array.resize( src_face_count );
+
+ DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
+ _VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
+
+ faces.resize(src_face_count);
+ DVector<Face>::Write w = faces.write();
+ Face *facesw=w.ptr();
+
+ vertices.resize( src_face_count*3 );
+
+ DVector<Vector3>::Write vw = vertices.write();
+ Vector3 *verticesw=vw.ptr();
+
+ AABB _aabb;
+
+
+ for(int i=0;i<src_face_count;i++) {
+
+ Face3 face( facesr[i*3+0], facesr[i*3+1], facesr[i*3+2] );
+
+ bvh_arrayw[i].aabb=face.get_aabb();
+ bvh_arrayw[i].center = bvh_arrayw[i].aabb.pos + bvh_arrayw[i].aabb.size * 0.5;
+ bvh_arrayw[i].face_index=i;
+ facesw[i].indices[0]=i*3+0;
+ facesw[i].indices[1]=i*3+1;
+ facesw[i].indices[2]=i*3+2;
+ facesw[i].normal=face.get_plane().normal;
+ verticesw[i*3+0]=face.vertex[0];
+ verticesw[i*3+1]=face.vertex[1];
+ verticesw[i*3+2]=face.vertex[2];
+ if (i==0)
+ _aabb=bvh_arrayw[i].aabb;
+ else
+ _aabb.merge_with(bvh_arrayw[i].aabb);
+
+ }
+
+ w=DVector<Face>::Write();
+ vw=DVector<Vector3>::Write();
+
+ int count=0;
+ _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,src_face_count,count);
+
+ bvh.resize( count+1 );
+
+ DVector<BVH>::Write bvhw2 = bvh.write();
+ BVH*bvh_arrayw2=bvhw2.ptr();
+
+ int idx=0;
+ _fill_bvh(bvh_tree,bvh_arrayw2,idx);
+
+ configure(_aabb); // this type of shape has no margin
+
+
+#endif
+}
+
+
+void ConcavePolygonShapeSW::set_data(const Variant& p_data) {
+
+
+ _setup(p_data);
+}
+
+Variant ConcavePolygonShapeSW::get_data() const {
+
+ return get_faces();
+}
+
+ConcavePolygonShapeSW::ConcavePolygonShapeSW() {
+
+
+}
+
+
+
+/* HEIGHT MAP SHAPE */
+
+DVector<float> HeightMapShapeSW::get_heights() const {
+
+ return heights;
+}
+int HeightMapShapeSW::get_width() const {
+
+ return width;
+}
+int HeightMapShapeSW::get_depth() const {
+
+ return depth;
+}
+float HeightMapShapeSW::get_cell_size() const {
+
+ return cell_size;
+}
+
+
+void HeightMapShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ //not very useful, but not very used either
+ p_transform.xform(get_aabb()).project_range_in_plane( Plane(p_normal,0),r_min,r_max );
+
+}
+
+Vector3 HeightMapShapeSW::get_support(const Vector3& p_normal) const {
+
+
+ //not very useful, but not very used either
+ return get_aabb().get_support(p_normal);
+
+}
+
+bool HeightMapShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const {
+
+
+ return false;
+}
+
+
+void HeightMapShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
+
+
+
+}
+
+
+Vector3 HeightMapShapeSW::get_moment_of_inertia(float p_mass) const {
+
+
+ // use crappy AABB approximation
+ Vector3 extents=get_aabb().size*0.5;
+
+ return Vector3(
+ (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
+ (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
+ (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
+ );
+}
+
+
+void HeightMapShapeSW::_setup(DVector<real_t> p_heights,int p_width,int p_depth,real_t p_cell_size) {
+
+ heights=p_heights;
+ width=p_width;
+ depth=p_depth;;
+ cell_size=p_cell_size;
+
+ DVector<real_t>::Read r = heights. read();
+
+ AABB aabb;
+
+ for(int i=0;i<depth;i++) {
+
+ for(int j=0;j<width;j++) {
+
+ float h = r[i*width+j];
+
+ Vector3 pos( j*cell_size, h, i*cell_size );
+ if (i==0 || j==0)
+ aabb.pos=pos;
+ else
+ aabb.expand_to(pos);
+
+ }
+ }
+
+
+ configure(aabb);
+}
+
+void HeightMapShapeSW::set_data(const Variant& p_data) {
+
+ ERR_FAIL_COND( p_data.get_type()!=Variant::DICTIONARY );
+ Dictionary d=p_data;
+ ERR_FAIL_COND( !d.has("width") );
+ ERR_FAIL_COND( !d.has("depth") );
+ ERR_FAIL_COND( !d.has("cell_size") );
+ ERR_FAIL_COND( !d.has("heights") );
+
+ int width=d["width"];
+ int depth=d["depth"];
+ float cell_size=d["cell_size"];
+ DVector<float> heights=d["heights"];
+
+ ERR_FAIL_COND( width<= 0);
+ ERR_FAIL_COND( depth<= 0);
+ ERR_FAIL_COND( cell_size<= CMP_EPSILON);
+ ERR_FAIL_COND( heights.size() != (width*depth) );
+ _setup(heights, width, depth, cell_size );
+
+}
+
+Variant HeightMapShapeSW::get_data() const {
+
+ ERR_FAIL_V(Variant());
+
+}
+
+HeightMapShapeSW::HeightMapShapeSW() {
+
+ width=0;
+ depth=0;
+ cell_size=0;
+}
+
+
+
diff --git a/servers/physics/shape_sw.h b/servers/physics/shape_sw.h
index 890d6d8741..4826eaea4f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,405 +26,446 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SHAPE_SW_H
-#define SHAPE_SW_H
-
-#include "servers/physics_server.h"
-#include "bsp_tree.h"
-#include "geometry.h"
-/*
-
-SHAPE_LINE, ///< plane:"plane"
-SHAPE_SEGMENT, ///< float:"length"
-SHAPE_CIRCLE, ///< float:"radius"
-SHAPE_RECTANGLE, ///< vec3:"extents"
-SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
-SHAPE_CONCAVE_POLYGON, ///< Vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
-SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
-
-*/
-
-class ShapeSW;
-
-class ShapeOwnerSW {
-public:
-
- virtual void _shape_changed()=0;
- virtual void remove_shape(ShapeSW *p_shape)=0;
-
- virtual ~ShapeOwnerSW() {}
-};
-
-
-class ShapeSW {
-
- RID self;
- AABB aabb;
- bool configured;
- real_t custom_bias;
-
- Map<ShapeOwnerSW*,int> owners;
-protected:
-
- void configure(const AABB& p_aabb);
-public:
-
- enum {
- MAX_SUPPORTS=8
- };
-
- _FORCE_INLINE_ void set_self(const RID& p_self) { self=p_self; }
- _FORCE_INLINE_ RID get_self() const {return self; }
-
- virtual PhysicsServer::ShapeType get_type() const=0;
-
- _FORCE_INLINE_ AABB get_aabb() const { return aabb; }
- _FORCE_INLINE_ bool is_configured() const { return configured; }
-
- virtual bool is_concave() const { return false; }
-
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const=0;
- virtual Vector3 get_support(const Vector3& p_normal) const;
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const=0;
-
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const=0;
- virtual Vector3 get_moment_of_inertia(float p_mass) const=0;
-
- virtual void set_data(const Variant& p_data)=0;
- virtual Variant get_data() const=0;
-
- _FORCE_INLINE_ void set_custom_bias(real_t p_bias) { custom_bias=p_bias; }
- _FORCE_INLINE_ real_t get_custom_bias() const { return custom_bias; }
-
- void add_owner(ShapeOwnerSW *p_owner);
- void remove_owner(ShapeOwnerSW *p_owner);
- bool is_owner(ShapeOwnerSW *p_owner) const;
- const Map<ShapeOwnerSW*,int>& get_owners() const;
-
- ShapeSW();
- virtual ~ShapeSW();
-};
-
-
-class ConcaveShapeSW : public ShapeSW {
-
-public:
-
- virtual bool is_concave() const { return true; }
- typedef void (*Callback)(void* p_userdata,ShapeSW *p_convex);
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { r_amount=0; }
-
- virtual void cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const=0;
-
- ConcaveShapeSW() {}
-};
-
-class PlaneShapeSW : public ShapeSW {
-
- Plane plane;
-
- void _setup(const Plane& p_plane);
-public:
-
- Plane get_plane() const;
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_PLANE; }
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3& p_normal) const;
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { r_amount=0; }
-
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- virtual Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data);
- virtual Variant get_data() const;
-
- PlaneShapeSW();
-};
-
-class RayShapeSW : public ShapeSW {
-
- float length;
-
- void _setup(float p_length);
-public:
-
- float get_length() const;
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_RAY; }
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3& p_normal) const;
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
-
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- virtual Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data);
- virtual Variant get_data() const;
-
- RayShapeSW();
-};
-
-class SphereShapeSW : public ShapeSW {
-
- real_t radius;
-
- void _setup(real_t p_radius);
-public:
-
- real_t get_radius() const;
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_SPHERE; }
-
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3& p_normal) const;
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- virtual Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data);
- virtual Variant get_data() const;
-
- SphereShapeSW();
-};
-
-class BoxShapeSW : public ShapeSW {
-
- Vector3 half_extents;
- void _setup(const Vector3& p_half_extents);
-public:
-
- _FORCE_INLINE_ Vector3 get_half_extents() const { return half_extents; }
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_BOX; }
-
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3& p_normal) const;
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- virtual Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data);
- virtual Variant get_data() const;
-
- BoxShapeSW();
-};
-
-class CapsuleShapeSW : public ShapeSW {
-
- real_t height;
- real_t radius;
-
-
- void _setup(real_t p_height,real_t p_radius);
-public:
-
- _FORCE_INLINE_ real_t get_height() const { return height; }
- _FORCE_INLINE_ real_t get_radius() const { return radius; }
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CAPSULE; }
-
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3& p_normal) const;
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- virtual Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data);
- virtual Variant get_data() const;
-
- CapsuleShapeSW();
-};
-
-struct ConvexPolygonShapeSW : public ShapeSW {
-
- Geometry::MeshData mesh;
-
- void _setup(const Vector<Vector3>& p_vertices);
-public:
-
- const Geometry::MeshData& get_mesh() const { return mesh; }
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONVEX_POLYGON; }
-
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3& p_normal) const;
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- virtual Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data);
- virtual Variant get_data() const;
-
- ConvexPolygonShapeSW();
-
-};
-
-
-struct _VolumeSW_BVH;
-struct FaceShapeSW;
-
-struct ConcavePolygonShapeSW : public ConcaveShapeSW {
- // always a trimesh
-
- struct Face {
-
- Vector3 normal;
- int indices[3];
- };
-
- DVector<Face> faces;
- DVector<Vector3> vertices;
-
- struct BVH {
-
- AABB aabb;
- int left;
- int right;
-
- int face_index;
- };
-
- DVector<BVH> bvh;
-
- struct _CullParams {
-
- AABB aabb;
- Callback callback;
- void *userdata;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
- FaceShapeSW *face;
- };
-
- struct _SegmentCullParams {
-
- Vector3 from;
- Vector3 to;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
-
- Vector3 result;
- Vector3 normal;
- real_t min_d;
- int collisions;
-
- };
-
- void _cull_segment(int p_idx,_SegmentCullParams *p_params) const;
- void _cull(int p_idx,_CullParams *p_params) const;
-
- void _fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array,int& p_idx);
-
-
- void _setup(DVector<Vector3> p_faces);
-public:
-
- DVector<Vector3> get_faces() const;
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONCAVE_POLYGON; }
-
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3& p_normal) const;
-
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- virtual void cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const;
-
- virtual Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data);
- virtual Variant get_data() const;
-
- ConcavePolygonShapeSW();
-
-};
-
-
-struct HeightMapShapeSW : public ConcaveShapeSW {
-
- DVector<real_t> heights;
- int width;
- int depth;
- float cell_size;
-
-// void _cull_segment(int p_idx,_SegmentCullParams *p_params) const;
-// void _cull(int p_idx,_CullParams *p_params) const;
-
- void _setup(DVector<float> p_heights,int p_width,int p_depth,float p_cell_size);
-public:
-
- DVector<real_t> get_heights() const;
- int get_width() const;
- int get_depth() const;
- float get_cell_size() const;
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_HEIGHTMAP; }
-
- virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3& p_normal) const;
- virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- virtual void cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const;
-
- virtual Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data);
- virtual Variant get_data() const;
-
- HeightMapShapeSW();
-
-};
-
-//used internally
-struct FaceShapeSW : public ShapeSW {
-
- Vector3 normal; //cache
- Vector3 vertex[3];
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONCAVE_POLYGON; }
-
- const Vector3& get_vertex(int p_idx) const { return vertex[p_idx]; }
-
- void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
- Vector3 get_support(const Vector3& p_normal) const;
- virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
- bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
-
- Vector3 get_moment_of_inertia(float p_mass) const;
-
- virtual void set_data(const Variant& p_data) {}
- virtual Variant get_data() const { return Variant(); }
-
- FaceShapeSW();
-};
-
-
-
-
-
-struct _ShapeTestConvexBSPSW {
-
- const BSP_Tree *bsp;
- const ShapeSW *shape;
- Transform transform;
-
- _FORCE_INLINE_ void project_range(const Vector3& p_normal, real_t& r_min, real_t& r_max) const {
-
- shape->project_range(p_normal,transform,r_min,r_max);
- }
-
-};
-
-
-
-
-#endif // SHAPESW_H
+#ifndef SHAPE_SW_H
+#define SHAPE_SW_H
+
+#include "servers/physics_server.h"
+#include "bsp_tree.h"
+#include "geometry.h"
+/*
+
+SHAPE_LINE, ///< plane:"plane"
+SHAPE_SEGMENT, ///< float:"length"
+SHAPE_CIRCLE, ///< float:"radius"
+SHAPE_RECTANGLE, ///< vec3:"extents"
+SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
+SHAPE_CONCAVE_POLYGON, ///< Vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
+SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
+
+*/
+
+class ShapeSW;
+
+class ShapeOwnerSW {
+public:
+
+ virtual void _shape_changed()=0;
+ virtual void remove_shape(ShapeSW *p_shape)=0;
+
+ virtual ~ShapeOwnerSW() {}
+};
+
+
+class ShapeSW {
+
+ RID self;
+ AABB aabb;
+ bool configured;
+ real_t custom_bias;
+
+ Map<ShapeOwnerSW*,int> owners;
+protected:
+
+ void configure(const AABB& p_aabb);
+public:
+
+ enum {
+ MAX_SUPPORTS=8
+ };
+
+ _FORCE_INLINE_ void set_self(const RID& p_self) { self=p_self; }
+ _FORCE_INLINE_ RID get_self() const {return self; }
+
+ virtual PhysicsServer::ShapeType get_type() const=0;
+
+ _FORCE_INLINE_ AABB get_aabb() const { return aabb; }
+ _FORCE_INLINE_ bool is_configured() const { return configured; }
+
+ virtual bool is_concave() const { return false; }
+
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const=0;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const=0;
+
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const=0;
+ virtual Vector3 get_moment_of_inertia(float p_mass) const=0;
+
+ virtual void set_data(const Variant& p_data)=0;
+ virtual Variant get_data() const=0;
+
+ _FORCE_INLINE_ void set_custom_bias(real_t p_bias) { custom_bias=p_bias; }
+ _FORCE_INLINE_ real_t get_custom_bias() const { return custom_bias; }
+
+ void add_owner(ShapeOwnerSW *p_owner);
+ void remove_owner(ShapeOwnerSW *p_owner);
+ bool is_owner(ShapeOwnerSW *p_owner) const;
+ const Map<ShapeOwnerSW*,int>& get_owners() const;
+
+ ShapeSW();
+ virtual ~ShapeSW();
+};
+
+
+class ConcaveShapeSW : public ShapeSW {
+
+public:
+
+ virtual bool is_concave() const { return true; }
+ typedef void (*Callback)(void* p_userdata,ShapeSW *p_convex);
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { r_amount=0; }
+
+ virtual void cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const=0;
+
+ ConcaveShapeSW() {}
+};
+
+class PlaneShapeSW : public ShapeSW {
+
+ Plane plane;
+
+ void _setup(const Plane& p_plane);
+public:
+
+ Plane get_plane() const;
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_PLANE; }
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { r_amount=0; }
+
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ virtual Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data);
+ virtual Variant get_data() const;
+
+ PlaneShapeSW();
+};
+
+class RayShapeSW : public ShapeSW {
+
+ float length;
+
+ void _setup(float p_length);
+public:
+
+ float get_length() const;
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_RAY; }
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
+
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ virtual Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data);
+ virtual Variant get_data() const;
+
+ RayShapeSW();
+};
+
+class SphereShapeSW : public ShapeSW {
+
+ real_t radius;
+
+ void _setup(real_t p_radius);
+public:
+
+ real_t get_radius() const;
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_SPHERE; }
+
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ virtual Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data);
+ virtual Variant get_data() const;
+
+ SphereShapeSW();
+};
+
+class BoxShapeSW : public ShapeSW {
+
+ Vector3 half_extents;
+ void _setup(const Vector3& p_half_extents);
+public:
+
+ _FORCE_INLINE_ Vector3 get_half_extents() const { return half_extents; }
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_BOX; }
+
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ virtual Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data);
+ virtual Variant get_data() const;
+
+ BoxShapeSW();
+};
+
+class CapsuleShapeSW : public ShapeSW {
+
+ real_t height;
+ real_t radius;
+
+
+ void _setup(real_t p_height,real_t p_radius);
+public:
+
+ _FORCE_INLINE_ real_t get_height() const { return height; }
+ _FORCE_INLINE_ real_t get_radius() const { return radius; }
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CAPSULE; }
+
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ virtual Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data);
+ virtual Variant get_data() const;
+
+ CapsuleShapeSW();
+};
+
+struct ConvexPolygonShapeSW : public ShapeSW {
+
+ Geometry::MeshData mesh;
+
+ void _setup(const Vector<Vector3>& p_vertices);
+public:
+
+ const Geometry::MeshData& get_mesh() const { return mesh; }
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONVEX_POLYGON; }
+
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ virtual Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data);
+ virtual Variant get_data() const;
+
+ ConvexPolygonShapeSW();
+
+};
+
+
+struct _VolumeSW_BVH;
+struct FaceShapeSW;
+
+struct ConcavePolygonShapeSW : public ConcaveShapeSW {
+ // always a trimesh
+
+ struct Face {
+
+ Vector3 normal;
+ int indices[3];
+ };
+
+ DVector<Face> faces;
+ DVector<Vector3> vertices;
+
+ struct BVH {
+
+ AABB aabb;
+ int left;
+ int right;
+
+ int face_index;
+ };
+
+ DVector<BVH> bvh;
+
+ struct _CullParams {
+
+ AABB aabb;
+ Callback callback;
+ void *userdata;
+ const Face *faces;
+ const Vector3 *vertices;
+ const BVH *bvh;
+ FaceShapeSW *face;
+ };
+
+ struct _SegmentCullParams {
+
+ Vector3 from;
+ Vector3 to;
+ const Face *faces;
+ const Vector3 *vertices;
+ const BVH *bvh;
+ Vector3 dir;
+
+ Vector3 result;
+ Vector3 normal;
+ real_t min_d;
+ int collisions;
+
+ };
+
+ void _cull_segment(int p_idx,_SegmentCullParams *p_params) const;
+ void _cull(int p_idx,_CullParams *p_params) const;
+
+ void _fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array,int& p_idx);
+
+
+ void _setup(DVector<Vector3> p_faces);
+public:
+
+ DVector<Vector3> get_faces() const;
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONCAVE_POLYGON; }
+
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ virtual void cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const;
+
+ virtual Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data);
+ virtual Variant get_data() const;
+
+ ConcavePolygonShapeSW();
+
+};
+
+
+struct HeightMapShapeSW : public ConcaveShapeSW {
+
+ DVector<real_t> heights;
+ int width;
+ int depth;
+ float cell_size;
+
+// void _cull_segment(int p_idx,_SegmentCullParams *p_params) const;
+// void _cull(int p_idx,_CullParams *p_params) const;
+
+ void _setup(DVector<float> p_heights,int p_width,int p_depth,float p_cell_size);
+public:
+
+ DVector<real_t> get_heights() const;
+ int get_width() const;
+ int get_depth() const;
+ float get_cell_size() const;
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_HEIGHTMAP; }
+
+ virtual void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3& p_normal) const;
+ virtual bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ virtual void cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const;
+
+ virtual Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data);
+ virtual Variant get_data() const;
+
+ HeightMapShapeSW();
+
+};
+
+//used internally
+struct FaceShapeSW : public ShapeSW {
+
+ Vector3 normal; //cache
+ Vector3 vertex[3];
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONCAVE_POLYGON; }
+
+ const Vector3& get_vertex(int p_idx) const { return vertex[p_idx]; }
+
+ void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const;
+ Vector3 get_support(const Vector3& p_normal) const;
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const;
+ bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const;
+
+ Vector3 get_moment_of_inertia(float p_mass) const;
+
+ virtual void set_data(const Variant& p_data) {}
+ virtual Variant get_data() const { return Variant(); }
+
+ FaceShapeSW();
+};
+
+
+struct MotionShapeSW : public ShapeSW {
+
+ ShapeSW *shape;
+ Vector3 motion;
+
+ virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONVEX_POLYGON; }
+
+
+ void project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+ Vector3 cast = p_transform.basis.xform(motion);
+ real_t mina,maxa;
+ real_t minb,maxb;
+ Transform ofsb = p_transform;
+ ofsb.origin+=cast;
+ shape->project_range(p_normal,p_transform,mina,maxa);
+ shape->project_range(p_normal,ofsb,minb,maxb);
+ r_min=MIN(mina,minb);
+ r_max=MAX(maxa,maxb);
+ }
+
+ Vector3 get_support(const Vector3& p_normal) const {
+
+ Vector3 support = shape->get_support(p_normal);
+ if (p_normal.dot(motion)>0) {
+ support+=motion;
+ }
+ return support;
+ }
+ virtual void get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { r_amount=0; }
+ bool intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { return false; }
+
+ Vector3 get_moment_of_inertia(float p_mass) const { return Vector3(); }
+
+ virtual void set_data(const Variant& p_data) {}
+ virtual Variant get_data() const { return Variant(); }
+
+ MotionShapeSW() { configure(AABB()); }
+};
+
+
+
+
+struct _ShapeTestConvexBSPSW {
+
+ const BSP_Tree *bsp;
+ const ShapeSW *shape;
+ Transform transform;
+
+ _FORCE_INLINE_ void project_range(const Vector3& p_normal, real_t& r_min, real_t& r_max) const {
+
+ shape->project_range(p_normal,transform,r_min,r_max);
+ }
+
+};
+
+
+
+
+#endif // SHAPESW_H
diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp
index ad86a62280..778d20d3f1 100644
--- a/servers/physics/space_sw.cpp
+++ b/servers/physics/space_sw.cpp
@@ -1,430 +1,748 @@
-/*************************************************************************/
-/* space_sw.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "globals.h"
-#include "space_sw.h"
-#include "collision_solver_sw.h"
-#include "physics_server_sw.h"
-
-
-bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3& p_from, const Vector3& p_to,RayResult &r_result,const Set<RID>& p_exclude,uint32_t p_user_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 (space->intersection_query_results[i]->get_type()==CollisionObjectSW::TYPE_AREA)
- continue; //ignore area
-
- 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);
- 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,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude,uint32_t p_user_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 (space->intersection_query_results[i]->get_type()==CollisionObjectSW::TYPE_AREA)
- continue; //ignore area
-
- 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))
- 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);
- r_results[cc].rid=col_obj->get_self();
- r_results[cc].shape=shape_idx;
-
- cc++;
-
- }
-
- return cc;
-
-}
-
-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;
-
- if (type_A==CollisionObjectSW::TYPE_AREA) {
-
-
- ERR_FAIL_COND_V(type_B!=CollisionObjectSW::TYPE_BODY,NULL);
- AreaSW *area=static_cast<AreaSW*>(A);
- 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;
- 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() {
-
-
- 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-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_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) {
+
+
+ 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;
+
+ 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 cec1053400..ac788ba93f 100644
--- a/servers/physics/space_sw.h
+++ b/servers/physics/space_sw.h
@@ -1,157 +1,187 @@
-/*************************************************************************/
-/* space_sw.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#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;
-
- bool intersect_ray(const Vector3& p_from, const Vector3& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0);
- int intersect_shape(const RID& p_shape, const Transform& p_xform,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0);
-
- 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;
-
-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;
-
- PhysicsDirectSpaceStateSW *get_direct_state();
-
- SpaceSW();
- ~SpaceSW();
-};
-
-
-#endif // SPACE__SW_H
+/*************************************************************************/
+/* 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;
+
+ 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 b7815d2250..2424b36833 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "step_sw.h"
-
+#include "joints_sw.h"
void StepSW::_populate_island(BodySW* p_body,BodySW** p_island,ConstraintSW **p_constraint_island) {
@@ -49,7 +49,7 @@ void StepSW::_populate_island(BodySW* p_body,BodySW** p_island,ConstraintSW **p_
if (i==E->get())
continue;
BodySW *b = c->get_body_ptr()[i];
- if (b->get_island_step()==_step || b->get_mode()==PhysicsServer::BODY_MODE_STATIC)
+ if (b->get_island_step()==_step || b->get_mode()==PhysicsServer::BODY_MODE_STATIC || b->get_mode()==PhysicsServer::BODY_MODE_KINEMATIC)
continue; //no go
_populate_island(c->get_body_ptr()[i],p_island,p_constraint_island);
}
@@ -68,14 +68,41 @@ void StepSW::_setup_island(ConstraintSW *p_island,float p_delta) {
void StepSW::_solve_island(ConstraintSW *p_island,int p_iterations,float p_delta){
- for(int i=0;i<p_iterations;i++) {
+ int at_priority=1;
- ConstraintSW *ci=p_island;
- while(ci) {
- ci->solve(p_delta);
- ci=ci->get_island_next();
+ while(p_island) {
+
+ for(int i=0;i<p_iterations;i++) {
+
+ ConstraintSW *ci=p_island;
+ while(ci) {
+ ci->solve(p_delta);
+ ci=ci->get_island_next();
+ }
+ }
+
+ at_priority++;
+
+ {
+ ConstraintSW *ci=p_island;
+ ConstraintSW *prev=NULL;
+ while(ci) {
+ if (ci->get_priority()<at_priority) {
+ if (prev) {
+ prev->set_island_next(ci->get_island_next()); //remove
+ } else {
+ p_island=ci->get_island_next();
+ }
+ } else {
+
+ prev=ci;
+ }
+
+ ci=ci->get_island_next();
+ }
}
}
+
}
void StepSW::_check_suspend(BodySW *p_island,float p_delta) {
@@ -86,8 +113,10 @@ void StepSW::_check_suspend(BodySW *p_island,float p_delta) {
BodySW *b = p_island;
while(b) {
- if (b->get_mode()==PhysicsServer::BODY_MODE_STATIC)
+ if (b->get_mode()==PhysicsServer::BODY_MODE_STATIC || b->get_mode()==PhysicsServer::BODY_MODE_KINEMATIC) {
+ b=b->get_island_next();
continue; //ignore for static
+ }
if (!b->sleep_test(p_delta))
can_sleep=false;
@@ -100,8 +129,10 @@ void StepSW::_check_suspend(BodySW *p_island,float p_delta) {
b = p_island;
while(b) {
- if (b->get_mode()==PhysicsServer::BODY_MODE_STATIC)
+ if (b->get_mode()==PhysicsServer::BODY_MODE_STATIC || b->get_mode()==PhysicsServer::BODY_MODE_KINEMATIC) {
+ b=b->get_island_next();
continue; //ignore for static
+ }
bool active = b->is_active();
@@ -131,6 +162,7 @@ void StepSW::step(SpaceSW* p_space,float p_delta,int p_iterations) {
active_count++;
}
+ p_space->set_active_objects(active_count);
/* GENERATE CONSTRAINT ISLANDS */
@@ -164,6 +196,8 @@ void StepSW::step(SpaceSW* p_space,float p_delta,int p_iterations) {
b=b->next();
}
+ p_space->set_island_count(island_count);
+
const SelfList<AreaSW>::List &aml = p_space->get_moved_area_list();
while(aml.first()) {
@@ -207,9 +241,9 @@ void StepSW::step(SpaceSW* p_space,float p_delta,int p_iterations) {
b = body_list->first();
while(b) {
-
+ const SelfList<BodySW>*n=b->next();
b->self()->integrate_velocities(p_delta);
- b=b->next();
+ b=n;
}
/* SLEEP / WAKE UP ISLANDS */
diff --git a/servers/physics/step_sw.h b/servers/physics/step_sw.h
index 9aaef97920..f089c041fc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 c840004190..a5a132020a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,6 +31,7 @@
#include "body_2d_sw.h"
Area2DSW::BodyKey::BodyKey(Body2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape) { rid=p_body->get_self(); instance_id=p_body->get_instance_id(); body_shape=p_body_shape; area_shape=p_area_shape; }
+Area2DSW::BodyKey::BodyKey(Area2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape) { rid=p_body->get_self(); instance_id=p_body->get_instance_id(); body_shape=p_body_shape; area_shape=p_area_shape; }
void Area2DSW::_shapes_changed() {
@@ -43,6 +44,7 @@ void Area2DSW::set_transform(const Matrix32& p_transform) {
get_space()->area_add_to_moved_list(&moved_list);
_set_transform(p_transform);
+ _set_inv_transform(p_transform.affine_inverse());
}
void Area2DSW::set_space(Space2DSW *p_space) {
@@ -56,6 +58,7 @@ void Area2DSW::set_space(Space2DSW *p_space) {
}
monitored_bodies.clear();
+ monitored_areas.clear();
_set_space(p_space);
}
@@ -75,11 +78,39 @@ void Area2DSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) {
monitor_callback_method=p_method;
monitored_bodies.clear();
+ monitored_areas.clear();
_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) {
+
+
+ if (p_id==area_monitor_callback_id) {
+ area_monitor_callback_method=p_method;
+ return;
+ }
+
+ _unregister_shapes();
+
+ area_monitor_callback_id=p_id;
+ area_monitor_callback_method=p_method;
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _shape_changed();
+
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+
+
+}
void Area2DSW::set_space_override_mode(Physics2DServer::AreaSpaceOverrideMode p_mode) {
@@ -97,8 +128,10 @@ void Area2DSW::set_param(Physics2DServer::AreaParameter p_param, const Variant&
case Physics2DServer::AREA_PARAM_GRAVITY: gravity=p_value; ; break;
case Physics2DServer::AREA_PARAM_GRAVITY_VECTOR: gravity_vector=p_value; ; break;
case Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point=p_value; ; break;
+ case Physics2DServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: gravity_distance_scale=p_value; ; break;
case Physics2DServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation=p_value; ; break;
- case Physics2DServer::AREA_PARAM_DENSITY: density=p_value; ; break;
+ case Physics2DServer::AREA_PARAM_LINEAR_DAMP: linear_damp=p_value; ; break;
+ case Physics2DServer::AREA_PARAM_ANGULAR_DAMP: angular_damp=p_value; ; break;
case Physics2DServer::AREA_PARAM_PRIORITY: priority=p_value; ; break;
}
@@ -112,8 +145,10 @@ Variant Area2DSW::get_param(Physics2DServer::AreaParameter p_param) const {
case Physics2DServer::AREA_PARAM_GRAVITY: return gravity;
case Physics2DServer::AREA_PARAM_GRAVITY_VECTOR: return gravity_vector;
case Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point;
+ case Physics2DServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: return gravity_distance_scale;
case Physics2DServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation;
- case Physics2DServer::AREA_PARAM_DENSITY: return density;
+ case Physics2DServer::AREA_PARAM_LINEAR_DAMP: return linear_damp;
+ case Physics2DServer::AREA_PARAM_ANGULAR_DAMP: return angular_damp;
case Physics2DServer::AREA_PARAM_PRIORITY: return priority;
}
@@ -131,6 +166,15 @@ void Area2DSW::_queue_monitor_update() {
}
+void Area2DSW::set_monitorable(bool p_monitorable) {
+
+ if (monitorable==p_monitorable)
+ return;
+
+ monitorable=p_monitorable;
+ _set_static(!monitorable);
+}
+
void Area2DSW::call_queries() {
if (monitor_callback_id && !monitored_bodies.empty()) {
@@ -167,21 +211,62 @@ void Area2DSW::call_queries() {
monitored_bodies.clear();
+ if (area_monitor_callback_id && !monitored_areas.empty()) {
+
+
+ Variant res[5];
+ Variant *resptr[5];
+ for(int i=0;i<5;i++)
+ resptr[i]=&res[i];
+
+ Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
+ if (!obj) {
+ monitored_areas.clear();
+ area_monitor_callback_id=0;
+ return;
+ }
+
+
+
+ for (Map<BodyKey,BodyState>::Element *E=monitored_areas.front();E;E=E->next()) {
+
+ if (E->get().state==0)
+ continue; //nothing happened
+
+ res[0]=E->get().state>0 ? Physics2DServer::AREA_BODY_ADDED : Physics2DServer::AREA_BODY_REMOVED;
+ res[1]=E->key().rid;
+ res[2]=E->key().instance_id;
+ res[3]=E->key().body_shape;
+ res[4]=E->key().area_shape;
+
+
+ Variant::CallError ce;
+ obj->call(area_monitor_callback_method,(const Variant**)resptr,5,ce);
+ }
+ }
+
+ monitored_areas.clear();
+
//get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
}
Area2DSW::Area2DSW() : CollisionObject2DSW(TYPE_AREA), monitor_query_list(this), moved_list(this) {
- _set_static(true); //areas are never active
+ _set_static(true); //areas are not active by default
space_override_mode=Physics2DServer::AREA_SPACE_OVERRIDE_DISABLED;
gravity=9.80665;
gravity_vector=Vector2(0,-1);
gravity_is_point=false;
+ gravity_distance_scale=0;
point_attenuation=1;
- density=0.1;
+
+ angular_damp=1.0;
+ linear_damp=0.1;
priority=0;
monitor_callback_id=0;
+ area_monitor_callback_id=0;
+ monitorable=false;
}
diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/area_2d_sw.h
index 51e6ccd166..6d99764c68 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,13 +46,19 @@ class Area2DSW : public CollisionObject2DSW{
float gravity;
Vector2 gravity_vector;
bool gravity_is_point;
+ float gravity_distance_scale;
float point_attenuation;
- float density;
+ float linear_damp;
+ float angular_damp;
int priority;
+ bool monitorable;
ObjectID monitor_callback_id;
StringName monitor_callback_method;
+ ObjectID area_monitor_callback_id;
+ StringName area_monitor_callback_method;
+
SelfList<Area2DSW> monitor_query_list;
SelfList<Area2DSW> moved_list;
@@ -71,7 +77,7 @@ class Area2DSW : public CollisionObject2DSW{
return area_shape < p_key.area_shape;
} else
- return body_shape < p_key.area_shape;
+ return body_shape < p_key.body_shape;
} else
return rid < p_key.rid;
@@ -79,6 +85,7 @@ class Area2DSW : public CollisionObject2DSW{
_FORCE_INLINE_ BodyKey() {}
BodyKey(Body2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+ BodyKey(Area2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
};
struct BodyState {
@@ -90,6 +97,7 @@ class Area2DSW : public CollisionObject2DSW{
};
Map<BodyKey,BodyState> monitored_bodies;
+ Map<BodyKey,BodyState> monitored_areas;
//virtual void shape_changed_notify(Shape2DSW *p_shape);
//virtual void shape_deleted_notify(Shape2DSW *p_shape);
@@ -107,9 +115,16 @@ public:
void set_monitor_callback(ObjectID p_id, const StringName& p_method);
_FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id; }
+ void set_area_monitor_callback(ObjectID p_id, const StringName& p_method);
+ _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id; }
+
+
_FORCE_INLINE_ void add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
_FORCE_INLINE_ void remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+ _FORCE_INLINE_ void add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape);
+ _FORCE_INLINE_ void remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape);
+
void set_param(Physics2DServer::AreaParameter p_param, const Variant& p_value);
Variant get_param(Physics2DServer::AreaParameter p_param) const;
@@ -125,11 +140,17 @@ public:
_FORCE_INLINE_ void set_gravity_as_point(bool p_enable) { gravity_is_point=p_enable; }
_FORCE_INLINE_ bool is_gravity_point() const { return gravity_is_point; }
+ _FORCE_INLINE_ void set_gravity_distance_scale(float scale) { gravity_distance_scale=scale; }
+ _FORCE_INLINE_ float get_gravity_distance_scale() const { return gravity_distance_scale; }
+
_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; }
@@ -138,6 +159,9 @@ public:
_FORCE_INLINE_ void remove_constraint( Constraint2DSW* p_constraint) { constraints.erase(p_constraint); }
_FORCE_INLINE_ const Set<Constraint2DSW*>& get_constraints() const { return constraints; }
+ void set_monitorable(bool p_monitorable);
+ _FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
+
void set_transform(const Matrix32& p_transform);
void set_space(Space2DSW *p_space);
@@ -164,6 +188,24 @@ void Area2DSW::remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape,ui
_queue_monitor_update();
}
+void Area2DSW::add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape) {
+
+
+ BodyKey bk(p_area,p_area_shape,p_self_shape);
+ monitored_areas[bk].inc();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+
+
+}
+void Area2DSW::remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape) {
+
+
+ BodyKey bk(p_area,p_area_shape,p_self_shape);
+ monitored_areas[bk].dec();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+}
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
index 35286bdb67..3b1705bd56 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@
bool AreaPair2DSW::setup(float p_step) {
- bool result = CollisionSolver2DSW::solve(body->get_shape(body_shape),body->get_transform() * body->get_shape_transform(body_shape),Vector2(),area->get_shape(area_shape),area->get_transform() * area->get_shape_transform(area_shape),Vector2(),NULL,this);
+ bool result = area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape),body->get_transform() * body->get_shape_transform(body_shape),Vector2(),area->get_shape(area_shape),area->get_transform() * area->get_shape_transform(area_shape),Vector2(),NULL,this);
if (result!=colliding) {
@@ -75,6 +75,8 @@ AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body,int p_body_shape, Area2DSW *p_area,i
colliding=false;
body->add_constraint(this,0);
area->add_constraint(this);
+ if (p_body->get_mode()==Physics2DServer::BODY_MODE_KINEMATIC) //need to be active to process pair
+ p_body->set_active(true);
}
@@ -92,3 +94,72 @@ AreaPair2DSW::~AreaPair2DSW() {
body->remove_constraint(this);
area->remove_constraint(this);
}
+
+
+//////////////////////////////////
+
+
+
+bool Area2Pair2DSW::setup(float p_step) {
+
+ bool result = area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a),area_a->get_transform() * area_a->get_shape_transform(shape_a),Vector2(),area_b->get_shape(shape_b),area_b->get_transform() * area_b->get_shape_transform(shape_b),Vector2(),NULL,this);
+
+ if (result!=colliding) {
+
+ if (result) {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->add_area_to_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->add_area_to_query(area_b,shape_b,shape_a);
+
+ } else {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->remove_area_from_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->remove_area_from_query(area_b,shape_b,shape_a);
+ }
+
+ colliding=result;
+
+ }
+
+ return false; //never do any post solving
+}
+
+void Area2Pair2DSW::solve(float p_step) {
+
+
+}
+
+
+Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a,int p_shape_a, Area2DSW *p_area_b,int p_shape_b) {
+
+
+ area_a=p_area_a;
+ area_b=p_area_b;
+ shape_a=p_shape_a;
+ shape_b=p_shape_b;
+ colliding=false;
+ area_a->add_constraint(this);
+ area_b->add_constraint(this);
+
+}
+
+Area2Pair2DSW::~Area2Pair2DSW() {
+
+ if (colliding) {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->remove_area_from_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->remove_area_from_query(area_b,shape_b,shape_a);
+ }
+
+ area_a->remove_constraint(this);
+ area_b->remove_constraint(this);
+}
diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h
index 5dad8c7a12..59113c9162 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,5 +49,23 @@ public:
~AreaPair2DSW();
};
+
+class Area2Pair2DSW : public Constraint2DSW {
+
+ Area2DSW *area_a;
+ Area2DSW *area_b;
+ int shape_a;
+ int shape_b;
+ bool colliding;
+public:
+
+ bool setup(float p_step);
+ void solve(float p_step);
+
+ Area2Pair2DSW(Area2DSW *p_area_a,int p_shape_a, Area2DSW *p_area_b,int p_shape_b);
+ ~Area2Pair2DSW();
+};
+
+
#endif // AREA_PAIR_2D_SW_H
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index f10cdadf4e..d0c5cbc77b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -65,7 +65,13 @@ void Body2DSW::update_inertias() {
float mass = area * this->mass / total_area;
- _inertia += shape->get_moment_of_inertia(mass) + mass * get_shape_transform(i).get_origin().length_squared();
+ Matrix32 mtx = get_shape_transform(i);
+ Vector2 scale = mtx.get_scale();
+ _inertia += shape->get_moment_of_inertia(mass,scale) + mass * mtx.get_origin().length_squared();
+ //Rect2 ab = get_shape_aabb(i);
+ //_inertia+=mass*ab.size.dot(ab.size)/12.0f;
+
+
}
@@ -150,6 +156,17 @@ void Body2DSW::set_param(Physics2DServer::BodyParameter p_param, float p_value)
_update_inertia();
} break;
+ case Physics2DServer::BODY_PARAM_GRAVITY_SCALE: {
+ gravity_scale=p_value;
+ } break;
+ case Physics2DServer::BODY_PARAM_LINEAR_DAMP: {
+
+ linear_damp=p_value;
+ } break;
+ case Physics2DServer::BODY_PARAM_ANGULAR_DAMP: {
+
+ angular_damp=p_value;
+ } break;
default:{}
}
}
@@ -168,6 +185,17 @@ float Body2DSW::get_param(Physics2DServer::BodyParameter p_param) const {
case Physics2DServer::BODY_PARAM_MASS: {
return mass;
} break;
+ case Physics2DServer::BODY_PARAM_GRAVITY_SCALE: {
+ return gravity_scale;
+ } break;
+ case Physics2DServer::BODY_PARAM_LINEAR_DAMP: {
+
+ return linear_damp;
+ } break;
+ case Physics2DServer::BODY_PARAM_ANGULAR_DAMP: {
+
+ return angular_damp;
+ } break;
default:{}
}
@@ -176,6 +204,7 @@ float Body2DSW::get_param(Physics2DServer::BodyParameter p_param) const {
void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) {
+ Physics2DServer::BodyMode prev=mode;
mode=p_mode;
switch(p_mode) {
@@ -186,9 +215,12 @@ void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) {
_set_inv_transform(get_transform().affine_inverse());
_inv_mass=0;
_set_static(p_mode==Physics2DServer::BODY_MODE_STATIC);
- //set_active(p_mode==Physics2DServer::BODY_MODE_KINEMATIC);
+ set_active(p_mode==Physics2DServer::BODY_MODE_KINEMATIC && contacts.size());
linear_velocity=Vector2();
angular_velocity=0;
+ if (mode==Physics2DServer::BODY_MODE_KINEMATIC && prev!=mode) {
+ first_time_kinematic=true;
+ }
} break;
case Physics2DServer::BODY_MODE_RIGID: {
@@ -226,9 +258,15 @@ void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant& p_va
if (mode==Physics2DServer::BODY_MODE_KINEMATIC) {
- new_transform=p_variant;
+
+ new_transform=p_variant;
//wakeup_neighbours();
set_active(true);
+ if (first_time_kinematic) {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().affine_inverse());
+ first_time_kinematic=false;
+ }
} else if (mode==Physics2DServer::BODY_MODE_STATIC) {
_set_transform(p_variant);
_set_inv_transform(get_transform().affine_inverse());
@@ -237,10 +275,13 @@ void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant& p_va
Matrix32 t = p_variant;
t.orthonormalize();
new_transform=get_transform(); //used as old to compute motion
+ if (t==new_transform)
+ break;
_set_transform(t);
_set_inv_transform(get_transform().inverse());
}
+ wakeup();
} break;
case Physics2DServer::BODY_STATE_LINEAR_VELOCITY: {
@@ -248,12 +289,14 @@ void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant& p_va
//if (mode==Physics2DServer::BODY_MODE_STATIC)
// break;
linear_velocity=p_variant;
+ wakeup();
} break;
case Physics2DServer::BODY_STATE_ANGULAR_VELOCITY: {
//if (mode!=Physics2DServer::BODY_MODE_RIGID)
// break;
angular_velocity=p_variant;
+ wakeup();
} break;
case Physics2DServer::BODY_STATE_SLEEPING: {
@@ -337,15 +380,21 @@ void Body2DSW::set_space(Space2DSW *p_space){
}
-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()) {
-
- gravity = (p_area->get_transform().get_origin()+p_area->get_gravity_vector() - get_transform().get_origin()).normalized() * p_area->get_gravity();
-
+ if(p_area->get_gravity_distance_scale() > 0) {
+ Vector2 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
+ gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale()+1, 2) );
+ } else {
+ gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
+ }
} else {
- gravity = p_area->get_gravity_vector() * p_area->get_gravity();
+ 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) {
@@ -353,23 +402,42 @@ void Body2DSW::integrate_forces(real_t p_step) {
if (mode==Physics2DServer::BODY_MODE_STATIC)
return;
- Area2DSW *current_area = get_space()->get_default_area();
- ERR_FAIL_COND(!current_area);
+ Area2DSW *def_area = get_space()->get_default_area();
+ Area2DSW *damp_area = def_area;
+ ERR_FAIL_COND(!def_area);
- int prio = current_area->get_priority();
int ac = areas.size();
+ bool replace = false;
+ gravity = Vector2(0,0);
+ area_angular_damp = 0;
+ area_linear_damp = 0;
if (ac) {
+ areas.sort();
const AreaCMP *aa = &areas[0];
- for(int i=0;i<ac;i++) {
- if (aa[i].area->get_priority() > prio) {
- current_area=aa[i].area;
- prio=current_area->get_priority();
+ damp_area = aa[ac-1].area;
+ for(int i=ac-1;i>=0;i--) {
+ _compute_area_gravity_and_dampenings(aa[i].area);
+ if (aa[i].area->get_space_override_mode() == Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE) {
+ replace = true;
+ break;
}
}
}
+ if( !replace ) {
+ _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();
- _compute_area_gravity(current_area);
- density=current_area->get_density();
+ if (linear_damp>=0)
+ area_linear_damp = linear_damp;
+ //else
+ // area_linear_damp=damp_area->get_linear_damp();
Vector2 motion;
bool do_motion=false;
@@ -379,16 +447,16 @@ 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];
do_motion=true;
- for(int i=0;i<get_shape_count();i++) {
- set_shape_kinematic_advance(i,Vector2());
- set_shape_kinematic_retreat(i,0);
- }
+ //for(int i=0;i<get_shape_count();i++) {
+ // set_shape_kinematic_advance(i,Vector2());
+ // set_shape_kinematic_retreat(i,0);
+ //}
} else {
if (!omit_force_integration) {
@@ -398,12 +466,12 @@ void Body2DSW::integrate_forces(real_t p_step) {
force+=applied_force;
real_t 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;
@@ -433,8 +501,9 @@ void Body2DSW::integrate_forces(real_t p_step) {
_update_shapes_with_motion(motion);
}
- current_area=NULL; // clear the area, so it is set in the next frame
- contact_count=0;
+ 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;
}
@@ -449,8 +518,8 @@ void Body2DSW::integrate_velocities(real_t p_step) {
if (mode==Physics2DServer::BODY_MODE_KINEMATIC) {
_set_transform(new_transform,false);
- _set_inv_transform(new_transform.affine_inverse()); ;
- if (linear_velocity==Vector2() && angular_velocity==0)
+ _set_inv_transform(new_transform.affine_inverse());
+ if (contacts.size()==0 && linear_velocity==Vector2() && angular_velocity==0)
set_active(false); //stopped moving, deactivate
return;
}
@@ -507,6 +576,7 @@ void Body2DSW::call_queries() {
Variant v=dbs;
const Variant *vp[2]={&v,&fi_callback->callback_udata};
+
Object *obj = ObjectDB::get_instance(fi_callback->id);
if (!obj) {
@@ -590,8 +660,15 @@ Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), inerti
island_next=NULL;
island_list_next=NULL;
_set_static(false);
- density=0;
+ first_time_kinematic=false;
+ linear_damp=-1;
+ angular_damp=-1;
+ area_angular_damp=0;
+ area_linear_damp=0;
contact_count=0;
+ gravity_scale=1.0;
+ using_one_way_cache=false;
+ one_way_collision_max_depth=0.1;
still_time=0;
continuous_cd_mode=Physics2DServer::CCD_MODE_DISABLED;
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index ffe47e0267..8418c5dcd7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,6 +47,10 @@ class Body2DSW : public CollisionObject2DSW {
Vector2 linear_velocity;
real_t angular_velocity;
+ real_t linear_damp;
+ real_t angular_damp;
+ real_t gravity_scale;
+
real_t mass;
real_t bounce;
real_t friction;
@@ -55,13 +59,17 @@ class Body2DSW : public CollisionObject2DSW {
real_t _inv_inertia;
Vector2 gravity;
- real_t density;
+ real_t area_linear_damp;
+ real_t area_angular_damp;
real_t still_time;
Vector2 applied_force;
real_t applied_torque;
+ Vector2 one_way_collision_direction;
+ float one_way_collision_max_depth;
+
SelfList<Body2DSW> active_list;
SelfList<Body2DSW> inertia_update_list;
@@ -72,6 +80,8 @@ class Body2DSW : public CollisionObject2DSW {
bool omit_force_integration;
bool active;
bool can_sleep;
+ bool first_time_kinematic;
+ bool using_one_way_cache;
void _update_inertia();
virtual void _shapes_changed();
Matrix32 new_transform;
@@ -82,13 +92,14 @@ class Body2DSW : public CollisionObject2DSW {
struct AreaCMP {
Area2DSW *area;
- _FORCE_INLINE_ bool operator<(const AreaCMP& p_cmp) const { return area->get_self() < p_cmp.area->get_self() ; }
+ _FORCE_INLINE_ bool operator==(const AreaCMP& p_cmp) const { return area->get_self() == p_cmp.area->get_self();}
+ _FORCE_INLINE_ bool operator<(const AreaCMP& p_cmp) const { return area->get_priority() < p_cmp.area->get_priority();}
_FORCE_INLINE_ AreaCMP() {}
_FORCE_INLINE_ AreaCMP(Area2DSW *p_area) { area=p_area;}
};
- VSet<AreaCMP> areas;
+ Vector<AreaCMP> areas;
struct Contact {
@@ -121,7 +132,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
@@ -131,10 +142,11 @@ public:
void set_force_integration_callback(ObjectID p_id, const StringName& p_method, const Variant &p_udata=Variant());
- _FORCE_INLINE_ void add_area(Area2DSW *p_area) { areas.insert(AreaCMP(p_area)); }
+ _FORCE_INLINE_ void add_area(Area2DSW *p_area) { areas.ordered_insert(AreaCMP(p_area)); }
_FORCE_INLINE_ void remove_area(Area2DSW *p_area) { areas.erase(AreaCMP(p_area)); }
- _FORCE_INLINE_ void set_max_contacts_reported(int p_size) { contacts.resize(p_size); contact_count=0; }
+ _FORCE_INLINE_ void set_max_contacts_reported(int p_size) { contacts.resize(p_size); contact_count=0; if (mode==Physics2DServer::BODY_MODE_KINEMATIC && p_size) set_active(true);}
+
_FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); }
_FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); }
@@ -190,6 +202,15 @@ public:
void set_active(bool p_active);
_FORCE_INLINE_ bool is_active() const { return active; }
+ _FORCE_INLINE_ void wakeup() {
+ if ((!get_space()) || mode==Physics2DServer::BODY_MODE_STATIC || mode==Physics2DServer::BODY_MODE_KINEMATIC)
+ return;
+ set_active(true);
+ }
+
+
+
+
void set_param(Physics2DServer::BodyParameter p_param, float);
float get_param(Physics2DServer::BodyParameter p_param) const;
@@ -209,6 +230,17 @@ public:
_FORCE_INLINE_ void set_continuous_collision_detection_mode(Physics2DServer::CCDMode p_mode) { continuous_cd_mode=p_mode; }
_FORCE_INLINE_ Physics2DServer::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; }
+ void set_one_way_collision_direction(const Vector2& p_dir) {
+ one_way_collision_direction=p_dir;
+ using_one_way_cache=one_way_collision_direction!=Vector2();
+ }
+ Vector2 get_one_way_collision_direction() const { return one_way_collision_direction; }
+
+ void set_one_way_collision_max_depth(float p_depth) { one_way_collision_max_depth=p_depth; }
+ float get_one_way_collision_max_depth() const { return one_way_collision_max_depth; }
+
+ _FORCE_INLINE_ bool is_using_one_way_collision() const { return using_one_way_cache; }
+
void set_space(Space2DSW *p_space);
void update_inertias();
@@ -217,8 +249,10 @@ public:
_FORCE_INLINE_ real_t get_inv_inertia() const { return _inv_inertia; }
_FORCE_INLINE_ real_t get_friction() const { return friction; }
_FORCE_INLINE_ Vector2 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_ real_t get_linear_damp() const { return linear_damp; }
+ _FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
+
void integrate_forces(real_t p_step);
void integrate_velocities(real_t p_step);
@@ -303,8 +337,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_density() const { return body->get_density(); } // 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
@@ -334,6 +369,8 @@ 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 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; }
virtual Physics2DDirectSpaceState* get_space_state();
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index ee169cde28..eb3abbb267 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -190,7 +190,7 @@ bool BodyPair2DSW::_test_ccd(float p_step,Body2DSW *p_A, int p_shape_A,const Mat
p_A->get_shape(p_shape_A)->project_rangev(mnormal,p_xform_A,min,max);
bool fast_object = mlen > (max-min)*0.3; //going too fast in that direction
- if (fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
+ if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
return false;
}
@@ -234,7 +234,7 @@ bool BodyPair2DSW::setup(float p_step) {
//cannot collide
- if ((A->get_layer_mask()&B->get_layer_mask())==0 || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode()<=Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode()<=Physics2DServer::BODY_MODE_KINEMATIC)) {
+ if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode()<=Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode()<=Physics2DServer::BODY_MODE_KINEMATIC && A->get_max_contacts_reported()==0 && B->get_max_contacts_reported()==0)) {
collided=false;
return false;
}
@@ -265,6 +265,8 @@ bool BodyPair2DSW::setup(float p_step) {
}
//faster to set than to check..
+ //bool prev_collided=collided;
+
collided = CollisionSolver2DSW::solve(shape_A_ptr,xform_A,motion_A,shape_B_ptr,xform_B,motion_B,_add_contact,this,&sep_axis);
if (!collided) {
@@ -280,9 +282,68 @@ bool BodyPair2DSW::setup(float p_step) {
collided=true;
}
- if (!collided)
+ if (!collided) {
+ oneway_disabled=false;
return false;
+ }
+
+ }
+
+ if (oneway_disabled)
+ return false;
+
+ //if (!prev_collided) {
+ {
+
+ if (A->is_using_one_way_collision()) {
+ Vector2 direction = A->get_one_way_collision_direction();
+ bool valid=false;
+ for(int i=0;i<contact_count;i++) {
+ Contact& c = contacts[i];
+
+ if (c.normal.dot(direction)<0)
+ continue;
+ if (B->get_linear_velocity().dot(direction)<0)
+ continue;
+
+ if (!c.reused) {
+ continue;
+ }
+
+ valid=true;
+ }
+
+ if (!valid) {
+ collided=false;
+ oneway_disabled=true;
+ return false;
+ }
+ }
+
+ if (B->is_using_one_way_collision()) {
+ Vector2 direction = B->get_one_way_collision_direction();
+ bool valid=false;
+ for(int i=0;i<contact_count;i++) {
+
+ Contact& c = contacts[i];
+
+ if (c.normal.dot(direction)<0)
+ continue;
+ if (A->get_linear_velocity().dot(direction)<0)
+ continue;
+ if (!c.reused) {
+ continue;
+ }
+
+ valid=true;
+ }
+ if (!valid) {
+ collided=false;
+ oneway_disabled=true;
+ return false;
+ }
+ }
}
real_t max_penetration = space->get_contact_max_allowed_penetration();
@@ -318,7 +379,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();
@@ -343,9 +409,11 @@ bool BodyPair2DSW::setup(float p_step) {
}
}
- if (A->is_shape_set_as_trigger(shape_A) || B->is_shape_set_as_trigger(shape_B)) {
+ if (A->is_shape_set_as_trigger(shape_A) || B->is_shape_set_as_trigger(shape_B) || (A->get_mode()<=Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode()<=Physics2DServer::BODY_MODE_KINEMATIC)) {
c.active=false;
collided=false;
+ continue;
+
}
// Precompute normal mass, tangent mass, and bias.
@@ -470,12 +538,14 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A,Body2DSW *p_B, int p_sha
B->add_constraint(this,1);
contact_count=0;
collided=false;
+ oneway_disabled=false;
}
BodyPair2DSW::~BodyPair2DSW() {
+
A->remove_constraint(this);
B->remove_constraint(this);
diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/body_pair_2d_sw.h
index 15d7e62d3a..a7fa287be4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -76,6 +76,7 @@ class BodyPair2DSW : public Constraint2DSW {
Contact contacts[MAX_CONTACTS];
int contact_count;
bool collided;
+ bool oneway_disabled;
int cc;
diff --git a/servers/physics_2d/broad_phase_2d_basic.cpp b/servers/physics_2d/broad_phase_2d_basic.cpp
index 9641a986e8..e61b4735b9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/broad_phase_2d_basic.h b/servers/physics_2d/broad_phase_2d_basic.h
index ce15752251..cdee77ffd7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index 0f08f63937..4651d485c2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -467,9 +467,10 @@ int BroadPhase2DHashGrid::cull_segment(const Vector2& p_from, const Vector2& p_t
delta.x=cell_size/delta.x;
delta.y=cell_size/delta.y;
- Point2i pos = p_from.floor() / cell_size;
- Point2i end = p_to.floor() / cell_size;
- Point2i step = Vector2( SGN(dir.x), SGN(dir.y));
+ Point2i pos = (p_from/cell_size).floor();
+ Point2i end = (p_to/cell_size).floor();
+
+ Point2i step = Vector2( SGN(dir.x), SGN(dir.y) );
Vector2 max;
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h
index d530b35d5d..a2eecf7bbf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/broad_phase_2d_sw.cpp b/servers/physics_2d/broad_phase_2d_sw.cpp
index 7ded6ed01e..fd8e7254b6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/broad_phase_2d_sw.h
index 510f7db112..283d6941e1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp
index 277a286144..7c8e223c57 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -55,6 +55,14 @@ void CollisionObject2DSW::set_shape(int p_index,Shape2DSW *p_shape){
_shapes_changed();
}
+
+void CollisionObject2DSW::set_shape_metadata(int p_index,const Variant& p_metadata) {
+
+ ERR_FAIL_INDEX(p_index,shapes.size());
+ shapes[p_index].metadata=p_metadata;
+
+}
+
void CollisionObject2DSW::set_shape_transform(int p_index,const Matrix32& p_transform){
ERR_FAIL_INDEX(p_index,shapes.size());
@@ -218,6 +226,7 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) {
type=p_type;
space=NULL;
instance_id=0;
- user_mask=0;
+ collision_mask=1;
layer_mask=1;
+ pickable=true;
}
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h
index cc7f8f50bd..f3432060b9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,6 +47,7 @@ private:
Type type;
RID self;
ObjectID instance_id;
+ bool pickable;
struct Shape {
@@ -55,17 +56,16 @@ private:
BroadPhase2DSW::ID bpid;
Rect2 aabb_cache; //for rayqueries
Shape2DSW *shape;
- Vector2 kinematic_advance;
- float kinematic_retreat;
+ Variant metadata;
bool trigger;
- Shape() { trigger=false; kinematic_retreat=0; }
+ Shape() { trigger=false; }
};
Vector<Shape> shapes;
Space2DSW *space;
Matrix32 transform;
Matrix32 inv_transform;
- uint32_t user_mask;
+ uint32_t collision_mask;
uint32_t layer_mask;
bool _static;
@@ -99,17 +99,15 @@ public:
void add_shape(Shape2DSW *p_shape,const Matrix32& p_transform=Matrix32());
void set_shape(int p_index,Shape2DSW *p_shape);
void set_shape_transform(int p_index,const Matrix32& p_transform);
+ void set_shape_metadata(int p_index,const Variant& p_metadata);
+
+
_FORCE_INLINE_ int get_shape_count() const { return shapes.size(); }
_FORCE_INLINE_ Shape2DSW *get_shape(int p_index) const { return shapes[p_index].shape; }
_FORCE_INLINE_ const Matrix32& get_shape_transform(int p_index) const { return shapes[p_index].xform; }
_FORCE_INLINE_ const Matrix32& get_shape_inv_transform(int p_index) const { return shapes[p_index].xform_inv; }
_FORCE_INLINE_ const Rect2& get_shape_aabb(int p_index) const { return shapes[p_index].aabb_cache; }
-
- _FORCE_INLINE_ void set_shape_kinematic_advance(int p_index,const Vector2& p_advance) { shapes[p_index].kinematic_advance=p_advance; }
- _FORCE_INLINE_ Vector2 get_shape_kinematic_advance(int p_index) const { return shapes[p_index].kinematic_advance; }
-
- _FORCE_INLINE_ void set_shape_kinematic_retreat(int p_index,float p_retreat) { shapes[p_index].kinematic_retreat=p_retreat; }
- _FORCE_INLINE_ float get_shape_kinematic_retreat(int p_index) const { return shapes[p_index].kinematic_retreat; }
+ _FORCE_INLINE_ const Variant& get_shape_metadata(int p_index) const { return shapes[p_index].metadata; }
_FORCE_INLINE_ Matrix32 get_transform() const { return transform; }
_FORCE_INLINE_ Matrix32 get_inv_transform() const { return inv_transform; }
@@ -119,8 +117,8 @@ public:
_FORCE_INLINE_ bool is_shape_set_as_trigger(int p_idx) const { return shapes[p_idx].trigger; }
- void set_user_mask(uint32_t p_mask) {user_mask=p_mask;}
- _FORCE_INLINE_ uint32_t get_user_mask() const { return user_mask; }
+ void set_collision_mask(uint32_t p_mask) {collision_mask=p_mask;}
+ _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }
void set_layer_mask(uint32_t p_mask) {layer_mask=p_mask;}
_FORCE_INLINE_ uint32_t get_layer_mask() const { return layer_mask; }
@@ -132,6 +130,14 @@ public:
_FORCE_INLINE_ bool is_static() const { return _static; }
+ void set_pickable(bool p_pickable) { pickable=p_pickable; }
+ _FORCE_INLINE_ bool is_pickable() const { return pickable; }
+
+ _FORCE_INLINE_ bool test_collision_mask(CollisionObject2DSW* p_other) const {
+
+ return layer_mask&p_other->collision_mask || p_other->layer_mask&collision_mask;
+ }
+
virtual ~CollisionObject2DSW() {}
};
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp
index 7d85183645..2525c6e942 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -593,8 +593,8 @@ static void _collision_segment_segment(const Shape2DSW* p_a,const Matrix32& p_tr
//this collision is kind of pointless
- if (!separator.test_previous_axis())
- return;
+ //if (!separator.test_previous_axis())
+ // return;
if (!separator.test_cast())
return;
@@ -1086,6 +1086,7 @@ static void _collision_rectangle_convex_polygon(const Shape2DSW* p_a,const Matri
SeparatorAxisTest2D<RectangleShape2DSW,ConvexPolygonShape2DSW,castA,castB,withMargin> separator(rectangle_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B);
+
if (!separator.test_previous_axis())
return;
diff --git a/servers/physics_2d/collision_solver_2d_sat.h b/servers/physics_2d/collision_solver_2d_sat.h
index be5a3dc79f..554f756738 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp
index 4c7e68d643..134ad04222 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h
index 07141b0d09..0cdd54f8b6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/constraint_2d_sw.cpp b/servers/physics_2d/constraint_2d_sw.cpp
index e97b5d794e..24d56ce9fe 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h
index 7abe49f5b4..a9145c382f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index fea58b6e8d..7c12000084 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 0a9bf34250..e43f8eee33 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 2171a9c2c4..6a1c790da8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#include "broad_phase_2d_basic.h"
#include "broad_phase_2d_hash_grid.h"
#include "collision_solver_2d_sw.h"
-
+#include "globals.h"
RID Physics2DServerSW::shape_create(ShapeType p_shape) {
Shape2DSW *shape=NULL;
@@ -138,6 +138,21 @@ void Physics2DServerSW::_shape_col_cbk(const Vector2& p_point_A,const Vector2& p
if (cbk->max==0)
return;
+ if (cbk->valid_dir!=Vector2()) {
+ if (p_point_A.distance_squared_to(p_point_B)>cbk->valid_depth*cbk->valid_depth) {
+ return;
+ }
+ if (cbk->valid_dir.dot((p_point_A-p_point_B).normalized())<0.7071) {
+/* print_line("A: "+p_point_A);
+ print_line("B: "+p_point_B);
+ print_line("discard too angled "+rtos(cbk->valid_dir.dot((p_point_A-p_point_B))));
+ print_line("resnorm: "+(p_point_A-p_point_B).normalized());
+ print_line("distance: "+rtos(p_point_A.distance_to(p_point_B)));
+*/
+ return;
+ }
+ }
+
if (cbk->amount == cbk->max) {
//find least deep
float min_depth=1e20;
@@ -242,11 +257,35 @@ 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);
ERR_FAIL_COND_V(!space,NULL);
- if (/*doing_sync ||*/ space->is_locked()) {
+ if ((using_threads && !doing_sync) || space->is_locked()) {
ERR_EXPLAIN("Space state is inaccesible right now, wait for iteration or fixed process notification.");
ERR_FAIL_V(NULL);
@@ -448,6 +487,40 @@ Matrix32 Physics2DServerSW::area_get_transform(RID p_area) const {
return area->get_transform();
};
+void Physics2DServerSW::area_set_pickable(RID p_area,bool p_pickable) {
+
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_pickable(p_pickable);
+
+}
+
+void Physics2DServerSW::area_set_monitorable(RID p_area,bool p_monitorable) {
+
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_monitorable(p_monitorable);
+
+}
+
+void Physics2DServerSW::area_set_collision_mask(RID p_area,uint32_t p_mask) {
+
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_mask(p_mask);
+}
+
+void Physics2DServerSW::area_set_layer_mask(RID p_area,uint32_t p_mask) {
+
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_layer_mask(p_mask);
+}
+
+
void Physics2DServerSW::area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) {
Area2DSW *area = area_owner.get(p_area);
@@ -458,6 +531,14 @@ void Physics2DServerSW::area_set_monitor_callback(RID p_area,Object *p_receiver,
}
+void Physics2DServerSW::area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) {
+
+
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_area_monitor_callback(p_receiver?p_receiver->get_instance_ID():0,p_method);
+}
/* BODY API */
@@ -548,6 +629,22 @@ void Physics2DServerSW::body_set_shape_transform(RID p_body, int p_shape_idx, co
body->set_shape_transform(p_shape_idx,p_transform);
}
+void Physics2DServerSW::body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant& p_metadata) {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_shape_metadata(p_shape_idx,p_metadata);
+}
+
+
+Variant Physics2DServerSW::body_get_shape_metadata(RID p_body, int p_shape_idx) const {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body,Variant());
+ return body->get_shape_metadata(p_shape_idx);
+}
+
+
int Physics2DServerSW::body_get_shape_count(RID p_body) const {
Body2DSW *body = body_owner.get(p_body);
@@ -660,7 +757,7 @@ void Physics2DServerSW::body_set_layer_mask(RID p_body, uint32_t p_flags) {
};
-uint32_t Physics2DServerSW::body_get_layer_mask(RID p_body, uint32_t p_flags) const {
+uint32_t Physics2DServerSW::body_get_layer_mask(RID p_body) const {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body,0);
@@ -669,20 +766,20 @@ uint32_t Physics2DServerSW::body_get_layer_mask(RID p_body, uint32_t p_flags) co
};
-void Physics2DServerSW::body_set_user_mask(RID p_body, uint32_t p_flags) {
+void Physics2DServerSW::body_set_collision_mask(RID p_body, uint32_t p_flags) {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
- body->set_user_mask(p_flags);
+ body->set_collision_mask(p_flags);
};
-uint32_t Physics2DServerSW::body_get_user_mask(RID p_body, uint32_t p_flags) const {
+uint32_t Physics2DServerSW::body_get_collision_mask(RID p_body) const {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body,0);
- return body->get_user_mask();
+ return body->get_collision_mask();
};
void Physics2DServerSW::body_set_param(RID p_body, BodyParameter p_param, float p_value) {
@@ -726,6 +823,8 @@ void Physics2DServerSW::body_set_applied_force(RID p_body, const Vector2& p_forc
ERR_FAIL_COND(!body);
body->set_applied_force(p_force);
+ body->wakeup();
+
};
Vector2 Physics2DServerSW::body_get_applied_force(RID p_body) const {
@@ -741,6 +840,7 @@ void Physics2DServerSW::body_set_applied_torque(RID p_body, float p_torque) {
ERR_FAIL_COND(!body);
body->set_applied_torque(p_torque);
+ body->wakeup();
};
float Physics2DServerSW::body_get_applied_torque(RID p_body) const {
@@ -757,6 +857,7 @@ void Physics2DServerSW::body_apply_impulse(RID p_body, const Vector2& p_pos, con
ERR_FAIL_COND(!body);
body->apply_impulse(p_pos,p_impulse);
+ body->wakeup();
};
void Physics2DServerSW::body_set_axis_velocity(RID p_body, const Vector2& p_axis_velocity) {
@@ -769,7 +870,7 @@ void Physics2DServerSW::body_set_axis_velocity(RID p_body, const Vector2& p_axis
v-=axis*axis.dot(v);
v+=p_axis_velocity;
body->set_linear_velocity(v);
-
+ body->wakeup();
};
void Physics2DServerSW::body_add_collision_exception(RID p_body, RID p_body_b) {
@@ -778,7 +879,7 @@ void Physics2DServerSW::body_add_collision_exception(RID p_body, RID p_body_b) {
ERR_FAIL_COND(!body);
body->add_exception(p_body_b);
-
+ body->wakeup();
};
void Physics2DServerSW::body_remove_collision_exception(RID p_body, RID p_body_b) {
@@ -787,6 +888,7 @@ void Physics2DServerSW::body_remove_collision_exception(RID p_body, RID p_body_b
ERR_FAIL_COND(!body);
body->remove_exception(p_body_b);
+ body->wakeup();
};
@@ -844,6 +946,37 @@ int Physics2DServerSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
+void Physics2DServerSW::body_set_one_way_collision_direction(RID p_body,const Vector2& p_direction) {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_one_way_collision_direction(p_direction);
+}
+
+Vector2 Physics2DServerSW::body_get_one_way_collision_direction(RID p_body) const{
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body,Vector2());
+ return body->get_one_way_collision_direction();
+
+}
+
+void Physics2DServerSW::body_set_one_way_collision_max_depth(RID p_body,float p_max_depth) {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_one_way_collision_max_depth(p_max_depth);
+
+}
+
+float Physics2DServerSW::body_get_one_way_collision_max_depth(RID p_body) const {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body,0);
+ return body->get_one_way_collision_max_depth();
+
+}
+
void Physics2DServerSW::body_set_force_integration_callback(RID p_body,Object *p_receiver,const StringName& p_method,const Variant& p_udata) {
@@ -863,6 +996,25 @@ bool Physics2DServerSW::body_collide_shape(RID p_body, int p_body_shape, RID p_s
}
+void Physics2DServerSW::body_set_pickable(RID p_body,bool p_pickable) {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_pickable(p_pickable);
+
+}
+
+bool Physics2DServerSW::body_test_motion(RID p_body,const Vector2& p_motion,float p_margin,MotionResult *r_result) {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body,false);
+ ERR_FAIL_COND_V(!body->get_space(),false);
+ ERR_FAIL_COND_V(body->get_space()->is_locked(),false);
+
+ return body->get_space()->test_body_motion(body,p_motion,p_margin,r_result);
+
+}
+
/* JOINT API */
@@ -944,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) {
@@ -1068,7 +1239,7 @@ void Physics2DServerSW::set_active(bool p_active) {
void Physics2DServerSW::init() {
- doing_sync=true;
+ doing_sync=false;
last_step=0.001;
iterations=8;// 8?
stepper = memnew( Step2DSW );
@@ -1086,14 +1257,21 @@ void Physics2DServerSW::step(float p_step) {
last_step=p_step;
Physics2DDirectBodyStateSW::singleton->step=p_step;
+ island_count=0;
+ active_objects=0;
+ collision_pairs=0;
for( Set<const Space2DSW*>::Element *E=active_spaces.front();E;E=E->next()) {
stepper->step((Space2DSW*)E->get(),p_step,iterations);
+ island_count+=E->get()->get_island_count();
+ active_objects+=E->get()->get_active_objects();
+ collision_pairs+=E->get()->get_collision_pairs();
}
};
void Physics2DServerSW::sync() {
+ doing_sync=true;
};
void Physics2DServerSW::flush_queries() {
@@ -1101,7 +1279,7 @@ void Physics2DServerSW::flush_queries() {
if (!active)
return;
- doing_sync=true;
+
for( Set<const Space2DSW*>::Element *E=active_spaces.front();E;E=E->next()) {
Space2DSW *space=(Space2DSW *)E->get();
@@ -1110,6 +1288,10 @@ void Physics2DServerSW::flush_queries() {
};
+void Physics2DServerSW::end_sync() {
+ doing_sync=false;
+}
+
void Physics2DServerSW::finish() {
@@ -1118,6 +1300,27 @@ void Physics2DServerSW::finish() {
memdelete(direct_state);
};
+int Physics2DServerSW::get_process_info(ProcessInfo p_info) {
+
+ switch(p_info) {
+
+ case INFO_ACTIVE_OBJECTS: {
+
+ return active_objects;
+ } break;
+ case INFO_COLLISION_PAIRS: {
+ return collision_pairs;
+ } break;
+ case INFO_ISLAND_COUNT: {
+
+ return island_count;
+ } break;
+
+ }
+
+ return 0;
+}
+
Physics2DServerSW::Physics2DServerSW() {
@@ -1125,8 +1328,14 @@ Physics2DServerSW::Physics2DServerSW() {
// BroadPhase2DSW::create_func=BroadPhase2DBasic::_create;
active=true;
+ island_count=0;
+ active_objects=0;
+ collision_pairs=0;
+ using_threads=int(Globals::get_singleton()->get("physics_2d/thread_model"))==2;
+
};
+
Physics2DServerSW::~Physics2DServerSW() {
};
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index 09ca029127..b2c58b788e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,6 +47,13 @@ friend class Physics2DDirectSpaceStateSW;
bool doing_sync;
real_t last_step;
+ int island_count;
+ int active_objects;
+ int collision_pairs;
+
+ bool using_threads;
+
+
Step2DSW *stepper;
Set<const Space2DSW*> active_spaces;
@@ -66,6 +73,8 @@ public:
struct CollCbkData {
+ Vector2 valid_dir;
+ float valid_depth;
int max;
int amount;
Vector2 *ptr;
@@ -93,6 +102,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);
@@ -126,8 +140,14 @@ public:
virtual Variant area_get_param(RID p_parea,AreaParameter p_param) const;
virtual Matrix32 area_get_transform(RID p_area) const;
+ virtual void area_set_monitorable(RID p_area,bool p_monitorable);
+ virtual void area_set_collision_mask(RID p_area,uint32_t p_mask);
+ virtual void area_set_layer_mask(RID p_area,uint32_t p_mask);
virtual void area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method);
+ virtual void area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method);
+
+ virtual void area_set_pickable(RID p_area,bool p_pickable);
/* BODY API */
@@ -144,10 +164,14 @@ public:
virtual void body_add_shape(RID p_body, RID p_shape, const Matrix32& p_transform=Matrix32());
virtual void body_set_shape(RID p_body, int p_shape_idx,RID p_shape);
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Matrix32& p_transform);
+ virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant& p_metadata);
+
virtual int body_get_shape_count(RID p_body) const;
virtual RID body_get_shape(RID p_body, int p_shape_idx) const;
virtual Matrix32 body_get_shape_transform(RID p_body, int p_shape_idx) const;
+ virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const;
+
virtual void body_remove_shape(RID p_body, int p_shape_idx);
virtual void body_clear_shapes(RID p_body);
@@ -162,10 +186,10 @@ public:
virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const;
virtual void body_set_layer_mask(RID p_body, uint32_t p_mask);
- virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const;
+ virtual uint32_t body_get_layer_mask(RID p_body) const;
- virtual void body_set_user_mask(RID p_body, uint32_t p_mask);
- virtual uint32_t body_get_user_mask(RID p_body, uint32_t p_mask) const;
+ virtual void body_set_collision_mask(RID p_body, uint32_t p_mask);
+ virtual uint32_t body_get_collision_mask(RID p_) const;
virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value);
virtual float body_get_param(RID p_body, BodyParameter p_param) const;
@@ -196,9 +220,21 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts);
virtual int body_get_max_contacts_reported(RID p_body) const;
+ virtual void body_set_one_way_collision_direction(RID p_body,const Vector2& p_direction);
+ virtual Vector2 body_get_one_way_collision_direction(RID p_body) const;
+
+ virtual void body_set_one_way_collision_max_depth(RID p_body,float p_max_depth);
+ virtual float body_get_one_way_collision_max_depth(RID p_body) const;
+
+
virtual void body_set_force_integration_callback(RID p_body,Object *p_receiver,const StringName& p_method,const Variant& p_udata=Variant());
virtual bool body_collide_shape(RID p_body, int p_body_shape,RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,Vector2 *r_results,int p_result_max,int &r_result_count);
+ virtual void body_set_pickable(RID p_body,bool p_pickable);
+
+ virtual bool body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.001,MotionResult *r_result=NULL);
+
+
/* JOINT API */
virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value);
@@ -207,6 +243,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;
@@ -219,10 +257,13 @@ public:
virtual void set_active(bool p_active);
virtual void init();
virtual void step(float p_step);
- virtual void sync();
+ virtual void sync();
virtual void flush_queries();
+ virtual void end_sync();
virtual void finish();
+ int get_process_info(ProcessInfo p_info);
+
Physics2DServerSW();
~Physics2DServerSW();
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.cpp b/servers/physics_2d/physics_2d_server_wrap_mt.cpp
new file mode 100644
index 0000000000..c5f023f162
--- /dev/null
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.cpp
@@ -0,0 +1,169 @@
+#include "physics_2d_server_wrap_mt.h"
+
+#include "os/os.h"
+
+void Physics2DServerWrapMT::thread_exit() {
+
+ exit=true;
+}
+
+void Physics2DServerWrapMT::thread_step(float p_delta) {
+
+ physics_2d_server->step(p_delta);
+ step_sem->post();
+
+}
+
+void Physics2DServerWrapMT::_thread_callback(void *_instance) {
+
+ Physics2DServerWrapMT *vsmt = reinterpret_cast<Physics2DServerWrapMT*>(_instance);
+
+
+ vsmt->thread_loop();
+}
+
+void Physics2DServerWrapMT::thread_loop() {
+
+ server_thread=Thread::get_caller_ID();
+
+ OS::get_singleton()->make_rendering_thread();
+
+ physics_2d_server->init();
+
+ exit=false;
+ step_thread_up=true;
+ while(!exit) {
+ // flush commands one by one, until exit is requested
+ command_queue.wait_and_flush_one();
+ }
+
+ command_queue.flush_all(); // flush all
+
+ physics_2d_server->finish();
+
+}
+
+
+/* EVENT QUEUING */
+
+
+void Physics2DServerWrapMT::step(float p_step) {
+
+ if (create_thread) {
+
+ command_queue.push( this, &Physics2DServerWrapMT::thread_step,p_step);
+ } else {
+
+ command_queue.flush_all(); //flush all pending from other threads
+ physics_2d_server->step(p_step);
+ }
+}
+
+void Physics2DServerWrapMT::sync() {
+
+ if (step_sem) {
+ if (first_frame)
+ first_frame=false;
+ else
+ step_sem->wait(); //must not wait if a step was not issued
+ }
+ physics_2d_server->sync();;
+}
+
+void Physics2DServerWrapMT::flush_queries(){
+
+ physics_2d_server->flush_queries();
+}
+
+void Physics2DServerWrapMT::end_sync() {
+
+ physics_2d_server->end_sync();;
+}
+
+void Physics2DServerWrapMT::init() {
+
+ if (create_thread) {
+
+ step_sem = Semaphore::create();
+ print_line("CREATING PHYSICS 2D THREAD");
+ //OS::get_singleton()->release_rendering_thread();
+ if (create_thread) {
+ thread = Thread::create( _thread_callback, this );
+ print_line("STARTING PHYISICS 2D THREAD");
+ }
+ while(!step_thread_up) {
+ OS::get_singleton()->delay_usec(1000);
+ }
+ print_line("DONE PHYSICS 2D THREAD");
+ } else {
+
+ physics_2d_server->init();
+ }
+
+}
+
+void Physics2DServerWrapMT::finish() {
+
+
+ if (thread) {
+
+ command_queue.push( this, &Physics2DServerWrapMT::thread_exit);
+ Thread::wait_to_finish( thread );
+ memdelete(thread);
+
+/*
+ shape_free_cached_ids();
+ area_free_cached_ids();
+ body_free_cached_ids();
+ pin_joint_free_cached_ids();
+ groove_joint_free_cached_ids();
+ damped_string_free_cached_ids();
+*/
+ thread=NULL;
+ } else {
+ physics_2d_server->finish();
+ }
+
+ if (step_sem)
+ memdelete(step_sem);
+
+}
+
+
+Physics2DServerWrapMT::Physics2DServerWrapMT(Physics2DServer* p_contained,bool p_create_thread) : command_queue(p_create_thread) {
+
+ physics_2d_server=p_contained;
+ create_thread=p_create_thread;
+ thread=NULL;
+ step_sem=NULL;
+ step_pending=0;
+ step_thread_up=false;
+ alloc_mutex=Mutex::create();
+
+ shape_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ area_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ body_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ pin_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ groove_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ damped_spring_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+
+ if (!p_create_thread) {
+ server_thread=Thread::get_caller_ID();
+ } else {
+ server_thread=0;
+ }
+
+ main_thread = Thread::get_caller_ID();
+ first_frame=true;
+}
+
+
+Physics2DServerWrapMT::~Physics2DServerWrapMT() {
+
+ memdelete(physics_2d_server);
+ memdelete(alloc_mutex);
+ //finish();
+
+}
+
+
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
new file mode 100644
index 0000000000..60f8a4c879
--- /dev/null
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.h
@@ -0,0 +1,316 @@
+#ifndef PHYSICS2DSERVERWRAPMT_H
+#define PHYSICS2DSERVERWRAPMT_H
+
+
+#include "servers/physics_2d_server.h"
+#include "command_queue_mt.h"
+#include "os/thread.h"
+#include "globals.h"
+
+#ifdef DEBUG_SYNC
+#define SYNC_DEBUG print_line("sync on: "+String(__FUNCTION__));
+#else
+#define SYNC_DEBUG
+#endif
+
+
+class Physics2DServerWrapMT : public Physics2DServer {
+
+ mutable Physics2DServer *physics_2d_server;
+
+ mutable CommandQueueMT command_queue;
+
+ static void _thread_callback(void *_instance);
+ void thread_loop();
+
+ Thread::ID server_thread;
+ Thread::ID main_thread;
+ volatile bool exit;
+ Thread *thread;
+ volatile bool step_thread_up;
+ bool create_thread;
+
+ Semaphore *step_sem;
+ int step_pending;
+ void thread_step(float p_delta);
+ void thread_flush();
+
+ void thread_exit();
+
+ Mutex*alloc_mutex;
+ bool first_frame;
+
+ int shape_pool_max_size;
+ List<RID> shape_id_pool;
+ int area_pool_max_size;
+ List<RID> area_id_pool;
+ int body_pool_max_size;
+ List<RID> body_id_pool;
+ int pin_joint_pool_max_size;
+ List<RID> pin_joint_id_pool;
+ int groove_joint_pool_max_size;
+ List<RID> groove_joint_id_pool;
+ int damped_spring_joint_pool_max_size;
+ List<RID> damped_spring_joint_id_pool;
+
+
+public:
+
+#define ServerName Physics2DServer
+#define ServerNameWrapMT Physics2DServerWrapMT
+#define server_name physics_2d_server
+#include "servers/server_wrap_mt_common.h"
+
+ //FUNC1RID(shape,ShapeType); todo fix
+ FUNC1R(RID,shape_create,ShapeType);
+ FUNC2(shape_set_data,RID,const Variant& );
+ FUNC2(shape_set_custom_solver_bias,RID,real_t );
+
+ FUNC1RC(ShapeType,shape_get_type,RID );
+ FUNC1RC(Variant,shape_get_data,RID);
+ FUNC1RC(real_t,shape_get_custom_solver_bias,RID);
+
+
+ //these work well, but should be used from the main thread only
+ bool shape_collide(RID p_shape_A, const Matrix32& p_xform_A,const Vector2& p_motion_A,RID p_shape_B, const Matrix32& p_xform_B, const Vector2& p_motion_B,Vector2 *r_results,int p_result_max,int &r_result_count) {
+
+ ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),false);
+ return physics_2d_server->shape_collide(p_shape_A,p_xform_A,p_motion_A,p_shape_B,p_xform_B,p_motion_B,r_results,p_result_max,r_result_count);
+ }
+
+ /* SPACE API */
+
+ FUNC0R(RID,space_create);
+ FUNC2(space_set_active,RID,bool);
+ FUNC1RC(bool,space_is_active,RID);
+
+ FUNC3(space_set_param,RID,SpaceParameter,real_t);
+ FUNC2RC(real_t,space_get_param,RID,SpaceParameter);
+
+ // this function only works on fixed process, errors and returns null otherwise
+ Physics2DDirectSpaceState* space_get_direct_state(RID p_space) {
+
+ ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),NULL);
+ 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 */
+
+ //FUNC0RID(area);
+ FUNC0R(RID,area_create);
+
+ FUNC2(area_set_space,RID,RID);
+ FUNC1RC(RID,area_get_space,RID);
+
+ FUNC2(area_set_space_override_mode,RID,AreaSpaceOverrideMode);
+ FUNC1RC(AreaSpaceOverrideMode,area_get_space_override_mode,RID);
+
+ FUNC3(area_add_shape,RID,RID,const Matrix32&);
+ FUNC3(area_set_shape,RID,int,RID);
+ FUNC3(area_set_shape_transform,RID,int,const Matrix32&);
+
+ FUNC1RC(int,area_get_shape_count,RID);
+ FUNC2RC(RID,area_get_shape,RID,int);
+ FUNC2RC(Matrix32,area_get_shape_transform,RID,int);
+ FUNC2(area_remove_shape,RID,int);
+ FUNC1(area_clear_shapes,RID);
+
+ FUNC2(area_attach_object_instance_ID,RID,ObjectID);
+ FUNC1RC(ObjectID,area_get_object_instance_ID,RID);
+
+ FUNC3(area_set_param,RID,AreaParameter,const Variant&);
+ FUNC2(area_set_transform,RID,const Matrix32&);
+
+ FUNC2RC(Variant,area_get_param,RID,AreaParameter);
+ FUNC1RC(Matrix32,area_get_transform,RID);
+
+ FUNC2(area_set_collision_mask,RID,uint32_t);
+ FUNC2(area_set_layer_mask,RID,uint32_t);
+
+ FUNC2(area_set_monitorable,RID,bool);
+ FUNC2(area_set_pickable,RID,bool);
+
+ FUNC3(area_set_monitor_callback,RID,Object*,const StringName&);
+ FUNC3(area_set_area_monitor_callback,RID,Object*,const StringName&);
+
+
+ /* BODY API */
+
+ //FUNC2RID(body,BodyMode,bool);
+ FUNC2R(RID,body_create,BodyMode,bool)
+
+ FUNC2(body_set_space,RID,RID);
+ FUNC1RC(RID,body_get_space,RID);
+
+ FUNC2(body_set_mode,RID,BodyMode);
+ FUNC1RC(BodyMode,body_get_mode,RID);
+
+
+ FUNC3(body_add_shape,RID,RID,const Matrix32&);
+ FUNC3(body_set_shape,RID,int,RID);
+ FUNC3(body_set_shape_transform,RID,int,const Matrix32&);
+ FUNC3(body_set_shape_metadata,RID,int,const Variant&);
+
+ FUNC1RC(int,body_get_shape_count,RID);
+ FUNC2RC(Matrix32,body_get_shape_transform,RID,int);
+ FUNC2RC(Variant,body_get_shape_metadata,RID,int);
+ FUNC2RC(RID,body_get_shape,RID,int);
+
+ FUNC3(body_set_shape_as_trigger,RID,int,bool);
+ FUNC2RC(bool,body_is_shape_set_as_trigger,RID,int);
+
+ FUNC2(body_remove_shape,RID,int);
+ FUNC1(body_clear_shapes,RID);
+
+ FUNC2(body_attach_object_instance_ID,RID,uint32_t);
+ FUNC1RC(uint32_t,body_get_object_instance_ID,RID);
+
+ FUNC2(body_set_continuous_collision_detection_mode,RID,CCDMode);
+ FUNC1RC(CCDMode,body_get_continuous_collision_detection_mode,RID);
+
+ FUNC2(body_set_layer_mask,RID,uint32_t);
+ FUNC1RC(uint32_t,body_get_layer_mask,RID);
+
+ FUNC2(body_set_collision_mask,RID,uint32_t);
+ FUNC1RC(uint32_t,body_get_collision_mask,RID);
+
+
+ FUNC3(body_set_param,RID,BodyParameter,float);
+ FUNC2RC(float,body_get_param,RID,BodyParameter);
+
+
+ FUNC3(body_set_state,RID,BodyState,const Variant&);
+ FUNC2RC(Variant,body_get_state,RID,BodyState);
+
+ FUNC2(body_set_applied_force,RID,const Vector2&);
+ FUNC1RC(Vector2,body_get_applied_force,RID);
+
+ FUNC2(body_set_applied_torque,RID,float);
+ FUNC1RC(float,body_get_applied_torque,RID);
+
+ FUNC3(body_apply_impulse,RID,const Vector2&,const Vector2&);
+ FUNC2(body_set_axis_velocity,RID,const Vector2&);
+
+ FUNC2(body_add_collision_exception,RID,RID);
+ FUNC2(body_remove_collision_exception,RID,RID);
+ FUNC2S(body_get_collision_exceptions,RID,List<RID>*);
+
+ FUNC2(body_set_max_contacts_reported,RID,int);
+ FUNC1RC(int,body_get_max_contacts_reported,RID);
+
+ FUNC2(body_set_one_way_collision_direction,RID,const Vector2&);
+ FUNC1RC(Vector2,body_get_one_way_collision_direction,RID);
+
+ FUNC2(body_set_one_way_collision_max_depth,RID,float);
+ FUNC1RC(float,body_get_one_way_collision_max_depth,RID);
+
+
+ FUNC2(body_set_contacts_reported_depth_treshold,RID,float);
+ FUNC1RC(float,body_get_contacts_reported_depth_treshold,RID);
+
+ FUNC2(body_set_omit_force_integration,RID,bool);
+ FUNC1RC(bool,body_is_omitting_force_integration,RID);
+
+ FUNC4(body_set_force_integration_callback,RID ,Object *,const StringName& ,const Variant& );
+
+
+ bool body_collide_shape(RID p_body, int p_body_shape,RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,Vector2 *r_results,int p_result_max,int &r_result_count) {
+ return physics_2d_server->body_collide_shape(p_body,p_body_shape,p_shape,p_shape_xform,p_motion,r_results,p_result_max,r_result_count);
+ }
+
+ FUNC2(body_set_pickable,RID,bool);
+
+ bool body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.001,MotionResult *r_result=NULL) {
+
+ ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),false);
+ return physics_2d_server->body_test_motion(p_body,p_motion,p_margin,r_result);
+ }
+
+ /* JOINT API */
+
+
+ FUNC3(joint_set_param,RID,JointParam,real_t);
+ FUNC2RC(real_t,joint_get_param,RID,JointParam);
+
+
+ ///FUNC3RID(pin_joint,const Vector2&,RID,RID);
+ ///FUNC5RID(groove_joint,const Vector2&,const Vector2&,const Vector2&,RID,RID);
+ ///FUNC4RID(damped_spring_joint,const Vector2&,const Vector2&,RID,RID);
+
+ FUNC3R(RID,pin_joint_create,const Vector2&,RID,RID);
+ 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);
+
+ FUNC1RC(JointType,joint_get_type,RID);
+
+
+ /* MISC */
+
+
+ FUNC1(free,RID);
+ FUNC1(set_active,bool);
+
+ virtual void init();
+ virtual void step(float p_step);
+ virtual void sync();
+ virtual void end_sync();
+ virtual void flush_queries();
+ virtual void finish();
+
+ int get_process_info(ProcessInfo p_info) {
+ return physics_2d_server->get_process_info(p_info);
+ }
+
+ Physics2DServerWrapMT(Physics2DServer* p_contained,bool p_create_thread);
+ ~Physics2DServerWrapMT();
+
+
+ template<class T>
+ static Physics2DServer* init_server() {
+
+ int tm = GLOBAL_DEF("physics_2d/thread_model",1);
+ if (tm==0) //single unsafe
+ return memnew( T );
+ else if (tm==1) //single saef
+ return memnew( Physics2DServerWrapMT( memnew( T ), false ));
+ else //single unsafe
+ return memnew( Physics2DServerWrapMT( memnew( T ), true ));
+
+
+ }
+
+#undef ServerNameWrapMT
+#undef ServerName
+#undef server_name
+
+};
+
+#ifdef DEBUG_SYNC
+#undef DEBUG_SYNC
+#endif
+#undef SYNC_DEBUG
+
+#endif // PHYSICS2DSERVERWRAPMT_H
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp
index 012c4ed404..d3591ec744 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -106,6 +106,11 @@ void LineShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,int
r_amount=0;
}
+bool LineShape2DSW::contains_point(const Vector2& p_point) const {
+
+ return normal.dot(p_point) < d;
+}
+
bool LineShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
Vector2 segment= p_begin - p_end;
@@ -131,11 +136,12 @@ bool LineShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_en
return true;
}
-real_t LineShape2DSW::get_moment_of_inertia(float p_mass) const {
+real_t LineShape2DSW::get_moment_of_inertia(float p_mass, const Vector2 &p_scale) const {
return 0;
}
+
void LineShape2DSW::set_data(const Variant& p_data) {
ERR_FAIL_COND(p_data.get_type()!=Variant::ARRAY);
@@ -174,13 +180,18 @@ void RayShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,int
}
+bool RayShape2DSW::contains_point(const Vector2& p_point) const {
+
+ return false;
+}
+
bool RayShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
return false; //rays can't be intersected
}
-real_t RayShape2DSW::get_moment_of_inertia(float p_mass) const {
+real_t RayShape2DSW::get_moment_of_inertia(float p_mass, const Vector2 &p_scale) const {
return 0; //rays are mass-less
}
@@ -222,6 +233,11 @@ void SegmentShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,
}
+bool SegmentShape2DSW::contains_point(const Vector2& p_point) const {
+
+ return false;
+}
+
bool SegmentShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
if (!Geometry::segment_intersects_segment_2d(p_begin,p_end,a,b,&r_point))
@@ -237,10 +253,12 @@ bool SegmentShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p
return true;
}
-real_t SegmentShape2DSW::get_moment_of_inertia(float p_mass) const {
+real_t SegmentShape2DSW::get_moment_of_inertia(float p_mass, const Vector2 &p_scale) const {
- real_t l = b.distance_to(a);
- Vector2 ofs = (a+b)*0.5;
+ Vector2 s[2]={a*p_scale,b*p_scale};
+
+ real_t l = s[1].distance_to(s[0]);
+ Vector2 ofs = (s[0]+s[1])*0.5;
return p_mass*(l*l/12.0f + ofs.length_squared());
}
@@ -285,6 +303,13 @@ void CircleShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,i
}
+
+bool CircleShape2DSW::contains_point(const Vector2& p_point) const {
+
+ return p_point.length_squared() < radius*radius;
+}
+
+
bool CircleShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
@@ -312,9 +337,10 @@ bool CircleShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_
return true;
}
-real_t CircleShape2DSW::get_moment_of_inertia(float p_mass) const {
+real_t CircleShape2DSW::get_moment_of_inertia(float p_mass, const Vector2 &p_scale) const {
+
+ return (radius*radius)*(p_scale.x*0.5+p_scale.y*0.5);
- return radius*radius;
}
void CircleShape2DSW::set_data(const Variant& p_data) {
@@ -371,15 +397,20 @@ void RectangleShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_support
}
+bool RectangleShape2DSW::contains_point(const Vector2& p_point) const {
+
+ return Math::abs(p_point.x)<half_extents.x && Math::abs(p_point.y)<half_extents.y;
+}
+
bool RectangleShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
return get_aabb().intersects_segment(p_begin,p_end,&r_point,&r_normal);
}
-real_t RectangleShape2DSW::get_moment_of_inertia(float p_mass) const {
+real_t RectangleShape2DSW::get_moment_of_inertia(float p_mass,const Vector2& p_scale) const {
- Vector2 he2=half_extents*2;
+ Vector2 he2=half_extents*2*p_scale;
return p_mass*he2.dot(he2)/12.0f;
}
@@ -435,6 +466,17 @@ void CapsuleShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,
}
}
+bool CapsuleShape2DSW::contains_point(const Vector2& p_point) const {
+
+ Vector2 p = p_point;
+ p.y=Math::abs(p.y);
+ p.y-=height*0.5;
+ if (p.y<0)
+ p.y=0;
+
+ return p.length_squared() < radius*radius;
+}
+
bool CapsuleShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
@@ -499,9 +541,9 @@ bool CapsuleShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p
return collided; //todo
}
-real_t CapsuleShape2DSW::get_moment_of_inertia(float p_mass) const {
+real_t CapsuleShape2DSW::get_moment_of_inertia(float p_mass, const Vector2 &p_scale) const {
- Vector2 he2(radius*2,height+radius*2);
+ Vector2 he2=Vector2(radius*2,height+radius*2)*p_scale;
return p_mass*he2.dot(he2)/12.0f;
}
@@ -570,6 +612,25 @@ void ConvexPolygonShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_sup
}
+
+bool ConvexPolygonShape2DSW::contains_point(const Vector2& p_point) const {
+
+ bool out=false;
+ bool in=false;
+
+ for(int i=0;i<point_count;i++) {
+
+ float d = points[i].normal.dot(p_point) - points[i].normal.dot(points[i].pos);
+ if (d>0)
+ out=true;
+ else
+ in=true;
+ }
+
+ return (in && !out) || (!in && out);
+}
+
+
bool ConvexPolygonShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
Vector2 n = (p_end-p_begin).normalized();
@@ -610,16 +671,16 @@ bool ConvexPolygonShape2DSW::intersect_segment(const Vector2& p_begin,const Vect
return inters; //todo
}
-real_t ConvexPolygonShape2DSW::get_moment_of_inertia(float p_mass) const {
+real_t ConvexPolygonShape2DSW::get_moment_of_inertia(float p_mass,const Vector2& p_scale) const {
Rect2 aabb;
- aabb.pos=points[0].pos;
+ aabb.pos=points[0].pos*p_scale;
for(int i=0;i<point_count;i++) {
- aabb.expand_to(points[i].pos);
+ aabb.expand_to(points[i].pos*p_scale);
}
- return p_mass*aabb.size.dot(aabb.size)/12.0f;
+ return p_mass*aabb.size.dot(aabb.size)/12.0f + p_mass * (aabb.pos+aabb.size*0.5).length_squared();
}
void ConvexPolygonShape2DSW::set_data(const Variant& p_data) {
@@ -730,6 +791,12 @@ void ConcavePolygonShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_su
}
+bool ConcavePolygonShape2DSW::contains_point(const Vector2& p_point) const {
+
+ return false; //sorry
+}
+
+
bool ConcavePolygonShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const{
uint32_t* stack = (uint32_t*)alloca(sizeof(int)*bvh_depth);
diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h
index d3fcf1fab2..6d5473aa17 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -78,14 +78,15 @@ public:
virtual bool is_concave() const { return false; }
+ virtual bool contains_point(const Vector2& p_point) const=0;
+
virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const=0;
virtual void project_range_castv(const Vector2& p_cast, const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const=0;
virtual Vector2 get_support(const Vector2& p_normal) const;
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const=0;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const=0;
- virtual real_t get_moment_of_inertia(float p_mass) const=0;
-
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const=0;
virtual void set_data(const Variant& p_data)=0;
virtual Variant get_data() const=0;
@@ -172,8 +173,9 @@ public:
virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); }
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const;
+ virtual bool contains_point(const Vector2& p_point) const;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(float p_mass) const;
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const;
virtual void set_data(const Variant& p_data);
virtual Variant get_data() const;
@@ -214,8 +216,9 @@ public:
virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); }
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const;
+ virtual bool contains_point(const Vector2& p_point) const;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(float p_mass) const;
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const;
virtual void set_data(const Variant& p_data);
virtual Variant get_data() const;
@@ -261,8 +264,9 @@ public:
virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); }
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const;
+ virtual bool contains_point(const Vector2& p_point) const;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(float p_mass) const;
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const;
virtual void set_data(const Variant& p_data);
virtual Variant get_data() const;
@@ -298,8 +302,9 @@ public:
virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); }
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const;
+ virtual bool contains_point(const Vector2& p_point) const;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(float p_mass) const;
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const;
virtual void set_data(const Variant& p_data);
virtual Variant get_data() const;
@@ -337,21 +342,27 @@ public:
virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); }
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const;
+ virtual bool contains_point(const Vector2& p_point) const;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(float p_mass) const;
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const;
virtual void set_data(const Variant& p_data);
virtual Variant get_data() const;
_FORCE_INLINE_ void project_range(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const {
// no matter the angle, the box is mirrored anyway
- Vector2 local_normal=p_transform.basis_xform_inv(p_normal);
+ r_max=-1e20;
+ r_min=1e20;
+ for(int i=0;i<4;i++) {
- float length = local_normal.abs().dot(half_extents);
- float distance = p_normal.dot( p_transform.get_origin() );
+ real_t d=p_normal.dot(p_transform.xform(Vector2( ((i&1)*2-1)*half_extents.x, ((i>>1)*2-1)*half_extents.y )));
+
+ if (d>r_max)
+ r_max=d;
+ if (d<r_min)
+ r_min=d;
- r_min = distance - length;
- r_max = distance + length;
+ }
}
@@ -419,8 +430,9 @@ public:
virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); }
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const;
+ virtual bool contains_point(const Vector2& p_point) const;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(float p_mass) const;
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const;
virtual void set_data(const Variant& p_data);
virtual Variant get_data() const;
@@ -481,8 +493,9 @@ public:
virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); }
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const;
+ virtual bool contains_point(const Vector2& p_point) const;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(float p_mass) const;
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const;
virtual void set_data(const Variant& p_data);
virtual Variant get_data() const;
@@ -568,9 +581,10 @@ public:
virtual void project_range(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { /*project_range(p_normal,p_transform,r_min,r_max);*/ }
virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const;
+ virtual bool contains_point(const Vector2& p_point) const;
virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(float p_mass) const { return 0; }
+ virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const { return 0; }
virtual void set_data(const Variant& p_data);
virtual Variant get_data() const;
@@ -582,5 +596,6 @@ public:
};
+#undef DEFAULT_PROJECT_RANGE_CAST
#endif // SHAPE_2D_2DSW_H
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 5fbf828c38..9f2f03baec 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
@@ -45,6 +45,57 @@ _FORCE_INLINE_ static bool _match_object_type_query(CollisionObject2DSW *p_objec
}
+
+int Physics2DDirectSpaceStateSW::intersect_point(const Vector2& p_point,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;
+
+ Rect2 aabb;
+ aabb.pos=p_point-Vector2(0.00001,0.00001);
+ aabb.size=Vector2(0.00002,0.00002);
+
+ int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
+
+ int cc=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;
+
+ if (p_exclude.has( space->intersection_query_results[i]->get_self()))
+ continue;
+
+ const CollisionObject2DSW *col_obj=space->intersection_query_results[i];
+
+ if (!col_obj->is_pickable())
+ continue;
+
+ int shape_idx=space->intersection_query_subindex_results[i];
+
+ Shape2DSW * shape = col_obj->get_shape(shape_idx);
+
+ Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_point);
+
+ if (!shape->contains_point(local_point))
+ 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);
+ r_results[cc].rid=col_obj->get_self();
+ r_results[cc].shape=shape_idx;
+ r_results[cc].metadata=col_obj->get_shape_metadata(shape_idx);
+
+ cc++;
+ }
+
+ return cc;
+
+
+}
+
bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) {
@@ -98,7 +149,7 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vec
if (shape->intersect_segment(local_from,local_to,shape_point,shape_normal)) {
- //print_line("inters sgment!");
+
Matrix32 xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
shape_point=xform.xform(shape_point);
@@ -126,6 +177,7 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vec
if (r_result.collider_id!=0)
r_result.collider=ObjectDB::get_instance(r_result.collider_id);
r_result.normal=res_normal;
+ r_result.metadata=res_obj->get_shape_metadata(res_shape);
r_result.position=res_point;
r_result.rid=res_obj->get_self();
r_result.shape=res_shape;
@@ -171,6 +223,7 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matri
r_results[cc].collider=ObjectDB::get_instance(r_results[cc].collider_id);
r_results[cc].rid=col_obj->get_self();
r_results[cc].shape=shape_idx;
+ r_results[cc].metadata=col_obj->get_shape_metadata(shape_idx);
cc++;
@@ -215,6 +268,16 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32
int shape_idx=space->intersection_query_subindex_results[i];
+ /*if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+
+ const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
+ if (body->get_one_way_collision_direction()!=Vector2() && p_motion.dot(body->get_one_way_collision_direction())<=CMP_EPSILON) {
+ print_line("failed in motion dir");
+ continue;
+ }
+ }*/
+
+
Matrix32 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 (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,p_margin)) {
@@ -225,6 +288,14 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32
//test initial overlap
if (CollisionSolver2DSW::solve(shape,p_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,p_margin)) {
+ if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+ //if one way collision direction ignore initial overlap
+ const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
+ if (body->get_one_way_collision_direction()!=Vector2()) {
+ continue;
+ }
+ }
+
return false;
}
@@ -251,6 +322,29 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32
}
}
+ if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+
+ const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
+ if (body->get_one_way_collision_direction()!=Vector2()) {
+
+ Vector2 cd[2];
+ Physics2DServerSW::CollCbkData cbk;
+ cbk.max=1;
+ cbk.amount=0;
+ cbk.ptr=cd;
+ cbk.valid_dir=body->get_one_way_collision_direction();
+ cbk.valid_depth=body->get_one_way_collision_max_depth();
+
+ Vector2 sep=mnormal; //important optimization for this to work fast enough
+ bool collided = CollisionSolver2DSW::solve(shape,p_xform,p_motion*(hi+space->contact_max_allowed_penetration),col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),Physics2DServerSW::_shape_col_cbk,&cbk,&sep,p_margin);
+ if (!collided || cbk.amount==0) {
+ continue;
+ }
+
+ }
+ }
+
+
if (low<best_safe) {
best_safe=low;
best_unsafe=hi;
@@ -309,21 +403,30 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Matrix32& p_s
if (p_exclude.has( col_obj->get_self() ))
continue;
-
+ if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+
+ const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
+ cbk.valid_dir=body->get_one_way_collision_direction();
+ cbk.valid_depth=body->get_one_way_collision_max_depth();
+ } else {
+ cbk.valid_dir=Vector2();
+ cbk.valid_depth=0;
+ }
if (CollisionSolver2DSW::solve(shape,p_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),cbkres,cbkptr,NULL,p_margin)) {
- collided=true;
+ collided=p_result_max==0 || cbk.amount>0;
}
}
+
r_result_count=cbk.amount;
return collided;
}
-struct _RestCallbackData {
+struct _RestCallbackData2D {
const CollisionObject2DSW *object;
const CollisionObject2DSW *best_object;
@@ -332,24 +435,39 @@ struct _RestCallbackData {
Vector2 best_contact;
Vector2 best_normal;
float best_len;
+ Vector2 valid_dir;
+ float valid_depth;
};
static void _rest_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,void *p_userdata) {
- _RestCallbackData *rd=(_RestCallbackData*)p_userdata;
+ _RestCallbackData2D *rd=(_RestCallbackData2D*)p_userdata;
+
+ if (rd->valid_dir!=Vector2()) {
+
+ if (rd->valid_dir!=Vector2()) {
+ if (p_point_A.distance_squared_to(p_point_B)>rd->valid_depth*rd->valid_depth)
+ return;
+ if (rd->valid_dir.dot((p_point_A-p_point_B).normalized())<Math_PI*0.25)
+ return;
+ }
+
+ }
Vector2 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;
+
}
@@ -365,7 +483,7 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Matrix32& p_shape
int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
- _RestCallbackData rcd;
+ _RestCallbackData2D rcd;
rcd.best_len=0;
rcd.best_object=NULL;
rcd.best_shape=0;
@@ -382,6 +500,17 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Matrix32& p_shape
if (p_exclude.has( col_obj->get_self() ))
continue;
+ if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+
+ const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
+ rcd.valid_dir=body->get_one_way_collision_direction();
+ rcd.valid_depth=body->get_one_way_collision_max_depth();
+ } else {
+ rcd.valid_dir=Vector2();
+ rcd.valid_depth=0;
+ }
+
+
rcd.object=col_obj;
rcd.shape=shape_idx;
bool sc = CollisionSolver2DSW::solve(shape,p_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2() ,_rest_cbk_result,&rcd,NULL,p_margin);
@@ -399,6 +528,7 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Matrix32& p_shape
r_info->normal=rcd.best_normal;
r_info->point=rcd.best_contact;
r_info->rid=rcd.best_object->get_self();
+ r_info->metadata=rcd.best_object->get_shape_metadata(rcd.best_shape);
if (rcd.best_object->get_type()==CollisionObject2DSW::TYPE_BODY) {
const Body2DSW *body = static_cast<const Body2DSW*>(rcd.best_object);
@@ -425,14 +555,531 @@ Physics2DDirectSpaceStateSW::Physics2DDirectSpaceStateSW() {
+int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body,const Rect2& p_aabb) {
+
+
+ int amount = broadphase->cull_aabb(p_aabb,intersection_query_results,INTERSECTION_QUERY_MAX,intersection_query_subindex_results);
+
+ for(int i=0;i<amount;i++) {
+
+ bool keep=true;
+
+ if (intersection_query_results[i]==p_body)
+ keep=false;
+ else if (intersection_query_results[i]->get_type()==CollisionObject2DSW::TYPE_AREA)
+ keep=false;
+ else if ((static_cast<Body2DSW*>(intersection_query_results[i])->test_collision_mask(p_body))==0)
+ keep=false;
+ else if (static_cast<Body2DSW*>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self()))
+ keep=false;
+ else if (static_cast<Body2DSW*>(intersection_query_results[i])->is_shape_set_as_trigger(intersection_query_subindex_results[i]))
+ keep=false;
+
+ if (!keep) {
+
+ if (i<amount-1) {
+ SWAP(intersection_query_results[i],intersection_query_results[amount-1]);
+ SWAP(intersection_query_subindex_results[i],intersection_query_subindex_results[amount-1]);
+
+ }
+
+ amount--;
+ i--;
+
+ }
+ }
+
+ return amount;
+}
+
+bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p_margin,Physics2DServer::MotionResult *r_result) {
+
+ //give me back regular physics engine logic
+ //this is madness
+ //and most people using this function will think
+ //what it does is simpler than using physics
+ //this took about a week to get right..
+ //but is it right? who knows at this point..
+
+ Rect2 body_aabb;
+
+ for(int i=0;i<p_body->get_shape_count();i++) {
+
+ if (i==0)
+ body_aabb=p_body->get_shape_aabb(i);
+ else
+ body_aabb=body_aabb.merge(p_body->get_shape_aabb(i));
+ }
+
+ body_aabb=body_aabb.grow(p_margin);
+
+
+ Matrix32 body_transform = p_body->get_transform();
+
+ {
+ //STEP 1, FREE BODY IF STUCK
+
+ const int max_results = 32;
+ int recover_attempts=4;
+ Vector2 sr[max_results*2];
+
+ do {
+
+ Physics2DServerSW::CollCbkData cbk;
+ cbk.max=max_results;
+ cbk.amount=0;
+ cbk.ptr=sr;
+
+
+ CollisionSolver2DSW::CallbackResult cbkres=NULL;
+
+ Physics2DServerSW::CollCbkData *cbkptr=NULL;
+ cbkptr=&cbk;
+ cbkres=Physics2DServerSW::_shape_col_cbk;
+
+ bool collided=false;
+
+ int amount = _cull_aabb_for_body(p_body,body_aabb);
+
+ for(int j=0;j<p_body->get_shape_count();j++) {
+ if (p_body->is_shape_set_as_trigger(j))
+ continue;
+
+ Matrix32 body_shape_xform = body_transform * p_body->get_shape_transform(j);
+ Shape2DSW *body_shape = p_body->get_shape(j);
+ for(int i=0;i<amount;i++) {
+
+ const CollisionObject2DSW *col_obj=intersection_query_results[i];
+ int shape_idx=intersection_query_subindex_results[i];
+
+ if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+
+ 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;
+
+ cbk.valid_dir=cdir;
+ cbk.valid_depth=body->get_one_way_collision_max_depth();
+ } else {
+ cbk.valid_dir=Vector2();
+ cbk.valid_depth=0;
+ }
+
+ if (CollisionSolver2DSW::solve(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),cbkres,cbkptr,NULL,p_margin)) {
+ collided=cbk.amount>0;
+ }
+ }
+ }
+
+
+ if (!collided)
+ break;
+
+ Vector2 recover_motion;
+
+ for(int i=0;i<cbk.amount;i++) {
+
+ Vector2 a = sr[i*2+0];
+ Vector2 b = sr[i*2+1];
+
+ // float d = a.distance_to(b);
+
+ //if (d<margin)
+ /// continue;
+ recover_motion+=(b-a)*0.4;
+ }
+
+ if (recover_motion==Vector2()) {
+ collided=false;
+ break;
+ }
+
+ body_transform.elements[2]+=recover_motion;
+ body_aabb.pos+=recover_motion;
+
+ recover_attempts--;
+
+ } while (recover_attempts);
+ }
+
+
+
+ float safe = 1.0;
+ float unsafe = 1.0;
+ int best_shape=-1;
+
+ {
+ // STEP 2 ATTEMPT MOTION
+
+ Rect2 motion_aabb=body_aabb;
+ motion_aabb.pos+=p_motion;
+ motion_aabb=motion_aabb.merge(body_aabb);
+ int amount = _cull_aabb_for_body(p_body,motion_aabb);
+ for(int j=0;j<p_body->get_shape_count();j++) {
+
+ if (p_body->is_shape_set_as_trigger(j))
+ continue;
+
+ Matrix32 body_shape_xform = body_transform * p_body->get_shape_transform(j);
+ Shape2DSW *body_shape = p_body->get_shape(j);
+
+ bool stuck=false;
+
+ float best_safe=1;
+ float best_unsafe=1;
+
+ for(int i=0;i<amount;i++) {
+
+ const CollisionObject2DSW *col_obj=intersection_query_results[i];
+ int shape_idx=intersection_query_subindex_results[i];
+
+
+ Matrix32 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 (!CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,0)) {
+ continue;
+ }
+
+
+ //test initial overlap
+ if (CollisionSolver2DSW::solve(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,0)) {
+
+ if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+ //if one way collision direction ignore initial overlap
+ const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
+ if (body->get_one_way_collision_direction()!=Vector2()) {
+ continue;
+ }
+ }
+
+ stuck=true;
+ break;
+ }
+
+
+ //just do kinematic solving
+ float low=0;
+ float hi=1;
+ Vector2 mnormal=p_motion.normalized();
+
+ for(int i=0;i<8;i++) { //steps should be customizable..
+
+ //Matrix32 xfa = p_xform;
+ float ofs = (low+hi)*0.5;
+
+ Vector2 sep=mnormal; //important optimization for this to work fast enough
+ bool collided = CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion*ofs,col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),NULL,NULL,&sep,0);
+
+ if (collided) {
+
+ hi=ofs;
+ } else {
+
+ low=ofs;
+ }
+ }
+
+ if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+
+ const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
+ if (body->get_one_way_collision_direction()!=Vector2()) {
+
+ Vector2 cd[2];
+ Physics2DServerSW::CollCbkData cbk;
+ cbk.max=1;
+ cbk.amount=0;
+ cbk.ptr=cd;
+ cbk.valid_dir=body->get_one_way_collision_direction();
+ cbk.valid_depth=body->get_one_way_collision_max_depth();
+
+ Vector2 sep=mnormal; //important optimization for this to work fast enough
+ bool collided = CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion*(hi+contact_max_allowed_penetration),col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),Physics2DServerSW::_shape_col_cbk,&cbk,&sep,0);
+ if (!collided || cbk.amount==0) {
+ continue;
+ }
+
+ }
+ }
+
+
+ if (low<best_safe) {
+ best_safe=low;
+ best_unsafe=hi;
+ }
+ }
+
+ if (stuck) {
+
+ safe=0;
+ unsafe=0;
+ best_shape=j; //sadly it's the best
+ break;
+ }
+ if (best_safe==1.0) {
+ continue;
+ }
+ if (best_safe < safe) {
+
+ safe=best_safe;
+ unsafe=best_unsafe;
+ best_shape=j;
+ }
+ }
+ }
+
+ bool collided=false;
+ if (safe>=1) {
+ //not collided
+ collided=false;
+ if (r_result) {
+
+ r_result->motion=p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]);
+ r_result->remainder=Vector2();
+ }
+
+ } else {
+
+ //it collided, let's get the rest info in unsafe advance
+ Matrix32 ugt = body_transform;
+ ugt.elements[2]+=p_motion*unsafe;
+
+ _RestCallbackData2D rcd;
+ rcd.best_len=0;
+ rcd.best_object=NULL;
+ rcd.best_shape=0;
+
+ Matrix32 body_shape_xform = ugt * p_body->get_shape_transform(best_shape);
+ Shape2DSW *body_shape = p_body->get_shape(best_shape);
+
+ body_aabb.pos+=p_motion*unsafe;
+
+ int amount = _cull_aabb_for_body(p_body,body_aabb);
+
+
+ for(int i=0;i<amount;i++) {
+
+
+ const CollisionObject2DSW *col_obj=intersection_query_results[i];
+ int shape_idx=intersection_query_subindex_results[i];
+
+ if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
+
+ const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
+ rcd.valid_dir=body->get_one_way_collision_direction();
+ rcd.valid_depth=body->get_one_way_collision_max_depth();
+ } else {
+ rcd.valid_dir=Vector2();
+ rcd.valid_depth=0;
+ }
+
+
+ rcd.object=col_obj;
+ rcd.shape=shape_idx;
+ bool sc = CollisionSolver2DSW::solve(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2() ,_rest_cbk_result,&rcd,NULL,p_margin);
+ if (!sc)
+ continue;
+
+ }
+
+ if (rcd.best_len!=0) {
+
+ if (r_result) {
+ r_result->collider=rcd.best_object->get_self();
+ r_result->collider_id=rcd.best_object->get_instance_id();
+ r_result->collider_shape=rcd.best_shape;
+ r_result->collision_normal=rcd.best_normal;
+ r_result->collision_point=rcd.best_contact;
+ r_result->collider_metadata=rcd.best_object->get_shape_metadata(rcd.best_shape);
+
+ const Body2DSW *body = static_cast<const Body2DSW*>(rcd.best_object);
+ Vector2 rel_vec = r_result->collision_point-body->get_transform().get_origin();
+ r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
+
+ r_result->motion=safe*p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]);
+ r_result->remainder=p_motion - safe * p_motion;
+ }
+
+ collided=true;
+ } else {
+ if (r_result) {
+
+ r_result->motion=p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]);
+ r_result->remainder=Vector2();
+ }
+
+ collided=false;
+
+ }
+ }
+
+ return collided;
+
+
+#if 0
+ //give me back regular physics engine logic
+ //this is madness
+ //and most people using this function will think
+ //what it does is simpler than using physics
+ //this took about a week to get right..
+ //but is it right? who knows at this point..
+
+
+ colliding=false;
+ ERR_FAIL_COND_V(!is_inside_tree(),Vector2());
+ Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space());
+ ERR_FAIL_COND_V(!dss,Vector2());
+ const int max_shapes=32;
+ Vector2 sr[max_shapes*2];
+ int res_shapes;
+
+ Set<RID> exclude;
+ exclude.insert(get_rid());
+
+
+ //recover first
+ int recover_attempts=4;
+
+ bool collided=false;
+ uint32_t mask=0;
+ if (collide_static)
+ mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY;
+ if (collide_kinematic)
+ mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY;
+ if (collide_rigid)
+ mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY;
+ if (collide_character)
+ mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY;
+
+// print_line("motion: "+p_motion+" margin: "+rtos(margin));
+
+ //print_line("margin: "+rtos(margin));
+ do {
+
+ //motion recover
+ for(int i=0;i<get_shape_count();i++) {
+
+ if (is_shape_set_as_trigger(i))
+ continue;
+ if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask))
+ collided=true;
+
+ }
+
+ if (!collided)
+ break;
+
+ Vector2 recover_motion;
+
+ for(int i=0;i<res_shapes;i++) {
+
+ Vector2 a = sr[i*2+0];
+ Vector2 b = sr[i*2+1];
+
+ float d = a.distance_to(b);
+
+ //if (d<margin)
+ /// continue;
+ recover_motion+=(b-a)*0.4;
+ }
+
+ if (recover_motion==Vector2()) {
+ collided=false;
+ break;
+ }
+
+ Matrix32 gt = get_global_transform();
+ gt.elements[2]+=recover_motion;
+ set_global_transform(gt);
+
+ recover_attempts--;
+
+ } while (recover_attempts);
+
+
+ //move second
+ float safe = 1.0;
+ float unsafe = 1.0;
+ int best_shape=-1;
+
+ for(int i=0;i<get_shape_count();i++) {
+
+ if (is_shape_set_as_trigger(i))
+ continue;
+
+ float lsafe,lunsafe;
+ bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask);
+ //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel));
+ if (!valid) {
+
+ safe=0;
+ unsafe=0;
+ best_shape=i; //sadly it's the best
+ break;
+ }
+ if (lsafe==1.0) {
+ continue;
+ }
+ if (lsafe < safe) {
+
+ safe=lsafe;
+ unsafe=lunsafe;
+ best_shape=i;
+ }
+ }
+
+
+ //print_line("best shape: "+itos(best_shape)+" motion "+p_motion);
+
+ if (safe>=1) {
+ //not collided
+ colliding=false;
+ } else {
+
+ //it collided, let's get the rest info in unsafe advance
+ Matrix32 ugt = get_global_transform();
+ ugt.elements[2]+=p_motion*unsafe;
+ Physics2DDirectSpaceState::ShapeRestInfo rest_info;
+ bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,get_layer_mask(),mask);
+ if (!c2) {
+ //should not happen, but floating point precision is so weird..
+
+ colliding=false;
+ } else {
+
+
+ //print_line("Travel: "+rtos(travel));
+ colliding=true;
+ collision=rest_info.point;
+ normal=rest_info.normal;
+ collider=rest_info.collider_id;
+ collider_vel=rest_info.linear_velocity;
+ collider_shape=rest_info.shape;
+ collider_metadata=rest_info.metadata;
+ }
+
+ }
+
+ Vector2 motion=p_motion*safe;
+ Matrix32 gt = get_global_transform();
+ gt.elements[2]+=motion;
+ set_global_transform(gt);
+
+ return p_motion-motion;
+
+#endif
+ return false;
+}
void* Space2DSW::_broadphase_pair(CollisionObject2DSW *A,int p_subindex_A,CollisionObject2DSW *B,int p_subindex_B,void *p_self) {
+
CollisionObject2DSW::Type type_A=A->get_type();
CollisionObject2DSW::Type type_B=B->get_type();
if (type_A>type_B) {
@@ -443,17 +1090,24 @@ void* Space2DSW::_broadphase_pair(CollisionObject2DSW *A,int p_subindex_A,Collis
}
Space2DSW *self = (Space2DSW*)p_self;
+ self->collision_pairs++;
if (type_A==CollisionObject2DSW::TYPE_AREA) {
-
- ERR_FAIL_COND_V(type_B!=CollisionObject2DSW::TYPE_BODY,NULL);
Area2DSW *area=static_cast<Area2DSW*>(A);
- Body2DSW *body=static_cast<Body2DSW*>(B);
+ if (type_B==CollisionObject2DSW::TYPE_AREA) {
+
+ Area2DSW *area_b=static_cast<Area2DSW*>(B);
+ Area2Pair2DSW *area2_pair = memnew(Area2Pair2DSW(area_b,p_subindex_B,area,p_subindex_A) );
+ return area2_pair;
+ } else {
+
+ Body2DSW *body=static_cast<Body2DSW*>(B);
+ AreaPair2DSW *area_pair = memnew(AreaPair2DSW(body,p_subindex_B,area,p_subindex_A) );
+ return area_pair;
+ }
- AreaPair2DSW *area_pair = memnew(AreaPair2DSW(body,p_subindex_B,area,p_subindex_A) );
- return area_pair;
} else {
@@ -468,8 +1122,8 @@ void* Space2DSW::_broadphase_pair(CollisionObject2DSW *A,int p_subindex_A,Collis
void Space2DSW::_broadphase_unpair(CollisionObject2DSW *A,int p_subindex_A,CollisionObject2DSW *B,int p_subindex_B,void *p_data,void *p_self) {
-
Space2DSW *self = (Space2DSW*)p_self;
+ self->collision_pairs--;
Constraint2DSW *c = (Constraint2DSW*)p_data;
memdelete(c);
}
@@ -576,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();
@@ -601,8 +1256,7 @@ void Space2DSW::set_param(Physics2DServer::SpaceParameter p_param, real_t p_valu
case Physics2DServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: contact_max_allowed_penetration=p_value; break;
case Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD: body_linear_velocity_sleep_treshold=p_value; break;
case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD: body_angular_velocity_sleep_treshold=p_value; break;
- case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep=p_value; break;
- case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: body_angular_velocity_damp_ratio=p_value; break;
+ case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep=p_value; break;
case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias=p_value; break;
}
}
@@ -617,7 +1271,6 @@ real_t Space2DSW::get_param(Physics2DServer::SpaceParameter p_param) const {
case Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD: return body_linear_velocity_sleep_treshold;
case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD: return body_angular_velocity_sleep_treshold;
case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep;
- case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: return body_angular_velocity_damp_ratio;
case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias;
}
return 0;
@@ -646,6 +1299,12 @@ Physics2DDirectSpaceStateSW *Space2DSW::get_direct_state() {
Space2DSW::Space2DSW() {
+ 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;
@@ -655,7 +1314,6 @@ Space2DSW::Space2DSW() {
body_linear_velocity_sleep_treshold=0.01;
body_angular_velocity_sleep_treshold=(8.0 / 180.0 * Math_PI);
body_time_to_sleep=0.5;
- body_angular_velocity_damp_ratio=15;
broadphase = BroadPhase2DSW::create_func();
@@ -665,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 bd41097fba..97ad3d7f80 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,6 +46,7 @@ public:
Space2DSW *space;
+ virtual int intersect_point(const Vector2& p_point,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 intersect_ray(const Vector2& p_from, const Vector2& 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 Matrix32& p_xform,const Vector2& p_motion,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 Matrix32& p_xform,const Vector2& 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);
@@ -93,10 +94,18 @@ class Space2DSW {
float body_linear_velocity_sleep_treshold;
float body_angular_velocity_sleep_treshold;
float body_time_to_sleep;
- float body_angular_velocity_damp_ratio;
bool locked;
+ int island_count;
+ int active_objects;
+ int collision_pairs;
+
+ int _cull_aabb_for_body(Body2DSW *p_body,const Rect2& p_aabb);
+
+ Vector<Vector2> contact_debug;
+ int contact_debug_count;
+
friend class Physics2DDirectSpaceStateSW;
public:
@@ -138,7 +147,7 @@ public:
_FORCE_INLINE_ real_t get_body_linear_velocity_sleep_treshold() const { return body_linear_velocity_sleep_treshold; }
_FORCE_INLINE_ real_t get_body_angular_velocity_sleep_treshold() const { return body_angular_velocity_sleep_treshold; }
_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();
@@ -153,6 +162,24 @@ public:
void set_param(Physics2DServer::SpaceParameter p_param, real_t p_value);
real_t get_param(Physics2DServer::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; }
+
+ 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 29f4a58287..bc87789937 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -137,6 +137,8 @@ void Step2DSW::step(Space2DSW* p_space,float p_delta,int p_iterations) {
active_count++;
}
+ p_space->set_active_objects(active_count);
+
/* GENERATE CONSTRAINT ISLANDS */
Body2DSW *island_list=NULL;
@@ -168,6 +170,8 @@ void Step2DSW::step(Space2DSW* p_space,float p_delta,int p_iterations) {
b=b->next();
}
+ p_space->set_island_count(island_count);
+
const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list();
diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h
index 91ac9d8584..d5e919836c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
index 9cbd7414bd..b9d15d6e35 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,20 +39,24 @@ void Physics2DDirectBodyState::integrate_forces() {
real_t av = get_angular_velocity();
- float damp = 1.0 - step * get_total_density();
+ float damp = 1.0 - step * get_total_linear_damp();
if (damp<0) // reached zero in the given time
damp=0;
lv*=damp;
+
+ damp = 1.0 - step * get_total_angular_damp();
+
+ if (damp<0) // reached zero in the given time
+ damp=0;
+
av*=damp;
set_linear_velocity(lv);
set_angular_velocity(av);
-
-
}
Object* Physics2DDirectBodyState::get_contact_collider_object(int p_contact_idx) const {
@@ -70,7 +74,8 @@ Physics2DServer * Physics2DServer::get_singleton() {
void Physics2DDirectBodyState::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_total_gravity"),&Physics2DDirectBodyState::get_total_gravity);
- ObjectTypeDB::bind_method(_MD("get_total_density"),&Physics2DDirectBodyState::get_total_density);
+ ObjectTypeDB::bind_method(_MD("get_total_linear_damp"),&Physics2DDirectBodyState::get_total_linear_damp);
+ ObjectTypeDB::bind_method(_MD("get_total_angular_damp"),&Physics2DDirectBodyState::get_total_angular_damp);
ObjectTypeDB::bind_method(_MD("get_inverse_mass"),&Physics2DDirectBodyState::get_inverse_mass);
ObjectTypeDB::bind_method(_MD("get_inverse_inertia"),&Physics2DDirectBodyState::get_inverse_inertia);
@@ -97,6 +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_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);
@@ -110,17 +116,132 @@ Physics2DDirectBodyState::Physics2DDirectBodyState() {}
-Variant Physics2DDirectSpaceState::_intersect_ray(const Vector2& p_from, const Vector2& p_to,const Vector<RID>& p_exclude,uint32_t p_user_mask) {
+void Physics2DShapeQueryParameters::set_shape(const RES &p_shape) {
+
+ ERR_FAIL_COND(p_shape.is_null());
+ shape=p_shape->get_rid();
+}
+
+void Physics2DShapeQueryParameters::set_shape_rid(const RID& p_shape) {
+
+ shape=p_shape;
+}
+
+RID Physics2DShapeQueryParameters::get_shape_rid() const {
+
+ return shape;
+}
+
+void Physics2DShapeQueryParameters::set_transform(const Matrix32& p_transform){
+
+ transform=p_transform;
+}
+Matrix32 Physics2DShapeQueryParameters::get_transform() const{
+
+ return transform;
+}
+
+void Physics2DShapeQueryParameters::set_motion(const Vector2& p_motion){
+
+ motion=p_motion;
+}
+Vector2 Physics2DShapeQueryParameters::get_motion() const{
+
+ return motion;
+}
+
+void Physics2DShapeQueryParameters::set_margin(float p_margin){
+
+ margin=p_margin;
+}
+float Physics2DShapeQueryParameters::get_margin() const{
+
+ return margin;
+}
+
+void Physics2DShapeQueryParameters::set_layer_mask(int p_layer_mask){
+
+ layer_mask=p_layer_mask;
+}
+int Physics2DShapeQueryParameters::get_layer_mask() const{
+
+ return layer_mask;
+}
+
+
+void Physics2DShapeQueryParameters::set_object_type_mask(int p_object_type_mask){
+
+ object_type_mask=p_object_type_mask;
+}
+int Physics2DShapeQueryParameters::get_object_type_mask() const{
+
+ return object_type_mask;
+}
+void Physics2DShapeQueryParameters::set_exclude(const Vector<RID>& p_exclude) {
+
+ exclude.clear();;
+ for(int i=0;i<p_exclude.size();i++)
+ exclude.insert(p_exclude[i]);
+
+}
+
+Vector<RID> Physics2DShapeQueryParameters::get_exclude() const{
+
+ Vector<RID> ret;
+ ret.resize(exclude.size());
+ int idx=0;
+ for(Set<RID>::Element *E=exclude.front();E;E=E->next()) {
+ ret[idx]=E->get();
+ }
+ return ret;
+}
+
+void Physics2DShapeQueryParameters::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_shape","shape:Shape2D"),&Physics2DShapeQueryParameters::set_shape);
+ ObjectTypeDB::bind_method(_MD("set_shape_rid","shape"),&Physics2DShapeQueryParameters::set_shape_rid);
+ ObjectTypeDB::bind_method(_MD("get_shape_rid"),&Physics2DShapeQueryParameters::get_shape_rid);
+
+ ObjectTypeDB::bind_method(_MD("set_transform","transform"),&Physics2DShapeQueryParameters::set_transform);
+ ObjectTypeDB::bind_method(_MD("get_transform"),&Physics2DShapeQueryParameters::get_transform);
+
+ ObjectTypeDB::bind_method(_MD("set_motion","motion"),&Physics2DShapeQueryParameters::set_motion);
+ ObjectTypeDB::bind_method(_MD("get_motion"),&Physics2DShapeQueryParameters::get_motion);
+
+ ObjectTypeDB::bind_method(_MD("set_margin","margin"),&Physics2DShapeQueryParameters::set_margin);
+ ObjectTypeDB::bind_method(_MD("get_margin"),&Physics2DShapeQueryParameters::get_margin);
+
+ ObjectTypeDB::bind_method(_MD("set_layer_mask","layer_mask"),&Physics2DShapeQueryParameters::set_layer_mask);
+ ObjectTypeDB::bind_method(_MD("get_layer_mask"),&Physics2DShapeQueryParameters::get_layer_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_object_type_mask","object_type_mask"),&Physics2DShapeQueryParameters::set_object_type_mask);
+ ObjectTypeDB::bind_method(_MD("get_object_type_mask"),&Physics2DShapeQueryParameters::get_object_type_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_exclude","exclude"),&Physics2DShapeQueryParameters::set_exclude);
+ ObjectTypeDB::bind_method(_MD("get_exclude"),&Physics2DShapeQueryParameters::get_exclude);
+
+
+}
+
+Physics2DShapeQueryParameters::Physics2DShapeQueryParameters() {
+
+ margin=0;
+ layer_mask=0x7FFFFFFF;
+ object_type_mask=Physics2DDirectSpaceState::TYPE_MASK_COLLISION;
+}
+
+
+Dictionary Physics2DDirectSpaceState::_intersect_ray(const Vector2& p_from, const Vector2& p_to,const Vector<RID>& p_exclude,uint32_t p_layers,uint32_t p_object_type_mask) {
RayResult inters;
Set<RID> exclude;
for(int i=0;i<p_exclude.size();i++)
exclude.insert(p_exclude[i]);
- bool res = intersect_ray(p_from,p_to,inters,exclude,p_user_mask);
+ bool res = intersect_ray(p_from,p_to,inters,exclude,p_layers,p_object_type_mask);
if (!res)
- return Variant();
+ return Dictionary(true);
Dictionary d(true);
d["position"]=inters.position;
@@ -129,63 +250,108 @@ Variant Physics2DDirectSpaceState::_intersect_ray(const Vector2& p_from, const V
d["collider"]=inters.collider;
d["shape"]=inters.shape;
d["rid"]=inters.rid;
+ d["metadata"]=inters.metadata;
return d;
}
-Variant Physics2DDirectSpaceState::_intersect_shape(const RID& p_shape, const Matrix32& p_xform,int p_result_max,const Vector<RID>& p_exclude,uint32_t p_user_mask) {
+Array Physics2DDirectSpaceState::_intersect_shape(const Ref<Physics2DShapeQueryParameters> &psq, int p_max_results) {
+
+ Vector<ShapeResult> sr;
+ sr.resize(p_max_results);
+ int rc = intersect_shape(psq->shape,psq->transform,psq->motion,psq->margin,sr.ptr(),sr.size(),psq->exclude,psq->layer_mask,psq->object_type_mask);
+ Array ret;
+ ret.resize(rc);
+ for(int i=0;i<rc;i++) {
+
+ Dictionary d;
+ d["rid"]=sr[i].rid;
+ d["collider_id"]=sr[i].collider_id;
+ d["collider"]=sr[i].collider;
+ d["shape"]=sr[i].shape;
+ d["metadata"]=sr[i].metadata;
+ ret[i]=d;
+ }
+
+ return ret;
+}
+
+Array Physics2DDirectSpaceState::_cast_motion(const Ref<Physics2DShapeQueryParameters> &psq){
+
+ float closest_safe,closest_unsafe;
+ bool res = cast_motion(psq->shape,psq->transform,psq->motion,psq->margin,closest_safe,closest_unsafe,psq->exclude,psq->layer_mask,psq->object_type_mask);
+ if (!res)
+ return Array();
+ Array ret(true);
+ ret.resize(2);
+ ret[0]=closest_safe;
+ ret[1]=closest_unsafe;
+ return ret;
+
+}
- ERR_FAIL_INDEX_V(p_result_max,4096,Variant());
- if (p_result_max<=0)
- return Variant();
+Array Physics2DDirectSpaceState::_intersect_point(const Vector2& p_point,int p_max_results,const Vector<RID>& p_exclude,uint32_t p_layers,uint32_t p_object_type_mask) {
Set<RID> exclude;
for(int i=0;i<p_exclude.size();i++)
exclude.insert(p_exclude[i]);
- ShapeResult *res=(ShapeResult*)alloca(p_result_max*sizeof(ShapeResult));
-
- int rc = intersect_shape(p_shape,p_xform,Vector2(),0,res,p_result_max,exclude,p_user_mask);
+ Vector<ShapeResult> ret;
+ ret.resize(p_max_results);
+ int rc = intersect_point(p_point,ret.ptr(),ret.size(),exclude,p_layers,p_object_type_mask);
if (rc==0)
- return Variant();
-
- Ref<Physics2DShapeQueryResult> result = memnew( Physics2DShapeQueryResult );
- result->result.resize(rc);
- for(int i=0;i<rc;i++)
- result->result[i]=res[i];
-
- return result;
+ return Array();
+
+ Array r;
+ r.resize(rc);
+ for(int i=0;i<rc;i++) {
+
+ Dictionary d;
+ d["rid"]=ret[i].rid;
+ d["collider_id"]=ret[i].collider_id;
+ d["collider"]=ret[i].collider;
+ d["shape"]=ret[i].shape;
+ d["metadata"]=ret[i].metadata;
+ r[i]=d;
+ }
+ return r;
}
+Array Physics2DDirectSpaceState::_collide_shape(const Ref<Physics2DShapeQueryParameters> &psq, int p_max_results){
-Variant Physics2DDirectSpaceState::_cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,const Vector<RID>& p_exclude,uint32_t p_user_mask) {
-
-
-#if 0
- Set<RID> exclude;
- for(int i=0;i<p_exclude.size();i++)
- exclude.insert(p_exclude[i]);
-
+ Vector<Vector2> ret;
+ ret.resize(p_max_results*2);
+ int rc=0;
+ bool res = collide_shape(psq->shape,psq->transform,psq->motion,psq->margin,ret.ptr(),p_max_results,rc,psq->exclude,psq->layer_mask,psq->object_type_mask);
+ if (!res)
+ return Array();
+ Array r;
+ r.resize(rc*2);
+ for(int i=0;i<rc*2;i++)
+ r[i]=ret[i];
+ return r;
- bool result = cast_motion(p_shape,p_xform,p_motion,0,mcc,exclude,p_user_mask);
+}
+Dictionary Physics2DDirectSpaceState::_get_rest_info(const Ref<Physics2DShapeQueryParameters> &psq){
- if (!result)
- return Variant();
+ ShapeRestInfo sri;
- Dictionary d(true);
- d["point"]=mcc.point;
- d["normal"]=mcc.normal;
- d["rid"]=mcc.rid;
- d["collider_id"]=mcc.collider_id;
- d["collider"]=mcc.collider;
- d["shape"]=mcc.shape;
+ bool res = rest_info(psq->shape,psq->transform,psq->motion,psq->margin,&sri,psq->exclude,psq->layer_mask,psq->object_type_mask);
+ Dictionary r(true);
+ if (!res)
+ return r;
- return d;
-#endif
- return Variant();
+ r["point"]=sri.point;
+ r["normal"]=sri.normal;
+ r["rid"]=sri.rid;
+ r["collider_id"]=sri.collider_id;
+ r["shape"]=sri.shape;
+ r["linear_velocity"]=sri.linear_velocity;
+ r["metadata"]=sri.metadata;
+ return r;
}
@@ -200,9 +366,20 @@ Physics2DDirectSpaceState::Physics2DDirectSpaceState() {
void Physics2DDirectSpaceState::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("intersect_ray:Dictionary","from","to","exclude","umask"),&Physics2DDirectSpaceState::_intersect_ray,DEFVAL(Array()),DEFVAL(0));
- ObjectTypeDB::bind_method(_MD("intersect_shape:Physics2DShapeQueryResult","shape","xform","result_max","exclude","umask"),&Physics2DDirectSpaceState::_intersect_shape,DEFVAL(Array()),DEFVAL(0));
- ObjectTypeDB::bind_method(_MD("cast_motion","shape","xform","motion","exclude","umask"),&Physics2DDirectSpaceState::_intersect_shape,DEFVAL(Array()),DEFVAL(0));
+ ObjectTypeDB::bind_method(_MD("intersect_point","point","max_results","exclude","layer_mask","type_mask"),&Physics2DDirectSpaceState::_intersect_point,DEFVAL(32),DEFVAL(Array()),DEFVAL(0x7FFFFFFF),DEFVAL(TYPE_MASK_COLLISION));
+ ObjectTypeDB::bind_method(_MD("intersect_ray:Dictionary","from","to","exclude","layer_mask","type_mask"),&Physics2DDirectSpaceState::_intersect_ray,DEFVAL(Array()),DEFVAL(0x7FFFFFFF),DEFVAL(TYPE_MASK_COLLISION));
+ ObjectTypeDB::bind_method(_MD("intersect_shape","shape:Physics2DShapeQueryParameters","max_results"),&Physics2DDirectSpaceState::_intersect_shape,DEFVAL(32));
+ ObjectTypeDB::bind_method(_MD("cast_motion","shape:Physics2DShapeQueryParameters"),&Physics2DDirectSpaceState::_cast_motion);
+ ObjectTypeDB::bind_method(_MD("collide_shape","shape:Physics2DShapeQueryParameters","max_results"),&Physics2DDirectSpaceState::_collide_shape,DEFVAL(32));
+ ObjectTypeDB::bind_method(_MD("get_rest_info","shape:Physics2DShapeQueryParameters"),&Physics2DDirectSpaceState::_get_rest_info);
+ //ObjectTypeDB::bind_method(_MD("cast_motion","shape","xform","motion","exclude","umask"),&Physics2DDirectSpaceState::_intersect_shape,DEFVAL(Array()),DEFVAL(0));
+
+ BIND_CONSTANT( TYPE_MASK_STATIC_BODY );
+ BIND_CONSTANT( TYPE_MASK_KINEMATIC_BODY );
+ BIND_CONSTANT( TYPE_MASK_RIGID_BODY );
+ BIND_CONSTANT( TYPE_MASK_CHARACTER_BODY );
+ BIND_CONSTANT( TYPE_MASK_AREA );
+ BIND_CONSTANT( TYPE_MASK_COLLISION );
}
@@ -244,13 +421,86 @@ void Physics2DShapeQueryResult::_bind_methods() {
}
+///////////////////////////////
+/*bool Physics2DTestMotionResult::is_colliding() const {
+ return colliding;
+}*/
+Vector2 Physics2DTestMotionResult::get_motion() const{
+ return result.motion;
+}
+Vector2 Physics2DTestMotionResult::get_motion_remainder() const{
+
+ return result.remainder;
+}
+
+Vector2 Physics2DTestMotionResult::get_collision_point() const{
+
+ return result.collision_point;
+}
+Vector2 Physics2DTestMotionResult::get_collision_normal() const{
+
+ return result.collision_normal;
+}
+Vector2 Physics2DTestMotionResult::get_collider_velocity() const{
+
+ return result.collider_velocity;
+}
+ObjectID Physics2DTestMotionResult::get_collider_id() const{
+
+ return result.collider_id;
+}
+RID Physics2DTestMotionResult::get_collider_rid() const{
+
+ return result.collider;
+}
+
+Object* Physics2DTestMotionResult::get_collider() const {
+ return ObjectDB::get_instance(result.collider_id);
+}
+
+int Physics2DTestMotionResult::get_collider_shape() const{
+
+ return result.collider_shape;
+}
+
+void Physics2DTestMotionResult::_bind_methods() {
+
+ //ObjectTypeDB::bind_method(_MD("is_colliding"),&Physics2DTestMotionResult::is_colliding);
+ ObjectTypeDB::bind_method(_MD("get_motion"),&Physics2DTestMotionResult::get_motion);
+ ObjectTypeDB::bind_method(_MD("get_motion_remainder"),&Physics2DTestMotionResult::get_motion_remainder);
+ ObjectTypeDB::bind_method(_MD("get_collision_point"),&Physics2DTestMotionResult::get_collision_point);
+ ObjectTypeDB::bind_method(_MD("get_collision_normal"),&Physics2DTestMotionResult::get_collision_normal);
+ ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&Physics2DTestMotionResult::get_collider_velocity);
+ ObjectTypeDB::bind_method(_MD("get_collider_id"),&Physics2DTestMotionResult::get_collider_id);
+ ObjectTypeDB::bind_method(_MD("get_collider_rid"),&Physics2DTestMotionResult::get_collider_rid);
+ ObjectTypeDB::bind_method(_MD("get_collider"),&Physics2DTestMotionResult::get_collider);
+ ObjectTypeDB::bind_method(_MD("get_collider_shape"),&Physics2DTestMotionResult::get_collider_shape);
+
+}
+
+Physics2DTestMotionResult::Physics2DTestMotionResult(){
+
+ colliding=false;
+ result.collider_id=0;
+ result.collider_shape=0;
+}
///////////////////////////////////////
+
+
+bool Physics2DServer::_body_test_motion(RID p_body,const Vector2& p_motion,float p_margin,const Ref<Physics2DTestMotionResult>& p_result) {
+
+ MotionResult *r=NULL;
+ if (p_result.is_valid())
+ r=p_result->get_result_ptr();
+ return body_test_motion(p_body,p_motion,p_margin,r);
+}
+
void Physics2DServer::_bind_methods() {
@@ -275,8 +525,8 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("area_set_space_override_mode","area","mode"),&Physics2DServer::area_set_space_override_mode);
ObjectTypeDB::bind_method(_MD("area_get_space_override_mode","area"),&Physics2DServer::area_get_space_override_mode);
- ObjectTypeDB::bind_method(_MD("area_add_shape","area","shape","transform"),&Physics2DServer::area_set_shape,DEFVAL(Matrix32()));
- ObjectTypeDB::bind_method(_MD("area_set_shape","area","shape_idx","shape"),&Physics2DServer::area_get_shape);
+ ObjectTypeDB::bind_method(_MD("area_add_shape","area","shape","transform"),&Physics2DServer::area_add_shape,DEFVAL(Matrix32()));
+ ObjectTypeDB::bind_method(_MD("area_set_shape","area","shape_idx","shape"),&Physics2DServer::area_set_shape);
ObjectTypeDB::bind_method(_MD("area_set_shape_transform","area","shape_idx","transform"),&Physics2DServer::area_set_shape_transform);
ObjectTypeDB::bind_method(_MD("area_get_shape_count","area"),&Physics2DServer::area_get_shape_count);
@@ -286,6 +536,8 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("area_remove_shape","area","shape_idx"),&Physics2DServer::area_remove_shape);
ObjectTypeDB::bind_method(_MD("area_clear_shapes","area"),&Physics2DServer::area_clear_shapes);
+ ObjectTypeDB::bind_method(_MD("area_set_layer_mask","area","mask"),&Physics2DServer::area_set_layer_mask);
+ ObjectTypeDB::bind_method(_MD("area_set_collision_mask","area","mask"),&Physics2DServer::area_set_collision_mask);
ObjectTypeDB::bind_method(_MD("area_set_param","area","param","value"),&Physics2DServer::area_set_param);
ObjectTypeDB::bind_method(_MD("area_set_transform","area","transform"),&Physics2DServer::area_set_transform);
@@ -309,10 +561,12 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("body_add_shape","body","shape","transform"),&Physics2DServer::body_add_shape,DEFVAL(Matrix32()));
ObjectTypeDB::bind_method(_MD("body_set_shape","body","shape_idx","shape"),&Physics2DServer::body_set_shape);
ObjectTypeDB::bind_method(_MD("body_set_shape_transform","body","shape_idx","transform"),&Physics2DServer::body_set_shape_transform);
+ ObjectTypeDB::bind_method(_MD("body_set_shape_metadata","body","shape_idx","metadata"),&Physics2DServer::body_set_shape_metadata);
ObjectTypeDB::bind_method(_MD("body_get_shape_count","body"),&Physics2DServer::body_get_shape_count);
ObjectTypeDB::bind_method(_MD("body_get_shape","body","shape_idx"),&Physics2DServer::body_get_shape);
ObjectTypeDB::bind_method(_MD("body_get_shape_transform","body","shape_idx"),&Physics2DServer::body_get_shape_transform);
+ ObjectTypeDB::bind_method(_MD("body_get_shape_metadata","body","shape_idx"),&Physics2DServer::body_get_shape_metadata);
ObjectTypeDB::bind_method(_MD("body_remove_shape","body","shape_idx"),&Physics2DServer::body_remove_shape);
ObjectTypeDB::bind_method(_MD("body_clear_shapes","body"),&Physics2DServer::body_clear_shapes);
@@ -332,8 +586,8 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("body_set_layer_mask","body","mask"),&Physics2DServer::body_set_layer_mask);
ObjectTypeDB::bind_method(_MD("body_get_layer_mask","body"),&Physics2DServer::body_get_layer_mask);
- ObjectTypeDB::bind_method(_MD("body_set_user_mask","body","mask"),&Physics2DServer::body_set_user_mask);
- ObjectTypeDB::bind_method(_MD("body_get_user_mask","body"),&Physics2DServer::body_get_user_mask);
+ ObjectTypeDB::bind_method(_MD("body_set_collision_mask","body","mask"),&Physics2DServer::body_set_collision_mask);
+ ObjectTypeDB::bind_method(_MD("body_get_collision_mask","body"),&Physics2DServer::body_get_collision_mask);
ObjectTypeDB::bind_method(_MD("body_set_param","body","param","value"),&Physics2DServer::body_set_param);
@@ -352,11 +606,20 @@ 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_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_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_test_motion","body","motion","margin","result:Physics2DTestMotionResult"),&Physics2DServer::_body_test_motion,DEFVAL(0.08),DEFVAL(Variant()));
+
/* JOINT API */
ObjectTypeDB::bind_method(_MD("joint_set_param","joint","param","value"),&Physics2DServer::joint_set_param);
@@ -371,10 +634,12 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("joint_get_type","joint"),&Physics2DServer::joint_get_type);
- ObjectTypeDB::bind_method(_MD("free","rid"),&Physics2DServer::free);
+ ObjectTypeDB::bind_method(_MD("free_rid","rid"),&Physics2DServer::free);
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("init"),&Physics2DServer::init);
// ObjectTypeDB::bind_method(_MD("step"),&Physics2DServer::step);
// ObjectTypeDB::bind_method(_MD("sync"),&Physics2DServer::sync);
@@ -392,8 +657,10 @@ void Physics2DServer::_bind_methods() {
BIND_CONSTANT( AREA_PARAM_GRAVITY );
BIND_CONSTANT( AREA_PARAM_GRAVITY_VECTOR );
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 );
@@ -408,6 +675,9 @@ void Physics2DServer::_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_LINEAR_DAMP);
+ BIND_CONSTANT( BODY_PARAM_ANGULAR_DAMP);
BIND_CONSTANT( BODY_PARAM_MAX );
BIND_CONSTANT( BODY_STATE_TRANSFORM );
@@ -434,13 +704,17 @@ void Physics2DServer::_bind_methods() {
BIND_CONSTANT( AREA_BODY_ADDED );
BIND_CONSTANT( AREA_BODY_REMOVED );
+ BIND_CONSTANT( INFO_ACTIVE_OBJECTS );
+ BIND_CONSTANT( INFO_COLLISION_PAIRS );
+ BIND_CONSTANT( INFO_ISLAND_COUNT );
+
}
Physics2DServer::Physics2DServer() {
- ERR_FAIL_COND( singleton!=NULL );
+ //ERR_FAIL_COND( singleton!=NULL );
singleton=this;
}
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index def1e69992..6845c7dfe1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,6 +31,7 @@
#include "object.h"
#include "reference.h"
+#include "resource.h"
class Physics2DDirectSpaceState;
@@ -42,7 +43,8 @@ protected:
public:
virtual Vector2 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 float get_total_linear_damp() const=0; // get density of this body space/area
+ virtual float get_total_angular_damp() const=0; // get density of this body space/area
virtual float get_inverse_mass() const=0; // get the mass
virtual real_t get_inverse_inertia() const=0; // get density of this body space
@@ -70,6 +72,7 @@ public:
virtual ObjectID get_contact_collider_id(int p_contact_idx) const=0;
virtual Object* get_contact_collider_object(int p_contact_idx) const;
virtual int get_contact_collider_shape(int p_contact_idx) const=0;
+ virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const=0;
virtual Vector2 get_contact_collider_velocity_at_pos(int p_contact_idx) const=0;
virtual real_t get_step() const=0;
@@ -84,14 +87,61 @@ public:
class Physics2DShapeQueryResult;
+//used for script
+class Physics2DShapeQueryParameters : public Reference {
+
+ OBJ_TYPE(Physics2DShapeQueryParameters, Reference);
+friend class Physics2DDirectSpaceState;
+ RID shape;
+ Matrix32 transform;
+ Vector2 motion;
+ float margin;
+ Set<RID> exclude;
+ uint32_t layer_mask;
+ uint32_t object_type_mask;
+protected:
+ static void _bind_methods();
+public:
+
+
+ void set_shape(const RES& p_shape);
+ void set_shape_rid(const RID& p_shape);
+ RID get_shape_rid() const;
+
+ void set_transform(const Matrix32& p_transform);
+ Matrix32 get_transform() const;
+
+ void set_motion(const Vector2& p_motion);
+ Vector2 get_motion() const;
+
+ void set_margin(float p_margin);
+ float get_margin() const;
+
+ void set_layer_mask(int p_layer_mask);
+ int get_layer_mask() const;
+
+ void set_object_type_mask(int p_object_type_mask);
+ int get_object_type_mask() const;
+
+ void set_exclude(const Vector<RID>& p_exclude);
+ Vector<RID> get_exclude() const;
+
+ Physics2DShapeQueryParameters();
+
+};
+
+
class Physics2DDirectSpaceState : public Object {
OBJ_TYPE( Physics2DDirectSpaceState, Object );
- Variant _intersect_ray(const Vector2& p_from, const Vector2& p_to,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_layers=0);
- Variant _intersect_shape(const RID& p_shape, const Matrix32& p_xform,int p_result_max=64,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_layers=0);
- Variant _cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_layers=0);
+ Dictionary _intersect_ray(const Vector2& p_from, const Vector2& p_to,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_layers=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
+ Array _intersect_point(const Vector2& p_point,int p_max_results=32,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_layers=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
+ Array _intersect_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query,int p_max_results=32);
+ Array _cast_motion(const Ref<Physics2DShapeQueryParameters> &p_shape_query);
+ Array _collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query,int p_max_results=32);
+ Dictionary _get_rest_info(const Ref<Physics2DShapeQueryParameters> &p_shape_query);
protected:
static void _bind_methods();
@@ -116,6 +166,7 @@ public:
ObjectID collider_id;
Object *collider;
int shape;
+ Variant metadata;
};
virtual bool intersect_ray(const Vector2& p_from, const Vector2& 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;
@@ -126,12 +177,14 @@ public:
ObjectID collider_id;
Object *collider;
int shape;
+ Variant metadata;
- };
- virtual int intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,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)=0;
+ };
+ virtual int intersect_point(const Vector2& p_point,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)=0;
+ virtual int intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,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)=0;
virtual bool cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& 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)=0;
@@ -145,6 +198,7 @@ public:
ObjectID collider_id;
int shape;
Vector2 linear_velocity; //velocity at contact point
+ Variant metadata;
};
@@ -176,6 +230,7 @@ public:
Physics2DShapeQueryResult();
};
+class Physics2DTestMotionResult;
class Physics2DServer : public Object {
@@ -183,6 +238,8 @@ class Physics2DServer : public Object {
static Physics2DServer * singleton;
+ virtual bool _body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.08,const Ref<Physics2DTestMotionResult>& p_result=Ref<Physics2DTestMotionResult>());
+
protected:
static void _bind_methods();
@@ -227,7 +284,6 @@ public:
SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD,
SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD,
SPACE_PARAM_BODY_TIME_TO_SLEEP,
- SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,
SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,
};
@@ -237,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
@@ -250,8 +309,10 @@ public:
AREA_PARAM_GRAVITY,
AREA_PARAM_GRAVITY_VECTOR,
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
};
@@ -290,7 +351,14 @@ public:
virtual Variant area_get_param(RID p_parea,AreaParameter p_param) const=0;
virtual Matrix32 area_get_transform(RID p_area) const=0;
+ virtual void area_set_collision_mask(RID p_area,uint32_t p_mask)=0;
+ virtual void area_set_layer_mask(RID p_area,uint32_t p_mask)=0;
+
+ virtual void area_set_monitorable(RID p_area,bool p_monitorable)=0;
+ virtual void area_set_pickable(RID p_area,bool p_pickable)=0;
+
virtual void area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method)=0;
+ virtual void area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method)=0;
/* BODY API */
@@ -315,10 +383,12 @@ public:
virtual void body_add_shape(RID p_body, RID p_shape, const Matrix32& p_transform=Matrix32())=0;
virtual void body_set_shape(RID p_body, int p_shape_idx,RID p_shape)=0;
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Matrix32& p_transform)=0;
+ virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant& p_metadata)=0;
virtual int body_get_shape_count(RID p_body) const=0;
virtual RID body_get_shape(RID p_body, int p_shape_idx) const=0;
virtual Matrix32 body_get_shape_transform(RID p_body, int p_shape_idx) const=0;
+ virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const=0;
virtual void body_set_shape_as_trigger(RID p_body, int p_shape_idx,bool p_enable)=0;
virtual bool body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) const=0;
@@ -339,16 +409,19 @@ public:
virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const=0;
virtual void body_set_layer_mask(RID p_body, uint32_t p_mask)=0;
- virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const=0;
+ virtual uint32_t body_get_layer_mask(RID p_body) const=0;
- virtual void body_set_user_mask(RID p_body, uint32_t p_mask)=0;
- virtual uint32_t body_get_user_mask(RID p_body, uint32_t p_mask) const=0;
+ virtual void body_set_collision_mask(RID p_body, uint32_t p_mask)=0;
+ virtual uint32_t body_get_collision_mask(RID p_body) const=0;
// common body variables
enum BodyParameter {
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,
};
@@ -362,7 +435,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;
@@ -386,6 +459,12 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts)=0;
virtual int body_get_max_contacts_reported(RID p_body) const=0;
+ virtual void body_set_one_way_collision_direction(RID p_body,const Vector2& p_direction)=0;
+ virtual Vector2 body_get_one_way_collision_direction(RID p_body) const=0;
+
+ virtual void body_set_one_way_collision_max_depth(RID p_body,float p_max_depth)=0;
+ virtual float body_get_one_way_collision_max_depth(RID p_body) const=0;
+
//missing remove
virtual void body_set_contacts_reported_depth_treshold(RID p_body, float p_treshold)=0;
virtual float body_get_contacts_reported_depth_treshold(RID p_body) const=0;
@@ -397,6 +476,24 @@ public:
virtual bool body_collide_shape(RID p_body, int p_body_shape,RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,Vector2 *r_results,int p_result_max,int &r_result_count)=0;
+ virtual void body_set_pickable(RID p_body,bool p_pickable)=0;
+
+ struct MotionResult {
+
+ Vector2 motion;
+ Vector2 remainder;
+
+ Vector2 collision_point;
+ Vector2 collision_normal;
+ Vector2 collider_velocity;
+ ObjectID collider_id;
+ RID collider;
+ int collider_shape;
+ Variant collider_metadata;
+ };
+
+ virtual bool body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.001,MotionResult *r_result=NULL)=0;
+
/* JOINT API */
enum JointType {
@@ -419,6 +516,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,
@@ -446,12 +550,53 @@ public:
virtual void step(float p_step)=0;
virtual void sync()=0;
virtual void flush_queries()=0;
+ virtual void end_sync()=0;
virtual void finish()=0;
+ enum ProcessInfo {
+
+ INFO_ACTIVE_OBJECTS,
+ INFO_COLLISION_PAIRS,
+ INFO_ISLAND_COUNT
+ };
+
+ virtual int get_process_info(ProcessInfo p_info)=0;
+
Physics2DServer();
~Physics2DServer();
};
+
+class Physics2DTestMotionResult : public Reference {
+
+ OBJ_TYPE( Physics2DTestMotionResult, Reference );
+
+ Physics2DServer::MotionResult result;
+ bool colliding;
+friend class Physics2DServer;
+
+protected:
+ static void _bind_methods();
+public:
+
+ Physics2DServer::MotionResult* get_result_ptr() const { return const_cast<Physics2DServer::MotionResult*>(&result); }
+
+ //bool is_colliding() const;
+ Vector2 get_motion() const;
+ Vector2 get_motion_remainder() const;
+
+ Vector2 get_collision_point() const;
+ Vector2 get_collision_normal() const;
+ Vector2 get_collider_velocity() const;
+ ObjectID get_collider_id() const;
+ RID get_collider_rid() const;
+ Object* get_collider() const;
+ int get_collider_shape() const;
+
+ Physics2DTestMotionResult();
+};
+
+
VARIANT_ENUM_CAST( Physics2DServer::ShapeType );
VARIANT_ENUM_CAST( Physics2DServer::SpaceParameter );
VARIANT_ENUM_CAST( Physics2DServer::AreaParameter );
@@ -465,5 +610,6 @@ VARIANT_ENUM_CAST( Physics2DServer::JointType );
VARIANT_ENUM_CAST( Physics2DServer::DampedStringParam );
//VARIANT_ENUM_CAST( Physics2DServer::ObjectType );
VARIANT_ENUM_CAST( Physics2DServer::AreaBodyStatus );
+VARIANT_ENUM_CAST( Physics2DServer::ProcessInfo );
#endif
diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp
index 69c82519dd..53409acdfb 100644
--- a/servers/physics_server.cpp
+++ b/servers/physics_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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);
@@ -85,6 +91,7 @@ void PhysicsDirectBodyState::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_transform"),&PhysicsDirectBodyState::get_transform);
ObjectTypeDB::bind_method(_MD("add_force","force","pos"),&PhysicsDirectBodyState::add_force);
+ ObjectTypeDB::bind_method(_MD("apply_impulse","pos","j"),&PhysicsDirectBodyState::apply_impulse);
ObjectTypeDB::bind_method(_MD("set_sleep_state","enabled"),&PhysicsDirectBodyState::set_sleep_state);
ObjectTypeDB::bind_method(_MD("is_sleeping"),&PhysicsDirectBodyState::is_sleeping);
@@ -112,30 +119,115 @@ PhysicsDirectBodyState::PhysicsDirectBodyState() {}
-Variant PhysicsDirectSpaceState::_intersect_ray(const Vector3& p_from, const Vector3& p_to,const Vector<RID>& p_exclude,uint32_t p_user_mask) {
+void PhysicsShapeQueryParameters::set_shape(const RES &p_shape) {
- RayResult inters;
- Set<RID> exclude;
+ ERR_FAIL_COND(p_shape.is_null());
+ shape=p_shape->get_rid();
+}
+
+void PhysicsShapeQueryParameters::set_shape_rid(const RID& p_shape) {
+
+ shape=p_shape;
+}
+
+RID PhysicsShapeQueryParameters::get_shape_rid() const {
+
+ return shape;
+}
+
+void PhysicsShapeQueryParameters::set_transform(const Transform& p_transform){
+
+ transform=p_transform;
+}
+Transform PhysicsShapeQueryParameters::get_transform() const{
+
+ return transform;
+}
+
+void PhysicsShapeQueryParameters::set_margin(float p_margin){
+
+ margin=p_margin;
+}
+
+float PhysicsShapeQueryParameters::get_margin() const{
+
+ return margin;
+}
+
+void PhysicsShapeQueryParameters::set_layer_mask(int p_layer_mask){
+
+ layer_mask=p_layer_mask;
+}
+int PhysicsShapeQueryParameters::get_layer_mask() const{
+
+ return layer_mask;
+}
+
+
+void PhysicsShapeQueryParameters::set_object_type_mask(int p_object_type_mask){
+
+ object_type_mask=p_object_type_mask;
+}
+int PhysicsShapeQueryParameters::get_object_type_mask() const{
+
+ return object_type_mask;
+}
+void PhysicsShapeQueryParameters::set_exclude(const Vector<RID>& p_exclude) {
+
+ exclude.clear();;
for(int i=0;i<p_exclude.size();i++)
exclude.insert(p_exclude[i]);
- bool res = intersect_ray(p_from,p_to,inters,exclude,p_user_mask);
+}
- if (!res)
- return Variant();
+Vector<RID> PhysicsShapeQueryParameters::get_exclude() const{
+
+ Vector<RID> ret;
+ ret.resize(exclude.size());
+ int idx=0;
+ for(Set<RID>::Element *E=exclude.front();E;E=E->next()) {
+ ret[idx]=E->get();
+ }
+ return ret;
+}
+
+void PhysicsShapeQueryParameters::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_shape","shape:Shape"),&PhysicsShapeQueryParameters::set_shape);
+ ObjectTypeDB::bind_method(_MD("set_shape_rid","shape"),&PhysicsShapeQueryParameters::set_shape_rid);
+ ObjectTypeDB::bind_method(_MD("get_shape_rid"),&PhysicsShapeQueryParameters::get_shape_rid);
+
+ ObjectTypeDB::bind_method(_MD("set_transform","transform"),&PhysicsShapeQueryParameters::set_transform);
+ ObjectTypeDB::bind_method(_MD("get_transform"),&PhysicsShapeQueryParameters::get_transform);
+
+ ObjectTypeDB::bind_method(_MD("set_margin","margin"),&PhysicsShapeQueryParameters::set_margin);
+ ObjectTypeDB::bind_method(_MD("get_margin"),&PhysicsShapeQueryParameters::get_margin);
+
+ ObjectTypeDB::bind_method(_MD("set_layer_mask","layer_mask"),&PhysicsShapeQueryParameters::set_layer_mask);
+ ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsShapeQueryParameters::get_layer_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_object_type_mask","object_type_mask"),&PhysicsShapeQueryParameters::set_object_type_mask);
+ ObjectTypeDB::bind_method(_MD("get_object_type_mask"),&PhysicsShapeQueryParameters::get_object_type_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_exclude","exclude"),&PhysicsShapeQueryParameters::set_exclude);
+ ObjectTypeDB::bind_method(_MD("get_exclude"),&PhysicsShapeQueryParameters::get_exclude);
- Dictionary d;
- d["position"]=inters.position;
- d["normal"]=inters.normal;
- d["collider_id"]=inters.collider_id;
- d["collider"]=inters.collider;
- d["shape"]=inters.shape;
- d["rid"]=inters.rid;
- return d;
}
-Variant PhysicsDirectSpaceState::_intersect_shape(const RID& p_shape, const Transform& p_xform,int p_result_max,const Vector<RID>& p_exclude,uint32_t p_user_mask) {
+PhysicsShapeQueryParameters::PhysicsShapeQueryParameters() {
+
+ margin=0;
+ layer_mask=0x7FFFFFFF;
+ object_type_mask=PhysicsDirectSpaceState::TYPE_MASK_COLLISION;
+}
+
+
+
+/////////////////////////////////////
+
+/*
+Variant PhysicsDirectSpaceState::_intersect_shape(const RID& p_shape, const Transform& p_xform,int p_result_max,const Vector<RID>& p_exclude,uint32_t p_collision_mask) {
@@ -149,7 +241,7 @@ Variant PhysicsDirectSpaceState::_intersect_shape(const RID& p_shape, const Tran
ShapeResult *res=(ShapeResult*)alloca(p_result_max*sizeof(ShapeResult));
- int rc = intersect_shape(p_shape,p_xform,res,p_result_max,exclude,p_user_mask);
+ int rc = intersect_shape(p_shape,p_xform,0,res,p_result_max,exclude);
if (rc==0)
return Variant();
@@ -162,8 +254,98 @@ Variant PhysicsDirectSpaceState::_intersect_shape(const RID& p_shape, const Tran
return result;
}
+*/
+
+
+Dictionary PhysicsDirectSpaceState::_intersect_ray(const Vector3& p_from, const Vector3& p_to,const Vector<RID>& p_exclude,uint32_t p_layers,uint32_t p_object_type_mask) {
+
+ RayResult inters;
+ Set<RID> exclude;
+ for(int i=0;i<p_exclude.size();i++)
+ exclude.insert(p_exclude[i]);
+
+ bool res = intersect_ray(p_from,p_to,inters,exclude,p_layers,p_object_type_mask);
+
+ if (!res)
+ return Dictionary(true);
+
+ Dictionary d(true);
+ d["position"]=inters.position;
+ d["normal"]=inters.normal;
+ d["collider_id"]=inters.collider_id;
+ d["collider"]=inters.collider;
+ d["shape"]=inters.shape;
+ d["rid"]=inters.rid;
+
+ return d;
+}
+Array PhysicsDirectSpaceState::_intersect_shape(const Ref<PhysicsShapeQueryParameters> &psq, int p_max_results) {
+ Vector<ShapeResult> sr;
+ sr.resize(p_max_results);
+ int rc = intersect_shape(psq->shape,psq->transform,psq->margin,sr.ptr(),sr.size(),psq->exclude,psq->layer_mask,psq->object_type_mask);
+ Array ret;
+ ret.resize(rc);
+ for(int i=0;i<rc;i++) {
+
+ Dictionary d;
+ d["rid"]=sr[i].rid;
+ d["collider_id"]=sr[i].collider_id;
+ d["collider"]=sr[i].collider;
+ d["shape"]=sr[i].shape;
+ ret[i]=d;
+ }
+
+ return ret;
+}
+
+Array PhysicsDirectSpaceState::_cast_motion(const Ref<PhysicsShapeQueryParameters> &psq,const Vector3& p_motion){
+
+ float closest_safe,closest_unsafe;
+ bool res = cast_motion(psq->shape,psq->transform,p_motion,psq->margin,closest_safe,closest_unsafe,psq->exclude,psq->layer_mask,psq->object_type_mask);
+ if (!res)
+ return Array();
+ Array ret(true);
+ ret.resize(2);
+ ret[0]=closest_safe;
+ ret[1]=closest_unsafe;
+ return ret;
+
+}
+Array PhysicsDirectSpaceState::_collide_shape(const Ref<PhysicsShapeQueryParameters> &psq, int p_max_results){
+
+ Vector<Vector3> ret;
+ ret.resize(p_max_results*2);
+ int rc=0;
+ bool res = collide_shape(psq->shape,psq->transform,psq->margin,ret.ptr(),p_max_results,rc,psq->exclude,psq->layer_mask,psq->object_type_mask);
+ if (!res)
+ return Array();
+ Array r;
+ r.resize(rc*2);
+ for(int i=0;i<rc*2;i++)
+ r[i]=ret[i];
+ return r;
+
+}
+Dictionary PhysicsDirectSpaceState::_get_rest_info(const Ref<PhysicsShapeQueryParameters> &psq){
+
+ ShapeRestInfo sri;
+
+ bool res = rest_info(psq->shape,psq->transform,psq->margin,&sri,psq->exclude,psq->layer_mask,psq->object_type_mask);
+ Dictionary r(true);
+ if (!res)
+ return r;
+
+ r["point"]=sri.point;
+ r["normal"]=sri.normal;
+ r["rid"]=sri.rid;
+ r["collider_id"]=sri.collider_id;
+ r["shape"]=sri.shape;
+ r["linear_velocity"]=sri.linear_velocity;
+
+ return r;
+}
@@ -177,8 +359,22 @@ PhysicsDirectSpaceState::PhysicsDirectSpaceState() {
void PhysicsDirectSpaceState::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("intersect_ray","from","to","exclude","umask"),&PhysicsDirectSpaceState::_intersect_ray,DEFVAL(Array()),DEFVAL(0));
- ObjectTypeDB::bind_method(_MD("intersect_shape:PhysicsShapeQueryResult","shape","xform","result_max","exclude","umask"),&PhysicsDirectSpaceState::_intersect_shape,DEFVAL(Array()),DEFVAL(0));
+// ObjectTypeDB::bind_method(_MD("intersect_ray","from","to","exclude","umask"),&PhysicsDirectSpaceState::_intersect_ray,DEFVAL(Array()),DEFVAL(0));
+// ObjectTypeDB::bind_method(_MD("intersect_shape:PhysicsShapeQueryResult","shape","xform","result_max","exclude","umask"),&PhysicsDirectSpaceState::_intersect_shape,DEFVAL(Array()),DEFVAL(0));
+
+ ObjectTypeDB::bind_method(_MD("intersect_ray:Dictionary","from","to","exclude","layer_mask","type_mask"),&PhysicsDirectSpaceState::_intersect_ray,DEFVAL(Array()),DEFVAL(0x7FFFFFFF),DEFVAL(TYPE_MASK_COLLISION));
+ ObjectTypeDB::bind_method(_MD("intersect_shape","shape:PhysicsShapeQueryParameters","max_results"),&PhysicsDirectSpaceState::_intersect_shape,DEFVAL(32));
+ ObjectTypeDB::bind_method(_MD("cast_motion","shape:PhysicsShapeQueryParameters","motion"),&PhysicsDirectSpaceState::_cast_motion);
+ ObjectTypeDB::bind_method(_MD("collide_shape","shape:PhysicsShapeQueryParameters","max_results"),&PhysicsDirectSpaceState::_collide_shape,DEFVAL(32));
+ ObjectTypeDB::bind_method(_MD("get_rest_info","shape:PhysicsShapeQueryParameters"),&PhysicsDirectSpaceState::_get_rest_info);
+
+
+ BIND_CONSTANT( TYPE_MASK_STATIC_BODY );
+ BIND_CONSTANT( TYPE_MASK_KINEMATIC_BODY );
+ BIND_CONSTANT( TYPE_MASK_RIGID_BODY );
+ BIND_CONSTANT( TYPE_MASK_CHARACTER_BODY );
+ BIND_CONSTANT( TYPE_MASK_AREA );
+ BIND_CONSTANT( TYPE_MASK_COLLISION );
}
@@ -224,7 +420,6 @@ void PhysicsShapeQueryResult::_bind_methods() {
-
///////////////////////////////////////
void PhysicsServer::_bind_methods() {
@@ -251,8 +446,8 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("area_set_space_override_mode","area","mode"),&PhysicsServer::area_set_space_override_mode);
ObjectTypeDB::bind_method(_MD("area_get_space_override_mode","area"),&PhysicsServer::area_get_space_override_mode);
- ObjectTypeDB::bind_method(_MD("area_add_shape","area","shape","transform"),&PhysicsServer::area_set_shape,DEFVAL(Transform()));
- ObjectTypeDB::bind_method(_MD("area_set_shape","area","shape_idx","shape"),&PhysicsServer::area_get_shape);
+ ObjectTypeDB::bind_method(_MD("area_add_shape","area","shape","transform"),&PhysicsServer::area_add_shape,DEFVAL(Transform()));
+ ObjectTypeDB::bind_method(_MD("area_set_shape","area","shape_idx","shape"),&PhysicsServer::area_set_shape);
ObjectTypeDB::bind_method(_MD("area_set_shape_transform","area","shape_idx","transform"),&PhysicsServer::area_set_shape_transform);
ObjectTypeDB::bind_method(_MD("area_get_shape_count","area"),&PhysicsServer::area_get_shape_count);
@@ -263,8 +458,8 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("area_clear_shapes","area"),&PhysicsServer::area_clear_shapes);
- ObjectTypeDB::bind_method(_MD("area_set_param","area","param","value"),&PhysicsServer::area_get_param);
- ObjectTypeDB::bind_method(_MD("area_set_transform","area","transform"),&PhysicsServer::area_get_transform);
+ ObjectTypeDB::bind_method(_MD("area_set_param","area","param","value"),&PhysicsServer::area_set_param);
+ ObjectTypeDB::bind_method(_MD("area_set_transform","area","transform"),&PhysicsServer::area_set_transform);
ObjectTypeDB::bind_method(_MD("area_get_param","area","param"),&PhysicsServer::area_get_param);
ObjectTypeDB::bind_method(_MD("area_get_transform","area"),&PhysicsServer::area_get_transform);
@@ -274,6 +469,9 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("area_set_monitor_callback","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);
+
ObjectTypeDB::bind_method(_MD("body_create","mode","init_sleeping"),&PhysicsServer::body_create,DEFVAL(BODY_MODE_RIGID),DEFVAL(false));
ObjectTypeDB::bind_method(_MD("body_set_space","body","space"),&PhysicsServer::body_set_space);
@@ -307,8 +505,6 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("body_set_param","body","param","value"),&PhysicsServer::body_set_param);
ObjectTypeDB::bind_method(_MD("body_get_param","body","param"),&PhysicsServer::body_get_param);
- ObjectTypeDB::bind_method(_MD("body_static_simulate_motion","body","new_xform"),&PhysicsServer::body_static_simulate_motion);
-
ObjectTypeDB::bind_method(_MD("body_set_state","body","state","value"),&PhysicsServer::body_set_state);
ObjectTypeDB::bind_method(_MD("body_get_state","body","state"),&PhysicsServer::body_get_state);
@@ -316,7 +512,7 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("body_set_axis_velocity","body","axis_velocity"),&PhysicsServer::body_set_axis_velocity);
ObjectTypeDB::bind_method(_MD("body_set_axis_lock","body","axis"),&PhysicsServer::body_set_axis_lock);
- ObjectTypeDB::bind_method(_MD("body_get_axis_lock","body"),&PhysicsServer::body_set_axis_lock);
+ ObjectTypeDB::bind_method(_MD("body_get_axis_lock","body"),&PhysicsServer::body_get_axis_lock);
ObjectTypeDB::bind_method(_MD("body_add_collision_exception","body","excepted_body"),&PhysicsServer::body_add_collision_exception);
ObjectTypeDB::bind_method(_MD("body_remove_collision_exception","body","excepted_body"),&PhysicsServer::body_remove_collision_exception);
@@ -330,7 +526,128 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("body_set_force_integration_callback","body","receiver","method","userdata"),&PhysicsServer::body_set_force_integration_callback,DEFVAL(Variant()));
+ ObjectTypeDB::bind_method(_MD("body_set_ray_pickable","body","enable"),&PhysicsServer::body_set_ray_pickable);
+ ObjectTypeDB::bind_method(_MD("body_is_ray_pickable","body"),&PhysicsServer::body_is_ray_pickable);
+
/* JOINT API */
+
+ BIND_CONSTANT( JOINT_PIN );
+ BIND_CONSTANT( JOINT_HINGE );
+ BIND_CONSTANT( JOINT_SLIDER );
+ BIND_CONSTANT( JOINT_CONE_TWIST );
+ BIND_CONSTANT( JOINT_6DOF );
+
+ ObjectTypeDB::bind_method(_MD("joint_create_pin","body_A","local_A","body_B","local_B"),&PhysicsServer::joint_create_pin);
+ ObjectTypeDB::bind_method(_MD("pin_joint_set_param","joint","param","value"),&PhysicsServer::pin_joint_set_param);
+ ObjectTypeDB::bind_method(_MD("pin_joint_get_param","joint","param"),&PhysicsServer::pin_joint_get_param);
+
+ ObjectTypeDB::bind_method(_MD("pin_joint_set_local_A","joint","local_A"),&PhysicsServer::pin_joint_set_local_A);
+ ObjectTypeDB::bind_method(_MD("pin_joint_get_local_A","joint"),&PhysicsServer::pin_joint_get_local_A);
+
+ ObjectTypeDB::bind_method(_MD("pin_joint_set_local_B","joint","local_B"),&PhysicsServer::pin_joint_set_local_B);
+ ObjectTypeDB::bind_method(_MD("pin_joint_get_local_B","joint"),&PhysicsServer::pin_joint_get_local_B);
+
+ BIND_CONSTANT(PIN_JOINT_BIAS );
+ BIND_CONSTANT(PIN_JOINT_DAMPING );
+ BIND_CONSTANT(PIN_JOINT_IMPULSE_CLAMP );
+
+
+ BIND_CONSTANT(HINGE_JOINT_BIAS);
+ BIND_CONSTANT(HINGE_JOINT_LIMIT_UPPER);
+ BIND_CONSTANT(HINGE_JOINT_LIMIT_LOWER);
+ BIND_CONSTANT(HINGE_JOINT_LIMIT_BIAS);
+ BIND_CONSTANT(HINGE_JOINT_LIMIT_SOFTNESS);
+ BIND_CONSTANT(HINGE_JOINT_LIMIT_RELAXATION);
+ BIND_CONSTANT(HINGE_JOINT_MOTOR_TARGET_VELOCITY);
+ BIND_CONSTANT(HINGE_JOINT_MOTOR_MAX_IMPULSE);
+ BIND_CONSTANT(HINGE_JOINT_FLAG_USE_LIMIT);
+ BIND_CONSTANT(HINGE_JOINT_FLAG_ENABLE_MOTOR);
+
+ ObjectTypeDB::bind_method(_MD("joint_create_hinge","body_A","hinge_A","body_B","hinge_B"),&PhysicsServer::joint_create_hinge);
+
+ ObjectTypeDB::bind_method(_MD("hinge_joint_set_param","joint","param","value"),&PhysicsServer::hinge_joint_set_param);
+ ObjectTypeDB::bind_method(_MD("hinge_joint_get_param","joint","param"),&PhysicsServer::hinge_joint_get_param);
+
+ ObjectTypeDB::bind_method(_MD("hinge_joint_set_flag","joint","flag","enabled"),&PhysicsServer::hinge_joint_set_flag);
+ ObjectTypeDB::bind_method(_MD("hinge_joint_get_flag","joint","flag"),&PhysicsServer::hinge_joint_get_flag);
+
+ ObjectTypeDB::bind_method(_MD("joint_create_slider","body_A","local_ref_A","body_B","local_ref_B"),&PhysicsServer::joint_create_slider);
+
+ ObjectTypeDB::bind_method(_MD("slider_joint_set_param","joint","param","value"),&PhysicsServer::slider_joint_set_param);
+ ObjectTypeDB::bind_method(_MD("slider_joint_get_param","joint","param"),&PhysicsServer::slider_joint_get_param);
+
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_LIMIT_UPPER );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_LIMIT_LOWER );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_LIMIT_DAMPING );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_MOTION_SOFTNESS );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_MOTION_RESTITUTION );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_MOTION_DAMPING );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION );
+ BIND_CONSTANT( SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING );
+
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_LIMIT_UPPER );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_LIMIT_LOWER );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_LIMIT_DAMPING );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_MOTION_DAMPING );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION );
+ BIND_CONSTANT( SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING );
+ BIND_CONSTANT( SLIDER_JOINT_MAX );
+
+
+ ObjectTypeDB::bind_method(_MD("joint_create_cone_twist","body_A","local_ref_A","body_B","local_ref_B"),&PhysicsServer::joint_create_cone_twist);
+
+ ObjectTypeDB::bind_method(_MD("cone_twist_joint_set_param","joint","param","value"),&PhysicsServer::cone_twist_joint_set_param);
+ ObjectTypeDB::bind_method(_MD("cone_twist_joint_get_param","joint","param"),&PhysicsServer::cone_twist_joint_get_param);
+
+ BIND_CONSTANT( CONE_TWIST_JOINT_SWING_SPAN );
+ BIND_CONSTANT( CONE_TWIST_JOINT_TWIST_SPAN );
+ BIND_CONSTANT( CONE_TWIST_JOINT_BIAS );
+ BIND_CONSTANT( CONE_TWIST_JOINT_SOFTNESS );
+ BIND_CONSTANT( CONE_TWIST_JOINT_RELAXATION );
+
+
+ BIND_CONSTANT( G6DOF_JOINT_LINEAR_LOWER_LIMIT );
+ BIND_CONSTANT( G6DOF_JOINT_LINEAR_UPPER_LIMIT );
+ BIND_CONSTANT( G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS );
+ BIND_CONSTANT( G6DOF_JOINT_LINEAR_RESTITUTION );
+ BIND_CONSTANT( G6DOF_JOINT_LINEAR_DAMPING );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_LOWER_LIMIT );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_UPPER_LIMIT );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_DAMPING );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_RESTITUTION );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_FORCE_LIMIT );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_ERP );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY );
+ BIND_CONSTANT( G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT );
+
+
+ BIND_CONSTANT( G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT );
+ BIND_CONSTANT( G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT );
+ BIND_CONSTANT( G6DOF_JOINT_FLAG_ENABLE_MOTOR );
+
+ ObjectTypeDB::bind_method(_MD("joint_get_type","joint"),&PhysicsServer::joint_get_type);
+
+ ObjectTypeDB::bind_method(_MD("joint_set_solver_priority","joint","priority"),&PhysicsServer::joint_set_solver_priority);
+ ObjectTypeDB::bind_method(_MD("joint_get_solver_priority","joint"),&PhysicsServer::joint_get_solver_priority);
+
+ ObjectTypeDB::bind_method(_MD("joint_create_generic_6dof","body_A","local_ref_A","body_B","local_ref_B"),&PhysicsServer::joint_create_generic_6dof);
+
+ ObjectTypeDB::bind_method(_MD("generic_6dof_joint_set_param","joint","axis","param","value"),&PhysicsServer::generic_6dof_joint_set_param);
+ ObjectTypeDB::bind_method(_MD("generic_6dof_joint_get_param","joint","axis","param"),&PhysicsServer::generic_6dof_joint_get_param);
+
+ ObjectTypeDB::bind_method(_MD("generic_6dof_joint_set_flag","joint","axis","flag","enable"),&PhysicsServer::generic_6dof_joint_set_flag);
+ ObjectTypeDB::bind_method(_MD("generic_6dof_joint_get_flag","joint","axis","flag"),&PhysicsServer::generic_6dof_joint_get_flag);
+
+
/*
ObjectTypeDB::bind_method(_MD("joint_set_param","joint","param","value"),&PhysicsServer::joint_set_param);
ObjectTypeDB::bind_method(_MD("joint_get_param","joint","param"),&PhysicsServer::joint_get_param);
@@ -344,7 +661,7 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("joint_get_type","joint"),&PhysicsServer::joint_get_type);
*/
- ObjectTypeDB::bind_method(_MD("free","rid"),&PhysicsServer::free);
+ ObjectTypeDB::bind_method(_MD("free_rid","rid"),&PhysicsServer::free);
ObjectTypeDB::bind_method(_MD("set_active","active"),&PhysicsServer::set_active);
@@ -354,6 +671,8 @@ void PhysicsServer::_bind_methods() {
//ObjectTypeDB::bind_method(_MD("flush_queries"),&PhysicsServer::flush_queries);
+ ObjectTypeDB::bind_method(_MD("get_process_info"),&PhysicsServer::get_process_info);
+
BIND_CONSTANT( SHAPE_PLANE );
BIND_CONSTANT( SHAPE_RAY );
BIND_CONSTANT( SHAPE_SPHERE );
@@ -368,8 +687,10 @@ void PhysicsServer::_bind_methods() {
BIND_CONSTANT( AREA_PARAM_GRAVITY );
BIND_CONSTANT( AREA_PARAM_GRAVITY_VECTOR );
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 );
@@ -384,6 +705,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 );
@@ -406,6 +730,11 @@ void PhysicsServer::_bind_methods() {
BIND_CONSTANT( AREA_BODY_ADDED );
BIND_CONSTANT( AREA_BODY_REMOVED );
+ BIND_CONSTANT( INFO_ACTIVE_OBJECTS );
+ BIND_CONSTANT( INFO_COLLISION_PAIRS );
+ BIND_CONSTANT( INFO_ISLAND_COUNT );
+
+
}
diff --git a/servers/physics_server.h b/servers/physics_server.h
index da51dbc8e1..75584966bb 100644
--- a/servers/physics_server.h
+++ b/servers/physics_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#define PHYSICS_SERVER_H
#include "object.h"
-#include "reference.h"
+#include "resource.h"
class PhysicsDirectSpaceState;
@@ -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
@@ -58,6 +59,7 @@ public:
virtual Transform get_transform() const=0;
virtual void add_force(const Vector3& p_force, const Vector3& p_pos)=0;
+ virtual void apply_impulse(const Vector3& p_pos, const Vector3& p_j)=0;
virtual void set_sleep_state(bool p_enable)=0;
virtual bool is_sleeping() const=0;
@@ -86,13 +88,70 @@ public:
class PhysicsShapeQueryResult;
+class PhysicsShapeQueryParameters : public Reference {
+
+ OBJ_TYPE(PhysicsShapeQueryParameters, Reference);
+friend class PhysicsDirectSpaceState;
+ RID shape;
+ Transform transform;
+ float margin;
+ Set<RID> exclude;
+ uint32_t layer_mask;
+ uint32_t object_type_mask;
+protected:
+ static void _bind_methods();
+public:
+
+
+ void set_shape(const RES& p_shape);
+ void set_shape_rid(const RID& p_shape);
+ RID get_shape_rid() const;
+
+ void set_transform(const Transform& p_transform);
+ Transform get_transform() const;
+
+ void set_margin(float p_margin);
+ float get_margin() const;
+
+ void set_layer_mask(int p_layer_mask);
+ int get_layer_mask() const;
+
+ void set_object_type_mask(int p_object_type_mask);
+ int get_object_type_mask() const;
+
+ void set_exclude(const Vector<RID>& p_exclude);
+ Vector<RID> get_exclude() const;
+
+ PhysicsShapeQueryParameters();
+
+};
+
+
class PhysicsDirectSpaceState : public Object {
OBJ_TYPE( PhysicsDirectSpaceState, Object );
- Variant _intersect_ray(const Vector3& p_from, const Vector3& p_to,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_user_mask=0);
- Variant _intersect_shape(const RID& p_shape, const Transform& p_xform,int p_result_max=64,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_user_mask=0);
+// Variant _intersect_ray(const Vector3& p_from, const Vector3& p_to,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_collision_mask=0);
+// Variant _intersect_shape(const RID& p_shape, const Transform& p_xform,int p_result_max=64,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_collision_mask=0);
+public:
+
+ enum ObjectTypeMask {
+ TYPE_MASK_STATIC_BODY=1<<0,
+ TYPE_MASK_KINEMATIC_BODY=1<<1,
+ TYPE_MASK_RIGID_BODY=1<<2,
+ TYPE_MASK_CHARACTER_BODY=1<<3,
+ TYPE_MASK_AREA=1<<4,
+ TYPE_MASK_COLLISION=TYPE_MASK_STATIC_BODY|TYPE_MASK_CHARACTER_BODY|TYPE_MASK_KINEMATIC_BODY|TYPE_MASK_RIGID_BODY
+ };
+
+
+private:
+ Dictionary _intersect_ray(const Vector3& p_from, const Vector3& p_to,const Vector<RID>& p_exclude=Vector<RID>(),uint32_t p_layers=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
+ Array _intersect_shape(const Ref<PhysicsShapeQueryParameters> &p_shape_query,int p_max_results=32);
+ Array _cast_motion(const Ref<PhysicsShapeQueryParameters> &p_shape_query,const Vector3& p_motion);
+ Array _collide_shape(const Ref<PhysicsShapeQueryParameters> &p_shape_query,int p_max_results=32);
+ Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters> &p_shape_query);
protected:
@@ -100,6 +159,7 @@ protected:
public:
+
struct RayResult {
Vector3 position;
@@ -110,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_user_mask=0)=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)=0;
struct ShapeResult {
@@ -121,7 +181,25 @@ public:
};
- virtual int intersect_shape(const RID& p_shape, const Transform& p_xform,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0)=0;
+ 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)=0;
+
+ struct ShapeRestInfo {
+
+ Vector3 point;
+ Vector3 normal;
+ RID rid;
+ ObjectID collider_id;
+ int shape;
+ Vector3 linear_velocity; //velocity at contact point
+
+ };
+
+ 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)=0;
+
+ 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)=0;
+
+ 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)=0;
+
PhysicsDirectSpaceState();
};
@@ -155,6 +233,7 @@ class PhysicsServer : public Object {
static PhysicsServer * singleton;
+
protected:
static void _bind_methods();
@@ -207,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
@@ -220,8 +302,10 @@ public:
AREA_PARAM_GRAVITY,
AREA_PARAM_GRAVITY_VECTOR,
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
};
@@ -260,7 +344,13 @@ public:
virtual Variant area_get_param(RID p_parea,AreaParameter p_param) const=0;
virtual Transform area_get_transform(RID p_area) const=0;
+ virtual void area_set_monitorable(RID p_area,bool p_monitorable)=0;
+
virtual void area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method)=0;
+ virtual void area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method)=0;
+
+ virtual void area_set_ray_pickable(RID p_area,bool p_enable)=0;
+ virtual bool area_is_ray_pickable(RID p_area) const=0;
/* BODY API */
@@ -302,6 +392,9 @@ public:
virtual void body_set_enable_continuous_collision_detection(RID p_body,bool p_enable)=0;
virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const=0;
+ virtual void body_set_layer_mask(RID p_body, uint32_t p_mask)=0;
+ virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const=0;
+
virtual void body_set_user_flags(RID p_body, uint32_t p_flags)=0;
virtual uint32_t body_get_user_flags(RID p_body, uint32_t p_flags) const=0;
@@ -310,14 +403,15 @@ 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,
};
virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value)=0;
virtual float body_get_param(RID p_body, BodyParameter p_param) const=0;
- //advanced simulation
- virtual void body_static_simulate_motion(RID p_body,const Transform& p_new_transform)=0;
//state
enum BodyState {
@@ -325,7 +419,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;
@@ -368,7 +462,161 @@ public:
virtual void body_set_force_integration_callback(RID p_body,Object *p_receiver,const StringName& p_method,const Variant& p_udata=Variant())=0;
+ virtual void body_set_ray_pickable(RID p_body,bool p_enable)=0;
+ virtual bool body_is_ray_pickable(RID p_body) const=0;
+
+
/* JOINT API */
+
+ enum JointType {
+
+ JOINT_PIN,
+ JOINT_HINGE,
+ JOINT_SLIDER,
+ JOINT_CONE_TWIST,
+ JOINT_6DOF
+
+ };
+
+ virtual JointType joint_get_type(RID p_joint) const=0;
+
+ virtual void joint_set_solver_priority(RID p_joint,int p_priority)=0;
+ virtual int joint_get_solver_priority(RID p_joint) const=0;
+
+
+ virtual RID joint_create_pin(RID p_body_A,const Vector3& p_local_A,RID p_body_B,const Vector3& p_local_B)=0;
+
+ enum PinJointParam {
+ PIN_JOINT_BIAS,
+ PIN_JOINT_DAMPING,
+ PIN_JOINT_IMPULSE_CLAMP
+ };
+
+ virtual void pin_joint_set_param(RID p_joint,PinJointParam p_param, float p_value)=0;
+ virtual float pin_joint_get_param(RID p_joint,PinJointParam p_param) const=0;
+
+ virtual void pin_joint_set_local_A(RID p_joint, const Vector3& p_A)=0;
+ virtual Vector3 pin_joint_get_local_A(RID p_joint) const=0;
+
+ virtual void pin_joint_set_local_B(RID p_joint, const Vector3& p_B)=0;
+ virtual Vector3 pin_joint_get_local_B(RID p_joint) const=0;
+
+ enum HingeJointParam {
+
+ HINGE_JOINT_BIAS,
+ HINGE_JOINT_LIMIT_UPPER,
+ HINGE_JOINT_LIMIT_LOWER,
+ HINGE_JOINT_LIMIT_BIAS,
+ HINGE_JOINT_LIMIT_SOFTNESS,
+ HINGE_JOINT_LIMIT_RELAXATION,
+ HINGE_JOINT_MOTOR_TARGET_VELOCITY,
+ HINGE_JOINT_MOTOR_MAX_IMPULSE,
+ HINGE_JOINT_MAX
+ };
+
+ enum HingeJointFlag {
+ HINGE_JOINT_FLAG_USE_LIMIT,
+ HINGE_JOINT_FLAG_ENABLE_MOTOR,
+ HINGE_JOINT_FLAG_MAX
+ };
+
+ virtual RID joint_create_hinge(RID p_body_A,const Transform& p_hinge_A,RID p_body_B,const Transform& p_hinge_B)=0;
+ virtual RID joint_create_hinge_simple(RID p_body_A,const Vector3& p_pivot_A,const Vector3& p_axis_A,RID p_body_B,const Vector3& p_pivot_B,const Vector3& p_axis_B)=0;
+
+
+ virtual void hinge_joint_set_param(RID p_joint,HingeJointParam p_param, float p_value)=0;
+ virtual float hinge_joint_get_param(RID p_joint,HingeJointParam p_param) const=0;
+
+ virtual void hinge_joint_set_flag(RID p_joint,HingeJointFlag p_flag, bool p_value)=0;
+ virtual bool hinge_joint_get_flag(RID p_joint,HingeJointFlag p_flag) const=0;
+
+ enum SliderJointParam {
+ SLIDER_JOINT_LINEAR_LIMIT_UPPER,
+ SLIDER_JOINT_LINEAR_LIMIT_LOWER,
+ SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS,
+ SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION,
+ SLIDER_JOINT_LINEAR_LIMIT_DAMPING,
+ SLIDER_JOINT_LINEAR_MOTION_SOFTNESS,
+ SLIDER_JOINT_LINEAR_MOTION_RESTITUTION,
+ SLIDER_JOINT_LINEAR_MOTION_DAMPING,
+ SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS,
+ SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION,
+ SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING,
+
+ SLIDER_JOINT_ANGULAR_LIMIT_UPPER,
+ SLIDER_JOINT_ANGULAR_LIMIT_LOWER,
+ SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS,
+ SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION,
+ SLIDER_JOINT_ANGULAR_LIMIT_DAMPING,
+ SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS,
+ SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION,
+ SLIDER_JOINT_ANGULAR_MOTION_DAMPING,
+ SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS,
+ SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION,
+ SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING,
+ SLIDER_JOINT_MAX
+
+
+ };
+
+ virtual RID joint_create_slider(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B)=0; //reference frame is A
+
+ virtual void slider_joint_set_param(RID p_joint,SliderJointParam p_param, float p_value)=0;
+ virtual float slider_joint_get_param(RID p_joint,SliderJointParam p_param) const=0;
+
+ enum ConeTwistJointParam {
+ CONE_TWIST_JOINT_SWING_SPAN,
+ CONE_TWIST_JOINT_TWIST_SPAN,
+ CONE_TWIST_JOINT_BIAS,
+ CONE_TWIST_JOINT_SOFTNESS,
+ CONE_TWIST_JOINT_RELAXATION,
+ CONE_TWIST_MAX
+ };
+
+
+ virtual RID joint_create_cone_twist(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B)=0; //reference frame is A
+
+ virtual void cone_twist_joint_set_param(RID p_joint,ConeTwistJointParam p_param, float p_value)=0;
+ virtual float cone_twist_joint_get_param(RID p_joint,ConeTwistJointParam p_param) const=0;
+
+
+ enum G6DOFJointAxisParam {
+ G6DOF_JOINT_LINEAR_LOWER_LIMIT,
+ G6DOF_JOINT_LINEAR_UPPER_LIMIT,
+ G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
+ G6DOF_JOINT_LINEAR_RESTITUTION,
+ G6DOF_JOINT_LINEAR_DAMPING,
+ G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
+ G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
+ G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
+ G6DOF_JOINT_ANGULAR_DAMPING,
+ G6DOF_JOINT_ANGULAR_RESTITUTION,
+ G6DOF_JOINT_ANGULAR_FORCE_LIMIT,
+ G6DOF_JOINT_ANGULAR_ERP,
+ G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY,
+ G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT,
+ G6DOF_JOINT_MAX
+ };
+
+ enum G6DOFJointAxisFlag {
+
+ G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
+ G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
+ G6DOF_JOINT_FLAG_ENABLE_MOTOR,
+ G6DOF_JOINT_FLAG_MAX
+ };
+
+
+
+ virtual RID joint_create_generic_6dof(RID p_body_A,const Transform& p_local_frame_A,RID p_body_B,const Transform& p_local_frame_B)=0; //reference frame is A
+
+ virtual void generic_6dof_joint_set_param(RID p_joint,Vector3::Axis,G6DOFJointAxisParam p_param, float p_value)=0;
+ virtual float generic_6dof_joint_get_param(RID p_joint,Vector3::Axis,G6DOFJointAxisParam p_param)=0;
+
+ virtual void generic_6dof_joint_set_flag(RID p_joint,Vector3::Axis,G6DOFJointAxisFlag p_flag, bool p_enable)=0;
+ virtual bool generic_6dof_joint_get_flag(RID p_joint,Vector3::Axis,G6DOFJointAxisFlag p_flag)=0;
+
+
#if 0
enum JointType {
@@ -419,6 +667,15 @@ public:
virtual void flush_queries()=0;
virtual void finish()=0;
+ enum ProcessInfo {
+
+ INFO_ACTIVE_OBJECTS,
+ INFO_COLLISION_PAIRS,
+ INFO_ISLAND_COUNT
+ };
+
+ virtual int get_process_info(ProcessInfo p_info)=0;
+
PhysicsServer();
~PhysicsServer();
};
@@ -431,10 +688,16 @@ VARIANT_ENUM_CAST( PhysicsServer::BodyMode );
VARIANT_ENUM_CAST( PhysicsServer::BodyParameter );
VARIANT_ENUM_CAST( PhysicsServer::BodyState );
VARIANT_ENUM_CAST( PhysicsServer::BodyAxisLock );
-//VARIANT_ENUM_CAST( PhysicsServer::JointParam );
-//VARIANT_ENUM_CAST( PhysicsServer::JointType );
-//VARIANT_ENUM_CAST( PhysicsServer::DampedStringParam );
+VARIANT_ENUM_CAST( PhysicsServer::PinJointParam );
+VARIANT_ENUM_CAST( PhysicsServer::JointType );
+VARIANT_ENUM_CAST( PhysicsServer::HingeJointParam );
+VARIANT_ENUM_CAST( PhysicsServer::HingeJointFlag );
+VARIANT_ENUM_CAST( PhysicsServer::SliderJointParam );
+VARIANT_ENUM_CAST( PhysicsServer::ConeTwistJointParam );
+VARIANT_ENUM_CAST( PhysicsServer::G6DOFJointAxisParam );
+VARIANT_ENUM_CAST( PhysicsServer::G6DOFJointAxisFlag);
//VARIANT_ENUM_CAST( PhysicsServer::ObjectType );
VARIANT_ENUM_CAST( PhysicsServer::AreaBodyStatus );
+VARIANT_ENUM_CAST( PhysicsServer::ProcessInfo );
#endif
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 638156d813..2af2a79d07 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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() {
@@ -55,11 +74,15 @@ void register_server_types() {
ObjectTypeDB::register_virtual_type<Physics2DDirectBodyState>();
ObjectTypeDB::register_virtual_type<Physics2DDirectSpaceState>();
ObjectTypeDB::register_virtual_type<Physics2DShapeQueryResult>();
+ ObjectTypeDB::register_type<Physics2DTestMotionResult>();
+ ObjectTypeDB::register_type<Physics2DShapeQueryParameters>();
+ ObjectTypeDB::register_type<PhysicsShapeQueryParameters>();
ObjectTypeDB::register_virtual_type<PhysicsDirectBodyState>();
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 b0a01fc0a5..d3d6c6b566 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h
new file mode 100644
index 0000000000..cbb75129d0
--- /dev/null
+++ b/servers/server_wrap_mt_common.h
@@ -0,0 +1,700 @@
+
+#define FUNC0R(m_r,m_type)\
+ virtual m_r m_type() { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type();\
+ }\
+ }
+
+
+#define FUNCRID(m_type)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create() { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create();\
+ }\
+ }
+
+#define FUNC1RID(m_type,m_arg1)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1);\
+ }\
+ }
+
+#define FUNC2RID(m_type,m_arg1,m_arg2)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1,m_arg2 p2) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1,p2);\
+ }\
+ }
+
+#define FUNC3RID(m_type,m_arg1,m_arg2,m_arg3)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1,p2,p3);\
+ }\
+ }
+
+
+#define FUNC4RID(m_type,m_arg1,m_arg2,m_arg3,m_arg4)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3,m_arg4 p4) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,p4,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1,p2,p3,p4);\
+ }\
+ }
+
+
+#define FUNC5RID(m_type,m_arg1,m_arg2,m_arg3,m_arg4,m_arg5)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3,m_arg4 p4,m_arg5 p5) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,p4,p5,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1,p2,p3,p4,p5);\
+ }\
+ }
+
+#define FUNC0RC(m_r,m_type)\
+ virtual m_r m_type() const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type();\
+ }\
+ }
+
+
+#define FUNC0(m_type)\
+ virtual void m_type() { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type);\
+ } else {\
+ server_name->m_type();\
+ }\
+ }
+
+#define FUNC0C(m_type)\
+ virtual void m_type() const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type);\
+ } else {\
+ server_name->m_type();\
+ }\
+ }
+
+
+#define FUNC0S(m_type)\
+ virtual void m_type() { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type);\
+ } else {\
+ server_name->m_type();\
+ }\
+ }
+
+#define FUNC0SC(m_type)\
+ virtual void m_type() const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type);\
+ } else {\
+ server_name->m_type();\
+ }\
+ }
+
+
+///////////////////////////////////////////////
+
+
+#define FUNC1R(m_r,m_type,m_arg1)\
+ virtual m_r m_type(m_arg1 p1) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1);\
+ }\
+ }
+
+#define FUNC1RC(m_r,m_type,m_arg1)\
+ virtual m_r m_type(m_arg1 p1) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1);\
+ }\
+ }
+
+
+#define FUNC1S(m_type,m_arg1)\
+ virtual void m_type(m_arg1 p1) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1);\
+ } else {\
+ server_name->m_type(p1);\
+ }\
+ }
+
+#define FUNC1SC(m_type,m_arg1)\
+ virtual void m_type(m_arg1 p1) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1);\
+ } else {\
+ server_name->m_type(p1);\
+ }\
+ }
+
+
+#define FUNC1(m_type,m_arg1)\
+ virtual void m_type(m_arg1 p1) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1);\
+ } else {\
+ server_name->m_type(p1);\
+ }\
+ }
+
+#define FUNC1C(m_type,m_arg1)\
+ virtual void m_type(m_arg1 p1) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1);\
+ } else {\
+ server_name->m_type(p1);\
+ }\
+ }
+
+
+
+
+#define FUNC2R(m_r,m_type,m_arg1, m_arg2)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2);\
+ }\
+ }
+
+#define FUNC2RC(m_r,m_type,m_arg1, m_arg2)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2);\
+ }\
+ }
+
+
+#define FUNC2S(m_type,m_arg1, m_arg2)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2);\
+ } else {\
+ server_name->m_type(p1, p2);\
+ }\
+ }
+
+#define FUNC2SC(m_type,m_arg1, m_arg2)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2);\
+ } else {\
+ server_name->m_type(p1, p2);\
+ }\
+ }
+
+
+#define FUNC2(m_type,m_arg1, m_arg2)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2);\
+ } else {\
+ server_name->m_type(p1, p2);\
+ }\
+ }
+
+#define FUNC2C(m_type,m_arg1, m_arg2)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2);\
+ } else {\
+ server_name->m_type(p1, p2);\
+ }\
+ }
+
+
+
+
+#define FUNC3R(m_r,m_type,m_arg1, m_arg2, m_arg3)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+#define FUNC3RC(m_r,m_type,m_arg1, m_arg2, m_arg3)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3,&ret);\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+
+#define FUNC3S(m_type,m_arg1, m_arg2, m_arg3)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3);\
+ } else {\
+ server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+#define FUNC3SC(m_type,m_arg1, m_arg2, m_arg3)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3);\
+ } else {\
+ server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+
+#define FUNC3(m_type,m_arg1, m_arg2, m_arg3)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3);\
+ } else {\
+ server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+#define FUNC3C(m_type,m_arg1, m_arg2, m_arg3)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3);\
+ } else {\
+ server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+
+
+
+#define FUNC4R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+#define FUNC4RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+
+#define FUNC4S(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+#define FUNC4SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+
+#define FUNC4(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+#define FUNC4C(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+
+
+
+#define FUNC5R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+#define FUNC5RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+
+#define FUNC5S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+#define FUNC5SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+
+#define FUNC5(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+#define FUNC5C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+
+
+
+#define FUNC6R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+#define FUNC6RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6,&ret);\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+
+#define FUNC6S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+#define FUNC6SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+
+#define FUNC6(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+#define FUNC6C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+
+
+
+#define FUNC7R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+#define FUNC7RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+
+#define FUNC7S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+#define FUNC7SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+
+#define FUNC7(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+#define FUNC7C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
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 7ec29d32cb..d00deb3912 100644
--- a/servers/spatial_sound/spatial_sound_server_sw.cpp
+++ b/servers/spatial_sound/spatial_sound_server_sw.cpp
@@ -879,10 +879,13 @@ void SpatialSoundServerSW::update(float p_delta) {
float volume_attenuation = 0.0;
float air_absorption_hf_cutoff = 0.0;
float air_absorption = 0.0;
- float pitch_scale=0.0;
+ float pitch_scale=1.0;
Vector3 panning;
+ //print_line("listeners: "+itos(space->listeners.size()));
+
+
for(Set<RID>::Element *L=space->listeners.front();L;L=L->next()) {
Listener *listener=listener_owner.get(L->get());
@@ -899,9 +902,11 @@ void SpatialSoundServerSW::update(float p_delta) {
float attenuation_exp=source->params[SOURCE_PARAM_ATTENUATION_DISTANCE_EXP];
float attenuation=1;
+ //print_line("DIST MIN: "+rtos(distance_min));
+ //print_line("DIST MAX: "+rtos(distance_max));
if (distance_max>0) {
distance = CLAMP(distance,distance_min,distance_max);
- attenuation = Math::pow(1.0 - ((distance - distance_min)/distance_max),CLAMP(attenuation_exp,0.001,16));
+ attenuation = Math::pow(1.0 - ((distance - distance_min)/(distance_max-distance_min)),CLAMP(attenuation_exp,0.001,16));
}
float hf_attenuation_cutoff = room->params[ROOM_PARAM_ATTENUATION_HF_CUTOFF];
@@ -945,7 +950,7 @@ void SpatialSoundServerSW::update(float p_delta) {
air_absorption+=weight*absorption;
air_absorption_hf_cutoff+=weight*hf_attenuation_cutoff;
panning+=vpanning*weight;
- pitch_scale+=pscale*weight;
+ //pitch_scale+=pscale*weight;
}
@@ -991,8 +996,8 @@ void SpatialSoundServerSW::update(float p_delta) {
reverb_send*=volume_scale;
int mix_rate = v.sample_mix_rate*v.pitch_scale*pitch_scale*source->params[SOURCE_PARAM_PITCH_SCALE];
- if (mix_rate<=0) {
+ if (mix_rate<=0) {
ERR_PRINT("Invalid mix rate for voice (0) check for invalid pitch_scale param.");
to_disable.push_back(ActiveVoice(source,voice)); // oh well..
continue; //invalid mix rate, disabling
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 e3c8aba758..439149b1a2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -904,7 +904,7 @@ void SpatialSound2DServerSW::update(float p_delta) {
if (distance_max>0) {
distance = CLAMP(distance,distance_min,distance_max);
- attenuation = Math::pow(1.0 - ((distance - distance_min)/distance_max),CLAMP(attenuation_exp,0.001,16));
+ attenuation = Math::pow(1.0 - ((distance - distance_min)/(distance_max-distance_min)),CLAMP(attenuation_exp,0.001,16));
}
float hf_attenuation_cutoff = room->params[ROOM_PARAM_ATTENUATION_HF_CUTOFF];
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 6e7ac2157d..ed305d25de 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/spatial_sound_2d_server.cpp b/servers/spatial_sound_2d_server.cpp
index d27803559e..574c3d761f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/spatial_sound_2d_server.h b/servers/spatial_sound_2d_server.h
index e3ed4ce00c..9917b36be1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/spatial_sound_server.cpp b/servers/spatial_sound_server.cpp
index 1fcfb0008b..f5f5925483 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/spatial_sound_server.h b/servers/spatial_sound_server.h
index ff4342a42b..1cc323b370 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 49a68f8e80..aa9b737459 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/visual/particle_system_sw.h b/servers/visual/particle_system_sw.h
index 2b18c7f4e3..b7ff5e9bb5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/visual/rasterizer.cpp b/servers/visual/rasterizer.cpp
index e160b4dccc..5984e6e35c 100644
--- a/servers/visual/rasterizer.cpp
+++ b/servers/visual/rasterizer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -79,7 +79,7 @@ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) {
if (texcoords_used&(1<<VS::FIXED_MATERIAL_TEXCOORD_UV_TRANSFORM)) {
code+="uniform mat4 fmp_uv_xform;\n";
- code+="vec2 uv_xform = fmp_uv_xform * UV;\n";
+ code+="vec2 uv_xform = (fmp_uv_xform * vec4(UV,0,1)).xy;\n";
}
/* HANDLE NORMAL MAPPING */
@@ -91,13 +91,19 @@ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) {
scode+="uniform float fmp_normal;\n";
scode+="uniform texture fmp_normal_tex;\n";
String uv_str;
- if ((p_key.texcoord_mask>>(VS::FIXED_MATERIAL_PARAM_NORMAL*2))&0x3==VS::FIXED_MATERIAL_TEXCOORD_SPHERE) {
+ if (((p_key.texcoord_mask>>(VS::FIXED_MATERIAL_PARAM_NORMAL*2))&0x3)==VS::FIXED_MATERIAL_TEXCOORD_SPHERE) {
uv_str="uv"; //sorry not supported
} else {
uv_str=_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_NORMAL);
}
- scode+="vec3 normal=tex( fmp_normal_tex,"+uv_str+").xyz * vec3(2.0,2.0,1.0) - vec3(1.0,1.0,0.0);\n";
- scode+="NORMAL = mix( NORMAL,mat3(TANGENT,BINORMAL,NORMAL) * normal, fmp_normal);\n";
+ if (p_key.use_xy_normalmap) {
+ scode+="vec2 ywnormal=tex( fmp_normal_tex,"+uv_str+").wy * vec2(2.0,2.0) - vec2(1.0,1.0);\n";
+ scode+="NORMALMAP=vec3(ywnormal,sqrt(1 - (ywnormal.x * ywnormal.x) - (ywnormal.y * ywnormal.y) ));\n";
+ } else {
+ scode+="NORMALMAP=tex( fmp_normal_tex,"+uv_str+").xyz * vec3(2.0,2.0,1.0) - vec3(1.0,1.0,0.0);\n";
+ }
+ scode+="NORMALMAP_DEPTH=fmp_normal;\n";
+
code+=scode;
}
@@ -323,6 +329,7 @@ void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags
case VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY: fm.use_color_array=p_enabled; break;
case VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE: fm.use_pointsize=p_enabled; break;
case VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA: fm.discard_alpha=p_enabled; break;
+ case VS::FIXED_MATERIAL_FLAG_USE_XY_NORMALMAP: fm.use_xy_normalmap=p_enabled; break;
}
if (!fm.dirty_list.in_list())
@@ -341,6 +348,8 @@ bool Rasterizer::fixed_material_get_flag(RID p_material, VS::FixedMaterialFlags
case VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY: return fm.use_color_array;; break;
case VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE: return fm.use_pointsize;; break;
case VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA: return fm.discard_alpha;; break;
+ case VS::FIXED_MATERIAL_FLAG_USE_XY_NORMALMAP: return fm.use_xy_normalmap;; break;
+
}
@@ -355,12 +364,13 @@ RID Rasterizer::fixed_material_create() {
FixedMaterial &fm=*fixed_materials[mat];
fm.self=mat;
fm.get_key();
+ material_set_flag(mat,VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB,true);
for(int i=0;i<VS::FIXED_MATERIAL_PARAM_MAX;i++) {
material_set_param(mat,_fixed_material_param_names[i],fm.param[i]); //must be there
}
fixed_material_dirty_list.add(&fm.dirty_list);
- //print_line("FMC: "+itos(mat.get_id()));
+ //print_line("FMC: "+itos(mat.get_id()));
return mat;
}
@@ -558,8 +568,9 @@ void Rasterizer::_update_fixed_materials() {
}
material_set_param(fm.self,_fixed_material_uv_xform_name,fm.uv_xform);
- if (fm.use_pointsize)
+ if (fm.use_pointsize) {
material_set_param(fm.self,_fixed_material_point_size_name,fm.point_size);
+ }
}
fixed_material_dirty_list.remove(fixed_material_dirty_list.first());
@@ -610,6 +621,10 @@ Rasterizer::Rasterizer() {
_fixed_material_uv_xform_name="fmp_uv_xform";
_fixed_material_point_size_name="fmp_point_size";
+ draw_viewport_func=NULL;
+
+ ERR_FAIL_COND( sizeof(FixedMaterialShaderKey)!=4);
+
}
RID Rasterizer::create_overdraw_debug_material() {
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 2b02a81a44..d94067961f 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,6 +40,9 @@
class Rasterizer {
protected:
+
+ typedef void (*CanvasItemDrawViewportFunc)(VisualServer*owner,void*ud,const Rect2& p_rect);
+
RID create_default_material();
RID create_overdraw_debug_material();
@@ -56,6 +59,7 @@ protected:
bool use_color_array:1;
bool use_pointsize:1;
bool discard_alpha:1;
+ bool use_xy_normalmap:1;
bool valid:1;
};
@@ -83,6 +87,7 @@ protected:
bool use_color_array;
bool discard_alpha;
bool use_pointsize;
+ bool use_xy_normalmap;
float point_size;
Transform uv_xform;
VS::FixedMaterialLightShader light_shader;
@@ -102,6 +107,7 @@ protected:
k.use_alpha=use_alpha;
k.use_color_array=use_color_array;
k.use_pointsize=use_pointsize;
+ k.use_xy_normalmap=use_xy_normalmap;
k.discard_alpha=discard_alpha;
k.light_shader=light_shader;
k.valid=true;
@@ -123,6 +129,7 @@ protected:
use_color_array=false;
use_pointsize=false;
discard_alpha=false;
+ use_xy_normalmap=false;
point_size=1.0;
light_shader=VS::FIXED_MATERIAL_LIGHT_SHADER_LAMBERT;
for(int i=0;i<VS::FIXED_MATERIAL_PARAM_MAX;i++) {
@@ -185,6 +192,10 @@ public:
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;
@@ -199,6 +210,11 @@ public:
virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const=0;
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture)=0;
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const=0;
+
+ virtual Variant shader_get_default_param(RID p_shader, const StringName& p_name)=0;
+
/* COMMON MATERIAL API */
virtual RID material_create()=0;
@@ -275,7 +291,7 @@ public:
virtual void mesh_remove_surface(RID p_mesh,int p_index)=0;
virtual int mesh_get_surface_count(RID p_mesh) const=0;
- virtual AABB mesh_get_aabb(RID p_mesh) const=0;
+ virtual AABB mesh_get_aabb(RID p_mesh,RID p_skeleton=RID()) const=0;
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;
@@ -489,7 +505,7 @@ public:
virtual void begin_scene(RID p_viewport_data,RID p_env,VS::ScenarioDebugMode p_debug)=0;
virtual void begin_shadow_map( RID p_light_instance, int p_shadow_pass )=0;
- virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection)=0;
+ virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection,bool p_ortho_hint)=0;
virtual void add_light( RID p_light_instance )=0; ///< all "add_light" calls happen before add_geometry calls
@@ -499,6 +515,7 @@ public:
VS::BakedLightMode mode;
RID octree_texture;
+ RID light_texture;
float color_multiplier; //used for both lightmaps and octree
Transform octree_transform;
Map<int,RID> lightmaps;
@@ -507,8 +524,10 @@ public:
float octree_lattice_size;
float octree_lattice_divide;
float texture_multiplier;
+ float lightmap_multiplier;
int octree_steps;
Vector2 octree_tex_pixel_size;
+ Vector2 light_tex_pixel_size;
};
struct InstanceData {
@@ -516,10 +535,12 @@ public:
Transform transform;
RID skeleton;
RID material_override;
+ RID sampled_light;
Vector<RID> light_instances;
Vector<float> morph_values;
BakedLightData *baked_light;
Transform *baked_light_octree_xform;
+ int baked_lightmap_id;
bool mirror :8;
bool depth_scale :8;
bool billboard :8;
@@ -546,9 +567,370 @@ public:
CANVAS_RECT_REGION=1,
CANVAS_RECT_TILE=2,
CANVAS_RECT_FLIP_H=4,
- CANVAS_RECT_FLIP_V=8
+ CANVAS_RECT_FLIP_V=8,
+ CANVAS_RECT_TRANSPOSE=16
};
-
+
+
+ struct CanvasLight {
+
+
+
+ bool enabled;
+ Color color;
+ Matrix32 xform;
+ float height;
+ float energy;
+ float scale;
+ int z_min;
+ int z_max;
+ int layer_min;
+ int layer_max;
+ int item_mask;
+ int item_shadow_mask;
+ VS::CanvasLightMode mode;
+ RID texture;
+ Vector2 texture_offset;
+ RID canvas;
+ RID shadow_buffer;
+ int shadow_buffer_size;
+ float shadow_esm_mult;
+ Color shadow_color;
+
+
+ void *texture_cache; // implementation dependent
+ Rect2 rect_cache;
+ Matrix32 xform_cache;
+ float radius_cache; //used for shadow far plane
+ CameraMatrix shadow_matrix_cache;
+
+ Matrix32 light_shader_xform;
+ Vector2 light_shader_pos;
+
+ 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;
+ layer_min=0;
+ layer_max=0;
+ item_mask=1;
+ scale=1.0;
+ energy=1.0;
+ item_shadow_mask=-1;
+ 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;
+
+ }
+ };
+
+ struct CanvasItem;
+
+ struct CanvasItemMaterial {
+
+ RID shader;
+ Map<StringName,Variant> shader_param;
+ uint32_t shader_version;
+ Set<CanvasItem*> owners;
+ VS::CanvasItemShadingMode shading_mode;
+
+ CanvasItemMaterial() {shading_mode=VS::CANVAS_ITEM_SHADING_NORMAL; shader_version=0; }
+ };
+
+ struct CanvasItem {
+
+ struct Command {
+
+ enum Type {
+
+ TYPE_LINE,
+ TYPE_RECT,
+ TYPE_STYLE,
+ TYPE_PRIMITIVE,
+ TYPE_POLYGON,
+ TYPE_POLYGON_PTR,
+ TYPE_CIRCLE,
+ TYPE_TRANSFORM,
+ TYPE_BLEND_MODE,
+ TYPE_CLIP_IGNORE,
+ };
+
+ Type type;
+ virtual ~Command(){}
+ };
+
+ struct CommandLine : public Command {
+
+ Point2 from,to;
+ Color color;
+ float width;
+ CommandLine() { type = TYPE_LINE; }
+ };
+
+ struct CommandRect : public Command {
+
+ Rect2 rect;
+ RID texture;
+ Color modulate;
+ Rect2 source;
+ uint8_t flags;
+
+ CommandRect() { flags=0; type = TYPE_RECT; }
+ };
+
+ struct CommandStyle : public Command {
+
+ Rect2 rect;
+ RID texture;
+ float margin[4];
+ bool draw_center;
+ Color color;
+ CommandStyle() { draw_center=true; type = TYPE_STYLE; }
+ };
+
+ struct CommandPrimitive : public Command {
+
+ Vector<Point2> points;
+ Vector<Point2> uvs;
+ Vector<Color> colors;
+ RID texture;
+ float width;
+
+ CommandPrimitive() { type = TYPE_PRIMITIVE; width=1;}
+ };
+
+ struct CommandPolygon : public Command {
+
+ Vector<int> indices;
+ Vector<Point2> points;
+ Vector<Point2> uvs;
+ Vector<Color> colors;
+ RID texture;
+ int count;
+
+ CommandPolygon() { type = TYPE_POLYGON; count = 0; }
+ };
+
+ struct CommandPolygonPtr : public Command {
+
+ const int* indices;
+ const Point2* points;
+ const Point2* uvs;
+ const Color* colors;
+ RID texture;
+ int count;
+
+ CommandPolygonPtr() { type = TYPE_POLYGON_PTR; count = 0; }
+ };
+
+ struct CommandCircle : public Command {
+
+ Point2 pos;
+ float radius;
+ Color color;
+ CommandCircle() { type = TYPE_CIRCLE; }
+ };
+
+ struct CommandTransform : public Command {
+
+ Matrix32 xform;
+ CommandTransform() { type = TYPE_TRANSFORM; }
+ };
+
+ struct CommandBlendMode : public Command {
+
+ VS::MaterialBlendMode blend_mode;
+ CommandBlendMode() { type = TYPE_BLEND_MODE; blend_mode = VS::MATERIAL_BLEND_MODE_MIX; }
+ };
+ struct CommandClipIgnore : public Command {
+
+ bool ignore;
+ CommandClipIgnore() { type = TYPE_CLIP_IGNORE; ignore=false; }
+ };
+
+
+ struct ViewportRender {
+ VisualServer*owner;
+ void* udata;
+ Rect2 rect;
+ };
+
+ Matrix32 xform;
+ bool clip;
+ bool visible;
+ bool ontop;
+ VS::MaterialBlendMode blend_mode;
+ int light_mask;
+ Vector<Command*> commands;
+ mutable bool custom_rect;
+ mutable bool rect_dirty;
+ mutable Rect2 rect;
+ CanvasItem*next;
+ CanvasItemMaterial* material;
+ struct CopyBackBuffer {
+ Rect2 rect;
+ Rect2 screen_rect;
+ bool full;
+ };
+ CopyBackBuffer *copy_back_buffer;
+
+
+ float final_opacity;
+ Matrix32 final_transform;
+ Rect2 final_clip_rect;
+ CanvasItem* final_clip_owner;
+ CanvasItem* material_owner;
+ ViewportRender *vp_render;
+ bool distance_field;
+ bool light_masked;
+
+ Rect2 global_rect_cache;
+
+ const Rect2& get_rect() const {
+ if (custom_rect || !rect_dirty)
+ return rect;
+
+ //must update rect
+ int s=commands.size();
+ if (s==0) {
+
+ rect=Rect2();
+ rect_dirty=false;
+ return rect;
+ }
+
+ Matrix32 xf;
+ bool found_xform=false;
+ bool first=true;
+
+ const CanvasItem::Command * const *cmd = &commands[0];
+
+
+ for (int i=0;i<s;i++) {
+
+ const CanvasItem::Command *c=cmd[i];
+ Rect2 r;
+
+ switch(c->type) {
+ case CanvasItem::Command::TYPE_LINE: {
+
+ const CanvasItem::CommandLine* line = static_cast< const CanvasItem::CommandLine*>(c);
+ r.pos=line->from;
+ r.expand_to(line->to);
+ } break;
+ case CanvasItem::Command::TYPE_RECT: {
+
+ const CanvasItem::CommandRect* crect = static_cast< const CanvasItem::CommandRect*>(c);
+ r=crect->rect;
+
+ } break;
+ case CanvasItem::Command::TYPE_STYLE: {
+
+ const CanvasItem::CommandStyle* style = static_cast< const CanvasItem::CommandStyle*>(c);
+ r=style->rect;
+ } break;
+ case CanvasItem::Command::TYPE_PRIMITIVE: {
+
+ const CanvasItem::CommandPrimitive* primitive = static_cast< const CanvasItem::CommandPrimitive*>(c);
+ r.pos=primitive->points[0];
+ for(int i=1;i<primitive->points.size();i++) {
+
+ r.expand_to(primitive->points[i]);
+
+ }
+ } break;
+ case CanvasItem::Command::TYPE_POLYGON: {
+
+ const CanvasItem::CommandPolygon* polygon = static_cast< const CanvasItem::CommandPolygon*>(c);
+ int l = polygon->points.size();
+ const Point2*pp=&polygon->points[0];
+ r.pos=pp[0];
+ for(int i=1;i<l;i++) {
+
+ r.expand_to(pp[i]);
+
+ }
+ } break;
+
+ case CanvasItem::Command::TYPE_POLYGON_PTR: {
+
+ const CanvasItem::CommandPolygonPtr* polygon = static_cast< const CanvasItem::CommandPolygonPtr*>(c);
+ int l = polygon->count;
+ if (polygon->indices != NULL) {
+
+ r.pos=polygon->points[polygon->indices[0]];
+ for (int i=1; i<l; i++) {
+
+ r.expand_to(polygon->points[polygon->indices[i]]);
+ }
+ } else {
+ r.pos=polygon->points[0];
+ for (int i=1; i<l; i++) {
+
+ r.expand_to(polygon->points[i]);
+ }
+ }
+ } break;
+ case CanvasItem::Command::TYPE_CIRCLE: {
+
+ const CanvasItem::CommandCircle* circle = static_cast< const CanvasItem::CommandCircle*>(c);
+ r.pos=Point2(-circle->radius,-circle->radius)+circle->pos;
+ r.size=Point2(circle->radius*2.0,circle->radius*2.0);
+ } break;
+ case CanvasItem::Command::TYPE_TRANSFORM: {
+
+ const CanvasItem::CommandTransform* transform = static_cast<const CanvasItem::CommandTransform*>(c);
+ xf=transform->xform;
+ found_xform=true;
+ continue;
+ } break;
+ case CanvasItem::Command::TYPE_BLEND_MODE: {
+
+ } break;
+ case CanvasItem::Command::TYPE_CLIP_IGNORE: {
+
+ } break;
+ }
+
+ if (found_xform) {
+ r = xf.xform(r);
+ found_xform=false;
+ }
+
+
+ if (first) {
+ rect=r;
+ first=false;
+ } else
+ rect=rect.merge(r);
+ }
+
+ rect_dirty=false;
+ 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; 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); }
+ };
+
+
+ CanvasItemDrawViewportFunc draw_viewport_func;
+
+
+ virtual void begin_canvas_bg()=0;
virtual void canvas_begin()=0;
virtual void canvas_disable_blending()=0;
virtual void canvas_set_opacity(float p_opacity)=0;
@@ -562,7 +944,39 @@ public:
virtual void canvas_draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width)=0;
virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor)=0;
virtual void canvas_set_transform(const Matrix32& p_transform)=0;
-
+
+ virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light)=0;
+ virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow)=0;
+ /* LIGHT SHADOW MAPPING */
+
+ virtual RID canvas_light_occluder_create()=0;
+ virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines)=0;
+
+
+ virtual RID canvas_light_shadow_buffer_create(int p_width)=0;
+
+ struct CanvasLightOccluderInstance {
+
+
+ bool enabled;
+ RID canvas;
+ RID polygon;
+ RID polygon_buffer;
+ Rect2 aabb_cache;
+ Matrix32 xform;
+ Matrix32 xform_cache;
+ int light_mask;
+ VS::CanvasOccluderPolygonCullMode cull_cache;
+
+ CanvasLightOccluderInstance *next;
+
+ CanvasLightOccluderInstance() { enabled=true; next=NULL; light_mask=1; cull_cache=VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; }
+ };
+
+
+
+ virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache)=0;
+
/* ENVIRONMENT */
@@ -580,6 +994,10 @@ public:
virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value)=0;
virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const=0;
+ /* SAMPLED LIGHT */
+ virtual RID sampled_light_dp_create(int p_width,int p_height)=0;
+ virtual void sampled_light_dp_update(RID p_sampled_light,const Color *p_data,float p_multiplier)=0;
+
/*MISC*/
@@ -597,6 +1015,8 @@ public:
virtual bool is_environment(const RID& p_rid) const=0;
virtual bool is_shader(const RID& p_rid) const=0;
+ virtual bool is_canvas_light_occluder(const RID& p_rid) const=0;
+
virtual void free(const RID& p_rid)=0;
virtual void init()=0;
@@ -608,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 e0c1932589..c05438aef3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -221,6 +221,21 @@ void RasterizerDummy::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_
}
+
+void RasterizerDummy::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture) {
+
+}
+
+RID RasterizerDummy::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const {
+
+ return RID();
+}
+
+Variant RasterizerDummy::shader_get_default_param(RID p_shader, const StringName& p_name) {
+
+ return Variant();
+}
+
/* COMMON MATERIAL API */
@@ -561,7 +576,7 @@ int RasterizerDummy::mesh_get_surface_count(RID p_mesh) const {
return mesh->surfaces.size();
}
-AABB RasterizerDummy::mesh_get_aabb(RID p_mesh) const {
+AABB RasterizerDummy::mesh_get_aabb(RID p_mesh,RID p_skeleton) const {
Mesh *mesh = mesh_owner.get( p_mesh );
ERR_FAIL_COND_V(!mesh,AABB());
@@ -1482,7 +1497,7 @@ void RasterizerDummy::begin_shadow_map( RID p_light_instance, int p_shadow_pass
}
-void RasterizerDummy::set_camera(const Transform& p_world,const CameraMatrix& p_projection) {
+void RasterizerDummy::set_camera(const Transform& p_world, const CameraMatrix& p_projection, bool p_ortho_hint) {
}
@@ -1530,9 +1545,36 @@ void RasterizerDummy::end_frame() {
}
+RID RasterizerDummy::canvas_light_occluder_create() {
+ return RID();
+}
+
+void RasterizerDummy::canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines) {
+
+
+}
+
+RID RasterizerDummy::canvas_light_shadow_buffer_create(int p_width) {
+
+ return RID();
+}
+
+void RasterizerDummy::canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache) {
+
+
+}
+
+void RasterizerDummy::canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow) {
+
+
+}
+
/* CANVAS API */
+void RasterizerDummy::begin_canvas_bg() {
+
+}
void RasterizerDummy::canvas_begin() {
@@ -1607,6 +1649,11 @@ void RasterizerDummy::canvas_set_transform(const Matrix32& p_transform) {
}
+void RasterizerDummy::canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light) {
+
+
+}
+
/* ENVIRONMENT */
RID RasterizerDummy::environment_create() {
@@ -1679,6 +1726,18 @@ Variant RasterizerDummy::environment_fx_get_param(RID p_env,VS::EnvironmentFxPar
}
+
+RID RasterizerDummy::sampled_light_dp_create(int p_width,int p_height) {
+
+ return sampled_light_owner.make_rid(memnew(SampledLight));
+}
+
+void RasterizerDummy::sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier) {
+
+
+}
+
+
/*MISC*/
bool RasterizerDummy::is_texture(const RID& p_rid) const {
@@ -1729,6 +1788,11 @@ bool RasterizerDummy::is_environment(const RID& p_rid) const {
return environment_owner.owns(p_rid);
}
+bool RasterizerDummy::is_canvas_light_occluder(const RID& p_rid) const {
+
+ return false;
+}
+
bool RasterizerDummy::is_shader(const RID& p_rid) const {
return false;
@@ -1816,6 +1880,14 @@ void RasterizerDummy::free(const RID& p_rid) {
Environment *env = environment_owner.get( p_rid );
environment_owner.free(p_rid);
memdelete( env );
+ } else if (sampled_light_owner.owns(p_rid)) {
+
+ SampledLight *sampled_light = sampled_light_owner.get( p_rid );
+ ERR_FAIL_COND(!sampled_light);
+
+ sampled_light_owner.free(p_rid);
+ memdelete( sampled_light );
+
};
}
@@ -1876,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 01ae6c7644..2c503249fe 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -162,10 +162,6 @@ class RasterizerDummy : public Rasterizer {
uint32_t format;
uint32_t morph_format;
- RID material;
- bool material_owned;
-
-
Surface() {
packed=false;
@@ -353,6 +349,13 @@ class RasterizerDummy : public Rasterizer {
mutable RID_Owner<Environment> environment_owner;
+ struct SampledLight {
+
+ int w,h;
+ };
+
+ mutable RID_Owner<SampledLight> sampled_light_owner;
+
struct ShadowBuffer;
struct LightInstance {
@@ -408,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);
@@ -422,6 +429,12 @@ public:
virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
+
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture);
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const;
+
+ virtual Variant shader_get_default_param(RID p_shader, const StringName& p_name);
+
/* COMMON MATERIAL API */
virtual RID material_create();
@@ -471,7 +484,7 @@ public:
virtual void mesh_remove_surface(RID p_mesh,int p_index);
virtual int mesh_get_surface_count(RID p_mesh) const;
- virtual AABB mesh_get_aabb(RID p_mesh) const;
+ virtual AABB mesh_get_aabb(RID p_mesh,RID p_skeleton=RID()) const;
virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb);
virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
@@ -666,7 +679,7 @@ public:
virtual void begin_scene(RID p_viewport_data,RID p_env,VS::ScenarioDebugMode p_debug);
virtual void begin_shadow_map( RID p_light_instance, int p_shadow_pass );
- virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection);
+ virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection,bool p_ortho_hint);
virtual void add_light( RID p_light_instance ); ///< all "add_light" calls happen before add_geometry calls
@@ -683,6 +696,7 @@ public:
/* CANVAS API */
+ virtual void begin_canvas_bg();
virtual void canvas_begin();
virtual void canvas_disable_blending();
virtual void canvas_set_opacity(float p_opacity);
@@ -697,6 +711,16 @@ public:
virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor);
virtual void canvas_set_transform(const Matrix32& p_transform);
+ virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light);
+
+ virtual RID canvas_light_occluder_create();
+ virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines);
+
+ virtual RID canvas_light_shadow_buffer_create(int p_width);
+ virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache);
+
+ virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow);
+
/* ENVIRONMENT */
virtual RID environment_create();
@@ -713,6 +737,10 @@ public:
virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value);
virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const;
+ /* SAMPLED LIGHT */
+ virtual RID sampled_light_dp_create(int p_width,int p_height);
+ virtual void sampled_light_dp_update(RID p_sampled_light,const Color *p_data,float p_multiplier);
+
/*MISC*/
@@ -728,6 +756,7 @@ public:
virtual bool is_particles_instance(const RID& p_rid) const;
virtual bool is_skeleton(const RID& p_rid) const;
virtual bool is_environment(const RID& p_rid) const;
+ virtual bool is_canvas_light_occluder(const RID& p_rid) const;
virtual bool is_shader(const RID& p_rid) const;
@@ -750,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 df2ffa6889..d7b171f5a7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/visual/shader_compiler.h b/servers/visual/shader_compiler.h
index 6bb523fbce..69d9eedf9c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/visual/shader_graph.cpp b/servers/visual/shader_graph.cpp
index 8fb7196276..1346ec9253 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/servers/visual/shader_graph.h b/servers/visual/shader_graph.h
index 5c5079202f..807dbb3719 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,8 +26,6 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SHADER_GRAPH_H
-#define SHADER_GRAPH_H
#if 0
@@ -109,4 +107,3 @@ public:
};
#endif
-#endif
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index 16a725010d..0e10c7dfe4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,6 +56,7 @@ const char * ShaderLanguage::token_names[TK_MAX]={
"TYPE_VEC2",
"TYPE_VEC3",
"TYPE_VEC4",
+ "TYPE_MAT2",
"TYPE_MAT3",
"TYPE_MAT4",
"TYPE_TEXTURE",
@@ -117,13 +118,17 @@ ShaderLanguage::Token ShaderLanguage::read_token(const CharType* p_text,int p_le
while(true) {
- if (GETCHAR(r_chars+1)=='0')
+ if (GETCHAR(r_chars+1)==0) {
+ r_chars+=1;
break;
- if (GETCHAR(r_chars+1)=='*' && GETCHAR(r_chars+2)=='/')
+ } if (GETCHAR(r_chars+1)=='*' && GETCHAR(r_chars+2)=='/') {
+ r_chars+=3;
break;
- if (GETCHAR(r_chars+1)=='\n')
+ } if (GETCHAR(r_chars+1)=='\n') {
r_line++;
- r_chars++;
+ }
+
+ r_chars++;
}
return Token();
@@ -134,6 +139,8 @@ ShaderLanguage::Token ShaderLanguage::read_token(const CharType* p_text,int p_le
while(GETCHAR(r_chars+1)!='\n' && GETCHAR(r_chars+1)!=0) {
r_chars++;
}
+ r_chars++;
+ //r_line++;
return Token();
@@ -401,9 +408,9 @@ ShaderLanguage::Token ShaderLanguage::read_token(const CharType* p_text,int p_le
{TK_TYPE_TEXTURE,"texture"},
{TK_TYPE_CUBEMAP,"cubemap"},
{TK_TYPE_COLOR,"color"},
- /*
+
{TK_TYPE_MAT2,"mat2"},
- {TK_TYPE_MAT3,"mat3"},
+ /*{TK_TYPE_MAT3,"mat3"},
{TK_TYPE_MAT4,"mat3"},*/
{TK_TYPE_MAT3,"mat3"},
{TK_TYPE_MAT4,"mat4"},
@@ -434,7 +441,10 @@ ShaderLanguage::Token ShaderLanguage::read_token(const CharType* p_text,int p_le
return Token(TK_INDENTIFIER,str);
}
- return Token(TK_ERROR,"Unknown character");
+ if (GETCHAR(0)>32)
+ return Token(TK_ERROR,"Tokenizer: Unknown character #"+itos(GETCHAR(0))+": '"+String::chr(GETCHAR(0))+"'");
+ else
+ return Token(TK_ERROR,"Tokenizer: Unknown character #"+itos(GETCHAR(0)));
} break;
}
@@ -461,9 +471,9 @@ Error ShaderLanguage::tokenize(const String& p_text,Vector<Token> *p_tokens,Stri
if (t.type==TK_ERROR) {
if (r_error) {
- return ERR_COMPILATION_FAILED;
*r_error=t.text;
*r_err_line=line;
+ return ERR_COMPILATION_FAILED;
}
}
@@ -506,6 +516,7 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) {
(p_type==TK_TYPE_VEC3) ||
(p_type==TK_TYPE_VEC4) ||
(p_type==TK_TYPE_COLOR) ||
+ (p_type==TK_TYPE_MAT2) ||
(p_type==TK_TYPE_MAT3) ||
(p_type==TK_TYPE_MAT4) ||
(p_type==TK_TYPE_CUBEMAP) ||
@@ -524,6 +535,7 @@ ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) {
case TK_TYPE_VEC3: return TYPE_VEC3;
case TK_TYPE_VEC4: return TYPE_VEC4;
case TK_TYPE_COLOR: return TYPE_VEC4;
+ case TK_TYPE_MAT2: return TYPE_MAT2;
case TK_TYPE_MAT3: return TYPE_MAT3;
case TK_TYPE_MAT4: return TYPE_MAT4;
case TK_TYPE_TEXTURE: return TYPE_TEXTURE;
@@ -545,6 +557,7 @@ String ShaderLanguage::get_datatype_name(DataType p_type) {
case TYPE_VEC2: return "vec2";
case TYPE_VEC3: return "vec3";
case TYPE_VEC4: return "vec4";
+ case TYPE_MAT2: return "mat2";
case TYPE_MAT3: return "mat3";
case TYPE_MAT4: return "mat4";
case TYPE_TEXTURE: return "texture";
@@ -565,6 +578,7 @@ bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
(p_type==TK_TYPE_VEC3) ||
(p_type==TK_TYPE_VEC4) ||
(p_type==TK_TYPE_COLOR) ||
+ (p_type==TK_TYPE_MAT2) ||
(p_type==TK_TYPE_MAT3) ||
(p_type==TK_TYPE_MAT4) ||
(p_type==TK_TYPE_TEXTURE) ||
@@ -763,16 +777,21 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
//constructors
{"bool",TYPE_BOOL,{TYPE_BOOL,TYPE_VOID}},
{"float",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
+ {"vec2",TYPE_VEC2,{TYPE_FLOAT,TYPE_VOID}},
{"vec2",TYPE_VEC2,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
+ {"vec3",TYPE_VEC3,{TYPE_FLOAT,TYPE_VOID}},
{"vec3",TYPE_VEC3,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
{"vec3",TYPE_VEC3,{TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}},
{"vec3",TYPE_VEC3,{TYPE_FLOAT,TYPE_VEC2,TYPE_VOID}},
+ {"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_VOID}},
{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}},
{"vec4",TYPE_VEC4,{TYPE_VEC2,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VEC2,TYPE_VOID}},
{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC3,TYPE_VOID}},
{"vec4",TYPE_VEC4,{TYPE_VEC3,TYPE_FLOAT,TYPE_VOID}},
+ {"vec4",TYPE_VEC4,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}},
+ {"mat2",TYPE_MAT2,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}},
{"mat3",TYPE_MAT3,{TYPE_VEC3,TYPE_VEC3,TYPE_VEC3,TYPE_VOID}},
{"mat4",TYPE_MAT4,{TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VOID}},
//intrinsics - trigonometry
@@ -851,6 +870,9 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
{"clamp",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VEC2,TYPE_VOID}},
{"clamp",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VEC3,TYPE_VOID}},
{"clamp",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VOID}},
+ {"clamp",TYPE_VEC2,{TYPE_VEC2,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
+ {"clamp",TYPE_VEC3,{TYPE_VEC3,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
+ {"clamp",TYPE_VEC4,{TYPE_VEC4,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
{"mix",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
{"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}},
{"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VEC2,TYPE_VOID}},
@@ -888,6 +910,7 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
{"normalize",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}},
{"normalize",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}},
{"reflect",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}},
+ {"refract",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_FLOAT,TYPE_VOID}},
//intrinsics - texture
{"tex",TYPE_VEC4,{TYPE_TEXTURE,TYPE_VEC2,TYPE_VOID}},
{"texcube",TYPE_VEC4,{TYPE_CUBEMAP,TYPE_VEC3,TYPE_VOID}},
@@ -905,6 +928,7 @@ const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={
{OP_ASSIGN,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}},
{OP_ASSIGN,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}},
{OP_ASSIGN,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}},
+ {OP_ASSIGN,TYPE_VOID,{TYPE_MAT2,TYPE_MAT2}},
{OP_ASSIGN,TYPE_VOID,{TYPE_MAT3,TYPE_MAT3}},
{OP_ASSIGN,TYPE_VOID,{TYPE_MAT4,TYPE_MAT4}},
{OP_ADD,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}},
@@ -920,6 +944,8 @@ const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={
{OP_MUL,TYPE_VEC2,{TYPE_VEC2,TYPE_FLOAT}},
{OP_MUL,TYPE_VEC2,{TYPE_FLOAT,TYPE_VEC2}},
{OP_MUL,TYPE_VEC2,{TYPE_VEC2,TYPE_MAT3}},
+ {OP_MUL,TYPE_VEC2,{TYPE_MAT2,TYPE_VEC2}},
+ {OP_MUL,TYPE_VEC2,{TYPE_VEC2,TYPE_MAT2}},
{OP_MUL,TYPE_VEC2,{TYPE_MAT3,TYPE_VEC2}},
{OP_MUL,TYPE_VEC2,{TYPE_VEC2,TYPE_MAT4}},
{OP_MUL,TYPE_VEC2,{TYPE_MAT4,TYPE_VEC2}},
@@ -934,6 +960,7 @@ const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={
{OP_MUL,TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC4}},
{OP_MUL,TYPE_VEC4,{TYPE_MAT4,TYPE_VEC4}},
{OP_MUL,TYPE_VEC4,{TYPE_VEC4,TYPE_MAT4}},
+ {OP_MUL,TYPE_MAT2,{TYPE_MAT2,TYPE_MAT2}},
{OP_MUL,TYPE_MAT3,{TYPE_MAT3,TYPE_MAT3}},
{OP_MUL,TYPE_MAT4,{TYPE_MAT4,TYPE_MAT4}},
{OP_DIV,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}},
@@ -950,22 +977,28 @@ const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={
{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}},
{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}},
{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}},
+ {OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC2,TYPE_FLOAT}},
+ {OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC3,TYPE_FLOAT}},
+ {OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC4,TYPE_FLOAT}},
{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}},
{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}},
{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}},
{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}},
+ {OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC2,TYPE_FLOAT}},
+ {OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC3,TYPE_FLOAT}},
+ {OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC4,TYPE_FLOAT}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC2,TYPE_FLOAT}},
- {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT3,TYPE_VEC2}},
- {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT4,TYPE_VEC2}},
+ {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC2,TYPE_MAT2}},
+ {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT2,TYPE_MAT2}},
+ {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC3,TYPE_MAT3}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC3,TYPE_FLOAT}},
- {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT3,TYPE_VEC3}},
- {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT4,TYPE_VEC3}},
+ {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC3,TYPE_MAT4}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC4,TYPE_FLOAT}},
- {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT4,TYPE_VEC4}},
+ {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC4,TYPE_MAT4}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT3,TYPE_MAT3}},
{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT4,TYPE_MAT4}},
{OP_ASSIGN_DIV,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}},
@@ -981,17 +1014,17 @@ const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={
{OP_NEG,TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}},
{OP_NOT,TYPE_BOOL,{TYPE_BOOL,TYPE_VOID}},
{OP_CMP_EQ,TYPE_BOOL,{TYPE_BOOL,TYPE_BOOL}},
- {OP_CMP_EQ,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}},
- {OP_CMP_EQ,TYPE_VEC2,{TYPE_VEC3,TYPE_VEC2}},
- {OP_CMP_EQ,TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3}},
- {OP_CMP_EQ,TYPE_VEC4,{TYPE_VEC3,TYPE_VEC4}},
+ {OP_CMP_EQ,TYPE_BOOL,{TYPE_FLOAT,TYPE_FLOAT}},
+ {OP_CMP_EQ,TYPE_BOOL,{TYPE_VEC3,TYPE_VEC2}},
+ {OP_CMP_EQ,TYPE_BOOL,{TYPE_VEC3,TYPE_VEC3}},
+ {OP_CMP_EQ,TYPE_BOOL,{TYPE_VEC3,TYPE_VEC4}},
//{OP_CMP_EQ,TYPE_MAT3,{TYPE_MAT4,TYPE_MAT3}}, ??
//{OP_CMP_EQ,TYPE_MAT4,{TYPE_MAT4,TYPE_MAT4}}, ??
{OP_CMP_NEQ,TYPE_BOOL,{TYPE_BOOL,TYPE_BOOL}},
- {OP_CMP_NEQ,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}},
- {OP_CMP_NEQ,TYPE_VEC3,{TYPE_VEC2,TYPE_VEC2}},
- {OP_CMP_NEQ,TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3}},
- {OP_CMP_NEQ,TYPE_VEC3,{TYPE_VEC4,TYPE_VEC4}},
+ {OP_CMP_NEQ,TYPE_BOOL,{TYPE_FLOAT,TYPE_FLOAT}},
+ {OP_CMP_NEQ,TYPE_BOOL,{TYPE_VEC2,TYPE_VEC2}},
+ {OP_CMP_NEQ,TYPE_BOOL,{TYPE_VEC3,TYPE_VEC3}},
+ {OP_CMP_NEQ,TYPE_BOOL,{TYPE_VEC4,TYPE_VEC4}},
//{OP_CMP_NEQ,TYPE_MAT4,{TYPE_MAT4,TYPE_MAT4}}, //?
{OP_CMP_LEQ,TYPE_BOOL,{TYPE_FLOAT,TYPE_FLOAT}},
{OP_CMP_GEQ,TYPE_BOOL,{TYPE_FLOAT,TYPE_FLOAT}},
@@ -1005,6 +1038,12 @@ const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={
const ShaderLanguage::BuiltinsDef ShaderLanguage::vertex_builtins_defs[]={
+ { "SRC_VERTEX", TYPE_VEC3},
+ { "SRC_NORMAL", TYPE_VEC3},
+ { "SRC_TANGENT", TYPE_VEC3},
+ { "SRC_BINORMALF", TYPE_FLOAT},
+
+ { "POSITION", TYPE_VEC4 },
{ "VERTEX", TYPE_VEC3},
{ "NORMAL", TYPE_VEC3},
{ "TANGENT", TYPE_VEC3},
@@ -1023,6 +1062,7 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::vertex_builtins_defs[]={
{ "WORLD_MATRIX", TYPE_MAT4},
{ "INV_CAMERA_MATRIX", TYPE_MAT4},
{ "PROJECTION_MATRIX", TYPE_MAT4},
+ { "MODELVIEW_MATRIX", TYPE_MAT4},
{ "INSTANCE_ID", TYPE_FLOAT},
{ "TIME", TYPE_FLOAT},
{ NULL, TYPE_VOID},
@@ -1030,10 +1070,12 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::vertex_builtins_defs[]={
const ShaderLanguage::BuiltinsDef ShaderLanguage::fragment_builtins_defs[]={
{ "VERTEX", TYPE_VEC3},
- { "POSITION", TYPE_VEC3},
+ { "POSITION", TYPE_VEC4},
{ "NORMAL", TYPE_VEC3},
{ "TANGENT", TYPE_VEC3},
{ "BINORMAL", TYPE_VEC3},
+ { "NORMALMAP", TYPE_VEC3},
+ { "NORMALMAP_DEPTH", TYPE_FLOAT},
{ "UV", TYPE_VEC2},
{ "UV2", TYPE_VEC2},
{ "COLOR", TYPE_VEC4},
@@ -1071,6 +1113,75 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::light_builtins_defs[]={
{ "SPECULAR_EXP", TYPE_FLOAT},
{ "SHADE_PARAM", TYPE_FLOAT},
{ "LIGHT", TYPE_VEC3},
+ { "SHADOW", TYPE_VEC3 },
+ { "POINT_COORD", TYPE_VEC2 },
+// { "SCREEN_POS", TYPE_VEC2},
+// { "SCREEN_TEXEL_SIZE", TYPE_VEC2},
+ { "TIME", TYPE_FLOAT},
+ { NULL, TYPE_VOID}
+
+};
+
+
+
+const ShaderLanguage::BuiltinsDef ShaderLanguage::ci_vertex_builtins_defs[]={
+
+ { "SRC_VERTEX", TYPE_VEC2},
+ { "VERTEX", TYPE_VEC2},
+ { "WORLD_VERTEX", TYPE_VEC2},
+ { "UV", TYPE_VEC2},
+ { "COLOR", TYPE_VEC4},
+ { "VAR1", TYPE_VEC4},
+ { "VAR2", TYPE_VEC4},
+ { "POINT_SIZE", TYPE_FLOAT},
+
+ //builtins
+ { "WORLD_MATRIX", TYPE_MAT4},
+ { "PROJECTION_MATRIX", TYPE_MAT4},
+ { "EXTRA_MATRIX", TYPE_MAT4},
+ { "TIME", TYPE_FLOAT},
+ { NULL, TYPE_VOID},
+};
+const ShaderLanguage::BuiltinsDef ShaderLanguage::ci_fragment_builtins_defs[]={
+
+ { "SRC_COLOR", TYPE_VEC4},
+ { "POSITION", TYPE_VEC4},
+ { "NORMAL", TYPE_VEC3},
+ { "NORMALMAP", TYPE_VEC3},
+ { "NORMALMAP_DEPTH", TYPE_FLOAT},
+ { "UV", TYPE_VEC2},
+ { "COLOR", TYPE_VEC4},
+ { "TEXTURE", TYPE_TEXTURE},
+ { "TEXTURE_PIXEL_SIZE", TYPE_VEC2},
+ { "VAR1", TYPE_VEC4},
+ { "VAR2", TYPE_VEC4},
+ { "SCREEN_UV", TYPE_VEC2},
+ { "POINT_COORD", TYPE_VEC2},
+
+// { "SCREEN_POS", TYPE_VEC2},
+// { "SCREEN_TEXEL_SIZE", TYPE_VEC2},
+ { "TIME", TYPE_FLOAT},
+ { NULL, TYPE_VOID}
+
+};
+
+const ShaderLanguage::BuiltinsDef ShaderLanguage::ci_light_builtins_defs[]={
+
+ { "POSITION", TYPE_VEC4},
+ { "NORMAL", TYPE_VEC3},
+ { "UV", TYPE_VEC2},
+ { "COLOR", TYPE_VEC4},
+ { "TEXTURE", TYPE_TEXTURE},
+ { "TEXTURE_PIXEL_SIZE", TYPE_VEC2},
+ { "VAR1", TYPE_VEC4},
+ { "VAR2", TYPE_VEC4},
+ { "SCREEN_UV", TYPE_VEC2},
+ { "LIGHT_VEC", TYPE_VEC2},
+ { "LIGHT_HEIGHT", TYPE_FLOAT},
+ { "LIGHT_COLOR", TYPE_VEC4},
+ { "LIGHT_UV", TYPE_VEC2},
+ { "LIGHT", TYPE_VEC4},
+ { "SHADOW", TYPE_VEC4},
{ "POINT_COORD", TYPE_VEC2},
// { "SCREEN_POS", TYPE_VEC2},
// { "SCREEN_TEXEL_SIZE", TYPE_VEC2},
@@ -1170,7 +1281,7 @@ ShaderLanguage::Node* ShaderLanguage::validate_function_call(Parser&parser, Oper
if (p_func->op==OP_CONSTRUCT && all_const) {
- bool all_const=false;
+
Vector<float> cdata;
for(int i=0;i<argcount;i++) {
@@ -1191,9 +1302,25 @@ ShaderLanguage::Node* ShaderLanguage::validate_function_call(Parser&parser, Oper
Variant data;
switch(p_func->return_cache) {
case TYPE_FLOAT: data = cdata[0]; break;
- case TYPE_VEC2: data = Vector2(cdata[0],cdata[1]); break;
- case TYPE_VEC3: data = Vector3(cdata[0],cdata[1],cdata[2]); break;
- case TYPE_VEC4: data = Plane(cdata[0],cdata[1],cdata[2],cdata[3]); break;
+ case TYPE_VEC2:
+ if (cdata.size()==1)
+ data = Vector2(cdata[0],cdata[0]);
+ else
+ data = Vector2(cdata[0],cdata[1]);
+
+ break;
+ case TYPE_VEC3:
+ if (cdata.size()==1)
+ data = Vector3(cdata[0],cdata[0],cdata[0]);
+ else
+ data = Vector3(cdata[0],cdata[1],cdata[2]);
+ break;
+ case TYPE_VEC4:
+ if (cdata.size()==1)
+ data = Plane(cdata[0],cdata[0],cdata[0],cdata[0]);
+ else
+ data = Plane(cdata[0],cdata[1],cdata[2],cdata[3]);
+ break;
}
cn->datatype=p_func->return_cache;
@@ -1243,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;
}
@@ -1391,8 +1518,8 @@ ShaderLanguage::Operator ShaderLanguage::get_token_operator(TokenType p_type) {
Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_expr) {
- Vector<Node*> expressions;
- Vector<TokenType> operators;
+ Vector<Expression> expression;
+ //Vector<TokenType> operators;
while(true) {
@@ -1459,6 +1586,7 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
case TYPE_VEC2: name="vec2"; break;
case TYPE_VEC3: name="vec3"; break;
case TYPE_VEC4: name="vec4"; break;
+ case TYPE_MAT2: name="mat2"; break;
case TYPE_MAT3: name="mat3"; break;
case TYPE_MAT4: name="mat4"; break;
default: ERR_FAIL_V(ERR_BUG);
@@ -1588,7 +1716,7 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
if (!existing) {
- parser.set_error("Unexisting identifier in expression: "+identifier);
+ parser.set_error("Nonexistent identifier in expression: "+identifier);
return ERR_PARSE_ERROR;
}
@@ -1599,34 +1727,33 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
parser.advance();
expr=varname;
- } else if (parser.get_token_type()==TK_OP_NEG || parser.get_token_type()==TK_OP_NOT) {
+ } else if (parser.get_token_type()==TK_OP_SUB || parser.get_token_type()==TK_OP_NOT) {
//single prefix operators
TokenType token_type=parser.get_token_type();
parser.advance();
- Node *subexpr=NULL;
- Error err = parse_expression(parser,p_parent,&subexpr);
- if (err)
- return err;
+ //Node *subexpr=NULL;
+ //Error err = parse_expression(parser,p_parent,&subexpr);
+ //if (err)
+ // return err;
+
+ //OperatorNode *op = parser.create_node<OperatorNode>(p_parent);
+
+ Expression e;
+ e.is_op=true;
- OperatorNode *op = parser.create_node<OperatorNode>(p_parent);
switch(token_type) {
- case TK_OP_NEG: op->op=OP_NEG; break;
- case TK_OP_NOT: op->op=OP_NOT; break;
+ case TK_OP_SUB: e.op=TK_OP_NEG; break;
+ case TK_OP_NOT: e.op=TK_OP_NOT; break;
//case TK_OP_PLUS_PLUS: op->op=OP_PLUS_PLUS; break;
//case TK_OP_MINUS_MINUS: op->op=OP_MINUS_MINUS; break;
default: ERR_FAIL_V(ERR_BUG);
}
- op->arguments.push_back(subexpr);
+ expression.push_back(e);
- expr=validate_operator(parser,op);
-
- if (!expr) {
+ continue;
- parser.set_error("Invalid argument for negation operator");
- return ERR_PARSE_ERROR;
- }
} else {
print_line("found bug?");
@@ -1754,6 +1881,7 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
}
} break;
+ case TYPE_MAT2: ok=(ident=="x" || ident=="y"); member_type=TYPE_VEC2; break;
case TYPE_MAT3: ok=(ident=="x" || ident=="y" || ident=="z" ); member_type=TYPE_VEC3; break;
case TYPE_MAT4: ok=(ident=="x" || ident=="y" || ident=="z" || ident=="w"); member_type=TYPE_VEC4; break;
default: {}
@@ -1792,48 +1920,64 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
} */
-
- expressions.push_back(expr);
+ Expression e;
+ e.is_op=false;
+ e.node=expr;
+ expression.push_back(e);
if (is_token_operator(parser.get_token_type())) {
- operators.push_back(parser.get_token_type());
+ Expression o;
+ o.is_op=true;
+ o.op=parser.get_token_type();
+ expression.push_back(o);
parser.advance();
} else {
break;
}
}
- ERR_FAIL_COND_V(expressions.size()!=(operators.size()+1),ERR_BUG);
+
/* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
- while(expressions.size()>1) {
+ while(expression.size()>1) {
int next_op=-1;
int min_priority=0xFFFFF;
+ bool is_unary=false;
+
+ for(int i=0;i<expression.size();i++) {
+
+ if (!expression[i].is_op) {
+
+ continue;
+ }
- for(int i=0;i<operators.size();i++) {
+ bool unary=false;
int priority;
- switch(operators[i]) {
+ switch(expression[i].op) {
- case TK_OP_MUL: priority=0; break;
- case TK_OP_DIV: priority=0; break;
+ case TK_OP_NOT: priority=0; unary=true; break;
+ case TK_OP_NEG: priority=0; unary=true; break;
- case TK_OP_ADD: priority=1; break;
- case TK_OP_SUB: priority=1; break;
+ case TK_OP_MUL: priority=1; break;
+ case TK_OP_DIV: priority=1; break;
+
+ case TK_OP_ADD: priority=2; break;
+ case TK_OP_SUB: priority=2; break;
// shift left/right =2
- case TK_OP_LESS: priority=3; break;
- case TK_OP_LESS_EQUAL: priority=3; break;
- case TK_OP_GREATER: priority=3; break;
- case TK_OP_GREATER_EQUAL: priority=3; break;
+ case TK_OP_LESS: priority=4; break;
+ case TK_OP_LESS_EQUAL: priority=4; break;
+ case TK_OP_GREATER: priority=4; break;
+ case TK_OP_GREATER_EQUAL: priority=4; break;
- case TK_OP_EQUAL: priority=4; break;
- case TK_OP_NOT_EQUAL: priority=4; break;
+ case TK_OP_EQUAL: priority=5; break;
+ case TK_OP_NOT_EQUAL: priority=5; break;
//bit and =5
//bit xor =6
@@ -1859,6 +2003,7 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
// <= is used for right to left
next_op=i;
min_priority=priority;
+ is_unary=unary;
}
}
@@ -1866,7 +2011,94 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
ERR_FAIL_COND_V(next_op==-1,ERR_BUG);
// OK! create operator..
+ // OK! create operator..
+ if (is_unary) {
+
+ int expr_pos=next_op;
+ while(expression[expr_pos].is_op) {
+
+ expr_pos++;
+ if (expr_pos==expression.size()) {
+ //can happen..
+ parser.set_error("Unexpected end of expression..");
+ return ERR_BUG;
+ }
+ }
+
+ //consecutively do unary opeators
+ for(int i=expr_pos-1;i>=next_op;i--) {
+
+ OperatorNode *op = parser.create_node<OperatorNode>(p_parent);
+ op->op=get_token_operator(expression[i].op);
+ op->arguments.push_back(expression[i+1].node);
+
+ expression[i].is_op=false;
+ expression[i].node=validate_operator(parser,op);
+ if (!expression[i].node) {
+
+ String at;
+ for(int i=0;i<op->arguments.size();i++) {
+ if (i>0)
+ at+=" and ";
+ at+=get_datatype_name(compute_node_type(op->arguments[i]));
+
+ }
+ parser.set_error("Invalid argument to unary operator "+String(token_names[op->op])+": "+at);
+ return ERR_PARSE_ERROR;
+ }
+ expression.remove(i+1);
+ }
+ } else {
+
+ if (next_op <1 || next_op>=(expression.size()-1)) {
+ parser.set_error("Parser bug..");
+ ERR_FAIL_V(ERR_BUG);
+ }
+
+ OperatorNode *op = parser.create_node<OperatorNode>(p_parent);
+ op->op=get_token_operator(expression[next_op].op);
+ if (expression[next_op-1].is_op) {
+
+ parser.set_error("Parser bug..");
+ ERR_FAIL_V(ERR_BUG);
+ }
+
+ if (expression[next_op+1].is_op) {
+ // this is not invalid and can really appear
+ // but it becomes invalid anyway because no binary op
+ // can be followed by an unary op in a valid combination,
+ // due to how precedence works, unaries will always dissapear first
+
+ parser.set_error("Parser bug..");
+
+ }
+
+
+ op->arguments.push_back(expression[next_op-1].node); //expression goes as left
+ op->arguments.push_back(expression[next_op+1].node); //next expression goes as right
+
+ //replace all 3 nodes by this operator and make it an expression
+ expression[next_op-1].node=validate_operator(parser,op);
+ if (!expression[next_op-1].node) {
+
+ String at;
+ for(int i=0;i<op->arguments.size();i++) {
+ if (i>0)
+ at+=" and ";
+ at+=get_datatype_name(compute_node_type(op->arguments[i]));
+
+ }
+ static const char *op_names[OP_MAX]={"=","+","-","*","/","+=","-=","*=","/=","-","!","==","!=","<=",">=","<",">","||","&&","call","()"};
+
+ parser.set_error("Invalid arguments to operator "+String(op_names[op->op])+": "+at);
+ return ERR_PARSE_ERROR;
+ }
+ expression.remove(next_op);
+ expression.remove(next_op);
+ }
+
+#if 0
OperatorNode *op = parser.create_node<OperatorNode>(p_parent);
op->op=get_token_operator(operators[next_op]);
@@ -1890,10 +2122,11 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
expressions.remove(next_op+1);
operators.remove(next_op);
+#endif
}
- *r_expr=expressions[0];
+ *r_expr=expression[0].node;
return OK;
@@ -2035,6 +2268,7 @@ Error ShaderLanguage::parse_variable_declaration(Parser& parser,BlockNode *p_blo
case TYPE_VEC2: con->value=Vector2(); break;
case TYPE_VEC3: con->value=Vector3(); break;
case TYPE_VEC4: con->value=iscolor?Variant(Color()):Variant(Plane()); break;
+ case TYPE_MAT2: con->value=Matrix32(); break;
case TYPE_MAT3: con->value=Matrix3(); break;
case TYPE_MAT4: con->value=Transform(); break;
case TYPE_TEXTURE:
@@ -2107,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)
@@ -2327,6 +2569,27 @@ Error ShaderLanguage::parse(const Vector<Token>& p_tokens,ShaderType p_type,Comp
idx++;
}
} break;
+ case SHADER_CANVAS_ITEM_VERTEX: {
+ int idx=0;
+ while (ci_vertex_builtins_defs[idx].name) {
+ parser.program->builtin_variables[ci_vertex_builtins_defs[idx].name]=ci_vertex_builtins_defs[idx].type;
+ idx++;
+ }
+ } break;
+ case SHADER_CANVAS_ITEM_FRAGMENT: {
+ int idx=0;
+ while (ci_fragment_builtins_defs[idx].name) {
+ parser.program->builtin_variables[ci_fragment_builtins_defs[idx].name]=ci_fragment_builtins_defs[idx].type;
+ idx++;
+ }
+ } break;
+ case SHADER_CANVAS_ITEM_LIGHT: {
+ int idx=0;
+ while (ci_light_builtins_defs[idx].name) {
+ parser.program->builtin_variables[ci_light_builtins_defs[idx].name]=ci_light_builtins_defs[idx].type;
+ idx++;
+ }
+ } break;
case SHADER_POST_PROCESS: {
int idx=0;
while (postprocess_fragment_builtins_defs[idx].name) {
@@ -2373,6 +2636,9 @@ Error ShaderLanguage::compile(const String& p_code,ShaderType p_type,CompileFunc
uint64_t t = OS::get_singleton()->get_ticks_usec();
Error err = tokenize(p_code,&tokens,r_error,r_err_line,r_err_column);
+ if (err!=OK) {
+ print_line("tokenizer error!");
+ }
double tf = (OS::get_singleton()->get_ticks_usec()-t)/1000.0;
//print_line("tokenize time: "+rtos(tf));
@@ -2393,12 +2659,20 @@ void ShaderLanguage::get_keyword_list(ShaderType p_type, List<String> *p_keyword
int idx=0;
+ p_keywords->push_back("uniform");
+ p_keywords->push_back("texture");
+ p_keywords->push_back("cubemap");
+ p_keywords->push_back("color");
+ p_keywords->push_back("if");
+ p_keywords->push_back("else");
+
while(intrinsic_func_defs[idx].name) {
p_keywords->push_back(intrinsic_func_defs[idx].name);
idx++;
}
+
switch(p_type) {
case SHADER_MATERIAL_VERTEX: {
idx=0;
@@ -2421,6 +2695,28 @@ void ShaderLanguage::get_keyword_list(ShaderType p_type, List<String> *p_keyword
idx++;
}
} break;
+ case SHADER_CANVAS_ITEM_VERTEX: {
+ idx=0;
+ while (ci_vertex_builtins_defs[idx].name) {
+ p_keywords->push_back(ci_vertex_builtins_defs[idx].name);
+ idx++;
+ }
+ } break;
+ case SHADER_CANVAS_ITEM_FRAGMENT: {
+ idx=0;
+ while (ci_fragment_builtins_defs[idx].name) {
+ p_keywords->push_back(ci_fragment_builtins_defs[idx].name);
+ idx++;
+ }
+ } break;
+ case SHADER_CANVAS_ITEM_LIGHT: {
+ idx=0;
+ while (ci_light_builtins_defs[idx].name) {
+ p_keywords->push_back(ci_light_builtins_defs[idx].name);
+ idx++;
+ }
+ } break;
+
case SHADER_POST_PROCESS: {
idx=0;
while (postprocess_fragment_builtins_defs[idx].name) {
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
index 36f5bd64c7..9fd070ee2e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,8 +38,67 @@
class ShaderLanguage {
+
+
+
public:
+ enum TokenType {
+
+ TK_EMPTY,
+ TK_INDENTIFIER,
+ TK_TRUE,
+ TK_FALSE,
+ TK_REAL_CONSTANT,
+ TK_TYPE_VOID,
+ TK_TYPE_BOOL,
+ TK_TYPE_FLOAT,
+ TK_TYPE_VEC2,
+ TK_TYPE_VEC3,
+ TK_TYPE_VEC4,
+ TK_TYPE_MAT2,
+ TK_TYPE_MAT3,
+ TK_TYPE_MAT4,
+ TK_TYPE_TEXTURE,
+ TK_TYPE_CUBEMAP,
+ TK_TYPE_COLOR,
+ TK_OP_EQUAL,
+ TK_OP_NOT_EQUAL,
+ TK_OP_LESS,
+ TK_OP_LESS_EQUAL,
+ TK_OP_GREATER,
+ TK_OP_GREATER_EQUAL,
+ TK_OP_AND,
+ TK_OP_OR,
+ TK_OP_NOT,
+ TK_OP_ADD,
+ TK_OP_SUB,
+ TK_OP_MUL,
+ TK_OP_DIV,
+ TK_OP_NEG,
+ TK_OP_ASSIGN,
+ TK_OP_ASSIGN_ADD,
+ TK_OP_ASSIGN_SUB,
+ TK_OP_ASSIGN_MUL,
+ TK_OP_ASSIGN_DIV,
+ TK_CF_IF,
+ TK_CF_ELSE,
+ TK_CF_RETURN,
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_PARENTHESIS_OPEN,
+ TK_PARENTHESIS_CLOSE,
+ TK_COMMA,
+ TK_SEMICOLON,
+ TK_PERIOD,
+ TK_UNIFORM,
+ TK_ERROR,
+ TK_MAX
+ };
+
+
/* COMPILER */
@@ -47,6 +106,9 @@ public:
SHADER_MATERIAL_VERTEX,
SHADER_MATERIAL_FRAGMENT,
SHADER_MATERIAL_LIGHT,
+ SHADER_CANVAS_ITEM_VERTEX,
+ SHADER_CANVAS_ITEM_FRAGMENT,
+ SHADER_CANVAS_ITEM_LIGHT,
SHADER_POST_PROCESS,
};
@@ -57,6 +119,7 @@ public:
TYPE_VEC2,
TYPE_VEC3,
TYPE_VEC4,
+ TYPE_MAT2,
TYPE_MAT3,
TYPE_MAT4,
TYPE_TEXTURE,
@@ -216,6 +279,16 @@ public:
ProgramNode() { type=TYPE_PROGRAM; }
};
+
+ struct Expression {
+
+ bool is_op;
+ union {
+ TokenType op;
+ Node *node;
+ };
+ };
+
typedef Error (*CompileFunc)(void*,ProgramNode*);
struct VarInfo {
@@ -228,60 +301,6 @@ private:
- enum TokenType {
-
- TK_EMPTY,
- TK_INDENTIFIER,
- TK_TRUE,
- TK_FALSE,
- TK_REAL_CONSTANT,
- TK_TYPE_VOID,
- TK_TYPE_BOOL,
- TK_TYPE_FLOAT,
- TK_TYPE_VEC2,
- TK_TYPE_VEC3,
- TK_TYPE_VEC4,
- TK_TYPE_MAT3,
- TK_TYPE_MAT4,
- TK_TYPE_TEXTURE,
- TK_TYPE_CUBEMAP,
- TK_TYPE_COLOR,
- TK_OP_EQUAL,
- TK_OP_NOT_EQUAL,
- TK_OP_LESS,
- TK_OP_LESS_EQUAL,
- TK_OP_GREATER,
- TK_OP_GREATER_EQUAL,
- TK_OP_AND,
- TK_OP_OR,
- TK_OP_NOT,
- TK_OP_ADD,
- TK_OP_SUB,
- TK_OP_MUL,
- TK_OP_DIV,
- TK_OP_NEG,
- TK_OP_ASSIGN,
- TK_OP_ASSIGN_ADD,
- TK_OP_ASSIGN_SUB,
- TK_OP_ASSIGN_MUL,
- TK_OP_ASSIGN_DIV,
- TK_CF_IF,
- TK_CF_ELSE,
- TK_CF_RETURN,
- TK_BRACKET_OPEN,
- TK_BRACKET_CLOSE,
- TK_CURLY_BRACKET_OPEN,
- TK_CURLY_BRACKET_CLOSE,
- TK_PARENTHESIS_OPEN,
- TK_PARENTHESIS_CLOSE,
- TK_COMMA,
- TK_SEMICOLON,
- TK_PERIOD,
- TK_UNIFORM,
- TK_ERROR,
- TK_MAX
- };
-
static const char * token_names[TK_MAX];
struct Token {
@@ -362,6 +381,12 @@ private:
static const BuiltinsDef vertex_builtins_defs[];
static const BuiltinsDef fragment_builtins_defs[];
static const BuiltinsDef light_builtins_defs[];
+
+ static const BuiltinsDef ci_vertex_builtins_defs[];
+ static const BuiltinsDef ci_fragment_builtins_defs[];
+ static const BuiltinsDef ci_light_builtins_defs[];
+
+
static const BuiltinsDef postprocess_fragment_builtins_defs[];
static DataType get_token_datatype(TokenType p_type);
diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp
index 7c1f03b71b..79911121f5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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) {
@@ -148,7 +163,7 @@ String VisualServerRaster::shader_get_fragment_code(RID p_shader) const{
String VisualServerRaster::shader_get_light_code(RID p_shader) const{
- return rasterizer->shader_get_fragment_code(p_shader);
+ return rasterizer->shader_get_light_code(p_shader);
}
void VisualServerRaster::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
@@ -157,6 +172,16 @@ void VisualServerRaster::shader_get_param_list(RID p_shader, List<PropertyInfo>
}
+void VisualServerRaster::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture) {
+
+ rasterizer->shader_set_default_texture_param(p_shader,p_name,p_texture);
+}
+
+RID VisualServerRaster::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const{
+
+ return rasterizer->shader_get_default_texture_param(p_shader,p_name);
+}
+
/* Material */
@@ -444,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 */
@@ -888,8 +921,17 @@ int VisualServerRaster::skeleton_get_bone_count(RID p_skeleton) const {
void VisualServerRaster::skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform) {
VS_CHANGED;
- return rasterizer->skeleton_bone_set_transform(p_skeleton,p_bone,p_transform);
+ rasterizer->skeleton_bone_set_transform(p_skeleton,p_bone,p_transform);
+
+ Map< RID, Set<Instance*> >::Element *E=skeleton_dependency_map.find(p_skeleton);
+
+ if (E) {
+ //detach skeletons
+ for (Set<Instance*>::Element *F=E->get().front();F;F=F->next()) {
+ _instance_queue_update( F->get() , true);
+ }
+ }
}
Transform VisualServerRaster::skeleton_bone_get_transform(RID p_skeleton,int p_bone) {
@@ -1038,6 +1080,7 @@ RID VisualServerRaster::baked_light_create() {
baked_light->data.octree_lattice_size=0;
baked_light->data.octree_lattice_divide=0;
baked_light->data.octree_steps=1;
+ baked_light->data.lightmap_multiplier=1.0;
return baked_light_owner.make_rid( baked_light );
@@ -1063,6 +1106,26 @@ VisualServer::BakedLightMode VisualServerRaster::baked_light_get_mode(RID p_bake
}
+void VisualServerRaster::baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier) {
+
+ VS_CHANGED;
+ BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+ ERR_FAIL_COND(!baked_light);
+
+ baked_light->data.lightmap_multiplier=p_multiplier;
+
+}
+
+float VisualServerRaster::baked_light_get_lightmap_multiplier(RID p_baked_light) const{
+
+ const BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+ ERR_FAIL_COND_V(!baked_light,0);
+
+ return baked_light->data.lightmap_multiplier;
+
+}
+
+
void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree){
VS_CHANGED;
@@ -1079,8 +1142,12 @@ void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<
int tex_w;
int tex_h;
+ int light_tex_w;
+ int light_tex_h;
bool is16;
+ bool has_light_tex=false;
{
+
DVector<uint8_t>::Read r=p_octree.read();
tex_w = decode_uint32(&r[0]);
tex_h = decode_uint32(&r[4]);
@@ -1093,7 +1160,22 @@ void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<
baked_light->data.octree_steps=decode_uint32(&r[16]);
baked_light->data.octree_tex_pixel_size.x=1.0/tex_w;
baked_light->data.octree_tex_pixel_size.y=1.0/tex_h;
+
baked_light->data.texture_multiplier=decode_uint32(&r[20]);
+ light_tex_w=decode_uint16(&r[24]);
+ light_tex_h=decode_uint16(&r[26]);
+ print_line("ltexw "+itos(light_tex_w));
+ print_line("ltexh "+itos(light_tex_h));
+
+ if (light_tex_w>0 && light_tex_h>0) {
+ baked_light->data.light_tex_pixel_size.x=1.0/light_tex_w;
+ baked_light->data.light_tex_pixel_size.y=1.0/light_tex_h;
+ has_light_tex=true;
+ } else {
+ baked_light->data.light_tex_pixel_size=baked_light->data.octree_tex_pixel_size;
+
+ }
+
baked_light->octree_aabb.pos.x=decode_float(&r[32]);
@@ -1111,12 +1193,33 @@ void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<
rasterizer->free(baked_light->data.octree_texture);
baked_light->data.octree_texture=RID();
+ baked_light->octree_tex_size.x=0;
+ baked_light->octree_tex_size.y=0;
+ }
+ }
+
+ if (baked_light->data.light_texture.is_valid()) {
+ if (!has_light_tex || light_tex_w!=baked_light->light_tex_size.x || light_tex_h!=baked_light->light_tex_size.y) {
+ rasterizer->free(baked_light->data.light_texture);
+ baked_light->data.light_texture=RID();
+ baked_light->light_tex_size.x=0;
+ baked_light->light_tex_size.y=0;
}
}
if (!baked_light->data.octree_texture.is_valid()) {
baked_light->data.octree_texture=rasterizer->texture_create();
rasterizer->texture_allocate(baked_light->data.octree_texture,tex_w,tex_h,Image::FORMAT_RGBA,TEXTURE_FLAG_FILTER);
+ baked_light->octree_tex_size.x=tex_w;
+ baked_light->octree_tex_size.y=tex_h;
+ }
+
+ if (!baked_light->data.light_texture.is_valid() && has_light_tex) {
+ baked_light->data.light_texture=rasterizer->texture_create();
+ rasterizer->texture_allocate(baked_light->data.light_texture,light_tex_w,light_tex_h,Image::FORMAT_RGBA,TEXTURE_FLAG_FILTER);
+ baked_light->light_tex_size.x=light_tex_w;
+ baked_light->light_tex_size.y=light_tex_h;
+
}
Image img(tex_w,tex_h,0,Image::FORMAT_RGBA,p_octree);
@@ -1129,6 +1232,7 @@ void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<
}
+
DVector<uint8_t> VisualServerRaster::baked_light_get_octree(RID p_baked_light) const{
@@ -1144,6 +1248,67 @@ DVector<uint8_t> VisualServerRaster::baked_light_get_octree(RID p_baked_light) c
}
}
+void VisualServerRaster::baked_light_set_light(RID p_baked_light,const DVector<uint8_t> p_light) {
+
+ VS_CHANGED;
+ BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+ ERR_FAIL_COND(!baked_light);
+ ERR_FAIL_COND(p_light.size()==0);
+
+ int tex_w=baked_light->light_tex_size.x;
+ int tex_h=baked_light->light_tex_size.y;
+
+ ERR_FAIL_COND(tex_w==0 && tex_h==0);
+ ERR_FAIL_COND(!baked_light->data.light_texture.is_valid());
+
+
+
+ print_line("w: "+itos(tex_w)+" h: "+itos(tex_h)+" lightsize: "+itos(p_light.size()));
+
+ Image img(tex_w,tex_h,0,Image::FORMAT_RGBA,p_light);
+ rasterizer->texture_set_data(baked_light->data.light_texture,img);
+
+
+
+}
+
+DVector<uint8_t> VisualServerRaster::baked_light_get_light(RID p_baked_light) const{
+
+ BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+ ERR_FAIL_COND_V(!baked_light,DVector<uint8_t>());
+
+ if (rasterizer->is_texture(baked_light->data.light_texture)) {
+
+ Image img = rasterizer->texture_get_data(baked_light->data.light_texture);
+ return img.get_data();
+ } else {
+ return DVector<uint8_t>();
+ }
+}
+
+
+
+void VisualServerRaster::baked_light_set_sampler_octree(RID p_baked_light, const DVector<int> &p_sampler) {
+
+ BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+ ERR_FAIL_COND(!baked_light);
+
+ baked_light->sampler=p_sampler;
+
+
+
+}
+
+DVector<int> VisualServerRaster::baked_light_get_sampler_octree(RID p_baked_light) const {
+
+ BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+ ERR_FAIL_COND_V(!baked_light,DVector<int>());
+
+ return baked_light->sampler;
+
+}
+
+
void VisualServerRaster::baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id){
VS_CHANGED;
@@ -1162,6 +1327,84 @@ void VisualServerRaster::baked_light_clear_lightmaps(RID p_baked_light){
}
+/* BAKED LIGHT SAMPLER */
+
+RID VisualServerRaster::baked_light_sampler_create() {
+
+ BakedLightSampler * blsamp = memnew( BakedLightSampler );
+ RID rid = baked_light_sampler_owner.make_rid(blsamp);
+ _update_baked_light_sampler_dp_cache(blsamp);
+ return rid;
+}
+
+void VisualServerRaster::baked_light_sampler_set_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param,float p_value){
+
+ VS_CHANGED;
+ BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
+ ERR_FAIL_COND(!blsamp);
+ ERR_FAIL_INDEX(p_param,BAKED_LIGHT_SAMPLER_MAX);
+ blsamp->params[p_param]=p_value;
+ _dependency_queue_update(p_baked_light_sampler,true);
+}
+
+float VisualServerRaster::baked_light_sampler_get_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param) const{
+
+
+ BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
+ ERR_FAIL_COND_V(!blsamp,0);
+ ERR_FAIL_INDEX_V(p_param,BAKED_LIGHT_SAMPLER_MAX,0);
+ return blsamp->params[p_param];
+}
+
+void VisualServerRaster::_update_baked_light_sampler_dp_cache(BakedLightSampler * blsamp) {
+
+ int res = blsamp->resolution;
+ blsamp->dp_cache.resize(res*res*2);
+ Vector3 *dp_normals=blsamp->dp_cache.ptr();
+
+ for(int p=0;p<2;p++) {
+ float sign = p==0?1:-1;
+ int ofs = res*res*p;
+ for(int i=0;i<res;i++) {
+ for(int j=0;j<res;j++) {
+
+ Vector2 v(
+ (i/float(res))*2.0-1.0,
+ (j/float(res))*2.0-1.0
+ );
+
+ float l=v.length();
+ if (l>1.0) {
+ v/=l;
+ l=1.0; //clamp to avoid imaginary
+ }
+ v*=(2*l)/(l*l+1); //inverse of the dual paraboloid function
+ Vector3 n = Vector3(v.x,v.y,sign*sqrtf(MAX(1 - v.dot(v),0))); //reconstruction of z
+ n.y*=sign;
+ dp_normals[j*res+i+ofs]=n;
+ }
+ }
+ }
+
+}
+
+void VisualServerRaster::baked_light_sampler_set_resolution(RID p_baked_light_sampler,int p_resolution){
+
+ 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);
+ blsamp->resolution=p_resolution;
+ _update_baked_light_sampler_dp_cache(blsamp);
+
+}
+int VisualServerRaster::baked_light_sampler_get_resolution(RID p_baked_light_sampler) const{
+
+ BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
+ ERR_FAIL_COND_V(!blsamp,0);
+ return blsamp->resolution;
+}
+
/* CAMERA API */
RID VisualServerRaster::camera_create() {
@@ -1172,7 +1415,7 @@ RID VisualServerRaster::camera_create() {
}
void VisualServerRaster::camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far) {
- VS_CHANGED;
+ VS_CHANGED
Camera *camera = camera_owner.get( p_camera );
ERR_FAIL_COND(!camera);
camera->type=Camera::PERSPECTIVE;
@@ -1196,7 +1439,7 @@ void VisualServerRaster::camera_set_transform(RID p_camera,const Transform& p_tr
VS_CHANGED;
Camera *camera = camera_owner.get( p_camera );
ERR_FAIL_COND(!camera);
- camera->transform=p_transform;
+ camera->transform=p_transform.orthonormalized();
}
@@ -1356,6 +1599,15 @@ void VisualServerRaster::viewport_set_render_target_vflip(RID p_viewport,bool p_
}
+void VisualServerRaster::viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable) {
+
+ Viewport *viewport = viewport_owner.get( p_viewport );
+ ERR_FAIL_COND(!viewport);
+
+ viewport->render_target_clear_on_new_frame=p_enable;
+
+}
+
void VisualServerRaster::viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect) {
Viewport *viewport = viewport_owner.get( p_viewport );
@@ -1374,6 +1626,23 @@ bool VisualServerRaster::viewport_get_render_target_vflip(RID p_viewport) const{
}
+bool VisualServerRaster::viewport_get_render_target_clear_on_new_frame(RID p_viewport) const{
+
+ const Viewport *viewport = viewport_owner.get( p_viewport );
+ ERR_FAIL_COND_V(!viewport,false);
+
+ return viewport->render_target_clear_on_new_frame;
+
+}
+
+void VisualServerRaster::viewport_render_target_clear(RID p_viewport) {
+
+ Viewport *viewport = viewport_owner.get( p_viewport );
+ ERR_FAIL_COND(!viewport);
+
+ viewport->render_target_clear=true;
+
+}
void VisualServerRaster::viewport_queue_screen_capture(RID p_viewport) {
@@ -1447,6 +1716,17 @@ void VisualServerRaster::viewport_set_hide_canvas(RID p_viewport,bool p_hide) {
}
+void VisualServerRaster::viewport_set_disable_environment(RID p_viewport,bool p_disable) {
+
+ VS_CHANGED;
+
+ Viewport *viewport=NULL;
+ viewport = viewport_owner.get( p_viewport );
+ ERR_FAIL_COND(!viewport);
+ viewport->disable_environment=p_disable;
+
+}
+
void VisualServerRaster::viewport_attach_camera(RID p_viewport,RID p_camera) {
VS_CHANGED;
@@ -1756,6 +2036,17 @@ void VisualServerRaster::scenario_set_environment(RID p_scenario, RID p_environm
}
+void VisualServerRaster::scenario_set_fallback_environment(RID p_scenario, RID p_environment) {
+
+ VS_CHANGED;
+
+ Scenario *scenario = scenario_owner.get(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ scenario->fallback_environment=p_environment;
+
+
+}
+
RID VisualServerRaster::scenario_get_environment(RID p_scenario, RID p_environment) const{
const Scenario *scenario = scenario_owner.get(p_scenario);
@@ -1902,6 +2193,20 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) {
}
+ if (instance->baked_light_sampler_info) {
+
+ while (instance->baked_light_sampler_info->owned_instances.size()) {
+
+ instance_geometry_set_baked_light_sampler(instance->baked_light_sampler_info->owned_instances.front()->get()->self,RID());
+ }
+
+ if (instance->baked_light_sampler_info->sampled_light.is_valid()) {
+ rasterizer->free(instance->baked_light_sampler_info->sampled_light);
+ }
+ memdelete( instance->baked_light_sampler_info );
+ instance->baked_light_sampler_info=NULL;
+ }
+
instance->data.morph_values.clear();
}
@@ -1951,6 +2256,16 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) {
//instance->portal_info = memnew(Instance::PortalInfo);
//instance->portal_info->portal=portal_owner.get(p_base);
+ } else if (baked_light_sampler_owner.owns(p_base)) {
+
+
+ instance->base_type=INSTANCE_BAKED_LIGHT_SAMPLER;
+ instance->baked_light_sampler_info=memnew( Instance::BakedLightSamplerInfo);
+ instance->baked_light_sampler_info->sampler=baked_light_sampler_owner.get(p_base);
+
+ //instance->portal_info = memnew(Instance::PortalInfo);
+ //instance->portal_info->portal=portal_owner.get(p_base);
+
} else {
ERR_EXPLAIN("Invalid base RID for instance!")
ERR_FAIL();
@@ -2092,8 +2407,17 @@ void VisualServerRaster::instance_attach_skeleton(RID p_instance,RID p_skeleton)
VS_CHANGED;
Instance *instance = instance_owner.get( p_instance );
ERR_FAIL_COND( !instance );
+
+ if (instance->data.skeleton.is_valid()) {
+ skeleton_dependency_map[instance->data.skeleton].erase(instance);
+ }
+
instance->data.skeleton=p_skeleton;
+ if (instance->data.skeleton.is_valid()) {
+ skeleton_dependency_map[instance->data.skeleton].insert(instance);
+ }
+
}
RID VisualServerRaster::instance_get_skeleton(RID p_instance) const {
@@ -2557,18 +2881,57 @@ RID VisualServerRaster::instance_geometry_get_baked_light(RID p_instance) const{
const Instance *instance = instance_owner.get( p_instance );
ERR_FAIL_COND_V( !instance,RID() );
if (instance->baked_light)
- instance->baked_light->self;
+ return instance->baked_light->self;
return RID();
}
+
+void VisualServerRaster::instance_geometry_set_baked_light_sampler(RID p_instance,RID p_baked_light_sampler) {
+
+ VS_CHANGED;
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND( !instance );
+
+ if (instance->sampled_light) {
+ instance->sampled_light->baked_light_sampler_info->owned_instances.erase(instance);
+ instance->data.sampled_light=RID();
+ }
+
+ if(p_baked_light_sampler.is_valid()) {
+ Instance *sampler_instance = instance_owner.get( p_baked_light_sampler );
+ ERR_FAIL_COND( !sampler_instance );
+ ERR_FAIL_COND( sampler_instance->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER );
+ instance->sampled_light=sampler_instance;
+ instance->sampled_light->baked_light_sampler_info->owned_instances.insert(instance);
+ } else {
+ instance->sampled_light=NULL;
+ }
+
+ instance->data.sampled_light=RID();
+
+}
+
+RID VisualServerRaster::instance_geometry_get_baked_light_sampler(RID p_instance) const {
+
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND_V( !instance,RID() );
+
+ if (instance->sampled_light)
+ return instance->sampled_light->self;
+ else
+ return RID();
+
+}
+
+
void VisualServerRaster::instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id){
VS_CHANGED;
Instance *instance = instance_owner.get( p_instance );
ERR_FAIL_COND( !instance );
- instance->lightmap_texture_index=p_tex_id;
+ instance->data.baked_lightmap_id=p_tex_id;
}
@@ -2577,7 +2940,7 @@ int VisualServerRaster::instance_geometry_get_baked_light_texture_index(RID p_in
const Instance *instance = instance_owner.get( p_instance );
ERR_FAIL_COND_V( !instance,0 );
- return instance->lightmap_texture_index;
+ return instance->data.baked_lightmap_id;
}
@@ -2697,6 +3060,13 @@ void VisualServerRaster::_update_instance(Instance *p_instance) {
pairable=true;
}
+ if (p_instance->base_type == INSTANCE_BAKED_LIGHT_SAMPLER) {
+
+ pairable_mask=(1<<INSTANCE_BAKED_LIGHT);
+ pairable=true;
+ }
+
+
if (!p_instance->room && (1<<p_instance->base_type)&INSTANCE_GEOMETRY_MASK) {
base_type|=INSTANCE_ROOMLESS_MASK;
@@ -2752,7 +3122,7 @@ void VisualServerRaster::_update_instance_aabb(Instance *p_instance) {
} break;
case VisualServer::INSTANCE_MESH: {
- new_aabb = rasterizer->mesh_get_aabb(p_instance->base_rid);
+ new_aabb = rasterizer->mesh_get_aabb(p_instance->base_rid,p_instance->data.skeleton);
} break;
case VisualServer::INSTANCE_MULTIMESH: {
@@ -2809,6 +3179,16 @@ void VisualServerRaster::_update_instance_aabb(Instance *p_instance) {
new_aabb=baked_light->octree_aabb;
} break;
+ case VisualServer::INSTANCE_BAKED_LIGHT_SAMPLER: {
+
+ BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get( p_instance->base_rid );
+ ERR_FAIL_COND(!baked_light_sampler);
+ float radius = baked_light_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS];
+
+ new_aabb=AABB(Vector3(-radius,-radius,-radius),Vector3(radius*2,radius*2,radius*2));
+
+ } break;
+
default: {}
}
@@ -2875,6 +3255,7 @@ RID VisualServerRaster::canvas_create() {
return rid;
}
+
void VisualServerRaster::canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring) {
Canvas * canvas = canvas_owner.get(p_canvas);
@@ -2900,6 +3281,14 @@ Point2 VisualServerRaster::canvas_get_item_mirroring(RID p_canvas,RID p_item) co
return canvas->child_items[idx].mirror;
}
+void VisualServerRaster::canvas_set_modulate(RID p_canvas,const Color& p_color) {
+
+ Canvas * canvas = canvas_owner.get(p_canvas);
+ ERR_FAIL_COND(!canvas);
+ canvas->modulate=p_color;
+}
+
+
RID VisualServerRaster::canvas_item_create() {
@@ -2985,14 +3374,27 @@ bool VisualServerRaster::canvas_item_is_visible(RID p_item) const {
}
+void VisualServerRaster::canvas_item_set_light_mask(RID p_canvas_item,int p_mask) {
+
+ VS_CHANGED;
+
+ CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item );
+ ERR_FAIL_COND(!canvas_item);
+
+ if (canvas_item->light_mask==p_mask)
+ return;
+ VS_CHANGED;
+
+ canvas_item->light_mask=p_mask;
+
+}
+
+
void VisualServerRaster::canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend) {
VS_CHANGED;
CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item );
- if (!canvas_item) {
- printf("!canvas_item\n");
- };
ERR_FAIL_COND(!canvas_item);
if (canvas_item->blend_mode==p_blend)
@@ -3032,130 +3434,15 @@ void VisualServerRaster::canvas_item_set_clip(RID p_item, bool p_clip) {
canvas_item->clip=p_clip;
}
-const Rect2& VisualServerRaster::CanvasItem::get_rect() const {
-
- if (custom_rect || !rect_dirty)
- return rect;
-
- //must update rect
- int s=commands.size();
- if (s==0) {
-
- rect=Rect2();
- rect_dirty=false;
- return rect;
- }
-
- Matrix32 xf;
- bool found_xform=false;
- bool first=true;
-
- const CanvasItem::Command * const *cmd = &commands[0];
-
-
- for (int i=0;i<s;i++) {
-
- const CanvasItem::Command *c=cmd[i];
- Rect2 r;
-
- switch(c->type) {
- case CanvasItem::Command::TYPE_LINE: {
-
- const CanvasItem::CommandLine* line = static_cast< const CanvasItem::CommandLine*>(c);
- r.pos=line->from;
- r.expand_to(line->to);
- } break;
- case CanvasItem::Command::TYPE_RECT: {
-
- const CanvasItem::CommandRect* crect = static_cast< const CanvasItem::CommandRect*>(c);
- r=crect->rect;
-
- } break;
- case CanvasItem::Command::TYPE_STYLE: {
-
- const CanvasItem::CommandStyle* style = static_cast< const CanvasItem::CommandStyle*>(c);
- r=style->rect;
- } break;
- case CanvasItem::Command::TYPE_PRIMITIVE: {
-
- const CanvasItem::CommandPrimitive* primitive = static_cast< const CanvasItem::CommandPrimitive*>(c);
- r.pos=primitive->points[0];
- for(int i=1;i<primitive->points.size();i++) {
-
- r.expand_to(primitive->points[i]);
-
- }
- } break;
- case CanvasItem::Command::TYPE_POLYGON: {
-
- const CanvasItem::CommandPolygon* polygon = static_cast< const CanvasItem::CommandPolygon*>(c);
- int l = polygon->points.size();
- const Point2*pp=&polygon->points[0];
- r.pos=pp[0];
- for(int i=1;i<l;i++) {
-
- r.expand_to(pp[i]);
-
- }
- } break;
-
- case CanvasItem::Command::TYPE_POLYGON_PTR: {
-
- const CanvasItem::CommandPolygonPtr* polygon = static_cast< const CanvasItem::CommandPolygonPtr*>(c);
- int l = polygon->count;
- if (polygon->indices != NULL) {
-
- r.pos=polygon->points[polygon->indices[0]];
- for (int i=1; i<polygon->count; i++) {
-
- r.expand_to(polygon->points[polygon->indices[i]]);
- };
- } else {
- r.pos=polygon->points[0];
- for (int i=1; i<polygon->count; i++) {
-
- r.expand_to(polygon->points[i]);
- };
- };
- } break;
- case CanvasItem::Command::TYPE_CIRCLE: {
-
- const CanvasItem::CommandCircle* circle = static_cast< const CanvasItem::CommandCircle*>(c);
- r.pos=Point2(-circle->radius,-circle->radius)+circle->pos;
- r.size=Point2(circle->radius*2.0,circle->radius*2.0);
- } break;
- case CanvasItem::Command::TYPE_TRANSFORM: {
-
- const CanvasItem::CommandTransform* transform = static_cast<const CanvasItem::CommandTransform*>(c);
- xf=transform->xform;
- found_xform=true;
- continue;
- } break;
- case CanvasItem::Command::TYPE_BLEND_MODE: {
-
- } break;
- case CanvasItem::Command::TYPE_CLIP_IGNORE: {
-
- } break;
- }
-
- if (found_xform) {
- r = xf.xform(r);
- found_xform=false;
- }
-
-
- if (first) {
- rect=r;
- first=false;
- } else
- rect=rect.merge(r);
- }
+void VisualServerRaster::canvas_item_set_distance_field_mode(RID p_item, bool p_distance_field) {
+ VS_CHANGED;
+ CanvasItem *canvas_item = canvas_item_owner.get( p_item );
+ ERR_FAIL_COND(!canvas_item);
- rect_dirty=false;
- return rect;
+ canvas_item->distance_field=p_distance_field;
}
+
void VisualServerRaster::canvas_item_set_transform(RID p_item, const Matrix32& p_transform) {
VS_CHANGED;
@@ -3273,7 +3560,7 @@ void VisualServerRaster::canvas_item_add_circle(RID p_item, const Point2& p_pos,
}
-void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile,const Color& p_modulate) {
+void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile,const Color& p_modulate,bool p_transpose) {
VS_CHANGED;
CanvasItem *canvas_item = canvas_item_owner.get( p_item );
ERR_FAIL_COND(!canvas_item);
@@ -3296,12 +3583,16 @@ void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p
rect->flags|=Rasterizer::CANVAS_RECT_FLIP_V;
rect->rect.size.y = -rect->rect.size.y;
}
+ if (p_transpose) {
+ rect->flags|=Rasterizer::CANVAS_RECT_TRANSPOSE;
+ SWAP(rect->rect.size.x, rect->rect.size.y);
+ }
rect->texture=p_texture;
canvas_item->rect_dirty=true;
canvas_item->commands.push_back(rect);
}
-void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate) {
+void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate,bool p_transpose) {
VS_CHANGED;
CanvasItem *canvas_item = canvas_item_owner.get( p_item );
ERR_FAIL_COND(!canvas_item);
@@ -3324,12 +3615,17 @@ void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const R
rect->flags|=Rasterizer::CANVAS_RECT_FLIP_V;
rect->rect.size.y = -rect->rect.size.y;
}
+ if (p_transpose) {
+ rect->flags|=Rasterizer::CANVAS_RECT_TRANSPOSE;
+ SWAP(rect->rect.size.x, rect->rect.size.y);
+ }
canvas_item->rect_dirty=true;
canvas_item->commands.push_back(rect);
}
+
void VisualServerRaster::canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center,const Color& p_modulate) {
VS_CHANGED;
@@ -3492,6 +3788,81 @@ void VisualServerRaster::canvas_item_add_set_blend_mode(RID p_item, MaterialBlen
canvas_item->commands.push_back(bm);
};
+void VisualServerRaster::canvas_item_set_z(RID p_item, int p_z) {
+
+ ERR_FAIL_COND(p_z<CANVAS_ITEM_Z_MIN || p_z>CANVAS_ITEM_Z_MAX);
+ VS_CHANGED;
+ CanvasItem *canvas_item = canvas_item_owner.get( p_item );
+ ERR_FAIL_COND(!canvas_item);
+ canvas_item->z=p_z;
+
+}
+
+void VisualServerRaster::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) {
+
+ VS_CHANGED;
+ CanvasItem *canvas_item = canvas_item_owner.get( p_item );
+ ERR_FAIL_COND(!canvas_item);
+ canvas_item->z_relative=p_enable;
+
+}
+
+void VisualServerRaster::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2& p_rect) {
+
+ VS_CHANGED;
+ CanvasItem *canvas_item = canvas_item_owner.get( p_item );
+ ERR_FAIL_COND(!canvas_item);
+ if (bool(canvas_item->copy_back_buffer!=NULL) !=p_enable) {
+ if (p_enable) {
+ canvas_item->copy_back_buffer = memnew( Rasterizer::CanvasItem::CopyBackBuffer );
+ } else {
+ memdelete(canvas_item->copy_back_buffer);
+ canvas_item->copy_back_buffer=NULL;
+ }
+ }
+
+ if (p_enable) {
+ canvas_item->copy_back_buffer->rect=p_rect;
+ canvas_item->copy_back_buffer->full=p_rect==Rect2();
+ }
+
+}
+
+void VisualServerRaster::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {
+
+ VS_CHANGED;
+ CanvasItem *canvas_item = canvas_item_owner.get( p_item );
+ ERR_FAIL_COND(!canvas_item);
+ canvas_item->use_parent_material=p_enable;
+
+}
+
+void VisualServerRaster::canvas_item_set_material(RID p_item, RID p_material) {
+
+ VS_CHANGED;
+ CanvasItem *canvas_item = canvas_item_owner.get( p_item );
+ ERR_FAIL_COND(!canvas_item);
+
+ if (canvas_item->material)
+ canvas_item->material->owners.erase(canvas_item);
+
+ canvas_item->material=NULL;
+
+ if (canvas_item_material_owner.owns(p_material)) {
+ canvas_item->material=canvas_item_material_owner.get(p_material);
+ canvas_item->material->owners.insert(canvas_item);
+ }
+}
+
+void VisualServerRaster::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) {
+
+ VS_CHANGED;
+ CanvasItem *canvas_item = canvas_item_owner.get( p_item );
+ ERR_FAIL_COND(!canvas_item);
+ canvas_item->sort_y=p_enable;
+}
+
+
void VisualServerRaster::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) {
VS_CHANGED;
@@ -3545,6 +3916,408 @@ void VisualServerRaster::canvas_item_raise(RID p_item) {
}
+/***** CANVAS LIGHT *******/
+
+RID VisualServerRaster::canvas_light_create() {
+
+ Rasterizer::CanvasLight *clight = memnew( Rasterizer::CanvasLight );
+ return canvas_light_owner.make_rid(clight);
+}
+
+void VisualServerRaster::canvas_light_attach_to_canvas(RID p_light,RID p_canvas){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+
+ if (clight->canvas.is_valid()) {
+
+ Canvas *canvas = canvas_owner.get(clight->canvas);
+ canvas->lights.erase(clight);
+ }
+
+ if (!canvas_owner.owns(p_canvas))
+ p_canvas=RID();
+ clight->canvas=p_canvas;
+
+ if (clight->canvas.is_valid()) {
+
+ Canvas *canvas = canvas_owner.get(clight->canvas);
+ canvas->lights.insert(clight);
+ }
+
+
+
+}
+void VisualServerRaster::canvas_light_set_enabled(RID p_light, bool p_enabled){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->enabled=p_enabled;
+
+}
+void VisualServerRaster::canvas_light_set_transform(RID p_light, const Matrix32& p_transform){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->xform=p_transform;
+
+}
+void VisualServerRaster::canvas_light_set_scale(RID p_light, float p_scale) {
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->scale=p_scale;
+
+}
+
+
+void VisualServerRaster::canvas_light_set_texture(RID p_light, RID p_texture){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->texture=p_texture;
+
+}
+void VisualServerRaster::canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->texture_offset=p_offset;
+
+}
+void VisualServerRaster::canvas_light_set_color(RID p_light, const Color& p_color){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->color=p_color;
+
+
+}
+void VisualServerRaster::canvas_light_set_height(RID p_light, float p_height){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->height=p_height;
+
+}
+
+void VisualServerRaster::canvas_light_set_energy(RID p_light, float p_energy){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->energy=p_energy;
+
+}
+
+void VisualServerRaster::canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->z_min=p_min_z;
+ clight->z_max=p_max_z;
+
+}
+
+void VisualServerRaster::canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer) {
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->layer_min=p_min_layer;
+ clight->layer_max=p_max_layer;
+
+}
+
+void VisualServerRaster::canvas_light_set_item_mask(RID p_light, int p_mask){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->item_mask=p_mask;
+
+}
+
+void VisualServerRaster::canvas_light_set_item_shadow_mask(RID p_light, int p_mask){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->item_shadow_mask=p_mask;
+
+}
+
+
+void VisualServerRaster::canvas_light_set_mode(RID p_light, CanvasLightMode p_mode) {
+
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->mode=p_mode;
+
+}
+void VisualServerRaster::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+
+ if (clight->shadow_buffer.is_valid()==p_enabled)
+ return;
+ if (p_enabled) {
+ clight->shadow_buffer=rasterizer->canvas_light_shadow_buffer_create(clight->shadow_buffer_size);
+ } else {
+ rasterizer->free(clight->shadow_buffer);
+ clight->shadow_buffer=RID();
+
+ }
+
+}
+
+void VisualServerRaster::canvas_light_set_shadow_buffer_size(RID p_light, int p_size){
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+
+ ERR_FAIL_COND(p_size<32 || p_size>16384);
+
+ clight->shadow_buffer_size=nearest_power_of_2(p_size);
+
+
+ if (clight->shadow_buffer.is_valid()) {
+ rasterizer->free(clight->shadow_buffer);
+ clight->shadow_buffer=rasterizer->canvas_light_shadow_buffer_create(clight->shadow_buffer_size);
+ }
+
+}
+
+void VisualServerRaster::canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier) {
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->shadow_esm_mult=p_multiplier;
+
+}
+
+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() {
+
+ Rasterizer::CanvasLightOccluderInstance *occluder = memnew( Rasterizer::CanvasLightOccluderInstance );
+
+ return canvas_light_occluder_owner.make_rid( occluder );
+
+}
+
+void VisualServerRaster::canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas) {
+
+ Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ if (occluder->canvas.is_valid()) {
+
+ Canvas *canvas = canvas_owner.get(occluder->canvas);
+ canvas->occluders.erase(occluder);
+ }
+
+ if (!canvas_owner.owns(p_canvas))
+ p_canvas=RID();
+
+ occluder->canvas=p_canvas;
+
+ if (occluder->canvas.is_valid()) {
+
+ Canvas *canvas = canvas_owner.get(occluder->canvas);
+ canvas->occluders.insert(occluder);
+ }
+}
+
+void VisualServerRaster::canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled){
+
+ Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ occluder->enabled=p_enabled;
+
+}
+
+void VisualServerRaster::canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon) {
+
+ Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ if (occluder->polygon.is_valid()) {
+ CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon);
+ if (occluder_poly) {
+ occluder_poly->owners.erase(occluder);
+ }
+ }
+
+ occluder->polygon=p_polygon;
+ occluder->polygon_buffer=RID();
+
+ if (occluder->polygon.is_valid()) {
+ CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon);
+ if (!occluder_poly)
+ occluder->polygon=RID();
+ ERR_FAIL_COND(!occluder_poly);
+ occluder_poly->owners.insert(occluder);
+ occluder->polygon_buffer=occluder_poly->occluder;
+ occluder->aabb_cache=occluder_poly->aabb;
+ occluder->cull_cache=occluder_poly->cull_mode;
+ }
+
+}
+
+
+
+
+void VisualServerRaster::canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform) {
+
+ Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ occluder->xform=p_xform;
+
+}
+
+void VisualServerRaster::canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask) {
+
+ Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ occluder->light_mask=p_mask;
+
+}
+
+
+RID VisualServerRaster::canvas_occluder_polygon_create() {
+
+ CanvasLightOccluderPolygon * occluder_poly = memnew( CanvasLightOccluderPolygon );
+ occluder_poly->occluder=rasterizer->canvas_light_occluder_create();
+ return canvas_light_occluder_polygon_owner.make_rid(occluder_poly);
+
+}
+
+void VisualServerRaster::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const DVector<Vector2>& p_shape, bool p_close){
+
+ if (p_shape.size()<3) {
+ canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon,p_shape);
+ return;
+ }
+
+ DVector<Vector2> lines;
+ int lc = p_shape.size()*2;
+
+ lines.resize(lc-(p_close?0:2));
+ {
+ DVector<Vector2>::Write w = lines.write();
+ DVector<Vector2>::Read r = p_shape.read();
+
+ int max=lc/2;
+ if (!p_close) {
+ max--;
+ }
+ for(int i=0;i<max;i++) {
+
+ Vector2 a = r[i];
+ Vector2 b = r[(i+1)%(lc/2)];
+ w[i*2+0]=a;
+ w[i*2+1]=b;
+ }
+
+ }
+
+ canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon,lines);
+}
+
+void VisualServerRaster::canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape) {
+
+ CanvasLightOccluderPolygon * occluder_poly = canvas_light_occluder_polygon_owner.get(p_occluder_polygon);
+ ERR_FAIL_COND(!occluder_poly);
+ ERR_FAIL_COND(p_shape.size()&1);
+
+ int lc = p_shape.size();
+ occluder_poly->aabb=Rect2();
+ {
+ DVector<Vector2>::Read r = p_shape.read();
+ for(int i=0;i<lc;i++) {
+ if (i==0)
+ occluder_poly->aabb.pos=r[i];
+ else
+ occluder_poly->aabb.expand_to(r[i]);
+ }
+ }
+
+ rasterizer->canvas_light_occluder_set_polylines(occluder_poly->occluder,p_shape);
+ for( Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=occluder_poly->owners.front();E;E=E->next()) {
+ E->get()->aabb_cache=occluder_poly->aabb;
+ }
+}
+
+void VisualServerRaster::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode) {
+
+ CanvasLightOccluderPolygon * occluder_poly = canvas_light_occluder_polygon_owner.get(p_occluder_polygon);
+ ERR_FAIL_COND(!occluder_poly);
+ occluder_poly->cull_mode=p_mode;
+ for( Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=occluder_poly->owners.front();E;E=E->next()) {
+ E->get()->cull_cache=p_mode;
+ }
+
+}
+
+RID VisualServerRaster::canvas_item_material_create() {
+
+ Rasterizer::CanvasItemMaterial *material = memnew( Rasterizer::CanvasItemMaterial );
+ return canvas_item_material_owner.make_rid(material);
+
+}
+
+void VisualServerRaster::canvas_item_material_set_shader(RID p_material, RID p_shader){
+
+ VS_CHANGED;
+ Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+ ERR_FAIL_COND(!material);
+ material->shader=p_shader;
+
+}
+void VisualServerRaster::canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value){
+
+ VS_CHANGED;
+ Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+ ERR_FAIL_COND(!material);
+ if (p_value.get_type()==Variant::NIL)
+ material->shader_param.erase(p_param);
+ else
+ material->shader_param[p_param]=p_value;
+
+
+}
+Variant VisualServerRaster::canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const{
+ Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+ ERR_FAIL_COND_V(!material,Variant());
+ if (!material->shader_param.has(p_param)) {
+ ERR_FAIL_COND_V(!material->shader.is_valid(),Variant());
+ return rasterizer->shader_get_default_param(material->shader,p_param);
+ }
+
+ return material->shader_param[p_param];
+}
+
+void VisualServerRaster::canvas_item_material_set_shading_mode(RID p_material, CanvasItemShadingMode p_mode) {
+
+ VS_CHANGED;
+ Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+ ERR_FAIL_COND(!material);
+ material->shading_mode=p_mode;
+
+}
+
+
/******** CANVAS *********/
@@ -3652,11 +4425,24 @@ void VisualServerRaster::free( RID p_rid ) {
VS_CHANGED;
- if (rasterizer->is_texture(p_rid) || rasterizer->is_material(p_rid) || rasterizer->is_skeleton(p_rid) || rasterizer->is_shader(p_rid)) {
+ if (rasterizer->is_texture(p_rid) || rasterizer->is_material(p_rid) || rasterizer->is_shader(p_rid) || rasterizer->is_environment(p_rid)) {
rasterizer->free(p_rid);
-
- } else if (rasterizer->is_mesh(p_rid) || rasterizer->is_multimesh(p_rid) || rasterizer->is_light(p_rid) || rasterizer->is_particles(p_rid) ) {
+ } else if (rasterizer->is_skeleton(p_rid)) {
+
+ Map< RID, Set<Instance*> >::Element *E=skeleton_dependency_map.find(p_rid);
+
+ if (E) {
+ //detach skeletons
+ for (Set<Instance*>::Element *F=E->get().front();F;F=F->next()) {
+
+ F->get()->data.skeleton=RID();
+ }
+ skeleton_dependency_map.erase(E);
+ }
+
+ rasterizer->free(p_rid);
+ } else if (rasterizer->is_mesh(p_rid) || rasterizer->is_multimesh(p_rid) || rasterizer->is_light(p_rid) || rasterizer->is_particles(p_rid) || rasterizer->is_immediate(p_rid)) {
//delete the resource
_free_attached_instances(p_rid);
@@ -3690,6 +4476,17 @@ void VisualServerRaster::free( RID p_rid ) {
baked_light_owner.free(p_rid);
memdelete(baked_light);
+ } else if (baked_light_sampler_owner.owns(p_rid)) {
+
+ _free_attached_instances(p_rid);
+
+ BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get(p_rid);
+ ERR_FAIL_COND(!baked_light_sampler);
+ //if (baked_light->data.octree_texture.is_valid())
+ // rasterizer->free(baked_light->data.octree_texture);
+ baked_light_sampler_owner.free(p_rid);
+ memdelete(baked_light_sampler);
+
} else if (camera_owner.owns(p_rid)) {
// delete te camera
@@ -3741,8 +4538,12 @@ void VisualServerRaster::free( RID p_rid ) {
instance_set_room(p_rid,RID());
instance_set_scenario(p_rid,RID());
instance_geometry_set_baked_light(p_rid,RID());
+ instance_geometry_set_baked_light_sampler(p_rid,RID());
instance_set_base(p_rid,RID());
+ if (instance->data.skeleton.is_valid())
+ instance_attach_skeleton(p_rid,RID());
+
instance_owner.free(p_rid);
memdelete(instance);
@@ -3767,7 +4568,17 @@ void VisualServerRaster::free( RID p_rid ) {
canvas->child_items[i].item->parent=RID();
}
-
+
+ for (Set<Rasterizer::CanvasLight*>::Element *E=canvas->lights.front();E;E=E->next()) {
+
+ E->get()->canvas=RID();
+ }
+
+ for (Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=canvas->occluders.front();E;E=E->next()) {
+
+ E->get()->canvas=RID();
+ }
+
canvas_owner.free( p_rid );
memdelete( canvas );
@@ -3796,9 +4607,82 @@ void VisualServerRaster::free( RID p_rid ) {
canvas_item->child_items[i]->parent=RID();
}
+ if (canvas_item->material) {
+ canvas_item->material->owners.erase(canvas_item);
+ }
+
canvas_item_owner.free( p_rid );
memdelete( canvas_item );
+
+ } else if (canvas_item_material_owner.owns(p_rid)) {
+
+ Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get(p_rid);
+ ERR_FAIL_COND(!material);
+ for(Set<Rasterizer::CanvasItem*>::Element *E=material->owners.front();E;E=E->next()) {
+
+ E->get()->material=NULL;
+ }
+
+ canvas_item_material_owner.free(p_rid);
+ memdelete(material);
+
+ } else if (canvas_light_owner.owns(p_rid)) {
+
+ Rasterizer::CanvasLight *canvas_light = canvas_light_owner.get(p_rid);
+ ERR_FAIL_COND(!canvas_light);
+
+ if (canvas_light->canvas.is_valid()) {
+ Canvas* canvas = canvas_owner.get(canvas_light->canvas);
+ if (canvas)
+ canvas->lights.erase(canvas_light);
+ }
+
+ if (canvas_light->shadow_buffer.is_valid())
+ rasterizer->free(canvas_light->shadow_buffer);
+
+ canvas_light_owner.free( p_rid );
+ memdelete( canvas_light );
+
+ } else if (canvas_light_occluder_owner.owns(p_rid)) {
+
+ Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_rid);
+ ERR_FAIL_COND(!occluder);
+
+ if (occluder->polygon.is_valid()) {
+
+ CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(occluder->polygon);
+ if (occluder_poly) {
+ occluder_poly->owners.erase(occluder);
+ }
+
+ }
+
+ if (occluder->canvas.is_valid() && canvas_owner.owns(occluder->canvas)) {
+
+ Canvas *canvas = canvas_owner.get(occluder->canvas);
+ canvas->occluders.erase(occluder);
+
+ }
+
+ canvas_light_occluder_owner.free( p_rid );
+ memdelete(occluder);
+
+ } else if (canvas_light_occluder_polygon_owner.owns(p_rid)) {
+
+ CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_rid);
+ ERR_FAIL_COND(!occluder_poly);
+ rasterizer->free(occluder_poly->occluder);
+
+ while(occluder_poly->owners.size()) {
+
+ occluder_poly->owners.front()->get()->polygon=RID();
+ occluder_poly->owners.erase( occluder_poly->owners.front() );
+ }
+
+ canvas_light_occluder_polygon_owner.free( p_rid );
+ memdelete(occluder_poly);
+
} else if (scenario_owner.owns(p_rid)) {
Scenario *scenario=scenario_owner.get(p_rid);
@@ -4350,7 +5234,6 @@ void VisualServerRaster::_light_instance_update_lispsm_shadow(Instance *p_light,
AABB proj_space_aabb;
- float max_d,min_d;
{
@@ -4883,6 +5766,15 @@ void* VisualServerRaster::instance_pair(void *p_self, OctreeElementID, Instance
//attempt to conncet portal A (will go through B anyway)
//this is a little hackish, but works fine in practice
+ } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+
+ if (B->base_type==INSTANCE_BAKED_LIGHT) {
+ SWAP(A,B);
+ }
+
+ ERR_FAIL_COND_V(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER,NULL);
+ B->baked_light_sampler_info->baked_lights.insert(A);
+
} else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
if (B->base_type==INSTANCE_ROOM)
@@ -4932,6 +5824,15 @@ void VisualServerRaster::instance_unpair(void *p_self, OctreeElementID, Instance
self->_portal_attempt_connect(A);
self->_portal_attempt_connect(B);
+ } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+
+ if (B->base_type==INSTANCE_BAKED_LIGHT) {
+ SWAP(A,B);
+ }
+
+ ERR_FAIL_COND(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER);
+ B->baked_light_sampler_info->baked_lights.erase(A);
+
} else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
if (B->base_type==INSTANCE_ROOM)
@@ -5123,6 +6024,322 @@ void VisualServerRaster::_cull_room(Camera *p_camera, Instance *p_room,Instance
}
+void VisualServerRaster::_process_sampled_light(const Transform& p_camera,Instance *p_sampled_light,bool p_linear_colorspace) {
+
+
+ BakedLightSampler *sampler_opts = p_sampled_light->baked_light_sampler_info->sampler;
+ int res = sampler_opts->resolution;
+ int dp_size = res*res*2;
+ Color * dp_map = (Color*)alloca( sizeof(Color)*dp_size); //allocate the dual parabolloid colors
+ Vector3 * dp_normals = (Vector3*)alloca( sizeof(Vector3)*dp_size); //allocate the dual parabolloid normals
+ const Vector3 * dp_src_normals = p_sampled_light->baked_light_sampler_info->sampler->dp_cache.ptr();
+
+
+ if (!p_sampled_light->baked_light_sampler_info->sampled_light.is_valid() || p_sampled_light->baked_light_sampler_info->resolution!=sampler_opts->resolution) {
+ if (p_sampled_light->baked_light_sampler_info->sampled_light.is_valid()) {
+ rasterizer->free(p_sampled_light->baked_light_sampler_info->sampled_light);
+ }
+
+ p_sampled_light->baked_light_sampler_info->resolution=sampler_opts->resolution;
+ p_sampled_light->baked_light_sampler_info->sampled_light=rasterizer->sampled_light_dp_create(sampler_opts->resolution,sampler_opts->resolution*2);
+
+
+ }
+
+
+ zeromem(dp_map,sizeof(Color)*dp_size);
+ bool valid=false;
+ int samples=0;
+
+
+ for(Set<Instance*>::Element *E=p_sampled_light->baked_light_sampler_info->baked_lights.front();E;E=E->next()) {
+
+ Instance *bl = E->get();
+ if (bl->baked_light_info->baked_light->sampler.size()==0)
+ continue; //not usable
+
+
+ Matrix3 norm_xform = bl->baked_light_info->affine_inverse.basis;//.inverse();
+ for(int i=0;i<dp_size;i++) {
+ dp_normals[i]=norm_xform.xform(dp_src_normals[i]).normalized();
+ }
+
+ //normals in place
+
+
+ //sample octree
+
+ float r = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_RADIUS];
+ float att = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_ATTENUATION];
+ float str = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_STRENGTH];
+ Vector3 s = p_sampled_light->data.transform.basis.get_scale();
+
+ r*=MAX(MAX(s.x,s.y),s.z);
+ AABB sample_aabb= bl->data.transform.affine_inverse().xform(AABB(Vector3(-r,-r,-r)+p_sampled_light->data.transform.origin,Vector3(r*2,r*2,r*2)));
+ //ok got octree local AABB
+
+ DVector<int>::Read rp = bl->baked_light_info->baked_light->sampler.read();
+ const int *rptr = rp.ptr();
+
+ int first = rptr[1];
+ int depth = rptr[2];
+ bool islinear = rptr[3]&1;
+ depth+=1;
+
+ AABB aabb;
+ aabb.pos.x=decode_float((const uint8_t*)&rptr[4]);
+ aabb.pos.y=decode_float((const uint8_t*)&rptr[5]);
+ aabb.pos.z=decode_float((const uint8_t*)&rptr[6]);
+ aabb.size.x=decode_float((const uint8_t*)&rptr[7]);
+ aabb.size.y=decode_float((const uint8_t*)&rptr[8]);
+ aabb.size.z=decode_float((const uint8_t*)&rptr[9]);
+
+ uint32_t *stack=(uint32_t*)alloca(depth*sizeof(uint32_t));
+ int *stack_ptr=(int*)alloca(depth*sizeof(int));
+ AABB *aabb_stack=(AABB*)alloca(depth*sizeof(AABB));
+
+ stack[0]=0;
+ stack_ptr[0]=first;
+ aabb_stack[0]=aabb;
+ Vector3 center = sample_aabb.pos + sample_aabb.size * 0.5;
+
+
+ int stack_pos=0;
+ Color max_col;
+
+ //int reso = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_DETAIL_RATIO];
+
+ int lalimit = sample_aabb.get_longest_axis_index();
+ float limit = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_DETAIL_RATIO]*sample_aabb.size[lalimit];
+
+
+ while(true) {
+
+
+ bool leaf = (rptr[ stack_ptr[stack_pos] ]>>16)==0;
+
+ if (aabb_stack[stack_pos].size[lalimit]<limit) {
+ leaf=true;
+ }
+
+
+ if (leaf) {
+
+ Vector3 from = aabb_stack[stack_pos].pos + aabb_stack[stack_pos].size * 0.5;
+ Vector3 norm = (from-center).normalized();
+
+
+ Color col;
+ col.r = ((rptr[ stack_ptr[stack_pos] ]&0xFFFF)/256.0);
+ col.g = ((rptr[ stack_ptr[stack_pos]+1 ]>>16)/256.0);
+ col.b = ((rptr[ stack_ptr[stack_pos]+1 ]&0xFFFF)/256.0);
+
+
+ max_col.r = MAX(max_col.r,col.r);
+ max_col.g = MAX(max_col.g,col.g);
+ max_col.b = MAX(max_col.b,col.b);
+
+ if (!islinear && p_linear_colorspace) {
+ col=col.to_linear();
+ }
+
+ float distance;
+
+ if (aabb_stack[stack_pos].has_point(center)) {
+ distance=0;
+ } else {
+
+ Vector3 support = aabb_stack[stack_pos].get_support(norm);
+ distance = Math::absf(norm.dot(support)-norm.dot(center));
+
+ }
+
+ if (distance>r)
+ distance=r;
+
+ float mult = Math::pow(1.0-distance/r,att)*str;
+ if (mult>0) {
+ col.r*=mult;
+ col.g*=mult;
+ col.b*=mult;
+
+
+
+ for(int i=0;i<dp_size;i++) {
+ float mult2 = norm.dot(dp_normals[i]);
+ if (mult2<0)
+ mult2=0;
+ Color col2(col.r*mult2,col.g*mult2,col.b*mult2,1.0);
+ dp_map[i].r=MAX(dp_map[i].r,col2.r);
+ dp_map[i].g=MAX(dp_map[i].g,col2.g);
+ dp_map[i].b=MAX(dp_map[i].b,col2.b);
+ }
+
+ }
+
+ samples++;
+ //nothing is valid unless you hit a leaf
+ valid=true;
+ stack_pos--;
+ } else if ((stack[stack_pos]&0xFF)<8) {
+
+ int i = stack[stack_pos]&0xFF;
+ int base = (stack[stack_pos]>>8);
+
+ if (!((rptr[ stack_ptr[stack_pos] ]>>16)&(1<<i))) {
+ //no bit, no test
+ stack[stack_pos]=(base<<8)+(i+1);
+ continue;
+ }
+
+ stack[stack_pos]=((base+1)<<8)+(i+1);
+
+ AABB child_aabb = aabb_stack[stack_pos];
+ child_aabb.size*=0.5;
+ if (i&1)
+ child_aabb.pos.x+=child_aabb.size.x;
+ if (i&2)
+ child_aabb.pos.y+=child_aabb.size.y;
+ if (i&4)
+ child_aabb.pos.z+=child_aabb.size.z;
+
+ if (!child_aabb.intersects(sample_aabb)) {
+ continue;
+ }
+
+ if (child_aabb.encloses(sample_aabb)) {
+ stack[stack_pos]=(base<<8)|8; //don't test the rest
+ }
+
+ stack_pos++;
+ ERR_FAIL_COND(stack_pos>=depth);
+
+ stack[stack_pos]=0;
+ stack_ptr[stack_pos]=rptr[ stack_ptr[stack_pos-1]+2+base ];
+ aabb_stack[stack_pos]=child_aabb;
+ } else {
+ stack_pos--;
+ if (stack_pos<0)
+ break;
+ }
+ }
+
+
+ }
+
+ //print_line("samples "+itos(samples) );
+
+ if (valid) {
+
+ for(int i=0;i<res;i++) {
+ //average seams to avoid aliasing
+ {
+ //top
+ int ofs1 = i;
+ int ofs2 = dp_size-res+i;
+ Color avg(
+ (dp_map[ofs1].r+dp_map[ofs2].r)*0.5,
+ (dp_map[ofs1].g+dp_map[ofs2].g)*0.5,
+ (dp_map[ofs1].b+dp_map[ofs2].b)*0.5,
+ 1.0
+ );
+ dp_map[ofs1]=avg;
+ dp_map[ofs2]=avg;
+ }
+ {
+ //bottom
+ int ofs1 = res*res-res+i;
+ int ofs2 = res*res+i;
+ Color avg(
+ (dp_map[ofs1].r+dp_map[ofs2].r)*0.5,
+ (dp_map[ofs1].g+dp_map[ofs2].g)*0.5,
+ (dp_map[ofs1].b+dp_map[ofs2].b)*0.5,
+ 1.0
+ );
+ dp_map[ofs1]=avg;
+ dp_map[ofs2]=avg;
+ }
+ {
+ //left
+ int ofs1 = i*res;
+ int ofs2 = res*res+(res-i-1)*res;
+ Color avg(
+ (dp_map[ofs1].r+dp_map[ofs2].r)*0.5,
+ (dp_map[ofs1].g+dp_map[ofs2].g)*0.5,
+ (dp_map[ofs1].b+dp_map[ofs2].b)*0.5,
+ 1.0
+ );
+ dp_map[ofs1]=avg;
+ dp_map[ofs2]=avg;
+ }
+ {
+ //right
+ int ofs1 = i*res+(res-1);
+ int ofs2 = res*res+(res-i-1)*res+(res-1);
+ Color avg(
+ (dp_map[ofs1].r+dp_map[ofs2].r)*0.5,
+ (dp_map[ofs1].g+dp_map[ofs2].g)*0.5,
+ (dp_map[ofs1].b+dp_map[ofs2].b)*0.5,
+ 1.0
+ );
+ dp_map[ofs1]=avg;
+ dp_map[ofs2]=avg;
+ }
+
+ }
+
+ rasterizer->sampled_light_dp_update(p_sampled_light->baked_light_sampler_info->sampled_light,dp_map,1.0);
+ for(Set<Instance*>::Element *F=p_sampled_light->baked_light_sampler_info->owned_instances.front();F;F=F->next()) {
+
+ F->get()->data.sampled_light=p_sampled_light->baked_light_sampler_info->sampled_light;
+ }
+
+
+ } else {
+
+ for(Set<Instance*>::Element *F=p_sampled_light->baked_light_sampler_info->owned_instances.front();F;F=F->next()) {
+
+ F->get()->data.sampled_light=RID(); //do not use because nothing close
+ }
+ }
+
+
+
+
+/*
+ highp vec3 vtx = vertex_interp;
+ vtx.z*=dual_paraboloid.y; //side to affect
+ vtx.z+=0.01;
+ dp_clip=vtx.z;
+ highp float len=length( vtx );
+ vtx=normalize(vtx);
+ vtx.xy/=1.0+vtx.z;
+ vtx.z = len*dual_paraboloid.x; // it's a reciprocal(len - z_near) / (z_far - z_near);
+ vtx+=normalize(vtx)*0.025;
+ vtx.z = vtx.z * 2.0 - 1.0; // fit to clipspace
+ vertex_interp=vtx;
+*/
+
+
+
+
+}
+
+
+void VisualServerRaster::_render_no_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario) {
+ RID environment;
+ if (p_scenario->environment.is_valid())
+ environment=p_scenario->environment;
+ else
+ environment=p_scenario->fallback_environment;
+
+ rasterizer->set_camera(Transform(),CameraMatrix(),false);
+ rasterizer->begin_scene(p_viewport->viewport_data,environment,p_scenario->debug);
+ rasterizer->set_viewport(viewport_rect);
+ rasterizer->end_scene();
+}
+
+
void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario) {
@@ -5132,7 +6349,8 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
/* STEP 1 - SETUP CAMERA */
CameraMatrix camera_matrix;
-
+ bool ortho=false;
+
switch(p_camera->type) {
case Camera::ORTHOGONAL: {
@@ -5144,6 +6362,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
p_camera->vaspect
);
+ ortho=true;
} break;
case Camera::PERSPECTIVE: {
@@ -5155,12 +6374,13 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
p_camera->vaspect
);
+ ortho=false;
} break;
}
- rasterizer->set_camera(p_camera->transform, camera_matrix);
+ rasterizer->set_camera(p_camera->transform, camera_matrix,ortho);
Vector<Plane> planes = camera_matrix.get_projection_planes(p_camera->transform);
@@ -5174,6 +6394,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
/* STEP 2 - CULL */
int cull_count = p_scenario->octree.cull_convex(planes,instance_cull_result,MAX_INSTANCE_CULL);
light_cull_count=0;
+ light_samplers_culled=0;
/* print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0));
print_line("OTO: "+itos(p_scenario->octree.get_octant_count()));
@@ -5334,6 +6555,8 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
keep=true;
}
+
+
}
@@ -5346,6 +6569,13 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
cull_range.min=min;
if (max>cull_range.max)
cull_range.max=max;
+
+ if (ins->sampled_light && ins->sampled_light->baked_light_sampler_info->last_pass!=render_pass) {
+ if (light_samplers_culled<MAX_LIGHT_SAMPLERS) {
+ light_sampler_cull_result[light_samplers_culled++]=ins->sampled_light;
+ ins->sampled_light->baked_light_sampler_info->last_pass=render_pass;
+ }
+ }
}
}
@@ -5425,7 +6655,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
}
- {
+ { //this should eventually change to
//assign shadows by distance to camera
SortArray<Instance*,_InstanceLightsort> sorter;
sorter.sort(light_cull_result,light_cull_count);
@@ -5446,15 +6676,31 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
}
}
+ /* ENVIRONMENT */
-
- /* STEP 6 - PROCESS GEOMETRY AND DRAW SCENE*/
-
RID environment;
if (p_camera->env.is_valid()) //camera has more environment priority
environment=p_camera->env;
- else
+ else if (p_scenario->environment.is_valid())
environment=p_scenario->environment;
+ else
+ environment=p_scenario->fallback_environment;
+
+
+ /* STEP 6 - SAMPLE BAKED LIGHT */
+
+ bool islinear =false;
+ if (environment.is_valid()) {
+ islinear = rasterizer->environment_is_fx_enabled(environment,VS::ENV_FX_SRGB);
+ }
+
+ for(int i=0;i<light_samplers_culled;i++) {
+
+ _process_sampled_light(p_camera->transform,light_sampler_cull_result[i],islinear);
+ }
+
+ /* STEP 7 - PROCESS GEOMETRY AND DRAW SCENE*/
+
rasterizer->begin_scene(p_viewport->viewport_data,environment,p_scenario->debug);
rasterizer->set_viewport(viewport_rect);
@@ -5497,7 +6743,42 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
rasterizer->end_scene();
}
-void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity) {
+
+void VisualServerRaster::_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) {
+
+
+ static const int z_range = CANVAS_ITEM_Z_MAX-CANVAS_ITEM_Z_MIN+1;
+ Rasterizer::CanvasItem *z_list[z_range];
+ Rasterizer::CanvasItem *z_last_list[z_range];
+
+ for(int i=0;i<z_range;i++) {
+ z_list[i]=NULL;
+ z_last_list[i]=NULL;
+ }
+
+
+ _render_canvas_item(p_canvas_item,p_transform,p_clip_rect,1.0,0,z_list,z_last_list,NULL,NULL);
+
+ for(int i=0;i<z_range;i++) {
+ if (!z_list[i])
+ continue;
+ rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_modulate,p_lights);
+ }
+
+}
+
+
+void VisualServerRaster::_render_canvas_item_viewport(VisualServer* p_self,void *p_vp,const Rect2& p_rect) {
+
+ VisualServerRaster *self=(VisualServerRaster*)(p_self);
+ Viewport *vp=(Viewport*)p_vp;
+ self->_draw_viewport(vp,p_rect.pos.x,p_rect.pos.y,p_rect.size.x,p_rect.size.y);
+ self->rasterizer->canvas_begin();
+
+}
+
+
+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;
@@ -5516,237 +6797,230 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
if (global_rect.intersects(p_clip_rect) && ci->viewport.is_valid() && viewport_owner.owns(ci->viewport)) {
- Viewport *vp = viewport_owner.get(ci->viewport);
+ Viewport *vp = viewport_owner.get(ci->viewport);
Point2i from = xform.get_origin() + Point2(viewport_rect.x,viewport_rect.y);
Point2i size = rect.size;
size.x *= xform[0].length();
size.y *= xform[1].length();
+ ci->vp_render = memnew( Rasterizer::CanvasItem::ViewportRender );
+ ci->vp_render->owner=this;
+ ci->vp_render->udata=vp;
+ ci->vp_render->rect=Rect2(from.x,
+ from.y,
+ size.x,
+ size.y);
+/*
_draw_viewport(vp,
from.x,
from.y,
size.x,
size.y);
+*/
+ //rasterizer->canvas_begin();
+ } else {
+ ci->vp_render=NULL;
+ }
- rasterizer->canvas_begin();
+ if (ci->use_parent_material && p_material_owner)
+ ci->material_owner=p_material_owner;
+ else {
+ p_material_owner=ci;
+ ci->material_owner=NULL;
}
- int s = ci->commands.size();
- bool reclip=false;
float opacity = ci->opacity * p_opacity;
-#ifndef ONTOP_DISABLED
- CanvasItem **child_items = ci->child_items.ptr();
+
int child_item_count=ci->child_items.size();
- int top_item_count=0;
- CanvasItem **top_items=(CanvasItem**)alloca(child_item_count*sizeof(CanvasItem*));
+ CanvasItem **child_items=(CanvasItem**)alloca(child_item_count*sizeof(CanvasItem*));
+ copymem(child_items,ci->child_items.ptr(),child_item_count*sizeof(CanvasItem*));
if (ci->clip) {
- rasterizer->canvas_set_clip(true,global_rect);
- canvas_clip=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 {
+ ci->final_clip_owner=p_canvas_clip;
}
+ if (ci->sort_y) {
+
+ SortArray<CanvasItem*,CanvasItemPtrSort> sorter;
+ sorter.sort(child_items,child_item_count);
+ }
+
+ if (ci->z_relative)
+ p_z=CLAMP(p_z+ci->z,CANVAS_ITEM_Z_MIN,CANVAS_ITEM_Z_MAX);
+ else
+ p_z=ci->z;
+
for(int i=0;i<child_item_count;i++) {
if (child_items[i]->ontop)
- top_items[top_item_count++]=child_items[i];
- else {
- _render_canvas_item(child_items[i],xform,p_clip_rect,opacity);
- }
+ continue;
+ _render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_material_owner);
}
-#endif
- if (s!=0) {
+ if (ci->copy_back_buffer) {
- //Rect2 rect( ci->rect.pos + p_ofs, ci->rect.size);
+ ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect);
+ }
- if (p_clip_rect.intersects(global_rect)) {
+ if ((!ci->commands.empty() && p_clip_rect.intersects(global_rect)) || ci->vp_render || ci->copy_back_buffer) {
+ //something to draw?
+ ci->final_transform=xform;
+ 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;
- rasterizer->canvas_begin_rect(xform);
- rasterizer->canvas_set_opacity( opacity * ci->self_opacity );
- rasterizer->canvas_set_blend_mode( ci->blend_mode );
+ int zidx = p_z-CANVAS_ITEM_Z_MIN;
- CanvasItem::Command **commands = &ci->commands[0];
+ if (z_last_list[zidx]) {
+ z_last_list[zidx]->next=ci;
+ z_last_list[zidx]=ci;
- for (int i=0;i<s;i++) {
+ } else {
+ z_list[zidx]=ci;
+ z_last_list[zidx]=ci;
+ }
- CanvasItem::Command *c=commands[i];
- switch(c->type) {
- case CanvasItem::Command::TYPE_LINE: {
- CanvasItem::CommandLine* line = static_cast<CanvasItem::CommandLine*>(c);
- rasterizer->canvas_draw_line(line->from,line->to,line->color,line->width);
- } break;
- case CanvasItem::Command::TYPE_RECT: {
+ ci->next=NULL;
- CanvasItem::CommandRect* rect = static_cast<CanvasItem::CommandRect*>(c);
-// rasterizer->canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate);
-#if 0
- int flags=0;
+ }
- if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) {
- flags|=Rasterizer::CANVAS_RECT_REGION;
- }
- if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) {
- flags|=Rasterizer::CANVAS_RECT_TILE;
- }
- if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) {
+ for(int i=0;i<child_item_count;i++) {
- flags|=Rasterizer::CANVAS_RECT_FLIP_H;
- }
- if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) {
+ if (!child_items[i]->ontop)
+ continue;
+ _render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_material_owner);
+ }
- flags|=Rasterizer::CANVAS_RECT_FLIP_V;
- }
-#else
+}
- int flags=rect->flags;
-#endif
- rasterizer->canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate);
+void VisualServerRaster::_light_mask_canvas_items(int p_z,Rasterizer::CanvasItem *p_canvas_item,Rasterizer::CanvasLight *p_masked_lights) {
- } break;
- case CanvasItem::Command::TYPE_STYLE: {
+ if (!p_masked_lights)
+ return;
- CanvasItem::CommandStyle* style = static_cast<CanvasItem::CommandStyle*>(c);
- rasterizer->canvas_draw_style_box(style->rect,style->texture,style->margin,style->draw_center,style->color);
+ Rasterizer::CanvasItem *ci=p_canvas_item;
- } break;
- case CanvasItem::Command::TYPE_PRIMITIVE: {
+ while(ci) {
- CanvasItem::CommandPrimitive* primitive = static_cast<CanvasItem::CommandPrimitive*>(c);
- rasterizer->canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width);
- } break;
- case CanvasItem::Command::TYPE_POLYGON: {
+ Rasterizer::CanvasLight *light=p_masked_lights;
+ while(light) {
- CanvasItem::CommandPolygon* polygon = static_cast<CanvasItem::CommandPolygon*>(c);
- rasterizer->canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1);
+ 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;
+ }
- } break;
+ light=light->mask_next_ptr;
+ }
- case CanvasItem::Command::TYPE_POLYGON_PTR: {
+ ci=ci->next;
+ }
- CanvasItem::CommandPolygonPtr* polygon = static_cast<CanvasItem::CommandPolygonPtr*>(c);
- rasterizer->canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false);
- } break;
- case CanvasItem::Command::TYPE_CIRCLE: {
- CanvasItem::CommandCircle* circle = static_cast<CanvasItem::CommandCircle*>(c);
- static const int numpoints=32;
- Vector2 points[numpoints+1];
- points[numpoints]=circle->pos;
- int indices[numpoints*3];
- for(int i=0;i<numpoints;i++) {
- points[i]=circle->pos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius;
- indices[i*3+0]=i;
- indices[i*3+1]=(i+1)%numpoints;
- indices[i*3+2]=numpoints;
- }
- rasterizer->canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true);
- //rasterizer->canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1);
- } break;
- case CanvasItem::Command::TYPE_TRANSFORM: {
-
- CanvasItem::CommandTransform* transform = static_cast<CanvasItem::CommandTransform*>(c);
- rasterizer->canvas_set_transform(transform->xform);
- } break;
- case CanvasItem::Command::TYPE_BLEND_MODE: {
-
- CanvasItem::CommandBlendMode* bm = static_cast<CanvasItem::CommandBlendMode*>(c);
- rasterizer->canvas_set_blend_mode(bm->blend_mode);
-
- } break;
- case CanvasItem::Command::TYPE_CLIP_IGNORE: {
-
- CanvasItem::CommandClipIgnore* ci = static_cast<CanvasItem::CommandClipIgnore*>(c);
- if (canvas_clip!=Rect2()) {
-
- if (ci->ignore!=reclip) {
- if (ci->ignore) {
-
- rasterizer->canvas_set_clip(false,Rect2());
- reclip=true;
- } else {
- rasterizer->canvas_set_clip(true,canvas_clip);
- reclip=false;
- }
- }
- }
+}
+void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights,Rasterizer::CanvasLight *p_masked_lights) {
+ rasterizer->canvas_begin();
- } break;
- }
- }
- rasterizer->canvas_end_rect();
+ int l = p_canvas->child_items.size();
+ Canvas::ChildItem *ci=p_canvas->child_items.ptr();
+
+ bool has_mirror=false;
+ for(int i=0;i<l;i++) {
+ if (ci[i].mirror.x || ci[i].mirror.y) {
+ has_mirror=true;
+ break;
}
}
+ Rect2 clip_rect(viewport_rect.x,viewport_rect.y,viewport_rect.width,viewport_rect.height);
+ if (!has_mirror) {
- if (reclip) {
+ static const int z_range = CANVAS_ITEM_Z_MAX-CANVAS_ITEM_Z_MIN+1;
+ Rasterizer::CanvasItem *z_list[z_range];
+ Rasterizer::CanvasItem *z_last_list[z_range];
- rasterizer->canvas_set_clip(true,canvas_clip);
- }
-
-#ifndef ONTOP_DISABLED
+ for(int i=0;i<z_range;i++) {
+ z_list[i]=NULL;
+ z_last_list[i]=NULL;
+ }
+ for(int i=0;i<l;i++) {
+ _render_canvas_item(ci[i].item,p_transform,clip_rect,1.0,0,z_list,z_last_list,NULL,NULL);
+ }
- for(int i=0;i<top_item_count;i++) {
+ for(int i=0;i<z_range;i++) {
+ if (!z_list[i])
+ continue;
- _render_canvas_item(top_items[i],xform,p_clip_rect,opacity);
- }
+ if (p_masked_lights) {
+ _light_mask_canvas_items(CANVAS_ITEM_Z_MIN+i,z_list[i],p_masked_lights);
+ }
-#else
- for(int i=0;i<p_canvas_item->child_items.size();i++) {
+ rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_canvas->modulate,p_lights);
+ }
+ } else {
- _render_canvas_item(p_canvas_item->child_items[i],xform,p_clip_rect,opacity);
- }
-#endif
+ for(int i=0;i<l;i++) {
+ Canvas::ChildItem& ci=p_canvas->child_items[i];
+ _render_canvas_item_tree(ci.item,p_transform,clip_rect,p_canvas->modulate,p_lights);
- if (ci->clip) {
- rasterizer->canvas_set_clip(false,Rect2());
- canvas_clip=Rect2();
- }
+ //mirroring (useful for scrolling backgrounds)
+ if (ci.mirror.x!=0) {
-}
+ Matrix32 xform2 = p_transform * Matrix32(0,Vector2(ci.mirror.x,0));
+ _render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);
+ }
+ if (ci.mirror.y!=0) {
-void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform) {
+ Matrix32 xform2 = p_transform * Matrix32(0,Vector2(0,ci.mirror.y));
+ _render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);
+ }
+ if (ci.mirror.y!=0 && ci.mirror.x!=0) {
- rasterizer->canvas_begin();
+ Matrix32 xform2 = p_transform * Matrix32(0,ci.mirror);
+ _render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);
+ }
- int l = p_canvas->child_items.size();
+ }
+ }
- for(int i=0;i<l;i++) {
+}
- Canvas::ChildItem& ci=p_canvas->child_items[i];
- _render_canvas_item(ci.item,p_transform,Rect2(viewport_rect.x,viewport_rect.y,viewport_rect.width,viewport_rect.height),1);
- //mirroring (useful for scrolling backgrounds)
- if (ci.mirror.x!=0) {
+void VisualServerRaster::_draw_viewport_camera(Viewport *p_viewport,bool p_ignore_camera) {
- Matrix32 xform2 = p_transform * Matrix32(0,Vector2(ci.mirror.x,0));
- _render_canvas_item(ci.item,xform2,Rect2(viewport_rect.x,viewport_rect.y,viewport_rect.width,viewport_rect.height),1);
- }
- if (ci.mirror.y!=0) {
- Matrix32 xform2 = p_transform * Matrix32(0,Vector2(0,ci.mirror.y));
- _render_canvas_item(ci.item,xform2,Rect2(viewport_rect.x,viewport_rect.y,viewport_rect.width,viewport_rect.height),1);
- }
- if (ci.mirror.y!=0 && ci.mirror.x!=0) {
+ Camera *camera=NULL;
+ if (camera_owner.owns( p_viewport->camera ))
+ camera=camera_owner.get( p_viewport->camera );
+ Scenario *scenario = scenario_owner.get( p_viewport->scenario );
- Matrix32 xform2 = p_transform * Matrix32(0,ci.mirror);
- _render_canvas_item(ci.item,xform2,Rect2(viewport_rect.x,viewport_rect.y,viewport_rect.width,viewport_rect.height),1);
- }
+ _update_instances(); // check dirty instances before rendering
- }
+ if (p_ignore_camera)
+ _render_no_camera(p_viewport, camera,scenario );
+ else
+ _render_camera(p_viewport, camera,scenario );
}
-
void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ofs_y,int p_parent_w,int p_parent_h) {
ViewportRect desired_rect=p_viewport->rect;
@@ -5765,6 +7039,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
desired_rect.x+=p_ofs_x;
desired_rect.y+=p_ofs_y;
+
// if the viewport is different than the actual one, change it
if ( p_viewport->render_target.is_valid() || viewport_rect.x != desired_rect.x ||
@@ -5774,25 +7049,53 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
viewport_rect=desired_rect;
- rasterizer->set_viewport(viewport_rect);
+ rasterizer->set_viewport(viewport_rect);
}
/* Camera should always be BEFORE any other 3D */
- if (!p_viewport->hide_scenario && camera_owner.owns(p_viewport->camera) && scenario_owner.owns(p_viewport->scenario)) {
+ bool scenario_draw_canvas_bg=false;
+ int scenario_canvas_max_layer=0;
- Camera *camera = camera_owner.get( p_viewport->camera );
- Scenario *scenario = scenario_owner.get( p_viewport->scenario );
+ if (!p_viewport->hide_canvas && !p_viewport->disable_environment && scenario_owner.owns(p_viewport->scenario)) {
- _update_instances(); // check dirty instances before rendering
+ Scenario *scenario=scenario_owner.get(p_viewport->scenario);
+ if (scenario->environment.is_valid()) {
+ if (rasterizer->is_environment(scenario->environment)) {
+ scenario_draw_canvas_bg=rasterizer->environment_get_background(scenario->environment)==VS::ENV_BG_CANVAS;
+ scenario_canvas_max_layer=rasterizer->environment_get_background_param(scenario->environment,VS::ENV_BG_PARAM_CANVAS_MAX_LAYER);
+ }
+ }
+ }
- _render_camera(p_viewport, camera,scenario );
+ bool can_draw_3d=!p_viewport->hide_scenario && camera_owner.owns(p_viewport->camera) && scenario_owner.owns(p_viewport->scenario);
+
+
+ if (scenario_draw_canvas_bg) {
+
+ rasterizer->begin_canvas_bg();
+ }
+
+ if (!scenario_draw_canvas_bg && can_draw_3d) {
+
+ _draw_viewport_camera(p_viewport,false);
} else if (true /*|| !p_viewport->canvas_list.empty()*/){
//clear the viewport black because of no camera? i seriously should..
- rasterizer->clear_viewport(clear_color);
+ if (p_viewport->render_target_clear_on_new_frame || p_viewport->render_target_clear) {
+ if (p_viewport->transparent_bg) {
+ rasterizer->clear_viewport(Color(0,0,0,0));
+ }
+ else {
+ Color cc=clear_color;
+ if (scenario_draw_canvas_bg)
+ cc.a=0;
+ rasterizer->clear_viewport(cc);
+ }
+ p_viewport->render_target_clear=false;
+ }
}
if (!p_viewport->hide_canvas) {
@@ -5800,21 +7103,151 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
Map<Viewport::CanvasKey,Viewport::CanvasData*> canvas_map;
+ 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;
+
for (Map<RID,Viewport::CanvasData>::Element *E=p_viewport->canvas_map.front();E;E=E->next()) {
+
+ Matrix32 xf = p_viewport->global_transform * E->get().transform;
+
+ //find lights in canvas
+
+
+ for(Set<Rasterizer::CanvasLight*>::Element *F=E->get().canvas->lights.front();F;F=F->next()) {
+
+
+ Rasterizer::CanvasLight* cl=F->get();
+ if (cl->enabled && cl->texture.is_valid()) {
+ //not super efficient..
+ Size2 tsize(rasterizer->texture_get_width(cl->texture),rasterizer->texture_get_height(cl->texture));
+ tsize*=cl->scale;
+
+ Vector2 offset=tsize/2.0;
+ cl->rect_cache=Rect2(-offset+cl->texture_offset,tsize);
+ cl->xform_cache=xf * cl->xform;
+
+
+ if (clip_rect.intersects_transformed(cl->xform_cache,cl->rect_cache)) {
+
+ cl->filter_next_ptr=lights;
+ lights=cl;
+ cl->texture_cache=NULL;
+ Matrix32 scale;
+ scale.scale(cl->rect_cache.size);
+ scale.elements[2]=cl->rect_cache.pos;
+ cl->light_shader_xform = (cl->xform_cache * scale).affine_inverse();
+ cl->light_shader_pos=cl->xform_cache[2];
+ if (cl->shadow_buffer.is_valid()) {
+
+ cl->shadows_next_ptr=lights_with_shadow;
+ if (lights_with_shadow==NULL) {
+ shadow_rect = cl->xform_cache.xform(cl->rect_cache);
+ } else {
+ shadow_rect=shadow_rect.merge( cl->xform_cache.xform(cl->rect_cache) );
+ }
+ lights_with_shadow=cl;
+ 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++;
+ }
+
+ }
+ }
+
+ //print_line("lights: "+itos(light_count));
canvas_map[ Viewport::CanvasKey( E->key(), E->get().layer) ]=&E->get();
}
+ if (lights_with_shadow) {
+ //update shadows if any
+
+ Rasterizer::CanvasLightOccluderInstance * occluders=NULL;
+
+ //make list of occluders
+ for (Map<RID,Viewport::CanvasData>::Element *E=p_viewport->canvas_map.front();E;E=E->next()) {
+
+ Matrix32 xf = p_viewport->global_transform * E->get().transform;
+
+ for(Set<Rasterizer::CanvasLightOccluderInstance*>::Element *F=E->get().canvas->occluders.front();F;F=F->next()) {
+
+ F->get()->xform_cache = xf * F->get()->xform;
+ if (shadow_rect.intersects_transformed(F->get()->xform_cache,F->get()->aabb_cache)) {
+
+ F->get()->next=occluders;
+ occluders=F->get();
+
+ }
+ }
+ }
+ //update the light shadowmaps with them
+ Rasterizer::CanvasLight *light=lights_with_shadow;
+ while(light) {
+
+ rasterizer->canvas_light_shadow_buffer_update(light->shadow_buffer,light->xform_cache.affine_inverse(),light->item_mask,light->radius_cache/1000.0,light->radius_cache*1.1,occluders,&light->shadow_matrix_cache);
+ light=light->shadows_next_ptr;
+ }
+
+ rasterizer->set_viewport(viewport_rect); //must reset viewport afterwards
+ }
+
+
+
+
+ if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().layer>scenario_canvas_max_layer) {
+
+ _draw_viewport_camera(p_viewport,!can_draw_3d);
+ scenario_draw_canvas_bg=false;
+
+ }
+
for (Map<Viewport::CanvasKey,Viewport::CanvasData*>::Element *E=canvas_map.front();E;E=E->next()) {
// print_line("canvas "+itos(i)+" size: "+itos(I->get()->canvas->child_items.size()));
//print_line("GT "+p_viewport->global_transform+". CT: "+E->get()->transform);
Matrix32 xform = p_viewport->global_transform * E->get()->transform;
- _render_canvas( E->get()->canvas,xform );
+
+ Rasterizer::CanvasLight *canvas_lights=NULL;
+
+ Rasterizer::CanvasLight *ptr=lights;
+ while(ptr) {
+ if (E->get()->layer>=ptr->layer_min && E->get()->layer<=ptr->layer_max) {
+ ptr->next_ptr=canvas_lights;
+ canvas_lights=ptr;
+ }
+ ptr=ptr->filter_next_ptr;
+ }
+
+ _render_canvas( E->get()->canvas,xform,canvas_lights,lights_with_mask );
i++;
+ if (scenario_draw_canvas_bg && E->key().layer>=scenario_canvas_max_layer) {
+ _draw_viewport_camera(p_viewport,!can_draw_3d);
+ scenario_draw_canvas_bg=false;
+ }
+
+
}
+
+ if (scenario_draw_canvas_bg) {
+ _draw_viewport_camera(p_viewport,!can_draw_3d);
+ scenario_draw_canvas_bg=false;
+ }
+
+
+// rasterizer->canvas_debug_viewport_shadows(lights_with_shadow);
}
//capture
@@ -5822,6 +7255,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
if (p_viewport->queue_capture) {
rasterizer->capture_viewport(&p_viewport->capture);
+ p_viewport->queue_capture = false;
}
//restore
@@ -5902,7 +7336,7 @@ void VisualServerRaster::_draw_viewports() {
rasterizer->set_viewport(viewport_rect);
}
- rasterizer->canvas_begin();
+ rasterizer->canvas_begin();
rasterizer->canvas_disable_blending();
rasterizer->canvas_begin_rect(Matrix32());
rasterizer->canvas_draw_rect(E->get()->rt_to_screen_rect,0,Rect2(Point2(),E->get()->rt_to_screen_rect.size),E->get()->render_target_texture,Color(1,1,1));
@@ -5921,7 +7355,14 @@ void VisualServerRaster::_draw_viewports() {
int window_w = OS::get_singleton()->get_video_mode(E->get()).width;
int window_h = OS::get_singleton()->get_video_mode(E->get()).height;
- _draw_viewport(vp,0,0,window_w,window_h);
+ Rect2 r(0,0,vp->rect.width,vp->rect.height);
+ if (r.size.width==0)
+ r.size.width=window_w;
+ if (r.size.height==0)
+ r.size.height=window_h;
+
+
+ _draw_viewport(vp,r.pos.x,r.pos.y,r.size.width,r.size.height);
}
@@ -5976,6 +7417,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));
@@ -5987,15 +7430,27 @@ 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();
};
-void VisualServerRaster::flush() {
+void VisualServerRaster::sync() {
//do none
}
@@ -6033,11 +7488,13 @@ void VisualServerRaster::set_default_clear_color(const Color& p_color) {
clear_color=p_color;
}
-void VisualServerRaster::set_boot_image(const Image& p_image, const Color& p_color) {
+void VisualServerRaster::set_boot_image(const Image& p_image, const Color& p_color,bool p_scale) {
if (p_image.empty())
return;
+ rasterizer->restore_framebuffer();
+
rasterizer->begin_frame();
int window_w = OS::get_singleton()->get_video_mode(0).width;
@@ -6055,9 +7512,27 @@ void VisualServerRaster::set_boot_image(const Image& p_image, const Color& p_col
texture_set_data(texture,p_image);
rasterizer->canvas_begin_rect(Matrix32());
Rect2 imgrect(0,0,p_image.get_width(),p_image.get_height());
- Rect2 screenrect=imgrect;
- screenrect.pos+=((Size2(vr.width,vr.height)-screenrect.size)/2.0).floor();
- rasterizer->canvas_draw_rect(screenrect,0,imgrect,texture,Color(1,1,1,0));
+ Rect2 screenrect;
+ if (p_scale) {
+
+ if (window_w > window_h) {
+ //scale horizontally
+ screenrect.size.y = window_h;
+ screenrect.size.x = imgrect.size.x * window_h / imgrect.size.y;
+ screenrect.pos.x = (window_w - screenrect.size.x)/2;
+
+ } else {
+ //scale vertically
+ screenrect.size.x = window_w;
+ screenrect.size.y = imgrect.size.y * window_w / imgrect.size.x;
+ screenrect.pos.y = (window_h - screenrect.size.y)/2;
+ }
+ } else {
+
+ screenrect=imgrect;
+ screenrect.pos+=((Size2(vr.width,vr.height)-screenrect.size)/2.0).floor();
+
+ }
rasterizer->canvas_draw_rect(screenrect,0,imgrect,texture,Color(1,1,1,1));
rasterizer->canvas_end_rect();
@@ -6112,6 +7587,10 @@ void VisualServerRaster::finish() {
free(default_cursor_texture);
+ if (test_cube.is_valid())
+ free(test_cube);
+
+ _free_internal_rids();
_clean_up_owner( &room_owner,"Room" );
_clean_up_owner( &portal_owner,"Portal" );
@@ -6129,7 +7608,7 @@ void VisualServerRaster::finish() {
octree_allocator.clear();
if (instance_dependency_map.size()) {
- print_line("base resources missing "+itos(instance_dependency_map.size()));
+ print_line("Base resources missing amount: "+itos(instance_dependency_map.size()));
}
ERR_FAIL_COND( instance_dependency_map.size() );
}
@@ -6150,6 +7629,7 @@ RID VisualServerRaster::get_test_cube() {
VisualServerRaster::VisualServerRaster(Rasterizer *p_rasterizer) {
rasterizer=p_rasterizer;
+ rasterizer->draw_viewport_func=_render_canvas_item_viewport;
instance_update_list=NULL;
render_pass=0;
clear_color=Color(0.3,0.3,0.3,1.0);
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index 0368780bfb..e0127faf41 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -51,6 +51,7 @@ class VisualServerRaster : public VisualServer {
MAX_LIGHTS_CULLED=256,
MAX_ROOM_CULL=32,
MAX_EXTERIOR_PORTALS=128,
+ MAX_LIGHT_SAMPLERS=256,
INSTANCE_ROOMLESS_MASK=(1<<20)
@@ -84,18 +85,36 @@ class VisualServerRaster : public VisualServer {
Vector<Point2> shape;
Rect2 bounds;
+
Portal() { enabled=true; disable_distance=50; disable_color=Color(); connect_range=0.8; }
};
struct BakedLight {
Rasterizer::BakedLightData data;
+ DVector<int> sampler;
AABB octree_aabb;
Size2i octree_tex_size;
+ Size2i light_tex_size;
};
+ struct BakedLightSampler {
+
+ float params[BAKED_LIGHT_SAMPLER_MAX];
+ int resolution;
+ Vector<Vector3> dp_cache;
+
+ BakedLightSampler() {
+ params[BAKED_LIGHT_SAMPLER_STRENGTH]=1.0;
+ params[BAKED_LIGHT_SAMPLER_ATTENUATION]=1.0;
+ params[BAKED_LIGHT_SAMPLER_RADIUS]=1.0;
+ params[BAKED_LIGHT_SAMPLER_DETAIL_RATIO]=0.1;
+ resolution=16;
+ }
+ };
+ void _update_baked_light_sampler_dp_cache(BakedLightSampler * blsamp);
struct Camera {
enum Type {
@@ -157,7 +176,7 @@ class VisualServerRaster : public VisualServer {
float draw_range_begin;
float draw_range_end;
float extra_margin;
- int lightmap_texture_index;
+
Rasterizer::InstanceData data;
@@ -169,6 +188,7 @@ class VisualServerRaster : public VisualServer {
List<Instance*>::Element *RE;
Instance *baked_light;
List<Instance*>::Element *BLE;
+ Instance *sampled_light;
bool exterior;
uint64_t last_render_pass;
@@ -179,6 +199,8 @@ class VisualServerRaster : public VisualServer {
InstanceSet lights;
bool light_cache_dirty;
+
+
struct RoomInfo {
Transform affine_inverse;
@@ -235,6 +257,23 @@ class VisualServerRaster : public VisualServer {
Transform affine_inverse;
List<Instance*> owned_instances;
};
+
+ struct BakedLightSamplerInfo {
+
+ Set<Instance*> baked_lights;
+ Set<Instance*> owned_instances;
+ BakedLightSampler *sampler;
+ int resolution;
+ Vector<Color> light_bufer;
+ RID sampled_light;
+ uint64_t last_pass;
+ Transform xform; // viewspace normal to lightspace, might not use one.
+ BakedLightSamplerInfo() {
+ sampler=NULL;
+ last_pass=0;
+ resolution=0;
+ }
+ };
struct ParticlesInfo {
@@ -247,6 +286,7 @@ class VisualServerRaster : public VisualServer {
ParticlesInfo *particles_info;
PortalInfo * portal_info;
BakedLightInfo * baked_light_info;
+ BakedLightSamplerInfo * baked_light_sampler_info;
Instance() {
@@ -267,6 +307,7 @@ class VisualServerRaster : public VisualServer {
data.billboard_y=false;
data.baked_light=NULL;
data.baked_light_octree_xform=NULL;
+ data.baked_lightmap_id=-1;
version=1;
room_info=NULL;
room=NULL;
@@ -278,9 +319,11 @@ class VisualServerRaster : public VisualServer {
draw_range_end=0;
extra_margin=0;
visible_in_all_rooms=false;
- lightmap_texture_index=-1;
+
baked_light=NULL;
baked_light_info=NULL;
+ baked_light_sampler_info=NULL;
+ sampled_light=NULL;
BLE=NULL;
light_cache_dirty=true;
@@ -319,6 +362,7 @@ class VisualServerRaster : public VisualServer {
List<RID> directional_lights;
RID environment;
+ RID fallback_environment;
Instance *dirty_instances;
@@ -327,143 +371,64 @@ class VisualServerRaster : public VisualServer {
-
+ mutable RID_Owner<Rasterizer::CanvasItemMaterial> canvas_item_material_owner;
- struct CanvasItem {
-
- struct Command {
-
- enum Type {
-
- TYPE_LINE,
- TYPE_RECT,
- TYPE_STYLE,
- TYPE_PRIMITIVE,
- TYPE_POLYGON,
- TYPE_POLYGON_PTR,
- TYPE_CIRCLE,
- TYPE_TRANSFORM,
- TYPE_BLEND_MODE,
- TYPE_CLIP_IGNORE,
- };
-
- Type type;
- };
-
- struct CommandLine : public Command {
-
- Point2 from,to;
- Color color;
- float width;
- CommandLine() { type = TYPE_LINE; }
- };
-
- struct CommandRect : public Command {
-
- Rect2 rect;
- RID texture;
- Color modulate;
- Rect2 source;
- uint8_t flags;
-
- CommandRect() { flags=0; type = TYPE_RECT; }
- };
-
- struct CommandStyle : public Command {
-
- Rect2 rect;
- RID texture;
- float margin[4];
- float draw_center;
- Color color;
- CommandStyle() { draw_center=true; type = TYPE_STYLE; }
- };
-
- struct CommandPrimitive : public Command {
-
- Vector<Point2> points;
- Vector<Point2> uvs;
- Vector<Color> colors;
- RID texture;
- float width;
-
- CommandPrimitive() { type = TYPE_PRIMITIVE; width=1;}
- };
+ struct CanvasItem : public Rasterizer::CanvasItem {
- struct CommandPolygon : public Command {
- Vector<int> indices;
- Vector<Point2> points;
- Vector<Point2> uvs;
- Vector<Color> colors;
- RID texture;
- int count;
+ RID parent; // canvas it belongs to
+ List<CanvasItem*>::Element *E;
+ RID viewport;
+ int z;
+ bool z_relative;
+ bool sort_y;
+ float opacity;
+ float self_opacity;
+ bool use_parent_material;
- CommandPolygon() { type = TYPE_POLYGON; count = 0; }
- };
- struct CommandPolygonPtr : public Command {
+ Vector<CanvasItem*> child_items;
- const int* indices;
- const Point2* points;
- const Point2* uvs;
- const Color* colors;
- RID texture;
- int count;
- CommandPolygonPtr() { type = TYPE_POLYGON_PTR; count = 0; }
- };
+ CanvasItem() {
+ E=NULL;
+ z=0;
+ opacity=1;
+ self_opacity=1;
+ sort_y=false;
+ use_parent_material=false;
+ z_relative=true;
+ }
+ };
- struct CommandCircle : public Command {
- Point2 pos;
- float radius;
- Color color;
- CommandCircle() { type = TYPE_CIRCLE; }
- };
+ struct CanvasItemPtrSort {
- struct CommandTransform : public Command {
+ _FORCE_INLINE_ bool operator()(const CanvasItem* p_left,const CanvasItem* p_right) const {
- Matrix32 xform;
- CommandTransform() { type = TYPE_TRANSFORM; }
- };
+ return p_left->xform.elements[2].y < p_right->xform.elements[2].y;
+ }
+ };
- struct CommandBlendMode : public Command {
+ struct CanvasLightOccluder;
- MaterialBlendMode blend_mode;
- CommandBlendMode() { type = TYPE_BLEND_MODE; blend_mode = MATERIAL_BLEND_MODE_MIX; };
- };
- struct CommandClipIgnore : public Command {
+ struct CanvasLightOccluderPolygon {
- bool ignore;
- CommandClipIgnore() { type = TYPE_CLIP_IGNORE; ignore=false; };
- };
+ bool active;
+ Rect2 aabb;
+ CanvasOccluderPolygonCullMode cull_mode;
+ RID occluder;
+ Set<Rasterizer::CanvasLightOccluderInstance*> owners;
- RID parent; // canvas it belongs to
- List<CanvasItem*>::Element *E;
- Matrix32 xform;
- bool clip;
- bool visible;
- bool ontop;
- float opacity;
- float self_opacity;
- MaterialBlendMode blend_mode;
- RID viewport;
+ CanvasLightOccluderPolygon() { active=false; cull_mode=CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; }
+ };
- mutable bool custom_rect;
- mutable bool rect_dirty;
- mutable Rect2 rect;
-
- Vector<Command*> commands;
- Vector<CanvasItem*> child_items;
- const Rect2& get_rect() const;
- void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true;};
- CanvasItem() { clip=false; E=NULL; opacity=1; self_opacity=1; blend_mode=MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; }
- ~CanvasItem() { clear(); }
- };
+ RID_Owner<CanvasLightOccluderPolygon> canvas_light_occluder_polygon_owner;
+ RID_Owner<Rasterizer::CanvasLightOccluderInstance> canvas_light_occluder_owner;
+ struct CanvasLight;
struct Canvas {
@@ -474,8 +439,11 @@ class VisualServerRaster : public VisualServer {
CanvasItem *item;
};
+ Set<Rasterizer::CanvasLight*> lights;
+ Set<Rasterizer::CanvasLightOccluderInstance*> occluders;
Vector<ChildItem> child_items;
+ Color modulate;
int find_item(CanvasItem *p_item) {
for(int i=0;i<child_items.size();i++) {
@@ -490,11 +458,13 @@ class VisualServerRaster : public VisualServer {
child_items.remove(idx);
}
- Canvas() { }
+ Canvas() { modulate=Color(1,1,1,1); }
};
+ RID_Owner<Rasterizer::CanvasLight> canvas_light_owner;
+
struct Viewport {
@@ -517,6 +487,10 @@ class VisualServerRaster : public VisualServer {
bool transparent_bg;
bool queue_capture;
bool render_target_vflip;
+ bool render_target_clear_on_new_frame;
+ bool render_target_clear;
+ bool disable_environment;
+
Image capture;
bool rendered_in_prev_frame;
@@ -543,7 +517,7 @@ class VisualServerRaster : public VisualServer {
SelfList<Viewport> update_list;
- Viewport() : update_list(this) { transparent_bg=false; render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; queue_capture=false; rendered_in_prev_frame=false; render_target_vflip=false;}
+ Viewport() : update_list(this) { transparent_bg=false; render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; queue_capture=false; rendered_in_prev_frame=false; render_target_vflip=false; render_target_clear_on_new_frame=true; render_target_clear=true; disable_environment=false; }
};
SelfList<Viewport>::List viewport_update_list;
@@ -593,6 +567,9 @@ class VisualServerRaster : public VisualServer {
int exterior_portal_cull_count;
bool exterior_visited;
+ Instance *light_sampler_cull_result[MAX_LIGHT_SAMPLERS];
+ int light_samplers_culled;
+
Instance *room_cull_result[MAX_ROOM_CULL];
int room_cull_count;
bool room_cull_enabled;
@@ -609,7 +586,7 @@ class VisualServerRaster : public VisualServer {
void _portal_disconnect(Instance *p_portal,bool p_cleanup=false);
void _portal_attempt_connect(Instance *p_portal);
void _dependency_queue_update(RID p_rid,bool p_update_aabb=false);
- void _instance_queue_update(Instance *p_instance,bool p_update_aabb=false);
+ _FORCE_INLINE_ void _instance_queue_update(Instance *p_instance,bool p_update_aabb=false);
void _update_instances();
void _update_instance_aabb(Instance *p_instance);
void _update_instance(Instance *p_instance);
@@ -628,6 +605,7 @@ class VisualServerRaster : public VisualServer {
mutable RID_Owner<Portal> portal_owner;
mutable RID_Owner<BakedLight> baked_light_owner;
+ mutable RID_Owner<BakedLightSampler> baked_light_sampler_owner;
mutable RID_Owner<Camera> camera_owner;
mutable RID_Owner<Viewport> viewport_owner;
@@ -639,7 +617,8 @@ class VisualServerRaster : public VisualServer {
mutable RID_Owner<CanvasItem> canvas_item_owner;
Map< RID, Set<RID> > instance_dependency_map;
-
+ Map< RID, Set<Instance*> > skeleton_dependency_map;
+
ViewportRect viewport_rect;
_FORCE_INLINE_ void _instance_draw(Instance *p_instance);
@@ -647,9 +626,16 @@ class VisualServerRaster : public VisualServer {
bool _test_portal_cull(Camera *p_camera, Instance *p_portal_from, Instance *p_portal_to);
void _cull_portal(Camera *p_camera, Instance *p_portal,Instance *p_from_portal);
void _cull_room(Camera *p_camera, Instance *p_room,Instance *p_from_portal=NULL);
+ void _process_sampled_light(const Transform &p_camera, Instance *p_sampled_light, bool p_linear_colorspace);
+
+ void _render_no_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario);
void _render_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario);
- void _render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect,float p_opacity);
- void _render_canvas(Canvas *p_canvas,const Matrix32 &p_transform);
+ 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, 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);
@@ -662,6 +648,7 @@ class VisualServerRaster : public VisualServer {
int changes;
bool draw_extra_frame;
+ void _draw_viewport_camera(Viewport *p_viewport, bool p_ignore_camera);
void _draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ofs_y,int p_parent_w,int p_parent_h);
void _draw_viewports();
void _draw_cursors_and_margins();
@@ -683,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 */
@@ -698,6 +690,10 @@ public:
virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture);
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const;
+
+
/* COMMON MATERIAL API */
virtual RID material_create();
@@ -776,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 */
@@ -942,9 +939,28 @@ public:
virtual void baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree);
virtual DVector<uint8_t> baked_light_get_octree(RID p_baked_light) const;
+ virtual void baked_light_set_light(RID p_baked_light,const DVector<uint8_t> p_light);
+ virtual DVector<uint8_t> baked_light_get_light(RID p_baked_light) const;
+
+ virtual void baked_light_set_sampler_octree(RID p_baked_light,const DVector<int> &p_sampler);
+ virtual DVector<int> baked_light_get_sampler_octree(RID p_baked_light) const;
+
+ virtual void baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier);
+ virtual float baked_light_get_lightmap_multiplier(RID p_baked_light) const;
+
virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id);
virtual void baked_light_clear_lightmaps(RID p_baked_light);
+ /* BAKED LIGHT SAMPLER */
+
+ virtual RID baked_light_sampler_create();
+
+ virtual void baked_light_sampler_set_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param,float p_value);
+ virtual float baked_light_sampler_get_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param) const;
+
+ virtual void baked_light_sampler_set_resolution(RID p_baked_light_sampler,int p_resolution);
+ virtual int baked_light_sampler_get_resolution(RID p_baked_light_sampler) const;
+
/* CAMERA API */
virtual RID camera_create();
@@ -974,8 +990,12 @@ public:
virtual RID viewport_get_render_target_texture(RID p_viewport) const;
virtual void viewport_set_render_target_vflip(RID p_viewport,bool p_enable);
virtual bool viewport_get_render_target_vflip(RID p_viewport) const;
+ virtual void viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable);
+ virtual bool viewport_get_render_target_clear_on_new_frame(RID p_viewport) const;
+ virtual void viewport_render_target_clear(RID p_viewport);
virtual void viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect);
+
virtual void viewport_queue_screen_capture(RID p_viewport);
virtual Image viewport_get_screen_capture(RID p_viewport) const;
@@ -984,6 +1004,7 @@ public:
virtual void viewport_set_hide_scenario(RID p_viewport,bool p_hide);
virtual void viewport_set_hide_canvas(RID p_viewport,bool p_hide);
+ virtual void viewport_set_disable_environment(RID p_viewport,bool p_disable);
virtual void viewport_attach_camera(RID p_viewport,RID p_camera);
virtual void viewport_set_scenario(RID p_viewport,RID p_scenario);
@@ -1025,6 +1046,8 @@ public:
virtual void scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode);
virtual void scenario_set_environment(RID p_scenario, RID p_environment);
virtual RID scenario_get_environment(RID p_scenario, RID p_environment) const;
+ virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
+
/* INSTANCING API */
@@ -1080,6 +1103,9 @@ public:
virtual void instance_geometry_set_baked_light(RID p_instance,RID p_baked_light);
virtual RID instance_geometry_get_baked_light(RID p_instance) const;
+ virtual void instance_geometry_set_baked_light_sampler(RID p_instance,RID p_baked_light_sampler);
+ virtual RID instance_geometry_get_baked_light_sampler(RID p_instance) const;
+
virtual void instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id);
virtual int instance_geometry_get_baked_light_texture_index(RID p_instance) const;
@@ -1091,6 +1117,8 @@ public:
virtual RID canvas_create();
virtual void canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring);
virtual Point2 canvas_get_item_mirroring(RID p_canvas,RID p_item) const;
+ virtual void canvas_set_modulate(RID p_canvas,const Color& p_color);
+
virtual RID canvas_item_create();
@@ -1101,11 +1129,14 @@ public:
virtual bool canvas_item_is_visible(RID p_item) const;
virtual void canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend);
+ virtual void canvas_item_set_light_mask(RID p_canvas_item,int p_mask);
+
//virtual void canvas_item_set_rect(RID p_item, const Rect2& p_rect);
virtual void canvas_item_set_transform(RID p_item, const Matrix32& p_transform);
virtual void canvas_item_set_clip(RID p_item, bool p_clip);
+ virtual void canvas_item_set_distance_field_mode(RID p_item, bool p_enable);
virtual void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect,const Rect2& p_rect=Rect2());
virtual void canvas_item_set_opacity(RID p_item, float p_opacity);
virtual float canvas_item_get_opacity(RID p_item, float p_opacity) const;
@@ -1120,8 +1151,8 @@ public:
virtual void canvas_item_add_line(RID p_item, const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0);
virtual void canvas_item_add_rect(RID p_item, const Rect2& p_rect, const Color& p_color);
virtual void canvas_item_add_circle(RID p_item, const Point2& p_pos, float p_radius,const Color& p_color);
- virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1));
- virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1));
+ virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1),bool p_transpose=false);
+ virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1),bool p_transpose=false);
virtual void canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center=true,const Color& p_modulate=Color(1,1,1));
virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width=1.0);
virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), RID p_texture=RID());
@@ -1130,10 +1161,65 @@ public:
virtual void canvas_item_add_set_transform(RID p_item,const Matrix32& p_transform);
virtual void canvas_item_add_set_blend_mode(RID p_item, MaterialBlendMode p_blend);
virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore);
+ virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable);
+ virtual void canvas_item_set_z(RID p_item, int p_z);
+ virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable);
+ virtual void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable,const Rect2& p_rect);
+
+ virtual void canvas_item_set_material(RID p_item, RID p_material);
+ virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
+
+ virtual RID canvas_light_create();
+ virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas);
+ virtual void canvas_light_set_enabled(RID p_light, bool p_enabled);
+ virtual void canvas_light_set_transform(RID p_light, const Matrix32& p_transform);
+ virtual void canvas_light_set_scale(RID p_light, float p_scale);
+ virtual void canvas_light_set_texture(RID p_light, RID p_texture);
+ virtual void canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset);
+ virtual void canvas_light_set_color(RID p_light, const Color& p_color);
+ virtual void canvas_light_set_height(RID p_light, float p_height);
+ virtual void canvas_light_set_energy(RID p_light, float p_energy);
+ virtual void canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z);
+ virtual void canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer);
+ virtual void canvas_light_set_item_mask(RID p_light, int p_mask);
+ virtual void canvas_light_set_item_shadow_mask(RID p_light, int p_mask);
+
+ virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode);
+ 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();
+ virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas);
+ virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled);
+ virtual void canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon);
+ virtual void canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform);
+ virtual void canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask);
+
+
+ virtual RID canvas_occluder_polygon_create();
+ virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon,const DVector<Vector2>& p_shape,bool p_close);
+ virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape);
+ virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode);
+
+
virtual void canvas_item_clear(RID p_item);
virtual void canvas_item_raise(RID p_item);
+ /* CANVAS ITEM MATERIAL */
+
+ virtual RID canvas_item_material_create();
+ virtual void canvas_item_material_set_shader(RID p_material, RID p_shader);
+ virtual void canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value);
+ virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const;
+ virtual void canvas_item_material_set_shading_mode(RID p_material, CanvasItemShadingMode p_mode);
+
+
+
/* CURSOR */
virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0); // radians
virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor=0);
@@ -1161,7 +1247,7 @@ public:
/* EVENT QUEUING */
virtual void draw();
- virtual void flush();
+ virtual void sync();
virtual void init();
virtual void finish();
@@ -1175,7 +1261,7 @@ public:
RID get_test_cube();
- virtual void set_boot_image(const Image& p_image, const Color& p_color);
+ virtual void set_boot_image(const Image& p_image, const Color& p_color, bool p_scale);
virtual void set_default_clear_color(const Color& p_color);
VisualServerRaster(Rasterizer *p_rasterizer);
diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp
index 62f18b9e81..19dff3d36c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -96,16 +96,19 @@ void VisualServerWrapMT::thread_loop() {
/* EVENT QUEUING */
-void VisualServerWrapMT::flush() {
+void VisualServerWrapMT::sync() {
if (create_thread) {
+ /* TODO: sync with the thread */
+
+ /*
ERR_FAIL_COND(!draw_mutex);
draw_mutex->lock();
draw_pending++; //cambiar por un saferefcount
draw_mutex->unlock();
-
- command_queue.push( this, &VisualServerWrapMT::thread_flush);
+ */
+ //command_queue.push( this, &VisualServerWrapMT::thread_flush);
} else {
command_queue.flush_all(); //flush all pending from other threads
@@ -118,15 +121,16 @@ void VisualServerWrapMT::draw() {
if (create_thread) {
+ /* TODO: Make it draw
ERR_FAIL_COND(!draw_mutex);
draw_mutex->lock();
draw_pending++; //cambiar por un saferefcount
draw_mutex->unlock();
command_queue.push( this, &VisualServerWrapMT::thread_draw);
+ */
} else {
- command_queue.flush_all(); //flush all pending from other threads
visual_server->draw();
}
}
@@ -187,8 +191,8 @@ VisualServerWrapMT::VisualServerWrapMT(VisualServer* p_contained,bool p_create_t
draw_pending=0;
draw_thread_up=false;
alloc_mutex=Mutex::create();
- texture_pool_max_size=GLOBAL_DEF("render/thread_textures_prealloc",20);
- mesh_pool_max_size=GLOBAL_DEF("render/thread_meshes_prealloc",20);
+ texture_pool_max_size=GLOBAL_DEF("render/thread_textures_prealloc",5);
+ mesh_pool_max_size=GLOBAL_DEF("core/rid_pool_prealloc",20);
if (!p_create_thread) {
server_thread=Thread::get_caller_ID();
} else {
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index d577ca0c59..57d691ae68 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -79,554 +79,10 @@ class VisualServerWrapMT : public VisualServer {
public:
-#define FUNC0R(m_r,m_type)\
- virtual m_r m_type() { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type();\
- }\
- }
-
-#define FUNCRID(m_type)\
- int m_type##allocn() {\
- for(int i=0;i<m_type##_pool_max_size;i++) {\
- m_type##_id_pool.push_back( visual_server->m_type##_create() );\
- }\
- return 0;\
- }\
- void m_type##_free_cached_ids() {\
- while (m_type##_id_pool.size()) {\
- free(m_type##_id_pool.front()->get());\
- m_type##_id_pool.pop_front();\
- }\
- }\
- virtual RID m_type##_create() { \
- if (Thread::get_caller_ID()!=server_thread) {\
- RID rid;\
- alloc_mutex->lock();\
- if (m_type##_id_pool.size()==0) {\
- int ret;\
- command_queue.push_and_ret( this, &VisualServerWrapMT::m_type##allocn,&ret);\
- }\
- rid=m_type##_id_pool.front()->get();\
- m_type##_id_pool.pop_front();\
- alloc_mutex->unlock();\
- return rid;\
- } else {\
- return visual_server->m_type##_create();\
- }\
- }
-
-#define FUNC0RC(m_r,m_type)\
- virtual m_r m_type() const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type();\
- }\
- }
-
-
-#define FUNC0(m_type)\
- virtual void m_type() { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type);\
- } else {\
- visual_server->m_type();\
- }\
- }
-
-#define FUNC0C(m_type)\
- virtual void m_type() const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type);\
- } else {\
- visual_server->m_type();\
- }\
- }
-
-
-#define FUNC0S(m_type)\
- virtual void m_type() { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type);\
- } else {\
- visual_server->m_type();\
- }\
- }
-
-#define FUNC0SC(m_type)\
- virtual void m_type() const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type);\
- } else {\
- visual_server->m_type();\
- }\
- }
-
-
-///////////////////////////////////////////////
-
-
-#define FUNC1R(m_r,m_type,m_arg1)\
- virtual m_r m_type(m_arg1 p1) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1);\
- }\
- }
-
-#define FUNC1RC(m_r,m_type,m_arg1)\
- virtual m_r m_type(m_arg1 p1) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1);\
- }\
- }
-
-
-#define FUNC1S(m_type,m_arg1)\
- virtual void m_type(m_arg1 p1) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1);\
- } else {\
- visual_server->m_type(p1);\
- }\
- }
-
-#define FUNC1SC(m_type,m_arg1)\
- virtual void m_type(m_arg1 p1) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1);\
- } else {\
- visual_server->m_type(p1);\
- }\
- }
-
-
-#define FUNC1(m_type,m_arg1)\
- virtual void m_type(m_arg1 p1) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1);\
- } else {\
- visual_server->m_type(p1);\
- }\
- }
-
-#define FUNC1C(m_type,m_arg1)\
- virtual void m_type(m_arg1 p1) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1);\
- } else {\
- visual_server->m_type(p1);\
- }\
- }
-
-
-
-
-#define FUNC2R(m_r,m_type,m_arg1, m_arg2)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2);\
- }\
- }
-
-#define FUNC2RC(m_r,m_type,m_arg1, m_arg2)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2);\
- }\
- }
-
-
-#define FUNC2S(m_type,m_arg1, m_arg2)\
- virtual void m_type(m_arg1 p1, m_arg2 p2) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2);\
- } else {\
- visual_server->m_type(p1, p2);\
- }\
- }
-
-#define FUNC2SC(m_type,m_arg1, m_arg2)\
- virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2);\
- } else {\
- visual_server->m_type(p1, p2);\
- }\
- }
-
-
-#define FUNC2(m_type,m_arg1, m_arg2)\
- virtual void m_type(m_arg1 p1, m_arg2 p2) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2);\
- } else {\
- visual_server->m_type(p1, p2);\
- }\
- }
-
-#define FUNC2C(m_type,m_arg1, m_arg2)\
- virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2);\
- } else {\
- visual_server->m_type(p1, p2);\
- }\
- }
-
-
-
-
-#define FUNC3R(m_r,m_type,m_arg1, m_arg2, m_arg3)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-#define FUNC3RC(m_r,m_type,m_arg1, m_arg2, m_arg3)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3,&ret);\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-
-#define FUNC3S(m_type,m_arg1, m_arg2, m_arg3)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3);\
- } else {\
- visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-#define FUNC3SC(m_type,m_arg1, m_arg2, m_arg3)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3);\
- } else {\
- visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-
-#define FUNC3(m_type,m_arg1, m_arg2, m_arg3)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3);\
- } else {\
- visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-#define FUNC3C(m_type,m_arg1, m_arg2, m_arg3)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3);\
- } else {\
- visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-
-
-
-#define FUNC4R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-#define FUNC4RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-
-#define FUNC4S(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-#define FUNC4SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-
-#define FUNC4(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-#define FUNC4C(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-
-
-
-#define FUNC5R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-#define FUNC5RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-
-#define FUNC5S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-#define FUNC5SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-
-#define FUNC5(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-#define FUNC5C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-
-
-
-#define FUNC6R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-#define FUNC6RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6,&ret);\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-
-#define FUNC6S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-#define FUNC6SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-
-#define FUNC6(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-#define FUNC6C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-
-
-
-#define FUNC7R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-#define FUNC7RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-
-#define FUNC7S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-#define FUNC7SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-
-#define FUNC7(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-#define FUNC7C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-
-
+#define ServerName VisualServer
+#define ServerNameWrapMT VisualServerWrapMT
+#define server_name visual_server
+#include "servers/server_wrap_mt_common.h"
//FUNC0R(RID,texture_create);
FUNCRID(texture);
@@ -642,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);
@@ -653,6 +118,10 @@ public:
FUNC1RC(String,shader_get_light_code,RID);
FUNC2SC(shader_get_param_list,RID,List<PropertyInfo>*);
+ FUNC3(shader_set_default_texture_param,RID,const StringName&,RID);
+ FUNC2RC(RID,shader_get_default_texture_param,RID,const StringName&);
+
+
/*virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) {
if (Thread::get_caller_ID()!=server_thread) {
command_queue.push_and_sync( visual_server, &VisualServer::shader_get_param_list,p_shader,p_param_list);
@@ -739,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&);
@@ -909,11 +379,27 @@ public:
FUNC2(baked_light_set_octree,RID,DVector<uint8_t>);
FUNC1RC(DVector<uint8_t>,baked_light_get_octree,RID);
+ FUNC2(baked_light_set_light,RID,DVector<uint8_t>);
+ FUNC1RC(DVector<uint8_t>,baked_light_get_light,RID);
+
+ FUNC2(baked_light_set_sampler_octree,RID,const DVector<int>&);
+ FUNC1RC(DVector<int>,baked_light_get_sampler_octree,RID);
+
+ FUNC2(baked_light_set_lightmap_multiplier,RID,float);
+ FUNC1RC(float,baked_light_get_lightmap_multiplier,RID);
FUNC3(baked_light_add_lightmap,RID,RID,int);
FUNC1(baked_light_clear_lightmaps,RID);
+ FUNC0R(RID,baked_light_sampler_create);
+
+ FUNC3(baked_light_sampler_set_param,RID, BakedLightSamplerParam , float );
+ FUNC2RC(float,baked_light_sampler_get_param,RID, BakedLightSamplerParam );
+
+ FUNC2(baked_light_sampler_set_resolution,RID,int);
+ FUNC1RC(int,baked_light_sampler_get_resolution,RID);
+
/* CAMERA API */
FUNC0R(RID,camera_create);
@@ -927,6 +413,7 @@ public:
FUNC2(camera_set_environment,RID,RID);
FUNC1RC(RID,camera_get_environment,RID);
+
FUNC2(camera_set_use_vertical_aspect,RID,bool);
FUNC2RC(bool,camera_is_using_vertical_aspect,RID,bool);
@@ -946,6 +433,10 @@ public:
FUNC2(viewport_set_render_target_vflip,RID,bool);
FUNC1RC(bool,viewport_get_render_target_vflip,RID);
FUNC2(viewport_set_render_target_to_screen_rect,RID,const Rect2&);
+
+ FUNC2(viewport_set_render_target_clear_on_new_frame,RID,bool);
+ FUNC1RC(bool,viewport_get_render_target_clear_on_new_frame,RID);
+ FUNC1(viewport_render_target_clear,RID);
FUNC1(viewport_queue_screen_capture,RID);
FUNC1RC(Image,viewport_get_screen_capture,RID);
@@ -957,6 +448,7 @@ public:
FUNC2(viewport_set_hide_canvas,RID,bool );
FUNC2(viewport_attach_camera,RID,RID );
FUNC2(viewport_set_scenario,RID,RID );
+ FUNC2(viewport_set_disable_environment,RID,bool );
FUNC1RC(RID,viewport_get_attached_camera,RID);
FUNC1RC(RID,viewport_get_scenario,RID );
@@ -996,6 +488,7 @@ public:
FUNC2(scenario_set_debug,RID,ScenarioDebugMode);
FUNC2(scenario_set_environment,RID, RID);
FUNC2RC(RID,scenario_get_environment,RID, RID);
+ FUNC2(scenario_set_fallback_environment,RID, RID);
/* INSTANCING API */
@@ -1051,6 +544,9 @@ public:
FUNC2(instance_geometry_set_baked_light,RID, RID );
FUNC1RC(RID,instance_geometry_get_baked_light,RID);
+ FUNC2(instance_geometry_set_baked_light_sampler,RID, RID );
+ FUNC1RC(RID,instance_geometry_get_baked_light_sampler,RID);
+
FUNC2(instance_geometry_set_baked_light_texture_index,RID, int);
FUNC1RC(int,instance_geometry_get_baked_light_texture_index,RID);
@@ -1062,6 +558,8 @@ public:
FUNC0R(RID,canvas_create);
FUNC3(canvas_set_item_mirroring,RID,RID,const Point2&);
FUNC2RC(Point2,canvas_get_item_mirroring,RID,RID);
+ FUNC2(canvas_set_modulate,RID,const Color&);
+
FUNC0R(RID,canvas_item_create);
@@ -1072,11 +570,12 @@ public:
FUNC1RC(bool,canvas_item_is_visible,RID);
FUNC2(canvas_item_set_blend_mode,RID,MaterialBlendMode );
-
+ FUNC2(canvas_item_set_light_mask,RID,int );
//FUNC(canvas_item_set_rect,RID, const Rect2& p_rect);
FUNC2(canvas_item_set_transform,RID, const Matrix32& );
FUNC2(canvas_item_set_clip,RID, bool );
+ FUNC2(canvas_item_set_distance_field_mode,RID, bool );
FUNC3(canvas_item_set_custom_rect,RID, bool ,const Rect2&);
FUNC2(canvas_item_set_opacity,RID, float );
FUNC2RC(float,canvas_item_get_opacity,RID, float );
@@ -1091,9 +590,8 @@ public:
FUNC5(canvas_item_add_line,RID, const Point2& , const Point2& ,const Color& ,float );
FUNC3(canvas_item_add_rect,RID, const Rect2& , const Color& );
FUNC4(canvas_item_add_circle,RID, const Point2& , float ,const Color& );
- FUNC5(canvas_item_add_texture_rect,RID, const Rect2& , RID ,bool ,const Color& );
- FUNC5(canvas_item_add_texture_rect_region,RID, const Rect2& , RID ,const Rect2& ,const Color& );
-
+ FUNC6(canvas_item_add_texture_rect,RID, const Rect2& , RID ,bool ,const Color&,bool );
+ FUNC6(canvas_item_add_texture_rect_region,RID, const Rect2& , RID ,const Rect2& ,const Color&,bool );
FUNC7(canvas_item_add_style_box,RID, const Rect2& , RID ,const Vector2& ,const Vector2&, bool ,const Color& );
FUNC6(canvas_item_add_primitive,RID, const Vector<Point2>& , const Vector<Color>& ,const Vector<Point2>& , RID ,float );
FUNC5(canvas_item_add_polygon,RID, const Vector<Point2>& , const Vector<Color>& ,const Vector<Point2>& , RID );
@@ -1105,9 +603,65 @@ public:
FUNC2(canvas_item_add_set_blend_mode,RID, MaterialBlendMode );
FUNC2(canvas_item_add_clip_ignore,RID, bool );
+ FUNC2(canvas_item_set_sort_children_by_y,RID,bool);
+ FUNC2(canvas_item_set_z,RID,int);
+ FUNC2(canvas_item_set_z_as_relative_to_parent,RID,bool);
+ FUNC3(canvas_item_set_copy_to_backbuffer,RID,bool,const Rect2&);
+
+
+ FUNC2(canvas_item_set_material,RID, RID );
+
+ FUNC2(canvas_item_set_use_parent_material,RID, bool );
+
FUNC1(canvas_item_clear,RID);
FUNC1(canvas_item_raise,RID);
+ /* CANVAS LIGHT */
+ FUNC0R(RID,canvas_light_create);
+ FUNC2(canvas_light_attach_to_canvas,RID,RID);
+ FUNC2(canvas_light_set_enabled,RID,bool);
+ FUNC2(canvas_light_set_transform,RID,const Matrix32&);
+ FUNC2(canvas_light_set_scale,RID,float);
+ FUNC2(canvas_light_set_texture,RID,RID);
+ FUNC2(canvas_light_set_texture_offset,RID,const Vector2&);
+ FUNC2(canvas_light_set_color,RID,const Color&);
+ FUNC2(canvas_light_set_height,RID,float);
+ FUNC2(canvas_light_set_energy,RID,float);
+ FUNC3(canvas_light_set_layer_range,RID,int,int);
+ FUNC3(canvas_light_set_z_range,RID,int,int);
+ FUNC2(canvas_light_set_item_mask,RID,int);
+ FUNC2(canvas_light_set_item_shadow_mask,RID,int);
+
+ FUNC2(canvas_light_set_mode,RID,CanvasLightMode);
+ 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 */
+
+ FUNC0R(RID,canvas_light_occluder_create);
+ FUNC2(canvas_light_occluder_attach_to_canvas,RID,RID);
+ FUNC2(canvas_light_occluder_set_enabled,RID,bool);
+ FUNC2(canvas_light_occluder_set_polygon,RID,RID);
+ FUNC2(canvas_light_occluder_set_transform,RID,const Matrix32&);
+ FUNC2(canvas_light_occluder_set_light_mask,RID,int);
+
+
+ FUNC0R(RID,canvas_occluder_polygon_create);
+ FUNC3(canvas_occluder_polygon_set_shape,RID,const DVector<Vector2>&,bool);
+ FUNC2(canvas_occluder_polygon_set_shape_as_lines,RID,const DVector<Vector2>&);
+ FUNC2(canvas_occluder_polygon_set_cull_mode,RID,CanvasOccluderPolygonCullMode);
+
+ /* CANVAS MATERIAL */
+
+ FUNC0R(RID,canvas_item_material_create);
+ FUNC2(canvas_item_material_set_shader,RID,RID);
+ FUNC3(canvas_item_material_set_shader_param,RID,const StringName&,const Variant&);
+ FUNC2RC(Variant,canvas_item_material_get_shader_param,RID,const StringName&);
+ FUNC2(canvas_item_material_set_shading_mode,RID,CanvasItemShadingMode);
/* CURSOR */
FUNC2(cursor_set_rotation,float , int ); // radians
@@ -1139,7 +693,7 @@ public:
virtual void init();
virtual void finish();
virtual void draw();
- virtual void flush();
+ virtual void sync();
FUNC0RC(bool,has_changed);
/* RENDER INFO */
@@ -1147,7 +701,7 @@ public:
FUNC1R(int,get_render_info,RenderInfo );
virtual bool has_feature(Features p_feature) const { return visual_server->has_feature(p_feature); }
- FUNC2(set_boot_image,const Image& , const Color& );
+ FUNC3(set_boot_image,const Image& , const Color&,bool );
FUNC1(set_default_clear_color,const Color& );
FUNC0R(RID,get_test_cube );
@@ -1156,7 +710,15 @@ public:
VisualServerWrapMT(VisualServer* p_contained,bool p_create_thread);
~VisualServerWrapMT();
+#undef ServerName
+#undef ServerNameWrapMT
+#undef server_name
+
};
+#ifdef DEBUG_SYNC
+#undef DEBUG_SYNC
+#endif
+#undef SYNC_DEBUG
#endif
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 8dfcb186a9..25e6a68469 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,6 +28,7 @@
/*************************************************************************/
#include "visual_server.h"
#include "globals.h"
+#include "method_bind_ext.inc"
VisualServer *VisualServer::singleton=NULL;
VisualServer* (*VisualServer::create_func)()=NULL;
@@ -129,6 +130,24 @@ RID VisualServer::get_test_texture() {
return test_texture;
};
+void VisualServer::_free_internal_rids() {
+
+ if (test_texture.is_valid())
+ free(test_texture);
+ if (white_texture.is_valid())
+ free(white_texture);
+ if (test_material.is_valid())
+ free(test_material);
+
+ for(int i=0;i<16;i++) {
+ if (material_2d[i].is_valid())
+ free(material_2d[i]);
+ }
+
+
+
+}
+
RID VisualServer::_make_test_cube() {
DVector<Vector3> vertices;
@@ -145,7 +164,6 @@ RID VisualServer::_make_test_cube() {
tangents.push_back( normal_points[m_idx][0] );\
tangents.push_back( 1.0 );\
uvs.push_back( Vector3(uv_points[m_idx*2+0],uv_points[m_idx*2+1],0) );\
- print_line(itos( (face_points[m_idx][0]>0?1:0)|(face_points[m_idx][1]>0?2:0)|(face_points[m_idx][2]>0?4:0)));\
vtx_idx++;\
for (int i=0;i<6;i++) {
@@ -202,16 +220,17 @@ RID VisualServer::_make_test_cube() {
mesh_add_surface( test_cube, PRIMITIVE_TRIANGLES,d );
- RID material = fixed_material_create();
+
+ test_material = fixed_material_create();
//material_set_flag(material, MATERIAL_FLAG_BILLBOARD_TOGGLE,true);
- fixed_material_set_texture( material, FIXED_MATERIAL_PARAM_DIFFUSE, get_test_texture() );
- fixed_material_set_param( material, FIXED_MATERIAL_PARAM_SPECULAR_EXP, 70 );
- fixed_material_set_param( material, FIXED_MATERIAL_PARAM_EMISSION, Vector3(0.2,0.2,0.2) );
+ fixed_material_set_texture( test_material, FIXED_MATERIAL_PARAM_DIFFUSE, get_test_texture() );
+ fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_SPECULAR_EXP, 70 );
+ fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_EMISSION, Color(0.2,0.2,0.2) );
- fixed_material_set_param( material, FIXED_MATERIAL_PARAM_DIFFUSE, Color(1, 1, 1) );
- fixed_material_set_param( material, FIXED_MATERIAL_PARAM_SPECULAR, Color(1,1,1) );
+ fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_DIFFUSE, Color(1, 1, 1) );
+ fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_SPECULAR, Color(1,1,1) );
- mesh_surface_set_material(test_cube, 0, material );
+ mesh_surface_set_material(test_cube, 0, test_material );
return test_cube;
}
@@ -486,7 +505,7 @@ void VisualServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("instances_cull_aabb"),&VisualServer::instances_cull_aabb);
ObjectTypeDB::bind_method(_MD("instances_cull_ray"),&VisualServer::instances_cull_ray);
- ObjectTypeDB::bind_method(_MD("instances_cull_convex"),&VisualServer::instances_cull_ray);
+ ObjectTypeDB::bind_method(_MD("instances_cull_convex"),&VisualServer::instances_cull_convex);
@@ -510,8 +529,9 @@ void VisualServer::_bind_methods() {
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);
- ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect"),&VisualServer::canvas_item_add_texture_rect, DEFVAL(Color(1,1,1)));
- ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect_region"),&VisualServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1,1,1)));
+ ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect"),&VisualServer::canvas_item_add_texture_rect, DEFVAL(Color(1,1,1)), DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect_region"),&VisualServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1,1,1)), DEFVAL(false));
+
ObjectTypeDB::bind_method(_MD("canvas_item_add_style_box"),&VisualServer::_canvas_item_add_style_box, DEFVAL(Color(1,1,1)));
// ObjectTypeDB::bind_method(_MD("canvas_item_add_primitive"),&VisualServer::canvas_item_add_primitive,DEFVAL(Vector<Vector2>()),DEFVAL(RID()));
ObjectTypeDB::bind_method(_MD("canvas_item_add_circle"),&VisualServer::canvas_item_add_circle);
@@ -534,6 +554,7 @@ void VisualServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("mesh_add_surface_from_planes"),&VisualServer::mesh_add_surface_from_planes);
ObjectTypeDB::bind_method(_MD("draw"),&VisualServer::draw);
+ ObjectTypeDB::bind_method(_MD("sync"),&VisualServer::sync);
ObjectTypeDB::bind_method(_MD("free"),&VisualServer::free);
ObjectTypeDB::bind_method(_MD("set_default_clear_color"),&VisualServer::set_default_clear_color);
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 9cad173903..c5100b8d30 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -55,8 +55,10 @@ class VisualServer : public Object {
void _canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector<float>& p_margins, const Color& p_modulate=Color(1,1,1));
protected:
RID _make_test_cube();
+ void _free_internal_rids();
RID test_texture;
RID white_texture;
+ RID test_material;
RID material_2d[16];
static VisualServer* (*create_func)();
@@ -86,6 +88,10 @@ public:
ARRAY_WEIGHTS_SIZE=4,
MAX_PARTICLE_COLOR_PHASES=4,
MAX_PARTICLE_ATTRACTORS=4,
+ CANVAS_ITEM_Z_MIN=-4096,
+ CANVAS_ITEM_Z_MAX=4096,
+
+
MAX_CURSORS = 8,
};
@@ -96,8 +102,11 @@ public:
TEXTURE_FLAG_MIPMAPS=1, /// Enable automatic mipmap generation - when available
TEXTURE_FLAG_REPEAT=2, /// Repeat texture (Tiling), otherwise Clamping
TEXTURE_FLAG_FILTER=4, /// Create texure with linear (or available) filter
- TEXTURE_FLAG_CUBEMAP=8,
- TEXTURE_FLAG_VIDEO_SURFACE=16,
+ 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
};
@@ -126,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 */
@@ -137,6 +158,7 @@ public:
SHADER_POST_PROCESS,
};
+
virtual RID shader_create(ShaderMode p_mode=SHADER_MATERIAL)=0;
virtual void shader_set_mode(RID p_shader,ShaderMode p_mode)=0;
@@ -148,6 +170,9 @@ public:
virtual String shader_get_light_code(RID p_shader) const=0;
virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const=0;
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture)=0;
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const=0;
+
/* COMMON MATERIAL API */
@@ -166,6 +191,7 @@ public:
MATERIAL_FLAG_UNSHADED,
MATERIAL_FLAG_ONTOP,
MATERIAL_FLAG_LIGHTMAP_ON_UV2,
+ MATERIAL_FLAG_COLOR_ARRAY_SRGB,
MATERIAL_FLAG_MAX,
};
@@ -229,6 +255,7 @@ public:
FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,
FIXED_MATERIAL_FLAG_USE_POINT_SIZE,
FIXED_MATERIAL_FLAG_DISCARD_ALPHA,
+ FIXED_MATERIAL_FLAG_USE_XY_NORMALMAP,
FIXED_MATERIAL_FLAG_MAX,
};
@@ -338,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;
@@ -585,9 +614,35 @@ public:
virtual void baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree)=0;
virtual DVector<uint8_t> baked_light_get_octree(RID p_baked_light) const=0;
+ virtual void baked_light_set_light(RID p_baked_light,const DVector<uint8_t> p_light)=0;
+ virtual DVector<uint8_t> baked_light_get_light(RID p_baked_light) const=0;
+
+ virtual void baked_light_set_sampler_octree(RID p_baked_light,const DVector<int> &p_sampler)=0;
+ virtual DVector<int> baked_light_get_sampler_octree(RID p_baked_light) const=0;
+
+ virtual void baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier)=0;
+ virtual float baked_light_get_lightmap_multiplier(RID p_baked_light) const=0;
+
virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id)=0;
virtual void baked_light_clear_lightmaps(RID p_baked_light)=0;
+ /* BAKED LIGHT SAMPLER */
+
+ virtual RID baked_light_sampler_create()=0;
+
+ enum BakedLightSamplerParam {
+ BAKED_LIGHT_SAMPLER_RADIUS,
+ BAKED_LIGHT_SAMPLER_STRENGTH,
+ BAKED_LIGHT_SAMPLER_ATTENUATION,
+ BAKED_LIGHT_SAMPLER_DETAIL_RATIO,
+ BAKED_LIGHT_SAMPLER_MAX
+ };
+
+ virtual void baked_light_sampler_set_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param,float p_value)=0;
+ virtual float baked_light_sampler_get_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param) const=0;
+
+ virtual void baked_light_sampler_set_resolution(RID p_baked_light_sampler,int p_resolution)=0;
+ virtual int baked_light_sampler_get_resolution(RID p_baked_light_sampler) const=0;
/* CAMERA API */
@@ -646,6 +701,9 @@ public:
virtual RID viewport_get_render_target_texture(RID p_viewport) const=0;
virtual void viewport_set_render_target_vflip(RID p_viewport,bool p_enable)=0;
virtual bool viewport_get_render_target_vflip(RID p_viewport) const=0;
+ virtual void viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable)=0;
+ virtual bool viewport_get_render_target_clear_on_new_frame(RID p_viewport) const=0;
+ virtual void viewport_render_target_clear(RID p_viewport)=0;
virtual void viewport_queue_screen_capture(RID p_viewport)=0;
virtual Image viewport_get_screen_capture(RID p_viewport) const=0;
@@ -663,6 +721,7 @@ public:
virtual void viewport_set_hide_scenario(RID p_viewport,bool p_hide)=0;
virtual void viewport_set_hide_canvas(RID p_viewport,bool p_hide)=0;
+ virtual void viewport_set_disable_environment(RID p_viewport,bool p_disable)=0;
virtual void viewport_attach_camera(RID p_viewport,RID p_camera)=0;
virtual void viewport_set_scenario(RID p_viewport,RID p_scenario)=0;
@@ -693,8 +752,7 @@ public:
ENV_BG_COLOR,
ENV_BG_TEXTURE,
ENV_BG_CUBEMAP,
- ENV_BG_TEXTURE_RGBE,
- ENV_BG_CUBEMAP_RGBE,
+ ENV_BG_CANVAS,
ENV_BG_MAX
};
@@ -703,6 +761,7 @@ public:
enum EnvironmentBGParam {
+ ENV_BG_PARAM_CANVAS_MAX_LAYER,
ENV_BG_PARAM_COLOR,
ENV_BG_PARAM_TEXTURE,
ENV_BG_PARAM_CUBEMAP,
@@ -792,6 +851,7 @@ public:
SCENARIO_DEBUG_DISABLED,
SCENARIO_DEBUG_WIREFRAME,
SCENARIO_DEBUG_OVERDRAW,
+ SCENARIO_DEBUG_SHADELESS,
};
@@ -799,7 +859,7 @@ public:
virtual void scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode)=0;
virtual void scenario_set_environment(RID p_scenario, RID p_environment)=0;
virtual RID scenario_get_environment(RID p_scenario, RID p_environment) const=0;
-
+ virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment)=0;
/* INSTANCING API */
@@ -815,7 +875,8 @@ public:
INSTANCE_ROOM,
INSTANCE_PORTAL,
INSTANCE_BAKED_LIGHT,
-
+ INSTANCE_BAKED_LIGHT_SAMPLER,
+
INSTANCE_GEOMETRY_MASK=(1<<INSTANCE_MESH)|(1<<INSTANCE_MULTIMESH)|(1<<INSTANCE_IMMEDIATE)|(1<<INSTANCE_PARTICLES)
};
@@ -889,9 +950,13 @@ public:
virtual void instance_geometry_set_baked_light(RID p_instance,RID p_baked_light)=0;
virtual RID instance_geometry_get_baked_light(RID p_instance) const=0;
+ virtual void instance_geometry_set_baked_light_sampler(RID p_instance,RID p_baked_light_sampler)=0;
+ virtual RID instance_geometry_get_baked_light_sampler(RID p_instance) const=0;
+
virtual void instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id)=0;
virtual int instance_geometry_get_baked_light_texture_index(RID p_instance) const=0;
+
virtual void instance_light_set_enabled(RID p_instance,bool p_enabled)=0;
virtual bool instance_light_is_enabled(RID p_instance) const=0;
@@ -900,6 +965,8 @@ public:
virtual RID canvas_create()=0;
virtual void canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring)=0;
virtual Point2 canvas_get_item_mirroring(RID p_canvas,RID p_item) const=0;
+ virtual void canvas_set_modulate(RID p_canvas,const Color& p_color)=0;
+
virtual RID canvas_item_create()=0;
@@ -909,6 +976,8 @@ public:
virtual void canvas_item_set_visible(RID p_item,bool p_visible)=0;
virtual bool canvas_item_is_visible(RID p_item) const=0;
+ virtual void canvas_item_set_light_mask(RID p_item,int p_mask)=0;
+
virtual void canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend)=0;
virtual void canvas_item_attach_viewport(RID p_item, RID p_viewport)=0;
@@ -917,6 +986,7 @@ public:
virtual void canvas_item_set_transform(RID p_item, const Matrix32& p_transform)=0;
virtual void canvas_item_set_clip(RID p_item, bool p_clip)=0;
+ virtual void canvas_item_set_distance_field_mode(RID p_item, bool p_enable)=0;
virtual void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect,const Rect2& p_rect=Rect2())=0;
virtual void canvas_item_set_opacity(RID p_item, float p_opacity)=0;
virtual float canvas_item_get_opacity(RID p_item, float p_opacity) const=0;
@@ -930,8 +1000,8 @@ public:
virtual void canvas_item_add_line(RID p_item, const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0)=0;
virtual void canvas_item_add_rect(RID p_item, const Rect2& p_rect, const Color& p_color)=0;
virtual void canvas_item_add_circle(RID p_item, const Point2& p_pos, float p_radius,const Color& p_color)=0;
- virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1))=0;
- virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1))=0;
+ virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1),bool p_transpose=false)=0;
+ virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1),bool p_transpose=false)=0;
virtual void canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center=true,const Color& p_modulate=Color(1,1,1))=0;
virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width=1.0)=0;
virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), RID p_texture=RID())=0;
@@ -940,10 +1010,81 @@ public:
virtual void canvas_item_add_set_transform(RID p_item,const Matrix32& p_transform)=0;
virtual void canvas_item_add_set_blend_mode(RID p_item, MaterialBlendMode p_blend)=0;
virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore)=0;
+ virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable)=0;
+ virtual void canvas_item_set_z(RID p_item, int p_z)=0;
+ virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable)=0;
+ virtual void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable,const Rect2& p_rect)=0;
virtual void canvas_item_clear(RID p_item)=0;
virtual void canvas_item_raise(RID p_item)=0;
+ virtual void canvas_item_set_material(RID p_item, RID p_material)=0;
+
+ virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable)=0;
+
+ virtual RID canvas_light_create()=0;
+ virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas)=0;
+ virtual void canvas_light_set_enabled(RID p_light, bool p_enabled)=0;
+ virtual void canvas_light_set_scale(RID p_light, float p_scale)=0;
+ virtual void canvas_light_set_transform(RID p_light, const Matrix32& p_transform)=0;
+ virtual void canvas_light_set_texture(RID p_light, RID p_texture)=0;
+ virtual void canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset)=0;
+ virtual void canvas_light_set_color(RID p_light, const Color& p_color)=0;
+ virtual void canvas_light_set_height(RID p_light, float p_height)=0;
+ virtual void canvas_light_set_energy(RID p_light, float p_energy)=0;
+ virtual void canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z)=0;
+ virtual void canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer)=0;
+ virtual void canvas_light_set_item_mask(RID p_light, int p_mask)=0;
+ virtual void canvas_light_set_item_shadow_mask(RID p_light, int p_mask)=0;
+
+ enum CanvasLightMode {
+ 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;
+
+
+
+ virtual RID canvas_light_occluder_create()=0;
+ virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas)=0;
+ virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled)=0;
+ virtual void canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon)=0;
+ virtual void canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform)=0;
+ virtual void canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask)=0;
+
+ virtual RID canvas_occluder_polygon_create()=0;
+ virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon,const DVector<Vector2>& p_shape,bool p_closed)=0;
+ virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape)=0;
+ enum CanvasOccluderPolygonCullMode {
+ CANVAS_OCCLUDER_POLYGON_CULL_DISABLED,
+ CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE,
+ CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE,
+ };
+ virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode)=0;
+
+ /* CANVAS ITEM MATERIAL */
+
+ virtual RID canvas_item_material_create()=0;
+ virtual void canvas_item_material_set_shader(RID p_material, RID p_shader)=0;
+ virtual void canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value)=0;
+ virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const=0;
+
+
+ enum CanvasItemShadingMode {
+ CANVAS_ITEM_SHADING_NORMAL,
+ CANVAS_ITEM_SHADING_UNSHADED,
+ CANVAS_ITEM_SHADING_ONLY_LIGHT,
+ };
+
+ virtual void canvas_item_material_set_shading_mode(RID p_material, CanvasItemShadingMode p_mode)=0;
+
/* CURSOR */
virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0)=0; // radians
virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset = Point2(0, 0), int p_cursor=0)=0;
@@ -973,7 +1114,7 @@ public:
/* EVENT QUEUING */
virtual void draw()=0;
- virtual void flush()=0;
+ virtual void sync()=0;
virtual bool has_changed() const=0;
virtual void init()=0;
virtual void finish()=0;
@@ -1015,7 +1156,7 @@ public:
virtual void mesh_add_surface_from_mesh_data( RID p_mesh, const Geometry::MeshData& p_mesh_data);
virtual void mesh_add_surface_from_planes( RID p_mesh, const DVector<Plane>& p_planes);
- virtual void set_boot_image(const Image& p_image, const Color& p_color)=0;
+ virtual void set_boot_image(const Image& p_image, const Color& p_color,bool p_scale)=0;
virtual void set_default_clear_color(const Color& p_color)=0;
enum Features {
diff --git a/tools/Godot.app/Contents/Info.plist b/tools/Godot.app/Contents/Info.plist
index 3a4b51e2fe..8a89993fb9 100755
--- a/tools/Godot.app/Contents/Info.plist
+++ b/tools/Godot.app/Contents/Info.plist
@@ -13,7 +13,7 @@
<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>
@@ -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 4f1432143b..f046e9ad08 100644
--- a/tools/SCsub
+++ b/tools/SCsub
@@ -5,15 +5,16 @@ env.add_source_files(env.tool_sources,"*.cpp")
Export('env')
-SConscript('editor/SCsub');
-#SConscript('scintilla/SCsub');
-SConscript('collada/SCsub');
-SConscript('docdump/SCsub');
-SConscript('freetype/SCsub');
-SConscript('doc/SCsub');
-
-lib = env.Library("tool",env.tool_sources, LIBSUFFIX=env['platform_libsuffix'])
-
-env.Prepend(LIBS=[lib])
+if (env["tools"]!="no"):
+ SConscript('editor/SCsub');
+ #SConscript('scintilla/SCsub');
+ 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 6870a1e926..038cec96d0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 9962eed1b2..deec5f60c7 100644
--- a/tools/collada/collada.cpp
+++ b/tools/collada/collada.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -322,7 +322,7 @@ void Collada::_parse_image(XMLParser& parser) {
String path = parser.get_attribute_value("source").strip_edges();
if (path.find("://")==-1 && path.is_rel_path()) {
// path is relative to file being loaded, so convert to a resource path
- image.path=Globals::get_singleton()->localize_path(state.local_path.get_base_dir()+"/"+path);
+ image.path=Globals::get_singleton()->localize_path(state.local_path.get_base_dir()+"/"+path.percent_decode());
}
} else {
@@ -338,7 +338,7 @@ void Collada::_parse_image(XMLParser& parser) {
if (name=="init_from") {
parser.read();
- String path = parser.get_node_data().strip_edges();
+ String path = parser.get_node_data().strip_edges().percent_decode();
if (path.find("://")==-1 && path.is_rel_path()) {
// path is relative to file being loaded, so convert to a resource path
@@ -443,7 +443,10 @@ Vector<String> Collada::_read_string_array(XMLParser& parser) {
if (parser.get_node_type() == XMLParser::NODE_TEXT) {
// parse String data
String str = parser.get_node_data();
- array=str.split(" ",false);
+ array=str.split_spaces();
+ //for(int i=0;i<array.size();i++) {
+ // print_line(itos(i)+": "+array[i]);
+ //}
}
else
if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
@@ -814,7 +817,7 @@ void Collada::_parse_camera(XMLParser& parser) {
if (name=="perspective") {
camera.mode=CameraData::MODE_PERSPECTIVE;
- } else if (name=="orthogonal") {
+ } else if (name=="orthographic") {
camera.mode=CameraData::MODE_ORTHOGONAL;
} else if (name=="xfov") {
@@ -976,7 +979,7 @@ void Collada::_parse_curve_geometry(XMLParser& parser,String p_id,String p_name)
current_source=id;
COLLADA_PRINT("source data: "+id);
- } else if (section=="float_array" || section=="array" || section=="float_array") {
+ } else if (section=="float_array" || section=="array") {
// create a new array and read it.
if (curvedata.sources.has(current_source)) {
@@ -1388,8 +1391,11 @@ void Collada::_parse_morph_controller(XMLParser& parser, String p_id) {
state.morph_controller_data_map[p_id]=MorphControllerData();
MorphControllerData &morphdata = state.morph_controller_data_map[p_id];
+ print_line("morph source: "+parser.get_attribute_value("source")+" id: "+p_id);
morphdata.mesh=_uri_to_id(parser.get_attribute_value("source"));
+ print_line("morph source2: "+morphdata.mesh);
morphdata.mode=parser.get_attribute_value("method");
+ printf("JJmorph: %p\n",&morphdata);
String current_source;
while(parser.read()==OK) {
@@ -1680,6 +1686,10 @@ Collada::Node* Collada::_parse_visual_scene_node(XMLParser& parser) {
} else if (state.idref_joints.has(name))
joint->sid=name; //kind of a cheat but..
+ if (joint->sid!="") {
+ state.sid_to_node_map[joint->sid]=id;
+ }
+
node=joint;
@@ -2044,8 +2054,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);
@@ -2059,6 +2069,8 @@ void Collada::_parse_animation(XMLParser& parser) {
track.target=target;
}
+ print_line("TARGET: "+track.target);
+
state.animation_tracks.push_back(track);
if (!state.referenced_tracks.has(target))
@@ -2094,6 +2106,8 @@ void Collada::_parse_animation_clip(XMLParser& parser) {
if (parser.has_attribute("name"))
clip.name=parser.get_attribute_value("name");
+ else if (parser.has_attribute("id"))
+ clip.name=parser.get_attribute_value("id");
if (parser.has_attribute("start"))
clip.begin=parser.get_attribute_value("start").to_double();
if (parser.has_attribute("end"))
@@ -2137,6 +2151,7 @@ void Collada::_parse_scene(XMLParser& parser) {
if (name=="instance_visual_scene") {
state.root_visual_scene=_uri_to_id(parser.get_attribute_value("url"));
+ print_line("***ROOT VISUAL SCENE: "+state.root_visual_scene);
} if (name=="instance_physics_scene") {
state.root_physics_scene=_uri_to_id(parser.get_attribute_value("url"));
@@ -2235,27 +2250,35 @@ void Collada::_joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner) {
}
}
-void Collada::_create_skeletons(Collada::Node **p_node) {
+void Collada::_create_skeletons(Collada::Node **p_node,NodeSkeleton *p_skeleton) {
Node *node = *p_node;
if (node->type==Node::TYPE_JOINT) {
- // ohohohoohoo it's a joint node, time to work!
+ if (!p_skeleton) {
+
+ // ohohohoohoo it's a joint node, time to work!
+ NodeSkeleton *sk = memnew( NodeSkeleton );
+ *p_node=sk;
+ sk->children.push_back(node);
+ sk->parent=node->parent;
+ node->parent=sk;
+ p_skeleton=sk;
+ }
- NodeSkeleton *sk = memnew( NodeSkeleton );
- *p_node=sk;
- sk->children.push_back(node);
- sk->parent=node->parent;
- node->parent=sk;
- _joint_set_owner(node,sk);
+ NodeJoint *nj = static_cast<NodeJoint*>(node);
+ nj->owner=p_skeleton;
} else {
+ p_skeleton=NULL;
+ }
- for(int i=0;i<node->children.size();i++) {
- _create_skeletons(&node->children[i]);
- }
+
+ for(int i=0;i<node->children.size();i++) {
+ _create_skeletons(&node->children[i],p_skeleton);
}
+
}
bool Collada::_remove_node(Node *p_parent,Node *p_node) {
@@ -2308,6 +2331,9 @@ void Collada::_merge_skeletons(VisualScene *p_vscene,Node *p_node) {
NodeJoint *nj = SAFE_CAST<NodeJoint*>(state.scene_map[nodeid]);
+ if (!nj->owner) {
+ print_line("no owner for: "+String(nodeid));
+ }
ERR_CONTINUE( !nj->owner ); //weird, node should have a skeleton owner
skeletons.insert(nj->owner);
@@ -2346,6 +2372,79 @@ void Collada::_merge_skeletons(VisualScene *p_vscene,Node *p_node) {
}
+
+void Collada::_merge_skeletons2(VisualScene *p_vscene) {
+
+ for (Map<String,SkinControllerData>::Element *E=state.skin_controller_data_map.front();E;E=E->next()) {
+
+ SkinControllerData &cd=E->get();
+
+ NodeSkeleton *skeleton=NULL;
+
+ for (Map<String,Transform>::Element *F=cd.bone_rest_map.front();F;F=F->next()) {
+
+ String name;
+
+ if (!state.sid_to_node_map.has(F->key())) {
+ continue;
+ }
+
+ name = state.sid_to_node_map[F->key()];
+
+ if (!state.scene_map.has(name)) {
+ print_line("no foundie node for: "+name);
+ }
+
+ ERR_CONTINUE( !state.scene_map.has(name) );
+
+ Node *node=state.scene_map[name];
+ ERR_CONTINUE( node->type!=Node::TYPE_JOINT );
+ if (node->type!=Node::TYPE_JOINT)
+ continue;
+ NodeSkeleton *sk=NULL;
+
+ while(node && !sk) {
+
+ if (node->type==Node::TYPE_SKELETON) {
+ sk=static_cast<NodeSkeleton*>(node);
+ }
+ node=node->parent;
+ }
+ ERR_CONTINUE( !sk );
+
+ if (!sk)
+ continue; //bleh
+
+ if (!skeleton) {
+ skeleton=sk;
+ continue;
+ }
+
+ if (skeleton!=sk) {
+ //whoa.. wtf, merge.
+ print_line("MERGED BONES!!");
+
+ //NodeSkeleton *merged = E->get();
+ _remove_node(p_vscene,sk);
+ for(int i=0;i<sk->children.size();i++) {
+
+ _joint_set_owner(sk->children[i],skeleton);
+ skeleton->children.push_back( sk->children[i] );
+ sk->children[i]->parent=skeleton;
+
+
+ }
+
+ sk->children.clear(); //take children from it
+ memdelete( sk );
+ }
+ }
+ }
+
+
+
+}
+
bool Collada::_optimize_skeletons(VisualScene *p_vscene,Node *p_node) {
Node *node=p_node;
@@ -2431,6 +2530,9 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene,Node *p_node,Lis
ERR_FAIL_COND_V( !state.scene_map.has( nodeid ), false); //weird, it should have it...
NodeJoint *nj = SAFE_CAST<NodeJoint*>(state.scene_map[nodeid]);
ERR_FAIL_COND_V(!nj,false);
+ if (!nj->owner) {
+ print_line("Has no owner: "+nj->name);
+ }
ERR_FAIL_COND_V( !nj->owner,false ); //weird, node should have a skeleton owner
NodeSkeleton *sk = nj->owner;
@@ -2533,10 +2635,14 @@ void Collada::_optimize() {
_create_skeletons(&vs.root_nodes[i]);
}
+#if 1
for(int i=0;i<vs.root_nodes.size();i++) {
_merge_skeletons(&vs,vs.root_nodes[i]);
}
+ _merge_skeletons2(&vs);
+
+
for(int i=0;i<vs.root_nodes.size();i++) {
_optimize_skeletons(&vs,vs.root_nodes[i]);
}
@@ -2557,6 +2663,7 @@ void Collada::_optimize() {
}
}
+#endif
for(int i=0;i<vs.root_nodes.size();i++) {
_find_morph_nodes(&vs,vs.root_nodes[i]);
}
diff --git a/tools/collada/collada.h b/tools/collada/collada.h
index 69ed05beba..81f51a1f3d 100644
--- a/tools/collada/collada.h
+++ b/tools/collada/collada.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -302,6 +302,7 @@ public:
Vector3 uv2;
Plane tangent;
Color color;
+ int uid;
struct Weight {
int bone_idx;
float weight;
@@ -331,21 +332,44 @@ public:
bool operator<(const Vertex& p_vert) const {
- if (vertex==p_vert.vertex) {
- if(normal==p_vert.normal) {
- if(uv==p_vert.uv) {
- if(uv2==p_vert.uv2) {
- return (color<p_vert.color);
+ if (uid==p_vert.uid) {
+ if (vertex==p_vert.vertex) {
+ if(normal==p_vert.normal) {
+ if(uv==p_vert.uv) {
+ if(uv2==p_vert.uv2) {
+
+ if (!weights.empty() || !p_vert.weights.empty()) {
+
+ if (weights.size()==p_vert.weights.size()) {
+
+ for(int i=0;i<weights.size();i++) {
+ if (weights[i].bone_idx!=p_vert.weights[i].bone_idx)
+ return weights[i].bone_idx<p_vert.weights[i].bone_idx;
+
+ if (weights[i].weight!=p_vert.weights[i].weight)
+ return weights[i].weight<p_vert.weights[i].weight;
+ }
+ } else {
+ return weights.size() < p_vert.weights.size();
+ }
+
+ }
+
+ return (color<p_vert.color);
+ } else
+ return (uv2<p_vert.uv2);
} else
- return (uv2<p_vert.uv2);
+ return (uv<p_vert.uv);
} else
- return (uv<p_vert.uv);
+ return (normal<p_vert.normal);
} else
- return (normal<p_vert.normal);
+ return vertex<p_vert.vertex;
} else
- return vertex<p_vert.vertex;
+ return uid < p_vert.uid;
}
+
+ Vertex() { uid=0; idx=0; }
};
struct Node {
@@ -544,6 +568,7 @@ public:
Map<String,VisualScene> visual_scene_map;
Map<String,Node*> scene_map;
Set<String> idref_joints;
+ Map<String,String> sid_to_node_map;
//Map<String,NodeJoint*> bone_map;
Map<String,Transform> bone_rest_map;
@@ -612,10 +637,11 @@ private: // private stuff
Transform _read_transform(XMLParser& parser);
void _joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner);
- void _create_skeletons(Collada::Node **p_node);
+ void _create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton=NULL);
void _find_morph_nodes(VisualScene *p_vscene,Node *p_node);
bool _remove_node(Node *p_parent,Node *p_node);
void _remove_node(VisualScene *p_vscene,Node *p_node);
+ void _merge_skeletons2(VisualScene *p_vscene);
void _merge_skeletons(VisualScene *p_vscene,Node *p_node);
bool _optimize_skeletons(VisualScene *p_vscene,Node *p_node);
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 319c1ad8b7..c1d3e5e314 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -59,6 +59,9 @@ void DocData::merge_from(const DocData& p_data) {
if (cf.methods[j].name!=m.name)
continue;
+ if (cf.methods[j].arguments.size()!=m.arguments.size())
+ continue;
+
const MethodDoc &mf = cf.methods[j];
m.description=mf.description;
@@ -134,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()) {
@@ -186,8 +189,12 @@ void DocData::generate(bool p_basic_types) {
arginfo=E->get().return_val;
if (arginfo.type==Variant::NIL)
continue;
-
- method.return_type=(arginfo.hint==PROPERTY_HINT_RESOURCE_TYPE)?arginfo.hint_string:Variant::get_type_name(arginfo.type);
+#ifdef DEBUG_METHODS_ENABLED
+ if (m && m->get_return_type()!=StringName())
+ method.return_type=m->get_return_type();
+ else
+#endif
+ method.return_type=(arginfo.hint==PROPERTY_HINT_RESOURCE_TYPE)?arginfo.hint_string:Variant::get_type_name(arginfo.type);
} else {
@@ -542,7 +549,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());
@@ -724,6 +731,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
class_list[name]=ClassDoc();
ClassDoc& c = class_list[name];
+// print_line("class: "+name);
c.name=name;
if (parser->has_attribute("inherits"))
c.inherits = parser->get_attribute_value("inherits");
@@ -809,7 +817,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
ERR_FAIL_V(ERR_FILE_CORRUPT);
}
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="members")
+ } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="theme_items")
break; //end of <constants>
}
@@ -911,9 +919,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!="") {
@@ -997,8 +1005,8 @@ Error DocData::save(const String& p_path) {
_write_string(f,1,"</constants>");
- _write_string(f,1,"<theme_items>");
if (c.theme_properties.size()) {
+ _write_string(f,1,"<theme_items>");
for(int i=0;i<c.theme_properties.size();i++) {
@@ -1007,9 +1015,10 @@ Error DocData::save(const String& p_path) {
_write_string(f,2,"</theme_item>");
}
+ _write_string(f,1,"</theme_items>");
}
- _write_string(f,0,"</theme_items>");
+ _write_string(f,0,"</class>");
}
diff --git a/tools/doc/doc_data.h b/tools/doc/doc_data.h
index 018bd67aaf..b62eb21b4a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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
index 897477ff48..3d07f84177 100644
--- a/tools/docdump/class_list.xml
+++ b/tools/docdump/class_list.xml
@@ -319,7 +319,7 @@
<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; arguemnt.
+ Add an animation resource to the player, which will be later referenced by the &quot;name&quot; argument.
</description>
</method>
<method name="remove_animation" >
@@ -3140,7 +3140,7 @@
<constant name="MODE_OPEN_DIR" value="1">
</constant>
<constant name="MODE_OPEN_FILE" value="0">
- Editor will not allow to select unexisting files.
+ Editor will not allow to select nonexistent files.
</constant>
<constant name="MODE_SAVE_FILE" value="2">
Editor will warn when a file exists.
diff --git a/tools/docdump/doc_dump.cpp b/tools/docdump/doc_dump.cpp
index 9fece38995..5f108ee9c8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -65,7 +65,7 @@ static String _escape_string(const String& p_str) {
ret=ret.replace(">","&lt;");
ret=ret.replace("'","&apos;");
ret=ret.replace("\"","&quot;");
- for (int i=1;i<32;i++) {
+ for (char i=1;i<32;i++) {
char chr[2]={i,0};
ret=ret.replace(chr,"&#"+String::num(i)+";");
@@ -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 1f2f8fb484..cb18289e31 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/docdump/locales/es/LC_MESSAGES/makedocs.mo b/tools/docdump/locales/es/LC_MESSAGES/makedocs.mo
new file mode 100644
index 0000000000..8d7ea2689e
--- /dev/null
+++ b/tools/docdump/locales/es/LC_MESSAGES/makedocs.mo
Binary files differ
diff --git a/tools/docdump/locales/es/LC_MESSAGES/makedocs.po b/tools/docdump/locales/es/LC_MESSAGES/makedocs.po
new file mode 100644
index 0000000000..82115dd897
--- /dev/null
+++ b/tools/docdump/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/tools/docdump/makedocs.pot b/tools/docdump/makedocs.pot
new file mode 100644
index 0000000000..be3220f686
--- /dev/null
+++ b/tools/docdump/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/tools/docdump/makedocs.py b/tools/docdump/makedocs.py
new file mode 100644
index 0000000000..be57891abc
--- /dev/null
+++ b/tools/docdump/makedocs.py
@@ -0,0 +1,382 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+#
+# makedocs.py: Generate documentation for Open Project Wiki
+# Copyright (c) 2007-2015 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
+# DokuWiki, Markdown, 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/tools/docdump/makehtml.py b/tools/docdump/makehtml.py
index d533ca1b8b..9b9c62f33b 100644
--- a/tools/docdump/makehtml.py
+++ b/tools/docdump/makehtml.py
@@ -1,5 +1,19 @@
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 = []
@@ -96,7 +110,7 @@ def make_html_class_list(class_list,columns):
idx=0
for n in class_list:
- col = idx/col_max
+ col = int(idx/col_max)
if (col>=columns):
col=columns-1
fit_columns[col]+=[n]
@@ -299,6 +313,7 @@ def make_type(p_type,p_parent):
def make_text_def(class_name,parent,text):
+ text = html_escape(text)
pos=0
while(True):
pos = text.find("[",pos)
@@ -598,7 +613,6 @@ def make_html_class(node):
descr=node.find("description")
if (descr!=None and descr.text.strip()!=""):
-
h4=ET.SubElement(div,"h4")
h4.text="Description:"
@@ -644,7 +658,6 @@ def make_html_class(node):
class_names=[]
classes={}
-
for file in input_list:
tree = ET.parse(file)
doc=tree.getroot()
diff --git a/tools/docdump/makemd.py b/tools/docdump/makemd.py
index 7cc2e9dc4b..f85d145d5e 100644
--- a/tools/docdump/makemd.py
+++ b/tools/docdump/makemd.py
@@ -337,7 +337,7 @@ for file in input_list:
class_names.sort()
-make_class_list(class_names, 3)
+make_class_list(class_names, 2)
for cn in class_names:
c = classes[cn]
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 e693753c33..b8aa5874d1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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
@@ -44,11 +46,207 @@
*/
+class AnimationCurveEdit : public Control {
+ OBJ_TYPE( AnimationCurveEdit, Control );
+public:
+ enum Mode {
+ MODE_DISABLED,
+ MODE_SINGLE,
+ MODE_MULTIPLE
+ };
+private:
+
+ Set<float> multiples;
+ float transition;
+ Mode mode;
+
+ void _notification(int p_what) {
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+
+ RID ci = get_canvas_item();
+
+ Size2 s = get_size();
+ Rect2 r(Point2(),s);
+
+ //r=r.grow(3);
+ Ref<StyleBox> sb = get_stylebox("normal","LineEdit");
+ sb->draw(ci,r);
+ r.size-=sb->get_minimum_size();
+ r.pos+=sb->get_offset();
+ //VisualServer::get_singleton()->canvas_item_add
+
+ Ref<Font> f = get_font("font","Label");
+ r=r.grow(-2);
+ Color color = get_color("font_color","Label");
+
+ int points = 48;
+ if (mode==MODE_MULTIPLE) {
+
+ int max_draw = 16;
+ Color mcolor=color;
+ mcolor.a*=0.3;
+
+ Set<float>::Element *E=multiples.front();
+ for(int j=0;j<16;j++) {
+
+ if (!E)
+ break;
+
+ float prev=1.0;
+ float exp=E->get();
+ bool flip=false;//hint_text=="attenuation";
+
+
+ for(int i=1;i<=points;i++) {
+
+ float ifl = i/float(points);
+ float iflp = (i-1)/float(points);
+
+ float h = 1.0-Math::ease(ifl,exp);
+
+ if (flip) {
+ ifl=1.0-ifl;
+ iflp=1.0-iflp;
+ }
+
+ VisualServer::get_singleton()->canvas_item_add_line(ci,r.pos+Point2(iflp*r.size.width,prev*r.size.height),r.pos+Point2(ifl*r.size.width,h*r.size.height),mcolor);
+ prev=h;
+ }
+
+ E=E->next();
+ }
+ }
+
+ float exp=transition;
+ if (mode!=MODE_DISABLED) {
+
+
+ float prev=1.0;
+
+ bool flip=false;//hint_text=="attenuation";
+
+
+ for(int i=1;i<=points;i++) {
+
+ float ifl = i/float(points);
+ float iflp = (i-1)/float(points);
+
+ float h = 1.0-Math::ease(ifl,exp);
+
+ if (flip) {
+ ifl=1.0-ifl;
+ iflp=1.0-iflp;
+ }
+
+ VisualServer::get_singleton()->canvas_item_add_line(ci,r.pos+Point2(iflp*r.size.width,prev*r.size.height),r.pos+Point2(ifl*r.size.width,h*r.size.height),color);
+ prev=h;
+ }
+ }
+
+ String txt=String::num(exp,2);
+ if (mode==MODE_DISABLED) {
+ txt="Disabled";
+ } else if (mode==MODE_MULTIPLE) {
+ txt+=" - All Selection";
+ }
+
+ f->draw(ci,Point2(10,10+f->get_ascent()),txt,color);
+
+ }
+ }
+
+ void _input_event(const InputEvent& p_ev) {
+ if (p_ev.type==InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT) {
+
+ if (mode==MODE_DISABLED)
+ return;
+
+ float rel = p_ev.mouse_motion.relative_x;
+ if (rel==0)
+ return;
+
+ bool flip=false;
+
+ if (flip)
+ rel=-rel;
+
+ float val = transition;
+ if (val==0)
+ return;
+ bool sg = val < 0;
+ val = Math::absf(val);
+
+ val = Math::log(val)/Math::log(2);
+ //logspace
+ val+=rel*0.05;
+ //
+
+ val = Math::pow(2,val);
+ if (sg)
+ val=-val;
+
+ transition=val;
+ update();
+ //emit_signal("variant_changed");
+ emit_signal("transition_changed",transition);
+ }
+ }
+
+public:
+
+ static void _bind_methods() {
+
+ // ObjectTypeDB::bind_method("_update_obj",&AnimationKeyEdit::_update_obj);
+ ObjectTypeDB::bind_method("_input_event",&AnimationCurveEdit::_input_event);
+ ADD_SIGNAL(MethodInfo("transition_changed"));
+ }
+
+ void set_mode(Mode p_mode) {
+
+ mode=p_mode;
+ update();
+ }
+
+ void clear_multiples() { multiples.clear(); update();}
+ void set_multiple(float p_transition) {
+
+ multiples.insert(p_transition);
+ }
+
+ void set_transition(float p_transition) {
+ transition=p_transition;
+ update();
+ }
+
+ float get_transition() const {
+ return transition;
+ }
+
+ void force_transition(float p_value) {
+ if (mode==MODE_DISABLED)
+ return;
+ transition=p_value;
+ emit_signal("transition_changed",p_value);
+ update();
+ }
+
+ AnimationCurveEdit() {
+
+ transition=1.0;
+ set_default_cursor_shape(CURSOR_HSPLIT);
+ mode=MODE_DISABLED;
+ }
+
+};
+
class AnimationKeyEdit : public Object {
OBJ_TYPE(AnimationKeyEdit,Object);
public:
bool setting;
+ bool hidden;
static void _bind_methods() {
@@ -56,12 +254,12 @@ public:
ObjectTypeDB::bind_method("_key_ofs_changed",&AnimationKeyEdit::_key_ofs_changed);
}
- PopupDialog *ke_dialog;
+ //PopupDialog *ke_dialog;
void _update_obj(const Ref<Animation> &p_anim) {
if (setting)
return;
- if (!ke_dialog->is_visible())
+ if (hidden)
return;
if (!(animation==p_anim))
return;
@@ -69,7 +267,7 @@ public:
}
void _key_ofs_changed(const Ref<Animation> &p_anim,float from, float to) {
- if (!ke_dialog->is_visible())
+ if (hidden)
return;
if (!(animation==p_anim))
return;
@@ -408,8 +606,8 @@ public:
} break;
}
- if (animation->track_get_type(track)!=Animation::TYPE_METHOD)
- p_list->push_back( PropertyInfo( Variant::REAL, "easing", PROPERTY_HINT_EXP_EASING));
+ //if (animation->track_get_type(track)!=Animation::TYPE_METHOD)
+ // p_list->push_back( PropertyInfo( Variant::REAL, "easing", PROPERTY_HINT_EXP_EASING));
}
UndoRedo *undo_redo;
@@ -425,31 +623,46 @@ public:
_change_notify();
}
- AnimationKeyEdit() { key_ofs=0; track=-1; setting=false; }
+ AnimationKeyEdit() { hidden=true; key_ofs=0; track=-1; setting=false; }
};
-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: {
@@ -610,6 +823,8 @@ void AnimationKeyEditor::_menu_track(int p_type) {
selection=new_selection;
track_editor->update();
+ _edit_if_single_selection();
+
}
@@ -687,17 +902,118 @@ void AnimationKeyEditor::_menu_track(int p_type) {
case TRACK_MENU_OPTIMIZE: {
- animation->optimize();
+ 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);
+
+ } break;
+ case CURVE_SET_IN: {
+
+ curve_edit->force_transition(4.0);
+
+ } break;
+ case CURVE_SET_OUT: {
+
+ curve_edit->force_transition(0.25);
+ } break;
+ case CURVE_SET_INOUT: {
+ curve_edit->force_transition(-4);
+
+ } break;
+ case CURVE_SET_OUTIN: {
- track_editor->update();
+ curve_edit->force_transition(-0.25);
} break;
+ case CURVE_SET_CONSTANT: {
+
+ curve_edit->force_transition(0);
+ } break;
+
+ }
+
+}
+
+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() {
+
+
+ print_line("OPTIMIZE!");
+ animation->optimize(optimize_linear_error->get_val(),optimize_angular_error->get_val(),optimize_max_angle->get_val());
+ track_editor->update();
+ undo_redo->clear_history();
+
}
+
float AnimationKeyEditor::_get_zoom_scale() const {
float zv = zoom->get_val();
@@ -762,19 +1078,24 @@ 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);
move_down_button->set_disabled(false);
remove_button->set_disabled(false);
+ if (edit_button->is_pressed())
+ key_editor_tab->show();
te_drawing=true;
@@ -790,6 +1111,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");
@@ -816,6 +1138,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");
@@ -990,13 +1315,35 @@ void AnimationKeyEditor::_track_editor_draw() {
}
}
+ Color sep_color=color;
+ color.a*=0.5;
+
for(int i=0;i<fit;i++) {
+ //this code sucks, i always forget how it works
+
int idx = v_scroll->get_val() + i;
if (idx>=animation->get_track_count())
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;
@@ -1017,6 +1364,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);
@@ -1080,6 +1429,9 @@ void AnimationKeyEditor::_track_editor_draw() {
float key_hofs = -Math::floor(type_icon[tt]->get_height()/2);
int kc=animation->track_get_key_count(idx);
+ bool first=true;
+
+
for(int i=0;i<kc;i++) {
@@ -1087,8 +1439,16 @@ void AnimationKeyEditor::_track_editor_draw() {
float time = animation->track_get_key_time(idx,i);
if (time<keys_from)
continue;
- if (time>keys_to)
+ if (time>keys_to) {
+
+ if (first && i>0 && animation->track_get_key_value(idx,i)==animation->track_get_key_value(idx,i-1)) {
+ //draw whole line
+ te->draw_line(ofs+Vector2(name_limit,y+h/2),ofs+Point2(settings_limit,y+h/2),color);
+ }
+
break;
+ }
+
float x = key_hofs + name_limit + (time-keys_from)*zoom_scale;
Ref<Texture> tex = type_icon[tt];
@@ -1106,7 +1466,36 @@ void AnimationKeyEditor::_track_editor_draw() {
if (mouse_over.over==MouseOver::OVER_KEY && mouse_over.track==idx && mouse_over.over_key==i)
tex=type_hover;
- te->draw_texture(tex,ofs+Point2(x,y+key_vofs).floor());
+ Variant value = animation->track_get_key_value(idx,i);
+ if (first && i>0 && value==animation->track_get_key_value(idx,i-1)) {
+
+ te->draw_line(ofs+Vector2(name_limit,y+h/2),ofs+Point2(x,y+h/2),color);
+ }
+
+ if (i<kc-1 && value==animation->track_get_key_value(idx,i+1)) {
+ float x_n = key_hofs + name_limit + (animation->track_get_key_time(idx,i+1)-keys_from)*zoom_scale;
+
+ x_n = MIN( x_n, settings_limit);
+ te->draw_line(ofs+Point2(x_n,y+h/2),ofs+Point2(x,y+h/2),color);
+
+ }
+
+ 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;
}
}
@@ -1216,7 +1605,9 @@ void AnimationKeyEditor::_clear_selection_for_anim(const Ref<Animation>& p_anim)
if (!(animation==p_anim))
return;
- selection.clear();
+ //selection.clear();
+ _clear_selection();
+
}
void AnimationKeyEditor::_select_at_anim(const Ref<Animation>& p_anim,int p_track,float p_pos){
@@ -1234,6 +1625,7 @@ void AnimationKeyEditor::_select_at_anim(const Ref<Animation>& p_anim,int p_trac
ki.pos=p_pos;
selection.insert(sk,ki);
+
}
@@ -1273,6 +1665,83 @@ PropertyInfo AnimationKeyEditor::_find_hint_for_track(int p_idx) {
}
+void AnimationKeyEditor::_curve_transition_changed(float p_what) {
+
+ if (selection.size()==0)
+ return;
+ if (selection.size()==1)
+ undo_redo->create_action("Edit Node Curve",true);
+ else
+ undo_redo->create_action("Edit Selection Curve",true);
+
+ for(Map<SelectedKey,KeyInfo>::Element *E=selection.front();E;E=E->next()) {
+
+ int track = E->key().track;
+ int key = E->key().key;
+ float prev_val = animation->track_get_key_transition(track,key);
+ undo_redo->add_do_method(animation.ptr(),"track_set_key_transition",track,key,p_what);
+ undo_redo->add_undo_method(animation.ptr(),"track_set_key_transition",track,key,prev_val);
+ }
+
+ undo_redo->commit_action();
+
+}
+
+void AnimationKeyEditor::_toggle_edit_curves() {
+
+ if (edit_button->is_pressed())
+ key_editor_tab->show();
+ else
+ key_editor_tab->hide();
+}
+
+
+bool AnimationKeyEditor::_edit_if_single_selection() {
+
+ if (selection.size()!=1) {
+
+ if (selection.size()==0) {
+ curve_edit->set_mode(AnimationCurveEdit::MODE_DISABLED);
+ print_line("disable");
+ } else {
+
+ curve_edit->set_mode(AnimationCurveEdit::MODE_MULTIPLE);
+ curve_edit->set_transition(1.0);
+ curve_edit->clear_multiples();
+ //add all
+ for(Map<SelectedKey,KeyInfo>::Element *E=selection.front();E;E=E->next()) {
+
+ curve_edit->set_multiple(animation->track_get_key_transition(E->key().track,E->key().key));
+ }
+ print_line("multiple");
+
+ }
+ return false;
+ }
+ curve_edit->set_mode(AnimationCurveEdit::MODE_SINGLE);
+ print_line("regular");
+
+ int idx = selection.front()->key().track;
+ int key = selection.front()->key().key;
+ {
+
+ key_edit->animation=animation;
+ key_edit->track=idx;
+ key_edit->key_ofs=animation->track_get_key_time(idx,key);
+ key_edit->hint=_find_hint_for_track(idx);
+ key_edit->notify_change();
+
+ curve_edit->set_transition(animation->track_get_key_transition(idx,key));
+
+ /*key_edit_dialog->set_size( Size2( 200,200) );
+ key_edit_dialog->set_pos( track_editor->get_global_pos() + ofs + mpos +Point2(-100,20));
+ key_edit_dialog->popup();*/
+
+ }
+
+ return true;
+
+}
void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
@@ -1354,9 +1823,12 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
undo_redo->add_undo_method(animation.ptr(),"track_insert_key",E->key().track,E->get().pos,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key));
}
+ undo_redo->add_do_method(this,"_clear_selection_for_anim",animation);
+ undo_redo->add_undo_method(this,"_clear_selection_for_anim",animation);
undo_redo->commit_action();
- selection.clear();
+ //selection.clear();
accept_event();
+ _edit_if_single_selection();
}
} else if (animation.is_valid() && animation->get_track_count()>0) {
@@ -1365,7 +1837,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (p_input.is_action("ui_up"))
selected_track--;
if (v_scroll->is_visible() && p_input.is_action("ui_page_up"))
- selected_track=selected_track--;;
+ selected_track--;
if (selected_track<0)
selected_track=0;
@@ -1542,20 +2014,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
}
- if (mb.mod.command || edit_button->is_pressed()) {
-
- key_edit->animation=animation;
- key_edit->track=idx;
- key_edit->key_ofs=animation->track_get_key_time(idx,key);
- key_edit->hint=_find_hint_for_track(idx);
-
- key_edit->notify_change();
- key_edit_dialog->set_size( Size2( 200,200) );
- key_edit_dialog->set_pos( track_editor->get_global_pos() + ofs + mpos +Point2(-100,20));
- key_edit_dialog->popup();
-
- }
SelectedKey sk;
sk.track=idx;
@@ -1567,7 +2026,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (!mb.mod.shift && !selection.has(sk))
- selection.clear();
+ _clear_selection();
selection.insert(sk,ki);
@@ -1578,7 +2037,10 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
selected_track=idx;
track_editor->update();
-
+ if (_edit_if_single_selection() && mb.mod.command) {
+ edit_button->set_pressed(true);
+ key_editor_tab->show();
+ }
} else {
//button column
int ofsx = size.width - mpos.x;
@@ -1814,7 +2276,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (from_track>to_track) {
if (!click.shift)
- selection.clear();
+ _clear_selection();
+ _edit_if_single_selection();
break;
}
@@ -1832,12 +2295,13 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (from_track > tracks_to || to_track < tracks_from) {
if (!click.shift)
- selection.clear();
+ _clear_selection();
+ _edit_if_single_selection();
break;
}
if (!click.shift)
- selection.clear();
+ _clear_selection();
int higher_track=0x7FFFFFFF;
@@ -1870,6 +2334,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
}
+ _edit_if_single_selection();
+
} break;
case ClickOver::CLICK_MOVE_KEYS: {
@@ -1881,8 +2347,9 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (!click.shift) {
KeyInfo ki=selection[click.selk];
- selection.clear();
+ _clear_selection();
selection[click.selk]=ki;
+ _edit_if_single_selection();
}
break;
@@ -1997,6 +2464,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
}
undo_redo->commit_action();
+ _edit_if_single_selection();
} break;
default: {}
@@ -2021,7 +2489,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");
@@ -2195,6 +2663,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: {
@@ -2209,8 +2679,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: {
@@ -2233,6 +2728,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;
@@ -2309,14 +2807,16 @@ void AnimationKeyEditor::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ 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();
@@ -2335,22 +2835,37 @@ void AnimationKeyEditor::_notification(int p_what) {
tpp->add_item("Out-In",TRACK_MENU_SET_ALL_TRANS_OUTIN);
tpp->set_name("Transitions");
tpp->connect("item_pressed",this,"_menu_track");
+ optimize_dialog->connect("confirmed",this,"_animation_optimize");
menu_track->get_popup()->add_child(tpp);
- menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions");
+ //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("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"));
+ curve_out->set_icon(get_icon("CurveOut","EditorIcons"));
+ curve_inout->set_icon(get_icon("CurveInOut","EditorIcons"));
+ curve_outin->set_icon(get_icon("CurveOutIn","EditorIcons"));
+ curve_constant->set_icon(get_icon("CurveConstant","EditorIcons"));
+ curve_linear->connect("pressed",this,"_menu_track",varray(CURVE_SET_LINEAR));
+ curve_in->connect("pressed",this,"_menu_track",varray(CURVE_SET_IN));
+ curve_out->connect("pressed",this,"_menu_track",varray(CURVE_SET_OUT));
+ curve_inout->connect("pressed",this,"_menu_track",varray(CURVE_SET_INOUT));
+ curve_outin->connect("pressed",this,"_menu_track",varray(CURVE_SET_OUTIN));
+ curve_constant->connect("pressed",this,"_menu_track",varray(CURVE_SET_CONSTANT));
move_up_button->set_icon(get_icon("MoveUp","EditorIcons"));
move_down_button->set_icon(get_icon("MoveDown","EditorIcons"));
remove_button->set_icon(get_icon("Remove","EditorIcons"));
edit_button->set_icon(get_icon("EditKey","EditorIcons"));
+ edit_button->connect("pressed",this,"_toggle_edit_curves");
loop->set_icon(get_icon("Loop","EditorIcons"));
+ curve_edit->connect("transition_changed",this,"_curve_transition_changed");
//edit_button->add_color_override("font_color",get_color("font_color","Tree"));
//edit_button->add_color_override("font_color_hover",get_color("font_color","Tree"));
@@ -2379,6 +2894,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") );
@@ -2445,6 +2961,17 @@ void AnimationKeyEditor::_update_menu() {
updating=false;
}
+void AnimationKeyEditor::_clear_selection() {
+
+ selection.clear();
+ key_edit->animation=Ref<Animation>();
+ key_edit->track=0;
+ key_edit->key_ofs=0;
+ key_edit->hint=PropertyInfo();
+ key_edit->notify_change();
+
+}
+
void AnimationKeyEditor::set_animation(const Ref<Animation>& p_anim) {
@@ -2455,22 +2982,23 @@ void AnimationKeyEditor::set_animation(const Ref<Animation>& p_anim) {
animation->connect("changed",this,"_update_paths");
timeline_pos=0;
- selection.clear();
+ _clear_selection();
_update_paths();
_update_menu();
selected_track=-1;
+ _edit_if_single_selection();
}
void AnimationKeyEditor::set_root(Node *p_root) {
if (root)
- root->disconnect("exit_scene",this,"_root_removed");
+ root->disconnect("exit_tree",this,"_root_removed");
root=p_root;
if (root)
- root->connect("exit_scene",this,"_root_removed",make_binds(),CONNECT_ONESHOT);
+ root->connect("exit_tree",this,"_root_removed",make_binds(),CONNECT_ONESHOT);
}
@@ -2502,6 +3030,7 @@ void AnimationKeyEditor::_query_insert(const InsertData& p_id) {
if (insert_frame!=OS::get_singleton()->get_frames_drawn()) {
+ //clear insert list for the frame if frame changed
if (insert_confirm->is_visible())
return; //do nothing
insert_data.clear();
@@ -2509,19 +3038,29 @@ void AnimationKeyEditor::_query_insert(const InsertData& p_id) {
}
insert_frame=OS::get_singleton()->get_frames_drawn();
+ for (List<InsertData>::Element *E=insert_data.front();E;E=E->next()) {
+ //prevent insertion of multiple tracks
+ if (E->get().path==p_id.path)
+ return; //already inserted a track for this on this frame
+ }
+
insert_data.push_back(p_id);
if (p_id.track_idx==-1) {
- //potential new key, does not exist
- if (insert_data.size()==1)
- insert_confirm->set_text("Create NEW track for "+p_id.query+" and insert key?");
- else
- insert_confirm->set_text("Create "+itos(insert_data.size())+" NEW tracks and insert keys?");
-
- insert_confirm->get_ok()->set_text("Create");
- insert_confirm->popup_centered(Size2(300,100));
- insert_query=true;
-
+ if (bool(EDITOR_DEF("animation/confirm_insert_track",true))) {
+ //potential new key, does not exist
+ if (insert_data.size()==1)
+ insert_confirm->set_text("Create NEW track for "+p_id.query+" and insert key?");
+ else
+ insert_confirm->set_text("Create "+itos(insert_data.size())+" NEW tracks and insert keys?");
+
+ insert_confirm->get_ok()->set_text("Create");
+ insert_confirm->popup_centered_minsize();
+ insert_query=true;
+ } else {
+ call_deferred("_insert_delay");
+ insert_queue=true;
+ }
} else {
if (!insert_query && !insert_queue) {
@@ -2569,6 +3108,7 @@ void AnimationKeyEditor::insert_transform_key(Spatial *p_node,const String& p_su
id.value=p_xform;
id.type=Animation::TYPE_TRANSFORM;
id.query="node '"+p_node->get_name()+"'";
+ id.advance=false;
//dialog insert
@@ -2621,6 +3161,7 @@ void AnimationKeyEditor::insert_node_value_key(Node* p_node, const String& p_pro
id.value=p_value;
id.type=Animation::TYPE_VALUE;
id.query="property '"+p_property+"'";
+ id.advance=false;
//dialog insert
_query_insert(id);
@@ -2628,7 +3169,7 @@ void AnimationKeyEditor::insert_node_value_key(Node* p_node, const String& p_pro
}
-void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant& p_value) {
+void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant& p_value,bool p_advance) {
ERR_FAIL_COND(!root);
//let's build a node path
@@ -2674,6 +3215,7 @@ void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant
id.value=p_value;
id.type=Animation::TYPE_VALUE;
id.query="property '"+p_property+"'";
+ id.advance=p_advance;
//dialog insert
_query_insert(id);
@@ -2887,11 +3429,11 @@ void AnimationKeyEditor::set_anim_pos(float p_pos) {
void AnimationKeyEditor::_pane_drag(const Point2& p_delta) {
- Size2 ecs = ec->get_minsize();
+ Size2 ecs = ec->get_custom_minimum_size();
ecs.y-=p_delta.y;
if (ecs.y<100)
ecs.y=100;
- ec->set_minsize(ecs);;
+ ec->set_custom_minimum_size(ecs);;
}
@@ -2906,20 +3448,39 @@ void AnimationKeyEditor::_insert_delay() {
undo_redo->create_action("Anim Insert");
int last_track = animation->get_track_count();
+ bool advance=false;
while(insert_data.size()) {
+ if (insert_data.front()->get().advance)
+ advance=true;
last_track=_confirm_insert(insert_data.front()->get(),last_track);
insert_data.pop_front();
}
undo_redo->commit_action();
+
+ if (advance) {
+ float step = animation->get_step();
+ if (step==0)
+ step=1;
+
+ float pos=timeline_pos;
+
+ pos=Math::stepify(pos+step,step);
+ if (pos>animation->get_length())
+ pos=animation->get_length();
+ timeline_pos=pos;
+ track_pos->update();
+ emit_signal("timeline_changed",pos);
+ }
insert_queue=false;
}
void AnimationKeyEditor::_step_changed(float p_len) {
updating=true;
- animation->set_step(p_len);
+ if (!animation.is_null())
+ animation->set_step(p_len);
updating=false;
}
@@ -3055,6 +3616,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>());
@@ -3083,6 +3664,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);
@@ -3099,12 +3681,17 @@ void AnimationKeyEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_animation_len_update"),&AnimationKeyEditor::_animation_len_update);
ObjectTypeDB::bind_method(_MD("set_animation"),&AnimationKeyEditor::set_animation);
+ 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("key_edited", PropertyInfo(Variant::INT,"track"), PropertyInfo(Variant::INT,"key") ) );
}
@@ -3130,15 +3717,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.");
@@ -3196,12 +3774,10 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
hb->add_child( memnew( VSeparator ) );
- edit_button = memnew( ToolButton );
- edit_button->set_toggle_mode(true);
- edit_button->set_focus_mode(FOCUS_NONE);
- edit_button->set_disabled(true);
- hb->add_child(edit_button);
- edit_button->set_tooltip("Enable editing of individual keys by clicking them.");
+ 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);
@@ -3215,7 +3791,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
move_down_button->connect("pressed",this,"_menu_track",make_binds(TRACK_MENU_MOVE_DOWN));
move_down_button->set_focus_mode(FOCUS_NONE);
move_down_button->set_disabled(true);
- move_down_button->set_tooltip("Move current track dosn.");
+ move_down_button->set_tooltip("Move current track down.");
remove_button = memnew( ToolButton );
hb->add_child(remove_button);
@@ -3224,6 +3800,51 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
remove_button->set_disabled(true);
remove_button->set_tooltip("Remove selected track.");
+ 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);
+ edit_button->set_disabled(true);
+
+ hb->add_child(edit_button);
+ edit_button->set_tooltip("Enable editing of individual keys by clicking them.");
+
+ optimize_dialog = memnew( ConfirmationDialog );
+ add_child(optimize_dialog);
+ optimize_dialog->set_title("Anim. Optimizer");
+ VBoxContainer *optimize_vb = memnew( VBoxContainer );
+ optimize_dialog->add_child(optimize_vb);
+ optimize_dialog->set_child_rect(optimize_vb);
+ optimize_linear_error = memnew( SpinBox );
+ optimize_linear_error->set_max(1.0);
+ optimize_linear_error->set_min(0.001);
+ optimize_linear_error->set_step(0.001);
+ optimize_linear_error->set_val(0.05);
+ optimize_vb->add_margin_child("Max. Linear Error:",optimize_linear_error);
+ optimize_angular_error = memnew( SpinBox );
+ optimize_angular_error->set_max(1.0);
+ optimize_angular_error->set_min(0.001);
+ optimize_angular_error->set_step(0.001);
+ optimize_angular_error->set_val(0.01);
+
+ optimize_vb->add_margin_child("Max. Angular Error:",optimize_angular_error);
+ optimize_max_angle = memnew( SpinBox );
+ optimize_vb->add_margin_child("Max Optimizable Angle:",optimize_max_angle);
+ optimize_max_angle->set_max(360.0);
+ optimize_max_angle->set_min(0.0);
+ optimize_max_angle->set_step(0.1);
+ optimize_max_angle->set_val(22);
+
+ optimize_dialog->get_ok()->set_text("Optimize");
+
+
+
/*keying = memnew( Button );
keying->set_toggle_mode(true);
//keying->set_text("Keys");
@@ -3235,15 +3856,15 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
keying->connect("pressed",this,"_keying_toggled");
*/
- l = memnew( Label );
+/* l = memnew( Label );
l->set_text("Base: ");
l->set_pos(Point2(0,3));
-// dr_panel->add_child(l);
+// dr_panel->add_child(l);*/
// menu->get_popup()->connect("item_pressed",this,"_menu_callback");
- ec = memnew (EmptyControl);
- ec->set_minsize(Size2(0,50));
+ ec = memnew (Control);
+ ec->set_custom_minimum_size(Size2(0,150));
add_child(ec);
ec->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -3259,6 +3880,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
track_editor->set_focus_mode(Control::FOCUS_ALL);
track_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+
track_pos = memnew( Control );
track_pos->set_area_as_parent_rect();
track_pos->set_ignore_mouse(true);
@@ -3271,6 +3893,56 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
v_scroll->connect("value_changed",this,"_scroll_changed");
v_scroll->set_val(0);
+ key_editor_tab = memnew(TabContainer);
+ hb->add_child(key_editor_tab);
+ key_editor_tab->set_custom_minimum_size(Size2(200,0));
+
+ key_editor = memnew( PropertyEditor );
+ key_editor->set_area_as_parent_rect();
+ key_editor->hide_top_label();
+ key_editor->set_name("Key");
+ key_editor_tab->add_child(key_editor);
+
+ key_edit = memnew( AnimationKeyEdit );
+ key_edit->undo_redo=undo_redo;
+ //key_edit->ke_dialog=key_edit_dialog;
+ key_editor->edit(key_edit);
+ type_menu = memnew( PopupMenu );
+ add_child(type_menu);
+ for(int i=0;i<Variant::VARIANT_MAX;i++)
+ type_menu->add_item(Variant::get_type_name(Variant::Type(i)),i);
+ type_menu->connect("item_pressed",this,"_create_value_item");
+
+ VBoxContainer *curve_vb = memnew( VBoxContainer );
+ curve_vb->set_name("Transition");
+ HBoxContainer *curve_hb = memnew( HBoxContainer );
+ curve_vb->add_child(curve_hb);
+
+ curve_linear = memnew( ToolButton );
+ curve_linear->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_linear);
+ curve_in = memnew( ToolButton );
+ curve_in->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_in);
+ curve_out = memnew( ToolButton );
+ curve_out->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_out);
+ curve_inout = memnew( ToolButton );
+ curve_inout->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_inout);
+ curve_outin = memnew( ToolButton );
+ curve_outin->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_outin);
+ curve_constant = memnew( ToolButton );
+ curve_constant->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_constant);
+
+
+ curve_edit = memnew( AnimationCurveEdit );
+ curve_vb->add_child(curve_edit);
+ 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);
@@ -3286,7 +3958,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
add_child(track_menu);
track_menu->connect("item_pressed",this,"_track_menu_selected");
-
+ key_editor_tab->hide();
last_idx =1;
@@ -3298,8 +3970,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
add_child(insert_confirm);
insert_confirm->connect("confirmed",this,"_confirm_insert_list");
- EDITOR_DEF("animation_editor/confirm_insert_key",true);
-
click.click=ClickOver::CLICK_NONE;
@@ -3307,24 +3977,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
timeline_pos=0;
- key_edit_dialog = memnew( PopupDialog );
- key_editor = memnew( PropertyEditor );
- add_child(key_edit_dialog);
- key_editor->set_area_as_parent_rect();
- key_editor->hide_top_label();
- for(int i=0;i<4;i++)
- key_editor->set_margin(Margin(i),5);
- key_edit_dialog->add_child(key_editor);
-
- key_edit = memnew( AnimationKeyEdit );
- key_edit->undo_redo=undo_redo;
- key_edit->ke_dialog=key_edit_dialog;
- key_editor->edit(key_edit);
- type_menu = memnew( PopupMenu );
- add_child(type_menu);
- for(int i=0;i<Variant::VARIANT_MAX;i++)
- type_menu->add_item(Variant::get_type_name(Variant::Type(i)),i);
- type_menu->connect("item_pressed",this,"_create_value_item");
keying=false;
insert_frame=0;
insert_query=false;
@@ -3345,6 +3997,34 @@ 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));
+
}
diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h
index 01f6e294cc..743242fe94 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -37,15 +37,17 @@
#include "scene/gui/scroll_bar.h"
#include "scene/gui/tool_button.h"
#include "scene/gui/file_dialog.h"
-#include "scene/gui/empty_control.h"
+#include "scene/gui/tab_container.h"
+
#include "scene/resources/animation.h"
#include "scene/animation/animation_cache.h"
#include "scene_tree_editor.h"
#include "editor_data.h"
#include "property_editor.h"
-
+#include "scene_tree_editor.h"
class AnimationKeyEdit;
+class AnimationCurveEdit;
class AnimationKeyEditor : public VBoxContainer {
@@ -68,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,
@@ -86,7 +88,15 @@ class AnimationKeyEditor : public VBoxContainer {
TRACK_MENU_SET_ALL_TRANS_OUTIN,
TRACK_MENU_NEXT_STEP,
TRACK_MENU_PREV_STEP,
- TRACK_MENU_OPTIMIZE
+ TRACK_MENU_OPTIMIZE,
+ TRACK_MENU_CLEAN_UP,
+ TRACK_MENU_CLEAN_UP_CONFIRM,
+ CURVE_SET_LINEAR,
+ CURVE_SET_IN,
+ CURVE_SET_OUT,
+ CURVE_SET_INOUT,
+ CURVE_SET_OUTIN,
+ CURVE_SET_CONSTANT
};
struct MouseOver {
@@ -157,7 +167,7 @@ class AnimationKeyEditor : public VBoxContainer {
PopupMenu *track_menu;
PopupMenu *type_menu;
- EmptyControl *ec;
+ Control *ec;
TextureFrame *zoomicon;
HSlider *zoom;
//MenuButton *menu;
@@ -169,8 +179,27 @@ class AnimationKeyEditor : public VBoxContainer {
ToolButton *move_down_button;
ToolButton *remove_button;
+ ToolButton *curve_linear;
+ ToolButton *curve_in;
+ ToolButton *curve_out;
+ ToolButton *curve_inout;
+ ToolButton *curve_outin;
+ ToolButton *curve_constant;
+
+
+ ConfirmationDialog *optimize_dialog;
+ SpinBox *optimize_linear_error;
+ 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;
@@ -178,13 +207,15 @@ class AnimationKeyEditor : public VBoxContainer {
Control *track_editor;
Control *track_pos;
+ TabContainer *key_editor_tab;
ConfirmationDialog *scale_dialog;
SpinBox *scale;
- PopupDialog *key_edit_dialog;
PropertyEditor *key_editor;
+ SceneTreeDialog *call_select;
+
Ref<Animation> animation;
void _update_paths();
@@ -198,6 +229,7 @@ class AnimationKeyEditor : public VBoxContainer {
AnimationKeyEdit *key_edit;
+ AnimationCurveEdit *curve_edit;
bool inserting;
@@ -215,6 +247,7 @@ class AnimationKeyEditor : public VBoxContainer {
int track_idx;
Variant value;
String query;
+ bool advance;
};/* insert_data;*/
bool insert_query;
@@ -249,7 +282,7 @@ class AnimationKeyEditor : public VBoxContainer {
void _scale();
-
+ void _clear_selection();
//void _browse_path();
@@ -257,21 +290,29 @@ class AnimationKeyEditor : public VBoxContainer {
StringName alc;
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);
void _select_at_anim(const Ref<Animation>& p_anim,int p_track,float p_pos);
+ void _curve_transition_changed(float p_what);
PropertyInfo _find_hint_for_track(int p_idx);
void _create_value_item(int p_type);
void _pane_drag(const Point2& p_delta);
+ bool _edit_if_single_selection();
+ void _toggle_edit_curves();
void _animation_len_update();
+ void _add_call_track(const NodePath& p_base);
+
void _root_removed();
protected:
@@ -290,7 +331,7 @@ public:
void set_anim_pos(float p_pos);
void insert_node_value_key(Node* p_node, const String& p_property,const Variant& p_value,bool p_only_if_exists=false);
- void insert_value_key(const String& p_property,const Variant& p_value);
+ 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);
diff --git a/tools/editor/array_property_edit.cpp b/tools/editor/array_property_edit.cpp
new file mode 100644
index 0000000000..9cd443270b
--- /dev/null
+++ b/tools/editor/array_property_edit.cpp
@@ -0,0 +1,231 @@
+#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));
+
+ }
+ }
+ 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;
+
+}
+
+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..acfb8e68ed
--- /dev/null
+++ b/tools/editor/array_property_edit.h
@@ -0,0 +1,36 @@
+#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);
+
+ ArrayPropertyEdit();
+};
+
+#endif // ARRAY_PROPERTY_EDIT_H
diff --git a/tools/editor/call_dialog.cpp b/tools/editor/call_dialog.cpp
index 4548d7291c..0e3abcf4ef 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -76,7 +76,7 @@ void CallDialog::_notification(int p_what) {
_update_method_list();
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
call->disconnect("pressed", this,"_call");
cancel->disconnect("pressed", this,"_cancel");
@@ -285,7 +285,7 @@ CallDialog::CallDialog() {
property_editor->set_anchor_and_margin( MARGIN_TOP, ANCHOR_BEGIN, 50 );
property_editor->set_anchor_and_margin( MARGIN_LEFT, ANCHOR_RATIO, 0.55 );
property_editor->set_anchor_and_margin( MARGIN_BOTTOM, ANCHOR_END, 90 );
- property_editor->get_tree()->set_hide_root( true );
+ property_editor->get_scene_tree()->set_hide_root( true );
property_editor->hide_top_label();
add_child(property_editor);
diff --git a/tools/editor/call_dialog.h b/tools/editor/call_dialog.h
index b7bf1affda..fe69847796 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/code_editor.cpp b/tools/editor/code_editor.cpp
index 281415e4b7..0728b3b7c1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -246,14 +246,28 @@ bool FindReplaceDialog::_search() {
if (is_backwards())
flags|=TextEdit::SEARCH_BACKWARDS;
- int line,col;
- bool found = text_edit->search(text,flags,text_edit->cursor_get_line(),text_edit->cursor_get_column(),line,col);
+ int line=text_edit->cursor_get_line(),col=text_edit->cursor_get_column();
+
+ if (is_backwards()) {
+ col-=1;
+ if (col<0) {
+ line-=1;
+ if (line<0) {
+ line=text_edit->get_line_count()-1;
+ }
+ col=text_edit->get_line(line).length();
+ }
+ }
+ bool found = text_edit->search(text,flags,line,col,line,col);
if (found) {
// print_line("found");
text_edit->cursor_set_line(line);
- text_edit->cursor_set_column(col+text.length());
+ if (is_backwards())
+ text_edit->cursor_set_column(col);
+ else
+ text_edit->cursor_set_column(col+text.length());
text_edit->select(line,col,line,col+text.length());
set_error("");
return true;
@@ -473,6 +487,7 @@ FindReplaceDialog::FindReplaceDialog() {
vb->add_child(error_label);
+
set_hide_on_ok(false);
}
@@ -493,15 +508,19 @@ void CodeTextEditor::_text_changed() {
}
void CodeTextEditor::_code_complete_timer_timeout() {
+ if (!is_visible())
+ return;
if (enable_complete_timer)
text_editor->query_code_comple();
}
-void CodeTextEditor::_complete_request(const String& p_request, int p_line) {
+void CodeTextEditor::_complete_request() {
List<String> entries;
- _code_complete_script(text_editor->get_text(),p_request,p_line,&entries);
+ _code_complete_script(text_editor->get_text_for_completion(),&entries);
// print_line("COMPLETE: "+p_request);
+ if (entries.size()==0)
+ return;
Vector<String> strs;
strs.resize(entries.size());
int i=0;
@@ -541,7 +560,7 @@ void CodeTextEditor::_on_settings_change() {
// AUTO BRACE COMPLETION
text_editor->set_auto_brace_completion(
- EDITOR_DEF("text_editor/auto_brace_complete", false)
+ EDITOR_DEF("text_editor/auto_brace_complete", true)
);
code_complete_timer->set_wait_time(
@@ -580,13 +599,27 @@ CodeTextEditor::CodeTextEditor() {
add_child(text_editor);
text_editor->set_area_as_parent_rect();
text_editor->set_margin(MARGIN_BOTTOM,20);
- text_editor->add_font_override("font",get_font("source","Fonts"));
+
+ String editor_font = EDITOR_DEF("text_editor/font", "");
+ bool font_overrode = false;
+ if (editor_font!="") {
+ Ref<Font> fnt = ResourceLoader::load(editor_font);
+ if (fnt.is_valid()) {
+ text_editor->add_font_override("font",fnt);
+ font_overrode = true;
+ }
+ }
+
+ 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);
@@ -605,7 +638,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();
@@ -618,6 +651,8 @@ CodeTextEditor::CodeTextEditor() {
text_editor->connect("request_completion", this,"_complete_request");
Vector<String> cs;
cs.push_back(".");
+ cs.push_back(",");
+ cs.push_back("(");
text_editor->set_completion(true,cs);
idle->connect("timeout", this,"_text_changed_idle_timeout");
diff --git a/tools/editor/code_editor.h b/tools/editor/code_editor.h
index 1804237f18..0c32aeb68f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -135,7 +135,7 @@ class CodeTextEditor : public Control {
void _on_settings_change();
- void _complete_request(const String& p_request,int p_line);
+ void _complete_request();
protected:
void set_error(const String& p_error);
@@ -143,7 +143,7 @@ protected:
virtual void _load_theme_settings() {}
virtual void _validate_script()=0;
- virtual void _code_complete_script(const String& p_code, const String& p_keyword,int p_line, List<String>* r_options) {};
+ virtual void _code_complete_script(const String& p_code, List<String>* r_options) {};
void _text_changed_idle_timeout();
diff --git a/tools/editor/connections_dialog.cpp b/tools/editor/connections_dialog.cpp
index d7158eb7e9..d4937d7114 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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();
}
@@ -172,7 +173,7 @@ void ConnectDialog::ok_pressed() {
if (dst_method->get_text()=="") {
error->set_text("Method in target Node must be specified!");
- error->popup_centered(Size2(300,80));
+ error->popup_centered_minsize();
return;
}
emit_signal("connected");
@@ -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;
@@ -607,6 +616,14 @@ void ConnectionsDialog::_remove_confirm() {
}
*/
+
+struct _ConnectionsDialogMethodInfoSort {
+
+ _FORCE_INLINE_ bool operator()(const MethodInfo& a, const MethodInfo& b) const {
+ return a.name < b.name;
+ }
+};
+
void ConnectionsDialog::update_tree() {
if (!is_visible())
@@ -623,74 +640,133 @@ void ConnectionsDialog::update_tree() {
node->get_signal_list(&node_signals);
-
- for(List<MethodInfo>::Element *E=node_signals.front();E;E=E->next()) {
-
+ //node_signals.sort_custom<_ConnectionsDialogMethodInfoSort>();
+ bool did_script=false;
+ StringName base = node->get_type();
- MethodInfo &mi =E->get();
+ while(base) {
- String signaldesc;
- signaldesc=mi.name+"(";
- StringArray argnames;
- if (mi.arguments.size()) {
- signaldesc+=" ";
- for(int i=0;i<mi.arguments.size();i++) {
+ List<MethodInfo> node_signals;
+ Ref<Texture> icon;
+ String name;
- PropertyInfo &pi = mi.arguments[i];
+ if (!did_script) {
- if (i>0)
- signaldesc+=", ";
- signaldesc+=Variant::get_type_name(pi.type)+" "+(pi.name==""?String("arg "+itos(i)):pi.name);
- argnames.push_back(pi.name);
+ Ref<Script> scr = node->get_script();
+ if (scr.is_valid()) {
+ scr->get_script_signal_list(&node_signals);
+ if (scr->get_path().is_resource_file())
+ name=scr->get_path().get_file();
+ else
+ name=scr->get_type();
+ if (has_icon(scr->get_type(),"EditorIcons")) {
+ icon=get_icon(scr->get_type(),"EditorIcons");
+ }
}
- signaldesc+=" ";
+
+ } else {
+
+ ObjectTypeDB::get_signal_list(base,&node_signals,true);
+ if (has_icon(base,"EditorIcons")) {
+ icon=get_icon(base,"EditorIcons");
+ }
+ name=base;
}
- signaldesc+=")";
-
- TreeItem *item=tree->create_item(root);
- item->set_text(0,signaldesc);
- Dictionary sinfo;
- sinfo["name"]=mi.name;
- sinfo["args"]=argnames;
- item->set_metadata(0,sinfo);
- item->set_icon(0,get_icon("Signal","EditorIcons"));
- List<Object::Connection> connections;
- node->get_signal_connection_list(mi.name,&connections);
+ TreeItem *pitem = NULL;
- for(List<Object::Connection>::Element *F=connections.front();F;F=F->next()) {
+ if (node_signals.size()) {
+ pitem=tree->create_item(root);
+ pitem->set_text(0,name);
+ pitem->set_icon(0,icon);
+ pitem->set_selectable(0,false);
+ pitem->set_editable(0,false);
+ pitem->set_custom_bg_color(0,get_color("prop_subsection","Editor"));
+ node_signals.sort();
+ }
- Object::Connection&c = F->get();
- if (!(c.flags&CONNECT_PERSIST))
- continue;
+ for(List<MethodInfo>::Element *E=node_signals.front();E;E=E->next()) {
- Node *target = c.target->cast_to<Node>();
- if (!target)
- continue;
- String path = String(node->get_path_to(target))+" :: "+c.method+"()";
- if (c.flags&CONNECT_DEFERRED)
- path+=" (deferred)";
- if (c.binds.size()) {
+ MethodInfo &mi =E->get();
+
+ String signaldesc;
+ signaldesc=mi.name+"(";
+ StringArray argnames;
+ if (mi.arguments.size()) {
+ signaldesc+=" ";
+ for(int i=0;i<mi.arguments.size();i++) {
- path+=" binds( ";
- for(int i=0;i<c.binds.size();i++) {
+ PropertyInfo &pi = mi.arguments[i];
if (i>0)
- path+=", ";
- path+=c.binds[i].operator String();
+ signaldesc+=", ";
+ String tname="var";
+ if (pi.type!=Variant::NIL) {
+ tname=Variant::get_type_name(pi.type);
+ }
+ signaldesc+=tname+" "+(pi.name==""?String("arg "+itos(i)):pi.name);
+ argnames.push_back(pi.name);
+
}
- path+=" )";
+ signaldesc+=" ";
}
- TreeItem *item2=tree->create_item(item);
- item2->set_text(0,path);
- item2->set_metadata(0,c);
- item2->set_icon(0,get_icon("Slot","EditorIcons"));
+ signaldesc+=")";
+
+ TreeItem *item=tree->create_item(pitem);
+ item->set_text(0,signaldesc);
+ Dictionary sinfo;
+ sinfo["name"]=mi.name;
+ sinfo["args"]=argnames;
+ item->set_metadata(0,sinfo);
+ item->set_icon(0,get_icon("Signal","EditorIcons"));
+
+ List<Object::Connection> connections;
+ node->get_signal_connection_list(mi.name,&connections);
+
+ for(List<Object::Connection>::Element *F=connections.front();F;F=F->next()) {
+
+ Object::Connection&c = F->get();
+ if (!(c.flags&CONNECT_PERSIST))
+ continue;
+
+ Node *target = c.target->cast_to<Node>();
+ if (!target)
+ continue;
+ 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( ";
+ for(int i=0;i<c.binds.size();i++) {
+
+ if (i>0)
+ path+=", ";
+ path+=c.binds[i].operator String();
+ }
+ path+=" )";
+ }
+
+ TreeItem *item2=tree->create_item(item);
+ item2->set_text(0,path);
+ item2->set_metadata(0,c);
+ item2->set_icon(0,get_icon("Slot","EditorIcons"));
+
+
+ }
+ }
+ if (!did_script) {
+ did_script=true;
+ } else {
+ base=ObjectTypeDB::type_inherits_from(base);
}
}
@@ -713,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 1e223494c8..4a1c3f189c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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
index 746f61ad67..0c98f05706 100644
--- a/tools/editor/console.cpp
+++ b/tools/editor/console.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -129,7 +129,7 @@ void Console::_window_input_event(InputEvent p_event) {
if (p_event.key.scancode==KEY_ESCAPE && !window_has_modal_stack() && is_visible()) {
hide();
- get_scene()->call_group(0,"windows","_cancel_input_ID",p_event.ID);
+ get_tree()->call_group(0,"windows","_cancel_input_ID",p_event.ID);
}
@@ -153,7 +153,7 @@ void Console::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
_resized();
show();
diff --git a/tools/editor/console.h b/tools/editor/console.h
index b4ff62fa75..aff425fcde 100644
--- a/tools/editor/console.h
+++ b/tools/editor/console.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/create_dialog.cpp b/tools/editor/create_dialog.cpp
index 3a6b856247..a9119349c8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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()) {
@@ -225,11 +225,16 @@ void CreateDialog::_confirmed() {
void CreateDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
connect("confirmed",this,"_confirmed");
_update_search();
}
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+ disconnect("confirmed",this,"_confirmed");
+
+ }
if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
@@ -289,7 +294,7 @@ CreateDialog::CreateDialog() {
search_box->connect("input_event",this,"_sbox_input");
search_options = memnew( Tree );
vbc->add_margin_child("Matches:",search_options,true);
- get_ok()->set_text("Open");
+ get_ok()->set_text("Create");
get_ok()->set_disabled(true);
register_text_enter(search_box);
set_hide_on_ok(false);
diff --git a/tools/editor/create_dialog.h b/tools/editor/create_dialog.h
index 35f9f2a1fb..f200e1caf5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/default_saver.cpp b/tools/editor/default_saver.cpp
index bbeda8addb..c865adb1eb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/default_saver.h b/tools/editor/default_saver.h
index 3c5d23b134..4e11ff5592 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 470054ccd4..91f67c4a41 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,7 +26,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-static const int _bi_font_doc_code_font_height=19;
-static const int _bi_font_doc_code_font_ascent=15;
-static const int _bi_font_doc_code_font_charcount=193;
-static const int _bi_font_doc_code_font_characters[]={0, 253, 53, 2, 2, -1, 14, 0, 13, 253, 56, 2, 2, -1, 14, 0, 32, 253, 59, 2, 2, -1, 14, 4, 33, 221, 29, 3, 12, 1, 3, 5, 34, 144, 77, 6, 5, 0, 3, 7, 35, 180, 55, 9, 11, -1, 4, 8, 36, 215, 0, 8, 15, 0, 2, 8, 37, 28, 45, 12, 11, -1, 4, 12, 38, 199, 16, 11, 12, 0, 3, 11, 39, 157, 77, 3, 5, 0, 3, 4, 40, 36, 16, 4, 15, 0, 3, 5, 41, 31, 16, 4, 15, 0, 3, 5, 42, 93, 79, 9, 7, -1, 3, 8, 43, 110, 68, 9, 9, -1, 5, 8, 44, 121, 78, 4, 6, -1, 12, 4, 45, 204, 76, 5, 3, -1, 9, 5, 46, 216, 75, 4, 3, 0, 12, 4, 47, 233, 0, 8, 15, -1, 2, 7, 48, 246, 29, 9, 11, -1, 4, 8, 49, 208, 54, 8, 11, 0, 4, 8, 50, 219, 42, 9, 11, -1, 4, 8, 51, 229, 41, 9, 11, -1, 4, 8, 52, 239, 41, 9, 11, -1, 4, 8, 53, 0, 57, 9, 11, -1, 4, 8, 54, 160, 55, 9, 11, -1, 4, 8, 55, 10, 57, 9, 11, -1, 4, 8, 56, 20, 57, 9, 11, -1, 4, 8, 57, 40, 57, 9, 11, -1, 4, 8, 58, 78, 80, 3, 8, 0, 7, 4, 59, 72, 68, 4, 11, -1, 7, 4, 60, 18, 69, 8, 11, 0, 4, 8, 61, 112, 78, 8, 7, 0, 6, 8, 62, 0, 69, 8, 11, 0, 4, 8, 63, 184, 30, 7, 12, 0, 3, 7, 64, 148, 16, 13, 13, 0, 4, 14, 65, 117, 44, 11, 11, -1, 4, 10, 66, 50, 57, 9, 11, 0, 4, 9, 67, 197, 42, 10, 11, -1, 4, 8, 68, 153, 43, 10, 11, 0, 4, 10, 69, 244, 53, 8, 11, 0, 4, 8, 70, 43, 69, 7, 11, 0, 4, 7, 71, 93, 44, 11, 11, -1, 4, 10, 72, 60, 56, 9, 11, 0, 4, 10, 73, 77, 68, 4, 11, 0, 4, 4, 74, 249, 41, 6, 11, -1, 4, 5, 75, 70, 56, 9, 11, 0, 4, 9, 76, 27, 69, 7, 11, 0, 4, 7, 77, 14, 45, 13, 11, 0, 4, 14, 78, 208, 42, 10, 11, 0, 4, 11, 79, 41, 45, 12, 11, -1, 4, 11, 80, 199, 54, 8, 11, 0, 4, 9, 81, 162, 16, 13, 13, -1, 4, 11, 82, 80, 56, 9, 11, 0, 4, 9, 83, 90, 56, 9, 11, -1, 4, 8, 84, 100, 56, 9, 11, -1, 4, 8, 85, 164, 43, 10, 11, 0, 4, 10, 86, 129, 44, 11, 11, -1, 4, 9, 87, 229, 29, 16, 11, -1, 4, 15, 88, 175, 43, 10, 11, -1, 4, 9, 89, 186, 43, 10, 11, -1, 4, 8, 90, 110, 56, 9, 11, -1, 4, 8, 91, 26, 16, 4, 15, 0, 3, 5, 92, 123, 0, 10, 15, -2, 2, 7, 93, 251, 0, 4, 15, 0, 3, 5, 94, 82, 79, 10, 7, -2, 4, 8, 95, 180, 76, 9, 3, -1, 15, 8, 96, 161, 77, 6, 4, -1, 3, 5, 97, 27, 81, 8, 8, -1, 7, 8, 98, 68, 31, 8, 12, 0, 3, 9, 99, 18, 81, 8, 8, -1, 7, 7, 100, 211, 16, 9, 12, -1, 3, 9, 101, 228, 66, 9, 8, -1, 7, 8, 102, 176, 30, 7, 12, -1, 3, 5, 103, 120, 56, 9, 11, -1, 7, 8, 104, 59, 31, 8, 12, 0, 3, 9, 105, 66, 68, 5, 11, -1, 4, 4, 106, 141, 16, 6, 14, -2, 4, 4, 107, 104, 31, 8, 12, 0, 3, 8, 108, 251, 16, 3, 12, 0, 3, 4, 109, 144, 68, 13, 8, 0, 7, 13, 110, 9, 81, 8, 8, 0, 7, 9, 111, 208, 66, 9, 8, -1, 7, 9, 112, 217, 54, 8, 11, 0, 7, 9, 113, 140, 56, 9, 11, -1, 7, 9, 114, 53, 81, 6, 8, 0, 7, 6, 115, 45, 81, 7, 8, -1, 7, 6, 116, 102, 68, 7, 10, -1, 5, 6, 117, 36, 81, 8, 8, 0, 7, 9, 118, 238, 65, 9, 8, -1, 7, 8, 119, 158, 68, 13, 8, -1, 7, 12, 120, 218, 66, 9, 8, -1, 7, 7, 121, 150, 56, 9, 11, -1, 7, 8, 122, 248, 65, 7, 8, -1, 7, 6, 123, 14, 16, 5, 15, 0, 3, 6, 124, 41, 16, 3, 15, 2, 3, 8, 125, 20, 16, 5, 15, 0, 3, 6, 126, 135, 78, 8, 5, -1, 4, 8, 160, 253, 62, 2, 2, -1, 14, 4, 161, 225, 29, 3, 12, 0, 5, 5, 162, 35, 69, 7, 11, 0, 4, 8, 163, 190, 55, 8, 11, 0, 4, 8, 164, 82, 68, 9, 10, -1, 5, 8, 165, 105, 44, 11, 11, -2, 4, 8, 166, 45, 16, 3, 15, 2, 3, 8, 167, 125, 16, 8, 14, 0, 3, 8, 168, 197, 76, 6, 3, 0, 4, 7, 169, 186, 16, 12, 12, 0, 3, 13, 170, 137, 68, 6, 9, 0, 4, 7, 171, 197, 67, 10, 8, -1, 6, 9, 172, 126, 78, 8, 5, -1, 8, 8, 173, 210, 75, 5, 3, -1, 9, 5, 174, 103, 79, 8, 7, 0, 3, 8, 175, 190, 76, 6, 3, 0, 4, 6, 176, 151, 77, 5, 5, 0, 3, 5, 177, 221, 16, 9, 12, -1, 3, 8, 178, 60, 81, 6, 8, -1, 2, 5, 179, 67, 80, 5, 8, -1, 2, 5, 180, 168, 77, 6, 4, -1, 3, 5, 181, 170, 55, 9, 11, 0, 7, 9, 182, 176, 16, 9, 13, 0, 4, 10, 183, 221, 75, 3, 3, 0, 9, 4, 184, 175, 76, 4, 4, 0, 14, 5, 185, 73, 80, 4, 8, 0, 2, 4, 186, 129, 68, 7, 9, 0, 4, 7, 187, 185, 67, 11, 8, -1, 6, 9, 188, 54, 44, 12, 11, -2, 4, 11, 189, 67, 44, 12, 11, -2, 4, 11, 190, 80, 44, 12, 11, -1, 4, 11, 191, 192, 29, 7, 12, -1, 5, 7, 192, 88, 0, 11, 15, -1, 0, 10, 193, 64, 0, 11, 15, -1, 0, 10, 194, 76, 0, 11, 15, -1, 0, 10, 195, 100, 0, 11, 15, -1, 0, 10, 196, 74, 16, 11, 14, -1, 1, 10, 197, 62, 16, 11, 14, -1, 1, 10, 198, 0, 45, 13, 11, -1, 4, 12, 199, 107, 16, 8, 14, 0, 4, 8, 200, 188, 0, 8, 15, 0, 0, 8, 201, 206, 0, 8, 15, 0, 0, 8, 202, 224, 0, 8, 15, 0, 0, 8, 203, 116, 16, 8, 14, 0, 1, 8, 204, 0, 16, 6, 15, -2, 0, 4, 205, 7, 16, 6, 15, -1, 0, 4, 206, 242, 0, 8, 15, -2, 0, 4, 207, 134, 16, 6, 14, -1, 1, 4, 208, 141, 44, 11, 11, -1, 4, 10, 209, 145, 0, 10, 15, 0, 0, 11, 210, 0, 0, 12, 15, -1, 0, 11, 211, 39, 0, 12, 15, -1, 0, 11, 212, 26, 0, 12, 15, -1, 0, 11, 213, 13, 0, 12, 15, -1, 0, 11, 214, 49, 16, 12, 14, -1, 1, 11, 215, 0, 81, 8, 8, 0, 6, 8, 216, 52, 0, 11, 15, 0, 2, 11, 217, 167, 0, 10, 15, 0, 0, 10, 218, 134, 0, 10, 15, 0, 0, 10, 219, 156, 0, 10, 15, 0, 0, 10, 220, 86, 16, 10, 14, 0, 1, 10, 221, 112, 0, 10, 15, -1, 0, 8, 222, 226, 54, 8, 11, 0, 4, 9, 223, 77, 31, 8, 12, 0, 3, 9, 224, 113, 31, 8, 12, -1, 3, 8, 225, 122, 31, 8, 12, -1, 3, 8, 226, 131, 31, 8, 12, -1, 3, 8, 227, 167, 30, 8, 12, -1, 3, 8, 228, 235, 53, 8, 11, -1, 4, 8, 229, 50, 31, 8, 12, -1, 3, 8, 230, 172, 67, 12, 8, 0, 7, 12, 231, 51, 69, 7, 11, 0, 7, 7, 232, 40, 32, 9, 12, -1, 3, 8, 233, 231, 16, 9, 12, -1, 3, 8, 234, 241, 16, 9, 12, -1, 3, 8, 235, 30, 57, 9, 11, -1, 4, 8, 236, 200, 29, 6, 12, -2, 3, 4, 237, 214, 29, 6, 12, -1, 3, 4, 238, 207, 29, 6, 12, -1, 3, 4, 239, 59, 69, 6, 11, -1, 4, 4, 240, 86, 31, 8, 12, 0, 3, 9, 241, 95, 31, 8, 12, 0, 3, 9, 242, 0, 32, 9, 12, -1, 3, 9, 243, 10, 32, 9, 12, -1, 3, 9, 244, 20, 32, 9, 12, -1, 3, 9, 245, 30, 32, 9, 12, -1, 3, 9, 246, 130, 56, 9, 11, -1, 4, 9, 247, 120, 68, 8, 9, -1, 5, 8, 248, 92, 68, 9, 10, 0, 6, 9, 249, 140, 31, 8, 12, 0, 3, 9, 250, 149, 30, 8, 12, 0, 3, 9, 251, 158, 30, 8, 12, 0, 3, 9, 252, 9, 69, 8, 11, 0, 4, 9, 253, 178, 0, 9, 15, -1, 3, 8, 254, 197, 0, 8, 15, 0, 3, 9, 255, 97, 16, 9, 14, -1, 4, 8};
+static const int _bi_font_doc_code_font_height=19;
+static const int _bi_font_doc_code_font_ascent=15;
+static const int _bi_font_doc_code_font_charcount=193;
+static const int _bi_font_doc_code_font_characters[]={0, 253, 53, 2, 2, -1, 14, 0, 13, 253, 56, 2, 2, -1, 14, 0, 32, 253, 59, 2, 2, -1, 14, 4, 33, 221, 29, 3, 12, 1, 3, 5, 34, 144, 77, 6, 5, 0, 3, 7, 35, 180, 55, 9, 11, -1, 4, 8, 36, 215, 0, 8, 15, 0, 2, 8, 37, 28, 45, 12, 11, -1, 4, 12, 38, 199, 16, 11, 12, 0, 3, 11, 39, 157, 77, 3, 5, 0, 3, 4, 40, 36, 16, 4, 15, 0, 3, 5, 41, 31, 16, 4, 15, 0, 3, 5, 42, 93, 79, 9, 7, -1, 3, 8, 43, 110, 68, 9, 9, -1, 5, 8, 44, 121, 78, 4, 6, -1, 12, 4, 45, 204, 76, 5, 3, -1, 9, 5, 46, 216, 75, 4, 3, 0, 12, 4, 47, 233, 0, 8, 15, -1, 2, 7, 48, 246, 29, 9, 11, -1, 4, 8, 49, 208, 54, 8, 11, 0, 4, 8, 50, 219, 42, 9, 11, -1, 4, 8, 51, 229, 41, 9, 11, -1, 4, 8, 52, 239, 41, 9, 11, -1, 4, 8, 53, 0, 57, 9, 11, -1, 4, 8, 54, 160, 55, 9, 11, -1, 4, 8, 55, 10, 57, 9, 11, -1, 4, 8, 56, 20, 57, 9, 11, -1, 4, 8, 57, 40, 57, 9, 11, -1, 4, 8, 58, 78, 80, 3, 8, 0, 7, 4, 59, 72, 68, 4, 11, -1, 7, 4, 60, 18, 69, 8, 11, 0, 4, 8, 61, 112, 78, 8, 7, 0, 6, 8, 62, 0, 69, 8, 11, 0, 4, 8, 63, 184, 30, 7, 12, 0, 3, 7, 64, 148, 16, 13, 13, 0, 4, 14, 65, 117, 44, 11, 11, -1, 4, 10, 66, 50, 57, 9, 11, 0, 4, 9, 67, 197, 42, 10, 11, -1, 4, 8, 68, 153, 43, 10, 11, 0, 4, 10, 69, 244, 53, 8, 11, 0, 4, 8, 70, 43, 69, 7, 11, 0, 4, 7, 71, 93, 44, 11, 11, -1, 4, 10, 72, 60, 56, 9, 11, 0, 4, 10, 73, 77, 68, 4, 11, 0, 4, 4, 74, 249, 41, 6, 11, -1, 4, 5, 75, 70, 56, 9, 11, 0, 4, 9, 76, 27, 69, 7, 11, 0, 4, 7, 77, 14, 45, 13, 11, 0, 4, 14, 78, 208, 42, 10, 11, 0, 4, 11, 79, 41, 45, 12, 11, -1, 4, 11, 80, 199, 54, 8, 11, 0, 4, 9, 81, 162, 16, 13, 13, -1, 4, 11, 82, 80, 56, 9, 11, 0, 4, 9, 83, 90, 56, 9, 11, -1, 4, 8, 84, 100, 56, 9, 11, -1, 4, 8, 85, 164, 43, 10, 11, 0, 4, 10, 86, 129, 44, 11, 11, -1, 4, 9, 87, 229, 29, 16, 11, -1, 4, 15, 88, 175, 43, 10, 11, -1, 4, 9, 89, 186, 43, 10, 11, -1, 4, 8, 90, 110, 56, 9, 11, -1, 4, 8, 91, 26, 16, 4, 15, 0, 3, 5, 92, 123, 0, 10, 15, -2, 2, 7, 93, 251, 0, 4, 15, 0, 3, 5, 94, 82, 79, 10, 7, -2, 4, 8, 95, 180, 76, 9, 3, -1, 15, 8, 96, 161, 77, 6, 4, -1, 3, 5, 97, 27, 81, 8, 8, -1, 7, 8, 98, 68, 31, 8, 12, 0, 3, 9, 99, 18, 81, 8, 8, -1, 7, 7, 100, 211, 16, 9, 12, -1, 3, 9, 101, 228, 66, 9, 8, -1, 7, 8, 102, 176, 30, 7, 12, -1, 3, 5, 103, 120, 56, 9, 11, -1, 7, 8, 104, 59, 31, 8, 12, 0, 3, 9, 105, 66, 68, 5, 11, -1, 4, 4, 106, 141, 16, 6, 14, -2, 4, 4, 107, 104, 31, 8, 12, 0, 3, 8, 108, 251, 16, 3, 12, 0, 3, 4, 109, 144, 68, 13, 8, 0, 7, 13, 110, 9, 81, 8, 8, 0, 7, 9, 111, 208, 66, 9, 8, -1, 7, 9, 112, 217, 54, 8, 11, 0, 7, 9, 113, 140, 56, 9, 11, -1, 7, 9, 114, 53, 81, 6, 8, 0, 7, 6, 115, 45, 81, 7, 8, -1, 7, 6, 116, 102, 68, 7, 10, -1, 5, 6, 117, 36, 81, 8, 8, 0, 7, 9, 118, 238, 65, 9, 8, -1, 7, 8, 119, 158, 68, 13, 8, -1, 7, 12, 120, 218, 66, 9, 8, -1, 7, 7, 121, 150, 56, 9, 11, -1, 7, 8, 122, 248, 65, 7, 8, -1, 7, 6, 123, 14, 16, 5, 15, 0, 3, 6, 124, 41, 16, 3, 15, 2, 3, 8, 125, 20, 16, 5, 15, 0, 3, 6, 126, 135, 78, 8, 5, -1, 4, 8, 160, 253, 62, 2, 2, -1, 14, 4, 161, 225, 29, 3, 12, 0, 5, 5, 162, 35, 69, 7, 11, 0, 4, 8, 163, 190, 55, 8, 11, 0, 4, 8, 164, 82, 68, 9, 10, -1, 5, 8, 165, 105, 44, 11, 11, -2, 4, 8, 166, 45, 16, 3, 15, 2, 3, 8, 167, 125, 16, 8, 14, 0, 3, 8, 168, 197, 76, 6, 3, 0, 4, 7, 169, 186, 16, 12, 12, 0, 3, 13, 170, 137, 68, 6, 9, 0, 4, 7, 171, 197, 67, 10, 8, -1, 6, 9, 172, 126, 78, 8, 5, -1, 8, 8, 173, 210, 75, 5, 3, -1, 9, 5, 174, 103, 79, 8, 7, 0, 3, 8, 175, 190, 76, 6, 3, 0, 4, 6, 176, 151, 77, 5, 5, 0, 3, 5, 177, 221, 16, 9, 12, -1, 3, 8, 178, 60, 81, 6, 8, -1, 2, 5, 179, 67, 80, 5, 8, -1, 2, 5, 180, 168, 77, 6, 4, -1, 3, 5, 181, 170, 55, 9, 11, 0, 7, 9, 182, 176, 16, 9, 13, 0, 4, 10, 183, 221, 75, 3, 3, 0, 9, 4, 184, 175, 76, 4, 4, 0, 14, 5, 185, 73, 80, 4, 8, 0, 2, 4, 186, 129, 68, 7, 9, 0, 4, 7, 187, 185, 67, 11, 8, -1, 6, 9, 188, 54, 44, 12, 11, -2, 4, 11, 189, 67, 44, 12, 11, -2, 4, 11, 190, 80, 44, 12, 11, -1, 4, 11, 191, 192, 29, 7, 12, -1, 5, 7, 192, 88, 0, 11, 15, -1, 0, 10, 193, 64, 0, 11, 15, -1, 0, 10, 194, 76, 0, 11, 15, -1, 0, 10, 195, 100, 0, 11, 15, -1, 0, 10, 196, 74, 16, 11, 14, -1, 1, 10, 197, 62, 16, 11, 14, -1, 1, 10, 198, 0, 45, 13, 11, -1, 4, 12, 199, 107, 16, 8, 14, 0, 4, 8, 200, 188, 0, 8, 15, 0, 0, 8, 201, 206, 0, 8, 15, 0, 0, 8, 202, 224, 0, 8, 15, 0, 0, 8, 203, 116, 16, 8, 14, 0, 1, 8, 204, 0, 16, 6, 15, -2, 0, 4, 205, 7, 16, 6, 15, -1, 0, 4, 206, 242, 0, 8, 15, -2, 0, 4, 207, 134, 16, 6, 14, -1, 1, 4, 208, 141, 44, 11, 11, -1, 4, 10, 209, 145, 0, 10, 15, 0, 0, 11, 210, 0, 0, 12, 15, -1, 0, 11, 211, 39, 0, 12, 15, -1, 0, 11, 212, 26, 0, 12, 15, -1, 0, 11, 213, 13, 0, 12, 15, -1, 0, 11, 214, 49, 16, 12, 14, -1, 1, 11, 215, 0, 81, 8, 8, 0, 6, 8, 216, 52, 0, 11, 15, 0, 2, 11, 217, 167, 0, 10, 15, 0, 0, 10, 218, 134, 0, 10, 15, 0, 0, 10, 219, 156, 0, 10, 15, 0, 0, 10, 220, 86, 16, 10, 14, 0, 1, 10, 221, 112, 0, 10, 15, -1, 0, 8, 222, 226, 54, 8, 11, 0, 4, 9, 223, 77, 31, 8, 12, 0, 3, 9, 224, 113, 31, 8, 12, -1, 3, 8, 225, 122, 31, 8, 12, -1, 3, 8, 226, 131, 31, 8, 12, -1, 3, 8, 227, 167, 30, 8, 12, -1, 3, 8, 228, 235, 53, 8, 11, -1, 4, 8, 229, 50, 31, 8, 12, -1, 3, 8, 230, 172, 67, 12, 8, 0, 7, 12, 231, 51, 69, 7, 11, 0, 7, 7, 232, 40, 32, 9, 12, -1, 3, 8, 233, 231, 16, 9, 12, -1, 3, 8, 234, 241, 16, 9, 12, -1, 3, 8, 235, 30, 57, 9, 11, -1, 4, 8, 236, 200, 29, 6, 12, -2, 3, 4, 237, 214, 29, 6, 12, -1, 3, 4, 238, 207, 29, 6, 12, -1, 3, 4, 239, 59, 69, 6, 11, -1, 4, 4, 240, 86, 31, 8, 12, 0, 3, 9, 241, 95, 31, 8, 12, 0, 3, 9, 242, 0, 32, 9, 12, -1, 3, 9, 243, 10, 32, 9, 12, -1, 3, 9, 244, 20, 32, 9, 12, -1, 3, 9, 245, 30, 32, 9, 12, -1, 3, 9, 246, 130, 56, 9, 11, -1, 4, 9, 247, 120, 68, 8, 9, -1, 5, 8, 248, 92, 68, 9, 10, 0, 6, 9, 249, 140, 31, 8, 12, 0, 3, 9, 250, 149, 30, 8, 12, 0, 3, 9, 251, 158, 30, 8, 12, 0, 3, 9, 252, 9, 69, 8, 11, 0, 4, 9, 253, 178, 0, 9, 15, -1, 3, 8, 254, 197, 0, 8, 15, 0, 3, 9, 255, 97, 16, 9, 14, -1, 4, 8};
diff --git a/tools/editor/doc_font.h b/tools/editor/doc_font.h
index fe998cfb16..f2e5e7950b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,7 +26,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-static const int _bi_font_doc_font_height=18;
-static const int _bi_font_doc_font_ascent=14;
-static const int _bi_font_doc_font_charcount=193;
-static const int _bi_font_doc_font_characters[]={0, 253, 3, 2, 2, -1, 13, 0, 13, 253, 9, 2, 2, -1, 13, 0, 32, 253, 0, 2, 2, -1, 13, 3, 33, 220, 26, 3, 11, 1, 3, 5, 34, 187, 59, 5, 5, 0, 3, 6, 35, 88, 40, 9, 10, -1, 4, 7, 36, 50, 0, 8, 14, -1, 2, 7, 37, 175, 14, 11, 11, -1, 3, 11, 38, 187, 14, 11, 11, -1, 3, 10, 39, 198, 58, 3, 5, 0, 3, 3, 40, 98, 0, 4, 14, 0, 3, 5, 41, 103, 0, 4, 14, 0, 3, 5, 42, 146, 61, 7, 6, 0, 3, 7, 43, 246, 48, 8, 8, -1, 5, 7, 44, 193, 58, 4, 5, -1, 11, 4, 45, 13, 73, 5, 2, 0, 9, 5, 46, 241, 57, 3, 3, 0, 11, 4, 47, 84, 0, 7, 14, -1, 2, 6, 48, 246, 37, 8, 10, -1, 4, 7, 49, 33, 52, 7, 10, 0, 4, 7, 50, 237, 37, 8, 10, -1, 4, 7, 51, 219, 38, 8, 10, -1, 4, 7, 52, 128, 39, 9, 10, -1, 4, 7, 53, 41, 52, 7, 10, -1, 4, 7, 54, 9, 53, 7, 10, 0, 4, 7, 55, 228, 38, 8, 10, -1, 4, 7, 56, 57, 52, 7, 10, 0, 4, 7, 57, 65, 51, 7, 10, 0, 4, 7, 58, 98, 62, 4, 8, 0, 6, 4, 59, 162, 50, 5, 10, -1, 6, 4, 60, 174, 49, 8, 9, -1, 4, 7, 61, 179, 59, 7, 5, 0, 7, 7, 62, 228, 49, 8, 8, -1, 5, 7, 63, 89, 28, 7, 11, 0, 3, 7, 64, 54, 15, 12, 12, 0, 4, 13, 65, 36, 41, 10, 10, -1, 4, 9, 66, 97, 51, 7, 10, 0, 4, 8, 67, 174, 38, 8, 10, 0, 4, 8, 68, 156, 39, 8, 10, 0, 4, 9, 69, 105, 51, 7, 10, 0, 4, 7, 70, 121, 51, 6, 10, 0, 4, 7, 71, 0, 53, 8, 10, 0, 4, 9, 72, 192, 38, 8, 10, 0, 4, 9, 73, 251, 26, 3, 10, 0, 4, 4, 74, 156, 50, 5, 10, -1, 4, 5, 75, 147, 39, 8, 10, 0, 4, 8, 76, 135, 50, 6, 10, 0, 4, 6, 77, 13, 41, 11, 10, 0, 4, 12, 78, 210, 38, 8, 10, 0, 4, 10, 79, 68, 40, 9, 10, 0, 4, 10, 80, 113, 51, 7, 10, 0, 4, 8, 81, 199, 14, 10, 11, 0, 4, 10, 82, 183, 38, 8, 10, 0, 4, 8, 83, 128, 50, 6, 10, 0, 4, 7, 84, 108, 40, 9, 10, -1, 4, 7, 85, 165, 39, 8, 10, 0, 4, 9, 86, 25, 41, 10, 10, -1, 4, 9, 87, 236, 26, 14, 10, -1, 4, 13, 88, 98, 40, 9, 10, -1, 4, 8, 89, 118, 40, 9, 10, -1, 4, 7, 90, 138, 39, 8, 10, -1, 4, 7, 91, 49, 15, 4, 13, 0, 3, 5, 92, 76, 0, 7, 14, -1, 2, 6, 93, 43, 15, 5, 13, -1, 3, 5, 94, 137, 61, 8, 6, -1, 4, 7, 95, 245, 57, 9, 2, -1, 15, 7, 96, 230, 58, 5, 3, -1, 3, 4, 97, 57, 63, 7, 8, 0, 6, 7, 98, 81, 28, 7, 11, 0, 3, 8, 99, 79, 62, 6, 8, 0, 6, 6, 100, 33, 29, 7, 11, 0, 3, 8, 101, 9, 64, 7, 8, 0, 6, 8, 102, 200, 26, 6, 11, -1, 3, 5, 103, 153, 27, 7, 11, 0, 6, 7, 104, 121, 27, 7, 11, 0, 3, 8, 105, 224, 26, 3, 11, 0, 3, 4, 106, 92, 0, 5, 14, -2, 3, 4, 107, 25, 29, 7, 11, 0, 3, 7, 108, 228, 26, 3, 11, 0, 3, 4, 109, 204, 49, 11, 8, 0, 6, 12, 110, 17, 63, 7, 8, 0, 6, 8, 111, 33, 63, 7, 8, 0, 6, 8, 112, 17, 29, 7, 11, 0, 6, 8, 113, 9, 29, 7, 11, 0, 6, 8, 114, 86, 62, 5, 8, 0, 6, 5, 115, 92, 62, 5, 8, 0, 6, 6, 116, 168, 50, 5, 10, -1, 4, 5, 117, 49, 63, 7, 8, 0, 6, 8, 118, 0, 64, 8, 8, -1, 6, 7, 119, 216, 49, 11, 8, -1, 6, 10, 120, 41, 63, 7, 8, -1, 6, 7, 121, 0, 30, 8, 11, -1, 6, 7, 122, 72, 62, 6, 8, 0, 6, 6, 123, 8, 15, 6, 13, -1, 3, 5, 124, 0, 0, 3, 15, 1, 2, 7, 125, 15, 15, 6, 13, -1, 3, 5, 126, 202, 58, 8, 4, -1, 4, 7, 160, 253, 6, 2, 2, -1, 13, 3, 161, 232, 26, 3, 11, 0, 4, 5, 162, 149, 50, 6, 10, 0, 4, 7, 163, 17, 52, 7, 10, 0, 4, 7, 164, 183, 49, 8, 9, -1, 5, 7, 165, 47, 41, 10, 10, -2, 4, 7, 166, 4, 0, 3, 15, 2, 2, 7, 167, 122, 14, 7, 12, 0, 3, 7, 168, 0, 73, 6, 2, -1, 4, 6, 169, 162, 14, 12, 11, 0, 3, 13, 170, 65, 62, 6, 8, -1, 4, 6, 171, 112, 62, 8, 7, -1, 6, 8, 172, 211, 58, 7, 4, -1, 8, 7, 173, 19, 72, 5, 2, 0, 9, 5, 174, 103, 62, 8, 7, -1, 3, 8, 175, 7, 73, 5, 2, 0, 3, 6, 176, 171, 61, 7, 5, -1, 3, 5, 177, 58, 40, 9, 10, -1, 4, 7, 178, 154, 61, 5, 6, 0, 2, 5, 179, 160, 61, 5, 6, -1, 2, 5, 180, 224, 58, 5, 3, -1, 3, 4, 181, 241, 14, 8, 11, 0, 6, 8, 182, 97, 15, 8, 12, 0, 4, 9, 183, 236, 58, 4, 3, 0, 8, 4, 184, 219, 58, 4, 4, 0, 13, 5, 185, 166, 61, 4, 6, 0, 2, 4, 186, 25, 63, 7, 8, -1, 4, 6, 187, 129, 61, 7, 7, 0, 6, 8, 188, 221, 14, 9, 11, 0, 3, 10, 189, 231, 14, 9, 11, 0, 3, 10, 190, 210, 14, 10, 11, -1, 3, 10, 191, 41, 29, 7, 11, -1, 4, 7, 192, 141, 0, 10, 13, -1, 1, 9, 193, 130, 0, 10, 13, -1, 1, 9, 194, 119, 0, 10, 13, -1, 1, 9, 195, 20, 0, 10, 14, -1, 0, 9, 196, 67, 15, 10, 12, -1, 2, 9, 197, 108, 0, 10, 13, -1, 1, 9, 198, 0, 42, 12, 10, -1, 4, 11, 199, 228, 0, 8, 13, 0, 4, 8, 200, 245, 0, 7, 13, 0, 1, 7, 201, 237, 0, 7, 13, 0, 1, 7, 202, 0, 16, 7, 13, 0, 1, 7, 203, 130, 14, 7, 12, 0, 2, 7, 204, 36, 15, 6, 13, -2, 1, 4, 205, 22, 15, 6, 13, -1, 1, 4, 206, 29, 15, 6, 13, -1, 1, 4, 207, 154, 14, 7, 12, -2, 2, 4, 208, 78, 40, 9, 10, -1, 4, 9, 209, 59, 0, 8, 14, 0, 0, 10, 210, 172, 0, 9, 13, 0, 1, 10, 211, 152, 0, 9, 13, 0, 1, 10, 212, 182, 0, 9, 13, 0, 1, 10, 213, 31, 0, 9, 14, 0, 0, 10, 214, 78, 15, 9, 12, 0, 2, 10, 215, 121, 62, 7, 7, 0, 6, 7, 216, 8, 0, 11, 14, -1, 2, 10, 217, 192, 0, 8, 13, 0, 1, 9, 218, 210, 0, 8, 13, 0, 1, 9, 219, 201, 0, 8, 13, 0, 1, 9, 220, 88, 15, 8, 12, 0, 2, 9, 221, 162, 0, 9, 13, -1, 1, 7, 222, 81, 51, 7, 10, 0, 4, 8, 223, 49, 29, 7, 11, 0, 3, 8, 224, 57, 28, 7, 11, 0, 3, 7, 225, 65, 28, 7, 11, 0, 3, 7, 226, 73, 28, 7, 11, 0, 3, 7, 227, 138, 14, 7, 12, 0, 2, 7, 228, 25, 52, 7, 10, 0, 4, 7, 229, 146, 14, 7, 12, 0, 2, 7, 230, 192, 49, 11, 8, 0, 6, 12, 231, 207, 26, 6, 11, 0, 6, 6, 232, 97, 28, 7, 11, 0, 3, 8, 233, 105, 28, 7, 11, 0, 3, 8, 234, 113, 28, 7, 11, 0, 3, 8, 235, 73, 51, 7, 10, 0, 4, 8, 236, 214, 26, 5, 11, -2, 3, 3, 237, 250, 14, 5, 11, -1, 3, 3, 238, 193, 26, 6, 11, -2, 3, 3, 239, 142, 50, 6, 10, -2, 4, 3, 240, 185, 26, 7, 11, 0, 3, 8, 241, 106, 15, 7, 12, 0, 2, 8, 242, 129, 27, 7, 11, 0, 3, 8, 243, 137, 27, 7, 11, 0, 3, 8, 244, 145, 27, 7, 11, 0, 3, 8, 245, 114, 14, 7, 12, 0, 2, 8, 246, 49, 52, 7, 10, 0, 4, 8, 247, 237, 48, 8, 8, -1, 5, 7, 248, 201, 38, 8, 10, 0, 5, 8, 249, 161, 27, 7, 11, 0, 3, 8, 250, 169, 26, 7, 11, 0, 3, 8, 251, 177, 26, 7, 11, 0, 3, 8, 252, 89, 51, 7, 10, 0, 4, 8, 253, 41, 0, 8, 14, -1, 3, 7, 254, 68, 0, 7, 14, 0, 3, 8, 255, 219, 0, 8, 13, -1, 4, 7};
+static const int _bi_font_doc_font_height=18;
+static const int _bi_font_doc_font_ascent=14;
+static const int _bi_font_doc_font_charcount=193;
+static const int _bi_font_doc_font_characters[]={0, 253, 3, 2, 2, -1, 13, 0, 13, 253, 9, 2, 2, -1, 13, 0, 32, 253, 0, 2, 2, -1, 13, 3, 33, 220, 26, 3, 11, 1, 3, 5, 34, 187, 59, 5, 5, 0, 3, 6, 35, 88, 40, 9, 10, -1, 4, 7, 36, 50, 0, 8, 14, -1, 2, 7, 37, 175, 14, 11, 11, -1, 3, 11, 38, 187, 14, 11, 11, -1, 3, 10, 39, 198, 58, 3, 5, 0, 3, 3, 40, 98, 0, 4, 14, 0, 3, 5, 41, 103, 0, 4, 14, 0, 3, 5, 42, 146, 61, 7, 6, 0, 3, 7, 43, 246, 48, 8, 8, -1, 5, 7, 44, 193, 58, 4, 5, -1, 11, 4, 45, 13, 73, 5, 2, 0, 9, 5, 46, 241, 57, 3, 3, 0, 11, 4, 47, 84, 0, 7, 14, -1, 2, 6, 48, 246, 37, 8, 10, -1, 4, 7, 49, 33, 52, 7, 10, 0, 4, 7, 50, 237, 37, 8, 10, -1, 4, 7, 51, 219, 38, 8, 10, -1, 4, 7, 52, 128, 39, 9, 10, -1, 4, 7, 53, 41, 52, 7, 10, -1, 4, 7, 54, 9, 53, 7, 10, 0, 4, 7, 55, 228, 38, 8, 10, -1, 4, 7, 56, 57, 52, 7, 10, 0, 4, 7, 57, 65, 51, 7, 10, 0, 4, 7, 58, 98, 62, 4, 8, 0, 6, 4, 59, 162, 50, 5, 10, -1, 6, 4, 60, 174, 49, 8, 9, -1, 4, 7, 61, 179, 59, 7, 5, 0, 7, 7, 62, 228, 49, 8, 8, -1, 5, 7, 63, 89, 28, 7, 11, 0, 3, 7, 64, 54, 15, 12, 12, 0, 4, 13, 65, 36, 41, 10, 10, -1, 4, 9, 66, 97, 51, 7, 10, 0, 4, 8, 67, 174, 38, 8, 10, 0, 4, 8, 68, 156, 39, 8, 10, 0, 4, 9, 69, 105, 51, 7, 10, 0, 4, 7, 70, 121, 51, 6, 10, 0, 4, 7, 71, 0, 53, 8, 10, 0, 4, 9, 72, 192, 38, 8, 10, 0, 4, 9, 73, 251, 26, 3, 10, 0, 4, 4, 74, 156, 50, 5, 10, -1, 4, 5, 75, 147, 39, 8, 10, 0, 4, 8, 76, 135, 50, 6, 10, 0, 4, 6, 77, 13, 41, 11, 10, 0, 4, 12, 78, 210, 38, 8, 10, 0, 4, 10, 79, 68, 40, 9, 10, 0, 4, 10, 80, 113, 51, 7, 10, 0, 4, 8, 81, 199, 14, 10, 11, 0, 4, 10, 82, 183, 38, 8, 10, 0, 4, 8, 83, 128, 50, 6, 10, 0, 4, 7, 84, 108, 40, 9, 10, -1, 4, 7, 85, 165, 39, 8, 10, 0, 4, 9, 86, 25, 41, 10, 10, -1, 4, 9, 87, 236, 26, 14, 10, -1, 4, 13, 88, 98, 40, 9, 10, -1, 4, 8, 89, 118, 40, 9, 10, -1, 4, 7, 90, 138, 39, 8, 10, -1, 4, 7, 91, 49, 15, 4, 13, 0, 3, 5, 92, 76, 0, 7, 14, -1, 2, 6, 93, 43, 15, 5, 13, -1, 3, 5, 94, 137, 61, 8, 6, -1, 4, 7, 95, 245, 57, 9, 2, -1, 15, 7, 96, 230, 58, 5, 3, -1, 3, 4, 97, 57, 63, 7, 8, 0, 6, 7, 98, 81, 28, 7, 11, 0, 3, 8, 99, 79, 62, 6, 8, 0, 6, 6, 100, 33, 29, 7, 11, 0, 3, 8, 101, 9, 64, 7, 8, 0, 6, 8, 102, 200, 26, 6, 11, -1, 3, 5, 103, 153, 27, 7, 11, 0, 6, 7, 104, 121, 27, 7, 11, 0, 3, 8, 105, 224, 26, 3, 11, 0, 3, 4, 106, 92, 0, 5, 14, -2, 3, 4, 107, 25, 29, 7, 11, 0, 3, 7, 108, 228, 26, 3, 11, 0, 3, 4, 109, 204, 49, 11, 8, 0, 6, 12, 110, 17, 63, 7, 8, 0, 6, 8, 111, 33, 63, 7, 8, 0, 6, 8, 112, 17, 29, 7, 11, 0, 6, 8, 113, 9, 29, 7, 11, 0, 6, 8, 114, 86, 62, 5, 8, 0, 6, 5, 115, 92, 62, 5, 8, 0, 6, 6, 116, 168, 50, 5, 10, -1, 4, 5, 117, 49, 63, 7, 8, 0, 6, 8, 118, 0, 64, 8, 8, -1, 6, 7, 119, 216, 49, 11, 8, -1, 6, 10, 120, 41, 63, 7, 8, -1, 6, 7, 121, 0, 30, 8, 11, -1, 6, 7, 122, 72, 62, 6, 8, 0, 6, 6, 123, 8, 15, 6, 13, -1, 3, 5, 124, 0, 0, 3, 15, 1, 2, 7, 125, 15, 15, 6, 13, -1, 3, 5, 126, 202, 58, 8, 4, -1, 4, 7, 160, 253, 6, 2, 2, -1, 13, 3, 161, 232, 26, 3, 11, 0, 4, 5, 162, 149, 50, 6, 10, 0, 4, 7, 163, 17, 52, 7, 10, 0, 4, 7, 164, 183, 49, 8, 9, -1, 5, 7, 165, 47, 41, 10, 10, -2, 4, 7, 166, 4, 0, 3, 15, 2, 2, 7, 167, 122, 14, 7, 12, 0, 3, 7, 168, 0, 73, 6, 2, -1, 4, 6, 169, 162, 14, 12, 11, 0, 3, 13, 170, 65, 62, 6, 8, -1, 4, 6, 171, 112, 62, 8, 7, -1, 6, 8, 172, 211, 58, 7, 4, -1, 8, 7, 173, 19, 72, 5, 2, 0, 9, 5, 174, 103, 62, 8, 7, -1, 3, 8, 175, 7, 73, 5, 2, 0, 3, 6, 176, 171, 61, 7, 5, -1, 3, 5, 177, 58, 40, 9, 10, -1, 4, 7, 178, 154, 61, 5, 6, 0, 2, 5, 179, 160, 61, 5, 6, -1, 2, 5, 180, 224, 58, 5, 3, -1, 3, 4, 181, 241, 14, 8, 11, 0, 6, 8, 182, 97, 15, 8, 12, 0, 4, 9, 183, 236, 58, 4, 3, 0, 8, 4, 184, 219, 58, 4, 4, 0, 13, 5, 185, 166, 61, 4, 6, 0, 2, 4, 186, 25, 63, 7, 8, -1, 4, 6, 187, 129, 61, 7, 7, 0, 6, 8, 188, 221, 14, 9, 11, 0, 3, 10, 189, 231, 14, 9, 11, 0, 3, 10, 190, 210, 14, 10, 11, -1, 3, 10, 191, 41, 29, 7, 11, -1, 4, 7, 192, 141, 0, 10, 13, -1, 1, 9, 193, 130, 0, 10, 13, -1, 1, 9, 194, 119, 0, 10, 13, -1, 1, 9, 195, 20, 0, 10, 14, -1, 0, 9, 196, 67, 15, 10, 12, -1, 2, 9, 197, 108, 0, 10, 13, -1, 1, 9, 198, 0, 42, 12, 10, -1, 4, 11, 199, 228, 0, 8, 13, 0, 4, 8, 200, 245, 0, 7, 13, 0, 1, 7, 201, 237, 0, 7, 13, 0, 1, 7, 202, 0, 16, 7, 13, 0, 1, 7, 203, 130, 14, 7, 12, 0, 2, 7, 204, 36, 15, 6, 13, -2, 1, 4, 205, 22, 15, 6, 13, -1, 1, 4, 206, 29, 15, 6, 13, -1, 1, 4, 207, 154, 14, 7, 12, -2, 2, 4, 208, 78, 40, 9, 10, -1, 4, 9, 209, 59, 0, 8, 14, 0, 0, 10, 210, 172, 0, 9, 13, 0, 1, 10, 211, 152, 0, 9, 13, 0, 1, 10, 212, 182, 0, 9, 13, 0, 1, 10, 213, 31, 0, 9, 14, 0, 0, 10, 214, 78, 15, 9, 12, 0, 2, 10, 215, 121, 62, 7, 7, 0, 6, 7, 216, 8, 0, 11, 14, -1, 2, 10, 217, 192, 0, 8, 13, 0, 1, 9, 218, 210, 0, 8, 13, 0, 1, 9, 219, 201, 0, 8, 13, 0, 1, 9, 220, 88, 15, 8, 12, 0, 2, 9, 221, 162, 0, 9, 13, -1, 1, 7, 222, 81, 51, 7, 10, 0, 4, 8, 223, 49, 29, 7, 11, 0, 3, 8, 224, 57, 28, 7, 11, 0, 3, 7, 225, 65, 28, 7, 11, 0, 3, 7, 226, 73, 28, 7, 11, 0, 3, 7, 227, 138, 14, 7, 12, 0, 2, 7, 228, 25, 52, 7, 10, 0, 4, 7, 229, 146, 14, 7, 12, 0, 2, 7, 230, 192, 49, 11, 8, 0, 6, 12, 231, 207, 26, 6, 11, 0, 6, 6, 232, 97, 28, 7, 11, 0, 3, 8, 233, 105, 28, 7, 11, 0, 3, 8, 234, 113, 28, 7, 11, 0, 3, 8, 235, 73, 51, 7, 10, 0, 4, 8, 236, 214, 26, 5, 11, -2, 3, 3, 237, 250, 14, 5, 11, -1, 3, 3, 238, 193, 26, 6, 11, -2, 3, 3, 239, 142, 50, 6, 10, -2, 4, 3, 240, 185, 26, 7, 11, 0, 3, 8, 241, 106, 15, 7, 12, 0, 2, 8, 242, 129, 27, 7, 11, 0, 3, 8, 243, 137, 27, 7, 11, 0, 3, 8, 244, 145, 27, 7, 11, 0, 3, 8, 245, 114, 14, 7, 12, 0, 2, 8, 246, 49, 52, 7, 10, 0, 4, 8, 247, 237, 48, 8, 8, -1, 5, 7, 248, 201, 38, 8, 10, 0, 5, 8, 249, 161, 27, 7, 11, 0, 3, 8, 250, 169, 26, 7, 11, 0, 3, 8, 251, 177, 26, 7, 11, 0, 3, 8, 252, 89, 51, 7, 10, 0, 4, 8, 253, 41, 0, 8, 14, -1, 3, 7, 254, 68, 0, 7, 14, 0, 3, 8, 255, 219, 0, 8, 13, -1, 4, 7};
diff --git a/tools/editor/doc_title_font.h b/tools/editor/doc_title_font.h
index 22bad995f8..fb6b4eaf5b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,7 +26,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-static const int _bi_font_doc_title_font_height=22;
-static const int _bi_font_doc_title_font_ascent=17;
-static const int _bi_font_doc_title_font_charcount=193;
-static const int _bi_font_doc_title_font_characters[]={0, 108, 97, 2, 2, -1, 16, 0, 13, 111, 97, 2, 2, -1, 16, 0, 32, 252, 55, 2, 2, -1, 16, 4, 33, 84, 48, 3, 13, 1, 4, 6, 34, 9, 99, 6, 6, 0, 4, 8, 35, 52, 76, 9, 12, -1, 5, 9, 36, 31, 18, 9, 16, 0, 3, 9, 37, 28, 35, 13, 13, -1, 4, 13, 38, 56, 35, 12, 13, 0, 4, 13, 39, 16, 99, 3, 6, 0, 4, 4, 40, 48, 0, 5, 17, 0, 3, 6, 41, 54, 0, 5, 17, 0, 3, 6, 42, 207, 84, 9, 8, 0, 3, 9, 43, 121, 86, 9, 9, 0, 7, 9, 44, 251, 71, 4, 6, -1, 13, 5, 45, 102, 97, 5, 3, 0, 10, 6, 46, 66, 99, 4, 4, 0, 13, 5, 47, 24, 0, 9, 17, -2, 3, 8, 48, 11, 76, 10, 12, -1, 5, 9, 49, 102, 74, 9, 12, 0, 5, 9, 50, 48, 63, 10, 12, -1, 5, 9, 51, 59, 63, 10, 12, -1, 5, 9, 52, 70, 63, 10, 12, -1, 5, 9, 53, 81, 62, 10, 12, -1, 5, 9, 54, 235, 59, 10, 12, -1, 5, 9, 55, 103, 61, 10, 12, -1, 5, 9, 56, 114, 60, 10, 12, -1, 5, 9, 57, 125, 60, 10, 12, -1, 5, 9, 58, 252, 45, 3, 9, 0, 8, 5, 59, 246, 71, 4, 11, -1, 8, 5, 60, 148, 73, 8, 12, 0, 5, 9, 61, 0, 100, 8, 7, 0, 8, 9, 62, 139, 73, 8, 12, 0, 5, 9, 63, 40, 49, 8, 13, 0, 4, 8, 64, 184, 17, 15, 14, 0, 5, 16, 65, 178, 47, 12, 12, -1, 5, 11, 66, 136, 60, 10, 12, 0, 5, 10, 67, 240, 45, 11, 12, -1, 5, 10, 68, 0, 63, 11, 12, 0, 5, 11, 69, 130, 73, 8, 12, 0, 5, 9, 70, 112, 74, 8, 12, 0, 5, 8, 71, 191, 46, 12, 12, -1, 5, 11, 72, 24, 63, 11, 12, 0, 5, 11, 73, 193, 72, 4, 12, 0, 5, 5, 74, 173, 73, 6, 12, -1, 5, 6, 75, 147, 60, 10, 12, 0, 5, 10, 76, 121, 73, 8, 12, 0, 5, 8, 77, 122, 47, 15, 12, 0, 5, 16, 78, 12, 63, 11, 12, 0, 5, 12, 79, 138, 47, 13, 12, -1, 5, 12, 80, 62, 76, 9, 12, 0, 5, 10, 81, 200, 17, 14, 14, -1, 5, 12, 82, 158, 60, 10, 12, 0, 5, 10, 83, 32, 76, 9, 12, -1, 5, 9, 84, 169, 60, 10, 12, -1, 5, 9, 85, 204, 46, 11, 12, 0, 5, 12, 86, 165, 47, 12, 12, -1, 5, 11, 87, 88, 48, 17, 12, -1, 5, 16, 88, 216, 46, 11, 12, -1, 5, 10, 89, 228, 46, 11, 12, -1, 5, 9, 90, 180, 60, 10, 12, -1, 5, 9, 91, 249, 0, 5, 16, 0, 4, 6, 92, 13, 0, 10, 17, -2, 3, 8, 93, 85, 17, 5, 16, 0, 4, 6, 94, 196, 85, 10, 8, -1, 5, 9, 95, 71, 99, 10, 3, -1, 17, 9, 96, 46, 99, 6, 4, -1, 4, 5, 97, 111, 87, 9, 9, -1, 8, 9, 98, 207, 32, 9, 13, 0, 4, 10, 99, 161, 86, 8, 9, -1, 8, 8, 100, 69, 34, 10, 13, -1, 4, 10, 101, 89, 88, 10, 9, -1, 8, 9, 102, 58, 49, 7, 13, -1, 4, 6, 103, 191, 59, 10, 12, -1, 8, 9, 104, 177, 33, 9, 13, 0, 4, 10, 105, 187, 73, 5, 12, -1, 5, 4, 106, 177, 17, 6, 15, -2, 5, 5, 107, 217, 32, 9, 13, 0, 4, 9, 108, 250, 17, 4, 13, 0, 4, 4, 109, 24, 89, 14, 9, 0, 8, 15, 110, 151, 86, 9, 9, 0, 8, 10, 111, 100, 87, 10, 9, -1, 8, 10, 112, 42, 76, 9, 12, 0, 8, 10, 113, 213, 59, 10, 12, -1, 8, 10, 114, 188, 86, 7, 9, 0, 8, 6, 115, 170, 86, 8, 9, -1, 8, 7, 116, 230, 72, 7, 11, -1, 6, 6, 117, 141, 86, 9, 9, 0, 8, 10, 118, 78, 89, 10, 9, -1, 8, 9, 119, 8, 89, 15, 9, -1, 8, 13, 120, 131, 86, 9, 9, -1, 8, 8, 121, 224, 59, 10, 12, -1, 8, 9, 122, 179, 86, 8, 9, -1, 8, 7, 123, 34, 0, 6, 17, -1, 3, 6, 124, 64, 0, 3, 17, 2, 3, 9, 125, 41, 0, 6, 17, 0, 3, 6, 126, 30, 99, 9, 5, 0, 5, 9, 160, 114, 97, 2, 2, -1, 16, 4, 161, 80, 48, 3, 13, 1, 6, 6, 162, 165, 73, 7, 12, 0, 5, 9, 163, 92, 74, 9, 12, 0, 5, 9, 164, 209, 72, 10, 11, -1, 6, 9, 165, 36, 63, 11, 12, -2, 5, 9, 166, 60, 0, 3, 17, 2, 3, 9, 167, 151, 17, 8, 15, 0, 4, 9, 168, 82, 99, 6, 3, 0, 5, 7, 169, 236, 17, 13, 13, 0, 4, 15, 170, 238, 72, 7, 11, 0, 5, 7, 171, 54, 89, 11, 9, -1, 7, 10, 172, 20, 99, 9, 5, -1, 10, 9, 173, 96, 98, 5, 3, 0, 10, 6, 174, 226, 84, 8, 8, 0, 4, 9, 175, 89, 98, 6, 3, 0, 4, 7, 176, 40, 99, 5, 5, 0, 4, 6, 177, 22, 76, 9, 12, 0, 5, 9, 178, 235, 84, 6, 8, 0, 3, 6, 179, 242, 84, 6, 8, 0, 3, 6, 180, 53, 99, 6, 4, -1, 4, 5, 181, 0, 76, 10, 12, 0, 8, 10, 182, 215, 17, 10, 14, 0, 5, 11, 183, 251, 78, 3, 4, 0, 9, 5, 184, 60, 99, 5, 4, 0, 16, 5, 185, 249, 83, 5, 8, -1, 3, 5, 186, 0, 89, 7, 10, 0, 5, 8, 187, 66, 89, 11, 9, -1, 7, 10, 188, 42, 35, 13, 13, -1, 4, 12, 189, 0, 35, 13, 13, -1, 4, 12, 190, 14, 35, 13, 13, -1, 4, 13, 191, 49, 49, 8, 13, -1, 6, 8, 192, 150, 0, 12, 16, -1, 1, 11, 193, 176, 0, 12, 16, -1, 1, 11, 194, 163, 0, 12, 16, -1, 1, 11, 195, 124, 0, 12, 16, -1, 1, 11, 196, 105, 17, 12, 15, -1, 2, 11, 197, 0, 0, 12, 17, -1, 0, 11, 198, 106, 47, 15, 12, -1, 5, 14, 199, 141, 17, 9, 15, 0, 5, 10, 200, 60, 18, 8, 16, 0, 1, 9, 201, 41, 18, 9, 16, 0, 1, 9, 202, 21, 18, 9, 16, 0, 1, 9, 203, 160, 17, 8, 15, 0, 2, 9, 204, 69, 17, 7, 16, -2, 1, 5, 205, 77, 17, 7, 16, -1, 1, 5, 206, 51, 18, 8, 16, -2, 1, 5, 207, 169, 17, 7, 15, -2, 2, 5, 208, 152, 47, 12, 12, -1, 5, 12, 209, 237, 0, 11, 16, 0, 1, 12, 210, 82, 0, 13, 16, -1, 1, 12, 211, 68, 0, 13, 16, -1, 1, 12, 212, 110, 0, 13, 16, -1, 1, 12, 213, 96, 0, 13, 16, -1, 1, 12, 214, 91, 17, 13, 15, -1, 2, 12, 215, 217, 84, 8, 8, 0, 8, 9, 216, 137, 0, 12, 16, 0, 3, 12, 217, 225, 0, 11, 16, 0, 1, 12, 218, 189, 0, 11, 16, 0, 1, 12, 219, 213, 0, 11, 16, 0, 1, 12, 220, 118, 17, 11, 15, 0, 2, 12, 221, 201, 0, 11, 16, -1, 1, 9, 222, 72, 76, 9, 12, 0, 5, 10, 223, 167, 33, 9, 13, 0, 4, 10, 224, 157, 33, 9, 13, -1, 4, 9, 225, 30, 49, 9, 13, -1, 4, 9, 226, 227, 32, 9, 13, -1, 4, 9, 227, 237, 31, 9, 13, -1, 4, 9, 228, 82, 75, 9, 12, -1, 5, 9, 229, 226, 17, 9, 14, -1, 3, 9, 230, 39, 89, 14, 9, 0, 8, 14, 231, 157, 73, 7, 12, 0, 8, 8, 232, 146, 33, 10, 13, -1, 4, 9, 233, 80, 34, 10, 13, -1, 4, 9, 234, 91, 33, 10, 13, -1, 4, 9, 235, 92, 61, 10, 12, -1, 5, 9, 236, 66, 49, 6, 13, -2, 4, 4, 237, 73, 48, 6, 13, -1, 4, 4, 238, 247, 31, 8, 13, -2, 4, 4, 239, 180, 73, 6, 12, -1, 5, 4, 240, 187, 32, 9, 13, 0, 4, 10, 241, 197, 32, 9, 13, 0, 4, 10, 242, 102, 33, 10, 13, -1, 4, 10, 243, 113, 33, 10, 13, -1, 4, 10, 244, 124, 33, 10, 13, -1, 4, 10, 245, 135, 33, 10, 13, -1, 4, 10, 246, 202, 59, 10, 12, -1, 5, 10, 247, 220, 72, 9, 11, -1, 6, 9, 248, 198, 72, 10, 11, 0, 7, 10, 249, 0, 49, 9, 13, 0, 4, 10, 250, 10, 49, 9, 13, 0, 4, 10, 251, 20, 49, 9, 13, 0, 4, 10, 252, 246, 58, 9, 12, 0, 5, 10, 253, 0, 18, 10, 16, -1, 4, 9, 254, 11, 18, 9, 16, 0, 4, 10, 255, 130, 17, 10, 15, -1, 5, 9};
+static const int _bi_font_doc_title_font_height=22;
+static const int _bi_font_doc_title_font_ascent=17;
+static const int _bi_font_doc_title_font_charcount=193;
+static const int _bi_font_doc_title_font_characters[]={0, 108, 97, 2, 2, -1, 16, 0, 13, 111, 97, 2, 2, -1, 16, 0, 32, 252, 55, 2, 2, -1, 16, 4, 33, 84, 48, 3, 13, 1, 4, 6, 34, 9, 99, 6, 6, 0, 4, 8, 35, 52, 76, 9, 12, -1, 5, 9, 36, 31, 18, 9, 16, 0, 3, 9, 37, 28, 35, 13, 13, -1, 4, 13, 38, 56, 35, 12, 13, 0, 4, 13, 39, 16, 99, 3, 6, 0, 4, 4, 40, 48, 0, 5, 17, 0, 3, 6, 41, 54, 0, 5, 17, 0, 3, 6, 42, 207, 84, 9, 8, 0, 3, 9, 43, 121, 86, 9, 9, 0, 7, 9, 44, 251, 71, 4, 6, -1, 13, 5, 45, 102, 97, 5, 3, 0, 10, 6, 46, 66, 99, 4, 4, 0, 13, 5, 47, 24, 0, 9, 17, -2, 3, 8, 48, 11, 76, 10, 12, -1, 5, 9, 49, 102, 74, 9, 12, 0, 5, 9, 50, 48, 63, 10, 12, -1, 5, 9, 51, 59, 63, 10, 12, -1, 5, 9, 52, 70, 63, 10, 12, -1, 5, 9, 53, 81, 62, 10, 12, -1, 5, 9, 54, 235, 59, 10, 12, -1, 5, 9, 55, 103, 61, 10, 12, -1, 5, 9, 56, 114, 60, 10, 12, -1, 5, 9, 57, 125, 60, 10, 12, -1, 5, 9, 58, 252, 45, 3, 9, 0, 8, 5, 59, 246, 71, 4, 11, -1, 8, 5, 60, 148, 73, 8, 12, 0, 5, 9, 61, 0, 100, 8, 7, 0, 8, 9, 62, 139, 73, 8, 12, 0, 5, 9, 63, 40, 49, 8, 13, 0, 4, 8, 64, 184, 17, 15, 14, 0, 5, 16, 65, 178, 47, 12, 12, -1, 5, 11, 66, 136, 60, 10, 12, 0, 5, 10, 67, 240, 45, 11, 12, -1, 5, 10, 68, 0, 63, 11, 12, 0, 5, 11, 69, 130, 73, 8, 12, 0, 5, 9, 70, 112, 74, 8, 12, 0, 5, 8, 71, 191, 46, 12, 12, -1, 5, 11, 72, 24, 63, 11, 12, 0, 5, 11, 73, 193, 72, 4, 12, 0, 5, 5, 74, 173, 73, 6, 12, -1, 5, 6, 75, 147, 60, 10, 12, 0, 5, 10, 76, 121, 73, 8, 12, 0, 5, 8, 77, 122, 47, 15, 12, 0, 5, 16, 78, 12, 63, 11, 12, 0, 5, 12, 79, 138, 47, 13, 12, -1, 5, 12, 80, 62, 76, 9, 12, 0, 5, 10, 81, 200, 17, 14, 14, -1, 5, 12, 82, 158, 60, 10, 12, 0, 5, 10, 83, 32, 76, 9, 12, -1, 5, 9, 84, 169, 60, 10, 12, -1, 5, 9, 85, 204, 46, 11, 12, 0, 5, 12, 86, 165, 47, 12, 12, -1, 5, 11, 87, 88, 48, 17, 12, -1, 5, 16, 88, 216, 46, 11, 12, -1, 5, 10, 89, 228, 46, 11, 12, -1, 5, 9, 90, 180, 60, 10, 12, -1, 5, 9, 91, 249, 0, 5, 16, 0, 4, 6, 92, 13, 0, 10, 17, -2, 3, 8, 93, 85, 17, 5, 16, 0, 4, 6, 94, 196, 85, 10, 8, -1, 5, 9, 95, 71, 99, 10, 3, -1, 17, 9, 96, 46, 99, 6, 4, -1, 4, 5, 97, 111, 87, 9, 9, -1, 8, 9, 98, 207, 32, 9, 13, 0, 4, 10, 99, 161, 86, 8, 9, -1, 8, 8, 100, 69, 34, 10, 13, -1, 4, 10, 101, 89, 88, 10, 9, -1, 8, 9, 102, 58, 49, 7, 13, -1, 4, 6, 103, 191, 59, 10, 12, -1, 8, 9, 104, 177, 33, 9, 13, 0, 4, 10, 105, 187, 73, 5, 12, -1, 5, 4, 106, 177, 17, 6, 15, -2, 5, 5, 107, 217, 32, 9, 13, 0, 4, 9, 108, 250, 17, 4, 13, 0, 4, 4, 109, 24, 89, 14, 9, 0, 8, 15, 110, 151, 86, 9, 9, 0, 8, 10, 111, 100, 87, 10, 9, -1, 8, 10, 112, 42, 76, 9, 12, 0, 8, 10, 113, 213, 59, 10, 12, -1, 8, 10, 114, 188, 86, 7, 9, 0, 8, 6, 115, 170, 86, 8, 9, -1, 8, 7, 116, 230, 72, 7, 11, -1, 6, 6, 117, 141, 86, 9, 9, 0, 8, 10, 118, 78, 89, 10, 9, -1, 8, 9, 119, 8, 89, 15, 9, -1, 8, 13, 120, 131, 86, 9, 9, -1, 8, 8, 121, 224, 59, 10, 12, -1, 8, 9, 122, 179, 86, 8, 9, -1, 8, 7, 123, 34, 0, 6, 17, -1, 3, 6, 124, 64, 0, 3, 17, 2, 3, 9, 125, 41, 0, 6, 17, 0, 3, 6, 126, 30, 99, 9, 5, 0, 5, 9, 160, 114, 97, 2, 2, -1, 16, 4, 161, 80, 48, 3, 13, 1, 6, 6, 162, 165, 73, 7, 12, 0, 5, 9, 163, 92, 74, 9, 12, 0, 5, 9, 164, 209, 72, 10, 11, -1, 6, 9, 165, 36, 63, 11, 12, -2, 5, 9, 166, 60, 0, 3, 17, 2, 3, 9, 167, 151, 17, 8, 15, 0, 4, 9, 168, 82, 99, 6, 3, 0, 5, 7, 169, 236, 17, 13, 13, 0, 4, 15, 170, 238, 72, 7, 11, 0, 5, 7, 171, 54, 89, 11, 9, -1, 7, 10, 172, 20, 99, 9, 5, -1, 10, 9, 173, 96, 98, 5, 3, 0, 10, 6, 174, 226, 84, 8, 8, 0, 4, 9, 175, 89, 98, 6, 3, 0, 4, 7, 176, 40, 99, 5, 5, 0, 4, 6, 177, 22, 76, 9, 12, 0, 5, 9, 178, 235, 84, 6, 8, 0, 3, 6, 179, 242, 84, 6, 8, 0, 3, 6, 180, 53, 99, 6, 4, -1, 4, 5, 181, 0, 76, 10, 12, 0, 8, 10, 182, 215, 17, 10, 14, 0, 5, 11, 183, 251, 78, 3, 4, 0, 9, 5, 184, 60, 99, 5, 4, 0, 16, 5, 185, 249, 83, 5, 8, -1, 3, 5, 186, 0, 89, 7, 10, 0, 5, 8, 187, 66, 89, 11, 9, -1, 7, 10, 188, 42, 35, 13, 13, -1, 4, 12, 189, 0, 35, 13, 13, -1, 4, 12, 190, 14, 35, 13, 13, -1, 4, 13, 191, 49, 49, 8, 13, -1, 6, 8, 192, 150, 0, 12, 16, -1, 1, 11, 193, 176, 0, 12, 16, -1, 1, 11, 194, 163, 0, 12, 16, -1, 1, 11, 195, 124, 0, 12, 16, -1, 1, 11, 196, 105, 17, 12, 15, -1, 2, 11, 197, 0, 0, 12, 17, -1, 0, 11, 198, 106, 47, 15, 12, -1, 5, 14, 199, 141, 17, 9, 15, 0, 5, 10, 200, 60, 18, 8, 16, 0, 1, 9, 201, 41, 18, 9, 16, 0, 1, 9, 202, 21, 18, 9, 16, 0, 1, 9, 203, 160, 17, 8, 15, 0, 2, 9, 204, 69, 17, 7, 16, -2, 1, 5, 205, 77, 17, 7, 16, -1, 1, 5, 206, 51, 18, 8, 16, -2, 1, 5, 207, 169, 17, 7, 15, -2, 2, 5, 208, 152, 47, 12, 12, -1, 5, 12, 209, 237, 0, 11, 16, 0, 1, 12, 210, 82, 0, 13, 16, -1, 1, 12, 211, 68, 0, 13, 16, -1, 1, 12, 212, 110, 0, 13, 16, -1, 1, 12, 213, 96, 0, 13, 16, -1, 1, 12, 214, 91, 17, 13, 15, -1, 2, 12, 215, 217, 84, 8, 8, 0, 8, 9, 216, 137, 0, 12, 16, 0, 3, 12, 217, 225, 0, 11, 16, 0, 1, 12, 218, 189, 0, 11, 16, 0, 1, 12, 219, 213, 0, 11, 16, 0, 1, 12, 220, 118, 17, 11, 15, 0, 2, 12, 221, 201, 0, 11, 16, -1, 1, 9, 222, 72, 76, 9, 12, 0, 5, 10, 223, 167, 33, 9, 13, 0, 4, 10, 224, 157, 33, 9, 13, -1, 4, 9, 225, 30, 49, 9, 13, -1, 4, 9, 226, 227, 32, 9, 13, -1, 4, 9, 227, 237, 31, 9, 13, -1, 4, 9, 228, 82, 75, 9, 12, -1, 5, 9, 229, 226, 17, 9, 14, -1, 3, 9, 230, 39, 89, 14, 9, 0, 8, 14, 231, 157, 73, 7, 12, 0, 8, 8, 232, 146, 33, 10, 13, -1, 4, 9, 233, 80, 34, 10, 13, -1, 4, 9, 234, 91, 33, 10, 13, -1, 4, 9, 235, 92, 61, 10, 12, -1, 5, 9, 236, 66, 49, 6, 13, -2, 4, 4, 237, 73, 48, 6, 13, -1, 4, 4, 238, 247, 31, 8, 13, -2, 4, 4, 239, 180, 73, 6, 12, -1, 5, 4, 240, 187, 32, 9, 13, 0, 4, 10, 241, 197, 32, 9, 13, 0, 4, 10, 242, 102, 33, 10, 13, -1, 4, 10, 243, 113, 33, 10, 13, -1, 4, 10, 244, 124, 33, 10, 13, -1, 4, 10, 245, 135, 33, 10, 13, -1, 4, 10, 246, 202, 59, 10, 12, -1, 5, 10, 247, 220, 72, 9, 11, -1, 6, 9, 248, 198, 72, 10, 11, 0, 7, 10, 249, 0, 49, 9, 13, 0, 4, 10, 250, 10, 49, 9, 13, 0, 4, 10, 251, 20, 49, 9, 13, 0, 4, 10, 252, 246, 58, 9, 12, 0, 5, 10, 253, 0, 18, 10, 16, -1, 4, 9, 254, 11, 18, 9, 16, 0, 4, 10, 255, 130, 17, 10, 15, -1, 5, 9};
diff --git a/tools/editor/editor_data.cpp b/tools/editor/editor_data.cpp
index bb4262e4b0..a6aedf2706 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,7 +39,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 +70,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 +123,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 +338,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++) {
@@ -424,9 +453,225 @@ void EditorData::remove_custom_type(const String& p_type){
}
+int EditorData::add_edited_scene(int p_at_pos) {
+
+ if (p_at_pos<0)
+ p_at_pos=edited_scene.size();
+ EditedScene es;
+ 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);
+ else
+ edited_scene.insert(p_at_pos,es);
+
+ if (current_edited_scene<0)
+ current_edited_scene=0;
+ return p_at_pos;
+}
+
+void EditorData::move_edited_scene_index(int p_idx,int p_to_idx){
+
+ ERR_FAIL_INDEX(p_idx,edited_scene.size());
+ ERR_FAIL_INDEX(p_to_idx,edited_scene.size());
+ SWAP(edited_scene[p_idx],edited_scene[p_to_idx]);
+}
+void EditorData::remove_scene(int p_idx){
+ ERR_FAIL_INDEX(p_idx,edited_scene.size());
+ if (edited_scene[p_idx].root)
+ memdelete(edited_scene[p_idx].root);
+
+ if (current_edited_scene>p_idx)
+ current_edited_scene--;
+ else if (current_edited_scene==p_idx && current_edited_scene>0) {
+ current_edited_scene--;
+ }
+
+ edited_scene.remove(p_idx);
+
+}
+int EditorData::get_edited_scene() const {
+
+ return current_edited_scene;
+}
+void EditorData::set_edited_scene(int p_idx){
+
+ ERR_FAIL_INDEX(p_idx,edited_scene.size());
+ current_edited_scene=p_idx;
+ //swap
+}
+Node* EditorData::get_edited_scene_root(){
+
+ ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),NULL);
+
+ return edited_scene[current_edited_scene].root;
+}
+void EditorData::set_edited_scene_root(Node* p_root) {
+
+ ERR_FAIL_INDEX(current_edited_scene,edited_scene.size());
+ edited_scene[current_edited_scene].root=p_root;
+}
+
+int EditorData::get_edited_scene_count() const {
+
+ return edited_scene.size();
+}
+
+void EditorData::set_edited_scene_version(uint64_t version) {
+ ERR_FAIL_INDEX(current_edited_scene,edited_scene.size());
+ edited_scene[current_edited_scene].version=version;
+
+}
+
+uint64_t EditorData::get_edited_scene_version() const{
+
+ ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),0);
+ return edited_scene[current_edited_scene].version;
+
+}
+uint64_t EditorData::get_scene_version(int p_idx) const{
+ ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),false);
+ 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)
+ return "[empty]";
+ if (edited_scene[p_idx].root->get_filename()=="")
+ return "[unsaved]";
+ return edited_scene[p_idx].root->get_filename().get_file();
+}
+
+
+String EditorData::get_scene_path(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_filename();
+
+}
+
+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());
+
+ EditedScene &es=edited_scene[current_edited_scene];
+ es.selection = p_selection->get_selected_node_list();
+ es.history_current=p_history->current;
+ es.history_stored=p_history->history;
+ es.editor_states=get_editor_states();
+ es.custom_state=p_custom;
+
+}
+
+Dictionary EditorData::restore_edited_scene_state(EditorSelection *p_selection, EditorHistory *p_history) {
+ ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),Dictionary());
+
+ EditedScene &es=edited_scene[current_edited_scene];
+
+ p_history->current=es.history_current;
+ p_history->history=es.history_stored;
+
+
+ p_selection->clear();
+ for(List<Node*>::Element *E=es.selection.front();E;E=E->next()) {
+ p_selection->add_node(E->get());
+ }
+ set_editor_states(es.editor_states);
+
+ return es.custom_state;
+}
+
+
+void EditorData::set_edited_scene_import_metadata(Ref<ResourceImportMetadata> p_mdata) {
+
+ ERR_FAIL_INDEX(current_edited_scene,edited_scene.size());
+ edited_scene[current_edited_scene].medatata=p_mdata;
+
+}
+
+Ref<ResourceImportMetadata> EditorData::get_edited_scene_import_metadata() const{
+
+ ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),Ref<ResourceImportMetadata>());
+ return edited_scene[current_edited_scene].medatata;
+}
+
+void EditorData::clear_edited_scenes() {
+
+ for(int i=0;i<edited_scene.size();i++) {
+ if (edited_scene[i].root) {
+ memdelete( edited_scene[i].root );
+ }
+ }
+ edited_scene.clear();
+}
+
+
+
+void EditorData::set_plugin_window_layout(Ref<ConfigFile> p_layout) {
+ for(int i=0;i<editor_plugins.size();i++) {
+ editor_plugins[i]->set_window_layout(p_layout);
+ }
+}
+
+void EditorData::get_plugin_window_layout(Ref<ConfigFile> p_layout) {
+ for(int i=0;i<editor_plugins.size();i++) {
+ editor_plugins[i]->get_window_layout(p_layout);
+ }
+}
EditorData::EditorData() {
+ current_edited_scene=-1;
+
// load_imported_scenes_from_globals();
}
@@ -462,7 +707,7 @@ void EditorSelection::add_node(Node *p_node) {
}
selection[p_node]=meta;
- p_node->connect("exit_scene",this,"_node_removed",varray(p_node),CONNECT_ONESHOT);
+ p_node->connect("exit_tree",this,"_node_removed",varray(p_node),CONNECT_ONESHOT);
//emit_signal("selection_changed");
}
@@ -478,7 +723,7 @@ void EditorSelection::remove_node(Node *p_node) {
if (meta)
memdelete(meta);
selection.erase(p_node);
- p_node->disconnect("exit_scene",this,"_node_removed");
+ p_node->disconnect("exit_tree",this,"_node_removed");
//emit_signal("selection_changed");
}
bool EditorSelection::is_selected(Node * p_node) const {
diff --git a/tools/editor/editor_data.h b/tools/editor/editor_data.h
index 50faba88ee..a90a071c39 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -45,7 +45,7 @@ class EditorHistory {
struct Obj {
- RES res;
+ REF ref;
ObjectID object;
String property;
};
@@ -55,6 +55,7 @@ class EditorHistory {
Vector<Obj> path;
int level;
};
+friend class EditorData;
Vector<History> history;
int current;
@@ -74,10 +75,17 @@ class EditorHistory {
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();
@@ -91,6 +99,8 @@ public:
EditorHistory();
};
+class EditorSelection;
+
class EditorData {
public:
@@ -117,6 +127,22 @@ private:
void _cleanup_history();
+ struct EditedScene {
+ Node* root;
+ Dictionary editor_states;
+ Ref<ResourceImportMetadata> medatata;
+ List<Node*> selection;
+ Vector<EditorHistory::History> history_stored;
+ int history_current;
+ Dictionary custom_state;
+ uint64_t version;
+ NodePath live_edit_root;
+
+
+ };
+
+ Vector<EditedScene> edited_scene;
+ int current_edited_scene;
public:
@@ -146,6 +172,37 @@ public:
void remove_custom_type(const String& p_type);
const Map<String,Vector<CustomType> >& get_custom_types() const { return custom_types; }
+
+ int add_edited_scene(int p_at_pos);
+ void move_edited_scene_index(int p_idx,int p_to_idx);
+ void remove_scene(int p_idx);
+ void set_edited_scene(int p_idx);
+ void set_edited_scene_root(Node* p_root);
+ void set_edited_scene_import_metadata(Ref<ResourceImportMetadata> p_mdata);
+ Ref<ResourceImportMetadata> get_edited_scene_import_metadata() const;
+ int get_edited_scene() const;
+ Node* get_edited_scene_root();
+ 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();
+
+
+ void set_plugin_window_layout(Ref<ConfigFile> p_layout);
+ void get_plugin_window_layout(Ref<ConfigFile> p_layout);
+
+ 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 790c3c8cd5..a8421acff8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,6 +28,9 @@
/*************************************************************************/
#include "editor_dir_dialog.h"
#include "os/os.h"
+#include "os/keyboard.h"
+#include "tools/editor/editor_settings.h"
+
void EditorDirDialog::_update_dir(TreeItem* p_item) {
@@ -39,17 +42,33 @@ void EditorDirDialog::_update_dir(TreeItem* p_item) {
da->change_dir(cdir);
da->list_dir_begin();
String p=da->get_next();
+
+ List<String> dirs;
+ bool ishidden;
+ bool show_hidden = EditorSettings::get_singleton()->get("file_dialog/show_hidden_files");
+
while(p!="") {
- if (da->current_is_dir() && !p.begins_with(".")) {
- TreeItem *ti = tree->create_item(p_item);
- ti->set_text(0,p);
- ti->set_icon(0,get_icon("Folder","EditorIcons"));
- ti->set_collapsed(true);
- }
+ ishidden = da->current_is_hidden();
+
+ if (show_hidden || !ishidden) {
+ if (da->current_is_dir() && !p.begins_with(".")) {
+ dirs.push_back(p);
+ }
+ }
p=da->get_next();
}
+ dirs.sort();
+
+ for(List<String>::Element *E=dirs.front();E;E=E->next()) {
+ TreeItem *ti = tree->create_item(p_item);
+ ti->set_text(0,E->get());
+ ti->set_icon(0,get_icon("Folder","EditorIcons"));
+ ti->set_collapsed(true);
+
+ }
+
memdelete(da);
updating=false;
@@ -69,7 +88,7 @@ void EditorDirDialog::reload() {
void EditorDirDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
reload();
tree->connect("item_collapsed",this,"_item_collapsed",varray(),CONNECT_DEFERRED);
}
diff --git a/tools/editor/editor_dir_dialog.h b/tools/editor/editor_dir_dialog.h
index 060fb724ce..8ac83b86e8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/editor_file_dialog.cpp b/tools/editor/editor_file_dialog.cpp
new file mode 100644
index 0000000000..7365cf9069
--- /dev/null
+++ b/tools/editor/editor_file_dialog.cpp
@@ -0,0 +1,1378 @@
+#include "editor_file_dialog.h"
+#include "scene/gui/label.h"
+#include "scene/gui/center_container.h"
+#include "print_string.h"
+#include "os/keyboard.h"
+#include "editor_resource_preview.h"
+#include "editor_settings.h"
+#include "scene/gui/margin_container.h"
+EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func=NULL;
+EditorFileDialog::GetIconFunc EditorFileDialog::get_large_icon_func=NULL;
+
+EditorFileDialog::RegisterFunc EditorFileDialog::register_func=NULL;
+EditorFileDialog::RegisterFunc EditorFileDialog::unregister_func=NULL;
+
+
+VBoxContainer *EditorFileDialog::get_vbox() {
+ return vbox;
+
+}
+
+void EditorFileDialog::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ mode_thumbnails->set_icon(get_icon("FileThumbnail","EditorIcons"));
+ mode_list->set_icon(get_icon("FileList","EditorIcons"));
+ 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"));
+
+ } else if (p_what==NOTIFICATION_PROCESS) {
+
+ if (preview_waiting) {
+ preview_wheel_timeout-=get_process_delta_time();
+ if (preview_wheel_timeout<=0) {
+ preview_wheel_index++;
+ if (preview_wheel_index>=8)
+ preview_wheel_index=0;
+ Ref<Texture> frame = get_icon("WaitPreview"+itos(preview_wheel_index+1),"EditorIcons");
+ preview->set_texture(frame);
+ preview_wheel_timeout=0.1;
+ }
+ }
+ } 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==EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
+
+ bool show_hidden = EditorSettings::get_singleton()->get("file_dialog/show_hidden_files");
+
+ if (show_hidden != show_hidden_files) {
+ set_show_hidden_files(show_hidden);
+ }
+ }
+}
+
+void EditorFileDialog::set_enable_multiple_selection(bool p_enable) {
+
+ item_list->set_select_mode(p_enable?ItemList::SELECT_MULTI:ItemList::SELECT_SINGLE);
+
+};
+
+Vector<String> EditorFileDialog::get_selected_files() const {
+
+ Vector<String> list;
+ for(int i=0;i<item_list->get_item_count();i++) {
+ if (item_list->is_selected(i))
+ list.push_back(item_list->get_item_text(i));
+ }
+ return list;
+
+};
+
+void EditorFileDialog::update_dir() {
+
+ dir->set_text(dir_access->get_current_dir());
+}
+
+void EditorFileDialog::_dir_entered(String p_dir) {
+
+
+ dir_access->change_dir(p_dir);
+ file->set_text("");
+ invalidate();
+ update_dir();
+ _push_history();
+
+
+}
+
+void EditorFileDialog::_file_entered(const String& p_file) {
+
+ _action_pressed();
+}
+
+void EditorFileDialog::_save_confirm_pressed() {
+ String f=dir_access->get_current_dir().plus_file(file->get_text());
+ _save_to_recent();
+ emit_signal("file_selected",f);
+ hide();
+}
+
+void EditorFileDialog::_post_popup() {
+
+ ConfirmationDialog::_post_popup();
+ if (invalidated) {
+ update_file_list();
+ invalidated=false;
+ }
+ if (mode==MODE_SAVE_FILE)
+ file->grab_focus();
+ else
+ item_list->grab_focus();
+
+ if (is_visible() && get_current_file()!="")
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+
+ if (is_visible()) {
+ Ref<Texture> folder = get_icon("folder","FileDialog");
+ recent->clear();
+
+
+ bool res = access==ACCESS_RESOURCES;
+ Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
+ for(int i=0;i<recentd.size();i++) {
+ bool cres = recentd[i].begins_with("res://");
+ if (cres!=res)
+ continue;
+ String name = recentd[i];
+ if (res && name=="res://") {
+ name="/";
+ } else {
+ name=name.get_file()+"/";
+ }
+
+ //print_line("file: "+name);
+ recent->add_item(name,folder);
+ recent->set_item_metadata( recent->get_item_count()-1,recentd[i]);
+ }
+
+ local_history.clear();
+ local_history_pos=-1;
+ _push_history();
+
+ _update_favorites();
+ }
+
+}
+
+void EditorFileDialog::_thumbnail_result(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) {
+
+ if (display_mode==DISPLAY_LIST || p_preview.is_null())
+ return;
+
+ for(int i=0;i<item_list->get_item_count();i++) {
+ Dictionary d = item_list->get_item_metadata(i);
+ String pname = d["path"];
+ if (pname==p_path) {
+ item_list->set_item_icon(i,p_preview);
+ item_list->set_item_tag_icon(i,Ref<Texture>());
+ }
+ }
+}
+
+void EditorFileDialog::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) {
+
+ set_process(false);
+ preview_waiting=false;
+
+ if (p_preview.is_valid() && get_current_path()==p_path) {
+
+
+ preview->set_texture(p_preview);
+ if (display_mode==DISPLAY_THUMBNAILS) {
+ preview_vb->hide();
+ } else {
+ preview_vb->show();
+ }
+
+ } else {
+ preview_vb->hide();
+ preview->set_texture(Ref<Texture>());
+
+ }
+
+}
+
+void EditorFileDialog::_request_single_thumbnail(const String& p_path) {
+
+ EditorResourcePreview::get_singleton()->queue_resource_preview(p_path,this,"_thumbnail_done",p_path);
+ //print_line("want file "+p_path);
+ set_process(true);
+ preview_waiting=true;
+ preview_wheel_timeout=0;
+
+}
+
+void EditorFileDialog::_action_pressed() {
+
+ if (mode==MODE_OPEN_FILES) {
+
+
+ String fbase=dir_access->get_current_dir();
+
+ DVector<String> files;
+ for(int i=0;i<item_list->get_item_count();i++) {
+ if (item_list->is_selected(i))
+ files.push_back( fbase.plus_file(item_list->get_item_text(i) ));
+ }
+
+ if (files.size()) {
+ _save_to_recent();
+ emit_signal("files_selected",files);
+ hide();
+ }
+
+ return;
+ }
+
+ String f=dir_access->get_current_dir().plus_file(file->get_text());
+
+ if (mode==MODE_OPEN_FILE && dir_access->file_exists(f)) {
+ _save_to_recent();
+ emit_signal("file_selected",f);
+ hide();
+ }
+
+ if (mode==MODE_OPEN_DIR) {
+
+
+ String path=dir_access->get_current_dir();
+ /*if (tree->get_selected()) {
+ Dictionary d = tree->get_selected()->get_metadata(0);
+ if (d["dir"]) {
+ path=path+"/"+String(d["name"]);
+ }
+ }*/
+ path=path.replace("\\","/");
+ _save_to_recent();
+ emit_signal("dir_selected",path);
+ hide();
+ }
+
+ if (mode==MODE_SAVE_FILE) {
+
+ bool valid=false;
+
+ if (filter->get_selected()==filter->get_item_count()-1) {
+ valid=true; //match none
+ } else if (filters.size()>1 && filter->get_selected()==0) {
+ // match all filters
+ for (int i=0;i<filters.size();i++) {
+
+ String flt=filters[i].get_slice(";",0);
+ for (int j=0;j<flt.get_slice_count(",");j++) {
+
+ String str = flt.get_slice(",",j).strip_edges();
+ if (f.match(str)) {
+ valid=true;
+ break;
+ }
+ }
+ if (valid)
+ break;
+ }
+ } else {
+ int idx=filter->get_selected();
+ if (filters.size()>1)
+ idx--;
+ if (idx>=0 && idx<filters.size()) {
+
+ String flt=filters[idx].get_slice(";",0);
+ int filterSliceCount=flt.get_slice_count(",");
+ for (int j=0;j<filterSliceCount;j++) {
+
+ String str = (flt.get_slice(",",j).strip_edges());
+ if (f.match(str)) {
+ valid=true;
+ break;
+ }
+ }
+
+ if (!valid && filterSliceCount>0) {
+ String str = (flt.get_slice(",",0).strip_edges());
+ f+=str.substr(1, str.length()-1);
+ _request_single_thumbnail(get_current_dir().plus_file(f.get_file()));
+ file->set_text(f.get_file());
+ valid=true;
+ }
+ } else {
+ valid=true;
+ }
+ }
+
+
+ if (!valid) {
+
+ exterr->popup_centered_minsize(Size2(250,80));
+ return;
+
+ }
+
+ if (dir_access->file_exists(f)) {
+ confirm_save->set_text("File Exists, Overwrite?");
+ confirm_save->popup_centered(Size2(200,80));
+ } else {
+
+ _save_to_recent();
+ emit_signal("file_selected",f);
+ hide();
+ }
+ }
+}
+
+void EditorFileDialog::_cancel_pressed() {
+
+ file->set_text("");
+ invalidate();
+ hide();
+}
+
+void EditorFileDialog::_item_selected(int p_item) {
+
+ int current = p_item;
+ if (current<0 || current>=item_list->get_item_count())
+ return;
+
+ Dictionary d=item_list->get_item_metadata(current);
+
+ if (!d["dir"]) {
+
+ file->set_text(d["name"]);
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ }
+}
+
+void EditorFileDialog::_push_history() {
+
+ local_history.resize(local_history_pos+1);
+ String new_path = dir_access->get_current_dir();
+ if (local_history.size()==0 || new_path!=local_history[local_history_pos]) {
+ local_history.push_back(new_path);
+ local_history_pos++;
+ dir_prev->set_disabled(local_history_pos==0);
+ dir_next->set_disabled(true);
+ }
+
+}
+void EditorFileDialog::_item_dc_selected(int p_item) {
+
+
+ int current = p_item;
+ if (current<0 || current>=item_list->get_item_count())
+ return;
+
+ Dictionary d=item_list->get_item_metadata(current);
+
+ if (d["dir"]) {
+
+ //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("");
+ call_deferred("_update_file_list");
+ call_deferred("_update_dir");
+
+ _push_history();
+
+
+ } else {
+
+ _action_pressed();
+ }
+}
+
+
+
+void EditorFileDialog::update_file_list() {
+
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ Ref<Texture> folder_thumbnail;
+ Ref<Texture> file_thumbnail;
+
+ item_list->clear();
+
+ if (display_mode==DISPLAY_THUMBNAILS) {
+
+ item_list->set_max_columns(0);
+ item_list->set_icon_mode(ItemList::ICON_MODE_TOP);
+ item_list->set_fixed_column_width(thumbnail_size*3/2);
+ item_list->set_max_text_lines(2);
+ item_list->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");
+
+ preview_vb->hide();
+
+ } else {
+
+ item_list->set_icon_mode(ItemList::ICON_MODE_LEFT);
+ item_list->set_max_columns(1);
+ item_list->set_max_text_lines(1);
+ item_list->set_fixed_column_width(0);
+ item_list->set_min_icon_size(Size2());
+ if (preview->get_texture().is_valid())
+ preview_vb->show();
+
+ }
+
+ String cdir = dir_access->get_current_dir();
+ bool skip_pp = access==ACCESS_RESOURCES && cdir=="res://";
+
+ dir_access->list_dir_begin();
+
+
+ Ref<Texture> folder = get_icon("folder","FileDialog");
+ List<String> files;
+ List<String> dirs;
+
+ bool isdir;
+ bool ishidden;
+ bool show_hidden = show_hidden_files;
+ String item;
+
+ while ((item=dir_access->get_next(&isdir))!="") {
+
+ ishidden = dir_access->current_is_hidden();
+
+ if (show_hidden || !ishidden) {
+ if (!isdir)
+ files.push_back(item);
+ else if (item!=".." || !skip_pp)
+ dirs.push_back(item);
+ }
+ }
+
+ dirs.sort_custom<NoCaseComparator>();
+ files.sort_custom<NoCaseComparator>();
+
+ while(!dirs.empty()) {
+
+ if (dirs.front()->get()!=".") {
+ item_list->add_item(dirs.front()->get()+"/");
+ if (display_mode==DISPLAY_THUMBNAILS) {
+
+ item_list->set_item_icon(item_list->get_item_count()-1,folder_thumbnail);
+ } else {
+
+ item_list->set_item_icon(item_list->get_item_count()-1,folder);
+ }
+
+ Dictionary d;
+ d["name"]=dirs.front()->get();
+ d["path"]=String();
+ d["dir"]=true;
+ item_list->set_item_metadata( item_list->get_item_count() -1, d);
+ }
+ dirs.pop_front();
+
+ }
+
+ dirs.clear();
+
+ List<String> patterns;
+ // build filter
+ if (filter->get_selected()==filter->get_item_count()-1) {
+
+ // match all
+ } else if (filters.size()>1 && filter->get_selected()==0) {
+ // match all filters
+ for (int i=0;i<filters.size();i++) {
+
+ String f=filters[i].get_slice(";",0);
+ for (int j=0;j<f.get_slice_count(",");j++) {
+
+ patterns.push_back(f.get_slice(",",j).strip_edges());
+ }
+ }
+ } else {
+ int idx=filter->get_selected();
+ if (filters.size()>1)
+ idx--;
+
+ if (idx>=0 && idx<filters.size()) {
+
+ String f=filters[idx].get_slice(";",0);
+ for (int j=0;j<f.get_slice_count(",");j++) {
+
+ patterns.push_back(f.get_slice(",",j).strip_edges());
+ }
+ }
+ }
+
+
+ String base_dir = dir_access->get_current_dir();
+
+
+ while(!files.empty()) {
+
+ bool match=patterns.empty();
+
+ for(List<String>::Element *E=patterns.front();E;E=E->next()) {
+
+ if (files.front()->get().matchn(E->get())) {
+
+ match=true;
+ break;
+ }
+ }
+
+ if (match) {
+ //TreeItem *ti=tree->create_item(root);
+ //ti->set_text(0,files.front()->get());
+ item_list->add_item(files.front()->get());
+
+ 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) {
+
+ item_list->set_item_icon(item_list->get_item_count()-1,file_thumbnail);
+ item_list->set_item_tag_icon(item_list->get_item_count()-1,icon);
+ } else {
+ item_list->set_item_icon(item_list->get_item_count()-1,icon);
+ }
+ }
+
+ if (mode==MODE_OPEN_DIR) {
+ //disabled mode?
+ //ti->set_custom_color(0,get_color("files_disabled"));
+ //ti->set_selectable(0,false);
+ }
+ Dictionary d;
+ d["name"]=files.front()->get();
+ d["dir"]=false;
+ String fullpath = base_dir.plus_file(files.front()->get());
+
+ if (display_mode==DISPLAY_THUMBNAILS) {
+ EditorResourcePreview::get_singleton()->queue_resource_preview(fullpath,this,"_thumbnail_result",fullpath);
+ }
+ d["path"]=base_dir.plus_file(files.front()->get());
+ //ti->set_metadata(0,d);
+ item_list->set_item_metadata(item_list->get_item_count()-1,d);
+
+ if (file->get_text()==files.front()->get())
+ item_list->set_current(item_list->get_item_count()-1);
+ }
+
+ files.pop_front();
+ }
+
+ if (favorites->get_current()>=0) {
+ favorites->unselect(favorites->get_current());
+ }
+
+ favorite->set_pressed(false);
+ fav_up->set_disabled(true);
+ fav_down->set_disabled(true);
+ for(int i=0;i<favorites->get_item_count();i++) {
+ if (favorites->get_item_metadata(i)==base_dir) {
+ favorites->select(i);
+ favorite->set_pressed(true);
+ if (i>0) {
+ fav_up->set_disabled(false);
+ }
+ if (i<favorites->get_item_count()-1) {
+ fav_down->set_disabled(false);
+ }
+ break;
+ }
+
+ }
+ // ??
+ //if (tree->get_root() && tree->get_root()->get_children())
+ // tree->get_root()->get_children()->select(0);
+
+ files.clear();
+
+}
+
+void EditorFileDialog::_filter_selected(int) {
+
+ update_file_list();
+}
+
+void EditorFileDialog::update_filters() {
+
+ filter->clear();
+
+ if (filters.size()>1) {
+ String all_filters;
+
+ const int max_filters=5;
+
+ for(int i=0;i<MIN( max_filters, filters.size()) ;i++) {
+ String flt=filters[i].get_slice(";",0);
+ if (i>0)
+ all_filters+=",";
+ all_filters+=flt;
+ }
+
+ if (max_filters<filters.size())
+ all_filters+=", ...";
+
+ filter->add_item("All Recognized ( "+all_filters+" )");
+ }
+ for(int i=0;i<filters.size();i++) {
+
+ String flt=filters[i].get_slice(";",0).strip_edges();
+ String desc=filters[i].get_slice(";",1).strip_edges();
+ if (desc.length())
+ filter->add_item(desc+" ( "+flt+" )");
+ else
+ filter->add_item("( "+flt+" )");
+ }
+
+ filter->add_item("All Files (*)");
+
+}
+
+void EditorFileDialog::clear_filters() {
+
+ filters.clear();
+ update_filters();
+ invalidate();
+}
+void EditorFileDialog::add_filter(const String& p_filter) {
+
+ filters.push_back(p_filter);
+ update_filters();
+ invalidate();
+
+}
+
+String EditorFileDialog::get_current_dir() const {
+
+ return dir->get_text();
+}
+String EditorFileDialog::get_current_file() const {
+
+ return file->get_text();
+}
+String EditorFileDialog::get_current_path() const {
+
+ return dir->get_text().plus_file(file->get_text());
+}
+void EditorFileDialog::set_current_dir(const String& p_dir) {
+
+ dir_access->change_dir(p_dir);
+ update_dir();
+ invalidate();
+ //_push_history();
+
+
+}
+void EditorFileDialog::set_current_file(const String& p_file) {
+
+ file->set_text(p_file);
+ update_dir();
+ invalidate();
+ int lp = p_file.find_last(".");
+ if (lp!=-1) {
+ file->select(0,lp);
+ file->grab_focus();
+ }
+
+ if (is_visible())
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+
+
+}
+void EditorFileDialog::set_current_path(const String& p_path) {
+
+ if (!p_path.size())
+ return;
+ int pos=MAX( p_path.find_last("/"), p_path.find_last("\\") );
+ if (pos==-1) {
+
+ set_current_file(p_path);
+ } else {
+
+ String dir=p_path.substr(0,pos);
+ String file=p_path.substr(pos+1,p_path.length());
+ set_current_dir(dir);
+ set_current_file(file);
+ }
+}
+
+
+void EditorFileDialog::set_mode(Mode p_mode) {
+
+ mode=p_mode;
+ switch(mode) {
+
+ case MODE_OPEN_FILE: get_ok()->set_text("Open"); set_title("Open a File"); makedir->hide(); break;
+ case MODE_OPEN_FILES: get_ok()->set_text("Open"); set_title("Open File(s)"); makedir->hide(); break;
+ case MODE_SAVE_FILE: get_ok()->set_text("Save"); set_title("Save a File"); makedir->show(); break;
+ case MODE_OPEN_DIR: get_ok()->set_text("Open"); set_title("Open a Directory"); makedir->show(); break;
+ }
+
+ if (mode==MODE_OPEN_FILES) {
+ item_list->set_select_mode(ItemList::SELECT_MULTI);
+ } else {
+ item_list->set_select_mode(ItemList::SELECT_SINGLE);
+ }
+}
+
+EditorFileDialog::Mode EditorFileDialog::get_mode() const {
+
+ return mode;
+}
+
+void EditorFileDialog::set_access(Access p_access) {
+
+ ERR_FAIL_INDEX(p_access,3);
+ if (access==p_access)
+ return;
+ memdelete( dir_access );
+ switch(p_access) {
+ case ACCESS_FILESYSTEM: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ } break;
+ case ACCESS_RESOURCES: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ } break;
+ case ACCESS_USERDATA: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_USERDATA);
+ } break;
+ }
+ access=p_access;
+ _update_drives();
+ invalidate();
+ update_filters();
+ update_dir();
+}
+
+void EditorFileDialog::invalidate() {
+
+ if (is_visible()) {
+ update_file_list();
+ invalidated=false;
+ } else {
+ invalidated=true;
+ }
+
+}
+
+EditorFileDialog::Access EditorFileDialog::get_access() const{
+
+ return access;
+}
+
+void EditorFileDialog::_make_dir_confirm() {
+
+
+ Error err = dir_access->make_dir( makedirname->get_text() );
+ if (err==OK) {
+ dir_access->change_dir(makedirname->get_text());
+ invalidate();
+ update_filters();
+ update_dir();
+ _push_history();
+
+ } else {
+ mkdirerr->popup_centered_minsize(Size2(250,50));
+ }
+}
+
+
+void EditorFileDialog::_make_dir() {
+
+ makedialog->popup_centered_minsize(Size2(250,80));
+ makedirname->grab_focus();
+
+}
+
+void EditorFileDialog::_select_drive(int p_idx) {
+
+ String d = drives->get_item_text(p_idx);
+ dir_access->change_dir(d);
+ file->set_text("");
+ invalidate();
+ update_dir();
+ _push_history();
+
+
+}
+
+void EditorFileDialog::_update_drives() {
+
+
+ int dc = dir_access->get_drive_count();
+ if (dc==0 || access!=ACCESS_FILESYSTEM) {
+ drives->hide();
+ } else {
+ drives->clear();
+ drives->show();
+
+ for(int i=0;i<dir_access->get_drive_count();i++) {
+ String d = dir_access->get_drive(i);
+ drives->add_item(dir_access->get_drive(i));
+ }
+
+ drives->select(dir_access->get_current_drive());
+
+ }
+}
+
+
+void EditorFileDialog::_favorite_selected(int p_idx) {
+
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+ ERR_FAIL_INDEX(p_idx,favorited.size());
+
+ dir_access->change_dir(favorited[p_idx]);
+ file->set_text("");
+ invalidate();
+ update_dir();
+ _push_history();
+}
+
+void EditorFileDialog::_favorite_move_up(){
+
+ int current = favorites->get_current();
+
+ if (current>0 && current<favorites->get_item_count()) {
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+
+ int a_idx=favorited.find(String(favorites->get_item_metadata(current-1)));
+ int b_idx=favorited.find(String(favorites->get_item_metadata(current)));
+
+ if (a_idx==-1 || b_idx==-1)
+ return;
+ SWAP(favorited[a_idx],favorited[b_idx]);
+
+ EditorSettings::get_singleton()->set_favorite_dirs(favorited);
+
+ _update_favorites();
+ update_file_list();
+
+ }
+}
+void EditorFileDialog::_favorite_move_down(){
+
+ int current = favorites->get_current();
+
+ if (current>=0 && current<favorites->get_item_count()-1) {
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+
+ int a_idx=favorited.find(String(favorites->get_item_metadata(current+1)));
+ int b_idx=favorited.find(String(favorites->get_item_metadata(current)));
+
+ if (a_idx==-1 || b_idx==-1)
+ return;
+ SWAP(favorited[a_idx],favorited[b_idx]);
+
+ EditorSettings::get_singleton()->set_favorite_dirs(favorited);
+
+ _update_favorites();
+ update_file_list();
+
+ }
+}
+
+
+void EditorFileDialog::_update_favorites() {
+
+ bool res = access==ACCESS_RESOURCES;
+
+ String current = get_current_dir();
+ Ref<Texture> star = get_icon("Favorites","EditorIcons");
+ favorites->clear();
+
+ favorite->set_pressed(false);
+
+
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+ for(int i=0;i<favorited.size();i++) {
+ bool cres = favorited[i].begins_with("res://");
+ if (cres!=res)
+ continue;
+ String name = favorited[i];
+
+ bool setthis = name==current;
+
+ if (res && name=="res://") {
+ name="/";
+ } else {
+ name=name.get_file()+"/";
+ }
+
+
+ //print_line("file: "+name);
+ favorites->add_item(name,star);
+ favorites->set_item_metadata( favorites->get_item_count()-1,favorited[i]);
+
+ if (setthis) {
+ favorite->set_pressed(true);
+ favorites->set_current(favorites->get_item_count()-1);
+ }
+ }
+
+
+}
+
+void EditorFileDialog::_favorite_toggled(bool p_toggle) {
+ bool res = access==ACCESS_RESOURCES;
+
+ String cd = get_current_dir();
+
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+
+ bool found = false;
+ for(int i=0;i<favorited.size();i++) {
+ bool cres = favorited[i].begins_with("res://");
+ if (cres!=res)
+ continue;
+
+ if (favorited[i]==cd) {
+ found=true;
+ break;
+ }
+ }
+
+ if (found) {
+ favorited.erase(cd);
+ favorite->set_pressed(false);
+ } else {
+ favorited.push_back(cd);
+ favorite->set_pressed(true);
+ }
+
+ EditorSettings::get_singleton()->set_favorite_dirs(favorited);
+
+ _update_favorites();
+
+}
+
+void EditorFileDialog::_recent_selected(int p_idx) {
+
+ Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
+ ERR_FAIL_INDEX(p_idx,recentd.size());
+
+ dir_access->change_dir(recent->get_item_metadata(p_idx));
+ update_file_list();
+ update_dir();
+ _push_history();
+}
+
+void EditorFileDialog::_go_up() {
+
+ dir_access->change_dir("..");
+ update_file_list();
+ update_dir();
+ _push_history();
+
+}
+
+void EditorFileDialog::_go_back(){
+
+ if (local_history_pos<=0) {
+ return;
+ }
+
+ local_history_pos--;
+ dir_access->change_dir(local_history[local_history_pos]);
+ update_file_list();
+ update_dir();
+
+ dir_prev->set_disabled(local_history_pos==0);
+ dir_next->set_disabled(local_history_pos==local_history.size()-1);
+}
+void EditorFileDialog::_go_forward(){
+
+ if (local_history_pos==local_history.size()-1) {
+ return;
+ }
+
+ local_history_pos++;
+ dir_access->change_dir(local_history[local_history_pos]);
+ update_file_list();
+ update_dir();
+
+ dir_prev->set_disabled(local_history_pos==0);
+ dir_next->set_disabled(local_history_pos==local_history.size()-1);
+
+}
+
+bool EditorFileDialog::default_show_hidden_files=false;
+
+void EditorFileDialog::set_display_mode(DisplayMode p_mode) {
+
+ if (display_mode==p_mode)
+ return;
+ if (p_mode==DISPLAY_THUMBNAILS) {
+ mode_list->set_pressed(false);
+ mode_thumbnails->set_pressed(true);
+ } else {
+ mode_thumbnails->set_pressed(false);
+ mode_list->set_pressed(true);
+ }
+ display_mode=p_mode;
+ invalidate();;
+}
+
+EditorFileDialog::DisplayMode EditorFileDialog::get_display_mode() const{
+
+ return display_mode;
+}
+
+
+
+void EditorFileDialog::_bind_methods() {
+
+ 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);
+ ObjectTypeDB::bind_method(_MD("_file_entered"),&EditorFileDialog::_file_entered);
+ ObjectTypeDB::bind_method(_MD("_action_pressed"),&EditorFileDialog::_action_pressed);
+ ObjectTypeDB::bind_method(_MD("_cancel_pressed"),&EditorFileDialog::_cancel_pressed);
+ ObjectTypeDB::bind_method(_MD("_filter_selected"),&EditorFileDialog::_filter_selected);
+ ObjectTypeDB::bind_method(_MD("_save_confirm_pressed"),&EditorFileDialog::_save_confirm_pressed);
+
+ ObjectTypeDB::bind_method(_MD("clear_filters"),&EditorFileDialog::clear_filters);
+ ObjectTypeDB::bind_method(_MD("add_filter","filter"),&EditorFileDialog::add_filter);
+ ObjectTypeDB::bind_method(_MD("get_current_dir"),&EditorFileDialog::get_current_dir);
+ ObjectTypeDB::bind_method(_MD("get_current_file"),&EditorFileDialog::get_current_file);
+ ObjectTypeDB::bind_method(_MD("get_current_path"),&EditorFileDialog::get_current_path);
+ ObjectTypeDB::bind_method(_MD("set_current_dir","dir"),&EditorFileDialog::set_current_dir);
+ ObjectTypeDB::bind_method(_MD("set_current_file","file"),&EditorFileDialog::set_current_file);
+ ObjectTypeDB::bind_method(_MD("set_current_path","path"),&EditorFileDialog::set_current_path);
+ ObjectTypeDB::bind_method(_MD("set_mode","mode"),&EditorFileDialog::set_mode);
+ ObjectTypeDB::bind_method(_MD("get_mode"),&EditorFileDialog::get_mode);
+ 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("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);
+ ObjectTypeDB::bind_method(_MD("_make_dir_confirm"),&EditorFileDialog::_make_dir_confirm);
+ ObjectTypeDB::bind_method(_MD("_update_file_list"),&EditorFileDialog::update_file_list);
+ ObjectTypeDB::bind_method(_MD("_update_dir"),&EditorFileDialog::update_dir);
+ ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&EditorFileDialog::_thumbnail_done);
+ ObjectTypeDB::bind_method(_MD("set_display_mode","mode"),&EditorFileDialog::set_display_mode);
+ ObjectTypeDB::bind_method(_MD("get_display_mode"),&EditorFileDialog::get_display_mode);
+ ObjectTypeDB::bind_method(_MD("_thumbnail_result"),&EditorFileDialog::_thumbnail_result);
+
+ ObjectTypeDB::bind_method(_MD("_recent_selected"),&EditorFileDialog::_recent_selected);
+ ObjectTypeDB::bind_method(_MD("_go_back"),&EditorFileDialog::_go_back);
+ ObjectTypeDB::bind_method(_MD("_go_forward"),&EditorFileDialog::_go_forward);
+ ObjectTypeDB::bind_method(_MD("_go_up"),&EditorFileDialog::_go_up);
+
+ ObjectTypeDB::bind_method(_MD("_favorite_toggled"),&EditorFileDialog::_favorite_toggled);
+ ObjectTypeDB::bind_method(_MD("_favorite_selected"),&EditorFileDialog::_favorite_selected);
+ ObjectTypeDB::bind_method(_MD("_favorite_move_up"),&EditorFileDialog::_favorite_move_up);
+ ObjectTypeDB::bind_method(_MD("_favorite_move_down"),&EditorFileDialog::_favorite_move_down);
+
+ ObjectTypeDB::bind_method(_MD("invalidate"),&EditorFileDialog::invalidate);
+
+ ADD_SIGNAL(MethodInfo("file_selected",PropertyInfo( Variant::STRING,"path")));
+ ADD_SIGNAL(MethodInfo("files_selected",PropertyInfo( Variant::STRING_ARRAY,"paths")));
+ ADD_SIGNAL(MethodInfo("dir_selected",PropertyInfo( Variant::STRING,"dir")));
+
+ BIND_CONSTANT( MODE_OPEN_FILE );
+ BIND_CONSTANT( MODE_OPEN_FILES );
+ BIND_CONSTANT( MODE_OPEN_DIR );
+ BIND_CONSTANT( MODE_SAVE_FILE );
+
+ BIND_CONSTANT( ACCESS_RESOURCES );
+ BIND_CONSTANT( ACCESS_USERDATA );
+ BIND_CONSTANT( ACCESS_FILESYSTEM );
+
+}
+
+
+void EditorFileDialog::set_show_hidden_files(bool p_show) {
+ show_hidden_files=p_show;
+ invalidate();
+}
+
+bool EditorFileDialog::is_showing_hidden_files() const {
+ return show_hidden_files;
+}
+
+void EditorFileDialog::set_default_show_hidden_files(bool p_show) {
+ default_show_hidden_files=p_show;
+}
+
+void EditorFileDialog::_save_to_recent() {
+
+ String dir = get_current_dir();
+ Vector<String> recent = EditorSettings::get_singleton()->get_recent_dirs();
+
+ const int max=20;
+ int count=0;
+ bool res=dir.begins_with("res://");
+
+ for(int i=0;i<recent.size();i++) {
+ bool cres=recent[i].begins_with("res://");
+ if (recent[i]==dir || (res==cres && count>max)) {
+ recent.remove(i);
+ i--;
+ } else {
+ count++;
+ }
+ }
+
+ recent.insert(0,dir);
+
+ EditorSettings::get_singleton()->set_recent_dirs(recent);
+
+
+}
+
+EditorFileDialog::EditorFileDialog() {
+
+ show_hidden_files=default_show_hidden_files;
+ display_mode=DISPLAY_THUMBNAILS;
+ local_history_pos=0;
+
+ VBoxContainer *vbc = memnew( VBoxContainer );
+ add_child(vbc);
+ set_child_rect(vbc);
+
+ mode=MODE_SAVE_FILE;
+ set_title("Save a File");
+
+ HBoxContainer *pathhb = memnew( HBoxContainer );
+
+ dir_prev = memnew( ToolButton );
+ dir_next = memnew( ToolButton );
+ dir_up = memnew( ToolButton );
+
+ pathhb->add_child(dir_prev);
+ pathhb->add_child(dir_next);
+ pathhb->add_child(dir_up);
+
+ dir_prev->connect("pressed",this,"_go_back");
+ dir_next->connect("pressed",this,"_go_forward");
+ dir_up->connect("pressed",this,"_go_up");
+
+ dir = memnew(LineEdit);
+ 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");
+ pathhb->add_child(favorite);
+
+ 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);
+ 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);
+ pathhb->add_child(mode_list);
+
+ drives = memnew( OptionButton );
+ pathhb->add_child(drives);
+ drives->connect("item_selected",this,"_select_drive");
+
+ makedir = memnew( Button );
+ makedir->set_text("Create Folder");
+ makedir->connect("pressed",this,"_make_dir");
+ pathhb->add_child(makedir);
+
+ list_hb = memnew( HBoxContainer );
+
+ vbc->add_margin_child("Path:",pathhb);
+ vbc->add_child(list_hb);
+ list_hb->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ VBoxContainer *fav_vb = memnew( VBoxContainer );
+ list_hb->add_child(fav_vb);
+ HBoxContainer *fav_hb = memnew( HBoxContainer );
+ fav_vb->add_child(fav_hb);
+ fav_hb->add_child(memnew(Label("Favorites:")));
+ fav_hb->add_spacer();
+ fav_up = memnew( ToolButton );
+ fav_hb->add_child(fav_up);
+ fav_up->connect("pressed",this,"_favorite_move_up");
+ fav_down = memnew( ToolButton );
+ fav_hb->add_child(fav_down);
+ fav_down->connect("pressed",this,"_favorite_move_down");
+ fav_rm = memnew( ToolButton );
+ fav_hb->add_child(fav_rm);
+ fav_rm->hide(); // redundant
+
+ MarginContainer *fav_mv = memnew( MarginContainer );
+ fav_vb->add_child(fav_mv);
+ fav_mv->set_v_size_flags(SIZE_EXPAND_FILL);
+ favorites = memnew( ItemList );
+ fav_mv->add_child(favorites);
+ favorites->connect("item_selected",this,"_favorite_selected");
+
+ recent = memnew( ItemList );
+ fav_vb->add_margin_child("Recent:",recent,true);
+ recent->connect("item_selected",this,"_recent_selected");
+
+ VBoxContainer *item_vb = memnew( VBoxContainer );
+ list_hb->add_child(item_vb);
+ item_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ item_list = memnew( ItemList );
+ item_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ item_vb->add_margin_child("Directories & Files:",item_list,true);
+
+ HBoxContainer* filter_hb = memnew( HBoxContainer );
+ item_vb->add_child(filter_hb);
+
+ VBoxContainer *filter_vb = memnew( VBoxContainer );
+ filter_hb->add_child(filter_vb);
+ filter_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ preview_vb = memnew( VBoxContainer );
+ filter_hb->add_child(preview_vb);
+ CenterContainer *prev_cc = memnew( CenterContainer );
+ preview_vb->add_margin_child("Preview:",prev_cc);
+ preview = memnew( TextureFrame );
+ prev_cc->add_child(preview);
+ preview_vb->hide();
+
+
+ file = memnew(LineEdit);
+ //add_child(file);
+ filter_vb->add_margin_child("File:",file);
+
+
+ filter = memnew( OptionButton );
+ //add_child(filter);
+ filter_vb->add_margin_child("Filter:",filter);
+ filter->set_clip_text(true);//too many extensions overflow it
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ access=ACCESS_RESOURCES;
+ _update_drives();
+
+
+ connect("confirmed", this,"_action_pressed");
+ //cancel->connect("pressed", this,"_cancel_pressed");
+ item_list->connect("item_selected", this,"_item_selected",varray(),CONNECT_DEFERRED);
+ item_list->connect("item_activated", this,"_item_db_selected",varray());
+ dir->connect("text_entered", this,"_dir_entered");
+ file->connect("text_entered", this,"_file_entered");
+ filter->connect("item_selected", this,"_filter_selected");
+
+
+ confirm_save = memnew( ConfirmationDialog );
+ confirm_save->set_as_toplevel(true);
+ add_child(confirm_save);
+
+
+ confirm_save->connect("confirmed", this,"_save_confirm_pressed");
+
+ makedialog = memnew( ConfirmationDialog );
+ makedialog->set_title("Create Folder");
+ 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);
+
+ exterr = memnew( AcceptDialog );
+ exterr->set_text("Must use a valid extension.");
+ add_child(exterr);
+
+
+ //update_file_list();
+ update_filters();
+ update_dir();
+
+ set_hide_on_ok(false);
+ vbox=vbc;
+
+
+ invalidated=true;
+ if (register_func)
+ register_func(this);
+
+ preview_wheel_timeout=0;
+ preview_wheel_index=0;
+ preview_waiting=false;
+
+}
+
+
+EditorFileDialog::~EditorFileDialog() {
+
+ if (unregister_func)
+ unregister_func(this);
+ memdelete(dir_access);
+}
+
+
+void EditorLineEditFileChooser::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_browse"),&EditorLineEditFileChooser::_browse);
+ ObjectTypeDB::bind_method(_MD("_chosen"),&EditorLineEditFileChooser::_chosen);
+ ObjectTypeDB::bind_method(_MD("get_button:Button"),&EditorLineEditFileChooser::get_button);
+ ObjectTypeDB::bind_method(_MD("get_line_edit:LineEdit"),&EditorLineEditFileChooser::get_line_edit);
+ ObjectTypeDB::bind_method(_MD("get_file_dialog:EditorFileDialog"),&EditorLineEditFileChooser::get_file_dialog);
+
+}
+
+void EditorLineEditFileChooser::_chosen(const String& p_text){
+
+ line_edit->set_text(p_text);
+ line_edit->emit_signal("text_entered",p_text);
+}
+
+void EditorLineEditFileChooser::_browse() {
+
+ dialog->popup_centered_ratio();
+}
+
+EditorLineEditFileChooser::EditorLineEditFileChooser() {
+
+ line_edit = memnew( LineEdit );
+ add_child(line_edit);
+ line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ button = memnew( Button );
+ button->set_text(" .. ");
+ add_child(button);
+ button->connect("pressed",this,"_browse");
+ dialog = memnew( EditorFileDialog);
+ add_child(dialog);
+ dialog->connect("file_selected",this,"_chosen");
+ dialog->connect("dir_selected",this,"_chosen");
+ dialog->connect("files_selected",this,"_chosen");
+
+}
diff --git a/tools/editor/editor_file_dialog.h b/tools/editor/editor_file_dialog.h
new file mode 100644
index 0000000000..eb38c3c02f
--- /dev/null
+++ b/tools/editor/editor_file_dialog.h
@@ -0,0 +1,246 @@
+/*************************************************************************/
+/* file_dialog.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 EDITORFILEDIALOG_H
+#define EDITORFILEDIALOG_H
+
+#include "scene/gui/dialogs.h"
+#include "scene/gui/item_list.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/dialogs.h"
+#include "os/dir_access.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/texture_frame.h"
+#include "scene/gui/tool_button.h"
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class EditorFileDialog : public ConfirmationDialog {
+
+ OBJ_TYPE( EditorFileDialog, ConfirmationDialog );
+
+public:
+
+ enum DisplayMode {
+ DISPLAY_THUMBNAILS,
+ DISPLAY_LIST
+ };
+
+
+ enum Access {
+ ACCESS_RESOURCES,
+ ACCESS_USERDATA,
+ ACCESS_FILESYSTEM
+ };
+
+
+ enum Mode {
+ MODE_OPEN_FILE,
+ MODE_OPEN_FILES,
+ MODE_OPEN_DIR,
+ MODE_SAVE_FILE,
+ };
+
+ typedef Ref<Texture> (*GetIconFunc)(const String&);
+ typedef void (*RegisterFunc)(EditorFileDialog*);
+
+ static GetIconFunc get_icon_func;
+ static GetIconFunc get_large_icon_func;
+ static RegisterFunc register_func;
+ static RegisterFunc unregister_func;
+
+private:
+
+ ConfirmationDialog *makedialog;
+ LineEdit *makedirname;
+
+ Button *makedir;
+ Access access;
+ //Button *action;
+ VBoxContainer *vbox;
+ Mode mode;
+ LineEdit *dir;
+
+ ToolButton *dir_prev;
+ ToolButton *dir_next;
+ ToolButton *dir_up;
+
+ OptionButton *drives;
+ ItemList *item_list;
+ TextureFrame *preview;
+ VBoxContainer *preview_vb;
+ HBoxContainer *list_hb;
+ LineEdit *file;
+ AcceptDialog *mkdirerr;
+ AcceptDialog *exterr;
+ OptionButton *filter;
+ DirAccess *dir_access;
+ ConfirmationDialog *confirm_save;
+ ToolButton *mode_thumbnails;
+ ToolButton *mode_list;
+
+
+ ToolButton *refresh;
+ ToolButton *favorite;
+
+ ToolButton *fav_up;
+ ToolButton *fav_down;
+ ToolButton *fav_rm;
+
+ ItemList *favorites;
+ ItemList *recent;
+
+ Vector<String> local_history;
+ int local_history_pos;
+ void _push_history();
+
+ Vector<String> filters;
+
+ bool preview_waiting;
+ int preview_wheel_index;
+ float preview_wheel_timeout;
+ static bool default_show_hidden_files;
+ bool show_hidden_files;
+ DisplayMode display_mode;
+
+ bool invalidated;
+
+ void update_dir();
+ void update_file_list();
+ void update_filters();
+
+ void _update_favorites();
+ void _favorite_toggled(bool p_toggle);
+ void _favorite_selected(int p_idx);
+ void _favorite_move_up();
+ void _favorite_move_down();
+
+
+
+ void _recent_selected(int p_idx);
+
+ void _item_selected(int p_item);
+ void _item_dc_selected(int p_item);
+
+ void _select_drive(int p_idx);
+ void _dir_entered(String p_dir);
+ void _file_entered(const String& p_file);
+ void _action_pressed();
+ void _save_confirm_pressed();
+ void _cancel_pressed();
+ void _filter_selected(int);
+ void _make_dir();
+ void _make_dir_confirm();
+
+ void _update_drives();
+
+ void _go_up();
+ void _go_back();
+ void _go_forward();
+
+ virtual void _post_popup();
+
+ void _save_to_recent();
+ //callback funtion is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
+
+ void _thumbnail_result(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata);
+ void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata);
+ void _request_single_thumbnail(const String& p_path);
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+ //bind helpers
+public:
+
+ void clear_filters();
+ void add_filter(const String& p_filter);
+
+ void set_enable_multiple_selection(bool p_enable);
+ Vector<String> get_selected_files() const;
+
+ String get_current_dir() const;
+ String get_current_file() const;
+ String get_current_path() const;
+ void set_current_dir(const String& p_dir);
+ void set_current_file(const String& p_file);
+ void set_current_path(const String& p_path);
+
+ void set_display_mode(DisplayMode p_mode);
+ DisplayMode get_display_mode() const;
+
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ VBoxContainer *get_vbox();
+ LineEdit *get_line_edit() { return file; }
+
+ void set_access(Access p_access);
+ Access get_access() const;
+
+ void set_show_hidden_files(bool p_show);
+ bool is_showing_hidden_files() const;
+
+ static void set_default_show_hidden_files(bool p_show);
+
+ void invalidate();
+
+ EditorFileDialog();
+ ~EditorFileDialog();
+
+};
+
+class EditorLineEditFileChooser : public HBoxContainer {
+
+ OBJ_TYPE( EditorLineEditFileChooser, HBoxContainer );
+ Button *button;
+ LineEdit *line_edit;
+ EditorFileDialog *dialog;
+
+ void _chosen(const String& p_text);
+ void _browse();
+protected:
+ static void _bind_methods();
+public:
+
+ Button *get_button() { return button; }
+ LineEdit *get_line_edit() { return line_edit; }
+ EditorFileDialog *get_file_dialog() { return dialog; }
+
+ EditorLineEditFileChooser();
+};
+
+VARIANT_ENUM_CAST( EditorFileDialog::Mode );
+VARIANT_ENUM_CAST( EditorFileDialog::Access );
+VARIANT_ENUM_CAST( EditorFileDialog::DisplayMode );
+
+#endif // EDITORFILEDIALOG_H
diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp
index daba52be03..33e4a15c85 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,7 +33,7 @@
#include "os/file_access.h"
#include "editor_node.h"
#include "io/resource_saver.h"
-
+#include "editor_settings.h"
EditorFileSystem *EditorFileSystem::singleton=NULL;
@@ -94,6 +94,12 @@ bool EditorFileSystemDirectory::get_file_meta(int p_idx) const {
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>());
@@ -118,7 +124,7 @@ bool EditorFileSystemDirectory::is_missing_sources(int p_idx) const {
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;
@@ -142,7 +148,7 @@ void EditorFileSystemDirectory::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_file","idx"),&EditorFileSystemDirectory::get_file);
ObjectTypeDB::bind_method(_MD("get_file_path","idx"),&EditorFileSystemDirectory::get_file_path);
ObjectTypeDB::bind_method(_MD("get_file_types","idx"),&EditorFileSystemDirectory::get_file_type);
- ObjectTypeDB::bind_method(_MD("is_missing_sources","idx"),&EditorFileSystemDirectory::get_file_type);
+ ObjectTypeDB::bind_method(_MD("is_missing_sources","idx"),&EditorFileSystemDirectory::is_missing_sources);
ObjectTypeDB::bind_method(_MD("get_name"),&EditorFileSystemDirectory::get_name);
ObjectTypeDB::bind_method(_MD("get_parent"),&EditorFileSystemDirectory::get_parent);
@@ -198,6 +204,13 @@ EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String&
}
m.import_editor=imd->get_editor();
}
+
+ 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());
+ }
+
return m;
}
@@ -357,7 +370,9 @@ void EditorFileSystem::_scan_scenes() {
String project=Globals::get_singleton()->get_resource_path();
- FileAccess *f =FileAccess::open(project+"/.fscache",FileAccess::READ);
+
+ String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache");
+ FileAccess *f =FileAccess::open(fscache,FileAccess::READ);
if (f) {
//read the disk cache
@@ -395,7 +410,7 @@ void EditorFileSystem::_scan_scenes() {
} else {
Vector<String> split = l.split("::");
- ERR_CONTINUE( split.size() != 4);
+ ERR_CONTINUE( split.size() != 5);
String name = split[0];
String file;
@@ -427,6 +442,15 @@ 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);
@@ -470,7 +494,9 @@ void EditorFileSystem::_scan_scenes() {
//save back the findings
- f=FileAccess::open(project+"/.fscache",FileAccess::WRITE);
+// 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);
f->close();
memdelete(f);
@@ -526,6 +552,7 @@ void EditorFileSystem::scan() {
thread = Thread::create(_thread_func,this,s);
//tree->hide();
//progress->show();
+
}
@@ -681,12 +708,12 @@ void EditorFileSystem::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
_load_type_cache();
scan();
} break;
- case NOTIFICATION_EXIT_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
if (use_threads && thread) {
//abort thread if in progress
abort_scan=true;
@@ -794,6 +821,14 @@ 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);
}
@@ -940,19 +975,19 @@ String EditorFileSystem::get_file_type(const String& p_file) const {
EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) {
if (!filesystem || scanning)
- return false;
+ return NULL;
String f = Globals::get_singleton()->localize_path(p_path);
if (!f.begins_with("res://"))
- return false;
+ return NULL;
f=f.substr(6,f.length());
f=f.replace("\\","/");
if (f==String())
- return filesystem;
+ return filesystem;
if (f.ends_with("/"))
f=f.substr(0,f.length()-1);
@@ -960,7 +995,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) {
Vector<String> path = f.split("/");
if (path.size()==0)
- return false;
+ return NULL;
EditorFileSystemDirectory *fs=filesystem;
@@ -989,9 +1024,39 @@ EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) {
void EditorFileSystem::_resource_saved(const String& 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++) {
+
+ if (p_dir->files[i].meta.sources[j].path==p_src)
+ return p_dir->get_file_path(i);
+ }
+ }
+
+ for(int i=0;i<p_dir->subdirs.size();i++) {
+
+ String ret = _find_first_from_source(p_dir->subdirs[i],p_src);
+ if (ret.length()>0)
+ return ret;
+ }
+
+ return String();
+}
+
+
+String EditorFileSystem::find_resource_from_source(const String& p_path) const {
+
+
+ if (filesystem)
+ return _find_first_from_source(filesystem,p_path);
+ return String();
+}
+
void EditorFileSystem::update_file(const String& p_file) {
EditorFileSystemDirectory *fs=NULL;
@@ -1003,6 +1068,13 @@ void EditorFileSystem::update_file(const String& p_file) {
return;
}
+ if (!FileAccess::exists(p_file)) {
+ //was removed
+ fs->files.remove(cpos);
+ call_deferred("emit_signal","filesystem_changed"); //update later
+ return;
+
+ }
String type = ResourceLoader::get_resource_type(p_file);
diff --git a/tools/editor/editor_file_system.h b/tools/editor/editor_file_system.h
index c26fc02548..f79dd209ef 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -59,13 +59,14 @@ 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;
@@ -75,6 +76,7 @@ class EditorFileSystemDirectory : public Object {
static void _bind_methods();
+
friend class EditorFileSystem;
public:
@@ -86,10 +88,11 @@ 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();
@@ -119,7 +122,7 @@ class EditorFileSystem : public Node {
String path;
String name;
Vector<DirItem*> dirs;
- Vector<SceneItem*> files;
+ Vector<SceneItem*> files;
~DirItem();
};
@@ -148,6 +151,7 @@ class EditorFileSystem : public Node {
String type;
uint64_t modification_time;
EditorFileSystemDirectory::ImportMeta meta;
+ Vector<String> deps;
};
struct DirCache {
@@ -180,6 +184,7 @@ class EditorFileSystem : public Node {
List<String> sources_changed;
static void _resource_saved(const String& p_path);
+ String _find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const;
protected:
@@ -197,6 +202,7 @@ public:
void scan_sources();
void get_changed_sources(List<String> *r_changed);
void update_file(const String& p_file);
+ String find_resource_from_source(const String& p_path) const;
EditorFileSystemDirectory *get_path(const String& p_path);
String get_file_type(const String& p_file) const;
EditorFileSystem();
diff --git a/tools/editor/editor_fonts.cpp b/tools/editor/editor_fonts.cpp
index 86f1e9283c..f145f1ddef 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,50 +26,50 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "editor_fonts.h"
-#include "doc_font.h"
-#include "doc_title_font.h"
-#include "doc_code_font.h"
-
-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];
-
- int chr=c[0];
- Rect2 frect;
- frect.pos.x=c[1];
- frect.pos.y=c[2];
- frect.size.x=c[3];
- frect.size.y=c[4];
- Point2 align( c[5], c[6]+p_valign);
- int advance=c[7];
-
-
- font->add_char( chr, 0, frect, align,advance );
-
- }
-
- font->set_height( p_height );
- font->set_ascent( p_ascent );
-
- return font;
-}
-
-
-void editor_register_fonts(Ref<Theme> p_theme) {
-
-
- Ref<Font> doc_font = make_font(_bi_font_doc_font_height,_bi_font_doc_font_ascent,0,_bi_font_doc_font_charcount,_bi_font_doc_font_characters,p_theme->get_icon("DocFont","EditorIcons"));
- Ref<Font> doc_code_font = make_font(_bi_font_doc_code_font_height,_bi_font_doc_code_font_ascent,0,_bi_font_doc_code_font_charcount,_bi_font_doc_code_font_characters,p_theme->get_icon("DocCodeFont","EditorIcons"));
- Ref<Font> doc_title_font = make_font(_bi_font_doc_title_font_height,_bi_font_doc_title_font_ascent,0,_bi_font_doc_title_font_charcount,_bi_font_doc_title_font_characters,p_theme->get_icon("DocTitleFont","EditorIcons"));
- p_theme->set_font("doc","EditorFonts",doc_font);
- p_theme->set_font("doc_code","EditorFonts",doc_code_font);
- p_theme->set_font("doc_title","EditorFonts",doc_title_font);
-
-}
+#include "editor_fonts.h"
+#include "doc_font.h"
+#include "doc_title_font.h"
+#include "doc_code_font.h"
+
+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];
+
+ int chr=c[0];
+ Rect2 frect;
+ frect.pos.x=c[1];
+ frect.pos.y=c[2];
+ frect.size.x=c[3];
+ frect.size.y=c[4];
+ Point2 align( c[5], c[6]+p_valign);
+ int advance=c[7];
+
+
+ font->add_char( chr, 0, frect, align,advance );
+
+ }
+
+ font->set_height( p_height );
+ font->set_ascent( p_ascent );
+
+ return font;
+}
+
+
+void editor_register_fonts(Ref<Theme> p_theme) {
+
+
+ Ref<Font> doc_font = make_font(_bi_font_doc_font_height,_bi_font_doc_font_ascent,0,_bi_font_doc_font_charcount,_bi_font_doc_font_characters,p_theme->get_icon("DocFont","EditorIcons"));
+ Ref<Font> doc_code_font = make_font(_bi_font_doc_code_font_height,_bi_font_doc_code_font_ascent,0,_bi_font_doc_code_font_charcount,_bi_font_doc_code_font_characters,p_theme->get_icon("DocCodeFont","EditorIcons"));
+ Ref<Font> doc_title_font = make_font(_bi_font_doc_title_font_height,_bi_font_doc_title_font_ascent,0,_bi_font_doc_title_font_charcount,_bi_font_doc_title_font_characters,p_theme->get_icon("DocTitleFont","EditorIcons"));
+ p_theme->set_font("doc","EditorFonts",doc_font);
+ p_theme->set_font("doc_code","EditorFonts",doc_code_font);
+ p_theme->set_font("doc_title","EditorFonts",doc_title_font);
+
+}
diff --git a/tools/editor/editor_fonts.h b/tools/editor/editor_fonts.h
index a3973513b3..cc990a560c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,11 +26,11 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef EDITOR_FONTS_H
-#define EDITOR_FONTS_H
-
-#include "scene/resources/theme.h"
-
-void editor_register_fonts(Ref<Theme> p_theme);
-
-#endif
+#ifndef EDITOR_FONTS_H
+#define EDITOR_FONTS_H
+
+#include "scene/resources/theme.h"
+
+void editor_register_fonts(Ref<Theme> p_theme);
+
+#endif
diff --git a/tools/editor/editor_help.cpp b/tools/editor/editor_help.cpp
index b7e708e360..a5a3890129 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,14 +271,14 @@ 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();
}
void EditorHelpSearch::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
connect("confirmed",this,"_confirmed");
_update_search();
@@ -293,16 +301,16 @@ void EditorHelpSearch::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_text_changed"),&EditorHelpSearch::_text_changed);
ObjectTypeDB::bind_method(_MD("_confirmed"),&EditorHelpSearch::_confirmed);
ObjectTypeDB::bind_method(_MD("_sbox_input"),&EditorHelpSearch::_sbox_input);
- ObjectTypeDB::bind_method(_MD("_update_search"),&EditorHelpSearch::_sbox_input);
+ ObjectTypeDB::bind_method(_MD("_update_search"),&EditorHelpSearch::_update_search);
ADD_SIGNAL(MethodInfo("go_to_help"));
}
-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);
+ 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,17 +541,28 @@ void EditorHelp::_class_list_select(const String& p_select) {
void EditorHelp::_class_desc_select(const String& p_select) {
- if (p_select.begins_with("#")) {
- _goto_desc(p_select.substr(1,p_select.length()));
+
+// print_line("LINK: "+p_select);
+ if (p_select.begins_with("#")) {
+ //_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]);
+ }
+
}
@@ -450,67 +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)) {
- tree_item_map[p_class]->select(0);
- class_list->ensure_cursor_is_visible();
- }
+ //if (tree_item_map.has(p_class)) {
+ select_locked = true;
+ //}
+
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();
}
@@ -591,7 +705,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
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 +717,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,7 +736,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();
}
@@ -655,7 +771,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 +780,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 +815,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 +824,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 +854,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 +868,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 +884,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 +920,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 +958,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 +990,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 +1000,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 +1019,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 +1028,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,22 +1047,17 @@ 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;
return OK;
}
-void EditorHelp::_request_help(const String& p_string) {
+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 +1097,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 +1184,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,316 +1320,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;
- if (inherits.length()) {
+void EditorHelp::_update_doc() {
- 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)
- 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));
- edited_class->hide();
-
- 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);
- EmptyControl *ec = memnew( EmptyControl );
- ec->set_minsize(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 );
- pc->add_style_override("panel",get_stylebox("normal","TextEdit"));
- h_split->add_child(pc);
+ Panel *pc = memnew( Panel );
+ Ref<StyleBoxFlat> style( memnew( StyleBoxFlat ) );
+ 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"));
+ 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 1c2b704b98..04ac4d35ff 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 4cd08bba03..910febc895 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp
index 649db5fc45..cd455406b7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,6 +40,7 @@
#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"
String EditorImportPlugin::validate_source_path(const String& p_path) {
@@ -47,6 +48,7 @@ String EditorImportPlugin::validate_source_path(const String& p_path) {
String rp = Globals::get_singleton()->get_resource_path();
if (!rp.ends_with("/"))
rp+="/";
+
return rp.path_to_file(gp);
}
@@ -253,7 +255,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 {
@@ -268,13 +279,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 {
@@ -292,7 +299,11 @@ Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const
_add_filter_to_list(exported,"*");
} else {
_add_to_list(EditorFileSystem::get_singleton()->get_filesystem(),exported);
- _add_filter_to_list(exported,EditorImportExport::get_singleton()->get_export_custom_filter());
+ String cf = EditorImportExport::get_singleton()->get_export_custom_filter();
+ if (cf!="")
+ cf+=",";
+ cf+="*.flags";
+ _add_filter_to_list(exported,cf);
}
@@ -361,8 +372,12 @@ Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const
}
}
}
+ String cf = EditorImportExport::get_singleton()->get_export_custom_filter();
+ if (cf!="")
+ cf+=",";
+ cf+="*.flags";
+ _add_filter_to_list(exported,cf);
- _add_filter_to_list(exported,EditorImportExport::get_singleton()->get_export_custom_filter());
}
@@ -384,6 +399,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)!="";
+}
+
///////////////////////////////////////
@@ -439,8 +488,8 @@ bool EditorExportPlatformPC::_get(const StringName& p_name,Variant &r_ret) const
void EditorExportPlatformPC::_get_property_list( List<PropertyInfo> *p_list) const {
- p_list->push_back( PropertyInfo( Variant::STRING, "custom_binary/debug", PROPERTY_HINT_FILE,binary_extension));
- p_list->push_back( PropertyInfo( Variant::STRING, "custom_binary/release", PROPERTY_HINT_FILE,binary_extension));
+ 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::BOOL, "binary/64_bits"));
}
@@ -547,6 +596,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()) {
@@ -571,7 +621,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;
@@ -815,13 +865,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) );
@@ -896,6 +976,69 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
return OK;
}
+static int _get_pad(int p_alignment, int p_n) {
+
+ int rest = p_n % p_alignment;
+ int pad = 0;
+ if (rest > 0) {
+ pad = p_alignment - rest;
+ };
+
+ 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) {
@@ -922,11 +1065,19 @@ Error EditorExportPlatform::save_pack_file(void *p_userdata,const String& p_path
pd->ep->step("Storing File: "+p_path,2+p_file*100/p_total);
pd->count++;
pd->ftmp->store_buffer(p_data.ptr(),p_data.size());
+ if (pd->alignment > 1) {
+
+ int pad = _get_pad(pd->alignment, pd->ftmp->get_pos());
+ for (int i=0; i<pad; i++) {
+
+ pd->ftmp->store_8(0);
+ };
+ };
return OK;
}
-Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles) {
+Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles, int p_alignment) {
EditorProgress ep("savepack","Packing",102);
@@ -938,13 +1089,12 @@ Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles) {
dst->store_32(0); //pack version
dst->store_32(VERSION_MAJOR);
dst->store_32(VERSION_MINOR);
- dst->store_32(VERSION_REVISION);
+ dst->store_32(0); //hmph
for(int i=0;i<16;i++) {
//reserved
dst->store_32(0);
}
-
size_t fcountpos = dst->get_pos();
dst->store_32(0);
@@ -953,11 +1103,20 @@ Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles) {
pd.f=dst;
pd.ftmp=tmp;
pd.count=0;
+ pd.alignment = p_alignment;
Error err = export_project_files(save_pack_file,&pd,p_make_bundles);
memdelete(tmp);
if (err)
return err;
+ if (p_alignment > 1) {
+ int pad = _get_pad(p_alignment, dst->get_pos());
+ for (int i=0; i<pad; i++) {
+
+ dst->store_8(0);
+ };
+ };
+
size_t ofsplus = dst->get_pos();
//append file
@@ -994,7 +1153,7 @@ Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles) {
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) {
@@ -1006,19 +1165,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:debug_binary64;
- else
- exe_path+=custom_release_binary!=""?custom_release_binary:release_binary64;
- } else {
+ String exe_path="";
- if (p_debug)
- exe_path+=custom_debug_binary!=""?custom_debug_binary:debug_binary32;
- else
- exe_path+=custom_release_binary!=""?custom_release_binary: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);
@@ -1032,7 +1204,7 @@ Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug,
if (!dst) {
EditorNode::add_io_error("Can't copy executable file to:\n "+p_path);
- return ERR_FILE_CANT_READ;
+ return ERR_FILE_CANT_WRITE;
}
uint8_t buff[32768];
@@ -1061,7 +1233,7 @@ Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug,
if (!dst) {
EditorNode::add_io_error("Can't write data pack to:\n "+p_path);
- return ERR_FILE_CANT_READ;
+ return ERR_FILE_CANT_WRITE;
}
}
@@ -1082,32 +1254,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;
-
}
@@ -1133,10 +1315,36 @@ EditorImportExport* EditorImportExport::singleton=NULL;
void EditorImportExport::add_import_plugin(const Ref<EditorImportPlugin>& p_plugin) {
+ // Need to make sure the name is unique if we are going to lookup by it
+ ERR_FAIL_COND(by_idx.has(p_plugin->get_name()));
+
by_idx[ p_plugin->get_name() ]=plugins.size();
plugins.push_back(p_plugin);
}
+void EditorImportExport::remove_import_plugin(const Ref<EditorImportPlugin>& p_plugin) {
+
+ String plugin_name = p_plugin->get_name();
+
+ // Keep the indices the same
+ // Find the index of the target plugin
+ ERR_FAIL_COND(!by_idx.has(plugin_name));
+ int idx = by_idx[plugin_name];
+ int last_idx = plugins.size() - 1;
+
+ // Swap the last plugin and the target one
+ SWAP(plugins[idx], plugins[last_idx]);
+
+ // Update the index of the old last one
+ by_idx[plugins[idx]->get_name()] = idx;
+
+ // Remove the target plugin's by_idx entry
+ by_idx.erase(plugin_name);
+
+ // Erase the plugin
+ plugins.remove(last_idx);
+}
+
int EditorImportExport::get_import_plugin_count() const{
return plugins.size();
@@ -1269,12 +1477,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;
}
@@ -1345,12 +1553,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;
@@ -1399,6 +1607,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 );
@@ -1441,6 +1660,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")) {
@@ -1504,6 +1729,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"))
@@ -1553,6 +1780,17 @@ void EditorImportExport::load_config() {
}
}
+ if (cf->has_section("convert_samples")) {
+
+ 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");
+ }
+
+
+
}
@@ -1631,6 +1869,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;
}
@@ -1660,8 +1899,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");
}
@@ -1687,6 +1936,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);
@@ -1714,8 +1992,23 @@ 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;
+
+}
+
+
+
+EditorImportExport::~EditorImportExport() {
+
+
+
}
diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h
index 8305e3c88c..93086f7ad4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -83,8 +83,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 {
@@ -100,9 +103,11 @@ protected:
Vector<TempData> file_ofs;
EditorProgress *ep;
int count;
+ int alignment;
};
+ 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);
public:
@@ -118,10 +123,17 @@ 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);
+ Error save_pack(FileAccess *p_where, bool p_make_bundles=false, int p_alignment = 1);
virtual String get_name() const =0;
virtual ImageCompression get_image_compression() const=0;
virtual Ref<Texture> get_logo() const =0;
@@ -130,14 +142,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() {};
};
@@ -187,7 +199,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; }
@@ -225,6 +237,8 @@ public:
IMAGE_ACTION_NONE,
IMAGE_ACTION_COMPRESS_DISK,
IMAGE_ACTION_COMPRESS_RAM,
+ IMAGE_ACTION_KEEP //for group
+
};
enum ScriptAction {
@@ -233,6 +247,12 @@ public:
SCRIPT_ACTION_ENCRYPT
};
+ enum SampleAction {
+
+ SAMPLE_ACTION_NONE,
+ SAMPLE_ACTION_COMPRESS_RAM,
+ };
+
protected:
struct ImageGroup {
@@ -240,7 +260,7 @@ protected:
ImageAction action;
bool make_atlas;
float lossy_quality;
- int shrink;
+ float shrink;
};
Vector<Ref<EditorExportPlugin> > export_plugins;
@@ -248,7 +268,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;
@@ -262,6 +282,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();
@@ -270,6 +296,7 @@ public:
static EditorImportExport* get_singleton() { return singleton; }
void add_import_plugin(const Ref<EditorImportPlugin>& p_plugin);
+ void remove_import_plugin(const Ref<EditorImportPlugin>& p_plugin);
int get_import_plugin_count() const;
Ref<EditorImportPlugin> get_import_plugin(int p_idx) const;
Ref<EditorImportPlugin> get_import_plugin_by_name(const String& p_string) const;
@@ -297,8 +324,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;
@@ -313,8 +340,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;
@@ -330,10 +357,23 @@ 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();
EditorImportExport();
+ ~EditorImportExport();
};
VARIANT_ENUM_CAST(EditorImportExport::ImageAction);
diff --git a/tools/editor/editor_layout_dialog.cpp b/tools/editor/editor_layout_dialog.cpp
new file mode 100644
index 0000000000..e37f263c0c
--- /dev/null
+++ b/tools/editor/editor_layout_dialog.cpp
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* editor_node.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 "editor_layout_dialog.h"
+#include "object_type_db.h"
+
+void EditorLayoutDialog::clear_layout_name() {
+
+ layout_name->clear();
+}
+
+void EditorLayoutDialog::ok_pressed() {
+
+ if (layout_name->get_text()!="") {
+ emit_signal("layout_selected", layout_name->get_text());
+ }
+}
+
+void EditorLayoutDialog::_bind_methods() {
+
+ ADD_SIGNAL(MethodInfo("layout_selected",PropertyInfo( Variant::STRING,"layout_name")));
+}
+
+EditorLayoutDialog::EditorLayoutDialog()
+{
+
+ layout_name = memnew( LineEdit );
+ layout_name->set_margin(MARGIN_TOP,5);
+ layout_name->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,5);
+ layout_name->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,5);
+ add_child(layout_name);
+ move_child(layout_name, get_label()->get_index()+1);
+}
diff --git a/tools/editor/editor_layout_dialog.h b/tools/editor/editor_layout_dialog.h
new file mode 100644
index 0000000000..7e3b9e3d8a
--- /dev/null
+++ b/tools/editor/editor_layout_dialog.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* editor_layout_dialog.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 EDITOR_LAYOUT_DIALOG_H
+#define EDITOR_LAYOUT_DIALOG_H
+
+#include "scene/gui/dialogs.h"
+#include "scene/gui/line_edit.h"
+
+class EditorLayoutDialog : public ConfirmationDialog {
+
+ OBJ_TYPE( EditorLayoutDialog, ConfirmationDialog );
+
+ LineEdit *layout_name;
+
+protected:
+
+ static void _bind_methods();
+ virtual void ok_pressed();
+
+public:
+ void clear_layout_name();
+
+ EditorLayoutDialog();
+};
+
+#endif // EDITOR_LAYOUT_DIALOG_H
diff --git a/tools/editor/editor_log.cpp b/tools/editor/editor_log.cpp
index 5933b09173..264117eecd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -76,11 +76,12 @@ void EditorLog::_error_handler(void *p_self, const char*p_func, const char*p_fil
void EditorLog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ 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"));
}
@@ -104,6 +105,17 @@ void EditorLog::_close_request() {
}
+void EditorLog::_clear_request() {
+
+ log->clear();
+
+}
+
+void EditorLog::clear() {
+ _clear_request();
+}
+
+
void EditorLog::add_message(const String& p_msg,bool p_error) {
@@ -114,6 +126,7 @@ void EditorLog::add_message(const String& p_msg,bool p_error) {
log->push_color(get_color("fg_error","Editor"));
} else {
button->set_icon(Ref<Texture>());
+
}
@@ -143,17 +156,20 @@ void EditorLog::_dragged(const Point2& p_ofs) {
*/
-ToolButton *EditorLog::get_button() {
+Button *EditorLog::get_button() {
return button;
}
void EditorLog::_flip_request() {
- if (is_visible())
+ if (is_visible()) {
hide();
- else
+ button->show();
+ } else {
show();
+ button->hide();
+ }
}
void EditorLog::_undo_redo_cbk(void *p_self,const String& p_name) {
@@ -167,9 +183,12 @@ 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() {
@@ -186,7 +205,7 @@ EditorLog::EditorLog() {
hb->add_child(title);
- button = memnew( ToolButton );
+ button = memnew( Button );
button->set_text_align(Button::ALIGN_LEFT);
button->connect("pressed",this,"_flip_request");
button->set_focus_mode(FOCUS_NONE);
@@ -198,14 +217,19 @@ EditorLog::EditorLog() {
//pd->connect("dragged",this,"_dragged");
//pd->set_default_cursor_shape(Control::CURSOR_MOVE);
+ clearbutton = memnew( Button );
+ hb->add_child(clearbutton);
+ clearbutton->set_text("Clear");
+ clearbutton->connect("pressed", this,"_clear_request");
+
tb = memnew( TextureButton );
hb->add_child(tb);
tb->connect("pressed",this,"_close_request");
- ec = memnew( EmptyControl);
+ ec = memnew( Control);
vb->add_child(ec);
- ec->set_minsize(Size2(0,100));
+ ec->set_custom_minimum_size(Size2(0,100));
ec->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -216,8 +240,10 @@ EditorLog::EditorLog() {
log = memnew( RichTextLabel );
log->set_scroll_follow(true);
+ log->set_selection_enabled(true);
+ log->set_focus_mode(FOCUS_CLICK);
pc->add_child(log);
- add_message(VERSION_FULL_NAME" (c) 2008-2014 Juan Linietsky, Ariel Manzur.");
+ add_message(VERSION_FULL_NAME" (c) 2008-2015 Juan Linietsky, Ariel Manzur.");
//log->add_text("Initialization Complete.\n"); //because it looks cool.
add_style_override("panel",get_stylebox("panelf","Panel"));
@@ -239,8 +265,8 @@ void EditorLog::deinit() {
}
+
EditorLog::~EditorLog() {
}
-
diff --git a/tools/editor/editor_log.h b/tools/editor/editor_log.h
index b6cd951287..93044f9a2d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,7 +33,7 @@
#include "scene/gui/label.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/texture_button.h"
-#include "scene/gui/empty_control.h"
+//#include "scene/gui/empty_control.h"
#include "scene/gui/box_container.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/texture_frame.h"
@@ -44,13 +44,14 @@ class EditorLog : public PanelContainer {
OBJ_TYPE( EditorLog, PanelContainer );
- ToolButton *button;
+ Button *button;
+ Button *clearbutton;
Label *title;
RichTextLabel *log;
TextureButton *tb;
HBoxContainer *title_hb;
// PaneDrag *pd;
- EmptyControl *ec;
+ Control *ec;
static void _error_handler(void *p_self, const char*p_func, const char*p_file,int p_line, const char*p_error,const char*p_errorexp,ErrorHandlerType p_type);
@@ -58,10 +59,10 @@ 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 +73,8 @@ public:
void add_message(const String& p_msg, bool p_error=false);
void deinit();
- ToolButton *get_button();
+ Button *get_button();
+ void clear();
EditorLog();
~EditorLog();
};
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index a6243df69d..35404b0bba 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,14 +33,13 @@
#include "editor_fonts.h"
#include "editor_help.h"
-#include "scene/io/scene_saver.h"
-#include "scene/io/scene_loader.h"
#include "core/io/resource_saver.h"
#include "core/io/resource_loader.h"
#include "servers/physics_2d_server.h"
#include "scene/resources/packed_scene.h"
#include "editor_settings.h"
#include "io_plugins/editor_import_collada.h"
+#include "io_plugins/editor_scene_importer_fbxconv.h"
#include "globals.h"
#include <stdio.h>
#include "object_type_db.h"
@@ -55,10 +54,11 @@
#include "register_exporters.h"
#include "bind/core_bind.h"
#include "io/zip_io.h"
-
+#include "io/config_file.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"
@@ -70,14 +70,17 @@
#include "plugins/item_list_editor_plugin.h"
#include "plugins/stream_editor_plugin.h"
#include "plugins/multimesh_editor_plugin.h"
+#include "plugins/mesh_editor_plugin.h"
#include "plugins/theme_editor_plugin.h"
#include "plugins/tile_map_editor_plugin.h"
#include "plugins/cube_grid_theme_editor_plugin.h"
#include "plugins/shader_editor_plugin.h"
+#include "plugins/shader_graph_editor_plugin.h"
#include "plugins/path_editor_plugin.h"
#include "plugins/rich_text_editor_plugin.h"
#include "plugins/collision_polygon_editor_plugin.h"
+#include "plugins/collision_polygon_2d_editor_plugin.h"
#include "plugins/script_editor_plugin.h"
#include "plugins/path_2d_editor_plugin.h"
#include "plugins/particles_editor_plugin.h"
@@ -87,6 +90,11 @@
#include "plugins/animation_player_editor_plugin.h"
#include "plugins/baked_light_editor_plugin.h"
#include "plugins/polygon_2d_editor_plugin.h"
+#include "plugins/navigation_polygon_editor_plugin.h"
+#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"
@@ -94,16 +102,55 @@
#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?"(*)":""),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());
+
+}
+
void EditorNode::_update_title() {
String appname = Globals::get_singleton()->get("application/name");
String title = appname.empty()?String(VERSION_FULL_NAME):String(_MKSTR(VERSION_NAME) + String(" - ") + appname);
- String edited = edited_scene?edited_scene->get_filename():String();
+ String edited = editor_data.get_edited_scene_root()?editor_data.get_edited_scene_root()->get_filename():String();
if (!edited.empty())
title+=" - " + String(edited.get_file());
if (unsaved_cache)
@@ -119,13 +166,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;
@@ -139,7 +195,8 @@ void EditorNode::_unhandled_input(const InputEvent& p_event) {
void EditorNode::_notification(int p_what) {
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
editor_data.save_editor_external_data();
log->deinit(); // do not get messages anymore
@@ -167,6 +224,11 @@ void EditorNode::_notification(int p_what) {
_update_title();
}
+ if (last_checked_version!=editor_data.get_undo_redo().get_version()) {
+ _update_scene_tabs();
+ last_checked_version=editor_data.get_undo_redo().get_version();
+ }
+
//get_root_node()->set_rect(viewport->get_global_rect());
//update the circle
@@ -180,7 +242,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"));
@@ -212,44 +274,35 @@ void EditorNode::_notification(int p_what) {
}
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
//MessageQueue::get_singleton()->push_call(this,"_get_scene_metadata");
- get_scene()->set_editor_hint(true);
- get_scene()->get_root()->set_as_audio_listener(false);
- get_scene()->get_root()->set_as_audio_listener_2d(false);
- get_scene()->set_auto_accept_quit(false);
+ get_tree()->set_editor_hint(true);
+ get_tree()->get_root()->set_as_audio_listener(false);
+ get_tree()->get_root()->set_as_audio_listener_2d(false);
+ get_tree()->set_auto_accept_quit(false);
//VisualServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport(),false);
//import_monitor->scan_changes();
}
+
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+
+ editor_data.clear_edited_scenes();
+
+ }
if (p_what==NOTIFICATION_READY) {
VisualServer::get_singleton()->viewport_set_hide_scenario(get_scene_root()->get_viewport(),true);
VisualServer::get_singleton()->viewport_set_hide_canvas(get_scene_root()->get_viewport(),true);
- _editor_select(1);
-
- if (defer_load_scene!="") {
+ VisualServer::get_singleton()->viewport_set_disable_environment(get_viewport()->get_viewport_rid(),true);
-#ifdef OLD_SCENE_FORMAT_ENABLED
+ _editor_select(EDITOR_3D);
- if (convert_old) {
- get_scene()->quit();
- Node *scn = SceneLoader::load(defer_load_scene,true);
- ERR_EXPLAIN("Couldn't load scene: "+defer_load_scene);
- ERR_FAIL_COND(!scn);
- Ref<PackedScene> sdata = memnew( PackedScene );
- Error err = sdata->pack(scn);
- ERR_EXPLAIN("Couldn't repack scene: "+defer_load_scene);
- ERR_FAIL_COND(err!=OK);
- err = ResourceSaver::save(defer_load_scene,sdata);
- ERR_EXPLAIN("Couldn't resave scene: "+defer_load_scene);
- ERR_FAIL_COND(err!=OK);
-
- return;
- }
+ if (defer_load_scene!="") {
-#endif
load_scene(defer_load_scene);
defer_load_scene="";
}
@@ -260,7 +313,7 @@ void EditorNode::_notification(int p_what) {
if (ok!=OK)
OS::get_singleton()->set_exit_code(255);
defer_translatable="";
- get_scene()->quit();
+ get_tree()->quit();
}
/*
@@ -331,6 +384,11 @@ void EditorNode::_fs_changed() {
E->get()->invalidate();
}
+
+ for(Set<EditorFileDialog*>::Element *E=editor_file_dialogs.front();E;E=E->next()) {
+
+ E->get()->invalidate();
+ }
}
void EditorNode::_sources_changed(bool p_exist) {
@@ -353,6 +411,19 @@ void EditorNode::_vp_resized() {
}
+void EditorNode::_rebuild_import_menu()
+{
+ PopupMenu* p = import_menu->get_popup();
+ p->clear();
+ p->add_item("Sub-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);
+ }
+ p->add_separator();
+ p->add_item("Re-Import..", SETTINGS_IMPORT);
+}
+
void EditorNode::_node_renamed() {
if (property_editor)
@@ -384,7 +455,7 @@ void EditorNode::edit_node(Node *p_node) {
void EditorNode::open_resource(const String& p_type) {
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type(p_type,&extensions);
@@ -401,19 +472,75 @@ 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);
+
+ 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) {
- 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 (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());
-}
+ List<String> extensions;
+ Ref<PackedScene> sd = memnew( PackedScene );
+ 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..");
+}
void EditorNode::_menu_option(int p_option) {
@@ -452,14 +579,14 @@ void EditorNode::_dialog_display_file_error(String p_file,Error p_error) {
}break;
}
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
}
}
void EditorNode::_get_scene_metadata() {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (!scene)
return;
@@ -486,7 +613,7 @@ void EditorNode::_get_scene_metadata() {
void EditorNode::_set_scene_metadata() {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (!scene)
return;
@@ -608,7 +735,42 @@ static Error _fix_imported_scene_paths(Node* node, Node* root, String save_path)
};
-bool EditorNode::_find_and_save_edited_subresources(Object *obj,Set<RES>& processed,int32_t flags) {
+bool EditorNode::_find_and_save_resource(RES res,Map<RES,bool>& processed,int32_t flags) {
+
+ if (res.is_null())
+ return false;
+
+ if (processed.has(res)) {
+
+ return processed[res];
+ }
+
+
+ bool changed = res->is_edited();
+ res->set_edited(false);
+
+ bool subchanged = _find_and_save_edited_subresources(res.ptr(),processed,flags);
+
+// print_line("checking if edited: "+res->get_type()+" :: "+res->get_name()+" :: "+res->get_path()+" :: "+itos(changed)+" :: SR "+itos(subchanged));
+
+ if (res->get_path().is_resource_file()) {
+ if (changed || subchanged) {
+ //save
+ print_line("Also saving modified external resource: "+res->get_path());
+ Error err = ResourceSaver::save(res->get_path(),res,flags);
+
+ }
+ processed[res]=false; //because it's a file
+ return false;
+ } else {
+
+
+ processed[res]=changed;
+ return changed;
+ }
+}
+
+bool EditorNode::_find_and_save_edited_subresources(Object *obj,Map<RES,bool>& processed,int32_t flags) {
bool ret_changed=false;
List<PropertyInfo> pi;
@@ -618,57 +780,45 @@ bool EditorNode::_find_and_save_edited_subresources(Object *obj,Set<RES>& proces
if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
continue;
+
+
switch(E->get().type) {
case Variant::OBJECT: {
RES res = obj->get(E->get().name);
- if (res.is_null() || processed.has(res))
- break;
-
- processed.insert(res);
-
- bool changed = res->is_edited();
- res->set_edited(false);
-
- bool subchanged = _find_and_save_edited_subresources(res.ptr(),processed,flags);
-
- if (res->get_path().is_resource_file()) {
- if (changed || subchanged) {
- //save
- print_line("Also saving modified external resource: "+res->get_path());
- Error err = ResourceSaver::save(res->get_path(),res,flags);
-
- }
- } else {
-
+ if (_find_and_save_resource(res,processed,flags))
ret_changed=true;
- }
-
} break;
case Variant::ARRAY: {
- /*Array varray=p_variant;
+ Array varray= obj->get(E->get().name);
int len=varray.size();
for(int i=0;i<len;i++) {
Variant v=varray.get(i);
- _find_resources(v);
- }*/
+ RES res=v;
+ if (_find_and_save_resource(res,processed,flags))
+ ret_changed=true;
+
+ //_find_resources(v);
+ }
} break;
case Variant::DICTIONARY: {
- /*
- Dictionary d=p_variant;
+
+ Dictionary d=obj->get(E->get().name);;
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);
- } */
+ RES res=v;
+ if (_find_and_save_resource(res,processed,flags))
+ ret_changed=true;
+ }
} break;
default: {}
}
@@ -679,23 +829,113 @@ bool EditorNode::_find_and_save_edited_subresources(Object *obj,Set<RES>& proces
}
-void EditorNode::_save_edited_subresources(Node* scene,Set<RES>& processed,int32_t flags) {
+void EditorNode::_save_edited_subresources(Node* scene,Map<RES,bool>& processed,int32_t flags) {
_find_and_save_edited_subresources(scene,processed,flags);
for(int i=0;i<scene->get_child_count();i++) {
Node *n = scene->get_child(i);
- if (n->get_owner()!=edited_scene)
+ if (n->get_owner()!=editor_data.get_edited_scene_root())
continue;
_save_edited_subresources(n,processed,flags);
}
}
+void EditorNode::_find_node_types(Node* p_node, int&count_2d, int&count_3d) {
+
+ if (p_node->is_type("Viewport") || (p_node!=editor_data.get_edited_scene_root() && p_node->get_owner()!=editor_data.get_edited_scene_root()))
+ return;
+
+ if (p_node->is_type("CanvasItem"))
+ count_2d++;
+ else if (p_node->is_type("Spatial"))
+ count_3d++;
+
+ for(int i=0;i<p_node->get_child_count();i++)
+ _find_node_types(p_node->get_child(i),count_2d,count_3d);
+
+}
+
+
+void EditorNode::_save_scene_with_preview(String p_file) {
+
+ int c2d=0;
+ int c3d=0;
+
+ EditorProgress save("save","Saving Scene",4);
+ save.step("Analyzing",0);
+ _find_node_types(editor_data.get_edited_scene_root(),c2d,c3d);
+
+ RID viewport;
+ bool is2d;
+ if (c3d<c2d) {
+ viewport=scene_root->get_viewport();
+ is2d=true;
+ } else {
+ viewport=SpatialEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_viewport();
+ is2d=false;
+
+ }
+ save.step("Creating Thumbnail",1);
+ //current view?
+ int screen =-1;
+ for(int i=0;i<editor_table.size();i++) {
+ if (editor_plugin_screen==editor_table[i]) {
+ screen=i;
+ break;
+ }
+ }
+
+ _editor_select(is2d?EDITOR_2D:EDITOR_3D);
+
+ VS::get_singleton()->viewport_queue_screen_capture(viewport);
+ save.step("Creating Thumbnail",2);
+ save.step("Creating Thumbnail",3);
+ Image img = VS::get_singleton()->viewport_get_screen_capture(viewport);
+ int preview_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");;
+ int width,height;
+ if (img.get_width() > preview_size && img.get_width() >= img.get_height()) {
+
+ width=preview_size;
+ height = img.get_height() * preview_size / img.get_width();
+ } else if (img.get_height() > preview_size && img.get_height() >= img.get_width()) {
+
+ height=preview_size;
+ width = img.get_width() * preview_size / img.get_height();
+ } else {
+
+ width=img.get_width();
+ height=img.get_height();
+ }
+
+ img.convert(Image::FORMAT_RGB);
+ img.resize(width,height);
+
+ String pfile = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/last_scene_preview.png");
+ img.save_png(pfile);
+ Vector<uint8_t> imgdata = FileAccess::get_file_as_array(pfile);
+
+ //print_line("img data is "+itos(imgdata.size()));
+
+ if (editor_data.get_edited_scene_import_metadata().is_null())
+ editor_data.set_edited_scene_import_metadata(Ref<ResourceImportMetadata>( memnew( ResourceImportMetadata ) ) );
+ editor_data.get_edited_scene_import_metadata()->set_option("thumbnail",imgdata);
+
+ //tamanio tel thumbnail
+ if (screen!=-1) {
+ _editor_select(screen);
+ }
+ save.step("Saving Scene",4);
+ _save_scene(p_file);
+
+}
+
+
void EditorNode::_save_scene(String p_file) {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
@@ -703,7 +943,7 @@ void EditorNode::_save_scene(String p_file) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation can't be done without a tree root.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
@@ -725,11 +965,11 @@ void EditorNode::_save_scene(String p_file) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Couldn't save scene. Likely dependencies (instances) couldn't be satisfied.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
- sdata->set_import_metadata(scene_import_metadata);
+ sdata->set_import_metadata(editor_data.get_edited_scene_import_metadata());
int flg=0;
if (EditorSettings::get_singleton()->get("on_save/compress_binary_resources"))
flg|=ResourceSaver::FLAG_COMPRESS;
@@ -739,14 +979,15 @@ void EditorNode::_save_scene(String p_file) {
err = ResourceSaver::save(p_file,sdata,flg);
- Set<RES> processed;
+ Map<RES,bool> processed;
_save_edited_subresources(scene,processed,flg);
editor_data.save_editor_external_data();
if (err==OK) {
scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
//EditorFileSystem::get_singleton()->update_file(p_file,sdata->get_type());
- saved_version=editor_data.get_undo_redo().get_version();
+ set_current_version(editor_data.get_undo_redo().get_version());
_update_title();
+ _update_scene_tabs();
} else {
_dialog_display_file_error(p_file,err);
@@ -878,71 +1119,17 @@ void EditorNode::_dialog_action(String p_file) {
push_item(res.operator->() );
- } break;
- case FILE_OPEN_SCENE: {
+ } break;
+ case FILE_NEW_INHERITED_SCENE: {
- load_scene(p_file);
+ load_scene(p_file,false,true);
} break;
-#ifdef OLD_SCENE_FORMAT_ENABLED
- case FILE_OPEN_OLD_SCENE: {
-
- String lpath = Globals::get_singleton()->localize_path(p_file);
- if (!lpath.begins_with("res://")) {
-
- current_option=-1;
- //accept->get_cancel()->hide();
- accept->get_ok()->set_text("Ugh");
- accept->set_text("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path.");
- accept->popup_centered(Size2(300,120));
- return ;
- }
-
- Node*new_scene=SceneLoader::load(lpath,true);
-
- if (!new_scene) {
-
- current_option=-1;
- //accept->get_cancel()->hide();
- accept->get_ok()->set_text("Ugh");
- accept->set_text("Error loading scene.");
- accept->popup_centered(Size2(300,70));;
- return ;
- }
-
- Node *old_scene = edited_scene;
- _hide_top_editors();
- set_edited_scene(NULL);
- editor_data.clear_editor_states();
- if (old_scene) {
- memdelete(old_scene);
- }
-
- set_edited_scene(new_scene);
- scene_tree_dock->set_selected(new_scene);
- _get_scene_metadata();
-
- editor_data.get_undo_redo().clear_history();
- saved_version=editor_data.get_undo_redo().get_version();
- _update_title();
-
- _add_to_recent_scenes(lpath);
-
- if (new_scene->has_meta("__editor_plugin_screen__")) {
-
- String editor = new_scene->get_meta("__editor_plugin_screen__");
- for(int i=0;i<editor_table.size();i++) {
-
- if (editor_table[i]->get_name()==editor) {
- _editor_select(i);
- break;
- }
- }
- }
+ case FILE_OPEN_SCENE: {
+ load_scene(p_file);
} break;
-#endif
case FILE_SAVE_OPTIMIZED: {
@@ -985,14 +1172,14 @@ void EditorNode::_dialog_action(String p_file) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation requieres a single selected node.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
Node *base = selection.front()->get();
Map<Node*,Node*> reown;
- reown[get_edited_scene()]=base;
+ reown[editor_data.get_edited_scene_root()]=base;
Node *copy = base->duplicate_and_reown(reown);
if (copy) {
@@ -1007,7 +1194,7 @@ void EditorNode::_dialog_action(String p_file) {
//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(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
@@ -1025,7 +1212,7 @@ void EditorNode::_dialog_action(String p_file) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Error saving scene.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
//EditorFileSystem::get_singleton()->update_file(p_file,sdata->get_type());
@@ -1036,7 +1223,7 @@ void EditorNode::_dialog_action(String p_file) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Error duplicating scene to save it.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
@@ -1050,10 +1237,22 @@ void EditorNode::_dialog_action(String p_file) {
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
- _save_scene(p_file);
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
+
}
} break;
+
+ case FILE_SAVE_AND_RUN: {
+ if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
+
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
+ _run(false);
+ }
+ } break;
+
case FILE_EXPORT_MESH_LIBRARY: {
Ref<MeshLibrary> ml;
@@ -1065,7 +1264,7 @@ void EditorNode::_dialog_action(String p_file) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Can't load MeshLibrary for merging!.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
@@ -1075,14 +1274,14 @@ void EditorNode::_dialog_action(String p_file) {
ml = Ref<MeshLibrary>( memnew( MeshLibrary ));
}
- MeshLibraryEditor::update_library_file(edited_scene,ml,true);
+ MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(),ml,true);
Error err = ResourceSaver::save(p_file,ml);
if (err) {
accept->get_ok()->set_text("I see..");
accept->set_text("Error saving MeshLibrary!.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
@@ -1099,7 +1298,7 @@ void EditorNode::_dialog_action(String p_file) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Can't load TileSet for merging!.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
@@ -1109,14 +1308,14 @@ void EditorNode::_dialog_action(String p_file) {
ml = Ref<TileSet>( memnew( TileSet ));
}
- TileSetEditor::update_library_file(edited_scene,ml,true);
+ TileSetEditor::update_library_file(editor_data.get_edited_scene_root(),ml,true);
Error err = ResourceSaver::save(p_file,ml);
if (err) {
accept->get_ok()->set_text("I see..");
accept->set_text("Error saving TileSet!.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
} break;
@@ -1133,7 +1332,7 @@ void EditorNode::_dialog_action(String p_file) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Can't open export templates zip.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
@@ -1196,13 +1395,89 @@ 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;
+
+ if (p_file=="Default") {
+ confirm_error->set_text("Cannot overwrite default layout!");
+ confirm_error->popup_centered_minsize();
+ return;
+ }
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+ if (err!=OK && err!=ERR_FILE_NOT_FOUND) {
+ return; //no config
+ }
+
+ _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();
+
+ } break;
+ case SETTINGS_LAYOUT_DELETE: {
+
+ if (p_file.empty())
+ return;
+
+ if (p_file=="Default") {
+ confirm_error->set_text("Cannot delete default layout!");
+ confirm_error->popup_centered_minsize();
+ return;
+ }
+
+ 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
+ }
+
+ if (!config->has_section(p_file)) {
+ confirm_error->set_text("Layout name not found!");
+ confirm_error->popup_centered_minsize();
+ 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();
+
+ } break;
default: { //save scene?
-
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
- _save_scene(p_file);
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
}
} break;
@@ -1233,6 +1508,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())
@@ -1249,15 +1585,15 @@ void EditorNode::_property_editor_back() {
void EditorNode::_imported(Node *p_node) {
- Node *scene = edited_scene;
- set_edited_scene(p_node);
-
+ Node *scene = editor_data.get_edited_scene_root();
+// add_edited_scene(p_node);
+/*
if (scene) {
String path = scene->get_filename();
p_node->set_filename(path);
memdelete(scene);
}
-
+*/
}
@@ -1277,6 +1613,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();
@@ -1286,12 +1625,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>();
@@ -1300,16 +1646,15 @@ 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);
- ERR_FAIL_COND(!current_node->is_inside_scene());
+ ERR_FAIL_COND(!current_node->is_inside_tree());
@@ -1318,7 +1663,13 @@ void EditorNode::_edit_current() {
scene_tree_dock->set_selected(current_node);
object_menu->get_popup()->clear();
- top_pallete->set_current_tab(0);
+ //top_pallete->set_current_tab(0);
+
+ } else {
+
+ property_editor->edit( current_obj );
+ //scene_tree_dock->set_selected(current_node);
+ //object_menu->get_popup()->clear();
}
@@ -1332,17 +1683,20 @@ void EditorNode::_edit_current() {
if (main_plugin!=editor_plugin_screen) {
// update screen main_plugin
- if (editor_plugin_screen)
- editor_plugin_screen->make_visible(false);
- editor_plugin_screen=main_plugin;
- editor_plugin_screen->edit(current_obj);
- editor_plugin_screen->make_visible(true);
+ if (!changing_scene) {
- for(int i=0;i<editor_table.size();i++) {
- if (editor_table[i]==main_plugin) {
- main_editor_tabs->set_current_tab(i);
- break;
+ if (editor_plugin_screen)
+ editor_plugin_screen->make_visible(false);
+ editor_plugin_screen=main_plugin;
+ editor_plugin_screen->edit(current_obj);
+
+ editor_plugin_screen->make_visible(true);
+
+
+ for(int i=0;i<editor_table.size();i++) {
+
+ main_editor_buttons[i]->set_pressed(editor_table[i]==main_plugin);
}
}
@@ -1387,6 +1741,14 @@ 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("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;
current_obj->get_method_list(&methods);
@@ -1418,6 +1780,20 @@ void EditorNode::_edit_current() {
_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) {
@@ -1440,8 +1816,10 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
}
play_button->set_pressed(false);
- pause_button->set_pressed(false);
+ play_button->set_icon(gui_base->get_icon("Play","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;
@@ -1449,29 +1827,25 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
- if (p_current || (edited_scene && p_custom==edited_scene->get_filename())) {
+ if (p_current || (editor_data.get_edited_scene_root() && p_custom==editor_data.get_edited_scene_root()->get_filename())) {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
-
current_option=-1;
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("No scene to run exists.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
if (scene->get_filename()=="") {
-
-
current_option=-1;
//accept->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("Scene has never been saved. Save before running!");
- accept->popup_centered(Size2(300,70));;
+ /**/
+ _menu_option_confirm(FILE_SAVE_BEFORE_RUN, false);
return;
}
@@ -1506,7 +1880,7 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("No main scene has ever been defined.\nSelect one from \"Project Settings\" under the 'application' category.");
- accept->popup_centered(Size2(300,100));;
+ accept->popup_centered_minsize();
return;
}
@@ -1517,7 +1891,7 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
if (unsaved_cache) {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (scene) { //only autosave if there is a scene obviously
@@ -1527,17 +1901,22 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Current scene was never saved, please save scene before running.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
- _save_scene(scene->get_filename());
+ //_save_scene(scene->get_filename());
+ _save_scene_with_preview(scene->get_filename());
}
}
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);
@@ -1550,7 +1929,7 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Could not start subprocess!");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return;
}
@@ -1558,8 +1937,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;
@@ -1568,8 +1949,8 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
void EditorNode::_cleanup_scene() {
-
- Node *scene = edited_scene;
+#if 0
+ Node *scene = editor_data.get_edited_scene_root();
editor_selection->clear();
editor_data.clear_editor_states();
editor_history.clear();
@@ -1578,7 +1959,7 @@ void EditorNode::_cleanup_scene() {
property_editor->edit(NULL);
resources_dock->cleanup();
scene_import_metadata.unref();
- set_edited_scene(NULL);
+ //set_edited_scene(NULL);
if (scene) {
if (scene->get_filename()!="") {
previous_scenes.push_back(scene->get_filename());
@@ -1604,35 +1985,43 @@ void EditorNode::_cleanup_scene() {
}
_update_title();
-
+#endif
}
void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
- current_option=(MenuOptions)p_option;
+ //print_line("option "+itos(p_option)+" confirm "+itos(p_confirmed));
+ if (!p_confirmed) //this may be a hack..
+ current_option=(MenuOptions)p_option;
switch( p_option ) {
case FILE_NEW_SCENE: {
+ /*
if (!p_confirmed) {
confirmation->get_ok()->set_text("Yes");
//confirmation->get_cancel()->show();
confirmation->set_text("Start a New Scene? (Current will be lost)");
- confirmation->popup_centered(Size2(300,70));
+ confirmation->popup_centered_minsize();
break;
- }
+ }*/
+
+ int idx = editor_data.add_edited_scene(-1);
+ _scene_tab_changed(idx);
+ editor_data.clear_editor_states();
- _cleanup_scene();
+ //_cleanup_scene();
} break;
+ case FILE_NEW_INHERITED_SCENE:
case FILE_OPEN_SCENE: {
//print_tree();
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
//not for now?
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions);
@@ -1644,11 +2033,11 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//file->set_current_path(current_path);
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
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;
@@ -1665,6 +2054,13 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
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();
@@ -1677,42 +2073,41 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
open_request(previous_scenes.back()->get());
} break;
-#ifdef OLD_SCENE_FORMAT_ENABLED
- case FILE_OPEN_OLD_SCENE: {
+ case FILE_CLOSE: {
- //print_tree();
- file->set_mode(FileDialog::MODE_OPEN_FILE);
- //not for now?
- file->clear_filters();
- file->add_filter("*.xml");
+ if (!p_confirmed) {
+ confirmation->get_ok()->set_text("Yes");
+ //confirmation->get_cancel()->show();
+ confirmation->set_text("Close scene? (Unsaved changes will be lost)");
+ confirmation->popup_centered_minsize();
+ break;
+ }
+ _remove_edited_scene();
- //file->set_current_path(current_path);
- Node *scene = edited_scene;
- if (scene) {
- file->set_current_path(scene->get_filename());
- };
- file->set_title("Open Scene");
- file->popup_centered_ratio();
} break;
-
-#endif
+ case SCENE_TAB_CLOSE: {
+ _remove_scene(tab_closing);
+ _update_scene_tabs();
+ current_option = -1;
+ } break;
case FILE_SAVE_SCENE: {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (scene && scene->get_filename()!="") {
- _save_scene(scene->get_filename());
+ //_save_scene(scene->get_filename());
+ _save_scene_with_preview(scene->get_filename());
return;
};
// fallthrough to save_as
};
case FILE_SAVE_AS_SCENE: {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
@@ -1720,11 +2115,11 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation can't be done without a tree root.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
bool relpaths = (scene->has_meta("__editor_relpaths__") && scene->get_meta("__editor_relpaths__").operator bool());
@@ -1760,9 +2155,21 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
} break;
+ case FILE_SAVE_BEFORE_RUN: {
+ if (!p_confirmed) {
+ accept->get_ok()->set_text("Yes");
+ accept->set_text("This scene has never been saved. Save before running?");
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ _menu_option(FILE_SAVE_AS_SCENE);
+ _menu_option_confirm(FILE_SAVE_AND_RUN, true);
+ } break;
+
case FILE_DUMP_STRINGS: {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
@@ -1770,7 +2177,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation can't be done without a tree root.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
@@ -1788,13 +2195,15 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("Please save the scene first.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
bool relpaths = (scene->has_meta("__editor_relpaths__") && scene->get_meta("__editor_relpaths__").operator bool());
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+
file->set_current_path(cpath);
file->set_title("Save Translatable Strings");
file->popup_centered_ratio();
@@ -1804,7 +2213,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
case FILE_SAVE_SUBSCENE: {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
@@ -1812,7 +2221,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//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(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
@@ -1825,24 +2234,24 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation requieres a single selected node.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
Node *tocopy = selection.front()->get();
- if (tocopy!=edited_scene && tocopy->get_filename()!="") {
+ 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(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
List<String> extensions;
Ref<PackedScene> sd = memnew( PackedScene );
@@ -1865,7 +2274,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
file->set_title("Save Sub-Scene As..");
} break;
case FILE_SAVE_OPTIMIZED: {
- Node *scene = edited_scene;
+ Node *scene = editor_data.get_edited_scene_root();
#if 0
if (!scene) {
@@ -1927,13 +2336,13 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
case FILE_EXPORT_MESH_LIBRARY: {
- if (!edited_scene) {
+ if (!editor_data.get_edited_scene_root()) {
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(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
@@ -1972,13 +2381,13 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//import_subscene->popup_centered_ratio();
- if (!edited_scene) {
+ if (!editor_data.get_edited_scene_root()) {
current_option=-1;
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation can't be done without a selected node.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
@@ -1988,16 +2397,19 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
case FILE_QUIT: {
+
if (!p_confirmed) {
+
confirmation->get_ok()->set_text("Quit");
//confirmation->get_cancel()->show();
confirmation->set_text("Exit the Editor?");
- confirmation->popup_centered(Size2(300,70));
+ confirmation->popup_centered(Size2(180,70));
break;
}
+
_menu_option_confirm(RUN_STOP,true);
- get_scene()->quit();
+ get_tree()->quit();
} break;
case FILE_EXTERNAL_OPEN_SCENE: {
@@ -2007,7 +2419,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
confirmation->get_ok()->set_text("Open");
//confirmation->get_cancel()->show();
confirmation->set_text("Current scene not saved. Open anyway?");
- confirmation->popup_centered(Size2(300,70));
+ confirmation->popup_centered_minsize();
break;
}
@@ -2043,6 +2455,29 @@ 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: {
+
+ Node *scene = get_edited_scene();
+
+ if (!scene)
+ break;
+
+ if (unsaved_cache && !p_confirmed) {
+ confirmation->get_ok()->set_text("Revert");
+ confirmation->set_text("This action cannot be undone. Revert anyway?");
+ confirmation->popup_centered_minsize();
+ break;
+ }
+
+ Error err = load_scene(scene->get_filename());
+
+ } break;
+
#if 0
case NODE_EXTERNAL_INSTANCE: {
@@ -2097,11 +2532,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());
}
@@ -2120,6 +2618,47 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
editor_data.paste_object_params(current);
editor_data.get_undo_redo().clear_history();
} break;
+ case OBJECT_UNIQUE_RESOURCES: {
+
+ editor_data.apply_changes_in_editors();;
+ if (current) {
+ List<PropertyInfo> props;
+ current->get_property_list(&props);
+ Map<RES,RES> duplicates;
+ for (List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
+
+ if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
+ continue;
+
+ Variant v = current->get(E->get().name);
+ if (v.is_ref()) {
+ REF ref = v;
+ if (ref.is_valid()) {
+
+ RES res = ref;
+ if (res.is_valid()) {
+
+ if (!duplicates.has(res)) {
+ duplicates[res]=res->duplicate();
+ }
+ res=duplicates[res];
+
+ current->set(E->get().name,res);
+ }
+
+ }
+ }
+
+ }
+ }
+
+ editor_data.get_undo_redo().clear_history();
+ if (editor_plugin_over) { //reload editor plugin
+ editor_plugin_over->edit(NULL);
+ editor_plugin_over->edit(current);
+ }
+
+ } break;
case OBJECT_CALL_METHOD: {
editor_data.apply_changes_in_editors();;
@@ -2127,12 +2666,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..");
@@ -2149,16 +2688,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("Play","EditorIcons"));
play_scene_button->set_pressed(false);
- pause_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();
@@ -2172,11 +2720,11 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
if (!p_confirmed) {
confirmation->get_ok()->set_text("Yes");
confirmation->set_text("Open Project Manager? \n(Unsaved changes will be lost)");
- confirmation->popup_centered(Size2(300,70));
+ confirmation->popup_centered_minsize();
break;
}
- get_scene()->quit();
+ get_tree()->quit();
String exec = OS::get_singleton()->get_executable_path();
List<String> args;
@@ -2190,28 +2738,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);
@@ -2360,7 +2937,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;
@@ -2368,7 +2945,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;
@@ -2386,6 +2965,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) {
@@ -2393,7 +2974,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 );
@@ -2405,16 +2991,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_tabs->get_tab_title(i)) {
+ if (p_editor->get_name()==singleton->main_editor_buttons[i]->get_name()) {
+
+ 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);
@@ -2423,27 +3011,80 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) {
}
+void EditorNode::add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
+
+ editor_import_export->add_import_plugin(p_editor_import);
+ _rebuild_import_menu();
+}
+
+void EditorNode::remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
+
+ editor_import_export->remove_import_plugin(p_editor_import);
+ _rebuild_import_menu();
+}
+
+void EditorNode::_remove_edited_scene() {
+ int new_index = editor_data.get_edited_scene();
+ int old_index=new_index;
+
+ if (new_index>0) {
+ new_index=new_index-1;
+ } else if (editor_data.get_edited_scene_count()>1) {
+ new_index=1;
+ } else {
+ editor_data.add_edited_scene(-1);
+ new_index=1;
+ }
+
+ _scene_tab_changed(new_index);
+ editor_data.remove_scene(old_index);
+ editor_data.get_undo_redo().clear_history();
+ _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;
+// }
+}
+
+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 (edited_scene) {
- if (edited_scene->get_parent()==scene_root)
- scene_root->remove_child(edited_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);
}
- edited_scene=p_scene;
- if (edited_scene && edited_scene->cast_to<Popup>())
- edited_scene->cast_to<Popup>()->show(); //show popups
- scene_tree_dock->set_edited_scene(edited_scene);
+ get_editor_data().set_edited_scene_root(p_scene);
+
+ if (p_scene && p_scene->cast_to<Popup>())
+ p_scene->cast_to<Popup>()->show(); //show popups
+ scene_tree_dock->set_edited_scene(p_scene);
+ if (get_tree())
+ get_tree()->set_edited_scene_root(p_scene);
- if (edited_scene) {
+ if (p_scene) {
if (p_scene->get_parent()!=scene_root)
scene_root->add_child(p_scene);
animation_editor->set_root(p_scene);
}
-
-
}
+
void EditorNode::_fetch_translatable_strings(const Object *p_object,Set<StringName>& strings) {
@@ -2477,7 +3118,7 @@ void EditorNode::_fetch_translatable_strings(const Object *p_object,Set<StringNa
Error EditorNode::save_translatable_strings(const String& p_to_file) {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
defer_translatable=p_to_file;
return OK;
}
@@ -2495,7 +3136,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-2014 Juan Linietsky, Ariel Manzur.");
+ f->store_line("# \t" VERSION_FULL_NAME " (c) 2008-2015 Juan Linietsky, Ariel Manzur.");
f->store_line("# From Scene: ");
f->store_line("# \t"+get_edited_scene()->get_filename());
f->store_line("");
@@ -2610,7 +3251,7 @@ Error EditorNode::save_optimized_copy(const String& p_scene,const String& p_pres
}
}
- ERR_EXPLAIN("Preset '"+p_preset+"' references unexisting saver: "+type);
+ ERR_EXPLAIN("Preset '"+p_preset+"' references nonexistent saver: "+type);
ERR_FAIL_COND_V(saver.is_null(),ERR_INVALID_DATA);
List<Variant> keys;
@@ -2669,14 +3310,196 @@ Error EditorNode::save_optimized_copy(const String& p_scene,const String& p_pres
return OK;
}
-Error EditorNode::load_scene(const String& p_scene) {
- if (!is_inside_scene()) {
+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"]=_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;
+ //print_line(" getting main tab: "+itos(state["main_tab"]));
+ return 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]) {
+ current=i;
+ break;
+ }
+ }
+
+
+ if (idx<2 && current<2) {
+ //only set tab for 2D and 3D
+ _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"]);
+ if (p_state.has("property_edit_offset"))
+ get_property_editor()->get_scene_tree()->get_vscroll_bar()->set_val(p_state["property_edit_offset"]);
+
+ //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;
+
+}
+
+void EditorNode::set_current_version(uint64_t p_version) {
+
+ saved_version=p_version;
+ editor_data.set_edited_scene_version(p_version);
+}
+
+bool EditorNode::is_changing_scene() const {
+ return changing_scene;
+}
+void EditorNode::set_current_scene(int p_idx) {
+
+ 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 ");
+
+ editor_selection->clear();
+ editor_data.set_edited_scene(p_idx);
+
+ Node* new_scene = editor_data.get_edited_scene_root();
+
+ if (new_scene && new_scene->cast_to<Popup>())
+ new_scene->cast_to<Popup>()->show(); //show popups
+
+ //print_line("set current 3 ");
+
+ scene_tree_dock->set_edited_scene(new_scene);
+ if (get_tree())
+ get_tree()->set_edited_scene_root(new_scene);
+
+ 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 ");
+
+
+ Dictionary state = editor_data.restore_edited_scene_state(editor_selection,&editor_history);
+ _edit_current();
+
+ /*if (!unsaved) {
+ saved_version=editor_data.get_undo_redo().get_version();
+ if (p_backwards)
+ saved_version--;
+ else
+ saved_version++;
+ print_line("was saved, updating version");
+ } else {
+ saved_version=state["saved_version"];
+ }*/
+ //_set_main_scene_state(state);
+
+ call_deferred("_set_main_scene_state",state); //do after everything else is done setting up
+ //print_line("set current 6 ");
+
+
+}
+
+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;
return OK;
}
+ 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;
+ }
+ }
+
load_errors->clear();
String lpath = Globals::get_singleton()->localize_path(p_scene);
@@ -2687,38 +3510,97 @@ Error EditorNode::load_scene(const String& p_scene) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("Ugh");
accept->set_text("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path.");
- accept->popup_centered(Size2(300,120));
+ accept->popup_centered_minsize();
opening_prev=false;
return ERR_FILE_NOT_FOUND;
}
- _cleanup_scene(); // i'm sorry but this MUST happen to avoid modified resources to not be reloaded.
+ int prev = editor_data.get_edited_scene();
+ int idx = editor_data.add_edited_scene(-1);
+ //print_line("load scene callback");
+ //set_current_scene(idx);
+
+ if (!editor_data.get_edited_scene_root() && editor_data.get_edited_scene_count()==2) {
+ _remove_edited_scene();
+ } else {
+ _scene_tab_changed(idx);
+ }
+
+
+
+ //_cleanup_scene(); // i'm sorry but this MUST happen to avoid modified resources to not be reloaded.
+
+ dependency_errors.clear();
- Ref<PackedScene> sdata = ResourceLoader::load(lpath);
+ Ref<PackedScene> sdata = ResourceLoader::load(lpath,"",true);
if (!sdata.is_valid()) {
current_option=-1;
//accept->get_cancel()->hide();
accept->get_ok()->set_text("Ugh");
accept->set_text("Error loading scene.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
opening_prev=false;
+
+ if (prev!=-1) {
+ set_current_scene(prev);
+ editor_data.remove_scene(idx);
+ }
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);
+ }
+
+ sdata->set_path(lpath,true); //take over path
+
Node*new_scene=sdata->instance(true);
if (!new_scene) {
+ sdata.unref();
current_option=-1;
//accept->get_cancel()->hide();
accept->get_ok()->set_text("Ugh");
accept->set_text("Error loading scene.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
opening_prev=false;
+ if (prev!=-1) {
+ set_current_scene(prev);
+ editor_data.remove_scene(idx);
+ }
return ERR_FILE_NOT_FOUND;
}
+ //guess not needed in the end?
+ //new_scene->clear_internal_tree_resource_paths(); //make sure no internal tree paths to internal resources exist
+
/*
Node *old_scene = edited_scene;
_hide_top_editors();
@@ -2731,16 +3613,34 @@ Error EditorNode::load_scene(const String& p_scene) {
memdelete(old_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();
+ /*
+ editor_data.set_edited_scene_root(new_scene);
+
scene_tree_dock->set_selected(new_scene, true);
property_editor->edit(new_scene);
- scene_import_metadata = sdata->get_import_metadata();
+ editor_data.set_edited_scene_root(new_scene);
+*/
+ editor_data.set_edited_scene_import_metadata( sdata->get_import_metadata() );
- editor_data.get_undo_redo().clear_history();
+
+// editor_data.get_undo_redo().clear_history();
saved_version=editor_data.get_undo_redo().get_version();
_update_title();
-
+ _update_scene_tabs();
_add_to_recent_scenes(lpath);
if (new_scene->has_meta("__editor_plugin_screen__")) {
@@ -2759,7 +3659,9 @@ Error EditorNode::load_scene(const String& p_scene) {
prev_scene->set_disabled(previous_scenes.size()==0);
opening_prev=false;
- top_pallete->set_current_tab(0); //always go to scene
+ ScriptEditor::get_singleton()->get_debugger()->update_live_edit_root();
+
+ //top_pallete->set_current_tab(0); //always go to scene
push_item(new_scene);
@@ -2770,8 +3672,9 @@ Error EditorNode::load_scene(const String& p_scene) {
void EditorNode::open_request(const String& p_path) {
- external_file=p_path;
- _menu_option_confirm(FILE_EXTERNAL_OPEN_SCENE,false);
+ load_scene(p_path); // as it will be opened in separate tab
+ //external_file=p_path;
+ //_menu_option_confirm(FILE_EXTERNAL_OPEN_SCENE,false);
}
@@ -2792,9 +3695,9 @@ void EditorNode::_instance_request(const String& p_path){
request_instance_scene(p_path);
}
-void EditorNode::_property_keyed(const String& p_keyed,const Variant& p_value) {
+void EditorNode::_property_keyed(const String& p_keyed,const Variant& p_value,bool p_advance) {
- animation_editor->insert_value_key(p_keyed,p_value);
+ animation_editor->insert_value_key(p_keyed,p_value,p_advance);
}
void EditorNode::_transform_keyed(Object *sp,const String& p_sub,const Transform& p_key) {
@@ -2832,15 +3735,15 @@ void EditorNode::_update_keying() {
void EditorNode::_close_messages() {
// left_split->set_dragger_visible(false);
- old_split_ofs = left_split->get_split_offset();
- left_split->set_split_offset(0);
+ old_split_ofs = center_split->get_split_offset();
+ center_split->set_split_offset(0);
// scene_root_parent->set_anchor_and_margin(MARGIN_BOTTOM,Control::ANCHOR_END,0);
}
void EditorNode::_show_messages() {
// left_split->set_dragger_visible(true);
- left_split->set_split_offset(old_split_ofs);
+ center_split->set_split_offset(old_split_ofs);
// scene_root_parent->set_anchor_and_margin(MARGIN_BOTTOM,Control::ANCHOR_END,log->get_margin(MARGIN_TOP));
}
@@ -2871,6 +3774,8 @@ void EditorNode::animation_editor_make_visible(bool p_visible) {
//pd_anim->hide();
animation_editor->hide();
// scene_root_parent->set_margin(MARGIN_TOP,0);
+ if (!animation_vb->get_parent_control())
+ return;
animation_vb->get_parent_control()->minimum_size_changed();
top_split->set_collapsed(true);
}
@@ -2907,15 +3812,16 @@ void EditorNode::_open_recent_scene(int p_idx) {
String path = "res://"+rc[p_idx];
- if (unsaved_cache) {
+
+ /*if (unsaved_cache) {
_recent_scene=rc[p_idx];
open_recent_confirmation->set_text("Discard current scene and open:\n'"+rc[p_idx]+"'");
open_recent_confirmation->get_label()->set_align(Label::ALIGN_CENTER);
open_recent_confirmation->popup_centered(Size2(400,100));
return;
- }
+ }*/
- load_scene(rc[p_idx]);
+ load_scene(path);
}
@@ -2959,12 +3865,6 @@ void EditorNode::_save_optimized() {
#endif
}
-void EditorNode::_open_recent_scene_confirm() {
-
- load_scene(_recent_scene);
-
-}
-
void EditorNode::_update_recent_scenes() {
String base="_"+Globals::get_singleton()->get_resource_path().replace("\\","::").replace("/","::");
@@ -2984,9 +3884,12 @@ void EditorNode::hide_animation_player_editors() {
void EditorNode::_quick_opened(const String& p_resource) {
- print_line("quick_opened");
- if (quick_open->get_base_type()=="PackedScene") {
+ if (current_option==FILE_QUICK_OPEN_FILE) {
+ scenes_dock->open(p_resource);
+ return;
+ }
+ if (quick_open->get_base_type()=="PackedScene") {
open_request(p_resource);
} else {
load_resource(p_resource);
@@ -3002,9 +3905,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();
@@ -3039,7 +3940,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);
}
@@ -3084,6 +3986,8 @@ void EditorNode::register_editor_types() {
ObjectTypeDB::register_type<EditorImportPlugin>();
ObjectTypeDB::register_type<EditorScenePostImport>();
ObjectTypeDB::register_type<EditorScript>();
+ ObjectTypeDB::register_type<EditorFileDialog>();
+ ObjectTypeDB::register_type<UndoRedo>();
//ObjectTypeDB::register_type<EditorImporter>();
@@ -3169,11 +4073,13 @@ void EditorNode::_bind_methods() {
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("_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);
@@ -3182,7 +4088,35 @@ void EditorNode::_bind_methods() {
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("_layout_dialog_action",&EditorNode::_dialog_action);
+
+ 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(_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") );
@@ -3231,6 +4165,16 @@ void EditorNode::_file_dialog_unregister(FileDialog *p_dialog){
singleton->file_dialogs.erase(p_dialog);
}
+void EditorNode::_editor_file_dialog_register(EditorFileDialog *p_dialog) {
+
+ singleton->editor_file_dialogs.insert(p_dialog);
+}
+
+void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog){
+
+ singleton->editor_file_dialogs.erase(p_dialog);
+}
+
Vector<EditorNodeInitCallback> EditorNode::_init_callbacks;
Error EditorNode::export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after) {
@@ -3243,13 +4187,550 @@ Error EditorNode::export_platform(const String& p_platform, const String& p_path
return OK;
}
+void EditorNode::show_warning(const String& p_text) {
+
+ warning->set_text(p_text);
+ warning->popup_centered_minsize();
+}
+
+void EditorNode::_dock_select_input(const InputEvent& p_input) {
+
+ if (p_input.type==InputEvent::MOUSE_BUTTON || p_input.type==InputEvent::MOUSE_MOTION) {
+
+ Vector2 point(p_input.mouse_motion.x,p_input.mouse_motion.y);
+
+ int nrect = -1;
+ for(int i=0;i<DOCK_SLOT_MAX;i++) {
+ if (dock_select_rect[i].has_point(point)) {
+ nrect=i;
+ break;
+ }
+ }
+
+
+ if (nrect!=dock_select_rect_over) {
+ dock_select->update();
+ dock_select_rect_over=nrect;
+
+ }
+
+
+ if (nrect==-1)
+ return;
+
+ if (p_input.type==InputEvent::MOUSE_BUTTON && p_input.mouse_button.button_index==1 && p_input.mouse_button.pressed && dock_popup_selected!=nrect) {
+ Control *dock = dock_slot[dock_popup_selected]->get_current_tab_control();
+ if (dock) {
+ dock_slot[dock_popup_selected]->remove_child(dock);
+ }
+ if (dock_slot[dock_popup_selected]->get_tab_count()==0) {
+ dock_slot[dock_popup_selected]->hide();
+
+ } else {
+
+ dock_slot[dock_popup_selected]->set_current_tab(0);
+ }
+
+ print_line("performing reparent");
+ dock_slot[nrect]->add_child(dock);
+ dock_popup_selected=nrect;
+ dock_slot[nrect]->set_current_tab(dock_slot[nrect]->get_tab_count()-1);
+ dock_slot[nrect]->show();
+ dock_select->update();
+
+ VSplitContainer*splits[DOCK_SLOT_MAX/2]={
+ left_l_vsplit,
+ left_r_vsplit,
+ right_l_vsplit,
+ right_r_vsplit,
+ };
+
+ for(int i=0;i<4;i++) {
+ bool in_use = dock_slot[i*2+0]->get_tab_count() || dock_slot[i*2+1]->get_tab_count();
+ if (in_use)
+ splits[i]->show();
+ else
+ splits[i]->hide();
+ }
+
+ _save_docks();
+ }
+ }
+}
+
+void EditorNode::_dock_popup_exit() {
+
+ dock_select_rect_over=-1;
+ dock_select->update();
+}
+
+void EditorNode::_dock_pre_popup(int p_which) {
+
+
+ dock_popup_selected=p_which;
+}
+
+void EditorNode::_dock_move_left() {
+
+ if (dock_popup_selected<0 || dock_popup_selected>=DOCK_SLOT_MAX)
+ return;
+ Control *current = dock_slot[dock_popup_selected]->get_tab_control( dock_slot[dock_popup_selected]->get_current_tab() );
+ Control *prev = dock_slot[dock_popup_selected]->get_tab_control( dock_slot[dock_popup_selected]->get_current_tab()-1 );
+ if (!current || !prev)
+ return;
+ dock_slot[dock_popup_selected]->move_child(current,prev->get_index());
+ dock_slot[dock_popup_selected]->set_current_tab( dock_slot[dock_popup_selected]->get_current_tab()-1 );
+ dock_select->update();
+ _save_docks();
+
+
+}
+
+void EditorNode::_dock_move_right() {
+
+ Control *current = dock_slot[dock_popup_selected]->get_tab_control( dock_slot[dock_popup_selected]->get_current_tab() );
+ Control *next = dock_slot[dock_popup_selected]->get_tab_control( dock_slot[dock_popup_selected]->get_current_tab()+1 );
+ if (!current || !next)
+ return;
+ dock_slot[dock_popup_selected]->move_child(next,current->get_index());
+ dock_slot[dock_popup_selected]->set_current_tab( dock_slot[dock_popup_selected]->get_current_tab()+1 );
+ dock_select->update();
+ _save_docks();
+}
+
+void EditorNode::_dock_select_draw(){
+ Size2 s = dock_select->get_size();
+ s.y/=2.0;
+ s.x/=6.0;
+
+ Color used=Color(0.6,0.6,0.6,0.8);
+ Color used_selected=Color(0.8,0.8,0.8,0.8);
+ Color tab_selected=Color(1,1,1,1);
+ Color unused=used;
+ unused.a=0.4;
+ Color unusable=unused;
+ unusable.a=0.1;
+
+ Rect2 unr(s.x*2,0,s.x*2,s.y*2);
+ unr.pos+=Vector2(2,5);
+ unr.size-=Vector2(4,7);
+
+ dock_select->draw_rect(unr,unusable);
+
+ dock_tab_move_left->set_disabled(true);
+ dock_tab_move_right->set_disabled(true);
+
+ if (dock_popup_selected!=-1 && dock_slot[dock_popup_selected]->get_tab_count()) {
+
+ dock_tab_move_left->set_disabled(dock_slot[dock_popup_selected]->get_current_tab()==0);
+ dock_tab_move_right->set_disabled(dock_slot[dock_popup_selected]->get_current_tab()>=dock_slot[dock_popup_selected]->get_tab_count()-1);
+ }
+
+ for(int i=0;i<DOCK_SLOT_MAX;i++) {
+
+ Vector2 ofs;
+
+ switch(i) {
+ case DOCK_SLOT_LEFT_UL: {
+
+ } break;
+ case DOCK_SLOT_LEFT_BL: {
+ ofs.y+=s.y;
+ } break;
+ case DOCK_SLOT_LEFT_UR: {
+ ofs.x+=s.x;
+ } break;
+ case DOCK_SLOT_LEFT_BR: {
+ ofs+=s;
+ } break;
+ case DOCK_SLOT_RIGHT_UL: {
+ ofs.x+=s.x*4;
+ } break;
+ case DOCK_SLOT_RIGHT_BL: {
+ ofs.x+=s.x*4;
+ ofs.y+=s.y;
+
+ } break;
+ case DOCK_SLOT_RIGHT_UR: {
+ ofs.x+=s.x*4;
+ ofs.x+=s.x;
+
+ } break;
+ case DOCK_SLOT_RIGHT_BR: {
+ ofs.x+=s.x*4;
+ ofs+=s;
+
+ } break;
+ }
+
+ Rect2 r(ofs,s);
+ dock_select_rect[i]=r;
+ r.pos+=Vector2(2,5);
+ r.size-=Vector2(4,7);
+
+
+ if (i==dock_select_rect_over) {
+ dock_select->draw_rect(r,used_selected);
+ } else if (dock_slot[i]->get_child_count()==0) {
+ dock_select->draw_rect(r,unused);
+ } else {
+
+ dock_select->draw_rect(r,used);
+ }
+
+ for(int j=0;j<MIN(3,dock_slot[i]->get_child_count());j++) {
+ int xofs = (r.size.width/3)*j;
+ Color c = used;
+ if (i==dock_popup_selected && (dock_slot[i]->get_current_tab()>3 || dock_slot[i]->get_current_tab()==j))
+ c=tab_selected;
+ dock_select->draw_rect(Rect2(2+ofs.x+xofs,ofs.y,r.size.width/3-1,3),c);
+ }
+
+ }
+}
+
+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++) {
+ String name = dock_slot[i]->get_tab_control(j)->get_name();
+ if (names!="")
+ names+=",";
+ names+=name;
+ }
+
+ if (names!="") {
+ p_layout->set_value(p_section,"dock_"+itos(i+1),names);
+ }
+ }
+
+ VSplitContainer*splits[DOCK_SLOT_MAX/2]={
+ left_l_vsplit,
+ left_r_vsplit,
+ right_l_vsplit,
+ right_r_vsplit,
+ };
+
+ for(int i=0;i<DOCK_SLOT_MAX/2;i++) {
+
+ if (splits[i]->is_visible()) {
+ p_layout->set_value(p_section,"dock_split_"+itos(i+1),splits[i]->get_split_offset());
+ }
+ }
+
+
+ HSplitContainer *h_splits[4]={
+ left_l_hsplit,
+ left_r_hsplit,
+ main_hsplit,
+ right_hsplit,
+ };
+
+ for(int i=0;i<4;i++) {
+
+ p_layout->set_value(p_section,"dock_hsplit_"+itos(i+1),h_splits[i]->get_split_offset());
+ }
+
+}
+
+void EditorNode::save_layout() {
+
+ dock_drag_timer->start();
+}
+
+void EditorNode::_dock_split_dragged(int ofs) {
+
+ dock_drag_timer->start();
+}
+
+void EditorNode::_load_docks() {
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg"));
+ if (err!=OK) {
+ return; //no config
+ }
+
+ _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 (!p_layout->has_section_key(p_section,"dock_"+itos(i+1)))
+ continue;
+
+ Vector<String> names = String(p_layout->get_value(p_section,"dock_"+itos(i+1))).split(",");
+
+ for(int j=0;j<names.size();j++) {
+ String name=names[j];
+ //find it, in a horribly inefficient way
+ int atidx=-1;
+ Control *node=NULL;
+ for(int k=0;k<DOCK_SLOT_MAX;k++) {
+ if (!dock_slot[k]->has_node(name))
+ continue;
+ node=dock_slot[k]->get_node(name)->cast_to<Control>();
+ if (!node)
+ continue;
+ atidx=k;
+ break;
+ }
+ if (atidx==-1) //well, it's not anywhere
+ continue;
+
+ if (atidx==i) {
+ node->raise();
+ continue;
+ }
+
+
+ dock_slot[atidx]->remove_child(node);
+
+ if (dock_slot[atidx]->get_tab_count()==0) {
+ dock_slot[atidx]->hide();
+
+ }
+ dock_slot[i]->add_child(node);
+ dock_slot[i]->show();
+ }
+ }
+
+ VSplitContainer*splits[DOCK_SLOT_MAX/2]={
+ left_l_vsplit,
+ left_r_vsplit,
+ right_l_vsplit,
+ right_r_vsplit,
+ };
+
+ for(int i=0;i<DOCK_SLOT_MAX/2;i++) {
+
+ if (!p_layout->has_section_key(p_section,"dock_split_"+itos(i+1)))
+ continue;
+
+ int ofs = p_layout->get_value(p_section,"dock_split_"+itos(i+1));
+ splits[i]->set_split_offset(ofs);
+ }
+
+ HSplitContainer*h_splits[4]={
+ left_l_hsplit,
+ left_r_hsplit,
+ main_hsplit,
+ right_hsplit,
+ };
+
+ for(int i=0;i<4;i++) {
+ if (!p_layout->has_section_key(p_section,"dock_hsplit_"+itos(i+1)))
+ continue;
+ int ofs = p_layout->get_value(p_section,"dock_hsplit_"+itos(i+1));
+ h_splits[i]->set_split_offset(ofs);
+ }
+
+ for(int i=0;i<DOCK_SLOT_MAX/2;i++) {
+ bool in_use = dock_slot[i*2+0]->get_tab_count() || dock_slot[i*2+1]->get_tab_count();
+ if (in_use)
+ splits[i]->show();
+ else
+ splits[i]->hide();
+ }
+
+ for(int i=0;i<DOCK_SLOT_MAX;i++) {
+
+ if (!dock_slot[i]->is_hidden() && dock_slot[i]->get_tab_count()) {
+ dock_slot[i]->set_current_tab(0);
+ }
+ }
+}
+
+
+void EditorNode::_update_layouts_menu() {
+
+ editor_layouts->clear();
+ 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->add_item(layout);
+ }
+
+}
+
+void EditorNode::_layout_menu_option(int p_id) {
+
+ switch (p_id) {
+
+ case SETTINGS_LAYOUT_SAVE: {
+
+ current_option=p_id;
+ layout_dialog->clear_layout_name();
+ 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->clear_layout_name();
+ 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_theme, "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
+ }
+
+ int idx=editor_layouts->get_item_index(p_id);
+ _load_docks_from_config(config, editor_layouts->get_item_text(idx));
+ _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();
+ }
+
+}
+
+
+void EditorNode::_scene_tab_changed(int p_tab) {
+
+
+ //print_line("set current 1 ");
+ bool unsaved = (saved_version!=editor_data.get_undo_redo().get_version());
+ //print_line("version: "+itos(editor_data.get_undo_redo().get_version())+", saved "+itos(saved_version));
+
+ if (p_tab==editor_data.get_edited_scene())
+ return; //pointless
+
+ uint64_t next_scene_version = editor_data.get_scene_version(p_tab);
+
+
+
+ //print_line("scene tab changed???");
+ editor_data.get_undo_redo().create_action("Switch Scene 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(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(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();
+}
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;
+ changing_scene=false;
FileAccess::set_backup_save(true);
@@ -3260,7 +4741,10 @@ EditorNode::EditorNode() {
EditorSettings::create();
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"));
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);
@@ -3277,7 +4761,13 @@ EditorNode::EditorNode() {
FileDialog::register_func=_file_dialog_register;
FileDialog::unregister_func=_file_dialog_unregister;
+ EditorFileDialog::get_icon_func=_file_dialog_get_icon;
+ EditorFileDialog::register_func=_editor_file_dialog_register;
+ EditorFileDialog::unregister_func=_editor_file_dialog_unregister;
+
+
editor_import_export = memnew( EditorImportExport );
+ add_child(editor_import_export);
register_exporters();
@@ -3295,11 +4785,14 @@ EditorNode::EditorNode() {
gui_base->set_area_as_parent_rect();
- Ref<Theme> theme( memnew( Theme ) );
+ theme = Ref<Theme>( memnew( Theme ) );
gui_base->set_theme( theme );
editor_register_icons(theme);
editor_register_fonts(theme);
+ //theme->set_icon("folder","EditorFileDialog",Theme::get_default()->get_icon("folder","EditorFileDialog"));
+ //theme->set_color("files_disabled","EditorFileDialog",Color(0,0,0,0.7));
+
String global_font = EditorSettings::get_singleton()->get("global/font");
if (global_font!="") {
Ref<Font> fnt = ResourceLoader::load(global_font);
@@ -3318,6 +4811,8 @@ EditorNode::EditorNode() {
theme->set_stylebox("EditorFocus","EditorStyles",focus_sbt);
+ resource_preview = memnew( EditorResourcePreview );
+ add_child(resource_preview);
progress_dialog = memnew( ProgressDialog );
gui_base->add_child(progress_dialog);
@@ -3325,26 +4820,166 @@ EditorNode::EditorNode() {
gui_base->set_anchor( MARGIN_RIGHT, Control::ANCHOR_END );
gui_base->set_anchor( MARGIN_BOTTOM, Control::ANCHOR_END );
gui_base->set_end( Point2(0,0) );
-
+
main_vbox = memnew( VBoxContainer );
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();;
+ top_dark_sb->set_texture(theme->get_icon("PanelTop","EditorIcons"));
+ for(int i=0;i<4;i++) {
+ top_dark_sb->set_margin_size(Margin(i),3);
+ top_dark_sb->set_default_margin(Margin(i),0);
+ }
+ top_dark_sb->set_expand_margin_size(MARGIN_LEFT,20);
+ top_dark_sb->set_expand_margin_size(MARGIN_RIGHT,20);
+
+ top_dark_panel->add_style_override("panel",top_dark_sb);
+ 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 );
main_vbox->add_child(menu_hb);
- main_split = memnew( HSplitContainer );
- main_vbox->add_child(main_split);
- main_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
-
+// top_dark_vb->add_child(scene_tabs);
+ //left
+ left_l_hsplit = memnew( HSplitContainer );
+ main_vbox->add_child(left_l_hsplit);
+
+ left_l_hsplit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ left_l_vsplit = memnew( VSplitContainer );
+ left_l_hsplit->add_child(left_l_vsplit);
+ dock_slot[DOCK_SLOT_LEFT_UL]=memnew( TabContainer );
+ left_l_vsplit->add_child(dock_slot[DOCK_SLOT_LEFT_UL]);
+ dock_slot[DOCK_SLOT_LEFT_BL]=memnew( TabContainer );
+ left_l_vsplit->add_child(dock_slot[DOCK_SLOT_LEFT_BL]);
+ left_l_vsplit->hide();
+ dock_slot[DOCK_SLOT_LEFT_UL]->hide();
+ dock_slot[DOCK_SLOT_LEFT_BL]->hide();
+
+ left_r_hsplit = memnew( HSplitContainer );
+ left_l_hsplit->add_child(left_r_hsplit);
+ left_r_vsplit = memnew( VSplitContainer );
+ left_r_hsplit->add_child(left_r_vsplit);
+ dock_slot[DOCK_SLOT_LEFT_UR]=memnew( TabContainer );
+ left_r_vsplit->add_child(dock_slot[DOCK_SLOT_LEFT_UR]);
+ dock_slot[DOCK_SLOT_LEFT_BR]=memnew( TabContainer );
+ left_r_vsplit->add_child(dock_slot[DOCK_SLOT_LEFT_BR]);
+ //left_r_vsplit->hide();
+ //dock_slot[DOCK_SLOT_LEFT_UR]->hide();
+ //dock_slot[DOCK_SLOT_LEFT_BR]->hide();
+
+
+ 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_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);
+
+ right_l_vsplit = memnew( VSplitContainer );
+ right_hsplit->add_child(right_l_vsplit);
+ dock_slot[DOCK_SLOT_RIGHT_UL]=memnew( TabContainer );
+ 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);
+ dock_slot[DOCK_SLOT_RIGHT_UR]=memnew( TabContainer );
+ right_r_vsplit->add_child(dock_slot[DOCK_SLOT_RIGHT_UR]);
+ 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_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");
+ right_l_vsplit->connect("dragged",this,"_dock_split_dragged");
+ right_r_vsplit->connect("dragged",this,"_dock_split_dragged");
+
+ left_l_hsplit->connect("dragged",this,"_dock_split_dragged");
+ left_r_hsplit->connect("dragged",this,"_dock_split_dragged");
+ main_hsplit->connect("dragged",this,"_dock_split_dragged");
+ right_hsplit->connect("dragged",this,"_dock_split_dragged");
+
+
+
+ dock_select_popoup = memnew( PopupPanel );
+ gui_base->add_child(dock_select_popoup);
+ VBoxContainer *dock_vb = memnew( VBoxContainer );
+ dock_select_popoup->add_child(dock_vb);
+
+ HBoxContainer *dock_hb = memnew( HBoxContainer);
+ dock_tab_move_left = memnew( ToolButton );
+ dock_tab_move_left->set_icon(theme->get_icon("Back","EditorIcons"));
+ dock_tab_move_left->set_focus_mode(Control::FOCUS_NONE);
+ dock_tab_move_left->connect("pressed",this,"_dock_move_left");
+ //dock_tab_move_left->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ dock_hb->add_child(dock_tab_move_left);
+ dock_hb->add_spacer();
+ dock_tab_move_right = memnew( ToolButton );
+ dock_tab_move_right->set_icon(theme->get_icon("Forward","EditorIcons"));
+ dock_tab_move_right->set_focus_mode(Control::FOCUS_NONE);
+ dock_tab_move_right->connect("pressed",this,"_dock_move_right");
+
+ //dock_tab_move_right->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ dock_hb->add_child(dock_tab_move_right);
+ dock_vb->add_child(dock_hb);
+
+ dock_select = memnew( Control );
+ dock_select->set_custom_minimum_size(Size2(128,64));
+ dock_select->connect("input_event",this,"_dock_select_input");
+ dock_select->connect("draw",this,"_dock_select_draw");
+ dock_select->connect("mouse_exit",this,"_dock_popup_exit");
+ dock_select->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ dock_vb->add_child(dock_select);
+
+
+ dock_select_popoup->set_child_rect(dock_vb);
+ dock_select_popoup->set_as_minsize();
+ dock_select_rect_over=-1;
+ dock_popup_selected=-1;
+ //dock_select_popoup->set_(Size2(20,20));
+
+ for(int i=0;i<DOCK_SLOT_MAX;i++) {
+ 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));
+
+ //dock_slot[i]->set_tab_align(TabContainer::ALIGN_LEFT);
+ }
- left_split = memnew( VSplitContainer );
- main_split->add_child(left_split);
- left_split->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- left_split->set_collapsed(false);
+ dock_drag_timer = memnew( Timer );
+ add_child(dock_drag_timer);
+ dock_drag_timer->set_wait_time(0.5);
+ dock_drag_timer->set_one_shot(true);
+ dock_drag_timer->connect("timeout",this,"_save_docks");
top_split = memnew( VSplitContainer );
- left_split->add_child(top_split);
+ center_split->add_child(top_split);
top_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
top_split->set_collapsed(true);
@@ -3354,19 +4989,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 );
- EmptyControl *tec = memnew( EmptyControl );
- tec->set_minsize(Size2(100,0));
- tec->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- srth->add_child(tec);
- srth->add_child(main_editor_tabs);
- tec = memnew( EmptyControl );
- tec->set_minsize(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::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 );
@@ -3388,6 +5023,8 @@ EditorNode::EditorNode() {
scene_root = memnew( Viewport );
+
+
//scene_root_base->add_child(scene_root);
scene_root->set_meta("_editor_disable_input",true);
VisualServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport(),true);
@@ -3413,6 +5050,7 @@ EditorNode::EditorNode() {
animation_panel=pc;
animation_panel->hide();
+
HBoxContainer *animation_hb = memnew( HBoxContainer);
animation_vb->add_child(animation_hb);
@@ -3440,6 +5078,8 @@ EditorNode::EditorNode() {
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 );
@@ -3461,8 +5101,9 @@ EditorNode::EditorNode() {
prev_scene->set_disabled(true);
//left_menu_hb->add_child( prev_scene );
prev_scene->connect("pressed",this,"_menu_option",make_binds(FILE_OPEN_PREV));
- //gui_base->add_child(prev_scene);
+ gui_base->add_child(prev_scene);
prev_scene->set_pos(Point2(3,24));
+ prev_scene->hide();
Separator *vs=NULL;
@@ -3470,15 +5111,20 @@ 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);
- p->add_item("Save Scene As..",FILE_SAVE_AS_SCENE);
+ p->add_item("Save Scene As..",FILE_SAVE_AS_SCENE,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_S);
p->add_separator();
- p->add_item("Goto Prev. Scene",FILE_OPEN_PREV,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_P);
+ p->add_item("Close Scene",FILE_CLOSE,KEY_MASK_SHIFT+KEY_MASK_CTRL+KEY_W);
+ p->add_separator();
+ p->add_item("Close Goto Prev. Scene",FILE_OPEN_PREV,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_P);
p->add_submenu_item("Open Recent","RecentScenes",FILE_OPEN_RECENT);
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 );
@@ -3500,6 +5146,8 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_item("Project Settings",RUN_SETTINGS);
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);
p->add_item("Quit",FILE_QUIT,KEY_MASK_CMD+KEY_Q);
@@ -3508,6 +5156,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 );
@@ -3544,13 +5204,19 @@ EditorNode::EditorNode() {
left_menu_hb->add_child( import_menu );
p=import_menu->get_popup();
- p->add_item("Sub-Scene",FILE_IMPORT_SUBSCENE);
-#ifdef OLD_SCENE_FORMAT_ENABLED
- p->add_item("Import Old Scene",FILE_OPEN_OLD_SCENE);
-#endif
- p->add_separator();
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");
@@ -3586,18 +5252,18 @@ EditorNode::EditorNode() {
play_button->set_icon(gui_base->get_icon("MainPlay","EditorIcons"));
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", this,"_menu_option",make_binds(RUN_PLAY));
- play_button->set_tooltip("Start the scene (F5).");
+ play_button->set_tooltip("Play the project (F5).");
- pause_button = memnew( ToolButton );
+ /*pause_button = memnew( ToolButton );
//menu_panel->add_child(pause_button); - not needed for now?
pause_button->set_toggle_mode(true);
pause_button->set_icon(gui_base->get_icon("Pause","EditorIcons"));
pause_button->set_focus_mode(Control::FOCUS_NONE);
pause_button->connect("pressed", this,"_menu_option",make_binds(RUN_PAUSE));
pause_button->set_tooltip("Pause the scene (F7).");
-
+*/
stop_button = memnew( ToolButton );
play_hb->add_child(stop_button);
//stop_button->set_toggle_mode(true);
@@ -3613,8 +5279,9 @@ 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 );
+// VSeparator *s1 = memnew( VSeparator );
// play_hb->add_child(s1);
play_scene_button = memnew( ToolButton );
@@ -3633,30 +5300,34 @@ 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 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("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("Visible Collision Shapes",RUN_DEBUG_COLLISONS);
+ p->add_check_item("Visible Navigation",RUN_DEBUG_NAVIGATION);
p->connect("item_pressed",this,"_menu_option");
+ /*
run_settings_button = memnew( ToolButton );
//menu_hb->add_child(run_settings_button);
//run_settings_button->set_toggle_mode(true);
run_settings_button->set_focus_mode(Control::FOCUS_NONE);
run_settings_button->set_icon(gui_base->get_icon("Run","EditorIcons"));
run_settings_button->connect("pressed", this,"_menu_option",make_binds(RUN_SCENE_SETTINGS));
-
+*/
/*
run_settings_button = memnew( ToolButton );
@@ -3668,6 +5339,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 );
@@ -3681,17 +5385,29 @@ 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();
+ 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_check_item("Show Animation",SETTINGS_SHOW_ANIMATION,KEY_MASK_CMD+KEY_N);
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( EditorLayoutDialog );
+ gui_base->add_child(layout_dialog);
+ layout_dialog->set_hide_on_ok(false);
+ layout_dialog->set_size(Size2(175, 70));
+ confirm_error = memnew( AcceptDialog );
+ layout_dialog->add_child(confirm_error);
+ layout_dialog->connect("layout_selected", this,"_layout_dialog_action");
sources_button = memnew( ToolButton );
right_menu_hb->add_child(sources_button);
@@ -3699,6 +5415,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();
/*
@@ -3710,68 +5435,84 @@ EditorNode::EditorNode() {
- editor_hsplit = memnew( HSplitContainer );
- main_split->add_child(editor_hsplit);
- editor_hsplit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ //editor_hsplit = memnew( HSplitContainer );
+ //main_split->add_child(editor_hsplit);
+ //editor_hsplit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- editor_vsplit = memnew( VSplitContainer );
- editor_hsplit->add_child(editor_vsplit);
+ //editor_vsplit = memnew( VSplitContainer );
+ //editor_hsplit->add_child(editor_vsplit);
- top_pallete = memnew( TabContainer );
+ //top_pallete = memnew( TabContainer );
scene_tree_dock = memnew( SceneTreeDock(this,scene_root,editor_selection,editor_data) );
scene_tree_dock->set_name("Scene");
- top_pallete->add_child(scene_tree_dock);
-
+ //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);
- top_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL);
-
- EmptyControl *editor_spacer = memnew( EmptyControl );
- editor_spacer->set_minsize(Size2(260,200));
+ //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);
editor_vsplit->add_child( editor_spacer );
editor_spacer->add_child( top_pallete );
- top_pallete->set_area_as_parent_rect();
+ top_pallete->set_area_as_parent_rect();*/
- prop_pallete = memnew( TabContainer );
+ //prop_pallete = memnew( TabContainer );
- prop_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ //prop_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- editor_spacer = memnew( EmptyControl );
- editor_spacer->set_minsize(Size2(260,200));
+ /*editor_spacer = memnew( Control );
+ editor_spacer->set_custom_minimum_size(Size2(260,200));
editor_spacer->set_v_size_flags(Control::SIZE_EXPAND_FILL);
editor_vsplit->add_child( editor_spacer );
editor_spacer->add_child( prop_pallete );
- prop_pallete->set_area_as_parent_rect();
+ prop_pallete->set_area_as_parent_rect();*/
VBoxContainer *prop_editor_base = memnew( VBoxContainer );
prop_editor_base->set_name("Inspector"); // Properties?
- prop_pallete->add_child(prop_editor_base);
+ 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 );
@@ -3779,28 +5520,101 @@ 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();
+
+ 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");
- prop_pallete->add_child(scenes_dock);
+ 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";
+
+ default_theme.instance();
+ default_theme->set_value(docks_section, "dock_3", "Scene");
+ default_theme->set_value(docks_section, "dock_4", "FileSystem");
+ default_theme->set_value(docks_section, "dock_5", "Inspector");
+
+ for(int i=0;i<DOCK_SLOT_MAX/2;i++)
+ default_theme->set_value(docks_section, "dock_hsplit_"+itos(i+1), 0);
+ for(int i=0;i<DOCK_SLOT_MAX/2;i++)
+ default_theme->set_value(docks_section, "dock_split_"+itos(i+1), 0);
+ _update_layouts_menu();
log = memnew( EditorLog );
- left_split->add_child(log);
+ 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;
@@ -3813,42 +5627,23 @@ EditorNode::EditorNode() {
animation_vb->add_child(animation_editor);
- left_split->connect("resized",this,"_vp_resized");
+ 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);*/
- bottom_hb->add_child( log->get_button() );
+ center_vb->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 );
@@ -3874,7 +5669,8 @@ EditorNode::EditorNode() {
-
+ orphan_resources = memnew( OrphanResourcesDialog );
+ gui_base->add_child(orphan_resources);
@@ -3913,7 +5709,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);
@@ -3947,7 +5747,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-2014 Juan Linietsky, Ariel Manzur.\n");
+ about_text->set_text(VERSION_FULL_NAME"\n(c) 2008-2015 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);
@@ -3956,6 +5756,8 @@ EditorNode::EditorNode() {
logo->set_pos(Point2(20,20));
logo->set_texture(gui_base->get_icon("Logo","EditorIcons") );
+ warning = memnew( AcceptDialog );
+ add_child(warning);
@@ -3969,7 +5771,7 @@ EditorNode::EditorNode() {
file_templates->add_filter("*.tpz ; Template Package");
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
gui_base->add_child(file);
file->set_current_dir("res://");
@@ -4043,11 +5845,14 @@ EditorNode::EditorNode() {
editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_2D) )));
- editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_3D) )));
editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_ATLAS) )));
+ editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_LARGE) )));
+ editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_3D) )));
Ref<EditorSceneImportPlugin> _scene_import = memnew(EditorSceneImportPlugin(this) );
Ref<EditorSceneImporterCollada> _collada_import = memnew( EditorSceneImporterCollada);
_scene_import->add_importer(_collada_import);
+// Ref<EditorSceneImporterFBXConv> _fbxconv_import = memnew( EditorSceneImporterFBXConv);
+// _scene_import->add_importer(_fbxconv_import);
editor_import_export->add_import_plugin( _scene_import);
editor_import_export->add_import_plugin( Ref<EditorSceneAnimationImportPlugin>( memnew(EditorSceneAnimationImportPlugin(this))));
editor_import_export->add_import_plugin( Ref<EditorMeshImportPlugin>( memnew(EditorMeshImportPlugin(this))));
@@ -4055,24 +5860,24 @@ EditorNode::EditorNode() {
editor_import_export->add_import_plugin( Ref<EditorSampleImportPlugin>( memnew(EditorSampleImportPlugin(this))));
editor_import_export->add_import_plugin( Ref<EditorTranslationImportPlugin>( memnew(EditorTranslationImportPlugin(this))));
-
- for(int i=0;i<editor_import_export->get_import_plugin_count();i++) {
- import_menu->get_popup()->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(),IMPORT_PLUGIN_BASE+i);
- }
-
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( 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) ) );
- add_editor_plugin( memnew( ShaderEditorPlugin(this) ) );
+ add_editor_plugin( memnew( ShaderGraphEditorPlugin(this,true) ) );
+ add_editor_plugin( memnew( ShaderGraphEditorPlugin(this,false) ) );
+ add_editor_plugin( memnew( ShaderEditorPlugin(this,true) ) );
+ add_editor_plugin( memnew( ShaderEditorPlugin(this,false) ) );
add_editor_plugin( memnew( CameraEditorPlugin(this) ) );
add_editor_plugin( memnew( SampleEditorPlugin(this) ) );
add_editor_plugin( memnew( SampleLibraryEditorPlugin(this) ) );
add_editor_plugin( memnew( ThemeEditorPlugin(this) ) );
add_editor_plugin( memnew( MultiMeshEditorPlugin(this) ) );
+ add_editor_plugin( memnew( MeshInstanceEditorPlugin(this) ) );
add_editor_plugin( memnew( AnimationTreeEditorPlugin(this) ) );
add_editor_plugin( memnew( SamplePlayerEditorPlugin(this) ) );
add_editor_plugin( memnew( MeshLibraryEditorPlugin(this) ) );
@@ -4081,27 +5886,39 @@ EditorNode::EditorNode() {
add_editor_plugin( memnew( ParticlesEditorPlugin(this) ) );
add_editor_plugin( memnew( ResourcePreloaderEditorPlugin(this) ) );
add_editor_plugin( memnew( ItemListEditorPlugin(this) ) );
- add_editor_plugin( memnew( RichTextEditorPlugin(this) ) );
+ //add_editor_plugin( memnew( RichTextEditorPlugin(this) ) );
add_editor_plugin( memnew( CollisionPolygonEditorPlugin(this) ) );
+ add_editor_plugin( memnew( CollisionPolygon2DEditorPlugin(this) ) );
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) ) );
add_editor_plugin( memnew( BakedLightEditorPlugin(this) ) );
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( CollisionShape2DEditorPlugin(this) ) );
for(int i=0;i<EditorPlugins::get_plugin_count();i++)
add_editor_plugin( EditorPlugins::create(i,this) );
+
+ resource_preview->add_preview_generator( Ref<EditorTexturePreviewPlugin>( memnew(EditorTexturePreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorPackedScenePreviewPlugin>( memnew(EditorPackedScenePreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorMaterialPreviewPlugin>( memnew(EditorMaterialPreviewPlugin )));
+ 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 )));
+
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;
-
- import_menu->get_popup()->add_separator();
- import_menu->get_popup()->add_item("Re-Import..",SETTINGS_IMPORT);
+ _rebuild_import_menu();
editor_plugin_screen=NULL;
editor_plugin_over=NULL;
@@ -4116,9 +5933,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(0x3f3945ff));
- theme->set_color("prop_section","Editor",Color::hex(0x38323dff));
- theme->set_color("prop_subsection","Editor",Color::hex(0x342e39ff));
+ 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"));
@@ -4149,8 +5966,8 @@ EditorNode::EditorNode() {
}
- edited_scene=NULL;
- saved_version=0;
+ //edited_scene=NULL;
+ saved_version=1;
unsaved_cache=true;
_last_instanced_scene=NULL;
@@ -4204,17 +6021,28 @@ EditorNode::EditorNode() {
Node::set_human_readable_collision_renaming(true);
+
+
// Ref<ImageTexture> it = gui_base->get_icon("logo","Icons");
// OS::get_singleton()->set_icon( it->get_data() );
for(int i=0;i<_init_callbacks.size();i++)
_init_callbacks[i]();
+ editor_data.add_edited_scene(-1);
+ editor_data.set_edited_scene(0);
+ _update_scene_tabs();
+
+ _load_docks();
+
+
}
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 2cec301cf6..bd25f27c59 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -76,9 +76,10 @@
#include "editor_reimport_dialog.h"
#include "import_settings.h"
#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_layout_dialog.h"
#include "fileserver/editor_file_server.h"
-
+#include "editor_resource_preview.h"
@@ -94,6 +95,8 @@
typedef void (*EditorNodeInitCallback)();
+
+
class EditorNode : public Node {
OBJ_TYPE( EditorNode, Node );
@@ -105,9 +108,12 @@ class EditorNode : public Node {
enum MenuOptions {
FILE_NEW_SCENE,
+ FILE_NEW_INHERITED_SCENE,
FILE_OPEN_SCENE,
FILE_SAVE_SCENE,
FILE_SAVE_AS_SCENE,
+ FILE_SAVE_BEFORE_RUN,
+ FILE_SAVE_AND_RUN,
FILE_IMPORT_SUBSCENE,
FILE_EXPORT_PROJECT,
FILE_EXPORT_MESH_LIBRARY,
@@ -119,38 +125,52 @@ class EditorNode : public Node {
FILE_OPEN_OLD_SCENE,
FILE_QUICK_OPEN_SCENE,
FILE_QUICK_OPEN_SCRIPT,
+ FILE_QUICK_OPEN_FILE,
FILE_RUN_SCRIPT,
FILE_OPEN_PREV,
+ FILE_CLOSE,
FILE_QUIT,
FILE_EXTERNAL_OPEN_SCENE,
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,
OBJECT_CALL_METHOD,
OBJECT_REQUEST_HELP,
RUN_PLAY,
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_LAYOUT_SAVE,
+ SETTINGS_LAYOUT_DELETE,
+ SETTINGS_LAYOUT_DEFAULT,
SETTINGS_SHOW_ANIMATION,
SETTINGS_LOAD_EXPORT_TEMPLATES,
SETTINGS_HELP,
@@ -158,25 +178,54 @@ class EditorNode : public Node {
SOURCES_REIMPORT,
DEPENDENCY_LOAD_CHANGED_IMAGES,
DEPENDENCY_UPDATE_IMPORTED,
+ SCENE_TAB_CLOSE,
IMPORT_PLUGIN_BASE=100,
OBJECT_METHOD_BASE=500
};
+ enum DockSlot {
+ DOCK_SLOT_LEFT_UL,
+ DOCK_SLOT_LEFT_BL,
+ DOCK_SLOT_LEFT_UR,
+ DOCK_SLOT_LEFT_BR,
+ DOCK_SLOT_RIGHT_UL,
+ DOCK_SLOT_RIGHT_BL,
+ DOCK_SLOT_RIGHT_UR,
+ DOCK_SLOT_RIGHT_BR,
+ DOCK_SLOT_MAX
+ };
-
- Node *edited_scene; //scene being edited
+ //Node *edited_scene; //scene being edited
Viewport *scene_root; //root of the scene being edited
- Ref<ResourceImportMetadata> scene_import_metadata;
+ //Ref<ResourceImportMetadata> scene_import_metadata;
Control* scene_root_parent;
Control *gui_base;
VBoxContainer *main_vbox;
- HSplitContainer *main_split;
- VSplitContainer *left_split;
+
+ //split
+
+ HSplitContainer *left_l_hsplit;
+ VSplitContainer *left_l_vsplit;
+ HSplitContainer *left_r_hsplit;
+ VSplitContainer *left_r_vsplit;
+ HSplitContainer *main_hsplit;
+ HSplitContainer *right_hsplit;
+ VSplitContainer *right_l_vsplit;
+ VSplitContainer *right_r_vsplit;
+
+ VSplitContainer *center_split;
+
+ //main tabs
+
+ Tabs *scene_tabs;
+ int tab_closing;
+
+
int old_split_ofs;
VSplitContainer *top_split;
HBoxContainer *bottom_hb;
@@ -186,12 +235,14 @@ class EditorNode : public Node {
TextureButton *anim_close;
Panel *menu_panel;
- HSplitContainer *editor_hsplit;
- VSplitContainer *editor_vsplit;
+
+ //HSplitContainer *editor_hsplit;
+ //VSplitContainer *editor_vsplit;
HBoxContainer *menu_hb;
Control *viewport;
MenuButton *file_menu;
MenuButton *import_menu;
+ MenuButton *tool_menu;
ToolButton *export_button;
ToolButton *prev_scene;
MenuButton *object_menu;
@@ -204,35 +255,49 @@ class EditorNode : public Node {
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;
Control *scene_root_base;
+ Ref<Theme> theme;
PopupMenu *recent_scenes;
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;
ConfirmationDialog *open_recent_confirmation;
AcceptDialog *accept;
AcceptDialog *about;
+ AcceptDialog *warning;
+
+ Ref<ConfigFile> default_theme;
+ PopupMenu *editor_layouts;
+ EditorLayoutDialog *layout_dialog;
+ AcceptDialog *confirm_error;
//OptimizedPresetsDialog *optimized_presets;
EditorSettingsDialog *settings_config_dialog;
RunSettingsDialog *run_settings_dialog;
ProjectSettings *project_settings;
- FileDialog *file;
+ EditorFileDialog *file;
FileDialog *file_templates;
FileDialog *file_export;
FileDialog *file_export_lib;
@@ -243,8 +308,8 @@ class EditorNode : public Node {
String current_path;
MenuButton *update_menu;
ToolButton *sources_button;
- TabContainer *prop_pallete;
- TabContainer *top_pallete;
+ //TabContainer *prop_pallete;
+ //TabContainer *top_pallete;
String defer_load_scene;
String defer_translatable;
String defer_optimize;
@@ -257,12 +322,18 @@ class EditorNode : public Node {
HBoxContainer *animation_panel_hb;
VBoxContainer *animation_vb;
EditorPath *editor_path;
+ ToolButton *resource_new_button;
+ ToolButton *resource_load_button;
+ MenuButton *resource_save_button;
+ MenuButton *editor_history_menu;
AnimationKeyEditor *animation_editor;
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;
@@ -271,6 +342,20 @@ 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;
+ PopupPanel *dock_select_popoup;
+ Control *dock_select;
+ ToolButton *dock_tab_move_left;
+ ToolButton *dock_tab_move_right;
+ int dock_popup_selected;
+ Timer *dock_drag_timer;
+
String _tmp_import_path;
EditorImportExport *editor_import_export;
@@ -281,8 +366,10 @@ class EditorNode : public Node {
bool reference_resource_mem;
bool save_external_resources_mem;
uint64_t saved_version;
+ uint64_t last_checked_version;
bool unsaved_cache;
String open_navigate;
+ bool changing_scene;
uint32_t circle_step_msec;
uint64_t circle_step_frame;
@@ -298,6 +385,7 @@ class EditorNode : public Node {
EditorSelection *editor_selection;
ProjectExport *project_export;
ProjectExportDialog *project_export_settings;
+ EditorResourcePreview *resource_preview;
EditorFileServer *file_server;
@@ -313,6 +401,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();
@@ -321,6 +410,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);
@@ -331,16 +423,19 @@ class EditorNode : public Node {
void _set_scene_metadata();
void _get_scene_metadata();
void _update_title();
+ void _update_scene_tabs();
void _close_messages();
void _show_messages();
void _vp_resized();
+ void _rebuild_import_menu();
+
void _save_scene(String p_file);
void _instance_request(const String& p_path);
- void _property_keyed(const String& p_keyed,const Variant& p_value);
+ 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();
@@ -356,7 +451,7 @@ class EditorNode : public Node {
void _add_to_recent_scenes(const String& p_scene);
void _update_recent_scenes();
void _open_recent_scene(int p_idx);
- void _open_recent_scene_confirm();
+ //void _open_recent_scene_confirm();
String _recent_scene;
bool convert_old;
@@ -373,18 +468,37 @@ class EditorNode : public Node {
String import_reload_fn;
Set<FileDialog*> file_dialogs;
+ Set<EditorFileDialog*> editor_file_dialogs;
+
Map<String,Ref<Texture> > icon_type_cache;
static Ref<Texture> _file_dialog_get_icon(const String& p_path);
static void _file_dialog_register(FileDialog *p_dialog);
static void _file_dialog_unregister(FileDialog *p_dialog);
+ static void _editor_file_dialog_register(EditorFileDialog *p_dialog);
+ static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog);
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);
+
+ void _find_node_types(Node* p_node, int&count_2d, int&count_3d);
+ void _save_scene_with_preview(String p_file);
- bool _find_and_save_edited_subresources(Object *obj,Set<RES>& processed,int32_t flags);
- void _save_edited_subresources(Node* scene,Set<RES>& processed,int32_t flags);
+ 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;
@@ -400,12 +514,44 @@ class EditorNode : public Node {
bool _find_scene_in_use(Node* p_node,const String& p_path) const;
+ void _dock_select_input(const InputEvent& p_input);
+ void _dock_move_left();
+ void _dock_move_right();
+ void _dock_select_draw();
+ void _dock_pre_popup(int p_which);
+ 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();
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; }
@@ -416,10 +562,15 @@ public:
static void add_editor_plugin(EditorPlugin *p_editor);
static void remove_editor_plugin(EditorPlugin *p_editor);
+ void add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
+ void remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
+
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);
@@ -431,7 +582,7 @@ public:
void open_request(const String& p_path);
- void set_edited_scene(Node *p_scene);
+ bool is_changing_scene() const;
static EditorLog *get_log() { return singleton->log; }
@@ -444,15 +595,23 @@ public:
void hide_animation_player_editors();
void animation_panel_make_visible(bool p_visible);
- Node *get_edited_scene() { return edited_scene; }
+ void set_edited_scene(Node *p_scene);
+
+ Node *get_edited_scene() { return editor_data.get_edited_scene_root(); }
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; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
@@ -471,6 +630,12 @@ public:
void stop_child_process();
+ Ref<Theme> get_editor_theme() const { return theme; }
+
+
+ void show_warning(const String& p_text);
+
+
Error export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after=false);
static void register_editor_types();
@@ -493,6 +658,9 @@ public:
bool is_scene_in_use(const String& p_path);
void scan_import_changes();
+
+ void save_layout();
+
EditorNode();
~EditorNode();
void get_singleton(const char* arg1, bool arg2);
diff --git a/tools/editor/editor_path.cpp b/tools/editor/editor_path.cpp
index 6c283d1f09..94e2efe346 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -73,14 +73,24 @@ 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>()) {
name=obj->cast_to<Node>()->get_name();
- } else
+ } else if (obj->cast_to<Resource>() && obj->cast_to<Resource>()->get_name()!="") {
+ name=obj->cast_to<Resource>()->get_name();
+ } else {
name=obj->get_type();
+ }
+
+ set_tooltip(obj->get_type());
+
label_font->draw(ci,Point2i(ofs,(size.height-label_font->get_height())/2+label_font->get_ascent()),name,Color(1,1,1),left);
} else {
diff --git a/tools/editor/editor_path.h b/tools/editor/editor_path.h
index effa87b423..2edaeb92a3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/editor_plugin.cpp b/tools/editor/editor_plugin.cpp
index 2a2ad63d32..7417d707bb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -73,6 +73,13 @@ void EditorPlugin::add_custom_control(CustomControlContainer p_location,Control
} break;
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: {
+
+ CanvasItemEditor::get_singleton()->get_bottom_split()->add_child(p_control);
} break;
@@ -191,6 +198,13 @@ bool EditorPlugin::get_remove_list(List<Node*> *p_list) {
void EditorPlugin::restore_global_state() {}
void EditorPlugin::save_global_state() {}
+void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
+
+}
+
+void EditorPlugin::get_window_layout(Ref<ConfigFile> p_layout){
+
+}
void EditorPlugin::_bind_methods() {
diff --git a/tools/editor/editor_plugin.h b/tools/editor/editor_plugin.h
index bcde0f73fb..6850be2eaa 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@
#include "scene/main/node.h"
#include "scene/resources/texture.h"
#include "undo_redo.h"
-
+#include "io/config_file.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -66,7 +66,8 @@ public:
CONTAINER_SPATIAL_EDITOR_SIDE,
CONTAINER_SPATIAL_EDITOR_BOTTOM,
CONTAINER_CANVAS_EDITOR_MENU,
- CONTAINER_CANVAS_EDITOR_SIDE
+ CONTAINER_CANVAS_EDITOR_SIDE,
+ CONTAINER_CANVAS_EDITOR_BOTTOM
};
//TODO: send a resoucre for editing to the editor node?
@@ -89,6 +90,9 @@ public:
virtual void apply_changes() ; // if changes are pending in editor, apply them
virtual void get_breakpoints(List<String> *p_breakpoints);
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 034ac58a8e..8842a485b3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,7 +33,7 @@ void EditorReImportDialog::popup_reimport() {
if (EditorFileSystem::get_singleton()->is_scanning()) {
error->set_text("Please wait for scan to complete");
- error->popup_centered(Size2(250,100));
+ error->popup_centered_minsize();
return;
}
@@ -70,7 +70,7 @@ void EditorReImportDialog::popup_reimport() {
if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->get_filename()=="") {
error->set_text("Current scene must be saved to re-import.");
- error->popup_centered(Size2(250,100));
+ error->popup_centered_minsize();
get_ok()->set_text("Re-Import");
get_ok()->set_disabled(true);
return;
@@ -93,7 +93,7 @@ void EditorReImportDialog::ok_pressed() {
if (EditorFileSystem::get_singleton()->is_scanning()) {
error->set_text("Please wait for scan to complete");
- error->popup_centered(Size2(250,100));
+ error->popup_centered_minsize();
return;
}
diff --git a/tools/editor/editor_reimport_dialog.h b/tools/editor/editor_reimport_dialog.h
index a5fac262fc..9726bac805 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/editor_resource_preview.cpp b/tools/editor/editor_resource_preview.cpp
new file mode 100644
index 0000000000..f684b49a2c
--- /dev/null
+++ b/tools/editor/editor_resource_preview.cpp
@@ -0,0 +1,261 @@
+#include "editor_resource_preview.h"
+#include "editor_settings.h"
+#include "os/file_access.h"
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "globals.h"
+
+
+Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String& p_path) {
+
+ RES res = ResourceLoader::load(p_path);
+ if (!res.is_valid())
+ return res;
+ return generate(res);
+}
+
+EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
+
+
+}
+
+
+EditorResourcePreview* EditorResourcePreview::singleton=NULL;
+
+
+void EditorResourcePreview::_thread_func(void *ud) {
+
+ EditorResourcePreview *erp=(EditorResourcePreview*)ud;
+ erp->_thread();
+
+}
+
+
+void EditorResourcePreview::_preview_ready(const String& p_str,const Ref<Texture>& p_texture,ObjectID id,const StringName& p_func,const Variant& p_ud) {
+
+ //print_line("preview is ready");
+ preview_mutex->lock();
+
+ Item item;
+ item.order=order++;
+ item.preview=p_texture;
+ cache[p_str]=item;
+
+ Object *recv = ObjectDB::get_instance(id);
+ if (recv) {
+ recv->call_deferred(p_func,p_str,p_texture,p_ud);
+ }
+
+ preview_mutex->unlock();
+}
+
+Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem& p_item,const String& cache_base) {
+
+ String type = ResourceLoader::get_resource_type(p_item.path);
+ //print_line("resource type is: "+type);
+
+ if (type=="")
+ return Ref<Texture>(); //could not guess type
+
+ Ref<Texture> generated;
+
+ for(int i=0;i<preview_generators.size();i++) {
+ if (!preview_generators[i]->handles(type))
+ continue;
+ generated = preview_generators[i]->generate_from_path(p_item.path);
+
+ break;
+ }
+
+ if (generated.is_valid()) {
+ //print_line("was generated");
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ //wow it generated a preview... save cache
+ ResourceSaver::save(cache_base+".png",generated);
+ FileAccess *f=FileAccess::open(cache_base+".txt",FileAccess::WRITE);
+ f->store_line(itos(thumbnail_size));
+ f->store_line(itos(FileAccess::get_modified_time(p_item.path)));
+ f->store_line(FileAccess::get_md5(p_item.path));
+ memdelete(f);
+ } else {
+ //print_line("was not generated");
+
+ }
+
+ return generated;
+}
+
+void EditorResourcePreview::_thread() {
+
+ //print_line("begin thread");
+ while(!exit) {
+
+ //print_line("wait for semaphore");
+ preview_sem->wait();
+ preview_mutex->lock();
+
+ //print_line("blue team go");
+
+ if (queue.size()) {
+
+
+
+ QueueItem item = queue.front()->get();
+ queue.pop_front();
+ preview_mutex->unlock();
+
+ Ref<Texture> texture;
+
+ //print_line("pop from queue "+item.path);
+
+ uint64_t modtime = FileAccess::get_modified_time(item.path);
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+
+ if (cache.has(item.path)) {
+ //already has it because someone loaded it, just let it know it's ready
+ call_deferred("_preview_ready",item.path,cache[item.path].preview,item.id,item.function,item.userdata);
+
+ } else {
+
+
+ String temp_path=EditorSettings::get_singleton()->get_settings_path().plus_file("tmp");
+ String cache_base = Globals::get_singleton()->globalize_path(item.path).md5_text();
+ cache_base = temp_path.plus_file("resthumb-"+cache_base);
+
+ //does not have it, try to load a cached thumbnail
+
+ String file = cache_base+".txt";
+ //print_line("cachetxt at "+file);
+ FileAccess *f=FileAccess::open(file,FileAccess::READ);
+ if (!f) {
+
+ //print_line("generate because not cached");
+
+ //generate
+ texture=_generate_preview(item,cache_base);
+ } else {
+
+ int tsize = f->get_line().to_int64();
+ uint64_t last_modtime = f->get_line().to_int64();
+
+ bool cache_valid = true;
+
+ if (tsize!=thumbnail_size) {
+ cache_valid=false;
+ memdelete(f);
+ } else if (last_modtime!=modtime) {
+
+ String last_md5 = f->get_line();
+ String md5 = FileAccess::get_md5(item.path);
+ memdelete(f);
+
+ if (last_md5!=md5) {
+
+ cache_valid=false;
+ } else {
+ //update modified time
+
+ f=FileAccess::open(file,FileAccess::WRITE);
+ f->store_line(itos(modtime));
+ f->store_line(md5);
+ memdelete(f);
+ }
+ } else {
+ memdelete(f);
+ }
+
+ if (cache_valid) {
+
+ texture = ResourceLoader::load(cache_base+".png","ImageTexture",true);
+ if (!texture.is_valid()) {
+ //well fuck
+ cache_valid=false;
+ }
+ }
+
+ if (!cache_valid) {
+
+ texture=_generate_preview(item,cache_base);
+ }
+
+ }
+
+ //print_line("notify of preview ready");
+ call_deferred("_preview_ready",item.path,texture,item.id,item.function,item.userdata);
+
+ }
+
+ } else {
+ preview_mutex->unlock();
+ }
+
+ }
+}
+
+
+
+
+void EditorResourcePreview::queue_resource_preview(const String& p_path, Object* p_receiver, const StringName& p_receiver_func, const Variant& p_userdata) {
+
+ ERR_FAIL_NULL(p_receiver);
+ preview_mutex->lock();
+ if (cache.has(p_path)) {
+ cache[p_path].order=order++;
+ p_receiver->call_deferred(p_receiver_func,p_path,cache[p_path].preview,p_userdata);
+ preview_mutex->unlock();
+ return;
+
+ }
+
+ //print_line("send to thread "+p_path);
+ QueueItem item;
+ item.function=p_receiver_func;
+ item.id=p_receiver->get_instance_ID();
+ item.path=p_path;
+ item.userdata=p_userdata;
+
+ queue.push_back(item);
+ preview_mutex->unlock();
+ preview_sem->post();
+
+}
+
+void EditorResourcePreview::add_preview_generator(const Ref<EditorResourcePreviewGenerator>& p_generator) {
+
+ preview_generators.push_back(p_generator);
+}
+
+EditorResourcePreview* EditorResourcePreview::get_singleton() {
+
+ return singleton;
+}
+
+void EditorResourcePreview::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_preview_ready",&EditorResourcePreview::_preview_ready);
+}
+
+EditorResourcePreview::EditorResourcePreview() {
+ singleton=this;
+ preview_mutex = Mutex::create();
+ preview_sem = Semaphore::create();
+ order=0;
+ exit=false;
+
+ thread = Thread::create(_thread_func,this);
+}
+
+
+EditorResourcePreview::~EditorResourcePreview()
+{
+
+ exit=true;
+ preview_sem->post();
+ Thread::wait_to_finish(thread);
+ memdelete(thread);
+ memdelete(preview_mutex);
+ memdelete(preview_sem);
+
+
+}
+
diff --git a/tools/editor/editor_resource_preview.h b/tools/editor/editor_resource_preview.h
new file mode 100644
index 0000000000..aadae75597
--- /dev/null
+++ b/tools/editor/editor_resource_preview.h
@@ -0,0 +1,95 @@
+#ifndef EDITORRESOURCEPREVIEW_H
+#define EDITORRESOURCEPREVIEW_H
+
+#include "scene/main/node.h"
+#include "os/semaphore.h"
+#include "os/thread.h"
+#include "scene/resources/texture.h"
+
+/* make previews for:
+*packdscene
+*wav
+*image
+*mesh
+-font
+*script
+*material
+-shader
+-shader graph?
+-navigation mesh
+-collision?
+-occluder polygon
+-navigation polygon
+-tileset
+-curve and curve2D
+*/
+
+
+class EditorResourcePreviewGenerator : public Reference {
+
+ OBJ_TYPE(EditorResourcePreviewGenerator,Reference );
+
+public:
+
+ virtual bool handles(const String& p_type) const=0;
+ virtual Ref<Texture> generate(const RES& p_from)=0;
+ virtual Ref<Texture> generate_from_path(const String& p_path);
+
+ EditorResourcePreviewGenerator();
+};
+
+
+class EditorResourcePreview : public Node {
+
+ OBJ_TYPE(EditorResourcePreview,Node);
+
+
+ static EditorResourcePreview* singleton;
+
+ struct QueueItem {
+ String path;
+ ObjectID id;
+ StringName function;
+ Variant userdata;
+ };
+
+ List<QueueItem> queue;
+
+ Mutex *preview_mutex;
+ Semaphore *preview_sem;
+ Thread *thread;
+ bool exit;
+
+ struct Item {
+ Ref<Texture> preview;
+ int order;
+ };
+
+ int order;
+
+ Map<String,Item> cache;
+
+ void _preview_ready(const String& p_str,const Ref<Texture>& p_texture, ObjectID id, const StringName &p_func, const Variant &p_ud);
+ Ref<Texture> _generate_preview(const QueueItem& p_item, const String &cache_base);
+
+ static void _thread_func(void *ud);
+ void _thread();
+
+ Vector<Ref<EditorResourcePreviewGenerator> > preview_generators;
+protected:
+
+ static void _bind_methods();
+public:
+
+ static EditorResourcePreview* get_singleton();
+
+ //callback funtion is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
+ void queue_resource_preview(const String& p_path, Object* p_receiver, const StringName& p_receiver_func, const Variant& p_userdata);
+
+ void add_preview_generator(const Ref<EditorResourcePreviewGenerator>& p_generator);
+
+ EditorResourcePreview();
+ ~EditorResourcePreview();
+};
+
+#endif // EDITORRESOURCEPREVIEW_H
diff --git a/tools/editor/editor_run.cpp b/tools/editor/editor_run.cpp
index d545b8d8f2..b635cea84b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 94a0f1878f..e1b0b081c7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 be1a124fc2..2eedba93dc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,7 +33,7 @@
void EditorRunNative::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
List<StringName> ep;
EditorImportExport::get_singleton()->get_export_platforms(&ep);
@@ -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 f4bda2d07d..77d6dc198e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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_run_script.cpp b/tools/editor/editor_run_script.cpp
index 5f8598d052..90581374f6 100644
--- a/tools/editor/editor_run_script.cpp
+++ b/tools/editor/editor_run_script.cpp
@@ -18,7 +18,7 @@ void EditorScript::add_root_node(Node *p_node) {
return;
}
- editor->set_edited_scene(p_node);
+// editor->set_edited_scene(p_node);
}
Node *EditorScript::get_scene() {
diff --git a/tools/editor/editor_selection.cpp b/tools/editor/editor_selection.cpp
index 890b31cd4d..d8fd8735fc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/editor_selection.h b/tools/editor/editor_selection.h
index 7f726e2446..f10f313a4e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp
index 0b896a725e..15de6e7266 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,7 +30,7 @@
#include "os/os.h"
#include "os/dir_access.h"
#include "os/file_access.h"
-#include "io/object_format_xml.h"
+
#include "version.h"
#include "scene/main/scene_main_loop.h"
#include "os/os.h"
@@ -224,6 +224,28 @@ void EditorSettings::create() {
dir->change_dir("..");
}
+ if (dir->change_dir("config")!=OK) {
+ dir->make_dir("config");
+ } else {
+
+ dir->change_dir("..");
+ }
+
+ dir->change_dir("config");
+
+ String pcp=Globals::get_singleton()->get_resource_path();
+ if (pcp.ends_with("/"))
+ pcp=config_path.substr(0,pcp.size()-1);
+ pcp=pcp.get_file()+"-"+pcp.md5_text();
+
+ if (dir->change_dir(pcp)) {
+ dir->make_dir(pcp);
+ } else {
+ dir->change_dir("..");
+ }
+
+ dir->change_dir("..");
+
// path at least is validated, so validate config file
@@ -244,6 +266,7 @@ void EditorSettings::create() {
}
singleton->config_file_path=config_file_path;
+ singleton->project_config_path=pcp;
singleton->settings_path=config_path+"/"+config_dir;
if (OS::get_singleton()->is_stdout_verbose()) {
@@ -251,7 +274,8 @@ void EditorSettings::create() {
print_line("EditorSettings: Load OK!");
}
-
+ singleton->setup_network();
+ singleton->load_favorites();
singleton->scan_plugins();
return;
@@ -264,7 +288,9 @@ void EditorSettings::create() {
singleton = Ref<EditorSettings>( memnew( EditorSettings ) );
singleton->config_file_path=config_file_path;
+ singleton->settings_path=config_path+"/"+config_dir;
singleton->_load_defaults();
+ singleton->setup_network();
singleton->scan_plugins();
@@ -306,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;
@@ -386,7 +441,13 @@ void EditorSettings::_load_defaults() {
set("global/font","");
hints["global/font"]=PropertyInfo(Variant::STRING,"global/font",PROPERTY_HINT_GLOBAL_FILE,"*.fnt");
-
+ set("global/autoscan_project_path","");
+ hints["global/autoscan_project_path"]=PropertyInfo(Variant::STRING,"global/autoscan_project_path",PROPERTY_HINT_GLOBAL_DIR);
+ set("global/default_project_path","");
+ 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"));
@@ -397,14 +458,23 @@ void EditorSettings::_load_defaults() {
set("text_editor/string_color",Color::html("ef6ebe"));
set("text_editor/symbol_color",Color::html("badfff"));
set("text_editor/selection_color",Color::html("7b5dbe"));
+ set("text_editor/brace_mismatch_color",Color(1,0.2,0.2));
+ set("text_editor/current_line_color",Color(0.3,0.5,0.8,0.15));
set("text_editor/idle_parse_delay",2);
set("text_editor/create_signal_callbacks",true);
- set("text_editor/autosave_interval_seconds",60);
+ set("text_editor/autosave_interval_secs",0);
+
set("text_editor/font","");
- set("text_editor/auto_brace_complete", false);
hints["text_editor/font"]=PropertyInfo(Variant::STRING,"text_editor/font",PROPERTY_HINT_GLOBAL_FILE,"*.fnt");
+ set("text_editor/auto_brace_complete", false);
+ set("text_editor/restore_scripts_on_load",true);
+
+ 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);
@@ -412,6 +482,8 @@ void EditorSettings::_load_defaults() {
set("3d_editor/navigation_scheme",0);
hints["3d_editor/navigation_scheme"]=PropertyInfo(Variant::INT,"3d_editor/navigation_scheme",PROPERTY_HINT_ENUM,"Godot,Maya,Modo");
+ set("3d_editor/zoom_style",0);
+ hints["3d_editor/zoom_style"]=PropertyInfo(Variant::INT,"3d_editor/zoom_style",PROPERTY_HINT_ENUM,"Vertical, Horizontal");
set("3d_editor/orbit_modifier",0);
hints["3d_editor/orbit_modifier"]=PropertyInfo(Variant::INT,"3d_editor/orbit_modifier",PROPERTY_HINT_ENUM,"None,Shift,Alt,Meta,Ctrl");
set("3d_editor/pan_modifier",1);
@@ -425,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);
@@ -432,10 +514,15 @@ void EditorSettings::_load_defaults() {
set("text_editor/create_signal_callbacks",true);
+ set("file_dialog/show_hidden_files", false);
+ set("file_dialog/thumbnail_size", 64);
+ hints["file_dialog/thumbnail_size"]=PropertyInfo(Variant::INT,"file_dialog/thumbnail_size",PROPERTY_HINT_RANGE,"32,128,16");
set("animation/autorename_animation_tracks",true);
+ set("animation/confirm_insert_track",true);
set("property_editor/texture_preview_width",48);
+ set("property_editor/auto_refresh_interval",0.3);
set("help/doc_path","");
set("import/ask_save_before_reimport",false);
@@ -458,10 +545,10 @@ void EditorSettings::notify_changes() {
_THREAD_SAFE_METHOD_
- SceneMainLoop *sml=NULL;
+ SceneTree *sml=NULL;
if (OS::get_singleton()->get_main_loop())
- sml = OS::get_singleton()->get_main_loop()->cast_to<SceneMainLoop>();
+ sml = OS::get_singleton()->get_main_loop()->cast_to<SceneTree>();
if (!sml) {
print_line("not SML");
@@ -628,6 +715,71 @@ void EditorSettings::set_plugin_enabled(const String& p_plugin, bool p_enabled)
}
+void EditorSettings::set_favorite_dirs(const Vector<String>& p_favorites) {
+
+ favorite_dirs=p_favorites;
+ FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"),FileAccess::WRITE);
+ if (f) {
+ for(int i=0;i<favorite_dirs.size();i++)
+ f->store_line(favorite_dirs[i]);
+ memdelete(f);
+ }
+
+}
+
+Vector<String> EditorSettings::get_favorite_dirs() const {
+
+ return favorite_dirs;
+}
+
+
+void EditorSettings::set_recent_dirs(const Vector<String>& p_recent) {
+
+ recent_dirs=p_recent;
+ FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"),FileAccess::WRITE);
+ if (f) {
+ for(int i=0;i<recent_dirs.size();i++)
+ f->store_line(recent_dirs[i]);
+ memdelete(f);
+ }
+}
+
+Vector<String> EditorSettings::get_recent_dirs() const {
+
+ return recent_dirs;
+}
+
+String EditorSettings::get_project_settings_path() const {
+
+
+ return get_settings_path().plus_file("config").plus_file(project_config_path);
+}
+
+
+void EditorSettings::load_favorites() {
+
+ FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"),FileAccess::READ);
+ if (f) {
+ String line = f->get_line().strip_edges();
+ while(line!="") {
+ favorite_dirs.push_back(line);
+ line = f->get_line().strip_edges();
+ }
+ memdelete(f);
+ }
+
+ f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"),FileAccess::READ);
+ if (f) {
+ String line = f->get_line().strip_edges();
+ while(line!="") {
+ recent_dirs.push_back(line);
+ line = f->get_line().strip_edges();
+ }
+ memdelete(f);
+ }
+
+}
+
void EditorSettings::_bind_methods() {
diff --git a/tools/editor/editor_settings.h b/tools/editor/editor_settings.h
index c44afd9593..bdfa5160d6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -88,6 +88,11 @@ private:
void _load_defaults();
+ String project_config_path;
+
+ Vector<String> favorite_dirs;
+ Vector<String> recent_dirs;
+
protected:
static void _bind_methods();
@@ -102,11 +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();
@@ -125,6 +133,14 @@ public:
void add_property_hint(const PropertyInfo& p_hint);
+ void set_favorite_dirs(const Vector<String>& p_favorite_dirs);
+ Vector<String> get_favorite_dirs() const;
+
+ void set_recent_dirs(const Vector<String>& p_recent_dirs);
+ Vector<String> get_recent_dirs() const;
+
+ void load_favorites();
+
EditorSettings();
~EditorSettings();
diff --git a/tools/editor/editor_shape_gizmos.cpp b/tools/editor/editor_shape_gizmos.cpp
deleted file mode 100644
index df7332b64a..0000000000
--- a/tools/editor/editor_shape_gizmos.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/*************************************************************************/
-/* editor_shape_gizmos.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#include "editor_shape_gizmos.h"
-
-
-
-
-
-
-String EditableShapeSpatialGizmo::get_handle_name(int p_idx) const {
-
- if (es->cast_to<EditableSphere>()) {
-
- return "Radius";
- }
-#if 0
- if (es->cast_to<EditableBox>()) {
-
- return "Extents";
- }
-
- if (es->cast_to<EditableCapsule>()) {
-
- return p_idx==0?"Radius":"Height";
- }
-
- if (es->cast_to<EditableRay>()) {
-
- return "Length";
- }
-#endif
- return "";
-}
-Variant EditableShapeSpatialGizmo::get_handle_value(int p_idx) const{
-
- if (es->cast_to<EditableSphere>()) {
-
- EditableSphere *ss = es->cast_to<EditableSphere>();
- return ss->get_radius();
- }
-#if 0
- if (es->cast_to<EditableBox>()) {
-
- EditableBox *bs = es->cast_to<EditableBox>();
- return bs->get_extents();
- }
-
- if (es->cast_to<EditableCapsule>()) {
-
- EditableCapsule *cs = es->cast_to<EditableCapsule>();
- return p_idx==0?es->get_radius():es->get_height();
- }
-
- if (es->cast_to<EditableRay>()) {
-
- EditableRay* cs = es->cast_to<EditableRay>();
- return es->get_length();
- }
-#endif
- return Variant();
-}
-void EditableShapeSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
-
- Transform gt = es->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 (es->cast_to<EditableSphere>()) {
-
- EditableSphere *ss = es->cast_to<EditableSphere>();
- 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 0
- if (es->cast_to<EditableRay>()) {
-
- EditableRay*cs = es->cast_to<EditableRay>();
- 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 (es->cast_to<EditableBox>()) {
-
- Vector3 axis;
- axis[p_idx]=1.0;
- EditableBox *bs = es->cast_to<EditableBox>();
- 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 (es->cast_to<EditableCapsule>()) {
-
- Vector3 axis;
- axis[p_idx]=1.0;
- EditableCapsule *cs = es->cast_to<EditableCapsule>();
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(Vector3(),axis*4096,sg[0],sg[1],ra,rb);
- float d = ra[p_idx];
- if (p_idx==1)
- d-=es->get_radius();
- if (d<0.001)
- d=0.001;
-
- if (p_idx==0)
- es->set_radius(d);
- else if (p_idx==1)
- es->set_height(d*2.0);
-
- }
-
-#endif
-
-}
-void EditableShapeSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
-
-
- if (es->cast_to<EditableSphere>()) {
-
- EditableSphere *ss = es->cast_to<EditableSphere>();
- 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,"set_radius",ss->get_radius());
- ur->add_undo_method(ss,"set_radius",p_restore);
- ur->commit_action();
-
- }
-#if 0
- if (es->cast_to<EditableBox>()) {
-
- EditableBox *ss = es->cast_to<EditableBox>();
- 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,"set_extents",ss->get_extents());
- ur->add_undo_method(ss,"set_extents",p_restore);
- ur->commit_action();
- }
-
- if (es->cast_to<EditableCapsule>()) {
-
- EditableCapsule *cs = es->cast_to<EditableCapsule>();
- 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,"set_radius",ss->get_radius());
- ur->add_undo_method(ss,"set_radius",p_restore);
- } else {
- ur->create_action("Change Capsule Shape Height");
- ur->add_do_method(ss,"set_height",ss->get_height());
- ur->add_undo_method(ss,"set_height",p_restore);
-
- }
-
- ur->commit_action();
-
- }
-
- if (es->cast_to<EditableRay>()) {
-
- EditableRay*rs = es->cast_to<EditableRay>()
- 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,"set_length",ss->get_length());
- ur->add_undo_method(ss,"set_length",p_restore);
- ur->commit_action();
-
- }
-#endif
-}
-void EditableShapeSpatialGizmo::redraw(){
-
- clear();
-
- if (es->cast_to<EditableSphere>()) {
-
- EditableSphere* sp= es->cast_to<EditableSphere>();
- 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 0
- if (es->cast_to<EditableBox>()) {
-
- EditableBox*bs = es->cast_to<EditableBox>();
- 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 (es->cast_to<EditableCapsule>()) {
-
- EditableCapsule *cs = es->cast_to<EditableCapsule>();
- float radius = es->get_radius();
- float height = es->get_height();
-
-
- Vector<Vector3> points;
-
- Vector3 d(0,height*0.5,0);
- 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,0,a.y)+d);
- points.push_back(Vector3(b.x,0,b.y)+d);
-
- points.push_back(Vector3(a.x,0,a.y)-d);
- points.push_back(Vector3(b.x,0,b.y)-d);
-
- if (i%90==0) {
-
- points.push_back(Vector3(a.x,0,a.y)+d);
- points.push_back(Vector3(a.x,0,a.y)-d);
- }
-
- Vector3 dud = i<180?d:-d;
-
- points.push_back(Vector3(0,a.x,a.y)+dud);
- points.push_back(Vector3(0,b.x,b.y)+dud);
- points.push_back(Vector3(a.y,a.x,0)+dud);
- points.push_back(Vector3(b.y,b.x,0)+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,0,a.y)+d);
- collision_segments.push_back(Vector3(b.x,0,b.y)+d);
-
- collision_segments.push_back(Vector3(a.x,0,a.y)-d);
- collision_segments.push_back(Vector3(b.x,0,b.y)-d);
-
- if (i%16==0) {
-
- collision_segments.push_back(Vector3(a.x,0,a.y)+d);
- collision_segments.push_back(Vector3(a.x,0,a.y)-d);
- }
-
- Vector3 dud = i<32?d:-d;
-
- collision_segments.push_back(Vector3(0,a.x,a.y)+dud);
- collision_segments.push_back(Vector3(0,b.x,b.y)+dud);
- collision_segments.push_back(Vector3(a.y,a.x,0)+dud);
- collision_segments.push_back(Vector3(b.y,b.x,0)+dud);
-
- }
-
- add_collision_segments(collision_segments);
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(es->get_radius(),0,0));
- handles.push_back(Vector3(0,es->get_height()*0.5+es->get_radius(),0));
- add_handles(handles);
-
-
- }
-
- if (es->cast_to<EditablePlane>()) {
-
- EditablePlane* ps=es->cast_to<EditablePlane();
- 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 (es->cast_to<EditableRay>()) {
-
- EditableRay*cs = es->cast_to<EditableRay>();
-
- 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);
-
-
- }
-
-#endif
-
-}
-EditableShapeSpatialGizmo::EditableShapeSpatialGizmo(EditableShape* p_cs) {
-
- es=p_cs;
- set_spatial_node(p_cs);
-}
-
-
-
-EditorShapeGizmos::EditorShapeGizmos()
-{
-}
diff --git a/tools/editor/editor_shape_gizmos.h b/tools/editor/editor_shape_gizmos.h
deleted file mode 100644
index 4b5af49b4e..0000000000
--- a/tools/editor/editor_shape_gizmos.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*************************************************************************/
-/* editor_shape_gizmos.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#ifndef EDITOR_SHAPE_GIZMOS_H
-#define EDITOR_SHAPE_GIZMOS_H
-
-#include "spatial_editor_gizmos.h"
-#include "scene/3d/editable_shape.h"
-
-
-class EditableShapeSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(EditableShapeSpatialGizmo,SpatialGizmoTool);
-
- EditableShape *es;
-
-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();
- EditableShapeSpatialGizmo(EditableShape* p_cs=NULL);
-
-};
-
-
-
-class EditorShapeGizmos
-{
-public:
- EditorShapeGizmos();
-};
-
-#endif // EDITOR_SHAPE_GIZMOS_H
diff --git a/tools/editor/editor_sub_scene.cpp b/tools/editor/editor_sub_scene.cpp
index 25a52bb2cd..2a6eba2554 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -215,7 +215,7 @@ EditorSubScene::EditorSubScene() {
tree->set_v_size_flags(SIZE_EXPAND_FILL);
vb->add_margin_child("Import From Node:",tree)->set_v_size_flags(SIZE_EXPAND_FILL);
- file_dialog = memnew( FileDialog );
+ file_dialog = memnew( EditorFileDialog );
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions);
@@ -224,7 +224,7 @@ EditorSubScene::EditorSubScene() {
file_dialog->add_filter("*."+E->get());
}
- file_dialog->set_mode(FileDialog::MODE_OPEN_FILE);
+ file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
add_child(file_dialog);
file_dialog->connect("file_selected",this,"_path_selected");
diff --git a/tools/editor/editor_sub_scene.h b/tools/editor/editor_sub_scene.h
index 8f5e864eb9..dfd6c531e2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,7 @@
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
-#include "scene/gui/file_dialog.h"
+#include "tools/editor/editor_file_dialog.h"
class EditorSubScene : public ConfirmationDialog {
@@ -42,7 +42,7 @@ class EditorSubScene : public ConfirmationDialog {
Tree *tree;
Node *scene;
- FileDialog *file_dialog;
+ EditorFileDialog *file_dialog;
void _fill_tree(Node* p_node,TreeItem *p_parent);
void _reown(Node* p_node,List<Node*> *p_to_reown);
diff --git a/tools/editor/editor_vu.cpp b/tools/editor/editor_vu.cpp
index cd0e75f22d..ac11aceb21 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/editor_vu.h b/tools/editor/editor_vu.h
index f8fef8b510..4c51ac31c0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/file_type_cache.cpp b/tools/editor/file_type_cache.cpp
index f00fc8fe1a..a86400a560 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/file_type_cache.h b/tools/editor/file_type_cache.h
index bb89718a55..efc6d22b25 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 f21d9b4ec1..ea95e4da1c 100644
--- a/tools/editor/fileserver/editor_file_server.cpp
+++ b/tools/editor/fileserver/editor_file_server.cpp
@@ -278,6 +278,7 @@ void EditorFileServer::_thread_start(void*s) {
self->to_wait.erase(w);
self->wait_mutex->unlock();
Thread::wait_to_finish(w);
+ memdelete(w);
self->wait_mutex->lock();
}
self->wait_mutex->unlock();
@@ -317,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","");
}
@@ -346,5 +327,6 @@ EditorFileServer::~EditorFileServer() {
quit=true;
Thread::wait_to_finish(thread);
+ memdelete(thread);
memdelete(wait_mutex);
}
diff --git a/tools/editor/groups_editor.cpp b/tools/editor/groups_editor.cpp
index f0a2a6a758..bb5e93da34 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,148 +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_SCENE) {
- connect("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 6357358e1d..3a9cc77727 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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.png b/tools/editor/icons/icon_add.png
index 1a97f356d6..26283ca67c 100644
--- a/tools/editor/icons/icon_add.png
+++ b/tools/editor/icons/icon_add.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_animation.png b/tools/editor/icons/icon_animation.png
index 6af126bf37..ac663c0554 100644
--- a/tools/editor/icons/icon_animation.png
+++ b/tools/editor/icons/icon_animation.png
Binary files differ
diff --git a/tools/editor/icons/icon_arrow_left.png b/tools/editor/icons/icon_arrow_left.png
new file mode 100644
index 0000000000..b72ac2a10d
--- /dev/null
+++ b/tools/editor/icons/icon_arrow_left.png
Binary files differ
diff --git a/tools/editor/icons/icon_arrow_left_disabled.png b/tools/editor/icons/icon_arrow_left_disabled.png
new file mode 100644
index 0000000000..f1f9d0f988
--- /dev/null
+++ b/tools/editor/icons/icon_arrow_left_disabled.png
Binary files differ
diff --git a/tools/editor/icons/icon_arrow_right.png b/tools/editor/icons/icon_arrow_right.png
new file mode 100644
index 0000000000..d0a48b01ac
--- /dev/null
+++ b/tools/editor/icons/icon_arrow_right.png
Binary files differ
diff --git a/tools/editor/icons/icon_arrow_right_disabled.png b/tools/editor/icons/icon_arrow_right_disabled.png
new file mode 100644
index 0000000000..840cd0da0a
--- /dev/null
+++ b/tools/editor/icons/icon_arrow_right_disabled.png
Binary files differ
diff --git a/tools/editor/icons/icon_arrow_up.png b/tools/editor/icons/icon_arrow_up.png
new file mode 100644
index 0000000000..10aac0e0f6
--- /dev/null
+++ b/tools/editor/icons/icon_arrow_up.png
Binary files differ
diff --git a/tools/editor/icons/icon_arrow_up_disabled.png b/tools/editor/icons/icon_arrow_up_disabled.png
new file mode 100644
index 0000000000..fb46aa1373
--- /dev/null
+++ b/tools/editor/icons/icon_arrow_up_disabled.png
Binary files differ
diff --git a/tools/editor/icons/icon_atlas_texture.png b/tools/editor/icons/icon_atlas_texture.png
index 3da9f0bee4..0051b0cda4 100644
--- a/tools/editor/icons/icon_atlas_texture.png
+++ b/tools/editor/icons/icon_atlas_texture.png
Binary files differ
diff --git a/tools/editor/icons/icon_audio_stream_gibberish.png b/tools/editor/icons/icon_audio_stream_gibberish.png
index f10671e8a2..95470c298e 100644
--- a/tools/editor/icons/icon_audio_stream_gibberish.png
+++ b/tools/editor/icons/icon_audio_stream_gibberish.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_auto_play.png b/tools/editor/icons/icon_auto_play.png
index e454ca8c7b..1d5c957cc7 100644
--- a/tools/editor/icons/icon_auto_play.png
+++ b/tools/editor/icons/icon_auto_play.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_back_buffer_copy.png b/tools/editor/icons/icon_back_buffer_copy.png
new file mode 100644
index 0000000000..b27eb39108
--- /dev/null
+++ b/tools/editor/icons/icon_back_buffer_copy.png
Binary files differ
diff --git a/tools/editor/icons/icon_back_disabled.png b/tools/editor/icons/icon_back_disabled.png
new file mode 100644
index 0000000000..31aab496e2
--- /dev/null
+++ b/tools/editor/icons/icon_back_disabled.png
Binary files differ
diff --git a/tools/editor/icons/icon_bake.png b/tools/editor/icons/icon_bake.png
index b1b0f941da..ae06ce48e6 100644
--- a/tools/editor/icons/icon_bake.png
+++ b/tools/editor/icons/icon_bake.png
Binary files differ
diff --git a/tools/editor/icons/icon_baked_light.png b/tools/editor/icons/icon_baked_light.png
new file mode 100644
index 0000000000..48039e264c
--- /dev/null
+++ b/tools/editor/icons/icon_baked_light.png
Binary files differ
diff --git a/tools/editor/icons/icon_baked_light_instance.png b/tools/editor/icons/icon_baked_light_instance.png
new file mode 100644
index 0000000000..77e53aa8f6
--- /dev/null
+++ b/tools/editor/icons/icon_baked_light_instance.png
Binary files differ
diff --git a/tools/editor/icons/icon_blend.png b/tools/editor/icons/icon_blend.png
index 985b63d5d1..2a75f0b2f4 100644
--- a/tools/editor/icons/icon_blend.png
+++ b/tools/editor/icons/icon_blend.png
Binary files differ
diff --git a/tools/editor/icons/icon_bone.png b/tools/editor/icons/icon_bone.png
index 174b0bc167..81b6d8856e 100644
--- a/tools/editor/icons/icon_bone.png
+++ b/tools/editor/icons/icon_bone.png
Binary files differ
diff --git a/tools/editor/icons/icon_bool.png b/tools/editor/icons/icon_bool.png
index d465b7da07..3381033b00 100644
--- a/tools/editor/icons/icon_bool.png
+++ b/tools/editor/icons/icon_bool.png
Binary files differ
diff --git a/tools/editor/icons/icon_canvas_item.png b/tools/editor/icons/icon_canvas_item.png
index 99403bed21..add54ba1af 100644
--- a/tools/editor/icons/icon_canvas_item.png
+++ b/tools/editor/icons/icon_canvas_item.png
Binary files differ
diff --git a/tools/editor/icons/icon_canvas_item_material.png b/tools/editor/icons/icon_canvas_item_material.png
new file mode 100644
index 0000000000..2fe8921653
--- /dev/null
+++ b/tools/editor/icons/icon_canvas_item_material.png
Binary files differ
diff --git a/tools/editor/icons/icon_canvas_item_shader.png b/tools/editor/icons/icon_canvas_item_shader.png
new file mode 100644
index 0000000000..a5f4e7bf85
--- /dev/null
+++ b/tools/editor/icons/icon_canvas_item_shader.png
Binary files differ
diff --git a/tools/editor/icons/icon_canvas_item_shader_graph.png b/tools/editor/icons/icon_canvas_item_shader_graph.png
new file mode 100644
index 0000000000..bba966b43e
--- /dev/null
+++ b/tools/editor/icons/icon_canvas_item_shader_graph.png
Binary files differ
diff --git a/tools/editor/icons/icon_canvas_modulate.png b/tools/editor/icons/icon_canvas_modulate.png
new file mode 100644
index 0000000000..2a34df7793
--- /dev/null
+++ b/tools/editor/icons/icon_canvas_modulate.png
Binary files differ
diff --git a/tools/editor/icons/icon_check_box.png b/tools/editor/icons/icon_check_box.png
new file mode 100644
index 0000000000..8a2b56cc3e
--- /dev/null
+++ b/tools/editor/icons/icon_check_box.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_close.png b/tools/editor/icons/icon_close.png
index 11fa746271..10e56d5bb8 100644
--- a/tools/editor/icons/icon_close.png
+++ b/tools/editor/icons/icon_close.png
Binary files differ
diff --git a/tools/editor/icons/icon_close_hover.png b/tools/editor/icons/icon_close_hover.png
index efcc9e7471..cb519691e5 100644
--- a/tools/editor/icons/icon_close_hover.png
+++ b/tools/editor/icons/icon_close_hover.png
Binary files differ
diff --git a/tools/editor/icons/icon_collapse.png b/tools/editor/icons/icon_collapse.png
index bd5c9765a5..23db9e42a7 100644
--- a/tools/editor/icons/icon_collapse.png
+++ b/tools/editor/icons/icon_collapse.png
Binary files differ
diff --git a/tools/editor/icons/icon_collapse_hl.png b/tools/editor/icons/icon_collapse_hl.png
index 7ed9a5c125..0dfbc8b175 100644
--- a/tools/editor/icons/icon_collapse_hl.png
+++ b/tools/editor/icons/icon_collapse_hl.png
Binary files differ
diff --git a/tools/editor/icons/icon_collision_polygon.png b/tools/editor/icons/icon_collision_polygon.png
new file mode 100644
index 0000000000..a82b43589e
--- /dev/null
+++ b/tools/editor/icons/icon_collision_polygon.png
Binary files differ
diff --git a/tools/editor/icons/icon_color_ramp.png b/tools/editor/icons/icon_color_ramp.png
new file mode 100644
index 0000000000..9031b5ec53
--- /dev/null
+++ b/tools/editor/icons/icon_color_ramp.png
Binary files differ
diff --git a/tools/editor/icons/icon_connect.png b/tools/editor/icons/icon_connect.png
index 24258414c4..745e445a61 100644
--- a/tools/editor/icons/icon_connect.png
+++ b/tools/editor/icons/icon_connect.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_curve_constant.png b/tools/editor/icons/icon_curve_constant.png
new file mode 100644
index 0000000000..cdeac1785e
--- /dev/null
+++ b/tools/editor/icons/icon_curve_constant.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_in.png b/tools/editor/icons/icon_curve_in.png
new file mode 100644
index 0000000000..2db202632e
--- /dev/null
+++ b/tools/editor/icons/icon_curve_in.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_in_out.png b/tools/editor/icons/icon_curve_in_out.png
new file mode 100644
index 0000000000..f4cb593496
--- /dev/null
+++ b/tools/editor/icons/icon_curve_in_out.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_linear.png b/tools/editor/icons/icon_curve_linear.png
new file mode 100644
index 0000000000..9467dc97a3
--- /dev/null
+++ b/tools/editor/icons/icon_curve_linear.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_out.png b/tools/editor/icons/icon_curve_out.png
new file mode 100644
index 0000000000..c91ade6f4a
--- /dev/null
+++ b/tools/editor/icons/icon_curve_out.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_out_in.png b/tools/editor/icons/icon_curve_out_in.png
new file mode 100644
index 0000000000..6499fa753e
--- /dev/null
+++ b/tools/editor/icons/icon_curve_out_in.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_default_project_icon.png b/tools/editor/icons/icon_default_project_icon.png
index 3e991fcc29..e87a49bd28 100644
--- a/tools/editor/icons/icon_default_project_icon.png
+++ b/tools/editor/icons/icon_default_project_icon.png
Binary files differ
diff --git a/tools/editor/icons/icon_del.png b/tools/editor/icons/icon_del.png
index 5349af466e..10e56d5bb8 100644
--- a/tools/editor/icons/icon_del.png
+++ b/tools/editor/icons/icon_del.png
Binary files differ
diff --git a/tools/editor/icons/icon_duplicate.png b/tools/editor/icons/icon_duplicate.png
index bae4aa2c30..f854a14fd3 100644
--- a/tools/editor/icons/icon_duplicate.png
+++ b/tools/editor/icons/icon_duplicate.png
Binary files differ
diff --git a/tools/editor/icons/icon_edit.png b/tools/editor/icons/icon_edit.png
index 012a7f5f1d..157f785b83 100644
--- a/tools/editor/icons/icon_edit.png
+++ b/tools/editor/icons/icon_edit.png
Binary files differ
diff --git a/tools/editor/icons/icon_edit_key.png b/tools/editor/icons/icon_edit_key.png
index 43a7056f38..9ab1287fc6 100644
--- a/tools/editor/icons/icon_edit_key.png
+++ b/tools/editor/icons/icon_edit_key.png
Binary files differ
diff --git a/tools/editor/icons/icon_edit_resource.png b/tools/editor/icons/icon_edit_resource.png
index de538dfe95..31d0c68fc6 100644
--- a/tools/editor/icons/icon_edit_resource.png
+++ b/tools/editor/icons/icon_edit_resource.png
Binary files differ
diff --git a/tools/editor/icons/icon_editor_focus.png b/tools/editor/icons/icon_editor_focus.png
index f21d22ebd8..40ce11f381 100644
--- a/tools/editor/icons/icon_editor_focus.png
+++ b/tools/editor/icons/icon_editor_focus.png
Binary files differ
diff --git a/tools/editor/icons/icon_enum.png b/tools/editor/icons/icon_enum.png
index 2496e1d0db..ac36c96e28 100644
--- a/tools/editor/icons/icon_enum.png
+++ b/tools/editor/icons/icon_enum.png
Binary files differ
diff --git a/tools/editor/icons/icon_event_player.png b/tools/editor/icons/icon_event_player.png
index b67f91b1b3..68646b3dfe 100644
--- a/tools/editor/icons/icon_event_player.png
+++ b/tools/editor/icons/icon_event_player.png
Binary files differ
diff --git a/tools/editor/icons/icon_favorites.png b/tools/editor/icons/icon_favorites.png
index da4713d032..4a3b575f95 100644
--- a/tools/editor/icons/icon_favorites.png
+++ b/tools/editor/icons/icon_favorites.png
Binary files differ
diff --git a/tools/editor/icons/icon_file_big.png b/tools/editor/icons/icon_file_big.png
new file mode 100644
index 0000000000..887a4ee05c
--- /dev/null
+++ b/tools/editor/icons/icon_file_big.png
Binary files differ
diff --git a/tools/editor/icons/icon_file_list.png b/tools/editor/icons/icon_file_list.png
new file mode 100644
index 0000000000..ab790a85a5
--- /dev/null
+++ b/tools/editor/icons/icon_file_list.png
Binary files differ
diff --git a/tools/editor/icons/icon_file_server.png b/tools/editor/icons/icon_file_server.png
index 27c99127c3..4bd94fa8c8 100644
--- a/tools/editor/icons/icon_file_server.png
+++ b/tools/editor/icons/icon_file_server.png
Binary files differ
diff --git a/tools/editor/icons/icon_file_thumbnail.png b/tools/editor/icons/icon_file_thumbnail.png
new file mode 100644
index 0000000000..c32be5e8f8
--- /dev/null
+++ b/tools/editor/icons/icon_file_thumbnail.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_folder.png b/tools/editor/icons/icon_folder.png
index 814f217edf..a450a7b297 100644
--- a/tools/editor/icons/icon_folder.png
+++ b/tools/editor/icons/icon_folder.png
Binary files differ
diff --git a/tools/editor/icons/icon_folder_big.png b/tools/editor/icons/icon_folder_big.png
new file mode 100644
index 0000000000..988e070f98
--- /dev/null
+++ b/tools/editor/icons/icon_folder_big.png
Binary files differ
diff --git a/tools/editor/icons/icon_font.png b/tools/editor/icons/icon_font.png
index d9554183c2..3ffe4f1b17 100644
--- a/tools/editor/icons/icon_font.png
+++ b/tools/editor/icons/icon_font.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_g_d_script.png b/tools/editor/icons/icon_g_d_script.png
index 3b1cc98c4d..88d865356c 100644
--- a/tools/editor/icons/icon_g_d_script.png
+++ b/tools/editor/icons/icon_g_d_script.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_graph_color_ramp.png b/tools/editor/icons/icon_graph_color_ramp.png
new file mode 100644
index 0000000000..9031b5ec53
--- /dev/null
+++ b/tools/editor/icons/icon_graph_color_ramp.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_comment.png b/tools/editor/icons/icon_graph_comment.png
new file mode 100644
index 0000000000..bf7889c510
--- /dev/null
+++ b/tools/editor/icons/icon_graph_comment.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_cube_uniform.png b/tools/editor/icons/icon_graph_cube_uniform.png
new file mode 100644
index 0000000000..d1b92b4943
--- /dev/null
+++ b/tools/editor/icons/icon_graph_cube_uniform.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_curve_map.png b/tools/editor/icons/icon_graph_curve_map.png
new file mode 100644
index 0000000000..de5c32f09e
--- /dev/null
+++ b/tools/editor/icons/icon_graph_curve_map.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_default_texture.png b/tools/editor/icons/icon_graph_default_texture.png
new file mode 100644
index 0000000000..da77ec9364
--- /dev/null
+++ b/tools/editor/icons/icon_graph_default_texture.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_input.png b/tools/editor/icons/icon_graph_input.png
new file mode 100644
index 0000000000..a396bc2350
--- /dev/null
+++ b/tools/editor/icons/icon_graph_input.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_rgb.png b/tools/editor/icons/icon_graph_rgb.png
new file mode 100644
index 0000000000..abffaedd34
--- /dev/null
+++ b/tools/editor/icons/icon_graph_rgb.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_rgb_op.png b/tools/editor/icons/icon_graph_rgb_op.png
new file mode 100644
index 0000000000..642fc838c2
--- /dev/null
+++ b/tools/editor/icons/icon_graph_rgb_op.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_rgb_uniform.png b/tools/editor/icons/icon_graph_rgb_uniform.png
new file mode 100644
index 0000000000..92c79997ef
--- /dev/null
+++ b/tools/editor/icons/icon_graph_rgb_uniform.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_scalar.png b/tools/editor/icons/icon_graph_scalar.png
new file mode 100644
index 0000000000..028d0e9ea4
--- /dev/null
+++ b/tools/editor/icons/icon_graph_scalar.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_scalar_interp.png b/tools/editor/icons/icon_graph_scalar_interp.png
new file mode 100644
index 0000000000..4f178a27c4
--- /dev/null
+++ b/tools/editor/icons/icon_graph_scalar_interp.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_scalar_op.png b/tools/editor/icons/icon_graph_scalar_op.png
new file mode 100644
index 0000000000..0fc4cae94c
--- /dev/null
+++ b/tools/editor/icons/icon_graph_scalar_op.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_scalar_uniform.png b/tools/editor/icons/icon_graph_scalar_uniform.png
new file mode 100644
index 0000000000..fc6590a8cf
--- /dev/null
+++ b/tools/editor/icons/icon_graph_scalar_uniform.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_scalars_to_vec.png b/tools/editor/icons/icon_graph_scalars_to_vec.png
new file mode 100644
index 0000000000..7ca39a2f56
--- /dev/null
+++ b/tools/editor/icons/icon_graph_scalars_to_vec.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_texscreen.png b/tools/editor/icons/icon_graph_texscreen.png
new file mode 100644
index 0000000000..e183a8fa56
--- /dev/null
+++ b/tools/editor/icons/icon_graph_texscreen.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_texture_uniform.png b/tools/editor/icons/icon_graph_texture_uniform.png
new file mode 100644
index 0000000000..7517ac1d92
--- /dev/null
+++ b/tools/editor/icons/icon_graph_texture_uniform.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_time.png b/tools/editor/icons/icon_graph_time.png
new file mode 100644
index 0000000000..b61e45589f
--- /dev/null
+++ b/tools/editor/icons/icon_graph_time.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vec_dp.png b/tools/editor/icons/icon_graph_vec_dp.png
new file mode 100644
index 0000000000..059c3025e7
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vec_dp.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vec_interp.png b/tools/editor/icons/icon_graph_vec_interp.png
new file mode 100644
index 0000000000..daf7a00203
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vec_interp.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vec_length.png b/tools/editor/icons/icon_graph_vec_length.png
new file mode 100644
index 0000000000..60ade8c90a
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vec_length.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vec_op.png b/tools/editor/icons/icon_graph_vec_op.png
new file mode 100644
index 0000000000..f2a7a51123
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vec_op.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vec_scalar_op.png b/tools/editor/icons/icon_graph_vec_scalar_op.png
new file mode 100644
index 0000000000..f0f4e7a196
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vec_scalar_op.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vec_to_scalars.png b/tools/editor/icons/icon_graph_vec_to_scalars.png
new file mode 100644
index 0000000000..a677a7cc53
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vec_to_scalars.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vecs_to_xform.png b/tools/editor/icons/icon_graph_vecs_to_xform.png
new file mode 100644
index 0000000000..51216c93eb
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vecs_to_xform.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vector.png b/tools/editor/icons/icon_graph_vector.png
new file mode 100644
index 0000000000..9dfe47d757
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vector.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_vector_uniform.png b/tools/editor/icons/icon_graph_vector_uniform.png
new file mode 100644
index 0000000000..611539fca7
--- /dev/null
+++ b/tools/editor/icons/icon_graph_vector_uniform.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_xform.png b/tools/editor/icons/icon_graph_xform.png
new file mode 100644
index 0000000000..22df472be4
--- /dev/null
+++ b/tools/editor/icons/icon_graph_xform.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_xform_mult.png b/tools/editor/icons/icon_graph_xform_mult.png
new file mode 100644
index 0000000000..5d0ce7982d
--- /dev/null
+++ b/tools/editor/icons/icon_graph_xform_mult.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_xform_scalar_func.png b/tools/editor/icons/icon_graph_xform_scalar_func.png
new file mode 100644
index 0000000000..e53f08a564
--- /dev/null
+++ b/tools/editor/icons/icon_graph_xform_scalar_func.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_xform_to_vecs.png b/tools/editor/icons/icon_graph_xform_to_vecs.png
new file mode 100644
index 0000000000..847261f726
--- /dev/null
+++ b/tools/editor/icons/icon_graph_xform_to_vecs.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_xform_uniform.png b/tools/editor/icons/icon_graph_xform_uniform.png
new file mode 100644
index 0000000000..94c9759b25
--- /dev/null
+++ b/tools/editor/icons/icon_graph_xform_uniform.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_xform_vec_func.png b/tools/editor/icons/icon_graph_xform_vec_func.png
new file mode 100644
index 0000000000..f3ba528896
--- /dev/null
+++ b/tools/editor/icons/icon_graph_xform_vec_func.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_xform_vec_imult.png b/tools/editor/icons/icon_graph_xform_vec_imult.png
new file mode 100644
index 0000000000..7e7330cb8c
--- /dev/null
+++ b/tools/editor/icons/icon_graph_xform_vec_imult.png
Binary files differ
diff --git a/tools/editor/icons/icon_graph_xform_vec_mult.png b/tools/editor/icons/icon_graph_xform_vec_mult.png
new file mode 100644
index 0000000000..f80a28c80d
--- /dev/null
+++ b/tools/editor/icons/icon_graph_xform_vec_mult.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_group.png b/tools/editor/icons/icon_group.png
index 577c84777e..d43b4958c9 100644
--- a/tools/editor/icons/icon_group.png
+++ b/tools/editor/icons/icon_group.png
Binary files differ
diff --git a/tools/editor/icons/icon_groups.png b/tools/editor/icons/icon_groups.png
index da4fd0d985..f4386821ed 100644
--- a/tools/editor/icons/icon_groups.png
+++ b/tools/editor/icons/icon_groups.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_hidden.png b/tools/editor/icons/icon_hidden.png
index 45fcfc2f47..e51b9ad03a 100644
--- a/tools/editor/icons/icon_hidden.png
+++ b/tools/editor/icons/icon_hidden.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_image.png b/tools/editor/icons/icon_image.png
index a6b1fbf6c1..5919ca8c6d 100644
--- a/tools/editor/icons/icon_image.png
+++ b/tools/editor/icons/icon_image.png
Binary files differ
diff --git a/tools/editor/icons/icon_image_texture.png b/tools/editor/icons/icon_image_texture.png
index 4618d984b8..b87e284a52 100644
--- a/tools/editor/icons/icon_image_texture.png
+++ b/tools/editor/icons/icon_image_texture.png
Binary files differ
diff --git a/tools/editor/icons/icon_immediate_geometry.png b/tools/editor/icons/icon_immediate_geometry.png
new file mode 100644
index 0000000000..e7fa8a9e42
--- /dev/null
+++ b/tools/editor/icons/icon_immediate_geometry.png
Binary files differ
diff --git a/tools/editor/icons/icon_instance_options.png b/tools/editor/icons/icon_instance_options.png
new file mode 100644
index 0000000000..9108448095
--- /dev/null
+++ b/tools/editor/icons/icon_instance_options.png
Binary files differ
diff --git a/tools/editor/icons/icon_integer.png b/tools/editor/icons/icon_integer.png
index 0e5b5abd62..32c8d9885b 100644
--- a/tools/editor/icons/icon_integer.png
+++ b/tools/editor/icons/icon_integer.png
Binary files differ
diff --git a/tools/editor/icons/icon_interp_cubic.png b/tools/editor/icons/icon_interp_cubic.png
index ab33aa7e6a..a946d70947 100644
--- a/tools/editor/icons/icon_interp_cubic.png
+++ b/tools/editor/icons/icon_interp_cubic.png
Binary files differ
diff --git a/tools/editor/icons/icon_interp_linear.png b/tools/editor/icons/icon_interp_linear.png
index bf3849ecaf..9174af39e7 100644
--- a/tools/editor/icons/icon_interp_linear.png
+++ b/tools/editor/icons/icon_interp_linear.png
Binary files differ
diff --git a/tools/editor/icons/icon_interp_raw.png b/tools/editor/icons/icon_interp_raw.png
index 48650d6e66..f12936493b 100644
--- a/tools/editor/icons/icon_interp_raw.png
+++ b/tools/editor/icons/icon_interp_raw.png
Binary files differ
diff --git a/tools/editor/icons/icon_item_list.png b/tools/editor/icons/icon_item_list.png
new file mode 100644
index 0000000000..f930e7ecaa
--- /dev/null
+++ b/tools/editor/icons/icon_item_list.png
Binary files differ
diff --git a/tools/editor/icons/icon_key.png b/tools/editor/icons/icon_key.png
index d647876866..d6096ef41f 100644
--- a/tools/editor/icons/icon_key.png
+++ b/tools/editor/icons/icon_key.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_key_next.png b/tools/editor/icons/icon_key_next.png
new file mode 100644
index 0000000000..759008d064
--- /dev/null
+++ b/tools/editor/icons/icon_key_next.png
Binary files differ
diff --git a/tools/editor/icons/icon_key_selected.png b/tools/editor/icons/icon_key_selected.png
index d916c55286..562beef98a 100644
--- a/tools/editor/icons/icon_key_selected.png
+++ b/tools/editor/icons/icon_key_selected.png
Binary files differ
diff --git a/tools/editor/icons/icon_kinematic_body.png b/tools/editor/icons/icon_kinematic_body.png
new file mode 100644
index 0000000000..7feb38f6ba
--- /dev/null
+++ b/tools/editor/icons/icon_kinematic_body.png
Binary files differ
diff --git a/tools/editor/icons/icon_kinematic_body_2d.png b/tools/editor/icons/icon_kinematic_body_2d.png
new file mode 100644
index 0000000000..3d8e09a179
--- /dev/null
+++ b/tools/editor/icons/icon_kinematic_body_2d.png
Binary files differ
diff --git a/tools/editor/icons/icon_light_2d.png b/tools/editor/icons/icon_light_2d.png
new file mode 100644
index 0000000000..9162b33090
--- /dev/null
+++ b/tools/editor/icons/icon_light_2d.png
Binary files differ
diff --git a/tools/editor/icons/icon_light_map.png b/tools/editor/icons/icon_light_map.png
new file mode 100644
index 0000000000..e0333f06ea
--- /dev/null
+++ b/tools/editor/icons/icon_light_map.png
Binary files differ
diff --git a/tools/editor/icons/icon_light_occluder_2d.png b/tools/editor/icons/icon_light_occluder_2d.png
new file mode 100644
index 0000000000..c66dd536d3
--- /dev/null
+++ b/tools/editor/icons/icon_light_occluder_2d.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_load.png b/tools/editor/icons/icon_load.png
index fdc06d38a3..a450a7b297 100644
--- a/tools/editor/icons/icon_load.png
+++ b/tools/editor/icons/icon_load.png
Binary files differ
diff --git a/tools/editor/icons/icon_lock.png b/tools/editor/icons/icon_lock.png
index 0cfd1d4ab1..995d87b6fb 100644
--- a/tools/editor/icons/icon_lock.png
+++ b/tools/editor/icons/icon_lock.png
Binary files differ
diff --git a/tools/editor/icons/icon_loop.png b/tools/editor/icons/icon_loop.png
index d75642359d..7bde451ca0 100644
--- a/tools/editor/icons/icon_loop.png
+++ b/tools/editor/icons/icon_loop.png
Binary files differ
diff --git a/tools/editor/icons/icon_main_play.png b/tools/editor/icons/icon_main_play.png
index 401708c49e..9e8cc6c4a9 100644
--- a/tools/editor/icons/icon_main_play.png
+++ b/tools/editor/icons/icon_main_play.png
Binary files differ
diff --git a/tools/editor/icons/icon_main_stop.png b/tools/editor/icons/icon_main_stop.png
index 3f54ba69c9..31a6cd601e 100644
--- a/tools/editor/icons/icon_main_stop.png
+++ b/tools/editor/icons/icon_main_stop.png
Binary files differ
diff --git a/tools/editor/icons/icon_material_shader.png b/tools/editor/icons/icon_material_shader.png
new file mode 100644
index 0000000000..0e476b2540
--- /dev/null
+++ b/tools/editor/icons/icon_material_shader.png
Binary files differ
diff --git a/tools/editor/icons/icon_material_shader_graph.png b/tools/editor/icons/icon_material_shader_graph.png
new file mode 100644
index 0000000000..68d8b4cb49
--- /dev/null
+++ b/tools/editor/icons/icon_material_shader_graph.png
Binary files differ
diff --git a/tools/editor/icons/icon_mirror_x.png b/tools/editor/icons/icon_mirror_x.png
index d20f90c1da..657e7f5458 100644
--- a/tools/editor/icons/icon_mirror_x.png
+++ b/tools/editor/icons/icon_mirror_x.png
Binary files differ
diff --git a/tools/editor/icons/icon_mirror_y.png b/tools/editor/icons/icon_mirror_y.png
index 5e2f710425..111aa5e4ae 100644
--- a/tools/editor/icons/icon_mirror_y.png
+++ b/tools/editor/icons/icon_mirror_y.png
Binary files differ
diff --git a/tools/editor/icons/icon_move_down.png b/tools/editor/icons/icon_move_down.png
index ef310e80e1..06c7246084 100644
--- a/tools/editor/icons/icon_move_down.png
+++ b/tools/editor/icons/icon_move_down.png
Binary files differ
diff --git a/tools/editor/icons/icon_move_down_hl.png b/tools/editor/icons/icon_move_down_hl.png
index dec56e8da8..f9de58a940 100644
--- a/tools/editor/icons/icon_move_down_hl.png
+++ b/tools/editor/icons/icon_move_down_hl.png
Binary files differ
diff --git a/tools/editor/icons/icon_move_up.png b/tools/editor/icons/icon_move_up.png
index d67b1aff0b..ca6c64f7a1 100644
--- a/tools/editor/icons/icon_move_up.png
+++ b/tools/editor/icons/icon_move_up.png
Binary files differ
diff --git a/tools/editor/icons/icon_move_up_hl.png b/tools/editor/icons/icon_move_up_hl.png
index 19ce8bbe27..e076c9a265 100644
--- a/tools/editor/icons/icon_move_up_hl.png
+++ b/tools/editor/icons/icon_move_up_hl.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_navigation.png b/tools/editor/icons/icon_navigation.png
new file mode 100644
index 0000000000..eeaa660f8d
--- /dev/null
+++ b/tools/editor/icons/icon_navigation.png
Binary files differ
diff --git a/tools/editor/icons/icon_navigation_2d.png b/tools/editor/icons/icon_navigation_2d.png
new file mode 100644
index 0000000000..8170ecf68c
--- /dev/null
+++ b/tools/editor/icons/icon_navigation_2d.png
Binary files differ
diff --git a/tools/editor/icons/icon_navigation_mesh_instance.png b/tools/editor/icons/icon_navigation_mesh_instance.png
new file mode 100644
index 0000000000..163bd0cdb3
--- /dev/null
+++ b/tools/editor/icons/icon_navigation_mesh_instance.png
Binary files differ
diff --git a/tools/editor/icons/icon_navigation_polygon_instance.png b/tools/editor/icons/icon_navigation_polygon_instance.png
new file mode 100644
index 0000000000..9f9c318906
--- /dev/null
+++ b/tools/editor/icons/icon_navigation_polygon_instance.png
Binary files differ
diff --git a/tools/editor/icons/icon_new.png b/tools/editor/icons/icon_new.png
index 3596d2e8ea..c04785fc3f 100644
--- a/tools/editor/icons/icon_new.png
+++ b/tools/editor/icons/icon_new.png
Binary files differ
diff --git a/tools/editor/icons/icon_node.png b/tools/editor/icons/icon_node.png
index b0f7fb01dc..d8ce1b7538 100644
--- a/tools/editor/icons/icon_node.png
+++ b/tools/editor/icons/icon_node.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_occluder_polygon_2d.png b/tools/editor/icons/icon_occluder_polygon_2d.png
new file mode 100644
index 0000000000..705794b729
--- /dev/null
+++ b/tools/editor/icons/icon_occluder_polygon_2d.png
Binary files differ
diff --git a/tools/editor/icons/icon_open.png b/tools/editor/icons/icon_open.png
index 4fad5677ca..a450a7b297 100644
--- a/tools/editor/icons/icon_open.png
+++ b/tools/editor/icons/icon_open.png
Binary files differ
diff --git a/tools/editor/icons/icon_p_hash_translation.png b/tools/editor/icons/icon_p_hash_translation.png
index c0eadc3c55..e18ef6a76f 100644
--- a/tools/editor/icons/icon_p_hash_translation.png
+++ b/tools/editor/icons/icon_p_hash_translation.png
Binary files differ
diff --git a/tools/editor/icons/icon_packed_scene.png b/tools/editor/icons/icon_packed_scene.png
index 9c1e1c4fbf..c9802f2b66 100644
--- a/tools/editor/icons/icon_packed_scene.png
+++ b/tools/editor/icons/icon_packed_scene.png
Binary files differ
diff --git a/tools/editor/icons/icon_panel_top.png b/tools/editor/icons/icon_panel_top.png
new file mode 100644
index 0000000000..20e67fad1a
--- /dev/null
+++ b/tools/editor/icons/icon_panel_top.png
Binary files differ
diff --git a/tools/editor/icons/icon_panels_1.png b/tools/editor/icons/icon_panels_1.png
index 501c8c9acc..546ca61c89 100644
--- a/tools/editor/icons/icon_panels_1.png
+++ b/tools/editor/icons/icon_panels_1.png
Binary files differ
diff --git a/tools/editor/icons/icon_panels_2.png b/tools/editor/icons/icon_panels_2.png
index 08f104e2b1..5a4750bda2 100644
--- a/tools/editor/icons/icon_panels_2.png
+++ b/tools/editor/icons/icon_panels_2.png
Binary files differ
diff --git a/tools/editor/icons/icon_panels_2_alt.png b/tools/editor/icons/icon_panels_2_alt.png
new file mode 100644
index 0000000000..2006f212ce
--- /dev/null
+++ b/tools/editor/icons/icon_panels_2_alt.png
Binary files differ
diff --git a/tools/editor/icons/icon_panels_3.png b/tools/editor/icons/icon_panels_3.png
index 1d1902d8dd..13988de93a 100644
--- a/tools/editor/icons/icon_panels_3.png
+++ b/tools/editor/icons/icon_panels_3.png
Binary files differ
diff --git a/tools/editor/icons/icon_panels_3_alt.png b/tools/editor/icons/icon_panels_3_alt.png
new file mode 100644
index 0000000000..5195b799a5
--- /dev/null
+++ b/tools/editor/icons/icon_panels_3_alt.png
Binary files differ
diff --git a/tools/editor/icons/icon_panels_4.png b/tools/editor/icons/icon_panels_4.png
index 83cc133d21..c217330d43 100644
--- a/tools/editor/icons/icon_panels_4.png
+++ b/tools/editor/icons/icon_panels_4.png
Binary files differ
diff --git a/tools/editor/icons/icon_particle_attractor_2d.png b/tools/editor/icons/icon_particle_attractor_2d.png
new file mode 100644
index 0000000000..bb66611e45
--- /dev/null
+++ b/tools/editor/icons/icon_particle_attractor_2d.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_pause.png b/tools/editor/icons/icon_pause.png
index e63661353c..7c0a57003e 100644
--- a/tools/editor/icons/icon_pause.png
+++ b/tools/editor/icons/icon_pause.png
Binary files differ
diff --git a/tools/editor/icons/icon_pin.png b/tools/editor/icons/icon_pin.png
index f34c8585f7..037352137d 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_pin_joint.png b/tools/editor/icons/icon_pin_joint.png
new file mode 100644
index 0000000000..cdfae660d8
--- /dev/null
+++ b/tools/editor/icons/icon_pin_joint.png
Binary files differ
diff --git a/tools/editor/icons/icon_pin_pressed.png b/tools/editor/icons/icon_pin_pressed.png
index f151b5a590..5738e6856f 100644
--- a/tools/editor/icons/icon_pin_pressed.png
+++ b/tools/editor/icons/icon_pin_pressed.png
Binary files differ
diff --git a/tools/editor/icons/icon_play.png b/tools/editor/icons/icon_play.png
index 544b3bc5f4..d2bd9d310c 100644
--- a/tools/editor/icons/icon_play.png
+++ b/tools/editor/icons/icon_play.png
Binary files differ
diff --git a/tools/editor/icons/icon_play_backwards.png b/tools/editor/icons/icon_play_backwards.png
new file mode 100644
index 0000000000..8dff5f20e3
--- /dev/null
+++ b/tools/editor/icons/icon_play_backwards.png
Binary files differ
diff --git a/tools/editor/icons/icon_play_custom.png b/tools/editor/icons/icon_play_custom.png
index 5c98c7100b..8e8ab8c62a 100644
--- a/tools/editor/icons/icon_play_custom.png
+++ b/tools/editor/icons/icon_play_custom.png
Binary files differ
diff --git a/tools/editor/icons/icon_play_scene.png b/tools/editor/icons/icon_play_scene.png
index 7ca59fe900..7079cc9677 100644
--- a/tools/editor/icons/icon_play_scene.png
+++ b/tools/editor/icons/icon_play_scene.png
Binary files differ
diff --git a/tools/editor/icons/icon_play_start.png b/tools/editor/icons/icon_play_start.png
new file mode 100644
index 0000000000..5b085aa1ed
--- /dev/null
+++ b/tools/editor/icons/icon_play_start.png
Binary files differ
diff --git a/tools/editor/icons/icon_play_start_backwards.png b/tools/editor/icons/icon_play_start_backwards.png
new file mode 100644
index 0000000000..09afac637c
--- /dev/null
+++ b/tools/editor/icons/icon_play_start_backwards.png
Binary files differ
diff --git a/tools/editor/icons/icon_polygon_2d.png b/tools/editor/icons/icon_polygon_2d.png
new file mode 100644
index 0000000000..9deb63a248
--- /dev/null
+++ b/tools/editor/icons/icon_polygon_2d.png
Binary files differ
diff --git a/tools/editor/icons/icon_prev_scene.png b/tools/editor/icons/icon_prev_scene.png
index c7c180e1c4..9d8dda5180 100644
--- a/tools/editor/icons/icon_prev_scene.png
+++ b/tools/editor/icons/icon_prev_scene.png
Binary files differ
diff --git a/tools/editor/icons/icon_ray_cast.png b/tools/editor/icons/icon_ray_cast.png
new file mode 100644
index 0000000000..a53ef0b516
--- /dev/null
+++ b/tools/editor/icons/icon_ray_cast.png
Binary files differ
diff --git a/tools/editor/icons/icon_real.png b/tools/editor/icons/icon_real.png
index bfe5038319..80fbf7017c 100644
--- a/tools/editor/icons/icon_real.png
+++ b/tools/editor/icons/icon_real.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_reload.png b/tools/editor/icons/icon_reload.png
index 07f53efb56..f7c6530d77 100644
--- a/tools/editor/icons/icon_reload.png
+++ b/tools/editor/icons/icon_reload.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_remove.png b/tools/editor/icons/icon_remove.png
index 5349af466e..f0f814e304 100644
--- a/tools/editor/icons/icon_remove.png
+++ b/tools/editor/icons/icon_remove.png
Binary files differ
diff --git a/tools/editor/icons/icon_remove_small.png b/tools/editor/icons/icon_remove_small.png
new file mode 100644
index 0000000000..e0903689cf
--- /dev/null
+++ b/tools/editor/icons/icon_remove_small.png
Binary files differ
diff --git a/tools/editor/icons/icon_rename.png b/tools/editor/icons/icon_rename.png
index f88da39915..7b6a10df93 100644
--- a/tools/editor/icons/icon_rename.png
+++ b/tools/editor/icons/icon_rename.png
Binary files differ
diff --git a/tools/editor/icons/icon_reparent.png b/tools/editor/icons/icon_reparent.png
index af85b17ecc..59aee5e42d 100644
--- a/tools/editor/icons/icon_reparent.png
+++ b/tools/editor/icons/icon_reparent.png
Binary files differ
diff --git a/tools/editor/icons/icon_replace.png b/tools/editor/icons/icon_replace.png
index 2ae843ae10..662a58dc93 100644
--- a/tools/editor/icons/icon_replace.png
+++ b/tools/editor/icons/icon_replace.png
Binary files differ
diff --git a/tools/editor/icons/icon_resource_preloader.png b/tools/editor/icons/icon_resource_preloader.png
index e31e5a0d59..14b8c4de3c 100644
--- a/tools/editor/icons/icon_resource_preloader.png
+++ b/tools/editor/icons/icon_resource_preloader.png
Binary files differ
diff --git a/tools/editor/icons/icon_rotate_0.png b/tools/editor/icons/icon_rotate_0.png
new file mode 100644
index 0000000000..85a4b4c420
--- /dev/null
+++ b/tools/editor/icons/icon_rotate_0.png
Binary files differ
diff --git a/tools/editor/icons/icon_rotate_180.png b/tools/editor/icons/icon_rotate_180.png
new file mode 100644
index 0000000000..c4c516cff5
--- /dev/null
+++ b/tools/editor/icons/icon_rotate_180.png
Binary files differ
diff --git a/tools/editor/icons/icon_rotate_270.png b/tools/editor/icons/icon_rotate_270.png
new file mode 100644
index 0000000000..6e0f2e62b8
--- /dev/null
+++ b/tools/editor/icons/icon_rotate_270.png
Binary files differ
diff --git a/tools/editor/icons/icon_rotate_90.png b/tools/editor/icons/icon_rotate_90.png
new file mode 100644
index 0000000000..f25b0e99a3
--- /dev/null
+++ b/tools/editor/icons/icon_rotate_90.png
Binary files differ
diff --git a/tools/editor/icons/icon_sample_player.png b/tools/editor/icons/icon_sample_player.png
index 5561769b05..92d9cc77bf 100644
--- a/tools/editor/icons/icon_sample_player.png
+++ b/tools/editor/icons/icon_sample_player.png
Binary files differ
diff --git a/tools/editor/icons/icon_save.png b/tools/editor/icons/icon_save.png
index dce274ffb1..ddef66688d 100644
--- a/tools/editor/icons/icon_save.png
+++ b/tools/editor/icons/icon_save.png
Binary files differ
diff --git a/tools/editor/icons/icon_script.png b/tools/editor/icons/icon_script.png
index 65fb3c4934..baf5927c18 100644
--- a/tools/editor/icons/icon_script.png
+++ b/tools/editor/icons/icon_script.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/icons/icon_slider_joint.png b/tools/editor/icons/icon_slider_joint.png
new file mode 100644
index 0000000000..ce35b6bfa2
--- /dev/null
+++ b/tools/editor/icons/icon_slider_joint.png
Binary files differ
diff --git a/tools/editor/icons/icon_sound_room_params.png b/tools/editor/icons/icon_sound_room_params.png
index 8e381d7978..2d37a4b49f 100644
--- a/tools/editor/icons/icon_sound_room_params.png
+++ b/tools/editor/icons/icon_sound_room_params.png
Binary files differ
diff --git a/tools/editor/icons/icon_stop.png b/tools/editor/icons/icon_stop.png
index 3b7562fa4a..0fd43b403a 100644
--- a/tools/editor/icons/icon_stop.png
+++ b/tools/editor/icons/icon_stop.png
Binary files differ
diff --git a/tools/editor/icons/icon_stream_player.png b/tools/editor/icons/icon_stream_player.png
index 2670a567e8..cf8fdcbaea 100644
--- a/tools/editor/icons/icon_stream_player.png
+++ b/tools/editor/icons/icon_stream_player.png
Binary files differ
diff --git a/tools/editor/icons/icon_string.png b/tools/editor/icons/icon_string.png
index 86cc8e633f..48bf753c40 100644
--- a/tools/editor/icons/icon_string.png
+++ b/tools/editor/icons/icon_string.png
Binary files differ
diff --git a/tools/editor/icons/icon_tab_menu.png b/tools/editor/icons/icon_tab_menu.png
new file mode 100644
index 0000000000..29edd02f01
--- /dev/null
+++ b/tools/editor/icons/icon_tab_menu.png
Binary files differ
diff --git a/tools/editor/icons/icon_texture.png b/tools/editor/icons/icon_texture.png
index 03d6ac7db2..bbcc54bd6e 100644
--- a/tools/editor/icons/icon_texture.png
+++ b/tools/editor/icons/icon_texture.png
Binary files differ
diff --git a/tools/editor/icons/icon_timer.png b/tools/editor/icons/icon_timer.png
index 3855683033..e8c36ae893 100644
--- a/tools/editor/icons/icon_timer.png
+++ b/tools/editor/icons/icon_timer.png
Binary files differ
diff --git a/tools/editor/icons/icon_tool_move.png b/tools/editor/icons/icon_tool_move.png
index fc611cdbb1..7257d3897b 100644
--- a/tools/editor/icons/icon_tool_move.png
+++ b/tools/editor/icons/icon_tool_move.png
Binary files differ
diff --git a/tools/editor/icons/icon_tool_pan.png b/tools/editor/icons/icon_tool_pan.png
index 5c078a7b1c..bfe6fddf45 100644
--- a/tools/editor/icons/icon_tool_pan.png
+++ b/tools/editor/icons/icon_tool_pan.png
Binary files differ
diff --git a/tools/editor/icons/icon_tool_rotate.png b/tools/editor/icons/icon_tool_rotate.png
index c833b93d6e..9575ceb54e 100644
--- a/tools/editor/icons/icon_tool_rotate.png
+++ b/tools/editor/icons/icon_tool_rotate.png
Binary files differ
diff --git a/tools/editor/icons/icon_tool_scale.png b/tools/editor/icons/icon_tool_scale.png
index 3eaeae1e99..a94a6e7c98 100644
--- a/tools/editor/icons/icon_tool_scale.png
+++ b/tools/editor/icons/icon_tool_scale.png
Binary files differ
diff --git a/tools/editor/icons/icon_tool_select.png b/tools/editor/icons/icon_tool_select.png
index eb5ff6e1da..47683228e9 100644
--- a/tools/editor/icons/icon_tool_select.png
+++ b/tools/editor/icons/icon_tool_select.png
Binary files differ
diff --git a/tools/editor/icons/icon_tools.png b/tools/editor/icons/icon_tools.png
index 927173ea0f..f02d924203 100644
--- a/tools/editor/icons/icon_tools.png
+++ b/tools/editor/icons/icon_tools.png
Binary files differ
diff --git a/tools/editor/icons/icon_touch_screen_button.png b/tools/editor/icons/icon_touch_screen_button.png
new file mode 100644
index 0000000000..16e84927f1
--- /dev/null
+++ b/tools/editor/icons/icon_touch_screen_button.png
Binary files differ
diff --git a/tools/editor/icons/icon_track_continuous.png b/tools/editor/icons/icon_track_continuous.png
index 97e8762299..9f99891c21 100644
--- a/tools/editor/icons/icon_track_continuous.png
+++ b/tools/editor/icons/icon_track_continuous.png
Binary files differ
diff --git a/tools/editor/icons/icon_track_discrete.png b/tools/editor/icons/icon_track_discrete.png
index 57a4cd5579..4e65e49afb 100644
--- a/tools/editor/icons/icon_track_discrete.png
+++ b/tools/editor/icons/icon_track_discrete.png
Binary files differ
diff --git a/tools/editor/icons/icon_translation.png b/tools/editor/icons/icon_translation.png
index 6211ab9a1b..917c6f548a 100644
--- a/tools/editor/icons/icon_translation.png
+++ b/tools/editor/icons/icon_translation.png
Binary files differ
diff --git a/tools/editor/icons/icon_transpose.png b/tools/editor/icons/icon_transpose.png
new file mode 100644
index 0000000000..f9b78bc0fd
--- /dev/null
+++ b/tools/editor/icons/icon_transpose.png
Binary files differ
diff --git a/tools/editor/icons/icon_unbone.png b/tools/editor/icons/icon_unbone.png
index 819e8a8e5d..c8cd774460 100644
--- a/tools/editor/icons/icon_unbone.png
+++ b/tools/editor/icons/icon_unbone.png
Binary files differ
diff --git a/tools/editor/icons/icon_ungroup.png b/tools/editor/icons/icon_ungroup.png
index 16511e3f1c..4ea620bf96 100644
--- a/tools/editor/icons/icon_ungroup.png
+++ b/tools/editor/icons/icon_ungroup.png
Binary files differ
diff --git a/tools/editor/icons/icon_unlock.png b/tools/editor/icons/icon_unlock.png
index b86447bf7a..f9fa31c3e0 100644
--- a/tools/editor/icons/icon_unlock.png
+++ b/tools/editor/icons/icon_unlock.png
Binary files differ
diff --git a/tools/editor/icons/icon_uv.png b/tools/editor/icons/icon_uv.png
index 4d9d198d86..39bc737a37 100644
--- a/tools/editor/icons/icon_uv.png
+++ b/tools/editor/icons/icon_uv.png
Binary files differ
diff --git a/tools/editor/icons/icon_vector.png b/tools/editor/icons/icon_vector.png
index 7826d7f7a9..0ee33ba0b7 100644
--- a/tools/editor/icons/icon_vector.png
+++ b/tools/editor/icons/icon_vector.png
Binary files differ
diff --git a/tools/editor/icons/icon_vector2.png b/tools/editor/icons/icon_vector2.png
index 44e48c36c7..5920109a55 100644
--- a/tools/editor/icons/icon_vector2.png
+++ b/tools/editor/icons/icon_vector2.png
Binary files differ
diff --git a/tools/editor/icons/icon_vehicle_body.png b/tools/editor/icons/icon_vehicle_body.png
new file mode 100644
index 0000000000..1c6af388eb
--- /dev/null
+++ b/tools/editor/icons/icon_vehicle_body.png
Binary files differ
diff --git a/tools/editor/icons/icon_vehicle_wheel.png b/tools/editor/icons/icon_vehicle_wheel.png
new file mode 100644
index 0000000000..161283e1bf
--- /dev/null
+++ b/tools/editor/icons/icon_vehicle_wheel.png
Binary files differ
diff --git a/tools/editor/icons/icon_viewport.png b/tools/editor/icons/icon_viewport.png
index 0a0d93cf4d..3859f6c7e9 100644
--- a/tools/editor/icons/icon_viewport.png
+++ b/tools/editor/icons/icon_viewport.png
Binary files differ
diff --git a/tools/editor/icons/icon_visible.png b/tools/editor/icons/icon_visible.png
index 519898bbef..cbc44c4e30 100644
--- a/tools/editor/icons/icon_visible.png
+++ b/tools/editor/icons/icon_visible.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_no_preview.png b/tools/editor/icons/icon_wait_no_preview.png
new file mode 100644
index 0000000000..5d20cd99ec
--- /dev/null
+++ b/tools/editor/icons/icon_wait_no_preview.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_1.png b/tools/editor/icons/icon_wait_preview_1.png
new file mode 100644
index 0000000000..0aab42e04a
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_1.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_2.png b/tools/editor/icons/icon_wait_preview_2.png
new file mode 100644
index 0000000000..f476b9ce1f
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_2.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_3.png b/tools/editor/icons/icon_wait_preview_3.png
new file mode 100644
index 0000000000..2775d1ef43
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_3.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_4.png b/tools/editor/icons/icon_wait_preview_4.png
new file mode 100644
index 0000000000..2eaa86fec9
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_4.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_5.png b/tools/editor/icons/icon_wait_preview_5.png
new file mode 100644
index 0000000000..6590644bc1
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_5.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_6.png b/tools/editor/icons/icon_wait_preview_6.png
new file mode 100644
index 0000000000..307e412310
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_6.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_7.png b/tools/editor/icons/icon_wait_preview_7.png
new file mode 100644
index 0000000000..b0edc94d93
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_7.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_8.png b/tools/editor/icons/icon_wait_preview_8.png
new file mode 100644
index 0000000000..67a2f48ec3
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_8.png
Binary files differ
diff --git a/tools/editor/icons/icon_y_sort.png b/tools/editor/icons/icon_y_sort.png
new file mode 100644
index 0000000000..6f80fac156
--- /dev/null
+++ b/tools/editor/icons/icon_y_sort.png
Binary files differ
diff --git a/tools/editor/icons/icon_zoom.png b/tools/editor/icons/icon_zoom.png
index cbacaaaeca..e4bbbfe7c3 100644
--- a/tools/editor/icons/icon_zoom.png
+++ b/tools/editor/icons/icon_zoom.png
Binary files differ
diff --git a/tools/editor/import_settings.cpp b/tools/editor/import_settings.cpp
index 74e4aa97d7..36d7828be0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -224,7 +224,7 @@ void ImportSettingsDialog::update_tree() {
void ImportSettingsDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"update_tree");
}
diff --git a/tools/editor/import_settings.h b/tools/editor/import_settings.h
index eb7a8b6143..31237dd8cf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 4c716874ba..7e9acd193d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 685cf60c9d..716faff0c6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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..cd5c34e53b
--- /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+=".optimized.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 4b3e052907..5ba0669f1d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,7 +28,7 @@
/*************************************************************************/
#include "editor_font_import_plugin.h"
#include "scene/gui/dialogs.h"
-#include "scene/gui/file_dialog.h"
+#include "tools/editor/editor_file_dialog.h"
#include "tools/editor/editor_node.h"
#include "os/file_access.h"
#include "editor_atlas.h"
@@ -47,6 +47,12 @@ class _EditorFontImportOptions : public Object {
OBJ_TYPE(_EditorFontImportOptions,Object);
public:
+ enum FontMode {
+
+ FONT_BITMAP,
+ FONT_DISTANCE_FIELD
+ };
+
enum ColorType {
COLOR_WHITE,
COLOR_CUSTOM,
@@ -69,6 +75,9 @@ public:
CHARSET_CUSTOM_LATIN
};
+
+ FontMode font_mode;
+
CharacterSet character_set;
String custom_file;
@@ -91,7 +100,7 @@ public:
bool color_use_monochrome;
String gradient_image;
-
+ bool disable_filter;
bool round_advance;
@@ -99,7 +108,10 @@ public:
bool _set(const StringName& p_name, const Variant& p_value) {
String n = p_name;
- if (n=="extra_space/char")
+ if (n=="mode/mode") {
+ font_mode=FontMode(int(p_value));
+ _change_notify();
+ } else if (n=="extra_space/char")
char_extra_spacing=p_value;
else if (n=="extra_space/space")
space_extra_spacing=p_value;
@@ -153,6 +165,8 @@ public:
color_use_monochrome=p_value;
else if (n=="advanced/round_advance")
round_advance=p_value;
+ else if (n=="advanced/disable_filter")
+ disable_filter=p_value;
else
return false;
@@ -166,7 +180,9 @@ public:
bool _get(const StringName& p_name,Variant &r_ret) const{
String n = p_name;
- if (n=="extra_space/char")
+ if (n=="mode/mode")
+ r_ret=font_mode;
+ else if (n=="extra_space/char")
r_ret=char_extra_spacing;
else if (n=="extra_space/space")
r_ret=space_extra_spacing;
@@ -217,6 +233,8 @@ public:
r_ret=color_use_monochrome;
else if (n=="advanced/round_advance")
r_ret=round_advance;
+ else if (n=="advanced/disable_filter")
+ r_ret=disable_filter;
else
return false;
@@ -226,6 +244,9 @@ public:
void _get_property_list( List<PropertyInfo> *p_list) const{
+
+ p_list->push_back(PropertyInfo(Variant::INT,"mode/mode",PROPERTY_HINT_ENUM,"Bitmap,Distance Field"));
+
p_list->push_back(PropertyInfo(Variant::INT,"extra_space/char",PROPERTY_HINT_RANGE,"-64,64,1"));
p_list->push_back(PropertyInfo(Variant::INT,"extra_space/space",PROPERTY_HINT_RANGE,"-64,64,1"));
p_list->push_back(PropertyInfo(Variant::INT,"extra_space/top",PROPERTY_HINT_RANGE,"-64,64,1"));
@@ -235,36 +256,47 @@ public:
if (character_set>=CHARSET_CUSTOM)
p_list->push_back(PropertyInfo(Variant::STRING,"character_set/custom",PROPERTY_HINT_FILE));
- p_list->push_back(PropertyInfo(Variant::BOOL,"shadow/enabled"));
- if (shadow) {
- p_list->push_back(PropertyInfo(Variant::INT,"shadow/radius",PROPERTY_HINT_RANGE,"-64,64,1"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow/offset"));
- p_list->push_back(PropertyInfo(Variant::COLOR,"shadow/color"));
- p_list->push_back(PropertyInfo(Variant::REAL,"shadow/transition",PROPERTY_HINT_EXP_EASING));
- }
+ int usage = PROPERTY_USAGE_DEFAULT;
- p_list->push_back(PropertyInfo(Variant::BOOL,"shadow2/enabled"));
- if (shadow2) {
- p_list->push_back(PropertyInfo(Variant::INT,"shadow2/radius",PROPERTY_HINT_RANGE,"-64,64,1"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow2/offset"));
- p_list->push_back(PropertyInfo(Variant::COLOR,"shadow2/color"));
- p_list->push_back(PropertyInfo(Variant::REAL,"shadow2/transition",PROPERTY_HINT_EXP_EASING));
+ if (font_mode==FONT_DISTANCE_FIELD) {
+ usage = PROPERTY_USAGE_NOEDITOR;
}
- p_list->push_back(PropertyInfo(Variant::INT,"color/mode",PROPERTY_HINT_ENUM,"White,Color,Gradient,Gradient Image"));
- if (color_type==COLOR_CUSTOM) {
- p_list->push_back(PropertyInfo(Variant::COLOR,"color/color"));
+ {
+ p_list->push_back(PropertyInfo(Variant::BOOL,"shadow/enabled",PROPERTY_HINT_NONE,"",usage));
+ if (shadow) {
+ p_list->push_back(PropertyInfo(Variant::INT,"shadow/radius",PROPERTY_HINT_RANGE,"-64,64,1",usage));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow/offset",PROPERTY_HINT_NONE,"",usage));
+ p_list->push_back(PropertyInfo(Variant::COLOR,"shadow/color",PROPERTY_HINT_NONE,"",usage));
+ p_list->push_back(PropertyInfo(Variant::REAL,"shadow/transition",PROPERTY_HINT_EXP_EASING,"",usage));
+ }
+
+ p_list->push_back(PropertyInfo(Variant::BOOL,"shadow2/enabled",PROPERTY_HINT_NONE,"",usage));
+ if (shadow2) {
+ p_list->push_back(PropertyInfo(Variant::INT,"shadow2/radius",PROPERTY_HINT_RANGE,"-64,64,1",usage));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow2/offset",PROPERTY_HINT_NONE,"",usage));
+ p_list->push_back(PropertyInfo(Variant::COLOR,"shadow2/color",PROPERTY_HINT_NONE,"",usage));
+ p_list->push_back(PropertyInfo(Variant::REAL,"shadow2/transition",PROPERTY_HINT_EXP_EASING,"",usage));
+ }
+
+ p_list->push_back(PropertyInfo(Variant::INT,"color/mode",PROPERTY_HINT_ENUM,"White,Color,Gradient,Gradient Image",usage));
+ if (color_type==COLOR_CUSTOM) {
+ p_list->push_back(PropertyInfo(Variant::COLOR,"color/color",PROPERTY_HINT_NONE,"",usage));
+
+ }
+ if (color_type==COLOR_GRADIENT_RANGE) {
+ p_list->push_back(PropertyInfo(Variant::COLOR,"color/begin",PROPERTY_HINT_NONE,"",usage));
+ p_list->push_back(PropertyInfo(Variant::COLOR,"color/end",PROPERTY_HINT_NONE,"",usage));
+ }
+ if (color_type==COLOR_GRADIENT_IMAGE) {
+ p_list->push_back(PropertyInfo(Variant::STRING,"color/image",PROPERTY_HINT_FILE,"",usage));
+ }
+ p_list->push_back(PropertyInfo(Variant::BOOL,"color/monochrome",PROPERTY_HINT_NONE,"",usage));
}
- if (color_type==COLOR_GRADIENT_RANGE) {
- p_list->push_back(PropertyInfo(Variant::COLOR,"color/begin"));
- p_list->push_back(PropertyInfo(Variant::COLOR,"color/end"));
- }
- if (color_type==COLOR_GRADIENT_IMAGE) {
- p_list->push_back(PropertyInfo(Variant::STRING,"color/image",PROPERTY_HINT_FILE));
- }
- p_list->push_back(PropertyInfo(Variant::BOOL,"color/monochrome"));
+
p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/round_advance"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/disable_filter"));
}
@@ -301,12 +333,16 @@ public:
gradient_end=Color(0.5,0.5,0.5,1);
color_use_monochrome=false;
+ font_mode=FONT_BITMAP;
round_advance=true;
+ disable_filter=false;
}
_EditorFontImportOptions() {
+ font_mode=FONT_BITMAP;
+
char_extra_spacing=0;
top_extra_spacing=0;
bottom_extra_spacing=0;
@@ -331,6 +367,7 @@ public:
color_use_monochrome=false;
round_advance=true;
+ disable_filter=false;
}
@@ -342,8 +379,8 @@ class EditorFontImportDialog : public ConfirmationDialog {
OBJ_TYPE(EditorFontImportDialog, ConfirmationDialog);
- LineEditFileChooser *source;
- LineEditFileChooser *dest;
+ EditorLineEditFileChooser *source;
+ EditorLineEditFileChooser *dest;
SpinBox *font_size;
LineEdit *test_string;
ColorPickerButton *test_color;
@@ -369,7 +406,10 @@ class EditorFontImportDialog : public ConfirmationDialog {
imd->set_option(opt,v);
}
- imd->add_source(EditorImportPlugin::validate_source_path(source->get_line_edit()->get_text()));
+ String src_path = EditorImportPlugin::validate_source_path(source->get_line_edit()->get_text());
+ //print_line("pre src path "+source->get_line_edit()->get_text());
+ //print_line("src path "+src_path);
+ imd->add_source(src_path);
imd->set_option("font/size",font_size->get_val());
return imd;
@@ -480,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()) {
@@ -491,7 +535,7 @@ class EditorFontImportDialog : public ConfirmationDialog {
Error err = plugin->import(dest->get_line_edit()->get_text(),rimd);
if (err!=OK) {
- error_dialog->set_text("Could't save font.");
+ error_dialog->set_text("Couldn't save font.");
error_dialog->popup_centered(Size2(200,100));
return;
}
@@ -521,7 +565,7 @@ public:
void _notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
prop_edit->edit(options);
_update_text();
}
@@ -572,9 +616,9 @@ public:
hbc->add_child(vbr);
vbr->set_h_size_flags(SIZE_EXPAND_FILL);
- source = memnew( LineEditFileChooser );
- source->get_file_dialog()->set_access(FileDialog::ACCESS_FILESYSTEM);
- source->get_file_dialog()->set_mode(FileDialog::MODE_OPEN_FILE);
+ source = memnew( EditorLineEditFileChooser );
+ source->get_file_dialog()->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ 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_line_edit()->connect("text_entered",this,"_src_changed");
@@ -586,7 +630,7 @@ public:
font_size->set_max(256);
font_size->set_val(16);
font_size->connect("value_changed",this,"_font_size_changed");
- dest = memnew( LineEditFileChooser );
+ dest = memnew( EditorLineEditFileChooser );
//
List<String> fl;
Ref<Font> font= memnew(Font);
@@ -613,6 +657,7 @@ public:
vbl->add_spacer();
vbl->add_margin_child("Test: ",testhb);
+ /*
HBoxContainer *upd_hb = memnew( HBoxContainer );
// vbl->add_child(upd_hb);
upd_hb->add_spacer();
@@ -620,7 +665,7 @@ public:
upd_hb->add_child(update);
update->set_text("Update");
update->connect("pressed",this,"_update");
-
+*/
options = memnew( _EditorFontImportOptions );
prop_edit = memnew( PropertyEditor() );
vbr->add_margin_child("Options:",prop_edit,true);
@@ -698,6 +743,137 @@ struct _EditorKerningKey {
};
+
+static unsigned char get_SDF_radial(
+ unsigned char *fontmap,
+ int w, int h,
+ int x, int y,
+ int max_radius )
+{
+ // hideous brute force method
+ float d2 = max_radius*max_radius+1.0;
+ unsigned char v = fontmap[x+y*w];
+ for( int radius = 1; (radius <= max_radius) && (radius*radius < d2); ++radius )
+ {
+ int line, lo, hi;
+ // north
+ line = y - radius;
+ if( (line >= 0) && (line < h) )
+ {
+ lo = x - radius;
+ hi = x + radius;
+ if( lo < 0 ) { lo = 0; }
+ if( hi >= w ) { hi = w-1; }
+ int idx = line * w + lo;
+ for( int i = lo; i <= hi; ++i )
+ {
+ // check this pixel
+ if( fontmap[idx] != v )
+ {
+ float nx = i - x;
+ float ny = line - y;
+ float nd2 = nx*nx+ny*ny;
+ if( nd2 < d2 )
+ {
+ d2 = nd2;
+ }
+ }
+ // move on
+ ++idx;
+ }
+ }
+ // south
+ line = y + radius;
+ if( (line >= 0) && (line < h) )
+ {
+ lo = x - radius;
+ hi = x + radius;
+ if( lo < 0 ) { lo = 0; }
+ if( hi >= w ) { hi = w-1; }
+ int idx = line * w + lo;
+ for( int i = lo; i <= hi; ++i )
+ {
+ // check this pixel
+ if( fontmap[idx] != v )
+ {
+ float nx = i - x;
+ float ny = line - y;
+ float nd2 = nx*nx+ny*ny;
+ if( nd2 < d2 )
+ {
+ d2 = nd2;
+ }
+ }
+ // move on
+ ++idx;
+ }
+ }
+ // west
+ line = x - radius;
+ if( (line >= 0) && (line < w) )
+ {
+ lo = y - radius + 1;
+ hi = y + radius - 1;
+ if( lo < 0 ) { lo = 0; }
+ if( hi >= h ) { hi = h-1; }
+ int idx = lo * w + line;
+ for( int i = lo; i <= hi; ++i )
+ {
+ // check this pixel
+ if( fontmap[idx] != v )
+ {
+ float nx = line - x;
+ float ny = i - y;
+ float nd2 = nx*nx+ny*ny;
+ if( nd2 < d2 )
+ {
+ d2 = nd2;
+ }
+ }
+ // move on
+ idx += w;
+ }
+ }
+ // east
+ line = x + radius;
+ if( (line >= 0) && (line < w) )
+ {
+ lo = y - radius + 1;
+ hi = y + radius - 1;
+ if( lo < 0 ) { lo = 0; }
+ if( hi >= h ) { hi = h-1; }
+ int idx = lo * w + line;
+ for( int i = lo; i <= hi; ++i )
+ {
+ // check this pixel
+ if( fontmap[idx] != v )
+ {
+ float nx = line - x;
+ float ny = i - y;
+ float nd2 = nx*nx+ny*ny;
+ if( nd2 < d2 )
+ {
+ d2 = nd2;
+ }
+ }
+ // move on
+ idx += w;
+ }
+ }
+ }
+ d2 = sqrtf( d2 );
+ if( v==0 )
+ {
+ d2 = -d2;
+ }
+ d2 *= 127.5 / max_radius;
+ d2 += 127.5;
+ if( d2 < 0.0 ) d2 = 0.0;
+ if( d2 > 255.0 ) d2 = 255.0;
+ return (unsigned char)(d2 + 0.5);
+}
+
+
Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata>& p_from, const String &p_existing) {
Ref<ResourceImportMetadata> from = p_from;
@@ -746,7 +922,11 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
}
- error = FT_Set_Pixel_Sizes(face,0,size);
+ int font_mode = from->get_option("mode/mode");
+
+ int scaler=(font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD)?16:1;
+
+ error = FT_Set_Pixel_Sizes(face,0,size*scaler);
FT_GlyphSlot slot = face->glyph;
@@ -812,9 +992,9 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
{
bool skip=false;
- error = FT_Load_Char( face, charcode, FT_LOAD_RENDER );
+ error = FT_Load_Char( face, charcode, font_mode==_EditorFontImportOptions::FONT_BITMAP?FT_LOAD_RENDER:FT_LOAD_MONOCHROME );
if (error) skip=true;
- else error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ else error = FT_Render_Glyph( face->glyph, font_mode==_EditorFontImportOptions::FONT_BITMAP?ft_render_mode_normal:ft_render_mode_mono );
if (error) {
skip=true;
} else if (!skip) {
@@ -839,28 +1019,36 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
}
_EditorFontData * fdata = memnew( _EditorFontData );
- fdata->bitmap.resize( slot->bitmap.width*slot->bitmap.rows );
- fdata->width=slot->bitmap.width;
- fdata->height=slot->bitmap.rows;
- fdata->character=charcode;
- fdata->glyph=FT_Get_Char_Index(face,charcode);
- if (charcode=='x')
- xsize=slot->bitmap.width;
- if (charcode<127) {
- if (slot->bitmap_top>max_up) {
+ int w = slot->bitmap.width;
+ int h = slot->bitmap.rows;
+ int p = slot->bitmap.pitch;
- max_up=slot->bitmap_top;
- }
+ //print_line("W: "+itos(w)+" P: "+itos(slot->bitmap.pitch));
+ if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) {
- if ( (slot->bitmap_top - fdata->height)<max_down ) {
+ // oversize the holding buffer so I can smooth it!
+ int sw = w + scaler * 4;
+ int sh = h + scaler * 4;
+ // do the SDF
+ int sdfw = sw / scaler;
+ int sdfh = sh / scaler;
- max_down=slot->bitmap_top - fdata->height;
- }
+ fdata->width=sdfw;
+ fdata->height=sdfh;
+ } else {
+ fdata->width=w;
+ fdata->height=h;
}
+ fdata->character=charcode;
+ fdata->glyph=FT_Get_Char_Index(face,charcode);
+ if (charcode=='x')
+ xsize=w/scaler;
+
+
fdata->valign=slot->bitmap_top;
fdata->halign=slot->bitmap_left;
@@ -870,12 +1058,85 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
else
fdata->advance=slot->advance.x/float(1<<6);
+ if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) {
+
+ fdata->halign = fdata->halign / scaler - 1.5;
+ fdata->valign = fdata->valign / scaler + 1.5;
+ fdata->advance/=scaler;
+
+ }
+
fdata->advance+=font_spacing;
- for (int i=0;i<slot->bitmap.width;i++) {
- for (int j=0;j<slot->bitmap.rows;j++) {
- fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i];
+ if (charcode<127) {
+ int top = fdata->valign;
+ int hmax = h/scaler;
+
+ if (top>max_up) {
+
+ max_up=top;
+ }
+
+
+ if ( (top - hmax)<max_down ) {
+
+ max_down=top - hmax;
+ }
+ }
+
+ if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) {
+
+
+ // oversize the holding buffer so I can smooth it!
+ int sw = w + scaler * 4;
+ int sh = h + scaler * 4;
+
+ unsigned char *smooth_buf = new unsigned char[sw*sh];
+
+ for( int i = 0; i < sw*sh; ++i ) {
+ smooth_buf[i] = 0;
+ }
+
+ // copy the glyph into the buffer to be smoothed
+ unsigned char *buf = slot->bitmap.buffer;
+ for( int j = 0; j < h; ++j ) {
+ for( int i = 0; i < w; ++i ) {
+ smooth_buf[scaler*2+i+(j+scaler*2)*sw] = 255 * ((buf[j*p+(i>>3)] >> (7 - (i & 7))) & 1);
+ }
+ }
+
+ // do the SDF
+ int sdfw = fdata->width;
+ int sdfh = fdata->height;
+
+ fdata->bitmap.resize( sdfw*sdfh );
+
+ for( int j = 0; j < sdfh; ++j ) {
+ for( int i = 0; i < sdfw; ++i ) {
+ int pd_idx = j*sdfw+i;
+
+ //fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i];
+
+ fdata->bitmap[pd_idx] =
+ //get_SDF
+ get_SDF_radial
+ ( smooth_buf, sw, sh,
+ i*scaler + (scaler >>1), j*scaler + (scaler >>1),
+ 2*scaler );
+
+ }
+ }
+
+ delete [] smooth_buf;
+
+ } else {
+ fdata->bitmap.resize( slot->bitmap.width*slot->bitmap.rows );
+ for (int i=0;i<slot->bitmap.width;i++) {
+ for (int j=0;j<slot->bitmap.rows;j++) {
+
+ fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i];
+ }
}
}
@@ -896,9 +1157,10 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
spd->ofs_x=0;
spd->ofs_y=0;
- if (!FT_Load_Char( face, ' ', FT_LOAD_RENDER ) && !FT_Render_Glyph( face->glyph, ft_render_mode_normal )) {
+ if (!FT_Load_Char( face, ' ', FT_LOAD_RENDER ) && !FT_Render_Glyph( face->glyph, font_mode==_EditorFontImportOptions::FONT_BITMAP?ft_render_mode_normal:ft_render_mode_mono )) {
spd->advance = slot->advance.x>>6; //round to nearest or store as float
+ spd->advance/=scaler;
spd->advance+=font_spacing;
} else {
@@ -947,7 +1209,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
if (kern==0)
continue;
- kerning_map[kpk]=kern;
+ kerning_map[kpk]=kern/scaler;
}
}
}
@@ -1071,7 +1333,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
pixels.resize(s.x*s.y*4);
DVector<uint8_t>::Write w = pixels.write();
- print_line("val: "+itos(font_data_list[i]->valign));
+ //print_line("val: "+itos(font_data_list[i]->valign));
for(int y=0;y<s.height;y++) {
int yc=CLAMP(y-o.y+font_data_list[i]->valign,0,height-1);
@@ -1260,6 +1522,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
int space_space = from->get_option("extra_space/space");
int top_space = from->get_option("extra_space/top");
int bottom_space = from->get_option("extra_space/bottom");
+ bool disable_filter = from->get_option("advanced/disable_filter");
Ref<Font> font;
@@ -1275,11 +1538,17 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
font->clear();
font->set_height(height+bottom_space+top_space);
font->set_ascent(ascent+top_space);
+ font->set_distance_field_hint(font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD);
//register texures
{
Ref<ImageTexture> t = memnew(ImageTexture);
- t->create_from_image(atlas);
+ int flags;
+ if (disable_filter)
+ flags=0;
+ else
+ flags=Texture::FLAG_FILTER;
+ t->create_from_image(atlas,flags);
t->set_storage( ImageTexture::STORAGE_COMPRESS_LOSSLESS );
font->add_texture(t);
diff --git a/tools/editor/io_plugins/editor_font_import_plugin.h b/tools/editor/io_plugins/editor_font_import_plugin.h
index ac3b4eb0fe..451f01080e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp
index a0f1626b03..d57cff850e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,6 +39,7 @@
#include "scene/resources/packed_scene.h"
#include "os/os.h"
#include "tools/editor/editor_node.h"
+#include <iostream>
struct ColladaImport {
@@ -61,6 +62,8 @@ struct ColladaImport {
Color ambient;
bool found_directional;
bool force_make_tangents;
+ bool apply_mesh_xform_to_vertices;
+ float bake_fps;
@@ -68,6 +71,7 @@ struct ColladaImport {
Map<String, Ref<Mesh> > mesh_cache;
Map<String, Ref<Curve3D> > curve_cache;
Map<String, Ref<Material> > material_cache;
+ Map<Collada::Node*,Skeleton*> skeleton_map;
Map< Skeleton*, Map< String, int> > skeleton_bone_map;
@@ -76,14 +80,15 @@ struct ColladaImport {
Map<String,bool> bones_with_animation;
Error _populate_skeleton(Skeleton *p_skeleton,Collada::Node *p_node, int &r_bone, int p_parent);
+ Error _create_scene_skeletons(Collada::Node *p_node);
Error _create_scene(Collada::Node *p_node, Spatial *p_parent);
Error _create_resources(Collada::Node *p_node);
Error _create_material(const String& p_material);
- Error _create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Collada::NodeGeometry::Material>& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_data, const Collada::MorphControllerData *p_morph_data);
+ Error _create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,const Map<String,Collada::NodeGeometry::Material>& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_data, const Collada::MorphControllerData *p_morph_data,Vector<Ref<Mesh> > p_morph_meshes=Vector<Ref<Mesh> >());
Error load(const String& p_path, int p_flags, bool p_force_make_tangents=false);
void _fix_param_animation_tracks();
- void create_animation(int p_clip=-1);
- void create_animations();
+ void create_animation(int p_clip,bool p_make_tracks_in_all_bones);
+ void create_animations(bool p_make_tracks_in_all_bones);
Set<String> tracks_in_clips;
Vector<String> missing_textures;
@@ -95,6 +100,8 @@ struct ColladaImport {
found_ambient=false;
found_directional=false;
force_make_tangents=false;
+ apply_mesh_xform_to_vertices=true;
+ bake_fps=15;
}
};
@@ -108,7 +115,7 @@ Error ColladaImport::_populate_skeleton(Skeleton *p_skeleton,Collada::Node *p_no
Collada::NodeJoint *joint = static_cast<Collada::NodeJoint*>(p_node);
-
+ print_line("populating joint "+joint->name);
p_skeleton->add_bone(p_node->name);
if (p_parent>=0)
p_skeleton->set_bone_parent(r_bone,p_parent);
@@ -168,6 +175,34 @@ void ColladaImport::_pre_process_lights(Collada::Node *p_node) {
_pre_process_lights(p_node->children[i]);
}
+Error ColladaImport::_create_scene_skeletons(Collada::Node *p_node) {
+
+
+ if (p_node->type==Collada::Node::TYPE_SKELETON) {
+
+ Skeleton *sk = memnew( Skeleton );
+ int bone = 0;
+
+ for(int i=0;i<p_node->children.size();i++) {
+
+ _populate_skeleton(sk,p_node->children[i],bone,-1);
+ }
+ sk->localize_rests(); //after creating skeleton, rests must be localized...!
+ skeleton_map[p_node]=sk;
+ }
+
+
+ for(int i=0;i<p_node->children.size();i++) {
+
+ Error err = _create_scene_skeletons(p_node->children[i]);
+ if (err)
+ return err;
+ }
+ return OK;
+
+}
+
+
Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
Spatial * node=NULL;
@@ -251,13 +286,16 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
case Collada::CameraData::MODE_ORTHOGONAL: {
- if (cd.orthogonal.x_mag) {
+ if (cd.orthogonal.y_mag) {
+
+ camera->set_keep_aspect_mode(Camera::KEEP_HEIGHT);
+ camera->set_orthogonal(cd.orthogonal.y_mag*2.0 ,cd.z_near,cd.z_far);
- camera->set_orthogonal(cd.orthogonal.x_mag,cd.z_near,cd.z_far);
+ } else if (!cd.orthogonal.y_mag && cd.orthogonal.x_mag) {
- } else if (!cd.orthogonal.x_mag && cd.orthogonal.y_mag) {
- camera->set_orthogonal(cd.orthogonal.y_mag * cd.aspect,cd.z_near,cd.z_far);
+ camera->set_keep_aspect_mode(Camera::KEEP_WIDTH);
+ camera->set_orthogonal(cd.orthogonal.x_mag*2.0,cd.z_near,cd.z_far);
}
} break;
@@ -295,15 +333,8 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
} break;
case Collada::Node::TYPE_SKELETON: {
- Skeleton *sk = memnew( Skeleton );
- int bone = 0;
-
- for(int i=0;i<p_node->children.size();i++) {
-
- _populate_skeleton(sk,p_node->children[i],bone,-1);
- }
- sk->localize_rests(); //after creating skeleton, rests must be localized...!
-
+ ERR_FAIL_COND_V(!skeleton_map.has(p_node),ERR_CANT_CREATE);
+ Skeleton *sk = skeleton_map[p_node];
node=sk;
} break;
@@ -558,12 +589,13 @@ static void _generate_tangents_and_binormals(const DVector<int>& p_indices,const
}
}
-Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Collada::NodeGeometry::Material>& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector<int> &bone_remap, const Collada::SkinControllerData *skin_controller, const Collada::MorphControllerData *p_morph_data) {
+Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,const Map<String,Collada::NodeGeometry::Material>& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector<int> &bone_remap, const Collada::SkinControllerData *skin_controller, const Collada::MorphControllerData *p_morph_data,Vector<Ref<Mesh> > p_morph_meshes) {
bool local_xform_mirror=p_local_xform.basis.determinant() < 0;
if (p_morph_data) {
+
//add morphie target
ERR_FAIL_COND_V( !p_morph_data->targets.has("MORPH_TARGET"), ERR_INVALID_DATA );
String mt = p_morph_data->targets["MORPH_TARGET"];
@@ -678,10 +710,126 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
//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 */
@@ -693,6 +841,7 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
// Must convert to GL/DX format.
int _prim_ofs=0;
+ int vertidx=0;
for(int p_i=0;p_i<p.count;p_i++) {
@@ -717,12 +866,19 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
ERR_FAIL_INDEX_V(src,p.indices.size(),ERR_INVALID_DATA);
Collada::Vertex vertex;
+ 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) {
@@ -745,7 +901,7 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
Vector3 tangent =Vector3(tangent_src->array[tangent_pos+0],tangent_src->array[tangent_pos+1],tangent_src->array[tangent_pos+2]);
vertex.tangent.normal=tangent;
- vertex.tangent.d= vertex.normal.cross(tangent).dot(binormal) > 0 ? -1 : 1;
+ vertex.tangent.d= vertex.normal.cross(tangent).dot(binormal) > 0 ? 1 : -1;
}
}
@@ -780,6 +936,8 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
vertex.vertex.z = -vertex.vertex.z;
SWAP( vertex.normal.z, vertex.normal.y );
vertex.normal.z = -vertex.normal.z;
+ SWAP( vertex.tangent.normal.z, vertex.tangent.normal.y );
+ vertex.tangent.normal.z = -vertex.tangent.normal.z;
}
@@ -799,9 +957,9 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
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;
@@ -837,120 +995,10 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
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++) {
@@ -963,11 +1011,9 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
//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();
@@ -1088,7 +1134,7 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
DVector<Vector3>::Write uv2arrayw = uv2array.write();
for(int k=0;k<vlen;k++) {
- uv2arrayw[k]=vertex_array[k].uv;
+ uv2arrayw[k]=vertex_array[k].uv2;
}
uv2arrayw = DVector<Vector3>::Write();
@@ -1239,7 +1285,7 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
////////////////////////////
// THEN THE MORPH TARGETS //
////////////////////////////
-
+#if 0
if (p_morph_data) {
//add morphie target
@@ -1321,8 +1367,63 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
vertw = DVector<Vector3>::Write();
DVector<Vector3> normals;
DVector<float> tangents;
+ print_line("vertex source id: "+vertex_src_id);
+ if(md.vertices[vertex_src_id].sources.has("NORMAL")){
+ //has normals
+ normals.resize(vlen);
+ //std::cout << "has normals" << std::endl;
+ String normal_src_id = md.vertices[vertex_src_id].sources["NORMAL"];
+ //std::cout << "normals source: "<< normal_src_id.utf8().get_data() <<std::endl;
+ ERR_FAIL_COND_V(!md.sources.has(normal_src_id),ERR_INVALID_DATA);
+
+ const Collada::MeshData::Source *m=&md.sources[normal_src_id];
- _generate_normals(index_array,vertices,normals);
+ ERR_FAIL_COND_V( m->array.size() != vertex_src->array.size(), ERR_INVALID_DATA);
+ int stride=m->stride;
+ if (stride==0)
+ stride=3;
+
+
+ //read normals from morph target
+ DVector<Vector3>::Write vertw = normals.write();
+
+ for(int m_i=0;m_i<m->array.size()/stride;m_i++) {
+
+ int pos = m_i*stride;
+ Vector3 vtx( m->array[pos+0], m->array[pos+1], m->array[pos+2] );
+
+ #ifndef NO_UP_AXIS_SWAP
+ if (collada.state.up_axis==Vector3::AXIS_Z) {
+
+ SWAP( vtx.z, vtx.y );
+ vtx.z = -vtx.z;
+
+ }
+ #endif
+
+ Collada::Vertex vertex;
+ vertex.vertex=vtx;
+ vertex.fix_unit_scale(collada);
+ vtx=vertex.vertex;
+
+ vtx = p_local_xform.xform(vtx);
+
+
+ if (vertex_map.has(m_i)) { //vertex may no longer be here, don't bother converting
+
+
+ for (Set<int> ::Element *E=vertex_map[m_i].front() ; E; E=E->next() ) {
+
+ vertw[E->get()]=vtx;
+ }
+ }
+ }
+
+ print_line("using built-in normals");
+ }else{
+ print_line("generating normals");
+ _generate_normals(index_array,vertices,normals);//no normals
+ }
if (final_tangent_array.size() && final_uv_array.size()) {
_generate_tangents_and_binormals(index_array,vertices,final_uv_array,normals,tangents);
@@ -1347,6 +1448,17 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
}
+#endif
+ for(int mi=0;mi<p_morph_meshes.size();mi++) {
+
+ // print_line("want surface "+itos(mi)+" has "+itos(p_morph_meshes[mi]->get_surface_count()));
+ Array a = p_morph_meshes[mi]->surface_get_arrays(surface);
+ a[Mesh::ARRAY_BONES]=Variant();
+ a[Mesh::ARRAY_WEIGHTS]=Variant();
+ a[Mesh::ARRAY_INDEX]=Variant();
+ //a.resize(Mesh::ARRAY_MAX); //no need for index
+ mr.push_back(a);
+ }
p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,d,mr);
@@ -1477,20 +1589,30 @@ Error ColladaImport::_create_resources(Collada::Node *p_node) {
String meshid;
Transform apply_xform;
Vector<int> bone_remap;
+ Vector<Ref<Mesh> > morphs;
+
+ print_line("mesh: "+String(mi->get_name()));
if (ng->controller) {
- if (collada.state.skin_controller_data_map.has(ng->source)) {
+ print_line("has controller");
+ String ngsource = ng->source;
- ERR_FAIL_COND_V(!collada.state.skin_controller_data_map.has(ng->source),ERR_INVALID_DATA);
- skin=&collada.state.skin_controller_data_map[ng->source];
+ if (collada.state.skin_controller_data_map.has(ngsource)) {
+
+
+ ERR_FAIL_COND_V(!collada.state.skin_controller_data_map.has(ngsource),ERR_INVALID_DATA);
+ skin=&collada.state.skin_controller_data_map[ngsource];
Vector<String> skeletons = ng->skeletons;
ERR_FAIL_COND_V( skeletons.empty(), ERR_INVALID_DATA );
String skname = skeletons[0];
+ if (!node_map.has(skname)) {
+ print_line("no node for skeleton "+skname);
+ }
ERR_FAIL_COND_V( !node_map.has(skname), ERR_INVALID_DATA );
NodeMap nmsk = node_map[skname];
Skeleton *sk = nmsk.node->cast_to<Skeleton>();
@@ -1504,11 +1626,18 @@ Error ColladaImport::_create_resources(Collada::Node *p_node) {
if (collada.state.morph_controller_data_map.has(meshid)) {
//it's a morph!!
morph = &collada.state.morph_controller_data_map[meshid];
+ ngsource=meshid;
meshid=morph->mesh;
+ } else {
+ ngsource="";
}
- apply_xform=collada.fix_transform(p_node->default_transform);
- node->set_transform(Transform());
+ if (apply_mesh_xform_to_vertices) {
+ apply_xform=collada.fix_transform(p_node->default_transform);
+ node->set_transform(Transform());
+ } else {
+ apply_xform=Transform();
+ }
Collada::SkinControllerData::Source *joint_src=NULL;
@@ -1524,15 +1653,55 @@ Error ColladaImport::_create_resources(Collada::Node *p_node) {
for(int i=0;i<bone_remap.size();i++) {
String str = joint_src->sarray[i];
+ if (!bone_remap_map.has(str)) {
+ print_line("bone not found for remap: "+str);
+ print_line("in skeleton: "+skname);
+ }
ERR_FAIL_COND_V( !bone_remap_map.has(str), ERR_INVALID_DATA );
bone_remap[i]=bone_remap_map[str];
}
- } else if (collada.state.morph_controller_data_map.has(ng->source)) {
+ }
+
+ if (collada.state.morph_controller_data_map.has(ngsource)) {
+ print_line("is morph "+ngsource);
//it's a morph!!
- morph = &collada.state.morph_controller_data_map[meshid];
+ morph = &collada.state.morph_controller_data_map[ngsource];
meshid=morph->mesh;
- } else {
- ERR_EXPLAIN("Controller Instance Source '"+ng->source+"' is neither skin or morph!");
+ printf("KKmorph: %p\n",morph);
+ print_line("morph mshid: "+meshid);
+
+ Vector<String> targets;
+
+ morph->targets.has("MORPH_TARGET");
+ String target = morph->targets["MORPH_TARGET"];
+ bool valid=false;
+ if (morph->sources.has(target)) {
+ valid=true;
+ Vector<String> names = morph->sources[target].sarray;
+ for(int i=0;i<names.size();i++) {
+
+ String meshid=names[i];
+ if (collada.state.mesh_data_map.has(meshid)) {
+ Ref<Mesh> mesh=Ref<Mesh>(memnew( Mesh ));
+ const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
+ Error err = _create_mesh_surfaces(false,mesh,ng->material_map,meshdata,apply_xform,bone_remap,skin,NULL);
+ ERR_FAIL_COND_V(err,err);
+
+ morphs.push_back(mesh);
+ } else {
+ valid=false;
+ }
+ }
+ }
+
+ if (!valid)
+ morphs.clear();
+
+ ngsource="";
+ }
+
+ if (ngsource!=""){
+ ERR_EXPLAIN("Controller Instance Source '"+ngsource+"' is neither skin or morph!");
ERR_FAIL_V( ERR_INVALID_DATA );
}
@@ -1553,7 +1722,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node) {
mesh=Ref<Mesh>(memnew( Mesh ));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
mesh->set_name( meshdata.name );
- Error err = _create_mesh_surfaces(mesh,ng->material_map,meshdata,apply_xform,bone_remap,skin,morph);
+ Error err = _create_mesh_surfaces(morphs.size()==0,mesh,ng->material_map,meshdata,apply_xform,bone_remap,skin,morph,morphs);
ERR_FAIL_COND_V(err,err);
mesh_cache[meshid]=mesh;
@@ -1597,6 +1766,16 @@ Error ColladaImport::load(const String& p_path,int p_flags,bool p_force_make_tan
}
//import scene
+
+ for(int i=0;i<vs.root_nodes.size();i++) {
+
+ Error err = _create_scene_skeletons(vs.root_nodes[i]);
+ if (err!=OK) {
+ memdelete(scene);
+ ERR_FAIL_COND_V(err,err);
+ }
+ }
+
for(int i=0;i<vs.root_nodes.size();i++) {
Error err = _create_scene(vs.root_nodes[i],scene);
@@ -1659,16 +1838,21 @@ void ColladaImport::_fix_param_animation_tracks() {
source=skin.base;
} else if (collada.state.morph_controller_data_map.has(source)) {
+
const Collada::MorphControllerData& morph = collada.state.morph_controller_data_map[source];
+
if (morph.targets.has("MORPH_WEIGHT") && morph.targets.has("MORPH_TARGET")) {
+
String weights = morph.targets["MORPH_WEIGHT"];
String targets = morph.targets["MORPH_TARGET"];
+ //fails here
if (morph.sources.has(targets) && morph.sources.has(weights)) {
const Collada::MorphControllerData::Source &weight_src=morph.sources[weights];
const Collada::MorphControllerData::Source &target_src=morph.sources[targets];
+
ERR_FAIL_COND(weight_src.array.size() != target_src.sarray.size());
for(int i=0;i<weight_src.array.size();i++) {
@@ -1677,6 +1861,7 @@ void ColladaImport::_fix_param_animation_tracks() {
String mesh_name = target_src.sarray[i];
if (collada.state.mesh_name_map.has(mesh_name) && collada.state.referenced_tracks.has(track_name)) {
+
const Vector<int>&rt = collada.state.referenced_tracks[track_name];
for(int rti=0;rti<rt.size();rti++) {
@@ -1705,9 +1890,9 @@ void ColladaImport::_fix_param_animation_tracks() {
}
-void ColladaImport::create_animations() {
+void ColladaImport::create_animations(bool p_make_tracks_in_all_bones) {
+
- print_line("-=-=-=-=-PRE CA");
_fix_param_animation_tracks();
for(int i=0;i<collada.state.animation_clips.size();i++) {
@@ -1720,6 +1905,7 @@ void ColladaImport::create_animations() {
for(int i=0;i<collada.state.animation_tracks.size();i++) {
Collada::AnimationTrack &at = collada.state.animation_tracks[i];
+ //print_line("CHANNEL: "+at.target+" PARAM: "+at.param);
if (!node_map.has(at.target)) {
print_line("Coudlnt find node: "+at.target);
continue;
@@ -1737,23 +1923,23 @@ void ColladaImport::create_animations() {
}
- create_animation();
- print_line("clipcount: "+itos(collada.state.animation_clips.size()));
+ create_animation(-1,p_make_tracks_in_all_bones);
+ //print_line("clipcount: "+itos(collada.state.animation_clips.size()));
for(int i=0;i<collada.state.animation_clips.size();i++)
- create_animation(i);
+ create_animation(i,p_make_tracks_in_all_bones);
}
-void ColladaImport::create_animation(int p_clip) {
+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");
+ //print_line("default");
animation->set_name("default");
} else {
- print_line("clip name: "+collada.state.animation_clips[p_clip].name);
+ //print_line("clip name: "+collada.state.animation_clips[p_clip].name);
animation->set_name(collada.state.animation_clips[p_clip].name);
}
@@ -1812,20 +1998,23 @@ void ColladaImport::create_animation(int p_clip) {
Vector<float> base_snapshots;
float f=0;
- float snapshot_interval = 1.0/20.0; //should be customizable somewhere...
+ float snapshot_interval = 1.0/bake_fps; //should be customizable somewhere...
float anim_length=collada.state.animation_length;
if (p_clip>=0 && collada.state.animation_clips[p_clip].end)
anim_length=collada.state.animation_clips[p_clip].end;
- while(f<collada.state.animation_length) {
- if (f>=collada.state.animation_length)
- f=collada.state.animation_length;
+ while(f<anim_length) {
base_snapshots.push_back(f);
f+=snapshot_interval;
+
+ if (f>=anim_length) {
+ base_snapshots.push_back(anim_length);
+ }
}
- print_line("anim len: "+rtos(anim_length));
+
+ //print_line("anim len: "+rtos(anim_length));
animation->set_length(anim_length);
bool tracks_found=false;
@@ -1850,7 +2039,7 @@ void ColladaImport::create_animation(int p_clip) {
Collada::Node *cn = collada.state.scene_map[E->get()];
if (cn->ignore_anim) {
- print_line("warning, ignoring animation on node: "+path);
+ //print_line("warning, ignoring animation on node: "+path);
continue;
}
@@ -1869,6 +2058,8 @@ void ColladaImport::create_animation(int p_clip) {
for(int i=0;i<at.keys.size();i++)
snapshots.push_back(at.keys[i].time);
+ print_line("using anim snapshots");
+
}
@@ -1980,46 +2171,48 @@ void ColladaImport::create_animation(int p_clip) {
}
+ if (p_make_tracks_in_all_bones) {
- //some bones may lack animation, but since we don't store pose as a property, we must add keyframes!
- for(Map<String,bool>::Element *E=bones_with_animation.front();E;E=E->next()) {
+ //some bones may lack animation, but since we don't store pose as a property, we must add keyframes!
+ for(Map<String,bool>::Element *E=bones_with_animation.front();E;E=E->next()) {
- if (E->get())
- continue;
+ if (E->get())
+ continue;
- //print_line("BONE LACKS ANIM: "+E->key());
+ //print_line("BONE LACKS ANIM: "+E->key());
- NodeMap &nm = node_map[E->key()];
- String path = scene->get_path_to(nm.node);
- ERR_CONTINUE( nm.bone <0 );
- Skeleton *sk = static_cast<Skeleton*>(nm.node);
- String name = sk->get_bone_name(nm.bone);
- path=path+":"+name;
+ NodeMap &nm = node_map[E->key()];
+ String path = scene->get_path_to(nm.node);
+ ERR_CONTINUE( nm.bone <0 );
+ Skeleton *sk = static_cast<Skeleton*>(nm.node);
+ String name = sk->get_bone_name(nm.bone);
+ path=path+":"+name;
- Collada::Node *cn = collada.state.scene_map[E->key()];
- if (cn->ignore_anim) {
- print_line("warning, ignoring animation on node: "+path);
- continue;
- }
+ Collada::Node *cn = collada.state.scene_map[E->key()];
+ if (cn->ignore_anim) {
+ print_line("warning, ignoring animation on node: "+path);
+ continue;
+ }
- animation->add_track(Animation::TYPE_TRANSFORM);
- int track = animation->get_track_count() -1;
- animation->track_set_path( track , path );
+ animation->add_track(Animation::TYPE_TRANSFORM);
+ int track = animation->get_track_count() -1;
+ animation->track_set_path( track , path );
- Transform xform = cn->compute_transform(collada);
- xform = collada.fix_transform(xform) * cn->post_transform;
+ Transform xform = cn->compute_transform(collada);
+ xform = collada.fix_transform(xform) * cn->post_transform;
- xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
+ xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
- Quat q = xform.basis;
- q.normalize();
- Vector3 s = xform.basis.get_scale();
- Vector3 l = xform.origin;
+ Quat q = xform.basis;
+ q.normalize();
+ Vector3 s = xform.basis.get_scale();
+ Vector3 l = xform.origin;
- animation->transform_track_insert_key(track,0,l,q,s);
+ animation->transform_track_insert_key(track,0,l,q,s);
- tracks_found=true;
+ tracks_found=true;
+ }
}
@@ -2117,14 +2310,14 @@ void EditorSceneImporterCollada::get_extensions(List<String> *r_extensions) cons
r_extensions->push_back("dae");
}
-Node* EditorSceneImporterCollada::import_scene(const String& p_path, uint32_t p_flags, List<String> *r_missing_deps, Error* r_err) {
-
+Node* EditorSceneImporterCollada::import_scene(const String& p_path, uint32_t p_flags,int p_bake_fps, List<String> *r_missing_deps, Error* r_err) {
ColladaImport state;
uint32_t flags=Collada::IMPORT_FLAG_SCENE;
if (p_flags&IMPORT_ANIMATION)
flags|=Collada::IMPORT_FLAG_ANIMATION;
+ state.bake_fps=p_bake_fps;
Error err = state.load(p_path,flags,p_flags&EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS);
@@ -2149,7 +2342,7 @@ Node* EditorSceneImporterCollada::import_scene(const String& p_path, uint32_t p_
if (p_flags&IMPORT_ANIMATION) {
- state.create_animations();
+ state.create_animations(p_flags&IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
AnimationPlayer *ap = memnew( AnimationPlayer );
for(int i=0;i<state.animations.size();i++) {
String name;
@@ -2158,8 +2351,6 @@ Node* EditorSceneImporterCollada::import_scene(const String& p_path, uint32_t p_
else
name=state.animations[i]->get_name();
- if (p_flags&IMPORT_ANIMATION_OPTIMIZE)
- state.animations[i]->optimize();
if (p_flags&IMPORT_ANIMATION_DETECT_LOOP) {
if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
@@ -2188,7 +2379,7 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String& p_path
ERR_FAIL_COND_V(err!=OK,RES());
- state.create_animations();
+ state.create_animations(p_flags&EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
if (state.scene)
memdelete(state.scene);
@@ -2205,8 +2396,6 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String& p_path
}
}
- if (p_flags&IMPORT_ANIMATION_OPTIMIZE)
- anim->optimize();
return anim;
}
diff --git a/tools/editor/io_plugins/editor_import_collada.h b/tools/editor/io_plugins/editor_import_collada.h
index 9580f42ed0..243cd043a0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -40,7 +40,7 @@ public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node* import_scene(const String& p_path,uint32_t p_flags,List<String> *r_missing_deps=NULL,Error* r_err=NULL);
+ virtual Node* import_scene(const String& p_path,uint32_t p_flags,int p_bake_fps,List<String> *r_missing_deps=NULL,Error* r_err=NULL);
virtual Ref<Animation> import_animation(const String& p_path,uint32_t p_flags);
EditorSceneImporterCollada();
diff --git a/tools/editor/io_plugins/editor_mesh_import_plugin.cpp b/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
index d76a778433..b32ab8cb0b 100644
--- a/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
@@ -1,6 +1,6 @@
#include "editor_mesh_import_plugin.h"
-#include "scene/gui/file_dialog.h"
+#include "tools/editor/editor_file_dialog.h"
#include "tools/editor/editor_dir_dialog.h"
#include "tools/editor/editor_node.h"
#include "tools/editor/property_editor.h"
@@ -105,7 +105,7 @@ public:
_EditorMeshImportOptions() {
generate_tangents=true;
- generate_normals=true;
+ generate_normals=false;
flip_faces=false;
smooth_shading=false;
weld_vertices=true;
@@ -126,9 +126,9 @@ class EditorMeshImportDialog : public ConfirmationDialog {
LineEdit *import_path;
LineEdit *save_path;
- FileDialog *file_select;
+ 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,23 +227,22 @@ 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) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
option_editor->edit(options);
}
@@ -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(FileDialog);
- file_select->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file_select = memnew( EditorFileDialog );
+ file_select->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ file_select->set_mode(EditorFileDialog::MODE_OPEN_FILES);
+ file_select->add_filter("*.obj ; Wavefront OBJ");
add_child(file_select);
- file_select->set_mode(FileDialog::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);
- // save_select->set_mode(FileDialog::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 );
@@ -425,7 +414,7 @@ Error EditorMeshImportPlugin::import(const String& p_path, const Ref<ResourceImp
ERR_FAIL_COND_V(v.size()<3,ERR_INVALID_DATA);
Vector2 uv;
uv.x=v[1].to_float();
- uv.y=v[2].to_float();
+ uv.y=1.0-v[2].to_float();
uvs.push_back(uv);
} else if (l.begins_with("vn ")) {
diff --git a/tools/editor/io_plugins/editor_sample_import_plugin.cpp b/tools/editor/io_plugins/editor_sample_import_plugin.cpp
index cd02156eef..7888246956 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor_sample_import_plugin.h"
-#include "scene/gui/file_dialog.h"
+#include "tools/editor/editor_file_dialog.h"
#include "tools/editor/editor_dir_dialog.h"
#include "tools/editor/editor_node.h"
#include "tools/editor/property_editor.h"
@@ -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;
}
@@ -171,7 +172,7 @@ class EditorSampleImportDialog : public ConfirmationDialog {
LineEdit *import_path;
LineEdit *save_path;
- FileDialog *file_select;
+ EditorFileDialog *file_select;
EditorDirDialog *save_select;
ConfirmationDialog *error_dialog;
PropertyEditor *option_editor;
@@ -254,6 +255,24 @@ public:
error_dialog->popup_centered(Size2(200,100));
}
+ if (save_path->get_text().strip_edges()=="") {
+ error_dialog->set_text("Target path is empty.");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ if (!save_path->get_text().begins_with("res://")) {
+ error_dialog->set_text("Target path must be full resource path.");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ if (!DirAccess::exists(save_path->get_text())) {
+ error_dialog->set_text("Target path must exist.");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
for(int i=0;i<samples.size();i++) {
Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
@@ -290,7 +309,7 @@ public:
void _notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
option_editor->edit(options);
}
@@ -345,16 +364,16 @@ public:
save_choose->connect("pressed", this,"_browse_target");
- file_select = memnew(FileDialog);
- file_select->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file_select = memnew(EditorFileDialog);
+ file_select->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
add_child(file_select);
- file_select->set_mode(FileDialog::MODE_OPEN_FILES);
+ file_select->set_mode(EditorFileDialog::MODE_OPEN_FILES);
file_select->connect("files_selected", this,"_choose_files");
file_select->add_filter("*.wav ; MS Waveform");
save_select = memnew( EditorDirDialog );
add_child(save_select);
- // save_select->set_mode(FileDialog::MODE_OPEN_DIR);
+ // save_select->set_mode(EditorFileDialog::MODE_OPEN_DIR);
save_select->connect("dir_selected", this,"_choose_save_dir");
get_ok()->connect("pressed", this,"_import");
@@ -562,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) {
@@ -590,8 +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;
- _compress_ima_adpcm(data,dst_data);
+ 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(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 {
@@ -691,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;
@@ -701,8 +758,8 @@ void EditorSampleImportPlugin::_compress_ima_adpcm(const Vector<float>& p_data,D
xm_sample=CLAMP(in[i]*32767.0,-32768,32767);
- if (xm_sample==32767 || xm_sample==-32768)
- printf("clippy!\n",xm_sample);
+ //if (xm_sample==32767 || xm_sample==-32768)
+ // printf("clippy!\n",xm_sample);
}
// xm_sample=xm_sample+xm_prev;
@@ -737,10 +794,10 @@ void EditorSampleImportPlugin::_compress_ima_adpcm(const Vector<float>& p_data,D
prev+=vpdiff ;
if (prev > 32767) {
- printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip up %i\n",i,xm_sample,prev,diff,vpdiff,prev);
+ //printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip up %i\n",i,xm_sample,prev,diff,vpdiff,prev);
prev=32767;
} else if (prev < -32768) {
- printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip down %i\n",i,xm_sample,prev,diff,vpdiff,prev);
+ //printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip down %i\n",i,xm_sample,prev,diff,vpdiff,prev);
prev = -32768 ;
}
@@ -762,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()+".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 176dece0d5..89319affa0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 0b7ffd55f0..ca44df269b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -35,10 +35,12 @@
#include "scene/animation/animation_player.h"
#include "io/resource_saver.h"
#include "scene/3d/mesh_instance.h"
+#include "scene/3d/navigation.h"
#include "scene/3d/room_instance.h"
#include "scene/3d/body_shape.h"
#include "scene/3d/physics_body.h"
#include "scene/3d/portal.h"
+#include "scene/3d/vehicle_body.h"
#include "os/os.h"
@@ -76,12 +78,31 @@ class EditorImportAnimationOptions : public VBoxContainer {
OBJ_TYPE( EditorImportAnimationOptions, VBoxContainer );
+
+ TreeItem *fps;
+ TreeItem* optimize_linear_error;
+ TreeItem* optimize_angular_error;
+ TreeItem* optimize_max_angle;
+
+ TreeItem *clips_base;
+
+ TextEdit *filters;
+ Vector<TreeItem*> clips;
+
Tree *flags;
+ Tree *clips_tree;
+ Tree *optimization_tree;
Vector<TreeItem*> items;
bool updating;
+ bool validating;
+
+
void _changed();
+ void _item_edited();
+ void _button_action(Object *p_obj,int p_col,int p_id);
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -91,6 +112,23 @@ public:
void set_flags(uint32_t p_flags);
uint32_t get_flags() const;
+ void set_fps(int p_fps);
+ int get_fps() const;
+
+ void set_optimize_linear_error(float p_error);
+ float get_optimize_linear_error() const;
+
+ void set_optimize_angular_error(float p_error);
+ float get_optimize_angular_error() const;
+
+ void set_optimize_max_angle(float p_error);
+ float get_optimize_max_angle() const;
+
+ void setup_clips(const Array& p_clips);
+ Array get_clips() const;
+
+ void set_filter(const String& p_filter);
+ String get_filter() const;
EditorImportAnimationOptions();
@@ -124,8 +162,8 @@ class EditorSceneImportDialog : public ConfirmationDialog {
LineEdit *save_path;
LineEdit *script_path;
Tree *import_options;
- FileDialog *file_select;
- FileDialog *script_select;
+ EditorFileDialog *file_select;
+ EditorFileDialog *script_select;
EditorDirDialog *save_select;
OptionButton *texture_action;
@@ -139,6 +177,9 @@ class EditorSceneImportDialog : public ConfirmationDialog {
Map<Ref<Mesh>,Ref<Shape> > collision_map;
ConfirmationDialog *error_dialog;
+ OptionButton *this_import;
+ OptionButton *next_import;
+
void _choose_file(const String& p_path);
void _choose_save_file(const String& p_path);
void _choose_script(const String& p_path);
@@ -176,6 +217,7 @@ static const char *anim_flag_names[]={
"Detect Loop (-loop,-cycle)",
"Keep Value Tracks",
"Optimize",
+ "Force All Tracks in All Clips",
NULL
};
@@ -183,6 +225,7 @@ static const char *anim_flag_descript[]={
"Set loop flag for animation names that\ncontain 'cycle' or 'loop' in the name.",
"When merging an existing aimation,\nkeep the user-created value-tracks.",
"Remove redundant keyframes in\n transform tacks.",
+ "Some exporters will rely on default pose for some bones.\nThis forces those bones to have at least one animation key.",
NULL
};
@@ -219,9 +262,101 @@ void EditorImportAnimationOptions::_changed() {
}
+void EditorImportAnimationOptions::_button_action(Object *p_obj,int p_col,int p_id) {
+
+ memdelete(p_obj);
+
+}
+
+
+void EditorImportAnimationOptions::_item_edited() {
+
+ if (validating)
+ return;
+
+ if (clips.size()==0)
+ return;
+ validating=true;
+ print_line("edited");
+ TreeItem *item = clips_tree->get_edited();
+ if (item==clips[clips.size()-1]) {
+ //add new
+ print_line("islast");
+ if (item->get_text(0).find("<")!=-1 || item->get_text(0).find(">")!=-1) {
+ validating=false;
+ return; //fuckit
+ }
+
+ item->set_editable(1,true);
+ item->set_editable(2,true);
+ item->add_button(0,EditorNode::get_singleton()->get_gui_base()->get_icon("Del","EditorIcons"));
+ item->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
+ item->set_range_config(1,0,3600,0.01);
+ item->set_range(1,0);
+ item->set_editable(1,true);
+ item->set_cell_mode(2,TreeItem::CELL_MODE_RANGE);
+ item->set_range_config(2,0,3600,0.01);
+ item->set_range(2,0);
+ item->set_cell_mode(3,TreeItem::CELL_MODE_CHECK);
+ item->set_editable(3,true);
+
+ TreeItem *newclip = clips_tree->create_item(clips_base);
+ newclip->set_text(0,"<new clip>");
+ newclip->set_editable(0,true);
+ newclip->set_editable(1,false);
+ newclip->set_editable(2,false);
+ clips.push_back(newclip);
+
+
+
+ }
+
+
+ //make name unique JUST IN CASE
+ String name = item->get_text(0);
+ name=name.replace("/","_").replace(":","_").strip_edges();
+ if (name=="")
+ name="New Clip";
+
+ if (clips.size()>2) {
+ int index=1;
+ while(true) {
+ bool valid = true;
+ String try_name=name;
+ if (index>1)
+ try_name+=" "+itos(index);
+
+ for(int i=0;i<clips.size()-1;i++) {
+
+ if (clips[i]==item)
+ continue;
+ if (clips[i]->get_text(0)==try_name) {
+ index++;
+ valid=false;
+ break;
+ }
+ }
+
+ if (valid) {
+ name=try_name;
+ break;
+ }
+
+ }
+ }
+
+ if (item->get_text(0)!=name)
+ item->set_text(0,name);
+
+ validating=false;
+
+}
+
void EditorImportAnimationOptions::_bind_methods() {
ObjectTypeDB::bind_method("_changed",&EditorImportAnimationOptions::_changed);
+ ObjectTypeDB::bind_method("_item_edited",&EditorImportAnimationOptions::_item_edited);
+ ObjectTypeDB::bind_method("_button_action",&EditorImportAnimationOptions::_button_action);
// ObjectTypeDB::bind_method("_changedp",&EditorImportAnimationOptions::_changedp);
ADD_SIGNAL(MethodInfo("changed"));
@@ -230,20 +365,87 @@ void EditorImportAnimationOptions::_bind_methods() {
void EditorImportAnimationOptions::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
flags->connect("item_edited",this,"_changed");
+ clips_tree->connect("item_edited",this,"_item_edited");
+ clips_tree->connect("button_pressed",this,"_button_action",varray(),CONNECT_DEFERRED);
// format->connect("item_selected",this,"_changedp");
}
}
+
+Array EditorImportAnimationOptions::get_clips() const {
+
+ Array arr;
+ for(int i=0;i<clips.size()-1;i++) {
+
+ arr.push_back(clips[i]->get_text(0));
+ arr.push_back(clips[i]->get_range(1));
+ arr.push_back(clips[i]->get_range(2));
+ arr.push_back(clips[i]->is_checked(3));
+ }
+
+ return arr;
+}
+
+
+void EditorImportAnimationOptions::setup_clips(const Array& p_clips) {
+
+ ERR_FAIL_COND(p_clips.size()%4!=0);
+ for(int i=0;i<clips.size();i++) {
+
+ memdelete(clips[i]);
+ }
+
+
+ clips.clear();
+
+ for(int i=0;i<p_clips.size();i+=4) {
+
+ TreeItem *clip = clips_tree->create_item(clips_base);
+ clip->set_text(0,p_clips[i]);
+ clip->add_button(0,EditorNode::get_singleton()->get_gui_base()->get_icon("Del","EditorIcons"));
+ clip->set_editable(0,true);
+ clip->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
+ clip->set_range_config(1,0,3600,0.01);
+ clip->set_range(1,p_clips[i+1]);
+ clip->set_editable(1,true);
+ clip->set_cell_mode(2,TreeItem::CELL_MODE_RANGE);
+ clip->set_range_config(2,0,3600,0.01);
+ clip->set_range(2,p_clips[i+2]);
+ clip->set_editable(2,true);
+ clip->set_cell_mode(3,TreeItem::CELL_MODE_CHECK);
+ clip->set_editable(3,true);
+ clip->set_checked(3,p_clips[i+3]);
+ clips.push_back(clip);
+
+ }
+
+ TreeItem *newclip = clips_tree->create_item(clips_base);
+ newclip->set_text(0,"<new clip>");
+ newclip->set_editable(0,true);
+ newclip->set_editable(1,false);
+ newclip->set_editable(2,false);
+ newclip->set_editable(3,false);
+ clips.push_back(newclip);
+
+}
+
+
EditorImportAnimationOptions::EditorImportAnimationOptions() {
updating=false;
+ validating=false;
+
+ TabContainer *tab= memnew(TabContainer);
+ add_margin_child("Animation Options",tab,true);
flags = memnew( Tree );
flags->set_hide_root(true);
+ tab->add_child(flags);
+ flags->set_name("Flags");
TreeItem *root = flags->create_item();
const char ** fname=anim_flag_names;
@@ -259,14 +461,133 @@ EditorImportAnimationOptions::EditorImportAnimationOptions() {
items.push_back(ti);
fname++;
fdescr++;
- }
+ }
+
+
+ TreeItem *fps_base = flags->create_item(root);
+ fps_base->set_text(0,"Bake FPS:");
+ fps_base->set_editable(0,false);
+ fps = flags->create_item(fps_base);
+ fps->set_cell_mode(0,TreeItem::CELL_MODE_RANGE);
+ fps->set_editable(0,true);
+ fps->set_range_config(0,1,120,1);
+ fps->set_range(0,15);
+
+ optimization_tree = memnew( Tree );
+ optimization_tree->set_columns(2);
+ tab->add_child(optimization_tree);
+ optimization_tree->set_name("Optimizer");
+ optimization_tree->set_column_expand(0,true);
+ optimization_tree->set_column_expand(1,false);
+ optimization_tree->set_column_min_width(1,80);
+ optimization_tree->set_hide_root(true);
+
+
+ TreeItem *optimize_root = optimization_tree->create_item();
+
+ optimize_linear_error = optimization_tree->create_item(optimize_root);
+ optimize_linear_error->set_text(0,"Max Linear Error");
+ optimize_linear_error->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
+ optimize_linear_error->set_editable(1,true);
+ optimize_linear_error->set_range_config(1,0,1,0.001);
+ optimize_linear_error->set_range(1,0.05);
+
+ optimize_angular_error = optimization_tree->create_item(optimize_root);
+ optimize_angular_error->set_text(0,"Max Angular Error");
+ optimize_angular_error->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
+ optimize_angular_error->set_editable(1,true);
+ optimize_angular_error->set_range_config(1,0,1,0.001);
+ optimize_angular_error->set_range(1,0.01);
+
+ optimize_max_angle = optimization_tree->create_item(optimize_root);
+ optimize_max_angle->set_text(0,"Max Angle");
+ optimize_max_angle->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
+ optimize_max_angle->set_editable(1,true);
+ optimize_max_angle->set_range_config(1,0,360,0.001);
+ optimize_max_angle->set_range(1,int(180*0.125));
+
+ clips_tree = memnew( Tree );
+ clips_tree->set_hide_root(true);
+ tab->add_child(clips_tree);
+ clips_tree->set_name("Clips");
+
+ clips_tree->set_columns(4);
+ clips_tree->set_column_expand(0,1);
+ clips_tree->set_column_expand(1,0);
+ clips_tree->set_column_expand(2,0);
+ clips_tree->set_column_expand(3,0);
+ clips_tree->set_column_min_width(1,60);
+ clips_tree->set_column_min_width(2,60);
+ clips_tree->set_column_min_width(3,40);
+ clips_tree->set_column_titles_visible(true);
+ clips_tree->set_column_title(0,"Name");
+ clips_tree->set_column_title(1,"Start(s)");
+ clips_tree->set_column_title(2,"End(s)");
+ clips_tree->set_column_title(3,"Loop");
+ clips_base =clips_tree->create_item(0);
+
+
+ setup_clips(Array());
+
+
+ filters = memnew( TextEdit );
+ tab->add_child(filters);
+ filters->set_name("Filters");
+}
+
+
+
+void EditorImportAnimationOptions::set_fps(int p_fps) {
+
+ fps->set_range(0,p_fps);
+}
+
+int EditorImportAnimationOptions::get_fps() const {
+
+ return fps->get_range(0);
+}
+
+
+void EditorImportAnimationOptions::set_optimize_linear_error(float p_optimize_linear_error) {
+
+ optimize_linear_error->set_range(1,p_optimize_linear_error);
+}
+
+float EditorImportAnimationOptions::get_optimize_linear_error() const {
+
+ return optimize_linear_error->get_range(1);
+}
+
+void EditorImportAnimationOptions::set_optimize_angular_error(float p_optimize_angular_error) {
+
+ optimize_angular_error->set_range(1,p_optimize_angular_error);
+}
+
+float EditorImportAnimationOptions::get_optimize_angular_error() const {
+
+ return optimize_angular_error->get_range(1);
+}
+
+void EditorImportAnimationOptions::set_optimize_max_angle(float p_optimize_max_angle) {
+
+ optimize_max_angle->set_range(1,p_optimize_max_angle);
+}
+
+float EditorImportAnimationOptions::get_optimize_max_angle() const {
+
+ return optimize_max_angle->get_range(1);
+}
- add_margin_child("Animation Options",flags,true);
+void EditorImportAnimationOptions::set_filter(const String& p_filter) {
+ filters->set_text(p_filter);
}
+String EditorImportAnimationOptions::get_filter() const {
+ return filters->get_text();
+}
@@ -304,6 +625,17 @@ void EditorSceneImportDialog::_choose_file(const String& p_path) {
}
#endif
+ if (p_path!=String()) {
+
+ String from_path = EditorFileSystem::get_singleton()->find_resource_from_source(EditorImportPlugin::validate_source_path(p_path));
+ print_line("from path.."+from_path);
+ if (from_path!=String()) {
+ popup_import(from_path);
+
+ }
+ }
+
+
import_path->set_text(p_path);
}
@@ -339,15 +671,28 @@ void EditorSceneImportDialog::_import(bool p_and_open) {
wip_open=p_and_open;
//' ImportMonitorBlock imb;
- if (import_path->get_text()=="") {
+
+ if (import_path->get_text().strip_edges()=="") {
error_dialog->set_text("Source path is empty.");
- error_dialog->popup_centered(Size2(200,100));
+ error_dialog->popup_centered_minsize();
return;
}
- if (save_path->get_text()=="") {
+ if (save_path->get_text().strip_edges()=="") {
error_dialog->set_text("Target path is empty.");
- error_dialog->popup_centered(Size2(200,100));
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ if (!save_path->get_text().begins_with("res://")) {
+ error_dialog->set_text("Target path must be full resource path.");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ if (!DirAccess::exists(save_path->get_text())) {
+ error_dialog->set_text("Target path must exist.");
+ error_dialog->popup_centered_minsize();
return;
}
@@ -369,7 +714,8 @@ void EditorSceneImportDialog::_import(bool p_and_open) {
}
- Ref<EditorScenePostImport> pi;
+
+
if (script_path->get_text()!="") {
Ref<Script> scr = ResourceLoader::load(script_path->get_text());
@@ -379,7 +725,7 @@ void EditorSceneImportDialog::_import(bool p_and_open) {
return;
}
- pi = Ref<EditorScenePostImport>( memnew( EditorScenePostImport ) );
+ Ref<EditorScenePostImport> pi = Ref<EditorScenePostImport>( memnew( EditorScenePostImport ) );
pi->set_script(scr.get_ref_ptr());
if (!pi->get_script_instance()) {
@@ -387,6 +733,7 @@ void EditorSceneImportDialog::_import(bool p_and_open) {
error_dialog->popup_centered(Size2(200,100));
return;
}
+
}
@@ -404,17 +751,26 @@ void EditorSceneImportDialog::_import(bool p_and_open) {
rim->add_source(EditorImportPlugin::validate_source_path(import_path->get_text()));
rim->set_option("flags",flags);
+ print_line("GET FLAGS: "+itos(texture_options->get_flags()));
rim->set_option("texture_flags",texture_options->get_flags());
rim->set_option("texture_format",texture_options->get_format());
rim->set_option("texture_quality",texture_options->get_quality());
rim->set_option("animation_flags",animation_options->get_flags());
- rim->set_option("post_import_script",script_path->get_text()!=String()?EditorImportPlugin::validate_source_path(script_path->get_text()):String());
+ rim->set_option("animation_bake_fps",animation_options->get_fps());
+ rim->set_option("animation_optimizer_linear_error",animation_options->get_optimize_linear_error());
+ rim->set_option("animation_optimizer_angular_error",animation_options->get_optimize_angular_error());
+ rim->set_option("animation_optimizer_max_angle",animation_options->get_optimize_max_angle());
+ rim->set_option("animation_filters",animation_options->get_filter());
+ rim->set_option("animation_clips",animation_options->get_clips());
+ rim->set_option("post_import_script",script_path->get_text());
+ rim->set_option("import_this_time",this_import->get_selected());
+ rim->set_option("import_next_time",next_import->get_selected());
rim->set_option("reimport",true);
List<String> missing;
Error err = plugin->import1(rim,&scene,&missing);
- if (err) {
+ if (err || !scene) {
error_dialog->set_text("Error importing scene.");
error_dialog->popup_centered(Size2(200,100));
@@ -521,7 +877,7 @@ void EditorSceneImportDialog::_browse_script() {
void EditorSceneImportDialog::popup_import(const String &p_from) {
- popup_centered(Size2(700,500));
+ popup_centered(Size2(750,550));
if (p_from!="") {
Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_from);
if (rimd.is_null())
@@ -539,7 +895,25 @@ void EditorSceneImportDialog::popup_import(const String &p_from) {
texture_options->set_format(EditorTextureImportPlugin::ImageFormat(int(rimd->get_option("texture_format"))));
texture_options->set_quality(rimd->get_option("texture_quality"));
animation_options->set_flags(rimd->get_option("animation_flags"));
+ if (rimd->has_option("animation_clips"))
+ animation_options->setup_clips(rimd->get_option("animation_clips"));
+ if (rimd->has_option("animation_filters"))
+ animation_options->set_filter(rimd->get_option("animation_filters"));
+ if (rimd->has_option("animation_bake_fps"))
+ animation_options->set_fps(rimd->get_option("animation_bake_fps"));
+ if (rimd->has_option("animation_optimizer_linear_error"))
+ animation_options->set_optimize_linear_error(rimd->get_option("animation_optimizer_linear_error"));
+ if (rimd->has_option("animation_optimizer_angular_error"))
+ animation_options->set_optimize_angular_error(rimd->get_option("animation_optimizer_angular_error"));
+ if (rimd->has_option("animation_optimizer_max_angle"))
+ animation_options->set_optimize_max_angle(rimd->get_option("animation_optimizer_max_angle"));
+
+
script_path->set_text(rimd->get_option("post_import_script"));
+ if (rimd->has_option("import_this_time"))
+ this_import->select(rimd->get_option("import_this_time"));
+ if (rimd->has_option("import_next_time"))
+ next_import->select(rimd->get_option("import_next_time"));
save_path->set_text(p_from.get_base_dir());
import_path->set_text(EditorImportPlugin::expand_source_path(rimd->get_source_path(0)));
@@ -551,7 +925,7 @@ void EditorSceneImportDialog::popup_import(const String &p_from) {
void EditorSceneImportDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
List<String> extensions;
@@ -614,7 +988,7 @@ void EditorSceneImportDialog::_bind_methods() {
ObjectTypeDB::bind_method("_choose_file",&EditorSceneImportDialog::_choose_file);
ObjectTypeDB::bind_method("_choose_save_file",&EditorSceneImportDialog::_choose_save_file);
ObjectTypeDB::bind_method("_choose_script",&EditorSceneImportDialog::_choose_script);
- ObjectTypeDB::bind_method("_import",&EditorSceneImportDialog::_import);
+ ObjectTypeDB::bind_method("_import",&EditorSceneImportDialog::_import,DEFVAL(false));
ObjectTypeDB::bind_method("_browse",&EditorSceneImportDialog::_browse);
ObjectTypeDB::bind_method("_browse_target",&EditorSceneImportDialog::_browse_target);
ObjectTypeDB::bind_method("_browse_script",&EditorSceneImportDialog::_browse_script);
@@ -637,6 +1011,8 @@ const EditorSceneImportDialog::FlagInfo EditorSceneImportDialog::scene_flag_name
{EditorSceneImportPlugin::SCENE_FLAG_DETECT_ALPHA,"Materials","Set Alpha in Materials (-alpha)",true},
{EditorSceneImportPlugin::SCENE_FLAG_DETECT_VCOLOR,"Materials","Set Vert. Color in Materials (-vcol)",true},
{EditorSceneImportPlugin::SCENE_FLAG_LINEARIZE_DIFFUSE_TEXTURES,"Actions","SRGB->Linear Of Diffuse Textures",false},
+ {EditorSceneImportPlugin::SCENE_FLAG_CONVERT_NORMALMAPS_TO_XY,"Actions","Convert Normal Maps to XY",true},
+ {EditorSceneImportPlugin::SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS,"Actions","Set Material Lightmap to UV2 if Tex2Array Exists",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_COLLISIONS,"Create","Create Collisions (-col},-colonly)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_PORTALS,"Create","Create Portals (-portal)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_ROOMS,"Create","Create Rooms (-room)",true},
@@ -644,9 +1020,10 @@ const EditorSceneImportDialog::FlagInfo EditorSceneImportDialog::scene_flag_name
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_BILLBOARDS,"Create","Create Billboards (-bb)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_IMPOSTORS,"Create","Create Impostors (-imp:dist)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_LODS,"Create","Create LODs (-lod:dist)",true},
- {EditorSceneImportPlugin::SCENE_FLAG_CREATE_CARS,"Create","Create Cars (-car)",true},
- {EditorSceneImportPlugin::SCENE_FLAG_CREATE_WHEELS,"Create","Create Car Wheels (-wheel)",true},
+ {EditorSceneImportPlugin::SCENE_FLAG_CREATE_CARS,"Create","Create Vehicles (-vehicle)",true},
+ {EditorSceneImportPlugin::SCENE_FLAG_CREATE_WHEELS,"Create","Create Vehicle Wheels (-wheel)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_NAVMESH,"Create","Create Navigation Meshes (-navmesh)",true},
+ {EditorSceneImportPlugin::SCENE_FLAG_DETECT_LIGHTMAP_LAYER,"Create","Detect LightMap Layer (-lm:<int>).",true},
{-1,NULL,NULL,false}
};
@@ -702,19 +1079,19 @@ EditorSceneImportDialog::EditorSceneImportDialog(EditorNode *p_editor, EditorSce
vbc->set_v_size_flags(SIZE_EXPAND_FILL);
vbc->add_margin_child("Options:",import_options,true);
- file_select = memnew(FileDialog);
- file_select->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file_select = memnew(EditorFileDialog);
+ file_select->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
add_child(file_select);
- file_select->set_mode(FileDialog::MODE_OPEN_FILE);
+ file_select->set_mode(EditorFileDialog::MODE_OPEN_FILE);
file_select->connect("file_selected", this,"_choose_file");
save_select = memnew(EditorDirDialog);
add_child(save_select);
- //save_select->set_mode(FileDialog::MODE_SAVE_FILE);
+ //save_select->set_mode(EditorFileDialog::MODE_SAVE_FILE);
save_select->connect("dir_selected", this,"_choose_save_file");
get_ok()->connect("pressed", this,"_import");
@@ -763,7 +1140,7 @@ EditorSceneImportDialog::EditorSceneImportDialog(EditorNode *p_editor, EditorSce
script_choose->connect("pressed", this,"_browse_script");
- script_select = memnew(FileDialog);
+ script_select = memnew(EditorFileDialog);
add_child(script_select);
for(int i=0;i<ScriptServer::get_language_count();i++) {
@@ -775,7 +1152,7 @@ EditorSceneImportDialog::EditorSceneImportDialog(EditorNode *p_editor, EditorSce
}
- script_select->set_mode(FileDialog::MODE_OPEN_FILE);
+ script_select->set_mode(EditorFileDialog::MODE_OPEN_FILE);
script_select->connect("file_selected", this,"_choose_script");
@@ -784,6 +1161,20 @@ EditorSceneImportDialog::EditorSceneImportDialog(EditorNode *p_editor, EditorSce
error_dialog->get_ok()->set_text("Accept");
// error_dialog->get_cancel()->hide();
+ this_import = memnew( OptionButton );
+ this_import->add_item("Overwrite Existing Scene");
+ this_import->add_item("Owerwrite Existing, Keep Materials");
+ this_import->add_item("Keep Existing, Merge with New");
+ this_import->add_item("Keep Existing, Ignore New");
+ vbc->add_margin_child("This Time:",this_import);
+
+ next_import = memnew( OptionButton );
+ next_import->add_item("Overwrite Existing Scene");
+ next_import->add_item("Owerwrite Existing, Keep Materials");
+ next_import->add_item("Keep Existing, Merge with New");
+ next_import->add_item("Keep Existing, Ignore New");
+ vbc->add_margin_child("Next Time:",next_import);
+
set_hide_on_ok(false);
GLOBAL_DEF("import/shared_textures","res://");
@@ -806,7 +1197,7 @@ EditorSceneImportDialog::EditorSceneImportDialog(EditorNode *p_editor, EditorSce
animation_options = memnew( EditorImportAnimationOptions );
ovb->add_child(animation_options);
animation_options->set_v_size_flags(SIZE_EXPAND_FILL);
- animation_options->set_flags(EditorSceneAnimationImportPlugin::ANIMATION_DETECT_LOOP|EditorSceneAnimationImportPlugin::ANIMATION_KEEP_VALUE_TRACKS|EditorSceneAnimationImportPlugin::ANIMATION_OPTIMIZE);
+ animation_options->set_flags(EditorSceneAnimationImportPlugin::ANIMATION_DETECT_LOOP|EditorSceneAnimationImportPlugin::ANIMATION_KEEP_VALUE_TRACKS|EditorSceneAnimationImportPlugin::ANIMATION_OPTIMIZE|EditorSceneAnimationImportPlugin::ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
confirm_import = memnew( ConfirmationDialog );
@@ -873,6 +1264,8 @@ static bool _teststr(const String& p_what,const String& p_str) {
return true;
if (p_what.to_lower().ends_with("-"+p_str)) //collada only supports "_" and "-" besides letters
return true;
+ if (p_what.to_lower().ends_with("_"+p_str)) //collada only supports "_" and "-" besides letters
+ return true;
return false;
}
@@ -882,12 +1275,14 @@ static String _fixstr(const String& p_what,const String& p_str) {
return p_what.replace("$"+p_str,"");
if (p_what.to_lower().ends_with("-"+p_str)) //collada only supports "_" and "-" besides letters
return p_what.substr(0,p_what.length()-(p_str.length()+1));
+ if (p_what.to_lower().ends_with("_"+p_str)) //collada only supports "_" and "-" besides letters
+ return p_what.substr(0,p_what.length()-(p_str.length()+1));
return p_what;
}
-void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<ImageTexture>, bool> &image_map) {
+void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<ImageTexture>, TextureRole> &image_map,int p_flags) {
switch(p_var.get_type()) {
@@ -899,7 +1294,7 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<Imag
if (res->is_type("Texture") && !image_map.has(res)) {
- image_map.insert(res,false);
+ image_map.insert(res,TEXTURE_ROLE_DEFAULT);
} else {
@@ -915,11 +1310,22 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<Imag
Ref<ImageTexture> tex =res->get(E->get().name);
if (tex.is_valid()) {
- image_map.insert(tex,true);
+ image_map.insert(tex,TEXTURE_ROLE_DIFFUSE);
+ }
+
+ } else if (E->get().type==Variant::OBJECT && res->cast_to<FixedMaterial>() && (E->get().name=="textures/normal")) {
+
+ Ref<ImageTexture> tex =res->get(E->get().name);
+ if (tex.is_valid()) {
+
+ image_map.insert(tex,TEXTURE_ROLE_NORMALMAP);
+ if (p_flags&SCENE_FLAG_CONVERT_NORMALMAPS_TO_XY)
+ res->cast_to<FixedMaterial>()->set_fixed_flag(FixedMaterial::FLAG_USE_XY_NORMALMAP,true);
}
+
} else {
- _find_resources(res->get(E->get().name),image_map);
+ _find_resources(res->get(E->get().name),image_map,p_flags);
}
}
}
@@ -938,8 +1344,8 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<Imag
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
- _find_resources(E->get(),image_map);
- _find_resources(d[E->get()],image_map);
+ _find_resources(E->get(),image_map,p_flags);
+ _find_resources(d[E->get()],image_map,p_flags);
}
@@ -950,7 +1356,7 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<Imag
Array a = p_var;
for(int i=0;i<a.size();i++) {
- _find_resources(a[i],image_map);
+ _find_resources(a[i],image_map,p_flags);
}
} break;
@@ -960,7 +1366,7 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<Imag
}
-Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Map<Ref<ImageTexture>,bool >& image_map) {
+Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Map<Ref<ImageTexture>,TextureRole >& image_map) {
// children first..
for(int i=0;i<p_node->get_child_count();i++) {
@@ -991,7 +1397,7 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
if (E->get().type==Variant::OBJECT || E->get().type==Variant::ARRAY || E->get().type==Variant::DICTIONARY) {
- _find_resources(p_node->get(E->get().name),image_map);
+ _find_resources(p_node->get(E->get().name),image_map,p_flags);
}
}
@@ -1033,7 +1439,7 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
}
- if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR) && p_node->cast_to<MeshInstance>()) {
+ if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR|SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS) && p_node->cast_to<MeshInstance>()) {
MeshInstance *mi = p_node->cast_to<MeshInstance>();
@@ -1058,6 +1464,10 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
mat->set_name(_fixstr(mat->get_name(),"vcol"));
}
+ if (p_flags&SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS && m->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV2) {
+ mat->set_flag(Material::FLAG_LIGHTMAP_ON_UV2,true);
+ }
+
}
}
}
@@ -1186,6 +1596,17 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
}
}
}
+
+
+ if (p_flags&SCENE_FLAG_DETECT_LIGHTMAP_LAYER && _teststr(name,"lm") && p_node->cast_to<MeshInstance>()) {
+
+ MeshInstance *mi = p_node->cast_to<MeshInstance>();
+
+ String str=name;
+ int layer = str.substr(str.find("lm")+3,str.length()).to_int();
+ mi->set_baked_light_texture_id(layer);
+ }
+
if (p_flags&SCENE_FLAG_CREATE_COLLISIONS && _teststr(name,"colonly") && p_node->cast_to<MeshInstance>()) {
if (isroot)
@@ -1221,13 +1642,74 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
col->set_name("col");
p_node->add_child(col);
-
- StaticBody *sb = col->cast_to<StaticBody>();
+ StaticBody *sb=col->cast_to<StaticBody>();
CollisionShape *colshape = memnew( CollisionShape);
colshape->set_shape(sb->get_shape(0));
colshape->set_name("shape");
- sb->add_child(colshape);
+ col->add_child(colshape);
colshape->set_owner(p_node->get_owner());
+ sb->set_owner(p_node->get_owner());
+
+ } else if (p_flags&SCENE_FLAG_CREATE_NAVMESH &&_teststr(name,"navmesh") && p_node->cast_to<MeshInstance>()) {
+
+ if (isroot)
+ return p_node;
+
+ MeshInstance *mi = p_node->cast_to<MeshInstance>();
+
+ Ref<Mesh> mesh=mi->get_mesh();
+ ERR_FAIL_COND_V(mesh.is_null(),NULL);
+ NavigationMeshInstance *nmi = memnew( NavigationMeshInstance );
+
+
+ nmi->set_name(_fixstr(name,"navmesh"));
+ Ref<NavigationMesh> nmesh = memnew( NavigationMesh);
+ nmesh->create_from_mesh(mesh);
+ nmi->set_navigation_mesh(nmesh);
+ nmi->cast_to<Spatial>()->set_transform(mi->get_transform());
+ p_node->replace_by(nmi);
+ memdelete(p_node);
+ p_node=nmi;
+ } else if (p_flags&SCENE_FLAG_CREATE_CARS &&_teststr(name,"vehicle")) {
+
+ if (isroot)
+ return p_node;
+
+ Node *owner = p_node->get_owner();
+ Spatial *s = p_node->cast_to<Spatial>();
+ VehicleBody *bv = memnew( VehicleBody );
+ String n = _fixstr(p_node->get_name(),"vehicle");
+ bv->set_name(n);
+ p_node->replace_by(bv);
+ p_node->set_name(n);
+ bv->add_child(p_node);
+ bv->set_owner(owner);
+ p_node->set_owner(owner);
+ bv->set_transform(s->get_transform());
+ s->set_transform(Transform());
+
+ p_node=bv;
+
+
+ } else if (p_flags&SCENE_FLAG_CREATE_CARS &&_teststr(name,"wheel")) {
+
+ if (isroot)
+ return p_node;
+
+ Node *owner = p_node->get_owner();
+ Spatial *s = p_node->cast_to<Spatial>();
+ VehicleWheel *bv = memnew( VehicleWheel );
+ String n = _fixstr(p_node->get_name(),"wheel");
+ bv->set_name(n);
+ p_node->replace_by(bv);
+ p_node->set_name(n);
+ bv->add_child(p_node);
+ bv->set_owner(owner);
+ p_node->set_owner(owner);
+ bv->set_transform(s->get_transform());
+ s->set_transform(Transform());
+
+ p_node=bv;
} else if (p_flags&SCENE_FLAG_CREATE_ROOMS && _teststr(name,"room") && p_node->cast_to<MeshInstance>()) {
@@ -1332,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] );
@@ -1514,22 +1996,74 @@ void EditorSceneImportPlugin::_merge_existing_node(Node *p_node,Node *p_imported
skeleton_node->add_bone(skeleton_imported->get_bone_name(i));
skeleton_node->set_bone_parent(i,skeleton_imported->get_bone_parent(i));
skeleton_node->set_bone_rest(i,skeleton_imported->get_bone_rest(i));
- skeleton_node->set_bone_pose(i,skeleton_imported->get_bone_pose(i));
+ //skeleton_node->set_bone_pose(i,skeleton_imported->get_bone_pose(i)); // not in a scene, will throw errors
}
- } else if (p_node->get_type()=="AnimationPlayer") {
+ }
+ else if (p_node->get_type() == "AnimationPlayer") {
//for paths, overwrite path
-
- AnimationPlayer *aplayer_imported =imported_node->cast_to<AnimationPlayer>();
- AnimationPlayer *aplayer_node =p_node->cast_to<AnimationPlayer>();
+ AnimationPlayer *aplayer_imported = imported_node->cast_to<AnimationPlayer>();
+ AnimationPlayer *aplayer_node = p_node->cast_to<AnimationPlayer>();
//use imported bones, obviously
List<StringName> anims;
+ List<StringName> existing_anims;
aplayer_imported->get_animation_list(&anims);
- //use imported animations, could merge some stuff though
- for (List<StringName>::Element *E=anims.front();E;E=E->next()) {
+ aplayer_node->get_animation_list(&existing_anims);
+
+ //use imported animations
+ for (List<StringName>::Element *N = anims.front(); N; N = N->next()) {
+
+ Ref<Animation> candidate = aplayer_imported->get_animation(N->get());
+
+ if (aplayer_node->has_animation(N->get())) {
+
+ Ref<Animation> found = aplayer_node->get_animation(N->get());
+
+ candidate->set_loop(found->has_loop());
+ candidate->set_step(found->get_step());
+
+ //For each track candidate
+ for (int i = 0; i < candidate->get_track_count(); i++) {
+
+ NodePath track_path = candidate->track_get_path(i);
+ // For each track existing
+ for (int x = 0; x < found->get_track_count(); x++) {
+
+ NodePath path_to_compare = found->track_get_path(x);
+
+ if (track_path.hash() == path_to_compare.hash() && candidate->track_get_type(x) == found->track_get_type(i)) {
+
+ //Tracks matches
+ if (candidate->track_get_interpolation_type(i) != found->track_get_interpolation_type(x))
+ candidate->track_set_interpolation_type(i, found->track_get_interpolation_type(x));
+ if (candidate->track_get_type(i) == Animation::TYPE_VALUE && candidate->value_track_is_continuous(i) != found->value_track_is_continuous(x))
+ candidate->value_track_set_continuous(i, found->value_track_is_continuous(x));
+
+ //Key transitions might have changed, but the animation remained unchanged
+ if (candidate->track_get_key_count(i) == found->track_get_key_count(x)) {
+ for (int k = 0; k < candidate->track_get_key_count(i); k++) {
+ if (candidate->track_get_key_transition(i, k) != found->track_get_key_transition(x, k))
+ candidate->track_set_key_transition(i, k, found->track_get_key_transition(x, k));
+ }
+ }
- aplayer_node->add_animation(E->get(),aplayer_imported->get_animation(E->get()));
+ }
+
+ }
+ }
+
+ // Append function callbacks and values
+ for (int x = 0; x < found->get_track_count(); x++) {
+ if (found->track_get_type(x) == Animation::TYPE_METHOD || found->track_get_type(x) == Animation::TYPE_VALUE)
+ candidate->add_track(found->track_get_type(x), candidate->get_track_count());
+
+ for (int k = 0; k < found->track_get_key_count(x); k++)
+ candidate->track_insert_key(x, found->track_get_key_time(x, k), found->track_get_key_value(x, k), found->track_get_key_transition(x, k));
+ }
+ }
+
+ aplayer_node->add_animation(N->get(), candidate);
}
} else if (p_node->get_type()=="CollisionShape") {
@@ -1603,7 +2137,7 @@ void EditorSceneImportPlugin::_merge_existing_node(Node *p_node,Node *p_imported
}
-void EditorSceneImportPlugin::_add_new_nodes(Node *p_node,Node *p_imported,Node *p_imported_scene,Set<Node*> &checked_nodes) {
+void EditorSceneImportPlugin::_add_new_nodes(Node *p_node,Node *p_imported,Node *p_imported_scene,Node *p_existing_scene,Set<Node*> &checked_nodes) {
for(int i=0;i<p_imported->get_child_count();i++) {
@@ -1611,12 +2145,15 @@ void EditorSceneImportPlugin::_add_new_nodes(Node *p_node,Node *p_imported,Node
Node *imported_node = p_imported->get_child(i);
- if (imported_node->get_owner()!=p_imported_scene)
+ if (imported_node->get_owner()!=p_imported_scene) {
+ // print_line("skipping because not imported at "+String(imported_node->get_name()));
continue; //end of the road
+ }
Vector<StringName> nn;
nn.push_back(imported_node->get_name());
NodePath imported_path(nn,false);
+ //print_line("check for: "+String(imported_path));
if (!p_node->has_node(imported_path) && !checked_nodes.has(imported_node)) {
//not there, re-add it
@@ -1626,8 +2163,11 @@ void EditorSceneImportPlugin::_add_new_nodes(Node *p_node,Node *p_imported,Node
if (o)
n=o->cast_to<Node>();
+ //print_line("creating node of same type..");
+
if (n) {
+ //print_line("copy props and add");
List<PropertyInfo> pl;
imported_node->get_property_list(&pl);
for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
@@ -1637,8 +2177,11 @@ void EditorSceneImportPlugin::_add_new_nodes(Node *p_node,Node *p_imported,Node
}
p_node->add_child(n);
+ n->set_owner(p_existing_scene);
}
+ } else {
+ //print_line("already exists");
}
@@ -1646,7 +2189,7 @@ void EditorSceneImportPlugin::_add_new_nodes(Node *p_node,Node *p_imported,Node
Node *other_node = p_node->get_node(imported_path);
- _add_new_nodes(other_node,imported_node,p_imported_scene,checked_nodes);
+ _add_new_nodes(other_node,imported_node,p_imported_scene,p_existing_scene,checked_nodes);
}
@@ -1659,11 +2202,100 @@ void EditorSceneImportPlugin::_merge_scenes(Node *p_node,Node *p_imported) {
Set<Ref<Resource> > checked_resources;
Set<Node*> checked_nodes;
_merge_existing_node(p_node,p_imported,checked_resources,checked_nodes);
- _add_new_nodes(p_node,p_imported,p_imported,checked_nodes);
+ _add_new_nodes(p_node,p_imported,p_imported,p_node,checked_nodes);
//add existing.. ?
}
+void EditorSceneImportPlugin::_scan_materials(Node*p_base,Node *p_node,Map<String,Ref<Material> > &mesh_materials,Map<String,Ref<Material> >& override_materials) {
+
+ if (!p_base && p_node->get_owner()!=p_base)
+ return;
+ MeshInstance *mi=p_node->cast_to<MeshInstance>();
+
+ if (mi) {
+ if (mi->get_material_override().is_valid()) {
+ String path = p_base->get_path_to(p_node);
+ override_materials[path]=mi->get_material_override();
+ }
+ Ref<Mesh> mesh = mi->get_mesh();
+ if (mesh.is_valid()) {
+
+ for(int i=0;i<mesh->get_surface_count();i++) {
+
+ String name = mesh->get_name()+":"+mesh->surface_get_name(i);
+ if (!mesh_materials.has(name)) {
+ mesh_materials[name]=mesh->surface_get_material(i);
+ }
+ }
+ }
+ }
+
+ for(int i=0;i<p_node->get_child_count();i++) {
+ _scan_materials(p_base,p_node->get_child(i),mesh_materials,override_materials);
+ }
+}
+
+
+void EditorSceneImportPlugin::_apply_materials(Node*p_base,Node *p_node,Map<String,Ref<Material> > &mesh_materials,Map<String,Ref<Material> >& override_materials,Set<Ref<Mesh> >& meshes_processed) {
+
+ if (p_node!=p_base && p_node->get_owner()!=p_base)
+ return;
+
+ MeshInstance *mi=p_node->cast_to<MeshInstance>();
+
+ if (mi) {
+
+ print_line("is mesh "+String(p_node->get_name()));
+ String path = p_base->get_path_to(p_node);
+ if (override_materials.has(path)) {
+ print_line("is in material overrides");
+ mi->set_material_override(override_materials[path]);
+ }
+
+ Ref<Mesh> mesh = mi->get_mesh();
+ if (mesh.is_valid() && !meshes_processed.has(mesh)) {
+ print_line("mesh was not processed");
+ meshes_processed.insert(mesh);
+ for(int i=0;i<mesh->get_surface_count();i++) {
+
+ String name = mesh->get_name()+":"+mesh->surface_get_name(i);
+ print_line("name for surface "+itos(i)+": "+name);
+ if (mesh_materials.has(name)) {
+
+ Ref<Material> mat = mesh_materials[name];
+ mesh->surface_set_material(i,mat);
+ print_line("overriding!");
+ }
+ }
+ }
+ }
+
+ for(int i=0;i<p_node->get_child_count();i++) {
+ _apply_materials(p_base,p_node->get_child(i),mesh_materials,override_materials,meshes_processed);
+ }
+}
+
+void EditorSceneImportPlugin::_merge_materials(Node *p_node,Node *p_imported) {
+
+ Map<String,Ref<Material> > mesh_materials;
+ Map<String,Ref<Material> > override_materials;
+
+ _scan_materials(p_node,p_node,mesh_materials,override_materials);
+
+ for (Map<String,Ref<Material> >::Element *E=mesh_materials.front();E;E=E->next()) {
+ print_line("Mats: "+String(E->key()));
+ }
+
+ for (Map<String,Ref<Material> >::Element *E=override_materials.front();E;E=E->next()) {
+ print_line("Overrides: "+String(E->key()));
+ }
+
+ Set<Ref<Mesh> > mp;
+ _apply_materials(p_imported,p_imported,mesh_materials,override_materials,mp);
+
+
+}
#if 0
@@ -1731,16 +2363,26 @@ Error EditorSceneImportPlugin::import1(const Ref<ResourceImportMetadata>& p_from
int animation_flags=p_from->get_option("animation_flags");
int scene_flags = from->get_option("flags");
+ int fps = 24;
+ if (from->has_option("animation_bake_fps"))
+ fps=from->get_option("animation_bake_fps");
+
+
+ Array clips;
+ if (from->has_option("animation_clips"))
+ clips=from->get_option("animation_clips");
uint32_t import_flags=0;
if (animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_DETECT_LOOP)
import_flags|=EditorSceneImporter::IMPORT_ANIMATION_DETECT_LOOP;
if (animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_OPTIMIZE)
import_flags|=EditorSceneImporter::IMPORT_ANIMATION_OPTIMIZE;
+ if (animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS)
+ import_flags|=EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS;
if (scene_flags&SCENE_FLAG_IMPORT_ANIMATIONS)
import_flags|=EditorSceneImporter::IMPORT_ANIMATION;
-// if (scene_flags&SCENE_FLAG_FAIL_ON_MISSING_IMAGES)
-// import_flags|=EditorSceneImporter::IMPORT_FAIL_ON_MISSING_DEPENDENCIES;
+ //if (scene_flags&SCENE_FLAG_FAIL_ON_MISSING_IMAGES)
+ // import_flags|=EditorSceneImporter::IMPORT_FAIL_ON_MISSING_DEPENDENCIES;
if (scene_flags&SCENE_FLAG_GENERATE_TANGENT_ARRAYS)
import_flags|=EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
@@ -1749,7 +2391,7 @@ Error EditorSceneImportPlugin::import1(const Ref<ResourceImportMetadata>& p_from
Error err=OK;
- Node *scene = importer->import_scene(src_path,import_flags,r_missing,&err);
+ Node *scene = importer->import_scene(src_path,import_flags,fps,r_missing,&err);
if (!scene || err!=OK) {
return err;
}
@@ -1760,19 +2402,304 @@ Error EditorSceneImportPlugin::import1(const Ref<ResourceImportMetadata>& p_from
return OK;
}
+
+void EditorSceneImportPlugin::_create_clips(Node *scene, const Array& p_clips,bool p_bake_all) {
+
+ if (!scene->has_node(String("AnimationPlayer")))
+ return;
+
+ Node* n = scene->get_node(String("AnimationPlayer"));
+ ERR_FAIL_COND(!n);
+ AnimationPlayer *anim = n->cast_to<AnimationPlayer>();
+ ERR_FAIL_COND(!anim);
+
+ if (!anim->has_animation("default"))
+ return;
+
+
+ Ref<Animation> default_anim = anim->get_animation("default");
+
+ for(int i=0;i<p_clips.size();i+=4) {
+
+ String name = p_clips[i];
+ float from=p_clips[i+1];
+ float to=p_clips[i+2];
+ bool loop=p_clips[i+3];
+ if (from>=to)
+ continue;
+
+ Ref<Animation> new_anim = memnew( Animation );
+
+ for(int j=0;j<default_anim->get_track_count();j++) {
+
+
+ List<float> keys;
+ int kc = default_anim->track_get_key_count(j);
+ int dtrack=-1;
+ for(int k=0;k<kc;k++) {
+
+ float kt = default_anim->track_get_key_time(j,k);
+ if (kt>=from && kt<to) {
+
+ //found a key within range, so create track
+ if (dtrack==-1) {
+ new_anim->add_track(default_anim->track_get_type(j));
+ dtrack = new_anim->get_track_count()-1;
+ new_anim->track_set_path(dtrack,default_anim->track_get_path(j));
+
+ if (kt>(from+0.01) && k>0) {
+
+ if (default_anim->track_get_type(j)==Animation::TYPE_TRANSFORM) {
+ Quat q;
+ Vector3 p;
+ Vector3 s;
+ default_anim->transform_track_interpolate(j,from,&p,&q,&s);
+ new_anim->transform_track_insert_key(dtrack,0,p,q,s);
+ }
+ }
+
+ }
+
+ if (default_anim->track_get_type(j)==Animation::TYPE_TRANSFORM) {
+ Quat q;
+ Vector3 p;
+ Vector3 s;
+ default_anim->transform_track_get_key(j,k,&p,&q,&s);
+ new_anim->transform_track_insert_key(dtrack,kt-from,p,q,s);
+ }
+
+ }
+
+ if (dtrack!=-1 && kt>=to) {
+
+ if (default_anim->track_get_type(j)==Animation::TYPE_TRANSFORM) {
+ Quat q;
+ Vector3 p;
+ Vector3 s;
+ default_anim->transform_track_interpolate(j,to,&p,&q,&s);
+ new_anim->transform_track_insert_key(dtrack,to-from,p,q,s);
+ }
+ }
+
+ }
+
+ if (dtrack==-1 && p_bake_all) {
+ new_anim->add_track(default_anim->track_get_type(j));
+ dtrack = new_anim->get_track_count()-1;
+ new_anim->track_set_path(dtrack,default_anim->track_get_path(j));
+ if (default_anim->track_get_type(j)==Animation::TYPE_TRANSFORM) {
+
+
+ Quat q;
+ Vector3 p;
+ Vector3 s;
+ default_anim->transform_track_interpolate(j,from,&p,&q,&s);
+ new_anim->transform_track_insert_key(dtrack,0,p,q,s);
+ default_anim->transform_track_interpolate(j,to,&p,&q,&s);
+ new_anim->transform_track_insert_key(dtrack,to-from,p,q,s);
+ }
+
+ }
+ }
+
+
+ new_anim->set_loop(loop);
+ new_anim->set_length(to-from);
+ anim->add_animation(name,new_anim);
+ }
+
+ anim->remove_animation("default"); //remove default (no longer needed)
+}
+
+void EditorSceneImportPlugin::_filter_anim_tracks(Ref<Animation> anim,Set<String> &keep) {
+
+ Ref<Animation> a = anim;
+ ERR_FAIL_COND(!a.is_valid());
+
+ print_line("From Anim "+anim->get_name()+":");
+
+ for(int j=0;j<a->get_track_count();j++) {
+
+ String path = a->track_get_path(j);
+
+ if (!keep.has(path)) {
+
+ print_line("Remove: "+path);
+ a->remove_track(j);
+ j--;
+ }
+
+ }
+}
+
+
+void EditorSceneImportPlugin::_filter_tracks(Node *scene, const String& p_text) {
+
+ if (!scene->has_node(String("AnimationPlayer")))
+ return;
+ Node* n = scene->get_node(String("AnimationPlayer"));
+ ERR_FAIL_COND(!n);
+ AnimationPlayer *anim = n->cast_to<AnimationPlayer>();
+ ERR_FAIL_COND(!anim);
+
+ Vector<String> strings = p_text.split("\n");
+ for(int i=0;i<strings.size();i++) {
+
+ strings[i]=strings[i].strip_edges();
+ }
+
+ List<StringName> anim_names;
+ anim->get_animation_list(&anim_names);
+ for(List<StringName>::Element *E=anim_names.front();E;E=E->next()) {
+
+ String name = E->get();
+ bool valid_for_this=false;
+ bool valid=false;
+
+ Set<String> keep;
+ Set<String> keep_local;
+
+
+ for(int i=0;i<strings.size();i++) {
+
+
+ if (strings[i].begins_with("@")) {
+
+ valid_for_this=false;
+ for(Set<String>::Element *F=keep_local.front();F;F=F->next()) {
+ keep.insert(F->get());
+ }
+ keep_local.clear();
+
+ Vector<String> filters=strings[i].substr(1,strings[i].length()).split(",");
+ for(int j=0;j<filters.size();j++) {
+
+ String fname = filters[j].strip_edges();
+ if (fname=="")
+ continue;
+ int fc = fname[0];
+ bool plus;
+ if (fc=='+')
+ plus=true;
+ else if (fc=='-')
+ plus=false;
+ else
+ continue;
+
+ String filter=fname.substr(1,fname.length()).strip_edges();
+
+ if (!name.matchn(filter))
+ continue;
+ valid_for_this=plus;
+ }
+
+ if (valid_for_this)
+ valid=true;
+
+ } else if (valid_for_this) {
+
+ Ref<Animation> a = anim->get_animation(name);
+ if (!a.is_valid())
+ continue;
+
+ for(int j=0;j<a->get_track_count();j++) {
+
+ String path = a->track_get_path(j);
+
+ String tname = strings[i];
+ if (tname=="")
+ continue;
+ int fc = tname[0];
+ bool plus;
+ if (fc=='+')
+ plus=true;
+ else if (fc=='-')
+ plus=false;
+ else
+ continue;
+
+ String filter=tname.substr(1,tname.length()).strip_edges();
+
+ if (!path.matchn(filter))
+ continue;
+
+ if (plus)
+ keep_local.insert(path);
+ else if (!keep.has(path)) {
+ keep_local.erase(path);
+ }
+ }
+
+ }
+
+ }
+
+ if (valid) {
+ for(Set<String>::Element *F=keep_local.front();F;F=F->next()) {
+ keep.insert(F->get());
+ }
+ print_line("FILTERING ANIM: "+String(E->get()));
+ _filter_anim_tracks(anim->get_animation(name),keep);
+ } else {
+ print_line("NOT FILTERING ANIM: "+String(E->get()));
+
+ }
+
+ }
+
+
+
+}
+
+void EditorSceneImportPlugin::_optimize_animations(Node *scene, float p_max_lin_error,float p_max_ang_error,float p_max_angle) {
+
+ if (!scene->has_node(String("AnimationPlayer")))
+ return;
+ Node* n = scene->get_node(String("AnimationPlayer"));
+ ERR_FAIL_COND(!n);
+ AnimationPlayer *anim = n->cast_to<AnimationPlayer>();
+ ERR_FAIL_COND(!anim);
+
+
+ List<StringName> anim_names;
+ anim->get_animation_list(&anim_names);
+ for(List<StringName>::Element *E=anim_names.front();E;E=E->next()) {
+
+ Ref<Animation> a = anim->get_animation(E->get());
+ a->optimize(p_max_lin_error,p_max_ang_error,Math::deg2rad(p_max_angle));
+ }
+}
+
+
Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, const Ref<ResourceImportMetadata>& p_from) {
Error err=OK;
Ref<ResourceImportMetadata> from=p_from;
String src_path=EditorImportPlugin::expand_source_path(from->get_source_path(0));
int animation_flags=p_from->get_option("animation_flags");
+ Array animation_clips = p_from->get_option("animation_clips");
+ String animation_filter = p_from->get_option("animation_filters");
int scene_flags = from->get_option("flags");
+ float anim_optimizer_linerr=0.05;
+ float anim_optimizer_angerr=0.01;
+ float anim_optimizer_maxang=22;
+
+ if (from->has_option("animation_optimizer_linear_error"))
+ anim_optimizer_linerr=from->get_option("animation_optimizer_linear_error");
+ if (from->has_option("animation_optimizer_angular_error"))
+ anim_optimizer_angerr=from->get_option("animation_optimizer_angular_error");
+ if (from->has_option("animation_optimizer_max_angle"))
+ anim_optimizer_maxang=from->get_option("animation_optimizer_max_angle");
EditorProgress progress("import","Import Scene",104);
progress.step("Importing Scene..",2);
- bool merge = !bool(from->get_option("reimport"));
+ bool reimport = bool(from->get_option("reimport"));
+ int this_time_action = from->get_option("import_this_time");
+ int next_time_action = from->get_option("import_next_time");
+
+ int import_action = reimport?this_time_action:next_time_action;
from->set_source_md5(0,FileAccess::get_md5(src_path));
from->set_editor(get_name());
@@ -1784,9 +2711,16 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
Ref<ResourceImportMetadata> imd = memnew(ResourceImportMetadata);
- Map< Ref<ImageTexture>,bool > imagemap;
+ Map< Ref<ImageTexture>,TextureRole > imagemap;
scene=_fix_node(scene,scene,collision_map,scene_flags,imagemap);
+ if (animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_OPTIMIZE)
+ _optimize_animations(scene,anim_optimizer_linerr,anim_optimizer_angerr,anim_optimizer_maxang);
+ if (animation_clips.size())
+ _create_clips(scene,animation_clips,animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
+
+ _filter_tracks(scene,animation_filter);
+
/// BEFORE ANYTHING, RUN SCRIPT
@@ -1797,7 +2731,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
Ref<EditorScenePostImport> post_import_script;
if (post_import_script_path!="") {
- post_import_script_path = EditorImportPlugin::expand_source_path(post_import_script_path);
+ post_import_script_path = post_import_script_path;
Ref<Script> scr = ResourceLoader::load(post_import_script_path);
if (!scr.is_valid()) {
EditorNode::add_io_error("Couldn't load post-import script: '"+post_import_script_path);
@@ -1819,8 +2753,11 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
EditorNode::add_io_error("Error running Post-Import script: '"+post_import_script_path);
return err;
}
+
+
}
+
/// IMPORT IMAGES
@@ -1830,7 +2767,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
int image_flags = from->get_option("texture_flags");
float image_quality = from->get_option("texture_quality");
- for (Map< Ref<ImageTexture>,bool >::Element *E=imagemap.front();E;E=E->next()) {
+ for (Map< Ref<ImageTexture>,TextureRole >::Element *E=imagemap.front();E;E=E->next()) {
//texture could be converted to something more useful for 3D, that could load individual mipmaps and stuff
//but not yet..
@@ -1866,8 +2803,12 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
print_line("flags: "+itos(image_flags));
uint32_t flags = image_flags;
- if (E->get())
+ if (E->get()==TEXTURE_ROLE_DIFFUSE && scene_flags&SCENE_FLAG_LINEARIZE_DIFFUSE_TEXTURES)
flags|=EditorTextureImportPlugin::IMAGE_FLAG_CONVERT_TO_LINEAR;
+
+ if (E->get()==TEXTURE_ROLE_NORMALMAP && scene_flags&SCENE_FLAG_CONVERT_NORMALMAPS_TO_XY)
+ flags|=EditorTextureImportPlugin::IMAGE_FLAG_CONVERT_NORMAL_TO_XY;
+
imd->set_option("flags",flags);
imd->set_option("format",image_format);
imd->set_option("quality",image_quality);
@@ -1906,7 +2847,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
/// BEFORE SAVING - MERGE
- if (merge) {
+ if (import_action!=SCENE_UPDATE_REPLACE_WITH_NEW) {
progress.step("Merging..",103);
@@ -1925,10 +2866,30 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
if (existing) {
- _merge_scenes(existing,scene);
- memdelete(scene);
- scene=existing;
+ switch(import_action) {
+
+ case SCENE_UPDATE_REPLACE_WITH_NEW: break;
+ case SCENE_UPDATE_REPLACE_WITH_NEW_KEEP_MATERIALS: {
+
+ _merge_materials(existing,scene);
+ memdelete(existing);
+
+ } break;
+ case SCENE_UPDATE_KEEP_OLD_MERGE_CHANGES: {
+
+ _merge_scenes(existing,scene);
+ memdelete(scene);
+ scene=existing;
+
+ } break;
+ case SCENE_UPDATE_KEEP_OLD: {
+
+ memdelete(scene);
+ scene=existing;
+ } break;
+ }
+
}
}
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.h b/tools/editor/io_plugins/editor_scene_import_plugin.h
index 928fff2afb..71efab9503 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -58,14 +58,15 @@ public:
IMPORT_ANIMATION=2,
IMPORT_ANIMATION_DETECT_LOOP=4,
IMPORT_ANIMATION_OPTIMIZE=8,
- IMPORT_GENERATE_TANGENT_ARRAYS=16,
- IMPORT_FAIL_ON_MISSING_DEPENDENCIES=128
+ IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS=16,
+ IMPORT_GENERATE_TANGENT_ARRAYS=256,
+ IMPORT_FAIL_ON_MISSING_DEPENDENCIES=512
};
virtual uint32_t get_import_flags() const=0;
virtual void get_extensions(List<String> *r_extensions) const=0;
- virtual Node* import_scene(const String& p_path,uint32_t p_flags,List<String> *r_missing_deps,Error* r_err=NULL)=0;
+ virtual Node* import_scene(const String& p_path,uint32_t p_flags,int p_bake_fps,List<String> *r_missing_deps,Error* r_err=NULL)=0;
virtual Ref<Animation> import_animation(const String& p_path,uint32_t p_flags)=0;
@@ -99,12 +100,26 @@ class EditorSceneImportPlugin : public EditorImportPlugin {
Vector<Ref<EditorSceneImporter> > importers;
- void _find_resources(const Variant& p_var,Map<Ref<ImageTexture>,bool >& image_map);
- Node* _fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Map<Ref<ImageTexture>,bool >& image_map);
+ enum TextureRole {
+ TEXTURE_ROLE_DEFAULT,
+ TEXTURE_ROLE_DIFFUSE,
+ TEXTURE_ROLE_NORMALMAP
+ };
+
+ void _find_resources(const Variant& p_var,Map<Ref<ImageTexture>,TextureRole >& image_map,int p_flags);
+ Node* _fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Map<Ref<ImageTexture>,TextureRole >& image_map);
+ void _create_clips(Node *scene, const Array& p_clips, bool p_bake_all);
+ void _filter_anim_tracks(Ref<Animation> anim,Set<String> &keep);
+ void _filter_tracks(Node *scene, const String& p_text);
void _merge_existing_node(Node *p_node,Node *p_imported_scene,Set<Ref<Resource> >& checked_resources,Set<Node*> &checked_nodes);
- void _add_new_nodes(Node *p_node,Node *p_imported,Node *p_imported_scene,Set<Node*> &checked_nodes);
+
+ void _add_new_nodes(Node *p_node,Node *p_imported,Node *p_imported_scene,Node *p_existing_scene,Set<Node*> &checked_nodes);
+ void _optimize_animations(Node *scene, float p_max_lin_error,float p_max_ang_error,float p_max_angle);
void _merge_scenes(Node *p_node, Node *p_imported);
+ void _scan_materials(Node*p_base,Node *p_node,Map<String,Ref<Material> > &mesh_materials,Map<String,Ref<Material> >& override_materials);
+ void _apply_materials(Node*p_base,Node *p_node,Map<String,Ref<Material> > &mesh_materials,Map<String,Ref<Material> >& override_materials,Set<Ref<Mesh> >& meshes_processed);
+ void _merge_materials(Node *p_node,Node *p_imported);
void _tag_import_paths(Node *p_scene,Node *p_node);
@@ -124,12 +139,22 @@ public:
SCENE_FLAG_DETECT_ALPHA=1<<15,
SCENE_FLAG_DETECT_VCOLOR=1<<16,
SCENE_FLAG_CREATE_NAVMESH=1<<17,
+ SCENE_FLAG_DETECT_LIGHTMAP_LAYER=1<<18,
SCENE_FLAG_REMOVE_NOIMP=1<<24,
SCENE_FLAG_IMPORT_ANIMATIONS=1<<25,
SCENE_FLAG_COMPRESS_GEOMETRY=1<<26,
SCENE_FLAG_GENERATE_TANGENT_ARRAYS=1<<27,
SCENE_FLAG_LINEARIZE_DIFFUSE_TEXTURES=1<<28,
+ SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS=1<<29,
+ SCENE_FLAG_CONVERT_NORMALMAPS_TO_XY=1<<30,
+ };
+
+ enum SceneUpdate {
+ SCENE_UPDATE_REPLACE_WITH_NEW,
+ SCENE_UPDATE_REPLACE_WITH_NEW_KEEP_MATERIALS,
+ SCENE_UPDATE_KEEP_OLD_MERGE_CHANGES,
+ SCENE_UPDATE_KEEP_OLD,
};
@@ -160,7 +185,8 @@ public:
ANIMATION_DETECT_LOOP=1,
ANIMATION_KEEP_VALUE_TRACKS=2,
- ANIMATION_OPTIMIZE=4
+ ANIMATION_OPTIMIZE=4,
+ ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS=8
};
virtual String get_name() const;
@@ -174,5 +200,4 @@ public:
};
-
#endif // EDITOR_SCENE_IMPORT_PLUGIN_H
diff --git a/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp b/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp
new file mode 100644
index 0000000000..0c388b91ca
--- /dev/null
+++ b/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp
@@ -0,0 +1,1106 @@
+#include "editor_scene_importer_fbxconv.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "tools/editor/editor_settings.h"
+#include "scene/3d/mesh_instance.h"
+#include "scene/animation/animation_player.h"
+
+
+String EditorSceneImporterFBXConv::_id(const String& p_id) const {
+
+ return p_id.replace(":","_").replace("/","_");
+}
+
+uint32_t EditorSceneImporterFBXConv::get_import_flags() const {
+
+ return IMPORT_SCENE|IMPORT_ANIMATION;
+}
+void EditorSceneImporterFBXConv::get_extensions(List<String> *r_extensions) const{
+
+ r_extensions->push_back("fbx");
+ r_extensions->push_back("g3dj");
+}
+
+
+Color EditorSceneImporterFBXConv::_get_color(const Array& a) {
+
+ if (a.size()<3)
+ return Color();
+ Color c;
+ c.r=a[0];
+ c.g=a[1];
+ c.b=a[2];
+ if (a.size()>=4)
+ c.a=a[3];
+ return c;
+
+}
+
+Transform EditorSceneImporterFBXConv::_get_transform_mixed(const Dictionary& d,const Dictionary& dbase) {
+
+
+
+
+ Array translation;
+
+ if (d.has("translation"))
+ translation=d["translation"];
+ else if (dbase.has("translation"))
+ translation=dbase["translation"];
+
+ Array rotation;
+
+ if (d.has("rotation"))
+ rotation=d["rotation"];
+ else if (dbase.has("rotation"))
+ rotation=dbase["rotation"];
+
+ Array scale;
+
+ if (d.has("scale"))
+ scale=d["scale"];
+ else if (dbase.has("scale"))
+ scale=dbase["scale"];
+
+ Transform t;
+
+
+ if (translation.size()) {
+ Array tr = translation;
+ if (tr.size()>=3) {
+ t.origin.x=tr[0];
+ t.origin.y=tr[1];
+ t.origin.z=tr[2];
+ }
+ }
+
+ if (rotation.size()) {
+
+ Array r = rotation;
+ if (r.size()>=4) {
+
+ Quat q;
+ q.x = r[0];
+ q.y = r[1];
+ q.z = r[2];
+ q.w = r[3];
+ t.basis=Matrix3(q);
+ }
+ }
+
+
+ if (scale.size()) {
+
+ Array sc = scale;
+ if (sc.size()>=3) {
+ Vector3 s;
+ s.x=sc[0];
+ s.y=sc[1];
+ s.z=sc[2];
+ t.basis.scale(s);
+ }
+ }
+
+ return t;
+
+
+}
+
+Transform EditorSceneImporterFBXConv::_get_transform(const Dictionary& d) {
+
+
+ Transform t;
+
+ if (d.has("translation")) {
+ Array tr = d["translation"];
+ if (tr.size()>=3) {
+ t.origin.x=tr[0];
+ t.origin.y=tr[1];
+ t.origin.z=tr[2];
+ }
+ }
+
+ if (d.has("rotation")) {
+
+ Array r = d["rotation"];
+ if (r.size()>=4) {
+
+ Quat q;
+ q.x = r[0];
+ q.y = r[1];
+ q.z = r[2];
+ q.w = r[3];
+ t.basis=Matrix3(q);
+ }
+ }
+
+
+ if (d.has("scale")) {
+
+ Array sc = d["scale"];
+ if (sc.size()>=3) {
+ Vector3 s;
+ s.x=sc[0];
+ s.y=sc[1];
+ s.z=sc[2];
+ t.basis.scale(s);
+ }
+ }
+
+ return t;
+}
+
+
+void EditorSceneImporterFBXConv::_detect_bones_in_nodes(State& state,const Array& p_nodes) {
+
+
+ for(int i=0;i<p_nodes.size();i++) {
+
+ Dictionary d = p_nodes[i];
+ if (d.has("isBone") && bool(d["isBone"])) {
+
+ String bone_name=_id(d["id"]);
+ print_line("IS BONE: "+bone_name);
+ if (!state.bones.has(bone_name)) {
+ state.bones.insert(bone_name,BoneInfo());
+ }
+
+ if (!state.bones[bone_name].has_rest) {
+ state.bones[bone_name].rest=_get_transform(d).affine_inverse();
+ }
+
+ state.bones[bone_name].node=d;
+
+ //state.bones[name].rest=_get_transform(b);
+ }
+
+ if (d.has("parts")) {
+
+ Array parts=d["parts"];
+ for(int j=0;j<parts.size();j++) {
+
+ Dictionary p=parts[j];
+ if (p.has("bones")) {
+ Array bones=p["bones"];
+ //omfg
+ for(int k=0;k<bones.size();k++) {
+
+ Dictionary b = bones[k];
+ if (b.has("node")) {
+
+ String name = _id(b["node"]);
+ if (!state.bones.has(name)) {
+ state.bones.insert(name,BoneInfo());
+ }
+
+ state.bones[name].rest=_get_transform(b);
+ state.bones[name].has_rest=true;
+ }
+ }
+ }
+
+ }
+ }
+
+ if (d.has("children")) {
+
+ _detect_bones_in_nodes(state,d["children"]);
+ }
+ }
+
+}
+
+void EditorSceneImporterFBXConv::_parse_skeletons(const String& p_name,State& state, const Array &p_nodes, Skeleton *p_skeleton,int p_parent) {
+
+
+
+ for(int i=0;i<p_nodes.size();i++) {
+
+
+ Dictionary d = p_nodes[i];
+ int bone_idx=-1;
+ String id;
+ Skeleton* skeleton=p_skeleton;
+ if (d.has("id")) {
+
+ id=_id(d["id"]);
+ if (state.bones.has(id)) {
+ //BONER
+ if (!skeleton) {
+ skeleton=memnew( Skeleton );
+ state.skeletons[id]=skeleton;
+ }
+ bone_idx = skeleton->get_bone_count();
+ skeleton->add_bone(id);
+ skeleton->set_bone_parent(bone_idx,p_parent);
+ skeleton->set_bone_rest(bone_idx,state.bones[id].rest);
+ state.bones[id].skeleton=skeleton;
+ }
+ }
+
+ if (d.has("children")) {
+
+ _parse_skeletons(id,state,d["children"],skeleton,bone_idx);
+ }
+ }
+
+}
+
+void EditorSceneImporterFBXConv::_detect_bones(State& state) {
+ //This format should mark when a node is a bone,
+ //which is the only thing that Collada does right.
+ //think about others implementing a parser.
+ //Just _one_ string and you avoid loads of lines of code to other people.
+
+ for(int i=0;i<state.animations.size();i++) {
+
+ Dictionary an = state.animations[i];
+ if (an.has("bones")) {
+
+ Array bo=an["bones"];
+ for(int j=0;j<bo.size();j++) {
+
+ Dictionary b=bo[j];
+ if (b.has("boneId")) {
+
+ String id = b["boneId"];
+ if (!state.bones.has(id)) {
+ state.bones.insert(id,BoneInfo());
+ }
+ state.bones[id].has_anim_chan=true; //used in anim
+
+
+ }
+ }
+ }
+ }
+
+ _detect_bones_in_nodes(state,state.nodes);
+ _parse_skeletons("",state,state.nodes,NULL,-1);
+
+ print_line("found bones: "+itos(state.bones.size()));
+ print_line("found skeletons: "+itos(state.skeletons.size()));
+}
+
+Error EditorSceneImporterFBXConv::_parse_bones(State& state,const Array &p_bones,Skeleton* p_skeleton) {
+
+
+
+ return OK;
+}
+
+
+void EditorSceneImporterFBXConv::_add_surface(State& state,Ref<Mesh>& m,const Dictionary &part) {
+
+ if (part.has("meshpartid")) {
+
+ String id = part["meshpartid"];
+ ERR_FAIL_COND(!state.surface_cache.has(id));
+
+
+ Ref<Material> mat;
+ if (part.has("materialid")) {
+ String matid=part["materialid"];
+ if (state.material_cache.has(matid)) {
+ mat=state.material_cache[matid];
+ }
+ }
+ int idx = m->get_surface_count();
+
+ Array array = state.surface_cache[id].array;
+ DVector<float> indices = array[Mesh::ARRAY_BONES];
+ if (indices.size() && part.has("bones")) {
+
+
+ Map<int,int> index_map;
+
+ Array bones=part["bones"];
+
+ for(int i=0;i<bones.size();i++) {
+
+ Dictionary bone=bones[i];
+ String name=_id(bone["node"]);
+
+ if (state.bones.has(name)) {
+ int idx=state.bones[name].skeleton->find_bone(name);
+ if (idx==-1)
+ idx=0;
+ index_map[i]=idx;
+ }
+ }
+
+
+
+ int ilen=indices.size();
+ {
+ DVector<float>::Write iw=indices.write();
+ for(int j=0;j<ilen;j++) {
+ int b = iw[j];
+ ERR_CONTINUE(!index_map.has(b));
+ b=index_map[b];
+ iw[j]=b;
+ }
+ }
+
+ array[Mesh::ARRAY_BONES]=indices;
+
+
+ }
+
+ m->add_surface(state.surface_cache[id].primitive,array);
+ m->surface_set_material(idx,mat);
+ m->surface_set_name(idx,id);
+ }
+
+}
+
+Error EditorSceneImporterFBXConv::_parse_nodes(State& state,const Array &p_nodes,Node* p_base) {
+
+ for(int i=0;i<p_nodes.size();i++) {
+
+ Dictionary n = p_nodes[i];
+ Spatial *node=NULL;
+ bool skip=false;
+
+ String id;
+ if (n.has("id")) {
+ id=_id(n["id"]);
+ }
+
+ print_line("ID: "+id);
+
+ if (state.skeletons.has(id)) {
+
+ Skeleton *skeleton = state.skeletons[id];
+ node=skeleton;
+ skeleton->localize_rests();
+ print_line("IS SKELETON! ");
+ } else if (state.bones.has(id)) {
+ if (p_base)
+ node=p_base->cast_to<Spatial>();
+ if (!state.bones[id].has_anim_chan) {
+ print_line("no has anim "+id);
+ }
+ skip=true;
+ } else if (n.has("parts")) {
+ //is a mesh
+ MeshInstance *mesh = memnew( MeshInstance );
+ node=mesh;
+
+ Array parts=n["parts"];
+ String long_identifier;
+ for(int j=0;j<parts.size();j++) {
+
+ Dictionary part=parts[j];
+ if (part.has("meshpartid")) {
+ String partid=part["meshpartid"];
+ long_identifier+=partid;
+ }
+ }
+
+ Ref<Mesh> m;
+
+ if (state.mesh_cache.has(long_identifier)) {
+ m=state.mesh_cache[long_identifier];
+ } else {
+ m = Ref<Mesh>( memnew( Mesh ) );
+
+ //and parts are surfaces
+ for(int j=0;j<parts.size();j++) {
+
+ Dictionary part=parts[j];
+ if (part.has("meshpartid")) {
+ _add_surface(state,m,part);
+ }
+ }
+
+
+ state.mesh_cache[long_identifier]=m;
+ }
+
+ mesh->set_mesh(m);
+ }
+
+ if (!skip) {
+
+ if (!node) {
+ node = memnew( Spatial );
+ }
+
+ node->set_name(id);
+ node->set_transform(_get_transform(n));
+ p_base->add_child(node);
+ node->set_owner(state.scene);
+ }
+
+
+ if (n.has("children")) {
+ Error err = _parse_nodes(state,n["children"],node);
+ if (err)
+ return err;
+ }
+ }
+
+ return OK;
+}
+
+
+void EditorSceneImporterFBXConv::_parse_materials(State& state) {
+
+ for(int i=0;i<state.materials.size();i++) {
+
+ Dictionary material = state.materials[i];
+
+ ERR_CONTINUE(!material.has("id"));
+ String id = _id(material["id"]);
+
+ Ref<FixedMaterial> mat = memnew( FixedMaterial );
+
+ if (material.has("diffuse")) {
+ mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,_get_color(material["diffuse"]));
+ }
+
+ if (material.has("specular")) {
+ mat->set_parameter(FixedMaterial::PARAM_SPECULAR,_get_color(material["specular"]));
+ }
+
+ if (material.has("emissive")) {
+ mat->set_parameter(FixedMaterial::PARAM_EMISSION,_get_color(material["emissive"]));
+ }
+
+ if (material.has("shininess")) {
+ float exp = material["shininess"];
+ mat->set_parameter(FixedMaterial::PARAM_SPECULAR_EXP,exp);
+ }
+
+ if (material.has("opacity")) {
+ Color c = mat->get_parameter(FixedMaterial::PARAM_DIFFUSE);
+ c.a=material["opacity"];
+ mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,c);
+ }
+
+
+ if (material.has("textures")) {
+
+ Array textures = material["textures"];
+ for(int j=0;j<textures.size();j++) {
+
+ Dictionary texture=textures[j];
+ Ref<Texture> tex;
+ if (texture.has("filename")) {
+
+
+ String filename=texture["filename"];
+ String path=state.base_path+"/"+filename.replace("\\","/");
+ if (state.texture_cache.has(path)) {
+ tex=state.texture_cache[path];
+ } else {
+ tex = ResourceLoader::load(path,"ImageTexture");
+ if (tex.is_null()) {
+ if (state.missing_deps)
+ state.missing_deps->push_back(path);
+ }
+ state.texture_cache[path]=tex; //add anyway
+ }
+ }
+
+ if (tex.is_valid() && texture.has("type")) {
+
+ String type=texture["type"];
+ if (type=="DIFFUSE")
+ mat->set_texture(FixedMaterial::PARAM_DIFFUSE,tex);
+ else if (type=="SPECULAR")
+ mat->set_texture(FixedMaterial::PARAM_SPECULAR,tex);
+ else if (type=="SHININESS")
+ mat->set_texture(FixedMaterial::PARAM_SPECULAR_EXP,tex);
+ else if (type=="NORMAL")
+ mat->set_texture(FixedMaterial::PARAM_NORMAL,tex);
+ else if (type=="EMISSIVE")
+ mat->set_texture(FixedMaterial::PARAM_EMISSION,tex);
+ }
+
+ }
+ }
+
+ state.material_cache[id]=mat;
+
+ }
+
+}
+
+void EditorSceneImporterFBXConv::_parse_surfaces(State& state) {
+
+ for(int i=0;i<state.meshes.size();i++) {
+
+ Dictionary mesh = state.meshes[i];
+
+ ERR_CONTINUE(!mesh.has("attributes"));
+ ERR_CONTINUE(!mesh.has("vertices"));
+ ERR_CONTINUE(!mesh.has("parts"));
+
+ print_line("MESH #"+itos(i));
+
+ Array attrlist=mesh["attributes"];
+ Array vertices=mesh["vertices"];
+ bool exists[Mesh::ARRAY_MAX];
+ int ofs[Mesh::ARRAY_MAX];
+ int weight_max=0;
+ int binormal_ofs=-1;
+ int weight_ofs[4];
+
+ for(int j=0;j<Mesh::ARRAY_MAX;j++) {
+ exists[j]=false;
+ ofs[j]=0;
+ }
+ exists[Mesh::ARRAY_INDEX]=true;
+ float stride=0;
+
+ for(int j=0;j<attrlist.size();j++) {
+
+ String attr=attrlist[j];
+ if (attr=="POSITION") {
+ exists[Mesh::ARRAY_VERTEX]=true;
+ ofs[Mesh::ARRAY_VERTEX]=stride;
+ stride+=3;
+ } else if (attr=="NORMAL") {
+ exists[Mesh::ARRAY_NORMAL]=true;
+ ofs[Mesh::ARRAY_NORMAL]=stride;
+ stride+=3;
+ } else if (attr=="COLOR") {
+ exists[Mesh::ARRAY_COLOR]=true;
+ ofs[Mesh::ARRAY_COLOR]=stride;
+ stride+=4;
+ } else if (attr=="COLORPACKED") {
+ stride+=1; //ignore
+ } else if (attr=="TANGENT") {
+ exists[Mesh::ARRAY_TANGENT]=true;
+ ofs[Mesh::ARRAY_TANGENT]=stride;
+ stride+=3;
+ } else if (attr=="BINORMAL") {
+ binormal_ofs=stride;
+ stride+=3;
+ } else if (attr=="TEXCOORD0") {
+ exists[Mesh::ARRAY_TEX_UV]=true;
+ ofs[Mesh::ARRAY_TEX_UV]=stride;
+ stride+=2;
+ } else if (attr=="TEXCOORD1") {
+ exists[Mesh::ARRAY_TEX_UV2]=true;
+ ofs[Mesh::ARRAY_TEX_UV2]=stride;
+ stride+=2;
+ } else if (attr.begins_with("TEXCOORD")) {
+ stride+=2;
+ } else if (attr.begins_with("BLENDWEIGHT")) {
+ int idx=attr.replace("BLENDWEIGHT","").to_int();
+ if (idx==0) {
+ exists[Mesh::ARRAY_BONES]=true;
+ ofs[Mesh::ARRAY_BONES]=stride;
+ exists[Mesh::ARRAY_WEIGHTS]=true;
+ ofs[Mesh::ARRAY_WEIGHTS]=stride+1;
+ } if (idx<4) {
+ weight_ofs[idx]=stride;
+ weight_max=MAX(weight_max,idx+1);
+ }
+
+ stride+=2;
+ }
+
+ print_line("ATTR "+attr+" OFS: "+itos(stride));
+
+ }
+
+ Array parts=mesh["parts"];
+
+ for(int j=0;j<parts.size();j++) {
+
+
+
+ Dictionary part=parts[j];
+ ERR_CONTINUE(!part.has("indices"));
+ ERR_CONTINUE(!part.has("id"));
+
+ print_line("PART: "+String(part["id"]));
+ Array indices=part["indices"];
+ Map<int,int> iarray;
+ Map<int,int> array;
+
+ for(int k=0;k<indices.size();k++) {
+
+ int idx = indices[k];
+ if (!iarray.has(idx)) {
+ int map_to=array.size();
+ iarray[idx]=map_to;
+ array[map_to]=idx;
+ }
+ }
+
+ print_line("indices total "+itos(indices.size())+" vertices used: "+itos(array.size()));
+
+ Array arrays;
+ arrays.resize(Mesh::ARRAY_MAX);
+
+
+
+ for(int k=0;k<Mesh::ARRAY_MAX;k++) {
+
+
+ if (!exists[k])
+ continue;
+ print_line("exists: "+itos(k));
+ int lofs = ofs[k];
+ switch(k) {
+
+ case Mesh::ARRAY_VERTEX:
+ case Mesh::ARRAY_NORMAL: {
+
+ DVector<Vector3> vtx;
+ vtx.resize(array.size());
+ {
+ int len=array.size();
+ DVector<Vector3>::Write w = vtx.write();
+ for(int l=0;l<len;l++) {
+
+ int pos = array[l];
+ w[l].x=vertices[pos*stride+lofs+0];
+ w[l].y=vertices[pos*stride+lofs+1];
+ w[l].z=vertices[pos*stride+lofs+2];
+ }
+ }
+ arrays[k]=vtx;
+
+ } break;
+ case Mesh::ARRAY_TANGENT: {
+
+ if (binormal_ofs<0)
+ break;
+
+ DVector<float> tangents;
+ tangents.resize(array.size()*4);
+ {
+ int len=array.size();
+
+ DVector<float>::Write w = tangents.write();
+ for(int l=0;l<len;l++) {
+
+ int pos = array[l];
+ Vector3 n;
+ n.x=vertices[pos*stride+ofs[Mesh::ARRAY_NORMAL]+0];
+ n.y=vertices[pos*stride+ofs[Mesh::ARRAY_NORMAL]+1];
+ n.z=vertices[pos*stride+ofs[Mesh::ARRAY_NORMAL]+2];
+ Vector3 t;
+ t.x=vertices[pos*stride+lofs+0];
+ t.y=vertices[pos*stride+lofs+1];
+ t.z=vertices[pos*stride+lofs+2];
+ Vector3 bi;
+ bi.x=vertices[pos*stride+binormal_ofs+0];
+ bi.y=vertices[pos*stride+binormal_ofs+1];
+ bi.z=vertices[pos*stride+binormal_ofs+2];
+ float d = bi.dot(n.cross(t));
+
+ w[l*4+0]=t.x;
+ w[l*4+1]=t.y;
+ w[l*4+2]=t.z;
+ w[l*4+3]=d;
+
+ }
+ }
+ arrays[k]=tangents;
+
+ } break;
+ case Mesh::ARRAY_COLOR: {
+
+ DVector<Color> cols;
+ cols.resize(array.size());
+ {
+ int len=array.size();
+ DVector<Color>::Write w = cols.write();
+ for(int l=0;l<len;l++) {
+
+ int pos = array[l];
+ w[l].r=vertices[pos*stride+lofs+0];
+ w[l].g=vertices[pos*stride+lofs+1];
+ w[l].b=vertices[pos*stride+lofs+2];
+ w[l].a=vertices[pos*stride+lofs+3];
+ }
+ }
+ arrays[k]=cols;
+
+ } break;
+ case Mesh::ARRAY_TEX_UV:
+ case Mesh::ARRAY_TEX_UV2: {
+
+ DVector<Vector2> uvs;
+ uvs.resize(array.size());
+ {
+ int len=array.size();
+ DVector<Vector2>::Write w = uvs.write();
+ for(int l=0;l<len;l++) {
+
+ int pos = array[l];
+ w[l].x=vertices[pos*stride+lofs+0];
+ w[l].y=vertices[pos*stride+lofs+1];
+ w[l].y=1.0-w[l].y;
+ }
+ }
+ arrays[k]=uvs;
+
+ } break;
+ case Mesh::ARRAY_BONES:
+ case Mesh::ARRAY_WEIGHTS: {
+
+ DVector<float> arr;
+ arr.resize(array.size()*4);
+ int po=k==Mesh::ARRAY_WEIGHTS?1:0;
+ lofs=ofs[Mesh::ARRAY_BONES];
+ {
+ int len=array.size();
+
+ DVector<float>::Write w = arr.write();
+ for(int l=0;l<len;l++) {
+
+ int pos = array[l];
+
+ for(int m=0;m<4;m++) {
+
+ float val=0;
+ if (m<=weight_max)
+ val=vertices[pos*stride+lofs+m*2+po];
+ w[l*4+m]=val;
+ }
+ }
+ }
+
+ arrays[k]=arr;
+ } break;
+ case Mesh::ARRAY_INDEX: {
+
+ DVector<int> arr;
+ arr.resize(indices.size());
+ {
+ int len=indices.size();
+
+ DVector<int>::Write w = arr.write();
+ for(int l=0;l<len;l++) {
+
+ w[l]=iarray[ indices[l] ];
+ }
+ }
+
+ arrays[k]=arr;
+
+ } break;
+
+
+ }
+
+
+ }
+
+ Mesh::PrimitiveType pt=Mesh::PRIMITIVE_TRIANGLES;
+
+ if (part.has("type")) {
+ String type=part["type"];
+ if (type=="LINES")
+ pt=Mesh::PRIMITIVE_LINES;
+ else if (type=="POINTS")
+ pt=Mesh::PRIMITIVE_POINTS;
+ else if (type=="TRIANGLE_STRIP")
+ pt=Mesh::PRIMITIVE_TRIANGLE_STRIP;
+ else if (type=="LINE_STRIP")
+ pt=Mesh::PRIMITIVE_LINE_STRIP;
+ }
+
+ if (pt==Mesh::PRIMITIVE_TRIANGLES) {
+ DVector<int> ia=arrays[Mesh::ARRAY_INDEX];
+ int len=ia.size();
+ {
+ DVector<int>::Write w=ia.write();
+ for(int l=0;l<len;l+=3) {
+ SWAP(w[l+1],w[l+2]);
+ }
+ }
+ arrays[Mesh::ARRAY_INDEX]=ia;
+
+
+ }
+ SurfaceInfo si;
+ si.array=arrays;
+ si.primitive=pt;
+ state.surface_cache[_id(part["id"])]=si;
+
+ }
+ }
+}
+
+
+Error EditorSceneImporterFBXConv::_parse_animations(State& state) {
+
+ AnimationPlayer *ap = memnew( AnimationPlayer );
+
+ state.scene->add_child(ap);
+ ap->set_owner(state.scene);
+
+ for(int i=0;i<state.animations.size();i++) {
+
+ Dictionary anim = state.animations[i];
+ ERR_CONTINUE(!anim.has("id"));
+ Ref<Animation> an = memnew( Animation );
+ an->set_name(_id(anim["id"]));
+
+
+ if (anim.has("bones")) {
+
+ Array bone_tracks = anim["bones"];
+ for(int j=0;j<bone_tracks.size();j++) {
+ Dictionary bone_track=bone_tracks[j];
+ String bone = bone_track["boneId"];
+ if (!bone_track.has("keyframes"))
+ continue;
+ if (!state.bones.has(bone))
+ continue;
+
+ Skeleton *sk = state.bones[bone].skeleton;
+
+ if (!sk)
+ continue;
+ int bone_idx=sk->find_bone(bone);
+ if (bone_idx==-1)
+ continue;
+
+
+
+ String path = state.scene->get_path_to(sk);
+ path+=":"+bone;
+ an->add_track(Animation::TYPE_TRANSFORM);
+ int tidx = an->get_track_count()-1;
+ an->track_set_path(tidx,path);
+
+
+ Dictionary parent_xform_dict;
+ Dictionary xform_dict;
+
+ if (state.bones.has(bone)) {
+ xform_dict=state.bones[bone].node;
+ }
+
+
+ Array parent_keyframes;
+ if (sk->get_bone_parent(bone_idx)!=-1) {
+ String parent_name = sk->get_bone_name(sk->get_bone_parent(bone_idx));
+ if (state.bones.has(parent_name)) {
+ parent_xform_dict=state.bones[parent_name].node;
+ }
+
+ print_line("parent for "+bone+"? "+parent_name+" XFD: "+String(Variant(parent_xform_dict)));
+ for(int k=0;k<bone_tracks.size();k++) {
+ Dictionary d = bone_tracks[k];
+ if (d["boneId"]==parent_name) {
+ parent_keyframes=d["keyframes"];
+ print_line("found keyframes");
+ break;
+ }
+ }
+
+
+ }
+
+ print_line("BONE XFD "+String(Variant(xform_dict)));
+
+ Array keyframes=bone_track["keyframes"];
+
+ for(int k=0;k<keyframes.size();k++) {
+
+ Dictionary key=keyframes[k];
+ Transform xform=_get_transform_mixed(key,xform_dict);
+ float time = key["keytime"];
+ time=time/1000.0;
+#if 0
+ if (parent_keyframes.size()) {
+ //localize
+ print_line(itos(k)+" localizate for: "+bone);
+
+ float prev_kt=-1;
+ float kt;
+ int idx=0;
+
+ for(int l=0;l<parent_keyframes.size();l++) {
+
+ Dictionary d=parent_keyframes[l];
+ kt=d["keytime"];
+ kt=kt/1000.0;
+ if (kt>time)
+ break;
+ prev_kt=kt;
+ idx++;
+
+ }
+
+ Transform t;
+ if (idx==0) {
+ t=_get_transform_mixed(parent_keyframes[0],parent_xform_dict);
+ } else if (idx==parent_keyframes.size()){
+ t=_get_transform_mixed(parent_keyframes[idx-1],parent_xform_dict);
+ } else {
+ t=_get_transform_mixed(parent_keyframes[idx-1],parent_xform_dict);
+ float d = (time-prev_kt)/(kt-prev_kt);
+ if (d>0) {
+ Transform t2=_get_transform_mixed(parent_keyframes[idx],parent_xform_dict);
+ t=t.interpolate_with(t2,d);
+ } else {
+ print_line("exact: "+rtos(kt));
+ }
+ }
+
+ xform = t.affine_inverse() * xform; //localize
+ } else if (!parent_xform_dict.empty()) {
+ Transform t = _get_transform(parent_xform_dict);
+ xform = t.affine_inverse() * xform; //localize
+ }
+#endif
+
+ xform = sk->get_bone_rest(bone_idx).affine_inverse() * xform;
+
+
+ Quat q = xform.basis;
+ q.normalize();
+ Vector3 s = xform.basis.get_scale();
+ Vector3 l = xform.origin;
+
+
+
+ an->transform_track_insert_key(tidx,time,l,q,s);
+
+ }
+
+ }
+
+
+ }
+
+
+ ap->add_animation(_id(anim["id"]),an);
+
+ }
+
+ return OK;
+}
+
+Error EditorSceneImporterFBXConv::_parse_json(State& state, const String &p_path) {
+
+ //not the happiest....
+ Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
+ ERR_FAIL_COND_V(!data.size(),ERR_FILE_CANT_OPEN);
+ String str;
+ bool utferr = str.parse_utf8((const char*)data.ptr(),data.size());
+ ERR_FAIL_COND_V(utferr,ERR_PARSE_ERROR);
+
+ Dictionary dict;
+ Error err = dict.parse_json(str);
+ str=String(); //free mem immediately
+ ERR_FAIL_COND_V(err,err);
+
+ if (dict.has("meshes"))
+ state.meshes=dict["meshes"];
+ if (dict.has("materials"))
+ state.materials=dict["materials"];
+ if (dict.has("nodes"))
+ state.nodes=dict["nodes"];
+ if (dict.has("animations"))
+ state.animations=dict["animations"];
+
+
+ state.scene = memnew( Spatial );
+ _detect_bones(state);
+ _parse_surfaces(state);
+ _parse_materials(state);
+ err = _parse_nodes(state,state.nodes,state.scene);
+ if (err)
+ return err;
+
+ if (state.import_animations) {
+ err = _parse_animations(state);
+ if (err)
+ return err;
+ }
+
+ print_line("JSON PARSED O-K!");
+
+ return OK;
+}
+
+Error EditorSceneImporterFBXConv::_parse_fbx(State& state,const String& p_path) {
+
+ state.base_path=p_path.get_base_dir();
+
+ if (p_path.to_lower().ends_with("g3dj")) {
+ return _parse_json(state,p_path.basename()+".g3dj");
+ }
+
+ String tool = EDITOR_DEF("fbxconv/path","");
+ ERR_FAIL_COND_V( !FileAccess::exists(tool),ERR_UNCONFIGURED);
+ String wine = EDITOR_DEF("fbxconv/use_wine","");
+
+ List<String> args;
+ String path=p_path;
+ if (wine!="") {
+ List<String> wpargs;
+ wpargs.push_back("-w");
+ wpargs.push_back(p_path);
+ String pipe; //winepath to convert to windows path
+ int wpres;
+ Error wperr = OS::get_singleton()->execute(wine+"path",wpargs,true,NULL,&pipe,&wpres);
+ ERR_FAIL_COND_V(wperr!=OK,ERR_CANT_CREATE);
+ ERR_FAIL_COND_V(wpres!=0,ERR_CANT_CREATE);
+ path=pipe.strip_edges();
+ args.push_back(tool);
+ tool=wine;
+ }
+
+ args.push_back("-o");
+ args.push_back("G3DJ");
+ args.push_back(path);
+
+ int res;
+ Error err = OS::get_singleton()->execute(tool,args,true,NULL,NULL,&res);
+ ERR_FAIL_COND_V(err!=OK,ERR_CANT_CREATE);
+ ERR_FAIL_COND_V(res!=0,ERR_CANT_CREATE);
+
+ return _parse_json(state,p_path.basename()+".g3dj");
+
+
+}
+
+Node* EditorSceneImporterFBXConv::import_scene(const String& p_path,uint32_t p_flags,List<String> *r_missing_deps,Error* r_err){
+
+ State state;
+ state.scene=NULL;
+ state.missing_deps=r_missing_deps;
+ state.import_animations=p_flags&IMPORT_ANIMATION;
+ Error err = _parse_fbx(state,p_path);
+ if (err!=OK) {
+ if (r_err)
+ *r_err=err;
+ return NULL;
+ }
+
+
+ return state.scene;
+}
+Ref<Animation> EditorSceneImporterFBXConv::import_animation(const String& p_path,uint32_t p_flags){
+
+
+ return Ref<Animation>();
+}
+
+
+EditorSceneImporterFBXConv::EditorSceneImporterFBXConv() {
+
+ EDITOR_DEF("fbxconv/path","");
+#ifndef WINDOWS_ENABLED
+ EDITOR_DEF("fbxconv/use_wine","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"fbxconv/use_wine",PROPERTY_HINT_GLOBAL_FILE));
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"fbxconv/path",PROPERTY_HINT_GLOBAL_FILE));
+#else
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"fbxconv/path",PROPERTY_HINT_GLOBAL_FILE,"exe"));
+#endif
+
+}
diff --git a/tools/editor/io_plugins/editor_scene_importer_fbxconv.h b/tools/editor/io_plugins/editor_scene_importer_fbxconv.h
new file mode 100644
index 0000000000..261b072b04
--- /dev/null
+++ b/tools/editor/io_plugins/editor_scene_importer_fbxconv.h
@@ -0,0 +1,81 @@
+#ifndef EDITOR_SCENE_IMPORTER_FBXCONV_H
+#define EDITOR_SCENE_IMPORTER_FBXCONV_H
+
+#include "tools/editor/io_plugins/editor_scene_import_plugin.h"
+#include "scene/3d/skeleton.h"
+
+
+class EditorSceneImporterFBXConv : public EditorSceneImporter {
+
+ OBJ_TYPE(EditorSceneImporterFBXConv,EditorSceneImporter );
+
+
+ struct BoneInfo {
+
+ Skeleton *skeleton;
+ Transform rest;
+ int index;
+ bool has_anim_chan;
+ bool has_rest;
+ Dictionary node;
+ BoneInfo() {
+ has_rest=false;
+ skeleton=NULL;
+ index=-1;
+ has_anim_chan=false;
+ }
+ };
+
+ struct SurfaceInfo {
+ Array array;
+ Mesh::PrimitiveType primitive;
+ };
+
+ struct State {
+
+ Node *scene;
+ Array meshes;
+ Array materials;
+ Array nodes;
+ Array animations;
+ Map<String,BoneInfo > bones;
+ Map<String,Skeleton*> skeletons;
+ Map<String,Ref<Mesh> > mesh_cache;
+ Map<String,SurfaceInfo> surface_cache;
+ Map<String,Ref<Material> > material_cache;
+ Map<String,Ref<Texture> > texture_cache;
+ List<String> *missing_deps;
+ String base_path;
+ bool import_animations;
+ };
+
+ String _id(const String& p_id) const;
+
+ Transform _get_transform_mixed(const Dictionary& d, const Dictionary& dbase);
+ Transform _get_transform(const Dictionary& d);
+ Color _get_color(const Array& a);
+ void _detect_bones_in_nodes(State& state,const Array& p_nodes);
+ void _detect_bones(State& state);
+
+ Error _parse_bones(State& state,const Array &p_bones,Skeleton* p_skeleton);
+ void _parse_skeletons(const String& p_name,State& state, const Array &p_nodes, Skeleton*p_skeleton=NULL, int p_parent=-1);
+
+ void _add_surface(State& state,Ref<Mesh>& m,const Dictionary &part);
+ Error _parse_nodes(State& state,const Array &p_nodes,Node* p_base);
+ Error _parse_animations(State& state);
+ void _parse_materials(State& state);
+ void _parse_surfaces(State& state);
+ Error _parse_json(State& state,const String& p_path);
+ Error _parse_fbx(State &state, const String &p_path);
+
+public:
+
+ virtual uint32_t get_import_flags() const;
+ virtual void get_extensions(List<String> *r_extensions) const;
+ virtual Node* import_scene(const String& p_path,uint32_t p_flags,List<String> *r_missing_deps=NULL,Error* r_err=NULL);
+ virtual Ref<Animation> import_animation(const String& p_path,uint32_t p_flags);
+
+ EditorSceneImporterFBXConv();
+};
+
+#endif // EDITOR_SCENE_IMPORTER_FBXCONV_H
diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp
index c7593625ff..8d5a4f1dcf 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,9 +46,12 @@ static const char *flag_names[]={
"Filter (Magnifying)",
"Premultiply Alpha",
"Convert SRGB->Linear",
+ "Convert NormalMap to XY",
+ "Use Anisotropy",
NULL
};
+#if 0 // not used
static const char *flag_short_names[]={
"Stream",
"FixBorder",
@@ -59,8 +62,11 @@ static const char *flag_short_names[]={
"Filter",
"PMAlpha",
"ToLinear",
+ "ToRG",
+ "Anisoropic",
NULL
};
+#endif
void EditorImportTextureOptions::set_format(EditorTextureImportPlugin::ImageFormat p_format) {
@@ -138,6 +144,8 @@ void EditorImportTextureOptions::_changed() {
void EditorImportTextureOptions::_bind_methods() {
+ print_line("bind toptions");
+
ObjectTypeDB::bind_method("_changed",&EditorImportTextureOptions::_changed);
ObjectTypeDB::bind_method("_changedp",&EditorImportTextureOptions::_changedp);
@@ -147,7 +155,7 @@ void EditorImportTextureOptions::_bind_methods() {
void EditorImportTextureOptions::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
flags->connect("item_edited",this,"_changed");
format->connect("item_selected",this,"_changedp");
@@ -213,7 +221,6 @@ EditorImportTextureOptions::EditorImportTextureOptions() {
fname++;
}
-
add_margin_child("Texture Options",flags,true);
notice_for_2d = memnew( Label );
@@ -241,17 +248,20 @@ class EditorTextureImportDialog : public ConfirmationDialog {
LineEdit *import_path;
LineEdit *save_path;
- FileDialog *file_select;
- FileDialog *save_file_select;
+ EditorFileDialog *file_select;
+ EditorFileDialog *save_file_select;
EditorDirDialog *save_select;
OptionButton *texture_action;
ConfirmationDialog *error_dialog;
CheckButton *crop_source;
+ SpinBox *size;
bool atlas;
+ bool large;
EditorTextureImportPlugin *plugin;
void _choose_files(const Vector<String>& p_path);
+ void _choose_file(const String& p_path);
void _choose_save_dir(const String& p_path);
void _browse();
void _browse_target();
@@ -266,7 +276,7 @@ public:
Error import(const String& p_from, const String& p_to, const String& p_preset);
void popup_import(const String &p_from=String());
- EditorTextureImportDialog(EditorTextureImportPlugin *p_plugin=NULL,bool p_2d=false,bool p_atlas=false);
+ EditorTextureImportDialog(EditorTextureImportPlugin *p_plugin=NULL,bool p_2d=false,bool p_atlas=false,bool p_large=false);
};
@@ -295,6 +305,15 @@ void EditorTextureImportDialog::_choose_files(const Vector<String>& p_path) {
import_path->set_text(files);
}
+
+
+
+void EditorTextureImportDialog::_choose_file(const String& p_path) {
+
+
+ import_path->set_text(p_path);
+
+}
void EditorTextureImportDialog::_choose_save_dir(const String& p_path) {
save_path->set_text(p_path);
@@ -317,12 +336,23 @@ void EditorTextureImportDialog::_import() {
String dst_path=save_path->get_text();
- if (dst_path.empty()) {
+ if (save_path->get_text().strip_edges()=="") {
+ error_dialog->set_text("Target path is empty.");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
- error_dialog->set_text("Please specify a valid target import path!");
- error_dialog->popup_centered(Size2(200,100));
+ if (!save_path->get_text().begins_with("res://")) {
+ error_dialog->set_text("Target path must be full resource path.");
+ error_dialog->popup_centered_minsize();
return;
+ }
+
+ if (!atlas && !large && !DirAccess::exists(save_path->get_text())) {
+ error_dialog->set_text("Target path must exist.");
+ error_dialog->popup_centered_minsize();
+ return;
}
if (atlas) { //atlas
@@ -345,6 +375,8 @@ void EditorTextureImportDialog::_import() {
imd->set_option("flags",texture_options->get_flags());
imd->set_option("quality",texture_options->get_quality());
imd->set_option("atlas",true);
+ imd->set_option("atlas_size",int(size->get_val()));
+ imd->set_option("large",false);
imd->set_option("crop",crop_source->is_pressed());
Error err = plugin->import(dst_file,imd);
@@ -355,7 +387,38 @@ void EditorTextureImportDialog::_import() {
return;
}
+ } else if (large) { //atlas
+ if (files.size()!=1) {
+
+ error_dialog->set_text("Only one file is required for large texture");
+ error_dialog->popup_centered(Size2(200,100));
+ return;
+
+ }
+ String dst_file = dst_path;
+ //dst_file=dst_file.basename()+".tex";
+ Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
+ //imd->set_editor();
+ for(int i=0;i<files.size();i++) {
+ imd->add_source(EditorImportPlugin::validate_source_path(files[i]));
+ }
+ imd->set_option("format",texture_options->get_format());
+ imd->set_option("flags",texture_options->get_flags());
+ imd->set_option("quality",texture_options->get_quality());
+ imd->set_option("atlas",false);
+ imd->set_option("large",true);
+ imd->set_option("large_cell_size",int(size->get_val()));
+ imd->set_option("crop",crop_source->is_pressed());
+
+ Error err = plugin->import(dst_file,imd);
+ if (err) {
+
+ error_dialog->set_text("Error importing: "+dst_file.get_file());
+ error_dialog->popup_centered(Size2(200,100));
+ return;
+
+ }
} else {
@@ -370,6 +433,8 @@ void EditorTextureImportDialog::_import() {
imd->set_option("flags",texture_options->get_flags());
imd->set_option("quality",texture_options->get_quality());
imd->set_option("atlas",false);
+ imd->set_option("large",false);
+
Error err = plugin->import(dst_file,imd);
if (err) {
@@ -391,7 +456,7 @@ void EditorTextureImportDialog::_browse() {
void EditorTextureImportDialog::_browse_target() {
- if (atlas) {
+ if (atlas || large) {
save_file_select->popup_centered_ratio();
} else {
save_select->popup_centered_ratio();
@@ -407,7 +472,11 @@ void EditorTextureImportDialog::popup_import(const String& p_from) {
Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_from);
ERR_FAIL_COND(!rimd.is_valid());
- save_path->set_text(p_from.get_base_dir());
+ if (plugin->get_mode()==EditorTextureImportPlugin::MODE_ATLAS || plugin->get_mode()==EditorTextureImportPlugin::MODE_LARGE)
+ save_path->set_text(p_from);
+ else
+ save_path->set_text(p_from.get_base_dir());
+
texture_options->set_format(EditorTextureImportPlugin::ImageFormat(int(rimd->get_option("format"))));
texture_options->set_flags(rimd->get_option("flags"));
texture_options->set_quality(rimd->get_option("quality"));
@@ -425,7 +494,7 @@ void EditorTextureImportDialog::popup_import(const String& p_from) {
void EditorTextureImportDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
List<String> extensions;
@@ -453,6 +522,7 @@ void EditorTextureImportDialog::_bind_methods() {
ObjectTypeDB::bind_method("_choose_files",&EditorTextureImportDialog::_choose_files);
+ ObjectTypeDB::bind_method("_choose_file",&EditorTextureImportDialog::_choose_file);
ObjectTypeDB::bind_method("_choose_save_dir",&EditorTextureImportDialog::_choose_save_dir);
ObjectTypeDB::bind_method("_import",&EditorTextureImportDialog::_import);
ObjectTypeDB::bind_method("_browse",&EditorTextureImportDialog::_browse);
@@ -460,21 +530,25 @@ void EditorTextureImportDialog::_bind_methods() {
// ADD_SIGNAL( MethodInfo("imported",PropertyInfo(Variant::OBJECT,"scene")) );
}
-EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin* p_plugin, bool p_2d, bool p_atlas) {
+EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin* p_plugin, bool p_2d, bool p_atlas,bool p_large) {
atlas=p_atlas;
+ large=p_large;
plugin=p_plugin;
set_title("Import Textures");
- texture_options = memnew( EditorImportTextureOptions );;
- VBoxContainer *vbc = texture_options;
+
+ VBoxContainer *vbc = memnew(VBoxContainer);
add_child(vbc);
set_child_rect(vbc);
VBoxContainer *source_vb=memnew(VBoxContainer);
- vbc->add_margin_child("Source Texture(s):",source_vb);
+ if (large)
+ vbc->add_margin_child("Source Texture:",source_vb);
+ else
+ vbc->add_margin_child("Source Texture(s):",source_vb);
HBoxContainer *hbc = memnew( HBoxContainer );
source_vb->add_child(hbc);
@@ -489,6 +563,7 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
if (!p_atlas)
crop_source->hide();
+
Button * import_choose = memnew( Button );
import_choose->set_text(" .. ");
hbc->add_child(import_choose);
@@ -498,6 +573,19 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
hbc = memnew( HBoxContainer );
vbc->add_margin_child("Target Path:",hbc);
+ size = memnew( SpinBox );
+ size->set_min(128);
+ size->set_max(16384);
+
+ if (p_atlas) {
+ size->set_val(2048);
+ vbc->add_margin_child("Max Texture size:",size);
+ } else {
+ size->set_val(256);
+ vbc->add_margin_child("Cell Size:",size);
+ }
+
+
save_path = memnew( LineEdit );
save_path->set_h_size_flags(SIZE_EXPAND_FILL);
hbc->add_child(save_path);
@@ -508,32 +596,39 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
save_choose->connect("pressed", this,"_browse_target");
- file_select = memnew(FileDialog);
- file_select->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file_select = memnew(EditorFileDialog);
+ file_select->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
add_child(file_select);
- file_select->set_mode(FileDialog::MODE_OPEN_FILES);
+ if (!large)
+ file_select->set_mode(EditorFileDialog::MODE_OPEN_FILES);
+ else
+ file_select->set_mode(EditorFileDialog::MODE_OPEN_FILE);
file_select->connect("files_selected", this,"_choose_files");
+ file_select->connect("file_selected", this,"_choose_file");
- save_file_select = memnew(FileDialog);
- save_file_select->set_access(FileDialog::ACCESS_RESOURCES);
+ save_file_select = memnew(EditorFileDialog);
+ save_file_select->set_access(EditorFileDialog::ACCESS_RESOURCES);
add_child(save_file_select);
- save_file_select->set_mode(FileDialog::MODE_SAVE_FILE);
+ save_file_select->set_mode(EditorFileDialog::MODE_SAVE_FILE);
save_file_select->clear_filters();
- save_file_select->add_filter("*.tex;Base Atlas Texture");
+ if (large)
+ save_file_select->add_filter("*.ltex;Large Texture");
+ else
+ save_file_select->add_filter("*.tex;Base Atlas Texture");
save_file_select->connect("file_selected", this,"_choose_save_dir");
save_select = memnew( EditorDirDialog );
add_child(save_select);
-// save_select->set_mode(FileDialog::MODE_OPEN_DIR);
+// save_select->set_mode(EditorFileDialog::MODE_OPEN_DIR);
save_select->connect("dir_selected", this,"_choose_save_dir");
get_ok()->connect("pressed", this,"_import");
get_ok()->set_text("Import");
//move stuff up
- for(int i=0;i<4;i++)
- vbc->move_child( vbc->get_child( vbc->get_child_count() -1), 0);
+ //for(int i=0;i<4;i++)
+ // vbc->move_child( vbc->get_child( vbc->get_child_count() -1), 0);
error_dialog = memnew ( ConfirmationDialog );
add_child(error_dialog);
@@ -542,13 +637,24 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
set_hide_on_ok(false);
+ texture_options = memnew( EditorImportTextureOptions );;
+ vbc->add_child(texture_options);
+ texture_options->set_v_size_flags(SIZE_EXPAND_FILL);
+
if (atlas) {
texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA|EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS|EditorTextureImportPlugin::IMAGE_FLAG_FILTER);
texture_options->set_quality(0.7);
texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY);
- texture_options->show_2d_notice();
+ //texture_options->show_2d_notice();
set_title("Import Textures for Atlas (2D)");
+ } else if (large) {
+
+ texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA|EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS|EditorTextureImportPlugin::IMAGE_FLAG_FILTER);
+ texture_options->set_quality(0.7);
+ texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS);
+ texture_options->show_2d_notice();
+ set_title("Import Large Textures (2D)");
} else if (p_2d) {
@@ -594,12 +700,17 @@ String EditorTextureImportPlugin::get_name() const {
return "texture_atlas";
} break;
+ case MODE_LARGE: {
+
+ return "texture_large";
+ } break;
}
return "";
}
+
String EditorTextureImportPlugin::get_visible_name() const {
switch(mode) {
@@ -614,7 +725,11 @@ String EditorTextureImportPlugin::get_visible_name() const {
} break;
case MODE_ATLAS: {
- return "Atlas Texture";
+ return "2D Atlas Texture";
+ } break;
+ case MODE_LARGE: {
+
+ return "2D Large Texture";
} break;
}
@@ -712,6 +827,135 @@ Error EditorTextureImportPlugin::import(const String& p_path, const Ref<Resource
return import2(p_path,p_from,EditorExportPlatform::IMAGE_COMPRESSION_BC,false);
}
+
+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) {
+
+ Image image=texture->get_data();
+ ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA);
+
+ bool has_alpha=image.detect_alpha();
+ if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) {
+
+ image.convert(Image::FORMAT_RGB);
+
+ }
+
+ if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) {
+
+ image.fix_alpha_edges();
+ }
+
+ if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
+
+ image.premultiply_alpha();
+ }
+
+ if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
+ image.normalmap_to_xy();
+ }
+
+ //if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
+
+ // image.srgb_to_linear();
+ //}
+
+ if (shrink>1) {
+
+ int orig_w=image.get_width();
+ int orig_h=image.get_height();
+ 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));
+
+
+ } else {
+
+ texture->create_from_image(image,tex_flags);
+ }
+
+
+ if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS) {
+ texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSLESS);
+ } else {
+ texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
+ }
+
+
+
+ texture->set_lossy_storage_quality(quality);
+
+
+ } else {
+
+
+ Image image=texture->get_data();
+ ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA);
+
+
+ bool has_alpha=image.detect_alpha();
+ if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) {
+
+ image.convert(Image::FORMAT_RGB);
+
+ }
+
+ if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) {
+
+ image.fix_alpha_edges();
+ }
+
+ if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
+
+ image.premultiply_alpha();
+ }
+
+ if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
+ image.normalmap_to_xy();
+ }
+
+ //if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
+//
+ // print_line("CONVERT BECAUSE: "+itos(flags));
+ // image.srgb_to_linear();
+ //}
+
+ int orig_w=image.get_width();
+ int orig_h=image.get_height();
+
+ if (shrink>1) {
+ 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));
+ }
+
+ if (!(flags&IMAGE_FLAG_NO_MIPMAPS)) {
+ image.generate_mipmaps();
+
+ }
+
+ if (format!=IMAGE_FORMAT_UNCOMPRESSED) {
+
+ compress_image(p_compr,image,flags&IMAGE_FLAG_COMPRESS_EXTRA);
+ }
+
+
+ texture->create_from_image(image,tex_flags);
+
+
+ if (shrink>1 || (format!=IMAGE_FORMAT_UNCOMPRESSED && (image.get_width()!=orig_w || image.get_height()!=orig_h))) {
+ texture->set_size_override(Size2(orig_w,orig_h));
+ }
+
+ //uint32_t save_flags=ResourceSaver::FLAG_COMPRESS;
+ }
+
+ return OK;
+}
+
+
Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<ResourceImportMetadata>& p_from,EditorExportPlatform::ImageCompression p_compr, bool p_external){
@@ -723,8 +967,12 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
Ref<ImageTexture> texture;
Vector<Ref<AtlasTexture> > atlases;
bool atlas = from->get_option("atlas");
+ bool large = from->get_option("large");
int flags=from->get_option("flags");
+ int format=from->get_option("format");
+ float quality=from->get_option("quality");
+
uint32_t tex_flags=0;
if (flags&EditorTextureImportPlugin::IMAGE_FLAG_REPEAT)
@@ -733,22 +981,101 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
tex_flags|=Texture::FLAG_FILTER;
if (!(flags&EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS))
tex_flags|=Texture::FLAG_MIPMAPS;
+ if (flags&EditorTextureImportPlugin::IMAGE_FLAG_CONVERT_TO_LINEAR)
+ tex_flags|=Texture::FLAG_CONVERT_TO_LINEAR;
+ if (flags&EditorTextureImportPlugin::IMAGE_FLAG_USE_ANISOTROPY)
+ 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");
- if (atlas) {
+ if (large) {
+ ERR_FAIL_COND_V(from->get_source_count()!=1,ERR_INVALID_PARAMETER);
+
+ String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0));
+
+
+ int cell_size=from->get_option("large_cell_size");
+ ERR_FAIL_COND_V(cell_size<128 || cell_size>16384,ERR_CANT_OPEN);
+
+ EditorProgress pg("ltex","Import Large Texture",3);
+
+ pg.step("Load Source Image",0);
+ Image img;
+ Error err = ImageLoader::load_image(src_path,&img);
+ if (err) {
+ return err;
+ }
+
+ pg.step("Slicing",1);
+
+ Map<Vector2,Image> pieces;
+ for(int i=0;i<img.get_width();i+=cell_size) {
+ int w = MIN(img.get_width()-i,cell_size);
+ for(int j=0;j<img.get_height();j+=cell_size) {
+ int h = MIN(img.get_height()-j,cell_size);
+
+ Image piece(w,h,0,img.get_format());
+ piece.blit_rect(img,Rect2(i,j,w,h),Point2(0,0));
+ if (!piece.is_invisible()) {
+ pieces[Vector2(i,j)]=piece;
+ //print_line("ADDING PIECE AT "+Vector2(i,j));
+ }
+ }
+ }
+
+ Ref<LargeTexture> existing;
+ if (ResourceCache::has(p_path)) {
+ existing = ResourceCache::get(p_path);
+ }
+
+ if (existing.is_valid()) {
+ existing->clear();
+ } else {
+ existing = Ref<LargeTexture>(memnew( LargeTexture ));
+ }
+
+ existing->set_size(Size2(img.get_width(),img.get_height()));
+ pg.step("Inserting",2);
+
+ for (Map<Vector2,Image>::Element *E=pieces.front();E;E=E->next()) {
+
+ Ref<ImageTexture> imgtex = Ref<ImageTexture>( memnew( ImageTexture ) );
+ imgtex->create_from_image(E->get(),tex_flags);
+ _process_texture_data(imgtex,format,quality,flags,p_compr,tex_flags,shrink);
+ existing->add_piece(E->key(),imgtex);
+ }
+
+ if (!p_external) {
+ from->set_editor(get_name());
+ existing->set_path(p_path);
+ existing->set_import_metadata(from);
+ }
+ pg.step("Saving",3);
+
+ err = ResourceSaver::save(p_path,existing);
+ if (err!=OK) {
+ EditorNode::add_io_error("Couldn't save large texture: "+p_path);
+ return err;
+ }
+
+ return OK;
+
+
+ } else if (atlas) {
//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));
@@ -766,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..
@@ -813,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>() );
@@ -871,8 +1266,6 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
}
- int format=from->get_option("format");
- float quality=from->get_option("quality");
if (!p_external) {
from->set_editor(get_name());
@@ -906,7 +1299,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
}
}
+ bool compress=false;
+#if 1
+ _process_texture_data(texture,format,quality,flags,p_compr,tex_flags,shrink);
+#else
if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) {
Image image=texture->get_data();
@@ -929,11 +1326,15 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
image.premultiply_alpha();
}
- if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
-
- image.srgb_to_linear();
+ if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
+ image.normalmap_to_xy();
}
+ //if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
+
+ // image.srgb_to_linear();
+ //}
+
if (shrink>1) {
int orig_w=image.get_width();
@@ -959,13 +1360,6 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
texture->set_lossy_storage_quality(quality);
- Error err = ResourceSaver::save(p_path,texture);
-
- if (err!=OK) {
- EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
- return err;
- }
-
} else {
@@ -991,11 +1385,16 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
image.premultiply_alpha();
}
- if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
-
- image.srgb_to_linear();
+ if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
+ image.normalmap_to_xy();
}
+ //if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
+//
+ // print_line("CONVERT BECAUSE: "+itos(flags));
+ // image.srgb_to_linear();
+ //}
+
int orig_w=image.get_width();
int orig_h=image.get_height();
@@ -1019,19 +1418,24 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
texture->create_from_image(image,tex_flags);
- if (shrink>1) {
+ if (shrink>1 || (format!=IMAGE_FORMAT_UNCOMPRESSED && (image.get_width()!=orig_w || image.get_height()!=orig_h))) {
texture->set_size_override(Size2(orig_w,orig_h));
}
- uint32_t save_flags=ResourceSaver::FLAG_COMPRESS;
+ compress=true;
- Error err = ResourceSaver::save(p_path,texture,save_flags);
- if (err!=OK) {
- EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
- return err;
- }
}
+#endif
+ uint32_t save_flags=0;
+ if (compress)
+ save_flags=ResourceSaver::FLAG_COMPRESS;
+
+ Error err = ResourceSaver::save(p_path,texture,save_flags);
+ if (err!=OK) {
+ EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
+ return err;
+ }
return OK;
}
@@ -1080,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
}
@@ -1220,14 +1627,14 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c
}
-EditorTextureImportPlugin *EditorTextureImportPlugin::singleton[3]={NULL,NULL,NULL};
+EditorTextureImportPlugin *EditorTextureImportPlugin::singleton[EditorTextureImportPlugin::MODE_MAX]={NULL,NULL,NULL,NULL};
EditorTextureImportPlugin::EditorTextureImportPlugin(EditorNode *p_editor, Mode p_mode) {
singleton[p_mode]=this;
editor=p_editor;
- mode=p_mode;
- dialog = memnew( EditorTextureImportDialog(this,p_mode==MODE_TEXTURE_2D || p_mode==MODE_ATLAS,p_mode==MODE_ATLAS) );
+ mode=p_mode;
+ dialog = memnew( EditorTextureImportDialog(this,p_mode==MODE_TEXTURE_2D || p_mode==MODE_ATLAS || p_mode==MODE_LARGE,p_mode==MODE_ATLAS,p_mode==MODE_LARGE) );
editor->get_gui_base()->add_child(dialog);
}
diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.h b/tools/editor/io_plugins/editor_texture_import_plugin.h
index 9374c6eb0b..38fd671e9d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,7 +56,9 @@ public:
enum Mode {
MODE_TEXTURE_2D,
MODE_TEXTURE_3D,
- MODE_ATLAS
+ MODE_ATLAS,
+ MODE_LARGE,
+ MODE_MAX
};
@@ -65,10 +67,10 @@ private:
Mode mode;
EditorNode *editor;
EditorTextureImportDialog *dialog;
- static EditorTextureImportPlugin *singleton[3];
+ 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,float shrink);
void compress_image(EditorExportPlatform::ImageCompression p_mode,Image& image,bool p_smaller);
public:
@@ -93,9 +95,12 @@ public:
IMAGE_FLAG_REPEAT=32, //usually disabled in 2D
IMAGE_FLAG_FILTER=64, //almost always enabled
IMAGE_FLAG_PREMULT_ALPHA=128,//almost always enabled
- IMAGE_FLAG_CONVERT_TO_LINEAR=256 //convert image to linear
+ IMAGE_FLAG_CONVERT_TO_LINEAR=256, //convert image to linear
+ IMAGE_FLAG_CONVERT_NORMAL_TO_XY=512, //convert image to linear
+ IMAGE_FLAG_USE_ANISOTROPY=1024, //convert image to linear
};
+ Mode get_mode() const { return mode; }
virtual String get_name() const;
virtual String get_visible_name() const;
virtual void import_dialog(const String& p_from="");
@@ -118,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 89a7584f77..d152d71af4 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,7 +47,7 @@ class EditorTranslationImportDialog : public ConfirmationDialog {
LineEdit *import_path;
LineEdit *save_path;
- FileDialog *file_select;
+ EditorFileDialog *file_select;
CheckButton *ignore_first;
CheckButton *compress;
CheckButton *add_to_project;
@@ -273,7 +273,7 @@ public:
void _notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
}
@@ -347,16 +347,16 @@ public:
add_to_project->set_text("Add to Project (engine.cfg)");
tcomp->add_child(add_to_project);
- file_select = memnew(FileDialog);
- file_select->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file_select = memnew(EditorFileDialog);
+ file_select->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
add_child(file_select);
- file_select->set_mode(FileDialog::MODE_OPEN_FILE);
+ file_select->set_mode(EditorFileDialog::MODE_OPEN_FILE);
file_select->connect("file_selected", this,"_choose_file");
file_select->add_filter("*.csv ; Translation CSV");
save_select = memnew( EditorDirDialog );
add_child(save_select);
- // save_select->set_mode(FileDialog::MODE_OPEN_DIR);
+ // save_select->set_mode(EditorFileDialog::MODE_OPEN_DIR);
save_select->connect("dir_selected", this,"_choose_save_dir");
get_ok()->connect("pressed", this,"_import");
diff --git a/tools/editor/io_plugins/editor_translation_import_plugin.h b/tools/editor/io_plugins/editor_translation_import_plugin.h
index 8ea422c244..f3c2884534 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
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 8a28272f12..687d3675fc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/optimized_save_dialog.h b/tools/editor/optimized_save_dialog.h
index a3879b7cb4..739d0e1506 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/output_strings.cpp b/tools/editor/output_strings.cpp
index 122db3adf9..30569d11b0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -129,7 +129,7 @@ void OutputStrings::_notification(int p_what) {
} break;
- case NOTIFICATION_ENTER_SCENE:
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_RESIZED: {
diff --git a/tools/editor/output_strings.h b/tools/editor/output_strings.h
index cd9caa2b71..ad893534fa 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,64 +26,64 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef OUTPUT_STRINGS_H
-#define OUTPUT_STRINGS_H
-
-
-#include "scene/gui/control.h"
-#include "scene/gui/scroll_bar.h"
-#include "map.h"
-
-class OutputStrings : public Control {
-
- OBJ_TYPE( OutputStrings, Control );
-public:
-
- enum LineType {
-
- LINE_NORMAL,
- LINE_WARNING,
- LINE_ERROR,
- LINE_LINK
- };
-private:
-
- struct Line {
-
-
- LineType type;
- Variant meta;
- String text;
- };
-
-
- int font_height;
- int size_height;
-
- Size2 margin;
- typedef Map<int,Line> LineMap;
- Map<int,Line> line_map;
-
- VScrollBar *v_scroll;
- HScrollBar *h_scroll;
-
- bool following;
- int line_max_count;
- bool updating;
-
- void _vscroll_changed(float p_value);
- void _hscroll_changed(float p_value);
- void update_scrollbars();
-protected:
-
- static void _bind_methods();
- void _notification(int p_what);
-
-public:
-
- void add_line(const String& p_text, const Variant& p_meta=Variant(), const LineType p_type=LINE_NORMAL);
-
- OutputStrings();
-};
-
-#endif // OUTPUT_STRINGS_H
+#ifndef OUTPUT_STRINGS_H
+#define OUTPUT_STRINGS_H
+
+
+#include "scene/gui/control.h"
+#include "scene/gui/scroll_bar.h"
+#include "map.h"
+
+class OutputStrings : public Control {
+
+ OBJ_TYPE( OutputStrings, Control );
+public:
+
+ enum LineType {
+
+ LINE_NORMAL,
+ LINE_WARNING,
+ LINE_ERROR,
+ LINE_LINK
+ };
+private:
+
+ struct Line {
+
+
+ LineType type;
+ Variant meta;
+ String text;
+ };
+
+
+ int font_height;
+ int size_height;
+
+ Size2 margin;
+ typedef Map<int,Line> LineMap;
+ Map<int,Line> line_map;
+
+ VScrollBar *v_scroll;
+ HScrollBar *h_scroll;
+
+ bool following;
+ int line_max_count;
+ bool updating;
+
+ void _vscroll_changed(float p_value);
+ void _hscroll_changed(float p_value);
+ void update_scrollbars();
+protected:
+
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+
+ void add_line(const String& p_text, const Variant& p_meta=Variant(), const LineType p_type=LINE_NORMAL);
+
+ OutputStrings();
+};
+
+#endif // OUTPUT_STRINGS_H
diff --git a/tools/editor/pane_drag.cpp b/tools/editor/pane_drag.cpp
index f3a236201a..fb137de5ce 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/pane_drag.h b/tools/editor/pane_drag.h
index 268c940e35..a6cd9b6662 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,26 +26,26 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PANE_DRAG_H
-#define PANE_DRAG_H
-
-#include "scene/gui/control.h"
-
-class PaneDrag : public Control {
-
- OBJ_TYPE( PaneDrag, Control );
-
- bool mouse_over;
-
-
-protected:
-
- void _input_event(const InputEvent& p_input);
- void _notification(int p_what);
- virtual Size2 get_minimum_size() const;
- static void _bind_methods();
-public:
- PaneDrag();
-};
-
-#endif // PANE_DRAG_H
+#ifndef PANE_DRAG_H
+#define PANE_DRAG_H
+
+#include "scene/gui/control.h"
+
+class PaneDrag : public Control {
+
+ OBJ_TYPE( PaneDrag, Control );
+
+ bool mouse_over;
+
+
+protected:
+
+ void _input_event(const InputEvent& p_input);
+ void _notification(int p_what);
+ virtual Size2 get_minimum_size() const;
+ static void _bind_methods();
+public:
+ PaneDrag();
+};
+
+#endif // PANE_DRAG_H
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 17f17bba7d..d8d65b875a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,8 +26,8 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "animation_data_editor_plugin.h"
-
-AnimationDataEditorPlugin::AnimationDataEditorPlugin()
-{
-}
+#include "animation_data_editor_plugin.h"
+
+AnimationDataEditorPlugin::AnimationDataEditorPlugin()
+{
+}
diff --git a/tools/editor/plugins/animation_data_editor_plugin.h b/tools/editor/plugins/animation_data_editor_plugin.h
index 2fd3d5b32a..0daa67d0a5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,13 +26,13 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ANIMATION_DATA_EDITOR_PLUGIN_H
-#define ANIMATION_DATA_EDITOR_PLUGIN_H
-
-class AnimationDataEditorPlugin
-{
-public:
- AnimationDataEditorPlugin();
-};
-
-#endif // ANIMATION_DATA_EDITOR_PLUGIN_H
+#ifndef ANIMATION_DATA_EDITOR_PLUGIN_H
+#define ANIMATION_DATA_EDITOR_PLUGIN_H
+
+class AnimationDataEditorPlugin
+{
+public:
+ AnimationDataEditorPlugin();
+};
+
+#endif // ANIMATION_DATA_EDITOR_PLUGIN_H
diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp
index 0d709b9a72..dc2c241d2f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,8 +27,11 @@
/* 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"
void AnimationPlayerEditor::_node_removed(Node *p_node) {
@@ -76,6 +79,8 @@ void AnimationPlayerEditor::_notification(int p_what) {
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());
+ EditorNode::get_singleton()->get_property_editor()->refresh();
+
} else if (last_active) {
//need the last frame after it stopped
@@ -87,7 +92,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
updating = false;
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
editor->connect("hide_animation_player_editors",this,"_hide_anim_editors");
add_anim->set_icon( get_icon("New","EditorIcons") );
@@ -95,15 +100,23 @@ 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") );
- remove_anim->set_icon( get_icon("Del","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("Play","EditorIcons") );
+ play->set_icon( get_icon("PlayStart","EditorIcons") );
+ play_from->set_icon( get_icon("Play","EditorIcons") );
+ play_bw->set_icon( get_icon("PlayStartBackwards","EditorIcons") );
+ play_bw_from->set_icon( get_icon("PlayBackwards","EditorIcons") );
+
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") );
+ 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");
@@ -119,7 +132,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_READY) {
- get_scene()->connect("node_removed",this,"_node_removed");
+ get_tree()->connect("node_removed",this,"_node_removed");
}
if (p_what==NOTIFICATION_DRAW) {
@@ -178,9 +191,82 @@ void AnimationPlayerEditor::_play_pressed() {
//unpause
//pause->set_pressed(false);
}
+
+void AnimationPlayerEditor::_play_from_pressed() {
+
+ String current;
+ if (animation->get_selected()>=0 && animation->get_selected()<animation->get_item_count()) {
+
+ current = animation->get_item_text( animation->get_selected() );
+ }
+
+ if (current!="") {
+
+ float time = player->get_current_animation_pos();
+
+ if (current==player->get_current_animation() && player->is_playing()) {
+
+ player->stop(); //so it wont blend with itself
+ }
+
+ player->play( current );
+ player->seek(time);
+ }
+
+ //unstop
+ stop->set_pressed(false);
+ //unpause
+ //pause->set_pressed(false);
+}
+
+
+void AnimationPlayerEditor::_play_bw_pressed() {
+
+ String current;
+ if (animation->get_selected()>=0 && animation->get_selected()<animation->get_item_count()) {
+
+ current = animation->get_item_text( animation->get_selected() );
+ }
+
+ if (current!="") {
+
+ if (current==player->get_current_animation())
+ player->stop(); //so it wont blend with itself
+ player->play(current,-1,-1,true);
+ }
+
+ //unstop
+ stop->set_pressed(false);
+ //unpause
+ //pause->set_pressed(false);
+}
+
+void AnimationPlayerEditor::_play_bw_from_pressed() {
+
+ String current;
+ if (animation->get_selected()>=0 && animation->get_selected()<animation->get_item_count()) {
+
+ current = animation->get_item_text( animation->get_selected() );
+ }
+
+ if (current!="") {
+
+ float time = player->get_current_animation_pos();
+ if (current==player->get_current_animation())
+ player->stop(); //so it wont blend with itself
+
+ player->play(current,-1,-1,true);
+ player->seek(time);
+ }
+
+ //unstop
+ stop->set_pressed(false);
+ //unpause
+ //pause->set_pressed(false);
+}
void AnimationPlayerEditor::_stop_pressed() {
- player->stop();
+ player->stop(false);
play->set_pressed(false);
stop->set_pressed(true);
//pause->set_pressed(false);
@@ -273,7 +359,7 @@ void AnimationPlayerEditor::_animation_rename() {
}
void AnimationPlayerEditor::_animation_load() {
ERR_FAIL_COND(!player);
- file->set_mode( FileDialog::MODE_OPEN_FILE );
+ file->set_mode( EditorFileDialog::MODE_OPEN_FILE );
file->clear_filters();
List<String> extensions;
@@ -285,9 +371,79 @@ 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() {
if (animation->get_item_count()==0)
@@ -334,7 +490,7 @@ void AnimationPlayerEditor::_animation_name_edited() {
String new_name = name->get_text();
if (new_name=="" || new_name.find(":")!=-1 || new_name.find("/")!=-1) {
error_dialog->set_text("ERROR: Invalid animation name!");
- error_dialog->popup_centered(Size2(300,70));
+ error_dialog->popup_centered_minsize();
return;
}
@@ -345,7 +501,7 @@ void AnimationPlayerEditor::_animation_name_edited() {
if (player->has_animation(new_name)) {
error_dialog->set_text("ERROR: Animation Name Already Exists!");
- error_dialog->popup_centered(Size2(300,70));
+ error_dialog->popup_centered_minsize();
return;
}
@@ -467,6 +623,49 @@ 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();
+ d["editing"]=edit_anim->is_pressed();
+ }
+
+ 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);
+ if (p_state.has("editing") && p_state["editing"]) {
+
+ edit_anim->set_pressed(true);
+ _animation_edit();
+ }
+ }
+
+ }
+ }
+
+}
+
+
void AnimationPlayerEditor::_animation_resource_edit() {
if (animation->get_item_count()) {
@@ -510,38 +709,55 @@ void AnimationPlayerEditor::_animation_edit() {
//get_scene()->get_root_node()->call("_resource_selected",anim,"");
}
-void AnimationPlayerEditor::_file_selected(String p_file) {
+void AnimationPlayerEditor::_dialog_action(String p_file) {
- ERR_FAIL_COND(!player);
+ switch (current_option) {
+ case RESOURCE_LOAD: {
+ ERR_FAIL_COND(!player);
- 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) {
+ 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_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(".")!=-1)
- p_file=p_file.substr(0,p_file.find("."));
+ if (p_file.find(".") != -1)
+ p_file = p_file.substr(0, p_file.find("."));
- 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->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();
+ }
+ 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: {
+
+ 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>())
+
+ RES current_res = RES(anim->cast_to<Resource>());
+ _animation_save_in_path(current_res, p_file);
+ }
+ }
+ }
}
void AnimationPlayerEditor::_scale_changed(const String& p_scale) {
@@ -596,12 +812,17 @@ void AnimationPlayerEditor::_update_player() {
stop->set_disabled(animlist.size()==0);
play->set_disabled(animlist.size()==0);
+ play_bw->set_disabled(animlist.size()==0);
+ play_bw_from->set_disabled(animlist.size()==0);
+ play_from->set_disabled(animlist.size()==0);
autoplay->set_disabled(animlist.size()==0);
duplicate_anim->set_disabled(animlist.size()==0);
rename_anim->set_disabled(animlist.size()==0);
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()) {
@@ -854,6 +1075,8 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos) {
return;
seek->set_val(p_pos);
+ EditorNode::get_singleton()->get_property_editor()->refresh();
+
//seekit
@@ -873,11 +1096,125 @@ void AnimationPlayerEditor::_hide_anim_editors() {
}
}
+
+void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
+
+ switch(p_option) {
+
+ case TOOL_COPY_ANIM: {
+
+ if (!animation->get_item_count()) {
+ error_dialog->set_text("ERROR: No animation to copy!");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
+ //editor->edit_resource(anim);
+ EditorSettings::get_singleton()->set_resource_clipboard(anim);
+
+ } break;
+ case TOOL_PASTE_ANIM: {
+
+ Ref<Animation> anim = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (!anim.is_valid()) {
+ error_dialog->set_text("ERROR: No animation resource on clipboard!");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ String name = anim->get_name();
+ if (name=="") {
+ name="Pasted Animation";
+ }
+
+ int idx=1;
+ String base = name;
+ while (player->has_animation(name)) {
+
+ idx++;
+ name=base+" "+itos(idx);
+ }
+
+ undo_redo->create_action("Paste Animation");
+ undo_redo->add_do_method(player,"add_animation",name,anim);
+ undo_redo->add_undo_method(player,"remove_animation",name);
+ undo_redo->add_do_method(this,"_animation_player_changed",player);
+ undo_redo->add_undo_method(this,"_animation_player_changed",player);
+ undo_redo->commit_action();
+
+ _select_anim_by_name(name);
+
+
+ } break;
+ case TOOL_EDIT_RESOURCE: {
+
+ if (!animation->get_item_count()) {
+ error_dialog->set_text("ERROR: No animation to edit!");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
+ editor->edit_resource(anim);
+
+ } break;
+
+ }
+}
+
+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) {
+
+ switch(p_ev.key.scancode) {
+
+ case KEY_A: {
+ if (!p_ev.key.mod.shift)
+ _play_bw_from_pressed();
+ else
+ _play_bw_pressed();
+ } break;
+ case KEY_S: {
+ _stop_pressed();
+ } break;
+ case KEY_D: {
+ if (!p_ev.key.mod.shift)
+ _play_from_pressed();
+ else
+ _play_pressed();
+ } break;
+ }
+ }
+}
+
void AnimationPlayerEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_input_event"),&AnimationPlayerEditor::_input_event);
ObjectTypeDB::bind_method(_MD("_node_removed"),&AnimationPlayerEditor::_node_removed);
ObjectTypeDB::bind_method(_MD("_play_pressed"),&AnimationPlayerEditor::_play_pressed);
+ ObjectTypeDB::bind_method(_MD("_play_from_pressed"),&AnimationPlayerEditor::_play_from_pressed);
+ ObjectTypeDB::bind_method(_MD("_play_bw_pressed"),&AnimationPlayerEditor::_play_bw_pressed);
+ ObjectTypeDB::bind_method(_MD("_play_bw_from_pressed"),&AnimationPlayerEditor::_play_bw_from_pressed);
ObjectTypeDB::bind_method(_MD("_stop_pressed"),&AnimationPlayerEditor::_stop_pressed);
ObjectTypeDB::bind_method(_MD("_autoplay_pressed"),&AnimationPlayerEditor::_autoplay_pressed);
ObjectTypeDB::bind_method(_MD("_pause_pressed"),&AnimationPlayerEditor::_pause_pressed);
@@ -890,7 +1227,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);
@@ -904,14 +1241,24 @@ void AnimationPlayerEditor::_bind_methods() {
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;
@@ -931,47 +1278,67 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
add_child(hb);
- add_anim = memnew( Button );
+ add_anim = memnew( ToolButton );
add_anim->set_tooltip("Create new animation in player.");
hb->add_child(add_anim);
-
- load_anim = memnew( Button );
+ load_anim = memnew( ToolButton );
load_anim->set_tooltip("Load an animation from disk.");
hb->add_child(load_anim);
- duplicate_anim = memnew( Button );
+ 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");
+ rename_anim = memnew( ToolButton );
+ hb->add_child(rename_anim);
+ rename_anim->set_tooltip("Rename Animation");
+
+ remove_anim = memnew( ToolButton );
+
+ hb->add_child(remove_anim);
+ remove_anim->set_tooltip("Remove Animation");
+
+
animation = memnew( OptionButton );
hb->add_child(animation);
animation->set_h_size_flags(SIZE_EXPAND_FILL);
animation->set_tooltip("Display list of animations in player.");
- autoplay = memnew( Button );
+ autoplay = memnew( ToolButton );
hb->add_child(autoplay);
autoplay->set_tooltip("Autoplay On Load");
- rename_anim = memnew( Button );
- hb->add_child(rename_anim);
- rename_anim->set_tooltip("Rename Animation");
- remove_anim = memnew( Button );
-
- hb->add_child(remove_anim);
- remove_anim->set_tooltip("Remove Animation");
-
- blend_anim = memnew( Button );
+ blend_anim = memnew( ToolButton );
hb->add_child(blend_anim);
blend_anim->set_tooltip("Edit Target Blend Times");
+ tool_anim = memnew( MenuButton);
+ //tool_anim->set_flat(false);
+ tool_anim->set_tooltip("Animation Tools");
+ tool_anim->get_popup()->add_item("Copy Animation",TOOL_COPY_ANIM);
+ tool_anim->get_popup()->add_item("Paste Animation",TOOL_PASTE_ANIM);
+ //tool_anim->get_popup()->add_separator();
+ //tool_anim->get_popup()->add_item("Edit Anim Resource",TOOL_PASTE_ANIM);
+ hb->add_child(tool_anim);
- edit_anim = memnew( Button );
+ 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.");
@@ -980,15 +1347,29 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
hb = memnew (HBoxContainer);
add_child(hb);
- play = memnew( Button );
- play->set_tooltip("Play selected animation.");
+ play_bw_from = memnew( ToolButton );
+ play_bw_from->set_tooltip("Play backwards selected animation from current pos. (A)");
+ hb->add_child(play_bw_from);
- hb->add_child(play);
+ play_bw = memnew( ToolButton );
+ play_bw->set_tooltip("Play backwards selected animation from end. (Shift+A)");
+ hb->add_child(play_bw);
- stop = memnew( Button );
+ stop = memnew( ToolButton );
stop->set_toggle_mode(true);
hb->add_child(stop);
- play->set_tooltip("Stop animation playback.");
+ 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);
@@ -1020,12 +1401,14 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
resource_edit_anim= memnew( Button );
hb->add_child(resource_edit_anim);
+ resource_edit_anim->hide();
- file = memnew(FileDialog);
+ file = memnew(EditorFileDialog);
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 );
@@ -1070,7 +1453,10 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
autoplay->connect("pressed", this,"_autoplay_pressed");
autoplay->set_toggle_mode(true);
- play->connect("pressed", this,"_play_pressed");
+ play->connect("pressed", this,"_play_pressed");
+ play_from->connect("pressed", this,"_play_from_pressed");
+ play_bw->connect("pressed", this,"_play_bw_pressed");
+ play_bw_from->connect("pressed", this,"_play_bw_from_pressed");
stop->connect("pressed", this,"_stop_pressed");
//pause->connect("pressed", this,"_pause_pressed");
add_anim->connect("pressed", this,"_animation_new");
@@ -1083,7 +1469,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
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");
+ file->connect("file_selected", this,"_dialog_action");
seek->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");
@@ -1100,6 +1486,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
renaming=false;
last_active=false;
+
+ set_process_unhandled_key_input(true);
}
@@ -1135,6 +1523,7 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin(EditorNode *p_node) {
editor=p_node;
anim_editor = memnew( AnimationPlayerEditor(editor) );
+ anim_editor->set_undo_redo(editor->get_undo_redo());
editor->get_animation_panel()->add_child(anim_editor);
/*
editor->get_viewport()->add_child(anim_editor);
diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h
index 2c6bcae97e..839df3ddcc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,10 +49,30 @@ class AnimationPlayerEditor : public VBoxContainer {
EditorNode *editor;
AnimationPlayer *player;
+ enum {
+ TOOL_COPY_ANIM,
+ TOOL_PASTE_ANIM,
+ TOOL_EDIT_RESOURCE
+ };
+
+ enum {
+ ANIM_SAVE,
+ ANIM_SAVE_AS
+ };
+
+ enum {
+ RESOURCE_LOAD,
+ RESOURCE_SAVE
+ };
+
OptionButton *animation;
Button *stop;
Button *play;
+ Button *play_from;
+ Button *play_bw;
+ Button *play_bw_from;
+
// Button *pause;
Button *add_anim;
Button *autoplay;
@@ -61,8 +81,10 @@ class AnimationPlayerEditor : public VBoxContainer {
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;
SpinBox *frame;
@@ -74,7 +96,9 @@ class AnimationPlayerEditor : public VBoxContainer {
Ref<Texture> autoplay_icon;
bool last_active;
- FileDialog *file;
+ EditorFileDialog *file;
+ AcceptDialog *accept;
+ int current_option;
struct BlendEditor {
@@ -95,6 +119,9 @@ class AnimationPlayerEditor : public VBoxContainer {
void _select_anim_by_name(const String& p_anim);
void _play_pressed();
+ void _play_from_pressed();
+ void _play_bw_pressed();
+ void _play_bw_from_pressed();
void _autoplay_pressed();
void _stop_pressed();
void _pause_pressed();
@@ -103,13 +130,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);
@@ -126,6 +158,10 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_key_editor_seek(float p_pos);
void _animation_key_editor_anim_len_changed(float p_new);
+ void _unhandled_key_input(const InputEvent& p_ev);
+ void _animation_tool_menu(int p_option);
+ void _animation_save_menu(int p_option);
+
AnimationPlayerEditor();
protected:
@@ -136,6 +172,13 @@ protected:
static void _bind_methods();
public:
+ AnimationPlayer *get_player() const;
+ static AnimationPlayerEditor *singleton;
+
+ 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; }
@@ -152,6 +195,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 aeef593093..382bc44726 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -221,8 +221,8 @@ void AnimationTreeEditor::_edit_dialog_animation_changed() {
void AnimationTreeEditor::_edit_dialog_edit_animation() {
- if (get_scene()->is_editor_hint()) {
- get_scene()->get_root()->get_child(0)->call("_resource_selected", property_editor->get_variant().operator RefPtr());
+ if (get_tree()->is_editor_hint()) {
+ get_tree()->get_root()->get_child(0)->call("_resource_selected", property_editor->get_variant().operator RefPtr());
};
};
@@ -936,7 +936,7 @@ void AnimationTreeEditor::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
play_button->set_icon( get_icon("Play","EditorIcons") );
add_menu->set_icon( get_icon("Add","EditorIcons") );
@@ -1193,7 +1193,7 @@ void AnimationTreeEditor::_add_menu_item(int p_item) {
} else if (p_item == MENU_IMPORT_ANIMATIONS) {
file_op = MENU_IMPORT_ANIMATIONS;
- file_dialog->set_mode(FileDialog::MODE_OPEN_FILE);
+ file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
file_dialog->popup_centered_ratio();
} else {
@@ -1458,7 +1458,7 @@ AnimationTreeEditor::AnimationTreeEditor() {
edit_check->hide();;
edit_check->connect("pressed", this,"_edit_dialog_changed");
- file_dialog = memnew( FileDialog );
+ file_dialog = memnew( EditorFileDialog );
file_dialog->set_enable_multiple_selection(true);
file_dialog->set_current_dir(Globals::get_singleton()->get_resource_path());
add_child(file_dialog);
diff --git a/tools/editor/plugins/animation_tree_editor_plugin.h b/tools/editor/plugins/animation_tree_editor_plugin.h
index 21b31863b6..bd29530c7a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -79,7 +79,7 @@ class AnimationTreeEditor : public Control {
Button *edit_button;
Button *filter_button;
CheckButton *edit_check;
- FileDialog* file_dialog;
+ EditorFileDialog* file_dialog;
int file_op;
void _popup_edit_dialog();
diff --git a/tools/editor/plugins/baked_light_baker.cpp b/tools/editor/plugins/baked_light_baker.cpp
index 1fa4d8d06c..4599dbfb54 100644
--- a/tools/editor/plugins/baked_light_baker.cpp
+++ b/tools/editor/plugins/baked_light_baker.cpp
@@ -4,6 +4,53 @@
#include <cmath>
#include "io/marshalls.h"
#include "tools/editor/editor_node.h"
+#include "tools/editor/editor_settings.h"
+
+
+void baked_light_baker_add_64f(double *dst,double value);
+void baked_light_baker_add_64i(int64_t *dst,int64_t value);
+
+//-separar en 2 testuras?
+//*mejorar performance y threads
+//*modos lineales
+//*saturacion
+
+_FORCE_INLINE_ static uint64_t get_uv_normal_bit(const Vector3& p_vector) {
+
+ int lat = Math::fast_ftoi(Math::floor(Math::acos(p_vector.dot(Vector3(0,1,0)))*6.0/Math_PI+0.5));
+
+ if (lat==0) {
+ return 60;
+ } else if (lat==6) {
+ return 61;
+ }
+
+ int lon = Math::fast_ftoi(Math::floor( (Math_PI+Math::atan2(p_vector.x,p_vector.z))*12.0/(Math_PI*2.0) + 0.5))%12;
+
+ return lon+(lat-1)*12;
+}
+
+
+
+_FORCE_INLINE_ static Vector3 get_bit_normal(int p_bit) {
+
+ if (p_bit==61) {
+ return Vector3(0,1,0);
+ } else if (p_bit==62){
+ return Vector3(0,-1,0);
+ }
+
+ float latang = ((p_bit / 12)+1)*Math_PI/6.0;
+
+ Vector2 latv(Math::sin(latang),Math::cos(latang));
+
+ float lonang = ((p_bit%12)*Math_PI*2.0/12.0)-Math_PI;
+
+ Vector2 lonv(Math::sin(lonang),Math::cos(lonang));
+
+ return Vector3(lonv.x*latv.x,latv.y,lonv.y*latv.x).normalized();
+
+}
BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref<Texture>& p_tex) {
@@ -28,6 +75,12 @@ BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref<Texture>&
image.convert(Image::FORMAT_RGBA);
}
+ if (imgtex->get_flags()&Texture::FLAG_CONVERT_TO_LINEAR) {
+ Image copy = image;
+ copy.srgb_to_linear();
+ image=copy;
+ }
+
DVector<uint8_t> dvt=image.get_data();
DVector<uint8_t>::Read r=dvt.read();
MeshTexture mt;
@@ -45,7 +98,7 @@ BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref<Texture>&
}
-void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform) {
+void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform,int p_baked_texture) {
for(int i=0;i<p_mesh->get_surface_count();i++) {
@@ -55,6 +108,7 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
Ref<Material> mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i);
MeshMaterial *matptr=NULL;
+ int baked_tex=p_baked_texture;
if (mat.is_valid()) {
@@ -66,8 +120,13 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
if (fm.is_valid()) {
//fixed route
mm.diffuse.color=fm->get_parameter(FixedMaterial::PARAM_DIFFUSE);
+ if (linear_color)
+ mm.diffuse.color=mm.diffuse.color.to_linear();
mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_DIFFUSE));
mm.specular.color=fm->get_parameter(FixedMaterial::PARAM_SPECULAR);
+ if (linear_color)
+ mm.specular.color=mm.specular.color.to_linear();
+
mm.specular.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_SPECULAR));
} else {
@@ -112,6 +171,8 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
DVector<Vector3>::Read vr=vertices.read();
DVector<Vector2> uv;
DVector<Vector2>::Read uvr;
+ DVector<Vector2> uv2;
+ DVector<Vector2>::Read uv2r;
DVector<Vector3> normal;
DVector<Vector3>::Read normalr;
bool read_uv=false;
@@ -122,6 +183,18 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
uv=a[Mesh::ARRAY_TEX_UV];
uvr=uv.read();
read_uv=true;
+
+ if (mat.is_valid() && mat->get_flag(Material::FLAG_LIGHTMAP_ON_UV2) && p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV2) {
+
+ uv2=a[Mesh::ARRAY_TEX_UV2];
+ uv2r=uv2.read();
+
+ } else {
+ uv2r=uv.read();
+ if (baked_light->get_transfer_lightmaps_only_to_uv2()) {
+ baked_tex=-1;
+ }
+ }
}
if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_NORMAL) {
@@ -145,11 +218,16 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
t.vertices[1]=p_xform.xform(vr[ ir[i*3+1] ]);
t.vertices[2]=p_xform.xform(vr[ ir[i*3+2] ]);
t.material=matptr;
+ t.baked_texture=baked_tex;
if (read_uv) {
t.uvs[0]=uvr[ ir[i*3+0] ];
t.uvs[1]=uvr[ ir[i*3+1] ];
t.uvs[2]=uvr[ ir[i*3+2] ];
+
+ t.bake_uvs[0]=uv2r[ ir[i*3+0] ];
+ t.bake_uvs[1]=uv2r[ ir[i*3+1] ];
+ t.bake_uvs[2]=uv2r[ ir[i*3+2] ];
}
if (read_normal) {
@@ -167,11 +245,17 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
t.vertices[1]=p_xform.xform(vr[ i*3+1 ]);
t.vertices[2]=p_xform.xform(vr[ i*3+2 ]);
t.material=matptr;
+ t.baked_texture=baked_tex;
if (read_uv) {
t.uvs[0]=uvr[ i*3+0 ];
t.uvs[1]=uvr[ i*3+1 ];
t.uvs[2]=uvr[ i*3+2 ];
+
+ t.bake_uvs[0]=uv2r[ i*3+0 ];
+ t.bake_uvs[1]=uv2r[ i*3+1 ];
+ t.bake_uvs[2]=uv2r[ i*3+2 ];
+
}
if (read_normal) {
@@ -193,7 +277,7 @@ void BakedLightBaker::_parse_geometry(Node* p_node) {
MeshInstance *meshi=p_node->cast_to<MeshInstance>();
Ref<Mesh> mesh=meshi->get_mesh();
if (mesh.is_valid()) {
- _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform());
+ _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform(),meshi->get_baked_light_texture_id());
}
} else if (p_node->cast_to<Light>()) {
@@ -206,6 +290,11 @@ void BakedLightBaker::_parse_geometry(Node* p_node) {
dirl.type=VS::LightType(dl->get_light_type());
dirl.diffuse=dl->get_color(DirectionalLight::COLOR_DIFFUSE);
dirl.specular=dl->get_color(DirectionalLight::COLOR_SPECULAR);
+ if (linear_color)
+ dirl.diffuse=dirl.diffuse.to_linear();
+ if (linear_color)
+ dirl.specular=dirl.specular.to_linear();
+
dirl.energy=dl->get_parameter(DirectionalLight::PARAM_ENERGY);
dirl.pos=dl->get_global_transform().origin;
dirl.up=dl->get_global_transform().basis.get_axis(1).normalized();
@@ -214,9 +303,11 @@ void BakedLightBaker::_parse_geometry(Node* p_node) {
dirl.spot_angle=dl->get_parameter(DirectionalLight::PARAM_SPOT_ANGLE);
dirl.spot_attenuation=dl->get_parameter(DirectionalLight::PARAM_SPOT_ATTENUATION);
dirl.attenuation=dl->get_parameter(DirectionalLight::PARAM_ATTENUATION);
+ dirl.darkening=dl->get_parameter(DirectionalLight::PARAM_SHADOW_DARKENING);
dirl.radius=dl->get_parameter(DirectionalLight::PARAM_RADIUS);
dirl.bake_direct=dl->get_bake_mode()==Light::BAKE_MODE_FULL;
dirl.rays_thrown=0;
+ dirl.bake_shadow=dl->get_bake_mode()==Light::BAKE_MODE_INDIRECT_AND_SHADOWS;
lights.push_back(dirl);
}
@@ -310,7 +401,7 @@ void BakedLightBaker::_fix_lights() {
}
if (dl.type==VS::LIGHT_OMNI) {
- dl.area=4.0*Math_PI*pow(dl.radius,2.0);
+ dl.area=4.0*Math_PI*pow(dl.radius,2.0f);
dl.constant=1.0/3.5;
} else {
@@ -406,8 +497,11 @@ void BakedLightBaker::_make_bvh() {
}
bvh=_parse_bvh(bases.ptr(),bases.size(),1,max_depth);
+
ray_stack = memnew_arr(uint32_t,max_depth);
bvh_stack = memnew_arr(BVH*,max_depth);
+
+ bvh_depth = max_depth;
}
void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_depth) {
@@ -497,6 +591,12 @@ void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_de
child->aabb.pos.z+=child->aabb.size.z;
+ child->full_accum[0]=0;
+ child->full_accum[1]=0;
+ child->full_accum[2]=0;
+ child->sampler_ofs=0;
+
+
if (stack_pos==octree_depth-1) {
child->leaf=true;
@@ -505,10 +605,12 @@ void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_de
child->offset[2]=child->aabb.pos.z+child->aabb.size.z*0.5;
child->next_leaf=leaf_list;
+
for(int ci=0;ci<8;ci++) {
child->normal_accum[ci][0]=0;
child->normal_accum[ci][1]=0;
child->normal_accum[ci][2]=0;
+
}
child->bake_neighbour=0;
@@ -517,14 +619,10 @@ void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_de
cell_count++;
int lz = lights.size();
- child->light = memnew_arr(OctantLight,lz);
-
- for(int li=0;li<lz;li++) {
- for(int ci=0;ci<8;ci++) {
- child->light[li].accum[ci][0]=0;
- child->light[li].accum[ci][1]=0;
- child->light[li].accum[ci][2]=0;
- }
+ for(int ci=0;ci<8;ci++) {
+ child->light_accum[ci][0]=0;
+ child->light_accum[ci][1]=0;
+ child->light_accum[ci][2]=0;
}
child->parent=ptr_stack[stack_pos];
@@ -565,11 +663,26 @@ void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_de
pos.y=floor((pos.y+cell_size*0.5)/cell_size);
pos.z=floor((pos.z+cell_size*0.5)/cell_size);
- Map<Vector3,Vector3>::Element *E=endpoint_normal.find(pos);
- if (!E) {
- endpoint_normal[pos]=n;
- } else {
- E->get()+=n;
+ {
+ Map<Vector3,Vector3>::Element *E=endpoint_normal.find(pos);
+ if (!E) {
+ endpoint_normal[pos]=n;
+ } else {
+ E->get()+=n;
+ }
+ }
+
+ {
+
+ uint64_t bit = get_uv_normal_bit(n);
+
+ Map<Vector3,uint64_t>::Element *E=endpoint_normal_bits.find(pos);
+ if (!E) {
+ endpoint_normal_bits[pos]=(1<<bit);
+ } else {
+ E->get()|=(1<<bit);
+ }
+
}
}
@@ -649,18 +762,58 @@ void BakedLightBaker::_make_octree() {
pos.y=floor((pos.y+cell_size*0.5)/cell_size);
pos.z=floor((pos.z+cell_size*0.5)/cell_size);
- Map<Vector3,Vector3>::Element *E=endpoint_normal.find(pos);
- if (!E) {
- //?
- print_line("lolwut?");
- } else {
- Vector3 n = E->get().normalized();
- oct->normal_accum[ci][0]=n.x;
- oct->normal_accum[ci][1]=n.y;
- oct->normal_accum[ci][2]=n.z;
+ {
+ Map<Vector3,Vector3>::Element *E=endpoint_normal.find(pos);
+ if (!E) {
+ //?
+ print_line("lolwut?");
+ } else {
+ Vector3 n = E->get().normalized();
+ oct->normal_accum[ci][0]=n.x;
+ oct->normal_accum[ci][1]=n.y;
+ oct->normal_accum[ci][2]=n.z;
+
+ }
}
+ {
+
+ Map<Vector3,uint64_t>::Element *E=endpoint_normal_bits.find(pos);
+ if (!E) {
+ //?
+ print_line("lolwut?");
+ } else {
+
+ float max_aper=0;
+ for(uint64_t i=0;i<62;i++) {
+
+ if (!(E->get()&(1<<i)))
+ continue;
+ Vector3 ang_i = get_bit_normal(i);
+
+ for(uint64_t j=0;j<62;j++) {
+
+ if (i==j)
+ continue;
+ if (!(E->get()&(1<<j)))
+ continue;
+ Vector3 ang_j = get_bit_normal(j);
+ float ang = Math::acos(ang_i.dot(ang_j));
+ if (ang>max_aper)
+ max_aper=ang;
+ }
+ }
+ if (max_aper>0.75*Math_PI) {
+ //angle too wide prevent problems and forget
+ oct->normal_accum[ci][0]=0;
+ oct->normal_accum[ci][1]=0;
+ oct->normal_accum[ci][2]=0;
+ }
+ }
+ }
+
+
}
oct_idx=oct->next_leaf;
@@ -674,12 +827,12 @@ void BakedLightBaker::_make_octree() {
-void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos, const AABB& p_plot_aabb, const Color& p_light, const Plane& p_plane) {
+void BakedLightBaker::_plot_light(ThreadStack& thread_stack,const Vector3& p_plot_pos, const AABB& p_plot_aabb, const Color& p_light,const Color& p_tint_light,bool p_only_full, const Plane& p_plane) {
//stackless version
- uint32_t *stack=octant_stack;
- uint32_t *ptr_stack=octantptr_stack;
+ uint32_t *stack=thread_stack.octant_stack;
+ uint32_t *ptr_stack=thread_stack.octantptr_stack;
Octant *octants=octant_pool.ptr();
stack[0]=0;
@@ -692,6 +845,29 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos,
Octant &octant=octants[ptr_stack[stack_pos]];
+ if (stack[stack_pos]==0) {
+
+
+ Vector3 pos = octant.aabb.pos + octant.aabb.size*0.5;
+ float md = 1<<(octree_depth - stack_pos );
+ float r=cell_size*plot_size*md;
+ float div = 1.0/(md*md*md);
+ //div=1.0;
+
+
+ float d = p_plot_pos.distance_to(pos);
+
+ if ((p_plane.distance_to(pos)>-cell_size*1.75*md) && d<=r) {
+
+
+ float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
+
+ baked_light_baker_add_64f(&octant.full_accum[0],p_tint_light.r*intensity*div);
+ baked_light_baker_add_64f(&octant.full_accum[1],p_tint_light.g*intensity*div);
+ baked_light_baker_add_64f(&octant.full_accum[2],p_tint_light.b*intensity*div);
+ }
+ }
+
if (octant.leaf) {
@@ -699,31 +875,44 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos,
//if (p_plane.normal.dot(octant.aabb.get_support(p_plane.normal)) < p_plane.d-CMP_EPSILON) { //octants behind are no go
+ if (!p_only_full) {
+ float r=cell_size*plot_size;
+ for(int i=0;i<8;i++) {
+ Vector3 pos=octant.aabb.pos;
+ if (i&1)
+ pos.x+=octant.aabb.size.x;
+ if (i&2)
+ pos.y+=octant.aabb.size.y;
+ if (i&4)
+ pos.z+=octant.aabb.size.z;
+
- float r=cell_size*plot_size;
- for(int i=0;i<8;i++) {
- Vector3 pos=octant.aabb.pos;
- if (i&1)
- pos.x+=octant.aabb.size.x;
- if (i&2)
- pos.y+=octant.aabb.size.y;
- if (i&4)
- pos.z+=octant.aabb.size.z;
+ float d = p_plot_pos.distance_to(pos);
+ if ((p_plane.distance_to(pos)>-cell_size*1.75) && d<=r) {
- float d = p_plot_pos.distance_to(pos);
- if (d<=r) {
+ float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
+ if (edge_damp>0) {
+ Vector3 normal = Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2]);
+ if (normal.x>0 || normal.y>0 || normal.z>0) {
+
+ float damp = Math::abs(p_plane.normal.dot(normal));
+ intensity*=pow(damp,edge_damp);
+
+ }
+ }
+
+ //intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size);
+ //intensity = Math::cos(d*Math_PI*0.5/r);
+ baked_light_baker_add_64f(&octant.light_accum[i][0],p_light.r*intensity);
+ baked_light_baker_add_64f(&octant.light_accum[i][1],p_light.g*intensity);
+ baked_light_baker_add_64f(&octant.light_accum[i][2],p_light.b*intensity);
- float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
- float damp = Math::abs(p_plane.normal.dot(Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2])));
- intensity*=pow(damp,edge_damp);
- //intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size);
- octant.light[p_light_index].accum[i][0]+=p_light.r*intensity;
- octant.light[p_light_index].accum[i][1]+=p_light.g*intensity;
- octant.light[p_light_index].accum[i][2]+=p_light.b*intensity;
+
+ }
}
}
@@ -760,11 +949,11 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos,
}
-float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce) {
+float BakedLightBaker::_throw_ray(ThreadStack& thread_stack,bool p_bake_direct,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce,bool p_only_dist) {
- uint32_t* stack = ray_stack;
- BVH **bstack = bvh_stack;
+ uint32_t* stack = thread_stack.ray_stack;
+ BVH **bstack = thread_stack.bvh_stack;
enum {
TEST_AABB_BIT=0,
@@ -782,6 +971,7 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
n/=len;
+
real_t d=1e10;
bool inters=false;
Vector3 r_normal;
@@ -890,8 +1080,13 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
}
+
if (inters) {
+ if (p_only_dist) {
+
+ return p_begin.distance_to(r_point);
+ }
//should check if there is normals first
@@ -905,6 +1100,9 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
}
if (n.dot(r_normal)>0)
+ return -1;
+
+ if (n.dot(r_normal)>0)
r_normal=-r_normal;
@@ -941,6 +1139,20 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
//the multiplication can happen with more detail in the shader
+
+ if (triangle->material) {
+
+ //triangle->get_uv(r_point);
+
+ diffuse_at_point=triangle->material->diffuse.get_color(uv);
+ specular_at_point=triangle->material->specular.get_color(uv);
+ }
+
+
+ diffuse_at_point.r=res_light.r*diffuse_at_point.r;
+ diffuse_at_point.g=res_light.g*diffuse_at_point.g;
+ diffuse_at_point.b=res_light.b*diffuse_at_point.b;
+
float ret=1e6;
if (p_bounces>0) {
@@ -957,18 +1169,6 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
- if (triangle->material) {
-
- //triangle->get_uv(r_point);
-
- diffuse_at_point=triangle->material->diffuse.get_color(uv);
- specular_at_point=triangle->material->specular.get_color(uv);
- }
-
-
- diffuse_at_point.r=res_light.r*diffuse_at_point.r;
- diffuse_at_point.g=res_light.g*diffuse_at_point.g;
- diffuse_at_point.b=res_light.b*diffuse_at_point.b;
specular_at_point.r=res_light.r*specular_at_point.r;
specular_at_point.g=res_light.g*specular_at_point.g;
@@ -996,7 +1196,7 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
#endif
- ret=_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
+ ret=_throw_ray(thread_stack,p_bake_direct,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
}
if (use_specular && (specular_at_point.r>CMP_EPSILON || specular_at_point.g>CMP_EPSILON || specular_at_point.b>CMP_EPSILON)) {
@@ -1007,7 +1207,7 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
Vector3 rn = n - r_normal *r_normal.dot(n) * 2.0;
- _throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,specular_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
+ _throw_ray(thread_stack,p_bake_direct,r_point,r_point+rn*p_rest,p_rest,specular_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
}
}
@@ -1015,34 +1215,58 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
// _plot_light_point(r_point,octree,octree_aabb,p_light);
- Color plot_light=res_light;
+ Color plot_light=res_light.linear_interpolate(diffuse_at_point,tint);
plot_light.r*=att;
plot_light.g*=att;
plot_light.b*=att;
+ Color tint_light=diffuse_at_point;
+ tint_light.r*=att;
+ tint_light.g*=att;
+ tint_light.b*=att;
+
+ bool skip=false;
- if (!p_first_bounce) {
+ if (!p_first_bounce || p_bake_direct) {
- float r = plot_size * cell_size;
- if (ret<r) {
+ float r = plot_size * cell_size*2;
+ if (dist<r) {
//avoid accumulaiton of light on corners
//plot_light=plot_light.linear_interpolate(Color(0,0,0,0),1.0-sd/plot_size*plot_size);
- plot_light=Color(0,0,0,0);
+ skip=true;
+
+ } else {
+
+
+ Vector3 c1=r_normal.cross(n).normalized();
+ Vector3 c2=r_normal.cross(c1).normalized();
+ double r1 = double(rand())/RAND_MAX;
+ double r2 = double(rand())/RAND_MAX;
+ double r3 = double(rand())/RAND_MAX;
+ Vector3 rn = ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*r3*0.25)).normalized();
+ float d =_throw_ray(thread_stack,p_bake_direct,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1,false,true);
+ r = plot_size*cell_size*ao_radius;
+ if (d>0 && d<r) {
+ //avoid accumulaiton of light on corners
+ //plot_light=plot_light.linear_interpolate(Color(0,0,0,0),1.0-sd/plot_size*plot_size);
+ skip=true;
+
+ } else {
+ //plot_light=Color(0,0,0,0);
+ }
}
}
- if (!p_first_bounce || lights[p_light_index].bake_direct) {
- Plane plane(r_point,r_normal);
- //print_line(String(plot_light)+String(" ")+rtos(att));
- _plot_light(p_light_index,r_point,aabb,plot_light,plane);
- }
+ Plane plane(r_point,r_normal);
+ if (!skip)
+ _plot_light(thread_stack,r_point,aabb,plot_light,tint_light,!(!p_first_bounce || p_bake_direct),plane);
return dist;
}
- return 0;
+ return -1;
}
@@ -1142,79 +1366,100 @@ void BakedLightBaker::_make_octree_texture() {
//ok let's try to just create a texture
- {
+ int otex_w=256;
- int otex_w=(1<<lattice_size)*(1<<lattice_size)*2; //make sure lattice fits horizontally
- Vector3 lattice_cell_size=octree_aabb.size;
- for(int i=0;i<lattice_size;i++) {
+ while (true) {
- lattice_cell_size*=0.5;
- }
+ uint32_t oct_idx=leaf_list;
- while(true) {
+ int row=0;
- //let's plot the leafs first, given the octree is not so obvious which size it will have
- int row=4+4*(1<<lattice_size);
+ print_line("begin at row "+itos(row));
+ int longest_line_reused=0;
+ int col=0;
+ int processed=0;
+
+ //reset
+ while(oct_idx) {
+
+ BakedLightBaker::Octant *oct = &octants[oct_idx];
+ oct->texture_x=0;
+ oct->texture_y=0;
+ oct_idx=oct->next_leaf;
+
+ }
- uint32_t oct_idx=leaf_list;
+ oct_idx=leaf_list;
+ //assign
+ while(oct_idx) {
- //untag
- while(oct_idx) {
+ BakedLightBaker::Octant *oct = &octants[oct_idx];
+ if (oct->first_neighbour && oct->texture_x==0 && oct->texture_y==0) {
+ //was not processed
+ uint32_t current_idx=oct_idx;
+ int reused=0;
+
+ while(current_idx) {
+ BakedLightBaker::Octant *o = &octants[current_idx];
+ if (col+1 >= otex_w) {
+ col=0;
+ row+=4;
+ }
+ o->texture_x=col;
+ o->texture_y=row;
+ processed++;
- BakedLightBaker::Octant *oct = &octants[oct_idx];
- //0,0 also means unprocessed
- oct->texture_x=0;
- oct->texture_y=0;
- oct_idx=oct->next_leaf;
+ if (o->bake_neighbour) {
+ reused++;
+ }
+ col+=o->bake_neighbour ? 1 : 2; //reuse neighbour
+ current_idx=o->bake_neighbour;
+ }
+ if (reused>longest_line_reused) {
+ longest_line_reused=reused;
+ }
}
+ oct_idx=oct->next_leaf;
+ }
- oct_idx=leaf_list;
+ row+=4;
+ if (otex_w < row) {
- print_line("begin at row "+itos(row));
- int longest_line_reused=0;
- int col=0;
- int processed=0;
+ otex_w*=2;
+ } else {
- while(oct_idx) {
+ baked_light_texture_w=otex_w;
+ baked_light_texture_h=nearest_power_of_2(row);
+ print_line("w: "+itos(otex_w));
+ print_line("h: "+itos(row));
+ break;
+ }
- BakedLightBaker::Octant *oct = &octants[oct_idx];
- if (oct->first_neighbour && oct->texture_x==0 && oct->texture_y==0) {
- //was not processed
- uint32_t current_idx=oct_idx;
- int reused=0;
- while(current_idx) {
- BakedLightBaker::Octant *o = &octants[current_idx];
- if (col+1 >= otex_w) {
- col=0;
- row+=4;
- }
- o->texture_x=col;
- o->texture_y=row;
- processed++;
+ }
- if (o->bake_neighbour) {
- reused++;
- }
- col+=o->bake_neighbour ? 1 : 2; //reuse neighbour
- current_idx=o->bake_neighbour;
- }
- if (reused>longest_line_reused) {
- longest_line_reused=reused;
- }
- }
- oct_idx=oct->next_leaf;
- }
+ {
+
+ otex_w=(1<<lattice_size)*(1<<lattice_size)*2; //make sure lattice fits horizontally
+ Vector3 lattice_cell_size=octree_aabb.size;
+ for(int i=0;i<lattice_size;i++) {
+
+ lattice_cell_size*=0.5;
+ }
- print_line("processed "+itos(processed));
- print_line("longest reused: "+itos(longest_line_reused));
+
+ while(true) {
+
+ //let's plot the leafs first, given the octree is not so obvious which size it will have
+ int row=4+4*(1<<lattice_size);
+ int col=0;
col=0;
row+=4;
@@ -1310,12 +1555,30 @@ double BakedLightBaker::get_normalization(int p_light_idx) const {
nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel
nrg*=dl.constant;
//nrg*=5;
- print_line("CS: "+rtos(cell_size));
+
return nrg;
}
-void BakedLightBaker::throw_rays(int p_amount) {
+
+
+double BakedLightBaker::get_modifier(int p_light_idx) const {
+
+ double nrg=0;
+
+ const LightData &dl=lights[p_light_idx];
+ double cell_area = cell_size*cell_size;;
+ //nrg+= /*dl.energy */ (dl.rays_thrown * cell_area / dl.area);
+ nrg=cell_area;
+ nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel
+ nrg*=dl.constant;
+ //nrg*=5;
+
+
+ return nrg;
+}
+
+void BakedLightBaker::throw_rays(ThreadStack& thread_stack,int p_amount) {
@@ -1325,6 +1588,8 @@ void BakedLightBaker::throw_rays(int p_amount) {
int amount = p_amount * total_light_area / dl.area;
+ double mod = 1.0/double(get_modifier(i));
+ mod*=p_amount/float(amount);
switch(dl.type) {
@@ -1339,12 +1604,15 @@ void BakedLightBaker::throw_rays(int p_amount) {
from+=dl.left*(r2*2.0-1.0);
Vector3 to = from+dl.dir*dl.length;
Color col=dl.diffuse;
- col.r*=dl.energy;
- col.g*=dl.energy;
- col.b*=dl.energy;
+ float m = mod*dl.energy;
+ col.r*=m;
+ col.g*=m;
+ col.b*=m;
+
dl.rays_thrown++;
- total_rays++;
- _throw_ray(i,from,to,dl.length,col,NULL,0,0,max_bounces,true);
+ baked_light_baker_add_64i(&total_rays,1);
+
+ _throw_ray(thread_stack,dl.bake_direct,from,to,dl.length,col,NULL,0,0,max_bounces,true);
}
} break;
case VS::LIGHT_OMNI: {
@@ -1380,13 +1648,14 @@ void BakedLightBaker::throw_rays(int p_amount) {
#endif
Vector3 to = dl.pos+dir*dl.radius;
Color col=dl.diffuse;
- col.r*=dl.energy;
- col.g*=dl.energy;
- col.b*=dl.energy;
+ float m = mod*dl.energy;
+ col.r*=m;
+ col.g*=m;
+ col.b*=m;
dl.rays_thrown++;
- total_rays++;
- _throw_ray(i,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
+ baked_light_baker_add_64i(&total_rays,1);
+ _throw_ray(thread_stack,dl.bake_direct,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
// _throw_ray(i,from,to,dl.radius,col,NULL,0,dl.radius,max_bounces,true);
}
@@ -1411,13 +1680,14 @@ void BakedLightBaker::throw_rays(int p_amount) {
Vector3 to = dl.pos+dir*dl.radius;
Color col=dl.diffuse;
- col.r*=dl.energy;
- col.g*=dl.energy;
- col.b*=dl.energy;
+ float m = mod*dl.energy;
+ col.r*=m;
+ col.g*=m;
+ col.b*=m;
dl.rays_thrown++;
- total_rays++;
- _throw_ray(i,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
+ baked_light_baker_add_64i(&total_rays,1);
+ _throw_ray(thread_stack,dl.bake_direct,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
// _throw_ray(i,from,to,dl.radius,col,NULL,0,dl.radius,max_bounces,true);
}
@@ -1459,7 +1729,18 @@ void BakedLightBaker::bake(const Ref<BakedLight> &p_light, Node* p_node) {
edge_damp=baked_light->get_edge_damp();
normal_damp=baked_light->get_normal_damp();
octree_extra_margin=baked_light->get_cell_extra_margin();
-
+ tint=baked_light->get_tint();
+ ao_radius=baked_light->get_ao_radius();
+ ao_strength=baked_light->get_ao_strength();
+ linear_color=baked_light->get_bake_flag(BakedLight::BAKE_LINEAR_COLOR);
+
+ baked_textures.clear();
+ for(int i=0;i<baked_light->get_lightmaps_count();i++) {
+ BakeTexture bt;
+ bt.width=baked_light->get_lightmap_gen_size(i).x;
+ bt.height=baked_light->get_lightmap_gen_size(i).y;
+ baked_textures.push_back(bt);
+ }
ep.step("Parsing Geometry",0);
@@ -1481,13 +1762,134 @@ void BakedLightBaker::bake(const Ref<BakedLight> &p_light, Node* p_node) {
}
-void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
+void BakedLightBaker::update_octree_sampler(DVector<int> &p_sampler) {
+
+ BakedLightBaker::Octant *octants=octant_pool.ptr();
+ double norm = 1.0/double(total_rays);
+
+
+
+ if (p_sampler.size()==0 || first_bake_to_map) {
+
+ Vector<int> tmp_smp;
+ tmp_smp.resize(32); //32 for header
+
+ for(int i=0;i<32;i++) {
+ tmp_smp[i]=0;
+ }
+
+ for(int i=octant_pool_size-1;i>=0;i--) {
+
+ if (i==0)
+ tmp_smp[1]=tmp_smp.size();
+
+ Octant &octant=octants[i];
+ octant.sampler_ofs = tmp_smp.size();
+ int idxcol[2]={0,0};
+
+ int r = CLAMP((octant.full_accum[0]*norm)*2048,0,32767);
+ int g = CLAMP((octant.full_accum[1]*norm)*2048,0,32767);
+ int b = CLAMP((octant.full_accum[2]*norm)*2048,0,32767);
+
+ idxcol[0]|=r;
+ idxcol[1]|=(g<<16)|b;
+
+ if (octant.leaf) {
+ tmp_smp.push_back(idxcol[0]);
+ tmp_smp.push_back(idxcol[1]);
+ } else {
+
+ for(int j=0;j<8;j++) {
+ if (octant.children[j]) {
+ idxcol[0]|=(1<<(j+16));
+ }
+ }
+ tmp_smp.push_back(idxcol[0]);
+ tmp_smp.push_back(idxcol[1]);
+ for(int j=0;j<8;j++) {
+ if (octant.children[j]) {
+ tmp_smp.push_back(octants[octant.children[j]].sampler_ofs);
+ if (octants[octant.children[j]].sampler_ofs==0) {
+ print_line("FUUUUUUUUCK");
+ }
+ }
+ }
+ }
+
+ }
+
+ p_sampler.resize(tmp_smp.size());
+ DVector<int>::Write w = p_sampler.write();
+ int ss = tmp_smp.size();
+ for(int i=0;i<ss;i++) {
+ w[i]=tmp_smp[i];
+ }
+
+ first_bake_to_map=false;
+
+ }
+
+ double gamma = baked_light->get_gamma_adjust();
+ double mult = baked_light->get_energy_multiplier();
+ float saturation = baked_light->get_saturation();
+
+ DVector<int>::Write w = p_sampler.write();
+
+ encode_uint32(octree_depth,(uint8_t*)&w[2]);
+ encode_uint32(linear_color,(uint8_t*)&w[3]);
+
+ encode_float(octree_aabb.pos.x,(uint8_t*)&w[4]);
+ encode_float(octree_aabb.pos.y,(uint8_t*)&w[5]);
+ encode_float(octree_aabb.pos.z,(uint8_t*)&w[6]);
+ encode_float(octree_aabb.size.x,(uint8_t*)&w[7]);
+ encode_float(octree_aabb.size.y,(uint8_t*)&w[8]);
+ encode_float(octree_aabb.size.z,(uint8_t*)&w[9]);
+
+ //norm*=multiplier;
+
+ for(int i=octant_pool_size-1;i>=0;i--) {
+
+ Octant &octant=octants[i];
+ int idxcol[2]={w[octant.sampler_ofs],w[octant.sampler_ofs+1]};
+
+ double rf=pow(octant.full_accum[0]*norm*mult,gamma);
+ double gf=pow(octant.full_accum[1]*norm*mult,gamma);
+ double bf=pow(octant.full_accum[2]*norm*mult,gamma);
+
+ double gray = (rf+gf+bf)/3.0;
+ rf = gray + (rf-gray)*saturation;
+ gf = gray + (gf-gray)*saturation;
+ bf = gray + (bf-gray)*saturation;
+
+
+ int r = CLAMP((rf)*2048,0,32767);
+ int g = CLAMP((gf)*2048,0,32767);
+ int b = CLAMP((bf)*2048,0,32767);
+
+ idxcol[0]=((idxcol[0]>>16)<<16)|r;
+ idxcol[1]=(g<<16)|b;
+ w[octant.sampler_ofs]=idxcol[0];
+ w[octant.sampler_ofs+1]=idxcol[1];
+ }
+
+}
+
+void BakedLightBaker::update_octree_images(DVector<uint8_t> &p_octree,DVector<uint8_t> &p_light) {
int len = baked_octree_texture_w*baked_octree_texture_h*4;
- p_image.resize(len);
- DVector<uint8_t>::Write w = p_image.write();
+ p_octree.resize(len);
+
+ int ilen = baked_light_texture_w*baked_light_texture_h*4;
+ p_light.resize(ilen);
+
+
+ DVector<uint8_t>::Write w = p_octree.write();
zeromem(w.ptr(),len);
+
+ DVector<uint8_t>::Write iw = p_light.write();
+ zeromem(iw.ptr(),ilen);
+
float gamma = baked_light->get_gamma_adjust();
float mult = baked_light->get_energy_multiplier();
@@ -1498,6 +1900,13 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
w[i+3]=0xFF;
}
+ for(int i=0;i<ilen;i+=4) {
+ iw[i+0]=0xFF;
+ iw[i+1]=0;
+ iw[i+2]=0xFF;
+ iw[i+3]=0xFF;
+ }
+
float multiplier=1.0;
if (baked_light->get_format()==BakedLight::FORMAT_HDR8)
@@ -1508,6 +1917,9 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
encode_float(1<<lattice_size,&w[12]);
encode_uint32(octree_depth-lattice_size,&w[16]);
encode_uint32(multiplier,&w[20]);
+ encode_uint16(baked_light_texture_w,&w[24]); //if present, use the baked light texture
+ encode_uint16(baked_light_texture_h,&w[26]);
+ encode_uint32(0,&w[28]); //baked light texture format
encode_float(octree_aabb.pos.x,&w[32]);
encode_float(octree_aabb.pos.y,&w[36]);
@@ -1520,6 +1932,7 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
BakedLightBaker::Octant *octants=octant_pool.ptr();
int octant_count=octant_pool_size;
uint8_t *ptr = w.ptr();
+ uint8_t *lptr = iw.ptr();
int child_offsets[8]={
@@ -1533,7 +1946,18 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
baked_octree_texture_w*8+baked_octree_texture_w*4+4,
};
- Vector<double> norm_arr;
+ int lchild_offsets[8]={
+ 0,
+ 4,
+ baked_light_texture_w*4,
+ baked_light_texture_w*4+4,
+ baked_light_texture_w*8+0,
+ baked_light_texture_w*8+4,
+ baked_light_texture_w*8+baked_light_texture_w*4,
+ baked_light_texture_w*8+baked_light_texture_w*4+4,
+ };
+
+ /*Vector<double> norm_arr;
norm_arr.resize(lights.size());
for(int i=0;i<lights.size();i++) {
@@ -1541,39 +1965,43 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
}
const double *normptr=norm_arr.ptr();
-
+*/
+ double norm = 1.0/double(total_rays);
int lz=lights.size();
mult/=multiplier;
+ double saturation = baked_light->get_saturation();
for(int i=0;i<octant_count;i++) {
Octant &oct=octants[i];
if (oct.texture_x==0 && oct.texture_y==0)
continue;
- int ofs = (oct.texture_y * baked_octree_texture_w + oct.texture_x)<<2;
+
if (oct.leaf) {
+ int ofs = (oct.texture_y * baked_light_texture_w + oct.texture_x)<<2;
+ ERR_CONTINUE(ofs<0 || ofs >ilen);
//write colors
for(int j=0;j<8;j++) {
//if (!oct.children[j])
// continue;
- uint8_t *iptr=&ptr[ofs+child_offsets[j]];
- float r=0;
- float g=0;
- float b=0;
-
- for(int k=0;k<lz;k++) {
- r+=oct.light[k].accum[j][0]*normptr[k];
- g+=oct.light[k].accum[j][1]*normptr[k];
- b+=oct.light[k].accum[j][2]*normptr[k];
- }
+ uint8_t *iptr=&lptr[ofs+lchild_offsets[j]];
+
+ float r=oct.light_accum[j][0]*norm;
+ float g=oct.light_accum[j][1]*norm;
+ float b=oct.light_accum[j][2]*norm;
r=pow(r*mult,gamma);
g=pow(g*mult,gamma);
b=pow(b*mult,gamma);
+ double gray = (r+g+b)/3.0;
+ r = gray + (r-gray)*saturation;
+ g = gray + (g-gray)*saturation;
+ b = gray + (b-gray)*saturation;
+
float ic[3]={
r,
g,
@@ -1587,6 +2015,8 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
} else {
+ int ofs = (oct.texture_y * baked_octree_texture_w + oct.texture_x)<<2;
+ ERR_CONTINUE(ofs<0 || ofs >len);
//write indices
for(int j=0;j<8;j++) {
@@ -1652,42 +2082,531 @@ void BakedLightBaker::_bake_thread_func(void *arg) {
BakedLightBaker *ble = (BakedLightBaker*)arg;
- ble->rays_at_snap_time=ble->total_rays;
- ble->snap_time=OS::get_singleton()->get_ticks_usec();
- while(!ble->bake_thread_exit) {
- ble->throw_rays(1000);
- uint64_t t=OS::get_singleton()->get_ticks_usec();
- if (t-ble->snap_time>1000000) {
+ ThreadStack thread_stack;
- double time = (t-ble->snap_time)/1000000.0;
+ thread_stack.ray_stack = memnew_arr(uint32_t,ble->bvh_depth);
+ thread_stack.bvh_stack = memnew_arr(BVH*,ble->bvh_depth);
+ thread_stack.octant_stack = memnew_arr(uint32_t,ble->octree_depth*2 );
+ thread_stack.octantptr_stack = memnew_arr(uint32_t,ble->octree_depth*2 );
- int rays=ble->total_rays-ble->rays_at_snap_time;
- ble->rays_sec=int(rays/time);
- ble->snap_time=OS::get_singleton()->get_ticks_usec();
- ble->rays_at_snap_time=ble->total_rays;
- }
+ while(!ble->bake_thread_exit) {
+
+ ble->throw_rays(thread_stack,1000);
}
+ memdelete_arr(thread_stack.ray_stack );
+ memdelete_arr(thread_stack.bvh_stack );
+ memdelete_arr(thread_stack.octant_stack );
+ memdelete_arr(thread_stack.octantptr_stack );
+
}
void BakedLightBaker::_start_thread() {
- if (thread!=NULL)
+ if (threads.size()!=0)
return;
bake_thread_exit=false;
- thread=Thread::create(_bake_thread_func,this);
+ int thread_count = EDITOR_DEF("light_baker/custom_bake_threads",0);
+ if (thread_count<=0 || thread_count>64)
+ thread_count=OS::get_singleton()->get_processor_count();
+
+ //thread_count=1;
+ threads.resize(thread_count);
+ for(int i=0;i<threads.size();i++) {
+ threads[i]=Thread::create(_bake_thread_func,this);
+ }
}
void BakedLightBaker::_stop_thread() {
- if (thread==NULL)
+ if (threads.size()==0)
return;
bake_thread_exit=true;
- Thread::wait_to_finish(thread);
- thread=NULL;
+ for(int i=0;i<threads.size();i++) {
+ Thread::wait_to_finish(threads[i]);
+ memdelete(threads[i]);
+ }
+ threads.clear();
+}
+
+void BakedLightBaker::_plot_pixel_to_lightmap(int x, int y, int width, int height, uint8_t *image, const Vector3& p_pos,const Vector3& p_normal,double *p_norm_ptr,float mult,float gamma) {
+
+
+ uint8_t *ptr = &image[(y*width+x)*4];
+ //int lc = lights.size();
+ double norm = 1.0/double(total_rays);
+
+
+ Color color;
+
+ Octant *octants=octant_pool.ptr();
+
+
+ int octant_idx=0;
+
+
+ while(true) {
+
+ Octant &octant=octants[octant_idx];
+
+ if (octant.leaf) {
+
+ Vector3 lpos = p_pos-octant.aabb.pos;
+ lpos/=octant.aabb.size;
+
+ Vector3 cols[8];
+
+ for(int i=0;i<8;i++) {
+
+ cols[i].x+=octant.light_accum[i][0]*norm;
+ cols[i].y+=octant.light_accum[i][1]*norm;
+ cols[i].z+=octant.light_accum[i][2]*norm;
+ }
+
+
+ /*Vector3 final = (cols[0] + (cols[1] - cols[0]) * lpos.y);
+ final = final + ((cols[2] + (cols[3] - cols[2]) * lpos.y) - final)*lpos.x;
+
+ Vector3 final2 = (cols[4+0] + (cols[4+1] - cols[4+0]) * lpos.y);
+ final2 = final2 + ((cols[4+2] + (cols[4+3] - cols[4+2]) * lpos.y) - final2)*lpos.x;*/
+
+ Vector3 finala = cols[0].linear_interpolate(cols[1],lpos.x);
+ Vector3 finalb = cols[2].linear_interpolate(cols[3],lpos.x);
+ Vector3 final = finala.linear_interpolate(finalb,lpos.y);
+
+ Vector3 final2a = cols[4+0].linear_interpolate(cols[4+1],lpos.x);
+ Vector3 final2b = cols[4+2].linear_interpolate(cols[4+3],lpos.x);
+ Vector3 final2 = final2a.linear_interpolate(final2b,lpos.y);
+
+ final = final.linear_interpolate(final2,lpos.z);
+ if (baked_light->get_format()==BakedLight::FORMAT_HDR8)
+ final*=8.0;
+
+
+ color.r=pow(final.x*mult,gamma);
+ color.g=pow(final.y*mult,gamma);
+ color.b=pow(final.z*mult,gamma);
+ color.a=1.0;
+
+ int lc = lights.size();
+ LightData *lv = lights.ptr();
+ for(int i=0;i<lc;i++) {
+ //shadow baking
+ if (!lv[i].bake_shadow)
+ continue;
+ Vector3 from = p_pos+p_normal*0.01;
+ Vector3 to;
+ float att=0;
+ switch(lv[i].type) {
+ case VS::LIGHT_DIRECTIONAL: {
+ to=from-lv[i].dir*lv[i].length;
+ } break;
+ case VS::LIGHT_OMNI: {
+ to=lv[i].pos;
+ float d = MIN(lv[i].radius,to.distance_to(from))/lv[i].radius;
+ att=d;//1.0-d;
+ } break;
+ default: continue;
+ }
+
+ uint32_t* stack = ray_stack;
+ BVH **bstack = bvh_stack;
+
+ enum {
+ TEST_RAY_BIT=0,
+ VISIT_LEFT_BIT=1,
+ VISIT_RIGHT_BIT=2,
+ VISIT_DONE_BIT=3,
+
+
+ };
+
+ bool intersected=false;
+
+ int level=0;
+
+ Vector3 n = (to-from);
+ float len=n.length();
+ if (len==0)
+ continue;
+ n/=len;
+
+ const BVH *bvhptr = bvh;
+
+ bstack[0]=bvh;
+ stack[0]=TEST_RAY_BIT;
+
+
+ while(!intersected) {
+
+ uint32_t mode = stack[level];
+ const BVH &b = *bstack[level];
+ bool done=false;
+
+ switch(mode) {
+ case TEST_RAY_BIT: {
+
+ if (b.leaf) {
+
+
+ Face3 f3(b.leaf->vertices[0],b.leaf->vertices[1],b.leaf->vertices[2]);
+
+
+ Vector3 res;
+
+ if (f3.intersects_segment(from,to)) {
+ intersected=true;
+ done=true;
+ }
+
+ stack[level]=VISIT_DONE_BIT;
+ } else {
+
+
+ bool valid = b.aabb.smits_intersect_ray(from,n,0,len);
+ //bool valid = b.aabb.intersects_segment(p_begin,p_end);
+ // bool valid = b.aabb.intersects(ray_aabb);
+
+ if (!valid) {
+
+ stack[level]=VISIT_DONE_BIT;
+
+ } else {
+
+ stack[level]=VISIT_LEFT_BIT;
+ }
+ }
+
+ } continue;
+ case VISIT_LEFT_BIT: {
+
+ stack[level]=VISIT_RIGHT_BIT;
+ bstack[level+1]=b.children[0];
+ stack[level+1]=TEST_RAY_BIT;
+ level++;
+
+ } continue;
+ case VISIT_RIGHT_BIT: {
+
+ stack[level]=VISIT_DONE_BIT;
+ bstack[level+1]=b.children[1];
+ stack[level+1]=TEST_RAY_BIT;
+ level++;
+ } continue;
+ case VISIT_DONE_BIT: {
+
+ if (level==0) {
+ done=true;
+ break;
+ } else
+ level--;
+
+ } continue;
+ }
+
+
+ if (done)
+ break;
+ }
+
+
+
+ if (intersected) {
+
+ color.a=Math::lerp(MAX(0.01,lv[i].darkening),1.0,att);
+ }
+
+ }
+
+ break;
+ } else {
+
+ Vector3 lpos = p_pos - octant.aabb.pos;
+ Vector3 half = octant.aabb.size * 0.5;
+
+ int ofs=0;
+
+ if (lpos.x >= half.x)
+ ofs|=1;
+ if (lpos.y >= half.y)
+ ofs|=2;
+ if (lpos.z >= half.z)
+ ofs|=4;
+
+ octant_idx = octant.children[ofs];
+
+ if (octant_idx==0)
+ return;
+
+ }
+ }
+
+ ptr[0]=CLAMP(color.r*255.0,0,255);
+ ptr[1]=CLAMP(color.g*255.0,0,255);
+ ptr[2]=CLAMP(color.b*255.0,0,255);
+ ptr[3]=CLAMP(color.a*255.0,0,255);
+
+}
+
+
+Error BakedLightBaker::transfer_to_lightmaps() {
+
+ if (!triangles.size() || baked_textures.size()==0)
+ return ERR_UNCONFIGURED;
+
+ EditorProgress ep("transfer_to_lightmaps","Transfer to Lightmaps:",baked_textures.size()*2+triangles.size());
+
+ for(int i=0;i<baked_textures.size();i++) {
+
+ ERR_FAIL_COND_V( baked_textures[i].width<=0 || baked_textures[i].height<=0,ERR_UNCONFIGURED );
+
+ baked_textures[i].data.resize( baked_textures[i].width*baked_textures[i].height*4 );
+ zeromem(baked_textures[i].data.ptr(),baked_textures[i].data.size());
+ ep.step("Allocating Texture #"+itos(i+1),i);
+ }
+
+ Vector<double> norm_arr;
+ norm_arr.resize(lights.size());
+
+ for(int i=0;i<lights.size();i++) {
+ norm_arr[i] = 1.0/get_normalization(i);
+ }
+ float gamma = baked_light->get_gamma_adjust();
+ float mult = baked_light->get_energy_multiplier();
+
+
+ const double *normptr=norm_arr.ptr();
+ for(int i=0;i<triangles.size();i++) {
+
+ if (i%200==0) {
+ ep.step("Baking Triangle #"+itos(i),i+baked_textures.size());
+ }
+ Triangle &t=triangles[i];
+ if (t.baked_texture<0 || t.baked_texture>=baked_textures.size())
+ continue;
+
+ BakeTexture &bt=baked_textures[t.baked_texture];
+ Vector3 normal = Plane(t.vertices[0],t.vertices[1],t.vertices[2]).normal;
+
+
+ int x[3];
+ int y[3];
+
+ Vector3 vertices[3]={
+ t.vertices[0],
+ t.vertices[1],
+ t.vertices[2]
+ };
+
+ for(int j=0;j<3;j++) {
+
+ x[j]=t.bake_uvs[j].x*bt.width;
+ y[j]=t.bake_uvs[j].y*bt.height;
+ x[j]=CLAMP(x[j],0,bt.width-1);
+ y[j]=CLAMP(y[j],0,bt.height-1);
+ }
+
+
+ {
+
+ // sort the points vertically
+ if (y[1] > y[2]) {
+ SWAP(x[1], x[2]);
+ SWAP(y[1], y[2]);
+ SWAP(vertices[1],vertices[2]);
+ }
+ if (y[0] > y[1]) {
+ SWAP(x[0], x[1]);
+ SWAP(y[0], y[1]);
+ SWAP(vertices[0],vertices[1]);
+ }
+ if (y[1] > y[2]) {
+ SWAP(x[1], x[2]);
+ SWAP(y[1], y[2]);
+ SWAP(vertices[1],vertices[2]);
+ }
+
+ double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1);
+ double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1);
+ double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1);
+ double xf = x[0];
+ double xt = x[0] + dx_upper; // if y[0] == y[1], special case
+ for (int yi = y[0]; yi <= (y[2] > bt.height-1 ? bt.height-1 : y[2]); yi++)
+ {
+ if (yi >= 0) {
+ for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < bt.width ? xt : bt.width-1) ; xi++) {
+ //pixels[int(x + y * width)] = color;
+
+ Vector2 v0 = Vector2(x[1]-x[0],y[1]-y[0]);
+ Vector2 v1 = Vector2(x[2]-x[0],y[2]-y[0]);
+ //vertices[2] - vertices[0];
+ Vector2 v2 = Vector2(xi-x[0],yi-y[0]);
+ float d00 = v0.dot( v0);
+ float d01 = v0.dot( v1);
+ float d11 = v1.dot( v1);
+ float d20 = v2.dot( v0);
+ float d21 = v2.dot( v1);
+ float denom = (d00 * d11 - d01 * d01);
+ Vector3 pos;
+ if (denom==0) {
+ pos=t.vertices[0];
+ } else {
+ float v = (d11 * d20 - d01 * d21) / denom;
+ float w = (d00 * d21 - d01 * d20) / denom;
+ float u = 1.0f - v - w;
+ pos = vertices[0]*u + vertices[1]*v + vertices[2]*w;
+ }
+ _plot_pixel_to_lightmap(xi,yi,bt.width,bt.height,bt.data.ptr(),pos,normal,norm_arr.ptr(),mult,gamma);
+
+ }
+
+ for (int xi = (xf < bt.width ? int(xf) : bt.width-1); xi >= (xt > 0 ? xt : 0); xi--) {
+ //pixels[int(x + y * width)] = color;
+ Vector2 v0 = Vector2(x[1]-x[0],y[1]-y[0]);
+ Vector2 v1 = Vector2(x[2]-x[0],y[2]-y[0]);
+ //vertices[2] - vertices[0];
+ Vector2 v2 = Vector2(xi-x[0],yi-y[0]);
+ float d00 = v0.dot( v0);
+ float d01 = v0.dot( v1);
+ float d11 = v1.dot( v1);
+ float d20 = v2.dot( v0);
+ float d21 = v2.dot( v1);
+ float denom = (d00 * d11 - d01 * d01);
+ Vector3 pos;
+ if (denom==0) {
+ pos=t.vertices[0];
+ } else {
+ float v = (d11 * d20 - d01 * d21) / denom;
+ float w = (d00 * d21 - d01 * d20) / denom;
+ float u = 1.0f - v - w;
+ pos = vertices[0]*u + vertices[1]*v + vertices[2]*w;
+ }
+
+ _plot_pixel_to_lightmap(xi,yi,bt.width,bt.height,bt.data.ptr(),pos,normal,norm_arr.ptr(),mult,gamma);
+
+ }
+ }
+ xf += dx_far;
+ if (yi < y[1])
+ xt += dx_upper;
+ else
+ xt += dx_low;
+ }
+ }
+
+ }
+
+
+ for(int i=0;i<baked_textures.size();i++) {
+
+
+ {
+
+ ep.step("Post-Processing Texture #"+itos(i),i+baked_textures.size()+triangles.size());
+
+ BakeTexture &bt=baked_textures[i];
+
+ Vector<uint8_t> copy_data=bt.data;
+ uint8_t *data=bt.data.ptr();
+ uint8_t *src_data=copy_data.ptr();
+ const int max_radius=8;
+ const int shadow_radius=2;
+ const int max_dist=0x7FFFFFFF;
+
+ for(int x=0;x<bt.width;x++) {
+
+ for(int y=0;y<bt.height;y++) {
+
+
+ uint8_t a = copy_data[(y*bt.width+x)*4+3];
+
+ if (a>0) {
+ //blur shadow
+
+ int from_x = MAX(0,x-shadow_radius);
+ int to_x = MIN(bt.width-1,x+shadow_radius);
+ int from_y = MAX(0,y-shadow_radius);
+ int to_y = MIN(bt.height-1,y+shadow_radius);
+
+ int sum=0;
+ int sumc=0;
+
+ for(int k=from_y;k<=to_y;k++) {
+ for(int l=from_x;l<=to_x;l++) {
+
+ const uint8_t * rp = &copy_data[(k*bt.width+l)<<2];
+
+ sum+=rp[3];
+ sumc++;
+ }
+ }
+
+ sum/=sumc;
+ data[(y*bt.width+x)*4+3]=sum;
+
+ } else {
+
+ int closest_dist=max_dist;
+ uint8_t closest_color[4];
+
+ int from_x = MAX(0,x-max_radius);
+ int to_x = MIN(bt.width-1,x+max_radius);
+ int from_y = MAX(0,y-max_radius);
+ int to_y = MIN(bt.height-1,y+max_radius);
+
+ for(int k=from_y;k<=to_y;k++) {
+ for(int l=from_x;l<=to_x;l++) {
+
+ int dy = y-k;
+ int dx = x-l;
+ int dist = dy*dy+dx*dx;
+ if (dist>=closest_dist)
+ continue;
+
+ const uint8_t * rp = &copy_data[(k*bt.width+l)<<2];
+
+ if (rp[3]==0)
+ continue;
+
+ closest_dist=dist;
+ closest_color[0]=rp[0];
+ closest_color[1]=rp[1];
+ closest_color[2]=rp[2];
+ closest_color[3]=rp[3];
+ }
+ }
+
+
+ if (closest_dist!=max_dist) {
+
+ data[(y*bt.width+x)*4+0]=closest_color[0];
+ data[(y*bt.width+x)*4+1]=closest_color[1];
+ data[(y*bt.width+x)*4+2]=closest_color[2];
+ data[(y*bt.width+x)*4+3]=closest_color[3];
+ }
+ }
+ }
+ }
+ }
+
+ DVector<uint8_t> dv;
+ dv.resize(baked_textures[i].data.size());
+ {
+ DVector<uint8_t>::Write w = dv.write();
+ copymem(w.ptr(),baked_textures[i].data.ptr(),baked_textures[i].data.size());
+ }
+
+ Image img(baked_textures[i].width,baked_textures[i].height,0,Image::FORMAT_RGBA,dv);
+ Ref<ImageTexture> tex = memnew( ImageTexture );
+ tex->create_from_image(img);
+ baked_light->set_lightmap_texture(i,tex);
+ }
+
+
+ return OK;
}
void BakedLightBaker::clear() {
@@ -1707,12 +2626,21 @@ void BakedLightBaker::clear() {
memdelete_arr(octantptr_stack);
if (bvh_stack)
memdelete_arr(bvh_stack);
-
+/*
+ * ???
for(int i=0;i<octant_pool.size();i++) {
- if (octant_pool[i].leaf) {
- memdelete_arr( octant_pool[i].light );
+ //if (octant_pool[i].leaf) {
+ // memdelete_arr( octant_pool[i].light );
+ //} Vector<double> norm_arr;
+ //norm_arr.resize(lights.size());
+
+ for(int i=0;i<lights.size();i++) {
+ norm_arr[i] = 1.0/get_normalization(i);
}
+
+ const double *normptr=norm_arr.ptr();
}
+*/
octant_pool.clear();
octant_pool_size=0;
bvh=NULL;
@@ -1728,12 +2656,14 @@ void BakedLightBaker::clear() {
lights.clear();
triangles.clear();;
endpoint_normal.clear();
+ endpoint_normal_bits.clear();
baked_octree_texture_w=0;
baked_octree_texture_h=0;
paused=false;
baking=false;
- thread=NULL;
+
bake_thread_exit=false;
+ first_bake_to_map=true;
baked_light=Ref<BakedLight>();
total_rays=0;
@@ -1758,12 +2688,11 @@ BakedLightBaker::BakedLightBaker() {
baked_octree_texture_h=0;
paused=false;
baking=false;
- thread=NULL;
+
bake_thread_exit=false;
- rays_at_snap_time=0;
- snap_time=0;
- rays_sec=0;
total_rays=0;
+ first_bake_to_map=true;
+ linear_color=false;
}
diff --git a/tools/editor/plugins/baked_light_baker.h b/tools/editor/plugins/baked_light_baker.h
index 99c8211eed..8fbeeddc6a 100644
--- a/tools/editor/plugins/baked_light_baker.h
+++ b/tools/editor/plugins/baked_light_baker.h
@@ -15,17 +15,19 @@ public:
OCTANT_POOL_CHUNK=1000000
};
- struct OctantLight {
+ //struct OctantLight {
- double accum[8][3];
- };
+ // double accum[8][3];
+ //};
struct Octant {
bool leaf;
AABB aabb;
uint16_t texture_x;
uint16_t texture_y;
+ int sampler_ofs;
float normal_accum[8][3];
+ double full_accum[3];
int parent;
union {
struct {
@@ -33,7 +35,7 @@ public:
float offset[3];
int bake_neighbour;
bool first_neighbour;
- OctantLight *light;
+ double light_accum[8][3];
};
int children[8];
};
@@ -94,11 +96,13 @@ public:
struct Triangle {
- AABB aabb;
+ AABB aabb;
Vector3 vertices[3];
Vector2 uvs[3];
+ Vector2 bake_uvs[3];
Vector3 normals[3];
MeshMaterial *material;
+ int baked_texture;
_FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos) {
@@ -180,6 +184,12 @@ public:
}
};
+ struct BakeTexture {
+
+ Vector<uint8_t> data;
+ int width,height;
+ };
+
struct LightData {
@@ -194,10 +204,12 @@ public:
float energy;
float length;
int rays_thrown;
+ bool bake_shadow;
float radius;
float attenuation;
float spot_angle;
+ float darkening;
float spot_attenuation;
float area;
@@ -220,34 +232,53 @@ public:
int octant_pool_size;
BVH*bvh;
Vector<Triangle> triangles;
+ Vector<BakeTexture> baked_textures;
Transform base_inv;
int leaf_list;
int octree_depth;
+ int bvh_depth;
int cell_count;
uint32_t *ray_stack;
+ BVH **bvh_stack;
uint32_t *octant_stack;
uint32_t *octantptr_stack;
+
+ struct ThreadStack {
+ uint32_t *octant_stack;
+ uint32_t *octantptr_stack;
+ uint32_t *ray_stack;
+ BVH **bvh_stack;
+ };
+
Map<Vector3,Vector3> endpoint_normal;
- BVH **bvh_stack;
+ Map<Vector3,uint64_t> endpoint_normal_bits;
+
float cell_size;
float plot_size; //multiplied by cell size
float octree_extra_margin;
int max_bounces;
- uint64_t total_rays;
+ int64_t total_rays;
bool use_diffuse;
bool use_specular;
bool use_translucency;
+ bool linear_color;
int baked_octree_texture_w;
int baked_octree_texture_h;
+ int baked_light_texture_w;
+ int baked_light_texture_h;
int lattice_size;
float edge_damp;
float normal_damp;
+ float tint;
+ float ao_radius;
+ float ao_strength;
bool paused;
bool baking;
+ bool first_bake_to_map;
Map<Ref<Material>,MeshMaterial*> mat_map;
Map<Ref<Texture>,MeshTexture*> tex_map;
@@ -255,13 +286,14 @@ public:
MeshTexture* _get_mat_tex(const Ref<Texture>& p_tex);
- void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform);
+ void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform,int p_baked_texture=-1);
void _parse_geometry(Node* p_node);
BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth);
void _make_bvh();
void _make_octree();
void _make_octree_texture();
void _octree_insert(int p_octant, Triangle* p_triangle, int p_depth);
+ _FORCE_INLINE_ void _plot_pixel_to_lightmap(int x, int y, int width, int height, uint8_t *image, const Vector3& p_pos,const Vector3& p_normal,double *p_norm_ptr,float mult,float gamma);
void _free_bvh(BVH* p_bvh);
@@ -272,19 +304,16 @@ public:
//void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,int p_octant=0);
- void _plot_light(int p_light_index,const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,const Plane& p_plane);
+ void _plot_light(ThreadStack& thread_stack,const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,const Color& p_tint_light,bool p_only_full,const Plane& p_plane);
//void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light);
- float _throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce=false);
+ float _throw_ray(ThreadStack& thread_stack,bool p_bake_direct,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce=false,bool p_only_dist=false);
float total_light_area;
- uint64_t rays_at_snap_time;
- uint64_t snap_time;
- int rays_sec;
+ Vector<Thread*> threads;
- Thread *thread;
bool bake_thread_exit;
static void _bake_thread_func(void *arg);
@@ -293,16 +322,20 @@ public:
public:
- void throw_rays(int p_amount);
+ void throw_rays(ThreadStack &thread_stack, int p_amount);
double get_normalization(int p_light_idx) const;
+ double get_modifier(int p_light_idx) const;
void bake(const Ref<BakedLight>& p_light,Node *p_base);
bool is_baking();
void set_pause(bool p_pause);
bool is_paused();
- int get_rays_sec() { return rays_sec; }
+ uint64_t get_rays_thrown() { return total_rays; }
+
+ Error transfer_to_lightmaps();
- void update_octree_image(DVector<uint8_t> &p_image);
+ void update_octree_sampler(DVector<int> &p_sampler);
+ void update_octree_images(DVector<uint8_t> &p_octree,DVector<uint8_t> &p_light);
Ref<BakedLight> get_baked_light() { return baked_light; }
diff --git a/tools/editor/plugins/baked_light_baker_cmpxchg.cpp b/tools/editor/plugins/baked_light_baker_cmpxchg.cpp
new file mode 100644
index 0000000000..42d3fc5276
--- /dev/null
+++ b/tools/editor/plugins/baked_light_baker_cmpxchg.cpp
@@ -0,0 +1,85 @@
+
+#include "typedefs.h"
+
+
+#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
+
+void baked_light_baker_add_64f(double *dst,double value) {
+
+
+ union {
+ int64_t i;
+ double f;
+ } swapy;
+
+
+ while(true) {
+ swapy.f=*dst;
+ int64_t from = swapy.i;
+ swapy.f+=value;
+ int64_t to=swapy.i;
+ if (__sync_bool_compare_and_swap((int64_t*)dst,from,to))
+ break;
+ }
+}
+
+void baked_light_baker_add_64i(int64_t *dst,int64_t value) {
+
+ while(!__sync_bool_compare_and_swap(dst,*dst,(*dst)+value)) {}
+
+}
+
+#elif defined(WINDOWS_ENABLED)
+
+#include "windows.h"
+
+void baked_light_baker_add_64f(double *dst,double value) {
+
+ union {
+ int64_t i;
+ double f;
+ } swapy;
+
+
+ while(true) {
+ swapy.f=*dst;
+ int64_t from = swapy.i;
+ swapy.f+=value;
+ int64_t to=swapy.i;
+ int64_t result = InterlockedCompareExchange64((int64_t*)dst,to,from);
+ if (result==from)
+ break;
+ }
+
+}
+
+void baked_light_baker_add_64i(int64_t *dst,int64_t value) {
+
+ while(true) {
+ int64_t from = *dst;
+ int64_t to = from+value;
+ int64_t result = InterlockedCompareExchange64(dst,to,from);
+ if (result==from)
+ break;
+ }
+}
+
+
+#else
+
+//in goder (the god of programmers) we trust
+#warning seems this platform or compiler does not support safe cmpxchg, your baked lighting may be funny
+
+void baked_light_baker_add_64f(double *dst,double value) {
+
+ *dst+=value;
+
+}
+
+void baked_light_baker_add_64i(int64_t *dst,int64_t value) {
+
+ *dst+=value;
+
+}
+
+#endif
diff --git a/tools/editor/plugins/baked_light_editor_plugin.cpp b/tools/editor/plugins/baked_light_editor_plugin.cpp
index a1383f22fe..26524b2437 100644
--- a/tools/editor/plugins/baked_light_editor_plugin.cpp
+++ b/tools/editor/plugins/baked_light_editor_plugin.cpp
@@ -34,10 +34,11 @@ void BakedLightEditor::_node_removed(Node *p_node) {
void BakedLightEditor::_notification(int p_option) {
- if (p_option==NOTIFICATION_ENTER_SCENE) {
+ if (p_option==NOTIFICATION_ENTER_TREE) {
button_bake->set_icon(get_icon("Bake","EditorIcons"));
button_reset->set_icon(get_icon("Reload","EditorIcons"));
+ button_make_lightmaps->set_icon(get_icon("LightMap","EditorIcons"));
}
if (p_option==NOTIFICATION_PROCESS) {
@@ -110,7 +111,10 @@ void BakedLightEditor::_notification(int p_option) {
#endif
ERR_FAIL_COND(node->get_baked_light().is_null());
- baker->update_octree_image(octree_texture);
+ baker->update_octree_images(octree_texture,light_texture);
+ baker->update_octree_sampler(octree_sampler);
+ // print_line("sampler size: "+itos(octree_sampler.size()*4));
+
#if 1
//debug
Image img(baker->baked_octree_texture_w,baker->baked_octree_texture_h,0,Image::FORMAT_RGBA,octree_texture);
@@ -120,11 +124,19 @@ void BakedLightEditor::_notification(int p_option) {
#endif
- bake_info->set_text("rays/s: "+itos(baker->get_rays_sec()));
+
+
+ uint64_t rays_snap = baker->get_rays_thrown();
+ int rays_sec = (rays_snap-last_rays_time)*1.0-(update_timeout);
+ last_rays_time=rays_snap;
+
+ bake_info->set_text("rays/s: "+itos(rays_sec));
update_timeout=1;
print_line("MSUPDATE: "+itos(OS::get_singleton()->get_ticks_msec()-t));
t=OS::get_singleton()->get_ticks_msec();
node->get_baked_light()->set_octree(octree_texture);
+ node->get_baked_light()->set_light(light_texture);
+ node->get_baked_light()->set_sampler_octree(octree_sampler);
node->get_baked_light()->set_edited(true);
print_line("MSSET: "+itos(OS::get_singleton()->get_ticks_msec()-t));
@@ -148,7 +160,7 @@ void BakedLightEditor::_menu_option(int p_option) {
ERR_FAIL_COND(!node);
ERR_FAIL_COND(node->get_baked_light().is_null());
baker->bake(node->get_baked_light(),node);
-
+ node->get_baked_light()->set_mode(BakedLight::MODE_OCTREE);
update_timeout=0;
set_process(true);
@@ -168,7 +180,7 @@ void BakedLightEditor::_bake_pressed() {
ERR_FAIL_COND(!node);
if (node->get_baked_light().is_null()) {
err_dialog->set_text("BakedLightInstance does not contain a BakedLight resource.");
- err_dialog->popup_centered(Size2(350,70));
+ err_dialog->popup_centered_minsize();
button_bake->set_pressed(false);
return;
}
@@ -180,15 +192,23 @@ void BakedLightEditor::_bake_pressed() {
set_process(false);
bake_info->set_text("");
+ button_reset->show();
+ button_make_lightmaps->show();
+
} else {
update_timeout=0;
set_process(true);
+ button_make_lightmaps->hide();
+ button_reset->hide();
}
-
} else {
baker->bake(node->get_baked_light(),node);
+ node->get_baked_light()->set_mode(BakedLight::MODE_OCTREE);
update_timeout=0;
+
+ last_rays_time=0;
+
set_process(true);
}
@@ -216,13 +236,27 @@ void BakedLightEditor::edit(BakedLightInstance *p_baked_light) {
}
+void BakedLightEditor::_bake_lightmaps() {
+
+ Error err = baker->transfer_to_lightmaps();
+ if (err) {
+ err_dialog->set_text("Error baking to lightmaps!\nMake sure that a bake has just\n happened and that lightmaps are\n configured. ");
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ node->get_baked_light()->set_mode(BakedLight::MODE_LIGHTMAPS);
+
+
+}
void BakedLightEditor::_bind_methods() {
ObjectTypeDB::bind_method("_menu_option",&BakedLightEditor::_menu_option);
ObjectTypeDB::bind_method("_bake_pressed",&BakedLightEditor::_bake_pressed);
ObjectTypeDB::bind_method("_clear_pressed",&BakedLightEditor::_clear_pressed);
+ ObjectTypeDB::bind_method("_bake_lightmaps",&BakedLightEditor::_bake_lightmaps);
}
BakedLightEditor::BakedLightEditor() {
@@ -233,6 +267,11 @@ BakedLightEditor::BakedLightEditor() {
button_bake->set_text("Bake!");
button_bake->set_toggle_mode(true);
button_reset = memnew( Button );
+ button_make_lightmaps = memnew( Button );
+ button_bake->set_tooltip("Start/Unpause the baking process.\nThis bakes lighting into the lightmap octree.");
+ button_make_lightmaps ->set_tooltip("Convert the lightmap octree to lightmap textures\n(must have set up UV/Lightmaps properly before!).");
+
+
bake_info = memnew( Label );
bake_hbox->add_child( button_bake );
bake_hbox->add_child( button_reset );
@@ -243,8 +282,15 @@ BakedLightEditor::BakedLightEditor() {
node=NULL;
baker = memnew( BakedLightBaker );
+ bake_hbox->add_child(button_make_lightmaps);
+ button_make_lightmaps->hide();
+
button_bake->connect("pressed",this,"_bake_pressed");
button_reset->connect("pressed",this,"_clear_pressed");
+ button_make_lightmaps->connect("pressed",this,"_bake_lightmaps");
+ button_reset->hide();
+ button_reset->set_tooltip("Reset the lightmap octree baking process (start over).");
+
update_timeout=0;
diff --git a/tools/editor/plugins/baked_light_editor_plugin.h b/tools/editor/plugins/baked_light_editor_plugin.h
index 4ecc0b458f..27ab88d70b 100644
--- a/tools/editor/plugins/baked_light_editor_plugin.h
+++ b/tools/editor/plugins/baked_light_editor_plugin.h
@@ -23,6 +23,8 @@ class BakedLightEditor : public Control {
float update_timeout;
DVector<uint8_t> octree_texture;
+ DVector<uint8_t> light_texture;
+ DVector<int> octree_sampler;
BakedLightBaker *baker;
AcceptDialog *err_dialog;
@@ -30,8 +32,12 @@ class BakedLightEditor : public Control {
HBoxContainer *bake_hbox;
Button *button_bake;
Button *button_reset;
+ Button *button_make_lightmaps;
Label *bake_info;
+ uint64_t last_rays_time;
+
+
BakedLightInstance *node;
@@ -41,6 +47,8 @@ class BakedLightEditor : public Control {
MENU_OPTION_CLEAR
};
+ void _bake_lightmaps();
+
void _bake_pressed();
void _clear_pressed();
diff --git a/tools/editor/plugins/camera_editor_plugin.cpp b/tools/editor/plugins/camera_editor_plugin.cpp
index aa7562b17e..08ed2c745d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/camera_editor_plugin.h b/tools/editor/plugins/camera_editor_plugin.h
index 5529b32e56..afb8f9415d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp
index e2944af422..a3164fc524 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,18 +36,185 @@
#include "globals.h"
#include "os/input.h"
#include "tools/editor/editor_settings.h"
+#include "scene/gui/grid_container.h"
+
+class SnapDialog : public ConfirmationDialog {
+
+ OBJ_TYPE(SnapDialog,ConfirmationDialog);
+
+friend class CanvasItemEditor;
+
+ SpinBox *grid_offset_x;
+ SpinBox *grid_offset_y;
+ SpinBox *grid_step_x;
+ SpinBox *grid_step_y;
+ SpinBox *rotation_offset;
+ SpinBox *rotation_step;
+
+public:
+ SnapDialog() : ConfirmationDialog() {
+ const int SPIN_BOX_GRID_RANGE = 256;
+ const int SPIN_BOX_ROTATION_RANGE = 360;
+ Label *label;
+ VBoxContainer *container;
+ GridContainer *child_container;
+
+ set_title("Configure Snap");
+ get_ok()->set_text("Close");
+
+ container = memnew( VBoxContainer );
+ add_child(container);
+ set_child_rect(container);
+
+ child_container = memnew( GridContainer );
+ child_container->set_columns(3);
+ container->add_child(child_container);
+
+ label = memnew( Label );
+ label->set_text("Grid Offset:");
+ child_container->add_child(label);
+ 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->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->set_text("Grid Step:");
+ child_container->add_child(label);
+ 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->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 );
+ child_container->set_columns(2);
+ container->add_child(child_container);
+
+ label = memnew( Label );
+ label->set_text("Rotation Offset:");
+ child_container->add_child(label);
+ 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->set_text("Rotation Step:");
+ child_container->add_child(label);
+ 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");
+ child_container->add_child(rotation_step);
+ }
+
+ void set_fields(const Point2 p_grid_offset, const Size2 p_grid_step, const float p_rotation_offset, const float p_rotation_step) {
+ grid_offset_x->set_val(p_grid_offset.x);
+ grid_offset_y->set_val(p_grid_offset.y);
+ grid_step_x->set_val(p_grid_step.x);
+ grid_step_y->set_val(p_grid_step.y);
+ rotation_offset->set_val(p_rotation_offset * (180 / Math_PI));
+ rotation_step->set_val(p_rotation_step * (180 / Math_PI));
+ }
+
+ void get_fields(Point2 &p_grid_offset, Size2 &p_grid_step, float &p_rotation_offset, float &p_rotation_step) {
+ p_grid_offset.x = grid_offset_x->get_val();
+ p_grid_offset.y = grid_offset_y->get_val();
+ p_grid_step.x = grid_step_x->get_val();
+ p_grid_step.y = grid_step_y->get_val();
+ p_rotation_offset = rotation_offset->get_val() / (180 / Math_PI);
+ p_rotation_step = rotation_step->get_val() / (180 / Math_PI);
+ }
+};
+
void CanvasItemEditor::_unhandled_key_input(const InputEvent& p_ev) {
if (!is_visible())
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);
if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_W)
_tool_select(TOOL_MOVE);
if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_E)
_tool_select(TOOL_ROTATE);
- if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_V && drag==DRAG_ALL && can_move_pivot)
- drag=DRAG_PIVOT;
+ if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_V && drag==DRAG_NONE && can_move_pivot) {
+ if (p_ev.key.mod.shift) {
+ //move drag pivot
+ drag=DRAG_PIVOT;
+ } else if (!Input::get_singleton()->is_mouse_button_pressed(0)) {
+
+ List<Node*> &selection = editor_selection->get_selected_node_list();
+
+ Vector2 mouse_pos = viewport->get_local_mouse_pos();
+ if (selection.size() && viewport->get_rect().has_point(mouse_pos)) {
+ //just in case, make it work if over viewport
+ 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();
+ }
+
+ }
+ }
}
@@ -75,9 +242,24 @@ Object *CanvasItemEditor::_get_editor_data(Object *p_what) {
return memnew( CanvasItemEditorSelectedItem );
}
-bool CanvasItemEditor::is_snap_active() const {
+inline float _snap_scalar(float p_offset, float p_step, bool p_snap_relative, float p_target, float p_start) {
+ float offset = p_snap_relative ? p_start : p_offset;
+ return p_step != 0 ? Math::stepify(p_target - offset, p_step) + offset : p_target;
+}
+
+Vector2 CanvasItemEditor::snap_point(Vector2 p_target, Vector2 p_start) const {
+ if (snap_grid) {
+ p_target.x = _snap_scalar(snap_offset.x, snap_step.x, snap_relative, p_target.x, p_start.x);
+ p_target.y = _snap_scalar(snap_offset.y, snap_step.y, snap_relative, p_target.y, p_start.y);
+ }
+ if (snap_pixel)
+ p_target = p_target.snapped(Size2(1, 1));
+
+ return p_target;
+}
- return edit_menu->get_popup()->is_item_checked(edit_menu->get_popup()->get_item_index(SNAP_USE));
+float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
+ return snap_rotation ? _snap_scalar(snap_rotation_offset, snap_rotation_step, snap_relative, p_target, p_start) : p_target;
}
Dictionary CanvasItemEditor::get_state() const {
@@ -86,9 +268,15 @@ Dictionary CanvasItemEditor::get_state() const {
state["zoom"]=zoom;
state["ofs"]=Point2(h_scroll->get_val(),v_scroll->get_val());
// state["ofs"]=-transform.get_origin();
- state["use_snap"]=is_snap_active();
- state["snap"]=snap;
- state["pixel_snap"]=pixel_snap;
+ state["snap_offset"]=snap_offset;
+ state["snap_step"]=snap_step;
+ state["snap_rotation_offset"]=snap_rotation_offset;
+ state["snap_rotation_step"]=snap_rotation_step;
+ state["snap_grid"]=snap_grid;
+ state["snap_show_grid"]=snap_show_grid;
+ state["snap_rotation"]=snap_rotation;
+ state["snap_relative"]=snap_relative;
+ state["snap_pixel"]=snap_pixel;
return state;
}
void CanvasItemEditor::set_state(const Dictionary& p_state){
@@ -105,19 +293,50 @@ void CanvasItemEditor::set_state(const Dictionary& p_state){
v_scroll->set_val(ofs.y);
}
- if (state.has("use_snap")) {
+ if (state.has("snap_step")) {
+ snap_step=state["snap_step"];
+ }
+
+ if (state.has("snap_offset")) {
+ snap_offset=state["snap_offset"];
+ }
+
+ if (state.has("snap_rotation_step")) {
+ snap_rotation_step=state["snap_rotation_step"];
+ }
+
+ if (state.has("snap_rotation_offset")) {
+ snap_rotation_offset=state["snap_rotation_offset"];
+ }
+
+ if (state.has("snap_grid")) {
+ snap_grid=state["snap_grid"];
int idx = edit_menu->get_popup()->get_item_index(SNAP_USE);
- edit_menu->get_popup()->set_item_checked(idx,state["use_snap"]);
+ edit_menu->get_popup()->set_item_checked(idx,snap_grid);
}
- if (state.has("snap")) {
- snap=state["snap"];
+ if (state.has("snap_show_grid")) {
+ snap_show_grid=state["snap_show_grid"];
+ int idx = edit_menu->get_popup()->get_item_index(SNAP_SHOW_GRID);
+ edit_menu->get_popup()->set_item_checked(idx,snap_show_grid);
}
- if (state.has("pixel_snap")) {
- pixel_snap=state["pixel_snap"];
+ if (state.has("snap_rotation")) {
+ snap_rotation=state["snap_rotation"];
+ int idx = edit_menu->get_popup()->get_item_index(SNAP_USE_ROTATION);
+ edit_menu->get_popup()->set_item_checked(idx,snap_rotation);
+ }
+
+ if (state.has("snap_relative")) {
+ snap_relative=state["snap_relative"];
+ int idx = edit_menu->get_popup()->get_item_index(SNAP_RELATIVE);
+ edit_menu->get_popup()->set_item_checked(idx,snap_relative);
+ }
+
+ if (state.has("snap_pixel")) {
+ snap_pixel=state["snap_pixel"];
int idx = edit_menu->get_popup()->get_item_index(SNAP_USE_PIXEL);
- edit_menu->get_popup()->set_item_checked(idx,pixel_snap);
+ edit_menu->get_popup()->set_item_checked(idx,snap_pixel);
}
}
@@ -204,8 +423,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
}
@@ -214,7 +431,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);
@@ -228,6 +445,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) {
@@ -245,14 +501,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();
@@ -270,6 +524,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) {
@@ -286,9 +630,7 @@ void CanvasItemEditor::_key_move(const Vector2& p_dir, bool p_snap, KeyMoveMODE
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
@@ -300,7 +642,7 @@ void CanvasItemEditor::_key_move(const Vector2& p_dir, bool p_snap, KeyMoveMODE
Vector2 drag = p_dir;
if (p_snap)
- drag*=snap;
+ drag*=snap_step;
undo_redo->add_undo_method(canvas_item,"edit_set_state",canvas_item->edit_get_state());
@@ -347,9 +689,7 @@ Point2 CanvasItemEditor::_find_topleftmost_point() {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
@@ -377,9 +717,7 @@ int CanvasItemEditor::get_item_count() {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
ic++;
@@ -398,9 +736,7 @@ CanvasItem *CanvasItemEditor::get_single_item() {
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->key()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
if (single_item)
@@ -554,6 +890,11 @@ void CanvasItemEditor::_append_canvas_item(CanvasItem *c) {
}
+void CanvasItemEditor::_snap_changed() {
+ ((SnapDialog *)snap_dialog)->get_fields(snap_offset, snap_step, snap_rotation_offset, snap_rotation_step);
+ viewport->update();
+}
+
void CanvasItemEditor::_dialog_value_changed(double) {
if (updating_value_dialog)
@@ -561,11 +902,6 @@ void CanvasItemEditor::_dialog_value_changed(double) {
switch(last_option) {
- case SNAP_CONFIGURE: {
-
- snap=dialog_val->get_val();
- viewport->update();
- } break;
case ZOOM_SET: {
zoom=dialog_val->get_val()/100.0;
@@ -577,6 +913,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) {
@@ -639,7 +993,60 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
if (b.button_index==BUTTON_RIGHT) {
+ if (b.pressed && tool==TOOL_SELECT && b.mod.alt) {
+
+ 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);
+
+ 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");
+
+ return;
+ }
+ }
if (get_item_count() > 0 && drag!=DRAG_NONE) {
//cancel drag
@@ -661,9 +1068,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
@@ -735,9 +1140,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
@@ -799,13 +1202,13 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
}
- List<BoneList>::Element *Cbone=NULL; //closest
+ Map<ObjectID,BoneList>::Element *Cbone=NULL; //closest
{
bone_ik_list.clear();
float closest_dist=1e20;
int bone_width = EditorSettings::get_singleton()->get("2d_editor/bone_width");
- for(List<BoneList>::Element *E=bone_list.front();E;E=E->next()) {
+ for(Map<ObjectID,BoneList>::Element *E=bone_list.front();E;E=E->next()) {
if (E->get().from == E->get().to)
continue;
@@ -943,9 +1346,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
@@ -1010,90 +1411,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_scene()->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)
- continue;
- if (!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;
@@ -1126,9 +1453,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
@@ -1153,39 +1478,21 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
if (drag==DRAG_ROTATE) {
Vector2 center = canvas_item->get_global_transform_with_canvas().get_origin();
-
- Matrix32 rot;
- rot.elements[1] = (dfrom - center).normalized();
- rot.elements[0] = rot.elements[1].tangent();
- float ang = rot.xform_inv(dto-center).atan2();
- canvas_item->edit_rotate(ang);
- display_rotate_to = dto;
- display_rotate_from = center;
+ if (Node2D *node = canvas_item->cast_to<Node2D>()) {
+ 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).angle(), node->get_rot()));
+ display_rotate_to = dto;
+ display_rotate_from = center;
+ viewport->update();
+ }
continue;
}
- if (pixel_snap || (is_snap_active() && snap>0)) {
-
- if (drag!=DRAG_ALL) {
- dfrom=drag_point_from;
- dto=snapify(dto);
- } else {
-
- Vector2 newpos = drag_point_from + (dto-dfrom);
- Vector2 disp;
- if (!is_snap_active() || snap<1) {
-
- disp.x = Math::fposmod(newpos.x,1);
- disp.y = Math::fposmod(newpos.y,1);
-
- } else {
- disp.x = Math::fposmod(newpos.x,snap);
- disp.y = Math::fposmod(newpos.y,snap);
- }
- dto-=disp;
- }
- }
+ dfrom = drag_point_from;
+ dto = snap_point(dto - (drag == DRAG_ALL ? drag_from - drag_point_from : Vector2(0, 0)), drag_point_from);
Vector2 drag_vector =
canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dto) -
@@ -1293,8 +1600,6 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
-
-
if (!dragging_bone) {
local_rect.pos=begin;
@@ -1477,32 +1782,32 @@ void CanvasItemEditor::_viewport_draw() {
_update_scrollbars();
RID ci=viewport->get_canvas_item();
- if (snap>0 && is_snap_active() && true ) {
-
+ if (snap_show_grid) {
Size2 s = viewport->get_size();
-
int last_cell;
Matrix32 xform = transform.affine_inverse();
- for(int i=0;i<s.width;i++) {
- int cell = Math::fast_ftoi(Math::floor(xform.xform(Vector2(i,0)).x/snap));
- if (i==0)
+ if (snap_step.x!=0) {
+ for(int i=0;i<s.width;i++) {
+ int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(i,0)).x-snap_offset.x)/snap_step.x));
+ if (i==0)
+ last_cell=cell;
+ if (last_cell!=cell)
+ viewport->draw_line(Point2(i,0),Point2(i,s.height),Color(0.3,0.7,1,0.3));
last_cell=cell;
- if (last_cell!=cell)
- viewport->draw_line(Point2(i,0),Point2(i,s.height),Color(0.3,0.7,1,0.3));
- last_cell=cell;
+ }
}
- for(int i=0;i<s.height;i++) {
-
- int cell = Math::fast_ftoi(Math::floor(xform.xform(Vector2(0,i)).y/snap));
- if (i==0)
+ if (snap_step.y!=0) {
+ for(int i=0;i<s.height;i++) {
+ int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(0,i)).y-snap_offset.y)/snap_step.y));
+ if (i==0)
+ last_cell=cell;
+ if (last_cell!=cell)
+ viewport->draw_line(Point2(0,i),Point2(s.width,i),Color(0.3,0.7,1,0.3));
last_cell=cell;
- if (last_cell!=cell)
- viewport->draw_line(Point2(0,i),Point2(s.width,i),Color(0.3,0.7,1,0.3));
- last_cell=cell;
+ }
}
-
}
if (viewport->has_focus()) {
@@ -1530,9 +1835,7 @@ void CanvasItemEditor::_viewport_draw() {
CanvasItem *canvas_item = E->key()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
@@ -1569,7 +1872,7 @@ void CanvasItemEditor::_viewport_draw() {
viewport->draw_line(endpoints[i],endpoints[(i+1)%4],c,2);
}
- if (single && (tool==TOOL_SELECT || tool == TOOL_MOVE)) { //kind of sucks
+ if (single && (tool==TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_ROTATE)) { //kind of sucks
if (canvas_item->cast_to<Node2D>()) {
@@ -1673,7 +1976,7 @@ void CanvasItemEditor::_viewport_draw() {
Color bone_ik_color = EditorSettings::get_singleton()->get("2d_editor/bone_ik_color");
Color bone_selected_color = EditorSettings::get_singleton()->get("2d_editor/bone_selected_color");
- for(List<BoneList>::Element*E=bone_list.front();E;E=E->next()) {
+ for(Map<ObjectID,BoneList>::Element*E=bone_list.front();E;E=E->next()) {
E->get().from=Vector2();
E->get().to=Vector2();
@@ -1746,14 +2049,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)
- continue;
- if (!canvas_item->is_visible())
+ 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;
@@ -1770,10 +2079,19 @@ void CanvasItemEditor::_notification(int p_what) {
}
- for(List<BoneList>::Element *E=bone_list.front();E;E=E->next()) {
+ 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()) {
Object *b = ObjectDB::get_instance(E->get().bone);
if (!b) {
+
viewport->update();
break;
}
@@ -1791,7 +2109,7 @@ void CanvasItemEditor::_notification(int p_what) {
}
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
select_sb->set_texture( get_icon("EditorRect2D","EditorIcons") );
for(int i=0;i<4;i++) {
@@ -1810,11 +2128,37 @@ 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) {
- get_scene()->connect("node_removed",this,"_node_removed");
+ get_tree()->connect("node_removed",this,"_node_removed");
}
if (p_what==NOTIFICATION_DRAW) {
@@ -1875,9 +2219,14 @@ void CanvasItemEditor::_find_canvas_items_span(Node *p_node, Rect2& r_rect, cons
if (c->has_meta("_edit_bone_")) {
- BoneList bone;
- bone.bone=c->get_instance_ID();
- bone_list.push_back(bone);
+ ObjectID id = c->get_instance_ID();
+ if (!bone_list.has(id)) {
+ BoneList bone;
+ bone.bone=id;
+ bone_list[id]=bone;
+ }
+
+ bone_list[id].last_pass=bone_last_frame;
}
r_rect.expand_to( xform.xform(rect.pos) );
@@ -1912,11 +2261,26 @@ void CanvasItemEditor::_update_scrollbars() {
Rect2 canvas_item_rect=Rect2(Point2(),screen_rect);
lock_list.clear();;
- bone_list.clear();;
+ bone_last_frame++;
+
+
if (editor->get_edited_scene())
_find_canvas_items_span(editor->get_edited_scene(),canvas_item_rect,Matrix32());
+ List<Map<ObjectID,BoneList>::Element*> bone_to_erase;
+
+ for(Map<ObjectID,BoneList>::Element*E=bone_list.front();E;E=E->next()) {
+
+ if (E->get().last_pass!=bone_last_frame) {
+ bone_to_erase.push_back(E);
+ }
+ }
+
+ while(bone_to_erase.size()) {
+ bone_list.erase(bone_to_erase.front()->get());
+ bone_to_erase.pop_front();
+ }
//expand area so it's easier to do animations and stuff at 0,0
canvas_item_rect.size+=screen_rect*2;
@@ -1995,60 +2359,62 @@ 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();
-Point2 CanvasItemEditor::snapify(const Point2& p_pos) const {
-
- bool active=is_snap_active();
-
- Vector2 pos = p_pos;
-
- if (!active || snap<1) {
-
- if (pixel_snap) {
+ undo_redo->create_action("Change Anchors");
+ for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
- pos.x=Math::stepify(pos.x,1);
- pos.y=Math::stepify(pos.y,1);
- }
+ Control *c = E->get()->cast_to<Control>();
- return pos;
+ 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));
}
-
- pos.x=Math::stepify(pos.x,snap);
- pos.y=Math::stepify(pos.y,snap);
- return pos;
-
+ undo_redo->commit_action();
}
-
void CanvasItemEditor::_popup_callback(int p_op) {
last_option=MenuOption(p_op);
switch(p_op) {
case SNAP_USE: {
-
+ snap_grid = !snap_grid;
int idx = edit_menu->get_popup()->get_item_index(SNAP_USE);
- edit_menu->get_popup()->set_item_checked( idx,!edit_menu->get_popup()->is_item_checked(0));
+ edit_menu->get_popup()->set_item_checked(idx,snap_grid);
+ } break;
+ case SNAP_SHOW_GRID: {
+ snap_show_grid = !snap_show_grid;
+ int idx = edit_menu->get_popup()->get_item_index(SNAP_SHOW_GRID);
+ edit_menu->get_popup()->set_item_checked(idx,snap_show_grid);
viewport->update();
} break;
+ case SNAP_USE_ROTATION: {
+ snap_rotation = !snap_rotation;
+ int idx = edit_menu->get_popup()->get_item_index(SNAP_USE_ROTATION);
+ edit_menu->get_popup()->set_item_checked(idx,snap_rotation);
+ } break;
+ case SNAP_RELATIVE: {
+ snap_relative = !snap_relative;
+ int idx = edit_menu->get_popup()->get_item_index(SNAP_RELATIVE);
+ edit_menu->get_popup()->set_item_checked(idx,snap_relative);
+ } break;
case SNAP_USE_PIXEL: {
- pixel_snap = ! pixel_snap;
+ snap_pixel = !snap_pixel;
int idx = edit_menu->get_popup()->get_item_index(SNAP_USE_PIXEL);
- edit_menu->get_popup()->set_item_checked(idx,pixel_snap);
+ edit_menu->get_popup()->set_item_checked(idx,snap_pixel);
} break;
case SNAP_CONFIGURE: {
- updating_value_dialog=true;
-
- dialog_label->set_text("Snap (Pixels):");
- dialog_val->set_min(1);
- dialog_val->set_step(1);
- dialog_val->set_max(4096);
- dialog_val->set_val(snap);
- value_dialog->popup_centered(Size2(200,85));
- updating_value_dialog=false;
-
+ ((SnapDialog *)snap_dialog)->set_fields(snap_offset, snap_step, snap_rotation_offset, snap_rotation_step);
+ snap_dialog->popup_centered(Size2(220,160));
} break;
case ZOOM_IN: {
zoom=zoom*(1.0/0.5);
@@ -2092,9 +2458,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
canvas_item->set_meta("_edit_lock_",true);
@@ -2109,9 +2473,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
@@ -2129,9 +2491,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
canvas_item->set_meta("_edit_group_",true);
@@ -2146,9 +2506,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
canvas_item->set_meta("_edit_group_",Variant());
@@ -2166,9 +2524,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
@@ -2226,6 +2582,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: {
@@ -2236,9 +2642,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->key()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
if (canvas_item->cast_to<Node2D>()) {
@@ -2307,7 +2711,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
} break;
case ANIM_INSERT_ROT: {
- key_pos = key_rot_button->is_pressed();
+ key_rot = key_rot_button->is_pressed();
} break;
case ANIM_INSERT_SCALE: {
@@ -2348,9 +2752,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->key()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
@@ -2400,9 +2802,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->key()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
if (canvas_item->cast_to<Node2D>()) {
@@ -2528,9 +2928,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item)
- continue;
- if (!canvas_item->is_visible())
+ if (!canvas_item || !canvas_item->is_visible())
continue;
@@ -2604,6 +3002,9 @@ void CanvasItemEditor::_bind_methods() {
ObjectTypeDB::bind_method("_unhandled_key_input",&CanvasItemEditor::_unhandled_key_input);
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") );
@@ -2683,6 +3084,16 @@ void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
hb->add_child(p_control);
}
+HSplitContainer *CanvasItemEditor::get_palette_split() {
+
+ return palette_split;
+}
+
+VSplitContainer *CanvasItemEditor::get_bottom_split() {
+
+ return bottom_split;
+}
+
CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
tool = TOOL_SELECT;
@@ -2697,15 +3108,24 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
add_child( hb );
hb->set_area_as_parent_rect();
+ bottom_split = memnew( VSplitContainer );
+ bottom_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(bottom_split);
+
+ palette_split = memnew( HSplitContainer);
+ palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ bottom_split->add_child(palette_split);
+
Control *vp_base = memnew (Control);
- add_child(vp_base);
vp_base->set_v_size_flags(SIZE_EXPAND_FILL);
+ palette_split->add_child(vp_base);
Control *vp = memnew (Control);
vp_base->add_child(vp);
vp->set_area_as_parent_rect();
vp->add_child(p_editor->get_scene_root());
+
viewport = memnew( Control );
vp_base->add_child(viewport);
viewport->set_area_as_parent_rect();
@@ -2735,7 +3155,7 @@ 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 Move 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).");
move_button = memnew( ToolButton );
move_button->set_toggle_mode(true);
@@ -2790,6 +3210,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
PopupMenu *p;
p = edit_menu->get_popup();
p->add_check_item("Use Snap",SNAP_USE);
+ p->add_check_item("Show Grid",SNAP_SHOW_GRID);
+ p->add_check_item("Use Rotation Snap",SNAP_USE_ROTATION);
+ p->add_check_item("Snap Relative",SNAP_RELATIVE);
p->add_item("Configure Snap..",SNAP_CONFIGURE);
p->add_separator();
p->add_check_item("Use Pixel Snap",SNAP_USE_PIXEL);
@@ -2829,6 +3252,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 );
@@ -2878,7 +3309,11 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_separator();
p->add_item("Copy Pose",ANIM_COPY_POSE);
p->add_item("Paste Pose",ANIM_PASTE_POSE);
- p->add_item("Clear Pose",ANIM_CLEAR_POSE,KEY_MASK_ALT|KEY_K);
+ p->add_item("Clear Pose",ANIM_CLEAR_POSE,KEY_MASK_SHIFT|KEY_K);
+
+ snap_dialog = memnew( SnapDialog );
+ snap_dialog->connect("confirmed",this,"_snap_changed");
+ add_child(snap_dialog);
value_dialog = memnew( AcceptDialog );
value_dialog->set_title("Set a Value");
@@ -2899,12 +3334,25 @@ 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;
zoom=1;
- snap=10;
+ snap_offset=Vector2(0, 0);
+ snap_step=Vector2(10, 10);
+ snap_rotation_offset=0;
+ snap_rotation_step=15 / (180 / Math_PI);
+ snap_grid=false;
+ snap_show_grid=false;
+ snap_rotation=false;
+ snap_pixel=false;
updating_value_dialog=false;
box_selecting=false;
//zoom=0.5;
@@ -2912,8 +3360,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
editor->get_animation_editor()->connect("keying_changed",this,"_keying_changed");
set_process_unhandled_key_input(true);
can_move_pivot=false;
- pixel_snap=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 15ac7b1bb3..b96d36f7dc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -75,6 +75,9 @@ class CanvasItemEditor : public VBoxContainer {
enum MenuOption {
SNAP_USE,
+ SNAP_SHOW_GRID,
+ SNAP_USE_ROTATION,
+ SNAP_RELATIVE,
SNAP_CONFIGURE,
SNAP_USE_PIXEL,
ZOOM_IN,
@@ -87,6 +90,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,
@@ -130,6 +150,7 @@ class CanvasItemEditor : public VBoxContainer {
};
EditorSelection *editor_selection;
+ bool additive_selection;
Tool tool;
bool first_update;
@@ -143,8 +164,15 @@ class CanvasItemEditor : public VBoxContainer {
Matrix32 transform;
float zoom;
- int snap;
- bool pixel_snap;
+ Vector2 snap_offset;
+ Vector2 snap_step;
+ float snap_rotation_step;
+ float snap_rotation_offset;
+ bool snap_grid;
+ bool snap_show_grid;
+ bool snap_rotation;
+ bool snap_relative;
+ bool snap_pixel;
bool box_selecting;
Point2 box_selecting_to;
bool key_pos;
@@ -156,6 +184,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;
@@ -171,9 +211,12 @@ class CanvasItemEditor : public VBoxContainer {
Vector2 from;
Vector2 to;
ObjectID bone;
+ uint64_t last_pass;
};
- List<BoneList> bone_list;
+ uint64_t bone_last_frame;
+ Map<ObjectID,BoneList> bone_list;
+
Matrix32 bone_orig_xform;
struct BoneIK {
@@ -212,12 +255,15 @@ 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;
@@ -245,8 +291,13 @@ 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;
Label *dialog_label;
SpinBox *dialog_val;
@@ -261,7 +312,6 @@ class CanvasItemEditor : public VBoxContainer {
DragType _find_drag_type(const Matrix32& p_xform, const Rect2& p_local_rect, const Point2& p_click, Vector2& r_point);
- Point2 snapify(const Point2& p_pos) const;
void _popup_callback(int p_op);
bool updating_scroll;
void _update_scroll(float);
@@ -271,6 +321,10 @@ 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();
@@ -289,6 +343,12 @@ class CanvasItemEditor : public VBoxContainer {
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;
+
friend class CanvasItemEditorPlugin;
protected:
@@ -330,8 +390,8 @@ protected:
static CanvasItemEditor *singleton;
public:
- bool is_snap_active() const;
- int get_snap() const { return snap; }
+ Vector2 snap_point(Vector2 p_target, Vector2 p_start = Vector2(0, 0)) const;
+ float snap_angle(float p_target, float p_start = 0) const;
Matrix32 get_canvas_transform() const { return transform; }
@@ -341,6 +401,9 @@ public:
void add_control_to_menu_panel(Control *p_control);
+ HSplitContainer *get_palette_split();
+ VSplitContainer *get_bottom_split();
+
Control *get_viewport_control() { return viewport; }
diff --git a/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..8eea723126
--- /dev/null
+++ b/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp
@@ -0,0 +1,456 @@
+#include "collision_polygon_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "os/file_access.h"
+#include "tools/editor/editor_settings.h"
+
+
+void CollisionPolygon2DEditor::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_READY: {
+
+ button_create->set_icon( get_icon("Edit","EditorIcons"));
+ button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
+ button_edit->set_pressed(true);
+ get_tree()->connect("node_removed",this,"_node_removed");
+
+ } break;
+ case NOTIFICATION_FIXED_PROCESS: {
+
+
+ } break;
+ }
+
+}
+void CollisionPolygon2DEditor::_node_removed(Node *p_node) {
+
+ if(p_node==node) {
+ node=NULL;
+ hide();
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
+}
+
+
+void CollisionPolygon2DEditor::_menu_option(int p_option) {
+
+ switch(p_option) {
+
+ case MODE_CREATE: {
+
+ mode=MODE_CREATE;
+ button_create->set_pressed(true);
+ button_edit->set_pressed(false);
+ } break;
+ case MODE_EDIT: {
+
+ mode=MODE_EDIT;
+ button_create->set_pressed(false);
+ button_edit->set_pressed(true);
+ } break;
+
+ }
+}
+
+void CollisionPolygon2DEditor::_wip_close() {
+
+ undo_redo->create_action("Create Poly");
+ undo_redo->add_undo_method(node,"set_polygon",node->get_polygon());
+ undo_redo->add_do_method(node,"set_polygon",wip);
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ wip.clear();
+ wip_active=false;
+ mode=MODE_EDIT;
+ button_edit->set_pressed(true);
+ button_create->set_pressed(false);
+ edited_point=-1;
+}
+
+bool CollisionPolygon2DEditor::forward_input_event(const InputEvent& p_event) {
+
+
+ if (!node)
+ return false;
+
+ switch(p_event.type) {
+
+ case InputEvent::MOUSE_BUTTON: {
+
+ const InputEventMouseButton &mb=p_event.mouse_button;
+
+ Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+
+ Vector2 gpoint = Point2(mb.x,mb.y);
+ Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint=canvas_item_editor->snap_point(cpoint);
+ cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
+
+ Vector<Vector2> poly = node->get_polygon();
+
+ //first check if a point is to be added (segment split)
+ real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);
+
+ switch(mode) {
+
+
+ case MODE_CREATE: {
+
+ if (mb.button_index==BUTTON_LEFT && mb.pressed) {
+
+
+ if (!wip_active) {
+
+ wip.clear();
+ wip.push_back( cpoint );
+ wip_active=true;
+ edited_point_pos=cpoint;
+ canvas_item_editor->get_viewport_control()->update();
+ edited_point=1;
+ return true;
+ } else {
+
+
+ if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
+ //wip closed
+ _wip_close();
+
+ return true;
+ } else {
+
+ wip.push_back( cpoint );
+ edited_point=wip.size();
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+
+ //add wip point
+ }
+ }
+ } else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) {
+ _wip_close();
+ }
+
+
+
+ } break;
+
+ case MODE_EDIT: {
+
+ if (mb.button_index==BUTTON_LEFT) {
+ if (mb.pressed) {
+
+ if (mb.mod.control) {
+
+
+ if (poly.size() < 3) {
+
+ undo_redo->create_action("Edit Poly");
+ undo_redo->add_undo_method(node,"set_polygon",poly);
+ poly.push_back(cpoint);
+ undo_redo->add_do_method(node,"set_polygon",poly);
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ return true;
+ }
+
+ //search edges
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+ for(int i=0;i<poly.size();i++) {
+
+ Vector2 points[2] ={ xform.xform(poly[i]),
+ xform.xform(poly[(i+1)%poly.size()]) };
+
+ Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
+ if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2)
+ continue; //not valid to reuse point
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_idx=i;
+ }
+
+
+ }
+
+ if (closest_idx>=0) {
+
+ pre_move_edit=poly;
+ poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos));
+ edited_point=closest_idx+1;
+ edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ node->set_polygon(poly);
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ } else {
+
+ //look for points to move
+
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+ for(int i=0;i<poly.size();i++) {
+
+ Vector2 cp =xform.xform(poly[i]);
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_idx=i;
+ }
+
+ }
+
+ if (closest_idx>=0) {
+
+ pre_move_edit=poly;
+ edited_point=closest_idx;
+ edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ }
+ } else {
+
+ if (edited_point!=-1) {
+
+ //apply
+
+ ERR_FAIL_INDEX_V(edited_point,poly.size(),false);
+ poly[edited_point]=edited_point_pos;
+ undo_redo->create_action("Edit Poly");
+ undo_redo->add_do_method(node,"set_polygon",poly);
+ undo_redo->add_undo_method(node,"set_polygon",pre_move_edit);
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+
+ edited_point=-1;
+ return true;
+ }
+ }
+ } if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) {
+
+
+
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+ for(int i=0;i<poly.size();i++) {
+
+ Vector2 cp =xform.xform(poly[i]);
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_idx=i;
+ }
+
+ }
+
+ if (closest_idx>=0) {
+
+
+ undo_redo->create_action("Edit Poly (Remove Point)");
+ undo_redo->add_undo_method(node,"set_polygon",poly);
+ poly.remove(closest_idx);
+ undo_redo->add_do_method(node,"set_polygon",poly);
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ return true;
+ }
+
+ }
+
+
+
+ } break;
+ }
+
+
+
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+ const InputEventMouseMotion &mm=p_event.mouse_motion;
+
+ if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {
+
+ Vector2 gpoint = Point2(mm.x,mm.y);
+ Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint=canvas_item_editor->snap_point(cpoint);
+ edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
+
+ canvas_item_editor->get_viewport_control()->update();
+
+ }
+
+ } break;
+ }
+
+ return false;
+}
+void CollisionPolygon2DEditor::_canvas_draw() {
+
+ if (!node)
+ return;
+
+ Control *vpc = canvas_item_editor->get_viewport_control();
+
+ Vector<Vector2> poly;
+
+ if (wip_active)
+ poly=wip;
+ else
+ poly=node->get_polygon();
+
+
+ Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+ Ref<Texture> handle= get_icon("EditorHandle","EditorIcons");
+
+ int len = poly.size();
+
+ for(int i=0;i<poly.size();i++) {
+
+
+ Vector2 p,p2;
+ p = i==edited_point ? edited_point_pos : poly[i];
+ if ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point))
+ p2=edited_point_pos;
+ else
+ p2 = poly[(i+1)%poly.size()];
+
+ Vector2 point = xform.xform(p);
+ Vector2 next_point = xform.xform(p2);
+
+ Color col=Color(1,0.3,0.1,0.8);
+ vpc->draw_line(point,next_point,col,2);
+ vpc->draw_texture(handle,point-handle->get_size()*0.5);
+ }
+}
+
+
+
+void CollisionPolygon2DEditor::edit(Node *p_collision_polygon) {
+
+ if (!canvas_item_editor) {
+ canvas_item_editor=CanvasItemEditor::get_singleton();
+ }
+
+ if (p_collision_polygon) {
+
+ node=p_collision_polygon->cast_to<CollisionPolygon2D>();
+ if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+ canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw");
+ wip.clear();
+ wip_active=false;
+ edited_point=-1;
+ canvas_item_editor->get_viewport_control()->update();
+
+ } else {
+ node=NULL;
+
+ if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+ canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw");
+
+ }
+
+}
+
+void CollisionPolygon2DEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_menu_option"),&CollisionPolygon2DEditor::_menu_option);
+ ObjectTypeDB::bind_method(_MD("_canvas_draw"),&CollisionPolygon2DEditor::_canvas_draw);
+ ObjectTypeDB::bind_method(_MD("_node_removed"),&CollisionPolygon2DEditor::_node_removed);
+
+}
+
+CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) {
+
+ node=NULL;
+ canvas_item_editor=NULL;
+ editor=p_editor;
+ undo_redo = editor->get_undo_redo();
+
+ add_child( memnew( VSeparator ));
+ button_create = memnew( ToolButton );
+ add_child(button_create);
+ button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE));
+ button_create->set_toggle_mode(true);
+ button_create->set_tooltip("Create a new polygon from scratch");
+
+ button_edit = memnew( ToolButton );
+ add_child(button_edit);
+ button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT));
+ button_edit->set_toggle_mode(true);
+ button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point.");
+
+ //add_constant_override("separation",0);
+
+#if 0
+ options = memnew( MenuButton );
+ add_child(options);
+ options->set_area_as_parent_rect();
+ options->set_text("Polygon");
+ //options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE);
+ options->get_popup()->connect("item_pressed", this,"_menu_option");
+#endif
+
+ mode = MODE_EDIT;
+ wip_active=false;
+
+}
+
+
+void CollisionPolygon2DEditorPlugin::edit(Object *p_object) {
+
+ collision_polygon_editor->edit(p_object->cast_to<Node>());
+}
+
+bool CollisionPolygon2DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_type("CollisionPolygon2D");
+}
+
+void CollisionPolygon2DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ collision_polygon_editor->show();
+ } else {
+
+ collision_polygon_editor->hide();
+ collision_polygon_editor->edit(NULL);
+ }
+
+}
+
+CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) {
+
+ editor=p_node;
+ collision_polygon_editor = memnew( CollisionPolygon2DEditor(p_node) );
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+
+ collision_polygon_editor->hide();
+
+
+
+}
+
+
+CollisionPolygon2DEditorPlugin::~CollisionPolygon2DEditorPlugin()
+{
+}
+
diff --git a/tools/editor/plugins/collision_polygon_2d_editor_plugin.h b/tools/editor/plugins/collision_polygon_2d_editor_plugin.h
new file mode 100644
index 0000000000..f34405b355
--- /dev/null
+++ b/tools/editor/plugins/collision_polygon_2d_editor_plugin.h
@@ -0,0 +1,83 @@
+#ifndef COLLISION_POLYGON_2D_EDITOR_PLUGIN_H
+#define COLLISION_POLYGON_2D_EDITOR_PLUGIN_H
+
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/2d/collision_polygon_2d.h"
+#include "scene/gui/tool_button.h"
+#include "scene/gui/button_group.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class CanvasItemEditor;
+
+class CollisionPolygon2DEditor : public HBoxContainer {
+
+ OBJ_TYPE(CollisionPolygon2DEditor, HBoxContainer );
+
+ UndoRedo *undo_redo;
+ enum Mode {
+
+ MODE_CREATE,
+ MODE_EDIT,
+
+ };
+
+ Mode mode;
+
+ ToolButton *button_create;
+ ToolButton *button_edit;
+
+ CanvasItemEditor *canvas_item_editor;
+ EditorNode *editor;
+ Panel *panel;
+ CollisionPolygon2D *node;
+ MenuButton *options;
+
+ int edited_point;
+ Vector2 edited_point_pos;
+ Vector<Vector2> pre_move_edit;
+ Vector<Vector2> wip;
+ bool wip_active;
+
+
+ void _wip_close();
+ void _canvas_draw();
+ void _menu_option(int p_option);
+
+protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+public:
+
+ bool forward_input_event(const InputEvent& p_event);
+ void edit(Node *p_collision_polygon);
+ CollisionPolygon2DEditor(EditorNode *p_editor);
+};
+
+class CollisionPolygon2DEditorPlugin : public EditorPlugin {
+
+ OBJ_TYPE( CollisionPolygon2DEditorPlugin, EditorPlugin );
+
+ CollisionPolygon2DEditor *collision_polygon_editor;
+ EditorNode *editor;
+
+public:
+
+ virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); }
+
+ virtual String get_name() const { return "CollisionPolygon2D"; }
+ 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);
+
+ CollisionPolygon2DEditorPlugin(EditorNode *p_node);
+ ~CollisionPolygon2DEditorPlugin();
+
+};
+
+#endif // COLLISION_POLYGON_2D_EDITOR_PLUGIN_H
diff --git a/tools/editor/plugins/collision_polygon_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_editor_plugin.cpp
index 93ad918b0e..60683f4eda 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -27,9 +27,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_polygon_editor_plugin.h"
-#include "canvas_item_editor_plugin.h"
+#include "spatial_editor_plugin.h"
#include "os/file_access.h"
#include "tools/editor/editor_settings.h"
+#include "scene/3d/camera.h"
+#include "canvas_item_editor_plugin.h"
void CollisionPolygonEditor::_notification(int p_what) {
@@ -40,11 +42,16 @@ void CollisionPolygonEditor::_notification(int p_what) {
button_create->set_icon( get_icon("Edit","EditorIcons"));
button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
button_edit->set_pressed(true);
+ get_tree()->connect("node_removed",this,"_node_removed");
} break;
- case NOTIFICATION_FIXED_PROCESS: {
+ case NOTIFICATION_PROCESS: {
+ if (node->get_depth() != prev_depth) {
+ _polygon_draw();
+ prev_depth=node->get_depth();
+ }
} break;
}
@@ -54,23 +61,15 @@ void CollisionPolygonEditor::_node_removed(Node *p_node) {
if(p_node==node) {
node=NULL;
+ if (imgeom->get_parent()==p_node)
+ p_node->remove_child(imgeom);
hide();
+ set_process(false);
}
}
-Vector2 CollisionPolygonEditor::snap_point(const Vector2& p_point) const {
-
- if (canvas_item_editor->is_snap_active()) {
-
- return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap());
-
- } else {
- return p_point;
- }
-}
-
void CollisionPolygonEditor::_menu_option(int p_option) {
switch(p_option) {
@@ -93,21 +92,31 @@ void CollisionPolygonEditor::_menu_option(int p_option) {
void CollisionPolygonEditor::_wip_close() {
- undo_redo->create_action("Create Poly");
+ undo_redo->create_action("Create Poly3D");
undo_redo->add_undo_method(node,"set_polygon",node->get_polygon());
undo_redo->add_do_method(node,"set_polygon",wip);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
- undo_redo->commit_action();
+ undo_redo->add_do_method(this,"_polygon_draw");
+ undo_redo->add_undo_method(this,"_polygon_draw");
wip.clear();
wip_active=false;
mode=MODE_EDIT;
button_edit->set_pressed(true);
button_create->set_pressed(false);
edited_point=-1;
+ undo_redo->commit_action();
+
}
-bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
+bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) {
+
+ if (!node)
+ 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);
switch(p_event.type) {
@@ -116,13 +125,22 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
const InputEventMouseButton &mb=p_event.mouse_button;
- Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- Vector2 gpoint = Point2(mb.x,mb.y);
- Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
- cpoint=snap_point(cpoint);
- cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
+ Vector2 gpoint=Point2(mb.x,mb.y);
+ Vector3 ray_from = p_camera->project_ray_origin(gpoint);
+ Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
+
+ Vector3 spoint;
+
+ 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);
Vector<Vector2> poly = node->get_polygon();
@@ -143,13 +161,13 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
wip.push_back( cpoint );
wip_active=true;
edited_point_pos=cpoint;
- canvas_item_editor->get_viewport_control()->update();
+ _polygon_draw();
edited_point=1;
return true;
} else {
- if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
+ if (wip.size()>1 && p_camera->unproject_position(gt.xform(Vector3(wip[0].x,wip[0].y,depth))).distance_to(gpoint)<grab_treshold) {
//wip closed
_wip_close();
@@ -158,7 +176,7 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
wip.push_back( cpoint );
edited_point=wip.size();
- canvas_item_editor->get_viewport_control()->update();
+ _polygon_draw();
return true;
//add wip point
@@ -186,8 +204,8 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
undo_redo->add_undo_method(node,"set_polygon",poly);
poly.push_back(cpoint);
undo_redo->add_do_method(node,"set_polygon",poly);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_do_method(this,"_polygon_draw");
+ undo_redo->add_undo_method(this,"_polygon_draw");
undo_redo->commit_action();
return true;
}
@@ -198,8 +216,10 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
real_t closest_dist=1e10;
for(int i=0;i<poly.size();i++) {
- Vector2 points[2] ={ xform.xform(poly[i]),
- xform.xform(poly[(i+1)%poly.size()]) };
+ Vector2 points[2] ={
+ p_camera->unproject_position(gt.xform(Vector3(poly[i].x,poly[i].y,depth))),
+ p_camera->unproject_position(gt.xform(Vector3(poly[(i+1)%poly.size()].x,poly[(i+1)%poly.size()].y,depth)))
+ };
Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2)
@@ -218,11 +238,11 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
if (closest_idx>=0) {
pre_move_edit=poly;
- poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos));
+ poly.insert(closest_idx+1,cpoint);
edited_point=closest_idx+1;
- edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ edited_point_pos=cpoint;
node->set_polygon(poly);
- canvas_item_editor->get_viewport_control()->update();
+ _polygon_draw();
return true;
}
} else {
@@ -234,7 +254,7 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
real_t closest_dist=1e10;
for(int i=0;i<poly.size();i++) {
- Vector2 cp =xform.xform(poly[i]);
+ Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x,poly[i].y,depth)));
real_t d = cp.distance_to(gpoint);
if (d<closest_dist && d<grab_treshold) {
@@ -249,8 +269,8 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
pre_move_edit=poly;
edited_point=closest_idx;
- edited_point_pos=xform.affine_inverse().xform(closest_pos);
- canvas_item_editor->get_viewport_control()->update();
+ edited_point_pos=poly[closest_idx];
+ _polygon_draw();
return true;
}
}
@@ -265,8 +285,8 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
undo_redo->create_action("Edit Poly");
undo_redo->add_do_method(node,"set_polygon",poly);
undo_redo->add_undo_method(node,"set_polygon",pre_move_edit);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_do_method(this,"_polygon_draw");
+ undo_redo->add_undo_method(this,"_polygon_draw");
undo_redo->commit_action();
edited_point=-1;
@@ -282,7 +302,7 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
real_t closest_dist=1e10;
for(int i=0;i<poly.size();i++) {
- Vector2 cp =xform.xform(poly[i]);
+ Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x,poly[i].y,depth)));
real_t d = cp.distance_to(gpoint);
if (d<closest_dist && d<grab_treshold) {
@@ -300,8 +320,8 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
undo_redo->add_undo_method(node,"set_polygon",poly);
poly.remove(closest_idx);
undo_redo->add_do_method(node,"set_polygon",poly);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_do_method(this,"_polygon_draw");
+ undo_redo->add_undo_method(this,"_polygon_draw");
undo_redo->commit_action();
return true;
}
@@ -323,11 +343,23 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {
Vector2 gpoint = Point2(mm.x,mm.y);
- Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
- cpoint=snap_point(cpoint);
- edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
- canvas_item_editor->get_viewport_control()->update();
+ Vector3 ray_from = p_camera->project_ray_origin(gpoint);
+ Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
+
+ Vector3 spoint;
+
+ 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);
+ edited_point_pos = cpoint;
+
+ _polygon_draw();
}
@@ -336,13 +368,11 @@ bool CollisionPolygonEditor::forward_input_event(const InputEvent& p_event) {
return false;
}
-void CollisionPolygonEditor::_canvas_draw() {
+void CollisionPolygonEditor::_polygon_draw() {
if (!node)
return;
- Control *vpc = canvas_item_editor->get_viewport_control();
-
Vector<Vector2> poly;
if (wip_active)
@@ -351,10 +381,16 @@ void CollisionPolygonEditor::_canvas_draw() {
poly=node->get_polygon();
- Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- Ref<Texture> handle= get_icon("EditorHandle","EditorIcons");
int len = poly.size();
+ float depth = node->get_depth()*0.5;
+
+ imgeom->clear();
+ imgeom->set_material_override(line_material);
+ imgeom->begin(Mesh::PRIMITIVE_LINES,Ref<Texture>());
+
+
+ Rect2 rect;
for(int i=0;i<poly.size();i++) {
@@ -366,38 +402,127 @@ void CollisionPolygonEditor::_canvas_draw() {
else
p2 = poly[(i+1)%poly.size()];
- Vector2 point = xform.xform(p);
- Vector2 next_point = xform.xform(p2);
+ if (i==0)
+ rect.pos=p;
+ else
+ rect.expand_to(p);
+
+ Vector3 point = Vector3(p.x,p.y,depth);
+ Vector3 next_point = Vector3(p2.x,p2.y,depth);
+
+ imgeom->set_color(Color(1,0.3,0.1,0.8));
+ imgeom->add_vertex(point);
+ imgeom->set_color(Color(1,0.3,0.1,0.8));
+ imgeom->add_vertex(next_point);
- Color col=Color(1,0.3,0.1,0.8);
- vpc->draw_line(point,next_point,col,2);
- vpc->draw_texture(handle,point-handle->get_size()*0.5);
+ //Color col=Color(1,0.3,0.1,0.8);
+ //vpc->draw_line(point,next_point,col,2);
+ //vpc->draw_texture(handle,point-handle->get_size()*0.5);
}
+
+ rect=rect.grow(1);
+
+ AABB r;
+ r.pos.x=rect.pos.x;
+ r.pos.y=rect.pos.y;
+ r.pos.z=depth;
+ r.size.x=rect.size.x;
+ r.size.y=rect.size.y;
+ r.size.z=0;
+
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos);
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(0.3,0,0));
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos);
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(0.0,0.3,0));
+
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(r.size.x,0,0));
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(r.size.x,0,0)-Vector3(0.3,0,0));
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(r.size.x,0,0));
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(r.size.x,0,0)+Vector3(0,0.3,0));
+
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(0,r.size.y,0));
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(0,r.size.y,0)-Vector3(0,0.3,0));
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(0,r.size.y,0));
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+Vector3(0,r.size.y,0)+Vector3(0.3,0,0));
+
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+r.size);
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+r.size-Vector3(0.3,0,0));
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+r.size);
+ imgeom->set_color(Color(0.8,0.8,0.8,0.2));
+ imgeom->add_vertex(r.pos+r.size-Vector3(0.0,0.3,0));
+
+ imgeom->end();
+
+
+ while(m->get_surface_count()) {
+ m->surface_remove(0);
+ }
+
+ if (poly.size()==0)
+ return;
+
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ DVector<Vector3> va;
+ {
+
+ va.resize(poly.size());
+ DVector<Vector3>::Write w=va.write();
+ for(int i=0;i<poly.size();i++) {
+
+
+ Vector2 p,p2;
+ p = i==edited_point ? edited_point_pos : poly[i];
+
+ Vector3 point = Vector3(p.x,p.y,depth);
+ w[i]=point;
+ }
+ }
+ a[Mesh::ARRAY_VERTEX]=va;
+ m->add_surface(Mesh::PRIMITIVE_POINTS,a);
+ m->surface_set_material(0,handle_material);
+
}
void CollisionPolygonEditor::edit(Node *p_collision_polygon) {
- if (!canvas_item_editor) {
- canvas_item_editor=CanvasItemEditor::get_singleton();
- }
+
if (p_collision_polygon) {
- node=p_collision_polygon->cast_to<CollisionPolygon2D>();
- 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=p_collision_polygon->cast_to<CollisionPolygon>();
wip.clear();
wip_active=false;
edited_point=-1;
+ p_collision_polygon->add_child(imgeom);
+ _polygon_draw();
+ set_process(true);
+ prev_depth=-1;
} else {
node=NULL;
- if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
- canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw");
+ if (imgeom->get_parent())
+ imgeom->get_parent()->remove_child(imgeom);
+ set_process(false);
}
}
@@ -405,13 +530,15 @@ void CollisionPolygonEditor::edit(Node *p_collision_polygon) {
void CollisionPolygonEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_menu_option"),&CollisionPolygonEditor::_menu_option);
- ObjectTypeDB::bind_method(_MD("_canvas_draw"),&CollisionPolygonEditor::_canvas_draw);
+ ObjectTypeDB::bind_method(_MD("_polygon_draw"),&CollisionPolygonEditor::_polygon_draw);
+ ObjectTypeDB::bind_method(_MD("_node_removed"),&CollisionPolygonEditor::_node_removed);
}
CollisionPolygonEditor::CollisionPolygonEditor(EditorNode *p_editor) {
- canvas_item_editor=NULL;
+
+ node=NULL;
editor=p_editor;
undo_redo = editor->get_undo_redo();
@@ -439,7 +566,42 @@ CollisionPolygonEditor::CollisionPolygonEditor(EditorNode *p_editor) {
mode = MODE_EDIT;
wip_active=false;
+ imgeom = memnew( ImmediateGeometry );
+ imgeom->set_transform(Transform(Matrix3(),Vector3(0,0,0.00001)));
+
+
+ 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,Color(1,1,1));
+
+
+
+
+ handle_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ handle_material->set_flag(Material::FLAG_UNSHADED, true);
+ handle_material->set_fixed_flag(FixedMaterial::FLAG_USE_POINT_SIZE, true);
+ handle_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1));
+ handle_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ handle_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
+ Ref<Texture> handle= SpatialEditor::get_singleton()->get_icon("Editor3DHandle","EditorIcons");
+ handle_material->set_point_size(handle->get_width());
+ handle_material->set_texture(FixedMaterial::PARAM_DIFFUSE,handle);
+
+ pointsm = memnew( MeshInstance );
+ imgeom->add_child(pointsm);
+ m = Ref<Mesh>( memnew( Mesh ) );
+ pointsm->set_mesh(m);
+ pointsm->set_transform(Transform(Matrix3(),Vector3(0,0,0.00001)));
+
+
+}
+
+CollisionPolygonEditor::~CollisionPolygonEditor() {
+ memdelete( imgeom );
}
@@ -450,7 +612,7 @@ void CollisionPolygonEditorPlugin::edit(Object *p_object) {
bool CollisionPolygonEditorPlugin::handles(Object *p_object) const {
- return p_object->is_type("CollisionPolygon2D");
+ return p_object->is_type("CollisionPolygon");
}
void CollisionPolygonEditorPlugin::make_visible(bool p_visible) {
@@ -469,7 +631,7 @@ CollisionPolygonEditorPlugin::CollisionPolygonEditorPlugin(EditorNode *p_node) {
editor=p_node;
collision_polygon_editor = memnew( CollisionPolygonEditor(p_node) );
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
collision_polygon_editor->hide();
diff --git a/tools/editor/plugins/collision_polygon_editor_plugin.h b/tools/editor/plugins/collision_polygon_editor_plugin.h
index a05ac0f8c8..20a0b3c3f6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,7 +31,9 @@
#include "tools/editor/editor_plugin.h"
#include "tools/editor/editor_node.h"
-#include "scene/2d/collision_polygon_2d.h"
+#include "scene/3d/collision_polygon.h"
+#include "scene/3d/immediate_geometry.h"
+#include "scene/3d/mesh_instance.h"
#include "scene/gui/tool_button.h"
#include "scene/gui/button_group.h"
@@ -57,10 +59,17 @@ class CollisionPolygonEditor : public HBoxContainer {
ToolButton *button_create;
ToolButton *button_edit;
- CanvasItemEditor *canvas_item_editor;
+
+ Ref<FixedMaterial> line_material;
+ Ref<FixedMaterial> handle_material;
+
EditorNode *editor;
Panel *panel;
- CollisionPolygon2D *node;
+ CollisionPolygon *node;
+ ImmediateGeometry *imgeom;
+ MeshInstance *pointsm;
+ Ref<Mesh> m;
+
MenuButton *options;
int edited_point;
@@ -69,9 +78,10 @@ class CollisionPolygonEditor : public HBoxContainer {
Vector<Vector2> wip;
bool wip_active;
+ float prev_depth;
void _wip_close();
- void _canvas_draw();
+ void _polygon_draw();
void _menu_option(int p_option);
protected:
@@ -80,10 +90,10 @@ protected:
static void _bind_methods();
public:
- Vector2 snap_point(const Vector2& p_point) const;
- bool forward_input_event(const InputEvent& p_event);
+ virtual bool forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event);
void edit(Node *p_collision_polygon);
CollisionPolygonEditor(EditorNode *p_editor);
+ ~CollisionPolygonEditor();
};
class CollisionPolygonEditorPlugin : public EditorPlugin {
@@ -95,7 +105,7 @@ class CollisionPolygonEditorPlugin : public EditorPlugin {
public:
- virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); }
+ virtual bool forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) { return collision_polygon_editor->forward_spatial_input_event(p_camera,p_event); }
virtual String get_name() const { return "CollisionPolygon"; }
bool has_main_screen() const { return false; }
diff --git a/tools/editor/plugins/collision_shape_2d_editor_plugin.cpp b/tools/editor/plugins/collision_shape_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..7e5d52d17d
--- /dev/null
+++ b/tools/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -0,0 +1,573 @@
+#include "collision_shape_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+
+#include "scene/resources/segment_shape_2d.h"
+#include "scene/resources/shape_line_2d.h"
+#include "scene/resources/circle_shape_2d.h"
+#include "scene/resources/rectangle_shape_2d.h"
+#include "scene/resources/capsule_shape_2d.h"
+#include "scene/resources/convex_polygon_shape_2d.h"
+#include "scene/resources/concave_polygon_shape_2d.h"
+
+Variant CollisionShape2DEditor::get_handle_value(int idx) const {
+
+ switch ( shape_type ) {
+ case CAPSULE_SHAPE: {
+ Ref<CapsuleShape2D> capsule = node->get_shape();
+
+ if (idx==0) {
+ return capsule->get_radius();
+ } else if (idx==1) {
+ return capsule->get_height();
+ }
+
+ } break;
+
+ case CIRCLE_SHAPE: {
+ Ref<CircleShape2D> circle = node->get_shape();
+
+ if (idx==0) {
+ return circle->get_radius();
+ }
+
+ } break;
+
+ case CONCAVE_POLYGON_SHAPE: {
+
+ } break;
+
+ case CONVEX_POLYGON_SHAPE: {
+
+ } break;
+
+ case LINE_SHAPE: {
+ Ref<LineShape2D> line = node->get_shape();
+
+ if (idx==0) {
+ return line->get_d();
+ } else {
+ return line->get_normal();
+ }
+
+ } break;
+
+ case RAY_SHAPE: {
+ Ref<RayShape2D> ray = node->get_shape();
+
+ if (idx==0) {
+ return ray->get_length();
+ }
+
+ } break;
+
+ case RECTANGLE_SHAPE: {
+ Ref<RectangleShape2D> rect = node->get_shape();
+
+ if (idx<2) {
+ return rect->get_extents().abs();
+ }
+
+ } break;
+
+ case SEGMENT_SHAPE: {
+ Ref<SegmentShape2D> seg = node->get_shape();
+
+ if (idx==0) {
+ return seg->get_a();
+ } else if (idx==1) {
+ return seg->get_b();
+ }
+
+ } break;
+ }
+
+ return Variant();
+}
+
+void CollisionShape2DEditor::set_handle(int idx, Point2& p_point) {
+
+ switch ( shape_type ) {
+ case CAPSULE_SHAPE: {
+ if (idx < 2) {
+ Ref<CapsuleShape2D> capsule = node->get_shape();
+
+ real_t parameter = Math::abs(p_point[idx]);
+
+ if (idx==0) {
+ capsule->set_radius(parameter);
+ } else if (idx==1){
+ capsule->set_height(parameter*2 - capsule->get_radius()*2);
+ }
+
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
+ } break;
+
+ case CIRCLE_SHAPE: {
+ Ref<CircleShape2D> circle = node->get_shape();
+ circle->set_radius(p_point.length());
+
+ canvas_item_editor->get_viewport_control()->update();
+
+ } break;
+
+ case CONCAVE_POLYGON_SHAPE: {
+
+ } break;
+
+ case CONVEX_POLYGON_SHAPE: {
+
+ } 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;
+
+ case RAY_SHAPE: {
+ Ref<RayShape2D> ray = node->get_shape();
+
+ ray->set_length(Math::abs(p_point.y));
+
+ canvas_item_editor->get_viewport_control()->update();
+
+ } break;
+
+ case RECTANGLE_SHAPE: {
+ if (idx<2) {
+ Ref<RectangleShape2D> rect = node->get_shape();
+
+ Vector2 extents = rect->get_extents();
+ extents[idx] = p_point[idx];
+
+ rect->set_extents(extents.abs());
+
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
+ } break;
+
+ case SEGMENT_SHAPE: {
+ if (edit_handle < 2) {
+ Ref<SegmentShape2D> seg = node->get_shape();
+
+ if (idx==0) {
+ seg->set_a(p_point);
+ } else if (idx==1) {
+ seg->set_b(p_point);
+ }
+
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
+ } break;
+ }
+}
+
+void CollisionShape2DEditor::commit_handle(int idx, Variant& p_org) {
+
+ Control* c = canvas_item_editor->get_viewport_control();
+ undo_redo->create_action("Set Handle");
+
+ switch ( shape_type ) {
+ case CAPSULE_SHAPE: {
+ Ref<CapsuleShape2D> capsule = node->get_shape();
+
+ if (idx==0) {
+ undo_redo->add_do_method(capsule.ptr(),"set_radius",capsule->get_radius());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(capsule.ptr(),"set_radius",p_org);
+ undo_redo->add_do_method(c,"update");
+ } else if (idx==1) {
+ undo_redo->add_do_method(capsule.ptr(),"set_height",capsule->get_height());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(capsule.ptr(),"set_height",p_org);
+ undo_redo->add_undo_method(c,"update");
+ }
+
+ } break;
+
+ case CIRCLE_SHAPE: {
+ Ref<CircleShape2D> circle = node->get_shape();
+
+ undo_redo->add_do_method(circle.ptr(),"set_radius",circle->get_radius());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(circle.ptr(),"set_radius",p_org);
+ undo_redo->add_undo_method(c,"update");
+
+ } break;
+
+ case CONCAVE_POLYGON_SHAPE: {
+
+ } break;
+
+ case CONVEX_POLYGON_SHAPE: {
+
+ } 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;
+
+ case RAY_SHAPE: {
+ Ref<RayShape2D> ray = node->get_shape();
+
+ undo_redo->add_do_method(ray.ptr(),"set_length",ray->get_length());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(ray.ptr(),"set_length",p_org);
+ undo_redo->add_undo_method(c,"update");
+
+ } break;
+
+ case RECTANGLE_SHAPE: {
+ Ref<RectangleShape2D> rect = node->get_shape();
+
+ undo_redo->add_do_method(rect.ptr(),"set_extents",rect->get_extents());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(rect.ptr(),"set_extents",p_org);
+ undo_redo->add_undo_method(c,"update");
+
+ } break;
+
+ case SEGMENT_SHAPE: {
+ Ref<SegmentShape2D> seg = node->get_shape();
+ if (idx==0) {
+ undo_redo->add_do_method(seg.ptr(),"set_a",seg->get_a());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(seg.ptr(),"set_a",p_org);
+ undo_redo->add_undo_method(c,"update");
+ } else if (idx==1) {
+ undo_redo->add_do_method(seg.ptr(),"set_b",seg->get_b());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(seg.ptr(),"set_b",p_org);
+ undo_redo->add_undo_method(c,"update");
+ }
+
+ } break;
+ }
+
+ undo_redo->commit_action();
+}
+
+bool CollisionShape2DEditor::forward_input_event(const InputEvent& p_event) {
+
+ if (!node) {
+ return false;
+ }
+
+ if (!node->get_shape().is_valid()) {
+ return false;
+ }
+
+ if (shape_type == -1) {
+ return false;
+ }
+
+ switch( p_event.type ) {
+ case InputEvent::MOUSE_BUTTON: {
+ const InputEventMouseButton& mb = p_event.mouse_button;
+
+ Matrix32 gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+ Point2 gpoint(mb.x,mb.y);
+
+ if (mb.button_index == BUTTON_LEFT) {
+ if (mb.pressed) {
+ for (int i = 0; i < handles.size(); i++) {
+ if (gt.xform(handles[i]).distance_to(gpoint) < 8) {
+ edit_handle = i;
+
+ break;
+ }
+ }
+
+ if (edit_handle==-1) {
+ pressed = false;
+
+ return false;
+ }
+
+ original = get_handle_value(edit_handle);
+ pressed = true;
+
+ return true;
+
+ } else {
+ if (pressed) {
+ commit_handle(edit_handle, original);
+
+ edit_handle = -1;
+ pressed = false;
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+
+ } break;
+
+ case InputEvent::MOUSE_MOTION: {
+ const InputEventMouseMotion& mm = p_event.mouse_motion;
+
+ if (edit_handle == -1 || !pressed) {
+ return false;
+ }
+
+ Point2 gpoint = Point2(mm.x,mm.y);
+ Point2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint = canvas_item_editor->snap_point(cpoint);
+ cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
+
+ set_handle(edit_handle, cpoint);
+
+ return true;
+
+ } break;
+ }
+
+ return false;
+}
+
+void CollisionShape2DEditor::_get_current_shape_type() {
+
+ if (!node) {
+ return;
+ }
+
+ Ref<Shape2D> s = node->get_shape();
+
+ if (!s.is_valid()) {
+ return;
+ }
+
+ if (s->cast_to<CapsuleShape2D>()) {
+ shape_type = CAPSULE_SHAPE;
+ } else if (s->cast_to<CircleShape2D>()) {
+ shape_type = CIRCLE_SHAPE;
+ } else if (s->cast_to<ConcavePolygonShape2D>()) {
+ shape_type = CONCAVE_POLYGON_SHAPE;
+ } else if (s->cast_to<ConvexPolygonShape2D>()) {
+ shape_type = CONVEX_POLYGON_SHAPE;
+ } else if (s->cast_to<LineShape2D>()) {
+ shape_type = LINE_SHAPE;
+ } else if (s->cast_to<RayShape2D>()) {
+ shape_type = RAY_SHAPE;
+ } else if (s->cast_to<RectangleShape2D>()) {
+ shape_type = RECTANGLE_SHAPE;
+ } else if (s->cast_to<SegmentShape2D>()) {
+ shape_type = SEGMENT_SHAPE;
+ } else {
+ shape_type = -1;
+ }
+
+ canvas_item_editor->get_viewport_control()->update();
+}
+
+void CollisionShape2DEditor::_canvas_draw() {
+
+ if (!node) {
+ return;
+ }
+
+ if (!node->get_shape().is_valid()) {
+ return;
+ }
+
+ _get_current_shape_type();
+
+ if (shape_type == -1) {
+ return;
+ }
+
+ Control *c = canvas_item_editor->get_viewport_control();
+ Matrix32 gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+ Ref<Texture> h = get_icon("EditorHandle","EditorIcons");
+ Vector2 size = h->get_size()*0.5;
+
+ handles.clear();
+
+ switch (shape_type) {
+ case CAPSULE_SHAPE: {
+ Ref<CapsuleShape2D> shape = node->get_shape();
+
+ handles.resize(2);
+ float radius = shape->get_radius();
+ float height = shape->get_height()/2;
+
+ handles[0] = Point2(radius, -height);
+ handles[1] = Point2(0,-(height + radius));
+
+ c->draw_texture(h, gt.xform(handles[0])-size);
+ c->draw_texture(h, gt.xform(handles[1])-size);
+
+ } break;
+
+ case CIRCLE_SHAPE: {
+ Ref<CircleShape2D> shape = node->get_shape();
+
+ handles.resize(1);
+ handles[0] = Point2(shape->get_radius(),0);
+
+ c->draw_texture(h, gt.xform(handles[0])-size);
+
+ } break;
+
+ case CONCAVE_POLYGON_SHAPE: {
+
+ } break;
+
+ case CONVEX_POLYGON_SHAPE: {
+
+ } 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;
+
+ case RAY_SHAPE: {
+ Ref<RayShape2D> shape = node->get_shape();
+
+ handles.resize(1);
+ handles[0] = Point2(0,shape->get_length());
+
+ c->draw_texture(h,gt.xform(handles[0])-size);
+
+ } break;
+
+ case RECTANGLE_SHAPE: {
+ Ref<RectangleShape2D> shape = node->get_shape();
+
+ handles.resize(2);
+ Vector2 ext = shape->get_extents();
+ handles[0] = Point2(ext.x,0);
+ handles[1] = Point2(0,-ext.y);
+
+ c->draw_texture(h,gt.xform(handles[0])-size);
+ c->draw_texture(h,gt.xform(handles[1])-size);
+
+ } break;
+
+ case SEGMENT_SHAPE: {
+ Ref<SegmentShape2D> shape = node->get_shape();
+
+ handles.resize(2);
+ handles[0] = shape->get_a();
+ handles[1] = shape->get_b();
+
+ c->draw_texture(h, gt.xform(handles[0])-size);
+ c->draw_texture(h, gt.xform(handles[1])-size);
+
+ } break;
+ }
+}
+
+void CollisionShape2DEditor::edit(Node* p_node) {
+
+ if (!canvas_item_editor) {
+ canvas_item_editor=CanvasItemEditor::get_singleton();
+ }
+
+ if (p_node) {
+ node=p_node->cast_to<CollisionShape2D>();
+
+ if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+ canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw");
+
+ _get_current_shape_type();
+
+ } else {
+ edit_handle = -1;
+ shape_type = -1;
+
+ if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+ canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw");
+
+ node=NULL;
+ }
+
+ canvas_item_editor->get_viewport_control()->update();
+}
+
+void CollisionShape2DEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_canvas_draw",&CollisionShape2DEditor::_canvas_draw);
+ ObjectTypeDB::bind_method("_get_current_shape_type",&CollisionShape2DEditor::_get_current_shape_type);
+}
+
+CollisionShape2DEditor::CollisionShape2DEditor(EditorNode* p_editor) {
+
+ node = NULL;
+ canvas_item_editor = NULL;
+ editor = p_editor;
+
+ undo_redo = p_editor->get_undo_redo();
+
+ edit_handle = -1;
+ pressed = false;
+}
+
+void CollisionShape2DEditorPlugin::edit(Object* p_obj) {
+
+ collision_shape_2d_editor->edit(p_obj->cast_to<Node>());
+}
+
+bool CollisionShape2DEditorPlugin::handles(Object* p_obj) const {
+
+ return p_obj->is_type("CollisionShape2D");
+}
+
+void CollisionShape2DEditorPlugin::make_visible(bool visible) {
+
+ if (!visible) {
+ edit(NULL);
+ }
+}
+
+CollisionShape2DEditorPlugin::CollisionShape2DEditorPlugin(EditorNode* p_node) {
+
+ editor=p_node;
+
+ collision_shape_2d_editor = memnew( CollisionShape2DEditor(p_node) );
+ p_node->get_gui_base()->add_child(collision_shape_2d_editor);
+}
+
+CollisionShape2DEditorPlugin::~CollisionShape2DEditorPlugin() {
+
+}
diff --git a/tools/editor/plugins/collision_shape_2d_editor_plugin.h b/tools/editor/plugins/collision_shape_2d_editor_plugin.h
new file mode 100644
index 0000000000..75e9b68ea7
--- /dev/null
+++ b/tools/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -0,0 +1,73 @@
+#ifndef COLLISION_SHAPE_2D_EDITOR_PLUGIN_H
+#define COLLISION_SHAPE_2D_EDITOR_PLUGIN_H
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+
+#include "scene/2d/collision_shape_2d.h"
+
+class CanvasItemEditor;
+
+class CollisionShape2DEditor : public Control {
+ OBJ_TYPE(CollisionShape2DEditor, Control);
+
+ enum ShapeType {
+ CAPSULE_SHAPE,
+ CIRCLE_SHAPE,
+ CONCAVE_POLYGON_SHAPE,
+ CONVEX_POLYGON_SHAPE,
+ LINE_SHAPE,
+ RAY_SHAPE,
+ RECTANGLE_SHAPE,
+ SEGMENT_SHAPE
+ };
+
+ EditorNode* editor;
+ UndoRedo* undo_redo;
+ CanvasItemEditor* canvas_item_editor;
+ CollisionShape2D* node;
+
+ Vector<Point2> handles;
+
+ int shape_type;
+ int edit_handle;
+ bool pressed;
+ Variant original;
+
+ Variant get_handle_value(int idx) const;
+ void set_handle(int idx, Point2& p_point);
+ void commit_handle(int idx, Variant& p_org);
+
+ void _get_current_shape_type();
+ void _canvas_draw();
+
+protected:
+ static void _bind_methods();
+
+public:
+ bool forward_input_event(const InputEvent& p_event);
+ void edit(Node* p_node);
+
+ CollisionShape2DEditor(EditorNode* p_editor);
+};
+
+class CollisionShape2DEditorPlugin : public EditorPlugin {
+ OBJ_TYPE(CollisionShape2DEditorPlugin, EditorPlugin);
+
+ CollisionShape2DEditor* collision_shape_2d_editor;
+ EditorNode* editor;
+
+public:
+ virtual bool forward_input_event(const InputEvent& p_event) { return collision_shape_2d_editor->forward_input_event(p_event); }
+
+ virtual String get_name() const { return "CollisionShape2D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object* p_obj);
+ virtual bool handles(Object* p_obj) const;
+ virtual void make_visible(bool visible);
+
+ CollisionShape2DEditorPlugin(EditorNode* p_editor);
+ ~CollisionShape2DEditorPlugin();
+};
+
+#endif //COLLISION_SHAPE_2D_EDITOR_PLUGIN_H
diff --git a/tools/editor/plugins/color_ramp_editor_plugin.cpp b/tools/editor/plugins/color_ramp_editor_plugin.cpp
new file mode 100644
index 0000000000..df50535402
--- /dev/null
+++ b/tools/editor/plugins/color_ramp_editor_plugin.cpp
@@ -0,0 +1,83 @@
+/*
+ * color_ramp_editor_plugin.cpp
+ */
+
+#include "color_ramp_editor_plugin.h"
+
+ColorRampEditorPlugin::ColorRampEditorPlugin(EditorNode *p_node) {
+
+ 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);
+ ramp_editor->set_custom_minimum_size(Size2(100, 48));
+ ramp_editor->hide();
+ ramp_editor->connect("ramp_changed", this, "ramp_changed");
+}
+
+void ColorRampEditorPlugin::edit(Object *p_object) {
+
+ ColorRamp* color_ramp = p_object->cast_to<ColorRamp>();
+ if (!color_ramp)
+ return;
+ color_ramp_ref = Ref<ColorRamp>(color_ramp);
+ ramp_editor->set_points(color_ramp_ref->get_points());
+}
+
+bool ColorRampEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_type("ColorRamp");
+}
+
+void ColorRampEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ ramp_editor->show();
+ } else {
+ ramp_editor->hide();
+ }
+
+}
+
+void ColorRampEditorPlugin::_ramp_changed() {
+
+ if(color_ramp_ref.is_valid())
+ {
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+
+ //Not sure if I should convert this data to DVector
+ Vector<float> new_offsets=ramp_editor->get_offsets();
+ Vector<Color> new_colors=ramp_editor->get_colors();
+ Vector<float> old_offsets=color_ramp_ref->get_offsets();
+ Vector<Color> old_colors=color_ramp_ref->get_colors();
+
+ if (old_offsets.size()!=new_offsets.size())
+ ur->create_action("Add/Remove Color Ramp Point");
+ else
+ ur->create_action("Modify Color Ramp",true);
+ ur->add_do_method(this,"undo_redo_color_ramp",new_offsets,new_colors);
+ ur->add_undo_method(this,"undo_redo_color_ramp",old_offsets,old_colors);
+ ur->commit_action();
+
+ //color_ramp_ref->set_points(ramp_editor->get_points());
+ }
+}
+
+void ColorRampEditorPlugin::_undo_redo_color_ramp(const Vector<float>& offsets,
+ const Vector<Color>& colors) {
+
+ color_ramp_ref->set_offsets(offsets);
+ color_ramp_ref->set_colors(colors);
+ ramp_editor->set_points(color_ramp_ref->get_points());
+ ramp_editor->update();
+}
+
+ColorRampEditorPlugin::~ColorRampEditorPlugin(){
+}
+
+void ColorRampEditorPlugin::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("ramp_changed"),&ColorRampEditorPlugin::_ramp_changed);
+ ObjectTypeDB::bind_method(_MD("undo_redo_color_ramp","offsets","colors"),&ColorRampEditorPlugin::_undo_redo_color_ramp);
+}
diff --git a/tools/editor/plugins/color_ramp_editor_plugin.h b/tools/editor/plugins/color_ramp_editor_plugin.h
new file mode 100644
index 0000000000..e39a5d65fe
--- /dev/null
+++ b/tools/editor/plugins/color_ramp_editor_plugin.h
@@ -0,0 +1,37 @@
+/*
+ * color_ramp_editor_plugin.h
+ */
+
+#ifndef TOOLS_EDITOR_PLUGINS_COLOR_RAMP_EDITOR_PLUGIN_H_
+#define TOOLS_EDITOR_PLUGINS_COLOR_RAMP_EDITOR_PLUGIN_H_
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/gui/color_ramp_edit.h"
+
+class ColorRampEditorPlugin : public EditorPlugin {
+
+ OBJ_TYPE( ColorRampEditorPlugin, EditorPlugin );
+
+ Ref<ColorRamp> color_ramp_ref;
+ ColorRampEdit *ramp_editor;
+ EditorNode *editor;
+
+protected:
+ static void _bind_methods();
+ void _ramp_changed();
+ void _undo_redo_color_ramp(const Vector<float>& offsets, const Vector<Color>& colors);
+
+public:
+ virtual String get_name() const { return "ColorRamp"; }
+ 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);
+
+ ColorRampEditorPlugin(EditorNode *p_node);
+ ~ColorRampEditorPlugin();
+
+};
+
+#endif /* TOOLS_EDITOR_PLUGINS_COLOR_RAMP_EDITOR_PLUGIN_H_ */
diff --git a/tools/editor/plugins/control_editor_plugin.cpp b/tools/editor/plugins/control_editor_plugin.cpp
index 8d8e107f41..7348a69665 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/control_editor_plugin.h b/tools/editor/plugins/control_editor_plugin.h
index a229327990..074298d0df 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/cube_grid_theme_editor_plugin.cpp b/tools/editor/plugins/cube_grid_theme_editor_plugin.cpp
index aad7cf2c6a..c118485083 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -269,8 +269,8 @@ void MeshLibraryEditor::_bind_methods() {
MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
- file = memnew( FileDialog );
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file = memnew( EditorFileDialog );
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
//not for now?
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions);
diff --git a/tools/editor/plugins/cube_grid_theme_editor_plugin.h b/tools/editor/plugins/cube_grid_theme_editor_plugin.h
index 0dab1d12b8..583ddf6e14 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -42,7 +42,7 @@ class MeshLibraryEditor : public Control {
EditorNode *editor;
MenuButton *menu;
ConfirmationDialog *cd;
- FileDialog *file;
+ EditorFileDialog *file;
int to_erase;
enum {
diff --git a/tools/editor/plugins/editor_preview_plugins.cpp b/tools/editor/plugins/editor_preview_plugins.cpp
new file mode 100644
index 0000000000..5f52d4c3e7
--- /dev/null
+++ b/tools/editor/plugins/editor_preview_plugins.cpp
@@ -0,0 +1,783 @@
+#include "editor_preview_plugins.h"
+#include "io/resource_loader.h"
+#include "tools/editor/editor_settings.h"
+#include "io/file_access_memory.h"
+#include "os/os.h"
+#include "scene/resources/material.h"
+#include "scene/resources/sample.h"
+#include "scene/resources/mesh.h"
+
+bool EditorTexturePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"ImageTexture");
+}
+
+Ref<Texture> EditorTexturePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<ImageTexture> tex =p_from;
+ Image img = tex->get_data();
+ if (img.empty())
+ return Ref<Texture>();
+
+ img.clear_mipmaps();
+
+ 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;
+
+}
+
+EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() {
+
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
+Ref<Texture> EditorPackedScenePreviewPlugin::_gen_from_imd(Ref<ResourceImportMetadata> p_imd) {
+
+ if (p_imd.is_null()) {
+ return Ref<Texture>();
+ }
+
+ if (!p_imd->has_option("thumbnail"))
+ return Ref<Texture>();
+
+ Variant tn = p_imd->get_option("thumbnail");
+ //print_line(Variant::get_type_name(tn.get_type()));
+ DVector<uint8_t> thumbnail = tn;
+
+ int len = thumbnail.size();
+ if (len==0)
+ return Ref<Texture>();
+
+
+ DVector<uint8_t>::Read r = thumbnail.read();
+
+ Image img(r.ptr(),len);
+ if (img.empty())
+ return Ref<Texture>();
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+bool EditorPackedScenePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"PackedScene");
+}
+Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<ResourceImportMetadata> imd = p_from->get_import_metadata();
+ return _gen_from_imd(imd);
+}
+
+Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String& p_path) {
+
+ Ref<ResourceImportMetadata> imd = ResourceLoader::load_import_metadata(p_path);
+ return _gen_from_imd(imd);
+}
+
+EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
+
+}
+
+//////////////////////////////////////////////////////////////////
+
+bool EditorMaterialPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Material"); //any material
+}
+
+Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES& p_from) {
+
+ Ref<Material> material = p_from;
+ ERR_FAIL_COND_V(material.is_null(),Ref<Texture>());
+
+ VS::get_singleton()->mesh_surface_set_material(sphere,0,material->get_rid());
+
+ VS::get_singleton()->viewport_queue_screen_capture(viewport);
+ VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_ONCE); //once used for capture
+// print_line("queue capture!");
+ Image img;
+
+ int timeout=1000;
+ while(timeout) {
+ //print_line("try capture?");
+ OS::get_singleton()->delay_usec(10);
+ img = VS::get_singleton()->viewport_get_screen_capture(viewport);
+ if (!img.empty())
+ break;
+ timeout--;
+ }
+
+ //print_line("captured!");
+ VS::get_singleton()->mesh_surface_set_material(sphere,0,RID());
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ img.resize(thumbnail_size,thumbnail_size);
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+ ptex->create_from_image(img,0);
+ return ptex;
+}
+
+EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
+
+ scenario = VS::get_singleton()->scenario_create();
+
+ viewport = VS::get_singleton()->viewport_create();
+ VS::get_singleton()->viewport_set_as_render_target(viewport,true);
+ VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_DISABLED);
+ VS::get_singleton()->viewport_set_scenario(viewport,scenario);
+ VS::ViewportRect vr;
+ vr.x=0;
+ vr.y=0;
+ vr.width=128;
+ vr.height=128;
+ VS::get_singleton()->viewport_set_rect(viewport,vr);
+
+ camera = VS::get_singleton()->camera_create();
+ VS::get_singleton()->viewport_attach_camera(viewport,camera);
+ VS::get_singleton()->camera_set_transform(camera,Transform(Matrix3(),Vector3(0,0,3)));
+ VS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
+
+ light = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
+ light_instance = VS::get_singleton()->instance_create2(light,scenario);
+ VS::get_singleton()->instance_set_transform(light_instance,Transform().looking_at(Vector3(-1,-1,-1),Vector3(0,1,0)));
+
+ light2 = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
+ VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_DIFFUSE,Color(0.7,0.7,0.7));
+ VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_SPECULAR,Color(0.0,0.0,0.0));
+ light_instance2 = VS::get_singleton()->instance_create2(light2,scenario);
+
+ VS::get_singleton()->instance_set_transform(light_instance2,Transform().looking_at(Vector3(0,1,0),Vector3(0,0,1)));
+
+ sphere = VS::get_singleton()->mesh_create();
+ sphere_instance = VS::get_singleton()->instance_create2(sphere,scenario);
+
+ int lats=32;
+ int lons=32;
+ float radius=1.0;
+
+ DVector<Vector3> vertices;
+ DVector<Vector3> normals;
+ DVector<Vector2> uvs;
+ DVector<float> tangents;
+ Matrix3 tt = Matrix3(Vector3(0,1,0),Math_PI*0.5);
+
+ for(int i = 1; i <= lats; i++) {
+ double lat0 = Math_PI * (-0.5 + (double) (i - 1) / lats);
+ double z0 = Math::sin(lat0);
+ double zr0 = Math::cos(lat0);
+
+ double lat1 = Math_PI * (-0.5 + (double) i / lats);
+ double z1 = Math::sin(lat1);
+ double zr1 = Math::cos(lat1);
+
+ for(int j = lons; j >= 1; j--) {
+
+ double lng0 = 2 * Math_PI * (double) (j - 1) / lons;
+ double x0 = Math::cos(lng0);
+ double y0 = Math::sin(lng0);
+
+ double lng1 = 2 * Math_PI * (double) (j) / lons;
+ double x1 = Math::cos(lng1);
+ double y1 = Math::sin(lng1);
+
+
+ Vector3 v[4]={
+ Vector3(x1 * zr0, z0, y1 *zr0),
+ Vector3(x1 * zr1, z1, y1 *zr1),
+ Vector3(x0 * zr1, z1, y0 *zr1),
+ Vector3(x0 * zr0, z0, y0 *zr0)
+ };
+
+#define ADD_POINT(m_idx) \
+ normals.push_back(v[m_idx]);\
+ vertices.push_back(v[m_idx]*radius);\
+ { Vector2 uv(Math::atan2(v[m_idx].x,v[m_idx].z),Math::atan2(-v[m_idx].y,v[m_idx].z));\
+ uv/=Math_PI;\
+ uv*=4.0;\
+ uv=uv*0.5+Vector2(0.5,0.5);\
+ uvs.push_back(uv);\
+ }\
+ { Vector3 t = tt.xform(v[m_idx]);\
+ tangents.push_back(t.x);\
+ tangents.push_back(t.y);\
+ tangents.push_back(t.z);\
+ tangents.push_back(1.0);\
+ }
+
+
+
+ ADD_POINT(0);
+ ADD_POINT(1);
+ ADD_POINT(2);
+
+ ADD_POINT(2);
+ ADD_POINT(3);
+ ADD_POINT(0);
+ }
+ }
+
+ Array arr;
+ arr.resize(VS::ARRAY_MAX);
+ arr[VS::ARRAY_VERTEX]=vertices;
+ arr[VS::ARRAY_NORMAL]=normals;
+ arr[VS::ARRAY_TANGENT]=tangents;
+ arr[VS::ARRAY_TEX_UV]=uvs;
+ VS::get_singleton()->mesh_add_surface(sphere,VS::PRIMITIVE_TRIANGLES,arr);
+
+}
+
+EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
+
+ VS::get_singleton()->free(sphere);
+ VS::get_singleton()->free(sphere_instance);
+ VS::get_singleton()->free(viewport);
+ VS::get_singleton()->free(light);
+ VS::get_singleton()->free(light_instance);
+ VS::get_singleton()->free(light2);
+ VS::get_singleton()->free(light_instance2);
+ VS::get_singleton()->free(camera);
+ VS::get_singleton()->free(scenario);
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static bool _is_text_char(CharType c) {
+
+ return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
+}
+
+bool EditorScriptPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Script");
+}
+
+Ref<Texture> EditorScriptPreviewPlugin::generate(const RES& p_from) {
+
+
+ Ref<Script> scr = p_from;
+ if (scr.is_null())
+ return Ref<Texture>();
+
+ String code = scr->get_source_code().strip_edges();
+ if (code=="")
+ return Ref<Texture>();
+
+ List<String> kwors;
+ scr->get_language()->get_reserved_words(&kwors);
+
+ Set<String> keywords;
+
+ for(List<String>::Element *E=kwors.front();E;E=E->next()) {
+
+ keywords.insert(E->get());
+
+ }
+
+
+ int line = 0;
+ int col=0;
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ Image img(thumbnail_size,thumbnail_size,0,Image::FORMAT_RGBA);
+
+
+
+ Color bg_color = EditorSettings::get_singleton()->get("text_editor/background_color");
+ bg_color.a=1.0;
+ Color keyword_color = EditorSettings::get_singleton()->get("text_editor/keyword_color");
+ Color text_color = EditorSettings::get_singleton()->get("text_editor/text_color");
+ Color symbol_color = EditorSettings::get_singleton()->get("text_editor/symbol_color");
+ Color comment_color = EditorSettings::get_singleton()->get("text_editor/comment_color");
+
+
+ for(int i=0;i<thumbnail_size;i++) {
+ for(int j=0;j<thumbnail_size;j++) {
+ img.put_pixel(i,j,bg_color);
+ }
+
+ }
+
+ bool prev_is_text=false;
+ bool in_keyword=false;
+ for(int i=0;i<code.length();i++) {
+
+ CharType c = code[i];
+ if (c>32) {
+ if (col<thumbnail_size) {
+ Color color = text_color;
+
+ if (c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t')) {
+ //make symbol a little visible
+ color=symbol_color;
+ in_keyword=false;
+ } else if (!prev_is_text && _is_text_char(c)) {
+ int pos = i;
+
+ while(_is_text_char(code[pos])) {
+ pos++;
+ }
+ ///print_line("from "+itos(i)+" to "+itos(pos));
+ String word = code.substr(i,pos-i);
+ //print_line("found word: "+word);
+ if (keywords.has(word))
+ in_keyword=true;
+
+ } else if (!_is_text_char(c)) {
+ in_keyword=false;
+ }
+
+ if (in_keyword)
+ color=keyword_color;
+
+ Color ul=color;
+ ul.a*=0.5;
+ img.put_pixel(col,line*2,bg_color.blend(ul));
+ img.put_pixel(col,line*2+1,color);
+
+ prev_is_text=_is_text_char(c);
+ }
+ } else {
+
+ prev_is_text=false;
+ in_keyword=false;
+
+ if (c=='\n') {
+ col=0;
+ line++;
+ if (line>=thumbnail_size/2)
+ break;
+ } else if (c=='\t') {
+ col+=3;
+ }
+ }
+ col++;
+ }
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture));
+
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+EditorScriptPreviewPlugin::EditorScriptPreviewPlugin() {
+
+
+}
+///////////////////////////////////////////////////////////////////
+
+bool EditorSamplePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Sample");
+}
+
+Ref<Texture> EditorSamplePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<Sample> smp =p_from;
+ ERR_FAIL_COND_V(smp.is_null(),Ref<Texture>());
+
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+
+ DVector<uint8_t> img;
+ int w = thumbnail_size;
+ int h = thumbnail_size;
+ img.resize(w*h*3);
+
+ DVector<uint8_t>::Write imgdata = img.write();
+ uint8_t * imgw = imgdata.ptr();
+ DVector<uint8_t> data = smp->get_data();
+ DVector<uint8_t>::Read sampledata = data.read();
+ const uint8_t *sdata=sampledata.ptr();
+
+ bool stereo = smp->is_stereo();
+ bool _16=smp->get_format()==Sample::FORMAT_PCM16;
+ int len = smp->get_length();
+
+ if (len<1)
+ return Ref<Texture>();
+
+ if (smp->get_format()==Sample::FORMAT_IMA_ADPCM) {
+
+ struct IMA_ADPCM_State {
+
+ int16_t step_index;
+ int32_t predictor;
+ /* values at loop point */
+ int16_t loop_step_index;
+ int32_t loop_predictor;
+ int32_t last_nibble;
+ int32_t loop_pos;
+ int32_t window_ofs;
+ const uint8_t *ptr;
+ } ima_adpcm;
+
+ ima_adpcm.step_index=0;
+ ima_adpcm.predictor=0;
+ ima_adpcm.loop_step_index=0;
+ ima_adpcm.loop_predictor=0;
+ ima_adpcm.last_nibble=-1;
+ ima_adpcm.loop_pos=0x7FFFFFFF;
+ ima_adpcm.window_ofs=0;
+ ima_adpcm.ptr=NULL;
+
+
+ for(int i=0;i<w;i++) {
+
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ for(int j=from;j<to;j++) {
+
+ while(j>ima_adpcm.last_nibble) {
+
+ static const int16_t _ima_adpcm_step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+ };
+
+ static const int8_t _ima_adpcm_index_table[16] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+ };
+
+ int16_t nibble,signed_nibble,diff,step;
+
+ 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[ofs]>>4):(src_ptr[ofs]&0xF);
+ step=_ima_adpcm_step_table[ima_adpcm.step_index];
+
+ ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
+ if (ima_adpcm.step_index<0)
+ ima_adpcm.step_index=0;
+ if (ima_adpcm.step_index>88)
+ ima_adpcm.step_index=88;
+
+ /*
+ 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 ;
+
+ ima_adpcm.predictor+=diff;
+ if (ima_adpcm.predictor<-0x8000)
+ ima_adpcm.predictor=-0x8000;
+ else if (ima_adpcm.predictor>0x7FFF)
+ ima_adpcm.predictor=0x7FFF;
+
+
+ /* store loop if there */
+ if (ima_adpcm.last_nibble==ima_adpcm.loop_pos) {
+
+ ima_adpcm.loop_step_index = ima_adpcm.step_index;
+ ima_adpcm.loop_predictor = ima_adpcm.predictor;
+ }
+
+ }
+
+ float v=ima_adpcm.predictor/32767.0;
+ if (v>max[0])
+ max[0]=v;
+ if (v<min[0])
+ min[0]=v;
+ }
+ max[0]*=0.8;
+ min[0]*=0.8;
+
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ }
+ } else {
+ for(int i=0;i<w;i++) {
+ // i trust gcc will optimize this loop
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int c=stereo?2:1;
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ if (_16) {
+ const int16_t*src =(const int16_t*)sdata;
+
+ for(int j=0;j<c;j++) {
+
+ for(int k=from;k<=to;k++) {
+
+ float v = src[k*c+j]/32768.0;
+ if (v>max[j])
+ max[j]=v;
+ if (v<min[j])
+ min[j]=v;
+ }
+
+ }
+ } else {
+
+ const int8_t*src =(const int8_t*)sdata;
+
+ for(int j=0;j<c;j++) {
+
+ for(int k=from;k<=to;k++) {
+
+ float v = src[k*c+j]/128.0;
+ if (v>max[j])
+ max[j]=v;
+ if (v<min[j])
+ min[j]=v;
+ }
+
+ }
+ }
+
+ max[0]*=0.8;
+ max[1]*=0.8;
+ min[0]*=0.8;
+ min[1]*=0.8;
+
+ if (!stereo) {
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ } else {
+
+ for(int j=0;j<h;j++) {
+
+ int half,ofs;
+ float v;
+ if (j<(h/2)) {
+ half=0;
+ ofs=0;
+ v = (j/(float)(h/2)) * 2.0 - 1.0;
+ } else {
+ half=1;
+ ofs=h/2;
+ v = ((j-(h/2))/(float)(h/2)) * 2.0 - 1.0;
+ }
+
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[half] && v<max[half]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+
+ }
+
+ }
+ }
+
+ imgdata = DVector<uint8_t>::Write();
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture));
+ ptex->create_from_image(Image(w,h,0,Image::FORMAT_RGB,img),0);
+ return ptex;
+
+}
+
+EditorSamplePreviewPlugin::EditorSamplePreviewPlugin() {
+
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+bool EditorMeshPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Mesh"); //any Mesh
+}
+
+Ref<Texture> EditorMeshPreviewPlugin::generate(const RES& p_from) {
+
+ Ref<Mesh> mesh = p_from;
+ ERR_FAIL_COND_V(mesh.is_null(),Ref<Texture>());
+
+ VS::get_singleton()->instance_set_base(mesh_instance,mesh->get_rid());
+
+ AABB aabb= mesh->get_aabb();
+ Vector3 ofs = aabb.pos + aabb.size*0.5;
+ aabb.pos-=ofs;
+ Transform xform;
+ xform.basis=Matrix3().rotated(Vector3(0,1,0),Math_PI*0.125);
+ xform.basis = Matrix3().rotated(Vector3(1,0,0),-Math_PI*0.125)*xform.basis;
+ AABB rot_aabb = xform.xform(aabb);
+ float m = MAX(rot_aabb.size.x,rot_aabb.size.y)*0.5;
+ if (m==0)
+ return Ref<Texture>();
+ m=1.0/m;
+ m*=0.5;
+ //print_line("scale: "+rtos(m));
+ xform.basis.scale(Vector3(m,m,m));
+ xform.origin=-xform.basis.xform(ofs); //-ofs*m;
+ xform.origin.z-=rot_aabb.size.z*2;
+ VS::get_singleton()->instance_set_transform(mesh_instance,xform);
+
+
+
+ VS::get_singleton()->viewport_queue_screen_capture(viewport);
+ VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_ONCE); //once used for capture
+// print_line("queue capture!");
+ Image img;
+
+ int timeout=1000;
+ while(timeout) {
+ //print_line("try capture?");
+ OS::get_singleton()->delay_usec(10);
+ img = VS::get_singleton()->viewport_get_screen_capture(viewport);
+ if (!img.empty())
+ break;
+ timeout--;
+ }
+
+ //print_line("captured!");
+ VS::get_singleton()->instance_set_base(mesh_instance,RID());
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ img.resize(thumbnail_size,thumbnail_size);
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+ ptex->create_from_image(img,0);
+ return ptex;
+}
+
+EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() {
+
+ scenario = VS::get_singleton()->scenario_create();
+ viewport = VS::get_singleton()->viewport_create();
+ VS::get_singleton()->viewport_set_as_render_target(viewport,true);
+ VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_DISABLED);
+ VS::get_singleton()->viewport_set_scenario(viewport,scenario);
+ VS::ViewportRect vr;
+ vr.x=0;
+ vr.y=0;
+ vr.width=128;
+ vr.height=128;
+ VS::get_singleton()->viewport_set_rect(viewport,vr);
+
+ camera = VS::get_singleton()->camera_create();
+ VS::get_singleton()->viewport_attach_camera(viewport,camera);
+ VS::get_singleton()->camera_set_transform(camera,Transform(Matrix3(),Vector3(0,0,3)));
+// VS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
+ VS::get_singleton()->camera_set_orthogonal(camera,1.0,0.01,1000.0);
+
+ light = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
+ light_instance = VS::get_singleton()->instance_create2(light,scenario);
+ VS::get_singleton()->instance_set_transform(light_instance,Transform().looking_at(Vector3(-1,-1,-1),Vector3(0,1,0)));
+
+ light2 = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
+ VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_DIFFUSE,Color(0.7,0.7,0.7));
+ VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_SPECULAR,Color(0.0,0.0,0.0));
+ light_instance2 = VS::get_singleton()->instance_create2(light2,scenario);
+
+ VS::get_singleton()->instance_set_transform(light_instance2,Transform().looking_at(Vector3(0,1,0),Vector3(0,0,1)));
+
+// sphere = VS::get_singleton()->mesh_create();
+ mesh_instance = VS::get_singleton()->instance_create();
+ VS::get_singleton()->instance_set_scenario(mesh_instance,scenario);
+
+
+
+}
+
+EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
+
+ //VS::get_singleton()->free(sphere);
+ VS::get_singleton()->free(mesh_instance);
+ VS::get_singleton()->free(viewport);
+ VS::get_singleton()->free(light);
+ VS::get_singleton()->free(light_instance);
+ VS::get_singleton()->free(light2);
+ VS::get_singleton()->free(light_instance2);
+ VS::get_singleton()->free(camera);
+ VS::get_singleton()->free(scenario);
+
+}
diff --git a/tools/editor/plugins/editor_preview_plugins.h b/tools/editor/plugins/editor_preview_plugins.h
new file mode 100644
index 0000000000..98071e2a0e
--- /dev/null
+++ b/tools/editor/plugins/editor_preview_plugins.h
@@ -0,0 +1,88 @@
+#ifndef EDITORPREVIEWPLUGINS_H
+#define EDITORPREVIEWPLUGINS_H
+
+#include "tools/editor/editor_resource_preview.h"
+
+class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorTexturePreviewPlugin();
+};
+
+
+class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
+
+ Ref<Texture> _gen_from_imd(Ref<ResourceImportMetadata> p_imd);
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+ virtual Ref<Texture> generate_from_path(const String& p_path);
+
+ EditorPackedScenePreviewPlugin();
+};
+
+class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
+
+ RID scenario;
+ RID sphere;
+ RID sphere_instance;
+ RID viewport;
+ RID light;
+ RID light_instance;
+ RID light2;
+ RID light_instance2;
+ RID camera;
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorMaterialPreviewPlugin();
+ ~EditorMaterialPreviewPlugin();
+};
+
+class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorScriptPreviewPlugin();
+};
+
+
+class EditorSamplePreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorSamplePreviewPlugin();
+};
+
+
+class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
+
+ RID scenario;
+ RID mesh_instance;
+ RID viewport;
+ RID light;
+ RID light_instance;
+ RID light2;
+ RID light_instance2;
+ RID camera;
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorMeshPreviewPlugin();
+ ~EditorMeshPreviewPlugin();
+};
+
+
+#endif // EDITORPREVIEWPLUGINS_H
diff --git a/tools/editor/plugins/item_list_editor_plugin.cpp b/tools/editor/plugins/item_list_editor_plugin.cpp
index a059470cec..9c53c73afd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,123 +89,193 @@ 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) {
- if (p_notification==NOTIFICATION_ENTER_SCENE) {
+ 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 {
+
for(int i=0;i<item_plugins.size();i++) {
if (item_plugins[i]->handles(p_object)) {
return true;
@@ -217,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>());
@@ -287,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 6b4d26fb45..b40a2c22f8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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/light_occluder_2d_editor_plugin.cpp b/tools/editor/plugins/light_occluder_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..757b5327dd
--- /dev/null
+++ b/tools/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -0,0 +1,492 @@
+#include "light_occluder_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "os/file_access.h"
+#include "tools/editor/editor_settings.h"
+
+void LightOccluder2DEditor::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_READY: {
+
+ button_create->set_icon( get_icon("Edit","EditorIcons"));
+ button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
+ button_edit->set_pressed(true);
+ get_tree()->connect("node_removed",this,"_node_removed");
+ create_poly->connect("confirmed",this,"_create_poly");
+
+ } break;
+ case NOTIFICATION_FIXED_PROCESS: {
+
+
+ } break;
+ }
+
+}
+void LightOccluder2DEditor::_node_removed(Node *p_node) {
+
+ if(p_node==node) {
+ node=NULL;
+ hide();
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
+}
+
+
+void LightOccluder2DEditor::_menu_option(int p_option) {
+
+ switch(p_option) {
+
+ case MODE_CREATE: {
+
+ mode=MODE_CREATE;
+ button_create->set_pressed(true);
+ button_edit->set_pressed(false);
+ } break;
+ case MODE_EDIT: {
+
+ mode=MODE_EDIT;
+ button_create->set_pressed(false);
+ button_edit->set_pressed(true);
+ } break;
+
+ }
+}
+
+void LightOccluder2DEditor::_wip_close(bool p_closed) {
+
+ undo_redo->create_action("Create Poly");
+ undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",node->get_occluder_polygon()->get_polygon());
+ undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",wip);
+ undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_closed",node->get_occluder_polygon()->is_closed());
+ undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_closed",p_closed);
+
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ wip.clear();
+ wip_active=false;
+ mode=MODE_EDIT;
+ button_edit->set_pressed(true);
+ button_create->set_pressed(false);
+ edited_point=-1;
+}
+
+bool LightOccluder2DEditor::forward_input_event(const InputEvent& p_event) {
+
+
+ if (!node)
+ return false;
+
+ if (node->get_occluder_polygon().is_null()) {
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
+ create_poly->set_text("No OccluderPolygon2D resource on this node.\nCreate and assign one?");
+ create_poly->popup_centered_minsize();
+ }
+ return (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1);
+ }
+ switch(p_event.type) {
+
+ case InputEvent::MOUSE_BUTTON: {
+
+ const InputEventMouseButton &mb=p_event.mouse_button;
+
+ Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+
+ Vector2 gpoint = Point2(mb.x,mb.y);
+ Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint=canvas_item_editor->snap_point(cpoint);
+ cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
+
+ Vector<Vector2> poly = Variant(node->get_occluder_polygon()->get_polygon());
+
+ //first check if a point is to be added (segment split)
+ real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);
+
+ switch(mode) {
+
+
+ case MODE_CREATE: {
+
+ if (mb.button_index==BUTTON_LEFT && mb.pressed) {
+
+
+ if (!wip_active) {
+
+ wip.clear();
+ wip.push_back( cpoint );
+ wip_active=true;
+ edited_point_pos=cpoint;
+ canvas_item_editor->get_viewport_control()->update();
+ edited_point=1;
+ return true;
+ } else {
+
+
+ if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
+ //wip closed
+ _wip_close(true);
+
+ return true;
+ } else if (wip.size()>1 && xform.xform(wip[wip.size()-1]).distance_to(gpoint)<grab_treshold) {
+ //wip closed
+ _wip_close(false);
+ return true;
+
+ } else {
+
+ wip.push_back( cpoint );
+ edited_point=wip.size();
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+
+ //add wip point
+ }
+ }
+ } else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) {
+ _wip_close(true);
+ }
+
+
+
+ } break;
+
+ case MODE_EDIT: {
+
+ if (mb.button_index==BUTTON_LEFT) {
+ if (mb.pressed) {
+
+ if (mb.mod.control) {
+
+
+ if (poly.size() < 3) {
+
+ undo_redo->create_action("Edit Poly");
+ undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+ poly.push_back(cpoint);
+ undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ return true;
+ }
+
+ //search edges
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+ for(int i=0;i<poly.size();i++) {
+
+ Vector2 points[2] ={ xform.xform(poly[i]),
+ xform.xform(poly[(i+1)%poly.size()]) };
+
+ Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
+ if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2)
+ continue; //not valid to reuse point
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_idx=i;
+ }
+
+
+ }
+
+ if (closest_idx>=0) {
+
+ pre_move_edit=poly;
+ poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos));
+ edited_point=closest_idx+1;
+ edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ node->get_occluder_polygon()->set_polygon(Variant(poly));
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ } else {
+
+ //look for points to move
+
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+ for(int i=0;i<poly.size();i++) {
+
+ Vector2 cp =xform.xform(poly[i]);
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_idx=i;
+ }
+
+ }
+
+ if (closest_idx>=0) {
+
+ pre_move_edit=poly;
+ edited_point=closest_idx;
+ edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ }
+ } else {
+
+ if (edited_point!=-1) {
+
+ //apply
+
+ ERR_FAIL_INDEX_V(edited_point,poly.size(),false);
+ poly[edited_point]=edited_point_pos;
+ undo_redo->create_action("Edit Poly");
+ undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+ undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",pre_move_edit);
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+
+ edited_point=-1;
+ return true;
+ }
+ }
+ } if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) {
+
+
+
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+ for(int i=0;i<poly.size();i++) {
+
+ Vector2 cp =xform.xform(poly[i]);
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_idx=i;
+ }
+
+ }
+
+ if (closest_idx>=0) {
+
+
+ undo_redo->create_action("Edit Poly (Remove Point)");
+ undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+ poly.remove(closest_idx);
+ undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ return true;
+ }
+
+ }
+
+
+
+ } break;
+ }
+
+
+
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+ const InputEventMouseMotion &mm=p_event.mouse_motion;
+
+ if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {
+
+ Vector2 gpoint = Point2(mm.x,mm.y);
+ Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint=canvas_item_editor->snap_point(cpoint);
+ edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
+
+ canvas_item_editor->get_viewport_control()->update();
+
+ }
+
+ } break;
+ }
+
+ return false;
+}
+void LightOccluder2DEditor::_canvas_draw() {
+
+ if (!node || !node->get_occluder_polygon().is_valid())
+ return;
+
+ Control *vpc = canvas_item_editor->get_viewport_control();
+
+ Vector<Vector2> poly;
+
+ if (wip_active)
+ poly=wip;
+ else
+ poly=Variant(node->get_occluder_polygon()->get_polygon());
+
+
+ Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+ Ref<Texture> handle= get_icon("EditorHandle","EditorIcons");
+
+ int len = poly.size();
+
+ for(int i=0;i<poly.size();i++) {
+
+
+ Vector2 p,p2;
+ p = i==edited_point ? edited_point_pos : poly[i];
+ if ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point))
+ p2=edited_point_pos;
+ else
+ p2 = poly[(i+1)%poly.size()];
+
+ Vector2 point = xform.xform(p);
+ Vector2 next_point = xform.xform(p2);
+
+ Color col=Color(1,0.3,0.1,0.8);
+
+ if (i==poly.size()-1 && (!node->get_occluder_polygon()->is_closed() || wip_active)) {
+
+ } else {
+ vpc->draw_line(point,next_point,col,2);
+ }
+ vpc->draw_texture(handle,point-handle->get_size()*0.5);
+ }
+}
+
+
+
+void LightOccluder2DEditor::edit(Node *p_collision_polygon) {
+
+ if (!canvas_item_editor) {
+ canvas_item_editor=CanvasItemEditor::get_singleton();
+ }
+
+ if (p_collision_polygon) {
+
+ node=p_collision_polygon->cast_to<LightOccluder2D>();
+ if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+ canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw");
+ wip.clear();
+ wip_active=false;
+ edited_point=-1;
+ canvas_item_editor->get_viewport_control()->update();
+ } else {
+ node=NULL;
+
+ if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+ canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw");
+
+ }
+
+}
+
+void LightOccluder2DEditor::_create_poly() {
+
+ if (!node)
+ return;
+ undo_redo->create_action("Create Occluder Polygon");
+ undo_redo->add_do_method(node,"set_occluder_polygon",Ref<OccluderPolygon2D>(memnew( OccluderPolygon2D)));
+ undo_redo->add_undo_method(node,"set_occluder_polygon",Variant(REF()));
+ undo_redo->commit_action();
+}
+
+void LightOccluder2DEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_menu_option"),&LightOccluder2DEditor::_menu_option);
+ ObjectTypeDB::bind_method(_MD("_canvas_draw"),&LightOccluder2DEditor::_canvas_draw);
+ ObjectTypeDB::bind_method(_MD("_node_removed"),&LightOccluder2DEditor::_node_removed);
+ ObjectTypeDB::bind_method(_MD("_create_poly"),&LightOccluder2DEditor::_create_poly);
+
+}
+
+
+LightOccluder2DEditor::LightOccluder2DEditor(EditorNode *p_editor) {
+
+ node=NULL;
+ canvas_item_editor=NULL;
+ editor=p_editor;
+ undo_redo = editor->get_undo_redo();
+
+ add_child( memnew( VSeparator ));
+ button_create = memnew( ToolButton );
+ add_child(button_create);
+ button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE));
+ button_create->set_toggle_mode(true);
+ button_create->set_tooltip("Create a new polygon from scratch");
+
+ button_edit = memnew( ToolButton );
+ add_child(button_edit);
+ button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT));
+ button_edit->set_toggle_mode(true);
+ button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point.");
+
+ create_poly = memnew( ConfirmationDialog );
+ add_child(create_poly);
+ create_poly->get_ok()->set_text("Create");
+
+
+ //add_constant_override("separation",0);
+
+#if 0
+ options = memnew( MenuButton );
+ add_child(options);
+ options->set_area_as_parent_rect();
+ options->set_text("Polygon");
+ //options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE);
+ options->get_popup()->connect("item_pressed", this,"_menu_option");
+#endif
+
+ mode = MODE_EDIT;
+ wip_active=false;
+
+}
+
+
+void LightOccluder2DEditorPlugin::edit(Object *p_object) {
+
+ collision_polygon_editor->edit(p_object->cast_to<Node>());
+}
+
+bool LightOccluder2DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_type("LightOccluder2D");
+}
+
+void LightOccluder2DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ collision_polygon_editor->show();
+ } else {
+
+ collision_polygon_editor->hide();
+ collision_polygon_editor->edit(NULL);
+ }
+
+}
+
+LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin(EditorNode *p_node) {
+
+ editor=p_node;
+ collision_polygon_editor = memnew( LightOccluder2DEditor(p_node) );
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+
+ collision_polygon_editor->hide();
+
+
+
+}
+
+
+LightOccluder2DEditorPlugin::~LightOccluder2DEditorPlugin()
+{
+}
+
diff --git a/tools/editor/plugins/light_occluder_2d_editor_plugin.h b/tools/editor/plugins/light_occluder_2d_editor_plugin.h
new file mode 100644
index 0000000000..5fb5631d05
--- /dev/null
+++ b/tools/editor/plugins/light_occluder_2d_editor_plugin.h
@@ -0,0 +1,87 @@
+#ifndef LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H
+#define LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H
+
+
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/2d/light_occluder_2d.h"
+#include "scene/gui/tool_button.h"
+#include "scene/gui/button_group.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class CanvasItemEditor;
+
+class LightOccluder2DEditor : public HBoxContainer {
+
+ OBJ_TYPE(LightOccluder2DEditor, HBoxContainer );
+
+ UndoRedo *undo_redo;
+ enum Mode {
+
+ MODE_CREATE,
+ MODE_EDIT,
+
+ };
+
+ Mode mode;
+
+ ToolButton *button_create;
+ ToolButton *button_edit;
+
+ CanvasItemEditor *canvas_item_editor;
+ EditorNode *editor;
+ Panel *panel;
+ LightOccluder2D *node;
+ MenuButton *options;
+
+ int edited_point;
+ Vector2 edited_point_pos;
+ Vector<Vector2> pre_move_edit;
+ Vector<Vector2> wip;
+ bool wip_active;
+
+ ConfirmationDialog *create_poly;
+
+ void _wip_close(bool p_closed);
+ void _canvas_draw();
+ void _menu_option(int p_option);
+ void _create_poly();
+
+protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+public:
+
+ Vector2 snap_point(const Vector2& p_point) const;
+ bool forward_input_event(const InputEvent& p_event);
+ void edit(Node *p_collision_polygon);
+ LightOccluder2DEditor(EditorNode *p_editor);
+};
+
+class LightOccluder2DEditorPlugin : public EditorPlugin {
+
+ OBJ_TYPE( LightOccluder2DEditorPlugin, EditorPlugin );
+
+ LightOccluder2DEditor *collision_polygon_editor;
+ EditorNode *editor;
+
+public:
+
+ virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); }
+
+ virtual String get_name() const { return "LightOccluder2D"; }
+ 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);
+
+ LightOccluder2DEditorPlugin(EditorNode *p_node);
+ ~LightOccluder2DEditorPlugin();
+
+};
+
+#endif // LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H
diff --git a/tools/editor/plugins/mesh_editor_plugin.cpp b/tools/editor/plugins/mesh_editor_plugin.cpp
new file mode 100644
index 0000000000..5314529a23
--- /dev/null
+++ b/tools/editor/plugins/mesh_editor_plugin.cpp
@@ -0,0 +1,300 @@
+#include "mesh_editor_plugin.h"
+
+#include "scene/3d/physics_body.h"
+#include "scene/3d/body_shape.h"
+#include "scene/gui/box_container.h"
+#include "scene/3d/navigation_mesh.h"
+#include "spatial_editor_plugin.h"
+
+void MeshInstanceEditor::_node_removed(Node *p_node) {
+
+ if(p_node==node) {
+ node=NULL;
+ options->hide();
+ }
+
+}
+
+
+
+void MeshInstanceEditor::edit(MeshInstance *p_mesh) {
+
+ node=p_mesh;
+
+}
+
+void MeshInstanceEditor::_menu_option(int p_option) {
+
+ Ref<Mesh> mesh = node->get_mesh();
+ if (mesh.is_null()) {
+ err_dialog->set_text("Mesh is empty!");
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ switch(p_option) {
+ case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY:
+ case MENU_OPTION_CREATE_STATIC_CONVEX_BODY: {
+
+ 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();
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if (selection.empty()) {
+ 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);
+ StaticBody *body = memnew( StaticBody );
+ body->add_child(cshape);
+
+ 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");
+
+ 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;
+ }
+
+ 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);
+ }
+
+ ur->commit_action();
+
+ } break;
+
+ 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;
+ }
+
+ 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();
+
+ 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);
+ ur->add_do_reference(cshape);
+ ur->add_undo_method(node->get_parent(),"remove_child",cshape);
+ ur->commit_action();
+
+ } break;
+
+ case MENU_OPTION_CREATE_NAVMESH: {
+
+ Ref<NavigationMesh> nmesh = memnew( NavigationMesh );
+
+ if (nmesh.is_null())
+ return;
+
+ nmesh->create_from_mesh(mesh);
+ NavigationMeshInstance *nmi = memnew( NavigationMeshInstance );
+ nmi->set_navigation_mesh(nmesh);
+
+ Node *owner = node==get_tree()->get_edited_scene_root() ? node : node->get_owner();
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Create Navigation Mesh");
+
+ ur->add_do_method(node,"add_child",nmi);
+ ur->add_do_method(nmi,"set_owner",owner);
+
+ ur->add_do_reference(nmi);
+ ur->add_undo_method(node,"remove_child",nmi);
+ ur->commit_action();
+ } break;
+
+ case MENU_OPTION_CREATE_OUTLINE_MESH: {
+
+ outline_dialog->popup_centered(Vector2(200, 90));
+ } break;
+ }
+
+}
+
+void MeshInstanceEditor::_create_outline_mesh() {
+
+ Ref<Mesh> mesh = node->get_mesh();
+ if (mesh.is_null()) {
+ err_dialog->set_text("MeshInstance lacks a Mesh!");
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ Ref<Mesh> mesho = mesh->create_outline(outline_size->get_val());
+
+ if (mesho.is_null()) {
+ err_dialog->set_text("Could not create outline!");
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ MeshInstance *mi = memnew( MeshInstance );
+ mi->set_mesh(mesho);
+ Node *owner=node->get_owner();
+ if (get_tree()->get_edited_scene_root()==node) {
+ owner=node;
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action("Create Outline");
+
+ ur->add_do_method(node,"add_child",mi);
+ ur->add_do_method(mi,"set_owner",owner);
+
+ ur->add_do_reference(mi);
+ ur->add_undo_method(node,"remove_child",mi);
+ ur->commit_action();
+}
+
+void MeshInstanceEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_menu_option",&MeshInstanceEditor::_menu_option);
+ ObjectTypeDB::bind_method("_create_outline_mesh",&MeshInstanceEditor::_create_outline_mesh);
+}
+
+MeshInstanceEditor::MeshInstanceEditor() {
+
+
+ options = memnew( MenuButton );
+ 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();
+ options->get_popup()->add_item("Create Trimesh Collision Sibling",MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
+ options->get_popup()->add_item("Create Convex Collision Sibling",MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE);
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item("Create Navigation Mesh",MENU_OPTION_CREATE_NAVMESH);
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item("Create Outline Mesh..",MENU_OPTION_CREATE_OUTLINE_MESH);
+
+ options->get_popup()->connect("item_pressed", this,"_menu_option");
+
+ outline_dialog = memnew( ConfirmationDialog );
+ 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_vbc->add_margin_child("Outline Size:",outline_size);
+
+ add_child(outline_dialog);
+ outline_dialog->connect("confirmed",this,"_create_outline_mesh");
+
+ err_dialog = memnew( AcceptDialog );
+ add_child(err_dialog);
+
+}
+
+
+void MeshInstanceEditorPlugin::edit(Object *p_object) {
+
+ mesh_editor->edit(p_object->cast_to<MeshInstance>());
+}
+
+bool MeshInstanceEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_type("MeshInstance");
+}
+
+void MeshInstanceEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ mesh_editor->options->show();
+ } else {
+
+ mesh_editor->options->hide();
+ mesh_editor->edit(NULL);
+ }
+
+}
+
+MeshInstanceEditorPlugin::MeshInstanceEditorPlugin(EditorNode *p_node) {
+
+ editor=p_node;
+ mesh_editor = memnew( MeshInstanceEditor );
+ editor->get_viewport()->add_child(mesh_editor);
+
+ mesh_editor->options->hide();
+}
+
+
+MeshInstanceEditorPlugin::~MeshInstanceEditorPlugin()
+{
+}
+
+
diff --git a/tools/editor/plugins/mesh_editor_plugin.h b/tools/editor/plugins/mesh_editor_plugin.h
new file mode 100644
index 0000000000..6b3e23f31f
--- /dev/null
+++ b/tools/editor/plugins/mesh_editor_plugin.h
@@ -0,0 +1,69 @@
+#ifndef MESH_EDITOR_PLUGIN_H
+#define MESH_EDITOR_PLUGIN_H
+
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/3d/mesh_instance.h"
+#include "scene/gui/spin_box.h"
+
+
+class MeshInstanceEditor : public Node {
+
+ OBJ_TYPE(MeshInstanceEditor, Node );
+
+
+ enum Menu {
+
+ MENU_OPTION_CREATE_STATIC_TRIMESH_BODY,
+ MENU_OPTION_CREATE_STATIC_CONVEX_BODY,
+ MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE,
+ MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE,
+ MENU_OPTION_CREATE_NAVMESH,
+ MENU_OPTION_CREATE_OUTLINE_MESH,
+ };
+
+ MeshInstance *node;
+
+ MenuButton *options;
+
+ ConfirmationDialog *outline_dialog;
+ SpinBox *outline_size;
+
+ AcceptDialog *err_dialog;
+
+ void _menu_option(int p_option);
+ void _create_outline_mesh();
+
+friend class MeshInstanceEditorPlugin;
+
+protected:
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+public:
+
+ void edit(MeshInstance *p_mesh);
+ MeshInstanceEditor();
+};
+
+class MeshInstanceEditorPlugin : public EditorPlugin {
+
+ OBJ_TYPE( MeshInstanceEditorPlugin, EditorPlugin );
+
+ MeshInstanceEditor *mesh_editor;
+ EditorNode *editor;
+
+public:
+
+ virtual String get_name() const { return "MeshInstance"; }
+ 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);
+
+ MeshInstanceEditorPlugin(EditorNode *p_node);
+ ~MeshInstanceEditorPlugin();
+
+};
+
+#endif // MESH_EDITOR_PLUGIN_H
diff --git a/tools/editor/plugins/multimesh_editor_plugin.cpp b/tools/editor/plugins/multimesh_editor_plugin.cpp
index b2b6cbe9b7..a5c823f8bd 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,8 +29,7 @@
#include "multimesh_editor_plugin.h"
#include "scene/gui/box_container.h"
#include "scene/3d/mesh_instance.h"
-
-
+#include "spatial_editor_plugin.h"
void MultiMeshEditor::_node_removed(Node *p_node) {
@@ -57,13 +56,13 @@ void MultiMeshEditor::_populate() {
if (multimesh.is_null()) {
err_dialog->set_text("No mesh source specified (and no MultiMesh set in node).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
if (multimesh->get_mesh().is_null()) {
err_dialog->set_text("No mesh source specified (and MultiMesh contains no Mesh).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -75,7 +74,7 @@ void MultiMeshEditor::_populate() {
if (!ms_node) {
err_dialog->set_text("Mesh source is invalid (Invalid Path).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -84,7 +83,7 @@ void MultiMeshEditor::_populate() {
if (!ms_instance) {
err_dialog->set_text("Mesh source is invalid (Not a MeshInstance).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -93,7 +92,7 @@ void MultiMeshEditor::_populate() {
if (mesh.is_null()) {
err_dialog->set_text("Mesh source is invalid (Contains no Mesh resource).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -102,7 +101,7 @@ void MultiMeshEditor::_populate() {
if (surface_source->get_text()=="") {
err_dialog->set_text("No surface source specified.");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -111,7 +110,7 @@ void MultiMeshEditor::_populate() {
if (!ss_node) {
err_dialog->set_text("Surface source is invalid (Invalid Path).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -120,7 +119,7 @@ void MultiMeshEditor::_populate() {
if (!ss_instance) {
err_dialog->set_text("Surface source is invalid (Not Geometry).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -131,7 +130,7 @@ void MultiMeshEditor::_populate() {
if (geometry.size()==0) {
err_dialog->set_text("Surface source is invalid (No Faces).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -290,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;
}
@@ -299,14 +298,14 @@ void MultiMeshEditor::_menu_option(int p_option) {
void MultiMeshEditor::edit(MultiMeshInstance *p_multimesh) {
- node=p_multimesh;
+ node=p_multimesh;
}
void MultiMeshEditor::_browse(bool p_source) {
browsing_source=p_source;
- std->get_tree()->set_marked(node,false);
+ std->get_scene_tree()->set_marked(node,false);
std->popup_centered_ratio();
if (p_source)
std->set_title("Select a Source Mesh:");
@@ -326,10 +325,11 @@ MultiMeshEditor::MultiMeshEditor() {
options = memnew( MenuButton );
- add_child(options);
- options->set_area_as_parent_rect();
-
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
+
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");
@@ -341,7 +341,6 @@ MultiMeshEditor::MultiMeshEditor() {
populate_dialog->add_child(vbc);
populate_dialog->set_child_rect(vbc);
-
HBoxContainer *hbc = memnew( HBoxContainer );
surface_source = memnew( LineEdit );
@@ -372,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);
@@ -415,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);
}
@@ -435,10 +433,10 @@ bool MultiMeshEditorPlugin::handles(Object *p_object) const {
void MultiMeshEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- multimesh_editor->show();
+ multimesh_editor->options->show();
} else {
- multimesh_editor->hide();
+ multimesh_editor->options->hide();
multimesh_editor->edit(NULL);
}
@@ -450,16 +448,7 @@ 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->hide();
+ multimesh_editor->options->hide();
}
diff --git a/tools/editor/plugins/multimesh_editor_plugin.h b/tools/editor/plugins/multimesh_editor_plugin.h
index a4d5f9bd30..edc3dfd55f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -42,14 +42,14 @@ class MultiMeshEditor : public Control {
OBJ_TYPE(MultiMeshEditor, Control );
+friend class MultiMeshEditorPlugin;
AcceptDialog *err_dialog;
-
+ MenuButton * options;
MultiMeshInstance *_last_pp_node;
bool browsing_source;
Panel *panel;
- MenuButton * options;
MultiMeshInstance *node;
LineEdit *surface_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/navigation_polygon_editor_plugin.cpp b/tools/editor/plugins/navigation_polygon_editor_plugin.cpp
new file mode 100644
index 0000000000..fa1f614413
--- /dev/null
+++ b/tools/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -0,0 +1,540 @@
+#include "navigation_polygon_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "os/file_access.h"
+#include "tools/editor/editor_settings.h"
+
+void NavigationPolygonEditor::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_READY: {
+
+ button_create->set_icon( get_icon("Edit","EditorIcons"));
+ button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
+ button_edit->set_pressed(true);
+ get_tree()->connect("node_removed",this,"_node_removed");
+ create_nav->connect("confirmed",this,"_create_nav");
+
+ } break;
+ case NOTIFICATION_FIXED_PROCESS: {
+
+
+ } break;
+ }
+
+}
+void NavigationPolygonEditor::_node_removed(Node *p_node) {
+
+ if(p_node==node) {
+ node=NULL;
+ hide();
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
+}
+
+void NavigationPolygonEditor::_create_nav() {
+
+ if (!node)
+ return;
+
+ undo_redo->create_action("Create Navigation Polygon");
+ undo_redo->add_do_method(node,"set_navigation_polygon",Ref<NavigationPolygon>(memnew( NavigationPolygon)));
+ undo_redo->add_undo_method(node,"set_navigation_polygon",Variant(REF()));
+ undo_redo->commit_action();
+}
+
+void NavigationPolygonEditor::_menu_option(int p_option) {
+
+ switch(p_option) {
+
+ case MODE_CREATE: {
+
+ mode=MODE_CREATE;
+ button_create->set_pressed(true);
+ button_edit->set_pressed(false);
+ } break;
+ case MODE_EDIT: {
+
+ mode=MODE_EDIT;
+ button_create->set_pressed(false);
+ button_edit->set_pressed(true);
+ } break;
+
+ }
+}
+
+void NavigationPolygonEditor::_wip_close() {
+
+
+ if (wip.size()>=3) {
+
+ undo_redo->create_action("Create Poly");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"remove_outline",node->get_navigation_polygon()->get_outline_count());
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"add_outline",wip);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ mode=MODE_EDIT;
+ button_edit->set_pressed(true);
+ button_create->set_pressed(false);
+ }
+
+ wip.clear();
+ wip_active=false;
+ edited_point=-1;
+}
+
+bool NavigationPolygonEditor::forward_input_event(const InputEvent& p_event) {
+
+
+ if (!node)
+ return false;
+
+ if (node->get_navigation_polygon().is_null()) {
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
+ create_nav->set_text("No NavigationPolygon resource on this node.\nCreate and assign one?");
+ create_nav->popup_centered_minsize();
+ }
+ return (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1);;
+ }
+
+
+ switch(p_event.type) {
+
+ case InputEvent::MOUSE_BUTTON: {
+
+ const InputEventMouseButton &mb=p_event.mouse_button;
+
+ Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+
+ Vector2 gpoint = Point2(mb.x,mb.y);
+ Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint=canvas_item_editor->snap_point(cpoint);
+ cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
+
+
+
+ //first check if a point is to be added (segment split)
+ real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);
+
+ switch(mode) {
+
+
+ case MODE_CREATE: {
+
+ if (mb.button_index==BUTTON_LEFT && mb.pressed) {
+
+
+ if (!wip_active) {
+
+ wip.clear();
+ wip.push_back( cpoint );
+ wip_active=true;
+ edited_point_pos=cpoint;
+ edited_outline=-1;
+ canvas_item_editor->get_viewport_control()->update();
+ edited_point=1;
+ return true;
+ } else {
+
+
+ if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
+ //wip closed
+ _wip_close();
+
+ return true;
+ } else {
+
+ wip.push_back( cpoint );
+ edited_point=wip.size();
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+
+ //add wip point
+ }
+ }
+ } else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) {
+ _wip_close();
+ }
+
+
+
+ } break;
+
+ case MODE_EDIT: {
+
+ if (mb.button_index==BUTTON_LEFT) {
+ if (mb.pressed) {
+
+ if (mb.mod.control) {
+
+
+ //search edges
+ int closest_outline=-1;
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+
+ for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
+
+
+ DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
+
+ int pc=points.size();
+ DVector<Vector2>::Read poly=points.read();
+
+ for(int i=0;i<pc;i++) {
+
+ Vector2 points[2] ={ xform.xform(poly[i]),
+ xform.xform(poly[(i+1)%pc]) };
+
+ Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
+ if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2)
+ continue; //not valid to reuse point
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_outline=j;
+ closest_pos=cp;
+ closest_idx=i;
+ }
+
+
+ }
+ }
+
+ if (closest_idx>=0) {
+
+ pre_move_edit=node->get_navigation_polygon()->get_outline(closest_outline);
+ DVector<Point2> poly = pre_move_edit;
+ poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos));
+ edited_point=closest_idx+1;
+ edited_outline=closest_outline;
+ edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ node->get_navigation_polygon()->set_outline(closest_outline,poly);
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ } else {
+
+ //look for points to move
+ int closest_outline=-1;
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+
+ for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
+
+
+ DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
+
+ int pc=points.size();
+ DVector<Vector2>::Read poly=points.read();
+
+ for(int i=0;i<pc;i++) {
+
+
+ Vector2 cp =xform.xform(poly[i]);
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_outline=j;
+ closest_idx=i;
+ }
+ }
+ }
+
+ if (closest_idx>=0) {
+
+ pre_move_edit=node->get_navigation_polygon()->get_outline(closest_outline);
+ edited_point=closest_idx;
+ edited_outline=closest_outline;
+ edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ }
+ } else {
+
+ if (edited_point!=-1) {
+
+ //apply
+
+ DVector<Vector2> poly = node->get_navigation_polygon()->get_outline(edited_outline);
+ ERR_FAIL_INDEX_V(edited_point,poly.size(),false);
+ poly.set(edited_point,edited_point_pos);
+ undo_redo->create_action("Edit Poly");
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"set_outline",edited_outline,poly);
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"set_outline",edited_outline,pre_move_edit);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+
+ edited_point=-1;
+ return true;
+ }
+ }
+ } if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) {
+
+ int closest_outline=-1;
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+
+ for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
+
+
+ DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
+
+ int pc=points.size();
+ DVector<Vector2>::Read poly=points.read();
+
+ for(int i=0;i<pc;i++) {
+
+
+ Vector2 cp =xform.xform(poly[i]);
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_outline=j;
+ closest_idx=i;
+ }
+ }
+ }
+
+ if (closest_idx>=0) {
+
+
+ DVector<Vector2> poly = node->get_navigation_polygon()->get_outline(closest_outline);
+
+ if (poly.size()>3) {
+ undo_redo->create_action("Edit Poly (Remove Point)");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"set_outline",closest_outline,poly);
+ poly.remove(closest_idx);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"set_outline",closest_outline,poly);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ } else {
+
+ undo_redo->create_action("Remove Poly And Point");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"add_outline_at_index",poly,closest_outline);
+ poly.remove(closest_idx);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"remove_outline",closest_outline);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+
+ }
+ return true;
+ }
+ }
+
+
+
+ } break;
+ }
+
+
+
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+ const InputEventMouseMotion &mm=p_event.mouse_motion;
+
+ if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {
+
+ Vector2 gpoint = Point2(mm.x,mm.y);
+ Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint=canvas_item_editor->snap_point(cpoint);
+ edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
+
+ canvas_item_editor->get_viewport_control()->update();
+
+ }
+
+ } break;
+ }
+
+ return false;
+}
+void NavigationPolygonEditor::_canvas_draw() {
+
+ if (!node)
+ return;
+
+ Control *vpc = canvas_item_editor->get_viewport_control();
+ if (node->get_navigation_polygon().is_null())
+ return;
+
+ Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+ Ref<Texture> handle= get_icon("EditorHandle","EditorIcons");
+
+
+
+ for(int j=-1;j<node->get_navigation_polygon()->get_outline_count();j++) {
+ Vector<Vector2> poly;
+
+ if (wip_active && j==edited_outline) {
+ poly=wip;
+ } else {
+ if (j==-1)
+ continue;
+ poly = Variant(node->get_navigation_polygon()->get_outline(j));
+ }
+
+ int len = poly.size();
+
+ for(int i=0;i<poly.size();i++) {
+
+
+ Vector2 p,p2;
+ p = (j==edited_outline && i==edited_point) ? edited_point_pos : poly[i];
+ if (j==edited_outline && ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point)))
+ p2=edited_point_pos;
+ else
+ p2 = poly[(i+1)%poly.size()];
+
+ Vector2 point = xform.xform(p);
+ Vector2 next_point = xform.xform(p2);
+
+ Color col=Color(1,0.3,0.1,0.8);
+ vpc->draw_line(point,next_point,col,2);
+ vpc->draw_texture(handle,point-handle->get_size()*0.5);
+ }
+ }
+}
+
+
+
+void NavigationPolygonEditor::edit(Node *p_collision_polygon) {
+
+ if (!canvas_item_editor) {
+ canvas_item_editor=CanvasItemEditor::get_singleton();
+ }
+
+ if (p_collision_polygon) {
+
+ node=p_collision_polygon->cast_to<NavigationPolygonInstance>();
+ if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+ canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw");
+ wip.clear();
+ wip_active=false;
+ edited_point=-1;
+ canvas_item_editor->get_viewport_control()->update();
+
+ } else {
+ node=NULL;
+
+ if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+ canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw");
+
+ }
+
+}
+
+void NavigationPolygonEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_menu_option"),&NavigationPolygonEditor::_menu_option);
+ ObjectTypeDB::bind_method(_MD("_canvas_draw"),&NavigationPolygonEditor::_canvas_draw);
+ ObjectTypeDB::bind_method(_MD("_node_removed"),&NavigationPolygonEditor::_node_removed);
+ ObjectTypeDB::bind_method(_MD("_create_nav"),&NavigationPolygonEditor::_create_nav);
+
+}
+
+NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) {
+ node=NULL;
+ canvas_item_editor=NULL;
+ editor=p_editor;
+ undo_redo = editor->get_undo_redo();
+
+ add_child( memnew( VSeparator ));
+ button_create = memnew( ToolButton );
+ add_child(button_create);
+ button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE));
+ button_create->set_toggle_mode(true);
+ button_create->set_tooltip("Create a new polygon from scratch");
+
+ button_edit = memnew( ToolButton );
+ add_child(button_edit);
+ button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT));
+ button_edit->set_toggle_mode(true);
+ button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point.");
+ create_nav = memnew( ConfirmationDialog );
+ add_child(create_nav);
+ create_nav->get_ok()->set_text("Create");
+
+
+ //add_constant_override("separation",0);
+
+#if 0
+ options = memnew( MenuButton );
+ add_child(options);
+ options->set_area_as_parent_rect();
+ options->set_text("Polygon");
+ //options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE);
+ options->get_popup()->connect("item_pressed", this,"_menu_option");
+#endif
+
+ mode = MODE_EDIT;
+ wip_active=false;
+ edited_outline=-1;
+
+}
+
+
+void NavigationPolygonEditorPlugin::edit(Object *p_object) {
+
+ collision_polygon_editor->edit(p_object->cast_to<Node>());
+}
+
+bool NavigationPolygonEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_type("NavigationPolygonInstance");
+}
+
+void NavigationPolygonEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ collision_polygon_editor->show();
+ } else {
+
+ collision_polygon_editor->hide();
+ collision_polygon_editor->edit(NULL);
+ }
+
+}
+
+NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) {
+
+ editor=p_node;
+ collision_polygon_editor = memnew( NavigationPolygonEditor(p_node) );
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+
+ collision_polygon_editor->hide();
+
+
+
+}
+
+
+NavigationPolygonEditorPlugin::~NavigationPolygonEditorPlugin()
+{
+}
+
diff --git a/tools/editor/plugins/navigation_polygon_editor_plugin.h b/tools/editor/plugins/navigation_polygon_editor_plugin.h
new file mode 100644
index 0000000000..f742cb011d
--- /dev/null
+++ b/tools/editor/plugins/navigation_polygon_editor_plugin.h
@@ -0,0 +1,90 @@
+#ifndef NAVIGATIONPOLYGONEDITORPLUGIN_H
+#define NAVIGATIONPOLYGONEDITORPLUGIN_H
+
+
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/2d/navigation_polygon.h"
+#include "scene/gui/tool_button.h"
+#include "scene/gui/button_group.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class CanvasItemEditor;
+
+class NavigationPolygonEditor : public HBoxContainer {
+
+ OBJ_TYPE(NavigationPolygonEditor, HBoxContainer );
+
+ UndoRedo *undo_redo;
+ enum Mode {
+
+ MODE_CREATE,
+ MODE_EDIT,
+
+ };
+
+ Mode mode;
+
+ ToolButton *button_create;
+ ToolButton *button_edit;
+
+ ConfirmationDialog *create_nav;
+
+ CanvasItemEditor *canvas_item_editor;
+ EditorNode *editor;
+ Panel *panel;
+ NavigationPolygonInstance *node;
+ MenuButton *options;
+
+ int edited_outline;
+ int edited_point;
+ Vector2 edited_point_pos;
+ DVector<Vector2> pre_move_edit;
+ Vector<Vector2> wip;
+ bool wip_active;
+
+
+ void _wip_close();
+ void _canvas_draw();
+ void _create_nav();
+
+ void _menu_option(int p_option);
+
+protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+public:
+
+ bool forward_input_event(const InputEvent& p_event);
+ void edit(Node *p_collision_polygon);
+ NavigationPolygonEditor(EditorNode *p_editor);
+};
+
+class NavigationPolygonEditorPlugin : public EditorPlugin {
+
+ OBJ_TYPE( NavigationPolygonEditorPlugin, EditorPlugin );
+
+ NavigationPolygonEditor *collision_polygon_editor;
+ EditorNode *editor;
+
+public:
+
+ virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); }
+
+ virtual String get_name() const { return "NavigationPolygonInstance"; }
+ 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);
+
+ NavigationPolygonEditorPlugin(EditorNode *p_node);
+ ~NavigationPolygonEditorPlugin();
+
+};
+
+
+#endif // NAVIGATIONPOLYGONEDITORPLUGIN_H
diff --git a/tools/editor/plugins/particles_2d_editor_plugin.cpp b/tools/editor/plugins/particles_2d_editor_plugin.cpp
index b23847231b..dadfa8bfdc 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,173 +26,174 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "particles_2d_editor_plugin.h"
-#include "canvas_item_editor_plugin.h"
-#include "io/image_loader.h"
-
-
-void Particles2DEditorPlugin::edit(Object *p_object) {
-
- if (p_object) {
- particles=p_object->cast_to<Particles2D>();
- } else {
- particles=NULL;
- }
-}
-
-bool Particles2DEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_type("Particles2D");
-}
-
-void Particles2DEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
-
- sep->show();
- menu->show();
- } else {
-
- menu->hide();
- sep->hide();
- }
-
-}
-
-void Particles2DEditorPlugin::_file_selected(const String& p_file) {
-
- print_line("file: "+p_file);
-
- int epc=epoints->get_val();
-
- Image img;
- Error err = ImageLoader::load_image(p_file,&img);
- ERR_EXPLAIN("Error loading image: "+p_file);
- ERR_FAIL_COND(err!=OK);
-
- img.convert(Image::FORMAT_GRAYSCALE_ALPHA);
- ERR_FAIL_COND(img.get_format()!=Image::FORMAT_GRAYSCALE_ALPHA);
- Size2i s = Size2(img.get_width(),img.get_height());
- ERR_FAIL_COND(s.width==0 || s.height==0);
-
- DVector<uint8_t> data = img.get_data();
- DVector<uint8_t>::Read r = data.read();
-
- Vector<Point2i> valid_positions;
- valid_positions.resize(s.width*s.height);
- int vpc=0;
-
-
- for(int i=0;i<s.width*s.height;i++) {
-
- uint8_t a = r[i*2+1];
- if (a>128) {
- valid_positions[vpc++]=Point2i(i%s.width,i/s.width);
- }
- }
-
- valid_positions.resize(vpc);
-
- ERR_EXPLAIN("No pixels with transparency > 128 in image..");
- ERR_FAIL_COND(valid_positions.size()==0);
-
- DVector<Point2> epoints;
- epoints.resize(epc);
- DVector<Point2>::Write w = epoints.write();
-
- Size2 extents = Size2(img.get_width()*0.5,img.get_height()*0.5);
-
- for(int i=0;i<epc;i++) {
-
- Point2 p = valid_positions[Math::rand()%vpc];
- p-=s/2;
- w[i]=p/extents;
- }
-
- w = DVector<Point2>::Write();
-
- undo_redo->create_action("Set Emission Mask");
- undo_redo->add_do_method(particles,"set_emission_points",epoints);
- undo_redo->add_do_method(particles,"set_emission_half_extents",extents);
- undo_redo->add_undo_method(particles,"set_emission_points",particles->get_emission_points());
- undo_redo->add_undo_method(particles,"set_emission_half_extents",particles->get_emission_half_extents());
- undo_redo->commit_action();
-
-}
-
-void Particles2DEditorPlugin::_menu_callback(int p_idx) {
-
- switch(p_idx) {
- case MENU_LOAD_EMISSION_MASK: {
-
-
- file->popup_centered_ratio();
-
- } break;
- case MENU_CLEAR_EMISSION_MASK: {
-
- undo_redo->create_action("Clear Emission Mask");
- undo_redo->add_do_method(particles,"set_emission_points",DVector<Vector2>());
- undo_redo->add_undo_method(particles,"set_emission_points",particles->get_emission_points());
- undo_redo->commit_action();
- } break;
- }
-
-}
-
-
-void Particles2DEditorPlugin::_notification(int p_what) {
-
- if (p_what==NOTIFICATION_ENTER_SCENE) {
-
- menu->get_popup()->connect("item_pressed",this,"_menu_callback");
- file->connect("file_selected",this,"_file_selected");
- }
-}
-
-void Particles2DEditorPlugin::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("_menu_callback"),&Particles2DEditorPlugin::_menu_callback);
- ObjectTypeDB::bind_method(_MD("_file_selected"),&Particles2DEditorPlugin::_file_selected);
-}
-
-
-
-Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
-
- particles=NULL;
- editor=p_node;
- undo_redo=editor->get_undo_redo();
- sep = memnew( VSeparator );
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(sep);
- sep->hide();
-
- menu = memnew( MenuButton );
- menu->get_popup()->add_item("Load Emission Mask",MENU_LOAD_EMISSION_MASK);
- menu->get_popup()->add_item("Clear Emission Mask",MENU_CLEAR_EMISSION_MASK);
- menu->set_text("Particles");
-
- file = memnew(FileDialog);
- add_child(file);
- List<String> ext;
- ImageLoader::get_recognized_extensions(&ext);
- for(List<String>::Element *E=ext.front();E;E=E->next()) {
- file->add_filter("*."+E->get()+"; "+E->get().to_upper());
- }
- file->set_mode(FileDialog::MODE_OPEN_FILE);
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(menu);
- epoints = memnew( SpinBox );
- epoints->set_min(1);
- epoints->set_max(8192);
- epoints->set_step(1);
- epoints->set_val(512);
- file->get_vbox()->add_margin_child("Generated Point Count:",epoints);
- menu->hide();
-
-}
-
-
-Particles2DEditorPlugin::~Particles2DEditorPlugin()
-{
-}
-
+#include "particles_2d_editor_plugin.h"
+#include "canvas_item_editor_plugin.h"
+#include "io/image_loader.h"
+
+
+void Particles2DEditorPlugin::edit(Object *p_object) {
+
+ if (p_object) {
+ particles=p_object->cast_to<Particles2D>();
+ } else {
+ particles=NULL;
+ }
+}
+
+bool Particles2DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_type("Particles2D");
+}
+
+void Particles2DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+
+ sep->show();
+ menu->show();
+ } else {
+
+ menu->hide();
+ sep->hide();
+ }
+
+}
+
+void Particles2DEditorPlugin::_file_selected(const String& p_file) {
+
+ print_line("file: "+p_file);
+
+ int epc=epoints->get_val();
+
+ Image img;
+ Error err = ImageLoader::load_image(p_file,&img);
+ ERR_EXPLAIN("Error loading image: "+p_file);
+ ERR_FAIL_COND(err!=OK);
+
+ img.convert(Image::FORMAT_GRAYSCALE_ALPHA);
+ ERR_FAIL_COND(img.get_format()!=Image::FORMAT_GRAYSCALE_ALPHA);
+ Size2i s = Size2(img.get_width(),img.get_height());
+ ERR_FAIL_COND(s.width==0 || s.height==0);
+
+ DVector<uint8_t> data = img.get_data();
+ DVector<uint8_t>::Read r = data.read();
+
+ Vector<Point2i> valid_positions;
+ valid_positions.resize(s.width*s.height);
+ int vpc=0;
+
+
+ for(int i=0;i<s.width*s.height;i++) {
+
+ uint8_t a = r[i*2+1];
+ if (a>128) {
+ valid_positions[vpc++]=Point2i(i%s.width,i/s.width);
+ }
+ }
+
+ valid_positions.resize(vpc);
+
+ ERR_EXPLAIN("No pixels with transparency > 128 in image..");
+ ERR_FAIL_COND(valid_positions.size()==0);
+
+ DVector<Point2> epoints;
+ epoints.resize(epc);
+ DVector<Point2>::Write w = epoints.write();
+
+ Size2 extents = Size2(img.get_width()*0.5,img.get_height()*0.5);
+
+ for(int i=0;i<epc;i++) {
+
+ Point2 p = valid_positions[Math::rand()%vpc];
+ p-=s/2;
+ w[i]=p/extents;
+ }
+
+ w = DVector<Point2>::Write();
+
+ undo_redo->create_action("Set Emission Mask");
+ undo_redo->add_do_method(particles,"set_emission_points",epoints);
+ undo_redo->add_do_method(particles,"set_emission_half_extents",extents);
+ undo_redo->add_undo_method(particles,"set_emission_points",particles->get_emission_points());
+ undo_redo->add_undo_method(particles,"set_emission_half_extents",particles->get_emission_half_extents());
+ undo_redo->commit_action();
+
+}
+
+void Particles2DEditorPlugin::_menu_callback(int p_idx) {
+
+ switch(p_idx) {
+ case MENU_LOAD_EMISSION_MASK: {
+
+
+ file->popup_centered_ratio();
+
+ } break;
+ case MENU_CLEAR_EMISSION_MASK: {
+
+ undo_redo->create_action("Clear Emission Mask");
+ undo_redo->add_do_method(particles,"set_emission_points",DVector<Vector2>());
+ undo_redo->add_undo_method(particles,"set_emission_points",particles->get_emission_points());
+ undo_redo->commit_action();
+ } break;
+ }
+
+}
+
+
+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");
+ }
+}
+
+void Particles2DEditorPlugin::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_menu_callback"),&Particles2DEditorPlugin::_menu_callback);
+ ObjectTypeDB::bind_method(_MD("_file_selected"),&Particles2DEditorPlugin::_file_selected);
+}
+
+
+
+Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
+
+ particles=NULL;
+ editor=p_node;
+ undo_redo=editor->get_undo_redo();
+ sep = memnew( VSeparator );
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(sep);
+ sep->hide();
+
+ menu = memnew( MenuButton );
+ menu->get_popup()->add_item("Load Emission Mask",MENU_LOAD_EMISSION_MASK);
+ menu->get_popup()->add_item("Clear Emission Mask",MENU_CLEAR_EMISSION_MASK);
+ menu->set_text("Particles");
+
+ file = memnew(EditorFileDialog);
+ add_child(file);
+ List<String> ext;
+ ImageLoader::get_recognized_extensions(&ext);
+ for(List<String>::Element *E=ext.front();E;E=E->next()) {
+ file->add_filter("*."+E->get()+"; "+E->get().to_upper());
+ }
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(menu);
+ epoints = memnew( SpinBox );
+ epoints->set_min(1);
+ epoints->set_max(8192);
+ epoints->set_step(1);
+ epoints->set_val(512);
+ file->get_vbox()->add_margin_child("Generated Point Count:",epoints);
+ menu->hide();
+
+}
+
+
+Particles2DEditorPlugin::~Particles2DEditorPlugin()
+{
+}
+
diff --git a/tools/editor/plugins/particles_2d_editor_plugin.h b/tools/editor/plugins/particles_2d_editor_plugin.h
index b824774d0e..dba0bb4dae 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,57 +26,57 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PARTICLES_2D_EDITOR_PLUGIN_H
-#define PARTICLES_2D_EDITOR_PLUGIN_H
-
-#include "tools/editor/editor_plugin.h"
-#include "tools/editor/editor_node.h"
-#include "scene/2d/collision_polygon_2d.h"
-
-#include "scene/gui/separator.h"
-#include "scene/gui/file_dialog.h"
-#include "scene/2d/particles_2d.h"
-
-class Particles2DEditorPlugin : public EditorPlugin {
-
- OBJ_TYPE( Particles2DEditorPlugin, EditorPlugin );
-
- enum {
-
- MENU_LOAD_EMISSION_MASK,
- MENU_CLEAR_EMISSION_MASK
- };
-
-
- FileDialog *file;
- EditorNode *editor;
-
- MenuButton *menu;
-
- VSeparator *sep;
- Particles2D *particles;
- SpinBox *epoints;
-
- UndoRedo *undo_redo;
- void _file_selected(const String& p_file);
- void _menu_callback(int p_idx);
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
-
-
- virtual String get_name() const { return "Particles2D"; }
- 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);
-
- Particles2DEditorPlugin(EditorNode *p_node);
- ~Particles2DEditorPlugin();
-
-};
-
-
-#endif // PARTICLES_2D_EDITOR_PLUGIN_H
+#ifndef PARTICLES_2D_EDITOR_PLUGIN_H
+#define PARTICLES_2D_EDITOR_PLUGIN_H
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/2d/collision_polygon_2d.h"
+
+#include "scene/gui/separator.h"
+#include "scene/gui/file_dialog.h"
+#include "scene/2d/particles_2d.h"
+
+class Particles2DEditorPlugin : public EditorPlugin {
+
+ OBJ_TYPE( Particles2DEditorPlugin, EditorPlugin );
+
+ enum {
+
+ MENU_LOAD_EMISSION_MASK,
+ MENU_CLEAR_EMISSION_MASK
+ };
+
+
+ EditorFileDialog *file;
+ EditorNode *editor;
+
+ MenuButton *menu;
+
+ VSeparator *sep;
+ Particles2D *particles;
+ SpinBox *epoints;
+
+ UndoRedo *undo_redo;
+ void _file_selected(const String& p_file);
+ void _menu_callback(int p_idx);
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+
+
+ virtual String get_name() const { return "Particles2D"; }
+ 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);
+
+ Particles2DEditorPlugin(EditorNode *p_node);
+ ~Particles2DEditorPlugin();
+
+};
+
+
+#endif // PARTICLES_2D_EDITOR_PLUGIN_H
diff --git a/tools/editor/plugins/particles_editor_plugin.cpp b/tools/editor/plugins/particles_editor_plugin.cpp
index 38781d93b9..5c84d9a86a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,6 +29,7 @@
#include "particles_editor_plugin.h"
#include "io/resource_loader.h"
#include "servers/visual/particle_system_sw.h"
+#include "tools/editor/plugins/spatial_editor_plugin.h"
void ParticlesEditor::_node_removed(Node *p_node) {
@@ -57,7 +58,7 @@ void ParticlesEditor::_node_selected(const NodePath& p_path){
if (!vi) {
err_dialog->set_text("Node does not contain geometry.");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -66,7 +67,7 @@ void ParticlesEditor::_node_selected(const NodePath& p_path){
if (geometry.size()==0) {
err_dialog->set_text("Node does not contain geometry (faces).");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -109,7 +110,8 @@ void ParticlesEditor::_populate() {
void ParticlesEditor::_notification(int p_notification) {
- if (p_notification==NOTIFICATION_ENTER_SCENE) {
+ if (p_notification==NOTIFICATION_ENTER_TREE) {
+ options->set_icon(options->get_popup()->get_icon("Particles","EditorIcons"));
}
}
@@ -218,7 +220,7 @@ void ParticlesEditor::_generate_emission_points() {
if (!triangle_area_map.size() || area_accum==0) {
err_dialog->set_text("Faces contain no area!");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -248,7 +250,7 @@ void ParticlesEditor::_generate_emission_points() {
if (gcount==0) {
err_dialog->set_text("No Faces!");
- err_dialog->popup_centered(Size2(300,100));
+ err_dialog->popup_centered_minsize();
return;
}
@@ -340,9 +342,11 @@ void ParticlesEditor::_bind_methods() {
ParticlesEditor::ParticlesEditor() {
+ particles_editor_hb = memnew ( HBoxContainer );
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
options = memnew( MenuButton );
- add_child(options);
- options->set_area_as_parent_rect();
+ particles_editor_hb->add_child(options);
+ particles_editor_hb->hide();
options->set_text("Particles");
options->get_popup()->add_item("Generate AABB",MENU_OPTION_GENERATE_AABB);
@@ -391,7 +395,7 @@ ParticlesEditor::ParticlesEditor() {
add_child(err_dialog);
- emission_file_dialog = memnew( FileDialog );
+ emission_file_dialog = memnew( EditorFileDialog );
add_child(emission_file_dialog);
emission_file_dialog->connect("file_selected",this,"_resource_seleted");
emission_tree_dialog = memnew( SceneTreeDialog );
@@ -407,7 +411,7 @@ ParticlesEditor::ParticlesEditor() {
emission_file_dialog->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper());
}
- emission_file_dialog->set_mode(FileDialog::MODE_OPEN_FILE);
+ emission_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
//options->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
//options->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
@@ -429,8 +433,9 @@ void ParticlesEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
particles_editor->show();
+ particles_editor->particles_editor_hb->show();
} else {
-
+ particles_editor->particles_editor_hb->hide();
particles_editor->hide();
particles_editor->edit(NULL);
}
@@ -443,14 +448,6 @@ ParticlesEditorPlugin::ParticlesEditorPlugin(EditorNode *p_node) {
particles_editor = memnew( ParticlesEditor );
editor->get_viewport()->add_child(particles_editor);
-// particles_editor->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
-// particles_editor->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
- particles_editor->set_margin(MARGIN_LEFT,253);
- particles_editor->set_margin(MARGIN_RIGHT,280);
- particles_editor->set_margin(MARGIN_TOP,0);
- particles_editor->set_margin(MARGIN_BOTTOM,10);
-
-
particles_editor->hide();
}
diff --git a/tools/editor/plugins/particles_editor_plugin.h b/tools/editor/plugins/particles_editor_plugin.h
index ba655c9b39..92756af1f6 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -43,11 +43,12 @@ class ParticlesEditor : public Control {
OBJ_TYPE(ParticlesEditor, Control );
Panel *panel;
- MenuButton * options;
+ MenuButton *options;
+ HBoxContainer *particles_editor_hb;
Particles *node;
- FileDialog *emission_file_dialog;
+ EditorFileDialog *emission_file_dialog;
SceneTreeDialog *emission_tree_dialog;
ConfirmationDialog *err_dialog;
@@ -78,6 +79,8 @@ class ParticlesEditor : public Control {
void _populate();
+friend class ParticlesEditorPlugin;
+
protected:
void _notification(int p_notification);
diff --git a/tools/editor/plugins/path_2d_editor_plugin.cpp b/tools/editor/plugins/path_2d_editor_plugin.cpp
index 33ea5f3588..d037adc555 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -62,17 +62,6 @@ void Path2DEditor::_node_removed(Node *p_node) {
}
-Vector2 Path2DEditor::snap_point(const Vector2& p_point) const {
-
- if (canvas_item_editor->is_snap_active()) {
-
- return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap());
-
- } else {
- return p_point;
- }
-}
-
bool Path2DEditor::forward_input_event(const InputEvent& p_event) {
if (!node)
@@ -93,8 +82,8 @@ bool Path2DEditor::forward_input_event(const InputEvent& p_event) {
Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Vector2 gpoint = Point2(mb.x,mb.y);
- Vector2 cpoint = !mb.mod.alt? snap_point(xform.affine_inverse().xform(gpoint))
- : node->get_global_transform().affine_inverse().xform( snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) );
+ Vector2 cpoint = !mb.mod.alt? canvas_item_editor->snap_point(xform.affine_inverse().xform(gpoint))
+ : node->get_global_transform().affine_inverse().xform( canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) );
//first check if a point is to be added (segment split)
real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);
@@ -195,7 +184,7 @@ bool Path2DEditor::forward_input_event(const InputEvent& p_event) {
Ref<Curve2D> curve = node->get_curve();
- Vector2 new_pos = moving_from + xform.basis_xform( gpoint - moving_screen_from );
+ Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
switch(action) {
case ACTION_MOVING_POINT: {
@@ -250,9 +239,9 @@ bool Path2DEditor::forward_input_event(const InputEvent& p_event) {
if (!wip_active) {
wip.clear();
- wip.push_back( snap_point(cpoint) );
+ wip.push_back( canvas_item_editor->snap_point(cpoint) );
wip_active=true;
- edited_point_pos=snap_point(cpoint);
+ edited_point_pos=canvas_item_editor->snap_point(cpoint);
canvas_item_editor->update();
edited_point=1;
return true;
@@ -265,7 +254,7 @@ bool Path2DEditor::forward_input_event(const InputEvent& p_event) {
return true;
} else {
- wip.push_back( snap_point(cpoint) );
+ wip.push_back( canvas_item_editor->snap_point(cpoint) );
edited_point=wip.size();
canvas_item_editor->update();
return true;
@@ -327,9 +316,9 @@ bool Path2DEditor::forward_input_event(const InputEvent& p_event) {
if (closest_idx>=0) {
pre_move_edit=poly;
- poly.insert(closest_idx+1,snap_point(xform.affine_inverse().xform(closest_pos)));
+ poly.insert(closest_idx+1,canvas_item_editor->snap_point(xform.affine_inverse().xform(closest_pos)));
edited_point=closest_idx+1;
- edited_point_pos=snap_point(xform.affine_inverse().xform(closest_pos));
+ edited_point_pos=canvas_item_editor->snap_point(xform.affine_inverse().xform(closest_pos));
node->set_polygon(poly);
canvas_item_editor->update();
return true;
@@ -434,12 +423,12 @@ bool Path2DEditor::forward_input_event(const InputEvent& p_event) {
Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Vector2 gpoint = Point2(mm.x,mm.y);
- Vector2 cpoint = !mm.mod.alt? snap_point(xform.affine_inverse().xform(gpoint))
- : node->get_global_transform().affine_inverse().xform( snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) );
+ Vector2 cpoint = !mm.mod.alt? canvas_item_editor->snap_point(xform.affine_inverse().xform(gpoint))
+ : node->get_global_transform().affine_inverse().xform( canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) );
Ref<Curve2D> curve = node->get_curve();
- Vector2 new_pos = moving_from + xform.basis_xform( gpoint - moving_screen_from );
+ Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
switch(action) {
@@ -471,7 +460,7 @@ bool Path2DEditor::forward_input_event(const InputEvent& p_event) {
Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Vector2 gpoint = Point2(mm.x,mm.y);
- edited_point_pos = snap_point(xform.affine_inverse().xform(gpoint));
+ edited_point_pos = canvas_item_editor->snap_point(xform.affine_inverse().xform(gpoint));
canvas_item_editor->update();
}
diff --git a/tools/editor/plugins/path_2d_editor_plugin.h b/tools/editor/plugins/path_2d_editor_plugin.h
index 73de2cc838..9f15c0669f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -94,7 +94,6 @@ protected:
static void _bind_methods();
public:
- Vector2 snap_point(const Vector2& p_point) const;
bool forward_input_event(const InputEvent& p_event);
void edit(Node *p_path2d);
Path2DEditor(EditorNode *p_editor);
diff --git a/tools/editor/plugins/path_editor_plugin.cpp b/tools/editor/plugins/path_editor_plugin.cpp
index 7b0ff971d2..f4bdf50fe9 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-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. */
-/*************************************************************************/
-#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_SCENE) {
-
- 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-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()
+{
+}
+
diff --git a/tools/editor/plugins/path_editor_plugin.h b/tools/editor/plugins/path_editor_plugin.h
index d730d33551..fcd4241e59 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/polygon_2d_editor_plugin.cpp b/tools/editor/plugins/polygon_2d_editor_plugin.cpp
index 7dd8dd3035..cd82297365 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,24 +67,15 @@ 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();
}
}
-Vector2 Polygon2DEditor::snap_point(const Vector2& p_point) const {
-
- if (canvas_item_editor->is_snap_active()) {
-
- return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap());
-
- } else {
- return p_point;
- }
-}
-
void Polygon2DEditor::_menu_option(int p_option) {
switch(p_option) {
@@ -101,7 +97,7 @@ void Polygon2DEditor::_menu_option(int p_option) {
if (node->get_texture().is_null()) {
error->set_text("No texture in this polygon.\nSet a texture to be able to edit UV.");
- error->popup_centered_minsize(Size2(300,70));
+ error->popup_centered_minsize();
return;
}
@@ -169,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");
@@ -187,6 +218,8 @@ void Polygon2DEditor::_wip_close() {
bool Polygon2DEditor::forward_input_event(const InputEvent& p_event) {
+ if (node==NULL)
+ return false;
switch(p_event.type) {
@@ -199,7 +232,7 @@ bool Polygon2DEditor::forward_input_event(const InputEvent& p_event) {
Vector2 gpoint = Point2(mb.x,mb.y);
Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
- cpoint=snap_point(cpoint);
+ cpoint=canvas_item_editor->snap_point(cpoint);
cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
@@ -403,7 +436,7 @@ bool Polygon2DEditor::forward_input_event(const InputEvent& p_event) {
Vector2 gpoint = Point2(mm.x,mm.y);
Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
- cpoint=snap_point(cpoint);
+ cpoint=canvas_item_editor->snap_point(cpoint);
edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
canvas_item_editor->get_viewport_control()->update();
@@ -503,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;
}
}
@@ -554,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);
@@ -658,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");
@@ -701,11 +761,13 @@ void Polygon2DEditor::edit(Node *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");
+
wip.clear();
wip_active=false;
edited_point=-1;
} else {
+
node=NULL;
if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
@@ -723,16 +785,41 @@ void Polygon2DEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_uv_draw"),&Polygon2DEditor::_uv_draw);
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;
canvas_item_editor=NULL;
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);
@@ -802,9 +889,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 88d1c20493..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,13 +93,22 @@ 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:
- Vector2 snap_point(const Vector2& p_point) const;
bool forward_input_event(const InputEvent& p_event);
void edit(Node *p_collision_polygon);
Polygon2DEditor(EditorNode *p_editor);
diff --git a/tools/editor/plugins/resource_preloader_editor_plugin.cpp b/tools/editor/plugins/resource_preloader_editor_plugin.cpp
index b0841933ec..9cd20ac53a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -45,7 +45,7 @@ void ResourcePreloaderEditor::_notification(int p_what) {
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
load->set_icon( get_icon("Folder","EditorIcons") );
_delete->set_icon( get_icon("Del","EditorIcons") );
}
@@ -72,7 +72,7 @@ void ResourcePreloaderEditor::_file_load_request(const String& p_path) {
dialog->set_title("Error!");
//dialog->get_cancel()->set_text("Close");
dialog->get_ok()->set_text("Close");
- dialog->popup_centered(Size2(300,60));
+ dialog->popup_centered_minsize();
return; ///beh should show an error i guess
}
@@ -102,7 +102,7 @@ void ResourcePreloaderEditor::_load_pressed() {
for(int i=0;i<extensions.size();i++)
file->add_filter("*."+extensions[i]);
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
file->popup_centered_ratio();
@@ -167,7 +167,7 @@ void ResourcePreloaderEditor::_paste_pressed() {
dialog->set_title("Error!");
//dialog->get_cancel()->set_text("Close");
dialog->get_ok()->set_text("Close");
- dialog->popup_centered(Size2(300,60));
+ dialog->popup_centered_minsize();
return; ///beh should show an error i guess
}
@@ -310,7 +310,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
paste->set_text("Paste");
hbc->add_child(paste);
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
add_child(file);
diff --git a/tools/editor/plugins/resource_preloader_editor_plugin.h b/tools/editor/plugins/resource_preloader_editor_plugin.h
index e3178bc8ff..88272bc603 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -49,7 +49,7 @@ class ResourcePreloaderEditor : public PanelContainer {
bool loading_scene;
- FileDialog *file;
+ EditorFileDialog *file;
AcceptDialog *dialog;
diff --git a/tools/editor/plugins/rich_text_editor_plugin.cpp b/tools/editor/plugins/rich_text_editor_plugin.cpp
index 58b3636dcc..a0daad854f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,6 +28,8 @@
/*************************************************************************/
#include "rich_text_editor_plugin.h"
#include "os/file_access.h"
+#include "canvas_item_editor_plugin.h"
+
void RichTextEditor::_notification(int p_what) {
switch(p_what) {
@@ -100,7 +102,8 @@ void RichTextEditor::edit(Node *p_rich_text) {
RichTextEditor::RichTextEditor() {
options = memnew( MenuButton );
- add_child(options);
+ //add_child(options);
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_area_as_parent_rect();
options->set_text("RichText");
@@ -108,10 +111,10 @@ RichTextEditor::RichTextEditor() {
options->get_popup()->add_item("Clear",CLEAR);
options->get_popup()->connect("item_pressed", this,"_menu_option");
- file_dialog = memnew( FileDialog );
+ file_dialog = memnew( EditorFileDialog );
add_child(file_dialog);
file_dialog->add_filter("*.txt");
- file_dialog->set_mode(FileDialog::MODE_OPEN_FILE);
+ file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
file_dialog->connect("file_selected",this,"_file_selected");
}
@@ -129,10 +132,10 @@ bool RichTextEditorPlugin::handles(Object *p_object) const {
void RichTextEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- rich_text_editor->show();
+ rich_text_editor->options->show();
} else {
- rich_text_editor->hide();
+ rich_text_editor->options->hide();
rich_text_editor->edit(NULL);
}
@@ -149,10 +152,7 @@ RichTextEditorPlugin::RichTextEditorPlugin(EditorNode *p_node) {
rich_text_editor->set_margin(MARGIN_TOP,0);
rich_text_editor->set_margin(MARGIN_BOTTOM,10);
-
- rich_text_editor->hide();
-
-
+ rich_text_editor->options->hide();
}
diff --git a/tools/editor/plugins/rich_text_editor_plugin.h b/tools/editor/plugins/rich_text_editor_plugin.h
index e51e0653b9..478dc0d308 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -42,6 +42,8 @@ class RichTextEditor : public Control {
OBJ_TYPE(RichTextEditor, Control );
+ friend class RichTextEditorPlugin;
+
enum {
PARSE_BBCODE,
@@ -49,9 +51,9 @@ class RichTextEditor : public Control {
};
Panel *panel;
+ MenuButton *options;
RichTextLabel *node;
- MenuButton *options;
- FileDialog *file_dialog;
+ EditorFileDialog *file_dialog;
void _file_selected(const String& p_path);
void _menu_option(int p_option);
diff --git a/tools/editor/plugins/sample_editor_plugin.cpp b/tools/editor/plugins/sample_editor_plugin.cpp
index e3fad58a89..d88f2adc73 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,7 +46,7 @@ void SampleEditor::_notification(int p_what) {
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
play->set_icon( get_icon("Play","EditorIcons") );
stop->set_icon( get_icon("Stop","EditorIcons") );
}
@@ -98,6 +98,131 @@ void SampleEditor::generate_preview_texture(const Ref<Sample>& p_sample,Ref<Imag
if (p_sample->get_format()==Sample::FORMAT_IMA_ADPCM) {
+ struct IMA_ADPCM_State {
+
+ int16_t step_index;
+ int32_t predictor;
+ /* values at loop point */
+ int16_t loop_step_index;
+ int32_t loop_predictor;
+ int32_t last_nibble;
+ int32_t loop_pos;
+ int32_t window_ofs;
+ const uint8_t *ptr;
+ } ima_adpcm;
+
+ ima_adpcm.step_index=0;
+ ima_adpcm.predictor=0;
+ ima_adpcm.loop_step_index=0;
+ ima_adpcm.loop_predictor=0;
+ ima_adpcm.last_nibble=-1;
+ ima_adpcm.loop_pos=0x7FFFFFFF;
+ ima_adpcm.window_ofs=0;
+ ima_adpcm.ptr=NULL;
+
+
+ for(int i=0;i<w;i++) {
+
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ for(int j=from;j<to;j++) {
+
+ while(j>ima_adpcm.last_nibble) {
+
+ static const int16_t _ima_adpcm_step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+ };
+
+ static const int8_t _ima_adpcm_index_table[16] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+ };
+
+ int16_t nibble,signed_nibble,diff,step;
+
+ 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[ofs]>>4):(src_ptr[ofs]&0xF);
+
+ step=_ima_adpcm_step_table[ima_adpcm.step_index];
+
+ ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
+ if (ima_adpcm.step_index<0)
+ ima_adpcm.step_index=0;
+ if (ima_adpcm.step_index>88)
+ ima_adpcm.step_index=88;
+
+ /*
+ 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 ;
+
+ ima_adpcm.predictor+=diff;
+ if (ima_adpcm.predictor<-0x8000)
+ ima_adpcm.predictor=-0x8000;
+ else if (ima_adpcm.predictor>0x7FFF)
+ ima_adpcm.predictor=0x7FFF;
+
+
+ /* store loop if there */
+ if (ima_adpcm.last_nibble==ima_adpcm.loop_pos) {
+
+ ima_adpcm.loop_step_index = ima_adpcm.step_index;
+ ima_adpcm.loop_predictor = ima_adpcm.predictor;
+ }
+
+ }
+
+ float v=ima_adpcm.predictor/32767.0;
+ if (v>max[0])
+ max[0]=v;
+ if (v<min[0])
+ min[0]=v;
+ }
+
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ }
} else {
for(int i=0;i<w;i++) {
// i trust gcc will optimize this loop
diff --git a/tools/editor/plugins/sample_editor_plugin.h b/tools/editor/plugins/sample_editor_plugin.h
index 78d5ed401c..e615667914 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/sample_library_editor_plugin.cpp b/tools/editor/plugins/sample_library_editor_plugin.cpp
index 84143dcd4b..b497458a2a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,11 +47,15 @@ void SampleLibraryEditor::_notification(int p_what) {
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ 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) {
@@ -93,7 +97,7 @@ void SampleLibraryEditor::_file_load_request(const DVector<String>& p_path) {
dialog->set_title("Error!");
//dialog->get_cancel()->set_text("Close");
dialog->get_ok()->set_text("Close");
- dialog->popup_centered(Size2(300,60));
+ dialog->popup_centered_minsize();
return; ///beh should show an error i guess
}
String basename = path.get_file().basename();
@@ -129,7 +133,7 @@ void SampleLibraryEditor::_button_pressed(Object *p_item,int p_column, int p_id)
player->play(name,true);
} else if (p_column==1) {
- get_scene()->get_root()->get_child(0)->call("_resource_selected",sample_library->get_sample(name));
+ get_tree()->get_root()->get_child(0)->call("_resource_selected",sample_library->get_sample(name));
}
@@ -186,7 +190,7 @@ void SampleLibraryEditor::_item_edited() {
Ref<Sample> samp = sample_library->get_sample(tree->get_selected()->get_metadata(0));
- get_scene()->get_root()->get_child(0)->call("_resource_selected",samp);
+ get_tree()->get_root()->get_child(0)->call("_resource_selected",samp);
}
@@ -235,6 +239,7 @@ void SampleLibraryEditor::_update_library() {
List<StringName> names;
sample_library->get_sample_list(&names);
+ names.sort_custom<StringName::AlphCompare>();
for(List<StringName>::Element *E=names.front();E;E=E->next()) {
@@ -331,7 +336,8 @@ SampleLibraryEditor::SampleLibraryEditor() {
play->set_pos(Point2( 5, 5 ));
play->set_size( Size2(1,1 ) );
play->set_toggle_mode(true);
- //add_child(play);
+ add_child(play);
+ play->hide();
stop = memnew( Button );
@@ -348,13 +354,13 @@ SampleLibraryEditor::SampleLibraryEditor() {
_delete = memnew( Button );
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
add_child(file);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Sample",&extensions);
for(int i=0;i<extensions.size();i++)
file->add_filter("*."+extensions[i]);
- file->set_mode(FileDialog::MODE_OPEN_FILES);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILES);
_delete->set_pos(Point2( 65, 5 ));
_delete->set_size( Size2(1,1 ) );
diff --git a/tools/editor/plugins/sample_library_editor_plugin.h b/tools/editor/plugins/sample_library_editor_plugin.h
index a6ce764b9c..2770ca2d9a 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -54,7 +54,7 @@ class SampleLibraryEditor : public Panel {
Button *_delete;
Tree *tree;
- FileDialog *file;
+ EditorFileDialog *file;
ConfirmationDialog *dialog;
diff --git a/tools/editor/plugins/sample_player_editor_plugin.cpp b/tools/editor/plugins/sample_player_editor_plugin.cpp
index fa8a285e4e..f1c7ca8c98 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@
void SamplePlayerEditor::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
play->set_icon( get_icon("Play","EditorIcons") );
stop->set_icon( get_icon("Stop","EditorIcons") );
}
@@ -64,6 +64,8 @@ void SamplePlayerEditor::_play() {
return;
node->call("play",samples->get_item_text( samples->get_selected() ));
+ stop->set_pressed(false);
+ play->set_pressed(true);
}
void SamplePlayerEditor::_stop() {
@@ -74,6 +76,9 @@ void SamplePlayerEditor::_stop() {
return;
node->call("stop_all");
+ print_line("STOP ALL!!");
+ stop->set_pressed(true);
+ play->set_pressed(false);
}
@@ -89,6 +94,7 @@ void SamplePlayerEditor::_update_sample_library() {
List<StringName> samplenames;
sl->get_sample_list(&samplenames);
+ samplenames.sort_custom<StringName::AlphCompare>();
for(List<StringName>::Element *E=samplenames.front();E;E=E->next()) {
samples->add_item(E->get());
}
diff --git a/tools/editor/plugins/sample_player_editor_plugin.h b/tools/editor/plugins/sample_player_editor_plugin.h
index 4e35e4d8bb..cdd1a99c17 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp
index 31ccc79d2a..37f4076a0c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,11 +38,90 @@
#include "os/file_access.h"
#include "scene/main/viewport.h"
#include "os/keyboard.h"
+#include "os/input.h"
+
/*** 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) {
popup_centered_ratio(0.6);
@@ -115,9 +194,11 @@ void ScriptEditorQuickOpen::_confirmed() {
void ScriptEditorQuickOpen::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
connect("confirmed",this,"_confirmed");
+
+
}
}
@@ -188,7 +269,9 @@ void ScriptTextEditor::apply_code() {
if (script.is_null())
return;
+// print_line("applying code");
script->set_source_code(get_text_edit()->get_text());
+ script->update_exports();
}
Ref<Script> ScriptTextEditor::get_edited_script() const {
@@ -207,6 +290,8 @@ void ScriptTextEditor::_load_theme_settings() {
get_text_edit()->add_color_override("font_color",EDITOR_DEF("text_editor/text_color",Color(0,0,0)));
get_text_edit()->add_color_override("font_selected_color",EDITOR_DEF("text_editor/text_selected_color",Color(1,1,1)));
get_text_edit()->add_color_override("selection_color",EDITOR_DEF("text_editor/selection_color",Color(0.2,0.2,1)));
+ get_text_edit()->add_color_override("brace_mismatch_color",EDITOR_DEF("text_editor/brace_mismatch_color",Color(1,0.2,0.2)));
+ get_text_edit()->add_color_override("current_line_color",EDITOR_DEF("text_editor/current_line_color",Color(0.3,0.5,0.8,0.15)));
Color keyword_color= EDITOR_DEF("text_editor/keyword_color",Color(0.5,0.0,0.2));
@@ -235,10 +320,10 @@ void ScriptTextEditor::_load_theme_settings() {
//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()) {
get_text_edit()->add_keyword_color(E->get(),type_color);
}
@@ -281,8 +366,21 @@ void ScriptTextEditor::reload_text() {
ERR_FAIL_COND(script.is_null()) ;
- get_text_edit()->set_text(script->get_source_code());
- get_text_edit()->clear_undo_history();
+ TextEdit *te = get_text_edit();
+ int column = te->cursor_get_column();
+ int row = te->cursor_get_line();
+ int h = te->get_h_scroll();
+ int v = te->get_v_scroll();
+
+ te->set_text(script->get_source_code());
+ te->clear_undo_history();
+ te->cursor_set_line(row);
+ te->cursor_set_column(column);
+ te->set_h_scroll(h);
+ te->set_v_scroll(v);
+
+ te->tag_saved_version();
+
_line_col_changed();
}
@@ -291,12 +389,17 @@ void ScriptTextEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_READY) {
- _update_name();
+ //emit_signal("name_changed");
}
}
-void ScriptTextEditor::_update_name() {
+bool ScriptTextEditor::is_unsaved() {
+
+ return get_text_edit()->get_version()!=get_text_edit()->get_saved_version();
+}
+
+String ScriptTextEditor::get_name() {
String name;
if (script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) {
@@ -309,21 +412,20 @@ void ScriptTextEditor::_update_name() {
else
name=script->get_type()+"("+itos(script->get_instance_ID())+")";
+ return name;
- if (name!=String(get_name())) {
+}
- set_name(name);
+Ref<Texture> ScriptTextEditor::get_icon() {
+ if (get_parent_control() && get_parent_control()->has_icon(script->get_type(),"EditorIcons")) {
+ return get_parent_control()->get_icon(script->get_type(),"EditorIcons");
}
- if (!has_meta("_tab_icon")) {
- if (get_parent_control() && get_parent_control()->has_icon(script->get_type(),"EditorIcons")) {
- set_meta("_tab_icon",get_parent_control()->get_icon(script->get_type(),"EditorIcons"));
- }
- }
+ return Ref<Texture>();
+}
-}
void ScriptTextEditor::set_edited_script(const Ref<Script>& p_script) {
@@ -339,8 +441,7 @@ void ScriptTextEditor::set_edited_script(const Ref<Script>& p_script) {
get_text_edit()->tag_saved_version();
- _update_name();
-
+ emit_signal("name_changed");
_line_col_changed();
}
@@ -362,7 +463,8 @@ void ScriptTextEditor::_validate_script() {
line=-1;
if (!script->is_tool()) {
script->set_source_code(text);
- script->reload(); //will update all the variables in property editors
+ script->update_exports();
+ //script->reload(); //will update all the variables in property editors
}
functions.clear();
@@ -378,15 +480,98 @@ void ScriptTextEditor::_validate_script() {
te->set_line_as_marked(i,line==i);
}
- _update_name();
+ emit_signal("name_changed");
}
-void ScriptTextEditor::_code_complete_script(const String& p_code, const String& p_keyword,int p_line, List<String>* r_options) {
- Error err = script->get_language()->complete_keyword(p_code,p_line,script->get_path().get_base_dir(),p_keyword,r_options);
+static Node* _find_node_for_script(Node* p_base, Node*p_current, const Ref<Script>& p_script) {
+
+ if (p_current->get_owner()!=p_base && p_base!=p_current)
+ return NULL;
+ Ref<Script> c = p_current->get_script();
+ if (c==p_script)
+ return p_current;
+ for(int i=0;i<p_current->get_child_count();i++) {
+ Node *found = _find_node_for_script(p_base,p_current->get_child(i),p_script);
+ if (found)
+ return found;
+ }
+
+ 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();
+ if (base) {
+ base = _find_node_for_script(base,base,script);
+ }
+ String hint;
+ Error err = script->get_language()->complete_code(p_code,script->get_path().get_base_dir(),base,r_options,hint);
+ if (hint!="") {
+ get_text_edit()->set_code_hint(hint);
+ print_line("hint: "+hint.replace(String::chr(0xFFFF),"|"));
+ }
+
+}
+void ScriptTextEditor::_bind_methods() {
+
+ ADD_SIGNAL(MethodInfo("name_changed"));
+}
+
ScriptTextEditor::ScriptTextEditor() {
get_text_edit()->set_draw_tabs(true);
@@ -422,6 +607,10 @@ void ScriptEditor::_show_debugger(bool p_show) {
}
+void ScriptEditor::_script_created(Ref<Script> p_script) {
+ editor->push_item(p_script.operator->());
+}
+
void ScriptEditor::_goto_script_line2(int p_line) {
int selected = tab_container->get_current_tab();
@@ -444,27 +633,122 @@ 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 (idx>=0) {
+
+ if (history_pos>=0) {
+ idx = history[history_pos].control->get_index();
+ }
tab_container->set_current_tab(idx);
- _update_window_menu();
- _save_files_state();
+ //script_list->select(idx);
+ }
+
+
+ _update_history_arrows();
+
+
+
+ _update_script_names();
+ EditorNode::get_singleton()->save_layout();
}
@@ -526,6 +810,7 @@ void ScriptEditor::_reload_scripts(){
}
disk_changed->hide();
+ _update_script_names();
}
@@ -555,10 +840,10 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource>& p_res) {
ste->get_text_edit()->tag_saved_version();
}
- ste->_update_name();
-
}
+ _update_script_names();
+
}
bool ScriptEditor::_test_script_times_on_disk() {
@@ -568,71 +853,77 @@ 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)
- disk_changed->call_deferred("popup_centered_ratio",0.5);
+ 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::_menu_option(int p_option) {
-
+void ScriptEditor::swap_lines(TextEdit *tx, int line1, int line2)
+{
+ String tmp = tx->get_line(line1);
+ String tmp2 = tx->get_line(line2);
+ tx->set_line(line2, tmp);
+ tx->set_line(line1, tmp2);
- if (p_option==FILE_OPEN) {
+ tx->cursor_set_line(line2);
+}
- editor->open_resource("Script");
- return;
- }
- int selected = tab_container->get_current_tab();
- if (selected<0 || selected>=tab_container->get_child_count())
- return;
+void ScriptEditor::_menu_option(int p_option) {
- 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: {
@@ -657,159 +948,471 @@ void ScriptEditor::_menu_option(int p_option) {
} break;
- case EDIT_UNDO: {
-
-
- current->get_text_edit()->undo();
- } break;
- case EDIT_REDO: {
- current->get_text_edit()->redo();
-
- } break;
- case EDIT_CUT: {
-
- current->get_text_edit()->cut();
- } break;
- case EDIT_COPY: {
- current->get_text_edit()->copy();
-
- } break;
- case EDIT_PASTE: {
- current->get_text_edit()->paste();
-
- } break;
- case EDIT_SELECT_ALL: {
-
- current->get_text_edit()->select_all();
+ case SEARCH_HELP: {
+ help_search_dialog->popup();
} break;
- case EDIT_COMPLETE: {
+ case SEARCH_CLASSES: {
- current->get_text_edit()->query_code_comple();
+ String current;
- } 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);
-
- } 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: {
+ help_index->popup_centered_ratio(0.6);
- find_replace_dialog->set_text_edit(current->get_text_edit());
- find_replace_dialog->popup_replace();
+ if (current!="") {
+ help_index->call_deferred("select_class",current);
+ }
} break;
- case SEARCH_LOCATE_FUNCTION: {
+ case SEARCH_WEBSITE: {
- if (!current)
- return;
- quick_open->popup(current->get_functions());
+ OS::get_singleton()->shell_open("http://www.godotengine.org/projects/godot-engine/wiki/Documentation#Tutorials");
} 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: {
+ case WINDOW_NEXT: {
- if (debugger)
- debugger->debug_next();
+ _history_forward();
} break;
- case DEBUG_STEP: {
-
- if (debugger)
- debugger->debug_step();
-
+ case WINDOW_PREV: {
+ _history_back();
} break;
- case DEBUG_BREAK: {
- if (debugger)
- debugger->debug_break();
+ }
- } break;
- case DEBUG_CONTINUE: {
- if (debugger)
- debugger->debug_continue();
+ int selected = tab_container->get_current_tab();
+ if (selected<0 || selected>=tab_container->get_child_count())
+ return;
- } break;
- case DEBUG_SHOW: {
- if (debugger) {
- bool visible = debug_menu->get_popup()->is_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW) );
- debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW), !visible);
- if (visible)
- debugger->hide();
+ 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
- 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 WINDOW_CLOSE: {
-
- erase_tab_confirm->set_text("Close Tab?:\n\""+current->get_name()+"\"");
- erase_tab_confirm->popup_centered(Point2(250,80));
- } 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);
- tab_container->move_child(current,tab_container->get_current_tab()-1);
- _update_window_menu();
+ {
+ 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;
+ 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 DEBUG_SHOW: {
+ if (debugger) {
+ bool visible = debug_menu->get_popup()->is_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW) );
+ debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW), !visible);
+ if (visible)
+ debugger->hide();
+ else
+ 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 != "")
+ 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);
+
+ }
}
- } 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);
- tab_container->move_child(current,tab_container->get_current_tab()+1);
- _update_window_menu();
- }
+ EditorHelp *help = tab_container->get_child(selected)->cast_to<EditorHelp>();
+ if (help) {
+ switch(p_option) {
- } break;
- default: {
+ case SEARCH_FIND: {
+ help->popup_search();
+ } break;
+ case SEARCH_FIND_NEXT: {
+ help->search_again();
+ } break;
+ case FILE_CLOSE: {
+ _close_current_tab();
+ } break;
- if (p_option>=WINDOW_SELECT_BASE) {
- tab_container->set_current_tab(p_option-WINDOW_SELECT_BASE);
- }
}
}
+
}
void ScriptEditor::_tab_changed(int p_which) {
@@ -819,22 +1422,46 @@ void ScriptEditor::_tab_changed(int p_which) {
void ScriptEditor::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
editor->connect("play_pressed",this,"_editor_play");
editor->connect("pause_pressed",this,"_editor_pause");
editor->connect("stop_pressed",this,"_editor_stop");
editor->connect("script_add_function_request",this,"_add_callback");
editor->connect("resource_saved",this,"_res_saved_callback");
+ script_list->connect("item_selected",this,"_script_selected");
+ script_split->connect("dragged",this,"_script_split_dragged");
+ autosave_timer->connect("timeout",this,"_autosave_scripts");
+ {
+ float autosave_time = EditorSettings::get_singleton()->get("text_editor/autosave_interval_secs");
+ if (autosave_time>0) {
+ autosave_timer->set_wait_time(autosave_time);
+ autosave_timer->start();
+ } else {
+ autosave_timer->stop();
+ }
+ }
+
+ 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"));
+
+
}
if (p_what==NOTIFICATION_READY) {
- _update_window_menu();
+
+ get_tree()->connect("tree_changed",this,"_tree_changed");
+ editor->connect("request_help",this,"_request_help");
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
editor->disconnect("play_pressed",this,"_editor_play");
editor->disconnect("pause_pressed",this,"_editor_pause");
@@ -845,6 +1472,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) {
@@ -853,6 +1481,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) {
@@ -871,10 +1504,11 @@ static const Node * _find_node_with_script(const Node* p_node, const RefPtr & p_
Dictionary ScriptEditor::get_state() const {
- apply_scripts();
- Dictionary state;
+// apply_scripts();
+ Dictionary state;
+#if 0
Array paths;
int open=-1;
@@ -892,7 +1526,7 @@ Dictionary ScriptEditor::get_state() const {
} else {
- const Node *owner = _find_node_with_script(get_scene()->get_root(),script.get_ref_ptr());
+ const Node *owner = _find_node_with_script(get_tree()->get_root(),script.get_ref_ptr());
if (owner)
paths.push_back(owner->get_path());
@@ -907,12 +1541,12 @@ Dictionary ScriptEditor::get_state() const {
if (open!=-1)
state["current"]=open;
-
+#endif
return state;
}
void ScriptEditor::set_state(const Dictionary& p_state) {
-
+#if 0
print_line("attempt set state: "+String(Variant(p_state)));
if (!p_state.has("sources"))
@@ -928,7 +1562,7 @@ void ScriptEditor::set_state(const Dictionary& p_state) {
if (source.get_type()==Variant::NODE_PATH) {
- Node *owner=get_scene()->get_root()->get_node(source);
+ Node *owner=get_tree()->get_root()->get_node(source);
if (!owner)
continue;
@@ -949,10 +1583,11 @@ void ScriptEditor::set_state(const Dictionary& p_state) {
if (p_state.has("current")) {
tab_container->set_current_tab(p_state["current"]);
}
+#endif
}
void ScriptEditor::clear() {
-
+#if 0
List<ScriptTextEditor*> stes;
for(int i=0;i<tab_container->get_child_count();i++) {
@@ -972,24 +1607,18 @@ void ScriptEditor::clear() {
int idx = tab_container->get_current_tab();
if (idx>=tab_container->get_child_count())
idx=tab_container->get_child_count()-1;
- if (idx>=0)
+ if (idx>=0) {
tab_container->set_current_tab(idx);
+ script_list->select( script_list->find_metadata(idx) );
+ }
- _update_window_menu();
+#endif
}
-void ScriptEditor::_save_files_state() {
-
- return; //no thank you
-
- String rpath="_open_scripts_"+Globals::get_singleton()->get_resource_path();
- rpath=rpath.replace("\\","_-_");
- rpath=rpath.replace("/","_-_");
- rpath=rpath.replace(":","_");
- Vector<String> scripts;
+void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
for(int i=0;i<tab_container->get_child_count();i++) {
@@ -997,113 +1626,236 @@ void ScriptEditor::_save_files_state() {
if (!ste)
continue;
+ List<int> bpoints;
+ ste->get_text_edit()->get_breakpoints(&bpoints);
Ref<Script> script = ste->get_edited_script();
- if (script->get_path()!="" && script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) {
+ String base = script->get_path();
+ ERR_CONTINUE( base.begins_with("local://") || base=="" );
+ for(List<int>::Element *E=bpoints.front();E;E=E->next()) {
- scripts.push_back(script->get_path());
+ p_breakpoints->push_back(base+":"+itos(E->get()+1));
}
}
+}
+
+
+
- EditorSettings::get_singleton()->set(rpath,scripts);
- EditorSettings::get_singleton()->save();
+void ScriptEditor::ensure_focus_current() {
+
+ if (!is_inside_tree())
+ return;
+
+ int cidx = tab_container->get_current_tab();
+ if (cidx<0 || cidx>=tab_container->get_tab_count());
+ Control *c = tab_container->get_child(cidx)->cast_to<Control>();
+ if (!c)
+ return;
+ ScriptTextEditor *ste = c->cast_to<ScriptTextEditor>();
+ if (!ste)
+ return;
+ ste->get_text_edit()->grab_focus();
}
-void ScriptEditor::_load_files_state() {
- return;
+void ScriptEditor::_script_selected(int p_idx) {
- String rpath="_open_scripts_"+Globals::get_singleton()->get_resource_path();
- rpath=rpath.replace("\\","_-_");
- rpath=rpath.replace("/","_-_");
- rpath=rpath.replace(":","_");
+ grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(1); //amazing hack, simply amazing
- if (EditorSettings::get_singleton()->has(rpath)) {
+ _go_to_tab(script_list->get_item_metadata(p_idx));
+ grab_focus_block=false;
+}
+
+void ScriptEditor::ensure_select_current() {
+
+
+ if (tab_container->get_child_count() && tab_container->get_current_tab()>=0) {
+
+ 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();
- Vector<String> open_files=EditorSettings::get_singleton()->get("rpath");
- for(int i=0;i<open_files.size();i++) {
- Ref<Script> scr = ResourceLoader::load(open_files[i]);
- if (!scr.is_valid())
- continue;
- editor->edit_resource(scr);
+ }
+
+ EditorHelp *eh = current->cast_to<EditorHelp>();
+
+ if (eh) {
+ edit_menu->hide();
+ search_menu->hide();
+ script_search_menu->show();
+
}
}
-}
-void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
- for(int i=0;i<tab_container->get_child_count();i++) {
- ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
- if (!ste)
- continue;
- List<int> bpoints;
- ste->get_text_edit()->get_breakpoints(&bpoints);
+}
- Ref<Script> script = ste->get_edited_script();
- String base = script->get_path();
- ERR_CONTINUE( base.begins_with("local://") || base=="" );
+void ScriptEditor::_find_scripts(Node* p_base, Node* p_current, Set<Ref<Script> > &used) {
+ if (p_current!=p_base && p_current->get_owner()!=p_base)
+ return;
- for(List<int>::Element *E=bpoints.front();E;E=E->next()) {
+ if (p_current->get_script_instance()) {
+ Ref<Script> scr = p_current->get_script();
+ if (scr.is_valid())
+ used.insert(scr);
+ }
- p_breakpoints->push_back(base+":"+itos(E->get()+1));
- }
+ for(int i=0;i<p_current->get_child_count();i++) {
+ _find_scripts(p_base,p_current->get_child(i),used);
}
}
+struct _ScriptEditorItemData {
+ String name;
+ Ref<Texture> icon;
+ int index;
+ String tooltip;
+ bool used;
+ int category;
-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);
+ bool operator<(const _ScriptEditorItemData& id) const {
-}
+ return category==id.category?name.nocasecmp_to(id.name)<0:category<id.category;
+ }
+};
-void ScriptEditor::ensure_focus_current() {
- int cidx = tab_container->get_current_tab();
- if (cidx<0 || cidx>=tab_container->get_tab_count());
- Control *c = tab_container->get_child(cidx)->cast_to<Control>();
- if (!c)
- return;
- ScriptTextEditor *ste = c->cast_to<ScriptTextEditor>();
- if (!ste)
+void ScriptEditor::_update_script_colors() {
+
+ bool enabled = EditorSettings::get_singleton()->get("text_editor/script_temperature_enabled");
+ if (!enabled)
return;
- ste->get_text_edit()->grab_focus();
+
+ 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_t(hist_size),0.4);
+
+
+ script_list->set_item_custom_bg_color(i,hot_color.linear_interpolate(cold_color,v));
+ }
}
-void ScriptEditor::ensure_select_current() {
+void ScriptEditor::_update_script_names() {
+ waiting_update_names=false;
+ Set<Ref<Script> > used;
+ Node* edited = EditorNode::get_singleton()->get_edited_scene();
+ if (edited) {
+ _find_scripts(edited,edited,used);
+ }
- if (tab_container->get_child_count() && tab_container->get_current_tab()>=0) {
+ 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) {
+
+ String name = ste->get_name();
+ Ref<Texture> icon = ste->get_icon();
+ String tooltip = ste->get_edited_script()->get_path();
+
+ _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);
+ }
+
+ 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);
+
+ }
- ScriptTextEditor *ste = tab_container->get_child(tab_container->get_current_tab())->cast_to<ScriptTextEditor>();
- if (!ste)
- return;
- Ref<Script> script = ste->get_edited_script();
- editor->call("_resource_selected",script);
}
+
+ 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()==sedata[i].index) {
+ script_list->select(index);
+ script_name_label->set_text(sedata[i].name);
+ script_icon->set_texture(sedata[i].icon);
+
+ }
+ }
+
+ _update_script_colors();
+
+
+
+
}
void ScriptEditor::edit(const Ref<Script>& p_script) {
@@ -1113,6 +1865,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");
@@ -1141,9 +1895,14 @@ void ScriptEditor::edit(const Ref<Script>& p_script) {
if (ste->get_edited_script()==p_script) {
- if (tab_container->get_current_tab()!=i)
- tab_container->set_current_tab(i);
- ste->get_text_edit()->grab_focus();
+ if (open_dominant || !EditorNode::get_singleton()->is_changing_scene()) {
+ if (tab_container->get_current_tab()!=i) {
+ _go_to_tab(i);
+ script_list->select( script_list->find_metadata(i) );
+ }
+ if (is_visible())
+ ste->get_text_edit()->grab_focus();
+ }
return;
}
}
@@ -1153,12 +1912,18 @@ 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);
+
- _update_window_menu();
- _save_files_state();
+
+ _update_script_names();
+ ste->connect("name_changed",this,"_update_script_names");
+ if (!restoring_layout) {
+ EditorNode::get_singleton()->save_layout();
+ }
}
void ScriptEditor::save_external_data() {
@@ -1218,51 +1983,6 @@ void ScriptEditor::_editor_stop() {
debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true );
}
-void ScriptEditor::_update_window_menu() {
-
- int idx=0;
- for(int i=0;i<tab_container->get_child_count();i++) {
-
- ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
- if (!ste)
- continue;
- idx++;
- }
-
- if (idx==0) {
- window_menu->set_disabled(true);
- edit_menu->set_disabled(true);
- search_menu->set_disabled(true);
- return;
- } else {
-
- window_menu->set_disabled(false);
- edit_menu->set_disabled(false);
- search_menu->set_disabled(false);
- }
-
- window_menu->get_popup()->clear();
- window_menu->get_popup()->add_item("Close",WINDOW_CLOSE,KEY_MASK_CMD|KEY_W);
- window_menu->get_popup()->add_separator();
- window_menu->get_popup()->add_item("Move Left",WINDOW_MOVE_LEFT,KEY_MASK_CMD|KEY_LEFT);
- window_menu->get_popup()->add_item("Move Right",WINDOW_MOVE_RIGHT,KEY_MASK_CMD|KEY_RIGHT);
- window_menu->get_popup()->add_separator();
-
- idx=0;
- for(int i=0;i<tab_container->get_child_count();i++) {
-
- ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
- if (!ste)
- continue;
- String n = ste->get_name();
- uint32_t accel=0;
- if (idx<9) {
- accel=KEY_MASK_ALT|(KEY_1+idx);
- }
- window_menu->get_popup()->add_item(n,WINDOW_SELECT_BASE+idx,accel);
- idx++;
- }
-}
void ScriptEditor::_add_callback(Object *p_obj, const String& p_function, const StringArray& p_args) {
@@ -1282,10 +2002,10 @@ void ScriptEditor::_add_callback(Object *p_obj, const String& p_function, const
continue;
String code = ste->get_text_edit()->get_text();
- int pos = script->get_language()->find_function(code,p_function);
+ int pos = script->get_language()->find_function(p_function,code);
if (pos==-1) {
//does not exist
-
+ ste->get_text_edit()->deselect();
pos=ste->get_text_edit()->get_line_count()+2;
String func = script->get_language()->make_function("",p_function,p_args);
//code=code+func;
@@ -1294,18 +2014,285 @@ 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);
+ script_list->select( script_list->find_metadata(i) );
+
break;
}
}
+void ScriptEditor::_editor_settings_changed() {
+
+ print_line("settings changed");
+ float autosave_time = EditorSettings::get_singleton()->get("text_editor/autosave_interval_secs");
+ if (autosave_time>0) {
+ autosave_timer->set_wait_time(autosave_time);
+ autosave_timer->start();
+ } else {
+ autosave_timer->stop();
+ }
+
+}
+
+void ScriptEditor::_autosave_scripts() {
+
+ print_line("autosaving");
+ save_external_data();
+}
+
+void ScriptEditor::_tree_changed() {
+
+ if (waiting_update_names)
+ return;
+
+ waiting_update_names=true;
+ call_deferred("_update_script_names");
+}
+
+void ScriptEditor::_script_split_dragged(float) {
+
+ EditorNode::get_singleton()->save_layout();
+}
+
+void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
+
+ if (!bool(EDITOR_DEF("text_editor/restore_scripts_on_load",true))) {
+ return;
+ }
+
+ 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;
+
+ for(int i=0;i<scripts.size();i++) {
+
+ String path = scripts[i];
+ Ref<Script> scr = ResourceLoader::load(path);
+ if (scr.is_valid()) {
+ edit(scr);
+ }
+ }
+
+
+ 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"));
+ }
+
+
+ restoring_layout=false;
+
+}
+
+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) {
+
+ 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());
+ }
+
+
+ }
+
+ 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 (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;
menu_hb = memnew( HBoxContainer );
@@ -1315,24 +2302,43 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
add_child(v_split);
v_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ script_split = memnew( HSplitContainer );
+ v_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(70,0));
+ script_split->set_split_offset(70);
+
tab_container = memnew( TabContainer );
- v_split->add_child(tab_container);
- tab_container->set_v_size_flags(SIZE_EXPAND_FILL);
+ tab_container->set_tabs_visible(false);
+ script_split->add_child(tab_container);
+
+
+ tab_container->set_h_size_flags(SIZE_EXPAND_FILL);
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_item("Save",FILE_SAVE,KEY_MASK_ALT|KEY_S);
+ 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");
edit_menu = memnew( MenuButton );
menu_hb->add_child(edit_menu);
edit_menu->set_text("Edit");
- edit_menu->get_popup()->add_item("Undo");
- edit_menu->get_popup()->add_item("Redo");
+ edit_menu->get_popup()->add_item("Undo",EDIT_UNDO,KEY_MASK_CMD|KEY_Z);
+ edit_menu->get_popup()->add_item("Redo",EDIT_REDO,KEY_MASK_CMD|KEY_Y);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_item("Cut",EDIT_CUT,KEY_MASK_CMD|KEY_X);
edit_menu->get_popup()->add_item("Copy",EDIT_COPY,KEY_MASK_CMD|KEY_C);
@@ -1340,7 +2346,18 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_item("Select All",EDIT_SELECT_ALL,KEY_MASK_CMD|KEY_A);
edit_menu->get_popup()->add_separator();
+ edit_menu->get_popup()->add_item("Move Up",EDIT_MOVE_LINE_UP,KEY_MASK_ALT|KEY_UP);
+ edit_menu->get_popup()->add_item("Move Down",EDIT_MOVE_LINE_DOWN,KEY_MASK_ALT|KEY_DOWN);
+ edit_menu->get_popup()->add_item("Indent Left",EDIT_INDENT_LEFT,KEY_MASK_ALT|KEY_LEFT);
+ edit_menu->get_popup()->add_item("Indent Right",EDIT_INDENT_RIGHT,KEY_MASK_ALT|KEY_RIGHT);
+ edit_menu->get_popup()->add_item("Toggle Comment",EDIT_TOGGLE_COMMENT,KEY_MASK_CMD|KEY_K);
+ edit_menu->get_popup()->add_item("Clone Down",EDIT_CLONE_DOWN,KEY_MASK_CMD|KEY_B);
+ edit_menu->get_popup()->add_separator();
+#ifdef OSX_ENABLED
+ edit_menu->get_popup()->add_item("Complete Symbol",EDIT_COMPLETE,KEY_MASK_CTRL|KEY_SPACE);
+#else
edit_menu->get_popup()->add_item("Complete Symbol",EDIT_COMPLETE,KEY_MASK_CMD|KEY_SPACE);
+#endif
edit_menu->get_popup()->add_item("Auto Indent",EDIT_AUTO_INDENT,KEY_MASK_CMD|KEY_I);
edit_menu->get_popup()->connect("item_pressed", this,"_menu_option");
@@ -1349,13 +2366,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");
@@ -1376,6 +2402,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true );
+#if 0
window_menu = memnew( MenuButton );
menu_hb->add_child(window_menu);
window_menu->set_text("Window");
@@ -1386,12 +2413,61 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
window_menu->get_popup()->add_separator();
window_menu->get_popup()->connect("item_pressed", this,"_menu_option");
+#endif
+
help_menu = memnew( MenuButton );
menu_hb->add_child(help_menu);
help_menu->set_text("Help");
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);
@@ -1401,6 +2477,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);
@@ -1443,11 +2523,35 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
v_split->add_child(debugger);
debugger->connect("breaked",this,"_breaked");
+
+ autosave_timer = memnew( Timer );
+ autosave_timer->set_one_shot(false);
+ add_child(autosave_timer);
+
+ 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>())
@@ -1507,26 +2611,35 @@ void ScriptEditorPlugin::apply_changes() {
void ScriptEditorPlugin::restore_global_state() {
- if (bool(EDITOR_DEF("text_editor/restore_scripts_on_load",true))) {
- script_editor->_load_files_state();
- }
}
void ScriptEditorPlugin::save_global_state() {
- if (bool(EDITOR_DEF("text_editor/restore_scripts_on_load",true))) {
- script_editor->_save_files_state();
- }
+}
+
+void ScriptEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
+
+ script_editor->set_window_layout(p_layout);
+}
+
+void ScriptEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout){
+ script_editor->get_window_layout(p_layout);
}
+
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;
@@ -1536,8 +2649,15 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
script_editor->hide();
+ 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 69b8739d67..7875b4d144 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 {
@@ -85,9 +88,10 @@ protected:
virtual void _validate_script();
- virtual void _code_complete_script(const String& p_code,const String& p_keyword, int p_line, List<String>* r_options);
+ virtual void _code_complete_script(const String& p_code, List<String>* r_options);
virtual void _load_theme_settings();
void _notification(int p_what);
+ static void _bind_methods();
public:
@@ -97,12 +101,15 @@ public:
Vector<String> get_functions() ;
void set_edited_script(const Ref<Script>& p_script);
void reload_text();
- void _update_name();
-
+ String get_name() ;
+ Ref<Texture> get_icon() ;
+ bool is_unsaved();
ScriptTextEditor();
};
+class EditorScriptCodeCompletionCache;
+
class ScriptEditor : public VBoxContainer {
OBJ_TYPE(ScriptEditor, VBoxContainer );
@@ -110,11 +117,12 @@ class ScriptEditor : public VBoxContainer {
EditorNode *editor;
enum {
-
+ FILE_NEW,
FILE_OPEN,
FILE_SAVE,
FILE_SAVE_AS,
FILE_SAVE_ALL,
+ FILE_CLOSE,
EDIT_UNDO,
EDIT_REDO,
EDIT_CUT,
@@ -123,21 +131,31 @@ class ScriptEditor : public VBoxContainer {
EDIT_SELECT_ALL,
EDIT_COMPLETE,
EDIT_AUTO_INDENT,
+ EDIT_TOGGLE_COMMENT,
+ EDIT_MOVE_LINE_UP,
+ EDIT_MOVE_LINE_DOWN,
+ EDIT_INDENT_RIGHT,
+ EDIT_INDENT_LEFT,
+ EDIT_CLONE_DOWN,
SEARCH_FIND,
SEARCH_FIND_NEXT,
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,
- WINDOW_CLOSE,
+ HELP_CONTEXTUAL,
WINDOW_MOVE_LEFT,
WINDOW_MOVE_RIGHT,
+ WINDOW_NEXT,
+ WINDOW_PREV,
WINDOW_SELECT_BASE=100
};
@@ -145,16 +163,47 @@ class ScriptEditor : public VBoxContainer {
MenuButton *file_menu;
MenuButton *edit_menu;
MenuButton *search_menu;
- MenuButton *window_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);
@@ -164,6 +213,8 @@ class ScriptEditor : public VBoxContainer {
VSplitContainer *v_split;
+ bool restoring_layout;
+
String _get_debug_tooltip(const String&p_text,Node *_ste);
void _resave_scripts(const String& p_str);
@@ -173,13 +224,18 @@ class ScriptEditor : public VBoxContainer {
void _close_current_tab();
+ bool grab_focus_block;
+
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);
@@ -188,6 +244,35 @@ 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();
+
+ void _update_script_names();
+
+ void _script_selected(int p_idx);
+
+ void _find_scripts(Node* p_base, Node* p_current,Set<Ref<Script> >& used);
+
+ void _tree_changed();
+
+ 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:
@@ -196,9 +281,6 @@ protected:
public:
static ScriptEditor *get_singleton() { return script_editor; }
- void _save_files_state();
- void _load_files_state();
-
void ensure_focus_current();
void apply_scripts() const;
@@ -212,11 +294,21 @@ public:
void get_breakpoints(List<String> *p_breakpoints);
-
+ void swap_lines(TextEdit *tx, int line1, int line2);
void save_external_data();
+ 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 {
@@ -244,8 +336,12 @@ public:
virtual void restore_global_state();
virtual void save_global_state();
+ virtual void set_window_layout(Ref<ConfigFile> p_layout);
+ virtual void get_window_layout(Ref<ConfigFile> p_layout);
+
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 73b6265819..848073af3e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -57,9 +57,9 @@ void ShaderTextEditor::set_edited_shader(const Ref<Shader>& p_shader,ShaderLangu
_load_theme_settings();
- if (p_type==ShaderLanguage::SHADER_MATERIAL_LIGHT)
+ if (p_type==ShaderLanguage::SHADER_MATERIAL_LIGHT || p_type==ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT)
get_text_edit()->set_text(shader->get_light_code());
- else if (p_type==ShaderLanguage::SHADER_MATERIAL_VERTEX)
+ else if (p_type==ShaderLanguage::SHADER_MATERIAL_VERTEX || p_type==ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX)
get_text_edit()->set_text(shader->get_vertex_code());
else
get_text_edit()->set_text(shader->get_fragment_code());
@@ -80,6 +80,8 @@ void ShaderTextEditor::_load_theme_settings() {
get_text_edit()->add_color_override("font_color",EDITOR_DEF("text_editor/text_color",Color(0,0,0)));
get_text_edit()->add_color_override("font_selected_color",EDITOR_DEF("text_editor/text_selected_color",Color(1,1,1)));
get_text_edit()->add_color_override("selection_color",EDITOR_DEF("text_editor/selection_color",Color(0.2,0.2,1)));
+ get_text_edit()->add_color_override("brace_mismatch_color",EDITOR_DEF("text_editor/brace_mismatch_color",Color(1,0.2,0.2)));
+ get_text_edit()->add_color_override("current_line_color",EDITOR_DEF("text_editor/current_line_color",Color(0.3,0.5,0.8,0.15)));
Color keyword_color= EDITOR_DEF("text_editor/keyword_color",Color(0.5,0.0,0.2));
@@ -130,24 +132,22 @@ void ShaderTextEditor::_validate_script() {
String errortxt;
int line,col;
- String code;
- if (type==ShaderLanguage::SHADER_MATERIAL_LIGHT)
- code=get_text_edit()->get_text();
- else if (type==ShaderLanguage::SHADER_MATERIAL_VERTEX)
- code=get_text_edit()->get_text();
- else
- code=get_text_edit()->get_text();
-
+ String code=get_text_edit()->get_text();
//List<StringName> params;
//shader->get_param_list(&params);
+ print_line("compile: type: "+itos(type)+" code:\n"+code);
+
Error err = ShaderLanguage::compile(code,type,NULL,NULL,&errortxt,&line,&col);
if (err!=OK) {
- String error_text="error("+itos(line)+","+itos(col)+"): "+errortxt;
+ String error_text="error("+itos(line+1)+","+itos(col)+"): "+errortxt;
set_error(error_text);
+ get_text_edit()->set_line_as_marked(line,true);
} else {
+ for(int i=0;i<get_text_edit()->get_line_count();i++)
+ get_text_edit()->set_line_as_marked(i,false);
set_error("");
}
@@ -229,36 +229,23 @@ void ShaderEditor::_menu_option(int p_option) {
goto_line_dialog->popup_find_line(current->get_text_edit());
} break;
- case SHADER_POST_PROCESS_MODE:{
-
- fragment_editor->set_edited_shader(shader,ShaderLanguage::SHADER_POST_PROCESS);
- fragment_editor->_validate_script();
- apply_shaders();
- settings_menu->get_popup()->set_item_checked( settings_menu->get_popup()->get_item_index(SHADER_MATERIAL_MODE), false);
- settings_menu->get_popup()->set_item_checked( settings_menu->get_popup()->get_item_index(SHADER_POST_PROCESS_MODE), true);
-
- } break;
- case SHADER_MATERIAL_MODE: {
-
- fragment_editor->set_edited_shader(shader,ShaderLanguage::SHADER_MATERIAL_FRAGMENT);
- fragment_editor->_validate_script();
- apply_shaders();
- settings_menu->get_popup()->set_item_checked( settings_menu->get_popup()->get_item_index(SHADER_MATERIAL_MODE), true);
- settings_menu->get_popup()->set_item_checked( settings_menu->get_popup()->get_item_index(SHADER_POST_PROCESS_MODE), false);
-
- } break;
}
}
void ShaderEditor::_tab_changed(int p_which) {
+ ShaderTextEditor *shader_editor = tab_container->get_child(p_which)->cast_to<ShaderTextEditor>();
+
+ if (shader_editor)
+ shader_editor->get_text_edit()->grab_focus();
+
ensure_select_current();
}
void ShaderEditor::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
close->set_normal_texture( get_icon("Close","EditorIcons"));
close->set_hover_texture( get_icon("CloseHover","EditorIcons"));
@@ -404,18 +391,17 @@ void ShaderEditor::edit(const Ref<Shader>& p_shader) {
shader=p_shader;
if (shader->get_mode()==Shader::MODE_MATERIAL) {
+ vertex_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_MATERIAL_VERTEX);
fragment_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_MATERIAL_FRAGMENT);
light_editor->set_edited_shader(shader,ShaderLanguage::SHADER_MATERIAL_LIGHT);
- settings_menu->get_popup()->set_item_checked( settings_menu->get_popup()->get_item_index(SHADER_MATERIAL_MODE), true);
- settings_menu->get_popup()->set_item_checked( settings_menu->get_popup()->get_item_index(SHADER_POST_PROCESS_MODE), false);
- } else {
+ } else if (shader->get_mode()==Shader::MODE_CANVAS_ITEM) {
- fragment_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_POST_PROCESS);
- settings_menu->get_popup()->set_item_checked( settings_menu->get_popup()->get_item_index(SHADER_MATERIAL_MODE), false);
- settings_menu->get_popup()->set_item_checked( settings_menu->get_popup()->get_item_index(SHADER_POST_PROCESS_MODE), true);
+ vertex_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX);
+ fragment_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT);
+ light_editor->set_edited_shader(shader,ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT);
}
- vertex_editor->set_edited_shader(shader,ShaderLanguage::SHADER_MATERIAL_VERTEX);
+ //vertex_editor->set_edited_shader(shader,ShaderLanguage::SHADER_MATERIAL_VERTEX);
// see if already has it
@@ -436,8 +422,10 @@ void ShaderEditor::save_external_data() {
void ShaderEditor::apply_shaders() {
- if (shader.is_valid())
+ if (shader.is_valid()) {
shader->set_code(vertex_editor->get_text_edit()->get_text(),fragment_editor->get_text_edit()->get_text(),light_editor->get_text_edit()->get_text(),0,0);
+ shader->set_edited(true);
+ }
}
void ShaderEditor::_close_callback() {
@@ -489,15 +477,6 @@ ShaderEditor::ShaderEditor() {
search_menu->get_popup()->add_item("Goto Line..",SEARCH_GOTO_LINE,KEY_MASK_CMD|KEY_G);
search_menu->get_popup()->connect("item_pressed", this,"_menu_option");
- settings_menu = memnew( MenuButton );
- add_child(settings_menu);
- settings_menu->set_pos(Point2(90,-1));
- settings_menu->set_text("Shader");
- settings_menu->get_popup()->add_check_item("Material Mode",SHADER_MATERIAL_MODE);
- settings_menu->get_popup()->set_item_checked(settings_menu->get_popup()->get_item_index(SHADER_MATERIAL_MODE),true);
- settings_menu->get_popup()->add_check_item("Post Process Mode",SHADER_POST_PROCESS_MODE);
-
- settings_menu->get_popup()->connect("item_pressed", this,"_menu_option");
tab_container->connect("tab_changed", this,"_tab_changed");
@@ -544,7 +523,13 @@ void ShaderEditorPlugin::edit(Object *p_object) {
bool ShaderEditorPlugin::handles(Object *p_object) const {
- return p_object->is_type("Shader");
+ Shader *shader=p_object->cast_to<Shader>();
+ if (!shader)
+ return false;
+ if (_2d)
+ return shader->get_mode()==Shader::MODE_CANVAS_ITEM;
+ else
+ return shader->get_mode()==Shader::MODE_MATERIAL;
}
void ShaderEditorPlugin::make_visible(bool p_visible) {
@@ -590,12 +575,15 @@ void ShaderEditorPlugin::apply_changes() {
shader_editor->apply_shaders();
}
-ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) {
+ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node, bool p_2d) {
editor=p_node;
shader_editor = memnew( ShaderEditor );
-
- SpatialEditor::get_singleton()->get_shader_split()->add_child(shader_editor);
+ _2d=p_2d;
+ if (p_2d)
+ add_custom_control(CONTAINER_CANVAS_EDITOR_BOTTOM,shader_editor);
+ else
+ add_custom_control(CONTAINER_SPATIAL_EDITOR_BOTTOM,shader_editor);
// editor->get_viewport()->add_child(shader_editor);
// shader_editor->set_area_as_parent_rect();
diff --git a/tools/editor/plugins/shader_editor_plugin.h b/tools/editor/plugins/shader_editor_plugin.h
index 49caee5da6..4ead2ba94e 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -79,9 +79,6 @@ class ShaderEditor : public Control {
SEARCH_REPLACE,
//SEARCH_LOCATE_SYMBOL,
SEARCH_GOTO_LINE,
- SHADER_MATERIAL_MODE,
- SHADER_POST_PROCESS_MODE,
- SHADER_SHADE_MODEL_MODE,
};
@@ -134,6 +131,7 @@ class ShaderEditorPlugin : public EditorPlugin {
OBJ_TYPE( ShaderEditorPlugin, EditorPlugin );
+ bool _2d;
ShaderEditor *shader_editor;
EditorNode *editor;
public:
@@ -152,7 +150,7 @@ public:
virtual void save_external_data();
virtual void apply_changes();
- ShaderEditorPlugin(EditorNode *p_node);
+ ShaderEditorPlugin(EditorNode *p_node,bool p_2d);
~ShaderEditorPlugin();
};
diff --git a/tools/editor/plugins/shader_graph_editor_plugin.cpp b/tools/editor/plugins/shader_graph_editor_plugin.cpp
index 2686ca895e..3a7dc26466 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -28,1082 +28,2807 @@
/*************************************************************************/
#include "shader_graph_editor_plugin.h"
-#if 0
+
+#include "scene/gui/check_box.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
+#include "spatial_editor_plugin.h"
+#include "os/keyboard.h"
+#include "canvas_item_editor_plugin.h"
-class _ShaderTester : public ShaderCodeGenerator {
-public:
+void GraphColorRampEdit::_input_event(const InputEvent& p_event) {
- Set<int> *_set;
+ if (p_event.type==InputEvent::KEY && p_event.key.pressed && p_event.key.scancode==KEY_DELETE && grabbed!=-1) {
- virtual void begin() {}
- virtual Error add_node(VS::ShaderNodeType p_type,int p_node_pos,int p_id,const Variant& p_param,const Vector<int>& p_in_connections,const Vector<int>& p_out_connections,const Vector<int>& p_out_connection_outputs) { if (_set) _set->insert(p_id); return OK; }
- virtual void end() {}
+ points.remove(grabbed);
+ grabbed=-1;
+ update();
+ emit_signal("ramp_changed");
+ accept_event();
+ }
- _ShaderTester() { _set=NULL; }
-};
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
+
+ update();
+ int x = p_event.mouse_button.x;
+ int total_w = get_size().width-get_size().height-3;
+ if (x>total_w+3) {
+
+ if (grabbed==-1)
+ return;
+ Size2 ms = Size2(350, picker->get_combined_minimum_size().height+10);
+ picker->set_color(points[grabbed].color);
+ popup->set_pos(get_global_pos()-Size2(0,ms.height));
+ popup->set_size(ms);
+ popup->popup();
+ return;
+ }
+ float ofs = CLAMP(x/float(total_w),0,1);
-void ShaderEditor::edit(Ref<Shader> p_shader) {
+ grabbed=-1;
+ grabbing=true;
+ int pos=-1;
+ for(int i=0;i<points.size();i++) {
+ if (ABS(x-points[i].offset*total_w)<4) {
+ grabbed=i;
+ }
+ if (points[i].offset<ofs)
+ pos=i;
+ }
- shader=p_shader;
+ grabbed_at=ofs;
+ //grab or select
+ if (grabbed!=-1) {
+ return;
+ }
+ //insert
- if (shader.is_null())
- hide();
- else {
- _read_shader_graph();
- }
-}
+ Point p;
+ p.offset=ofs;
-Size2 ShaderEditor::_get_maximum_size() {
+ Point prev;
+ Point next;
- Size2 max;
+ if (pos==-1) {
- for(List<int>::Element *E=order.front();E;E=E->next()) {
+ prev.color=Color(0,0,0);
+ prev.offset=0;
+ if (points.size()) {
+ next=points[0];
+ } else {
+ next.color=Color(1,1,1);
+ next.offset=1.0;
+ }
+ } else {
- Point2 pos = Point2( shader_graph.node_get_pos_x(E->get()), shader_graph.node_get_pos_y(E->get()) );
+ if (pos==points.size()-1) {
+ next.color=Color(1,1,1);
+ next.offset=1.0;
+ } else {
+ next=points[pos+1];
+ }
+ prev=points[pos];
- if (click_type==CLICK_NODE && click_node==E->get()) {
+ }
+
+ p.color=prev.color.linear_interpolate(next.color,(p.offset-prev.offset)/(next.offset-prev.offset));
- pos+=click_motion-click_pos;
+ points.push_back(p);
+ points.sort();
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset==ofs) {
+ grabbed=i;
+ break;
+ }
}
- pos+=get_node_size(E->get());
- if (pos.x>max.x)
- max.x=pos.x;
- if (pos.y>max.y)
- max.y=pos.y;
+
+ emit_signal("ramp_changed");
}
- return max;
-}
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && !p_event.mouse_button.pressed) {
-Size2 ShaderEditor::get_node_size(int p_node) const {
+ if (grabbing) {
+ grabbing=false;
+ emit_signal("ramp_changed");
+ }
+ update();
+ }
- VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node);
- Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
- Ref<Font> font = get_font("font","PopupMenu");
- Color font_color = get_color("font_color","PopupMenu");
+ if (p_event.type==InputEvent::MOUSE_MOTION && grabbing) {
- Size2 size = style->get_minimum_size();
+ int total_w = get_size().width-get_size().height-3;
- int count=1; // title
- count += VisualServer::shader_get_input_count( type) + VisualServer::shader_get_output_count( type);
+ int x = p_event.mouse_motion.x;
+ float newofs = CLAMP(x/float(total_w),0,1);
- float max_w=font->get_string_size( VisualServer::shader_node_get_type_info(type).name ).width;
+ bool valid=true;
+ for(int i=0;i<points.size();i++) {
- for(int i=0;i<VisualServer::shader_get_input_count(type);i++)
- max_w = MAX( max_w, font->get_string_size( VisualServer::shader_get_input_name(type,i) ).width );
+ if (points[i].offset==newofs && i!=grabbed) {
+ valid=false;
+ }
+ }
+ if (!valid)
+ return;
- for(int i=0;i<VisualServer::shader_get_output_count(type);i++)
- max_w = MAX( max_w, font->get_string_size( VisualServer::shader_get_output_name(type,i) ).width );
+ points[grabbed].offset=newofs;
+ points.sort();
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset==newofs) {
+ grabbed=i;
+ break;
+ }
+ }
+ emit_signal("ramp_changed");
+ update();
+ }
+}
- switch(type) {
+void GraphColorRampEdit::_notification(int p_what){
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+ picker->connect("color_changed",this,"_color_changed");
+ }
+ if (p_what==NOTIFICATION_DRAW) {
- case VS::NODE_IN:
- case VS::NODE_OUT:
- case VS::NODE_VEC_IN:
- case VS::NODE_VEC_OUT:
- case VS::NODE_PARAMETER:
- case VS::NODE_VEC_PARAMETER:
- case VS::NODE_COLOR_PARAMETER:
- case VS::NODE_TEXTURE_PARAMETER:
- case VS::NODE_TEXTURE_2D_PARAMETER:
- case VS::NODE_TEXTURE_CUBE_PARAMETER:
- case VS::NODE_TRANSFORM_PARAMETER:
- case VS::NODE_LABEL: {
- max_w=MAX( max_w, font->get_string_size( shader_graph.node_get_param(p_node) ).width );
- count++;
- } break;
- case VS::NODE_TIME:
- case VS::NODE_CONSTANT:
- case VS::NODE_VEC_CONSTANT:
- case VS::NODE_COLOR_CONSTANT:
- case VS::NODE_TRANSFORM_CONSTANT: {
- count++;
- } break;
- case VS::NODE_TEXTURE:
- case VS::NODE_VEC_TEXTURE_2D:
- case VS::NODE_VEC_TEXTURE_CUBE: {
+ Point prev;
+ prev.offset=0;
+ prev.color=Color(0,0,0);
+ int w = get_size().x;
+ int h = get_size().y;
- RefPtr res = shader_graph.node_get_param(p_node);
- Ref<Texture> texture = res;
- if (texture.is_null() || texture->get_width()==0) {
+ int total_w = get_size().width-get_size().height-3;
- size.y+=max_w;
+ for(int i=-1;i<points.size();i++) {
+
+ Point next;
+ if (i+1==points.size()) {
+ next.color=Color(1,1,1);
+ next.offset=1;
} else {
+ next=points[i+1];
+ }
- size.y+=max_w * texture->get_height() / texture->get_width();
+ if (prev.offset==next.offset) {
+ prev=next;
+ continue;
}
- } break;
- default: {}
+
+ Vector<Vector2> points;
+ Vector<Color> colors;
+ points.push_back(Vector2(prev.offset*total_w,h));
+ points.push_back(Vector2(prev.offset*total_w,0));
+ points.push_back(Vector2(next.offset*total_w,0));
+ points.push_back(Vector2(next.offset*total_w,h));
+ colors.push_back(prev.color);
+ colors.push_back(prev.color);
+ colors.push_back(next.color);
+ colors.push_back(next.color);
+ draw_primitive(points,colors,Vector<Point2>());
+ prev=next;
+ }
+
+ for(int i=0;i<points.size();i++) {
+
+ Color col=i==grabbed?Color(1,0.0,0.0,0.9):Color(1,1,1,0.8);
+
+ draw_line(Vector2(points[i].offset*total_w,0),Vector2(points[i].offset*total_w,h-1),Color(0,0,0,0.7));
+ draw_line(Vector2(points[i].offset*total_w-1,h/2),Vector2(points[i].offset*total_w-1,h-1),col);
+ draw_line(Vector2(points[i].offset*total_w+1,h/2),Vector2(points[i].offset*total_w+1,h-1),col);
+ draw_line(Vector2(points[i].offset*total_w-1,h/2),Vector2(points[i].offset*total_w+1,h/2),col);
+ draw_line(Vector2(points[i].offset*total_w-1,h-1),Vector2(points[i].offset*total_w+1,h-1),col);
+
+ }
+
+ if (grabbed!=-1) {
+
+ draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color);
+ }
+
+ if (has_focus()) {
+
+ draw_line(Vector2(-1,-1),Vector2(total_w+1,-1),Color(1,1,1,0.6));
+ draw_line(Vector2(total_w+1,-1),Vector2(total_w+1,h+1),Color(1,1,1,0.6));
+ draw_line(Vector2(total_w+1,h+1),Vector2(-1,h+1),Color(1,1,1,0.6));
+ draw_line(Vector2(-1,-1),Vector2(-1,h+1),Color(1,1,1,0.6));
+ }
}
+}
- size.x+=max_w;
- size.y+=count*(font->get_height()+get_constant("vseparation","PopupMenu"));
+Size2 GraphColorRampEdit::get_minimum_size() const {
- return size;
+ return Vector2(0,16);
}
-Error ShaderEditor::validate_graph() {
+void GraphColorRampEdit::_color_changed(const Color& p_color) {
+
+ if (grabbed==-1)
+ return;
+ points[grabbed].color=p_color;
+ update();
+ emit_signal("ramp_changed");
- _ShaderTester st;
- active_nodes.clear();
- st._set=&active_nodes;
- return shader_graph.generate(&st);
}
-void ShaderEditor::_draw_node(int p_node) {
+void GraphColorRampEdit::set_ramp(const Vector<float>& p_offsets,const Vector<Color>& p_colors) {
+
+ ERR_FAIL_COND(p_offsets.size()!=p_colors.size());
+ points.clear();
+ for(int i=0;i<p_offsets.size();i++) {
+ Point p;
+ p.offset=p_offsets[i];
+ p.color=p_colors[i];
+ points.push_back(p);
+ }
- VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node);
- Ref<StyleBox> style = active_nodes.has(p_node)?get_stylebox("panel","PopupMenu"):get_stylebox("panel_disabled","PopupMenu");
- Ref<Font> font = get_font("font","PopupMenu");
- Color font_color = get_color("font_color","PopupMenu");
- Color font_color_title = get_color("font_color_hover","PopupMenu");
- Size2 size=get_node_size(p_node);
- Point2 pos = Point2( shader_graph.node_get_pos_x(p_node), shader_graph.node_get_pos_y(p_node) )-offset;
+ points.sort();
+ update();
+}
- if (click_type==CLICK_NODE && click_node==p_node) {
+Vector<float> GraphColorRampEdit::get_offsets() const{
+ Vector<float> ret;
+ for(int i=0;i<points.size();i++)
+ ret.push_back(points[i].offset);
+ return ret;
+}
+Vector<Color> GraphColorRampEdit::get_colors() const{
- pos+=click_motion-click_pos;
+ Vector<Color> ret;
+ for(int i=0;i<points.size();i++)
+ ret.push_back(points[i].color);
+ return ret;
+}
+
+
+void GraphColorRampEdit::_bind_methods(){
+
+ ObjectTypeDB::bind_method(_MD("_input_event"),&GraphColorRampEdit::_input_event);
+ ObjectTypeDB::bind_method(_MD("_color_changed"),&GraphColorRampEdit::_color_changed);
+ ADD_SIGNAL(MethodInfo("ramp_changed"));
+}
+
+GraphColorRampEdit::GraphColorRampEdit(){
+
+ grabbed=-1;
+ grabbing=false;
+ set_focus_mode(FOCUS_ALL);
+
+ popup = memnew( PopupPanel );
+ picker = memnew( ColorPicker );
+ popup->add_child(picker);
+ popup->set_child_rect(picker);
+ add_child(popup);
+
+}
+////////////
+
+void GraphCurveMapEdit::_input_event(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::KEY && p_event.key.pressed && p_event.key.scancode==KEY_DELETE && grabbed!=-1) {
+
+ points.remove(grabbed);
+ grabbed=-1;
+ update();
+ emit_signal("curve_changed");
+ accept_event();
}
- RID ci = get_canvas_item();
- style->draw(ci,Rect2(pos,size));
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
+
+ update();
+ Point2 p = Vector2(p_event.mouse_button.x,p_event.mouse_button.y)/get_size();
+ p.y=1.0-p.y;
+ grabbed=-1;
+ grabbing=true;
- Point2 ofs=style->get_offset()+pos;
- Point2 ascent=Point2(0,font->get_ascent());
- float w = size.width-style->get_minimum_size().width;
- float h = font->get_height()+get_constant("vseparation","PopupMenu");
+ for(int i=0;i<points.size();i++) {
- font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, VisualServer::shader_node_get_type_info(type).name,font_color_title);
- ofs.y+=h;
+ Vector2 ps = p*get_size();
+ Vector2 pt = Vector2(points[i].offset,points[i].height)*get_size();
+ if (ps.distance_to(pt)<4) {
+ grabbed=i;
+ }
- Ref<Texture> vec_icon = get_icon("NodeVecSlot","EditorIcons");
- Ref<Texture> real_icon = get_icon("NodeRealSlot","EditorIcons");
- float icon_h_ofs = Math::floor(( font->get_height()-vec_icon->get_height())/2.0 )+1;
+ }
+
+
+ //grab or select
+ if (grabbed!=-1) {
+ return;
+ }
+ //insert
- for(int i=0;i<VisualServer::shader_get_input_count(type);i++) {
+ Point np;
+ np.offset=p.x;
+ np.height=p.y;
+
+ points.push_back(np);
+ points.sort();
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset==p.x && points[i].height==p.y) {
+ grabbed=i;
+ break;
+ }
+ }
+
+ emit_signal("curve_changed");
- String name = VisualServer::shader_get_input_name(type,i);
- font->draw_halign( ci, ofs+ascent, HALIGN_LEFT,w, name,font_color);
- Ref<Texture> icon = VisualServer::shader_is_input_vector(type,i)?vec_icon:real_icon;
- icon->draw(ci,ofs+Point2(-real_icon->get_width(),icon_h_ofs));
- ofs.y+=h;
}
- for(int i=0;i<VisualServer::shader_get_output_count(type);i++) {
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && !p_event.mouse_button.pressed) {
- String name = VisualServer::shader_get_output_name(type,i);
- font->draw_halign( ci, ofs+ascent, HALIGN_RIGHT,w, name,font_color);
- Ref<Texture> icon = VisualServer::shader_is_output_vector(type,i)?vec_icon:real_icon;
- icon->draw(ci,ofs+Point2(w,icon_h_ofs));
- ofs.y+=h;
+ if (grabbing) {
+ grabbing=false;
+ emit_signal("curve_changed");
+ }
+ update();
}
- switch(type) {
-
- case VS::NODE_IN:
- case VS::NODE_OUT:
- case VS::NODE_PARAMETER:
- case VS::NODE_VEC_IN:
- case VS::NODE_COLOR_PARAMETER:
- case VS::NODE_VEC_OUT:
- case VS::NODE_TEXTURE_PARAMETER:
- case VS::NODE_TEXTURE_2D_PARAMETER:
- case VS::NODE_TEXTURE_CUBE_PARAMETER:
- case VS::NODE_TRANSFORM_CONSTANT:
- case VS::NODE_TRANSFORM_PARAMETER:
- case VS::NODE_VEC_PARAMETER:
- case VS::NODE_LABEL: {
- String text = shader_graph.node_get_param(p_node);
- font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color);
- } break;
- case VS::NODE_TIME:
- case VS::NODE_CONSTANT: {
- String text = rtos(shader_graph.node_get_param(p_node));
- font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color);
-
- } break;
- case VS::NODE_VEC_CONSTANT: {
- String text = Vector3(shader_graph.node_get_param(p_node));
- font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color);
- } break;
- case VS::NODE_COLOR_CONSTANT: {
-
- Color color = shader_graph.node_get_param(p_node);
- Rect2 r(ofs,Size2(w,h));
- VisualServer::get_singleton()->canvas_item_add_rect(ci,r,color);
- } break;
- case VS::NODE_TEXTURE:
- case VS::NODE_VEC_TEXTURE_2D:
- case VS::NODE_VEC_TEXTURE_CUBE: {
-
- Rect2 r(ofs,Size2(w,(pos.y+size.y-style->get_margin(MARGIN_BOTTOM))-ofs.y));
- Vector<Point2> points;
- Vector<Point2> uvs;
- points.resize(4);
- uvs.resize(4);
- points[0]=r.pos;
- points[1]=r.pos+Point2(r.size.x,0);
- points[2]=r.pos+r.size;
- points[3]=r.pos+Point2(0,r.size.y);
- uvs[0]=Point2(0,0);
- uvs[1]=Point2(1,0);
- uvs[2]=Point2(1,1);
- uvs[3]=Point2(0,1);
-
- Ref<Texture> texture = shader_graph.node_get_param(p_node).operator RefPtr();
- if (texture.is_null() || texture->get_width()==0) {
- texture=get_icon("Click2Edit","EditorIcons");
+ if (p_event.type==InputEvent::MOUSE_MOTION && grabbing && grabbed != -1) {
+
+ Point2 p = Vector2(p_event.mouse_button.x,p_event.mouse_button.y)/get_size();
+ p.y=1.0-p.y;
+
+ p.x = CLAMP(p.x,0.0,1.0);
+ p.y = CLAMP(p.y,0.0,1.0);
+
+ bool valid=true;
+
+ for(int i=0;i<points.size();i++) {
+
+ if (points[i].offset==p.x && points[i].height==p.y && i!=grabbed) {
+ valid=false;
}
+ }
+
+ if (!valid)
+ return;
+
+ points[grabbed].offset=p.x;
+ points[grabbed].height=p.y;
- VisualServer::get_singleton()->canvas_item_add_primitive(ci,points,Vector<Color>(),uvs,texture->get_rid());
- } break;
- default: {}
+ points.sort();
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset==p.x && points[i].height==p.y) {
+ grabbed=i;
+ break;
+ }
+ }
+
+ emit_signal("curve_changed");
+
+ update();
}
}
-void ShaderEditor::_node_param_changed() {
+void GraphCurveMapEdit::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d) {
+
+ float geometry[4][4];
+ float tmp1[4][4];
+ float tmp2[4][4];
+ float deltas[4][4];
+ double x, dx, dx2, dx3;
+ double y, dy, dy2, dy3;
+ double d, d2, d3;
+ int lastx, lasty;
+ int newx, newy;
+ int ntimes;
+ int i,j;
+
+ int xmax=get_size().x;
+ int ymax=get_size().y;
+
+ /* construct the geometry matrix from the segment */
+ for (i = 0; i < 4; i++) {
+ geometry[i][2] = 0;
+ geometry[i][3] = 0;
+ }
- shader_graph.node_set_param( click_node,property_editor->get_variant() );
- update();
- _write_shader_graph();
-}
+ geometry[0][0] = (p_a[0] * xmax);
+ geometry[1][0] = (p_b[0] * xmax);
+ geometry[2][0] = (p_c[0] * xmax);
+ geometry[3][0] = (p_d[0] * xmax);
+
+ geometry[0][1] = (p_a[1] * ymax);
+ geometry[1][1] = (p_b[1] * ymax);
+ geometry[2][1] = (p_c[1] * ymax);
+ geometry[3][1] = (p_d[1] * ymax);
+
+ /* subdivide the curve ntimes (1000) times */
+ ntimes = 4 * xmax;
+ /* ntimes can be adjusted to give a finer or coarser curve */
+ d = 1.0 / ntimes;
+ d2 = d * d;
+ 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;
+
+ /* 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 },
+ };
+
+ for (i = 0; i < 4; i++)
+ {
+ 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]);
+ }
+ }
+ /* compose the above results to get the deltas matrix */
+
+ for (i = 0; i < 4; i++)
+ {
+ 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]);
+ }
+ }
-ShaderEditor::ClickType ShaderEditor::_locate_click(const Point2& p_click,int *p_node_id,int *p_slot_index) const {
- Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
- Ref<Texture> real_icon = get_icon("NodeRealSlot","EditorIcons");
- Ref<Font> font = get_font("font","PopupMenu");
- float h = font->get_height()+get_constant("vseparation","PopupMenu");
- float extra_left=MAX( real_icon->get_width()-style->get_margin(MARGIN_LEFT), 0 );
- float extra_right=MAX( real_icon->get_width()-style->get_margin(MARGIN_RIGHT), 0 );
+ /* extract the x deltas */
+ x = deltas[0][0];
+ dx = deltas[1][0];
+ dx2 = deltas[2][0];
+ dx3 = deltas[3][0];
+ /* extract the y deltas */
+ y = deltas[0][1];
+ dy = deltas[1][1];
+ dy2 = deltas[2][1];
+ dy3 = deltas[3][1];
- for(const List<int>::Element *E=order.back();E;E=E->prev()) {
- Size2 size=get_node_size(E->get());
- size.width+=extra_left+extra_right;
- Point2 pos = Point2( shader_graph.node_get_pos_x(E->get()), shader_graph.node_get_pos_y(E->get()) )-offset;
- pos.x-=extra_left;
+ lastx = CLAMP (x, 0, xmax);
+ lasty = CLAMP (y, 0, ymax);
- Rect2 rect( pos, size );
- if (!rect.has_point(p_click))
- continue;
- VisualServer::ShaderNodeType type=shader_graph.node_get_type(E->get());
- if (p_node_id)
- *p_node_id=E->get();
- float y=p_click.y-(pos.y+style->get_margin(MARGIN_TOP));
- if (y<h)
- return CLICK_NODE;
- y-=h;
-
- for(int i=0;i<VisualServer::shader_get_input_count(type);i++) {
-
- if (y<h) {
- if (p_slot_index)
- *p_slot_index=i;
- return CLICK_INPUT_SLOT;
+ /* 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++)
+ {
+ /* increment the x values */
+ x += dx;
+ dx += dx2;
+ dx2 += dx3;
+
+ /* increment the y values */
+ y += dy;
+ dy += dy2;
+ dy2 += dy3;
+
+ newx = CLAMP ((Math::round (x)), 0, xmax);
+ newy = CLAMP ((Math::round (y)), 0, ymax);
+
+ /* if this point is different than the last one...then draw it */
+ if ((lastx != newx) || (lasty != newy))
+ {
+#if 0
+ if(fix255)
+ {
+ /* use fixed array size (for the curve graph) */
+ cd->curve[cd->outline][newx] = newy;
}
- y-=h;
+ else
+ {
+ /* use dynamic allocated curve_ptr (for the real curve) */
+ cd->curve_ptr[cd->outline][newx] = newy;
+
+ if(gb_debug) printf("outline: %d cX: %d cY: %d\n", (int)cd->outline, (int)newx, (int)newy);
+ }
+#endif
+ draw_line(Vector2(lastx,ymax-lasty),Vector2(newx,ymax-newy),Color(0.8,0.8,0.8,0.8),2.0);
}
- for(int i=0;i<VisualServer::shader_get_output_count(type);i++) {
+ lastx = newx;
+ lasty = newy;
+ }
+}
+
+
+void GraphCurveMapEdit::_notification(int p_what){
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ draw_style_box(get_stylebox("bg","Tree"),Rect2(Point2(),get_size()));
+
+ int w = get_size().x;
+ int h = get_size().y;
- if (y<h) {
- if (p_slot_index)
- *p_slot_index=i;
- return CLICK_OUTPUT_SLOT;
+ Vector2 prev=Vector2(0,0);
+ Vector2 prev2=Vector2(0,0);
+
+ for(int i=-1;i<points.size();i++) {
+
+ Vector2 next;
+ Vector2 next2;
+ if (i+1>=points.size()) {
+ next=Vector2(1,1);
+ } else {
+ next=Vector2(points[i+1].offset,points[i+1].height);
}
- y-=h;
+
+ if (i+2>=points.size()) {
+ next2=Vector2(1,1);
+ } else {
+ next2=Vector2(points[i+2].offset,points[i+2].height);
+ }
+
+ /*if (i==-1 && prev.offset==next.offset) {
+ prev=next;
+ continue;
+ }*/
+
+ _plot_curve(prev2,prev,next,next2);
+
+ prev2=prev;
+ prev=next;
}
- if (p_click.y<(rect.pos.y+rect.size.height-style->get_margin(MARGIN_BOTTOM)))
- return CLICK_PARAMETER;
- else
- return CLICK_NODE;
+ for(int i=0;i<points.size();i++) {
+
+ Color col=i==grabbed?Color(1,0.0,0.0,0.9):Color(1,1,1,0.8);
+
+
+ draw_rect(Rect2( Vector2(points[i].offset,1.0-points[i].height)*get_size()-Vector2(2,2),Vector2(5,5)),col);
+ }
+
+ /* if (grabbed!=-1) {
+
+ draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color);
+ }
+*/
+ if (has_focus()) {
+
+ draw_line(Vector2(-1,-1),Vector2(w+1,-1),Color(1,1,1,0.6));
+ draw_line(Vector2(w+1,-1),Vector2(w+1,h+1),Color(1,1,1,0.6));
+ draw_line(Vector2(w+1,h+1),Vector2(-1,h+1),Color(1,1,1,0.6));
+ draw_line(Vector2(-1,-1),Vector2(-1,h+1),Color(1,1,1,0.6));
+ }
}
+}
- return CLICK_NONE;
+Size2 GraphCurveMapEdit::get_minimum_size() const {
+ return Vector2(64,64);
}
-Point2 ShaderEditor::_get_slot_pos(int p_node_id,bool p_input,int p_slot) {
- Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
- float w = get_node_size(p_node_id).width;
- Ref<Font> font = get_font("font","PopupMenu");
- float h = font->get_height()+get_constant("vseparation","PopupMenu");
- Ref<Texture> vec_icon = get_icon("NodeVecSlot","EditorIcons");
- Point2 pos = Point2( shader_graph.node_get_pos_x(p_node_id), shader_graph.node_get_pos_y(p_node_id) )-offset;
- pos+=style->get_offset();
- pos.y+=h;
- if(p_input) {
+void GraphCurveMapEdit::set_points(const Vector<Vector2>& p_points) {
- pos.y+=p_slot*h;
- pos+=Point2( -vec_icon->get_width()/2.0, h/2.0).floor();
- return pos;
- } else {
- pos.y+=VisualServer::shader_get_input_count( shader_graph.node_get_type(p_node_id ) )*h;
+ points.clear();
+ for(int i=0;i<p_points.size();i++) {
+ Point p;
+ p.offset=p_points[i].x;
+ p.height=p_points[i].y;
+ points.push_back(p);
}
- pos.y+=p_slot*h;
- pos+=Point2( w-style->get_minimum_size().width+vec_icon->get_width()/2.0, h/2.0).floor();
-
- return pos;
+ points.sort();
+ update();
+}
+Vector<Vector2> GraphCurveMapEdit::get_points() const {
+ Vector<Vector2> ret;
+ for(int i=0;i<points.size();i++)
+ ret.push_back(Vector2(points[i].offset,points[i].height));
+ return ret;
}
-void ShaderEditor::_node_edit_property(int p_node) {
+void GraphCurveMapEdit::_bind_methods(){
- Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
- Size2 size = get_node_size(p_node);
- Point2 pos = Point2( shader_graph.node_get_pos_x(p_node), shader_graph.node_get_pos_y(p_node) )-offset;
+ ObjectTypeDB::bind_method(_MD("_input_event"),&GraphCurveMapEdit::_input_event);
+ ADD_SIGNAL(MethodInfo("curve_changed"));
+}
- VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node);
+GraphCurveMapEdit::GraphCurveMapEdit(){
- PropertyInfo ph = VisualServer::get_singleton()->shader_node_get_type_info(type);
- if (ph.type==Variant::NIL)
- return;
- if (ph.type==Variant::_RID)
- ph.type=Variant::OBJECT;
+ grabbed=-1;
+ grabbing=false;
+ set_focus_mode(FOCUS_ALL);
- property_editor->edit(NULL,ph.name,ph.type,shader_graph.node_get_param(p_node),ph.hint,ph.hint_string);
+}
- Point2 popup_pos=Point2( pos.x+(size.width-property_editor->get_size().width)/2.0,pos.y+(size.y-style->get_margin(MARGIN_BOTTOM))).floor();
- popup_pos+=get_global_pos();
- property_editor->set_pos(popup_pos);
- property_editor->popup();
+////cbacks
+///
+void ShaderGraphView::_scalar_const_changed(double p_value,int p_id) {
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Scalar Constant",true);
+ ur->add_do_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,p_value);
+ ur->add_undo_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,graph->scalar_const_node_get_value(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
}
-bool ShaderEditor::has_point(const Point2& p_point) const {
+void ShaderGraphView::_vec_const_changed(double p_value, int p_id,Array p_arr){
+
+ Vector3 val;
+ for(int i=0;i<p_arr.size();i++) {
+ val[i]=p_arr[i].call("get_val");
+ }
- int n,si;
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Vec Constant",true);
+ ur->add_do_method(graph.ptr(),"vec_const_node_set_value",type,p_id,val);
+ ur->add_undo_method(graph.ptr(),"vec_const_node_set_value",type,p_id,graph->vec_const_node_get_value(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
- return _locate_click(p_point,&n,&si)!=CLICK_NONE;
}
+void ShaderGraphView::_rgb_const_changed(const Color& p_color, int p_id){
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change RGB Constant",true);
+ ur->add_do_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,p_color);
+ ur->add_undo_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,graph->rgb_const_node_get_value(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
-void ShaderEditor::_input_event(InputEvent p_event) {
+}
+void ShaderGraphView::_scalar_op_changed(int p_op, int p_id){
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Scalar Operator");
+ ur->add_do_method(graph.ptr(),"scalar_op_node_set_op",type,p_id,p_op);
+ ur->add_undo_method(graph.ptr(),"scalar_op_node_set_op",type,p_id,graph->scalar_op_node_get_op(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
- switch(p_event.type) {
+}
+void ShaderGraphView::_vec_op_changed(int p_op, int p_id){
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Vec Operator");
+ ur->add_do_method(graph.ptr(),"vec_op_node_set_op",type,p_id,p_op);
+ ur->add_undo_method(graph.ptr(),"vec_op_node_set_op",type,p_id,graph->vec_op_node_get_op(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
+}
+void ShaderGraphView::_vec_scalar_op_changed(int p_op, int p_id){
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change VecxScalar Operator");
+ ur->add_do_method(graph.ptr(),"vec_scalar_op_node_set_op",type,p_id,p_op);
+ ur->add_undo_method(graph.ptr(),"vec_scalar_op_node_set_op",type,p_id,graph->vec_scalar_op_node_get_op(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
- case InputEvent::MOUSE_BUTTON: {
+}
+void ShaderGraphView::_rgb_op_changed(int p_op, int p_id){
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change RGB Operator");
+ ur->add_do_method(graph.ptr(),"rgb_op_node_set_op",type,p_id,p_op);
+ ur->add_undo_method(graph.ptr(),"rgb_op_node_set_op",type,p_id,graph->rgb_op_node_get_op(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
+}
+void ShaderGraphView::_xform_inv_rev_changed(bool p_enabled, int p_id){
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Toggle Rot Only");
+ ur->add_do_method(graph.ptr(),"xform_vec_mult_node_set_no_translation",type,p_id,p_enabled);
+ ur->add_undo_method(graph.ptr(),"xform_vec_mult_node_set_no_translation",type,p_id,graph->xform_vec_mult_node_get_no_translation(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
+}
+void ShaderGraphView::_scalar_func_changed(int p_func, int p_id){
+
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Scalar Function");
+ ur->add_do_method(graph.ptr(),"scalar_func_node_set_function",type,p_id,p_func);
+ ur->add_undo_method(graph.ptr(),"scalar_func_node_set_function",type,p_id,graph->scalar_func_node_get_function(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
+}
+void ShaderGraphView::_vec_func_changed(int p_func, int p_id){
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Vec Function");
+ ur->add_do_method(graph.ptr(),"vec_func_node_set_function",type,p_id,p_func);
+ ur->add_undo_method(graph.ptr(),"vec_func_node_set_function",type,p_id,graph->vec_func_node_get_function(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
- if (p_event.mouse_button.pressed) {
+}
+void ShaderGraphView::_scalar_input_changed(double p_value,int p_id){
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Scalar Uniform",true);
+ ur->add_do_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,p_value);
+ ur->add_undo_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,graph->scalar_input_node_get_value(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
+}
+void ShaderGraphView::_vec_input_changed(double p_value, int p_id,Array p_arr){
- if (p_event.mouse_button.button_index==1) {
- click_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
- click_motion=click_pos;
- click_type = _locate_click(click_pos,&click_node,&click_slot);
- if( click_type!=CLICK_NONE) {
+ Vector3 val;
+ for(int i=0;i<p_arr.size();i++) {
+ val[i]=p_arr[i].call("get_val");
+ }
- order.erase(click_node);
- order.push_back(click_node);
- update();
- }
- switch(click_type) {
- case CLICK_INPUT_SLOT: {
- click_pos=_get_slot_pos(click_node,true,click_slot);
- } break;
- case CLICK_OUTPUT_SLOT: {
- click_pos=_get_slot_pos(click_node,false,click_slot);
- } break;
- case CLICK_PARAMETER: {
- //open editor
- _node_edit_property(click_node);
- } break;
- }
- }
- if (p_event.mouse_button.button_index==2) {
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Vec Uniform",true);
+ ur->add_do_method(graph.ptr(),"vec_input_node_set_value",type,p_id,val);
+ ur->add_undo_method(graph.ptr(),"vec_input_node_set_value",type,p_id,graph->vec_input_node_get_value(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
- if (click_type!=CLICK_NONE) {
- click_type=CLICK_NONE;
- update();
- } else {
- // try to disconnect/remove
+}
+void ShaderGraphView::_xform_input_changed(int p_id, Node *p_button){
- Point2 rclick_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
- rclick_type = _locate_click(rclick_pos,&rclick_node,&rclick_slot);
- if (rclick_type==CLICK_INPUT_SLOT || rclick_type==CLICK_OUTPUT_SLOT) {
- node_popup->clear();
- node_popup->add_item("Disconnect",NODE_DISCONNECT);
- node_popup->set_pos(rclick_pos);
- node_popup->popup();
+ 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=-1;
+ ped_popup->edit(NULL,"",Variant::TRANSFORM,graph->xform_input_node_get_value(type,p_id),PROPERTY_HINT_NONE,"");
+ ped_popup->popup();
- }
+}
+void ShaderGraphView::_xform_const_changed(int p_id, Node *p_button){
- if (rclick_type==CLICK_NODE) {
- node_popup->clear();
- node_popup->add_item("Remove",NODE_ERASE);
- node_popup->set_pos(rclick_pos);
- node_popup->popup();
- }
+ 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=-1;
+ ped_popup->edit(NULL,"",Variant::TRANSFORM,graph->xform_const_node_get_value(type,p_id),PROPERTY_HINT_NONE,"");
+ ped_popup->popup();
+}
- }
- }
- } else {
+void ShaderGraphView::_rgb_input_changed(const Color& p_color, int p_id){
- if (p_event.mouse_button.button_index==1 && click_type!=CLICK_NONE) {
- switch(click_type) {
- case CLICK_INPUT_SLOT:
- case CLICK_OUTPUT_SLOT: {
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change RGB Uniform",true);
+ ur->add_do_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,p_color);
+ ur->add_undo_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,graph->rgb_input_node_get_value(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
+}
+void ShaderGraphView::_tex_input_change(int p_id, Node *p_button){
- Point2 dst_click_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
- int id;
- int slot;
- ClickType dst_click_type = _locate_click(dst_click_pos,&id,&slot);
- if (dst_click_type==CLICK_INPUT_SLOT && click_type==CLICK_OUTPUT_SLOT) {
- shader_graph.connect(click_node,click_slot,id,slot);
+}
+void ShaderGraphView::_cube_input_change(int p_id){
- Error err = validate_graph();
- if (err==ERR_CYCLIC_LINK)
- shader_graph.disconnect(click_node,click_slot,id,slot);
- _write_shader_graph();
- }
- if (click_type==CLICK_INPUT_SLOT && dst_click_type==CLICK_OUTPUT_SLOT) {
+}
- shader_graph.connect(id,slot,click_node,click_slot);
+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;
+ }
- Error err = validate_graph();
- if (err==ERR_CYCLIC_LINK)
- shader_graph.disconnect(id,slot,click_node,click_slot);
- _write_shader_graph();
- }
+ if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_XFORM_CONST) {
- } break;
- case CLICK_NODE: {
- int new_x=shader_graph.node_get_pos_x(click_node)+(click_motion.x-click_pos.x);
- int new_y=shader_graph.node_get_pos_y(click_node)+(click_motion.y-click_pos.y);
- shader_graph.node_set_pos(click_node,new_x,new_y);
- _write_shader_graph();
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change XForm Uniform");
+ ur->add_do_method(graph.ptr(),"xform_const_node_set_value",type,edited_id,ped_popup->get_variant());
+ ur->add_undo_method(graph.ptr(),"xform_const_node_set_value",type,edited_id,graph->xform_const_node_get_value(type,edited_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
+ }
- } break;
- }
- click_type=CLICK_NONE;
- update();
- }
- }
+ if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_XFORM_INPUT) {
- }
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change XForm Uniform");
+ ur->add_do_method(graph.ptr(),"xform_input_node_set_value",type,edited_id,ped_popup->get_variant());
+ ur->add_undo_method(graph.ptr(),"xform_input_node_set_value",type,edited_id,graph->xform_input_node_get_value(type,edited_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
+ }
- case InputEvent::MOUSE_MOTION: {
+ if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_TEXTURE_INPUT) {
- if (p_event.mouse_motion.button_mask&1 && click_type!=CLICK_NONE) {
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Texture Uniform");
+ ur->add_do_method(graph.ptr(),"texture_input_node_set_value",type,edited_id,ped_popup->get_variant());
+ ur->add_undo_method(graph.ptr(),"texture_input_node_set_value",type,edited_id,graph->texture_input_node_get_value(type,edited_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
+ }
- click_motion=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
- update();
- }
+ if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_CUBEMAP_INPUT) {
- } break;
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Cubemap Uniform");
+ ur->add_do_method(graph.ptr(),"cubemap_input_node_set_value",type,edited_id,ped_popup->get_variant());
+ ur->add_undo_method(graph.ptr(),"cubemap_input_node_set_value",type,edited_id,graph->cubemap_input_node_get_value(type,edited_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
}
+
}
-void ShaderEditor::_notification(int p_what) {
+void ShaderGraphView::_comment_edited(int p_id,Node* p_button) {
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ TextEdit *te=p_button->cast_to<TextEdit>();
+ ur->create_action("Change Comment",true);
+ ur->add_do_method(graph.ptr(),"comment_node_set_text",type,p_id,te->get_text());
+ ur->add_undo_method(graph.ptr(),"comment_node_set_text",type,p_id,graph->comment_node_get_text(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
- switch(p_what) {
+}
- case NOTIFICATION_DRAW: {
+void ShaderGraphView::_color_ramp_changed(int p_id,Node* p_ramp) {
- _update_scrollbars();
- //VisualServer::get_singleton()->canvas_item_add_rect(get_canvas_item(),Rect2(Point2(),get_size()),Color(0,0,0,1));
+ GraphColorRampEdit *cr=p_ramp->cast_to<GraphColorRampEdit>();
- for(List<int>::Element *E=order.front();E;E=E->next()) {
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
- _draw_node(E->get());
- }
- if (click_type==CLICK_INPUT_SLOT || click_type==CLICK_OUTPUT_SLOT) {
+ Vector<float> offsets=cr->get_offsets();
+ Vector<Color> colors=cr->get_colors();
- VisualServer::get_singleton()->canvas_item_add_line(get_canvas_item(),click_pos,click_motion,Color(0.5,1,0.5,0.8),2);
- }
+ DVector<float> new_offsets;
+ DVector<Color> new_colors;
+ {
+ new_offsets.resize(offsets.size());
+ new_colors.resize(colors.size());
+ DVector<float>::Write ow=new_offsets.write();
+ DVector<Color>::Write cw=new_colors.write();
+ for(int i=0;i<new_offsets.size();i++) {
+ ow[i]=offsets[i];
+ cw[i]=colors[i];
+ }
- List<ShaderGraph::Connection> connections = shader_graph.get_connection_list();
- for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
+ }
- const ShaderGraph::Connection &c=E->get();
- Point2 source = _get_slot_pos(c.src_id,false,c.src_slot);
- Point2 dest = _get_slot_pos(c.dst_id,true,c.dst_slot);
- bool vec = VisualServer::shader_is_input_vector( shader_graph.node_get_type(c.dst_id), c.dst_slot );
- Color col = vec?Color(1,0.5,0.5,0.8):Color(1,1,0.5,0.8);
- if (click_type==CLICK_NODE && click_node==c.src_id) {
+ DVector<float> old_offsets=graph->color_ramp_node_get_offsets(type,p_id);
+ DVector<Color> old_colors=graph->color_ramp_node_get_colors(type,p_id);
- source+=click_motion-click_pos;
- }
+ if (old_offsets.size()!=new_offsets.size())
+ ur->create_action("Add/Remove to Color Ramp");
+ else
+ ur->create_action("Modify Color Ramp",true);
- if (click_type==CLICK_NODE && click_node==c.dst_id) {
+ ur->add_do_method(graph.ptr(),"color_ramp_node_set_ramp",type,p_id,new_colors,new_offsets);
+ ur->add_undo_method(graph.ptr(),"color_ramp_node_set_ramp",type,p_id,old_colors,old_offsets);
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
+}
- dest+=click_motion-click_pos;
- }
+void ShaderGraphView::_curve_changed(int p_id,Node* p_curve) {
- VisualServer::get_singleton()->canvas_item_add_line(get_canvas_item(),source,dest,col,2);
+ GraphCurveMapEdit *cr=p_curve->cast_to<GraphCurveMapEdit>();
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+
+
+ Vector<Point2> points=cr->get_points();
+
+ DVector<Vector2> new_points;
+ {
+ new_points.resize(points.size());
+ DVector<Vector2>::Write ow=new_points.write();
+ for(int i=0;i<new_points.size();i++) {
+ ow[i]=points[i];
+ }
- }
- } break;
}
+
+ DVector<Vector2> old_points=graph->curve_map_node_get_points(type,p_id);
+
+ if (old_points.size()!=new_points.size())
+ ur->create_action("Add/Remove to Curve Map");
+ else
+ ur->create_action("Modify Curve Map",true);
+
+ ur->add_do_method(graph.ptr(),"curve_map_node_set_points",type,p_id,new_points);
+ ur->add_undo_method(graph.ptr(),"curve_map_node_set_points",type,p_id,old_points);
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
}
-void ShaderEditor::_update_scrollbars() {
- Size2 size = get_size();
- Size2 hmin = h_scroll->get_minimum_size();
- Size2 vmin = v_scroll->get_minimum_size();
+void ShaderGraphView::_input_name_changed(const String& p_name, int p_id, Node *p_line_edit) {
- v_scroll->set_begin( Point2(size.width - vmin.width, 0) );
- v_scroll->set_end( Point2(size.width, size.height) );
+ LineEdit *le=p_line_edit->cast_to<LineEdit>();
+ ERR_FAIL_COND(!le);
- h_scroll->set_begin( Point2( 0, size.height - hmin.height) );
- h_scroll->set_end( Point2(size.width-vmin.width, size.height) );
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Input Name");
+ ur->add_do_method(graph.ptr(),"input_node_set_name",type,p_id,p_name);
+ ur->add_undo_method(graph.ptr(),"input_node_set_name",type,p_id,graph->input_node_get_name(type,p_id));
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ block_update=true;
+ ur->commit_action();
+ block_update=false;
+ le->set_text(graph->input_node_get_name(type,p_id));
+}
+void ShaderGraphView::_tex_edited(int p_id,Node* p_button) {
- Size2 min = _get_maximum_size();
+ 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=-1;
+ ped_popup->edit(NULL,"",Variant::OBJECT,graph->texture_input_node_get_value(type,p_id),PROPERTY_HINT_RESOURCE_TYPE,"Texture");
+}
- if (min.height < size.height - hmin.height) {
+void ShaderGraphView::_cube_edited(int p_id,Node* p_button) {
- v_scroll->hide();
- offset.y=0;
- } else {
+ 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=-1;
+ ped_popup->edit(NULL,"",Variant::OBJECT,graph->cubemap_input_node_get_value(type,p_id),PROPERTY_HINT_RESOURCE_TYPE,"CubeMap");
+}
+
+
+//////////////view/////////////
+
+
+void ShaderGraphView::_connection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot) {
- v_scroll->show();
- v_scroll->set_max(min.height);
- v_scroll->set_page(size.height - hmin.height);
- offset.y=v_scroll->get_val();
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+
+ int from_idx=-1;
+ int to_idx=-1;
+ for (Map<int,GraphNode*>::Element *E=node_map.front();E;E=E->next()) {
+
+ if (p_from==E->get()->get_name())
+ from_idx=E->key();
+ if (p_to==E->get()->get_name())
+ to_idx=E->key();
}
- if (min.width < size.width - vmin.width) {
+ ERR_FAIL_COND(from_idx==-1);
+ ERR_FAIL_COND(to_idx==-1);
- h_scroll->hide();
- offset.x=0;
- } else {
+ ur->create_action("Connect Graph Nodes");
+
+ List<ShaderGraph::Connection> conns;
- h_scroll->show();
- h_scroll->set_max(min.width);
- h_scroll->set_page(size.width - vmin.width);
- offset.x=h_scroll->get_val();
+ graph->get_node_connections(type,&conns);
+ //disconnect/reconnect dependencies
+ ur->add_undo_method(graph.ptr(),"disconnect_node",type,from_idx,p_from_slot,to_idx,p_to_slot);
+ for(List<ShaderGraph::Connection>::Element *E=conns.front();E;E=E->next()) {
+
+ if (E->get().dst_id==to_idx && E->get().dst_slot==p_to_slot) {
+ ur->add_do_method(graph.ptr(),"disconnect_node",type,E->get().src_id,E->get().src_slot,E->get().dst_id,E->get().dst_slot);
+ 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(graph.ptr(),"connect_node",type,from_idx,p_from_slot,to_idx,p_to_slot);
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
-void ShaderEditor::_scroll_moved() {
- offset.x=h_scroll->get_val();
- offset.y=v_scroll->get_val();
- update();
}
-void ShaderEditor::_bind_methods() {
+void ShaderGraphView::_disconnection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot) {
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+
+ int from_idx=-1;
+ int to_idx=-1;
+ for (Map<int,GraphNode*>::Element *E=node_map.front();E;E=E->next()) {
+
+ if (p_from==E->get()->get_name())
+ from_idx=E->key();
+ if (p_to==E->get()->get_name())
+ to_idx=E->key();
+ }
+
+ ERR_FAIL_COND(from_idx==-1);
+ ERR_FAIL_COND(to_idx==-1);
+
+ if (!graph->is_node_connected(type,from_idx,p_from_slot,to_idx,p_to_slot))
+ return; //nothing to disconnect
+
+ ur->create_action("Disconnect Graph Nodes");
+
+ List<ShaderGraph::Connection> conns;
+
+ graph->get_node_connections(type,&conns);
+ //disconnect/reconnect dependencies
+ ur->add_do_method(graph.ptr(),"disconnect_node",type,from_idx,p_from_slot,to_idx,p_to_slot);
+ ur->add_undo_method(graph.ptr(),"connect_node",type,from_idx,p_from_slot,to_idx,p_to_slot);
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
+
- ObjectTypeDB::bind_method( "_node_menu_item", &ShaderEditor::_node_menu_item );
- ObjectTypeDB::bind_method( "_node_add_callback", &ShaderEditor::_node_add_callback );
- ObjectTypeDB::bind_method( "_input_event", &ShaderEditor::_input_event );
- ObjectTypeDB::bind_method( "_node_param_changed", &ShaderEditor::_node_param_changed );
- ObjectTypeDB::bind_method( "_scroll_moved", &ShaderEditor::_scroll_moved );
- ObjectTypeDB::bind_method( "_vertex_item", &ShaderEditor::_vertex_item );
- ObjectTypeDB::bind_method( "_fragment_item", &ShaderEditor::_fragment_item );
- ObjectTypeDB::bind_method( "_post_item", &ShaderEditor::_post_item );
}
-void ShaderEditor::_read_shader_graph() {
+void ShaderGraphView::_node_removed(int p_id) {
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Remove Shader Graph Node");
- shader_graph.clear();;
- order.clear();
- List<int> nodes;
- shader->get_node_list(&nodes);
- int larger_id=0;
- for(List<int>::Element *E=nodes.front();E;E=E->next()) {
+ ur->add_do_method(graph.ptr(),"node_remove",type,p_id);
+ ur->add_undo_method(graph.ptr(),"node_add",type,graph->node_get_type(type,p_id),p_id);
+ ur->add_undo_method(graph.ptr(),"node_set_state",type,p_id,graph->node_get_state(type,p_id));
+ List<ShaderGraph::Connection> conns;
- if (E->get() > larger_id)
- larger_id = E->get();
+ graph->get_node_connections(type,&conns);
+ for(List<ShaderGraph::Connection>::Element *E=conns.front();E;E=E->next()) {
- shader_graph.node_add( (VS::ShaderNodeType)shader->node_get_type(E->get()), E->get() );
- shader_graph.node_set_param( E->get(), shader->node_get_param( E->get() ) );
- Point2 pos = shader->node_get_pos(E->get());
- shader_graph.node_set_pos( E->get(), pos.x,pos.y );
- order.push_back(E->get());
+ if (E->get().dst_id==p_id || E->get().src_id==p_id) {
+ 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();
- last_id=larger_id+1;
+}
- List<Shader::Connection> connections;
- shader->get_connections(&connections);
+void ShaderGraphView::_begin_node_move()
+{
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Move Shader Graph Node");
+}
- for(List<Shader::Connection>::Element *E=connections.front();E;E=E->next()) {
+void ShaderGraphView::_node_moved(const Vector2& p_from, const Vector2& p_to,int p_id) {
- Shader::Connection &c=E->get();
- shader_graph.connect(c.src_id,c.src_slot,c.dst_id,c.dst_slot);
- }
- validate_graph();
- update();
+ ERR_FAIL_COND(!node_map.has(p_id));
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->add_do_method(this,"_move_node",p_id,p_to);
+ ur->add_undo_method(this,"_move_node",p_id,p_from);
}
-void ShaderEditor::_write_shader_graph() {
+void ShaderGraphView::_end_node_move()
+{
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->commit_action();
+}
- shader->clear();
- List<int> nodes;
- shader_graph.get_node_list(&nodes);
- for(List<int>::Element *E=nodes.front();E;E=E->next()) {
+void ShaderGraphView::_move_node(int p_id,const Vector2& p_to) {
- shader->node_add((Shader::NodeType)shader_graph.node_get_type(E->get()),E->get());
- shader->node_set_param(E->get(),shader_graph.node_get_param(E->get()));
- shader->node_set_pos(E->get(),Point2( shader_graph.node_get_pos_x(E->get()),shader_graph.node_get_pos_y(E->get()) ) );
- }
+ ERR_FAIL_COND(!node_map.has(p_id));
+ node_map[p_id]->set_offset(p_to);
+ graph->node_set_pos(type,p_id,p_to);
+}
- List<ShaderGraph::Connection> connections = shader_graph.get_connection_list();
- for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
+void ShaderGraphView::_duplicate_nodes_request()
+{
+ Array s_id;
- const ShaderGraph::Connection &c=E->get();
- shader->connect(c.src_id,c.src_slot,c.dst_id,c.dst_slot);
+ 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());
}
+
+ if (s_id.size()==0)
+ return;
+
+ 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();
+
}
-void ShaderEditor::_add_node_from_text(const String& p_text) {
+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");
+}
- ERR_FAIL_COND( p_text.get_slice_count(" ") != 3 );
- bool input = p_text.get_slice(" ",0)=="In:";
- String name = p_text.get_slice(" ",1);
- bool vec = p_text.get_slice(" ",2)=="(vec3)";
+void ShaderGraphView::_delete_nodes_request()
+{
+ List<int> s_id=List<int>();
- _node_add( input?
- ( vec? VisualServer::NODE_VEC_IN : VisualServer::NODE_IN ) :
- ( vec? VisualServer::NODE_VEC_OUT : VisualServer::NODE_OUT ) );
+ 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());
+ }
+
+ if (s_id.size()==0)
+ return;
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Delete Shader Graph Node(s)");
+
+ 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;
+
+ graph->get_node_connections(type,&conns);
+ for(List<ShaderGraph::Connection>::Element *E=conns.front();E;E=E->next()) {
+
+ 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();
- shader_graph.node_set_param( last_id-1,name );
- _write_shader_graph();
}
-void ShaderEditor::_vertex_item(int p_item) {
+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;
+ }
+
+ ped_popup->edit(NULL,"",vt,v,h,p_hint);
- _add_node_from_text(vertex_popup->get_item_text(p_item));
+ ped_popup->popup();
}
-void ShaderEditor::_fragment_item(int p_item) {
- _add_node_from_text(fragment_popup->get_item_text(p_item));
+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;
}
-void ShaderEditor::_post_item(int p_item) {
- _add_node_from_text(post_popup->get_item_text(p_item));
+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;
}
+void ShaderGraphView::_create_node(int p_id) {
-void ShaderEditor::_node_menu_item(int p_item) {
- switch(p_item) {
+ 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)
+ };
- case GRAPH_ADD_NODE: {
- add_popup->popup_centered_ratio();
- validate_graph();
- } break;
- case NODE_DISCONNECT: {
+ const String hint_spin = "-65536,65535,0.001";
+ const String hint_slider = "0.0,1.0,0.01,slider";
- if (rclick_type==CLICK_INPUT_SLOT) {
- List<ShaderGraph::Connection> connections = shader_graph.get_connection_list();
- for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
+ switch(graph->node_get_type(type,p_id)) {
- const ShaderGraph::Connection &c=E->get();
- if( c.dst_id==rclick_node && c.dst_slot==rclick_slot) {
+ case ShaderGraph::NODE_INPUT: {
- shader_graph.disconnect(c.src_id,c.src_slot,c.dst_id,c.dst_slot);
- }
- }
- update();
- _write_shader_graph();
- validate_graph();
+ gn->set_title("Input");
+
+ 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) {
+
+ 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++;
}
+ }
- if (rclick_type==CLICK_OUTPUT_SLOT) {
+ } 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]);
+
+ } 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);
+ }
- List<ShaderGraph::Connection> connections = shader_graph.get_connection_list();
- for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
+ 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));
+ }
- const ShaderGraph::Connection &c=E->get();
- if( c.src_id==rclick_node && c.src_slot==rclick_slot) {
+ 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());
- shader_graph.disconnect(c.src_id,c.src_slot,c.dst_id,c.dst_slot);
- }
- }
- update();
- _write_shader_graph();
- validate_graph();
+
+ } 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);
+
+ 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->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());
+
+
+ } break; // vec3 vs vec3 op (mul: { } break;ad: { } break;div: { } break;crossprod: { } break;etc)
+ case ShaderGraph::NODE_VEC_SCALAR_OP: {
+
+ gn->set_title("VecScalarOp");
+ static const char* op_name[ShaderGraph::VEC_SCALAR_MAX_OP]={
+ "Mul",
+ "Div",
+ "Pow",
+ };
+
+ OptionButton *ob = memnew( OptionButton );
+ for(int i=0;i<ShaderGraph::VEC_SCALAR_MAX_OP;i++) {
+
+ ob->add_item(op_name[i],i);
+ }
+
+ 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);
+ }
+
+ 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);
+
+ 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],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 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_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(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; // 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->add_child(button);
+
+ 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));
+ }
+
+ 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;
+ case ShaderGraph::NODE_XFORM_VEC_INV_MULT: {
+
+ gn->set_title("XFVecInvMult");
+
+
+ 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->add_child(button);
+
+ 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);
+ }
+
+ 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);
+
+ 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);
+
+ 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 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",
+ };
+
+ OptionButton *ob = memnew( OptionButton );
+ for(int i=0;i<ShaderGraph::VEC_MAX_FUNC;i++) {
+
+ ob->add_item(func_name[i],i);
+ }
+
+ 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));
+ }
+
+ 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());
+
+ } break; // vec3 . vec3 (dot product -> scalar output)
+ case ShaderGraph::NODE_VEC_TO_SCALAR: {
+
+ 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));
+ }
+
+ 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_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());
+
+ } break; // 3 vec input: { } break; 1 xform output
+ case ShaderGraph::NODE_XFORM_TO_VEC: {
+
+ 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));
+ }
+
+ 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());
+
+
+ } break; // scalar interpolation (with optional curve)
+ case ShaderGraph::NODE_VEC_INTERP: {
+
+ 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_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; // vec3 interpolation (with optional curve)
+ case ShaderGraph::NODE_COLOR_RAMP: {
+
+ gn->set_title("ColorRamp");
+ GraphColorRampEdit * ramp = memnew( GraphColorRampEdit );
+
+ 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);
+
+ int oc = offsets.size();
+
+ 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]);
}
- } break;
- case NODE_ERASE: {
-
- order.erase(rclick_node);
- shader_graph.node_remove(rclick_node);
- update();
- _write_shader_graph();
- validate_graph();
- } break;
- case GRAPH_CLEAR: {
-
- order.clear();
- shader_graph.clear();
- last_id=1;
- last_x=20;
- last_y=20;
- update();
- _write_shader_graph();
- validate_graph();
-
- } break;
- }
-}
+ ramp->set_ramp(ofsv,colorv);
-void ShaderEditor::_node_add(VisualServer::ShaderNodeType p_type) {
+ }
- shader_graph.node_add(p_type,last_id );
- shader_graph.node_set_pos(last_id ,last_x,last_y);
- String test_param;
+ ramp->connect("ramp_changed",this,"_color_ramp_changed",varray(p_id,ramp));
+ ramp->set_custom_minimum_size(Size2(128,1));
+ gn->add_child(ramp);
- switch(p_type) {
- case VS::NODE_PARAMETER: {
- test_param="param";
- } break;
- case VS::NODE_VEC_PARAMETER: {
+ 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);
- test_param="vec";
- } break;
- case VS::NODE_COLOR_PARAMETER: {
- test_param="color";
- } break;
- case VS::NODE_TEXTURE_PARAMETER: {
+ 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]);
- test_param="tex";
- } break;
- case VS::NODE_TEXTURE_2D_PARAMETER: {
- test_param="tex2D";
- } break;
- case VS::NODE_TEXTURE_CUBE_PARAMETER: {
+ } break; // scalar interpolation (with optional curve)
+ case ShaderGraph::NODE_CURVE_MAP: {
- test_param="cubemap";
- } break;
- case VS::NODE_TRANSFORM_PARAMETER: {
- test_param="xform";
- } break;
- case VS::NODE_LABEL: {
+ gn->set_title("CurveMap");
+ GraphCurveMapEdit * map = memnew( GraphCurveMapEdit );
- test_param="label";
- } break;
- }
+ DVector<Vector2> points = graph->curve_map_node_get_points(type,p_id);
- if(test_param!="") {
+ int oc = points.size();
- int iter=0;
- List<int> l;
+ if (oc) {
+ DVector<Vector2>::Read rofs = points.read();
- shader_graph.get_node_list(&l);
- bool found;
- String test;
- do {
- iter++;
- test=test_param;
- if (iter>1)
- test+="_"+itos(iter);
- found=false;
- for(List<int>::Element *E=l.front();E;E=E->next()) {
+ Vector<Vector2> ofsv;
+ for(int i=0;i<oc;i++) {
+ ofsv.push_back(rofs[i]);
+ }
+ map->set_points(ofsv);
- String param = shader_graph.node_get_param( E->get() );
- if (param==test) {
- found=true;
- break;
- }
+ }
+ 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 );
+ 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);
+ 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++;
}
+ }
- } while (found);
+ } 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
- shader_graph.node_set_param(last_id,test);
}
- order.push_back(last_id);
- last_x+=10;
- last_y+=10;
- last_id++;
- last_x=last_x % (int)get_size().width;
- last_y=last_y % (int)get_size().height;
- update();
- add_popup->hide();;
- _write_shader_graph();
-}
+ gn->connect("dragged",this,"_node_moved",varray(p_id));
+ gn->connect("close_request",this,"_node_removed",varray(p_id),CONNECT_DEFERRED);
+ graph_edit->add_child(gn);
+ node_map[p_id]=gn;
+ gn->set_offset(graph->node_get_pos(type,p_id));
-void ShaderEditor::_node_add_callback() {
- TreeItem * item = add_types->get_selected();
- ERR_FAIL_COND(!item);
- _node_add((VisualServer::ShaderNodeType)(int)item->get_metadata(0));
- add_popup->hide() ;
}
-ShaderEditor::ShaderEditor() {
+void ShaderGraphView::_update_graph() {
- set_focus_mode(FOCUS_ALL);
- Panel* menu_panel = memnew( Panel );
- menu_panel->set_anchor( MARGIN_RIGHT, Control::ANCHOR_END );
- menu_panel->set_end( Point2(0,22) );
+ if (block_update)
+ return;
+
+ for (Map<int,GraphNode*>::Element *E=node_map.front();E;E=E->next()) {
- add_child( menu_panel );
+ memdelete(E->get());
+ }
- PopupMenu *p;
- List<PropertyInfo> defaults;
+ node_map.clear();
- MenuButton* node_menu = memnew( MenuButton );
- node_menu->set_text("Graph");
- node_menu->set_pos( Point2( 5,0) );
- menu_panel->add_child( node_menu );
+ if (!graph.is_valid())
+ return;
- p=node_menu->get_popup();
- p->add_item("Add Node",GRAPH_ADD_NODE);
- p->add_separator();
- p->add_item("Clear",GRAPH_CLEAR);
- p->connect("item_pressed", this,"_node_menu_item");
- MenuButton* vertex_menu = memnew( MenuButton );
- vertex_menu->set_text("Vertex");
- vertex_menu->set_pos( Point2( 49,0) );
- menu_panel->add_child( vertex_menu );
+ List<int> nl;
+ graph->get_node_list(type,&nl);
- p=vertex_menu->get_popup();
- defaults.clear();
- VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_VERTEX,&defaults);
+ for(List<int>::Element *E=nl.front();E;E=E->next()) {
- int id=0;
- for(int i=0;i<defaults.size();i++) {
+ _create_node(E->get());
+ }
+ graph_edit->clear_connections();
- p->add_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
+ List<ShaderGraph::Connection> connections;
+ graph->get_node_connections(type,&connections);
+ for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
+
+ ERR_CONTINUE(!node_map.has(E->get().src_id) || !node_map.has(E->get().dst_id));
+ 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);
}
- p->add_separator();
- id++;
- defaults.clear();
- VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_VERTEX,&defaults);
+}
- for(int i=0;i<defaults.size();i++) {
+void ShaderGraphView::_sg_updated() {
- p->add_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
+ 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;
}
+}
- vertex_popup=p;
- vertex_popup->connect("item_pressed", this,"_vertex_item");
- MenuButton* fragment_menu = memnew( MenuButton );
- fragment_menu->set_text("Fragment");
- fragment_menu->set_pos( Point2( 95 ,0) );
- menu_panel->add_child( fragment_menu );
+void ShaderGraphView::set_graph(Ref<ShaderGraph> p_graph){
- p=fragment_menu->get_popup();
- defaults.clear();
- VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_FRAGMENT,&defaults);
- id=0;
- for(int i=0;i<defaults.size();i++) {
- p->add_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
+ if (graph.is_valid()) {
+ graph->disconnect("updated",this,"_sg_updated");
+ }
+ graph=p_graph;
+ if (graph.is_valid()) {
+ graph->connect("updated",this,"_sg_updated");
}
- p->add_separator();
- id++;
- defaults.clear();
- VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_FRAGMENT,&defaults);
+ _update_graph();
+ _sg_updated();
+
+}
- for(int i=0;i<defaults.size();i++) {
+void ShaderGraphView::_notification(int p_what) {
- p->add_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
- }
+ if (p_what==NOTIFICATION_ENTER_TREE) {
- fragment_popup=p;
- fragment_popup->connect("item_pressed", this,"_fragment_item");
+ ped_popup->connect("variant_changed",this,"_variant_edited");
+ }
+}
- MenuButton* post_menu = memnew( MenuButton );
- post_menu->set_text("Post");
- post_menu->set_pos( Point2( 161,0) );
- menu_panel->add_child( post_menu );
+void ShaderGraphView::add_node(int p_type, const Vector2 &location) {
- p=post_menu->get_popup();
- defaults.clear();
- VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_POST_PROCESS,&defaults);
- id=0;
- for(int i=0;i<defaults.size();i++) {
+ if (p_type==ShaderGraph::NODE_INPUT && graph->node_count(type, p_type)>0)
+ return;
- p->add_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
+ List<int> existing;
+ graph->get_node_list(type,&existing);
+ existing.sort();
+ int newid=1;
+ for(List<int>::Element *E=existing.front();E;E=E->next()) {
+ if (!E->next() || (E->get()+1!=E->next()->get())){
+ newid=E->get()+1;
+ break;
+ }
}
- p->add_separator();
- id++;
- defaults.clear();
- VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_POST_PROCESS,&defaults);
+ Vector2 init_ofs = location;
+ while(true) {
+ bool valid=true;
+ for(List<int>::Element *E=existing.front();E;E=E->next()) {
+ Vector2 pos = graph->node_get_pos(type,E->get());
+ if (init_ofs==pos) {
+ init_ofs+=Vector2(20,20);
+ valid=false;
+ break;
- for(int i=0;i<defaults.size();i++) {
+ }
+ }
- p->add_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
+ if (valid)
+ break;
}
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Add Shader Graph Node");
+ ur->add_do_method(graph.ptr(),"node_add",type,p_type,newid);
+ ur->add_do_method(graph.ptr(),"node_set_pos",type,newid,init_ofs);
+ ur->add_undo_method(graph.ptr(),"node_remove",type,newid);
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
- post_popup=p;
- post_popup->connect("item_pressed", this,"_post_item");
+}
+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);
+ ObjectTypeDB::bind_method("_xform_const_changed",&ShaderGraphView::_xform_const_changed);
+ ObjectTypeDB::bind_method("_scalar_op_changed",&ShaderGraphView::_scalar_op_changed);
+ ObjectTypeDB::bind_method("_vec_op_changed",&ShaderGraphView::_vec_op_changed);
+ ObjectTypeDB::bind_method("_vec_scalar_op_changed",&ShaderGraphView::_vec_scalar_op_changed);
+ ObjectTypeDB::bind_method("_rgb_op_changed",&ShaderGraphView::_rgb_op_changed);
+ ObjectTypeDB::bind_method("_xform_inv_rev_changed",&ShaderGraphView::_xform_inv_rev_changed);
+ ObjectTypeDB::bind_method("_scalar_func_changed",&ShaderGraphView::_scalar_func_changed);
+ ObjectTypeDB::bind_method("_vec_func_changed",&ShaderGraphView::_vec_func_changed);
+ ObjectTypeDB::bind_method("_scalar_input_changed",&ShaderGraphView::_scalar_input_changed);
+ ObjectTypeDB::bind_method("_vec_input_changed",&ShaderGraphView::_vec_input_changed);
+ ObjectTypeDB::bind_method("_xform_input_changed",&ShaderGraphView::_xform_input_changed);
+ ObjectTypeDB::bind_method("_rgb_input_changed",&ShaderGraphView::_rgb_input_changed);
+ ObjectTypeDB::bind_method("_tex_input_change",&ShaderGraphView::_tex_input_change);
+ ObjectTypeDB::bind_method("_cube_input_change",&ShaderGraphView::_cube_input_change);
+ ObjectTypeDB::bind_method("_input_name_changed",&ShaderGraphView::_input_name_changed);
+ ObjectTypeDB::bind_method("_tex_edited",&ShaderGraphView::_tex_edited);
+ ObjectTypeDB::bind_method("_variant_edited",&ShaderGraphView::_variant_edited);
+ ObjectTypeDB::bind_method("_cube_edited",&ShaderGraphView::_cube_edited);
+ ObjectTypeDB::bind_method("_comment_edited",&ShaderGraphView::_comment_edited);
+ ObjectTypeDB::bind_method("_color_ramp_changed",&ShaderGraphView::_color_ramp_changed);
+ ObjectTypeDB::bind_method("_curve_changed",&ShaderGraphView::_curve_changed);
+
+ ObjectTypeDB::bind_method("_sg_updated",&ShaderGraphView::_sg_updated);
+}
- /* add popup */
+ShaderGraphView::ShaderGraphView(ShaderGraph::ShaderType p_type) {
+
+ type=p_type;
+ graph_edit = memnew( GraphEdit );
+ block_update=false;
+ ped_popup = memnew( CustomPropertyEditor );
+ 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));
+ status->add_constant_override("shadow_as_outline",1);
+ status->add_constant_override("shadow_offset_x",2);
+ status->add_constant_override("shadow_offset_y",2);
+ status->set_text("");
+}
+
+
+//////////////edit//////////////
+void ShaderGraphEditor::edit(Ref<ShaderGraph> p_shader) {
+
+ for(int i=0;i<ShaderGraph::SHADER_TYPE_MAX;i++) {
+ graph_edits[i]->set_graph(p_shader);
+ }
+}
- add_popup = memnew( Popup );
- add_child(add_popup);
- add_popup->set_as_toplevel(true);
- Panel *add_panel = memnew( Panel );
- add_popup->add_child(add_panel);
- add_panel->set_area_as_parent_rect();
+void ShaderGraphEditor::_add_node(int p_type) {
- Label *add_label = memnew (Label );
- add_label->set_pos(Point2(5,5));
- add_label->set_text("Available Nodes:");
- add_panel->add_child(add_label);
+ ShaderGraph::ShaderType shader_type=ShaderGraph::ShaderType(tabs->get_current_tab());
+ graph_edits[shader_type]->add_node(p_type, next_location);
+}
- add_types = memnew( Tree );
- add_types->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- add_types->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
- add_types->set_begin( Point2( 20,25 ) );
- add_types->set_end( Point2( 10, 30 ) );
- add_types->set_hide_root(true);
- add_types->set_columns(4);
- add_types->set_select_mode(Tree::SELECT_ROW);
+void ShaderGraphEditor::_popup_requested(const Vector2 &p_position)
+{
+ next_location = get_local_mouse_pos();
+ 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) {
- TreeItem *add_types_root = add_types->create_item(NULL);
- TreeItem *info_item = add_types->create_item(add_types_root);
+ for(int i=0;i<ShaderGraph::NODE_TYPE_MAX;i++) {
- for(int i=0;i<VisualServer::NODE_TYPE_MAX;i++) {
+ if (i==ShaderGraph::NODE_OUTPUT)
+ continue;
+ if (!_2d && i==ShaderGraph::NODE_DEFAULT_TEXTURE)
+ continue;
- TreeItem *item = add_types->create_item(add_types_root);
- PropertyInfo prop = VisualServer::shader_node_get_type_info((VisualServer::ShaderNodeType)i);
- item->set_text(0,prop.name);
- item->set_text(1,itos(VisualServer::shader_get_input_count((VisualServer::ShaderNodeType)i)));
- item->set_text(2,itos(VisualServer::shader_get_output_count((VisualServer::ShaderNodeType)i)));
- String hint = (prop.type==Variant::_RID)?prop.hint_string:Variant::get_type_name(prop.type);
- item->set_text(3,hint);
- item->set_metadata(0,i);
- }
- info_item->set_text(0,"::NODE::");
- info_item->set_custom_color(0,Color(0.6,0.1,0.1));
- info_item->set_text(1,"::INPUTS::");
- info_item->set_custom_color(1,Color(0.6,0.1,0.1));
- info_item->set_text(2,"::OUTPUTS::");
- info_item->set_custom_color(2,Color(0.6,0.1,0.1));
- info_item->set_text(3,"::PARAM::");
- info_item->set_custom_color(3,Color(0.6,0.1,0.1));
- info_item->set_selectable(0,false);
- info_item->set_selectable(1,false);
- info_item->set_selectable(2,false);
- info_item->set_selectable(3,false);
+ String nn = node_names[i];
+ String ic = nn.get_slice(":",0);
+ String v = nn.get_slice(":",1);
+ bool addsep=false;
+ if (nn.ends_with(":")) {
+ addsep=true;
+ }
+ popup->add_icon_item(get_icon(ic,"EditorIcons"),v,i);
+ if (addsep)
+ popup->add_separator();
+ }
+ popup->connect("item_pressed",this,"_add_node");
- add_panel->add_child(add_types);
- add_confirm = memnew( Button );
- add_confirm->set_anchor( MARGIN_LEFT, ANCHOR_END );
- add_confirm->set_anchor( MARGIN_TOP, ANCHOR_END );
- add_confirm->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- add_confirm->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
- add_confirm->set_begin( Point2( 75, 29 ) );
- add_confirm->set_end( Point2( 10, 15 ) );
- add_confirm->set_text("Add");
- add_panel->add_child(add_confirm);
- add_confirm->connect("pressed", this,"_node_add_callback");
+ }
+}
- last_id=1;
- last_x=20;
- last_y=20;
+void ShaderGraphEditor::_bind_methods() {
- property_editor = memnew( CustomPropertyEditor );
- add_child(property_editor);
- property_editor->connect("variant_changed", this,"_node_param_changed");
+ ObjectTypeDB::bind_method("_add_node",&ShaderGraphEditor::_add_node);
+ ObjectTypeDB::bind_method("_popup_requested",&ShaderGraphEditor::_popup_requested);
+}
- h_scroll = memnew( HScrollBar );
- v_scroll = memnew( VScrollBar );
- add_child(h_scroll);
- add_child(v_scroll);
+const char* ShaderGraphEditor::node_names[ShaderGraph::NODE_TYPE_MAX]={
+ "GraphInput:Input", // all inputs (shader type dependent)
+ "GraphScalar:Scalar Constant", //scalar constant
+ "GraphVector:Vector Constant", //vec3 constant
+ "GraphRgb:RGB Constant", //rgb constant (shows a color picker instead)
+ "GraphXform:XForm Constant", // 4x4 matrix constant
+ "GraphTime:Time:", // time in seconds
+ "GraphTexscreen:Screen Sample", // screen texture sampler (takes uv) (only usable in fragment shader)
+ "GraphScalarOp:Scalar Operator", // scalar vs scalar op (mul", add", div", etc)
+ "GraphVecOp:Vector Operator", // vec3 vs vec3 op (mul",ad",div",crossprod",etc)
+ "GraphVecScalarOp:Scalar+Vector Operator", // vec3 vs scalar op (mul", add", div", etc)
+ "GraphRgbOp:RGB Operator:", // vec3 vs vec3 rgb op (with scalar amount)", like brighten", darken", burn", dodge", multiply", etc.
+ "GraphXformMult:XForm Multiply", // mat4 x mat4
+ "GraphXformVecMult:XForm+Vector Multiply", // mat4 x vec3 mult (with no-translation option)
+ "GraphXformVecImult:Form+Vector InvMultiply:", // mat4 x vec3 inverse mult (with no-translation option)
+ "GraphXformScalarFunc:Scalar Function", // scalar function (sin", cos", etc)
+ "GraphXformVecFunc:Vector Function", // vector function (normalize", negate", reciprocal", rgb2hsv", hsv2rgb", etc", etc)
+ "GraphVecLength:Vector Length", // vec3 length
+ "GraphVecDp:Dot Product:", // vec3 . vec3 (dot product -> scalar output)
+ "GraphVecToScalars:Vector -> Scalars", // 1 vec3 input", 3 scalar outputs
+ "GraphScalarsToVec:Scalars -> Vector", // 3 scalar input", 1 vec3 output
+ "GraphXformToVecs:XForm -> Vectors", // 3 vec input", 1 xform output
+ "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)
+ "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)
+ "GraphComment:Comment", // comment
- h_scroll->connect("value_changed", this,"_scroll_moved");
- v_scroll->connect("value_changed", this,"_scroll_moved");
- node_popup= memnew(PopupMenu );
- add_child(node_popup);
- node_popup->set_as_toplevel(true);
+};
+ShaderGraphEditor::ShaderGraphEditor(bool p_2d) {
+ _2d=p_2d;
+
+ popup = memnew( PopupMenu );
+ add_child(popup);
+
+
+ tabs = memnew(TabContainer);
+ tabs->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(tabs);
+ const char* sname[ShaderGraph::SHADER_TYPE_MAX]={
+ "Vertex",
+ "Fragment",
+ "Light"
+ };
+ for(int i=0;i<ShaderGraph::SHADER_TYPE_MAX;i++) {
+
+ graph_edits[i]= memnew( ShaderGraphView(ShaderGraph::ShaderType(i)) );
+ add_child(graph_edits[i]);
+ graph_edits[i]->get_graph_edit()->set_name(sname[i]);
+ 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);
+ }
- node_popup->connect("item_pressed", this,"_node_menu_item");
+ tabs->set_current_tab(1);
+ set_custom_minimum_size(Size2(100,300));
}
-void ShaderEditorPlugin::edit(Object *p_object) {
+void ShaderGraphEditorPlugin::edit(Object *p_object) {
- shader_editor->edit(p_object->cast_to<Shader>());
+ shader_editor->edit(p_object->cast_to<ShaderGraph>());
}
-bool ShaderEditorPlugin::handles(Object *p_object) const {
+bool ShaderGraphEditorPlugin::handles(Object *p_object) const {
- return p_object->is_type("Shader");
+ ShaderGraph *shader=p_object->cast_to<ShaderGraph>();
+ if (!shader)
+ return false;
+ if (_2d)
+ return shader->get_mode()==Shader::MODE_CANVAS_ITEM;
+ else
+ return shader->get_mode()==Shader::MODE_MATERIAL;
}
-void ShaderEditorPlugin::make_visible(bool p_visible) {
+void ShaderGraphEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
shader_editor->show();
- shader_editor->set_process(true);
} else {
shader_editor->hide();
- shader_editor->set_process(false);
}
}
-ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) {
+ShaderGraphEditorPlugin::ShaderGraphEditorPlugin(EditorNode *p_node, bool p_2d) {
+ _2d=p_2d;
editor=p_node;
- shader_editor = memnew( ShaderEditor );
- editor->get_viewport()->add_child(shader_editor);
- shader_editor->set_area_as_parent_rect();
+ shader_editor = memnew( ShaderGraphEditor(p_2d) );
shader_editor->hide();
+ if (p_2d)
+ CanvasItemEditor::get_singleton()->get_bottom_split()->add_child(shader_editor);
+ else
+ 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();
}
-ShaderEditorPlugin::~ShaderEditorPlugin()
+ShaderGraphEditorPlugin::~ShaderGraphEditorPlugin()
{
}
-#endif
+
diff --git a/tools/editor/plugins/shader_graph_editor_plugin.h b/tools/editor/plugins/shader_graph_editor_plugin.h
index 5b0767dc82..39e9b29d45 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,122 +29,211 @@
#ifndef SHADER_GRAPH_EDITOR_PLUGIN_H
#define SHADER_GRAPH_EDITOR_PLUGIN_H
-#if 0
+
#include "tools/editor/editor_plugin.h"
#include "tools/editor/editor_node.h"
#include "scene/resources/shader.h"
#include "servers/visual/shader_graph.h"
#include "scene/gui/tree.h"
#include "scene/gui/button.h"
+#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
#include "tools/editor/property_editor.h"
+#include "scene/resources/shader_graph.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
-class ShaderEditor : public Control {
- OBJ_TYPE(ShaderEditor, Control );
+class GraphColorRampEdit : public Control {
+
+ OBJ_TYPE(GraphColorRampEdit,Control);
- enum MenuAction {
- GRAPH_ADD_NODE,
- GRAPH_CLEAR,
- NODE_DISCONNECT,
- NODE_ERASE,
+ struct Point {
+ float offset;
+ Color color;
+ bool operator<(const Point& p_ponit) const {
+ return offset<p_ponit.offset;
+ }
};
- enum ClickType {
- CLICK_NONE,
- CLICK_NODE,
- CLICK_INPUT_SLOT,
- CLICK_OUTPUT_SLOT,
- CLICK_PARAMETER
+ PopupPanel *popup;
+ ColorPicker *picker;
+
+
+ bool grabbing;
+ int grabbed;
+ float grabbed_at;
+ Vector<Point> points;
+
+ void _color_changed(const Color& p_color);
+
+protected:
+ void _input_event(const InputEvent& p_event);
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_ramp(const Vector<float>& p_offsets,const Vector<Color>& p_colors);
+ Vector<float> get_offsets() const;
+ Vector<Color> get_colors() const;
+ virtual Size2 get_minimum_size() const;
+ GraphColorRampEdit();
+};
+
+
+class GraphCurveMapEdit : public Control {
+
+ OBJ_TYPE(GraphCurveMapEdit,Control);
+
+
+ struct Point {
+
+ float offset;
+ float height;
+ bool operator<(const Point& p_ponit) const {
+ return offset<p_ponit.offset;
+ }
};
- PopupMenu *node_popup;
- Popup *add_popup;
- PopupMenu *vertex_popup;
- PopupMenu *fragment_popup;
- PopupMenu *post_popup;
- Tree *add_types;
- Button *add_confirm;
- HScrollBar *h_scroll;
- VScrollBar *v_scroll;
-
- Ref<Shader> shader;
- List<int> order;
- Set<int> active_nodes;
- ShaderGraph shader_graph;
- int last_x,last_y;
- uint32_t last_id;
-
- CustomPropertyEditor *property_editor;
-
- Point2 offset;
- ClickType click_type;
- Point2 click_pos;
- int click_node;
- int click_slot;
- Point2 click_motion;
- ClickType rclick_type;
- int rclick_node;
- int rclick_slot;
-
- Size2 _get_maximum_size();
- Size2 get_node_size(int p_node) const;
- void _draw_node(int p_node);
-
- void _add_node_from_text(const String& p_text);
- void _update_scrollbars();
- void _scroll_moved();
- void _node_param_changed();
- void _node_add_callback();
- void _node_add(VisualServer::ShaderNodeType p_type);
- void _node_edit_property(int p_node);
- void _node_menu_item(int p_item);
- void _vertex_item(int p_item);
- void _fragment_item(int p_item);
- void _post_item(int p_item);
-
- ClickType _locate_click(const Point2& p_click,int *p_node_id,int *p_slot_index) const;
- Point2 _get_slot_pos(int p_node_id,bool p_input,int p_slot);
-
- Error validate_graph();
-
- void _read_shader_graph();
- void _write_shader_graph();
-
- virtual bool has_point(const Point2& p_point) const;
+
+ bool grabbing;
+ int grabbed;
+ Vector<Point> points;
+
+ void _plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d);
protected:
+ void _input_event(const InputEvent& p_event);
void _notification(int p_what);
- void _input_event(InputEvent p_event);
static void _bind_methods();
public:
- void edit(Ref<Shader> p_shader);
- ShaderEditor();
+ void set_points(const Vector<Vector2>& p_points);
+ Vector<Vector2> get_points() const;
+ virtual Size2 get_minimum_size() const;
+ GraphCurveMapEdit();
};
-class ShaderEditorPlugin : public EditorPlugin {
+class ShaderGraphView : public Node {
+
+ OBJ_TYPE(ShaderGraphView,Node);
+
+
+
+ CustomPropertyEditor *ped_popup;
+ bool block_update;
+
+ Label *status;
+ GraphEdit *graph_edit;
+ Ref<ShaderGraph> graph;
+ int edited_id;
+ int edited_def;
+
+ ShaderGraph::ShaderType type;
+
+ void _update_graph();
+ 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);
+ void _rgb_const_changed(const Color& p_color, int p_id);
+ void _xform_const_changed(int p_id,Node* p_button);
+ void _scalar_op_changed(int p_op, int p_id);
+ void _vec_op_changed(int p_op, int p_id);
+ void _vec_scalar_op_changed(int p_op, int p_id);
+ void _rgb_op_changed(int p_op, int p_id);
+ void _xform_inv_rev_changed(bool p_enabled, int p_id);
+ void _scalar_func_changed(int p_func, int p_id);
+ void _vec_func_changed(int p_func, int p_id);
+ void _scalar_input_changed(double p_value,int p_id);
+ void _vec_input_changed(double p_value, int p_id, Array p_arr);
+ void _xform_input_changed(int p_id,Node* p_button);
+ void _rgb_input_changed(const Color& p_color, int p_id);
+ void _tex_input_change(int p_id,Node* p_button);
+ void _cube_input_change(int p_id);
+ void _input_name_changed(const String& p_name,int p_id,Node* p_line_edit);
+ void _tex_edited(int p_id,Node* p_button);
+ void _cube_edited(int p_id,Node* p_button);
+ void _variant_edited();
+ void _comment_edited(int p_id,Node* p_button);
+ void _color_ramp_changed(int p_id,Node* p_ramp);
+ void _curve_changed(int p_id,Node* p_curve);
+ void _sg_updated();
+ Map<int,GraphNode*> node_map;
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void add_node(int p_type, const Vector2 &location);
+ GraphEdit *get_graph_edit() { return graph_edit; }
+ void set_graph(Ref<ShaderGraph> p_graph);
- OBJ_TYPE( ShaderEditorPlugin, EditorPlugin );
+ ShaderGraphView(ShaderGraph::ShaderType p_type=ShaderGraph::SHADER_TYPE_FRAGMENT);
+};
+
+class ShaderGraphEditor : public VBoxContainer {
+
+ OBJ_TYPE(ShaderGraphEditor,VBoxContainer);
- ShaderEditor *shader_editor;
+ 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();
+public:
+
+ void edit(Ref<ShaderGraph> p_shader);
+ ShaderGraphEditor(bool p_2d);
+};
+
+class ShaderGraphEditorPlugin : public EditorPlugin {
+
+ OBJ_TYPE( ShaderGraphEditorPlugin, EditorPlugin );
+
+ bool _2d;
+ ShaderGraphEditor *shader_editor;
EditorNode *editor;
public:
- virtual String get_name() const { return "Shader"; }
+ virtual String get_name() const { return "ShaderGraph"; }
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);
- ShaderEditorPlugin(EditorNode *p_node);
- ~ShaderEditorPlugin();
+ ShaderGraphEditorPlugin(EditorNode *p_node,bool p_2d);
+ ~ShaderGraphEditorPlugin();
};
#endif
-#endif // SHADER_GRAPH_EDITOR_PLUGIN_H
+
diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp
index 1bf425f3f3..7816efe89f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,7 +38,7 @@
#include "tools/editor/editor_settings.h"
#include "scene/resources/surface_tool.h"
#include "tools/editor/spatial_editor_gizmos.h"
-
+#include "globals.h"
#define DISTANCE_DEFAULT 4
@@ -232,15 +232,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)
@@ -249,7 +240,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2& p_pos, bool p_append,b
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_scene()->get_root()->get_world()->get_scenario() );
+ Vector<RID> instances=VisualServer::get_singleton()->instances_cull_ray(pos,ray,get_tree()->get_root()->get_world()->get_scenario() );
Set<Ref<SpatialEditorGizmo> > found_gizmos;
//uint32_t closest=0;
@@ -379,6 +370,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) {
@@ -449,7 +504,7 @@ void SpatialEditorViewport::_select_region() {
frustum.push_back( far );
- Vector<RID> instances=VisualServer::get_singleton()->instances_cull_convex(frustum,get_scene()->get_root()->get_world()->get_scenario());
+ Vector<RID> instances=VisualServer::get_singleton()->instances_cull_convex(frustum,get_tree()->get_root()->get_world()->get_scenario());
for (int i=0;i<instances.size();i++) {
@@ -477,6 +532,16 @@ void SpatialEditorViewport::_select_region() {
}
+void SpatialEditorViewport::_update_name() {
+
+ String ortho = orthogonal?"Orthogonal":"Perspective";
+
+ if (name!="")
+ view_menu->set_text("[ "+name+" "+ortho+" ]");
+ else
+ view_menu->set_text("[ "+ortho+" ]");
+}
+
void SpatialEditorViewport::_compute_edit(const Point2& p_point) {
@@ -535,6 +600,14 @@ SpatialEditorViewport::NavigationScheme SpatialEditorViewport::_get_navigation_s
return NAVIGATION_GODOT;
}
+SpatialEditorViewport::NavigationZoomStyle SpatialEditorViewport::_get_navigation_zoom_style(const String& p_property) {
+ switch(EditorSettings::get_singleton()->get(p_property).operator int()) {
+ case 0: return NAVIGATION_ZOOM_VERTICAL;
+ case 1: return NAVIGATION_ZOOM_HORIZONTAL;
+ }
+ return NAVIGATION_ZOOM_VERTICAL;
+}
+
bool SpatialEditorViewport::_gizmo_select(const Vector2& p_screenpos,bool p_hilite_only) {
if (!spatial_editor->is_gizmo_visible())
@@ -659,7 +732,8 @@ 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::_sinput(const InputEvent &p_event) {
@@ -690,15 +764,22 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
case BUTTON_WHEEL_UP: {
+
cursor.distance/=1.08;
+ if (cursor.distance<0.001)
+ cursor.distance=0.001;
+
} break;
case BUTTON_WHEEL_DOWN: {
+ if (cursor.distance<0.001)
+ cursor.distance=0.001;
cursor.distance*=1.08;
} break;
case BUTTON_RIGHT: {
+ NavigationScheme nav_scheme = _get_navigation_schema("3d_editor/navigation_scheme");
if (b.pressed && _edit.gizmo.is_valid()) {
//restore
@@ -718,7 +799,7 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (b.mod.control) {
- Vector<RID> instances=VisualServer::get_singleton()->instances_cull_ray(ray_origin,ray_dir,get_scene()->get_root()->get_world()->get_scenario() );
+ Vector<RID> instances=VisualServer::get_singleton()->instances_cull_ray(ray_origin,ray_dir,get_tree()->get_root()->get_world()->get_scenario() );
Plane p(ray_origin,_get_camera_normal());
@@ -781,6 +862,57 @@ 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;
+
+ _find_items_at_pos(Vector2( b.x, b.y ),clicked_includes_current,selection_results,b.mod.shift);
+
+ 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");
+
+ break;
+ }
+ }
}
if (_edit.mode!=TRANSFORM_NONE && b.pressed) {
@@ -818,6 +950,8 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
_edit.plane=TRANSFORM_X_AXIS;
set_message("View Plane Transform.",2);
+ name="";
+ _update_name();
} break;
case TRANSFORM_X_AXIS: {
@@ -854,10 +988,19 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
_edit.snap=false;
_edit.mode=TRANSFORM_NONE;
+
//gizmo has priority over everything
+ bool can_select_gizmos=true;
+
+ {
+ int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
+ can_select_gizmos = view_menu->get_popup()->is_item_checked( idx );
+ }
- if (spatial_editor->get_selected()) {
+
+
+ if (can_select_gizmos && spatial_editor->get_selected()) {
Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo();
if (seg.is_valid()) {
@@ -1414,10 +1557,19 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (nav_scheme==NAVIGATION_MAYA && m.mod.shift)
zoom_speed *= zoom_speed_modifier;
- if ( m.relative_y > 0)
- cursor.distance*=1+m.relative_y*zoom_speed;
- else if (m.relative_y < 0)
- cursor.distance/=1-m.relative_y*zoom_speed;
+ NavigationZoomStyle zoom_style = _get_navigation_zoom_style("3d_editor/zoom_style");
+ if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
+ if ( m.relative_x > 0)
+ cursor.distance*=1-m.relative_x*zoom_speed;
+ else if (m.relative_x < 0)
+ cursor.distance/=1+m.relative_x*zoom_speed;
+ }
+ else {
+ if ( m.relative_y > 0)
+ cursor.distance*=1+m.relative_y*zoom_speed;
+ else if (m.relative_y < 0)
+ cursor.distance/=1-m.relative_y*zoom_speed;
+ }
} break;
@@ -1428,6 +1580,8 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
cursor.x_rot=Math_PI/2.0;
if (cursor.x_rot<-Math_PI/2.0)
cursor.x_rot=-Math_PI/2.0;
+ name="";
+ _update_name();
} break;
default: {}
@@ -1452,9 +1606,14 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (k.mod.shift) {
cursor.x_rot=-Math_PI/2.0;
set_message("Bottom View.",2);
+ name="Bottom";
+ _update_name();
+
} else {
cursor.x_rot=Math_PI/2.0;
set_message("Top View.",2);
+ name="Top";
+ _update_name();
}
} break;
case KEY_KP_1: {
@@ -1463,10 +1622,14 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (k.mod.shift) {
cursor.y_rot=Math_PI;
set_message("Rear View.",2);
+ name="Rear";
+ _update_name();
} else {
cursor.y_rot=0;
set_message("Front View.",2);
+ name="Front";
+ _update_name();
}
} break;
@@ -1476,9 +1639,13 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (k.mod.shift) {
cursor.y_rot=Math_PI/2.0;
set_message("Left View.",2);
+ name="Left";
+ _update_name();
} else {
cursor.y_rot=-Math_PI/2.0;
set_message("Right View.",2);
+ name="Right";
+ _update_name();
}
} break;
@@ -1486,6 +1653,7 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
orthogonal = !orthogonal;
_menu_option(orthogonal?VIEW_PERSPECTIVE:VIEW_ORTHOGONAL);
+ _update_name();
} break;
@@ -1696,7 +1864,7 @@ void SpatialEditorViewport::_notification(int p_what) {
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
surface->connect("draw",this,"_draw");
surface->connect("input_event",this,"_sinput");
@@ -1705,6 +1873,12 @@ void SpatialEditorViewport::_notification(int p_what) {
_init_gizmo_instance(index);
}
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+
+ _finish_gizmo_instances();
+
+ }
if (p_what==NOTIFICATION_MOUSE_ENTER) {
@@ -1753,6 +1927,41 @@ void SpatialEditorViewport::_draw() {
}
+ if (previewing) {
+
+
+ Size2 ss = Size2( Globals::get_singleton()->get("display/width"), Globals::get_singleton()->get("display/height") );
+ float aspect = ss.get_aspect();
+ Size2 s = get_size();
+
+ Rect2 draw_rect;
+
+
+ switch(previewing->get_keep_aspect_mode()) {
+ case Camera::KEEP_WIDTH: {
+
+ draw_rect.size = Size2(s.width,s.width/aspect);
+ draw_rect.pos.x=0;
+ draw_rect.pos.y=(s.height-draw_rect.size.y)*0.5;
+
+ } break;
+ case Camera::KEEP_HEIGHT: {
+
+ draw_rect.size = Size2(s.height*aspect,s.height);
+ draw_rect.pos.y=0;
+ draw_rect.pos.x=(s.width-draw_rect.size.x)*0.5;
+
+ } break;
+ }
+
+ draw_rect = Rect2(Vector2(),s).clip(draw_rect);
+
+ surface->draw_line(draw_rect.pos,draw_rect.pos+Vector2(draw_rect.size.x,0),Color(0.6,0.6,0.1,0.5),2.0);
+ surface->draw_line(draw_rect.pos+Vector2(draw_rect.size.x,0),draw_rect.pos+draw_rect.size,Color(0.6,0.6,0.1,0.5),2.0);
+ surface->draw_line(draw_rect.pos+draw_rect.size,draw_rect.pos+Vector2(0,draw_rect.size.y),Color(0.6,0.6,0.1,0.5),2.0);
+ surface->draw_line(draw_rect.pos,draw_rect.pos+Vector2(0,draw_rect.size.y),Color(0.6,0.6,0.1,0.5),2.0);
+ }
+
}
@@ -1764,35 +1973,47 @@ void SpatialEditorViewport::_menu_option(int p_option) {
cursor.x_rot=Math_PI/2.0;
cursor.y_rot=0;
+ name="Top";
+ _update_name();
} break;
case VIEW_BOTTOM: {
cursor.x_rot=-Math_PI/2.0;
cursor.y_rot=0;
+ name="Bottom";
+ _update_name();
} break;
case VIEW_LEFT: {
cursor.y_rot=Math_PI/2.0;
cursor.x_rot=0;
+ name="Left";
+ _update_name();
} break;
case VIEW_RIGHT: {
cursor.y_rot=-Math_PI/2.0;
cursor.x_rot=0;
+ name="Right";
+ _update_name();
} break;
case VIEW_FRONT: {
cursor.y_rot=0;
cursor.x_rot=0;
+ name="Front";
+ _update_name();
} break;
case VIEW_REAR: {
cursor.y_rot=Math_PI;
cursor.x_rot=0;
+ name="Rear";
+ _update_name();
} break;
case VIEW_CENTER_TO_SELECTION: {
@@ -1843,11 +2064,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;
@@ -1874,6 +2095,7 @@ void SpatialEditorViewport::_menu_option(int p_option) {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false );
orthogonal=false;
call_deferred("update_transform_gizmo_view");
+ _update_name();
} break;
case VIEW_ORTHOGONAL: {
@@ -1882,6 +2104,28 @@ void SpatialEditorViewport::_menu_option(int p_option) {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true );
orthogonal=true;
call_deferred("update_transform_gizmo_view");
+ _update_name();
+
+ } break;
+ case VIEW_AUDIO_LISTENER: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
+ bool current = view_menu->get_popup()->is_item_checked( idx );
+ current=!current;
+ viewport->set_as_audio_listener(current);
+ view_menu->get_popup()->set_item_checked( idx, current );
+
+ } break;
+ case VIEW_GIZMOS: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
+ bool current = view_menu->get_popup()->is_item_checked( idx );
+ current=!current;
+ if (current)
+ camera->set_visible_layers( ((1<<20)-1)|(1<<(GIZMO_BASE_LAYER+index))|(1<<GIZMO_EDIT_LAYER)|(1<<GIZMO_GRID_LAYER) );
+ else
+ camera->set_visible_layers( ((1<<20)-1)|(1<<(GIZMO_BASE_LAYER+index))|(1<<GIZMO_GRID_LAYER) );
+ view_menu->get_popup()->set_item_checked( idx, current );
} break;
@@ -1900,12 +2144,12 @@ void SpatialEditorViewport::_preview_exited_scene() {
void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
- uint32_t layer=1<<(GIZMO_BASE_LAYER+p_idx);
+ uint32_t layer=1<<(GIZMO_BASE_LAYER+p_idx);//|(1<<GIZMO_GRID_LAYER);
for(int i=0;i<3;i++) {
move_gizmo_instance[i]=VS::get_singleton()->instance_create();
VS::get_singleton()->instance_set_base(move_gizmo_instance[i],spatial_editor->get_move_gizmo(i)->get_rid());
- VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i],get_scene()->get_root()->get_world()->get_scenario());
+ VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i],get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i],VS::INSTANCE_FLAG_VISIBLE,false);
//VS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i],VS::INSTANCE_FLAG_CAST_SHADOW,false);
@@ -1913,7 +2157,7 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
rotate_gizmo_instance[i]=VS::get_singleton()->instance_create();
VS::get_singleton()->instance_set_base(rotate_gizmo_instance[i],spatial_editor->get_rotate_gizmo(i)->get_rid());
- VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i],get_scene()->get_root()->get_world()->get_scenario());
+ VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i],get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i],VS::INSTANCE_FLAG_VISIBLE,false);
//VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i],VS::INSTANCE_FLAG_CAST_SHADOW,false);
@@ -1922,6 +2166,16 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
}
+
+void SpatialEditorViewport::_finish_gizmo_instances() {
+
+
+ for(int i=0;i<3;i++) {
+ VS::get_singleton()->free(move_gizmo_instance[i]);
+ VS::get_singleton()->free(rotate_gizmo_instance[i]);
+ }
+
+}
void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
@@ -1930,23 +2184,45 @@ void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
if (!p_activate) {
- previewing->disconnect("exit_scene",this,"_preview_exited_scene");
+ previewing->disconnect("exit_tree",this,"_preview_exited_scene");
previewing=NULL;
VS::get_singleton()->viewport_attach_camera( viewport->get_viewport(), camera->get_camera() ); //restore
if (!preview)
preview_camera->hide();
view_menu->show();
+ surface->update();
} else {
previewing=preview;
- previewing->connect("exit_scene",this,"_preview_exited_scene");
+ previewing->connect("exit_tree",this,"_preview_exited_scene");
VS::get_singleton()->viewport_attach_camera( viewport->get_viewport(), preview->get_camera() ); //replace
view_menu->hide();
+ surface->update();
+
+ }
+}
+
+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;
@@ -2012,8 +2288,26 @@ void SpatialEditorViewport::set_state(const Dictionary& p_state) {
_menu_option(VIEW_PERSPECTIVE);
if (env != camera->get_environment().is_valid())
_menu_option(VIEW_ENVIRONMENT);
+ if (p_state.has("listener")) {
+ bool listener = p_state["listener"];
+ int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
+ viewport->set_as_audio_listener(listener);
+ 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 {
@@ -2025,6 +2319,11 @@ Dictionary SpatialEditorViewport::get_state() const {
d["distance"]=cursor.distance;
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;
}
@@ -2038,15 +2337,38 @@ 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")) );
}
+void SpatialEditorViewport::reset() {
+ orthogonal=false;
+ message_time=0;
+ message="";
+ last_message="";
+ name="Top";
+
+ cursor.x_rot=0;
+ cursor.y_rot=0;
+ cursor.distance=4;
+ cursor.region_select=false;
+ _update_name();
+}
SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
+ _edit.mode=TRANSFORM_NONE;
+ _edit.plane=TRANSFORM_VIEW;
+ _edit.edited_gizmo=0;
+ _edit.snap=1;
+ _edit.gizmo_handle=0;
+
+
+
index=p_index;
editor=p_editor;
editor_selection=editor->get_editor_selection();;
@@ -2067,7 +2389,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
surface->set_area_as_parent_rect();
camera = memnew(Camera);
camera->set_disable_gizmo(true);
- camera->set_visible_layers( ((1<<20)-1)|(1<<(GIZMO_BASE_LAYER+p_index)) );
+ camera->set_visible_layers( ((1<<20)-1)|(1<<(GIZMO_BASE_LAYER+p_index))|(1<<GIZMO_EDIT_LAYER)|(1<<GIZMO_GRID_LAYER) );
//camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment());
viewport->add_child(camera);
camera->make_current();
@@ -2076,23 +2398,28 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
view_menu = memnew( MenuButton );
surface->add_child(view_menu);
view_menu->set_pos( Point2(4,4));
- view_menu->set_text("[view]");
view_menu->set_self_opacity(0.5);
- view_menu->get_popup()->add_item("Top",VIEW_TOP);
- view_menu->get_popup()->add_item("Bottom",VIEW_BOTTOM);
- view_menu->get_popup()->add_item("Left",VIEW_LEFT);
- view_menu->get_popup()->add_item("Right",VIEW_RIGHT);
- view_menu->get_popup()->add_item("Front",VIEW_FRONT);
- view_menu->get_popup()->add_item("Rear",VIEW_REAR);
+ view_menu->get_popup()->add_item("Top (Num7)",VIEW_TOP);
+ view_menu->get_popup()->add_item("Bottom (Shift+Num7)",VIEW_BOTTOM);
+ view_menu->get_popup()->add_item("Left (Num3)",VIEW_LEFT);
+ view_menu->get_popup()->add_item("Right (Shift+Num3)",VIEW_RIGHT);
+ view_menu->get_popup()->add_item("Front (Num1)",VIEW_FRONT);
+ view_menu->get_popup()->add_item("Rear (Shift+Num1)",VIEW_REAR);
view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_check_item("Perspective",VIEW_PERSPECTIVE);
- view_menu->get_popup()->add_check_item("Orthogonal",VIEW_ORTHOGONAL);
+ view_menu->get_popup()->add_check_item("Perspective (Num5)",VIEW_PERSPECTIVE);
+ view_menu->get_popup()->add_check_item("Orthogonal (Num5)",VIEW_ORTHOGONAL);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE),true);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_item("Environment",VIEW_ENVIRONMENT);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT),true);
view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_check_item("Audio Listener",VIEW_AUDIO_LISTENER);
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_check_item("Gizmos",VIEW_GIZMOS);
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_GIZMOS),true);
+
+ view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_item("Selection (F)",VIEW_CENTER_TO_SELECTION);
view_menu->get_popup()->add_item("Align with view (Ctrl+Shift+F)",VIEW_ALIGN_SELECTION_WITH_VIEW);
view_menu->get_popup()->connect("item_pressed",this,"_menu_option");
@@ -2108,6 +2435,22 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
previewing=NULL;
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);
+ }
+
+
+ name="Top";
+ _update_name();
+
EditorSettings::get_singleton()->connect("settings_changed",this,"update_transform_gizmo_view");
}
@@ -2205,7 +2548,7 @@ Object *SpatialEditor::_get_editor_data(Object *p_what) {
// si->aabb = VisualServer::get_singleton()->instance_get_base_aabb(inst);
- if (get_scene()->is_editor_hint())
+ if (get_tree()->is_editor_hint())
editor->call("edit_node",sp);
@@ -2267,6 +2610,10 @@ Dictionary SpatialEditor::get_state() const {
vc=3;
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS) ))
vc=4;
+ else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT) ))
+ vc=5;
+ else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT) ))
+ vc=6;
d["viewport_mode"]=vc;
Array vpdata;
@@ -2277,11 +2624,16 @@ Dictionary SpatialEditor::get_state() const {
d["viewports"]=vpdata;
d["default_light"]=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT) );;
+ d["ambient_light_color"]=settings_ambient_color->get_color();
+
+ d["default_srgb"]=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB) );;
d["show_grid"]=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID) );;
d["show_origin"]=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN) );;
d["fov"]=get_fov();
d["znear"]=get_znear();
d["zfar"]=get_zfar();
+ d["deflight_rot_x"]=settings_default_light_rot_x;
+ d["deflight_rot_y"]=settings_default_light_rot_y;
return d;
}
@@ -2308,6 +2660,10 @@ void SpatialEditor::set_state(const Dictionary& p_state) {
_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);
@@ -2318,11 +2674,12 @@ void SpatialEditor::set_state(const Dictionary& p_state) {
if (d.has("zfar"))
- settings_zfar->set_text(d["zfar"]);
+ settings_zfar->set_val(float(d["zfar"]));
if (d.has("znear"))
- settings_znear->set_text(d["znear"]);
+ settings_znear->set_val(float(d["znear"]));
if (d.has("fov"))
- settings_fov->set_text(d["fov"]);
+ settings_fov->set_val(float(d["fov"]));
+
if (d.has("default_light")) {
bool use = d["default_light"];
@@ -2332,7 +2689,7 @@ void SpatialEditor::set_state(const Dictionary& p_state) {
VisualServer::get_singleton()->free(light_instance);
light_instance=RID();
} else {
- light_instance=VisualServer::get_singleton()->instance_create2(light,get_scene()->get_root()->get_world()->get_scenario());
+ light_instance=VisualServer::get_singleton()->instance_create2(light,get_tree()->get_root()->get_world()->get_scenario());
VisualServer::get_singleton()->instance_set_transform(light_instance,light_transform);
}
@@ -2340,13 +2697,22 @@ void SpatialEditor::set_state(const Dictionary& p_state) {
}
}
+ if (d.has("ambient_light_color")) {
+ settings_ambient_color->set_color(d["ambient_light_color"]);
+ viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,d["ambient_light_color"]);
+ }
+ if (d.has("default_srgb")) {
+ bool use = d["default_srgb"];
+
+ viewport_environment->set_enable_fx(Environment::FX_SRGB,use);
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB), use );
+ }
if (d.has("show_grid")) {
bool use = d["show_grid"];
if (use!=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID))) {
- view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), use );
- grid_enabled=use;
+ _menu_item_pressed(MENU_VIEW_GRID);
}
}
@@ -2359,6 +2725,12 @@ void SpatialEditor::set_state(const Dictionary& p_state) {
}
}
+ if (d.has("deflight_rot_x"))
+ settings_default_light_rot_x=d["deflight_rot_x"];
+ if (d.has("deflight_rot_y"))
+ settings_default_light_rot_y=d["deflight_rot_y"];
+
+ _update_default_light_angle();
}
@@ -2488,7 +2860,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: {
@@ -2519,13 +2891,31 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
VisualServer::get_singleton()->free(light_instance);
light_instance=RID();
} else {
- light_instance=VisualServer::get_singleton()->instance_create2(light,get_scene()->get_root()->get_world()->get_scenario());
+ light_instance=VisualServer::get_singleton()->instance_create2(light,get_tree()->get_root()->get_world()->get_scenario());
VisualServer::get_singleton()->instance_set_transform(light_instance,light_transform);
+
+ _update_default_light_angle();
}
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(p_option), light_instance.is_valid() );
} break;
+ case MENU_VIEW_USE_DEFAULT_SRGB: {
+
+ bool is_checked = view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(p_option) );
+
+ if (is_checked) {
+ viewport_environment->set_enable_fx(Environment::FX_SRGB,false);
+ } else {
+ viewport_environment->set_enable_fx(Environment::FX_SRGB,true);
+ }
+
+ is_checked = ! is_checked;
+
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(p_option), is_checked );
+
+
+ } break;
case MENU_VIEW_USE_1_VIEWPORT: {
for(int i=1;i<4;i++) {
@@ -2539,6 +2929,8 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
} break;
case MENU_VIEW_USE_2_VIEWPORTS: {
@@ -2561,6 +2953,32 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
+
+ } break;
+ case MENU_VIEW_USE_2_VIEWPORTS_ALT: {
+
+ for(int i=1;i<4;i++) {
+
+ if (i==1 || i==3)
+ viewports[i]->hide();
+ else
+ viewports[i]->show();
+
+
+ }
+ viewports[0]->set_area_as_parent_rect();
+ viewports[0]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
+ viewports[2]->set_area_as_parent_rect();
+ viewports[2]->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_RATIO,0.5);
+
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), true );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
} break;
case MENU_VIEW_USE_3_VIEWPORTS: {
@@ -2585,6 +3003,34 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
+
+ } break;
+ case MENU_VIEW_USE_3_VIEWPORTS_ALT: {
+
+ for(int i=1;i<4;i++) {
+
+ if (i==1)
+ viewports[i]->hide();
+ else
+ viewports[i]->show();
+ }
+ viewports[0]->set_area_as_parent_rect();
+ viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_RATIO,0.5);
+ viewports[0]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
+ viewports[2]->set_area_as_parent_rect();
+ viewports[2]->set_anchor_and_margin(MARGIN_TOP,ANCHOR_RATIO,0.5);
+ viewports[2]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
+ viewports[3]->set_area_as_parent_rect();
+ viewports[3]->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_RATIO,0.5);
+
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), true );
} break;
case MENU_VIEW_USE_4_VIEWPORTS: {
@@ -2610,32 +3056,46 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), true );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
} break;
case MENU_VIEW_DISPLAY_NORMAL: {
- VisualServer::get_singleton()->scenario_set_debug( get_scene()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_DISABLED );
+ VisualServer::get_singleton()->scenario_set_debug( get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_DISABLED );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false );
} break;
case MENU_VIEW_DISPLAY_WIREFRAME: {
- VisualServer::get_singleton()->scenario_set_debug( get_scene()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_WIREFRAME );
+ VisualServer::get_singleton()->scenario_set_debug( get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_WIREFRAME );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false );
} break;
case MENU_VIEW_DISPLAY_OVERDRAW: {
- VisualServer::get_singleton()->scenario_set_debug( get_scene()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_OVERDRAW );
+ VisualServer::get_singleton()->scenario_set_debug( get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_OVERDRAW );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), true );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false );
+
+ } break;
+ case MENU_VIEW_DISPLAY_SHADELESS: {
+
+ VisualServer::get_singleton()->scenario_set_debug( get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_SHADELESS );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false );
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), true );
} break;
case MENU_VIEW_ORIGIN: {
@@ -2653,13 +3113,20 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
grid_enabled=!is_checked;
+ for(int i=0;i<3;++i) {
+ if (grid_enable[i]) {
+ VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,grid_enabled);
+ grid_visible[i]=grid_enabled;
+ }
+ }
+
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(p_option), grid_enabled );
} break;
case MENU_VIEW_CAMERA_SETTINGS: {
- settings_dialog->popup_centered(Size2(200,160));
+ settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size()+Size2(50,50));
} break;
}
@@ -2671,21 +3138,22 @@ void SpatialEditor::_init_indicators() {
//make sure that the camera indicator is not selectable
light=VisualServer::get_singleton()->light_create( VisualServer::LIGHT_DIRECTIONAL );
//VisualServer::get_singleton()->light_set_shadow( light, true );
- light_instance=VisualServer::get_singleton()->instance_create2(light,get_scene()->get_root()->get_world()->get_scenario());
+ light_instance=VisualServer::get_singleton()->instance_create2(light,get_tree()->get_root()->get_world()->get_scenario());
+
light_transform.rotate(Vector3(1,0,0),Math_PI/5.0);
VisualServer::get_singleton()->instance_set_transform(light_instance,light_transform);
- RID mat = VisualServer::get_singleton()->fixed_material_create();
- VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
- VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
+ //RID mat = VisualServer::get_singleton()->fixed_material_create();
+ ///VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
+ //VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
{
- RID indicator_mat = VisualServer::get_singleton()->fixed_material_create();
+ indicator_mat = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_UNSHADED, true );
VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_ONTOP, false );
VisualServer::get_singleton()->fixed_material_set_flag(indicator_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
@@ -2731,11 +3199,13 @@ void SpatialEditor::_init_indicators() {
d[VisualServer::ARRAY_COLOR]=grid_colors[i];
VisualServer::get_singleton()->mesh_add_surface(grid[i],VisualServer::PRIMITIVE_LINES,d);
VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat);
- grid_instance[i] = VisualServer::get_singleton()->instance_create2(grid[i],get_scene()->get_root()->get_world()->get_scenario());
+ grid_instance[i] = VisualServer::get_singleton()->instance_create2(grid[i],get_tree()->get_root()->get_world()->get_scenario());
+
grid_visible[i]=false;
grid_enable[i]=false;
VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,false);
VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_CAST_SHADOW,false);
+ VS::get_singleton()->instance_set_layer_mask(grid_instance[i],1<<SpatialEditorViewport::GIZMO_GRID_LAYER);
}
@@ -2747,13 +3217,15 @@ void SpatialEditor::_init_indicators() {
d[VisualServer::ARRAY_COLOR]=origin_colors;
VisualServer::get_singleton()->mesh_add_surface(origin,VisualServer::PRIMITIVE_LINES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(origin,0,indicator_mat,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(origin,0,indicator_mat);
// origin = VisualServer::get_singleton()->poly_create();
// VisualServer::get_singleton()->poly_add_primitive(origin,origin_points,Vector<Vector3>(),origin_colors,Vector<Vector3>());
// VisualServer::get_singleton()->poly_set_material(origin,indicator_mat,true);
- origin_instance = VisualServer::get_singleton()->instance_create2(origin,get_scene()->get_root()->get_world()->get_scenario());
+ origin_instance = VisualServer::get_singleton()->instance_create2(origin,get_tree()->get_root()->get_world()->get_scenario());
+ VS::get_singleton()->instance_set_layer_mask(origin_instance,1<<SpatialEditorViewport::GIZMO_GRID_LAYER);
+
VisualServer::get_singleton()->instance_geometry_set_flag(origin_instance,VS::INSTANCE_FLAG_CAST_SHADOW,false);
@@ -2776,19 +3248,21 @@ void SpatialEditor::_init_indicators() {
cursor_points.push_back(Vector3(0,-cs,0));
cursor_points.push_back(Vector3(0,0,+cs));
cursor_points.push_back(Vector3(0,0,-cs));
- RID cmat=VisualServer::get_singleton()->fixed_material_create();
- VisualServer::get_singleton()->fixed_material_set_param(cmat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0,1,1));
- VisualServer::get_singleton()->material_set_flag( cmat, VisualServer::MATERIAL_FLAG_UNSHADED, true );
- VisualServer::get_singleton()->fixed_material_set_flag(cmat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
- VisualServer::get_singleton()->fixed_material_set_flag(cmat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
+ cursor_material=VisualServer::get_singleton()->fixed_material_create();
+ VisualServer::get_singleton()->fixed_material_set_param(cursor_material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0,1,1));
+ VisualServer::get_singleton()->material_set_flag( cursor_material, VisualServer::MATERIAL_FLAG_UNSHADED, true );
+ VisualServer::get_singleton()->fixed_material_set_flag(cursor_material, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
+ VisualServer::get_singleton()->fixed_material_set_flag(cursor_material, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
Array d;
d.resize(VS::ARRAY_MAX);
d[VS::ARRAY_VERTEX]=cursor_points;
VisualServer::get_singleton()->mesh_add_surface(cursor_mesh,VS::PRIMITIVE_LINES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(cursor_mesh,0,cmat,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(cursor_mesh,0,cursor_material);
+
+ cursor_instance = VisualServer::get_singleton()->instance_create2(cursor_mesh,get_tree()->get_root()->get_world()->get_scenario());
+ VS::get_singleton()->instance_set_layer_mask(cursor_instance,1<<SpatialEditorViewport::GIZMO_GRID_LAYER);
- cursor_instance = VisualServer::get_singleton()->instance_create2(cursor_mesh,get_scene()->get_root()->get_world()->get_scenario());
VisualServer::get_singleton()->instance_geometry_set_flag(cursor_instance,VS::INSTANCE_FLAG_CAST_SHADOW,false);
@@ -2800,11 +3274,13 @@ void SpatialEditor::_init_indicators() {
//move gizmo
+ float gizmo_alph = EditorSettings::get_singleton()->get("3d_editor/manipulator_gizmo_opacity");
+
gizmo_hl = Ref<FixedMaterial>( memnew( FixedMaterial ) );
gizmo_hl->set_flag(Material::FLAG_UNSHADED, true);
gizmo_hl->set_flag(Material::FLAG_ONTOP, true);
gizmo_hl->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- gizmo_hl->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.4));
+ gizmo_hl->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,gizmo_alph+0.2f));
for(int i=0;i<3;i++) {
@@ -2818,7 +3294,7 @@ void SpatialEditor::_init_indicators() {
mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
Color col;
col[i]=1.0;
- col.a=0.2;
+ col.a= gizmo_alph;
mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,col);
gizmo_color[i]=mat;
@@ -2855,11 +3331,11 @@ void SpatialEditor::_init_indicators() {
int arrow_sides=6;
- for(int i = 0; i < 7 ; i++) {
+ for(int k = 0; k < 7 ; k++) {
- Matrix3 ma(ivec,Math_PI*2*float(i)/arrow_sides);
- Matrix3 mb(ivec,Math_PI*2*float(i+1)/arrow_sides);
+ Matrix3 ma(ivec,Math_PI*2*float(k)/arrow_sides);
+ Matrix3 mb(ivec,Math_PI*2*float(k+1)/arrow_sides);
for(int j=0;j<arrow_points-1;j++) {
@@ -2951,7 +3427,6 @@ void SpatialEditor::_init_indicators() {
void SpatialEditor::_finish_indicators() {
-
VisualServer::get_singleton()->free(origin_instance);
VisualServer::get_singleton()->free(origin);
for(int i=0;i<3;i++) {
@@ -2966,6 +3441,8 @@ void SpatialEditor::_finish_indicators() {
VisualServer::get_singleton()->free(cursor_instance);
VisualServer::get_singleton()->free(cursor_mesh);
+ VisualServer::get_singleton()->free(indicator_mat);
+ VisualServer::get_singleton()->free(cursor_material);
}
void SpatialEditor::_instance_scene() {
@@ -3054,26 +3531,31 @@ void SpatialEditor::_notification(int p_what) {
tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon( get_icon("ToolRotate","EditorIcons") );
tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon( get_icon("ToolScale","EditorIcons") );
instance_button->set_icon( get_icon("SpatialAdd","EditorIcons") );
+ instance_button->hide();
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT),get_icon("Panels1","EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS),get_icon("Panels2","EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT),get_icon("Panels2Alt","EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS),get_icon("Panels3","EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT),get_icon("Panels3Alt","EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS),get_icon("Panels4","EditorIcons"));
_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
- get_scene()->connect("node_removed",this,"_node_removed");
+ get_tree()->connect("node_removed",this,"_node_removed");
+ VS::get_singleton()->scenario_set_fallback_environment(get_viewport()->find_world()->get_scenario(),viewport_environment->get_rid());
+
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
gizmos = memnew( SpatialEditorGizmos );
_init_indicators();
-
+ _update_default_light_angle();
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
_finish_indicators();
memdelete( gizmos );
@@ -3175,8 +3657,12 @@ void SpatialEditor::_toggle_maximize_view(Object* p_viewport) {
_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS) ))
_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
+ else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT) ))
+ _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS) ))
_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
+ else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT) ))
+ _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS) ))
_menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
}
@@ -3201,7 +3687,8 @@ void SpatialEditor::_bind_methods() {
// 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);
+ ObjectTypeDB::bind_method("_update_ambient_light_color",&SpatialEditor::_update_ambient_light_color);
ObjectTypeDB::bind_method("_toggle_maximize_view",&SpatialEditor::_toggle_maximize_view);
ADD_SIGNAL( MethodInfo("transform_key_request") );
@@ -3209,8 +3696,86 @@ void SpatialEditor::_bind_methods() {
}
+void SpatialEditor::clear() {
+
+ settings_fov->set_val(EDITOR_DEF("3d_editor/default_fov",60.0));
+ settings_znear->set_val(EDITOR_DEF("3d_editor/default_z_near",0.1));
+ settings_zfar->set_val(EDITOR_DEF("3d_editor/default_z_far",1500.0));
+
+ for(int i=0;i<4;i++) {
+ viewports[i]->reset();
+ }
+
+ _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
+ _menu_item_pressed(MENU_VIEW_DISPLAY_NORMAL);
+
+
+ VisualServer::get_singleton()->instance_geometry_set_flag(origin_instance,VS::INSTANCE_FLAG_VISIBLE,true);
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true);
+ for(int i=0;i<3;++i) {
+ if (grid_enable[i]) {
+ VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,true);
+ grid_visible[i]=true;
+ }
+ }
+
+ for(int i=0;i<4;i++) {
+
+ viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(SpatialEditorViewport::VIEW_AUDIO_LISTENER),i==0);
+ viewports[i]->viewport->set_as_audio_listener(i==0);
+ }
+
+ view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true );
+
+ settings_default_light_rot_x=Math_PI*0.3;
+ settings_default_light_rot_y=Math_PI*0.2;
+
+ viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,Color(0.15,0.15,0.15));
+ settings_ambient_color->set_color(Color(0.15,0.15,0.15));
+ if (!light_instance.is_valid())
+ _menu_item_pressed(MENU_VIEW_USE_DEFAULT_LIGHT);
+
+ _update_default_light_angle();
+
+
+}
+
+
+void SpatialEditor::_update_ambient_light_color(const Color& p_color) {
+
+ viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,settings_ambient_color->get_color());
+
+}
+
+void SpatialEditor::_update_default_light_angle() {
+
+ Transform t;
+ t.basis.rotate(Vector3(1,0,0),settings_default_light_rot_x);
+ t.basis.rotate(Vector3(0,1,0),settings_default_light_rot_y);
+ settings_dlight->set_transform(t);
+ if (light_instance.is_valid()) {
+ VS::get_singleton()->instance_set_transform(light_instance,t);
+ }
+
+}
+
+void SpatialEditor::_default_light_angle_input(const InputEvent& p_event) {
+
+
+ if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&(0x1|0x2|0x4)) {
+
+ settings_default_light_rot_y = Math::fposmod(settings_default_light_rot_y - p_event.mouse_motion.relative_x*0.01,Math_PI*2.0);
+ settings_default_light_rot_x = Math::fposmod(settings_default_light_rot_x - p_event.mouse_motion.relative_y*0.01,Math_PI*2.0);
+ _update_default_light_angle();
+ }
+
+}
+
+
SpatialEditor::SpatialEditor(EditorNode *p_editor) {
+ gizmo.visible=true;
+ gizmo.scale=1.0;
viewport_environment = Ref<Environment>( memnew( Environment ) );
undo_redo=p_editor->get_undo_redo();
@@ -3304,22 +3869,26 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
p = view_menu->get_popup();
p->add_check_item("Use Default Light",MENU_VIEW_USE_DEFAULT_LIGHT);
+ p->add_check_item("Use Default sRGB",MENU_VIEW_USE_DEFAULT_SRGB);
p->add_separator();
- p->add_check_item("1 Viewport",MENU_VIEW_USE_1_VIEWPORT,KEY_MASK_ALT+KEY_1);
- p->add_check_item("2 Viewports",MENU_VIEW_USE_2_VIEWPORTS,KEY_MASK_ALT+KEY_2);
- p->add_check_item("3 Viewports",MENU_VIEW_USE_3_VIEWPORTS,KEY_MASK_ALT+KEY_3);
- p->add_check_item("4 Viewports",MENU_VIEW_USE_4_VIEWPORTS,KEY_MASK_ALT+KEY_4);
+ p->add_check_item("1 Viewport",MENU_VIEW_USE_1_VIEWPORT,KEY_MASK_CMD+KEY_1);
+ p->add_check_item("2 Viewports",MENU_VIEW_USE_2_VIEWPORTS,KEY_MASK_CMD+KEY_2);
+ p->add_check_item("2 Viewports (Alt)",MENU_VIEW_USE_2_VIEWPORTS_ALT,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_2);
+ p->add_check_item("3 Viewports",MENU_VIEW_USE_3_VIEWPORTS,KEY_MASK_CMD+KEY_3);
+ p->add_check_item("3 Viewports (Alt)",MENU_VIEW_USE_3_VIEWPORTS_ALT,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_3);
+ p->add_check_item("4 Viewports",MENU_VIEW_USE_4_VIEWPORTS,KEY_MASK_CMD+KEY_4);
p->add_separator();
p->add_check_item("Display Normal",MENU_VIEW_DISPLAY_NORMAL);
p->add_check_item("Display Wireframe",MENU_VIEW_DISPLAY_WIREFRAME);
p->add_check_item("Display Overdraw",MENU_VIEW_DISPLAY_OVERDRAW);
+ p->add_check_item("Display Shadeless",MENU_VIEW_DISPLAY_SHADELESS);
p->add_separator();
p->add_check_item("View Origin",MENU_VIEW_ORIGIN);
p->add_check_item("View Grid",MENU_VIEW_GRID);
p->add_separator();
- p->add_check_item("Settings",MENU_VIEW_CAMERA_SETTINGS );
+ p->add_item("Settings",MENU_VIEW_CAMERA_SETTINGS);
p->set_item_checked( p->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT), true );
@@ -3359,86 +3928,90 @@ 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");
add_child(settings_dialog);
- l = memnew(Label);
- l->set_text("Perspective FOV (deg.):");
- l->set_pos(Point2(5,5));
- settings_dialog->add_child(l);
-
- settings_fov = memnew( LineEdit );
- settings_fov->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- settings_fov->set_begin( Point2(15,22) );
- settings_fov->set_end( Point2(15,35) );
- settings_fov->set_text(EDITOR_DEF("3d_editor/default_fov",60.0));
- settings_dialog->add_child(settings_fov);
-
- l = memnew(Label);
- l->set_text("View Z-Near");
- l->set_pos(Point2(5,45));
- settings_dialog->add_child(l);
-
- settings_znear = memnew( LineEdit );
- settings_znear->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- settings_znear->set_begin( Point2(15,62) );
- settings_znear->set_end( Point2(15,75) );
- settings_znear->set_text(EDITOR_DEF("3d_editor/default_z_near",0.1));
- settings_dialog->add_child(settings_znear);
-
-
- l = memnew(Label);
- l->set_text("View Z-Far");
- l->set_pos(Point2(5,85));
- settings_dialog->add_child(l);
-
- settings_zfar = memnew( LineEdit );
- settings_zfar->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- settings_zfar->set_begin( Point2(15,102) );
- settings_zfar->set_end( Point2(15,115) );
- settings_zfar->set_text(EDITOR_DEF("3d_editor/default_z_far",500.0));
- settings_dialog->add_child(settings_zfar);
+ 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_light_base = memnew( Control );
+ settings_light_base->set_custom_minimum_size(Size2(128,128));
+ 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_use_own_world(true);
+ settings_light_base->add_child(settings_light_vp);
+
+ settings_dlight = memnew( DirectionalLight );
+ settings_light_vp->add_child(settings_dlight);
+ settings_sphere = memnew( ImmediateGeometry );
+ settings_sphere->begin(Mesh::PRIMITIVE_TRIANGLES,Ref<Texture>());
+ settings_sphere->set_color(Color(1,1,1));
+ settings_sphere->add_sphere(32,16,1);
+ settings_sphere->end();
+ settings_light_vp->add_child(settings_sphere);
+ settings_camera = memnew( Camera );
+ settings_light_vp->add_child(settings_camera);
+ settings_camera->set_translation(Vector3(0,0,2));
+ settings_camera->set_orthogonal(2.1,0.1,5);
+
+ settings_default_light_rot_x=Math_PI*0.3;
+ settings_default_light_rot_y=Math_PI*0.2;
+
+
+
+ settings_ambient_color = memnew( ColorPickerButton );
+ settings_vbc->add_margin_child("Ambient Light Color:",settings_ambient_color);
+ settings_ambient_color->connect("color_changed",this,"_update_ambient_light_color");
+
+ viewport_environment->set_enable_fx(Environment::FX_AMBIENT_LIGHT,true);
+ viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,Color(0.15,0.15,0.15));
+ settings_ambient_color->set_color(Color(0.15,0.15,0.15));
+
+
+ settings_fov = memnew( SpinBox );
+ settings_fov->set_max(179);
+ settings_fov->set_min(1);
+ settings_fov->set_step(0.01);
+ settings_fov->set_val(EDITOR_DEF("3d_editor/default_fov",60.0));
+ settings_vbc->add_margin_child("Perspective FOV (deg.):",settings_fov);
+
+ settings_znear = memnew( SpinBox );
+ settings_znear->set_max(10000);
+ settings_znear->set_min(0.1);
+ settings_znear->set_step(0.01);
+ settings_znear->set_val(EDITOR_DEF("3d_editor/default_z_near",0.1));
+ settings_vbc->add_margin_child("View Z-Near:",settings_znear);
+
+ settings_zfar = memnew( SpinBox );
+ settings_zfar->set_max(10000);
+ settings_zfar->set_min(0.1);
+ settings_zfar->set_step(0.01);
+ settings_zfar->set_val(EDITOR_DEF("3d_editor/default_z_far",1500));
+ settings_vbc->add_margin_child("View Z-Far:",settings_zfar);
//settings_dialog->get_cancel()->hide();
/* XFORM DIALOG */
@@ -3446,7 +4019,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);
@@ -3507,6 +4080,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
EDITOR_DEF("3d_editor/manipulator_gizmo_size",80);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT,"3d_editor/manipulator_gizmo_size",PROPERTY_HINT_RANGE,"16,1024,1"));
+ EDITOR_DEF("3d_editor/manipulator_gizmo_opacity",0.2);
over_gizmo_handle=-1;
}
diff --git a/tools/editor/plugins/spatial_editor_plugin.h b/tools/editor/plugins/spatial_editor_plugin.h
index 29719cb80c..ebd3f77fe7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,6 +32,8 @@
#include "tools/editor/editor_plugin.h"
#include "tools/editor/editor_node.h"
#include "scene/3d/visual_instance.h"
+#include "scene/3d/immediate_geometry.h"
+#include "scene/3d/light.h"
#include "scene/gui/panel_container.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
@@ -65,7 +67,7 @@ public:
class SpatialEditorViewport : public Control {
OBJ_TYPE( SpatialEditorViewport, Control );
-
+friend class SpatialEditor;
enum {
VIEW_TOP,
@@ -78,13 +80,19 @@ class SpatialEditorViewport : public Control {
VIEW_ALIGN_SELECTION_WITH_VIEW,
VIEW_PERSPECTIVE,
VIEW_ENVIRONMENT,
- VIEW_ORTHOGONAL
+ VIEW_ORTHOGONAL,
+ VIEW_AUDIO_LISTENER,
+ VIEW_GIZMOS,
};
+public:
enum {
- GIZMO_BASE_LAYER=25
+ GIZMO_BASE_LAYER=27,
+ GIZMO_EDIT_LAYER=26,
+ GIZMO_GRID_LAYER=25
};
-
+private:
int index;
+ String name;
void _menu_option(int p_option);
Size2 prev_size;
@@ -103,11 +111,21 @@ class SpatialEditorViewport : public Control {
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);
@@ -127,9 +145,12 @@ class SpatialEditorViewport : public Control {
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,
@@ -137,6 +158,12 @@ class SpatialEditorViewport : public Control {
};
NavigationScheme _get_navigation_schema(const String& p_property);
+ enum NavigationZoomStyle {
+ NAVIGATION_ZOOM_VERTICAL,
+ NAVIGATION_ZOOM_HORIZONTAL
+ };
+ NavigationZoomStyle _get_navigation_zoom_style(const String& p_property);
+
enum NavigationMode {
NAVIGATION_NONE,
NAVIGATION_PAN,
@@ -209,6 +236,9 @@ class SpatialEditorViewport : public Control {
void _preview_exited_scene();
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();
protected:
@@ -222,7 +252,8 @@ public:
void set_can_preview(Camera* p_preview);
void set_state(const Dictionary& p_state);
Dictionary get_state() const;
-
+ void reset();
+ Viewport *get_viewport_node() { return viewport; }
SpatialEditorViewport(SpatialEditor *p_spatial_editor,EditorNode *p_editor,int p_index);
@@ -308,6 +339,8 @@ private:
RID indicators_instance;
RID cursor_mesh;
RID cursor_instance;
+ RID indicator_mat;
+ RID cursor_material;
/*
struct Selected {
@@ -342,12 +375,16 @@ private:
MENU_TRANSFORM_DIALOG,
MENU_VIEW_USE_1_VIEWPORT,
MENU_VIEW_USE_2_VIEWPORTS,
+ MENU_VIEW_USE_2_VIEWPORTS_ALT,
MENU_VIEW_USE_3_VIEWPORTS,
+ MENU_VIEW_USE_3_VIEWPORTS_ALT,
MENU_VIEW_USE_4_VIEWPORTS,
MENU_VIEW_USE_DEFAULT_LIGHT,
+ MENU_VIEW_USE_DEFAULT_SRGB,
MENU_VIEW_DISPLAY_NORMAL,
MENU_VIEW_DISPLAY_WIREFRAME,
MENU_VIEW_DISPLAY_OVERDRAW,
+ MENU_VIEW_DISPLAY_SHADELESS,
MENU_VIEW_ORIGIN,
MENU_VIEW_GRID,
MENU_VIEW_CAMERA_SETTINGS,
@@ -377,15 +414,29 @@ private:
LineEdit *xform_scale[3];
OptionButton *xform_type;
- LineEdit *settings_fov;
- LineEdit *settings_znear;
- LineEdit *settings_zfar;
+ VBoxContainer *settings_vbc;
+ SpinBox *settings_fov;
+ SpinBox *settings_znear;
+ SpinBox *settings_zfar;
+ DirectionalLight *settings_dlight;
+ ImmediateGeometry *settings_sphere;
+ Camera *settings_camera;
+ float settings_default_light_rot_x;
+ float settings_default_light_rot_y;
+
+ Control *settings_light_base;
+ Viewport *settings_light_vp;
+ ColorPickerButton *settings_ambient_color;
+ Image settings_light_dir_image;
+
void _xform_dialog_action();
void _menu_item_pressed(int p_option);
HBoxContainer *hbc_menu;
+
+
//
//
void _generate_selection_box();
@@ -415,6 +466,10 @@ private:
SpatialEditorGizmos *gizmos;
SpatialEditor();
+ void _update_ambient_light_color(const Color& p_color);
+ void _update_default_light_angle();
+ void _default_light_angle_input(const InputEvent& p_event);
+
protected:
@@ -431,9 +486,9 @@ public:
static SpatialEditor *get_singleton() { return singleton; }
void snap_cursor_to_plane(const Plane& p_plane);
- float get_znear() const { return settings_znear->get_text().to_double(); }
- float get_zfar() const { return settings_zfar->get_text().to_double(); }
- float get_fov() const { return settings_fov->get_text().to_double(); }
+ float get_znear() const { return settings_znear->get_val(); }
+ float get_zfar() const { return settings_zfar->get_val(); }
+ float get_fov() const { return settings_fov->get_val(); }
Transform get_gizmo_transform() const { return gizmo.transform; }
bool is_gizmo_visible() const { return gizmo.visible; }
@@ -474,8 +529,14 @@ public:
void set_can_preview(Camera* p_preview);
+ SpatialEditorViewport *get_editor_viewport(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx,4,NULL);
+ return viewports[p_idx];
+ }
+
Camera *get_camera() { return NULL; }
void edit(Spatial *p_spatial);
+ void clear();
SpatialEditor(EditorNode *p_editor);
~SpatialEditor();
};
@@ -501,6 +562,7 @@ public:
virtual Dictionary get_state() const;
virtual void set_state(const Dictionary& p_state);
+ virtual void clear() { spatial_editor->clear(); }
SpatialEditorPlugin(EditorNode *p_node);
diff --git a/tools/editor/plugins/sprite_frames_editor_plugin.cpp b/tools/editor/plugins/sprite_frames_editor_plugin.cpp
index a26fab0f9a..e90087efda 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,7 +46,7 @@ void SpriteFramesEditor::_notification(int p_what) {
}
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
load->set_icon( get_icon("Folder","EditorIcons") );
_delete->set_icon( get_icon("Del","EditorIcons") );
}
@@ -76,7 +76,7 @@ void SpriteFramesEditor::_file_load_request(const DVector<String>& p_path) {
dialog->set_title("Error!");
//dialog->get_cancel()->set_text("Close");
dialog->get_ok()->set_text("Close");
- dialog->popup_centered(Size2(300,60));
+ dialog->popup_centered_minsize();
return; ///beh should show an error i guess
}
@@ -115,7 +115,7 @@ void SpriteFramesEditor::_load_pressed() {
for(int i=0;i<extensions.size();i++)
file->add_filter("*."+extensions[i]);
- file->set_mode(FileDialog::MODE_OPEN_FILES);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILES);
file->popup_centered_ratio();
@@ -188,7 +188,7 @@ void SpriteFramesEditor::_paste_pressed() {
dialog->set_title("Error!");
//dialog->get_cancel()->set_text("Close");
dialog->get_ok()->set_text("Close");
- dialog->popup_centered(Size2(300,60));
+ dialog->popup_centered_minsize();
return; ///beh should show an error i guess
}
@@ -229,6 +229,33 @@ void SpriteFramesEditor::_empty_pressed() {
}
+void SpriteFramesEditor::_empty2_pressed() {
+
+
+ int from=-1;
+
+ if (tree->get_selected()) {
+
+ from = tree->get_selected()->get_metadata(0);
+ sel=from;
+
+ } else {
+ from=frames->get_frame_count();
+ }
+
+
+
+ Ref<Texture> r;
+
+ undo_redo->create_action("Add Empty");
+ undo_redo->add_do_method(frames,"add_frame",r,from+1);
+ undo_redo->add_undo_method(frames,"remove_frame",from+1);
+ undo_redo->add_do_method(this,"_update_library");
+ undo_redo->add_undo_method(this,"_update_library");
+ undo_redo->commit_action();
+
+}
+
void SpriteFramesEditor::_up_pressed() {
if (!tree->get_selected())
@@ -322,6 +349,8 @@ void SpriteFramesEditor::_update_library() {
ti->set_text(0,"Frame "+itos(i));
ti->set_icon(0,frames->get_frame(i));
}
+ if (frames->get_frame(i).is_valid())
+ ti->set_tooltip(0,frames->get_frame(i)->get_path());
ti->set_metadata(0,i);
ti->set_icon_max_width(0,96);
if (sel==i)
@@ -355,6 +384,7 @@ void SpriteFramesEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_input_event"),&SpriteFramesEditor::_input_event);
ObjectTypeDB::bind_method(_MD("_load_pressed"),&SpriteFramesEditor::_load_pressed);
ObjectTypeDB::bind_method(_MD("_empty_pressed"),&SpriteFramesEditor::_empty_pressed);
+ ObjectTypeDB::bind_method(_MD("_empty2_pressed"),&SpriteFramesEditor::_empty2_pressed);
ObjectTypeDB::bind_method(_MD("_item_edited"),&SpriteFramesEditor::_item_edited);
ObjectTypeDB::bind_method(_MD("_delete_pressed"),&SpriteFramesEditor::_delete_pressed);
ObjectTypeDB::bind_method(_MD("_paste_pressed"),&SpriteFramesEditor::_paste_pressed);
@@ -387,9 +417,13 @@ SpriteFramesEditor::SpriteFramesEditor() {
hbc->add_child(paste);
empty = memnew( Button );
- empty->set_text("Insert Empty");
+ empty->set_text("Insert Empty (Before)");
hbc->add_child(empty);
+ empty2 = memnew( Button );
+ empty2->set_text("Insert Empty (After)");
+ hbc->add_child(empty2);
+
move_up = memnew( Button );
move_up->set_text("Up");
hbc->add_child(move_up);
@@ -401,7 +435,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
_delete = memnew( Button );
hbc->add_child(_delete);
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
add_child(file);
@@ -422,6 +456,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
_delete->connect("pressed", this,"_delete_pressed");
paste->connect("pressed", this,"_paste_pressed");
empty->connect("pressed", this,"_empty_pressed");
+ empty2->connect("pressed", this,"_empty2_pressed");
move_up->connect("pressed", this,"_up_pressed");
move_down->connect("pressed", this,"_down_pressed");
file->connect("files_selected", this,"_file_load_request");
diff --git a/tools/editor/plugins/sprite_frames_editor_plugin.h b/tools/editor/plugins/sprite_frames_editor_plugin.h
index 99c6ad486e..969d7b1ce3 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -46,6 +46,7 @@ class SpriteFramesEditor : public PanelContainer {
Button *_delete;
Button *paste;
Button *empty;
+ Button *empty2;
Button *move_up;
Button *move_down;
Tree *tree;
@@ -53,7 +54,7 @@ class SpriteFramesEditor : public PanelContainer {
int sel;
- FileDialog *file;
+ EditorFileDialog *file;
AcceptDialog *dialog;
@@ -65,6 +66,7 @@ class SpriteFramesEditor : public PanelContainer {
void _file_load_request(const DVector<String>& p_path);
void _paste_pressed();
void _empty_pressed();
+ void _empty2_pressed();
void _delete_pressed();
void _delete_confirm_pressed();
void _up_pressed();
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..35c53cf562
--- /dev/null
+++ b/tools/editor/plugins/sprite_region_editor_plugin.cpp
@@ -0,0 +1,565 @@
+/*************************************************************************/
+/* sprite_region_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2015 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;
+
+ 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:") ) );
+
+ 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");
+ hb_tools->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");
+ hb_tools->add_child(sb_off_y);
+
+ hb_tools->add_child( memnew( VSeparator ));
+ hb_tools->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");
+ hb_tools->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");
+ hb_tools->add_child(sb_step_y);
+
+// MARIANOGNU::TODO: Add more tools?
+
+ 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);
+ }
+}
+
+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..cf69395f40
--- /dev/null
+++ b/tools/editor/plugins/sprite_region_editor_plugin.h
@@ -0,0 +1,125 @@
+/*************************************************************************/
+/* sprite_region_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2015 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 );
+
+ ToolButton *edit_node;
+// Button *use_region;
+ ToolButton *b_snap_enable;
+ ToolButton *b_snap_grid;
+ TextureFrame *icon_zoom;
+ HSlider *zoom;
+ SpinBox *zoom_value;
+ 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 "Sprite"; }
+ 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);
+
+ 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 4588c694ee..81db7f2846 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@
void StreamEditor::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
play->set_icon( get_icon("Play","EditorIcons") );
stop->set_icon( get_icon("Stop","EditorIcons") );
}
diff --git a/tools/editor/plugins/stream_editor_plugin.h b/tools/editor/plugins/stream_editor_plugin.h
index d49d15b765..7378bfad0c 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/style_box_editor_plugin.cpp b/tools/editor/plugins/style_box_editor_plugin.cpp
index 3b537fb5c4..898c69e1e0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/style_box_editor_plugin.h b/tools/editor/plugins/style_box_editor_plugin.h
index 87f72b3cc8..00b0871572 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/plugins/theme_editor_plugin.cpp b/tools/editor/plugins/theme_editor_plugin.cpp
index ccbd923118..63ba57bfc0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -408,7 +408,7 @@ void ThemeEditor::_theme_menu_cbk(int p_option) {
if (p_option==POPUP_CREATE_TEMPLATE) {
- file_dialog->set_mode(FileDialog::MODE_SAVE_FILE);
+ file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
file_dialog->set_current_path("custom.theme");
file_dialog->popup_centered_ratio();
return;
@@ -568,6 +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 );
+
+
+ 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");
@@ -714,7 +732,7 @@ ThemeEditor::ThemeEditor() {
fd_button->set_text("Open File Dialog");
panel->add_child(fd_button);
- test_file_dialog = memnew( FileDialog );
+ test_file_dialog = memnew( EditorFileDialog );
panel->add_child(test_file_dialog);
fd_button->connect("pressed", this,"_open_file_dialog");
@@ -784,7 +802,7 @@ ThemeEditor::ThemeEditor() {
add_del_dialog->get_ok()->connect("pressed", this,"_dialog_cbk");
- file_dialog = memnew( FileDialog );
+ file_dialog = memnew( EditorFileDialog );
file_dialog->add_filter("*.theme ; Theme File");
add_child(file_dialog);
file_dialog->connect("file_selected",this,"_save_template_cbk");
diff --git a/tools/editor/plugins/theme_editor_plugin.h b/tools/editor/plugins/theme_editor_plugin.h
index 98156422ee..40c7ad8186 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,6 +33,8 @@
#include "scene/gui/texture_frame.h"
#include "scene/gui/option_button.h"
#include "scene/gui/file_dialog.h"
+#include "scene/gui/check_box.h"
+#include "scene/gui/button_group.h"
#include "tools/editor/editor_node.h"
@@ -46,7 +48,7 @@ class ThemeEditor : public Control {
VBoxContainer *main_vb;
Ref<Theme> theme;
- FileDialog *file_dialog;
+ EditorFileDialog *file_dialog;
double time_left;
diff --git a/tools/editor/plugins/tile_map_editor_plugin.cpp b/tools/editor/plugins/tile_map_editor_plugin.cpp
index 09f26c8ca0..66c7a39096 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,7 +34,7 @@
#include "os/file_access.h"
#include "tools/editor/editor_settings.h"
#include "os/input.h"
-
+#include "method_bind_ext.inc"
void TileMapEditor::_notification(int p_what) {
@@ -42,9 +42,13 @@ void TileMapEditor::_notification(int p_what) {
case NOTIFICATION_READY: {
- pane_drag->connect("dragged", this,"_pane_drag");
+ transpose->set_icon( get_icon("Transpose","EditorIcons"));
mirror_x->set_icon( get_icon("MirrorX","EditorIcons"));
mirror_y->set_icon( get_icon("MirrorY","EditorIcons"));
+ rotate_0->set_icon( get_icon("Rotate0","EditorIcons"));
+ rotate_90->set_icon( get_icon("Rotate90","EditorIcons"));
+ rotate_180->set_icon( get_icon("Rotate180","EditorIcons"));
+ rotate_270->set_icon( get_icon("Rotate270","EditorIcons"));
} break;
}
@@ -67,34 +71,71 @@ void TileMapEditor::_canvas_mouse_exit() {
}
int TileMapEditor::get_selected_tile() const {
-
- TreeItem *item = palette->get_selected();
- if (!item)
+ int item = palette->get_current();
+ if (item==-1)
return TileMap::INVALID_CELL;
- return item->get_metadata(0);
+ return palette->get_item_metadata(item);
}
-void TileMapEditor::_set_cell(const Point2i& p_pos,int p_value,bool p_flip_h, bool p_flip_v,bool p_with_undo) {
+void TileMapEditor::set_selected_tile(int p_tile) {
+ for (int i = 0; i < palette->get_item_count(); i++) {
+ if (palette->get_item_metadata(i).operator int() == p_tile) {
+ palette->select(i,true);
+ palette->ensure_current_is_visible();
+ break;
+ }
+ }
+}
+
+// Wrapper to workaround five arg limit of undo/redo methods
+void TileMapEditor::_set_cell_shortened(const Point2& p_pos,int p_value,bool p_flip_h, bool p_flip_v, bool p_transpose) {
+ ERR_FAIL_COND(!node);
+ node->set_cell(floor(p_pos.x), floor(p_pos.y), p_value, p_flip_h, p_flip_v, p_transpose);
+}
+
+void TileMapEditor::_set_cell(const Point2i& p_pos,int p_value,bool p_flip_h, bool p_flip_v, bool p_transpose,bool p_with_undo) {
ERR_FAIL_COND(!node);
bool prev_flip_h=node->is_cell_x_flipped(p_pos.x,p_pos.y);
bool prev_flip_v=node->is_cell_y_flipped(p_pos.x,p_pos.y);
+ bool prev_transpose=node->is_cell_transposed(p_pos.x,p_pos.y);
int prev_val=node->get_cell(p_pos.x,p_pos.y);
- if (p_value==prev_val && p_flip_h==prev_flip_h && p_flip_v==prev_flip_v)
+ if (p_value==prev_val && p_flip_h==prev_flip_h && p_flip_v==prev_flip_v && p_transpose==prev_transpose)
return; //check that it's actually different
if (p_with_undo) {
- undo_redo->add_do_method(node,"set_cell",p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v);
- undo_redo->add_undo_method(node,"set_cell",p_pos.x,p_pos.y,prev_val,prev_flip_h,prev_flip_v);
+ 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);
+ node->set_cell(p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v,p_transpose);
+
+ }
+
+}
+
+void TileMapEditor::_set_display_mode(int p_mode) {
+ if (display_mode == p_mode) {
+ return;
+ }
+ switch (p_mode) {
+ case DISPLAY_THUMBNAIL: {
+ button_thumbnail->set_pressed(true);
+ button_list->set_pressed(false);
+ } break;
+ case DISPLAY_LIST: {
+ button_thumbnail->set_pressed(false);
+ button_list->set_pressed(true);
+ } break;
}
+ display_mode = p_mode;
+
+ _update_palette();
}
void TileMapEditor::_update_palette() {
@@ -102,37 +143,52 @@ void TileMapEditor::_update_palette() {
if (!node)
return;
- palette->clear();;
+ palette->clear();
Ref<TileSet> tileset=node->get_tileset();
if (!tileset.is_valid())
return;
-
- TreeItem *root = palette->create_item();
- palette->set_hide_root(true);
List<int> tiles;
tileset->get_tile_list(&tiles);
- for(List<int>::Element *E=tiles.front();E;E=E->next()) {
+ if (display_mode == DISPLAY_THUMBNAIL) {
+ palette->set_max_columns(0);
+ palette->set_icon_mode(ItemList::ICON_MODE_TOP);
+ } else if (display_mode == DISPLAY_LIST) {
+ palette->set_max_columns(1);
+ palette->set_icon_mode(ItemList::ICON_MODE_LEFT);
+ }
- TreeItem *tile = palette->create_item(root);
+ palette->set_max_text_lines(2);
+
+ for(List<int>::Element *E=tiles.front();E;E=E->next()) {
+ palette->add_item("");
- tile->set_icon_max_width(0,64);
Ref<Texture> tex = tileset->tile_get_texture(E->get());
+
if (tex.is_valid()) {
- tile->set_icon(0,tex);
Rect2 region = tileset->tile_get_region(E->get());
- if (region!=Rect2())
- tile->set_icon_region(0,region);
- } else if (tileset->tile_get_name(E->get())!="")
- tile->set_text(0,tileset->tile_get_name(E->get()));
- else
- tile->set_text(0,"#"+itos(E->get()));
+ if (!region.has_no_area()) {
+ Image data = VS::get_singleton()->texture_get_data(tex->get_rid());
- tile->set_metadata(0,E->get());
+ Ref<ImageTexture> img = memnew( ImageTexture );
+ img->create_from_image(data.get_rect(region));
+
+ palette->set_item_icon(palette->get_item_count()-1, img);
+ } else {
+ palette->set_item_icon(palette->get_item_count()-1,tex);
+ }
+ }
+ if (tileset->tile_get_name(E->get())!="") {
+ palette->set_item_text(palette->get_item_count()-1, tileset->tile_get_name(E->get()));
+ } else {
+ palette->set_item_text(palette->get_item_count()-1, "#"+itos(E->get()));
+ }
+
+ palette->set_item_metadata(palette->get_item_count()-1, E->get());
}
}
@@ -157,6 +213,7 @@ struct _TileMapEditorCopyData {
int cell;
bool flip_h;
bool flip_v;
+ bool transpose;
};
bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
@@ -166,7 +223,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
Matrix32 xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
Matrix32 xform_inv = xform.affine_inverse();
- Vector2 snap = Vector2(1,1)*node->get_cell_size();
+ Vector2 snap = node->get_cell_size();
switch(p_event.type) {
@@ -193,6 +250,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
tcd.cell=node->get_cell(j,i);
tcd.flip_h=node->is_cell_x_flipped(j,i);
tcd.flip_v=node->is_cell_y_flipped(j,i);
+ tcd.transpose=node->is_cell_transposed(j,i);
dupdata.push_back(tcd);
@@ -203,7 +261,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
for (List<_TileMapEditorCopyData>::Element *E=dupdata.front();E;E=E->next()) {
- _set_cell(E->get().pos+ofs,E->get().cell,E->get().flip_h,E->get().flip_v,true);
+ _set_cell(E->get().pos+ofs,E->get().cell,E->get().flip_h,E->get().flip_v,E->get().transpose,true);
}
undo_redo->commit_action();
@@ -218,35 +276,36 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
if (mb.mod.shift) {
tool=TOOL_SELECTING;
- selection_begin =(xform_inv.xform(Point2(mb.x,mb.y))/snap).floor();
+ selection_begin =node->world_to_map(xform_inv.xform(Point2(mb.x,mb.y)));
selection.pos=selection_begin;
selection.size=Point2(0,0);
selection_active=true;
canvas_item_editor->update();
return true;
+ } else if (mb.mod.control) {
+ tool=TOOL_PICKING;
+ set_selected_tile(node->get_cell(over_tile.x, over_tile.y));
+ mirror_x->set_pressed(node->is_cell_x_flipped(over_tile.x, over_tile.y));
+ mirror_y->set_pressed(node->is_cell_y_flipped(over_tile.x, over_tile.y));
+ transpose->set_pressed(node->is_cell_transposed(over_tile.x, over_tile.y));
+ _update_transform_buttons();
+ canvas_item_editor->update();
+ return true;
} else {
int id = get_selected_tile();
if (id!=TileMap::INVALID_CELL) {
tool=TOOL_PAINTING;
- Point2i local =(xform_inv.xform(Point2(mb.x,mb.y))/snap).floor();
+ Point2i local =node->world_to_map((xform_inv.xform(Point2(mb.x,mb.y))));
paint_undo.clear();
- CellOp op;
- op.idx = node->get_cell(local.x,local.y);
- if (op.idx>=0) {
- if (node->is_cell_x_flipped(local.x,local.y))
- op.xf=true;
- if (node->is_cell_y_flipped(local.x,local.y))
- op.yf=true;
- }
- paint_undo[local]=op;
- node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed());
+ paint_undo[local]=_get_op_from_cell(local);
+ node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());
return true;
}
}
} else {
- if (tool==TOOL_PAINTING || tool == TOOL_SELECTING) {
+ if (tool==TOOL_PAINTING || tool == TOOL_SELECTING || tool == TOOL_PICKING) {
if (tool==TOOL_PAINTING) {
@@ -255,8 +314,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(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));
- undo_redo->add_undo_method(node,"set_cell",p.x,p.y,E->get().idx,E->get().xf,E->get().yf);
+ 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();
@@ -278,22 +337,14 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
} else if (mb.pressed && tool==TOOL_NONE) {
tool=TOOL_ERASING;
- Point2i local =(xform_inv.xform(Point2(mb.x,mb.y))/snap).floor();
+ Point2i local =node->world_to_map(xform_inv.xform(Point2(mb.x,mb.y)));
paint_undo.clear();
- CellOp op;
- op.idx = node->get_cell(local.x,local.y);
- if (op.idx>=0) {
- if (node->is_cell_x_flipped(local.x,local.y))
- op.xf=true;
- if (node->is_cell_y_flipped(local.x,local.y))
- op.yf=true;
- }
- paint_undo[local]=op;
- //node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed());
+ paint_undo[local]=_get_op_from_cell(local);
+ //node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());
//return true;
_set_cell(local,TileMap::INVALID_CELL);
return true;
- } else {
+ } else if (!mb.pressed) {
if (tool==TOOL_ERASING) {
@@ -302,9 +353,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));
- _set_cell(p,TileMap::INVALID_CELL,false,false,true);
- undo_redo->add_undo_method(node,"set_cell",p.x,p.y,E->get().idx,E->get().xf,E->get().yf);
+ //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();
@@ -322,7 +374,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
const InputEventMouseMotion &mm=p_event.mouse_motion;
- Point2i new_over_tile = (xform_inv.xform(Point2(mm.x,mm.y))/snap).floor();
+ Point2i new_over_tile = node->world_to_map(xform_inv.xform(Point2(mm.x,mm.y)));//(xform_inv.xform(Point2(mm.x,mm.y))/snap).floor();
if (new_over_tile!=over_tile) {
over_tile=new_over_tile;
@@ -338,17 +390,9 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
if (!paint_undo.has(over_tile)) {
- CellOp op;
- op.idx = node->get_cell(over_tile.x,over_tile.y);
- if (op.idx>=0) {
- if (node->is_cell_x_flipped(over_tile.x,over_tile.y))
- op.xf=true;
- if (node->is_cell_y_flipped(over_tile.x,over_tile.y))
- op.yf=true;
- }
- paint_undo[over_tile]=op;
+ paint_undo[over_tile]=_get_op_from_cell(over_tile);
}
- node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed());
+ node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());
return true;
}
@@ -375,25 +419,26 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
return true;
}
+
if (tool==TOOL_ERASING) {
- Point2i local =over_tile;
+ Point2i local =over_tile;
if (!paint_undo.has(over_tile)) {
-
- CellOp op;
- op.idx = node->get_cell(over_tile.x,over_tile.y);
- if (op.idx>=0) {
- if (node->is_cell_x_flipped(over_tile.x,over_tile.y))
- op.xf=true;
- if (node->is_cell_y_flipped(over_tile.x,over_tile.y))
- op.yf=true;
- }
- paint_undo[over_tile]=op;
+ paint_undo[over_tile]=_get_op_from_cell(over_tile);
}
- //node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed());
+ //node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());
_set_cell(local,TileMap::INVALID_CELL);
return true;
}
+ if (tool==TOOL_PICKING) {
+ set_selected_tile(node->get_cell(over_tile.x, over_tile.y));
+ mirror_x->set_pressed(node->is_cell_x_flipped(over_tile.x, over_tile.y));
+ mirror_y->set_pressed(node->is_cell_y_flipped(over_tile.x, over_tile.y));
+ transpose->set_pressed(node->is_cell_transposed(over_tile.x, over_tile.y));
+ _update_transform_buttons();
+ canvas_item_editor->update();
+ return true;
+ }
} break;
case InputEvent::KEY: {
@@ -469,44 +514,104 @@ void TileMapEditor::_canvas_draw() {
if (!node)
return;
- int cell_size=node->get_cell_size();
+ Size2 cell_size=node->get_cell_size();
+ Matrix32 cell_xf = node->get_cell_transform();
Matrix32 xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
Matrix32 xform_inv = xform.affine_inverse();
Size2 screen_size=canvas_item_editor->get_size();
- Rect2 aabb;
- aabb.pos=xform_inv.xform(Vector2());
- aabb.expand_to(xform_inv.xform(Vector2(0,screen_size.height)));
- aabb.expand_to(xform_inv.xform(Vector2(screen_size.width,0)));
- aabb.expand_to(xform_inv.xform(screen_size));
- Rect2i si=aabb;
+ {
+ Rect2 aabb;
+ aabb.pos=node->world_to_map(xform_inv.xform(Vector2()));
+ aabb.expand_to(node->world_to_map(xform_inv.xform(Vector2(0,screen_size.height))));
+ aabb.expand_to(node->world_to_map(xform_inv.xform(Vector2(screen_size.width,0))));
+ aabb.expand_to(node->world_to_map(xform_inv.xform(screen_size)));
+ Rect2i si=aabb.grow(1.0);
- for(int i=(si.pos.x/cell_size)-1;i<=(si.pos.x+si.size.x)/cell_size;i++) {
+ if (node->get_half_offset()!=TileMap::HALF_OFFSET_X) {
- int ofs = i*cell_size;
+ for(int i=(si.pos.x)-1;i<=(si.pos.x+si.size.x);i++) {
- Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
- canvas_item_editor->draw_line(xform.xform(Point2(ofs,si.pos.y)),xform.xform(Point2(ofs,si.pos.y+si.size.y)),col,1);
+ Vector2 from = xform.xform(node->map_to_world(Vector2(i,si.pos.y)));
+ Vector2 to = xform.xform(node->map_to_world(Vector2(i,si.pos.y+si.size.y+1)));
- }
+ Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
+ canvas_item_editor->draw_line(from,to,col,1);
+
+ }
+ } else {
+
+
+ for(int i=(si.pos.x)-1;i<=(si.pos.x+si.size.x);i++) {
- for(int i=(si.pos.y/cell_size)-1;i<=(si.pos.y+si.size.y)/cell_size;i++) {
+ for(int j=(si.pos.y)-1;j<=(si.pos.y+si.size.y);j++) {
+
+ Vector2 ofs;
+ if (ABS(j)&1) {
+ ofs=cell_xf[0]*0.5;
+ }
+
+ Vector2 from = xform.xform(node->map_to_world(Vector2(i,j),true)+ofs);
+ Vector2 to = xform.xform(node->map_to_world(Vector2(i,j+1),true)+ofs);
+ Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
+ canvas_item_editor->draw_line(from,to,col,1);
+ }
+
+ }
+ }
- int ofs = i*cell_size;
+ if (node->get_half_offset()!=TileMap::HALF_OFFSET_Y) {
+
+ for(int i=(si.pos.y)-1;i<=(si.pos.y+si.size.y);i++) {
+
+ Vector2 from = xform.xform(node->map_to_world(Vector2(si.pos.x,i)));
+ Vector2 to = xform.xform(node->map_to_world(Vector2(si.pos.x+si.size.x+1,i)));
+
+ Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
+ canvas_item_editor->draw_line(from,to,col,1);
+
+ }
+ } else {
+
+
+ for(int i=(si.pos.y)-1;i<=(si.pos.y+si.size.y);i++) {
+
+ for(int j=(si.pos.x)-1;j<=(si.pos.x+si.size.x);j++) {
+
+ Vector2 ofs;
+ if (ABS(j)&1) {
+ ofs=cell_xf[1]*0.5;
+ }
+
+ Vector2 from = xform.xform(node->map_to_world(Vector2(j,i),true)+ofs);
+ Vector2 to = xform.xform(node->map_to_world(Vector2(j+1,i),true)+ofs);
+ Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
+ canvas_item_editor->draw_line(from,to,col,1);
+ }
+
+ }
+
+
+
+ }
+/*
+ for(int i=(si.pos.y/cell_size.y)-1;i<=(si.pos.y+si.size.y)/cell_size.y;i++) {
+
+ int ofs = i*cell_size.y;
Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
- canvas_item_editor->draw_line(xform.xform(Point2(si.pos.x,ofs)),xform.xform(Point2(si.pos.x+si.size.x,ofs)),col,1);
+ canvas_item_editor->draw_line(xform.xform(Point2(si.pos.x,ofs)),xform.xform(Point2(si.pos.x+si.size.x,ofs)),col,1);*/
}
if (selection_active) {
Vector<Vector2> points;
- points.push_back( xform.xform( selection.pos * cell_size) );
- points.push_back( xform.xform( (selection.pos+Point2(selection.size.x+1,0)) * cell_size) );
- points.push_back( xform.xform( (selection.pos+Point2(selection.size.x+1,selection.size.y+1)) * cell_size) );
- points.push_back( xform.xform( (selection.pos+Point2(0,selection.size.y+1)) * cell_size) );
+ points.push_back( xform.xform( node->map_to_world(( selection.pos ) )));
+ points.push_back( xform.xform( node->map_to_world((selection.pos+Point2(selection.size.x+1,0)) ) ));
+ points.push_back( xform.xform( node->map_to_world((selection.pos+Point2(selection.size.x+1,selection.size.y+1)) ) ));
+ points.push_back( xform.xform( node->map_to_world((selection.pos+Point2(0,selection.size.y+1)) ) ));
Color col=Color(0.2,0.8,1,0.4);
canvas_item_editor->draw_colored_polygon(points,col);
@@ -515,15 +620,22 @@ void TileMapEditor::_canvas_draw() {
if (mouse_over){
- const Vector2 endpoints[4]={
-
- xform.xform( over_tile * cell_size) ,
- xform.xform( (over_tile+Point2(1,0)) * cell_size) ,
- xform.xform( (over_tile+Point2(1,1)) * cell_size) ,
- xform.xform( (over_tile+Point2(0,1)) * cell_size) ,
+ Vector2 endpoints[4]={
+ ( node->map_to_world(over_tile,true) ) ,
+ ( node->map_to_world((over_tile+Point2(1,0)),true ) ),
+ ( node->map_to_world((over_tile+Point2(1,1)),true ) ),
+ ( node->map_to_world((over_tile+Point2(0,1)),true ) )
};
+
+ for(int i=0;i<4;i++) {
+ if (node->get_half_offset()==TileMap::HALF_OFFSET_X && ABS(over_tile.y)&1)
+ endpoints[i]+=cell_xf[0]*0.5;
+ if (node->get_half_offset()==TileMap::HALF_OFFSET_Y && ABS(over_tile.x)&1)
+ endpoints[i]+=cell_xf[1]*0.5;
+ endpoints[i]=xform.xform(endpoints[i]);
+ }
Color col;
if (node->get_cell(over_tile.x,over_tile.y)!=TileMap::INVALID_CELL)
col=Color(0.2,0.8,1.0,0.8);
@@ -542,10 +654,10 @@ void TileMapEditor::_canvas_draw() {
Vector<Vector2> points;
- points.push_back( xform.xform( duplicate.pos * cell_size) );
- points.push_back( xform.xform( (duplicate.pos+Point2(duplicate.size.x+1,0)) * cell_size) );
- points.push_back( xform.xform( (duplicate.pos+Point2(duplicate.size.x+1,duplicate.size.y+1)) * cell_size) );
- points.push_back( xform.xform( (duplicate.pos+Point2(0,duplicate.size.y+1)) * cell_size) );
+ points.push_back( xform.xform( node->map_to_world(duplicate.pos ) ));
+ points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(duplicate.size.x+1,0)) ) ));
+ points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(duplicate.size.x+1,duplicate.size.y+1))) ));
+ points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(0,duplicate.size.y+1))) ));
Color col=Color(0.2,1.0,0.8,0.4);
canvas_item_editor->draw_colored_polygon(points,col);
@@ -562,18 +674,53 @@ 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();
Rect2 r = ts->tile_get_region(st);
- Size2 sc = (endpoints[2]-endpoints[0])/cell_size;
+ 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()) {
+ rect=Rect2(from,t->get_size());
+ } else {
+
+ rect=Rect2(from,r.get_size());
+ }
+
+
+ if (node->get_tile_origin()==TileMap::TILE_ORIGIN_TOP_LEFT) {
+ rect.pos+=ts->tile_get_texture_offset(st);
+
+ } 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);
+
+
+ if (mirror_x->is_pressed())
+ rect.pos.x-=s.x-center.x;
+ else
+ rect.pos.x-=center.x;
+
+ if (mirror_y->is_pressed())
+ rect.pos.y-=s.y-center.y;
+ else
+ rect.pos.y-=center.y;
+ }
+
+ rect.pos=xform.xform(rect.pos);
+ rect.size*=sc;
+
if (r==Rect2()) {
- canvas_item_editor->draw_texture_rect(t,Rect2(endpoints[0],t->get_size()*sc),false,Color(1,1,1,0.5));
+ canvas_item_editor->draw_texture_rect(t,rect,false,Color(1,1,1,0.5),transpose->is_pressed());
} else {
- canvas_item_editor->draw_texture_rect_region(t,Rect2(endpoints[0],r.get_size()*sc),r,Color(1,1,1,0.5));
+ canvas_item_editor->draw_texture_rect_region(t,rect,r,Color(1,1,1,0.5),transpose->is_pressed());
}
}
}
@@ -633,27 +780,79 @@ void TileMapEditor::_tileset_settings_changed() {
canvas_item_editor->update();
}
-void TileMapEditor::_pane_drag(const Point2& p_to) {
-
- int x = theme_panel->get_margin(MARGIN_RIGHT);
-
- x+=p_to.x;
- if (x<10)
- x=10;
- if (x>300)
- x=300;
- theme_panel->set_margin(MARGIN_RIGHT,x);
-}
-
void TileMapEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_menu_option"),&TileMapEditor::_menu_option);
ObjectTypeDB::bind_method(_MD("_canvas_draw"),&TileMapEditor::_canvas_draw);
- ObjectTypeDB::bind_method(_MD("_pane_drag"),&TileMapEditor::_pane_drag);
ObjectTypeDB::bind_method(_MD("_canvas_mouse_enter"),&TileMapEditor::_canvas_mouse_enter);
ObjectTypeDB::bind_method(_MD("_canvas_mouse_exit"),&TileMapEditor::_canvas_mouse_exit);
ObjectTypeDB::bind_method(_MD("_tileset_settings_changed"),&TileMapEditor::_tileset_settings_changed);
+ ObjectTypeDB::bind_method(_MD("_update_transform_buttons"),&TileMapEditor::_update_transform_buttons);
+ ObjectTypeDB::bind_method(_MD("_set_cell_shortened","pos","tile","flip_x","flip_y","transpose"),&TileMapEditor::_set_cell_shortened,DEFVAL(false),DEFVAL(false),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("_set_display_mode","mode"),&TileMapEditor::_set_display_mode);
+}
+TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i& p_pos)
+{
+ CellOp op;
+ op.idx = node->get_cell(p_pos.x,p_pos.y);
+ if (op.idx>=0) {
+ if (node->is_cell_x_flipped(p_pos.x,p_pos.y))
+ op.xf=true;
+ if (node->is_cell_y_flipped(p_pos.x,p_pos.y))
+ op.yf=true;
+ if (node->is_cell_transposed(p_pos.x,p_pos.y))
+ op.tr=true;
+ }
+ return op;
+}
+
+void TileMapEditor::_update_transform_buttons(Object *p_button) {
+ //ERR_FAIL_NULL(p_button);
+ ToolButton *b=p_button->cast_to<ToolButton>();
+ //ERR_FAIL_COND(!b);
+
+ mirror_x->set_block_signals(true);
+ mirror_y->set_block_signals(true);
+ transpose->set_block_signals(true);
+ rotate_0->set_block_signals(true);
+ rotate_90->set_block_signals(true);
+ rotate_180->set_block_signals(true);
+ rotate_270->set_block_signals(true);
+
+ if (b == rotate_0) {
+ mirror_x->set_pressed(false);
+ mirror_y->set_pressed(false);
+ transpose->set_pressed(false);
+ }
+ else if (b == rotate_90) {
+ mirror_x->set_pressed(true);
+ mirror_y->set_pressed(false);
+ transpose->set_pressed(true);
+ }
+ else if (b == rotate_180) {
+ mirror_x->set_pressed(true);
+ mirror_y->set_pressed(true);
+ transpose->set_pressed(false);
+ }
+ else if (b == rotate_270) {
+ mirror_x->set_pressed(false);
+ mirror_y->set_pressed(true);
+ transpose->set_pressed(true);
+ }
+
+ rotate_0->set_pressed(!mirror_x->is_pressed() && !mirror_y->is_pressed() && !transpose->is_pressed());
+ rotate_90->set_pressed(mirror_x->is_pressed() && !mirror_y->is_pressed() && transpose->is_pressed());
+ rotate_180->set_pressed(mirror_x->is_pressed() && mirror_y->is_pressed() && !transpose->is_pressed());
+ rotate_270->set_pressed(!mirror_x->is_pressed() && mirror_y->is_pressed() && transpose->is_pressed());
+
+ mirror_x->set_block_signals(false);
+ mirror_y->set_block_signals(false);
+ transpose->set_block_signals(false);
+ rotate_0->set_block_signals(false);
+ rotate_90->set_block_signals(false);
+ rotate_180->set_block_signals(false);
+ rotate_270->set_block_signals(false);
}
TileMapEditor::TileMapEditor(EditorNode *p_editor) {
@@ -663,37 +862,85 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
editor=p_editor;
undo_redo = editor->get_undo_redo();
- theme_panel = memnew( Panel );
- theme_panel->set_anchor(MARGIN_BOTTOM,ANCHOR_END);
- theme_panel->set_begin( Point2(0,26));
- theme_panel->set_end( Point2(100,0) );
- p_editor->get_viewport()->add_child(theme_panel);
- theme_panel->hide();
-
- palette = memnew( Tree );
- palette->set_area_as_parent_rect(4);
- palette->set_margin(MARGIN_TOP,25);;
- theme_panel->add_child(palette);
-
- pane_drag = memnew( PaneDrag ) ;
- pane_drag->set_anchor(MARGIN_LEFT,ANCHOR_END);
- pane_drag->set_begin(Point2(16,4));
- theme_panel->add_child(pane_drag);
-
- add_child( memnew( VSeparator ));
-
+ int mw = EDITOR_DEF("tile_map/palette_min_width",80);
+ Control *ec = memnew( Control);
+ ec->set_custom_minimum_size(Size2(mw,0));
+ add_child(ec);
+
+ HBoxContainer *hb = memnew( HBoxContainer );
+ add_child(hb);
+ hb->set_h_size_flags(SIZE_EXPAND_FILL);
+ hb->add_spacer(true);
+
+ button_thumbnail = memnew( ToolButton );
+ button_thumbnail->set_toggle_mode(true);
+ button_thumbnail->set_pressed(true);
+ button_thumbnail->set_icon(p_editor->get_gui_base()->get_icon("FileThumbnail","EditorIcons"));
+ hb->add_child(button_thumbnail);
+ button_thumbnail->connect("pressed", this, "_set_display_mode", varray(DISPLAY_THUMBNAIL));
+
+ button_list = memnew( ToolButton );
+ button_list->set_toggle_mode(true);
+ button_list->set_pressed(false);
+ button_list->set_icon(p_editor->get_gui_base()->get_icon("FileList","EditorIcons"));
+ hb->add_child(button_list);
+ button_list->connect("pressed", this, "_set_display_mode", varray(DISPLAY_LIST));
+
+ // Add tile palette
+ palette = memnew( ItemList );
+ palette->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(palette);
+
+ // Add menu items
+ canvas_item_editor_hb = memnew( HBoxContainer );
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(canvas_item_editor_hb);
+ canvas_item_editor_hb->add_child( memnew( VSeparator ));
+ transpose = memnew( ToolButton );
+ transpose->set_toggle_mode(true);
+ transpose->set_tooltip("Transpose");
+ transpose->set_focus_mode(FOCUS_NONE);
+ transpose->connect("pressed", this, "_update_transform_buttons", make_binds(transpose));
+ canvas_item_editor_hb->add_child(transpose);
mirror_x = memnew( ToolButton );
mirror_x->set_toggle_mode(true);
mirror_x->set_tooltip("Mirror X (A)");
mirror_x->set_focus_mode(FOCUS_NONE);
- add_child(mirror_x);
+ mirror_x->connect("pressed", this, "_update_transform_buttons", make_binds(mirror_x));
+ canvas_item_editor_hb->add_child(mirror_x);
mirror_y = memnew( ToolButton );
mirror_y->set_toggle_mode(true);
mirror_y->set_tooltip("Mirror Y (S)");
mirror_y->set_focus_mode(FOCUS_NONE);
- add_child(mirror_y);
-
-
+ mirror_y->connect("pressed", this, "_update_transform_buttons", make_binds(mirror_y));
+ canvas_item_editor_hb->add_child(mirror_y);
+ canvas_item_editor_hb->add_child(memnew(VSeparator));
+ rotate_0 = memnew( ToolButton );
+ rotate_0->set_toggle_mode(true);
+ rotate_0->set_tooltip("Rotate 0 degrees");
+ rotate_0->set_focus_mode(FOCUS_NONE);
+ rotate_0->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_0));
+ canvas_item_editor_hb->add_child(rotate_0);
+ rotate_90 = memnew( ToolButton );
+ rotate_90->set_toggle_mode(true);
+ rotate_90->set_tooltip("Rotate 90 degrees");
+ rotate_90->set_focus_mode(FOCUS_NONE);
+ rotate_90->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_90));
+ canvas_item_editor_hb->add_child(rotate_90);
+ rotate_180 = memnew( ToolButton );
+ rotate_180->set_toggle_mode(true);
+ rotate_180->set_tooltip("Rotate 180 degrees");
+ rotate_180->set_focus_mode(FOCUS_NONE);
+ rotate_180->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_180));
+ canvas_item_editor_hb->add_child(rotate_180);
+ rotate_270 = memnew( ToolButton );
+ rotate_270->set_toggle_mode(true);
+ rotate_270->set_tooltip("Rotate 270 degrees");
+ rotate_270->set_focus_mode(FOCUS_NONE);
+ rotate_270->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_270));
+ canvas_item_editor_hb->add_child(rotate_270);
+ canvas_item_editor_hb->hide();
+
+ rotate_0->set_pressed(true);
tool=TOOL_NONE;
selection_active=false;
mouse_over=false;
@@ -714,12 +961,12 @@ void TileMapEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
tile_map_editor->show();
- tile_map_editor->theme_panel->show();
+ tile_map_editor->get_canvas_item_editor_hb()->show();
} else {
tile_map_editor->hide();
- tile_map_editor->theme_panel->hide();
+ tile_map_editor->get_canvas_item_editor_hb()->hide();
tile_map_editor->edit(NULL);
}
@@ -729,7 +976,8 @@ TileMapEditorPlugin::TileMapEditorPlugin(EditorNode *p_node) {
editor=p_node;
tile_map_editor = memnew( TileMapEditor(p_node) );
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(tile_map_editor);
+ CanvasItemEditor::get_singleton()->get_palette_split()->add_child(tile_map_editor);
+ CanvasItemEditor::get_singleton()->get_palette_split()->move_child(tile_map_editor,0);
tile_map_editor->hide();
diff --git a/tools/editor/plugins/tile_map_editor_plugin.h b/tools/editor/plugins/tile_map_editor_plugin.h
index 2336507f1b..74d1573d0f 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,15 +34,14 @@
#include "scene/2d/tile_map.h"
#include "scene/gui/tool_button.h"
#include "scene/gui/button_group.h"
-#include "tools/editor/pane_drag.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class CanvasItemEditor;
-class TileMapEditor : public HBoxContainer {
+class TileMapEditor : public VBoxContainer {
- OBJ_TYPE(TileMapEditor, BoxContainer );
+ OBJ_TYPE(TileMapEditor, VBoxContainer );
UndoRedo *undo_redo;
@@ -52,18 +51,26 @@ class TileMapEditor : public HBoxContainer {
TOOL_PAINTING,
TOOL_SELECTING,
TOOL_ERASING,
- TOOL_DUPLICATING
+ TOOL_DUPLICATING,
+ TOOL_PICKING
+ };
+
+ enum DisplayMode {
+ DISPLAY_THUMBNAIL,
+ DISPLAY_LIST
};
Tool tool;
Control *canvas_item_editor;
- Tree *palette;
+ int display_mode;
+ ItemList *palette;
+ ToolButton *button_thumbnail;
+ ToolButton *button_list;
EditorNode *editor;
Panel *panel;
TileMap *node;
MenuButton *options;
- PaneDrag *pane_drag;
bool selection_active;
Point2i selection_begin;
@@ -72,42 +79,52 @@ class TileMapEditor : public HBoxContainer {
bool mouse_over;
Label *mirror_label;
+ ToolButton *transpose;
ToolButton *mirror_x;
ToolButton *mirror_y;
+ ToolButton *rotate_0;
+ ToolButton *rotate_90;
+ ToolButton *rotate_180;
+ ToolButton *rotate_270;
+
+ HBoxContainer *canvas_item_editor_hb;
struct CellOp {
int idx;
bool xf;
bool yf;
- CellOp() { idx=-1; xf=false; yf=false; }
+ bool tr;
+ CellOp() { idx=-1; xf=false; yf=false; tr=false; }
};
Map<Point2i,CellOp> paint_undo;
int get_selected_tile() const;
+ void set_selected_tile(int p_tile);
+ void _set_display_mode(int p_mode);
void _update_palette();
- void _pane_drag(const Point2& p_to);
void _canvas_draw();
void _menu_option(int p_option);
- void _set_cell(const Point2i& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_with_undo=false);
+ void _set_cell(const Point2i& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_transpose=false, bool p_with_undo=false);
+ void _set_cell_shortened(const Point2& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_transpose=false);
void _canvas_mouse_enter();
void _canvas_mouse_exit();
void _tileset_settings_changed();
-friend class TileMapEditorPlugin;
- Panel *theme_panel;
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
static void _bind_methods();
+ CellOp _get_op_from_cell(const Point2i& p_pos);
+ void _update_transform_buttons(Object *p_button=0);
public:
- Vector2 snap_point(const Vector2& p_point) const;
+ HBoxContainer *get_canvas_item_editor_hb() const { return canvas_item_editor_hb; }
bool forward_input_event(const InputEvent& p_event);
void edit(Node *p_tile_map);
TileMapEditor(EditorNode *p_editor);
@@ -120,6 +137,7 @@ class TileMapEditorPlugin : public EditorPlugin {
TileMapEditor *tile_map_editor;
EditorNode *editor;
+
public:
virtual bool forward_input_event(const InputEvent& p_event) { return tile_map_editor->forward_input_event(p_event); }
diff --git a/tools/editor/plugins/tile_set_editor_plugin.cpp b/tools/editor/plugins/tile_set_editor_plugin.cpp
index 6026cda4dc..09115472a8 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -37,82 +37,107 @@ void TileSetEditor::edit(const Ref<TileSet>& p_tileset) {
void TileSetEditor::_import_scene(Node *scene, Ref<TileSet> p_library, bool p_merge) {
if (!p_merge)
- p_library->clear();
+ p_library->clear();
for(int i=0;i<scene->get_child_count();i++) {
- Node *child = scene->get_child(i);
+ Node *child = scene->get_child(i);
- if (!child->cast_to<Sprite>()) {
- if (child->get_child_count()>0) {
- child=child->get_child(0);
- if (!child->cast_to<Sprite>()) {
- continue;
- }
- } else
- continue;
+ if (!child->cast_to<Sprite>()) {
+ if (child->get_child_count()>0) {
+ child=child->get_child(0);
+ if (!child->cast_to<Sprite>()) {
+ continue;
+ }
+ } else
+ continue;
- }
- Sprite *mi = child->cast_to<Sprite>();
- Ref<Texture> texture=mi->get_texture();
- if (texture.is_null())
+ }
+
+ Sprite *mi = child->cast_to<Sprite>();
+ Ref<Texture> texture=mi->get_texture();
+ Ref<CanvasItemMaterial> material=mi->get_material();
+
+ if (texture.is_null())
continue;
- int id = p_library->find_tile_by_name(mi->get_name());
- if (id<0) {
-
- id=p_library->get_last_unused_tile_id();
- p_library->create_tile(id);
- p_library->tile_set_name(id,mi->get_name());
- }
-
-
- p_library->tile_set_texture(id,texture);
- Vector2 phys_offset = mi->get_offset();
-
- if (mi->is_centered()) {
- Size2 s;
- if (mi->is_region()) {
- s=mi->get_region_rect().size;
- } else {
- s=texture->get_size();
- }
- phys_offset+=-s/2;
- }
- if (mi->is_region()) {
- p_library->tile_set_region(id,mi->get_region_rect());
- }
-
- Vector<Ref<Shape2D> >collisions;
-
- for(int j=0;j<mi->get_child_count();j++) {
-
- Node *child2 = mi->get_child(j);
- if (!child2->cast_to<StaticBody2D>())
- continue;
- StaticBody2D *sb = child2->cast_to<StaticBody2D>();
- if (sb->get_shape_count()==0)
- continue;
- Ref<Shape2D> collision=sb->get_shape(0);
- if (collision.is_valid()) {
- collisions.push_back(collision);
+ int id = p_library->find_tile_by_name(mi->get_name());
+ if (id<0) {
+
+ id=p_library->get_last_unused_tile_id();
+ p_library->create_tile(id);
+ p_library->tile_set_name(id,mi->get_name());
+ }
+
+
+
+ p_library->tile_set_texture(id,texture);
+ p_library->tile_set_material(id,material);
+
+ Vector2 phys_offset;
+
+ if (mi->is_centered()) {
+ Size2 s;
+ if (mi->is_region()) {
+ s=mi->get_region_rect().size;
+ } else {
+ s=texture->get_size();
+ }
+ phys_offset+=-s/2;
+ }
+ if (mi->is_region()) {
+ p_library->tile_set_region(id,mi->get_region_rect());
+ }
+
+ Vector<Ref<Shape2D> >collisions;
+ Ref<NavigationPolygon> nav_poly;
+ Ref<OccluderPolygon2D> occluder;
+
+ for(int j=0;j<mi->get_child_count();j++) {
+
+ Node *child2 = mi->get_child(j);
+
+ if (child2->cast_to<NavigationPolygonInstance>())
+ nav_poly=child2->cast_to<NavigationPolygonInstance>()->get_navigation_polygon();
+
+ if (child2->cast_to<LightOccluder2D>())
+ occluder=child2->cast_to<LightOccluder2D>()->get_occluder_polygon();
+
+ if (!child2->cast_to<StaticBody2D>())
+ continue;
+ StaticBody2D *sb = child2->cast_to<StaticBody2D>();
+ int shape_count = sb->get_shape_count();
+ if (shape_count==0)
+ continue;
+ 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);
+ }
}
- }
+ }
- if (collisions.size()) {
+ if (collisions.size()) {
- p_library->tile_set_shapes(id,collisions);
- p_library->tile_set_shape_offset(id,-phys_offset);
- } else {
- p_library->tile_set_shape_offset(id,Vector2());
+ p_library->tile_set_shapes(id,collisions);
+ p_library->tile_set_shape_offset(id,-phys_offset);
+ } else {
+ p_library->tile_set_shape_offset(id,Vector2());
+
+ }
+
+ p_library->tile_set_texture_offset(id,mi->get_offset());
+ p_library->tile_set_navigation_polygon(id,nav_poly);
+ p_library->tile_set_light_occluder(id,occluder);
+ p_library->tile_set_occluder_offset(id,-phys_offset);
+ p_library->tile_set_navigation_polygon_offset(id,-phys_offset);
- }
- p_library->tile_set_texture_offset(id,Vector2());
}
}
@@ -120,23 +145,23 @@ void TileSetEditor::_menu_confirm() {
switch(option) {
- case MENU_OPTION_REMOVE_ITEM: {
+ case MENU_OPTION_REMOVE_ITEM: {
- tileset->remove_tile(to_erase);
- } break;
- case MENU_OPTION_MERGE_FROM_SCENE:
- case MENU_OPTION_CREATE_FROM_SCENE: {
+ tileset->remove_tile(to_erase);
+ } break;
+ case MENU_OPTION_MERGE_FROM_SCENE:
+ case MENU_OPTION_CREATE_FROM_SCENE: {
- EditorNode *en = editor;
- Node * scene = en->get_edited_scene();
- if (!scene)
- break;
+ EditorNode *en = editor;
+ Node * scene = en->get_edited_scene();
+ if (!scene)
+ break;
- _import_scene(scene,tileset,option==MENU_OPTION_MERGE_FROM_SCENE);
+ _import_scene(scene,tileset,option==MENU_OPTION_MERGE_FROM_SCENE);
- } break;
+ } break;
}
}
@@ -164,11 +189,11 @@ void TileSetEditor::_menu_cbk(int p_option) {
cd->set_text("Create from scene?");
cd->popup_centered(Size2(300,60));
} break;
- case MENU_OPTION_MERGE_FROM_SCENE: {
+ case MENU_OPTION_MERGE_FROM_SCENE: {
- cd->set_text("Merge from scene?");
- cd->popup_centered(Size2(300,60));
- } break;
+ cd->set_text("Merge from scene?");
+ cd->popup_centered(Size2(300,60));
+ } break;
}
}
diff --git a/tools/editor/plugins/tile_set_editor_plugin.h b/tools/editor/plugins/tile_set_editor_plugin.h
index 2531ec55bf..df82df6993 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -56,7 +56,7 @@ class TileSetEditor : public Control {
int option;
void _menu_cbk(int p_option);
- void _menu_confirm();
+ void _menu_confirm();
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 42dd971bc3..c8b87486c0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -29,7 +29,7 @@
#include "progress_dialog.h"
#include "main/main.h"
#include "message_queue.h"
-#include "scene/gui/empty_control.h"
+
void BackgroundProgress::_add_task(const String& p_task,const String& p_label, int p_steps) {
@@ -43,12 +43,12 @@ void BackgroundProgress::_add_task(const String& p_task,const String& p_label, i
t.progress = memnew( ProgressBar );
t.progress->set_max(p_steps);
t.progress->set_val(p_steps);
- EmptyControl *ec = memnew( EmptyControl );
+ Control *ec = memnew( Control );
ec->set_h_size_flags(SIZE_EXPAND_FILL);
ec->set_v_size_flags(SIZE_EXPAND_FILL);
t.progress->set_area_as_parent_rect();
ec->add_child(t.progress);
- ec->set_minsize(Size2(80,5));
+ ec->set_custom_minimum_size(Size2(80,5));
t.hb->add_child(ec);
add_child(t.hb);
@@ -182,6 +182,7 @@ void ProgressDialog::add_task(const String& p_task,const String& p_label,int p_s
t.progress->set_val(p_steps);
vb2->add_child(t.progress);
t.state=memnew( Label );
+ t.state->set_clip_text(true);
vb2->add_child(t.state);
main->add_child(t.vb);
diff --git a/tools/editor/progress_dialog.h b/tools/editor/progress_dialog.h
index a9d4938efe..7f1cc4cb2d 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp
index d757a4c07d..b288439b74 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -31,13 +31,13 @@
#include "os/dir_access.h"
#include "os/file_access.h"
#include "globals.h"
-#include "scene/io/scene_loader.h"
+
#include "io/resource_loader.h"
#include "io/resource_saver.h"
#include "os/os.h"
#include "scene/gui/box_container.h"
#include "default_saver.h"
-#include "scene/io/scene_saver.h"
+
#include "scene/gui/tab_container.h"
#include "scene/gui/scroll_container.h"
#include "editor_data.h"
@@ -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,11 +254,18 @@ 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() );
+
+}
+
void ProjectExportDialog::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
CenterContainer *cc = memnew( CenterContainer );
@@ -288,6 +297,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,8 +329,17 @@ 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_SCENE: {
+ case NOTIFICATION_EXIT_TREE: {
} break;
case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
@@ -402,6 +421,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();
}
@@ -416,7 +437,7 @@ void ProjectExportDialog::_export_action(const String& p_file) {
if (FileAccess::exists(location.plus_file("engine.cfg"))) {
error->set_text("Please export outside the project folder!");
- error->popup_centered(Size2(300,70));;
+ error->popup_centered_minsize();
return;
}
String nl = (location+"/..").simplify_path();
@@ -434,7 +455,7 @@ void ProjectExportDialog::_export_action(const String& p_file) {
Error err = export_platform(platform,p_file,file_export_check->is_pressed(),file_export_password->get_text(),false);
if (err!=OK) {
error->set_text("Error exporting project!");
- error->popup_centered(Size2(300,70));;
+ error->popup_centered_minsize();
}
}
@@ -453,7 +474,7 @@ void ProjectExportDialog::_export_action_pck(const String& p_file) {
FileAccess *f = FileAccess::open(p_file,FileAccess::WRITE);
if (!f) {
error->set_text("Error exporting project PCK! Can't write");
- error->popup_centered(Size2(300,70));;
+ error->popup_centered_minsize();
}
ERR_FAIL_COND(!f);
@@ -462,7 +483,7 @@ void ProjectExportDialog::_export_action_pck(const String& p_file) {
if (err!=OK) {
error->set_text("Error exporting project!");
- error->popup_centered(Size2(300,70));;
+ error->popup_centered_minsize();
return;
}
}
@@ -473,16 +494,33 @@ 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);
if (err!=OK) {
error->set_text("Error exporting project!");
- error->popup_centered(Size2(300,70));;
+ error->popup_centered_minsize();
+ ERR_PRINT("Exporting failed!");
+ if (p_quit_after) {
+ OS::get_singleton()->set_exit_code(255);
+ get_tree()->quit();
+ }
return ERR_CANT_CREATE;
} else {
if (p_quit_after) {
- get_scene()->quit();
+ get_tree()->quit();
}
}
@@ -507,7 +545,7 @@ void ProjectExportDialog::custom_action(const String&) {
if (exporter.is_null()) {
error->set_text("No exporter for platform '"+platform+"' yet.");
- error->popup_centered(Size2(300,70));;
+ error->popup_centered_minsize();
return;
}
@@ -529,6 +567,8 @@ void ProjectExportDialog::_group_selected() {
_update_group(); //?
+
+ _update_group_tree();
}
String ProjectExportDialog::_get_selected_group() {
@@ -556,7 +596,7 @@ void ProjectExportDialog::_update_group_list() {
TreeItem *ti = groups->create_item(r);
ti->set_text(0,E->get());
- ti->add_button(0,get_icon("Del","EditorIcons"));
+ ti->add_button(0,get_icon("Remove","EditorIcons"));
if (E->get()==current) {
ti->select(0);
}
@@ -738,6 +778,8 @@ void ProjectExportDialog::_group_changed(Variant v) {
EditorNode::get_undo_redo()->add_undo_method(this,"_save_export_cfg");
EditorNode::get_undo_redo()->commit_action();
updating=false;
+ // update atlas preview button
+ _update_group();
}
void ProjectExportDialog::_group_item_edited() {
@@ -1036,6 +1078,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);
@@ -1097,6 +1140,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.");
@@ -1105,6 +1149,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);
@@ -1122,9 +1168,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");
@@ -1147,7 +1197,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);
@@ -1207,6 +1257,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");
@@ -1227,7 +1278,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");
@@ -1236,8 +1287,8 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
group_options->add_child(atlas_preview);
atlas_preview->show();
atlas_preview->connect("pressed",this,"_group_atlas_preview");
- EmptyControl *ec = memnew(EmptyControl );
- ec->set_minsize(Size2(150,1));
+ Control *ec = memnew(Control );
+ ec->set_custom_minimum_size(Size2(150,1));
gvb->add_child(ec);
VBoxContainer *group_vb_right = memnew( VBoxContainer );
@@ -1306,6 +1357,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);
@@ -1333,9 +1400,10 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
expopt="--,Export,Bundle";
- file_export = memnew( FileDialog );
+ file_export = memnew( EditorFileDialog );
add_child(file_export);
- file_export->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file_export->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ file_export->set_current_dir( EditorSettings::get_singleton()->get("global/default_project_export_path") );
file_export->set_title("Export Project");
file_export->connect("file_selected", this,"_export_action");
@@ -1351,8 +1419,9 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
file_export_password->set_editable(false);
file_export->get_vbox()->add_margin_child("Password:",file_export_password);
- pck_export = memnew( FileDialog );
- pck_export->set_access(FileDialog::ACCESS_FILESYSTEM);
+ pck_export = memnew( EditorFileDialog );
+ pck_export->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ pck_export->set_current_dir( EditorSettings::get_singleton()->get("global/default_project_export_path") );
pck_export->set_title("Export Project PCK");
pck_export->connect("file_selected", this,"_export_action_pck");
pck_export->add_filter("*.pck ; Data Pack");
@@ -1361,6 +1430,8 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck");
updating_script=false;
+ ei="EditorIcons";
+ ot="Object";
}
@@ -1642,7 +1713,7 @@ Error ProjectExport::export_project(const String& p_preset) {
if (saver.is_null()) {
memdelete(d);
- ERR_EXPLAIN("Preset '"+preset+"' references unexisting saver: "+type);
+ ERR_EXPLAIN("Preset '"+preset+"' references nonexistent saver: "+type);
ERR_FAIL_COND_V(saver.is_null(),ERR_INVALID_DATA);
}
diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h
index dfe7a2d900..09c8f10206 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,14 +33,14 @@
#include "scene/gui/control.h"
#include "scene/gui/tree.h"
#include "scene/gui/label.h"
-#include "scene/gui/file_dialog.h"
+#include "tools/editor/editor_file_dialog.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tab_container.h"
#include "os/dir_access.h"
#include "os/thread.h"
#include "scene/gui/option_button.h"
-#include "scene/gui/empty_control.h"
+
#include "scene/gui/slider.h"
#include "tools/editor/editor_file_system.h"
#include "property_editor.h"
@@ -78,10 +78,13 @@ private:
HBoxContainer *plat_errors;
Label *platform_error_string;
+ StringName ei;
+ StringName ot;
+
Tree * tree;
- FileDialog *pck_export;
- FileDialog *file_export;
+ EditorFileDialog *pck_export;
+ EditorFileDialog *file_export;
CheckButton *file_export_check;
LineEdit *file_export_password;
@@ -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 cd28c6da97..4db56ea2f9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -39,7 +39,7 @@
#include "scene/gui/line_edit.h"
#include "scene/gui/panel_container.h"
-#include "scene/gui/empty_control.h"
+
#include "scene/gui/texture_frame.h"
#include "scene/gui/margin_container.h"
#include "io/resource_saver.h"
@@ -65,7 +65,7 @@ class NewProjectDialog : public ConfirmationDialog {
error->set_text("");
get_ok()->set_disabled(true);
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- if (d->change_dir(project_path->get_text())!=OK) {
+ if (project_path->get_text() != "" && d->change_dir(project_path->get_text())!=OK) {
error->set_text("Invalid Path for Project, Path Must Exist!");
memdelete(d);
return false;
@@ -82,7 +82,7 @@ class NewProjectDialog : public ConfirmationDialog {
} else {
- if (!d->file_exists("engine.cfg")) {
+ if (project_path->get_text() != "" && !d->file_exists("engine.cfg")) {
error->set_text("Invalid Project Path (engine.cfg must exist).");
memdelete(d);
@@ -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);
@@ -321,6 +322,7 @@ public:
fdialog = memnew( FileDialog );
add_child(fdialog);
fdialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ fdialog->set_current_dir( EditorSettings::get_singleton()->get("global/default_project_path") );
project_name->connect("text_changed", this,"_text_changed");
project_path->connect("text_changed", this,"_path_text_changed");
fdialog->connect("dir_selected", this,"_path_selected");
@@ -478,20 +480,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();
@@ -579,8 +586,8 @@ void ProjectManager::_load_recent_projects() {
VBoxContainer *vb = memnew(VBoxContainer);
hb->add_child(vb);
- EmptyControl *ec = memnew( EmptyControl );
- ec->set_minsize(Size2(0,1));
+ Control *ec = memnew( Control );
+ ec->set_custom_minimum_size(Size2(0,1));
vb->add_child(ec);
Label *title = memnew( Label(project_name) );
title->add_font_override("font",get_font("large","Fonts"));
@@ -599,6 +606,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() {
@@ -615,11 +624,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;
@@ -627,7 +631,7 @@ void ProjectManager::_open_project_confirm() {
ERR_FAIL_COND(err);
}
- get_scene()->quit();
+ get_tree()->quit();
}
void ProjectManager::_open_project() {
@@ -638,7 +642,7 @@ void ProjectManager::_open_project() {
if (selected_list.size()>1) {
multi_open_ask->set_text("Are you sure to open more than one projects?");
- multi_open_ask->popup_centered(Size2(300,100));
+ multi_open_ask->popup_centered_minsize();
} else {
_open_project_confirm();
}
@@ -678,7 +682,7 @@ void ProjectManager::_run_project() {
if (selected_list.size()>1) {
multi_run_ask->set_text("Are you sure to run more than one projects?");
- multi_run_ask->popup_centered(Size2(300,100));
+ multi_run_ask->popup_centered_minsize();
} else {
_run_project_confirm();
}
@@ -778,14 +782,14 @@ void ProjectManager::_erase_project() {
erase_ask->set_text("Erase project from list?? (Folder contents will not be modified)");
- erase_ask->popup_centered(Size2(300,100));
+ erase_ask->popup_centered_minsize();
}
void ProjectManager::_exit_dialog() {
- get_scene()->quit();
+ get_tree()->quit();
}
void ProjectManager::_bind_methods() {
@@ -818,8 +822,22 @@ ProjectManager::ProjectManager() {
if (!EditorSettings::get_singleton())
EditorSettings::create();
+ 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();
@@ -828,6 +846,7 @@ ProjectManager::ProjectManager() {
panel->add_child(vb);
vb->set_area_as_parent_rect(20);
+ OS::get_singleton()->set_window_title(_MKSTR(VERSION_NAME)" - Project Manager");
Label *l = memnew( Label );
l->set_text(_MKSTR(VERSION_NAME)" - Project Manager");
@@ -835,7 +854,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);
@@ -900,6 +919,7 @@ ProjectManager::ProjectManager() {
scan_dir = memnew( FileDialog );
scan_dir->set_access(FileDialog::ACCESS_FILESYSTEM);
scan_dir->set_mode(FileDialog::MODE_OPEN_DIR);
+ scan_dir->set_current_dir( EditorSettings::get_singleton()->get("global/default_project_path") );
add_child(scan_dir);
scan_dir->connect("dir_selected",this,"_scan_begin");
@@ -937,7 +957,7 @@ ProjectManager::ProjectManager() {
String cp;
cp.push_back(0xA9);
cp.push_back(0);
- l->set_text(cp+" 2008-2012 Juan Linietsky, Ariel Manzur.");
+ l->set_text(cp+" 2008-2015 Juan Linietsky, Ariel Manzur.");
l->set_align(Label::ALIGN_CENTER);
vb->add_child(l);
@@ -965,12 +985,13 @@ 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();
+
+ if ( EditorSettings::get_singleton()->get("global/autoscan_project_path") ) {
+ _scan_begin( EditorSettings::get_singleton()->get("global/autoscan_project_path") );
+ }
+
//get_ok()->set_text("Open");
//get_ok()->set_text("Exit");
@@ -1025,7 +1046,7 @@ void ProjectListFilter::_filter_option_selected(int p_idx) {
void ProjectListFilter::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
clear_search_button->set_icon(get_icon("CloseHover","EditorIcons"));
} break;
}
diff --git a/tools/editor/project_manager.h b/tools/editor/project_manager.h
index c51a885d7d..1e6ea9c1c9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/project_settings.cpp b/tools/editor/project_settings.cpp
index 105f251461..a2419895eb 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -57,7 +57,10 @@ static const char* _button_names[JOY_BUTTON_MAX]={
void ProjectSettings::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ search_button->set_icon(get_icon("Zoom","EditorIcons"));
+ clear_button->set_icon(get_icon("Close","EditorIcons"));
translation_list->connect("button_pressed",this,"_translation_delete");
_update_actions();
@@ -415,7 +418,7 @@ void ProjectSettings::_update_actions() {
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("Del","EditorIcons"),2);
+ item->add_button(0,get_icon("Remove","EditorIcons"),2);
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);
@@ -483,7 +486,7 @@ void ProjectSettings::_update_actions() {
action->set_icon(0,get_icon("JoyAxis","EditorIcons"));
} break;
}
- action->add_button(0,get_icon("Del","EditorIcons"),2);
+ action->add_button(0,get_icon("Remove","EditorIcons"),2);
action->set_metadata(0,i);
}
}
@@ -504,7 +507,7 @@ void ProjectSettings::popup_project_settings() {
void ProjectSettings::_item_selected() {
- TreeItem *ti = globals_editor->get_tree()->get_selected();
+ TreeItem *ti = globals_editor->get_scene_tree()->get_selected();
if (!ti)
return;
if (!ti->get_parent())
@@ -719,6 +722,10 @@ 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);
}
@@ -766,23 +773,55 @@ 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);
+
+ undo_redo->create_action("Move Autoload");
+ undo_redo->add_do_method(Globals::get_singleton(),"set_order",swap_name,Globals::get_singleton()->get_order(name));
+ undo_redo->add_do_method(Globals::get_singleton(),"set_order",name,Globals::get_singleton()->get_order(swap_name));
+ undo_redo->add_undo_method(Globals::get_singleton(),"set_order",swap_name,Globals::get_singleton()->get_order(swap_name));
+ undo_redo->add_undo_method(Globals::get_singleton(),"set_order",name,Globals::get_singleton()->get_order(name));
+ 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();
+
+ }
}
@@ -916,8 +955,8 @@ void ProjectSettings::_translation_res_option_changed() {
ERR_FAIL_COND(!remaps.has(key));
- StringArray r = remaps[key];
- ERR_FAIL_INDEX(idx,remaps.size());
+ StringArray r = remaps[key];
+ ERR_FAIL_INDEX(idx,r.size());
r.set(idx,path+":"+langs[which]);
remaps[key]=r;
@@ -1095,6 +1134,7 @@ void ProjectSettings::_update_translations() {
t2->set_editable(1,true);
t2->set_metadata(1,path);
int idx = langs.find(locale);
+ print_line("find "+locale+" at "+itos(idx));
if (idx<0)
idx=0;
@@ -1133,12 +1173,39 @@ void ProjectSettings::_update_autoload() {
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("MoveUp","EditorIcons"),1);
+ t->add_button(1,get_icon("MoveDown","EditorIcons"),2);
t->add_button(1,get_icon("Del","EditorIcons"),0);
}
}
+void ProjectSettings::_toggle_search_bar(bool p_pressed) {
+
+ globals_editor->set_use_filter(p_pressed);
+
+ if (p_pressed) {
+
+ search_bar->show();
+ add_prop_bar->hide();
+ search_box->grab_focus();
+ search_box->select_all();
+ } else {
+
+ search_bar->hide();
+ add_prop_bar->show();
+ }
+}
+
+void ProjectSettings::_clear_search_box() {
+
+ if (search_box->get_text()=="")
+ return;
+
+ search_box->clear();
+ globals_editor->update_tree();
+}
void ProjectSettings::_bind_methods() {
@@ -1180,6 +1247,9 @@ void ProjectSettings::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_update_autoload"),&ProjectSettings::_update_autoload);
ObjectTypeDB::bind_method(_MD("_autoload_delete"),&ProjectSettings::_autoload_delete);
+ ObjectTypeDB::bind_method(_MD("_clear_search_box"),&ProjectSettings::_clear_search_box);
+ ObjectTypeDB::bind_method(_MD("_toggle_search_bar"),&ProjectSettings::_toggle_search_bar);
+
}
ProjectSettings::ProjectSettings(EditorData *p_data) {
@@ -1200,88 +1270,96 @@ 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_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));
- l->set_text("Category:");
+ search_button = memnew( ToolButton );
+ search_button->set_toggle_mode(true);
+ search_button->set_pressed(false);
+ search_button->set_text("Search");
+ hbc->add_child(search_button);
+ search_button->connect("toggled",this,"_toggle_search_bar");
+ hbc->add_child( memnew( VSeparator ) );
- l = memnew( Label );
- l->set_anchor(MARGIN_LEFT,ANCHOR_RATIO);
- props_base->add_child(l);
- l->set_begin(Point2(0.21,5));
- l->set_text("Property:");
+ add_prop_bar = memnew( HBoxContainer );
+ add_prop_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hbc->add_child(add_prop_bar);
- 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:");
+ Label *l = memnew( Label );
+ add_prop_bar->add_child(l);
+ l->set_text("Category:");
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->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ add_prop_bar->add_child(category);
category->connect("text_entered",this,"_item_adds");
+ l = memnew( Label );
+ add_prop_bar->add_child(l);
+ l->set_text("Property:");
+
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);
+ add_prop_bar->add_child(property);
property->connect("text_entered",this,"_item_adds");
+ l = memnew( Label );
+ add_prop_bar->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);
+ add_prop_bar->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) );
+ add_prop_bar->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) );
+ add_prop_bar->add_child(del);
del->set_text("Del");
del->connect("pressed",this,"_item_del");
+ search_bar = memnew( HBoxContainer );
+ search_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hbc->add_child(search_bar);
+ search_bar->hide();
+
+ search_box = memnew( LineEdit );
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_bar->add_child(search_box);
+
+ clear_button = memnew( ToolButton );
+ search_bar->add_child(clear_button);
+ clear_button->connect("pressed",this,"_clear_search_box");
+
+ globals_editor = memnew( PropertyEditor );
+ props_base->add_child(globals_editor);
+ globals_editor->hide_top_label();
+ globals_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ globals_editor->register_text_enter(search_box);
+ 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");
+
+/*
Button *save = memnew( Button );
- //props_base->add_child(save);
+ props_base->add_child(save);
+
save->set_anchor(MARGIN_LEFT,ANCHOR_END);
save->set_anchor(MARGIN_RIGHT,ANCHOR_END);
save->set_anchor(MARGIN_TOP,ANCHOR_END);
@@ -1290,18 +1368,17 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
save->set_end( Point2(10,20) );
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);
@@ -1409,6 +1486,7 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
device_input->add_child(device_index);
+ /*
save = memnew( Button );
input_base->add_child(save);
save->set_anchor(MARGIN_LEFT,ANCHOR_END);
@@ -1419,7 +1497,7 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
save->set_end( Point2(10,20) );
save->set_text("Save");
save->connect("pressed",this,"_save");
-
+*/
setting=false;
//translations
@@ -1446,9 +1524,9 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
translation_list->set_v_size_flags(SIZE_EXPAND_FILL);
tmc->add_child(translation_list);
- translation_file_open=memnew( FileDialog );
+ translation_file_open=memnew( EditorFileDialog );
add_child(translation_file_open);
- translation_file_open->set_mode(FileDialog::MODE_OPEN_FILE);
+ translation_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
translation_file_open->connect("file_selected",this,"_translation_add");
}
@@ -1473,9 +1551,9 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
tmc->add_child(translation_remap);
translation_remap->connect("button_pressed",this,"_translation_res_delete");
- translation_res_file_open=memnew( FileDialog );
+ translation_res_file_open=memnew( EditorFileDialog );
add_child(translation_res_file_open);
- translation_res_file_open->set_mode(FileDialog::MODE_OPEN_FILE);
+ translation_res_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
translation_res_file_open->connect("file_selected",this,"_translation_res_add");
thb = memnew( HBoxContainer);
@@ -1503,9 +1581,9 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
translation_remap_options->connect("item_edited",this,"_translation_res_option_changed");
translation_remap_options->connect("button_pressed",this,"_translation_res_option_delete");
- translation_res_option_file_open=memnew( FileDialog );
+ translation_res_option_file_open=memnew( EditorFileDialog );
add_child(translation_res_option_file_open);
- translation_res_option_file_open->set_mode(FileDialog::MODE_OPEN_FILE);
+ translation_res_option_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
translation_res_option_file_open->connect("file_selected",this,"_translation_res_option_add");
}
@@ -1518,11 +1596,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);
@@ -1533,20 +1606,31 @@ 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);
- autoload_file_open=memnew( FileDialog );
+ autoload_file_open=memnew( EditorFileDialog );
add_child(autoload_file_open);
- autoload_file_open->set_mode(FileDialog::MODE_OPEN_FILE);
+ autoload_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
autoload_file_open->connect("file_selected",this,"_autoload_file_callback");
autoload_list->set_columns(2);
diff --git a/tools/editor/project_settings.h b/tools/editor/project_settings.h
index 51f49a46ff..b122609e52 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -47,6 +47,12 @@ class ProjectSettings : public AcceptDialog {
UndoRedo *undo_redo;
PropertyEditor *globals_editor;
+ HBoxContainer *search_bar;
+ ToolButton *search_button;
+ LineEdit *search_box;
+ ToolButton *clear_button;
+
+ HBoxContainer *add_prop_bar;
ConfirmationDialog *message;
LineEdit *category;
LineEdit *property;
@@ -67,19 +73,19 @@ class ProjectSettings : public AcceptDialog {
InputEvent last_wait_for_key;
- FileDialog *translation_file_open;
+ EditorFileDialog *translation_file_open;
Tree *translation_list;
Button *translation_res_option_add_button;
- FileDialog *translation_res_file_open;
- FileDialog *translation_res_option_file_open;
+ EditorFileDialog *translation_res_file_open;
+ EditorFileDialog *translation_res_option_file_open;
Tree *translation_remap;
Tree *translation_remap_options;
Tree *autoload_list;
- FileDialog *autoload_file_open;
+ EditorFileDialog *autoload_file_open;
LineEdit *autoload_add_name;
LineEdit *autoload_add_path;
@@ -130,6 +136,9 @@ class ProjectSettings : public AcceptDialog {
void _translation_res_option_changed();
void _translation_res_option_delete(Object *p_item,int p_column, int p_button);
+ void _toggle_search_bar(bool p_pressed);
+ void _clear_search_box();
+
ProjectSettings();
diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp
index 4ac2ff0594..0a06d78255 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,17 +38,23 @@
#include "scene/scene_string_names.h"
#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 );
}*/
}
@@ -82,7 +88,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
switch(p_which) {
case OBJ_MENU_LOAD: {
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
String type=(hint==PROPERTY_HINT_RESOURCE_TYPE)?hint_text:String();
@@ -141,7 +147,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
}
String orig_type = res_orig->get_type();
- print_line("orig type: "+orig_type);
+
Object *inst = ObjectTypeDB::instance( orig_type );
Ref<Resource> res = Ref<Resource>( inst->cast_to<Resource>() );
@@ -186,6 +192,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
ERR_FAIL_COND( inheritors_array.empty() );
+
String intype=inheritors_array[p_which-TYPE_BASE_ID];
Object *obj = ObjectTypeDB::instance(intype);
@@ -208,11 +215,11 @@ void CustomPropertyEditor::_menu_option(int p_which) {
}
Variant CustomPropertyEditor::get_variant() const {
-
- return v;
+
+ return v;
}
String CustomPropertyEditor::get_name() const {
-
+
return name;
}
@@ -230,9 +237,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)
@@ -240,8 +249,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++)
@@ -251,11 +260,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++) {
@@ -403,7 +450,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");
@@ -415,7 +462,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");
@@ -427,10 +474,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");
@@ -445,7 +492,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");
@@ -454,7 +501,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 ) );
@@ -462,7 +509,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: {
@@ -483,7 +530,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");
@@ -495,17 +542,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");
@@ -520,20 +567,20 @@ 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);
@@ -547,13 +594,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));
@@ -561,30 +608,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");
@@ -592,7 +639,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
} break;
case Variant::OBJECT: {
-
+
if (hint!=PROPERTY_HINT_RESOURCE_TYPE)
break;
@@ -602,6 +649,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
if (hint_text!="") {
+ int idx=0;
for(int i=0;i<hint_text.get_slice_count(",");i++) {
@@ -611,27 +659,27 @@ 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();
}
- int idx=0;
for(Set<String>::Element *E=valid_inheritors.front();E;E=E->next()) {
String t = E->get();
if (!ObjectTypeDB::can_instance(t))
continue;
inheritors_array.push_back(t);
+ int id = TYPE_BASE_ID+idx;
if (has_icon(t,"EditorIcons")) {
- menu->add_icon_item(get_icon(t,"EditorIcons"),"New "+t,TYPE_BASE_ID+idx);
+ menu->add_icon_item(get_icon(t,"EditorIcons"),"New "+t,id);
} else {
- menu->add_item("New "+t,TYPE_BASE_ID+idx);
+ menu->add_item("New "+t,id);
}
idx++;
@@ -648,6 +696,8 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
if (!RES(v).is_null()) {
+
+
menu->add_icon_item(get_icon("EditResource","EditorIcons"),"Edit",OBJ_MENU_EDIT);
menu->add_icon_item(get_icon("Del","EditorIcons"),"Clear",OBJ_MENU_CLEAR);
menu->add_icon_item(get_icon("Duplicate","EditorIcons"),"Make Unique",OBJ_MENU_MAKE_UNIQUE);
@@ -656,6 +706,13 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
menu->add_separator();
menu->add_icon_item(get_icon("Reload","EditorIcons"),"Re-Import",OBJ_MENU_REIMPORT);
}
+ /*if (r.is_valid() && r->get_path().is_resource_file()) {
+ menu->set_item_tooltip(1,r->get_path());
+ } else if (r.is_valid()) {
+ menu->set_item_tooltip(1,r->get_name()+" ("+r->get_type()+")");
+ }*/
+ } else {
+
}
@@ -688,40 +745,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;
}
@@ -729,7 +786,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) {
@@ -754,7 +811,7 @@ void CustomPropertyEditor::_file_selected(String p_file) {
RES res = ResourceLoader::load(p_file,type);
if (res.is_null()) {
error->set_text("Error loading file: Not a resource!");
- error->popup_centered(Size2(300,80));
+ error->popup_centered_minsize();
break;
}
v=res.get_ref_ptr();
@@ -867,9 +924,9 @@ void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
void CustomPropertyEditor::_action_pressed(int p_which) {
- if (updating)
+ if (updating)
return;
-
+
switch(type) {
case Variant::INT: {
@@ -896,11 +953,11 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
if (p_which==0) {
if (hint==PROPERTY_HINT_FILE)
- file->set_access(FileDialog::ACCESS_RESOURCES);
+ file->set_access(EditorFileDialog::ACCESS_RESOURCES);
else
- file->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
file->clear_filters();
file->clear_filters();
@@ -934,10 +991,10 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
if (p_which==0) {
if (hint==PROPERTY_HINT_DIR)
- file->set_access(FileDialog::ACCESS_RESOURCES);
+ file->set_access(EditorFileDialog::ACCESS_RESOURCES);
else
- file->set_access(FileDialog::ACCESS_FILESYSTEM);
- file->set_mode(FileDialog::MODE_OPEN_DIR);
+ file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ file->set_mode(EditorFileDialog::MODE_OPEN_DIR);
file->clear_filters();
file->popup_centered_ratio();
} else {
@@ -952,7 +1009,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
} break;
case Variant::NODE_PATH: {
-
+
if (p_which==0) {
@@ -963,58 +1020,60 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
v=NodePath();
emit_signal("variant_changed");
- }
+ }
} 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(FileDialog::ACCESS_RESOURCES);
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+
+ 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();
@@ -1057,7 +1116,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
emit_signal("variant_changed");
hide();
}
-
+
} break;
case Variant::IMAGE: {
@@ -1067,8 +1126,8 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
} else if (p_which==1) {
- file->set_access(FileDialog::ACCESS_RESOURCES);
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_access(EditorFileDialog::ACCESS_RESOURCES);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
ImageLoader::get_recognized_extensions(&extensions);
@@ -1096,16 +1155,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;
@@ -1130,7 +1189,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";
@@ -1213,7 +1272,7 @@ void CustomPropertyEditor::_text_edit_changed() {
}
void CustomPropertyEditor::_modified(String p_string) {
-
+
if (updating)
return;
updating=true;
@@ -1254,17 +1313,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();
@@ -1272,10 +1331,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();
@@ -1283,10 +1342,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();
@@ -1295,14 +1354,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();
@@ -1313,39 +1372,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;
@@ -1359,51 +1418,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:
@@ -1460,10 +1525,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);
@@ -1471,29 +1536,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) ) );
@@ -1503,16 +1568,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);
@@ -1529,13 +1595,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 );
@@ -1546,17 +1612,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++) {
@@ -1580,15 +1646,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();
@@ -1598,10 +1664,10 @@ CustomPropertyEditor::CustomPropertyEditor() {
color_picker->connect("color_changed",this,"_color_changed");
set_as_toplevel(true);
- file = memnew ( FileDialog );
+ file = memnew ( EditorFileDialog );
add_child(file);
file->hide();
-
+
file->connect("file_selected", this,"_file_selected");
file->connect("dir_selected", this,"_file_selected");
@@ -1609,16 +1675,17 @@ 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);
scene_tree->connect("selected", this,"_node_path_selected");
+ scene_tree->get_scene_tree()->set_show_enabled_subscene(true);
texture_preview = memnew( TextureFrame );
add_child( texture_preview);
@@ -1635,52 +1702,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
- return node;
+ //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 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;
}
@@ -1703,9 +1900,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;
-
+
}
}
@@ -1717,7 +1914,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: {
@@ -1810,7 +2007,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)]");
@@ -1851,51 +2048,99 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
} else {
p_item->set_text(1,"<"+res->get_type()+">");
};
+
+
+ if (res.is_valid() && res->get_path().is_resource_file()) {
+ p_item->set_tooltip(1,res->get_path());
+ } else if (res.is_valid()) {
+ p_item->set_tooltip(1,res->get_name()+" ("+res->get_type()+")");
+ }
+
+
+ if (has_icon(res->get_type(),"EditorIcons")) {
+
+ p_item->set_icon(0,get_icon(res->get_type(),"EditorIcons"));
+ } else {
+
+ Dictionary d = p_item->get_metadata(0);
+ int hint=d.has("hint")?d["hint"].operator int():-1;
+ String hint_text=d.has("hint_text")?d["hint_text"]:"";
+ if (hint==PROPERTY_HINT_RESOURCE_TYPE) {
+
+ if (has_icon(hint_text,"EditorIcons")) {
+
+ p_item->set_icon(0,get_icon(hint_text,"EditorIcons"));
+
+ } else {
+ p_item->set_icon(0,get_icon("Object","EditorIcons"));
+
+ }
+ }
+ }
+
+
+
}
+
} break;
default: {};
}
-
+
}
+
+
void PropertyEditor::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
- get_scene()->connect("node_removed",this,"_node_removed");
+ get_tree()->connect("node_removed",this,"_node_removed");
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+ get_tree()->disconnect("node_removed",this,"_node_removed");
edit(NULL);
}
-
+
if (p_what==NOTIFICATION_FIXED_PROCESS) {
-
-
+
+
+ if (refresh_countdown>0) {
+ refresh_countdown-=get_fixed_process_delta_time();
+ if (refresh_countdown<=0) {
+ TreeItem *root = tree->get_root();
+ _refresh_item(root);
+ }
+ }
+
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)) {
+ 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(*k,vorig) || usage) {
Variant v = obj->get(*k);
- Variant vorig = d[*k];
int found=-1;
for(int i=0;i<item->get_button_count(1);i++) {
@@ -1906,7 +2151,7 @@ void PropertyEditor::_notification(int p_what) {
}
}
- bool changed = ! (v==vorig);
+ bool changed = _is_property_different(v,vorig,usage);
if ((found!=-1)!=changed) {
@@ -1923,15 +2168,15 @@ void PropertyEditor::_notification(int p_what) {
}
}
- 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;
-
+
}
}
@@ -1962,9 +2207,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) {
@@ -1980,7 +2225,73 @@ TreeItem *PropertyEditor::get_parent_node(String p_path,HashMap<String,TreeItem*
}
+void PropertyEditor::_refresh_item(TreeItem *p_item) {
+
+ if (!p_item)
+ return;
+
+ String name = p_item->get_metadata(1);
+
+ if (name!=String()) {
+
+ 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);
+
+ 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;
+ }
+ }
+
+ bool changed = _is_property_different(v,vorig,usage);
+
+ if ((found!=-1)!=changed) {
+
+ if (changed) {
+
+ p_item->add_button(1,get_icon("Reload","EditorIcons"),3);
+ } else {
+
+ p_item->erase_button(1,found);
+ }
+
+ }
+
+ }
+
+ }
+
+ Dictionary d=p_item->get_metadata(0);
+ set_item_text(p_item,d["type"],d["name"],d["hint"],d["hint_text"]);
+ }
+
+ TreeItem *c=p_item->get_children();
+
+ while (c) {
+
+ _refresh_item(c);
+
+ c=c->get_next();
+ }
+
+}
+
+void PropertyEditor::refresh() {
+
+ if (refresh_countdown>0)
+ return;
+ refresh_countdown=EditorSettings::get_singleton()->get("property_editor/auto_refresh_interval");
+}
void PropertyEditor::update_tree() {
@@ -2037,10 +2348,23 @@ void PropertyEditor::update_tree() {
List<PropertyInfo> plist;
obj->get_property_list(&plist,true);
+ bool draw_red=false;
+
+ {
+ Node *nod = obj->cast_to<Node>();
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (nod && es!=nod && nod->get_owner()!=es) {
+ draw_red=true;
+ }
+ }
+
+
Color sscolor=get_color("prop_subsection","Editor");
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();
@@ -2080,6 +2404,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));
@@ -2087,7 +2428,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)
@@ -2109,8 +2467,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);
@@ -2126,27 +2482,65 @@ void PropertyEditor::update_tree() {
item->set_checked(0,p.usage&PROPERTY_USAGE_CHECKED);
}
- if (capitalize_paths)
- item->set_text( 0, name.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 ) {
@@ -2155,7 +2549,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;
@@ -2167,7 +2562,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;
@@ -2210,8 +2606,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;
@@ -2227,15 +2625,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;
@@ -2243,7 +2642,7 @@ void PropertyEditor::update_tree() {
} else {
if (p.type == Variant::REAL) {
- item->set_range_config(1, -65536, 65535, 0.01);
+ item->set_range_config(1, -65536, 65535, 0.001);
} else {
item->set_range_config(1, -65536, 65535, 1);
@@ -2251,11 +2650,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 ) );
}
@@ -2275,7 +2676,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"));
@@ -2295,7 +2697,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;
@@ -2303,7 +2706,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") );
@@ -2312,37 +2716,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: {
@@ -2350,7 +2843,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: {
@@ -2358,7 +2852,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: {
@@ -2366,15 +2861,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: {
@@ -2382,7 +2886,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: {
@@ -2390,7 +2895,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: {
@@ -2398,7 +2904,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: {
@@ -2407,11 +2914,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 );
@@ -2419,8 +2927,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: {
@@ -2435,7 +2944,10 @@ void PropertyEditor::update_tree() {
item->set_editable( 1, !read_only );
item->add_button(1,get_icon("EditResource","EditorIcons"));
String type;
+ if (p.hint==PROPERTY_HINT_RESOURCE_TYPE)
+ type=p.hint_string;
bool notnil=false;
+
if (obj->get( p.name ).get_type() == Variant::NIL || obj->get( p.name ).operator RefPtr().is_null()) {
item->set_text(1,"<null>");
@@ -2459,12 +2971,25 @@ void PropertyEditor::update_tree() {
};
notnil=true;
+ if (has_icon(res->get_type(),"EditorIcons")) {
+ type=res->get_type();
+ }
+
+ if (res.is_valid() && res->get_path().is_resource_file()) {
+ item->set_tooltip(1,res->get_path());
+ } else if (res.is_valid()) {
+ item->set_tooltip(1,res->get_name()+" ("+res->get_type()+")");
+ }
+
}
- if (p.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+
+ if (type!=String()) {
+ if (type.find(",")!=-1)
+ type=type.get_slice(",",0);
//printf("prop %s , type %s\n",p.name.ascii().get_data(),p.hint_string.ascii().get_data());
- if (has_icon(p.hint_string,"EditorIcons"))
- item->set_icon( 0, get_icon(p.hint_string,"EditorIcons") );
+ if (has_icon(type,"EditorIcons"))
+ item->set_icon( 0, get_icon(type,"EditorIcons") );
else
item->set_icon( 0, get_icon("Object","EditorIcons") );
}
@@ -2477,17 +3002,25 @@ void PropertyEditor::update_tree() {
if (keying) {
- item->add_button(1,get_icon("Key","EditorIcons"),2);
+ if (p.hint==PROPERTY_HINT_SPRITE_FRAME) {
+
+ item->add_button(1,get_icon("KeyNext","EditorIcons"),5);
+ } else {
+ item->add_button(1,get_icon("Key","EditorIcons"),2);
+ }
}
- if (get_instanced_node()) {
+ 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);
}
}
@@ -2518,7 +3051,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);
@@ -2550,10 +3083,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) {
@@ -2582,12 +3115,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:
@@ -2606,7 +3139,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);
@@ -2624,64 +3157,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;
-
-
+
+
};
}
@@ -2732,24 +3265,34 @@ 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) {
+
+ TreeItem *ti = p_item->cast_to<TreeItem>();
+ ERR_FAIL_COND(!ti);
+
+ ti->call_deferred("set_range",1, p_frame);
+ obj->call_deferred("set",prop,p_frame);
+
}
void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
@@ -2763,20 +3306,29 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
if (!d.has("name"))
return;
String prop=d["name"];
- emit_signal("property_keyed",prop,obj->get(prop));
+ emit_signal("property_keyed",prop,obj->get(prop),false);
+ } else if (p_button==5) {
+ print_line("PB5");
+ if (!d.has("name"))
+ return;
+ String prop=d["name"];
+ emit_signal("property_keyed",prop,obj->get(prop),true);
+ //set_range(p_column, ti->get_range(p_column)+1.0 );
+ call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0);
} else if (p_button==3) {
- if (!get_instanced_node())
+ if (!_might_be_in_instance())
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 (_get_instanced_node_original_property(prop,vorig)) {
- _edit_set(prop,d2[prop]);
+ _edit_set(prop,vorig);
}
} else {
@@ -2820,15 +3372,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);
}
}
@@ -2883,17 +3448,24 @@ 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);
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") ) );
@@ -2901,7 +3473,7 @@ void PropertyEditor::_bind_methods() {
ADD_SIGNAL( MethodInfo("property_edited",PropertyInfo( Variant::STRING, "property")));
}
-Tree *PropertyEditor::get_tree() {
+Tree *PropertyEditor::get_scene_tree() {
return tree;
}
@@ -2948,30 +3520,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);
@@ -2979,21 +3579,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");
@@ -3003,7 +3604,12 @@ PropertyEditor::PropertyEditor() {
keying=false;
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);
+
}
diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h
index f13deab1ae..e933d7ab3b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@
#include "scene/gui/tree.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
-#include "scene/gui/file_dialog.h"
+#include "tools/editor/editor_file_dialog.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/color_picker.h"
#include "scene/gui/menu_button.h"
@@ -46,9 +46,9 @@
*/
class CustomPropertyEditor : public Popup {
-
+
OBJ_TYPE( CustomPropertyEditor, Popup );
-
+
enum {
MAX_VALUE_EDITORS=12,
MAX_ACTION_BUTTONS=5,
@@ -75,7 +75,7 @@ class CustomPropertyEditor : public Popup {
PopupMenu *menu;
SceneTreeDialog *scene_tree;
- FileDialog *file;
+ EditorFileDialog *file;
ConfirmationDialog *error;
String name;
Variant::Type type;
@@ -93,6 +93,8 @@ class CustomPropertyEditor : public Popup {
TextEdit *text_edit;
bool read_only;
Button *checks20[20];
+ SpinBox *spinbox;
+ HSlider *slider;
Control *easing_draw;
@@ -105,6 +107,7 @@ 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);
@@ -113,36 +116,38 @@ class CustomPropertyEditor : public Popup {
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,39 +161,55 @@ 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 _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:
@@ -197,12 +218,14 @@ public:
String get_selected_path() const;
- Tree *get_tree();
+ Tree *get_scene_tree();
Label* get_top_label();
void hide_top_label();
void update_tree();
void update_property(const String& p_prop);
+ void refresh();
+
void edit(Object* p_object);
void set_keying(bool p_active);
@@ -212,7 +235,13 @@ 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();
diff --git a/tools/editor/pvrtc_compress.cpp b/tools/editor/pvrtc_compress.cpp
index 9511d6a26d..a2f98adbe0 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,11 +32,34 @@
#include "io/resource_saver.h"
#include "io/resource_loader.h"
#include "os/os.h"
-
+#include "os/file_access.h"
+static void (*_base_image_compress_pvrtc2_func)(Image *)=NULL;
+static void (*_base_image_compress_pvrtc4_func)(Image *)=NULL;
static void _compress_image(Image::CompressMode p_mode,Image *p_image) {
String ttpath = EditorSettings::get_singleton()->get("PVRTC/texture_tool");
+
+ if (ttpath.strip_edges()=="" || !FileAccess::exists(ttpath)) {
+ switch(p_mode) {
+
+ case Image::COMPRESS_PVRTC2:
+ if (_base_image_compress_pvrtc2_func)
+ _base_image_compress_pvrtc2_func(p_image);
+ else if (_base_image_compress_pvrtc4_func)
+ _base_image_compress_pvrtc4_func(p_image);
+
+ break;
+ case Image::COMPRESS_PVRTC4:
+ if (_base_image_compress_pvrtc4_func)
+ _base_image_compress_pvrtc4_func(p_image);
+
+ break;
+ default: ERR_FAIL();
+
+ }
+ return;
+ }
String spath = EditorSettings::get_singleton()->get_settings_path();
@@ -100,6 +123,9 @@ static void _compress_etc(Image *p_image) {
void _pvrtc_register_compressors() {
+ _base_image_compress_pvrtc2_func=Image::_image_compress_pvrtc2_func;
+ _base_image_compress_pvrtc4_func=Image::_image_compress_pvrtc4_func;
+
Image::_image_compress_pvrtc2_func=_compress_pvrtc2;
Image::_image_compress_pvrtc4_func=_compress_pvrtc4;
//Image::_image_compress_etc_func=_compress_etc; //use the built in one for ETC
diff --git a/tools/editor/pvrtc_compress.h b/tools/editor/pvrtc_compress.h
index e683ed7804..c4fb0bacb5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/quick_open.cpp b/tools/editor/quick_open.cpp
index bae7528150..6135a4ab64 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,8 +30,9 @@
#include "os/keyboard.h"
-void EditorQuickOpen::popup(const String& p_base, bool p_dontclear) {
+void EditorQuickOpen::popup(const StringName &p_base, bool p_dontclear, bool p_add_dirs) {
+ add_directories=p_add_dirs;
popup_centered_ratio(0.6);
if (p_dontclear)
search_box->select_all();
@@ -66,27 +67,53 @@ void EditorQuickOpen::_sbox_input(const InputEvent& p_ie) {
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() {
@@ -111,14 +138,14 @@ void EditorQuickOpen::_confirmed() {
void EditorQuickOpen::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
connect("confirmed",this,"_confirmed");
}
}
-String EditorQuickOpen::get_base_type() const {
+StringName EditorQuickOpen::get_base_type() const {
return base_type;
}
@@ -152,4 +179,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 9d8a7a1abd..8b38256d39 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,9 @@ protected:
static void _bind_methods();
public:
- String get_base_type() const;
+ StringName get_base_type() const;
- void popup(const String& p_base,bool p_dontclear=false);
+ void popup(const StringName& p_base,bool p_dontclear=false,bool p_add_dirs=false);
EditorQuickOpen();
};
diff --git a/tools/editor/register_exporters.h b/tools/editor/register_exporters.h
index 559f0a9200..0e1ad2ca46 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/reparent_dialog.cpp b/tools/editor/reparent_dialog.cpp
index 2c85eb3a2a..78ba47d54b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -36,11 +36,16 @@
void ReparentDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
connect("confirmed", this,"_reparent");
}
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+ disconnect("confirmed", this,"_reparent");
+ }
+
if (p_what==NOTIFICATION_DRAW) {
//RID ci = get_canvas_item();
@@ -98,6 +103,7 @@ ReparentDialog::ReparentDialog() {
add_child(node_only);
node_only->hide();
+ tree->set_show_enabled_subscene(true);
//vbc->add_margin_child("Options:",node_only);;
diff --git a/tools/editor/reparent_dialog.h b/tools/editor/reparent_dialog.h
index 52a2192d7c..78c0df9285 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/resources_dock.cpp b/tools/editor/resources_dock.cpp
index a05fe425b3..b69eec4a51 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -69,36 +69,8 @@ void ResourcesDock::_tool_selected(int p_tool) {
TreeItem *ti = resources->get_selected();
if (!ti)
break;
- Ref<Resource> current_res = ti->get_metadata(0);
-
- RES res(current_res);
-
- List<String> extensions;
- ResourceSaver::get_recognized_extensions(res,&extensions);
- file->set_mode(FileDialog::MODE_SAVE_FILE);
- //not for now?
-
- if (current_res->get_path()!="" && current_res->get_path().find("::")==-1) {
-
- file->set_current_path(current_res->get_path());
- } else {
- String existing;
- if (extensions.size()) {
- existing="new_"+res->get_type().to_lower()+"."+extensions.front()->get().to_lower();
- }
-
- file->set_current_file(existing);
- }
-
- 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);
- file->popup_centered_ratio();
+ save_resource_as(ti->get_metadata(0));
} break;
@@ -134,7 +106,7 @@ void ResourcesDock::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
button_new->set_icon(get_icon("New","EditorIcons"));
button_open->set_icon(get_icon("Folder","EditorIcons"));
@@ -162,7 +134,7 @@ void ResourcesDock::save_resource(const String& p_path,const Ref<Resource>& p_re
if (err!=OK) {
accept->set_text("Error saving resource!");
- accept->popup_centered(Size2(300,100));
+ accept->popup_centered_minsize();
return;
}
// EditorFileSystem::get_singleton()->update_file(path,p_resource->get_type());
@@ -174,33 +146,34 @@ void ResourcesDock::save_resource(const String& p_path,const Ref<Resource>& p_re
void ResourcesDock::save_resource_as(const Ref<Resource>& p_resource) {
+ current_action=TOOL_SAVE_AS;
- add_resource(p_resource);
- TreeItem *root=resources->get_root();
- ERR_FAIL_COND(!root);
+ RES res(p_resource);
- TreeItem *existing=root->get_children();
+ List<String> extensions;
+ ResourceSaver::get_recognized_extensions(res,&extensions);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
- while(existing) {
+ if (p_resource->get_path()!="" && p_resource->get_path().find("::")==-1) {
- Ref<Resource> r = existing->get_metadata(0);
- if (r==p_resource) {
- //existing->move_to_top();
- existing->select(0);
- resources->ensure_cursor_is_visible();
- return; // existing
- }
- existing=existing->get_next();
- }
-
- ERR_FAIL_COND(!existing);
+ file->set_current_path(p_resource->get_path());
+ } else {
- existing->select(0);
+ String existing;
+ if (extensions.size()) {
+ existing="new_"+res->get_type().to_lower()+"."+extensions.front()->get().to_lower();
+ }
- _tool_selected(TOOL_SAVE_AS);
+ file->set_current_file(existing);
+ }
+ file->clear_filters();
+ for(int i=0;i<extensions.size();i++) {
+ file->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper());
+ }
+ file->popup_centered_ratio();
}
@@ -423,7 +396,7 @@ ResourcesDock::ResourcesDock(EditorNode *p_editor) {
accept = memnew (AcceptDialog);
add_child(accept);
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
add_child(file);
file->connect("file_selected",this,"_file_action");
diff --git a/tools/editor/resources_dock.h b/tools/editor/resources_dock.h
index edf769b157..933b457b29 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -38,6 +38,7 @@
#include "scene/gui/menu_button.h"
#include "scene/gui/file_dialog.h"
#include "create_dialog.h"
+#include "editor_file_dialog.h"
class EditorNode;
@@ -68,7 +69,7 @@ class ResourcesDock : public VBoxContainer {
CreateDialog *create_dialog;
AcceptDialog *accept;
- FileDialog *file;
+ EditorFileDialog *file;
Tree *resources;
bool block_add;
int current_action;
diff --git a/tools/editor/run_settings_dialog.cpp b/tools/editor/run_settings_dialog.cpp
index efe9c8f05f..e883c69939 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/run_settings_dialog.h b/tools/editor/run_settings_dialog.h
index da7c818263..fdb8857f6b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp
index c4c3a10f74..8b5bf8c1e1 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -33,11 +33,12 @@
#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 "multi_node_edit.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;
@@ -61,7 +62,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("Ok :( ");
accept->set_text("No parent to instance a child at.");
- accept->popup_centered(Size2(300,70));
+ accept->popup_centered_minsize();
return NULL;
};
@@ -70,7 +71,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) {
@@ -79,11 +80,23 @@ Node* SceneTreeDock::instance(const String& p_file) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("Ugh");
accept->set_text(String("Error loading scene from ")+p_file);
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
return NULL;
}
- instanced_scene->generate_instance_state();
+ // If the scene hasn't been saved yet a cyclical dependency cannot exist.
+ if (edited_scene->get_filename()!="") {
+
+ if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) {
+
+ accept->get_ok()->set_text("Ok");
+ accept->set_text(String("Cannot instance the scene '")+p_file+String("' because the current scene exists within one of its' nodes."));
+ accept->popup_centered_minsize();
+ return NULL;
+ }
+ }
+
+ //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");
@@ -93,6 +106,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();
@@ -100,6 +120,35 @@ Node* SceneTreeDock::instance(const String& p_file) {
}
+bool SceneTreeDock::_cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node) {
+ int childCount = p_desired_node->get_child_count();
+
+ if (p_desired_node->get_filename()==p_target_scene_path) {
+ return true;
+ }
+
+ for (int i=0;i<childCount;i++) {
+ Node* child=p_desired_node->get_child(i);
+
+ if(_cyclical_dependency_exists(p_target_scene_path,child)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static String _get_name_num_separator() {
+ switch(EditorSettings::get_singleton()->get("scenetree_editor/duplicate_node_name_num_separator").operator int()) {
+ case 0: return "";
+ case 1: return " ";
+ case 2: return "_";
+ case 3: return "-";
+ }
+ return " ";
+}
+
void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
current_option=p_tool;
@@ -108,6 +157,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
case TOOL_NEW: {
+
+ //if (!_validate_no_foreign())
+ // break;
create_dialog->popup_centered_ratio();
} break;
case TOOL_INSTANCE: {
@@ -120,11 +172,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation can't be done without a tree root.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ //if (!_validate_no_foreign())
+ // break;
+
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions);
file->clear_filters();
@@ -147,6 +202,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!current)
break;
+ //if (!_validate_no_foreign())
+ // break;
connect_dialog->popup_centered_ratio();
connect_dialog->set_node(current);
@@ -156,6 +213,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;
groups_editor->set_current(current);
groups_editor->popup_centered_ratio();
} break;
@@ -165,6 +224,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!selected)
break;
+ //if (!_validate_no_foreign())
+ // break;
+
Ref<Script> existing = selected->get_script();
if (existing.is_valid())
editor->push_item(existing.ptr());
@@ -183,6 +245,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!scene_tree->get_selected())
break;
+
if (scene_tree->get_selected()==edited_scene) {
@@ -190,22 +253,58 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation can't be done on the tree root.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
+ break;
+ }
+
+
+ if (!_validate_no_foreign())
break;
+
+ bool MOVING_DOWN = (p_tool == TOOL_MOVE_DOWN);
+ bool MOVING_UP = !MOVING_DOWN;
+
+ Node *common_parent = scene_tree->get_selected()->get_parent();
+ List<Node*> selection = editor_selection->get_selected_node_list();
+ selection.sort_custom<Node::Comparator>(); // sort by index
+ if (MOVING_DOWN)
+ selection.invert();
+
+ int lowest_id = common_parent->get_child_count() - 1;
+ int highest_id = 0;
+ for (List<Node*>::Element *E = selection.front(); E; E = E->next()) {
+ int index = E->get()->get_index();
+
+ if (index > highest_id) highest_id = index;
+ if (index < lowest_id) lowest_id = index;
+
+ if (E->get()->get_parent() != common_parent)
+ common_parent = NULL;
}
+ if (!common_parent || (MOVING_DOWN && highest_id >= common_parent->get_child_count() - MOVING_DOWN) || (MOVING_UP && lowest_id == 0))
+ break; // one or more nodes can not be moved
+
+ if (selection.size() == 1) editor_data->get_undo_redo().create_action("Move Node In Parent");
+ if (selection.size() > 1) editor_data->get_undo_redo().create_action("Move Nodes In Parent");
- Node * node=scene_tree->get_selected();
- ERR_FAIL_COND(!node->get_parent());
- int current_pos = node->get_index();
- int next_pos = current_pos + ((p_tool==TOOL_MOVE_DOWN)?1:-1);
+ 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());
- if (next_pos< 0 || next_pos>=node->get_parent()->get_child_count())
- break; // invalid position
+ int top_node_pos = top_node->get_index();
+ int bottom_node_pos = bottom_node->get_index();
+
+ int top_node_pos_next = top_node_pos + (MOVING_DOWN ? 1 : -1);
+ int bottom_node_pos_next = bottom_node_pos + (MOVING_DOWN ? 1 : -1);
+
+ editor_data->get_undo_redo().add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next);
+ editor_data->get_undo_redo().add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos);
+ }
- editor_data->get_undo_redo().create_action("Move Node In Parent");
- editor_data->get_undo_redo().add_do_method(node->get_parent(),"move_child",node,next_pos);
- editor_data->get_undo_redo().add_undo_method(node->get_parent(),"move_child",node,current_pos);
editor_data->get_undo_redo().commit_action();
} break;
@@ -214,6 +313,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!edited_scene)
break;
+
if (editor_selection->is_selected(edited_scene)) {
@@ -221,10 +321,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation can't be done on the tree root.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
+ if (!_validate_no_foreign())
+ break;
+
List<Node*> selection = editor_selection->get_selected_node_list();
List<Node*> reselect;
@@ -264,17 +367,21 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
int num=nums.to_int();
- if (num<2)
- num=2;
+ if (num<1)
+ num=1;
else
num++;
- name=name.substr(0,name.length()-nums.length()).strip_edges();
- String attempt=name+" "+itos(num);
+ String nnsep = _get_name_num_separator();
+ name = name.substr(0,name.length()-nums.length()).strip_edges();
+ if ( name.substr(name.length()-nnsep.length(),nnsep.length()) == nnsep) {
+ name = name.substr(0,name.length()-nnsep.length());
+ }
+ String attempt = (name + nnsep + itos(num)).strip_edges();
while(parent->has_node(attempt)) {
num++;
- attempt=name+" "+itos(num);
+ attempt = (name + nnsep + itos(num)).strip_edges();
}
dup->set_name(attempt);
@@ -290,9 +397,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_do_method(d,"set_owner",node->get_owner());
}
editor_data->get_undo_redo().add_do_method(editor_selection,"add_node",dup);
- editor_data->get_undo_redo().add_undo_method(parent,"remove_child",dup);
+ 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);
}
@@ -313,6 +425,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!scene_tree->get_selected())
break;
+
if (editor_selection->is_selected(edited_scene)) {
@@ -320,10 +433,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
//confirmation->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
accept->set_text("This operation can't be done on the tree root.");
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered_minsize();
break;
}
+ if (!_validate_no_foreign())
+ break;
+
List<Node*> nodes = editor_selection->get_selected_node_list();
Set<Node*> nodeset;
for(List<Node*>::Element *E=nodes.front();E;E=E->next()) {
@@ -334,6 +450,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();
@@ -341,6 +470,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (remove_list.empty())
return;
+ if (!_validate_no_foreign())
+ break;
+
if (p_confirm_override) {
_delete_confirm();
@@ -350,7 +482,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
} else {
delete_dialog->set_text("Delete Node(s)?");
- delete_dialog->popup_centered(Size2(200,80));
+ delete_dialog->popup_centered_minsize();
}
@@ -365,8 +497,18 @@ void SceneTreeDock::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_READY: {
+ if (!first_enter)
+ break;
+ first_enter=false;
+
+ CanvasItemEditorPlugin *canvas_item_plugin = editor_data->get_editor("2D")->cast_to<CanvasItemEditorPlugin>();
+ if (canvas_item_plugin) {
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", scene_tree, "_update_tree");
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", scene_tree, "_update_tree");
+ scene_tree->connect("node_changed", canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), "update");
+ }
static const char* button_names[TOOL_BUTTON_MAX]={
"New",
"Add",
@@ -378,21 +520,17 @@ void SceneTreeDock::_notification(int p_what) {
"MoveDown",
"Duplicate",
"Reparent",
- "Del",
+ "MultiNodeEdit",
+ "Remove",
};
+
+
for(int i=0;i<TOOL_BUTTON_MAX;i++)
tool_buttons[i]->set_icon(get_icon(button_names[i],"EditorIcons"));
- } break;
- case NOTIFICATION_READY: {
+ EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed",this,"_selection_changed");
- CanvasItemEditorPlugin *canvas_item_plugin = editor_data->get_editor("2D")->cast_to<CanvasItemEditorPlugin>();
- if (canvas_item_plugin) {
- canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", scene_tree, "_update_tree");
- canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", scene_tree, "_update_tree");
- scene_tree->connect("node_changed", canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), "update");
- }
} break;
}
}
@@ -422,6 +560,11 @@ void SceneTreeDock::_node_selected() {
editor->push_item(node);
}
+void SceneTreeDock::_node_renamed() {
+
+ _node_selected();
+}
+
Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node*,Node*> &duplimap) {
Node *node=NULL;
@@ -430,9 +573,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);
@@ -456,6 +599,16 @@ Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node*,Node*> &duplimap) {
}
+
+ List<Node::GroupInfo> group_info;
+ p_node->get_groups(&group_info);
+ for (List<Node::GroupInfo>::Element *E=group_info.front();E;E=E->next()) {
+
+ if (E->get().persistent)
+ node->add_to_group(E->get().name,true);
+ }
+
+
node->set_name(p_node->get_name());
duplimap[p_node]=node;
@@ -707,6 +860,35 @@ void SceneTreeDock::_node_prerenamed(Node* p_node, const String& p_new_name) {
}
+bool SceneTreeDock::_validate_no_foreign() {
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ for (List<Node*>::Element *E=selection.front();E;E=E->next()) {
+
+ if (E->get()!=edited_scene && E->get()->get_owner()!=edited_scene) {
+
+ accept->get_ok()->set_text("Makes Sense!");
+ accept->set_text("Can't operate on nodes from a foreign scene!");
+ accept->popup_centered_minsize();
+ 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) {
@@ -760,6 +942,13 @@ 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());
+
+
editor_data->get_undo_redo().add_do_method(this,"_set_owners",edited_scene,owners);
if (editor->get_animation_editor()->get_root()==node)
@@ -851,7 +1040,7 @@ void SceneTreeDock::_delete_confirm() {
//delete from animation
for(List<Node*>::Element *E=remove_list.front();E;E=E->next()) {
Node *n = E->get();
- if (!n->is_inside_scene() || !n->get_parent())
+ if (!n->is_inside_tree() || !n->get_parent())
continue;
fill_path_renames(n,NULL,&path_renames);
@@ -862,7 +1051,7 @@ void SceneTreeDock::_delete_confirm() {
//delete for read
for(List<Node*>::Element *E=remove_list.front();E;E=E->next()) {
Node *n = E->get();
- if (!n->is_inside_scene() || !n->get_parent())
+ if (!n->is_inside_tree() || !n->get_parent())
continue;
List<Node*> owned;
@@ -882,6 +1071,11 @@ void SceneTreeDock::_delete_confirm() {
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());
+
}
@@ -894,22 +1088,34 @@ void SceneTreeDock::_delete_confirm() {
void SceneTreeDock::_update_tool_buttons() {
Node *sel = scene_tree->get_selected();
- bool disable = !sel;
+ 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_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() {
@@ -919,14 +1125,15 @@ void SceneTreeDock::_create() {
if (edited_scene) {
-
+ // If root exists in edited scene
parent = scene_tree->get_selected();
- ERR_FAIL_COND(!parent);
- } else {
+ if( !parent )
+ parent = edited_scene;
+ } else {
+ // If no root exist in edited scene
parent = scene_root;
ERR_FAIL_COND(!parent);
-
}
Object *c = create_dialog->instance_selected();
@@ -938,12 +1145,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);
@@ -1008,24 +1223,21 @@ 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);
}
-
-
-
editor_data->get_undo_redo().clear_history();
- memdelete(n);
newnode->set_name(newname);
+
editor->push_item(newnode);
+ memdelete(n);
+
_update_tool_buttons();
}
@@ -1052,7 +1264,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..
@@ -1077,6 +1292,7 @@ void SceneTreeDock::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_node_reparent"),&SceneTreeDock::_node_reparent);
ObjectTypeDB::bind_method(_MD("_set_owners"),&SceneTreeDock::_set_owners);
ObjectTypeDB::bind_method(_MD("_node_selected"),&SceneTreeDock::_node_selected);
+ ObjectTypeDB::bind_method(_MD("_node_renamed"),&SceneTreeDock::_node_renamed);
ObjectTypeDB::bind_method(_MD("_script_created"),&SceneTreeDock::_script_created);
ObjectTypeDB::bind_method(_MD("_load_request"),&SceneTreeDock::_load_request);
ObjectTypeDB::bind_method(_MD("_script_open_request"),&SceneTreeDock::_script_open_request);
@@ -1084,6 +1300,7 @@ 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("instance"),&SceneTreeDock::instance);
}
@@ -1113,7 +1330,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
tb = memnew( ToolButton );
tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_INSTANCE, false));
- tb->set_tooltip("Instance a Node from scene file.");
+ tb->set_tooltip("Instance a scene file as a Node.");
hbc_top->add_child(tb);
tool_buttons[TOOL_INSTANCE]=tb;
@@ -1187,6 +1404,12 @@ 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_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);
@@ -1213,7 +1436,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
accept = memnew( AcceptDialog );
add_child(accept);
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
add_child(file);
file->connect("file_selected",this,"instance");
set_process_unhandled_key_input(true);
@@ -1225,7 +1448,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
add_child(import_subscene_dialog);
import_subscene_dialog->connect("subscene_selected",this,"_import_subscene");
-
+ first_enter=true;
}
diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h
index 99ef16e6f6..b1c53d2ff9 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -62,6 +62,7 @@ class SceneTreeDock : public VBoxContainer {
TOOL_MOVE_DOWN,
TOOL_DUPLICATE,
TOOL_REPARENT,
+ TOOL_MULTI_EDIT,
TOOL_ERASE,
TOOL_BUTTON_MAX
};
@@ -87,9 +88,10 @@ class SceneTreeDock : public VBoxContainer {
ConfirmationDialog *delete_dialog;
ReparentDialog *reparent_dialog;
- FileDialog *file;
+ EditorFileDialog *file;
EditorSubScene *import_subscene_dialog;
+ bool first_enter;
void _create();
Node *scene_root;
@@ -102,8 +104,10 @@ class SceneTreeDock : public VBoxContainer {
void _load_request(const String& p_path);
void _script_open_request(const Ref<Script>& p_script);
+ bool _cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node);
void _node_selected();
+ void _node_renamed();
void _script_created(Ref<Script> p_script);
void _delete_confirm();
@@ -115,6 +119,8 @@ class SceneTreeDock : public VBoxContainer {
void _import_subscene();
+ 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);
@@ -130,6 +136,7 @@ public:
void set_selected(Node *p_node, bool p_emit_selected=false);
void fill_path_renames(Node* p_node, Node *p_new_parent, List<Pair<NodePath,NodePath> > *p_renames);
void perform_node_renames(Node* p_base,List<Pair<NodePath,NodePath> > *p_renames, Map<Ref<Animation>, Set<int> > *r_rem_anims=NULL);
+ SceneTreeEditor *get_tree_editor() { return scene_tree; }
SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelection *p_editor_selection,EditorData &p_editor_data);
};
diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp
index 4d0ed3e1dd..6575603073 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -34,17 +34,89 @@
#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_scene(),NULL);
- if (get_scene()->get_root()->get_child_count() && get_scene()->get_root()->get_child(0)->cast_to<EditorNode>())
- return get_scene()->get_root()->get_child(0)->cast_to<EditorNode>()->get_edited_scene();
+ 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_scene()->get_root();
+ return get_tree()->get_root();
return NULL;
}
+
+void SceneTreeEditor::_subscene_option(int p_idx) {
+
+ Object *obj = ObjectDB::get_instance(instance_node);
+ if (!obj)
+ return;
+ Node *node = obj->cast_to<Node>();
+ if (!node)
+ return;
+
+ switch(p_idx) {
+
+ case SCENE_MENU_EDITABLE_CHILDREN: {
+
+ 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;
+
+ }
+
+}
+
+
void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id) {
TreeItem *item=p_item->cast_to<TreeItem>();
@@ -57,7 +129,37 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id)
if (p_id==BUTTON_SUBSCENE) {
//open scene request
- emit_signal("open",n->get_filename());
+ Rect2 item_rect = tree->get_item_rect(item,0);
+ item_rect.pos.y-=tree->get_scroll().y;
+ item_rect.pos+=tree->get_global_pos();
+
+ 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();
if (!script.is_null())
@@ -66,18 +168,26 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id)
} else if (p_id==BUTTON_VISIBILITY) {
- if (n->is_type("GeometryInstance")) {
- bool v = n->call("get_flag",VS::INSTANCE_FLAG_VISIBLE);
- undo_redo->create_action("Toggle Geometry Visible");
- undo_redo->add_do_method(n,"set_flag",VS::INSTANCE_FLAG_VISIBLE,!v);
- undo_redo->add_undo_method(n,"set_flag",VS::INSTANCE_FLAG_VISIBLE,v);
+ if (n->is_type("Spatial")) {
+
+ Spatial *ci = n->cast_to<Spatial>();
+ if (!ci->is_visible() && ci->get_parent_spatial() && !ci->get_parent_spatial()->is_visible()) {
+ error->set_text("This item cannot be made visible because the parent is hidden. Unhide the parent first.");
+ error->popup_centered_minsize();
+ return;
+ }
+
+ bool v = !bool(n->call("is_hidden"));
+ undo_redo->create_action("Toggle Spatial Visible");
+ undo_redo->add_do_method(n,"_set_visible_",!v);
+ undo_redo->add_undo_method(n,"_set_visible_",v);
undo_redo->commit_action();
} else if (n->is_type("CanvasItem")) {
CanvasItem *ci = n->cast_to<CanvasItem>();
if (!ci->is_visible() && ci->get_parent_item() && !ci->get_parent_item()->is_visible()) {
error->set_text("This item cannot be made visible because the parent is hidden. Unhide the parent first.");
- error->popup_centered_minsize(Size2(400,80));
+ error->popup_centered_minsize();
return;
}
bool v = !bool(n->call("is_hidden"));
@@ -111,13 +221,25 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
// only owned nodes are editable, since nodes can create their own (manually owned) child nodes,
// which the editor needs not to know about.
-
- if (!display_foreign && p_node->get_owner()!=get_scene_node() && p_node!=get_scene_node())
- return;
+
+ bool part_of_subscene=false;
+
+ 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() && (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);
@@ -135,8 +257,13 @@ 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 (marked.has(p_node)) {
+
+ if (part_of_subscene) {
+
+ //item->set_selectable(0,marked_selectable);
+ item->set_custom_color(0,Color(0.8,0.4,0.20));
+
+ } else if (marked.has(p_node)) {
item->set_selectable(0,marked_selectable);
item->set_custom_color(0,Color(0.8,0.1,0.10));
@@ -153,10 +280,15 @@ 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("Load","EditorIcons"),BUTTON_SUBSCENE);
- item->set_tooltip(0,"Instance: "+p_node->get_filename());
+ item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
+ item->set_tooltip(0,"Instance: "+p_node->get_filename()+"\nType: "+p_node->get_type());
+ } else {
+ item->set_tooltip(0,String(p_node->get_name())+"\nType: "+p_node->get_type());
}
if (can_open_instance) {
@@ -189,9 +321,9 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
if (!p_node->is_connected("visibility_changed",this,"_node_visibility_changed"))
p_node->connect("visibility_changed",this,"_node_visibility_changed",varray(p_node));
- } else if (p_node->is_type("GeometryInstance")) {
+ } else if (p_node->is_type("Spatial")) {
- bool h = !p_node->call("get_flag",VS::INSTANCE_FLAG_VISIBLE);
+ bool h = p_node->call("is_hidden");
if (h)
item->add_button(0,get_icon("Hidden","EditorIcons"),BUTTON_VISIBILITY);
else
@@ -226,7 +358,16 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
+
+ if (p_node!=get_scene_node() && !p_node->get_owner()) {
+
+ return;
+ }
TreeItem* item=p_node?_find(tree->get_root(),p_node->get_path()):NULL;
+ if (!item) {
+
+ return;
+ }
int idx=item->get_button_by_id(0,BUTTON_VISIBILITY);
ERR_FAIL_COND(idx==-1);
@@ -234,11 +375,10 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
if (p_node->is_type("CanvasItem")) {
visible = !p_node->call("is_hidden");
- } else if (p_node->is_type("GeometryInstance")) {
- visible = p_node->call("get_flag",VS::INSTANCE_FLAG_VISIBLE);
+ } else if (p_node->is_type("Spatial")) {
+ visible = !p_node->call("is_hidden");
}
-
if (!visible)
item->set_button(0,idx,get_icon("Hidden","EditorIcons"));
else
@@ -274,7 +414,7 @@ void SceneTreeEditor::_node_removed(Node *p_node) {
if (p_node->is_connected("script_changed",this,"_node_script_changed"))
p_node->disconnect("script_changed",this,"_node_script_changed");
- if (p_node->is_type("GeometryInstance") || p_node->is_type("CanvasItem")) {
+ if (p_node->is_type("Spatial") || p_node->is_type("CanvasItem")) {
if (p_node->is_connected("visibility_changed",this,"_node_visibility_changed"))
p_node->disconnect("visibility_changed",this,"_node_visibility_changed");
}
@@ -289,7 +429,7 @@ void SceneTreeEditor::_node_removed(Node *p_node) {
void SceneTreeEditor::_update_tree() {
- if (!is_inside_scene()) {
+ if (!is_inside_tree()) {
tree_dirty=false;
return;
}
@@ -325,7 +465,7 @@ void SceneTreeEditor::_test_update_tree() {
pending_test_update=false;
- if (!is_inside_scene())
+ if (!is_inside_tree())
return;
if(tree_dirty)
@@ -405,21 +545,26 @@ void SceneTreeEditor::_cell_multi_selected(Object *p_object,int p_cell,bool p_se
void SceneTreeEditor::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
- get_scene()->connect("tree_changed",this,"_tree_changed");
- get_scene()->connect("node_removed",this,"_node_removed");
+ get_tree()->connect("tree_changed",this,"_tree_changed");
+ get_tree()->connect("node_removed",this,"_node_removed");
+ 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);
_update_tree();
}
- if (p_what==NOTIFICATION_EXIT_SCENE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
- get_scene()->disconnect("tree_changed",this,"_tree_changed");
- get_scene()->disconnect("node_removed",this,"_node_removed");
- _update_tree();
+ get_tree()->disconnect("tree_changed",this,"_tree_changed");
+ get_tree()->disconnect("node_removed",this,"_node_removed");
+ tree->disconnect("item_collapsed",this,"_cell_collapsed");
+ clear_inherit_confirm->disconnect("confirmed",this,"_subscene_option");
}
}
@@ -503,20 +648,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();
}
@@ -630,6 +783,7 @@ void SceneTreeEditor::_cell_collapsed(Object *p_obj) {
}
+
void SceneTreeEditor::_bind_methods() {
ObjectTypeDB::bind_method("_tree_changed",&SceneTreeEditor::_tree_changed);
@@ -643,6 +797,7 @@ void SceneTreeEditor::_bind_methods() {
ObjectTypeDB::bind_method("_selection_changed",&SceneTreeEditor::_selection_changed);
ObjectTypeDB::bind_method("_cell_button_pressed",&SceneTreeEditor::_cell_button_pressed);
ObjectTypeDB::bind_method("_cell_collapsed",&SceneTreeEditor::_cell_collapsed);
+ ObjectTypeDB::bind_method("_subscene_option",&SceneTreeEditor::_subscene_option);
ObjectTypeDB::bind_method("_node_script_changed",&SceneTreeEditor::_node_script_changed);
ObjectTypeDB::bind_method("_node_visibility_changed",&SceneTreeEditor::_node_visibility_changed);
@@ -698,10 +853,35 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open
error = memnew( AcceptDialog );
add_child(error);
+ show_enabled_subscene=false;
+
last_hash=0;
pending_test_update=false;
updating_tree=false;
blocked=0;
+
+ instance_menu = memnew( PopupMenu );
+ 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);
+
+
}
@@ -715,10 +895,15 @@ SceneTreeEditor::~SceneTreeEditor() {
void SceneTreeDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
connect("confirmed", this,"_select");
}
+
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+ disconnect("confirmed", this,"_select");
+
+ }
if (p_what==NOTIFICATION_DRAW) {
RID ci = get_canvas_item();
diff --git a/tools/editor/scene_tree_editor.h b/tools/editor/scene_tree_editor.h
index 19375ba638..50cca4e24b 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -51,10 +51,23 @@ class SceneTreeEditor : public Control {
BUTTON_GROUP=4,
};
+ enum {
+ 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;
@@ -78,6 +91,7 @@ class SceneTreeEditor : public Control {
bool can_rename;
bool can_open_instance;
bool updating_tree;
+ bool show_enabled_subscene;
void _renamed();
UndoRedo *undo_redo;
@@ -95,6 +109,7 @@ class SceneTreeEditor : public Control {
void _update_selection(TreeItem *item);
void _node_script_changed(Node *p_node);
void _node_visibility_changed(Node *p_node);
+ void _subscene_option(int p_idx);
void _selection_changed();
Node *get_scene_node();
@@ -112,8 +127,13 @@ public:
void set_can_rename(bool p_can_rename) { can_rename=p_can_rename; }
void set_editor_selection(EditorSelection *p_selection);
+ void set_show_enabled_subscene(bool p_show) { show_enabled_subscene=p_show; }
+
void update_tree() { _update_tree(); }
+
+ Tree* get_scene_tree() { return tree; }
+
SceneTreeEditor(bool p_label=true,bool p_can_rename=false, bool p_can_open_instance=false);
~SceneTreeEditor();
@@ -139,7 +159,7 @@ protected:
static void _bind_methods();
public:
- SceneTreeEditor *get_tree() { return tree; }
+ SceneTreeEditor *get_scene_tree() { return tree; }
SceneTreeDialog();
~SceneTreeDialog();
diff --git a/tools/editor/scenes.cpp b/tools/editor/scenes.cpp
index 7860c04870..ada5751b5a 100644
--- a/tools/editor/scenes.cpp
+++ b/tools/editor/scenes.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/scenes.h b/tools/editor/scenes.h
index 59e7b728e2..463c3b5e18 100644
--- a/tools/editor/scenes.h
+++ b/tools/editor/scenes.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp
index a23c9cead7..c9b376ebec 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -30,20 +30,35 @@
#include "os/dir_access.h"
#include "os/file_access.h"
#include "globals.h"
-#include "scene/io/scene_loader.h"
+
#include "io/resource_loader.h"
#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;
}
@@ -115,70 +151,194 @@ void ScenesDock::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ 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) {
+ 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");
- String l = f->get_line();
- 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_EXIT_SCENE: {
-
} 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;
+
}
}
-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();
- timer->start();
+ 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_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,229 +352,902 @@ 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(){
- TreeItem *sel = tree->get_selected();
- if (!sel)
+void ScenesDock::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) {
+
+ 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;
- String path = sel->get_metadata(0);
- if (ResourceLoader::get_resource_type(path)=="PackedScene") {
+ 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");
- editor->open_request(path);
} 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());
- RES res = ResourceLoader::load(path);
- if (res.is_null()) {
+ }
- return;
- }*/
+ 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);
- editor->load_resource(path);
}
-// emit_signal("open",path);
}
-void ScenesDock::_save_favorites() {
+void ScenesDock::_select_file(int p_idx) {
- 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() ) {
+ files->select(p_idx,true);
+ _open_pressed();
+}
- CharString utf8f = E->get().utf8();
- f->store_buffer((const uint8_t*)utf8f.get_data(),utf8f.length());
- f->store_8('\n');
+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);
+
- f->close();
- memdelete(f);
}
+void ScenesDock::_fs_changed() {
-void ScenesDock::_rescan() {
+ button_hist_prev->set_disabled(history_pos==0);
+ button_hist_next->set_disabled(history_pos+1==history.size());
+ scanning_vb->hide();
- EditorFileSystem::get_singleton()->scan();
+ 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::_bind_methods() {
+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);
+ }
- 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("_instance_pressed"),&ScenesDock::_instance_pressed);
- ObjectTypeDB::bind_method(_MD("_open_pressed"),&ScenesDock::_open_pressed);
- ObjectTypeDB::bind_method(_MD("_save_favorites"),&ScenesDock::_save_favorites);
+}
- ADD_SIGNAL(MethodInfo("instance"));
- ADD_SIGNAL(MethodInfo("open"));
+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());
}
-ScenesDock::ScenesDock(EditorNode *p_editor) {
+void ScenesDock::_bw_history() {
- editor=p_editor;
+ if (history_pos>0)
+ history_pos--;
- HBoxContainer *toolbar_hbc = memnew( HBoxContainer );
- add_child(toolbar_hbc);
+ path=history[history_pos];
- button_reload = memnew( Button );
- button_reload->set_flat(true);
- button_reload->connect("pressed",this,"_rescan");
- toolbar_hbc->add_child(button_reload);
+ if (tree_mode) {
+ _update_tree();
+ tree->grab_focus();
+ tree->ensure_cursor_is_visible();
+ } else {
+ _update_files(false);
+ current_path->set_text(path);
+ }
- button_favorite = memnew( Button );
- button_favorite->set_flat(true);
- button_favorite->set_toggle_mode(true);
- button_favorite->connect("toggled",this,"_favorites_toggled");
- toolbar_hbc->add_child(button_favorite);
+ button_hist_prev->set_disabled(history_pos==0);
+ button_hist_next->set_disabled(history_pos+1==history.size());
- 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);
+void ScenesDock::_push_to_history() {
- button_instance = memnew( Button );
- button_instance->set_flat(true);
- button_instance->connect("pressed",this,"_instance_pressed");
- toolbar_hbc->add_child(button_instance);
+ history.resize(history_pos+1);
+ if (history[history_pos]!=path) {
+ history.push_back(path);
+ history_pos++;
+ }
- tree = memnew( Tree );
- tree_filter=memnew( ScenesDockFilter() );
- tree_filter->connect("filter_changed", this, "_update_tree");
- add_child(tree_filter);
- add_child(tree);
+ button_hist_prev->set_disabled(history_pos==0);
+ button_hist_next->set_disabled(history_pos+1==history.size());
- tree->set_v_size_flags(SIZE_EXPAND_FILL);
- tree->connect("item_edited",this,"_favorite_toggled");
+}
- timer = memnew( Timer );
- timer->set_one_shot(true);
- timer->set_wait_time(2);
- timer->connect("timeout",this,"_save_favorites");
- add_child(timer);
+void ScenesDock::_find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files) {
- updating_tree=false;
+ 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));
+ }
}
-ScenesDock::~ScenesDock() {
+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 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);
+void ScenesDock::_rename_operation(const String& p_to_path) {
- file_filter->add_item("All Files (*)");
- filters.push_back("*");
+ 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;
+ }
- 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]);
+ 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");
+ }
}
- 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+" )");
+ //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");
}
-#endif
+
+ //rescan everything
+ memdelete(da);
+ print_line("call rescan!");
+ _rescan();
}
-void ScenesDockFilter::_command(int p_command) {
- switch (p_command) {
- case CMD_CLEAR_FILTER: {
- if (search_box->get_text()!="") {
- search_box->clear();
- emit_signal("filter_changed");
+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;
+ }
+
+ EditorFileSystemDirectory *efsd=EditorFileSystem::get_singleton()->get_path(move_dirs[i]);
+ if (!efsd)
+ continue;
+ _find_inside_move_files(efsd,inside_files);
+ }
+
+ //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;
}
- }break;
+
+ remove_dialog->show(torem);
+ //1) find if used
+ //2) warn
+
+ } break;
+ case FILE_INFO: {
+
+ } break;
+
}
}
-void ScenesDockFilter::_search_text_changed(const String &p_newtext) {
- emit_signal("filter_changed");
+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;
+
+ 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();
+
+ _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);
+ }
+ }
+ }
+
+// emit_signal("open",path);
+
}
-String ScenesDockFilter::get_search_term() {
- return search_box->get_text().strip_edges();
+
+void ScenesDock::_rescan() {
+
+ _set_scannig_mode();
+ EditorFileSystem::get_singleton()->scan();
+
}
-ScenesDockFilter::FilterOption ScenesDockFilter::get_file_filter() {
- return _current_filter;
+void ScenesDock::fix_dependencies(const String& p_for_file) {
+ deps_editor->edit(p_for_file);
}
-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 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();
}
-}
-void ScenesDockFilter::_notification(int p_what) {
- switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
- clear_search_button->set_icon(get_icon("CloseHover","EditorIcons"));
- } break;
+ 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 ScenesDockFilter::_bind_methods() {
+void ScenesDock::_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);
+ ObjectTypeDB::bind_method(_MD("_update_tree"),&ScenesDock::_update_tree);
+ ObjectTypeDB::bind_method(_MD("_rescan"),&ScenesDock::_rescan);
+ 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("_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"));
- ADD_SIGNAL( MethodInfo("filter_changed") );
}
-ScenesDockFilter::ScenesDockFilter() {
+ScenesDock::ScenesDock(EditorNode *p_editor) {
+
+ editor=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("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);
- _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);
+ 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.");
- _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);
+ 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.");
- clear_search_button = memnew( ToolButton );
- clear_search_button->connect("pressed",this,"_command",make_binds(CMD_CLEAR_FILTER));
- add_child(clear_search_button);
+ tree = memnew( Tree );
+
+ 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");
+ 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;
+
+ history.push_back("res://");
+ history_pos=0;
+ tree_mode=true;
+
+
+}
+
+ScenesDock::~ScenesDock() {
}
diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h
index 9849f5ace0..d045124bf7 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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,14 @@ protected:
public:
String get_selected_path() const;
+ void open(const String& p_path);
+
+ void fix_dependencies(const String& p_for_file);
+
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 89c0bd6ab4..622150ab68 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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 {
@@ -99,12 +99,12 @@ void ScriptCreateDialog::ok_pressed() {
if (class_name->is_editable() && !_validate(class_name->get_text())) {
alert->set_text("Class Name is Invalid!");
- alert->popup_centered(Size2(200,60));
+ alert->popup_centered_minsize();
return;
}
if (!_validate(parent_name->get_text())) {
alert->set_text("Parent Class Name is Invalid!");
- alert->popup_centered(Size2(200,60));
+ alert->popup_centered_minsize();
return;
@@ -134,7 +134,7 @@ void ScriptCreateDialog::ok_pressed() {
if (!path_valid) {
alert->set_text("Path is Invalid!");
- alert->popup_centered(Size2(200,60));
+ alert->popup_centered_minsize();
return;
}
@@ -142,7 +142,7 @@ void ScriptCreateDialog::ok_pressed() {
if (err!=OK) {
alert->set_text("Could not create script in filesystem: "+String(""));
- alert->popup_centered(Size2(200,60));
+ alert->popup_centered_minsize();
return;
}
scr->set_path(lpath);
@@ -184,7 +184,7 @@ void ScriptCreateDialog::_built_in_pressed() {
void ScriptCreateDialog::_browse_path() {
- file_browse->set_mode(FileDialog::MODE_SAVE_FILE);
+ file_browse->set_mode(EditorFileDialog::MODE_SAVE_FILE);
file_browse->clear_filters();
List<String> extensions;
@@ -363,9 +363,9 @@ 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( FileDialog );
+ file_browse = memnew( EditorFileDialog );
file_browse->connect("file_selected",this,"_file_selected");
add_child(file_browse);
get_ok()->set_text("Create");
diff --git a/tools/editor/script_create_dialog.h b/tools/editor/script_create_dialog.h
index 42fa9d68c3..59fde8fbd5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -32,7 +32,7 @@
#include "scene/gui/dialogs.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
-#include "scene/gui/file_dialog.h"
+#include "tools/editor/editor_file_dialog.h"
#include "scene/gui/check_button.h"
class ScriptCreateDialog : public ConfirmationDialog {
@@ -44,7 +44,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
LineEdit *parent_name;
OptionButton *language_menu;
LineEdit *file_path;
- FileDialog *file_browse;
+ EditorFileDialog *file_browse;
CheckButton *internal;
VBoxContainer *path_vb;
AcceptDialog *alert;
diff --git a/tools/editor/script_editor_debugger.cpp b/tools/editor/script_editor_debugger.cpp
index 00066e67e9..60f2afa2c2 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -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();
@@ -241,6 +252,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") {
@@ -342,6 +380,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");
@@ -431,7 +526,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
switch(p_what) {
- case NOTIFICATION_ENTER_SCENE: {
+ case NOTIFICATION_ENTER_TREE: {
step->set_icon( get_icon("DebugStep","EditorIcons"));
next->set_icon( get_icon("DebugNext","EditorIcons"));
@@ -443,10 +538,24 @@ 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");
+ } else {
+ error_split->set_name("Errors ("+itos(error_count)+")");
+ }
+ last_error_count=error_count;
+ }
if (connection.is_null()) {
if (server->is_connection_available()) {
@@ -468,6 +577,15 @@ void ScriptEditorDebugger::_notification(int p_what) {
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 {
@@ -478,8 +596,6 @@ void ScriptEditorDebugger::_notification(int p_what) {
if (!connection->is_connected()) {
stop();
editor->notify_child_process_exited(); //somehow, exited
- msgdialog->set_text("Process being debugged exited.");
- msgdialog->popup_centered(Size2(250,100));
break;
};
@@ -615,6 +731,10 @@ void ScriptEditorDebugger::stop(){
log_forced_visible=false;
}
+ node_path_cache.clear();
+ res_path_cache.clear();
+ le_clear->set_disabled(false);
+ le_set->set_disabled(true);
hide();
@@ -666,6 +786,381 @@ 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::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_stack_dump_frame_selected"),&ScriptEditorDebugger::_stack_dump_frame_selected);
@@ -678,6 +1173,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")));
@@ -771,7 +1280,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
inspector = memnew( PropertyEditor );
inspector->set_h_size_flags(SIZE_EXPAND_FILL);
inspector->hide_top_label();
- inspector->get_tree()->set_column_title(0,"Variable");
+ inspector->get_scene_tree()->set_column_title(0,"Variable");
inspector->set_capitalize_paths(false);
inspector->set_read_only(true);
sc->add_child(inspector);
@@ -791,6 +1300,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);
@@ -834,6 +1360,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);
@@ -845,6 +1412,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);
@@ -870,6 +1457,14 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
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;
+ last_error_count=0;
+
+
}
ScriptEditorDebugger::~ScriptEditorDebugger() {
diff --git a/tools/editor/script_editor_debugger.h b/tools/editor/script_editor_debugger.h
index 5127a329aa..6b66a62dd5 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -26,110 +26,166 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCRIPT_EDITOR_DEBUGGER_H
-#define SCRIPT_EDITOR_DEBUGGER_H
-
-#include "scene/gui/box_container.h"
-#include "scene/gui/button.h"
-#include "core/io/tcp_server.h"
-#include "core/io/packet_peer.h"
-
-class Tree;
-class PropertyEditor;
-class EditorNode;
-class ScriptEditorDebuggerVariables;
-class LineEdit;
-class TabContainer;
-class RichTextLabel;
-class TextureButton;
-class AcceptDialog;
-class TreeItem;
-class HSplitContainer;
-
-class ScriptEditorDebugger : public Control {
-
- OBJ_TYPE( ScriptEditorDebugger, Control );
-
- AcceptDialog *msgdialog;
-
-
-
- LineEdit *clicked_ctrl;
- LineEdit *clicked_ctrl_type;
- Tree *scene_tree;
- HSplitContainer *info;
- Button *scene_tree_refresh;
-
- TextureButton *tb;
-
-
- TabContainer *tabs;
-
- Label *reason;
- bool log_forced_visible;
- ScriptEditorDebuggerVariables *variables;
-
- Button *step;
- Button *next;
- Button *back;
- Button *forward;
- Button *dobreak;
- Button *docontinue;
-
- List<Vector<float> > perf_history;
- Vector<float> perf_max;
- Vector<TreeItem*> perf_items;
-
- Tree *perf_monitors;
- Control *perf_draw;
-
- Tree *stack_dump;
- PropertyEditor *inspector;
-
- Ref<TCP_Server> server;
- Ref<StreamPeerTCP> connection;
- Ref<PacketPeerStream> ppeer;
-
- String message_type;
- Array message;
- int pending_in_queue;
-
-
- EditorNode *editor;
-
- bool breaked;
-
- void _performance_draw();
- void _performance_select(Object *, int, bool);
- void _stack_dump_frame_selected();
- void _output_clear();
- void _hide_request();
-
- void _scene_tree_request();
- void _parse_message(const String& p_msg,const Array& p_data);
-
-protected:
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
-
- void start();
- void pause();
- void unpause();
- void stop();
-
- void debug_next();
- void debug_step();
- void debug_break();
- void debug_continue();
-
- String get_var_value(const String& p_var) const;
-
- virtual Size2 get_minimum_size() const;
- ScriptEditorDebugger(EditorNode *p_editor=NULL);
- ~ScriptEditorDebugger();
-};
-
-#endif // SCRIPT_EDITOR_DEBUGGER_H
+#ifndef SCRIPT_EDITOR_DEBUGGER_H
+#define SCRIPT_EDITOR_DEBUGGER_H
+
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "core/io/tcp_server.h"
+#include "core/io/packet_peer.h"
+
+class Tree;
+class PropertyEditor;
+class EditorNode;
+class ScriptEditorDebuggerVariables;
+class LineEdit;
+class TabContainer;
+class RichTextLabel;
+class TextureButton;
+class AcceptDialog;
+class TreeItem;
+class HSplitContainer;
+class ItemList;
+
+class ScriptEditorDebugger : public Control {
+
+ OBJ_TYPE( ScriptEditorDebugger, Control );
+
+ AcceptDialog *msgdialog;
+
+
+
+ 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;
+
+
+
+ TextureButton *tb;
+
+
+ TabContainer *tabs;
+
+ Label *reason;
+ bool log_forced_visible;
+ ScriptEditorDebuggerVariables *variables;
+
+ Button *step;
+ Button *next;
+ Button *back;
+ Button *forward;
+ Button *dobreak;
+ Button *docontinue;
+
+ List<Vector<float> > perf_history;
+ Vector<float> perf_max;
+ Vector<TreeItem*> perf_items;
+
+ Tree *perf_monitors;
+ Control *perf_draw;
+
+ Tree *vmem_tree;
+ Button *vmem_refresh;
+ LineEdit *vmem_total;
+
+ Tree *stack_dump;
+ PropertyEditor *inspector;
+
+ Ref<TCP_Server> server;
+ Ref<StreamPeerTCP> connection;
+ Ref<PacketPeerStream> ppeer;
+
+ String message_type;
+ 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();
+ void _output_clear();
+ void _hide_request();
+
+ 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);
+ static void _bind_methods();
+
+public:
+
+ void start();
+ void pause();
+ void unpause();
+ void stop();
+
+ void debug_next();
+ void debug_step();
+ void debug_break();
+ void debug_continue();
+
+ 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();
+
+
+ virtual Size2 get_minimum_size() const;
+ ScriptEditorDebugger(EditorNode *p_editor=NULL);
+ ~ScriptEditorDebugger();
+};
+
+#endif // SCRIPT_EDITOR_DEBUGGER_H
diff --git a/tools/editor/settings_config_dialog.cpp b/tools/editor/settings_config_dialog.cpp
index c82b075bc4..6d8f849427 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -72,6 +72,10 @@ void EditorSettingsDialog::popup_edit_settings() {
property_editor->edit(EditorSettings::get_singleton());
property_editor->update_tree();
+
+ search_box->select_all();
+ search_box->grab_focus();
+
popup_centered_ratio(0.7);
}
@@ -244,11 +248,21 @@ void EditorSettingsDialog::_update_plugins() {
}
+void EditorSettingsDialog::_clear_search_box() {
+
+ if (search_box->get_text()=="")
+ return;
+
+ search_box->clear();
+ property_editor->update_tree();
+}
+
void EditorSettingsDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_SCENE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
rescan_plugins->set_icon(get_icon("Reload","EditorIcons"));
+ clear_button->set_icon(get_icon("Close","EditorIcons"));
_update_plugins();
}
}
@@ -261,6 +275,7 @@ void EditorSettingsDialog::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_plugin_settings"),&EditorSettingsDialog::_plugin_settings);
ObjectTypeDB::bind_method(_MD("_plugin_edited"),&EditorSettingsDialog::_plugin_edited);
ObjectTypeDB::bind_method(_MD("_plugin_install"),&EditorSettingsDialog::_plugin_install);
+ ObjectTypeDB::bind_method(_MD("_clear_search_box"),&EditorSettingsDialog::_clear_search_box);
}
EditorSettingsDialog::EditorSettingsDialog() {
@@ -271,16 +286,38 @@ EditorSettingsDialog::EditorSettingsDialog() {
add_child(tabs);
set_child_rect(tabs);
+ VBoxContainer *vbc = memnew( VBoxContainer );
+ tabs->add_child(vbc);
+ vbc->set_name("General");
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ vbc->add_child(hbc);
+
+ Label *l = memnew( Label );
+ l->set_text("Search: ");
+ hbc->add_child(l);
+
+ search_box = memnew( LineEdit );
+ search_box->set_h_size_flags(Control::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");
+
property_editor = memnew( PropertyEditor );
property_editor->hide_top_label();
- tabs->add_child(property_editor);
- property_editor->set_name("General");
+ property_editor->set_use_filter(true);
+ property_editor->register_text_enter(search_box);
+ property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ vbc->add_child(property_editor);
- VBoxContainer *vbc = memnew( VBoxContainer );
+ vbc = memnew( VBoxContainer );
tabs->add_child(vbc);
vbc->set_name("Plugins");
- HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc = memnew( HBoxContainer );
vbc->add_child(hbc);
hbc->add_child( memnew( Label("Plugin List: ")));
hbc->add_spacer();
diff --git a/tools/editor/settings_config_dialog.h b/tools/editor/settings_config_dialog.h
index a3e4a87faf..50159cf488 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-2014 Juan Linietsky, Ariel Manzur. */
+/* 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 */
@@ -51,6 +51,8 @@ class EditorSettingsDialog : public AcceptDialog {
Button *rescan_plugins;
Tree *plugins;
+ LineEdit *search_box;
+ ToolButton *clear_button;
PropertyEditor *property_editor;
Timer *timer;
@@ -71,6 +73,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 83efb48bd3..5efca44c7d 100644
--- a/tools/editor/spatial_editor_gizmos.cpp
+++ b/tools/editor/spatial_editor_gizmos.cpp
@@ -1,2370 +1,3191 @@
-/*************************************************************************/
-/* spatial_editor_gizmos.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#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 "editor_shape_gizmos.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);
-}
-
-
-
-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;
-
-
-
- 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;
-
-
- 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 CarWheelSpatialGizmo::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_travel()*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_travel(),0));
-
- //axis
- points.push_back(Vector3(r*0.2,car_wheel->get_travel(),0));
- points.push_back(Vector3(-r*0.2,car_wheel->get_travel(),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);
-
-}
-
-CarWheelSpatialGizmo::CarWheelSpatialGizmo(CarWheel* 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 = ra[p_idx];
- 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<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);
-}
-
-
-
-
-
-
-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);
-}
-
-
-
-////////
-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<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<EditableShape>()) {
-
- Ref<EditableShapeSpatialGizmo> misg = memnew( EditableShapeSpatialGizmo(p_spatial->cast_to<EditableShape>()) );
- return misg;
- }
- if (p_spatial->cast_to<CarWheel>()) {
-
- Ref<CarWheelSpatialGizmo> misg = memnew( CarWheelSpatialGizmo(p_spatial->cast_to<CarWheel>()) );
- 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;
-
-}
-
-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));
-
-
- 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));
-
- 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-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).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);
+ }
+ }
+
+
+ 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 8176157bc9..bc7e8ad21d 100644
--- a/tools/editor/spatial_editor_gizmos.h
+++ b/tools/editor/spatial_editor_gizmos.h
@@ -1,367 +1,491 @@
-/*************************************************************************/
-/* spatial_editor_gizmos.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-#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/car_body.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 clear();
- 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 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 RayCastSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(RayCastSpatialGizmo,SpatialGizmoTool);
-
- RayCast* raycast;
-
-public:
-
- void redraw();
- RayCastSpatialGizmo(RayCast* p_raycast=NULL);
-
-};
-
-
-class CarWheelSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(CarWheelSpatialGizmo,SpatialGizmoTool);
-
- CarWheel* car_wheel;
-
-public:
-
- void redraw();
- CarWheelSpatialGizmo(CarWheel* p_car_wheel=NULL);
-
-};
-
-
-
-class SpatialEditorGizmos {
-public:
-
- Ref<FixedMaterial> create_line_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> 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-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
+
diff --git a/tools/export/blender25/godot_export_manager.py b/tools/export/blender25/godot_export_manager.py
new file mode 100644
index 0000000000..582d76f94f
--- /dev/null
+++ b/tools/export/blender25/godot_export_manager.py
@@ -0,0 +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_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/install.txt b/tools/export/blender25/install.txt
index b245bbf3df..049af8848e 100644
--- a/tools/export/blender25/install.txt
+++ b/tools/export/blender25/install.txt
@@ -5,19 +5,7 @@ Godot Author's Own Collada Exporter
scripts/addons folder (You will see many other io_scene_blahblah like
folders). Copy the entire dir, not just the contents, make it just like
the others.
-2) Go to Blender settings and enable the "Khronos Collada" plugin
+2) Go to Blender settings and enable the "Better Collada" plugin
3) Enjoy proper Collada export.
-4) If it's broken, you can:
- a) Flame the Blender developers in their mailing list for changing
- the API every month.
- b) Flame the Blender developers for not giving a home to this script
- and mantaining it themselves, instead choosing to use the huge,
- bloated and buggy OpenCollada based implementation that is as big
- as Blender itself, while this script is a little over 1000 lines
- of code, works better and has more features.
- c) Cry to the poor Godot developers who are busy enough to fix it,
- because they are good people and will fix it for you anyway (submit
- an issue to github).
- d) Be a Hero, save the day, fix it yourself and submit a pull request to
- github with the changes.
+4) If it's broken, contact us.
\ No newline at end of file
diff --git a/tools/export/blender25/io_scene_dae/__init__.py b/tools/export/blender25/io_scene_dae/__init__.py
index 39d8e94a53..182ec21e63 100644
--- a/tools/export/blender25/io_scene_dae/__init__.py
+++ b/tools/export/blender25/io_scene_dae/__init__.py
@@ -19,14 +19,14 @@
# <pep8-80 compliant>
bl_info = {
- "name": "Khronos Collada format",
+ "name": "Better Collada Exporter",
"author": "Juan Linietsky",
"blender": (2, 5, 8),
"api": 38691,
"location": "File > Import-Export",
- "description": ("Export DAE Scenes"),
+ "description": ("Export DAE Scenes, This plugin actually works better! otherwise contact me."),
"warning": "",
- "wiki_url": ("None"),
+ "wiki_url": ("http://www.godotengine.org"),
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Import-Export"}
@@ -81,8 +81,19 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
use_mesh_modifiers = BoolProperty(
name="Apply Modifiers",
description="Apply modifiers to mesh objects (on a copy!).",
- default=True,
+ default=False,
)
+ 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)",
@@ -93,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",
@@ -108,11 +114,17 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
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 "
@@ -121,12 +133,13 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
soft_min=1, soft_max=16,
default=6.0,
)
+
use_metadata = BoolProperty(
name="Use Metadata",
default=True,
options={'HIDDEN'},
)
-
+
@property
def check_extension(self):
return True#return self.batch_mode == 'OFF'
@@ -162,7 +175,7 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
def menu_func(self, context):
- self.layout.operator(ExportDAE.bl_idname, text="Khronos Collada (.dae)")
+ self.layout.operator(ExportDAE.bl_idname, text="Better Collada (.dae)")
def register():
diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py
index 1a0cb37a17..b846f0e2d8 100644
--- a/tools/export/blender25/io_scene_dae/export_dae.py
+++ b/tools/export/blender25/io_scene_dae/export_dae.py
@@ -43,6 +43,7 @@ import time
import math # math.pi
import shutil
import bpy
+import bmesh
from mathutils import Vector, Matrix
#according to collada spec, order matters
@@ -51,12 +52,14 @@ S_IMGS=1
S_FX=2
S_MATS=3
S_GEOM=4
-S_CONT=5
-S_CAMS=6
-S_LAMPS=7
-S_ANIM_CLIPS=8
-S_NODES=9
-S_ANIM=10
+S_MORPH=5
+S_SKIN=6
+S_CONT=7
+S_CAMS=8
+S_LAMPS=9
+S_ANIM_CLIPS=10
+S_NODES=11
+S_ANIM=12
CMP_EPSILON=0.0001
@@ -84,6 +87,15 @@ def numarr(a,mult=1.0):
s+=" "
return s
+def numarr_alpha(a,mult=1.0):
+ s=" "
+ for x in a:
+ s+=" "+str(x*mult)
+ if len(a) == 3:
+ s+=" 1.0"
+ s+=" "
+ return s
+
def strarr(arr):
s=" "
for x in arr:
@@ -91,8 +103,6 @@ def strarr(arr):
s+=" "
return s
-
-
class DaeExporter:
def validate_id(self,d):
@@ -123,12 +133,25 @@ class DaeExporter:
tup = (self.vertex.x,self.vertex.y,self.vertex.z,self.normal.x,self.normal.y,self.normal.z)
for t in self.uv:
tup = tup + (t.x,t.y)
+ if (self.color!=None):
+ tup = tup + (self.color.x,self.color.y,self.color.z)
+ if (self.tangent!=None):
+ tup = tup + (self.tangent.x,self.tangent.y,self.tangent.z)
+ if (self.bitangent!=None):
+ tup = tup + (self.bitangent.x,self.bitangent.y,self.bitangent.z)
+ for t in self.bones:
+ tup = tup + (float(t),)
+ for t in self.weights:
+ tup = tup + (float(t),)
+
return tup
def __init__(self):
self.vertex = Vector( (0.0,0.0,0.0) )
self.normal = Vector( (0.0,0.0,0.0) )
- self.color = Vector( (0.0,0.0,0.0) )
+ self.tangent = None
+ self.bitangent = None
+ self.color = None
self.uv = []
self.uv2 = Vector( (0.0,0.0) )
self.bones=[]
@@ -146,35 +169,66 @@ class DaeExporter:
def export_image(self,image):
-
if (image in self.image_cache):
return self.image_cache[image]
-
+
imgpath = image.filepath
if (imgpath.find("//")==0 or imgpath.find("\\\\")==0):
#if relative, convert to absolute
imgpath = bpy.path.abspath(imgpath)
#path is absolute, now do something!
-
+
if (self.config["use_copy_images"]):
#copy image
basedir = os.path.dirname(self.path)+"/images"
if (not os.path.isdir(basedir)):
os.makedirs(basedir)
- dstfile=basedir+"/"+os.path.basename(imgpath)
- if (not os.path.isfile(dstfile)):
- shutil.copy(imgpath,dstfile)
- imgpath="images/"+os.path.basename(imgpath)
+
+ if os.path.isfile(imgpath):
+ dstfile=basedir+"/"+os.path.basename(imgpath)
+
+ if (not os.path.isfile(dstfile)):
+ shutil.copy(imgpath,dstfile)
+ 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
+ if img_tmp_path.endswith((".bmp",".rgb",".png",".jpeg",".jpg",".jp2",".tga",".cin",".dpx",".exr",".hdr",".tif")):
+ image.filepath = basedir+"/"+os.path.basename(img_tmp_path)
+ else:
+ image.filepath = basedir+"/"+image.name+".png"
+
+ dstfile=basedir+"/"+os.path.basename(image.filepath)
+
+ if (not os.path.isfile(dstfile)):
+
+ image.save()
+ imgpath="images/"+os.path.basename(image.filepath)
+ image.filepath = img_tmp_path
else:
#export relative, always, no one wants absolute paths.
- imgpath = os.path.relpath(imgpath,os.path.dirname(self.path)).replace("\\","/") # export unix compatible always
-
+ try:
+ imgpath = os.path.relpath(imgpath,os.path.dirname(self.path)).replace("\\","/") # export unix compatible always
+
+ except:
+ pass #fails sometimes, not sure why
+
imgid = self.new_id("image")
+
+ print("FOR: "+imgpath)
+
+# if (not os.path.isfile(imgpath)):
+# print("NOT FILE?")
+# if imgpath.endswith((".bmp",".rgb",".png",".jpeg",".jpg",".jp2",".tga",".cin",".dpx",".exr",".hdr",".tif")):
+# imgpath="images/"+os.path.basename(imgpath)
+# else:
+# imgpath="images/"+image.name+".png"
+
self.writel(S_IMGS,1,'<image id="'+imgid+'" name="'+image.name+'">')
- self.writel(S_IMGS,2,'<init_from>'+imgpath+'</init_from>"/>')
+ self.writel(S_IMGS,2,'<init_from>'+imgpath+'</init_from>')
self.writel(S_IMGS,1,'</image>')
self.image_cache[image]=imgid
return imgid
@@ -246,25 +300,25 @@ class DaeExporter:
if (emission_tex!=None):
self.writel(S_FX,6,'<texture texture="'+emission_tex+'" texcoord="CHANNEL1"/>')
else:
- self.writel(S_FX,6,'<color>'+numarr(material.diffuse_color,material.emit)+' </color>') # not totally right but good enough
+ self.writel(S_FX,6,'<color>'+numarr_alpha(material.diffuse_color,material.emit)+' </color>') # not totally right but good enough
self.writel(S_FX,5,'</emission>')
self.writel(S_FX,5,'<ambient>')
- self.writel(S_FX,6,'<color>'+numarr(self.scene.world.ambient_color,material.ambient)+' </color>')
+ self.writel(S_FX,6,'<color>'+numarr_alpha(self.scene.world.ambient_color,material.ambient)+' </color>')
self.writel(S_FX,5,'</ambient>')
self.writel(S_FX,5,'<diffuse>')
if (diffuse_tex!=None):
self.writel(S_FX,6,'<texture texture="'+diffuse_tex+'" texcoord="CHANNEL1"/>')
else:
- self.writel(S_FX,6,'<color>'+numarr(material.diffuse_color,material.diffuse_intensity)+'</color>')
+ self.writel(S_FX,6,'<color>'+numarr_alpha(material.diffuse_color,material.diffuse_intensity)+'</color>')
self.writel(S_FX,5,'</diffuse>')
self.writel(S_FX,5,'<specular>')
if (specular_tex!=None):
self.writel(S_FX,6,'<texture texture="'+specular_tex+'" texcoord="CHANNEL1"/>')
else:
- self.writel(S_FX,6,'<color>'+numarr(material.specular_color,material.specular_intensity)+'</color>')
+ self.writel(S_FX,6,'<color>'+numarr_alpha(material.specular_color,material.specular_intensity)+'</color>')
self.writel(S_FX,5,'</specular>')
self.writel(S_FX,5,'<shininess>')
@@ -272,7 +326,7 @@ class DaeExporter:
self.writel(S_FX,5,'</shininess>')
self.writel(S_FX,5,'<reflective>')
- self.writel(S_FX,6,'<color>'+strarr(material.mirror_color)+'</color>')
+ self.writel(S_FX,6,'<color>'+numarr_alpha(material.mirror_color)+'</color>')
self.writel(S_FX,5,'</reflective>')
if (material.use_transparency):
@@ -280,8 +334,9 @@ class DaeExporter:
self.writel(S_FX,6,'<float>'+str(material.alpha)+'</float>')
self.writel(S_FX,5,'</transparency>')
-
- self.writel(S_FX,5,'<index_of_refraction>'+str(material.specular_ior)+'</index_of_refraction>')
+ self.writel(S_FX,5,'<index_of_refraction>')
+ self.writel(S_FX,6,'<float>'+str(material.specular_ior)+'</float>')
+ self.writel(S_FX,5,'</index_of_refraction>')
self.writel(S_FX,4,'</'+shtype+'>')
@@ -293,6 +348,9 @@ class DaeExporter:
self.writel(S_FX,6,'</bump>')
self.writel(S_FX,5,'</technique>')
+ self.writel(S_FX,5,'<technique profile="GOOGLEEARTH">')
+ self.writel(S_FX,6,'<double_sided>'+["0","1"][double_sided_hint]+"</double_sided>")
+ self.writel(S_FX,5,'</technique>')
self.writel(S_FX,4,'</extra>')
self.writel(S_FX,3,'</technique>')
@@ -312,16 +370,144 @@ class DaeExporter:
return matid
- def export_mesh(self,node,armature=None):
+ def export_mesh(self,node,armature=None,skeyindex=-1,skel_source=None,custom_name=None):
+
+ mesh = node.data
- if (len(node.modifiers) and self.config["use_mesh_modifiers"]):
- mesh=node.to_mesh(self.scene,True,"RENDER") #is this allright?
- else:
- mesh=node.data
- if (mesh in self.mesh_cache):
+ if (node.data in self.mesh_cache):
return self.mesh_cache[mesh]
+ if (skeyindex==-1 and mesh.shape_keys!=None and len(mesh.shape_keys.key_blocks)):
+ values=[]
+ morph_targets=[]
+ md=None
+ for k in range(0,len(mesh.shape_keys.key_blocks)):
+ shape = node.data.shape_keys.key_blocks[k]
+ values+=[shape.value] #save value
+ shape.value=0
+
+ mid = self.new_id("morph")
+
+ for k in range(0,len(mesh.shape_keys.key_blocks)):
+
+ shape = node.data.shape_keys.key_blocks[k]
+ node.show_only_shape_key=True
+ node.active_shape_key_index = k
+ shape.value = 1.0
+ mesh.update()
+ """
+ oldval = shape.value
+ shape.value = 1.0
+
+ """
+ p = node.data
+ v = node.to_mesh(bpy.context.scene, True, "RENDER")
+ node.data = v
+# self.export_node(node,il,shape.name)
+ node.data.update()
+ if (armature and k==0):
+ md=self.export_mesh(node,armature,k,mid,shape.name)
+ else:
+ md=self.export_mesh(node,None,k,None,shape.name)
+
+ node.data = p
+ node.data.update()
+ shape.value = 0.0
+ morph_targets.append(md)
+
+ """
+ shape.value = oldval
+ """
+ node.show_only_shape_key=False
+ node.active_shape_key_index = 0
+
+
+ self.writel(S_MORPH,1,'<controller id="'+mid+'" name="">')
+ #if ("skin_id" in morph_targets[0]):
+ # self.writel(S_MORPH,2,'<morph source="#'+morph_targets[0]["skin_id"]+'" method="NORMALIZED">')
+ #else:
+ self.writel(S_MORPH,2,'<morph source="#'+morph_targets[0]["id"]+'" method="NORMALIZED">')
+
+ self.writel(S_MORPH,3,'<source id="'+mid+'-morph-targets">')
+ self.writel(S_MORPH,4,'<IDREF_array id="'+mid+'-morph-targets-array" count="'+str(len(morph_targets)-1)+'">')
+ marr=""
+ warr=""
+ for i in range(len(morph_targets)):
+ if (i==0):
+ continue
+ elif (i>1):
+ marr+=" "
+
+ if ("skin_id" in morph_targets[i]):
+ marr+=morph_targets[i]["skin_id"]
+ else:
+ marr+=morph_targets[i]["id"]
+
+ warr+=" 0"
+
+ self.writel(S_MORPH,5,marr)
+ self.writel(S_MORPH,4,'</IDREF_array>')
+ self.writel(S_MORPH,4,'<technique_common>')
+ self.writel(S_MORPH,5,'<accessor source="#'+mid+'-morph-targets-array" count="'+str(len(morph_targets)-1)+'" stride="1">')
+ self.writel(S_MORPH,6,'<param name="MORPH_TARGET" type="IDREF"/>')
+ self.writel(S_MORPH,5,'</accessor>')
+ self.writel(S_MORPH,4,'</technique_common>')
+ self.writel(S_MORPH,3,'</source>')
+
+ self.writel(S_MORPH,3,'<source id="'+mid+'-morph-weights">')
+ self.writel(S_MORPH,4,'<float_array id="'+mid+'-morph-weights-array" count="'+str(len(morph_targets)-1)+'" >')
+ self.writel(S_MORPH,5,warr)
+ self.writel(S_MORPH,4,'</float_array>')
+ self.writel(S_MORPH,4,'<technique_common>')
+ self.writel(S_MORPH,5,'<accessor source="#'+mid+'-morph-weights-array" count="'+str(len(morph_targets)-1)+'" stride="1">')
+ self.writel(S_MORPH,6,'<param name="MORPH_WEIGHT" type="float"/>')
+ self.writel(S_MORPH,5,'</accessor>')
+ self.writel(S_MORPH,4,'</technique_common>')
+ self.writel(S_MORPH,3,'</source>')
+
+ self.writel(S_MORPH,3,'<targets>')
+ self.writel(S_MORPH,4,'<input semantic="MORPH_TARGET" source="#'+mid+'-morph-targets"/>')
+ self.writel(S_MORPH,4,'<input semantic="MORPH_WEIGHT" source="#'+mid+'-morph-weights"/>')
+ self.writel(S_MORPH,3,'</targets>')
+ self.writel(S_MORPH,2,'</morph>')
+ self.writel(S_MORPH,1,'</controller>')
+ if (armature!=None):
+
+ self.armature_for_morph[node]=armature
+
+ meshdata={}
+ if (armature):
+ meshdata = morph_targets[0]
+ meshdata["morph_id"]=mid
+ else:
+ meshdata["id"]=morph_targets[0]["id"]
+ meshdata["morph_id"]=mid
+ meshdata["material_assign"]=morph_targets[0]["material_assign"]
+
+
+
+ self.mesh_cache[node.data]=meshdata
+ return meshdata
+
+ apply_modifiers = len(node.modifiers) and self.config["use_mesh_modifiers"]
+
+ name_to_use = mesh.name
+ #print("name to use: "+mesh.name)
+ if (custom_name!=None and custom_name!=""):
+ name_to_use=custom_name
+
+ mesh=node.to_mesh(self.scene,apply_modifiers,"RENDER") #is this allright?
+
+ triangulate=self.config["use_triangles"]
+ if (triangulate):
+ bm = bmesh.new()
+ bm.from_mesh(mesh)
+ bmesh.ops.triangulate(bm, faces=bm.faces)
+ bm.to_mesh(mesh)
+ bm.free()
+
+
mesh.update(calc_tessface=True)
vertices=[]
vertex_map={}
@@ -337,20 +523,32 @@ class DaeExporter:
has_uv=False
has_uv2=False
has_weights=armature!=None
- has_colors=False
+ has_tangents=self.config["use_tangent_arrays"] # could detect..
+ has_colors=len(mesh.vertex_colors)
mat_assign=[]
uv_layer_count=len(mesh.uv_textures)
+ if (has_tangents and len(mesh.uv_textures)):
+ try:
+ mesh.calc_tangents()
+ except:
+ self.operator.report({'WARNING'},'CalcTangets failed for mesh "'+mesh.name+'", no tangets will be exported.')
+ #uv_layer_count=0
+ mesh.calc_normals_split()
+ has_tangents=False
+
+ else:
+ mesh.calc_normals_split()
+ has_tangents=False
- for fi in range(len(mesh.tessfaces)):
- f=mesh.tessfaces[fi]
+ for fi in range(len(mesh.polygons)):
+ f=mesh.polygons[fi]
if (not (f.material_index in surface_indices)):
surface_indices[f.material_index]=[]
- print("Type: "+str(type(f.material_index)))
- print("IDX: "+str(f.material_index)+"/"+str(len(mesh.materials)))
-
+ #print("Type: "+str(type(f.material_index)))
+ #print("IDX: "+str(f.material_index)+"/"+str(len(mesh.materials)))
try:
#Bizarre blender behavior i don't understand, so catching exception
@@ -359,41 +557,48 @@ class DaeExporter:
mat= None
if (mat!=None):
- materials[f.material_index]=self.export_material( mat )
+ materials[f.material_index]=self.export_material( mat,mesh.show_double_sided )
else:
materials[f.material_index]=None #weird, has no material?
indices = surface_indices[f.material_index]
vi=[]
- #make triangles always
+ #vertices always 3
+ """
if (len(f.vertices)==3):
vi.append(0)
vi.append(1)
vi.append(2)
elif (len(f.vertices)==4):
+ #todo, should use shortest path
vi.append(0)
vi.append(1)
vi.append(2)
vi.append(0)
vi.append(2)
vi.append(3)
+ """
- for x in vi:
- mv = mesh.vertices[f.vertices[x]]
+ for lt in range(f.loop_total):
+ loop_index = f.loop_start + lt
+ ml = mesh.loops[loop_index]
+ mv = mesh.vertices[ml.vertex_index]
v = self.Vertex()
v.vertex = Vector( mv.co )
- for xt in mesh.tessface_uv_textures:
- d = xt.data[fi]
- uvsrc = [d.uv1,d.uv2,d.uv3,d.uv4]
- v.uv.append( Vector( uvsrc[x] ) )
+ for xt in mesh.uv_layers:
+ v.uv.append( Vector( xt.data[loop_index].uv ) )
+ if (has_colors):
+ v.color = Vector( mesh.vertex_colors[0].data[loop_index].color )
+
+ v.normal = Vector( ml.normal )
+
+ if (has_tangents):
+ v.tangent = Vector( ml.tangent )
+ v.bitangent = Vector( ml.bitangent )
- if (f.use_smooth):
- v.normal=Vector( mv.normal )
- else:
- v.normal=Vector( f.normal )
# if (armature):
# v.vertex = node.matrix_world * v.vertex
@@ -402,31 +607,51 @@ class DaeExporter:
if (armature!=None):
wsum=0.0
+ zero_bones=[]
+
for vg in mv.groups:
if vg.group >= len(node.vertex_groups):
continue;
name = node.vertex_groups[vg.group].name
+
if (name in si["bone_index"]):
+ #could still put the weight as 0.0001 maybe
if (vg.weight>0.001): #blender has a lot of zero weight stuff
v.bones.append(si["bone_index"][name])
v.weights.append(vg.weight)
wsum+=vg.weight
+ if (wsum==0.0):
+ if not self.wrongvtx_report:
+ self.operator.report({'WARNING'},'Mesh for object "'+node.name+'" has unassigned weights. This may look wrong in exported model.')
+ self.wrongvtx_report=True
+
+ #blender can have bones assigned that weight zero so they remain local
+ #this is the best it can be done?
+ v.bones.append(0)
+ v.weights.append(1)
+
+
tup = v.get_tup()
idx = 0
- if (tup in vertex_map):
+ if (skeyindex==-1 and tup in vertex_map): #do not optmize if using shapekeys
idx = vertex_map[tup]
else:
idx = len(vertices)
vertices.append(v)
vertex_map[tup]=idx
- indices.append(idx)
+ vi.append(idx)
+
+ if (len(vi)>2):
+ #only triangles and above
+ indices.append(vi)
+
meshid = self.new_id("mesh")
+ self.writel(S_GEOM,1,'<geometry id="'+meshid+'" name="'+name_to_use+'">')
- self.writel(S_GEOM,1,'<geometry id="'+meshid+'" name="'+mesh.name+'">')
self.writel(S_GEOM,2,'<mesh>')
@@ -461,6 +686,37 @@ class DaeExporter:
self.writel(S_GEOM,4,'</technique_common>')
self.writel(S_GEOM,3,'</source>')
+ if (has_tangents):
+ self.writel(S_GEOM,3,'<source id="'+meshid+'-tangents">')
+ float_values=""
+ for v in vertices:
+ float_values+=" "+str(v.tangent.x)+" "+str(v.tangent.y)+" "+str(v.tangent.z)
+ self.writel(S_GEOM,4,'<float_array id="'+meshid+'-tangents-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>')
+ self.writel(S_GEOM,4,'<technique_common>')
+ self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-tangents-array" count="'+str(len(vertices))+'" stride="3">')
+ self.writel(S_GEOM,5,'<param name="X" type="float"/>')
+ self.writel(S_GEOM,5,'<param name="Y" type="float"/>')
+ self.writel(S_GEOM,5,'<param name="Z" type="float"/>')
+ self.writel(S_GEOM,4,'</accessor>')
+ self.writel(S_GEOM,4,'</technique_common>')
+ self.writel(S_GEOM,3,'</source>')
+
+ self.writel(S_GEOM,3,'<source id="'+meshid+'-bitangents">')
+ float_values=""
+ for v in vertices:
+ float_values+=" "+str(v.bitangent.x)+" "+str(v.bitangent.y)+" "+str(v.bitangent.z)
+ self.writel(S_GEOM,4,'<float_array id="'+meshid+'-bitangents-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>')
+ self.writel(S_GEOM,4,'<technique_common>')
+ self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-bitangents-array" count="'+str(len(vertices))+'" stride="3">')
+ self.writel(S_GEOM,5,'<param name="X" type="float"/>')
+ self.writel(S_GEOM,5,'<param name="Y" type="float"/>')
+ self.writel(S_GEOM,5,'<param name="Z" type="float"/>')
+ self.writel(S_GEOM,4,'</accessor>')
+ self.writel(S_GEOM,4,'</technique_common>')
+ self.writel(S_GEOM,3,'</source>')
+
+
+
# UV Arrays
for uvi in range(uv_layer_count):
@@ -468,7 +724,12 @@ class DaeExporter:
self.writel(S_GEOM,3,'<source id="'+meshid+'-texcoord-'+str(uvi)+'">')
float_values=""
for v in vertices:
- float_values+=" "+str(v.uv[uvi].x)+" "+str(v.uv[uvi].y)
+ try:
+ float_values+=" "+str(v.uv[uvi].x)+" "+str(v.uv[uvi].y)
+ except:
+ # I don't understand this weird multi-uv-layer API, but with this it seems to works
+ float_values+=" 0 0 "
+
self.writel(S_GEOM,4,'<float_array id="'+meshid+'-texcoord-'+str(uvi)+'-array" count="'+str(len(vertices)*2)+'">'+float_values+'</float_array>')
self.writel(S_GEOM,4,'<technique_common>')
self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-texcoord-'+str(uvi)+'-array" count="'+str(len(vertices))+'" stride="2">')
@@ -478,84 +739,129 @@ class DaeExporter:
self.writel(S_GEOM,4,'</technique_common>')
self.writel(S_GEOM,3,'</source>')
+ # Color Arrays
+
+ if (has_colors):
+ self.writel(S_GEOM,3,'<source id="'+meshid+'-colors">')
+ float_values=""
+ for v in vertices:
+ float_values+=" "+str(v.color.x)+" "+str(v.color.y)+" "+str(v.color.z)
+ self.writel(S_GEOM,4,'<float_array id="'+meshid+'-colors-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>')
+ self.writel(S_GEOM,4,'<technique_common>')
+ self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-colors-array" count="'+str(len(vertices))+'" stride="3">')
+ self.writel(S_GEOM,5,'<param name="X" type="float"/>')
+ self.writel(S_GEOM,5,'<param name="Y" type="float"/>')
+ self.writel(S_GEOM,5,'<param name="Z" type="float"/>')
+ self.writel(S_GEOM,4,'</accessor>')
+ self.writel(S_GEOM,4,'</technique_common>')
+ self.writel(S_GEOM,3,'</source>')
+
# Triangle Lists
self.writel(S_GEOM,3,'<vertices id="'+meshid+'-vertices">')
self.writel(S_GEOM,4,'<input semantic="POSITION" source="#'+meshid+'-positions"/>')
self.writel(S_GEOM,3,'</vertices>')
+ prim_type=""
+ if (triangulate):
+ prim_type="triangles"
+ else:
+ prim_type="polygons"
+
+
for m in surface_indices:
indices = surface_indices[m]
mat = materials[m]
+
if (mat!=None):
matref = self.new_id("trimat")
- self.writel(S_GEOM,3,'<triangles count="'+str(int(len(indices)/3))+'" material="'+matref+'">') # todo material
+ self.writel(S_GEOM,3,'<'+prim_type+' count="'+str(int(len(indices)))+'" material="'+matref+'">') # todo material
mat_assign.append( (mat,matref) )
else:
- self.writel(S_GEOM,3,'<triangles count="'+str(int(len(indices)/3))+'">') # todo material
+ self.writel(S_GEOM,3,'<'+prim_type+' count="'+str(int(len(indices)))+'">') # todo material
+
+
self.writel(S_GEOM,4,'<input semantic="VERTEX" source="#'+meshid+'-vertices" offset="0"/>')
- self.writel(S_GEOM,4,'<input semantic="NORMAL" source="#'+meshid+'-normals" offset="1"/>')
- extra_indices=0
+ self.writel(S_GEOM,4,'<input semantic="NORMAL" source="#'+meshid+'-normals" offset="0"/>')
+
for uvi in range(uv_layer_count):
- self.writel(S_GEOM,4,'<input semantic="TEXCOORD" source="#'+meshid+'-texcoord-'+str(uvi)+'" offset="'+str(2+uvi)+'" set="'+str(uvi)+'"/>')
- extra_indices+=1
+ self.writel(S_GEOM,4,'<input semantic="TEXCOORD" source="#'+meshid+'-texcoord-'+str(uvi)+'" offset="0" set="'+str(uvi)+'"/>')
+
+ if (has_colors):
+ self.writel(S_GEOM,4,'<input semantic="COLOR" source="#'+meshid+'-colors" offset="0"/>')
+ if (has_tangents):
+ self.writel(S_GEOM,4,'<input semantic="TEXTANGENT" source="#'+meshid+'-tangents" offset="0"/>')
+ self.writel(S_GEOM,4,'<input semantic="TEXBINORMAL" source="#'+meshid+'-bitangents" offset="0"/>')
+
+ if (triangulate):
+ int_values="<p>"
+ for p in indices:
+ for i in p:
+ int_values+=" "+str(i)
+ int_values+=" </p>"
+ self.writel(S_GEOM,4,int_values)
+ else:
+ for p in indices:
+ int_values="<p>"
+ for i in p:
+ int_values+=" "+str(i)
+ int_values+=" </p>"
+ self.writel(S_GEOM,4,int_values)
- int_values="<p>"
- for i in range(len(indices)):
- int_values+=" "+str(indices[i]) # vertex index
- int_values+=" "+str(indices[i]) # normal index
- for e in range(extra_indices):
- int_values+=" "+str(indices[i]) # normal index
- int_values+="</p>"
- self.writel(S_GEOM,4,int_values)
- self.writel(S_GEOM,3,'</triangles>')
+ self.writel(S_GEOM,3,'</'+prim_type+'>')
self.writel(S_GEOM,2,'</mesh>')
self.writel(S_GEOM,1,'</geometry>')
+
meshdata={}
meshdata["id"]=meshid
meshdata["material_assign"]=mat_assign
- self.mesh_cache[mesh]=meshdata
+ if (skeyindex==-1):
+ self.mesh_cache[node.data]=meshdata
# Export armature data (if armature exists)
- if (armature!=None):
+ if (armature!=None and (skel_source!=None or skeyindex==-1)):
contid = self.new_id("controller")
- self.writel(S_CONT,1,'<controller id="'+contid+'">')
- self.writel(S_CONT,2,'<skin source="'+meshid+'">')
- self.writel(S_CONT,3,'<bind_shape_matrix>'+strmtx(node.matrix_world)+'</bind_shape_matrix>')
+ self.writel(S_SKIN,1,'<controller id="'+contid+'">')
+ if (skel_source!=None):
+ self.writel(S_SKIN,2,'<skin source="#'+skel_source+'">')
+ else:
+ self.writel(S_SKIN,2,'<skin source="#'+meshid+'">')
+
+ self.writel(S_SKIN,3,'<bind_shape_matrix>'+strmtx(node.matrix_world)+'</bind_shape_matrix>')
#Joint Names
- self.writel(S_CONT,3,'<source id="'+contid+'-joints">')
+ self.writel(S_SKIN,3,'<source id="'+contid+'-joints">')
name_values=""
for v in si["bone_names"]:
name_values+=" "+v
- self.writel(S_CONT,4,'<Name_array id="'+contid+'-joints-array" count="'+str(len(si["bone_names"]))+'">'+name_values+'</Name_array>')
- self.writel(S_CONT,4,'<technique_common>')
- self.writel(S_CONT,4,'<accessor source="#'+contid+'-joints-array" count="'+str(len(si["bone_names"]))+'" stride="1">')
- self.writel(S_CONT,5,'<param name="JOINT" type="Name"/>')
- self.writel(S_CONT,4,'</accessor>')
- self.writel(S_CONT,4,'</technique_common>')
- self.writel(S_CONT,3,'</source>')
+ self.writel(S_SKIN,4,'<Name_array id="'+contid+'-joints-array" count="'+str(len(si["bone_names"]))+'">'+name_values+'</Name_array>')
+ self.writel(S_SKIN,4,'<technique_common>')
+ self.writel(S_SKIN,4,'<accessor source="#'+contid+'-joints-array" count="'+str(len(si["bone_names"]))+'" stride="1">')
+ self.writel(S_SKIN,5,'<param name="JOINT" type="Name"/>')
+ self.writel(S_SKIN,4,'</accessor>')
+ self.writel(S_SKIN,4,'</technique_common>')
+ self.writel(S_SKIN,3,'</source>')
#Pose Matrices!
- self.writel(S_CONT,3,'<source id="'+contid+'-bind_poses">')
+ self.writel(S_SKIN,3,'<source id="'+contid+'-bind_poses">')
pose_values=""
for v in si["bone_bind_poses"]:
pose_values+=" "+strmtx(v)
- self.writel(S_CONT,4,'<float_array id="'+contid+'-bind_poses-array" count="'+str(len(si["bone_bind_poses"])*16)+'">'+pose_values+'</float_array>')
- self.writel(S_CONT,4,'<technique_common>')
- self.writel(S_CONT,4,'<accessor source="#'+contid+'-bind_poses-array" count="'+str(len(si["bone_bind_poses"]))+'" stride="16">')
- self.writel(S_CONT,5,'<param name="TRANSFORM" type="float4x4"/>')
- self.writel(S_CONT,4,'</accessor>')
- self.writel(S_CONT,4,'</technique_common>')
- self.writel(S_CONT,3,'</source>')
+ self.writel(S_SKIN,4,'<float_array id="'+contid+'-bind_poses-array" count="'+str(len(si["bone_bind_poses"])*16)+'">'+pose_values+'</float_array>')
+ self.writel(S_SKIN,4,'<technique_common>')
+ self.writel(S_SKIN,4,'<accessor source="#'+contid+'-bind_poses-array" count="'+str(len(si["bone_bind_poses"]))+'" stride="16">')
+ self.writel(S_SKIN,5,'<param name="TRANSFORM" type="float4x4"/>')
+ self.writel(S_SKIN,4,'</accessor>')
+ self.writel(S_SKIN,4,'</technique_common>')
+ self.writel(S_SKIN,3,'</source>')
#Skin Weights!
- self.writel(S_CONT,3,'<source id="'+contid+'-skin_weights">')
+ self.writel(S_SKIN,3,'<source id="'+contid+'-skin_weights">')
skin_weights=""
skin_weights_total=0
for v in vertices:
@@ -563,22 +869,22 @@ class DaeExporter:
for w in v.weights:
skin_weights+=" "+str(w)
- self.writel(S_CONT,4,'<float_array id="'+contid+'-skin_weights-array" count="'+str(skin_weights_total)+'">'+skin_weights+'</float_array>')
- self.writel(S_CONT,4,'<technique_common>')
- self.writel(S_CONT,4,'<accessor source="#'+contid+'-skin_weights-array" count="'+str(skin_weights_total)+'" stride="1">')
- self.writel(S_CONT,5,'<param name="WEIGHT" type="float"/>')
- self.writel(S_CONT,4,'</accessor>')
- self.writel(S_CONT,4,'</technique_common>')
- self.writel(S_CONT,3,'</source>')
-
-
- self.writel(S_CONT,3,'<joints>')
- self.writel(S_CONT,4,'<input semantic="JOINT" source="#'+contid+'-joints"/>')
- self.writel(S_CONT,4,'<input semantic="INV_BIND_MATRIX" source="#'+contid+'-bind_poses"/>')
- self.writel(S_CONT,3,'</joints>')
- self.writel(S_CONT,3,'<vertex_weights count="'+str(len(vertices))+'">')
- self.writel(S_CONT,4,'<input semantic="JOINT" source="#'+contid+'-joints" offset="0"/>')
- self.writel(S_CONT,4,'<input semantic="WEIGHT" source="#'+contid+'-skin_weights" offset="1"/>')
+ self.writel(S_SKIN,4,'<float_array id="'+contid+'-skin_weights-array" count="'+str(skin_weights_total)+'">'+skin_weights+'</float_array>')
+ self.writel(S_SKIN,4,'<technique_common>')
+ self.writel(S_SKIN,4,'<accessor source="#'+contid+'-skin_weights-array" count="'+str(skin_weights_total)+'" stride="1">')
+ self.writel(S_SKIN,5,'<param name="WEIGHT" type="float"/>')
+ self.writel(S_SKIN,4,'</accessor>')
+ self.writel(S_SKIN,4,'</technique_common>')
+ self.writel(S_SKIN,3,'</source>')
+
+
+ self.writel(S_SKIN,3,'<joints>')
+ self.writel(S_SKIN,4,'<input semantic="JOINT" source="#'+contid+'-joints"/>')
+ self.writel(S_SKIN,4,'<input semantic="INV_BIND_MATRIX" source="#'+contid+'-bind_poses"/>')
+ self.writel(S_SKIN,3,'</joints>')
+ self.writel(S_SKIN,3,'<vertex_weights count="'+str(len(vertices))+'">')
+ self.writel(S_SKIN,4,'<input semantic="JOINT" source="#'+contid+'-joints" offset="0"/>')
+ self.writel(S_SKIN,4,'<input semantic="WEIGHT" source="#'+contid+'-skin_weights" offset="1"/>')
vcounts=""
vs=""
vcount=0
@@ -588,13 +894,13 @@ class DaeExporter:
vs+=" "+str(b)
vs+=" "+str(vcount)
vcount+=1
- self.writel(S_CONT,4,'<vcount>'+vcounts+'</vcount>')
- self.writel(S_CONT,4,'<v>'+vs+'</v>')
- self.writel(S_CONT,3,'</vertex_weights>')
+ self.writel(S_SKIN,4,'<vcount>'+vcounts+'</vcount>')
+ self.writel(S_SKIN,4,'<v>'+vs+'</v>')
+ self.writel(S_SKIN,3,'</vertex_weights>')
- self.writel(S_CONT,2,'</skin>')
- self.writel(S_CONT,1,'</controller>')
+ self.writel(S_SKIN,2,'</skin>')
+ self.writel(S_SKIN,1,'</controller>')
meshdata["skin_id"]=contid
@@ -606,20 +912,51 @@ class DaeExporter:
if (node.data==None):
return
armature=None
+ armcount=0
+ for n in node.modifiers:
+ if (n.type=="ARMATURE"):
+ armcount+=1
if (node.parent!=None):
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.')
+ if (armcount==0):
+ self.operator.report({'WARNING'},'Object "'+node.name+'" is child of an armature, but has no armature modifier.')
+
+
+ if (armcount>0 and not armature):
+ self.operator.report({'WARNING'},'Object "'+node.name+'" has armature modifier, but is not a child of an armature. This is unsupported.')
+
+
+ if (node.data.shape_keys!=None):
+ sk = node.data.shape_keys
+ if (sk.animation_data):
+ #print("HAS ANIM")
+ #print("DRIVERS: "+str(len(sk.animation_data.drivers)))
+ for d in sk.animation_data.drivers:
+ if (d.driver):
+ for v in d.driver.variables:
+ for t in v.targets:
+ if (t.id!=None and t.id.name in self.scene.objects):
+ #print("LINKING "+str(node)+" WITH "+str(t.id.name))
+ self.armature_for_morph[node]=self.scene.objects[t.id.name]
meshdata = self.export_mesh(node,armature)
+ close_controller=False
- if (armature==None):
- self.writel(S_NODES,il,'<instance_geometry url="#'+meshdata["id"]+'">')
- else:
+ if ("skin_id" in meshdata):
+ close_controller=True
self.writel(S_NODES,il,'<instance_controller url="#'+meshdata["skin_id"]+'">')
for sn in self.skeleton_info[armature]["skeleton_nodes"]:
self.writel(S_NODES,il+1,'<skeleton>#'+sn+'</skeleton>')
+ elif ("morph_id" in meshdata):
+ self.writel(S_NODES,il,'<instance_controller url="#'+meshdata["morph_id"]+'">')
+ close_controller=True
+ elif (armature==None):
+ self.writel(S_NODES,il,'<instance_geometry url="#'+meshdata["id"]+'">')
if (len(meshdata["material_assign"])>0):
@@ -632,17 +969,23 @@ class DaeExporter:
self.writel(S_NODES,il+2,'</technique_common>')
self.writel(S_NODES,il+1,'</bind_material>')
- if (armature==None):
- self.writel(S_NODES,il,'</instance_geometry>')
- else:
+ if (close_controller):
self.writel(S_NODES,il,'</instance_controller>')
+ else:
+ self.writel(S_NODES,il,'</instance_geometry>')
def export_armature_bone(self,bone,il,si):
boneid = self.new_id("bone")
boneidx = si["bone_count"]
si["bone_count"]+=1
- bonesid = si["name"]+"-"+str(boneidx)
+ bonesid = si["id"]+"-"+str(boneidx)
+ if (bone.name in self.used_bones):
+ if (self.config["use_anim_action_all"]):
+ self.operator.report({'WARNING'},'Bone name "'+bone.name+'" used in more than one skeleton. Actions might export wrong.')
+ else:
+ self.used_bones.append(bone.name)
+
si["bone_index"][bone.name]=boneidx
si["bone_ids"][bone]=boneid
si["bone_names"].append(bonesid)
@@ -671,7 +1014,7 @@ class DaeExporter:
self.skeletons.append(node)
armature = node.data
- self.skeleton_info[node]={ "bone_count":0, "name":node.name, "bone_index":{},"bone_ids":{},"bone_names":[],"bone_bind_poses":[],"skeleton_nodes":[],"armature_xform":node.matrix_world }
+ self.skeleton_info[node]={ "bone_count":0, "id":self.new_id("skelbones"),"name":node.name, "bone_index":{},"bone_ids":{},"bone_names":[],"bone_bind_poses":[],"skeleton_nodes":[],"armature_xform":node.matrix_world }
@@ -705,12 +1048,12 @@ class DaeExporter:
self.writel(S_CAMS,5,'<zfar> '+str(camera.clip_end)+' </zfar>')
self.writel(S_CAMS,4,'</perspective>')
else:
- self.writel(S_CAMS,4,'<orthografic>')
- self.writel(S_CAMS,5,'<xmag> '+str(camera.ortho_scale)+' </xmag>') # I think?
+ self.writel(S_CAMS,4,'<orthographic>')
+ self.writel(S_CAMS,5,'<xmag> '+str(camera.ortho_scale*0.5)+' </xmag>') # I think?
self.writel(S_CAMS,5,'<aspect_ratio> '+str(self.scene.render.resolution_x / self.scene.render.resolution_y)+' </aspect_ratio>')
self.writel(S_CAMS,5,'<znear> '+str(camera.clip_start)+' </znear>')
self.writel(S_CAMS,5,'<zfar> '+str(camera.clip_end)+' </zfar>')
- self.writel(S_CAMS,4,'</orthografic>')
+ self.writel(S_CAMS,4,'</orthographic>')
self.writel(S_CAMS,3,'</technique_common>')
self.writel(S_CAMS,2,'</optics>')
@@ -727,10 +1070,10 @@ class DaeExporter:
light=node.data
lightid=self.new_id("light")
self.writel(S_LAMPS,1,'<light id="'+lightid+'" name="'+light.name+'">')
- self.writel(S_LAMPS,2,'<optics>')
+ #self.writel(S_LAMPS,2,'<optics>')
self.writel(S_LAMPS,3,'<technique_common>')
- if (light.type=="POINT" or light.type=="HEMI"):
+ if (light.type=="POINT"):
self.writel(S_LAMPS,4,'<point>')
self.writel(S_LAMPS,5,'<color>'+strarr(light.color)+'</color>')
att_by_distance = 2.0 / light.distance # convert to linear attenuation
@@ -755,7 +1098,7 @@ class DaeExporter:
self.writel(S_LAMPS,3,'</technique_common>')
- self.writel(S_LAMPS,2,'</optics>')
+ #self.writel(S_LAMPS,2,'</optics>')
self.writel(S_LAMPS,1,'</light>')
@@ -901,15 +1244,16 @@ class DaeExporter:
def export_node(self,node,il):
-
- if (not self.is_node_valid(node)):
+ if (not node in self.valid_nodes):
return
+ prev_node = bpy.context.scene.objects.active
+ bpy.context.scene.objects.active = node
self.writel(S_NODES,il,'<node id="'+self.validate_id(node.name)+'" name="'+node.name+'" type="NODE">')
il+=1
self.writel(S_NODES,il,'<matrix sid="transform">'+strmtx(node.matrix_local)+'</matrix>')
- print("NODE TYPE: "+node.type+" NAME: "+node.name)
+ #print("NODE TYPE: "+node.type+" NAME: "+node.name)
if (node.type=="MESH"):
self.export_mesh_node(node,il)
elif (node.type=="CURVE"):
@@ -921,17 +1265,19 @@ class DaeExporter:
elif (node.type=="LAMP"):
self.export_lamp_node(node,il)
- self.valid_nodes.append(node)
for x in node.children:
self.export_node(x,il)
+
il-=1
self.writel(S_NODES,il,'</node>')
+ bpy.context.scene.objects.active = prev_node #make previous node active again
def is_node_valid(self,node):
if (not node.type in self.config["object_types"]):
return False
if (self.config["use_active_layers"]):
valid=False
+ #print("NAME: "+node.name)
for i in range(20):
if (node.layers[i] and self.scene.layers[i]):
valid=True
@@ -951,8 +1297,21 @@ class DaeExporter:
self.writel(S_NODES,0,'<library_visual_scenes>')
self.writel(S_NODES,1,'<visual_scene id="'+self.scene_name+'" name="scene">')
+ #validate nodes
for obj in self.scene.objects:
- if (obj.parent==None):
+ if (obj in self.valid_nodes):
+ continue
+ if (self.is_node_valid(obj)):
+ n = obj
+ while (n!=None):
+ if (not n in self.valid_nodes):
+ self.valid_nodes.append(n)
+ n=n.parent
+
+
+
+ for obj in self.scene.objects:
+ if (obj in self.valid_nodes and obj.parent==None):
self.export_node(obj,2)
self.writel(S_NODES,1,'</visual_scene>')
@@ -974,18 +1333,22 @@ class DaeExporter:
self.writel(S_ASSET,0,'</asset>')
- def export_animation_transform_channel(self,target,transform_keys):
+ def export_animation_transform_channel(self,target,keys,matrices=True):
- frame_total=len(transform_keys)
+ frame_total=len(keys)
anim_id=self.new_id("anim")
self.writel(S_ANIM,1,'<animation id="'+anim_id+'">')
source_frames = ""
source_transforms = ""
source_interps = ""
- for k in transform_keys:
+ for k in keys:
source_frames += " "+str(k[0])
- source_transforms += " "+strmtx(k[1])
+ if (matrices):
+ source_transforms += " "+strmtx(k[1])
+ else:
+ source_transforms += " "+str(k[1])
+
source_interps +=" LINEAR"
@@ -993,27 +1356,38 @@ class DaeExporter:
self.writel(S_ANIM,2,'<source id="'+anim_id+'-input">')
self.writel(S_ANIM,3,'<float_array id="'+anim_id+'-input-array" count="'+str(frame_total)+'">'+source_frames+'</float_array>')
self.writel(S_ANIM,3,'<technique_common>')
- self.writel(S_ANIM,4,'<accessor source="'+anim_id+'-input-array" count="'+str(frame_total)+'" stride="1">')
+ self.writel(S_ANIM,4,'<accessor source="#'+anim_id+'-input-array" count="'+str(frame_total)+'" stride="1">')
self.writel(S_ANIM,5,'<param name="TIME" type="float"/>')
self.writel(S_ANIM,4,'</accessor>')
self.writel(S_ANIM,3,'</technique_common>')
self.writel(S_ANIM,2,'</source>')
- # Transform Source
- self.writel(S_ANIM,2,'<source id="'+anim_id+'-transform-output">')
- self.writel(S_ANIM,3,'<float_array id="'+anim_id+'-transform-output-array" count="'+str(frame_total*16)+'">'+source_transforms+'</float_array>')
- self.writel(S_ANIM,3,'<technique_common>')
- self.writel(S_ANIM,4,'<accessor source="'+anim_id+'-transform-output-array" count="'+str(frame_total)+'" stride="16">')
- self.writel(S_ANIM,5,'<param name="TRANSFORM" type="float4x4"/>')
- self.writel(S_ANIM,4,'</accessor>')
- self.writel(S_ANIM,3,'</technique_common>')
- self.writel(S_ANIM,2,'</source>')
+ if (matrices):
+ # Transform Source
+ self.writel(S_ANIM,2,'<source id="'+anim_id+'-transform-output">')
+ self.writel(S_ANIM,3,'<float_array id="'+anim_id+'-transform-output-array" count="'+str(frame_total*16)+'">'+source_transforms+'</float_array>')
+ self.writel(S_ANIM,3,'<technique_common>')
+ self.writel(S_ANIM,4,'<accessor source="#'+anim_id+'-transform-output-array" count="'+str(frame_total)+'" stride="16">')
+ self.writel(S_ANIM,5,'<param name="TRANSFORM" type="float4x4"/>')
+ self.writel(S_ANIM,4,'</accessor>')
+ self.writel(S_ANIM,3,'</technique_common>')
+ self.writel(S_ANIM,2,'</source>')
+ else:
+ # Value Source
+ self.writel(S_ANIM,2,'<source id="'+anim_id+'-transform-output">')
+ self.writel(S_ANIM,3,'<float_array id="'+anim_id+'-transform-output-array" count="'+str(frame_total)+'">'+source_transforms+'</float_array>')
+ self.writel(S_ANIM,3,'<technique_common>')
+ self.writel(S_ANIM,4,'<accessor source="#'+anim_id+'-transform-output-array" count="'+str(frame_total)+'" stride="1">')
+ self.writel(S_ANIM,5,'<param name="X" type="float"/>')
+ self.writel(S_ANIM,4,'</accessor>')
+ self.writel(S_ANIM,3,'</technique_common>')
+ self.writel(S_ANIM,2,'</source>')
# Interpolation Source
self.writel(S_ANIM,2,'<source id="'+anim_id+'-interpolation-output">')
self.writel(S_ANIM,3,'<Name_array id="'+anim_id+'-interpolation-output-array" count="'+str(frame_total)+'">'+source_interps+'</Name_array>')
self.writel(S_ANIM,3,'<technique_common>')
- self.writel(S_ANIM,4,'<accessor source="'+anim_id+'-interpolation-output-array" count="'+str(frame_total)+'" stride="1">')
+ self.writel(S_ANIM,4,'<accessor source="#'+anim_id+'-interpolation-output-array" count="'+str(frame_total)+'" stride="1">')
self.writel(S_ANIM,5,'<param name="INTERPOLATION" type="Name"/>')
self.writel(S_ANIM,4,'</accessor>')
self.writel(S_ANIM,3,'</technique_common>')
@@ -1024,18 +1398,23 @@ class DaeExporter:
self.writel(S_ANIM,3,'<input semantic="OUTPUT" source="#'+anim_id+'-transform-output"/>')
self.writel(S_ANIM,3,'<input semantic="INTERPOLATION" source="#'+anim_id+'-interpolation-output"/>')
self.writel(S_ANIM,2,'</sampler>')
- self.writel(S_ANIM,2,'<channel source="#'+anim_id+'-sampler" target="'+target+'/transform"/>')
+ if (matrices):
+ self.writel(S_ANIM,2,'<channel source="#'+anim_id+'-sampler" target="'+target+'/transform"/>')
+ else:
+ self.writel(S_ANIM,2,'<channel source="#'+anim_id+'-sampler" target="'+target+'"/>')
self.writel(S_ANIM,1,'</animation>')
return [anim_id]
- def export_animation(self,start,end):
+ def export_animation(self,start,end,allowed=None):
#Blender -> Collada frames needs a little work
#Collada starts from 0, blender usually from 1
#The last frame must be included also
+ frame_orig = self.scene.frame_current
+
frame_len = 1.0 / self.scene.render.fps
frame_total = end - start + 1
frame_sub = 0
@@ -1044,10 +1423,11 @@ class DaeExporter:
tcn = []
xform_cache={}
+ blend_cache={}
# Change frames first, export objects last
# This improves performance enormously
- print("anim from: "+str(start)+" to "+str(end))
+ #print("anim from: "+str(start)+" to "+str(end)+" allowed: "+str(allowed))
for t in range(start,end+1):
self.scene.frame_set(t)
key = t * frame_len - frame_sub
@@ -1057,8 +1437,28 @@ class DaeExporter:
if (not node in self.valid_nodes):
continue
+ if (allowed!=None and not (node in allowed)):
+ if (node.type=="MESH" and node.data!=None and (node in self.armature_for_morph) and (self.armature_for_morph[node] in allowed)):
+ pass #all good you pass with flying colors for morphs inside of action
+ else:
+ #print("fail "+str((node in self.armature_for_morph)))
+ continue
+ if (node.type=="MESH" and node.data!=None and node.data.shape_keys!=None and (node.data in self.mesh_cache) and len(node.data.shape_keys.key_blocks)):
+ target = self.mesh_cache[node.data]["morph_id"]
+ for i in range(len(node.data.shape_keys.key_blocks)):
+
+ if (i==0):
+ continue
+
+ name=target+"-morph-weights("+str(i-1)+")"
+ if (not (name in blend_cache)):
+ blend_cache[name]=[]
+
+ blend_cache[name].append( (key,node.data.shape_keys.key_blocks[i].value) )
+
if (node.type=="MESH" and node.parent and node.parent.type=="ARMATURE"):
+
continue #In Collada, nodes that have skin modifier must not export animation, animate the skin instead.
if (len(node.constraints)>0 or node.animation_data!=None):
@@ -1075,11 +1475,13 @@ class DaeExporter:
if (node.type=="ARMATURE"):
#All bones exported for now
+
for bone in node.data.bones:
bone_name=self.skeleton_info[node]["bone_ids"][bone]
if (not (bone_name in xform_cache)):
+ #print("has bone: "+bone_name)
xform_cache[bone_name]=[]
posebone = node.pose.bones[bone.name]
@@ -1088,52 +1490,119 @@ class DaeExporter:
mtx = posebone.matrix.copy()
if (bone.parent):
parent_posebone=node.pose.bones[bone.parent.name]
- mtx = parent_posebone.matrix.inverted() * mtx
+ parent_invisible=False
+
+ for i in range(3):
+ if (parent_posebone.scale[i]==0.0):
+ parent_invisible=True
+
+ if (not parent_invisible):
+ mtx = parent_posebone.matrix.inverted() * mtx
xform_cache[bone_name].append( (key,mtx) )
+ self.scene.frame_set(frame_orig)
#export animation xml
for nid in xform_cache:
- tcn+=self.export_animation_transform_channel(nid,xform_cache[nid])
+ tcn+=self.export_animation_transform_channel(nid,xform_cache[nid],True)
+ for nid in blend_cache:
+ tcn+=self.export_animation_transform_channel(nid,blend_cache[nid],False)
return tcn
def export_animations(self):
-
+ tmp_mat = []
+ for s in self.skeletons:
+ tmp_bone_mat = []
+ for bone in s.pose.bones:
+ tmp_bone_mat.append(Matrix(bone.matrix_basis))
+ bone.matrix_basis = Matrix()
+ tmp_mat.append([Matrix(s.matrix_local),tmp_bone_mat])
+
self.writel(S_ANIM,0,'<library_animations>')
-
if (self.config["use_anim_action_all"] and len(self.skeletons)):
+ cached_actions = {}
+
+ for s in self.skeletons:
+ if s.animation_data and s.animation_data.action:
+ cached_actions[s] = s.animation_data.action.name
+
+
self.writel(S_ANIM_CLIPS,0,'<library_animation_clips>')
for x in bpy.data.actions[:]:
- if x in self.action_constraints:
+ if x.users==0 or x in self.action_constraints:
continue
- for y in self.skeletons:
+ if (self.config["use_anim_skip_noexp"] and x.name.endswith("-noexp")):
+ continue
+
+ bones=[]
+ #find bones used
+ for p in x.fcurves:
+ dp = str(p.data_path)
+ base = "pose.bones[\""
+ if (dp.find(base)==0):
+ dp=dp[len(base):]
+ if (dp.find('"')!=-1):
+ dp=dp[:dp.find('"')]
+ if (not dp in bones):
+ bones.append(dp)
+
+ allowed_skeletons=[]
+ for i,y in enumerate(self.skeletons):
if (y.animation_data):
+ for z in y.pose.bones:
+ if (z.bone.name in bones):
+ if (not y in allowed_skeletons):
+ allowed_skeletons.append(y)
y.animation_data.action=x;
+
+ y.matrix_local = tmp_mat[i][0]
+ for j,bone in enumerate(s.pose.bones):
+ bone.matrix_basis = Matrix()
+
+
+ #print("allowed skeletons "+str(allowed_skeletons))
+ #print(str(x))
- tcn = self.export_animation(int(x.frame_range[0]),int(x.frame_range[1]))
+ tcn = self.export_animation(int(x.frame_range[0]),int(x.frame_range[1]+0.5),allowed_skeletons)
framelen=(1.0/self.scene.render.fps)
start = x.frame_range[0]*framelen
end = x.frame_range[1]*framelen
- print("Export anim: "+x.name)
+ #print("Export anim: "+x.name)
self.writel(S_ANIM_CLIPS,1,'<animation_clip name="'+x.name+'" start="'+str(start)+'" end="'+str(end)+'">')
for z in tcn:
- self.writel(S_ANIM_CLIPS,2,'<instance_animation url="#'+z+'">')
+ self.writel(S_ANIM_CLIPS,2,'<instance_animation url="#'+z+'"/>')
self.writel(S_ANIM_CLIPS,1,'</animation_clip>')
+ if (len(tcn)==0):
+ self.operator.report({'WARNING'},'Animation clip "'+x.name+'" contains no tracks.')
+
self.writel(S_ANIM_CLIPS,0,'</library_animation_clips>')
+
+ for i,s in enumerate(self.skeletons):
+ if (s.animation_data==None):
+ continue
+ if s in cached_actions:
+ s.animation_data.action = bpy.data.actions[cached_actions[s]]
+ else:
+ s.animation_data.action = None
+ for j,bone in enumerate(s.pose.bones):
+ bone.matrix_basis = tmp_mat[i][1][j]
+
else:
self.export_animation(self.scene.frame_start,self.scene.frame_end)
-
+
+
+
self.writel(S_ANIM,0,'</library_animations>')
def export(self):
@@ -1153,6 +1622,19 @@ class DaeExporter:
self.export_scene()
self.writel(S_GEOM,0,'</library_geometries>')
+
+ #morphs always go before skin controllers
+ if S_MORPH in self.sections:
+ for l in self.sections[S_MORPH]:
+ self.writel(S_CONT,0,l)
+ del self.sections[S_MORPH]
+
+ #morphs always go before skin controllers
+ if S_SKIN in self.sections:
+ for l in self.sections[S_SKIN]:
+ self.writel(S_CONT,0,l)
+ del self.sections[S_SKIN]
+
self.writel(S_CONT,0,'</library_controllers>')
self.writel(S_CAMS,0,'</library_cameras>')
self.writel(S_LAMPS,0,'</library_lights>')
@@ -1186,7 +1668,8 @@ class DaeExporter:
f.write(bytes('</COLLADA>\n',"UTF-8"))
return True
- def __init__(self,path,kwargs):
+ def __init__(self,path,kwargs,operator):
+ self.operator=operator
self.scene=bpy.context.scene
self.last_id=0
self.scene_name=self.new_id("scene")
@@ -1199,6 +1682,12 @@ class DaeExporter:
self.skeleton_info={}
self.config=kwargs
self.valid_nodes=[]
+ self.armature_for_morph={}
+ self.used_bones=[]
+ self.wrongvtx_report=False
+
+
+
@@ -1209,9 +1698,11 @@ def save(operator, context,
**kwargs
):
- exp = DaeExporter(filepath,kwargs)
+ exp = DaeExporter(filepath,kwargs,operator)
exp.export()
+
+
return {'FINISHED'} # so the script wont run after we have batch exported.
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..6bb6bc2188 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-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. */
+/*************************************************************************/
#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..75e44659e0 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-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. */
+/*************************************************************************/
#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
new file mode 100644
index 0000000000..cf98ae145d
--- /dev/null
+++ b/tools/pck/SCsub
@@ -0,0 +1,4 @@
+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
new file mode 100644
index 0000000000..d398fefb5f
--- /dev/null
+++ b/tools/pck/pck_packer.cpp
@@ -0,0 +1,163 @@
+#include "pck_packer.h"
+
+#include "core/os/file_access.h"
+
+static uint64_t _align(uint64_t p_n, int p_alignment) {
+
+ if (p_alignment == 0)
+ return p_n;
+
+ uint64_t rest = p_n % p_alignment;
+ if (rest == 0)
+ return p_n;
+ else
+ return p_n + (p_alignment - rest);
+};
+
+static void _pad(FileAccess* p_file, int p_bytes) {
+
+ for (int i=0; i<p_bytes; i++) {
+
+ p_file->store_8(0);
+ };
+};
+
+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);
+};
+
+
+Error PCKPacker::pck_start(const String& p_file, int p_alignment) {
+
+ file = FileAccess::open(p_file, FileAccess::WRITE);
+ if (file == NULL) {
+
+ return ERR_CANT_CREATE;
+ };
+
+ alignment = p_alignment;
+
+ file->store_32(0x43504447); // MAGIC
+ file->store_32(0); // # version
+ file->store_32(0); // # major
+ file->store_32(0); // # minor
+ file->store_32(0); // # revision
+
+ for (int i=0; i<16; i++) {
+
+ file->store_32(0); // reserved
+ };
+
+ files.clear();
+
+ return OK;
+};
+
+Error PCKPacker::add_file(const String& p_file, const String& p_src) {
+
+ FileAccess* f = FileAccess::open(p_src, FileAccess::READ);
+ if (!f) {
+ return ERR_FILE_CANT_OPEN;
+ };
+
+ File pf;
+ pf.path = p_file;
+ pf.src_path = p_src;
+ pf.size = f->get_len();
+ pf.offset_offset = 0;
+
+ files.push_back(pf);
+
+ f->close();
+ memdelete(f);
+
+ return OK;
+};
+
+Error PCKPacker::flush(bool p_verbose) {
+
+ if (!file) {
+ ERR_FAIL_COND_V(!file, ERR_INVALID_PARAMETER);
+ return ERR_INVALID_PARAMETER;
+ };
+
+ // write the index
+
+ file->store_32(files.size());
+
+ for (int i=0; i<files.size(); i++) {
+
+ file->store_pascal_string(files[i].path);
+ files[i].offset_offset = file->get_pos();
+ file->store_64(0); // offset
+ file->store_64(files[i].size); // size
+
+ // # empty md5
+ file->store_32(0);
+ file->store_32(0);
+ file->store_32(0);
+ file->store_32(0);
+ };
+
+
+ uint64_t ofs = file->get_pos();
+ ofs = _align(ofs, alignment);
+
+ _pad(file, ofs - file->get_pos());
+
+ const uint32_t buf_max = 65536;
+ uint8_t *buf = memnew_arr(uint8_t, buf_max);
+
+ int count = 0;
+ for (int i=0; i<files.size(); i++) {
+
+ FileAccess* src = FileAccess::open(files[i].src_path, FileAccess::READ);
+ uint64_t to_write = files[i].size;
+ while (to_write > 0) {
+
+ int read = src->get_buffer(buf, MIN(to_write, buf_max));
+ file->store_buffer(buf, read);
+ to_write -= read;
+ };
+
+ uint64_t pos = file->get_pos();
+ file->seek(files[i].offset_offset); // go back to store the file's offset
+ file->store_64(ofs);
+ file->seek(pos);
+
+ ofs = _align(ofs + files[i].size, alignment);
+ _pad(file, ofs - pos);
+
+ src->close();
+ memdelete(src);
+ count += 1;
+ if (p_verbose) {
+ if (count % 100 == 0) {
+ printf("%i/%i (%.2f)\r", count, files.size(), float(count) / files.size() * 100);
+ fflush(stdout);
+ };
+ };
+ };
+
+ if (p_verbose)
+ printf("\n");
+
+ file->close();
+
+ return OK;
+};
+
+PCKPacker::PCKPacker() {
+
+ file = NULL;
+};
+
+PCKPacker::~PCKPacker() {
+ if (file != NULL) {
+ memdelete(file);
+ };
+ file = NULL;
+};
diff --git a/tools/pck/pck_packer.h b/tools/pck/pck_packer.h
new file mode 100644
index 0000000000..2bb51128e9
--- /dev/null
+++ b/tools/pck/pck_packer.h
@@ -0,0 +1,31 @@
+#include "core/reference.h"
+
+class FileAccess;
+
+class PCKPacker : public Reference {
+
+ OBJ_TYPE(PCKPacker, Reference);
+
+ FileAccess* file;
+ int alignment;
+
+ static void _bind_methods();
+
+ struct File {
+
+ String path;
+ String src_path;
+ int size;
+ uint64_t offset_offset;
+ };
+ Vector<File> files;
+
+public:
+ Error pck_start(const String& p_file, int p_alignment);
+ Error add_file(const String& p_file, const String& p_src);
+ Error flush(bool p_verbose = false);
+
+
+ PCKPacker();
+ ~PCKPacker();
+};
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/script_plugins/time/time.gd b/tools/script_plugins/time/time.gd
index 66b3e9ed04..2e56d89d4f 100644
--- a/tools/script_plugins/time/time.gd
+++ b/tools/script_plugins/time/time.gd
@@ -21,12 +21,12 @@ func _init():
timer.set_one_shot(false)
timer.connect("timeout",self,"_timeout")
-func _enter_scene():
+func _enter_tree():
label = Label.new()
add_custom_control(CONTAINER_TOOLBAR,label)
timer.start()
-func _exit_scene():
+func _exit_tree():
timer.stop()
label.free()
label=null
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/tools/scrits/makeargs.py b/tools/scripts/makeargs.py
index 6f7afa6328..6f7afa6328 100644
--- a/tools/scrits/makeargs.py
+++ b/tools/scripts/makeargs.py
diff --git a/version.py b/version.py
index 31257304f6..284bda9520 100644
--- a/version.py
+++ b/version.py
@@ -1,8 +1,8 @@
short_name="godot"
name="Godot Engine"
-major=1
+major=2
minor=0
-revision="$Rev: 3917 $"
-status="beta1"
+status="alpha"
+